Merge "defconfig: enable L2TP/IPSEC VPN protocol" into msm-3.4
diff --git a/Documentation/devicetree/bindings/arm/msm/bam_dmux.txt b/Documentation/devicetree/bindings/arm/msm/bam_dmux.txt
new file mode 100644
index 0000000..d82284d
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/bam_dmux.txt
@@ -0,0 +1,14 @@
+Qualcomm BAM Data Multiplexer Driver
+
+Required properties:
+- compatible : should be "qcom,bam_dmux"
+- reg : the location and size of the BAM hardware
+- interrupts : the BAM hardware to apps processor interrupt line
+
+Example:
+
+ qcom,bam_dmux@fc834000 {
+ compatible = "qcom,bam_dmux";
+ reg = <0xfc834000 0x7000>;
+ interrupts = <0 29 1>;
+ };
diff --git a/Documentation/devicetree/bindings/arm/msm/spm-v2.txt b/Documentation/devicetree/bindings/arm/msm/spm-v2.txt
index d8784db..1a19dbb 100644
--- a/Documentation/devicetree/bindings/arm/msm/spm-v2.txt
+++ b/Documentation/devicetree/bindings/arm/msm/spm-v2.txt
@@ -31,7 +31,6 @@
- qcom,saw2-avs-limit: The AVS limit register
- qcom,saw2-avs-dly: The AVS delay register is used to specify the delay values
between AVS controller requests
-- qcom,saw2-pmic-dly: The delay values for waiting on PMIC response
- qcom,saw2-pmic-data0..7: Specify the pmic data value and the associated FTS
index to send the PMIC data to
- qcom,saw2-vctl-port: The FTS port used for changing voltage
diff --git a/Documentation/devicetree/bindings/fb/msm-hdmi-tx.txt b/Documentation/devicetree/bindings/fb/msm-hdmi-tx.txt
new file mode 100644
index 0000000..70fea73
--- /dev/null
+++ b/Documentation/devicetree/bindings/fb/msm-hdmi-tx.txt
@@ -0,0 +1,50 @@
+* Qualcomm HDMI Tx
+
+Required properties:
+- cell-index: hdmi tx controller index
+- compatible: must be "qcom,hdmi-tx"
+- reg: offset and length of the register regions(s) for the device.
+- reg-names: a list of strings that map in order to the list of regs.
+
+- <supply-name>-supply: phandle to the regulator device tree node.
+- <compatible-name>-supply-names: a list of strings that map in order
+ to the list of supplies.
+- <<compatible-name>-supply-type: a type of supply(ies) mentioned above.
+ 0 = supply with controlled output
+ 1 = supply without controlled output. i.e. voltage switch
+- <compatible-name>-min-voltage-level: specifies minimum voltage level
+ of supply(ies) mentioned above.
+- <compatible-name>-max-voltage-level: specifies maximum voltage level
+ of supply(ies) mentioned above.
+- <compatible-name>-op-mode: specifies optimum operating mode of
+ supply(ies) mentioned above.
+
+- gpios: specifies gpios assigned for the device.
+- <compatible-name>-gpio-names: a list of strings that map in order to
+ the list of gpios
+
+Example:
+ qcom,hdmi_tx@fd922100 {
+ cell-index = <0>;
+ compatible = "qcom,hdmi-tx";
+ reg = <0xfd922100 0x35C>,
+ <0xfd922500 0x7C>,
+ <0xfc4b8000 0x60F0>;
+ reg-names = "core_physical", "phy_physical", "qfprom_physical";
+
+ hpd-5v-supply = <&pm8941_mvs2>;
+ core-vdda-supply = <&pm8941_l12>;
+ core-vcc-supply = <&pm8941_s3>;
+ qcom,hdmi-tx-supply-names = "hpd-5v", "core-vdda", "core-vcc";
+ qcom,hdmi-tx-supply-type = <0 1 1>;
+ qcom,hdmi-tx-min-voltage-level = <0 1800000 1800000>;
+ qcom,hdmi-tx-max-voltage-level = <0 1800000 1800000>;
+ qcom,hdmi-tx-op-mode = <0 1800000 0>;
+
+ gpios = <&msmgpio 31 0>,
+ <&msmgpio 32 0>,
+ <&msmgpio 33 0>,
+ <&msmgpio 34 0>;
+ qcom,hdmi-tx-gpio-names =
+ "cec-pin", "hpd-ddc-clk", "hpd-ddc-data", "hpd-pin";
+ };
diff --git a/Documentation/devicetree/bindings/mmc/msm_sdcc.txt b/Documentation/devicetree/bindings/mmc/msm_sdcc.txt
index c674a13..5f7651a 100644
--- a/Documentation/devicetree/bindings/mmc/msm_sdcc.txt
+++ b/Documentation/devicetree/bindings/mmc/msm_sdcc.txt
@@ -5,8 +5,12 @@
Required properties:
- compatible : should be "qcom,msm-sdcc"
- - reg : should contain SDCC, BAM register map.
+ - reg : should contain SDCC, SDCC-DML and BAM register map.
+ - reg-names : indicates various resources passed to driver (via reg proptery) by name.
+ "reg-names" examples are "core_mem", "dml_mem" and "bam_mem"
- interrupts : should contain SDCC core interrupt.
+ - interrupt-names : indicates interrupts passed to driver (via interrupts property) by name.
+ "interrupt-names" examples are "core_irq", "bam_irq" and "status_irq"
- qcom,sdcc-clk-rates : specifies supported SDCC clock frequencies, Units - Hz.
- qcom,sdcc-sup-voltages: specifies supported voltage ranges for card. Should always be
specified in pairs (min, max), Units - mV.
diff --git a/Documentation/devicetree/bindings/usb/msm-hsusb.txt b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
index 62258ca..43e87a8 100644
--- a/Documentation/devicetree/bindings/usb/msm-hsusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
@@ -95,6 +95,10 @@
- qcom,descriptor-fifo-offset: descriptor fifo offset address
- qcom,descriptor-fifo-size: descriptor fifo size
+Optional properties :
+- qcom,ignore-core-reset-ack: If present then BAM ignores ACK from USB core
+ while performing PIPE RESET
+
Example USB BAM controller device node:
qcom,usbbam@f9304000 {
@@ -109,6 +113,7 @@
qcom,usb-total-bam-num = <2>;
qcom,usb-bam-num-pipes = <16>;
qcom,usb-base-address = <0xf9200000>;
+ qcom,ignore-core-reset-ack;
qcom,pipe1 {
label = "usb-to-peri-qdss-dwc3";
diff --git a/Documentation/devicetree/bindings/usb/msm-ssusb.txt b/Documentation/devicetree/bindings/usb/msm-ssusb.txt
index a2b7dfc..bff3732 100644
--- a/Documentation/devicetree/bindings/usb/msm-ssusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-ssusb.txt
@@ -3,6 +3,8 @@
Required properties :
- compatible : should be "qcom,dwc-usb3-msm"
- reg : offset and length of the register set in the memory map
+ offset and length of the TCSR register for routing USB
+ signals to either picoPHY0 or picoPHY1.
- interrupts: IRQ lines used by this controller
- interrupt-names : Required interrupt resource entries are:
"irq" : Interrupt for DWC3 core
@@ -18,7 +20,8 @@
Example MSM USB3.0 controller device node :
usb@f9200000 {
compatible = "qcom,dwc-usb3-msm";
- reg = <0xF9200000 0xFA000>;
+ reg = <0xF9200000 0xFA000>,
+ <0xFD4AB000 0x4>;
interrupts = <0 131 0 0 179 0>;
interrupt-names = "irq", "otg_irq";
SSUSB_VDDCX-supply = <&pm8841_s2>;
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index d249f21..d7ebcfe 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -4,6 +4,7 @@
select HAVE_AOUT
select HAVE_DMA_API_DEBUG
select HAVE_IDE if PCI || ISA || PCMCIA
+ select HAVE_DMA_CONTIGUOUS if (CPU_V6 || CPU_V6K || CPU_V7)
select HAVE_DMA_ATTRS
select HAVE_MEMBLOCK
select RTC_LIB
diff --git a/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi b/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi
new file mode 100644
index 0000000..1f7e488
--- /dev/null
+++ b/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi
@@ -0,0 +1,119 @@
+/* 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.
+ */
+
+&mdss_dsi {
+
+ qcom,mdss_dsi_toshiba_720p_video {
+ compatible = "qcom,mdss-dsi-panel";
+ label = "toshiba 720p video mode dsi panel";
+ status = "disable";
+ qcom,enable-gpio = <&msmgpio 58 0>;
+ qcom,rst-gpio = <&pm8941_gpios 19 0>;
+ qcom,mdss-pan-res = <720 1280>;
+ qcom,mdss-pan-bpp = <24>;
+ qcom,mdss-pan-porch-values = <32 12 144 3 4 9>;
+ qcom,mdss-pan-underflow-clr = <0xff>;
+ qcom,mdss-pan-bl-ctrl = "bl_ctrl_wled";
+ qcom,mdss-pan-bl-levels = <1 255>;
+ qcom,mdss-pan-dsi-mode = <0>;
+ qcom,mdss-pan-dsi-h-pulse-mode = <0>;
+ qcom,mdss-pan-dsi-h-power-stop = <0 0 0>;
+ qcom,mdss-pan-dsi-bllp-power-stop = <1 1>;
+ qcom,mdss-pan-dsi-traffic-mode = <1>;
+ qcom,mdss-pan-dsi-dst-format = <3>;
+ qcom,mdss-pan-dsi-vc = <0>;
+ qcom,mdss-pan-dsi-rgb-swap = <0>;
+ qcom,mdss-pan-dsi-data-lanes = <1 1 1 1>;
+ qcom,mdss-pan-dsi-t-clk = <0x1b 0x04>;
+ qcom,mdss-pan-dsi-stream = <0>;
+ qcom,mdss-pan-dsi-mdp-tr = <0x0>;
+ qcom,mdss-pan-dsi-dma-tr = <0x04>;
+ qcom,mdss-pan-frame-rate = <60>;
+ qcom,panel-phy-regulatorSettings = [03 01 01 00 /* Regualotor settings */
+ 20 00 01 00];
+ qcom,panel-phy-timingSettings = [69 29 1f 00 55 55
+ 19 2a 2a 03 04 00];
+ qcom,panel-phy-strengthCtrl = [77 06];
+ qcom,panel-phy-bistCtrl = [00 00 01 ff /* BIST Ctrl settings */
+ 00 00];
+ qcom,panel-phy-laneConfig = [05 c2 00 00 00 00 00 01 75 /* lane0 config */
+ 05 c2 00 00 00 00 00 01 75 /* lane1 config */
+ 05 c2 00 00 00 00 00 01 75 /* lane2 config */
+ 05 c2 00 00 00 00 00 01 75 /* lane3 config */
+ 00 c2 00 00 00 00 00 01 97]; /* Clk ln config */
+
+ qcom,panel-on-cmds = [23 01 00 00 0a 02 b0 00
+ 23 01 00 00 0a 02 b2 00
+ 23 01 00 00 0a 02 b3 0c
+ 23 01 00 00 0a 02 b4 02
+ 29 01 00 00 00 06
+ c0 40 02 7f c8 08
+ 29 01 00 00 00 10
+ c1 00 a8 00 00 00
+ 00 00 9d 08 27 00
+ 00 00 00 00
+ 29 01 00 00 00 06
+ c2 00 00 09 00 00
+ 23 01 00 00 0a 02 c3 04
+ 29 01 00 00 00 04
+ c4 4d 83 00
+ 29 01 00 00 00 0b
+ c6 12 00 08 71 00
+ 00 00 80 00 04
+ 23 01 00 00 0a 02 c7 22
+ 29 01 00 00 00 05
+ c8 4c 0c 0c 0c
+ 29 01 00 00 00 0e
+ c9 00 40 00 16 32
+ 2e 3a 43 3e 3c 45
+ 79 3f
+ 29 01 00 00 00 0e
+ ca 00 46 1a 23 21
+ 1c 25 31 2d 49 5f
+ 7f 3f
+ 29 01 00 00 00 0e
+ cb 00 4c 20 3a 42
+ 40 47 4b 42 3e 46
+ 7e 3f
+ 29 01 00 00 00 0e
+ cc 00 41 19 21 1d
+ 14 18 1f 1d 25 3f
+ 73 3f
+ 29 01 00 00 00 0e
+ cd 23 79 5a 5f 57
+ 4c 51 51 45 3f 4b
+ 7f 3f
+ 29 01 00 00 00 0e
+ ce 00 40 14 20 1a
+ 0e 0e 13 08 00 05
+ 46 1c
+ 29 01 00 00 00 04
+ d0 6a 64 01
+ 29 01 00 00 00 03 d1 77 d4
+ 23 01 00 00 0a 02 d3 33
+ 29 01 00 00 00 03 d5 0f 0f
+ 29 01 00 00 00 07
+ d8 34 64 23 25 62
+ 32
+ 29 01 00 00 00 0c
+ de 10 7b 11 0a 00
+ 00 00 00 00 00 00
+ 29 01 00 00 00 09
+ fd 04 55 53 00 70
+ ff 10 73
+ 23 01 00 00 0a 02 e2 00
+ 05 01 00 00 78 02 11 00
+ 05 01 00 00 32 02 29 00];
+ qcom,panel-off-cmds = [05 01 00 00 32 02 28 00
+ 05 01 00 00 78 02 10 00];
+ };
+};
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index 030d0e3..6347b51 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -750,5 +750,66 @@
compatible = "qcom,qpnp-regulator";
status = "disabled";
};
+
+ qcom,leds@d800 {
+ compatible = "qcom,leds-qpnp";
+ reg = <0xd800 0x100>;
+ qcom,label = "wled";
+ };
+
+ qcom,leds@d900 {
+ compatible = "qcom,leds-qpnp";
+ reg = <0xd900 0x100>;
+ qcom,label = "wled";
+ };
+
+ qcom,leds@da00 {
+ compatible = "qcom,leds-qpnp";
+ reg = <0xda00 0x100>;
+ qcom,label = "wled";
+ };
+
+ qcom,leds@db00 {
+ compatible = "qcom,leds-qpnp";
+ reg = <0xdb00 0x100>;
+ qcom,label = "wled";
+ };
+
+ qcom,leds@dc00 {
+ compatible = "qcom,leds-qpnp";
+ reg = <0xdc00 0x100>;
+ qcom,label = "wled";
+ };
+
+ qcom,leds@dd00 {
+ compatible = "qcom,leds-qpnp";
+ reg = <0xdd00 0x100>;
+ qcom,label = "wled";
+ };
+
+ qcom,leds@de00 {
+ compatible = "qcom,leds-qpnp";
+ reg = <0xde00 0x100>;
+ qcom,label = "wled";
+ };
+
+ qcom,leds@df00 {
+ compatible = "qcom,leds-qpnp";
+ reg = <0xdf00 0x100>;
+ qcom,label = "wled";
+ };
+
+ qcom,leds@e000 {
+ compatible = "qcom,leds-qpnp";
+ reg = <0xe000 0x100>;
+ qcom,label = "wled";
+ };
+
+ qcom,leds@e100 {
+ compatible = "qcom,leds-qpnp";
+ reg = <0xe100 0x100>;
+ qcom,label = "wled";
+ };
+
};
};
diff --git a/arch/arm/boot/dts/msm8974-camera.dtsi b/arch/arm/boot/dts/msm8974-camera.dtsi
index 0375e93..cf4f098 100644
--- a/arch/arm/boot/dts/msm8974-camera.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera.dtsi
@@ -19,6 +19,7 @@
reg = <0xfd8C0000 0x10000>;
reg-names = "server";
};
+
qcom,csiphy@fda0ac00 {
cell-index = <0>;
compatible = "qcom,csiphy";
@@ -27,6 +28,7 @@
interrupts = <0 78 0>;
interrupt-names = "csiphy";
};
+
qcom,csiphy@fda0b000 {
cell-index = <1>;
compatible = "qcom,csiphy";
@@ -35,6 +37,7 @@
interrupts = <0 79 0>;
interrupt-names = "csiphy";
};
+
qcom,csiphy@fda0b400 {
cell-index = <2>;
compatible = "qcom,csiphy";
@@ -43,6 +46,7 @@
interrupts = <0 80 0>;
interrupt-names = "csiphy";
};
+
qcom,csid@fda08000 {
cell-index = <0>;
compatible = "qcom,csid";
@@ -50,7 +54,9 @@
reg-names = "csid";
interrupts = <0 51 0>;
interrupt-names = "csid";
+ mipi_csi_vdd-supply = <&pm8941_l12>;
};
+
qcom,csid@fda08400 {
cell-index = <1>;
compatible = "qcom,csid";
@@ -58,7 +64,9 @@
reg-names = "csid";
interrupts = <0 52 0>;
interrupt-names = "csid";
+ mipi_csi_vdd-supply = <&pm8941_l12>;
};
+
qcom,csid@fda08800 {
cell-index = <2>;
compatible = "qcom,csid";
@@ -66,7 +74,9 @@
reg-names = "csid";
interrupts = <0 53 0>;
interrupt-names = "csid";
+ mipi_csi_vdd-supply = <&pm8941_l12>;
};
+
qcom,csid@fda08C00 {
cell-index = <3>;
compatible = "qcom,csid";
@@ -74,7 +84,9 @@
reg-names = "csid";
interrupts = <0 54 0>;
interrupt-names = "csid";
+ mipi_csi_vdd-supply = <&pm8941_l12>;
};
+
qcom,ispif@fda0A000 {
cell-index = <0>;
compatible = "qcom,ispif";
@@ -83,32 +95,29 @@
interrupts = <0 55 0>;
interrupt-names = "ispif";
};
- qcom,cci@fda0C000 {
- cell-index = <0>;
- compatible = "qcom,cci";
- reg = <0xfda0C000 0x1000>;
- reg-names = "cci";
- interrupts = <0 50 0>;
- interrupt-names = "cci";
- };
+
qcom,vfe@fda10000 {
cell-index = <0>;
compatible = "qcom,vfe40";
- reg = <0xfda10000 0x1000>;
- reg-names = "vfe";
+ reg = <0xfda10000 0x1000>,
+ <0xfda40000 0x200>;
+ reg-names = "vfe", "vfe_vbif";
interrupts = <0 57 0>;
interrupt-names = "vfe";
vdd-supply = <&gdsc_vfe>;
};
+
qcom,vfe@fda14000 {
cell-index = <1>;
compatible = "qcom,vfe40";
- reg = <0xfda14000 0x1000>;
- reg-names = "vfe";
+ reg = <0xfda14000 0x1000>,
+ <0xfda40000 0x200>;
+ reg-names = "vfe", "vfe_vbif";
interrupts = <0 58 0>;
interrupt-names = "vfe";
vdd-supply = <&gdsc_vfe>;
};
+
qcom,jpeg@fda1c000 {
cell-index = <0>;
compatible = "qcom,jpeg";
@@ -117,6 +126,7 @@
interrupts = <0 59 0>;
interrupt-names = "jpeg";
};
+
qcom,jpeg@fda20000 {
cell-index = <1>;
compatible = "qcom,jpeg";
@@ -125,6 +135,7 @@
interrupts = <0 60 0>;
interrupt-names = "jpeg";
};
+
qcom,jpeg@fda24000 {
cell-index = <2>;
compatible = "qcom,jpeg";
@@ -133,12 +144,14 @@
interrupts = <0 61 0>;
interrupt-names = "jpeg";
};
+
qcom,irqrouter@fda00000 {
cell-index = <0>;
compatible = "qcom,irqrouter";
reg = <0xfda00000 0x100>;
reg-names = "irqrouter";
};
+
qcom,cpp@fda04000 {
cell-index = <0>;
compatible = "qcom,cpp";
@@ -148,4 +161,98 @@
interrupt-names = "cpp";
vdd-supply = <&gdsc_vfe>;
};
+
+ qcom,cci@fda0C000 {
+ cell-index = <0>;
+ compatible = "qcom,cci";
+ reg = <0xfda0C000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+ reg-names = "cci";
+ interrupts = <0 50 0>;
+ interrupt-names = "cci";
+
+ qcom,camera@6e {
+ compatible = "qcom,s5k3l1yx";
+ reg = <0x6e 0x0>;
+ qcom,csi-if = <1>;
+ qcom,csid-core = <0>;
+ qcom,is-vpe = <1>;
+ qcom,flash-type = <0>;
+ qcom,mount-angle = <90>;
+ qcom,sensor-name = "s5k3l1yx";
+ cam_vdig-supply = <&pm8941_l3>;
+ cam_vana-supply = <&pm8941_l17>;
+ cam_vio-supply = <&pm8941_lvs3>;
+ cam_vaf-supply = <&pm8941_l23>;
+ qcom,cam-vreg-name = "cam_vdig", "cam_vana", "cam_vio",
+ "cam_vaf";
+ qcom,cam-vreg-type = <0 0 1 0>;
+ qcom,cam-vreg-min-voltage = <1225000 2850000 0 3000000>;
+ qcom,cam-vreg-max-voltage = <1225000 2850000 0 3000000>;
+ qcom,cam-vreg-op-mode = <105000 80000 0 100000>;
+ qcom,gpio-no-mux = <0>;
+ gpios = <&msmgpio 15 0>,
+ <&msmgpio 19 0>,
+ <&msmgpio 20 0>,
+ <&msmgpio 90 0>;
+ qcom,gpio-common-tbl-num = <0 1 2>;
+ qcom,gpio-common-tbl-flags = <1 1 1>;
+ qcom,gpio-common-tbl-label = "CAMIF_MCLK",
+ "CAMIF_I2C_DATA",
+ "CAMIF_I2C_CLK";
+ qcom,gpio-req-tbl-num = <3>;
+ qcom,gpio-req-tbl-flags = <0>;
+ qcom,gpio-req-tbl-label = "CAM_RESET1";
+ qcom,gpio-set-tbl-num = <3 3>;
+ qcom,gpio-set-tbl-flags = <0 2>;
+ qcom,gpio-set-tbl-delay = <1000 30000>;
+ qcom,csi-lane-assign = <0x4320>;
+ qcom,csi-lane-mask = <0x1F>;
+ qcom,csi-phy-sel = <0>;
+ qcom,camera-type = <0>;
+ qcom,sensor-type = <0>;
+ };
+
+ qcom,camera@6c {
+ compatible = "qcom,ov2720";
+ reg = <0x6c 0x0>;
+ qcom,csi-if = <1>;
+ qcom,csid-core = <1>;
+ qcom,is-vpe = <1>;
+ qcom,flash-type = <0>;
+ qcom,mount-angle = <0>;
+ qcom,sensor-name = "ov2720";
+ cam_vdig-supply = <&pm8941_l3>;
+ cam_vana-supply = <&pm8941_l17>;
+ cam_vio-supply = <&pm8941_lvs3>;
+ qcom,cam-vreg-name = "cam_vdig", "cam_vana", "cam_vio";
+ qcom,cam-vreg-type = <0 0 1>;
+ qcom,cam-vreg-min-voltage = <1225000 2850000 0>;
+ qcom,cam-vreg-max-voltage = <1225000 2850000 0>;
+ qcom,cam-vreg-op-mode = <105000 80000 0>;
+ qcom,gpio-no-mux = <0>;
+ gpios = <&msmgpio 16 0>,
+ <&msmgpio 19 0>,
+ <&msmgpio 20 0>,
+ <&msmgpio 92 0>;
+ qcom,gpio-common-tbl-num = <0 1 2>;
+ qcom,gpio-common-tbl-flags = <1 1 1>;
+ qcom,gpio-common-tbl-label = "CAMIF_MCLK",
+ "CAMIF_I2C_DATA",
+ "CAMIF_I2C_CLK";
+ qcom,gpio-req-tbl-num = <3>;
+ qcom,gpio-req-tbl-flags = <0>;
+ qcom,gpio-req-tbl-label = "CAM_RESET1";
+ qcom,gpio-set-tbl-num = <3 3>;
+ qcom,gpio-set-tbl-flags = <0 2>;
+ qcom,gpio-set-tbl-delay = <1000 4000>;
+ qcom,csi-lane-assign = <0x4320>;
+ qcom,csi-lane-mask = <0x7>;
+ qcom,csi-phy-sel = <1>;
+ qcom,camera-type = <0>;
+ qcom,sensor-type = <0>;
+ };
+ };
};
diff --git a/arch/arm/boot/dts/msm8974-cdp.dts b/arch/arm/boot/dts/msm8974-cdp.dts
index 8ae9583..e764e01 100644
--- a/arch/arm/boot/dts/msm8974-cdp.dts
+++ b/arch/arm/boot/dts/msm8974-cdp.dts
@@ -13,6 +13,7 @@
/dts-v1/;
/include/ "msm8974.dtsi"
+/include/ "dsi-panel-toshiba-720p-video.dtsi"
/ {
model = "Qualcomm MSM 8974 CDP";
@@ -22,16 +23,23 @@
serial@f991e000 {
status = "ok";
};
+
+ qcom,mdss_dsi@fd922800 {
+ qcom,mdss_dsi_toshiba_720p_video {
+ status = "ok";
+ };
+ };
};
&sdcc2 {
#address-cells = <0>;
interrupt-parent = <&sdcc2>;
- interrupts = <0 1>;
+ interrupts = <0 1 2>;
#interrupt-cells = <1>;
interrupt-map-mask = <0xffffffff>;
interrupt-map = <0 &intc 0 125 0
- 1 &msmgpio 62 0x3>;
- interrupt-names = "core_irq", "status_irq";
+ 1 &intc 0 220 0
+ 2 &msmgpio 62 0x3>;
+ interrupt-names = "core_irq", "bam_irq", "status_irq";
cd-gpios = <&msmgpio 62 0x1>;
};
diff --git a/arch/arm/boot/dts/msm8974-mdss.dtsi b/arch/arm/boot/dts/msm8974-mdss.dtsi
index de9173c7..dbaa492 100644
--- a/arch/arm/boot/dts/msm8974-mdss.dtsi
+++ b/arch/arm/boot/dts/msm8974-mdss.dtsi
@@ -22,8 +22,11 @@
mdss_dsi: qcom,mdss_dsi@fd922800 {
compatible = "qcom,msm-mdss-dsi";
- reg = <0xfd922800 0x5ac>,
+ reg = <0xfd922800 0x600>,
<0xfd8c2000 0x01000>;
+ vdd-supply = <&pm8941_l22>;
+ vdd_io-supply = <&pm8941_l12>;
+ vreg-supply = <&pm8941_l2>;
};
qcom,mdss_wb_panel {
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 1be0af9..7563576 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -101,10 +101,12 @@
sdcc1: qcom,sdcc@f9824000 {
cell-index = <1>; /* SDC1 eMMC slot */
compatible = "qcom,msm-sdcc";
- reg = <0xf9824000 0x1000>;
- reg-names = "core_mem";
- interrupts = <0 123 0>;
- interrupt-names = "core_irq";
+ reg = <0xf9824000 0x800>,
+ <0xf9824800 0x100>,
+ <0xf9804000 0x7000>;
+ reg-names = "core_mem", "dml_mem", "bam_mem";
+ interrupts = <0 123 0>, <0 137 0>;
+ interrupt-names = "core_irq", "bam_irq";
vdd-supply = <&pm8941_l20>;
vdd-io-supply = <&pm8941_s3>;
@@ -130,10 +132,12 @@
sdcc2: qcom,sdcc@f98a4000 {
cell-index = <2>; /* SDC2 SD card slot */
compatible = "qcom,msm-sdcc";
- reg = <0xf98a4000 0x1000>;
- reg-names = "core_mem";
- interrupts = <0 125 0>;
- interrupt-names = "core_irq";
+ reg = <0xf98a4000 0x800>,
+ <0xf98a4800 0x100>,
+ <0xf9884000 0x7000>;
+ reg-names = "core_mem", "dml_mem", "bam_mem";
+ interrupts = <0 125 0>, <0 220 0>;
+ interrupt-names = "core_irq", "bam_irq";
vdd-supply = <&pm8941_l21>;
vdd-io-supply = <&pm8941_l13>;
@@ -161,10 +165,12 @@
sdcc3: qcom,sdcc@f9864000 {
cell-index = <3>; /* SDC3 SDIO slot */
compatible = "qcom,msm-sdcc";
- reg = <0xf9864000 0x1000>;
- reg-names = "core_mem";
- interrupts = <0 127 0>;
- interrupt-names = "core_irq";
+ reg = <0xf9864000 0x800>,
+ <0xf9864800 0x100>,
+ <0xf9844000 0x7000>;
+ reg-names = "core_mem", "dml_mem", "bam_mem";
+ interrupts = <0 127 0>, <0 223 0>;
+ interrupt-names = "core_irq", "bam_irq";
gpios = <&msmgpio 40 0>, /* CLK */
<&msmgpio 39 0>, /* CMD */
@@ -184,10 +190,12 @@
sdcc4: qcom,sdcc@f98e4000 {
cell-index = <4>; /* SDC4 SDIO slot */
compatible = "qcom,msm-sdcc";
- reg = <0xf98e4000 0x1000>;
- reg-names = "core_mem";
- interrupts = <0 129 0>;
- interrupt-names = "core_irq";
+ reg = <0xf98e4000 0x800>,
+ <0xf98e4800 0x100>,
+ <0xf98c4000 0x7000>;
+ reg-names = "core_mem", "dml_mem", "bam_mem";
+ interrupts = <0 129 0>, <0 226 0>;
+ interrupt-names = "core_irq", "bam_irq";
gpios = <&msmgpio 93 0>, /* CLK */
<&msmgpio 91 0>, /* CMD */
@@ -419,14 +427,68 @@
<0x1e50008a>, /* LPG_CHAN10 */
<0x1e60008b>, /* LPG_CHAN11 */
<0x1e70008c>; /* LPG_CHAN12 */
+
+ qcom,pm8941@1 {
+ qcom,leds@d800 {
+ qcom,name = "wled:backlight";
+ linux,default-trigger = "bkl-trigger";
+ qcom,cs-out-en;
+ qcom,op-fdbck;
+ qcom,default-state = "on";
+ qcom,max-current = <25>;
+ qcom,ctrl-delay-us = <0>;
+ qcom,boost-curr-lim = <3>;
+ qcom,cp-sel = <0>;
+ qcom,switch-freq = <2>;
+ qcom,ovp-val = <2>;
+ qcom,num-strings = <1>;
+ status = "okay";
+ };
+
+ qcom,leds@d900 {
+ status = "disabled";
+ };
+
+ qcom,leds@da00 {
+ status = "disabled";
+ };
+
+ qcom,leds@db00 {
+ status = "disabled";
+ };
+
+ qcom,leds@dc00 {
+ status = "disabled";
+ };
+
+ qcom,leds@dd00 {
+ status = "disabled";
+ };
+
+ qcom,leds@de00 {
+ status = "disabled";
+ };
+
+ qcom,leds@df00 {
+ status = "disabled";
+ };
+
+ qcom,leds@e000 {
+ status = "disabled";
+ };
+
+ qcom,leds@e100 {
+ status = "disabled";
+ };
+ };
};
- i2c@f9966000 {
+ i2c@f9967000 {
cell-index = <0>;
compatible = "qcom,i2c-qup";
- reg = <0Xf9966000 0x1000>;
+ reg = <0Xf9967000 0x1000>;
reg-names = "qup_phys_addr";
- interrupts = <0 104 0>;
+ interrupts = <0 105 0>;
interrupt-names = "qup_err_intr";
qcom,i2c-bus-freq = <100000>;
qcom,i2c-src-freq = <24000000>;
@@ -551,7 +613,8 @@
qcom,ssusb@f9200000 {
compatible = "qcom,dwc-usb3-msm";
- reg = <0xf9200000 0xfc000>;
+ reg = <0xf9200000 0xfc000>,
+ <0xfd4ab000 0x4>;
interrupts = <0 131 0 0 179 0>;
interrupt-names = "irq", "otg_irq";
SSUSB_VDDCX-supply = <&pm8841_s2>;
@@ -828,6 +891,7 @@
qcom,usb-total-bam-num = <2>;
qcom,usb-bam-num-pipes = <16>;
qcom,usb-base-address = <0xf9200000>;
+ qcom,ignore-core-reset-ack;
qcom,pipe1 {
label = "usb-to-peri-qdss-dwc3";
@@ -925,6 +989,12 @@
debounce-interval = <15>;
};
};
+
+ qcom,bam_dmux@fc834000 {
+ compatible = "qcom,bam_dmux";
+ reg = <0xfc834000 0x7000>;
+ interrupts = <0 29 1>;
+ };
};
/include/ "msm-pm8x41-rpm-regulator.dtsi"
diff --git a/arch/arm/boot/dts/msm8974_pm.dtsi b/arch/arm/boot/dts/msm8974_pm.dtsi
index 476f2b5..82d317d 100644
--- a/arch/arm/boot/dts/msm8974_pm.dtsi
+++ b/arch/arm/boot/dts/msm8974_pm.dtsi
@@ -20,7 +20,7 @@
reg = <0xf9089000 0x1000>;
qcom,core-id = <0>;
qcom,saw2-ver-reg = <0xfd0>;
- qcom,saw2-cfg = <0x1b>;
+ qcom,saw2-cfg = <0x01>;
qcom,saw2-avs-ctl = <0>;
qcom,saw2-avs-hysteresis = <0>;
qcom,saw2-avs-limit = <0>;
@@ -28,11 +28,10 @@
qcom,saw2-spm-dly= <0x20000400>;
qcom,saw2-spm-ctl = <0x1>;
qcom,saw2-spm-cmd-wfi = [03 0b 0f];
- qcom,saw2-spm-cmd-spc = [00 20 50 80 60 70 10 92
- a0 b0 03 68 70 3b 92 a0 b0
- 82 2b 50 10 30 02 22 30 0f];
- qcom,saw2-spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
- a0 b0 82 10 30 02 22 30 0f];
+ qcom,saw2-spm-cmd-spc = [00 20 80 10 90 a0 b0 03 3b 98 a2 b0 82
+ 10 0b 30 06 26 30 0f];
+ qcom,saw2-spm-cmd-pc = [00 20 80 10 90 a0 b0 07 3b 98 a2 b0 82
+ 10 0b 30 06 26 30 0f];
};
qcom,spm@f9099000 {
@@ -42,7 +41,7 @@
reg = <0xf9099000 0x1000>;
qcom,core-id = <1>;
qcom,saw2-ver-reg = <0xfd0>;
- qcom,saw2-cfg = <0x1b>;
+ qcom,saw2-cfg = <0x01>;
qcom,saw2-avs-ctl = <0>;
qcom,saw2-avs-hysteresis = <0>;
qcom,saw2-avs-limit = <0>;
@@ -50,11 +49,10 @@
qcom,saw2-spm-dly= <0x20000400>;
qcom,saw2-spm-ctl = <0x1>;
qcom,saw2-spm-cmd-wfi = [03 0b 0f];
- qcom,saw2-spm-cmd-spc = [00 20 50 80 60 70 10 92
- a0 b0 03 68 70 3b 92 a0 b0
- 82 2b 50 10 30 02 22 30 0f];
- qcom,saw2-spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
- a0 b0 82 10 30 02 22 30 0f];
+ qcom,saw2-spm-cmd-spc = [00 20 80 10 90 a0 b0 03 3b 98 a2 b0 82
+ 10 0b 30 06 26 30 0f];
+ qcom,saw2-spm-cmd-pc = [00 20 80 10 90 a0 b0 07 3b 98 a2 b0 82
+ 10 0b 30 06 26 30 0f];
};
qcom,spm@f90a9000 {
@@ -64,7 +62,7 @@
reg = <0xf90a9000 0x1000>;
qcom,core-id = <2>;
qcom,saw2-ver-reg = <0xfd0>;
- qcom,saw2-cfg = <0x1b>;
+ qcom,saw2-cfg = <0x01>;
qcom,saw2-avs-ctl = <0>;
qcom,saw2-avs-hysteresis = <0>;
qcom,saw2-avs-limit = <0>;
@@ -72,11 +70,10 @@
qcom,saw2-spm-dly= <0x20000400>;
qcom,saw2-spm-ctl = <0x1>;
qcom,saw2-spm-cmd-wfi = [03 0b 0f];
- qcom,saw2-spm-cmd-spc = [00 20 50 80 60 70 10 92
- a0 b0 03 68 70 3b 92 a0 b0
- 82 2b 50 10 30 02 22 30 0f];
- qcom,saw2-spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
- a0 b0 82 10 30 02 22 30 0f];
+ qcom,saw2-spm-cmd-spc = [00 20 80 10 90 a0 b0 03 3b 98 a2 b0 82
+ 10 0b 30 06 26 30 0f];
+ qcom,saw2-spm-cmd-pc = [00 20 80 10 90 a0 b0 07 3b 98 a2 b0 82
+ 10 0b 30 06 26 30 0f];
};
qcom,spm@f90b9000 {
@@ -86,7 +83,7 @@
reg = <0xf90b9000 0x1000>;
qcom,core-id = <3>;
qcom,saw2-ver-reg = <0xfd0>;
- qcom,saw2-cfg = <0x1b>;
+ qcom,saw2-cfg = <0x01>;
qcom,saw2-avs-ctl = <0>;
qcom,saw2-avs-hysteresis = <0>;
qcom,saw2-avs-limit = <0>;
@@ -94,11 +91,10 @@
qcom,saw2-spm-dly= <0x20000400>;
qcom,saw2-spm-ctl = <0x1>;
qcom,saw2-spm-cmd-wfi = [03 0b 0f];
- qcom,saw2-spm-cmd-spc = [00 20 50 80 60 70 10 92
- a0 b0 03 68 70 3b 92 a0 b0
- 82 2b 50 10 30 02 22 30 0f];
- qcom,saw2-spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
- a0 b0 82 10 30 02 22 30 0f];
+ qcom,saw2-spm-cmd-spc = [00 20 80 10 90 a0 b0 03 3b 98 a2 b0 82
+ 10 0b 30 06 26 30 0f];
+ qcom,saw2-spm-cmd-pc = [00 20 80 10 90 a0 b0 07 3b 98 a2 b0 82
+ 10 0b 30 06 26 30 0f];
};
qcom,spm@f9012000 {
@@ -108,28 +104,26 @@
reg = <0xf9012000 0x1000>;
qcom,core-id = <0xffff>; /* L2/APCS SAW */
qcom,saw2-ver-reg = <0xfd0>;
- qcom,saw2-cfg = <0x1a>;
+ qcom,saw2-cfg = <0x14>;
qcom,saw2-avs-ctl = <0>;
qcom,saw2-avs-hysteresis = <0>;
qcom,saw2-avs-limit = <0>;
qcom,saw2-avs-dly= <0>;
qcom,saw2-spm-dly= <0x20000400>;
- qcom,saw2-spm-ctl = <0x0>; /* TODO: Enable L2 SPM */
+ qcom,saw2-spm-ctl = <0x1>;
qcom,saw2-pmic-dly = <0x02020204>;
qcom,saw2-pmic-data0 = <0x0400009c>;
qcom,saw2-pmic-data1 = <0x00000060>;
qcom,saw2-pmic-data2 = <0x0000001c>;
qcom,saw2-pmic-data3 = <0x04000000>;
qcom,vctl-timeout-us = <50>;
- qcom,vctl-port = <0x0>; /* TODO: */
- qcom,phase-port = <0x1>; /* TODO: */
+ qcom,vctl-port = <0x0>;
+ qcom,phase-port = <0x1>;
qcom,saw2-spm-cmd-ret = [0b 00 20 03 22 00 0f];
- qcom,saw2-spm-cmd-gdhs = [00 20 32 60 70 80 0b 42 07
- 78 80 44 22 50 3b 60 02 32
- 50 0f];
- qcom,saw2-spm-cmd-pc = [00 10 32 60 70 80 b0 11 0b
- 42 07 01 b0 78 80 12 44 a0 50
- 3b 60 02 32 a0 50 0f];
+ qcom,saw2-spm-cmd-gdhs = [00 20 32 0b 42 07 44 22 50 02 32 50
+ 0f];
+ qcom,saw2-spm-cmd-pc = [00 10 32 b0 11 0b 42 07 01 b0 12 44 a0
+ 50 02 32 a0 50 0f];
};
qcom,lpm-resources {
diff --git a/arch/arm/common/cpaccess.c b/arch/arm/common/cpaccess.c
index 12e2c38..85cd09f 100644
--- a/arch/arm/common/cpaccess.c
+++ b/arch/arm/common/cpaccess.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-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
@@ -149,7 +149,8 @@
asm volatile (".globl cpaccess_dummy_inst\n"
"cpaccess_dummy_inst:\n\t"
- "mrc p15, 0, %0, c0, c0, 0\n\t" : "=r" (ret));
+ "mrc p15, 0, %0, c0, c0, 0\n\t" : "=r" (ret) :
+ "r" (write_val));
return ret;
} __attribute__((aligned(32)))
diff --git a/arch/arm/configs/msm8660-perf_defconfig b/arch/arm/configs/msm8660-perf_defconfig
index c8f9212..957dbcf 100644
--- a/arch/arm/configs/msm8660-perf_defconfig
+++ b/arch/arm/configs/msm8660-perf_defconfig
@@ -70,6 +70,7 @@
CONFIG_MSM_PIL_DSPS=y
CONFIG_MSM_PIL_VIDC=y
CONFIG_MSM_SUBSYSTEM_RESTART=y
+CONFIG_MSM_SYSMON_COMM=y
CONFIG_MSM_TZ_LOG=y
CONFIG_MSM_RPM_LOG=y
CONFIG_MSM_RPM_STATS_LOG=y
@@ -86,6 +87,7 @@
CONFIG_AEABI=y
CONFIG_HIGHMEM=y
CONFIG_VMALLOC_RESERVE=0x19000000
+CONFIG_COMPACTION=y
CONFIG_CP_ACCESS=y
CONFIG_CPU_FREQ=y
CONFIG_CPU_FREQ_GOV_POWERSAVE=y
diff --git a/arch/arm/configs/msm8660_defconfig b/arch/arm/configs/msm8660_defconfig
index 2eba8ab..4e5479a 100644
--- a/arch/arm/configs/msm8660_defconfig
+++ b/arch/arm/configs/msm8660_defconfig
@@ -69,6 +69,7 @@
CONFIG_MSM_PIL_DSPS=y
CONFIG_MSM_PIL_VIDC=y
CONFIG_MSM_SUBSYSTEM_RESTART=y
+CONFIG_MSM_SYSMON_COMM=y
CONFIG_MSM_TZ_LOG=y
CONFIG_MSM_RPM_LOG=y
CONFIG_MSM_RPM_STATS_LOG=y
@@ -86,6 +87,7 @@
CONFIG_AEABI=y
CONFIG_HIGHMEM=y
CONFIG_VMALLOC_RESERVE=0x19000000
+CONFIG_COMPACTION=y
CONFIG_CP_ACCESS=y
CONFIG_CPU_FREQ=y
CONFIG_CPU_FREQ_GOV_POWERSAVE=y
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index 408175d..5ec9517 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -77,6 +77,7 @@
CONFIG_MSM_PIL_VIDC=y
CONFIG_MSM_PIL_GSS=y
CONFIG_MSM_SUBSYSTEM_RESTART=y
+CONFIG_MSM_SYSMON_COMM=y
CONFIG_MSM_MODEM_8960=y
CONFIG_MSM_LPASS_8960=y
CONFIG_MSM_WCNSS_SSR_8960=y
@@ -114,6 +115,7 @@
CONFIG_CPU_FREQ_GOV_POWERSAVE=y
CONFIG_CPU_FREQ_GOV_USERSPACE=y
CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_INTERACTIVE=y
CONFIG_CPU_IDLE=y
CONFIG_VFP=y
CONFIG_NEON=y
@@ -293,6 +295,7 @@
CONFIG_STM_LIS3DH=y
CONFIG_INPUT_MPU3050=y
# CONFIG_LEGACY_PTYS is not set
+CONFIG_MSM_IPC_LOGGING=y
CONFIG_N_SMUX=y
CONFIG_N_SMUX_LOOPBACK=y
CONFIG_SMUX_CTL=y
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index 7a4bf08..023114e 100644
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -76,6 +76,7 @@
CONFIG_MSM_PIL_VIDC=y
CONFIG_MSM_PIL_GSS=y
CONFIG_MSM_SUBSYSTEM_RESTART=y
+CONFIG_MSM_SYSMON_COMM=y
CONFIG_MSM_MODEM_8960=y
CONFIG_MSM_LPASS_8960=y
CONFIG_MSM_WCNSS_SSR_8960=y
@@ -118,6 +119,7 @@
CONFIG_CPU_FREQ_GOV_POWERSAVE=y
CONFIG_CPU_FREQ_GOV_USERSPACE=y
CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_INTERACTIVE=y
CONFIG_CPU_IDLE=y
CONFIG_VFP=y
CONFIG_NEON=y
@@ -297,6 +299,7 @@
CONFIG_STM_LIS3DH=y
CONFIG_INPUT_MPU3050=y
# CONFIG_LEGACY_PTYS is not set
+CONFIG_MSM_IPC_LOGGING=y
CONFIG_N_SMUX=y
CONFIG_N_SMUX_LOOPBACK=y
CONFIG_SMUX_CTL=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index 719933f..258470c 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -148,6 +148,7 @@
CONFIG_I2C=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_QUP=y
+CONFIG_MSM_BUS_SCALING=y
CONFIG_SPI=y
CONFIG_SPI_QUP=y
CONFIG_SPI_SPIDEV=m
@@ -168,12 +169,22 @@
CONFIG_REGULATOR_STUB=y
CONFIG_REGULATOR_QPNP=y
CONFIG_MEDIA_SUPPORT=y
+CONFIG_MEDIA_CONTROLLER=y
CONFIG_VIDEO_DEV=y
-# CONFIG_RC_CORE is not set
-# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
+CONFIG_VIDEO_V4L2_SUBDEV_API=y
CONFIG_VIDEOBUF2_MSM_MEM=y
-# CONFIG_VIDEO_CAPTURE_DRIVERS is not set
-# CONFIG_RADIO_ADAPTERS is not set
+CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_MSM_CAMERA_V4L2=y
+CONFIG_MSM_CAMERA_SENSOR=y
+CONFIG_MSM_ACTUATOR=y
+CONFIG_MSM_CAM_IRQ_ROUTER=n
+CONFIG_MSM_CCI=y
+CONFIG_MSM_CSI30_HEADER=y
+CONFIG_MSM_CSIPHY=y
+CONFIG_MSM_CSID=y
+CONFIG_MSM_CSI2_REGISTER=y
+CONFIG_MSM_ISPIF=y
+CONFIG_S5K3L1YX=y
CONFIG_ION=y
CONFIG_ION_MSM=y
CONFIG_MSM_KGSL=y
@@ -218,6 +229,13 @@
# CONFIG_MMC_BLOCK_BOUNCE is not set
CONFIG_MMC_TEST=m
CONFIG_MMC_MSM=y
+CONFIG_MMC_MSM_SPS_SUPPORT=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_QPNP=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_BACKLIGHT=y
+CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
CONFIG_SWITCH=y
CONFIG_RTC_CLASS=y
# CONFIG_RTC_DRV_MSM is not set
@@ -231,6 +249,7 @@
CONFIG_ANDROID_LOW_MEMORY_KILLER=y
CONFIG_MSM_SSBI=y
CONFIG_SPS=y
+CONFIG_USB_BAM=y
CONFIG_SPS_SUPPORT_BAMDMA=y
CONFIG_SPS_SUPPORT_NDP_BAM=y
CONFIG_QPNP_POWER_ON=y
@@ -255,6 +274,7 @@
# CONFIG_DEBUG_PREEMPT is not set
CONFIG_DEBUG_INFO=y
CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_ENABLE_DEFAULT_TRACERS=y
CONFIG_DYNAMIC_DEBUG=y
CONFIG_DEBUG_USER=y
CONFIG_KEYS=y
@@ -284,3 +304,4 @@
CONFIG_RADIO_IRIS=y
CONFIG_RADIO_IRIS_TRANSPORT=m
+CONFIG_MSM_BAM_DMUX=y
diff --git a/arch/arm/configs/msm9615_defconfig b/arch/arm/configs/msm9615_defconfig
index db94f13..b8417fe 100644
--- a/arch/arm/configs/msm9615_defconfig
+++ b/arch/arm/configs/msm9615_defconfig
@@ -147,6 +147,10 @@
CONFIG_IP6_NF_TARGET_REJECT_SKERR=y
CONFIG_IP6_NF_MANGLE=y
CONFIG_IP6_NF_RAW=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_HTB=y
+CONFIG_NET_SCH_PRIO=y
+CONFIG_NET_CLS_FW=y
CONFIG_MTD=y
CONFIG_MTD_TESTS=m
CONFIG_MTD_CMDLINE_PARTS=y
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index e41ab0a..42dda69 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -1826,6 +1826,24 @@
be used on systems which contain an RPM which communicates with the
application processor over SMD.
+config MSM_SUBSYSTEM_RESTART
+ bool "MSM Subsystem Restart"
+ help
+ This option enables the MSM subsystem restart framework.
+
+ The MSM subsystem restart framework provides support to boot,
+ shutdown, and restart subsystems with a reference counted API.
+ It also notifies userspace of transitions between these states via
+ sysfs.
+
+config MSM_SYSMON_COMM
+ bool "MSM System Monitor communication support"
+ depends on MSM_SMD && MSM_SUBSYSTEM_RESTART
+ help
+ This option adds support for MSM System Monitor library, which
+ provides an API that may be used for notifying subsystems within
+ the SoC about other subsystems' power-up/down state-changes.
+
config MSM_PIL
bool "Peripheral image loading"
select FW_LOADER
@@ -1937,23 +1955,6 @@
bool "Secure Channel Manager (SCM) support"
default n
-config MSM_SUBSYSTEM_RESTART
- bool "MSM Subsystem Restart Driver"
- depends on (ARCH_MSM8X60 || ARCH_MSM8960 || ARCH_MSM9615)
- default n
- help
- This option enables the MSM subsystem restart driver, which provides
- a framework to handle subsystem crashes.
-
-config MSM_SYSMON_COMM
- bool "MSM System Monitor communication support"
- depends on MSM_SMD && MSM_SUBSYSTEM_RESTART
- default y
- help
- This option adds support for MSM System Monitor library, which
- provides an API that may be used for notifying subsystems within
- the SoC about other subsystems' power-up/down state-changes.
-
config MSM_MODEM_8960
bool "MSM 8960 Modem driver"
depends on (ARCH_MSM8960 || ARCH_MSM9615)
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index f27889b..da3d3c4 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -276,9 +276,9 @@
obj-$(CONFIG_MACH_MSM8960_CDP) += board-8960-all.o board-8960-regulator.o
obj-$(CONFIG_MACH_MSM8960_MTP) += board-8960-all.o board-8960-regulator.o
obj-$(CONFIG_MACH_MSM8960_FLUID) += board-8960-all.o board-8960-regulator.o
-obj-$(CONFIG_MACH_MSM8930_CDP) += board-8930-all.o board-8930-regulator.o
-obj-$(CONFIG_MACH_MSM8930_MTP) += board-8930-all.o board-8930-regulator.o
-obj-$(CONFIG_MACH_MSM8930_FLUID) += board-8930-all.o board-8930-regulator.o
+obj-$(CONFIG_MACH_MSM8930_CDP) += board-8930-all.o board-8930-regulator-pm8038.o board-8930-regulator-pm8917.o
+obj-$(CONFIG_MACH_MSM8930_MTP) += board-8930-all.o board-8930-regulator-pm8038.o board-8930-regulator-pm8917.o
+obj-$(CONFIG_MACH_MSM8930_FLUID) += board-8930-all.o board-8930-regulator-pm8038.o board-8930-regulator-pm8917.o
obj-$(CONFIG_PM8921_BMS) += bms-batterydata.o bms-batterydata-desay.o
obj-$(CONFIG_MACH_APQ8064_CDP) += board-8064-all.o board-8064-regulator.o
obj-$(CONFIG_MACH_APQ8064_MTP) += board-8064-all.o board-8064-regulator.o
diff --git a/arch/arm/mach-msm/acpuclock-8930.c b/arch/arm/mach-msm/acpuclock-8930.c
index 5647d14..782ee60 100644
--- a/arch/arm/mach-msm/acpuclock-8930.c
+++ b/arch/arm/mach-msm/acpuclock-8930.c
@@ -45,6 +45,39 @@
.vdd[HFPLL_VDD_HIGH] = LVL_HIGH,
};
+static struct scalable scalable_pm8917[] __initdata = {
+ [CPU0] = {
+ .hfpll_phys_base = 0x00903200,
+ .aux_clk_sel_phys = 0x02088014,
+ .aux_clk_sel = 3,
+ .l2cpmr_iaddr = 0x4501,
+ .vreg[VREG_CORE] = { "krait0", 1300000 },
+ .vreg[VREG_MEM] = { "krait0_mem", 1150000 },
+ .vreg[VREG_DIG] = { "krait0_dig", 1150000 },
+ .vreg[VREG_HFPLL_A] = { "krait0_s8", 2050000 },
+ .vreg[VREG_HFPLL_B] = { "krait0_l23", 1800000 },
+ },
+ [CPU1] = {
+ .hfpll_phys_base = 0x00903300,
+ .aux_clk_sel_phys = 0x02098014,
+ .aux_clk_sel = 3,
+ .l2cpmr_iaddr = 0x5501,
+ .vreg[VREG_CORE] = { "krait1", 1300000 },
+ .vreg[VREG_MEM] = { "krait1_mem", 1150000 },
+ .vreg[VREG_DIG] = { "krait1_dig", 1150000 },
+ .vreg[VREG_HFPLL_A] = { "krait1_s8", 2050000 },
+ .vreg[VREG_HFPLL_B] = { "krait1_l23", 1800000 },
+ },
+ [L2] = {
+ .hfpll_phys_base = 0x00903400,
+ .aux_clk_sel_phys = 0x02011028,
+ .aux_clk_sel = 3,
+ .l2cpmr_iaddr = 0x0500,
+ .vreg[VREG_HFPLL_A] = { "l2_s8", 2050000 },
+ .vreg[VREG_HFPLL_B] = { "l2_l23", 1800000 },
+ },
+};
+
static struct scalable scalable[] __initdata = {
[CPU0] = {
.hfpll_phys_base = 0x00903200,
@@ -193,6 +226,10 @@
static int __init acpuclk_8930_probe(struct platform_device *pdev)
{
+ struct acpuclk_platform_data *pdata = pdev->dev.platform_data;
+ if (pdata && pdata->uses_pm8917)
+ acpuclk_8930_params.scalable = scalable_pm8917;
+
return acpuclk_krait_init(&pdev->dev, &acpuclk_8930_params);
}
diff --git a/arch/arm/mach-msm/acpuclock-8960ab.c b/arch/arm/mach-msm/acpuclock-8960ab.c
index 1097907..3c42090 100644
--- a/arch/arm/mach-msm/acpuclock-8960ab.c
+++ b/arch/arm/mach-msm/acpuclock-8960ab.c
@@ -124,6 +124,10 @@
{ 0, { 1404000, HFPLL, 1, 0, 0x34 }, L2(9), 1237500 },
{ 1, { 1458000, HFPLL, 1, 0, 0x36 }, L2(9), 1237500 },
{ 1, { 1512000, HFPLL, 1, 0, 0x38 }, L2(9), 1250000 },
+ { 1, { 1566000, HFPLL, 1, 0, 0x3A }, L2(9), 1250000 },
+ { 1, { 1620000, HFPLL, 1, 0, 0x3C }, L2(9), 1250000 },
+ { 1, { 1674000, HFPLL, 1, 0, 0x3E }, L2(9), 1250000 },
+ { 1, { 1728000, HFPLL, 1, 0, 0x40 }, L2(9), 1250000 },
{ 0, { 0 } }
};
diff --git a/arch/arm/mach-msm/acpuclock-krait.h b/arch/arm/mach-msm/acpuclock-krait.h
index 5a95e76..1b891b1 100644
--- a/arch/arm/mach-msm/acpuclock-krait.h
+++ b/arch/arm/mach-msm/acpuclock-krait.h
@@ -253,9 +253,16 @@
};
/**
+ * struct acpuclk_platform_data - PMIC configuration data.
+ * @uses_pm8917: Boolean indicates presence of pm8917.
+ */
+struct acpuclk_platform_data {
+ bool uses_pm8917;
+};
+
+/**
* acpuclk_krait_init - Initialize the Krait CPU clock driver give SoC params.
*/
extern int acpuclk_krait_init(struct device *dev,
const struct acpuclk_krait_params *params);
-
#endif
diff --git a/arch/arm/mach-msm/bam_dmux.c b/arch/arm/mach-msm/bam_dmux.c
index 125094d..fbc3e25 100644
--- a/arch/arm/mach-msm/bam_dmux.c
+++ b/arch/arm/mach-msm/bam_dmux.c
@@ -27,6 +27,7 @@
#include <linux/clk.h>
#include <linux/wakelock.h>
#include <linux/kfifo.h>
+#include <linux/of.h>
#include <mach/sps.h>
#include <mach/bam_dmux.h>
@@ -175,6 +176,14 @@
#define A2_PHYS_SIZE 0x2000
#define BUFFER_SIZE 2048
#define NUM_BUFFERS 32
+
+#ifndef A2_BAM_IRQ
+#define A2_BAM_IRQ -1
+#endif
+
+static void *a2_phys_base;
+static uint32_t a2_phys_size;
+static int a2_bam_irq;
static struct sps_bam_props a2_props;
static u32 a2_device_handle;
static struct sps_pipe *bam_tx_pipe;
@@ -2028,16 +2037,17 @@
vote_dfab();
/* init BAM */
- a2_virt_addr = ioremap_nocache(A2_PHYS_BASE, A2_PHYS_SIZE);
+ a2_virt_addr = ioremap_nocache((unsigned long)(a2_phys_base),
+ a2_phys_size);
if (!a2_virt_addr) {
pr_err("%s: ioremap failed\n", __func__);
ret = -ENOMEM;
goto ioremap_failed;
}
- a2_props.phys_addr = A2_PHYS_BASE;
+ a2_props.phys_addr = (u32)(a2_phys_base);
a2_props.virt_addr = a2_virt_addr;
- a2_props.virt_size = A2_PHYS_SIZE;
- a2_props.irq = A2_BAM_IRQ;
+ a2_props.virt_size = a2_phys_size;
+ a2_props.irq = a2_bam_irq;
a2_props.options = SPS_BAM_OPT_IRQ_WAKEUP;
a2_props.num_pipes = A2_NUM_PIPES;
a2_props.summing_threshold = A2_SUMMING_THRESHOLD;
@@ -2199,16 +2209,17 @@
void *a2_virt_addr;
/* init BAM */
- a2_virt_addr = ioremap_nocache(A2_PHYS_BASE, A2_PHYS_SIZE);
+ a2_virt_addr = ioremap_nocache((unsigned long)(a2_phys_base),
+ a2_phys_size);
if (!a2_virt_addr) {
pr_err("%s: ioremap failed\n", __func__);
ret = -ENOMEM;
goto ioremap_failed;
}
- a2_props.phys_addr = A2_PHYS_BASE;
+ a2_props.phys_addr = (u32)(a2_phys_base);
a2_props.virt_addr = a2_virt_addr;
- a2_props.virt_size = A2_PHYS_SIZE;
- a2_props.irq = A2_BAM_IRQ;
+ a2_props.virt_size = a2_phys_size;
+ a2_props.irq = a2_bam_irq;
a2_props.options = SPS_BAM_OPT_IRQ_WAKEUP;
a2_props.num_pipes = A2_NUM_PIPES;
a2_props.summing_threshold = A2_SUMMING_THRESHOLD;
@@ -2321,11 +2332,35 @@
static int bam_dmux_probe(struct platform_device *pdev)
{
int rc;
+ struct resource *r;
DBG("%s probe called\n", __func__);
if (bam_mux_initialized)
return 0;
+ if (pdev->dev.of_node) {
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!r) {
+ pr_err("%s: reg field missing\n", __func__);
+ return -ENODEV;
+ }
+ a2_phys_base = (void *)(r->start);
+ a2_phys_size = (uint32_t)(resource_size(r));
+ a2_bam_irq = platform_get_irq(pdev, 0);
+ if (a2_bam_irq == -ENXIO) {
+ pr_err("%s: irq field missing\n", __func__);
+ return -ENODEV;
+ }
+ DBG("%s: base:%p size:%x irq:%d\n", __func__,
+ a2_phys_base,
+ a2_phys_size,
+ a2_bam_irq);
+ } else { /* fallback to default init data */
+ a2_phys_base = (void *)(A2_PHYS_BASE);
+ a2_phys_size = A2_PHYS_SIZE;
+ a2_bam_irq = A2_BAM_IRQ;
+ }
+
xo_clk = clk_get(&pdev->dev, "xo");
if (IS_ERR(xo_clk)) {
bam_dmux_log("%s: did not get xo clock\n", __func__);
@@ -2409,11 +2444,17 @@
return 0;
}
+static struct of_device_id msm_match_table[] = {
+ {.compatible = "qcom,bam_dmux"},
+ {},
+};
+
static struct platform_driver bam_dmux_driver = {
.probe = bam_dmux_probe,
.driver = {
.name = "BAM_RMNT",
.owner = THIS_MODULE,
+ .of_match_table = msm_match_table,
},
};
diff --git a/arch/arm/mach-msm/bms-batterydata.c b/arch/arm/mach-msm/bms-batterydata.c
index 77e7dab..81ab121 100644
--- a/arch/arm/mach-msm/bms-batterydata.c
+++ b/arch/arm/mach-msm/bms-batterydata.c
@@ -12,116 +12,97 @@
#include <linux/mfd/pm8xxx/pm8921-bms.h>
-static struct single_row_lut palladium_1500_fcc_temp = {
- .x = {-30, -20, -10, 0, 10, 25, 40, 60},
- .y = {1103, 1179, 1284, 1330, 1420, 1511, 1541, 1571},
- .cols = 8,
+static struct single_row_lut fcc_temp = {
+ .x = {-20, 0, 25, 40, 65},
+ .y = {1492, 1492, 1493, 1483, 1502},
+ .cols = 5
};
-static struct single_row_lut palladium_1500_fcc_sf = {
- .x = {100, 200, 300, 400, 500},
- .y = {97, 93, 93, 90, 87},
- .cols = 5,
-};
-
-static struct sf_lut palladium_1500_pc_sf = {
- .rows = 10,
+static struct pc_temp_ocv_lut pc_temp_ocv = {
+ .rows = 29,
.cols = 5,
- /* row_entries are chargecycles */
- .row_entries = {100, 200, 300, 400, 500},
- .percent = {100, 90, 80, 70, 60, 50, 40, 30, 20, 10},
- .sf = {
- {97, 93, 93, 90, 87},
- {97, 93, 93, 90, 87},
- {98, 94, 92, 89, 86},
- {98, 94, 92, 89, 86},
- {99, 94, 92, 88, 86},
- {99, 95, 92, 88, 87},
- {99, 95, 92, 88, 87},
- {99, 95, 92, 88, 87},
- {99, 95, 92, 88, 87},
- {99, 95, 92, 88, 87}
- },
+ .temp = {-20, 0, 25, 40, 65},
+ .percent = {100, 95, 90, 85, 80, 75, 70, 65, 60, 55, 50, 45, 40,
+ 35, 30, 25, 20, 15, 10, 9, 8, 7, 6, 5,
+ 4, 3, 2, 1, 0},
+ .ocv = {
+ {4173, 4167, 4163, 4156, 4154},
+ {4104, 4107, 4108, 4102, 4104},
+ {4057, 4072, 4069, 4061, 4060},
+ {3973, 4009, 4019, 4016, 4020},
+ {3932, 3959, 3981, 3982, 3983},
+ {3899, 3928, 3954, 3950, 3950},
+ {3868, 3895, 3925, 3921, 3920},
+ {3837, 3866, 3898, 3894, 3892},
+ {3812, 3841, 3853, 3856, 3862},
+ {3794, 3818, 3825, 3823, 3822},
+ {3780, 3799, 3804, 3804, 3803},
+ {3768, 3787, 3790, 3788, 3788},
+ {3757, 3779, 3778, 3775, 3776},
+ {3747, 3772, 3771, 3766, 3765},
+ {3736, 3763, 3766, 3760, 3746},
+ {3725, 3749, 3756, 3747, 3729},
+ {3714, 3718, 3734, 3724, 3706},
+ {3701, 3703, 3696, 3689, 3668},
+ {3675, 3695, 3682, 3675, 3662},
+ {3670, 3691, 3680, 3673, 3661},
+ {3661, 3686, 3679, 3672, 3656},
+ {3649, 3680, 3676, 3669, 3641},
+ {3633, 3669, 3667, 3655, 3606},
+ {3610, 3647, 3640, 3620, 3560},
+ {3580, 3607, 3596, 3572, 3501},
+ {3533, 3548, 3537, 3512, 3425},
+ {3457, 3468, 3459, 3429, 3324},
+ {3328, 3348, 3340, 3297, 3172},
+ {3000, 3000, 3000, 3000, 3000}
+ }
};
-static struct sf_lut palladium_1500_rbatt_sf = {
- .rows = 19,
+static struct sf_lut rbatt_sf = {
+ .rows = 29,
.cols = 5,
/* row_entries are temperature */
.row_entries = {-20, 0, 20, 40, 65},
- .percent = {100, 95, 90, 85, 80, 75, 70, 65, 60, 55, 50,
- 45, 40, 35, 30, 25, 20, 15, 10
- },
+ .percent = {100, 95, 90, 85, 80, 75, 70, 65, 60, 55, 50, 45, 40,
+ 35, 30, 25, 20, 15, 10, 9, 8, 7, 6, 5,
+ 4, 3, 2, 1, 0},
.sf = {
- {645, 301, 100, 80, 69},
- {616, 290, 100, 79, 69},
- {586, 279, 100, 78, 68},
- {564, 270, 100, 78, 68},
- {546, 262, 100, 78, 68},
- {537, 256, 100, 79, 68},
- {536, 253, 100, 79, 69},
- {552, 258, 100, 81, 71},
- {618, 284, 100, 80, 72},
- {643, 290, 100, 77, 68},
- {673, 294, 100, 77, 68},
- {720, 296, 100, 77, 69},
- {769, 294, 100, 76, 68},
- {821, 288, 100, 74, 67},
- {892, 284, 100, 74, 61},
- {1003, 290, 100, 71, 58},
- {1192, 307, 100, 70, 58},
- {1579, 345, 100, 68, 57},
- {1261, 324, 100, 68, 57},
+ {357, 187, 100, 91, 91},
+ {400, 208, 105, 94, 94},
+ {390, 204, 106, 95, 96},
+ {391, 201, 108, 98, 98},
+ {391, 202, 110, 98, 100},
+ {390, 200, 110, 99, 102},
+ {389, 200, 110, 99, 102},
+ {393, 202, 101, 93, 100},
+ {407, 205, 99, 89, 94},
+ {428, 208, 100, 91, 96},
+ {455, 212, 102, 92, 98},
+ {495, 220, 104, 93, 101},
+ {561, 232, 107, 95, 102},
+ {634, 245, 112, 98, 98},
+ {714, 258, 114, 98, 98},
+ {791, 266, 114, 97, 100},
+ {871, 289, 108, 95, 97},
+ {973, 340, 124, 108, 105},
+ {489, 241, 109, 96, 99},
+ {511, 246, 110, 96, 99},
+ {534, 252, 111, 95, 98},
+ {579, 263, 112, 96, 96},
+ {636, 276, 111, 95, 97},
+ {730, 294, 109, 96, 99},
+ {868, 328, 112, 98, 104},
+ {1089, 374, 119, 101, 115},
+ {1559, 457, 128, 105, 213},
+ {12886, 1026, 637, 422, 3269},
+ {170899, 127211, 98968, 88907, 77102},
}
};
-static struct pc_temp_ocv_lut palladium_1500_pc_temp_ocv = {
- .rows = 29,
- .cols = 8,
- .temp = {-30, -20, -10, 0, 10, 25, 40, 60},
- .percent = {100, 95, 90, 85, 80, 75, 70, 65, 60, 55,
- 50, 45, 40, 35, 30, 25, 20, 15, 10, 9,
- 8, 7, 6, 5, 4, 3, 2, 1, 0
- },
- .ocv = {
- {3673, 3814, 3945, 4025, 4106, 4176, 4218, 4260},
- {3613, 3751, 3880, 3959, 4038, 4107, 4149, 4190},
- {3573, 3710, 3837, 3916, 3994, 4062, 4103, 4144},
- {3534, 3670, 3796, 3873, 3951, 4019, 4059, 4099},
- {3491, 3625, 3749, 3826, 3902, 3969, 4009, 4049},
- {3464, 3597, 3721, 3796, 3872, 3939, 3978, 4018},
- {3436, 3568, 3691, 3766, 3841, 3907, 3946, 3985},
- {3407, 3537, 3659, 3733, 3808, 3873, 3912, 3951},
- {3377, 3507, 3627, 3701, 3775, 3840, 3878, 3917},
- {3355, 3484, 3604, 3677, 3751, 3815, 3853, 3891},
- {3339, 3467, 3586, 3659, 3732, 3796, 3834, 3872},
- {3324, 3452, 3570, 3643, 3716, 3780, 3818, 3855},
- {3312, 3440, 3558, 3630, 3703, 3766, 3804, 3842},
- {3303, 3430, 3548, 3620, 3692, 3756, 3793, 3831},
- {3297, 3424, 3541, 3614, 3686, 3749, 3787, 3824},
- {3288, 3414, 3531, 3603, 3675, 3738, 3776, 3813},
- {3272, 3398, 3514, 3586, 3658, 3720, 3757, 3795},
- {3240, 3365, 3480, 3551, 3622, 3684, 3721, 3758},
- {3224, 3348, 3463, 3533, 3604, 3666, 3702, 3739},
- {3221, 3344, 3459, 3530, 3600, 3662, 3695, 3728},
- {3216, 3340, 3454, 3525, 3595, 3657, 3686, 3715},
- {3212, 3335, 3449, 3520, 3590, 3652, 3677, 3703},
- {3203, 3326, 3440, 3510, 3580, 3642, 3664, 3686},
- {3185, 3307, 3420, 3490, 3560, 3621, 3639, 3657},
- {3176, 3298, 3411, 3481, 3550, 3611, 3626, 3640},
- {3151, 3272, 3384, 3453, 3522, 3583, 3593, 3604},
- {3106, 3225, 3335, 3446, 3472, 3531, 3538, 3545},
- {3021, 3217, 3245, 3417, 3429, 3435, 3439, 3442},
- {3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000}
- },
-};
struct pm8921_bms_battery_data palladium_1500_data = {
.fcc = 1500,
- .fcc_temp_lut = &palladium_1500_fcc_temp,
- .fcc_sf_lut = &palladium_1500_fcc_sf,
- .pc_temp_ocv_lut = &palladium_1500_pc_temp_ocv,
- .pc_sf_lut = &palladium_1500_pc_sf,
- .rbatt_sf_lut = &palladium_1500_rbatt_sf,
- .default_rbatt_mohm = 254,
- .delta_rbatt_mohm = 60,
+ .fcc_temp_lut = &fcc_temp,
+ .pc_temp_ocv_lut = &pc_temp_ocv,
+ .rbatt_sf_lut = &rbatt_sf,
+ .default_rbatt_mohm = 236,
};
diff --git a/arch/arm/mach-msm/board-8064-gpiomux.c b/arch/arm/mach-msm/board-8064-gpiomux.c
index 4c7ea58..9e43874 100644
--- a/arch/arm/mach-msm/board-8064-gpiomux.c
+++ b/arch/arm/mach-msm/board-8064-gpiomux.c
@@ -428,6 +428,20 @@
.pull = GPIOMUX_PULL_DOWN,
};
+static struct gpiomux_setting hdmi_active_3_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_UP,
+ .dir = GPIOMUX_IN,
+};
+
+static struct gpiomux_setting hdmi_active_4_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_UP,
+ .dir = GPIOMUX_OUT_HIGH,
+};
+
static struct gpiomux_setting gsbi5_suspended_cfg = {
.func = GPIOMUX_FUNC_2,
.drv = GPIOMUX_DRV_12MA,
@@ -617,6 +631,23 @@
},
};
+static struct msm_gpiomux_config apq8064_mhl_configs[] __initdata = {
+ {
+ .gpio = 30,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &hdmi_active_3_cfg,
+ [GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg,
+ },
+ },
+ {
+ .gpio = 35,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &hdmi_active_4_cfg,
+ [GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg,
+ },
+ },
+};
+
static struct msm_gpiomux_config apq8064_gsbi_configs[] __initdata = {
{
.gpio = 8, /* GSBI3 I2C QUP SDA */
@@ -1267,6 +1298,49 @@
},
};
+static struct gpiomux_setting gsbi6_uartdm_active = {
+ .func = GPIOMUX_FUNC_2,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting gsbi6_uartdm_suspended = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct msm_gpiomux_config mpq8064_uartdm_configs[] __initdata = {
+ { /* UARTDM_TX */
+ .gpio = 14,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &gsbi6_uartdm_active,
+ [GPIOMUX_SUSPENDED] = &gsbi6_uartdm_suspended,
+ },
+ },
+ { /* UARTDM_RX */
+ .gpio = 15,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &gsbi6_uartdm_active,
+ [GPIOMUX_SUSPENDED] = &gsbi6_uartdm_suspended,
+ },
+ },
+ { /* UARTDM_CTS */
+ .gpio = 16,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &gsbi6_uartdm_active,
+ [GPIOMUX_SUSPENDED] = &gsbi6_uartdm_suspended,
+ },
+ },
+ { /* UARTDM_RFR */
+ .gpio = 17,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &gsbi6_uartdm_active,
+ [GPIOMUX_SUSPENDED] = &gsbi6_uartdm_suspended,
+ },
+ },
+};
+
void __init apq8064_init_gpiomux(void)
{
int rc;
@@ -1357,6 +1431,10 @@
msm_gpiomux_install(apq8064_hdmi_configs,
ARRAY_SIZE(apq8064_hdmi_configs));
+ if (apq8064_mhl_display_enabled())
+ msm_gpiomux_install(apq8064_mhl_configs,
+ ARRAY_SIZE(apq8064_mhl_configs));
+
if (machine_is_mpq8064_cdp())
msm_gpiomux_install(mpq8064_ir_configs,
ARRAY_SIZE(mpq8064_ir_configs));
@@ -1373,4 +1451,7 @@
msm_gpiomux_install(apq8064_sdc3_configs,
ARRAY_SIZE(apq8064_sdc3_configs));
+ if (machine_is_mpq8064_hrd() || machine_is_mpq8064_dtv())
+ msm_gpiomux_install(mpq8064_uartdm_configs,
+ ARRAY_SIZE(mpq8064_uartdm_configs));
}
diff --git a/arch/arm/mach-msm/board-8064-pmic.c b/arch/arm/mach-msm/board-8064-pmic.c
index 86bc6ba..04326aa 100644
--- a/arch/arm/mach-msm/board-8064-pmic.c
+++ b/arch/arm/mach-msm/board-8064-pmic.c
@@ -126,7 +126,7 @@
PM8921_GPIO_INPUT(35, PM_GPIO_PULL_UP_30),
PM8921_GPIO_INPUT(38, PM_GPIO_PULL_UP_30),
/* TABLA CODEC RESET */
- PM8921_GPIO_OUTPUT(34, 1, MED),
+ PM8921_GPIO_OUTPUT(34, 0, MED),
PM8921_GPIO_OUTPUT(13, 0, HIGH), /* PCIE_CLK_PWR_EN */
PM8921_GPIO_INPUT(12, PM_GPIO_PULL_UP_30), /* PCIE_WAKE_N */
};
@@ -494,5 +494,7 @@
apq8064_pm8921_bms_pdata.battery_type = BATT_PALLADIUM;
} else if (machine_is_apq8064_liquid()) {
apq8064_pm8921_bms_pdata.battery_type = BATT_DESAY;
+ } else if (machine_is_apq8064_cdp()) {
+ apq8064_pm8921_chg_pdata.has_dc_supply = true;
}
}
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index 7070b42..97cb2aa 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -68,6 +68,7 @@
#include <linux/msm_tsens.h>
#include <mach/msm_xo.h>
#include <mach/msm_rtb.h>
+#include <mach/msm_serial_hs.h>
#include <sound/cs8427.h>
#include <media/gpio-ir-recv.h>
#include <linux/fmem.h>
@@ -85,6 +86,9 @@
#include "devices-msm8x60.h"
#include "smd_private.h"
+#define MHL_GPIO_INT 30
+#define MHL_GPIO_RESET 35
+
#define MSM_PMEM_ADSP_SIZE 0x7800000
#define MSM_PMEM_AUDIO_SIZE 0x4CF000
#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
@@ -1805,6 +1809,26 @@
(void *)MSM_QGIC_CPU_BASE);
}
+static struct msm_mhl_platform_data mhl_platform_data = {
+ .irq = MSM_GPIO_TO_INT(MHL_GPIO_INT),
+ .gpio_mhl_int = MHL_GPIO_INT,
+ .gpio_mhl_reset = MHL_GPIO_RESET,
+ .gpio_mhl_power = 0,
+ .gpio_hdmi_mhl_mux = 0,
+};
+
+static struct i2c_board_info sii_device_info[] __initdata = {
+ {
+ /*
+ * keeps SI 8334 as the default
+ * MHL TX
+ */
+ I2C_BOARD_INFO("sii8334", 0x39),
+ .platform_data = &mhl_platform_data,
+ .flags = I2C_CLIENT_WAKE,
+ },
+};
+
static struct platform_device msm8064_device_saw_regulator_core0 = {
.name = "saw-regulator",
.id = 0,
@@ -1847,6 +1871,13 @@
},
{
+ MSM_PM_SLEEP_MODE_RETENTION,
+ MSM_RPMRS_LIMITS(ON, ACTIVE, MAX, ACTIVE),
+ true,
+ 415, 715, 340827, 475,
+ },
+
+ {
MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE,
MSM_RPMRS_LIMITS(ON, ACTIVE, MAX, ACTIVE),
true,
@@ -1938,6 +1969,11 @@
0x24, 0x30, 0x0f,
};
+static uint8_t spm_retention_cmd_sequence[] __initdata = {
+ 0x00, 0x05, 0x03, 0x0D,
+ 0x0B, 0x00, 0x0f,
+};
+
static uint8_t spm_power_collapse_with_rpm[] __initdata = {
0x00, 0x24, 0x54, 0x10,
0x09, 0x07, 0x01, 0x0B,
@@ -1945,7 +1981,29 @@
0x24, 0x30, 0x0f,
};
-static struct msm_spm_seq_entry msm_spm_seq_list[] __initdata = {
+static struct msm_spm_seq_entry msm_spm_boot_cpu_seq_list[] __initdata = {
+ [0] = {
+ .mode = MSM_SPM_MODE_CLOCK_GATING,
+ .notify_rpm = false,
+ .cmd = spm_wfi_cmd_sequence,
+ },
+ [1] = {
+ .mode = MSM_SPM_MODE_POWER_RETENTION,
+ .notify_rpm = false,
+ .cmd = spm_retention_cmd_sequence,
+ },
+ [2] = {
+ .mode = MSM_SPM_MODE_POWER_COLLAPSE,
+ .notify_rpm = false,
+ .cmd = spm_power_collapse_without_rpm,
+ },
+ [3] = {
+ .mode = MSM_SPM_MODE_POWER_COLLAPSE,
+ .notify_rpm = true,
+ .cmd = spm_power_collapse_with_rpm,
+ },
+};
+static struct msm_spm_seq_entry msm_spm_nonboot_cpu_seq_list[] __initdata = {
[0] = {
.mode = MSM_SPM_MODE_CLOCK_GATING,
.notify_rpm = false,
@@ -2021,12 +2079,12 @@
.reg_init_values[MSM_SPM_REG_SAW2_AVS_HYSTERESIS] = 0x00,
#endif
.reg_init_values[MSM_SPM_REG_SAW2_SPM_CTL] = 0x01,
- .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DLY] = 0x02020204,
- .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_0] = 0x0060009C,
- .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_1] = 0x0000001C,
+ .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DLY] = 0x03020004,
+ .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_0] = 0x0084009C,
+ .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_1] = 0x00A4001C,
.vctl_timeout_us = 50,
- .num_modes = ARRAY_SIZE(msm_spm_seq_list),
- .modes = msm_spm_seq_list,
+ .num_modes = ARRAY_SIZE(msm_spm_boot_cpu_seq_list),
+ .modes = msm_spm_boot_cpu_seq_list,
},
[1] = {
.reg_base_addr = MSM_SAW1_BASE,
@@ -2040,8 +2098,8 @@
.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_0] = 0x0060009C,
.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_1] = 0x0000001C,
.vctl_timeout_us = 50,
- .num_modes = ARRAY_SIZE(msm_spm_seq_list),
- .modes = msm_spm_seq_list,
+ .num_modes = ARRAY_SIZE(msm_spm_nonboot_cpu_seq_list),
+ .modes = msm_spm_nonboot_cpu_seq_list,
},
[2] = {
.reg_base_addr = MSM_SAW2_BASE,
@@ -2055,8 +2113,8 @@
.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_0] = 0x0060009C,
.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_1] = 0x0000001C,
.vctl_timeout_us = 50,
- .num_modes = ARRAY_SIZE(msm_spm_seq_list),
- .modes = msm_spm_seq_list,
+ .num_modes = ARRAY_SIZE(msm_spm_nonboot_cpu_seq_list),
+ .modes = msm_spm_nonboot_cpu_seq_list,
},
[3] = {
.reg_base_addr = MSM_SAW3_BASE,
@@ -2070,8 +2128,8 @@
.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_0] = 0x0060009C,
.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_1] = 0x0000001C,
.vctl_timeout_us = 50,
- .num_modes = ARRAY_SIZE(msm_spm_seq_list),
- .modes = msm_spm_seq_list,
+ .num_modes = ARRAY_SIZE(msm_spm_nonboot_cpu_seq_list),
+ .modes = msm_spm_nonboot_cpu_seq_list,
},
};
@@ -2419,6 +2477,40 @@
}
late_initcall(rf4ce_gpio_init);
+#ifdef CONFIG_SERIAL_MSM_HS
+static int configure_uart_gpios(int on)
+{
+ int ret = 0, i;
+ int uart_gpios[] = {14, 15, 16, 17};
+
+ for (i = 0; i < ARRAY_SIZE(uart_gpios); i++) {
+ if (on) {
+ ret = gpio_request(uart_gpios[i], NULL);
+ if (ret) {
+ pr_err("%s:unable to request uart gpio[%d]\n",
+ __func__, uart_gpios[i]);
+ break;
+ }
+ } else {
+ gpio_free(uart_gpios[i]);
+ }
+ }
+
+ if (ret && on && i)
+ for (; i >= 0; i--)
+ gpio_free(uart_gpios[i]);
+ return ret;
+}
+
+static struct msm_serial_hs_platform_data mpq8064_gsbi6_uartdm_pdata = {
+ .inject_rx_on_wakeup = 1,
+ .rx_to_inject = 0xFD,
+ .gpio_config = configure_uart_gpios,
+};
+#else
+static struct msm_serial_hs_platform_data msm_uart_dm9_pdata;
+#endif
+
static struct platform_device *mpq_devices[] __initdata = {
&msm_device_sps_apq8064,
&mpq8064_device_qup_i2c_gsbi5,
@@ -2833,6 +2925,12 @@
cs8427_device_info,
ARRAY_SIZE(cs8427_device_info),
},
+ {
+ I2C_SURF | I2C_FFA | I2C_LIQUID,
+ APQ_8064_GSBI1_QUP_I2C_BUS_ID,
+ sii_device_info,
+ ARRAY_SIZE(sii_device_info),
+ }
};
#define SX150X_EXP1_INT_N PM8921_MPP_IRQ(PM8921_IRQ_BASE, 9)
@@ -3023,6 +3121,9 @@
if (machine_is_apq8064_liquid())
msm_otg_pdata.mhl_enable = true;
+ if (apq8064_mhl_display_enabled())
+ mhl_platform_data.mhl_enabled = true;
+
android_usb_pdata.swfi_latency =
msm_rpmrs_levels[0].latency_us;
@@ -3075,6 +3176,7 @@
msm_spm_l2_init(msm_spm_l2_data);
BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
apq8064_epm_adc_init();
+ msm_pm_set_tz_retention_flag(1);
}
static void __init apq8064_allocate_memory_regions(void)
@@ -3110,6 +3212,16 @@
apq8064_init_cam();
#endif
+ if (machine_is_mpq8064_hrd() || machine_is_mpq8064_dtv()) {
+ platform_device_register(&mpq8064_device_uartdm_gsbi6);
+#ifdef CONFIG_SERIAL_MSM_HS
+ /* GSBI6(2) - UARTDM_RX */
+ mpq8064_gsbi6_uartdm_pdata.wakeup_irq = gpio_to_irq(15);
+ mpq8064_device_uartdm_gsbi6.dev.platform_data =
+ &mpq8064_gsbi6_uartdm_pdata;
+#endif
+ }
+
if (machine_is_apq8064_cdp() || machine_is_apq8064_liquid())
platform_device_register(&cdp_kp_pdev);
@@ -3195,4 +3307,3 @@
.init_very_early = apq8064_early_reserve,
.restart = msm_restart,
MACHINE_END
-
diff --git a/arch/arm/mach-msm/board-8930-display.c b/arch/arm/mach-msm/board-8930-display.c
index 2a8e918..4b4a51a 100644
--- a/arch/arm/mach-msm/board-8930-display.c
+++ b/arch/arm/mach-msm/board-8930-display.c
@@ -135,6 +135,8 @@
static int mipi_dsi_cdp_panel_power(int on)
{
static struct regulator *reg_l8, *reg_l23, *reg_l2;
+ /* Control backlight GPIO (24) directly when using PM8917 */
+ int gpio24 = PM8917_GPIO_PM_TO_SYS(24);
int rc;
pr_debug("%s: state : %d\n", __func__, on);
@@ -190,13 +192,21 @@
rc);
gpio_free(DISP_3D_2D_MODE);
return -ENODEV;
- }
+ }
rc = gpio_direction_output(DISP_3D_2D_MODE, 0);
if (rc) {
pr_err("gpio_direction_output failed for %d gpio rc=%d\n",
DISP_3D_2D_MODE, rc);
return -ENODEV;
+ }
+ if (socinfo_get_pmic_model() == PMIC_MODEL_PM8917) {
+ rc = gpio_request(gpio24, "disp_bl");
+ if (rc) {
+ pr_err("request for gpio 24 failed, rc=%d\n",
+ rc);
+ return -ENODEV;
}
+ }
dsi_power_on = true;
}
if (on) {
@@ -238,6 +248,8 @@
gpio_set_value(DISP_RST_GPIO, 1);
gpio_set_value(DISP_3D_2D_MODE, 1);
usleep(20);
+ if (socinfo_get_pmic_model() == PMIC_MODEL_PM8917)
+ gpio_set_value_cansleep(gpio24, 1);
} else {
gpio_set_value(DISP_RST_GPIO, 0);
@@ -274,6 +286,8 @@
}
gpio_set_value(DISP_3D_2D_MODE, 0);
usleep(20);
+ if (socinfo_get_pmic_model() == PMIC_MODEL_PM8917)
+ gpio_set_value_cansleep(gpio24, 0);
}
return 0;
}
diff --git a/arch/arm/mach-msm/board-8930-gpiomux.c b/arch/arm/mach-msm/board-8930-gpiomux.c
index 74dfca1..2331b0b 100644
--- a/arch/arm/mach-msm/board-8930-gpiomux.c
+++ b/arch/arm/mach-msm/board-8930-gpiomux.c
@@ -280,6 +280,13 @@
#endif
+static struct gpiomux_setting sitar_reset = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_6MA,
+ .pull = GPIOMUX_PULL_NONE,
+ .dir = GPIOMUX_OUT_LOW,
+};
+
#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
static struct msm_gpiomux_config msm8960_ethernet_configs[] = {
{
@@ -710,6 +717,15 @@
},
};
+static struct msm_gpiomux_config msm_sitar_config[] __initdata = {
+ {
+ .gpio = 42, /* SYS_RST_N */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &sitar_reset,
+ },
+ }
+};
+
int __init msm8930_init_gpiomux(void)
{
int rc = msm_gpiomux_init(NR_GPIO_IRQS);
@@ -784,5 +800,7 @@
msm_gpiomux_install(msm8930_gyro_int_config,
ARRAY_SIZE(msm8930_gyro_int_config));
+ msm_gpiomux_install(msm_sitar_config, ARRAY_SIZE(msm_sitar_config));
+
return 0;
}
diff --git a/arch/arm/mach-msm/board-8930-pmic.c b/arch/arm/mach-msm/board-8930-pmic.c
index e3479eb..b6e20fd 100644
--- a/arch/arm/mach-msm/board-8930-pmic.c
+++ b/arch/arm/mach-msm/board-8930-pmic.c
@@ -18,6 +18,7 @@
#include <asm/mach-types.h>
#include <mach/msm_bus_board.h>
#include <mach/restart.h>
+#include <mach/socinfo.h>
#include "devices.h"
#include "board-8930.h"
@@ -31,7 +32,7 @@
struct pm8xxx_mpp_config_data config;
};
-#define PM8XXX_GPIO_INIT(_gpio, _dir, _buf, _val, _pull, _vin, _out_strength, \
+#define PM8038_GPIO_INIT(_gpio, _dir, _buf, _val, _pull, _vin, _out_strength, \
_func, _inv, _disable) \
{ \
.gpio = PM8038_GPIO_PM_TO_SYS(_gpio), \
@@ -48,7 +49,7 @@
} \
}
-#define PM8XXX_MPP_INIT(_mpp, _type, _level, _control) \
+#define PM8038_MPP_INIT(_mpp, _type, _level, _control) \
{ \
.mpp = PM8038_MPP_PM_TO_SYS(_mpp), \
.config = { \
@@ -58,49 +59,128 @@
} \
}
-#define PM8XXX_GPIO_DISABLE(_gpio) \
- PM8XXX_GPIO_INIT(_gpio, PM_GPIO_DIR_IN, 0, 0, 0, PM8038_GPIO_VIN_L11, \
+#define PM8038_GPIO_DISABLE(_gpio) \
+ PM8038_GPIO_INIT(_gpio, PM_GPIO_DIR_IN, 0, 0, 0, PM8038_GPIO_VIN_L11, \
0, 0, 0, 1)
-#define PM8XXX_GPIO_OUTPUT(_gpio, _val) \
- PM8XXX_GPIO_INIT(_gpio, PM_GPIO_DIR_OUT, PM_GPIO_OUT_BUF_CMOS, _val, \
+#define PM8038_GPIO_OUTPUT(_gpio, _val) \
+ PM8038_GPIO_INIT(_gpio, PM_GPIO_DIR_OUT, PM_GPIO_OUT_BUF_CMOS, _val, \
PM_GPIO_PULL_NO, PM8038_GPIO_VIN_L11, \
PM_GPIO_STRENGTH_HIGH, \
PM_GPIO_FUNC_NORMAL, 0, 0)
-#define PM8XXX_GPIO_INPUT(_gpio, _pull) \
- PM8XXX_GPIO_INIT(_gpio, PM_GPIO_DIR_IN, PM_GPIO_OUT_BUF_CMOS, 0, \
+#define PM8038_GPIO_INPUT(_gpio, _pull) \
+ PM8038_GPIO_INIT(_gpio, PM_GPIO_DIR_IN, PM_GPIO_OUT_BUF_CMOS, 0, \
_pull, PM8038_GPIO_VIN_L11, \
PM_GPIO_STRENGTH_NO, \
PM_GPIO_FUNC_NORMAL, 0, 0)
-#define PM8XXX_GPIO_OUTPUT_FUNC(_gpio, _val, _func) \
- PM8XXX_GPIO_INIT(_gpio, PM_GPIO_DIR_OUT, PM_GPIO_OUT_BUF_CMOS, _val, \
+#define PM8038_GPIO_OUTPUT_FUNC(_gpio, _val, _func) \
+ PM8038_GPIO_INIT(_gpio, PM_GPIO_DIR_OUT, PM_GPIO_OUT_BUF_CMOS, _val, \
PM_GPIO_PULL_NO, PM8038_GPIO_VIN_L11, \
PM_GPIO_STRENGTH_HIGH, \
_func, 0, 0)
-#define PM8XXX_GPIO_OUTPUT_VIN(_gpio, _val, _vin) \
- PM8XXX_GPIO_INIT(_gpio, PM_GPIO_DIR_OUT, PM_GPIO_OUT_BUF_CMOS, _val, \
+#define PM8038_GPIO_OUTPUT_VIN(_gpio, _val, _vin) \
+ PM8038_GPIO_INIT(_gpio, PM_GPIO_DIR_OUT, PM_GPIO_OUT_BUF_CMOS, _val, \
PM_GPIO_PULL_NO, _vin, \
PM_GPIO_STRENGTH_HIGH, \
PM_GPIO_FUNC_NORMAL, 0, 0)
-/* Initial pm8038 GPIO configurations */
+#define PM8917_GPIO_INIT(_gpio, _dir, _buf, _val, _pull, _vin, _out_strength, \
+ _func, _inv, _disable) \
+{ \
+ .gpio = PM8917_GPIO_PM_TO_SYS(_gpio), \
+ .config = { \
+ .direction = _dir, \
+ .output_buffer = _buf, \
+ .output_value = _val, \
+ .pull = _pull, \
+ .vin_sel = _vin, \
+ .out_strength = _out_strength, \
+ .function = _func, \
+ .inv_int_pol = _inv, \
+ .disable_pin = _disable, \
+ } \
+}
+
+#define PM8917_MPP_INIT(_mpp, _type, _level, _control) \
+{ \
+ .mpp = PM8917_MPP_PM_TO_SYS(_mpp), \
+ .config = { \
+ .type = PM8XXX_MPP_TYPE_##_type, \
+ .level = _level, \
+ .control = PM8XXX_MPP_##_control, \
+ } \
+}
+
+#define PM8917_GPIO_DISABLE(_gpio) \
+ PM8917_GPIO_INIT(_gpio, PM_GPIO_DIR_IN, 0, 0, 0, PM_GPIO_VIN_S4, \
+ 0, 0, 0, 1)
+
+#define PM8917_GPIO_OUTPUT(_gpio, _val) \
+ PM8917_GPIO_INIT(_gpio, PM_GPIO_DIR_OUT, PM_GPIO_OUT_BUF_CMOS, _val, \
+ PM_GPIO_PULL_NO, PM_GPIO_VIN_S4, \
+ PM_GPIO_STRENGTH_HIGH, \
+ PM_GPIO_FUNC_NORMAL, 0, 0)
+
+#define PM8917_GPIO_INPUT(_gpio, _pull) \
+ PM8917_GPIO_INIT(_gpio, PM_GPIO_DIR_IN, PM_GPIO_OUT_BUF_CMOS, 0, \
+ _pull, PM_GPIO_VIN_S4, \
+ PM_GPIO_STRENGTH_NO, \
+ PM_GPIO_FUNC_NORMAL, 0, 0)
+
+#define PM8917_GPIO_OUTPUT_FUNC(_gpio, _val, _func) \
+ PM8917_GPIO_INIT(_gpio, PM_GPIO_DIR_OUT, PM_GPIO_OUT_BUF_CMOS, _val, \
+ PM_GPIO_PULL_NO, PM_GPIO_VIN_S4, \
+ PM_GPIO_STRENGTH_HIGH, \
+ _func, 0, 0)
+
+#define PM8917_GPIO_OUTPUT_VIN(_gpio, _val, _vin) \
+ PM8917_GPIO_INIT(_gpio, PM_GPIO_DIR_OUT, PM_GPIO_OUT_BUF_CMOS, _val, \
+ PM_GPIO_PULL_NO, _vin, \
+ PM_GPIO_STRENGTH_HIGH, \
+ PM_GPIO_FUNC_NORMAL, 0, 0)
+
+/* GPIO and MPP configurations for MSM8930 + PM8038 targets */
+
+/* Initial PM8038 GPIO configurations */
static struct pm8xxx_gpio_init pm8038_gpios[] __initdata = {
/* keys GPIOs */
- PM8XXX_GPIO_INPUT(3, PM_GPIO_PULL_UP_30),
- PM8XXX_GPIO_INPUT(8, PM_GPIO_PULL_UP_30),
- PM8XXX_GPIO_INPUT(10, PM_GPIO_PULL_UP_30),
- PM8XXX_GPIO_INPUT(11, PM_GPIO_PULL_UP_30),
+ PM8038_GPIO_INPUT(3, PM_GPIO_PULL_UP_30),
+ PM8038_GPIO_INPUT(8, PM_GPIO_PULL_UP_30),
+ PM8038_GPIO_INPUT(10, PM_GPIO_PULL_UP_30),
+ PM8038_GPIO_INPUT(11, PM_GPIO_PULL_UP_30),
/* haptics gpio */
- PM8XXX_GPIO_OUTPUT_FUNC(7, 0, PM_GPIO_FUNC_1),
+ PM8038_GPIO_OUTPUT_FUNC(7, 0, PM_GPIO_FUNC_1),
/* MHL PWR EN */
- PM8XXX_GPIO_OUTPUT_VIN(5, 1, PM_GPIO_VIN_VPH),
+ PM8038_GPIO_OUTPUT_VIN(5, 1, PM8038_GPIO_VIN_VPH),
};
-/* Initial pm8038 MPP configurations */
-static struct pm8xxx_mpp_init pm8038_mpps[] __initdata = {};
+/* Initial PM8038 MPP configurations */
+static struct pm8xxx_mpp_init pm8038_mpps[] __initdata = {
+};
+
+/* GPIO and MPP configurations for MSM8930 + PM8917 targets */
+
+/* Initial PM8917 GPIO configurations */
+static struct pm8xxx_gpio_init pm8917_gpios[] __initdata = {
+ /* Backlight enable control */
+ PM8917_GPIO_OUTPUT(24, 1),
+ /* keys GPIOs */
+ PM8917_GPIO_INPUT(27, PM_GPIO_PULL_UP_30),
+ PM8917_GPIO_INPUT(28, PM_GPIO_PULL_UP_30),
+ PM8917_GPIO_INPUT(36, PM_GPIO_PULL_UP_30),
+ PM8917_GPIO_INPUT(37, PM_GPIO_PULL_UP_30),
+ /* haptics gpio */
+ PM8917_GPIO_OUTPUT_FUNC(38, 0, PM_GPIO_FUNC_2),
+ /* MHL PWR EN */
+ PM8917_GPIO_OUTPUT_VIN(25, 1, PM_GPIO_VIN_VPH),
+};
+
+/* Initial PM8917 MPP configurations */
+static struct pm8xxx_mpp_init pm8917_mpps[] __initdata = {
+};
void __init msm8930_pm8038_gpio_mpp_init(void)
{
@@ -126,7 +206,31 @@
}
}
-static struct pm8xxx_adc_amux pm8xxx_adc_channels_data[] = {
+void __init msm8930_pm8917_gpio_mpp_init(void)
+{
+ int i, rc;
+
+ for (i = 0; i < ARRAY_SIZE(pm8917_gpios); i++) {
+ rc = pm8xxx_gpio_config(pm8917_gpios[i].gpio,
+ &pm8917_gpios[i].config);
+ if (rc) {
+ pr_err("%s: pm8xxx_gpio_config: rc=%d\n", __func__, rc);
+ break;
+ }
+ }
+
+ /* Initial MPP configuration. */
+ for (i = 0; i < ARRAY_SIZE(pm8917_mpps); i++) {
+ rc = pm8xxx_mpp_config(pm8917_mpps[i].mpp,
+ &pm8917_mpps[i].config);
+ if (rc) {
+ pr_err("%s: pm8xxx_mpp_config: rc=%d\n", __func__, rc);
+ break;
+ }
+ }
+}
+
+static struct pm8xxx_adc_amux pm8038_adc_channels_data[] = {
{"vcoin", CHANNEL_VCOIN, CHAN_PATH_SCALING2, AMUX_RSV1,
ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
{"vbat", CHANNEL_VBAT, CHAN_PATH_SCALING2, AMUX_RSV1,
@@ -161,16 +265,16 @@
ADC_DECIMATION_TYPE2, ADC_SCALE_PA_THERM},
};
-static struct pm8xxx_adc_properties pm8xxx_adc_data = {
+static struct pm8xxx_adc_properties pm8038_adc_data = {
.adc_vdd_reference = 1800, /* milli-voltage for this adc */
.bitresolution = 15,
.bipolar = 0,
};
-static struct pm8xxx_adc_platform_data pm8xxx_adc_pdata = {
- .adc_channel = pm8xxx_adc_channels_data,
- .adc_num_board_channel = ARRAY_SIZE(pm8xxx_adc_channels_data),
- .adc_prop = &pm8xxx_adc_data,
+static struct pm8xxx_adc_platform_data pm8038_adc_pdata = {
+ .adc_channel = pm8038_adc_channels_data,
+ .adc_num_board_channel = ARRAY_SIZE(pm8038_adc_channels_data),
+ .adc_prop = &pm8038_adc_data,
.adc_mpp_base = PM8038_MPP_PM_TO_SYS(1),
};
@@ -227,6 +331,7 @@
.thermal_mitigation = pm8921_therm_mitigation,
.thermal_levels = ARRAY_SIZE(pm8921_therm_mitigation),
.led_src_config = LED_SRC_VPH_PWR,
+ .rconn_mohm = 18,
};
#define PM8038_WLED_MAX_CURRENT 25
@@ -348,6 +453,7 @@
.shutdown_soc_valid_limit = 20,
.adjust_soc_low_threshold = 25,
.chg_term_ua = CHG_TERM_MA * 1000,
+ .rconn_mohm = 18,
};
static struct pm8038_platform_data pm8038_platform_data __devinitdata = {
@@ -360,7 +466,7 @@
.regulator_pdatas = msm8930_pm8038_regulator_pdata,
.charger_pdata = &pm8921_chg_pdata,
.bms_pdata = &pm8921_bms_pdata,
- .adc_pdata = &pm8xxx_adc_pdata,
+ .adc_pdata = &pm8038_adc_pdata,
.leds_pdata = &pm8xxx_leds_pdata,
.ccadc_pdata = &pm8xxx_ccadc_pdata,
.spk_pdata = &pm8xxx_spk_pdata,
@@ -374,15 +480,99 @@
},
};
+/* PM8917 platform data */
+
+static struct pm8xxx_adc_amux pm8917_adc_channels_data[] = {
+ {"vcoin", CHANNEL_VCOIN, CHAN_PATH_SCALING2, AMUX_RSV1,
+ ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+ {"vbat", CHANNEL_VBAT, CHAN_PATH_SCALING2, AMUX_RSV1,
+ ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+ {"dcin", CHANNEL_DCIN, CHAN_PATH_SCALING4, AMUX_RSV1,
+ ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+ {"ichg", CHANNEL_ICHG, CHAN_PATH_SCALING1, AMUX_RSV1,
+ ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+ {"vph_pwr", CHANNEL_VPH_PWR, CHAN_PATH_SCALING2, AMUX_RSV1,
+ ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+ {"ibat", CHANNEL_IBAT, CHAN_PATH_SCALING1, AMUX_RSV1,
+ ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+ {"batt_therm", CHANNEL_BATT_THERM, CHAN_PATH_SCALING1, AMUX_RSV2,
+ ADC_DECIMATION_TYPE2, ADC_SCALE_BATT_THERM},
+ {"batt_id", CHANNEL_BATT_ID, CHAN_PATH_SCALING1, AMUX_RSV2,
+ ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+ {"usbin", CHANNEL_USBIN, CHAN_PATH_SCALING3, AMUX_RSV1,
+ ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+ {"pmic_therm", CHANNEL_DIE_TEMP, CHAN_PATH_SCALING1, AMUX_RSV1,
+ ADC_DECIMATION_TYPE2, ADC_SCALE_PMIC_THERM},
+ {"625mv", CHANNEL_625MV, CHAN_PATH_SCALING1, AMUX_RSV1,
+ ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+ {"125v", CHANNEL_125V, CHAN_PATH_SCALING1, AMUX_RSV1,
+ ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+ {"chg_temp", CHANNEL_CHG_TEMP, CHAN_PATH_SCALING1, AMUX_RSV1,
+ ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
+ {"xo_therm", CHANNEL_MUXOFF, CHAN_PATH_SCALING1, AMUX_RSV0,
+ ADC_DECIMATION_TYPE2, ADC_SCALE_XOTHERM},
+ {"pa_therm0", ADC_MPP_1_AMUX3, CHAN_PATH_SCALING1, AMUX_RSV1,
+ ADC_DECIMATION_TYPE2, ADC_SCALE_PA_THERM},
+};
+
+static struct pm8xxx_adc_properties pm8917_adc_data = {
+ .adc_vdd_reference = 1800, /* milli-voltage for this adc */
+ .bitresolution = 15,
+ .bipolar = 0,
+};
+
+static struct pm8xxx_adc_platform_data pm8917_adc_pdata = {
+ .adc_channel = pm8917_adc_channels_data,
+ .adc_num_board_channel = ARRAY_SIZE(pm8917_adc_channels_data),
+ .adc_prop = &pm8917_adc_data,
+ .adc_mpp_base = PM8917_MPP_PM_TO_SYS(1),
+};
+
+static struct pm8921_platform_data pm8917_platform_data __devinitdata = {
+ .irq_pdata = &pm8xxx_irq_pdata,
+ .gpio_pdata = &pm8xxx_gpio_pdata,
+ .mpp_pdata = &pm8xxx_mpp_pdata,
+ .rtc_pdata = &pm8xxx_rtc_pdata,
+ .pwrkey_pdata = &pm8xxx_pwrkey_pdata,
+ .misc_pdata = &pm8xxx_misc_pdata,
+ .regulator_pdatas = msm8930_pm8917_regulator_pdata,
+ .charger_pdata = &pm8921_chg_pdata,
+ .bms_pdata = &pm8921_bms_pdata,
+ .adc_pdata = &pm8917_adc_pdata,
+ .ccadc_pdata = &pm8xxx_ccadc_pdata,
+};
+
+static struct msm_ssbi_platform_data msm8930_ssbi_pm8917_pdata __devinitdata = {
+ .controller_type = MSM_SBI_CTRL_PMIC_ARBITER,
+ .slave = {
+ .name = "pm8921-core",
+ .platform_data = &pm8917_platform_data,
+ },
+};
+
void __init msm8930_init_pmic(void)
{
- pmic_reset_irq = PM8038_IRQ_BASE + PM8038_RESOUT_IRQ;
- msm8960_device_ssbi_pmic.dev.platform_data =
- &msm8930_ssbi_pm8038_pdata;
- pm8038_platform_data.num_regulators
- = msm8930_pm8038_regulator_pdata_len;
- if (machine_is_apq8064_mtp())
- pm8921_bms_pdata.battery_type = BATT_PALLADIUM;
- else if (machine_is_apq8064_liquid())
- pm8921_bms_pdata.battery_type = BATT_DESAY;
+ if (socinfo_get_pmic_model() != PMIC_MODEL_PM8917) {
+ /* PM8038 configuration */
+ pmic_reset_irq = PM8038_IRQ_BASE + PM8038_RESOUT_IRQ;
+ msm8960_device_ssbi_pmic.dev.platform_data =
+ &msm8930_ssbi_pm8038_pdata;
+ pm8038_platform_data.num_regulators
+ = msm8930_pm8038_regulator_pdata_len;
+ if (machine_is_msm8930_mtp())
+ pm8921_bms_pdata.battery_type = BATT_PALLADIUM;
+ else if (machine_is_msm8930_cdp())
+ pm8921_chg_pdata.has_dc_supply = true;
+ } else {
+ /* PM8917 configuration */
+ pmic_reset_irq = PM8917_IRQ_BASE + PM8921_RESOUT_IRQ;
+ msm8960_device_ssbi_pmic.dev.platform_data =
+ &msm8930_ssbi_pm8917_pdata;
+ pm8917_platform_data.num_regulators
+ = msm8930_pm8917_regulator_pdata_len;
+ if (machine_is_msm8930_mtp())
+ pm8921_bms_pdata.battery_type = BATT_PALLADIUM;
+ else if (machine_is_msm8930_cdp())
+ pm8921_chg_pdata.has_dc_supply = true;
+ }
}
diff --git a/arch/arm/mach-msm/board-8930-regulator.c b/arch/arm/mach-msm/board-8930-regulator-pm8038.c
similarity index 97%
rename from arch/arm/mach-msm/board-8930-regulator.c
rename to arch/arm/mach-msm/board-8930-regulator-pm8038.c
index d4bd18f..ed9d802 100644
--- a/arch/arm/mach-msm/board-8930-regulator.c
+++ b/arch/arm/mach-msm/board-8930-regulator-pm8038.c
@@ -11,6 +11,11 @@
* GNU General Public License for more details.
*/
+/*
+ * This file contains regulator configuration and mappings for targets
+ * consisting of MSM8930 and PM8038.
+ */
+
#include <linux/regulator/pm8xxx-regulator.h>
#include "board-8930.h"
@@ -449,17 +454,17 @@
/* GPIO regulator constraints */
struct gpio_regulator_platform_data
-msm8930_gpio_regulator_pdata[] __devinitdata = {
+msm8930_pm8038_gpio_regulator_pdata[] __devinitdata = {
/* ID vreg_name gpio_label gpio supply */
GPIO_VREG(EXT_5V, "ext_5v", "ext_5v_en", 63, NULL),
GPIO_VREG(EXT_OTG_SW, "ext_otg_sw", "ext_otg_sw_en", 97, "ext_5v"),
};
/* SAW regulator constraints */
-struct regulator_init_data msm8930_saw_regulator_core0_pdata =
+struct regulator_init_data msm8930_pm8038_saw_regulator_core0_pdata =
/* ID vreg_name min_uV max_uV */
SAW_VREG_INIT(S5, "8038_s5", 850000, 1300000);
-struct regulator_init_data msm8930_saw_regulator_core1_pdata =
+struct regulator_init_data msm8930_pm8038_saw_regulator_core1_pdata =
SAW_VREG_INIT(S6, "8038_s6", 850000, 1300000);
/* PM8038 regulator constraints */
@@ -558,7 +563,8 @@
RPM_REG_MAP(VDD_DIG_CORNER, 0, 2, "krait1_dig", "acpuclk-8930aa"),
};
-struct rpm_regulator_platform_data msm8930_rpm_regulator_pdata __devinitdata = {
+struct rpm_regulator_platform_data
+msm8930_pm8038_rpm_regulator_pdata __devinitdata = {
.init_data = msm8930_rpm_regulator_init_data,
.num_regulators = ARRAY_SIZE(msm8930_rpm_regulator_init_data),
.version = RPM_VREG_VERSION_8930,
diff --git a/arch/arm/mach-msm/board-8930-regulator.c b/arch/arm/mach-msm/board-8930-regulator-pm8917.c
similarity index 72%
copy from arch/arm/mach-msm/board-8930-regulator.c
copy to arch/arm/mach-msm/board-8930-regulator-pm8917.c
index d4bd18f..db40e5d 100644
--- a/arch/arm/mach-msm/board-8930-regulator.c
+++ b/arch/arm/mach-msm/board-8930-regulator-pm8917.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+ * 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
@@ -11,6 +11,11 @@
* GNU General Public License for more details.
*/
+/*
+ * This file contains regulator configuration and mappings for targets
+ * consisting of MSM8930 and PM8917.
+ */
+
#include <linux/regulator/pm8xxx-regulator.h>
#include "board-8930.h"
@@ -23,11 +28,10 @@
* regulator name consumer dev_name
*/
VREG_CONSUMERS(L1) = {
- REGULATOR_SUPPLY("8038_l1", NULL),
- REGULATOR_SUPPLY("iris_vddrfa", "wcnss_wlan.0"),
+ REGULATOR_SUPPLY("8917_l1", NULL),
};
VREG_CONSUMERS(L2) = {
- REGULATOR_SUPPLY("8038_l2", NULL),
+ REGULATOR_SUPPLY("8917_l2", NULL),
REGULATOR_SUPPLY("iris_vdddig", "wcnss_wlan.0"),
REGULATOR_SUPPLY("dsi_vdda", "mipi_dsi.1"),
REGULATOR_SUPPLY("mipi_csi_vdd", "msm_csid.0"),
@@ -35,53 +39,152 @@
REGULATOR_SUPPLY("mipi_csi_vdd", "msm_csid.2"),
};
VREG_CONSUMERS(L3) = {
- REGULATOR_SUPPLY("8038_l3", NULL),
+ REGULATOR_SUPPLY("8917_l3", NULL),
REGULATOR_SUPPLY("HSUSB_3p3", "msm_otg"),
};
VREG_CONSUMERS(L4) = {
- REGULATOR_SUPPLY("8038_l4", NULL),
+ REGULATOR_SUPPLY("8917_l4", NULL),
REGULATOR_SUPPLY("HSUSB_1p8", "msm_otg"),
REGULATOR_SUPPLY("iris_vddxo", "wcnss_wlan.0"),
};
VREG_CONSUMERS(L5) = {
- REGULATOR_SUPPLY("8038_l5", NULL),
+ REGULATOR_SUPPLY("8917_l5", NULL),
REGULATOR_SUPPLY("sdc_vdd", "msm_sdcc.1"),
};
VREG_CONSUMERS(L6) = {
- REGULATOR_SUPPLY("8038_l6", NULL),
+ REGULATOR_SUPPLY("8917_l6", NULL),
REGULATOR_SUPPLY("sdc_vdd", "msm_sdcc.3"),
};
VREG_CONSUMERS(L7) = {
- REGULATOR_SUPPLY("8038_l7", NULL),
+ REGULATOR_SUPPLY("8917_l7", NULL),
+ REGULATOR_SUPPLY("sdc_vdd_io", "msm_sdcc.3"),
};
VREG_CONSUMERS(L8) = {
- REGULATOR_SUPPLY("8038_l8", NULL),
+ REGULATOR_SUPPLY("8917_l8", NULL),
REGULATOR_SUPPLY("dsi_vdc", "mipi_dsi.1"),
};
VREG_CONSUMERS(L9) = {
- REGULATOR_SUPPLY("8038_l9", NULL),
+ REGULATOR_SUPPLY("8917_l9", NULL),
REGULATOR_SUPPLY("vdd_ana", "3-004a"),
REGULATOR_SUPPLY("vdd", "3-0024"),
- REGULATOR_SUPPLY("cam_vana", "4-001a"),
- REGULATOR_SUPPLY("cam_vana", "4-006c"),
- REGULATOR_SUPPLY("cam_vana", "4-0048"),
- REGULATOR_SUPPLY("cam_vaf", "4-001a"),
- REGULATOR_SUPPLY("cam_vaf", "4-006c"),
- REGULATOR_SUPPLY("cam_vaf", "4-0048"),
- REGULATOR_SUPPLY("cam_vana", "4-0020"),
- REGULATOR_SUPPLY("cam_vaf", "4-0020"),
REGULATOR_SUPPLY("vdd", "12-0018"),
REGULATOR_SUPPLY("vdd", "12-0068"),
};
VREG_CONSUMERS(L10) = {
- REGULATOR_SUPPLY("8038_l10", NULL),
+ REGULATOR_SUPPLY("8917_l10", NULL),
REGULATOR_SUPPLY("iris_vddpa", "wcnss_wlan.0"),
};
VREG_CONSUMERS(L11) = {
- REGULATOR_SUPPLY("8038_l11", NULL),
+ REGULATOR_SUPPLY("8917_l11", NULL),
+ REGULATOR_SUPPLY("cam_vana", "4-001a"),
+ REGULATOR_SUPPLY("cam_vana", "4-006c"),
+ REGULATOR_SUPPLY("cam_vana", "4-0048"),
+ REGULATOR_SUPPLY("cam_vana", "4-0020"),
+};
+VREG_CONSUMERS(L12) = {
+ REGULATOR_SUPPLY("8917_l12", NULL),
+ REGULATOR_SUPPLY("cam_vdig", "4-001a"),
+ REGULATOR_SUPPLY("cam_vdig", "4-006c"),
+ REGULATOR_SUPPLY("cam_vdig", "4-0048"),
+ REGULATOR_SUPPLY("cam_vdig", "4-0020"),
+};
+VREG_CONSUMERS(L14) = {
+ REGULATOR_SUPPLY("8917_l14", NULL),
+ REGULATOR_SUPPLY("pa_therm", "pm8xxx-adc"),
+};
+VREG_CONSUMERS(L15) = {
+ REGULATOR_SUPPLY("8917_l15", NULL),
+};
+VREG_CONSUMERS(L16) = {
+ REGULATOR_SUPPLY("8917_l16", NULL),
+ REGULATOR_SUPPLY("cam_vaf", "4-001a"),
+ REGULATOR_SUPPLY("cam_vaf", "4-006c"),
+ REGULATOR_SUPPLY("cam_vaf", "4-0048"),
+ REGULATOR_SUPPLY("cam_vaf", "4-0020"),
+};
+VREG_CONSUMERS(L17) = {
+ REGULATOR_SUPPLY("8917_l17", NULL),
+};
+VREG_CONSUMERS(L18) = {
+ REGULATOR_SUPPLY("8917_l18", NULL),
+};
+VREG_CONSUMERS(L21) = {
+ REGULATOR_SUPPLY("8917_l21", NULL),
+};
+VREG_CONSUMERS(L22) = {
+ REGULATOR_SUPPLY("8917_l22", NULL),
+};
+VREG_CONSUMERS(L23) = {
+ REGULATOR_SUPPLY("8917_l23", NULL),
+ REGULATOR_SUPPLY("dsi_vddio", "mipi_dsi.1"),
+ REGULATOR_SUPPLY("hdmi_avdd", "hdmi_msm.0"),
+ REGULATOR_SUPPLY("hdmi_vcc", "hdmi_msm.0"),
+ REGULATOR_SUPPLY("pll_vdd", "pil_riva"),
+ REGULATOR_SUPPLY("pll_vdd", "pil_qdsp6v4.1"),
+ REGULATOR_SUPPLY("pll_vdd", "pil_qdsp6v4.2"),
+};
+VREG_CONSUMERS(L24) = {
+ REGULATOR_SUPPLY("8917_l24", NULL),
+ REGULATOR_SUPPLY("riva_vddmx", "wcnss_wlan.0"),
+};
+VREG_CONSUMERS(L25) = {
+ REGULATOR_SUPPLY("8917_l25", NULL),
+ REGULATOR_SUPPLY("VDDD_CDC_D", "sitar-slim"),
+ REGULATOR_SUPPLY("CDC_VDDA_A_1P2V", "sitar-slim"),
+ REGULATOR_SUPPLY("VDDD_CDC_D", "sitar1p1-slim"),
+ REGULATOR_SUPPLY("CDC_VDDA_A_1P2V", "sitar1p1-slim"),
+ REGULATOR_SUPPLY("mhl_avcc12", "0-0039"),
+};
+VREG_CONSUMERS(L26) = {
+ REGULATOR_SUPPLY("8921_l26", NULL),
+ REGULATOR_SUPPLY("core_vdd", "pil_qdsp6v4.0"),
+};
+VREG_CONSUMERS(L27) = {
+ REGULATOR_SUPPLY("8921_l27", NULL),
+ REGULATOR_SUPPLY("core_vdd", "pil_qdsp6v4.2"),
+};
+VREG_CONSUMERS(L28) = {
+ REGULATOR_SUPPLY("8921_l28", NULL),
+ REGULATOR_SUPPLY("core_vdd", "pil_qdsp6v4.1"),
+};
+VREG_CONSUMERS(L29) = {
+ REGULATOR_SUPPLY("8921_l29", NULL),
+};
+VREG_CONSUMERS(L30) = {
+ REGULATOR_SUPPLY("8917_l30", NULL),
+};
+VREG_CONSUMERS(L31) = {
+ REGULATOR_SUPPLY("8917_l31", NULL),
+};
+VREG_CONSUMERS(L32) = {
+ REGULATOR_SUPPLY("8917_l32", NULL),
+};
+VREG_CONSUMERS(L33) = {
+ REGULATOR_SUPPLY("8917_l33", NULL),
+};
+VREG_CONSUMERS(L34) = {
+ REGULATOR_SUPPLY("8917_l34", NULL),
+};
+VREG_CONSUMERS(L35) = {
+ REGULATOR_SUPPLY("8917_l35", NULL),
+};
+VREG_CONSUMERS(L36) = {
+ REGULATOR_SUPPLY("8917_l36", NULL),
+};
+VREG_CONSUMERS(S1) = {
+ REGULATOR_SUPPLY("8917_s1", NULL),
+};
+VREG_CONSUMERS(S2) = {
+ REGULATOR_SUPPLY("8917_s2", NULL),
+ REGULATOR_SUPPLY("iris_vddrfa", "wcnss_wlan.0"),
+};
+VREG_CONSUMERS(S3) = {
+ REGULATOR_SUPPLY("8917_s3", NULL),
+ REGULATOR_SUPPLY("riva_vddcx", "wcnss_wlan.0"),
+};
+VREG_CONSUMERS(S4) = {
+ REGULATOR_SUPPLY("8917_s4", NULL),
REGULATOR_SUPPLY("vdd_dig", "3-004a"),
- REGULATOR_SUPPLY("iris_vddio", "wcnss_wlan.0"),
- REGULATOR_SUPPLY("riva_vddpx", "wcnss_wlan.0"),
REGULATOR_SUPPLY("sdc_vdd_io", "msm_sdcc.1"),
REGULATOR_SUPPLY("VDDIO_CDC", "sitar-slim"),
REGULATOR_SUPPLY("CDC_VDDA_TX", "sitar-slim"),
@@ -91,132 +194,71 @@
REGULATOR_SUPPLY("CDC_VDDA_RX", "sitar1p1-slim"),
REGULATOR_SUPPLY("vddp", "0-0048"),
REGULATOR_SUPPLY("mhl_iovcc18", "0-0039"),
-};
-VREG_CONSUMERS(L12) = {
- REGULATOR_SUPPLY("8038_l12", NULL),
- REGULATOR_SUPPLY("cam_vdig", "4-001a"),
- REGULATOR_SUPPLY("cam_vdig", "4-006c"),
- REGULATOR_SUPPLY("cam_vdig", "4-0048"),
- REGULATOR_SUPPLY("cam_vdig", "4-0020"),
-};
-VREG_CONSUMERS(L13) = {
- REGULATOR_SUPPLY("8038_l13", NULL),
-};
-VREG_CONSUMERS(L14) = {
- REGULATOR_SUPPLY("8038_l14", NULL),
- REGULATOR_SUPPLY("pa_therm", "pm8xxx-adc"),
-};
-VREG_CONSUMERS(L15) = {
- REGULATOR_SUPPLY("8038_l15", NULL),
-};
-VREG_CONSUMERS(L16) = {
- REGULATOR_SUPPLY("8038_l16", NULL),
- REGULATOR_SUPPLY("core_vdd", "pil_qdsp6v4.2"),
-};
-VREG_CONSUMERS(L17) = {
- REGULATOR_SUPPLY("8038_l17", NULL),
-};
-VREG_CONSUMERS(L18) = {
- REGULATOR_SUPPLY("8038_l18", NULL),
-};
-VREG_CONSUMERS(L19) = {
- REGULATOR_SUPPLY("8038_l19", NULL),
- REGULATOR_SUPPLY("core_vdd", "pil_qdsp6v4.1"),
-};
-VREG_CONSUMERS(L20) = {
- REGULATOR_SUPPLY("8038_l20", NULL),
- REGULATOR_SUPPLY("VDDD_CDC_D", "sitar-slim"),
- REGULATOR_SUPPLY("CDC_VDDA_A_1P2V", "sitar-slim"),
- REGULATOR_SUPPLY("VDDD_CDC_D", "sitar1p1-slim"),
- REGULATOR_SUPPLY("CDC_VDDA_A_1P2V", "sitar1p1-slim"),
- REGULATOR_SUPPLY("mhl_avcc12", "0-0039"),
-};
-VREG_CONSUMERS(L21) = {
- REGULATOR_SUPPLY("8038_l21", NULL),
-};
-VREG_CONSUMERS(L22) = {
- REGULATOR_SUPPLY("8038_l22", NULL),
- REGULATOR_SUPPLY("sdc_vdd_io", "msm_sdcc.3"),
-};
-VREG_CONSUMERS(L23) = {
- REGULATOR_SUPPLY("8038_l23", NULL),
- REGULATOR_SUPPLY("dsi_vddio", "mipi_dsi.1"),
- REGULATOR_SUPPLY("hdmi_avdd", "hdmi_msm.0"),
- REGULATOR_SUPPLY("hdmi_vcc", "hdmi_msm.0"),
- REGULATOR_SUPPLY("pll_vdd", "pil_riva"),
- REGULATOR_SUPPLY("pll_vdd", "pil_qdsp6v4.1"),
- REGULATOR_SUPPLY("pll_vdd", "pil_qdsp6v4.2"),
-};
-VREG_CONSUMERS(L24) = {
- REGULATOR_SUPPLY("8038_l24", NULL),
- REGULATOR_SUPPLY("riva_vddmx", "wcnss_wlan.0"),
-};
-VREG_CONSUMERS(L25) = {
- REGULATOR_SUPPLY("8038_l25", NULL),
-};
-VREG_CONSUMERS(L26) = {
- REGULATOR_SUPPLY("8038_l26", NULL),
-};
-VREG_CONSUMERS(L27) = {
- REGULATOR_SUPPLY("8038_l27", NULL),
- REGULATOR_SUPPLY("core_vdd", "pil_qdsp6v4.0"),
-};
-VREG_CONSUMERS(S1) = {
- REGULATOR_SUPPLY("8038_s1", NULL),
- REGULATOR_SUPPLY("riva_vddcx", "wcnss_wlan.0"),
-};
-VREG_CONSUMERS(S2) = {
- REGULATOR_SUPPLY("8038_s2", NULL),
-};
-VREG_CONSUMERS(S3) = {
- REGULATOR_SUPPLY("8038_s3", NULL),
-};
-VREG_CONSUMERS(S4) = {
- REGULATOR_SUPPLY("8038_s4", NULL),
REGULATOR_SUPPLY("CDC_VDD_CP", "sitar-slim"),
REGULATOR_SUPPLY("CDC_VDD_CP", "sitar1p1-slim"),
};
VREG_CONSUMERS(S5) = {
- REGULATOR_SUPPLY("8038_s5", NULL),
+ REGULATOR_SUPPLY("8917_s5", NULL),
REGULATOR_SUPPLY("krait0", "acpuclk-8627"),
REGULATOR_SUPPLY("krait0", "acpuclk-8930"),
REGULATOR_SUPPLY("krait0", "acpuclk-8930aa"),
};
VREG_CONSUMERS(S6) = {
- REGULATOR_SUPPLY("8038_s6", NULL),
+ REGULATOR_SUPPLY("8917_s6", NULL),
REGULATOR_SUPPLY("krait1", "acpuclk-8627"),
REGULATOR_SUPPLY("krait1", "acpuclk-8930"),
REGULATOR_SUPPLY("krait1", "acpuclk-8930aa"),
};
-VREG_CONSUMERS(LVS1) = {
- REGULATOR_SUPPLY("8038_lvs1", NULL),
- REGULATOR_SUPPLY("cam_vio", "4-001a"),
- REGULATOR_SUPPLY("cam_vio", "4-006c"),
- REGULATOR_SUPPLY("cam_vio", "4-0048"),
- REGULATOR_SUPPLY("cam_vio", "4-0020"),
+VREG_CONSUMERS(S7) = {
+ REGULATOR_SUPPLY("8917_s7", NULL),
};
-VREG_CONSUMERS(LVS2) = {
- REGULATOR_SUPPLY("8038_lvs2", NULL),
+VREG_CONSUMERS(S8) = {
+ REGULATOR_SUPPLY("8917_s8", NULL),
+};
+VREG_CONSUMERS(LVS1) = {
+ REGULATOR_SUPPLY("8917_lvs1", NULL),
+ REGULATOR_SUPPLY("iris_vddio", "wcnss_wlan.0"),
+ REGULATOR_SUPPLY("riva_vddpx", "wcnss_wlan.0"),
+};
+VREG_CONSUMERS(LVS3) = {
+ REGULATOR_SUPPLY("8917_lvs3", NULL),
+};
+VREG_CONSUMERS(LVS4) = {
+ REGULATOR_SUPPLY("8917_lvs4", NULL),
REGULATOR_SUPPLY("vcc_i2c", "3-004a"),
REGULATOR_SUPPLY("vcc_i2c", "3-0024"),
REGULATOR_SUPPLY("vcc_i2c", "0-0048"),
REGULATOR_SUPPLY("vddio", "12-0018"),
REGULATOR_SUPPLY("vlogic", "12-0068"),
};
-VREG_CONSUMERS(EXT_5V) = {
- REGULATOR_SUPPLY("ext_5v", NULL),
+VREG_CONSUMERS(LVS5) = {
+ REGULATOR_SUPPLY("8917_lvs5", NULL),
+ REGULATOR_SUPPLY("cam_vio", "4-001a"),
+ REGULATOR_SUPPLY("cam_vio", "4-006c"),
+ REGULATOR_SUPPLY("cam_vio", "4-0048"),
+ REGULATOR_SUPPLY("cam_vio", "4-0020"),
+};
+VREG_CONSUMERS(LVS6) = {
+ REGULATOR_SUPPLY("8917_lvs6", NULL),
+};
+VREG_CONSUMERS(LVS7) = {
+ REGULATOR_SUPPLY("8917_lvs7", NULL),
+};
+VREG_CONSUMERS(USB_OTG) = {
+ REGULATOR_SUPPLY("8921_usb_otg", NULL),
+ REGULATOR_SUPPLY("vbus_otg", "msm_otg"),
+};
+VREG_CONSUMERS(BOOST) = {
+ REGULATOR_SUPPLY("8917_boost", NULL),
REGULATOR_SUPPLY("hdmi_mvs", "hdmi_msm.0"),
REGULATOR_SUPPLY("mhl_usb_hs_switch", "msm_otg"),
};
-VREG_CONSUMERS(EXT_OTG_SW) = {
- REGULATOR_SUPPLY("ext_otg_sw", NULL),
- REGULATOR_SUPPLY("vbus_otg", "msm_otg"),
-};
VREG_CONSUMERS(VDD_DIG_CORNER) = {
REGULATOR_SUPPLY("vdd_dig_corner", NULL),
REGULATOR_SUPPLY("hsusb_vdd_dig", "msm_otg"),
};
+
#define PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, _modes, _ops, \
_apply_uV, _pull_down, _always_on, _supply_regulator, \
_system_uA, _enable_time, _reg_id) \
@@ -286,7 +328,7 @@
_pull_down, _always_on, _supply_regulator, 0, _enable_time, \
_reg_id)
-#define PM8XXX_NCP(_id, _name, _always_on, _min_uV, _max_uV, _enable_time, \
+#define PM8XXX_BOOST(_id, _name, _always_on, _min_uV, _max_uV, _enable_time, \
_supply_regulator, _reg_id) \
PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, 0, \
REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS, 0, 0, \
@@ -332,7 +374,7 @@
.consumer_supplies = vreg_consumers_##_id, \
.supply_regulator = _supply_regulator, \
}, \
- .id = RPM_VREG_ID_PM8038_##_id, \
+ .id = RPM_VREG_ID_PM8917_##_id, \
.default_uV = _default_uV, \
.peak_uA = _peak_uA, \
.avg_uA = _avg_uA, \
@@ -414,7 +456,7 @@
.consumer_supplies = vreg_consumers_##_id##_PC, \
.supply_regulator = _supply_regulator, \
}, \
- .id = RPM_VREG_ID_PM8038_##_id##_PC, \
+ .id = RPM_VREG_ID_PM8917_##_id##_PC, \
.pin_fn = RPM_VREG_PIN_FN_8930_##_pin_fn, \
.pin_ctrl = _pin_ctrl, \
}
@@ -449,93 +491,122 @@
/* GPIO regulator constraints */
struct gpio_regulator_platform_data
-msm8930_gpio_regulator_pdata[] __devinitdata = {
+msm8930_pm8917_gpio_regulator_pdata[] __devinitdata = {
/* ID vreg_name gpio_label gpio supply */
- GPIO_VREG(EXT_5V, "ext_5v", "ext_5v_en", 63, NULL),
- GPIO_VREG(EXT_OTG_SW, "ext_otg_sw", "ext_otg_sw_en", 97, "ext_5v"),
};
/* SAW regulator constraints */
-struct regulator_init_data msm8930_saw_regulator_core0_pdata =
+struct regulator_init_data msm8930_pm8917_saw_regulator_core0_pdata =
/* ID vreg_name min_uV max_uV */
- SAW_VREG_INIT(S5, "8038_s5", 850000, 1300000);
-struct regulator_init_data msm8930_saw_regulator_core1_pdata =
- SAW_VREG_INIT(S6, "8038_s6", 850000, 1300000);
+ SAW_VREG_INIT(S5, "8917_s5", 850000, 1300000);
+struct regulator_init_data msm8930_pm8917_saw_regulator_core1_pdata =
+ SAW_VREG_INIT(S6, "8917_s6", 850000, 1300000);
-/* PM8038 regulator constraints */
+/* PM8917 regulator constraints */
struct pm8xxx_regulator_platform_data
-msm8930_pm8038_regulator_pdata[] __devinitdata = {
+msm8930_pm8917_regulator_pdata[] __devinitdata = {
/*
- * ID name always_on pd min_uV max_uV en_t supply
+ * ID name always_on pd min_uV max_uV en_t supply
* system_uA reg_ID
*/
- PM8XXX_NLDO1200(L16, "8038_l16", 0, 1, 375000, 1050000, 200, "8038_s3",
+ PM8XXX_NLDO1200(L26, "8921_l26", 0, 1, 375000, 1050000, 200, "8917_s7",
0, 0),
- PM8XXX_NLDO1200(L19, "8038_l19", 0, 1, 375000, 1050000, 200, "8038_s3",
+ PM8XXX_NLDO1200(L27, "8921_l27", 0, 1, 375000, 1050000, 200, "8917_s7",
0, 1),
- PM8XXX_NLDO1200(L27, "8038_l27", 0, 1, 375000, 1050000, 200, "8038_s3",
+ PM8XXX_NLDO1200(L28, "8921_l28", 0, 1, 375000, 1050000, 200, "8917_s7",
0, 2),
+ PM8XXX_LDO(L29, "8921_l29", 0, 1, 1800000, 1800000, 200, "8917_s8",
+ 0, 3),
+ PM8XXX_LDO(L30, "8917_l30", 0, 1, 1800000, 1800000, 200, NULL,
+ 0, 4),
+ PM8XXX_LDO(L31, "8917_l31", 0, 1, 1800000, 1800000, 200, NULL,
+ 0, 5),
+ PM8XXX_LDO(L32, "8917_l32", 0, 1, 2800000, 2800000, 200, NULL,
+ 0, 6),
+ PM8XXX_LDO(L33, "8917_l33", 0, 1, 2800000, 2800000, 200, NULL,
+ 0, 7),
+ PM8XXX_LDO(L34, "8917_l34", 0, 1, 1800000, 1800000, 200, NULL,
+ 0, 8),
+ PM8XXX_LDO(L35, "8917_l35", 0, 1, 3000000, 3000000, 200, NULL,
+ 0, 9),
+ PM8XXX_LDO(L36, "8917_l36", 0, 1, 1800000, 1800000, 200, NULL,
+ 0, 10),
+ /*
+ * ID name always_on min_uV max_uV en_t supply reg_ID
+ */
+ PM8XXX_BOOST(BOOST, "8917_boost", 0, 5000000, 5000000, 500, NULL, 11),
+
+ /* ID name always_on pd en_t supply reg_ID */
+ PM8XXX_VS300(USB_OTG, "8921_usb_otg", 0, 1, 0, "8917_boost", 12),
};
static struct rpm_regulator_init_data
msm8930_rpm_regulator_init_data[] __devinitdata = {
/* ID a_on pd ss min_uV max_uV supply sys_uA freq fm ss_fm */
- RPM_SMPS(S1, 0, 1, 1, 500000, 1150000, NULL, 100000, 4p80, AUTO, LPM),
- RPM_SMPS(S2, 1, 1, 1, 1400000, 1400000, NULL, 100000, 1p60, AUTO, LPM),
- RPM_SMPS(S3, 0, 1, 1, 1150000, 1150000, NULL, 100000, 3p20, AUTO, LPM),
- RPM_SMPS(S4, 1, 1, 1, 1950000, 2200000, NULL, 100000, 1p60, AUTO, LPM),
+ RPM_SMPS(S1, 1, 1, 0, 1300000, 1300000, NULL, 100000, 3p20, NONE, NONE),
+ RPM_SMPS(S2, 0, 1, 0, 1300000, 1300000, NULL, 0, 1p60, NONE, NONE),
+ RPM_SMPS(S3, 0, 1, 1, 500000, 1150000, NULL, 100000, 4p80, AUTO, LPM),
+ RPM_SMPS(S4, 1, 1, 0, 1800000, 1800000, NULL, 100000, 1p60, AUTO, LPM),
+ RPM_SMPS(S7, 0, 1, 0, 1150000, 1150000, NULL, 100000, 3p20, NONE, NONE),
+ RPM_SMPS(S8, 1, 1, 1, 2050000, 2050000, NULL, 100000, 1p60, NONE, NONE),
/* ID a_on pd ss min_uV max_uV supply sys_uA init_ip */
- RPM_LDO(L1, 0, 1, 0, 1300000, 1300000, "8038_s2", 0, 0),
- RPM_LDO(L2, 0, 1, 0, 1200000, 1200000, "8038_s2", 0, 0),
+ RPM_LDO(L1, 1, 1, 0, 1050000, 1050000, "8917_s4", 0, 10000),
+ RPM_LDO(L2, 0, 1, 0, 1200000, 1200000, "8917_s4", 0, 0),
RPM_LDO(L3, 0, 1, 0, 3075000, 3075000, NULL, 0, 0),
RPM_LDO(L4, 1, 1, 0, 1800000, 1800000, NULL, 10000, 10000),
RPM_LDO(L5, 0, 1, 0, 2950000, 2950000, NULL, 0, 0),
RPM_LDO(L6, 0, 1, 0, 2950000, 2950000, NULL, 0, 0),
- RPM_LDO(L7, 0, 1, 0, 2050000, 2050000, "8038_s4", 0, 0),
+ RPM_LDO(L7, 1, 1, 0, 1850000, 2950000, NULL, 10000, 10000),
RPM_LDO(L8, 0, 1, 0, 2800000, 2800000, NULL, 0, 0),
RPM_LDO(L9, 0, 1, 0, 2850000, 2850000, NULL, 0, 0),
RPM_LDO(L10, 0, 1, 0, 2900000, 2900000, NULL, 0, 0),
- RPM_LDO(L11, 1, 1, 0, 1800000, 1800000, "8038_s4", 10000, 10000),
- RPM_LDO(L12, 0, 1, 0, 1200000, 1200000, "8038_s2", 0, 0),
- RPM_LDO(L13, 0, 0, 0, 2220000, 2220000, NULL, 0, 0),
+ RPM_LDO(L11, 0, 1, 0, 2850000, 2850000, NULL, 0, 0),
+ RPM_LDO(L12, 0, 1, 0, 1200000, 1200000, "8917_s4", 0, 0),
RPM_LDO(L14, 0, 1, 0, 1800000, 1800000, NULL, 0, 0),
RPM_LDO(L15, 0, 1, 0, 1800000, 2950000, NULL, 0, 0),
+ RPM_LDO(L16, 0, 1, 0, 2850000, 2850000, NULL, 0, 0),
RPM_LDO(L17, 0, 1, 0, 1800000, 2950000, NULL, 0, 0),
- RPM_LDO(L18, 0, 1, 0, 1800000, 1800000, NULL, 0, 0),
- RPM_LDO(L20, 1, 1, 0, 1250000, 1250000, "8038_s2", 10000, 10000),
- RPM_LDO(L21, 0, 1, 0, 1900000, 1900000, "8038_s4", 0, 0),
- RPM_LDO(L22, 1, 1, 0, 1850000, 2950000, NULL, 10000, 10000),
- RPM_LDO(L23, 1, 1, 1, 1800000, 1800000, "8038_s4", 0, 0),
- RPM_LDO(L24, 0, 1, 1, 500000, 1150000, "8038_s2", 10000, 10000),
- RPM_LDO(L25, 0, 0, 0, 1740000, 1740000, "8038_l13", 0, 0),
- RPM_LDO(L26, 1, 1, 0, 1050000, 1050000, "8038_s2", 10000, 10000),
+ RPM_LDO(L18, 0, 1, 0, 1200000, 1200000, "8917_s4", 0, 0),
+ RPM_LDO(L21, 0, 1, 0, 1900000, 1900000, "8917_s8", 0, 0),
+ RPM_LDO(L22, 0, 1, 0, 2750000, 2750000, NULL, 0, 0),
+ RPM_LDO(L23, 1, 1, 1, 1800000, 1800000, "8917_s8", 10000, 10000),
+ RPM_LDO(L24, 0, 1, 1, 500000, 1150000, "8917_s1", 10000, 10000),
+ RPM_LDO(L25, 1, 1, 0, 1250000, 1250000, "8917_s1", 10000, 10000),
/* ID a_on pd ss supply */
- RPM_VS(LVS1, 0, 1, 0, "8038_l11"),
- RPM_VS(LVS2, 0, 1, 0, "8038_l11"),
+ RPM_VS(LVS1, 0, 1, 0, "8917_s4"),
+ RPM_VS(LVS3, 0, 1, 0, "8917_s4"),
+ RPM_VS(LVS4, 0, 1, 0, "8917_s4"),
+ RPM_VS(LVS5, 0, 1, 0, "8917_s4"),
+ RPM_VS(LVS6, 0, 1, 0, "8917_s4"),
+ RPM_VS(LVS7, 0, 1, 0, "8917_s4"),
/* ID a_on ss min_corner max_corner supply */
RPM_CORNER(VDD_DIG_CORNER, 0, 1, RPM_VREG_CORNER_NONE,
RPM_VREG_CORNER_HIGH, NULL),
};
-int msm8930_pm8038_regulator_pdata_len __devinitdata =
- ARRAY_SIZE(msm8930_pm8038_regulator_pdata);
+int msm8930_pm8917_regulator_pdata_len __devinitdata =
+ ARRAY_SIZE(msm8930_pm8917_regulator_pdata);
#define RPM_REG_MAP(_id, _sleep_also, _voter, _supply, _dev_name) \
{ \
- .vreg_id = RPM_VREG_ID_PM8038_##_id, \
+ .vreg_id = RPM_VREG_ID_PM8917_##_id, \
.sleep_also = _sleep_also, \
.voter = _voter, \
.supply = _supply, \
.dev_name = _dev_name, \
}
+
static struct rpm_regulator_consumer_mapping
msm_rpm_regulator_consumer_mapping[] __devinitdata = {
- RPM_REG_MAP(L23, 0, 1, "krait0_hfpll", "acpuclk-8930"),
- RPM_REG_MAP(L23, 0, 2, "krait1_hfpll", "acpuclk-8930"),
- RPM_REG_MAP(L23, 0, 6, "l2_hfpll", "acpuclk-8930"),
+ RPM_REG_MAP(L23, 0, 1, "krait0_l23", "acpuclk-8930"),
+ RPM_REG_MAP(S8, 0, 1, "krait0_s8", "acpuclk-8930"),
+ RPM_REG_MAP(L23, 0, 2, "krait1_l23", "acpuclk-8930"),
+ RPM_REG_MAP(S8, 0, 2, "krait1_s8", "acpuclk-8930"),
+ RPM_REG_MAP(L23, 0, 6, "l2_l23", "acpuclk-8930"),
+ RPM_REG_MAP(S8, 0, 6, "l2_s8", "acpuclk-8930"),
RPM_REG_MAP(L24, 0, 1, "krait0_mem", "acpuclk-8930"),
RPM_REG_MAP(L24, 0, 2, "krait1_mem", "acpuclk-8930"),
RPM_REG_MAP(VDD_DIG_CORNER, 0, 1, "krait0_dig", "acpuclk-8930"),
@@ -558,12 +629,13 @@
RPM_REG_MAP(VDD_DIG_CORNER, 0, 2, "krait1_dig", "acpuclk-8930aa"),
};
-struct rpm_regulator_platform_data msm8930_rpm_regulator_pdata __devinitdata = {
+struct rpm_regulator_platform_data
+msm8930_pm8917_rpm_regulator_pdata __devinitdata = {
.init_data = msm8930_rpm_regulator_init_data,
.num_regulators = ARRAY_SIZE(msm8930_rpm_regulator_init_data),
- .version = RPM_VREG_VERSION_8930,
- .vreg_id_vdd_mem = RPM_VREG_ID_PM8038_L24,
- .vreg_id_vdd_dig = RPM_VREG_ID_PM8038_VDD_DIG_CORNER,
+ .version = RPM_VREG_VERSION_8930_PM8917,
+ .vreg_id_vdd_mem = RPM_VREG_ID_PM8917_L24,
+ .vreg_id_vdd_dig = RPM_VREG_ID_PM8917_VDD_DIG_CORNER,
.consumer_map = msm_rpm_regulator_consumer_mapping,
.consumer_map_len = ARRAY_SIZE(msm_rpm_regulator_consumer_mapping),
};
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index a7147b5..7760f07 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -100,6 +100,7 @@
#include "pm-boot.h"
#include "msm_watchdog.h"
#include "board-8930.h"
+#include "acpuclock-krait.h"
static struct platform_device msm_fm_platform_init = {
.name = "iris_fm",
@@ -791,7 +792,7 @@
.regulator = {
{
.name = "CDC_VDD_CP",
- .min_uV = 1950000,
+ .min_uV = 1800000,
.max_uV = 2200000,
.optimum_uA = WCD9XXX_CDC_VDDA_CP_CUR_MAX,
},
@@ -857,7 +858,7 @@
.regulator = {
{
.name = "CDC_VDD_CP",
- .min_uV = 1950000,
+ .min_uV = 1800000,
.max_uV = 2200000,
.optimum_uA = WCD9XXX_CDC_VDDA_CP_CUR_MAX,
},
@@ -1541,6 +1542,11 @@
0x03, 0x0f,
};
+static uint8_t spm_retention_cmd_sequence[] __initdata = {
+ 0x00, 0x05, 0x03, 0x0D,
+ 0x0B, 0x00, 0x0f,
+};
+
static uint8_t spm_power_collapse_without_rpm[] __initdata = {
0x00, 0x24, 0x54, 0x10,
0x09, 0x03, 0x01,
@@ -1555,7 +1561,30 @@
0x24, 0x30, 0x0f,
};
-static struct msm_spm_seq_entry msm_spm_seq_list[] __initdata = {
+static struct msm_spm_seq_entry msm_spm_boot_cpu_seq_list[] __initdata = {
+ [0] = {
+ .mode = MSM_SPM_MODE_CLOCK_GATING,
+ .notify_rpm = false,
+ .cmd = spm_wfi_cmd_sequence,
+ },
+ [1] = {
+ .mode = MSM_SPM_MODE_POWER_RETENTION,
+ .notify_rpm = false,
+ .cmd = spm_retention_cmd_sequence,
+ },
+ [2] = {
+ .mode = MSM_SPM_MODE_POWER_COLLAPSE,
+ .notify_rpm = false,
+ .cmd = spm_power_collapse_without_rpm,
+ },
+ [3] = {
+ .mode = MSM_SPM_MODE_POWER_COLLAPSE,
+ .notify_rpm = true,
+ .cmd = spm_power_collapse_with_rpm,
+ },
+};
+
+static struct msm_spm_seq_entry msm_spm_nonboot_cpu_seq_list[] __initdata = {
[0] = {
.mode = MSM_SPM_MODE_CLOCK_GATING,
.notify_rpm = false,
@@ -1582,12 +1611,12 @@
.reg_init_values[MSM_SPM_REG_SAW2_AVS_HYSTERESIS] = 0x00,
#endif
.reg_init_values[MSM_SPM_REG_SAW2_SPM_CTL] = 0x01,
- .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DLY] = 0x02020204,
- .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_0] = 0x0060009C,
- .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_1] = 0x0000001C,
+ .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DLY] = 0x03020004,
+ .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_0] = 0x0084009C,
+ .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_1] = 0x00A4001C,
.vctl_timeout_us = 50,
- .num_modes = ARRAY_SIZE(msm_spm_seq_list),
- .modes = msm_spm_seq_list,
+ .num_modes = ARRAY_SIZE(msm_spm_boot_cpu_seq_list),
+ .modes = msm_spm_boot_cpu_seq_list,
},
[1] = {
.reg_base_addr = MSM_SAW1_BASE,
@@ -1601,8 +1630,8 @@
.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_0] = 0x0060009C,
.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_1] = 0x0000001C,
.vctl_timeout_us = 50,
- .num_modes = ARRAY_SIZE(msm_spm_seq_list),
- .modes = msm_spm_seq_list,
+ .num_modes = ARRAY_SIZE(msm_spm_nonboot_cpu_seq_list),
+ .modes = msm_spm_nonboot_cpu_seq_list,
},
};
@@ -1656,18 +1685,26 @@
#define ISA1200_HAP_EN_GPIO 77
#define ISA1200_HAP_LEN_GPIO 78
-#define ISA1200_HAP_CLK PM8038_GPIO_PM_TO_SYS(7)
+#define ISA1200_HAP_CLK_PM8038 PM8038_GPIO_PM_TO_SYS(7)
+#define ISA1200_HAP_CLK_PM8917 PM8917_GPIO_PM_TO_SYS(38)
static int isa1200_power(int on)
{
+ unsigned int gpio = ISA1200_HAP_CLK_PM8038;
+ enum pm8xxx_aux_clk_id clk_id = CLK_MP3_1;
int rc = 0;
- gpio_set_value_cansleep(ISA1200_HAP_CLK, !!on);
+ if (socinfo_get_pmic_model() == PMIC_MODEL_PM8917) {
+ gpio = ISA1200_HAP_CLK_PM8917;
+ clk_id = CLK_MP3_2;
+ }
+
+ gpio_set_value_cansleep(gpio, !!on);
if (on)
- rc = pm8xxx_aux_clk_control(CLK_MP3_1, XO_DIV_1, true);
+ rc = pm8xxx_aux_clk_control(clk_id, XO_DIV_1, true);
else
- rc = pm8xxx_aux_clk_control(CLK_MP3_1, XO_DIV_NONE, true);
+ rc = pm8xxx_aux_clk_control(clk_id, XO_DIV_NONE, true);
if (rc) {
pr_err("%s: unable to write aux clock register(%d)\n",
@@ -1679,29 +1716,33 @@
static int isa1200_dev_setup(bool enable)
{
+ unsigned int gpio = ISA1200_HAP_CLK_PM8038;
int rc = 0;
+ if (socinfo_get_pmic_model() == PMIC_MODEL_PM8917)
+ gpio = ISA1200_HAP_CLK_PM8917;
+
if (!enable)
goto fail_gpio_dir;
- rc = gpio_request(ISA1200_HAP_CLK, "haptics_clk");
+ rc = gpio_request(gpio, "haptics_clk");
if (rc) {
pr_err("%s: gpio_request for %d gpio failed rc(%d)\n",
- __func__, ISA1200_HAP_CLK, rc);
+ __func__, gpio, rc);
goto fail_gpio_req;
}
- rc = gpio_direction_output(ISA1200_HAP_CLK, 0);
+ rc = gpio_direction_output(gpio, 0);
if (rc) {
pr_err("%s: gpio_direction_output failed for %d gpio rc(%d)\n",
- __func__, ISA1200_HAP_CLK, rc);
+ __func__, gpio, rc);
goto fail_gpio_dir;
}
return 0;
fail_gpio_dir:
- gpio_free(ISA1200_HAP_CLK);
+ gpio_free(gpio);
fail_gpio_req:
return rc;
@@ -1938,12 +1979,13 @@
},
};
-#define MHL_POWER_GPIO PM8038_GPIO_PM_TO_SYS(MHL_GPIO_PWR_EN)
+#define MHL_POWER_GPIO_PM8038 PM8038_GPIO_PM_TO_SYS(MHL_GPIO_PWR_EN)
+#define MHL_POWER_GPIO_PM8917 PM8917_GPIO_PM_TO_SYS(25)
static struct msm_mhl_platform_data mhl_platform_data = {
.irq = MSM_GPIO_TO_INT(MHL_GPIO_INT),
.gpio_mhl_int = MHL_GPIO_INT,
.gpio_mhl_reset = MHL_GPIO_RESET,
- .gpio_mhl_power = MHL_POWER_GPIO,
+ .gpio_mhl_power = MHL_POWER_GPIO_PM8038,
.gpio_hdmi_mhl_mux = HDMI_MHL_MUX_GPIO,
};
@@ -1962,17 +2004,22 @@
#ifdef MSM8930_PHASE_2
-#define GPIO_VOLUME_UP PM8038_GPIO_PM_TO_SYS(3)
-#define GPIO_VOLUME_DOWN PM8038_GPIO_PM_TO_SYS(8)
-#define GPIO_CAMERA_SNAPSHOT PM8038_GPIO_PM_TO_SYS(10)
-#define GPIO_CAMERA_FOCUS PM8038_GPIO_PM_TO_SYS(11)
+#define GPIO_VOLUME_UP_PM8038 PM8038_GPIO_PM_TO_SYS(3)
+#define GPIO_VOLUME_DOWN_PM8038 PM8038_GPIO_PM_TO_SYS(8)
+#define GPIO_CAMERA_SNAPSHOT_PM8038 PM8038_GPIO_PM_TO_SYS(10)
+#define GPIO_CAMERA_FOCUS_PM8038 PM8038_GPIO_PM_TO_SYS(11)
-static struct gpio_keys_button keys_8930[] = {
+#define GPIO_VOLUME_UP_PM8917 PM8917_GPIO_PM_TO_SYS(27)
+#define GPIO_VOLUME_DOWN_PM8917 PM8917_GPIO_PM_TO_SYS(28)
+#define GPIO_CAMERA_SNAPSHOT_PM8917 PM8917_GPIO_PM_TO_SYS(36)
+#define GPIO_CAMERA_FOCUS_PM8917 PM8917_GPIO_PM_TO_SYS(37)
+
+static struct gpio_keys_button keys_8930_pm8038[] = {
{
.code = KEY_VOLUMEUP,
.type = EV_KEY,
.desc = "volume_up",
- .gpio = GPIO_VOLUME_UP,
+ .gpio = GPIO_VOLUME_UP_PM8038,
.wakeup = 1,
.active_low = 1,
.debounce_interval = 15,
@@ -1981,7 +2028,7 @@
.code = KEY_VOLUMEDOWN,
.type = EV_KEY,
.desc = "volume_down",
- .gpio = GPIO_VOLUME_DOWN,
+ .gpio = GPIO_VOLUME_DOWN_PM8038,
.wakeup = 1,
.active_low = 1,
.debounce_interval = 15,
@@ -1990,7 +2037,7 @@
.code = KEY_CAMERA_FOCUS,
.type = EV_KEY,
.desc = "camera_focus",
- .gpio = GPIO_CAMERA_FOCUS,
+ .gpio = GPIO_CAMERA_FOCUS_PM8038,
.wakeup = 1,
.active_low = 1,
.debounce_interval = 15,
@@ -1999,7 +2046,46 @@
.code = KEY_CAMERA_SNAPSHOT,
.type = EV_KEY,
.desc = "camera_snapshot",
- .gpio = GPIO_CAMERA_SNAPSHOT,
+ .gpio = GPIO_CAMERA_SNAPSHOT_PM8038,
+ .wakeup = 1,
+ .active_low = 1,
+ .debounce_interval = 15,
+ },
+};
+
+static struct gpio_keys_button keys_8930_pm8917[] = {
+ {
+ .code = KEY_VOLUMEUP,
+ .type = EV_KEY,
+ .desc = "volume_up",
+ .gpio = GPIO_VOLUME_UP_PM8917,
+ .wakeup = 1,
+ .active_low = 1,
+ .debounce_interval = 15,
+ },
+ {
+ .code = KEY_VOLUMEDOWN,
+ .type = EV_KEY,
+ .desc = "volume_down",
+ .gpio = GPIO_VOLUME_DOWN_PM8917,
+ .wakeup = 1,
+ .active_low = 1,
+ .debounce_interval = 15,
+ },
+ {
+ .code = KEY_CAMERA_FOCUS,
+ .type = EV_KEY,
+ .desc = "camera_focus",
+ .gpio = GPIO_CAMERA_FOCUS_PM8917,
+ .wakeup = 1,
+ .active_low = 1,
+ .debounce_interval = 15,
+ },
+ {
+ .code = KEY_CAMERA_SNAPSHOT,
+ .type = EV_KEY,
+ .desc = "camera_snapshot",
+ .gpio = GPIO_CAMERA_SNAPSHOT_PM8917,
.wakeup = 1,
.active_low = 1,
.debounce_interval = 15,
@@ -2008,8 +2094,8 @@
/* Add GPIO keys for 8930 */
static struct gpio_keys_platform_data gpio_keys_8930_pdata = {
- .buttons = keys_8930,
- .nbuttons = 4,
+ .buttons = keys_8930_pm8038,
+ .nbuttons = ARRAY_SIZE(keys_8930_pm8038),
};
static struct platform_device gpio_keys_8930 = {
@@ -2075,7 +2161,7 @@
.name = "saw-regulator",
.id = 0,
.dev = {
- .platform_data = &msm8930_saw_regulator_core0_pdata,
+ .platform_data = &msm8930_pm8038_saw_regulator_core0_pdata,
},
};
@@ -2083,7 +2169,7 @@
.name = "saw-regulator",
.id = 1,
.dev = {
- .platform_data = &msm8930_saw_regulator_core1_pdata,
+ .platform_data = &msm8930_pm8038_saw_regulator_core1_pdata,
},
};
@@ -2140,8 +2226,8 @@
.name = GPIO_REGULATOR_DEV_NAME,
.id = 63,
.dev = {
- .platform_data =
- &msm8930_gpio_regulator_pdata[MSM8930_GPIO_VREG_ID_EXT_5V],
+ .platform_data = &msm8930_pm8038_gpio_regulator_pdata[
+ MSM8930_GPIO_VREG_ID_EXT_5V],
},
};
@@ -2149,8 +2235,8 @@
.name = GPIO_REGULATOR_DEV_NAME,
.id = 97,
.dev = {
- .platform_data =
- &msm8930_gpio_regulator_pdata[MSM8930_GPIO_VREG_ID_EXT_OTG_SW],
+ .platform_data = &msm8930_pm8038_gpio_regulator_pdata[
+ MSM8930_GPIO_VREG_ID_EXT_OTG_SW],
},
};
@@ -2163,18 +2249,22 @@
#ifndef MSM8930_PHASE_2
.platform_data = &msm_rpm_regulator_pdata,
#else
- .platform_data = &msm8930_rpm_regulator_pdata,
+ .platform_data = &msm8930_pm8038_rpm_regulator_pdata,
#endif
},
};
-static struct platform_device *common_devices[] __initdata = {
+static struct platform_device *early_common_devices[] __initdata = {
&msm8960_device_dmov,
&msm_device_smd,
&msm8960_device_uart_gsbi5,
&msm_device_uart_dm6,
&msm_device_saw_core0,
&msm_device_saw_core1,
+};
+
+/* ext_5v and ext_otg_sw are present when using PM8038 */
+static struct platform_device *pmic_pm8038_devices[] __initdata = {
&msm8930_device_ext_5v_vreg,
#ifndef MSM8930_PHASE_2
&msm8930_device_ext_l2_vreg,
@@ -2183,6 +2273,14 @@
#ifdef MSM8930_PHASE_2
&msm8930_device_ext_otg_sw_vreg,
#endif
+};
+
+/* ext_5v and ext_otg_sw are not present when using PM8917 */
+static struct platform_device *pmic_pm8917_devices[] __initdata = {
+ &msm8960_device_ssbi_pmic,
+};
+
+static struct platform_device *common_devices[] __initdata = {
&msm_8960_q6_lpass,
&msm_8960_q6_mss_fw,
&msm_8960_q6_mss_sw,
@@ -2328,6 +2426,13 @@
},
{
+ MSM_PM_SLEEP_MODE_RETENTION,
+ MSM_RPMRS_LIMITS(ON, ACTIVE, MAX, ACTIVE),
+ true,
+ 415, 715, 340827, 475,
+ },
+
+ {
MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE,
MSM_RPMRS_LIMITS(ON, ACTIVE, MAX, ACTIVE),
true,
@@ -2404,6 +2509,33 @@
},
};
+static struct msm_rpmrs_platform_data msm_rpmrs_data_pm8917 __initdata = {
+ .levels = &msm_rpmrs_levels[0],
+ .num_levels = ARRAY_SIZE(msm_rpmrs_levels),
+ .vdd_mem_levels = {
+ [MSM_RPMRS_VDD_MEM_RET_LOW] = 750000,
+ [MSM_RPMRS_VDD_MEM_RET_HIGH] = 750000,
+ [MSM_RPMRS_VDD_MEM_ACTIVE] = 1050000,
+ [MSM_RPMRS_VDD_MEM_MAX] = 1150000,
+ },
+ .vdd_dig_levels = {
+ [MSM_RPMRS_VDD_DIG_RET_LOW] = 0,
+ [MSM_RPMRS_VDD_DIG_RET_HIGH] = 0,
+ [MSM_RPMRS_VDD_DIG_ACTIVE] = 1,
+ [MSM_RPMRS_VDD_DIG_MAX] = 3,
+ },
+ .vdd_mask = 0x7FFFFF,
+ .rpmrs_target_id = {
+ [MSM_RPMRS_ID_PXO_CLK] = MSM_RPM_ID_PXO_CLK,
+ [MSM_RPMRS_ID_L2_CACHE_CTL] = MSM_RPM_ID_LAST,
+ [MSM_RPMRS_ID_VDD_DIG_0] = MSM_RPM_ID_VOLTAGE_CORNER,
+ [MSM_RPMRS_ID_VDD_DIG_1] = MSM_RPM_ID_LAST,
+ [MSM_RPMRS_ID_VDD_MEM_0] = MSM_RPM_ID_PM8917_L24_0,
+ [MSM_RPMRS_ID_VDD_MEM_1] = MSM_RPM_ID_PM8917_L24_1,
+ [MSM_RPMRS_ID_RPM_CTL] = MSM_RPM_ID_RPM_CTL,
+ },
+};
+
static struct msm_pm_boot_platform_data msm_pm_boot_pdata __initdata = {
.mode = MSM_PM_BOOT_CONFIG_TZ,
};
@@ -2570,22 +2702,54 @@
#endif
}
+/* Modify platform data values to match requirements for PM8917. */
+static void __init msm8930_pm8917_pdata_fixup(void)
+{
+ struct acpuclk_platform_data *pdata;
+
+ mhl_platform_data.gpio_mhl_power = MHL_POWER_GPIO_PM8917;
+
+ gpio_keys_8930_pdata.buttons = keys_8930_pm8917;
+ gpio_keys_8930_pdata.nbuttons = ARRAY_SIZE(keys_8930_pm8917);
+
+ msm_device_saw_core0.dev.platform_data
+ = &msm8930_pm8038_saw_regulator_core0_pdata;
+ msm_device_saw_core1.dev.platform_data
+ = &msm8930_pm8038_saw_regulator_core1_pdata;
+
+ msm8930_device_rpm_regulator.dev.platform_data
+ = &msm8930_pm8917_rpm_regulator_pdata;
+
+ pdata = msm8930_device_acpuclk.dev.platform_data;
+ pdata->uses_pm8917 = true;
+}
+
static void __init msm8930_cdp_init(void)
{
+ if (socinfo_get_pmic_model() == PMIC_MODEL_PM8917)
+ msm8930_pm8917_pdata_fixup();
if (meminfo_init(SYS_MEMORY, SZ_256M) < 0)
pr_err("meminfo_init() failed!\n");
platform_device_register(&msm_gpio_device);
msm_tsens_early_init(&msm_tsens_pdata);
msm_thermal_init(&msm_thermal_pdata);
- BUG_ON(msm_rpm_init(&msm8930_rpm_data));
- BUG_ON(msm_rpmrs_levels_init(&msm_rpmrs_data));
+ if (socinfo_get_pmic_model() != PMIC_MODEL_PM8917) {
+ BUG_ON(msm_rpm_init(&msm8930_rpm_data));
+ BUG_ON(msm_rpmrs_levels_init(&msm_rpmrs_data));
+ } else {
+ BUG_ON(msm_rpm_init(&msm8930_rpm_data_pm8917));
+ BUG_ON(msm_rpmrs_levels_init(&msm_rpmrs_data_pm8917));
+ }
regulator_suppress_info_printing();
if (msm_xo_init())
pr_err("Failed to initialize XO votes\n");
platform_device_register(&msm8930_device_rpm_regulator);
- msm_clock_init(&msm8930_clock_init_data);
+ if (socinfo_get_pmic_model() == PMIC_MODEL_PM8917)
+ msm_clock_init(&msm8930_pm8917_clock_init_data);
+ else
+ msm_clock_init(&msm8930_clock_init_data);
msm_otg_pdata.phy_init_seq = hsusb_phy_init_seq;
msm8960_device_otg.dev.platform_data = &msm_otg_pdata;
android_usb_pdata.swfi_latency =
@@ -2622,6 +2786,14 @@
platform_device_register(&msm8930_device_acpuclk);
else if (cpu_is_msm8930aa())
platform_device_register(&msm8930aa_device_acpuclk);
+ platform_add_devices(early_common_devices,
+ ARRAY_SIZE(early_common_devices));
+ if (socinfo_get_pmic_model() != PMIC_MODEL_PM8917)
+ platform_add_devices(pmic_pm8038_devices,
+ ARRAY_SIZE(pmic_pm8038_devices));
+ else
+ platform_add_devices(pmic_pm8917_devices,
+ ARRAY_SIZE(pmic_pm8917_devices));
platform_add_devices(common_devices, ARRAY_SIZE(common_devices));
msm8930_add_vidc_device();
/*
@@ -2632,7 +2804,10 @@
#ifndef MSM8930_PHASE_2
msm8960_pm8921_gpio_mpp_init();
#else
- msm8930_pm8038_gpio_mpp_init();
+ if (socinfo_get_pmic_model() != PMIC_MODEL_PM8917)
+ msm8930_pm8038_gpio_mpp_init();
+ else
+ msm8930_pm8917_gpio_mpp_init();
#endif
platform_add_devices(cdp_devices, ARRAY_SIZE(cdp_devices));
#ifdef CONFIG_MSM_CAMERA
@@ -2646,6 +2821,7 @@
ARRAY_SIZE(msm_slim_devices));
change_memory_power = &msm8930_change_memory_power;
BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
+ msm_pm_set_tz_retention_flag(1);
if (PLATFORM_IS_CHARM25())
platform_add_devices(mdm_devices, ARRAY_SIZE(mdm_devices));
diff --git a/arch/arm/mach-msm/board-8930.h b/arch/arm/mach-msm/board-8930.h
index 9f6276c..7c1ad5b 100644
--- a/arch/arm/mach-msm/board-8930.h
+++ b/arch/arm/mach-msm/board-8930.h
@@ -17,6 +17,7 @@
#include <linux/regulator/msm-gpio-regulator.h>
#include <linux/mfd/pm8xxx/pm8038.h>
+#include <linux/mfd/pm8xxx/pm8921.h>
#include <linux/i2c.h>
#include <linux/i2c/sx150x.h>
#include <mach/irqs.h>
@@ -37,12 +38,23 @@
#endif
/* Macros assume PMIC GPIOs and MPPs start at 1 */
+/*
+ * PM8917 has more GPIOs and MPPs than PM8038; therefore, use PM8038 sizes at
+ * all times so that PM8038 vs PM8917 can be chosen at runtime. This results in
+ * the Linux GPIO address space being contiguous for PM8917 and discontiguous
+ * for PM8038.
+ */
#define PM8038_GPIO_BASE NR_GPIO_IRQS
#define PM8038_GPIO_PM_TO_SYS(pm_gpio) (pm_gpio - 1 + PM8038_GPIO_BASE)
-#define PM8038_MPP_BASE (PM8038_GPIO_BASE + PM8038_NR_GPIOS)
+#define PM8038_MPP_BASE (PM8038_GPIO_BASE + PM8917_NR_GPIOS)
#define PM8038_MPP_PM_TO_SYS(pm_gpio) (pm_gpio - 1 + PM8038_MPP_BASE)
#define PM8038_IRQ_BASE (NR_MSM_IRQS + NR_GPIO_IRQS)
+/* These PM8917 alias macros are used to provide context in board files. */
+#define PM8917_GPIO_PM_TO_SYS(pm_gpio) PM8038_GPIO_PM_TO_SYS(pm_gpio)
+#define PM8917_MPP_PM_TO_SYS(pm_gpio) PM8038_MPP_PM_TO_SYS(pm_gpio)
+#define PM8917_IRQ_BASE PM8038_IRQ_BASE
+
/*
* TODO: When physical 8930/PM8038 hardware becomes
* available, replace this block with 8930/pm8038 regulator
@@ -64,27 +76,36 @@
#define GPIO_VREG_ID_EXT_3P3V 2
#endif
-extern struct regulator_init_data msm8930_saw_regulator_core0_pdata;
-extern struct regulator_init_data msm8930_saw_regulator_core1_pdata;
+extern struct regulator_init_data msm8930_pm8038_saw_regulator_core0_pdata;
+extern struct regulator_init_data msm8930_pm8038_saw_regulator_core1_pdata;
+extern struct regulator_init_data msm8930_pm8917_saw_regulator_core0_pdata;
+extern struct regulator_init_data msm8930_pm8917_saw_regulator_core1_pdata;
extern struct pm8xxx_regulator_platform_data
msm8930_pm8038_regulator_pdata[] __devinitdata;
-
extern int msm8930_pm8038_regulator_pdata_len __devinitdata;
+extern struct pm8xxx_regulator_platform_data
+ msm8930_pm8917_regulator_pdata[] __devinitdata;
+extern int msm8930_pm8917_regulator_pdata_len __devinitdata;
+
#define MSM8930_GPIO_VREG_ID_EXT_5V 0
#define MSM8930_GPIO_VREG_ID_EXT_OTG_SW 1
extern struct gpio_regulator_platform_data
- msm8930_gpio_regulator_pdata[] __devinitdata;
+ msm8930_pm8038_gpio_regulator_pdata[] __devinitdata;
+extern struct gpio_regulator_platform_data
+ msm8930_pm8917_gpio_regulator_pdata[] __devinitdata;
extern struct rpm_regulator_platform_data
- msm8930_rpm_regulator_pdata __devinitdata;
+ msm8930_pm8038_rpm_regulator_pdata __devinitdata;
+extern struct rpm_regulator_platform_data
+ msm8930_pm8917_rpm_regulator_pdata __devinitdata;
#if defined(CONFIG_GPIO_SX150X) || defined(CONFIG_GPIO_SX150X_MODULE)
enum {
GPIO_EXPANDER_IRQ_BASE = (PM8038_IRQ_BASE + PM8038_NR_IRQS),
- GPIO_EXPANDER_GPIO_BASE = (PM8038_MPP_BASE + PM8038_NR_MPPS),
+ GPIO_EXPANDER_GPIO_BASE = (PM8038_MPP_BASE + PM8917_NR_MPPS),
/* CAM Expander */
GPIO_CAM_EXPANDER_BASE = GPIO_EXPANDER_GPIO_BASE,
GPIO_CAM_GP_STROBE_READY = GPIO_CAM_EXPANDER_BASE,
@@ -126,6 +147,7 @@
int msm8930_init_gpiomux(void);
void msm8930_allocate_fb_region(void);
void msm8930_pm8038_gpio_mpp_init(void);
+void msm8930_pm8917_gpio_mpp_init(void);
void msm8930_mdp_writeback(struct memtype_reserve *reserve_table);
void __init msm8930_init_gpu(void);
diff --git a/arch/arm/mach-msm/board-8960-pmic.c b/arch/arm/mach-msm/board-8960-pmic.c
index 8d75ee9..244125c 100644
--- a/arch/arm/mach-msm/board-8960-pmic.c
+++ b/arch/arm/mach-msm/board-8960-pmic.c
@@ -109,7 +109,7 @@
PM8XXX_GPIO_OUTPUT(43, 1), /* DISP_RESET_N */
PM8XXX_GPIO_OUTPUT(42, 0), /* USB 5V reg enable */
/* TABLA CODEC RESET */
- PM8XXX_GPIO_OUTPUT_STRENGTH(34, 1, PM_GPIO_STRENGTH_MED)
+ PM8XXX_GPIO_OUTPUT_STRENGTH(34, 0, PM_GPIO_STRENGTH_MED)
};
/* Initial PM8921 MPP configurations */
@@ -603,6 +603,8 @@
pm8921_platform_data.bms_pdata->battery_type = BATT_DESAY;
} else if (machine_is_msm8960_mtp()) {
pm8921_platform_data.bms_pdata->battery_type = BATT_PALLADIUM;
+ } else if (machine_is_msm8960_cdp()) {
+ pm8921_chg_pdata.has_dc_supply = true;
}
if (machine_is_msm8960_fluid())
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index 4263cd6..a3de539 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -1425,7 +1425,7 @@
static struct msm_spi_platform_data msm8960_qup_spi_gsbi1_pdata = {
.max_clock_speed = 15060000,
- .infinite_mode = 1
+ .infinite_mode = 0xFFC0,
};
#ifdef CONFIG_USB_MSM_OTG_72K
@@ -1447,6 +1447,14 @@
0x23, 0x83,/* set source impedance sdjusment */
-1};
+static int sglte_phy_init_seq[] = {
+ 0x44, 0x80, /* set VBUS valid threshold
+ and disconnect valid threshold */
+ 0x3A, 0x81, /* update DC voltage level */
+ 0x24, 0x82, /* set preemphasis and rise/fall time */
+ 0x13, 0x83, /* set source impedance adjusment */
+ -1};
+
#ifdef CONFIG_MSM_BUS_SCALING
/* Bandwidth requests (zero) if no vote placed */
static struct msm_bus_vectors usb_init_vectors[] = {
@@ -1595,6 +1603,11 @@
0x03, 0x0f,
};
+static uint8_t spm_retention_cmd_sequence[] __initdata = {
+ 0x00, 0x05, 0x03, 0x0D,
+ 0x0B, 0x00, 0x0f,
+};
+
static uint8_t spm_power_collapse_without_rpm[] __initdata = {
0x00, 0x24, 0x54, 0x10,
0x09, 0x03, 0x01,
@@ -1609,7 +1622,32 @@
0x24, 0x30, 0x0f,
};
-static struct msm_spm_seq_entry msm_spm_seq_list[] __initdata = {
+static struct msm_spm_seq_entry msm_spm_boot_cpu_seq_list[] __initdata = {
+ [0] = {
+ .mode = MSM_SPM_MODE_CLOCK_GATING,
+ .notify_rpm = false,
+ .cmd = spm_wfi_cmd_sequence,
+ },
+
+ [1] = {
+ .mode = MSM_SPM_MODE_POWER_RETENTION,
+ .notify_rpm = false,
+ .cmd = spm_retention_cmd_sequence,
+ },
+
+ [2] = {
+ .mode = MSM_SPM_MODE_POWER_COLLAPSE,
+ .notify_rpm = false,
+ .cmd = spm_power_collapse_without_rpm,
+ },
+ [3] = {
+ .mode = MSM_SPM_MODE_POWER_COLLAPSE,
+ .notify_rpm = true,
+ .cmd = spm_power_collapse_with_rpm,
+ },
+};
+
+static struct msm_spm_seq_entry msm_spm_nonboot_cpu_seq_list[] __initdata = {
[0] = {
.mode = MSM_SPM_MODE_CLOCK_GATING,
.notify_rpm = false,
@@ -1636,12 +1674,12 @@
.reg_init_values[MSM_SPM_REG_SAW2_AVS_HYSTERESIS] = 0x00,
#endif
.reg_init_values[MSM_SPM_REG_SAW2_SPM_CTL] = 0x01,
- .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DLY] = 0x02020204,
- .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_0] = 0x0060009C,
- .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_1] = 0x0000001C,
+ .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DLY] = 0x03020004,
+ .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_0] = 0x0084009C,
+ .reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_1] = 0x00A4001C,
.vctl_timeout_us = 50,
- .num_modes = ARRAY_SIZE(msm_spm_seq_list),
- .modes = msm_spm_seq_list,
+ .num_modes = ARRAY_SIZE(msm_spm_boot_cpu_seq_list),
+ .modes = msm_spm_boot_cpu_seq_list,
},
[1] = {
.reg_base_addr = MSM_SAW1_BASE,
@@ -1655,8 +1693,8 @@
.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_0] = 0x0060009C,
.reg_init_values[MSM_SPM_REG_SAW2_PMIC_DATA_1] = 0x0000001C,
.vctl_timeout_us = 50,
- .num_modes = ARRAY_SIZE(msm_spm_seq_list),
- .modes = msm_spm_seq_list,
+ .num_modes = ARRAY_SIZE(msm_spm_nonboot_cpu_seq_list),
+ .modes = msm_spm_nonboot_cpu_seq_list,
},
};
@@ -2324,6 +2362,7 @@
static struct msm_i2c_platform_data msm8960_i2c_qup_gsbi4_pdata = {
.clk_freq = 100000,
.src_clk_rate = 24000000,
+ .keep_ahb_clk_on = 1,
};
static struct msm_i2c_platform_data msm8960_i2c_qup_gsbi3_pdata = {
@@ -2550,43 +2589,42 @@
{
int rc;
+ pr_debug("%s on= %d\n", __func__, on);
+
if (on) {
- rc = gpio_direction_output(gpio_bt_sys_rest_en, 1);
+ rc = gpio_request(gpio_bt_sys_rest_en, "bt sys_rst_n");
+ if (rc) {
+ pr_err("%s: unable to request gpio %d (%d)\n",
+ __func__, gpio_bt_sys_rest_en, rc);
+ goto out;
+ }
+ rc = gpio_direction_output(gpio_bt_sys_rest_en, 0);
+ if (rc) {
+ pr_err("%s: Unable to set gpio %d direction\n",
+ __func__, gpio_bt_sys_rest_en);
+ goto free_gpio;
+ }
msleep(100);
+ gpio_set_value(gpio_bt_sys_rest_en, 1);
+ msleep(100);
+ goto out;
} else {
gpio_set_value(gpio_bt_sys_rest_en, 0);
rc = gpio_direction_input(gpio_bt_sys_rest_en);
msleep(100);
}
- pr_err("%s on= %d rc = %d\n", __func__, on, rc);
- return 0;
+
+free_gpio:
+ gpio_free(gpio_bt_sys_rest_en);
+out:
+ return rc;
}
static void __init bt_power_init(void)
{
- int rc;
-
+ pr_debug("%s enter\n", __func__);
msm_bt_power_device.dev.platform_data = &bluetooth_power;
- pr_err("%s enter\n", __func__);
- rc = gpio_request(gpio_bt_sys_rest_en, "bt sys_rst_n");
- if (rc) {
- pr_err("%s: unable to request gpio %d (%d)\n",
- __func__, gpio_bt_sys_rest_en, rc);
- return;
- }
-
- /* When booting up, de-assert BT reset pin */
- rc = gpio_direction_output(gpio_bt_sys_rest_en, 0);
- if (rc) {
- pr_err("%s: Unable to set direction\n", __func__);
- goto free_gpio;
- }
- pr_err("%s done\n", __func__);
- return;
-
-free_gpio:
- gpio_free(gpio_bt_sys_rest_en);
return;
}
#else
@@ -2758,6 +2796,8 @@
if (cpu_is_msm8960ab()) {
kgsl_3d0_pdata->chipid = ADRENO_CHIPID(3, 2, 1, 0);
+ /* 8960PRO nominal clock rate is 325Mhz instead of 320Mhz */
+ kgsl_3d0_pdata->pwrlevel[1].gpu_freq = 325000000;
} else if (SOCINFO_VERSION_MAJOR(soc_platform_version) == 1) {
kgsl_3d0_pdata->pwrlevel[0].gpu_freq = 320000000;
kgsl_3d0_pdata->pwrlevel[1].gpu_freq = 266667000;
@@ -2788,6 +2828,13 @@
},
{
+ MSM_PM_SLEEP_MODE_RETENTION,
+ MSM_RPMRS_LIMITS(ON, ACTIVE, MAX, ACTIVE),
+ true,
+ 415, 715, 340827, 475,
+ },
+
+ {
MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE,
MSM_RPMRS_LIMITS(ON, ACTIVE, MAX, ACTIVE),
true,
@@ -2837,6 +2884,7 @@
},
};
+
static struct msm_rpmrs_platform_data msm_rpmrs_data __initdata = {
.levels = &msm_rpmrs_levels[0],
.num_levels = ARRAY_SIZE(msm_rpmrs_levels),
@@ -3097,7 +3145,14 @@
msm8960_device_otg.dev.platform_data = &msm_otg_pdata;
if (machine_is_msm8960_mtp() || machine_is_msm8960_fluid() ||
machine_is_msm8960_cdp()) {
- msm_otg_pdata.phy_init_seq = wr_phy_init_seq;
+ /* Due to availability of USB Switch in SGLTE Platform
+ * it requires different HSUSB PHY settings compare to
+ * 8960 MTP/CDP platform.
+ */
+ if (socinfo_get_platform_subtype() == PLATFORM_SUBTYPE_SGLTE)
+ msm_otg_pdata.phy_init_seq = sglte_phy_init_seq;
+ else
+ msm_otg_pdata.phy_init_seq = wr_phy_init_seq;
} else if (machine_is_msm8960_liquid()) {
msm_otg_pdata.phy_init_seq =
liquid_v1_phy_init_seq;
@@ -3176,6 +3231,7 @@
mdm_sglte_device.dev.platform_data = &sglte_platform_data;
platform_device_register(&mdm_sglte_device);
}
+ msm_pm_set_tz_retention_flag(1);
}
MACHINE_START(MSM8960_CDP, "QCT MSM8960 CDP")
diff --git a/arch/arm/mach-msm/board-8974-gpiomux.c b/arch/arm/mach-msm/board-8974-gpiomux.c
index a2087e4..74c503d 100644
--- a/arch/arm/mach-msm/board-8974-gpiomux.c
+++ b/arch/arm/mach-msm/board-8974-gpiomux.c
@@ -102,6 +102,13 @@
.pull = GPIOMUX_PULL_DOWN,
};
+static struct gpiomux_setting taiko_reset = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_6MA,
+ .pull = GPIOMUX_PULL_NONE,
+ .dir = GPIOMUX_OUT_LOW,
+};
+
static struct msm_gpiomux_config msm_touch_configs[] __initdata = {
{
.gpio = 60, /* TOUCH RESET */
@@ -355,6 +362,15 @@
},
};
+static struct msm_gpiomux_config msm_taiko_config[] __initdata = {
+ {
+ .gpio = 63, /* SYS_RST_N */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &taiko_reset,
+ },
+ }
+};
+
void __init msm_8974_init_gpiomux(void)
{
int rc;
@@ -376,4 +392,6 @@
msm_gpiomux_install(msm_touch_configs, ARRAY_SIZE(msm_touch_configs));
msm_gpiomux_install(msm_sensor_configs, ARRAY_SIZE(msm_sensor_configs));
+
+ msm_gpiomux_install(msm_taiko_config, ARRAY_SIZE(msm_taiko_config));
}
diff --git a/arch/arm/mach-msm/board-8974.c b/arch/arm/mach-msm/board-8974.c
index c3eb10c..8d593f6 100644
--- a/arch/arm/mach-msm/board-8974.c
+++ b/arch/arm/mach-msm/board-8974.c
@@ -383,6 +383,11 @@
.id = MSM_BUS_FAB_OCMEM_VNOC,
};
+static struct platform_device msm_fm_platform_init = {
+ .name = "iris_fm",
+ .id = -1,
+};
+
static struct platform_device *msm_bus_8974_devices[] = {
&msm_bus_sys_noc,
&msm_bus_bimc,
@@ -391,6 +396,7 @@
&msm_bus_periph_noc,
&msm_bus_config_noc,
&msm_bus_ocmem_vnoc,
+ &msm_fm_platform_init,
};
static ssize_t mxt336s_vkeys_show(struct kobject *kobj,
diff --git a/arch/arm/mach-msm/board-9615-gpiomux.c b/arch/arm/mach-msm/board-9615-gpiomux.c
index 47a9835..9339638 100644
--- a/arch/arm/mach-msm/board-9615-gpiomux.c
+++ b/arch/arm/mach-msm/board-9615-gpiomux.c
@@ -119,6 +119,13 @@
.dir = GPIOMUX_IN,
};
+static struct gpiomux_setting tabla_reset = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_6MA,
+ .pull = GPIOMUX_PULL_NONE,
+ .dir = GPIOMUX_OUT_LOW,
+};
+
static struct msm_gpiomux_config msm9615_audio_codec_configs[] __initdata = {
{
.gpio = 24,
@@ -126,6 +133,12 @@
[GPIOMUX_SUSPENDED] = &cdc_mclk,
},
},
+ {
+ .gpio = 84, /* SYS_RST_N */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &tabla_reset,
+ },
+ }
};
static struct msm_gpiomux_config msm9615_sdcc2_configs[] __initdata = {
diff --git a/arch/arm/mach-msm/board-fsm9xxx.c b/arch/arm/mach-msm/board-fsm9xxx.c
index 0e2aa3b..24d54e4 100644
--- a/arch/arm/mach-msm/board-fsm9xxx.c
+++ b/arch/arm/mach-msm/board-fsm9xxx.c
@@ -193,7 +193,7 @@
PM8XXX_MPP_INIT(PMIC_MPP_6, A_OUTPUT,
PM8XXX_MPP_AOUT_LVL_1V25_2, AOUT_CTRL_ENABLE),
PM8XXX_MPP_INIT(PMIC_MPP_UIM_M_DATA, D_BI_DIR,
- PM8058_MPP_DIG_LEVEL_L3, BI_PULLUP_30KOHM),
+ PM8058_MPP_DIG_LEVEL_S3, BI_PULLUP_1KOHM),
PM8XXX_MPP_INIT(PMIC_MPP_UIM_DATA, D_BI_DIR,
PM8058_MPP_DIG_LEVEL_L3, BI_PULLUP_30KOHM),
};
@@ -261,7 +261,7 @@
REGULATOR_CHANGE_STATUS, 0, 0, 1)
static struct pm8058_vreg_pdata pm8058_vreg_init[] = {
- PM8058_VREG_INIT_LDO(PM8058_VREG_ID_L3, 1800000, 1800000),
+ PM8058_VREG_INIT_LDO(PM8058_VREG_ID_L3, 3000000, 3000000),
PM8058_VREG_INIT_LDO(PM8058_VREG_ID_L8, 2200000, 2200000),
PM8058_VREG_INIT_LDO(PM8058_VREG_ID_L9, 2050000, 2050000),
PM8058_VREG_INIT_LDO(PM8058_VREG_ID_L14, 2850000, 2850000),
@@ -614,11 +614,11 @@
static struct msm_gpio uart3_uim_config_data[] = {
{ GPIO_CFG(GPIO_UIM_RESET, 0, GPIO_CFG_OUTPUT,
- GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), "UIM_Reset" },
+ GPIO_CFG_PULL_UP, GPIO_CFG_2MA), "UIM_Reset" },
{ GPIO_CFG(GPIO_UIM_DATA_IO, 2, GPIO_CFG_OUTPUT,
- GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), "UIM_Data" },
+ GPIO_CFG_PULL_UP, GPIO_CFG_2MA), "UIM_Data" },
{ GPIO_CFG(GPIO_UIM_CLOCK, 2, GPIO_CFG_OUTPUT,
- GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), "UIM_Clock" },
+ GPIO_CFG_PULL_UP, GPIO_CFG_2MA), "UIM_Clock" },
};
static void fsm9xxx_init_uart3_uim(void)
diff --git a/arch/arm/mach-msm/board-msm7627a-display.c b/arch/arm/mach-msm/board-msm7627a-display.c
index e305fe6..d62254a 100644
--- a/arch/arm/mach-msm/board-msm7627a-display.c
+++ b/arch/arm/mach-msm/board-msm7627a-display.c
@@ -65,6 +65,8 @@
#define SKU3_LCDC_LCD_CAMERA_LDO_1V8 34 /*LCD_CAMERA_LDO_1V8*/
#define SKU3_1_LCDC_LCD_CAMERA_LDO_1V8 58 /*LCD_CAMERA_LDO_1V8*/
+static struct regulator *gpio_reg_2p85v_sku3, *gpio_reg_1p8v_sku3;
+
static uint32_t lcdc_truly_gpio_table[] = {
19,
20,
@@ -133,7 +135,7 @@
}
-void sku3_lcdc_lcd_camera_power_init(void)
+void sku3_lcdc_power_init(void)
{
int rc = 0;
u32 socinfo = socinfo_get_platform_type();
@@ -188,6 +190,29 @@
}
}
+ if (socinfo == 0x0B)
+ gpio_free(SKU3_LCDC_LCD_CAMERA_LDO_1V8);
+ else if (socinfo == 0x0F || machine_is_msm8625_qrd7())
+ gpio_free(SKU3_1_LCDC_LCD_CAMERA_LDO_1V8);
+
+ gpio_free(SKU3_LCDC_LCD_CAMERA_LDO_2V8);
+
+ gpio_reg_2p85v_sku3 = regulator_get(&msm_lcdc_device.dev,
+ "lcd_vdd_sku3");
+ if (IS_ERR(gpio_reg_2p85v_sku3)) {
+ pr_err("%s:ext_2p85v regulator get failed", __func__);
+ regulator_put(gpio_reg_2p85v_sku3);
+ return;
+ }
+
+ gpio_reg_1p8v_sku3 = regulator_get(&msm_lcdc_device.dev,
+ "lcd_vddi_sku3");
+ if (IS_ERR(gpio_reg_1p8v_sku3)) {
+ pr_err("%s:ext_1p8v regulator get failed", __func__);
+ regulator_put(gpio_reg_1p8v_sku3);
+ return;
+ }
+
rc = regulator_bulk_get(NULL, ARRAY_SIZE(regs_truly_lcdc),
regs_truly_lcdc);
if (rc)
@@ -210,41 +235,48 @@
return;
}
-int sku3_lcdc_lcd_camera_power_onoff(int on)
+int sku3_lcdc_power_onoff(int on)
{
int rc = 0;
- u32 socinfo = socinfo_get_platform_type();
if (on) {
- if (socinfo == 0x0B)
- gpio_set_value_cansleep(SKU3_LCDC_LCD_CAMERA_LDO_1V8,
- 1);
- else if (socinfo == 0x0F || machine_is_msm8625_qrd7())
- gpio_set_value_cansleep(SKU3_1_LCDC_LCD_CAMERA_LDO_1V8,
- 1);
-
- gpio_set_value_cansleep(SKU3_LCDC_LCD_CAMERA_LDO_2V8, 1);
+ rc = regulator_enable(gpio_reg_2p85v_sku3);
+ if (rc < 0) {
+ pr_err("%s: reg enable failed\n", __func__);
+ return -EINVAL;
+ }
+ rc = regulator_enable(gpio_reg_1p8v_sku3);
+ if (rc < 0) {
+ pr_err("%s: reg enable failed\n", __func__);
+ return -EINVAL;
+ }
rc = regulator_bulk_enable(ARRAY_SIZE(regs_truly_lcdc),
regs_truly_lcdc);
- if (rc)
+ if (rc) {
pr_err("%s: could not enable regulators: %d\n",
__func__, rc);
+ return -EINVAL;
+ }
} else {
- if (socinfo == 0x0B)
- gpio_set_value_cansleep(SKU3_LCDC_LCD_CAMERA_LDO_1V8,
- 0);
- else if (socinfo == 0x0F || machine_is_msm8625_qrd7())
- gpio_set_value_cansleep(SKU3_1_LCDC_LCD_CAMERA_LDO_1V8,
- 0);
-
- gpio_set_value_cansleep(SKU3_LCDC_LCD_CAMERA_LDO_2V8, 0);
+ rc = regulator_disable(gpio_reg_2p85v_sku3);
+ if (rc < 0) {
+ pr_err("%s: reg disable failed\n", __func__);
+ return -EINVAL;
+ }
+ rc = regulator_disable(gpio_reg_1p8v_sku3);
+ if (rc < 0) {
+ pr_err("%s: reg disable failed\n", __func__);
+ return -EINVAL;
+ }
rc = regulator_bulk_disable(ARRAY_SIZE(regs_truly_lcdc),
regs_truly_lcdc);
- if (rc)
+ if (rc) {
pr_err("%s: could not disable regulators: %d\n",
__func__, rc);
+ return -EINVAL;
+ }
}
return rc;
@@ -256,7 +288,7 @@
static int cont_splash_done;
if (on) {
- sku3_lcdc_lcd_camera_power_onoff(1);
+ sku3_lcdc_power_onoff(1);
rc = lcdc_truly_gpio_init();
if (rc < 0) {
pr_err("%s(): Truly GPIO initializations failed",
@@ -285,7 +317,7 @@
gpio_set_value(SKU3_LCDC_GPIO_SPI_CS0_N, 0);
gpio_set_value(SKU3_LCDC_GPIO_DISPLAY_RESET, 0);
- sku3_lcdc_lcd_camera_power_onoff(0);
+ sku3_lcdc_power_onoff(0);
}
return rc;
}
@@ -1353,21 +1385,19 @@
{
int rc = 0;
msm7x27a_set_display_params(prim_panel_name);
- if (machine_is_msm7627a_qrd1())
+ if (machine_is_msm7627a_qrd1()) {
platform_add_devices(qrd_fb_devices,
ARRAY_SIZE(qrd_fb_devices));
- else if (machine_is_msm7627a_evb() || machine_is_msm8625_evb()
+ } else if (machine_is_msm7627a_evb() || machine_is_msm8625_evb()
|| 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));
@@ -1382,6 +1412,8 @@
machine_is_msm8625_surf() || machine_is_msm7627a_qrd3()
|| machine_is_msm8625_qrd7())
msm_fb_register_device("lcdc", &lcdc_pdata);
+ if (machine_is_msm7627a_qrd3() || machine_is_msm8625_qrd7())
+ sku3_lcdc_power_init();
#ifdef CONFIG_FB_MSM_MIPI_DSI
msm_fb_register_device("mipi_dsi", &mipi_dsi_pdata);
#endif
diff --git a/arch/arm/mach-msm/board-msm7x27a.c b/arch/arm/mach-msm/board-msm7x27a.c
index e00f150..cda7c2a 100644
--- a/arch/arm/mach-msm/board-msm7x27a.c
+++ b/arch/arm/mach-msm/board-msm7x27a.c
@@ -781,6 +781,30 @@
},
};
+#ifdef CONFIG_MSM_RTB
+static struct msm_rtb_platform_data msm7x27a_rtb_pdata = {
+ .size = SZ_1M,
+};
+
+static int __init msm_rtb_set_buffer_size(char *p)
+{
+ int s;
+
+ s = memparse(p, NULL);
+ msm7x27a_rtb_pdata.size = ALIGN(s, SZ_4K);
+ return 0;
+}
+early_param("msm_rtb_size", msm_rtb_set_buffer_size);
+
+struct platform_device msm7x27a_rtb_device = {
+ .name = "msm_rtb",
+ .id = -1,
+ .dev = {
+ .platform_data = &msm7x27a_rtb_pdata,
+ },
+};
+#endif
+
#define ETH_FIFO_SEL_GPIO 49
static void msm7x27a_cfg_smsc911x(void)
{
@@ -876,6 +900,9 @@
&asoc_msm_dai1,
&msm_batt_device,
&msm_adc_device,
+#ifdef CONFIG_MSM_RTB
+ &msm7x27a_rtb_device,
+#endif
#ifdef CONFIG_ION_MSM
&ion_dev,
#endif
@@ -994,6 +1021,17 @@
},
};
+#ifdef CONFIG_MSM_RTB
+static void __init reserve_rtb_memory(void)
+{
+ msm7x27a_reserve_table[MEMTYPE_EBI1].size += msm7x27a_rtb_pdata.size;
+}
+#else
+static void __init reserve_rtb_memory(void)
+{
+}
+#endif
+
#ifdef CONFIG_ANDROID_PMEM
#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
static struct android_pmem_platform_data *pmem_pdata_array[] __initdata = {
@@ -1063,6 +1101,7 @@
reserve_pmem_memory();
size_ion_devices();
reserve_ion_memory();
+ reserve_rtb_memory();
}
static int msm7x27a_paddr_to_memtype(unsigned int paddr)
@@ -1187,6 +1226,7 @@
ARRAY_SIZE(msm8625_pm_data));
BUG_ON(msm_pm_boot_init(&msm_pm_8625_boot_pdata));
msm8x25_spm_device_init();
+ msm_pm_register_cpr_ops();
}
#define UART1DM_RX_GPIO 45
@@ -1265,6 +1305,7 @@
ARRAY_SIZE(msm8625_pm_data));
BUG_ON(msm_pm_boot_init(&msm_pm_8625_boot_pdata));
msm8x25_spm_device_init();
+ msm_pm_register_cpr_ops();
} else {
msm_pm_set_platform_data(msm7x27a_pm_data,
ARRAY_SIZE(msm7x27a_pm_data));
diff --git a/arch/arm/mach-msm/board-msm7x30.c b/arch/arm/mach-msm/board-msm7x30.c
index 4524f43..f16751d 100644
--- a/arch/arm/mach-msm/board-msm7x30.c
+++ b/arch/arm/mach-msm/board-msm7x30.c
@@ -7173,7 +7173,6 @@
.type = ION_HEAP_TYPE_CARVEOUT,
.name = ION_CAMERA_HEAP_NAME,
.memory_type = ION_EBI_TYPE,
- .has_outer_cache = 1,
.extra_data = (void *)&co_ion_pdata,
},
/* PMEM_AUDIO */
@@ -7182,7 +7181,6 @@
.type = ION_HEAP_TYPE_CARVEOUT,
.name = ION_AUDIO_HEAP_NAME,
.memory_type = ION_EBI_TYPE,
- .has_outer_cache = 1,
.extra_data = (void *)&co_ion_pdata,
},
/* PMEM_MDP = SF */
@@ -7191,7 +7189,6 @@
.type = ION_HEAP_TYPE_CARVEOUT,
.name = ION_SF_HEAP_NAME,
.memory_type = ION_EBI_TYPE,
- .has_outer_cache = 1,
.extra_data = (void *)&co_ion_pdata,
},
#endif
diff --git a/arch/arm/mach-msm/board-qrd7627a.c b/arch/arm/mach-msm/board-qrd7627a.c
index 1da9ede..0d17f47 100644
--- a/arch/arm/mach-msm/board-qrd7627a.c
+++ b/arch/arm/mach-msm/board-qrd7627a.c
@@ -693,6 +693,30 @@
},
};
+#ifdef CONFIG_MSM_RTB
+static struct msm_rtb_platform_data msm7627a_rtb_pdata = {
+ .size = SZ_1M,
+};
+
+static int __init msm_rtb_set_buffer_size(char *p)
+{
+ int s;
+
+ s = memparse(p, NULL);
+ msm7627a_rtb_pdata.size = ALIGN(s, SZ_4K);
+ return 0;
+}
+early_param("msm_rtb_size", msm_rtb_set_buffer_size);
+
+struct platform_device msm7627a_rtb_device = {
+ .name = "msm_rtb",
+ .id = -1,
+ .dev = {
+ .platform_data = &msm7627a_rtb_pdata,
+ },
+};
+#endif
+
#define GPIO_VREG_INIT(_id, _reg_name, _gpio_label, _gpio, _active_low) \
[GPIO_VREG_ID_##_id] = { \
.init_data = { \
@@ -711,6 +735,9 @@
#define GPIO_VREG_ID_EXT_2P85V 0
#define GPIO_VREG_ID_EXT_1P8V 1
+#define GPIO_VREG_ID_EXT_2P85V_SKU3 2
+#define GPIO_VREG_ID_EXT_1P8V_SKU3 3
+#define GPIO_VREG_ID_EXT_1P8V_SKU3_1 4
static struct regulator_consumer_supply vreg_consumers_EXT_2P85V[] = {
REGULATOR_SUPPLY("cam_ov5647_avdd", "0-006c"),
@@ -726,10 +753,37 @@
REGULATOR_SUPPLY("lcd_vddi", "mipi_dsi.1"),
};
+static struct regulator_consumer_supply vreg_consumers_EXT_2P85V_SKU3[] = {
+ REGULATOR_SUPPLY("cam_ov5647_avdd", "0-006c"),
+ REGULATOR_SUPPLY("cam_ov7692_avdd", "0-0078"),
+ REGULATOR_SUPPLY("cam_ov8825_avdd", "0-000d"),
+ REGULATOR_SUPPLY("lcd_vdd_sku3", "lcdc.0"),
+};
+
+static struct regulator_consumer_supply vreg_consumers_EXT_1P8V_SKU3[] = {
+ REGULATOR_SUPPLY("cam_ov5647_vdd", "0-006c"),
+ REGULATOR_SUPPLY("cam_ov7692_vdd", "0-0078"),
+ REGULATOR_SUPPLY("cam_ov8825_vdd", "0-000d"),
+ REGULATOR_SUPPLY("lcd_vddi_sku3", "lcdc.0"),
+};
+
+static struct regulator_consumer_supply vreg_consumers_EXT_1P8V_SKU3_1[] = {
+ REGULATOR_SUPPLY("cam_ov5647_vdd", "0-006c"),
+ REGULATOR_SUPPLY("cam_ov7692_vdd", "0-0078"),
+ REGULATOR_SUPPLY("cam_ov8825_vdd", "0-000d"),
+ REGULATOR_SUPPLY("lcd_vddi_sku3", "lcdc.0"),
+};
+
/* GPIO regulator constraints */
static struct gpio_regulator_platform_data msm_gpio_regulator_pdata[] = {
GPIO_VREG_INIT(EXT_2P85V, "ext_2p85v", "ext_2p85v_en", 35, 0),
GPIO_VREG_INIT(EXT_1P8V, "ext_1p8v", "ext_1p8v_en", 40, 0),
+ GPIO_VREG_INIT(EXT_2P85V_SKU3, "ext_2p85v_sku3", "ext_2p85v_sku3_en",
+ 35, 0),
+ GPIO_VREG_INIT(EXT_1P8V_SKU3, "ext_1p8v_sku3", "ext_1p8v_sku3_en",
+ 34, 0),
+ GPIO_VREG_INIT(EXT_1P8V_SKU3_1, "ext_1p8v_sku3_1", "ext_1p8v_sku3_1_en",
+ 58, 0),
};
/* GPIO regulator */
@@ -751,6 +805,33 @@
},
};
+static struct platform_device qrd_vreg_gpio_ext_2p85v_sku3 __devinitdata = {
+ .name = GPIO_REGULATOR_DEV_NAME,
+ .id = 35,
+ .dev = {
+ .platform_data =
+ &msm_gpio_regulator_pdata[GPIO_VREG_ID_EXT_2P85V_SKU3],
+ },
+};
+
+static struct platform_device qrd_vreg_gpio_ext_1p8v_sku3 __devinitdata = {
+ .name = GPIO_REGULATOR_DEV_NAME,
+ .id = 34,
+ .dev = {
+ .platform_data =
+ &msm_gpio_regulator_pdata[GPIO_VREG_ID_EXT_1P8V_SKU3],
+ },
+};
+
+static struct platform_device qrd_vreg_gpio_ext_1p8v_sku3_1 __devinitdata = {
+ .name = GPIO_REGULATOR_DEV_NAME,
+ .id = 58,
+ .dev = {
+ .platform_data =
+ &msm_gpio_regulator_pdata[GPIO_VREG_ID_EXT_1P8V_SKU3_1],
+ },
+};
+
static struct platform_device *common_devices[] __initdata = {
&android_usb_device,
&android_pmem_device,
@@ -764,6 +845,9 @@
&asoc_msm_dai0,
&asoc_msm_dai1,
&msm_adc_device,
+#ifdef CONFIG_MSM_RTB
+ &msm7627a_rtb_device,
+#endif
#ifdef CONFIG_ION_MSM
&ion_dev,
#endif
@@ -779,10 +863,23 @@
&msm_device_otg,
&msm_device_gadget_peripheral,
&msm_kgsl_3d0,
+};
+
+static struct platform_device *msm8625_lcd_camera_devices[] __initdata = {
&qrd_vreg_gpio_ext_2p85v,
&qrd_vreg_gpio_ext_1p8v,
};
+static struct platform_device *sku3_lcd_camera_devices[] __initdata = {
+ &qrd_vreg_gpio_ext_2p85v_sku3,
+ &qrd_vreg_gpio_ext_1p8v_sku3,
+};
+
+static struct platform_device *sku3_1_lcd_camera_devices[] __initdata = {
+ &qrd_vreg_gpio_ext_2p85v_sku3,
+ &qrd_vreg_gpio_ext_1p8v_sku3_1,
+};
+
static struct platform_device *qrd3_devices[] __initdata = {
&msm_device_nand,
};
@@ -797,8 +894,6 @@
&msm8625_device_otg,
&msm8625_device_gadget_peripheral,
&msm8625_kgsl_3d0,
- &qrd_vreg_gpio_ext_2p85v,
- &qrd_vreg_gpio_ext_1p8v,
};
static unsigned pmem_kernel_ebi1_size = PMEM_KERNEL_EBI1_SIZE;
@@ -894,6 +989,17 @@
},
};
+#ifdef CONFIG_MSM_RTB
+static void __init reserve_rtb_memory(void)
+{
+ msm7627a_reserve_table[MEMTYPE_EBI1].size += msm7627a_rtb_pdata.size;
+}
+#else
+static void __init reserve_rtb_memory(void)
+{
+}
+#endif
+
#ifdef CONFIG_ANDROID_PMEM
#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
static struct android_pmem_platform_data *pmem_pdata_array[] __initdata = {
@@ -962,6 +1068,7 @@
reserve_pmem_memory();
size_ion_devices();
reserve_ion_memory();
+ reserve_rtb_memory();
}
static int msm7627a_paddr_to_memtype(unsigned int paddr)
@@ -1070,6 +1177,23 @@
platform_add_devices(qrd3_devices,
ARRAY_SIZE(qrd3_devices));
+ if (machine_is_msm7627a_evb() || machine_is_msm8625_evb()
+ || machine_is_msm8625_evt())
+ platform_add_devices(msm8625_lcd_camera_devices,
+ ARRAY_SIZE(msm8625_lcd_camera_devices));
+ else if (machine_is_msm8625_qrd7())
+ platform_add_devices(sku3_1_lcd_camera_devices,
+ ARRAY_SIZE(sku3_1_lcd_camera_devices));
+ else if (machine_is_msm7627a_qrd3()) {
+ u32 socinfo = socinfo_get_platform_type();
+ if (socinfo == 0x0B)
+ platform_add_devices(sku3_lcd_camera_devices,
+ ARRAY_SIZE(sku3_lcd_camera_devices));
+ else if (socinfo == 0x0F)
+ platform_add_devices(sku3_1_lcd_camera_devices,
+ ARRAY_SIZE(sku3_1_lcd_camera_devices));
+ }
+
platform_add_devices(common_devices,
ARRAY_SIZE(common_devices));
}
@@ -1115,6 +1239,7 @@
ARRAY_SIZE(msm8625_pm_data));
BUG_ON(msm_pm_boot_init(&msm_pm_8625_boot_pdata));
msm8x25_spm_device_init();
+ msm_pm_register_cpr_ops();
}
}
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index cde6437..373cf47 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -393,6 +393,7 @@
static DEFINE_VDD_CLASS(vdd_dig, set_vdd_dig_8960);
+static int rpm_vreg_dig_8930 = RPM_VREG_ID_PM8038_VDD_DIG_CORNER;
static int set_vdd_dig_8930(struct clk_vdd_class *vdd_class, int level)
{
static const int vdd_corner[] = {
@@ -401,7 +402,7 @@
[VDD_DIG_NOMINAL] = RPM_VREG_CORNER_NOMINAL,
[VDD_DIG_HIGH] = RPM_VREG_CORNER_HIGH,
};
- return rpm_vreg_set_voltage(RPM_VREG_ID_PM8038_VDD_DIG_CORNER,
+ return rpm_vreg_set_voltage(rpm_vreg_dig_8930,
RPM_VREG_VOTER3,
vdd_corner[level],
RPM_VREG_CORNER_HIGH, 1);
@@ -467,6 +468,36 @@
sr2_lreg_uv[level], sr2_lreg_uv[level], 1);
}
+static int set_vdd_sr2_hdmi_pll_8930_pm8917(struct clk_vdd_class *vdd_class,
+ int level)
+{
+ int rc = 0;
+
+ if (level == VDD_SR2_HDMI_PLL_OFF) {
+ rc = rpm_vreg_set_voltage(RPM_VREG_ID_PM8917_L23,
+ RPM_VREG_VOTER3, 0, 0, 1);
+ if (rc)
+ return rc;
+ rc = rpm_vreg_set_voltage(RPM_VREG_ID_PM8917_S8,
+ RPM_VREG_VOTER3, 0, 0, 1);
+ if (rc)
+ rpm_vreg_set_voltage(RPM_VREG_ID_PM8917_L23,
+ RPM_VREG_VOTER3, 1800000, 1800000, 1);
+ } else {
+ rc = rpm_vreg_set_voltage(RPM_VREG_ID_PM8917_S8,
+ RPM_VREG_VOTER3, 2050000, 2100000, 1);
+ if (rc)
+ return rc;
+ rc = rpm_vreg_set_voltage(RPM_VREG_ID_PM8917_L23,
+ RPM_VREG_VOTER3, 1800000, 1800000, 1);
+ if (rc)
+ rpm_vreg_set_voltage(RPM_VREG_ID_PM8917_S8,
+ RPM_VREG_VOTER3, 0, 0, 1);
+ }
+
+ return rc;
+}
+
static int set_vdd_sr2_hdmi_pll_8930(struct clk_vdd_class *vdd_class, int level)
{
return rpm_vreg_set_voltage(RPM_VREG_ID_PM8038_L23, RPM_VREG_VOTER3,
@@ -5203,7 +5234,7 @@
CLK_LOOKUP("core_clk", gsbi3_uart_clk.c, ""),
CLK_LOOKUP("core_clk", gsbi4_uart_clk.c, ""),
CLK_LOOKUP("core_clk", gsbi5_uart_clk.c, ""),
- CLK_LOOKUP("core_clk", gsbi6_uart_clk.c, ""),
+ CLK_LOOKUP("core_clk", gsbi6_uart_clk.c, "msm_serial_hs.0"),
CLK_LOOKUP("core_clk", gsbi7_uart_clk.c, "msm_serial_hsl.0"),
CLK_LOOKUP("core_clk", gsbi1_qup_clk.c, "qup_i2c.0"),
CLK_LOOKUP("core_clk", gsbi2_qup_clk.c, ""),
@@ -5253,7 +5284,7 @@
CLK_LOOKUP("iface_clk", gsbi4_p_clk.c, "qup_i2c.4"),
CLK_LOOKUP("iface_clk", gsbi5_p_clk.c, "spi_qsd.0"),
CLK_LOOKUP("iface_clk", gsbi5_p_clk.c, "qup_i2c.5"),
- CLK_LOOKUP("iface_clk", gsbi6_p_clk.c, ""),
+ CLK_LOOKUP("iface_clk", gsbi6_p_clk.c, "msm_serial_hs.0"),
CLK_LOOKUP("iface_clk", gsbi7_p_clk.c, "msm_serial_hsl.0"),
CLK_LOOKUP("ref_clk", tsif_ref_clk.c, "msm_tspp.0"),
CLK_LOOKUP("iface_clk", tsif_p_clk.c, "msm_tspp.0"),
@@ -6237,7 +6268,7 @@
rmwreg(0x00000003, AHB_EN_REG, 0x6C000103);
writel_relaxed(0x000007F9, AHB_EN2_REG);
} else {
- rmwreg(0x44000000, AHB_EN_REG, 0x6C000103);
+ rmwreg(0x40000000, AHB_EN_REG, 0x6C000103);
writel_relaxed(0x3C7097F9, AHB_EN2_REG);
}
@@ -6421,12 +6452,8 @@
/* Initialize clock registers. */
reg_init();
- if (cpu_is_apq8064()) {
+ if (cpu_is_apq8064())
vdd_sr2_hdmi_pll.set_vdd = set_vdd_sr2_hdmi_pll_8064;
- } else if (cpu_is_msm8930() || cpu_is_msm8930aa() || cpu_is_msm8627()) {
- vdd_dig.set_vdd = set_vdd_dig_8930;
- vdd_sr2_hdmi_pll.set_vdd = set_vdd_sr2_hdmi_pll_8930;
- }
/* Detect PLL4 programmed for alternate 491.52MHz clock plan. */
if (readl_relaxed(LCC_PLL0_L_VAL_REG) == 0x12) {
@@ -6510,6 +6537,25 @@
clk_ops_local_pll.enable = sr_pll_clk_enable;
}
+static void __init msm8930_pm8917_clock_pre_init(void)
+{
+ /* detect pmic8917 from board file, and call this init function */
+
+ vdd_dig.set_vdd = set_vdd_dig_8930;
+ rpm_vreg_dig_8930 = RPM_VREG_ID_PM8917_VDD_DIG_CORNER;
+ vdd_sr2_hdmi_pll.set_vdd = set_vdd_sr2_hdmi_pll_8930_pm8917;
+
+ msm8960_clock_pre_init();
+}
+
+static void __init msm8930_clock_pre_init(void)
+{
+ vdd_dig.set_vdd = set_vdd_dig_8930;
+ vdd_sr2_hdmi_pll.set_vdd = set_vdd_sr2_hdmi_pll_8930;
+
+ msm8960_clock_pre_init();
+}
+
static void __init msm8960_clock_post_init(void)
{
/* Keep PXO on whenever APPS cpu is active */
@@ -6620,7 +6666,15 @@
struct clock_init_data msm8930_clock_init_data __initdata = {
.table = msm_clocks_8930,
.size = ARRAY_SIZE(msm_clocks_8930),
- .pre_init = msm8960_clock_pre_init,
+ .pre_init = msm8930_clock_pre_init,
+ .post_init = msm8960_clock_post_init,
+ .late_init = msm8960_clock_late_init,
+};
+
+struct clock_init_data msm8930_pm8917_clock_init_data __initdata = {
+ .table = msm_clocks_8930,
+ .size = ARRAY_SIZE(msm_clocks_8930),
+ .pre_init = msm8930_pm8917_clock_pre_init,
.post_init = msm8960_clock_post_init,
.late_init = msm8960_clock_late_init,
};
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index e21a645..357f0b7 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -497,6 +497,7 @@
#define LPASS_Q6SS_XO_CBCR 0x26000
#define LPASS_Q6_AXI_CBCR 0x11C0
#define Q6SS_AHBM_CBCR 0x22004
+#define AUDIO_WRAPPER_BR_CBCR 0x24000
#define MSS_XO_Q6_CBCR 0x108C
#define MSS_BUS_Q6_CBCR 0x10A4
#define MSS_CFG_AHB_CBCR 0x0280
@@ -634,7 +635,8 @@
#define MMSSNOC_AHB_ID 0x3
#define BIMC_ID 0x0
-#define OCMEM_ID 0x1
+#define OXILI_ID 0x1
+#define OCMEM_ID 0x2
enum {
D0_ID = 1,
@@ -653,6 +655,8 @@
DEFINE_CLK_RPM_SMD(bimc_clk, bimc_a_clk, RPM_MEM_CLK_TYPE, BIMC_ID, NULL);
DEFINE_CLK_RPM_SMD(ocmemgx_clk, ocmemgx_a_clk, RPM_MEM_CLK_TYPE, OCMEM_ID,
NULL);
+DEFINE_CLK_RPM_SMD(gfx3d_clk_src, gfx3d_a_clk_src, RPM_MEM_CLK_TYPE, OXILI_ID,
+ NULL);
DEFINE_CLK_RPM_SMD_BRANCH(cxo_clk_src, cxo_a_clk_src,
RPM_MISC_CLK_TYPE, CXO_ID, 19200000);
@@ -773,7 +777,7 @@
static DEFINE_CLK_VOTER(bimc_msmbus_clk, &bimc_clk.c, LONG_MAX);
static DEFINE_CLK_VOTER(bimc_msmbus_a_clk, &bimc_a_clk.c, LONG_MAX);
static DEFINE_CLK_VOTER(bimc_acpu_a_clk, &bimc_a_clk.c, LONG_MAX);
-static DEFINE_CLK_VOTER(ocmemgx_gfx3d_clk, &ocmemgx_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(oxili_gfx3d_clk_src, &gfx3d_clk_src.c, LONG_MAX);
static DEFINE_CLK_VOTER(ocmemgx_msmbus_clk, &ocmemgx_clk.c, LONG_MAX);
static DEFINE_CLK_VOTER(ocmemgx_msmbus_a_clk, &ocmemgx_a_clk.c, LONG_MAX);
static DEFINE_CLK_VOTER(ocmemgx_core_clk, &ocmemgx_clk.c, LONG_MAX);
@@ -4012,7 +4016,7 @@
static struct branch_clk oxili_gfx3d_clk = {
.cbcr_reg = OXILI_GFX3D_CBCR,
- .parent = &ocmemgx_gfx3d_clk.c,
+ .parent = &oxili_gfx3d_clk_src.c,
.base = &virt_bases[MMSS_BASE],
.c = {
.dbg_name = "oxili_gfx3d_clk",
@@ -4494,6 +4498,17 @@
},
};
+static struct branch_clk audio_wrapper_br_clk = {
+ .cbcr_reg = AUDIO_WRAPPER_BR_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[LPASS_BASE],
+ .c = {
+ .dbg_name = "audio_wrapper_br_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(audio_wrapper_br_clk.c),
+ },
+};
+
static struct branch_clk mss_xo_q6_clk = {
.cbcr_reg = MSS_XO_Q6_CBCR,
.bcr_reg = MSS_Q6SS_BCR,
@@ -4702,6 +4717,7 @@
{&q6ss_ahb_lfabif_clk.c, LPASS_BASE, 0x001e},
{&q6ss_ahbm_clk.c, LPASS_BASE, 0x001d},
{&audio_core_ixfabric_clk.c, LPASS_BASE, 0x0059},
+ {&audio_wrapper_br_clk.c, LPASS_BASE, 0x0022},
{&mss_bus_q6_clk.c, MSS_BASE, 0x003b},
{&mss_xo_q6_clk.c, MSS_BASE, 0x0007},
@@ -4976,7 +4992,7 @@
CLK_LOOKUP("core_clk", gcc_blsp1_uart5_apps_clk.c, ""),
CLK_LOOKUP("core_clk", gcc_blsp1_uart6_apps_clk.c, ""),
- CLK_LOOKUP("iface_clk", gcc_blsp2_ahb_clk.c, "f9966000.i2c"),
+ CLK_LOOKUP("iface_clk", gcc_blsp2_ahb_clk.c, "f9967000.i2c"),
CLK_LOOKUP("iface_clk", gcc_blsp2_ahb_clk.c, "f995e000.serial"),
CLK_LOOKUP("core_clk", gcc_blsp2_qup1_i2c_apps_clk.c, ""),
CLK_LOOKUP("core_clk", gcc_blsp2_qup1_spi_apps_clk.c, ""),
@@ -4984,9 +5000,9 @@
CLK_LOOKUP("core_clk", gcc_blsp2_qup2_spi_apps_clk.c, ""),
CLK_LOOKUP("core_clk", gcc_blsp2_qup3_i2c_apps_clk.c, ""),
CLK_LOOKUP("core_clk", gcc_blsp2_qup3_spi_apps_clk.c, ""),
- CLK_LOOKUP("core_clk", gcc_blsp2_qup4_i2c_apps_clk.c, "f9966000.i2c"),
+ CLK_LOOKUP("core_clk", gcc_blsp2_qup4_i2c_apps_clk.c, ""),
CLK_LOOKUP("core_clk", gcc_blsp2_qup4_spi_apps_clk.c, ""),
- CLK_LOOKUP("core_clk", gcc_blsp2_qup5_i2c_apps_clk.c, ""),
+ CLK_LOOKUP("core_clk", gcc_blsp2_qup5_i2c_apps_clk.c, "f9967000.i2c"),
CLK_LOOKUP("core_clk", gcc_blsp2_qup5_spi_apps_clk.c, ""),
CLK_LOOKUP("core_clk", gcc_blsp2_qup6_i2c_apps_clk.c, ""),
CLK_LOOKUP("core_clk", gcc_blsp2_qup6_spi_apps_clk.c, ""),
@@ -5064,18 +5080,19 @@
CLK_LOOKUP("core_clk", mdss_esc1_clk.c, ""),
CLK_LOOKUP("pixel_clk", mdss_pclk0_clk.c, "fd922800.qcom,mdss_dsi"),
CLK_LOOKUP("pixel_clk", mdss_pclk1_clk.c, ""),
- CLK_LOOKUP("iface_clk", mdss_hdmi_ahb_clk.c, ""),
- CLK_LOOKUP("core_clk", mdss_hdmi_clk.c, ""),
+ CLK_LOOKUP("iface_clk", mdss_hdmi_ahb_clk.c, "fd922100.qcom,hdmi_tx"),
+ CLK_LOOKUP("core_clk", mdss_hdmi_clk.c, "fd922100.qcom,hdmi_tx"),
+ CLK_LOOKUP("extp_clk", mdss_extpclk_clk.c, "fd922100.qcom,hdmi_tx"),
CLK_LOOKUP("core_clk", mdss_mdp_clk.c, "mdp.0"),
CLK_LOOKUP("lut_clk", mdss_mdp_lut_clk.c, "mdp.0"),
CLK_LOOKUP("core_clk_src", mdp_clk_src.c, "mdp.0"),
CLK_LOOKUP("vsync_clk", mdss_vsync_clk.c, "mdp.0"),
/* MM sensor clocks */
- CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6e.qcom,s5k3l1yx"),
- CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6c.qcom,ov2720"),
- CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "6e.qcom,s5k3l1yx"),
- CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "6c.qcom,ov2720"),
+ CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6e.qcom,camera"),
+ CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6c.qcom,camera"),
+ CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "6e.qcom,camera"),
+ CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "6c.qcom,camera"),
CLK_LOOKUP("cam_clk", camss_mclk1_clk.c, ""),
CLK_LOOKUP("cam_clk", camss_mclk2_clk.c, ""),
CLK_LOOKUP("cam_clk", camss_mclk3_clk.c, ""),
@@ -5236,7 +5253,7 @@
"msm-dai-q6.4106"),
CLK_LOOKUP("core_oe_clk", audio_core_lpaif_pcmoe_clk.c,
"msm-dai-q6.4106"),
-
+ CLK_LOOKUP("br_clk", audio_wrapper_br_clk.c, "fdd00000.qcom,ocmem"),
CLK_LOOKUP("core_clk", mss_xo_q6_clk.c, "pil-q6v5-mss"),
CLK_LOOKUP("bus_clk", gcc_mss_q6_bimc_axi_clk.c, "pil-q6v5-mss"),
CLK_LOOKUP("iface_clk", gcc_mss_cfg_ahb_clk.c, "pil-q6v5-mss"),
diff --git a/arch/arm/mach-msm/clock-mdss-8974.c b/arch/arm/mach-msm/clock-mdss-8974.c
index e8aa790..4d147c3 100644
--- a/arch/arm/mach-msm/clock-mdss-8974.c
+++ b/arch/arm/mach-msm/clock-mdss-8974.c
@@ -24,8 +24,43 @@
#include "clock.h"
#include "clock-mdss-8974.h"
-#define MDSS_DSI_PHY_BASE_ADR 0xFD922800
-#define DSI_REG_SIZE 2048
+#define REG_R(addr) readl_relaxed(addr)
+#define REG_W(data, addr) writel_relaxed(data, addr)
+
+#define DSI_PHY_PHYS 0xFD922800
+#define DSI_PHY_SIZE 0x00000800
+
+#define HDMI_PHY_PHYS 0xFD922500
+#define HDMI_PHY_SIZE 0x0000007C
+
+#define HDMI_PHY_PLL_PHYS 0xFD922700
+#define HDMI_PHY_PLL_SIZE 0x000000D4
+
+/* hdmi phy registers */
+#define HDMI_PHY_PD_CTRL0 (0x0010)
+#define HDMI_PHY_GLB_CFG (0x0018)
+#define HDMI_PHY_STATUS (0x005C)
+
+/* hdmi phy unified pll registers */
+#define HDMI_UNI_PLL_REFCLK_CF (0x0000)
+#define HDMI_UNI_PLL_POSTDIV1_CFG (0x0004)
+#define HDMI_UNI_PLL_VCOLPF_CFG (0x000C)
+#define HDMI_UNI_PLL_GLB_CFG (0x0020)
+#define HDMI_UNI_PLL_POSTDIV2_CFG (0x0024)
+#define HDMI_UNI_PLL_POSTDIV3_CFG (0x0028)
+#define HDMI_UNI_PLL_SDM_CFG0 (0x0038)
+#define HDMI_UNI_PLL_SDM_CFG1 (0x003C)
+#define HDMI_UNI_PLL_SDM_CFG2 (0x0040)
+#define HDMI_UNI_PLL_SDM_CFG3 (0x0044)
+#define HDMI_UNI_PLL_SDM_CFG4 (0x0048)
+#define HDMI_UNI_PLL_LKDET_CFG0 (0x005C)
+#define HDMI_UNI_PLL_LKDET_CFG1 (0x0060)
+#define HDMI_UNI_PLL_LKDET_CFG2 (0x0064)
+#define HDMI_UNI_PLL_CAL_CFG8 (0x008C)
+#define HDMI_UNI_PLL_CAL_CFG9 (0x0090)
+#define HDMI_UNI_PLL_CAL_CFG10 (0x0094)
+#define HDMI_UNI_PLL_CAL_CFG11 (0x0098)
+#define HDMI_UNI_PLL_STATUS (0x00C0)
#define VCO_CLK 424000000
static unsigned char *mdss_dsi_base;
@@ -34,22 +69,32 @@
static int pll_initialized;
static struct clk *mdss_dsi_ahb_clk;
+static void __iomem *hdmi_phy_base;
+static void __iomem *hdmi_phy_pll_base;
+static unsigned hdmi_pll_on;
+
void __init mdss_clk_ctrl_init(void)
{
- mdss_dsi_base = ioremap(MDSS_DSI_PHY_BASE_ADR,
- DSI_REG_SIZE);
+ mdss_dsi_base = ioremap(DSI_PHY_PHYS, DSI_PHY_SIZE);
if (!mdss_dsi_base)
- pr_err("%s:%d unable to remap dsi base",
- __func__, __LINE__);
+ pr_err("%s: unable to remap dsi base", __func__);
mdss_dsi_ahb_clk = clk_get_sys("mdss_dsi_clk_ctrl", "iface_clk");
if (!IS_ERR(mdss_dsi_ahb_clk)) {
clk_prepare(mdss_dsi_ahb_clk);
} else {
mdss_dsi_ahb_clk = NULL;
- pr_err("%s:%d unable to get iface clock\n",
+ pr_err("%s:%d unable to get dsi iface clock\n",
__func__, __LINE__);
}
+
+ hdmi_phy_base = ioremap(HDMI_PHY_PHYS, HDMI_PHY_SIZE);
+ if (!hdmi_phy_base)
+ pr_err("%s: unable to ioremap hdmi phy base", __func__);
+
+ hdmi_phy_pll_base = ioremap(HDMI_PHY_PLL_PHYS, HDMI_PHY_PLL_SIZE);
+ if (!hdmi_phy_pll_base)
+ pr_err("%s: unable to ioremap hdmi phy pll base", __func__);
}
static long mdss_dsi_pll_byte_round_rate(struct clk *c, unsigned long rate)
@@ -112,41 +157,41 @@
/* Configure the Loop filter */
/* Loop filter resistance value */
- writel_relaxed(0x08, mdss_dsi_base + 0x022c);
+ REG_W(0x08, mdss_dsi_base + 0x022c);
/* Loop filter capacitance values : c1 and c2 */
- writel_relaxed(0x70, mdss_dsi_base + 0x0230);
- writel_relaxed(0x15, mdss_dsi_base + 0x0234);
+ REG_W(0x70, mdss_dsi_base + 0x0230);
+ REG_W(0x15, mdss_dsi_base + 0x0234);
- writel_relaxed(0x02, mdss_dsi_base + 0x0208); /* ChgPump */
- writel_relaxed(pll_divcfg1, mdss_dsi_base + 0x0204); /* postDiv1 */
- writel_relaxed(pll_divcfg2, mdss_dsi_base + 0x0224); /* postDiv2 */
- writel_relaxed(0x03, mdss_dsi_base + 0x0228); /* postDiv3 */
+ REG_W(0x02, mdss_dsi_base + 0x0208); /* ChgPump */
+ REG_W(pll_divcfg1, mdss_dsi_base + 0x0204); /* postDiv1 */
+ REG_W(pll_divcfg2, mdss_dsi_base + 0x0224); /* postDiv2 */
+ REG_W(0x03, mdss_dsi_base + 0x0228); /* postDiv3 */
- writel_relaxed(0x2b, mdss_dsi_base + 0x0278); /* Cal CFG3 */
- writel_relaxed(0x06, mdss_dsi_base + 0x027c); /* Cal CFG4 */
- writel_relaxed(0x05, mdss_dsi_base + 0x0264); /* Cal CFG4 */
+ REG_W(0x2b, mdss_dsi_base + 0x0278); /* Cal CFG3 */
+ REG_W(0x06, mdss_dsi_base + 0x027c); /* Cal CFG4 */
+ REG_W(0x05, mdss_dsi_base + 0x0264); /* Cal CFG4 */
- writel_relaxed(0x0a, mdss_dsi_base + 0x023c); /* SDM CFG1 */
- writel_relaxed(0xab, mdss_dsi_base + 0x0240); /* SDM CFG2 */
- writel_relaxed(0x0a, mdss_dsi_base + 0x0244); /* SDM CFG3 */
- writel_relaxed(0x00, mdss_dsi_base + 0x0248); /* SDM CFG4 */
+ REG_W(0x0a, mdss_dsi_base + 0x023c); /* SDM CFG1 */
+ REG_W(0xab, mdss_dsi_base + 0x0240); /* SDM CFG2 */
+ REG_W(0x0a, mdss_dsi_base + 0x0244); /* SDM CFG3 */
+ REG_W(0x00, mdss_dsi_base + 0x0248); /* SDM CFG4 */
udelay(10);
- writel_relaxed(0x01, mdss_dsi_base + 0x0200); /* REFCLK CFG */
- writel_relaxed(0x00, mdss_dsi_base + 0x0214); /* PWRGEN CFG */
- writel_relaxed(0x01, mdss_dsi_base + 0x020c); /* VCOLPF CFG */
- writel_relaxed(0x02, mdss_dsi_base + 0x0210); /* VREG CFG */
- writel_relaxed(0x00, mdss_dsi_base + 0x0238); /* SDM CFG0 */
+ REG_W(0x01, mdss_dsi_base + 0x0200); /* REFCLK CFG */
+ REG_W(0x00, mdss_dsi_base + 0x0214); /* PWRGEN CFG */
+ REG_W(0x01, mdss_dsi_base + 0x020c); /* VCOLPF CFG */
+ REG_W(0x02, mdss_dsi_base + 0x0210); /* VREG CFG */
+ REG_W(0x00, mdss_dsi_base + 0x0238); /* SDM CFG0 */
- writel_relaxed(0x5f, mdss_dsi_base + 0x028c); /* CAL CFG8 */
- writel_relaxed(0xa8, mdss_dsi_base + 0x0294); /* CAL CFG10 */
- writel_relaxed(0x01, mdss_dsi_base + 0x0298); /* CAL CFG11 */
- writel_relaxed(0x0a, mdss_dsi_base + 0x026c); /* CAL CFG0 */
- writel_relaxed(0x30, mdss_dsi_base + 0x0284); /* CAL CFG6 */
- writel_relaxed(0x00, mdss_dsi_base + 0x0288); /* CAL CFG7 */
- writel_relaxed(0x00, mdss_dsi_base + 0x0290); /* CAL CFG9 */
- writel_relaxed(0x20, mdss_dsi_base + 0x029c); /* EFUSE CFG */
+ REG_W(0x5f, mdss_dsi_base + 0x028c); /* CAL CFG8 */
+ REG_W(0xa8, mdss_dsi_base + 0x0294); /* CAL CFG10 */
+ REG_W(0x01, mdss_dsi_base + 0x0298); /* CAL CFG11 */
+ REG_W(0x0a, mdss_dsi_base + 0x026c); /* CAL CFG0 */
+ REG_W(0x30, mdss_dsi_base + 0x0284); /* CAL CFG6 */
+ REG_W(0x00, mdss_dsi_base + 0x0288); /* CAL CFG7 */
+ REG_W(0x00, mdss_dsi_base + 0x0290); /* CAL CFG9 */
+ REG_W(0x20, mdss_dsi_base + 0x029c); /* EFUSE CFG */
pll_byte_clk_rate = 53000000;
pll_pclk_rate = 105000000;
@@ -174,12 +219,12 @@
clk_enable(mdss_dsi_ahb_clk);
/* PLL power up */
- writel_relaxed(0x01, mdss_dsi_base + 0x0220); /* GLB CFG */
- writel_relaxed(0x05, mdss_dsi_base + 0x0220); /* GLB CFG */
+ REG_W(0x01, mdss_dsi_base + 0x0220); /* GLB CFG */
+ REG_W(0x05, mdss_dsi_base + 0x0220); /* GLB CFG */
udelay(20);
- writel_relaxed(0x07, mdss_dsi_base + 0x0220); /* GLB CFG */
+ REG_W(0x07, mdss_dsi_base + 0x0220); /* GLB CFG */
udelay(20);
- writel_relaxed(0x0f, mdss_dsi_base + 0x0220); /* GLB CFG */
+ REG_W(0x0f, mdss_dsi_base + 0x0220); /* GLB CFG */
/* poll for PLL ready status */
max_reads = 20;
@@ -210,6 +255,203 @@
clk_disable(mdss_dsi_ahb_clk);
}
+void hdmi_pll_disable(void)
+{
+ REG_W(0x0, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
+ udelay(5);
+ REG_W(0x0, hdmi_phy_base + HDMI_PHY_GLB_CFG);
+
+ hdmi_pll_on = 0;
+} /* hdmi_pll_disable */
+
+int hdmi_pll_enable(void)
+{
+ u32 status;
+ u32 max_reads, timeout_us;
+
+ /* Global Enable */
+ REG_W(0x81, hdmi_phy_base + HDMI_PHY_GLB_CFG);
+ /* Power up power gen */
+ REG_W(0x00, hdmi_phy_base + HDMI_PHY_PD_CTRL0);
+ udelay(350);
+
+ /* PLL Power-Up */
+ REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
+ udelay(5);
+ /* Power up PLL LDO */
+ REG_W(0x03, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
+ udelay(350);
+
+ /* PLL Power-Up */
+ REG_W(0x0F, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
+ udelay(350);
+
+ /* poll for PLL ready status */
+ max_reads = 20;
+ timeout_us = 100;
+ if (readl_poll_timeout_noirq((hdmi_phy_pll_base + HDMI_UNI_PLL_STATUS),
+ status, ((status & BIT(0)) == 1), max_reads, timeout_us)) {
+ pr_err("%s: hdmi phy pll status=%x failed to Lock\n",
+ __func__, status);
+ hdmi_pll_disable();
+ return -EINVAL;
+ }
+ pr_debug("%s: hdmi phy pll is locked\n", __func__);
+
+ udelay(350);
+ /* poll for PHY ready status */
+ max_reads = 20;
+ timeout_us = 100;
+ if (readl_poll_timeout_noirq((hdmi_phy_base + HDMI_PHY_STATUS),
+ status, ((status & BIT(0)) == 1), max_reads, timeout_us)) {
+ pr_err("%s: hdmi phy status=%x failed to Lock\n",
+ __func__, status);
+ hdmi_pll_disable();
+ return -EINVAL;
+ }
+ pr_debug("%s: hdmi phy is locked\n", __func__);
+
+ hdmi_pll_on = 1;
+
+ return 0;
+} /* hdmi_pll_enable */
+
+int hdmi_pll_set_rate(unsigned long rate)
+{
+ unsigned int set_power_dwn = 0;
+
+ if (hdmi_pll_on) {
+ hdmi_pll_disable();
+ set_power_dwn = 1;
+ }
+
+ pr_debug("%s: rate=%ld\n", __func__, rate);
+ switch (rate) {
+ case 0:
+ /* This case is needed for suspend/resume. */
+ break;
+
+ case 25200000:
+ /* 640x480p60 */
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_REFCLK_CF);
+ REG_W(0x20, hdmi_phy_pll_base + HDMI_UNI_PLL_VCOLPF_CFG);
+ REG_W(0x36, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG0);
+ REG_W(0x4C, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG1);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG2);
+ REG_W(0x20, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG3);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG4);
+ REG_W(0x10, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG0);
+ REG_W(0x1A, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG1);
+ REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG2);
+ REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV1_CFG);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV2_CFG);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV3_CFG);
+ REG_W(0x60, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG8);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG9);
+ REG_W(0xFC, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG10);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG11);
+ break;
+
+ case 27030000:
+ /* 480p60/480i60 case */
+ REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_REFCLK_CF);
+ REG_W(0x18, hdmi_phy_pll_base + HDMI_UNI_PLL_VCOLPF_CFG);
+ REG_W(0x36, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG0);
+ REG_W(0x14, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG1);
+ REG_W(0x63, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG2);
+ REG_W(0x1D, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG3);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG4);
+ REG_W(0x10, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG0);
+ REG_W(0x1A, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG1);
+ REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG2);
+ REG_W(0x03, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV1_CFG);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV2_CFG);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV3_CFG);
+ REG_W(0x60, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG8);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG9);
+ REG_W(0x2A, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG10);
+ REG_W(0x03, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG11);
+ break;
+
+ case 74250000:
+ /*
+ * 720p60/720p50/1080i60/1080i50
+ * 1080p24/1080p30/1080p25 case
+ */
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_REFCLK_CF);
+ REG_W(0x20, hdmi_phy_pll_base + HDMI_UNI_PLL_VCOLPF_CFG);
+ REG_W(0x36, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG0);
+ REG_W(0x52, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG1);
+ REG_W(0xFD, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG2);
+ REG_W(0x55, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG3);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG4);
+ REG_W(0x10, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG0);
+ REG_W(0x1A, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG1);
+ REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG2);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV1_CFG);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV2_CFG);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV3_CFG);
+ REG_W(0x60, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG8);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG9);
+ REG_W(0x73, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG10);
+ REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG11);
+ break;
+
+ case 148500000:
+ REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_REFCLK_CF);
+ REG_W(0x18, hdmi_phy_pll_base + HDMI_UNI_PLL_VCOLPF_CFG);
+ REG_W(0x36, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG0);
+ REG_W(0x52, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG1);
+ REG_W(0xFD, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG2);
+ REG_W(0x55, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG3);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG4);
+ REG_W(0x10, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG0);
+ REG_W(0x1A, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG1);
+ REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG2);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV1_CFG);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV2_CFG);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV3_CFG);
+ REG_W(0x60, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG8);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG9);
+ REG_W(0xE6, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG10);
+ REG_W(0x02, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG11);
+ break;
+
+ case 297000000:
+ REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_REFCLK_CF);
+ REG_W(0x18, hdmi_phy_pll_base + HDMI_UNI_PLL_VCOLPF_CFG);
+ REG_W(0x36, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG0);
+ REG_W(0x65, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG1);
+ REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG2);
+ REG_W(0xAC, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG3);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_SDM_CFG4);
+ REG_W(0x10, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG0);
+ REG_W(0x1A, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG1);
+ REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_LKDET_CFG2);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV1_CFG);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV2_CFG);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_POSTDIV3_CFG);
+ REG_W(0x60, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG8);
+ REG_W(0x00, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG9);
+ REG_W(0xCD, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG10);
+ REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG11);
+ break;
+
+ case 27000000:
+ /* 576p50/576i50 case */
+ default:
+ pr_err("%s: not supported rate=%ld\n", __func__, rate);
+ }
+
+ /* Make sure writes complete before disabling iface clock */
+ mb();
+
+ if (set_power_dwn)
+ hdmi_pll_enable();
+
+ return 0;
+} /* hdmi_pll_set_rate */
+
struct clk_ops clk_ops_dsi_pixel_pll = {
.enable = mdss_dsi_pll_enable,
.disable = mdss_dsi_pll_disable,
diff --git a/arch/arm/mach-msm/clock-mdss-8974.h b/arch/arm/mach-msm/clock-mdss-8974.h
index aaf72d2..509a220 100644
--- a/arch/arm/mach-msm/clock-mdss-8974.h
+++ b/arch/arm/mach-msm/clock-mdss-8974.h
@@ -13,8 +13,12 @@
#ifndef __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8974
#define __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8974
-void mdss_clk_ctrl_init(void);
extern struct clk_ops clk_ops_dsi_byte_pll;
extern struct clk_ops clk_ops_dsi_pixel_pll;
+void mdss_clk_ctrl_init(void);
+int hdmi_pll_enable(void);
+void hdmi_pll_disable(void);
+int hdmi_pll_set_rate(unsigned long rate);
+
#endif
diff --git a/arch/arm/mach-msm/clock.h b/arch/arm/mach-msm/clock.h
index d88466d..4e3d83b 100644
--- a/arch/arm/mach-msm/clock.h
+++ b/arch/arm/mach-msm/clock.h
@@ -169,6 +169,7 @@
extern struct clock_init_data qds8x50_clock_init_data;
extern struct clock_init_data msm8625_dummy_clock_init_data;
extern struct clock_init_data msm8930_clock_init_data;
+extern struct clock_init_data msm8930_pm8917_clock_init_data;
extern struct clock_init_data msm8974_clock_init_data;
extern struct clock_init_data msm8974_rumi_clock_init_data;
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index 3b262bc..da98f34 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -58,6 +58,7 @@
/* GSBI UART devices */
#define MSM_UART1DM_PHYS (MSM_GSBI1_PHYS + 0x10000)
#define MSM_UART3DM_PHYS (MSM_GSBI3_PHYS + 0x40000)
+#define MSM_UART6DM_PHYS (MSM_GSBI6_PHYS + 0x40000)
#define MSM_UART7DM_PHYS (MSM_GSBI7_PHYS + 0x40000)
/* GSBI QUP devices */
@@ -393,6 +394,50 @@
.resource = resources_qup_i2c_gsbi5,
};
+/* GSBI 6 used into UARTDM Mode */
+static struct resource msm_uart_dm6_resources[] = {
+ {
+ .start = MSM_UART6DM_PHYS,
+ .end = MSM_UART6DM_PHYS + PAGE_SIZE - 1,
+ .name = "uartdm_resource",
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = GSBI6_UARTDM_IRQ,
+ .end = GSBI6_UARTDM_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = MSM_GSBI6_PHYS,
+ .end = MSM_GSBI6_PHYS + 4 - 1,
+ .name = "gsbi_resource",
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = DMOV_MPQ8064_HSUART_GSBI6_TX_CHAN,
+ .end = DMOV_MPQ8064_HSUART_GSBI6_RX_CHAN,
+ .name = "uartdm_channels",
+ .flags = IORESOURCE_DMA,
+ },
+ {
+ .start = DMOV_MPQ8064_HSUART_GSBI6_TX_CRCI,
+ .end = DMOV_MPQ8064_HSUART_GSBI6_RX_CRCI,
+ .name = "uartdm_crci",
+ .flags = IORESOURCE_DMA,
+ },
+};
+static u64 msm_uart_dm6_dma_mask = DMA_BIT_MASK(32);
+struct platform_device mpq8064_device_uartdm_gsbi6 = {
+ .name = "msm_serial_hs",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(msm_uart_dm6_resources),
+ .resource = msm_uart_dm6_resources,
+ .dev = {
+ .dma_mask = &msm_uart_dm6_dma_mask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+};
+
static struct resource resources_uart_gsbi7[] = {
{
.start = GSBI7_UARTDM_IRQ,
diff --git a/arch/arm/mach-msm/devices-8930.c b/arch/arm/mach-msm/devices-8930.c
index a257a9c..867e8fc 100644
--- a/arch/arm/mach-msm/devices-8930.c
+++ b/arch/arm/mach-msm/devices-8930.c
@@ -32,6 +32,7 @@
#include "rpm_stats.h"
#include "rpm_rbcpr_stats.h"
#include "footswitch.h"
+#include "acpuclock-krait.h"
#ifdef CONFIG_MSM_MPM
#include <mach/mpm.h>
@@ -228,13 +229,13 @@
MSM_RPM_STATUS_ID_MAP(8930, PM8038_CLK2_1),
MSM_RPM_STATUS_ID_MAP(8930, PM8038_LVS1),
MSM_RPM_STATUS_ID_MAP(8930, PM8038_LVS2),
- MSM_RPM_STATUS_ID_MAP(8930, NCP_0),
- MSM_RPM_STATUS_ID_MAP(8930, NCP_1),
- MSM_RPM_STATUS_ID_MAP(8930, CXO_BUFFERS),
- MSM_RPM_STATUS_ID_MAP(8930, USB_OTG_SWITCH),
- MSM_RPM_STATUS_ID_MAP(8930, HDMI_SWITCH),
- MSM_RPM_STATUS_ID_MAP(8930, QDSS_CLK),
- MSM_RPM_STATUS_ID_MAP(8930, VOLTAGE_CORNER),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8038_NCP_0),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8038_NCP_1),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8038_CXO_BUFFERS),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8038_USB_OTG_SWITCH),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8038_HDMI_SWITCH),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8038_QDSS_CLK),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8038_VOLTAGE_CORNER),
},
.target_ctrl_id = {
MSM_RPM_CTRL_MAP(8930, VERSION_MAJOR),
@@ -251,6 +252,259 @@
.ver = {3, 0, 0},
};
+struct msm_rpm_platform_data msm8930_rpm_data_pm8917 __initdata = {
+ .reg_base_addrs = {
+ [MSM_RPM_PAGE_STATUS] = MSM_RPM_BASE,
+ [MSM_RPM_PAGE_CTRL] = MSM_RPM_BASE + 0x400,
+ [MSM_RPM_PAGE_REQ] = MSM_RPM_BASE + 0x600,
+ [MSM_RPM_PAGE_ACK] = MSM_RPM_BASE + 0xa00,
+ },
+ .irq_ack = RPM_APCC_CPU0_GP_HIGH_IRQ,
+ .irq_err = RPM_APCC_CPU0_GP_LOW_IRQ,
+ .irq_wakeup = RPM_APCC_CPU0_WAKE_UP_IRQ,
+ .ipc_rpm_reg = MSM_APCS_GCC_BASE + 0x008,
+ .ipc_rpm_val = 4,
+ .target_id = {
+ MSM_RPM_MAP(8930, NOTIFICATION_CONFIGURED_0, NOTIFICATION, 4),
+ MSM_RPM_MAP(8930, NOTIFICATION_REGISTERED_0, NOTIFICATION, 4),
+ MSM_RPM_MAP(8930, INVALIDATE_0, INVALIDATE, 8),
+ MSM_RPM_MAP(8960, TRIGGER_TIMED_TO, TRIGGER_TIMED, 1),
+ MSM_RPM_MAP(8960, TRIGGER_TIMED_SCLK_COUNT, TRIGGER_TIMED, 1),
+ MSM_RPM_MAP(8930, RPM_CTL, RPM_CTL, 1),
+ MSM_RPM_MAP(8930, CXO_CLK, CXO_CLK, 1),
+ MSM_RPM_MAP(8930, PXO_CLK, PXO_CLK, 1),
+ MSM_RPM_MAP(8930, APPS_FABRIC_CLK, APPS_FABRIC_CLK, 1),
+ MSM_RPM_MAP(8930, SYSTEM_FABRIC_CLK, SYSTEM_FABRIC_CLK, 1),
+ MSM_RPM_MAP(8930, MM_FABRIC_CLK, MM_FABRIC_CLK, 1),
+ MSM_RPM_MAP(8930, DAYTONA_FABRIC_CLK, DAYTONA_FABRIC_CLK, 1),
+ MSM_RPM_MAP(8930, SFPB_CLK, SFPB_CLK, 1),
+ MSM_RPM_MAP(8930, CFPB_CLK, CFPB_CLK, 1),
+ MSM_RPM_MAP(8930, MMFPB_CLK, MMFPB_CLK, 1),
+ MSM_RPM_MAP(8930, EBI1_CLK, EBI1_CLK, 1),
+ MSM_RPM_MAP(8930, APPS_FABRIC_CFG_HALT_0,
+ APPS_FABRIC_CFG_HALT, 2),
+ MSM_RPM_MAP(8930, APPS_FABRIC_CFG_CLKMOD_0,
+ APPS_FABRIC_CFG_CLKMOD, 3),
+ MSM_RPM_MAP(8930, APPS_FABRIC_CFG_IOCTL,
+ APPS_FABRIC_CFG_IOCTL, 1),
+ MSM_RPM_MAP(8930, APPS_FABRIC_ARB_0, APPS_FABRIC_ARB, 6),
+ MSM_RPM_MAP(8930, SYS_FABRIC_CFG_HALT_0,
+ SYS_FABRIC_CFG_HALT, 2),
+ MSM_RPM_MAP(8930, SYS_FABRIC_CFG_CLKMOD_0,
+ SYS_FABRIC_CFG_CLKMOD, 3),
+ MSM_RPM_MAP(8930, SYS_FABRIC_CFG_IOCTL,
+ SYS_FABRIC_CFG_IOCTL, 1),
+ MSM_RPM_MAP(8930, SYSTEM_FABRIC_ARB_0,
+ SYSTEM_FABRIC_ARB, 20),
+ MSM_RPM_MAP(8930, MMSS_FABRIC_CFG_HALT_0,
+ MMSS_FABRIC_CFG_HALT, 2),
+ MSM_RPM_MAP(8930, MMSS_FABRIC_CFG_CLKMOD_0,
+ MMSS_FABRIC_CFG_CLKMOD, 3),
+ MSM_RPM_MAP(8930, MMSS_FABRIC_CFG_IOCTL,
+ MMSS_FABRIC_CFG_IOCTL, 1),
+ MSM_RPM_MAP(8930, MM_FABRIC_ARB_0, MM_FABRIC_ARB, 11),
+ MSM_RPM_MAP(8930, PM8917_S1_0, PM8917_S1, 2),
+ MSM_RPM_MAP(8930, PM8917_S2_0, PM8917_S2, 2),
+ MSM_RPM_MAP(8930, PM8917_S3_0, PM8917_S3, 2),
+ MSM_RPM_MAP(8930, PM8917_S4_0, PM8917_S4, 2),
+ MSM_RPM_MAP(8930, PM8917_S5_0, PM8917_S5, 2),
+ MSM_RPM_MAP(8930, PM8917_S6_0, PM8917_S6, 2),
+ MSM_RPM_MAP(8930, PM8917_S7_0, PM8917_S7, 2),
+ MSM_RPM_MAP(8930, PM8917_S8_0, PM8917_S8, 2),
+ MSM_RPM_MAP(8930, PM8917_L1_0, PM8917_L1, 2),
+ MSM_RPM_MAP(8930, PM8917_L2_0, PM8917_L2, 2),
+ MSM_RPM_MAP(8930, PM8917_L3_0, PM8917_L3, 2),
+ MSM_RPM_MAP(8930, PM8917_L4_0, PM8917_L4, 2),
+ MSM_RPM_MAP(8930, PM8917_L5_0, PM8917_L5, 2),
+ MSM_RPM_MAP(8930, PM8917_L6_0, PM8917_L6, 2),
+ MSM_RPM_MAP(8930, PM8917_L7_0, PM8917_L7, 2),
+ MSM_RPM_MAP(8930, PM8917_L8_0, PM8917_L8, 2),
+ MSM_RPM_MAP(8930, PM8917_L9_0, PM8917_L9, 2),
+ MSM_RPM_MAP(8930, PM8917_L10_0, PM8917_L10, 2),
+ MSM_RPM_MAP(8930, PM8917_L11_0, PM8917_L11, 2),
+ MSM_RPM_MAP(8930, PM8917_L12_0, PM8917_L12, 2),
+ MSM_RPM_MAP(8930, PM8917_L14_0, PM8917_L14, 2),
+ MSM_RPM_MAP(8930, PM8917_L15_0, PM8917_L15, 2),
+ MSM_RPM_MAP(8930, PM8917_L16_0, PM8917_L16, 2),
+ MSM_RPM_MAP(8930, PM8917_L17_0, PM8917_L17, 2),
+ MSM_RPM_MAP(8930, PM8917_L18_0, PM8917_L18, 2),
+ MSM_RPM_MAP(8930, PM8917_L21_0, PM8917_L21, 2),
+ MSM_RPM_MAP(8930, PM8917_L22_0, PM8917_L22, 2),
+ MSM_RPM_MAP(8930, PM8917_L23_0, PM8917_L23, 2),
+ MSM_RPM_MAP(8930, PM8917_L24_0, PM8917_L24, 2),
+ MSM_RPM_MAP(8930, PM8917_L25_0, PM8917_L25, 2),
+ MSM_RPM_MAP(8930, PM8917_L26_0, PM8917_L26, 2),
+ MSM_RPM_MAP(8930, PM8917_L27_0, PM8917_L27, 2),
+ MSM_RPM_MAP(8930, PM8917_L28_0, PM8917_L28, 2),
+ MSM_RPM_MAP(8930, PM8917_L29_0, PM8917_L29, 2),
+ MSM_RPM_MAP(8930, PM8917_L30_0, PM8917_L30, 2),
+ MSM_RPM_MAP(8930, PM8917_L31_0, PM8917_L31, 2),
+ MSM_RPM_MAP(8930, PM8917_L32_0, PM8917_L32, 2),
+ MSM_RPM_MAP(8930, PM8917_L33_0, PM8917_L33, 2),
+ MSM_RPM_MAP(8930, PM8917_L34_0, PM8917_L34, 2),
+ MSM_RPM_MAP(8930, PM8917_L35_0, PM8917_L35, 2),
+ MSM_RPM_MAP(8930, PM8917_L36_0, PM8917_L36, 2),
+ MSM_RPM_MAP(8930, PM8917_CLK1_0, PM8917_CLK1, 2),
+ MSM_RPM_MAP(8930, PM8917_CLK2_0, PM8917_CLK2, 2),
+ MSM_RPM_MAP(8930, PM8917_LVS1, PM8917_LVS1, 1),
+ MSM_RPM_MAP(8930, PM8917_LVS3, PM8917_LVS3, 1),
+ MSM_RPM_MAP(8930, PM8917_LVS4, PM8917_LVS4, 1),
+ MSM_RPM_MAP(8930, PM8917_LVS5, PM8917_LVS5, 1),
+ MSM_RPM_MAP(8930, PM8917_LVS6, PM8917_LVS6, 1),
+ MSM_RPM_MAP(8930, PM8917_LVS7, PM8917_LVS7, 1),
+ MSM_RPM_MAP(8930, NCP_0, NCP, 2),
+ MSM_RPM_MAP(8930, CXO_BUFFERS, CXO_BUFFERS, 1),
+ MSM_RPM_MAP(8930, USB_OTG_SWITCH, USB_OTG_SWITCH, 1),
+ MSM_RPM_MAP(8930, HDMI_SWITCH, HDMI_SWITCH, 1),
+ MSM_RPM_MAP(8930, QDSS_CLK, QDSS_CLK, 1),
+ MSM_RPM_MAP(8930, VOLTAGE_CORNER, VOLTAGE_CORNER, 1),
+ },
+ .target_status = {
+ MSM_RPM_STATUS_ID_MAP(8930, VERSION_MAJOR),
+ MSM_RPM_STATUS_ID_MAP(8930, VERSION_MINOR),
+ MSM_RPM_STATUS_ID_MAP(8930, VERSION_BUILD),
+ MSM_RPM_STATUS_ID_MAP(8930, SUPPORTED_RESOURCES_0),
+ MSM_RPM_STATUS_ID_MAP(8930, SUPPORTED_RESOURCES_1),
+ MSM_RPM_STATUS_ID_MAP(8930, SUPPORTED_RESOURCES_2),
+ MSM_RPM_STATUS_ID_MAP(8930, RESERVED_SUPPORTED_RESOURCES_0),
+ MSM_RPM_STATUS_ID_MAP(8930, SEQUENCE),
+ MSM_RPM_STATUS_ID_MAP(8930, RPM_CTL),
+ MSM_RPM_STATUS_ID_MAP(8930, CXO_CLK),
+ MSM_RPM_STATUS_ID_MAP(8930, PXO_CLK),
+ MSM_RPM_STATUS_ID_MAP(8930, APPS_FABRIC_CLK),
+ MSM_RPM_STATUS_ID_MAP(8930, SYSTEM_FABRIC_CLK),
+ MSM_RPM_STATUS_ID_MAP(8930, MM_FABRIC_CLK),
+ MSM_RPM_STATUS_ID_MAP(8930, DAYTONA_FABRIC_CLK),
+ MSM_RPM_STATUS_ID_MAP(8930, SFPB_CLK),
+ MSM_RPM_STATUS_ID_MAP(8930, CFPB_CLK),
+ MSM_RPM_STATUS_ID_MAP(8930, MMFPB_CLK),
+ MSM_RPM_STATUS_ID_MAP(8930, EBI1_CLK),
+ MSM_RPM_STATUS_ID_MAP(8930, APPS_FABRIC_CFG_HALT),
+ MSM_RPM_STATUS_ID_MAP(8930, APPS_FABRIC_CFG_CLKMOD),
+ MSM_RPM_STATUS_ID_MAP(8930, APPS_FABRIC_CFG_IOCTL),
+ MSM_RPM_STATUS_ID_MAP(8930, APPS_FABRIC_ARB),
+ MSM_RPM_STATUS_ID_MAP(8930, SYS_FABRIC_CFG_HALT),
+ MSM_RPM_STATUS_ID_MAP(8930, SYS_FABRIC_CFG_CLKMOD),
+ MSM_RPM_STATUS_ID_MAP(8930, SYS_FABRIC_CFG_IOCTL),
+ MSM_RPM_STATUS_ID_MAP(8930, SYSTEM_FABRIC_ARB),
+ MSM_RPM_STATUS_ID_MAP(8930, MMSS_FABRIC_CFG_HALT),
+ MSM_RPM_STATUS_ID_MAP(8930, MMSS_FABRIC_CFG_CLKMOD),
+ MSM_RPM_STATUS_ID_MAP(8930, MMSS_FABRIC_CFG_IOCTL),
+ MSM_RPM_STATUS_ID_MAP(8930, MM_FABRIC_ARB),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_S1_0),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_S1_1),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_S2_0),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_S2_1),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_S3_0),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_S3_1),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_S4_0),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_S4_1),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_S5_0),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_S5_1),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_S6_0),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_S6_1),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_S7_0),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_S7_1),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_S8_0),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_S8_1),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_L1_0),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_L1_1),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_L2_0),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_L2_1),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_L3_0),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_L3_1),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_L4_0),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_L4_1),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_L5_0),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_L5_1),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_L6_0),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_L6_1),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_L7_0),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_L7_1),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_L8_0),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_L8_1),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_L9_0),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_L9_1),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_L10_0),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_L10_1),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_L11_0),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_L11_1),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_L12_0),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_L12_1),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_L14_0),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_L14_1),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_L15_0),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_L15_1),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_L16_0),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_L16_1),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_L17_0),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_L17_1),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_L18_0),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_L18_1),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_L21_0),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_L21_1),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_L22_0),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_L22_1),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_L23_0),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_L23_1),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_L24_0),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_L24_1),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_L25_0),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_L25_1),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_L26_0),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_L26_1),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_L27_0),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_L27_1),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_L28_0),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_L28_1),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_L29_0),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_L29_1),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_L30_0),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_L30_1),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_L31_0),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_L31_1),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_L32_0),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_L32_1),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_L33_0),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_L33_1),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_L34_0),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_L34_1),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_L35_0),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_L35_1),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_L36_0),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_L36_1),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_CLK1_0),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_CLK1_1),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_CLK2_0),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_CLK2_1),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_LVS1),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_LVS3),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_LVS4),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_LVS5),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_LVS6),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_LVS7),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_NCP_0),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_NCP_1),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_CXO_BUFFERS),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_USB_OTG_SWITCH),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_HDMI_SWITCH),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_QDSS_CLK),
+ MSM_RPM_STATUS_ID_MAP(8930, PM8917_VOLTAGE_CORNER),
+ },
+ .target_ctrl_id = {
+ MSM_RPM_CTRL_MAP(8930, VERSION_MAJOR),
+ MSM_RPM_CTRL_MAP(8930, VERSION_MINOR),
+ MSM_RPM_CTRL_MAP(8930, VERSION_BUILD),
+ MSM_RPM_CTRL_MAP(8930, REQ_CTX_0),
+ MSM_RPM_CTRL_MAP(8930, REQ_SEL_0),
+ MSM_RPM_CTRL_MAP(8930, ACK_CTX_0),
+ MSM_RPM_CTRL_MAP(8930, ACK_SEL_0),
+ },
+ .sel_invalidate = MSM_RPM_8930_SEL_INVALIDATE,
+ .sel_notification = MSM_RPM_8930_SEL_NOTIFICATION,
+ .sel_last = MSM_RPM_8930_SEL_LAST,
+ .ver = {3, 0, 0},
+};
struct platform_device msm8930_rpm_device = {
.name = "msm_rpm",
.id = -1,
@@ -386,9 +640,16 @@
.id = -1,
};
+static struct acpuclk_platform_data acpuclk_8930_pdata = {
+ .uses_pm8917 = false,
+};
+
struct platform_device msm8930_device_acpuclk = {
.name = "acpuclk-8930",
.id = -1,
+ .dev = {
+ .platform_data = &acpuclk_8930_pdata,
+ },
};
struct platform_device msm8930aa_device_acpuclk = {
diff --git a/arch/arm/mach-msm/devices-msm7x01a.c b/arch/arm/mach-msm/devices-msm7x01a.c
index 1b9eb86..6472fc4 100644
--- a/arch/arm/mach-msm/devices-msm7x01a.c
+++ b/arch/arm/mach-msm/devices-msm7x01a.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2008 Google, Inc.
- * Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -648,7 +648,7 @@
.resource = msm_ebi2_lcd_resources,
};
-static struct platform_device msm_lcdc_device = {
+struct platform_device msm_lcdc_device = {
.name = "lcdc",
.id = 0,
};
diff --git a/arch/arm/mach-msm/devices-msm7x25.c b/arch/arm/mach-msm/devices-msm7x25.c
index 99b2960..6f89007 100644
--- a/arch/arm/mach-msm/devices-msm7x25.c
+++ b/arch/arm/mach-msm/devices-msm7x25.c
@@ -777,7 +777,7 @@
.resource = msm_ebi2_lcd_resources,
};
-static struct platform_device msm_lcdc_device = {
+struct platform_device msm_lcdc_device = {
.name = "lcdc",
.id = 0,
};
diff --git a/arch/arm/mach-msm/devices-msm7x27.c b/arch/arm/mach-msm/devices-msm7x27.c
index 82c5eed..f869965 100644
--- a/arch/arm/mach-msm/devices-msm7x27.c
+++ b/arch/arm/mach-msm/devices-msm7x27.c
@@ -715,7 +715,7 @@
.resource = msm_ebi2_lcd_resources,
};
-static struct platform_device msm_lcdc_device = {
+struct platform_device msm_lcdc_device = {
.name = "lcdc",
.id = 0,
};
diff --git a/arch/arm/mach-msm/devices-msm7x27a.c b/arch/arm/mach-msm/devices-msm7x27a.c
index 0331919..951177c 100644
--- a/arch/arm/mach-msm/devices-msm7x27a.c
+++ b/arch/arm/mach-msm/devices-msm7x27a.c
@@ -509,6 +509,19 @@
}
+static struct msm_pm_cpr_ops msm8625_pm_cpr_ops = {
+ .cpr_suspend = msm_cpr_pm_suspend,
+ .cpr_resume = msm_cpr_pm_resume,
+};
+
+void __init msm_pm_register_cpr_ops(void)
+{
+ /* CPR presents on revision >= v2.0 chipsets */
+ if (cpu_is_msm8625() &&
+ SOCINFO_VERSION_MAJOR(socinfo_get_version()) >= 2)
+ msm_pm_set_cpr_ops(&msm8625_pm_cpr_ops);
+}
+
#define MSM_SDC1_BASE 0xA0400000
#define MSM_SDC2_BASE 0xA0500000
#define MSM_SDC3_BASE 0xA0600000
@@ -835,7 +848,7 @@
.resource = msm_mdp_resources,
};
-static struct platform_device msm_lcdc_device = {
+struct platform_device msm_lcdc_device = {
.name = "lcdc",
.id = 0,
};
@@ -1592,6 +1605,47 @@
},
};
+enum {
+ MSM8625,
+ MSM8625A,
+ MSM8625AB,
+};
+
+static int __init msm8625_cpu_id(void)
+{
+ int raw_id, cpu;
+
+ raw_id = socinfo_get_raw_id();
+ switch (raw_id) {
+ /* Part number for 1GHz part */
+ case 0x770:
+ case 0x771:
+ case 0x77C:
+ case 0x780:
+ case 0x8D0:
+ cpu = MSM8625;
+ break;
+ /* Part number for 1.2GHz part */
+ case 0x773:
+ case 0x774:
+ case 0x781:
+ case 0x8D1:
+ cpu = MSM8625A;
+ break;
+ case 0x775:
+ case 0x776:
+ case 0x77D:
+ case 0x782:
+ case 0x8D2:
+ cpu = MSM8625AB;
+ break;
+ default:
+ pr_err("Invalid Raw ID\n");
+ return -ENODEV;
+ }
+ return cpu;
+}
+
static struct resource cpr_resources[] = {
{
.start = MSM8625_INT_CPR_IRQ0,
@@ -1608,12 +1662,12 @@
* These are various Vdd levels supported by PMIC
*/
static uint32_t msm_c2_pmic_mv[] __initdata = {
- 1300, 12875 / 10, 1275, 12625 / 10, 1250,
- 12375 / 10, 1225, 12125 / 10, 1200, 11875 / 10,
- 1175, 11625 / 10, 1150, 11375 / 10, 1125,
- 11125 / 10, 1100, 10875 / 10, 1075, 10625 / 10,
- 1050, 10375 / 10, 1025, 10125 / 10, 0, 0, 0, 0,
- 0, 0, 0, 1000,
+ 1300000, 1287500, 1275000, 1262500, 1250000,
+ 1237500, 1225000, 1212500, 1200000, 1187500,
+ 1175000, 1162500, 1150000, 1137500, 1125000,
+ 1112500, 1100000, 1087500, 1075000, 1062500,
+ 1050000, 1037500, 1025000, 1012500, 0, 0, 0,
+ 0, 0, 0, 0, 1000,
};
/**
@@ -1633,10 +1687,10 @@
},
.ring_osc = 0,
.step_quot = ~0,
- .tgt_volt_offset = 1,
- .Vmax = 1200,
- .Vmin = 1000,
- .calibrated_mV = 1100,
+ .tgt_volt_offset = 0,
+ .Vmax = 1200000,
+ .Vmin = 1000000,
+ .calibrated_uV = 1100000,
},
[TURBO_MODE] = {
.ring_osc_data = {
@@ -1651,23 +1705,47 @@
},
.ring_osc = 0,
.step_quot = ~0,
- .tgt_volt_offset = 1,
- .Vmax = 1350,
- .Vmin = 1250,
- .calibrated_mV = 1300,
+ .tgt_volt_offset = 0,
+ .Vmax = 1350000,
+ .Vmin = 1150000,
+ .calibrated_uV = 1300000,
},
};
struct msm_cpr_vp_data vp_data = {
- .min_volt = 1000,
- .max_volt = 1350,
- .default_volt = 1300,
- .step_size = (12500 / 1000),
+ .min_volt = 1000000,
+ .max_volt = 1350000,
+ .default_volt = 1300000,
+ .step_size = 12500,
};
+static uint32_t
+msm_cpr_get_quot(uint32_t max_quot, uint32_t max_freq, uint32_t new_freq)
+{
+ uint32_t quot;
+
+ /* This formula is as per chip characterization data */
+ quot = max_quot - ((max_freq / 10 - new_freq / 10) * 9) + 20;
+
+ return quot;
+}
+
+static void msm_cpr_clk_enable(void)
+{
+ uint32_t reg_val;
+
+ /* Select TCXO (19.2MHz) as clock source */
+ reg_val = readl_relaxed(A11S_TEST_BUS_SEL_ADDR);
+ reg_val |= RBCPR_CLK_MUX_SEL;
+ writel_relaxed(reg_val, A11S_TEST_BUS_SEL_ADDR);
+
+ /* Get CPR out of reset */
+ writel_relaxed(0x1, RBCPR_SW_RESET_N);
+}
+
static struct msm_cpr_config msm_cpr_pdata = {
.ref_clk_khz = 19200,
- .delay_us = 10000,
+ .delay_us = 25000,
.irq_line = 0,
.cpr_mode_data = msm_cpr_mode_data,
.tgt_count_div_N = 1,
@@ -1678,8 +1756,12 @@
.dn_threshold = 2,
.up_margin = 0,
.dn_margin = 0,
- .nom_freq_limit = 1008000,
+ .max_nom_freq = 700800,
+ .max_freq = 1401600,
+ .max_quot = 0,
.vp_data = &vp_data,
+ .get_quot = msm_cpr_get_quot,
+ .clk_enable = msm_cpr_clk_enable,
};
static struct platform_device msm8625_device_cpr = {
@@ -1701,7 +1783,6 @@
{
struct cpr_info_type *cpr_info = NULL;
uint8_t ring_osc = 0;
- uint32_t reg_val;
cpr_info = kzalloc(sizeof(struct cpr_info_type), GFP_KERNEL);
if (!cpr_info) {
@@ -1728,35 +1809,32 @@
msm_cpr_mode_data[TURBO_MODE].ring_osc_data[ring_osc].gcnt = 19;
msm_cpr_mode_data[NORMAL_MODE].ring_osc_data[ring_osc].gcnt = 19;
- /* The multiplier and offset are as per PTE data */
- msm_cpr_mode_data[TURBO_MODE].ring_osc_data[ring_osc].target_count =
- cpr_info->turbo_quot * 10 + 440;
- msm_cpr_mode_data[NORMAL_MODE].ring_osc_data[ring_osc].target_count =
- cpr_info->turbo_quot / msm_cpr_pdata.tgt_count_div_N;
+ /**
+ * The scaling factor and offset are as per chip characterization data
+ * This formula is used since available fuse bits in the chip are not
+ * enough to represent the value of maximum quot
+ */
+ msm_cpr_pdata.max_quot = cpr_info->turbo_quot * 10 + 610;
/**
* Bits 4:0 of pvs_fuse provide mapping to the safe boot up voltage.
* Boot up mode is by default Turbo.
*/
- msm_cpr_mode_data[TURBO_MODE].calibrated_mV =
+ msm_cpr_mode_data[TURBO_MODE].calibrated_uV =
msm_c2_pmic_mv[cpr_info->pvs_fuse & 0x1F];
- /* TODO: Store the tgt_volt_offset values for the modes from PTE */
-
-
pr_debug("%s: cpr: ring_osc: 0x%x\n", __func__,
msm_cpr_mode_data[TURBO_MODE].ring_osc);
pr_debug("%s: cpr: turbo_quot: 0x%x\n", __func__, cpr_info->turbo_quot);
pr_debug("%s: cpr: pvs_fuse: 0x%x\n", __func__, cpr_info->pvs_fuse);
kfree(cpr_info);
- /* Select TCXO (19.2MHz) as clock source */
- reg_val = readl_relaxed(A11S_TEST_BUS_SEL_ADDR);
- reg_val |= RBCPR_CLK_MUX_SEL;
- writel_relaxed(reg_val, A11S_TEST_BUS_SEL_ADDR);
+ if (msm8625_cpu_id() == MSM8625A)
+ msm_cpr_pdata.max_freq = 1209600;
+ else if (msm8625_cpu_id() == MSM8625)
+ msm_cpr_pdata.max_freq = 1008000;
- /* Get CPR out of reset */
- writel_relaxed(0x1, RBCPR_SW_RESET_N);
+ msm_cpr_clk_enable();
platform_device_register(&msm8625_vp_device);
platform_device_register(&msm8625_device_cpr);
@@ -1828,47 +1906,6 @@
.table = msm_clock_8625_dummy,
.size = ARRAY_SIZE(msm_clock_8625_dummy),
};
-enum {
- MSM8625,
- MSM8625A,
- MSM8625AB,
-};
-
-static int __init msm8625_cpu_id(void)
-{
- int raw_id, cpu;
-
- raw_id = socinfo_get_raw_id();
- switch (raw_id) {
- /* Part number for 1GHz part */
- case 0x770:
- case 0x771:
- case 0x77C:
- case 0x780:
- case 0x8D0:
- cpu = MSM8625;
- break;
- /* Part number for 1.2GHz part */
- case 0x773:
- case 0x774:
- case 0x779:
- case 0x781:
- case 0x8D1:
- cpu = MSM8625A;
- break;
- case 0x775:
- case 0x776:
- case 0x77D:
- case 0x782:
- case 0x8D2:
- cpu = MSM8625AB;
- break;
- default:
- pr_err("Invalid Raw ID\n");
- return -ENODEV;
- }
- return cpu;
-}
int __init msm7x2x_misc_init(void)
{
diff --git a/arch/arm/mach-msm/devices-msm7x2xa.h b/arch/arm/mach-msm/devices-msm7x2xa.h
index 8febe26..8b59b14 100644
--- a/arch/arm/mach-msm/devices-msm7x2xa.h
+++ b/arch/arm/mach-msm/devices-msm7x2xa.h
@@ -31,6 +31,7 @@
void __init msm8625_map_io(void);
int ar600x_wlan_power(bool on);
void __init msm8x25_spm_device_init(void);
+void __init msm_pm_register_cpr_ops(void);
void __init msm8x25_kgsl_3d0_init(void);
void __iomem *core1_reset_base(void);
extern void setup_mm_for_reboot(void);
diff --git a/arch/arm/mach-msm/devices-msm7x30.c b/arch/arm/mach-msm/devices-msm7x30.c
index 45486f4..c12c0f7 100644
--- a/arch/arm/mach-msm/devices-msm7x30.c
+++ b/arch/arm/mach-msm/devices-msm7x30.c
@@ -1092,7 +1092,7 @@
.resource = msm_ebi2_lcd_resources,
};
-static struct platform_device msm_lcdc_device = {
+struct platform_device msm_lcdc_device = {
.name = "lcdc",
.id = 0,
};
diff --git a/arch/arm/mach-msm/devices-msm8x60.c b/arch/arm/mach-msm/devices-msm8x60.c
index 57d7f08..d086753 100644
--- a/arch/arm/mach-msm/devices-msm8x60.c
+++ b/arch/arm/mach-msm/devices-msm8x60.c
@@ -1733,7 +1733,7 @@
__func__, ret);
}
-static struct platform_device msm_lcdc_device = {
+struct platform_device msm_lcdc_device = {
.name = "lcdc",
.id = 0,
};
diff --git a/arch/arm/mach-msm/devices-qsd8x50.c b/arch/arm/mach-msm/devices-qsd8x50.c
index 03ffa2f..626367e 100644
--- a/arch/arm/mach-msm/devices-qsd8x50.c
+++ b/arch/arm/mach-msm/devices-qsd8x50.c
@@ -757,7 +757,7 @@
.resource = msm_ebi2_lcd_resources,
};
-static struct platform_device msm_lcdc_device = {
+struct platform_device msm_lcdc_device = {
.name = "lcdc",
.id = 0,
};
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index 3587672..4d338b1 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -55,6 +55,7 @@
extern struct platform_device msm_device_uart_dm6;
extern struct platform_device msm_device_uart_dm8;
extern struct platform_device msm_device_uart_dm9;
+extern struct platform_device mpq8064_device_uartdm_gsbi6;
extern struct platform_device msm8960_device_uart_gsbi2;
extern struct platform_device msm8960_device_uart_gsbi5;
@@ -312,6 +313,7 @@
extern struct platform_device msm_mipi_dsi1_device;
extern struct platform_device mipi_dsi_device;
+extern struct platform_device msm_lcdc_device;
extern struct platform_device msm_lvds_device;
extern struct platform_device msm_ebi2_lcdc_device;
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index d8f8480..aa33a0b 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -502,6 +502,7 @@
uint32_t gpio_mhl_power;
/* GPIO no. for hdmi-mhl mux */
uint32_t gpio_hdmi_mhl_mux;
+ bool mhl_enabled;
};
struct msm_i2c_platform_data {
@@ -515,6 +516,7 @@
int aux_dat;
int src_clk_rate;
int use_gsbi_shared_mode;
+ int keep_ahb_clk_on;
void (*msm_i2c_config_gpio)(int iface, int config_type);
};
diff --git a/arch/arm/mach-msm/include/mach/camera.h b/arch/arm/mach-msm/include/mach/camera.h
index 0867c1d..6298d94 100644
--- a/arch/arm/mach-msm/include/mach/camera.h
+++ b/arch/arm/mach-msm/include/mach/camera.h
@@ -700,4 +700,6 @@
(struct msm_camera_sensor_info *sinfo, int gpio_en);
int msm_camera_request_gpio_table
(struct msm_camera_sensor_info *sinfo, int gpio_en);
+void msm_camera_bus_scale_cfg(uint32_t bus_perf_client,
+ enum msm_bus_perf_setting perf_setting);
#endif
diff --git a/arch/arm/mach-msm/include/mach/dma.h b/arch/arm/mach-msm/include/mach/dma.h
index 6a389de..988b249 100644
--- a/arch/arm/mach-msm/include/mach/dma.h
+++ b/arch/arm/mach-msm/include/mach/dma.h
@@ -272,6 +272,12 @@
#define DMOV8064_TSIF_CHAN 2
#define DMOV8064_TSIF_CRCI 1
+/* channels for MPQ8064 */
+#define DMOV_MPQ8064_HSUART_GSBI6_TX_CHAN 7
+#define DMOV_MPQ8064_HSUART_GSBI6_TX_CRCI 6
+
+#define DMOV_MPQ8064_HSUART_GSBI6_RX_CHAN 6
+#define DMOV_MPQ8064_HSUART_GSBI6_RX_CRCI 11
/* no client rate control ifc (eg, ram) */
#define DMOV_NONE_CRCI 0
diff --git a/arch/arm/mach-msm/include/mach/msm_smd.h b/arch/arm/mach-msm/include/mach/msm_smd.h
index 97c03e7..0c452f8 100644
--- a/arch/arm/mach-msm/include/mach/msm_smd.h
+++ b/arch/arm/mach-msm/include/mach/msm_smd.h
@@ -309,6 +309,24 @@
*/
int smd_is_pkt_avail(smd_channel_t *ch);
+/**
+ * smd_module_init_notifier_register() - Register a smd module
+ * init notifier block
+ * @nb: Notifier block to be registered
+ *
+ * In order to mark the dependency on SMD Driver module initialization
+ * register a notifier using this API. Once the smd module_init is
+ * done, notification will be passed to the registered module.
+ */
+int smd_module_init_notifier_register(struct notifier_block *nb);
+
+/**
+ * smd_module_init_notifier_register() - Unregister a smd module
+ * init notifier block
+ * @nb: Notifier block to be registered
+ */
+int smd_module_init_notifier_unregister(struct notifier_block *nb);
+
/*
* SMD initialization function that registers for a SMD platform driver.
*
@@ -438,6 +456,16 @@
return -ENODEV;
}
+static inline int smd_module_init_notifier_register(struct notifier_block *nb)
+{
+ return -ENODEV;
+}
+
+static inline int smd_module_init_notifier_unregister(struct notifier_block *nb)
+{
+ return -ENODEV;
+}
+
static inline int __init msm_smd_init(void)
{
return 0;
diff --git a/arch/arm/mach-msm/include/mach/msm_smsm.h b/arch/arm/mach-msm/include/mach/msm_smsm.h
index e19f39d..133a1b3 100644
--- a/arch/arm/mach-msm/include/mach/msm_smsm.h
+++ b/arch/arm/mach-msm/include/mach/msm_smsm.h
@@ -133,8 +133,6 @@
void *data);
int smsm_state_cb_deregister(uint32_t smsm_entry, uint32_t mask,
void (*notify)(void *, uint32_t, uint32_t), void *data);
-int smsm_driver_state_notifier_register(struct notifier_block *nb);
-int smsm_driver_state_notifier_unregister(struct notifier_block *nb);
void smsm_print_sleep_info(uint32_t sleep_delay, uint32_t sleep_limit,
uint32_t irq_mask, uint32_t wakeup_reason, uint32_t pending_irqs);
void smsm_reset_modem(unsigned mode);
diff --git a/arch/arm/mach-msm/include/mach/msm_tspp.h b/arch/arm/mach-msm/include/mach/msm_tspp.h
index 6912f0c..48be504 100644
--- a/arch/arm/mach-msm/include/mach/msm_tspp.h
+++ b/arch/arm/mach-msm/include/mach/msm_tspp.h
@@ -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
@@ -13,6 +13,8 @@
#ifndef _MSM_TSPP_H_
#define _MSM_TSPP_H_
+#include <linux/tspp.h> /* tspp_source */
+
struct msm_tspp_platform_data {
int num_gpios;
const struct msm_gpio *gpios;
@@ -20,5 +22,34 @@
const char *tsif_ref_clk;
};
+struct tspp_data_descriptor {
+ void *virt_base; /* logical address of the actual data */
+ u32 phys_base; /* physical address of the actual data */
+ int size; /* size of buffer in bytes */
+ int id; /* unique identifier */
+ void *user; /* user-defined data */
+};
+
+typedef void (tspp_notifier)(int channel, void *user);
+typedef void* (tspp_allocator)(int channel, int size,
+ u32 *phys_base, void *user);
+
+/* Kernel API functions */
+int tspp_open_stream(u32 dev, u32 channel_id, enum tspp_source src,
+ enum tspp_tsif_mode mode);
+int tspp_close_stream(u32 dev, u32 channel_id);
+int tspp_open_channel(u32 dev, u32 channel_id);
+int tspp_close_channel(u32 dev, u32 channel_id);
+int tspp_add_filter(u32 dev, u32 channel_id, struct tspp_filter *filter);
+int tspp_remove_filter(u32 dev, u32 channel_id, struct tspp_filter *filter);
+int tspp_set_key(u32 dev, u32 channel_id, struct tspp_key *key);
+int tspp_register_notification(u32 dev, u32 channel, tspp_notifier *notify,
+ void *data, u32 timer_ms);
+int tspp_unregister_notification(u32 dev, u32 channel);
+const struct tspp_data_descriptor *tspp_get_buffer(u32 dev, u32 channel);
+int tspp_release_buffer(u32 dev, u32 channel, u32 descriptor_id);
+int tspp_allocate_buffers(u32 dev, u32 channel_id, u32 count,
+ u32 size, u32 int_freq, tspp_allocator *alloc, void *user);
+
#endif /* _MSM_TSPP_H_ */
diff --git a/arch/arm/mach-msm/include/mach/ocmem_priv.h b/arch/arm/mach-msm/include/mach/ocmem_priv.h
index 737db0b..47f9b10 100644
--- a/arch/arm/mach-msm/include/mach/ocmem_priv.h
+++ b/arch/arm/mach-msm/include/mach/ocmem_priv.h
@@ -10,8 +10,8 @@
* GNU General Public License for more details.
*/
-#ifndef _ARCH_ARM_MACH_MSM_OCMEM_CORE_H
-#define _ARCH_ARM_MACH_MSM_OCMEM_CORE_H
+#ifndef _ARCH_ARM_MACH_MSM_OCMEM_PRIV_H
+#define _ARCH_ARM_MACH_MSM_OCMEM_PRIV_H
/** All interfaces in this header should only be used by OCMEM driver
* Client drivers should use wrappers available in ocmem.h
@@ -36,6 +36,29 @@
int (*free) (struct ocmem_zone *, unsigned long, unsigned long);
};
+/* OCMEM Zone specific counters */
+/* Must be in sync with zstat_names */
+enum ocmem_zstat_item {
+ NR_REQUESTS = 0x0,
+ NR_SYNC_ALLOCATIONS,
+ NR_RANGE_ALLOCATIONS,
+ NR_ASYNC_ALLOCATIONS,
+ NR_ALLOCATION_FAILS,
+ NR_GROWTHS,
+ NR_FREES,
+ NR_SHRINKS,
+ NR_MAPS,
+ NR_MAP_FAILS,
+ NR_UNMAPS,
+ NR_UNMAP_FAILS,
+ NR_TRANSFERS_TO_OCMEM,
+ NR_TRANSFERS_TO_DDR,
+ NR_TRANSFER_FAILS,
+ NR_EVICTIONS,
+ NR_RESTORES,
+ NR_OCMEM_ZSTAT_ITEMS,
+};
+
struct ocmem_zone {
bool active;
int owner;
@@ -47,6 +70,7 @@
unsigned long z_head;
unsigned long z_tail;
unsigned long z_free;
+ atomic_long_t z_stat[NR_OCMEM_ZSTAT_ITEMS];
struct gen_pool *z_pool;
struct ocmem_zone_ops *z_ops;
};
@@ -82,6 +106,7 @@
void __iomem *reg_base;
void __iomem *br_base;
void __iomem *dm_base;
+ struct dentry *debug_node;
unsigned nr_regions;
unsigned nr_macros;
unsigned nr_ports;
@@ -143,7 +168,9 @@
struct ocmem_handle *req_to_handle(struct ocmem_req *);
int ocmem_read(void *);
int ocmem_write(unsigned long, void *);
-
+void inc_ocmem_stat(struct ocmem_zone *, enum ocmem_zstat_item);
+unsigned long get_ocmem_stat(struct ocmem_zone *z,
+ enum ocmem_zstat_item item);
struct ocmem_zone *get_zone(unsigned);
int zone_active(int);
unsigned long offset_to_phys(unsigned long);
@@ -159,7 +186,7 @@
int check_id(int);
int dispatch_notification(int, enum ocmem_notif_type, struct ocmem_buf *);
-int ocmem_sched_init(void);
+int ocmem_sched_init(struct platform_device *);
int ocmem_rdm_init(struct platform_device *);
int ocmem_core_init(struct platform_device *);
int process_allocate(int, struct ocmem_handle *, unsigned long, unsigned long,
diff --git a/arch/arm/mach-msm/include/mach/rpm-8930.h b/arch/arm/mach-msm/include/mach/rpm-8930.h
index 6fd9cf4..4ac9192 100644
--- a/arch/arm/mach-msm/include/mach/rpm-8930.h
+++ b/arch/arm/mach-msm/include/mach/rpm-8930.h
@@ -59,6 +59,8 @@
MSM_RPM_8930_SEL_MMSS_FABRIC_CFG_CLKMOD = 27,
MSM_RPM_8930_SEL_MMSS_FABRIC_CFG_IOCTL = 28,
MSM_RPM_8930_SEL_MM_FABRIC_ARB = 29,
+
+ /* PMIC 8038 */
MSM_RPM_8930_SEL_PM8038_S1 = 30,
MSM_RPM_8930_SEL_PM8038_S2 = 31,
MSM_RPM_8930_SEL_PM8038_S3 = 32,
@@ -96,12 +98,65 @@
MSM_RPM_8930_SEL_PM8038_CLK2 = 64,
MSM_RPM_8930_SEL_PM8038_LVS1 = 65,
MSM_RPM_8930_SEL_PM8038_LVS2 = 66,
+
+ /* PMIC 8917 */
+ MSM_RPM_8930_SEL_PM8917_S1 = 30,
+ MSM_RPM_8930_SEL_PM8917_S2 = 31,
+ MSM_RPM_8930_SEL_PM8917_S3 = 32,
+ MSM_RPM_8930_SEL_PM8917_S4 = 33,
+ MSM_RPM_8930_SEL_PM8917_S5 = 34,
+ MSM_RPM_8930_SEL_PM8917_S6 = 35,
+ MSM_RPM_8930_SEL_PM8917_S7 = 36,
+ MSM_RPM_8930_SEL_PM8917_S8 = 37,
+ MSM_RPM_8930_SEL_PM8917_L1 = 38,
+ MSM_RPM_8930_SEL_PM8917_L2 = 39,
+ MSM_RPM_8930_SEL_PM8917_L3 = 40,
+ MSM_RPM_8930_SEL_PM8917_L4 = 41,
+ MSM_RPM_8930_SEL_PM8917_L5 = 42,
+ MSM_RPM_8930_SEL_PM8917_L6 = 43,
+ MSM_RPM_8930_SEL_PM8917_L7 = 44,
+ MSM_RPM_8930_SEL_PM8917_L8 = 45,
+ MSM_RPM_8930_SEL_PM8917_L9 = 46,
+ MSM_RPM_8930_SEL_PM8917_L10 = 47,
+ MSM_RPM_8930_SEL_PM8917_L11 = 48,
+ MSM_RPM_8930_SEL_PM8917_L12 = 49,
+ MSM_RPM_8930_SEL_PM8917_L14 = 50,
+ MSM_RPM_8930_SEL_PM8917_L15 = 51,
+ MSM_RPM_8930_SEL_PM8917_L16 = 52,
+ MSM_RPM_8930_SEL_PM8917_L17 = 53,
+ MSM_RPM_8930_SEL_PM8917_L18 = 54,
+ MSM_RPM_8930_SEL_PM8917_L21 = 55,
+ MSM_RPM_8930_SEL_PM8917_L22 = 56,
+ MSM_RPM_8930_SEL_PM8917_L23 = 57,
+ MSM_RPM_8930_SEL_PM8917_L24 = 58,
+ MSM_RPM_8930_SEL_PM8917_L25 = 59,
+ MSM_RPM_8930_SEL_PM8917_L26 = 60,
+ MSM_RPM_8930_SEL_PM8917_L27 = 61,
+ MSM_RPM_8930_SEL_PM8917_L28 = 62,
+ MSM_RPM_8930_SEL_PM8917_L29 = 63,
+ MSM_RPM_8930_SEL_PM8917_L30 = 64,
+ MSM_RPM_8930_SEL_PM8917_L31 = 65,
+ MSM_RPM_8930_SEL_PM8917_L32 = 66,
+ MSM_RPM_8930_SEL_PM8917_L33 = 67,
+ MSM_RPM_8930_SEL_PM8917_L34 = 68,
+ MSM_RPM_8930_SEL_PM8917_L35 = 69,
+ MSM_RPM_8930_SEL_PM8917_L36 = 70,
+ MSM_RPM_8930_SEL_PM8917_CLK1 = 71,
+ MSM_RPM_8930_SEL_PM8917_CLK2 = 72,
+ MSM_RPM_8930_SEL_PM8917_LVS1 = 73,
+ MSM_RPM_8930_SEL_PM8917_LVS3 = 74,
+ MSM_RPM_8930_SEL_PM8917_LVS4 = 75,
+ MSM_RPM_8930_SEL_PM8917_LVS5 = 76,
+ MSM_RPM_8930_SEL_PM8917_LVS6 = 77,
+ MSM_RPM_8930_SEL_PM8917_LVS7 = 78,
+
MSM_RPM_8930_SEL_NCP = 80,
MSM_RPM_8930_SEL_CXO_BUFFERS = 81,
MSM_RPM_8930_SEL_USB_OTG_SWITCH = 82,
MSM_RPM_8930_SEL_HDMI_SWITCH = 83,
MSM_RPM_8930_SEL_DDR_DMM = 84,
MSM_RPM_8930_SEL_VOLTAGE_CORNER = 87,
+
MSM_RPM_8930_SEL_LAST = MSM_RPM_8930_SEL_VOLTAGE_CORNER,
};
@@ -163,6 +218,7 @@
MSM_RPM_8930_ID_MM_FABRIC_ARB_10 =
MSM_RPM_8930_ID_MM_FABRIC_ARB_0 + 10,
+ /* PMIC 8038 */
MSM_RPM_8930_ID_PM8038_S1_0 = 90,
MSM_RPM_8930_ID_PM8038_S1_1 = 91,
MSM_RPM_8930_ID_PM8038_S2_0 = 92,
@@ -235,13 +291,109 @@
MSM_RPM_8930_ID_PM8038_CLK2_1 = 159,
MSM_RPM_8930_ID_PM8038_LVS1 = 160,
MSM_RPM_8930_ID_PM8038_LVS2 = 161,
- MSM_RPM_8930_ID_NCP_0 = 162,
- MSM_RPM_8930_ID_NCP_1 = 163,
- MSM_RPM_8930_ID_CXO_BUFFERS = 164,
- MSM_RPM_8930_ID_USB_OTG_SWITCH = 165,
- MSM_RPM_8930_ID_HDMI_SWITCH = 166,
- MSM_RPM_8930_ID_QDSS_CLK = 167,
- MSM_RPM_8930_ID_VOLTAGE_CORNER = 168,
+
+ /* PMIC 8917 */
+ MSM_RPM_8930_ID_PM8917_S1_0 = 90,
+ MSM_RPM_8930_ID_PM8917_S1_1 = 91,
+ MSM_RPM_8930_ID_PM8917_S2_0 = 92,
+ MSM_RPM_8930_ID_PM8917_S2_1 = 93,
+ MSM_RPM_8930_ID_PM8917_S3_0 = 94,
+ MSM_RPM_8930_ID_PM8917_S3_1 = 95,
+ MSM_RPM_8930_ID_PM8917_S4_0 = 96,
+ MSM_RPM_8930_ID_PM8917_S4_1 = 97,
+ MSM_RPM_8930_ID_PM8917_S5_0 = 98,
+ MSM_RPM_8930_ID_PM8917_S5_1 = 99,
+ MSM_RPM_8930_ID_PM8917_S6_0 = 100,
+ MSM_RPM_8930_ID_PM8917_S6_1 = 101,
+ MSM_RPM_8930_ID_PM8917_S7_0 = 102,
+ MSM_RPM_8930_ID_PM8917_S7_1 = 103,
+ MSM_RPM_8930_ID_PM8917_S8_0 = 104,
+ MSM_RPM_8930_ID_PM8917_S8_1 = 105,
+ MSM_RPM_8930_ID_PM8917_L1_0 = 106,
+ MSM_RPM_8930_ID_PM8917_L1_1 = 107,
+ MSM_RPM_8930_ID_PM8917_L2_0 = 108,
+ MSM_RPM_8930_ID_PM8917_L2_1 = 109,
+ MSM_RPM_8930_ID_PM8917_L3_0 = 110,
+ MSM_RPM_8930_ID_PM8917_L3_1 = 111,
+ MSM_RPM_8930_ID_PM8917_L4_0 = 112,
+ MSM_RPM_8930_ID_PM8917_L4_1 = 113,
+ MSM_RPM_8930_ID_PM8917_L5_0 = 114,
+ MSM_RPM_8930_ID_PM8917_L5_1 = 115,
+ MSM_RPM_8930_ID_PM8917_L6_0 = 116,
+ MSM_RPM_8930_ID_PM8917_L6_1 = 117,
+ MSM_RPM_8930_ID_PM8917_L7_0 = 118,
+ MSM_RPM_8930_ID_PM8917_L7_1 = 119,
+ MSM_RPM_8930_ID_PM8917_L8_0 = 120,
+ MSM_RPM_8930_ID_PM8917_L8_1 = 121,
+ MSM_RPM_8930_ID_PM8917_L9_0 = 122,
+ MSM_RPM_8930_ID_PM8917_L9_1 = 123,
+ MSM_RPM_8930_ID_PM8917_L10_0 = 124,
+ MSM_RPM_8930_ID_PM8917_L10_1 = 125,
+ MSM_RPM_8930_ID_PM8917_L11_0 = 126,
+ MSM_RPM_8930_ID_PM8917_L11_1 = 127,
+ MSM_RPM_8930_ID_PM8917_L12_0 = 128,
+ MSM_RPM_8930_ID_PM8917_L12_1 = 129,
+ MSM_RPM_8930_ID_PM8917_L14_0 = 130,
+ MSM_RPM_8930_ID_PM8917_L14_1 = 131,
+ MSM_RPM_8930_ID_PM8917_L15_0 = 132,
+ MSM_RPM_8930_ID_PM8917_L15_1 = 133,
+ MSM_RPM_8930_ID_PM8917_L16_0 = 134,
+ MSM_RPM_8930_ID_PM8917_L16_1 = 135,
+ MSM_RPM_8930_ID_PM8917_L17_0 = 136,
+ MSM_RPM_8930_ID_PM8917_L17_1 = 137,
+ MSM_RPM_8930_ID_PM8917_L18_0 = 138,
+ MSM_RPM_8930_ID_PM8917_L18_1 = 139,
+ MSM_RPM_8930_ID_PM8917_L21_0 = 140,
+ MSM_RPM_8930_ID_PM8917_L21_1 = 141,
+ MSM_RPM_8930_ID_PM8917_L22_0 = 142,
+ MSM_RPM_8930_ID_PM8917_L22_1 = 143,
+ MSM_RPM_8930_ID_PM8917_L23_0 = 144,
+ MSM_RPM_8930_ID_PM8917_L23_1 = 145,
+ MSM_RPM_8930_ID_PM8917_L24_0 = 146,
+ MSM_RPM_8930_ID_PM8917_L24_1 = 147,
+ MSM_RPM_8930_ID_PM8917_L25_0 = 148,
+ MSM_RPM_8930_ID_PM8917_L25_1 = 149,
+ MSM_RPM_8930_ID_PM8917_L26_0 = 150,
+ MSM_RPM_8930_ID_PM8917_L26_1 = 151,
+ MSM_RPM_8930_ID_PM8917_L27_0 = 152,
+ MSM_RPM_8930_ID_PM8917_L27_1 = 153,
+ MSM_RPM_8930_ID_PM8917_L28_0 = 154,
+ MSM_RPM_8930_ID_PM8917_L28_1 = 155,
+ MSM_RPM_8930_ID_PM8917_L29_0 = 156,
+ MSM_RPM_8930_ID_PM8917_L29_1 = 157,
+ MSM_RPM_8930_ID_PM8917_L30_0 = 158,
+ MSM_RPM_8930_ID_PM8917_L30_1 = 159,
+ MSM_RPM_8930_ID_PM8917_L31_0 = 160,
+ MSM_RPM_8930_ID_PM8917_L31_1 = 161,
+ MSM_RPM_8930_ID_PM8917_L32_0 = 162,
+ MSM_RPM_8930_ID_PM8917_L32_1 = 163,
+ MSM_RPM_8930_ID_PM8917_L33_0 = 164,
+ MSM_RPM_8930_ID_PM8917_L33_1 = 165,
+ MSM_RPM_8930_ID_PM8917_L34_0 = 166,
+ MSM_RPM_8930_ID_PM8917_L34_1 = 167,
+ MSM_RPM_8930_ID_PM8917_L35_0 = 168,
+ MSM_RPM_8930_ID_PM8917_L35_1 = 169,
+ MSM_RPM_8930_ID_PM8917_L36_0 = 170,
+ MSM_RPM_8930_ID_PM8917_L36_1 = 171,
+ MSM_RPM_8930_ID_PM8917_CLK1_0 = 172,
+ MSM_RPM_8930_ID_PM8917_CLK1_1 = 173,
+ MSM_RPM_8930_ID_PM8917_CLK2_0 = 174,
+ MSM_RPM_8930_ID_PM8917_CLK2_1 = 175,
+ MSM_RPM_8930_ID_PM8917_LVS1 = 176,
+ MSM_RPM_8930_ID_PM8917_LVS3 = 177,
+ MSM_RPM_8930_ID_PM8917_LVS4 = 178,
+ MSM_RPM_8930_ID_PM8917_LVS5 = 179,
+ MSM_RPM_8930_ID_PM8917_LVS6 = 180,
+ MSM_RPM_8930_ID_PM8917_LVS7 = 181,
+
+ MSM_RPM_8930_ID_NCP_0 = 182,
+ MSM_RPM_8930_ID_NCP_1 = 183,
+ MSM_RPM_8930_ID_CXO_BUFFERS = 184,
+ MSM_RPM_8930_ID_USB_OTG_SWITCH = 185,
+ MSM_RPM_8930_ID_HDMI_SWITCH = 186,
+ MSM_RPM_8930_ID_QDSS_CLK = 187,
+ MSM_RPM_8930_ID_VOLTAGE_CORNER = 188,
+
MSM_RPM_8930_ID_LAST = MSM_RPM_8930_ID_VOLTAGE_CORNER,
};
@@ -278,6 +430,8 @@
MSM_RPM_8930_STATUS_ID_MMSS_FABRIC_CFG_CLKMOD = 28,
MSM_RPM_8930_STATUS_ID_MMSS_FABRIC_CFG_IOCTL = 29,
MSM_RPM_8930_STATUS_ID_MM_FABRIC_ARB = 30,
+
+ /* PMIC 8038 */
MSM_RPM_8930_STATUS_ID_PM8038_S1_0 = 31,
MSM_RPM_8930_STATUS_ID_PM8038_S1_1 = 32,
MSM_RPM_8930_STATUS_ID_PM8038_S2_0 = 33,
@@ -346,14 +500,119 @@
MSM_RPM_8930_STATUS_ID_PM8038_CLK2_1 = 100,
MSM_RPM_8930_STATUS_ID_PM8038_LVS1 = 101,
MSM_RPM_8930_STATUS_ID_PM8038_LVS2 = 102,
- MSM_RPM_8930_STATUS_ID_NCP_0 = 103,
- MSM_RPM_8930_STATUS_ID_NCP_1 = 104,
- MSM_RPM_8930_STATUS_ID_CXO_BUFFERS = 105,
- MSM_RPM_8930_STATUS_ID_USB_OTG_SWITCH = 106,
- MSM_RPM_8930_STATUS_ID_HDMI_SWITCH = 107,
- MSM_RPM_8930_STATUS_ID_QDSS_CLK = 108,
- MSM_RPM_8930_STATUS_ID_VOLTAGE_CORNER = 109,
- MSM_RPM_8930_STATUS_ID_LAST = MSM_RPM_8930_STATUS_ID_VOLTAGE_CORNER,
+ MSM_RPM_8930_STATUS_ID_PM8038_NCP_0 = 103,
+ MSM_RPM_8930_STATUS_ID_PM8038_NCP_1 = 104,
+ MSM_RPM_8930_STATUS_ID_PM8038_CXO_BUFFERS = 105,
+ MSM_RPM_8930_STATUS_ID_PM8038_USB_OTG_SWITCH = 106,
+ MSM_RPM_8930_STATUS_ID_PM8038_HDMI_SWITCH = 107,
+ MSM_RPM_8930_STATUS_ID_PM8038_QDSS_CLK = 108,
+ MSM_RPM_8930_STATUS_ID_PM8038_VOLTAGE_CORNER = 109,
+
+ MSM_RPM_8930_STATUS_ID_PM8038_LAST
+ = MSM_RPM_8930_STATUS_ID_PM8038_VOLTAGE_CORNER,
+
+ /* PMIC 8917 */
+ MSM_RPM_8930_STATUS_ID_PM8917_S1_0 = 31,
+ MSM_RPM_8930_STATUS_ID_PM8917_S1_1 = 32,
+ MSM_RPM_8930_STATUS_ID_PM8917_S2_0 = 33,
+ MSM_RPM_8930_STATUS_ID_PM8917_S2_1 = 34,
+ MSM_RPM_8930_STATUS_ID_PM8917_S3_0 = 35,
+ MSM_RPM_8930_STATUS_ID_PM8917_S3_1 = 36,
+ MSM_RPM_8930_STATUS_ID_PM8917_S4_0 = 37,
+ MSM_RPM_8930_STATUS_ID_PM8917_S4_1 = 38,
+ MSM_RPM_8930_STATUS_ID_PM8917_S5_0 = 39,
+ MSM_RPM_8930_STATUS_ID_PM8917_S5_1 = 40,
+ MSM_RPM_8930_STATUS_ID_PM8917_S6_0 = 41,
+ MSM_RPM_8930_STATUS_ID_PM8917_S6_1 = 42,
+ MSM_RPM_8930_STATUS_ID_PM8917_S7_0 = 43,
+ MSM_RPM_8930_STATUS_ID_PM8917_S7_1 = 44,
+ MSM_RPM_8930_STATUS_ID_PM8917_S8_0 = 45,
+ MSM_RPM_8930_STATUS_ID_PM8917_S8_1 = 46,
+ MSM_RPM_8930_STATUS_ID_PM8917_L1_0 = 47,
+ MSM_RPM_8930_STATUS_ID_PM8917_L1_1 = 48,
+ MSM_RPM_8930_STATUS_ID_PM8917_L2_0 = 49,
+ MSM_RPM_8930_STATUS_ID_PM8917_L2_1 = 50,
+ MSM_RPM_8930_STATUS_ID_PM8917_L3_0 = 51,
+ MSM_RPM_8930_STATUS_ID_PM8917_L3_1 = 52,
+ MSM_RPM_8930_STATUS_ID_PM8917_L4_0 = 53,
+ MSM_RPM_8930_STATUS_ID_PM8917_L4_1 = 54,
+ MSM_RPM_8930_STATUS_ID_PM8917_L5_0 = 55,
+ MSM_RPM_8930_STATUS_ID_PM8917_L5_1 = 56,
+ MSM_RPM_8930_STATUS_ID_PM8917_L6_0 = 57,
+ MSM_RPM_8930_STATUS_ID_PM8917_L6_1 = 58,
+ MSM_RPM_8930_STATUS_ID_PM8917_L7_0 = 59,
+ MSM_RPM_8930_STATUS_ID_PM8917_L7_1 = 60,
+ MSM_RPM_8930_STATUS_ID_PM8917_L8_0 = 61,
+ MSM_RPM_8930_STATUS_ID_PM8917_L8_1 = 62,
+ MSM_RPM_8930_STATUS_ID_PM8917_L9_0 = 63,
+ MSM_RPM_8930_STATUS_ID_PM8917_L9_1 = 64,
+ MSM_RPM_8930_STATUS_ID_PM8917_L10_0 = 65,
+ MSM_RPM_8930_STATUS_ID_PM8917_L10_1 = 66,
+ MSM_RPM_8930_STATUS_ID_PM8917_L11_0 = 67,
+ MSM_RPM_8930_STATUS_ID_PM8917_L11_1 = 68,
+ MSM_RPM_8930_STATUS_ID_PM8917_L12_0 = 69,
+ MSM_RPM_8930_STATUS_ID_PM8917_L12_1 = 70,
+ MSM_RPM_8930_STATUS_ID_PM8917_L14_0 = 71,
+ MSM_RPM_8930_STATUS_ID_PM8917_L14_1 = 72,
+ MSM_RPM_8930_STATUS_ID_PM8917_L15_0 = 73,
+ MSM_RPM_8930_STATUS_ID_PM8917_L15_1 = 74,
+ MSM_RPM_8930_STATUS_ID_PM8917_L16_0 = 75,
+ MSM_RPM_8930_STATUS_ID_PM8917_L16_1 = 76,
+ MSM_RPM_8930_STATUS_ID_PM8917_L17_0 = 77,
+ MSM_RPM_8930_STATUS_ID_PM8917_L17_1 = 78,
+ MSM_RPM_8930_STATUS_ID_PM8917_L18_0 = 79,
+ MSM_RPM_8930_STATUS_ID_PM8917_L18_1 = 80,
+ MSM_RPM_8930_STATUS_ID_PM8917_L21_0 = 81,
+ MSM_RPM_8930_STATUS_ID_PM8917_L21_1 = 82,
+ MSM_RPM_8930_STATUS_ID_PM8917_L22_0 = 83,
+ MSM_RPM_8930_STATUS_ID_PM8917_L22_1 = 84,
+ MSM_RPM_8930_STATUS_ID_PM8917_L23_0 = 85,
+ MSM_RPM_8930_STATUS_ID_PM8917_L23_1 = 86,
+ MSM_RPM_8930_STATUS_ID_PM8917_L24_0 = 87,
+ MSM_RPM_8930_STATUS_ID_PM8917_L24_1 = 88,
+ MSM_RPM_8930_STATUS_ID_PM8917_L25_0 = 89,
+ MSM_RPM_8930_STATUS_ID_PM8917_L25_1 = 90,
+ MSM_RPM_8930_STATUS_ID_PM8917_L26_0 = 91,
+ MSM_RPM_8930_STATUS_ID_PM8917_L26_1 = 92,
+ MSM_RPM_8930_STATUS_ID_PM8917_L27_0 = 93,
+ MSM_RPM_8930_STATUS_ID_PM8917_L27_1 = 94,
+ MSM_RPM_8930_STATUS_ID_PM8917_L28_0 = 95,
+ MSM_RPM_8930_STATUS_ID_PM8917_L28_1 = 96,
+ MSM_RPM_8930_STATUS_ID_PM8917_L29_0 = 97,
+ MSM_RPM_8930_STATUS_ID_PM8917_L29_1 = 98,
+ MSM_RPM_8930_STATUS_ID_PM8917_L30_0 = 99,
+ MSM_RPM_8930_STATUS_ID_PM8917_L30_1 = 100,
+ MSM_RPM_8930_STATUS_ID_PM8917_L31_0 = 101,
+ MSM_RPM_8930_STATUS_ID_PM8917_L31_1 = 102,
+ MSM_RPM_8930_STATUS_ID_PM8917_L32_0 = 103,
+ MSM_RPM_8930_STATUS_ID_PM8917_L32_1 = 104,
+ MSM_RPM_8930_STATUS_ID_PM8917_L33_0 = 105,
+ MSM_RPM_8930_STATUS_ID_PM8917_L33_1 = 106,
+ MSM_RPM_8930_STATUS_ID_PM8917_L34_0 = 107,
+ MSM_RPM_8930_STATUS_ID_PM8917_L34_1 = 108,
+ MSM_RPM_8930_STATUS_ID_PM8917_L35_0 = 109,
+ MSM_RPM_8930_STATUS_ID_PM8917_L35_1 = 110,
+ MSM_RPM_8930_STATUS_ID_PM8917_L36_0 = 111,
+ MSM_RPM_8930_STATUS_ID_PM8917_L36_1 = 112,
+ MSM_RPM_8930_STATUS_ID_PM8917_CLK1_0 = 113,
+ MSM_RPM_8930_STATUS_ID_PM8917_CLK1_1 = 114,
+ MSM_RPM_8930_STATUS_ID_PM8917_CLK2_0 = 115,
+ MSM_RPM_8930_STATUS_ID_PM8917_CLK2_1 = 116,
+ MSM_RPM_8930_STATUS_ID_PM8917_LVS1 = 117,
+ MSM_RPM_8930_STATUS_ID_PM8917_LVS3 = 118,
+ MSM_RPM_8930_STATUS_ID_PM8917_LVS4 = 119,
+ MSM_RPM_8930_STATUS_ID_PM8917_LVS5 = 120,
+ MSM_RPM_8930_STATUS_ID_PM8917_LVS6 = 121,
+ MSM_RPM_8930_STATUS_ID_PM8917_LVS7 = 122,
+ MSM_RPM_8930_STATUS_ID_PM8917_NCP_0 = 123,
+ MSM_RPM_8930_STATUS_ID_PM8917_NCP_1 = 124,
+ MSM_RPM_8930_STATUS_ID_PM8917_CXO_BUFFERS = 125,
+ MSM_RPM_8930_STATUS_ID_PM8917_USB_OTG_SWITCH = 126,
+ MSM_RPM_8930_STATUS_ID_PM8917_HDMI_SWITCH = 127,
+ MSM_RPM_8930_STATUS_ID_PM8917_QDSS_CLK = 128,
+ MSM_RPM_8930_STATUS_ID_PM8917_VOLTAGE_CORNER = 129,
+ MSM_RPM_8930_STATUS_ID_PM8917_PM8917_LAST
+ = MSM_RPM_8930_STATUS_ID_PM8917_VOLTAGE_CORNER,
};
#endif /* __ARCH_ARM_MACH_MSM_RPM_8930_H */
diff --git a/arch/arm/mach-msm/include/mach/rpm-regulator-8930.h b/arch/arm/mach-msm/include/mach/rpm-regulator-8930.h
index 47056a8..f8f53f6 100644
--- a/arch/arm/mach-msm/include/mach/rpm-regulator-8930.h
+++ b/arch/arm/mach-msm/include/mach/rpm-regulator-8930.h
@@ -85,9 +85,10 @@
};
/**
- * enum rpm_vreg_id - RPM regulator ID numbers (both real and pin control)
+ * enum rpm_vreg_id_8930_pm8038 - RPM regulator ID numbers (both real and
+ * pin control) used with MSM8930 + PM8038
*/
-enum rpm_vreg_id_8930 {
+enum rpm_vreg_id_8930_pm8038 {
RPM_VREG_ID_PM8038_L1,
RPM_VREG_ID_PM8038_L2,
RPM_VREG_ID_PM8038_L3,
@@ -155,6 +156,109 @@
RPM_VREG_ID_PM8038_MAX = RPM_VREG_ID_PM8038_LVS2_PC,
};
+/**
+ * enum rpm_vreg_id_8930_pm8917 - RPM regulator ID numbers (both real and
+ * pin control) used with MSM8930 + PM8917
+ */
+enum rpm_vreg_id_8930_pm8917 {
+ RPM_VREG_ID_PM8917_L1,
+ RPM_VREG_ID_PM8917_L2,
+ RPM_VREG_ID_PM8917_L3,
+ RPM_VREG_ID_PM8917_L4,
+ RPM_VREG_ID_PM8917_L5,
+ RPM_VREG_ID_PM8917_L6,
+ RPM_VREG_ID_PM8917_L7,
+ RPM_VREG_ID_PM8917_L8,
+ RPM_VREG_ID_PM8917_L9,
+ RPM_VREG_ID_PM8917_L10,
+ RPM_VREG_ID_PM8917_L11,
+ RPM_VREG_ID_PM8917_L12,
+ RPM_VREG_ID_PM8917_L14,
+ RPM_VREG_ID_PM8917_L15,
+ RPM_VREG_ID_PM8917_L16,
+ RPM_VREG_ID_PM8917_L17,
+ RPM_VREG_ID_PM8917_L18,
+ RPM_VREG_ID_PM8917_L21,
+ RPM_VREG_ID_PM8917_L22,
+ RPM_VREG_ID_PM8917_L23,
+ RPM_VREG_ID_PM8917_L24,
+ RPM_VREG_ID_PM8917_L25,
+ RPM_VREG_ID_PM8917_L26,
+ RPM_VREG_ID_PM8917_L27,
+ RPM_VREG_ID_PM8917_L28,
+ RPM_VREG_ID_PM8917_L29,
+ RPM_VREG_ID_PM8917_L30,
+ RPM_VREG_ID_PM8917_L31,
+ RPM_VREG_ID_PM8917_L32,
+ RPM_VREG_ID_PM8917_L33,
+ RPM_VREG_ID_PM8917_L34,
+ RPM_VREG_ID_PM8917_L35,
+ RPM_VREG_ID_PM8917_L36,
+ RPM_VREG_ID_PM8917_S1,
+ RPM_VREG_ID_PM8917_S2,
+ RPM_VREG_ID_PM8917_S3,
+ RPM_VREG_ID_PM8917_S4,
+ RPM_VREG_ID_PM8917_S5,
+ RPM_VREG_ID_PM8917_S6,
+ RPM_VREG_ID_PM8917_S7,
+ RPM_VREG_ID_PM8917_S8,
+ RPM_VREG_ID_PM8917_LVS1,
+ RPM_VREG_ID_PM8917_LVS3,
+ RPM_VREG_ID_PM8917_LVS4,
+ RPM_VREG_ID_PM8917_LVS5,
+ RPM_VREG_ID_PM8917_LVS6,
+ RPM_VREG_ID_PM8917_LVS7,
+ RPM_VREG_ID_PM8917_USB_OTG,
+ RPM_VREG_ID_PM8917_VDD_DIG_CORNER,
+ RPM_VREG_ID_PM8917_MAX_REAL = RPM_VREG_ID_PM8917_VDD_DIG_CORNER,
+
+ /* The following are IDs for regulator devices to enable pin control. */
+ RPM_VREG_ID_PM8917_L1_PC,
+ RPM_VREG_ID_PM8917_L2_PC,
+ RPM_VREG_ID_PM8917_L3_PC,
+ RPM_VREG_ID_PM8917_L4_PC,
+ RPM_VREG_ID_PM8917_L5_PC,
+ RPM_VREG_ID_PM8917_L6_PC,
+ RPM_VREG_ID_PM8917_L7_PC,
+ RPM_VREG_ID_PM8917_L8_PC,
+ RPM_VREG_ID_PM8917_L9_PC,
+ RPM_VREG_ID_PM8917_L10_PC,
+ RPM_VREG_ID_PM8917_L11_PC,
+ RPM_VREG_ID_PM8917_L12_PC,
+ RPM_VREG_ID_PM8917_L14_PC,
+ RPM_VREG_ID_PM8917_L15_PC,
+ RPM_VREG_ID_PM8917_L16_PC,
+ RPM_VREG_ID_PM8917_L17_PC,
+ RPM_VREG_ID_PM8917_L18_PC,
+ RPM_VREG_ID_PM8917_L21_PC,
+ RPM_VREG_ID_PM8917_L22_PC,
+ RPM_VREG_ID_PM8917_L23_PC,
+
+ RPM_VREG_ID_PM8917_L29_PC,
+ RPM_VREG_ID_PM8917_L30_PC,
+ RPM_VREG_ID_PM8917_L31_PC,
+ RPM_VREG_ID_PM8917_L32_PC,
+ RPM_VREG_ID_PM8917_L33_PC,
+ RPM_VREG_ID_PM8917_L34_PC,
+ RPM_VREG_ID_PM8917_L35_PC,
+ RPM_VREG_ID_PM8917_L36_PC,
+ RPM_VREG_ID_PM8917_S1_PC,
+ RPM_VREG_ID_PM8917_S2_PC,
+ RPM_VREG_ID_PM8917_S3_PC,
+ RPM_VREG_ID_PM8917_S4_PC,
+
+ RPM_VREG_ID_PM8917_S7_PC,
+ RPM_VREG_ID_PM8917_S8_PC,
+ RPM_VREG_ID_PM8917_LVS1_PC,
+ RPM_VREG_ID_PM8917_LVS3_PC,
+ RPM_VREG_ID_PM8917_LVS4_PC,
+ RPM_VREG_ID_PM8917_LVS5_PC,
+ RPM_VREG_ID_PM8917_LVS6_PC,
+ RPM_VREG_ID_PM8917_LVS7_PC,
+
+ RPM_VREG_ID_PM8917_MAX = RPM_VREG_ID_PM8917_LVS7_PC,
+};
+
/* Minimum high power mode loads in uA. */
#define RPM_VREG_8930_LDO_5_HPM_MIN_LOAD 0
#define RPM_VREG_8930_LDO_50_HPM_MIN_LOAD 5000
diff --git a/arch/arm/mach-msm/include/mach/rpm-regulator.h b/arch/arm/mach-msm/include/mach/rpm-regulator.h
index d2ff2fe..f6e082d 100644
--- a/arch/arm/mach-msm/include/mach/rpm-regulator.h
+++ b/arch/arm/mach-msm/include/mach/rpm-regulator.h
@@ -31,7 +31,8 @@
RPM_VREG_VERSION_8960,
RPM_VREG_VERSION_9615,
RPM_VREG_VERSION_8930,
- RPM_VREG_VERSION_MAX = RPM_VREG_VERSION_8930,
+ RPM_VREG_VERSION_8930_PM8917,
+ RPM_VREG_VERSION_MAX = RPM_VREG_VERSION_8930_PM8917,
};
#define RPM_VREG_PIN_CTRL_NONE 0x00
diff --git a/arch/arm/mach-msm/include/mach/rpm.h b/arch/arm/mach-msm/include/mach/rpm.h
index f6b9a6e..4ee1997 100644
--- a/arch/arm/mach-msm/include/mach/rpm.h
+++ b/arch/arm/mach-msm/include/mach/rpm.h
@@ -451,6 +451,100 @@
MSM_RPM_ID_PM8038_CLK2_1,
MSM_RPM_ID_PM8038_LVS1,
MSM_RPM_ID_PM8038_LVS2,
+
+ /* PM8917 specific */
+ MSM_RPM_ID_PM8917_S1_0,
+ MSM_RPM_ID_PM8917_S1_1,
+ MSM_RPM_ID_PM8917_S2_0,
+ MSM_RPM_ID_PM8917_S2_1,
+ MSM_RPM_ID_PM8917_S3_0,
+ MSM_RPM_ID_PM8917_S3_1,
+ MSM_RPM_ID_PM8917_S4_0,
+ MSM_RPM_ID_PM8917_S4_1,
+ MSM_RPM_ID_PM8917_S5_0,
+ MSM_RPM_ID_PM8917_S5_1,
+ MSM_RPM_ID_PM8917_S6_0,
+ MSM_RPM_ID_PM8917_S6_1,
+ MSM_RPM_ID_PM8917_S7_0,
+ MSM_RPM_ID_PM8917_S7_1,
+ MSM_RPM_ID_PM8917_S8_0,
+ MSM_RPM_ID_PM8917_S8_1,
+ MSM_RPM_ID_PM8917_L1_0,
+ MSM_RPM_ID_PM8917_L1_1,
+ MSM_RPM_ID_PM8917_L2_0,
+ MSM_RPM_ID_PM8917_L2_1,
+ MSM_RPM_ID_PM8917_L3_0,
+ MSM_RPM_ID_PM8917_L3_1,
+ MSM_RPM_ID_PM8917_L4_0,
+ MSM_RPM_ID_PM8917_L4_1,
+ MSM_RPM_ID_PM8917_L5_0,
+ MSM_RPM_ID_PM8917_L5_1,
+ MSM_RPM_ID_PM8917_L6_0,
+ MSM_RPM_ID_PM8917_L6_1,
+ MSM_RPM_ID_PM8917_L7_0,
+ MSM_RPM_ID_PM8917_L7_1,
+ MSM_RPM_ID_PM8917_L8_0,
+ MSM_RPM_ID_PM8917_L8_1,
+ MSM_RPM_ID_PM8917_L9_0,
+ MSM_RPM_ID_PM8917_L9_1,
+ MSM_RPM_ID_PM8917_L10_0,
+ MSM_RPM_ID_PM8917_L10_1,
+ MSM_RPM_ID_PM8917_L11_0,
+ MSM_RPM_ID_PM8917_L11_1,
+ MSM_RPM_ID_PM8917_L12_0,
+ MSM_RPM_ID_PM8917_L12_1,
+ MSM_RPM_ID_PM8917_L14_0,
+ MSM_RPM_ID_PM8917_L14_1,
+ MSM_RPM_ID_PM8917_L15_0,
+ MSM_RPM_ID_PM8917_L15_1,
+ MSM_RPM_ID_PM8917_L16_0,
+ MSM_RPM_ID_PM8917_L16_1,
+ MSM_RPM_ID_PM8917_L17_0,
+ MSM_RPM_ID_PM8917_L17_1,
+ MSM_RPM_ID_PM8917_L18_0,
+ MSM_RPM_ID_PM8917_L18_1,
+ MSM_RPM_ID_PM8917_L21_0,
+ MSM_RPM_ID_PM8917_L21_1,
+ MSM_RPM_ID_PM8917_L22_0,
+ MSM_RPM_ID_PM8917_L22_1,
+ MSM_RPM_ID_PM8917_L23_0,
+ MSM_RPM_ID_PM8917_L23_1,
+ MSM_RPM_ID_PM8917_L24_0,
+ MSM_RPM_ID_PM8917_L24_1,
+ MSM_RPM_ID_PM8917_L25_0,
+ MSM_RPM_ID_PM8917_L25_1,
+ MSM_RPM_ID_PM8917_L26_0,
+ MSM_RPM_ID_PM8917_L26_1,
+ MSM_RPM_ID_PM8917_L27_0,
+ MSM_RPM_ID_PM8917_L27_1,
+ MSM_RPM_ID_PM8917_L28_0,
+ MSM_RPM_ID_PM8917_L28_1,
+ MSM_RPM_ID_PM8917_L29_0,
+ MSM_RPM_ID_PM8917_L29_1,
+ MSM_RPM_ID_PM8917_L30_0,
+ MSM_RPM_ID_PM8917_L30_1,
+ MSM_RPM_ID_PM8917_L31_0,
+ MSM_RPM_ID_PM8917_L31_1,
+ MSM_RPM_ID_PM8917_L32_0,
+ MSM_RPM_ID_PM8917_L32_1,
+ MSM_RPM_ID_PM8917_L33_0,
+ MSM_RPM_ID_PM8917_L33_1,
+ MSM_RPM_ID_PM8917_L34_0,
+ MSM_RPM_ID_PM8917_L34_1,
+ MSM_RPM_ID_PM8917_L35_0,
+ MSM_RPM_ID_PM8917_L35_1,
+ MSM_RPM_ID_PM8917_L36_0,
+ MSM_RPM_ID_PM8917_L36_1,
+ MSM_RPM_ID_PM8917_CLK1_0,
+ MSM_RPM_ID_PM8917_CLK1_1,
+ MSM_RPM_ID_PM8917_CLK2_0,
+ MSM_RPM_ID_PM8917_CLK2_1,
+ MSM_RPM_ID_PM8917_LVS1,
+ MSM_RPM_ID_PM8917_LVS3,
+ MSM_RPM_ID_PM8917_LVS4,
+ MSM_RPM_ID_PM8917_LVS5,
+ MSM_RPM_ID_PM8917_LVS6,
+ MSM_RPM_ID_PM8917_LVS7,
MSM_RPM_ID_VOLTAGE_CORNER,
/* 8064 specific */
@@ -605,6 +699,29 @@
MSM_RPM_STATUS_ID_EBI1_CH1_RANGE,
MSM_RPM_STATUS_ID_QDSS_CLK,
+ /* 8930 aliases to simplify device mapping */
+ MSM_RPM_STATUS_ID_PM8038_NCP_0 = MSM_RPM_STATUS_ID_NCP_0,
+ MSM_RPM_STATUS_ID_PM8038_NCP_1 = MSM_RPM_STATUS_ID_NCP_1,
+ MSM_RPM_STATUS_ID_PM8038_CXO_BUFFERS
+ = MSM_RPM_STATUS_ID_CXO_BUFFERS,
+ MSM_RPM_STATUS_ID_PM8038_USB_OTG_SWITCH
+ = MSM_RPM_STATUS_ID_USB_OTG_SWITCH,
+ MSM_RPM_STATUS_ID_PM8038_HDMI_SWITCH
+ = MSM_RPM_STATUS_ID_HDMI_SWITCH,
+ MSM_RPM_STATUS_ID_PM8038_QDSS_CLK
+ = MSM_RPM_STATUS_ID_QDSS_CLK,
+
+ MSM_RPM_STATUS_ID_PM8917_NCP_0 = MSM_RPM_STATUS_ID_NCP_0,
+ MSM_RPM_STATUS_ID_PM8917_NCP_1 = MSM_RPM_STATUS_ID_NCP_1,
+ MSM_RPM_STATUS_ID_PM8917_CXO_BUFFERS
+ = MSM_RPM_STATUS_ID_CXO_BUFFERS,
+ MSM_RPM_STATUS_ID_PM8917_USB_OTG_SWITCH
+ = MSM_RPM_STATUS_ID_USB_OTG_SWITCH,
+ MSM_RPM_STATUS_ID_PM8917_HDMI_SWITCH
+ = MSM_RPM_STATUS_ID_HDMI_SWITCH,
+ MSM_RPM_STATUS_ID_PM8917_QDSS_CLK
+ = MSM_RPM_STATUS_ID_QDSS_CLK,
+
/* 8660 Specific */
MSM_RPM_STATUS_ID_PLL_4,
MSM_RPM_STATUS_ID_SMI_CLK,
@@ -817,7 +934,105 @@
MSM_RPM_STATUS_ID_PM8038_CLK2_1,
MSM_RPM_STATUS_ID_PM8038_LVS1,
MSM_RPM_STATUS_ID_PM8038_LVS2,
+
+ /* PMIC 8917 */
+ MSM_RPM_STATUS_ID_PM8917_S1_0,
+ MSM_RPM_STATUS_ID_PM8917_S1_1,
+ MSM_RPM_STATUS_ID_PM8917_S2_0,
+ MSM_RPM_STATUS_ID_PM8917_S2_1,
+ MSM_RPM_STATUS_ID_PM8917_S3_0,
+ MSM_RPM_STATUS_ID_PM8917_S3_1,
+ MSM_RPM_STATUS_ID_PM8917_S4_0,
+ MSM_RPM_STATUS_ID_PM8917_S4_1,
+ MSM_RPM_STATUS_ID_PM8917_S5_0,
+ MSM_RPM_STATUS_ID_PM8917_S5_1,
+ MSM_RPM_STATUS_ID_PM8917_S6_0,
+ MSM_RPM_STATUS_ID_PM8917_S6_1,
+ MSM_RPM_STATUS_ID_PM8917_S7_0,
+ MSM_RPM_STATUS_ID_PM8917_S7_1,
+ MSM_RPM_STATUS_ID_PM8917_S8_0,
+ MSM_RPM_STATUS_ID_PM8917_S8_1,
+ MSM_RPM_STATUS_ID_PM8917_L1_0,
+ MSM_RPM_STATUS_ID_PM8917_L1_1,
+ MSM_RPM_STATUS_ID_PM8917_L2_0,
+ MSM_RPM_STATUS_ID_PM8917_L2_1,
+ MSM_RPM_STATUS_ID_PM8917_L3_0,
+ MSM_RPM_STATUS_ID_PM8917_L3_1,
+ MSM_RPM_STATUS_ID_PM8917_L4_0,
+ MSM_RPM_STATUS_ID_PM8917_L4_1,
+ MSM_RPM_STATUS_ID_PM8917_L5_0,
+ MSM_RPM_STATUS_ID_PM8917_L5_1,
+ MSM_RPM_STATUS_ID_PM8917_L6_0,
+ MSM_RPM_STATUS_ID_PM8917_L6_1,
+ MSM_RPM_STATUS_ID_PM8917_L7_0,
+ MSM_RPM_STATUS_ID_PM8917_L7_1,
+ MSM_RPM_STATUS_ID_PM8917_L8_0,
+ MSM_RPM_STATUS_ID_PM8917_L8_1,
+ MSM_RPM_STATUS_ID_PM8917_L9_0,
+ MSM_RPM_STATUS_ID_PM8917_L9_1,
+ MSM_RPM_STATUS_ID_PM8917_L10_0,
+ MSM_RPM_STATUS_ID_PM8917_L10_1,
+ MSM_RPM_STATUS_ID_PM8917_L11_0,
+ MSM_RPM_STATUS_ID_PM8917_L11_1,
+ MSM_RPM_STATUS_ID_PM8917_L12_0,
+ MSM_RPM_STATUS_ID_PM8917_L12_1,
+ MSM_RPM_STATUS_ID_PM8917_L14_0,
+ MSM_RPM_STATUS_ID_PM8917_L14_1,
+ MSM_RPM_STATUS_ID_PM8917_L15_0,
+ MSM_RPM_STATUS_ID_PM8917_L15_1,
+ MSM_RPM_STATUS_ID_PM8917_L16_0,
+ MSM_RPM_STATUS_ID_PM8917_L16_1,
+ MSM_RPM_STATUS_ID_PM8917_L17_0,
+ MSM_RPM_STATUS_ID_PM8917_L17_1,
+ MSM_RPM_STATUS_ID_PM8917_L18_0,
+ MSM_RPM_STATUS_ID_PM8917_L18_1,
+ MSM_RPM_STATUS_ID_PM8917_L21_0,
+ MSM_RPM_STATUS_ID_PM8917_L21_1,
+ MSM_RPM_STATUS_ID_PM8917_L22_0,
+ MSM_RPM_STATUS_ID_PM8917_L22_1,
+ MSM_RPM_STATUS_ID_PM8917_L23_0,
+ MSM_RPM_STATUS_ID_PM8917_L23_1,
+ MSM_RPM_STATUS_ID_PM8917_L24_0,
+ MSM_RPM_STATUS_ID_PM8917_L24_1,
+ MSM_RPM_STATUS_ID_PM8917_L25_0,
+ MSM_RPM_STATUS_ID_PM8917_L25_1,
+ MSM_RPM_STATUS_ID_PM8917_L26_0,
+ MSM_RPM_STATUS_ID_PM8917_L26_1,
+ MSM_RPM_STATUS_ID_PM8917_L27_0,
+ MSM_RPM_STATUS_ID_PM8917_L27_1,
+ MSM_RPM_STATUS_ID_PM8917_L28_0,
+ MSM_RPM_STATUS_ID_PM8917_L28_1,
+ MSM_RPM_STATUS_ID_PM8917_L29_0,
+ MSM_RPM_STATUS_ID_PM8917_L29_1,
+ MSM_RPM_STATUS_ID_PM8917_L30_0,
+ MSM_RPM_STATUS_ID_PM8917_L30_1,
+ MSM_RPM_STATUS_ID_PM8917_L31_0,
+ MSM_RPM_STATUS_ID_PM8917_L31_1,
+ MSM_RPM_STATUS_ID_PM8917_L32_0,
+ MSM_RPM_STATUS_ID_PM8917_L32_1,
+ MSM_RPM_STATUS_ID_PM8917_L33_0,
+ MSM_RPM_STATUS_ID_PM8917_L33_1,
+ MSM_RPM_STATUS_ID_PM8917_L34_0,
+ MSM_RPM_STATUS_ID_PM8917_L34_1,
+ MSM_RPM_STATUS_ID_PM8917_L35_0,
+ MSM_RPM_STATUS_ID_PM8917_L35_1,
+ MSM_RPM_STATUS_ID_PM8917_L36_0,
+ MSM_RPM_STATUS_ID_PM8917_L36_1,
+ MSM_RPM_STATUS_ID_PM8917_CLK1_0,
+ MSM_RPM_STATUS_ID_PM8917_CLK1_1,
+ MSM_RPM_STATUS_ID_PM8917_CLK2_0,
+ MSM_RPM_STATUS_ID_PM8917_CLK2_1,
+ MSM_RPM_STATUS_ID_PM8917_LVS1,
+ MSM_RPM_STATUS_ID_PM8917_LVS3,
+ MSM_RPM_STATUS_ID_PM8917_LVS4,
+ MSM_RPM_STATUS_ID_PM8917_LVS5,
+ MSM_RPM_STATUS_ID_PM8917_LVS6,
+ MSM_RPM_STATUS_ID_PM8917_LVS7,
MSM_RPM_STATUS_ID_VOLTAGE_CORNER,
+ MSM_RPM_STATUS_ID_PM8917_VOLTAGE_CORNER
+ = MSM_RPM_STATUS_ID_VOLTAGE_CORNER,
+ MSM_RPM_STATUS_ID_PM8038_VOLTAGE_CORNER
+ = MSM_RPM_STATUS_ID_VOLTAGE_CORNER,
/* 8064 specific */
MSM_RPM_STATUS_ID_PM8821_S1_0,
@@ -899,6 +1114,7 @@
extern struct msm_rpm_platform_data msm8960_rpm_data;
extern struct msm_rpm_platform_data msm9615_rpm_data;
extern struct msm_rpm_platform_data msm8930_rpm_data;
+extern struct msm_rpm_platform_data msm8930_rpm_data_pm8917;
extern struct msm_rpm_platform_data apq8064_rpm_data;
#if defined(CONFIG_MSM_RPM)
diff --git a/arch/arm/mach-msm/include/mach/sps.h b/arch/arm/mach-msm/include/mach/sps.h
index 000ffe4..5333c2e 100644
--- a/arch/arm/mach-msm/include/mach/sps.h
+++ b/arch/arm/mach-msm/include/mach/sps.h
@@ -1249,10 +1249,15 @@
*
* @para - parameter used for an option (such as pipe combination)
*
+ * @tb_sel - testbus selection
+ *
+ * @pre_level - prescreening level
+ *
* @return 0 on success, negative value on error
*
*/
-int sps_get_bam_debug_info(u32 dev, u32 option, u32 para);
+int sps_get_bam_debug_info(u32 dev, u32 option, u32 para,
+ u32 tb_sel, u8 pre_level);
#else
static inline int sps_register_bam_device(const struct sps_bam_props
@@ -1411,7 +1416,8 @@
return -EPERM;
}
-static inline int sps_get_bam_debug_info(u32 dev, u32 option, u32 para)
+static inline int sps_get_bam_debug_info(u32 dev, u32 option, u32 para,
+ u32 tb_sel, u8 pre_level)
{
return -EPERM;
}
diff --git a/arch/arm/mach-msm/iommu_domains.c b/arch/arm/mach-msm/iommu_domains.c
index 8f9464c..3acb6d8 100644
--- a/arch/arm/mach-msm/iommu_domains.c
+++ b/arch/arm/mach-msm/iommu_domains.c
@@ -191,6 +191,7 @@
return ret;
}
+EXPORT_SYMBOL(msm_iommu_map_contig_buffer);
void msm_iommu_unmap_contig_buffer(unsigned long iova,
unsigned int domain_no,
@@ -203,6 +204,7 @@
iommu_unmap_range(msm_get_iommu_domain(domain_no), iova, size);
msm_free_iova_address(iova, domain_no, partition_no, size);
}
+EXPORT_SYMBOL(msm_iommu_unmap_contig_buffer);
static struct msm_iova_data *find_domain(int domain_num)
{
@@ -402,6 +404,7 @@
return -EINVAL;
}
+EXPORT_SYMBOL(msm_register_domain);
static int __init iommu_domain_probe(struct platform_device *pdev)
{
diff --git a/arch/arm/mach-msm/mpm-8625.c b/arch/arm/mach-msm/mpm-8625.c
index 3c219be..fe7ffff 100644
--- a/arch/arm/mach-msm/mpm-8625.c
+++ b/arch/arm/mach-msm/mpm-8625.c
@@ -98,6 +98,22 @@
[MSM8625_INT_ADSP_A11] = SMSM_FAKE_IRQ,
};
+static uint16_t msm_bypassed_apps_irqs[] = {
+ MSM8625_INT_CPR_IRQ0,
+};
+
+/* Check IRQ falls into bypassed list are not */
+static bool msm_mpm_bypass_apps_irq(unsigned int irq)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(msm_bypassed_apps_irqs); i++)
+ if (irq == msm_bypassed_apps_irqs[i])
+ return true;
+
+ return false;
+}
+
static void msm_gic_mask_irq(struct irq_data *d)
{
unsigned int index = GIC_IRQ_INDEX(d->irq);
@@ -106,6 +122,10 @@
mask = GIC_IRQ_MASK(d->irq);
+ /* check whether irq to be bypassed are not */
+ if (msm_mpm_bypass_apps_irq(d->irq))
+ return;
+
if (smsm_irq == 0) {
msm_gic_irq_idle_disable[index] &= ~mask;
} else {
@@ -122,6 +142,10 @@
mask = GIC_IRQ_MASK(d->irq);
+ /* check whether irq to be bypassed are not */
+ if (msm_mpm_bypass_apps_irq(d->irq))
+ return;
+
if (smsm_irq == 0) {
msm_gic_irq_idle_disable[index] |= mask;
} else {
@@ -140,6 +164,10 @@
return -EINVAL;
}
+ /* check whether irq to be bypassed are not */
+ if (msm_mpm_bypass_apps_irq(d->irq))
+ return 0;
+
if (smsm_irq == SMSM_FAKE_IRQ)
return 0;
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c b/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
index 012bf5a..be3e06f 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
@@ -20,7 +20,6 @@
#include <linux/clk.h>
#include <linux/radix-tree.h>
#include <mach/board.h>
-#include <mach/socinfo.h>
#include "msm_bus_core.h"
enum {
@@ -344,10 +343,6 @@
void *sel_cdata;
int i;
- /* Temporarily stub out arbitration settings for msm8974 */
- if (machine_is_msm8974())
- return;
-
sel_cdata = fabric->cdata[ctx];
/* If it's an ahb fabric, don't calculate arb values */
diff --git a/arch/arm/mach-msm/msm_cpr.c b/arch/arm/mach-msm/msm_cpr.c
index f4272f3..b6c05f4 100644
--- a/arch/arm/mach-msm/msm_cpr.c
+++ b/arch/arm/mach-msm/msm_cpr.c
@@ -36,6 +36,14 @@
#define MODULE_NAME "msm-cpr"
+/**
+ * Convert the Delay time to Timer Count Register
+ * e.g if frequency is 19200 kHz and delay required is
+ * 20000us, so timer count will be 19200 * 20000 / 1000
+ */
+#define TIMER_COUNT(freq, delay) ((freq * delay) / 1000)
+#define ALL_CPR_IRQ 0x3F
+
/* Need platform device handle for suspend and resume APIs */
static struct platform_device *cpr_pdev;
@@ -45,6 +53,7 @@
int prev_mode;
uint32_t floor;
uint32_t ceiling;
+ bool max_volt_set;
void __iomem *base;
unsigned int irq;
struct mutex cpr_mutex;
@@ -157,7 +166,7 @@
static void
cpr_2pt_kv_analysis(struct msm_cpr *cpr, struct msm_cpr_mode *chip_data)
{
- int32_t tgt_volt_mV = 0, level_uV, rc;
+ int32_t level_uV = 0, rc;
uint32_t quot1, quot2;
/**
@@ -180,15 +189,10 @@
* voltage, offset is always subtracted from it.
*
*/
- if (chip_data->tgt_volt_offset > 0) {
- tgt_volt_mV = chip_data->calibrated_mV -
- (chip_data->tgt_volt_offset * cpr->vp->step_size);
- }
- pr_debug("tgt_volt_mV = %d, calibrated_mV = %d", tgt_volt_mV,
- chip_data->calibrated_mV);
+ level_uV = chip_data->Vmax -
+ (chip_data->tgt_volt_offset * cpr->vp->step_size);
+ pr_debug("tgt_volt_uV = %d\n", level_uV);
- /* level_uV = tgt_volt_mV * 1000; */
- level_uV = 1350000;
/* Call the PMIC specific routine to set the voltage */
rc = regulator_set_voltage(cpr->vreg_cx, level_uV, level_uV);
if (rc) {
@@ -202,10 +206,7 @@
return;
}
- /* Store the adjusted value of voltage */
- chip_data->calibrated_mV = 1300;
-
- /* Take first CPR measurement at a higher voltage to get QUOT1 */
+ /* First CPR measurement at a higher voltage to get QUOT1 */
/* Enable the Software mode of operation */
cpr_modify_reg(cpr, RBCPR_CTL, HW_TO_PMIC_EN_M, SW_MODE);
@@ -231,7 +232,8 @@
quot1 = (cpr_read_reg(cpr, RBCPR_DEBUG1) & QUOT_SLOW_M) >> 12;
/* Take second CPR measurement at a lower voltage to get QUOT2 */
- level_uV = 1300000;
+ level_uV -= 4 * cpr->vp->step_size;
+ pr_debug("tgt_volt_uV = %d\n", level_uV);
cpr_modify_reg(cpr, RBCPR_CTL, LOOP_EN_M, DISABLE_CPR);
/* Call the PMIC specific routine to set the voltage */
@@ -261,7 +263,7 @@
}
quot2 = (cpr_read_reg(cpr, RBCPR_DEBUG1) & QUOT_SLOW_M) >> 12;
chip_data->step_quot = (quot1 - quot2) / 4;
- pr_debug("%s: Calculated Step Quot is %d\n",
+ pr_info("%s: Calculated Step Quot is %d\n",
__func__, chip_data->step_quot);
/* Disable the cpr */
cpr_modify_reg(cpr, RBCPR_CTL, LOOP_EN_M, DISABLE_CPR);
@@ -279,7 +281,7 @@
void cpr_irq_clr_and_ack(struct msm_cpr *cpr, uint32_t mask)
{
/* Clear the interrupt */
- cpr_write_reg(cpr, RBIF_IRQ_CLEAR, 0x3F);
+ cpr_write_reg(cpr, RBIF_IRQ_CLEAR, ALL_CPR_IRQ);
/* Acknowledge the Recommendation */
cpr_write_reg(cpr, RBIF_CONT_ACK_CMD, 0x1);
}
@@ -287,7 +289,7 @@
static inline
void cpr_irq_clr_and_nack(struct msm_cpr *cpr, uint32_t mask)
{
- cpr_write_reg(cpr, RBIF_IRQ_CLEAR, 0x3F);
+ cpr_write_reg(cpr, RBIF_IRQ_CLEAR, ALL_CPR_IRQ);
cpr_write_reg(cpr, RBIF_CONT_NACK_CMD, 0x1);
}
@@ -307,7 +309,7 @@
static void
cpr_up_event_handler(struct msm_cpr *cpr, uint32_t new_volt)
{
- int rc, set_volt_mV;
+ int rc, set_volt_uV;
struct msm_cpr_mode *chip_data;
chip_data = &cpr->config->cpr_mode_data[cpr->cpr_mode];
@@ -317,26 +319,28 @@
* freq switch handler and CPR interrupt handler here
*/
/* Set New PMIC voltage */
- set_volt_mV = (new_volt < chip_data->Vmax ? new_volt
+ set_volt_uV = (new_volt < chip_data->Vmax ? new_volt
: chip_data->Vmax);
- rc = regulator_set_voltage(cpr->vreg_cx, set_volt_mV * 1000,
- set_volt_mV * 1000);
+ rc = regulator_set_voltage(cpr->vreg_cx, set_volt_uV,
+ set_volt_uV);
if (rc) {
- pr_err("%s: Voltage set at %dmV failed. %d\n",
- __func__, set_volt_mV, rc);
+ pr_err("%s: Voltage set at %duV failed. %d\n",
+ __func__, set_volt_uV, rc);
cpr_irq_clr_and_nack(cpr, BIT(4) | BIT(0));
return;
}
- pr_debug("%s: Voltage set at %dmV\n", __func__, set_volt_mV);
+ pr_info("(railway_voltage: %d uV)\n", set_volt_uV);
+
+ cpr->max_volt_set = (set_volt_uV == chip_data->Vmax) ? 1 : 0;
/**
* Save the new calibrated voltage to be re-used
* whenever we return to same mode after a mode switch.
*/
- chip_data->calibrated_mV = set_volt_mV;
+ chip_data->calibrated_uV = set_volt_uV;
/* Clear all the interrupts */
- cpr_write_reg(cpr, RBIF_IRQ_CLEAR, 0x3F);
+ cpr_write_reg(cpr, RBIF_IRQ_CLEAR, ALL_CPR_IRQ);
/* Disable Auto ACK for Down interrupts */
cpr_modify_reg(cpr, RBCPR_CTL, SW_AUTO_CONT_NACK_DN_EN_M, 0);
@@ -353,7 +357,7 @@
static void
cpr_dn_event_handler(struct msm_cpr *cpr, uint32_t new_volt)
{
- int rc, set_volt_mV;
+ int rc, set_volt_uV;
struct msm_cpr_mode *chip_data;
chip_data = &cpr->config->cpr_mode_data[cpr->cpr_mode];
@@ -363,26 +367,28 @@
* freq switch handler and CPR interrupt handler here
*/
/* Set New PMIC volt */
- set_volt_mV = (new_volt > chip_data->Vmin ? new_volt
+ set_volt_uV = (new_volt > chip_data->Vmin ? new_volt
: chip_data->Vmin);
- rc = regulator_set_voltage(cpr->vreg_cx, set_volt_mV * 1000,
- set_volt_mV * 1000);
+ rc = regulator_set_voltage(cpr->vreg_cx, set_volt_uV,
+ set_volt_uV);
if (rc) {
- pr_err("%s: Voltage at %dmV failed %d\n",
- __func__, set_volt_mV, rc);
+ pr_err("%s: Voltage at %duV failed %d\n",
+ __func__, set_volt_uV, rc);
cpr_irq_clr_and_nack(cpr, BIT(2) | BIT(0));
return;
}
- pr_debug("%s: Voltage set at %dmV\n", __func__, set_volt_mV);
+ pr_info("(railway_voltage: %d uV)\n", set_volt_uV);
+
+ cpr->max_volt_set = 0;
/**
* Save the new calibrated voltage to be re-used
* whenever we return to same mode after a mode switch.
*/
- chip_data->calibrated_mV = set_volt_mV;
+ chip_data->calibrated_uV = set_volt_uV;
/* Clear all the interrupts */
- cpr_write_reg(cpr, RBIF_IRQ_CLEAR, 0x3F);
+ cpr_write_reg(cpr, RBIF_IRQ_CLEAR, ALL_CPR_IRQ);
if (new_volt <= chip_data->Vmin) {
/*
@@ -416,16 +422,22 @@
chip_data = &cpr->config->cpr_mode_data[cpr->cpr_mode];
error_step = cpr_read_reg(cpr, RBCPR_RESULT_0) >> 2;
error_step &= 0xF;
- curr_volt = chip_data->calibrated_mV;
+ curr_volt = chip_data->calibrated_uV;
if (action == UP) {
+ /* Clear IRQ, ACK and return if Vdd already at Vmax */
+ if (cpr->max_volt_set == 1) {
+ cpr_write_reg(cpr, RBIF_IRQ_CLEAR, ALL_CPR_IRQ);
+ cpr_write_reg(cpr, RBIF_CONT_NACK_CMD, 0x1);
+ return;
+ }
+
/**
* Using up margin in the comparison helps avoid having to
* change up threshold values in chip register.
*/
if (error_step < (cpr->config->up_threshold +
cpr->config->up_margin)) {
- /* FIXME: Avoid repeated dn interrupts if we are here */
pr_debug("UP_INT error step too small to set\n");
cpr_irq_clr_and_nack(cpr, BIT(4) | BIT(0));
return;
@@ -434,6 +446,7 @@
/* Calculte new PMIC voltage */
new_volt = curr_volt + (error_step * cpr->vp->step_size);
pr_debug("UP_INT: new_volt: %d\n", new_volt);
+ pr_info("(UP Voltage recommended by CPR: %d uV)\n", new_volt);
cpr_up_event_handler(cpr, new_volt);
} else if (action == DOWN) {
@@ -443,7 +456,6 @@
*/
if (error_step < (cpr->config->dn_threshold +
cpr->config->dn_margin)) {
- /* FIXME: Avoid repeated dn interrupts if we are here */
pr_debug("DOWN_INT error_step too small to set\n");
cpr_irq_clr_and_nack(cpr, BIT(2) | BIT(0));
return;
@@ -452,6 +464,7 @@
/* Calculte new PMIC voltage */
new_volt = curr_volt - (error_step * cpr->vp->step_size);
pr_debug("DOWN_INT: new_volt: %d\n", new_volt);
+ pr_info("(DN Voltage recommended by CPR: %d uV)\n", new_volt);
cpr_dn_event_handler(cpr, new_volt);
}
}
@@ -513,6 +526,8 @@
cpr->config->dn_threshold << 28);
cpr->curr_osc = chip_data->ring_osc;
+ chip_data->ring_osc_data[cpr->curr_osc].quot =
+ cpr->config->max_quot;
/**
* Program the gate count and target values
@@ -522,7 +537,7 @@
cpr_modify_reg(cpr, RBCPR_GCNT_TARGET(cnt),
(GCNT_M | TARGET_M),
(chip_data->ring_osc_data[cnt].gcnt << 12 |
- chip_data->ring_osc_data[cnt].target_count));
+ chip_data->ring_osc_data[cnt].quot));
pr_debug("RBCPR_GCNT_TARGET(%d): = 0x%x\n", cnt,
readl_relaxed(cpr->base + RBCPR_GCNT_TARGET(cnt)));
cnt++;
@@ -536,14 +551,19 @@
* Set with an extra step since it helps as per
* characterization data.
*/
- chip_data->calibrated_mV += cpr->vp->step_size;
- tmp_uV = chip_data->calibrated_mV * 1000;
+ chip_data->calibrated_uV += cpr->vp->step_size;
+ tmp_uV = chip_data->calibrated_uV;
rc = regulator_set_voltage(cpr->vreg_cx, tmp_uV, tmp_uV);
if (rc)
pr_err("%s: Voltage set failed %d\n", __func__, rc);
- /* Program the Timer for default delay between CPR measurements */
- delay_count = 0xFFFF;
+ /*
+ * Program the Timer Register for delay between CPR measurements
+ * This is required to allow the device sufficient time for idle
+ * power collapse.
+ */
+ delay_count = TIMER_COUNT(cpr->config->ref_clk_khz,
+ cpr->config->delay_us);
cpr_write_reg(cpr, RBCPR_TIMER_INTERVAL, delay_count);
/* Enable the Timer */
@@ -554,53 +574,69 @@
SW_AUTO_CONT_ACK_EN);
}
-static void cpr_mode_config(struct msm_cpr *cpr, enum cpr_mode mode)
-{
- if (cpr->cpr_mode == mode)
- return;
-
- cpr->cpr_mode = mode;
- pr_debug("%s: Switching to %s mode\n", __func__,
- (mode == TURBO_MODE ? "TURBO" : "NORMAL"));
-
- /* Configure the new mode */
- cpr_config(cpr);
-}
-
static int
cpr_freq_transition(struct notifier_block *nb, unsigned long val,
void *data)
{
struct msm_cpr *cpr = container_of(nb, struct msm_cpr, freq_transition);
struct cpufreq_freqs *freqs = data;
+ uint32_t quot, new_freq;
switch (val) {
case CPUFREQ_PRECHANGE:
- return 0;
pr_debug("pre freq change notification to cpr\n");
- disable_irq(cpr->irq);
+ /* Disable Measurement to stop generation of CPR IRQs */
cpr_disable(cpr);
+ /* Disable routing of IRQ to App */
+ cpr_irq_set(cpr, INT_MASK & ~MID_INT, 0);
+ disable_irq(cpr->irq);
+ cpr_write_reg(cpr, RBIF_IRQ_CLEAR, ALL_CPR_IRQ);
+ pr_debug("RBCPR_CTL: 0x%x\n",
+ readl_relaxed(cpr->base + RBCPR_CTL));
+ pr_debug("RBIF_IRQ_STATUS: 0x%x\n",
+ cpr_read_reg(cpr, RBIF_IRQ_STATUS));
+ pr_debug("RBIF_IRQ_EN(0): 0x%x\n",
+ cpr_read_reg(cpr, RBIF_IRQ_EN(cpr->config->irq_line)));
+
cpr->prev_mode = cpr->cpr_mode;
break;
- case CPUFREQ_POSTCHANGE:
- return 0;
- pr_debug("post freq change notification to cpr\n");
- if (freqs->new >= cpr->config->nom_freq_limit)
- cpr_mode_config(cpr, TURBO_MODE);
- else
- cpr_mode_config(cpr, NORMAL_MODE);
+ case CPUFREQ_POSTCHANGE:
+ pr_debug("post freq change notification to cpr\n");
+ /**
+ * As per chip characterization data, use max nominal freq
+ * to calculate quot for all lower frequencies too
+ */
+ new_freq = (freqs->new > cpr->config->max_nom_freq)
+ ? freqs->new
+ : cpr->config->max_nom_freq;
+
+ /* Configure CPR for the new frequency */
+ quot = cpr->config->get_quot(cpr->config->max_quot,
+ cpr->config->max_freq / 1000,
+ new_freq / 1000);
+ cpr_modify_reg(cpr, RBCPR_GCNT_TARGET(cpr->curr_osc), TARGET_M,
+ quot);
+ pr_debug("RBCPR_GCNT_TARGET(%d): = 0x%x\n", cpr->curr_osc,
+ readl_relaxed(cpr->base +
+ RBCPR_GCNT_TARGET(cpr->curr_osc)));
+ pr_debug("%s: new_freq: %d, set_freq: %d, quot: %d\n", __func__,
+ freqs->new, new_freq, quot);
+
+ enable_irq(cpr->irq);
/**
* Enable all interrupts. One of them could be in a disabled
* state if vdd had hit Vmax / Vmin earlier
*/
- cpr_irq_set(cpr, (UP_INT | DOWN_INT), 1);
-
- enable_irq(cpr->irq);
-
+ cpr_irq_set(cpr, INT_MASK & ~MID_INT, 1);
+ pr_debug("RBIF_IRQ_EN(0): 0x%x\n",
+ cpr_read_reg(cpr, RBIF_IRQ_EN(cpr->config->irq_line)));
+ pr_debug("RBCPR_CTL: 0x%x\n",
+ readl_relaxed(cpr->base + RBCPR_CTL));
+ pr_debug("RBIF_IRQ_STATUS: 0x%x\n",
+ cpr_read_reg(cpr, RBIF_IRQ_STATUS));
cpr_enable(cpr);
-
break;
default:
break;
@@ -614,6 +650,8 @@
struct msm_cpr *cpr = dev_get_drvdata(dev);
int osc_num = cpr->config->cpr_mode_data->ring_osc;
+ cpr->config->clk_enable();
+
cpr_write_reg(cpr, RBCPR_TIMER_INTERVAL,
cpr_save_state.rbif_timer_interval);
cpr_write_reg(cpr, RBIF_IRQ_EN(cpr->config->irq_line),
@@ -628,11 +666,11 @@
cpr_save_state.rbcpr_step_quot);
cpr_write_reg(cpr, RBIF_SW_VLEVEL,
cpr_save_state.rbif_sw_level);
-
- cpr_enable(cpr);
cpr_write_reg(cpr, RBCPR_CTL,
cpr_save_state.rbcpr_ctl);
+
enable_irq(cpr->irq);
+ cpr_enable(cpr);
return 0;
}
@@ -643,6 +681,10 @@
struct msm_cpr *cpr = dev_get_drvdata(dev);
int osc_num = cpr->config->cpr_mode_data->ring_osc;
+ /* Disable CPR measurement before IRQ to avoid pending interrupts */
+ cpr_disable(cpr);
+ disable_irq(cpr->irq);
+
cpr_save_state.rbif_timer_interval =
cpr_read_reg(cpr, RBCPR_TIMER_INTERVAL);
cpr_save_state.rbif_int_en =
@@ -660,9 +702,6 @@
cpr_save_state.rbcpr_ctl =
cpr_read_reg(cpr, RBCPR_CTL);
- disable_irq(cpr->irq);
- cpr_disable(cpr);
-
return 0;
}
@@ -700,6 +739,7 @@
const struct msm_cpr_config *pdata = pdev->dev.platform_data;
void __iomem *base;
struct resource *mem;
+ struct msm_cpr_mode *chip_data;
if (!pdata) {
pr_err("CPR: Platform data is not available\n");
@@ -766,6 +806,16 @@
platform_set_drvdata(pdev, cpr);
+ chip_data = &cpr->config->cpr_mode_data[cpr->cpr_mode];
+ pr_info("CPR Platform Data (upside_steps: %d) (downside_steps: %d) ",
+ cpr->config->up_threshold, cpr->config->dn_threshold);
+ pr_info("(nominal_voltage: %duV) (turbo_voltage: %duV)\n",
+ cpr->config->cpr_mode_data[NORMAL_MODE].calibrated_uV,
+ cpr->config->cpr_mode_data[TURBO_MODE].calibrated_uV);
+ pr_info("(Current corner: TURBO) (gcnt_target: %d) (quot: %d)\n",
+ chip_data->ring_osc_data[chip_data->ring_osc].gcnt,
+ chip_data->ring_osc_data[chip_data->ring_osc].quot);
+
/* Initialze the Debugfs Entry for cpr */
res = msm_cpr_debug_init(cpr->base);
if (res) {
@@ -793,7 +843,6 @@
/* Enable the cpr */
cpr_modify_reg(cpr, RBCPR_CTL, LOOP_EN_M, ENABLE_CPR);
-
cpr->freq_transition.notifier_call = cpr_freq_transition;
cpufreq_register_notifier(&cpr->freq_transition,
CPUFREQ_TRANSITION_NOTIFIER);
diff --git a/arch/arm/mach-msm/msm_cpr.h b/arch/arm/mach-msm/msm_cpr.h
index 2642b9c..cb665b7 100644
--- a/arch/arm/mach-msm/msm_cpr.h
+++ b/arch/arm/mach-msm/msm_cpr.h
@@ -120,10 +120,10 @@
/**
* struct msm_vp_data - structure for VP configuration
- * @min_volt_mV: minimum milivolt level for VP
- * @max_volt_mV: maximum milivolt level for VP
- * @default_volt_mV: default milivolt for VP
- * @step_size_mV: step size of voltage
+ * @min_volt: minimum microvolt level for VP
+ * @max_volt: maximum microvolt level for VP
+ * @default_volt: default microvolt for VP
+ * @step_size: step size of voltage in microvolt
*/
struct msm_cpr_vp_data {
int min_volt;
@@ -135,11 +135,11 @@
/**
* struct msm_cpr_osc - Data for CPR ring oscillator
* @gcnt: gate count value for the oscillator
- * @target_count: target value for ring oscillator
+ * @quot: target value for ring oscillator
*/
struct msm_cpr_osc {
int gcnt;
- uint32_t target_count;
+ uint32_t quot;
};
/**
@@ -156,7 +156,7 @@
uint32_t step_quot;
uint32_t Vmax;
uint32_t Vmin;
- uint32_t calibrated_mV;
+ uint32_t calibrated_uV;
};
/**
@@ -180,8 +180,13 @@
uint32_t dn_threshold;
uint32_t up_margin;
uint32_t dn_margin;
- uint32_t nom_freq_limit;
+ uint32_t max_nom_freq;
+ uint32_t max_freq;
+ uint32_t max_quot;
struct msm_cpr_vp_data *vp_data;
+ uint32_t (*get_quot)(uint32_t max_quot, uint32_t max_freq,
+ uint32_t new_freq);
+ void (*clk_enable)(void);
};
/**
diff --git a/arch/arm/mach-msm/msm_watchdog_v2.c b/arch/arm/mach-msm/msm_watchdog_v2.c
index af903f8..48a57cd 100644
--- a/arch/arm/mach-msm/msm_watchdog_v2.c
+++ b/arch/arm/mach-msm/msm_watchdog_v2.c
@@ -17,6 +17,7 @@
#include <linux/workqueue.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
+#include <linux/mutex.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
@@ -38,6 +39,7 @@
#define MASK_SIZE 32
#define SCM_SET_REGSAVE_CMD 0x2
+#define SCM_SVC_SEC_WDOG_DIS 0x7
struct msm_watchdog_data {
unsigned int __iomem phys_base;
@@ -54,6 +56,7 @@
unsigned long long min_slack_ns;
void *scm_regsave;
cpumask_t alive_mask;
+ struct mutex disable_lock;
struct work_struct init_dogwork_struct;
struct delayed_work dogwork_struct;
bool irq_ppi;
@@ -77,19 +80,6 @@
static long WDT_HZ = 32765;
module_param(WDT_HZ, long, 0);
-/*
- * If the watchdog is enabled at bootup (enable=1),
- * the runtime_disable sysfs node at
- * /sys/module/msm_watchdog/parameters/runtime_disable
- * can be used to deactivate the watchdog.
- * This is a one-time setting. The watchdog
- * cannot be re-enabled once it is disabled.
- */
-static int runtime_disable;
-static int wdog_enable_set(const char *val, struct kernel_param *kp);
-module_param_call(runtime_disable, wdog_enable_set, param_get_int,
- &runtime_disable, 0644);
-
static void pet_watchdog_work(struct work_struct *work);
static void init_watchdog_work(struct work_struct *work);
@@ -142,14 +132,99 @@
}
return NOTIFY_DONE;
}
-/*
- * TODO: implement enable/disable.
- */
-static int wdog_enable_set(const char *val, struct kernel_param *kp)
+
+static void wdog_disable(struct msm_watchdog_data *wdog_dd)
{
- return 0;
+ __raw_writel(0, wdog_dd->base + WDT0_EN);
+ mb();
+ if (wdog_dd->irq_ppi) {
+ disable_percpu_irq(wdog_dd->bark_irq);
+ free_percpu_irq(wdog_dd->bark_irq, wdog_dd->wdog_cpu_dd);
+ } else
+ devm_free_irq(wdog_dd->dev, wdog_dd->bark_irq, wdog_dd);
+ enable = 0;
+ /*Ensure all cpus see update to enable*/
+ smp_mb();
+ atomic_notifier_chain_unregister(&panic_notifier_list,
+ &wdog_dd->panic_blk);
+ cancel_delayed_work_sync(&wdog_dd->dogwork_struct);
+ /* may be suspended after the first write above */
+ __raw_writel(0, wdog_dd->base + WDT0_EN);
+ mb();
+ pr_info("MSM Apps Watchdog deactivated.\n");
}
+struct wdog_disable_work_data {
+ struct work_struct work;
+ struct completion complete;
+ struct msm_watchdog_data *wdog_dd;
+};
+
+static void wdog_disable_work(struct work_struct *work)
+{
+ struct wdog_disable_work_data *work_data =
+ container_of(work, struct wdog_disable_work_data, work);
+ wdog_disable(work_data->wdog_dd);
+ complete(&work_data->complete);
+}
+
+static ssize_t wdog_disable_get(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int ret;
+ struct msm_watchdog_data *wdog_dd = dev_get_drvdata(dev);
+
+ mutex_lock(&wdog_dd->disable_lock);
+ ret = snprintf(buf, PAGE_SIZE, "%d\n", enable == 0 ? 1 : 0);
+ mutex_unlock(&wdog_dd->disable_lock);
+ return ret;
+}
+
+static ssize_t wdog_disable_set(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret;
+ u8 disable;
+ struct wdog_disable_work_data work_data;
+ struct msm_watchdog_data *wdog_dd = dev_get_drvdata(dev);
+
+ ret = kstrtou8(buf, 10, &disable);
+ if (ret) {
+ dev_err(wdog_dd->dev, "invalid user input\n");
+ return ret;
+ }
+ if (disable == 1) {
+ mutex_lock(&wdog_dd->disable_lock);
+ if (enable == 0) {
+ pr_info("MSM Apps Watchdog already disabled\n");
+ mutex_unlock(&wdog_dd->disable_lock);
+ return count;
+ }
+ disable = 1;
+ ret = scm_call(SCM_SVC_BOOT, SCM_SVC_SEC_WDOG_DIS, &disable,
+ sizeof(disable), NULL, 0);
+ if (ret) {
+ dev_err(wdog_dd->dev,
+ "Failed to deactivate secure wdog\n");
+ mutex_unlock(&wdog_dd->disable_lock);
+ return -EIO;
+ }
+ work_data.wdog_dd = wdog_dd;
+ init_completion(&work_data.complete);
+ INIT_WORK_ONSTACK(&work_data.work, wdog_disable_work);
+ schedule_work_on(0, &work_data.work);
+ wait_for_completion(&work_data.complete);
+ mutex_unlock(&wdog_dd->disable_lock);
+ } else {
+ pr_err("invalid operation, only disable = 1 supported\n");
+ return -EINVAL;
+ }
+ return count;
+}
+
+static DEVICE_ATTR(disable, S_IWUSR | S_IRUSR, wdog_disable_get,
+ wdog_disable_set);
static void pet_watchdog(struct msm_watchdog_data *wdog_dd)
{
@@ -199,9 +274,13 @@
struct msm_watchdog_data,
dogwork_struct);
delay_time = msecs_to_jiffies(wdog_dd->pet_time);
- if (wdog_dd->do_ipi_ping)
- ping_other_cpus(wdog_dd);
- pet_watchdog(wdog_dd);
+ if (enable) {
+ if (wdog_dd->do_ipi_ping)
+ ping_other_cpus(wdog_dd);
+ pet_watchdog(wdog_dd);
+ }
+ /* Check again before scheduling *
+ * Could have been changed on other cpu */
if (enable)
schedule_delayed_work_on(0, &wdog_dd->dogwork_struct,
delay_time);
@@ -209,23 +288,24 @@
static int msm_watchdog_remove(struct platform_device *pdev)
{
+ struct wdog_disable_work_data work_data;
struct msm_watchdog_data *wdog_dd =
(struct msm_watchdog_data *)platform_get_drvdata(pdev);
+
+ mutex_lock(&wdog_dd->disable_lock);
if (enable) {
- __raw_writel(0, wdog_dd->base + WDT0_EN);
- mb();
- enable = 0;
- /*
- * TODO: Not sure if we need to call into TZ to disable
- * secure wdog.
- */
- /* In case we got suspended mid-exit */
- __raw_writel(0, wdog_dd->base + WDT0_EN);
+ work_data.wdog_dd = wdog_dd;
+ init_completion(&work_data.complete);
+ INIT_WORK_ONSTACK(&work_data.work, wdog_disable_work);
+ schedule_work_on(0, &work_data.work);
+ wait_for_completion(&work_data.complete);
}
+ mutex_unlock(&wdog_dd->disable_lock);
+ device_remove_file(wdog_dd->dev, &dev_attr_disable);
if (wdog_dd->irq_ppi)
free_percpu(wdog_dd->wdog_cpu_dd);
printk(KERN_INFO "MSM Watchdog Exit - Deactivated\n");
- kzfree(wdog_dd);
+ kfree(wdog_dd);
return 0;
}
@@ -299,6 +379,7 @@
struct msm_watchdog_data,
init_dogwork_struct);
unsigned long delay_time;
+ int error;
u64 timeout;
int ret;
@@ -337,14 +418,17 @@
wdog_dd->panic_blk.notifier_call = panic_wdog_handler;
atomic_notifier_chain_register(&panic_notifier_list,
&wdog_dd->panic_blk);
+ mutex_init(&wdog_dd->disable_lock);
schedule_delayed_work_on(0, &wdog_dd->dogwork_struct, delay_time);
-
__raw_writel(1, wdog_dd->base + WDT0_EN);
__raw_writel(1, wdog_dd->base + WDT0_RST);
wdog_dd->last_pet = sched_clock();
- printk(KERN_INFO "MSM Watchdog Initialized\n");
+ error = device_create_file(wdog_dd->dev, &dev_attr_disable);
+ if (error)
+ dev_err(wdog_dd->dev, "cannot create sysfs attribute\n");
if (wdog_dd->irq_ppi)
enable_percpu_irq(wdog_dd->bark_irq, 0);
+ dev_info(wdog_dd->dev, "MSM Watchdog Initialized\n");
return;
}
diff --git a/arch/arm/mach-msm/ocmem.c b/arch/arm/mach-msm/ocmem.c
index 82fe2f8..51445aa 100644
--- a/arch/arm/mach-msm/ocmem.c
+++ b/arch/arm/mach-msm/ocmem.c
@@ -63,6 +63,27 @@
"other_os",
};
+/* Must be in sync with enum ocmem_zstat_item */
+static const char *zstat_names[NR_OCMEM_ZSTAT_ITEMS] = {
+ "Allocation requests",
+ "Synchronous allocations",
+ "Ranged allocations",
+ "Asynchronous allocations",
+ "Allocation failures",
+ "Allocations grown",
+ "Allocations freed",
+ "Allocations shrunk",
+ "OCMEM maps",
+ "Map failures",
+ "OCMEM unmaps",
+ "Unmap failures",
+ "Transfers to OCMEM",
+ "Transfers to DDR",
+ "Transfer failures",
+ "Evictions",
+ "Restorations",
+};
+
struct ocmem_quota_table {
const char *name;
int id;
@@ -135,6 +156,23 @@
return 0;
}
+inline void inc_ocmem_stat(struct ocmem_zone *z,
+ enum ocmem_zstat_item item)
+{
+ if (!z)
+ return;
+ atomic_long_inc(&z->z_stat[item]);
+}
+
+inline unsigned long get_ocmem_stat(struct ocmem_zone *z,
+ enum ocmem_zstat_item item)
+{
+ if (!z)
+ return 0;
+ else
+ return atomic_long_read(&z->z_stat[item]);
+}
+
static struct ocmem_plat_data *parse_static_config(struct platform_device *pdev)
{
struct ocmem_plat_data *pdata = NULL;
@@ -473,6 +511,60 @@
return NULL;
}
+static int ocmem_zones_show(struct seq_file *f, void *dummy)
+{
+ unsigned i = 0;
+ for (i = OCMEM_GRAPHICS; i < OCMEM_CLIENT_MAX; i++) {
+ struct ocmem_zone *z = get_zone(i);
+ if (z && z->active == true)
+ seq_printf(f, "zone %s\t:0x%08lx - 0x%08lx (%4ld KB)\n",
+ get_name(z->owner), z->z_start, z->z_end - 1,
+ (z->z_end - z->z_start)/SZ_1K);
+ }
+ return 0;
+}
+
+static int ocmem_zones_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, ocmem_zones_show, inode->i_private);
+}
+
+static const struct file_operations zones_show_fops = {
+ .open = ocmem_zones_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+static int ocmem_stats_show(struct seq_file *f, void *dummy)
+{
+ unsigned i = 0;
+ unsigned j = 0;
+ for (i = OCMEM_GRAPHICS; i < OCMEM_CLIENT_MAX; i++) {
+ struct ocmem_zone *z = get_zone(i);
+ if (z && z->active == true) {
+ seq_printf(f, "zone %s:\n", get_name(z->owner));
+ for (j = 0 ; j < ARRAY_SIZE(zstat_names); j++) {
+ seq_printf(f, "\t %s: %lu\n", zstat_names[j],
+ get_ocmem_stat(z, j));
+ }
+ }
+ }
+ return 0;
+}
+
+static int ocmem_stats_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, ocmem_stats_show, inode->i_private);
+}
+
+static const struct file_operations stats_show_fops = {
+ .open = ocmem_stats_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
static int ocmem_zone_init(struct platform_device *pdev)
{
@@ -549,6 +641,8 @@
z_ops->allocate = allocate_head;
z_ops->free = free_head;
}
+ /* zap the counters */
+ memset(zone->z_stat, 0 , sizeof(zone->z_stat));
zone->active = true;
active_zones++;
@@ -557,7 +651,19 @@
pr_info(" zone %s\t: 0x%08lx - 0x%08lx (%4ld KB)\n",
client_names[part->id], zone->z_start,
- zone->z_end, part->p_size/SZ_1K);
+ zone->z_end - 1, part->p_size/SZ_1K);
+ }
+
+ if (!debugfs_create_file("zones", S_IRUGO, pdata->debug_node,
+ NULL, &zones_show_fops)) {
+ dev_err(dev, "Unable to create debugfs node for zones\n");
+ return -EBUSY;
+ }
+
+ if (!debugfs_create_file("stats", S_IRUGO, pdata->debug_node,
+ NULL, &stats_show_fops)) {
+ dev_err(dev, "Unable to create debugfs node for stats\n");
+ return -EBUSY;
}
dev_dbg(dev, "Total active zones = %d\n", active_zones);
@@ -587,6 +693,27 @@
return 0;
}
+static int __devinit ocmem_debugfs_init(struct platform_device *pdev)
+{
+ struct dentry *debug_dir = NULL;
+ struct ocmem_plat_data *pdata = platform_get_drvdata(pdev);
+
+ debug_dir = debugfs_create_dir("ocmem", NULL);
+ if (!debug_dir || IS_ERR(debug_dir)) {
+ pr_err("ocmem: Unable to create debugfs root\n");
+ return PTR_ERR(debug_dir);
+ }
+
+ pdata->debug_node = debug_dir;
+ return 0;
+}
+
+static void __devexit ocmem_debugfs_exit(struct platform_device *pdev)
+{
+ struct ocmem_plat_data *pdata = platform_get_drvdata(pdev);
+ debugfs_remove_recursive(pdata->debug_node);
+}
+
static int __devinit msm_ocmem_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -635,6 +762,9 @@
platform_set_drvdata(pdev, ocmem_pdata);
+ if (ocmem_debugfs_init(pdev))
+ return -EBUSY;
+
if (ocmem_core_init(pdev))
return -EBUSY;
@@ -644,7 +774,7 @@
if (ocmem_notifier_init())
return -EBUSY;
- if (ocmem_sched_init())
+ if (ocmem_sched_init(pdev))
return -EBUSY;
if (ocmem_rdm_init(pdev))
@@ -661,6 +791,7 @@
static int __devexit msm_ocmem_remove(struct platform_device *pdev)
{
+ ocmem_debugfs_exit(pdev);
return 0;
}
diff --git a/arch/arm/mach-msm/ocmem_core.c b/arch/arm/mach-msm/ocmem_core.c
index d9d67a3..de9856d 100644
--- a/arch/arm/mach-msm/ocmem_core.c
+++ b/arch/arm/mach-msm/ocmem_core.c
@@ -665,6 +665,81 @@
return switch_power_state(id, offset, len, REGION_DEFAULT_RETENTION);
}
+static int ocmem_power_show_sw_state(struct seq_file *f, void *dummy)
+{
+ unsigned i, j;
+ unsigned m_state;
+ mutex_lock(®ion_ctrl_lock);
+
+ seq_printf(f, "OCMEM Aggregated Power States\n");
+ for (i = 0 ; i < num_regions; i++) {
+ struct ocmem_hw_region *region = ®ion_ctrl[i];
+ seq_printf(f, "Region %u mode %x\n", i, region->mode);
+ for (j = 0; j < num_banks; j++) {
+ m_state = read_macro_state(i, j);
+ if (m_state == MACRO_ON)
+ seq_printf(f, "M%u:%s\t", j, "ON");
+ else if (m_state == MACRO_SLEEP_RETENTION)
+ seq_printf(f, "M%u:%s\t", j, "RETENTION");
+ else
+ seq_printf(f, "M%u:%s\t", j, "OFF");
+ }
+ seq_printf(f, "\n");
+ }
+ mutex_unlock(®ion_ctrl_lock);
+ return 0;
+}
+
+#ifdef CONFIG_MSM_OCMEM_POWER_DEBUG
+static int ocmem_power_show_hw_state(struct seq_file *f, void *dummy)
+{
+ unsigned i = 0;
+ unsigned r_state;
+
+ mutex_lock(®ion_ctrl_lock);
+
+ seq_printf(f, "OCMEM Hardware Power States\n");
+ for (i = 0 ; i < num_regions; i++) {
+ struct ocmem_hw_region *region = ®ion_ctrl[i];
+ seq_printf(f, "Region %u mode %x ", i, region->mode);
+ r_state = read_hw_region_state(i);
+ if (r_state == REGION_DEFAULT_ON)
+ seq_printf(f, "state: %s\t", "REGION_ON");
+ else if (r_state == MACRO_SLEEP_RETENTION)
+ seq_printf(f, "state: %s\t", "REGION_RETENTION");
+ else
+ seq_printf(f, "state: %s\t", "REGION_OFF");
+ seq_printf(f, "\n");
+ }
+ mutex_unlock(®ion_ctrl_lock);
+ return 0;
+}
+#else
+static int ocmem_power_show_hw_state(struct seq_file *f, void *dummy)
+{
+ return 0;
+}
+#endif
+
+static int ocmem_power_show(struct seq_file *f, void *dummy)
+{
+ ocmem_power_show_sw_state(f, dummy);
+ ocmem_power_show_hw_state(f, dummy);
+ return 0;
+}
+
+static int ocmem_power_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, ocmem_power_show, inode->i_private);
+}
+
+static const struct file_operations power_show_fops = {
+ .open = ocmem_power_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
int ocmem_core_init(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -785,8 +860,14 @@
return rc;
ocmem_disable_core_clock();
- return 0;
+ if (!debugfs_create_file("power_state", S_IRUGO, pdata->debug_node,
+ NULL, &power_show_fops)) {
+ dev_err(dev, "Unable to create debugfs node for power state\n");
+ return -EBUSY;
+ }
+
+ return 0;
err_no_mem:
pr_err("ocmem: Unable to allocate memory\n");
region_init_error:
diff --git a/arch/arm/mach-msm/ocmem_sched.c b/arch/arm/mach-msm/ocmem_sched.c
index 54510c9..c95728e 100644
--- a/arch/arm/mach-msm/ocmem_sched.c
+++ b/arch/arm/mach-msm/ocmem_sched.c
@@ -244,6 +244,15 @@
return ret_addr;
}
+static inline struct ocmem_zone *zone_of(struct ocmem_req *req)
+{
+ int owner;
+ if (!req)
+ return NULL;
+ owner = req->owner;
+ return get_zone(owner);
+}
+
static int insert_region(struct ocmem_region *region)
{
@@ -838,7 +847,6 @@
if (matched_req != req)
goto invalid_op_error;
-
ret = zone->z_ops->free(zone,
matched_req->req_start, matched_req->req_sz);
@@ -1317,6 +1325,8 @@
if (rc < 0)
return -EINVAL;
+ inc_ocmem_stat(zone_of(req), NR_FREES);
+
ocmem_destroy_req(req);
handle->req = NULL;
@@ -1393,14 +1403,16 @@
goto transfer_out_error;
}
+ inc_ocmem_stat(zone_of(req), NR_TRANSFERS_TO_DDR);
+
rc = queue_transfer(req, handle, list, TO_DDR);
if (rc < 0) {
pr_err("Failed to queue rdm transfer to DDR\n");
+ inc_ocmem_stat(zone_of(req), NR_TRANSFER_FAILS);
goto transfer_out_error;
}
-
return 0;
transfer_out_error:
@@ -1429,10 +1441,13 @@
goto transfer_in_error;
}
+ inc_ocmem_stat(zone_of(req), NR_TRANSFERS_TO_OCMEM);
+
rc = queue_transfer(req, handle, list, TO_OCMEM);
if (rc < 0) {
pr_err("Failed to queue rdm transfer to OCMEM\n");
+ inc_ocmem_stat(zone_of(req), NR_TRANSFER_FAILS);
goto transfer_in_error;
}
@@ -1469,6 +1484,8 @@
if (is_tcm(req->owner))
do_unmap(req);
+ inc_ocmem_stat(zone_of(req), NR_SHRINKS);
+
if (size == 0) {
pr_info("req %p being shrunk to zero\n", req);
rc = do_free(req);
@@ -1551,6 +1568,8 @@
req->edata = edata;
buffer.addr = req->req_start;
buffer.len = 0x0;
+ inc_ocmem_stat(zone_of(req),
+ NR_EVICTIONS);
dispatch_notification(req->owner,
OCMEM_ALLOC_SHRINK, &buffer);
}
@@ -1580,8 +1599,10 @@
rc = __sched_allocate(req, can_block, can_wait);
mutex_unlock(&sched_mutex);
- if (rc == OP_FAIL)
+ if (rc == OP_FAIL) {
+ inc_ocmem_stat(zone_of(req), NR_ALLOCATION_FAILS);
goto err_allocate_fail;
+ }
if (rc == OP_RESCHED) {
buffer->addr = 0x0;
@@ -1591,6 +1612,7 @@
} else if (rc == OP_PARTIAL) {
buffer->addr = device_address(req->owner, req->req_start);
buffer->len = req->req_sz;
+ inc_ocmem_stat(zone_of(req), NR_RANGE_ALLOCATIONS);
pr_debug("ocmem: Enqueuing req %p\n", req);
sched_enqueue(req);
} else if (rc == OP_COMPLETE) {
@@ -1622,6 +1644,7 @@
list_del(&req->sched_list);
req->op = SCHED_ALLOCATE;
sched_enqueue(req);
+ inc_ocmem_stat(zone_of(req), NR_RESTORES);
}
}
kfree(edata);
@@ -1668,11 +1691,15 @@
req->op = SCHED_ALLOCATE;
req->buffer = buffer;
+ inc_ocmem_stat(zone_of(req), NR_REQUESTS);
+
rc = do_allocate(req, can_block, can_wait);
if (rc < 0)
goto do_allocate_error;
+ inc_ocmem_stat(zone_of(req), NR_SYNC_ALLOCATIONS);
+
handle->req = req;
if (is_tcm(id)) {
@@ -1717,10 +1744,11 @@
rc = do_allocate(req, true, false);
-
if (rc < 0)
goto do_allocate_error;
+ inc_ocmem_stat(zone_of(req), NR_ASYNC_ALLOCATIONS);
+
if (is_tcm(id)) {
rc = process_map(req, req->req_start, req->req_end);
if (rc < 0)
@@ -1788,10 +1816,51 @@
return;
}
-int ocmem_sched_init(void)
+static int ocmem_allocations_show(struct seq_file *f, void *dummy)
+{
+ struct rb_node *rb_node = NULL;
+ struct ocmem_req *req = NULL;
+ unsigned j;
+ mutex_lock(&sched_mutex);
+ for (rb_node = rb_first(&sched_tree); rb_node;
+ rb_node = rb_next(rb_node)) {
+ struct ocmem_region *tmp_region = NULL;
+ tmp_region = rb_entry(rb_node, struct ocmem_region, region_rb);
+ for (j = MAX_OCMEM_PRIO - 1; j > NO_PRIO; j--) {
+ req = find_req_match(j, tmp_region);
+ if (req) {
+ seq_printf(f,
+ "owner: %s 0x%lx -- 0x%lx size 0x%lx [state: %2lx]\n",
+ get_name(req->owner),
+ req->req_start, req->req_end,
+ req->req_sz, req->state);
+ }
+ }
+ }
+ mutex_unlock(&sched_mutex);
+ return 0;
+}
+
+static int ocmem_allocations_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, ocmem_allocations_show, inode->i_private);
+}
+
+static const struct file_operations allocations_show_fops = {
+ .open = ocmem_allocations_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+int ocmem_sched_init(struct platform_device *pdev)
{
int i = 0;
+ struct ocmem_plat_data *pdata = NULL;
+ struct device *dev = &pdev->dev;
+
sched_tree = RB_ROOT;
+ pdata = platform_get_drvdata(pdev);
mutex_init(&sched_mutex);
mutex_init(&sched_queue_mutex);
for (i = MIN_PRIO; i < MAX_OCMEM_PRIO; i++)
@@ -1805,5 +1874,11 @@
ocmem_eviction_wq = alloc_workqueue("ocmem_eviction_wq", 0, 0);
if (!ocmem_eviction_wq)
return -ENOMEM;
+
+ if (!debugfs_create_file("allocations", S_IRUGO, pdata->debug_node,
+ NULL, &allocations_show_fops)) {
+ dev_err(dev, "Unable to create debugfs node for scheduler\n");
+ return -EBUSY;
+ }
return 0;
}
diff --git a/arch/arm/mach-msm/pil-q6v5-lpass.c b/arch/arm/mach-msm/pil-q6v5-lpass.c
index 44d8bc6..ed072ea 100644
--- a/arch/arm/mach-msm/pil-q6v5-lpass.c
+++ b/arch/arm/mach-msm/pil-q6v5-lpass.c
@@ -21,6 +21,7 @@
#include <mach/clk.h>
#include "peripheral-loader.h"
#include "pil-q6v5.h"
+#include "scm-pas.h"
#define QDSP6SS_RST_EVB 0x010
#define PROXY_TIMEOUT_MS 10000
@@ -122,6 +123,30 @@
.shutdown = pil_lpass_shutdown,
};
+static int pil_lpass_init_image_trusted(struct pil_desc *pil,
+ const u8 *metadata, size_t size)
+{
+ return pas_init_image(PAS_Q6, metadata, size);
+}
+
+static int pil_lpass_reset_trusted(struct pil_desc *pil)
+{
+ return pas_auth_and_reset(PAS_Q6);
+}
+
+static int pil_lpass_shutdown_trusted(struct pil_desc *pil)
+{
+ return pas_shutdown(PAS_Q6);
+}
+
+static struct pil_reset_ops pil_lpass_ops_trusted = {
+ .init_image = pil_lpass_init_image_trusted,
+ .proxy_vote = pil_q6v5_make_proxy_votes,
+ .proxy_unvote = pil_q6v5_remove_proxy_votes,
+ .auth_and_reset = pil_lpass_reset_trusted,
+ .shutdown = pil_lpass_shutdown_trusted,
+};
+
static int __devinit pil_lpass_driver_probe(struct platform_device *pdev)
{
struct q6v5_data *drv;
@@ -155,6 +180,14 @@
if (IS_ERR(drv->reg_clk))
return PTR_ERR(drv->reg_clk);
+ if (pas_supported(PAS_Q6) > 0) {
+ desc->ops = &pil_lpass_ops_trusted;
+ dev_info(&pdev->dev, "using secure boot\n");
+ } else {
+ desc->ops = &pil_lpass_ops;
+ dev_info(&pdev->dev, "using non-secure boot\n");
+ }
+
drv->pil = msm_pil_register(desc);
if (IS_ERR(drv->pil))
return PTR_ERR(drv->pil);
diff --git a/arch/arm/mach-msm/pm.h b/arch/arm/mach-msm/pm.h
index 4dd6df3..552fb16 100644
--- a/arch/arm/mach-msm/pm.h
+++ b/arch/arm/mach-msm/pm.h
@@ -80,6 +80,11 @@
bool notify_rpm, bool collapsed);
};
+struct msm_pm_cpr_ops {
+ void (*cpr_suspend)(void);
+ void (*cpr_resume)(void);
+};
+
void msm_pm_set_platform_data(struct msm_pm_platform_data *data, int count);
int msm_pm_idle_prepare(struct cpuidle_device *dev,
struct cpuidle_driver *drv, int index);
@@ -125,4 +130,6 @@
static inline void msm_pm_add_stat(enum msm_pm_time_stats_id id, int64_t t) {}
#endif
+void msm_pm_set_cpr_ops(struct msm_pm_cpr_ops *ops);
+
#endif /* __ARCH_ARM_MACH_MSM_PM_H */
diff --git a/arch/arm/mach-msm/pm2.c b/arch/arm/mach-msm/pm2.c
index 8fccda4..10c5445 100644
--- a/arch/arm/mach-msm/pm2.c
+++ b/arch/arm/mach-msm/pm2.c
@@ -152,6 +152,7 @@
static struct msm_pm_platform_data *msm_pm_modes;
static struct msm_pm_irq_calls *msm_pm_irq_extns;
+static struct msm_pm_cpr_ops *msm_cpr_ops;
struct msm_pm_kobj_attribute {
unsigned int cpu;
@@ -415,6 +416,11 @@
msm_pm_irq_extns = irq_calls;
}
+void __init msm_pm_set_cpr_ops(struct msm_pm_cpr_ops *ops)
+{
+ msm_cpr_ops = ops;
+}
+
/******************************************************************************
* Sleep Limitations
*****************************************************************************/
@@ -876,6 +882,10 @@
WARN_ON(ret);
}
+ /* Call CPR suspend only for "idlePC" case */
+ if (msm_cpr_ops && from_idle)
+ msm_cpr_ops->cpr_suspend();
+
msm_pm_irq_extns->enter_sleep1(true, from_idle,
&msm_pm_smem_data->irq_mask);
msm_sirc_enter_sleep();
@@ -1113,6 +1123,10 @@
WARN_ON(ret);
}
+ /* Call CPR resume only for "idlePC" case */
+ if (msm_cpr_ops && from_idle)
+ msm_cpr_ops->cpr_resume();
+
return 0;
power_collapse_early_exit:
@@ -1165,6 +1179,10 @@
if (collapsed)
smd_sleep_exit();
+ /* Call CPR resume only for "idlePC" case */
+ if (msm_cpr_ops && from_idle)
+ msm_cpr_ops->cpr_resume();
+
power_collapse_bail:
if (cpu_is_msm8625()) {
ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_CLOCK_GATING,
diff --git a/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.c b/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.c
index 2874700..5400ccc 100644
--- a/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.c
+++ b/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.c
@@ -10,8 +10,6 @@
* GNU General Public License for more details.
*
*/
-
-#include <linux/module.h>
#include <linux/fs.h>
#include <linux/mutex.h>
#include <linux/wait.h>
@@ -355,8 +353,6 @@
usc->priv);
break;
default:
- pr_debug("%s: command[0x%x] wrong response\n",
- __func__, payload[0]);
break;
}
}
@@ -367,19 +363,6 @@
case USM_DATA_EVENT_READ_DONE: {
struct us_port_data *port = &usc->port[OUT];
- pr_debug("%s: R-D: stat=%d; buff=%x; size=%d; off=%d\n",
- __func__,
- payload[READDONE_IDX_STATUS],
- payload[READDONE_IDX_BUFFER],
- payload[READDONE_IDX_SIZE],
- payload[READDONE_IDX_OFFSET]);
- pr_debug("msw_ts=%d; lsw_ts=%d; flags=%d; id=%d; num=%d\n",
- payload[READDONE_IDX_MSW_TS],
- payload[READDONE_IDX_LSW_TS],
- payload[READDONE_IDX_FLAGS],
- payload[READDONE_IDX_ID],
- payload[READDONE_IDX_NUMFRAMES]);
-
spin_lock_irqsave(&port->dsp_lock, dsp_flags);
if (payload[READDONE_IDX_STATUS]) {
pr_err("%s: wrong READDONE[%d]; token[%d]\n",
@@ -425,10 +408,6 @@
case USM_DATA_EVENT_WRITE_DONE: {
struct us_port_data *port = &usc->port[IN];
- pr_debug("%s W-D: code[0x%x]; status[0x%x]; token[%d]",
- __func__,
- payload[0], payload[1], token);
-
if (payload[WRITEDONE_IDX_STATUS]) {
pr_err("%s: wrong WRITEDONE_IDX_STATUS[%d]\n",
__func__,
@@ -442,10 +421,6 @@
port->dsp_buf = 0;
spin_unlock_irqrestore(&port->dsp_lock, dsp_flags);
- pr_debug("%s: WRITE_DONE: token=%d; dsp_buf=%d; cpu_buf=%d\n",
- __func__,
- token, port->dsp_buf, port->cpu_buf);
-
break;
} /* case USM_DATA_EVENT_WRITE_DONE */
@@ -458,8 +433,6 @@
} /* case USM_SESSION_EVENT_SIGNAL_DETECT_RESULT */
default:
- pr_debug("%s: not supported code [0x%x]",
- __func__, data->opcode);
return 0;
} /* switch */
@@ -498,9 +471,6 @@
static void q6usm_add_hdr(struct us_client *usc, struct apr_hdr *hdr,
uint32_t pkt_size, bool cmd_flg)
{
- pr_debug("%s: pkt size=%d; cmd_flg=%d\n",
- __func__, pkt_size, cmd_flg);
- pr_debug("**************\n");
mutex_lock(&usc->cmd_lock);
hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, \
APR_HDR_LEN(sizeof(struct apr_hdr)),\
@@ -523,9 +493,6 @@
static void q6usm_add_mmaphdr(struct us_client *usc, struct apr_hdr *hdr,
uint32_t pkt_size, bool cmd_flg)
{
- pr_debug("%s: pkt size=%d cmd_flg=%d\n",
- __func__, pkt_size, cmd_flg);
- pr_debug("**************\n");
hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, \
APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
hdr->src_port = 0;
@@ -1067,11 +1034,6 @@
cmd_write.uid = port->cpu_buf;
cmd_write.hdr.token = port->cpu_buf;
- pr_debug("%s:buf addr[0x%x] size[%d] token[%d] uid[%d]\n",
- __func__, cmd_write.buf_add, cmd_write.buf_size,
- cmd_write.hdr.token, cmd_write.uid);
- pr_debug("%s: data=0x%p\n", __func__, port->data);
-
++(port->cpu_buf);
if (port->cpu_buf == port->buf_cnt)
port->cpu_buf = 0;
@@ -1089,9 +1051,6 @@
rc = 0;
}
- pr_debug("%s:exit: rc=%d; write_ind=%d; cpu_buf=%d; dsp_buf=%d\n",
- __func__, rc, write_ind, port->cpu_buf, port->dsp_buf);
-
return rc;
}
@@ -1136,8 +1095,6 @@
goto fail_cmd;
}
- pr_debug("%s:session[%d]opcode[0x%x] ", __func__,
- usc->session, hdr.opcode);
rc = apr_send_pkt(usc->apr, (uint32_t *) &hdr);
if (rc < 0) {
pr_err("%s: Command 0x%x failed\n", __func__, hdr.opcode);
@@ -1204,6 +1161,3 @@
}
device_initcall(q6usm_init);
-
-MODULE_DESCRIPTION("Interface with QDSP6:USM");
-MODULE_VERSION(DRV_VERSION);
diff --git a/arch/arm/mach-msm/rpm-regulator-8930.c b/arch/arm/mach-msm/rpm-regulator-8930.c
index 3878e22..9133856 100644
--- a/arch/arm/mach-msm/rpm-regulator-8930.c
+++ b/arch/arm/mach-msm/rpm-regulator-8930.c
@@ -111,51 +111,64 @@
};
#define LDO(_id, _name, _name_pc, _ranges, _hpm_min_load, _requires_cxo) \
- [RPM_VREG_ID_PM8038_##_id] = { \
+ [RPM_VREG_ID_PM##_id] = { \
.req = { \
- [0] = { .id = MSM_RPM_ID_PM8038_##_id##_0, }, \
- [1] = { .id = MSM_RPM_ID_PM8038_##_id##_1, }, \
+ [0] = { .id = MSM_RPM_ID_PM##_id##_0, }, \
+ [1] = { .id = MSM_RPM_ID_PM##_id##_1, }, \
}, \
.hpm_min_load = RPM_VREG_8930_##_hpm_min_load##_HPM_MIN_LOAD, \
.type = RPM_REGULATOR_TYPE_LDO, \
.set_points = &_ranges##_set_points, \
.part = &ldo_parts, \
- .id = RPM_VREG_ID_PM8038_##_id, \
+ .id = RPM_VREG_ID_PM##_id, \
.rdesc.name = _name, \
.rdesc_pc.name = _name_pc, \
.requires_cxo = _requires_cxo, \
}
#define SMPS(_id, _name, _name_pc, _ranges, _hpm_min_load) \
- [RPM_VREG_ID_PM8038_##_id] = { \
+ [RPM_VREG_ID_PM##_id] = { \
.req = { \
- [0] = { .id = MSM_RPM_ID_PM8038_##_id##_0, }, \
- [1] = { .id = MSM_RPM_ID_PM8038_##_id##_1, }, \
+ [0] = { .id = MSM_RPM_ID_PM##_id##_0, }, \
+ [1] = { .id = MSM_RPM_ID_PM##_id##_1, }, \
}, \
.hpm_min_load = RPM_VREG_8930_##_hpm_min_load##_HPM_MIN_LOAD, \
.type = RPM_REGULATOR_TYPE_SMPS, \
.set_points = &_ranges##_set_points, \
.part = &smps_parts, \
- .id = RPM_VREG_ID_PM8038_##_id, \
+ .id = RPM_VREG_ID_PM##_id, \
.rdesc.name = _name, \
.rdesc_pc.name = _name_pc, \
}
#define LVS(_id, _name, _name_pc) \
- [RPM_VREG_ID_PM8038_##_id] = { \
+ [RPM_VREG_ID_PM##_id] = { \
.req = { \
- [0] = { .id = MSM_RPM_ID_PM8038_##_id, }, \
+ [0] = { .id = MSM_RPM_ID_PM##_id, }, \
[1] = { .id = -1, }, \
}, \
.type = RPM_REGULATOR_TYPE_VS, \
.part = &switch_parts, \
- .id = RPM_VREG_ID_PM8038_##_id, \
+ .id = RPM_VREG_ID_PM##_id, \
+ .rdesc.name = _name, \
+ .rdesc_pc.name = _name_pc, \
+ }
+
+#define MVS(_vreg_id, _name, _name_pc, _rpm_id) \
+ [RPM_VREG_ID_PM##_vreg_id] = { \
+ .req = { \
+ [0] = { .id = MSM_RPM_ID_##_rpm_id, }, \
+ [1] = { .id = -1, }, \
+ }, \
+ .type = RPM_REGULATOR_TYPE_VS, \
+ .part = &switch_parts, \
+ .id = RPM_VREG_ID_PM##_vreg_id, \
.rdesc.name = _name, \
.rdesc_pc.name = _name_pc, \
}
#define CORNER(_id, _rpm_id, _name, _ranges) \
- [RPM_VREG_ID_PM8038_##_id] = { \
+ [RPM_VREG_ID_PM##_id] = { \
.req = { \
[0] = { .id = MSM_RPM_ID_##_rpm_id, }, \
[1] = { .id = -1, }, \
@@ -163,50 +176,105 @@
.type = RPM_REGULATOR_TYPE_CORNER, \
.set_points = &_ranges##_set_points, \
.part = &corner_parts, \
- .id = RPM_VREG_ID_PM8038_##_id, \
+ .id = RPM_VREG_ID_PM##_id, \
.rdesc.name = _name, \
}
-static struct vreg vregs[] = {
- LDO(L1, "8038_l1", NULL, nldo1200, LDO_1200, 1),
- LDO(L2, "8038_l2", "8038_l2_pc", nldo, LDO_150, 1),
- LDO(L3, "8038_l3", "8038_l3_pc", pldo, LDO_50, 0),
- LDO(L4, "8038_l4", "8038_l4_pc", pldo, LDO_50, 0),
- LDO(L5, "8038_l5", "8038_l5_pc", pldo, LDO_600, 0),
- LDO(L6, "8038_l6", "8038_l6_pc", pldo, LDO_600, 0),
- LDO(L7, "8038_l7", "8038_l7_pc", pldo, LDO_600, 0),
- LDO(L8, "8038_l8", "8038_l8_pc", pldo, LDO_300, 0),
- LDO(L9, "8038_l9", "8038_l9_pc", pldo, LDO_300, 0),
- LDO(L10, "8038_l10", "8038_l10_pc", pldo, LDO_600, 0),
- LDO(L11, "8038_l11", "8038_l11_pc", pldo, LDO_600, 0),
- LDO(L12, "8038_l12", "8038_l12_pc", nldo, LDO_300, 1),
- LDO(L13, "8038_l13", NULL, ln_ldo, LDO_5, 0),
- LDO(L14, "8038_l14", "8038_l14_pc", pldo, LDO_50, 0),
- LDO(L15, "8038_l15", "8038_l15_pc", pldo, LDO_150, 0),
- LDO(L16, "8038_l16", NULL, nldo1200, LDO_1200, 1),
- LDO(L17, "8038_l17", "8038_l17_pc", pldo, LDO_150, 0),
- LDO(L18, "8038_l18", "8038_l18_pc", pldo, LDO_50, 0),
- LDO(L19, "8038_l19", NULL, nldo1200, LDO_1200, 1),
- LDO(L20, "8038_l20", NULL, nldo1200, LDO_1200, 1),
- LDO(L21, "8038_l21", "8038_l21_pc", pldo, LDO_150, 0),
- LDO(L22, "8038_l22", "8038_l22_pc", pldo, LDO_50, 0),
- LDO(L23, "8038_l23", "8038_l23_pc", pldo, LDO_50, 0),
- LDO(L24, "8038_l24", NULL, nldo1200, LDO_1200, 1),
- LDO(L25, "8038_l25", NULL, ln_ldo, LDO_5, 0),
- LDO(L26, "8038_l26", "8038_l26_pc", nldo, LDO_150, 1),
- LDO(L27, "8038_l27", NULL, nldo1200, LDO_1200, 1),
+static struct vreg vregs_msm8930_pm8038[] = {
+ LDO(8038_L1, "8038_l1", NULL, nldo1200, LDO_1200, 1),
+ LDO(8038_L2, "8038_l2", "8038_l2_pc", nldo, LDO_150, 1),
+ LDO(8038_L3, "8038_l3", "8038_l3_pc", pldo, LDO_50, 0),
+ LDO(8038_L4, "8038_l4", "8038_l4_pc", pldo, LDO_50, 0),
+ LDO(8038_L5, "8038_l5", "8038_l5_pc", pldo, LDO_600, 0),
+ LDO(8038_L6, "8038_l6", "8038_l6_pc", pldo, LDO_600, 0),
+ LDO(8038_L7, "8038_l7", "8038_l7_pc", pldo, LDO_600, 0),
+ LDO(8038_L8, "8038_l8", "8038_l8_pc", pldo, LDO_300, 0),
+ LDO(8038_L9, "8038_l9", "8038_l9_pc", pldo, LDO_300, 0),
+ LDO(8038_L10, "8038_l10", "8038_l10_pc", pldo, LDO_600, 0),
+ LDO(8038_L11, "8038_l11", "8038_l11_pc", pldo, LDO_600, 0),
+ LDO(8038_L12, "8038_l12", "8038_l12_pc", nldo, LDO_300, 1),
+ LDO(8038_L13, "8038_l13", NULL, ln_ldo, LDO_5, 0),
+ LDO(8038_L14, "8038_l14", "8038_l14_pc", pldo, LDO_50, 0),
+ LDO(8038_L15, "8038_l15", "8038_l15_pc", pldo, LDO_150, 0),
+ LDO(8038_L16, "8038_l16", NULL, nldo1200, LDO_1200, 1),
+ LDO(8038_L17, "8038_l17", "8038_l17_pc", pldo, LDO_150, 0),
+ LDO(8038_L18, "8038_l18", "8038_l18_pc", pldo, LDO_50, 0),
+ LDO(8038_L19, "8038_l19", NULL, nldo1200, LDO_1200, 1),
+ LDO(8038_L20, "8038_l20", NULL, nldo1200, LDO_1200, 1),
+ LDO(8038_L21, "8038_l21", "8038_l21_pc", pldo, LDO_150, 0),
+ LDO(8038_L22, "8038_l22", "8038_l22_pc", pldo, LDO_50, 0),
+ LDO(8038_L23, "8038_l23", "8038_l23_pc", pldo, LDO_50, 0),
+ LDO(8038_L24, "8038_l24", NULL, nldo1200, LDO_1200, 1),
+ LDO(8038_L25, "8038_l25", NULL, ln_ldo, LDO_5, 0),
+ LDO(8038_L26, "8038_l26", "8038_l26_pc", nldo, LDO_150, 1),
+ LDO(8038_L27, "8038_l27", NULL, nldo1200, LDO_1200, 1),
- SMPS(S1, "8038_s1", "8038_s1_pc", smps, SMPS_1500),
- SMPS(S2, "8038_s2", "8038_s2_pc", smps, SMPS_1500),
- SMPS(S3, "8038_s3", "8038_s3_pc", smps, SMPS_1500),
- SMPS(S4, "8038_s4", "8038_s4_pc", smps, SMPS_1500),
- SMPS(S5, "8038_s5", NULL, ftsmps, SMPS_2000),
- SMPS(S6, "8038_s6", NULL, ftsmps, SMPS_2000),
+ SMPS(8038_S1, "8038_s1", "8038_s1_pc", smps, SMPS_1500),
+ SMPS(8038_S2, "8038_s2", "8038_s2_pc", smps, SMPS_1500),
+ SMPS(8038_S3, "8038_s3", "8038_s3_pc", smps, SMPS_1500),
+ SMPS(8038_S4, "8038_s4", "8038_s4_pc", smps, SMPS_1500),
+ SMPS(8038_S5, "8038_s5", NULL, ftsmps, SMPS_2000),
+ SMPS(8038_S6, "8038_s6", NULL, ftsmps, SMPS_2000),
- LVS(LVS1, "8038_lvs1", "8038_lvs1_pc"),
- LVS(LVS2, "8038_lvs2", "8038_lvs2_pc"),
+ LVS(8038_LVS1, "8038_lvs1", "8038_lvs1_pc"),
+ LVS(8038_LVS2, "8038_lvs2", "8038_lvs2_pc"),
- CORNER(VDD_DIG_CORNER, VOLTAGE_CORNER, "vdd_dig_corner", corner),
+ CORNER(8038_VDD_DIG_CORNER, VOLTAGE_CORNER, "vdd_dig_corner", corner),
+};
+
+static struct vreg vregs_msm8930_pm8917[] = {
+ LDO(8917_L1, "8917_l1", "8917_l1_pc", nldo, LDO_150, 1),
+ LDO(8917_L2, "8917_l2", "8917_l2_pc", nldo, LDO_150, 1),
+ LDO(8917_L3, "8917_l3", "8917_l3_pc", pldo, LDO_150, 0),
+ LDO(8917_L4, "8917_l4", "8917_l4_pc", pldo, LDO_50, 0),
+ LDO(8917_L5, "8917_l5", "8917_l5_pc", pldo, LDO_300, 0),
+ LDO(8917_L6, "8917_l6", "8917_l6_pc", pldo, LDO_600, 0),
+ LDO(8917_L7, "8917_l7", "8917_l7_pc", pldo, LDO_150, 0),
+ LDO(8917_L8, "8917_l8", "8917_l8_pc", pldo, LDO_300, 0),
+ LDO(8917_L9, "8917_l9", "8917_l9_pc", pldo, LDO_300, 0),
+ LDO(8917_L10, "8917_l10", "8917_l10_pc", pldo, LDO_600, 0),
+ LDO(8917_L11, "8917_l11", "8917_l11_pc", pldo, LDO_150, 0),
+ LDO(8917_L12, "8917_l12", "8917_l12_pc", nldo, LDO_150, 1),
+ LDO(8917_L14, "8917_l14", "8917_l14_pc", pldo, LDO_50, 0),
+ LDO(8917_L15, "8917_l15", "8917_l15_pc", pldo, LDO_150, 0),
+ LDO(8917_L16, "8917_l16", "8917_l16_pc", pldo, LDO_300, 0),
+ LDO(8917_L17, "8917_l17", "8917_l17_pc", pldo, LDO_150, 0),
+ LDO(8917_L18, "8917_l18", "8917_l18_pc", nldo, LDO_150, 1),
+ LDO(8917_L21, "8917_l21", "8917_l21_pc", pldo, LDO_150, 0),
+ LDO(8917_L22, "8917_l22", "8917_l22_pc", pldo, LDO_150, 0),
+ LDO(8917_L23, "8917_l23", "8917_l23_pc", pldo, LDO_150, 0),
+ LDO(8917_L24, "8917_l24", NULL, nldo1200, LDO_1200, 0),
+ LDO(8917_L25, "8917_l25", NULL, nldo1200, LDO_1200, 0),
+ LDO(8917_L26, "8917_l26", NULL, nldo1200, LDO_1200, 0),
+ LDO(8917_L27, "8917_l27", NULL, nldo1200, LDO_1200, 0),
+ LDO(8917_L28, "8917_l28", NULL, nldo1200, LDO_1200, 0),
+ LDO(8917_L29, "8917_l29", "8917_l29_pc", pldo, LDO_150, 0),
+ LDO(8917_L30, "8917_l30", "8917_l30_pc", pldo, LDO_150, 0),
+ LDO(8917_L31, "8917_l31", "8917_l31_pc", pldo, LDO_150, 0),
+ LDO(8917_L32, "8917_l32", "8917_l32_pc", pldo, LDO_150, 0),
+ LDO(8917_L33, "8917_l33", "8917_l33_pc", pldo, LDO_150, 0),
+ LDO(8917_L34, "8917_l34", "8917_l34_pc", pldo, LDO_150, 0),
+ LDO(8917_L35, "8917_l35", "8917_l35_pc", pldo, LDO_300, 0),
+ LDO(8917_L36, "8917_l36", "8917_l36_pc", pldo, LDO_50, 0),
+
+ SMPS(8917_S1, "8917_s1", "8917_s1_pc", smps, SMPS_1500),
+ SMPS(8917_S2, "8917_s2", "8917_s2_pc", smps, SMPS_1500),
+ SMPS(8917_S3, "8917_s3", "8917_s3_pc", smps, SMPS_1500),
+ SMPS(8917_S4, "8917_s4", "8917_s4_pc", smps, SMPS_1500),
+ SMPS(8917_S5, "8917_s5", NULL, ftsmps, SMPS_2000),
+ SMPS(8917_S6, "8917_s6", NULL, ftsmps, SMPS_2000),
+ SMPS(8917_S7, "8917_s7", "8917_s7_pc", smps, SMPS_1500),
+ SMPS(8917_S8, "8917_s8", "8917_s8_pc", smps, SMPS_1500),
+
+ LVS(8917_LVS1, "8917_lvs1", "8917_lvs1_pc"),
+ LVS(8917_LVS3, "8917_lvs3", "8917_lvs3_pc"),
+ LVS(8917_LVS4, "8917_lvs4", "8917_lvs4_pc"),
+ LVS(8917_LVS5, "8917_lvs5", "8917_lvs5_pc"),
+ LVS(8917_LVS6, "8917_lvs6", "8917_lvs6_pc"),
+ LVS(8917_LVS7, "8917_lvs7", "8917_lvs7_pc"),
+ MVS(8917_USB_OTG, "8917_usb_otg", NULL, USB_OTG_SWITCH),
+
+ CORNER(8917_VDD_DIG_CORNER, VOLTAGE_CORNER, "vdd_dig_corner", corner),
};
static const char *pin_func_label[] = {
@@ -237,17 +305,18 @@
" A2",
};
-static int is_real_id(int id)
+static int is_real_id_msm8930_pm8038(int id)
{
return (id >= 0) && (id <= RPM_VREG_ID_PM8038_MAX_REAL);
}
-static int pc_id_to_real_id(int id)
+static int pc_id_to_real_id_msm8930_pm8038(int id)
{
int real_id = 0;
if (id >= RPM_VREG_ID_PM8038_L2_PC && id <= RPM_VREG_ID_PM8038_L12_PC)
- real_id = id - RPM_VREG_ID_PM8038_L2_PC;
+ real_id = id - RPM_VREG_ID_PM8038_L2_PC
+ + RPM_VREG_ID_PM8038_L2;
else if (id >= RPM_VREG_ID_PM8038_L14_PC
&& id <= RPM_VREG_ID_PM8038_L15_PC)
real_id = id - RPM_VREG_ID_PM8038_L14_PC
@@ -274,9 +343,33 @@
return real_id;
}
-static struct vreg_config config = {
- .vregs = vregs,
- .vregs_len = ARRAY_SIZE(vregs),
+static int is_real_id_msm8930_pm8917(int id)
+{
+ return (id >= 0) && (id <= RPM_VREG_ID_PM8917_MAX_REAL);
+}
+
+static int pc_id_to_real_id_msm8930_pm8917(int id)
+{
+ int real_id = 0;
+
+ if (id >= RPM_VREG_ID_PM8917_L1_PC && id <= RPM_VREG_ID_PM8917_L23_PC)
+ real_id = id - RPM_VREG_ID_PM8917_L1_PC
+ + RPM_VREG_ID_PM8917_L1;
+ else if (id >= RPM_VREG_ID_PM8917_L29_PC
+ && id <= RPM_VREG_ID_PM8917_S4_PC)
+ real_id = id - RPM_VREG_ID_PM8917_L29_PC
+ + RPM_VREG_ID_PM8917_L29;
+ else if (id >= RPM_VREG_ID_PM8917_S7_PC
+ && id <= RPM_VREG_ID_PM8917_LVS7_PC)
+ real_id = id - RPM_VREG_ID_PM8917_S7_PC
+ + RPM_VREG_ID_PM8917_S7;
+
+ return real_id;
+}
+
+static struct vreg_config config_msm8930_pm8038 = {
+ .vregs = vregs_msm8930_pm8038,
+ .vregs_len = ARRAY_SIZE(vregs_msm8930_pm8038),
.vreg_id_min = RPM_VREG_ID_PM8038_L1,
.vreg_id_max = RPM_VREG_ID_PM8038_MAX,
@@ -299,11 +392,45 @@
.label_power_mode = power_mode_label,
.label_power_mode_len = ARRAY_SIZE(power_mode_label),
- .is_real_id = is_real_id,
- .pc_id_to_real_id = pc_id_to_real_id,
+ .is_real_id = is_real_id_msm8930_pm8038,
+ .pc_id_to_real_id = pc_id_to_real_id_msm8930_pm8038,
+};
+
+static struct vreg_config config_msm8930_pm8917 = {
+ .vregs = vregs_msm8930_pm8917,
+ .vregs_len = ARRAY_SIZE(vregs_msm8930_pm8917),
+
+ .vreg_id_min = RPM_VREG_ID_PM8917_L1,
+ .vreg_id_max = RPM_VREG_ID_PM8917_MAX,
+
+ .pin_func_none = RPM_VREG_PIN_FN_8930_NONE,
+ .pin_func_sleep_b = RPM_VREG_PIN_FN_8930_SLEEP_B,
+
+ .mode_lpm = REGULATOR_MODE_IDLE,
+ .mode_hpm = REGULATOR_MODE_NORMAL,
+
+ .set_points = all_set_points,
+ .set_points_len = ARRAY_SIZE(all_set_points),
+
+ .label_pin_ctrl = pin_control_label,
+ .label_pin_ctrl_len = ARRAY_SIZE(pin_control_label),
+ .label_pin_func = pin_func_label,
+ .label_pin_func_len = ARRAY_SIZE(pin_func_label),
+ .label_force_mode = force_mode_label,
+ .label_force_mode_len = ARRAY_SIZE(force_mode_label),
+ .label_power_mode = power_mode_label,
+ .label_power_mode_len = ARRAY_SIZE(power_mode_label),
+
+ .is_real_id = is_real_id_msm8930_pm8917,
+ .pc_id_to_real_id = pc_id_to_real_id_msm8930_pm8917,
};
struct vreg_config *get_config_8930(void)
{
- return &config;
+ return &config_msm8930_pm8038;
+}
+
+struct vreg_config *get_config_8930_pm8917(void)
+{
+ return &config_msm8930_pm8917;
}
diff --git a/arch/arm/mach-msm/rpm-regulator-private.h b/arch/arm/mach-msm/rpm-regulator-private.h
index c3ddc33..d55bd73 100644
--- a/arch/arm/mach-msm/rpm-regulator-private.h
+++ b/arch/arm/mach-msm/rpm-regulator-private.h
@@ -176,11 +176,16 @@
#if defined(CONFIG_MSM_RPM_REGULATOR) && defined(CONFIG_ARCH_MSM8930)
struct vreg_config *get_config_8930(void);
+struct vreg_config *get_config_8930_pm8917(void);
#else
static inline struct vreg_config *get_config_8930(void)
{
return NULL;
}
+static inline struct vreg_config *get_config_8930_pm8917(void)
+{
+ return NULL;
+}
#endif
#endif
diff --git a/arch/arm/mach-msm/rpm-regulator.c b/arch/arm/mach-msm/rpm-regulator.c
index 68ff55b..424a4fe 100644
--- a/arch/arm/mach-msm/rpm-regulator.c
+++ b/arch/arm/mach-msm/rpm-regulator.c
@@ -62,6 +62,7 @@
[RPM_VREG_VERSION_8960] = get_config_8960,
[RPM_VREG_VERSION_9615] = get_config_9615,
[RPM_VREG_VERSION_8930] = get_config_8930,
+ [RPM_VREG_VERSION_8930_PM8917] = get_config_8930_pm8917,
};
static struct rpm_regulator_consumer_mapping *consumer_map;
diff --git a/arch/arm/mach-msm/rpm-smd.c b/arch/arm/mach-msm/rpm-smd.c
index 5b8284d..cd5556a 100644
--- a/arch/arm/mach-msm/rpm-smd.c
+++ b/arch/arm/mach-msm/rpm-smd.c
@@ -62,7 +62,7 @@
#define DEFAULT_BUFFER_SIZE 256
#define GFP_FLAG(noirq) (noirq ? GFP_ATOMIC : GFP_KERNEL)
-#define INV_HDR "resource does not exist"
+#define INV_RSC "resource does not exist"
#define ERR "err\0"
#define MAX_ERR_BUFFER_SIZE 128
#define INIT_ERROR 1
@@ -172,8 +172,10 @@
int i;
int data_size, msg_size;
- if (!handle)
+ if (!handle) {
+ pr_err("%s(): Invalid handle\n", __func__);
return -EINVAL;
+ }
data_size = ALIGN(size, SZ_4);
msg_size = data_size + sizeof(struct rpm_request_header);
@@ -191,8 +193,11 @@
break;
}
- if (i >= handle->num_elements)
+ if (i >= handle->num_elements) {
+ pr_err("%s(): Number of resources exceeds max allocated\n",
+ __func__);
return -ENOMEM;
+ }
if (i == handle->write_idx)
handle->write_idx++;
@@ -200,8 +205,10 @@
if (!handle->kvp[i].value) {
handle->kvp[i].value = kzalloc(data_size, GFP_FLAG(noirq));
- if (!handle->kvp[i].value)
+ if (!handle->kvp[i].value) {
+ pr_err("%s(): Failed malloc\n", __func__);
return -ENOMEM;
+ }
} else {
/* We enter the else case, if a key already exists but the
* data doesn't match. In which case, we should zero the data
@@ -366,13 +373,20 @@
return elem;
}
-static int msm_rpm_get_next_msg_id(void)
+static uint32_t msm_rpm_get_next_msg_id(void)
{
- int id;
+ uint32_t id;
+
+ /*
+ * A message id of 0 is used by the driver to indicate a error
+ * condition. The RPM driver uses a id of 1 to indicate unsent data
+ * when the data sent over hasn't been modified. This isn't a error
+ * scenario and wait for ack returns a success when the message id is 1.
+ */
do {
id = atomic_inc_return(&msm_rpm_msg_id);
- } while ((id == 0) || msm_rpm_get_entry_from_msg_id(id));
+ } while ((id == 0) || (id == 1) || msm_rpm_get_entry_from_msg_id(id));
return id;
}
@@ -459,8 +473,12 @@
tmp += 2 * sizeof(uint32_t);
- if (!(memcmp(tmp, INV_HDR, min(req_len, sizeof(INV_HDR))-1)))
+ if (!(memcmp(tmp, INV_RSC, min(req_len, sizeof(INV_RSC))-1))) {
+ pr_err("%s(): RPM NACK Unsupported resource\n", __func__);
rc = -EINVAL;
+ } else {
+ pr_err("%s(): RPM NACK Invalid header\n", __func__);
+ }
return rc;
}
@@ -658,7 +676,8 @@
int req_hdr_sz, msg_hdr_sz;
if (!cdata->msg_hdr.data_len)
- return 0;
+ return 1;
+
req_hdr_sz = sizeof(cdata->req_hdr);
msg_hdr_sz = sizeof(cdata->msg_hdr);
@@ -676,8 +695,10 @@
cdata->buf = kzalloc(msg_size, GFP_FLAG(noirq));
}
- if (!cdata->buf)
+ if (!cdata->buf) {
+ pr_err("%s(): Failed malloc\n", __func__);
return 0;
+ }
tmpbuff = cdata->buf;
@@ -722,7 +743,7 @@
ret = smd_write_avail(msm_rpm_data.ch_info);
if (ret < 0) {
- pr_warn("%s(): SMD not initialized\n", __func__);
+ pr_err("%s(): SMD not initialized\n", __func__);
spin_unlock_irqrestore(&msm_rpm_data.smd_lock_write, flags);
return 0;
}
@@ -749,7 +770,7 @@
} else if (ret < msg_size) {
struct msm_rpm_wait_data *rc;
ret = 0;
- pr_info("Failed to write data msg_size:%d ret:%d\n",
+ pr_err("Failed to write data msg_size:%d ret:%d\n",
msg_size, ret);
rc = msm_rpm_get_entry_from_msg_id(cdata->msg_hdr.msg_id);
if (rc)
@@ -774,8 +795,13 @@
{
struct msm_rpm_wait_data *elem;
- if (!msg_id)
- return -EINVAL;
+ if (!msg_id) {
+ pr_err("%s(): Invalid msg id\n", __func__);
+ return -ENOMEM;
+ }
+
+ if (msg_id == 1)
+ return 0;
if (standalone)
return 0;
@@ -798,8 +824,13 @@
uint32_t id = 0;
int count = 0;
- if (!msg_id)
- return -EINVAL;
+ if (!msg_id) {
+ pr_err("%s(): Invalid msg id\n", __func__);
+ return -ENOMEM;
+ }
+
+ if (msg_id == 1)
+ return 0;
if (standalone)
return 0;
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index e82e44b..332d9f3 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -361,9 +361,15 @@
static DEFINE_MUTEX(smsm_lock);
static struct smsm_state_info *smsm_states;
static int spinlocks_initialized;
-static RAW_NOTIFIER_HEAD(smsm_driver_state_notifier_list);
-static DEFINE_MUTEX(smsm_driver_state_notifier_lock);
-static void smsm_driver_state_notify(uint32_t state, void *data);
+
+/**
+ * Variables to indicate smd module initialization.
+ * Dependents to register for smd module init notifier.
+ */
+static int smd_module_inited;
+static RAW_NOTIFIER_HEAD(smd_module_init_notifier_list);
+static DEFINE_MUTEX(smd_module_init_notifier_lock);
+static void smd_module_init_notify(uint32_t state, void *data);
static inline void smd_write_intr(unsigned int val,
const void __iomem *addr)
@@ -372,24 +378,6 @@
__raw_writel(val, addr);
}
-#ifdef CONFIG_WCNSS
-static inline void wakeup_v1_riva(void)
-{
- /*
- * workaround hack for RIVA v1 hardware bug
- * trigger GPIO 40 to wake up RIVA from power collaspe
- * not to be sent to customers
- */
- if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 1) {
- __raw_writel(0x0, MSM_TLMM_BASE + 0x1284);
- __raw_writel(0x2, MSM_TLMM_BASE + 0x1284);
- }
- /* end workaround */
-}
-#else
-static inline void wakeup_v1_riva(void) {}
-#endif
-
static inline void notify_modem_smd(void)
{
static const struct interrupt_config_item *intr
@@ -436,7 +424,6 @@
{
static const struct interrupt_config_item *intr
= &private_intr_config[SMD_WCNSS].smd;
- wakeup_v1_riva();
if (intr->out_base) {
++interrupt_stats[SMD_WCNSS].smd_out_config_count;
@@ -506,7 +493,6 @@
{
static const struct interrupt_config_item *intr
= &private_intr_config[SMD_WCNSS].smsm;
- wakeup_v1_riva();
if (intr->out_base) {
++interrupt_stats[SMD_WCNSS].smsm_out_config_count;
@@ -2465,13 +2451,6 @@
int i;
struct smsm_size_info_type *smsm_size_info;
- i = remote_spin_lock_init(&remote_spinlock, SMEM_SPINLOCK_SMEM_ALLOC);
- if (i) {
- pr_err("%s: remote spinlock init failed %d\n", __func__, i);
- return i;
- }
- spinlocks_initialized = 1;
-
smsm_size_info = smem_alloc(SMEM_SMSM_SIZE_INFO,
sizeof(struct smsm_size_info_type));
if (smsm_size_info) {
@@ -2530,7 +2509,6 @@
return i;
wmb();
- smsm_driver_state_notify(SMSM_INIT, NULL);
return 0;
}
@@ -3104,37 +3082,40 @@
}
EXPORT_SYMBOL(smsm_state_cb_deregister);
-int smsm_driver_state_notifier_register(struct notifier_block *nb)
+int smd_module_init_notifier_register(struct notifier_block *nb)
{
int ret;
if (!nb)
return -EINVAL;
- mutex_lock(&smsm_driver_state_notifier_lock);
- ret = raw_notifier_chain_register(&smsm_driver_state_notifier_list, nb);
- mutex_unlock(&smsm_driver_state_notifier_lock);
+ mutex_lock(&smd_module_init_notifier_lock);
+ ret = raw_notifier_chain_register(&smd_module_init_notifier_list, nb);
+ if (smd_module_inited)
+ nb->notifier_call(nb, 0, NULL);
+ mutex_unlock(&smd_module_init_notifier_lock);
return ret;
}
-EXPORT_SYMBOL(smsm_driver_state_notifier_register);
+EXPORT_SYMBOL(smd_module_init_notifier_register);
-int smsm_driver_state_notifier_unregister(struct notifier_block *nb)
+int smd_module_init_notifier_unregister(struct notifier_block *nb)
{
int ret;
if (!nb)
return -EINVAL;
- mutex_lock(&smsm_driver_state_notifier_lock);
- ret = raw_notifier_chain_unregister(&smsm_driver_state_notifier_list,
+ mutex_lock(&smd_module_init_notifier_lock);
+ ret = raw_notifier_chain_unregister(&smd_module_init_notifier_list,
nb);
- mutex_unlock(&smsm_driver_state_notifier_lock);
+ mutex_unlock(&smd_module_init_notifier_lock);
return ret;
}
-EXPORT_SYMBOL(smsm_driver_state_notifier_unregister);
+EXPORT_SYMBOL(smd_module_init_notifier_unregister);
-static void smsm_driver_state_notify(uint32_t state, void *data)
+static void smd_module_init_notify(uint32_t state, void *data)
{
- mutex_lock(&smsm_driver_state_notifier_lock);
- raw_notifier_call_chain(&smsm_driver_state_notifier_list,
+ mutex_lock(&smd_module_init_notifier_lock);
+ smd_module_inited = 1;
+ raw_notifier_call_chain(&smd_module_init_notifier_list,
state, data);
- mutex_unlock(&smsm_driver_state_notifier_lock);
+ mutex_unlock(&smd_module_init_notifier_lock);
}
int smd_core_init(void)
@@ -3547,12 +3528,29 @@
int __init msm_smd_init(void)
{
static bool registered;
+ int rc;
if (registered)
return 0;
registered = true;
- return platform_driver_register(&msm_smd_driver);
+ rc = remote_spin_lock_init(&remote_spinlock, SMEM_SPINLOCK_SMEM_ALLOC);
+ if (rc) {
+ pr_err("%s: remote spinlock init failed %d\n", __func__, rc);
+ return rc;
+ }
+ spinlocks_initialized = 1;
+
+ rc = platform_driver_register(&msm_smd_driver);
+ if (rc) {
+ pr_err("%s: msm_smd_driver register failed %d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ smd_module_init_notify(0, NULL);
+
+ return 0;
}
module_init(msm_smd_init);
diff --git a/arch/arm/mach-msm/smem_log.c b/arch/arm/mach-msm/smem_log.c
index 2e9a97c..fd8144a 100644
--- a/arch/arm/mach-msm/smem_log.c
+++ b/arch/arm/mach-msm/smem_log.c
@@ -2008,25 +2008,23 @@
return ret;
}
-static int smsm_driver_state_notifier(struct notifier_block *this,
- unsigned long code,
- void *_cmd)
+static int smd_module_init_notifier(struct notifier_block *this,
+ unsigned long code,
+ void *_cmd)
{
int ret = 0;
- if (code & SMSM_INIT) {
- if (!smem_log_initialized)
- ret = smem_log_initialize();
- }
+ if (!smem_log_initialized)
+ ret = smem_log_initialize();
return ret;
}
static struct notifier_block nb = {
- .notifier_call = smsm_driver_state_notifier,
+ .notifier_call = smd_module_init_notifier,
};
static int __init smem_log_init(void)
{
- return smsm_driver_state_notifier_register(&nb);
+ return smd_module_init_notifier_register(&nb);
}
diff --git a/arch/arm/mach-msm/spm-v2.c b/arch/arm/mach-msm/spm-v2.c
index 9f5aa99..26dfdff 100644
--- a/arch/arm/mach-msm/spm-v2.c
+++ b/arch/arm/mach-msm/spm-v2.c
@@ -155,9 +155,6 @@
dev->reg_shadow[MSM_SPM_REG_SAW2_VCTL] &= ~0x700FF;
dev->reg_shadow[MSM_SPM_REG_SAW2_VCTL] |= pmic_data;
-
- dev->reg_shadow[MSM_SPM_REG_SAW2_PMIC_DATA_0] &= ~0x700FF;
- dev->reg_shadow[MSM_SPM_REG_SAW2_PMIC_DATA_0] |= pmic_data;
}
static inline void msm_spm_drv_apcs_set_vctl(struct msm_spm_driver_data *dev,
diff --git a/arch/arm/mach-msm/spm_devices.c b/arch/arm/mach-msm/spm_devices.c
index 9e9b661..05d11d2 100644
--- a/arch/arm/mach-msm/spm_devices.c
+++ b/arch/arm/mach-msm/spm_devices.c
@@ -247,10 +247,10 @@
{"qcom,saw2-cfg", MSM_SPM_REG_SAW2_CFG},
{"qcom,saw2-avs-ctl", MSM_SPM_REG_SAW2_AVS_CTL},
{"qcom,saw2-avs-hysteresis", MSM_SPM_REG_SAW2_AVS_HYSTERESIS},
- {"qcom,saw2-spm-ctl", MSM_SPM_REG_SAW2_SPM_CTL},
- {"qcom,saw2-pmic-dly", MSM_SPM_REG_SAW2_PMIC_DLY},
{"qcom,saw2-avs-limit", MSM_SPM_REG_SAW2_AVS_LIMIT},
+ {"qcom,saw2-avs-dly", MSM_SPM_REG_SAW2_AVS_DLY},
{"qcom,saw2-spm-dly", MSM_SPM_REG_SAW2_SPM_DLY},
+ {"qcom,saw2-spm-ctl", MSM_SPM_REG_SAW2_SPM_CTL},
{"qcom,saw2-pmic-data0", MSM_SPM_REG_SAW2_PMIC_DATA_0},
{"qcom,saw2-pmic-data1", MSM_SPM_REG_SAW2_PMIC_DATA_1},
{"qcom,saw2-pmic-data2", MSM_SPM_REG_SAW2_PMIC_DATA_2},
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index 69783f4..4495eb0 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -35,6 +35,8 @@
#define POOL_TYPE_COPY 1
#define POOL_TYPE_HDLC 2
#define POOL_TYPE_WRITE_STRUCT 4
+#define POOL_TYPE_HSIC 8
+#define POOL_TYPE_HSIC_WRITE 16
#define POOL_TYPE_ALL 7
#define MODEM_DATA 1
#define QDSP_DATA 2
@@ -273,20 +275,19 @@
int in_busy_smux;
int diag_smux_enabled;
int smux_connected;
+ struct diag_request *write_ptr_mdm;
/* HSIC variables */
- unsigned char *buf_in_hsic;
int hsic_ch;
int hsic_device_enabled;
int hsic_device_opened;
int hsic_suspend;
int in_busy_hsic_read_on_device;
- int in_busy_hsic_write_on_device;
int in_busy_hsic_write;
- int in_busy_hsic_read;
struct work_struct diag_read_hsic_work;
/* USB MDM channel variables */
int usb_mdm_connected;
int read_len_mdm;
+ int write_len_mdm;
unsigned char *usb_buf_mdm_out;
struct usb_diag_ch *mdm_ch;
struct workqueue_struct *diag_bridge_wq;
@@ -294,7 +295,16 @@
struct work_struct diag_disconnect_work;
struct work_struct diag_usb_read_complete_work;
struct diag_request *usb_read_mdm_ptr;
- struct diag_request *write_ptr_mdm;
+ int count_hsic_pool;
+ int count_hsic_write_pool;
+ unsigned int poolsize_hsic;
+ unsigned int poolsize_hsic_write;
+ unsigned int itemsize_hsic;
+ unsigned int itemsize_hsic_write;
+ mempool_t *diag_hsic_pool;
+ mempool_t *diag_hsic_write_pool;
+ int num_hsic_buf_tbl_entries;
+ struct diag_write_device *hsic_buf_tbl;
#endif
};
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 30504bc..2dc1929 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -243,6 +243,17 @@
driver->logging_mode = USB_MODE;
diagfwd_connect();
#ifdef CONFIG_DIAG_BRIDGE_CODE
+ driver->num_hsic_buf_tbl_entries = 0;
+ for (i = 0; i < driver->poolsize_hsic_write; i++) {
+ if (driver->hsic_buf_tbl[i].buf) {
+ /* Return the buffer to the pool */
+ diagmem_free(driver, (unsigned char *)
+ (driver->hsic_buf_tbl[i].buf),
+ POOL_TYPE_HSIC);
+ driver->hsic_buf_tbl[i].buf = 0;
+ driver->hsic_buf_tbl[i].length = 0;
+ }
+ }
diagfwd_cancel_hsic();
diagfwd_connect_bridge(0);
#endif
@@ -528,6 +539,17 @@
driver->in_busy_sdio = 1;
#endif
#ifdef CONFIG_DIAG_BRIDGE_CODE
+ driver->num_hsic_buf_tbl_entries = 0;
+ for (i = 0; i < driver->poolsize_hsic_write; i++) {
+ if (driver->hsic_buf_tbl[i].buf) {
+ /* Return the buffer to the pool */
+ diagmem_free(driver, (unsigned char *)
+ (driver->hsic_buf_tbl[i].buf),
+ POOL_TYPE_HSIC);
+ driver->hsic_buf_tbl[i].buf = 0;
+ driver->hsic_buf_tbl[i].length = 0;
+ }
+ }
diagfwd_disconnect_bridge(0);
#endif
} else if (temp == NO_LOGGING_MODE && driver->logging_mode
@@ -556,6 +578,11 @@
&(driver->diag_read_sdio_work));
#endif
#ifdef CONFIG_DIAG_BRIDGE_CODE
+ driver->num_hsic_buf_tbl_entries = 0;
+ for (i = 0; i < driver->poolsize_hsic_write; i++) {
+ driver->hsic_buf_tbl[i].buf = 0;
+ driver->hsic_buf_tbl[i].length = 0;
+ }
diagfwd_connect_bridge(0);
#endif
}
@@ -581,6 +608,7 @@
driver->in_busy_qdsp_2 = 0;
driver->in_busy_wcnss_1 = 0;
driver->in_busy_wcnss_2 = 0;
+
/* Poll SMD channels to check for data*/
if (driver->ch)
queue_work(driver->diag_wq,
@@ -599,6 +627,11 @@
&(driver->diag_read_sdio_work));
#endif
#ifdef CONFIG_DIAG_BRIDGE_CODE
+ driver->num_hsic_buf_tbl_entries = 0;
+ for (i = 0; i < driver->poolsize_hsic_write; i++) {
+ driver->hsic_buf_tbl[i].buf = 0;
+ driver->hsic_buf_tbl[i].length = 0;
+ }
diagfwd_cancel_hsic();
diagfwd_connect_bridge(0);
#endif
@@ -606,6 +639,17 @@
driver->logging_mode == USB_MODE) {
diagfwd_connect();
#ifdef CONFIG_DIAG_BRIDGE_CODE
+ driver->num_hsic_buf_tbl_entries = 0;
+ for (i = 0; i < driver->poolsize_hsic_write; i++) {
+ if (driver->hsic_buf_tbl[i].buf) {
+ /* Return the buffer to the pool */
+ diagmem_free(driver, (unsigned char *)
+ (driver->hsic_buf_tbl[i].buf),
+ POOL_TYPE_HSIC);
+ driver->hsic_buf_tbl[i].buf = 0;
+ driver->hsic_buf_tbl[i].length = 0;
+ }
+ }
diagfwd_cancel_hsic();
diagfwd_connect_bridge(0);
#endif
@@ -767,20 +811,44 @@
}
#endif
#ifdef CONFIG_DIAG_BRIDGE_CODE
- pr_debug("diag: Copy data to user space %d\n",
- driver->in_busy_hsic_write_on_device);
- if (driver->in_busy_hsic_write_on_device == 1) {
- num_data++;
- /*Copy the length of data being passed*/
- COPY_USER_SPACE_OR_EXIT(buf+ret,
- (driver->write_ptr_mdm->length), 4);
- /*Copy the actual data being passed*/
- COPY_USER_SPACE_OR_EXIT(buf+ret,
- *(driver->buf_in_hsic),
- driver->write_ptr_mdm->length);
- pr_debug("diag: data copied\n");
- /* call the write complete function */
- diagfwd_write_complete_hsic();
+
+ for (i = 0; i < driver->poolsize_hsic_write; i++) {
+ if (driver->hsic_buf_tbl[i].length > 0) {
+ pr_debug("diag: HSIC copy to user, i: %d, buf: %x, len: %d\n",
+ i, (unsigned int)
+ (driver->hsic_buf_tbl[i].buf),
+ driver->hsic_buf_tbl[i].length);
+ num_data++;
+ /* Copy the length of data being passed */
+ if (copy_to_user(buf+ret, (void *)&(driver->
+ hsic_buf_tbl[i].length), 4)) {
+ num_data--;
+ goto drop_hsic;
+ }
+ ret += 4;
+
+ /* Copy the actual data being passed */
+ if (copy_to_user(buf+ret,
+ (void *)driver->hsic_buf_tbl[i].buf,
+ driver->hsic_buf_tbl[i].length)) {
+ ret -= 4;
+ num_data--;
+ goto drop_hsic;
+ }
+ ret += driver->hsic_buf_tbl[i].length;
+drop_hsic:
+ /* Return the buffer to the pool */
+ diagmem_free(driver, (unsigned char *)
+ (driver->hsic_buf_tbl[i].buf),
+ POOL_TYPE_HSIC);
+
+ driver->hsic_buf_tbl[i].length = 0;
+ driver->hsic_buf_tbl[i].buf = 0;
+ driver->num_hsic_buf_tbl_entries--;
+
+ /* Call the write complete function */
+ diagfwd_write_complete_hsic(NULL);
+ }
}
#endif
/* copy number of data fields */
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index 5a74e8c..4b24e2b 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -66,6 +66,9 @@
msg_mask_tbl_ptr += 4; \
*(int *)(msg_mask_tbl_ptr) = MSG_SSID_ ## XX ## _LAST; \
msg_mask_tbl_ptr += 4; \
+ /* mimic the last entry as actual_last while creation */ \
+ *(int *)(msg_mask_tbl_ptr) = MSG_SSID_ ## XX ## _LAST; \
+ msg_mask_tbl_ptr += 4; \
/* increment by MAX_SSID_PER_RANGE cells */ \
msg_mask_tbl_ptr += MAX_SSID_PER_RANGE * sizeof(int); \
} while (0)
@@ -307,6 +310,26 @@
break;
}
}
+
+#ifdef CONFIG_DIAG_BRIDGE_CODE
+ else if (proc_num == HSIC_DATA) {
+ for (i = 0; i < driver->poolsize_hsic_write; i++) {
+ if (driver->hsic_buf_tbl[i].length == 0) {
+ driver->hsic_buf_tbl[i].buf = buf;
+ driver->hsic_buf_tbl[i].length =
+ driver->write_len_mdm;
+ driver->num_hsic_buf_tbl_entries++;
+#ifdef DIAG_DEBUG
+ pr_debug("diag: ENQUEUE HSIC buf ptr and length is %x , %d\n",
+ (unsigned int)
+ (driver->hsic_buf_tbl[i].buf),
+ driver->hsic_buf_tbl[i].length);
+#endif
+ break;
+ }
+ }
+ }
+#endif
for (i = 0; i < driver->num_clients; i++)
if (driver->client_map[i].pid ==
driver->logging_process_id)
@@ -343,8 +366,6 @@
#endif
#ifdef CONFIG_DIAG_BRIDGE_CODE
else if (proc_num == HSIC_DATA) {
- driver->in_busy_hsic_read = 0;
- driver->in_busy_hsic_write_on_device = 0;
if (driver->hsic_ch)
queue_work(driver->diag_bridge_wq,
&(driver->diag_read_hsic_work));
@@ -396,11 +417,33 @@
#ifdef CONFIG_DIAG_BRIDGE_CODE
else if (proc_num == HSIC_DATA) {
if (driver->hsic_device_enabled) {
- write_ptr->buf = buf;
- err = usb_diag_write(driver->mdm_ch, write_ptr);
- } else
+ struct diag_request *write_ptr_mdm;
+ write_ptr_mdm = (struct diag_request *)
+ diagmem_alloc(driver,
+ sizeof(struct diag_request),
+ POOL_TYPE_HSIC_WRITE);
+ if (write_ptr_mdm) {
+ write_ptr_mdm->buf = buf;
+ write_ptr_mdm->length =
+ driver->write_len_mdm;
+ err = usb_diag_write(driver->mdm_ch,
+ write_ptr_mdm);
+ /* Return to the pool immediately */
+ if (err) {
+ diagmem_free(driver,
+ write_ptr_mdm,
+ POOL_TYPE_HSIC_WRITE);
+ pr_err("diag: HSIC write failure\n");
+ }
+ } else {
+ pr_err("diag: allocate write fail\n");
+ err = -1;
+ }
+ } else {
pr_err("diag: Incorrect hsic data "
"while USB write\n");
+ err = -1;
+ }
} else if (proc_num == SMUX_DATA) {
write_ptr->buf = buf;
pr_debug("diag: writing SMUX data\n");
@@ -512,8 +555,7 @@
{
/* Enable this to print mask table when updated */
#ifdef MASK_DEBUG
- int first;
- int last;
+ int first, last, actual_last;
uint8_t *ptr = driver->msg_masks;
int i = 0;
pr_info("diag: F3 message mask table\n");
@@ -522,11 +564,12 @@
ptr += 4;
last = *(uint32_t *)ptr;
ptr += 4;
- printk(KERN_INFO "SSID %d - %d\n", first, last);
- for (i = 0 ; i <= last - first ; i++)
- printk(KERN_INFO "MASK:%x\n", *((uint32_t *)ptr + i));
+ actual_last = *(uint32_t *)ptr;
+ ptr += 4;
+ pr_info("diag: SSID %d, %d - %d\n", first, last, actual_last);
+ for (i = 0 ; i <= actual_last - first ; i++)
+ pr_info("diag: MASK:%x\n", *((uint32_t *)ptr + i));
ptr += MAX_SSID_PER_RANGE*4;
-
}
#endif
}
@@ -569,7 +612,7 @@
mutex_lock(&driver->diagchar_mutex);
while (*(uint32_t *)(ptr + 4)) {
first_ssid = *(uint32_t *)ptr;
- ptr += 4;
+ ptr += 8; /* increment by 8 to skip 'last' */
last_ssid = *(uint32_t *)ptr;
ptr += 4;
parse_ptr = ptr;
@@ -585,9 +628,8 @@
static void diag_update_msg_mask(int start, int end , uint8_t *buf)
{
- int found = 0;
- int first;
- int last;
+ int found = 0, first, last, actual_last;
+ uint8_t *actual_last_ptr;
uint8_t *ptr = driver->msg_masks;
uint8_t *ptr_buffer_start = &(*(driver->msg_masks));
uint8_t *ptr_buffer_end = &(*(driver->msg_masks)) + MSG_MASK_SIZE;
@@ -600,23 +642,23 @@
ptr += 4;
last = *(uint32_t *)ptr;
ptr += 4;
- if (start >= first && start <= last) {
+ actual_last = *(uint32_t *)ptr;
+ actual_last_ptr = ptr;
+ ptr += 4;
+ if (start >= first && start <= actual_last) {
ptr += (start - first)*4;
- if (end <= last)
- if (CHK_OVERFLOW(ptr_buffer_start, ptr,
- ptr_buffer_end,
- (((end - start)+1)*4))) {
- pr_debug("diag: update ssid start %d,"
- " end %d\n", start, end);
- memcpy(ptr, buf , ((end - start)+1)*4);
- } else
- printk(KERN_CRIT "Not enough"
- " buffer space for"
- " MSG_MASK\n");
- else
- printk(KERN_INFO "Unable to copy"
- " mask change\n");
-
+ if (end > actual_last) {
+ pr_info("diag: ssid range mismatch\n");
+ actual_last = end;
+ *(uint32_t *)(actual_last_ptr) = end;
+ }
+ if (CHK_OVERFLOW(ptr_buffer_start, ptr, ptr_buffer_end,
+ (((end - start)+1)*4))) {
+ pr_debug("diag: update ssid start %d, end %d\n",
+ start, end);
+ memcpy(ptr, buf , ((end - start)+1)*4);
+ } else
+ pr_alert("diag: Not enough space MSG_MASK\n");
found = 1;
break;
} else {
@@ -631,16 +673,16 @@
ptr += 4;
memcpy(ptr, &(end), 4);
ptr += 4;
+ memcpy(ptr, &(end), 4); /* create actual_last entry */
+ ptr += 4;
pr_debug("diag: adding NEW ssid start %d, end %d\n",
start, end);
memcpy(ptr, buf , ((end - start) + 1)*4);
} else
- printk(KERN_CRIT " Not enough buffer"
- " space for MSG_MASK\n");
+ pr_alert("diag: Not enough buffer space for MSG_MASK\n");
}
mutex_unlock(&driver->diagchar_mutex);
diag_print_mask_table();
-
}
void diag_toggle_event_mask(int toggle)
@@ -691,6 +733,30 @@
mutex_unlock(&driver->diagchar_mutex);
}
+int chk_equip_id_and_mask(int equip_id, uint8_t *buf)
+{
+ int i = 0, flag = 0, num_items, offset;
+ unsigned char *ptr_data;
+ struct mask_info *ptr = (struct mask_info *)(driver->log_masks);
+
+ pr_debug("diag: received equip id = %d\n", equip_id);
+ /* Check if this is valid equipment ID */
+ for (i = 0; i < MAX_EQUIP_ID; i++) {
+ if ((ptr->equip_id == equip_id) && (ptr->index != 0)) {
+ offset = ptr->index;
+ num_items = ptr->num_items;
+ flag = 1;
+ break;
+ }
+ ptr++;
+ }
+ if (!flag)
+ return -EPERM;
+ ptr_data = driver->log_masks + offset;
+ memcpy(buf, ptr_data, (num_items+7)/8);
+ return 0;
+}
+
static void diag_update_log_mask(int equip_id, uint8_t *buf, int num_items)
{
uint8_t *temp = buf;
@@ -916,7 +982,7 @@
int updated_ssid_last, int proc)
{
void *buf = driver->buf_msg_mask_update;
- int first, last, size = -ENOMEM, retry_count = 0, timer;
+ int first, last, actual_last, size = -ENOMEM, retry_count = 0, timer;
int header_size = sizeof(struct diag_ctrl_msg_mask);
uint8_t *ptr = driver->msg_masks;
@@ -926,18 +992,21 @@
ptr += 4;
last = *(uint32_t *)ptr;
ptr += 4;
- if ((updated_ssid_first >= first && updated_ssid_last <= last)
- || (updated_ssid_first == ALL_SSID)) {
+ actual_last = *(uint32_t *)ptr;
+ ptr += 4;
+ if ((updated_ssid_first >= first && updated_ssid_last <=
+ actual_last) || (updated_ssid_first == ALL_SSID)) {
/* send f3 mask update */
driver->msg_mask->cmd_type = DIAG_CTRL_MSG_F3_MASK;
- driver->msg_mask->msg_mask_size = last - first + 1;
+ driver->msg_mask->msg_mask_size = actual_last -
+ first + 1;
driver->msg_mask->data_len = 11 +
4 * (driver->msg_mask->msg_mask_size);
driver->msg_mask->stream_id = 1; /* 2, if dual stream */
driver->msg_mask->status = 3; /* status valid mask */
driver->msg_mask->msg_mode = 0; /* Legcay mode */
driver->msg_mask->ssid_first = first;
- driver->msg_mask->ssid_last = last;
+ driver->msg_mask->ssid_last = actual_last;
memcpy(buf, driver->msg_mask, header_size);
memcpy(buf+header_size, ptr,
4 * (driver->msg_mask->msg_mask_size));
@@ -959,8 +1028,8 @@
"fail %d, tried %d\n", proc, size,
header_size + 4*(driver->msg_mask->msg_mask_size));
else
- pr_debug("diag: sending mask update for"
- "ssid first %d, last %d on PROC %d\n", first, last, proc);
+ pr_debug("diag: sending mask update for ssid first %d, last %d on PROC %d\n",
+ first, actual_last, proc);
} else
pr_err("diag: proc %d, ch invalid msg mask"
"update\n", proc);
@@ -978,7 +1047,7 @@
int rt_mask, rt_first_ssid, rt_last_ssid, rt_mask_size;
unsigned char *temp = buf;
uint8_t *rt_mask_ptr;
- int data_type;
+ int data_type, equip_id, num_items;
#if defined(CONFIG_DIAG_OVER_USB)
int payload_length;
unsigned char *ptr;
@@ -1012,6 +1081,29 @@
} else
buf = temp;
#endif
+ } /* Get log masks */
+ else if (*buf == 0x73 && *(int *)(buf+4) == 4) {
+#if defined(CONFIG_DIAG_OVER_USB)
+ if (!(driver->ch) && chk_apps_only()) {
+ equip_id = *(int *)(buf + 8);
+ num_items = *(int *)(buf + 12);
+ driver->apps_rsp_buf[0] = 0x73;
+ driver->apps_rsp_buf[1] = 0x0;
+ driver->apps_rsp_buf[2] = 0x0;
+ driver->apps_rsp_buf[3] = 0x0;
+ *(int *)(driver->apps_rsp_buf + 4) = 0x4;
+ if (!chk_equip_id_and_mask(equip_id,
+ driver->apps_rsp_buf+20))
+ *(int *)(driver->apps_rsp_buf + 8) = 0x0;
+ else
+ *(int *)(driver->apps_rsp_buf + 8) = 0x1;
+ *(int *)(driver->apps_rsp_buf + 12) = equip_id;
+ *(int *)(driver->apps_rsp_buf + 16) = num_items;
+ ENCODE_RSP_AND_SEND(20+(num_items+7)/8-1);
+ return 0;
+ } else
+ buf = temp;
+#endif
} /* Disable log masks */
else if (*buf == 0x73 && *(int *)(buf+4) == 0) {
/* Disable mask for each log code */
@@ -1052,7 +1144,7 @@
rt_mask_ptr = driver->msg_masks;
while (*(uint32_t *)(rt_mask_ptr + 4)) {
rt_first_ssid = *(uint32_t *)rt_mask_ptr;
- rt_mask_ptr += 4;
+ rt_mask_ptr += 8; /* +8 to skip 'last' */
rt_last_ssid = *(uint32_t *)rt_mask_ptr;
rt_mask_ptr += 4;
if (ssid_first == rt_first_ssid && ssid_last ==
diff --git a/drivers/char/diag/diagfwd_cntl.c b/drivers/char/diag/diagfwd_cntl.c
index 95abd21..52fd673 100644
--- a/drivers/char/diag/diagfwd_cntl.c
+++ b/drivers/char/diag/diagfwd_cntl.c
@@ -401,7 +401,8 @@
"in_busy_qdsp_2: %d\n"
"in_busy_wcnss_1: %d\n"
"in_busy_wcnss_2: %d\n"
- "in_busy_dci: %d\n",
+ "in_busy_dci: %d\n"
+ "logging_mode: %d\n",
(unsigned int)driver->ch,
(unsigned int)driver->chqdsp,
(unsigned int)driver->ch_wcnss,
@@ -421,7 +422,8 @@
driver->in_busy_qdsp_2,
driver->in_busy_wcnss_1,
driver->in_busy_wcnss_2,
- driver->in_busy_dci);
+ driver->in_busy_dci,
+ driver->logging_mode);
#ifdef CONFIG_DIAG_OVER_USB
ret += scnprintf(buf+ret, DEBUG_BUF_SIZE,
@@ -541,7 +543,7 @@
return ret;
}
-#ifdef CONFIG_DIAG_HSIC_PIPE
+#ifdef CONFIG_DIAG_BRIDGE_CODE
static ssize_t diag_dbgfs_read_hsic(struct file *file, char __user *ubuf,
size_t count, loff_t *ppos)
{
@@ -555,29 +557,35 @@
}
ret = scnprintf(buf, DEBUG_BUF_SIZE,
- "hsic initialized: %d\n"
"hsic ch: %d\n"
"hsic enabled: %d\n"
"hsic_opened: %d\n"
- "hisc_suspend: %d\n"
- "in_busy_hsic_read_on_mdm: %d\n"
- "in_busy_hsic_write_on_mdm: %d\n"
+ "hsic_suspend: %d\n"
+ "in_busy_hsic_read_on_device: %d\n"
"in_busy_hsic_write: %d\n"
- "in_busy_hsic_read: %d\n"
+ "count_hsic_pool: %d\n"
+ "count_hsic_write_pool: %d\n"
+ "diag_hsic_pool: %x\n"
+ "diag_hsic_write_pool: %x\n"
+ "write_len_mdm: %d\n"
+ "num_hsic_buf_tbl_entries: %d\n"
"usb_mdm_connected: %d\n"
"diag_read_mdm_work: %d\n"
"diag_read_hsic_work: %d\n"
"diag_disconnect_work: %d\n"
"diag_usb_read_complete_work: %d\n",
- driver->hsic_initialized,
driver->hsic_ch,
driver->hsic_device_enabled,
driver->hsic_device_opened,
driver->hsic_suspend,
driver->in_busy_hsic_read_on_device,
- driver->in_busy_hsic_write_on_device,
driver->in_busy_hsic_write,
- driver->in_busy_hsic_read,
+ driver->count_hsic_pool,
+ driver->count_hsic_write_pool,
+ (unsigned int)driver->diag_hsic_pool,
+ (unsigned int)driver->diag_hsic_write_pool,
+ driver->write_len_mdm,
+ driver->num_hsic_buf_tbl_entries,
driver->usb_mdm_connected,
work_pending(&(driver->diag_read_mdm_work)),
work_pending(&(driver->diag_read_hsic_work)),
@@ -622,7 +630,7 @@
debugfs_create_file("work_pending", 0444, diag_dbgfs_dent, 0,
&diag_dbgfs_workpending_ops);
-#ifdef CONFIG_DIAG_HSIC_PIPE
+#ifdef CONFIG_DIAG_BRIDGE_CODE
debugfs_create_file("hsic", 0444, diag_dbgfs_dent, 0,
&diag_dbgfs_hsic_ops);
#endif
diff --git a/drivers/char/diag/diagfwd_hsic.c b/drivers/char/diag/diagfwd_hsic.c
index 81c6afa..11a8471 100644
--- a/drivers/char/diag/diagfwd_hsic.c
+++ b/drivers/char/diag/diagfwd_hsic.c
@@ -32,48 +32,86 @@
#include "diagfwd_hsic.h"
#include "diagfwd_smux.h"
+#define N_MDM_WRITE 8
+#define N_MDM_READ 1
+
+#define READ_HSIC_BUF_SIZE 2048
+
+#define NUM_HSIC_BUF_TBL_ENTRIES N_MDM_WRITE
+
static void diag_read_hsic_work_fn(struct work_struct *work)
{
+ unsigned char *buf_in_hsic = NULL;
+ int num_reads_submitted = 0;
+ int err = 0;
+ int write_ptrs_available;
+
if (!driver->hsic_ch) {
pr_err("DIAG in %s: driver->hsic_ch == 0\n", __func__);
return;
}
- /* If there is no hsic data being read from the hsic and there
- * is no hsic data being written to the device
+ /*
+ * Determine the current number of available buffers for writing after
+ * reading from the HSIC has completed.
*/
- if (!driver->in_busy_hsic_read &&
- !driver->in_busy_hsic_write_on_device) {
- /*
- * Initiate the read from the hsic. The hsic read is
- * asynchronous. Once the read is complete the read
- * callback function will be called.
- */
- int err;
- driver->in_busy_hsic_read = 1;
- APPEND_DEBUG('i');
- pr_debug("diag: read from HSIC\n");
- err = diag_bridge_read((char *)driver->buf_in_hsic,
- IN_BUF_SIZE);
- if (err) {
- pr_err_ratelimited("DIAG: Error initiating HSIC read, err: %d\n",
- err);
- /*
- * If the error is recoverable, then clear
- * the read flag, so we will resubmit a
- * read on the next frame. Otherwise, don't
- * resubmit a read on the next frame.
- */
- if ((-ENODEV) != err)
- driver->in_busy_hsic_read = 0;
- }
- }
+ if (driver->logging_mode == MEMORY_DEVICE_MODE)
+ write_ptrs_available = driver->poolsize_hsic_write -
+ driver->num_hsic_buf_tbl_entries;
+ else
+ write_ptrs_available = driver->poolsize_hsic_write -
+ driver->count_hsic_write_pool;
/*
- * If for some reason there was no hsic data, set up
- * the next read
+ * Queue up a read on the HSIC for all available buffers in the
+ * pool, exhausting the pool.
*/
- if (!driver->in_busy_hsic_read)
+ do {
+ /*
+ * If no more write buffers are available,
+ * stop queuing reads
+ */
+ if (write_ptrs_available <= 0)
+ break;
+
+ write_ptrs_available--;
+
+ buf_in_hsic = diagmem_alloc(driver, READ_HSIC_BUF_SIZE,
+ POOL_TYPE_HSIC);
+ if (buf_in_hsic) {
+ /*
+ * Initiate the read from the hsic. The hsic read is
+ * asynchronous. Once the read is complete the read
+ * callback function will be called.
+ */
+ pr_debug("diag: read from HSIC\n");
+ num_reads_submitted++;
+ err = diag_bridge_read((char *)buf_in_hsic,
+ READ_HSIC_BUF_SIZE);
+ if (err) {
+ num_reads_submitted--;
+
+ /* Return the buffer to the pool */
+ diagmem_free(driver, buf_in_hsic,
+ POOL_TYPE_HSIC);
+
+ pr_err_ratelimited("diag: Error initiating HSIC read, err: %d\n",
+ err);
+ /*
+ * An error occurred, discontinue queuing
+ * reads
+ */
+ break;
+ }
+ }
+ } while (buf_in_hsic);
+
+ /*
+ * If there are no buffers available or for some reason there
+ * was no hsic data, and if no unrecoverable error occurred
+ * (-ENODEV is an unrecoverable error), then set up the next read
+ */
+ if ((num_reads_submitted == 0) && (err != -ENODEV))
queue_work(driver->diag_bridge_wq,
&driver->diag_read_hsic_work);
}
@@ -81,45 +119,58 @@
static void diag_hsic_read_complete_callback(void *ctxt, char *buf,
int buf_size, int actual_size)
{
- /* The read of the data from the HSIC bridge is complete */
- driver->in_busy_hsic_read = 0;
+ int err = -2;
if (!driver->hsic_ch) {
- pr_err("DIAG in %s: driver->hsic_ch == 0\n", __func__);
+ /*
+ * The hsic channel is closed. Return the buffer to
+ * the pool. Do not send it on.
+ */
+ diagmem_free(driver, buf, POOL_TYPE_HSIC);
+ pr_debug("diag: In %s: driver->hsic_ch == 0, actual_size: %d\n",
+ __func__, actual_size);
return;
}
- APPEND_DEBUG('j');
- if (actual_size > 0) {
+ /* Note that zero length is valid and still needs to be sent */
+ if (actual_size >= 0) {
if (!buf) {
- pr_err("Out of diagmem for HSIC\n");
+ pr_err("diag: Out of diagmem for HSIC\n");
} else {
- driver->write_ptr_mdm->length = actual_size;
/*
- * Set flag to denote hsic data is currently
- * being written to the usb mdm channel.
- * driver->buf_in_hsic was given to
- * diag_bridge_read(), so buf here should be
- * driver->buf_in_hsic
+ * Send data in buf to be written on the
+ * appropriate device, e.g. USB MDM channel
*/
- driver->in_busy_hsic_write_on_device = 1;
- pr_debug("diag: write to device\n");
- diag_device_write((void *)buf, HSIC_DATA,
- driver->write_ptr_mdm);
+ driver->write_len_mdm = actual_size;
+ err = diag_device_write((void *)buf, HSIC_DATA, NULL);
+ /* If an error, return buffer to the pool */
+ if (err) {
+ diagmem_free(driver, buf, POOL_TYPE_HSIC);
+ pr_err("diag: In %s, error calling diag_device_write, err: %d\n",
+ __func__, err);
+ }
}
} else {
- pr_debug("%s: actual_size: %d\n", __func__, actual_size);
+ /*
+ * The buffer has an error status associated with it. Do not
+ * pass it on. Note that -ENOENT is sent when the diag bridge
+ * is closed.
+ */
+ diagmem_free(driver, buf, POOL_TYPE_HSIC);
+ pr_debug("diag: In %s: error status: %d\n", __func__,
+ actual_size);
}
/*
* If for some reason there was no hsic data to write to the
* mdm channel, set up another read
*/
- if (!driver->in_busy_hsic_write_on_device && ((driver->logging_mode
- == MEMORY_DEVICE_MODE) || (driver->usb_mdm_connected &&
- !driver->hsic_suspend)))
+ if (err &&
+ ((driver->logging_mode == MEMORY_DEVICE_MODE) ||
+ (driver->usb_mdm_connected && !driver->hsic_suspend))) {
queue_work(driver->diag_bridge_wq,
&driver->diag_read_hsic_work);
+ }
}
static void diag_hsic_write_complete_callback(void *ctxt, char *buf,
@@ -143,6 +194,8 @@
static int diag_hsic_suspend(void *ctxt)
{
pr_debug("diag: hsic_suspend\n");
+
+ /* Don't allow suspend if a write in the HSIC is in progress */
if (driver->in_busy_hsic_write)
return -EBUSY;
@@ -160,8 +213,8 @@
pr_debug("diag: hsic_resume\n");
driver->hsic_suspend = 0;
- if (!driver->in_busy_hsic_write_on_device && (driver->logging_mode
- == MEMORY_DEVICE_MODE || driver->usb_mdm_connected))
+ if ((driver->logging_mode == MEMORY_DEVICE_MODE) ||
+ (driver->usb_mdm_connected))
queue_work(driver->diag_bridge_wq,
&driver->diag_read_hsic_work);
}
@@ -202,10 +255,10 @@
diag_bridge_close();
err = diag_bridge_open(&hsic_diag_bridge_ops);
if (err) {
- pr_err("DIAG: HSIC channel open error: %d\n",
+ pr_err("diag: HSIC channel open error: %d\n",
err);
} else {
- pr_debug("DIAG: opened HSIC channel\n");
+ pr_debug("diag: opened HSIC channel\n");
driver->hsic_device_opened = 1;
driver->hsic_ch = 1;
}
@@ -234,10 +287,8 @@
}
if (driver->hsic_device_enabled) {
- driver->in_busy_hsic_write_on_device = 0;
driver->in_busy_hsic_read_on_device = 0;
driver->in_busy_hsic_write = 0;
- driver->in_busy_hsic_read = 0;
} else if (driver->diag_smux_enabled) {
driver->in_busy_smux = 0;
diagfwd_connect_smux();
@@ -288,7 +339,7 @@
*/
int diagfwd_disconnect_bridge(int process_cable)
{
- pr_debug("DIAG in %s\n", __func__);
+ pr_debug("diag: In %s, process_cable: %d\n", __func__, process_cable);
/* If the usb cable is being disconnected */
if (process_cable) {
@@ -298,10 +349,8 @@
if (driver->logging_mode == USB_MODE) {
if (driver->hsic_device_enabled) {
- driver->in_busy_hsic_write_on_device = 1;
driver->in_busy_hsic_read_on_device = 1;
driver->in_busy_hsic_write = 1;
- driver->in_busy_hsic_read = 1;
/* Turn off communication over usb mdm and hsic */
return diag_hsic_close();
} else if (driver->diag_smux_enabled) {
@@ -319,19 +368,21 @@
* diagfwd_write_complete_hsic is called after the asynchronous
* usb_diag_write() on mdm channel is complete
*/
-int diagfwd_write_complete_hsic(void)
+int diagfwd_write_complete_hsic(struct diag_request *diag_write_ptr)
{
- /*
- * Clear flag to denote that the write of the hsic data on the
- * usb mdm channel is complete
- */
- driver->in_busy_hsic_write_on_device = 0;
- if (!driver->hsic_ch) {
- pr_err("DIAG in %s: driver->hsic_ch == 0\n", __func__);
- return 0;
+ unsigned char *buf = (diag_write_ptr) ? diag_write_ptr->buf : NULL;
+
+ if (buf) {
+ /* Return buffers to their pools */
+ diagmem_free(driver, (unsigned char *)buf, POOL_TYPE_HSIC);
+ diagmem_free(driver, (unsigned char *)diag_write_ptr,
+ POOL_TYPE_HSIC_WRITE);
}
- APPEND_DEBUG('q');
+ if (!driver->hsic_ch) {
+ pr_err("diag: In %s: driver->hsic_ch == 0\n", __func__);
+ return 0;
+ }
/* Read data from the hsic */
queue_work(driver->diag_bridge_wq, &driver->diag_read_hsic_work);
@@ -375,7 +426,7 @@
err = diag_bridge_write(driver->usb_buf_mdm_out,
driver->read_len_mdm);
if (err) {
- pr_err_ratelimited("DIAG: mdm data on hsic write err: %d\n",
+ pr_err_ratelimited("diag: mdm data on hsic write err: %d\n",
err);
/*
* If the error is recoverable, then clear
@@ -415,7 +466,7 @@
break;
case USB_DIAG_WRITE_DONE:
if (driver->hsic_device_enabled)
- diagfwd_write_complete_hsic();
+ diagfwd_write_complete_hsic(d_req);
else if (driver->diag_smux_enabled)
diagfwd_write_complete_smux();
break;
@@ -492,8 +543,7 @@
int err = 0;
pr_debug("diag: in %s\n", __func__);
if (!driver->hsic_device_enabled) {
- if (driver->buf_in_hsic == NULL)
- driver->buf_in_hsic = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
+ diagmem_hsic_init(driver);
INIT_WORK(&(driver->diag_read_hsic_work),
diag_read_hsic_work_fn);
driver->hsic_device_enabled = 1;
@@ -517,10 +567,9 @@
pr_info("diag: opened HSIC channel\n");
driver->hsic_device_opened = 1;
driver->hsic_ch = 1;
- driver->in_busy_hsic_write_on_device = 0;
+
driver->in_busy_hsic_read_on_device = 0;
driver->in_busy_hsic_write = 0;
- driver->in_busy_hsic_read = 0;
if (driver->usb_mdm_connected) {
/* Poll USB mdm channel to check for data */
@@ -538,7 +587,7 @@
static int diag_hsic_remove(struct platform_device *pdev)
{
- pr_debug("DIAG: %s called\n", __func__);
+ pr_debug("diag: %s called\n", __func__);
diag_hsic_close();
return 0;
}
@@ -578,11 +627,14 @@
driver->diag_bridge_wq = create_singlethread_workqueue(
"diag_bridge_wq");
driver->read_len_mdm = 0;
+ driver->write_len_mdm = 0;
+ driver->num_hsic_buf_tbl_entries = 0;
if (driver->usb_buf_mdm_out == NULL)
driver->usb_buf_mdm_out = kzalloc(USB_MAX_OUT_BUF,
GFP_KERNEL);
if (driver->usb_buf_mdm_out == NULL)
goto err;
+ /* Only used by smux move to smux probe function */
if (driver->write_ptr_mdm == NULL)
driver->write_ptr_mdm = kzalloc(
sizeof(struct diag_request), GFP_KERNEL);
@@ -594,6 +646,20 @@
if (driver->usb_read_mdm_ptr == NULL)
goto err;
+ if (driver->hsic_buf_tbl == NULL)
+ driver->hsic_buf_tbl = kzalloc(NUM_HSIC_BUF_TBL_ENTRIES *
+ sizeof(struct diag_write_device), GFP_KERNEL);
+ if (driver->hsic_buf_tbl == NULL)
+ goto err;
+
+ driver->count_hsic_pool = 0;
+ driver->count_hsic_write_pool = 0;
+
+ driver->itemsize_hsic = READ_HSIC_BUF_SIZE;
+ driver->poolsize_hsic = N_MDM_WRITE;
+ driver->itemsize_hsic_write = sizeof(struct diag_request);
+ driver->poolsize_hsic_write = N_MDM_WRITE;
+
#ifdef CONFIG_DIAG_OVER_USB
INIT_WORK(&(driver->diag_read_mdm_work), diag_read_mdm_work_fn);
#endif
@@ -608,10 +674,6 @@
goto err;
}
#endif
-#ifdef CONFIG_DIAG_BRIDGE_CODE
- INIT_WORK(&(driver->diag_disconnect_work), diag_disconnect_work_fn);
- INIT_WORK(&(driver->diag_usb_read_complete_work),
- diag_usb_read_complete_fn);
/* register HSIC device */
ret = platform_driver_register(&msm_hsic_ch_driver);
if (ret)
@@ -620,11 +682,12 @@
ret = platform_driver_register(&msm_diagfwd_smux_driver);
if (ret)
pr_err("diag: could not register SMUX device, ret: %d\n", ret);
-#endif
+
return;
err:
pr_err("diag: Could not initialize for bridge forwarding\n");
kfree(driver->usb_buf_mdm_out);
+ kfree(driver->hsic_buf_tbl);
kfree(driver->write_ptr_mdm);
kfree(driver->usb_read_mdm_ptr);
if (driver->diag_bridge_wq)
@@ -639,8 +702,8 @@
if (driver->hsic_device_enabled) {
diag_hsic_close();
- kfree(driver->buf_in_hsic);
driver->hsic_device_enabled = 0;
+ diagmem_exit(driver, POOL_TYPE_ALL);
}
if (driver->diag_smux_enabled) {
driver->lcid = LCID_INVALID;
@@ -656,6 +719,7 @@
usb_diag_close(driver->mdm_ch);
#endif
kfree(driver->usb_buf_mdm_out);
+ kfree(driver->hsic_buf_tbl);
kfree(driver->write_ptr_mdm);
kfree(driver->usb_read_mdm_ptr);
destroy_workqueue(driver->diag_bridge_wq);
diff --git a/drivers/char/diag/diagfwd_hsic.h b/drivers/char/diag/diagfwd_hsic.h
index b189c94..b2d9c9f 100644
--- a/drivers/char/diag/diagfwd_hsic.h
+++ b/drivers/char/diag/diagfwd_hsic.h
@@ -14,12 +14,10 @@
#define DIAGFWD_HSIC_H
#include <mach/diag_bridge.h>
-#define N_MDM_WRITE 1 /* Upgrade to 2 with ping pong buffer */
-#define N_MDM_READ 1
int diagfwd_connect_bridge(int);
int diagfwd_disconnect_bridge(int);
-int diagfwd_write_complete_hsic(void);
+int diagfwd_write_complete_hsic(struct diag_request *);
int diagfwd_cancel_hsic(void);
void diagfwd_bridge_init(void);
void diagfwd_bridge_exit(void);
diff --git a/drivers/char/diag/diagmem.c b/drivers/char/diag/diagmem.c
index 0b5c27a..82c47af 100644
--- a/drivers/char/diag/diagmem.c
+++ b/drivers/char/diag/diagmem.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2008-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
@@ -51,6 +51,28 @@
driver->diag_write_struct_pool, GFP_ATOMIC);
}
}
+#ifdef CONFIG_DIAG_BRIDGE_CODE
+ } else if (pool_type == POOL_TYPE_HSIC) {
+ if (driver->diag_hsic_pool) {
+ if (driver->count_hsic_pool < driver->poolsize_hsic) {
+ atomic_add(1,
+ (atomic_t *)&driver->count_hsic_pool);
+ buf = mempool_alloc(driver->diag_hsic_pool,
+ GFP_ATOMIC);
+ }
+ }
+ } else if (pool_type == POOL_TYPE_HSIC_WRITE) {
+ if (driver->diag_hsic_write_pool) {
+ if (driver->count_hsic_write_pool <
+ driver->poolsize_hsic_write) {
+ atomic_add(1, (atomic_t *)
+ &driver->count_hsic_write_pool);
+ buf = mempool_alloc(
+ driver->diag_hsic_write_pool,
+ GFP_ATOMIC);
+ }
+ }
+#endif
}
return buf;
}
@@ -63,7 +85,7 @@
driver->diagpool = NULL;
} else if (driver->ref_count == 0 && pool_type == POOL_TYPE_ALL)
printk(KERN_ALERT "Unable to destroy COPY mempool");
- }
+ }
if (driver->diag_hdlc_pool) {
if (driver->count_hdlc_pool == 0 && driver->ref_count == 0) {
@@ -71,7 +93,7 @@
driver->diag_hdlc_pool = NULL;
} else if (driver->ref_count == 0 && pool_type == POOL_TYPE_ALL)
printk(KERN_ALERT "Unable to destroy HDLC mempool");
- }
+ }
if (driver->diag_write_struct_pool) {
/* Free up struct pool ONLY if there are no outstanding
@@ -82,7 +104,30 @@
driver->diag_write_struct_pool = NULL;
} else if (driver->ref_count == 0 && pool_type == POOL_TYPE_ALL)
printk(KERN_ALERT "Unable to destroy STRUCT mempool");
- }
+ }
+#ifdef CONFIG_DIAG_BRIDGE_CODE
+ if (driver->diag_hsic_pool && (driver->hsic_device_enabled == 0)) {
+ if (driver->count_hsic_pool == 0) {
+ mempool_destroy(driver->diag_hdlc_pool);
+ driver->diag_hdlc_pool = NULL;
+ } else if (pool_type == POOL_TYPE_ALL)
+ pr_err("Unable to destroy HDLC mempool");
+ }
+
+ if (driver->diag_hsic_write_pool &&
+ (driver->hsic_device_enabled == 0)) {
+ /*
+ * Free up struct pool ONLY if there are no outstanding
+ * transactions(aggregation buffer) with USB
+ */
+ if (driver->count_hsic_write_pool == 0 &&
+ driver->count_hsic_pool == 0) {
+ mempool_destroy(driver->diag_hsic_write_pool);
+ driver->diag_hsic_write_pool = NULL;
+ } else if (pool_type == POOL_TYPE_ALL)
+ pr_err("Unable to destroy HSIC USB struct mempool");
+ }
+#endif
}
void diagmem_free(struct diagchar_dev *driver, void *buf, int pool_type)
@@ -112,6 +157,29 @@
pr_err("diag: Attempt to free up DIAG driver "
"USB structure mempool which is already free %d ",
driver->count_write_struct_pool);
+#ifdef CONFIG_DIAG_BRIDGE_CODE
+ } else if (pool_type == POOL_TYPE_HSIC) {
+ if (driver->diag_hsic_pool != NULL &&
+ driver->count_hsic_pool > 0) {
+ mempool_free(buf, driver->diag_hsic_pool);
+ atomic_add(-1, (atomic_t *)&driver->count_hsic_pool);
+ } else
+ pr_err("diag: Attempt to free up DIAG driver HSIC mempool which is already free %d ",
+ driver->count_hsic_pool);
+ } else if (pool_type == POOL_TYPE_HSIC_WRITE) {
+ if (driver->diag_hsic_write_pool != NULL &&
+ driver->count_hsic_write_pool > 0) {
+ mempool_free(buf, driver->diag_hsic_write_pool);
+ atomic_add(-1,
+ (atomic_t *)&driver->count_hsic_write_pool);
+ } else
+ pr_err("diag: Attempt to free up DIAG driver HSIC USB structure mempool which is already free %d ",
+ driver->count_write_struct_pool);
+#endif
+ } else {
+ pr_err("diag: In %s, unknown pool type: %d\n",
+ __func__, pool_type);
+
}
diagmem_exit(driver, pool_type);
@@ -143,3 +211,25 @@
printk(KERN_INFO "Cannot allocate diag USB struct mempool\n");
}
+#ifdef CONFIG_DIAG_BRIDGE_CODE
+void diagmem_hsic_init(struct diagchar_dev *driver)
+{
+ if (driver->count_hsic_pool == 0)
+ driver->diag_hsic_pool = mempool_create_kmalloc_pool(
+ driver->poolsize_hsic,
+ driver->itemsize_hsic);
+
+ if (driver->count_hsic_write_pool == 0)
+ driver->diag_hsic_write_pool = mempool_create_kmalloc_pool(
+ driver->poolsize_hsic_write,
+ driver->itemsize_hsic_write);
+
+ if (!driver->diag_hsic_pool)
+ pr_err("Cannot allocate diag HSIC mempool\n");
+
+ if (!driver->diag_hsic_write_pool)
+ pr_err("Cannot allocate diag HSIC struct mempool\n");
+
+}
+#endif
+
diff --git a/drivers/char/diag/diagmem.h b/drivers/char/diag/diagmem.h
index 43829ae..8665c75 100644
--- a/drivers/char/diag/diagmem.h
+++ b/drivers/char/diag/diagmem.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2008-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
@@ -18,5 +18,7 @@
void diagmem_free(struct diagchar_dev *driver, void *buf, int pool_type);
void diagmem_init(struct diagchar_dev *driver);
void diagmem_exit(struct diagchar_dev *driver, int pool_type);
-
+#ifdef CONFIG_DIAG_BRIDGE_CODE
+void diagmem_hsic_init(struct diagchar_dev *driver);
+#endif
#endif
diff --git a/drivers/gpio/qpnp-pin.c b/drivers/gpio/qpnp-pin.c
index 7bfb208..67a2e6b 100644
--- a/drivers/gpio/qpnp-pin.c
+++ b/drivers/gpio/qpnp-pin.c
@@ -32,11 +32,17 @@
#define Q_REG_STATUS1 0x8
#define Q_REG_STATUS1_VAL_MASK 0x1
-#define Q_REG_STATUS1_GPIO_EN_MASK 0x2
+#define Q_REG_STATUS1_GPIO_EN_REV0_MASK 0x2
+#define Q_REG_STATUS1_GPIO_EN_MASK 0x80
#define Q_REG_STATUS1_MPP_EN_MASK 0x80
#define Q_NUM_CTL_REGS 0xD
+/* revision registers base address offsets */
+#define Q_REG_DIG_MINOR_REV 0x0
+#define Q_REG_DIG_MAJOR_REV 0x1
+#define Q_REG_ANA_MINOR_REV 0x2
+
/* type registers base address offsets */
#define Q_REG_TYPE 0x4
#define Q_REG_SUBTYPE 0x5
@@ -158,6 +164,7 @@
u8 num_ctl_regs; /* usable number on this pin */
u8 type; /* peripheral type */
u8 subtype; /* peripheral subtype */
+ u8 dig_major_rev;
struct device_node *node;
enum qpnp_pin_param_type params[Q_NUM_PARAMS];
struct qpnp_pin_chip *q_chip;
@@ -646,9 +653,14 @@
Q_REG_ADDR(q_spec, Q_REG_STATUS1),
&buf[0], 1);
- en_mask = q_spec->type == Q_GPIO_TYPE ?
- Q_REG_STATUS1_GPIO_EN_MASK :
- Q_REG_STATUS1_MPP_EN_MASK;
+ if (q_spec->type == Q_GPIO_TYPE && q_spec->dig_major_rev == 0)
+ en_mask = Q_REG_STATUS1_GPIO_EN_REV0_MASK;
+ else if (q_spec->type == Q_GPIO_TYPE &&
+ q_spec->dig_major_rev > 0)
+ en_mask = Q_REG_STATUS1_GPIO_EN_MASK;
+ else /* MPP */
+ en_mask = Q_REG_STATUS1_MPP_EN_MASK;
+
if (!(buf[0] & en_mask))
return -EPERM;
@@ -1099,6 +1111,28 @@
}
#endif
+static int qpnp_pin_is_valid_pin(struct qpnp_pin_spec *q_spec)
+{
+ if (q_spec->type == Q_GPIO_TYPE)
+ switch (q_spec->subtype) {
+ case Q_GPIO_SUBTYPE_GPIO_4CH:
+ case Q_GPIO_SUBTYPE_GPIOC_4CH:
+ case Q_GPIO_SUBTYPE_GPIO_8CH:
+ case Q_GPIO_SUBTYPE_GPIOC_8CH:
+ return 1;
+ }
+ else if (q_spec->type == Q_MPP_TYPE)
+ switch (q_spec->subtype) {
+ case Q_MPP_SUBTYPE_4CH_NO_ANA_OUT:
+ case Q_MPP_SUBTYPE_4CH_NO_SINK:
+ case Q_MPP_SUBTYPE_4CH_FULL_FUNC:
+ case Q_MPP_SUBTYPE_8CH_FULL_FUNC:
+ return 1;
+ }
+
+ return 0;
+}
+
static int qpnp_pin_probe(struct spmi_device *spmi)
{
struct qpnp_pin_chip *q_chip;
@@ -1108,7 +1142,7 @@
int i, rc;
int lowest_gpio = UINT_MAX, highest_gpio = 0;
u32 intspec[3], gpio;
- char buf[2];
+ char version[Q_REG_SUBTYPE - Q_REG_DIG_MAJOR_REV + 1];
const char *dev_name;
dev_name = spmi_get_primary_dev_name(spmi);
@@ -1218,14 +1252,23 @@
q_spec->q_chip = q_chip;
rc = spmi_ext_register_readl(spmi->ctrl, q_spec->slave,
- Q_REG_ADDR(q_spec, Q_REG_TYPE), &buf[0], 2);
+ Q_REG_ADDR(q_spec, Q_REG_DIG_MAJOR_REV),
+ &version[0], ARRAY_SIZE(version));
if (rc) {
dev_err(&spmi->dev, "%s: unable to read type regs\n",
__func__);
goto err_probe;
}
- q_spec->type = buf[0];
- q_spec->subtype = buf[1];
+ q_spec->dig_major_rev = version[Q_REG_DIG_MAJOR_REV -
+ Q_REG_DIG_MAJOR_REV];
+ q_spec->type = version[Q_REG_TYPE - Q_REG_DIG_MAJOR_REV];
+ q_spec->subtype = version[Q_REG_SUBTYPE - Q_REG_DIG_MAJOR_REV];
+
+ if (!qpnp_pin_is_valid_pin(q_spec)) {
+ dev_err(&spmi->dev, "%s: invalid pin type (type=0x%x subtype=0x%x)\n",
+ __func__, q_spec->type, q_spec->subtype);
+ goto err_probe;
+ }
rc = qpnp_pin_ctl_regs_init(q_spec);
if (rc)
diff --git a/drivers/gpu/msm/a3xx_reg.h b/drivers/gpu/msm/a3xx_reg.h
index 33fcbfd..6fe316a 100644
--- a/drivers/gpu/msm/a3xx_reg.h
+++ b/drivers/gpu/msm/a3xx_reg.h
@@ -151,9 +151,11 @@
#define A3XX_GRAS_CL_USER_PLANE_Y5 0xCB5
#define A3XX_GRAS_CL_USER_PLANE_Z5 0xCB6
#define A3XX_GRAS_CL_USER_PLANE_W5 0xCB7
+#define A3XX_RB_GMEM_BASE_ADDR 0xCC0
#define A3XX_VFD_PERFCOUNTER0_SELECT 0xE44
#define A3XX_VPC_VPC_DEBUG_RAM_SEL 0xE61
#define A3XX_VPC_VPC_DEBUG_RAM_READ 0xE62
+#define A3XX_UCHE_CACHE_MODE_CONTROL_REG 0xE82
#define A3XX_UCHE_CACHE_INVALIDATE0_REG 0xEA0
#define A3XX_GRAS_CL_CLIP_CNTL 0x2040
#define A3XX_GRAS_CL_GB_CLIP_ADJ 0x2044
@@ -234,6 +236,7 @@
#define A3XX_TPL1_TP_VS_TEX_OFFSET 0x2340
#define A3XX_TPL1_TP_FS_TEX_OFFSET 0x2342
#define A3XX_TPL1_TP_FS_BORDER_COLOR_BASE_ADDR 0x2343
+#define A3XX_VBIF_CLKON 0x3001
#define A3XX_VBIF_FIXED_SORT_EN 0x300C
#define A3XX_VBIF_FIXED_SORT_SEL0 0x300D
#define A3XX_VBIF_FIXED_SORT_SEL1 0x300E
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 6e95fff..d99d398 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -1107,7 +1107,7 @@
return -ENOMEM;
adreno_dev->gmem_size = adreno_dev->ocmem_hdl->len;
- adreno_dev->gmem_base = adreno_dev->ocmem_hdl->addr;
+ adreno_dev->ocmem_base = adreno_dev->ocmem_hdl->addr;
return 0;
}
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 26d5eaa..d151255 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -98,6 +98,7 @@
unsigned int ib_check_level;
unsigned int fast_hang_detect;
struct ocmem_buf *ocmem_hdl;
+ unsigned int ocmem_base;
};
struct adreno_gpudev {
diff --git a/drivers/gpu/msm/adreno_a2xx.c b/drivers/gpu/msm/adreno_a2xx.c
index 5ba3778..23d61ff 100644
--- a/drivers/gpu/msm/adreno_a2xx.c
+++ b/drivers/gpu/msm/adreno_a2xx.c
@@ -1507,7 +1507,7 @@
{
struct kgsl_device *device = &adreno_dev->dev;
- if (context == NULL)
+ if (context == NULL || (context->flags & CTXT_FLAGS_BEING_DESTOYED))
return;
if (context->flags & CTXT_FLAGS_GPU_HANG)
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index 5ce34db..4b3263d 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -2347,7 +2347,7 @@
{
struct kgsl_device *device = &adreno_dev->dev;
- if (context == NULL)
+ if (context == NULL || (context->flags & CTXT_FLAGS_BEING_DESTOYED))
return;
if (context->flags & CTXT_FLAGS_GPU_HANG)
@@ -2699,13 +2699,13 @@
/* Set up 16 deep read/write request queues */
if (adreno_dev->gpurev == ADRENO_REV_A330) {
- adreno_regwrite(device, A3XX_VBIF_IN_RD_LIM_CONF0, 0x01010101);
- adreno_regwrite(device, A3XX_VBIF_IN_RD_LIM_CONF1, 0x01010101);
- adreno_regwrite(device, A3XX_VBIF_OUT_RD_LIM_CONF0, 0x01010101);
- adreno_regwrite(device, A3XX_VBIF_OUT_WR_LIM_CONF0, 0x01010101);
+ adreno_regwrite(device, A3XX_VBIF_IN_RD_LIM_CONF0, 0x18181818);
+ adreno_regwrite(device, A3XX_VBIF_IN_RD_LIM_CONF1, 0x18181818);
+ adreno_regwrite(device, A3XX_VBIF_OUT_RD_LIM_CONF0, 0x18181818);
+ adreno_regwrite(device, A3XX_VBIF_OUT_WR_LIM_CONF0, 0x18181818);
adreno_regwrite(device, A3XX_VBIF_DDR_OUT_MAX_BURST, 0x0000303);
- adreno_regwrite(device, A3XX_VBIF_IN_WR_LIM_CONF0, 0x01010101);
- adreno_regwrite(device, A3XX_VBIF_IN_WR_LIM_CONF1, 0x01010101);
+ adreno_regwrite(device, A3XX_VBIF_IN_WR_LIM_CONF0, 0x18181818);
+ adreno_regwrite(device, A3XX_VBIF_IN_WR_LIM_CONF1, 0x18181818);
/* Enable WR-REQ */
adreno_regwrite(device, A3XX_VBIF_GATE_OFF_WRREQ_EN, 0x00003F);
@@ -2721,6 +2721,11 @@
/* Enable 1K sort */
adreno_regwrite(device, A3XX_VBIF_ABIT_SORT, 0x1FFFF);
adreno_regwrite(device, A3XX_VBIF_ABIT_SORT_CONF, 0x000000A4);
+
+ /* Diable VBIF clock gating. This is to enable AXI running
+ * higher frequency than GPU.
+ */
+ adreno_regwrite(device, A3XX_VBIF_CLKON, 1);
} else {
adreno_regwrite(device, A3XX_VBIF_IN_RD_LIM_CONF0, 0x10101010);
adreno_regwrite(device, A3XX_VBIF_IN_RD_LIM_CONF1, 0x10101010);
@@ -2768,10 +2773,18 @@
adreno_regwrite(device, A3XX_RBBM_INTERFACE_HANG_INT_CTL,
(1 << 16) | 0xFFF);
+ /* Enable 64-byte cacheline size. HW Default is 32-byte (0x000000E0). */
+ adreno_regwrite(device, A3XX_UCHE_CACHE_MODE_CONTROL_REG, 0x00000001);
+
/* Enable Clock gating */
adreno_regwrite(device, A3XX_RBBM_CLOCK_CTL,
A3XX_RBBM_CLOCK_CTL_DEFAULT);
+ /* Set the OCMEM base address for A330 */
+ if (adreno_dev->gpurev == ADRENO_REV_A330) {
+ adreno_regwrite(device, A3XX_RB_GMEM_BASE_ADDR,
+ (unsigned int)(adreno_dev->ocmem_base >> 14));
+ }
}
/* Defined in adreno_a3xx_snapshot.c */
diff --git a/drivers/gpu/msm/adreno_drawctxt.c b/drivers/gpu/msm/adreno_drawctxt.c
index bd22233..a50747d 100644
--- a/drivers/gpu/msm/adreno_drawctxt.c
+++ b/drivers/gpu/msm/adreno_drawctxt.c
@@ -221,11 +221,17 @@
CTXT_FLAGS_GMEM_SHADOW |
CTXT_FLAGS_STATE_SHADOW);
+ drawctxt->flags |= CTXT_FLAGS_BEING_DESTOYED;
+
adreno_drawctxt_switch(adreno_dev, NULL, 0);
}
adreno_idle(device);
+ if (adreno_is_a20x(adreno_dev) && adreno_dev->drawctxt_active)
+ kgsl_setstate(&device->mmu, adreno_dev->drawctxt_active->id,
+ KGSL_MMUFLAGS_PTUPDATE);
+
kgsl_sharedmem_free(&drawctxt->gpustate);
kgsl_sharedmem_free(&drawctxt->context_gmem_shadow.gmemshadow);
diff --git a/drivers/gpu/msm/adreno_drawctxt.h b/drivers/gpu/msm/adreno_drawctxt.h
index 5b14a69..d58f2da 100644
--- a/drivers/gpu/msm/adreno_drawctxt.h
+++ b/drivers/gpu/msm/adreno_drawctxt.h
@@ -46,6 +46,8 @@
#define CTXT_FLAGS_PER_CONTEXT_TS 0x00040000
/* Context has caused a GPU hang and recovered properly */
#define CTXT_FLAGS_GPU_HANG_RECOVERED 0x00008000
+/* Context is being destroyed so dont save it */
+#define CTXT_FLAGS_BEING_DESTOYED 0x00010000
struct kgsl_device;
struct adreno_device;
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index ad9007f..1a9da60 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -401,8 +401,15 @@
void adreno_ringbuffer_stop(struct adreno_ringbuffer *rb)
{
- if (rb->flags & KGSL_FLAGS_STARTED)
+ struct kgsl_device *device = rb->device;
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+
+ if (rb->flags & KGSL_FLAGS_STARTED) {
+ if (adreno_is_a200(adreno_dev))
+ adreno_regwrite(rb->device, REG_CP_ME_CNTL, 0x10000000);
+
rb->flags &= ~KGSL_FLAGS_STARTED;
+ }
}
int adreno_ringbuffer_init(struct kgsl_device *device)
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index 7254647..71dfe8c 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -36,6 +36,14 @@
{ 0x800, 0, 0 }, /* TLBIALL */
};
+static struct kgsl_iommu_register_list kgsl_iommuv2_reg[KGSL_IOMMU_REG_MAX] = {
+ { 0, 0, 0 }, /* GLOBAL_BASE */
+ { 0x20, 0x00FFFFFF, 14 }, /* TTBR0 */
+ { 0x28, 0x00FFFFFF, 14 }, /* TTBR1 */
+ { 0x58, 0, 0 }, /* FSR */
+ { 0x618, 0, 0 } /* TLBIALL */
+};
+
static int get_iommu_unit(struct device *dev, struct kgsl_mmu **mmu_out,
struct kgsl_iommu_unit **iommu_unit_out)
{
@@ -354,8 +362,13 @@
sizeof(struct kgsl_iommu_pt));
return NULL;
}
- iommu_pt->domain = iommu_domain_alloc(&platform_bus_type,
+ /* L2 redirect is not stable on IOMMU v2 */
+ if (msm_soc_version_supports_iommu_v1())
+ iommu_pt->domain = iommu_domain_alloc(&platform_bus_type,
MSM_IOMMU_DOMAIN_PT_CACHEABLE);
+ else
+ iommu_pt->domain = iommu_domain_alloc(&platform_bus_type,
+ 0);
if (!iommu_pt->domain) {
KGSL_CORE_ERR("Failed to create iommu domain\n");
kfree(iommu_pt);
@@ -703,6 +716,14 @@
iommu->iommu_reg_list = kgsl_iommuv1_reg;
iommu->ctx_offset = KGSL_IOMMU_CTX_OFFSET_V1;
+ if (msm_soc_version_supports_iommu_v1()) {
+ iommu->iommu_reg_list = kgsl_iommuv1_reg;
+ iommu->ctx_offset = KGSL_IOMMU_CTX_OFFSET_V1;
+ } else {
+ iommu->iommu_reg_list = kgsl_iommuv2_reg;
+ iommu->ctx_offset = KGSL_IOMMU_CTX_OFFSET_V2;
+ }
+
/* A nop is required in an indirect buffer when switching
* pagetables in-stream */
kgsl_sharedmem_writel(&mmu->setstate_memory,
@@ -733,19 +754,17 @@
int status = 0;
int i = 0;
struct kgsl_iommu *iommu = mmu->priv;
- struct kgsl_iommu_pt *iommu_pt;
struct kgsl_pagetable *pagetable = NULL;
/* If chip is not 8960 then we use the 2nd context bank for pagetable
* switching on the 3D side for which a separate table is allocated */
- if (!cpu_is_msm8960()) {
+ if (!cpu_is_msm8960() && msm_soc_version_supports_iommu_v1()) {
mmu->priv_bank_table =
kgsl_mmu_getpagetable(KGSL_MMU_PRIV_BANK_TABLE_NAME);
if (mmu->priv_bank_table == NULL) {
status = -ENOMEM;
goto err;
}
- iommu_pt = mmu->priv_bank_table->priv;
}
mmu->defaultpagetable = kgsl_mmu_getpagetable(KGSL_MMU_GLOBAL_PT);
/* Return error if the default pagetable doesn't exist */
@@ -756,16 +775,18 @@
pagetable = mmu->priv_bank_table ? mmu->priv_bank_table :
mmu->defaultpagetable;
/* Map the IOMMU regsiters to only defaultpagetable */
- for (i = 0; i < iommu->unit_count; i++) {
- iommu->iommu_units[i].reg_map.priv |=
- KGSL_MEMFLAGS_GLOBAL;
- status = kgsl_mmu_map(pagetable,
- &(iommu->iommu_units[i].reg_map),
- GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
- if (status) {
- iommu->iommu_units[i].reg_map.priv &=
- ~KGSL_MEMFLAGS_GLOBAL;
- goto err;
+ if (msm_soc_version_supports_iommu_v1()) {
+ for (i = 0; i < iommu->unit_count; i++) {
+ iommu->iommu_units[i].reg_map.priv |=
+ KGSL_MEMFLAGS_GLOBAL;
+ status = kgsl_mmu_map(pagetable,
+ &(iommu->iommu_units[i].reg_map),
+ GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
+ if (status) {
+ iommu->iommu_units[i].reg_map.priv &=
+ ~KGSL_MEMFLAGS_GLOBAL;
+ goto err;
+ }
}
}
return status;
@@ -884,7 +905,7 @@
* Flushing only required if per process pagetables are used. With
* global case, flushing will happen inside iommu_map function
*/
- if (!ret)
+ if (!ret && msm_soc_version_supports_iommu_v1())
*tlb_flags = UINT_MAX;
#endif
return 0;
diff --git a/drivers/gpu/msm/kgsl_iommu.h b/drivers/gpu/msm/kgsl_iommu.h
index 7dc222e..eafba7b 100644
--- a/drivers/gpu/msm/kgsl_iommu.h
+++ b/drivers/gpu/msm/kgsl_iommu.h
@@ -16,6 +16,7 @@
#include <mach/iommu.h>
#define KGSL_IOMMU_CTX_OFFSET_V1 0
+#define KGSL_IOMMU_CTX_OFFSET_V2 0x8000
#define KGSL_IOMMU_CTX_SHIFT 12
enum kgsl_iommu_reg_map {
diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c
index 3aea81f..dee889d 100644
--- a/drivers/gpu/msm/kgsl_mmu.c
+++ b/drivers/gpu/msm/kgsl_mmu.c
@@ -531,6 +531,10 @@
#ifndef CONFIG_KGSL_PER_PROCESS_PAGE_TABLE
name = KGSL_MMU_GLOBAL_PT;
#endif
+ /* We presently do not support per-process for IOMMU-v2 */
+ if (!msm_soc_version_supports_iommu_v1())
+ name = KGSL_MMU_GLOBAL_PT;
+
pt = kgsl_get_pagetable(name);
if (pt == NULL)
diff --git a/drivers/hwmon/epm_adc.c b/drivers/hwmon/epm_adc.c
index fd4524e..ab15945 100644
--- a/drivers/hwmon/epm_adc.c
+++ b/drivers/hwmon/epm_adc.c
@@ -68,6 +68,8 @@
#define EPM_ADC_CONVERSION_TIME_MIN 50000
#define EPM_ADC_CONVERSION_TIME_MAX 51000
+#define EPM_SPI_NOR_CS_N_GPIO 53
+
struct epm_adc_drv {
struct platform_device *pdev;
struct device *hwmon;
@@ -135,6 +137,14 @@
{
int rc = 0;
+ rc = gpio_request(EPM_SPI_NOR_CS_N_GPIO, "SPI_NOR_CS_N");
+ if (!rc)
+ gpio_direction_output(EPM_SPI_NOR_CS_N_GPIO, 1);
+ else {
+ pr_err("Configure spi nor Failed\n");
+ return -EINVAL;
+ }
+
if (epm_adc_first_request) {
rc = gpio_request(GPIO_EPM_GLOBAL_ENABLE, "EPM_GLOBAL_EN");
if (!rc) {
@@ -479,7 +489,7 @@
struct epm_adc_platform_data *pdata = epm_adc->pdev->dev.platform_data;
uint32_t chan_idx = (conv->device_idx * pdata->chan_per_adc) +
conv->channel_idx;
- int32_t *adc_scaled_data = &conv->physical;
+ int64_t *adc_scaled_data = 0;
/* Get the channel number */
channel_num = (adc_raw_data[0] & EPM_ADC_ADS_CHANNEL_DATA_CHID);
@@ -489,17 +499,17 @@
/* Obtain the internal system reading */
if (channel_num == EPM_ADC_ADS_CHANNEL_VCC) {
*adc_scaled_data *= EPM_ADC_SCALE_MILLI;
- *adc_scaled_data /= EPM_ADC_SCALE_CODE_VOLTS;
+ do_div(*adc_scaled_data, EPM_ADC_SCALE_CODE_VOLTS);
} else if (channel_num == EPM_ADC_ADS_CHANNEL_GAIN) {
- *adc_scaled_data /= EPM_ADC_SCALE_CODE_GAIN;
+ do_div(*adc_scaled_data, EPM_ADC_SCALE_CODE_GAIN);
} else if (channel_num == EPM_ADC_ADS_CHANNEL_REF) {
*adc_scaled_data *= EPM_ADC_SCALE_MILLI;
- *adc_scaled_data /= EPM_ADC_SCALE_CODE_VOLTS;
+ do_div(*adc_scaled_data, EPM_ADC_SCALE_CODE_VOLTS);
} else if (channel_num == EPM_ADC_ADS_CHANNEL_TEMP) {
/* Convert Code to micro-volts */
/* Use this formula to get the temperature reading */
*adc_scaled_data -= EPM_ADC_TEMP_TO_DEGC_COEFF;
- *adc_scaled_data /= EPM_ADC_TEMP_SENSOR_COEFF;
+ do_div(*adc_scaled_data, EPM_ADC_TEMP_SENSOR_COEFF);
} else if (channel_num == EPM_ADC_ADS_CHANNEL_OFFSET) {
/* The offset should be zero */
pr_debug("%s: ADC Channel Offset\n", __func__);
@@ -520,21 +530,23 @@
*adc_scaled_data *= EPM_ADC_SCALE_FACTOR;
/* Device is calibrated for 1LSB = VREF/7800h.*/
*adc_scaled_data *= EPM_ADC_MILLI_VOLTS_SOURCE;
- *adc_scaled_data /= EPM_ADC_VREF_CODE;
+ do_div(*adc_scaled_data, EPM_ADC_VREF_CODE);
/* Data will now be in micro-volts.*/
*adc_scaled_data *= EPM_ADC_SCALE_MILLI;
/* Divide by amplifier gain value.*/
- *adc_scaled_data /= pdata->channel[chan_idx].gain;
+ do_div(*adc_scaled_data, pdata->channel[chan_idx].gain);
/* Data will now be in nano-volts.*/
- *adc_scaled_data /= EPM_ADC_SCALE_FACTOR;
+ do_div(*adc_scaled_data, EPM_ADC_SCALE_FACTOR);
*adc_scaled_data *= EPM_ADC_SCALE_MILLI;
/* Data is now in micro-amps.*/
- *adc_scaled_data /=
- pdata->channel[chan_idx].resistorValue;
+ do_div(*adc_scaled_data,
+ pdata->channel[chan_idx].resistorValue);
/* Set the sign bit for lekage current. */
*adc_scaled_data *= sign_bit;
}
}
+ conv->physical = (int32_t) *adc_scaled_data;
+
return 0;
}
diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index c1617bff..085b632 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -328,12 +328,14 @@
dev->clk_state = state;
if (state != 0) {
clk_enable(dev->clk);
- clk_enable(dev->pclk);
+ if (!dev->pdata->keep_ahb_clk_on)
+ clk_enable(dev->pclk);
} else {
qup_update_state(dev, QUP_RESET_STATE);
clk_disable(dev->clk);
qup_config_core_on_en(dev);
- clk_disable(dev->pclk);
+ if (!dev->pdata->keep_ahb_clk_on)
+ clk_disable(dev->pclk);
}
}
@@ -1325,6 +1327,12 @@
dev->clk_state = 0;
clk_prepare(dev->clk);
clk_prepare(dev->pclk);
+ /* If the same AHB clock is used on Modem side
+ * switch it on here itself and don't switch it
+ * on and off during suspend and resume.
+ */
+ if (dev->pdata->keep_ahb_clk_on)
+ clk_enable(dev->pclk);
setup_timer(&dev->pwr_timer, qup_i2c_pwr_timer, (unsigned long) dev);
pm_runtime_set_active(&pdev->dev);
@@ -1396,9 +1404,11 @@
free_irq(dev->err_irq, dev);
i2c_del_adapter(&dev->adapter);
clk_unprepare(dev->clk);
- clk_unprepare(dev->pclk);
+ if (!dev->pdata->keep_ahb_clk_on) {
+ clk_unprepare(dev->pclk);
+ clk_put(dev->pclk);
+ }
clk_put(dev->clk);
- clk_put(dev->pclk);
qup_i2c_free_gpios(dev);
if (dev->gsbi)
iounmap(dev->gsbi);
@@ -1434,7 +1444,8 @@
if (dev->clk_state != 0)
qup_i2c_pwr_mgmt(dev, 0);
clk_unprepare(dev->clk);
- clk_unprepare(dev->pclk);
+ if (!dev->pdata->keep_ahb_clk_on)
+ clk_unprepare(dev->pclk);
qup_i2c_free_gpios(dev);
return 0;
}
@@ -1445,7 +1456,8 @@
struct qup_i2c_dev *dev = platform_get_drvdata(pdev);
BUG_ON(qup_i2c_request_gpios(dev) != 0);
clk_prepare(dev->clk);
- clk_prepare(dev->pclk);
+ if (!dev->pdata->keep_ahb_clk_on)
+ clk_prepare(dev->pclk);
dev->suspended = 0;
return 0;
}
diff --git a/drivers/input/misc/mpu3050.c b/drivers/input/misc/mpu3050.c
index d3da652..04a7598 100644
--- a/drivers/input/misc/mpu3050.c
+++ b/drivers/input/misc/mpu3050.c
@@ -123,6 +123,7 @@
struct delayed_work input_work;
u32 use_poll;
u32 poll_interval;
+ u32 dlpf_index;
};
struct sensor_regulator {
@@ -137,6 +138,39 @@
{NULL, "vlogic", 1800000, 1800000},
};
+struct dlpf_cfg_tb {
+ u8 cfg; /* cfg index */
+ u32 lpf_bw; /* low pass filter bandwidth in Hz */
+ u32 sample_rate; /* analog sample rate in Khz, 1 or 8 */
+};
+
+static struct dlpf_cfg_tb dlpf_table[] = {
+ {6, 5, 1},
+ {5, 10, 1},
+ {4, 20, 1},
+ {3, 42, 1},
+ {2, 98, 1},
+ {1, 188, 1},
+ {0, 256, 8},
+};
+
+static u8 interval_to_dlpf_cfg(u32 interval)
+{
+ u32 sample_rate = 1000 / interval;
+ u32 i;
+
+ /* the filter bandwidth needs to be greater or
+ * equal to half of the sample rate
+ */
+ for (i = 0; i < sizeof(dlpf_table)/sizeof(dlpf_table[0]); i++) {
+ if (dlpf_table[i].lpf_bw * 2 >= sample_rate)
+ return i;
+ }
+
+ /* return the maximum possible */
+ return --i;
+}
+
static int mpu3050_config_regulator(struct i2c_client *client, bool on)
{
int rc = 0, i;
@@ -217,6 +251,9 @@
{
struct mpu3050_sensor *sensor = dev_get_drvdata(dev);
unsigned long interval_ms;
+ unsigned int dlpf_index;
+ u8 divider, reg;
+ int ret;
if (kstrtoul(buf, 10, &interval_ms))
return -EINVAL;
@@ -224,12 +261,27 @@
(interval_ms > MPU3050_MAX_POLL_INTERVAL))
return -EINVAL;
- if (sensor)
- sensor->poll_interval = interval_ms;
+ dlpf_index = interval_to_dlpf_cfg(interval_ms);
+ divider = interval_ms * dlpf_table[dlpf_index].sample_rate - 1;
- /* Output frequency divider. The poll interval */
- i2c_smbus_write_byte_data(sensor->client, MPU3050_SMPLRT_DIV,
- interval_ms - 1);
+ if (sensor->dlpf_index != dlpf_index) {
+ /* Set low pass filter and full scale */
+ reg = dlpf_table[dlpf_index].cfg;
+ reg |= MPU3050_DEFAULT_FS_RANGE << 3;
+ reg |= MPU3050_EXT_SYNC_NONE << 5;
+ ret = i2c_smbus_write_byte_data(sensor->client,
+ MPU3050_DLPF_FS_SYNC, reg);
+ if (ret == 0)
+ sensor->dlpf_index = dlpf_index;
+ }
+
+ if (sensor->poll_interval != interval_ms) {
+ /* Output frequency divider. The poll interval */
+ ret = i2c_smbus_write_byte_data(sensor->client,
+ MPU3050_SMPLRT_DIV, divider);
+ if (ret == 0)
+ sensor->poll_interval = interval_ms;
+ }
return size;
}
@@ -482,8 +534,8 @@
return ret;
/* Set low pass filter and full scale */
- reg = MPU3050_DEFAULT_FS_RANGE;
- reg |= MPU3050_DLPF_CFG_42HZ << 3;
+ reg = MPU3050_DLPF_CFG_42HZ;
+ reg |= MPU3050_DEFAULT_FS_RANGE << 3;
reg |= MPU3050_EXT_SYNC_NONE << 5;
ret = i2c_smbus_write_byte_data(client, MPU3050_DLPF_FS_SYNC, reg);
if (ret < 0)
diff --git a/drivers/leds/leds-pm8xxx.c b/drivers/leds/leds-pm8xxx.c
index 04041e4..255920e 100644
--- a/drivers/leds/leds-pm8xxx.c
+++ b/drivers/leds/leds-pm8xxx.c
@@ -80,6 +80,17 @@
#define WLED_SYNC_VAL 0x07
#define WLED_SYNC_RESET_VAL 0x00
+#define WLED_SYNC_MASK 0xF8
+
+#define ONE_WLED_STRING 1
+#define TWO_WLED_STRINGS 2
+#define THREE_WLED_STRINGS 3
+
+#define WLED_CABC_ONE_STRING 0x01
+#define WLED_CABC_TWO_STRING 0x03
+#define WLED_CABC_THREE_STRING 0x07
+
+#define WLED_CABC_SHIFT 3
#define SSBI_REG_ADDR_RGB_CNTL1 0x12D
#define SSBI_REG_ADDR_RGB_CNTL2 0x12E
@@ -290,17 +301,23 @@
return rc;
}
}
-
+ rc = pm8xxx_readb(led->dev->parent, WLED_SYNC_REG, &val);
+ if (rc) {
+ dev_err(led->dev->parent,
+ "can't read wled sync register rc=%d\n", rc);
+ return rc;
+ }
/* sync */
- val = WLED_SYNC_VAL;
+ val &= WLED_SYNC_MASK;
+ val |= WLED_SYNC_VAL;
rc = pm8xxx_writeb(led->dev->parent, WLED_SYNC_REG, val);
if (rc) {
dev_err(led->dev->parent,
"can't read wled sync register rc=%d\n", rc);
return rc;
}
-
- val = WLED_SYNC_RESET_VAL;
+ val &= WLED_SYNC_MASK;
+ val |= WLED_SYNC_RESET_VAL;
rc = pm8xxx_writeb(led->dev->parent, WLED_SYNC_REG, val);
if (rc) {
dev_err(led->dev->parent,
@@ -656,6 +673,36 @@
}
}
+ if (led->wled_cfg->cabc_en) {
+ rc = pm8xxx_readb(led->dev->parent, WLED_SYNC_REG, &val);
+ if (rc) {
+ dev_err(led->dev->parent,
+ "can't read cabc register rc=%d\n", rc);
+ return rc;
+ }
+
+ switch (num_wled_strings) {
+ case ONE_WLED_STRING:
+ val |= (WLED_CABC_ONE_STRING << WLED_CABC_SHIFT);
+ break;
+ case TWO_WLED_STRINGS:
+ val |= (WLED_CABC_TWO_STRING << WLED_CABC_SHIFT);
+ break;
+ case THREE_WLED_STRINGS:
+ val |= (WLED_CABC_THREE_STRING << WLED_CABC_SHIFT);
+ break;
+ default:
+ break;
+ }
+
+ rc = pm8xxx_writeb(led->dev->parent, WLED_SYNC_REG, val);
+ if (rc) {
+ dev_err(led->dev->parent,
+ "can't write to enable cabc rc=%d\n", rc);
+ return rc;
+ }
+ }
+
/* program digital module generator, cs out and enable the module */
rc = pm8xxx_readb(led->dev->parent, WLED_MOD_CTRL_REG, &val);
if (rc) {
diff --git a/drivers/media/dvb/mpq/Kconfig b/drivers/media/dvb/mpq/Kconfig
index 868ad8c..766312c 100644
--- a/drivers/media/dvb/mpq/Kconfig
+++ b/drivers/media/dvb/mpq/Kconfig
@@ -8,5 +8,5 @@
Say Y or M if you own such a device and want to use it.
source "drivers/media/dvb/mpq/demux/Kconfig"
-
+source "drivers/media/dvb/mpq/video/Kconfig"
diff --git a/drivers/media/dvb/mpq/Makefile b/drivers/media/dvb/mpq/Makefile
index 7ccf13e..a8d7137 100644
--- a/drivers/media/dvb/mpq/Makefile
+++ b/drivers/media/dvb/mpq/Makefile
@@ -1,5 +1,5 @@
obj-$(CONFIG_DVB_MPQ) += adapter/
obj-$(CONFIG_DVB_MPQ_DEMUX) += demux/
-
+obj-$(CONFIG_DVB_MPQ_VIDEO) += video/
diff --git a/drivers/media/dvb/mpq/video/Kconfig b/drivers/media/dvb/mpq/video/Kconfig
new file mode 100644
index 0000000..1344a67
--- /dev/null
+++ b/drivers/media/dvb/mpq/video/Kconfig
@@ -0,0 +1,16 @@
+config DVB_MPQ_VIDEO
+ tristate "DVB Video Device"
+ depends on DVB_MPQ
+
+ ---help---
+ This is a dvb/video interface with extensions for
+ Qualcomm Chipset Video hardware. For dvb/video
+ specification please check http://linuxtv.org/
+
+ Say Y or M if you own such a device and want to use it.
+
+config DVB_MPQ_NUM_VIDEO_DEVICES
+ int "Number of video devices"
+ depends on DVB_MPQ_VIDEO
+ default 4
+ range 1 255
diff --git a/drivers/media/dvb/mpq/video/Makefile b/drivers/media/dvb/mpq/video/Makefile
new file mode 100644
index 0000000..38c1091
--- /dev/null
+++ b/drivers/media/dvb/mpq/video/Makefile
@@ -0,0 +1,5 @@
+
+ccflags-y += -Idrivers/media/dvb/dvb-core/
+ccflags-y += -Idrivers/media/dvb/mpq/include/
+
+obj-$(CONFIG_DVB_MPQ_VIDEO) += mpq_dvb_video.o
diff --git a/drivers/media/dvb/mpq/video/mpq_dvb_video.c b/drivers/media/dvb/mpq/video/mpq_dvb_video.c
new file mode 100644
index 0000000..cd0f605
--- /dev/null
+++ b/drivers/media/dvb/mpq/video/mpq_dvb_video.c
@@ -0,0 +1,2407 @@
+/* Copyright (c) 2010-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/cdev.h>
+#include <linux/device.h>
+#include <linux/firmware.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/poll.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/kthread.h>
+#include <linux/uaccess.h>
+#include <linux/wait.h>
+#include <linux/workqueue.h>
+#include <linux/android_pmem.h>
+#include <linux/clk.h>
+#include <linux/timer.h>
+#include <mach/msm_subsystem_map.h>
+#include <media/msm/vidc_type.h>
+#include <media/msm/vcd_api.h>
+#include <media/msm/vidc_init.h>
+#include "mpq_dvb_video_internal.h"
+
+
+#define DBG(x...) pr_debug(x)
+#define INFO(x...) pr_info(x)
+#define ERR(x...) pr_err(x)
+
+#define MPQ_VID_DEC_NAME "mpq_vidc_dec"
+static unsigned int vidc_mmu_subsystem[] = {
+ MSM_SUBSYSTEM_VIDEO};
+
+static char vid_thread_names[DVB_MPQ_NUM_VIDEO_DEVICES][10] = {
+ "dvb-vid-0",
+ "dvb-vid-1",
+ "dvb-vid-2",
+ "dvb-vid-3",
+};
+
+static int mpq_int_vid_dec_decode_frame(struct video_client_ctx *client_ctx,
+ struct video_data_buffer *input_frame);
+
+static struct mpq_dvb_video_dev *mpq_dvb_video_device;
+
+static int mpq_get_dev_frm_client(struct video_client_ctx *client_ctx,
+ struct mpq_dvb_video_inst **dev_inst)
+{
+ int i;
+
+ mutex_lock(&mpq_dvb_video_device->lock);
+ for (i = 0; i < DVB_MPQ_NUM_VIDEO_DEVICES; i++) {
+ if (mpq_dvb_video_device->dev_inst[i].client_ctx ==
+ client_ctx) {
+ *dev_inst = &mpq_dvb_video_device->dev_inst[i];
+ break;
+ }
+ }
+ mutex_unlock(&mpq_dvb_video_device->lock);
+
+ if (i == DVB_MPQ_NUM_VIDEO_DEVICES)
+ return -ENODEV;
+
+ return 0;
+}
+
+static u32 mpq_int_check_bcast_mq(struct mpq_dmx_src_data *dmx_data)
+{
+ u32 islist_empty = 0;
+ mutex_lock(&dmx_data->msg_queue_lock);
+ islist_empty = list_empty(&dmx_data->msg_queue);
+ mutex_unlock(&dmx_data->msg_queue_lock);
+
+ return !islist_empty;
+}
+
+static void mpq_get_frame_and_write(struct mpq_dvb_video_inst *dev_inst,
+ unsigned int free_buf)
+{
+ struct mpq_dmx_src_data *dmx_data = dev_inst->dmx_src_data;
+ struct mpq_streambuffer *streambuff = dmx_data->stream_buffer;
+ struct mpq_streambuffer_packet_header pkt_hdr;
+ struct mpq_adapter_video_meta_data meta_data;
+ ssize_t indx = -1;
+ ssize_t bytes_read = 0;
+ size_t pktlen = 0;
+ int frame_found = true;
+ unsigned long kernel_vaddr, phy_addr, user_vaddr;
+ int pmem_fd;
+ struct file *file;
+ s32 buffer_index = -1;
+ size_t size = 0;
+
+ do {
+ wait_event_interruptible(streambuff->packet_data.queue,
+ (!dvb_ringbuffer_empty(&streambuff->packet_data) ||
+ streambuff->packet_data.error != 0) ||
+ kthread_should_stop());
+
+ if (kthread_should_stop()) {
+ DBG("STOP signal Received\n");
+ return;
+ }
+
+ DBG("Received Free Buffer : %d\n", free_buf);
+
+ indx = mpq_streambuffer_pkt_next(streambuff, -1, &pktlen);
+
+ if (-1 == indx) {
+ DBG("Invalid Index -1\n");
+ return;
+ }
+
+ bytes_read = mpq_streambuffer_pkt_read(streambuff, indx,
+ &pkt_hdr, (u8 *)&meta_data);
+
+ switch (meta_data.packet_type) {
+ case DMX_FRAMING_INFO_PACKET:
+ switch (meta_data.info.framing.pattern_type) {
+ case DMX_FRM_H264_SPS:
+ case DMX_FRM_MPEG2_SEQUENCE_HEADER:
+ case DMX_FRM_VC1_SEQUENCE_HEADER:
+ DBG("SPS FOUND\n");
+ frame_found = false;
+ break;
+ case DMX_FRM_H264_PPS:
+ case DMX_FRM_MPEG2_GOP_HEADER:
+ case DMX_FRM_VC1_ENTRY_POINT_HEADER:
+ DBG("PPS FOUND\n");
+ frame_found = false;
+ break;
+ case DMX_FRM_H264_IDR_PIC:
+ case DMX_FRM_H264_NON_IDR_PIC:
+ case DMX_FRM_MPEG2_I_PIC:
+ case DMX_FRM_MPEG2_P_PIC:
+ case DMX_FRM_MPEG2_B_PIC:
+ case DMX_FRM_VC1_FRAME_START_CODE:
+ DBG("FRAME FOUND\n");
+ frame_found = true;
+ break;
+ default:
+ break;
+ }
+ user_vaddr = (unsigned long)
+ dmx_data->in_buffer[free_buf].bufferaddr;
+ vidc_lookup_addr_table(dev_inst->client_ctx,
+ BUFFER_TYPE_INPUT, true, &user_vaddr,
+ &kernel_vaddr, &phy_addr, &pmem_fd, &file,
+ &buffer_index);
+ bytes_read = 0;
+ bytes_read = mpq_streambuffer_data_read(streambuff,
+ (u8 *)(kernel_vaddr + size),
+ pkt_hdr.raw_data_len);
+ DBG("Data Read : %d from Packet Size : %d\n",
+ bytes_read, pkt_hdr.raw_data_len);
+ mpq_streambuffer_pkt_dispose(streambuff, indx, 0);
+ size += pkt_hdr.raw_data_len;
+ dmx_data->in_buffer[free_buf].pts =
+ (meta_data.info.framing.pts_dts_info.pts_exist) ?
+ (meta_data.info.framing.pts_dts_info.pts) : 0;
+ if (frame_found) {
+ dmx_data->in_buffer[free_buf].buffer_len =
+ size;
+ dmx_data->in_buffer[free_buf].client_data =
+ (void *)free_buf;
+ DBG("Size of Data Submitted : %d\n", size);
+ mpq_int_vid_dec_decode_frame(
+ dev_inst->client_ctx,
+ &dmx_data->in_buffer[free_buf]);
+ }
+ break;
+ case DMX_EOS_PACKET:
+ break;
+ case DMX_PES_PACKET:
+ case DMX_PADDING_PACKET:
+ break;
+ }
+ } while (!frame_found);
+
+}
+
+static int mpq_bcast_data_handler(void *arg)
+{
+ struct mpq_dvb_video_inst *dev_inst = arg;
+ struct mpq_dmx_src_data *dmx_data = dev_inst->dmx_src_data;
+ struct mpq_bcast_msg *pMesg;
+ struct mpq_bcast_msg_info msg = {0};
+
+ do {
+ wait_event_interruptible(dmx_data->msg_wait,
+ ((dmx_data->stream_buffer != NULL) &&
+ mpq_int_check_bcast_mq(dmx_data)) ||
+ kthread_should_stop());
+
+ if (kthread_should_stop()) {
+ DBG("STOP signal Received\n");
+ break;
+ }
+
+ mutex_lock(&dmx_data->msg_queue_lock);
+ if (!list_empty(&dmx_data->msg_queue)) {
+ pMesg = list_first_entry(&dmx_data->msg_queue,
+ struct mpq_bcast_msg, list);
+ list_del(&pMesg->list);
+ memcpy(&msg, &pMesg->info,
+ sizeof(struct mpq_bcast_msg_info));
+ kfree(pMesg);
+ }
+ mutex_unlock(&dmx_data->msg_queue_lock);
+
+ switch (msg.code) {
+ case MPQ_BCAST_MSG_IBD:
+ DBG("Received IBD Mesg for :%d\n", msg.data);
+ mpq_get_frame_and_write(dev_inst, msg.data);
+ break;
+ default:
+ DBG("Received Mesg : %d\n", msg.code);
+ }
+ } while (1);
+
+ return 0;
+}
+
+static s32 mpq_int_vid_dec_get_empty_client_index(void)
+{
+ u32 i, found = false;
+
+ for (i = 0; i < VIDC_MAX_NUM_CLIENTS; i++) {
+ if (!mpq_dvb_video_device->vdec_clients[i].vcd_handle) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ ERR("%s():ERROR No space for new client\n", __func__);
+ return -ENOMEM;
+ } else {
+ DBG("%s(): available client index = %u\n", __func__, i);
+ return i;
+ }
+}
+
+static u32 mpq_int_vid_dec_get_status(u32 status)
+{
+ u32 vdec_status;
+
+ switch (status) {
+ case VCD_ERR_SEQHDR_PARSE_FAIL:
+ case VCD_ERR_BITSTREAM_ERR:
+ vdec_status = VIDEO_STATUS_BITSTREAM_ERROR;
+ break;
+ case VCD_S_SUCCESS:
+ vdec_status = VIDEO_STATUS_SUCESS;
+ break;
+ case VCD_ERR_FAIL:
+ vdec_status = VIDEO_STATUS_FAILED;
+ break;
+ case VCD_ERR_ALLOC_FAIL:
+ case VCD_ERR_MAX_CLIENT:
+ vdec_status = VIDEO_STATUS_NORESOURCE;
+ break;
+ case VCD_ERR_ILLEGAL_OP:
+ vdec_status = VIDEO_STATUS_INVALID_CMD;
+ break;
+ case VCD_ERR_ILLEGAL_PARM:
+ vdec_status = VIDEO_STATUS_INVALID_PARAM;
+ break;
+ case VCD_ERR_BAD_POINTER:
+ case VCD_ERR_BAD_HANDLE:
+ vdec_status = VIDEO_STATUS_INVALID_HANDLE;
+ break;
+ case VCD_ERR_NOT_SUPPORTED:
+ vdec_status = VIDEO_STATUS_NO_SUPPORT;
+ break;
+ case VCD_ERR_BAD_STATE:
+ vdec_status = VIDEO_STATUS_INVALID_STATE;
+ break;
+ case VCD_ERR_BUSY:
+ vdec_status = VIDEO_STATUS_BUSY;
+ break;
+ default:
+ vdec_status = VIDEO_STATUS_FAILED;
+ break;
+ }
+
+ return vdec_status;
+}
+
+static void mpq_int_vid_dec_notify_client(struct video_client_ctx *client_ctx)
+{
+ if (client_ctx)
+ complete(&client_ctx->event);
+}
+
+static void mpq_int_vid_dec_vcd_open_done(struct video_client_ctx *client_ctx,
+ struct vcd_handle_container *handle_container)
+{
+ if (client_ctx) {
+ if (handle_container)
+ client_ctx->vcd_handle = handle_container->handle;
+ else
+ DBG("%s(): ERROR. handle_container is NULL\n",
+ __func__);
+
+ mpq_int_vid_dec_notify_client(client_ctx);
+ } else
+ DBG("%s(): ERROR. client_ctx is NULL\n", __func__);
+}
+
+static void mpq_int_vid_dec_handle_field_drop(
+ struct video_client_ctx *client_ctx,
+ u32 event, u32 status, int64_t time_stamp)
+{
+ struct vid_dec_msg *vdec_msg;
+
+ if (!client_ctx) {
+ DBG("%s() NULL pointer\n", __func__);
+ return;
+ }
+
+ vdec_msg = kzalloc(sizeof(struct vid_dec_msg), GFP_KERNEL);
+ if (!vdec_msg) {
+ DBG("%s(): cannot allocate vid_dec_msg "\
+ " buffer\n", __func__);
+ return;
+ }
+ vdec_msg->vdec_msg_info.status_code =
+ mpq_int_vid_dec_get_status(status);
+ if (event == VCD_EVT_IND_INFO_FIELD_DROPPED) {
+ vdec_msg->vdec_msg_info.msgcode =
+ VDEC_MSG_EVT_INFO_FIELD_DROPPED;
+ vdec_msg->vdec_msg_info.msgdata.output_frame.time_stamp
+ = time_stamp;
+ DBG("Send FIELD_DROPPED message to client = %p\n",
+ client_ctx);
+ } else {
+ DBG("mpq_int_vid_dec_input_frame_done(): "\
+ "invalid event type: %d\n", event);
+ vdec_msg->vdec_msg_info.msgcode = VDEC_MSG_INVALID;
+ }
+ vdec_msg->vdec_msg_info.msgdatasize =
+ sizeof(struct vdec_output_frameinfo);
+ mutex_lock(&client_ctx->msg_queue_lock);
+ list_add_tail(&vdec_msg->list, &client_ctx->msg_queue);
+ mutex_unlock(&client_ctx->msg_queue_lock);
+ wake_up(&client_ctx->msg_wait);
+}
+
+static void mpq_int_vid_dec_input_frame_done(
+ struct video_client_ctx *client_ctx, u32 event,
+ u32 status, struct vcd_frame_data *vcd_frame_data)
+{
+ struct vid_dec_msg *vdec_msg;
+ struct mpq_bcast_msg *bcast_msg;
+ struct mpq_dvb_video_inst *dev_inst;
+ struct mpq_dmx_src_data *dmx_data;
+ int rc = 0;
+
+ if (!client_ctx || !vcd_frame_data) {
+ DBG("mpq_int_vid_dec_input_frame_done() NULL pointer\n");
+ return;
+ }
+
+ kfree(vcd_frame_data->desc_buf);
+ vcd_frame_data->desc_buf = NULL;
+ vcd_frame_data->desc_size = 0;
+
+ rc = mpq_get_dev_frm_client(client_ctx, &dev_inst);
+ if (rc) {
+ DBG("Failed to obtain device instance\n");
+ return;
+ }
+
+ if (dev_inst->source == VIDEO_SOURCE_MEMORY) {
+ vdec_msg = kzalloc(sizeof(struct vid_dec_msg), GFP_KERNEL);
+ if (!vdec_msg) {
+ DBG("mpq_int_vid_dec_input_frame_done(): "\
+ "cannot allocate vid_dec_msg buffer\n");
+ return;
+ }
+
+ vdec_msg->vdec_msg_info.status_code =
+ mpq_int_vid_dec_get_status(status);
+
+ if (event == VCD_EVT_RESP_INPUT_DONE) {
+ vdec_msg->vdec_msg_info.msgcode =
+ VDEC_MSG_RESP_INPUT_BUFFER_DONE;
+ DBG("Send INPUT_DON message to client = %p\n",
+ client_ctx);
+
+ } else if (event == VCD_EVT_RESP_INPUT_FLUSHED) {
+ vdec_msg->vdec_msg_info.msgcode =
+ VDEC_MSG_RESP_INPUT_FLUSHED;
+ DBG("Send INPUT_FLUSHED message to client = %p\n",
+ client_ctx);
+ } else {
+ DBG("mpq_int_vid_dec_input_frame_done(): "\
+ "invalid event type: %d\n", event);
+ vdec_msg->vdec_msg_info.msgcode = VDEC_MSG_INVALID;
+ }
+
+ vdec_msg->vdec_msg_info.msgdata.input_frame_clientdata =
+ (void *)vcd_frame_data->frm_clnt_data;
+ vdec_msg->vdec_msg_info.msgdatasize = sizeof(void *);
+
+ mutex_lock(&client_ctx->msg_queue_lock);
+ list_add_tail(&vdec_msg->list, &client_ctx->msg_queue);
+ mutex_unlock(&client_ctx->msg_queue_lock);
+ wake_up(&client_ctx->msg_wait);
+ } else {
+ bcast_msg = kzalloc(sizeof(struct mpq_bcast_msg),
+ GFP_KERNEL);
+ if (!bcast_msg) {
+ DBG("mpq_int_vid_dec_input_frame_done(): "\
+ "cannot allocate mpq_bcast_msg buffer\n");
+ return;
+ }
+
+ if (event == VCD_EVT_RESP_INPUT_DONE) {
+ bcast_msg->info.code = MPQ_BCAST_MSG_IBD;
+ bcast_msg->info.data =
+ (unsigned int)vcd_frame_data->frm_clnt_data;
+ }
+
+ dmx_data = dev_inst->dmx_src_data;
+
+ mutex_lock(&dmx_data->msg_queue_lock);
+ list_add_tail(&bcast_msg->list, &dmx_data->msg_queue);
+ mutex_unlock(&dmx_data->msg_queue_lock);
+ wake_up(&dmx_data->msg_wait);
+ }
+}
+
+static void mpq_int_vid_dec_output_frame_done(
+ struct video_client_ctx *client_ctx,
+ u32 event, u32 status,
+ struct vcd_frame_data *vcd_frame_data)
+{
+ struct vid_dec_msg *vdec_msg;
+
+ unsigned long kernel_vaddr = 0, phy_addr = 0, user_vaddr = 0;
+ int pmem_fd;
+ struct file *file;
+ s32 buffer_index = -1;
+ enum vdec_picture pic_type;
+ u32 ion_flag = 0;
+ struct ion_handle *buff_handle = NULL;
+ struct vdec_output_frameinfo *output_frame;
+
+ if (!client_ctx || !vcd_frame_data) {
+ DBG("mpq_int_vid_dec_input_frame_done() NULL pointer\n");
+ return;
+ }
+
+ vdec_msg = kzalloc(sizeof(struct vid_dec_msg), GFP_KERNEL);
+ if (!vdec_msg) {
+ DBG("mpq_int_vid_dec_input_frame_done(): "\
+ "cannot allocate vid_dec_msg buffer\n");
+ return;
+ }
+
+ vdec_msg->vdec_msg_info.status_code =
+ mpq_int_vid_dec_get_status(status);
+
+ if (event == VCD_EVT_RESP_OUTPUT_DONE)
+ vdec_msg->vdec_msg_info.msgcode =
+ VDEC_MSG_RESP_OUTPUT_BUFFER_DONE;
+ else if (event == VCD_EVT_RESP_OUTPUT_FLUSHED)
+ vdec_msg->vdec_msg_info.msgcode = VDEC_MSG_RESP_OUTPUT_FLUSHED;
+ else {
+ DBG("QVD: mpq_int_vid_dec_output_frame_done"\
+ "invalid cmd type : %d\n", event);
+ vdec_msg->vdec_msg_info.msgcode = VDEC_MSG_INVALID;
+ }
+
+ kernel_vaddr = (unsigned long)vcd_frame_data->virtual;
+
+ if (vidc_lookup_addr_table(client_ctx, BUFFER_TYPE_OUTPUT,
+ false, &user_vaddr, &kernel_vaddr,
+ &phy_addr, &pmem_fd, &file,
+ &buffer_index) ||
+ (vcd_frame_data->flags & VCD_FRAME_FLAG_EOS)) {
+ /* Buffer address in user space */
+ vdec_msg->vdec_msg_info.msgdata.output_frame.bufferaddr =
+ (u8 *) user_vaddr;
+ /* Data length */
+ vdec_msg->vdec_msg_info.msgdata.output_frame.len =
+ vcd_frame_data->data_len;
+ vdec_msg->vdec_msg_info.msgdata.output_frame.flags =
+ vcd_frame_data->flags;
+ /* Timestamp pass-through from input frame */
+ vdec_msg->vdec_msg_info.msgdata.output_frame.time_stamp =
+ vcd_frame_data->time_stamp;
+ /* Output frame client data */
+ vdec_msg->vdec_msg_info.msgdata.output_frame.client_data =
+ (void *)vcd_frame_data->frm_clnt_data;
+ /* Associated input frame client data */
+ vdec_msg->vdec_msg_info.msgdata.output_frame.
+ input_frame_clientdata =
+ (void *)vcd_frame_data->ip_frm_tag;
+ /* Decoded picture width and height */
+ vdec_msg->vdec_msg_info.msgdata.output_frame.framesize.
+ bottom =
+ vcd_frame_data->dec_op_prop.disp_frm.bottom;
+ vdec_msg->vdec_msg_info.msgdata.output_frame.framesize.left =
+ vcd_frame_data->dec_op_prop.disp_frm.left;
+ vdec_msg->vdec_msg_info.msgdata.output_frame.framesize.right =
+ vcd_frame_data->dec_op_prop.disp_frm.right;
+ vdec_msg->vdec_msg_info.msgdata.output_frame.framesize.top =
+ vcd_frame_data->dec_op_prop.disp_frm.top;
+ if (vcd_frame_data->interlaced) {
+ vdec_msg->vdec_msg_info.msgdata.
+ output_frame.interlaced_format =
+ VDEC_InterlaceInterleaveFrameTopFieldFirst;
+ } else {
+ vdec_msg->vdec_msg_info.msgdata.
+ output_frame.interlaced_format =
+ VDEC_InterlaceFrameProgressive;
+ }
+ /* Decoded picture type */
+ switch (vcd_frame_data->frame) {
+ case VCD_FRAME_I:
+ pic_type = PICTURE_TYPE_I;
+ break;
+ case VCD_FRAME_P:
+ pic_type = PICTURE_TYPE_P;
+ break;
+ case VCD_FRAME_B:
+ pic_type = PICTURE_TYPE_B;
+ break;
+ case VCD_FRAME_NOTCODED:
+ pic_type = PICTURE_TYPE_SKIP;
+ break;
+ case VCD_FRAME_IDR:
+ pic_type = PICTURE_TYPE_IDR;
+ break;
+ default:
+ pic_type = PICTURE_TYPE_UNKNOWN;
+ }
+ vdec_msg->vdec_msg_info.msgdata.output_frame.pic_type =
+ pic_type;
+ output_frame = &vdec_msg->vdec_msg_info.msgdata.output_frame;
+ 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.par_width;
+ output_frame->aspect_ratio_info.par_height =
+ vcd_frame_data->aspect_ratio_info.par_height;
+ vdec_msg->vdec_msg_info.msgdatasize =
+ sizeof(struct vdec_output_frameinfo);
+ } else {
+ DBG("mpq_int_vid_dec_output_frame_done UVA"\
+ "can not be found\n");
+ vdec_msg->vdec_msg_info.status_code = VDEC_S_EFATAL;
+ }
+ if (vcd_frame_data->data_len > 0) {
+ ion_flag = vidc_get_fd_info(client_ctx, BUFFER_TYPE_OUTPUT,
+ pmem_fd, kernel_vaddr, buffer_index,
+ &buff_handle);
+ if (ion_flag == CACHED && buff_handle) {
+ msm_ion_do_cache_op(
+ client_ctx->user_ion_client,
+ buff_handle,
+ (unsigned long *) kernel_vaddr,
+ (unsigned long)vcd_frame_data->data_len,
+ ION_IOC_INV_CACHES);
+ }
+ }
+ mutex_lock(&client_ctx->msg_queue_lock);
+ list_add_tail(&vdec_msg->list, &client_ctx->msg_queue);
+ mutex_unlock(&client_ctx->msg_queue_lock);
+ wake_up(&client_ctx->msg_wait);
+}
+
+static void mpq_int_vid_dec_lean_event(struct video_client_ctx *client_ctx,
+ u32 event, u32 status)
+{
+ struct vid_dec_msg *vdec_msg;
+
+ if (!client_ctx) {
+ DBG("%s(): !client_ctx pointer\n", __func__);
+ return;
+ }
+
+ vdec_msg = kzalloc(sizeof(struct vid_dec_msg), GFP_KERNEL);
+ if (!vdec_msg) {
+ DBG("%s(): cannot allocate vid_dec_msg buffer\n",
+ __func__);
+ return;
+ }
+
+ vdec_msg->vdec_msg_info.status_code =
+ mpq_int_vid_dec_get_status(status);
+
+ switch (event) {
+ case VCD_EVT_IND_OUTPUT_RECONFIG:
+ DBG("msm_vidc_dec: Sending VDEC_MSG_EVT_CONFIG_CHANGED"\
+ " to client");
+ vdec_msg->vdec_msg_info.msgcode = VDEC_MSG_EVT_CONFIG_CHANGED;
+ break;
+ case VCD_EVT_IND_RESOURCES_LOST:
+ DBG("msm_vidc_dec: Sending VDEC_EVT_RESOURCES_LOST"\
+ " to client");
+ vdec_msg->vdec_msg_info.msgcode = VDEC_EVT_RESOURCES_LOST;
+ break;
+ case VCD_EVT_RESP_FLUSH_INPUT_DONE:
+ DBG("msm_vidc_dec: Sending VDEC_MSG_RESP_FLUSH_INPUT_DONE"\
+ " to client");
+ vdec_msg->vdec_msg_info.msgcode =
+ VDEC_MSG_RESP_FLUSH_INPUT_DONE;
+ break;
+ case VCD_EVT_RESP_FLUSH_OUTPUT_DONE:
+ DBG("msm_vidc_dec: Sending VDEC_MSG_RESP_FLUSH_OUTPUT_DONE"\
+ " to client");
+ vdec_msg->vdec_msg_info.msgcode =
+ VDEC_MSG_RESP_FLUSH_OUTPUT_DONE;
+ break;
+ case VCD_EVT_IND_HWERRFATAL:
+ DBG("msm_vidc_dec: Sending VDEC_MSG_EVT_HW_ERROR"\
+ " to client");
+ vdec_msg->vdec_msg_info.msgcode = VDEC_MSG_EVT_HW_ERROR;
+ break;
+ case VCD_EVT_RESP_START:
+ DBG("msm_vidc_dec: Sending VDEC_MSG_RESP_START_DONE"\
+ " to client");
+ vdec_msg->vdec_msg_info.msgcode = VDEC_MSG_RESP_START_DONE;
+ break;
+ case VCD_EVT_RESP_STOP:
+ DBG("msm_vidc_dec: Sending VDEC_MSG_RESP_STOP_DONE"\
+ " to client");
+ vdec_msg->vdec_msg_info.msgcode = VDEC_MSG_RESP_STOP_DONE;
+ break;
+ case VCD_EVT_RESP_PAUSE:
+ DBG("msm_vidc_dec: Sending VDEC_MSG_RESP_PAUSE_DONE"\
+ " to client");
+ vdec_msg->vdec_msg_info.msgcode = VDEC_MSG_RESP_PAUSE_DONE;
+ break;
+ case VCD_EVT_IND_INFO_OUTPUT_RECONFIG:
+ DBG("msm_vidc_dec: Sending VDEC_MSG_EVT_INFO_CONFIG_CHANGED"\
+ " to client");
+ vdec_msg->vdec_msg_info.msgcode =
+ VDEC_MSG_EVT_INFO_CONFIG_CHANGED;
+ break;
+ default:
+ DBG("%s() : unknown event type\n", __func__);
+ break;
+ }
+
+ vdec_msg->vdec_msg_info.msgdatasize = 0;
+ if (client_ctx->stop_sync_cb &&
+ (event == VCD_EVT_RESP_STOP || event == VCD_EVT_IND_HWERRFATAL)) {
+ client_ctx->stop_sync_cb = false;
+ complete(&client_ctx->event);
+ kfree(vdec_msg);
+ return;
+ }
+ mutex_lock(&client_ctx->msg_queue_lock);
+ list_add_tail(&vdec_msg->list, &client_ctx->msg_queue);
+ mutex_unlock(&client_ctx->msg_queue_lock);
+ wake_up(&client_ctx->msg_wait);
+}
+
+static void mpq_int_state_play(struct video_client_ctx *client_ctx,
+ u32 event, u32 status)
+{
+ struct mpq_bcast_msg *bcast_msg;
+ struct mpq_dvb_video_inst *dev_inst;
+ int i;
+ int rc = 0;
+ struct mpq_dmx_src_data *dmx_data = NULL;
+
+ if (!client_ctx->seq_header_set) {
+ rc = mpq_get_dev_frm_client(client_ctx, &dev_inst);
+ if (rc) {
+ DBG("Failed to get dev_instance in %s\n", __func__);
+ return;
+ }
+
+ if (VIDEO_SOURCE_DEMUX == dev_inst->source) {
+ dmx_data = dev_inst->dmx_src_data;
+ for (i = 0; i < DVB_VID_NUM_IN_BUFFERS; i++) {
+ bcast_msg = kzalloc(
+ sizeof(struct mpq_bcast_msg),
+ GFP_KERNEL);
+ if (!bcast_msg) {
+ DBG("cannot allocate mpq_bcast_msg"\
+ "buffer\n");
+ return;
+ }
+
+ bcast_msg->info.code = MPQ_BCAST_MSG_IBD;
+ bcast_msg->info.data = (unsigned int)i;
+
+ mutex_lock(&dmx_data->msg_queue_lock);
+ list_add_tail(&bcast_msg->list,
+ &dmx_data->msg_queue);
+ mutex_unlock(&dmx_data->msg_queue_lock);
+ wake_up(&dmx_data->msg_wait);
+ }
+ }
+ mpq_int_vid_dec_lean_event(client_ctx, event, status);
+ } else
+ mpq_int_vid_dec_notify_client(client_ctx);
+
+}
+
+static void mpq_int_vid_dec_vcd_cb(u32 event, u32 status,
+ void *info, size_t sz, void *handle,
+ void *const client_data)
+{
+ struct video_client_ctx *client_ctx = client_data;
+
+ DBG("Entering %s()\n", __func__);
+
+ if (!client_ctx) {
+ DBG("%s(): client_ctx is NULL\n", __func__);
+ return;
+ }
+
+ client_ctx->event_status = status;
+
+ switch (event) {
+ case VCD_EVT_RESP_OPEN:
+ mpq_int_vid_dec_vcd_open_done(client_ctx,
+ (struct vcd_handle_container *)
+ info);
+ break;
+ case VCD_EVT_RESP_INPUT_DONE:
+ case VCD_EVT_RESP_INPUT_FLUSHED:
+ mpq_int_vid_dec_input_frame_done(client_ctx, event, status,
+ (struct vcd_frame_data *)info);
+ break;
+ case VCD_EVT_IND_INFO_FIELD_DROPPED:
+ if (info)
+ mpq_int_vid_dec_handle_field_drop(client_ctx, event,
+ status, *((int64_t *)info));
+ else
+ DBG("Wrong Payload for Field dropped\n");
+ break;
+ case VCD_EVT_RESP_OUTPUT_DONE:
+ case VCD_EVT_RESP_OUTPUT_FLUSHED:
+ mpq_int_vid_dec_output_frame_done(client_ctx, event, status,
+ (struct vcd_frame_data *)info);
+ break;
+ case VCD_EVT_RESP_PAUSE:
+ case VCD_EVT_RESP_STOP:
+ case VCD_EVT_RESP_FLUSH_INPUT_DONE:
+ case VCD_EVT_RESP_FLUSH_OUTPUT_DONE:
+ case VCD_EVT_IND_OUTPUT_RECONFIG:
+ case VCD_EVT_IND_HWERRFATAL:
+ case VCD_EVT_IND_RESOURCES_LOST:
+ case VCD_EVT_IND_INFO_OUTPUT_RECONFIG:
+ mpq_int_vid_dec_lean_event(client_ctx, event, status);
+ break;
+ case VCD_EVT_RESP_START:
+ mpq_int_state_play(client_ctx, event, status);
+ break;
+ default:
+ DBG("%s() : Error - Invalid event type =%u\n", __func__,
+ event);
+ break;
+ }
+}
+
+static int mpq_int_vid_dec_set_cont_on_reconfig(
+ struct video_client_ctx *client_ctx)
+{
+ struct vcd_property_hdr vcd_property_hdr;
+ u32 vcd_status = VCD_ERR_FAIL;
+ u32 enable = true;
+ if (!client_ctx)
+ return -EINVAL;
+ vcd_property_hdr.prop_id = VCD_I_CONT_ON_RECONFIG;
+ vcd_property_hdr.sz = sizeof(u32);
+ vcd_status = vcd_set_property(client_ctx->vcd_handle,
+ &vcd_property_hdr, &enable);
+ if (vcd_status)
+ return -EIO;
+ return 0;
+}
+
+static int mpq_int_vid_dec_set_frame_resolution(
+ struct video_client_ctx *client_ctx,
+ struct vdec_picsize *video_resoultion)
+{
+ struct vcd_property_hdr vcd_property_hdr;
+ struct vcd_property_frame_size frame_resolution;
+ u32 vcd_status = VCD_ERR_FAIL;
+
+ if (!client_ctx || !video_resoultion)
+ return -EINVAL;
+
+ vcd_property_hdr.prop_id = VCD_I_FRAME_SIZE;
+ vcd_property_hdr.sz = sizeof(struct vcd_property_frame_size);
+ frame_resolution.width = video_resoultion->frame_width;
+ frame_resolution.height = video_resoultion->frame_height;
+ frame_resolution.stride = video_resoultion->stride;
+ frame_resolution.scan_lines = video_resoultion->scan_lines;
+
+ vcd_status = vcd_set_property(client_ctx->vcd_handle,
+ &vcd_property_hdr, &frame_resolution);
+
+ if (vcd_status)
+ return -EIO;
+ else
+ return 0;
+}
+
+static int mpq_int_set_full_hd_frame_resolution(
+ struct video_client_ctx *client_ctx)
+{
+ struct vdec_picsize pic_res;
+ int rc;
+
+ pic_res.frame_height = 1080;
+ pic_res.frame_width = 1920;
+ pic_res.scan_lines = 1080;
+ pic_res.stride = 1920;
+
+ rc = mpq_int_vid_dec_set_frame_resolution(client_ctx,
+ &pic_res);
+ if (rc)
+ DBG("Failed in mpq_int_vid_dec_set_frame_resolution : %d\n",\
+ rc);
+
+ rc = mpq_int_vid_dec_set_cont_on_reconfig(client_ctx);
+ if (rc)
+ DBG("Failed in mpq_int_vid_dec_set_cont_on_reconfig : %d\n",\
+ rc);
+
+ return rc;
+
+}
+
+static int mpq_int_vid_dec_get_frame_resolution(
+ struct video_client_ctx *client_ctx,
+ struct video_pic_res *video_resoultion)
+{
+ struct vcd_property_hdr vcd_property_hdr;
+ struct vcd_property_frame_size frame_resolution;
+ u32 vcd_status = VCD_ERR_FAIL;
+
+ if (!client_ctx || !video_resoultion)
+ return -EINVAL;
+
+ vcd_property_hdr.prop_id = VCD_I_FRAME_SIZE;
+ vcd_property_hdr.sz = sizeof(struct vcd_property_frame_size);
+
+ vcd_status = vcd_get_property(client_ctx->vcd_handle,
+ &vcd_property_hdr, &frame_resolution);
+
+ video_resoultion->width = frame_resolution.width;
+ video_resoultion->height = frame_resolution.height;
+ video_resoultion->scan_lines = frame_resolution.scan_lines;
+ video_resoultion->stride = frame_resolution.stride;
+
+ if (vcd_status)
+ return -EINVAL;
+ else
+ return 0;
+}
+
+static int mpq_int_vid_dec_get_codec(struct video_client_ctx *client_ctx,
+ enum video_codec_t *video_codec)
+{
+ unsigned int result = 0;
+ struct vcd_property_hdr vcd_property_hdr;
+ struct vcd_property_codec codec;
+
+ if ((client_ctx == NULL) || (video_codec == NULL))
+ return -EINVAL;
+
+ vcd_property_hdr.prop_id = VCD_I_CODEC;
+ vcd_property_hdr.sz = sizeof(struct vcd_property_codec);
+
+ result = vcd_get_property(client_ctx->vcd_handle,
+ &vcd_property_hdr, &codec);
+ if (result)
+ return -EINVAL;
+
+ switch (codec.codec) {
+ case VCD_CODEC_MPEG4:
+ *video_codec = VIDEO_CODECTYPE_MPEG4;
+ break;
+ case VCD_CODEC_H264:
+ *video_codec = VIDEO_CODECTYPE_H264;
+ break;
+ case VCD_CODEC_MPEG2:
+ *video_codec = VIDEO_CODECTYPE_MPEG2;
+ break;
+ case VCD_CODEC_VC1:
+ *video_codec = VIDEO_CODECTYPE_VC1;
+ break;
+ default:
+ *video_codec = VIDEO_CODECTYPE_NONE;
+ break;
+ }
+
+ return result;
+}
+
+static int mpq_int_vid_dec_set_codec(struct video_client_ctx *client_ctx,
+ enum video_codec_t video_codec)
+{
+ unsigned int result = 0;
+ struct vcd_property_hdr vcd_property_hdr;
+ struct vcd_property_codec codec;
+ unsigned int vcd_status = VCD_ERR_FAIL;
+
+ if (client_ctx == NULL)
+ return -EINVAL;
+
+ vcd_property_hdr.prop_id = VCD_I_CODEC;
+ vcd_property_hdr.sz = sizeof(struct vcd_property_codec);
+
+ switch (video_codec) {
+ case VIDEO_CODECTYPE_MPEG4:
+ codec.codec = VCD_CODEC_MPEG4;
+ break;
+ case VIDEO_CODECTYPE_H264:
+ codec.codec = VCD_CODEC_H264;
+ break;
+ case VIDEO_CODECTYPE_MPEG2:
+ codec.codec = VCD_CODEC_MPEG2;
+ break;
+ case VIDEO_CODECTYPE_VC1:
+ codec.codec = VCD_CODEC_VC1;
+ break;
+ default:
+ result = -EINVAL;
+ break;
+ }
+
+ if (!result) {
+ vcd_status = vcd_set_property(client_ctx->vcd_handle,
+ &vcd_property_hdr, &codec);
+ if (vcd_status)
+ result = -EINVAL;
+ }
+
+ result = mpq_int_set_full_hd_frame_resolution(client_ctx);
+
+ return result;
+}
+
+static int mpq_int_vid_dec_set_output_format(
+ struct video_client_ctx *client_ctx,
+ enum video_out_format_t format)
+{
+ unsigned int result = 0;
+ struct vcd_property_hdr vcd_property_hdr;
+ struct vcd_property_buffer_format vcd_prop_buffer_format;
+ unsigned int vcd_status = VCD_ERR_FAIL;
+
+ if (client_ctx == NULL)
+ return -EINVAL;
+
+ vcd_property_hdr.prop_id = VCD_I_BUFFER_FORMAT;
+ vcd_property_hdr.sz = sizeof(struct vcd_property_buffer_format);
+
+ switch (format) {
+ case VIDEO_YUV_FORMAT_NV12:
+ vcd_prop_buffer_format.buffer_format = VCD_BUFFER_FORMAT_NV12;
+ break;
+ case VIDEO_YUV_FORMAT_TILE_4x2:
+ vcd_prop_buffer_format.buffer_format =
+ VCD_BUFFER_FORMAT_TILE_4x2;
+ break;
+ default:
+ result = -EINVAL;
+ break;
+ }
+
+ if (!result)
+ vcd_status = vcd_set_property(client_ctx->vcd_handle,
+ &vcd_property_hdr,
+ &vcd_prop_buffer_format);
+
+ if (vcd_status)
+ return -EINVAL;
+
+ return 0;
+
+}
+
+static int mpq_int_vid_dec_get_output_format(
+ struct video_client_ctx *client_ctx,
+ enum video_out_format_t *format)
+{
+ unsigned int result = 0;
+ struct vcd_property_hdr vcd_property_hdr;
+ struct vcd_property_buffer_format vcd_prop_buffer_format;
+
+ if ((client_ctx == NULL) || (format == NULL))
+ return -EINVAL;
+
+ vcd_property_hdr.prop_id = VCD_I_BUFFER_FORMAT;
+ vcd_property_hdr.sz = sizeof(struct vcd_property_buffer_format);
+
+ result = vcd_get_property(client_ctx->vcd_handle, &vcd_property_hdr,
+ &vcd_prop_buffer_format);
+
+ if (result)
+ return -EINVAL;
+
+ switch (vcd_prop_buffer_format.buffer_format) {
+ case VCD_BUFFER_FORMAT_NV12:
+ *format = VIDEO_YUV_FORMAT_NV12;
+ break;
+ case VCD_BUFFER_FORMAT_TILE_4x2:
+ *format = VIDEO_YUV_FORMAT_TILE_4x2;
+ break;
+ default:
+ result = -EINVAL;
+ break;
+ }
+
+ return result;
+}
+
+static int mpq_int_vid_dec_set_h264_mv_buffers(
+ struct video_client_ctx *client_ctx,
+ struct video_h264_mv *mv_data)
+{
+ struct vcd_property_hdr vcd_property_hdr;
+ struct vcd_property_h264_mv_buffer *vcd_h264_mv_buffer = NULL;
+ struct msm_mapped_buffer *mapped_buffer = NULL;
+ u32 vcd_status = VCD_ERR_FAIL;
+ u32 len = 0, flags = 0;
+ struct file *file;
+ int rc = 0;
+ unsigned long ionflag = 0;
+ unsigned long buffer_size = 0;
+ unsigned long iova = 0;
+
+ if (!client_ctx || !mv_data)
+ return -EINVAL;
+
+ vcd_property_hdr.prop_id = VCD_I_H264_MV_BUFFER;
+ vcd_property_hdr.sz = sizeof(struct vcd_property_h264_mv_buffer);
+ vcd_h264_mv_buffer = &client_ctx->vcd_h264_mv_buffer;
+
+ memset(&client_ctx->vcd_h264_mv_buffer, 0,
+ sizeof(struct vcd_property_h264_mv_buffer));
+ vcd_h264_mv_buffer->size = mv_data->size;
+ vcd_h264_mv_buffer->count = mv_data->count;
+ vcd_h264_mv_buffer->pmem_fd = mv_data->ion_fd;
+ vcd_h264_mv_buffer->offset = mv_data->offset;
+
+ if (!vcd_get_ion_status()) {
+ if (get_pmem_file(vcd_h264_mv_buffer->pmem_fd,
+ (unsigned long *) (&(vcd_h264_mv_buffer->
+ physical_addr)),
+ (unsigned long *) (&vcd_h264_mv_buffer->
+ kernel_virtual_addr),
+ (unsigned long *) (&len), &file)) {
+ ERR("%s(): get_pmem_file failed\n", __func__);
+ return -EIO;
+ }
+ put_pmem_file(file);
+ flags = MSM_SUBSYSTEM_MAP_IOVA;
+ mapped_buffer = msm_subsystem_map_buffer(
+ (unsigned long)vcd_h264_mv_buffer->physical_addr, len,
+ flags, vidc_mmu_subsystem,
+ sizeof(vidc_mmu_subsystem)/
+ sizeof(unsigned int));
+ if (IS_ERR(mapped_buffer)) {
+ ERR("buffer map failed");
+ return PTR_ERR(mapped_buffer);
+ }
+ vcd_h264_mv_buffer->client_data = (void *) mapped_buffer;
+ vcd_h264_mv_buffer->dev_addr = (u8 *)mapped_buffer->iova[0];
+ } else {
+ client_ctx->h264_mv_ion_handle = ion_import_dma_buf(
+ client_ctx->user_ion_client,
+ vcd_h264_mv_buffer->pmem_fd);
+ if (IS_ERR_OR_NULL(client_ctx->h264_mv_ion_handle)) {
+ DBG("%s(): get_ION_handle failed\n", __func__);
+ goto import_ion_error;
+ }
+ rc = ion_handle_get_flags(client_ctx->user_ion_client,
+ client_ctx->h264_mv_ion_handle,
+ &ionflag);
+ if (rc) {
+ DBG("%s():get_ION_flags fail\n",
+ __func__);
+ goto import_ion_error;
+ }
+ vcd_h264_mv_buffer->kernel_virtual_addr =
+ (u8 *) ion_map_kernel(client_ctx->user_ion_client,
+ client_ctx->h264_mv_ion_handle,
+ ionflag);
+ if (!vcd_h264_mv_buffer->kernel_virtual_addr) {
+ DBG("%s(): get_ION_kernel virtual addr failed\n",
+ __func__);
+ goto import_ion_error;
+ }
+
+ rc = ion_map_iommu(client_ctx->user_ion_client,
+ client_ctx->h264_mv_ion_handle,
+ VIDEO_DOMAIN, VIDEO_MAIN_POOL,
+ SZ_4K, 0, (unsigned long *)&iova,
+ (unsigned long *)&buffer_size,
+ UNCACHED, 0);
+ if (rc) {
+ DBG("%s():get_ION_kernel physical addr fail\n",
+ __func__);
+ goto ion_map_error;
+ }
+ vcd_h264_mv_buffer->physical_addr = (u8 *) iova;
+ vcd_h264_mv_buffer->client_data = NULL;
+ vcd_h264_mv_buffer->dev_addr = (u8 *) iova;
+
+ }
+ DBG("Virt: %p, Phys %p, fd: %d", vcd_h264_mv_buffer->
+ kernel_virtual_addr, vcd_h264_mv_buffer->physical_addr,
+ vcd_h264_mv_buffer->pmem_fd);
+ DBG("Dev addr %p", vcd_h264_mv_buffer->dev_addr);
+ vcd_status = vcd_set_property(client_ctx->vcd_handle,
+ &vcd_property_hdr, vcd_h264_mv_buffer);
+
+ if (vcd_status)
+ return -EIO;
+ else
+ return 0;
+ion_map_error:
+ if (vcd_h264_mv_buffer->kernel_virtual_addr) {
+ ion_unmap_kernel(client_ctx->user_ion_client,
+ client_ctx->h264_mv_ion_handle);
+ vcd_h264_mv_buffer->kernel_virtual_addr = NULL;
+ }
+ if (!IS_ERR_OR_NULL(client_ctx->h264_mv_ion_handle)) {
+ ion_free(client_ctx->user_ion_client,
+ client_ctx->h264_mv_ion_handle);
+ client_ctx->h264_mv_ion_handle = NULL;
+ }
+import_ion_error:
+ return -EIO;
+}
+
+static int mpq_int_vid_dec_get_h264_mv_buffer_size(
+ struct video_client_ctx *client_ctx,
+ struct video_mv_buff_size *mv_buff)
+{
+ struct vcd_property_hdr vcd_property_hdr;
+ struct vcd_property_buffer_size h264_mv_buffer_size;
+ u32 vcd_status = VCD_ERR_FAIL;
+
+ if (!client_ctx || !mv_buff)
+ return -EINVAL;
+
+ vcd_property_hdr.prop_id = VCD_I_GET_H264_MV_SIZE;
+ vcd_property_hdr.sz = sizeof(struct vcd_property_buffer_size);
+
+ h264_mv_buffer_size.width = mv_buff->width;
+ h264_mv_buffer_size.height = mv_buff->height;
+
+ vcd_status = vcd_get_property(client_ctx->vcd_handle,
+ &vcd_property_hdr, &h264_mv_buffer_size);
+
+ mv_buff->width = h264_mv_buffer_size.width;
+ mv_buff->height = h264_mv_buffer_size.height;
+ mv_buff->size = h264_mv_buffer_size.size;
+ mv_buff->alignment = h264_mv_buffer_size.alignment;
+
+ if (vcd_status)
+ return -EIO;
+ else
+ return 0;
+}
+
+static int mpq_int_vid_dec_free_h264_mv_buffers(
+ struct video_client_ctx *client_ctx)
+{
+ struct vcd_property_hdr vcd_property_hdr;
+ struct vcd_property_buffer_size h264_mv_buffer_size;
+ u32 vcd_status = VCD_ERR_FAIL;
+
+ if (!client_ctx)
+ return -EINVAL;
+ if (client_ctx->vcd_h264_mv_buffer.client_data)
+ msm_subsystem_unmap_buffer((struct msm_mapped_buffer *)
+ client_ctx->vcd_h264_mv_buffer.client_data);
+
+ vcd_property_hdr.prop_id = VCD_I_FREE_H264_MV_BUFFER;
+ vcd_property_hdr.sz = sizeof(struct vcd_property_buffer_size);
+
+ vcd_status = vcd_set_property(client_ctx->vcd_handle,
+ &vcd_property_hdr, &h264_mv_buffer_size);
+
+ if (!IS_ERR_OR_NULL(client_ctx->h264_mv_ion_handle)) {
+ ion_unmap_kernel(client_ctx->user_ion_client,
+ client_ctx->h264_mv_ion_handle);
+ ion_unmap_iommu(client_ctx->user_ion_client,
+ client_ctx->h264_mv_ion_handle,
+ VIDEO_DOMAIN,
+ VIDEO_MAIN_POOL);
+ ion_free(client_ctx->user_ion_client,
+ client_ctx->h264_mv_ion_handle);
+ client_ctx->h264_mv_ion_handle = NULL;
+ }
+
+ if (vcd_status)
+ return -EIO;
+ else
+ return 0;
+}
+
+
+static int mpq_int_vid_dec_get_buffer_req(struct video_client_ctx *client_ctx,
+ struct video_buffer_req *vdec_buf_req)
+{
+ u32 vcd_status = VCD_ERR_FAIL;
+ struct vcd_buffer_requirement vcd_buf_req;
+
+ if (!client_ctx || !vdec_buf_req)
+ return -EINVAL;
+
+ vcd_status = vcd_get_buffer_requirements(client_ctx->vcd_handle,
+ VCD_BUFFER_INPUT, &vcd_buf_req);
+
+ if (vcd_status)
+ return -EINVAL;
+
+ vdec_buf_req->input_buf_prop.alignment = vcd_buf_req.align;
+ vdec_buf_req->input_buf_prop.buf_poolid = vcd_buf_req.buf_pool_id;
+ vdec_buf_req->input_buf_prop.buf_size = vcd_buf_req.sz;
+ vdec_buf_req->num_input_buffers = vcd_buf_req.actual_count;
+
+ vcd_status = vcd_get_buffer_requirements(client_ctx->vcd_handle,
+ VCD_BUFFER_OUTPUT, &vcd_buf_req);
+
+ if (vcd_status)
+ return -EINVAL;
+
+ vdec_buf_req->output_buf_prop.alignment = vcd_buf_req.align;
+ vdec_buf_req->output_buf_prop.buf_poolid = vcd_buf_req.buf_pool_id;
+ vdec_buf_req->output_buf_prop.buf_size = vcd_buf_req.sz;
+ vdec_buf_req->num_output_buffers = vcd_buf_req.actual_count;
+
+ return 0;
+}
+
+static int mpq_int_vid_dec_set_buffer(struct mpq_dvb_video_inst *dev_inst,
+ struct video_data_buffer *data_buffer,
+ enum buffer_dir dir_buffer)
+{
+ struct video_client_ctx *client_ctx =
+ (struct video_client_ctx *)dev_inst->client_ctx;
+ enum vcd_buffer_type buffer = VCD_BUFFER_INPUT;
+ u32 vcd_status = VCD_ERR_FAIL;
+ unsigned long kernel_vaddr, buf_adr_offset = 0, length;
+ int buffer_num = 0;
+
+ if (!client_ctx || !data_buffer)
+ return -EINVAL;
+
+ if (dir_buffer == BUFFER_TYPE_OUTPUT) {
+ buffer = VCD_BUFFER_OUTPUT;
+ buf_adr_offset = (unsigned long)data_buffer->offset;
+ }
+ length = data_buffer->buffer_len;
+ /*If buffer cannot be set, ignore */
+ if (!vidc_insert_addr_table(client_ctx, dir_buffer,
+ (unsigned long)data_buffer->bufferaddr,
+ &kernel_vaddr, data_buffer->ion_fd,
+ buf_adr_offset, MAX_VIDEO_NUM_OF_BUFF, length)) {
+ ERR("%s() : user_virt_addr = %p cannot be set.",
+ __func__, data_buffer->bufferaddr);
+ return -EINVAL;
+ }
+
+ vcd_status = vcd_set_buffer(client_ctx->vcd_handle,
+ buffer, (u8 *) kernel_vaddr, data_buffer->buffer_len);
+
+ if (!vcd_status) {
+ mutex_lock(&client_ctx->enrty_queue_lock);
+ if ((VIDEO_SOURCE_DEMUX == dev_inst->source) &&
+ (BUFFER_TYPE_INPUT == dir_buffer)) {
+ buffer_num = client_ctx->num_of_input_buffers - 1;
+ memcpy(&dev_inst->dmx_src_data->in_buffer[buffer_num],
+ data_buffer,
+ sizeof(struct video_data_buffer));
+ }
+ mutex_unlock(&client_ctx->enrty_queue_lock);
+ return 0;
+ } else
+ return -EINVAL;
+}
+
+static int mpq_int_vid_dec_free_buffer(struct video_client_ctx *client_ctx,
+ struct video_data_buffer *data_buffer,
+ enum buffer_dir dir_buffer)
+
+{
+ enum vcd_buffer_type buffer = VCD_BUFFER_INPUT;
+ u32 vcd_status = VCD_ERR_FAIL;
+ unsigned long kernel_vaddr;
+
+ if (!client_ctx || !data_buffer)
+ return -EINVAL;
+
+ if (dir_buffer == BUFFER_TYPE_OUTPUT)
+ buffer = VCD_BUFFER_OUTPUT;
+
+ /*If buffer NOT set, ignore */
+ if (!vidc_delete_addr_table(client_ctx, dir_buffer,
+ (unsigned long)data_buffer->bufferaddr,
+ &kernel_vaddr)) {
+ DBG("%s() : user_virt_addr = %p has not been set.",
+ __func__, data_buffer->bufferaddr);
+ return 0;
+ }
+ vcd_status = vcd_free_buffer(client_ctx->vcd_handle, buffer,
+ (u8 *)kernel_vaddr);
+
+ if (vcd_status)
+ return -EIO;
+ else
+ return 0;
+}
+
+static int mpq_int_vid_dec_pause_resume(struct video_client_ctx *client_ctx,
+ u32 pause)
+{
+ u32 vcd_status;
+
+ if (!client_ctx) {
+ DBG("%s(): Invalid client_ctx\n", __func__);
+ return -EINVAL;
+ }
+
+ if (pause) {
+ DBG("msm_vidc_dec: PAUSE command from client = %p\n",
+ client_ctx);
+ vcd_status = vcd_pause(client_ctx->vcd_handle);
+ } else {
+ DBG("msm_vidc_dec: RESUME command from client = %p\n",
+ client_ctx);
+ vcd_status = vcd_resume(client_ctx->vcd_handle);
+ }
+
+ if (vcd_status)
+ return -EIO;
+ else
+ return 0;
+}
+
+static int mpq_int_vid_dec_start_stop(struct video_client_ctx *client_ctx,
+ u32 start)
+{
+ struct vid_dec_msg *vdec_msg = NULL;
+ u32 vcd_status;
+
+ DBG("Inside %s()", __func__);
+ if (!client_ctx) {
+ DBG("Invalid client_ctx\n");
+ return -EINVAL;
+ }
+
+ if (start) {
+ if (client_ctx->seq_header_set) {
+ DBG("%s(): Seq Hdr set: Send START_DONE to client",
+ __func__);
+ vdec_msg = kzalloc(sizeof(*vdec_msg), GFP_KERNEL);
+ if (!vdec_msg) {
+ DBG("mpq_int_vid_dec_start_stop:"\
+ " cannot allocate buffer\n");
+ return -ENOMEM;
+ }
+ vdec_msg->vdec_msg_info.msgcode =
+ VDEC_MSG_RESP_START_DONE;
+ vdec_msg->vdec_msg_info.status_code = VDEC_S_SUCCESS;
+ vdec_msg->vdec_msg_info.msgdatasize = 0;
+ mutex_lock(&client_ctx->msg_queue_lock);
+ list_add_tail(&vdec_msg->list, &client_ctx->msg_queue);
+ mutex_unlock(&client_ctx->msg_queue_lock);
+
+ wake_up(&client_ctx->msg_wait);
+
+ DBG("Send START_DONE message to client = %p\n",
+ client_ctx);
+
+ } else {
+ DBG("%s(): Calling decode_start()", __func__);
+ vcd_status =
+ vcd_decode_start(client_ctx->vcd_handle, NULL);
+
+ if (vcd_status) {
+ DBG("%s(): vcd_decode_start failed."\
+ " vcd_status = %u\n", __func__,
+ vcd_status);
+ return -EIO;
+ }
+ }
+ } else {
+ DBG("%s(): Calling vcd_stop()", __func__);
+ mutex_lock(&mpq_dvb_video_device->lock);
+ vcd_status = VCD_ERR_FAIL;
+ if (!client_ctx->stop_called) {
+ client_ctx->stop_called = true;
+ vcd_status = vcd_stop(client_ctx->vcd_handle);
+ }
+ if (vcd_status) {
+ DBG("%s(): vcd_stop failed. vcd_status = %u\n",
+ __func__, vcd_status);
+ mutex_unlock(&mpq_dvb_video_device->lock);
+ return -EIO;
+ }
+ DBG("Send STOP_DONE message to client = %p\n", client_ctx);
+ mutex_unlock(&mpq_dvb_video_device->lock);
+ }
+ return 0;
+}
+
+static int mpq_int_vid_dec_decode_frame(struct video_client_ctx *client_ctx,
+ struct video_data_buffer *input_frame)
+{
+ struct vcd_frame_data vcd_input_buffer;
+ unsigned long kernel_vaddr, phy_addr, user_vaddr;
+ int pmem_fd;
+ struct file *file;
+ s32 buffer_index = -1;
+ u32 vcd_status = VCD_ERR_FAIL;
+ u32 ion_flag = 0;
+ struct ion_handle *buff_handle = NULL;
+
+ if (!client_ctx || !input_frame)
+ return -EINVAL;
+
+ user_vaddr = (unsigned long)input_frame->bufferaddr;
+
+ if (vidc_lookup_addr_table(client_ctx, BUFFER_TYPE_INPUT,
+ true, &user_vaddr, &kernel_vaddr,
+ &phy_addr, &pmem_fd, &file,
+ &buffer_index)) {
+
+ /* kernel_vaddr is found. send the frame to VCD */
+ memset((void *)&vcd_input_buffer, 0,
+ sizeof(struct vcd_frame_data));
+ vcd_input_buffer.virtual =
+ (u8 *) (kernel_vaddr + input_frame->offset);
+ vcd_input_buffer.offset = 0;
+ vcd_input_buffer.frm_clnt_data =
+ (u32) input_frame->client_data;
+ vcd_input_buffer.ip_frm_tag =
+ (u32) input_frame->client_data;
+ vcd_input_buffer.data_len = input_frame->buffer_len;
+ vcd_input_buffer.time_stamp = input_frame->pts;
+ /* Rely on VCD using the same flags as OMX */
+ vcd_input_buffer.flags = 0;
+ vcd_input_buffer.desc_buf = NULL;
+ vcd_input_buffer.desc_size = 0;
+ if (vcd_input_buffer.data_len > 0) {
+ ion_flag = vidc_get_fd_info(client_ctx,
+ BUFFER_TYPE_INPUT,
+ pmem_fd,
+ kernel_vaddr,
+ buffer_index,
+ &buff_handle);
+ if (ion_flag == CACHED && buff_handle) {
+ msm_ion_do_cache_op(
+ client_ctx->user_ion_client,
+ buff_handle,
+ (unsigned long *)kernel_vaddr,
+ (unsigned long) vcd_input_buffer.data_len,
+ ION_IOC_CLEAN_CACHES);
+ }
+ }
+ vcd_status = vcd_decode_frame(client_ctx->vcd_handle,
+ &vcd_input_buffer);
+ if (!vcd_status)
+ return 0;
+ else {
+ DBG("%s(): vcd_decode_frame failed = %u\n", __func__,
+ vcd_status);
+ return -EIO;
+ }
+
+ } else {
+ DBG("%s(): kernel_vaddr not found\n", __func__);
+ return -EIO;
+ }
+}
+
+static int mpq_int_vid_dec_fill_output_buffer(
+ struct video_client_ctx *client_ctx,
+ struct video_data_buffer *fill_buffer)
+{
+ unsigned long kernel_vaddr, phy_addr, user_vaddr;
+ int pmem_fd;
+ struct file *file;
+ s32 buffer_index = -1;
+ u32 vcd_status = VCD_ERR_FAIL;
+ struct ion_handle *buff_handle = NULL;
+
+ struct vcd_frame_data vcd_frame;
+
+ if (!client_ctx || !fill_buffer)
+ return -EINVAL;
+
+ user_vaddr = (unsigned long)fill_buffer->bufferaddr;
+
+ if (vidc_lookup_addr_table(client_ctx, BUFFER_TYPE_OUTPUT,
+ true, &user_vaddr, &kernel_vaddr,
+ &phy_addr, &pmem_fd, &file,
+ &buffer_index)) {
+
+ memset((void *)&vcd_frame, 0,
+ sizeof(struct vcd_frame_data));
+ vcd_frame.virtual = (u8 *) kernel_vaddr;
+ vcd_frame.frm_clnt_data = (u32) fill_buffer->client_data;
+ vcd_frame.alloc_len = fill_buffer->buffer_len;
+ vcd_frame.ion_flag = vidc_get_fd_info(client_ctx,
+ BUFFER_TYPE_OUTPUT,
+ pmem_fd, kernel_vaddr,
+ buffer_index,
+ &buff_handle);
+ vcd_frame.buff_ion_handle = buff_handle;
+ vcd_status = vcd_fill_output_buffer(client_ctx->vcd_handle,
+ &vcd_frame);
+ if (!vcd_status)
+ return 0;
+ else {
+ DBG("%s(): vcd_fill_output_buffer failed = %u\n",
+ __func__, vcd_status);
+ return -EINVAL;
+ }
+ } else {
+ DBG("%s(): kernel_vaddr not found\n", __func__);
+ return -EIO;
+ }
+}
+
+
+static int mpq_int_vid_dec_flush(struct video_client_ctx *client_ctx,
+ enum vdec_bufferflush flush_dir)
+{
+ u32 vcd_status = VCD_ERR_FAIL;
+
+ DBG("msm_vidc_dec: %s() called with dir = %u", __func__,
+ flush_dir);
+ if (!client_ctx) {
+ DBG("Invalid client_ctx\n");
+ return -EINVAL;
+ }
+
+ switch (flush_dir) {
+ case VDEC_FLUSH_TYPE_INPUT:
+ vcd_status = vcd_flush(client_ctx->vcd_handle,
+ VCD_FLUSH_INPUT);
+ break;
+ case VDEC_FLUSH_TYPE_OUTPUT:
+ vcd_status = vcd_flush(client_ctx->vcd_handle,
+ VCD_FLUSH_OUTPUT);
+ break;
+ case VDEC_FLUSH_TYPE_ALL:
+ vcd_status = vcd_flush(client_ctx->vcd_handle, VCD_FLUSH_ALL);
+ break;
+ default:
+ ERR("%s(): Inavlid flush cmd. flush_dir = %u\n", __func__,
+ flush_dir);
+ return -EINVAL;
+ break;
+ }
+
+ if (!vcd_status)
+ return 0;
+ else {
+ DBG("%s(): vcd_flush failed. vcd_status = %u "\
+ " flush_dir = %u\n", __func__, vcd_status, flush_dir);
+ return -EIO;
+ }
+}
+
+static u32 mpq_int_vid_dec_msg_pending(struct video_client_ctx *client_ctx)
+{
+ u32 islist_empty = 0;
+ mutex_lock(&client_ctx->msg_queue_lock);
+ islist_empty = list_empty(&client_ctx->msg_queue);
+ mutex_unlock(&client_ctx->msg_queue_lock);
+
+ if (islist_empty) {
+ DBG("%s(): vid_dec msg queue empty\n", __func__);
+ if (client_ctx->stop_msg) {
+ DBG("%s(): List empty and Stop Msg set\n",
+ __func__);
+ return client_ctx->stop_msg;
+ }
+ } else {
+ DBG("%s(): vid_dec msg queue Not empty\n", __func__);
+ }
+
+ return !islist_empty;
+}
+
+static int mpq_int_vid_dec_get_next_msg(struct video_client_ctx *client_ctx,
+ struct vdec_msginfo *vdec_msg_info)
+{
+ struct vid_dec_msg *vid_dec_msg = NULL;
+
+ if (!client_ctx)
+ return -EINVAL;
+
+ mutex_lock(&client_ctx->msg_queue_lock);
+ if (!list_empty(&client_ctx->msg_queue)) {
+ DBG("%s(): After Wait\n", __func__);
+ vid_dec_msg = list_first_entry(&client_ctx->msg_queue,
+ struct vid_dec_msg, list);
+ list_del(&vid_dec_msg->list);
+ memcpy(vdec_msg_info, &vid_dec_msg->vdec_msg_info,
+ sizeof(struct vdec_msginfo));
+ kfree(vid_dec_msg);
+ }
+ mutex_unlock(&client_ctx->msg_queue_lock);
+ return 0;
+}
+
+static u32 mpq_int_vid_dec_close_client(struct video_client_ctx *client_ctx)
+{
+ struct vid_dec_msg *vdec_msg;
+ u32 vcd_status;
+
+ DBG("msm_vidc_dec: Inside %s()", __func__);
+ if (!client_ctx || (!client_ctx->vcd_handle)) {
+ DBG("Invalid client_ctx\n");
+ return false;
+ }
+
+ mutex_lock(&mpq_dvb_video_device->lock);
+ if (!client_ctx->stop_called) {
+ client_ctx->stop_called = true;
+ client_ctx->stop_sync_cb = true;
+ vcd_status = vcd_stop(client_ctx->vcd_handle);
+ DBG("Stuck at the stop call\n");
+ if (!vcd_status)
+ wait_for_completion(&client_ctx->event);
+ DBG("Came out of wait event\n");
+ }
+ mutex_lock(&client_ctx->msg_queue_lock);
+ while (!list_empty(&client_ctx->msg_queue)) {
+ DBG("%s(): Delete remaining entries\n", __func__);
+ vdec_msg = list_first_entry(&client_ctx->msg_queue,
+ struct vid_dec_msg, list);
+ if (vdec_msg) {
+ list_del(&vdec_msg->list);
+ kfree(vdec_msg);
+ }
+ }
+ mutex_unlock(&client_ctx->msg_queue_lock);
+ vcd_status = vcd_close(client_ctx->vcd_handle);
+
+ if (vcd_status) {
+ mutex_unlock(&mpq_dvb_video_device->lock);
+ return false;
+ }
+ client_ctx->user_ion_client = NULL;
+ mutex_destroy(&client_ctx->msg_queue_lock);
+ mutex_destroy(&client_ctx->enrty_queue_lock);
+ memset((void *)client_ctx, 0, sizeof(struct video_client_ctx));
+ mpq_dvb_video_device->num_clients--;
+ mutex_unlock(&mpq_dvb_video_device->lock);
+ return true;
+}
+
+static int mpq_int_vid_dec_open_client(struct video_client_ctx **vid_clnt_ctx,
+ int flags)
+{
+ int rc = 0;
+ s32 client_index;
+ struct video_client_ctx *client_ctx = NULL;
+ u8 client_count;
+
+ if (!vid_clnt_ctx) {
+ DBG("Invalid input\n");
+ return -EINVAL;
+ }
+ *vid_clnt_ctx = NULL;
+ client_count = vcd_get_num_of_clients();
+ if (client_count == VIDC_MAX_NUM_CLIENTS) {
+ ERR("ERROR : vid_dec_open() max number of clients"\
+ "limit reached\n");
+ return -ENOMEM;
+ }
+
+ DBG(" Virtual Address of ioremap is %p\n",
+ mpq_dvb_video_device->virt_base);
+ if (!mpq_dvb_video_device->num_clients)
+ if (!vidc_load_firmware())
+ return -ENOMEM;
+
+ client_index = mpq_int_vid_dec_get_empty_client_index();
+ if (client_index == -1) {
+ DBG("%s() : No free clients client_index == -1\n", __func__);
+ vidc_release_firmware();
+ return -ENOMEM;
+ }
+ client_ctx = &mpq_dvb_video_device->vdec_clients[client_index];
+ mpq_dvb_video_device->num_clients++;
+ init_completion(&client_ctx->event);
+ mutex_init(&client_ctx->msg_queue_lock);
+ mutex_init(&client_ctx->enrty_queue_lock);
+ INIT_LIST_HEAD(&client_ctx->msg_queue);
+ init_waitqueue_head(&client_ctx->msg_wait);
+ client_ctx->stop_msg = 0;
+ client_ctx->stop_called = false;
+ client_ctx->stop_sync_cb = false;
+ client_ctx->dmx_disable = 0;
+ if (vcd_get_ion_status()) {
+ client_ctx->user_ion_client = vcd_get_ion_client();
+ if (!client_ctx->user_ion_client) {
+ ERR("vcd_open ion client get failed");
+ rc = -ENOMEM;
+ goto client_failure;
+ }
+ }
+ rc = vcd_open(mpq_dvb_video_device->device_handle, true,
+ mpq_int_vid_dec_vcd_cb, client_ctx, flags);
+ if (!rc) {
+ wait_for_completion(&client_ctx->event);
+ if (client_ctx->event_status) {
+ DBG("callback for vcd_open returned error: %u",
+ client_ctx->event_status);
+ rc = -ENODEV;
+ goto client_failure;
+ }
+ } else {
+ DBG("vcd_open returned error: %u", rc);
+ goto client_failure;
+ }
+ client_ctx->seq_header_set = false;
+ *vid_clnt_ctx = client_ctx;
+
+ return 0;
+
+client_failure:
+ vidc_release_firmware();
+ mpq_dvb_video_device->num_clients--;
+ mutex_destroy(&client_ctx->msg_queue_lock);
+ mutex_destroy(&client_ctx->enrty_queue_lock);
+ memset((void *)client_ctx, 0, sizeof(struct video_client_ctx));
+ return rc;
+}
+
+static int mpq_dvb_video_open(struct inode *inode, struct file *file)
+{
+ int rc;
+ struct mpq_dvb_video_inst *dev_inst = NULL;
+ struct dvb_device *device = NULL;
+
+ DBG("Inside %s()", __func__);
+ mutex_lock(&mpq_dvb_video_device->lock);
+
+ /* Open the dvb/video instance */
+ rc = dvb_generic_open(inode, file);
+ if (rc) {
+ DBG("Failed in dvb_generic_open with return value :%d\n",
+ rc);
+ mutex_unlock(&mpq_dvb_video_device->lock);
+ return rc;
+
+ }
+
+ device = (struct dvb_device *)file->private_data;
+ dev_inst = (struct mpq_dvb_video_inst *)device->priv;
+
+ if (dev_inst->client_ctx) {
+ dvb_generic_release(inode, file);
+ mutex_unlock(&mpq_dvb_video_device->lock);
+ return -EEXIST;
+ }
+
+ rc = mpq_int_vid_dec_open_client(&dev_inst->client_ctx, 0);
+ if (rc) {
+ dvb_generic_release(inode, file);
+ mutex_unlock(&mpq_dvb_video_device->lock);
+ return rc;
+ }
+
+ if (!dev_inst->client_ctx) {
+ dvb_generic_release(inode, file);
+ mutex_unlock(&mpq_dvb_video_device->lock);
+ return -ENOMEM;
+ }
+
+ /* Set default source to memory for easier handling */
+ dev_inst->source = VIDEO_SOURCE_MEMORY;
+
+ mutex_unlock(&mpq_dvb_video_device->lock);
+
+ return rc;
+}
+
+static int mpq_dvb_video_term_dmx_src(struct mpq_dvb_video_inst *dev_inst)
+{
+
+ struct mpq_dmx_src_data *dmx_data = dev_inst->dmx_src_data;
+
+ if (NULL == dmx_data)
+ return 0;
+
+ kthread_stop(dmx_data->data_task);
+ mutex_destroy(&dmx_data->msg_queue_lock);
+
+ kfree(dmx_data);
+ dev_inst->dmx_src_data = NULL;
+
+ return 0;
+
+}
+
+static int mpq_dvb_video_release(struct inode *inode, struct file *file)
+{
+ struct dvb_device *device = file->private_data;
+ struct mpq_dvb_video_inst *dev_inst = device->priv;
+
+ vidc_cleanup_addr_table(dev_inst->client_ctx, BUFFER_TYPE_OUTPUT);
+ vidc_cleanup_addr_table(dev_inst->client_ctx, BUFFER_TYPE_INPUT);
+ if (dev_inst->source == VIDEO_SOURCE_DEMUX)
+ mpq_dvb_video_term_dmx_src(dev_inst);
+ mpq_int_vid_dec_close_client(dev_inst->client_ctx);
+ memset((void *)dev_inst, 0, sizeof(struct mpq_dvb_video_inst));
+ vidc_release_firmware();
+ dvb_generic_release(inode, file);
+ return 0;
+}
+
+static void *mpq_int_vid_dec_map_dev_base_addr(void *device_name)
+{
+ return mpq_dvb_video_device->virt_base;
+}
+
+static int mpq_int_vid_dec_vcd_init(void)
+{
+ int rc;
+ struct vcd_init_config vcd_init_config;
+ u32 i;
+
+ /* init_timer(&hw_timer); */
+ DBG("msm_vidc_dec: Inside %s()", __func__);
+ mpq_dvb_video_device->num_clients = 0;
+
+ for (i = 0; i < VIDC_MAX_NUM_CLIENTS; i++) {
+ memset((void *)&mpq_dvb_video_device->vdec_clients[i], 0,
+ sizeof(mpq_dvb_video_device->vdec_clients[i]));
+ }
+
+ mutex_init(&mpq_dvb_video_device->lock);
+ mpq_dvb_video_device->virt_base = vidc_get_ioaddr();
+ DBG("%s() : base address for VIDC core %u\n", __func__, \
+ (int)mpq_dvb_video_device->virt_base);
+
+ if (!mpq_dvb_video_device->virt_base) {
+ DBG("%s() : ioremap failed\n", __func__);
+ return -ENOMEM;
+ }
+
+ vcd_init_config.device_name = "MPQ_VIDC";
+ vcd_init_config.map_dev_base_addr = mpq_int_vid_dec_map_dev_base_addr;
+ vcd_init_config.interrupt_clr = NULL;
+ vcd_init_config.register_isr = NULL;
+ vcd_init_config.deregister_isr = NULL;
+ vcd_init_config.timer_create = vidc_timer_create;
+ vcd_init_config.timer_release = vidc_timer_release;
+ vcd_init_config.timer_start = vidc_timer_start;
+ vcd_init_config.timer_stop = vidc_timer_stop;
+
+ rc = vcd_init(&vcd_init_config,
+ &mpq_dvb_video_device->device_handle);
+
+ if (rc) {
+ DBG("%s() : vcd_init failed\n", __func__);
+ mutex_destroy(&mpq_dvb_video_device->lock);
+ return -ENODEV;
+ }
+ return 0;
+}
+
+static int mpq_int_vdec_get_fps(struct video_client_ctx *client_ctx,
+ unsigned int *fps)
+{
+ struct vcd_property_hdr vcd_property_hdr;
+ struct vcd_property_frame_rate vcd_frame_rate;
+ u32 vcd_status = VCD_ERR_FAIL;
+
+ if (NULL == fps)
+ return -EINVAL;
+
+ vcd_property_hdr.prop_id = VCD_I_FRAME_RATE;
+ vcd_property_hdr.sz = sizeof(struct vcd_property_frame_rate);
+ vcd_frame_rate.fps_numerator = 0;
+ vcd_frame_rate.fps_denominator = 1;
+
+ *fps = 0;
+ vcd_status = vcd_get_property(client_ctx->vcd_handle,
+ &vcd_property_hdr, &vcd_frame_rate);
+
+ if (vcd_status)
+ return -EINVAL;
+ else {
+ *fps = (vcd_frame_rate.fps_numerator * 1000)
+ /(vcd_frame_rate.fps_denominator);
+ return 0;
+ }
+}
+
+static int mpq_dvb_video_command_handler(struct mpq_dvb_video_inst *dev_inst,
+ void *parg)
+{
+ struct video_client_ctx *client_ctx = dev_inst->client_ctx;
+ struct video_command *cmd = parg;
+ int rc = 0;
+
+ if (cmd == NULL)
+ return -EINVAL;
+
+ switch (cmd->cmd) {
+ case VIDEO_CMD_SET_CODEC:
+ DBG("cmd : VIDEO_CMD_SET_CODEC\n");
+ rc = mpq_int_vid_dec_set_codec(client_ctx, cmd->codec);
+ break;
+ case VIDEO_CMD_GET_CODEC:
+ DBG("cmd : VIDEO_CMD_GET_CODEC\n");
+ rc = mpq_int_vid_dec_get_codec(client_ctx, &cmd->codec);
+ break;
+ case VIDEO_CMD_SET_OUTPUT_FORMAT:
+ DBG("cmd : VIDEO_CMD_SET_OUTPUT_FORMAT\n");
+ rc = mpq_int_vid_dec_set_output_format(client_ctx,
+ cmd->format);
+ break;
+ case VIDEO_CMD_GET_OUTPUT_FORMAT:
+ DBG("cmd : VIDEO_CMD_GET_OUTPUT_FORMAT\n");
+ rc = mpq_int_vid_dec_get_output_format(client_ctx,
+ &cmd->format);
+ break;
+ case VIDEO_CMD_GET_PIC_RES:
+ DBG("cmd : VIDEO_CMD_GET_PIC_RES\n");
+ rc = mpq_int_vid_dec_get_frame_resolution(client_ctx,
+ &cmd->frame_res);
+ break;
+ case VIDEO_CMD_SET_INPUT_BUFFERS:
+ DBG("cmd : VIDEO_CMD_SET_INPUT_BUFFERS\n");
+ rc = mpq_int_vid_dec_set_buffer(dev_inst, &cmd->buffer,
+ BUFFER_TYPE_INPUT);
+ break;
+ case VIDEO_CMD_SET_OUTPUT_BUFFERS:
+ DBG("cmd : VIDEO_CMD_SET_OUTPUT_BUFFERS\n");
+ rc = mpq_int_vid_dec_set_buffer(dev_inst, &cmd->buffer,
+ BUFFER_TYPE_OUTPUT);
+ break;
+ case VIDEO_CMD_FREE_INPUT_BUFFERS:
+ DBG("cmd : VIDEO_CMD_FREE_INPUT_BUFFERS\n");
+ rc = mpq_int_vid_dec_free_buffer(client_ctx, &cmd->buffer,
+ BUFFER_TYPE_INPUT);
+ break;
+ case VIDEO_CMD_FREE_OUTPUT_BUFFERS:
+ DBG("cmd : VIDEO_CMD_FREE_OUTPUT_BUFFERS\n");
+ rc = mpq_int_vid_dec_free_buffer(client_ctx, &cmd->buffer,
+ BUFFER_TYPE_OUTPUT);
+ break;
+ case VIDEO_CMD_GET_BUFFER_REQ:
+ DBG("cmd : VIDEO_CMD_GET_BUFFER_REQ\n");
+ rc = mpq_int_vid_dec_get_buffer_req(client_ctx, &cmd->buf_req);
+ break;
+ case VIDEO_CMD_READ_RAW_OUTPUT:
+ DBG("cmd : VIDEO_CMD_READ_RAW_OUTPUT\n");
+ rc = mpq_int_vid_dec_fill_output_buffer(client_ctx,
+ &cmd->buffer);
+ break;
+ case VIDEO_CMD_SET_H264_MV_BUFFER:
+ DBG("cmd : VIDEO_CMD_SET_H264_MV_BUFFER\n");
+ rc = mpq_int_vid_dec_set_h264_mv_buffers(client_ctx,
+ &cmd->mv_buffer_prop);
+ break;
+ case VIDEO_CMD_GET_H264_MV_BUFFER:
+ DBG("cmd : VIDEO_CMD_GET_H264_MV_BUFFER\n");
+ rc = mpq_int_vid_dec_get_h264_mv_buffer_size(client_ctx,
+ &cmd->mv_buffer_req);
+ break;
+ case VIDEO_CMD_FREE_H264_MV_BUFFER:
+ DBG("cmd : VIDEO_CMD_FREE_H264_MV_BUFFER\n");
+ rc = mpq_int_vid_dec_free_h264_mv_buffers(client_ctx);
+ break;
+ case VIDEO_CMD_CLEAR_INPUT_BUFFER:
+ DBG("cmd : VIDEO_CMD_CLEAR_INPUT_BUFFER\n");
+ rc = mpq_int_vid_dec_flush(client_ctx, VDEC_FLUSH_TYPE_INPUT);
+ break;
+ case VIDEO_CMD_CLEAR_OUTPUT_BUFFER:
+ DBG("cmd : VIDEO_CMD_CLEAR_OUTPUT_BUFFER\n");
+ rc = mpq_int_vid_dec_flush(client_ctx, VDEC_FLUSH_TYPE_OUTPUT);
+ break;
+ default:
+ rc = -EINVAL;
+ break;
+ }
+
+ return rc;
+}
+
+
+static ssize_t mpq_dvb_video_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ int rc = 0;
+ struct dvb_device *device = file->private_data;
+ struct mpq_dvb_video_inst *dev_inst = NULL;
+
+ struct video_data_buffer *input_frame =
+ (struct video_data_buffer *)buf;
+
+ if ((device == NULL) || (input_frame == NULL))
+ return -EINVAL;
+
+ dev_inst = device->priv;
+ if (dev_inst == NULL)
+ return -EINVAL;
+
+ rc = mpq_int_vid_dec_decode_frame(dev_inst->client_ctx, input_frame);
+ if (rc)
+ return -EIO;
+
+ return input_frame->buffer_len;
+}
+
+static int mpq_dvb_video_get_event(struct video_client_ctx *client_ctx,
+ struct video_event *ev)
+{
+ int rc;
+ struct vdec_msginfo vdec_msg_info;
+
+ memset(ev, 0, sizeof(struct video_event));
+
+ rc = mpq_int_vid_dec_get_next_msg(client_ctx, &vdec_msg_info);
+ if (rc)
+ return rc;
+
+ ev->status = vdec_msg_info.status_code;
+ /* Map the Message here */
+ switch (vdec_msg_info.msgcode) {
+ case VDEC_MSG_INVALID:
+ DBG("VDEC_MSG_INVALID\n");
+ break;
+ case VDEC_MSG_RESP_INPUT_BUFFER_DONE:
+ DBG("VIDEO_EVENT_INPUT_BUFFER_DONE\n");
+ ev->type = VIDEO_EVENT_INPUT_BUFFER_DONE;
+ ev->u.buffer.client_data =
+ vdec_msg_info.msgdata.input_frame_clientdata;
+ break;
+ case VDEC_MSG_RESP_OUTPUT_BUFFER_DONE:
+ DBG("VIDEO_EVENT_OUTPUT_BUFFER_DONE\n");
+ ev->type = VIDEO_EVENT_OUTPUT_BUFFER_DONE;
+ ev->u.buffer.bufferaddr =
+ vdec_msg_info.msgdata.output_frame.bufferaddr;
+ ev->u.buffer.buffer_len =
+ vdec_msg_info.msgdata.output_frame.len;
+ ev->u.buffer.ip_buffer_tag = vdec_msg_info.msgdata.\
+ output_frame.input_frame_clientdata;
+ ev->u.buffer.client_data = vdec_msg_info.msgdata.\
+ output_frame.client_data;
+ ev->u.buffer.pts =
+ vdec_msg_info.msgdata.output_frame.time_stamp;
+ ev->u.buffer.offset =
+ vdec_msg_info.msgdata.output_frame.offset;
+ break;
+ case VDEC_MSG_RESP_START_DONE:
+ DBG("VIDEO_EVENT_DECODER_PLAYING\n");
+ ev->type = VIDEO_EVENT_DECODER_PLAYING;
+ break;
+ case VDEC_MSG_RESP_STOP_DONE:
+ DBG("VIDEO_EVENT_DECODER_FREEZED\n");
+ ev->type = VIDEO_EVENT_DECODER_STOPPED;
+ break;
+ case VDEC_MSG_RESP_PAUSE_DONE:
+ DBG("VDEC_MSG_RESP_PAUSE_DONE\n");
+ ev->type = VIDEO_EVENT_DECODER_FREEZED;
+ break;
+ case VDEC_MSG_RESP_RESUME_DONE:
+ DBG("VIDEO_EVENT_DECODER_RESUMED\n");
+ ev->type = VIDEO_EVENT_DECODER_RESUMED;
+ break;
+ case VDEC_MSG_EVT_CONFIG_CHANGED:
+ case VDEC_MSG_EVT_INFO_CONFIG_CHANGED:
+ DBG("VIDEO_EVENT_SEQ_HDR_FOUND\n");
+ ev->type = VIDEO_EVENT_SEQ_HDR_FOUND;
+ break;
+ case VDEC_MSG_RESP_FLUSH_OUTPUT_DONE:
+ DBG("VIDEO_EVENT_OUTPUT_FLUSH_DONE\n");
+ ev->type = VIDEO_EVENT_OUTPUT_FLUSH_DONE;
+ break;
+ case VDEC_MSG_RESP_OUTPUT_FLUSHED:
+ DBG("VIDEO_EVENT_OUTPUT_FLUSHED\n");
+ ev->type = VIDEO_EVENT_OUTPUT_FLUSHED;
+ ev->u.buffer.bufferaddr =
+ vdec_msg_info.msgdata.output_frame.bufferaddr;
+ ev->u.buffer.buffer_len =
+ vdec_msg_info.msgdata.output_frame.len;
+ ev->u.buffer.ip_buffer_tag = vdec_msg_info.msgdata.\
+ output_frame.input_frame_clientdata;
+ ev->u.buffer.client_data = vdec_msg_info.msgdata.\
+ output_frame.client_data;
+ ev->u.buffer.pts =
+ vdec_msg_info.msgdata.output_frame.time_stamp;
+ ev->u.buffer.offset =
+ vdec_msg_info.msgdata.output_frame.offset;
+ break;
+ case VDEC_MSG_RESP_FLUSH_INPUT_DONE:
+ DBG("VIDEO_EVENT_INPUT_FLUSH_DONE\n");
+ ev->type = VIDEO_EVENT_INPUT_FLUSH_DONE;
+ break;
+ case VDEC_MSG_RESP_INPUT_FLUSHED:
+ DBG("VIDEO_EVENT_INPUT_FLUSHED\n");
+ ev->type = VIDEO_EVENT_INPUT_FLUSHED;
+ ev->u.buffer.client_data =
+ vdec_msg_info.msgdata.input_frame_clientdata;
+ break;
+ }
+ return 0;
+}
+
+static int mpq_dvb_video_play(struct mpq_dvb_video_inst *dev_inst)
+{
+ return mpq_int_vid_dec_start_stop(dev_inst->client_ctx, true);
+}
+
+static int mpq_dvb_video_stop(struct video_client_ctx *client_ctx)
+{
+ return mpq_int_vid_dec_start_stop(client_ctx, false);
+}
+
+static void mpq_dvb_video_get_stream_if(
+ enum mpq_adapter_stream_if interface_id,
+ void *arg)
+{
+ struct mpq_dvb_video_inst *dev_inst = arg;
+
+ DBG("In mpq_dvb_video_get_stream_if : %d\n", interface_id);
+
+ mpq_adapter_get_stream_if(interface_id,
+ &dev_inst->dmx_src_data->stream_buffer);
+
+ wake_up(&dev_inst->dmx_src_data->msg_wait);
+}
+
+static int mpq_dvb_video_init_dmx_src(struct mpq_dvb_video_inst *dev_inst,
+ int device_id)
+{
+ int rc;
+
+ dev_inst->dmx_src_data = kzalloc(sizeof(struct mpq_dmx_src_data),
+ GFP_KERNEL);
+ if (dev_inst->dmx_src_data == NULL)
+ return -ENOMEM;
+
+ rc = mpq_adapter_get_stream_if(
+ (enum mpq_adapter_stream_if)device_id,
+ &dev_inst->dmx_src_data->stream_buffer);
+
+ if (rc) {
+ kfree(dev_inst->dmx_src_data);
+ return -ENODEV;
+ } else if (dev_inst->dmx_src_data->stream_buffer == NULL) {
+ DBG("Stream Buffer is NULL. Resigtering Notifier.\n");
+ rc = mpq_adapter_notify_stream_if(
+ (enum mpq_adapter_stream_if)device_id,
+ mpq_dvb_video_get_stream_if,
+ (void *)dev_inst);
+ if (rc) {
+ kfree(dev_inst->dmx_src_data);
+ return -ENODEV;
+ }
+ }
+
+ mutex_init(&dev_inst->dmx_src_data->msg_queue_lock);
+ INIT_LIST_HEAD(&dev_inst->dmx_src_data->msg_queue);
+ init_waitqueue_head(&dev_inst->dmx_src_data->msg_wait);
+
+ dev_inst->dmx_src_data->data_task = kthread_run(
+ mpq_bcast_data_handler, (void *)dev_inst,
+ vid_thread_names[device_id]);
+
+ return 0;
+}
+
+static int mpq_dvb_video_set_source(struct dvb_device *device,
+ video_stream_source_t source)
+{
+ int rc = 0;
+ struct mpq_dvb_video_inst *dev_inst =
+ (struct mpq_dvb_video_inst *)device->priv;
+
+ if (dev_inst->source == source)
+ return rc;
+
+ if ((VIDEO_SOURCE_MEMORY == source) &&
+ (VIDEO_SOURCE_DEMUX == dev_inst->source))
+ mpq_dvb_video_term_dmx_src(dev_inst);
+
+ dev_inst->source = source;
+ if (VIDEO_SOURCE_DEMUX == source)
+ rc = mpq_dvb_video_init_dmx_src(dev_inst, device->id);
+
+ return rc;
+}
+
+static int mpq_dvb_video_ioctl(struct file *file,
+ unsigned int cmd, void *parg)
+{
+ int rc;
+ struct dvb_device *device = (struct dvb_device *)file->private_data;
+ struct video_client_ctx *client_ctx = NULL;
+ struct mpq_dvb_video_inst *dev_inst = NULL;
+
+ if (device == NULL)
+ return -EINVAL;
+
+ dev_inst = (struct mpq_dvb_video_inst *)device->priv;
+ if (dev_inst == NULL)
+ return -EINVAL;
+
+ client_ctx = (struct video_client_ctx *)dev_inst->client_ctx;
+ if (client_ctx == NULL)
+ return -EINVAL;
+
+ switch (cmd) {
+ case VIDEO_PLAY:
+ DBG("ioctl : VIDEO_PLAY\n");
+ rc = mpq_dvb_video_play(dev_inst);
+ break;
+ case VIDEO_STOP:
+ DBG("ioctl : VIDEO_STOP\n");
+ rc = mpq_dvb_video_stop(client_ctx);
+ break;
+ case VIDEO_FREEZE:
+ DBG("ioctl : VIDEO_FREEZE\n");
+ rc = mpq_int_vid_dec_pause_resume(client_ctx, true);
+ break;
+ case VIDEO_CONTINUE:
+ DBG("ioctl : VIDEO_CONTINUE\n");
+ rc = mpq_int_vid_dec_pause_resume(client_ctx, false);
+ break;
+ case VIDEO_CLEAR_BUFFER:
+ DBG("ioctl : VIDEO_CLEAR_BUFFER\n");
+ rc = mpq_int_vid_dec_flush(client_ctx,
+ VDEC_FLUSH_TYPE_ALL);
+ break;
+ case VIDEO_COMMAND:
+ case VIDEO_TRY_COMMAND:
+ DBG("ioctl : VIDEO_COMMAND\n");
+ rc = mpq_dvb_video_command_handler(dev_inst, parg);
+ break;
+ case VIDEO_GET_FRAME_RATE:
+ DBG("ioctl : VIDEO_GET_FRAME_RATE\n");
+ rc = mpq_int_vdec_get_fps(client_ctx,
+ (unsigned int *)parg);
+ break;
+ case VIDEO_GET_EVENT:
+ DBG("ioctl : VIDEO_GET_EVENT\n");
+ rc = mpq_dvb_video_get_event(client_ctx,
+ (struct video_event *)parg);
+ break;
+ case VIDEO_SELECT_SOURCE:
+ DBG("ioctl : VIDEO_SELECT_SOURCE\n");
+ rc = mpq_dvb_video_set_source(device,
+ (video_stream_source_t)parg);
+ break;
+ default:
+ ERR("Invalid IOCTL\n");
+ rc = -EINVAL;
+ }
+
+ return rc;
+
+}
+
+static unsigned int mpq_dvb_video_poll(struct file *file, poll_table *wait)
+{
+ struct dvb_device *device = file->private_data;
+ struct video_client_ctx *client_ctx = NULL;
+ struct mpq_dvb_video_inst *dev_inst = NULL;
+ unsigned int mask = 0;
+
+ DBG("In %s\n", __func__);
+
+ if (device == NULL)
+ return -EINVAL;
+
+ dev_inst = device->priv;
+ if (dev_inst == NULL)
+ return -EINVAL;
+
+ client_ctx = dev_inst->client_ctx;
+ if (client_ctx == NULL)
+ return -EINVAL;
+
+ poll_wait(file, &client_ctx->msg_wait, wait);
+ if (mpq_int_vid_dec_msg_pending(client_ctx))
+ mask |= POLLIN;
+ else
+ mask = 0;
+
+ return mask;
+}
+
+/*
+ * Driver Registration.
+ */
+static const struct file_operations mpq_dvb_video_fops = {
+ .owner = THIS_MODULE,
+ .write = mpq_dvb_video_write,
+ .unlocked_ioctl = dvb_generic_ioctl,
+ .open = mpq_dvb_video_open,
+ .release = mpq_dvb_video_release,
+ .poll = mpq_dvb_video_poll,
+ .llseek = noop_llseek,
+};
+
+static const struct dvb_device mpq_dvb_video_device_ctrl = {
+ .priv = NULL,
+ .users = 4,
+ .readers = 4, /* arbitrary */
+ .writers = 4,
+ .fops = &mpq_dvb_video_fops,
+ .kernel_ioctl = mpq_dvb_video_ioctl,
+};
+
+static int __init mpq_dvb_video_init(void)
+{
+ int rc, i = 0, j;
+
+ mpq_dvb_video_device = kzalloc(sizeof(struct mpq_dvb_video_dev),
+ GFP_KERNEL);
+ if (!mpq_dvb_video_device) {
+ ERR("%s Unable to allocate memory for mpq_dvb_video_dev\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ mpq_dvb_video_device->mpq_adapter = mpq_adapter_get();
+ if (!mpq_dvb_video_device->mpq_adapter) {
+ ERR("%s Unable to get MPQ Adapter\n", __func__);
+ rc = -ENODEV;
+ goto free_region;
+ }
+
+ rc = mpq_int_vid_dec_vcd_init();
+ if (rc)
+ goto free_region;
+
+ for (i = 0; i < DVB_MPQ_NUM_VIDEO_DEVICES; i++) {
+
+ rc = dvb_register_device(mpq_dvb_video_device->mpq_adapter,
+ &mpq_dvb_video_device->dev_inst[i].video_dev,
+ &mpq_dvb_video_device_ctrl,
+ &mpq_dvb_video_device->dev_inst[i],
+ DVB_DEVICE_VIDEO);
+
+ if (rc) {
+ ERR("Failed in %s with at %d return value :%d\n",
+ __func__, i, rc);
+ goto free_region;
+ }
+
+ }
+
+ return 0;
+
+free_region:
+ for (j = 0; j < i; j++)
+ dvb_unregister_device(
+ mpq_dvb_video_device->dev_inst[j].video_dev);
+
+ kfree(mpq_dvb_video_device);
+ return rc;
+}
+
+static void __exit mpq_dvb_video_exit(void)
+{
+ int i;
+
+ for (i = 0; i < DVB_MPQ_NUM_VIDEO_DEVICES; i++)
+ dvb_unregister_device(
+ mpq_dvb_video_device->dev_inst[i].video_dev);
+
+ mutex_destroy(&mpq_dvb_video_device->lock);
+ kfree(mpq_dvb_video_device);
+}
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("MPQ DVB Video driver");
+
+module_init(mpq_dvb_video_init);
+module_exit(mpq_dvb_video_exit);
diff --git a/drivers/media/dvb/mpq/video/mpq_dvb_video_internal.h b/drivers/media/dvb/mpq/video/mpq_dvb_video_internal.h
new file mode 100644
index 0000000..df337b9
--- /dev/null
+++ b/drivers/media/dvb/mpq/video/mpq_dvb_video_internal.h
@@ -0,0 +1,93 @@
+/* Copyright (c) 2010,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 MPQ_DVB_VIDEO_INTERNAL_H
+#define MPQ_DVB_VIDEO_INTERNAL_H
+
+#include <linux/msm_vidc_dec.h>
+#include <media/msm/vidc_init.h>
+#include <linux/dvb/video.h>
+
+/*
+ * MPQ Specific Includes.
+ */
+#include "mpq_dvb_debug.h"
+#include "mpq_adapter.h"
+#include "mpq_stream_buffer.h"
+
+#define DVB_MPQ_NUM_VIDEO_DEVICES CONFIG_DVB_MPQ_NUM_VIDEO_DEVICES
+
+/*
+ * Input Buffer Requirements for Video Decoder.
+ */
+#define DVB_VID_NUM_IN_BUFFERS (2)
+#define DVB_VID_IN_BUFFER_SIZE (2*1024*1024)
+#define DVB_VID_IN_BUFFER_ALGN (8*1024)
+
+struct vid_dec_msg {
+ struct list_head list;
+ struct vdec_msginfo vdec_msg_info;
+};
+
+enum mpq_bcast_msgcode {
+ MPQ_BCAST_MSG_START,
+ MPQ_BCAST_MSG_IBD,
+ MPQ_BCAST_MSG_FLUSH,
+ MPQ_BCAST_MSG_TERM
+};
+
+struct mpq_bcast_msg_info {
+ enum mpq_bcast_msgcode code;
+ unsigned int data;
+};
+
+struct mpq_bcast_msg {
+ struct list_head list;
+ struct mpq_bcast_msg_info info;
+};
+
+struct mpq_dmx_src_data {
+ struct mpq_streambuffer *stream_buffer;
+ struct video_data_buffer in_buffer[DVB_VID_NUM_IN_BUFFERS];
+ struct list_head msg_queue;
+ wait_queue_head_t msg_wait;
+ struct mutex msg_queue_lock;
+ struct task_struct *data_task;
+};
+
+struct mpq_dvb_video_inst {
+ struct dvb_device *video_dev;
+ video_stream_source_t source;
+ struct mpq_dmx_src_data *dmx_src_data;
+ struct video_client_ctx *client_ctx;
+};
+
+struct mpq_dvb_video_dev {
+
+ resource_size_t phys_base;
+ void __iomem *virt_base;
+ unsigned int irq;
+ struct clk *hclk;
+ struct clk *hclk_div2;
+ struct clk *pclk;
+ unsigned long hclk_rate;
+ struct mutex lock;
+ s32 device_handle;
+ struct dvb_adapter *mpq_adapter;
+ struct mpq_dvb_video_inst dev_inst[DVB_MPQ_NUM_VIDEO_DEVICES];
+ struct video_client_ctx vdec_clients[DVB_MPQ_NUM_VIDEO_DEVICES];
+ u32 num_clients;
+ void(*timer_handler)(void *);
+};
+
+#endif /* MPQ_DVB_VIDEO_INTERNAL_H */
diff --git a/drivers/media/radio/radio-iris.c b/drivers/media/radio/radio-iris.c
index 1894465..d596782 100644
--- a/drivers/media/radio/radio-iris.c
+++ b/drivers/media/radio/radio-iris.c
@@ -2653,7 +2653,7 @@
tx_ps.pi = radio->pi;
tx_ps.pty = radio->pty;
tx_ps.ps_repeatcount = radio->ps_repeatcount;
- tx_ps.ps_len = bytes_to_copy;
+ tx_ps.ps_num = (bytes_to_copy / PS_STRING_LEN);
retval = radio_hci_request(radio->fm_hdev, hci_trans_ps_req,
(unsigned long)&tx_ps, RADIO_HCI_TIMEOUT);
@@ -2672,7 +2672,7 @@
tx_rt.rt_control = 0x01;
tx_rt.pi = radio->pi;
tx_rt.pty = radio->pty;
- tx_rt.ps_len = bytes_to_copy;
+ tx_rt.rt_len = bytes_to_copy;
retval = radio_hci_request(radio->fm_hdev, hci_trans_rt_req,
(unsigned long)&tx_rt, RADIO_HCI_TIMEOUT);
diff --git a/drivers/media/video/msm/cci/msm_cci.c b/drivers/media/video/msm/cci/msm_cci.c
index 3caa580..77bd91e 100644
--- a/drivers/media/video/msm/cci/msm_cci.c
+++ b/drivers/media/video/msm/cci/msm_cci.c
@@ -704,7 +704,9 @@
new_cci_dev->pdev = pdev;
msm_cci_initialize_cci_params(new_cci_dev);
-
+ rc = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
+ if (rc)
+ pr_err("%s: failed to add child nodes, rc=%d\n", __func__, rc);
CDBG("%s line %d\n", __func__, __LINE__);
return 0;
diff --git a/drivers/media/video/msm/csi/msm_csid.c b/drivers/media/video/msm/csi/msm_csid.c
index 7996ed1..e5258f1 100644
--- a/drivers/media/video/msm/csi/msm_csid.c
+++ b/drivers/media/video/msm/csi/msm_csid.c
@@ -195,6 +195,14 @@
rc = -EINVAL;
return rc;
}
+
+ if (csid_dev->csid_state == CSID_POWER_UP) {
+ pr_err("%s: csid invalid state %d\n", __func__,
+ csid_dev->csid_state);
+ rc = -EINVAL;
+ return rc;
+ }
+
csid_dev->base = ioremap(csid_dev->mem->start,
resource_size(csid_dev->mem));
if (!csid_dev->base) {
@@ -262,6 +270,7 @@
enable_irq(csid_dev->irq->start);
msm_csid_reset(csid_dev);
+ csid_dev->csid_state = CSID_POWER_UP;
return rc;
clk_enable_failed:
@@ -294,6 +303,12 @@
{
uint32_t irq;
+ if (csid_dev->csid_state != CSID_POWER_UP) {
+ pr_err("%s: csid invalid state %d\n", __func__,
+ csid_dev->csid_state);
+ return -EINVAL;
+ }
+
irq = msm_camera_io_r(csid_dev->base + CSID_IRQ_STATUS_ADDR);
msm_camera_io_w(irq, csid_dev->base + CSID_IRQ_CLEAR_CMD_ADDR);
msm_camera_io_w(0, csid_dev->base + CSID_IRQ_MASK_ADDR);
@@ -326,6 +341,7 @@
iounmap(csid_dev->base);
csid_dev->base = NULL;
+ csid_dev->csid_state = CSID_POWER_DOWN;
return 0;
}
@@ -528,6 +544,7 @@
goto csid_no_resource;
}
+ new_csid_dev->csid_state = CSID_POWER_DOWN;
return 0;
csid_no_resource:
diff --git a/drivers/media/video/msm/csi/msm_csid.h b/drivers/media/video/msm/csi/msm_csid.h
index 398acbc..1d4de01 100644
--- a/drivers/media/video/msm/csi/msm_csid.h
+++ b/drivers/media/video/msm/csi/msm_csid.h
@@ -18,6 +18,11 @@
#include <media/v4l2-subdev.h>
#include <media/msm_camera.h>
+enum msm_csid_state_t {
+ CSID_POWER_UP,
+ CSID_POWER_DOWN,
+};
+
struct csid_device {
struct platform_device *pdev;
struct v4l2_subdev subdev;
@@ -29,6 +34,7 @@
struct mutex mutex;
struct completion reset_complete;
uint32_t hw_version;
+ enum msm_csid_state_t csid_state;
struct clk *csid_clk[5];
};
diff --git a/drivers/media/video/msm/csi/msm_csiphy.c b/drivers/media/video/msm/csi/msm_csiphy.c
index 3113295..065ba34 100644
--- a/drivers/media/video/msm/csi/msm_csiphy.c
+++ b/drivers/media/video/msm/csi/msm_csiphy.c
@@ -162,6 +162,13 @@
return rc;
}
+ if (csiphy_dev->csiphy_state == CSIPHY_POWER_UP) {
+ pr_err("%s: csiphy invalid state %d\n", __func__,
+ csiphy_dev->csiphy_state);
+ rc = -EINVAL;
+ return rc;
+ }
+
if (csiphy_dev->ref_count++) {
CDBG("%s csiphy refcount = %d\n", __func__,
csiphy_dev->ref_count);
@@ -202,6 +209,7 @@
csiphy_dev->hw_version =
msm_camera_io_r(csiphy_dev->base + MIPI_CSIPHY_HW_VERSION_ADDR);
+ csiphy_dev->csiphy_state = CSIPHY_POWER_UP;
return 0;
}
@@ -217,6 +225,13 @@
pr_err("%s csiphy dev NULL / ref_count ZERO\n", __func__);
return 0;
}
+
+ if (csiphy_dev->csiphy_state != CSIPHY_POWER_UP) {
+ pr_err("%s: csiphy invalid state %d\n", __func__,
+ csiphy_dev->csiphy_state);
+ return -EINVAL;
+ }
+
CDBG("%s csiphy_params, lane assign %x mask = %x\n",
__func__,
csi_lane_params->csi_lane_assign,
@@ -264,6 +279,7 @@
iounmap(csiphy_dev->base);
csiphy_dev->base = NULL;
+ csiphy_dev->csiphy_state = CSIPHY_POWER_DOWN;
return 0;
}
@@ -408,6 +424,7 @@
new_csiphy_dev->subdev.entity.name = pdev->name;
new_csiphy_dev->subdev.entity.revision =
new_csiphy_dev->subdev.devnode->num;
+ new_csiphy_dev->csiphy_state = CSIPHY_POWER_DOWN;
return 0;
csiphy_no_resource:
diff --git a/drivers/media/video/msm/csi/msm_csiphy.h b/drivers/media/video/msm/csi/msm_csiphy.h
index 4b2e68e..2fb21d2 100644
--- a/drivers/media/video/msm/csi/msm_csiphy.h
+++ b/drivers/media/video/msm/csi/msm_csiphy.h
@@ -20,6 +20,11 @@
#define MAX_CSIPHY 3
+enum msm_csiphy_state_t {
+ CSIPHY_POWER_UP,
+ CSIPHY_POWER_DOWN,
+};
+
struct csiphy_device {
struct platform_device *pdev;
struct v4l2_subdev subdev;
@@ -29,6 +34,7 @@
void __iomem *base;
struct mutex mutex;
uint32_t hw_version;
+ enum msm_csiphy_state_t csiphy_state;
struct clk *csiphy_clk[3];
uint8_t ref_count;
diff --git a/drivers/media/video/msm/csi/msm_ispif.c b/drivers/media/video/msm/csi/msm_ispif.c
index ab97138..bbaa0da 100644
--- a/drivers/media/video/msm/csi/msm_ispif.c
+++ b/drivers/media/video/msm/csi/msm_ispif.c
@@ -115,7 +115,7 @@
uint8_t intftype, uint8_t csid, uint8_t vfe_intf)
{
int rc = 0;
- uint32_t data;
+ uint32_t data = 0;
if (ispif->csid_version <= CSID_VERSION_V2) {
if (ispif->ispif_clk[intftype] == NULL) {
@@ -154,14 +154,16 @@
data |= (csid << 20);
break;
}
- msm_camera_io_w(data, ispif->base + ISPIF_INPUT_SEL_ADDR +
- (0x200 * vfe_intf));
+ if (data) {
+ msm_camera_io_w(data, ispif->base + ISPIF_INPUT_SEL_ADDR +
+ (0x200 * vfe_intf));
+ }
}
static void msm_ispif_enable_intf_cids(struct ispif_device *ispif,
uint8_t intftype, uint16_t cid_mask, uint8_t vfe_intf)
{
- uint32_t data;
+ uint32_t data = 0;
mutex_lock(&ispif->mutex);
switch (intftype) {
case PIX0:
@@ -211,7 +213,7 @@
uint8_t intftype, uint8_t vfe_intf)
{
int32_t rc = 0;
- uint32_t data;
+ uint32_t data = 0;
mutex_lock(&ispif->mutex);
switch (intftype) {
case PIX0:
@@ -679,6 +681,14 @@
{
int rc = 0;
CDBG("%s called %d\n", __func__, __LINE__);
+
+ if (ispif->ispif_state == ISPIF_POWER_UP) {
+ pr_err("%s: ispif invalid state %d\n", __func__,
+ ispif->ispif_state);
+ rc = -EINVAL;
+ return rc;
+ }
+
spin_lock_init(&ispif_tasklet_lock);
INIT_LIST_HEAD(&ispif_tasklet_q);
rc = request_irq(ispif->irq->start, msm_io_ispif_irq,
@@ -701,11 +711,18 @@
return rc;
}
rc = msm_ispif_reset(ispif);
+ ispif->ispif_state = ISPIF_POWER_UP;
return rc;
}
static void msm_ispif_release(struct ispif_device *ispif)
{
+ if (ispif->ispif_state != ISPIF_POWER_UP) {
+ pr_err("%s: ispif invalid state %d\n", __func__,
+ ispif->ispif_state);
+ return;
+ }
+
CDBG("%s, free_irq\n", __func__);
free_irq(ispif->irq->start, ispif);
tasklet_kill(&ispif->ispif_tasklet);
@@ -717,6 +734,7 @@
msm_cam_clk_enable(&ispif->pdev->dev, ispif_8960_clk_info,
ispif->ispif_clk, ARRAY_SIZE(ispif_8960_clk_info), 0);
}
+ ispif->ispif_state = ISPIF_POWER_DOWN;
}
static long msm_ispif_cmd(struct v4l2_subdev *sd, void *arg)
@@ -853,6 +871,7 @@
ispif->subdev.entity.group_id = ISPIF_DEV;
ispif->subdev.entity.name = pdev->name;
ispif->subdev.entity.revision = ispif->subdev.devnode->num;
+ ispif->ispif_state = ISPIF_POWER_DOWN;
return 0;
ispif_no_mem:
diff --git a/drivers/media/video/msm/csi/msm_ispif.h b/drivers/media/video/msm/csi/msm_ispif.h
index a581a37..ea69959 100644
--- a/drivers/media/video/msm/csi/msm_ispif.h
+++ b/drivers/media/video/msm/csi/msm_ispif.h
@@ -23,6 +23,11 @@
uint32_t ispifIrqStatus2;
};
+enum msm_ispif_state_t {
+ ISPIF_POWER_UP,
+ ISPIF_POWER_DOWN,
+};
+
struct ispif_device {
struct platform_device *pdev;
struct v4l2_subdev subdev;
@@ -40,6 +45,7 @@
uint32_t rdi1_sof_count;
uint32_t rdi2_sof_count;
struct tasklet_struct ispif_tasklet;
+ enum msm_ispif_state_t ispif_state;
};
struct ispif_isr_queue_cmd {
diff --git a/drivers/media/video/msm/io/msm_camera_io_util.c b/drivers/media/video/msm/io/msm_camera_io_util.c
index 5dfa6a2..613850b 100644
--- a/drivers/media/video/msm/io/msm_camera_io_util.c
+++ b/drivers/media/video/msm/io/msm_camera_io_util.c
@@ -458,3 +458,39 @@
}
return rc;
}
+
+void msm_camera_bus_scale_cfg(uint32_t bus_perf_client,
+ enum msm_bus_perf_setting perf_setting)
+{
+ int rc = 0;
+ if (!bus_perf_client) {
+ pr_err("%s: Bus Client NOT Registered!!!\n", __func__);
+ return;
+ }
+
+ switch (perf_setting) {
+ case S_EXIT:
+ rc = msm_bus_scale_client_update_request(bus_perf_client, 1);
+ msm_bus_scale_unregister_client(bus_perf_client);
+ break;
+ case S_PREVIEW:
+ rc = msm_bus_scale_client_update_request(bus_perf_client, 1);
+ break;
+ case S_VIDEO:
+ rc = msm_bus_scale_client_update_request(bus_perf_client, 2);
+ break;
+ case S_CAPTURE:
+ rc = msm_bus_scale_client_update_request(bus_perf_client, 3);
+ break;
+ case S_ZSL:
+ rc = msm_bus_scale_client_update_request(bus_perf_client, 4);
+ break;
+ case S_LIVESHOT:
+ rc = msm_bus_scale_client_update_request(bus_perf_client, 5);
+ break;
+ case S_DEFAULT:
+ break;
+ default:
+ pr_warning("%s: INVALID CASE\n", __func__);
+ }
+}
diff --git a/drivers/media/video/msm/msm.c b/drivers/media/video/msm/msm.c
index 98b2372..e4dd756 100644
--- a/drivers/media/video/msm/msm.c
+++ b/drivers/media/video/msm/msm.c
@@ -934,7 +934,7 @@
pcam_inst->my_index,
pcam->vnode_id, pcam->use_count);
pcam->use_count++;
- D("%s use_count %d\n", __func__, pcam->use_count);
+ D("%s Inst %p use_count %d\n", __func__, pcam_inst, pcam->use_count);
if (pcam->use_count == 1) {
server_q_idx = msm_find_free_queue();
if (server_q_idx < 0)
diff --git a/drivers/media/video/msm/msm.h b/drivers/media/video/msm/msm.h
index 577648f..3dc0fe7 100644
--- a/drivers/media/video/msm/msm.h
+++ b/drivers/media/video/msm/msm.h
@@ -332,7 +332,7 @@
uint32_t data_offset;
};
-#define MSM_DEV_INST_MAX 16
+#define MSM_DEV_INST_MAX 24
struct msm_cam_v4l2_dev_inst {
struct v4l2_fh eventHandle;
struct vb2_queue vid_bufq;
diff --git a/drivers/media/video/msm/msm_mctl_pp.c b/drivers/media/video/msm/msm_mctl_pp.c
index 1f5b739..b2cddb0 100644
--- a/drivers/media/video/msm/msm_mctl_pp.c
+++ b/drivers/media/video/msm/msm_mctl_pp.c
@@ -329,6 +329,7 @@
pp_frame->frame_id = vb->vidbuf.v4l2_buf.sequence;
pp_frame->timestamp = vb->vidbuf.v4l2_buf.timestamp;
pp_frame->buf_idx = buf_idx;
+ pp_frame->inst_handle = pcam_inst->inst_handle;
/* Get the cookie for 1st plane and store the path.
* Also use this to check the number of planes in
* this buffer.*/
@@ -482,6 +483,8 @@
pr_err("%s Instance already closed ", __func__);
return -EINVAL;
}
+ D("%s Reserving free frame using %p inst handle %x ", __func__,
+ pcam_inst, div_frame.frame.inst_handle);
if (div_frame.frame.inst_handle) {
buf_handle.buf_lookup_type = BUF_LOOKUP_BY_INST_HANDLE;
buf_handle.inst_handle = div_frame.frame.inst_handle;
@@ -499,7 +502,7 @@
rc = -EFAULT;
}
}
- D("%s: reserve free buf got buffer %d from %p rc = %d, phy = 0x%x",
+ D("%s: Got buffer %d from Inst %p rc = %d, phy = 0x%x",
__func__, div_frame.frame.buf_idx,
pcam_inst, rc, free_buf.ch_paddr[0]);
return rc;
@@ -638,7 +641,7 @@
void __user *arg)
{
struct msm_pp_frame frame;
- int msg_type, image_mode, rc = 0;
+ int rc = 0;
struct msm_free_buf buf;
unsigned long flags;
struct msm_cam_buf_handle buf_handle;
@@ -652,51 +655,12 @@
}
spin_lock_irqsave(&p_mctl->pp_info.lock, flags);
- D("%s Frame path: %d\n", __func__, frame.path);
- switch (frame.path) {
- case OUTPUT_TYPE_P:
- msg_type = VFE_MSG_OUTPUT_P;
- image_mode = MSM_V4L2_EXT_CAPTURE_MODE_PREVIEW;
- break;
- case OUTPUT_TYPE_S:
- msg_type = VFE_MSG_OUTPUT_S;
- image_mode = MSM_V4L2_EXT_CAPTURE_MODE_MAIN;
- break;
- case OUTPUT_TYPE_V:
- msg_type = VFE_MSG_OUTPUT_V;
- image_mode = MSM_V4L2_EXT_CAPTURE_MODE_VIDEO;
- break;
- case OUTPUT_TYPE_T:
- msg_type = VFE_MSG_OUTPUT_T;
- image_mode = MSM_V4L2_EXT_CAPTURE_MODE_THUMBNAIL;
- break;
- case OUTPUT_TYPE_SAEC:
- msg_type = VFE_MSG_STATS_AEC;
- image_mode = MSM_V4L2_EXT_CAPTURE_MODE_AEC;
- break;
- case OUTPUT_TYPE_SAWB:
- msg_type = VFE_MSG_STATS_AWB;
- image_mode = MSM_V4L2_EXT_CAPTURE_MODE_AWB;
- break;
- case OUTPUT_TYPE_SAFC:
- msg_type = VFE_MSG_STATS_AF;
- image_mode = MSM_V4L2_EXT_CAPTURE_MODE_AF;
- break;
- case OUTPUT_TYPE_IHST:
- msg_type = VFE_MSG_STATS_IHIST;
- image_mode = MSM_V4L2_EXT_CAPTURE_MODE_IHIST;
- break;
- default:
- rc = -EFAULT;
- goto err;
- }
-
if (frame.inst_handle) {
buf_handle.buf_lookup_type = BUF_LOOKUP_BY_INST_HANDLE;
buf_handle.inst_handle = frame.inst_handle;
} else {
buf_handle.buf_lookup_type = BUF_LOOKUP_BY_IMG_MODE;
- buf_handle.image_mode = image_mode;
+ buf_handle.image_mode = frame.image_type;
}
if (frame.num_planes > 1)
@@ -713,9 +677,6 @@
D("%s Frame done id: %d\n", __func__, frame.frame_id);
rc = msm_mctl_buf_done_pp(p_mctl, &buf_handle, &buf, &ret_frame);
return rc;
-err:
- spin_unlock_irqrestore(&p_mctl->pp_info.lock, flags);
- return rc;
}
int msm_mctl_pp_mctl_divert_done(
diff --git a/drivers/media/video/msm/vfe/Makefile b/drivers/media/video/msm/vfe/Makefile
index 91f0e7f..250b55f 100644
--- a/drivers/media/video/msm/vfe/Makefile
+++ b/drivers/media/video/msm/vfe/Makefile
@@ -16,5 +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_ARCH_MSM8974) += msm_vfe40.o
obj-$(CONFIG_MSM_CAMERA_V4L2) += msm_vfe_stats_buf.o
diff --git a/drivers/media/video/msm/vfe/msm_vfe32.c b/drivers/media/video/msm/vfe/msm_vfe32.c
index 2740808..2a9c186 100644
--- a/drivers/media/video/msm/vfe/msm_vfe32.c
+++ b/drivers/media/video/msm/vfe/msm_vfe32.c
@@ -3712,7 +3712,7 @@
static void vfe32_process_camif_sof_irq(
struct vfe32_ctrl_type *vfe32_ctrl)
{
- if (vfe32_ctrl->share_ctrl->operation_mode &
+ if (vfe32_ctrl->share_ctrl->operation_mode ==
VFE_OUTPUTS_RAW) {
if (vfe32_ctrl->share_ctrl->start_ack_pending) {
vfe32_ctrl->share_ctrl->start_ack_pending = FALSE;
@@ -5624,6 +5624,10 @@
if (axi_ctrl->share_ctrl->outpath.output_mode &
VFE32_OUTPUT_MODE_PRIMARY) {
+ if (vfe_params.cmd_type == AXI_CMD_RAW_CAPTURE)
+ irq_comp_mask |= (
+ 0x1 << axi_ctrl->share_ctrl->outpath.out0.ch0);
+ else
irq_comp_mask |= (
0x1 << axi_ctrl->share_ctrl->outpath.out0.ch0 |
0x1 << axi_ctrl->share_ctrl->outpath.out0.ch1);
diff --git a/drivers/media/video/msm/vfe/msm_vfe40.c b/drivers/media/video/msm/vfe/msm_vfe40.c
index 875e034..1297379 100644
--- a/drivers/media/video/msm/vfe/msm_vfe40.c
+++ b/drivers/media/video/msm/vfe/msm_vfe40.c
@@ -15,226 +15,597 @@
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/io.h>
+#include <linux/of.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 <mach/msm_bus.h>
+#include <mach/msm_bus_board.h>
#include "msm.h"
+#include "msm_cam_server.h"
#include "msm_vfe40.h"
+atomic_t irq_cnt;
+
+#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)))
+
+static uint32_t vfe_clk_rate;
+static void vfe40_send_isp_msg(struct v4l2_subdev *sd,
+ uint32_t vfeFrameId, uint32_t isp_msg_id);
+
+
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 struct vfe40_cmd_type vfe40_cmd[] = {
+ [1] = {VFE_CMD_SET_CLK},
+ [2] = {VFE_CMD_RESET},
+ [3] = {VFE_CMD_START},
+ [4] = {VFE_CMD_TEST_GEN_START},
+ [5] = {VFE_CMD_OPERATION_CFG, V40_OPERATION_CFG_LEN},
+ [6] = {VFE_CMD_AXI_OUT_CFG, V40_AXI_OUT_LEN, V40_AXI_BUS_CMD_OFF, 0xFF},
+ [7] = {VFE_CMD_CAMIF_CFG, V40_CAMIF_LEN, V40_CAMIF_OFF, 0xFF},
+ [8] = {VFE_CMD_AXI_INPUT_CFG},
+ [9] = {VFE_CMD_BLACK_LEVEL_CFG},
+ [10] = {VFE_CMD_MESH_ROLL_OFF_CFG, V40_MESH_ROLL_OFF_CFG_LEN,
+ V40_MESH_ROLL_OFF_CFG_OFF, 0xFF},
+ [11] = {VFE_CMD_DEMUX_CFG, V40_DEMUX_LEN, V40_DEMUX_OFF, 0xFF},
+ [12] = {VFE_CMD_FOV_CFG},
+ [13] = {VFE_CMD_MAIN_SCALER_CFG},
+ [14] = {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},
+ [16] = {VFE_CMD_RGB_G_CFG, V40_RGB_G_LEN, V40_RGB_G_OFF, 0xFF},
+ [17] = {VFE_CMD_LA_CFG, V40_LA_LEN, V40_LA_OFF, 0xFF },
+ [18] = {VFE_CMD_CHROMA_EN_CFG, V40_CHROMA_EN_LEN, V40_CHROMA_EN_OFF,
+ 0xFF},
+ [19] = {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},
+ [21] = {VFE_CMD_SK_ENHAN_CFG, V40_SCE_LEN, V40_SCE_OFF, 0xFF},
+ [22] = {VFE_CMD_ASF_CFG, V40_ASF_LEN, V40_ASF_OFF, 0xFF},
+ [23] = {VFE_CMD_S2Y_CFG},
+ [24] = {VFE_CMD_S2CbCr_CFG},
+ [25] = {VFE_CMD_CHROMA_SUBS_CFG},
+ [26] = {VFE_CMD_OUT_CLAMP_CFG, V40_OUT_CLAMP_LEN, V40_OUT_CLAMP_OFF,
+ 0xFF},
+ [27] = {VFE_CMD_FRAME_SKIP_CFG},
+ [31] = {VFE_CMD_UPDATE},
+ [32] = {VFE_CMD_BL_LVL_UPDATE},
+ [33] = {VFE_CMD_DEMUX_UPDATE, V40_DEMUX_LEN, V40_DEMUX_OFF, 0xFF},
+ [34] = {VFE_CMD_FOV_UPDATE},
+ [35] = {VFE_CMD_MAIN_SCALER_UPDATE},
+ [36] = {VFE_CMD_WB_UPDATE, V40_WB_LEN, V40_WB_OFF, 0xFF},
+ [37] = {VFE_CMD_COLOR_COR_UPDATE, V40_COLOR_COR_LEN,
+ V40_COLOR_COR_OFF, 0xFF},
+ [38] = {VFE_CMD_RGB_G_UPDATE, V40_RGB_G_LEN, V40_CHROMA_EN_OFF, 0xFF},
+ [39] = {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},
+ [41] = {VFE_CMD_CHROMA_SUP_UPDATE, V40_CHROMA_SUP_LEN,
+ V40_CHROMA_SUP_OFF, 0xFF},
+ [42] = {VFE_CMD_MCE_UPDATE, V40_MCE_LEN, V40_MCE_OFF, 0xFF},
+ [43] = {VFE_CMD_SK_ENHAN_UPDATE, V40_SCE_LEN, V40_SCE_OFF, 0xFF},
+ [44] = {VFE_CMD_S2CbCr_UPDATE},
+ [45] = {VFE_CMD_S2Y_UPDATE},
+ [46] = {VFE_CMD_ASF_UPDATE, V40_ASF_UPDATE_LEN, V40_ASF_OFF, 0xFF},
+ [47] = {VFE_CMD_FRAME_SKIP_UPDATE},
+ [48] = {VFE_CMD_CAMIF_FRAME_UPDATE},
+ [49] = {VFE_CMD_STATS_AF_UPDATE},
+ [50] = {VFE_CMD_STATS_AE_UPDATE},
+ [51] = {VFE_CMD_STATS_AWB_UPDATE, V40_STATS_AWB_LEN,
+ V40_STATS_AWB_OFF},
+ [52] = {VFE_CMD_STATS_RS_UPDATE, V40_STATS_RS_LEN, V40_STATS_RS_OFF},
+ [53] = {VFE_CMD_STATS_CS_UPDATE, V40_STATS_CS_LEN, V40_STATS_CS_OFF},
+ [54] = {VFE_CMD_STATS_SKIN_UPDATE},
+ [55] = {VFE_CMD_STATS_IHIST_UPDATE, V40_STATS_IHIST_LEN,
+ V40_STATS_IHIST_OFF},
+ [57] = {VFE_CMD_EPOCH1_ACK},
+ [58] = {VFE_CMD_EPOCH2_ACK},
+ [59] = {VFE_CMD_START_RECORDING},
+ [60] = {VFE_CMD_STOP_RECORDING},
+ [63] = {VFE_CMD_CAPTURE, V40_CAPTURE_LEN, 0xFF},
+ [65] = {VFE_CMD_STOP},
+ [66] = {VFE_CMD_GET_HW_VERSION, V40_GET_HW_VERSION_LEN,
+ V40_GET_HW_VERSION_OFF},
+ [67] = {VFE_CMD_GET_FRAME_SKIP_COUNTS},
+ [68] = {VFE_CMD_OUTPUT1_BUFFER_ENQ},
+ [69] = {VFE_CMD_OUTPUT2_BUFFER_ENQ},
+ [70] = {VFE_CMD_OUTPUT3_BUFFER_ENQ},
+ [71] = {VFE_CMD_JPEG_OUT_BUF_ENQ},
+ [72] = {VFE_CMD_RAW_OUT_BUF_ENQ},
+ [73] = {VFE_CMD_RAW_IN_BUF_ENQ},
+ [74] = {VFE_CMD_STATS_AF_ENQ},
+ [75] = {VFE_CMD_STATS_AE_ENQ},
+ [76] = {VFE_CMD_STATS_AWB_ENQ},
+ [77] = {VFE_CMD_STATS_RS_ENQ},
+ [78] = {VFE_CMD_STATS_CS_ENQ},
+ [79] = {VFE_CMD_STATS_SKIN_ENQ},
+ [80] = {VFE_CMD_STATS_IHIST_ENQ},
+ [82] = {VFE_CMD_JPEG_ENC_CFG},
+ [84] = {VFE_CMD_STATS_AF_START},
+ [85] = {VFE_CMD_STATS_AF_STOP},
+ [86] = {VFE_CMD_STATS_AE_START},
+ [87] = {VFE_CMD_STATS_AE_STOP},
+ [88] = {VFE_CMD_STATS_AWB_START, V40_STATS_AWB_LEN, V40_STATS_AWB_OFF},
+ [89] = {VFE_CMD_STATS_AWB_STOP},
+ [90] = {VFE_CMD_STATS_RS_START, V40_STATS_RS_LEN, V40_STATS_RS_OFF},
+ [91] = {VFE_CMD_STATS_RS_STOP},
+ [92] = {VFE_CMD_STATS_CS_START, V40_STATS_CS_LEN, V40_STATS_CS_OFF},
+ [93] = {VFE_CMD_STATS_CS_STOP},
+ [94] = {VFE_CMD_STATS_SKIN_START},
+ [95] = {VFE_CMD_STATS_SKIN_STOP},
+ [96] = {VFE_CMD_STATS_IHIST_START,
+ V40_STATS_IHIST_LEN, V40_STATS_IHIST_OFF},
+ [97] = {VFE_CMD_STATS_IHIST_STOP},
+ [99] = {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},
+ [101] = {VFE_CMD_LIVESHOT},
+ [102] = {VFE_CMD_LA_SETUP},
+ [103] = {VFE_CMD_LINEARIZATION_CFG, V40_LINEARIZATION_LEN1,
+ V40_LINEARIZATION_OFF1},
+ [104] = {VFE_CMD_DEMOSAICV3},
+ [105] = {VFE_CMD_DEMOSAICV3_ABCC_CFG},
+ [106] = {VFE_CMD_DEMOSAICV3_DBCC_CFG, V40_DEMOSAICV3_DBCC_LEN,
+ V40_DEMOSAICV3_DBCC_OFF},
+ [107] = {VFE_CMD_DEMOSAICV3_DBPC_CFG},
+ [108] = {VFE_CMD_DEMOSAICV3_ABF_CFG, V40_DEMOSAICV3_ABF_LEN,
+ V40_DEMOSAICV3_ABF_OFF},
+ [109] = {VFE_CMD_DEMOSAICV3_ABCC_UPDATE},
+ [110] = {VFE_CMD_DEMOSAICV3_DBCC_UPDATE, V40_DEMOSAICV3_DBCC_LEN,
+ V40_DEMOSAICV3_DBCC_OFF},
+ [111] = {VFE_CMD_DEMOSAICV3_DBPC_UPDATE},
+ [112] = {VFE_CMD_XBAR_CFG},
+ [113] = {VFE_CMD_MODULE_CFG, V40_MODULE_CFG_LEN, V40_MODULE_CFG_OFF},
+ [114] = {VFE_CMD_ZSL},
+ [115] = {VFE_CMD_LINEARIZATION_UPDATE, V40_LINEARIZATION_LEN1,
+ V40_LINEARIZATION_OFF1},
+ [116] = {VFE_CMD_DEMOSAICV3_ABF_UPDATE, V40_DEMOSAICV3_ABF_LEN,
+ V40_DEMOSAICV3_ABF_OFF},
+ [117] = {VFE_CMD_CLF_CFG, V40_CLF_CFG_LEN, V40_CLF_CFG_OFF},
+ [118] = {VFE_CMD_CLF_LUMA_UPDATE, V40_CLF_LUMA_UPDATE_LEN,
+ V40_CLF_LUMA_UPDATE_OFF},
+ [119] = {VFE_CMD_CLF_CHROMA_UPDATE, V40_CLF_CHROMA_UPDATE_LEN,
+ V40_CLF_CHROMA_UPDATE_OFF},
+ [120] = {VFE_CMD_PCA_ROLL_OFF_CFG},
+ [121] = {VFE_CMD_PCA_ROLL_OFF_UPDATE},
+ [122] = {VFE_CMD_GET_REG_DUMP},
+ [123] = {VFE_CMD_GET_LINEARIZATON_TABLE},
+ [124] = {VFE_CMD_GET_MESH_ROLLOFF_TABLE},
+ [125] = {VFE_CMD_GET_PCA_ROLLOFF_TABLE},
+ [126] = {VFE_CMD_GET_RGB_G_TABLE},
+ [127] = {VFE_CMD_GET_LA_TABLE},
+ [128] = {VFE_CMD_DEMOSAICV3_UPDATE},
+ [129] = {VFE_CMD_ACTIVE_REGION_CFG},
+ [130] = {VFE_CMD_COLOR_PROCESSING_CONFIG},
+ [131] = {VFE_CMD_STATS_WB_AEC_CONFIG},
+ [132] = {VFE_CMD_STATS_WB_AEC_UPDATE},
+ [133] = {VFE_CMD_Y_GAMMA_CONFIG},
+ [134] = {VFE_CMD_SCALE_OUTPUT1_CONFIG},
+ [135] = {VFE_CMD_SCALE_OUTPUT2_CONFIG},
+ [136] = {VFE_CMD_CAPTURE_RAW},
+ [137] = {VFE_CMD_STOP_LIVESHOT},
+ [138] = {VFE_CMD_RECONFIG_VFE},
+ [139] = {VFE_CMD_STATS_REQBUF},
+ [140] = {VFE_CMD_STATS_ENQUEUEBUF},
+ [141] = {VFE_CMD_STATS_FLUSH_BUFQ},
+ [142] = {VFE_CMD_STATS_UNREGBUF},
+ [143] = {VFE_CMD_STATS_BG_START, V40_STATS_BG_LEN, V40_STATS_BG_OFF},
+ [144] = {VFE_CMD_STATS_BG_STOP},
+ [145] = {VFE_CMD_STATS_BF_START, V40_STATS_BF_LEN, V40_STATS_BF_OFF},
+ [146] = {VFE_CMD_STATS_BF_STOP},
+ [147] = {VFE_CMD_STATS_BHIST_START, V40_STATS_BHIST_LEN,
+ V40_STATS_BHIST_OFF},
+ [148] = {VFE_CMD_STATS_BHIST_STOP},
+ [149] = {VFE_CMD_RESET_2},
+ [150] = {VFE_CMD_FOV_ENC_CFG, V40_FOV_ENC_LEN,
+ V40_FOV_ENC_OFF, 0xFF},
+ [151] = {VFE_CMD_FOV_VIEW_CFG, V40_FOV_VIEW_LEN,
+ V40_FOV_VIEW_OFF, 0xFF},
+ [152] = {VFE_CMD_FOV_ENC_UPDATE, V40_FOV_ENC_LEN,
+ V40_FOV_ENC_OFF, 0xFF},
+ [153] = {VFE_CMD_FOV_VIEW_UPDATE, V40_FOV_VIEW_LEN,
+ V40_FOV_VIEW_OFF, 0xFF},
+ [154] = {VFE_CMD_SCALER_ENC_CFG, V40_SCALER_ENC_LEN,
+ V40_SCALER_ENC_OFF, 0xFF},
+ [155] = {VFE_CMD_SCALER_VIEW_CFG, V40_SCALER_VIEW_LEN,
+ V40_SCALER_VIEW_OFF, 0xFF},
+ [156] = {VFE_CMD_SCALER_ENC_UPDATE, V40_SCALER_ENC_LEN,
+ V40_SCALER_ENC_OFF, 0xFF},
+ [157] = {VFE_CMD_SCALER_VIEW_UPDATE, V40_SCALER_VIEW_LEN,
+ V40_SCALER_VIEW_OFF, 0xFF},
+ [158] = {VFE_CMD_COLORXFORM_ENC_CFG, V40_COLORXFORM_ENC_CFG_LEN,
+ V40_COLORXFORM_ENC_CFG_OFF, 0xFF},
+ [159] = {VFE_CMD_COLORXFORM_VIEW_CFG, V40_COLORXFORM_VIEW_CFG_LEN,
+ V40_COLORXFORM_VIEW_CFG_OFF},
+ [160] = {VFE_CMD_COLORXFORM_ENC_UPDATE, V40_COLORXFORM_ENC_CFG_LEN,
+ V40_COLORXFORM_ENC_CFG_OFF, 0xFF},
+ [161] = {VFE_CMD_COLORXFORM_VIEW_UPDATE, V40_COLORXFORM_VIEW_CFG_LEN,
+ V40_COLORXFORM_VIEW_CFG_OFF, 0xFF},
};
-static void vfe40_stop(struct vfe40_ctrl_type *vfe40_ctrl)
+static const uint32_t vfe40_AXI_WM_CFG[] = {
+ 0x0000006C,
+ 0x00000090,
+ 0x000000B4,
+ 0x000000D8,
+ 0x000000FC,
+ 0x00000120,
+ 0x00000144,
+};
+
+static const char * const vfe40_general_cmd[] = {
+ [1] = "SET_CLK",
+ [2] = "RESET",
+ [3] = "START",
+ [4] = "TEST_GEN_START",
+ [5] = "OPERATION_CFG", /* 5 */
+ [6] = "AXI_OUT_CFG",
+ [7] = "CAMIF_CFG",
+ [8] = "AXI_INPUT_CFG",
+ [9] = "BLACK_LEVEL_CFG",
+ [10] = "ROLL_OFF_CFG", /* 10 */
+ [11] = "DEMUX_CFG",
+ [12] = "FOV_CFG",
+ [13] = "MAIN_SCALER_CFG",
+ [14] = "WB_CFG",
+ [15] = "COLOR_COR_CFG", /* 15 */
+ [16] = "RGB_G_CFG",
+ [17] = "LA_CFG",
+ [18] = "CHROMA_EN_CFG",
+ [19] = "CHROMA_SUP_CFG",
+ [20] = "MCE_CFG", /* 20 */
+ [21] = "SK_ENHAN_CFG",
+ [22] = "ASF_CFG",
+ [23] = "S2Y_CFG",
+ [24] = "S2CbCr_CFG",
+ [25] = "CHROMA_SUBS_CFG", /* 25 */
+ [26] = "OUT_CLAMP_CFG",
+ [27] = "FRAME_SKIP_CFG",
+ [31] = "UPDATE",
+ [32] = "BL_LVL_UPDATE",
+ [33] = "DEMUX_UPDATE",
+ [34] = "FOV_UPDATE",
+ [35] = "MAIN_SCALER_UPDATE", /* 35 */
+ [36] = "WB_UPDATE",
+ [37] = "COLOR_COR_UPDATE",
+ [38] = "RGB_G_UPDATE",
+ [39] = "LA_UPDATE",
+ [40] = "CHROMA_EN_UPDATE", /* 40 */
+ [41] = "CHROMA_SUP_UPDATE",
+ [42] = "MCE_UPDATE",
+ [43] = "SK_ENHAN_UPDATE",
+ [44] = "S2CbCr_UPDATE",
+ [45] = "S2Y_UPDATE", /* 45 */
+ [46] = "ASF_UPDATE",
+ [47] = "FRAME_SKIP_UPDATE",
+ [48] = "CAMIF_FRAME_UPDATE",
+ [49] = "STATS_AF_UPDATE",
+ [50] = "STATS_AE_UPDATE", /* 50 */
+ [51] = "STATS_AWB_UPDATE",
+ [52] = "STATS_RS_UPDATE",
+ [53] = "STATS_CS_UPDATE",
+ [54] = "STATS_SKIN_UPDATE",
+ [55] = "STATS_IHIST_UPDATE", /* 55 */
+ [57] = "EPOCH1_ACK",
+ [58] = "EPOCH2_ACK",
+ [59] = "START_RECORDING",
+ [60] = "STOP_RECORDING", /* 60 */
+ [63] = "CAPTURE",
+ [65] = "STOP", /* 65 */
+ [66] = "GET_HW_VERSION",
+ [67] = "GET_FRAME_SKIP_COUNTS",
+ [68] = "OUTPUT1_BUFFER_ENQ",
+ [69] = "OUTPUT2_BUFFER_ENQ",
+ [70] = "OUTPUT3_BUFFER_ENQ", /* 70 */
+ [71] = "JPEG_OUT_BUF_ENQ",
+ [72] = "RAW_OUT_BUF_ENQ",
+ [73] = "RAW_IN_BUF_ENQ",
+ [74] = "STATS_AF_ENQ",
+ [75] = "STATS_AE_ENQ", /* 75 */
+ [76] = "STATS_AWB_ENQ",
+ [77] = "STATS_RS_ENQ",
+ [78] = "STATS_CS_ENQ",
+ [79] = "STATS_SKIN_ENQ",
+ [80] = "STATS_IHIST_ENQ", /* 80 */
+ [82] = "JPEG_ENC_CFG",
+ [84] = "STATS_AF_START",
+ [85] = "STATS_AF_STOP", /* 85 */
+ [86] = "STATS_AE_START",
+ [87] = "STATS_AE_STOP",
+ [88] = "STATS_AWB_START",
+ [89] = "STATS_AWB_STOP",
+ [90] = "STATS_RS_START", /* 90 */
+ [91] = "STATS_RS_STOP",
+ [92] = "STATS_CS_START",
+ [93] = "STATS_CS_STOP",
+ [94] = "STATS_SKIN_START",
+ [95] = "STATS_SKIN_STOP", /* 95 */
+ [96] = "STATS_IHIST_START",
+ [97] = "STATS_IHIST_STOP",
+ [99] = "SYNC_TIMER_SETTING",
+ [100] = "ASYNC_TIMER_SETTING", /* 100 */
+ [101] = "LIVESHOT",
+ [102] = "LA_SETUP",
+ [103] = "LINEARIZATION_CFG",
+ [104] = "DEMOSAICV3",
+ [105] = "DEMOSAICV3_ABCC_CFG", /* 105 */
+ [106] = "DEMOSAICV3_DBCC_CFG",
+ [107] = "DEMOSAICV3_DBPC_CFG",
+ [108] = "DEMOSAICV3_ABF_CFG",
+ [109] = "DEMOSAICV3_ABCC_UPDATE",
+ [110] = "DEMOSAICV3_DBCC_UPDATE", /* 110 */
+ [111] = "DEMOSAICV3_DBPC_UPDATE",
+ [112] = "XBAR_CFG",
+ [113] = "EZTUNE_CFG",
+ [114] = "V40_ZSL",
+ [115] = "LINEARIZATION_UPDATE", /*115*/
+ [116] = "DEMOSAICV3_ABF_UPDATE",
+ [117] = "CLF_CFG",
+ [118] = "CLF_LUMA_UPDATE",
+ [119] = "CLF_CHROMA_UPDATE",
+ [120] = "PCA_ROLL_OFF_CFG", /*120*/
+ [121] = "PCA_ROLL_OFF_UPDATE",
+ [122] = "GET_REG_DUMP",
+ [123] = "GET_LINEARIZATON_TABLE",
+ [124] = "GET_MESH_ROLLOFF_TABLE",
+ [125] = "GET_PCA_ROLLOFF_TABLE", /*125*/
+ [126] = "GET_RGB_G_TABLE",
+ [127] = "GET_LA_TABLE",
+ [128] = "DEMOSAICV3_UPDATE",
+ [139] = "STATS_REQBUF",
+ [140] = "STATS_ENQUEUEBUF", /*140*/
+ [141] = "STATS_FLUSH_BUFQ",
+ [142] = "STATS_UNREGBUF",
+ [143] = "STATS_BG_START",
+ [144] = "STATS_BG_STOP",
+ [145] = "STATS_BF_START", /*145*/
+ [146] = "STATS_BF_STOP",
+ [147] = "STATS_BHIST_START",
+ [148] = "STATS_BHIST_STOP",
+ [149] = "RESET_2",
+};
+
+/*Temporary use fixed bus vectors in VFE */
+static struct msm_bus_vectors vfe_init_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_VFE,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 0,
+ .ib = 0,
+ },
+};
+
+static struct msm_bus_vectors vfe_preview_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_VFE,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 27648000,
+ .ib = 110592000,
+ },
+};
+
+static struct msm_bus_vectors vfe_video_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_VFE,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 154275840,
+ .ib = 617103360,
+ },
+};
+
+static struct msm_bus_vectors vfe_snapshot_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_VFE,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 274423680,
+ .ib = 1097694720,
+ },
+};
+
+static struct msm_bus_vectors vfe_zsl_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_VFE,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 302071680,
+ .ib = 1208286720,
+ },
+};
+
+static struct msm_bus_paths vfe_bus_client_config[] = {
+ {
+ ARRAY_SIZE(vfe_init_vectors),
+ vfe_init_vectors,
+ },
+ {
+ ARRAY_SIZE(vfe_preview_vectors),
+ vfe_preview_vectors,
+ },
+ {
+ ARRAY_SIZE(vfe_video_vectors),
+ vfe_video_vectors,
+ },
+ {
+ ARRAY_SIZE(vfe_snapshot_vectors),
+ vfe_snapshot_vectors,
+ },
+ {
+ ARRAY_SIZE(vfe_zsl_vectors),
+ vfe_zsl_vectors,
+ },
+};
+
+static struct msm_bus_scale_pdata vfe_bus_client_pdata = {
+ vfe_bus_client_config,
+ ARRAY_SIZE(vfe_bus_client_config),
+ .name = "msm_camera_vfe",
+};
+
+uint8_t vfe40_use_bayer_stats(struct vfe40_ctrl_type *vfe40_ctrl)
{
- unsigned long flags;
+ if (vfe40_ctrl->ver_num.main >= 4) {
+ /* VFE 4 or above uses bayer stats */
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
- atomic_set(&vfe40_ctrl->share_ctrl->vstate, 0);
+static void axi_enable_irq(struct vfe_share_ctrl_t *share_ctrl)
+{
+ uint32_t irq_mask;
+ uint16_t vfe_operation_mode =
+ share_ctrl->current_mode & ~(VFE_OUTPUTS_RDI0|
+ VFE_OUTPUTS_RDI1);
+ irq_mask =
+ msm_camera_io_r(share_ctrl->vfebase +
+ VFE_IRQ_MASK_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);
+ irq_mask |= VFE_IMASK_WHILE_STOPPING_0;
+
+ if (share_ctrl->current_mode & VFE_OUTPUTS_RDI0)
+ irq_mask |= VFE_IRQ_STATUS0_RDI0_REG_UPDATE_MASK;
+
+ if (share_ctrl->current_mode & VFE_OUTPUTS_RDI1)
+ irq_mask |= VFE_IRQ_STATUS0_RDI1_REG_UPDATE_MASK;
+
+ msm_camera_io_w(irq_mask, share_ctrl->vfebase +
+ VFE_IRQ_MASK_0);
+
+ if (vfe_operation_mode) {
+ irq_mask =
+ msm_camera_io_r(share_ctrl->vfebase +
+ VFE_IRQ_MASK_0);
+ irq_mask |= 0x00000021;
+ if (share_ctrl->stats_comp)
+ irq_mask |= VFE_IRQ_STATUS0_STATS_COMPOSIT_MASK_0;
+ else
+ irq_mask |= 0x00FF0000;
+ msm_camera_io_w(irq_mask, share_ctrl->vfebase +
+ VFE_IRQ_MASK_0);
+ atomic_set(&share_ctrl->vstate, 1);
+ }
+ atomic_set(&share_ctrl->handle_common_irq, 1);
+}
+
+static void axi_disable_irq(struct vfe_share_ctrl_t *share_ctrl)
+{
/* disable all interrupts. */
+
+ uint32_t irq_mask = 0;
+ uint16_t vfe_operation_mode =
+ share_ctrl->current_mode & ~(VFE_OUTPUTS_RDI0|
+ VFE_OUTPUTS_RDI1);
+
+ if (share_ctrl->current_mode & VFE_OUTPUTS_RDI0) {
+ irq_mask =
+ msm_camera_io_r(share_ctrl->vfebase +
+ VFE_IRQ_MASK_0);
+ irq_mask &= ~(VFE_IRQ_STATUS0_RDI0_REG_UPDATE_MASK);
+ msm_camera_io_w(irq_mask, share_ctrl->vfebase +
+ VFE_IRQ_MASK_0);
+ msm_camera_io_w(VFE_IRQ_STATUS0_RDI0_REG_UPDATE_MASK,
+ share_ctrl->vfebase + VFE_IRQ_CLEAR_0);
+ }
+ if (share_ctrl->current_mode & VFE_OUTPUTS_RDI1) {
+ irq_mask =
+ msm_camera_io_r(share_ctrl->vfebase +
+ VFE_IRQ_MASK_0);
+ irq_mask &= ~(VFE_IRQ_STATUS0_RDI1_REG_UPDATE_MASK);
+ msm_camera_io_w(irq_mask, share_ctrl->vfebase +
+ VFE_IRQ_MASK_0);
+ msm_camera_io_w(VFE_IRQ_STATUS0_RDI1_REG_UPDATE_MASK,
+ share_ctrl->vfebase + VFE_IRQ_CLEAR_0);
+ }
+ if (vfe_operation_mode) {
+ atomic_set(&share_ctrl->vstate, 0);
+ irq_mask =
+ msm_camera_io_r(share_ctrl->vfebase +
+ VFE_IRQ_MASK_0);
+ irq_mask &= ~(0x00000011);
+ if (share_ctrl->stats_comp)
+ irq_mask &= ~(VFE_IRQ_STATUS0_STATS_COMPOSIT_MASK_0);
+ else
+ irq_mask &= ~0x00FF0000;
+ msm_camera_io_w(irq_mask, share_ctrl->vfebase +
+ VFE_IRQ_MASK_0);
+ }
+
+ if (share_ctrl->axi_ref_cnt == 1) {
+ atomic_set(&share_ctrl->handle_common_irq, 0);
msm_camera_io_w(VFE_DISABLE_ALL_IRQS,
- vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_0);
+ share_ctrl->vfebase + VFE_IRQ_MASK_0);
msm_camera_io_w(VFE_DISABLE_ALL_IRQS,
- vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_1);
+ 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);
+ msm_camera_io_w(0xFFFFFFFF,
+ share_ctrl->vfebase + VFE_IRQ_CLEAR_0);
+ msm_camera_io_w(0xFFFFFFFF,
+ 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);
+ share_ctrl->vfebase + VFE_IRQ_CMD);
+ }
+}
+
+static void vfe40_stop(struct vfe40_ctrl_type *vfe40_ctrl)
+{
/* 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);
+ vfe40_ctrl->share_ctrl->operation_mode &=
+ ~(vfe40_ctrl->share_ctrl->current_mode);
+ vfe40_ctrl->share_ctrl->current_mode = 0;
}
-void vfe40_subdev_notify(int id, int path, int image_mode,
+static void vfe40_subdev_notify(int id, int path, uint32_t inst_handle,
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);
+ CDBG("vfe40_subdev_notify : msgId = %d\n", id);
memset(&rp, 0, sizeof(struct msm_vfe_resp));
rp.evt_msg.type = MSM_CAMERA_MSG;
- frame_info.image_mode = image_mode;
+ frame_info.inst_handle = inst_handle;
frame_info.path = path;
rp.evt_msg.data = &frame_info;
rp.type = id;
@@ -242,45 +613,249 @@
spin_unlock_irqrestore(&share_ctrl->sd_notify_lock, flags);
}
+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;
+ int vfe_mode = (mode & ~(OUTPUT_TERT1|OUTPUT_TERT2));
+
+ /* 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.inst_handle = *ch_info++;
+
+ 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.inst_handle = *ch_info++;
+
+ 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++;
+ axi_ctrl->share_ctrl->outpath.out2.inst_handle = *ch_info++;
+
+ axi_ctrl->share_ctrl->outpath.out3.ch0 = 0x0000FFFF & *ch_info;
+ axi_ctrl->share_ctrl->outpath.out3.ch1 =
+ 0x0000FFFF & (*ch_info++ >> 16);
+ axi_ctrl->share_ctrl->outpath.out3.ch2 = 0x0000FFFF & *ch_info++;
+ axi_ctrl->share_ctrl->outpath.out3.inst_handle = *ch_info++;
+
+ axi_ctrl->share_ctrl->outpath.output_mode = 0;
+
+ if (mode & OUTPUT_TERT1)
+ axi_ctrl->share_ctrl->outpath.output_mode |=
+ VFE40_OUTPUT_MODE_TERTIARY1;
+ if (mode & OUTPUT_TERT2)
+ axi_ctrl->share_ctrl->outpath.output_mode |=
+ VFE40_OUTPUT_MODE_TERTIARY2;
+ if (mode == OUTPUT_TERT1 || mode == OUTPUT_TERT1
+ || mode == (OUTPUT_TERT1|OUTPUT_TERT2))
+ goto bus_cfg;
+
+ switch (vfe_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;
+ }
+
+bus_cfg:
+ msm_camera_io_memcpy(axi_ctrl->share_ctrl->vfebase +
+ vfe40_cmd[VFE_CMD_AXI_OUT_CFG].offset, axi_cfg,
+ V40_AXI_BUS_CFG_LEN);
+ msm_camera_io_w(*ch_info++,
+ axi_ctrl->share_ctrl->vfebase + VFE_RDI0_CFG);
+ msm_camera_io_w(*ch_info++,
+ axi_ctrl->share_ctrl->vfebase + VFE_RDI1_CFG);
+ msm_camera_io_w(*ch_info++,
+ axi_ctrl->share_ctrl->vfebase + VFE_RDI2_CFG);
+ 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);
+
+ 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->handle_common_irq, 0);
+ atomic_set(&axi_ctrl->share_ctrl->pix0_update_ack_pending, 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->comp_output_mode = 0;
+ axi_ctrl->share_ctrl->vfe_capture_count = 0;
+
+ /* this is unsigned 32 bit integer. */
+ axi_ctrl->share_ctrl->vfeFrameId = 0;
+ axi_ctrl->share_ctrl->rdi0FrameId = 0;
+ axi_ctrl->share_ctrl->rdi1FrameId = 0;
+ axi_ctrl->share_ctrl->rdi2FrameId = 0;
+}
+
+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_reset_dmi_tables(
+ struct vfe40_ctrl_type *vfe40_ctrl)
+{
+ int i = 0;
+
+ /* Reset Histogram LUTs */
+ CDBG("Reset Bayer histogram LUT : 0\n");
+ vfe40_program_dmi_cfg(STATS_BHIST_RAM0, vfe40_ctrl);
+ /* Loop for configuring LUT */
+ for (i = 0; i < 256; i++) {
+ msm_camera_io_w(0, vfe40_ctrl->share_ctrl->vfebase +
+ VFE_DMI_DATA_HI);
+ msm_camera_io_w(0, vfe40_ctrl->share_ctrl->vfebase +
+ VFE_DMI_DATA_LO);
+ }
+ vfe40_program_dmi_cfg(NO_MEM_SELECTED, vfe40_ctrl);
+
+ CDBG("Reset Bayer Histogram LUT: 1\n");
+ vfe40_program_dmi_cfg(STATS_BHIST_RAM1, vfe40_ctrl);
+ /* Loop for configuring LUT */
+ for (i = 0; i < 256; i++) {
+ msm_camera_io_w(0, vfe40_ctrl->share_ctrl->vfebase +
+ VFE_DMI_DATA_HI);
+ msm_camera_io_w(0, vfe40_ctrl->share_ctrl->vfebase +
+ VFE_DMI_DATA_LO);
+ }
+ vfe40_program_dmi_cfg(NO_MEM_SELECTED, vfe40_ctrl);
+
+ CDBG("Reset IHistogram LUT\n");
+ vfe40_program_dmi_cfg(STATS_IHIST_RAM, vfe40_ctrl);
+ /* Loop for configuring LUT */
+ for (i = 0; i < 256; i++) {
+ msm_camera_io_w(0, vfe40_ctrl->share_ctrl->vfebase +
+ VFE_DMI_DATA_HI);
+ msm_camera_io_w(0, vfe40_ctrl->share_ctrl->vfebase +
+ VFE_DMI_DATA_LO);
+ }
+ vfe40_program_dmi_cfg(NO_MEM_SELECTED, vfe40_ctrl);
+}
+
+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);
+ msm_camera_io_w(0xFFFFF,
+ vfe40_ctrl->share_ctrl->vfebase + VFE_CGC_OVERRIDE);
+
+ 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 */
+ CDBG("%s: Use bayer stats = %d\n", __func__,
+ vfe40_use_bayer_stats(vfe40_ctrl));
+ msm_camera_io_w(0x350001F,
+ vfe40_ctrl->share_ctrl->vfebase +
+ VFE_BUS_STATS_HIST_WR_UB_CFG);
+ msm_camera_io_w(0x370002F,
+ vfe40_ctrl->share_ctrl->vfebase +
+ VFE_BUS_STATS_BG_WR_UB_CFG);
+ msm_camera_io_w(0x3A0002F,
+ vfe40_ctrl->share_ctrl->vfebase +
+ VFE_BUS_STATS_BF_WR_UB_CFG);
+ msm_camera_io_w(0x3D00007,
+ vfe40_ctrl->share_ctrl->vfebase +
+ VFE_BUS_STATS_RS_WR_UB_CFG);
+ msm_camera_io_w(0x3D8001F,
+ vfe40_ctrl->share_ctrl->vfebase +
+ VFE_BUS_STATS_CS_WR_UB_CFG);
+ msm_camera_io_w(0x3F80007,
+ vfe40_ctrl->share_ctrl->vfebase +
+ VFE_BUS_STATS_SKIN_WR_UB_CFG);
+ vfe40_reset_dmi_tables(vfe40_ctrl);
+}
+
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,
+ memset(&(vfe40_ctrl->afbfStatsControl), 0,
sizeof(struct vfe_stats_control));
memset(&(vfe40_ctrl->awbStatsControl), 0,
sizeof(struct vfe_stats_control));
- memset(&(vfe40_ctrl->aecStatsControl), 0,
+ memset(&(vfe40_ctrl->aecbgStatsControl), 0,
+ sizeof(struct vfe_stats_control));
+
+ memset(&(vfe40_ctrl->bhistStatsControl), 0,
sizeof(struct vfe_stats_control));
memset(&(vfe40_ctrl->ihistStatsControl), 0,
@@ -295,32 +870,59 @@
vfe40_ctrl->frame_skip_cnt = 31;
vfe40_ctrl->frame_skip_pattern = 0xffffffff;
vfe40_ctrl->snapshot_frame_cnt = 0;
+ vfe40_set_default_reg_values(vfe40_ctrl);
}
-static void vfe40_reset(struct vfe40_ctrl_type *vfe40_ctrl)
+static int vfe40_reset(struct vfe40_ctrl_type *vfe40_ctrl)
{
- vfe40_reset_internal_variables(vfe40_ctrl);
+ uint32_t irq_mask;
+ atomic_set(&vfe40_ctrl->share_ctrl->vstate, 0);
+ msm_camera_io_w(VFE_MODULE_RESET_CMD,
+ vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_RESET);
+ msm_camera_io_w(0,
+ vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_RESET);
+
+ irq_mask =
+ msm_camera_io_r(vfe40_ctrl->share_ctrl->vfebase +
+ VFE_IRQ_MASK_0);
+ irq_mask &= ~(0x00FF0011|VFE_IRQ_STATUS0_STATS_COMPOSIT_MASK_0);
+
+ /* enable reset_ack interrupt. */
+ irq_mask |= VFE_IMASK_WHILE_STOPPING_0;
+ msm_camera_io_w(irq_mask, vfe40_ctrl->share_ctrl->vfebase +
+ VFE_IRQ_MASK_0);
+
+ msm_camera_io_w_mb(VFE_ONLY_RESET_CMD,
+ vfe40_ctrl->share_ctrl->vfebase + VFE_GLOBAL_RESET);
+
+ return wait_for_completion_interruptible(
+ &vfe40_ctrl->share_ctrl->reset_complete);
+}
+
+static int axi_reset(struct axi_ctrl_t *axi_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,
- vfe40_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,
- vfe40_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,
- 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);
+ msm_camera_io_w(VFE_CLEAR_ALL_IRQ0,
+ axi_ctrl->share_ctrl->vfebase + VFE_IRQ_CLEAR_0);
+ msm_camera_io_w(VFE_CLEAR_ALL_IRQ1,
+ 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, vfe40_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,
- vfe40_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_1);
+ msm_camera_io_w(VFE_IMASK_WHILE_STOPPING_0,
+ axi_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_0);
/* Write to VFE_GLOBAL_RESET_CMD to reset the vfe hardware. Once reset
* is done, hardware interrupt will be generated. VFE ist processes
@@ -330,24 +932,10 @@
/* 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);
+ axi_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);
+ return wait_for_completion_interruptible(
+ &axi_ctrl->share_ctrl->reset_complete);
}
static int vfe40_operation_config(uint32_t *cmd,
@@ -355,7 +943,6 @@
{
uint32_t *p = cmd;
- vfe40_ctrl->share_ctrl->operation_mode = *p;
vfe40_ctrl->share_ctrl->stats_comp = *(++p);
vfe40_ctrl->hfr_mode = *(++p);
@@ -425,6 +1012,26 @@
return 0L;
}
+
+static unsigned long vfe40_stats_unregbuf(
+ struct vfe40_ctrl_type *vfe40_ctrl,
+ struct msm_stats_reqbuf *req_buf, int domain_num)
+{
+ int i = 0, rc = 0;
+
+ for (i = 0; i < req_buf->num_buf; i++) {
+ rc = vfe40_ctrl->stats_ops.buf_unprepare(
+ vfe40_ctrl->stats_ops.stats_ctrl,
+ req_buf->stats_type, i,
+ vfe40_ctrl->stats_ops.client, domain_num);
+ if (rc < 0) {
+ pr_err("%s: unreg stats buf (type = %d) err = %d",
+ __func__, req_buf->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)
@@ -456,14 +1063,18 @@
return 0;
}
-static int vfe_stats_aec_buf_init(
- struct vfe40_ctrl_type *vfe40_ctrl, struct vfe_cmd_stats_buf *in)
+static uint32_t vfe_stats_aec_bg_buf_init(
+ struct vfe40_ctrl_type *vfe40_ctrl)
{
uint32_t addr;
unsigned long flags;
+ uint32_t stats_type;
+ stats_type =
+ (!vfe40_use_bayer_stats(vfe40_ctrl)) ? MSM_STATS_TYPE_AEC
+ : MSM_STATS_TYPE_BG;
spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
- addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, MSM_STATS_TYPE_AEC);
+ addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, stats_type);
spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
if (!addr) {
pr_err("%s: dq aec ping buf from free buf queue",
@@ -472,9 +1083,9 @@
}
msm_camera_io_w(addr,
vfe40_ctrl->share_ctrl->vfebase +
- VFE_BUS_STATS_AEC_WR_PING_ADDR);
+ VFE_BUS_STATS_BG_WR_PING_ADDR);
spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
- addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, MSM_STATS_TYPE_AEC);
+ addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, stats_type);
spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
if (!addr) {
pr_err("%s: dq aec pong buf from free buf queue",
@@ -483,26 +1094,31 @@
}
msm_camera_io_w(addr,
vfe40_ctrl->share_ctrl->vfebase +
- VFE_BUS_STATS_AEC_WR_PONG_ADDR);
+ VFE_BUS_STATS_BG_WR_PONG_ADDR);
return 0;
}
-static int vfe_stats_af_buf_init(
- struct vfe40_ctrl_type *vfe40_ctrl, struct vfe_cmd_stats_buf *in)
+static int vfe_stats_af_bf_buf_init(
+ struct vfe40_ctrl_type *vfe40_ctrl)
{
uint32_t addr;
unsigned long flags;
int rc = 0;
+ uint32_t stats_type;
+ stats_type =
+ (!vfe40_use_bayer_stats(vfe40_ctrl)) ? MSM_STATS_TYPE_AF
+ : MSM_STATS_TYPE_BF;
+
spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
- rc = vfe40_stats_flush_enqueue(vfe40_ctrl, MSM_STATS_TYPE_AF);
+ rc = vfe40_stats_flush_enqueue(vfe40_ctrl, stats_type);
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);
+ addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, stats_type);
spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
if (!addr) {
pr_err("%s: dq af ping buf from free buf queue", __func__);
@@ -510,9 +1126,9 @@
}
msm_camera_io_w(addr,
vfe40_ctrl->share_ctrl->vfebase +
- VFE_BUS_STATS_AF_WR_PING_ADDR);
+ VFE_BUS_STATS_BF_WR_PING_ADDR);
spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
- addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, MSM_STATS_TYPE_AF);
+ addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, stats_type);
spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
if (!addr) {
pr_err("%s: dq af pong buf from free buf queue", __func__);
@@ -520,13 +1136,44 @@
}
msm_camera_io_w(addr,
vfe40_ctrl->share_ctrl->vfebase +
- VFE_BUS_STATS_AF_WR_PONG_ADDR);
+ VFE_BUS_STATS_BF_WR_PONG_ADDR);
+ return 0;
+}
+
+static uint32_t vfe_stats_bhist_buf_init(
+ struct vfe40_ctrl_type *vfe40_ctrl)
+{
+ 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_BHIST);
+ 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_SKIN_WR_PING_ADDR);
+ spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, MSM_STATS_TYPE_BHIST);
+ 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_SKIN_WR_PONG_ADDR);
return 0;
}
static int vfe_stats_ihist_buf_init(
- struct vfe40_ctrl_type *vfe40_ctrl, struct vfe_cmd_stats_buf *in)
+ struct vfe40_ctrl_type *vfe40_ctrl)
{
uint32_t addr;
unsigned long flags;
@@ -558,7 +1205,7 @@
}
static int vfe_stats_rs_buf_init(
- struct vfe40_ctrl_type *vfe40_ctrl, struct vfe_cmd_stats_buf *in)
+ struct vfe40_ctrl_type *vfe40_ctrl)
{
uint32_t addr;
unsigned long flags;
@@ -587,7 +1234,7 @@
}
static int vfe_stats_cs_buf_init(
- struct vfe40_ctrl_type *vfe40_ctrl, struct vfe_cmd_stats_buf *in)
+ struct vfe40_ctrl_type *vfe40_ctrl)
{
uint32_t addr;
unsigned long flags;
@@ -614,39 +1261,45 @@
return 0;
}
+static void vfe40_cfg_qos_parms(struct vfe40_ctrl_type *vfe40_ctrl)
+{
+ void __iomem *vfebase = vfe40_ctrl->share_ctrl->vfebase;
+ msm_camera_io_w(0xAAAAAAAA, vfebase + VFE_0_BUS_BDG_QOS_CFG_0);
+ msm_camera_io_w(0xAAAAAAAA, vfebase + VFE_0_BUS_BDG_QOS_CFG_1);
+ msm_camera_io_w(0xAAAAAAAA, vfebase + VFE_0_BUS_BDG_QOS_CFG_2);
+ msm_camera_io_w(0xAAAAAAAA, vfebase + VFE_0_BUS_BDG_QOS_CFG_3);
+ msm_camera_io_w(0xAAAAAAAA, vfebase + VFE_0_BUS_BDG_QOS_CFG_4);
+ msm_camera_io_w(0xAAAAAAAA, vfebase + VFE_0_BUS_BDG_QOS_CFG_5);
+ msm_camera_io_w(0xAAAAAAAA, vfebase + VFE_0_BUS_BDG_QOS_CFG_6);
+ msm_camera_io_w(0x0002AAAA, vfebase + VFE_0_BUS_BDG_QOS_CFG_7);
+}
+
static void vfe40_start_common(struct vfe40_ctrl_type *vfe40_ctrl)
{
- uint32_t irq_mask = 0x1E000011;
- vfe40_ctrl->start_ack_pending = TRUE;
+ uint16_t vfe_operation_mode =
+ vfe40_ctrl->share_ctrl->current_mode & ~(VFE_OUTPUTS_RDI0|
+ VFE_OUTPUTS_RDI1);
CDBG("VFE opertaion mode = 0x%x, output mode = 0x%x\n",
- vfe40_ctrl->share_ctrl->operation_mode,
+ vfe40_ctrl->share_ctrl->current_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);
+ vfe40_cfg_qos_parms(vfe40_ctrl);
- /* 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_w_mb(0x1,
+ vfe40_ctrl->share_ctrl->vfebase +
+ VFE_REG_UPDATE_CMD);
- msm_camera_io_dump(vfe40_ctrl->share_ctrl->vfebase,
- vfe40_ctrl->share_ctrl->register_total*4);
-
- atomic_set(&vfe40_ctrl->share_ctrl->vstate, 1);
+ if (vfe_operation_mode) {
+ msm_camera_io_w_mb(1, vfe40_ctrl->share_ctrl->vfebase +
+ VFE_CAMIF_COMMAND);
+ }
}
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;
+ vfe40_ctrl->share_ctrl->recording_state = VFE_STATE_START_REQUESTED;
msm_camera_io_w_mb(1,
vfe40_ctrl->share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
return 0;
@@ -656,11 +1309,9 @@
struct msm_cam_media_controller *pmctl,
struct vfe40_ctrl_type *vfe40_ctrl)
{
- vfe40_ctrl->recording_state = VFE_STATE_STOP_REQUESTED;
+ vfe40_ctrl->share_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;
}
@@ -678,97 +1329,21 @@
share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
}
+static void vfe40_stop_liveshot(
+ struct msm_cam_media_controller *pmctl,
+ struct vfe40_ctrl_type *vfe40_ctrl)
+{
+ 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);
+}
+
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_ctrl->share_ctrl->start_ack_pending = TRUE;
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);
@@ -779,28 +1354,8 @@
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;
}
@@ -810,75 +1365,24 @@
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 ==
+ if (vfe40_ctrl->share_ctrl->current_mode ==
VFE_OUTPUTS_MAIN_AND_THUMB ||
- vfe40_ctrl->share_ctrl->operation_mode ==
+ vfe40_ctrl->share_ctrl->current_mode ==
VFE_OUTPUTS_THUMB_AND_MAIN ||
- vfe40_ctrl->share_ctrl->operation_mode ==
+ vfe40_ctrl->share_ctrl->current_mode ==
VFE_OUTPUTS_JPEG_AND_THUMB ||
- vfe40_ctrl->share_ctrl->operation_mode ==
+ vfe40_ctrl->share_ctrl->current_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);
@@ -890,41 +1394,6 @@
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;
}
@@ -967,9 +1436,9 @@
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);
+ spin_lock_irqsave(&vfe40_ctrl->share_ctrl->update_ack_lock, flags);
+ vfe40_ctrl->share_ctrl->update_ack_pending = TRUE;
+ spin_unlock_irqrestore(&vfe40_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,
@@ -1031,7 +1500,7 @@
8 + ((vfe40_ctrl->sync_timer_number) * 12));
/* Sync Timer Pixel Duration */
value = *tbl++;
- val = vfe40_ctrl->share_ctrl->vfe_clk_rate / 10000;
+ val = vfe_clk_rate / 10000;
val = 10000000 / val;
val = value * 10000 / val;
CDBG("%s: Pixel Clk Cycles!!! %d\n", __func__, val);
@@ -1048,19 +1517,7 @@
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,
@@ -1119,7 +1576,7 @@
vfe40_program_dmi_cfg(NO_MEM_SELECTED, vfe40_ctrl);
}
-struct vfe40_output_ch *vfe40_get_ch(
+static struct vfe40_output_ch *vfe40_get_ch(
int path, struct vfe_share_ctrl_t *share_ctrl)
{
struct vfe40_output_ch *ch = NULL;
@@ -1128,6 +1585,10 @@
ch = &share_ctrl->outpath.out0;
else if (path == VFE_MSG_OUTPUT_SECONDARY)
ch = &share_ctrl->outpath.out1;
+ else if (path == VFE_MSG_OUTPUT_TERTIARY1)
+ ch = &share_ctrl->outpath.out2;
+ else if (path == VFE_MSG_OUTPUT_TERTIARY2)
+ ch = &share_ctrl->outpath.out3;
else
pr_err("%s: Invalid path %d\n", __func__,
path);
@@ -1135,49 +1596,76 @@
BUG_ON(ch == NULL);
return ch;
}
+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 inst_handle = 0;
-static int vfe40_configure_pingpong_buffers(
- int id, int path, struct vfe40_ctrl_type *vfe40_ctrl)
+ if (path == VFE_MSG_OUTPUT_PRIMARY)
+ inst_handle = axi_ctrl->share_ctrl->outpath.out0.inst_handle;
+ else if (path == VFE_MSG_OUTPUT_SECONDARY)
+ inst_handle = axi_ctrl->share_ctrl->outpath.out1.inst_handle;
+ else if (path == VFE_MSG_OUTPUT_TERTIARY1)
+ inst_handle = axi_ctrl->share_ctrl->outpath.out2.inst_handle;
+ else if (path == VFE_MSG_OUTPUT_TERTIARY2)
+ inst_handle = axi_ctrl->share_ctrl->outpath.out3.inst_handle;
+
+ vfe40_subdev_notify(id, path, inst_handle,
+ &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 int configure_pingpong_buffers(
+ int id, int path, struct axi_ctrl_t *axi_ctrl)
{
struct vfe40_output_ch *outch = NULL;
int rc = 0;
- uint32_t image_mode = 0;
+ uint32_t inst_handle = 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;
+ inst_handle = axi_ctrl->share_ctrl->outpath.out0.inst_handle;
+ else if (path == VFE_MSG_OUTPUT_SECONDARY)
+ inst_handle = axi_ctrl->share_ctrl->outpath.out1.inst_handle;
+ else if (path == VFE_MSG_OUTPUT_TERTIARY1)
+ inst_handle = axi_ctrl->share_ctrl->outpath.out2.inst_handle;
+ else if (path == VFE_MSG_OUTPUT_TERTIARY2)
+ inst_handle = axi_ctrl->share_ctrl->outpath.out3.inst_handle;
- vfe40_subdev_notify(id, path, image_mode,
- &vfe40_ctrl->subdev, vfe40_ctrl->share_ctrl);
- outch = vfe40_get_ch(path, vfe40_ctrl->share_ctrl);
+ vfe40_subdev_notify(id, path, inst_handle,
+ &axi_ctrl->subdev, axi_ctrl->share_ctrl);
+ outch = vfe40_get_ch(path, axi_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",
+ pr_info("%s Configure ping/pong address for %d",
__func__, path);
vfe40_put_ch_ping_addr(
- vfe40_ctrl->share_ctrl->vfebase, outch->ch0,
+ axi_ctrl->share_ctrl->vfebase, outch->ch0,
outch->ping.ch_paddr[0]);
vfe40_put_ch_pong_addr(
- vfe40_ctrl->share_ctrl->vfebase, outch->ch0,
+ axi_ctrl->share_ctrl->vfebase, outch->ch0,
outch->pong.ch_paddr[0]);
- if (vfe40_ctrl->share_ctrl->operation_mode !=
- VFE_OUTPUTS_RAW) {
+ if ((axi_ctrl->share_ctrl->current_mode !=
+ VFE_OUTPUTS_RAW) && (path != VFE_MSG_OUTPUT_TERTIARY1)
+ && (path != VFE_MSG_OUTPUT_TERTIARY2)) {
vfe40_put_ch_ping_addr(
- vfe40_ctrl->share_ctrl->vfebase, outch->ch1,
+ axi_ctrl->share_ctrl->vfebase, outch->ch1,
outch->ping.ch_paddr[1]);
vfe40_put_ch_pong_addr(
- vfe40_ctrl->share_ctrl->vfebase, outch->ch1,
+ axi_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,
+ axi_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,
+ axi_ctrl->share_ctrl->vfebase, outch->ch2,
outch->pong.ch_paddr[2]);
/* avoid stale info */
@@ -1207,7 +1695,7 @@
vfe40_program_dmi_cfg(NO_MEM_SELECTED, vfe40_ctrl);
}
-void vfe40_send_isp_msg(
+static void vfe40_send_isp_msg(
struct v4l2_subdev *sd,
uint32_t vfeFrameId,
uint32_t isp_msg_id)
@@ -1227,142 +1715,76 @@
struct vfe40_ctrl_type *vfe40_ctrl)
{
int i , rc = 0;
- uint32_t old_val = 0 , new_val = 0;
+ uint32_t old_val = 0 , new_val = 0, module_val = 0;
uint32_t *cmdp = NULL;
uint32_t *cmdp_local = NULL;
uint32_t snapshot_cnt = 0;
uint32_t temp1 = 0, temp2 = 0;
+ struct msm_camera_vfe_params_t vfe_params;
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",
+ pr_info("vfe40_proc_general: cmdID = %s\n",
vfe40_general_cmd[cmd->id]);
+ vfe40_ctrl->share_ctrl->vfe_reset_flag = true;
vfe40_reset(vfe40_ctrl);
break;
case VFE_CMD_START:
- CDBG("vfe40_proc_general: cmdID = %s\n",
+ pr_info("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;
+ if (copy_from_user(&vfe_params,
+ (void __user *)(cmd->value),
+ sizeof(struct msm_camera_vfe_params_t))) {
+ rc = -EFAULT;
+ goto proc_general_done;
}
+ vfe40_ctrl->share_ctrl->current_mode =
+ vfe_params.operation_mode;
+
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;
+ pr_info("%s: cmdID = VFE_CMD_CAPTURE_RAW\n", __func__);
+ if (copy_from_user(&vfe_params,
+ (void __user *)(cmd->value),
+ sizeof(struct msm_camera_vfe_params_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;
- }
+
+ snapshot_cnt = vfe_params.capture_count;
+ vfe40_ctrl->share_ctrl->current_mode =
+ vfe_params.operation_mode;
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;
+ pr_info("%s: cmdID = VFE_CMD_CAPTURE\n", __func__);
+ if (copy_from_user(&vfe_params,
+ (void __user *)(cmd->value),
+ sizeof(struct msm_camera_vfe_params_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;
- }
+ snapshot_cnt = vfe_params.capture_count;
+ vfe40_ctrl->share_ctrl->current_mode =
+ vfe_params.operation_mode;
+
rc = vfe40_capture(pmctl, snapshot_cnt, vfe40_ctrl);
break;
case VFE_CMD_START_RECORDING:
- CDBG("vfe40_proc_general: cmdID = %s\n",
+ pr_info("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",
+ pr_info("vfe40_proc_general: cmdID = %s\n",
vfe40_general_cmd[cmd->id]);
rc = vfe40_stop_recording(pmctl, vfe40_ctrl);
break;
@@ -1383,7 +1805,12 @@
break;
case VFE_CMD_STATS_AE_START: {
- rc = vfe_stats_aec_buf_init(vfe40_ctrl, NULL);
+ if (vfe40_use_bayer_stats(vfe40_ctrl)) {
+ /* Error */
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ rc = vfe_stats_aec_bg_buf_init(vfe40_ctrl);
if (rc < 0) {
pr_err("%s: cannot config ping/pong address of AEC",
__func__);
@@ -1412,7 +1839,12 @@
}
break;
case VFE_CMD_STATS_AF_START: {
- rc = vfe_stats_af_buf_init(vfe40_ctrl, NULL);
+ if (vfe40_use_bayer_stats(vfe40_ctrl)) {
+ /* Error */
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ rc = vfe_stats_af_bf_buf_init(vfe40_ctrl);
if (rc < 0) {
pr_err("%s: cannot config ping/pong address of AF",
__func__);
@@ -1440,8 +1872,12 @@
cmdp, (vfe40_cmd[cmd->id].length));
}
break;
-
case VFE_CMD_STATS_AWB_START: {
+ if (vfe40_use_bayer_stats(vfe40_ctrl)) {
+ /* Error */
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
rc = vfe_stats_awb_buf_init(vfe40_ctrl, NULL);
if (rc < 0) {
pr_err("%s: cannot config ping/pong address of AWB",
@@ -1472,7 +1908,7 @@
break;
case VFE_CMD_STATS_IHIST_START: {
- rc = vfe_stats_ihist_buf_init(vfe40_ctrl, NULL);
+ rc = vfe_stats_ihist_buf_init(vfe40_ctrl);
if (rc < 0) {
pr_err("%s: cannot config ping/pong address of IHIST",
__func__);
@@ -1503,7 +1939,7 @@
case VFE_CMD_STATS_RS_START: {
- rc = vfe_stats_rs_buf_init(vfe40_ctrl, NULL);
+ rc = vfe_stats_rs_buf_init(vfe40_ctrl);
if (rc < 0) {
pr_err("%s: cannot config ping/pong address of RS",
__func__);
@@ -1528,7 +1964,7 @@
break;
case VFE_CMD_STATS_CS_START: {
- rc = vfe_stats_cs_buf_init(vfe40_ctrl, NULL);
+ rc = vfe_stats_cs_buf_init(vfe40_ctrl);
if (rc < 0) {
pr_err("%s: cannot config ping/pong address of CS",
__func__);
@@ -1552,6 +1988,65 @@
}
break;
+ case VFE_CMD_STATS_BG_START:
+ case VFE_CMD_STATS_BF_START:
+ case VFE_CMD_STATS_BHIST_START: {
+ if (!vfe40_use_bayer_stats(vfe40_ctrl)) {
+ /* Error */
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ old_val = msm_camera_io_r(
+ vfe40_ctrl->share_ctrl->vfebase + VFE_STATS_CFG);
+ module_val = msm_camera_io_r(
+ vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
+ if (VFE_CMD_STATS_BG_START == cmd->id) {
+ module_val |= BG_ENABLE_MASK;
+ rc = vfe_stats_aec_bg_buf_init(vfe40_ctrl);
+ if (rc < 0) {
+ pr_err("%s: cannot config ping/pong address of CS",
+ __func__);
+ goto proc_general_done;
+ }
+ } else if (VFE_CMD_STATS_BF_START == cmd->id) {
+ module_val |= BF_ENABLE_MASK;
+ rc = vfe_stats_af_bf_buf_init(vfe40_ctrl);
+ if (rc < 0) {
+ pr_err("%s: cannot config ping/pong address of CS",
+ __func__);
+ goto proc_general_done;
+ }
+ } else {
+ module_val |= BHIST_ENABLE_MASK;
+ old_val |= STATS_BHIST_ENABLE_MASK;
+ rc = vfe_stats_bhist_buf_init(vfe40_ctrl);
+ if (rc < 0) {
+ pr_err("%s: cannot config ping/pong address of CS",
+ __func__);
+ goto proc_general_done;
+ }
+ }
+ msm_camera_io_w(old_val, vfe40_ctrl->share_ctrl->vfebase +
+ VFE_STATS_CFG);
+ msm_camera_io_w(module_val,
+ vfe40_ctrl->share_ctrl->vfebase + VFE_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;
+ }
+ 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);
@@ -1638,6 +2133,38 @@
rc = -EFAULT;
goto proc_general_done;
+ case VFE_CMD_MESH_ROLL_OFF_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, V40_MESH_ROLL_OFF_CFG_LEN);
+ cmdp_local += 9;
+ vfe40_program_dmi_cfg(ROLLOFF_RAM0_BANK0, vfe40_ctrl);
+ /* for loop for extrcting table. */
+ for (i = 0; i < (V40_MESH_ROLL_OFF_TABLE_SIZE * 2); i++) {
+ msm_camera_io_w(*cmdp_local,
+ vfe40_ctrl->share_ctrl->vfebase +
+ VFE_DMI_DATA_LO);
+ cmdp_local++;
+ }
+ CDBG("done writing mesh table\n");
+ vfe40_program_dmi_cfg(NO_MEM_SELECTED, vfe40_ctrl);
+ }
+ break;
+ case VFE_CMD_GET_MESH_ROLLOFF_TABLE:
+ break;
+
case VFE_CMD_LA_CFG:
cmdp = kmalloc(cmd->length, GFP_ATOMIC);
if (!cmdp) {
@@ -1746,15 +2273,6 @@
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;
@@ -1774,7 +2292,6 @@
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);
@@ -2126,6 +2643,11 @@
break;
case VFE_CMD_STATS_AWB_STOP: {
+ if (vfe40_use_bayer_stats(vfe40_ctrl)) {
+ /* Error */
+ 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;
@@ -2133,27 +2655,30 @@
vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
}
break;
-
case VFE_CMD_STATS_AE_STOP: {
+ if (vfe40_use_bayer_stats(vfe40_ctrl)) {
+ /* Error */
+ 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;
+ 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: {
+ if (vfe40_use_bayer_stats(vfe40_ctrl)) {
+ /* Error */
+ 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);
- 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;
@@ -2183,9 +2708,47 @@
vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
}
break;
+
+ case VFE_CMD_STATS_BG_STOP:
+ case VFE_CMD_STATS_BF_STOP:
+ case VFE_CMD_STATS_BHIST_STOP: {
+ if (!vfe40_use_bayer_stats(vfe40_ctrl)) {
+ /* Error */
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ old_val = msm_camera_io_r(
+ vfe40_ctrl->share_ctrl->vfebase + VFE_STATS_CFG);
+
+ if (VFE_CMD_STATS_BHIST_STOP == cmd->id)
+ old_val &= ~STATS_BHIST_ENABLE_MASK;
+
+ msm_camera_io_w(old_val,
+ vfe40_ctrl->share_ctrl->vfebase + VFE_STATS_CFG);
+ if (VFE_CMD_STATS_BF_STOP == cmd->id) {
+ rc = vfe40_stats_flush_enqueue(vfe40_ctrl,
+ MSM_STATS_TYPE_BF);
+ if (rc < 0) {
+ pr_err("%s: dq stats buf err = %d",
+ __func__, rc);
+ return -EINVAL;
+ }
+ }
+ }
+ break;
+
case VFE_CMD_STOP:
- CDBG("vfe40_proc_general: cmdID = %s\n",
+ pr_info("vfe40_proc_general: cmdID = %s\n",
vfe40_general_cmd[cmd->id]);
+ if (copy_from_user(&vfe_params,
+ (void __user *)(cmd->value),
+ sizeof(struct msm_camera_vfe_params_t))) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+
+ vfe40_ctrl->share_ctrl->current_mode =
+ vfe_params.operation_mode;
vfe40_stop(vfe40_ctrl);
break;
@@ -2229,14 +2792,15 @@
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;
+ if (copy_from_user(&vfe_params,
+ (void __user *)(cmd->value),
+ sizeof(struct msm_camera_vfe_params_t))) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+
+ vfe40_ctrl->share_ctrl->current_mode =
+ vfe_params.operation_mode;
rc = vfe40_zsl(pmctl, vfe40_ctrl);
break;
@@ -2331,6 +2895,10 @@
*cmdp & VFE_FRAME_SKIP_PERIOD_MASK) + 1;
vfe40_ctrl->frame_skip_pattern = (uint32_t)(*(cmdp + 2));
break;
+ case VFE_CMD_STOP_LIVESHOT:
+ CDBG("%s Stopping liveshot ", __func__);
+ vfe40_stop_liveshot(pmctl, vfe40_ctrl);
+ break;
default:
if (cmd->length != vfe40_cmd[cmd->id].length)
return -EINVAL;
@@ -2389,221 +2957,505 @@
}
+void axi_stop_pix(struct vfe_share_ctrl_t *share_ctrl)
+{
+ uint32_t operation_mode =
+ share_ctrl->current_mode & ~(VFE_OUTPUTS_RDI0|
+ VFE_OUTPUTS_RDI1);
+ uint32_t irq_comp_mask, irq_mask;
+ uint32_t reg_update = 0x1;
+
+ irq_comp_mask =
+ msm_camera_io_r(share_ctrl->vfebase +
+ VFE_IRQ_COMP_MASK);
+ irq_mask = msm_camera_io_r(share_ctrl->vfebase +
+ VFE_IRQ_MASK_0);
+
+ switch (share_ctrl->cmd_type) {
+ case AXI_CMD_PREVIEW: {
+ switch (operation_mode) {
+ case VFE_OUTPUTS_PREVIEW:
+ case VFE_OUTPUTS_PREVIEW_AND_VIDEO:
+ if (share_ctrl->comp_output_mode &
+ VFE40_OUTPUT_MODE_PRIMARY) {
+ msm_camera_io_w(0, share_ctrl->vfebase
+ + vfe40_AXI_WM_CFG[share_ctrl->
+ outpath.out0.ch0]);
+ msm_camera_io_w(0, share_ctrl->vfebase
+ + vfe40_AXI_WM_CFG[share_ctrl->
+ outpath.out0.ch1]);
+ irq_comp_mask &= ~(
+ 0x1 << share_ctrl->outpath.out0.ch0 |
+ 0x1 << share_ctrl->outpath.out0.ch1);
+ share_ctrl->outpath.output_mode |=
+ VFE40_OUTPUT_MODE_PRIMARY;
+ } else if (share_ctrl->comp_output_mode &
+ VFE40_OUTPUT_MODE_PRIMARY_ALL_CHNLS) {
+ msm_camera_io_w(0, share_ctrl->vfebase
+ + vfe40_AXI_WM_CFG[share_ctrl->
+ outpath.out0.ch0]);
+ msm_camera_io_w(0, share_ctrl->vfebase
+ + vfe40_AXI_WM_CFG[share_ctrl->
+ outpath.out0.ch1]);
+ msm_camera_io_w(0, share_ctrl->vfebase
+ + vfe40_AXI_WM_CFG[share_ctrl->
+ outpath.out0.ch2]);
+ irq_comp_mask &= ~(
+ 0x1 << share_ctrl->outpath.out0.ch0 |
+ 0x1 << share_ctrl->outpath.out0.ch1 |
+ 0x1 << share_ctrl->outpath.out0.ch2);
+ share_ctrl->outpath.output_mode |=
+ VFE40_OUTPUT_MODE_PRIMARY_ALL_CHNLS;
+ }
+ irq_mask &= ~VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE0_MASK;
+ break;
+ default:
+ if (share_ctrl->comp_output_mode &
+ VFE40_OUTPUT_MODE_SECONDARY) {
+ msm_camera_io_w(0, share_ctrl->vfebase
+ + vfe40_AXI_WM_CFG[share_ctrl->
+ outpath.out1.ch0]);
+ msm_camera_io_w(0, share_ctrl->vfebase
+ + vfe40_AXI_WM_CFG[share_ctrl->
+ outpath.out1.ch1]);
+ irq_comp_mask &= ~(
+ 0x1 << share_ctrl->outpath.out1.ch0 |
+ 0x1 << share_ctrl->outpath.out1.ch1);
+ share_ctrl->outpath.output_mode |=
+ VFE40_OUTPUT_MODE_SECONDARY;
+ } else if (share_ctrl->comp_output_mode &
+ VFE40_OUTPUT_MODE_SECONDARY_ALL_CHNLS) {
+ msm_camera_io_w(0, share_ctrl->vfebase
+ + vfe40_AXI_WM_CFG[share_ctrl->
+ outpath.out1.ch0]);
+ msm_camera_io_w(0, share_ctrl->vfebase
+ + vfe40_AXI_WM_CFG[share_ctrl->
+ outpath.out1.ch1]);
+ msm_camera_io_w(0, share_ctrl->vfebase
+ + vfe40_AXI_WM_CFG[share_ctrl->
+ outpath.out1.ch2]);
+ irq_comp_mask &= ~(
+ 0x1 << share_ctrl->outpath.out1.ch0 |
+ 0x1 << share_ctrl->outpath.out1.ch1 |
+ 0x1 << share_ctrl->outpath.out1.ch2);
+ share_ctrl->outpath.output_mode |=
+ VFE40_OUTPUT_MODE_SECONDARY_ALL_CHNLS;
+ }
+ irq_mask &= ~VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE1_MASK;
+ break;
+ }
+ }
+ break;
+ default:
+ if (share_ctrl->comp_output_mode &
+ VFE40_OUTPUT_MODE_PRIMARY) {
+ msm_camera_io_w(0, share_ctrl->vfebase +
+ vfe40_AXI_WM_CFG[share_ctrl->
+ outpath.out0.ch0]);
+ msm_camera_io_w(0, share_ctrl->vfebase +
+ vfe40_AXI_WM_CFG[share_ctrl->
+ outpath.out0.ch1]);
+ irq_comp_mask &= ~(
+ 0x1 << share_ctrl->outpath.out0.ch0 |
+ 0x1 << share_ctrl->outpath.out0.ch1);
+ irq_mask &= ~VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE0_MASK;
+ share_ctrl->outpath.output_mode |=
+ VFE40_OUTPUT_MODE_PRIMARY;
+ } else if (share_ctrl->comp_output_mode &
+ VFE40_OUTPUT_MODE_PRIMARY_ALL_CHNLS) {
+ msm_camera_io_w(0, share_ctrl->vfebase +
+ vfe40_AXI_WM_CFG[share_ctrl->
+ outpath.out0.ch0]);
+ msm_camera_io_w(0, share_ctrl->vfebase +
+ vfe40_AXI_WM_CFG[share_ctrl->
+ outpath.out0.ch1]);
+ msm_camera_io_w(0, share_ctrl->vfebase +
+ vfe40_AXI_WM_CFG[share_ctrl->
+ outpath.out0.ch2]);
+ irq_comp_mask &= ~(
+ 0x1 << share_ctrl->outpath.out0.ch0 |
+ 0x1 << share_ctrl->outpath.out0.ch1 |
+ 0x1 << share_ctrl->outpath.out0.ch2);
+ irq_mask &= ~VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE0_MASK;
+ share_ctrl->outpath.output_mode |=
+ VFE40_OUTPUT_MODE_PRIMARY_ALL_CHNLS;
+ }
+
+ if (share_ctrl->comp_output_mode &
+ VFE40_OUTPUT_MODE_SECONDARY) {
+ msm_camera_io_w(0, share_ctrl->vfebase +
+ vfe40_AXI_WM_CFG[share_ctrl->
+ outpath.out1.ch0]);
+ msm_camera_io_w(0, share_ctrl->vfebase +
+ vfe40_AXI_WM_CFG[share_ctrl->outpath.out1.ch1]);
+ irq_comp_mask &= ~(
+ 0x1 << share_ctrl->outpath.out1.ch0 |
+ 0x1 << share_ctrl->outpath.out1.ch1);
+ irq_mask &= ~VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE1_MASK;
+ share_ctrl->outpath.output_mode |=
+ VFE40_OUTPUT_MODE_SECONDARY;
+ } else if (share_ctrl->comp_output_mode &
+ VFE40_OUTPUT_MODE_SECONDARY_ALL_CHNLS) {
+ msm_camera_io_w(0, share_ctrl->vfebase +
+ vfe40_AXI_WM_CFG[share_ctrl->outpath.out1.ch0]);
+ msm_camera_io_w(0, share_ctrl->vfebase +
+ vfe40_AXI_WM_CFG[share_ctrl->outpath.out1.ch1]);
+ msm_camera_io_w(0, share_ctrl->vfebase +
+ vfe40_AXI_WM_CFG[share_ctrl->outpath.out1.ch2]);
+ irq_comp_mask &= ~(
+ 0x1 << share_ctrl->outpath.out1.ch0 |
+ 0x1 << share_ctrl->outpath.out1.ch1 |
+ 0x1 << share_ctrl->outpath.out1.ch2);
+ irq_mask &= ~VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE1_MASK;
+ share_ctrl->outpath.output_mode |=
+ VFE40_OUTPUT_MODE_SECONDARY_ALL_CHNLS;
+ }
+ break;
+ }
+
+ msm_camera_io_w_mb(reg_update,
+ share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+ msm_camera_io_w(irq_comp_mask,
+ share_ctrl->vfebase + VFE_IRQ_COMP_MASK);
+ msm_camera_io_w(irq_mask, share_ctrl->vfebase +
+ VFE_IRQ_MASK_0);
+}
+
+void axi_stop_rdi0(struct vfe_share_ctrl_t *share_ctrl)
+{
+ uint32_t reg_update = 0x2;
+ uint32_t irq_mask;
+ irq_mask = msm_camera_io_r(share_ctrl->vfebase +
+ VFE_IRQ_MASK_0);
+
+ if (share_ctrl->current_mode & VFE_OUTPUTS_RDI0) {
+ msm_camera_io_w(0, share_ctrl->vfebase +
+ vfe40_AXI_WM_CFG[share_ctrl->outpath.out2.ch0]);
+ irq_mask &= ~(0x1 << (share_ctrl->outpath.out2.ch0 +
+ VFE_WM_OFFSET));
+ }
+ msm_camera_io_w_mb(reg_update,
+ share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+ msm_camera_io_w(irq_mask, share_ctrl->vfebase +
+ VFE_IRQ_MASK_0);
+}
+
+void axi_stop_rdi1(struct vfe_share_ctrl_t *share_ctrl)
+{
+ uint32_t reg_update = 0x4;
+ uint32_t irq_mask;
+ irq_mask = msm_camera_io_r(share_ctrl->vfebase +
+ VFE_IRQ_MASK_0);
+
+ if (share_ctrl->current_mode & VFE_OUTPUTS_RDI1) {
+ msm_camera_io_w(1, share_ctrl->vfebase +
+ vfe40_AXI_WM_CFG[share_ctrl->outpath.out3.ch0]);
+ irq_mask &= ~(0x1 << (share_ctrl->outpath.out3.ch0 +
+ VFE_WM_OFFSET));
+ }
+
+ msm_camera_io_w_mb(reg_update,
+ share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+ msm_camera_io_w(irq_mask, share_ctrl->vfebase +
+ VFE_IRQ_MASK_0);
+}
+
+void axi_stop_process(struct vfe_share_ctrl_t *share_ctrl)
+{
+ uint32_t operation_mode =
+ share_ctrl->current_mode & ~(VFE_OUTPUTS_RDI0|
+ VFE_OUTPUTS_RDI1);
+
+ if (share_ctrl->current_mode & VFE_OUTPUTS_RDI0) {
+ axi_stop_rdi0(share_ctrl);
+ share_ctrl->comp_output_mode &= ~VFE40_OUTPUT_MODE_TERTIARY1;
+ }
+ if (share_ctrl->current_mode & VFE_OUTPUTS_RDI1) {
+ axi_stop_rdi1(share_ctrl);
+ share_ctrl->comp_output_mode &= ~VFE40_OUTPUT_MODE_TERTIARY2;
+ }
+ if (operation_mode) {
+ axi_stop_pix(share_ctrl);
+ share_ctrl->comp_output_mode &=
+ ~(share_ctrl->outpath.output_mode);
+ }
+}
+
static void vfe40_process_reg_update_irq(
struct vfe40_ctrl_type *vfe40_ctrl)
{
unsigned long flags;
+ struct vfe_share_ctrl_t *share_ctrl = vfe40_ctrl->share_ctrl;
- if (vfe40_ctrl->recording_state == VFE_STATE_START_REQUESTED) {
- if (vfe40_ctrl->share_ctrl->operation_mode ==
+ if (atomic_cmpxchg(
+ &share_ctrl->pix0_update_ack_pending, 2, 0) == 2) {
+ axi_stop_pix(share_ctrl);
+ msm_camera_io_w_mb(
+ CAMIF_COMMAND_STOP_AT_FRAME_BOUNDARY,
+ share_ctrl->vfebase + VFE_CAMIF_COMMAND);
+ axi_disable_irq(share_ctrl);
+ vfe40_send_isp_msg(&vfe40_ctrl->subdev,
+ share_ctrl->vfeFrameId,
+ MSG_ID_PIX0_UPDATE_ACK);
+ share_ctrl->comp_output_mode &=
+ ~(share_ctrl->outpath.output_mode);
+ share_ctrl->current_mode &=
+ (VFE_OUTPUTS_RDI0|VFE_OUTPUTS_RDI0);
+ } else {
+ if (share_ctrl->recording_state == VFE_STATE_START_REQUESTED) {
+ if (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->
+ msm_camera_io_w(1,
+ share_ctrl->vfebase + vfe40_AXI_WM_CFG[
share_ctrl->outpath.out0.ch0]);
- msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase +
- vfe40_AXI_WM_CFG[vfe40_ctrl->
+ msm_camera_io_w(1,
+ share_ctrl->vfebase + vfe40_AXI_WM_CFG[
share_ctrl->outpath.out0.ch1]);
- } else if (vfe40_ctrl->share_ctrl->operation_mode ==
+ } else if (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->
+ msm_camera_io_w(1,
+ share_ctrl->vfebase + vfe40_AXI_WM_CFG[
share_ctrl->outpath.out1.ch0]);
- msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase +
- vfe40_AXI_WM_CFG[vfe40_ctrl->
+ msm_camera_io_w(1,
+ share_ctrl->vfebase + vfe40_AXI_WM_CFG[
share_ctrl->outpath.out1.ch1]);
}
- vfe40_ctrl->recording_state = VFE_STATE_STARTED;
+ share_ctrl->recording_state = VFE_STATE_STARTED;
msm_camera_io_w_mb(1,
- vfe40_ctrl->share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+ share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
CDBG("start video triggered .\n");
- } else if (vfe40_ctrl->recording_state ==
+ } else if (share_ctrl->recording_state ==
VFE_STATE_STOP_REQUESTED) {
- if (vfe40_ctrl->share_ctrl->operation_mode ==
+ if (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->
+ msm_camera_io_w(0,
+ share_ctrl->vfebase + vfe40_AXI_WM_CFG[
share_ctrl->outpath.out0.ch0]);
- msm_camera_io_w(0, vfe40_ctrl->share_ctrl->vfebase +
- vfe40_AXI_WM_CFG[vfe40_ctrl->
+ msm_camera_io_w(0,
+ share_ctrl->vfebase + vfe40_AXI_WM_CFG[
share_ctrl->outpath.out0.ch1]);
- } else if (vfe40_ctrl->share_ctrl->operation_mode ==
+ } else if (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->
+ msm_camera_io_w(0,
+ share_ctrl->vfebase + vfe40_AXI_WM_CFG[
share_ctrl->outpath.out1.ch0]);
- msm_camera_io_w(0, vfe40_ctrl->share_ctrl->vfebase +
- vfe40_AXI_WM_CFG[vfe40_ctrl->
+ msm_camera_io_w(0,
+ share_ctrl->vfebase + vfe40_AXI_WM_CFG[
share_ctrl->outpath.out1.ch1]);
}
CDBG("stop video triggered .\n");
}
- if (vfe40_ctrl->start_ack_pending == TRUE) {
+ if (atomic_cmpxchg(
+ &share_ctrl->pix0_update_ack_pending, 1, 0) == 1) {
+ share_ctrl->comp_output_mode |=
+ (share_ctrl->outpath.output_mode
+ & ~(VFE40_OUTPUT_MODE_TERTIARY1|
+ VFE40_OUTPUT_MODE_TERTIARY2));
vfe40_send_isp_msg(&vfe40_ctrl->subdev,
- vfe40_ctrl->share_ctrl->vfeFrameId, MSG_ID_START_ACK);
- vfe40_ctrl->start_ack_pending = FALSE;
+ share_ctrl->vfeFrameId, MSG_ID_PIX0_UPDATE_ACK);
+ share_ctrl->current_mode &=
+ (VFE_OUTPUTS_RDI0|VFE_OUTPUTS_RDI0);
} else {
- if (vfe40_ctrl->recording_state ==
- VFE_STATE_STOP_REQUESTED) {
- vfe40_ctrl->recording_state = VFE_STATE_STOPPED;
+ if (share_ctrl->recording_state ==
+ VFE_STATE_STOP_REQUESTED) {
+ 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,
- vfe40_ctrl->share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
- } else if (vfe40_ctrl->recording_state ==
+ msm_camera_io_w_mb(1, share_ctrl->vfebase +
+ VFE_REG_UPDATE_CMD);
+ } else if (share_ctrl->recording_state ==
VFE_STATE_STOPPED) {
vfe40_send_isp_msg(&vfe40_ctrl->subdev,
- vfe40_ctrl->share_ctrl->vfeFrameId,
+ share_ctrl->vfeFrameId,
MSG_ID_STOP_REC_ACK);
- vfe40_ctrl->recording_state = VFE_STATE_IDLE;
+ share_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_lock_irqsave(&share_ctrl->update_ack_lock, flags);
+ if (share_ctrl->update_ack_pending == TRUE) {
+ share_ctrl->update_ack_pending = FALSE;
spin_unlock_irqrestore(
- &vfe40_ctrl->update_ack_lock, flags);
+ &share_ctrl->update_ack_lock, flags);
vfe40_send_isp_msg(&vfe40_ctrl->subdev,
- vfe40_ctrl->share_ctrl->vfeFrameId,
- MSG_ID_UPDATE_ACK);
+ share_ctrl->vfeFrameId, MSG_ID_UPDATE_ACK);
} else {
spin_unlock_irqrestore(
- &vfe40_ctrl->update_ack_lock, flags);
+ &share_ctrl->update_ack_lock, flags);
}
}
- if (vfe40_ctrl->share_ctrl->liveshot_state ==
- VFE_STATE_START_REQUESTED) {
+ switch (share_ctrl->liveshot_state) {
+ case 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->
+ if (share_ctrl->comp_output_mode &
+ VFE40_OUTPUT_MODE_PRIMARY) {
+ msm_camera_io_w(1, share_ctrl->vfebase +
+ vfe40_AXI_WM_CFG[
share_ctrl->outpath.out0.ch0]);
- msm_camera_io_w(1, vfe40_ctrl->share_ctrl->vfebase +
- vfe40_AXI_WM_CFG[vfe40_ctrl->
+ msm_camera_io_w(1, share_ctrl->vfebase +
+ vfe40_AXI_WM_CFG[
share_ctrl->outpath.out0.ch1]);
- vfe40_ctrl->share_ctrl->liveshot_state =
+
+ 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->
+ break;
+ case VFE_STATE_STARTED:
+ share_ctrl->vfe_capture_count--;
+ if (!share_ctrl->vfe_capture_count &&
+ (share_ctrl->comp_output_mode &
+ VFE40_OUTPUT_MODE_PRIMARY)) {
+ msm_camera_io_w(0, share_ctrl->vfebase +
+ vfe40_AXI_WM_CFG[
share_ctrl->outpath.out0.ch0]);
- msm_camera_io_w(0, vfe40_ctrl->share_ctrl->vfebase +
- vfe40_AXI_WM_CFG[vfe40_ctrl->
+ msm_camera_io_w(0, share_ctrl->vfebase +
+ vfe40_AXI_WM_CFG[
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 +
+ }
+ break;
+ case VFE_STATE_STOP_REQUESTED:
+ if (share_ctrl->comp_output_mode &
+ VFE40_OUTPUT_MODE_PRIMARY) {
+ /* Stop requested, stop write masters, and
+ * trigger REG_UPDATE. Send STOP_LS_ACK in
+ * next reg update. */
+ msm_camera_io_w(0, share_ctrl->vfebase +
+ vfe40_AXI_WM_CFG[
+ share_ctrl->outpath.out0.ch0]);
+ msm_camera_io_w(0, share_ctrl->vfebase +
+ vfe40_AXI_WM_CFG[
+ share_ctrl->outpath.out0.ch1]);
+
+ share_ctrl->liveshot_state = VFE_STATE_STOPPED;
+ msm_camera_io_w_mb(1, 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;
+ break;
+ case VFE_STATE_STOPPED:
+ CDBG("%s Sending STOP_LS ACK\n", __func__);
+ vfe40_send_isp_msg(&vfe40_ctrl->subdev,
+ share_ctrl->vfeFrameId, MSG_ID_STOP_LS_ACK);
+ share_ctrl->liveshot_state = VFE_STATE_IDLE;
+ break;
+ default:
+ break;
}
- 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)) {
+ if ((share_ctrl->operation_mode & VFE_OUTPUTS_THUMB_AND_MAIN) ||
+ (share_ctrl->operation_mode &
+ VFE_OUTPUTS_MAIN_AND_THUMB) ||
+ (share_ctrl->operation_mode &
+ VFE_OUTPUTS_THUMB_AND_JPEG) ||
+ (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--;
+ 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
+ if (share_ctrl->vfe_capture_count == 0) {
+ /* stop the bus output: */
+ if (share_ctrl->comp_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&
+ msm_camera_io_w(0,
+ share_ctrl->vfebase+
+ vfe40_AXI_WM_CFG[
+ share_ctrl->
+ outpath.out0.ch0]);
+ msm_camera_io_w(0,
+ share_ctrl->vfebase+
+ vfe40_AXI_WM_CFG[
+ share_ctrl->
+ outpath.out0.ch1]);
+ }
+ if (share_ctrl->comp_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(0,
+ share_ctrl->vfebase+
+ vfe40_AXI_WM_CFG[
+ share_ctrl->
+ outpath.out1.ch0]);
+ msm_camera_io_w(0,
+ share_ctrl->vfebase+
+ vfe40_AXI_WM_CFG[
+ share_ctrl->
+ outpath.out1.ch1]);
}
msm_camera_io_w_mb
(CAMIF_COMMAND_STOP_AT_FRAME_BOUNDARY,
- vfe40_ctrl->share_ctrl->vfebase +
+ share_ctrl->vfebase +
VFE_CAMIF_COMMAND);
vfe40_ctrl->snapshot_frame_cnt = -1;
vfe40_ctrl->frame_skip_cnt = 31;
- vfe40_ctrl->frame_skip_pattern = 0xffffffff;
+ 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);
+ share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
} /* if snapshot mode. */
}
+}
-static void vfe40_set_default_reg_values(
- struct vfe40_ctrl_type *vfe40_ctrl)
+static void vfe40_process_rdi0_reg_update_irq(
+ 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);
+ if (atomic_cmpxchg(
+ &vfe40_ctrl->share_ctrl->rdi0_update_ack_pending, 2, 0) == 2) {
+ axi_stop_rdi0(vfe40_ctrl->share_ctrl);
+ axi_disable_irq(vfe40_ctrl->share_ctrl);
+ vfe40_send_isp_msg(&vfe40_ctrl->subdev,
+ vfe40_ctrl->share_ctrl->vfeFrameId,
+ MSG_ID_RDI0_UPDATE_ACK);
+ vfe40_ctrl->share_ctrl->comp_output_mode &=
+ ~VFE40_OUTPUT_MODE_TERTIARY1;
+ vfe40_ctrl->share_ctrl->current_mode &=
+ ~(VFE_OUTPUTS_RDI0);
+ }
- /* 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);
+ if (atomic_cmpxchg(
+ &vfe40_ctrl->share_ctrl->rdi0_update_ack_pending, 1, 0) == 1) {
+ vfe40_ctrl->share_ctrl->comp_output_mode |=
+ VFE40_OUTPUT_MODE_TERTIARY1;
+ vfe40_send_isp_msg(&vfe40_ctrl->subdev,
+ vfe40_ctrl->share_ctrl->vfeFrameId,
+ MSG_ID_RDI0_UPDATE_ACK);
+ vfe40_ctrl->share_ctrl->current_mode &=
+ ~(VFE_OUTPUTS_RDI0);
+ }
+}
- /* 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_rdi1_reg_update_irq(
+ struct vfe40_ctrl_type *vfe40_ctrl)
+{
+ if (atomic_cmpxchg(
+ &vfe40_ctrl->share_ctrl->rdi1_update_ack_pending, 2, 0) == 2) {
+ axi_stop_rdi1(vfe40_ctrl->share_ctrl);
+ axi_disable_irq(vfe40_ctrl->share_ctrl);
+ vfe40_send_isp_msg(&vfe40_ctrl->subdev,
+ vfe40_ctrl->share_ctrl->vfeFrameId,
+ MSG_ID_RDI1_UPDATE_ACK);
+ vfe40_ctrl->share_ctrl->comp_output_mode &=
+ ~VFE40_OUTPUT_MODE_TERTIARY2;
+ vfe40_ctrl->share_ctrl->current_mode &=
+ ~(VFE_OUTPUTS_RDI1);
+ }
+
+ if (atomic_cmpxchg(
+ &vfe40_ctrl->share_ctrl->rdi1_update_ack_pending, 1, 0) == 1) {
+ vfe40_ctrl->share_ctrl->comp_output_mode |=
+ VFE40_OUTPUT_MODE_TERTIARY2;
+ vfe40_send_isp_msg(&vfe40_ctrl->subdev,
+ vfe40_ctrl->share_ctrl->vfeFrameId,
+ MSG_ID_RDI1_UPDATE_ACK);
+ vfe40_ctrl->share_ctrl->current_mode &=
+ ~(VFE_OUTPUTS_RDI1);
+ }
}
static void vfe40_process_reset_irq(
@@ -2612,39 +3464,45 @@
unsigned long flags;
atomic_set(&vfe40_ctrl->share_ctrl->vstate, 0);
+ atomic_set(&vfe40_ctrl->share_ctrl->handle_common_irq, 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);
+ if (vfe40_ctrl->share_ctrl->sync_abort)
+ complete(&vfe40_ctrl->share_ctrl->reset_complete);
+ else
vfe40_send_isp_msg(&vfe40_ctrl->subdev,
- vfe40_ctrl->share_ctrl->vfeFrameId, MSG_ID_STOP_ACK);
+ 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);
-
+ vfe40_reset_internal_variables(vfe40_ctrl);
+ if (vfe40_ctrl->share_ctrl->vfe_reset_flag) {
+ vfe40_ctrl->share_ctrl->vfe_reset_flag = false;
+ msm_camera_io_w(0xFF00,
+ vfe40_ctrl->share_ctrl->vfebase + VFE_BUS_CMD);
+ } else {
/* reload all write masters. (frame & line)*/
- msm_camera_io_w(0x7FFF,
+ msm_camera_io_w(0xFF7F,
vfe40_ctrl->share_ctrl->vfebase + VFE_BUS_CMD);
- vfe40_send_isp_msg(&vfe40_ctrl->subdev,
- vfe40_ctrl->share_ctrl->vfeFrameId, MSG_ID_RESET_ACK);
+ }
+ complete(&vfe40_ctrl->share_ctrl->reset_complete);
}
}
static void vfe40_process_camif_sof_irq(
struct vfe40_ctrl_type *vfe40_ctrl)
{
- if (vfe40_ctrl->share_ctrl->operation_mode ==
+ 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;
- }
+ if (vfe40_ctrl->share_ctrl->start_ack_pending)
+ vfe40_ctrl->share_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) {
@@ -2659,11 +3517,15 @@
VFE_MODE_OF_OPERATION_VIDEO) &&
(vfe40_ctrl->share_ctrl->vfeFrameId %
vfe40_ctrl->hfr_mode != 0)) {
- vfe40_ctrl->share_ctrl->vfeFrameId++;
+ if (vfe40_ctrl->vfe_sof_count_enable)
+ vfe40_ctrl->share_ctrl->vfeFrameId++;
CDBG("Skip the SOF notification when HFR enabled\n");
return;
}
- vfe40_ctrl->share_ctrl->vfeFrameId++;
+
+ if (vfe40_ctrl->vfe_sof_count_enable)
+ 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",
@@ -2681,11 +3543,19 @@
struct axi_ctrl_t *axi_ctrl, uint32_t errStatus)
{
uint32_t reg_value;
+ 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_CAMIF_ERROR) {
pr_err("vfe40_irq: camif errors\n");
reg_value = msm_camera_io_r(
axi_ctrl->share_ctrl->vfebase + VFE_CAMIF_STATUS);
+ v4l2_subdev_notify(&axi_ctrl->subdev,
+ NOTIFY_VFE_CAMIF_ERROR, (void *)NULL);
pr_err("camifStatus = 0x%x\n", reg_value);
vfe40_send_isp_msg(&axi_ctrl->subdev,
axi_ctrl->share_ctrl->vfeFrameId, MSG_ID_CAMIF_ERROR);
@@ -2709,12 +3579,34 @@
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_STATS_BE_BUS_OVFL)
+ pr_err("vfe40_irq: be stats bus overflow\n");
+
+ if (errStatus & VFE40_IMASK_STATS_BG_BUS_OVFL)
+ pr_err("vfe40_irq: bg stats bus overflow\n");
+
+ if (errStatus & VFE40_IMASK_STATS_BF_BUS_OVFL)
+ pr_err("vfe40_irq: 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");
+}
+
+static void vfe40_process_common_error_irq(
+ struct axi_ctrl_t *axi_ctrl, uint32_t errStatus)
+{
if (errStatus & VFE40_IMASK_IMG_MAST_0_BUS_OVFL)
pr_err("vfe40_irq: image master 0 bus overflow\n");
@@ -2737,29 +3629,294 @@
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");
+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 inst_handle)
+{
+ struct isp_msg_output msg;
- if (errStatus & VFE40_IMASK_STATS_AWB_BUS_OVFL)
- pr_err("vfe40_irq: awb stats bus overflow\n");
+ msg.output_id = msgid;
+ msg.buf.inst_handle = inst_handle;
+ msg.buf.ch_paddr[0] = ch0_paddr;
+ msg.buf.ch_paddr[1] = ch1_paddr;
+ msg.buf.ch_paddr[2] = ch2_paddr;
+ switch (msgid) {
+ case MSG_ID_OUTPUT_TERTIARY1:
+ msg.frameCounter = axi_ctrl->share_ctrl->rdi0FrameId;
+ break;
+ case MSG_ID_OUTPUT_TERTIARY2:
+ msg.frameCounter = axi_ctrl->share_ctrl->rdi1FrameId;
+ break;
+ default:
+ msg.frameCounter = axi_ctrl->share_ctrl->vfeFrameId;
+ break;
+ }
- if (errStatus & VFE40_IMASK_STATS_RS_BUS_OVFL)
- pr_err("vfe40_irq: rs stats bus overflow\n");
+ v4l2_subdev_notify(&axi_ctrl->subdev,
+ NOTIFY_VFE_MSG_OUT,
+ &msg);
+ return;
+}
- if (errStatus & VFE40_IMASK_STATS_CS_BUS_OVFL)
- pr_err("vfe40_irq: cs stats bus overflow\n");
+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;
- if (errStatus & VFE40_IMASK_STATS_IHIST_BUS_OVFL)
- pr_err("vfe40_irq: ihist stats bus overflow\n");
+ free_buf = vfe40_check_free_buffer(VFE_MSG_OUTPUT_IRQ,
+ VFE_MSG_OUTPUT_PRIMARY, axi_ctrl);
- if (errStatus & VFE40_IMASK_STATS_SKIN_BHIST_BUS_OVFL)
- pr_err("vfe40_irq: skin/bhist stats bus overflow\n");
+ /* 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 (errStatus & VFE40_IMASK_AXI_ERROR)
- pr_err("vfe40_irq: axi error\n");
+ 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.inst_handle);
+
+ } 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.inst_handle);
+
+ } else {
+ axi_ctrl->share_ctrl->outpath.out1.frame_drop_cnt++;
+ CDBG("path_irq_1 - no free buffer!\n");
+ }
+}
+
+static void vfe40_process_output_path_irq_rdi0(
+ struct axi_ctrl_t *axi_ctrl)
+{
+ uint32_t ping_pong;
+ uint32_t ch0_paddr = 0;
+ /* this must be rdi image output. */
+ struct msm_free_buf *free_buf = NULL;
+ /*RDI0*/
+ if (axi_ctrl->share_ctrl->operation_mode & VFE_OUTPUTS_RDI0) {
+ free_buf = vfe40_check_free_buffer(VFE_MSG_OUTPUT_IRQ,
+ VFE_MSG_OUTPUT_TERTIARY1, axi_ctrl);
+ if (free_buf) {
+ ping_pong = msm_camera_io_r(axi_ctrl->
+ share_ctrl->vfebase +
+ VFE_BUS_PING_PONG_STATUS);
+
+ /* Y only channel */
+ ch0_paddr = vfe40_get_ch_addr(ping_pong,
+ axi_ctrl->share_ctrl->vfebase,
+ axi_ctrl->share_ctrl->outpath.out2.ch0);
+
+ pr_debug("%s ch0 = 0x%x\n",
+ __func__, ch0_paddr);
+
+ /* Y channel */
+ vfe40_put_ch_addr(ping_pong,
+ axi_ctrl->share_ctrl->vfebase,
+ axi_ctrl->share_ctrl->outpath.out2.ch0,
+ free_buf->ch_paddr[0]);
+
+ vfe_send_outmsg(axi_ctrl,
+ MSG_ID_OUTPUT_TERTIARY1, ch0_paddr,
+ 0, 0,
+ axi_ctrl->share_ctrl->outpath.out2.inst_handle);
+
+ } else {
+ axi_ctrl->share_ctrl->outpath.out2.frame_drop_cnt++;
+ pr_err("path_irq_2 irq - no free buffer for rdi0!\n");
+ }
+ }
+}
+
+static void vfe40_process_output_path_irq_rdi1(
+ struct axi_ctrl_t *axi_ctrl)
+{
+ uint32_t ping_pong;
+ uint32_t ch0_paddr = 0;
+ /* this must be rdi image output. */
+ struct msm_free_buf *free_buf = NULL;
+ /*RDI1*/
+ if (axi_ctrl->share_ctrl->operation_mode & VFE_OUTPUTS_RDI1) {
+ free_buf = vfe40_check_free_buffer(VFE_MSG_OUTPUT_IRQ,
+ VFE_MSG_OUTPUT_TERTIARY2, axi_ctrl);
+ if (free_buf) {
+ 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.out3.ch0);
+ pr_debug("%s ch0 = 0x%x\n",
+ __func__, ch0_paddr);
+
+ /* Y channel */
+ vfe40_put_ch_addr(ping_pong,
+ axi_ctrl->share_ctrl->vfebase,
+ axi_ctrl->share_ctrl->outpath.out3.ch0,
+ free_buf->ch_paddr[0]);
+
+ vfe_send_outmsg(axi_ctrl,
+ MSG_ID_OUTPUT_TERTIARY2, ch0_paddr,
+ 0, 0,
+ axi_ctrl->share_ctrl->outpath.out3.inst_handle);
+ } else {
+ axi_ctrl->share_ctrl->outpath.out3.frame_drop_cnt++;
+ pr_err("path_irq irq - no free buffer for rdi1!\n");
+ }
+ }
}
static uint32_t vfe40_process_stats_irq_common(
@@ -2786,8 +3943,8 @@
return returnAddr;
}
-static void
-vfe_send_stats_msg(struct vfe40_ctrl_type *vfe40_ctrl,
+static void vfe_send_stats_msg(
+ struct vfe40_ctrl_type *vfe40_ctrl,
uint32_t bufAddress, uint32_t statsNum)
{
int rc = 0;
@@ -2796,24 +3953,36 @@
/* @todo This is causing issues, need further investigate */
/* spin_lock_irqsave(&ctrl->state_lock, flags); */
struct isp_msg_stats msgStats;
+ uint32_t stats_type;
msgStats.frameCounter = vfe40_ctrl->share_ctrl->vfeFrameId;
+ if (vfe40_ctrl->simultaneous_sof_stat)
+ msgStats.frameCounter--;
msgStats.buffer = bufAddress;
-
switch (statsNum) {
case statsAeNum:{
- msgStats.id = MSG_ID_STATS_AEC;
+ msgStats.id =
+ (!vfe40_use_bayer_stats(vfe40_ctrl)) ? MSG_ID_STATS_AEC
+ : MSG_ID_STATS_BG;
+ stats_type =
+ (!vfe40_use_bayer_stats(vfe40_ctrl)) ?
+ MSM_STATS_TYPE_AEC : MSM_STATS_TYPE_BG;
rc = vfe40_ctrl->stats_ops.dispatch(
vfe40_ctrl->stats_ops.stats_ctrl,
- MSM_STATS_TYPE_AEC, bufAddress,
+ stats_type, bufAddress,
&msgStats.buf_idx, &vaddr, &msgStats.fd,
vfe40_ctrl->stats_ops.client);
}
break;
case statsAfNum:{
- msgStats.id = MSG_ID_STATS_AF;
+ msgStats.id =
+ (!vfe40_use_bayer_stats(vfe40_ctrl)) ? MSG_ID_STATS_AF
+ : MSG_ID_STATS_BF;
+ stats_type =
+ (!vfe40_use_bayer_stats(vfe40_ctrl)) ? MSM_STATS_TYPE_AF
+ : MSM_STATS_TYPE_BF;
rc = vfe40_ctrl->stats_ops.dispatch(
vfe40_ctrl->stats_ops.stats_ctrl,
- MSM_STATS_TYPE_AF, bufAddress,
+ stats_type, bufAddress,
&msgStats.buf_idx, &vaddr, &msgStats.fd,
vfe40_ctrl->stats_ops.client);
}
@@ -2855,6 +4024,15 @@
vfe40_ctrl->stats_ops.client);
}
break;
+ case statsSkinNum: {
+ msgStats.id = MSG_ID_STATS_BHIST;
+ rc = vfe40_ctrl->stats_ops.dispatch(
+ vfe40_ctrl->stats_ops.stats_ctrl,
+ MSM_STATS_TYPE_BHIST, bufAddress,
+ &msgStats.buf_idx, &vaddr, &msgStats.fd,
+ vfe40_ctrl->stats_ops.client);
+ }
+ break;
default:
goto stats_done;
@@ -2869,7 +4047,7 @@
__func__, msgStats.id, msgStats.buffer);
}
stats_done:
- spin_unlock_irqrestore(&ctrl->state_lock, flags);
+ /* spin_unlock_irqrestore(&ctrl->state_lock, flags); */
return;
}
@@ -2880,11 +4058,14 @@
uint32_t temp;
msgStats.frame_id = vfe40_ctrl->share_ctrl->vfeFrameId;
+ if (vfe40_ctrl->simultaneous_sof_stat)
+ msgStats.frame_id--;
+
msgStats.status_bits = status_bits;
- msgStats.aec.buff = vfe40_ctrl->aecStatsControl.bufToRender;
+ msgStats.aec.buff = vfe40_ctrl->aecbgStatsControl.bufToRender;
msgStats.awb.buff = vfe40_ctrl->awbStatsControl.bufToRender;
- msgStats.af.buff = vfe40_ctrl->afStatsControl.bufToRender;
+ msgStats.af.buff = vfe40_ctrl->afbfStatsControl.bufToRender;
msgStats.ihist.buff = vfe40_ctrl->ihistStatsControl.bufToRender;
msgStats.rs.buff = vfe40_ctrl->rsStatsControl.bufToRender;
@@ -2899,6 +4080,31 @@
&msgStats);
}
+static void vfe40_process_stats_bg_irq(struct vfe40_ctrl_type *vfe40_ctrl)
+{
+ unsigned long flags;
+ uint32_t addr;
+ uint32_t stats_type;
+ stats_type =
+ (!vfe40_use_bayer_stats(vfe40_ctrl)) ? MSM_STATS_TYPE_AEC
+ : MSM_STATS_TYPE_BG;
+ spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, stats_type);
+ spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
+ if (addr) {
+ vfe40_ctrl->aecbgStatsControl.bufToRender =
+ vfe40_process_stats_irq_common(vfe40_ctrl, statsAeNum,
+ addr);
+
+ vfe_send_stats_msg(vfe40_ctrl,
+ vfe40_ctrl->aecbgStatsControl.bufToRender, statsAeNum);
+ } else{
+ vfe40_ctrl->aecbgStatsControl.droppedStatsFrameCount++;
+ CDBG("%s: droppedStatsFrameCount = %d", __func__,
+ vfe40_ctrl->aecbgStatsControl.droppedStatsFrameCount);
+ }
+}
+
static void vfe40_process_stats_awb_irq(struct vfe40_ctrl_type *vfe40_ctrl)
{
unsigned long flags;
@@ -2920,6 +4126,53 @@
}
}
+static void vfe40_process_stats_bf_irq(struct vfe40_ctrl_type *vfe40_ctrl)
+{
+ unsigned long flags;
+ uint32_t addr;
+ uint32_t stats_type;
+ stats_type =
+ (!vfe40_use_bayer_stats(vfe40_ctrl)) ? MSM_STATS_TYPE_AF
+ : MSM_STATS_TYPE_BF;
+ spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, stats_type);
+ spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
+ if (addr) {
+ vfe40_ctrl->afbfStatsControl.bufToRender =
+ vfe40_process_stats_irq_common(vfe40_ctrl, statsAfNum,
+ addr);
+
+ vfe_send_stats_msg(vfe40_ctrl,
+ vfe40_ctrl->afbfStatsControl.bufToRender, statsAfNum);
+ } else{
+ vfe40_ctrl->afbfStatsControl.droppedStatsFrameCount++;
+ CDBG("%s: droppedStatsFrameCount = %d", __func__,
+ vfe40_ctrl->afbfStatsControl.droppedStatsFrameCount);
+ }
+}
+
+static void vfe40_process_stats_bhist_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_BHIST);
+ spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
+ if (addr) {
+ vfe40_ctrl->bhistStatsControl.bufToRender =
+ vfe40_process_stats_irq_common(vfe40_ctrl,
+ statsSkinNum, addr);
+
+ vfe_send_stats_msg(vfe40_ctrl,
+ vfe40_ctrl->bhistStatsControl.bufToRender,
+ statsSkinNum);
+ } else{
+ vfe40_ctrl->bhistStatsControl.droppedStatsFrameCount++;
+ CDBG("%s: droppedStatsFrameCount = %d", __func__,
+ vfe40_ctrl->bhistStatsControl.droppedStatsFrameCount);
+ }
+}
+
static void vfe40_process_stats_ihist_irq(struct vfe40_ctrl_type *vfe40_ctrl)
{
unsigned long flags;
@@ -2975,8 +4228,9 @@
vfe40_process_stats_irq_common(vfe40_ctrl, statsCsNum,
addr);
- vfe_send_stats_msg(vfe40_ctrl,
- vfe40_ctrl->csStatsControl.bufToRender, statsCsNum);
+ vfe_send_stats_msg(vfe40_ctrl,
+ vfe40_ctrl->csStatsControl.bufToRender,
+ statsCsNum);
} else {
vfe40_ctrl->csStatsControl.droppedStatsFrameCount++;
CDBG("%s: droppedStatsFrameCount = %d", __func__,
@@ -2990,9 +4244,30 @@
unsigned long flags;
int32_t process_stats = false;
uint32_t addr;
+ uint32_t stats_type;
CDBG("%s, stats = 0x%x\n", __func__, status_bits);
spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
+ stats_type =
+ (!vfe40_use_bayer_stats(vfe40_ctrl)) ? MSM_STATS_TYPE_AEC
+ : MSM_STATS_TYPE_BG;
+
+ if (status_bits & VFE_IRQ_STATUS0_STATS_BG) {
+ addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl,
+ stats_type);
+ if (addr) {
+ vfe40_ctrl->aecbgStatsControl.bufToRender =
+ vfe40_process_stats_irq_common(
+ vfe40_ctrl, statsAeNum, addr);
+ process_stats = true;
+ } else{
+ vfe40_ctrl->aecbgStatsControl.bufToRender = 0;
+ vfe40_ctrl->aecbgStatsControl.droppedStatsFrameCount++;
+ }
+ } else {
+ vfe40_ctrl->aecbgStatsControl.bufToRender = 0;
+ }
+
if (status_bits & VFE_IRQ_STATUS0_STATS_AWB) {
addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl,
MSM_STATS_TYPE_AWB);
@@ -3010,6 +4285,26 @@
vfe40_ctrl->awbStatsControl.bufToRender = 0;
}
+ stats_type =
+ (!vfe40_use_bayer_stats(vfe40_ctrl)) ? MSM_STATS_TYPE_AF
+ : MSM_STATS_TYPE_BF;
+ if (status_bits & VFE_IRQ_STATUS0_STATS_BF) {
+ addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl,
+ stats_type);
+ if (addr) {
+ vfe40_ctrl->afbfStatsControl.bufToRender =
+ vfe40_process_stats_irq_common(
+ vfe40_ctrl, statsAfNum,
+ addr);
+ process_stats = true;
+ } else {
+ vfe40_ctrl->afbfStatsControl.bufToRender = 0;
+ vfe40_ctrl->afbfStatsControl.droppedStatsFrameCount++;
+ }
+ } else {
+ vfe40_ctrl->afbfStatsControl.bufToRender = 0;
+ }
+
if (status_bits & VFE_IRQ_STATUS0_STATS_IHIST) {
addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl,
MSM_STATS_TYPE_IHIST);
@@ -3071,7 +4366,6 @@
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)) {
@@ -3101,14 +4395,34 @@
CDBG("irq regUpdateIrq\n");
vfe40_process_reg_update_irq(vfe40_ctrl);
break;
+ case VFE_IRQ_STATUS0_RDI0_REG_UPDATE:
+ CDBG("irq rdi0 regUpdateIrq\n");
+ vfe40_process_rdi0_reg_update_irq(vfe40_ctrl);
+ break;
+ case VFE_IRQ_STATUS0_RDI1_REG_UPDATE:
+ CDBG("irq rdi1 regUpdateIrq\n");
+ vfe40_process_rdi1_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_BG:
+ CDBG("Stats BG irq occured.\n");
+ vfe40_process_stats_bg_irq(vfe40_ctrl);
+ break;
+ case VFE_IRQ_STATUS0_STATS_BF:
+ CDBG("Stats BF irq occured.\n");
+ vfe40_process_stats_bf_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_SKIN_BHIST:
+ CDBG("Stats BHIST irq occured.\n");
+ vfe40_process_stats_bhist_irq(vfe40_ctrl);
+ break;
case VFE_IRQ_STATUS0_STATS_IHIST:
CDBG("Stats IHIST irq occured.\n");
vfe40_process_stats_ihist_irq(vfe40_ctrl);
@@ -3148,15 +4462,17 @@
{
unsigned long flags;
struct axi_ctrl_t *axi_ctrl = (struct axi_ctrl_t *)data;
+ struct vfe40_ctrl_type *vfe40_ctrl = axi_ctrl->share_ctrl->vfe40_ctrl;
struct vfe40_isr_queue_cmd *qcmd = NULL;
+ int stat_interrupt;
CDBG("=== axi40_do_tasklet start ===\n");
- while (atomic_read(&axi_ctrl->share_ctrl->irq_cnt)) {
+ while (atomic_read(&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);
+ atomic_sub(1, &irq_cnt);
if (!qcmd) {
spin_unlock_irqrestore(&axi_ctrl->tasklet_lock,
@@ -3168,38 +4484,82 @@
spin_unlock_irqrestore(&axi_ctrl->tasklet_lock,
flags);
+ if (axi_ctrl->share_ctrl->stats_comp) {
+ stat_interrupt = (qcmd->vfeInterruptStatus0 &
+ VFE_IRQ_STATUS0_STATS_COMPOSIT_MASK_0);
+ } else {
+ stat_interrupt =
+ (qcmd->vfeInterruptStatus0 &
+ VFE_IRQ_STATUS0_STATS_BG) |
+ (qcmd->vfeInterruptStatus0 &
+ VFE_IRQ_STATUS0_STATS_AWB) |
+ (qcmd->vfeInterruptStatus0 &
+ VFE_IRQ_STATUS0_STATS_BF) |
+ (qcmd->vfeInterruptStatus0 &
+ VFE_IRQ_STATUS0_STATS_IHIST) |
+ (qcmd->vfeInterruptStatus0 &
+ VFE_IRQ_STATUS0_STATS_RS) |
+ (qcmd->vfeInterruptStatus0 &
+ VFE_IRQ_STATUS0_STATS_CS);
+ }
if (qcmd->vfeInterruptStatus0 &
- VFE_IRQ_STATUS0_CAMIF_SOF_MASK)
- v4l2_subdev_notify(&axi_ctrl->subdev,
+ VFE_IRQ_STATUS0_CAMIF_SOF_MASK) {
+ if (stat_interrupt)
+ vfe40_ctrl->simultaneous_sof_stat = 1;
+ v4l2_subdev_notify(&vfe40_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,
+ VFE_IRQ_STATUS0_REG_UPDATE_MASK)
+ v4l2_subdev_notify(&vfe40_ctrl->subdev,
NOTIFY_VFE_IRQ,
(void *)VFE_IRQ_STATUS0_REG_UPDATE_MASK);
- }
+
+ if (qcmd->vfeInterruptStatus1 &
+ VFE_IRQ_STATUS0_RDI0_REG_UPDATE_MASK)
+ v4l2_subdev_notify(&vfe40_ctrl->subdev,
+ NOTIFY_VFE_IRQ,
+ (void *)VFE_IRQ_STATUS0_RDI0_REG_UPDATE);
+
+ if (qcmd->vfeInterruptStatus1 &
+ VFE_IRQ_STATUS0_RDI1_REG_UPDATE_MASK)
+ v4l2_subdev_notify(&vfe40_ctrl->subdev,
+ NOTIFY_VFE_IRQ,
+ (void *)VFE_IRQ_STATUS0_RDI1_REG_UPDATE);
if (qcmd->vfeInterruptStatus0 &
VFE_IMASK_WHILE_STOPPING_0)
- v4l2_subdev_notify(&axi_ctrl->subdev,
+ v4l2_subdev_notify(&vfe40_ctrl->subdev,
NOTIFY_VFE_IRQ,
(void *)VFE_IMASK_WHILE_STOPPING_0);
+ if (atomic_read(&axi_ctrl->share_ctrl->handle_common_irq)) {
+ if (qcmd->vfeInterruptStatus1 &
+ VFE40_IMASK_COMMON_ERROR_ONLY_1) {
+ pr_err("irq errorIrq\n");
+ vfe40_process_common_error_irq(
+ axi_ctrl,
+ qcmd->vfeInterruptStatus1 &
+ VFE40_IMASK_COMMON_ERROR_ONLY_1);
+ }
+
+ v4l2_subdev_notify(&axi_ctrl->subdev,
+ NOTIFY_AXI_IRQ,
+ (void *)qcmd->vfeInterruptStatus0);
+ }
+
if (atomic_read(&axi_ctrl->share_ctrl->vstate)) {
if (qcmd->vfeInterruptStatus1 &
- VFE40_IMASK_ERROR_ONLY_1) {
+ VFE40_IMASK_VFE_ERROR_ONLY_1) {
pr_err("irq errorIrq\n");
vfe40_process_error_irq(
axi_ctrl,
qcmd->vfeInterruptStatus1 &
- VFE40_IMASK_ERROR_ONLY_1);
+ VFE40_IMASK_VFE_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) {
@@ -3207,54 +4567,74 @@
if (qcmd->vfeInterruptStatus0 &
VFE_IRQ_STATUS0_STATS_COMPOSIT_MASK_0) {
CDBG("Stats composite irq occured.\n");
- v4l2_subdev_notify(&axi_ctrl->subdev,
+ v4l2_subdev_notify(&vfe40_ctrl->subdev,
NOTIFY_VFE_IRQ,
(void *)qcmd->vfeInterruptStatus0);
}
} else {
/* process individual stats interrupt. */
if (qcmd->vfeInterruptStatus0 &
+ VFE_IRQ_STATUS0_STATS_BG)
+ v4l2_subdev_notify(&vfe40_ctrl->subdev,
+ NOTIFY_VFE_IRQ,
+ (void *)VFE_IRQ_STATUS0_STATS_BG);
+
+ if (qcmd->vfeInterruptStatus0 &
VFE_IRQ_STATUS0_STATS_AWB)
- v4l2_subdev_notify(&axi_ctrl->subdev,
+ v4l2_subdev_notify(&vfe40_ctrl->subdev,
NOTIFY_VFE_IRQ,
(void *)VFE_IRQ_STATUS0_STATS_AWB);
+
+ if (qcmd->vfeInterruptStatus0 &
+ VFE_IRQ_STATUS0_STATS_BF)
+ v4l2_subdev_notify(&vfe40_ctrl->subdev,
+ NOTIFY_VFE_IRQ,
+ (void *)VFE_IRQ_STATUS0_STATS_BF);
+ if (qcmd->vfeInterruptStatus0 &
+ VFE_IRQ_STATUS0_STATS_SKIN_BHIST)
+ v4l2_subdev_notify(&vfe40_ctrl->subdev,
+ NOTIFY_VFE_IRQ,
+ (void *)
+ VFE_IRQ_STATUS0_STATS_SKIN_BHIST);
+
if (qcmd->vfeInterruptStatus0 &
VFE_IRQ_STATUS0_STATS_IHIST)
- v4l2_subdev_notify(&axi_ctrl->subdev,
+ v4l2_subdev_notify(&vfe40_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,
+ v4l2_subdev_notify(&vfe40_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,
+ v4l2_subdev_notify(&vfe40_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,
+ v4l2_subdev_notify(&vfe40_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,
+ v4l2_subdev_notify(&vfe40_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,
+ v4l2_subdev_notify(&vfe40_ctrl->subdev,
NOTIFY_VFE_IRQ,
(void *)VFE_IRQ_STATUS1_SYNC_TIMER2);
}
}
+ vfe40_ctrl->simultaneous_sof_stat = 0;
kfree(qcmd);
}
CDBG("=== axi40_do_tasklet end ===\n");
@@ -3299,12 +4679,22 @@
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);
+ atomic_add(1, &irq_cnt);
spin_unlock_irqrestore(&axi_ctrl->tasklet_lock, flags);
tasklet_schedule(&axi_ctrl->vfe40_tasklet);
return IRQ_HANDLED;
}
+int msm_axi_subdev_isr_routine(struct v4l2_subdev *sd,
+ u32 status, bool *handled)
+{
+ struct axi_ctrl_t *axi_ctrl = v4l2_get_subdevdata(sd);
+ irqreturn_t ret;
+ CDBG("%s E ", __func__);
+ ret = vfe40_parse_irq(axi_ctrl->vfeirq->start, axi_ctrl);
+ *handled = TRUE;
+ return 0;
+}
static long vfe_stats_bufq_sub_ioctl(
struct vfe40_ctrl_type *vfe_ctrl,
@@ -3378,6 +4768,22 @@
vfe_ctrl->stats_ops.client);
}
break;
+ case VFE_CMD_STATS_UNREGBUF:
+ {
+ struct msm_stats_reqbuf *req_buf = NULL;
+ req_buf = (struct msm_stats_reqbuf *)cmd->value;
+ 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 = vfe40_stats_unregbuf(vfe_ctrl, req_buf, domain_num);
+ }
+ break;
default:
rc = -1;
pr_err("%s: cmd_type %d not supported", __func__,
@@ -3396,10 +4802,9 @@
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;
+ struct msm_camvfe_params *vfe_params;
+ struct msm_vfe_cfg_cmd *cmd;
+ void *data;
long rc = 0;
struct vfe_cmd_stats_buf *scfg = NULL;
@@ -3410,6 +4815,17 @@
return -EFAULT;
}
+ CDBG("%s\n", __func__);
+ if (subdev_cmd == VIDIOC_MSM_VFE_INIT) {
+ CDBG("%s init\n", __func__);
+ return msm_vfe_subdev_init(sd);
+ } else if (subdev_cmd == VIDIOC_MSM_VFE_RELEASE) {
+ msm_vfe_subdev_release(sd);
+ return 0;
+ }
+ vfe_params = (struct msm_camvfe_params *)arg;
+ cmd = vfe_params->vfe_cfg;
+ data = vfe_params->data;
switch (cmd->cmd_type) {
case CMD_VFE_PROCESS_IRQ:
vfe40_process_irq(vfe40_ctrl, (uint32_t) data);
@@ -3417,27 +4833,33 @@
case VFE_CMD_STATS_REQBUF:
case VFE_CMD_STATS_ENQUEUEBUF:
case VFE_CMD_STATS_FLUSH_BUFQ:
+ case VFE_CMD_STATS_UNREGBUF:
/* for easy porting put in one envelope */
rc = vfe_stats_bufq_sub_ioctl(vfe40_ctrl,
cmd, vfe_params->data, pmctl->domain_num);
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,
+ 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 &&
+ 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_VFE_PIX_SOF_COUNT_UPDATE &&
+ cmd->cmd_type != CMD_VFE_COUNT_PIX_SOF_ENABLE) {
+ if (copy_from_user(&vfecmd,
(void __user *)(cmd->value),
sizeof(vfecmd))) {
- pr_err("%s %d: copy_from_user failed\n",
- __func__, __LINE__);
- return -EFAULT;
- }
+ 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 &&
@@ -3459,6 +4881,25 @@
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) ||
+ (cmd->cmd_type == CMD_STATS_BG_ENABLE) ||
+ (cmd->cmd_type == CMD_STATS_BF_ENABLE) ||
+ (cmd->cmd_type == CMD_STATS_BHIST_ENABLE)) {
+ struct axidata *axid;
+ axid = data;
+ if (!axid) {
+ rc = -EFAULT;
+ goto vfe40_config_done;
+ }
CDBG("%s: cmdType = %d\n", __func__, cmd->cmd_type);
if ((cmd->cmd_type == CMD_STATS_AF_ENABLE) ||
@@ -3472,39 +4913,69 @@
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;
+ case CMD_STATS_AEC_ENABLE:
+ case CMD_STATS_BG_ENABLE:
+ case CMD_STATS_BF_ENABLE:
+ case CMD_STATS_BHIST_ENABLE:
+ case CMD_STATS_AWB_ENABLE:
+ case CMD_STATS_IHIST_ENABLE:
+ case CMD_STATS_RS_ENABLE:
+ case CMD_STATS_CS_ENABLE:
default:
- pr_err("%s Unsupported AXI configuration %x ", __func__,
- cmd->cmd_type);
- break;
+ pr_err("%s Unsupported cmd type %d",
+ __func__, cmd->cmd_type);
+ break;
}
+ goto vfe40_config_done;
+ }
+ switch (cmd->cmd_type) {
+ case CMD_GENERAL:
+ rc = vfe40_proc_general(pmctl, &vfecmd, vfe40_ctrl);
+ break;
+ case CMD_VFE_COUNT_PIX_SOF_ENABLE: {
+ int enable = *((int *)cmd->value);
+ if (enable)
+ vfe40_ctrl->vfe_sof_count_enable = TRUE;
+ else
+ vfe40_ctrl->vfe_sof_count_enable = false;
+ }
+ break;
+ case CMD_VFE_PIX_SOF_COUNT_UPDATE:
+ if (!vfe40_ctrl->vfe_sof_count_enable)
+ vfe40_ctrl->share_ctrl->vfeFrameId =
+ *((uint32_t *)vfe_params->data);
+ 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);
@@ -3513,6 +4984,39 @@
return rc;
}
+static struct msm_cam_clk_info vfe40_clk_info[] = {
+ {"camss_top_ahb_clk", -1},
+ {"vfe_clk_src", 266670000},
+ {"camss_vfe_vfe_clk", -1},
+ {"camss_csi_vfe_clk", -1},
+ {"iface_clk", -1},
+ {"bus_clk", -1},
+ {"alt_bus_clk", -1},
+};
+
+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[1], freq);
+ if (rc < 0) {
+ pr_err("%s: clk_round_rate failed %d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ vfe_clk_rate = round_rate;
+ rc = clk_set_rate(axi_ctrl->vfe_clk[1], round_rate);
+ if (rc < 0)
+ pr_err("%s: clk_set_rate failed %d\n",
+ __func__, rc);
+
+ return rc;
+}
+
static const struct v4l2_subdev_core_ops msm_vfe_subdev_core_ops = {
.ioctl = msm_vfe_subdev_ioctl,
};
@@ -3521,46 +5025,1088 @@
.core = &msm_vfe_subdev_core_ops,
};
-int msm_vfe_subdev_init(struct v4l2_subdev *sd,
- struct msm_cam_media_controller *mctl)
+static void msm_vfe40_init_vbif_parms(void __iomem *vfe_vbif_base)
+{
+ msm_camera_io_w_mb(0x1,
+ vfe_vbif_base + VFE40_VBIF_CLKON);
+ msm_camera_io_w_mb(0x1,
+ vfe_vbif_base + VFE40_VBIF_ROUND_ROBIN_QOS_ARB);
+ msm_camera_io_w_mb(0xFFFF,
+ vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO_EN);
+ msm_camera_io_w_mb(0xFFFFFFFF,
+ vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO);
+
+ msm_camera_io_w_mb(0x10101010,
+ vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF0);
+ msm_camera_io_w_mb(0x10101010,
+ vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF1);
+ msm_camera_io_w_mb(0x10101010,
+ vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF2);
+ msm_camera_io_w_mb(0x10101010,
+ vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF0);
+ msm_camera_io_w_mb(0x10101010,
+ vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF1);
+ msm_camera_io_w_mb(0x10101010,
+ vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF2);
+ msm_camera_io_w_mb(0x00001010,
+ vfe_vbif_base + VFE40_VBIF_OUT_RD_LIM_CONF0);
+ msm_camera_io_w_mb(0x00001010,
+ vfe_vbif_base + VFE40_VBIF_OUT_WR_LIM_CONF0);
+ msm_camera_io_w_mb(0x00000707,
+ vfe_vbif_base + VFE40_VBIF_DDR_OUT_MAX_BURST);
+ msm_camera_io_w_mb(0x00000030,
+ vfe_vbif_base + VFE40_VBIF_ARB_CTL);
+ msm_camera_io_w_mb(0x04210842,
+ vfe_vbif_base + VFE40_VBIF_DDR_ARB_CONF0);
+ msm_camera_io_w_mb(0x04210842,
+ vfe_vbif_base + VFE40_VBIF_DDR_ARB_CONF1);
+}
+
+int msm_axi_subdev_init(struct v4l2_subdev *sd)
+{
+ int rc = 0;
+ struct axi_ctrl_t *axi_ctrl = v4l2_get_subdevdata(sd);
+ struct msm_cam_media_controller *mctl;
+ mctl = v4l2_get_subdev_hostdata(sd);
+ if (mctl == NULL) {
+ pr_err("%s: mctl is NULL\n", __func__);
+ rc = -EINVAL;
+ goto mctl_failed;
+ }
+ axi_ctrl->share_ctrl->axi_ref_cnt++;
+ if (axi_ctrl->share_ctrl->axi_ref_cnt > 1)
+ return rc;
+
+ 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;
+ }
+
+ axi_ctrl->share_ctrl->vfe_vbif_base =
+ ioremap(axi_ctrl->vfe_vbif_mem->start,
+ resource_size(axi_ctrl->vfe_vbif_mem));
+ if (!axi_ctrl->share_ctrl->vfe_vbif_base) {
+ rc = -ENOMEM;
+ pr_err("%s: vfe ioremap failed\n", __func__);
+ goto remap_failed;
+ }
+
+ if (axi_ctrl->fs_vfe) {
+ rc = regulator_enable(axi_ctrl->fs_vfe);
+ if (rc) {
+ pr_err("%s: Regulator enable failed\n", __func__);
+ 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;
+
+ axi_ctrl->bus_perf_client =
+ msm_bus_scale_register_client(&vfe_bus_client_pdata);
+ if (!axi_ctrl->bus_perf_client) {
+ pr_err("%s: Registration Failed!\n", __func__);
+ axi_ctrl->bus_perf_client = 0;
+ goto bus_scale_register_failed;
+ }
+
+ msm_camera_bus_scale_cfg(axi_ctrl->bus_perf_client, S_PREVIEW);
+
+ rc = iommu_attach_device(mctl->domain, axi_ctrl->iommu_ctx);
+ if (rc < 0) {
+ pr_err("%s: imgwr attach failed rc = %d\n", __func__, rc);
+ rc = -ENODEV;
+ goto device_imgwr_attach_failed;
+ }
+
+ msm_vfe40_init_vbif_parms(axi_ctrl->share_ctrl->vfe_vbif_base);
+
+ axi_ctrl->share_ctrl->register_total = VFE40_REGISTER_TOTAL;
+
+ spin_lock_init(&axi_ctrl->share_ctrl->stop_flag_lock);
+ spin_lock_init(&axi_ctrl->share_ctrl->update_ack_lock);
+ spin_lock_init(&axi_ctrl->share_ctrl->start_ack_lock);
+ init_completion(&axi_ctrl->share_ctrl->reset_complete);
+
+ if (!axi_ctrl->use_irq_router)
+ enable_irq(axi_ctrl->vfeirq->start);
+
+ return rc;
+
+bus_scale_register_failed:
+ msm_cam_clk_enable(&axi_ctrl->pdev->dev, vfe40_clk_info,
+ axi_ctrl->vfe_clk, ARRAY_SIZE(vfe40_clk_info), 0);
+clk_enable_failed:
+ if (axi_ctrl->fs_vfe)
+ regulator_disable(axi_ctrl->fs_vfe);
+fs_failed:
+ iounmap(axi_ctrl->share_ctrl->vfebase);
+ axi_ctrl->share_ctrl->vfebase = NULL;
+remap_failed:
+ iommu_detach_device(mctl->domain, axi_ctrl->iommu_ctx);
+device_imgwr_attach_failed:
+ if (!axi_ctrl->use_irq_router)
+ disable_irq(axi_ctrl->vfeirq->start);
+mctl_failed:
+ return rc;
+}
+
+int msm_vfe_subdev_init(struct v4l2_subdev *sd)
{
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->vfe_sof_count_enable = true;
vfe40_ctrl->hfr_mode = HFR_MODE_OFF;
+ memset(&vfe40_ctrl->stats_ctrl, 0,
+ sizeof(struct msm_stats_bufq_ctrl));
+ memset(&vfe40_ctrl->stats_ops, 0, sizeof(struct msm_stats_ops));
+
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__);
+ axi_ctrl->share_ctrl->axi_ref_cnt--;
+ if (axi_ctrl->share_ctrl->axi_ref_cnt > 0)
+ return;
+ if (!axi_ctrl->use_irq_router)
+ disable_irq(axi_ctrl->vfeirq->start);
+ tasklet_kill(&axi_ctrl->vfe40_tasklet);
+
+ iommu_detach_device(pmctl->domain, axi_ctrl->iommu_ctx);
+
+ 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);
+
+ iounmap(axi_ctrl->share_ctrl->vfebase);
+ iounmap(axi_ctrl->share_ctrl->vfe_vbif_base);
+ axi_ctrl->share_ctrl->vfebase = NULL;
+
+ if (atomic_read(&irq_cnt))
+ pr_warning("%s, Warning IRQ Count not ZERO\n", __func__);
+
+ msm_camera_bus_scale_cfg(axi_ctrl->bus_perf_client, S_EXIT);
+ axi_ctrl->bus_perf_client = 0;
+
+ msm_vfe_subdev_release(&axi_ctrl->share_ctrl->vfe40_ctrl->subdev);
+}
+
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;
+ CDBG("vfe subdev release %p\n",
+ vfe40_ctrl->share_ctrl->vfebase);
}
+void axi_abort(struct axi_ctrl_t *axi_ctrl)
+{
+ uint8_t axi_busy_flag = true;
+ unsigned long flags;
+ /* axi halt command. */
+
+ 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);
+ 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(0x80000000,
+ axi_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_0);
+ msm_camera_io_w(0xF0000000,
+ 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);
+ if (axi_ctrl->share_ctrl->sync_abort)
+ wait_for_completion_interruptible(
+ &axi_ctrl->share_ctrl->reset_complete);
+}
+
+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;
+ uint32_t reg_update = 0;
+ uint16_t operation_mode =
+ (axi_ctrl->share_ctrl->current_mode &
+ ~(VFE_OUTPUTS_RDI0|VFE_OUTPUTS_RDI1));
+ rc = axi_config_buffers(axi_ctrl, vfe_params);
+ if (rc < 0)
+ return;
+
+ switch (vfe_params.cmd_type) {
+ case AXI_CMD_PREVIEW:
+ msm_camera_bus_scale_cfg(axi_ctrl->bus_perf_client, S_PREVIEW);
+ break;
+ case AXI_CMD_CAPTURE:
+ case AXI_CMD_RAW_CAPTURE:
+ msm_camera_bus_scale_cfg(axi_ctrl->bus_perf_client, S_CAPTURE);
+ break;
+ case AXI_CMD_RECORD:
+ msm_camera_bus_scale_cfg(axi_ctrl->bus_perf_client, S_VIDEO);
+ return;
+ case AXI_CMD_ZSL:
+ msm_camera_bus_scale_cfg(axi_ctrl->bus_perf_client, S_ZSL);
+ break;
+ case AXI_CMD_LIVESHOT:
+ msm_camera_bus_scale_cfg(axi_ctrl->bus_perf_client, S_LIVESHOT);
+ return;
+ default:
+ return;
+ }
+
+ irq_comp_mask =
+ msm_camera_io_r(axi_ctrl->share_ctrl->vfebase +
+ VFE_IRQ_COMP_MASK);
+ irq_mask = msm_camera_io_r(axi_ctrl->share_ctrl->vfebase +
+ VFE_IRQ_MASK_0);
+
+ if (axi_ctrl->share_ctrl->outpath.output_mode &
+ VFE40_OUTPUT_MODE_PRIMARY) {
+ irq_comp_mask |= (
+ 0x1 << axi_ctrl->share_ctrl->outpath.out0.ch0 |
+ 0x1 << axi_ctrl->share_ctrl->outpath.out0.ch1);
+ irq_mask |= VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE0_MASK;
+ } else if (axi_ctrl->share_ctrl->outpath.output_mode &
+ VFE40_OUTPUT_MODE_PRIMARY_ALL_CHNLS) {
+ irq_comp_mask |= (
+ 0x1 << axi_ctrl->share_ctrl->outpath.out0.ch0 |
+ 0x1 << axi_ctrl->share_ctrl->outpath.out0.ch1 |
+ 0x1 << axi_ctrl->share_ctrl->outpath.out0.ch2);
+ irq_mask |= VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE0_MASK;
+ }
+ if (axi_ctrl->share_ctrl->outpath.output_mode &
+ VFE40_OUTPUT_MODE_SECONDARY) {
+ irq_comp_mask |= (
+ 0x1 << (axi_ctrl->share_ctrl->outpath.out1.ch0 + 8) |
+ 0x1 << (axi_ctrl->share_ctrl->outpath.out1.ch1 + 8));
+ irq_mask |= VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE1_MASK;
+ } else if (axi_ctrl->share_ctrl->outpath.output_mode &
+ VFE40_OUTPUT_MODE_SECONDARY_ALL_CHNLS) {
+ irq_comp_mask |= (
+ 0x1 << (axi_ctrl->share_ctrl->outpath.out1.ch0 + 8) |
+ 0x1 << (axi_ctrl->share_ctrl->outpath.out1.ch1 + 8) |
+ 0x1 << (axi_ctrl->share_ctrl->outpath.out1.ch2 + 8));
+ irq_mask |= VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE1_MASK;
+ }
+ if (axi_ctrl->share_ctrl->outpath.output_mode &
+ VFE40_OUTPUT_MODE_TERTIARY1) {
+ irq_mask |= (0x1 << (axi_ctrl->share_ctrl->outpath.out2.ch0 +
+ VFE_WM_OFFSET));
+ }
+ if (axi_ctrl->share_ctrl->outpath.output_mode &
+ VFE40_OUTPUT_MODE_TERTIARY2) {
+ irq_mask |= (0x1 << (axi_ctrl->share_ctrl->outpath.out3.ch0 +
+ VFE_WM_OFFSET));
+ }
+
+ msm_camera_io_w(irq_comp_mask,
+ axi_ctrl->share_ctrl->vfebase + VFE_IRQ_COMP_MASK);
+ msm_camera_io_w(irq_mask, axi_ctrl->share_ctrl->vfebase +
+ VFE_IRQ_MASK_0);
+
+ 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 &
+ 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;
+ }
+ }
+ break;
+ default:
+ 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]);
+ }
+
+ 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;
+ }
+ if (axi_ctrl->share_ctrl->current_mode & VFE_OUTPUTS_RDI0)
+ msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase +
+ vfe40_AXI_WM_CFG[axi_ctrl->share_ctrl->
+ outpath.out2.ch0]);
+ if (axi_ctrl->share_ctrl->current_mode & VFE_OUTPUTS_RDI1)
+ msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase +
+ vfe40_AXI_WM_CFG[axi_ctrl->share_ctrl->
+ outpath.out3.ch0]);
+
+ if (axi_ctrl->share_ctrl->current_mode & VFE_OUTPUTS_RDI0) {
+ irq_mask |= VFE_IRQ_STATUS0_RDI0_REG_UPDATE_MASK;
+ if (!atomic_cmpxchg(
+ &axi_ctrl->share_ctrl->rdi0_update_ack_pending,
+ 0, 1))
+ reg_update |= 0x2;
+ }
+ if (axi_ctrl->share_ctrl->current_mode & VFE_OUTPUTS_RDI1) {
+ irq_mask |= VFE_IRQ_STATUS0_RDI1_REG_UPDATE_MASK;
+ if (!atomic_cmpxchg(
+ &axi_ctrl->share_ctrl->rdi1_update_ack_pending,
+ 0, 1))
+ reg_update |= 0x4;
+ }
+ msm_camera_io_w(irq_mask, axi_ctrl->share_ctrl->vfebase +
+ VFE_IRQ_MASK_0);
+ if (operation_mode) {
+ if (!atomic_cmpxchg(
+ &axi_ctrl->share_ctrl->pix0_update_ack_pending,
+ 0, 1))
+ reg_update |= 0x1;
+ }
+
+ msm_camera_io_w_mb(reg_update,
+ axi_ctrl->share_ctrl->vfebase +
+ VFE_REG_UPDATE_CMD);
+ axi_ctrl->share_ctrl->operation_mode |=
+ axi_ctrl->share_ctrl->current_mode;
+ axi_enable_irq(axi_ctrl->share_ctrl);
+}
+
+void axi_stop(struct msm_cam_media_controller *pmctl,
+ struct axi_ctrl_t *axi_ctrl, struct msm_camera_vfe_params_t vfe_params)
+{
+ uint32_t reg_update = 0;
+ 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_camera_bus_scale_cfg(axi_ctrl->bus_perf_client, S_PREVIEW);
+ return;
+ case AXI_CMD_LIVESHOT:
+ msm_camera_bus_scale_cfg(axi_ctrl->bus_perf_client, S_VIDEO);
+ return;
+ default:
+ return;
+ }
+
+ if (axi_ctrl->share_ctrl->stop_immediately) {
+ axi_disable_irq(axi_ctrl->share_ctrl);
+ axi_stop_process(axi_ctrl->share_ctrl);
+ return;
+ }
+
+ if (axi_ctrl->share_ctrl->current_mode & VFE_OUTPUTS_RDI0) {
+ if (!atomic_cmpxchg(
+ &axi_ctrl->share_ctrl->rdi0_update_ack_pending, 0, 2))
+ reg_update |= 0x2;
+ }
+ if (axi_ctrl->share_ctrl->current_mode & VFE_OUTPUTS_RDI1) {
+ if (!atomic_cmpxchg(
+ &axi_ctrl->share_ctrl->rdi1_update_ack_pending, 0, 2))
+ reg_update |= 0x4;
+ }
+ if (operation_mode) {
+ if (!atomic_cmpxchg(
+ &axi_ctrl->share_ctrl->pix0_update_ack_pending, 0, 2))
+ reg_update |= 0x1;
+ }
+ msm_camera_io_w_mb(reg_update,
+ axi_ctrl->share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+}
+
+static int msm_axi_config(struct v4l2_subdev *sd, void __user *arg)
+{
+ 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;
+
+ if (!axi_ctrl->share_ctrl->vfebase) {
+ pr_err("%s: base address unmapped\n", __func__);
+ return -EFAULT;
+ }
+ memset(&cfgcmd, 0, sizeof(struct msm_vfe_cfg_cmd));
+ if (NULL != arg) {
+ if (copy_from_user(&cfgcmd, arg, sizeof(cfgcmd))) {
+ ERR_COPY_FROM_USER();
+ return -EFAULT;
+ }
+ }
+ memset(&vfecmd, 0, sizeof(struct msm_isp_cmd));
+ 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;
+ }
+ }
+
+ vfe_cmd_type = (cfgcmd.cmd_type & ~(CMD_AXI_CFG_TERT1|
+ CMD_AXI_CFG_TERT2));
+ switch (cfgcmd.cmd_type) {
+ case CMD_AXI_CFG_TERT1:{
+ uint32_t *axio = NULL;
+ axio = kmalloc(vfe40_cmd[VFE_CMD_AXI_OUT_CFG].length,
+ GFP_ATOMIC);
+ if (!axio)
+ return -ENOMEM;
+
+ if (copy_from_user(axio, (void __user *)(vfecmd.value),
+ vfe40_cmd[VFE_CMD_AXI_OUT_CFG].length)) {
+ kfree(axio);
+ return -EFAULT;
+ }
+ vfe40_config_axi(axi_ctrl, OUTPUT_TERT1, axio);
+ kfree(axio);
+ return rc;
+ }
+ case CMD_AXI_CFG_TERT2:{
+ uint32_t *axio = NULL;
+ axio = kmalloc(vfe40_cmd[VFE_CMD_AXI_OUT_CFG].length,
+ GFP_ATOMIC);
+ if (!axio)
+ return -ENOMEM;
+
+ if (copy_from_user(axio, (void __user *)(vfecmd.value),
+ vfe40_cmd[VFE_CMD_AXI_OUT_CFG].length)) {
+ kfree(axio);
+ return -EFAULT;
+ }
+ vfe40_config_axi(axi_ctrl, OUTPUT_TERT2, axio);
+ kfree(axio);
+ return rc;
+ }
+ case CMD_AXI_CFG_TERT1|CMD_AXI_CFG_TERT2:{
+ uint32_t *axio = NULL;
+ axio = kmalloc(vfe40_cmd[VFE_CMD_AXI_OUT_CFG].length,
+ GFP_ATOMIC);
+ if (!axio)
+ return -ENOMEM;
+
+ if (copy_from_user(axio, (void __user *)(vfecmd.value),
+ vfe40_cmd[VFE_CMD_AXI_OUT_CFG].length)) {
+ kfree(axio);
+ return -EFAULT;
+ }
+ vfe40_config_axi(axi_ctrl, OUTPUT_TERT1|OUTPUT_TERT2, axio);
+ kfree(axio);
+ return rc;
+ }
+ default:
+ if (cfgcmd.cmd_type & CMD_AXI_CFG_TERT1)
+ rdi_mode |= OUTPUT_TERT1;
+ if (cfgcmd.cmd_type & CMD_AXI_CFG_TERT2)
+ rdi_mode |= OUTPUT_TERT2;
+ }
+ switch (vfe_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, rdi_mode|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, rdi_mode|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,
+ rdi_mode|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,
+ rdi_mode|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,
+ rdi_mode|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: {
+ struct msm_camera_vfe_params_t vfe_params;
+ if (copy_from_user(&vfe_params,
+ (void __user *)(vfecmd.value),
+ sizeof(struct msm_camera_vfe_params_t))) {
+ return -EFAULT;
+ }
+ axi_ctrl->share_ctrl->current_mode =
+ vfe_params.operation_mode;
+ axi_start(pmctl, axi_ctrl, vfe_params);
+ }
+ break;
+ case CMD_AXI_STOP: {
+ struct msm_camera_vfe_params_t vfe_params;
+ if (copy_from_user(&vfe_params,
+ (void __user *)(vfecmd.value),
+ sizeof(struct msm_camera_vfe_params_t))) {
+ return -EFAULT;
+ }
+ axi_ctrl->share_ctrl->current_mode =
+ vfe_params.operation_mode;
+ axi_ctrl->share_ctrl->stop_immediately =
+ vfe_params.stop_immediately;
+ axi_stop(pmctl, axi_ctrl, vfe_params);
+ }
+ break;
+ case CMD_AXI_RESET:
+ axi_reset(axi_ctrl);
+ break;
+ case CMD_AXI_ABORT:
+ if (copy_from_user(&axi_ctrl->share_ctrl->sync_abort,
+ (void __user *)(vfecmd.value),
+ sizeof(uint8_t))) {
+ return -EFAULT;
+ }
+ axi_abort(axi_ctrl);
+ break;
+ default:
+ pr_err("%s Unsupported AXI configuration %x ", __func__,
+ cfgcmd.cmd_type);
+ break;
+ }
+ return rc;
+}
+
+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);
+ }
+
+ if (axi_ctrl->share_ctrl->comp_output_mode &
+ VFE40_OUTPUT_MODE_TERTIARY1)
+ if (irqstatus & (0x1 << (axi_ctrl->share_ctrl->outpath.out2.ch0
+ + VFE_WM_OFFSET)))
+ vfe40_process_output_path_irq_rdi0(axi_ctrl);
+ if (axi_ctrl->share_ctrl->comp_output_mode &
+ VFE40_OUTPUT_MODE_TERTIARY2)
+ if (irqstatus & (0x1 << (axi_ctrl->share_ctrl->outpath.out3.ch0
+ + VFE_WM_OFFSET)))
+ vfe40_process_output_path_irq_rdi1(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);
+ axi_disable_irq(axi_ctrl->share_ctrl);
+ vfe40_send_isp_msg(&axi_ctrl->subdev,
+ axi_ctrl->share_ctrl->vfeFrameId,
+ MSG_ID_PIX0_UPDATE_ACK);
+ 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 const struct v4l2_subdev_internal_ops msm_vfe_internal_ops;
+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);
+ 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;
+ case VIDIOC_MSM_AXI_RDI_COUNT_UPDATE: {
+ struct rdi_count_msg *msg = (struct rdi_count_msg *)arg;
+ struct axi_ctrl_t *axi_ctrl = v4l2_get_subdevdata(sd);
+ switch (msg->rdi_interface) {
+ case RDI_0:
+ axi_ctrl->share_ctrl->rdi0FrameId = msg->count;
+ rc = 0;
+ break;
+ case RDI_1:
+ axi_ctrl->share_ctrl->rdi1FrameId = msg->count;
+ rc = 0;
+ break;
+ case RDI_2:
+ axi_ctrl->share_ctrl->rdi2FrameId = msg->count;
+ rc = 0;
+ break;
+ default:
+ pr_err("%s: Incorrect interface sent\n", __func__);
+ rc = -EINVAL;
+ break;
+ }
+ break;
+ }
+ default:
+ pr_err("%s: command %d not found\n", __func__,
+ _IOC_NR(cmd));
+ break;
+ }
+ return rc;
+}
+
+static const struct v4l2_subdev_core_ops msm_axi_subdev_core_ops = {
+ .ioctl = msm_axi_subdev_ioctl,
+ .interrupt_service_routine = msm_axi_subdev_isr_routine,
+};
+
+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;
+
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 intr_table_entry irq_req;
struct msm_cam_subdev_info sd_info;
CDBG("%s: device id = %d\n", __func__, pdev->id);
@@ -3593,8 +6139,25 @@
share_ctrl->vfe40_ctrl = vfe40_ctrl;
axi_ctrl->share_ctrl = share_ctrl;
vfe40_ctrl->share_ctrl = share_ctrl;
+ axi_ctrl->share_ctrl->axi_ref_cnt = 0;
+ 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);
axi_ctrl->pdev = pdev;
- vfe40_axi_probe(axi_ctrl);
+
+ sd_info.sdev_type = AXI_DEV;
+ sd_info.sd_index = pdev->id;
+ sd_info.irq_num = 0;
+ msm_cam_register_subdev_node(&axi_ctrl->subdev, &sd_info);
+
+ media_entity_init(&axi_ctrl->subdev.entity, 0, NULL, 0);
+ axi_ctrl->subdev.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
+ axi_ctrl->subdev.entity.group_id = AXI_DEV;
+ axi_ctrl->subdev.entity.name = pdev->name;
+ axi_ctrl->subdev.entity.revision = axi_ctrl->subdev.devnode->num;
v4l2_subdev_init(&vfe40_ctrl->subdev, &msm_vfe_subdev_ops);
vfe40_ctrl->subdev.internal_ops = &msm_vfe_internal_ops;
@@ -3611,6 +6174,15 @@
rc = -ENODEV;
goto vfe40_no_resource;
}
+
+ axi_ctrl->vfe_vbif_mem = platform_get_resource_byname(pdev,
+ IORESOURCE_MEM, "vfe_vbif");
+ if (!axi_ctrl->vfe_vbif_mem) {
+ 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) {
@@ -3627,26 +6199,83 @@
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;
+ axi_ctrl->fs_vfe = regulator_get(&pdev->dev, "vdd");
+ if (IS_ERR(axi_ctrl->fs_vfe)) {
+ pr_err("%s: Regulator get failed %ld\n", __func__,
+ PTR_ERR(axi_ctrl->fs_vfe));
+ axi_ctrl->fs_vfe = NULL;
+ }
+
+ /* Register subdev node before requesting irq since
+ * irq_num is needed by msm_cam_server */
+ 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);
+
+ media_entity_init(&vfe40_ctrl->subdev.entity, 0, NULL, 0);
+ vfe40_ctrl->subdev.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
+ vfe40_ctrl->subdev.entity.group_id = VFE_DEV;
+ vfe40_ctrl->subdev.entity.name = pdev->name;
+ vfe40_ctrl->subdev.entity.revision = vfe40_ctrl->subdev.devnode->num;
+
+ /* Request for this device irq from the camera server. If the
+ * IRQ Router is present on this target, the interrupt will be
+ * handled by the camera server and the interrupt service
+ * routine called. If the request_irq call returns ENXIO, then
+ * the IRQ Router hardware is not present on this target. We
+ * have to request for the irq ourselves and register the
+ * appropriate interrupt handler. */
+ axi_ctrl->use_irq_router = true;
+ irq_req.cam_hw_idx = MSM_CAM_HW_VFE0 + pdev->id;
+ irq_req.dev_name = "vfe";
+ irq_req.irq_idx = CAMERA_SS_IRQ_8;
+ irq_req.irq_num = axi_ctrl->vfeirq->start;
+ irq_req.is_composite = 0;
+ irq_req.irq_trigger_type = IRQF_TRIGGER_RISING;
+ irq_req.num_hwcore = 1;
+ irq_req.subdev_list[0] = &axi_ctrl->subdev;
+ irq_req.data = (void *)axi_ctrl;
+ rc = msm_cam_server_request_irq(&irq_req);
+ if (rc == -ENXIO) {
+ /* IRQ Router hardware is not present on this hardware.
+ * Request for the IRQ and register the interrupt handler. */
+ axi_ctrl->use_irq_router = false;
+ 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);
+ } else if (rc < 0) {
+ pr_err("%s Error registering irq ", __func__);
goto vfe40_no_resource;
}
- disable_irq(axi_ctrl->vfeirq->start);
+ /*get device context for IOMMU*/
+ if (pdev->id == 0)
+ axi_ctrl->iommu_ctx = msm_iommu_get_ctx("vfe0");
+ else if (pdev->id == 1)
+ axi_ctrl->iommu_ctx = msm_iommu_get_ctx("vfe1");
+ if (!axi_ctrl->iommu_ctx) {
+ release_mem_region(axi_ctrl->vfemem->start,
+ resource_size(axi_ctrl->vfemem));
+ pr_err("%s: No iommu fw context found\n", __func__);
+ rc = -ENODEV;
+ goto vfe40_no_resource;
+ }
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);
+ /*disable bayer stats by default*/
+ vfe40_ctrl->ver_num.main = 0;
+
return 0;
vfe40_no_resource:
diff --git a/drivers/media/video/msm/vfe/msm_vfe40.h b/drivers/media/video/msm/vfe/msm_vfe40.h
index ab913e2..5b73751 100644
--- a/drivers/media/video/msm/vfe/msm_vfe40.h
+++ b/drivers/media/video/msm/vfe/msm_vfe40.h
@@ -50,7 +50,16 @@
/* 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
+#define VFE_RESET_UPON_RESET_CMD 0x000003ff
+
+/* reset the vfe only when reset command*/
+#define VFE_ONLY_RESET_CMD 0x00000002
+
+/*Vfe module reset command*/
+#define VFE_MODULE_RESET_CMD 0x07ffffff
+
+/* wm bit offset for IRQ MASK and IRQ STATUS register */
+#define VFE_WM_OFFSET 6
/* constants for irq registers */
#define VFE_DISABLE_ALL_IRQS 0
@@ -60,6 +69,9 @@
#define VFE_IRQ_STATUS0_CAMIF_SOF_MASK (0x00000001<<0)
#define VFE_IRQ_STATUS0_REG_UPDATE_MASK (0x00000001<<4)
+#define VFE_IRQ_STATUS0_RDI0_REG_UPDATE_MASK (0x00000001<<5)
+#define VFE_IRQ_STATUS0_RDI1_REG_UPDATE_MASK (0x00000001<<6)
+#define VFE_IRQ_STATUS0_RDI2_REG_UPDATE_MASK (0x00000001<<7)
#define VFE_IRQ_STATUS0_STATS_BE (0x00000001<<16)
#define VFE_IRQ_STATUS0_STATS_BG (0x00000001<<17)
#define VFE_IRQ_STATUS0_STATS_BF (0x00000001<<18)
@@ -84,13 +96,22 @@
#define VFE_IRQ_STATUS1_ASYNC_TIMER2 (0x00000001<<30)
#define VFE_IRQ_STATUS1_ASYNC_TIMER3 (0x00000001<<31)
+/*TODOs the irq status passed from axi to vfe irq handler does not account
+* for 2 irq status registers. So below macro is added to differentiate between
+* same bit set on both irq status registers. This wil be fixed later by passing
+*entire payload to vfe irq handler and parsing there instead of passing just the
+*status bit*/
+
+#define VFE_IRQ_STATUS0_RDI0_REG_UPDATE VFE_IRQ_STATUS0_RDI0_REG_UPDATE_MASK
+#define VFE_IRQ_STATUS0_RDI1_REG_UPDATE VFE_IRQ_STATUS0_RDI1_REG_UPDATE_MASK
+
/* 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
+ * For irq_status_1, bit 28-32 are for async timer. For
+ * irq_status_0, bit 31 for reset irq, bit 23 for axi_halt_ack
irq */
#define VFE_IMASK_WHILE_STOPPING_0 0x80000000
-#define VFE_IMASK_WHILE_STOPPING_1 0x00000100
+#define VFE_IMASK_WHILE_STOPPING_1 0xF0000000
/* For ABF bit 4 is set to zero and other's 1 */
#define ABF_MASK 0xFFFFFFF7
@@ -118,9 +139,12 @@
#define CS_ENABLE_MASK (0x00000001<<10)
#define CLF_ENABLE_MASK (0x00000001<<12)
#define IHIST_ENABLE_MASK (0x00000001<<15)
+#define BHIST_ENABLE_MASK (0x00000001<<18)
#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 STATS_BHIST_ENABLE_MASK (0x00000001<<1)
+
#define VFE_DMI_CFG_DEFAULT 0x00000100
#define HFR_MODE_OFF 1
@@ -175,9 +199,9 @@
#define V40_OPERATION_CFG_LEN 32
-#define V40_AXI_OUT_OFF 0x0000004C
-#define V40_AXI_OUT_LEN 424
-#define V40_AXI_CH_INF_LEN 32
+#define V40_AXI_BUS_CMD_OFF 0x0000004C
+#define V40_AXI_BUS_CFG_LEN 284
+#define V40_AXI_OUT_LEN 344
#define V40_AXI_CFG_LEN 71
#define V40_FOV_ENC_OFF 0x00000854
@@ -213,7 +237,6 @@
#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
@@ -309,29 +332,6 @@
#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;
@@ -704,7 +704,7 @@
struct vfe40_output_ch {
struct list_head free_buf_queue;
spinlock_t free_buf_lock;
- uint16_t image_mode;
+ uint32_t inst_handle;
int8_t ch0;
int8_t ch1;
int8_t ch2;
@@ -719,7 +719,8 @@
#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_COMMON_ERROR_ONLY_1 0x0000FE00
+#define VFE40_IMASK_VFE_ERROR_ONLY_1 0x00FF01FF
#define VFE40_IMASK_CAMIF_ERROR (0x00000001<<0)
#define VFE40_IMASK_BHIST_OVWR (0x00000001<<1)
#define VFE40_IMASK_STATS_CS_OVWR (0x00000001<<2)
@@ -728,21 +729,21 @@
#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 VFE40_IMASK_IMG_MAST_0_BUS_OVFL (0x00000001<<9)
+#define VFE40_IMASK_IMG_MAST_1_BUS_OVFL (0x00000001<<10)
+#define VFE40_IMASK_IMG_MAST_2_BUS_OVFL (0x00000001<<11)
+#define VFE40_IMASK_IMG_MAST_3_BUS_OVFL (0x00000001<<12)
+#define VFE40_IMASK_IMG_MAST_4_BUS_OVFL (0x00000001<<13)
+#define VFE40_IMASK_IMG_MAST_5_BUS_OVFL (0x00000001<<14)
+#define VFE40_IMASK_IMG_MAST_6_BUS_OVFL (0x00000001<<15)
+#define VFE40_IMASK_STATS_BE_BUS_OVFL (0x00000001<<16)
+#define VFE40_IMASK_STATS_BG_BUS_OVFL (0x00000001<<17)
+#define VFE40_IMASK_STATS_BF_BUS_OVFL (0x00000001<<18)
+#define VFE40_IMASK_STATS_AWB_BUS_OVFL (0x00000001<<19)
+#define VFE40_IMASK_STATS_RS_BUS_OVFL (0x00000001<<10)
+#define VFE40_IMASK_STATS_CS_BUS_OVFL (0x00000001<<21)
+#define VFE40_IMASK_STATS_IHIST_BUS_OVFL (0x00000001<<22)
+#define VFE40_IMASK_STATS_SKIN_BHIST_BUS_OVFL (0x00000001<<23)
#define VFE_COM_STATUS 0x000FE000
@@ -751,7 +752,8 @@
struct vfe40_output_ch out0; /* preview and thumbnail */
struct vfe40_output_ch out1; /* snapshot */
- struct vfe40_output_ch out2; /* video */
+ struct vfe40_output_ch out2; /* rdi0 */
+ struct vfe40_output_ch out3; /* rdi01 */
};
struct vfe40_frame_extra {
@@ -769,9 +771,7 @@
uint32_t frameCounter;
};
-#define VFE_CLEAR_ALL_IRQS 0xffffffff
-
-#define VFE_HW_VERSION 0x00000000
+#define VFE_HW_VERSION 0x00000000
#define VFE_GLOBAL_RESET 0x0000000C
#define VFE_MODULE_RESET 0x00000010
#define VFE_CGC_OVERRIDE 0x00000014
@@ -786,32 +786,67 @@
#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_PING_PONG_STATUS 0x00000268
+#define VFE_AXI_CMD 0x000002C0
+#define VFE_AXI_STATUS 0x000002E4
+#define VFE_BUS_STATS_PING_PONG_BASE 0x00000168
-#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_BUS_STATS_BE_WR_PING_ADDR 0x00000168
+#define VFE_BUS_STATS_BE_WR_PONG_ADDR 0x0000016C
+#define VFE_BUS_STATS_BE_WR_ADDR_CFG 0x00000170
+#define VFE_BUS_STATS_BE_UB_CFG 0x00000174
+#define VFE_BUS_STATS_BE_WR_FRAMEDROP_PATTERN 0x00000178
+#define VFE_BUS_STATS_BE_WR_IRQ_SUBSAMPLE_PATTERN 0x0000017C
+
+#define VFE_BUS_STATS_BG_WR_PING_ADDR 0x00000180
+#define VFE_BUS_STATS_BG_WR_PONG_ADDR 0x00000184
+#define VFE_BUS_STATS_BG_WR_ADDR_CFG 0x00000188
+#define VFE_BUS_STATS_BG_WR_UB_CFG 0x0000018C
+#define VFE_BUS_STATS_BG_WR_FRAMEDROP_PATTERN 0x00000190
+#define VFE_BUS_STATS_BG_WR_IRQ_SUBSAMPLE_PATTERN 0x00000194
+
+#define VFE_BUS_STATS_BF_WR_PING_ADDR 0x00000198
+#define VFE_BUS_STATS_BF_WR_PONG_ADDR 0x0000019C
+#define VFE_BUS_STATS_BF_WR_ADDR_CFG 0x000001A0
+#define VFE_BUS_STATS_BF_WR_UB_CFG 0x000001A4
+#define VFE_BUS_STATS_BF_WR_FRAMEDROP_PATTERN 0x000001A8
+#define VFE_BUS_STATS_BF_WR_IRQ_SUBSAMPLE_PATTERN 0x000001AC
+
+#define VFE_BUS_STATS_AWB_WR_PING_ADDR 0x000001B0
+#define VFE_BUS_STATS_AWB_WR_PONG_ADDR 0x000001B4
+#define VFE_BUS_STATS_AWB_WR_ADDR_CFG 0x000001B8
+#define VFE_BUS_STATS_AWB_WR_UB_CFG 0x000001BC
+#define VFE_BUS_STATS_AWB_WR_FRAMEDROP_PATTERN 0x000001C0
+#define VFE_BUS_STATS_AWB_WR_IRQ_SUBSAMPLE_PATTERN 0x000001C4
+
+#define VFE_BUS_STATS_RS_WR_PING_ADDR 0x000001C8
+#define VFE_BUS_STATS_RS_WR_PONG_ADDR 0x000001CC
+#define VFE_BUS_STATS_RS_WR_ADDR_CFG 0x000001D0
+#define VFE_BUS_STATS_RS_WR_UB_CFG 0x000001D4
+#define VFE_BUS_STATS_RS_WR_FRAMEDROP_PATTERN 0x000001D8
+#define VFE_BUS_STATS_RS_WR_IRQ_SUBSAMPLE_PATTERN 0x000001DC
+
+#define VFE_BUS_STATS_CS_WR_PING_ADDR 0x000001E0
+#define VFE_BUS_STATS_CS_WR_PONG_ADDR 0x000001E4
+#define VFE_BUS_STATS_CS_WR_ADDR_CFG 0x000001E8
+#define VFE_BUS_STATS_CS_WR_UB_CFG 0x000001EC
+#define VFE_BUS_STATS_CS_WR_FRAMEDROP_PATTERN 0x000001F0
+#define VFE_BUS_STATS_CS_WR_IRQ_SUBSAMPLE_PATTERN 0x000001F4
+
+#define VFE_BUS_STATS_HIST_WR_PING_ADDR 0x000001F8
+#define VFE_BUS_STATS_HIST_WR_PONG_ADDR 0x000001FC
+#define VFE_BUS_STATS_HIST_WR_ADDR_CFG 0x00000200
+#define VFE_BUS_STATS_HIST_WR_UB_CFG 0x00000204
+#define VFE_BUS_STATS_HIST_WR_FRAMEDROP_PATTERN 0x00000208
+#define VFE_BUS_STATS_HIST_WR_IRQ_SUBSAMPLE_PATTERN 0x0000020C
+
+
+#define VFE_BUS_STATS_SKIN_WR_PING_ADDR 0x00000210
+#define VFE_BUS_STATS_SKIN_WR_PONG_ADDR 0x00000214
+#define VFE_BUS_STATS_SKIN_WR_ADDR_CFG 0x00000218
+#define VFE_BUS_STATS_SKIN_WR_UB_CFG 0x0000021C
+#define VFE_BUS_STATS_SKIN_WR_FRAMEDROP_PATTERN 0x00000220
+#define VFE_BUS_STATS_SKIN_WR_IRQ_SUBSAMPLE_PATTERN 0x00000224
#define VFE_0_BUS_BDG_QOS_CFG_0 0x000002C4
#define VFE_0_BUS_BDG_QOS_CFG_1 0x000002C8
@@ -839,13 +874,14 @@
#define VFE_STATS_AWB_SGW_CFG 0x000008CC
#define VFE_DMI_CFG 0x00000910
#define VFE_DMI_ADDR 0x00000914
+#define VFE_DMI_DATA_HI 0x00000918
#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 VFE_VIOLATION_STATUS 0x00000048
#define VFE40_DMI_DATA_HI 0x00000918
#define VFE40_DMI_DATA_LO 0x0000091C
@@ -860,6 +896,25 @@
#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)
+#define VFE40_OUTPUT_MODE_TERTIARY1 BIT(10)
+#define VFE40_OUTPUT_MODE_TERTIARY2 BIT(11)
+
+#define VFE40_VBIF_CLKON 0x4
+#define VFE40_VBIF_IN_RD_LIM_CONF0 0xB0
+#define VFE40_VBIF_IN_RD_LIM_CONF1 0xB4
+#define VFE40_VBIF_IN_RD_LIM_CONF2 0xB8
+#define VFE40_VBIF_IN_WR_LIM_CONF0 0xC0
+#define VFE40_VBIF_IN_WR_LIM_CONF1 0xC4
+#define VFE40_VBIF_IN_WR_LIM_CONF2 0xC8
+#define VFE40_VBIF_OUT_RD_LIM_CONF0 0xD0
+#define VFE40_VBIF_OUT_WR_LIM_CONF0 0xD4
+#define VFE40_VBIF_DDR_OUT_MAX_BURST 0xD8
+#define VFE40_VBIF_ARB_CTL 0xF0
+#define VFE40_VBIF_DDR_ARB_CONF0 0xF4
+#define VFE40_VBIF_DDR_ARB_CONF1 0xF8
+#define VFE40_VBIF_ROUND_ROBIN_QOS_ARB 0x124
+#define VFE40_VBIF_OUT_AXI_AOOO_EN 0x178
+#define VFE40_VBIF_OUT_AXI_AOOO 0x17C
struct vfe_stats_control {
uint32_t droppedStatsFrameCount;
@@ -870,26 +925,50 @@
struct vfe_share_ctrl_t {
void __iomem *vfebase;
+ void __iomem *vfe_vbif_base;
uint32_t register_total;
atomic_t vstate;
+ atomic_t handle_common_irq;
uint32_t vfeFrameId;
+ uint32_t rdi0FrameId;
+ uint32_t rdi1FrameId;
+ uint32_t rdi2FrameId;
uint32_t stats_comp;
+ spinlock_t sd_notify_lock;
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 */
+ uint32_t operation_mode; /* streaming or snapshot */
+ uint32_t current_mode;
struct vfe40_output_path outpath;
- uint32_t ref_count;
- spinlock_t sd_notify_lock;
- uint32_t vfe_clk_rate;
+ uint16_t port_info;
+ uint8_t stop_immediately;
+ uint8_t sync_abort;
+ uint16_t cmd_type;
+ uint8_t vfe_reset_flag;
- atomic_t irq_cnt;
+ uint8_t axi_ref_cnt;
+ uint16_t comp_output_mode;
+
+ struct completion reset_complete;
+
+ spinlock_t update_ack_lock;
+ spinlock_t start_ack_lock;
+
struct axi_ctrl_t *axi_ctrl;
struct vfe40_ctrl_type *vfe40_ctrl;
+ int8_t start_ack_pending;
+ int8_t update_ack_pending;
+ enum vfe_output_state recording_state;
+
+ atomic_t pix0_update_ack_pending;
+ atomic_t rdi0_update_ack_pending;
+ atomic_t rdi1_update_ack_pending;
+ atomic_t rdi2_update_ack_pending;
};
struct axi_ctrl_t {
@@ -902,27 +981,25 @@
void *syncdata;
struct resource *vfemem;
+ struct resource *vfe_vbif_mem;
struct resource *vfeio;
+ struct resource *vfe_vbif_io;
struct regulator *fs_vfe;
- struct clk *vfe_clk[3];
+ struct clk *vfe_clk[7];
struct tasklet_struct vfe40_tasklet;
struct vfe_share_ctrl_t *share_ctrl;
+ struct device *iommu_ctx;
+ uint32_t bus_perf_client;
+ uint32_t use_irq_router;
};
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 vfe_sof_count_enable;
int8_t update_linear;
int8_t update_rolloff;
int8_t update_la;
@@ -934,18 +1011,14 @@
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 msm_ver_num_info ver_num;
+ struct vfe_stats_control afbfStatsControl;
struct vfe_stats_control awbStatsControl;
- struct vfe_stats_control aecStatsControl;
+ struct vfe_stats_control aecbgStatsControl;
struct vfe_stats_control ihistStatsControl;
struct vfe_stats_control rsStatsControl;
struct vfe_stats_control csStatsControl;
+ struct vfe_stats_control bhistStatsControl;
/* v4l2 subdev */
struct v4l2_subdev subdev;
@@ -956,6 +1029,8 @@
uint32_t snapshot_frame_cnt;
struct msm_stats_bufq_ctrl stats_ctrl;
struct msm_stats_ops stats_ops;
+
+ uint32_t simultaneous_sof_stat;
};
#define statsAeNum 0
@@ -976,227 +1051,4 @@
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_vidc/msm_v4l2_vidc.c b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
index 4e810dc..882d03e 100644
--- a/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
+++ b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
@@ -33,69 +33,209 @@
#define MAX_EVENTS 30
#define SHARED_QSIZE 0x1000000
-
-static struct msm_bus_vectors ocmem_init_vectors[] = {
+static struct msm_bus_vectors enc_ocmem_init_vectors[] = {
{
.src = MSM_BUS_MASTER_VIDEO_P0_OCMEM,
- .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .dst = MSM_BUS_SLAVE_OCMEM,
.ab = 0,
.ib = 0,
},
};
-static struct msm_bus_vectors ocmem_perf0_vectors[] = {
+static struct msm_bus_vectors enc_ocmem_perf1_vectors[] = {
{
.src = MSM_BUS_MASTER_VIDEO_P0_OCMEM,
.dst = MSM_BUS_SLAVE_OCMEM,
- .ab = 176900000,
- .ib = 221125000,
+ .ab = 414700000,
+ .ib = 1222000000,
},
};
-static struct msm_bus_vectors ocmem_perf1_vectors[] = {
+static struct msm_bus_vectors enc_ocmem_perf2_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_VIDEO_P0_OCMEM,
+ .dst = MSM_BUS_SLAVE_OCMEM,
+ .ab = 940000000,
+ .ib = 1222000000,
+ },
+};
+
+static struct msm_bus_vectors enc_ocmem_perf3_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_VIDEO_P0_OCMEM,
+ .dst = MSM_BUS_SLAVE_OCMEM,
+ .ab = 1880000000,
+ .ib = 2444000000U,
+ },
+};
+
+static struct msm_bus_vectors enc_ocmem_perf4_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_VIDEO_P0_OCMEM,
+ .dst = MSM_BUS_SLAVE_OCMEM,
+ .ab = 1880000000,
+ .ib = 2444000000U,
+ },
+};
+
+static struct msm_bus_vectors enc_ocmem_perf5_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_VIDEO_P0_OCMEM,
+ .dst = MSM_BUS_SLAVE_OCMEM,
+ .ab = 3008000000U,
+ .ib = 3910400000U,
+ },
+};
+
+static struct msm_bus_vectors enc_ocmem_perf6_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_VIDEO_P0_OCMEM,
+ .dst = MSM_BUS_SLAVE_OCMEM,
+ .ab = 3760000000U,
+ .ib = 3910400000U,
+ },
+};
+
+
+static struct msm_bus_vectors dec_ocmem_init_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_VIDEO_P0_OCMEM,
+ .dst = MSM_BUS_SLAVE_OCMEM,
+ .ab = 0,
+ .ib = 0,
+ },
+};
+
+static struct msm_bus_vectors dec_ocmem_perf1_vectors[] = {
{
.src = MSM_BUS_MASTER_VIDEO_P0_OCMEM,
.dst = MSM_BUS_SLAVE_OCMEM,
.ab = 456200000,
- .ib = 570250000,
+ .ib = 1556640000,
},
};
-static struct msm_bus_vectors ocmem_perf2_vectors[] = {
+static struct msm_bus_vectors dec_ocmem_perf2_vectors[] = {
{
.src = MSM_BUS_MASTER_VIDEO_P0_OCMEM,
.dst = MSM_BUS_SLAVE_OCMEM,
.ab = 864800000,
- .ib = 1081000000,
+ .ib = 1556640000,
},
};
-static struct msm_bus_paths ocmem_perf_vectors[] = {
+static struct msm_bus_vectors dec_ocmem_perf3_vectors[] = {
{
- ARRAY_SIZE(ocmem_init_vectors),
- ocmem_init_vectors,
- },
- {
- ARRAY_SIZE(ocmem_perf0_vectors),
- ocmem_perf0_vectors,
- },
- {
- ARRAY_SIZE(ocmem_perf1_vectors),
- ocmem_perf1_vectors,
- },
- {
- ARRAY_SIZE(ocmem_perf2_vectors),
- ocmem_perf2_vectors,
+ .src = MSM_BUS_MASTER_VIDEO_P0_OCMEM,
+ .dst = MSM_BUS_SLAVE_OCMEM,
+ .ab = 1729600000,
+ .ib = 3113280000U,
},
};
-static struct msm_bus_scale_pdata ocmem_bus_data = {
- .usecase = ocmem_perf_vectors,
- .num_usecases = ARRAY_SIZE(ocmem_perf_vectors),
- .name = "msm_vidc_ocmem",
+static struct msm_bus_vectors dec_ocmem_perf4_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_VIDEO_P0_OCMEM,
+ .dst = MSM_BUS_SLAVE_OCMEM,
+ .ab = 1729600000,
+ .ib = 3113280000U,
+ },
};
-static struct msm_bus_vectors vcodec_init_vectors[] = {
+static struct msm_bus_vectors dec_ocmem_perf5_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_VIDEO_P0_OCMEM,
+ .dst = MSM_BUS_SLAVE_OCMEM,
+ .ab = 2767360000U,
+ .ib = 3113280000U,
+ },
+};
+
+static struct msm_bus_vectors dec_ocmem_perf6_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_VIDEO_P0_OCMEM,
+ .dst = MSM_BUS_SLAVE_OCMEM,
+ .ab = 3459200000U,
+ .ib = 3459200000U,
+ },
+};
+
+static struct msm_bus_paths enc_ocmem_perf_vectors[] = {
+ {
+ ARRAY_SIZE(enc_ocmem_init_vectors),
+ enc_ocmem_init_vectors,
+ },
+ {
+ ARRAY_SIZE(enc_ocmem_perf1_vectors),
+ enc_ocmem_perf1_vectors,
+ },
+ {
+ ARRAY_SIZE(enc_ocmem_perf2_vectors),
+ enc_ocmem_perf2_vectors,
+ },
+ {
+ ARRAY_SIZE(enc_ocmem_perf3_vectors),
+ enc_ocmem_perf3_vectors,
+ },
+ {
+ ARRAY_SIZE(enc_ocmem_perf4_vectors),
+ enc_ocmem_perf4_vectors,
+ },
+ {
+ ARRAY_SIZE(enc_ocmem_perf5_vectors),
+ enc_ocmem_perf5_vectors,
+ },
+ {
+ ARRAY_SIZE(enc_ocmem_perf6_vectors),
+ enc_ocmem_perf6_vectors,
+ },
+};
+
+static struct msm_bus_paths dec_ocmem_perf_vectors[] = {
+ {
+ ARRAY_SIZE(dec_ocmem_init_vectors),
+ dec_ocmem_init_vectors,
+ },
+ {
+ ARRAY_SIZE(dec_ocmem_perf1_vectors),
+ dec_ocmem_perf1_vectors,
+ },
+ {
+ ARRAY_SIZE(dec_ocmem_perf2_vectors),
+ dec_ocmem_perf2_vectors,
+ },
+ {
+ ARRAY_SIZE(dec_ocmem_perf3_vectors),
+ dec_ocmem_perf3_vectors,
+ },
+ {
+ ARRAY_SIZE(dec_ocmem_perf4_vectors),
+ dec_ocmem_perf4_vectors,
+ },
+ {
+ ARRAY_SIZE(dec_ocmem_perf5_vectors),
+ dec_ocmem_perf5_vectors,
+ },
+ {
+ ARRAY_SIZE(dec_ocmem_perf6_vectors),
+ dec_ocmem_perf6_vectors,
+ },
+};
+
+
+static struct msm_bus_scale_pdata enc_ocmem_bus_data = {
+ .usecase = enc_ocmem_perf_vectors,
+ .num_usecases = ARRAY_SIZE(enc_ocmem_perf_vectors),
+ .name = "msm_vidc_enc_ocmem",
+};
+
+static struct msm_bus_scale_pdata dec_ocmem_bus_data = {
+ .usecase = dec_ocmem_perf_vectors,
+ .num_usecases = ARRAY_SIZE(dec_ocmem_perf_vectors),
+ .name = "msm_vidc_dec_ocmem",
+};
+
+static struct msm_bus_vectors enc_ddr_init_vectors[] = {
{
.src = MSM_BUS_MASTER_VIDEO_P0,
.dst = MSM_BUS_SLAVE_EBI_CH0,
@@ -104,56 +244,196 @@
},
};
-static struct msm_bus_vectors vcodec_perf0_vectors[] = {
+
+static struct msm_bus_vectors enc_ddr_perf1_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_VIDEO_P0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 60000000,
+ .ib = 664950000,
+ },
+};
+
+static struct msm_bus_vectors enc_ddr_perf2_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_VIDEO_P0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 181000000,
+ .ib = 664950000,
+ },
+};
+
+static struct msm_bus_vectors enc_ddr_perf3_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_VIDEO_P0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 403000000,
+ .ib = 664950000,
+ },
+};
+
+static struct msm_bus_vectors enc_ddr_perf4_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_VIDEO_P0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 806000000,
+ .ib = 1329900000,
+ },
+};
+
+static struct msm_bus_vectors enc_ddr_perf5_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_VIDEO_P0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 1289600000,
+ .ib = 2127840000U,
+ },
+};
+
+static struct msm_bus_vectors enc_ddr_perf6_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_VIDEO_P0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 161200000,
+ .ib = 2659800000U,
+ },
+};
+
+static struct msm_bus_vectors dec_ddr_init_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_VIDEO_P0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 0,
+ .ib = 0,
+ },
+};
+
+static struct msm_bus_vectors dec_ddr_perf1_vectors[] = {
{
.src = MSM_BUS_MASTER_VIDEO_P0,
.dst = MSM_BUS_SLAVE_EBI_CH0,
.ab = 110000000,
- .ib = 137500000,
+ .ib = 909000000,
},
};
-static struct msm_bus_vectors vcodec_perf1_vectors[] = {
+static struct msm_bus_vectors dec_ddr_perf2_vectors[] = {
{
.src = MSM_BUS_MASTER_VIDEO_P0,
.dst = MSM_BUS_SLAVE_EBI_CH0,
.ab = 268000000,
- .ib = 335000000,
+ .ib = 909000000,
},
};
-static struct msm_bus_vectors vcodec_perf2_vectors[] = {
+static struct msm_bus_vectors dec_ddr_perf3_vectors[] = {
{
.src = MSM_BUS_MASTER_VIDEO_P0,
.dst = MSM_BUS_SLAVE_EBI_CH0,
.ab = 505000000,
- .ib = 631250000,
+ .ib = 909000000,
},
};
-static struct msm_bus_paths vcodec_perf_vectors[] = {
+static struct msm_bus_vectors dec_ddr_perf4_vectors[] = {
{
- ARRAY_SIZE(vcodec_init_vectors),
- vcodec_init_vectors,
- },
- {
- ARRAY_SIZE(vcodec_perf0_vectors),
- vcodec_perf0_vectors,
- },
- {
- ARRAY_SIZE(vcodec_perf1_vectors),
- vcodec_perf1_vectors,
- },
- {
- ARRAY_SIZE(vcodec_perf2_vectors),
- vcodec_perf2_vectors,
+ .src = MSM_BUS_MASTER_VIDEO_P0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 1010000000,
+ .ib = 1818000000,
},
};
-static struct msm_bus_scale_pdata vcodec_bus_data = {
- .usecase = vcodec_perf_vectors,
- .num_usecases = ARRAY_SIZE(vcodec_perf_vectors),
- .name = "msm_vidc_vcodec",
+static struct msm_bus_vectors dec_ddr_perf5_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_VIDEO_P0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 1616000000,
+ .ib = 2908800000U,
+ },
+};
+
+static struct msm_bus_vectors dec_ddr_perf6_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_VIDEO_P0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 2020000000U,
+ .ib = 3636000000U,
+ },
+};
+
+static struct msm_bus_paths enc_ddr_perf_vectors[] = {
+ {
+ ARRAY_SIZE(enc_ddr_init_vectors),
+ enc_ddr_init_vectors,
+ },
+ {
+ ARRAY_SIZE(enc_ddr_perf1_vectors),
+ enc_ddr_perf1_vectors,
+ },
+ {
+ ARRAY_SIZE(enc_ddr_perf2_vectors),
+ enc_ddr_perf2_vectors,
+ },
+ {
+ ARRAY_SIZE(enc_ddr_perf3_vectors),
+ enc_ddr_perf3_vectors,
+ },
+ {
+ ARRAY_SIZE(enc_ddr_perf4_vectors),
+ enc_ddr_perf4_vectors,
+ },
+ {
+ ARRAY_SIZE(enc_ddr_perf5_vectors),
+ enc_ddr_perf5_vectors,
+ },
+ {
+ ARRAY_SIZE(enc_ddr_perf6_vectors),
+ enc_ddr_perf6_vectors,
+ },
+};
+
+static struct msm_bus_paths dec_ddr_perf_vectors[] = {
+ {
+ ARRAY_SIZE(dec_ddr_init_vectors),
+ dec_ddr_init_vectors,
+ },
+ {
+ ARRAY_SIZE(dec_ddr_perf1_vectors),
+ dec_ddr_perf1_vectors,
+ },
+ {
+ ARRAY_SIZE(dec_ddr_perf2_vectors),
+ dec_ddr_perf2_vectors,
+ },
+ {
+ ARRAY_SIZE(dec_ddr_perf3_vectors),
+ dec_ddr_perf3_vectors,
+ },
+ {
+ ARRAY_SIZE(dec_ddr_perf4_vectors),
+ dec_ddr_perf4_vectors,
+ },
+ {
+ ARRAY_SIZE(dec_ddr_perf5_vectors),
+ dec_ddr_perf5_vectors,
+ },
+ {
+ ARRAY_SIZE(dec_ddr_perf6_vectors),
+ dec_ddr_perf6_vectors,
+ },
+};
+
+static struct msm_bus_scale_pdata enc_ddr_bus_data = {
+ .usecase = enc_ddr_perf_vectors,
+ .num_usecases = ARRAY_SIZE(enc_ddr_perf_vectors),
+ .name = "msm_vidc_enc_ddr",
+};
+
+static struct msm_bus_scale_pdata dec_ddr_bus_data = {
+ .usecase = dec_ddr_perf_vectors,
+ .num_usecases = ARRAY_SIZE(dec_ddr_perf_vectors),
+ .name = "msm_vidc_dec_ddr",
};
struct msm_vidc_drv *vidc_driver;
@@ -808,17 +1088,29 @@
rc = -ENODEV;
goto core_init_failed;
}
- core->resources.bus_info.vcodec_handle =
- msm_bus_scale_register_client(&vcodec_bus_data);
- if (!core->resources.bus_info.vcodec_handle) {
+ core->resources.bus_info.ddr_handle[MSM_VIDC_ENCODER] =
+ msm_bus_scale_register_client(&enc_ddr_bus_data);
+ if (!core->resources.bus_info.ddr_handle[MSM_VIDC_ENCODER]) {
pr_err("Failed to register bus scale client\n");
- goto fail_register_vcodec_bus;
+ goto fail_register_enc_ddr_bus;
}
- core->resources.bus_info.ocmem_handle =
- msm_bus_scale_register_client(&ocmem_bus_data);
- if (!core->resources.bus_info.ocmem_handle) {
+ core->resources.bus_info.ddr_handle[MSM_VIDC_DECODER] =
+ msm_bus_scale_register_client(&dec_ddr_bus_data);
+ if (!core->resources.bus_info.ddr_handle[MSM_VIDC_DECODER]) {
pr_err("Failed to register bus scale client\n");
- goto fail_register_ocmem;
+ goto fail_register_dec_ddr_bus;
+ }
+ core->resources.bus_info.ocmem_handle[MSM_VIDC_ENCODER] =
+ msm_bus_scale_register_client(&enc_ocmem_bus_data);
+ if (!core->resources.bus_info.ocmem_handle[MSM_VIDC_ENCODER]) {
+ pr_err("Failed to register bus scale client\n");
+ goto fail_register_enc_ocmem;
+ }
+ core->resources.bus_info.ocmem_handle[MSM_VIDC_DECODER] =
+ msm_bus_scale_register_client(&dec_ocmem_bus_data);
+ if (!core->resources.bus_info.ocmem_handle[MSM_VIDC_DECODER]) {
+ pr_err("Failed to register bus scale client\n");
+ goto fail_register_dec_ocmem;
}
rc = register_iommu_domains(pdev, core);
if (rc) {
@@ -836,11 +1128,17 @@
return rc;
fail_register_domains:
msm_bus_scale_unregister_client(
- core->resources.bus_info.ocmem_handle);
-fail_register_ocmem:
+ core->resources.bus_info.ocmem_handle[MSM_VIDC_DECODER]);
+fail_register_dec_ocmem:
msm_bus_scale_unregister_client(
- core->resources.bus_info.vcodec_handle);
-fail_register_vcodec_bus:
+ core->resources.bus_info.ocmem_handle[MSM_VIDC_ENCODER]);
+fail_register_enc_ocmem:
+ msm_bus_scale_unregister_client(
+ core->resources.bus_info.ddr_handle[MSM_VIDC_DECODER]);
+fail_register_dec_ddr_bus:
+ msm_bus_scale_unregister_client(
+ core->resources.bus_info.ddr_handle[MSM_VIDC_ENCODER]);
+fail_register_enc_ddr_bus:
msm_vidc_deinit_clocks(core);
core_init_failed:
return rc;
@@ -852,7 +1150,6 @@
struct msm_vidc_core *core;
unsigned long flags;
char debugfs_name[MAX_DEBUGFS_NAME];
-
core = kzalloc(sizeof(*core), GFP_KERNEL);
if (!core || !vidc_driver) {
pr_err("Failed to allocate memory for device core\n");
@@ -935,8 +1232,13 @@
{
int rc = 0;
struct msm_vidc_core *core = pdev->dev.platform_data;
- msm_bus_scale_unregister_client(core->resources.bus_info.vcodec_handle);
- msm_bus_scale_unregister_client(core->resources.bus_info.ocmem_handle);
+ int i;
+ for (i = 0; i < MSM_VIDC_MAX_DEVICES; ++i) {
+ msm_bus_scale_unregister_client(
+ core->resources.bus_info.ddr_handle[i]);
+ msm_bus_scale_unregister_client(
+ core->resources.bus_info.ocmem_handle[i]);
+ }
vidc_hal_delete_device(core->device);
video_unregister_device(&core->vdev[MSM_VIDC_ENCODER].vdev);
video_unregister_device(&core->vdev[MSM_VIDC_DECODER].vdev);
diff --git a/drivers/media/video/msm_vidc/msm_vdec.c b/drivers/media/video/msm_vidc/msm_vdec.c
index cae486f..c0f8014 100644
--- a/drivers/media/video/msm_vidc/msm_vdec.c
+++ b/drivers/media/video/msm_vidc/msm_vdec.c
@@ -22,9 +22,9 @@
#define MAX_PLANES 1
#define DEFAULT_HEIGHT 720
#define DEFAULT_WIDTH 1280
-#define MAX_SUPPORTED_WIDTH 4096
-#define MAX_SUPPORTED_HEIGHT 2160
-#define MIN_NUM_OUTPUT_BUFFERS 2
+#define MAX_SUPPORTED_WIDTH 1920
+#define MAX_SUPPORTED_HEIGHT 1088
+#define MIN_NUM_OUTPUT_BUFFERS 4
#define MAX_NUM_OUTPUT_BUFFERS 6
static const char *const mpeg_video_vidc_divx_format[] = {
@@ -598,6 +598,7 @@
int i, rc = 0;
struct msm_vidc_inst *inst;
unsigned long flags;
+ struct hal_buffer_requirements *bufreq;
if (!q || !q->drv_priv) {
pr_err("Invalid input, q = %p\n", q);
return -EINVAL;
@@ -628,7 +629,6 @@
break;
}
*num_planes = 1;
-
spin_lock_irqsave(&inst->lock, flags);
if (*num_buffers && *num_buffers >
inst->buff_req.buffer[HAL_BUFFER_OUTPUT].
@@ -642,17 +642,12 @@
rc = vidc_hal_session_set_property(inst->session,
property_id, &new_buf_count);
- spin_unlock_irqrestore(&inst->lock, flags);
- if (!rc && msm_comm_try_get_bufreqs(inst)) {
- /* We are allowed to reject clients' request for
- * more buffers and suggest our own bufreq */
- pr_warn("Unable to increase the number of output buffers to %d\n",
- *num_buffers);
- }
- spin_lock_irqsave(&inst->lock, flags);
}
- *num_buffers = inst->buff_req.buffer[HAL_BUFFER_OUTPUT].
- buffer_count_actual;
+ bufreq = &inst->buff_req.buffer[HAL_BUFFER_OUTPUT];
+ if (bufreq->buffer_count_actual > *num_buffers)
+ *num_buffers = bufreq->buffer_count_actual;
+ else
+ bufreq->buffer_count_actual = *num_buffers ;
spin_unlock_irqrestore(&inst->lock, flags);
pr_debug("count = %d, size = %d, alignment = %d\n",
@@ -679,11 +674,6 @@
unsigned long flags;
struct vb2_buf_entry *temp;
struct list_head *ptr, *next;
- rc = msm_comm_try_get_bufreqs(inst);
- if (rc) {
- pr_err("Failed to get buffer requirements : %d\n", rc);
- goto fail_start;
- }
rc = msm_comm_set_scratch_buffers(inst);
if (rc) {
pr_err("Failed to set scratch buffers: %d\n", rc);
@@ -694,12 +684,16 @@
pr_err("Failed to set persist buffers: %d\n", rc);
goto fail_start;
}
+ if (msm_comm_scale_clocks(inst->core, inst->session_type))
+ pr_warn("Failed to scale clocks. Performance might be impacted\n");
+
rc = msm_comm_try_state(inst, MSM_VIDC_START_DONE);
if (rc) {
pr_err("Failed to move inst: %p to start done state\n",
inst);
goto fail_start;
}
+
spin_lock_irqsave(&inst->lock, flags);
if (!list_empty(&inst->pendingq)) {
list_for_each_safe(ptr, next, &inst->pendingq) {
@@ -731,14 +725,10 @@
pr_debug("Streamon called on: %d capability\n", q->type);
switch (q->type) {
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
- if (msm_comm_scale_clocks(inst->core))
- pr_err("Failed to scale clocks. Performance/power might be impacted\n");
if (inst->vb2_bufq[CAPTURE_PORT].streaming)
rc = start_streaming(inst);
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
- if (msm_comm_scale_clocks(inst->core))
- pr_err("Failed to scale clocks. Performance/power might be impacted\n");
if (inst->vb2_bufq[OUTPUT_PORT].streaming)
rc = start_streaming(inst);
break;
@@ -776,6 +766,9 @@
rc = -EINVAL;
break;
}
+ if (msm_comm_scale_clocks(inst->core, inst->session_type))
+ pr_warn("Failed to scale clocks. Power might be impacted\n");
+
if (rc)
pr_err("Failed to move inst: %p, cap = %d to state: %d\n",
inst, q->type, MSM_VIDC_RELEASE_RESOURCES_DONE);
diff --git a/drivers/media/video/msm_vidc/msm_venc.c b/drivers/media/video/msm_vidc/msm_venc.c
index 74f1415..1b1a0c5 100644
--- a/drivers/media/video/msm_vidc/msm_venc.c
+++ b/drivers/media/video/msm_vidc/msm_venc.c
@@ -652,6 +652,9 @@
pr_err("Failed to set persist buffers: %d\n", rc);
goto fail_start;
}
+ if (msm_comm_scale_clocks(inst->core, inst->session_type))
+ pr_warn("Failed to scale clocks. Performance might be impacted\n");
+
rc = msm_comm_try_state(inst, MSM_VIDC_START_DONE);
if (rc) {
pr_err("Failed to move inst: %p to start done state\n",
@@ -689,14 +692,10 @@
pr_debug("Streamon called on: %d capability\n", q->type);
switch (q->type) {
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
- if (msm_comm_scale_clocks(inst->core))
- pr_err("Failed to scale clocks. Performance/power might be impacted\n");
if (inst->vb2_bufq[CAPTURE_PORT].streaming)
rc = start_streaming(inst);
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
- if (msm_comm_scale_clocks(inst->core))
- pr_err("Failed to scale clocks. Performance/power might be impacted\n");
if (inst->vb2_bufq[OUTPUT_PORT].streaming)
rc = start_streaming(inst);
break;
@@ -729,6 +728,9 @@
rc = -EINVAL;
break;
}
+ if (msm_comm_scale_clocks(inst->core, inst->session_type))
+ pr_warn("Failed to scale clocks. Power might be impacted\n");
+
if (rc)
pr_err("Failed to move inst: %p, cap = %d to state: %d\n",
inst, q->type, MSM_VIDC_CLOSE_DONE);
diff --git a/drivers/media/video/msm_vidc/msm_vidc_common.c b/drivers/media/video/msm_vidc/msm_vidc_common.c
index b6dce2c..c9e8ff4 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_common.c
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.c
@@ -48,96 +48,48 @@
__mbs;\
})
-/*While adding entries to this array make sure
- * they are in descending order.
- * Look @ msm_comm_get_load function*/
-static const u32 clocks_table[][2] = {
- {979200, 410000000},
- {560145, 266670000},
- {421161, 200000000},
- {243000, 133330000},
- {108000, 100000000},
- {36000, 50000000},
-};
-
static const u32 bus_table[] = {
0,
- 9216000,
- 27648000,
- 62208000,
+ 36000,
+ 110400,
+ 244800,
+ 489000,
+ 783360,
+ 979200,
};
-static int msm_comm_get_bus_load(struct msm_vidc_core *core)
-{
- struct msm_vidc_inst *inst = NULL;
- int load = 0;
- if (!core) {
- pr_err("Invalid args: %p\n", core);
- return -EINVAL;
- }
- list_for_each_entry(inst, &core->instances, list) {
- load += VIDC_BUS_LOAD(inst->prop.height,
- inst->prop.width, inst->prop.fps,
- 2000000);
- }
- return load;
-}
-
static int get_bus_vector(int load)
{
int num_rows = sizeof(bus_table)/(sizeof(u32));
int i;
for (i = num_rows - 1; i > 0; i--) {
- if ((load >= bus_table[i]) || (i == 1))
+ if (load >= bus_table[i])
break;
}
- pr_err("Required bus = %d\n", i);
+ pr_debug("Required bus = %d\n", i);
return i;
}
-int msm_comm_scale_bus(struct msm_vidc_core *core)
-{
- int load;
- int rc = 0;
- if (!core) {
- pr_err("Invalid args: %p\n", core);
- return -EINVAL;
- }
- load = msm_comm_get_bus_load(core);
- if (load <= 0) {
- pr_err("Failed to scale bus for %d load\n",
- load);
- goto fail_scale_bus;
- }
- rc = msm_bus_scale_client_update_request(
- core->resources.bus_info.vcodec_handle,
- get_bus_vector(load));
- if (rc) {
- pr_err("Failed to scale bus: %d\n", rc);
- goto fail_scale_bus;
- }
- rc = msm_bus_scale_client_update_request(
- core->resources.bus_info.ocmem_handle,
- get_bus_vector(load));
- if (rc) {
- pr_err("Failed to scale bus: %d\n", rc);
- goto fail_scale_bus;
- }
-fail_scale_bus:
- return rc;
-}
-
-static int msm_comm_get_load(struct msm_vidc_core *core)
+static int msm_comm_get_load(struct msm_vidc_core *core,
+ enum session_type type)
{
struct msm_vidc_inst *inst = NULL;
int num_mbs_per_sec = 0;
+ unsigned long flags;
if (!core) {
pr_err("Invalid args: %p\n", core);
return -EINVAL;
}
- list_for_each_entry(inst, &core->instances, list)
- num_mbs_per_sec += NUM_MBS_PER_SEC(inst->prop.height,
- inst->prop.width, inst->prop.fps);
+ list_for_each_entry(inst, &core->instances, list) {
+ spin_lock_irqsave(&inst->lock, flags);
+ if (inst->session_type == type &&
+ inst->state >= MSM_VIDC_OPEN_DONE &&
+ inst->state < MSM_VIDC_STOP_DONE) {
+ num_mbs_per_sec += NUM_MBS_PER_SEC(inst->prop.height,
+ inst->prop.width, inst->prop.fps);
+ }
+ spin_unlock_irqrestore(&inst->lock, flags);
+ }
return num_mbs_per_sec;
}
@@ -153,10 +105,37 @@
break;
ret = table[i].freq;
}
- pr_err("Required clock rate = %lu\n", ret);
+ pr_debug("Required clock rate = %lu\n", ret);
return ret;
}
+int msm_comm_scale_bus(struct msm_vidc_core *core, enum session_type type)
+{
+ int load;
+ int rc = 0;
+ if (!core || type >= MSM_VIDC_MAX_DEVICES) {
+ pr_err("Invalid args: %p, %d\n", core, type);
+ return -EINVAL;
+ }
+ load = msm_comm_get_load(core, type);
+ rc = msm_bus_scale_client_update_request(
+ core->resources.bus_info.ddr_handle[type],
+ get_bus_vector(load));
+ if (rc) {
+ pr_err("Failed to scale bus: %d\n", rc);
+ goto fail_scale_bus;
+ }
+ rc = msm_bus_scale_client_update_request(
+ core->resources.bus_info.ocmem_handle[type],
+ get_bus_vector(load));
+ if (rc) {
+ pr_err("Failed to scale bus: %d\n", rc);
+ goto fail_scale_bus;
+ }
+fail_scale_bus:
+ return rc;
+}
+
struct msm_vidc_core *get_vidc_core(int core_id)
{
struct msm_vidc_core *core;
@@ -695,7 +674,7 @@
}
}
-int msm_comm_scale_clocks(struct msm_vidc_core *core)
+int msm_comm_scale_clocks(struct msm_vidc_core *core, enum session_type type)
{
int num_mbs_per_sec;
int rc = 0;
@@ -703,8 +682,9 @@
pr_err("Invalid args: %p\n", core);
return -EINVAL;
}
- num_mbs_per_sec = msm_comm_get_load(core);
- pr_err("num_mbs_per_sec = %d\n", num_mbs_per_sec);
+ num_mbs_per_sec = msm_comm_get_load(core, MSM_VIDC_ENCODER);
+ num_mbs_per_sec += msm_comm_get_load(core, MSM_VIDC_DECODER);
+ pr_debug("num_mbs_per_sec = %d\n", num_mbs_per_sec);
rc = clk_set_rate(core->resources.clock[VCODEC_CLK].clk,
get_clock_rate(&core->resources.clock[VCODEC_CLK],
num_mbs_per_sec));
@@ -712,7 +692,7 @@
pr_err("Failed to set clock rate: %d\n", rc);
goto fail_clk_set_rate;
}
- rc = msm_comm_scale_bus(core);
+ rc = msm_comm_scale_bus(core, type);
if (rc)
pr_err("Failed to scale bus bandwidth\n");
fail_clk_set_rate:
@@ -768,11 +748,6 @@
pr_err("Invalid paramter: %p\n", core);
return -EINVAL;
}
- rc = msm_comm_scale_clocks(core);
- if (rc) {
- pr_err("Failed to set clock rate: %d\n", rc);
- goto fail_pil_get;
- }
if (!core->resources.fw.cookie)
core->resources.fw.cookie = pil_get("venus");
@@ -1004,6 +979,11 @@
core->id, core->state);
goto core_already_inited;
}
+ rc = msm_comm_scale_clocks(core, inst->session_type);
+ if (rc) {
+ pr_err("Failed to set clock rate: %d\n", rc);
+ goto fail_load_fw;
+ }
rc = msm_comm_load_fw(core);
if (rc) {
pr_err("Failed to load video firmware\n");
@@ -1041,6 +1021,10 @@
core->id, core->state);
goto core_already_uninited;
}
+ if (msm_comm_scale_clocks(core, inst->session_type)) {
+ pr_warn("Failed to scale clocks while closing\n");
+ pr_warn("Power might be impacted\n");
+ }
if (list_empty(&core->instances)) {
msm_comm_unset_ocmem(core);
msm_comm_free_ocmem(core);
diff --git a/drivers/media/video/msm_vidc/msm_vidc_common.h b/drivers/media/video/msm_vidc/msm_vidc_common.h
index 9430d5f..69e466e 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_common.h
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.h
@@ -30,7 +30,7 @@
int msm_comm_set_scratch_buffers(struct msm_vidc_inst *inst);
int msm_comm_set_persist_buffers(struct msm_vidc_inst *inst);
int msm_comm_qbuf(struct vb2_buffer *vb);
-int msm_comm_scale_clocks(struct msm_vidc_core *core);
+int msm_comm_scale_clocks(struct msm_vidc_core *core, enum session_type type);
#define IS_PRIV_CTRL(idx) (\
(V4L2_CTRL_ID2CLASS(idx) == V4L2_CTRL_CLASS_MPEG) && \
V4L2_CTRL_DRIVER_PRIV(idx))
diff --git a/drivers/media/video/msm_vidc/msm_vidc_internal.h b/drivers/media/video/msm_vidc/msm_vidc_internal.h
index d01b1d1..29ed6dc 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_internal.h
+++ b/drivers/media/video/msm_vidc/msm_vidc_internal.h
@@ -176,8 +176,8 @@
};
struct vidc_bus_info {
- u32 vcodec_handle;
- u32 ocmem_handle;
+ u32 ddr_handle[MSM_VIDC_MAX_DEVICES];
+ u32 ocmem_handle[MSM_VIDC_MAX_DEVICES];
};
struct on_chip_mem {
diff --git a/drivers/media/video/msm_wfd/enc-subdev.c b/drivers/media/video/msm_wfd/enc-subdev.c
index 8b83a98..e1cabf9 100644
--- a/drivers/media/video/msm_wfd/enc-subdev.c
+++ b/drivers/media/video/msm_wfd/enc-subdev.c
@@ -1964,13 +1964,33 @@
client_ctx->user_ion_client,
client_ctx->recon_buffer_ion_handle[i], 0);
- rc = ion_map_iommu(client_ctx->user_ion_client,
- client_ctx->recon_buffer_ion_handle[i],
- VIDEO_DOMAIN, VIDEO_MAIN_POOL, SZ_4K,
- 0, &phy_addr, (unsigned long *)&len, 0, 0);
- if (rc) {
- WFD_MSG_ERR("Failed to allo recon buffers\n");
- break;
+ if (IS_ERR_OR_NULL(ctrl->kernel_virtual_addr)) {
+ WFD_MSG_ERR("ion map kernel failed\n");
+ rc = -EINVAL;
+ goto free_ion_alloc;
+ }
+
+ if (inst->secure) {
+ rc = ion_phys(client_ctx->user_ion_client,
+ client_ctx->recon_buffer_ion_handle[i],
+ &phy_addr, (size_t *)&len);
+ if (rc || !phy_addr) {
+ WFD_MSG_ERR("ion physical failed\n");
+ goto unmap_ion_alloc;
+ }
+ } else {
+ rc = ion_map_iommu(client_ctx->user_ion_client,
+ client_ctx->recon_buffer_ion_handle[i],
+ VIDEO_DOMAIN, VIDEO_MAIN_POOL, SZ_4K,
+ 0, &phy_addr, (unsigned long *)&len,
+ 0, 0);
+ if (rc || !phy_addr) {
+ WFD_MSG_ERR(
+ "ion map iommu failed, rc = %d, phy_addr = 0x%lx\n",
+ rc, phy_addr);
+ goto unmap_ion_alloc;
+ }
+
}
ctrl->physical_addr = (u8 *) phy_addr;
ctrl->dev_addr = ctrl->physical_addr;
@@ -1981,13 +2001,36 @@
&vcd_property_hdr, ctrl);
if (rc) {
WFD_MSG_ERR("Failed to set recon buffers\n");
- break;
+ goto unmap_ion_iommu;
}
}
} else {
WFD_MSG_ERR("PMEM not suported\n");
return -ENOMEM;
}
+ return rc;
+unmap_ion_iommu:
+ if (!inst->secure) {
+ if (client_ctx->recon_buffer_ion_handle[i]) {
+ ion_unmap_iommu(client_ctx->user_ion_client,
+ client_ctx->recon_buffer_ion_handle[i],
+ VIDEO_DOMAIN, VIDEO_MAIN_POOL);
+ }
+ }
+unmap_ion_alloc:
+ if (client_ctx->recon_buffer_ion_handle[i]) {
+ ion_unmap_kernel(client_ctx->user_ion_client,
+ client_ctx->recon_buffer_ion_handle[i]);
+ ctrl->kernel_virtual_addr = NULL;
+ ctrl->physical_addr = NULL;
+ }
+free_ion_alloc:
+ if (client_ctx->recon_buffer_ion_handle[i]) {
+ ion_free(client_ctx->user_ion_client,
+ client_ctx->recon_buffer_ion_handle[i]);
+ client_ctx->recon_buffer_ion_handle[i] = NULL;
+ }
+ WFD_MSG_ERR("Failed to allo recon buffers\n");
err:
return rc;
}
@@ -2115,10 +2158,14 @@
if (rc)
WFD_MSG_ERR("Failed to free recon buffer\n");
- if (client_ctx->recon_buffer_ion_handle[i]) {
- ion_unmap_iommu(client_ctx->user_ion_client,
- client_ctx->recon_buffer_ion_handle[i],
- VIDEO_DOMAIN, VIDEO_MAIN_POOL);
+ if (IS_ERR_OR_NULL(
+ client_ctx->recon_buffer_ion_handle[i])) {
+ if (!inst->secure) {
+ ion_unmap_iommu(
+ client_ctx->user_ion_client,
+ client_ctx->recon_buffer_ion_handle[i],
+ VIDEO_DOMAIN, VIDEO_MAIN_POOL);
+ }
ion_unmap_kernel(client_ctx->user_ion_client,
client_ctx->recon_buffer_ion_handle[i]);
ion_free(client_ctx->user_ion_client,
diff --git a/drivers/media/video/msm_wfd/wfd-ioctl.c b/drivers/media/video/msm_wfd/wfd-ioctl.c
index 4c27f19..232c202 100644
--- a/drivers/media/video/msm_wfd/wfd-ioctl.c
+++ b/drivers/media/video/msm_wfd/wfd-ioctl.c
@@ -170,7 +170,7 @@
goto alloc_fail;
}
- kvaddr = ion_map_kernel(client, handle, CACHED);
+ kvaddr = ion_map_kernel(client, handle, secure ? UNCACHED : CACHED);
if (IS_ERR_OR_NULL(kvaddr)) {
WFD_MSG_ERR("Failed to get virtual addr\n");
@@ -178,13 +178,23 @@
goto alloc_fail;
}
- rc = ion_map_iommu(client, handle,
- VIDEO_DOMAIN, VIDEO_MAIN_POOL, SZ_4K,
- 0, (unsigned long *)&phys_addr,
- &size, 0, 0);
+ if (secure) {
+ WFD_MSG_INFO("%s: calling ion_phys", __func__);
+ rc = ion_phys(client,
+ handle,
+ (unsigned long *)&phys_addr, (size_t *)&size);
+ } else {
+ WFD_MSG_INFO("%s: calling ion_map_iommu", __func__);
+ rc = ion_map_iommu(client, handle,
+ VIDEO_DOMAIN, VIDEO_MAIN_POOL, SZ_4K,
+ 0, (unsigned long *)&phys_addr,
+ &size, 0, 0);
+ }
- if (rc) {
- WFD_MSG_ERR("Failed to get physical addr\n");
+ if (rc || !phys_addr) {
+ WFD_MSG_ERR(
+ "Failed to get physical addr, rc = %d, phys_addr = 0x%p\n",
+ rc, phys_addr);
goto alloc_fail;
} else if (size < mregion->size) {
WFD_MSG_ERR("Failed to map enough memory\n");
@@ -311,8 +321,10 @@
(unsigned long *)&mdp_mregion->size, 0, 0);
}
- if (rc) {
- WFD_MSG_ERR("Failed to map to mdp\n");
+ if (rc || !mdp_mregion->paddr) {
+ WFD_MSG_ERR(
+ "Failed to map to mdp, rc = %d, paddr = 0x%p\n",
+ rc, mdp_mregion->paddr);
mdp_mregion->kvaddr = NULL;
mdp_mregion->paddr = NULL;
mdp_mregion->ion_handle = NULL;
@@ -324,8 +336,9 @@
mdp_buf.kvaddr = (u32) mdp_mregion->kvaddr;
mdp_buf.paddr = (u32) mdp_mregion->paddr;
- WFD_MSG_DBG("NOTE: mdp paddr = %p, kvaddr = %p\n",
- mdp_mregion->paddr,
+ WFD_MSG_DBG("NOTE: mdp paddr = [%p->%p], kvaddr = %p\n",
+ mdp_mregion->paddr, (void *)
+ ((int)mdp_mregion->paddr + mdp_mregion->size),
mdp_mregion->kvaddr);
INIT_LIST_HEAD(&mpair->list);
@@ -350,7 +363,12 @@
WFD_MSG_ERR("Failed to allocate recon buffers\n");
goto alloc_fail;
}
+ return rc;
+
alloc_fail:
+ kfree(mpair);
+ kfree(enc_mregion);
+ kfree(mdp_mregion);
return rc;
}
void wfd_free_input_buffers(struct wfd_device *wfd_dev,
@@ -395,7 +413,7 @@
}
}
- if (mpair->enc->paddr)
+ if (mpair->enc->paddr && !wfd_dev->secure_device)
ion_unmap_iommu(wfd_dev->ion_client,
mpair->enc->ion_handle,
VIDEO_DOMAIN, VIDEO_MAIN_POOL);
@@ -1509,10 +1527,6 @@
}
wfd_priv = pdev->dev.platform_data;
- if (wfd_priv && wfd_priv->wfd_check_mdp_iommu_split) {
- wfd_dev->mdp_iommu_split_domain =
- wfd_priv->wfd_check_mdp_iommu_split();
- }
pdev->dev.platform_data = (void *) wfd_dev;
@@ -1556,6 +1570,11 @@
mutex_init(&wfd_dev[c].dev_lock);
wfd_dev[c].ion_client = ion_client;
wfd_dev[c].in_use = false;
+ if (wfd_priv && wfd_priv->wfd_check_mdp_iommu_split) {
+ wfd_dev[c].mdp_iommu_split_domain =
+ wfd_priv->wfd_check_mdp_iommu_split();
+ }
+
switch (WFD_DEVICE_NUMBER_BASE + c) {
case WFD_DEVICE_SECURE:
wfd_dev[c].secure_device = true;
diff --git a/drivers/media/video/vcap_v4l2.c b/drivers/media/video/vcap_v4l2.c
index e8d9e04..cb33550 100644
--- a/drivers/media/video/vcap_v4l2.c
+++ b/drivers/media/video/vcap_v4l2.c
@@ -503,7 +503,7 @@
unsigned int *nplanes, unsigned int sizes[],
void *alloc_ctxs[])
{
- *nbuffers += 2;
+ *nbuffers += vcap_ctrl->vc_tot_buf;
if (*nbuffers > VIDEO_MAX_FRAME)
return -EINVAL;
*nplanes = 1;
@@ -524,17 +524,16 @@
{
struct vcap_client_data *c_data = vb2_get_drv_priv(vb->vb2_queue);
struct vcap_buffer *buf = container_of(vb, struct vcap_buffer, vb);
- struct vcap_action *vid_vc_action = &c_data->vid_vc_action;
+ struct vc_action *vc_action = &c_data->vc_action;
struct vb2_queue *q = vb->vb2_queue;
unsigned long flags = 0;
spin_lock_irqsave(&c_data->cap_slock, flags);
- list_add_tail(&buf->list, &vid_vc_action->active);
+ list_add_tail(&buf->list, &vc_action->active);
spin_unlock_irqrestore(&c_data->cap_slock, flags);
if (atomic_read(&c_data->dev->vc_enabled) == 0) {
-
- if (atomic_read(&q->queued_count) > 1)
+ if (atomic_read(&q->queued_count) >= c_data->vc_action.tot_buf)
if (vc_hw_kick_off(c_data) == 0)
atomic_set(&c_data->dev->vc_enabled, 1);
}
@@ -554,9 +553,9 @@
vc_stop_capture(c_data);
- while (!list_empty(&c_data->vid_vc_action.active)) {
+ while (!list_empty(&c_data->vc_action.active)) {
struct vcap_buffer *buf;
- buf = list_entry(c_data->vid_vc_action.active.next,
+ buf = list_entry(c_data->vc_action.active.next,
struct vcap_buffer, list);
list_del(&buf->list);
vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
@@ -617,7 +616,7 @@
{
struct vcap_client_data *cd = vb2_get_drv_priv(vb->vb2_queue);
struct vcap_buffer *buf = container_of(vb, struct vcap_buffer, vb);
- struct vp_action *vp_act = &cd->vid_vp_action;
+ struct vp_action *vp_act = &cd->vp_action;
struct vb2_queue *q = vb->vb2_queue;
unsigned long flags = 0;
@@ -626,7 +625,7 @@
spin_unlock_irqrestore(&cd->cap_slock, flags);
if (atomic_read(&cd->dev->vp_enabled) == 0) {
- if (cd->vid_vp_action.vp_state == VP_FRAME1) {
+ if (cd->vp_action.vp_state == VP_FRAME1) {
if (atomic_read(&q->queued_count) > 1 &&
atomic_read(&cd->vp_out_vidq.queued_count) > 0)
/* Valid code flow for VC-VP mode */
@@ -651,9 +650,9 @@
dprintk(2, "VP stop streaming\n");
- while (!list_empty(&c_data->vid_vp_action.in_active)) {
+ while (!list_empty(&c_data->vp_action.in_active)) {
struct vcap_buffer *buf;
- buf = list_entry(c_data->vid_vp_action.in_active.next,
+ buf = list_entry(c_data->vp_action.in_active.next,
struct vcap_buffer, list);
list_del(&buf->list);
vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
@@ -715,7 +714,7 @@
{
struct vcap_client_data *cd = vb2_get_drv_priv(vb->vb2_queue);
struct vcap_buffer *buf = container_of(vb, struct vcap_buffer, vb);
- struct vp_action *vp_act = &cd->vid_vp_action;
+ struct vp_action *vp_act = &cd->vp_action;
struct vb2_queue *q = vb->vb2_queue;
unsigned long flags = 0;
@@ -724,7 +723,7 @@
spin_unlock_irqrestore(&cd->cap_slock, flags);
if (atomic_read(&cd->dev->vp_enabled) == 0) {
- if (cd->vid_vp_action.vp_state == VP_FRAME1) {
+ if (cd->vp_action.vp_state == VP_FRAME1) {
if (atomic_read(&q->queued_count) > 0 &&
atomic_read(&
cd->vp_in_vidq.queued_count) > 1)
@@ -749,9 +748,9 @@
dprintk(2, "VP out q stop streaming\n");
vp_stop_capture(c_data);
- while (!list_empty(&c_data->vid_vp_action.out_active)) {
+ while (!list_empty(&c_data->vp_action.out_active)) {
struct vcap_buffer *buf;
- buf = list_entry(c_data->vid_vp_action.out_active.next,
+ buf = list_entry(c_data->vp_action.out_active.next,
struct vcap_buffer, list);
list_del(&buf->list);
vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
@@ -884,6 +883,7 @@
struct v4l2_requestbuffers *rb)
{
struct vcap_client_data *c_data = to_client_data(file->private_data);
+ struct vcap_dev *dev = c_data->dev;
int rc;
dprintk(3, "In Req Buf %08x\n", (unsigned int)rb->type);
@@ -905,7 +905,7 @@
pr_err("VCAP Err: VP No prog support\n");
return -ENOTRECOVERABLE;
}
- if (rb->count < 6) {
+ if (rb->count <= VCAP_VP_MIN_BUF) {
pr_err("VCAP Err: Not enough buf for VC_VP\n");
return -EINVAL;
}
@@ -924,10 +924,13 @@
rb->type = V4L2_BUF_TYPE_INTERLACED_IN_DECODER;
rc = vb2_reqbufs(&c_data->vp_in_vidq, rb);
rb->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ c_data->vc_action.tot_buf = dev->vc_tot_buf;
return rc;
} else {
- return vb2_reqbufs(&c_data->vc_vidq, rb);
+ rc = vb2_reqbufs(&c_data->vc_vidq, rb);
+ c_data->vc_action.tot_buf = dev->vc_tot_buf;
+ return rc;
}
case V4L2_BUF_TYPE_INTERLACED_IN_DECODER:
return vb2_reqbufs(&c_data->vp_in_vidq, rb);
@@ -1117,6 +1120,12 @@
return -ENOTRECOVERABLE;
}
+ if (!dev->vp_dummy_complete) {
+ pr_err("VCAP Err: %s: VP dummy read not complete",
+ __func__);
+ return -EINVAL;
+ }
+
switch (c_data->op_mode) {
case VC_VCAP_OP:
mutex_lock(&dev->dev_mutex);
@@ -1213,13 +1222,13 @@
rc = init_motion_buf(c_data);
if (rc < 0)
goto free_res;
- if (c_data->vid_vp_action.nr_param.mode) {
+ if (c_data->vp_action.nr_param.mode) {
rc = init_nr_buf(c_data);
if (rc < 0)
goto s_on_deinit_m_buf;
}
- c_data->vid_vp_action.vp_state = VP_FRAME1;
+ c_data->vp_action.vp_state = VP_FRAME1;
c_data->streaming = 1;
rc = vb2_streamon(&c_data->vp_in_vidq,
@@ -1302,14 +1311,14 @@
if (rc < 0)
goto free_res;
- if (c_data->vid_vp_action.nr_param.mode) {
+ if (c_data->vp_action.nr_param.mode) {
rc = init_nr_buf(c_data);
if (rc < 0)
goto s_on_deinit_m_buf;
}
c_data->dev->vc_to_vp_work.cd = c_data;
- c_data->vid_vp_action.vp_state = VP_FRAME1;
+ c_data->vp_action.vp_state = VP_FRAME1;
c_data->streaming = 1;
/* These stream on calls should not fail */
@@ -1335,7 +1344,7 @@
return 0;
s_on_deinit_nr_buf:
- if (c_data->vid_vp_action.nr_param.mode)
+ if (c_data->vp_action.nr_param.mode)
deinit_nr_buf(c_data);
s_on_deinit_m_buf:
deinit_motion_buf(c_data);
@@ -1390,19 +1399,13 @@
}
dev->vc_resource = 0;
mutex_unlock(&dev->dev_mutex);
+ c_data->streaming = 0;
rc = vb2_streamoff(&c_data->vc_vidq,
V4L2_BUF_TYPE_VIDEO_CAPTURE);
- if (rc >= 0) {
- c_data->streaming = 0;
+ if (rc >= 0)
atomic_set(&c_data->dev->vc_enabled, 0);
- }
return rc;
case VP_VCAP_OP:
- if (!dev->vp_dummy_complete) {
- pr_err("VCAP Err: %s: VP dummy read not complete",
- __func__);
- return -EINVAL;
- }
if (c_data != dev->vp_client) {
pr_err("VCAP Err: %s: VP held by other client",
__func__);
@@ -1436,16 +1439,11 @@
return rc;
deinit_motion_buf(c_data);
- if (c_data->vid_vp_action.nr_param.mode)
+ if (c_data->vp_action.nr_param.mode)
deinit_nr_buf(c_data);
atomic_set(&c_data->dev->vp_enabled, 0);
return rc;
case VC_AND_VP_VCAP_OP:
- if (!dev->vp_dummy_complete) {
- pr_err("VCAP Err: %s: VP dummy read not complete",
- __func__);
- return -EINVAL;
- }
if (c_data != dev->vp_client || c_data != dev->vc_client) {
pr_err("VCAP Err: %s: VC/VP held by other client",
__func__);
@@ -1489,7 +1487,7 @@
return rc;
deinit_motion_buf(c_data);
- if (c_data->vid_vp_action.nr_param.mode)
+ if (c_data->vp_action.nr_param.mode)
deinit_nr_buf(c_data);
atomic_set(&c_data->dev->vc_enabled, 0);
atomic_set(&c_data->dev->vp_enabled, 0);
@@ -1540,7 +1538,9 @@
int cmd, void *arg)
{
struct vcap_client_data *c_data = to_client_data(file->private_data);
+ struct vcap_dev *dev = c_data->dev;
struct nr_param *param;
+ int val;
unsigned long flags = 0;
int ret;
@@ -1549,7 +1549,7 @@
if (c_data->streaming != 0 &&
(!(!((struct nr_param *) arg)->mode) !=
- !(!(c_data->vid_vp_action.nr_param.mode)))) {
+ !(!(c_data->vp_action.nr_param.mode)))) {
pr_err("ERR: Trying to toggle on/off while VP is already running");
return -EBUSY;
}
@@ -1562,22 +1562,28 @@
return ret;
}
param = (struct nr_param *) arg;
- c_data->vid_vp_action.nr_param = *param;
+ c_data->vp_action.nr_param = *param;
if (param->mode == NR_AUTO)
- s_default_nr_val(&c_data->vid_vp_action.nr_param);
- c_data->vid_vp_action.nr_update = true;
+ s_default_nr_val(&c_data->vp_action.nr_param);
+ c_data->vp_action.nr_update = true;
spin_unlock_irqrestore(&c_data->cap_slock, flags);
break;
case VCAPIOC_NR_G_PARAMS:
- *((struct nr_param *)arg) = c_data->vid_vp_action.nr_param;
- if (c_data->vid_vp_action.nr_param.mode != NR_DISABLE) {
+ *((struct nr_param *)arg) = c_data->vp_action.nr_param;
+ if (c_data->vp_action.nr_param.mode != NR_DISABLE) {
if (c_data->streaming)
nr_g_param(c_data, (struct nr_param *) arg);
else
(*(struct nr_param *) arg) =
- c_data->vid_vp_action.nr_param;
+ c_data->vp_action.nr_param;
}
break;
+ case VCAPIOC_S_NUM_VC_BUF:
+ val = (*(int *) arg);
+ if (val < VCAP_VC_MIN_BUF || val > VCAP_VC_MAX_BUF)
+ return -EINVAL;
+ dev->vc_tot_buf = (uint8_t) val;
+ break;
default:
return -EINVAL;
}
@@ -1663,9 +1669,9 @@
if (ret < 0)
goto vp_out_q_failed;
- INIT_LIST_HEAD(&c_data->vid_vc_action.active);
- INIT_LIST_HEAD(&c_data->vid_vp_action.in_active);
- INIT_LIST_HEAD(&c_data->vid_vp_action.out_active);
+ INIT_LIST_HEAD(&c_data->vc_action.active);
+ INIT_LIST_HEAD(&c_data->vp_action.in_active);
+ INIT_LIST_HEAD(&c_data->vp_action.out_active);
v4l2_fh_init(&c_data->vfh, dev->vfd);
v4l2_fh_add(&c_data->vfh);
@@ -1727,6 +1733,7 @@
mutex_unlock(&dev->dev_mutex);
if (ret == 0) {
vcap_disable(dev);
+ dev->vc_tot_buf = 2;
dev->vp_dummy_complete = false;
}
v4l2_fh_del(&c_data->vfh);
@@ -1968,6 +1975,7 @@
goto rel_vcap_wq;
}
+ dev->vc_tot_buf = 2;
atomic_set(&dev->vc_enabled, 0);
atomic_set(&dev->vp_enabled, 0);
atomic_set(&dev->open_clients, 0);
diff --git a/drivers/media/video/vcap_vc.c b/drivers/media/video/vcap_vc.c
index 62cc306..1825352 100644
--- a/drivers/media/video/vcap_vc.c
+++ b/drivers/media/video/vcap_vc.c
@@ -107,19 +107,42 @@
}
}
+static uint8_t correct_buf_num(uint32_t reg)
+{
+ int i;
+ bool block_found = false;
+ for (i = 0; i < VCAP_VC_MAX_BUF; i++) {
+ if (reg & (0x2 << i)) {
+ block_found = true;
+ continue;
+ }
+ if (block_found)
+ return i;
+ }
+ return 0;
+}
+
irqreturn_t vc_handler(struct vcap_dev *dev)
{
uint32_t irq, timestamp;
- enum rdy_buf vc_buf_status, buf_ind;
struct vcap_buffer *buf;
struct vb2_buffer *vb = NULL;
struct vcap_client_data *c_data;
struct v4l2_event v4l2_evt;
+ uint8_t i, idx, buf_num, tot, done_count = 0;
+ bool work_todo = false;
irq = readl_relaxed(VCAP_VC_INT_STATUS);
dprintk(1, "%s: irq=0x%08x\n", __func__, irq);
+ c_data = dev->vc_client;
+ if (!c_data->streaming) {
+ writel_iowmb(irq, VCAP_VC_INT_CLEAR);
+ pr_err("VC no longer streaming\n");
+ return IRQ_HANDLED;
+ }
+
v4l2_evt.id = 0;
if (irq & 0x8000200) {
v4l2_evt.type = V4L2_EVENT_PRIVATE_START +
@@ -147,107 +170,75 @@
v4l2_event_queue(dev->vfd, &v4l2_evt);
}
- vc_buf_status = irq & VC_BUFFER_WRITTEN;
- dprintk(1, "Done buf status = %d\n", vc_buf_status);
-
- if (vc_buf_status == VC_NO_BUF) {
+ if (!(irq & VC_BUFFER_MASK)) {
writel_relaxed(irq, VCAP_VC_INT_CLEAR);
pr_err("VC IRQ shows some error\n");
return IRQ_HANDLED;
}
if (dev->vc_client == NULL) {
+ /* This should never happen */
writel_relaxed(irq, VCAP_VC_INT_CLEAR);
pr_err("VC: There is no active vc client\n");
return IRQ_HANDLED;
}
c_data = dev->vc_client;
- spin_lock(&dev->vc_client->cap_slock);
- if (list_empty(&dev->vc_client->vid_vc_action.active)) {
- /* Just leave we have no new queued buffers */
- spin_unlock(&dev->vc_client->cap_slock);
- writel_relaxed(irq, VCAP_VC_INT_CLEAR);
- v4l2_evt.type = V4L2_EVENT_PRIVATE_START +
- VCAP_VC_BUF_OVERWRITE_EVENT;
- v4l2_event_queue(dev->vfd, &v4l2_evt);
- dprintk(1, "We have no more avilable buffers\n");
- return IRQ_HANDLED;
+ for (i = 0; i < VCAP_VC_MAX_BUF; i++) {
+ if (0x2 & (irq >> i))
+ done_count++;
}
- spin_unlock(&dev->vc_client->cap_slock);
+ /* Double check expected buffers are done */
+ buf_num = c_data->vc_action.buf_num;
+ tot = c_data->vc_action.tot_buf;
+ for (i = 0; i < done_count; i++) {
+ if (!(irq & (0x1 << (((buf_num + i) % tot) + 1)))) {
+ v4l2_evt.type = V4L2_EVENT_PRIVATE_START +
+ VCAP_VC_UNEXPECT_BUF_DONE;
+ v4l2_event_queue(dev->vfd, &v4l2_evt);
+ pr_debug("Unexpected buffer done\n");
+ c_data->vc_action.buf_num =
+ correct_buf_num(irq) % tot;
+ writel_relaxed(irq, VCAP_VC_INT_CLEAR);
+ return IRQ_HANDLED;
+ }
+ }
+
+ /* If here we know which buffers are done */
timestamp = readl_relaxed(VCAP_VC_TIMESTAMP);
- buf_ind = dev->vc_client->vid_vc_action.buf_ind;
-
- if (vc_buf_status == VC_BUF1N2) {
- /* There are 2 buffer ready */
- writel_relaxed(irq, VCAP_VC_INT_CLEAR);
- return IRQ_HANDLED;
- } else if (buf_ind != vc_buf_status) {
- /* buffer is out of sync */
- writel_relaxed(irq, VCAP_VC_INT_CLEAR);
- return IRQ_HANDLED;
- }
-
- if (buf_ind == VC_BUF1) {
- dprintk(1, "Got BUF1\n");
- vb = &dev->vc_client->vid_vc_action.buf1->vb;
- spin_lock(&dev->vc_client->cap_slock);
- if (list_empty(&dev->vc_client->vid_vc_action.active)) {
- spin_unlock(&dev->vc_client->cap_slock);
+ c_data->vc_action.buf_num = (buf_num + done_count) % tot;
+ for (i = 0; i < done_count; i++) {
+ idx = (buf_num + i) % tot;
+ vb = &c_data->vc_action.buf[idx]->vb;
+ spin_lock(&c_data->cap_slock);
+ if (list_empty(&c_data->vc_action.active)) {
+ spin_unlock(&c_data->cap_slock);
v4l2_evt.type = V4L2_EVENT_PRIVATE_START +
VCAP_VC_BUF_OVERWRITE_EVENT;
v4l2_event_queue(dev->vfd, &v4l2_evt);
- writel_relaxed(irq, VCAP_VC_INT_CLEAR);
- return IRQ_HANDLED;
+ continue;
}
- buf = list_entry(dev->vc_client->vid_vc_action.active.next,
+ buf = list_entry(c_data->vc_action.active.next,
struct vcap_buffer, list);
list_del(&buf->list);
- spin_unlock(&dev->vc_client->cap_slock);
+ spin_unlock(&c_data->cap_slock);
/* Config vc with this new buffer */
- config_buffer(c_data, buf, VCAP_VC_Y_ADDR_1,
- VCAP_VC_C_ADDR_1);
-
- vb->v4l2_buf.timestamp.tv_usec = timestamp;
+ config_buffer(c_data, buf, VCAP_VC_Y_ADDR_1 + 0x8 * idx,
+ VCAP_VC_C_ADDR_1 + 0x8 * idx);
+ vb->v4l2_buf.timestamp.tv_usec = timestamp -
+ 1000000 / c_data->vc_format.frame_rate *
+ (done_count - 1 - i);
vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
- dev->vc_client->vid_vc_action.buf1 = buf;
- dev->vc_client->vid_vc_action.buf_ind = VC_BUF2;
- irq = VC_BUF1;
- } else {
- dprintk(1, "Got BUF2\n");
- spin_lock(&dev->vc_client->cap_slock);
- vb = &dev->vc_client->vid_vc_action.buf2->vb;
- if (list_empty(&dev->vc_client->vid_vc_action.active)) {
- spin_unlock(&dev->vc_client->cap_slock);
- writel_relaxed(irq, VCAP_VC_INT_CLEAR);
- v4l2_evt.type = V4L2_EVENT_PRIVATE_START +
- VCAP_VC_BUF_OVERWRITE_EVENT;
- v4l2_event_queue(dev->vfd, &v4l2_evt);
- return IRQ_HANDLED;
- }
- buf = list_entry(dev->vc_client->vid_vc_action.active.next,
- struct vcap_buffer, list);
- list_del(&buf->list);
- spin_unlock(&dev->vc_client->cap_slock);
- /* Config vc with this new buffer */
- config_buffer(c_data, buf, VCAP_VC_Y_ADDR_2,
- VCAP_VC_C_ADDR_2);
-
- vb->v4l2_buf.timestamp.tv_usec = timestamp;
- vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
-
- dev->vc_client->vid_vc_action.buf2 = buf;
- dev->vc_client->vid_vc_action.buf_ind = VC_BUF1;
- irq = VC_BUF2;
+ work_todo = true;
+ c_data->vc_action.buf[idx] = buf;
}
- if (c_data->op_mode == VC_AND_VP_VCAP_OP)
+ if (work_todo && c_data->op_mode == VC_AND_VP_VCAP_OP)
queue_work(dev->vcap_wq, &dev->vc_to_vp_work.work);
writel_relaxed(irq, VCAP_VC_INT_CLEAR);
-
return IRQ_HANDLED;
}
@@ -258,73 +249,93 @@
int vc_hw_kick_off(struct vcap_client_data *c_data)
{
- struct vcap_action *vid_vc_action = &c_data->vid_vc_action;
+ struct vc_action *vc_action = &c_data->vc_action;
struct vcap_dev *dev;
unsigned long flags = 0;
- int rc, counter = 0;
+ int rc, i, counter = 0;
struct vcap_buffer *buf;
dev = c_data->dev;
- vid_vc_action->buf_ind = VC_BUF1;
dprintk(2, "Start Kickoff\n");
if (dev->vc_client == NULL) {
pr_err("No active vc client\n");
return -ENODEV;
}
+ c_data->vc_action.buf_num = 0;
spin_lock_irqsave(&dev->vc_client->cap_slock, flags);
- if (list_empty(&dev->vc_client->vid_vc_action.active)) {
+ if (list_empty(&dev->vc_client->vc_action.active)) {
spin_unlock_irqrestore(&dev->vc_client->cap_slock, flags);
pr_err("%s: VC We have no more avilable buffers\n",
__func__);
return -EINVAL;
}
- list_for_each_entry(buf, &vid_vc_action->active, list)
+ list_for_each_entry(buf, &vc_action->active, list)
counter++;
- if (counter < 2) {
+ if (counter < c_data->vc_action.tot_buf) {
/* not enough buffers have been queued */
spin_unlock_irqrestore(&dev->vc_client->cap_slock, flags);
return -EINVAL;
}
- vid_vc_action->buf1 = list_entry(vid_vc_action->active.next,
+ for (i = 0; i < c_data->vc_action.tot_buf; i++) {
+ vc_action->buf[i] = list_entry(vc_action->active.next,
struct vcap_buffer, list);
- list_del(&vid_vc_action->buf1->list);
-
- vid_vc_action->buf2 = list_entry(vid_vc_action->active.next,
- struct vcap_buffer, list);
- list_del(&vid_vc_action->buf2->list);
-
+ list_del(&vc_action->buf[i]->list);
+ }
spin_unlock_irqrestore(&dev->vc_client->cap_slock, flags);
- config_buffer(c_data, vid_vc_action->buf1, VCAP_VC_Y_ADDR_1,
- VCAP_VC_C_ADDR_1);
- config_buffer(c_data, vid_vc_action->buf2, VCAP_VC_Y_ADDR_2,
- VCAP_VC_C_ADDR_2);
+ for (i = 0; i < c_data->vc_action.tot_buf; i++) {
+ config_buffer(c_data, vc_action->buf[i],
+ VCAP_VC_Y_ADDR_1 + i * 8,
+ VCAP_VC_C_ADDR_1 + i * 8);
+ }
+ rc = 0;
+ for (i = 0; i < c_data->vc_action.tot_buf; i++)
+ rc = rc << 1 | 0x2;
+ writel_relaxed(rc, VCAP_VC_INT_MASK);
+
+ enable_irq(dev->vcirq->start);
rc = readl_relaxed(VCAP_VC_CTRL);
writel_iowmb(rc | 0x1, VCAP_VC_CTRL);
- writel_relaxed(0x6, VCAP_VC_INT_MASK);
-
- enable_irq(dev->vcirq->start);
return 0;
}
void vc_stop_capture(struct vcap_client_data *c_data)
{
struct vcap_dev *dev = c_data->dev;
- int rc;
+ unsigned int reg;
+ int timeout;
- rc = readl_relaxed(VCAP_VC_CTRL);
- writel_iowmb(rc & ~(0x1), VCAP_VC_CTRL);
-
- if (atomic_read(&dev->vc_enabled) == 1)
- disable_irq(dev->vcirq->start);
-
+ writel_iowmb(0x00000102, VCAP_VC_NPL_CTRL);
+ writel_iowmb(0x0, VCAP_VC_INT_MASK);
flush_workqueue(dev->vcap_wq);
+ if (atomic_read(&dev->vc_enabled) == 1)
+ disable_irq_nosync(dev->vcirq->start);
+
+ writel_iowmb(0x00000000, VCAP_VC_CTRL);
+ writel_iowmb(0x00000001, VCAP_SW_RESET_REQ);
+ timeout = 10000;
+ while (1) {
+ reg = (readl_relaxed(VCAP_SW_RESET_STATUS) & 0x1);
+ if (!reg)
+ break;
+ timeout--;
+ if (timeout == 0) {
+ /* This should not happen */
+ pr_err("VC is not resetting properly\n");
+ writel_iowmb(0x00000000, VCAP_SW_RESET_REQ);
+ break;
+ }
+ }
+
+ reg = readl_relaxed(VCAP_VC_NPL_CTRL);
+ reg = readl_relaxed(VCAP_VC_NPL_CTRL);
+ writel_iowmb(0x00000002, VCAP_VC_NPL_CTRL);
}
int config_vc_format(struct vcap_client_data *c_data)
@@ -336,21 +347,20 @@
dev = c_data->dev;
/* restart VC */
- writel_relaxed(0x00000001, VCAP_SW_RESET_REQ);
+ writel_iowmb(0x00000102, VCAP_VC_NPL_CTRL);
+ writel_iowmb(0x00000001, VCAP_SW_RESET_REQ);
timeout = 10000;
while (1) {
- rc = (readl_relaxed(VCAP_SW_RESET_STATUS) & 0x1);
- if (!rc)
+ if (!(readl_relaxed(VCAP_SW_RESET_STATUS) & 0x1))
break;
timeout--;
if (timeout == 0) {
pr_err("VC is not resetting properly\n");
+ writel_iowmb(0x00000002, VCAP_VC_NPL_CTRL);
return -EINVAL;
}
}
- writel_relaxed(0x00000000, VCAP_SW_RESET_REQ);
- writel_iowmb(0x00000102, VCAP_VC_NPL_CTRL);
rc = readl_relaxed(VCAP_VC_NPL_CTRL);
rc = readl_relaxed(VCAP_VC_NPL_CTRL);
writel_iowmb(0x00000002, VCAP_VC_NPL_CTRL);
@@ -359,7 +369,9 @@
writel_iowmb(0x00000002, VCAP_VC_NPL_CTRL);
writel_iowmb(0x00000004 | vc_format->color_space << 1 |
vc_format->mode << 3 |
- vc_format->mode << 10, VCAP_VC_CTRL);
+ (c_data->vc_action.tot_buf - 2) << 4 |
+ vc_format->mode << 10,
+ VCAP_VC_CTRL);
writel_relaxed(vc_format->h_polar << 4 |
vc_format->v_polar << 0, VCAP_VC_POLARITY);
diff --git a/drivers/media/video/vcap_vc.h b/drivers/media/video/vcap_vc.h
index 792fb14..7f42c7f 100644
--- a/drivers/media/video/vcap_vc.h
+++ b/drivers/media/video/vcap_vc.h
@@ -19,14 +19,8 @@
#define VCAP_HARDWARE_VERSION 0x10000000
-#define VCAP_BASE (dev->vcapbase)
-#define VCAP_OFFSET(off) (VCAP_BASE + off)
-
#define VCAP_HARDWARE_VERSION_REG (VCAP_BASE + 0x0000)
-#define VCAP_SW_RESET_REQ (VCAP_BASE + 0x0024)
-#define VCAP_SW_RESET_STATUS (VCAP_BASE + 0x0028)
-
#define VCAP_VC_CTRL (VCAP_BASE + 0x0800)
#define VCAP_VC_NPL_CTRL (VCAP_BASE + 0x0804)
#define VCAP_VC_POLARITY (VCAP_BASE + 0x081c)
@@ -68,6 +62,7 @@
#define VCAP_VC_TIMESTAMP (VCAP_BASE + 0x0034)
#define VC_BUFFER_WRITTEN (0x3 << 1)
+#define VC_BUFFER_MASK 0x7E
int vc_start_capture(struct vcap_client_data *c_data);
int vc_hw_kick_off(struct vcap_client_data *c_data);
diff --git a/drivers/media/video/vcap_vp.c b/drivers/media/video/vcap_vp.c
index ba053f2..12b3208 100644
--- a/drivers/media/video/vcap_vp.c
+++ b/drivers/media/video/vcap_vp.c
@@ -74,8 +74,14 @@
dev = c_data->dev;
dprintk(2, "Start setup buffers\n");
+ if (dev->vp_shutdown) {
+ dprintk(1, "%s: VP shutting down, no buf setup\n",
+ __func__);
+ return -EPERM;
+ }
+
/* No need to verify vp_client is not NULL caller does so */
- vp_act = &dev->vp_client->vid_vp_action;
+ vp_act = &dev->vp_client->vp_action;
spin_lock_irqsave(&dev->vp_client->cap_slock, flags);
if (list_empty(&vp_act->in_active)) {
@@ -167,7 +173,7 @@
{
struct vcap_dev *dev = c_data->dev;
struct nr_param *par;
- par = &c_data->vid_vp_action.nr_param;
+ par = &c_data->vp_action.nr_param;
if (par->mode == NR_MANUAL) {
writel_relaxed(par->window << 24 | par->decay_ratio << 20,
VCAP_VP_NR_CONFIG);
@@ -184,7 +190,7 @@
par->chroma.blend_limit_ratio << 0,
VCAP_VP_NR_CHROMA_CONFIG);
}
- c_data->vid_vp_action.nr_update = false;
+ c_data->vp_action.nr_update = false;
}
static void vp_wq_fnc(struct work_struct *work)
@@ -204,7 +210,7 @@
else
return;
- vp_act = &dev->vp_client->vid_vp_action;
+ vp_act = &dev->vp_client->vp_action;
rc = readl_relaxed(VCAP_OFFSET(0x048));
while (!(rc & 0x00000100))
@@ -238,7 +244,7 @@
#endif
/* Cycle Buffers*/
- if (vp_work->cd->vid_vp_action.nr_param.mode) {
+ if (vp_work->cd->vp_action.nr_param.mode) {
if (vp_act->bufNR.nr_pos == TM1_BUF)
vp_act->bufNR.nr_pos = BUF_NOT_IN_USE;
@@ -262,6 +268,8 @@
writel_relaxed(0x00000000, VCAP_VP_INTERRUPT_ENABLE);
writel_iowmb(irq, VCAP_VP_INT_CLEAR);
atomic_set(&dev->vp_enabled, 0);
+ if (dev->vp_shutdown)
+ wake_up(&dev->vp_dummy_waitq);
return;
}
@@ -332,7 +340,7 @@
return IRQ_HANDLED;
}
- vp_act = &dev->vp_client->vid_vp_action;
+ vp_act = &dev->vp_client->vp_action;
c_data = dev->vp_client;
if (vp_act->vp_state == VP_UNKNOWN) {
@@ -350,30 +358,60 @@
return IRQ_HANDLED;
}
+int vp_sw_reset(struct vcap_dev *dev)
+{
+ int timeout;
+ writel_iowmb(0x00000010, VCAP_SW_RESET_REQ);
+ timeout = 10000;
+ while (1) {
+ if (!(readl_relaxed(VCAP_SW_RESET_STATUS) & 0x10))
+ break;
+ timeout--;
+ if (timeout == 0) {
+ /* This should not happen */
+ pr_err("VP is not resetting properly\n");
+ writel_iowmb(0x00000000, VCAP_SW_RESET_REQ);
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
void vp_stop_capture(struct vcap_client_data *c_data)
{
struct vcap_dev *dev = c_data->dev;
+ int rc;
- writel_iowmb(0x00000000, VCAP_VP_CTRL);
+ dev->vp_shutdown = true;
flush_workqueue(dev->vcap_wq);
- if (atomic_read(&dev->vp_enabled) == 1)
- disable_irq(dev->vpirq->start);
+ if (atomic_read(&dev->vp_enabled) == 1) {
+ rc = wait_event_interruptible_timeout(dev->vp_dummy_waitq,
+ !atomic_read(&dev->vp_enabled),
+ msecs_to_jiffies(50));
+ if (rc == 0 && atomic_read(&dev->vp_enabled) == 1) {
+ /* This should not happen, if it does hw is stuck */
+ pr_err("%s: VP Timeout and VP still running\n",
+ __func__);
+ }
+ }
- writel_iowmb(0x00000001, VCAP_VP_SW_RESET);
- writel_iowmb(0x00000000, VCAP_VP_SW_RESET);
+ vp_sw_reset(dev);
+ dev->vp_shutdown = false;
}
int config_vp_format(struct vcap_client_data *c_data)
{
struct vcap_dev *dev = c_data->dev;
+ int rc;
INIT_WORK(&dev->vp_to_vc_work.work, mov_buf_to_vc);
dev->vp_to_vc_work.cd = c_data;
/* SW restart VP */
- writel_iowmb(0x00000001, VCAP_VP_SW_RESET);
- writel_iowmb(0x00000000, VCAP_VP_SW_RESET);
+ rc = vp_sw_reset(dev);
+ if (rc < 0)
+ return rc;
/* Film Mode related settings */
writel_iowmb(0x00000000, VCAP_VP_FILM_PROJECTION_T0);
@@ -429,7 +467,7 @@
size_t size = ((c_data->vp_out_fmt.width + 63) >> 6) *
((c_data->vp_out_fmt.height + 7) >> 3) * 16;
- if (c_data->vid_vp_action.motionHandle) {
+ if (c_data->vp_action.motionHandle) {
pr_err("Motion buffer has already been created");
return -ENOEXEC;
}
@@ -463,7 +501,7 @@
}
memset(vaddr, 0, size);
- c_data->vid_vp_action.motionHandle = handle;
+ c_data->vp_action.motionHandle = handle;
vaddr = NULL;
ion_unmap_kernel(dev->ion_client, handle);
@@ -475,14 +513,14 @@
void deinit_motion_buf(struct vcap_client_data *c_data)
{
struct vcap_dev *dev = c_data->dev;
- if (!c_data->vid_vp_action.motionHandle) {
+ if (!c_data->vp_action.motionHandle) {
pr_err("Motion buffer has not been created");
return;
}
writel_iowmb(0x00000000, VCAP_VP_MOTION_EST_ADDR);
- ion_free(dev->ion_client, c_data->vid_vp_action.motionHandle);
- c_data->vid_vp_action.motionHandle = NULL;
+ ion_free(dev->ion_client, c_data->vp_action.motionHandle);
+ c_data->vp_action.motionHandle = NULL;
return;
}
@@ -494,7 +532,7 @@
unsigned long paddr;
int rc;
- if (c_data->vid_vp_action.bufNR.nr_handle) {
+ if (c_data->vp_action.bufNR.nr_handle) {
pr_err("NR buffer has already been created");
return -ENOEXEC;
}
@@ -519,16 +557,16 @@
return rc;
}
- c_data->vid_vp_action.bufNR.nr_handle = handle;
+ c_data->vp_action.bufNR.nr_handle = handle;
update_nr_value(c_data);
- c_data->vid_vp_action.bufNR.paddr = paddr;
+ c_data->vp_action.bufNR.paddr = paddr;
rc = readl_relaxed(VCAP_VP_NR_CONFIG2);
rc |= (((c_data->vp_out_fmt.width / 16) << 20) | 0x1);
writel_relaxed(rc, VCAP_VP_NR_CONFIG2);
writel_relaxed(paddr, VCAP_VP_NR_T2_Y_BASE_ADDR);
writel_relaxed(paddr + frame_size, VCAP_VP_NR_T2_C_BASE_ADDR);
- c_data->vid_vp_action.bufNR.nr_pos = NRT2_BUF;
+ c_data->vp_action.bufNR.nr_pos = NRT2_BUF;
return 0;
}
@@ -538,11 +576,11 @@
struct nr_buffer *buf;
uint32_t rc;
- if (!c_data->vid_vp_action.bufNR.nr_handle) {
+ if (!c_data->vp_action.bufNR.nr_handle) {
pr_err("NR buffer has not been created");
return;
}
- buf = &c_data->vid_vp_action.bufNR;
+ buf = &c_data->vp_action.bufNR;
rc = readl_relaxed(VCAP_VP_NR_CONFIG2);
rc &= !(0x0FF00001);
@@ -668,20 +706,18 @@
dev->vp_dummy_event = true;
+ enable_irq(dev->vpirq->start);
writel_relaxed(0x01100101, VCAP_VP_INTERRUPT_ENABLE);
writel_iowmb(0x00000000, VCAP_VP_CTRL);
writel_iowmb(0x00010000, VCAP_VP_CTRL);
- enable_irq(dev->vpirq->start);
rc = wait_event_interruptible_timeout(dev->vp_dummy_waitq,
dev->vp_dummy_complete, msecs_to_jiffies(50));
if (!rc && !dev->vp_dummy_complete) {
pr_err("%s: VP dummy event timeout", __func__);
rc = -ETIME;
- writel_iowmb(0x00000000, VCAP_VP_CTRL);
- writel_iowmb(0x00000001, VCAP_VP_SW_RESET);
- writel_iowmb(0x00000000, VCAP_VP_SW_RESET);
+ vp_sw_reset(dev);
dev->vp_dummy_complete = false;
}
@@ -721,7 +757,7 @@
pr_err("No active vp client\n");
return -ENODEV;
}
- vp_act = &dev->vp_client->vid_vp_action;
+ vp_act = &dev->vp_client->vp_action;
spin_lock_irqsave(&dev->vp_client->cap_slock, flags);
if (list_empty(&vp_act->in_active)) {
@@ -818,7 +854,7 @@
pr_err("No active vp client\n");
return -ENODEV;
}
- vp_act = &dev->vp_client->vid_vp_action;
+ vp_act = &dev->vp_client->vp_action;
if (vp_act->vp_state == VP_UNKNOWN) {
pr_err("%s: VP is in an unknown state\n",
diff --git a/drivers/media/video/vcap_vp.h b/drivers/media/video/vcap_vp.h
index b2b00e9..2ad5848 100644
--- a/drivers/media/video/vcap_vp.h
+++ b/drivers/media/video/vcap_vp.h
@@ -17,9 +17,6 @@
#include <media/vcap_v4l2.h>
-#define VCAP_BASE (dev->vcapbase)
-#define VCAP_OFFSET(off) (VCAP_BASE + off)
-
#define VCAP_VP_INT_STATUS (VCAP_BASE + 0x404)
#define VCAP_VP_INT_CLEAR (VCAP_BASE + 0x40C)
diff --git a/drivers/mfd/pm8018-core.c b/drivers/mfd/pm8018-core.c
index b1b64cb..a91152f 100644
--- a/drivers/mfd/pm8018-core.c
+++ b/drivers/mfd/pm8018-core.c
@@ -45,7 +45,6 @@
#define PM8018_REVISION_MASK 0x000F
#define REG_PM8018_PON_CNTRL_3 0x01D
-#define PM8018_RESTART_REASON_MASK 0x07
#define SINGLE_IRQ_RESOURCE(_name, _irq) \
{ \
@@ -61,6 +60,7 @@
struct mfd_cell *mfd_regulators;
struct pm8xxx_regulator_core_platform_data *regulator_cdata;
u32 rev_registers;
+ u8 restart_reason;
};
static int pm8018_readb(const struct device *dev, u16 addr, u8 *val)
@@ -125,6 +125,14 @@
return pmic->rev_registers & PM8018_REVISION_MASK;
}
+static u8 pm8018_restart_reason(const struct device *dev)
+{
+ const struct pm8xxx_drvdata *pm8018_drvdata = dev_get_drvdata(dev);
+ const struct pm8018 *pmic = pm8018_drvdata->pm_chip_data;
+
+ return pmic->restart_reason;
+}
+
static struct pm8xxx_drvdata pm8018_drvdata = {
.pmic_readb = pm8018_readb,
.pmic_writeb = pm8018_writeb,
@@ -133,6 +141,7 @@
.pmic_read_irq_stat = pm8018_read_irq_stat,
.pmic_get_version = pm8018_get_version,
.pmic_get_revision = pm8018_get_revision,
+ .pmic_restart_reason = pm8018_restart_reason,
};
static const struct resource gpio_cell_resources[] __devinitconst = {
@@ -516,17 +525,6 @@
return ret;
}
-static const char * const pm8018_restart_reason[] = {
- [0] = "Unknown",
- [1] = "Triggered from CBL (external charger)",
- [2] = "Triggered from KPD (power key press)",
- [3] = "Triggered from CHG (usb charger insertion)",
- [4] = "Triggered from SMPL (sudden momentary power loss)",
- [5] = "Triggered from RTC (real time clock)",
- [6] = "Triggered by Hard Reset",
- [7] = "Triggered by General Purpose Trigger",
-};
-
static const char * const pm8018_rev_names[] = {
[PM8XXX_REVISION_8018_TEST] = "test",
[PM8XXX_REVISION_8018_1p0] = "1.0",
@@ -594,8 +592,9 @@
pr_err("Cannot read restart reason rc=%d\n", rc);
goto err_read_rev;
}
- val &= PM8018_RESTART_REASON_MASK;
- pr_info("PMIC Restart Reason: %s\n", pm8018_restart_reason[val]);
+ val &= PM8XXX_RESTART_REASON_MASK;
+ pr_info("PMIC Restart Reason: %s\n", pm8xxx_restart_reason_str[val]);
+ pmic->restart_reason = val;
rc = pm8018_add_subdevices(pdata, pmic);
if (rc) {
diff --git a/drivers/mfd/pm8038-core.c b/drivers/mfd/pm8038-core.c
index b32932b..712a772 100644
--- a/drivers/mfd/pm8038-core.c
+++ b/drivers/mfd/pm8038-core.c
@@ -44,7 +44,6 @@
#define PM8038_REVISION_MASK 0x000F
#define REG_PM8038_PON_CNTRL_3 0x01D
-#define PM8038_RESTART_REASON_MASK 0x07
#define SINGLE_IRQ_RESOURCE(_name, _irq) \
{ \
@@ -60,6 +59,7 @@
struct mfd_cell *mfd_regulators;
struct pm8xxx_regulator_core_platform_data *regulator_cdata;
u32 rev_registers;
+ u8 restart_reason;
};
static int pm8038_readb(const struct device *dev, u16 addr, u8 *val)
@@ -124,6 +124,14 @@
return pmic->rev_registers & PM8038_REVISION_MASK;
}
+static u8 pm8038_restart_reason(const struct device *dev)
+{
+ const struct pm8xxx_drvdata *pm8038_drvdata = dev_get_drvdata(dev);
+ const struct pm8038 *pmic = pm8038_drvdata->pm_chip_data;
+
+ return pmic->restart_reason;
+}
+
static struct pm8xxx_drvdata pm8038_drvdata = {
.pmic_readb = pm8038_readb,
.pmic_writeb = pm8038_writeb,
@@ -132,6 +140,7 @@
.pmic_read_irq_stat = pm8038_read_irq_stat,
.pmic_get_version = pm8038_get_version,
.pmic_get_revision = pm8038_get_revision,
+ .pmic_restart_reason = pm8038_restart_reason,
};
static const struct resource gpio_cell_resources[] __devinitconst = {
@@ -674,17 +683,6 @@
return ret;
}
-static const char * const pm8038_restart_reason[] = {
- [0] = "Unknown",
- [1] = "Triggered from CBL (external charger)",
- [2] = "Triggered from KPD (power key press)",
- [3] = "Triggered from CHG (usb charger insertion)",
- [4] = "Triggered from SMPL (sudden momentary power loss)",
- [5] = "Triggered from RTC (real time clock)",
- [6] = "Triggered by Hard Reset",
- [7] = "Triggered by General Purpose Trigger",
-};
-
static const char * const pm8038_rev_names[] = {
[PM8XXX_REVISION_8038_TEST] = "test",
[PM8XXX_REVISION_8038_1p0] = "1.0",
@@ -753,8 +751,9 @@
pr_err("Cannot read restart reason rc=%d\n", rc);
goto err_read_rev;
}
- val &= PM8038_RESTART_REASON_MASK;
- pr_info("PMIC Restart Reason: %s\n", pm8038_restart_reason[val]);
+ val &= PM8XXX_RESTART_REASON_MASK;
+ pr_info("PMIC Restart Reason: %s\n", pm8xxx_restart_reason_str[val]);
+ pmic->restart_reason = val;
rc = pm8038_add_subdevices(pdata, pmic);
if (rc) {
diff --git a/drivers/mfd/pm8821-core.c b/drivers/mfd/pm8821-core.c
index 1d3c927a..86bd5ec 100644
--- a/drivers/mfd/pm8821-core.c
+++ b/drivers/mfd/pm8821-core.c
@@ -29,6 +29,9 @@
#define REG_MPP_BASE 0x050
#define REG_IRQ_BASE 0x100
+#define REG_TEMP_ALARM_CTRL 0x01B
+#define REG_TEMP_ALARM_PWM 0x09B
+
#define PM8821_VERSION_MASK 0xFFF0
#define PM8821_VERSION_VALUE 0x0BF0
#define PM8821_REVISION_MASK 0x000F
@@ -142,6 +145,29 @@
.pdata_size = sizeof("pm8821-dbg"),
};
+static const struct resource thermal_alarm_cell_resources[] __devinitconst = {
+ SINGLE_IRQ_RESOURCE("pm8821_tempstat_irq", PM8821_TEMPSTAT_IRQ),
+ SINGLE_IRQ_RESOURCE("pm8821_overtemp_irq", PM8821_OVERTEMP_IRQ),
+};
+
+static struct pm8xxx_tm_core_data thermal_alarm_cdata = {
+ .adc_type = PM8XXX_TM_ADC_NONE,
+ .reg_addr_temp_alarm_ctrl = REG_TEMP_ALARM_CTRL,
+ .reg_addr_temp_alarm_pwm = REG_TEMP_ALARM_PWM,
+ .tm_name = "pm8821_tz",
+ .irq_name_temp_stat = "pm8821_tempstat_irq",
+ .irq_name_over_temp = "pm8821_overtemp_irq",
+ .default_no_adc_temp = 37000,
+};
+
+static struct mfd_cell thermal_alarm_cell __devinitdata = {
+ .name = PM8XXX_TM_DEV_NAME,
+ .id = 1,
+ .resources = thermal_alarm_cell_resources,
+ .num_resources = ARRAY_SIZE(thermal_alarm_cell_resources),
+ .platform_data = &thermal_alarm_cdata,
+ .pdata_size = sizeof(struct pm8xxx_tm_core_data),
+};
static int __devinit
pm8821_add_subdevices(const struct pm8821_platform_data *pdata,
@@ -183,6 +209,14 @@
goto bail;
}
+ ret = mfd_add_devices(pmic->dev, 0, &thermal_alarm_cell, 1, NULL,
+ irq_base);
+ if (ret) {
+ pr_err("Failed to add thermal alarm subdevice ret=%d\n",
+ ret);
+ goto bail;
+ }
+
return 0;
bail:
if (pmic->irq_chip) {
diff --git a/drivers/mfd/pm8921-core.c b/drivers/mfd/pm8921-core.c
index f39a19f..7d63129 100644
--- a/drivers/mfd/pm8921-core.c
+++ b/drivers/mfd/pm8921-core.c
@@ -63,6 +63,7 @@
struct mfd_cell *mfd_regulators;
struct pm8xxx_regulator_core_platform_data *regulator_cdata;
u32 rev_registers;
+ u8 restart_reason;
};
static int pm8921_readb(const struct device *dev, u16 addr, u8 *val)
@@ -133,6 +134,14 @@
return pmic->rev_registers & PM8921_REVISION_MASK;
}
+static u8 pm8921_restart_reason(const struct device *dev)
+{
+ const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev);
+ const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data;
+
+ return pmic->restart_reason;
+}
+
static struct pm8xxx_drvdata pm8921_drvdata = {
.pmic_readb = pm8921_readb,
.pmic_writeb = pm8921_writeb,
@@ -141,6 +150,7 @@
.pmic_read_irq_stat = pm8921_read_irq_stat,
.pmic_get_version = pm8921_get_version,
.pmic_get_revision = pm8921_get_revision,
+ .pmic_restart_reason = pm8921_restart_reason,
};
static struct resource gpio_cell_resources[] = {
@@ -815,17 +825,6 @@
return ret;
}
-static const char * const pm8921_restart_reason[] = {
- [0] = "Unknown",
- [1] = "Triggered from CBL (external charger)",
- [2] = "Triggered from KPD (power key press)",
- [3] = "Triggered from CHG (usb charger insertion)",
- [4] = "Triggered from SMPL (sudden momentary power loss)",
- [5] = "Triggered from RTC (real time clock)",
- [6] = "Triggered by Hard Reset",
- [7] = "Triggered by General Purpose Trigger",
-};
-
static const char * const pm8921_rev_names[] = {
[PM8XXX_REVISION_8921_TEST] = "test",
[PM8XXX_REVISION_8921_1p0] = "1.0",
@@ -918,8 +917,9 @@
pr_err("Cannot read restart reason rc=%d\n", rc);
goto err_read_rev;
}
- val &= PM8921_RESTART_REASON_MASK;
- pr_info("PMIC Restart Reason: %s\n", pm8921_restart_reason[val]);
+ val &= PM8XXX_RESTART_REASON_MASK;
+ pr_info("PMIC Restart Reason: %s\n", pm8xxx_restart_reason_str[val]);
+ pmic->restart_reason = val;
rc = pm8921_add_subdevices(pdata, pmic);
if (rc) {
diff --git a/drivers/mfd/pm8xxx-misc.c b/drivers/mfd/pm8xxx-misc.c
index 0af013e..6bb1441 100644
--- a/drivers/mfd/pm8xxx-misc.c
+++ b/drivers/mfd/pm8xxx-misc.c
@@ -564,6 +564,7 @@
: SLEEP_CTRL_SMPL_EN_PWR_OFF));
break;
case PM8XXX_VERSION_8921:
+ case PM8XXX_VERSION_8917:
rc = pm8xxx_misc_masked_write(chip,
REG_PM8921_SLEEP_CTRL, SLEEP_CTRL_SMPL_EN_MASK,
(enable ? SLEEP_CTRL_SMPL_EN_RESET
@@ -624,6 +625,7 @@
delay);
break;
case PM8XXX_VERSION_8921:
+ case PM8XXX_VERSION_8917:
rc = pm8xxx_misc_masked_write(chip,
REG_PM8921_SLEEP_CTRL, SLEEP_CTRL_SMPL_SEL_MASK,
delay);
@@ -703,6 +705,7 @@
REG_PM8058_COIN_CHG, reg);
break;
case PM8XXX_VERSION_8921:
+ case PM8XXX_VERSION_8917:
rc = pm8xxx_writeb(chip->dev->parent,
REG_PM8921_COIN_CHG, reg);
break;
@@ -747,6 +750,7 @@
case PM8XXX_VERSION_8018:
case PM8XXX_VERSION_8058:
case PM8XXX_VERSION_8921:
+ case PM8XXX_VERSION_8917:
rc = pm8xxx_misc_masked_write(chip,
REG_PM8XXX_PON_CTRL_1, PON_CTRL_1_WD_EN_MASK,
(enable ? PON_CTRL_1_WD_EN_RESET
@@ -793,6 +797,7 @@
case PM8XXX_VERSION_8018:
case PM8XXX_VERSION_8058:
case PM8XXX_VERSION_8921:
+ case PM8XXX_VERSION_8917:
rc = pm8xxx_writeb(chip->dev->parent,
REG_PM8XXX_GP_TEST_1, PM8XXX_STAY_ON_CFG);
break;
@@ -884,6 +889,7 @@
REG_PM8901_PON_CNTL_4, REG_PM8901_PON_CNTL_5);
break;
case PM8XXX_VERSION_8921:
+ case PM8XXX_VERSION_8917:
__pm8xxx_hard_reset_config(chip, config,
REG_PM8921_PON_CNTL_4, REG_PM8921_PON_CNTL_5);
break;
@@ -941,6 +947,7 @@
case PM8XXX_VERSION_8018:
case PM8XXX_VERSION_8058:
case PM8XXX_VERSION_8921:
+ case PM8XXX_VERSION_8917:
rc = pm8xxx_misc_masked_write(chip,
REG_PM8XXX_GPIO_MUX_CTRL, UART_PATH_SEL_MASK,
uart_path_sel << UART_PATH_SEL_SHIFT);
@@ -1091,6 +1098,7 @@
switch (chip->version) {
case PM8XXX_VERSION_8038:
case PM8XXX_VERSION_8921:
+ case PM8XXX_VERSION_8917:
pm8xxx_misc_masked_write(chip,
REG_PM8XXX_XO_CNTRL_2, clk_mask, value);
break;
diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c
index b56f081..35ae29a 100644
--- a/drivers/mfd/wcd9xxx-core.c
+++ b/drivers/mfd/wcd9xxx-core.c
@@ -27,9 +27,9 @@
#include <linux/i2c.h>
#include <sound/soc.h>
-#define WCD9XXX_SLIM_GLA_MAX_RETRIES 5
#define WCD9XXX_REGISTER_START_OFFSET 0x800
#define WCD9XXX_SLIM_RW_MAX_TRIES 3
+#define SLIMBUS_PRESENT_TIMEOUT 100
#define MAX_WCD9XXX_DEVICE 4
#define TABLA_I2C_MODE 0x03
@@ -283,8 +283,6 @@
return ret;
}
- gpio_direction_output(wcd9xxx->reset_gpio, 1);
- msleep(20);
gpio_direction_output(wcd9xxx->reset_gpio, 0);
msleep(20);
gpio_direction_output(wcd9xxx->reset_gpio, 1);
@@ -1054,12 +1052,31 @@
return NULL;
}
+static int wcd9xxx_slim_get_laddr(struct slim_device *sb,
+ const u8 *e_addr, u8 e_len, u8 *laddr)
+{
+ int ret;
+ const unsigned long timeout = jiffies +
+ msecs_to_jiffies(SLIMBUS_PRESENT_TIMEOUT);
+
+ do {
+ ret = slim_get_logical_addr(sb, e_addr, e_len, laddr);
+ if (!ret)
+ break;
+ /* Give SLIMBUS time to report present and be ready. */
+ usleep_range(1000, 1000);
+ pr_debug_ratelimited("%s: retyring get logical addr\n",
+ __func__);
+ } while time_before(jiffies, timeout);
+
+ return ret;
+}
+
static int wcd9xxx_slim_probe(struct slim_device *slim)
{
struct wcd9xxx *wcd9xxx;
struct wcd9xxx_pdata *pdata;
int ret = 0;
- int sgla_retry_cnt;
if (slim->dev.of_node) {
dev_info(&slim->dev, "Platform data from device tree\n");
@@ -1104,10 +1121,12 @@
goto err_supplies;
}
- ret = slim_get_logical_addr(wcd9xxx->slim, wcd9xxx->slim->e_addr,
- ARRAY_SIZE(wcd9xxx->slim->e_addr), &wcd9xxx->slim->laddr);
+ ret = wcd9xxx_slim_get_laddr(wcd9xxx->slim, wcd9xxx->slim->e_addr,
+ ARRAY_SIZE(wcd9xxx->slim->e_addr),
+ &wcd9xxx->slim->laddr);
if (ret) {
- pr_err("fail to get slimbus logical address %d\n", ret);
+ pr_err("%s: failed to get slimbus %s logical address: %d\n",
+ __func__, wcd9xxx->slim->name, ret);
goto err_reset;
}
wcd9xxx->read_dev = wcd9xxx_slim_read_device;
@@ -1116,11 +1135,8 @@
wcd9xxx->irq_base = pdata->irq_base;
wcd9xxx_pgd_la = wcd9xxx->slim->laddr;
- if (pdata->num_irqs < TABLA_NUM_IRQS) {
- pr_err("%s: Error, not enough interrupt lines allocated\n",
- __func__);
- goto err_reset;
- }
+ if (pdata->num_irqs < TABLA_NUM_IRQS)
+ pr_warn("%s: Not enough interrupt lines allocated\n", __func__);
wcd9xxx->slim_slave = &pdata->slimbus_slave_device;
@@ -1130,28 +1146,14 @@
goto err_reset;
}
- sgla_retry_cnt = 0;
-
- while (1) {
- ret = slim_get_logical_addr(wcd9xxx->slim_slave,
- wcd9xxx->slim_slave->e_addr,
- ARRAY_SIZE(wcd9xxx->slim_slave->e_addr),
- &wcd9xxx->slim_slave->laddr);
- if (ret) {
- if (sgla_retry_cnt++ < WCD9XXX_SLIM_GLA_MAX_RETRIES) {
- /* Give SLIMBUS slave time to report present
- and be ready.
- */
- usleep_range(1000, 1000);
- pr_debug("%s: retry slim_get_logical_addr()\n",
- __func__);
- continue;
- }
- pr_err("fail to get slimbus slave logical address"
- " %d\n", ret);
- goto err_slim_add;
- }
- break;
+ ret = wcd9xxx_slim_get_laddr(wcd9xxx->slim_slave,
+ wcd9xxx->slim_slave->e_addr,
+ ARRAY_SIZE(wcd9xxx->slim_slave->e_addr),
+ &wcd9xxx->slim_slave->laddr);
+ if (ret) {
+ pr_err("%s: failed to get slimbus %s logical address: %d\n",
+ __func__, wcd9xxx->slim->name, ret);
+ goto err_slim_add;
}
wcd9xxx_inf_la = wcd9xxx->slim_slave->laddr;
wcd9xxx_intf = WCD9XXX_INTERFACE_TYPE_SLIMBUS;
diff --git a/drivers/misc/tspp.c b/drivers/misc/tspp.c
index cc65929..1792104 100644
--- a/drivers/misc/tspp.c
+++ b/drivers/misc/tspp.c
@@ -10,58 +10,54 @@
* GNU General Public License for more details.
*/
-#include <linux/module.h> /* Needed by all modules */
-#include <linux/kernel.h> /* Needed for KERN_INFO */
-#include <linux/init.h> /* Needed for the macros */
+#include <linux/module.h> /* Just for modules */
+#include <linux/kernel.h> /* Only for KERN_INFO */
+#include <linux/err.h> /* Error macros */
+#include <linux/list.h> /* Linked list */
#include <linux/cdev.h>
-#include <linux/err.h> /* IS_ERR */
+#include <linux/init.h> /* Needed for the macros */
+#include <linux/io.h> /* IO macros */
+#include <linux/device.h> /* Device drivers need this */
+#include <linux/sched.h> /* Externally defined globals */
+#include <linux/pm_runtime.h> /* Runtime power management */
#include <linux/fs.h>
-#include <linux/device.h>
-#include <linux/sched.h> /* TASK_INTERRUPTIBLE */
-#include <linux/uaccess.h> /* copy_to_user */
-#include <linux/platform_device.h>
-#include <linux/pm_runtime.h>
+#include <linux/uaccess.h> /* copy_to_user */
#include <linux/slab.h> /* kfree, kzalloc */
-#include <linux/wakelock.h>
-#include <linux/io.h> /* ioXXX */
-#include <linux/ioport.h> /* XXX_ mem_region */
-#include <linux/dma-mapping.h> /* dma_XXX */
-#include <linux/delay.h> /* msleep */
+#include <linux/ioport.h> /* XXX_ mem_region */
+#include <linux/dma-mapping.h> /* dma_XXX */
+#include <linux/delay.h> /* msleep */
+#include <linux/platform_device.h>
#include <linux/clk.h>
-#include <linux/poll.h> /* poll() file op */
-#include <linux/wait.h> /* wait() macros, sleeping */
-#include <linux/tspp.h> /* tspp functions */
+#include <linux/poll.h> /* poll() file op */
+#include <linux/wait.h> /* wait() macros, sleeping */
+#include <linux/tspp.h> /* tspp functions */
#include <linux/bitops.h> /* BIT() macro */
-#include <mach/sps.h> /* BAM stuff */
+#include <mach/sps.h> /* BAM stuff */
#include <mach/gpio.h>
+#include <linux/wakelock.h> /* Locking functions */
#include <mach/dma.h>
#include <mach/msm_tspp.h>
-
-#define TSPP_USE_DEBUGFS
-#ifdef TSPP_USE_DEBUGFS
#include <linux/debugfs.h>
-#endif /* TSPP_USE_DEBUGFS */
/*
* General defines
*/
-#define TSPP_USE_DMA_ALLOC_COHERENT
#define TSPP_TSIF_INSTANCES 2
#define TSPP_FILTER_TABLES 3
-#define TSPP_MAX_DEVICES 3
+#define TSPP_MAX_DEVICES 1
#define TSPP_NUM_CHANNELS 16
#define TSPP_NUM_PRIORITIES 16
#define TSPP_NUM_KEYS 8
#define INVALID_CHANNEL 0xFFFFFFFF
-#define TSPP_SPS_DESCRIPTOR_COUNT 32
+#define TSPP_SPS_DESCRIPTOR_COUNT 128
#define TSPP_PACKET_LENGTH 188
#define TSPP_MIN_BUFFER_SIZE (TSPP_PACKET_LENGTH)
-#define TSPP_MAX_BUFFER_SIZE (16 * 1024) /* maybe allow 64K? */
-#define TSPP_NUM_BUFFERS 16
+#define TSPP_MAX_BUFFER_SIZE (32 * 1024)
+#define TSPP_NUM_BUFFERS 64
#define TSPP_TSIF_DEFAULT_TIME_LIMIT 60
#define SPS_DESCRIPTOR_SIZE 8
#define MIN_ACCEPTABLE_BUFFER_COUNT 2
-#define TSPP_DEBUG(msg...) pr_info(msg)
+#define TSPP_DEBUG(msg...)
/*
* TSIF register offsets
@@ -99,6 +95,7 @@
#define TSIF_STS_CTL_EN_TIME_LIM BIT(8)
#define TSIF_STS_CTL_EN_TCR BIT(7)
#define TSIF_STS_CTL_TEST_MODE BIT(6)
+#define TSIF_STS_CTL_MODE_2 BIT(5)
#define TSIF_STS_CTL_EN_DM BIT(4)
#define TSIF_STS_CTL_STOP BIT(3)
#define TSIF_STS_CTL_START BIT(0)
@@ -212,7 +209,6 @@
#define TSPP_TSP_BUFF_WORD(_n) (0xC10 + (_n << 2))
#define TSPP_DATA_KEY 0xCD0
-#ifdef TSPP_USE_DEBUGFS
struct debugfs_entry {
const char *name;
mode_t mode;
@@ -265,8 +261,6 @@
{"data_key", S_IRUGO | S_IWUSR, TSPP_DATA_KEY}
};
-#endif /* TSPP_USE_DEBUGFS */
-
struct tspp_pid_filter {
u32 filter; /* see FILTER_ macros */
u32 config; /* see FILTER_ macros */
@@ -328,44 +322,24 @@
void __iomem *base;
u32 time_limit;
u32 ref_count;
+ enum tspp_tsif_mode mode;
/* debugfs */
-#ifdef TSPP_USE_DEBUGFS
struct dentry *dent_tsif;
struct dentry *debugfs_tsif_regs[ARRAY_SIZE(debugfs_tsif_regs)];
-#endif /* TSPP_USE_DEBUGFS */
-};
-
-/* this represents the actual hardware device */
-struct tspp_device {
- struct platform_device *pdev;
- void __iomem *base;
- unsigned int tspp_irq;
- unsigned int bam_irq;
- u32 bam_handle;
- struct sps_bam_props bam_props;
- struct wake_lock wake_lock;
- spinlock_t spinlock;
- struct tasklet_struct tlet;
- struct tspp_tsif_device tsif[TSPP_TSIF_INSTANCES];
- /* clocks */
- struct clk *tsif_pclk;
- struct clk *tsif_ref_clk;
-
-#ifdef TSPP_USE_DEBUGFS
- struct dentry *dent;
- struct dentry *debugfs_regs[ARRAY_SIZE(debugfs_tspp_regs)];
-#endif /* TSPP_USE_DEBUGFS */
};
enum tspp_buf_state {
TSPP_BUF_STATE_EMPTY, /* buffer has been allocated, but not waiting */
TSPP_BUF_STATE_WAITING, /* buffer is waiting to be filled */
- TSPP_BUF_STATE_DATA /* buffer is not empty and can be read */
+ TSPP_BUF_STATE_DATA, /* buffer is not empty and can be read */
+ TSPP_BUF_STATE_LOCKED /* buffer is being read by a client */
};
struct tspp_mem_buffer {
- struct sps_mem_buffer mem;
+ struct tspp_mem_buffer *next;
+ struct sps_mem_buffer sps;
+ struct tspp_data_descriptor desc; /* buffer descriptor for kernel api */
enum tspp_buf_state state;
size_t filled; /* how much data this buffer is holding */
int read_index; /* where to start reading data from */
@@ -375,22 +349,28 @@
struct tspp_channel {
struct cdev cdev;
struct device *dd;
- struct tspp_device *pdev;
+ struct tspp_device *pdev; /* can use container_of instead? */
struct sps_pipe *pipe;
struct sps_connect config;
struct sps_register_event event;
- struct tspp_mem_buffer buffer[TSPP_NUM_BUFFERS];
+ struct tspp_mem_buffer *data; /* list of buffers */
+ struct tspp_mem_buffer *read; /* first buffer ready to be read */
+ struct tspp_mem_buffer *waiting; /* first outstanding transfer */
+ struct tspp_mem_buffer *locked; /* buffer currently being read */
wait_queue_head_t in_queue; /* set when data is received */
- int read; /* index into mem showing buffers ready to be read by user */
- int waiting; /* index into mem showing outstanding transfers */
- int id; /* channel id (0-15) */
- int used; /* is this channel in use? */
- int key; /* which encryption key index is used */
- u32 bufsize; /* size of the sps transfer buffers */
- int buffer_count; /* how many buffers are actually allocated */
- int filter_count; /* how many filters have been added to this channel */
+ u32 id; /* channel id (0-15) */
+ int used; /* is this channel in use? */
+ int key; /* which encryption key index is used */
+ u32 buffer_size; /* size of the sps transfer buffers */
+ u32 max_buffers; /* how many buffers should be allocated */
+ u32 buffer_count; /* how many buffers are actually allocated */
+ u32 filter_count; /* how many filters have been added to this channel */
+ u32 int_freq; /* generate interrupts every x descriptors */
enum tspp_source src;
enum tspp_mode mode;
+ tspp_notifier *notifier; /* used only with kernel api */
+ void *notify_data; /* data to be passed with the notifier */
+ u32 notify_timer; /* notification for partially filled buffers */
};
struct tspp_pid_filter_table {
@@ -408,21 +388,62 @@
struct tspp_key_entry entry[TSPP_NUM_KEYS];
};
-static struct tspp_pid_filter_table *tspp_filter_table[TSPP_FILTER_TABLES];
-static struct tspp_channel channel_list[TSPP_NUM_CHANNELS];
-static struct tspp_key_table *tspp_key_table;
-static struct tspp_global_performance_regs *tspp_global_performance;
-static struct tspp_pipe_context_regs *tspp_pipe_context;
-static struct tspp_pipe_performance_regs *tspp_pipe_performance;
+/* this represents the actual hardware device */
+struct tspp_device {
+ struct list_head devlist; /* list of all devices */
+ struct platform_device *pdev;
+ void __iomem *base;
+ unsigned int tspp_irq;
+ unsigned int bam_irq;
+ u32 bam_handle;
+ struct sps_bam_props bam_props;
+ struct wake_lock wake_lock;
+ spinlock_t spinlock;
+ struct tasklet_struct tlet;
+ struct tspp_tsif_device tsif[TSPP_TSIF_INSTANCES];
+ /* clocks */
+ struct clk *tsif_pclk;
+ struct clk *tsif_ref_clk;
+ /* data */
+ struct tspp_pid_filter_table *filters[TSPP_FILTER_TABLES];
+ struct tspp_channel channels[TSPP_NUM_CHANNELS];
+ struct tspp_key_table *tspp_key_table;
+ struct tspp_global_performance_regs *tspp_global_performance;
+ struct tspp_pipe_context_regs *tspp_pipe_context;
+ struct tspp_pipe_performance_regs *tspp_pipe_performance;
+
+ struct dentry *dent;
+ struct dentry *debugfs_regs[ARRAY_SIZE(debugfs_tspp_regs)];
+};
+
+
static struct class *tspp_class;
static int tspp_key_entry;
static dev_t tspp_minor; /* next minor number to assign */
-static int loopback_mode; /* put tsif interfaces into loopback mode */
+
+static LIST_HEAD(tspp_devices);
+
+/* forward declarations */
+static ssize_t tspp_read(struct file *, char __user *, size_t, loff_t *);
+static ssize_t tspp_open(struct inode *inode, struct file *filp);
+static unsigned int tspp_poll(struct file *filp, struct poll_table_struct *p);
+static ssize_t tspp_release(struct inode *inode, struct file *filp);
+static long tspp_ioctl(struct file *, unsigned int, unsigned long);
+
+/* file operations */
+static const struct file_operations tspp_fops = {
+ .owner = THIS_MODULE,
+ .read = tspp_read,
+ .open = tspp_open,
+ .poll = tspp_poll,
+ .release = tspp_release,
+ .unlocked_ioctl = tspp_ioctl,
+};
/*** IRQ ***/
-static irqreturn_t tspp_isr(int irq, void *dev_id)
+static irqreturn_t tspp_isr(int irq, void *dev)
{
- struct tspp_device *device = dev_id;
+ struct tspp_device *device = dev;
u32 status, mask;
u32 data;
@@ -450,7 +471,7 @@
dev_info(&device->pdev->dev, "key switched");
if (status & 0xffff)
- dev_info(&device->pdev->dev, "broken pipe");
+ dev_info(&device->pdev->dev, "broken pipe %i", status & 0xffff);
writel_relaxed(status, device->base + TSPP_IRQ_CLEAR);
wmb();
@@ -460,8 +481,8 @@
/*** callbacks ***/
static void tspp_sps_complete_cb(struct sps_event_notify *notify)
{
- struct tspp_channel *channel = notify->user;
- tasklet_schedule(&channel->pdev->tlet);
+ struct tspp_device *pdev = notify->user;
+ tasklet_schedule(&pdev->tlet);
}
/*** tasklet ***/
@@ -473,17 +494,16 @@
struct sps_iovec iovec;
struct tspp_channel *channel;
struct tspp_device *device = (struct tspp_device *)data;
- struct tspp_mem_buffer *buffer;
-
spin_lock_irqsave(&device->spinlock, flags);
for (i = 0; i < TSPP_NUM_CHANNELS; i++) {
complete = 0;
- channel = &channel_list[i];
- buffer = &channel->buffer[channel->waiting];
+ channel = &device->channels[i];
+ if (!channel->used || !channel->waiting)
+ continue;
/* get completions */
- if (buffer->state == TSPP_BUF_STATE_WAITING) {
+ while (channel->waiting->state == TSPP_BUF_STATE_WAITING) {
if (sps_get_iovec(channel->pipe, &iovec) != 0) {
pr_err("tspp: Error in iovec on channel %i",
channel->id);
@@ -492,22 +512,27 @@
if (iovec.size == 0)
break;
- if (iovec.addr != buffer->mem.phys_base)
+ if (iovec.addr != channel->waiting->sps.phys_base)
pr_err("tspp: buffer mismatch 0x%08x",
- buffer->mem.phys_base);
+ channel->waiting->sps.phys_base);
complete = 1;
- buffer->state = TSPP_BUF_STATE_DATA;
- buffer->filled = iovec.size;
- buffer->read_index = 0;
- channel->waiting++;
- if (channel->waiting == TSPP_NUM_BUFFERS)
- channel->waiting = 0;
+ channel->waiting->state = TSPP_BUF_STATE_DATA;
+ channel->waiting->filled = iovec.size;
+ channel->waiting->read_index = 0;
+
+ /* update the pointers */
+ channel->waiting = channel->waiting->next;
}
+ /* wake any waiting processes */
if (complete) {
- /* wake any waiting processes */
wake_up_interruptible(&channel->in_queue);
+
+ /* call notifiers */
+ if (channel->notifier)
+ channel->notifier(channel->id,
+ channel->notify_data);
}
}
@@ -626,6 +651,33 @@
tspp_gpios_disable_free(pdata->gpios, pdata->num_gpios);
}
+/*** Clock functions ***/
+static int tspp_clock_start(struct tspp_device *device)
+{
+ if (device->tsif_pclk && clk_prepare_enable(device->tsif_pclk) != 0) {
+ pr_err("tspp: Can't start pclk");
+ return -EBUSY;
+ }
+
+ if (device->tsif_ref_clk &&
+ clk_prepare_enable(device->tsif_ref_clk) != 0) {
+ pr_err("tspp: Can't start ref clk");
+ clk_disable_unprepare(device->tsif_pclk);
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+static void tspp_clock_stop(struct tspp_device *device)
+{
+ if (device->tsif_pclk)
+ clk_disable(device->tsif_pclk);
+
+ if (device->tsif_ref_clk)
+ clk_disable(device->tsif_ref_clk);
+}
+
/*** TSIF functions ***/
static int tspp_start_tsif(struct tspp_tsif_device *tsif_device)
{
@@ -644,18 +696,26 @@
}
if (start_hardware) {
- if (loopback_mode) {
- ctl = TSIF_STS_CTL_EN_IRQ |
- TSIF_STS_CTL_EN_NULL |
- TSIF_STS_CTL_EN_ERROR |
- TSIF_STS_CTL_TEST_MODE |
+ ctl = TSIF_STS_CTL_EN_IRQ |
TSIF_STS_CTL_EN_DM;
- TSPP_DEBUG("tspp: starting tsif hw in loopback mode 0x%x", ctl);
- } else {
- ctl = TSIF_STS_CTL_EN_IRQ |
- TSIF_STS_CTL_EN_TIME_LIM |
- TSIF_STS_CTL_EN_TCR |
- TSIF_STS_CTL_EN_DM;
+ switch (tsif_device->mode) {
+ case TSPP_TSIF_MODE_LOOPBACK:
+ ctl |= TSIF_STS_CTL_EN_NULL |
+ TSIF_STS_CTL_EN_ERROR |
+ TSIF_STS_CTL_TEST_MODE;
+ break;
+ case TSPP_TSIF_MODE_1:
+ ctl |= TSIF_STS_CTL_EN_TIME_LIM |
+ TSIF_STS_CTL_EN_TCR;
+ break;
+ case TSPP_TSIF_MODE_2:
+ ctl |= TSIF_STS_CTL_EN_TIME_LIM |
+ TSIF_STS_CTL_EN_TCR |
+ TSIF_STS_CTL_MODE_2;
+ break;
+ default:
+ pr_warn("tspp: unknown tsif mode 0x%x",
+ tsif_device->mode);
}
writel_relaxed(ctl, tsif_device->base + TSIF_STS_CTL_OFF);
writel_relaxed(tsif_device->time_limit,
@@ -664,12 +724,12 @@
writel_relaxed(ctl | TSIF_STS_CTL_START,
tsif_device->base + TSIF_STS_CTL_OFF);
wmb();
- ctl = readl_relaxed(tsif_device->base + TSIF_STS_CTL_OFF);
}
+ ctl = readl_relaxed(tsif_device->base + TSIF_STS_CTL_OFF);
tsif_device->ref_count++;
- return (ctl & TSIF_STS_CTL_START) ? 0 : -EFAULT;
+ return (ctl & TSIF_STS_CTL_START) ? 0 : -EBUSY;
}
static void tspp_stop_tsif(struct tspp_tsif_device *tsif_device)
@@ -686,7 +746,27 @@
}
}
-/*** TSPP functions ***/
+/*** local TSPP functions ***/
+static int tspp_channels_in_use(struct tspp_device *pdev)
+{
+ int i;
+ int count = 0;
+ for (i = 0; i < TSPP_NUM_CHANNELS; i++)
+ count += (pdev->channels[i].used ? 1 : 0);
+
+ return count;
+}
+
+static struct tspp_device *tspp_find_by_id(int id)
+{
+ struct tspp_device *dev;
+ list_for_each_entry(dev, &tspp_devices, devlist) {
+ if (dev->pdev->id == id)
+ return dev;
+ }
+ return NULL;
+}
+
static int tspp_get_key_entry(void)
{
int i;
@@ -696,7 +776,7 @@
return i;
}
}
- return 1;
+ return 1 < TSPP_NUM_KEYS;
}
static void tspp_free_key_entry(int entry)
@@ -709,61 +789,56 @@
tspp_key_entry &= ~(1 << entry);
}
-static int tspp_alloc_buffer(struct sps_mem_buffer *mem,
- struct tspp_channel *channel)
+static int tspp_alloc_buffer(u32 channel_id, struct tspp_data_descriptor *desc,
+ u32 size, tspp_allocator *alloc, void *user)
{
- if (channel->bufsize < TSPP_MIN_BUFFER_SIZE ||
- channel->bufsize > TSPP_MAX_BUFFER_SIZE) {
- pr_err("tspp: bad buffer size");
- return 1;
- }
-
- switch (channel->mode) {
- case TSPP_MODE_DISABLED:
- mem->size = 0;
- pr_err("tspp: channel is disabled");
- return 1;
-
- case TSPP_MODE_PES:
- /* give the user what he asks for */
- mem->size = channel->bufsize;
- break;
-
- case TSPP_MODE_RAW:
- /* must be a multiple of 192 */
- if (channel->bufsize < (TSPP_PACKET_LENGTH+4))
- mem->size = (TSPP_PACKET_LENGTH+4);
- else
- mem->size = (channel->bufsize /
- (TSPP_PACKET_LENGTH+4)) *
- (TSPP_PACKET_LENGTH+4);
- break;
-
- case TSPP_MODE_RAW_NO_SUFFIX:
- /* must be a multiple of 188 */
- mem->size = (channel->bufsize / TSPP_PACKET_LENGTH) *
- TSPP_PACKET_LENGTH;
- break;
- }
-
-#ifdef TSPP_USE_DMA_ALLOC_COHERENT
- mem->base = dma_alloc_coherent(NULL, mem->size,
- &mem->phys_base, GFP_KERNEL);
- if (mem->base == 0) {
- pr_err("tspp dma alloc coherent failed %i", mem->size);
+ if (size < TSPP_MIN_BUFFER_SIZE ||
+ size > TSPP_MAX_BUFFER_SIZE) {
+ pr_err("tspp: bad buffer size %i", size);
return -ENOMEM;
}
-#else
- mem->base = kmalloc(mem->size, GFP_KERNEL);
- if (mem->base == 0) {
- pr_err("tspp buffer allocation failed %i", mem->size);
+
+ if (alloc) {
+ TSPP_DEBUG("tspp using alloc function");
+ desc->virt_base = alloc(channel_id, size,
+ &desc->phys_base, user);
+ } else {
+ desc->virt_base = dma_alloc_coherent(NULL, size,
+ &desc->phys_base, GFP_KERNEL);
+ if (desc->virt_base == 0) {
+ pr_err("tspp dma alloc coherent failed %i", size);
return -ENOMEM;
}
- mem->phys_base = dma_map_single(NULL,
- mem->base,
- mem->size,
- DMA_FROM_DEVICE);
-#endif
+ }
+
+ desc->size = size;
+ return 0;
+}
+
+static int tspp_queue_buffer(struct tspp_channel *channel,
+ struct tspp_mem_buffer *buffer)
+{
+ int rc;
+ u32 flags = 0;
+
+ /* make sure the interrupt frequency is valid */
+ if (channel->int_freq < 1)
+ channel->int_freq = 1;
+
+ /* generate interrupt according to requested frequency */
+ if (buffer->desc.id % channel->int_freq == channel->int_freq-1)
+ flags = SPS_IOVEC_FLAG_INT | SPS_IOVEC_FLAG_EOB;
+
+ /* start the transfer */
+ rc = sps_transfer_one(channel->pipe,
+ buffer->sps.phys_base,
+ buffer->sps.size,
+ channel->pdev,
+ flags);
+ if (rc < 0)
+ return rc;
+
+ buffer->state = TSPP_BUF_STATE_WAITING;
return 0;
}
@@ -784,12 +859,12 @@
/* BAM */
if (sps_device_reset(pdev->bam_handle) != 0) {
pr_err("tspp: error resetting bam");
- return 1;
+ return -EBUSY;
}
/* TSPP tables */
for (i = 0; i < TSPP_FILTER_TABLES; i++)
- memset(tspp_filter_table[i],
+ memset(pdev->filters[i],
0, sizeof(struct tspp_pid_filter_table));
/* disable all filters */
@@ -801,11 +876,11 @@
writel_relaxed(val | TSPP_CLK_CONTROL_FORCE_PERF_CNT,
pdev->base + TSPP_CONTROL);
wmb();
- memset(tspp_global_performance, 0,
+ memset(pdev->tspp_global_performance, 0,
sizeof(struct tspp_global_performance_regs));
- memset(tspp_pipe_context, 0,
+ memset(pdev->tspp_pipe_context, 0,
sizeof(struct tspp_pipe_context_regs));
- memset(tspp_pipe_performance, 0,
+ memset(pdev->tspp_pipe_performance, 0,
sizeof(struct tspp_pipe_performance_regs));
wmb();
writel_relaxed(val & ~TSPP_CLK_CONTROL_FORCE_PERF_CNT,
@@ -828,22 +903,147 @@
return 0;
}
-int tspp_open_stream(struct tspp_channel *channel, enum tspp_source src)
+static int tspp_select_source(u32 dev, u32 channel_id,
+ struct tspp_select_source *src)
+{
+ /* make sure the requested src id is in bounds */
+ if (src->source > TSPP_SOURCE_MEM) {
+ pr_err("tspp source out of bounds");
+ return -EINVAL;
+ }
+
+ /* open the stream */
+ tspp_open_stream(dev, channel_id, src->source, src->mode);
+
+ return 0;
+}
+
+static int tspp_set_iv(struct tspp_channel *channel, struct tspp_iv *iv)
+{
+ struct tspp_device *pdev = channel->pdev;
+
+ writel_relaxed(iv->data[0], pdev->base + TSPP_CBC_INIT_VAL(0));
+ writel_relaxed(iv->data[1], pdev->base + TSPP_CBC_INIT_VAL(1));
+ return 0;
+}
+
+static int tspp_set_system_keys(struct tspp_channel *channel,
+ struct tspp_system_keys *keys)
+{
+ int i;
+ struct tspp_device *pdev = channel->pdev;
+
+ for (i = 0; i < TSPP_NUM_SYSTEM_KEYS; i++)
+ writel_relaxed(keys->data[i], pdev->base + TSPP_SYSTEM_KEY(i));
+
+ return 0;
+}
+
+static int tspp_channel_init(struct tspp_channel *channel,
+ struct tspp_device *pdev)
+{
+ channel->cdev.owner = THIS_MODULE;
+ cdev_init(&channel->cdev, &tspp_fops);
+ channel->pdev = pdev;
+ channel->data = NULL;
+ channel->read = NULL;
+ channel->waiting = NULL;
+ channel->locked = NULL;
+ channel->id = MINOR(tspp_minor);
+ channel->used = 0;
+ channel->buffer_size = TSPP_MIN_BUFFER_SIZE;
+ channel->max_buffers = TSPP_NUM_BUFFERS;
+ channel->buffer_count = 0;
+ channel->filter_count = 0;
+ channel->int_freq = 1;
+ channel->notifier = NULL;
+ channel->notify_data = NULL;
+ channel->notify_timer = 0;
+ init_waitqueue_head(&channel->in_queue);
+
+ if (cdev_add(&channel->cdev, tspp_minor++, 1) != 0) {
+ pr_err("tspp: cdev_add failed");
+ return -EBUSY;
+ }
+
+ channel->dd = device_create(tspp_class, NULL, channel->cdev.dev,
+ channel, "tspp%02d", channel->id);
+ if (IS_ERR(channel->dd)) {
+ pr_err("tspp: device_create failed: %i",
+ (int)PTR_ERR(channel->dd));
+ cdev_del(&channel->cdev);
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+static int tspp_set_buffer_size(struct tspp_channel *channel,
+ struct tspp_buffer *buf)
+{
+ if (buf->size < TSPP_MIN_BUFFER_SIZE)
+ channel->buffer_size = TSPP_MIN_BUFFER_SIZE;
+ else if (buf->size > TSPP_MAX_BUFFER_SIZE)
+ channel->buffer_size = TSPP_MAX_BUFFER_SIZE;
+ else
+ channel->buffer_size = buf->size;
+
+ return 0;
+}
+
+static void tspp_set_tsif_mode(struct tspp_channel *channel,
+ enum tspp_tsif_mode mode)
+{
+ int index;
+
+ switch (channel->src) {
+ case TSPP_SOURCE_TSIF0:
+ index = 0;
+ break;
+ case TSPP_SOURCE_TSIF1:
+ index = 1;
+ break;
+ default:
+ pr_warn("tspp: can't set mode for non-tsif source %d",
+ channel->src);
+ return;
+ }
+ channel->pdev->tsif[index].mode = mode;
+}
+
+/*** TSPP API functions ***/
+int tspp_open_stream(u32 dev, u32 channel_id, enum tspp_source src, enum tspp_tsif_mode mode)
{
u32 val;
struct tspp_device *pdev;
+ struct tspp_channel *channel;
- if (!channel)
- return 1;
+ TSPP_DEBUG("tspp_open_stream %i %i %i %i", dev, channel_id, src, mode);
+ if (dev >= TSPP_MAX_DEVICES) {
+ pr_err("tspp: device id out of range");
+ return -ENODEV;
+ }
- pdev = channel->pdev;
+ if (channel_id >= TSPP_NUM_CHANNELS) {
+ pr_err("tspp: channel id out of range");
+ return -ECHRNG;
+ }
+
+ pdev = tspp_find_by_id(dev);
+ if (!pdev) {
+ pr_err("tspp_str: can't find device %i", dev);
+ return -ENODEV;
+ }
+ channel = &pdev->channels[channel_id];
+ channel->src = src;
+ tspp_set_tsif_mode(channel, mode);
switch (src) {
case TSPP_SOURCE_TSIF0:
/* make sure TSIF0 is running & enabled */
if (tspp_start_tsif(&pdev->tsif[0]) != 0) {
pr_err("tspp: error starting tsif0");
- return 1;
+ return -EBUSY;
}
val = readl_relaxed(pdev->base + TSPP_CONTROL);
writel_relaxed(val & ~TSPP_CONTROL_TSP_TSIF0_SRC_DIS,
@@ -854,7 +1054,7 @@
/* make sure TSIF1 is running & enabled */
if (tspp_start_tsif(&pdev->tsif[1]) != 0) {
pr_err("tspp: error starting tsif1");
- return 1;
+ return -EBUSY;
}
val = readl_relaxed(pdev->base + TSPP_CONTROL);
writel_relaxed(val & ~TSPP_CONTROL_TSP_TSIF1_SRC_DIS,
@@ -864,22 +1064,30 @@
case TSPP_SOURCE_MEM:
break;
default:
- pr_warn("tspp: channel %i invalid source %i", channel->id, src);
- return 1;
+ pr_err("tspp: channel %i invalid source %i", channel->id, src);
+ return -EBUSY;
}
- channel->src = src;
-
return 0;
}
EXPORT_SYMBOL(tspp_open_stream);
-int tspp_close_stream(struct tspp_channel *channel)
+int tspp_close_stream(u32 dev, u32 channel_id)
{
u32 val;
struct tspp_device *pdev;
+ struct tspp_channel *channel;
- pdev = channel->pdev;
+ if (channel_id >= TSPP_NUM_CHANNELS) {
+ pr_err("tspp: channel id out of range");
+ return -ECHRNG;
+ }
+ pdev = tspp_find_by_id(dev);
+ if (!pdev) {
+ pr_err("tspp_cs: can't find device %i", dev);
+ return -EBUSY;
+ }
+ channel = &pdev->channels[channel_id];
switch (channel->src) {
case TSPP_SOURCE_TSIF0:
@@ -901,22 +1109,43 @@
break;
}
- channel->src = -1;
+ channel->src = TSPP_SOURCE_NONE;
return 0;
}
EXPORT_SYMBOL(tspp_close_stream);
-int tspp_open_channel(struct tspp_channel *channel)
+int tspp_open_channel(u32 dev, u32 channel_id)
{
int rc = 0;
- struct sps_connect *config = &channel->config;
- struct sps_register_event *event = &channel->event;
+ struct sps_connect *config;
+ struct sps_register_event *event;
+ struct tspp_channel *channel;
+ struct tspp_device *pdev;
+
+ if (channel_id >= TSPP_NUM_CHANNELS) {
+ pr_err("tspp: channel id out of range");
+ return -ECHRNG;
+ }
+ pdev = tspp_find_by_id(dev);
+ if (!pdev) {
+ pr_err("tspp_oc: can't find device %i", dev);
+ return -ENODEV;
+ }
+ channel = &pdev->channels[channel_id];
if (channel->used) {
pr_err("tspp channel already in use");
- return 1;
+ return -EBUSY;
}
+ config = &channel->config;
+ event = &channel->event;
+
+ /* start the clocks if needed */
+ tspp_clock_start(pdev);
+ if (tspp_channels_in_use(pdev) == 0)
+ wake_lock(&pdev->wake_lock);
+
/* mark it as used */
channel->used = 1;
@@ -931,11 +1160,14 @@
/* get default configuration */
sps_get_config(channel->pipe, config);
- config->source = channel->pdev->bam_handle;
+ config->source = pdev->bam_handle;
config->destination = SPS_DEV_HANDLE_MEM;
config->mode = SPS_MODE_SRC;
- config->options = SPS_O_AUTO_ENABLE |
- SPS_O_EOT | SPS_O_ACK_TRANSFERS;
+ config->options =
+ SPS_O_AUTO_ENABLE | /* connection is auto-enabled */
+ SPS_O_STREAMING | /* streaming mode */
+ SPS_O_DESC_DONE | /* interrupt on end of descriptor */
+ SPS_O_ACK_TRANSFERS; /* must use sps_get_iovec() */
config->src_pipe_index = channel->id;
config->desc.size =
(TSPP_SPS_DESCRIPTOR_COUNT + 1) * SPS_DESCRIPTOR_SIZE;
@@ -958,10 +1190,10 @@
}
event->mode = SPS_TRIGGER_CALLBACK;
- event->options = SPS_O_EOT;
+ event->options = SPS_O_DESC_DONE;
event->callback = tspp_sps_complete_cb;
event->xfer_done = NULL;
- event->user = channel;
+ event->user = pdev;
rc = sps_register_event(channel->pipe, event);
if (rc) {
@@ -969,14 +1201,12 @@
goto err_event;
}
- rc = pm_runtime_get(&channel->pdev->pdev->dev);
+ rc = pm_runtime_get(&pdev->pdev->dev);
if (rc < 0) {
- dev_err(&channel->pdev->pdev->dev,
+ dev_err(&pdev->pdev->dev,
"Runtime PM: Unable to wake up tspp device, rc = %d",
rc);
}
-
- wake_lock(&channel->pdev->wake_lock);
return 0;
err_event:
@@ -991,16 +1221,38 @@
}
EXPORT_SYMBOL(tspp_open_channel);
-int tspp_close_channel(struct tspp_channel *channel)
+int tspp_close_channel(u32 dev, u32 channel_id)
{
int i;
int id;
u32 val;
- struct sps_connect *config = &channel->config;
- struct tspp_device *pdev = channel->pdev;
- TSPP_DEBUG("tspp_close_channel");
- channel->used = 0;
+ struct sps_connect *config;
+ struct tspp_device *pdev;
+ struct tspp_channel *channel;
+ struct tspp_mem_buffer *pbuf, *temp;
+
+ if (channel_id >= TSPP_NUM_CHANNELS) {
+ pr_err("tspp: channel id out of range");
+ return -ECHRNG;
+ }
+ pdev = tspp_find_by_id(dev);
+ if (!pdev) {
+ pr_err("tspp_close: can't find device %i", dev);
+ return -ENODEV;
+ }
+ channel = &pdev->channels[channel_id];
+
+ /* if the channel is not used, we are done */
+ if (!channel->used)
+ return 0;
+
+ channel->notifier = NULL;
+ channel->notify_data = NULL;
+ channel->notify_timer = 0;
+
+ config = &channel->config;
+ pdev = channel->pdev;
/* disable pipe (channel) */
val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
@@ -1010,7 +1262,7 @@
/* unregister all filters for this channel */
for (i = 0; i < TSPP_NUM_PRIORITIES; i++) {
struct tspp_pid_filter *tspp_filter =
- &tspp_filter_table[channel->src]->filter[i];
+ &pdev->filters[channel->src]->filter[i];
id = FILTER_GET_PIPE_NUMBER0(tspp_filter);
if (id == channel->id) {
if (FILTER_HAS_ENCRYPTION(tspp_filter))
@@ -1023,7 +1275,7 @@
channel->filter_count = 0;
/* stop the stream */
- tspp_close_stream(channel);
+ tspp_close_stream(dev, channel->id);
/* disconnect the bam */
if (sps_disconnect(channel->pipe) != 0)
@@ -1033,68 +1285,68 @@
dma_free_coherent(NULL, config->desc.size, config->desc.base,
config->desc.phys_base);
- for (i = 0; i < TSPP_NUM_BUFFERS; i++) {
- if (channel->buffer[i].mem.phys_base) {
-#ifdef TSPP_USE_DMA_ALLOC_COHERENT
+ pbuf = channel->data;
+ for (i = 0; i < channel->buffer_count; i++) {
+ if (pbuf->desc.phys_base) {
dma_free_coherent(NULL,
- channel->buffer[i].mem.size,
- channel->buffer[i].mem.base,
- channel->buffer[i].mem.phys_base);
-#else
- dma_unmap_single(channel->dd,
- channel->buffer[i].mem.phys_base,
- channel->buffer[i].mem.size,
- 0);
- kfree(channel->buffer[i].mem.base);
-#endif
- channel->buffer[i].mem.phys_base = 0;
+ pbuf->desc.size,
+ pbuf->desc.virt_base,
+ pbuf->desc.phys_base);
+ pbuf->desc.phys_base = 0;
}
- channel->buffer[i].mem.base = 0;
- channel->buffer[i].state = TSPP_BUF_STATE_EMPTY;
+ pbuf->desc.virt_base = 0;
+ pbuf->state = TSPP_BUF_STATE_EMPTY;
+ temp = pbuf;
+ pbuf = pbuf->next;
+ kfree(temp);
}
channel->buffer_count = 0;
+ channel->data = NULL;
+ channel->read = NULL;
+ channel->waiting = NULL;
+ channel->locked = NULL;
+ channel->used = 0;
- wake_unlock(&channel->pdev->wake_lock);
+ if (tspp_channels_in_use(pdev) == 0)
+ wake_unlock(&pdev->wake_lock);
+ tspp_clock_stop(pdev);
+
return 0;
}
EXPORT_SYMBOL(tspp_close_channel);
-/* picks a stream for this channel */
-int tspp_select_source(struct tspp_channel *channel,
- struct tspp_select_source *src)
-{
- /* make sure the requested src id is in bounds */
- if (src->source > TSPP_SOURCE_MEM) {
- pr_err("tspp source out of bounds");
- return 1;
- }
-
- /* open the stream */
- tspp_open_stream(channel, src->source);
-
- return 0;
-}
-EXPORT_SYMBOL(tspp_select_source);
-
-int tspp_add_filter(struct tspp_channel *channel,
+int tspp_add_filter(u32 dev, u32 channel_id,
struct tspp_filter *filter)
{
int i;
int other_channel;
int entry;
u32 val, pid, enabled;
- struct tspp_device *pdev = channel->pdev;
+ struct tspp_device *pdev;
struct tspp_pid_filter p;
+ struct tspp_channel *channel;
- TSPP_DEBUG("tspp_add_filter");
+ TSPP_DEBUG("tspp: add filter");
+ if (channel_id >= TSPP_NUM_CHANNELS) {
+ pr_err("tspp: channel id out of range");
+ return -ECHRNG;
+ }
+ pdev = tspp_find_by_id(dev);
+ if (!pdev) {
+ pr_err("tspp_add: can't find device %i", dev);
+ return -ENODEV;
+ }
+
+ channel = &pdev->channels[channel_id];
+
if (filter->source > TSPP_SOURCE_MEM) {
pr_err("tspp invalid source");
- return 1;
+ return -ENOSR;
}
if (filter->priority >= TSPP_NUM_PRIORITIES) {
pr_err("tspp invalid source");
- return 1;
+ return -ENOSR;
}
/* make sure this filter mode matches the channel mode */
@@ -1107,14 +1359,14 @@
case TSPP_MODE_RAW_NO_SUFFIX:
if (filter->mode != channel->mode) {
pr_err("tspp: wrong filter mode");
- return 1;
+ return -EBADSLT;
}
}
if (filter->mode == TSPP_MODE_PES) {
for (i = 0; i < TSPP_NUM_PRIORITIES; i++) {
struct tspp_pid_filter *tspp_filter =
- &tspp_filter_table[channel->src]->filter[i];
+ &pdev->filters[channel->src]->filter[i];
pid = FILTER_GET_PIPE_PID((tspp_filter));
enabled = FILTER_GET_PIPE_PROCESS0(tspp_filter);
if (enabled && (pid == filter->pid)) {
@@ -1122,18 +1374,18 @@
FILTER_GET_PIPE_NUMBER0(tspp_filter);
pr_err("tspp: pid 0x%x already in use by channel %i",
filter->pid, other_channel);
- return 1;
+ return -EBADSLT;
}
}
}
/* make sure this priority is not already in use */
enabled = FILTER_GET_PIPE_PROCESS0(
- (&(tspp_filter_table[channel->src]->filter[filter->priority])));
+ (&(pdev->filters[channel->src]->filter[filter->priority])));
if (enabled) {
pr_err("tspp: filter priority %i source %i is already enabled\n",
filter->priority, channel->src);
- return 1;
+ return -ENOSR;
}
if (channel->mode == TSPP_MODE_PES) {
@@ -1147,7 +1399,7 @@
/* update entry */
p.filter = 0;
- p.config = 0;
+ p.config = FILTER_TRANS_END_DISABLE;
FILTER_SET_PIPE_PROCESS0((&p), filter->mode);
FILTER_SET_PIPE_PID((&p), filter->pid);
FILTER_SET_PID_MASK((&p), filter->mask);
@@ -1162,68 +1414,56 @@
FILTER_SET_KEY_NUMBER((&p), entry);
}
}
- TSPP_DEBUG("tspp_add_filter: mode=%i pid=%i mask=%i channel=%i",
- filter->mode, filter->pid, filter->mask, channel->id);
- tspp_filter_table[channel->src]->
+ pdev->filters[channel->src]->
filter[filter->priority].config = p.config;
- tspp_filter_table[channel->src]->
+ pdev->filters[channel->src]->
filter[filter->priority].filter = p.filter;
+ /* allocate buffers if needed */
+ tspp_allocate_buffers(dev, channel->id, channel->max_buffers,
+ channel->buffer_size, channel->int_freq, 0, 0);
+ if (channel->buffer_count < MIN_ACCEPTABLE_BUFFER_COUNT) {
+ pr_err("tspp: failed to allocate at least %i buffers",
+ MIN_ACCEPTABLE_BUFFER_COUNT);
+ return -ENOMEM;
+ }
+
/* reenable pipe */
val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
writel_relaxed(val & ~(1 << channel->id), pdev->base + TSPP_PS_DISABLE);
wmb();
val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
- /* allocate buffers if needed */
- if (channel->buffer_count == 0) {
- TSPP_DEBUG("tspp: no buffers need %i", TSPP_NUM_BUFFERS);
- for (i = 0; i < TSPP_NUM_BUFFERS; i++) {
- if (tspp_alloc_buffer(&channel->buffer[i].mem,
- channel) != 0) {
- pr_warn("tspp: Can't allocate buffer %i", i);
- } else {
- channel->buffer[i].filled = 0;
- channel->buffer[i].read_index = 0;
- channel->buffer_count++;
-
- /* start the transfer */
- if (sps_transfer_one(channel->pipe,
- channel->buffer[i].mem.phys_base,
- channel->buffer[i].mem.size,
- channel,
- SPS_IOVEC_FLAG_INT |
- SPS_IOVEC_FLAG_EOB))
- pr_err("tspp: can't submit transfer");
- else
- channel->buffer[i].state =
- TSPP_BUF_STATE_WAITING;
- }
- }
- }
-
- if (channel->buffer_count < MIN_ACCEPTABLE_BUFFER_COUNT) {
- pr_err("failed to allocate at least %i buffers",
- MIN_ACCEPTABLE_BUFFER_COUNT);
- return -ENOMEM;
- }
-
channel->filter_count++;
return 0;
}
EXPORT_SYMBOL(tspp_add_filter);
-int tspp_remove_filter(struct tspp_channel *channel,
+int tspp_remove_filter(u32 dev, u32 channel_id,
struct tspp_filter *filter)
{
int entry;
u32 val;
- struct tspp_device *pdev = channel->pdev;
- int src = channel->src;
- struct tspp_pid_filter *tspp_filter =
- &(tspp_filter_table[src]->filter[filter->priority]);
+ struct tspp_device *pdev;
+ int src;
+ struct tspp_pid_filter *tspp_filter;
+ struct tspp_channel *channel;
+
+ if (channel_id >= TSPP_NUM_CHANNELS) {
+ pr_err("tspp: channel id out of range");
+ return -ECHRNG;
+ }
+ pdev = tspp_find_by_id(dev);
+ if (!pdev) {
+ pr_err("tspp_remove: can't find device %i", dev);
+ return -ENODEV;
+ }
+ channel = &pdev->channels[channel_id];
+
+ src = channel->src;
+ tspp_filter = &(pdev->filters[src]->filter[filter->priority]);
/* disable pipe (channel) */
val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
@@ -1253,17 +1493,30 @@
}
EXPORT_SYMBOL(tspp_remove_filter);
-int tspp_set_key(struct tspp_channel *channel, struct tspp_key* key)
+int tspp_set_key(u32 dev, u32 channel_id, struct tspp_key *key)
{
int i;
int id;
int key_index;
int data;
+ struct tspp_channel *channel;
+ struct tspp_device *pdev;
+
+ if (channel_id >= TSPP_NUM_CHANNELS) {
+ pr_err("tspp: channel id out of range");
+ return -ECHRNG;
+ }
+ pdev = tspp_find_by_id(dev);
+ if (!pdev) {
+ pr_err("tspp_set: can't find device %i", dev);
+ return -ENODEV;
+ }
+ channel = &pdev->channels[channel_id];
/* read the key index used by this channel */
for (i = 0; i < TSPP_NUM_PRIORITIES; i++) {
struct tspp_pid_filter *tspp_filter =
- &(tspp_filter_table[channel->src]->filter[i]);
+ &(pdev->filters[channel->src]->filter[i]);
id = FILTER_GET_PIPE_NUMBER0(tspp_filter);
if (id == channel->id) {
if (FILTER_HAS_ENCRYPTION(tspp_filter)) {
@@ -1274,15 +1527,15 @@
}
if (i == TSPP_NUM_PRIORITIES) {
pr_err("tspp: no encryption on this channel");
- return 1;
+ return -ENOKEY;
}
if (key->parity == TSPP_KEY_PARITY_EVEN) {
- tspp_key_table->entry[key_index].even_lsb = key->lsb;
- tspp_key_table->entry[key_index].even_msb = key->msb;
+ pdev->tspp_key_table->entry[key_index].even_lsb = key->lsb;
+ pdev->tspp_key_table->entry[key_index].even_msb = key->msb;
} else {
- tspp_key_table->entry[key_index].odd_lsb = key->lsb;
- tspp_key_table->entry[key_index].odd_msb = key->msb;
+ pdev->tspp_key_table->entry[key_index].odd_lsb = key->lsb;
+ pdev->tspp_key_table->entry[key_index].odd_msb = key->msb;
}
data = readl_relaxed(channel->pdev->base + TSPP_KEY_VALID);
@@ -1290,49 +1543,253 @@
}
EXPORT_SYMBOL(tspp_set_key);
-static int tspp_set_iv(struct tspp_channel *channel, struct tspp_iv *iv)
+int tspp_register_notification(u32 dev, u32 channel_id,
+ tspp_notifier *pNotify, void *userdata, u32 timer_ms)
{
- struct tspp_device *pdev = channel->pdev;
+ struct tspp_channel *channel;
+ struct tspp_device *pdev;
- writel_relaxed(iv->data[0], pdev->base + TSPP_CBC_INIT_VAL(0));
- writel_relaxed(iv->data[1], pdev->base + TSPP_CBC_INIT_VAL(1));
+ if (channel_id >= TSPP_NUM_CHANNELS) {
+ pr_err("tspp: channel id out of range");
+ return -ECHRNG;
+ }
+ pdev = tspp_find_by_id(dev);
+ if (!pdev) {
+ pr_err("tspp_reg: can't find device %i", dev);
+ return -ENODEV;
+ }
+ channel = &pdev->channels[channel_id];
+ channel->notifier = pNotify;
+ channel->notify_data = userdata;
+ channel->notify_timer = timer_ms;
return 0;
}
+EXPORT_SYMBOL(tspp_register_notification);
-static int tspp_set_system_keys(struct tspp_channel *channel,
- struct tspp_system_keys *keys)
+int tspp_unregister_notification(u32 dev, u32 channel_id)
{
- int i;
- struct tspp_device *pdev = channel->pdev;
+ struct tspp_channel *channel;
+ struct tspp_device *pdev;
- for (i = 0; i < TSPP_NUM_SYSTEM_KEYS; i++)
- writel_relaxed(keys->data[i], pdev->base + TSPP_SYSTEM_KEY(i));
-
+ if (channel_id >= TSPP_NUM_CHANNELS) {
+ pr_err("tspp: channel id out of range");
+ return -ECHRNG;
+ }
+ pdev = tspp_find_by_id(dev);
+ if (!pdev) {
+ pr_err("tspp_unreg: can't find device %i", dev);
+ return -ENODEV;
+ }
+ channel = &pdev->channels[channel_id];
+ channel->notifier = NULL;
+ channel->notify_data = 0;
return 0;
}
+EXPORT_SYMBOL(tspp_unregister_notification);
-static int tspp_set_buffer_size(struct tspp_channel *channel,
- struct tspp_buffer *buf)
+const struct tspp_data_descriptor *tspp_get_buffer(u32 dev, u32 channel_id)
{
- if (buf->size < TSPP_MIN_BUFFER_SIZE)
- channel->bufsize = TSPP_MIN_BUFFER_SIZE;
- else if (buf->size > TSPP_MAX_BUFFER_SIZE)
- channel->bufsize = TSPP_MAX_BUFFER_SIZE;
- else
- channel->bufsize = buf->size;
+ struct tspp_mem_buffer *buffer;
+ struct tspp_channel *channel;
+ struct tspp_device *pdev;
- TSPP_DEBUG("tspp channel %i buffer size %i",
- channel->id, channel->bufsize);
+ if (channel_id >= TSPP_NUM_CHANNELS) {
+ pr_err("tspp: channel id out of range");
+ return NULL;
+ }
+ pdev = tspp_find_by_id(dev);
+ if (!pdev) {
+ pr_err("tspp_get: can't find device %i", dev);
+ return NULL;
+ }
+ channel = &pdev->channels[channel_id];
+ if (!channel->read) {
+ pr_warn("tspp: no buffer to get on channel %i!",
+ channel->id);
+ return NULL;
+ }
+
+ buffer = channel->read;
+ /* see if we have any buffers ready to read */
+ if (buffer->state != TSPP_BUF_STATE_DATA)
+ return 0;
+
+ if (buffer->state == TSPP_BUF_STATE_DATA) {
+ /* mark the buffer as busy */
+ buffer->state = TSPP_BUF_STATE_LOCKED;
+
+ /* increment the pointer along the list */
+ channel->read = channel->read->next;
+ }
+
+ return &buffer->desc;
+}
+EXPORT_SYMBOL(tspp_get_buffer);
+
+int tspp_release_buffer(u32 dev, u32 channel_id, u32 descriptor_id)
+{
+ int i, found = 0;
+ struct tspp_mem_buffer *buffer;
+ struct tspp_channel *channel;
+ struct tspp_device *pdev;
+
+ if (channel_id >= TSPP_NUM_CHANNELS) {
+ pr_err("tspp: channel id out of range");
+ return -ECHRNG;
+ }
+ pdev = tspp_find_by_id(dev);
+ if (!pdev) {
+ pr_err("tspp: can't find device %i", dev);
+ return -ENODEV;
+ }
+ channel = &pdev->channels[channel_id];
+
+ if (descriptor_id > channel->buffer_count)
+ pr_warn("tspp: desc id looks weird 0x%08x", descriptor_id);
+
+ /* find the correct descriptor */
+ buffer = channel->locked;
+ for (i = 0; i < channel->buffer_count; i++) {
+ if (buffer->desc.id == descriptor_id) {
+ found = 1;
+ break;
+ }
+ buffer = buffer->next;
+ }
+ channel->locked = channel->locked->next;
+
+ if (!found) {
+ pr_err("tspp: cant find desc %i", descriptor_id);
+ return -EINVAL;
+ }
+
+ /* make sure the buffer is in the expected state */
+ if (buffer->state != TSPP_BUF_STATE_LOCKED) {
+ pr_err("tspp: buffer %i not locked", descriptor_id);
+ return -EINVAL;
+ }
+ /* unlock the buffer and requeue it */
+ buffer->state = TSPP_BUF_STATE_WAITING;
+
+ if (tspp_queue_buffer(channel, buffer))
+ pr_warn("tspp: can't requeue buffer");
return 0;
}
+EXPORT_SYMBOL(tspp_release_buffer);
+
+int tspp_allocate_buffers(u32 dev, u32 channel_id, u32 count,
+ u32 size, u32 int_freq, tspp_allocator *alloc, void *user)
+{
+ struct tspp_channel *channel;
+ struct tspp_device *pdev;
+ struct tspp_mem_buffer *last = NULL;
+
+ TSPP_DEBUG("tspp_allocate_buffers");
+
+ if (channel_id >= TSPP_NUM_CHANNELS) {
+ pr_err("tspp: channel id out of range");
+ return -ECHRNG;
+ }
+ pdev = tspp_find_by_id(dev);
+ if (!pdev) {
+ pr_err("tspp_alloc: can't find device %i", dev);
+ return -ENODEV;
+ }
+ channel = &pdev->channels[channel_id];
+
+ channel->max_buffers = count;
+
+ /* set up interrupt frequency */
+ if (int_freq > channel->max_buffers)
+ int_freq = channel->max_buffers;
+ channel->int_freq = int_freq;
+
+ switch (channel->mode) {
+ case TSPP_MODE_DISABLED:
+ case TSPP_MODE_PES:
+ /* give the user what he asks for */
+ channel->buffer_size = size;
+ break;
+
+ case TSPP_MODE_RAW:
+ /* must be a multiple of 192 */
+ if (size < (TSPP_PACKET_LENGTH+4))
+ channel->buffer_size = (TSPP_PACKET_LENGTH+4);
+ else
+ channel->buffer_size = (size /
+ (TSPP_PACKET_LENGTH+4)) *
+ (TSPP_PACKET_LENGTH+4);
+ break;
+
+ case TSPP_MODE_RAW_NO_SUFFIX:
+ /* must be a multiple of 188 */
+ channel->buffer_size = (size / TSPP_PACKET_LENGTH) *
+ TSPP_PACKET_LENGTH;
+ break;
+ }
+
+ for (; channel->buffer_count < channel->max_buffers;
+ channel->buffer_count++) {
+
+ /* allocate the descriptor */
+ struct tspp_mem_buffer *desc = (struct tspp_mem_buffer *)
+ kmalloc(sizeof(struct tspp_mem_buffer), GFP_KERNEL);
+ if (!desc) {
+ pr_warn("tspp: Can't allocate desc %i",
+ channel->buffer_count);
+ break;
+ }
+
+ desc->desc.id = channel->buffer_count;
+ /* allocate the buffer */
+ if (tspp_alloc_buffer(channel_id, &desc->desc,
+ channel->buffer_size, alloc, user) != 0) {
+ kfree(desc);
+ pr_warn("tspp: Can't allocate buffer %i",
+ channel->buffer_count);
+ break;
+ }
+
+ /* add the descriptor to the list */
+ desc->filled = 0;
+ desc->read_index = 0;
+ if (!channel->data) {
+ channel->data = desc;
+ desc->next = channel->data;
+ } else {
+ last->next = desc;
+ }
+ last = desc;
+ desc->next = channel->data;
+
+ /* prepare the sps descriptor */
+ desc->sps.phys_base = desc->desc.phys_base;
+ desc->sps.base = desc->desc.virt_base;
+ desc->sps.size = desc->desc.size;
+
+ /* start the transfer */
+ if (tspp_queue_buffer(channel, desc))
+ pr_err("tspp: can't queue buffer %i", desc->desc.id);
+ }
+
+ channel->waiting = channel->data;
+ channel->read = channel->data;
+ channel->locked = channel->data;
+ return 0;
+}
+EXPORT_SYMBOL(tspp_allocate_buffers);
/*** File Operations ***/
static ssize_t tspp_open(struct inode *inode, struct file *filp)
{
+ u32 dev;
struct tspp_channel *channel;
+
+ TSPP_DEBUG("tspp_open");
channel = container_of(inode->i_cdev, struct tspp_channel, cdev);
filp->private_data = channel;
+ dev = channel->pdev->pdev->id;
/* if this channel is already in use, quit */
if (channel->used) {
@@ -1341,7 +1798,7 @@
return -EACCES;
}
- if (tspp_open_channel(channel) != 0) {
+ if (tspp_open_channel(dev, channel->id) != 0) {
pr_err("tspp: error opening channel");
return -EACCES;
}
@@ -1360,7 +1817,8 @@
poll_wait(filp, &channel->in_queue, p);
spin_lock_irqsave(&channel->pdev->spinlock, flags);
- if (channel->buffer[channel->read].state == TSPP_BUF_STATE_DATA)
+ if (channel->read &&
+ channel->read->state == TSPP_BUF_STATE_DATA)
mask = POLLIN | POLLRDNORM;
spin_unlock_irqrestore(&channel->pdev->spinlock, flags);
@@ -1370,11 +1828,11 @@
static ssize_t tspp_release(struct inode *inode, struct file *filp)
{
- struct tspp_channel *channel;
- channel = filp->private_data;
+ struct tspp_channel *channel = filp->private_data;
+ u32 dev = channel->pdev->pdev->id;
+ TSPP_DEBUG("tspp_release");
- pr_info("tspp_release");
- tspp_close_channel(channel);
+ tspp_close_channel(dev, channel->id);
return 0;
}
@@ -1389,7 +1847,23 @@
channel = filp->private_data;
TSPP_DEBUG("tspp_read");
- buffer = &channel->buffer[channel->read];
+
+ while (!channel->read) {
+ if (filp->f_flags & O_NONBLOCK) {
+ pr_warn("tspp: no buffer on channel %i!",
+ channel->id);
+ return -EAGAIN;
+ }
+ /* go to sleep if there is nothing to read */
+ if (wait_event_interruptible(channel->in_queue,
+ (channel->read != NULL))) {
+ pr_err("tspp: rude awakening\n");
+ return -ERESTARTSYS;
+ }
+ }
+
+ buffer = channel->read;
+
/* see if we have any buffers ready to read */
while (buffer->state != TSPP_BUF_STATE_DATA) {
if (filp->f_flags & O_NONBLOCK) {
@@ -1398,7 +1872,6 @@
return -EAGAIN;
}
/* go to sleep if there is nothing to read */
- TSPP_DEBUG("tspp: sleeping");
if (wait_event_interruptible(channel->in_queue,
(buffer->state == TSPP_BUF_STATE_DATA))) {
pr_err("tspp: rude awakening\n");
@@ -1408,26 +1881,13 @@
while (buffer->state == TSPP_BUF_STATE_DATA) {
size = min(count, buffer->filled);
- TSPP_DEBUG("tspp: reading channel %i buffer %i size %i",
- channel->id, channel->read, size);
if (size == 0)
break;
-#ifndef TSPP_USE_DMA_ALLOC_COHERENT
- /* unmap buffer (invalidates processor cache) */
- if (buffer->mem.phys_base) {
- dma_unmap_single(NULL,
- buffer->mem.phys_base,
- buffer->mem.size,
- DMA_FROM_DEVICE);
- buffer->mem.phys_base = 0;
- }
-#endif
-
- if (copy_to_user(buf, buffer->mem.base +
+ if (copy_to_user(buf, buffer->desc.virt_base +
buffer->read_index, size)) {
pr_err("tspp: error copying to user buffer");
- return -EFAULT;
+ return -EBUSY;
}
buf += size;
count -= size;
@@ -1436,32 +1896,12 @@
/* after reading the end of the buffer, requeue it,
and set up for reading the next one */
- if (buffer->read_index ==
- channel->buffer[channel->read].filled) {
+ if (buffer->read_index == buffer->filled) {
buffer->state = TSPP_BUF_STATE_WAITING;
-#ifndef TSPP_USE_DMA_ALLOC_COHERENT
- buffer->mem.phys_base = dma_map_single(NULL,
- buffer->mem.base,
- buffer->mem.size,
- DMA_FROM_DEVICE);
- if (!dma_mapping_error(NULL,
- buffer->mem.phys_base)) {
-#endif
- if (sps_transfer_one(channel->pipe,
- buffer->mem.phys_base,
- buffer->mem.size,
- channel,
- SPS_IOVEC_FLAG_INT |
- SPS_IOVEC_FLAG_EOT))
- pr_err("tspp: can't submit transfer");
- else {
- channel->read++;
- if (channel->read == TSPP_NUM_BUFFERS)
- channel->read = 0;
- }
-#ifndef TSPP_USE_DMA_ALLOC_COHERENT
- }
-#endif
+ if (tspp_queue_buffer(channel, buffer))
+ pr_err("tspp: can't submit transfer");
+ channel->locked = channel->read;
+ channel->read = channel->read->next;
}
}
@@ -1471,45 +1911,84 @@
static long tspp_ioctl(struct file *filp,
unsigned int param0, unsigned long param1)
{
+ u32 dev;
int rc = -1;
struct tspp_channel *channel;
+ struct tspp_select_source ss;
+ struct tspp_filter f;
+ struct tspp_key k;
+ struct tspp_iv iv;
+ struct tspp_system_keys sk;
+ struct tspp_buffer b;
channel = filp->private_data;
+ dev = channel->pdev->pdev->id;
if (!param1)
return -EINVAL;
switch (param0) {
case TSPP_IOCTL_SELECT_SOURCE:
- rc = tspp_select_source(channel,
- (struct tspp_select_source *)param1);
+ if (!access_ok(VERIFY_READ, param1,
+ sizeof(struct tspp_select_source))) {
+ return -EBUSY;
+ }
+ if (__copy_from_user(&ss, (void *)param1,
+ sizeof(struct tspp_select_source)) == 0)
+ rc = tspp_select_source(dev, channel->id, &ss);
break;
case TSPP_IOCTL_ADD_FILTER:
- rc = tspp_add_filter(channel,
- (struct tspp_filter *)param1);
+ if (!access_ok(VERIFY_READ, param1,
+ sizeof(struct tspp_filter))) {
+ return -ENOSR;
+ }
+ if (__copy_from_user(&f, (void *)param1,
+ sizeof(struct tspp_filter)) == 0)
+ rc = tspp_add_filter(dev, channel->id, &f);
break;
case TSPP_IOCTL_REMOVE_FILTER:
- rc = tspp_remove_filter(channel,
- (struct tspp_filter *)param1);
+ if (!access_ok(VERIFY_READ, param1,
+ sizeof(struct tspp_filter))) {
+ return -EBUSY;
+ }
+ if (__copy_from_user(&f, (void *)param1,
+ sizeof(struct tspp_filter)) == 0)
+ rc = tspp_remove_filter(dev, channel->id, &f);
break;
case TSPP_IOCTL_SET_KEY:
- rc = tspp_set_key(channel,
- (struct tspp_key *)param1);
+ if (!access_ok(VERIFY_READ, param1,
+ sizeof(struct tspp_key))) {
+ return -EBUSY;
+ }
+ if (__copy_from_user(&k, (void *)param1,
+ sizeof(struct tspp_key)) == 0)
+ rc = tspp_set_key(dev, channel->id, &k);
break;
case TSPP_IOCTL_SET_IV:
- rc = tspp_set_iv(channel,
- (struct tspp_iv *)param1);
+ if (!access_ok(VERIFY_READ, param1,
+ sizeof(struct tspp_iv))) {
+ return -EBUSY;
+ }
+ if (__copy_from_user(&iv, (void *)param1,
+ sizeof(struct tspp_iv)) == 0)
+ rc = tspp_set_iv(channel, &iv);
break;
case TSPP_IOCTL_SET_SYSTEM_KEYS:
- rc = tspp_set_system_keys(channel,
- (struct tspp_system_keys *)param1);
+ if (!access_ok(VERIFY_READ, param1,
+ sizeof(struct tspp_system_keys))) {
+ return -EINVAL;
+ }
+ if (__copy_from_user(&sk, (void *)param1,
+ sizeof(struct tspp_system_keys)) == 0)
+ rc = tspp_set_system_keys(channel, &sk);
break;
case TSPP_IOCTL_BUFFER_SIZE:
- rc = tspp_set_buffer_size(channel,
- (struct tspp_buffer *)param1);
- break;
- case TSPP_IOCTL_LOOPBACK:
- loopback_mode = param1;
- rc = 0;
+ if (!access_ok(VERIFY_READ, param1,
+ sizeof(struct tspp_buffer))) {
+ rc = -EINVAL;
+ }
+ if (__copy_from_user(&b, (void *)param1,
+ sizeof(struct tspp_buffer)) == 0)
+ rc = tspp_set_buffer_size(channel, &b);
break;
default:
pr_err("tspp: Unknown ioctl %i", param0);
@@ -1518,13 +1997,12 @@
/* normalize the return code in case one of the subfunctions does
something weird */
if (rc != 0)
- rc = 1;
+ rc = -ENOIOCTLCMD;
return rc;
}
/*** debugfs ***/
-#ifdef TSPP_USE_DEBUGFS
static int debugfs_iomem_x32_set(void *data, u64 val)
{
writel_relaxed(val, data);
@@ -1605,45 +2083,6 @@
device->debugfs_regs[i] = NULL;
}
}
-#endif /* TSPP_USE_DEBUGFS */
-
-static const struct file_operations tspp_fops = {
- .owner = THIS_MODULE,
- .read = tspp_read,
- .open = tspp_open,
- .poll = tspp_poll,
- .release = tspp_release,
- .unlocked_ioctl = tspp_ioctl,
-};
-
-static int tspp_channel_init(struct tspp_channel *channel)
-{
- channel->bufsize = TSPP_MIN_BUFFER_SIZE;
- channel->read = 0;
- channel->waiting = 0;
- cdev_init(&channel->cdev, &tspp_fops);
- channel->cdev.owner = THIS_MODULE;
- channel->id = MINOR(tspp_minor);
- init_waitqueue_head(&channel->in_queue);
- channel->buffer_count = 0;
- channel->filter_count = 0;
-
- if (cdev_add(&channel->cdev, tspp_minor++, 1) != 0) {
- pr_err("tspp: cdev_add failed");
- return 1;
- }
-
- channel->dd = device_create(tspp_class, NULL, channel->cdev.dev,
- channel, "tspp%02d", channel->id);
- if (IS_ERR(channel->dd)) {
- pr_err("tspp: device_create failed: %i",
- (int)PTR_ERR(channel->dd));
- cdev_del(&channel->cdev);
- return 1;
- }
-
- return 0;
-}
static int __devinit msm_tspp_probe(struct platform_device *pdev)
{
@@ -1656,7 +2095,6 @@
struct resource *mem_tsif1;
struct resource *mem_tspp;
struct resource *mem_bam;
- struct tspp_channel *channel;
/* must have platform data */
data = pdev->dev.platform_data;
@@ -1667,7 +2105,7 @@
}
/* check for valid device id */
- if ((pdev->id < 0) || (pdev->id >= 1)) {
+ if ((pdev->id < 0) || (pdev->id >= TSPP_MAX_DEVICES)) {
pr_err("tspp: Invalid device ID %d", pdev->id);
rc = -EINVAL;
goto out;
@@ -1789,24 +2227,25 @@
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
-#ifdef TSPP_USE_DEBUGFS
tspp_debugfs_init(device, 0);
for (i = 0; i < TSPP_TSIF_INSTANCES; i++)
tsif_debugfs_init(&device->tsif[i], i);
-#endif /* TSPP_USE_DEBUGFS */
wake_lock_init(&device->wake_lock, WAKE_LOCK_SUSPEND,
dev_name(&pdev->dev));
/* set up pointers to ram-based 'registers' */
- tspp_filter_table[0] = TSPP_PID_FILTER_TABLE0 + device->base;
- tspp_filter_table[1] = TSPP_PID_FILTER_TABLE1 + device->base;
- tspp_filter_table[2] = TSPP_PID_FILTER_TABLE2 + device->base;
- tspp_key_table = TSPP_DATA_KEY + device->base;
- tspp_global_performance = TSPP_GLOBAL_PERFORMANCE + device->base;
- tspp_pipe_context = TSPP_PIPE_CONTEXT + device->base;
- tspp_pipe_performance = TSPP_PIPE_PERFORMANCE + device->base;
+ device->filters[0] = device->base + TSPP_PID_FILTER_TABLE0;
+ device->filters[1] = device->base + TSPP_PID_FILTER_TABLE1;
+ device->filters[2] = device->base + TSPP_PID_FILTER_TABLE2;
+ device->tspp_key_table = device->base + TSPP_DATA_KEY;
+ device->tspp_global_performance =
+ device->base + TSPP_GLOBAL_PERFORMANCE;
+ device->tspp_pipe_context =
+ device->base + TSPP_PIPE_CONTEXT;
+ device->tspp_pipe_performance =
+ device->base + TSPP_PIPE_PERFORMANCE;
device->bam_props.summing_threshold = 0x10;
device->bam_props.irq = device->bam_irq;
@@ -1818,14 +2257,9 @@
goto err_bam;
}
- if (device->tsif_pclk && clk_prepare_enable(device->tsif_pclk) != 0) {
- dev_err(&pdev->dev, "Can't start pclk");
- goto err_pclk;
- }
- if (device->tsif_ref_clk &&
- clk_prepare_enable(device->tsif_ref_clk) != 0) {
- dev_err(&pdev->dev, "Can't start ref clk");
- goto err_refclk;
+ if (tspp_clock_start(device) != 0) {
+ dev_err(&pdev->dev, "Can't start clocks");
+ goto err_clock;
}
spin_lock_init(&device->spinlock);
@@ -1839,26 +2273,29 @@
if (version != 1)
pr_warn("tspp: unrecognized hw version=%i", version);
- /* update the channels with the device */
+ /* initialize the channels */
for (i = 0; i < TSPP_NUM_CHANNELS; i++) {
- channel = &channel_list[i];
- channel->pdev = device;
+ if (tspp_channel_init(&(device->channels[i]), device) != 0) {
+ pr_err("tspp_channel_init failed");
+ goto err_channel;
+ }
}
- /* everything is ok */
+ /* stop the clocks for power savings */
+ tspp_clock_stop(device);
+
+ /* everything is ok, so add the device to the list */
+ list_add_tail(&(device->devlist), &tspp_devices);
+
return 0;
-err_refclk:
- if (device->tsif_pclk)
- clk_disable_unprepare(device->tsif_pclk);
-err_pclk:
+err_channel:
+err_clock:
sps_deregister_bam_device(device->bam_handle);
err_bam:
-#ifdef TSPP_USE_DEBUGFS
tspp_debugfs_exit(device);
for (i = 0; i < TSPP_TSIF_INSTANCES; i++)
tsif_debugfs_exit(&device->tsif[i]);
-#endif /* TSPP_USE_DEBUGFS */
err_gpio:
err_irq:
tspp_stop_gpios(device);
@@ -1888,18 +2325,23 @@
static int __devexit msm_tspp_remove(struct platform_device *pdev)
{
-#ifdef TSPP_USE_DEBUGFS
+ struct tspp_channel *channel;
u32 i;
-#endif /* TSPP_USE_DEBUGFS */
struct tspp_device *device = platform_get_drvdata(pdev);
+ /* free the buffers, and delete the channels */
+ for (i = 0; i < TSPP_NUM_CHANNELS; i++) {
+ channel = &device->channels[i];
+ tspp_close_channel(device->pdev->id, i);
+ device_destroy(tspp_class, channel->cdev.dev);
+ cdev_del(&channel->cdev);
+ }
+
sps_deregister_bam_device(device->bam_handle);
-#ifdef TSPP_USE_DEBUGFS
for (i = 0; i < TSPP_TSIF_INSTANCES; i++)
tsif_debugfs_exit(&device->tsif[i]);
-#endif /* TSPP_USE_DEBUGFS */
wake_lock_destroy(&device->wake_lock);
free_irq(device->tspp_irq, device);
@@ -1954,17 +2396,9 @@
static int __init mod_init(void)
{
- u32 i;
int rc;
- /* first register the driver, and check hardware */
- rc = platform_driver_register(&msm_tspp_driver);
- if (rc) {
- pr_err("tspp: platform_driver_register failed: %d", rc);
- goto err_register;
- }
-
- /* now make the char devs (channels) */
+ /* make the char devs (channels) */
rc = alloc_chrdev_region(&tspp_minor, 0, TSPP_NUM_CHANNELS, "tspp");
if (rc) {
pr_err("tspp: alloc_chrdev_region failed: %d", rc);
@@ -1978,43 +2412,35 @@
goto err_class;
}
- for (i = 0; i < TSPP_NUM_CHANNELS; i++) {
- if (tspp_channel_init(&channel_list[i]) != 0) {
- pr_err("tspp_channel_init failed");
- break;
- }
+ /* register the driver, and check hardware */
+ rc = platform_driver_register(&msm_tspp_driver);
+ if (rc) {
+ pr_err("tspp: platform_driver_register failed: %d", rc);
+ goto err_register;
}
return 0;
+err_register:
+ class_destroy(tspp_class);
err_class:
unregister_chrdev_region(0, TSPP_NUM_CHANNELS);
err_devrgn:
- platform_driver_unregister(&msm_tspp_driver);
-err_register:
return rc;
}
static void __exit mod_exit(void)
{
- u32 i;
- struct tspp_channel *channel;
+ /* delete low level driver */
+ platform_driver_unregister(&msm_tspp_driver);
- /* first delete upper layer interface */
- for (i = 0; i < TSPP_NUM_CHANNELS; i++) {
- channel = &channel_list[i];
- device_destroy(tspp_class, channel->cdev.dev);
- cdev_del(&channel->cdev);
- }
+ /* delete upper layer interface */
class_destroy(tspp_class);
unregister_chrdev_region(0, TSPP_NUM_CHANNELS);
-
- /* now delete low level driver */
- platform_driver_unregister(&msm_tspp_driver);
}
module_init(mod_init);
module_exit(mod_exit);
-MODULE_DESCRIPTION("TSPP character device interface");
+MODULE_DESCRIPTION("TSPP platform device and char dev");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index 2b278be..a86798d 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -1351,9 +1351,11 @@
*/
if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
|| data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
- pr_err("%s: CMD%d: Data timeout\n",
+ pr_err("%s: CMD%d: Data timeout. DAT0 => %d\n",
mmc_hostname(host->mmc),
- data->mrq->cmd->opcode);
+ data->mrq->cmd->opcode,
+ (readl_relaxed(host->base
+ + MCI_TEST_INPUT) & 0x2) ? 1 : 0);
data->error = -ETIMEDOUT;
msmsdcc_dump_sdcc_state(host);
}
@@ -3358,10 +3360,10 @@
{
struct device *dev = mmc_dev(host->mmc);
- pr_info("%s: PM: sdcc_suspended=%d, pending_resume=%d, sdcc_suspending=%d\n",
+ pr_err("%s: PM: sdcc_suspended=%d, pending_resume=%d, sdcc_suspending=%d\n",
mmc_hostname(host->mmc), host->sdcc_suspended,
host->pending_resume, host->sdcc_suspending);
- pr_info("%s: RPM: runtime_status=%d, usage_count=%d,"
+ pr_err("%s: RPM: runtime_status=%d, usage_count=%d,"
" is_suspended=%d, disable_depth=%d, runtime_error=%d,"
" request_pending=%d, request=%d\n",
mmc_hostname(host->mmc), dev->power.runtime_status,
@@ -4847,10 +4849,10 @@
if (!base)
return;
- pr_info("===== %s: Register Dumps @phys_base=0x%x, @virt_base=0x%x"
+ pr_err("===== %s: Register Dumps @phys_base=0x%x, @virt_base=0x%x"
" =====\n", name, phys_base, (u32)base);
for (i = 0; i < no_of_regs; i = i + 4) {
- pr_info("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x\n", i*4,
+ pr_err("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x\n", i*4,
(u32)readl_relaxed(base + i*4),
(u32)readl_relaxed(base + ((i+1)*4)),
(u32)readl_relaxed(base + ((i+2)*4)),
@@ -4861,25 +4863,29 @@
static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host)
{
/* Dump current state of SDCC clocks, power and irq */
- pr_info("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
+ pr_err("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
(host->pwr ? "ON" : "OFF"));
- pr_info("%s: SDCC clks are %s, MCLK rate=%d\n",
+ pr_err("%s: SDCC clks are %s, MCLK rate=%d\n",
mmc_hostname(host->mmc),
(atomic_read(&host->clks_on) ? "ON" : "OFF"),
(u32)clk_get_rate(host->clk));
- pr_info("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
+ pr_err("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
(host->sdcc_irq_disabled ? "disabled" : "enabled"));
/* Now dump SDCC registers. Don't print FIFO registers */
- if (atomic_read(&host->clks_on))
+ if (atomic_read(&host->clks_on)) {
msmsdcc_print_regs("SDCC-CORE", host->base,
host->core_memres->start, 28);
+ pr_err("%s: MCI_TEST_INPUT = 0x%.8x\n",
+ mmc_hostname(host->mmc),
+ readl_relaxed(host->base + MCI_TEST_INPUT));
+ }
if (host->curr.data) {
if (!msmsdcc_is_dma_possible(host, host->curr.data))
- pr_info("%s: PIO mode\n", mmc_hostname(host->mmc));
+ pr_err("%s: PIO mode\n", mmc_hostname(host->mmc));
else if (is_dma_mode(host))
- pr_info("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
+ pr_err("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
mmc_hostname(host->mmc), host->dma.busy,
host->dma.channel, host->dma.crci);
else if (is_sps_mode(host)) {
@@ -4887,16 +4893,16 @@
msmsdcc_print_regs("SDCC-DML", host->dml_base,
host->dml_memres->start,
16);
- pr_info("%s: SPS mode: busy=%d\n",
+ pr_err("%s: SPS mode: busy=%d\n",
mmc_hostname(host->mmc), host->sps.busy);
}
- pr_info("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
+ pr_err("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
mmc_hostname(host->mmc), host->curr.xfer_size,
host->curr.data_xfered, host->curr.xfer_remain);
}
- pr_info("%s: got_dataend=%d, prog_enable=%d,"
+ pr_err("%s: got_dataend=%d, prog_enable=%d,"
" wait_for_auto_prog_done=%d, got_auto_prog_done=%d,"
" req_tout_ms=%d\n", mmc_hostname(host->mmc),
host->curr.got_dataend, host->prog_enable,
diff --git a/drivers/net/ethernet/msm/msm_rmnet_bam.c b/drivers/net/ethernet/msm/msm_rmnet_bam.c
index fbe8d3c..295c55c 100644
--- a/drivers/net/ethernet/msm/msm_rmnet_bam.c
+++ b/drivers/net/ethernet/msm/msm_rmnet_bam.c
@@ -29,6 +29,7 @@
#include <linux/if_arp.h>
#include <linux/msm_rmnet.h>
#include <linux/platform_device.h>
+#include <net/pkt_sched.h>
#ifdef CONFIG_HAS_EARLYSUSPEND
#include <linux/earlysuspend.h>
@@ -638,6 +639,16 @@
dev->name);
break;
+ case RMNET_IOCTL_FLOW_ENABLE:
+ tc_qdisc_flow_control(dev, (u32)ifr->ifr_data, 1);
+ DBG0("[%s] rmnet_ioctl(): enabled flow", dev->name);
+ break;
+
+ case RMNET_IOCTL_FLOW_DISABLE:
+ tc_qdisc_flow_control(dev, (u32)ifr->ifr_data, 0);
+ DBG0("[%s] rmnet_ioctl(): disabled flow", dev->name);
+ break;
+
case RMNET_IOCTL_GET_QOS: /* Get QoS header state */
ifr->ifr_ifru.ifru_data =
(void *)(p->operation_mode & RMNET_MODE_QOS);
diff --git a/drivers/net/usb/rmnet_usb_ctrl.c b/drivers/net/usb/rmnet_usb_ctrl.c
index f6e4b00..ba16ed9 100644
--- a/drivers/net/usb/rmnet_usb_ctrl.c
+++ b/drivers/net/usb/rmnet_usb_ctrl.c
@@ -404,7 +404,7 @@
result = usb_autopm_get_interface(dev->intf);
if (result < 0) {
- dev_err(dev->devicep, "%s: Unable to resume interface: %d\n",
+ dev_dbg(dev->devicep, "%s: Unable to resume interface: %d\n",
__func__, result);
/*
@@ -669,7 +669,7 @@
retval = usb_autopm_get_interface(dev->intf);
if (retval < 0) {
- dev_err(dev->devicep, "%s: Unable to resume interface: %d\n",
+ dev_dbg(dev->devicep, "%s: Unable to resume interface: %d\n",
__func__, retval);
return retval;
}
diff --git a/drivers/net/wireless/libra/libra_sdioif.c b/drivers/net/wireless/libra/libra_sdioif.c
index aa7970a..1d72a16 100644
--- a/drivers/net/wireless/libra/libra_sdioif.c
+++ b/drivers/net/wireless/libra/libra_sdioif.c
@@ -27,6 +27,12 @@
/* SDIO Card ID / Device ID */
static unsigned short libra_sdio_card_id;
+/* completion variables */
+struct completion gCard_rem_event_var;
+EXPORT_SYMBOL(gCard_rem_event_var);
+struct completion gShutdown_event_var;
+EXPORT_SYMBOL(gShutdown_event_var);
+
static suspend_handler_t *libra_suspend_hldr;
static resume_handler_t *libra_resume_hldr;
static notify_card_removal_t *libra_notify_card_removal_hdlr;
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index c0a4e0e..633809a 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -22,7 +22,9 @@
#include <linux/jiffies.h>
#include <linux/gpio.h>
#include <linux/wakelock.h>
+#include <linux/delay.h>
#include <mach/peripheral-loader.h>
+#include <mach/msm_smd.h>
#define DEVICE "wcnss_wlan"
#define VERSION "1.01"
@@ -30,10 +32,36 @@
/* module params */
#define WCNSS_CONFIG_UNSPECIFIED (-1)
+
static int has_48mhz_xo = WCNSS_CONFIG_UNSPECIFIED;
module_param(has_48mhz_xo, int, S_IWUSR | S_IRUGO);
MODULE_PARM_DESC(has_48mhz_xo, "Is an external 48 MHz XO present");
+#define WCNSS_CTRL_CHANNEL "WCNSS_CTRL"
+#define WCNSS_MAX_FRAME_SIZE 500
+#define WCNSS_VERSION_LEN 30
+
+/* message types */
+#define WCNSS_CTRL_MSG_START 0x01000000
+#define WCNSS_VERSION_REQ (WCNSS_CTRL_MSG_START + 0)
+#define WCNSS_VERSION_RSP (WCNSS_CTRL_MSG_START + 1)
+
+#define VALID_VERSION(version) \
+ ((strncmp(version, "INVALID", WCNSS_VERSION_LEN)) ? 1 : 0)
+
+struct smd_msg_hdr {
+ unsigned int type;
+ unsigned int len;
+};
+
+struct wcnss_version {
+ struct smd_msg_hdr hdr;
+ unsigned char major;
+ unsigned char minor;
+ unsigned char version;
+ unsigned char revision;
+};
+
static struct {
struct platform_device *pdev;
void *pil;
@@ -44,11 +72,15 @@
const struct dev_pm_ops *pm_ops;
int triggered;
int smd_channel_ready;
+ smd_channel_t *smd_ch;
+ unsigned char wcnss_version[WCNSS_VERSION_LEN];
unsigned int serial_number;
int thermal_mitigation;
void (*tm_notify)(struct device *, int);
struct wcnss_wlan_config wlan_config;
struct delayed_work wcnss_work;
+ struct work_struct wcnssctrl_version_work;
+ struct work_struct wcnssctrl_rx_work;
struct wake_lock wcnss_wake_lock;
} *penv = NULL;
@@ -108,6 +140,19 @@
static DEVICE_ATTR(thermal_mitigation, S_IRUSR | S_IWUSR,
wcnss_thermal_mitigation_show, wcnss_thermal_mitigation_store);
+
+static ssize_t wcnss_version_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ if (!penv)
+ return -ENODEV;
+
+ return scnprintf(buf, PAGE_SIZE, "%s", penv->wcnss_version);
+}
+
+static DEVICE_ATTR(wcnss_version, S_IRUSR,
+ wcnss_version_show, NULL);
+
static int wcnss_create_sysfs(struct device *dev)
{
int ret;
@@ -120,11 +165,21 @@
return ret;
ret = device_create_file(dev, &dev_attr_thermal_mitigation);
- if (ret) {
- device_remove_file(dev, &dev_attr_serial_number);
- return ret;
- }
+ if (ret)
+ goto remove_serial;
+
+ ret = device_create_file(dev, &dev_attr_wcnss_version);
+ if (ret)
+ goto remove_thermal;
+
return 0;
+
+remove_thermal:
+ device_remove_file(dev, &dev_attr_thermal_mitigation);
+remove_serial:
+ device_remove_file(dev, &dev_attr_serial_number);
+
+ return ret;
}
static void wcnss_remove_sysfs(struct device *dev)
@@ -132,6 +187,39 @@
if (dev) {
device_remove_file(dev, &dev_attr_serial_number);
device_remove_file(dev, &dev_attr_thermal_mitigation);
+ device_remove_file(dev, &dev_attr_wcnss_version);
+ }
+}
+static void wcnss_smd_notify_event(void *data, unsigned int event)
+{
+ int len = 0;
+
+ if (penv != data) {
+ pr_err("wcnss: invalid env pointer in smd callback\n");
+ return;
+ }
+ switch (event) {
+ case SMD_EVENT_DATA:
+ len = smd_read_avail(penv->smd_ch);
+ if (len < 0)
+ pr_err("wcnss: failed to read from smd %d\n", len);
+ schedule_work(&penv->wcnssctrl_rx_work);
+ break;
+
+ case SMD_EVENT_OPEN:
+ pr_debug("wcnss: opening WCNSS SMD channel :%s",
+ WCNSS_CTRL_CHANNEL);
+ if (!VALID_VERSION(penv->wcnss_version))
+ schedule_work(&penv->wcnssctrl_version_work);
+ break;
+
+ case SMD_EVENT_CLOSE:
+ pr_debug("wcnss: closing WCNSS SMD channel :%s",
+ WCNSS_CTRL_CHANNEL);
+ break;
+
+ default:
+ break;
}
}
@@ -213,6 +301,45 @@
.remove = __devexit_p(wcnss_wlan_ctrl_remove),
};
+static int __devexit
+wcnss_ctrl_remove(struct platform_device *pdev)
+{
+ if (penv && penv->smd_ch)
+ smd_close(penv->smd_ch);
+
+ return 0;
+}
+
+static int __devinit
+wcnss_ctrl_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+
+ if (!penv)
+ return -ENODEV;
+
+ ret = smd_named_open_on_edge(WCNSS_CTRL_CHANNEL, SMD_APPS_WCNSS,
+ &penv->smd_ch, penv, wcnss_smd_notify_event);
+ if (ret < 0) {
+ pr_err("wcnss: cannot open the smd command channel %s: %d\n",
+ WCNSS_CTRL_CHANNEL, ret);
+ return -ENODEV;
+ }
+ smd_disable_read_intr(penv->smd_ch);
+
+ return 0;
+}
+
+/* platform device for WCNSS_CTRL SMD channel */
+static struct platform_driver wcnss_ctrl_driver = {
+ .driver = {
+ .name = "WCNSS_CTRL",
+ .owner = THIS_MODULE,
+ },
+ .probe = wcnss_ctrl_probe,
+ .remove = __devexit_p(wcnss_ctrl_remove),
+};
+
struct device *wcnss_wlan_get_device(void)
{
if (penv && penv->pdev && penv->smd_channel_ready)
@@ -342,6 +469,83 @@
}
EXPORT_SYMBOL(wcnss_allow_suspend);
+static int wcnss_smd_tx(void *data, int len)
+{
+ int ret = 0;
+
+ ret = smd_write_avail(penv->smd_ch);
+ if (ret < len) {
+ pr_err("wcnss: no space available for smd frame\n");
+ ret = -ENOSPC;
+ }
+ ret = smd_write(penv->smd_ch, data, len);
+ if (ret < len) {
+ pr_err("wcnss: failed to write Command %d", len);
+ ret = -ENODEV;
+ }
+ return ret;
+}
+
+static void wcnssctrl_rx_handler(struct work_struct *worker)
+{
+ int len = 0;
+ int rc = 0;
+ unsigned char buf[WCNSS_MAX_FRAME_SIZE];
+ struct smd_msg_hdr *phdr;
+ struct wcnss_version *pversion;
+
+ len = smd_read_avail(penv->smd_ch);
+ if (len > WCNSS_MAX_FRAME_SIZE) {
+ pr_err("wcnss: frame larger than the allowed size\n");
+ smd_read(penv->smd_ch, NULL, len);
+ return;
+ }
+ if (len <= 0)
+ return;
+
+ rc = smd_read(penv->smd_ch, buf, len);
+ if (rc < len) {
+ pr_err("wcnss: incomplete data read from smd\n");
+ return;
+ }
+
+ phdr = (struct smd_msg_hdr *)buf;
+
+ switch (phdr->type) {
+
+ case WCNSS_VERSION_RSP:
+ pversion = (struct wcnss_version *)buf;
+ if (len != sizeof(struct wcnss_version)) {
+ pr_err("wcnss: invalid version data from wcnss %d\n",
+ len);
+ return;
+ }
+ snprintf(penv->wcnss_version, WCNSS_VERSION_LEN,
+ "%02x%02x%02x%02x", pversion->major, pversion->minor,
+ pversion->version, pversion->revision);
+ pr_info("wcnss: version %s\n", penv->wcnss_version);
+ break;
+
+ default:
+ pr_err("wcnss: invalid message type %d\n", phdr->type);
+ }
+ return;
+}
+
+static void wcnss_send_version_req(struct work_struct *worker)
+{
+ struct smd_msg_hdr smd_msg;
+ int ret = 0;
+
+ smd_msg.type = WCNSS_VERSION_REQ;
+ smd_msg.len = sizeof(smd_msg);
+ ret = wcnss_smd_tx(&smd_msg, smd_msg.len);
+ if (ret < 0)
+ pr_err("wcnss: smd tx failed\n");
+
+ return;
+}
+
static int
wcnss_trigger_config(struct platform_device *pdev)
{
@@ -360,6 +564,7 @@
penv->wlan_config.use_48mhz_xo = has_48mhz_xo;
penv->thermal_mitigation = 0;
+ strlcpy(penv->wcnss_version, "INVALID", WCNSS_VERSION_LEN);
penv->gpios_5wire = platform_get_resource_byname(pdev, IORESOURCE_IO,
"wcnss_gpios_5wire");
@@ -408,17 +613,13 @@
ret = -ENOENT;
goto fail_res;
}
-
- /* register sysfs entries */
- ret = wcnss_create_sysfs(&pdev->dev);
- if (ret)
- goto fail_sysfs;
+ INIT_WORK(&penv->wcnssctrl_rx_work, wcnssctrl_rx_handler);
+ INIT_WORK(&penv->wcnssctrl_version_work, wcnss_send_version_req);
wake_lock_init(&penv->wcnss_wake_lock, WAKE_LOCK_SUSPEND, "wcnss");
return 0;
-fail_sysfs:
fail_res:
if (penv->pil)
pil_put(penv->pil);
@@ -460,6 +661,8 @@
static int __devinit
wcnss_wlan_probe(struct platform_device *pdev)
{
+ int ret = 0;
+
/* verify we haven't been called more than once */
if (penv) {
dev_err(&pdev->dev, "cannot handle multiple devices.\n");
@@ -474,6 +677,12 @@
}
penv->pdev = pdev;
+ /* register sysfs entries */
+ ret = wcnss_create_sysfs(&pdev->dev);
+ if (ret)
+ return -ENOENT;
+
+
#ifdef MODULE
/*
@@ -529,6 +738,7 @@
{
platform_driver_register(&wcnss_wlan_driver);
platform_driver_register(&wcnss_wlan_ctrl_driver);
+ platform_driver_register(&wcnss_ctrl_driver);
return 0;
}
@@ -544,6 +754,7 @@
penv = NULL;
}
+ platform_driver_unregister(&wcnss_ctrl_driver);
platform_driver_unregister(&wcnss_wlan_ctrl_driver);
platform_driver_unregister(&wcnss_wlan_driver);
}
diff --git a/drivers/platform/msm/sps/bam.c b/drivers/platform/msm/sps/bam.c
index 7924578..eb9e8ee 100644
--- a/drivers/platform/msm/sps/bam.c
+++ b/drivers/platform/msm/sps/bam.c
@@ -1403,3 +1403,32 @@
SPS_INFO("-------------------- end of FIFO --------------------\n");
}
+
+/* output BAM_TEST_BUS_REG with specified TEST_BUS_SEL */
+void print_bam_test_bus_reg(void *base, u32 tb_sel)
+{
+ u32 i;
+ u32 test_bus_selection[] = {0x1, 0x2, 0x3, 0x4, 0xD, 0x10,
+ 0x41, 0x42, 0x43, 0x44, 0x45, 0x46};
+ u32 size = sizeof(test_bus_selection) / sizeof(u32);
+
+ if ((base == NULL) || (tb_sel == 0))
+ return;
+
+ SPS_INFO("\nsps:Specified TEST_BUS_SEL value: 0x%x\n", tb_sel);
+ bam_write_reg_field(base, TEST_BUS_SEL, BAM_TESTBUS_SEL, tb_sel);
+ SPS_INFO("sps:BAM_TEST_BUS_REG: 0x%x when TEST_BUS_SEL: 0x%x\n\n",
+ bam_read_reg(base, TEST_BUS_REG),
+ bam_read_reg_field(base, TEST_BUS_SEL, BAM_TESTBUS_SEL));
+
+ /* output other selections */
+ for (i = 0; i < size; i++) {
+ bam_write_reg_field(base, TEST_BUS_SEL, BAM_TESTBUS_SEL,
+ test_bus_selection[i]);
+
+ SPS_INFO("sps:bam 0x%x(va);TEST_BUS_REG:0x%x;TEST_BUS_SEL:0x%x",
+ (u32) base, bam_read_reg(base, TEST_BUS_REG),
+ bam_read_reg_field(base, TEST_BUS_SEL,
+ BAM_TESTBUS_SEL));
+ }
+}
diff --git a/drivers/platform/msm/sps/sps.c b/drivers/platform/msm/sps/sps.c
index 656d1fb..5bbcc84 100644
--- a/drivers/platform/msm/sps/sps.c
+++ b/drivers/platform/msm/sps/sps.c
@@ -89,6 +89,9 @@
u8 debug_level_option;
u8 print_limit_option;
u8 reg_dump_option;
+u32 testbus_sel;
+u32 bam_pipe_sel;
+
static char *debugfs_buf;
static u32 debugfs_buf_size;
@@ -101,6 +104,8 @@
struct dentry *dfile_debug_level_option;
struct dentry *dfile_print_limit_option;
struct dentry *dfile_reg_dump_option;
+struct dentry *dfile_testbus_sel;
+struct dentry *dfile_bam_pipe_sel;
struct dentry *dfile_bam_addr;
static struct sps_bam *phy2bam(u32 phys_addr);
@@ -325,30 +330,53 @@
for (i = 0; i < num_pipes; i++)
print_bam_pipe_selected_reg(vir_addr, i);
break;
- case 5: /* output selected registers of some pipes */
+ case 5: /* output selected registers of selected pipes */
+ for (i = 0; i < num_pipes; i++)
+ if (bam_pipe_sel & (1UL << i))
+ print_bam_pipe_selected_reg(vir_addr, i);
+ break;
+ case 6: /* output selected registers of typical pipes */
print_bam_pipe_selected_reg(vir_addr, 4);
print_bam_pipe_selected_reg(vir_addr, 5);
break;
- case 6: /* output desc FIFO of all active pipes */
+ case 7: /* output desc FIFO of all pipes */
for (i = 0; i < num_pipes; i++)
print_bam_pipe_desc_fifo(vir_addr, i);
break;
- case 7: /* output desc FIFO of some pipes */
+ case 8: /* output desc FIFO of selected pipes */
+ for (i = 0; i < num_pipes; i++)
+ if (bam_pipe_sel & (1UL << i))
+ print_bam_pipe_desc_fifo(vir_addr, i);
+ break;
+ case 9: /* output desc FIFO of typical pipes */
print_bam_pipe_desc_fifo(vir_addr, 4);
print_bam_pipe_desc_fifo(vir_addr, 5);
break;
- case 8: /* output selected registers and valid desc FIFO of all pipes */
+ case 10: /* output selected registers and desc FIFO of all pipes */
for (i = 0; i < num_pipes; i++) {
print_bam_pipe_selected_reg(vir_addr, i);
print_bam_pipe_desc_fifo(vir_addr, i);
}
break;
- case 9: /* output selected registers and desc FIFO of some pipes */
+ case 11: /* output selected registers and desc FIFO of selected pipes */
+ for (i = 0; i < num_pipes; i++)
+ if (bam_pipe_sel & (1UL << i)) {
+ print_bam_pipe_selected_reg(vir_addr, i);
+ print_bam_pipe_desc_fifo(vir_addr, i);
+ }
+ break;
+ case 12: /* output selected registers and desc FIFO of typical pipes */
print_bam_pipe_selected_reg(vir_addr, 4);
print_bam_pipe_desc_fifo(vir_addr, 4);
print_bam_pipe_selected_reg(vir_addr, 5);
print_bam_pipe_desc_fifo(vir_addr, 5);
break;
+ case 13: /* output BAM_TEST_BUS_REG */
+ if (testbus_sel)
+ print_bam_test_bus_reg(vir_addr, testbus_sel);
+ else
+ pr_info("sps:TEST_BUS_SEL should NOT be zero.");
+ break;
default:
pr_info("sps:no dump option is chosen yet.");
}
@@ -367,6 +395,8 @@
debug_level_option = 0;
print_limit_option = 0;
reg_dump_option = 0;
+ testbus_sel = 0;
+ bam_pipe_sel = 0;
debugfs_buf_size = 0;
debugfs_buf_used = 0;
wraparound = false;
@@ -416,6 +446,20 @@
goto reg_dump_option_err;
}
+ dfile_testbus_sel = debugfs_create_u32("testbus_sel", 0666,
+ dent, &testbus_sel);
+ if (!dfile_testbus_sel || IS_ERR(dfile_testbus_sel)) {
+ pr_err("sps:fail to create debug_fs file for testbus_sel.\n");
+ goto testbus_sel_err;
+ }
+
+ dfile_bam_pipe_sel = debugfs_create_u32("bam_pipe_sel", 0666,
+ dent, &bam_pipe_sel);
+ if (!dfile_bam_pipe_sel || IS_ERR(dfile_bam_pipe_sel)) {
+ pr_err("sps:fail to create debug_fs file for bam_pipe_sel.\n");
+ goto bam_pipe_sel_err;
+ }
+
dfile_bam_addr = debugfs_create_file("bam_addr", 0666,
dent, 0, &sps_bam_addr_ops);
if (!dfile_bam_addr || IS_ERR(dfile_bam_addr)) {
@@ -427,6 +471,10 @@
return;
bam_addr_err:
+ debugfs_remove(dfile_bam_pipe_sel);
+bam_pipe_sel_err:
+ debugfs_remove(dfile_testbus_sel);
+testbus_sel_err:
debugfs_remove(dfile_reg_dump_option);
reg_dump_option_err:
debugfs_remove(dfile_print_limit_option);
@@ -452,6 +500,10 @@
debugfs_remove(dfile_print_limit_option);
if (dfile_reg_dump_option)
debugfs_remove(dfile_reg_dump_option);
+ if (dfile_testbus_sel)
+ debugfs_remove(dfile_testbus_sel);
+ if (dfile_bam_pipe_sel)
+ debugfs_remove(dfile_bam_pipe_sel);
if (dfile_bam_addr)
debugfs_remove(dfile_bam_addr);
if (dent)
@@ -462,7 +514,8 @@
#endif
/* Get the debug info of BAM registers and descriptor FIFOs */
-int sps_get_bam_debug_info(u32 dev, u32 option, u32 para)
+int sps_get_bam_debug_info(u32 dev, u32 option, u32 para,
+ u32 tb_sel, u8 pre_level)
{
int res = 0;
struct sps_bam *bam;
@@ -545,6 +598,12 @@
print_bam_pipe_selected_reg(vir_addr, 5);
print_bam_pipe_desc_fifo(vir_addr, 5);
break;
+ case 13: /* output BAM_TEST_BUS_REG */
+ if (tb_sel)
+ print_bam_test_bus_reg(vir_addr, tb_sel);
+ else
+ pr_info("sps:TEST_BUS_SEL should NOT be zero.");
+ break;
default:
pr_info("sps:no option is chosen yet.");
}
diff --git a/drivers/platform/msm/sps/spsi.h b/drivers/platform/msm/sps/spsi.h
index 43a50bd..8a5deff 100644
--- a/drivers/platform/msm/sps/spsi.h
+++ b/drivers/platform/msm/sps/spsi.h
@@ -200,6 +200,9 @@
/* output descriptor FIFO of a pipe */
void print_bam_pipe_desc_fifo(void *, u32);
+/* output BAM_TEST_BUS_REG */
+void print_bam_test_bus_reg(void *, u32);
+
/**
* Translate physical to virtual address
*
diff --git a/drivers/platform/msm/usb_bam.c b/drivers/platform/msm/usb_bam.c
index a347984..551c0a7 100644
--- a/drivers/platform/msm/usb_bam.c
+++ b/drivers/platform/msm/usb_bam.c
@@ -539,6 +539,9 @@
return NULL;
}
+ pdata->ignore_core_reset_ack = of_property_read_bool(node,
+ "qcom,ignore-core-reset-ack");
+
for_each_child_of_node(pdev->dev.of_node, node)
pipe_entry++;
@@ -684,6 +687,12 @@
usb_props.summing_threshold = USB_SUMMING_THRESHOLD;
usb_props.event_threshold = 512;
usb_props.num_pipes = pdata->usb_bam_num_pipes;
+ /*
+ * HSUSB and HSIC Cores don't support RESET ACK signal to BAMs
+ * Hence, let BAM to ignore acknowledge from USB while resetting PIPE
+ */
+ if (pdata->ignore_core_reset_ack && pdata->usb_active_bam != SSUSB_BAM)
+ usb_props.options = SPS_BAM_NO_EXT_P_RST;
ret = sps_register_bam_device(&usb_props, &h_usb);
if (ret < 0) {
diff --git a/drivers/power/ltc4088-charger.c b/drivers/power/ltc4088-charger.c
index dbc75cd..58503cf 100644
--- a/drivers/power/ltc4088-charger.c
+++ b/drivers/power/ltc4088-charger.c
@@ -1,5 +1,5 @@
/*
- * 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
@@ -206,9 +206,11 @@
struct ltc4088_chg_chip *chip;
if (psy->type == POWER_SUPPLY_TYPE_USB) {
- chip = container_of(psy, struct ltc4088_chg_chip,
- usb_psy);
+ chip = container_of(psy, struct ltc4088_chg_chip, usb_psy);
switch (psp) {
+ case POWER_SUPPLY_PROP_TYPE:
+ psy.type = val->intval;
+ break;
case POWER_SUPPLY_PROP_ONLINE:
ltc4088_set_charging(chip, val->intval);
break;
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index 2868d61..b3d31d5 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -147,6 +147,8 @@
int ibat_at_cv_ua;
int soc_at_cv;
int prev_chg_soc;
+
+ struct power_supply *batt_psy;
};
/*
@@ -346,13 +348,18 @@
return 0;
}
-static int usb_chg_plugged_in(void)
+static int usb_chg_plugged_in(struct pm8921_bms_chip *chip)
{
int val = pm8921_is_usb_chg_plugged_in();
- /* treat as if usb is not present in case of error */
- if (val == -EINVAL)
- val = 0;
+ /* if the charger driver was not initialized, use the restart reason */
+ if (val == -EINVAL) {
+ if (pm8xxx_restart_reason(chip->dev->parent)
+ == PM8XXX_RESTART_CHG)
+ val = 1;
+ else
+ val = 0;
+ }
return val;
}
@@ -814,28 +821,26 @@
}
static int interpolate_pc(struct pm8921_bms_chip *chip,
- int batt_temp, int ocv)
+ int batt_temp_degc, int ocv)
{
int i, j, pcj, pcj_minus_one, pc;
int rows = chip->pc_temp_ocv_lut->rows;
int cols = chip->pc_temp_ocv_lut->cols;
- /* batt_temp is in tenths of degC - convert it to degC for lookups */
- batt_temp = batt_temp/10;
- if (batt_temp < chip->pc_temp_ocv_lut->temp[0]) {
- pr_debug("batt_temp %d < known temp range for pc\n", batt_temp);
- batt_temp = chip->pc_temp_ocv_lut->temp[0];
+ if (batt_temp_degc < chip->pc_temp_ocv_lut->temp[0]) {
+ pr_debug("batt_temp %d < known temp range\n", batt_temp_degc);
+ batt_temp_degc = chip->pc_temp_ocv_lut->temp[0];
}
- if (batt_temp > chip->pc_temp_ocv_lut->temp[cols - 1]) {
- pr_debug("batt_temp %d > known temp range for pc\n", batt_temp);
- batt_temp = chip->pc_temp_ocv_lut->temp[cols - 1];
+ if (batt_temp_degc > chip->pc_temp_ocv_lut->temp[cols - 1]) {
+ pr_debug("batt_temp %d > known temp range\n", batt_temp_degc);
+ batt_temp_degc = chip->pc_temp_ocv_lut->temp[cols - 1];
}
for (j = 0; j < cols; j++)
- if (batt_temp <= chip->pc_temp_ocv_lut->temp[j])
+ if (batt_temp_degc <= chip->pc_temp_ocv_lut->temp[j])
break;
- if (batt_temp == chip->pc_temp_ocv_lut->temp[j]) {
+ if (batt_temp_degc == chip->pc_temp_ocv_lut->temp[j]) {
/* found an exact match for temp in the table */
if (ocv >= chip->pc_temp_ocv_lut->ocv[0][j])
return chip->pc_temp_ocv_lut->percent[0];
@@ -858,7 +863,7 @@
}
/*
- * batt_temp is within temperature for
+ * batt_temp_degc is within temperature for
* column j-1 and j
*/
if (ocv >= chip->pc_temp_ocv_lut->ocv[0][j])
@@ -898,7 +903,7 @@
chip->pc_temp_ocv_lut->temp[j-1],
pcj,
chip->pc_temp_ocv_lut->temp[j],
- batt_temp);
+ batt_temp_degc);
return pc;
}
}
@@ -910,7 +915,7 @@
return pcj_minus_one;
pr_debug("%d ocv wasn't found for temp %d in the LUT returning 100%%",
- ocv, batt_temp);
+ ocv, batt_temp_degc);
return 100;
}
@@ -944,7 +949,7 @@
mutex_unlock(&the_chip->bms_output_lock);
- usb_chg = usb_chg_plugged_in();
+ usb_chg = usb_chg_plugged_in(the_chip);
convert_vbatt_raw_to_uv(the_chip, usb_chg, vbat_raw, vbat_uv);
convert_vsense_to_uv(the_chip, vsense_raw, &vsense_uv);
@@ -985,7 +990,7 @@
pm_bms_unlock_output_data(chip);
mutex_unlock(&chip->bms_output_lock);
- usb_chg = usb_chg_plugged_in();
+ usb_chg = usb_chg_plugged_in(chip);
if (chip->prev_last_good_ocv_raw == 0) {
chip->prev_last_good_ocv_raw = raw->last_good_ocv_raw;
@@ -1120,7 +1125,7 @@
{
int pc, scalefactor;
- pc = interpolate_pc(chip, batt_temp, ocv_uv / 1000);
+ pc = interpolate_pc(chip, batt_temp / 10, ocv_uv / 1000);
pr_debug("pc = %u for ocv = %dmicroVolts batt_temp = %d\n",
pc, ocv_uv, batt_temp);
@@ -1876,10 +1881,6 @@
if (the_chip->start_percent == -EINVAL)
return prev_soc;
- /* if soc is called in quick succession return the last soc */
- if (delta_time_us < USEC_PER_SEC)
- return prev_soc;
-
chg_time_sec = DIV_ROUND_UP(the_chip->charge_time_us, USEC_PER_SEC);
catch_up_sec = DIV_ROUND_UP(the_chip->catch_up_time_us, USEC_PER_SEC);
pr_debug("cts= %d catch_up_sec = %d\n", chg_time_sec, catch_up_sec);
@@ -1918,6 +1919,16 @@
return 1;
}
+
+static void update_power_supply(struct pm8921_bms_chip *chip)
+{
+ if (chip->batt_psy == NULL || chip->batt_psy < 0)
+ chip->batt_psy = power_supply_get_by_name("battery");
+
+ if (chip->batt_psy > 0)
+ power_supply_changed(chip->batt_psy);
+}
+
/*
* Remaining Usable Charge = remaining_charge (charge at ocv instance)
* - coloumb counter charge
@@ -1939,6 +1950,7 @@
int new_ucc_uah;
int new_rbatt;
int shutdown_soc;
+ int new_calculated_soc;
static int firsttime = 1;
calculate_soc_params(chip, raw, batt_temp, chargecycles,
@@ -2056,10 +2068,14 @@
mutex_unlock(&soc_invalidation_mutex);
pr_debug("SOC before adjustment = %d\n", soc);
- calculated_soc = adjust_soc(chip, soc, batt_temp, chargecycles,
+ new_calculated_soc = adjust_soc(chip, soc, batt_temp, chargecycles,
rbatt, fcc_uah, unusable_charge_uah, cc_uah);
- pr_debug("calculated SOC = %d\n", calculated_soc);
+ pr_debug("calculated SOC = %d\n", new_calculated_soc);
+ if (new_calculated_soc != calculated_soc)
+ update_power_supply(chip);
+
+ calculated_soc = new_calculated_soc;
firsttime = 0;
return calculated_soc;
}
@@ -2251,7 +2267,7 @@
}
voltage = xoadc_reading_to_microvolt(result.adc_code);
- usb_chg = usb_chg_plugged_in();
+ usb_chg = usb_chg_plugged_in(chip);
pr_debug("result 0.625V = 0x%x, voltage = %duV adc_meas = %lld "
"usb_chg = %d\n",
result.adc_code, voltage, result.measurement,
@@ -2738,7 +2754,7 @@
*/
ocv_uv = 0;
pm_bms_read_output_data(chip, LAST_GOOD_OCV_VALUE, &ocv_raw);
- usb_chg = usb_chg_plugged_in();
+ usb_chg = usb_chg_plugged_in(chip);
rc = convert_vbatt_raw_to_uv(chip, usb_chg, ocv_raw, &ocv_uv);
if (rc || ocv_uv == 0) {
rc = adc_based_ocv(chip, &ocv_uv);
diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index 49e6ee5..d08a71d 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -270,6 +270,7 @@
int rconn_mohm;
enum pm8921_chg_led_src_config led_src_config;
bool host_mode;
+ bool has_dc_supply;
u8 active_path;
int recent_reported_soc;
};
@@ -1195,6 +1196,12 @@
case POWER_SUPPLY_PROP_PRESENT:
case POWER_SUPPLY_PROP_ONLINE:
val->intval = 0;
+
+ if (the_chip->has_dc_supply) {
+ val->intval = 1;
+ return 0;
+ }
+
if (charging_disabled)
return 0;
@@ -1281,6 +1288,8 @@
else
return -EINVAL;
break;
+ case POWER_SUPPLY_PROP_TYPE:
+ return pm8921_set_usb_power_supply_type(val->intval);
default:
return -EINVAL;
}
@@ -1669,8 +1678,7 @@
*/
if (!get_prop_batt_present(the_chip)
&& !is_dc_chg_plugged_in(the_chip)) {
- if (get_prop_batt_current(the_chip) <
- the_chip->min_voltage_mv) {
+ if (!the_chip->has_dc_supply) {
pr_err("rejected: no other power source connected\n");
return;
}
@@ -2480,8 +2488,10 @@
pm_chg_get_fsm_state(chip),
get_prop_batt_current(chip)
);
+ return;
+ } else {
+ goto check_again_later;
}
- return;
}
if (active_path & USB_ACTIVE_BIT) {
@@ -2503,7 +2513,6 @@
ibat = get_prop_batt_current(chip);
if (reg_loop & VIN_ACTIVE_BIT) {
-
pr_debug("ibat = %d fsm = %d reg_loop = 0x%x\n",
ibat, pm_chg_get_fsm_state(chip), reg_loop);
if (ibat > 0) {
@@ -2847,11 +2856,7 @@
pr_debug("Exiting ichg_meas_ua = %d > 0\n", ichg_meas_ua);
return;
}
- if (ichg_meas_ua <= ichg_threshold_ua) {
- pr_debug("Exiting ichg_meas_ua = %d < ichg_threshold_ua = %d\n",
- ichg_meas_ua, ichg_threshold_ua);
- return;
- }
+
ichg_meas_ma = ichg_meas_ua / 1000;
/* rconn_mohm is in milliOhms */
@@ -3697,24 +3702,9 @@
chip->led_src_config, rc);
}
- /* Workarounds for die 1.1 and 1.0 */
- if (pm8xxx_get_revision(chip->dev->parent) < PM8XXX_REVISION_8921_2p0) {
- pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST2, 0xF1);
- pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xCE);
- pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xD8);
-
- /* software workaround for correct battery_id detection */
- pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_0, 0xFF);
- pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_1, 0xFF);
- pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_2, 0xFF);
- pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_3, 0xFF);
- pm8xxx_writeb(chip->dev->parent, PSI_CONFIG_STATUS, 0x0D);
- udelay(100);
- pm8xxx_writeb(chip->dev->parent, PSI_CONFIG_STATUS, 0x0C);
- }
-
/* Workarounds for die 3.0 */
- if (pm8xxx_get_revision(chip->dev->parent) == PM8XXX_REVISION_8921_3p0)
+ if (pm8xxx_get_revision(chip->dev->parent) == PM8XXX_REVISION_8921_3p0
+ && pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8921)
pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xAC);
/* Enable isub_fine resolution AICL for PM8917 */
@@ -4052,6 +4042,7 @@
chip->hot_thr = pdata->hot_thr;
chip->rconn_mohm = pdata->rconn_mohm;
chip->led_src_config = pdata->led_src_config;
+ chip->has_dc_supply = pdata->has_dc_supply;
rc = pm8921_chg_hw_init(chip);
if (rc) {
diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c
index 40f3803..7e74eca 100644
--- a/drivers/regulator/fixed.c
+++ b/drivers/regulator/fixed.c
@@ -62,11 +62,11 @@
config = devm_kzalloc(dev, sizeof(struct fixed_voltage_config),
GFP_KERNEL);
if (!config)
- return NULL;
+ return ERR_PTR(-ENOMEM);
config->init_data = of_get_regulator_init_data(dev, dev->of_node);
if (!config->init_data)
- return NULL;
+ return ERR_PTR(-EINVAL);
init_data = config->init_data;
init_data->constraints.apply_uV = 0;
@@ -77,13 +77,26 @@
} else {
dev_err(dev,
"Fixed regulator specified with variable voltages\n");
- return NULL;
+ return ERR_PTR(-EINVAL);
}
if (init_data->constraints.boot_on)
config->enabled_at_boot = true;
config->gpio = of_get_named_gpio(np, "gpio", 0);
+ /*
+ * of_get_named_gpio() currently returns ENODEV rather than
+ * EPROBE_DEFER. This code attempts to be compatible with both
+ * for now; the ENODEV check can be removed once the API is fixed.
+ * of_get_named_gpio() doesn't differentiate between a missing
+ * property (which would be fine here, since the GPIO is optional)
+ * and some other error. Patches have been posted for both issues.
+ * Once they are check in, we should replace this with:
+ * if (config->gpio < 0 && config->gpio != -ENOENT)
+ */
+ if ((config->gpio == -ENODEV) || (config->gpio == -EPROBE_DEFER))
+ return ERR_PTR(-EPROBE_DEFER);
+
delay = of_get_property(np, "startup-delay-us", NULL);
if (delay)
config->startup_delay = be32_to_cpu(*delay);
@@ -168,10 +181,13 @@
struct fixed_voltage_data *drvdata;
int ret;
- if (pdev->dev.of_node)
+ if (pdev->dev.of_node) {
config = of_get_fixed_voltage_config(&pdev->dev);
- else
+ if (IS_ERR(config))
+ return PTR_ERR(config);
+ } else {
config = pdev->dev.platform_data;
+ }
if (!config)
return -ENOMEM;
diff --git a/drivers/slimbus/slim-msm-ctrl.c b/drivers/slimbus/slim-msm-ctrl.c
index 14d554c..f87a06a 100644
--- a/drivers/slimbus/slim-msm-ctrl.c
+++ b/drivers/slimbus/slim-msm-ctrl.c
@@ -25,6 +25,7 @@
#include <linux/of.h>
#include <linux/of_slimbus.h>
#include <mach/sps.h>
+#include <mach/qdsp6v2/apr.h>
/* Per spec.max 40 bytes per received message */
#define SLIM_RX_MSGQ_BUF_LEN 40
@@ -298,6 +299,7 @@
u16 chanh;
int req_rem;
int req_def;
+ bool reconf;
};
struct msm_slim_sat {
@@ -1228,16 +1230,15 @@
*/
if (sat->sent_capability) {
for (i = 0; i < sat->nsatch; i++) {
- enum slim_ch_state chs =
- slim_get_ch_state(&sat->satcl,
- sat->satch[i].chanh);
- pr_err("Slim-SSR, sat:%d, rm chan:%d",
+ if (sat->satch[i].reconf) {
+ pr_err("SSR, sat:%d, rm ch:%d",
laddr,
sat->satch[i].chan);
- if (chs == SLIM_CH_ACTIVE)
slim_control_ch(&sat->satcl,
sat->satch[i].chanh,
SLIM_CH_REMOVE, true);
+ sat->satch[i].reconf = false;
+ }
}
}
} else if (mt != SLIM_MSG_MT_CORE &&
@@ -1326,14 +1327,18 @@
for (i = 0; i < sat->nsatch; i++) {
struct msm_sat_chan *sch = &sat->satch[i];
if (sch->req_rem) {
- if (!ret)
+ if (!ret) {
slim_dealloc_ch(&sat->satcl,
sch->chanh);
+ sch->reconf = false;
+ }
sch->req_rem--;
} else if (sch->req_def) {
if (ret)
slim_dealloc_ch(&sat->satcl,
sch->chanh);
+ else
+ sch->reconf = true;
sch->req_def--;
}
}
@@ -1846,10 +1851,20 @@
{
struct msm_slim_ctrl *dev;
int ret;
+ enum apr_subsys_state q6_state;
struct resource *bam_mem, *bam_io;
struct resource *slim_mem, *slim_io;
struct resource *irq, *bam_irq;
bool rxreg_access = false;
+
+ q6_state = apr_get_q6_state();
+ if (q6_state == APR_SUBSYS_DOWN) {
+ dev_dbg(&pdev->dev, "defering %s, adsp_state %d\n", __func__,
+ q6_state);
+ return -EPROBE_DEFER;
+ } else
+ dev_dbg(&pdev->dev, "adsp is ready\n");
+
slim_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"slimbus_physical");
if (!slim_mem) {
@@ -2075,6 +2090,10 @@
* function
*/
mb();
+
+ /* Add devices registered with board-info now that controller is up */
+ slim_ctrl_add_boarddevs(&dev->ctrl);
+
if (pdev->dev.of_node)
of_register_slim_devices(&dev->ctrl);
diff --git a/drivers/slimbus/slimbus.c b/drivers/slimbus/slimbus.c
index d0b5817..8dce000 100644
--- a/drivers/slimbus/slimbus.c
+++ b/drivers/slimbus/slimbus.c
@@ -373,6 +373,24 @@
EXPORT_SYMBOL_GPL(slim_register_board_info);
/*
+ * slim_ctrl_add_boarddevs: Add devices registered by board-info
+ * @ctrl: Controller to which these devices are to be added to.
+ * This API is called by controller when it is up and running.
+ * If devices on a controller were registered before controller,
+ * this will make sure that they get probed when controller is up.
+ */
+void slim_ctrl_add_boarddevs(struct slim_controller *ctrl)
+{
+ struct sbi_boardinfo *bi;
+ mutex_lock(&board_lock);
+ list_add_tail(&ctrl->list, &slim_ctrl_list);
+ list_for_each_entry(bi, &board_list, list)
+ slim_match_ctrl_to_boardinfo(ctrl, &bi->board_info);
+ mutex_unlock(&board_lock);
+}
+EXPORT_SYMBOL_GPL(slim_ctrl_add_boarddevs);
+
+/*
* slim_busnum_to_ctrl: Map bus number to controller
* @busnum: Bus number
* Returns controller representing this bus number
@@ -394,7 +412,6 @@
static int slim_register_controller(struct slim_controller *ctrl)
{
int ret = 0;
- struct sbi_boardinfo *bi;
/* Can't register until after driver model init */
if (WARN_ON(!slimbus_type.p)) {
@@ -462,15 +479,6 @@
ctrl->wq = create_singlethread_workqueue(dev_name(&ctrl->dev));
if (!ctrl->wq)
goto err_workq_failed;
- /*
- * If devices on a controller were registered before controller,
- * this will make sure that they get probed now that controller is up
- */
- mutex_lock(&board_lock);
- list_add_tail(&ctrl->list, &slim_ctrl_list);
- list_for_each_entry(bi, &board_list, list)
- slim_match_ctrl_to_boardinfo(ctrl, &bi->board_info);
- mutex_unlock(&board_lock);
return 0;
@@ -2571,20 +2579,38 @@
u32 segdist;
struct slim_pending_ch *pch;
+ mutex_lock(&ctrl->sched.m_reconf);
+ mutex_lock(&ctrl->m_ctrl);
/*
* If there are no pending changes from this client, avoid sending
* the reconfiguration sequence
*/
if (sb->pending_msgsl == sb->cur_msgsl &&
list_empty(&sb->mark_define) &&
- list_empty(&sb->mark_removal) &&
list_empty(&sb->mark_suspend)) {
- pr_debug("SLIM_CL: skip reconfig sequence");
- return 0;
+ struct list_head *pos, *next;
+ list_for_each_safe(pos, next, &sb->mark_removal) {
+ struct slim_ich *slc;
+ pch = list_entry(pos, struct slim_pending_ch, pending);
+ slc = &ctrl->chans[pch->chan];
+ if (slc->def > 0)
+ slc->def--;
+ /* Disconnect source port to free it up */
+ if (SLIM_HDL_TO_LA(slc->srch) == sb->laddr)
+ slc->srch = 0;
+ if (slc->def != 0) {
+ list_del(&pch->pending);
+ kfree(pch);
+ }
+ }
+ if (list_empty(&sb->mark_removal)) {
+ mutex_unlock(&ctrl->m_ctrl);
+ mutex_unlock(&ctrl->sched.m_reconf);
+ pr_info("SLIM_CL: skip reconfig sequence");
+ return 0;
+ }
}
- mutex_lock(&ctrl->sched.m_reconf);
- mutex_lock(&ctrl->m_ctrl);
ctrl->sched.pending_msgsl += sb->pending_msgsl - sb->cur_msgsl;
list_for_each_entry(pch, &sb->mark_define, pending) {
struct slim_ich *slc = &ctrl->chans[pch->chan];
@@ -2840,13 +2866,7 @@
ret = -ENOTCONN;
break;
}
- if (slc->def > 0)
- slc->def--;
- /* Disconnect source port to free it up */
- if (SLIM_HDL_TO_LA(slc->srch) == sb->laddr)
- slc->srch = 0;
- if (slc->def == 0)
- ret = add_pending_ch(&sb->mark_removal, chan);
+ ret = add_pending_ch(&sb->mark_removal, chan);
if (ret)
break;
}
diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c
index 9f3327a..4a79f76 100644
--- a/drivers/spi/spi_qsd.c
+++ b/drivers/spi/spi_qsd.c
@@ -404,17 +404,21 @@
if (bytes_sent < 0)
bytes_sent = 0;
}
-
/* We'll send in chunks of SPI_MAX_LEN if larger than
- * 4K bytes for targets that doesn't support infinite
- * mode. Make sure this doesn't happen on targets that
- * support infinite mode.
+ * 4K bytes for targets that have only 12 bits in
+ * QUP_MAX_OUTPUT_CNT register. If the target supports
+ * more than 12bits then we send the data in chunks of
+ * the infinite_mode value that is defined in the
+ * corresponding board file.
*/
if (!dd->pdata->infinite_mode)
- bytes_to_send = dd->tx_bytes_remaining / SPI_MAX_LEN ?
- SPI_MAX_LEN : dd->tx_bytes_remaining;
+ dd->max_trfr_len = SPI_MAX_LEN;
else
- bytes_to_send = dd->tx_bytes_remaining;
+ dd->max_trfr_len = (dd->pdata->infinite_mode) *
+ (dd->bytes_per_word);
+
+ bytes_to_send = min_t(u32, dd->tx_bytes_remaining,
+ dd->max_trfr_len);
num_transfers = DIV_ROUND_UP(bytes_to_send, dd->bytes_per_word);
dd->unaligned_len = bytes_to_send % dd->burst_size;
@@ -520,10 +524,11 @@
msm_dmov_enqueue_cmd(dd->rx_dma_chan, &dd->rx_hdr);
}
-/* SPI core on targets that does not support infinite mode can send maximum of
- 4K transfers, Therefore, we are sending several chunks of 3K or less
- (depending on how much is left). Upon completion we send the next chunk,
- or complete the transfer if everything is finished. On targets that support
+/* SPI core on targets that does not support infinite mode can send
+ maximum of 4K transfers or 64K transfers depending up on size of
+ MAX_OUTPUT_COUNT register, Therefore, we are sending in several
+ chunks. Upon completion we send the next chunk, or complete the
+ transfer if everything is finished. On targets that support
infinite mode, we send all the bytes in as single chunk.
*/
static int msm_spi_dm_send_next(struct msm_spi *dd)
@@ -536,9 +541,8 @@
/* On targets which does not support infinite mode,
We need to send more chunks, if we sent max last time */
- if ((!dd->pdata->infinite_mode) &&
- (dd->tx_bytes_remaining > SPI_MAX_LEN)) {
- dd->tx_bytes_remaining -= SPI_MAX_LEN;
+ if (dd->tx_bytes_remaining > dd->max_trfr_len) {
+ dd->tx_bytes_remaining -= dd->max_trfr_len;
if (msm_spi_set_state(dd, SPI_OP_STATE_RESET))
return 0;
dd->read_len = dd->write_len = 0;
@@ -2047,6 +2051,7 @@
}
spi_debugfs_init(dd);
+
return 0;
err_attrs:
diff --git a/drivers/spi/spi_qsd.h b/drivers/spi/spi_qsd.h
index b0d72b7..a0dee34 100644
--- a/drivers/spi/spi_qsd.h
+++ b/drivers/spi/spi_qsd.h
@@ -322,6 +322,7 @@
/* SPI CS GPIOs for each slave */
struct spi_cs_gpio cs_gpios[ARRAY_SIZE(spi_cs_rsrcs)];
int qup_ver;
+ int max_trfr_len;
};
/* Forward declaration */
diff --git a/drivers/thermal/msm8960_tsens.c b/drivers/thermal/msm8960_tsens.c
index 78a1292..daf0564 100644
--- a/drivers/thermal/msm8960_tsens.c
+++ b/drivers/thermal/msm8960_tsens.c
@@ -159,6 +159,7 @@
enum platform_type hw_type;
int pm_tsens_thr_data;
int pm_tsens_cntl;
+ struct work_struct tsens_work;
struct tsens_tm_device_sensor sensor[0];
};
@@ -610,9 +611,10 @@
NULL, "type");
}
-static irqreturn_t tsens_isr(int irq, void *data)
+static void tsens_scheduler_fn(struct work_struct *work)
{
- struct tsens_tm_device *tm = data;
+ struct tsens_tm_device *tm = container_of(work, struct tsens_tm_device,
+ tsens_work);
unsigned int threshold, threshold_low, i, code, reg, sensor, mask;
unsigned int sensor_addr;
bool upper_th_x, lower_th_x;
@@ -627,6 +629,7 @@
writel_relaxed(reg | TSENS_LOWER_STATUS_CLR |
TSENS_UPPER_STATUS_CLR, TSENS_CNTL_ADDR);
}
+
mask = ~(TSENS_LOWER_STATUS_CLR | TSENS_UPPER_STATUS_CLR);
threshold = readl_relaxed(TSENS_THRESHOLD_ADDR);
threshold_low = (threshold & TSENS_THRESHOLD_LOWER_LIMIT_MASK)
@@ -658,9 +661,7 @@
/* Notify user space */
schedule_work(&tm->sensor[i].work);
adc_code = readl_relaxed(sensor_addr);
- pr_info("\nTrip point triggered by "
- "current temperature (%d degrees) "
- "measured by Temperature-Sensor %d\n",
+ pr_debug("Trigger (%d degrees) for sensor %d\n",
tsens_tz_code_to_degC(adc_code, i), i);
}
}
@@ -672,6 +673,12 @@
else
writel_relaxed(reg & mask, TSENS_CNTL_ADDR);
mb();
+}
+
+static irqreturn_t tsens_isr(int irq, void *data)
+{
+ schedule_work(&tmdev->tsens_work);
+
return IRQ_HANDLED;
}
@@ -869,8 +876,7 @@
tmdev->sensor[TSENS_MAIN_SENSOR].calib_data =
tmdev->sensor[TSENS_MAIN_SENSOR].calib_data_backup;
if (!tmdev->sensor[TSENS_MAIN_SENSOR].calib_data) {
- pr_err("%s: No temperature sensor data for calibration"
- " in QFPROM!\n", __func__);
+ pr_err("QFPROM TSENS calibration data not present\n");
return -ENODEV;
}
@@ -901,8 +907,7 @@
tmdev->sensor[i].calib_data =
tmdev->sensor[i].calib_data_backup;
if (!tmdev->sensor[i].calib_data) {
- WARN(1, "%s: No temperature sensor:%d data for"
- " calibration in QFPROM!\n", __func__, i);
+ pr_err("QFPROM TSENS calibration data not present\n");
return -ENODEV;
}
tmdev->sensor[i].offset = (TSENS_CAL_DEGC *
@@ -1026,6 +1031,7 @@
thermal_zone_device_unregister(tmdev->sensor[i].tz_dev);
goto fail;
}
+ INIT_WORK(&tmdev->tsens_work, tsens_scheduler_fn);
pr_debug("%s: OK\n", __func__);
mb();
diff --git a/drivers/thermal/msm8974-tsens.c b/drivers/thermal/msm8974-tsens.c
index 3366bba..b97ea1c 100644
--- a/drivers/thermal/msm8974-tsens.c
+++ b/drivers/thermal/msm8974-tsens.c
@@ -71,7 +71,8 @@
#define TSENS_CAL_SEL_SHIFT 30
#define TSENS_CAL_SEL_SHIFT_2 28
#define TSENS_ONE_POINT_CALIB 0x1
-#define TSENS_TWO_POINT_CALIB 0x2
+#define TSENS_ONE_POINT_CALIB_OPTION_2 0x2
+#define TSENS_TWO_POINT_CALIB 0x3
#define TSENS0_POINT1_SHIFT 8
#define TSENS1_POINT1_SHIFT 14
@@ -574,30 +575,66 @@
return -ENODEV;
}
- if (tsens_calibration_mode == TSENS_ONE_POINT_CALIB ||
- TSENS_TWO_POINT_CALIB) {
+ if (tsens_calibration_mode == TSENS_ONE_POINT_CALIB) {
tmdev->sensor[0].calib_data_point1 =
- (((tsens_base1_data + tsens0_point1) << 2) | TSENS_BIT_APPEND);
+ (((tsens_base1_data) << 2) | TSENS_BIT_APPEND) + tsens0_point1;
tmdev->sensor[1].calib_data_point1 =
- (((tsens_base1_data + tsens1_point1) << 2) | TSENS_BIT_APPEND);
+ (((tsens_base1_data) << 2) | TSENS_BIT_APPEND) + tsens1_point1;
tmdev->sensor[2].calib_data_point1 =
- (((tsens_base1_data + tsens2_point1) << 2) | TSENS_BIT_APPEND);
+ (((tsens_base1_data) << 2) | TSENS_BIT_APPEND) + tsens2_point1;
tmdev->sensor[3].calib_data_point1 =
- (((tsens_base1_data + tsens3_point1) << 2) | TSENS_BIT_APPEND);
+ (((tsens_base1_data) << 2) | TSENS_BIT_APPEND) + tsens3_point1;
tmdev->sensor[4].calib_data_point1 =
- (((tsens_base1_data + tsens4_point1) << 2) | TSENS_BIT_APPEND);
+ (((tsens_base1_data) << 2) | TSENS_BIT_APPEND) + tsens4_point1;
tmdev->sensor[5].calib_data_point1 =
- (((tsens_base1_data + tsens5_point1) << 2) | TSENS_BIT_APPEND);
+ (((tsens_base1_data) << 2) | TSENS_BIT_APPEND) + tsens5_point1;
tmdev->sensor[6].calib_data_point1 =
- (((tsens_base1_data + tsens6_point1) << 2) | TSENS_BIT_APPEND);
+ (((tsens_base1_data) << 2) | TSENS_BIT_APPEND) + tsens6_point1;
tmdev->sensor[7].calib_data_point1 =
- (((tsens_base1_data + tsens7_point1) << 2) | TSENS_BIT_APPEND);
+ (((tsens_base1_data) << 2) | TSENS_BIT_APPEND) + tsens7_point1;
tmdev->sensor[8].calib_data_point1 =
- (((tsens_base1_data + tsens8_point1) << 2) | TSENS_BIT_APPEND);
+ (((tsens_base1_data) << 2) | TSENS_BIT_APPEND) + tsens8_point1;
tmdev->sensor[9].calib_data_point1 =
- (((tsens_base1_data + tsens9_point1) << 2) | TSENS_BIT_APPEND);
+ (((tsens_base1_data) << 2) | TSENS_BIT_APPEND) + tsens9_point1;
tmdev->sensor[10].calib_data_point1 =
- (((tsens_base1_data + tsens10_point1) << 2) | TSENS_BIT_APPEND);
+ (((tsens_base1_data) << 2) | TSENS_BIT_APPEND) + tsens10_point1;
+ }
+
+ if (tsens_calibration_mode == (TSENS_ONE_POINT_CALIB_OPTION_2 ||
+ TSENS_TWO_POINT_CALIB)) {
+ tmdev->sensor[0].calib_data_point1 =
+ ((((tsens_base1_data) + tsens0_point1) << 2) |
+ TSENS_BIT_APPEND);
+ tmdev->sensor[1].calib_data_point1 =
+ ((((tsens_base1_data) + tsens1_point1) << 2) |
+ TSENS_BIT_APPEND);
+ tmdev->sensor[2].calib_data_point1 =
+ ((((tsens_base1_data) + tsens2_point1) << 2) |
+ TSENS_BIT_APPEND);
+ tmdev->sensor[3].calib_data_point1 =
+ ((((tsens_base1_data) + tsens3_point1) << 2) |
+ TSENS_BIT_APPEND);
+ tmdev->sensor[4].calib_data_point1 =
+ ((((tsens_base1_data) + tsens4_point1) << 2) |
+ TSENS_BIT_APPEND);
+ tmdev->sensor[5].calib_data_point1 =
+ ((((tsens_base1_data) + tsens5_point1) << 2) |
+ TSENS_BIT_APPEND);
+ tmdev->sensor[6].calib_data_point1 =
+ ((((tsens_base1_data) + tsens6_point1) << 2) |
+ TSENS_BIT_APPEND);
+ tmdev->sensor[7].calib_data_point1 =
+ ((((tsens_base1_data) + tsens7_point1) << 2) |
+ TSENS_BIT_APPEND);
+ tmdev->sensor[8].calib_data_point1 =
+ ((((tsens_base1_data) + tsens8_point1) << 2) |
+ TSENS_BIT_APPEND);
+ tmdev->sensor[9].calib_data_point1 =
+ ((((tsens_base1_data) + tsens9_point1) << 2) |
+ TSENS_BIT_APPEND);
+ tmdev->sensor[10].calib_data_point1 =
+ ((((tsens_base1_data) + tsens10_point1) << 2) |
+ TSENS_BIT_APPEND);
}
if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
diff --git a/drivers/tty/Makefile b/drivers/tty/Makefile
index 9ebb54a..71f6a99 100644
--- a/drivers/tty/Makefile
+++ b/drivers/tty/Makefile
@@ -6,7 +6,7 @@
obj-$(CONFIG_MAGIC_SYSRQ) += sysrq.o
obj-$(CONFIG_N_HDLC) += n_hdlc.o
obj-$(CONFIG_N_GSM) += n_gsm.o
-obj-$(CONFIG_N_SMUX) += n_smux.o
+obj-$(CONFIG_N_SMUX) += n_smux.o smux_debug.o
obj-$(CONFIG_N_SMUX_LOOPBACK) += smux_test.o smux_loopback.o
obj-$(CONFIG_SMUX_CTL) += smux_ctl.o
obj-$(CONFIG_TRACE_ROUTER) += n_tracerouter.o
diff --git a/drivers/tty/n_smux.c b/drivers/tty/n_smux.c
index 1385e08..14b8ca2 100644
--- a/drivers/tty/n_smux.c
+++ b/drivers/tty/n_smux.c
@@ -28,12 +28,13 @@
#include <mach/subsystem_notif.h>
#include <mach/subsystem_restart.h>
#include <mach/msm_serial_hs.h>
+#include <mach/msm_ipc_logging.h>
#include "smux_private.h"
#include "smux_loopback.h"
#define SMUX_NOTIFY_FIFO_SIZE 128
#define SMUX_TX_QUEUE_SIZE 256
-#define SMUX_PKT_LOG_SIZE 80
+#define SMUX_PKT_LOG_SIZE 128
/* Maximum size we can accept in a single RX buffer */
#define TTY_RECEIVE_ROOM 65536
@@ -59,10 +60,12 @@
MSM_SMUX_PKT = 1U << 3,
};
-static int smux_debug_mask;
+static int smux_debug_mask = MSM_SMUX_DEBUG | MSM_SMUX_POWER_INFO;
module_param_named(debug_mask, smux_debug_mask,
int, S_IRUGO | S_IWUSR | S_IWGRP);
+static int disable_ipc_logging;
+
/* Simulated wakeup used for testing */
int smux_byte_loopback;
module_param_named(byte_loopback, smux_byte_loopback,
@@ -71,14 +74,24 @@
module_param_named(simulate_wakeup_delay, smux_simulate_wakeup_delay,
int, S_IRUGO | S_IWUSR | S_IWGRP);
+#define IPC_LOG_STR(x...) do { \
+ if (!disable_ipc_logging && log_ctx) \
+ ipc_log_string(log_ctx, x); \
+} while (0)
+
#define SMUX_DBG(x...) do { \
if (smux_debug_mask & MSM_SMUX_DEBUG) \
- pr_info(x); \
+ IPC_LOG_STR(x); \
+} while (0)
+
+#define SMUX_ERR(x...) do { \
+ pr_err(x); \
+ IPC_LOG_STR(x); \
} while (0)
#define SMUX_PWR(x...) do { \
if (smux_debug_mask & MSM_SMUX_POWER_INFO) \
- pr_info(x); \
+ IPC_LOG_STR(x); \
} while (0)
#define SMUX_PWR_PKT_RX(pkt) do { \
@@ -90,10 +103,10 @@
if (smux_debug_mask & MSM_SMUX_POWER_INFO) { \
if (pkt->hdr.cmd == SMUX_CMD_BYTE && \
pkt->hdr.flags == SMUX_WAKEUP_ACK) \
- pr_info("smux: TX Wakeup ACK\n"); \
+ IPC_LOG_STR("smux: TX Wakeup ACK\n"); \
else if (pkt->hdr.cmd == SMUX_CMD_BYTE && \
pkt->hdr.flags == SMUX_WAKEUP_REQ) \
- pr_info("smux: TX Wakeup REQ\n"); \
+ IPC_LOG_STR("smux: TX Wakeup REQ\n"); \
else \
smux_log_pkt(pkt, 0); \
} \
@@ -170,59 +183,6 @@
SMUX_PWR_OFF_FLUSH,
};
-/**
- * Logical Channel Structure. One instance per channel.
- *
- * Locking Hierarchy
- * Each lock has a postfix that describes the locking level. If multiple locks
- * are required, only increasing lock hierarchy numbers may be locked which
- * ensures avoiding a deadlock.
- *
- * Locking Example
- * If state_lock_lhb1 is currently held and the TX list needs to be
- * manipulated, then tx_lock_lhb2 may be locked since it's locking hierarchy
- * is greater. However, if tx_lock_lhb2 is held, then state_lock_lhb1 may
- * not be acquired since it would result in a deadlock.
- *
- * Note that the Line Discipline locks (*_lha) should always be acquired
- * before the logical channel locks.
- */
-struct smux_lch_t {
- /* channel state */
- spinlock_t state_lock_lhb1;
- uint8_t lcid;
- unsigned local_state;
- unsigned local_mode;
- uint8_t local_tiocm;
- unsigned options;
-
- unsigned remote_state;
- unsigned remote_mode;
- uint8_t remote_tiocm;
-
- int tx_flow_control;
- int rx_flow_control_auto;
- int rx_flow_control_client;
-
- /* client callbacks and private data */
- void *priv;
- void (*notify)(void *priv, int event_type, const void *metadata);
- int (*get_rx_buffer)(void *priv, void **pkt_priv, void **buffer,
- int size);
-
- /* RX Info */
- struct list_head rx_retry_queue;
- unsigned rx_retry_queue_cnt;
- struct delayed_work rx_retry_work;
-
- /* TX Info */
- spinlock_t tx_lock_lhb2;
- struct list_head tx_queue;
- struct list_head tx_ready_list;
- unsigned tx_pending_data_cnt;
- unsigned notify_lwm;
-};
-
union notifier_metadata {
struct smux_meta_disconnected disconnected;
struct smux_meta_read read;
@@ -276,6 +236,7 @@
int is_initialized;
int platform_devs_registered;
int in_reset;
+ int remote_is_alive;
int ld_open_count;
struct tty_struct *tty;
@@ -302,7 +263,7 @@
/* data structures */
-static struct smux_lch_t smux_lch[SMUX_NUM_LOGICAL_CHANNELS];
+struct smux_lch_t smux_lch[SMUX_NUM_LOGICAL_CHANNELS];
static struct smux_ldisc_t smux;
static const char *tty_error_type[] = {
[TTY_NORMAL] = "normal",
@@ -312,7 +273,7 @@
[TTY_FRAME] = "framing",
};
-static const char *smux_cmds[] = {
+static const char * const smux_cmds[] = {
[SMUX_CMD_DATA] = "DATA",
[SMUX_CMD_OPEN_LCH] = "OPEN",
[SMUX_CMD_CLOSE_LCH] = "CLOSE",
@@ -321,6 +282,44 @@
[SMUX_CMD_BYTE] = "Raw Byte",
};
+static const char * const smux_events[] = {
+ [SMUX_CONNECTED] = "CONNECTED" ,
+ [SMUX_DISCONNECTED] = "DISCONNECTED",
+ [SMUX_READ_DONE] = "READ_DONE",
+ [SMUX_READ_FAIL] = "READ_FAIL",
+ [SMUX_WRITE_DONE] = "WRITE_DONE",
+ [SMUX_WRITE_FAIL] = "WRITE_FAIL",
+ [SMUX_TIOCM_UPDATE] = "TIOCM_UPDATE",
+ [SMUX_LOW_WM_HIT] = "LOW_WM_HIT",
+ [SMUX_HIGH_WM_HIT] = "HIGH_WM_HIT",
+ [SMUX_RX_RETRY_HIGH_WM_HIT] = "RX_RETRY_HIGH_WM_HIT",
+ [SMUX_RX_RETRY_LOW_WM_HIT] = "RX_RETRY_LOW_WM_HIT",
+};
+
+static const char * const smux_local_state[] = {
+ [SMUX_LCH_LOCAL_CLOSED] = "CLOSED",
+ [SMUX_LCH_LOCAL_OPENING] = "OPENING",
+ [SMUX_LCH_LOCAL_OPENED] = "OPENED",
+ [SMUX_LCH_LOCAL_CLOSING] = "CLOSING",
+};
+
+static const char * const smux_remote_state[] = {
+ [SMUX_LCH_REMOTE_CLOSED] = "CLOSED",
+ [SMUX_LCH_REMOTE_OPENED] = "OPENED",
+};
+
+static const char * const smux_mode[] = {
+ [SMUX_LCH_MODE_NORMAL] = "N",
+ [SMUX_LCH_MODE_LOCAL_LOOPBACK] = "L",
+ [SMUX_LCH_MODE_REMOTE_LOOPBACK] = "R",
+};
+
+static const char * const smux_undef[] = {
+ [SMUX_UNDEF_LONG] = "UNDEF",
+ [SMUX_UNDEF_SHORT] = "U",
+};
+
+static void *log_ctx;
static void smux_notify_local_fn(struct work_struct *work);
static DECLARE_WORK(smux_notify_local, smux_notify_local_fn);
@@ -346,12 +345,11 @@
static DECLARE_DELAYED_WORK(smux_delayed_inactivity_work,
smux_inactivity_worker);
-static long msm_smux_tiocm_get_atomic(struct smux_lch_t *ch);
static void list_channel(struct smux_lch_t *ch);
static int smux_send_status_cmd(struct smux_lch_t *ch);
static int smux_dispatch_rx_pkt(struct smux_pkt_t *pkt);
static void smux_flush_tty(void);
-static void smux_purge_ch_tx_queue(struct smux_lch_t *ch);
+static void smux_purge_ch_tx_queue(struct smux_lch_t *ch, int is_ssr);
static int schedule_notify(uint8_t lcid, int event,
const union notifier_metadata *metadata);
static int ssr_notifier_cb(struct notifier_block *this,
@@ -363,6 +361,45 @@
static void smux_pdev_release(struct device *dev);
/**
+ * local_lch_state() - Return human readable form of local logical state.
+ * @state: Local logical channel state enum.
+ *
+ */
+const char *local_lch_state(unsigned state)
+{
+ if (state < ARRAY_SIZE(smux_local_state))
+ return smux_local_state[state];
+ else
+ return smux_undef[SMUX_UNDEF_LONG];
+}
+
+/**
+ * remote_lch_state() - Return human readable for of remote logical state.
+ * @state: Remote logical channel state enum.
+ *
+ */
+const char *remote_lch_state(unsigned state)
+{
+ if (state < ARRAY_SIZE(smux_remote_state))
+ return smux_remote_state[state];
+ else
+ return smux_undef[SMUX_UNDEF_LONG];
+}
+
+/**
+ * lch_mode() - Return human readable form of mode.
+ * @mode: Mode of the logical channel.
+ *
+ */
+const char *lch_mode(unsigned mode)
+{
+ if (mode < ARRAY_SIZE(smux_mode))
+ return smux_mode[mode];
+ else
+ return smux_undef[SMUX_UNDEF_SHORT];
+}
+
+/**
* Convert TTY Error Flags to string for logging purposes.
*
* @flag TTY_* flag
@@ -389,14 +426,31 @@
}
/**
+ * Convert SMUX event to string for logging purposes.
+ *
+ * @event SMUX event
+ * @returns String description or NULL if unknown
+ */
+static const char *event_to_str(unsigned cmd)
+{
+ if (cmd < ARRAY_SIZE(smux_events))
+ return smux_events[cmd];
+ return NULL;
+}
+
+/**
* Set the reset state due to an unrecoverable failure.
*/
static void smux_enter_reset(void)
{
- pr_err("%s: unrecoverable failure, waiting for ssr\n", __func__);
+ SMUX_ERR("%s: unrecoverable failure, waiting for ssr\n", __func__);
smux.in_reset = 1;
+ smux.remote_is_alive = 0;
}
+/**
+ * Initialize the lch_structs.
+ */
static int lch_init(void)
{
unsigned int id;
@@ -410,7 +464,7 @@
smux_rx_wq = create_singlethread_workqueue("smux_rx_wq");
if (IS_ERR(smux_notify_wq) || IS_ERR(smux_tx_wq)) {
- SMUX_DBG("%s: create_singlethread_workqueue ENOMEM\n",
+ SMUX_DBG("smux: %s: create_singlethread_workqueue ENOMEM\n",
__func__);
return -ENOMEM;
}
@@ -421,7 +475,7 @@
i |= smux_loopback_init();
if (i) {
- pr_err("%s: out of memory error\n", __func__);
+ SMUX_ERR("%s: out of memory error\n", __func__);
return -ENOMEM;
}
@@ -471,7 +525,7 @@
/* Empty TX ready list */
spin_lock_irqsave(&smux.tx_lock_lha2, flags);
while (!list_empty(&smux.lch_tx_ready_list)) {
- SMUX_DBG("%s: emptying ready list %p\n",
+ SMUX_DBG("smux: %s: emptying ready list %p\n",
__func__, smux.lch_tx_ready_list.next);
ch = list_first_entry(&smux.lch_tx_ready_list,
struct smux_lch_t,
@@ -488,7 +542,7 @@
struct smux_pkt_t,
list);
list_del(&pkt->list);
- SMUX_DBG("%s: emptying power queue pkt=%p\n",
+ SMUX_DBG("smux: %s: emptying power queue pkt=%p\n",
__func__, pkt);
smux_free_pkt(pkt);
}
@@ -497,13 +551,13 @@
/* Close all ports */
for (i = 0 ; i < SMUX_NUM_LOGICAL_CHANNELS; i++) {
ch = &smux_lch[i];
- SMUX_DBG("%s: cleaning up lcid %d\n", __func__, i);
+ SMUX_DBG("smux: %s: cleaning up lcid %d\n", __func__, i);
spin_lock_irqsave(&ch->state_lock_lhb1, flags);
/* Purge TX queue */
spin_lock(&ch->tx_lock_lhb2);
- smux_purge_ch_tx_queue(ch);
+ smux_purge_ch_tx_queue(ch, 1);
spin_unlock(&ch->tx_lock_lhb2);
/* Notify user of disconnect and reset channel state */
@@ -670,7 +724,7 @@
i += snprintf(logbuf + i, SMUX_PKT_LOG_SIZE - i,
"%02x ", (unsigned)data[count]);
- pr_info("%s\n", logbuf);
+ IPC_LOG_STR(logbuf);
}
static void smux_notify_local_fn(struct work_struct *work)
@@ -688,8 +742,9 @@
¬ify_handle,
handle_size);
if (i != handle_size) {
- pr_err("%s: unable to retrieve handle %d expected %d\n",
- __func__, i, handle_size);
+ SMUX_ERR(
+ "%s: unable to retrieve handle %d expected %d\n",
+ __func__, i, handle_size);
spin_unlock_irqrestore(¬ify_lock_lhc1, flags);
break;
}
@@ -735,7 +790,7 @@
/* Consider a free list implementation instead of kmalloc */
pkt = kmalloc(sizeof(struct smux_pkt_t), GFP_ATOMIC);
if (!pkt) {
- pr_err("%s: out of memory\n", __func__);
+ SMUX_ERR("%s: out of memory\n", __func__);
return NULL;
}
smux_init_pkt(pkt);
@@ -779,7 +834,7 @@
pkt->payload = kmalloc(pkt->hdr.payload_len, GFP_ATOMIC);
pkt->free_payload = 1;
if (!pkt->payload) {
- pr_err("%s: unable to malloc %d bytes for payload\n",
+ SMUX_ERR("%s: unable to malloc %d bytes for payload\n",
__func__, pkt->hdr.payload_len);
return -ENOMEM;
}
@@ -797,11 +852,12 @@
unsigned long flags;
int ret = 0;
+ IPC_LOG_STR("smux: %s ch:%d\n", event_to_str(event), lcid);
ch = &smux_lch[lcid];
notify_handle = kzalloc(sizeof(struct smux_notify_handle),
GFP_ATOMIC);
if (!notify_handle) {
- pr_err("%s: out of memory\n", __func__);
+ SMUX_ERR("%s: out of memory\n", __func__);
ret = -ENOMEM;
goto free_out;
}
@@ -813,7 +869,7 @@
meta_copy = kzalloc(sizeof(union notifier_metadata),
GFP_ATOMIC);
if (!meta_copy) {
- pr_err("%s: out of memory\n", __func__);
+ SMUX_ERR("%s: out of memory\n", __func__);
ret = -ENOMEM;
goto free_out;
}
@@ -826,7 +882,7 @@
spin_lock_irqsave(¬ify_lock_lhc1, flags);
i = kfifo_avail(&smux_notify_fifo);
if (i < handle_size) {
- pr_err("%s: fifo full error %d expected %d\n",
+ SMUX_ERR("%s: fifo full error %d expected %d\n",
__func__, i, handle_size);
ret = -ENOMEM;
goto unlock_out;
@@ -834,7 +890,7 @@
i = kfifo_in(&smux_notify_fifo, ¬ify_handle, handle_size);
if (i < 0 || i != handle_size) {
- pr_err("%s: fifo not available error %d (expected %d)\n",
+ SMUX_ERR("%s: fifo not available error %d (expected %d)\n",
__func__, i, handle_size);
ret = -ENOSPC;
goto unlock_out;
@@ -886,7 +942,7 @@
char *data_start = out;
if (smux_serialize_size(pkt) > SMUX_MAX_PKT_SIZE) {
- pr_err("%s: packet size %d too big\n",
+ SMUX_ERR("%s: packet size %d too big\n",
__func__, smux_serialize_size(pkt));
return -E2BIG;
}
@@ -971,7 +1027,7 @@
len -= data_written;
data += data_written;
} else {
- pr_err("%s: TTY write returned error %d\n",
+ SMUX_ERR("%s: TTY write returned error %d\n",
__func__, data_written);
return data_written;
}
@@ -997,12 +1053,12 @@
int ret;
if (!smux.tty) {
- pr_err("%s: TTY not initialized", __func__);
+ SMUX_ERR("%s: TTY not initialized", __func__);
return -ENOTTY;
}
if (pkt->hdr.cmd == SMUX_CMD_BYTE) {
- SMUX_DBG("%s: tty send single byte\n", __func__);
+ SMUX_DBG("smux: %s: tty send single byte\n", __func__);
ret = write_to_tty(&pkt->hdr.flags, 1);
return ret;
}
@@ -1010,7 +1066,7 @@
smux_serialize_hdr(pkt, &data, &len);
ret = write_to_tty(data, len);
if (ret) {
- pr_err("%s: failed %d to write header %d\n",
+ SMUX_ERR("%s: failed %d to write header %d\n",
__func__, ret, len);
return ret;
}
@@ -1018,7 +1074,7 @@
smux_serialize_payload(pkt, &data, &len);
ret = write_to_tty(data, len);
if (ret) {
- pr_err("%s: failed %d to write payload %d\n",
+ SMUX_ERR("%s: failed %d to write payload %d\n",
__func__, ret, len);
return ret;
}
@@ -1028,7 +1084,7 @@
char zero = 0x0;
ret = write_to_tty(&zero, 1);
if (ret) {
- pr_err("%s: failed %d to write padding %d\n",
+ SMUX_ERR("%s: failed %d to write padding %d\n",
__func__, ret, len);
return ret;
}
@@ -1048,7 +1104,7 @@
pkt = smux_alloc_pkt();
if (!pkt) {
- pr_err("%s: alloc failure for byte %x\n", __func__, ch);
+ SMUX_ERR("%s: alloc failure for byte %x\n", __func__, ch);
return;
}
pkt->hdr.cmd = SMUX_CMD_BYTE;
@@ -1091,7 +1147,7 @@
{
unsigned long flags;
- SMUX_DBG("%s: queuing pkt %p\n", __func__, pkt_ptr);
+ SMUX_DBG("smux: %s: queuing pkt %p\n", __func__, pkt_ptr);
spin_lock_irqsave(&ch->tx_lock_lhb2, flags);
list_add_tail(&pkt_ptr->list, &ch->tx_queue);
@@ -1120,7 +1176,7 @@
spin_lock(&ch->state_lock_lhb1);
if (ch->local_state == SMUX_LCH_LOCAL_OPENING) {
- SMUX_DBG("lcid %d local state 0x%x -> 0x%x\n", lcid,
+ SMUX_DBG("smux: lcid %d local state 0x%x -> 0x%x\n", lcid,
ch->local_state,
SMUX_LCH_LOCAL_OPENED);
@@ -1132,10 +1188,10 @@
schedule_notify(lcid, SMUX_CONNECTED, NULL);
ret = 0;
} else if (ch->remote_mode == SMUX_LCH_MODE_REMOTE_LOOPBACK) {
- SMUX_DBG("Remote loopback OPEN ACK received\n");
+ SMUX_DBG("smux: Remote loopback OPEN ACK received\n");
ret = 0;
} else {
- pr_err("%s: lcid %d state 0x%x open ack invalid\n",
+ SMUX_ERR("%s: lcid %d state 0x%x open ack invalid\n",
__func__, lcid, ch->local_state);
ret = -EINVAL;
}
@@ -1145,7 +1201,7 @@
spin_lock(&smux.tx_lock_lha2);
if (!smux.powerdown_enabled) {
smux.powerdown_enabled = 1;
- SMUX_DBG("%s: enabling power-collapse support\n",
+ SMUX_DBG("smux: %s: enabling power-collapse support\n",
__func__);
}
spin_unlock(&smux.tx_lock_lha2);
@@ -1169,7 +1225,7 @@
spin_lock_irqsave(&ch->state_lock_lhb1, flags);
if (ch->local_state == SMUX_LCH_LOCAL_CLOSING) {
- SMUX_DBG("lcid %d local state 0x%x -> 0x%x\n", lcid,
+ SMUX_DBG("smux: lcid %d local state 0x%x -> 0x%x\n", lcid,
SMUX_LCH_LOCAL_CLOSING,
SMUX_LCH_LOCAL_CLOSED);
ch->local_state = SMUX_LCH_LOCAL_CLOSED;
@@ -1178,10 +1234,10 @@
&meta_disconnected);
ret = 0;
} else if (ch->remote_mode == SMUX_LCH_MODE_REMOTE_LOOPBACK) {
- SMUX_DBG("Remote loopback CLOSE ACK received\n");
+ SMUX_DBG("smux: Remote loopback CLOSE ACK received\n");
ret = 0;
} else {
- pr_err("%s: lcid %d state 0x%x close ack invalid\n",
+ SMUX_ERR("%s: lcid %d state 0x%x close ack invalid\n",
__func__, lcid, ch->local_state);
ret = -EINVAL;
}
@@ -1215,7 +1271,7 @@
spin_lock_irqsave(&ch->state_lock_lhb1, flags);
if (ch->remote_state == SMUX_LCH_REMOTE_CLOSED) {
- SMUX_DBG("lcid %d remote state 0x%x -> 0x%x\n", lcid,
+ SMUX_DBG("smux: lcid %d remote state 0x%x -> 0x%x\n", lcid,
SMUX_LCH_REMOTE_CLOSED,
SMUX_LCH_REMOTE_OPENED);
@@ -1259,15 +1315,16 @@
smux_tx_queue(ack_pkt, ch, 0);
tx_ready = 1;
} else {
- pr_err("%s: Remote loopack allocation failure\n",
- __func__);
+ SMUX_ERR(
+ "%s: Remote loopack allocation failure\n",
+ __func__);
}
} else if (ch->local_state == SMUX_LCH_LOCAL_OPENED) {
schedule_notify(lcid, SMUX_CONNECTED, NULL);
}
ret = 0;
} else {
- pr_err("%s: lcid %d remote state 0x%x open invalid\n",
+ SMUX_ERR("%s: lcid %d remote state 0x%x open invalid\n",
__func__, lcid, ch->remote_state);
ret = -EINVAL;
}
@@ -1279,7 +1336,7 @@
spin_lock_irqsave(&smux.tx_lock_lha2, flags);
if (!smux.powerdown_enabled) {
smux.powerdown_enabled = 1;
- SMUX_DBG("%s: enabling power-collapse support\n",
+ SMUX_DBG("smux: %s: enabling power-collapse support\n",
__func__);
}
spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
@@ -1317,7 +1374,7 @@
spin_lock_irqsave(&ch->state_lock_lhb1, flags);
if (ch->remote_state == SMUX_LCH_REMOTE_OPENED) {
- SMUX_DBG("lcid %d remote state 0x%x -> 0x%x\n", lcid,
+ SMUX_DBG("smux: lcid %d remote state 0x%x -> 0x%x\n", lcid,
SMUX_LCH_REMOTE_OPENED,
SMUX_LCH_REMOTE_CLOSED);
@@ -1351,8 +1408,9 @@
smux_tx_queue(ack_pkt, ch, 0);
tx_ready = 1;
} else {
- pr_err("%s: Remote loopack allocation failure\n",
- __func__);
+ SMUX_ERR(
+ "%s: Remote loopack allocation failure\n",
+ __func__);
}
}
@@ -1361,7 +1419,7 @@
&meta_disconnected);
ret = 0;
} else {
- pr_err("%s: lcid %d remote state 0x%x close invalid\n",
+ SMUX_ERR("%s: lcid %d remote state 0x%x close invalid\n",
__func__, lcid, ch->remote_state);
ret = -EINVAL;
}
@@ -1412,7 +1470,7 @@
if (ch->local_state != SMUX_LCH_LOCAL_OPENED
&& !remote_loopback) {
- pr_err("smux: ch %d error data on local state 0x%x",
+ SMUX_ERR("smux: ch %d error data on local state 0x%x",
lcid, ch->local_state);
ret = -EIO;
spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
@@ -1420,7 +1478,7 @@
}
if (ch->remote_state != SMUX_LCH_REMOTE_OPENED) {
- pr_err("smux: ch %d error data on remote state 0x%x",
+ SMUX_ERR("smux: ch %d error data on remote state 0x%x",
lcid, ch->remote_state);
ret = -EIO;
spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
@@ -1441,8 +1499,9 @@
}
if ((ch->rx_retry_queue_cnt + 1) > SMUX_RX_RETRY_MAX_PKTS) {
/* retry queue full */
- pr_err("%s: ch %d RX retry queue full\n",
- __func__, lcid);
+ SMUX_ERR(
+ "%s: ch %d RX retry queue full; rx flow=%d\n",
+ __func__, lcid, ch->rx_flow_control_auto);
schedule_notify(lcid, SMUX_READ_FAIL, NULL);
ret = -ENOMEM;
spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
@@ -1468,7 +1527,7 @@
smux_tx_queue(ack_pkt, ch, 0);
tx_ready = 1;
} else {
- pr_err("%s: Remote loopack allocation failure\n",
+ SMUX_ERR("%s: Remote loopack allocation failure\n",
__func__);
}
} else if (!do_retry) {
@@ -1492,7 +1551,7 @@
/* buffer allocation failed - add to retry queue */
do_retry = 1;
} else if (tmp < 0) {
- pr_err("%s: ch %d Client RX buffer alloc failed %d\n",
+ SMUX_ERR("%s: ch %d Client RX buffer alloc failed %d\n",
__func__, lcid, tmp);
schedule_notify(lcid, SMUX_READ_FAIL, NULL);
ret = -ENOMEM;
@@ -1504,7 +1563,7 @@
retry = kmalloc(sizeof(struct smux_rx_pkt_retry), GFP_KERNEL);
if (!retry) {
- pr_err("%s: retry alloc failure\n", __func__);
+ SMUX_ERR("%s: retry alloc failure\n", __func__);
ret = -ENOMEM;
schedule_notify(lcid, SMUX_READ_FAIL, NULL);
goto out;
@@ -1516,7 +1575,7 @@
retry->pkt = smux_alloc_pkt();
if (!retry->pkt) {
kfree(retry);
- pr_err("%s: pkt alloc failure\n", __func__);
+ SMUX_ERR("%s: pkt alloc failure\n", __func__);
ret = -ENOMEM;
schedule_notify(lcid, SMUX_READ_FAIL, NULL);
goto out;
@@ -1562,7 +1621,7 @@
unsigned long flags;
if (!pkt || smux_assert_lch_id(pkt->hdr.lcid)) {
- pr_err("%s: invalid packet or channel id\n", __func__);
+ SMUX_ERR("%s: invalid packet or channel id\n", __func__);
return -ENXIO;
}
@@ -1571,14 +1630,14 @@
spin_lock_irqsave(&ch->state_lock_lhb1, flags);
if (ch->local_state != SMUX_LCH_LOCAL_OPENED) {
- pr_err("smux: ch %d error data on local state 0x%x",
+ SMUX_ERR("smux: ch %d error data on local state 0x%x",
lcid, ch->local_state);
ret = -EIO;
goto out;
}
if (ch->remote_state != SMUX_LCH_REMOTE_OPENED) {
- pr_err("smux: ch %d error data on remote state 0x%x",
+ SMUX_ERR("smux: ch %d error data on remote state 0x%x",
lcid, ch->remote_state);
ret = -EIO;
goto out;
@@ -1623,11 +1682,11 @@
/* logical channel flow control changed */
if (pkt->hdr.flags & SMUX_CMD_STATUS_FLOW_CNTL) {
/* disabled TX */
- SMUX_DBG("TX Flow control enabled\n");
+ SMUX_DBG("smux: TX Flow control enabled\n");
ch->tx_flow_control = 1;
} else {
/* re-enable channel */
- SMUX_DBG("TX Flow control disabled\n");
+ SMUX_DBG("smux: TX Flow control disabled\n");
ch->tx_flow_control = 0;
tx_ready = 1;
}
@@ -1671,7 +1730,7 @@
/* Power-down complete, turn off UART */
power_down = 1;
else
- pr_err("%s: sleep request ack invalid in state %d\n",
+ SMUX_ERR("%s: sleep request ack invalid in state %d\n",
__func__, smux.power_state);
} else {
/*
@@ -1690,7 +1749,7 @@
if (smux.power_state == SMUX_PWR_ON) {
ack_pkt = smux_alloc_pkt();
if (ack_pkt) {
- SMUX_PWR("%s: Power %d->%d\n", __func__,
+ SMUX_PWR("smux: %s: Power %d->%d\n", __func__,
smux.power_state,
SMUX_PWR_TURNING_OFF_FLUSH);
@@ -1706,7 +1765,7 @@
}
} else if (smux.power_state == SMUX_PWR_TURNING_OFF_FLUSH) {
/* Local power-down request still in TX queue */
- SMUX_PWR("%s: Power-down shortcut - no ack\n",
+ SMUX_PWR("smux: %s: Power-down shortcut - no ack\n",
__func__);
smux.power_ctl_remote_req_received = 1;
} else if (smux.power_state == SMUX_PWR_TURNING_OFF) {
@@ -1714,17 +1773,17 @@
* Local power-down request already sent to remote
* side, so this request gets treated as an ACK.
*/
- SMUX_PWR("%s: Power-down shortcut - no ack\n",
+ SMUX_PWR("smux: %s: Power-down shortcut - no ack\n",
__func__);
power_down = 1;
} else {
- pr_err("%s: sleep request invalid in state %d\n",
+ SMUX_ERR("%s: sleep request invalid in state %d\n",
__func__, smux.power_state);
}
}
if (power_down) {
- SMUX_PWR("%s: Power %d->%d\n", __func__,
+ SMUX_PWR("smux: %s: Power %d->%d\n", __func__,
smux.power_state, SMUX_PWR_OFF_FLUSH);
smux.power_state = SMUX_PWR_OFF_FLUSH;
queue_work(smux_tx_wq, &smux_inactivity_work);
@@ -1749,7 +1808,7 @@
case SMUX_CMD_OPEN_LCH:
SMUX_LOG_PKT_RX(pkt);
if (smux_assert_lch_id(pkt->hdr.lcid)) {
- pr_err("%s: invalid channel id %d\n",
+ SMUX_ERR("%s: invalid channel id %d\n",
__func__, pkt->hdr.lcid);
break;
}
@@ -1759,7 +1818,7 @@
case SMUX_CMD_DATA:
SMUX_LOG_PKT_RX(pkt);
if (smux_assert_lch_id(pkt->hdr.lcid)) {
- pr_err("%s: invalid channel id %d\n",
+ SMUX_ERR("%s: invalid channel id %d\n",
__func__, pkt->hdr.lcid);
break;
}
@@ -1769,7 +1828,7 @@
case SMUX_CMD_CLOSE_LCH:
SMUX_LOG_PKT_RX(pkt);
if (smux_assert_lch_id(pkt->hdr.lcid)) {
- pr_err("%s: invalid channel id %d\n",
+ SMUX_ERR("%s: invalid channel id %d\n",
__func__, pkt->hdr.lcid);
break;
}
@@ -1779,7 +1838,7 @@
case SMUX_CMD_STATUS:
SMUX_LOG_PKT_RX(pkt);
if (smux_assert_lch_id(pkt->hdr.lcid)) {
- pr_err("%s: invalid channel id %d\n",
+ SMUX_ERR("%s: invalid channel id %d\n",
__func__, pkt->hdr.lcid);
break;
}
@@ -1797,7 +1856,7 @@
default:
SMUX_LOG_PKT_RX(pkt);
- pr_err("%s: command %d unknown\n", __func__, pkt->hdr.cmd);
+ SMUX_ERR("%s: command %d unknown\n", __func__, pkt->hdr.cmd);
ret = -EINVAL;
}
return ret;
@@ -1824,7 +1883,7 @@
memcpy(&recv.hdr, data, sizeof(struct smux_hdr_t));
if (recv.hdr.magic != SMUX_MAGIC) {
- pr_err("%s: invalid header magic\n", __func__);
+ SMUX_ERR("%s: invalid header magic\n", __func__);
return -EINVAL;
}
@@ -1845,7 +1904,7 @@
if (smux.power_state == SMUX_PWR_OFF
|| smux.power_state == SMUX_PWR_TURNING_ON) {
/* wakeup system */
- SMUX_PWR("%s: Power %d->%d\n", __func__,
+ SMUX_PWR("smux: %s: Power %d->%d\n", __func__,
smux.power_state, SMUX_PWR_ON);
smux.power_state = SMUX_PWR_ON;
queue_work(smux_tx_wq, &smux_wakeup_work);
@@ -1857,7 +1916,7 @@
smux_send_byte(SMUX_WAKEUP_ACK);
} else {
/* stale wakeup request from previous wakeup */
- SMUX_PWR("%s: stale Wakeup REQ in state %d\n",
+ SMUX_PWR("smux: %s: stale Wakeup REQ in state %d\n",
__func__, smux.power_state);
}
spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
@@ -1873,7 +1932,7 @@
spin_lock_irqsave(&smux.tx_lock_lha2, flags);
if (smux.power_state == SMUX_PWR_TURNING_ON) {
/* received response to wakeup request */
- SMUX_PWR("%s: Power %d->%d\n", __func__,
+ SMUX_PWR("smux: %s: Power %d->%d\n", __func__,
smux.power_state, SMUX_PWR_ON);
smux.power_state = SMUX_PWR_ON;
queue_work(smux_tx_wq, &smux_tx_work);
@@ -1882,7 +1941,7 @@
} else if (smux.power_state != SMUX_PWR_ON) {
/* invalid message */
- SMUX_PWR("%s: stale Wakeup REQ ACK in state %d\n",
+ SMUX_PWR("smux: %s: stale Wakeup REQ ACK in state %d\n",
__func__, smux.power_state);
}
spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
@@ -1905,7 +1964,7 @@
if (smux_byte_loopback)
smux_receive_byte(SMUX_UT_ECHO_ACK_FAIL,
smux_byte_loopback);
- pr_err("%s: TTY error 0x%x - ignoring\n", __func__, flag);
+ SMUX_ERR("%s: TTY error 0x%x - ignoring\n", __func__, flag);
++*used;
return;
}
@@ -1916,11 +1975,21 @@
smux.rx_state = SMUX_RX_MAGIC;
break;
case SMUX_WAKEUP_REQ:
- SMUX_PWR("smux: RX Wakeup REQ\n");
+ SMUX_PWR("smux: smux: RX Wakeup REQ\n");
+ if (unlikely(!smux.remote_is_alive)) {
+ mutex_lock(&smux.mutex_lha0);
+ smux.remote_is_alive = 1;
+ mutex_unlock(&smux.mutex_lha0);
+ }
smux_handle_wakeup_req();
break;
case SMUX_WAKEUP_ACK:
- SMUX_PWR("smux: RX Wakeup ACK\n");
+ SMUX_PWR("smux: smux: RX Wakeup ACK\n");
+ if (unlikely(!smux.remote_is_alive)) {
+ mutex_lock(&smux.mutex_lha0);
+ smux.remote_is_alive = 1;
+ mutex_unlock(&smux.mutex_lha0);
+ }
smux_handle_wakeup_ack();
break;
default:
@@ -1928,8 +1997,8 @@
if (smux_byte_loopback && data[i] == SMUX_UT_ECHO_REQ)
smux_receive_byte(SMUX_UT_ECHO_ACK_OK,
smux_byte_loopback);
- pr_err("%s: parse error 0x%02x - ignoring\n", __func__,
- (unsigned)data[i]);
+ SMUX_ERR("%s: parse error 0x%02x - ignoring\n",
+ __func__, (unsigned)data[i]);
break;
}
}
@@ -1951,7 +2020,7 @@
int i;
if (flag) {
- pr_err("%s: TTY RX error %d\n", __func__, flag);
+ SMUX_ERR("%s: TTY RX error %d\n", __func__, flag);
smux_enter_reset();
smux.rx_state = SMUX_RX_FAILURE;
++*used;
@@ -1967,8 +2036,9 @@
smux.rx_state = SMUX_RX_HDR;
} else {
/* unexpected / trash character */
- pr_err("%s: rx parse error for char %c; *used=%d, len=%d\n",
- __func__, data[i], *used, len);
+ SMUX_ERR(
+ "%s: rx parse error for char %c; *used=%d, len=%d\n",
+ __func__, data[i], *used, len);
smux.rx_state = SMUX_RX_IDLE;
}
}
@@ -1991,7 +2061,7 @@
struct smux_hdr_t *hdr;
if (flag) {
- pr_err("%s: TTY RX error %d\n", __func__, flag);
+ SMUX_ERR("%s: TTY RX error %d\n", __func__, flag);
smux_enter_reset();
smux.rx_state = SMUX_RX_FAILURE;
++*used;
@@ -2025,7 +2095,7 @@
int remaining;
if (flag) {
- pr_err("%s: TTY RX error %d\n", __func__, flag);
+ SMUX_ERR("%s: TTY RX error %d\n", __func__, flag);
smux_enter_reset();
smux.rx_state = SMUX_RX_FAILURE;
++*used;
@@ -2073,6 +2143,24 @@
}
/**
+ * Returns true if the remote side has acknowledged a wakeup
+ * request previously, so we know that the link is alive and active.
+ *
+ * @returns true for is alive, false for not alive
+ */
+bool smux_remote_is_active(void)
+{
+ bool is_active = false;
+
+ mutex_lock(&smux.mutex_lha0);
+ if (smux.remote_is_alive)
+ is_active = true;
+ mutex_unlock(&smux.mutex_lha0);
+
+ return is_active;
+}
+
+/**
* Add channel to transmit-ready list and trigger transmit worker.
*
* @ch Channel to add
@@ -2081,7 +2169,7 @@
{
unsigned long flags;
- SMUX_DBG("%s: listing channel %d\n",
+ SMUX_DBG("smux: %s: listing channel %d\n",
__func__, ch->lcid);
spin_lock_irqsave(&smux.tx_lock_lha2, flags);
@@ -2120,11 +2208,11 @@
meta_write.write.buffer = pkt->payload;
meta_write.write.len = pkt->hdr.payload_len;
if (ret >= 0) {
- SMUX_DBG("%s: PKT write done", __func__);
+ SMUX_DBG("smux: %s: PKT write done", __func__);
schedule_notify(ch->lcid, SMUX_WRITE_DONE,
&meta_write);
} else {
- pr_err("%s: failed to write pkt %d\n",
+ SMUX_ERR("%s: failed to write pkt %d\n",
__func__, ret);
schedule_notify(ch->lcid, SMUX_WRITE_FAIL,
&meta_write);
@@ -2140,7 +2228,7 @@
{
mutex_lock(&smux.mutex_lha0);
if (!smux.tty) {
- pr_err("%s: ldisc not loaded\n", __func__);
+ SMUX_ERR("%s: ldisc not loaded\n", __func__);
mutex_unlock(&smux.mutex_lha0);
return;
}
@@ -2149,7 +2237,7 @@
msecs_to_jiffies(TTY_BUFFER_FULL_WAIT_MS));
if (tty_chars_in_buffer(smux.tty) > 0)
- pr_err("%s: unable to flush UART queue\n", __func__);
+ SMUX_ERR("%s: unable to flush UART queue\n", __func__);
mutex_unlock(&smux.mutex_lha0);
}
@@ -2158,25 +2246,35 @@
* Purge TX queue for logical channel.
*
* @ch Logical channel pointer
+ * @is_ssr 1 = this is a subsystem restart purge
*
* Must be called with the following spinlocks locked:
* state_lock_lhb1
* tx_lock_lhb2
*/
-static void smux_purge_ch_tx_queue(struct smux_lch_t *ch)
+static void smux_purge_ch_tx_queue(struct smux_lch_t *ch, int is_ssr)
{
struct smux_pkt_t *pkt;
int send_disconnect = 0;
+ struct smux_pkt_t *pkt_tmp;
+ int is_state_pkt;
- while (!list_empty(&ch->tx_queue)) {
- pkt = list_first_entry(&ch->tx_queue, struct smux_pkt_t,
- list);
- list_del(&pkt->list);
-
+ list_for_each_entry_safe(pkt, pkt_tmp, &ch->tx_queue, list) {
+ is_state_pkt = 0;
if (pkt->hdr.cmd == SMUX_CMD_OPEN_LCH) {
- /* Open was never sent, just force to closed state */
- ch->local_state = SMUX_LCH_LOCAL_CLOSED;
- send_disconnect = 1;
+ if (pkt->hdr.flags & SMUX_CMD_OPEN_ACK) {
+ /* Open ACK must still be sent */
+ is_state_pkt = 1;
+ } else {
+ /* Open never sent -- force to closed state */
+ ch->local_state = SMUX_LCH_LOCAL_CLOSED;
+ send_disconnect = 1;
+ }
+ } else if (pkt->hdr.cmd == SMUX_CMD_CLOSE_LCH) {
+ if (pkt->hdr.flags & SMUX_CMD_CLOSE_ACK)
+ is_state_pkt = 1;
+ if (!send_disconnect)
+ is_state_pkt = 1;
} else if (pkt->hdr.cmd == SMUX_CMD_DATA) {
/* Notify client of failed write */
union notifier_metadata meta_write;
@@ -2186,7 +2284,11 @@
meta_write.write.len = pkt->hdr.payload_len;
schedule_notify(ch->lcid, SMUX_WRITE_FAIL, &meta_write);
}
- smux_free_pkt(pkt);
+
+ if (!is_state_pkt || is_ssr) {
+ list_del(&pkt->list);
+ smux_free_pkt(pkt);
+ }
}
if (send_disconnect) {
@@ -2208,7 +2310,7 @@
struct uart_state *state;
if (!smux.tty || !smux.tty->driver_data) {
- pr_err("%s: unable to find UART port for tty %p\n",
+ SMUX_ERR("%s: unable to find UART port for tty %p\n",
__func__, smux.tty);
return;
}
@@ -2236,7 +2338,7 @@
struct uart_state *state;
if (!smux.tty || !smux.tty->driver_data) {
- pr_err("%s: unable to find UART port for tty %p\n",
+ SMUX_ERR("%s: unable to find UART port for tty %p\n",
__func__, smux.tty);
mutex_unlock(&smux.mutex_lha0);
return;
@@ -2276,7 +2378,7 @@
/* wakeup complete */
smux.pwr_wakeup_delay_us = 1;
spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
- SMUX_DBG("%s: wakeup complete\n", __func__);
+ SMUX_DBG("smux: %s: wakeup complete\n", __func__);
/*
* Cancel any pending retry. This avoids a race condition with
@@ -2296,17 +2398,18 @@
SMUX_WAKEUP_DELAY_MAX;
spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
- SMUX_PWR("%s: triggering wakeup\n", __func__);
+ SMUX_PWR("smux: %s: triggering wakeup\n", __func__);
smux_send_byte(SMUX_WAKEUP_REQ);
if (wakeup_delay < SMUX_WAKEUP_DELAY_MIN) {
- SMUX_DBG("%s: sleeping for %u us\n", __func__,
+ SMUX_DBG("smux: %s: sleeping for %u us\n", __func__,
wakeup_delay);
usleep_range(wakeup_delay, 2*wakeup_delay);
queue_work(smux_tx_wq, &smux_wakeup_work);
} else {
/* schedule delayed work */
- SMUX_DBG("%s: scheduling delayed wakeup in %u ms\n",
+ SMUX_DBG(
+ "smux: %s: scheduling delayed wakeup in %u ms\n",
__func__, wakeup_delay / 1000);
queue_delayed_work(smux_tx_wq,
&smux_wakeup_delayed_work,
@@ -2316,7 +2419,7 @@
/* wakeup aborted */
smux.pwr_wakeup_delay_us = 1;
spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
- SMUX_PWR("%s: wakeup aborted\n", __func__);
+ SMUX_PWR("smux: %s: wakeup aborted\n", __func__);
cancel_delayed_work(&smux_wakeup_delayed_work);
}
}
@@ -2346,7 +2449,8 @@
/* start power-down sequence */
pkt = smux_alloc_pkt();
if (pkt) {
- SMUX_PWR("%s: Power %d->%d\n", __func__,
+ SMUX_PWR(
+ "smux: %s: Power %d->%d\n", __func__,
smux.power_state,
SMUX_PWR_TURNING_OFF_FLUSH);
smux.power_state =
@@ -2360,7 +2464,7 @@
&smux.power_queue);
queue_work(smux_tx_wq, &smux_tx_work);
} else {
- pr_err("%s: packet alloc failed\n",
+ SMUX_ERR("%s: packet alloc failed\n",
__func__);
}
}
@@ -2371,7 +2475,7 @@
if (smux.power_state == SMUX_PWR_OFF_FLUSH) {
/* ready to power-down the UART */
- SMUX_PWR("%s: Power %d->%d\n", __func__,
+ SMUX_PWR("smux: %s: Power %d->%d\n", __func__,
smux.power_state, SMUX_PWR_OFF);
smux.power_state = SMUX_PWR_OFF;
@@ -2452,16 +2556,16 @@
smux.rx_activity_flag = 1;
spin_unlock_irqrestore(&smux.rx_lock_lha1, flags);
- SMUX_DBG("%s: %p, len=%d, flag=%d\n", __func__, data, len, flag);
+ SMUX_DBG("smux: %s: %p, len=%d, flag=%d\n", __func__, data, len, flag);
used = 0;
do {
if (smux.in_reset) {
- SMUX_DBG("%s: abort RX due to reset\n", __func__);
+ SMUX_DBG("smux: %s: abort RX due to reset\n", __func__);
smux.rx_state = SMUX_RX_IDLE;
break;
}
- SMUX_DBG("%s: state %d; %d of %d\n",
+ SMUX_DBG("smux: %s: state %d; %d of %d\n",
__func__, smux.rx_state, used, len);
initial_rx_state = smux.rx_state;
@@ -2479,7 +2583,7 @@
smux_rx_handle_pkt_payload(data, len, &used, flag);
break;
default:
- SMUX_DBG("%s: invalid state %d\n",
+ SMUX_DBG("smux: %s: invalid state %d\n",
__func__, smux.rx_state);
smux.rx_state = SMUX_RX_IDLE;
break;
@@ -2520,7 +2624,7 @@
}
if (list_empty(&ch->rx_retry_queue)) {
- SMUX_DBG("%s: retry list empty for channel %d\n",
+ SMUX_DBG("smux: %s: retry list empty for channel %d\n",
__func__, ch->lcid);
spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
return;
@@ -2530,7 +2634,7 @@
rx_retry_list);
spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
- SMUX_DBG("%s: ch %d retrying rx pkt %p\n",
+ SMUX_DBG("smux: %s: ch %d retrying rx pkt %p\n",
__func__, ch->lcid, retry);
metadata.read.pkt_priv = 0;
metadata.read.buffer = 0;
@@ -2559,7 +2663,7 @@
retry->timeout_in_ms <<= 1;
if (retry->timeout_in_ms > SMUX_RX_RETRY_MAX_MS) {
/* timed out */
- pr_err("%s: ch %d RX retry client timeout\n",
+ SMUX_ERR("%s: ch %d RX retry client timeout\n",
__func__, ch->lcid);
spin_lock_irqsave(&ch->state_lock_lhb1, flags);
tx_ready = smux_remove_rx_retry(ch, retry);
@@ -2570,7 +2674,7 @@
}
} else {
/* client error - drop packet */
- pr_err("%s: ch %d RX retry client failed (%d)\n",
+ SMUX_ERR("%s: ch %d RX retry client failed (%d)\n",
__func__, ch->lcid, tmp);
spin_lock_irqsave(&ch->state_lock_lhb1, flags);
tx_ready = smux_remove_rx_retry(ch, retry);
@@ -2635,7 +2739,7 @@
if (!list_empty(&smux.lch_tx_ready_list) ||
!list_empty(&smux.power_queue)) {
/* data to transmit, do wakeup */
- SMUX_PWR("%s: Power %d->%d\n", __func__,
+ SMUX_PWR("smux: %s: Power %d->%d\n", __func__,
smux.power_state,
SMUX_PWR_TURNING_ON);
smux.power_state = SMUX_PWR_TURNING_ON;
@@ -2669,7 +2773,8 @@
* and we already received a remote
* power-down request.
*/
- SMUX_PWR("%s: Power %d->%d\n", __func__,
+ SMUX_PWR(
+ "smux: %s: Power %d->%d\n", __func__,
smux.power_state,
SMUX_PWR_OFF_FLUSH);
smux.power_state = SMUX_PWR_OFF_FLUSH;
@@ -2678,7 +2783,8 @@
&smux_inactivity_work);
} else {
/* sending local power-down request */
- SMUX_PWR("%s: Power %d->%d\n", __func__,
+ SMUX_PWR(
+ "smux: %s: Power %d->%d\n", __func__,
smux.power_state,
SMUX_PWR_TURNING_OFF);
smux.power_state = SMUX_PWR_TURNING_OFF;
@@ -2704,7 +2810,7 @@
/* get the next ready channel */
if (list_empty(&smux.lch_tx_ready_list)) {
/* no ready channels */
- SMUX_DBG("%s: no more ready channels, exiting\n",
+ SMUX_DBG("smux: %s: no more ready channels, exiting\n",
__func__);
spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
break;
@@ -2713,7 +2819,7 @@
if (smux.power_state != SMUX_PWR_ON) {
/* channel not ready to transmit */
- SMUX_DBG("%s: waiting for link up (state %d)\n",
+ SMUX_DBG("smux: %s: waiting for link up (state %d)\n",
__func__,
smux.power_state);
spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
@@ -2824,11 +2930,11 @@
{
smux.in_reset = 1;
- SMUX_DBG("%s: flushing tx wq\n", __func__);
+ SMUX_DBG("smux: %s: flushing tx wq\n", __func__);
flush_workqueue(smux_tx_wq);
- SMUX_DBG("%s: flushing rx wq\n", __func__);
+ SMUX_DBG("smux: %s: flushing rx wq\n", __func__);
flush_workqueue(smux_rx_wq);
- SMUX_DBG("%s: flushing notify wq\n", __func__);
+ SMUX_DBG("smux: %s: flushing notify wq\n", __func__);
flush_workqueue(smux_notify_wq);
}
@@ -2886,13 +2992,13 @@
/* Auto RX Flow Control */
if (set & SMUX_CH_OPTION_AUTO_REMOTE_TX_STOP) {
- SMUX_DBG("%s: auto rx flow control option enabled\n",
+ SMUX_DBG("smux: %s: auto rx flow control option enabled\n",
__func__);
ch->options |= SMUX_CH_OPTION_AUTO_REMOTE_TX_STOP;
}
if (clear & SMUX_CH_OPTION_AUTO_REMOTE_TX_STOP) {
- SMUX_DBG("%s: auto rx flow control option disabled\n",
+ SMUX_DBG("smux: %s: auto rx flow control option disabled\n",
__func__);
ch->options &= ~SMUX_CH_OPTION_AUTO_REMOTE_TX_STOP;
ch->rx_flow_control_auto = 0;
@@ -2947,13 +3053,13 @@
}
if (ch->local_state != SMUX_LCH_LOCAL_CLOSED) {
- pr_err("%s: open lcid %d local state %x invalid\n",
+ SMUX_ERR("%s: open lcid %d local state %x invalid\n",
__func__, lcid, ch->local_state);
ret = -EINVAL;
goto out;
}
- SMUX_DBG("lcid %d local state 0x%x -> 0x%x\n", lcid,
+ SMUX_DBG("smux: lcid %d local state 0x%x -> 0x%x\n", lcid,
ch->local_state,
SMUX_LCH_LOCAL_OPENING);
@@ -3017,16 +3123,17 @@
ch->remote_tiocm = 0x0;
ch->tx_pending_data_cnt = 0;
ch->notify_lwm = 0;
+ ch->tx_flow_control = 0;
/* Purge TX queue */
spin_lock(&ch->tx_lock_lhb2);
- smux_purge_ch_tx_queue(ch);
+ smux_purge_ch_tx_queue(ch, 0);
spin_unlock(&ch->tx_lock_lhb2);
/* Send Close Command */
if (ch->local_state == SMUX_LCH_LOCAL_OPENED ||
ch->local_state == SMUX_LCH_LOCAL_OPENING) {
- SMUX_DBG("lcid %d local state 0x%x -> 0x%x\n", lcid,
+ SMUX_DBG("smux: lcid %d local state 0x%x -> 0x%x\n", lcid,
ch->local_state,
SMUX_LCH_LOCAL_CLOSING);
@@ -3041,7 +3148,7 @@
smux_tx_queue(pkt, ch, 0);
tx_ready = 1;
} else {
- pr_err("%s: pkt allocation failed\n", __func__);
+ SMUX_ERR("%s: pkt allocation failed\n", __func__);
ret = -ENOMEM;
}
@@ -3091,14 +3198,14 @@
if (ch->local_state != SMUX_LCH_LOCAL_OPENED &&
ch->local_state != SMUX_LCH_LOCAL_OPENING) {
- pr_err("%s: hdr.invalid local state %d channel %d\n",
+ SMUX_ERR("%s: hdr.invalid local state %d channel %d\n",
__func__, ch->local_state, lcid);
ret = -EINVAL;
goto out;
}
if (len > SMUX_MAX_PKT_SIZE - sizeof(struct smux_hdr_t)) {
- pr_err("%s: payload %d too large\n",
+ SMUX_ERR("%s: payload %d too large\n",
__func__, len);
ret = -E2BIG;
goto out;
@@ -3120,10 +3227,10 @@
spin_lock(&ch->tx_lock_lhb2);
/* verify high watermark */
- SMUX_DBG("%s: pending %d", __func__, ch->tx_pending_data_cnt);
+ SMUX_DBG("smux: %s: pending %d", __func__, ch->tx_pending_data_cnt);
if (ch->tx_pending_data_cnt >= SMUX_TX_WM_HIGH) {
- pr_err("%s: ch %d high watermark %d exceeded %d\n",
+ SMUX_ERR("%s: ch %d high watermark %d exceeded %d\n",
__func__, lcid, SMUX_TX_WM_HIGH,
ch->tx_pending_data_cnt);
ret = -EAGAIN;
@@ -3133,7 +3240,7 @@
/* queue packet for transmit */
if (++ch->tx_pending_data_cnt == SMUX_TX_WM_HIGH) {
ch->notify_lwm = 1;
- pr_err("%s: high watermark hit\n", __func__);
+ SMUX_ERR("%s: high watermark hit\n", __func__);
schedule_notify(lcid, SMUX_HIGH_WM_HIT, NULL);
}
list_add_tail(&pkt->list, &ch->tx_queue);
@@ -3251,7 +3358,7 @@
*
* @returns TIOCM status
*/
-static long msm_smux_tiocm_get_atomic(struct smux_lch_t *ch)
+long msm_smux_tiocm_get_atomic(struct smux_lch_t *ch)
{
long status = 0x0;
@@ -3369,24 +3476,26 @@
int power_off_uart = 0;
if (code == SUBSYS_BEFORE_SHUTDOWN) {
- SMUX_DBG("%s: ssr - before shutdown\n", __func__);
+ SMUX_DBG("smux: %s: ssr - before shutdown\n", __func__);
mutex_lock(&smux.mutex_lha0);
smux.in_reset = 1;
+ smux.remote_is_alive = 0;
mutex_unlock(&smux.mutex_lha0);
return NOTIFY_DONE;
} else if (code == SUBSYS_AFTER_POWERUP) {
/* re-register platform devices */
- SMUX_DBG("%s: ssr - after power-up\n", __func__);
+ SMUX_DBG("smux: %s: ssr - after power-up\n", __func__);
mutex_lock(&smux.mutex_lha0);
if (smux.ld_open_count > 0
&& !smux.platform_devs_registered) {
for (i = 0; i < ARRAY_SIZE(smux_devs); ++i) {
- SMUX_DBG("%s: register pdev '%s'\n",
+ SMUX_DBG("smux: %s: register pdev '%s'\n",
__func__, smux_devs[i].name);
smux_devs[i].dev.release = smux_pdev_release;
tmp = platform_device_register(&smux_devs[i]);
if (tmp)
- pr_err("%s: error %d registering device %s\n",
+ SMUX_ERR(
+ "%s: error %d registering device %s\n",
__func__, tmp, smux_devs[i].name);
}
smux.platform_devs_registered = 1;
@@ -3396,7 +3505,7 @@
} else if (code != SUBSYS_AFTER_SHUTDOWN) {
return NOTIFY_DONE;
}
- SMUX_DBG("%s: ssr - after shutdown\n", __func__);
+ SMUX_DBG("smux: %s: ssr - after shutdown\n", __func__);
/* Cleanup channels */
smux_flush_workqueues();
@@ -3409,7 +3518,7 @@
/* Unregister platform devices */
if (smux.platform_devs_registered) {
for (i = 0; i < ARRAY_SIZE(smux_devs); ++i) {
- SMUX_DBG("%s: unregister pdev '%s'\n",
+ SMUX_DBG("smux: %s: unregister pdev '%s'\n",
__func__, smux_devs[i].name);
platform_device_unregister(&smux_devs[i]);
}
@@ -3419,7 +3528,8 @@
/* Power-down UART */
spin_lock_irqsave(&smux.tx_lock_lha2, flags);
if (smux.power_state != SMUX_PWR_OFF) {
- SMUX_PWR("%s: SSR - turning off UART\n", __func__);
+ SMUX_PWR("smux: %s: SSR - turning off UART\n",
+ __func__);
smux.power_state = SMUX_PWR_OFF;
power_off_uart = 1;
}
@@ -3433,6 +3543,7 @@
smux.rx_activity_flag = 0;
smux.rx_state = SMUX_RX_IDLE;
smux.in_reset = 0;
+ smux.remote_is_alive = 0;
mutex_unlock(&smux.mutex_lha0);
return NOTIFY_DONE;
@@ -3446,7 +3557,8 @@
struct platform_device *pdev;
pdev = container_of(dev, struct platform_device, dev);
- SMUX_DBG("%s: releasing pdev %p '%s'\n", __func__, pdev, pdev->name);
+ SMUX_DBG("smux: %s: releasing pdev %p '%s'\n",
+ __func__, pdev, pdev->name);
memset(&pdev->dev, 0x0, sizeof(pdev->dev));
}
@@ -3461,14 +3573,14 @@
mutex_lock(&smux.mutex_lha0);
if (smux.ld_open_count) {
- pr_err("%s: %p multiple instances not supported\n",
+ SMUX_ERR("%s: %p multiple instances not supported\n",
__func__, tty);
mutex_unlock(&smux.mutex_lha0);
return -EEXIST;
}
if (tty->ops->write == NULL) {
- pr_err("%s: tty->ops->write already NULL\n", __func__);
+ SMUX_ERR("%s: tty->ops->write already NULL\n", __func__);
mutex_unlock(&smux.mutex_lha0);
return -EINVAL;
}
@@ -3484,7 +3596,7 @@
/* power-down the UART if we are idle */
spin_lock_irqsave(&smux.tx_lock_lha2, flags);
if (smux.power_state == SMUX_PWR_OFF) {
- SMUX_PWR("%s: powering off uart\n", __func__);
+ SMUX_PWR("smux: %s: powering off uart\n", __func__);
smux.power_state = SMUX_PWR_OFF_FLUSH;
spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
queue_work(smux_tx_wq, &smux_inactivity_work);
@@ -3494,12 +3606,12 @@
/* register platform devices */
for (i = 0; i < ARRAY_SIZE(smux_devs); ++i) {
- SMUX_DBG("%s: register pdev '%s'\n",
+ SMUX_DBG("smux: %s: register pdev '%s'\n",
__func__, smux_devs[i].name);
smux_devs[i].dev.release = smux_pdev_release;
tmp = platform_device_register(&smux_devs[i]);
if (tmp)
- pr_err("%s: error %d registering device %s\n",
+ SMUX_ERR("%s: error %d registering device %s\n",
__func__, tmp, smux_devs[i].name);
}
smux.platform_devs_registered = 1;
@@ -3513,12 +3625,12 @@
int power_up_uart = 0;
int i;
- SMUX_DBG("%s: ldisc unload\n", __func__);
+ SMUX_DBG("smux: %s: ldisc unload\n", __func__);
smux_flush_workqueues();
mutex_lock(&smux.mutex_lha0);
if (smux.ld_open_count <= 0) {
- pr_err("%s: invalid ld count %d\n", __func__,
+ SMUX_ERR("%s: invalid ld count %d\n", __func__,
smux.ld_open_count);
mutex_unlock(&smux.mutex_lha0);
return;
@@ -3531,7 +3643,7 @@
/* Unregister platform devices */
if (smux.platform_devs_registered) {
for (i = 0; i < ARRAY_SIZE(smux_devs); ++i) {
- SMUX_DBG("%s: unregister pdev '%s'\n",
+ SMUX_DBG("smux: %s: unregister pdev '%s'\n",
__func__, smux_devs[i].name);
platform_device_unregister(&smux_devs[i]);
}
@@ -3555,8 +3667,9 @@
/* Disconnect from TTY */
smux.tty = NULL;
+ smux.remote_is_alive = 0;
mutex_unlock(&smux.mutex_lha0);
- SMUX_DBG("%s: ldisc complete\n", __func__);
+ SMUX_DBG("smux: %s: ldisc complete\n", __func__);
}
/**
@@ -3575,16 +3688,12 @@
const char *tty_name = NULL;
char *f;
- if (smux_debug_mask & MSM_SMUX_DEBUG)
- print_hex_dump(KERN_INFO, "smux tty rx: ", DUMP_PREFIX_OFFSET,
- 16, 1, cp, count, true);
-
/* verify error flags */
for (i = 0, f = fp; i < count; ++i, ++f) {
if (*f != TTY_NORMAL) {
if (tty)
tty_name = tty->name;
- pr_err("%s: TTY %s Error %d (%s)\n", __func__,
+ SMUX_ERR("%s: TTY %s Error %d (%s)\n", __func__,
tty_name, *f, tty_flag_to_str(*f));
/* feed all previous valid data to the parser */
@@ -3603,46 +3712,46 @@
static void smuxld_flush_buffer(struct tty_struct *tty)
{
- pr_err("%s: not supported\n", __func__);
+ SMUX_ERR("%s: not supported\n", __func__);
}
static ssize_t smuxld_chars_in_buffer(struct tty_struct *tty)
{
- pr_err("%s: not supported\n", __func__);
+ SMUX_ERR("%s: not supported\n", __func__);
return -ENODEV;
}
static ssize_t smuxld_read(struct tty_struct *tty, struct file *file,
unsigned char __user *buf, size_t nr)
{
- pr_err("%s: not supported\n", __func__);
+ SMUX_ERR("%s: not supported\n", __func__);
return -ENODEV;
}
static ssize_t smuxld_write(struct tty_struct *tty, struct file *file,
const unsigned char *buf, size_t nr)
{
- pr_err("%s: not supported\n", __func__);
+ SMUX_ERR("%s: not supported\n", __func__);
return -ENODEV;
}
static int smuxld_ioctl(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg)
{
- pr_err("%s: not supported\n", __func__);
+ SMUX_ERR("%s: not supported\n", __func__);
return -ENODEV;
}
static unsigned int smuxld_poll(struct tty_struct *tty, struct file *file,
struct poll_table_struct *tbl)
{
- pr_err("%s: not supported\n", __func__);
+ SMUX_ERR("%s: not supported\n", __func__);
return -ENODEV;
}
static void smuxld_write_wakeup(struct tty_struct *tty)
{
- pr_err("%s: not supported\n", __func__);
+ SMUX_ERR("%s: not supported\n", __func__);
}
static struct tty_ldisc_ops smux_ldisc_ops = {
@@ -3680,6 +3789,7 @@
smux.tty = NULL;
smux.ld_open_count = 0;
smux.in_reset = 0;
+ smux.remote_is_alive = 0;
smux.is_initialized = 1;
smux.platform_devs_registered = 0;
smux_byte_loopback = 0;
@@ -3689,7 +3799,7 @@
ret = tty_register_ldisc(N_SMUX, &smux_ldisc_ops);
if (ret != 0) {
- pr_err("%s: error %d registering line discipline\n",
+ SMUX_ERR("%s: error %d registering line discipline\n",
__func__, ret);
return ret;
}
@@ -3698,10 +3808,16 @@
ret = lch_init();
if (ret != 0) {
- pr_err("%s: lch_init failed\n", __func__);
+ SMUX_ERR("%s: lch_init failed\n", __func__);
return ret;
}
+ log_ctx = ipc_log_context_create(1, "smux");
+ if (!log_ctx) {
+ SMUX_ERR("%s: unable to create log context\n", __func__);
+ disable_ipc_logging = 1;
+ }
+
return 0;
}
@@ -3711,7 +3827,7 @@
ret = tty_unregister_ldisc(N_SMUX);
if (ret != 0) {
- pr_err("%s error %d unregistering line discipline\n",
+ SMUX_ERR("%s error %d unregistering line discipline\n",
__func__, ret);
return;
}
diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c
index a5235ba..e6f5bf5 100644
--- a/drivers/tty/serial/msm_serial.c
+++ b/drivers/tty/serial/msm_serial.c
@@ -503,7 +503,7 @@
if (msm_port->uim) {
msm_write(port,
- UART_SIM_CFG_STOP_BIT_LEN_N(1) |
+ UART_SIM_CFG_STOP_BIT_LEN_N(2) |
UART_SIM_CFG_SIM_CLK_ON |
UART_SIM_CFG_SIM_CLK_STOP_HIGH |
UART_SIM_CFG_MASK_RX |
diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c
index 9386804..3f4d87b 100644
--- a/drivers/tty/serial/msm_serial_hs.c
+++ b/drivers/tty/serial/msm_serial_hs.c
@@ -484,8 +484,9 @@
* Goal is to have around 8 ms before indicate stale.
* roundup (((Bit Rate * .008) / 10) + 1
*/
-static void msm_hs_set_bps_locked(struct uart_port *uport,
- unsigned int bps)
+static unsigned long msm_hs_set_bps_locked(struct uart_port *uport,
+ unsigned int bps,
+ unsigned long flags)
{
unsigned long rxstale;
unsigned long data;
@@ -584,11 +585,16 @@
} else {
uport->uartclk = 7372800;
}
+
+ spin_unlock_irqrestore(&uport->lock, flags);
if (clk_set_rate(msm_uport->clk, uport->uartclk)) {
printk(KERN_WARNING "Error setting clock rate on UART\n");
- return;
+ WARN_ON(1);
+ spin_lock_irqsave(&uport->lock, flags);
+ return flags;
}
+ spin_lock_irqsave(&uport->lock, flags);
data = rxstale & UARTDM_IPR_STALE_LSB_BMSK;
data |= UARTDM_IPR_STALE_TIMEOUT_MSB_BMSK & (rxstale << 2);
@@ -600,6 +606,7 @@
*/
msm_hs_write(uport, UARTDM_CR_ADDR, RESET_TX);
msm_hs_write(uport, UARTDM_CR_ADDR, RESET_RX);
+ return flags;
}
@@ -668,6 +675,7 @@
unsigned int c_cflag = termios->c_cflag;
struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
+ mutex_lock(&msm_uport->clk_mutex);
spin_lock_irqsave(&uport->lock, flags);
/*
@@ -694,7 +702,7 @@
if (!uport->uartclk)
msm_hs_set_std_bps_locked(uport, bps);
else
- msm_hs_set_bps_locked(uport, bps);
+ flags = msm_hs_set_bps_locked(uport, bps, flags);
data = msm_hs_read(uport, UARTDM_MR2_ADDR);
data &= ~UARTDM_MR2_PARITY_MODE_BMSK;
@@ -777,6 +785,7 @@
msm_hs_write(uport, UARTDM_IMR_ADDR, msm_uport->imr_reg);
mb();
spin_unlock_irqrestore(&uport->lock, flags);
+ mutex_unlock(&msm_uport->clk_mutex);
}
/*
diff --git a/drivers/tty/smux_debug.c b/drivers/tty/smux_debug.c
new file mode 100644
index 0000000..86377d6
--- /dev/null
+++ b/drivers/tty/smux_debug.c
@@ -0,0 +1,170 @@
+/* drivers/tty/smux_debug.c
+ *
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/debugfs.h>
+#include <linux/list.h>
+#include <linux/ctype.h>
+#include <linux/jiffies.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/completion.h>
+#include <linux/termios.h>
+#include <linux/smux.h>
+#include "smux_private.h"
+
+#define DEBUG_BUFMAX 4096
+
+
+
+/**
+ * smux_dump_ch() - Dumps the information of a channel to the screen.
+ * @buf: Buffer for status message.
+ * @max: Size of status queue.
+ * @lch_number: Number of the logical channel.
+ * @lch: Pointer to the lch_number'th instance of struct smux_lch_t.
+ *
+ */
+static int smux_dump_ch(char *buf, int max, struct smux_lch_t *lch)
+{
+ int bytes_written;
+ long tiocm_bits;
+ unsigned long flags;
+
+ spin_lock_irqsave(&lch->state_lock_lhb1, flags);
+ spin_lock(&lch->tx_lock_lhb2);
+
+ tiocm_bits = msm_smux_tiocm_get_atomic(lch);
+
+ bytes_written = scnprintf(
+ buf, max,
+ "ch%02d: "
+ "%s(%s) "
+ "%c%c%c%c%c "
+ "%d "
+ "%s(%s) "
+ "%c%c\n",
+ lch->lcid,
+ local_lch_state(lch->local_state), lch_mode(lch->local_mode),
+ (tiocm_bits & TIOCM_DSR) ? 'D' : 'd',
+ (tiocm_bits & TIOCM_CTS) ? 'T' : 't',
+ (tiocm_bits & TIOCM_RI) ? 'I' : 'i',
+ (tiocm_bits & TIOCM_CD) ? 'C' : 'c',
+ lch->tx_flow_control ? 'F' : 'f',
+ lch->tx_pending_data_cnt,
+ remote_lch_state(lch->remote_state), lch_mode(lch->remote_mode),
+ (tiocm_bits & TIOCM_DTR) ? 'R' : 'r',
+ (tiocm_bits & TIOCM_RTS) ? 'S' : 's'
+ );
+
+ spin_unlock(&lch->tx_lock_lhb2);
+ spin_unlock_irqrestore(&lch->state_lock_lhb1, flags);
+
+ return bytes_written;
+}
+
+/**
+ * smux_dump_format_ch() - Informs user of format for channel dump
+ * @buf: Buffer for status message.
+ * @max: Size of status queue.
+ *
+ */
+static int smux_dump_format_ch(char *buf, int max)
+{
+ return scnprintf(
+ buf, max,
+ "ch_id "
+ "local state(mode) tiocm "
+ "tx_queue "
+ "remote state(mode) tiocm\n"
+ "local tiocm: DSR(D) CTS(T) RI(I) DCD(C) FLOW_CONTROL(F)\n"
+ "remote tiocm: DTR(R) RTS(S)\n"
+ "A capital letter indicates set, otherwise, it is not set.\n\n"
+ );
+}
+
+/**
+ * smux_debug_ch() - Log following information about each channel
+ * local open, local mode, remote open, remote mode,
+ * tiocm bits, flow control state and transmit queue size.
+ * Returns the number of bytes written to buf.
+ * @buf Buffer for status message
+ * @max Size of status queue
+ *
+ */
+static int smux_debug_ch(char *buf, int max)
+{
+ int ch_id;
+
+ int bytes_written = smux_dump_format_ch(buf, max);
+
+ for (ch_id = 0; ch_id < SMUX_NUM_LOGICAL_CHANNELS; ch_id++) {
+ bytes_written += smux_dump_ch(buf + bytes_written,
+ max - bytes_written,
+ &smux_lch[ch_id]);
+ }
+
+ return bytes_written;
+
+}
+
+static char debug_buffer[DEBUG_BUFMAX];
+
+static ssize_t debug_read(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ int (*fill)(char *buf, int max) = file->private_data;
+ int bsize;
+
+ if (*ppos != 0)
+ return 0;
+
+ bsize = fill(debug_buffer, DEBUG_BUFMAX);
+ return simple_read_from_buffer(buf, count, ppos, debug_buffer, bsize);
+}
+
+static int debug_open(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+static const struct file_operations debug_ops = {
+ .read = debug_read,
+ .open = debug_open,
+};
+
+
+static void debug_create(const char *name, mode_t mode,
+ struct dentry *dent,
+ int (*fill)(char *buf, int max))
+{
+ debugfs_create_file(name, mode, dent, fill, &debug_ops);
+}
+
+
+static int __init smux_debugfs_init(void)
+{
+ struct dentry *dent;
+
+ dent = debugfs_create_dir("n_smux", 0);
+ if (IS_ERR(dent))
+ return PTR_ERR(dent);
+
+ debug_create("ch", 0444, dent, smux_debug_ch);
+
+
+ return 0;
+}
+
+late_initcall(smux_debugfs_init);
diff --git a/drivers/tty/smux_private.h b/drivers/tty/smux_private.h
index 353c762..195ee0f 100644
--- a/drivers/tty/smux_private.h
+++ b/drivers/tty/smux_private.h
@@ -31,14 +31,70 @@
#define SMUX_UT_ECHO_ACK_FAIL 0xF2
/* Maximum number of packets in retry queue */
-#define SMUX_RX_RETRY_MAX_PKTS 32
-#define SMUX_RX_WM_HIGH 16
-#define SMUX_RX_WM_LOW 4
-#define SMUX_TX_WM_LOW 2
-#define SMUX_TX_WM_HIGH 4
+#define SMUX_RX_RETRY_MAX_PKTS 128
+#define SMUX_RX_WM_HIGH 4
+#define SMUX_RX_WM_LOW 0
+#define SMUX_TX_WM_LOW 2
+#define SMUX_TX_WM_HIGH 4
struct tty_struct;
+/**
+ * Logical Channel Structure. One instance per channel.
+ *
+ * Locking Hierarchy
+ * Each lock has a postfix that describes the locking level. If multiple locks
+ * are required, only increasing lock hierarchy numbers may be locked which
+ * ensures avoiding a deadlock.
+ *
+ * Locking Example
+ * If state_lock_lhb1 is currently held and the TX list needs to be
+ * manipulated, then tx_lock_lhb2 may be locked since it's locking hierarchy
+ * is greater. However, if tx_lock_lhb2 is held, then state_lock_lhb1 may
+ * not be acquired since it would result in a deadlock.
+ *
+ * Note that the Line Discipline locks (*_lha) should always be acquired
+ * before the logical channel locks.
+ */
+struct smux_lch_t {
+ /* channel state */
+ spinlock_t state_lock_lhb1;
+ uint8_t lcid;
+ unsigned local_state;
+ unsigned local_mode;
+ uint8_t local_tiocm;
+ unsigned options;
+
+ unsigned remote_state;
+ unsigned remote_mode;
+ uint8_t remote_tiocm;
+
+ int tx_flow_control;
+ int rx_flow_control_auto;
+ int rx_flow_control_client;
+
+ /* client callbacks and private data */
+ void *priv;
+ void (*notify)(void *priv, int event_type, const void *metadata);
+ int (*get_rx_buffer)(void *priv, void **pkt_priv, void **buffer,
+ int size);
+
+ /* RX Info */
+ struct list_head rx_retry_queue;
+ unsigned rx_retry_queue_cnt;
+ struct delayed_work rx_retry_work;
+
+ /* TX Info */
+ spinlock_t tx_lock_lhb2;
+ struct list_head tx_queue;
+ struct list_head tx_ready_list;
+ unsigned tx_pending_data_cnt;
+ unsigned notify_lwm;
+};
+
+/* Each instance of smux_lch_t */
+extern struct smux_lch_t smux_lch[SMUX_NUM_LOGICAL_CHANNELS];
+
/* Packet header. */
struct smux_hdr_t {
uint16_t magic;
@@ -102,6 +158,16 @@
SMUX_LCH_REMOTE_OPENED,
};
+/* Enum used to report various undefined actions */
+enum {
+ SMUX_UNDEF_LONG,
+ SMUX_UNDEF_SHORT,
+};
+
+long msm_smux_tiocm_get_atomic(struct smux_lch_t *ch);
+const char *local_lch_state(unsigned state);
+const char *remote_lch_state(unsigned state);
+const char *lch_mode(unsigned mode);
int smux_assert_lch_id(uint32_t lcid);
void smux_init_pkt(struct smux_pkt_t *pkt);
@@ -114,6 +180,7 @@
void smux_rx_state_machine(const unsigned char *data, int len, int flag);
void smuxld_receive_buf(struct tty_struct *tty, const unsigned char *cp,
char *fp, int count);
+bool smux_remote_is_active(void);
/* testing parameters */
extern int smux_byte_loopback;
diff --git a/drivers/tty/smux_test.c b/drivers/tty/smux_test.c
index 4c255a4..81ac04b 100644
--- a/drivers/tty/smux_test.c
+++ b/drivers/tty/smux_test.c
@@ -690,6 +690,7 @@
};
int i = 0;
int failed = 0;
+ int retry_count = 0;
int ret;
i += scnprintf(buf + i, max - i, "Running %s\n", __func__);
@@ -701,7 +702,13 @@
i += smux_ut_basic_core(buf + i, max - i, test_data, __func__);
subsystem_restart("external_modem");
- msleep(5000);
+
+ do {
+ msleep(500);
+ ++retry_count;
+ UT_ASSERT_INT(retry_count, <, 20);
+ } while (!smux_remote_is_active() && !failed);
+
i += smux_ut_basic_core(buf + i, max - i, test_data, __func__);
break;
}
@@ -721,6 +728,7 @@
static struct smux_mock_callback cb_data;
static int cb_initialized;
int ret;
+ int retry_count;
int i = 0;
int failed = 0;
@@ -763,6 +771,14 @@
/* close port */
ret = msm_smux_close(SMUX_TEST_LCID);
UT_ASSERT_INT(ret, ==, 0);
+
+ /* wait for remote side to finish booting */
+ retry_count = 0;
+ do {
+ msleep(500);
+ ++retry_count;
+ UT_ASSERT_INT(retry_count, <, 20);
+ } while (!smux_remote_is_active() && !failed);
break;
}
@@ -795,6 +811,7 @@
static int cb_initialized;
int i = 0;
int failed = 0;
+ int retry_count;
int ret;
i += scnprintf(buf + i, max - i, "Running %s\n", __func__);
@@ -841,12 +858,16 @@
subsystem_restart("external_modem");
/* verify SSR completed */
- UT_ASSERT_INT(ret, ==, 0);
- UT_ASSERT_INT(
- (int)wait_for_completion_timeout(
- &cb_data.cb_completion, 5*HZ),
- >, 0);
- UT_ASSERT_INT(cb_data.cb_count, ==, 1);
+ retry_count = 0;
+ while (cb_data.event_disconnected_ssr == 0) {
+ (void)wait_for_completion_timeout(
+ &cb_data.cb_completion, HZ);
+ INIT_COMPLETION(cb_data.cb_completion);
+ ++retry_count;
+ UT_ASSERT_INT(retry_count, <, 10);
+ }
+ if (failed)
+ break;
UT_ASSERT_INT(cb_data.event_disconnected, ==, 1);
UT_ASSERT_INT(cb_data.event_disconnected_ssr, ==, 1);
mock_cb_data_reset(&cb_data);
@@ -854,6 +875,14 @@
/* close port */
ret = msm_smux_close(SMUX_TEST_LCID);
UT_ASSERT_INT(ret, ==, 0);
+
+ /* wait for remote side to finish booting */
+ retry_count = 0;
+ do {
+ msleep(500);
+ ++retry_count;
+ UT_ASSERT_INT(retry_count, <, 20);
+ } while (!smux_remote_is_active() && !failed);
break;
}
@@ -1924,6 +1953,136 @@
return i;
}
+/**
+ * Verify remote flow control (remote TX stop).
+ *
+ * @buf Buffer for status message
+ * @max Size of buffer
+ *
+ * @returns Number of bytes written to @buf
+ */
+static int smux_ut_remote_tx_stop(char *buf, int max)
+{
+ static struct smux_mock_callback cb_data;
+ static int cb_initialized;
+ int i = 0;
+ int failed = 0;
+ int ret;
+
+ i += scnprintf(buf + i, max - i, "Running %s\n", __func__);
+ pr_err("%s", buf);
+
+ if (!cb_initialized)
+ mock_cb_data_init(&cb_data);
+
+ mock_cb_data_reset(&cb_data);
+ while (!failed) {
+ /* open port for remote loopback */
+ ret = msm_smux_set_ch_option(SMUX_TEST_LCID,
+ SMUX_CH_OPTION_REMOTE_LOOPBACK, 0);
+ UT_ASSERT_INT(ret, ==, 0);
+
+ ret = msm_smux_open(SMUX_TEST_LCID, &cb_data, smux_mock_cb,
+ get_rx_buffer);
+ UT_ASSERT_INT(ret, ==, 0);
+ UT_ASSERT_INT(
+ (int)wait_for_completion_timeout(
+ &cb_data.cb_completion, HZ), >, 0);
+ UT_ASSERT_INT(cb_data.cb_count, ==, 1);
+ UT_ASSERT_INT(cb_data.event_connected, ==, 1);
+ mock_cb_data_reset(&cb_data);
+
+ /* send 1 packet and verify response */
+ ret = msm_smux_write(SMUX_TEST_LCID, (void *)1,
+ test_array, sizeof(test_array));
+ UT_ASSERT_INT(ret, ==, 0);
+ UT_ASSERT_INT(
+ (int)wait_for_completion_timeout(
+ &cb_data.cb_completion, HZ),
+ >, 0);
+ UT_ASSERT_INT(cb_data.event_write_done, ==, 1);
+
+ INIT_COMPLETION(cb_data.cb_completion);
+ if (!cb_data.event_read_done) {
+ UT_ASSERT_INT(
+ (int)wait_for_completion_timeout(
+ &cb_data.cb_completion, HZ),
+ >, 0);
+ }
+ UT_ASSERT_INT(cb_data.event_read_done, ==, 1);
+ mock_cb_data_reset(&cb_data);
+
+ /* enable flow control */
+ UT_ASSERT_INT(smux_lch[SMUX_TEST_LCID].tx_flow_control, ==, 0);
+ ret = msm_smux_set_ch_option(SMUX_TEST_LCID,
+ SMUX_CH_OPTION_REMOTE_TX_STOP, 0);
+ UT_ASSERT_INT(ret, ==, 0);
+
+ /* wait for remote echo and clear our tx_flow control */
+ msleep(500);
+ UT_ASSERT_INT(smux_lch[SMUX_TEST_LCID].tx_flow_control, ==, 1);
+ smux_lch[SMUX_TEST_LCID].tx_flow_control = 0;
+
+ /* Send 1 packet and verify no response */
+ ret = msm_smux_write(SMUX_TEST_LCID, (void *)2,
+ test_array, sizeof(test_array));
+ UT_ASSERT_INT(ret, ==, 0);
+ UT_ASSERT_INT(
+ (int)wait_for_completion_timeout(
+ &cb_data.cb_completion, HZ),
+ >, 0);
+ INIT_COMPLETION(cb_data.cb_completion);
+ UT_ASSERT_INT(cb_data.event_write_done, ==, 1);
+ UT_ASSERT_INT(cb_data.event_read_done, ==, 0);
+ UT_ASSERT_INT(cb_data.cb_count, ==, 1);
+
+ UT_ASSERT_INT(
+ (int)wait_for_completion_timeout(
+ &cb_data.cb_completion, 1*HZ),
+ ==, 0);
+ UT_ASSERT_INT(cb_data.event_read_done, ==, 0);
+ mock_cb_data_reset(&cb_data);
+
+ /* disable flow control and verify response is received */
+ UT_ASSERT_INT(cb_data.event_read_done, ==, 0);
+ ret = msm_smux_set_ch_option(SMUX_TEST_LCID,
+ 0, SMUX_CH_OPTION_REMOTE_TX_STOP);
+ UT_ASSERT_INT(ret, ==, 0);
+
+ UT_ASSERT_INT(
+ (int)wait_for_completion_timeout(
+ &cb_data.cb_completion, HZ),
+ >, 0);
+ UT_ASSERT_INT(cb_data.event_read_done, ==, 1);
+ mock_cb_data_reset(&cb_data);
+
+ /* close port */
+ ret = msm_smux_close(SMUX_TEST_LCID);
+ UT_ASSERT_INT(ret, ==, 0);
+ UT_ASSERT_INT(
+ (int)wait_for_completion_timeout(
+ &cb_data.cb_completion, HZ),
+ >, 0);
+ UT_ASSERT_INT(cb_data.cb_count, ==, 1);
+ UT_ASSERT_INT(cb_data.event_disconnected, ==, 1);
+ UT_ASSERT_INT(cb_data.event_disconnected_ssr, ==, 0);
+ break;
+ }
+
+ if (!failed) {
+ i += scnprintf(buf + i, max - i, "\tOK\n");
+ } else {
+ pr_err("%s: Failed\n", __func__);
+ i += scnprintf(buf + i, max - i, "\tFailed\n");
+ i += mock_cb_data_print(&cb_data, buf + i, max - i);
+ msm_smux_set_ch_option(SMUX_TEST_LCID,
+ 0, SMUX_CH_OPTION_REMOTE_TX_STOP);
+ msm_smux_close(SMUX_TEST_LCID);
+ }
+ mock_cb_data_reset(&cb_data);
+ return i;
+}
+
static char debug_buffer[DEBUG_BUFMAX];
static ssize_t debug_read(struct file *file, char __user *buf,
@@ -1961,7 +2120,7 @@
{
struct dentry *dent;
- dent = debugfs_create_dir("n_smux", 0);
+ dent = debugfs_create_dir("n_smux_test", 0);
if (IS_ERR(dent))
return PTR_ERR(dent);
@@ -1995,6 +2154,8 @@
smux_ut_remote_ssr_open);
debug_create("ut_remote_ssr_rx_buff_retry", 0444, dent,
smux_ut_remote_ssr_rx_buff_retry);
+ debug_create("ut_remote_tx_stop", 0444, dent,
+ smux_ut_remote_tx_stop);
return 0;
}
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 54ea85d..f517340 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -559,13 +559,6 @@
goto err1;
}
- ret = dwc3_host_init(dwc);
- if (ret) {
- dev_err(dev, "failed to initialize host\n");
- dwc3_otg_exit(dwc);
- goto err1;
- }
-
ret = dwc3_gadget_init(dwc);
if (ret) {
dev_err(dev, "failed to initialize gadget\n");
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index 522e3a4..6917b2d 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -124,7 +124,11 @@
u8 ep_num_mapping[DBM_MAX_EPS];
const struct usb_ep_ops *original_ep_ops[DWC3_ENDPOINTS_NUM];
struct list_head req_complete_list;
+ struct clk *ref_clk;
struct clk *core_clk;
+ struct clk *iface_clk;
+ struct clk *sleep_clk;
+ struct clk *hsphy_sleep_clk;
struct regulator *hsusb_3p3;
struct regulator *hsusb_1p8;
struct regulator *hsusb_vddcx;
@@ -1227,7 +1231,9 @@
return 0;
}
+ clk_disable_unprepare(mdwc->iface_clk);
clk_disable_unprepare(mdwc->core_clk);
+ clk_disable_unprepare(mdwc->ref_clk);
dwc3_hsusb_ldo_enable(0);
dwc3_ssusb_ldo_enable(0);
wake_unlock(&mdwc->wlock);
@@ -1248,7 +1254,9 @@
}
wake_lock(&mdwc->wlock);
+ clk_prepare_enable(mdwc->ref_clk);
clk_prepare_enable(mdwc->core_clk);
+ clk_prepare_enable(mdwc->iface_clk);
dwc3_hsusb_ldo_enable(1);
dwc3_ssusb_ldo_enable(1);
@@ -1378,6 +1386,7 @@
struct platform_device *dwc3;
struct dwc3_msm *msm;
struct resource *res;
+ void __iomem *tcsr;
int ret = 0;
msm = devm_kzalloc(&pdev->dev, sizeof(*msm), GFP_KERNEL);
@@ -1406,6 +1415,38 @@
clk_set_rate(msm->core_clk, 125000000);
clk_prepare_enable(msm->core_clk);
+ msm->iface_clk = devm_clk_get(&pdev->dev, "iface_clk");
+ if (IS_ERR(msm->iface_clk)) {
+ dev_err(&pdev->dev, "failed to get iface_clk\n");
+ ret = PTR_ERR(msm->iface_clk);
+ goto disable_core_clk;
+ }
+ clk_prepare_enable(msm->iface_clk);
+
+ msm->sleep_clk = devm_clk_get(&pdev->dev, "sleep_clk");
+ if (IS_ERR(msm->sleep_clk)) {
+ dev_err(&pdev->dev, "failed to get sleep_clk\n");
+ ret = PTR_ERR(msm->sleep_clk);
+ goto disable_iface_clk;
+ }
+ clk_prepare_enable(msm->sleep_clk);
+
+ msm->hsphy_sleep_clk = devm_clk_get(&pdev->dev, "sleep_a_clk");
+ if (IS_ERR(msm->hsphy_sleep_clk)) {
+ dev_err(&pdev->dev, "failed to get sleep_a_clk\n");
+ ret = PTR_ERR(msm->hsphy_sleep_clk);
+ goto disable_sleep_clk;
+ }
+ clk_prepare_enable(msm->hsphy_sleep_clk);
+
+ msm->ref_clk = devm_clk_get(&pdev->dev, "ref_clk");
+ if (IS_ERR(msm->ref_clk)) {
+ dev_err(&pdev->dev, "failed to get ref_clk\n");
+ ret = PTR_ERR(msm->ref_clk);
+ goto disable_sleep_a_clk;
+ }
+ clk_prepare_enable(msm->ref_clk);
+
/* SS PHY */
msm->ss_vdd_type = VDDCX_CORNER;
msm->ssusb_vddcx = devm_regulator_get(&pdev->dev, "ssusb_vdd_dig");
@@ -1415,7 +1456,7 @@
if (IS_ERR(msm->ssusb_vddcx)) {
dev_err(&pdev->dev, "unable to get ssusb vddcx\n");
ret = PTR_ERR(msm->ssusb_vddcx);
- goto disable_core_clk;
+ goto disable_ref_clk;
}
msm->ss_vdd_type = VDDCX;
dev_dbg(&pdev->dev, "ss_vdd_type: VDDCX\n");
@@ -1424,7 +1465,7 @@
ret = dwc3_ssusb_config_vddcx(1);
if (ret) {
dev_err(&pdev->dev, "ssusb vddcx configuration failed\n");
- goto disable_core_clk;
+ goto disable_ref_clk;
}
ret = regulator_enable(context->ssusb_vddcx);
@@ -1484,6 +1525,25 @@
goto free_hs_ldo_init;
}
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!res) {
+ dev_dbg(&pdev->dev, "missing TCSR memory resource\n");
+ } else {
+ tcsr = devm_ioremap_nocache(&pdev->dev, res->start,
+ resource_size(res));
+ if (!tcsr) {
+ dev_dbg(&pdev->dev, "tcsr ioremap failed\n");
+ } else {
+ /* Enable USB3 on the primary USB port. */
+ writel_relaxed(0x1, tcsr);
+ /*
+ * Ensure that TCSR write is completed before
+ * USB registers initialization.
+ */
+ mb();
+ }
+ }
+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "missing memory base resource\n");
@@ -1514,7 +1574,6 @@
msm->dwc3 = dwc3;
pm_runtime_set_active(msm->dev);
- pm_runtime_enable(msm->dev);
if (of_property_read_u32(node, "qcom,dwc-usb3-msm-dbm-eps",
&msm->dbm_num_eps)) {
@@ -1600,6 +1659,14 @@
regulator_disable(context->ssusb_vddcx);
unconfig_ss_vddcx:
dwc3_ssusb_config_vddcx(0);
+disable_ref_clk:
+ clk_disable_unprepare(msm->ref_clk);
+disable_sleep_a_clk:
+ clk_disable_unprepare(msm->hsphy_sleep_clk);
+disable_sleep_clk:
+ clk_disable_unprepare(msm->sleep_clk);
+disable_iface_clk:
+ clk_disable_unprepare(msm->iface_clk);
disable_core_clk:
clk_disable_unprepare(msm->core_clk);
@@ -1629,6 +1696,10 @@
regulator_disable(msm->ssusb_vddcx);
dwc3_ssusb_config_vddcx(0);
clk_disable_unprepare(msm->core_clk);
+ clk_disable_unprepare(msm->iface_clk);
+ clk_disable_unprepare(msm->sleep_clk);
+ clk_disable_unprepare(msm->hsphy_sleep_clk);
+ clk_disable_unprepare(msm->ref_clk);
return 0;
}
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index 7b34e60..23f6ea3 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -1334,7 +1334,7 @@
config->fsg.nluns = 2;
config->fsg.luns[1].cdrom = 1;
config->fsg.luns[1].ro = 1;
- config->fsg.luns[1].removable = 1;
+ config->fsg.luns[1].removable = 0;
name[1] = "lun0";
}
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index 4d15c55..831e970 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -2056,6 +2056,16 @@
spin_unlock(udc->lock);
+ if (udc->suspended) {
+ if (udc->udc_driver->notify_event)
+ udc->udc_driver->notify_event(udc,
+ CI13XXX_CONTROLLER_RESUME_EVENT);
+ if (udc->transceiver)
+ usb_phy_set_suspend(udc->transceiver, 0);
+ udc->driver->resume(&udc->gadget);
+ udc->suspended = 0;
+ }
+
/*stop charging upon reset */
if (udc->transceiver)
usb_phy_set_power(udc->transceiver, 0);
diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c
index 1ea3982..0514aa8 100644
--- a/drivers/usb/gadget/f_mass_storage.c
+++ b/drivers/usb/gadget/f_mass_storage.c
@@ -2921,7 +2921,7 @@
rc = fsg_lun_open(curlun, lcfg->filename);
if (rc)
goto error_luns;
- } else if (!curlun->removable) {
+ } else if (!curlun->removable && !curlun->cdrom) {
ERROR(common, "no file given for LUN%d\n", i);
rc = -EINVAL;
goto error_luns;
diff --git a/drivers/usb/gadget/udc-core.c b/drivers/usb/gadget/udc-core.c
index c16ff97..40b79a2 100644
--- a/drivers/usb/gadget/udc-core.c
+++ b/drivers/usb/gadget/udc-core.c
@@ -348,7 +348,6 @@
driver->unbind(udc->gadget);
goto err1;
}
- usb_gadget_connect(udc->gadget);
} else {
ret = usb_gadget_start(udc->gadget, driver, bind);
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index b396593..2126ff0 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -27,6 +27,7 @@
#include <linux/err.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
+#include <linux/wakelock.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
@@ -58,13 +59,14 @@
struct clk *phy_clk;
struct clk *cal_clk;
struct regulator *hsic_vddcx;
+ bool async_int;
atomic_t in_lpm;
+ struct wake_lock wlock;
int peripheral_status_irq;
int wakeup_irq;
int wakeup_gpio;
bool wakeup_irq_enabled;
- bool irq_enabled;
- bool async_int;
+ atomic_t pm_usage_cnt;
uint32_t bus_perf_client;
uint32_t wakeup_int_cnt;
enum usb_vdd_type vdd_type;
@@ -624,15 +626,13 @@
disable_irq(hcd->irq);
- /* make sure we don't race against the root hub being resumed */
- if (HCD_RH_RUNNING(hcd) || HCD_WAKEUP_PENDING(hcd) ||
+ /* make sure we don't race against a remote wakeup */
+ if (test_bit(HCD_FLAG_WAKEUP_PENDING, &hcd->flags) ||
readl_relaxed(USB_PORTSC) & PORT_RESUME) {
- dev_warn(mehci->dev, "%s: Root hub is not suspended\n",
- __func__);
+ dev_dbg(mehci->dev, "wakeup pending, aborting suspend\n");
enable_irq(hcd->irq);
return -EBUSY;
}
- mehci->irq_enabled = false;
/*
* PHY may take some time or even fail to enter into low power
@@ -690,13 +690,14 @@
}
atomic_set(&mehci->in_lpm, 1);
- mehci->irq_enabled = true;
enable_irq(hcd->irq);
mehci->wakeup_irq_enabled = 1;
enable_irq_wake(mehci->wakeup_irq);
enable_irq(mehci->wakeup_irq);
+ wake_unlock(&mehci->wlock);
+
dev_info(mehci->dev, "HSIC-USB in low power mode\n");
return 0;
@@ -720,6 +721,8 @@
mehci->wakeup_irq_enabled = 0;
}
+ wake_lock(&mehci->wlock);
+
if (mehci->bus_perf_client && debug_bus_voting_enabled) {
mehci->bus_vote = true;
queue_work(ehci_wq, &mehci->bus_vote_w);
@@ -775,14 +778,13 @@
if (mehci->async_int) {
mehci->async_int = false;
pm_runtime_put_noidle(mehci->dev);
- }
-
- if (!mehci->irq_enabled) {
enable_irq(hcd->irq);
- mehci->irq_enabled = true;
}
- pm_relax(mehci->dev);
+ if (atomic_read(&mehci->pm_usage_cnt)) {
+ atomic_set(&mehci->pm_usage_cnt, 0);
+ pm_runtime_put_noidle(mehci->dev);
+ }
dev_info(mehci->dev, "HSIC-USB exited from low power mode\n");
@@ -809,11 +811,9 @@
if (atomic_read(&mehci->in_lpm)) {
disable_irq_nosync(hcd->irq);
- mehci->irq_enabled = false;
dev_dbg(mehci->dev, "phy async intr\n");
mehci->async_int = true;
pm_runtime_get(mehci->dev);
- pm_stay_awake(mehci->dev);
return IRQ_HANDLED;
}
@@ -1030,9 +1030,7 @@
dev_dbg(mehci->dev, "%s: hsic remote wakeup interrupt cnt: %u\n",
__func__, mehci->wakeup_int_cnt);
- mehci->async_int = true;
- pm_runtime_get(mehci->dev);
- pm_stay_awake(mehci->dev);
+ wake_lock(&mehci->wlock);
if (mehci->wakeup_irq_enabled) {
mehci->wakeup_irq_enabled = 0;
@@ -1040,6 +1038,11 @@
disable_irq_nosync(irq);
}
+ if (!atomic_read(&mehci->pm_usage_cnt)) {
+ atomic_set(&mehci->pm_usage_cnt, 1);
+ pm_runtime_get(mehci->dev);
+ }
+
return IRQ_HANDLED;
}
@@ -1345,8 +1348,9 @@
goto unconfig_gpio;
}
- mehci->irq_enabled = true;
device_init_wakeup(&pdev->dev, 1);
+ wake_lock_init(&mehci->wlock, WAKE_LOCK_SUSPEND, dev_name(&pdev->dev));
+ wake_lock(&mehci->wlock);
if (mehci->peripheral_status_irq) {
ret = request_threaded_irq(mehci->peripheral_status_irq,
@@ -1460,6 +1464,7 @@
msm_hsic_init_vddcx(mehci, 0);
msm_hsic_init_clocks(mehci, 0);
+ wake_lock_destroy(&mehci->wlock);
iounmap(hcd->regs);
usb_put_hcd(hcd);
diff --git a/drivers/usb/misc/diag_bridge.c b/drivers/usb/misc/diag_bridge.c
index 6d5544a..ba7658b 100644
--- a/drivers/usb/misc/diag_bridge.c
+++ b/drivers/usb/misc/diag_bridge.c
@@ -96,13 +96,9 @@
dev_dbg(&dev->ifc->dev, "%s: status:%d actual:%d\n", __func__,
urb->status, urb->actual_length);
- if (urb->status == -EPROTO) {
- dev_err(&dev->ifc->dev, "%s: proto error\n", __func__);
- /* save error so that subsequent read/write returns ENODEV */
+ /* save error so that subsequent read/write returns ENODEV */
+ if (urb->status == -EPROTO)
dev->err = urb->status;
- kref_put(&dev->kref, diag_bridge_delete);
- return;
- }
if (cbs && cbs->read_complete_cb)
cbs->read_complete_cb(cbs->ctxt,
@@ -190,13 +186,9 @@
usb_autopm_put_interface_async(dev->ifc);
- if (urb->status == -EPROTO) {
- dev_err(&dev->ifc->dev, "%s: proto error\n", __func__);
- /* save error so that subsequent read/write returns ENODEV */
+ /* save error so that subsequent read/write returns ENODEV */
+ if (urb->status == -EPROTO)
dev->err = urb->status;
- kref_put(&dev->kref, diag_bridge_delete);
- return;
- }
if (cbs && cbs->write_complete_cb)
cbs->write_complete_cb(cbs->ctxt,
diff --git a/drivers/usb/misc/ks_bridge.c b/drivers/usb/misc/ks_bridge.c
index 10cbe59..be8b58b 100644
--- a/drivers/usb/misc/ks_bridge.c
+++ b/drivers/usb/misc/ks_bridge.c
@@ -58,6 +58,7 @@
struct list_head to_mdm_list;
struct list_head to_ks_list;
wait_queue_head_t ks_wait_q;
+ struct miscdevice *fs_dev;
/* usb specific */
struct usb_device *udev;
@@ -531,7 +532,6 @@
struct usb_endpoint_descriptor *ep_desc;
int i;
struct ks_bridge *ksb;
- struct miscdevice *fs_dev;
ifc_num = ifc->cur_altsetting->desc.bInterfaceNumber;
@@ -585,8 +585,8 @@
dbg_log_event(ksb, "PID-ATT", id->idProduct, 0);
- fs_dev = (struct miscdevice *)id->driver_info;
- misc_register(fs_dev);
+ ksb->fs_dev = (struct miscdevice *)id->driver_info;
+ misc_register(ksb->fs_dev);
usb_enable_autosuspend(ksb->udev);
@@ -649,6 +649,7 @@
}
spin_unlock_irqrestore(&ksb->lock, flags);
+ misc_deregister(ksb->fs_dev);
usb_put_dev(ksb->udev);
ksb->ifc = NULL;
usb_set_intfdata(ifc, NULL);
@@ -713,7 +714,8 @@
ksb = kzalloc(sizeof(struct ks_bridge), GFP_KERNEL);
if (!ksb) {
pr_err("unable to allocat mem for ks_bridge");
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto dev_free;
}
__ksb[i] = ksb;
diff --git a/drivers/usb/misc/mdm_ctrl_bridge.c b/drivers/usb/misc/mdm_ctrl_bridge.c
index e685233..2f7e2c3 100644
--- a/drivers/usb/misc/mdm_ctrl_bridge.c
+++ b/drivers/usb/misc/mdm_ctrl_bridge.c
@@ -404,7 +404,7 @@
result = usb_autopm_get_interface_async(dev->intf);
if (result < 0) {
- dev_err(&dev->intf->dev, "%s: unable to resume interface: %d\n",
+ dev_dbg(&dev->intf->dev, "%s: unable to resume interface: %d\n",
__func__, result);
/*
diff --git a/drivers/usb/misc/mdm_data_bridge.c b/drivers/usb/misc/mdm_data_bridge.c
index 1c9de07..59ae13b 100644
--- a/drivers/usb/misc/mdm_data_bridge.c
+++ b/drivers/usb/misc/mdm_data_bridge.c
@@ -370,7 +370,7 @@
status = usb_autopm_get_interface(dev->intf);
if (status < 0) {
- dev_err(&dev->intf->dev,
+ dev_dbg(&dev->intf->dev,
"can't acquire interface, status %d\n", status);
return;
}
@@ -389,7 +389,7 @@
status = usb_autopm_get_interface(dev->intf);
if (status < 0) {
- dev_err(&dev->intf->dev,
+ dev_dbg(&dev->intf->dev,
"can't acquire interface, status %d\n", status);
return;
}
@@ -478,7 +478,7 @@
result = usb_autopm_get_interface(dev->intf);
if (result < 0) {
- dev_err(&dev->intf->dev, "%s: resume failure\n", __func__);
+ dev_dbg(&dev->intf->dev, "%s: resume failure\n", __func__);
goto pm_error;
}
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index 0ef8249..65ddd4c 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -760,6 +760,14 @@
test_bit(A_BUS_SUSPEND, &motg->inputs) &&
motg->caps & ALLOW_LPM_ON_DEV_SUSPEND;
dcp = motg->chg_type == USB_DCP_CHARGER;
+
+ /* charging detection in progress due to cable plug-in */
+ if (test_bit(B_SESS_VLD, &motg->inputs) && !device_bus_suspend &&
+ !dcp) {
+ enable_irq(motg->irq);
+ return -EBUSY;
+ }
+
/*
* Chipidea 45-nm PHY suspend sequence:
*
@@ -1449,6 +1457,11 @@
struct usb_phy *phy = &motg->phy;
int ret;
+ if (!motg->pdata->mhl_enable) {
+ dev_dbg(phy->dev, "MHL feature not enabled\n");
+ return -ENODEV;
+ }
+
if (motg->pdata->otg_control != OTG_PMIC_CONTROL ||
!motg->pdata->pmic_id_irq) {
dev_dbg(phy->dev, "MHL can not be supported without PMIC Id\n");
diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c
index c3f741b..bde7340 100644
--- a/drivers/usb/serial/usb_wwan.c
+++ b/drivers/usb/serial/usb_wwan.c
@@ -283,6 +283,7 @@
{
struct usb_wwan_port_private *portdata =
container_of(w, struct usb_wwan_port_private, in_work);
+ struct usb_wwan_intf_private *intfdata;
struct list_head *q = &portdata->in_urb_list;
struct urb *urb;
unsigned char *data;
@@ -304,7 +305,9 @@
if (!tty)
break;
- list_del_init(&urb->urb_list);
+ /* list_empty() will still be false after this; it means
+ * URB is still being processed */
+ list_del(&urb->urb_list);
spin_unlock_irqrestore(&portdata->in_lock, flags);
@@ -326,18 +329,27 @@
spin_unlock_irqrestore(&portdata->in_lock, flags);
return;
}
+
+ /* re-init list pointer to indicate we are done with it */
+ INIT_LIST_HEAD(&urb->urb_list);
+
portdata->n_read = 0;
+ intfdata = port->serial->private;
- usb_anchor_urb(urb, &portdata->submitted);
- err = usb_submit_urb(urb, GFP_ATOMIC);
- if (err) {
- usb_unanchor_urb(urb);
- if (err != -EPERM)
- pr_err("%s: submit read urb failed:%d",
- __func__, err);
+ spin_lock_irqsave(&intfdata->susp_lock, flags);
+ if (!intfdata->suspended && !urb->anchor) {
+ usb_anchor_urb(urb, &portdata->submitted);
+ err = usb_submit_urb(urb, GFP_ATOMIC);
+ if (err) {
+ usb_unanchor_urb(urb);
+ if (err != -EPERM)
+ pr_err("%s: submit read urb failed:%d",
+ __func__, err);
+ }
+
+ usb_mark_last_busy(port->serial->dev);
}
-
- usb_mark_last_busy(port->serial->dev);
+ spin_unlock_irqrestore(&intfdata->susp_lock, flags);
spin_lock_irqsave(&portdata->in_lock, flags);
}
spin_unlock_irqrestore(&portdata->in_lock, flags);
@@ -348,6 +360,7 @@
int err;
int endpoint;
struct usb_wwan_port_private *portdata;
+ struct usb_wwan_intf_private *intfdata;
struct usb_serial_port *port;
int status = urb->status;
unsigned long flags;
@@ -357,6 +370,7 @@
endpoint = usb_pipeendpoint(urb->pipe);
port = urb->context;
portdata = usb_get_serial_port_data(port);
+ intfdata = port->serial->private;
usb_mark_last_busy(port->serial->dev);
@@ -373,6 +387,13 @@
dbg("%s: nonzero status: %d on endpoint %02x.",
__func__, status, endpoint);
+ spin_lock(&intfdata->susp_lock);
+ if (intfdata->suspended || !portdata->opened) {
+ spin_unlock(&intfdata->susp_lock);
+ return;
+ }
+ spin_unlock(&intfdata->susp_lock);
+
if (status != -ESHUTDOWN) {
usb_anchor_urb(urb, &portdata->submitted);
err = usb_submit_urb(urb, GFP_ATOMIC);
@@ -850,11 +871,17 @@
for (j = 0; j < N_IN_URB; j++) {
urb = portdata->in_urbs[j];
+
+ /* don't re-submit if it already was submitted or if
+ * it is being processed by in_work */
+ if (urb->anchor || !list_empty(&urb->urb_list))
+ continue;
+
usb_anchor_urb(urb, &portdata->submitted);
err = usb_submit_urb(urb, GFP_ATOMIC);
if (err < 0) {
- err("%s: Error %d for bulk URB %d",
- __func__, err, i);
+ err("%s: Error %d for bulk URB[%d]:%p %d",
+ __func__, err, j, urb, i);
usb_unanchor_urb(urb);
intfdata->suspended = 1;
spin_unlock_irq(&intfdata->susp_lock);
diff --git a/drivers/video/msm/hdmi_msm.c b/drivers/video/msm/hdmi_msm.c
index ade9691..902e92c 100644
--- a/drivers/video/msm/hdmi_msm.c
+++ b/drivers/video/msm/hdmi_msm.c
@@ -761,60 +761,61 @@
static int hdmi_msm_read_edid(void);
static void hdmi_msm_hpd_off(void);
-static void hdmi_msm_hpd_state_work(struct work_struct *work)
+static void hdmi_msm_send_event(boolean on)
{
- boolean hpd_state = false;
char *envp[2];
- if (hdmi_msm_state->is_mhl_enabled) {
- /*
- * HPD will be controlled from MHL
- */
- envp[0] = "";
- DEV_DBG("%s %u\n", envp[0], hpd_state);
- return;
+ /* QDSP OFF preceding the HPD event notification */
+ envp[0] = "HDCP_STATE=FAIL";
+ envp[1] = NULL;
+ DEV_ERR("hdmi: HDMI HPD: QDSP OFF\n");
+ kobject_uevent_env(external_common_state->uevent_kobj,
+ KOBJ_CHANGE, envp);
+
+ if (on) {
+ /* Build EDID table */
+ hdmi_msm_read_edid();
+ switch_set_state(&external_common_state->sdev, 1);
+ DEV_INFO("Hdmi state switched to %d: %s\n",
+ external_common_state->sdev.state, __func__);
+
+ DEV_INFO("HDMI HPD: CONNECTED: send ONLINE\n");
+ kobject_uevent(external_common_state->uevent_kobj, KOBJ_ONLINE);
+ if (!external_common_state->present_hdcp) {
+ /* Send Audio for HDMI Compliance Cases*/
+ envp[0] = "HDCP_STATE=PASS";
+ envp[1] = NULL;
+ DEV_INFO("HDMI HPD: sense : send HDCP_PASS\n");
+ kobject_uevent_env(external_common_state->uevent_kobj,
+ KOBJ_CHANGE, envp);
+ }
+ } else {
+ switch_set_state(&external_common_state->sdev, 0);
+ DEV_INFO("hdmi: Hdmi state switch to %d: %s\n",
+ external_common_state->sdev.state, __func__);
+ DEV_INFO("hdmi: HDMI HPD: sense DISCONNECTED: send OFFLINE\n");
+ kobject_uevent(external_common_state->uevent_kobj,
+ KOBJ_OFFLINE);
}
+}
+
+static void hdmi_msm_hpd_state_work(struct work_struct *work)
+{
+ boolean hpd_state;
if (!hdmi_msm_state || !hdmi_msm_state->hpd_initialized ||
!MSM_HDMI_BASE) {
- DEV_DBG("%s: ignored, probe failed\n", __func__);
+ DEV_ERR("hdmi: %s: ignored, probe failed\n", __func__);
return;
}
- DEV_DBG("%s:Got interrupt\n", __func__);
- /* HPD_INT_STATUS[0x0250] */
- hpd_state = (HDMI_INP(0x0250) & 0x2) >> 1;
- mutex_lock(&external_common_state_hpd_mutex);
mutex_lock(&hdmi_msm_state_mutex);
- if ((external_common_state->hpd_state != hpd_state) || (hdmi_msm_state->
- hpd_prev_state != external_common_state->hpd_state)) {
- external_common_state->hpd_state = hpd_state;
- hdmi_msm_state->hpd_prev_state =
- external_common_state->hpd_state;
- DEV_DBG("%s: state not stable yet, wait again (%d|%d|%d)\n",
- __func__, hdmi_msm_state->hpd_prev_state,
- external_common_state->hpd_state, hpd_state);
- mutex_unlock(&external_common_state_hpd_mutex);
- hdmi_msm_state->hpd_stable = 0;
- mutex_unlock(&hdmi_msm_state_mutex);
- mod_timer(&hdmi_msm_state->hpd_state_timer, jiffies + HZ/2);
- return;
- }
- mutex_unlock(&external_common_state_hpd_mutex);
-
- if (hdmi_msm_state->hpd_stable++) {
- mutex_unlock(&hdmi_msm_state_mutex);
- DEV_DBG("%s: no more timer, depending for IRQ now\n",
- __func__);
- return;
- }
-
- hdmi_msm_state->hpd_stable = 1;
- DEV_INFO("HDMI HPD: event detected\n");
+ DEV_DBG("%s: Handling HPD event in the workqueue\n", __func__);
if (!hdmi_msm_state->hpd_cable_chg_detected) {
+ /* The work item got called from outside the ISR */
mutex_unlock(&hdmi_msm_state_mutex);
- if (hpd_state) {
+ if (external_common_state->hpd_state) {
if (!external_common_state->
disp_mode_list.num_of_elements)
hdmi_msm_read_edid();
@@ -822,69 +823,44 @@
} else {
hdmi_msm_state->hpd_cable_chg_detected = FALSE;
mutex_unlock(&hdmi_msm_state_mutex);
- /* QDSP OFF preceding the HPD event notification */
- envp[0] = "HDCP_STATE=FAIL";
- envp[1] = NULL;
- DEV_INFO("HDMI HPD: QDSP OFF\n");
- kobject_uevent_env(external_common_state->uevent_kobj,
- KOBJ_CHANGE, envp);
- if (hpd_state) {
- /* Build EDID table */
- hdmi_msm_read_edid();
-#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT
- hdmi_msm_state->reauth = FALSE ;
-#endif
- switch_set_state(&external_common_state->sdev, 1);
- DEV_INFO("Hdmi state switched to %d: %s\n",
- external_common_state->sdev.state, __func__);
-
- DEV_INFO("HDMI HPD: CONNECTED: send ONLINE\n");
- kobject_uevent(external_common_state->uevent_kobj,
- KOBJ_ONLINE);
- switch_set_state(&external_common_state->sdev, 1);
- DEV_INFO("Hdmi state switch to %d: %s\n",
- external_common_state->sdev.state, __func__);
-#ifndef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT
- /* Send Audio for HDMI Compliance Cases*/
- envp[0] = "HDCP_STATE=PASS";
- envp[1] = NULL;
- DEV_INFO("HDMI HPD: sense : send HDCP_PASS\n");
- kobject_uevent_env(external_common_state->uevent_kobj,
- KOBJ_CHANGE, envp);
-#endif
- } else {
- switch_set_state(&external_common_state->sdev, 0);
- DEV_INFO("Hdmi state switched to %d: %s\n",
- external_common_state->sdev.state, __func__);
-
- DEV_INFO("HDMI HPD: DISCONNECTED: send OFFLINE\n");
- kobject_uevent(external_common_state->uevent_kobj,
- KOBJ_OFFLINE);
+ mutex_lock(&external_common_state_hpd_mutex);
+ /*
+ * Handle the connect event only if the cable is
+ * still connected. This check is needed for the case
+ * where we get a connect event followed by a disconnect
+ * event in quick succession. In this case, there is no need
+ * to process the connect event.
+ */
+ if ((external_common_state->hpd_state) &&
+ !((HDMI_INP(0x0250) & 0x2) >> 1)) {
+ external_common_state->hpd_state = 0;
+ hdmi_msm_state->hpd_state_in_isr = 0;
+ mutex_unlock(&external_common_state_hpd_mutex);
+ DEV_DBG("%s: Ignoring HPD connect event\n", __func__);
+ return;
}
+ mutex_unlock(&external_common_state_hpd_mutex);
+ hdmi_msm_send_event(external_common_state->hpd_state);
}
- /* HPD_INT_CTRL[0x0254]
- * 31:10 Reserved
- * 9 RCV_PLUGIN_DET_MASK receiver plug in interrupt mask.
- * When programmed to 1,
- * RCV_PLUGIN_DET_INT will toggle
- * the interrupt line
- * 8:6 Reserved
- * 5 RX_INT_EN Panel RX interrupt enable
- * 0: Disable
- * 1: Enable
- * 4 RX_INT_ACK WRITE ONLY. Panel RX interrupt
- * ack
- * 3 Reserved
- * 2 INT_EN Panel interrupt control
- * 0: Disable
- * 1: Enable
- * 1 INT_POLARITY Panel interrupt polarity
- * 0: generate interrupt on disconnect
- * 1: generate interrupt on connect
- * 0 INT_ACK WRITE ONLY. Panel interrupt ack */
- /* Set IRQ for HPD */
- HDMI_OUTP(0x0254, 4 | (hpd_state ? 0 : 2));
+ /*
+ * Wait for a short time before checking for
+ * any changes in the connection status
+ */
+ udelay(100);
+
+ mutex_lock(&external_common_state_hpd_mutex);
+ /* HPD_INT_STATUS[0x0250] */
+ hpd_state = (HDMI_INP(0x0250) & 0x2) >> 1;
+
+ if (external_common_state->hpd_state != hpd_state) {
+ external_common_state->hpd_state = hpd_state;
+ hdmi_msm_state->hpd_state_in_isr = hpd_state;
+ mutex_unlock(&external_common_state_hpd_mutex);
+ hdmi_msm_send_event(hpd_state);
+ } else {
+ mutex_unlock(&external_common_state_hpd_mutex);
+ }
}
#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_CEC_SUPPORT
@@ -978,41 +954,54 @@
hpd_int_ctrl = HDMI_INP_ND(0x0254);
if ((hpd_int_ctrl & (1 << 2)) && (hpd_int_status & (1 << 0))) {
boolean cable_detected = (hpd_int_status & 2) >> 1;
-
- /* HDMI_HPD_INT_CTRL[0x0254] */
- /* Clear all interrupts, timer will turn IRQ back on
- * Leaving the bit[2] on, else core goes off
- * on getting HPD during power off
- */
- HDMI_OUTP(0x0254, (1 << 2) | (1 << 0));
-
DEV_DBG("%s: HPD IRQ, Ctrl=%04x, State=%04x\n", __func__,
- hpd_int_ctrl, hpd_int_status);
- mutex_lock(&hdmi_msm_state_mutex);
- hdmi_msm_state->hpd_cable_chg_detected = TRUE;
+ hpd_int_ctrl, hpd_int_status);
- /* ensure 2 readouts */
- hdmi_msm_state->hpd_prev_state = cable_detected ? 0 : 1;
- external_common_state->hpd_state = cable_detected ? 1 : 0;
- hdmi_msm_state->hpd_stable = 0;
- mod_timer(&hdmi_msm_state->hpd_state_timer, jiffies + HZ/2);
- mutex_unlock(&hdmi_msm_state_mutex);
- /*
- * HDCP Compliance 1A-01:
- * The Quantum Data Box 882 triggers two consecutive
- * HPD events very close to each other as a part of this
- * test which can trigger two parallel HDCP auth threads
- * if HDCP authentication is going on and we get ISR
- * then stop the authentication , rather than
- * reauthenticating it again
- */
- if (!(hdmi_msm_state->full_auth_done)) {
- DEV_DBG("%s getting hpd while authenticating\n",\
- __func__);
- mutex_lock(&hdcp_auth_state_mutex);
- hdmi_msm_state->hpd_during_auth = TRUE;
- mutex_unlock(&hdcp_auth_state_mutex);
+ /* Ack the interrupt */
+ HDMI_OUTP(0x0254, (hpd_int_ctrl | (1 << 0)));
+
+ mutex_lock(&external_common_state_hpd_mutex);
+ if (hdmi_msm_state->hpd_state_in_isr == cable_detected) {
+ DEV_INFO("%s: HPD has the same state. Ignoring\n",
+ __func__);
+ mutex_unlock(&external_common_state_hpd_mutex);
+ } else {
+ if (!mod_timer(&hdmi_msm_state->hpd_state_timer,
+ jiffies + HZ/2)) {
+ hdmi_msm_state->hpd_state_in_isr =
+ cable_detected;
+ hdmi_msm_state->hpd_cable_chg_detected = TRUE;
+ DEV_DBG("%s: Scheduled work to handle HPD %s\n",
+ __func__,
+ cable_detected ? "connect"
+ : "disconnect");
+ }
+
+ mutex_unlock(&external_common_state_hpd_mutex);
+ /*
+ * HDCP Compliance 1A-01:
+ * The Quantum Data Box 882 triggers two consecutive
+ * HPD events very close to each other as a part of this
+ * test which can trigger two parallel HDCP auth threads
+ * if HDCP authentication is going on and we get ISR
+ * then stop the authentication , rather than
+ * reauthenticating it again
+ */
+ if (hdmi_msm_state->hdcp_activating &&
+ !(hdmi_msm_state->full_auth_done)) {
+ DEV_DBG("%s getting hpd while authenticating\n",
+ __func__);
+ mutex_lock(&hdcp_auth_state_mutex);
+ hdmi_msm_state->hpd_during_auth = TRUE;
+ mutex_unlock(&hdcp_auth_state_mutex);
+ }
}
+
+ /* Set up HPD_CTRL to sense HPD event */
+ HDMI_OUTP(0x0254, 4 | (cable_detected ? 0 : 2));
+ DEV_DBG("%s: Setting HPD_CTRL=%d\n", __func__,
+ HDMI_INP(0x0254));
+
return IRQ_HANDLED;
}
@@ -1092,10 +1081,11 @@
if ((hdcp_int_val & (1 << 6)) && (hdcp_int_val & (1 << 4))) {
/* AUTH_FAIL_INT */
/* Clear and Disable */
+ uint32 link_status = HDMI_INP_ND(0x011C);
HDMI_OUTP(0x0118, (hdcp_int_val | (1 << 5))
& ~((1 << 6) | (1 << 4)));
DEV_INFO("HDCP: AUTH_FAIL_INT received, LINK0_STATUS=0x%08x\n",
- HDMI_INP_ND(0x011C));
+ link_status);
if (hdmi_msm_state->full_auth_done) {
switch_set_state(&external_common_state->sdev, 0);
DEV_INFO("Hdmi state switched to %d: %s\n",
@@ -1112,20 +1102,18 @@
mutex_unlock(&hdcp_auth_state_mutex);
/* Calling reauth only when authentication
* is sucessful or else we always go into
- * the reauth loop
+ * the reauth loop. Also, No need to reauthenticate
+ * if authentication failed because of cable disconnect
*/
- queue_work(hdmi_work_queue,
- &hdmi_msm_state->hdcp_reauth_work);
+ if (((link_status & 0xF0) >> 4) != 0x7) {
+ DEV_DBG("Reauthenticate From %s HDCP FAIL INT ",
+ __func__);
+ queue_work(hdmi_work_queue,
+ &hdmi_msm_state->hdcp_reauth_work);
+ } else {
+ DEV_INFO("HDCP: HDMI cable disconnected\n");
+ }
}
- mutex_lock(&hdcp_auth_state_mutex);
- /* This flag prevents other threads from re-authenticating
- * after we've just authenticated (i.e., finished part3)
- */
- hdmi_msm_state->full_auth_done = FALSE;
-
- mutex_unlock(&hdcp_auth_state_mutex);
- DEV_DBG("calling reauthenticate from %s HDCP FAIL INT ",
- __func__);
/* Clear AUTH_FAIL_INFO as well */
HDMI_OUTP(0x0118, (hdcp_int_val | (1 << 7)));
@@ -2242,7 +2230,9 @@
/* Disable HDCP interrupts */
HDMI_OUTP(0x0118, 0x0);
+ mutex_lock(&hdcp_auth_state_mutex);
external_common_state->hdcp_active = FALSE;
+ mutex_unlock(&hdcp_auth_state_mutex);
/* 0x0130 HDCP_RESET
[0] LINK0_DEAUTHENTICATE */
HDMI_OUTP(0x0130, 0x1);
@@ -3029,7 +3019,6 @@
unfill_black_screen();
- external_common_state->hdcp_active = TRUE;
mutex_lock(&hdmi_msm_state_mutex);
hdmi_msm_state->hdcp_activating = FALSE;
mutex_unlock(&hdmi_msm_state_mutex);
@@ -3040,6 +3029,7 @@
* after we've just authenticated (i.e., finished part3)
*/
hdmi_msm_state->full_auth_done = TRUE;
+ external_common_state->hdcp_active = TRUE;
mutex_unlock(&hdcp_auth_state_mutex);
if (!hdmi_msm_is_dvi_mode()) {
@@ -3986,19 +3976,6 @@
HDMI_OUTP(0x00A4, packet_header);
check_sum += IFRAME_CHECKSUM_32(packet_header);
- /* Vendor Name (7bit ASCII code) */
- /* 0x00A8 GENERIC1_0
- * BYTE0 7:0 CheckSum
- * BYTE1 15:8 VENDOR_NAME[0]
- * BYTE2 23:16 VENDOR_NAME[1]
- * BYTE3 31:24 VENDOR_NAME[2] */
- packet_payload = ((vendor_name[0] & 0x7f) << 8)
- | ((vendor_name[1] & 0x7f) << 16)
- | ((vendor_name[2] & 0x7f) << 24);
- check_sum += IFRAME_CHECKSUM_32(packet_payload);
- packet_payload |= ((0x100 - (0xff & check_sum)) & 0xff);
- HDMI_OUTP(0x00A8, packet_payload);
-
/* 0x00AC GENERIC1_1
* BYTE4 7:0 VENDOR_NAME[3]
* BYTE5 15:8 VENDOR_NAME[4]
@@ -4080,6 +4057,19 @@
HDMI_OUTP(0x00C0, packet_payload);
check_sum += IFRAME_CHECKSUM_32(packet_payload);
+ /* Vendor Name (7bit ASCII code) */
+ /* 0x00A8 GENERIC1_0
+ * BYTE0 7:0 CheckSum
+ * BYTE1 15:8 VENDOR_NAME[0]
+ * BYTE2 23:16 VENDOR_NAME[1]
+ * BYTE3 31:24 VENDOR_NAME[2] */
+ packet_payload = ((vendor_name[0] & 0x7f) << 8)
+ | ((vendor_name[1] & 0x7f) << 16)
+ | ((vendor_name[2] & 0x7f) << 24);
+ check_sum += IFRAME_CHECKSUM_32(packet_payload);
+ packet_payload |= ((0x100 - (0xff & check_sum)) & 0xff);
+ HDMI_OUTP(0x00A8, packet_payload);
+
/* GENERIC1_LINE | GENERIC1_CONT | GENERIC1_SEND
* Setup HDMI TX generic packet control
* Enable this packet to transmit every frame
@@ -4168,9 +4158,6 @@
#endif
hdmi_msm_spd_infoframe_packetsetup();
- /* Set IRQ for HPD */
- HDMI_OUTP(0x0254, 4 | (external_common_state->hpd_state ? 0 : 2));
-
#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT
if (hdmi_msm_state->reauth) {
hdmi_msm_hdcp_enable();
@@ -4193,7 +4180,32 @@
static void hdmi_msm_hpd_state_timer(unsigned long data)
{
- queue_work(hdmi_work_queue, &hdmi_msm_state->hpd_state_work);
+ if (!work_busy(&hdmi_msm_state->hpd_state_work)) {
+ /*
+ * There is no event currently queued.
+ * Only queue the work if this event has not already
+ * been processed.
+ */
+ if (external_common_state->hpd_state !=
+ hdmi_msm_state->hpd_state_in_isr) {
+ /*
+ * There is no need to use any synchronization
+ * construct for safeguarding these state vairables
+ * here since the only other place these are modified
+ * is in the HPD work thread, which is known to be not
+ * pending/running.
+ */
+ external_common_state->hpd_state =
+ hdmi_msm_state->hpd_state_in_isr;
+ DEV_DBG("%s: Queuing work to handle HPD %s event\n",
+ __func__,
+ external_common_state->hpd_state ?
+ "connect" : "disconnect");
+ queue_work(hdmi_work_queue,
+ &hdmi_msm_state->hpd_state_work);
+ return;
+ }
+ }
}
#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT
@@ -4223,6 +4235,10 @@
del_timer(&hdmi_msm_state->hpd_state_timer);
disable_irq(hdmi_msm_state->irq);
+ /* Disable HPD interrupt */
+ HDMI_OUTP(0x0254, 0);
+ DEV_DBG("%s: Disabling HPD_CTRLd\n", __func__);
+
hdmi_msm_set_mode(FALSE);
hdmi_msm_state->pd->enable_5v(0);
hdmi_msm_clk(0);
@@ -4241,7 +4257,7 @@
#endif
}
-static int hdmi_msm_hpd_on(bool trigger_handler)
+static int hdmi_msm_hpd_on(void)
{
static int phy_reset_done;
uint32 hpd_ctrl;
@@ -4282,35 +4298,33 @@
/* HDMI_USEC_REFTIMER[0x0208] */
HDMI_OUTP(0x0208, 0x0001001B);
+ /* Set up HPD state variables */
+ mutex_lock(&external_common_state_hpd_mutex);
+ external_common_state->hpd_state = 0;
+ hdmi_msm_state->hpd_state_in_isr = 0;
+ mutex_unlock(&external_common_state_hpd_mutex);
+ mutex_lock(&hdmi_msm_state_mutex);
+ hdmi_msm_state->hpd_cable_chg_detected = TRUE;
+ mutex_unlock(&hdmi_msm_state_mutex);
+
+ /* Set up HPD_CTRL to sense HPD event */
+ HDMI_OUTP(0x0254, 0x6);
+ DEV_DBG("%s: Setting HPD_CTRL=%d\n", __func__,
+ HDMI_INP(0x0254));
+
+ hdmi_msm_state->hpd_initialized = TRUE;
+
+ enable_irq(hdmi_msm_state->irq);
+
/* set timeout to 4.1ms (max) for hardware debounce */
hpd_ctrl = HDMI_INP(0x0258) | 0x1FFF;
/* Toggle HPD circuit to trigger HPD sense */
HDMI_OUTP(0x0258, ~(1 << 28) & hpd_ctrl);
HDMI_OUTP(0x0258, (1 << 28) | hpd_ctrl);
-
- hdmi_msm_state->hpd_initialized = TRUE;
-
- /* Check HPD State */
- enable_irq(hdmi_msm_state->irq);
}
- if (trigger_handler) {
- /* Set HPD state machine: ensure at least 2 readouts */
- mutex_lock(&external_common_state_hpd_mutex);
- mutex_lock(&hdmi_msm_state_mutex);
- hdmi_msm_state->hpd_stable = 0;
- hdmi_msm_state->hpd_prev_state = TRUE;
- external_common_state->hpd_state = FALSE;
- hdmi_msm_state->hpd_cable_chg_detected = TRUE;
- mutex_unlock(&hdmi_msm_state_mutex);
- mutex_unlock(&external_common_state_hpd_mutex);
- mod_timer(&hdmi_msm_state->hpd_state_timer,
- jiffies + HZ/2);
- }
-
- DEV_DBG("%s: (IRQ, 5V on) <trigger:%s>\n", __func__,
- trigger_handler ? "true" : "false");
+ DEV_DBG("%s: (IRQ, 5V on)\n", __func__);
return 0;
error3:
@@ -4333,7 +4347,7 @@
if (hdmi_prim_display ||
external_common_state->hpd_feature_on) {
DEV_DBG("%s: Turning HPD ciruitry on\n", __func__);
- rc = hdmi_msm_hpd_on(true);
+ rc = hdmi_msm_hpd_on();
}
} else {
DEV_DBG("%s: Turning HPD ciruitry off\n", __func__);
@@ -4604,7 +4618,7 @@
DEV_ERR("Init FAILED: failed to add fb device\n");
if (hdmi_prim_display) {
- rc = hdmi_msm_hpd_on(true);
+ rc = hdmi_msm_hpd_on();
if (rc)
goto error;
}
@@ -4712,7 +4726,7 @@
DEV_INFO("%s: %d\n", __func__, on);
if (on) {
- rc = hdmi_msm_hpd_on(true);
+ rc = hdmi_msm_hpd_on();
} else {
hdmi_msm_hpd_off();
/* Set HDMI switch node to 0 on HPD feature disable */
diff --git a/drivers/video/msm/hdmi_msm.h b/drivers/video/msm/hdmi_msm.h
index 243a27b..5d27412 100644
--- a/drivers/video/msm/hdmi_msm.h
+++ b/drivers/video/msm/hdmi_msm.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-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
@@ -53,11 +53,10 @@
struct hdmi_msm_state_type {
boolean panel_power_on;
boolean hpd_initialized;
+ boolean hpd_state_in_isr;
#ifdef CONFIG_SUSPEND
boolean pm_suspended;
#endif
- int hpd_stable;
- boolean hpd_prev_state;
boolean hpd_cable_chg_detected;
boolean full_auth_done;
boolean hpd_during_auth;
diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c
index 6d14ec1..70685e7 100644
--- a/drivers/video/msm/mdp.c
+++ b/drivers/video/msm/mdp.c
@@ -548,7 +548,7 @@
}
/*mask off non LUT select bits*/
- out = inpdw(MDP_BASE + 0x90070) & ~((0x1 << 10) | 0x7);
+ out = inpdw(MDP_BASE + 0x90070);
MDP_OUTP(MDP_BASE + 0x90070, (mdp_lut_i << 10) | 0x7 | out);
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
mdp_lut_i = (mdp_lut_i + 1)%2;
@@ -1285,34 +1285,6 @@
kobject_uevent_env(&(vsync_cntrl.dev->kobj), KOBJ_CHANGE, envp);
}
-void mdp3_vsync_irq_enable(int intr, int term)
-{
- unsigned long flag;
-
- spin_lock_irqsave(&mdp_spin_lock, flag);
- outp32(MDP_INTR_CLEAR, intr);
- mdp_intr_mask |= intr;
- outp32(MDP_INTR_ENABLE, mdp_intr_mask);
- mdp_enable_irq(term);
- spin_unlock_irqrestore(&mdp_spin_lock, flag);
-}
-
-void mdp3_vsync_irq_disable(int intr, int term)
-{
- unsigned long flag;
-
- spin_lock_irqsave(&mdp_spin_lock, flag);
- /* required to synchronize between frame update and vsync
- * since both use the same LCDC_FRAME_START interrupt
- */
- if (intr == LCDC_FRAME_START && dma2_data.waiting == FALSE) {
- mdp_intr_mask &= ~intr;
- outp32(MDP_INTR_ENABLE, mdp_intr_mask);
- }
- mdp_disable_irq(term);
- spin_unlock_irqrestore(&mdp_spin_lock, flag);
-}
-
#ifdef CONFIG_FB_MSM_MDP303
/* vsync_isr_handler: Called from isr context*/
static void vsync_isr_handler(void)
@@ -1770,6 +1742,7 @@
struct mdp_hist_mgmt *mgmt = NULL;
char *base_addr;
int i, ret;
+ int vsync_isr;
/* Ensure all the register write are complete */
mb();
@@ -1789,8 +1762,23 @@
goto out;
/*Primary Vsync interrupt*/
- if (mdp_interrupt & MDP_PRIM_RDPTR)
- vsync_isr_handler();
+ if (mdp_interrupt & MDP_PRIM_RDPTR) {
+ spin_lock_irqsave(&mdp_spin_lock, flag);
+ vsync_isr = vsync_cntrl.vsync_irq_enabled;
+ if (!vsync_isr) {
+ mdp_intr_mask &= ~MDP_PRIM_RDPTR;
+ outp32(MDP_INTR_ENABLE, mdp_intr_mask);
+ }
+ spin_unlock_irqrestore(&mdp_spin_lock, flag);
+
+ if (vsync_isr) {
+ vsync_isr_handler();
+ } else {
+ mdp_pipe_ctrl(MDP_CMD_BLOCK,
+ MDP_BLOCK_POWER_OFF, TRUE);
+ complete(&vsync_cntrl.vsync_wait);
+ }
+ }
/* DMA3 TV-Out Start */
if (mdp_interrupt & TV_OUT_DMA3_START) {
@@ -1838,21 +1826,26 @@
if (mdp_interrupt & LCDC_FRAME_START) {
dma = &dma2_data;
spin_lock_irqsave(&mdp_spin_lock, flag);
+ vsync_isr = vsync_cntrl.vsync_irq_enabled;
/* let's disable LCDC interrupt */
if (dma->waiting) {
dma->waiting = FALSE;
complete(&dma->comp);
}
- if (vsync_cntrl.vsync_irq_enabled)
- vsync_isr_handler();
-
- if (!vsync_cntrl.vsync_irq_enabled && !(dma->waiting)) {
+ if (!vsync_isr) {
mdp_intr_mask &= ~LCDC_FRAME_START;
outp32(MDP_INTR_ENABLE, mdp_intr_mask);
}
-
spin_unlock_irqrestore(&mdp_spin_lock, flag);
+
+ if (vsync_isr) {
+ vsync_isr_handler();
+ } else {
+ mdp_pipe_ctrl(MDP_CMD_BLOCK,
+ MDP_BLOCK_POWER_OFF, TRUE);
+ complete(&vsync_cntrl.vsync_wait);
+ }
}
/* DMA2 LCD-Out Complete */
@@ -1983,6 +1976,7 @@
atomic_set(&mdp_block_power_cnt[i], 0);
}
INIT_WORK(&(vsync_cntrl.vsync_work), send_vsync_work);
+ init_completion(&vsync_cntrl.vsync_wait);
#ifdef MSM_FB_ENABLE_DBGFS
{
struct dentry *root;
@@ -2360,7 +2354,7 @@
if (!(mdp_pdata->cont_splash_enabled))
mdp4_hw_init();
#else
- mdp_hw_init();
+ mdp_hw_init(mdp_pdata->cont_splash_enabled);
#endif
#ifdef CONFIG_FB_MSM_OVERLAY
diff --git a/drivers/video/msm/mdp.h b/drivers/video/msm/mdp.h
index 293bd9b..af5a661 100644
--- a/drivers/video/msm/mdp.h
+++ b/drivers/video/msm/mdp.h
@@ -44,6 +44,7 @@
extern int mdp_rev;
extern int mdp_iommu_split_domain;
extern struct mdp_csc_cfg mdp_csc_convert[4];
+extern struct mdp_csc_cfg_data csc_cfg_matrix[];
extern struct workqueue_struct *mdp_hist_wq;
extern uint32 mdp_intr_mask;
@@ -96,6 +97,7 @@
struct device *dev;
struct work_struct vsync_work;
int vsync_irq_enabled;
+ struct completion vsync_wait;
};
extern struct vsync vsync_cntrl;
@@ -717,7 +719,7 @@
#define MDP_DMA_P_LUT_C2_EN BIT(2)
#define MDP_DMA_P_LUT_POST BIT(4)
-void mdp_hw_init(void);
+void mdp_hw_init(int splash);
int mdp_ppp_pipe_wait(void);
void mdp_pipe_kickoff(uint32 term, struct msm_fb_data_type *mfd);
void mdp_clk_ctrl(int on);
@@ -829,8 +831,6 @@
void mdp_dma_vsync_ctrl(int enable);
void mdp_dma_video_vsync_ctrl(int enable);
void mdp_dma_lcdc_vsync_ctrl(int enable);
-void mdp3_vsync_irq_enable(int intr, int term);
-void mdp3_vsync_irq_disable(int intr, int term);
#ifdef MDP_HW_VSYNC
void vsync_clk_prepare_enable(void);
diff --git a/drivers/video/msm/mdp4.h b/drivers/video/msm/mdp4.h
index 13a922f..054741f 100644
--- a/drivers/video/msm/mdp4.h
+++ b/drivers/video/msm/mdp4.h
@@ -193,6 +193,8 @@
MDP4_CHROMA_420
};
+#define CSC_MAX_BLOCKS 6
+
#define MDP4_BLEND_BG_TRANSP_EN BIT(9)
#define MDP4_BLEND_FG_TRANSP_EN BIT(8)
#define MDP4_BLEND_BG_MOD_ALPHA BIT(7)
@@ -456,9 +458,6 @@
void mdp4_clear_lcdc(void);
void mdp4_mixer_blend_init(int mixer_num);
void mdp4_vg_qseed_init(int vg_num);
-void mdp4_vg_csc_setup(int vp_num);
-void mdp4_mixer_csc_setup(uint32 mixer);
-void mdp4_dmap_csc_setup(void);
void mdp4_vg_csc_update(struct mdp_csc *p);
irqreturn_t mdp4_isr(int irq, void *ptr);
void mdp4_overlay_format_to_pipe(uint32 format, struct mdp4_overlay_pipe *pipe);
@@ -569,6 +568,7 @@
void mdp4_overlay_rgb_setup(struct mdp4_overlay_pipe *pipe);
void mdp4_overlay_reg_flush(struct mdp4_overlay_pipe *pipe, int all);
void mdp4_mixer_blend_setup(int mixer);
+void mdp4_mixer_blend_cfg(int);
struct mdp4_overlay_pipe *mdp4_overlay_stage_pipe(int mixer, int stage);
void mdp4_mixer_stage_up(struct mdp4_overlay_pipe *pipe);
void mdp4_mixer_stage_down(struct mdp4_overlay_pipe *pipe);
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index 31e62b2..c07b3a7 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -757,6 +757,7 @@
case MDP_Y_CBCR_H1V1:
case MDP_Y_CRCB_H2V1:
case MDP_Y_CBCR_H2V1:
+ case MDP_Y_CRCB_H1V2:
*luma_off = pipe->src_x;
*chroma_off = pipe->src_x;
break;
@@ -794,7 +795,8 @@
uint32 frame_size, src_size, src_xy, dst_size, dst_xy;
uint32 format, pattern, luma_offset, chroma_offset;
uint32 mask;
- int pnum, ptype;
+ int pnum, ptype, i;
+ uint32_t block;
pnum = pipe->pipe_num - OVERLAY_PIPE_VG1; /* start from 0 */
vg_base = MDP_BASE + MDP4_VIDEO_BASE;
@@ -822,6 +824,20 @@
mdp4_csc_write(&pipe->pp_cfg.csc_cfg,
(uint32_t) (vg_base + MDP4_VIDEO_CSC_OFF));
+
+ if (pipe->pipe_num == OVERLAY_PIPE_VG1)
+ block = MDP_BLOCK_VG_1;
+ else
+ block = MDP_BLOCK_VG_2;
+
+ for (i = 0; i < CSC_MAX_BLOCKS; i++) {
+ if (block == csc_cfg_matrix[i].block) {
+ memcpy(&csc_cfg_matrix[i].csc_data,
+ &(pipe->pp_cfg.csc_cfg),
+ sizeof(struct mdp_csc_cfg));
+ break;
+ }
+ }
}
if (pipe->pp_cfg.config_ops & MDP_OVERLAY_PP_QSEED_CFG) {
mdp4_qseed_access_cfg(&pipe->pp_cfg.qseed_cfg[0],
@@ -946,6 +962,7 @@
case MDP_YCRYCB_H2V1:
case MDP_Y_CRCB_H2V1:
case MDP_Y_CBCR_H2V1:
+ case MDP_Y_CRCB_H1V2:
case MDP_Y_CRCB_H2V2:
case MDP_Y_CBCR_H2V2:
case MDP_Y_CBCR_H2V2_TILE:
@@ -1129,6 +1146,7 @@
break;
case MDP_Y_CRCB_H2V1:
case MDP_Y_CBCR_H2V1:
+ case MDP_Y_CRCB_H1V2:
case MDP_Y_CRCB_H2V2:
case MDP_Y_CBCR_H2V2:
case MDP_Y_CRCB_H1V1:
@@ -1165,6 +1183,10 @@
pipe->chroma_sample = MDP4_CHROMA_H1V2;
else
pipe->chroma_sample = MDP4_CHROMA_RGB;
+ } else if (pipe->src_format == MDP_Y_CRCB_H1V2) {
+ pipe->element1 = C1_B_Cb;
+ pipe->element0 = C2_R_Cr;
+ pipe->chroma_sample = MDP4_CHROMA_H1V2;
} else if (pipe->src_format == MDP_Y_CRCB_H2V2) {
pipe->element1 = C1_B_Cb;
pipe->element0 = C2_R_Cr;
@@ -1325,6 +1347,7 @@
case MDP_Y_CR_CB_GH2V2:
case MDP_Y_CRCB_H2V2:
case MDP_Y_CRCB_H2V1:
+ case MDP_Y_CRCB_H1V2:
case MDP_Y_CRCB_H1V1:
case MDP_Y_CBCR_H1V1:
case MDP_YCRCB_H1V1:
@@ -1866,6 +1889,32 @@
mdp4_overlay_reg_flush(pipe, 0);
}
+void mdp4_mixer_blend_cfg(int mixer)
+{
+ int i, off;
+ unsigned char *overlay_base;
+ struct blend_cfg *blend;
+
+ if (mixer == MDP4_MIXER2)
+ overlay_base = MDP_BASE + MDP4_OVERLAYPROC2_BASE;
+ else if (mixer == MDP4_MIXER1)
+ overlay_base = MDP_BASE + MDP4_OVERLAYPROC1_BASE;
+ else
+ overlay_base = MDP_BASE + MDP4_OVERLAYPROC0_BASE;
+
+ blend = &ctrl->blend[mixer][MDP4_MIXER_STAGE_BASE];
+ blend++; /* stage0 */
+
+ for (i = MDP4_MIXER_STAGE0; i < MDP4_MIXER_STAGE_MAX; i++) {
+ off = 20 * i;
+ off = 0x20 * (i - MDP4_MIXER_STAGE0);
+ if (i == MDP4_MIXER_STAGE3)
+ off -= 4;
+ outpdw(overlay_base + off + 0x104, blend->op);
+ blend++;
+ }
+}
+
/*
* D(i+1) = Ks * S + Kd * D(i)
*/
@@ -2009,7 +2058,10 @@
outpdw(overlay_base + off + 0x108, blend->fg_alpha);
outpdw(overlay_base + off + 0x10c, blend->bg_alpha);
- outpdw(overlay_base + off + 0x104, blend->op);
+
+ if (mdp_rev >= MDP_REV_42)
+ outpdw(overlay_base + off + 0x104, blend->op);
+
outpdw(overlay_base + (off << 5) + 0x1004, blend->co3_sel);
outpdw(overlay_base + off + 0x110, blend->transp_low0);/* low */
outpdw(overlay_base + off + 0x114, blend->transp_low1);/* low */
@@ -2400,17 +2452,6 @@
return ret;
}
- /*
- * Serveral special cases require the max mdp clk but cannot
- * be explained by mdp clk equation.
- */
- if (pipe->flags & MDP_DEINTERLACE) {
- pr_info("%s deinterlace requires max mdp clk.\n",
- __func__);
- pipe->req_clk = mdp_max_clk;
- return 0;
- }
-
pr_debug("%s: pipe sets: panel res(x,y)=(%d,%d)\n",
__func__, mfd->panel_info.xres, mfd->panel_info.yres);
pr_debug("%s: src(w,h)(%d,%d),src(x,y)(%d,%d)\n",
@@ -2522,6 +2563,22 @@
rst >>= shift;
/*
+ * There is one special case for the panels that have low
+ * v_back_porch (<=4), mdp clk should be fast enough to buffer
+ * 4 lines input during back porch time if scaling is
+ * required(FIR).
+ */
+ if ((mfd->panel_info.lcdc.v_back_porch <= 4) &&
+ (pipe->src_h != pipe->dst_h)) {
+ u32 clk = 0;
+ clk = 4 * (pclk >> shift) / mfd->panel_info.lcdc.v_back_porch;
+ clk <<= shift;
+ pr_debug("%s: mdp clk rate %d based on low vbp %d\n",
+ __func__, clk, mfd->panel_info.lcdc.v_back_porch);
+ rst = (rst > clk) ? rst : clk;
+ }
+
+ /*
* If the calculated mdp clk is less than panel pixel clk,
* most likely due to upscaling, mdp clk rate will be set to
* greater than pclk. Now the driver uses 1.15 as the
@@ -2533,6 +2590,16 @@
__func__);
}
+ /*
+ * Interlaced videos require the max mdp clk but cannot
+ * be explained by mdp clk equation.
+ */
+ if (pipe->flags & MDP_DEINTERLACE) {
+ rst = (rst > mdp_max_clk) ? rst : mdp_max_clk;
+ pr_info("%s deinterlace requires max mdp clk.\n",
+ __func__);
+ }
+
pipe->req_clk = (u32) rst;
pr_debug("%s: required mdp clk %d mixer %d pipe ndx %d\n",
@@ -3222,9 +3289,7 @@
return 0;
}
- if (pipe->mixer_num == MDP4_MIXER2 ||
- ctrl->panel_mode & MDP4_PANEL_MDDI)
- mutex_lock(&mfd->dma->ov_mutex);
+ mutex_lock(&mfd->dma->ov_mutex);
img = &req->data;
get_img(img, info, pipe, 0, &start, &len, &srcp0_file,
@@ -3270,7 +3335,8 @@
}
pipe->srcp0_ystride = pipe->src_width;
if ((pipe->src_format == MDP_Y_CRCB_H1V1) ||
- (pipe->src_format == MDP_Y_CBCR_H1V1)) {
+ (pipe->src_format == MDP_Y_CBCR_H1V1) ||
+ (pipe->src_format == MDP_Y_CRCB_H1V2)) {
if (pipe->src_width > YUV_444_MAX_WIDTH)
pipe->srcp1_ystride = pipe->src_width << 2;
else
@@ -3354,6 +3420,7 @@
mdp4_dtv_pipe_queue(0, pipe);/* cndx = 0 */
}
+ mutex_unlock(&mfd->dma->ov_mutex);
return ret;
mddi:
@@ -3385,8 +3452,10 @@
if (!(pipe->flags & MDP_OV_PLAY_NOWAIT))
mdp4_iommu_unmap(pipe);
mdp4_stat.overlay_play[pipe->mixer_num]++;
- mutex_unlock(&mfd->dma->ov_mutex);
+
end:
+ mutex_unlock(&mfd->dma->ov_mutex);
+
#ifdef CONFIG_ANDROID_PMEM
if (srcp0_file)
put_pmem_file(srcp0_file);
@@ -3610,4 +3679,3 @@
mutex_unlock(&mfd->dma->ov_mutex);
return err;
}
-
diff --git a/drivers/video/msm/mdp4_overlay_dtv.c b/drivers/video/msm/mdp4_overlay_dtv.c
index 00f44d4..e131369 100644
--- a/drivers/video/msm/mdp4_overlay_dtv.c
+++ b/drivers/video/msm/mdp4_overlay_dtv.c
@@ -840,8 +840,12 @@
vctrl->blt_change = 0;
}
+ if (mdp_rev <= MDP_REV_41)
+ mdp4_mixer_blend_cfg(MDP4_MIXER1);
+
complete_all(&vctrl->dmae_comp);
mdp4_overlay_dma_commit(MDP4_MIXER1);
+
vsync_irq_disable(INTR_DMA_E_DONE, MDP_DMA_E_TERM);
spin_unlock(&vctrl->spin_lock);
}
diff --git a/drivers/video/msm/mdp4_overlay_lcdc.c b/drivers/video/msm/mdp4_overlay_lcdc.c
index 08c3815..a2fabca 100644
--- a/drivers/video/msm/mdp4_overlay_lcdc.c
+++ b/drivers/video/msm/mdp4_overlay_lcdc.c
@@ -780,6 +780,10 @@
}
complete_all(&vctrl->dmap_comp);
+
+ if (mdp_rev <= MDP_REV_41)
+ mdp4_mixer_blend_cfg(MDP4_MIXER0);
+
mdp4_overlay_dma_commit(cndx);
spin_unlock(&vctrl->spin_lock);
}
diff --git a/drivers/video/msm/mdp4_util.c b/drivers/video/msm/mdp4_util.c
index ca73a70..34ae716 100644
--- a/drivers/video/msm/mdp4_util.c
+++ b/drivers/video/msm/mdp4_util.c
@@ -35,6 +35,148 @@
struct mdp4_statistic mdp4_stat;
+struct mdp_csc_cfg_data csc_cfg_matrix[CSC_MAX_BLOCKS] = {
+ {
+ .block = MDP_BLOCK_VG_1,
+ .csc_data = {
+ (MDP_CSC_FLAG_YUV_OUT),
+ {
+ 0x0254, 0x0000, 0x0331,
+ 0x0254, 0xff37, 0xfe60,
+ 0x0254, 0x0409, 0x0000,
+ },
+ {
+ 0xfff0, 0xff80, 0xff80,
+ },
+ {
+ 0, 0, 0,
+ },
+ {
+ 0, 0xff, 0, 0xff, 0, 0xff,
+ },
+ {
+ 0, 0xff, 0, 0xff, 0, 0xff,
+ },
+ },
+ },
+ {
+ .block = MDP_BLOCK_VG_2,
+ .csc_data = {
+ (MDP_CSC_FLAG_YUV_OUT),
+ {
+ 0x0254, 0x0000, 0x0331,
+ 0x0254, 0xff37, 0xfe60,
+ 0x0254, 0x0409, 0x0000,
+ },
+ {
+ 0xfff0, 0xff80, 0xff80,
+ },
+ {
+ 0, 0, 0,
+ },
+ {
+ 0, 0xff, 0, 0xff, 0, 0xff,
+ },
+ {
+ 0, 0xff, 0, 0xff, 0, 0xff,
+ },
+ },
+ },
+ {
+ .block = MDP_BLOCK_DMA_P,
+ .csc_data = {
+ (0),
+ {
+ 0x0200, 0x0000, 0x0000,
+ 0x0000, 0x0200, 0x0000,
+ 0x0000, 0x0000, 0x0200,
+ },
+ {
+ 0x0, 0x0, 0x0,
+ },
+ {
+ 0, 0, 0,
+ },
+ {
+ 0, 0xff, 0, 0xff, 0, 0xff,
+ },
+ {
+ 0, 0xff, 0, 0xff, 0, 0xff,
+ },
+ },
+ },
+ {
+ .block = MDP_BLOCK_OVERLAY_1,
+ .csc_data = {
+ (0),
+ {
+ 0x0200, 0x0000, 0x0000,
+ 0x0000, 0x0200, 0x0000,
+ 0x0000, 0x0000, 0x0200,
+ },
+ {
+ 0x0, 0x0, 0x0,
+ },
+ {
+ 0, 0, 0,
+ },
+ {
+ 0, 0xff, 0, 0xff, 0, 0xff,
+ },
+ {
+ 0, 0xff, 0, 0xff, 0, 0xff,
+ },
+ },
+ },
+ {
+ .block = MDP_BLOCK_OVERLAY_2,
+ .csc_data = {
+ (0),
+ {
+ 0x0200, 0x0000, 0x0000,
+ 0x0000, 0x0200, 0x0000,
+ 0x0000, 0x0000, 0x0200,
+ },
+ {
+ 0x0, 0x0, 0x0,
+ },
+ {
+ 0, 0, 0,
+ },
+ {
+ 0, 0xff, 0, 0xff, 0, 0xff,
+ },
+ {
+ 0, 0xff, 0, 0xff, 0, 0xff,
+ },
+ },
+ },
+ {
+ .block = MDP_BLOCK_DMA_S,
+ .csc_data = {
+ (0),
+ {
+ 0x0200, 0x0000, 0x0000,
+ 0x0000, 0x0200, 0x0000,
+ 0x0000, 0x0000, 0x0200,
+ },
+ {
+ 0x0, 0x0, 0x0,
+ },
+ {
+ 0, 0, 0,
+ },
+ {
+ 0, 0xff, 0, 0xff, 0, 0xff,
+ },
+ {
+ 0, 0xff, 0, 0xff, 0, 0xff,
+ },
+ },
+ },
+};
+
+
unsigned is_mdp4_hw_reset(void)
{
unsigned hw_reset = 0;
@@ -245,7 +387,7 @@
{
ulong bits;
uint32 clk_rate;
-
+ int i;
/* MDP cmd block enable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
@@ -273,11 +415,8 @@
mdp4_vg_qseed_init(0);
mdp4_vg_qseed_init(1);
- mdp4_vg_csc_setup(0);
- mdp4_vg_csc_setup(1);
- mdp4_mixer_csc_setup(1);
- mdp4_mixer_csc_setup(2);
- mdp4_dmap_csc_setup();
+ for (i = 0; i < CSC_MAX_BLOCKS; i++)
+ mdp4_csc_config(&csc_cfg_matrix[i]);
if (mdp_rev <= MDP_REV_41) {
mdp4_mixer_gc_lut_setup(0);
@@ -1258,422 +1397,46 @@
},
};
-struct mdp_csc_cfg csc_matrix[3] = {
- {
- (MDP_CSC_FLAG_YUV_OUT),
- {
- 0x0254, 0x0000, 0x0331,
- 0x0254, 0xff37, 0xfe60,
- 0x0254, 0x0409, 0x0000,
- },
- {
- 0xfff0, 0xff80, 0xff80,
- },
- {
- 0, 0, 0,
- },
- {
- 0, 0xff, 0, 0xff, 0, 0xff,
- },
- {
- 0, 0xff, 0, 0xff, 0, 0xff,
- },
- },
- {
- (MDP_CSC_FLAG_YUV_OUT),
- {
- 0x0254, 0x0000, 0x0331,
- 0x0254, 0xff37, 0xfe60,
- 0x0254, 0x0409, 0x0000,
- },
- {
- 0xfff0, 0xff80, 0xff80,
- },
- {
- 0, 0, 0,
- },
- {
- 0, 0xff, 0, 0xff, 0, 0xff,
- },
- {
- 0, 0xff, 0, 0xff, 0, 0xff,
- },
- },
- {
- (0),
- {
- 0x0200, 0x0000, 0x0000,
- 0x0000, 0x0200, 0x0000,
- 0x0000, 0x0000, 0x0200,
- },
- {
- 0x0, 0x0, 0x0,
- },
- {
- 0, 0, 0,
- },
- {
- 0, 0xff, 0, 0xff, 0, 0xff,
- },
- {
- 0, 0xff, 0, 0xff, 0, 0xff,
- },
- },
-};
-
-
-#define MDP4_CSC_MV_OFF 0x4400
-#define MDP4_CSC_PRE_BV_OFF 0x4500
-#define MDP4_CSC_POST_BV_OFF 0x4580
-#define MDP4_CSC_PRE_LV_OFF 0x4600
-#define MDP4_CSC_POST_LV_OFF 0x4680
-
-void mdp4_vg_csc_mv_setup(int vp_num)
-{
- uint32 *off;
- int i, voff;
-
- voff = MDP4_VIDEO_OFF * vp_num;
- off = (uint32 *)(MDP_BASE + MDP4_VIDEO_BASE + voff +
- MDP4_CSC_MV_OFF);
-
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
- for (i = 0; i < 9; i++) {
- outpdw(off, csc_matrix[vp_num].csc_mv[i]);
- off++;
- }
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
-}
-
-void mdp4_vg_csc_pre_bv_setup(int vp_num)
-{
- uint32 *off;
- int i, voff;
-
- voff = MDP4_VIDEO_OFF * vp_num;
- off = (uint32 *)(MDP_BASE + MDP4_VIDEO_BASE + voff +
- MDP4_CSC_PRE_BV_OFF);
-
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
- for (i = 0; i < 3; i++) {
- outpdw(off, csc_matrix[vp_num].csc_pre_bv[i]);
- off++;
- }
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
-}
-
-void mdp4_vg_csc_post_bv_setup(int vp_num)
-{
- uint32 *off;
- int i, voff;
-
- voff = MDP4_VIDEO_OFF * vp_num;
- off = (uint32 *)(MDP_BASE + MDP4_VIDEO_BASE + voff +
- MDP4_CSC_POST_BV_OFF);
-
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
- for (i = 0; i < 3; i++) {
- outpdw(off, csc_matrix[vp_num].csc_post_bv[i]);
- off++;
- }
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
-}
-
-void mdp4_vg_csc_pre_lv_setup(int vp_num)
-{
- uint32 *off;
- int i, voff;
-
- voff = MDP4_VIDEO_OFF * vp_num;
- off = (uint32 *)(MDP_BASE + MDP4_VIDEO_BASE + voff +
- MDP4_CSC_PRE_LV_OFF);
-
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
- for (i = 0; i < 6; i++) {
- outpdw(off, csc_matrix[vp_num].csc_pre_lv[i]);
- off++;
- }
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
-}
-
-void mdp4_vg_csc_post_lv_setup(int vp_num)
-{
- uint32 *off;
- int i, voff;
-
- voff = MDP4_VIDEO_OFF * vp_num;
- off = (uint32 *)(MDP_BASE + MDP4_VIDEO_BASE + voff +
- MDP4_CSC_POST_LV_OFF);
-
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
- for (i = 0; i < 6; i++) {
- outpdw(off, csc_matrix[vp_num].csc_post_lv[i]);
- off++;
- }
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
-}
-
-void mdp4_vg_csc_convert_setup(int vp_num)
-{
- struct mdp_csc_cfg_data cfg;
-
- switch (vp_num) {
- case 0:
- cfg.block = MDP_BLOCK_VG_1;
- break;
- case 1:
- cfg.block = MDP_BLOCK_VG_2;
- break;
- default:
- pr_err("%s - invalid vp_num = %d", __func__, vp_num);
- return;
- }
- cfg.csc_data = csc_matrix[vp_num];
- mdp4_csc_enable(&cfg);
-}
-
-void mdp4_vg_csc_setup(int vp_num)
-{
- /* yuv2rgb */
- mdp4_vg_csc_mv_setup(vp_num);
- mdp4_vg_csc_pre_bv_setup(vp_num);
- mdp4_vg_csc_post_bv_setup(vp_num);
- mdp4_vg_csc_pre_lv_setup(vp_num);
- mdp4_vg_csc_post_lv_setup(vp_num);
- mdp4_vg_csc_convert_setup(vp_num);
-}
void mdp4_vg_csc_update(struct mdp_csc *p)
{
struct mdp4_overlay_pipe *pipe;
- int vp_num;
+ uint32_t block = 0;
+ int i = 0;
pipe = mdp4_overlay_ndx2pipe(p->id);
if (pipe == NULL) {
pr_err("%s: p->id = %d Error\n", __func__, p->id);
return;
}
-
- vp_num = pipe->pipe_num - OVERLAY_PIPE_VG1;
-
- if (vp_num == 0 || vp_num == 1) {
- memcpy(csc_matrix[vp_num].csc_mv, p->csc_mv, sizeof(p->csc_mv));
- memcpy(csc_matrix[vp_num].csc_pre_bv, p->csc_pre_bv,
- sizeof(p->csc_pre_bv));
- memcpy(csc_matrix[vp_num].csc_post_bv, p->csc_post_bv,
- sizeof(p->csc_post_bv));
- memcpy(csc_matrix[vp_num].csc_pre_lv, p->csc_pre_lv,
- sizeof(p->csc_pre_lv));
- memcpy(csc_matrix[vp_num].csc_post_lv, p->csc_post_lv,
- sizeof(p->csc_post_lv));
- mdp4_vg_csc_setup(vp_num);
- }
-}
-static uint32 csc_rgb2yuv_matrix_tab[9] = {
- 0x0083, 0x0102, 0x0032,
- 0x1fb5, 0x1f6c, 0x00e1,
- 0x00e1, 0x1f45, 0x1fdc
-};
-
-static uint32 csc_rgb2yuv_pre_bv_tab[3] = {0, 0, 0};
-
-static uint32 csc_rgb2yuv_post_bv_tab[3] = {0x0010, 0x0080, 0x0080};
-
-static uint32 csc_rgb2yuv_pre_lv_tab[6] = {
- 0x00, 0xff, 0x00,
- 0xff, 0x00, 0xff
-};
-
-static uint32 csc_rgb2yuv_post_lv_tab[6] = {
- 0x0010, 0x00eb, 0x0010,
- 0x00f0, 0x0010, 0x00f0
-};
-
-void mdp4_mixer_csc_mv_setup(uint32 mixer)
-{
- uint32 *off;
- int i;
-
- if (mixer == MDP4_MIXER1)
- off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC1_BASE + 0x2400);
+ if (pipe->pipe_num == OVERLAY_PIPE_VG1)
+ block = MDP_BLOCK_VG_1;
+ else if (pipe->pipe_num == OVERLAY_PIPE_VG2)
+ block = MDP_BLOCK_VG_2;
else
- off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC2_BASE + 0x2400);
+ return;
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
- for (i = 0; i < 9; i++) {
- outpdw(off, csc_rgb2yuv_matrix_tab[i]);
- off++;
+ for (i = 0; i < CSC_MAX_BLOCKS; i++) {
+ if (csc_cfg_matrix[i].block == block)
+ break;
}
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
-}
+ if (i == CSC_MAX_BLOCKS)
+ return;
-void mdp4_mixer_csc_pre_bv_setup(uint32 mixer)
-{
- uint32 *off;
- int i;
+ memcpy(&csc_cfg_matrix[i].csc_data.csc_mv, p->csc_mv,
+ sizeof(p->csc_mv));
+ memcpy(&csc_cfg_matrix[i].csc_data.csc_pre_bv, p->csc_pre_bv,
+ sizeof(p->csc_pre_bv));
+ memcpy(&csc_cfg_matrix[i].csc_data.csc_post_bv, p->csc_post_bv,
+ sizeof(p->csc_post_bv));
+ memcpy(&csc_cfg_matrix[i].csc_data.csc_pre_lv, p->csc_pre_lv,
+ sizeof(p->csc_pre_lv));
+ memcpy(&csc_cfg_matrix[i].csc_data.csc_post_lv, p->csc_post_lv,
+ sizeof(p->csc_post_lv));
+ csc_cfg_matrix[i].csc_data.flags = MDP_CSC_FLAG_YUV_OUT;
- if (mixer == MDP4_MIXER1)
- off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC1_BASE + 0x2500);
- else
- off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC2_BASE + 0x2500);
+ mdp4_csc_config(&csc_cfg_matrix[i]);
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
- for (i = 0; i < 3; i++) {
- outpdw(off, csc_rgb2yuv_pre_bv_tab[i]);
- off++;
- }
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
-}
-
-void mdp4_mixer_csc_post_bv_setup(uint32 mixer)
-{
- uint32 *off;
- int i;
-
- if (mixer == MDP4_MIXER1)
- off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC1_BASE + 0x2580);
- else
- off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC2_BASE + 0x2580);
-
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
- for (i = 0; i < 3; i++) {
- outpdw(off, csc_rgb2yuv_post_bv_tab[i]);
- off++;
- }
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
-}
-
-void mdp4_mixer_csc_pre_lv_setup(uint32 mixer)
-{
- uint32 *off;
- int i;
-
- if (mixer == MDP4_MIXER1)
- off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC1_BASE + 0x2600);
- else
- off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC2_BASE + 0x2600);
-
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
- for (i = 0; i < 6; i++) {
- outpdw(off, csc_rgb2yuv_pre_lv_tab[i]);
- off++;
- }
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
-}
-
-void mdp4_mixer_csc_post_lv_setup(uint32 mixer)
-{
- uint32 *off;
- int i;
-
- if (mixer == MDP4_MIXER1)
- off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC1_BASE + 0x2680);
- else
- off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC2_BASE + 0x2680);
-
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
- for (i = 0; i < 6; i++) {
- outpdw(off, csc_rgb2yuv_post_lv_tab[i]);
- off++;
- }
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
-}
-
-void mdp4_mixer_csc_setup(uint32 mixer)
-{
- if (mixer >= MDP4_MIXER1) {
- /* rgb2yuv */
- mdp4_mixer_csc_mv_setup(mixer);
- mdp4_mixer_csc_pre_bv_setup(mixer);
- mdp4_mixer_csc_post_bv_setup(mixer);
- mdp4_mixer_csc_pre_lv_setup(mixer);
- mdp4_mixer_csc_post_lv_setup(mixer);
- }
-}
-
-#define DMA_P_BASE 0x90000
-void mdp4_dmap_csc_mv_setup(void)
-{
- uint32 *off;
- int i;
-
- off = (uint32 *)(MDP_BASE + DMA_P_BASE + 0x3400);
-
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
- for (i = 0; i < 9; i++) {
- outpdw(off, csc_matrix[2].csc_mv[i]);
- off++;
- }
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
-}
-
-void mdp4_dmap_csc_pre_bv_setup(void)
-{
- uint32 *off;
- int i;
-
- off = (uint32 *)(MDP_BASE + DMA_P_BASE + 0x3500);
-
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
- for (i = 0; i < 3; i++) {
- outpdw(off, csc_matrix[2].csc_pre_bv[i]);
- off++;
- }
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
-}
-
-void mdp4_dmap_csc_post_bv_setup(void)
-{
- uint32 *off;
- int i;
-
- off = (uint32 *)(MDP_BASE + DMA_P_BASE + 0x3580);
-
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
- for (i = 0; i < 3; i++) {
- outpdw(off, csc_matrix[2].csc_post_bv[i]);
- off++;
- }
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
-}
-
-void mdp4_dmap_csc_pre_lv_setup(void)
-{
- uint32 *off;
- int i;
-
- off = (uint32 *)(MDP_BASE + DMA_P_BASE + 0x3600);
-
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
- for (i = 0; i < 6; i++) {
- outpdw(off, csc_matrix[2].csc_pre_lv[i]);
- off++;
- }
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
-}
-
-void mdp4_dmap_csc_post_lv_setup(void)
-{
- uint32 *off;
- int i;
-
- off = (uint32 *)(MDP_BASE + DMA_P_BASE + 0x3680);
-
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
- for (i = 0; i < 6; i++) {
- outpdw(off, csc_matrix[2].csc_post_lv[i]);
- off++;
- }
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
-}
-
-void mdp4_dmap_csc_setup(void)
-{
- mdp4_dmap_csc_mv_setup();
- mdp4_dmap_csc_pre_bv_setup();
- mdp4_dmap_csc_post_bv_setup();
- mdp4_dmap_csc_pre_lv_setup();
- mdp4_dmap_csc_post_lv_setup();
}
char gc_lut[] = {
diff --git a/drivers/video/msm/mdp_dma.c b/drivers/video/msm/mdp_dma.c
index a506648..df57ee1 100644
--- a/drivers/video/msm/mdp_dma.c
+++ b/drivers/video/msm/mdp_dma.c
@@ -514,18 +514,27 @@
void mdp_dma_vsync_ctrl(int enable)
{
+ unsigned long flag;
if (vsync_cntrl.vsync_irq_enabled == enable)
return;
+ spin_lock_irqsave(&mdp_spin_lock, flag);
vsync_cntrl.vsync_irq_enabled = enable;
+ spin_unlock_irqrestore(&mdp_spin_lock, flag);
if (enable) {
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
MDP_OUTP(MDP_BASE + 0x021c, 0x10); /* read pointer */
- mdp3_vsync_irq_enable(MDP_PRIM_RDPTR, MDP_VSYNC_TERM);
+ spin_lock_irqsave(&mdp_spin_lock, flag);
+ outp32(MDP_INTR_CLEAR, MDP_PRIM_RDPTR);
+ mdp_intr_mask |= MDP_PRIM_RDPTR;
+ outp32(MDP_INTR_ENABLE, mdp_intr_mask);
+ mdp_enable_irq(MDP_VSYNC_TERM);
+ spin_unlock_irqrestore(&mdp_spin_lock, flag);
} else {
- mdp3_vsync_irq_disable(MDP_PRIM_RDPTR, MDP_VSYNC_TERM);
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+ INIT_COMPLETION(vsync_cntrl.vsync_wait);
+ wait_for_completion(&vsync_cntrl.vsync_wait);
+ mdp_disable_irq(MDP_VSYNC_TERM);
}
}
diff --git a/drivers/video/msm/mdp_dma_dsi_video.c b/drivers/video/msm/mdp_dma_dsi_video.c
index d94896f..09ae82f 100644
--- a/drivers/video/msm/mdp_dma_dsi_video.c
+++ b/drivers/video/msm/mdp_dma_dsi_video.c
@@ -249,17 +249,26 @@
void mdp_dma_video_vsync_ctrl(int enable)
{
+ unsigned long flag;
if (vsync_cntrl.vsync_irq_enabled == enable)
return;
+ spin_lock_irqsave(&mdp_spin_lock, flag);
vsync_cntrl.vsync_irq_enabled = enable;
+ spin_unlock_irqrestore(&mdp_spin_lock, flag);
if (enable) {
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
- mdp3_vsync_irq_enable(LCDC_FRAME_START, MDP_VSYNC_TERM);
+ spin_lock_irqsave(&mdp_spin_lock, flag);
+ outp32(MDP_INTR_CLEAR, LCDC_FRAME_START);
+ mdp_intr_mask |= LCDC_FRAME_START;
+ outp32(MDP_INTR_ENABLE, mdp_intr_mask);
+ mdp_enable_irq(MDP_VSYNC_TERM);
+ spin_unlock_irqrestore(&mdp_spin_lock, flag);
} else {
- mdp3_vsync_irq_disable(LCDC_FRAME_START, MDP_VSYNC_TERM);
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+ INIT_COMPLETION(vsync_cntrl.vsync_wait);
+ wait_for_completion(&vsync_cntrl.vsync_wait);
+ mdp_disable_irq(MDP_VSYNC_TERM);
}
}
diff --git a/drivers/video/msm/mdp_dma_lcdc.c b/drivers/video/msm/mdp_dma_lcdc.c
index e030c99..e1b78c2 100644
--- a/drivers/video/msm/mdp_dma_lcdc.c
+++ b/drivers/video/msm/mdp_dma_lcdc.c
@@ -330,17 +330,26 @@
void mdp_dma_lcdc_vsync_ctrl(int enable)
{
+ unsigned long flag;
if (vsync_cntrl.vsync_irq_enabled == enable)
return;
+ spin_lock_irqsave(&mdp_spin_lock, flag);
vsync_cntrl.vsync_irq_enabled = enable;
+ spin_unlock_irqrestore(&mdp_spin_lock, flag);
if (enable) {
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
- mdp3_vsync_irq_enable(LCDC_FRAME_START, MDP_VSYNC_TERM);
+ spin_lock_irqsave(&mdp_spin_lock, flag);
+ outp32(MDP_INTR_CLEAR, LCDC_FRAME_START);
+ mdp_intr_mask |= LCDC_FRAME_START;
+ outp32(MDP_INTR_ENABLE, mdp_intr_mask);
+ mdp_enable_irq(MDP_VSYNC_TERM);
+ spin_unlock_irqrestore(&mdp_spin_lock, flag);
} else {
- mdp3_vsync_irq_disable(LCDC_FRAME_START, MDP_VSYNC_TERM);
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+ INIT_COMPLETION(vsync_cntrl.vsync_wait);
+ wait_for_completion(&vsync_cntrl.vsync_wait);
+ mdp_disable_irq(MDP_VSYNC_TERM);
}
}
diff --git a/drivers/video/msm/mdp_hw_init.c b/drivers/video/msm/mdp_hw_init.c
index ff3ad41..fc8435c 100644
--- a/drivers/video/msm/mdp_hw_init.c
+++ b/drivers/video/msm/mdp_hw_init.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2008-2009, 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
@@ -584,7 +584,7 @@
#define IRQ_EN_1__MDP_IRQ___M 0x00000800
-void mdp_hw_init(void)
+void mdp_hw_init(int splash)
{
int i;
@@ -632,7 +632,8 @@
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x01e4, 0);
#ifndef CONFIG_FB_MSM_MDP22
- MDP_OUTP(MDP_BASE + 0xE0000, 0);
+ if (!splash)
+ MDP_OUTP(MDP_BASE + 0xE0000, 0);
MDP_OUTP(MDP_BASE + 0x100, 0xffffffff);
MDP_OUTP(MDP_BASE + 0x90070, 0);
#endif
diff --git a/drivers/video/msm/mdss/Kconfig b/drivers/video/msm/mdss/Kconfig
index 30351a3..424455f 100644
--- a/drivers/video/msm/mdss/Kconfig
+++ b/drivers/video/msm/mdss/Kconfig
@@ -3,3 +3,11 @@
---help---
The MDSS Writeback Panel provides support for routing the output of
MDSS frame buffer driver and MDP processing to memory.
+
+config FB_MSM_MDSS_HDMI_PANEL
+ depends on FB_MSM_MDSS
+ bool "MDSS HDMI Tx Panel"
+ default n
+ ---help---
+ The MDSS HDMI Panel provides support for transmitting TMDS signals of
+ MDSS frame buffer data to connected hdmi compliant TVs, monitors etc.
diff --git a/drivers/video/msm/mdss/Makefile b/drivers/video/msm/mdss/Makefile
index b6294f4..6bc21bc 100644
--- a/drivers/video/msm/mdss/Makefile
+++ b/drivers/video/msm/mdss/Makefile
@@ -7,10 +7,13 @@
mdss-mdp-objs += mdss_mdp_wb.o
obj-$(CONFIG_FB_MSM_MDSS) += mdss-mdp.o
obj-$(CONFIG_FB_MSM_MDSS) += mdss_fb.o
+obj-$(CONFIG_FB_MSM_MDSS) += mdss_io_util.o
mdss-dsi-objs := mdss_dsi.o mdss_dsi_host.o
mdss-dsi-objs += mdss_dsi_panel.o
mdss-dsi-objs += msm_mdss_io_8974.o
obj-$(CONFIG_FB_MSM_MDSS) += mdss-dsi.o
+obj-$(CONFIG_FB_MSM_MDSS_HDMI_PANEL) += mdss_hdmi_tx.o
+obj-$(CONFIG_FB_MSM_MDSS_HDMI_PANEL) += mdss_hdmi_util.o
obj-$(CONFIG_FB_MSM_MDSS_WRITEBACK) += mdss_wb.o
diff --git a/drivers/video/msm/mdss/mdss.h b/drivers/video/msm/mdss/mdss.h
index 675df03..886e8de 100644
--- a/drivers/video/msm/mdss/mdss.h
+++ b/drivers/video/msm/mdss/mdss.h
@@ -84,6 +84,7 @@
struct mdss_hw {
u32 hw_ndx;
+ void *ptr;
irqreturn_t (*irq_handler)(int irq, void *ptr);
};
diff --git a/drivers/video/msm/mdss/mdss_dsi_host.c b/drivers/video/msm/mdss/mdss_dsi_host.c
index 7bc0105..a9cf61e 100644
--- a/drivers/video/msm/mdss/mdss_dsi_host.c
+++ b/drivers/video/msm/mdss/mdss_dsi_host.c
@@ -34,6 +34,7 @@
struct mdss_hw mdss_dsi_hw = {
.hw_ndx = MDSS_HW_DSI0,
+ .ptr = NULL,
.irq_handler = mdss_dsi_isr,
};
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index 1a1bb07..1f83b2b 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -186,7 +186,7 @@
/*
* alloc framebuffer info + par data
*/
- fbi = framebuffer_alloc(sizeof(struct msm_fb_data_type), &pdev->dev);
+ fbi = framebuffer_alloc(sizeof(struct msm_fb_data_type), NULL);
if (fbi == NULL) {
pr_err("can't allocate framebuffer info data!\n");
return -ENOMEM;
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.c b/drivers/video/msm/mdss/mdss_hdmi_tx.c
new file mode 100644
index 0000000..6317069
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.c
@@ -0,0 +1,1105 @@
+/* Copyright (c) 2010-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/bitops.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of_address.h>
+#include <linux/of_gpio.h>
+#include <linux/types.h>
+
+/* #define DEBUG */
+
+#include "mdss_fb.h"
+#include "mdss_hdmi_tx.h"
+#include "mdss.h"
+#include "mdss_panel.h"
+
+#define DRV_NAME "hdmi-tx"
+#define COMPATIBLE_NAME "qcom,hdmi-tx"
+
+static irqreturn_t hdmi_tx_isr(int irq, void *data);
+
+struct mdss_hw hdmi_tx_hw = {
+ .hw_ndx = MDSS_HW_HDMI,
+ .ptr = NULL,
+ .irq_handler = hdmi_tx_isr,
+};
+
+const char *hdmi_pm_name(enum hdmi_tx_power_module_type module)
+{
+ switch (module) {
+ case HDMI_TX_HPD_PM: return "HDMI_TX_HPD_PM";
+ case HDMI_TX_CORE_PM: return "HDMI_TX_CORE_PM";
+ case HDMI_TX_CEC_PM: return "HDMI_TX_CEC_PM";
+ default: return "???";
+ }
+} /* hdmi_pm_name */
+
+static const char *hdmi_tx_clk_name(u32 clk)
+{
+ switch (clk) {
+ case HDMI_TX_AHB_CLK: return "hdmi_ahb_clk";
+ case HDMI_TX_APP_CLK: return "hdmi_app_clk";
+ case HDMI_TX_EXTP_CLK: return "hdmi_extp_clk";
+ default: return "???";
+ }
+} /* hdmi_tx_clk_name */
+
+static const char *hdmi_tx_io_name(u32 io)
+{
+ switch (io) {
+ case HDMI_TX_CORE_IO: return "core_physical";
+ case HDMI_TX_PHY_IO: return "phy_physical";
+ case HDMI_TX_QFPROM_IO: return "qfprom_physical";
+ default: return NULL;
+ }
+} /* hdmi_tx_io_name */
+
+static inline u32 hdmi_tx_is_controller_on(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+ return HDMI_REG_R_ND(hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO].base,
+ HDMI_CTRL) & BIT(0);
+} /* hdmi_tx_is_controller_on */
+
+static inline u32 hdmi_tx_is_dvi_mode(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+ return !(HDMI_REG_R_ND(hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO].base,
+ HDMI_CTRL) & BIT(1));
+} /* hdmi_tx_is_dvi_mode */
+
+static int hdmi_tx_init_panel_info(uint32_t resolution,
+ struct mdss_panel_info *pinfo)
+{
+ const struct hdmi_disp_mode_timing_type *timing =
+ hdmi_get_supported_mode(resolution);
+
+ if (!timing || !pinfo) {
+ DEV_ERR("%s: invalid input.\n", __func__);
+ return -EINVAL;
+ }
+
+ pinfo->xres = timing->active_h;
+ pinfo->yres = timing->active_v;
+ pinfo->clk_rate = timing->pixel_freq*1000;
+
+ pinfo->lcdc.h_back_porch = timing->back_porch_h;
+ pinfo->lcdc.h_front_porch = timing->front_porch_h;
+ pinfo->lcdc.h_pulse_width = timing->pulse_width_h;
+ pinfo->lcdc.v_back_porch = timing->back_porch_v;
+ pinfo->lcdc.v_front_porch = timing->front_porch_v;
+ pinfo->lcdc.v_pulse_width = timing->pulse_width_v;
+
+ pinfo->type = DTV_PANEL;
+ pinfo->pdest = DISPLAY_2;
+ pinfo->wait_cycle = 0;
+ pinfo->bpp = 24;
+ pinfo->fb_num = 1;
+
+ pinfo->lcdc.border_clr = 0; /* blk */
+ pinfo->lcdc.underflow_clr = 0xff; /* blue */
+ pinfo->lcdc.hsync_skew = 0;
+
+ return 0;
+} /* hdmi_tx_init_panel_info */
+
+/* Table indicating the video format supported by the HDMI TX Core */
+/* Valid Pixel-Clock rates: 25.2MHz, 27MHz, 27.03MHz, 74.25MHz, 148.5MHz */
+static void hdmi_tx_setup_video_mode_lut(void)
+{
+ hdmi_set_supported_mode(HDMI_VFRMT_640x480p60_4_3);
+ hdmi_set_supported_mode(HDMI_VFRMT_720x480p60_4_3);
+ hdmi_set_supported_mode(HDMI_VFRMT_720x480p60_16_9);
+ hdmi_set_supported_mode(HDMI_VFRMT_720x576p50_4_3);
+ hdmi_set_supported_mode(HDMI_VFRMT_720x576p50_16_9);
+ hdmi_set_supported_mode(HDMI_VFRMT_1440x480i60_4_3);
+ hdmi_set_supported_mode(HDMI_VFRMT_1440x480i60_16_9);
+ hdmi_set_supported_mode(HDMI_VFRMT_1440x576i50_4_3);
+ hdmi_set_supported_mode(HDMI_VFRMT_1440x576i50_16_9);
+ hdmi_set_supported_mode(HDMI_VFRMT_1280x720p50_16_9);
+ hdmi_set_supported_mode(HDMI_VFRMT_1280x720p60_16_9);
+ hdmi_set_supported_mode(HDMI_VFRMT_1920x1080p24_16_9);
+ hdmi_set_supported_mode(HDMI_VFRMT_1920x1080p25_16_9);
+ hdmi_set_supported_mode(HDMI_VFRMT_1920x1080p30_16_9);
+ hdmi_set_supported_mode(HDMI_VFRMT_1920x1080p50_16_9);
+ hdmi_set_supported_mode(HDMI_VFRMT_1920x1080i60_16_9);
+ hdmi_set_supported_mode(HDMI_VFRMT_1920x1080p60_16_9);
+} /* hdmi_tx_setup_video_mode_lut */
+
+static void hdmi_tx_hpd_state_work(struct work_struct *work)
+{
+ u32 hpd_state = false;
+ struct hdmi_tx_ctrl *hdmi_ctrl = NULL;
+ struct hdmi_tx_io_data *io = NULL;
+
+ hdmi_ctrl = container_of(work, struct hdmi_tx_ctrl, hpd_state_work);
+ if (!hdmi_ctrl || !hdmi_ctrl->hpd_initialized) {
+ DEV_DBG("%s: invalid input\n", __func__);
+ return;
+ }
+
+ io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
+ DEV_DBG("%s: Got HPD interrupt\n", __func__);
+
+ hpd_state = (HDMI_REG_R(io->base, HDMI_HPD_INT_STATUS) & BIT(1)) >> 1;
+ mutex_lock(&hdmi_ctrl->mutex);
+ if ((hdmi_ctrl->hpd_prev_state != hdmi_ctrl->hpd_state) ||
+ (hdmi_ctrl->hpd_state != hpd_state)) {
+
+ hdmi_ctrl->hpd_state = hpd_state;
+ hdmi_ctrl->hpd_prev_state = hdmi_ctrl->hpd_state;
+ hdmi_ctrl->hpd_stable = 0;
+
+ DEV_DBG("%s: state not stable yet, wait again (%d|%d|%d)\n",
+ __func__, hdmi_ctrl->hpd_prev_state,
+ hdmi_ctrl->hpd_state, hpd_state);
+
+ mutex_unlock(&hdmi_ctrl->mutex);
+
+ mod_timer(&hdmi_ctrl->hpd_state_timer, jiffies + HZ/2);
+
+ return;
+ }
+
+ if (hdmi_ctrl->hpd_stable) {
+ mutex_unlock(&hdmi_ctrl->mutex);
+ DEV_DBG("%s: no more timer, depending on IRQ now\n",
+ __func__);
+ return;
+ }
+
+ hdmi_ctrl->hpd_stable = 1;
+ DEV_INFO("HDMI HPD: event detected\n");
+
+ /*
+ *todo: Revisit cable chg detected condition when HPD support is ready
+ */
+ hdmi_ctrl->hpd_cable_chg_detected = false;
+ mutex_unlock(&hdmi_ctrl->mutex);
+
+ if (hpd_state) {
+ DEV_INFO("HDMI HPD: sense CONNECTED: send ONLINE\n");
+ kobject_uevent(hdmi_ctrl->kobj, KOBJ_ONLINE);
+ switch_set_state(&hdmi_ctrl->sdev, 1);
+ DEV_INFO("%s: Hdmi state switch to %d\n", __func__,
+ hdmi_ctrl->sdev.state);
+ } else {
+ DEV_INFO("HDMI HPD: sense DISCONNECTED: send OFFLINE\n");
+ kobject_uevent(hdmi_ctrl->kobj, KOBJ_OFFLINE);
+ switch_set_state(&hdmi_ctrl->sdev, 0);
+ DEV_INFO("%s: Hdmi state switch to %d\n", __func__,
+ hdmi_ctrl->sdev.state);
+ }
+
+ /* Set IRQ for HPD */
+ HDMI_REG_W(io->base, HDMI_HPD_INT_CTRL, 4 | (hpd_state ? 0 : 2));
+} /* hdmi_tx_hpd_state_work */
+
+static int hdmi_tx_check_capability(void __iomem *base)
+{
+ u32 hdmi_disabled, hdcp_disabled;
+
+ if (!base) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return -EINVAL;
+ }
+
+ /* QFPROM_RAW_FEAT_CONFIG_ROW0_LSB */
+ hdcp_disabled = HDMI_REG_R_ND(base, 0x000000F8) & BIT(31);
+ /* QFPROM_RAW_FEAT_CONFIG_ROW0_MSB */
+ hdmi_disabled = HDMI_REG_R_ND(base, 0x000000FC) & BIT(0);
+
+ DEV_DBG("%s: Features <HDMI:%s, HDCP:%s>\n", __func__,
+ hdmi_disabled ? "OFF" : "ON", hdcp_disabled ? "OFF" : "ON");
+
+ if (hdmi_disabled) {
+ DEV_ERR("%s: HDMI disabled\n", __func__);
+ return -ENODEV;
+ }
+
+ if (hdcp_disabled)
+ DEV_WARN("%s: HDCP disabled\n", __func__);
+
+ return 0;
+} /* hdmi_tx_check_capability */
+
+/* todo: revisit when new HPD debouncing logic is available */
+static void hdmi_tx_hpd_state_timer(unsigned long data)
+{
+ struct hdmi_tx_ctrl *hdmi_ctrl = (struct hdmi_tx_ctrl *)data;
+
+ if (hdmi_ctrl)
+ queue_work(hdmi_ctrl->workq, &hdmi_ctrl->hpd_state_work);
+ else
+ DEV_ERR("%s: invalid input\n", __func__);
+} /* hdmi_tx_hpd_state_timer */
+
+static inline struct clk *hdmi_tx_get_clk(struct hdmi_tx_platform_data *pdata,
+ u32 clk_idx)
+{
+ if (!pdata || clk_idx > HDMI_TX_MAX_CLK) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return NULL;
+ }
+
+ return pdata->clk[clk_idx];
+} /* hdmi_tx_get_clk */
+
+static int hdmi_tx_clk_set_rate(struct hdmi_tx_platform_data *pdata,
+ u32 clk_idx, unsigned long clk_rate)
+{
+ int rc = 0;
+ struct clk *clk = NULL;
+
+ if (!pdata) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return -EINVAL;
+ }
+
+ clk = hdmi_tx_get_clk(pdata, clk_idx);
+ if (clk) {
+ rc = clk_set_rate(clk, clk_rate);
+ if (IS_ERR_VALUE(rc))
+ DEV_ERR("%s: failed rc=%d\n", __func__, rc);
+ else
+ DEV_DBG("%s: clk=%d rate=%lu\n", __func__,
+ clk_idx, clk_rate);
+ } else {
+ DEV_ERR("%s: FAILED: invalid clk_idx=%d\n", __func__, clk_idx);
+ rc = -EINVAL;
+ }
+
+ return rc;
+} /* hdmi_tx_clk_set_rate */
+
+static int hdmi_tx_power_on(struct mdss_panel_data *panel_data)
+{
+ return 0;
+} /* hdmi_tx_power_on */
+
+static int hdmi_tx_power_off(struct mdss_panel_data *panel_data)
+{
+ return 0;
+} /* hdmi_tx_power_off */
+
+static irqreturn_t hdmi_tx_isr(int irq, void *data)
+{
+ u32 hpd_int_status;
+ u32 hpd_int_ctrl;
+ struct hdmi_tx_io_data *io = NULL;
+ struct hdmi_tx_ctrl *hdmi_ctrl = (struct hdmi_tx_ctrl *)data;
+
+ if (!hdmi_ctrl || !hdmi_ctrl->hpd_initialized) {
+ DEV_WARN("%s: invalid input data, ISR ignored\n", __func__);
+ return IRQ_HANDLED;
+ }
+
+ io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
+ if (!io->base) {
+ DEV_WARN("%s: io not initialized, ISR ignored\n", __func__);
+ return IRQ_HANDLED;
+ }
+
+ /* Process HPD Interrupt */
+ hpd_int_status = HDMI_REG_R(io->base, HDMI_HPD_INT_STATUS);
+ hpd_int_ctrl = HDMI_REG_R(io->base, HDMI_HPD_INT_CTRL);
+ if ((hpd_int_ctrl & BIT(2)) && (hpd_int_status & BIT(0))) {
+ u32 cable_detected = hpd_int_status & BIT(1);
+
+ /*
+ * Clear all interrupts, timer will turn IRQ back on
+ * Leaving the bit[2] on, else core goes off
+ * on getting HPD during power off.
+ */
+ HDMI_REG_W(io->base, HDMI_HPD_INT_CTRL, BIT(2) | BIT(0));
+
+ DEV_DBG("%s: HPD IRQ, Ctrl=%04x, State=%04x\n", __func__,
+ hpd_int_ctrl, hpd_int_status);
+
+ mutex_lock(&hdmi_ctrl->mutex);
+ hdmi_ctrl->hpd_cable_chg_detected = true;
+ hdmi_ctrl->hpd_prev_state = cable_detected ? 0 : 1;
+ hdmi_ctrl->hpd_stable = 0;
+ mutex_unlock(&hdmi_ctrl->mutex);
+
+ mod_timer(&hdmi_ctrl->hpd_state_timer, jiffies + HZ/2);
+
+ return IRQ_HANDLED;
+ }
+
+ DEV_DBG("%s: HPD<Ctrl=%04x, State=%04x>\n", __func__, hpd_int_ctrl,
+ hpd_int_status);
+
+ return IRQ_HANDLED;
+} /* hdmi_tx_isr */
+
+static void hdmi_tx_clk_deinit(struct hdmi_tx_platform_data *pdata)
+{
+ int i;
+ if (!pdata) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return;
+ }
+
+ for (i = HDMI_TX_MAX_CLK - 1; i >= 0; i--) {
+ if (pdata->clk[i])
+ clk_put(pdata->clk[i]);
+ pdata->clk[i] = NULL;
+ }
+} /* hdmi_tx_clk_deinit */
+
+static int hdmi_tx_clk_init(struct platform_device *pdev,
+ struct hdmi_tx_platform_data *pdata)
+{
+ int rc = 0;
+ struct device *dev = NULL;
+ struct clk *clk = NULL;
+
+ if (!pdev || !pdata) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return -EINVAL;
+ }
+ dev = &pdev->dev;
+
+ clk = clk_get(dev, "iface_clk");
+ rc = IS_ERR(clk);
+ if (rc) {
+ DEV_ERR("%s: ERROR: '%s' clk not found\n", __func__,
+ hdmi_tx_clk_name(HDMI_TX_AHB_CLK));
+ goto error;
+ }
+ pdata->clk[HDMI_TX_AHB_CLK] = clk;
+
+ clk = clk_get(dev, "core_clk");
+ rc = IS_ERR(clk);
+ if (rc) {
+ DEV_ERR("%s: ERROR: '%s' clk not found\n", __func__,
+ hdmi_tx_clk_name(HDMI_TX_APP_CLK));
+ goto error;
+ }
+ pdata->clk[HDMI_TX_APP_CLK] = clk;
+
+ clk = clk_get(dev, "extp_clk");
+ rc = IS_ERR(clk);
+ if (rc) {
+ DEV_ERR("%s: ERROR: '%s' clk not found\n", __func__,
+ hdmi_tx_clk_name(HDMI_TX_EXTP_CLK));
+ goto error;
+ }
+ pdata->clk[HDMI_TX_EXTP_CLK] = clk;
+
+ /*
+ * extpclk src is hdmi phy pll. This phy pll programming requires
+ * hdmi_ahb_clk. So enable it and then disable.
+ */
+ rc = clk_prepare_enable(pdata->clk[HDMI_TX_AHB_CLK]);
+ if (rc) {
+ DEV_ERR("%s: failed to enable '%s' clk\n", __func__,
+ hdmi_tx_clk_name(HDMI_TX_AHB_CLK));
+ goto error;
+ }
+ rc = hdmi_tx_clk_set_rate(pdata, HDMI_TX_EXTP_CLK,
+ HDMI_TX_EXTP_CLK_DEFAULT);
+ if (rc) {
+ DEV_ERR("%s: FAILED: '%s' clk set rate\n", __func__,
+ hdmi_tx_clk_name(HDMI_TX_EXTP_CLK));
+ clk_disable_unprepare(pdata->clk[HDMI_TX_AHB_CLK]);
+ goto error;
+ }
+ clk_disable_unprepare(pdata->clk[HDMI_TX_AHB_CLK]);
+
+ return rc;
+
+error:
+ hdmi_tx_clk_deinit(pdata);
+ return rc;
+} /* hdmi_tx_clk_init */
+
+static void hdmi_tx_dev_deinit(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+ if (!hdmi_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return;
+ }
+
+ switch_dev_unregister(&hdmi_ctrl->sdev);
+ del_timer(&hdmi_ctrl->hpd_state_timer);
+ if (hdmi_ctrl->workq)
+ destroy_workqueue(hdmi_ctrl->workq);
+ mutex_destroy(&hdmi_ctrl->mutex);
+
+ hdmi_tx_hw.ptr = NULL;
+} /* hdmi_tx_dev_deinit */
+
+static int hdmi_tx_dev_init(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+ int rc = 0;
+ struct hdmi_tx_platform_data *pdata = NULL;
+
+ if (!hdmi_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return -EINVAL;
+ }
+
+ pdata = &hdmi_ctrl->pdata;
+
+ rc = hdmi_tx_check_capability(pdata->io[HDMI_TX_QFPROM_IO].base);
+ if (rc) {
+ DEV_ERR("%s: no HDMI device\n", __func__);
+ goto fail_no_hdmi;
+ }
+
+ /* irq enable/disable will be handled in hpd on/off */
+ hdmi_tx_hw.ptr = (void *)hdmi_ctrl;
+
+ hdmi_tx_setup_video_mode_lut();
+ mutex_init(&hdmi_ctrl->mutex);
+ hdmi_ctrl->workq = create_workqueue("hdmi_tx_workq");
+ if (!hdmi_ctrl->workq) {
+ DEV_ERR("%s: hdmi_tx_workq creation failed.\n", __func__);
+ goto fail_create_workq;
+ }
+
+ INIT_WORK(&hdmi_ctrl->hpd_state_work, hdmi_tx_hpd_state_work);
+ init_timer(&hdmi_ctrl->hpd_state_timer);
+ hdmi_ctrl->hpd_state_timer.function = hdmi_tx_hpd_state_timer;
+ hdmi_ctrl->hpd_state_timer.data = (u32)hdmi_ctrl;
+ hdmi_ctrl->hpd_state_timer.expires = 0xffffffffL;
+
+ hdmi_ctrl->sdev.name = "hdmi";
+ if (switch_dev_register(&hdmi_ctrl->sdev) < 0) {
+ DEV_ERR("%s: Hdmi switch registration failed\n", __func__);
+ goto fail_switch_dev;
+ }
+
+ return 0;
+
+fail_switch_dev:
+ del_timer(&hdmi_ctrl->hpd_state_timer);
+fail_create_workq:
+ if (hdmi_ctrl->workq)
+ destroy_workqueue(hdmi_ctrl->workq);
+ mutex_destroy(&hdmi_ctrl->mutex);
+fail_no_hdmi:
+ return rc;
+} /* hdmi_tx_dev_init */
+
+static int hdmi_tx_register_panel(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+ int rc = 0;
+
+ if (!hdmi_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return -EINVAL;
+ }
+
+ hdmi_ctrl->panel_data.on = hdmi_tx_power_on;
+ hdmi_ctrl->panel_data.off = hdmi_tx_power_off;
+
+ hdmi_ctrl->video_resolution = HDMI_VFRMT_1920x1080p60_16_9;
+ rc = hdmi_tx_init_panel_info(hdmi_ctrl->video_resolution,
+ &hdmi_ctrl->panel_data.panel_info);
+ if (rc) {
+ DEV_ERR("%s: hdmi_init_panel_info failed\n", __func__);
+ return rc;
+ }
+
+ rc = mdss_register_panel(&hdmi_ctrl->panel_data);
+ if (rc) {
+ DEV_ERR("%s: FAILED: to register HDMI panel\n", __func__);
+ return rc;
+ }
+
+ return rc;
+} /* hdmi_tx_register_panel */
+
+static void hdmi_tx_put_dt_vreg_data(struct device *dev,
+ struct dss_module_power *module_power)
+{
+ if (!module_power) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return;
+ }
+
+ if (module_power->vreg_config) {
+ devm_kfree(dev, module_power->vreg_config);
+ module_power->vreg_config = NULL;
+ }
+ module_power->num_vreg = 0;
+} /* hdmi_tx_put_dt_vreg_data */
+
+static int hdmi_tx_get_dt_vreg_data(struct device *dev,
+ struct dss_module_power *mp, u32 module_type)
+{
+ int i, j, rc = 0;
+ int dt_vreg_total = 0, mod_vreg_total = 0;
+ u32 ndx_mask = 0;
+ u32 *val_array = NULL;
+ const char *mod_name = NULL;
+ struct device_node *of_node = NULL;
+ char prop_name[32];
+
+ if (!dev || !mp) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ rc = -EINVAL;
+ goto error;
+ }
+
+ switch (module_type) {
+ case HDMI_TX_HPD_PM:
+ mod_name = "hpd";
+ break;
+ case HDMI_TX_CORE_PM:
+ mod_name = "core";
+ break;
+ case HDMI_TX_CEC_PM:
+ mod_name = "cec";
+ break;
+ default:
+ DEV_ERR("%s: invalid module type=%d\n", __func__,
+ module_type);
+ return -EINVAL;
+ }
+
+ DEV_DBG("%s: module: '%s'\n", __func__, hdmi_pm_name(module_type));
+
+ of_node = dev->of_node;
+
+ memset(prop_name, 0, sizeof(prop_name));
+ snprintf(prop_name, 32, "%s-%s", COMPATIBLE_NAME, "supply-names");
+ dt_vreg_total = of_property_count_strings(of_node, prop_name);
+ if (dt_vreg_total < 0) {
+ DEV_ERR("%s: vreg not found. rc=%d\n", __func__,
+ dt_vreg_total);
+ rc = dt_vreg_total;
+ goto error;
+ }
+
+ /* count how many vreg for particular hdmi module */
+ for (i = 0; i < dt_vreg_total; i++) {
+ const char *st = NULL;
+ memset(prop_name, 0, sizeof(prop_name));
+ snprintf(prop_name, 32, "%s-%s", COMPATIBLE_NAME,
+ "supply-names");
+ rc = of_property_read_string_index(of_node,
+ prop_name, i, &st);
+ if (rc) {
+ DEV_ERR("%s: error reading name. i=%d, rc=%d\n",
+ __func__, i, rc);
+ goto error;
+ }
+
+ if (strnstr(st, mod_name, strlen(st))) {
+ ndx_mask |= BIT(i);
+ mod_vreg_total++;
+ }
+ }
+
+ if (mod_vreg_total > 0) {
+ mp->num_vreg = mod_vreg_total;
+ mp->vreg_config = devm_kzalloc(dev, sizeof(struct dss_vreg) *
+ mod_vreg_total, GFP_KERNEL);
+ if (!mp->vreg_config) {
+ DEV_ERR("%s: can't alloc '%s' vreg mem\n", __func__,
+ hdmi_pm_name(module_type));
+ goto error;
+ }
+ } else {
+ DEV_DBG("%s: no vreg\n", __func__);
+ return 0;
+ }
+
+ val_array = devm_kzalloc(dev, sizeof(u32) * dt_vreg_total, GFP_KERNEL);
+ if (!val_array) {
+ DEV_ERR("%s: can't allocate vreg scratch mem\n", __func__);
+ rc = -ENOMEM;
+ goto error;
+ }
+
+ for (i = 0, j = 0; (i < dt_vreg_total) && (j < mod_vreg_total); i++) {
+ const char *st = NULL;
+
+ if (!(ndx_mask & BIT(0))) {
+ ndx_mask >>= 1;
+ continue;
+ }
+
+ /* vreg-name */
+ memset(prop_name, 0, sizeof(prop_name));
+ snprintf(prop_name, 32, "%s-%s", COMPATIBLE_NAME,
+ "supply-names");
+ rc = of_property_read_string_index(of_node,
+ prop_name, i, &st);
+ if (rc) {
+ DEV_ERR("%s: error reading name. i=%d, rc=%d\n",
+ __func__, i, rc);
+ goto error;
+ }
+ snprintf(mp->vreg_config[j].vreg_name, 32, "%s", st);
+
+ /* vreg-type */
+ memset(prop_name, 0, sizeof(prop_name));
+ snprintf(prop_name, 32, "%s-%s", COMPATIBLE_NAME,
+ "supply-type");
+ memset(val_array, 0, sizeof(u32) * dt_vreg_total);
+ rc = of_property_read_u32_array(of_node,
+ prop_name, val_array, dt_vreg_total);
+ if (rc) {
+ DEV_ERR("%s: error read '%s' vreg type. rc=%d\n",
+ __func__, hdmi_pm_name(module_type), rc);
+ goto error;
+ }
+ mp->vreg_config[j].type = val_array[i];
+
+ /* vreg-min-voltage */
+ memset(prop_name, 0, sizeof(prop_name));
+ snprintf(prop_name, 32, "%s-%s", COMPATIBLE_NAME,
+ "min-voltage-level");
+ memset(val_array, 0, sizeof(u32) * dt_vreg_total);
+ rc = of_property_read_u32_array(of_node,
+ prop_name, val_array,
+ dt_vreg_total);
+ if (rc) {
+ DEV_ERR("%s: error read '%s' min volt. rc=%d\n",
+ __func__, hdmi_pm_name(module_type), rc);
+ goto error;
+ }
+ mp->vreg_config[j].min_voltage = val_array[i];
+
+ /* vreg-max-voltage */
+ memset(prop_name, 0, sizeof(prop_name));
+ snprintf(prop_name, 32, "%s-%s", COMPATIBLE_NAME,
+ "max-voltage-level");
+ memset(val_array, 0, sizeof(u32) * dt_vreg_total);
+ rc = of_property_read_u32_array(of_node,
+ prop_name, val_array,
+ dt_vreg_total);
+ if (rc) {
+ DEV_ERR("%s: error read '%s' max volt. rc=%d\n",
+ __func__, hdmi_pm_name(module_type), rc);
+ goto error;
+ }
+ mp->vreg_config[j].max_voltage = val_array[i];
+
+ /* vreg-op-mode */
+ memset(prop_name, 0, sizeof(prop_name));
+ snprintf(prop_name, 32, "%s-%s", COMPATIBLE_NAME,
+ "op-mode");
+ memset(val_array, 0, sizeof(u32) * dt_vreg_total);
+ rc = of_property_read_u32_array(of_node,
+ prop_name, val_array,
+ dt_vreg_total);
+ if (rc) {
+ DEV_ERR("%s: error read '%s' min volt. rc=%d\n",
+ __func__, hdmi_pm_name(module_type), rc);
+ goto error;
+ }
+ mp->vreg_config[j].optimum_voltage = val_array[i];
+
+ DEV_DBG("%s: %s type=%d, min=%d, max=%d, op=%d\n",
+ __func__, mp->vreg_config[j].vreg_name,
+ mp->vreg_config[j].type,
+ mp->vreg_config[j].min_voltage,
+ mp->vreg_config[j].max_voltage,
+ mp->vreg_config[j].optimum_voltage);
+
+ ndx_mask >>= 1;
+ j++;
+ }
+
+ devm_kfree(dev, val_array);
+
+ return rc;
+
+error:
+ for (i = HDMI_TX_MAX_PM - 1; i >= 0; i--)
+ hdmi_tx_put_dt_vreg_data(dev, mp);
+ if (val_array)
+ devm_kfree(dev, val_array);
+ return rc;
+} /* hdmi_tx_get_dt_vreg_data */
+
+static void hdmi_tx_put_dt_gpio_data(struct device *dev,
+ struct dss_module_power *module_power)
+{
+ if (!module_power) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return;
+ }
+
+ if (module_power->gpio_config) {
+ devm_kfree(dev, module_power->gpio_config);
+ module_power->gpio_config = NULL;
+ }
+ module_power->num_gpio = 0;
+} /* hdmi_tx_put_dt_gpio_data */
+
+static int hdmi_tx_get_dt_gpio_data(struct device *dev,
+ struct dss_module_power *mp, u32 module_type)
+{
+ int i, j, rc = 0;
+ int dt_gpio_total = 0, mod_gpio_total = 0;
+ u32 ndx_mask = 0;
+ const char *mod_name = NULL;
+ struct device_node *of_node = NULL;
+ char prop_name[32];
+ snprintf(prop_name, 32, "%s-%s", COMPATIBLE_NAME, "gpio-names");
+
+ if (!dev || !mp) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ rc = -EINVAL;
+ goto error;
+ }
+
+ switch (module_type) {
+ case HDMI_TX_HPD_PM:
+ mod_name = "hpd";
+ break;
+ case HDMI_TX_CORE_PM:
+ mod_name = "core";
+ break;
+ case HDMI_TX_CEC_PM:
+ mod_name = "cec";
+ break;
+ default:
+ DEV_ERR("%s: invalid module type=%d\n", __func__,
+ module_type);
+ return -EINVAL;
+ }
+
+ DEV_DBG("%s: module: '%s'\n", __func__, hdmi_pm_name(module_type));
+
+ of_node = dev->of_node;
+
+ dt_gpio_total = of_gpio_count(of_node);
+ if (dt_gpio_total < 0) {
+ DEV_ERR("%s: gpio not found. rc=%d\n", __func__,
+ dt_gpio_total);
+ rc = dt_gpio_total;
+ goto error;
+ }
+
+ /* count how many gpio for particular hdmi module */
+ for (i = 0; i < dt_gpio_total; i++) {
+ const char *st = NULL;
+
+ rc = of_property_read_string_index(of_node,
+ prop_name, i, &st);
+ if (rc) {
+ DEV_ERR("%s: error reading name. i=%d, rc=%d\n",
+ __func__, i, rc);
+ goto error;
+ }
+
+ if (strnstr(st, mod_name, strlen(st))) {
+ ndx_mask |= BIT(i);
+ mod_gpio_total++;
+ continue;
+ }
+ }
+
+ if (mod_gpio_total > 0) {
+ mp->num_gpio = mod_gpio_total;
+ mp->gpio_config = devm_kzalloc(dev, sizeof(struct dss_gpio) *
+ mod_gpio_total, GFP_KERNEL);
+ if (!mp->gpio_config) {
+ DEV_ERR("%s: can't alloc '%s' gpio mem\n", __func__,
+ hdmi_pm_name(module_type));
+ goto error;
+ }
+ } else {
+ DEV_DBG("%s: no gpio\n", __func__);
+ return 0;
+ }
+
+
+ for (i = 0, j = 0; (i < dt_gpio_total) && (j < mod_gpio_total); i++) {
+ const char *st = NULL;
+
+ if (!(ndx_mask & BIT(0))) {
+ ndx_mask >>= 1;
+ continue;
+ }
+
+ /* gpio-name */
+ rc = of_property_read_string_index(of_node,
+ prop_name, i, &st);
+ if (rc) {
+ DEV_ERR("%s: error reading name. i=%d, rc=%d\n",
+ __func__, i, rc);
+ goto error;
+ }
+ snprintf(mp->gpio_config[j].gpio_name, 32, "%s", st);
+
+ /* gpio-number */
+ mp->gpio_config[j].gpio = of_get_gpio(of_node, i);
+
+ DEV_DBG("%s: gpio num=%d, name=%s\n", __func__,
+ mp->gpio_config[j].gpio,
+ mp->gpio_config[j].gpio_name);
+
+ ndx_mask >>= 1;
+ j++;
+ }
+
+ return rc;
+
+error:
+ for (i = HDMI_TX_MAX_PM - 1; i >= 0; i--)
+ hdmi_tx_put_dt_gpio_data(dev, mp);
+
+ return rc;
+} /* hdmi_tx_get_dt_gpio_data */
+
+static struct resource *hdmi_tx_get_res_byname(struct platform_device *pdev,
+ unsigned int type, const char *name)
+{
+ struct resource *res = NULL;
+
+ res = platform_get_resource_byname(pdev, type, name);
+ if (!res)
+ DEV_ERR("%s: '%s' resource not found\n", __func__, name);
+
+ return res;
+} /* hdmi_tx_get_res_byname */
+
+static int hdmi_tx_ioremap_byname(struct platform_device *pdev,
+ struct hdmi_tx_io_data *io_data, u32 io_type)
+{
+ struct resource *res = NULL;
+
+ if (!pdev) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return -EINVAL;
+ }
+
+ res = hdmi_tx_get_res_byname(pdev, IORESOURCE_MEM,
+ hdmi_tx_io_name(io_type));
+ if (!res) {
+ DEV_ERR("%s: '%s' hdmi_tx_get_res_byname failed\n", __func__,
+ hdmi_tx_io_name(io_type));
+ return -ENODEV;
+ }
+
+ io_data->len = resource_size(res);
+ io_data->base = ioremap(res->start, io_data->len);
+ if (!io_data->base) {
+ DEV_ERR("%s: '%s' ioremap failed\n", __func__,
+ hdmi_tx_io_name(io_type));
+ return -EIO;
+ }
+
+ return 0;
+} /* hdmi_tx_ioremap_byname */
+
+static void hdmi_tx_put_dt_data(struct device *dev,
+ struct hdmi_tx_platform_data *pdata)
+{
+ int i;
+ if (!dev || !pdata) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return;
+ }
+
+ hdmi_tx_clk_deinit(pdata);
+
+ for (i = HDMI_TX_MAX_PM - 1; i >= 0; i--)
+ hdmi_tx_put_dt_vreg_data(dev, &pdata->power_data[i]);
+
+ for (i = HDMI_TX_MAX_PM - 1; i >= 0; i--)
+ hdmi_tx_put_dt_gpio_data(dev, &pdata->power_data[i]);
+
+ for (i = HDMI_TX_MAX_IO - 1; i >= 0; i--) {
+ if (pdata->io[i].base)
+ iounmap(pdata->io[i].base);
+ pdata->io[i].base = NULL;
+ pdata->io[i].len = 0;
+ }
+} /* hdmi_tx_put_dt_data */
+
+static int hdmi_tx_get_dt_data(struct platform_device *pdev,
+ struct hdmi_tx_platform_data *pdata)
+{
+ int i, rc = 0;
+ struct device_node *of_node = NULL;
+
+ if (!pdev || !pdata) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return -EINVAL;
+ }
+
+ of_node = pdev->dev.of_node;
+
+ rc = of_property_read_u32(of_node, "cell-index", &pdev->id);
+ if (rc) {
+ DEV_ERR("%s: dev id from dt not found.rc=%d\n",
+ __func__, rc);
+ goto error;
+ }
+ DEV_DBG("%s: id=%d\n", __func__, pdev->id);
+
+ /* IO */
+ for (i = 0; i < HDMI_TX_MAX_IO; i++) {
+ rc = hdmi_tx_ioremap_byname(pdev, &pdata->io[i], i);
+ if (rc) {
+ DEV_ERR("%s: '%s' remap failed\n", __func__,
+ hdmi_tx_io_name(i));
+ goto error;
+ }
+ DEV_INFO("%s: '%s': start = 0x%x, len=0x%x\n", __func__,
+ hdmi_tx_io_name(i), (u32)pdata->io[i].base,
+ pdata->io[i].len);
+ }
+
+ /* GPIO */
+ for (i = 0; i < HDMI_TX_MAX_PM; i++) {
+ rc = hdmi_tx_get_dt_gpio_data(&pdev->dev,
+ &pdata->power_data[i], i);
+ if (rc) {
+ DEV_ERR("%s: '%s' get_dt_gpio_data failed.rc=%d\n",
+ __func__, hdmi_pm_name(i), rc);
+ goto error;
+ }
+ }
+
+ /* VREG */
+ for (i = 0; i < HDMI_TX_MAX_PM; i++) {
+ rc = hdmi_tx_get_dt_vreg_data(&pdev->dev,
+ &pdata->power_data[i], i);
+ if (rc) {
+ DEV_ERR("%s: '%s' get_dt_vreg_data failed.rc=%d\n",
+ __func__, hdmi_pm_name(i), rc);
+ goto error;
+ }
+ }
+
+ /* CLK */
+ rc = hdmi_tx_clk_init(pdev, pdata);
+ if (rc) {
+ DEV_ERR("%s: FAILED: clk init. rc=%d\n", __func__, rc);
+ goto error;
+ }
+
+ return rc;
+
+error:
+ hdmi_tx_put_dt_data(&pdev->dev, pdata);
+ return rc;
+} /* hdmi_tx_get_dt_data */
+
+static int __devinit hdmi_tx_probe(struct platform_device *pdev)
+{
+ int rc = 0;
+ struct device_node *of_node = pdev->dev.of_node;
+ struct hdmi_tx_ctrl *hdmi_ctrl = NULL;
+
+ if (!of_node) {
+ DEV_ERR("%s: FAILED: of_node not found\n", __func__);
+ rc = -ENODEV;
+ return rc;
+ }
+
+ hdmi_ctrl = devm_kzalloc(&pdev->dev, sizeof(*hdmi_ctrl), GFP_KERNEL);
+ if (!hdmi_ctrl) {
+ DEV_ERR("%s: FAILED: cannot alloc hdmi tx ctrl\n", __func__);
+ rc = -ENOMEM;
+ goto failed_no_mem;
+ }
+
+ platform_set_drvdata(pdev, hdmi_ctrl);
+ hdmi_ctrl->pdev = pdev;
+
+ rc = hdmi_tx_get_dt_data(pdev, &hdmi_ctrl->pdata);
+ if (rc) {
+ DEV_ERR("%s: FAILED: parsing device tree data. rc=%d\n",
+ __func__, rc);
+ goto failed_dt_data;
+ }
+
+ rc = hdmi_tx_dev_init(hdmi_ctrl);
+ if (rc) {
+ DEV_ERR("%s: FAILED: hdmi_tx_dev_init. rc=%d\n", __func__, rc);
+ goto failed_dev_init;
+ }
+
+ rc = hdmi_tx_register_panel(hdmi_ctrl);
+ if (rc) {
+ DEV_ERR("%s: FAILED: register_panel. rc=%d\n", __func__, rc);
+ goto failed_reg_panel;
+ }
+
+ return rc;
+
+failed_reg_panel:
+ hdmi_tx_dev_deinit(hdmi_ctrl);
+failed_dev_init:
+ hdmi_tx_put_dt_data(&pdev->dev, &hdmi_ctrl->pdata);
+failed_dt_data:
+ devm_kfree(&pdev->dev, hdmi_ctrl);
+failed_no_mem:
+ return rc;
+} /* hdmi_tx_probe */
+
+static int __devexit hdmi_tx_remove(struct platform_device *pdev)
+{
+ struct hdmi_tx_ctrl *hdmi_ctrl = platform_get_drvdata(pdev);
+ if (!hdmi_ctrl) {
+ DEV_ERR("%s: no driver data\n", __func__);
+ return -ENODEV;
+ }
+
+ hdmi_tx_dev_deinit(hdmi_ctrl);
+ hdmi_tx_put_dt_data(&pdev->dev, &hdmi_ctrl->pdata);
+ devm_kfree(&hdmi_ctrl->pdev->dev, hdmi_ctrl);
+
+ return 0;
+} /* hdmi_tx_remove */
+
+static const struct of_device_id hdmi_tx_dt_match[] = {
+ {.compatible = COMPATIBLE_NAME,},
+};
+MODULE_DEVICE_TABLE(of, hdmi_tx_dt_match);
+
+static struct platform_driver this_driver = {
+ .probe = hdmi_tx_probe,
+ .remove = hdmi_tx_remove,
+ .driver = {
+ .name = DRV_NAME,
+ .of_match_table = hdmi_tx_dt_match,
+ },
+};
+
+static int __init hdmi_tx_drv_init(void)
+{
+ int rc;
+
+ rc = platform_driver_register(&this_driver);
+ if (rc)
+ DEV_ERR("%s: FAILED: rc=%d\n", __func__, rc);
+
+ return rc;
+} /* hdmi_tx_drv_init */
+
+static void __exit hdmi_tx_drv_exit(void)
+{
+ platform_driver_unregister(&this_driver);
+} /* hdmi_tx_drv_exit */
+
+module_init(hdmi_tx_drv_init);
+module_exit(hdmi_tx_drv_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION("0.3");
+MODULE_DESCRIPTION("HDMI MSM TX driver");
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.h b/drivers/video/msm/mdss/mdss_hdmi_tx.h
new file mode 100644
index 0000000..2e175ee
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.h
@@ -0,0 +1,93 @@
+/* Copyright (c) 2010-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 __MDSS_HDMI_TX_H__
+#define __MDSS_HDMI_TX_H__
+
+#include <linux/switch.h>
+#include "mdss_hdmi_util.h"
+#include "mdss_io_util.h"
+
+#define HDMI_TX_EXTP_CLK_DEFAULT 148500000
+#define HDMI_TX_EXTP_CLK_LOW 148500000
+#define HDMI_TX_EXTP_CLK_NOMINAL 297000000
+#define HDMI_TX_EXTP_CLK_TURBO 297000000 /* ToDo: Find correct value */
+
+enum hdmi_tx_clk_type {
+ HDMI_TX_AHB_CLK,
+ HDMI_TX_APP_CLK,
+ HDMI_TX_EXTP_CLK,
+ HDMI_TX_MAX_CLK
+};
+
+enum hdmi_tx_io_type {
+ HDMI_TX_CORE_IO,
+ HDMI_TX_PHY_IO,
+ HDMI_TX_QFPROM_IO,
+ HDMI_TX_MAX_IO
+};
+
+enum hdmi_tx_power_module_type {
+ HDMI_TX_HPD_PM,
+ HDMI_TX_CORE_PM,
+ HDMI_TX_CEC_PM,
+ HDMI_TX_MAX_PM
+};
+
+struct hdmi_tx_io_data {
+ u32 len;
+ void __iomem *base;
+};
+
+struct hdmi_tx_platform_data {
+ /* Data filled from device tree nodes */
+ struct hdmi_tx_io_data io[HDMI_TX_MAX_IO];
+ struct dss_module_power power_data[HDMI_TX_MAX_PM];
+
+ /* clk and regulator handles */
+ struct clk *clk[HDMI_TX_MAX_CLK];
+};
+
+struct hdmi_tx_ctrl {
+ struct platform_device *pdev;
+ struct hdmi_tx_platform_data pdata;
+ struct mdss_panel_data panel_data;
+
+ struct mutex mutex;
+ struct kobject *kobj;
+ struct switch_dev sdev;
+ struct workqueue_struct *workq;
+
+ uint32_t video_resolution;
+ u32 panel_power_on;
+
+ u32 hpd_initialized;
+ int hpd_stable;
+ u32 hpd_prev_state;
+ u32 hpd_cable_chg_detected;
+ u32 hpd_state;
+ u32 hpd_feature_on;
+ struct work_struct hpd_state_work;
+ struct timer_list hpd_state_timer;
+
+ unsigned long pixel_clk;
+ u32 xres;
+ u32 yres;
+ u32 frame_rate;
+
+ u32 present_hdcp;
+
+ u8 spd_vendor_name[8];
+ u8 spd_product_description[16];
+};
+
+#endif /* __MDSS_HDMI_TX_H__ */
diff --git a/drivers/video/msm/mdss/mdss_hdmi_util.c b/drivers/video/msm/mdss/mdss_hdmi_util.c
new file mode 100644
index 0000000..e86f32b
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_hdmi_util.c
@@ -0,0 +1,485 @@
+/* Copyright (c) 2010-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/io.h>
+#include <mach/board.h>
+#include "mdss_hdmi_util.h"
+
+const char *hdmi_reg_name(u32 offset)
+{
+ switch (offset) {
+ case 0x00000000: return "HDMI_CTRL";
+ case 0x00000010: return "HDMI_TEST_PATTERN";
+ case 0x00000014: return "HDMI_RANDOM_PATTERN";
+ case 0x00000018: return "HDMI_PKT_BLK_CTRL";
+ case 0x0000001C: return "HDMI_STATUS";
+ case 0x00000020: return "HDMI_AUDIO_PKT_CTRL";
+ case 0x00000024: return "HDMI_ACR_PKT_CTRL";
+ case 0x00000028: return "HDMI_VBI_PKT_CTRL";
+ case 0x0000002C: return "HDMI_INFOFRAME_CTRL0";
+ case 0x00000030: return "HDMI_INFOFRAME_CTRL1";
+ case 0x00000034: return "HDMI_GEN_PKT_CTRL";
+ case 0x0000003C: return "HDMI_ACP";
+ case 0x00000040: return "HDMI_GC";
+ case 0x00000044: return "HDMI_AUDIO_PKT_CTRL2";
+ case 0x00000048: return "HDMI_ISRC1_0";
+ case 0x0000004C: return "HDMI_ISRC1_1";
+ case 0x00000050: return "HDMI_ISRC1_2";
+ case 0x00000054: return "HDMI_ISRC1_3";
+ case 0x00000058: return "HDMI_ISRC1_4";
+ case 0x0000005C: return "HDMI_ISRC2_0";
+ case 0x00000060: return "HDMI_ISRC2_1";
+ case 0x00000064: return "HDMI_ISRC2_2";
+ case 0x00000068: return "HDMI_ISRC2_3";
+ case 0x0000006C: return "HDMI_AVI_INFO0";
+ case 0x00000070: return "HDMI_AVI_INFO1";
+ case 0x00000074: return "HDMI_AVI_INFO2";
+ case 0x00000078: return "HDMI_AVI_INFO3";
+ case 0x0000007C: return "HDMI_MPEG_INFO0";
+ case 0x00000080: return "HDMI_MPEG_INFO1";
+ case 0x00000084: return "HDMI_GENERIC0_HDR";
+ case 0x00000088: return "HDMI_GENERIC0_0";
+ case 0x0000008C: return "HDMI_GENERIC0_1";
+ case 0x00000090: return "HDMI_GENERIC0_2";
+ case 0x00000094: return "HDMI_GENERIC0_3";
+ case 0x00000098: return "HDMI_GENERIC0_4";
+ case 0x0000009C: return "HDMI_GENERIC0_5";
+ case 0x000000A0: return "HDMI_GENERIC0_6";
+ case 0x000000A4: return "HDMI_GENERIC1_HDR";
+ case 0x000000A8: return "HDMI_GENERIC1_0";
+ case 0x000000AC: return "HDMI_GENERIC1_1";
+ case 0x000000B0: return "HDMI_GENERIC1_2";
+ case 0x000000B4: return "HDMI_GENERIC1_3";
+ case 0x000000B8: return "HDMI_GENERIC1_4";
+ case 0x000000BC: return "HDMI_GENERIC1_5";
+ case 0x000000C0: return "HDMI_GENERIC1_6";
+ case 0x000000C4: return "HDMI_ACR_32_0";
+ case 0x000000C8: return "HDMI_ACR_32_1";
+ case 0x000000CC: return "HDMI_ACR_44_0";
+ case 0x000000D0: return "HDMI_ACR_44_1";
+ case 0x000000D4: return "HDMI_ACR_48_0";
+ case 0x000000D8: return "HDMI_ACR_48_1";
+ case 0x000000DC: return "HDMI_ACR_STATUS_0";
+ case 0x000000E0: return "HDMI_ACR_STATUS_1";
+ case 0x000000E4: return "HDMI_AUDIO_INFO0";
+ case 0x000000E8: return "HDMI_AUDIO_INFO1";
+ case 0x000000EC: return "HDMI_CS_60958_0";
+ case 0x000000F0: return "HDMI_CS_60958_1";
+ case 0x000000F8: return "HDMI_RAMP_CTRL0";
+ case 0x000000FC: return "HDMI_RAMP_CTRL1";
+ case 0x00000100: return "HDMI_RAMP_CTRL2";
+ case 0x00000104: return "HDMI_RAMP_CTRL3";
+ case 0x00000108: return "HDMI_CS_60958_2";
+ case 0x00000110: return "HDMI_HDCP_CTRL";
+ case 0x00000114: return "HDMI_HDCP_DEBUG_CTRL";
+ case 0x00000118: return "HDMI_HDCP_INT_CTRL";
+ case 0x0000011C: return "HDMI_HDCP_LINK0_STATUS";
+ case 0x00000120: return "HDMI_HDCP_DDC_CTRL_0";
+ case 0x00000124: return "HDMI_HDCP_DDC_CTRL_1";
+ case 0x00000128: return "HDMI_HDCP_DDC_STATUS";
+ case 0x0000012C: return "HDMI_HDCP_ENTROPY_CTRL0";
+ case 0x00000130: return "HDMI_HDCP_RESET";
+ case 0x00000134: return "HDMI_HDCP_RCVPORT_DATA0";
+ case 0x00000138: return "HDMI_HDCP_RCVPORT_DATA1";
+ case 0x0000013C: return "HDMI_HDCP_RCVPORT_DATA2_0";
+ case 0x00000140: return "HDMI_HDCP_RCVPORT_DATA2_1";
+ case 0x00000144: return "HDMI_HDCP_RCVPORT_DATA3";
+ case 0x00000148: return "HDMI_HDCP_RCVPORT_DATA4";
+ case 0x0000014C: return "HDMI_HDCP_RCVPORT_DATA5";
+ case 0x00000150: return "HDMI_HDCP_RCVPORT_DATA6";
+ case 0x00000154: return "HDMI_HDCP_RCVPORT_DATA7";
+ case 0x00000158: return "HDMI_HDCP_RCVPORT_DATA8";
+ case 0x0000015C: return "HDMI_HDCP_RCVPORT_DATA9";
+ case 0x00000160: return "HDMI_HDCP_RCVPORT_DATA10";
+ case 0x00000164: return "HDMI_HDCP_RCVPORT_DATA11";
+ case 0x00000168: return "HDMI_HDCP_RCVPORT_DATA12";
+ case 0x0000016C: return "HDMI_VENSPEC_INFO0";
+ case 0x00000170: return "HDMI_VENSPEC_INFO1";
+ case 0x00000174: return "HDMI_VENSPEC_INFO2";
+ case 0x00000178: return "HDMI_VENSPEC_INFO3";
+ case 0x0000017C: return "HDMI_VENSPEC_INFO4";
+ case 0x00000180: return "HDMI_VENSPEC_INFO5";
+ case 0x00000184: return "HDMI_VENSPEC_INFO6";
+ case 0x00000194: return "HDMI_HDCP_DEBUG";
+ case 0x0000019C: return "HDMI_TMDS_CTRL_CHAR";
+ case 0x000001A4: return "HDMI_TMDS_CTRL_SEL";
+ case 0x000001A8: return "HDMI_TMDS_SYNCCHAR01";
+ case 0x000001AC: return "HDMI_TMDS_SYNCCHAR23";
+ case 0x000001B4: return "HDMI_TMDS_DEBUG";
+ case 0x000001B8: return "HDMI_TMDS_CTL_BITS";
+ case 0x000001BC: return "HDMI_TMDS_DCBAL_CTRL";
+ case 0x000001C0: return "HDMI_TMDS_DCBAL_CHAR";
+ case 0x000001C8: return "HDMI_TMDS_CTL01_GEN";
+ case 0x000001CC: return "HDMI_TMDS_CTL23_GEN";
+ case 0x000001D0: return "HDMI_AUDIO_CFG";
+ case 0x00000204: return "HDMI_DEBUG";
+ case 0x00000208: return "HDMI_USEC_REFTIMER";
+ case 0x0000020C: return "HDMI_DDC_CTRL";
+ case 0x00000210: return "HDMI_DDC_ARBITRATION";
+ case 0x00000214: return "HDMI_DDC_INT_CTRL";
+ case 0x00000218: return "HDMI_DDC_SW_STATUS";
+ case 0x0000021C: return "HDMI_DDC_HW_STATUS";
+ case 0x00000220: return "HDMI_DDC_SPEED";
+ case 0x00000224: return "HDMI_DDC_SETUP";
+ case 0x00000228: return "HDMI_DDC_TRANS0";
+ case 0x0000022C: return "HDMI_DDC_TRANS1";
+ case 0x00000230: return "HDMI_DDC_TRANS2";
+ case 0x00000234: return "HDMI_DDC_TRANS3";
+ case 0x00000238: return "HDMI_DDC_DATA";
+ case 0x0000023C: return "HDMI_HDCP_SHA_CTRL";
+ case 0x00000240: return "HDMI_HDCP_SHA_STATUS";
+ case 0x00000244: return "HDMI_HDCP_SHA_DATA";
+ case 0x00000248: return "HDMI_HDCP_SHA_DBG_M0_0";
+ case 0x0000024C: return "HDMI_HDCP_SHA_DBG_M0_1";
+ case 0x00000250: return "HDMI_HPD_INT_STATUS";
+ case 0x00000254: return "HDMI_HPD_INT_CTRL";
+ case 0x00000258: return "HDMI_HPD_CTRL";
+ case 0x0000025C: return "HDMI_HDCP_ENTROPY_CTRL1";
+ case 0x00000260: return "HDMI_HDCP_SW_UPPER_AN";
+ case 0x00000264: return "HDMI_HDCP_SW_LOWER_AN";
+ case 0x00000268: return "HDMI_CRC_CTRL";
+ case 0x0000026C: return "HDMI_VID_CRC";
+ case 0x00000270: return "HDMI_AUD_CRC";
+ case 0x00000274: return "HDMI_VBI_CRC";
+ case 0x0000027C: return "HDMI_DDC_REF";
+ case 0x00000284: return "HDMI_HDCP_SW_UPPER_AKSV";
+ case 0x00000288: return "HDMI_HDCP_SW_LOWER_AKSV";
+ case 0x0000028C: return "HDMI_CEC_CTRL";
+ case 0x00000290: return "HDMI_CEC_WR_DATA";
+ case 0x00000294: return "HDMI_CEC_RETRANSMIT";
+ case 0x00000298: return "HDMI_CEC_STATUS";
+ case 0x0000029C: return "HDMI_CEC_INT";
+ case 0x000002A0: return "HDMI_CEC_ADDR";
+ case 0x000002A4: return "HDMI_CEC_TIME";
+ case 0x000002A8: return "HDMI_CEC_REFTIMER";
+ case 0x000002AC: return "HDMI_CEC_RD_DATA";
+ case 0x000002B0: return "HDMI_CEC_RD_FILTER";
+ case 0x000002B4: return "HDMI_ACTIVE_H";
+ case 0x000002B8: return "HDMI_ACTIVE_V";
+ case 0x000002BC: return "HDMI_ACTIVE_V_F2";
+ case 0x000002C0: return "HDMI_TOTAL";
+ case 0x000002C4: return "HDMI_V_TOTAL_F2";
+ case 0x000002C8: return "HDMI_FRAME_CTRL";
+ case 0x000002CC: return "HDMI_AUD_INT";
+ case 0x000002D0: return "HDMI_DEBUG_BUS_CTRL";
+ case 0x000002D4: return "HDMI_PHY_CTRL";
+ case 0x000002DC: return "HDMI_CEC_WR_RANGE";
+ case 0x000002E0: return "HDMI_CEC_RD_RANGE";
+ case 0x000002E4: return "HDMI_VERSION";
+ case 0x000002F4: return "HDMI_BIST_ENABLE";
+ case 0x000002F8: return "HDMI_TIMING_ENGINE_EN";
+ case 0x000002FC: return "HDMI_INTF_CONFIG";
+ case 0x00000300: return "HDMI_HSYNC_CTL";
+ case 0x00000304: return "HDMI_VSYNC_PERIOD_F0";
+ case 0x00000308: return "HDMI_VSYNC_PERIOD_F1";
+ case 0x0000030C: return "HDMI_VSYNC_PULSE_WIDTH_F0";
+ case 0x00000310: return "HDMI_VSYNC_PULSE_WIDTH_F1";
+ case 0x00000314: return "HDMI_DISPLAY_V_START_F0";
+ case 0x00000318: return "HDMI_DISPLAY_V_START_F1";
+ case 0x0000031C: return "HDMI_DISPLAY_V_END_F0";
+ case 0x00000320: return "HDMI_DISPLAY_V_END_F1";
+ case 0x00000324: return "HDMI_ACTIVE_V_START_F0";
+ case 0x00000328: return "HDMI_ACTIVE_V_START_F1";
+ case 0x0000032C: return "HDMI_ACTIVE_V_END_F0";
+ case 0x00000330: return "HDMI_ACTIVE_V_END_F1";
+ case 0x00000334: return "HDMI_DISPLAY_HCTL";
+ case 0x00000338: return "HDMI_ACTIVE_HCTL";
+ case 0x0000033C: return "HDMI_HSYNC_SKEW";
+ case 0x00000340: return "HDMI_POLARITY_CTL";
+ case 0x00000344: return "HDMI_TPG_MAIN_CONTROL";
+ case 0x00000348: return "HDMI_TPG_VIDEO_CONFIG";
+ case 0x0000034C: return "HDMI_TPG_COMPONENT_LIMITS";
+ case 0x00000350: return "HDMI_TPG_RECTANGLE";
+ case 0x00000354: return "HDMI_TPG_INITIAL_VALUE";
+ case 0x00000358: return "HDMI_TPG_BLK_WHT_PATTERN_FRAMES";
+ case 0x0000035C: return "HDMI_TPG_RGB_MAPPING";
+ default: return "???";
+ }
+} /* hdmi_reg_name */
+
+void hdmi_reg_w(void __iomem *addr, u32 offset, u32 value, u32 debug)
+{
+ u32 in_val;
+
+ writel_relaxed(value, addr+offset);
+ if (debug && PORT_DEBUG) {
+ in_val = readl_relaxed(addr+offset);
+ DEV_DBG("HDMI[%04x] => %08x [%08x] %s\n", offset, value,
+ in_val, hdmi_reg_name(offset));
+ }
+} /* hdmi_reg_w */
+
+u32 hdmi_reg_r(void __iomem *addr, u32 offset, u32 debug)
+{
+ u32 value = readl_relaxed(addr+offset);
+ if (debug && PORT_DEBUG)
+ DEV_DBG("HDMI[%04x] <= %08x %s\n", offset, value,
+ hdmi_reg_name(offset));
+ return value;
+} /* hdmi_reg_r */
+
+void hdmi_reg_dump(void __iomem *base, u32 length, const char *prefix)
+{
+ if (REG_DUMP)
+ print_hex_dump(KERN_INFO, prefix, DUMP_PREFIX_OFFSET, 32, 4,
+ (void *)base, length, false);
+} /* hdmi_reg_dump */
+
+static struct hdmi_disp_mode_timing_type
+ hdmi_supported_video_mode_lut[HDMI_VFRMT_MAX] = {
+ HDMI_SETTINGS_640x480p60_4_3,
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x480p60_4_3),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x480p60_16_9),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1280x720p60_16_9),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080i60_16_9),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480i60_4_3),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480i60_16_9),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x240p60_4_3),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x240p60_16_9),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x480i60_4_3),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x480i60_16_9),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x240p60_4_3),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x240p60_16_9),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480p60_4_3),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480p60_16_9),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080p60_16_9),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x576p50_4_3),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x576p50_16_9),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1280x720p50_16_9),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080i50_16_9),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576i50_4_3),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576i50_16_9),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x288p50_4_3),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x288p50_16_9),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x576i50_4_3),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x576i50_16_9),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x288p50_4_3),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x288p50_16_9),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576p50_4_3),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576p50_16_9),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080p50_16_9),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080p24_16_9),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080p25_16_9),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080p30_16_9),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x480p60_4_3),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x480p60_16_9),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x576p50_4_3),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x576p50_16_9),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1250i50_16_9),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080i100_16_9),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1280x720p100_16_9),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x576p100_4_3),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x576p100_16_9),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576i100_4_3),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576i100_16_9),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080i120_16_9),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1280x720p120_16_9),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x480p120_4_3),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x480p120_16_9),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480i120_4_3),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480i120_16_9),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x576p200_4_3),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x576p200_16_9),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576i200_4_3),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576i200_16_9),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x480p240_4_3),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x480p240_16_9),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480i240_4_3),
+ VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480i240_16_9),
+}; /* hdmi_supported_video_mode_lut */
+
+#define HDMI_SETUP_LUT(MODE) do { \
+ struct hdmi_disp_mode_timing_type mode = HDMI_SETTINGS_##MODE; \
+ hdmi_supported_video_mode_lut[mode.video_format] = mode; \
+ } while (0)
+
+const struct hdmi_disp_mode_timing_type *hdmi_get_supported_mode(u32 mode)
+{
+ const struct hdmi_disp_mode_timing_type *ret = NULL;
+
+ if (mode >= HDMI_VFRMT_MAX)
+ return NULL;
+
+ ret = &hdmi_supported_video_mode_lut[mode];
+
+ if (ret == NULL || !ret->supported)
+ return NULL;
+
+ return ret;
+} /* hdmi_get_supported_mode */
+
+void hdmi_set_supported_mode(u32 mode)
+{
+ switch (mode) {
+ case HDMI_VFRMT_640x480p60_4_3:
+ HDMI_SETUP_LUT(640x480p60_4_3);
+ break;
+ case HDMI_VFRMT_720x480p60_4_3:
+ HDMI_SETUP_LUT(720x480p60_4_3);
+ break;
+ case HDMI_VFRMT_720x480p60_16_9:
+ HDMI_SETUP_LUT(720x480p60_16_9);
+ break;
+ case HDMI_VFRMT_720x576p50_4_3:
+ HDMI_SETUP_LUT(720x576p50_4_3);
+ break;
+ case HDMI_VFRMT_720x576p50_16_9:
+ HDMI_SETUP_LUT(720x576p50_16_9);
+ break;
+ case HDMI_VFRMT_1440x480i60_4_3:
+ HDMI_SETUP_LUT(1440x480i60_4_3);
+ break;
+ case HDMI_VFRMT_1440x480i60_16_9:
+ HDMI_SETUP_LUT(1440x480i60_16_9);
+ break;
+ case HDMI_VFRMT_1440x576i50_4_3:
+ HDMI_SETUP_LUT(1440x576i50_4_3);
+ break;
+ case HDMI_VFRMT_1440x576i50_16_9:
+ HDMI_SETUP_LUT(1440x576i50_16_9);
+ break;
+ case HDMI_VFRMT_1280x720p50_16_9:
+ HDMI_SETUP_LUT(1280x720p50_16_9);
+ break;
+ case HDMI_VFRMT_1280x720p60_16_9:
+ HDMI_SETUP_LUT(1280x720p60_16_9);
+ break;
+ case HDMI_VFRMT_1920x1080p24_16_9:
+ HDMI_SETUP_LUT(1920x1080p24_16_9);
+ break;
+ case HDMI_VFRMT_1920x1080p25_16_9:
+ HDMI_SETUP_LUT(1920x1080p25_16_9);
+ break;
+ case HDMI_VFRMT_1920x1080p30_16_9:
+ HDMI_SETUP_LUT(1920x1080p30_16_9);
+ break;
+ case HDMI_VFRMT_1920x1080p50_16_9:
+ HDMI_SETUP_LUT(1920x1080p50_16_9);
+ break;
+ case HDMI_VFRMT_1920x1080i60_16_9:
+ HDMI_SETUP_LUT(1920x1080i60_16_9);
+ break;
+ case HDMI_VFRMT_1920x1080p60_16_9:
+ HDMI_SETUP_LUT(1920x1080p60_16_9);
+ break;
+ default:
+ DEV_ERR("%s: unsupported mode=%d\n", __func__, mode);
+ }
+} /* hdmi_set_supported_mode */
+
+const char *hdmi_get_video_fmt_2string(u32 format)
+{
+ switch (format) {
+ case HDMI_VFRMT_640x480p60_4_3: return " 640x 480 p60 4/3";
+ case HDMI_VFRMT_720x480p60_4_3: return " 720x 480 p60 4/3";
+ case HDMI_VFRMT_720x480p60_16_9: return " 720x 480 p60 16/9";
+ case HDMI_VFRMT_1280x720p60_16_9: return "1280x 720 p60 16/9";
+ case HDMI_VFRMT_1920x1080i60_16_9: return "1920x1080 i60 16/9";
+ case HDMI_VFRMT_1440x480i60_4_3: return "1440x 480 i60 4/3";
+ case HDMI_VFRMT_1440x480i60_16_9: return "1440x 480 i60 16/9";
+ case HDMI_VFRMT_1440x240p60_4_3: return "1440x 240 p60 4/3";
+ case HDMI_VFRMT_1440x240p60_16_9: return "1440x 240 p60 16/9";
+ case HDMI_VFRMT_2880x480i60_4_3: return "2880x 480 i60 4/3";
+ case HDMI_VFRMT_2880x480i60_16_9: return "2880x 480 i60 16/9";
+ case HDMI_VFRMT_2880x240p60_4_3: return "2880x 240 p60 4/3";
+ case HDMI_VFRMT_2880x240p60_16_9: return "2880x 240 p60 16/9";
+ case HDMI_VFRMT_1440x480p60_4_3: return "1440x 480 p60 4/3";
+ case HDMI_VFRMT_1440x480p60_16_9: return "1440x 480 p60 16/9";
+ case HDMI_VFRMT_1920x1080p60_16_9: return "1920x1080 p60 16/9";
+ case HDMI_VFRMT_720x576p50_4_3: return " 720x 576 p50 4/3";
+ case HDMI_VFRMT_720x576p50_16_9: return " 720x 576 p50 16/9";
+ case HDMI_VFRMT_1280x720p50_16_9: return "1280x 720 p50 16/9";
+ case HDMI_VFRMT_1920x1080i50_16_9: return "1920x1080 i50 16/9";
+ case HDMI_VFRMT_1440x576i50_4_3: return "1440x 576 i50 4/3";
+ case HDMI_VFRMT_1440x576i50_16_9: return "1440x 576 i50 16/9";
+ case HDMI_VFRMT_1440x288p50_4_3: return "1440x 288 p50 4/3";
+ case HDMI_VFRMT_1440x288p50_16_9: return "1440x 288 p50 16/9";
+ case HDMI_VFRMT_2880x576i50_4_3: return "2880x 576 i50 4/3";
+ case HDMI_VFRMT_2880x576i50_16_9: return "2880x 576 i50 16/9";
+ case HDMI_VFRMT_2880x288p50_4_3: return "2880x 288 p50 4/3";
+ case HDMI_VFRMT_2880x288p50_16_9: return "2880x 288 p50 16/9";
+ case HDMI_VFRMT_1440x576p50_4_3: return "1440x 576 p50 4/3";
+ case HDMI_VFRMT_1440x576p50_16_9: return "1440x 576 p50 16/9";
+ case HDMI_VFRMT_1920x1080p50_16_9: return "1920x1080 p50 16/9";
+ case HDMI_VFRMT_1920x1080p24_16_9: return "1920x1080 p24 16/9";
+ case HDMI_VFRMT_1920x1080p25_16_9: return "1920x1080 p25 16/9";
+ case HDMI_VFRMT_1920x1080p30_16_9: return "1920x1080 p30 16/9";
+ case HDMI_VFRMT_2880x480p60_4_3: return "2880x 480 p60 4/3";
+ case HDMI_VFRMT_2880x480p60_16_9: return "2880x 480 p60 16/9";
+ case HDMI_VFRMT_2880x576p50_4_3: return "2880x 576 p50 4/3";
+ case HDMI_VFRMT_2880x576p50_16_9: return "2880x 576 p50 16/9";
+ case HDMI_VFRMT_1920x1250i50_16_9: return "1920x1250 i50 16/9";
+ case HDMI_VFRMT_1920x1080i100_16_9:return "1920x1080 i100 16/9";
+ case HDMI_VFRMT_1280x720p100_16_9: return "1280x 720 p100 16/9";
+ case HDMI_VFRMT_720x576p100_4_3: return " 720x 576 p100 4/3";
+ case HDMI_VFRMT_720x576p100_16_9: return " 720x 576 p100 16/9";
+ case HDMI_VFRMT_1440x576i100_4_3: return "1440x 576 i100 4/3";
+ case HDMI_VFRMT_1440x576i100_16_9: return "1440x 576 i100 16/9";
+ case HDMI_VFRMT_1920x1080i120_16_9:return "1920x1080 i120 16/9";
+ case HDMI_VFRMT_1280x720p120_16_9: return "1280x 720 p120 16/9";
+ case HDMI_VFRMT_720x480p120_4_3: return " 720x 480 p120 4/3";
+ case HDMI_VFRMT_720x480p120_16_9: return " 720x 480 p120 16/9";
+ case HDMI_VFRMT_1440x480i120_4_3: return "1440x 480 i120 4/3";
+ case HDMI_VFRMT_1440x480i120_16_9: return "1440x 480 i120 16/9";
+ case HDMI_VFRMT_720x576p200_4_3: return " 720x 576 p200 4/3";
+ case HDMI_VFRMT_720x576p200_16_9: return " 720x 576 p200 16/9";
+ case HDMI_VFRMT_1440x576i200_4_3: return "1440x 576 i200 4/3";
+ case HDMI_VFRMT_1440x576i200_16_9: return "1440x 576 i200 16/9";
+ case HDMI_VFRMT_720x480p240_4_3: return " 720x 480 p240 4/3";
+ case HDMI_VFRMT_720x480p240_16_9: return " 720x 480 p240 16/9";
+ case HDMI_VFRMT_1440x480i240_4_3: return "1440x 480 i240 4/3";
+ case HDMI_VFRMT_1440x480i240_16_9: return "1440x 480 i240 16/9";
+ default: return "???";
+ }
+} /* hdmi_get_video_fmt_2string */
+
+const char *hdmi_get_single_video_3d_fmt_2string(u32 format)
+{
+ switch (format) {
+ case TOP_AND_BOTTOM: return "TAB";
+ case FRAME_PACKING: return "FP";
+ case SIDE_BY_SIDE_HALF: return "SSH";
+ }
+ return "";
+} /* hdmi_get_single_video_3d_fmt_2string */
+
+ssize_t hdmi_get_video_3d_fmt_2string(u32 format, char *buf)
+{
+ ssize_t ret, len = 0;
+ ret = snprintf(buf, PAGE_SIZE, "%s",
+ hdmi_get_single_video_3d_fmt_2string(
+ format & FRAME_PACKING));
+ len += ret;
+
+ if (len && (format & TOP_AND_BOTTOM))
+ ret = snprintf(buf + len, PAGE_SIZE, ":%s",
+ hdmi_get_single_video_3d_fmt_2string(
+ format & TOP_AND_BOTTOM));
+ else
+ ret = snprintf(buf + len, PAGE_SIZE, "%s",
+ hdmi_get_single_video_3d_fmt_2string(
+ format & TOP_AND_BOTTOM));
+ len += ret;
+
+ if (len && (format & SIDE_BY_SIDE_HALF))
+ ret = snprintf(buf + len, PAGE_SIZE, ":%s",
+ hdmi_get_single_video_3d_fmt_2string(
+ format & SIDE_BY_SIDE_HALF));
+ else
+ ret = snprintf(buf + len, PAGE_SIZE, "%s",
+ hdmi_get_single_video_3d_fmt_2string(
+ format & SIDE_BY_SIDE_HALF));
+ len += ret;
+
+ return len;
+} /* hdmi_get_video_3d_fmt_2string */
diff --git a/drivers/video/msm/mdss/mdss_hdmi_util.h b/drivers/video/msm/mdss/mdss_hdmi_util.h
new file mode 100644
index 0000000..ae6f16a
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_hdmi_util.h
@@ -0,0 +1,400 @@
+/* Copyright (c) 2010-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 __HDMI_UTIL_H__
+#define __HDMI_UTIL_H__
+
+#define DEV_INFO(fmt, args...) pr_info(fmt, ##args)
+#define DEV_WARN(fmt, args...) pr_warn(fmt, ##args)
+#define DEV_ERR(fmt, args...) pr_err(fmt, ##args)
+
+#ifdef DEBUG
+#define DEV_DBG(fmt, args...) pr_err(fmt, ##args)
+#else
+#define DEV_DBG(args...) (void)0
+#endif
+
+#define PORT_DEBUG 0
+#define REG_DUMP 0
+void hdmi_reg_w(void __iomem *addr, u32 offset, u32 value, u32 debug);
+u32 hdmi_reg_r(void __iomem *addr, u32 offset, u32 debug);
+
+#define HDMI_REG_W_ND(addr, offset, val) hdmi_reg_w(addr, offset, val, false)
+#define HDMI_REG_W(addr, offset, val) hdmi_reg_w(addr, offset, val, true)
+#define HDMI_REG_R_ND(addr, offset) hdmi_reg_r(addr, offset, false)
+#define HDMI_REG_R(addr, offset) hdmi_reg_r(addr, offset, true)
+
+/* HDMI_TX Registers */
+#define HDMI_CTRL (0x00000000)
+#define HDMI_TEST_PATTERN (0x00000010)
+#define HDMI_RANDOM_PATTERN (0x00000014)
+#define HDMI_PKT_BLK_CTRL (0x00000018)
+#define HDMI_STATUS (0x0000001C)
+#define HDMI_AUDIO_PKT_CTRL (0x00000020)
+#define HDMI_ACR_PKT_CTRL (0x00000024)
+#define HDMI_VBI_PKT_CTRL (0x00000028)
+#define HDMI_INFOFRAME_CTRL0 (0x0000002C)
+#define HDMI_INFOFRAME_CTRL1 (0x00000030)
+#define HDMI_GEN_PKT_CTRL (0x00000034)
+#define HDMI_ACP (0x0000003C)
+#define HDMI_GC (0x00000040)
+#define HDMI_AUDIO_PKT_CTRL2 (0x00000044)
+#define HDMI_ISRC1_0 (0x00000048)
+#define HDMI_ISRC1_1 (0x0000004C)
+#define HDMI_ISRC1_2 (0x00000050)
+#define HDMI_ISRC1_3 (0x00000054)
+#define HDMI_ISRC1_4 (0x00000058)
+#define HDMI_ISRC2_0 (0x0000005C)
+#define HDMI_ISRC2_1 (0x00000060)
+#define HDMI_ISRC2_2 (0x00000064)
+#define HDMI_ISRC2_3 (0x00000068)
+#define HDMI_AVI_INFO0 (0x0000006C)
+#define HDMI_AVI_INFO1 (0x00000070)
+#define HDMI_AVI_INFO2 (0x00000074)
+#define HDMI_AVI_INFO3 (0x00000078)
+#define HDMI_MPEG_INFO0 (0x0000007C)
+#define HDMI_MPEG_INFO1 (0x00000080)
+#define HDMI_GENERIC0_HDR (0x00000084)
+#define HDMI_GENERIC0_0 (0x00000088)
+#define HDMI_GENERIC0_1 (0x0000008C)
+#define HDMI_GENERIC0_2 (0x00000090)
+#define HDMI_GENERIC0_3 (0x00000094)
+#define HDMI_GENERIC0_4 (0x00000098)
+#define HDMI_GENERIC0_5 (0x0000009C)
+#define HDMI_GENERIC0_6 (0x000000A0)
+#define HDMI_GENERIC1_HDR (0x000000A4)
+#define HDMI_GENERIC1_0 (0x000000A8)
+#define HDMI_GENERIC1_1 (0x000000AC)
+#define HDMI_GENERIC1_2 (0x000000B0)
+#define HDMI_GENERIC1_3 (0x000000B4)
+#define HDMI_GENERIC1_4 (0x000000B8)
+#define HDMI_GENERIC1_5 (0x000000BC)
+#define HDMI_GENERIC1_6 (0x000000C0)
+#define HDMI_ACR_32_0 (0x000000C4)
+#define HDMI_ACR_32_1 (0x000000C8)
+#define HDMI_ACR_44_0 (0x000000CC)
+#define HDMI_ACR_44_1 (0x000000D0)
+#define HDMI_ACR_48_0 (0x000000D4)
+#define HDMI_ACR_48_1 (0x000000D8)
+#define HDMI_ACR_STATUS_0 (0x000000DC)
+#define HDMI_ACR_STATUS_1 (0x000000E0)
+#define HDMI_AUDIO_INFO0 (0x000000E4)
+#define HDMI_AUDIO_INFO1 (0x000000E8)
+#define HDMI_CS_60958_0 (0x000000EC)
+#define HDMI_CS_60958_1 (0x000000F0)
+#define HDMI_RAMP_CTRL0 (0x000000F8)
+#define HDMI_RAMP_CTRL1 (0x000000FC)
+#define HDMI_RAMP_CTRL2 (0x00000100)
+#define HDMI_RAMP_CTRL3 (0x00000104)
+#define HDMI_CS_60958_2 (0x00000108)
+#define HDMI_HDCP_CTRL (0x00000110)
+#define HDMI_HDCP_DEBUG_CTRL (0x00000114)
+#define HDMI_HDCP_INT_CTRL (0x00000118)
+#define HDMI_HDCP_LINK0_STATUS (0x0000011C)
+#define HDMI_HDCP_DDC_CTRL_0 (0x00000120)
+#define HDMI_HDCP_DDC_CTRL_1 (0x00000124)
+#define HDMI_HDCP_DDC_STATUS (0x00000128)
+#define HDMI_HDCP_ENTROPY_CTRL0 (0x0000012C)
+#define HDMI_HDCP_RESET (0x00000130)
+#define HDMI_HDCP_RCVPORT_DATA0 (0x00000134)
+#define HDMI_HDCP_RCVPORT_DATA1 (0x00000138)
+#define HDMI_HDCP_RCVPORT_DATA2_0 (0x0000013C)
+#define HDMI_HDCP_RCVPORT_DATA2_1 (0x00000140)
+#define HDMI_HDCP_RCVPORT_DATA3 (0x00000144)
+#define HDMI_HDCP_RCVPORT_DATA4 (0x00000148)
+#define HDMI_HDCP_RCVPORT_DATA5 (0x0000014C)
+#define HDMI_HDCP_RCVPORT_DATA6 (0x00000150)
+#define HDMI_HDCP_RCVPORT_DATA7 (0x00000154)
+#define HDMI_HDCP_RCVPORT_DATA8 (0x00000158)
+#define HDMI_HDCP_RCVPORT_DATA9 (0x0000015C)
+#define HDMI_HDCP_RCVPORT_DATA10 (0x00000160)
+#define HDMI_HDCP_RCVPORT_DATA11 (0x00000164)
+#define HDMI_HDCP_RCVPORT_DATA12 (0x00000168)
+#define HDMI_VENSPEC_INFO0 (0x0000016C)
+#define HDMI_VENSPEC_INFO1 (0x00000170)
+#define HDMI_VENSPEC_INFO2 (0x00000174)
+#define HDMI_VENSPEC_INFO3 (0x00000178)
+#define HDMI_VENSPEC_INFO4 (0x0000017C)
+#define HDMI_VENSPEC_INFO5 (0x00000180)
+#define HDMI_VENSPEC_INFO6 (0x00000184)
+#define HDMI_HDCP_DEBUG (0x00000194)
+#define HDMI_TMDS_CTRL_CHAR (0x0000019C)
+#define HDMI_TMDS_CTRL_SEL (0x000001A4)
+#define HDMI_TMDS_SYNCCHAR01 (0x000001A8)
+#define HDMI_TMDS_SYNCCHAR23 (0x000001AC)
+#define HDMI_TMDS_DEBUG (0x000001B4)
+#define HDMI_TMDS_CTL_BITS (0x000001B8)
+#define HDMI_TMDS_DCBAL_CTRL (0x000001BC)
+#define HDMI_TMDS_DCBAL_CHAR (0x000001C0)
+#define HDMI_TMDS_CTL01_GEN (0x000001C8)
+#define HDMI_TMDS_CTL23_GEN (0x000001CC)
+#define HDMI_AUDIO_CFG (0x000001D0)
+#define HDMI_DEBUG (0x00000204)
+#define HDMI_USEC_REFTIMER (0x00000208)
+#define HDMI_DDC_CTRL (0x0000020C)
+#define HDMI_DDC_ARBITRATION (0x00000210)
+#define HDMI_DDC_INT_CTRL (0x00000214)
+#define HDMI_DDC_SW_STATUS (0x00000218)
+#define HDMI_DDC_HW_STATUS (0x0000021C)
+#define HDMI_DDC_SPEED (0x00000220)
+#define HDMI_DDC_SETUP (0x00000224)
+#define HDMI_DDC_TRANS0 (0x00000228)
+#define HDMI_DDC_TRANS1 (0x0000022C)
+#define HDMI_DDC_TRANS2 (0x00000230)
+#define HDMI_DDC_TRANS3 (0x00000234)
+#define HDMI_DDC_DATA (0x00000238)
+#define HDMI_HDCP_SHA_CTRL (0x0000023C)
+#define HDMI_HDCP_SHA_STATUS (0x00000240)
+#define HDMI_HDCP_SHA_DATA (0x00000244)
+#define HDMI_HDCP_SHA_DBG_M0_0 (0x00000248)
+#define HDMI_HDCP_SHA_DBG_M0_1 (0x0000024C)
+#define HDMI_HPD_INT_STATUS (0x00000250)
+#define HDMI_HPD_INT_CTRL (0x00000254)
+#define HDMI_HPD_CTRL (0x00000258)
+#define HDMI_HDCP_ENTROPY_CTRL1 (0x0000025C)
+#define HDMI_HDCP_SW_UPPER_AN (0x00000260)
+#define HDMI_HDCP_SW_LOWER_AN (0x00000264)
+#define HDMI_CRC_CTRL (0x00000268)
+#define HDMI_VID_CRC (0x0000026C)
+#define HDMI_AUD_CRC (0x00000270)
+#define HDMI_VBI_CRC (0x00000274)
+#define HDMI_DDC_REF (0x0000027C)
+#define HDMI_HDCP_SW_UPPER_AKSV (0x00000284)
+#define HDMI_HDCP_SW_LOWER_AKSV (0x00000288)
+#define HDMI_CEC_CTRL (0x0000028C)
+#define HDMI_CEC_WR_DATA (0x00000290)
+#define HDMI_CEC_RETRANSMIT (0x00000294)
+#define HDMI_CEC_STATUS (0x00000298)
+#define HDMI_CEC_INT (0x0000029C)
+#define HDMI_CEC_ADDR (0x000002A0)
+#define HDMI_CEC_TIME (0x000002A4)
+#define HDMI_CEC_REFTIMER (0x000002A8)
+#define HDMI_CEC_RD_DATA (0x000002AC)
+#define HDMI_CEC_RD_FILTER (0x000002B0)
+#define HDMI_ACTIVE_H (0x000002B4)
+#define HDMI_ACTIVE_V (0x000002B8)
+#define HDMI_ACTIVE_V_F2 (0x000002BC)
+#define HDMI_TOTAL (0x000002C0)
+#define HDMI_V_TOTAL_F2 (0x000002C4)
+#define HDMI_FRAME_CTRL (0x000002C8)
+#define HDMI_AUD_INT (0x000002CC)
+#define HDMI_DEBUG_BUS_CTRL (0x000002D0)
+#define HDMI_PHY_CTRL (0x000002D4)
+#define HDMI_CEC_WR_RANGE (0x000002DC)
+#define HDMI_CEC_RD_RANGE (0x000002E0)
+#define HDMI_VERSION (0x000002E4)
+#define HDMI_BIST_ENABLE (0x000002F4)
+#define HDMI_TIMING_ENGINE_EN (0x000002F8)
+#define HDMI_INTF_CONFIG (0x000002FC)
+#define HDMI_HSYNC_CTL (0x00000300)
+#define HDMI_VSYNC_PERIOD_F0 (0x00000304)
+#define HDMI_VSYNC_PERIOD_F1 (0x00000308)
+#define HDMI_VSYNC_PULSE_WIDTH_F0 (0x0000030C)
+#define HDMI_VSYNC_PULSE_WIDTH_F1 (0x00000310)
+#define HDMI_DISPLAY_V_START_F0 (0x00000314)
+#define HDMI_DISPLAY_V_START_F1 (0x00000318)
+#define HDMI_DISPLAY_V_END_F0 (0x0000031C)
+#define HDMI_DISPLAY_V_END_F1 (0x00000320)
+#define HDMI_ACTIVE_V_START_F0 (0x00000324)
+#define HDMI_ACTIVE_V_START_F1 (0x00000328)
+#define HDMI_ACTIVE_V_END_F0 (0x0000032C)
+#define HDMI_ACTIVE_V_END_F1 (0x00000330)
+#define HDMI_DISPLAY_HCTL (0x00000334)
+#define HDMI_ACTIVE_HCTL (0x00000338)
+#define HDMI_HSYNC_SKEW (0x0000033C)
+#define HDMI_POLARITY_CTL (0x00000340)
+#define HDMI_TPG_MAIN_CONTROL (0x00000344)
+#define HDMI_TPG_VIDEO_CONFIG (0x00000348)
+#define HDMI_TPG_COMPONENT_LIMITS (0x0000034C)
+#define HDMI_TPG_RECTANGLE (0x00000350)
+#define HDMI_TPG_INITIAL_VALUE (0x00000354)
+#define HDMI_TPG_BLK_WHT_PATTERN_FRAMES (0x00000358)
+#define HDMI_TPG_RGB_MAPPING (0x0000035C)
+
+/* HDMI PHY Registers, use them with PHY base and _ND macro */
+#define HDMI_PHY_ANA_CFG0 (0x00000000)
+#define HDMI_PHY_ANA_CFG1 (0x00000004)
+#define HDMI_PHY_PD_CTRL0 (0x00000010)
+#define HDMI_PHY_PD_CTRL1 (0x00000014)
+#define HDMI_PHY_BIST_CFG0 (0x00000034)
+#define HDMI_PHY_BIST_PATN0 (0x0000003C)
+#define HDMI_PHY_BIST_PATN1 (0x00000040)
+#define HDMI_PHY_BIST_PATN2 (0x00000044)
+#define HDMI_PHY_BIST_PATN3 (0x00000048)
+
+/* all video formats defined by EIA CEA 861D */
+#define HDMI_VFRMT_640x480p60_4_3 0
+#define HDMI_VFRMT_720x480p60_4_3 1
+#define HDMI_VFRMT_720x480p60_16_9 2
+#define HDMI_VFRMT_1280x720p60_16_9 3
+#define HDMI_VFRMT_1920x1080i60_16_9 4
+#define HDMI_VFRMT_720x480i60_4_3 5
+#define HDMI_VFRMT_1440x480i60_4_3 HDMI_VFRMT_720x480i60_4_3
+#define HDMI_VFRMT_720x480i60_16_9 6
+#define HDMI_VFRMT_1440x480i60_16_9 HDMI_VFRMT_720x480i60_16_9
+#define HDMI_VFRMT_720x240p60_4_3 7
+#define HDMI_VFRMT_1440x240p60_4_3 HDMI_VFRMT_720x240p60_4_3
+#define HDMI_VFRMT_720x240p60_16_9 8
+#define HDMI_VFRMT_1440x240p60_16_9 HDMI_VFRMT_720x240p60_16_9
+#define HDMI_VFRMT_2880x480i60_4_3 9
+#define HDMI_VFRMT_2880x480i60_16_9 10
+#define HDMI_VFRMT_2880x240p60_4_3 11
+#define HDMI_VFRMT_2880x240p60_16_9 12
+#define HDMI_VFRMT_1440x480p60_4_3 13
+#define HDMI_VFRMT_1440x480p60_16_9 14
+#define HDMI_VFRMT_1920x1080p60_16_9 15
+#define HDMI_VFRMT_720x576p50_4_3 16
+#define HDMI_VFRMT_720x576p50_16_9 17
+#define HDMI_VFRMT_1280x720p50_16_9 18
+#define HDMI_VFRMT_1920x1080i50_16_9 19
+#define HDMI_VFRMT_720x576i50_4_3 20
+#define HDMI_VFRMT_1440x576i50_4_3 HDMI_VFRMT_720x576i50_4_3
+#define HDMI_VFRMT_720x576i50_16_9 21
+#define HDMI_VFRMT_1440x576i50_16_9 HDMI_VFRMT_720x576i50_16_9
+#define HDMI_VFRMT_720x288p50_4_3 22
+#define HDMI_VFRMT_1440x288p50_4_3 HDMI_VFRMT_720x288p50_4_3
+#define HDMI_VFRMT_720x288p50_16_9 23
+#define HDMI_VFRMT_1440x288p50_16_9 HDMI_VFRMT_720x288p50_16_9
+#define HDMI_VFRMT_2880x576i50_4_3 24
+#define HDMI_VFRMT_2880x576i50_16_9 25
+#define HDMI_VFRMT_2880x288p50_4_3 26
+#define HDMI_VFRMT_2880x288p50_16_9 27
+#define HDMI_VFRMT_1440x576p50_4_3 28
+#define HDMI_VFRMT_1440x576p50_16_9 29
+#define HDMI_VFRMT_1920x1080p50_16_9 30
+#define HDMI_VFRMT_1920x1080p24_16_9 31
+#define HDMI_VFRMT_1920x1080p25_16_9 32
+#define HDMI_VFRMT_1920x1080p30_16_9 33
+#define HDMI_VFRMT_2880x480p60_4_3 34
+#define HDMI_VFRMT_2880x480p60_16_9 35
+#define HDMI_VFRMT_2880x576p50_4_3 36
+#define HDMI_VFRMT_2880x576p50_16_9 37
+#define HDMI_VFRMT_1920x1250i50_16_9 38
+#define HDMI_VFRMT_1920x1080i100_16_9 39
+#define HDMI_VFRMT_1280x720p100_16_9 40
+#define HDMI_VFRMT_720x576p100_4_3 41
+#define HDMI_VFRMT_720x576p100_16_9 42
+#define HDMI_VFRMT_720x576i100_4_3 43
+#define HDMI_VFRMT_1440x576i100_4_3 HDMI_VFRMT_720x576i100_4_3
+#define HDMI_VFRMT_720x576i100_16_9 44
+#define HDMI_VFRMT_1440x576i100_16_9 HDMI_VFRMT_720x576i100_16_9
+#define HDMI_VFRMT_1920x1080i120_16_9 45
+#define HDMI_VFRMT_1280x720p120_16_9 46
+#define HDMI_VFRMT_720x480p120_4_3 47
+#define HDMI_VFRMT_720x480p120_16_9 48
+#define HDMI_VFRMT_720x480i120_4_3 49
+#define HDMI_VFRMT_1440x480i120_4_3 HDMI_VFRMT_720x480i120_4_3
+#define HDMI_VFRMT_720x480i120_16_9 50
+#define HDMI_VFRMT_1440x480i120_16_9 HDMI_VFRMT_720x480i120_16_9
+#define HDMI_VFRMT_720x576p200_4_3 51
+#define HDMI_VFRMT_720x576p200_16_9 52
+#define HDMI_VFRMT_720x576i200_4_3 53
+#define HDMI_VFRMT_1440x576i200_4_3 HDMI_VFRMT_720x576i200_4_3
+#define HDMI_VFRMT_720x576i200_16_9 54
+#define HDMI_VFRMT_1440x576i200_16_9 HDMI_VFRMT_720x576i200_16_9
+#define HDMI_VFRMT_720x480p240_4_3 55
+#define HDMI_VFRMT_720x480p240_16_9 56
+#define HDMI_VFRMT_720x480i240_4_3 57
+#define HDMI_VFRMT_1440x480i240_4_3 HDMI_VFRMT_720x480i240_4_3
+#define HDMI_VFRMT_720x480i240_16_9 58
+#define HDMI_VFRMT_1440x480i240_16_9 HDMI_VFRMT_720x480i240_16_9
+#define HDMI_VFRMT_MAX 59
+#define HDMI_VFRMT_FORCE_32BIT 0x7FFFFFFF
+
+#define VFRMT_NOT_SUPPORTED(VFRMT) \
+ {VFRMT, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, false}
+
+#define HDMI_SETTINGS_640x480p60_4_3 \
+ {HDMI_VFRMT_640x480p60_4_3, 640, 16, 96, 48, true, \
+ 480, 10, 2, 33, true, 25200, 60000, false, true}
+#define HDMI_SETTINGS_720x480p60_4_3 \
+ {HDMI_VFRMT_720x480p60_4_3, 720, 16, 62, 60, true, \
+ 480, 9, 6, 30, true, 27030, 60000, false, true}
+#define HDMI_SETTINGS_720x480p60_16_9 \
+ {HDMI_VFRMT_720x480p60_16_9, 720, 16, 62, 60, true, \
+ 480, 9, 6, 30, true, 27030, 60000, false, true}
+#define HDMI_SETTINGS_1280x720p60_16_9 \
+ {HDMI_VFRMT_1280x720p60_16_9, 1280, 110, 40, 220, false, \
+ 720, 5, 5, 20, false, 74250, 60000, false, true}
+#define HDMI_SETTINGS_1920x1080i60_16_9 \
+ {HDMI_VFRMT_1920x1080i60_16_9, 1920, 88, 44, 148, false, \
+ 540, 2, 5, 5, false, 74250, 60000, false, true}
+#define HDMI_SETTINGS_1440x480i60_4_3 \
+ {HDMI_VFRMT_1440x480i60_4_3, 1440, 38, 124, 114, true, \
+ 240, 4, 3, 15, true, 27000, 60000, true, true}
+#define HDMI_SETTINGS_1440x480i60_16_9 \
+ {HDMI_VFRMT_1440x480i60_16_9, 1440, 38, 124, 114, true, \
+ 240, 4, 3, 15, true, 27000, 60000, true, true}
+#define HDMI_SETTINGS_1920x1080p60_16_9 \
+ {HDMI_VFRMT_1920x1080p60_16_9, 1920, 88, 44, 148, false, \
+ 1080, 4, 5, 36, false, 148500, 60000, false, true}
+#define HDMI_SETTINGS_720x576p50_4_3 \
+ {HDMI_VFRMT_720x576p50_4_3, 720, 12, 64, 68, true, \
+ 576, 5, 5, 39, true, 27000, 50000, false, true}
+#define HDMI_SETTINGS_720x576p50_16_9 \
+ {HDMI_VFRMT_720x576p50_16_9, 720, 12, 64, 68, true, \
+ 576, 5, 5, 39, true, 27000, 50000, false, true}
+#define HDMI_SETTINGS_1280x720p50_16_9 \
+ {HDMI_VFRMT_1280x720p50_16_9, 1280, 440, 40, 220, false, \
+ 720, 5, 5, 20, false, 74250, 50000, false, true}
+#define HDMI_SETTINGS_1440x576i50_4_3 \
+ {HDMI_VFRMT_1440x576i50_4_3, 1440, 24, 126, 138, true, \
+ 288, 2, 3, 19, true, 27000, 50000, true, true}
+#define HDMI_SETTINGS_1440x576i50_16_9 \
+ {HDMI_VFRMT_1440x576i50_16_9, 1440, 24, 126, 138, true, \
+ 288, 2, 3, 19, true, 27000, 50000, true, true}
+#define HDMI_SETTINGS_1920x1080p50_16_9 \
+ {HDMI_VFRMT_1920x1080p50_16_9, 1920, 528, 44, 148, false, \
+ 1080, 4, 5, 36, false, 148500, 50000, false, true}
+#define HDMI_SETTINGS_1920x1080p24_16_9 \
+ {HDMI_VFRMT_1920x1080p24_16_9, 1920, 638, 44, 148, false, \
+ 1080, 4, 5, 36, false, 74250, 24000, false, true}
+#define HDMI_SETTINGS_1920x1080p25_16_9 \
+ {HDMI_VFRMT_1920x1080p25_16_9, 1920, 528, 44, 148, false, \
+ 1080, 4, 5, 36, false, 74250, 25000, false, true}
+#define HDMI_SETTINGS_1920x1080p30_16_9 \
+ {HDMI_VFRMT_1920x1080p30_16_9, 1920, 88, 44, 148, false, \
+ 1080, 4, 5, 36, false, 74250, 30000, false, true}
+
+#define TOP_AND_BOTTOM 0x10
+#define FRAME_PACKING 0x20
+#define SIDE_BY_SIDE_HALF 0x40
+
+struct hdmi_disp_mode_timing_type {
+ u32 video_format;
+ u32 active_h;
+ u32 front_porch_h;
+ u32 pulse_width_h;
+ u32 back_porch_h;
+ u32 active_low_h;
+ u32 active_v;
+ u32 front_porch_v;
+ u32 pulse_width_v;
+ u32 back_porch_v;
+ u32 active_low_v;
+ /* Must divide by 1000 to get the actual frequency in MHZ */
+ u32 pixel_freq;
+ /* Must divide by 1000 to get the actual frequency in HZ */
+ u32 refresh_rate;
+ u32 interlaced;
+ u32 supported;
+};
+
+void hdmi_reg_dump(void __iomem *base, u32 length, const char *prefix);
+const char *hdmi_reg_name(u32 offset);
+
+const struct hdmi_disp_mode_timing_type *hdmi_get_supported_mode(u32 mode);
+void hdmi_set_supported_mode(u32 mode);
+const char *hdmi_get_video_fmt_2string(u32 format);
+ssize_t hdmi_get_video_3d_fmt_2string(u32 format, char *buf);
+
+#endif /* __HDMI_UTIL_H__ */
diff --git a/drivers/video/msm/mdss/mdss_io_util.c b/drivers/video/msm/mdss/mdss_io_util.c
new file mode 100644
index 0000000..84f5909
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_io_util.c
@@ -0,0 +1,152 @@
+/* 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/err.h>
+#include <linux/io.h>
+#include "mdss_io_util.h"
+
+int msm_dss_config_vreg(struct device *dev, struct dss_vreg *in_vreg,
+ int num_vreg, int config)
+{
+ int i = 0, rc = 0;
+ struct dss_vreg *curr_vreg;
+
+ if (config) {
+ for (i = 0; i < num_vreg; i++) {
+ curr_vreg = &in_vreg[i];
+ curr_vreg->vreg = regulator_get(dev,
+ curr_vreg->vreg_name);
+ if (IS_ERR(curr_vreg->vreg)) {
+ pr_err("%s: %s get failed\n",
+ __func__,
+ curr_vreg->vreg_name);
+ curr_vreg->vreg = NULL;
+ goto vreg_get_fail;
+ }
+ if (curr_vreg->type == DSS_REG_LDO) {
+ rc = regulator_set_voltage(
+ curr_vreg->vreg,
+ curr_vreg->min_voltage,
+ curr_vreg->max_voltage);
+ if (rc < 0) {
+ pr_err("%s: %s set voltage failed\n",
+ __func__,
+ curr_vreg->vreg_name);
+ goto vreg_set_voltage_fail;
+ }
+ if (curr_vreg->optimum_voltage >= 0) {
+ rc = regulator_set_optimum_mode(
+ curr_vreg->vreg,
+ curr_vreg->optimum_voltage);
+ if (rc < 0) {
+ pr_err(
+ "%s: %s set opt mode failed\n",
+ __func__,
+ curr_vreg->vreg_name);
+ goto vreg_set_opt_mode_fail;
+ }
+ }
+ }
+ }
+ } else {
+ for (i = num_vreg-1; i >= 0; i--) {
+ curr_vreg = &in_vreg[i];
+ if (curr_vreg->vreg &&
+ regulator_is_enabled(curr_vreg->vreg)) {
+ if (curr_vreg->type == DSS_REG_LDO) {
+ if (curr_vreg->optimum_voltage >= 0) {
+ regulator_set_optimum_mode(
+ curr_vreg->vreg, 0);
+ }
+ regulator_set_voltage(curr_vreg->vreg,
+ 0, curr_vreg->max_voltage);
+ }
+ regulator_put(curr_vreg->vreg);
+ curr_vreg->vreg = NULL;
+ }
+ }
+ }
+ return 0;
+
+vreg_unconfig:
+if (curr_vreg->type == DSS_REG_LDO)
+ regulator_set_optimum_mode(curr_vreg->vreg, 0);
+
+vreg_set_opt_mode_fail:
+if (curr_vreg->type == DSS_REG_LDO)
+ regulator_set_voltage(curr_vreg->vreg, 0, curr_vreg->max_voltage);
+
+vreg_set_voltage_fail:
+ regulator_put(curr_vreg->vreg);
+ curr_vreg->vreg = NULL;
+
+vreg_get_fail:
+ for (i--; i >= 0; i--) {
+ curr_vreg = &in_vreg[i];
+ goto vreg_unconfig;
+ }
+ return -EPERM;
+} /* msm_dss_config_vreg */
+
+int msm_dss_enable_vreg(struct dss_vreg *in_vreg, int num_vreg, int enable)
+{
+ int i = 0, rc = 0;
+ if (enable) {
+ for (i = 0; i < num_vreg; i++) {
+ if (IS_ERR(in_vreg[i].vreg)) {
+ pr_err("%s: %s null regulator\n",
+ __func__, in_vreg[i].vreg_name);
+ goto disable_vreg;
+ }
+ rc = regulator_enable(in_vreg[i].vreg);
+ if (rc < 0) {
+ pr_err("%s: %s enable failed\n",
+ __func__, in_vreg[i].vreg_name);
+ goto disable_vreg;
+ }
+ }
+ } else {
+ for (i = num_vreg-1; i >= 0; i--)
+ regulator_disable(in_vreg[i].vreg);
+ }
+ return rc;
+
+disable_vreg:
+ for (i--; i >= 0; i--)
+ regulator_disable(in_vreg[i].vreg);
+ return rc;
+} /* msm_dss_enable_vreg */
+
+int msm_dss_enable_gpio(struct dss_gpio *in_gpio, int num_gpio, int enable)
+{
+ int i = 0, rc = 0;
+ if (enable) {
+ for (i = 0; i < num_gpio; i++) {
+ rc = gpio_request(in_gpio[i].gpio,
+ in_gpio[i].gpio_name);
+ if (rc < 0) {
+ pr_err("%s: %s enable failed\n",
+ __func__, in_gpio[i].gpio_name);
+ goto disable_gpio;
+ }
+ }
+ } else {
+ for (i = num_gpio-1; i >= 0; i--)
+ gpio_free(in_gpio[i].gpio);
+ }
+ return rc;
+
+disable_gpio:
+ for (i--; i >= 0; i--)
+ gpio_free(in_gpio[i].gpio);
+ return rc;
+} /* msm_dss_enable_gpio */
diff --git a/drivers/video/msm/mdss/mdss_io_util.h b/drivers/video/msm/mdss/mdss_io_util.h
new file mode 100644
index 0000000..791e44a
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_io_util.h
@@ -0,0 +1,50 @@
+/* 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 __MDSS_IO_UTIL_H__
+#define __MDSS_IO_UTIL_H__
+
+#include <linux/gpio.h>
+#include <linux/regulator/consumer.h>
+
+enum dss_vreg_type {
+ DSS_REG_LDO,
+ DSS_REG_VS,
+};
+
+struct dss_vreg {
+ struct regulator *vreg; /* vreg handle */
+ char vreg_name[32];
+ enum dss_vreg_type type;
+ int min_voltage;
+ int max_voltage;
+ int optimum_voltage;
+};
+
+struct dss_gpio {
+ unsigned gpio;
+ char gpio_name[32];
+};
+
+struct dss_module_power {
+ unsigned num_vreg;
+ struct dss_vreg *vreg_config;
+ unsigned num_gpio;
+ struct dss_gpio *gpio_config;
+};
+
+int msm_dss_enable_gpio(struct dss_gpio *in_gpio, int num_gpio, int enable);
+int msm_dss_config_vreg(struct device *dev, struct dss_vreg *in_vreg,
+ int num_vreg, int config);
+int msm_dss_enable_vreg(struct dss_vreg *in_vreg, int num_vreg, int enable);
+
+#endif /* __MDSS_IO_UTIL_H__ */
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index 695ca1c..ce55e71 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -94,6 +94,7 @@
struct mdss_hw mdss_mdp_hw = {
.hw_ndx = MDSS_HW_MDP,
+ .ptr = NULL,
.irq_handler = mdss_mdp_isr,
};
@@ -108,7 +109,7 @@
hw = mdss_irq_handlers[hw_ndx];
spin_unlock(&mdss_lock);
if (hw)
- return hw->irq_handler(irq, ptr);
+ return hw->irq_handler(irq, hw->ptr);
return -ENODEV;
}
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index 17281d5..a282c3a 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -107,6 +107,9 @@
MDSS_MDP_MAX_CSC
};
+struct mdss_mdp_ctl;
+typedef void (*mdp_vsync_handler_t)(struct mdss_mdp_ctl *, ktime_t);
+
struct mdss_mdp_ctl {
u32 num;
u32 ref_cnt;
@@ -138,6 +141,7 @@
int (*stop_fnc) (struct mdss_mdp_ctl *ctl);
int (*prepare_fnc) (struct mdss_mdp_ctl *ctl, void *arg);
int (*display_fnc) (struct mdss_mdp_ctl *ctl, void *arg);
+ int (*set_vsync_handler) (struct mdss_mdp_ctl *, mdp_vsync_handler_t);
void *priv_data;
};
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index d29ecd6..21f4071 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -533,6 +533,11 @@
mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_PACK_3D, 0);
}
+ /* request bus bandwidth for panel commands */
+ ctl->clk_rate = MDP_CLK_DEFAULT_RATE;
+ ctl->bus_ib_quota = SZ_1M;
+ mdss_mdp_ctl_perf_commit(MDSS_MDP_PERF_UPDATE_ALL);
+
ret = pdata->on(pdata);
start_fail:
diff --git a/drivers/video/msm/mdss/mdss_mdp_formats.h b/drivers/video/msm/mdss/mdss_mdp_formats.h
index d8ae531..ee3b8e6 100644
--- a/drivers/video/msm/mdss/mdss_mdp_formats.h
+++ b/drivers/video/msm/mdss/mdss_mdp_formats.h
@@ -131,6 +131,8 @@
FMT_YUV_PSEUDO(MDP_Y_CBCR_H1V2, MDSS_MDP_CHROMA_H1V2, C1_B_Cb, C2_R_Cr),
FMT_YUV_PSEUDO(MDP_Y_CRCB_H2V2, MDSS_MDP_CHROMA_420, C2_R_Cr, C1_B_Cb),
FMT_YUV_PSEUDO(MDP_Y_CBCR_H2V2, MDSS_MDP_CHROMA_420, C1_B_Cb, C2_R_Cr),
+ FMT_YUV_PSEUDO(MDP_Y_CBCR_H2V2_VENUS, MDSS_MDP_CHROMA_420,
+ C1_B_Cb, C2_R_Cr),
FMT_YUV_PLANR(MDP_Y_CR_CB_H2V2, MDSS_MDP_CHROMA_420, C2_R_Cr, C1_B_Cb),
FMT_YUV_PLANR(MDP_Y_CB_CR_H2V2, MDSS_MDP_CHROMA_420, C1_B_Cb, C2_R_Cr),
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_video.c b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
index bc64d2e..5d8dd86 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_video.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
@@ -13,6 +13,8 @@
#define pr_fmt(fmt) "%s: " fmt, __func__
+#include <linux/workqueue.h>
+
#include "mdss_fb.h"
#include "mdss_mdp.h"
@@ -44,6 +46,12 @@
u8 timegen_en;
struct completion pp_comp;
struct completion vsync_comp;
+
+ struct mutex vsync_lock;
+ struct work_struct vsync_work;
+ mdp_vsync_handler_t vsync_handler;
+ void *vsync_ptr;
+ ktime_t vsync_time;
};
struct mdss_mdp_video_ctx mdss_mdp_video_ctx_list[MAX_SESSIONS];
@@ -54,6 +62,7 @@
u32 hsync_period, vsync_period;
u32 hsync_start_x, hsync_end_x, display_v_start, display_v_end;
u32 active_h_start, active_h_end, active_v_start, active_v_end;
+ u32 den_polarity, hsync_polarity, vsync_polarity;
u32 display_hctl, active_hctl, hsync_ctl, polarity_ctl;
int off;
@@ -106,9 +115,18 @@
hsync_ctl = (hsync_period << 16) | p->hsync_pulse_width;
display_hctl = (hsync_end_x << 16) | hsync_start_x;
- polarity_ctl = (0 << 2) | /* DEN Polarity */
- (0 << 1) | /* VSYNC Polarity */
- (0); /* HSYNC Polarity */
+
+ den_polarity = 0;
+ if (MDSS_INTF_HDMI == ctl->intf_type) {
+ hsync_polarity = p->yres >= 720 ? 0 : 1;
+ vsync_polarity = p->yres >= 720 ? 0 : 1;
+ } else {
+ hsync_polarity = 0;
+ vsync_polarity = 0;
+ }
+ polarity_ctl = (den_polarity << 2) | /* DEN Polarity */
+ (vsync_polarity << 1) | /* VSYNC Polarity */
+ (hsync_polarity << 0); /* HSYNC Polarity */
MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_INTF_HSYNC_CTL, hsync_ctl);
MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_INTF_VSYNC_PERIOD_F0,
@@ -141,6 +159,47 @@
return 0;
}
+static void send_vsync_work(struct work_struct *work)
+{
+ struct mdss_mdp_video_ctx *ctx;
+
+ ctx = container_of(work, typeof(*ctx), vsync_work);
+ mutex_lock(&ctx->vsync_lock);
+ if (ctx->vsync_handler)
+ ctx->vsync_handler(ctx->vsync_ptr, ctx->vsync_time);
+ mutex_unlock(&ctx->vsync_lock);
+}
+
+static int mdss_mdp_video_set_vsync_handler(struct mdss_mdp_ctl *ctl,
+ mdp_vsync_handler_t vsync_handler)
+{
+ struct mdss_mdp_video_ctx *ctx;
+
+ ctx = (struct mdss_mdp_video_ctx *) ctl->priv_data;
+ if (!ctx) {
+ pr_err("invalid ctx for ctl=%d\n", ctl->num);
+ return -ENODEV;
+ }
+ if (mutex_lock_interruptible(&ctx->vsync_lock))
+ return -EINTR;
+
+ if (!ctx->timegen_en) {
+ ctx->vsync_time = ktime_get();
+ schedule_work(&ctx->vsync_work);
+ }
+
+ if (!ctx->vsync_handler && vsync_handler)
+ mdss_mdp_irq_enable(MDSS_MDP_IRQ_INTF_VSYNC, ctl->intf_num);
+ else if (ctx->vsync_handler && !vsync_handler)
+ mdss_mdp_irq_disable(MDSS_MDP_IRQ_INTF_VSYNC, ctl->intf_num);
+
+ ctx->vsync_handler = vsync_handler;
+ ctx->vsync_ptr = ctl;
+ mutex_unlock(&ctx->vsync_lock);
+
+ return 0;
+}
+
static int mdss_mdp_video_stop(struct mdss_mdp_ctl *ctl)
{
struct mdss_mdp_video_ctx *ctx;
@@ -161,6 +220,11 @@
ctx->timegen_en = false;
}
+ mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_INTF_VSYNC, ctl->intf_num,
+ NULL, NULL);
+ mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num,
+ NULL, NULL);
+
memset(ctx, 0, sizeof(*ctx));
return 0;
@@ -190,10 +254,13 @@
pr_err("invalid ctx\n");
return;
}
+ ctx->vsync_time = ktime_get();
pr_debug("intr ctl=%d\n", ctx->ctl_num);
complete(&ctx->vsync_comp);
+ if (ctx->vsync_handler)
+ schedule_work(&ctx->vsync_work);
}
static int mdss_mdp_video_prepare(struct mdss_mdp_ctl *ctl, void *arg)
@@ -207,15 +274,10 @@
}
if (ctx->timegen_en) {
- u32 intr_type = MDSS_MDP_IRQ_PING_PONG_COMP;
-
pr_debug("waiting for ping pong %d done\n", ctx->pp_num);
- mdss_mdp_set_intr_callback(intr_type, ctx->pp_num,
- mdss_mdp_video_pp_intr_done, ctx);
- mdss_mdp_irq_enable(intr_type, ctx->pp_num);
-
+ mdss_mdp_irq_enable(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num);
wait_for_completion_interruptible(&ctx->pp_comp);
- mdss_mdp_irq_disable(intr_type, ctx->pp_num);
+ mdss_mdp_irq_disable(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num);
}
return 0;
@@ -224,7 +286,6 @@
static int mdss_mdp_video_display(struct mdss_mdp_ctl *ctl, void *arg)
{
struct mdss_mdp_video_ctx *ctx;
- u32 intr_type = MDSS_MDP_IRQ_INTF_VSYNC;
pr_debug("kickoff ctl=%d\n", ctl->num);
@@ -233,9 +294,12 @@
pr_err("invalid ctx\n");
return -ENODEV;
}
- mdss_mdp_set_intr_callback(intr_type, ctl->intf_num,
- mdss_mdp_video_vsync_intr_done, ctx);
- mdss_mdp_irq_enable(intr_type, ctl->intf_num);
+ INIT_COMPLETION(ctx->vsync_comp);
+
+ if (mutex_lock_interruptible(&ctx->vsync_lock))
+ return -EINTR;
+ if (!ctx->vsync_handler)
+ mdss_mdp_irq_enable(MDSS_MDP_IRQ_INTF_VSYNC, ctl->intf_num);
if (!ctx->timegen_en) {
int off = MDSS_MDP_REG_INTF_OFFSET(ctl->intf_num);
@@ -249,7 +313,9 @@
}
wait_for_completion_interruptible(&ctx->vsync_comp);
- mdss_mdp_irq_disable(intr_type, ctl->intf_num);
+ if (!ctx->vsync_handler)
+ mdss_mdp_irq_disable(MDSS_MDP_IRQ_INTF_VSYNC, ctl->intf_num);
+ mutex_unlock(&ctx->vsync_lock);
return 0;
}
@@ -293,6 +359,13 @@
init_completion(&ctx->pp_comp);
init_completion(&ctx->vsync_comp);
+ INIT_WORK(&ctx->vsync_work, send_vsync_work);
+ mutex_init(&ctx->vsync_lock);
+ mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_INTF_VSYNC, ctl->intf_num,
+ mdss_mdp_video_vsync_intr_done, ctx);
+ mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num,
+ mdss_mdp_video_pp_intr_done, ctx);
+
itp.width = pinfo->xres + pinfo->lcdc.xres_pad;
itp.height = pinfo->yres + pinfo->lcdc.yres_pad;
itp.border_clr = pinfo->lcdc.border_clr;
@@ -316,6 +389,7 @@
ctl->stop_fnc = mdss_mdp_video_stop;
ctl->prepare_fnc = mdss_mdp_video_prepare;
ctl->display_fnc = mdss_mdp_video_display;
+ ctl->set_vsync_handler = mdss_mdp_video_set_vsync_handler;
return 0;
}
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index d4d889b..1cb474d 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -615,6 +615,49 @@
mfd->kickoff_fnc(mfd->ctl);
}
+static void mdss_mdp_overlay_handle_vsync(struct mdss_mdp_ctl *ctl, ktime_t t)
+{
+ struct device *dev;
+ char buf[64];
+ char *envp[2];
+
+ if (!ctl || !ctl->mfd || !ctl->mfd->fbi) {
+ pr_warn("Invalid handle for vsync\n");
+ return;
+ }
+
+ dev = ctl->mfd->fbi->dev;
+
+ snprintf(buf, sizeof(buf), "VSYNC=%llu", ktime_to_ns(t));
+ envp[0] = buf;
+ envp[1] = NULL;
+ kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
+
+ pr_debug("sent vsync on ctl=%d ts=%llu\n", ctl->num, ktime_to_ns(t));
+}
+
+static int mdss_mdp_overlay_vsync_ctrl(struct msm_fb_data_type *mfd, int en)
+{
+ struct mdss_mdp_ctl *ctl = mfd->ctl;
+ int rc;
+
+ if (!ctl)
+ return -ENODEV;
+ if (!ctl->set_vsync_handler)
+ return -ENOTSUPP;
+
+ pr_debug("vsync en=%d\n", en);
+
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+ if (en)
+ rc = ctl->set_vsync_handler(ctl, mdss_mdp_overlay_handle_vsync);
+ else
+ rc = ctl->set_vsync_handler(ctl, NULL);
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+
+ return rc;
+}
+
static int mdss_mdp_hw_cursor_update(struct msm_fb_data_type *mfd,
struct fb_cursor *cursor)
{
@@ -822,6 +865,16 @@
}
break;
+ case MSMFB_VSYNC_CTRL:
+ case MSMFB_OVERLAY_VSYNC_CTRL:
+ if (!copy_from_user(&val, argp, sizeof(val))) {
+ ret = mdss_mdp_overlay_vsync_ctrl(mfd, val);
+ } else {
+ pr_err("MSMFB_OVERLAY_VSYNC_CTRL failed (%d)\n", ret);
+ ret = -EFAULT;
+ }
+ break;
+
default:
if (mfd->panel_info.type == WRITEBACK_PANEL)
ret = mdss_mdp_wb_ioctl_handler(mfd, cmd, argp);
diff --git a/drivers/video/msm/mdss/mdss_mdp_util.c b/drivers/video/msm/mdss/mdss_mdp_util.c
index 7f61a14..53cd378 100644
--- a/drivers/video/msm/mdss/mdss_mdp_util.c
+++ b/drivers/video/msm/mdss/mdss_mdp_util.c
@@ -102,8 +102,6 @@
spin_lock(&mdss_mdp_intr_lock);
fnc = mdp_intr_cb[index].func;
arg = mdp_intr_cb[index].arg;
- if (fnc != NULL)
- mdp_intr_cb[index].func = NULL;
spin_unlock(&mdss_mdp_intr_lock);
if (fnc)
fnc(arg);
@@ -202,18 +200,25 @@
} else {
u8 hmap[] = { 1, 2, 1, 2 };
u8 vmap[] = { 1, 1, 2, 2 };
- u8 horiz, vert;
+ u8 horiz, vert, stride_align;
horiz = hmap[fmt->chroma_sample];
vert = vmap[fmt->chroma_sample];
- if (format == MDP_Y_CR_CB_GH2V2) {
- ps->ystride[0] = ALIGN(w, 16);
- ps->ystride[1] = ALIGN(w / horiz, 16);
- } else {
- ps->ystride[0] = w;
- ps->ystride[1] = (w / horiz);
+ switch (format) {
+ case MDP_Y_CR_CB_GH2V2:
+ stride_align = 16;
+ break;
+ case MDP_Y_CBCR_H2V2_VENUS:
+ stride_align = 32;
+ break;
+ default:
+ stride_align = 1;
+ break;
}
+
+ ps->ystride[0] = ALIGN(w, stride_align);
+ ps->ystride[1] = ALIGN(w / horiz, stride_align);
ps->plane_size[0] = ps->ystride[0] * h;
ps->plane_size[1] = ps->ystride[1] * (h / vert);
diff --git a/drivers/video/msm/mhl/mhl_8334.c b/drivers/video/msm/mhl/mhl_8334.c
index 4347dc7..be160c4 100644
--- a/drivers/video/msm/mhl/mhl_8334.c
+++ b/drivers/video/msm/mhl/mhl_8334.c
@@ -37,6 +37,11 @@
#include "hdmi_msm.h"
#include "mhl_i2c_utils.h"
+#define MSC_START_BIT_MSC_CMD (0x01 << 0)
+#define MSC_START_BIT_VS_CMD (0x01 << 1)
+#define MSC_START_BIT_READ_REG (0x01 << 2)
+#define MSC_START_BIT_WRITE_REG (0x01 << 3)
+#define MSC_START_BIT_WRITE_BURST (0x01 << 4)
static struct i2c_device_id mhl_sii_i2c_id[] = {
{ MHL_DRIVER_NAME, 0 },
@@ -45,6 +50,7 @@
struct mhl_msm_state_t *mhl_msm_state;
spinlock_t mhl_state_lock;
+struct workqueue_struct *msc_send_workqueue;
static int mhl_i2c_probe(struct i2c_client *client,\
const struct i2c_device_id *id);
@@ -55,6 +61,7 @@
static irqreturn_t mhl_tx_isr(int irq, void *dev_id);
void (*notify_usb_online)(int online);
static void mhl_drive_hpd(uint8_t to_state);
+static int mhl_send_msc_command(struct msc_command_struct *req);
static struct i2c_driver mhl_sii_i2c_driver = {
.driver = {
@@ -540,6 +547,7 @@
mhl_msm_state->mhl_data = client->dev.platform_data;
pr_debug("MHL: mhl_msm_state->mhl_data->irq=[%d]\n",
mhl_msm_state->mhl_data->irq);
+ msc_send_workqueue = create_workqueue("mhl_msc_cmd_queue");
if (!mhl_msm_state->mhl_data->mhl_enabled) {
pr_info("MHL Display not enabled\n");
@@ -577,6 +585,46 @@
return 0;
}
+static void list_cmd_put(struct msc_command_struct *cmd)
+{
+ struct msc_cmd_envelope *new_cmd;
+ new_cmd = vmalloc(sizeof(struct msc_cmd_envelope));
+ memcpy(&new_cmd->msc_cmd_msg, cmd,
+ sizeof(struct msc_command_struct));
+ /* Need to check for queue getting filled up */
+ list_add_tail(&new_cmd->msc_queue_envelope, &mhl_msm_state->list_cmd);
+}
+
+struct msc_command_struct *list_cmd_get(void)
+{
+ struct msc_cmd_envelope *cmd_env =
+ list_first_entry(&mhl_msm_state->list_cmd,
+ struct msc_cmd_envelope, msc_queue_envelope);
+ list_del(&cmd_env->msc_queue_envelope);
+ return &cmd_env->msc_cmd_msg;
+}
+
+static void mhl_msc_send_work(struct work_struct *work)
+{
+ int ret;
+ /*
+ * Remove item from the queue
+ * and schedule it
+ */
+ struct msc_command_struct *req;
+ while (!list_empty(&mhl_msm_state->list_cmd)) {
+ req = mhl_msm_state->msc_command_get_work();
+ ret = mhl_send_msc_command(req);
+ if (ret == -EAGAIN)
+ pr_err("MHL: Queue still busy!!\n");
+ else {
+ vfree(req);
+ pr_debug("MESSAGE SENT!!!!\n");
+ }
+ }
+}
+
+
static int __init mhl_msm_init(void)
{
int32_t ret;
@@ -619,7 +667,12 @@
} else
pr_debug("request_threaded_irq succeeded\n");
+ INIT_WORK(&mhl_msm_state->mhl_msc_send_work, mhl_msc_send_work);
mhl_msm_state->cur_state = POWER_STATE_D0_MHL;
+ INIT_LIST_HEAD(&mhl_msm_state->list_cmd);
+ mhl_msm_state->msc_command_put_work = list_cmd_put;
+ mhl_msm_state->msc_command_get_work = list_cmd_get;
+ init_completion(&mhl_msm_state->msc_cmd_done);
/* MHL SII 8334 chip specific init */
mhl_chip_init();
@@ -636,6 +689,16 @@
return ret;
}
+static void mhl_msc_sched_work(struct msc_command_struct *req)
+{
+ /*
+ * Put an item to the queue
+ * and schedule work
+ */
+ mhl_msm_state->msc_command_put_work(req);
+ queue_work(msc_send_workqueue, &mhl_msm_state->mhl_msc_send_work);
+}
+
static void switch_mode(enum mhl_st_type to_mode)
{
unsigned long flags;
@@ -665,7 +728,8 @@
mhl_i2c_reg_write(TX_PAGE_3, 0x0030, 0xD0);
msleep(50);
mhl_i2c_reg_modify(TX_PAGE_3, 0x0010,
- BIT1 | BIT0, BIT1);
+ BIT1 | BIT0, 0x00);
+ mhl_i2c_reg_modify(TX_PAGE_3, 0x003D, BIT0, 0x00);
spin_lock_irqsave(&mhl_state_lock, flags);
mhl_msm_state->cur_state = POWER_STATE_D3;
spin_unlock_irqrestore(&mhl_state_lock, flags);
@@ -740,7 +804,7 @@
* Need to re-enable here
*/
val = mhl_i2c_reg_read(TX_PAGE_3, 0x10);
- mhl_i2c_reg_write(TX_PAGE_3, 0x10, val | BIT(0));
+ mhl_i2c_reg_write(TX_PAGE_3, 0x10, val | BIT0);
return;
}
@@ -958,16 +1022,454 @@
return;
}
-/*
- * RCP, RAP messages - mandatory for compliance
- *
- */
+static void mhl_cbus_process_errors(u8 int_status)
+{
+ u8 abort_reason = 0;
+ if (int_status & BIT2) {
+ abort_reason = mhl_i2c_reg_read(TX_PAGE_CBUS, 0x0B);
+ pr_debug("%s: CBUS DDC Abort Reason(0x%02x)\n",
+ __func__, abort_reason);
+ }
+ if (int_status & BIT5) {
+ abort_reason = mhl_i2c_reg_read(TX_PAGE_CBUS, 0x0D);
+ pr_debug("%s: CBUS MSC Requestor Abort Reason(0x%02x)\n",
+ __func__, abort_reason);
+ mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0D, 0xFF);
+ }
+ if (int_status & BIT6) {
+ abort_reason = mhl_i2c_reg_read(TX_PAGE_CBUS, 0x0E);
+ pr_debug("%s: CBUS MSC Responder Abort Reason(0x%02x)\n",
+ __func__, abort_reason);
+ mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0E, 0xFF);
+ }
+}
+
+static int mhl_msc_command_done(struct msc_command_struct *req)
+{
+ switch (req->command) {
+ case MHL_WRITE_STAT:
+ if (req->offset == MHL_STATUS_REG_LINK_MODE) {
+ if (req->payload.data[0]
+ & MHL_STATUS_PATH_ENABLED) {
+ /* Enable TMDS output */
+ mhl_i2c_reg_modify(TX_PAGE_L0, 0x0080,
+ BIT4, BIT4);
+ } else
+ /* Disable TMDS output */
+ mhl_i2c_reg_modify(TX_PAGE_L0, 0x0080,
+ BIT4, BIT4);
+ }
+ break;
+ case MHL_READ_DEVCAP:
+ mhl_msm_state->devcap_state |= BIT(req->offset);
+ switch (req->offset) {
+ case MHL_DEV_CATEGORY_OFFSET:
+ if (req->retval & MHL_DEV_CATEGORY_POW_BIT) {
+ /*
+ * Enable charging
+ */
+ } else {
+ /*
+ * Disable charging
+ */
+ }
+ break;
+ case DEVCAP_OFFSET_MHL_VERSION:
+ case DEVCAP_OFFSET_INT_STAT_SIZE:
+ break;
+ }
+
+ break;
+ }
+ return 0;
+}
+
+static int mhl_send_msc_command(struct msc_command_struct *req)
+{
+ int timeout;
+ u8 start_bit = 0x00;
+ u8 *burst_data;
+ int i;
+
+ if (mhl_msm_state->cur_state != POWER_STATE_D0_MHL) {
+ pr_debug("%s: power_state:%02x CBUS(0x0A):%02x\n",
+ __func__,
+ mhl_msm_state->cur_state, mhl_i2c_reg_read(TX_PAGE_CBUS, 0x0A));
+ return -EFAULT;
+ }
+
+ if (!req)
+ return -EFAULT;
+
+ pr_debug("%s: command=0x%02x offset=0x%02x %02x %02x",
+ __func__,
+ req->command,
+ req->offset,
+ req->payload.data[0],
+ req->payload.data[1]);
+
+ mhl_i2c_reg_write(TX_PAGE_CBUS, 0x13, req->offset);
+ mhl_i2c_reg_write(TX_PAGE_CBUS, 0x14, req->payload.data[0]);
+
+ switch (req->command) {
+ case MHL_SET_INT:
+ case MHL_WRITE_STAT:
+ start_bit = MSC_START_BIT_WRITE_REG;
+ break;
+ case MHL_READ_DEVCAP:
+ start_bit = MSC_START_BIT_READ_REG;
+ break;
+ case MHL_GET_STATE:
+ case MHL_GET_VENDOR_ID:
+ case MHL_SET_HPD:
+ case MHL_CLR_HPD:
+ case MHL_GET_SC1_ERRORCODE:
+ case MHL_GET_DDC_ERRORCODE:
+ case MHL_GET_MSC_ERRORCODE:
+ case MHL_GET_SC3_ERRORCODE:
+ start_bit = MSC_START_BIT_MSC_CMD;
+ mhl_i2c_reg_write(TX_PAGE_CBUS, 0x13, req->command);
+ break;
+ case MHL_MSC_MSG:
+ start_bit = MSC_START_BIT_VS_CMD;
+ mhl_i2c_reg_write(TX_PAGE_CBUS, 0x15, req->payload.data[1]);
+ mhl_i2c_reg_write(TX_PAGE_CBUS, 0x13, req->command);
+ break;
+ case MHL_WRITE_BURST:
+ start_bit = MSC_START_BIT_WRITE_BURST;
+ mhl_i2c_reg_write(TX_PAGE_CBUS, 0x20, req->length - 1);
+ if (!(req->payload.burst_data)) {
+ pr_err("%s: burst data is null!\n", __func__);
+ goto cbus_send_fail;
+ }
+ burst_data = req->payload.burst_data;
+ for (i = 0; i < req->length; i++, burst_data++)
+ mhl_i2c_reg_write(TX_PAGE_CBUS, 0xC0 + i, *burst_data);
+ break;
+ default:
+ pr_err("%s: unknown command! (%02x)\n",
+ __func__, req->command);
+ goto cbus_send_fail;
+ }
+
+ INIT_COMPLETION(mhl_msm_state->msc_cmd_done);
+ mhl_i2c_reg_write(TX_PAGE_CBUS, 0x12, start_bit);
+ timeout = wait_for_completion_interruptible_timeout
+ (&mhl_msm_state->msc_cmd_done, HZ);
+ if (!timeout) {
+ pr_err("%s: cbus_command_send timed out!\n", __func__);
+ goto cbus_send_fail;
+ }
+
+ switch (req->command) {
+ case MHL_READ_DEVCAP:
+ /* devcap */
+ req->retval = mhl_i2c_reg_read(TX_PAGE_CBUS, 0x16);
+ pr_debug("Read CBUS[0x16]=[%02x]\n", req->retval);
+ break;
+ case MHL_MSC_MSG:
+ /* check if MSC_MSG NACKed */
+ if (mhl_i2c_reg_read(TX_PAGE_CBUS, 0x20) & BIT6)
+ return -EAGAIN;
+ default:
+ req->retval = 0;
+ break;
+ }
+ mhl_msc_command_done(req);
+ pr_debug("%s: msc cmd done\n", __func__);
+ return 0;
+
+cbus_send_fail:
+ return -EFAULT;
+}
+
+static int mhl_msc_send_set_int(u8 offset, u8 mask)
+{
+ struct msc_command_struct req;
+ req.command = MHL_SET_INT;
+ req.offset = offset;
+ req.payload.data[0] = mask;
+ mhl_msc_sched_work(&req);
+ return 0;
+}
+
+static int mhl_msc_send_write_stat(u8 offset, u8 value)
+{
+ struct msc_command_struct req;
+ req.command = MHL_WRITE_STAT;
+ req.offset = offset;
+ req.payload.data[0] = value;
+ mhl_msc_sched_work(&req);
+ return 0;
+}
+
+static int mhl_msc_send_msc_msg(u8 sub_cmd, u8 cmd_data)
+{
+ struct msc_command_struct req;
+ req.command = MHL_MSC_MSG;
+ req.payload.data[0] = sub_cmd;
+ req.payload.data[1] = cmd_data;
+ mhl_msc_sched_work(&req);
+ return 0;
+}
+
+static int mhl_msc_read_devcap(u8 offset)
+{
+ struct msc_command_struct req;
+ if (offset < 0 || offset > 15)
+ return -EFAULT;
+ req.command = MHL_READ_DEVCAP;
+ req.offset = offset;
+ req.payload.data[0] = 0;
+ mhl_msc_sched_work(&req);
+ return 0;
+}
+
+static int mhl_msc_read_devcap_all(void)
+{
+ int offset;
+ int ret;
+
+ for (offset = 0; offset < DEVCAP_SIZE; offset++) {
+ ret = mhl_msc_read_devcap(offset);
+ msleep(200);
+ if (ret == -EFAULT) {
+ pr_err("%s: queue busy!\n", __func__);
+ return -EBUSY;
+ }
+ }
+
+ return 0;
+}
+
+/* supported RCP key code */
+static const u8 rcp_key_code_tbl[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00~0x07 */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x08~0x0f */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10~0x17 */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x18~0x1f */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20~0x27 */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x28~0x2f */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x30~0x37 */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x38~0x3f */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40~0x47 */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x48~0x4f */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50~0x57 */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x58~0x5f */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60~0x67 */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x68~0x6f */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70~0x77 */
+ 0, 0, 0, 0, 0, 0, 0, 0 /* 0x78~0x7f */
+};
+
+static int mhl_rcp_recv(u8 key_code)
+{
+ int rc;
+ if (rcp_key_code_tbl[(key_code & 0x7f)]) {
+ /*
+ * TODO: Take action for the RCP cmd
+ */
+
+ /* send ack to rcp cmd*/
+ rc = mhl_msc_send_msc_msg(
+ MHL_MSC_MSG_RCPK,
+ key_code);
+ } else {
+ /* send rcp error */
+ rc = mhl_msc_send_msc_msg(
+ MHL_MSC_MSG_RCPE,
+ MHL_RCPE_UNSUPPORTED_KEY_CODE);
+ if (rc)
+ return rc;
+ /* send rcpk after rcpe send */
+ rc = mhl_msc_send_msc_msg(
+ MHL_MSC_MSG_RCPK,
+ key_code);
+ }
+ return rc;
+}
+
+static int mhl_rap_action(u8 action_code)
+{
+ switch (action_code) {
+ case MHL_RAP_CONTENT_ON:
+ /*
+ * Enable TMDS on TMDS_CCTRL
+ */
+ mhl_i2c_reg_modify(TX_PAGE_L0, 0x0080, BIT4, BIT4);
+ break;
+ case MHL_RAP_CONTENT_OFF:
+ /*
+ * Disable TMDS on TMDS_CCTRL
+ */
+ mhl_i2c_reg_modify(TX_PAGE_L0, 0x0080, BIT4, 0x00);
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+static int mhl_rap_recv(u8 action_code)
+{
+ u8 error_code;
+
+ switch (action_code) {
+ /*case MHL_RAP_POLL:*/
+ case MHL_RAP_CONTENT_ON:
+ case MHL_RAP_CONTENT_OFF:
+ mhl_rap_action(action_code);
+ error_code = MHL_RAPK_NO_ERROR;
+ /* notify userspace */
+ break;
+ default:
+ error_code = MHL_RAPK_UNRECOGNIZED_ACTION_CODE;
+ break;
+ }
+ /* prior send rapk */
+ return mhl_msc_send_msc_msg(
+ MHL_MSC_MSG_RAPK,
+ error_code);
+}
+
+static int mhl_msc_recv_msc_msg(u8 sub_cmd, u8 cmd_data)
+{
+ int rc = 0;
+ switch (sub_cmd) {
+ case MHL_MSC_MSG_RCP:
+ pr_debug("MHL: receive RCP(0x%02x)\n", cmd_data);
+ rc = mhl_rcp_recv(cmd_data);
+ break;
+ case MHL_MSC_MSG_RCPK:
+ pr_debug("MHL: receive RCPK(0x%02x)\n", cmd_data);
+ break;
+ case MHL_MSC_MSG_RCPE:
+ pr_debug("MHL: receive RCPE(0x%02x)\n", cmd_data);
+ break;
+ case MHL_MSC_MSG_RAP:
+ pr_debug("MHL: receive RAP(0x%02x)\n", cmd_data);
+ rc = mhl_rap_recv(cmd_data);
+ break;
+ case MHL_MSC_MSG_RAPK:
+ pr_debug("MHL: receive RAPK(0x%02x)\n", cmd_data);
+ break;
+ default:
+ break;
+ }
+ return rc;
+}
+
+static int mhl_msc_recv_set_int(u8 offset, u8 set_int)
+{
+ if (offset >= 2)
+ return -EFAULT;
+
+ switch (offset) {
+ case 0:
+ /* DCAP_CHG */
+ if (set_int & MHL_INT_DCAP_CHG) {
+ /* peer dcap has changed */
+ if (mhl_msc_read_devcap_all() == -EBUSY) {
+ pr_err("READ DEVCAP FAILED to send successfully\n");
+ break;
+ }
+ }
+ /* DSCR_CHG */
+ if (set_int & MHL_INT_DSCR_CHG)
+ ;
+ /* REQ_WRT */
+ if (set_int & MHL_INT_REQ_WRT) {
+ /* SET_INT: GRT_WRT */
+ mhl_msc_send_set_int(
+ MHL_RCHANGE_INT,
+ MHL_INT_GRT_WRT);
+ }
+ /* GRT_WRT */
+ if (set_int & MHL_INT_GRT_WRT)
+ ;
+ break;
+ case 1:
+ /* EDID_CHG */
+ if (set_int & MHL_INT_EDID_CHG) {
+ /* peer EDID has changed.
+ * toggle HPD to read EDID again
+ * In 8x30 FLUID HDMI HPD line
+ * is not connected
+ * with MHL 8334 transmitter
+ */
+ }
+ }
+ return 0;
+}
+
+static int mhl_msc_recv_write_stat(u8 offset, u8 value)
+{
+ if (offset >= 2)
+ return -EFAULT;
+
+ switch (offset) {
+ case 0:
+ /* DCAP_RDY */
+ /*
+ * Connected Device bits changed and DEVCAP READY
+ */
+ pr_debug("MHL: value [0x%02x]\n", value);
+ pr_debug("MHL: offset [0x%02x]\n", offset);
+ pr_debug("MHL: devcap state [0x%02x]\n",
+ mhl_msm_state->devcap_state);
+ pr_debug("MHL: MHL_STATUS_DCAP_RDY [0x%02x]\n",
+ MHL_STATUS_DCAP_RDY);
+ if (((value ^ mhl_msm_state->devcap_state) &
+ MHL_STATUS_DCAP_RDY)) {
+ if (value & MHL_STATUS_DCAP_RDY) {
+ if (mhl_msc_read_devcap_all() == -EBUSY) {
+ pr_err("READ DEVCAP FAILED to send successfully\n");
+ break;
+ }
+ } else {
+ /* peer dcap turned not ready */
+ /*
+ * Clear DEVCAP READY state
+ */
+ }
+ }
+ break;
+ case 1:
+ /* PATH_EN */
+ /*
+ * Connected Device bits changed and PATH ENABLED
+ */
+ if ((value ^ mhl_msm_state->path_en_state)
+ & MHL_STATUS_PATH_ENABLED) {
+ if (value & MHL_STATUS_PATH_ENABLED) {
+ mhl_msm_state->path_en_state
+ |= (MHL_STATUS_PATH_ENABLED |
+ MHL_STATUS_CLK_MODE_NORMAL);
+ mhl_msc_send_write_stat(
+ MHL_STATUS_REG_LINK_MODE,
+ mhl_msm_state->path_en_state);
+ } else {
+ mhl_msm_state->path_en_state
+ &= ~(MHL_STATUS_PATH_ENABLED |
+ MHL_STATUS_CLK_MODE_NORMAL);
+ mhl_msc_send_write_stat(
+ MHL_STATUS_REG_LINK_MODE,
+ mhl_msm_state->path_en_state);
+ }
+ }
+ break;
+ }
+ mhl_msm_state->path_en_state = value;
+ return 0;
+}
+
+
static void mhl_cbus_isr(void)
{
uint8_t regval;
int req_done = FALSE;
- uint8_t sub_cmd;
- uint8_t cmd_data;
+ uint8_t sub_cmd = 0x0;
+ uint8_t cmd_data = 0x0;
int msc_msg_recved = FALSE;
int rc = -1;
@@ -982,14 +1484,17 @@
pr_debug("%s: CBUS_INT = %02x\n", __func__, regval);
/* MSC_MSG (RCP/RAP) */
- if (regval & BIT(3)) {
+ if (regval & BIT3) {
sub_cmd = mhl_i2c_reg_read(TX_PAGE_CBUS, 0x18);
cmd_data = mhl_i2c_reg_read(TX_PAGE_CBUS, 0x19);
msc_msg_recved = TRUE;
}
+ /* MSC_MT_ABRT/MSC_MR_ABRT/DDC_ABORT */
+ if (regval & (BIT6 | BIT5 | BIT2))
+ mhl_cbus_process_errors(regval);
/* MSC_REQ_DONE */
- if (regval & BIT(4))
+ if (regval & BIT4)
req_done = TRUE;
/* Now look for interrupts on CBUS_MSC_INT2 */
@@ -1003,11 +1508,15 @@
pr_debug("%s: CBUS_MSC_INT2 = %02x\n", __func__, regval);
/* received SET_INT */
- if (regval & BIT(2)) {
+ if (regval & BIT2) {
uint8_t intr;
intr = mhl_i2c_reg_read(TX_PAGE_CBUS, 0xA0);
+ mhl_msc_recv_set_int(0, intr);
+
pr_debug("%s: MHL_INT_0 = %02x\n", __func__, intr);
intr = mhl_i2c_reg_read(TX_PAGE_CBUS, 0xA1);
+ mhl_msc_recv_set_int(1, intr);
+
pr_debug("%s: MHL_INT_1 = %02x\n", __func__, intr);
mhl_i2c_reg_write(TX_PAGE_CBUS, 0xA0, 0xFF);
mhl_i2c_reg_write(TX_PAGE_CBUS, 0xA1, 0xFF);
@@ -1016,11 +1525,14 @@
}
/* received WRITE_STAT */
- if (regval & BIT(3)) {
+ if (regval & BIT3) {
uint8_t stat;
stat = mhl_i2c_reg_read(TX_PAGE_CBUS, 0xB0);
+ mhl_msc_recv_write_stat(0, stat);
+
pr_debug("%s: MHL_STATUS_0 = %02x\n", __func__, stat);
stat = mhl_i2c_reg_read(TX_PAGE_CBUS, 0xB1);
+ mhl_msc_recv_write_stat(1, stat);
pr_debug("%s: MHL_STATUS_1 = %02x\n", __func__, stat);
mhl_i2c_reg_write(TX_PAGE_CBUS, 0xB0, 0xFF);
@@ -1032,9 +1544,13 @@
/* received MSC_MSG */
if (msc_msg_recved) {
/*mhl msc recv msc msg*/
+ rc = mhl_msc_recv_msc_msg(sub_cmd, cmd_data);
if (rc)
pr_err("MHL: mhl msc recv msc msg failed(%d)!\n", rc);
}
+ /* complete last command */
+ if (req_done)
+ complete_all(&mhl_msm_state->msc_cmd_done);
return;
}
diff --git a/drivers/video/msm/mipi_dsi.c b/drivers/video/msm/mipi_dsi.c
index f08a4e4..e6e8aca 100644
--- a/drivers/video/msm/mipi_dsi.c
+++ b/drivers/video/msm/mipi_dsi.c
@@ -101,7 +101,6 @@
mdp_bus_scale_update_request(0);
#endif
- spin_lock_bh(&dsi_clk_lock);
mipi_dsi_clk_disable();
/* disbale dsi engine */
@@ -110,7 +109,6 @@
mipi_dsi_phy_ctrl(0);
mipi_dsi_ahb_ctrl(0);
- spin_unlock_bh(&dsi_clk_lock);
mipi_dsi_unprepare_clocks();
if (mipi_dsi_pdata && mipi_dsi_pdata->dsi_power_save)
diff --git a/drivers/video/msm/msm_dss_io_8x60.c b/drivers/video/msm/msm_dss_io_8x60.c
index bb6f710..c79c4c7 100644
--- a/drivers/video/msm/msm_dss_io_8x60.c
+++ b/drivers/video/msm/msm_dss_io_8x60.c
@@ -553,12 +553,8 @@
hdmi_msm_clk(1);
clk_reset(hdmi_msm_state->hdmi_app_clk, CLK_RESET_ASSERT);
- clk_reset(hdmi_msm_state->hdmi_m_pclk, CLK_RESET_ASSERT);
- clk_reset(hdmi_msm_state->hdmi_s_pclk, CLK_RESET_ASSERT);
udelay(20);
clk_reset(hdmi_msm_state->hdmi_app_clk, CLK_RESET_DEASSERT);
- clk_reset(hdmi_msm_state->hdmi_m_pclk, CLK_RESET_DEASSERT);
- clk_reset(hdmi_msm_state->hdmi_s_pclk, CLK_RESET_DEASSERT);
}
void hdmi_msm_init_phy(int video_format)
diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c
index 2c1f5b7..827a951 100644
--- a/drivers/video/msm/msm_fb.c
+++ b/drivers/video/msm/msm_fb.c
@@ -3255,7 +3255,9 @@
struct msmfb_mdp_pp *pp_ptr)
{
int ret = -1;
-
+#ifdef CONFIG_FB_MSM_MDP40
+ int i = 0;
+#endif
if (!pp_ptr)
return ret;
@@ -3263,6 +3265,15 @@
#ifdef CONFIG_FB_MSM_MDP40
case mdp_op_csc_cfg:
ret = mdp4_csc_config(&(pp_ptr->data.csc_cfg_data));
+ for (i = 0; i < CSC_MAX_BLOCKS; i++) {
+ if (pp_ptr->data.csc_cfg_data.block ==
+ csc_cfg_matrix[i].block) {
+ memcpy(&csc_cfg_matrix[i].csc_data,
+ &(pp_ptr->data.csc_cfg_data.csc_data),
+ sizeof(struct mdp_csc_cfg));
+ break;
+ }
+ }
break;
case mdp_op_pcc_cfg:
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
index 84f148f..400a3a7 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
@@ -289,6 +289,7 @@
u32 ext_enc_control_val;
u32 num_references_for_p_frame;
u32 closed_gop;
+ u32 num_slices_comp;
struct vcd_property_slice_delivery_info slice_delivery_info;
struct ddl_batch_frame_data batch_frame;
};
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c
index 95be1b6..dfbee84 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c
@@ -936,7 +936,9 @@
goto fail_enc_free_exit;
}
if (buf_size.sz_pred > 0) {
- enc_bufs->pred.mem_type = DDL_FW_MEM;
+ enc_bufs->pred.mem_type =
+ res_trk_check_for_sec_session() ?
+ DDL_MM_MEM : DDL_FW_MEM;
ptr = ddl_pmem_alloc(&enc_bufs->pred,
buf_size.sz_pred, DDL_KILO_BYTE(2));
if (!ptr)
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 c3d20cf..c1e460f 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
@@ -32,7 +32,7 @@
static void ddl_handle_enc_frame_done(struct ddl_client_context *ddl,
u32 eos_present);
static void ddl_handle_slice_done_slice_batch(struct ddl_client_context *ddl);
-static void ddl_handle_enc_frame_done_slice_mode(
+static u32 ddl_handle_enc_frame_done_slice_mode(
struct ddl_client_context *ddl, u32 eos_present);
static void ddl_handle_enc_skipframe_slice_mode(
struct ddl_client_context *ddl, u32 eos_present);
@@ -491,7 +491,7 @@
return ret_status;
}
-static void ddl_encoder_frame_run_callback(
+static u32 ddl_encoder_frame_run_callback(
struct ddl_client_context *ddl)
{
struct ddl_context *ddl_context = ddl->ddl_context;
@@ -500,6 +500,7 @@
struct vcd_frame_data *output_frame =
&(ddl->output_frame.vcd_frm);
u32 eos_present = false;
+ u32 status = true;
DDL_MSG_MED("ddl_encoder_frame_run_callback\n");
if (!DDLCLIENT_STATE_IS(ddl, DDL_CLIENT_WAIT_FOR_FRAME_DONE) &&
@@ -532,6 +533,7 @@
ddl_handle_enc_skipframe_slice_mode(
ddl, eos_present);
else
+ status =
ddl_handle_enc_frame_done_slice_mode(
ddl, eos_present);
} else {
@@ -605,6 +607,8 @@
ddl->command_channel);
}
}
+
+ return status;
}
static void get_dec_status(struct ddl_client_context *ddl,
@@ -821,7 +825,7 @@
if (ddl->cmd_state == DDL_CMD_DECODE_FRAME)
return_status = ddl_decoder_frame_run_callback(ddl);
else if (ddl->cmd_state == DDL_CMD_ENCODE_FRAME)
- ddl_encoder_frame_run_callback(ddl);
+ return_status = ddl_encoder_frame_run_callback(ddl);
else if (ddl->cmd_state == DDL_CMD_EOS)
return_status = ddl_eos_frame_done_callback(ddl);
else {
@@ -1028,6 +1032,9 @@
VIDC_1080P_RISC2HOST_CMD_SLICE_DONE_RET)
|| (ddl_hw_response->cmd ==
VIDC_1080P_RISC2HOST_CMD_FRAME_DONE_RET))) {
+ vidc_sm_get_num_slices_comp(
+ &ddl->shared_mem[ddl->command_channel],
+ &encoder->num_slices_comp);
vidc_sm_set_encoder_slice_batch_int_ctrl(
&ddl->shared_mem[ddl->command_channel],
1);
@@ -1828,7 +1835,7 @@
0);
}
-static void ddl_handle_enc_frame_done_slice_mode(
+static u32 ddl_handle_enc_frame_done_slice_mode(
struct ddl_client_context *ddl, u32 eos_present)
{
struct ddl_context *ddl_context = ddl->ddl_context;
@@ -1842,6 +1849,7 @@
u32 start_bfr_idx = 0;
u32 actual_idx = 0;
struct vcd_transc *transc;
+ u32 status = true;
DDL_MSG_LOW("%s\n", __func__);
vidc_sm_get_num_slices_comp(
@@ -1867,6 +1875,7 @@
DDL_MSG_ERROR("ERROR : %d %d\n",
encoder->slice_delivery_info.num_slices_enc,
encoder->batch_frame.num_output_frames);
+ status = false;
}
for (index = 0; index < num_slices_comp; index++) {
actual_idx =
@@ -1934,6 +1943,8 @@
sizeof(struct ddl_frame_data_tag),
(u32 *) ddl, ddl->client_data);
}
+
+ return status;
}
static void ddl_handle_enc_skipframe_slice_mode(
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
index 033457d..2d3bee3 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
@@ -1953,7 +1953,11 @@
DDL_TILE_MULTIPLY_FACTOR);
total_memory_size += component_mem_size;
} else {
- total_memory_size = frame_sz.scan_lines * frame_sz.stride;
+ if (decoding)
+ total_memory_size = frame_sz.scan_lines *
+ frame_sz.stride;
+ else
+ total_memory_size = frame_sz.height * frame_sz.stride;
c_offset = DDL_ALIGN(total_memory_size,
DDL_LINEAR_MULTIPLY_FACTOR);
total_memory_size = c_offset + DDL_ALIGN(
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
index 4072b02..04bb160 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
@@ -959,6 +959,7 @@
ddl_update_core_start_time(__func__, ENC_SLICE_OP_TIME);
ddl_set_core_start_time(__func__, ENC_OP_TIME);
}
+ encoder->num_slices_comp = 0;
ddl_vidc_encode_set_batch_slice_info(ddl);
ddl_context->vidc_encode_slice_batch_start[ddl->command_channel] (
&enc_param);
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_client_sm.c b/drivers/video/msm/vidc/common/vcd/vcd_client_sm.c
index 7c0d9fe..8f52f83 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_client_sm.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_client_sm.c
@@ -213,11 +213,11 @@
return vcd_handle_input_frame(cctxt, input_frame);
}
-static u32 vcd_pause_in_run(struct vcd_clnt_ctxt *cctxt)
+static u32 vcd_pause_cmn(struct vcd_clnt_ctxt *cctxt)
{
u32 rc = VCD_S_SUCCESS;
- VCD_MSG_LOW("vcd_pause_in_run:");
+ VCD_MSG_LOW("vcd_pause_cmn:");
if (cctxt->sched_clnt_hdl) {
rc = vcd_sched_suspend_resume_clnt(cctxt, false);
@@ -1709,7 +1709,7 @@
vcd_encode_frame_cmn,
vcd_decode_start_in_run,
vcd_decode_frame_cmn,
- vcd_pause_in_run,
+ vcd_pause_cmn,
NULL,
vcd_flush_cmn,
vcd_stop_in_run,
@@ -1784,7 +1784,7 @@
vcd_encode_frame_cmn,
NULL,
vcd_decode_frame_cmn,
- NULL,
+ vcd_pause_cmn,
NULL,
vcd_flush_in_eos,
vcd_stop_in_eos,
diff --git a/include/linux/dvb/video.h b/include/linux/dvb/video.h
index 1d750c0..81475c2 100644
--- a/include/linux/dvb/video.h
+++ b/include/linux/dvb/video.h
@@ -57,6 +57,19 @@
VIDEO_CENTER_CUT_OUT /* use center cut out format */
} video_displayformat_t;
+enum video_codec_t {
+ VIDEO_CODECTYPE_NONE,
+ VIDEO_CODECTYPE_MPEG2,
+ VIDEO_CODECTYPE_MPEG4,
+ VIDEO_CODECTYPE_H264,
+ VIDEO_CODECTYPE_VC1
+};
+
+enum video_out_format_t {
+ VIDEO_YUV_FORMAT_NV12,
+ VIDEO_YUV_FORMAT_TILE_4x2
+};
+
typedef struct {
int w;
int h;
@@ -84,12 +97,29 @@
#define VIDEO_CMD_FREEZE (2)
#define VIDEO_CMD_CONTINUE (3)
+#define VIDEO_CMD_SET_CODEC (4)
+#define VIDEO_CMD_GET_CODEC (5)
+#define VIDEO_CMD_SET_OUTPUT_FORMAT (6)
+#define VIDEO_CMD_GET_OUTPUT_FORMAT (7)
+#define VIDEO_CMD_GET_BUFFER_REQ (8)
+#define VIDEO_CMD_SET_INPUT_BUFFERS (9)
+#define VIDEO_CMD_SET_OUTPUT_BUFFERS (10)
+#define VIDEO_CMD_READ_RAW_OUTPUT (11)
+#define VIDEO_CMD_GET_PIC_RES (12)
+#define VIDEO_CMD_FREE_INPUT_BUFFERS (13)
+#define VIDEO_CMD_FREE_OUTPUT_BUFFERS (14)
+#define VIDEO_CMD_GET_H264_MV_BUFFER (15)
+#define VIDEO_CMD_SET_H264_MV_BUFFER (16)
+#define VIDEO_CMD_FREE_H264_MV_BUFFER (17)
+#define VIDEO_CMD_CLEAR_INPUT_BUFFER (18)
+#define VIDEO_CMD_CLEAR_OUTPUT_BUFFER (19)
+
/* Flags for VIDEO_CMD_FREEZE */
-#define VIDEO_CMD_FREEZE_TO_BLACK (1 << 0)
+#define VIDEO_CMD_FREEZE_TO_BLACK (1 << 0)
/* Flags for VIDEO_CMD_STOP */
-#define VIDEO_CMD_STOP_TO_BLACK (1 << 0)
-#define VIDEO_CMD_STOP_IMMEDIATELY (1 << 1)
+#define VIDEO_CMD_STOP_TO_BLACK (1 << 0)
+#define VIDEO_CMD_STOP_IMMEDIATELY (1 << 1)
/* Play input formats: */
/* The decoder has no special format requirements */
@@ -97,6 +127,56 @@
/* The decoder requires full GOPs */
#define VIDEO_PLAY_FMT_GOP (1)
+/* Picture Resolution for Video Data */
+struct video_pic_res {
+ unsigned int width;
+ unsigned int height;
+ unsigned int stride;
+ unsigned int scan_lines;
+};
+
+/* Video Buffer Properties */
+struct video_buffer_prop {
+ unsigned int alignment;
+ unsigned int buf_poolid;
+ size_t buf_size;
+};
+
+/* Buffer Requirements from Video Decoder */
+struct video_buffer_req {
+ unsigned int num_input_buffers; /* Number of Input Buffers */
+ unsigned int num_output_buffers; /* Number of Output Buffers */
+ struct video_buffer_prop input_buf_prop; /* Input Buffer Properties */
+ struct video_buffer_prop output_buf_prop; /* Output Buffer Prop */
+};
+
+/* Video Data Buffer Structure for Input and Output */
+struct video_data_buffer {
+ void __user *bufferaddr; /* Pointer to Buffer */
+ size_t buffer_len; /* Length of Buffer */
+ int ion_fd; /* file Descriptor */
+ size_t offset;
+ size_t mmaped_size;
+ void *client_data;
+ void *ip_buffer_tag;
+ __u64 pts;
+};
+
+struct video_h264_mv {
+ size_t size;
+ int count;
+ int ion_fd;
+ int offset;
+};
+
+struct video_mv_buff_size {
+ int width;
+ int height;
+ int size;
+ int alignment;
+};
+
+
/* The structure must be zeroed before use by the application
This ensures it can be extended safely in the future. */
struct video_command {
@@ -112,11 +192,23 @@
1 specifies forward single stepping,
-1 specifies backward single stepping,
>1: playback at speed/1000 of the normal speed,
- <-1: reverse playback at (-speed/1000) of the normal speed. */
+ <-1: reverse playback at (-speed/1000) of
+ the normal speed. */
__s32 speed;
__u32 format;
} play;
+ union {
+ enum video_codec_t codec; /* Video Codec Type */
+ enum video_out_format_t format; /* YUV Format */
+ struct video_pic_res frame_res; /* Frame Resolution */
+ /* Buffer Requirements for Video Decoder */
+ struct video_buffer_req buf_req;
+ struct video_data_buffer buffer; /* Buffer Details */
+ struct video_mv_buff_size mv_buffer_req;
+ struct video_h264_mv mv_buffer_prop;
+ };
+
struct {
__u32 data[16];
} raw;
@@ -126,22 +218,47 @@
/* FIELD_UNKNOWN can be used if the hardware does not know whether
the Vsync is for an odd, even or progressive (i.e. non-interlaced)
field. */
-#define VIDEO_VSYNC_FIELD_UNKNOWN (0)
-#define VIDEO_VSYNC_FIELD_ODD (1)
+#define VIDEO_VSYNC_FIELD_UNKNOWN (0)
+#define VIDEO_VSYNC_FIELD_ODD (1)
#define VIDEO_VSYNC_FIELD_EVEN (2)
#define VIDEO_VSYNC_FIELD_PROGRESSIVE (3)
struct video_event {
__s32 type;
-#define VIDEO_EVENT_SIZE_CHANGED 1
-#define VIDEO_EVENT_FRAME_RATE_CHANGED 2
-#define VIDEO_EVENT_DECODER_STOPPED 3
-#define VIDEO_EVENT_VSYNC 4
+#define VIDEO_EVENT_SIZE_CHANGED (1)
+#define VIDEO_EVENT_FRAME_RATE_CHANGED (2)
+#define VIDEO_EVENT_DECODER_STOPPED (3)
+#define VIDEO_EVENT_VSYNC (4)
+#define VIDEO_EVENT_DECODER_PLAYING (5)
+#define VIDEO_EVENT_DECODER_FREEZED (6)
+#define VIDEO_EVENT_DECODER_RESUMED (7)
+#define VIDEO_EVENT_INPUT_BUFFER_DONE (8)
+#define VIDEO_EVENT_SEQ_HDR_FOUND (9)
+#define VIDEO_EVENT_OUTPUT_BUFFER_DONE (10)
+#define VIDEO_EVENT_OUTPUT_FLUSH_DONE (11)
+#define VIDEO_EVENT_INPUT_FLUSH_DONE (12)
+#define VIDEO_EVENT_INPUT_FLUSHED (13)
+#define VIDEO_EVENT_OUTPUT_FLUSHED (14)
+
+
+ unsigned int status;
+#define VIDEO_STATUS_SUCESS 0
+#define VIDEO_STATUS_BITSTREAM_ERROR 1
+#define VIDEO_STATUS_FAILED 2
+#define VIDEO_STATUS_NORESOURCE 3
+#define VIDEO_STATUS_INVALID_CMD 4
+#define VIDEO_STATUS_INVALID_PARAM 5
+#define VIDEO_STATUS_INVALID_STATE 6
+#define VIDEO_STATUS_BUSY 7
+#define VIDEO_STATUS_INVALID_HANDLE 8
+#define VIDEO_STATUS_NO_SUPPORT 9
__kernel_time_t timestamp;
+
union {
video_size_t size;
unsigned int frame_rate; /* in frames per 1000sec */
- unsigned char vsync_field; /* unknown/odd/even/progressive */
+ unsigned char vsync_field; /* unknown/odd/even/progressive */
+ struct video_data_buffer buffer; /* Output Buffer Details */
} u;
};
@@ -149,8 +266,8 @@
struct video_status {
int video_blank; /* blank video on freeze? */
video_play_state_t play_state; /* current state of playback */
- video_stream_source_t stream_source; /* current source (demux/memory) */
- video_format_t video_format; /* current aspect ratio of stream*/
+ video_stream_source_t stream_source;/* current source (demux/memory) */
+ video_format_t video_format; /* current aspect ratio of stream*/
video_displayformat_t display_format;/* selected cropping mode */
};
@@ -160,7 +277,6 @@
__s32 size;
};
-
typedef
struct video_highlight {
int active; /* 1=show highlight, 0=hide highlight */
@@ -268,9 +384,9 @@
#define VIDEO_GET_PTS _IOR('o', 57, __u64)
/* Read the number of displayed frames since the decoder was started */
-#define VIDEO_GET_FRAME_COUNT _IOR('o', 58, __u64)
+#define VIDEO_GET_FRAME_COUNT _IOR('o', 58, __u64)
-#define VIDEO_COMMAND _IOWR('o', 59, struct video_command)
-#define VIDEO_TRY_COMMAND _IOWR('o', 60, struct video_command)
+#define VIDEO_COMMAND _IOWR('o', 59, struct video_command)
+#define VIDEO_TRY_COMMAND _IOWR('o', 60, struct video_command)
#endif /*_DVBVIDEO_H_*/
diff --git a/include/linux/leds-pm8xxx.h b/include/linux/leds-pm8xxx.h
index 60755de..ff1a93b 100644
--- a/include/linux/leds-pm8xxx.h
+++ b/include/linux/leds-pm8xxx.h
@@ -85,6 +85,7 @@
* @dig_mod_gen_en - digital module generator
* @cs_out_en - current sink output enable
* @op_fdbck - selection of output as feedback for the boost
+ * @cabc_en - enable cabc for backlight pwm control
*/
struct wled_config_data {
u8 num_strings;
@@ -95,6 +96,7 @@
bool dig_mod_gen_en;
bool cs_out_en;
bool op_fdbck;
+ bool cabc_en;
};
/**
diff --git a/include/linux/mfd/pm8xxx/core.h b/include/linux/mfd/pm8xxx/core.h
index 08e9014..38c589d 100644
--- a/include/linux/mfd/pm8xxx/core.h
+++ b/include/linux/mfd/pm8xxx/core.h
@@ -75,6 +75,27 @@
#define PM8XXX_REVISION_8917_TEST 0
#define PM8XXX_REVISION_8917_1p0 1
+#define PM8XXX_RESTART_UNKNOWN 0
+#define PM8XXX_RESTART_CBL 1
+#define PM8XXX_RESTART_KPD 2
+#define PM8XXX_RESTART_CHG 3
+#define PM8XXX_RESTART_SMPL 4
+#define PM8XXX_RESTART_RTC 5
+#define PM8XXX_RESTART_HARD_RESET 6
+#define PM8XXX_RESTART_GEN_PURPOSE 7
+#define PM8XXX_RESTART_REASON_MASK 0x07
+
+static const char * const pm8xxx_restart_reason_str[] = {
+ [0] = "Unknown",
+ [1] = "Triggered from CBL (external charger)",
+ [2] = "Triggered from KPD (power key press)",
+ [3] = "Triggered from CHG (usb charger insertion)",
+ [4] = "Triggered from SMPL (sudden momentary power loss)",
+ [5] = "Triggered from RTC (real time clock)",
+ [6] = "Triggered by Hard Reset",
+ [7] = "Triggered by General Purpose Trigger",
+};
+
struct pm8xxx_drvdata {
int (*pmic_readb) (const struct device *dev,
u16 addr, u8 *val);
@@ -88,6 +109,8 @@
int irq);
enum pm8xxx_version (*pmic_get_version) (const struct device *dev);
int (*pmic_get_revision) (const struct device *dev);
+ u8 (*pmic_restart_reason)
+ (const struct device *dev);
void *pm_chip_data;
};
@@ -156,4 +179,12 @@
return dd->pmic_get_revision(dev);
}
+static inline u8 pm8xxx_restart_reason(const struct device *dev)
+{
+ struct pm8xxx_drvdata *dd = dev_get_drvdata(dev);
+
+ if (!dd)
+ return -EINVAL;
+ return dd->pmic_restart_reason(dev);
+}
#endif
diff --git a/include/linux/mfd/pm8xxx/pm8821.h b/include/linux/mfd/pm8xxx/pm8821.h
index 7ed7617..f41a632 100644
--- a/include/linux/mfd/pm8xxx/pm8821.h
+++ b/include/linux/mfd/pm8xxx/pm8821.h
@@ -21,6 +21,7 @@
#include <linux/device.h>
#include <linux/mfd/pm8xxx/pm8821-irq.h>
#include <linux/mfd/pm8xxx/mpp.h>
+#include <linux/mfd/pm8xxx/tm.h>
#define PM8821_NR_IRQS (112)
#define PM8821_NR_MPPS (4)
@@ -38,6 +39,8 @@
PM8821_IRQ_BLOCK_BIT(PM8821_MPP_BLOCK_START, (mpp)-1))
/* PMIC Interrupts */
+#define PM8821_OVERTEMP_IRQ PM8821_IRQ_BLOCK_BIT(5, 2)
+#define PM8821_TEMPSTAT_IRQ PM8821_IRQ_BLOCK_BIT(5, 7)
struct pm8821_platform_data {
int irq_base;
diff --git a/include/linux/mfd/pm8xxx/pm8921-charger.h b/include/linux/mfd/pm8xxx/pm8921-charger.h
index 6bd4cb2..7b389c5 100644
--- a/include/linux/mfd/pm8xxx/pm8921-charger.h
+++ b/include/linux/mfd/pm8xxx/pm8921-charger.h
@@ -93,6 +93,7 @@
* however, this should only be enabled for devices which
* control the DC OVP FETs otherwise this option should
* remain disabled
+ * @has_dc_supply: report DC online if this bit is set in board file
* @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
@@ -142,6 +143,7 @@
int64_t batt_id_max;
bool keep_btm_on_suspend;
bool dc_unplug_check;
+ bool has_dc_supply;
int trkl_voltage;
int weak_voltage;
int trkl_current;
diff --git a/include/linux/mhl_8334.h b/include/linux/mhl_8334.h
index 1b19103..cb9d7fa 100644
--- a/include/linux/mhl_8334.h
+++ b/include/linux/mhl_8334.h
@@ -31,6 +31,17 @@
MHL_DISCOVERY_RESULT_MHL,
};
+struct msc_command_struct {
+ u8 command;
+ u8 offset;
+ u8 length;
+ union {
+ u8 data[16];
+ u8 *burst_data;
+ } payload;
+ u8 retval;
+};
+
/* USB driver interface */
#ifdef CONFIG_FB_MSM_HDMI_MHL_8334
@@ -59,6 +70,15 @@
}
#endif
+
+struct msc_cmd_envelope {
+ /*
+ * this list head is for list APIs
+ */
+ struct list_head msc_queue_envelope;
+ struct msc_command_struct msc_cmd_msg;
+};
+
struct mhl_msm_state_t {
struct i2c_client *i2c_client;
struct i2c_driver *i2c_driver;
@@ -68,6 +88,13 @@
/* Device Discovery stuff */
int mhl_mode;
struct completion rgnd_done;
+ struct completion msc_cmd_done;
+ uint8_t devcap_state;
+ uint8_t path_en_state;
+ struct work_struct mhl_msc_send_work;
+ struct list_head list_cmd;
+ void (*msc_command_put_work) (struct msc_command_struct *);
+ struct msc_command_struct* (*msc_command_get_work) (void);
};
enum {
diff --git a/include/linux/mhl_defs.h b/include/linux/mhl_defs.h
index 094874e..062bdf9 100644
--- a/include/linux/mhl_defs.h
+++ b/include/linux/mhl_defs.h
@@ -147,9 +147,15 @@
MHL_MSC_MSG_RAPK = 0x21,
};
-#define RCPE_NO_ERROR 0x00
-#define RCPE_INEEFECTIVE_KEY_CODE 0x01
-#define RCPE_BUSY 0x02
+#define MHL_RCPE_NO_ERROR 0x00
+#define MHL_RCPE_UNSUPPORTED_KEY_CODE 0x01
+#define MHL_RCPE_BUSY 0x02
+
+#define MHL_RAPK_NO_ERROR 0x00
+#define MHL_RAPK_UNRECOGNIZED_ACTION_CODE 0x01
+#define MHL_RAPK_UNSUPPORTED_ACTION_CODE 0x02
+#define MHL_RAPK_BUSY 0x03
+
/* MHL spec related defines*/
enum {
/* Command or Data byte acknowledge */
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index 4dd6907..e7cbb79 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -106,6 +106,7 @@
MDP_YCBCR_H1V1, /* YCbCr interleave */
MDP_BGR_565, /* BGR 565 planer */
MDP_BGR_888, /* BGR 888 */
+ MDP_Y_CBCR_H2V2_VENUS,
MDP_IMGTYPE_LIMIT,
MDP_RGB_BORDERFILL, /* border fill pipe */
MDP_FB_FORMAT = MDP_IMGTYPE2_START, /* framebuffer format */
diff --git a/include/linux/msm_rmnet.h b/include/linux/msm_rmnet.h
index 9f52464..063a8f1 100644
--- a/include/linux/msm_rmnet.h
+++ b/include/linux/msm_rmnet.h
@@ -40,6 +40,8 @@
RMNET_IOCTL_GET_OPMODE = 0x000089F7, /* Get operation mode */
RMNET_IOCTL_OPEN = 0x000089F8, /* Open transport port */
RMNET_IOCTL_CLOSE = 0x000089F9, /* Close transport port */
+ RMNET_IOCTL_FLOW_ENABLE = 0x000089FA, /* Flow enable */
+ RMNET_IOCTL_FLOW_DISABLE = 0x000089FB, /* Flow disable */
RMNET_IOCTL_MAX
};
diff --git a/include/linux/slimbus/slimbus.h b/include/linux/slimbus/slimbus.h
index a088b9c..d365b15 100644
--- a/include/linux/slimbus/slimbus.h
+++ b/include/linux/slimbus/slimbus.h
@@ -1011,6 +1011,15 @@
extern struct slim_controller *slim_busnum_to_ctrl(u32 busnum);
/*
+ * slim_ctrl_add_boarddevs: Add devices registered by board-info
+ * @ctrl: Controller to which these devices are to be added to.
+ * This API is called by controller when it is up and running.
+ * If devices on a controller were registered before controller,
+ * this will make sure that they get probed when controller is up
+ */
+extern void slim_ctrl_add_boarddevs(struct slim_controller *ctrl);
+
+/*
* slim_register_board_info: Board-initialization routine.
* @info: List of all devices on all controllers present on the board.
* @n: number of entries.
diff --git a/include/linux/tspp.h b/include/linux/tspp.h
index d5a5ffc..3f0cc81 100644
--- a/include/linux/tspp.h
+++ b/include/linux/tspp.h
@@ -24,6 +24,12 @@
TSPP_MODE_RAW_NO_SUFFIX
};
+enum tspp_tsif_mode {
+ TSPP_TSIF_MODE_LOOPBACK, /* loopback mode */
+ TSPP_TSIF_MODE_1, /* without sync */
+ TSPP_TSIF_MODE_2 /* with sync signal */
+};
+
struct tspp_filter {
int pid;
int mask;
@@ -35,6 +41,7 @@
struct tspp_select_source {
enum tspp_source source;
+ enum tspp_tsif_mode mode;
};
struct tspp_pid {
@@ -77,8 +84,5 @@
_IOW(TSPP_IOCTL_BASE, 5, struct tspp_system_keys)
#define TSPP_IOCTL_BUFFER_SIZE \
_IOW(TSPP_IOCTL_BASE, 6, struct tspp_buffer)
-#define TSPP_IOCTL_LOOPBACK \
- _IOW(TSPP_IOCTL_BASE, 0xFF, int)
-
#endif /* _TSPP_H_ */
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index 468a410..59ba64b 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -438,6 +438,7 @@
* @usb_bam_num_pipes: max number of pipes to use.
* @active_conn_num: number of active pipe connections.
* @usb_base_address: BAM physical address.
+ * @ignore_core_reset_ack: BAM can ignore ACK from USB core during PIPE RESET
*/
struct msm_usb_bam_platform_data {
struct usb_bam_pipe_connect *connections;
@@ -445,6 +446,7 @@
int usb_bam_num_pipes;
u32 total_bam_num;
u32 usb_base_address;
+ bool ignore_core_reset_ack;
};
enum usb_bam {
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 66b68d0..78b5b84 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -2088,6 +2088,8 @@
};
};
+#define V4L2_QCOM_BUF_FLAG_CODECCONFIG 0x4000
+
/* Decoder commands */
#define V4L2_DEC_CMD_START (0)
#define V4L2_DEC_CMD_STOP (1)
diff --git a/include/media/msm_camera.h b/include/media/msm_camera.h
index bd97b86..f95230e 100644
--- a/include/media/msm_camera.h
+++ b/include/media/msm_camera.h
@@ -824,29 +824,39 @@
/* extendedmode for the thumb nail image in VIDIOC_S_PARM */
#define MSM_V4L2_EXT_CAPTURE_MODE_THUMBNAIL \
(MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+4)
-#define MSM_V4L2_EXT_CAPTURE_MODE_RAW \
+/* ISP_PIX_OUTPUT1: no pp, directly send output1 buf to user */
+#define MSM_V4L2_EXT_CAPTURE_MODE_ISP_PIX_OUTPUT1 \
(MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+5)
-#define MSM_V4L2_EXT_CAPTURE_MODE_RDI \
+/* ISP_PIX_OUTPUT2: no pp, directly send output2 buf to user */
+#define MSM_V4L2_EXT_CAPTURE_MODE_ISP_PIX_OUTPUT2 \
(MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+6)
-#define MSM_V4L2_EXT_CAPTURE_MODE_RDI1 \
+/* raw image type */
+#define MSM_V4L2_EXT_CAPTURE_MODE_RAW \
(MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+7)
-#define MSM_V4L2_EXT_CAPTURE_MODE_RDI2 \
+/* RDI dump */
+#define MSM_V4L2_EXT_CAPTURE_MODE_RDI \
(MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+8)
-#define MSM_V4L2_EXT_CAPTURE_MODE_AEC \
+/* RDI dump 1 */
+#define MSM_V4L2_EXT_CAPTURE_MODE_RDI1 \
(MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+9)
-#define MSM_V4L2_EXT_CAPTURE_MODE_AWB \
+/* RDI dump 2 */
+#define MSM_V4L2_EXT_CAPTURE_MODE_RDI2 \
(MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+10)
-#define MSM_V4L2_EXT_CAPTURE_MODE_AF \
+#define MSM_V4L2_EXT_CAPTURE_MODE_AEC \
(MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+11)
-#define MSM_V4L2_EXT_CAPTURE_MODE_IHIST \
+#define MSM_V4L2_EXT_CAPTURE_MODE_AWB \
(MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+12)
-#define MSM_V4L2_EXT_CAPTURE_MODE_CS \
+#define MSM_V4L2_EXT_CAPTURE_MODE_AF \
(MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+13)
-#define MSM_V4L2_EXT_CAPTURE_MODE_RS \
+#define MSM_V4L2_EXT_CAPTURE_MODE_IHIST \
(MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+14)
-#define MSM_V4L2_EXT_CAPTURE_MODE_CSTA \
+#define MSM_V4L2_EXT_CAPTURE_MODE_CS \
(MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+15)
-#define MSM_V4L2_EXT_CAPTURE_MODE_MAX (MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+16)
+#define MSM_V4L2_EXT_CAPTURE_MODE_RS \
+ (MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+16)
+#define MSM_V4L2_EXT_CAPTURE_MODE_CSTA \
+ (MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+17)
+#define MSM_V4L2_EXT_CAPTURE_MODE_MAX (MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+18)
#define MSM_V4L2_PID_MOTION_ISO V4L2_CID_PRIVATE_BASE
#define MSM_V4L2_PID_EFFECT (V4L2_CID_PRIVATE_BASE+1)
diff --git a/include/media/radio-iris.h b/include/media/radio-iris.h
index 988de6a..ba705bd 100644
--- a/include/media/radio-iris.h
+++ b/include/media/radio-iris.h
@@ -210,8 +210,9 @@
#define HCI_FM_GET_DET_CH_TH_CMD 16
/* Defines for FM TX*/
-#define TX_PS_DATA_LENGTH 96
+#define TX_PS_DATA_LENGTH 108
#define TX_RT_DATA_LENGTH 64
+#define PS_STRING_LEN 9
/* ----- HCI Command request ----- */
struct hci_fm_recv_conf_req {
@@ -238,7 +239,7 @@
__u16 pi;
__u8 pty;
__u8 ps_repeatcount;
- __u8 ps_len;
+ __u8 ps_num;
__u8 ps_data[TX_PS_DATA_LENGTH];
} __packed;
@@ -246,7 +247,7 @@
__u8 rt_control;
__u16 pi;
__u8 pty;
- __u8 ps_len;
+ __u8 rt_len;
__u8 rt_data[TX_RT_DATA_LENGTH];
} __packed;
@@ -745,7 +746,7 @@
/* constants */
#define RDS_BLOCKS_NUM (4)
#define BYTES_PER_BLOCK (3)
-#define MAX_PS_LENGTH (96)
+#define MAX_PS_LENGTH (108)
#define MAX_RT_LENGTH (64)
#define RDS_GRP_CNTR_LEN (36)
#define RX_RT_DATA_LENGTH (63)
diff --git a/include/media/vcap_fmt.h b/include/media/vcap_fmt.h
index 00e0375..2641720 100644
--- a/include/media/vcap_fmt.h
+++ b/include/media/vcap_fmt.h
@@ -27,7 +27,8 @@
#define VCAP_VP_REG_W_ERR_EVENT 8
#define VCAP_VP_IN_HEIGHT_ERR_EVENT 9
#define VCAP_VP_IN_WIDTH_ERR_EVENT 10
-#define VCAP_MAX_NOTIFY_EVENT 11
+#define VCAP_VC_UNEXPECT_BUF_DONE 11
+#define VCAP_MAX_NOTIFY_EVENT 12
enum hal_vcap_mode {
HAL_VCAP_MODE_PRO = 0,
@@ -80,6 +81,7 @@
#define VCAPIOC_NR_S_PARAMS _IOWR('V', (BASE_VIDIOC_PRIVATE+0), struct nr_param)
#define VCAPIOC_NR_G_PARAMS _IOWR('V', (BASE_VIDIOC_PRIVATE+1), struct nr_param)
+#define VCAPIOC_S_NUM_VC_BUF _IOWR('V', (BASE_VIDIOC_PRIVATE+2), int)
struct v4l2_format_vc_ext {
enum hal_vcap_mode mode;
diff --git a/include/media/vcap_v4l2.h b/include/media/vcap_v4l2.h
index cf99435..81f7922 100644
--- a/include/media/vcap_v4l2.h
+++ b/include/media/vcap_v4l2.h
@@ -38,14 +38,16 @@
writel_relaxed(val, addr); \
} while (0)
-struct vcap_client_data;
+#define VCAP_BASE (dev->vcapbase)
+#define VCAP_OFFSET(off) (VCAP_BASE + off)
-enum rdy_buf {
- VC_NO_BUF = 0,
- VC_BUF1 = 1 << 1,
- VC_BUF2 = 1 << 2,
- VC_BUF1N2 = 0x11 << 1,
-};
+#define VCAP_SW_RESET_REQ (VCAP_BASE + 0x024)
+#define VCAP_SW_RESET_STATUS (VCAP_BASE + 0x028)
+
+#define VCAP_VP_MIN_BUF 4
+#define VCAP_VC_MAX_BUF 6
+#define VCAP_VC_MIN_BUF 2
+struct vcap_client_data;
enum vp_state {
VP_UNKNOWN = 0,
@@ -75,23 +77,18 @@
VC_AND_VP_VCAP_OP,
};
-struct vcap_action {
+struct vc_action {
struct list_head active;
/* thread for generating video stream*/
- struct task_struct *kthread;
wait_queue_head_t wq;
/* Buffer index */
- enum rdy_buf buf_ind;
+ uint8_t tot_buf;
+ uint8_t buf_num;
/* Buffers inside vc */
- struct vcap_buffer *buf1;
- struct vcap_buffer *buf2;
-
- /* Counters to control fps rate */
- int frame;
- int ini_jiffies;
+ struct vcap_buffer *buf[6];
};
struct nr_buffer {
@@ -167,8 +164,11 @@
bool vp_resource;
bool vp_dummy_event;
bool vp_dummy_complete;
+ bool vp_shutdown;
wait_queue_head_t vp_dummy_waitq;
+ uint8_t vc_tot_buf;
+
struct workqueue_struct *vcap_wq;
struct vp_work_t vp_work;
struct vp_work_t vc_to_vp_work;
@@ -204,8 +204,8 @@
struct vp_format_data vp_in_fmt;
struct vp_format_data vp_out_fmt;
- struct vcap_action vid_vc_action;
- struct vp_action vid_vp_action;
+ struct vc_action vc_action;
+ struct vp_action vp_action;
struct workqueue_struct *vcap_work_q;
struct ion_handle *vc_ion_handle;
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 71dcb28..e8c0bf3 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -1039,7 +1039,7 @@
int mgmt_connected(u16 index, bdaddr_t *bdaddr, u8 le);
int mgmt_le_conn_params(u16 index, bdaddr_t *bdaddr, u16 interval,
u16 latency, u16 timeout);
-int mgmt_disconnected(u16 index, bdaddr_t *bdaddr);
+int mgmt_disconnected(u16 index, bdaddr_t *bdaddr, u8 reason);
int mgmt_disconnect_failed(u16 index);
int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status);
int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr);
diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index 4a69331..602fe59 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -311,6 +311,7 @@
#define MGMT_EV_DISCONNECTED 0x000C
struct mgmt_ev_disconnected {
bdaddr_t bdaddr;
+ __u8 reason;
} __packed;
#define MGMT_EV_CONNECT_FAILED 0x000D
diff --git a/include/net/pkt_sched.h b/include/net/pkt_sched.h
index fffdc60..95ec28b 100644
--- a/include/net/pkt_sched.h
+++ b/include/net/pkt_sched.h
@@ -103,7 +103,8 @@
struct tcf_result *res);
extern int tc_classify(struct sk_buff *skb, const struct tcf_proto *tp,
struct tcf_result *res);
-
+extern void tc_qdisc_flow_control(struct net_device *dev, u32 tcm_handle,
+ int flow_enable);
/* Calculate maximal size of packet seen by hard_start_xmit
routine of this device.
*/
diff --git a/include/sound/apr_audio.h b/include/sound/apr_audio.h
index 382052b..90872c9 100644
--- a/include/sound/apr_audio.h
+++ b/include/sound/apr_audio.h
@@ -978,6 +978,16 @@
u32 sample_rate;
};
+struct asm_amrwbplus_cfg {
+ u32 size_bytes;
+ u32 version;
+ u32 num_channels;
+ u32 amr_band_mode;
+ u32 amr_dtx_mode;
+ u32 amr_frame_fmt;
+ u32 amr_lsf_idx;
+};
+
struct asm_flac_cfg {
u16 stream_info_present;
u16 min_blk_size;
@@ -1398,6 +1408,7 @@
struct asm_flac_cfg flac_cfg;
struct asm_vorbis_cfg vorbis_cfg;
struct asm_multi_channel_pcm_fmt_blk multi_ch_pcm_cfg;
+ struct asm_amrwbplus_cfg amrwbplus_cfg;
} __attribute__((packed)) write_cfg;
} __attribute__((packed));
diff --git a/include/sound/jack.h b/include/sound/jack.h
index 1089ba4..8e8c133 100644
--- a/include/sound/jack.h
+++ b/include/sound/jack.h
@@ -64,7 +64,7 @@
int type;
const char *id;
char name[100];
- unsigned int key[6]; /* Keep in sync with definitions above */
+ unsigned int key[8]; /* Keep in sync with definitions above */
void *private_data;
void (*private_free)(struct snd_jack *);
};
diff --git a/include/sound/q6asm.h b/include/sound/q6asm.h
index 01f2fac..323a228 100644
--- a/include/sound/q6asm.h
+++ b/include/sound/q6asm.h
@@ -288,6 +288,9 @@
int q6asm_media_format_block_aac(struct audio_client *ac,
struct asm_aac_cfg *cfg);
+int q6asm_media_format_block_amrwbplus(struct audio_client *ac,
+ struct asm_amrwbplus_cfg *cfg);
+
int q6asm_media_format_block_multi_aac(struct audio_client *ac,
struct asm_aac_cfg *cfg);
diff --git a/lib/genalloc.c b/lib/genalloc.c
index ef15640..188df2c 100644
--- a/lib/genalloc.c
+++ b/lib/genalloc.c
@@ -290,8 +290,8 @@
retry:
start_bit = bitmap_find_next_zero_area_off(chunk->bits, chunk_size,
- 0, nbits, align_mask,
- chunk->start_addr);
+ 0, nbits, align_mask,
+ chunk->start_addr >> order);
if (start_bit >= chunk_size)
continue;
remain = bitmap_set_ll(chunk->bits, start_bit, nbits);
diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c
index f504921..5ac5c52 100644
--- a/net/bluetooth/bnep/core.c
+++ b/net/bluetooth/bnep/core.c
@@ -56,6 +56,9 @@
#include "bnep.h"
#define VERSION "1.3"
+/* As this feature is dummy for BNEP net device
+** disabling support */
+#undef CONFIG_BT_BNEP_MC_FILTER
static bool compress_src = 1;
static bool compress_dst = 1;
diff --git a/net/bluetooth/bnep/netdev.c b/net/bluetooth/bnep/netdev.c
index 155ff74..a8e5449 100644
--- a/net/bluetooth/bnep/netdev.c
+++ b/net/bluetooth/bnep/netdev.c
@@ -44,6 +44,9 @@
#include "bnep.h"
#define BNEP_TX_QUEUE_LEN 20
+/* As this feature is dummy for BNEP net device
+** disabling support */
+#undef CONFIG_BT_BNEP_MC_FILTER
static int bnep_net_open(struct net_device *dev)
{
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index f57fab7..0ade089 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -206,6 +206,13 @@
}
EXPORT_SYMBOL(hci_le_remove_dev_white_list);
+static inline bool is_role_switch_possible(struct hci_dev *hdev)
+{
+ if (hci_conn_hash_lookup_state(hdev, ACL_LINK, BT_CONNECTED))
+ return false;
+ return true;
+}
+
void hci_acl_connect(struct hci_conn *conn)
{
struct hci_dev *hdev = conn->hdev;
@@ -241,7 +248,8 @@
}
cp.pkt_type = cpu_to_le16(conn->pkt_type);
- if (lmp_rswitch_capable(hdev) && !(hdev->link_mode & HCI_LM_MASTER))
+ if (lmp_rswitch_capable(hdev) && !(hdev->link_mode & HCI_LM_MASTER)
+ && is_role_switch_possible(hdev))
cp.role_switch = 0x01;
else
cp.role_switch = 0x00;
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index d3402b7..e5f43ec 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -1794,7 +1794,7 @@
struct hci_ev_disconn_complete *ev = (void *) skb->data;
struct hci_conn *conn;
- BT_DBG("%s status %d", hdev->name, ev->status);
+ BT_DBG("%s status %d reason %d", hdev->name, ev->status, ev->reason);
if (ev->status) {
hci_dev_lock(hdev);
@@ -1812,7 +1812,7 @@
conn->state = BT_CLOSED;
if (conn->type == ACL_LINK || conn->type == LE_LINK)
- mgmt_disconnected(hdev->id, &conn->dst);
+ mgmt_disconnected(hdev->id, &conn->dst, ev->reason);
if (conn->type == LE_LINK)
del_timer(&conn->smp_timer);
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index 3fa4a02..761f868 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -98,6 +98,20 @@
return 1;
}
+int l2cap_sock_le_conn_update_params_valid(struct bt_le_params *le_params)
+{
+ if (!le_params || le_params->latency > BT_LE_LATENCY_MAX ||
+ le_params->interval_min < BT_LE_CONN_INTERVAL_MIN ||
+ le_params->interval_max > BT_LE_CONN_INTERVAL_MAX ||
+ le_params->interval_min > le_params->interval_max ||
+ le_params->supervision_timeout < BT_LE_SUP_TO_MIN ||
+ le_params->supervision_timeout > BT_LE_SUP_TO_MAX) {
+ return 0;
+ }
+
+ return 1;
+}
+
static struct sock *__l2cap_get_sock_by_addr(__le16 psm, bdaddr_t *src)
{
struct sock *sk;
@@ -839,7 +853,8 @@
}
if (!conn->hcon->out ||
- !l2cap_sock_le_params_valid(&le_params)) {
+ !l2cap_sock_le_conn_update_params_valid(
+ &le_params)) {
err = -EINVAL;
break;
}
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 1702ce3..d7deaaf 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -2875,21 +2875,22 @@
mgmt_pending_remove(cmd);
}
-int mgmt_disconnected(u16 index, bdaddr_t *bdaddr)
+int mgmt_disconnected(u16 index, bdaddr_t *bdaddr, u8 reason)
{
struct mgmt_ev_disconnected ev;
struct sock *sk = NULL;
int err;
- mgmt_pending_foreach(MGMT_OP_DISCONNECT, index, disconnect_rsp, &sk);
-
bacpy(&ev.bdaddr, bdaddr);
+ ev.reason = reason;
err = mgmt_event(MGMT_EV_DISCONNECTED, index, &ev, sizeof(ev), sk);
if (sk)
sock_put(sk);
+ mgmt_pending_foreach(MGMT_OP_DISCONNECT, index, disconnect_rsp, &sk);
+
return err;
}
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c
index 3d8981f..60e2fa9 100644
--- a/net/sched/sch_api.c
+++ b/net/sched/sch_api.c
@@ -1030,6 +1030,35 @@
}
/*
+ * enable/disable flow on qdisc.
+ */
+void
+tc_qdisc_flow_control(struct net_device *dev, u32 tcm_handle, int enable_flow)
+{
+ struct Qdisc *q;
+ struct __qdisc_change_req {
+ struct nlattr attr;
+ struct tc_prio_qopt data;
+ } req = {
+ .attr = {sizeof(struct __qdisc_change_req), TCA_OPTIONS},
+ .data = {3, {1, 2, 2, 2, 1, 2, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1}, 1}
+ };
+
+ /* override flow bit */
+ req.data.enable_flow = enable_flow;
+
+ /* look up using tcm handle */
+ q = qdisc_lookup(dev, tcm_handle);
+
+ /* call registered change function */
+ if (q) {
+ if (q->ops->change(q, &(req.attr)) != 0)
+ pr_err("tc_qdisc_flow_control: qdisc change failed");
+ }
+}
+EXPORT_SYMBOL(tc_qdisc_flow_control);
+
+/*
* Create/change qdisc.
*/
diff --git a/sound/soc/codecs/cs8427.c b/sound/soc/codecs/cs8427.c
index e406a32..dc7f23b 100644
--- a/sound/soc/codecs/cs8427.c
+++ b/sound/soc/codecs/cs8427.c
@@ -740,7 +740,7 @@
unsigned char buf[CHANNEL_STATUS_SIZE];
unsigned char val = 0;
char addr = 0;
- unsigned int reset_timeout = 100;
+ unsigned int reset_timeout = 1;
int ret = 0;
struct cs8427 *chip;
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index 9881640..09cb605 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -1792,11 +1792,11 @@
0x00);
} else if ((tabla->bandgap_type == TABLA_BANDGAP_MBHC_MODE) &&
(choice == TABLA_BANDGAP_AUDIO_MODE)) {
- snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x00);
+ snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x50);
usleep_range(100, 100);
tabla_codec_enable_audio_mode_bandgap(codec);
} else if (choice == TABLA_BANDGAP_OFF) {
- snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x00);
+ snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x50);
} else {
pr_err("%s: Error, Invalid bandgap settings\n", __func__);
}
@@ -3063,6 +3063,26 @@
return 0;
}
+static int tabla_ear_pa_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+
+ pr_debug("%s %d\n", __func__, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ snd_soc_update_bits(codec, TABLA_A_RX_EAR_EN, 0x50, 0x50);
+ break;
+
+ case SND_SOC_DAPM_PRE_PMD:
+ snd_soc_update_bits(codec, TABLA_A_RX_EAR_EN, 0x10, 0x00);
+ snd_soc_update_bits(codec, TABLA_A_RX_EAR_EN, 0x40, 0x00);
+ break;
+ }
+ return 0;
+}
+
static const struct snd_soc_dapm_widget tabla_1_x_dapm_widgets[] = {
SND_SOC_DAPM_MICBIAS_E("MIC BIAS4 External", TABLA_1_A_MICB_4_CTL, 7,
0, tabla_codec_enable_micbias,
@@ -3759,6 +3779,35 @@
return 0;
}
+static void tabla_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct wcd9xxx *tabla_core = dev_get_drvdata(dai->codec->dev->parent);
+ struct tabla_priv *tabla = snd_soc_codec_get_drvdata(dai->codec);
+ u32 active = 0;
+
+ pr_debug("%s(): substream = %s stream = %d\n" , __func__,
+ substream->name, substream->stream);
+ if (tabla->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
+ return;
+
+ if (dai->id <= NUM_CODEC_DAIS) {
+ if (tabla->dai[dai->id-1].ch_mask) {
+ active = 1;
+ pr_debug("%s(): Codec DAI: chmask[%d] = 0x%x\n",
+ __func__, dai->id-1, tabla->dai[dai->id-1].ch_mask);
+ }
+ }
+
+ if ((tabla_core != NULL) &&
+ (tabla_core->dev != NULL) &&
+ (tabla_core->dev->parent != NULL) &&
+ (active == 0)) {
+ pm_runtime_mark_last_busy(tabla_core->dev->parent);
+ pm_runtime_put(tabla_core->dev->parent);
+ }
+}
+
int tabla_mclk_enable(struct snd_soc_codec *codec, int mclk_enable, bool dapm)
{
struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
@@ -4319,6 +4368,7 @@
static struct snd_soc_dai_ops tabla_dai_ops = {
.startup = tabla_startup,
+ .shutdown = tabla_shutdown,
.hw_params = tabla_hw_params,
.set_sysclk = tabla_set_dai_sysclk,
.set_fmt = tabla_set_dai_fmt,
@@ -4668,9 +4718,11 @@
/*RX stuff */
SND_SOC_DAPM_OUTPUT("EAR"),
- SND_SOC_DAPM_PGA("EAR PA", TABLA_A_RX_EAR_EN, 4, 0, NULL, 0),
+ SND_SOC_DAPM_PGA_E("EAR PA", SND_SOC_NOPM, 0, 0, NULL,
+ 0, tabla_ear_pa_event, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_PRE_PMD),
- SND_SOC_DAPM_MIXER("DAC1", TABLA_A_RX_EAR_EN, 6, 0, dac1_switch,
+ SND_SOC_DAPM_MIXER("DAC1", SND_SOC_NOPM, 0, 0, dac1_switch,
ARRAY_SIZE(dac1_switch)),
/* Headphone */
diff --git a/sound/soc/msm/Makefile b/sound/soc/msm/Makefile
index 390c314..99302eb 100644
--- a/sound/soc/msm/Makefile
+++ b/sound/soc/msm/Makefile
@@ -62,7 +62,7 @@
snd-soc-qdsp6-objs += msm-pcm-lpa.o msm-pcm-afe.o
obj-$(CONFIG_SND_SOC_QDSP6) += snd-soc-qdsp6.o
-snd-soc-msm8960-objs := msm8960.o apq8064.o msm8930.o mpq8064.o
+snd-soc-msm8960-objs := msm8960.o apq8064.o msm8930.o mpq8064.o apq8064-i2s.o
obj-$(CONFIG_SND_SOC_MSM8960) += snd-soc-msm8960.o
# Generic MSM drivers
diff --git a/sound/soc/msm/apq8064-i2s.c b/sound/soc/msm/apq8064-i2s.c
new file mode 100644
index 0000000..162f39d
--- /dev/null
+++ b/sound/soc/msm/apq8064-i2s.c
@@ -0,0 +1,2808 @@
+/* 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/clk.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/mfd/pm8xxx/pm8921.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/mfd/pm8xxx/pm8921.h>
+#include <linux/slab.h>
+#include <linux/pm_runtime.h>
+#include <linux/slimbus/slimbus.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+#include <sound/jack.h>
+#include <asm/mach-types.h>
+#include <mach/socinfo.h>
+#include "msm-pcm-routing.h"
+#include "../codecs/wcd9310.h"
+
+/* 8064 machine driver */
+
+#define PM8921_GPIO_BASE NR_GPIO_IRQS
+#define PM8921_GPIO_PM_TO_SYS(pm_gpio) (pm_gpio - 1 + PM8921_GPIO_BASE)
+
+#define MSM8064_SPK_ON 1
+#define MSM8064_SPK_OFF 0
+
+#define MSM_SLIM_0_RX_MAX_CHANNELS 2
+#define MSM_SLIM_0_TX_MAX_CHANNELS 4
+
+#define BTSCO_RATE_8KHZ 8000
+#define BTSCO_RATE_16KHZ 16000
+
+#define BOTTOM_SPK_AMP_POS 0x1
+#define BOTTOM_SPK_AMP_NEG 0x2
+#define TOP_SPK_AMP_POS 0x4
+#define TOP_SPK_AMP_NEG 0x8
+#define TOP_SPK_AMP 0x10
+
+
+#define GPIO_AUX_PCM_DOUT 43
+#define GPIO_AUX_PCM_DIN 44
+#define GPIO_AUX_PCM_SYNC 45
+#define GPIO_AUX_PCM_CLK 46
+
+#define TABLA_EXT_CLK_RATE 12288000
+
+#define TABLA_MBHC_DEF_BUTTONS 8
+#define TABLA_MBHC_DEF_RLOADS 5
+
+#define JACK_DETECT_GPIO 38
+
+#define APQ_I2S_SLAVE_CONFIG 0
+/* MCLK selection GPIOs from PMIC */
+#define PM_GPIO_MCLK_MDM 10
+#define PM_GPIO_MCLK_APQ 41
+
+/* SPKR I2S Configuration */
+#define GPIO_SPKR_I2S_MCLK 39
+#define GPIO_SPKR_I2S_SCK 40
+#define GPIO_SPKR_I2S_DOUT 41
+#define GPIO_SPKR_I2S_WS 42
+
+/* MIC I2S Configuration */
+#define GPIO_MIC_I2S_MCLK 34
+#define GPIO_MIC_I2S_SCK 35
+#define GPIO_MIC_I2S_WS 36
+#define GPIO_MIC_I2S_DIN0 37
+#define GPIO_MIC_I2S_DIN1 38
+
+/* MI2S Configuration */
+#define GPIO_MI2S_WS 27
+#define GPIO_MI2S_SCK 28
+#define GPIO_MI2S_SD3 29
+#define GPIO_MI2S_SD2 30
+#define GPIO_MI2S_SD1 31
+#define GPIO_MI2S_SD0 32
+#define GPIO_MI2S_MCLK 33
+
+struct request_gpio {
+ unsigned gpio_no;
+ char *gpio_name;
+};
+/* SD0 as RX and SD3 as TX. SD1 and SD2 are unused */
+static struct request_gpio mi2s_gpio[] = {
+ {
+ .gpio_no = GPIO_MI2S_WS,
+ .gpio_name = "MI2S_WS",
+ },
+ {
+ .gpio_no = GPIO_MI2S_SCK,
+ .gpio_name = "MI2S_SCK",
+ },
+ {
+ .gpio_no = GPIO_MI2S_SD3,
+ .gpio_name = "MI2S_SD3",
+ },
+ {
+ .gpio_no = GPIO_MI2S_SD0,
+ .gpio_name = "MI2S_SD0",
+ },
+ {
+ .gpio_no = GPIO_MI2S_MCLK,
+ .gpio_name = "MI2S_MCLK",
+ },
+};
+
+/* I2S RX is slave so MCLK is not needed */
+static struct request_gpio spkr_i2s_gpio[] = {
+ {
+ .gpio_no = GPIO_SPKR_I2S_WS,
+ .gpio_name = "SPKR_I2S_WS",
+ },
+ {
+ .gpio_no = GPIO_SPKR_I2S_SCK,
+ .gpio_name = "SPKR_I2S_SCK",
+ },
+ {
+ .gpio_no = GPIO_SPKR_I2S_DOUT,
+ .gpio_name = "SPKR_I2S_DOUT",
+ },
+};
+
+
+/* I2S TX is slave so MCLK is not needed. DIN1 is not used */
+static struct request_gpio mic_i2s_gpio[] = {
+ {
+ .gpio_no = GPIO_MIC_I2S_WS,
+ .gpio_name = "MIC_I2S_WS",
+ },
+ {
+ .gpio_no = GPIO_MIC_I2S_SCK,
+ .gpio_name = "MIC_I2S_SCK",
+ },
+ {
+ .gpio_no = GPIO_MIC_I2S_DIN0,
+ .gpio_name = "MIC_I2S_DIN",
+ },
+};
+
+/* Shared channel numbers for Slimbus ports that connect APQ to MDM. */
+enum {
+ SLIM_1_RX_1 = 145, /* BT-SCO and USB TX */
+ SLIM_1_TX_1 = 146, /* BT-SCO and USB RX */
+ SLIM_3_RX_1 = 151, /* External echo-cancellation ref */
+ SLIM_3_RX_2 = 152, /* External echo-cancellation ref */
+ SLIM_3_TX_1 = 153, /* HDMI RX */
+ SLIM_3_TX_2 = 154, /* HDMI RX */
+ SLIM_4_TX_1 = 148, /* In-call recording RX */
+ SLIM_4_TX_2 = 149, /* In-call recording RX */
+ SLIM_4_RX_1 = 150, /* In-call music delivery TX */
+};
+
+enum {
+ INCALL_REC_MONO,
+ INCALL_REC_STEREO,
+};
+
+
+#if APQ_I2S_SLAVE_CONFIG
+static u32 mdm_mclk_gpio = PM8921_GPIO_PM_TO_SYS(PM_GPIO_MCLK_MDM);
+static u32 apq_mclk_gpio = PM8921_GPIO_PM_TO_SYS(PM_GPIO_MCLK_APQ);
+#endif
+static u32 top_spk_pamp_gpio = PM8921_GPIO_PM_TO_SYS(18);
+static u32 bottom_spk_pamp_gpio = PM8921_GPIO_PM_TO_SYS(19);
+static int msm_spk_control;
+static int msm_ext_bottom_spk_pamp;
+static int msm_ext_top_spk_pamp;
+static int msm_slim_0_rx_ch = 1;
+static int msm_slim_0_tx_ch = 1;
+static int msm_slim_3_rx_ch = 1;
+
+static struct clk *i2s_rx_bit_clk;
+static struct clk *i2s_tx_bit_clk;
+
+#if (!APQ_I2S_SLAVE_CONFIG)
+static struct clk *mi2s_osr_clk;
+#endif
+static struct clk *mi2s_bit_clk;
+
+static int msm_i2s_rx_ch = 1;
+static int msm_i2s_tx_ch = 1;
+static int msm_mi2s_rx_ch = 1;
+static int msm_mi2s_tx_ch = 1;
+/* MI2S TX and RX share the same control block*/
+static atomic_t mi2s_rsc_ref;
+
+static int msm_btsco_rate = BTSCO_RATE_8KHZ;
+static int msm_btsco_ch = 1;
+
+static int rec_mode = INCALL_REC_MONO;
+
+static struct clk *codec_clk;
+static int clk_users;
+
+static struct snd_soc_jack hs_jack;
+static struct snd_soc_jack button_jack;
+
+static int apq8064_i2s_hs_detect_use_gpio = -1;
+module_param(apq8064_i2s_hs_detect_use_gpio, int, 0444);
+MODULE_PARM_DESC(apq8064_i2s_hs_detect_use_gpio, "Use GPIO for headset detection");
+
+static bool apq8064_i2s_hs_detect_use_firmware;
+module_param(apq8064_i2s_hs_detect_use_firmware, bool, 0444);
+MODULE_PARM_DESC(apq8064_i2s_hs_detect_use_firmware,
+ "Use firmware for headset detection");
+
+static int msm_enable_codec_ext_clk(struct snd_soc_codec *codec, int enable,
+ bool dapm);
+
+static struct tabla_mbhc_config mbhc_cfg = {
+ .headset_jack = &hs_jack,
+ .button_jack = &button_jack,
+ .read_fw_bin = false,
+ .calibration = NULL,
+ .micbias = TABLA_MICBIAS2,
+ .mclk_cb_fn = msm_enable_codec_ext_clk,
+ .mclk_rate = TABLA_EXT_CLK_RATE,
+ .gpio = 0,
+ .gpio_irq = 0,
+ .gpio_level_insert = 1,
+};
+
+static struct mutex cdc_mclk_mutex;
+
+static void msm_enable_ext_spk_amp_gpio(u32 spk_amp_gpio)
+{
+ int ret = 0;
+
+ struct pm_gpio param = {
+ .direction = PM_GPIO_DIR_OUT,
+ .output_buffer = PM_GPIO_OUT_BUF_CMOS,
+ .output_value = 1,
+ .pull = PM_GPIO_PULL_NO,
+ .vin_sel = PM_GPIO_VIN_S4,
+ .out_strength = PM_GPIO_STRENGTH_MED,
+ .
+ function = PM_GPIO_FUNC_NORMAL,
+ };
+
+ if (spk_amp_gpio == bottom_spk_pamp_gpio) {
+
+ ret = gpio_request(bottom_spk_pamp_gpio, "BOTTOM_SPK_AMP");
+ if (ret) {
+ pr_err("%s: Error requesting BOTTOM SPK AMP GPIO %u\n",
+ __func__, bottom_spk_pamp_gpio);
+ return;
+ }
+ ret = pm8xxx_gpio_config(bottom_spk_pamp_gpio, ¶m);
+ if (ret)
+ pr_err("%s: Failed to configure Bottom Spk Ampl gpio %u\n",
+ __func__, bottom_spk_pamp_gpio);
+ else {
+ pr_debug("%s: enable Bottom spkr amp gpio\n", __func__);
+ gpio_direction_output(bottom_spk_pamp_gpio, 1);
+ }
+
+ } else if (spk_amp_gpio == top_spk_pamp_gpio) {
+
+ ret = gpio_request(top_spk_pamp_gpio, "TOP_SPK_AMP");
+ if (ret) {
+ pr_err("%s: Error requesting GPIO %d\n", __func__,
+ top_spk_pamp_gpio);
+ return;
+ }
+ ret = pm8xxx_gpio_config(top_spk_pamp_gpio, ¶m);
+ if (ret)
+ pr_err("%s: Failed to configure Top Spk Ampl gpio %u\n",
+ __func__, top_spk_pamp_gpio);
+ else {
+ pr_debug("%s: enable Top spkr amp gpio\n", __func__);
+ gpio_direction_output(top_spk_pamp_gpio, 1);
+ }
+ } else {
+ pr_err("%s: ERROR : Invalid External Speaker Ampl GPIO gpio = %u\n",
+ __func__, spk_amp_gpio);
+ return;
+ }
+}
+
+static void msm_ext_spk_power_amp_on(u32 spk)
+{
+ if (spk & (BOTTOM_SPK_AMP_POS | BOTTOM_SPK_AMP_NEG)) {
+
+ if ((msm_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_POS) &&
+ (msm_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_NEG)) {
+
+ pr_debug("%s() External Bottom Speaker Ampl already turned on\n"
+ "spk = 0x%08x\n", __func__, spk);
+ return;
+ }
+
+ msm_ext_bottom_spk_pamp |= spk;
+
+ if ((msm_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_POS) &&
+ (msm_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_NEG)) {
+
+ msm_enable_ext_spk_amp_gpio(bottom_spk_pamp_gpio);
+ pr_debug("%s: slepping 4 ms after turning on external\n"
+ "Bottom Speaker Ampl\n", __func__);
+ usleep_range(4000, 4000);
+ }
+
+ } else if (spk & (TOP_SPK_AMP_POS | TOP_SPK_AMP_NEG | TOP_SPK_AMP)) {
+
+ pr_debug("%s():top_spk_amp_state = 0x%x spk_event = 0x%x\n",
+ __func__, msm_ext_top_spk_pamp, spk);
+
+ if (((msm_ext_top_spk_pamp & TOP_SPK_AMP_POS) &&
+ (msm_ext_top_spk_pamp & TOP_SPK_AMP_NEG)) ||
+ (msm_ext_top_spk_pamp & TOP_SPK_AMP)) {
+
+ pr_debug("%s() External Top Speaker Ampl already turned on\n"
+ "spk = 0x%08x\n", __func__, spk);
+ return;
+ }
+
+ msm_ext_top_spk_pamp |= spk;
+
+ if (((msm_ext_top_spk_pamp & TOP_SPK_AMP_POS) &&
+ (msm_ext_top_spk_pamp & TOP_SPK_AMP_NEG)) ||
+ (msm_ext_top_spk_pamp & TOP_SPK_AMP)) {
+
+ msm_enable_ext_spk_amp_gpio(top_spk_pamp_gpio);
+ pr_debug("%s: sleeping 4 ms after turning on\n"
+ "external Top Speaker Ampl\n", __func__);
+ usleep_range(4000, 4000);
+ }
+ } else {
+
+ pr_err("%s: ERROR : Invalid External Speaker Ampl. spk = 0x%08x\n",
+ __func__, spk);
+ return;
+ }
+}
+
+static void msm_ext_spk_power_amp_off(u32 spk)
+{
+ if (spk & (BOTTOM_SPK_AMP_POS | BOTTOM_SPK_AMP_NEG)) {
+
+ if (!msm_ext_bottom_spk_pamp)
+ return;
+
+ gpio_direction_output(bottom_spk_pamp_gpio, 0);
+ gpio_free(bottom_spk_pamp_gpio);
+ msm_ext_bottom_spk_pamp = 0;
+
+ pr_debug("%s: sleeping 4 ms after turning off external Bottom\n"
+ "Speaker Ampl\n", __func__);
+
+ usleep_range(4000, 4000);
+
+ } else if (spk & (TOP_SPK_AMP_POS | TOP_SPK_AMP_NEG | TOP_SPK_AMP)) {
+
+ pr_debug("%s: top_spk_amp_state = 0x%x spk_event = 0x%x\n",
+ __func__, msm_ext_top_spk_pamp, spk);
+
+ if (!msm_ext_top_spk_pamp)
+ return;
+
+ if ((spk & TOP_SPK_AMP_POS) || (spk & TOP_SPK_AMP_NEG)) {
+
+ msm_ext_top_spk_pamp &= (~(TOP_SPK_AMP_POS |
+ TOP_SPK_AMP_NEG));
+ } else if (spk & TOP_SPK_AMP) {
+ msm_ext_top_spk_pamp &= ~TOP_SPK_AMP;
+ }
+
+ if (msm_ext_top_spk_pamp)
+ return;
+
+ gpio_direction_output(top_spk_pamp_gpio, 0);
+ gpio_free(top_spk_pamp_gpio);
+ msm_ext_top_spk_pamp = 0;
+
+ pr_debug("%s: sleeping 4 ms after ext Top Spek Ampl is off\n",
+ __func__);
+
+ usleep_range(4000, 4000);
+ } else {
+
+ pr_err("%s: ERROR : Invalid Ext Spk Ampl. spk = 0x%08x\n",
+ __func__, spk);
+ return;
+ }
+}
+
+static void msm_ext_control(struct snd_soc_codec *codec)
+{
+ struct snd_soc_dapm_context *dapm = &codec->dapm;
+
+ pr_debug("%s: msm_spk_control = %d", __func__, msm_spk_control);
+ if (msm_spk_control == MSM8064_SPK_ON) {
+ snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Pos");
+ snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Neg");
+ snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Pos");
+ snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Neg");
+ } else {
+ snd_soc_dapm_disable_pin(dapm, "Ext Spk Bottom Pos");
+ snd_soc_dapm_disable_pin(dapm, "Ext Spk Bottom Neg");
+ snd_soc_dapm_disable_pin(dapm, "Ext Spk Top Pos");
+ snd_soc_dapm_disable_pin(dapm, "Ext Spk Top Neg");
+ }
+
+ snd_soc_dapm_sync(dapm);
+}
+
+static int msm_get_spk(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: msm_spk_control = %d", __func__, msm_spk_control);
+ ucontrol->value.integer.value[0] = msm_spk_control;
+ return 0;
+}
+static int msm_set_spk(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+ pr_debug("%s()\n", __func__);
+ if (msm_spk_control == ucontrol->value.integer.value[0])
+ return 0;
+
+ msm_spk_control = ucontrol->value.integer.value[0];
+ msm_ext_control(codec);
+ return 1;
+}
+static int msm_spkramp_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
+{
+ pr_debug("%s() %x\n", __func__, SND_SOC_DAPM_EVENT_ON(event));
+
+ if (SND_SOC_DAPM_EVENT_ON(event)) {
+ if (!strncmp(w->name, "Ext Spk Bottom Pos", 18))
+ msm_ext_spk_power_amp_on(BOTTOM_SPK_AMP_POS);
+ else if (!strncmp(w->name, "Ext Spk Bottom Neg", 18))
+ msm_ext_spk_power_amp_on(BOTTOM_SPK_AMP_NEG);
+ else if (!strncmp(w->name, "Ext Spk Top Pos", 15))
+ msm_ext_spk_power_amp_on(TOP_SPK_AMP_POS);
+ else if (!strncmp(w->name, "Ext Spk Top Neg", 15))
+ msm_ext_spk_power_amp_on(TOP_SPK_AMP_NEG);
+ else if (!strncmp(w->name, "Ext Spk Top", 12))
+ msm_ext_spk_power_amp_on(TOP_SPK_AMP);
+ else {
+ pr_err("%s() Invalid Speaker Widget = %s\n",
+ __func__, w->name);
+ return -EINVAL;
+ }
+
+ } else {
+ if (!strncmp(w->name, "Ext Spk Bottom Pos", 18))
+ msm_ext_spk_power_amp_off(BOTTOM_SPK_AMP_POS);
+ else if (!strncmp(w->name, "Ext Spk Bottom Neg", 18))
+ msm_ext_spk_power_amp_off(BOTTOM_SPK_AMP_NEG);
+ else if (!strncmp(w->name, "Ext Spk Top Pos", 15))
+ msm_ext_spk_power_amp_off(TOP_SPK_AMP_POS);
+ else if (!strncmp(w->name, "Ext Spk Top Neg", 15))
+ msm_ext_spk_power_amp_off(TOP_SPK_AMP_NEG);
+ else if (!strncmp(w->name, "Ext Spk Top", 12))
+ msm_ext_spk_power_amp_off(TOP_SPK_AMP);
+ else {
+ pr_err("%s() Invalid Speaker Widget = %s\n",
+ __func__, w->name);
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
+static int msm_enable_codec_ext_clk(struct snd_soc_codec *codec, int enable,
+ bool dapm)
+{
+ int r = 0;
+ pr_debug("%s: enable = %d\n", __func__, enable);
+
+ mutex_lock(&cdc_mclk_mutex);
+ if (enable) {
+ clk_users++;
+ pr_debug("%s: clk_users = %d\n", __func__, clk_users);
+ if (clk_users == 1) {
+ if (codec_clk) {
+ /*
+ * For MBHC calc, the MCLK is from APQ side
+ * so APQ has control of the MCLK at this point
+ */
+ clk_set_rate(codec_clk, TABLA_EXT_CLK_RATE);
+ clk_prepare_enable(codec_clk);
+ tabla_mclk_enable(codec, 1, dapm);
+ } else {
+ pr_err("%s: Error setting Tabla MCLK\n",
+ __func__);
+ clk_users--;
+ r = -EINVAL;
+ }
+ }
+ } else {
+ if (clk_users > 0) {
+ clk_users--;
+ pr_debug("%s: clk_users = %d\n", __func__, clk_users);
+ if (clk_users == 0) {
+ pr_debug("%s: disabling MCLK. clk_users = %d\n",
+ __func__, clk_users);
+ tabla_mclk_enable(codec, 0, dapm);
+ /*
+ * For MBHC calc, the MCLK is from APQ side
+ * so APQ has control of the MCLK at this point
+ */
+ clk_disable_unprepare(codec_clk);
+ }
+ } else {
+ pr_err("%s: Error releasing Tabla MCLK\n", __func__);
+ r = -EINVAL;
+ }
+ }
+ mutex_unlock(&cdc_mclk_mutex);
+ return r;
+}
+
+static int msm_mclk_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ pr_debug("%s: event = %d\n", __func__, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+
+ clk_users++;
+ pr_debug("%s: clk_users = %d\n", __func__, clk_users);
+
+ if (clk_users != 1)
+ return 0;
+
+ if (codec_clk) {
+ /*
+ * Since the MCLK is from MDM side so APQ side
+ * has no control of the MCLK at this point
+ */
+ /*clk_set_rate(codec_clk, TABLA_EXT_CLK_RATE);
+ clk_prepare_enable(codec_clk); */
+ tabla_mclk_enable(w->codec, 1, true);
+
+ } else {
+ pr_err("%s: Error setting Tabla MCLK\n", __func__);
+ clk_users--;
+ return -EINVAL;
+ }
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+
+ pr_debug("%s: clk_users = %d\n", __func__, clk_users);
+
+ if (clk_users == 0)
+ return 0;
+
+ clk_users--;
+
+ if (!clk_users) {
+ pr_debug("%s: disabling MCLK. clk_users = %d\n",
+ __func__, clk_users);
+
+ tabla_mclk_enable(w->codec, 0, true);
+ /*
+ * Since the MCLK is from MDM side so APQ side
+ * has no control of the MCLK at this point
+ */
+ /* clk_disable_unprepare(codec_clk); */
+ }
+ break;
+ }
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget apq8064_dapm_widgets[] = {
+
+ SND_SOC_DAPM_SUPPLY("MCLK", SND_SOC_NOPM, 0, 0,
+ msm_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_SPK("Ext Spk Bottom Pos", msm_spkramp_event),
+ SND_SOC_DAPM_SPK("Ext Spk Bottom Neg", msm_spkramp_event),
+
+ SND_SOC_DAPM_SPK("Ext Spk Top Pos", msm_spkramp_event),
+ SND_SOC_DAPM_SPK("Ext Spk Top Neg", msm_spkramp_event),
+ SND_SOC_DAPM_SPK("Ext Spk Top", msm_spkramp_event),
+
+ /************ Analog MICs ************/
+ /**
+ * Analog mic7 (Front Top) on Liquid.
+ * Used as Handset mic on CDP.
+ */
+ SND_SOC_DAPM_MIC("Analog mic7", NULL),
+
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_MIC("ANCRight Headset Mic", NULL),
+ SND_SOC_DAPM_MIC("ANCLeft Headset Mic", NULL),
+
+ /*********** Digital Mics ***************/
+ SND_SOC_DAPM_MIC("Digital Mic1", NULL),
+ SND_SOC_DAPM_MIC("Digital Mic2", NULL),
+ SND_SOC_DAPM_MIC("Digital Mic3", NULL),
+ SND_SOC_DAPM_MIC("Digital Mic4", NULL),
+ SND_SOC_DAPM_MIC("Digital Mic5", NULL),
+ SND_SOC_DAPM_MIC("Digital Mic6", NULL),
+};
+
+static const struct snd_soc_dapm_route apq8064_common_audio_map[] = {
+
+ {"RX_BIAS", NULL, "MCLK"},
+ {"LDO_H", NULL, "MCLK"},
+
+ {"HEADPHONE", NULL, "LDO_H"},
+
+ /* Speaker path */
+ {"Ext Spk Bottom Pos", NULL, "LINEOUT1"},
+ {"Ext Spk Bottom Neg", NULL, "LINEOUT3"},
+
+ {"Ext Spk Top Pos", NULL, "LINEOUT2"},
+ {"Ext Spk Top Neg", NULL, "LINEOUT4"},
+ {"Ext Spk Top", NULL, "LINEOUT5"},
+
+ /************ Analog MIC Paths ************/
+
+ /* Headset Mic */
+ {"AMIC2", NULL, "MIC BIAS2 External"},
+ {"MIC BIAS2 External", NULL, "Headset Mic"},
+
+ /* Headset ANC microphones */
+ {"AMIC3", NULL, "MIC BIAS3 Internal1"},
+ {"MIC BIAS3 Internal1", NULL, "ANCRight Headset Mic"},
+
+ {"AMIC4", NULL, "MIC BIAS1 Internal2"},
+ {"MIC BIAS1 Internal2", NULL, "ANCLeft Headset Mic"},
+};
+
+static const struct snd_soc_dapm_route apq8064_mtp_audio_map[] = {
+
+ /************ Digital MIC Paths ************/
+
+ /*
+ * Digital Mic1 (Front bottom Left) on MTP.
+ * Conncted to DMIC1 Input on Tabla codec.
+ */
+ {"DMIC1", NULL, "MIC BIAS1 External"},
+ {"MIC BIAS1 External", NULL, "Digital Mic1"},
+
+ /**
+ * Digital Mic2 (Front bottom right) on MTP.
+ * Conncted to DMIC2 Input on Tabla codec.
+ */
+ {"DMIC2", NULL, "MIC BIAS1 External"},
+ {"MIC BIAS1 External", NULL, "Digital Mic2"},
+
+ /**
+ * Digital Mic3 (Back bottom) on MTP.
+ * Conncted to DMIC3 Input on Tabla codec.
+ */
+ {"DMIC3", NULL, "MIC BIAS3 External"},
+ {"MIC BIAS3 External", NULL, "Digital Mic3"},
+
+ /**
+ * Digital Mic4 (Back top) on MTP.
+ * Conncted to DMIC4 Input on Tabla codec.
+ */
+ {"DMIC4", NULL, "MIC BIAS3 External"},
+ {"MIC BIAS3 External", NULL, "Digital Mic4"},
+
+ /**
+ * Digital Mic5 (Top front Mic) on MTP.
+ * Conncted to DMIC6 Input on Tabla codec.
+ */
+ {"DMIC6", NULL, "MIC BIAS4 External"},
+ {"MIC BIAS4 External", NULL, "Digital Mic5"},
+
+};
+
+static const struct snd_soc_dapm_route apq8064_liquid_cdp_audio_map[] = {
+
+ /************ Analog MIC Paths ************/
+ /**
+ * Analog mic7 (Front Top Mic) on Liquid.
+ * Used as Handset mic on CDP.
+ * Not there on MTP.
+ */
+ {"AMIC1", NULL, "MIC BIAS1 External"},
+ {"MIC BIAS1 External", NULL, "Analog mic7"},
+
+
+ /************ Digital MIC Paths ************/
+ /**
+ * The digital Mic routes are setup considering
+ * Liquid as default device.
+ */
+
+ /**
+ * Digital Mic1 (Front bottom left corner) on Liquid.
+ * Digital Mic2 (Front bottom right) on MTP.
+ * Digital Mic GM1 on CDP mainboard.
+ * Conncted to DMIC2 Input on Tabla codec.
+ */
+ {"DMIC2", NULL, "MIC BIAS1 External"},
+ {"MIC BIAS1 External", NULL, "Digital Mic1"},
+
+ /**
+ * Digital Mic2 (Front left side) on Liquid.
+ * Digital Mic GM2 on CDP mainboard.
+ * Not there on MTP.
+ * Conncted to DMIC3 Input on Tabla codec.
+ */
+ {"DMIC3", NULL, "MIC BIAS3 External"},
+ {"MIC BIAS3 External", NULL, "Digital Mic2"},
+
+ /**
+ * Digital Mic3. Front bottom left of middle on Liquid.
+ * Digital Mic5 (Top front Mic) on MTP.
+ * Digital Mic GM5 on CDP mainboard.
+ * Conncted to DMIC6 Input on Tabla codec.
+ */
+ {"DMIC6", NULL, "MIC BIAS4 External"},
+ {"MIC BIAS4 External", NULL, "Digital Mic3"},
+
+ /**
+ * Digital Mic4. Back bottom on Liquid.
+ * Digital Mic GM3 on CDP mainboard.
+ * Top Front Mic on MTP.
+ * Conncted to DMIC5 Input on Tabla codec.
+ */
+ {"DMIC5", NULL, "MIC BIAS4 External"},
+ {"MIC BIAS4 External", NULL, "Digital Mic4"},
+
+ /**
+ * Digital Mic5. Front bottom right of middle on Liquid.
+ * Digital Mic GM6 on CDP mainboard.
+ * Not there on MTP.
+ * Conncted to DMIC4 Input on Tabla codec.
+ */
+ {"DMIC4", NULL, "MIC BIAS3 External"},
+ {"MIC BIAS3 External", NULL, "Digital Mic5"},
+
+ /* Digital Mic6 (Front bottom right corner) on Liquid.
+ * Digital Mic1 (Front bottom Left) on MTP.
+ * Digital Mic GM4 on CDP.
+ * Conncted to DMIC1 Input on Tabla codec.
+ */
+ {"DMIC1", NULL, "MIC BIAS1 External"},
+ {"MIC BIAS1 External", NULL, "Digital Mic6"},
+};
+
+static const char * const spk_function[] = {"Off", "On"};
+static const char * const rx_ch_text[] = {"One", "Two"};
+static const char * const tx_ch_text[] = {"One", "Two", "Three", "Four"};
+
+static const struct soc_enum msm_enum[] = {
+ SOC_ENUM_SINGLE_EXT(2, spk_function),
+ SOC_ENUM_SINGLE_EXT(2, rx_ch_text),
+ SOC_ENUM_SINGLE_EXT(4, tx_ch_text),
+};
+
+static const char * const btsco_rate_text[] = {"8000", "16000"};
+static const struct soc_enum msm_btsco_enum[] = {
+ SOC_ENUM_SINGLE_EXT(2, btsco_rate_text),
+};
+
+static int msm_slim_0_rx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: msm_slim_0_rx_ch = %d\n", __func__,
+ msm_slim_0_rx_ch);
+ ucontrol->value.integer.value[0] = msm_slim_0_rx_ch - 1;
+ return 0;
+}
+
+static int msm_slim_0_rx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ msm_slim_0_rx_ch = ucontrol->value.integer.value[0] + 1;
+
+ pr_debug("%s: msm_slim_0_rx_ch = %d\n", __func__,
+ msm_slim_0_rx_ch);
+ return 1;
+}
+
+static int msm_slim_0_tx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: msm_slim_0_tx_ch = %d\n", __func__,
+ msm_slim_0_tx_ch);
+ ucontrol->value.integer.value[0] = msm_slim_0_tx_ch - 1;
+ return 0;
+}
+
+static int msm_slim_0_tx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ msm_slim_0_tx_ch = ucontrol->value.integer.value[0] + 1;
+
+ pr_debug("%s: msm_slim_0_tx_ch = %d\n", __func__,
+ msm_slim_0_tx_ch);
+ return 1;
+}
+
+static int msm_slim_3_rx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: msm_slim_3_rx_ch = %d\n", __func__,
+ msm_slim_3_rx_ch);
+ ucontrol->value.integer.value[0] = msm_slim_3_rx_ch - 1;
+ return 0;
+}
+
+static int msm_slim_3_rx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ msm_slim_3_rx_ch = ucontrol->value.integer.value[0] + 1;
+
+ pr_debug("%s: msm_slim_3_rx_ch = %d\n", __func__,
+ msm_slim_3_rx_ch);
+ return 1;
+}
+
+static int msm_btsco_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: msm_btsco_rate = %d", __func__,
+ msm_btsco_rate);
+ ucontrol->value.integer.value[0] = msm_btsco_rate;
+ return 0;
+}
+
+static int msm_btsco_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ switch (ucontrol->value.integer.value[0]) {
+ case 8000:
+ msm_btsco_rate = BTSCO_RATE_8KHZ;
+ break;
+ case 16000:
+ msm_btsco_rate = BTSCO_RATE_16KHZ;
+ break;
+ default:
+ msm_btsco_rate = BTSCO_RATE_8KHZ;
+ break;
+ }
+ pr_debug("%s: msm_btsco_rate = %d\n", __func__,
+ msm_btsco_rate);
+ return 0;
+}
+
+static int msm_incall_rec_mode_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = rec_mode;
+ return 0;
+}
+
+static int msm_incall_rec_mode_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+
+ rec_mode = ucontrol->value.integer.value[0];
+ pr_debug("%s: rec_mode:%d\n", __func__, rec_mode);
+
+ return 0;
+}
+
+static const struct snd_kcontrol_new tabla_msm_controls[] = {
+ SOC_ENUM_EXT("Speaker Function", msm_enum[0], msm_get_spk,
+ msm_set_spk),
+ SOC_ENUM_EXT("SLIM_0_RX Channels", msm_enum[1],
+ msm_slim_0_rx_ch_get, msm_slim_0_rx_ch_put),
+ SOC_ENUM_EXT("SLIM_0_TX Channels", msm_enum[2],
+ msm_slim_0_tx_ch_get, msm_slim_0_tx_ch_put),
+ SOC_ENUM_EXT("Internal BTSCO SampleRate", msm_btsco_enum[0],
+ msm_btsco_rate_get, msm_btsco_rate_put),
+ SOC_SINGLE_EXT("Incall Rec Mode", SND_SOC_NOPM, 0, 1, 0,
+ msm_incall_rec_mode_get, msm_incall_rec_mode_put),
+ SOC_ENUM_EXT("SLIM_3_RX Channels", msm_enum[1],
+ msm_slim_3_rx_ch_get, msm_slim_3_rx_ch_put),
+};
+
+
+static int msm_mi2s_rx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: msm_mi2s_rx_ch = %d\n", __func__,
+ msm_mi2s_rx_ch);
+ ucontrol->value.integer.value[0] = msm_mi2s_rx_ch - 1;
+ return 0;
+}
+
+static int msm_mi2s_rx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ msm_mi2s_rx_ch = ucontrol->value.integer.value[0] + 1;
+
+ pr_debug("%s: msm_mi2s_rx_ch = %d\n", __func__,
+ msm_mi2s_rx_ch);
+ return 1;
+}
+
+static int msm_mi2s_tx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: msm_mi2s_tx_ch = %d\n", __func__,
+ msm_mi2s_tx_ch);
+ ucontrol->value.integer.value[0] = msm_mi2s_tx_ch - 1;
+ return 0;
+}
+
+static int msm_mi2s_tx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ msm_mi2s_tx_ch = ucontrol->value.integer.value[0] + 1;
+
+ pr_debug("%s: msm_mi2s_tx_ch = %d\n", __func__,
+ msm_mi2s_tx_ch);
+ return 1;
+}
+
+static int msm_mi2s_get_spk(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: msm_spk_control = %d", __func__, msm_spk_control);
+ ucontrol->value.integer.value[0] = msm_spk_control;
+ return 0;
+}
+static int msm_mi2s_set_spk(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+ pr_debug("%s()\n", __func__);
+ if (msm_spk_control == ucontrol->value.integer.value[0])
+ return 0;
+
+ msm_spk_control = ucontrol->value.integer.value[0];
+ msm_ext_control(codec);
+ return 1;
+}
+
+static int msm_mi2s_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ pr_debug("%s()\n", __func__);
+ rate->min = rate->max = 48000;
+ channels->min = channels->max = msm_mi2s_rx_ch;
+
+ return 0;
+}
+
+static int msm_mi2s_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ pr_debug("%s()\n", __func__);
+ rate->min = rate->max = 48000;
+
+ channels->min = channels->max = msm_mi2s_tx_ch;
+
+ return 0;
+}
+
+
+static int msm_i2s_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ pr_debug("%s()\n", __func__);
+ rate->min = rate->max = 48000;
+ channels->min = channels->max = msm_i2s_rx_ch;
+
+ return 0;
+}
+
+static int msm_i2s_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ pr_debug("%s()\n", __func__);
+ rate->min = rate->max = 48000;
+
+ channels->min = channels->max = msm_i2s_tx_ch;
+
+ return 0;
+}
+
+static const struct snd_kcontrol_new tabla_msm_mi2s_controls[] = {
+ SOC_ENUM_EXT("Speaker Function", msm_enum[0], msm_mi2s_get_spk,
+ msm_mi2s_set_spk),
+ SOC_ENUM_EXT("MI2S_RX Channels", msm_enum[1],
+ msm_mi2s_rx_ch_get, msm_mi2s_rx_ch_put),
+ SOC_ENUM_EXT("MI2S_TX Channels", msm_enum[2],
+ msm_mi2s_tx_ch_get, msm_mi2s_tx_ch_put),
+ SOC_ENUM_EXT("Internal BTSCO SampleRate", msm_btsco_enum[0],
+ msm_btsco_rate_get, msm_btsco_rate_put),
+ SOC_SINGLE_EXT("Incall Rec Mode", SND_SOC_NOPM, 0, 1, 0,
+ msm_incall_rec_mode_get, msm_incall_rec_mode_put),
+};
+
+static int msm_mi2s_audrx_init(struct snd_soc_pcm_runtime *rtd)
+{
+ int ret;
+ uint32_t revision;
+ struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_dapm_context *dapm = &codec->dapm;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+
+#if APQ_I2S_SLAVE_CONFIG
+ struct pm_gpio param = {
+ .direction = PM_GPIO_DIR_OUT,
+ .output_buffer = PM_GPIO_OUT_BUF_CMOS,
+ .output_value = 1,
+ .pull = PM_GPIO_PULL_NO,
+ .vin_sel = PM_GPIO_VIN_S4,
+ .out_strength = PM_GPIO_STRENGTH_MED,
+ .function = PM_GPIO_FUNC_NORMAL,
+ };
+#endif
+ pr_debug("%s(), dev_name(%s)\n", __func__, dev_name(cpu_dai->dev));
+ ret = gpio_request(GPIO_MI2S_MCLK, "MI2S_MCLK");
+ if (ret)
+ pr_err("%s: Failed to request gpio %d\n", __func__,
+ GPIO_MI2S_MCLK);
+
+#if APQ_I2S_SLAVE_CONFIG
+ /* APQ provides the mclk to codec */
+ ret = gpio_request(mdm_mclk_gpio, "MDM_MCLK_SWITCH");
+ if (ret) {
+ pr_err("%s: Failed to request gpio %d\n", __func__,
+ mdm_mclk_gpio);
+ return ret;
+ }
+ ret = pm8xxx_gpio_config(mdm_mclk_gpio, ¶m);
+ if (ret)
+ pr_err("%s: Failed to configure gpio %d\n", __func__,
+ mdm_mclk_gpio);
+ else
+ gpio_direction_output(mdm_mclk_gpio, 0);
+
+ ret = gpio_request(apq_mclk_gpio, "APQ_MCLK_SWITCH");
+ if (ret) {
+ pr_err("%s: Failed to request gpio %d\n", __func__,
+ apq_mclk_gpio);
+ return ret;
+ }
+ ret = pm8xxx_gpio_config(apq_mclk_gpio, ¶m);
+ if (ret)
+ pr_err("%s: Failed to configure gpio %d\n", __func__,
+ apq_mclk_gpio);
+ else
+ gpio_direction_output(apq_mclk_gpio, 1);
+ pr_debug("%s: Config mdm_mclk_gpio and apq_mclk_gpio\n",
+ __func__);
+#else
+ pr_debug("%s: Not config mdm_mclk_gpio and apq_mclk_gpio\n",
+ __func__);
+#endif
+ snd_soc_dapm_new_controls(dapm, apq8064_dapm_widgets,
+ ARRAY_SIZE(apq8064_dapm_widgets));
+
+ snd_soc_dapm_add_routes(dapm, apq8064_common_audio_map,
+ ARRAY_SIZE(apq8064_common_audio_map));
+
+ if (machine_is_apq8064_mtp()) {
+ snd_soc_dapm_add_routes(dapm, apq8064_mtp_audio_map,
+ ARRAY_SIZE(apq8064_mtp_audio_map));
+ } else {
+ snd_soc_dapm_add_routes(dapm, apq8064_liquid_cdp_audio_map,
+ ARRAY_SIZE(apq8064_liquid_cdp_audio_map));
+ }
+
+ snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Pos");
+ snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Neg");
+ snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Pos");
+ snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Neg");
+
+ snd_soc_dapm_sync(dapm);
+
+ ret = snd_soc_jack_new(codec, "Headset Jack",
+ (SND_JACK_HEADSET | SND_JACK_OC_HPHL |
+ SND_JACK_OC_HPHR | SND_JACK_UNSUPPORTED),
+ &hs_jack);
+ if (ret) {
+ pr_err("failed to create new jack\n");
+ return ret;
+ }
+
+ ret = snd_soc_jack_new(codec, "Button Jack",
+ TABLA_JACK_BUTTON_MASK, &button_jack);
+ if (ret) {
+ pr_err("failed to create new jack\n");
+ return ret;
+ }
+ /* Get the MCLK from MI2S block for MBHC calibration */
+ codec_clk = clk_get(cpu_dai->dev, "osr_clk");
+ pr_debug("%s: Device name is %s\n", __func__, dev_name(cpu_dai->dev));
+
+ /* APQ8064 Rev 1.1 CDP and Liquid have mechanical switch */
+ revision = socinfo_get_version();
+ if (apq8064_i2s_hs_detect_use_gpio != -1) {
+ if (apq8064_i2s_hs_detect_use_gpio == 1)
+ pr_debug("%s: MBHC mechanical is enabled by request\n",
+ __func__);
+ else if (apq8064_i2s_hs_detect_use_gpio == 0)
+ pr_debug("%s: MBHC mechanical is disabled by request\n",
+ __func__);
+ else
+ pr_warn("%s: Invalid hs_detect_use_gpio %d\n", __func__,
+ apq8064_i2s_hs_detect_use_gpio);
+ } else if (SOCINFO_VERSION_MAJOR(revision) == 0) {
+ pr_warn("%s: Unknown HW revision detected %d.%d\n", __func__,
+ SOCINFO_VERSION_MAJOR(revision),
+ SOCINFO_VERSION_MINOR(revision));
+ } else if ((SOCINFO_VERSION_MAJOR(revision) == 1 &&
+ SOCINFO_VERSION_MINOR(revision) >= 1 &&
+ (machine_is_apq8064_cdp() ||
+ machine_is_apq8064_liquid())) ||
+ SOCINFO_VERSION_MAJOR(revision) > 1) {
+ pr_debug("%s: MBHC mechanical switch available APQ8064 detected\n",
+ __func__);
+ apq8064_i2s_hs_detect_use_gpio = 1;
+ }
+
+ if (apq8064_i2s_hs_detect_use_gpio == 1) {
+ pr_debug("%s: Using MBHC mechanical switch\n", __func__);
+ mbhc_cfg.gpio = JACK_DETECT_GPIO;
+ mbhc_cfg.gpio_irq = gpio_to_irq(JACK_DETECT_GPIO);
+ ret = gpio_request(mbhc_cfg.gpio, "MBHC_HS_DETECT");
+ if (ret < 0) {
+ pr_err("%s: gpio_request %d failed %d\n", __func__,
+ mbhc_cfg.gpio, ret);
+ return ret;
+ }
+ gpio_direction_input(JACK_DETECT_GPIO);
+ } else
+ pr_debug("%s: Not using MBHC mechanical switch\n", __func__);
+
+ mbhc_cfg.read_fw_bin = apq8064_i2s_hs_detect_use_firmware;
+
+ ret = tabla_hs_detect(codec, &mbhc_cfg);
+
+#if APQ_I2S_SLAVE_CONFIG
+ /* MDM provides the mclk to codec */
+ gpio_direction_output(apq_mclk_gpio, 0);
+ gpio_direction_output(mdm_mclk_gpio, 1);
+ pr_debug("%s: Should not running here if no clock switch\n", __func__);
+#endif
+ /* Should we add code to put back codec clock?*/
+ gpio_free(GPIO_MI2S_MCLK);
+ pr_debug("%s: Free MCLK GPIO\n", __func__);
+ return ret;
+}
+
+static int msm_mi2s_free_gpios(void)
+{
+ int i;
+ for (i = 0; i < ARRAY_SIZE(mi2s_gpio); i++)
+ gpio_free(mi2s_gpio[i].gpio_no);
+ return 0;
+}
+
+static void msm_mi2s_shutdown(struct snd_pcm_substream *substream)
+{
+
+ if (atomic_dec_return(&mi2s_rsc_ref) == 0) {
+ pr_debug("%s: free mi2s resources\n", __func__);
+ if (mi2s_bit_clk) {
+ clk_disable_unprepare(mi2s_bit_clk);
+ clk_put(mi2s_bit_clk);
+ mi2s_bit_clk = NULL;
+ }
+#if (!APQ_I2S_SLAVE_CONFIG)
+ if (mi2s_osr_clk) {
+ clk_disable_unprepare(mi2s_osr_clk);
+ clk_put(mi2s_osr_clk);
+ mi2s_osr_clk = NULL;
+ }
+#endif
+ msm_mi2s_free_gpios();
+ }
+}
+
+static int msm_configure_mi2s_gpio(void)
+{
+ int rtn;
+ int i;
+ int j;
+ for (i = 0; i < ARRAY_SIZE(mi2s_gpio); i++) {
+ rtn = gpio_request(mi2s_gpio[i].gpio_no,
+ mi2s_gpio[i].gpio_name);
+ pr_debug("%s: gpio = %d, gpio name = %s, rtn = %d\n",
+ __func__,
+ mi2s_gpio[i].gpio_no,
+ mi2s_gpio[i].gpio_name,
+ rtn);
+ if (rtn) {
+ pr_err("%s: Failed to request gpio %d\n",
+ __func__,
+ mi2s_gpio[i].gpio_no);
+ for (j = i; j >= 0; j--)
+ gpio_free(mi2s_gpio[j].gpio_no);
+ goto err;
+ }
+ }
+err:
+ return rtn;
+}
+
+static int msm_mi2s_startup(struct snd_pcm_substream *substream)
+{
+ int ret = 0;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+
+ pr_debug("%s: dai name %s %p\n", __func__, cpu_dai->name, cpu_dai->dev);
+
+ if (atomic_inc_return(&mi2s_rsc_ref) == 1) {
+ pr_debug("%s: acquire mi2s resources\n", __func__);
+ msm_configure_mi2s_gpio();
+
+#if APQ_I2S_SLAVE_CONFIG
+ pr_debug("%s: APQ is MI2S slave\n", __func__);
+ mi2s_bit_clk = clk_get(cpu_dai->dev, "bit_clk");
+ if (IS_ERR(mi2s_bit_clk))
+ return PTR_ERR(mi2s_bit_clk);
+ clk_set_rate(mi2s_bit_clk, 0);
+ ret = clk_prepare_enable(mi2s_bit_clk);
+ if (IS_ERR_VALUE(ret)) {
+ pr_err("Unable to enable mi2s_bit_clk\n");
+ clk_put(mi2s_bit_clk);
+ return ret;
+ }
+ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBM_CFM);
+ if (IS_ERR_VALUE(ret))
+ pr_err("set format for CPU dai failed\n");
+#else
+ pr_debug("%s: APQ is MI2S master\n", __func__);
+ mi2s_osr_clk = clk_get(cpu_dai->dev, "osr_clk");
+ if (IS_ERR(mi2s_osr_clk))
+ return PTR_ERR(mi2s_osr_clk);
+ clk_set_rate(mi2s_osr_clk, TABLA_EXT_CLK_RATE);
+ ret = clk_prepare_enable(mi2s_osr_clk);
+ if (IS_ERR_VALUE(ret)) {
+ pr_err("Unable to enable mi2s_osr_clk\n");
+ clk_put(mi2s_osr_clk);
+ return ret;
+ }
+ mi2s_bit_clk = clk_get(cpu_dai->dev, "bit_clk");
+ if (IS_ERR(mi2s_bit_clk)) {
+ pr_err("Unable to get mi2s_bit_clk\n");
+ clk_disable_unprepare(mi2s_osr_clk);
+ clk_put(mi2s_osr_clk);
+ return PTR_ERR(mi2s_bit_clk);
+ }
+ clk_set_rate(mi2s_bit_clk, 8);
+ ret = clk_prepare_enable(mi2s_bit_clk);
+ if (IS_ERR_VALUE(ret)) {
+ pr_err("Unable to enable mi2s_bit_clk\n");
+ clk_disable_unprepare(mi2s_osr_clk);
+ clk_put(mi2s_osr_clk);
+ clk_put(mi2s_bit_clk);
+ return ret;
+ }
+ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBS_CFS);
+ if (IS_ERR_VALUE(ret))
+ pr_err("set format for CPU dai failed\n");
+#endif
+ }
+
+ return ret;
+}
+
+
+static int msm_i2s_rx_free_gpios(void)
+{
+ int i;
+ for (i = 0; i < ARRAY_SIZE(spkr_i2s_gpio); i++)
+ gpio_free(spkr_i2s_gpio[i].gpio_no);
+ return 0;
+}
+
+
+static int msm_i2s_tx_free_gpios(void)
+{
+ int i;
+ for (i = 0; i < ARRAY_SIZE(mic_i2s_gpio); i++)
+ gpio_free(mic_i2s_gpio[i].gpio_no);
+ return 0;
+}
+
+static void msm_i2s_shutdown(struct snd_pcm_substream *substream)
+{
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ pr_debug("%s: free i2s rx resources\n", __func__);
+ if (i2s_rx_bit_clk) {
+ clk_disable_unprepare(i2s_rx_bit_clk);
+ clk_put(i2s_rx_bit_clk);
+ i2s_rx_bit_clk = NULL;
+ }
+ msm_i2s_rx_free_gpios();
+ } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ pr_debug("%s: free i2s tx resources\n", __func__);
+ if (i2s_tx_bit_clk) {
+ clk_disable_unprepare(i2s_tx_bit_clk);
+ clk_put(i2s_tx_bit_clk);
+ i2s_tx_bit_clk = NULL;
+ }
+ msm_i2s_tx_free_gpios();
+ }
+}
+
+static int msm_configure_i2s_rx_gpio(void)
+{
+ int rtn;
+ int i;
+ int j;
+ for (i = 0; i < ARRAY_SIZE(spkr_i2s_gpio); i++) {
+ rtn = gpio_request(spkr_i2s_gpio[i].gpio_no,
+ spkr_i2s_gpio[i].gpio_name);
+ pr_debug("%s: gpio = %d, gpio name = %s, rtn = %d\n",
+ __func__,
+ spkr_i2s_gpio[i].gpio_no,
+ spkr_i2s_gpio[i].gpio_name,
+ rtn);
+ if (rtn) {
+ pr_err("%s: Failed to request gpio %d\n",
+ __func__,
+ spkr_i2s_gpio[i].gpio_no);
+ for (j = i; j >= 0; j--)
+ gpio_free(spkr_i2s_gpio[j].gpio_no);
+ goto err;
+ }
+ }
+err:
+ return rtn;
+}
+
+static int msm_configure_i2s_tx_gpio(void)
+{
+ int rtn;
+ int i;
+ int j;
+ for (i = 0; i < ARRAY_SIZE(mic_i2s_gpio); i++) {
+ rtn = gpio_request(mic_i2s_gpio[i].gpio_no,
+ mic_i2s_gpio[i].gpio_name);
+ pr_debug("%s: gpio = %d, gpio name = %s, rtn = %d\n",
+ __func__,
+ mic_i2s_gpio[i].gpio_no,
+ mic_i2s_gpio[i].gpio_name,
+ rtn);
+ if (rtn) {
+ pr_err("%s: Failed to request gpio %d\n",
+ __func__,
+ mic_i2s_gpio[i].gpio_no);
+ for (j = i; j >= 0; j--)
+ gpio_free(mic_i2s_gpio[j].gpio_no);
+ goto err;
+ }
+ }
+err:
+ return rtn;
+}
+
+static int msm_i2s_startup(struct snd_pcm_substream *substream)
+{
+ int ret = 0;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ msm_configure_i2s_rx_gpio();
+ i2s_rx_bit_clk = clk_get(cpu_dai->dev, "bit_clk");
+ if (IS_ERR(i2s_rx_bit_clk)) {
+ pr_err("Failed to get i2s bit_clk\n");
+ return PTR_ERR(i2s_rx_bit_clk);
+ }
+ clk_set_rate(i2s_rx_bit_clk, 0);
+ ret = clk_prepare_enable(i2s_rx_bit_clk);
+ if (IS_ERR_VALUE(ret)) {
+ pr_err("Unable to enable i2s_rx_bit_clk\n");
+ clk_put(i2s_rx_bit_clk);
+ return ret;
+ }
+ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBM_CFM);
+ if (IS_ERR_VALUE(ret))
+ pr_err("set format for CPU dai failed\n");
+ } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ msm_configure_i2s_tx_gpio();
+ i2s_tx_bit_clk = clk_get(cpu_dai->dev, "bit_clk");
+ if (IS_ERR(i2s_tx_bit_clk)) {
+ pr_err("Failed to get i2s_tx_bit_clk\n");
+ return PTR_ERR(i2s_tx_bit_clk);
+ }
+ clk_set_rate(i2s_tx_bit_clk, 0);
+ ret = clk_prepare_enable(i2s_tx_bit_clk);
+ if (ret != 0) {
+ pr_err("Unable to enable i2s_tx_bit_clk\n");
+ clk_put(i2s_tx_bit_clk);
+ return ret;
+ }
+ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBM_CFM);
+ if (IS_ERR_VALUE(ret))
+ pr_err("set format for CPU dai failed\n");
+ }
+
+ pr_debug("%s: ret = %d\n", __func__, ret);
+ pr_debug("%s(): substream = %s stream = %d\n", __func__,
+ substream->name, substream->stream);
+ return ret;
+}
+
+static void *def_tabla_mbhc_cal(void)
+{
+ void *tabla_cal;
+ struct tabla_mbhc_btn_detect_cfg *btn_cfg;
+ u16 *btn_low, *btn_high;
+ u8 *n_ready, *n_cic, *gain;
+
+ tabla_cal = kzalloc(TABLA_MBHC_CAL_SIZE(TABLA_MBHC_DEF_BUTTONS,
+ TABLA_MBHC_DEF_RLOADS),
+ GFP_KERNEL);
+ if (!tabla_cal) {
+ pr_err("%s: out of memory\n", __func__);
+ return NULL;
+ }
+
+#define S(X, Y) ((TABLA_MBHC_CAL_GENERAL_PTR(tabla_cal)->X) = (Y))
+ S(t_ldoh, 100);
+ S(t_bg_fast_settle, 100);
+ S(t_shutdown_plug_rem, 255);
+ S(mbhc_nsa, 4);
+ S(mbhc_navg, 4);
+#undef S
+#define S(X, Y) ((TABLA_MBHC_CAL_PLUG_DET_PTR(tabla_cal)->X) = (Y))
+ S(mic_current, TABLA_PID_MIC_5_UA);
+ S(hph_current, TABLA_PID_MIC_5_UA);
+ S(t_mic_pid, 100);
+ S(t_ins_complete, 250);
+ S(t_ins_retry, 200);
+#undef S
+#define S(X, Y) ((TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla_cal)->X) = (Y))
+ S(v_no_mic, 30);
+ S(v_hs_max, 1550);
+#undef S
+#define S(X, Y) ((TABLA_MBHC_CAL_BTN_DET_PTR(tabla_cal)->X) = (Y))
+ S(c[0], 62);
+ S(c[1], 124);
+ S(nc, 1);
+ S(n_meas, 3);
+ S(mbhc_nsc, 11);
+ S(n_btn_meas, 1);
+ S(n_btn_con, 2);
+ S(num_btn, TABLA_MBHC_DEF_BUTTONS);
+ S(v_btn_press_delta_sta, 100);
+ S(v_btn_press_delta_cic, 50);
+#undef S
+ btn_cfg = TABLA_MBHC_CAL_BTN_DET_PTR(tabla_cal);
+ btn_low = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_V_BTN_LOW);
+ btn_high = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_V_BTN_HIGH);
+ btn_low[0] = -50;
+ btn_high[0] = 10;
+ btn_low[1] = 11;
+ btn_high[1] = 38;
+ btn_low[2] = 39;
+ btn_high[2] = 64;
+ btn_low[3] = 65;
+ btn_high[3] = 91;
+ btn_low[4] = 92;
+ btn_high[4] = 115;
+ btn_low[5] = 116;
+ btn_high[5] = 141;
+ btn_low[6] = 142;
+ btn_high[6] = 163;
+ btn_low[7] = 164;
+ btn_high[7] = 250;
+ n_ready = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_N_READY);
+ n_ready[0] = 48;
+ n_ready[1] = 38;
+ n_cic = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_N_CIC);
+ n_cic[0] = 60;
+ n_cic[1] = 47;
+ gain = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_GAIN);
+ gain[0] = 11;
+ gain[1] = 9;
+
+ return tabla_cal;
+}
+
+static int msm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ int ret = 0;
+ unsigned int rx_ch[SLIM_MAX_RX_PORTS], tx_ch[SLIM_MAX_TX_PORTS];
+ unsigned int rx_ch_cnt = 0, tx_ch_cnt = 0;
+ unsigned int num_tx_ch = 0;
+
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+
+ pr_debug("%s: rx_0_ch=%d\n", __func__, msm_slim_0_rx_ch);
+
+ ret = snd_soc_dai_get_channel_map(codec_dai,
+ &tx_ch_cnt, tx_ch, &rx_ch_cnt , rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to get codec chan map\n", __func__);
+ goto end;
+ }
+
+ ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0,
+ msm_slim_0_rx_ch, rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to set cpu chan map\n", __func__);
+ goto end;
+ }
+ ret = snd_soc_dai_set_channel_map(codec_dai, 0, 0,
+ msm_slim_0_rx_ch, rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to set codec channel map\n",
+ __func__);
+ goto end;
+ }
+ } else {
+
+ if (codec_dai->id == 2)
+ num_tx_ch = msm_slim_0_tx_ch;
+ else if (codec_dai->id == 5) {
+ /* DAI 5 is used for external EC reference from codec.
+ * Since Rx is fed as reference for EC, the config of
+ * this DAI is based on that of the Rx path.
+ */
+ num_tx_ch = msm_slim_0_rx_ch;
+ }
+
+ pr_debug("%s: %s_tx_dai_id_%d_ch=%d\n", __func__,
+ codec_dai->name, codec_dai->id, num_tx_ch);
+
+ ret = snd_soc_dai_get_channel_map(codec_dai,
+ &tx_ch_cnt, tx_ch, &rx_ch_cnt , rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to get codec chan map\n", __func__);
+ goto end;
+ }
+
+ ret = snd_soc_dai_set_channel_map(cpu_dai,
+ num_tx_ch, tx_ch, 0 , 0);
+ if (ret < 0) {
+ pr_err("%s: failed to set cpu chan map\n", __func__);
+ goto end;
+ }
+ ret = snd_soc_dai_set_channel_map(codec_dai,
+ num_tx_ch, tx_ch, 0, 0);
+ if (ret < 0) {
+ pr_err("%s: failed to set codec channel map\n",
+ __func__);
+ goto end;
+ }
+
+
+ }
+end:
+ return ret;
+}
+
+static int msm_stubrx_init(struct snd_soc_pcm_runtime *rtd)
+{
+ rtd->pmdown_time = 0;
+
+ return 0;
+}
+
+static int msm_slimbus_2_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ int ret = 0;
+ unsigned int rx_ch[SLIM_MAX_RX_PORTS], tx_ch[SLIM_MAX_TX_PORTS];
+ unsigned int rx_ch_cnt = 0, tx_ch_cnt = 0;
+ unsigned int num_tx_ch = 0;
+ unsigned int num_rx_ch = 0;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+
+ num_rx_ch = params_channels(params);
+
+ pr_debug("%s: %s rx_dai_id = %d num_ch = %d\n", __func__,
+ codec_dai->name, codec_dai->id, num_rx_ch);
+
+ ret = snd_soc_dai_get_channel_map(codec_dai,
+ &tx_ch_cnt, tx_ch, &rx_ch_cnt , rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to get codec chan map\n", __func__);
+ goto end;
+ }
+
+ ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0,
+ num_rx_ch, rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to set cpu chan map\n", __func__);
+ goto end;
+ }
+ ret = snd_soc_dai_set_channel_map(codec_dai, 0, 0,
+ num_rx_ch, rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to set codec channel map\n",
+ __func__);
+ goto end;
+ }
+ } else {
+
+ num_tx_ch = params_channels(params);
+
+ pr_debug("%s: %s tx_dai_id = %d num_ch = %d\n", __func__,
+ codec_dai->name, codec_dai->id, num_tx_ch);
+
+ ret = snd_soc_dai_get_channel_map(codec_dai,
+ &tx_ch_cnt, tx_ch, &rx_ch_cnt , rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to get codec chan map\n", __func__);
+ goto end;
+ }
+
+ ret = snd_soc_dai_set_channel_map(cpu_dai,
+ num_tx_ch, tx_ch, 0 , 0);
+ if (ret < 0) {
+ pr_err("%s: failed to set cpu chan map\n", __func__);
+ goto end;
+ }
+ ret = snd_soc_dai_set_channel_map(codec_dai,
+ num_tx_ch, tx_ch, 0, 0);
+ if (ret < 0) {
+ pr_err("%s: failed to set codec channel map\n",
+ __func__);
+ goto end;
+ }
+ }
+end:
+ return ret;
+}
+
+static int msm_slimbus_1_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ int ret = 0;
+ unsigned int rx_ch = SLIM_1_RX_1, tx_ch = SLIM_1_TX_1;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ pr_debug("%s: APQ BT/USB TX -> SLIMBUS_1_RX -> MDM TX shared ch %d\n",
+ __func__, rx_ch);
+
+ ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0, 1, &rx_ch);
+ if (ret < 0) {
+ pr_err("%s: Erorr %d setting SLIM_1 RX channel map\n",
+ __func__, ret);
+
+ goto end;
+ }
+ } else {
+ pr_debug("%s: MDM RX -> SLIMBUS_1_TX -> APQ BT/USB Rx shared ch %d\n",
+ __func__, tx_ch);
+
+ ret = snd_soc_dai_set_channel_map(cpu_dai, 1, &tx_ch, 0, 0);
+ if (ret < 0) {
+ pr_err("%s: Erorr %d setting SLIM_1 TX channel map\n",
+ __func__, ret);
+
+ goto end;
+ }
+ }
+
+end:
+ return ret;
+}
+
+static int msm_slimbus_3_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ int ret = 0;
+ unsigned int rx_ch[2] = {SLIM_3_RX_1, SLIM_3_RX_2};
+ unsigned int tx_ch[2] = {SLIM_3_TX_1, SLIM_3_TX_2};
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ pr_debug("%s: slim_3_rx_ch %d, sch %d %d\n",
+ __func__, msm_slim_3_rx_ch,
+ rx_ch[0], rx_ch[1]);
+
+ ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0,
+ msm_slim_3_rx_ch, rx_ch);
+ if (ret < 0) {
+ pr_err("%s: Erorr %d setting SLIM_3 RX channel map\n",
+ __func__, ret);
+
+ goto end;
+ }
+ } else {
+ pr_debug("%s: MDM RX -> SLIMBUS_3_TX -> APQ HDMI ch: %d, %d\n",
+ __func__, tx_ch[0], tx_ch[1]);
+
+ ret = snd_soc_dai_set_channel_map(cpu_dai, 2, tx_ch, 0, 0);
+ if (ret < 0) {
+ pr_err("%s: Erorr %d setting SLIM_3 TX channel map\n",
+ __func__, ret);
+
+ goto end;
+ }
+ }
+
+end:
+ return ret;
+}
+
+static int msm_slimbus_4_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ int ret = 0;
+ unsigned int rx_ch = SLIM_4_RX_1, tx_ch[2];
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ pr_debug("%s: APQ Incall Playback SLIMBUS_4_RX -> MDM TX shared ch %d\n",
+ __func__, rx_ch);
+
+ ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0, 1, &rx_ch);
+ if (ret < 0) {
+ pr_err("%s: Erorr %d setting SLIM_4 RX channel map\n",
+ __func__, ret);
+
+ }
+ } else {
+ if (rec_mode == INCALL_REC_STEREO) {
+ tx_ch[0] = SLIM_4_TX_1;
+ tx_ch[1] = SLIM_4_TX_2;
+ ret = snd_soc_dai_set_channel_map(cpu_dai, 2,
+ tx_ch, 0, 0);
+ } else {
+ tx_ch[0] = SLIM_4_TX_1;
+ ret = snd_soc_dai_set_channel_map(cpu_dai, 1,
+ tx_ch, 0, 0);
+ }
+ pr_debug("%s: Incall Record shared tx_ch[0]:%d, tx_ch[1]:%d\n",
+ __func__, tx_ch[0], tx_ch[1]);
+
+ if (ret < 0) {
+ pr_err("%s: Erorr %d setting SLIM_4 TX channel map\n",
+ __func__, ret);
+
+ }
+ }
+
+ return ret;
+}
+
+static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
+{
+ int err;
+ uint32_t revision;
+ struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_dapm_context *dapm = &codec->dapm;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+
+ pr_debug("%s(), dev_name(%s)\n", __func__, dev_name(cpu_dai->dev));
+
+ /*if (machine_is_msm_liquid()) {
+ top_spk_pamp_gpio = (PM8921_GPIO_PM_TO_SYS(19));
+ bottom_spk_pamp_gpio = (PM8921_GPIO_PM_TO_SYS(18));
+ }*/
+
+ snd_soc_dapm_new_controls(dapm, apq8064_dapm_widgets,
+ ARRAY_SIZE(apq8064_dapm_widgets));
+
+ snd_soc_dapm_add_routes(dapm, apq8064_common_audio_map,
+ ARRAY_SIZE(apq8064_common_audio_map));
+
+ if (machine_is_apq8064_mtp()) {
+ snd_soc_dapm_add_routes(dapm, apq8064_mtp_audio_map,
+ ARRAY_SIZE(apq8064_mtp_audio_map));
+ } else {
+ snd_soc_dapm_add_routes(dapm, apq8064_liquid_cdp_audio_map,
+ ARRAY_SIZE(apq8064_liquid_cdp_audio_map));
+ }
+
+ snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Pos");
+ snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Neg");
+ snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Pos");
+ snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Neg");
+
+ snd_soc_dapm_sync(dapm);
+
+ err = snd_soc_jack_new(codec, "Headset Jack",
+ (SND_JACK_HEADSET | SND_JACK_OC_HPHL |
+ SND_JACK_OC_HPHR | SND_JACK_UNSUPPORTED),
+ &hs_jack);
+ if (err) {
+ pr_err("failed to create new jack\n");
+ return err;
+ }
+
+ err = snd_soc_jack_new(codec, "Button Jack",
+ TABLA_JACK_BUTTON_MASK, &button_jack);
+ if (err) {
+ pr_err("failed to create new jack\n");
+ return err;
+ }
+
+ codec_clk = clk_get(cpu_dai->dev, "osr_clk");
+
+ /* APQ8064 Rev 1.1 CDP and Liquid have mechanical switch */
+ revision = socinfo_get_version();
+ if (apq8064_i2s_hs_detect_use_gpio != -1) {
+ if (apq8064_i2s_hs_detect_use_gpio == 1)
+ pr_debug("%s: MBHC mechanical is enabled by request\n",
+ __func__);
+ else if (apq8064_i2s_hs_detect_use_gpio == 0)
+ pr_debug("%s: MBHC mechanical is disabled by request\n",
+ __func__);
+ else
+ pr_warn("%s: Invalid hs_detect_use_gpio %d\n", __func__,
+ apq8064_i2s_hs_detect_use_gpio);
+ } else if (SOCINFO_VERSION_MAJOR(revision) == 0) {
+ pr_warn("%s: Unknown HW revision detected %d.%d\n", __func__,
+ SOCINFO_VERSION_MAJOR(revision),
+ SOCINFO_VERSION_MINOR(revision));
+ } else if ((SOCINFO_VERSION_MAJOR(revision) == 1 &&
+ SOCINFO_VERSION_MINOR(revision) >= 1 &&
+ (machine_is_apq8064_cdp() ||
+ machine_is_apq8064_liquid())) ||
+ SOCINFO_VERSION_MAJOR(revision) > 1) {
+ pr_debug("%s: MBHC mechanical switch available APQ8064 detected\n",
+ __func__);
+ apq8064_i2s_hs_detect_use_gpio = 1;
+ }
+
+ if (apq8064_i2s_hs_detect_use_gpio == 1) {
+ pr_debug("%s: Using MBHC mechanical switch\n", __func__);
+ mbhc_cfg.gpio = JACK_DETECT_GPIO;
+ mbhc_cfg.gpio_irq = gpio_to_irq(JACK_DETECT_GPIO);
+ err = gpio_request(mbhc_cfg.gpio, "MBHC_HS_DETECT");
+ if (err < 0) {
+ pr_err("%s: gpio_request %d failed %d\n", __func__,
+ mbhc_cfg.gpio, err);
+ return err;
+ }
+ gpio_direction_input(JACK_DETECT_GPIO);
+ } else
+ pr_debug("%s: Not using MBHC mechanical switch\n", __func__);
+
+ mbhc_cfg.read_fw_bin = apq8064_i2s_hs_detect_use_firmware;
+
+ err = tabla_hs_detect(codec, &mbhc_cfg);
+
+ return err;
+}
+
+static int msm_slim_0_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ pr_debug("%s()\n", __func__);
+ rate->min = rate->max = 48000;
+ channels->min = channels->max = msm_slim_0_rx_ch;
+
+ return 0;
+}
+
+static int msm_slim_0_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ pr_debug("%s()\n", __func__);
+ rate->min = rate->max = 48000;
+ channels->min = channels->max = msm_slim_0_tx_ch;
+
+ return 0;
+}
+
+static int msm_slim_3_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ pr_debug("%s()\n", __func__);
+ rate->min = rate->max = 48000;
+ channels->min = channels->max = msm_slim_3_rx_ch;
+
+ return 0;
+}
+
+static int msm_slim_3_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ pr_debug("%s()\n", __func__);
+ rate->min = rate->max = 48000;
+ channels->min = channels->max = 2;
+
+ return 0;
+}
+
+static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+
+ pr_debug("%s()\n", __func__);
+ rate->min = rate->max = 48000;
+
+ return 0;
+}
+
+static int msm_hdmi_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ pr_debug("%s channels->min %u channels->max %u ()\n", __func__,
+ channels->min, channels->max);
+
+ rate->min = rate->max = 48000;
+
+ return 0;
+}
+
+static int msm_btsco_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ rate->min = rate->max = msm_btsco_rate;
+ channels->min = channels->max = msm_btsco_ch;
+
+ return 0;
+}
+static int msm_auxpcm_be_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ /* PCM only supports mono output with 8khz sample rate */
+ rate->min = rate->max = 8000;
+ channels->min = channels->max = 1;
+
+ return 0;
+}
+static int msm_proxy_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+
+ pr_debug("%s()\n", __func__);
+ rate->min = rate->max = 48000;
+
+ return 0;
+}
+
+static int msm_aux_pcm_get_gpios(void)
+{
+ int ret = 0;
+
+ pr_debug("%s\n", __func__);
+
+ ret = gpio_request(GPIO_AUX_PCM_DOUT, "AUX PCM DOUT");
+ if (ret < 0) {
+ pr_err("%s: Failed to request gpio(%d): AUX PCM DOUT",
+ __func__, GPIO_AUX_PCM_DOUT);
+ goto fail_dout;
+ }
+
+ ret = gpio_request(GPIO_AUX_PCM_DIN, "AUX PCM DIN");
+ if (ret < 0) {
+ pr_err("%s: Failed to request gpio(%d): AUX PCM DIN",
+ __func__, GPIO_AUX_PCM_DIN);
+ goto fail_din;
+ }
+
+ ret = gpio_request(GPIO_AUX_PCM_SYNC, "AUX PCM SYNC");
+ if (ret < 0) {
+ pr_err("%s: Failed to request gpio(%d): AUX PCM SYNC",
+ __func__, GPIO_AUX_PCM_SYNC);
+ goto fail_sync;
+ }
+ ret = gpio_request(GPIO_AUX_PCM_CLK, "AUX PCM CLK");
+ if (ret < 0) {
+ pr_err("%s: Failed to request gpio(%d): AUX PCM CLK",
+ __func__, GPIO_AUX_PCM_CLK);
+ goto fail_clk;
+ }
+
+ return 0;
+
+fail_clk:
+ gpio_free(GPIO_AUX_PCM_SYNC);
+fail_sync:
+ gpio_free(GPIO_AUX_PCM_DIN);
+fail_din:
+ gpio_free(GPIO_AUX_PCM_DOUT);
+fail_dout:
+
+ return ret;
+}
+
+static int msm_aux_pcm_free_gpios(void)
+{
+ gpio_free(GPIO_AUX_PCM_DIN);
+ gpio_free(GPIO_AUX_PCM_DOUT);
+ gpio_free(GPIO_AUX_PCM_SYNC);
+ gpio_free(GPIO_AUX_PCM_CLK);
+
+ return 0;
+}
+static int msm_startup(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+
+ pr_debug("%s(): dai_link_str_name = %s cpu_dai = %s codec_dai = %s\n",
+ __func__, rtd->dai_link->stream_name,
+ rtd->dai_link->cpu_dai_name,
+ rtd->dai_link->codec_dai_name);
+ return 0;
+}
+
+static int msm_auxpcm_startup(struct snd_pcm_substream *substream)
+{
+ int ret = 0;
+
+ pr_debug("%s(): substream = %s\n", __func__, substream->name);
+ ret = msm_aux_pcm_get_gpios();
+ if (ret < 0) {
+ pr_err("%s: Aux PCM GPIO request failed\n", __func__);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int msm_slimbus_1_startup(struct snd_pcm_substream *substream)
+{
+ struct slim_controller *slim = slim_busnum_to_ctrl(1);
+
+ pr_debug("%s(): substream = %s stream = %d\n", __func__,
+ substream->name, substream->stream);
+
+ if (slim != NULL)
+ pm_runtime_get_sync(slim->dev.parent);
+
+ return 0;
+}
+
+static void msm_auxpcm_shutdown(struct snd_pcm_substream *substream)
+{
+
+ pr_debug("%s(): substream = %s\n", __func__, substream->name);
+ msm_aux_pcm_free_gpios();
+}
+
+static void msm_shutdown(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+
+ pr_debug("%s(): dai_link_str_name = %s cpu_dai = %s codec_dai = %s\n",
+ __func__, rtd->dai_link->stream_name,
+ rtd->dai_link->cpu_dai_name, rtd->dai_link->codec_dai_name);
+}
+
+static void msm_slimbus_1_shutdown(struct snd_pcm_substream *substream)
+{
+ struct slim_controller *slim = slim_busnum_to_ctrl(1);
+
+ pr_debug("%s(): substream = %s stream = %d\n", __func__,
+ substream->name, substream->stream);
+
+ if (slim != NULL) {
+ pm_runtime_mark_last_busy(slim->dev.parent);
+ pm_runtime_put(slim->dev.parent);
+ }
+}
+
+static struct snd_soc_ops msm_be_ops = {
+ .startup = msm_startup,
+ .hw_params = msm_hw_params,
+ .shutdown = msm_shutdown,
+};
+
+static struct snd_soc_ops msm_auxpcm_be_ops = {
+ .startup = msm_auxpcm_startup,
+ .shutdown = msm_auxpcm_shutdown,
+};
+
+static struct snd_soc_ops msm_slimbus_1_be_ops = {
+ .startup = msm_slimbus_1_startup,
+ .hw_params = msm_slimbus_1_hw_params,
+ .shutdown = msm_slimbus_1_shutdown,
+};
+
+static struct snd_soc_ops msm_slimbus_3_be_ops = {
+ .startup = msm_startup,
+ .hw_params = msm_slimbus_3_hw_params,
+ .shutdown = msm_shutdown,
+};
+
+static struct snd_soc_ops msm_slimbus_4_be_ops = {
+ .startup = msm_startup,
+ .hw_params = msm_slimbus_4_hw_params,
+ .shutdown = msm_shutdown,
+};
+
+static struct snd_soc_ops msm_slimbus_2_be_ops = {
+ .startup = msm_startup,
+ .hw_params = msm_slimbus_2_hw_params,
+ .shutdown = msm_shutdown,
+};
+
+static struct snd_soc_ops msm_mi2s_be_ops = {
+ .startup = msm_mi2s_startup,
+ .shutdown = msm_mi2s_shutdown,
+};
+
+
+static struct snd_soc_ops msm_i2s_be_ops = {
+ .startup = msm_i2s_startup,
+ .shutdown = msm_i2s_shutdown,
+};
+
+static struct snd_soc_dai_link msm_dai_delta_mi2s[] = {
+ /* Backend DAI Links */
+ {
+ .name = LPASS_BE_MI2S_RX,
+ .stream_name = "MI2S Playback",
+ .cpu_dai_name = "msm-dai-q6-mi2s",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tabla_codec",
+ .codec_dai_name = "tabla_i2s_rx1",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_MI2S_RX,
+ .init = &msm_mi2s_audrx_init,
+ .be_hw_params_fixup = msm_mi2s_rx_be_hw_params_fixup,
+ .ops = &msm_mi2s_be_ops,
+ .ignore_pmdown_time = 1, /* Playback support */
+ },
+ {
+ .name = LPASS_BE_MI2S_TX,
+ .stream_name = "MI2S Capture",
+ .cpu_dai_name = "msm-dai-q6-mi2s",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tabla_codec",
+ .codec_dai_name = "tabla_i2s_tx1",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_MI2S_TX,
+ .be_hw_params_fixup = msm_mi2s_tx_be_hw_params_fixup,
+ .ops = &msm_mi2s_be_ops,
+ },
+ {
+ .name = LPASS_BE_PRI_I2S_RX,
+ .stream_name = "Primary I2S Playback",
+ .cpu_dai_name = "msm-dai-q6.0",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_PRI_I2S_RX,
+ .be_hw_params_fixup = msm_i2s_rx_be_hw_params_fixup,
+ .ops = &msm_i2s_be_ops,
+ },
+ {
+ .name = LPASS_BE_PRI_I2S_TX,
+ .stream_name = "Primary I2S Capture",
+ .cpu_dai_name = "msm-dai-q6.1",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_PRI_I2S_TX,
+ .be_hw_params_fixup = msm_i2s_tx_be_hw_params_fixup,
+ .ops = &msm_i2s_be_ops,
+ },
+};
+
+
+static struct snd_soc_dai_link msm_dai_delta_slim[] = {
+ /* Hostless PMC purpose */
+ {
+ .name = "SLIMBUS_0 Hostless",
+ .stream_name = "SLIMBUS_0 Hostless",
+ .cpu_dai_name = "SLIMBUS0_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1, /* Playback support */
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ /* .be_id = do not care */
+ },
+ /* Backend DAI Links */
+ {
+ .name = LPASS_BE_SLIMBUS_0_RX,
+ .stream_name = "Slimbus Playback",
+ .cpu_dai_name = "msm-dai-q6.16384",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tabla_codec",
+ .codec_dai_name = "tabla_rx1",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ .init = &msm_audrx_init,
+ .be_hw_params_fixup = msm_slim_0_rx_be_hw_params_fixup,
+ .ops = &msm_be_ops,
+ .ignore_pmdown_time = 1, /* Playback support */
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_0_TX,
+ .stream_name = "Slimbus Capture",
+ .cpu_dai_name = "msm-dai-q6.16385",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tabla_codec",
+ .codec_dai_name = "tabla_tx1",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_0_TX,
+ .be_hw_params_fixup = msm_slim_0_tx_be_hw_params_fixup,
+ .ops = &msm_be_ops,
+ },
+ {
+ .name = LPASS_BE_STUB_RX,
+ .stream_name = "Stub Playback",
+ .cpu_dai_name = "msm-dai-stub",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tabla_codec",
+ .codec_dai_name = "tabla_rx2",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_EXTPROC_RX,
+ .be_hw_params_fixup = msm_slim_0_rx_be_hw_params_fixup,
+ .init = &msm_stubrx_init,
+ .ops = &msm_be_ops,
+ .ignore_pmdown_time = 1, /* Playback support */
+ },
+ {
+ .name = LPASS_BE_STUB_TX,
+ .stream_name = "Stub Capture",
+ .cpu_dai_name = "msm-dai-stub",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tabla_codec",
+ .codec_dai_name = "tabla_tx1",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_EXTPROC_TX,
+ .be_hw_params_fixup = msm_slim_0_tx_be_hw_params_fixup,
+ .ops = &msm_be_ops,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_1_RX,
+ .stream_name = "Slimbus1 Playback",
+ .cpu_dai_name = "msm-dai-q6.16386",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_1_RX,
+ .be_hw_params_fixup = msm_btsco_be_hw_params_fixup,
+ .ops = &msm_slimbus_1_be_ops,
+ .ignore_pmdown_time = 1, /* Playback support */
+
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_1_TX,
+ .stream_name = "Slimbus1 Capture",
+ .cpu_dai_name = "msm-dai-q6.16387",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_1_TX,
+ .be_hw_params_fixup = msm_btsco_be_hw_params_fixup,
+ .ops = &msm_slimbus_1_be_ops,
+ },
+ /* Ultrasound TX Back End DAI Link */
+ {
+ .name = "SLIMBUS_2 Hostless Capture",
+ .stream_name = "SLIMBUS_2 Hostless Capture",
+ .cpu_dai_name = "msm-dai-q6.16389",
+ .platform_name = "msm-pcm-hostless",
+ .codec_name = "tabla_codec",
+ .codec_dai_name = "tabla_tx2",
+ .ignore_suspend = 1,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ops = &msm_slimbus_2_be_ops,
+ },
+ /* Ultrasound RX Back End DAI Link */
+ {
+ .name = "SLIMBUS_2 Hostless Playback",
+ .stream_name = "SLIMBUS_2 Hostless Playback",
+ .cpu_dai_name = "msm-dai-q6.16388",
+ .platform_name = "msm-pcm-hostless",
+ .codec_name = "tabla_codec",
+ .codec_dai_name = "tabla_rx3",
+ .ignore_suspend = 1,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ops = &msm_slimbus_2_be_ops,
+ },
+ /* Incall Music Back End DAI Link */
+ {
+ .name = LPASS_BE_SLIMBUS_4_RX,
+ .stream_name = "Slimbus4 Playback",
+ .cpu_dai_name = "msm-dai-q6.16392",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_4_RX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &msm_slimbus_4_be_ops,
+ .ignore_pmdown_time = 1, /* Playback support */
+ },
+ /* Incall Record Back End DAI Link */
+ {
+ .name = LPASS_BE_SLIMBUS_4_TX,
+ .stream_name = "Slimbus4 Capture",
+ .cpu_dai_name = "msm-dai-q6.16393",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_4_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &msm_slimbus_4_be_ops,
+ },
+ {
+ .name = LPASS_BE_STUB_1_TX,
+ .stream_name = "Stub1 Capture",
+ .cpu_dai_name = "msm-dai-stub",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tabla_codec",
+ .codec_dai_name = "tabla_tx3",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_EXTPROC_EC_TX,
+ /* This BE is used for external EC reference from codec. Since
+ * Rx is fed as reference for EC, the config of this DAI is
+ * based on that of the Rx path.
+ */
+ .be_hw_params_fixup = msm_slim_0_rx_be_hw_params_fixup,
+ .ops = &msm_be_ops,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_3_RX,
+ .stream_name = "Slimbus3 Playback",
+ .cpu_dai_name = "msm-dai-q6.16390",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_3_RX,
+ .be_hw_params_fixup = msm_slim_3_rx_be_hw_params_fixup,
+ .ops = &msm_slimbus_3_be_ops,
+ .ignore_pmdown_time = 1, /* Playback support */
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_3_TX,
+ .stream_name = "Slimbus3 Capture",
+ .cpu_dai_name = "msm-dai-q6.16391",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_3_TX,
+ .be_hw_params_fixup = msm_slim_3_tx_be_hw_params_fixup,
+ .ops = &msm_slimbus_3_be_ops,
+ },
+};
+
+/* Digital audio interface glue - connects codec <---> CPU */
+static struct snd_soc_dai_link msm_dai[] = {
+ /* FrontEnd DAI Links */
+ {
+ .name = "MSM8960 Media1",
+ .stream_name = "MultiMedia1",
+ .cpu_dai_name = "MultiMedia1",
+ .platform_name = "msm-pcm-dsp",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1, /* Playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA1
+ },
+ {
+ .name = "MSM8960 Media2",
+ .stream_name = "MultiMedia2",
+ .cpu_dai_name = "MultiMedia2",
+ .platform_name = "msm-multi-ch-pcm-dsp",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1, /* Playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA2,
+ },
+ {
+ .name = "Circuit-Switch Voice",
+ .stream_name = "CS-Voice",
+ .cpu_dai_name = "CS-VOICE",
+ .platform_name = "msm-pcm-voice",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1, /* Playback support */
+ .be_id = MSM_FRONTEND_DAI_CS_VOICE,
+ },
+ {
+ .name = "MSM VoIP",
+ .stream_name = "VoIP",
+ .cpu_dai_name = "VoIP",
+ .platform_name = "msm-voip-dsp",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1, /* Playback support */
+ .be_id = MSM_FRONTEND_DAI_VOIP,
+ },
+ {
+ .name = "MSM8960 LPA",
+ .stream_name = "LPA",
+ .cpu_dai_name = "MultiMedia3",
+ .platform_name = "msm-pcm-lpa",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1, /* Playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA3,
+ },
+ {
+ .name = "INT_FM Hostless",
+ .stream_name = "INT_FM Hostless",
+ .cpu_dai_name = "INT_FM_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1, /* Playback support */
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ /* .be_id = do not care */
+ },
+ {
+ .name = "MSM AFE-PCM RX",
+ .stream_name = "AFE-PROXY RX",
+ .cpu_dai_name = "msm-dai-q6.241",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .platform_name = "msm-pcm-afe",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1, /* Playback support */
+ },
+ {
+ .name = "MSM AFE-PCM TX",
+ .stream_name = "AFE-PROXY TX",
+ .cpu_dai_name = "msm-dai-q6.240",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .platform_name = "msm-pcm-afe",
+ .ignore_suspend = 1,
+ },
+ {
+ .name = "MSM8960 Compr",
+ .stream_name = "COMPR",
+ .cpu_dai_name = "MultiMedia4",
+ .platform_name = "msm-compr-dsp",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1, /* Playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA4,
+ },
+ {
+ .name = "AUXPCM Hostless",
+ .stream_name = "AUXPCM Hostless",
+ .cpu_dai_name = "AUXPCM_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1, /* Playback support */
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ /* HDMI Hostless */
+ {
+ .name = "HDMI_RX_HOSTLESS",
+ .stream_name = "HDMI_RX_HOSTLESS",
+ .cpu_dai_name = "HDMI_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1, /* Playback support */
+ },
+ {
+ .name = "Voice Stub",
+ .stream_name = "Voice Stub",
+ .cpu_dai_name = "VOICE_STUB",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1, /* Playback support */
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ /* Backend BT/FM DAI Links */
+ {
+ .name = LPASS_BE_INT_BT_SCO_RX,
+ .stream_name = "Internal BT-SCO Playback",
+ .cpu_dai_name = "msm-dai-q6.12288",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_INT_BT_SCO_RX,
+ .be_hw_params_fixup = msm_btsco_be_hw_params_fixup,
+ .ignore_pmdown_time = 1, /* Playback support */
+ },
+ {
+ .name = LPASS_BE_INT_BT_SCO_TX,
+ .stream_name = "Internal BT-SCO Capture",
+ .cpu_dai_name = "msm-dai-q6.12289",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_INT_BT_SCO_TX,
+ .be_hw_params_fixup = msm_btsco_be_hw_params_fixup,
+ },
+ {
+ .name = LPASS_BE_INT_FM_RX,
+ .stream_name = "Internal FM Playback",
+ .cpu_dai_name = "msm-dai-q6.12292",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_INT_FM_RX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_pmdown_time = 1, /* Playback support */
+ },
+ {
+ .name = LPASS_BE_INT_FM_TX,
+ .stream_name = "Internal FM Capture",
+ .cpu_dai_name = "msm-dai-q6.12293",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_INT_FM_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ },
+ /* HDMI BACK END DAI Link */
+ {
+ .name = LPASS_BE_HDMI,
+ .stream_name = "HDMI Playback",
+ .cpu_dai_name = "msm-dai-q6-hdmi.8",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_HDMI_RX,
+ .be_hw_params_fixup = msm_hdmi_be_hw_params_fixup,
+ },
+ /* Backend AFE DAI Links */
+ {
+ .name = LPASS_BE_AFE_PCM_RX,
+ .stream_name = "AFE Playback",
+ .cpu_dai_name = "msm-dai-q6.224",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_AFE_PCM_RX,
+ .be_hw_params_fixup = msm_proxy_be_hw_params_fixup,
+ .ignore_pmdown_time = 1, /* Playback support */
+ },
+ {
+ .name = LPASS_BE_AFE_PCM_TX,
+ .stream_name = "AFE Capture",
+ .cpu_dai_name = "msm-dai-q6.225",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_AFE_PCM_TX,
+ .be_hw_params_fixup = msm_proxy_be_hw_params_fixup,
+ },
+ /* AUX PCM Backend DAI Links */
+ {
+ .name = LPASS_BE_AUXPCM_RX,
+ .stream_name = "AUX PCM Playback",
+ .cpu_dai_name = "msm-dai-q6.2",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_AUXPCM_RX,
+ .be_hw_params_fixup = msm_auxpcm_be_params_fixup,
+ .ops = &msm_auxpcm_be_ops,
+ .ignore_pmdown_time = 1, /* Playback support */
+ },
+ {
+ .name = LPASS_BE_AUXPCM_TX,
+ .stream_name = "AUX PCM Capture",
+ .cpu_dai_name = "msm-dai-q6.3",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_AUXPCM_TX,
+ .be_hw_params_fixup = msm_auxpcm_be_params_fixup,
+ },
+};
+
+
+/* Digital audio interface glue - connects codec <---> CPU */
+static struct snd_soc_dai_link msm_mi2s_dai[
+ ARRAY_SIZE(msm_dai) +
+ ARRAY_SIZE(msm_dai_delta_mi2s)];
+
+static struct snd_soc_dai_link msm_slim_dai[
+ ARRAY_SIZE(msm_dai) +
+ ARRAY_SIZE(msm_dai_delta_slim)];
+
+static struct snd_soc_card snd_soc_card_msm = {
+ .name = "apq8064-tabla-snd-card",
+};
+
+static struct platform_device *msm_snd_device;
+
+static int __init msm_audio_init(void)
+{
+
+ int ret;
+ u32 version = socinfo_get_platform_version();
+ if (!machine_is_apq8064_mtp() ||
+ (SOCINFO_VERSION_MINOR(version) != 1)) {
+ pr_info("%s: Not APQ8064 in I2S mode\n", __func__);
+ return -ENODEV;
+ }
+ pr_debug("%s: APQ8064 is in I2S mode\n", __func__);
+ mbhc_cfg.calibration = def_tabla_mbhc_cal();
+ if (!mbhc_cfg.calibration) {
+ pr_err("Calibration data allocation failed\n");
+ return -ENOMEM;
+ }
+
+ msm_snd_device = platform_device_alloc("soc-audio", 0);
+ if (!msm_snd_device) {
+ pr_err("Platform device allocation failed\n");
+ kfree(mbhc_cfg.calibration);
+ return -ENOMEM;
+ }
+
+ if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
+ memcpy(msm_slim_dai, msm_dai, sizeof(msm_dai));
+ memcpy(msm_slim_dai + ARRAY_SIZE(msm_dai),
+ msm_dai_delta_slim, sizeof(msm_dai_delta_slim));
+ snd_soc_card_msm.dai_link = msm_slim_dai;
+ snd_soc_card_msm.num_links = ARRAY_SIZE(msm_slim_dai);
+ snd_soc_card_msm.controls = tabla_msm_controls;
+ snd_soc_card_msm.num_controls =
+ ARRAY_SIZE(tabla_msm_controls);
+ pr_info("%s: Load Slimbus Dai\n", __func__);
+ } else if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C) {
+ memcpy(msm_mi2s_dai, msm_dai, sizeof(msm_dai));
+ memcpy(msm_mi2s_dai + ARRAY_SIZE(msm_dai),
+ msm_dai_delta_mi2s, sizeof(msm_dai_delta_mi2s));
+ snd_soc_card_msm.dai_link = msm_mi2s_dai;
+ snd_soc_card_msm.num_links = ARRAY_SIZE(msm_mi2s_dai);
+ snd_soc_card_msm.controls = tabla_msm_mi2s_controls;
+ snd_soc_card_msm.num_controls =
+ ARRAY_SIZE(tabla_msm_mi2s_controls);
+ pr_info("%s: Load MI2S\n", __func__);
+ }
+
+ platform_set_drvdata(msm_snd_device, &snd_soc_card_msm);
+ ret = platform_device_add(msm_snd_device);
+ if (ret) {
+ platform_device_put(msm_snd_device);
+ kfree(mbhc_cfg.calibration);
+ return ret;
+ }
+
+ mutex_init(&cdc_mclk_mutex);
+ atomic_set(&mi2s_rsc_ref, 0);
+ return ret;
+
+}
+module_init(msm_audio_init);
+
+static void __exit msm_audio_exit(void)
+{
+ if (!cpu_is_apq8064() || (socinfo_get_id() == 130)) {
+ pr_err("%s: Not the right machine type\n", __func__);
+ return ;
+ }
+ platform_device_unregister(msm_snd_device);
+ if (mbhc_cfg.gpio)
+ gpio_free(mbhc_cfg.gpio);
+ kfree(mbhc_cfg.calibration);
+ mutex_destroy(&cdc_mclk_mutex);
+}
+module_exit(msm_audio_exit);
+
+MODULE_DESCRIPTION("ALSA SoC msm");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/apq8064.c b/sound/soc/msm/apq8064.c
index 4b86f2b..ece0a15 100644
--- a/sound/soc/msm/apq8064.c
+++ b/sound/soc/msm/apq8064.c
@@ -2013,7 +2013,7 @@
},
};
-struct snd_soc_card snd_soc_card_msm = {
+static struct snd_soc_card snd_soc_card_msm = {
.name = "apq8064-tabla-snd-card",
.dai_link = msm_dai,
.num_links = ARRAY_SIZE(msm_dai),
@@ -2026,9 +2026,10 @@
static int __init msm_audio_init(void)
{
int ret;
-
- if (!cpu_is_apq8064() || (socinfo_get_id() == 130)) {
- pr_err("%s: Not the right machine type\n", __func__);
+ u32 version = socinfo_get_platform_version();
+ if (!cpu_is_apq8064() || (socinfo_get_id() == 130) ||
+ SOCINFO_VERSION_MINOR(version) == 1) {
+ pr_info("%s: Not APQ8064 in SLIMBUS mode\n", __func__);
return -ENODEV;
}
diff --git a/sound/soc/msm/mpq8064.c b/sound/soc/msm/mpq8064.c
index 3b880ed..be0395b 100644
--- a/sound/soc/msm/mpq8064.c
+++ b/sound/soc/msm/mpq8064.c
@@ -133,7 +133,7 @@
static int msm_ext_top_spk_pamp;
static int msm_slim_0_rx_ch = 1;
static int msm_slim_0_tx_ch = 1;
-static int msm_hdmi_rx_ch = 2;
+static int msm_hdmi_rx_ch = 8;
static struct clk *codec_clk;
static int clk_users;
@@ -515,14 +515,15 @@
static const char *spk_function[] = {"Off", "On"};
static const char *slim0_rx_ch_text[] = {"One", "Two"};
static const char *slim0_tx_ch_text[] = {"One", "Two", "Three", "Four"};
-static const char *hdmi_rx_ch_text[] = {"Two", "Three", "Four", "Five", "Six"};
+static const char * const hdmi_rx_ch_text[] = {"Two", "Three", "Four",
+ "Five", "Six", "Seven", "Eight"};
static const struct soc_enum msm_enum[] = {
SOC_ENUM_SINGLE_EXT(2, spk_function),
SOC_ENUM_SINGLE_EXT(2, slim0_rx_ch_text),
SOC_ENUM_SINGLE_EXT(4, slim0_tx_ch_text),
- SOC_ENUM_SINGLE_EXT(5, hdmi_rx_ch_text),
+ SOC_ENUM_SINGLE_EXT(7, hdmi_rx_ch_text),
};
diff --git a/sound/soc/msm/msm-compr-q6.c b/sound/soc/msm/msm-compr-q6.c
index 42bc979..bb138d3 100644
--- a/sound/soc/msm/msm-compr-q6.c
+++ b/sound/soc/msm/msm-compr-q6.c
@@ -26,6 +26,7 @@
#include <sound/initval.h>
#include <sound/control.h>
#include <sound/q6asm.h>
+#include <sound/pcm_params.h>
#include <asm/dma.h>
#include <linux/dma-mapping.h>
#include <linux/android_pmem.h>
@@ -82,12 +83,12 @@
.rate_min = 8000,
.rate_max = 48000,
.channels_min = 1,
- .channels_max = 2,
+ .channels_max = 8,
.buffer_bytes_max = 1200 * 1024 * 2,
- .period_bytes_min = 4800,
+ .period_bytes_min = 2400,
.period_bytes_max = 1200 * 1024,
.periods_min = 2,
- .periods_max = 512,
+ .periods_max = 1024,
.fifo_size = 0,
};
@@ -134,8 +135,6 @@
break;
} else
atomic_set(&prtd->pending_buffer, 0);
- if (runtime->status->hw_ptr >= runtime->control->appl_ptr)
- break;
buf = prtd->audio_client->port[IN].buf;
pr_debug("%s:writing %d bytes of buffer[%d] to dsp 2\n",
__func__, prtd->pcm_count, prtd->out_head);
@@ -197,7 +196,7 @@
buf = prtd->audio_client->port[OUT].buf;
pr_debug("pcm_irq_pos=%d, buf[0].phys = 0x%X\n",
prtd->pcm_irq_pos, (uint32_t)buf[0].phys);
- read_param.len = prtd->pcm_count - COMPRE_CAPTURE_HEADER_SIZE ;
+ read_param.len = prtd->pcm_count - COMPRE_CAPTURE_HEADER_SIZE;
read_param.paddr = (unsigned long)(buf[0].phys) +
prtd->pcm_irq_pos + COMPRE_CAPTURE_HEADER_SIZE;
prtd->pcm_irq_pos += prtd->pcm_count;
@@ -292,6 +291,7 @@
struct asm_aac_cfg aac_cfg;
struct asm_wma_cfg wma_cfg;
struct asm_wmapro_cfg wma_pro_cfg;
+ struct asm_amrwbplus_cfg amrwb_cfg;
int ret;
pr_debug("compressed stream prepare\n");
@@ -389,6 +389,27 @@
return ret;
}
break;
+ case SND_AUDIOCODEC_AMRWB:
+ pr_debug("SND_AUDIOCODEC_AMRWB\n");
+ ret = q6asm_media_format_block(prtd->audio_client,
+ compr->codec);
+ if (ret < 0) {
+ pr_err("%s: CMD Format block failed\n", __func__);
+ return ret;
+ }
+ break;
+ case SND_AUDIOCODEC_AMRWBPLUS:
+ pr_debug("SND_AUDIOCODEC_AMRWBPLUS\n");
+ memset(&amrwb_cfg, 0x0, sizeof(struct asm_amrwbplus_cfg));
+ amrwb_cfg.size_bytes = sizeof(struct asm_amrwbplus_cfg);
+ pr_debug("calling q6asm_media_format_block_amrwbplus");
+ ret = q6asm_media_format_block_amrwbplus(prtd->audio_client,
+ &amrwb_cfg);
+ if (ret < 0) {
+ pr_err("%s: CMD Format block failed\n", __func__);
+ return ret;
+ }
+ break;
default:
return -EINVAL;
}
@@ -405,6 +426,7 @@
struct compr_audio *compr = runtime->private_data;
struct msm_audio *prtd = &compr->prtd;
struct audio_buffer *buf = prtd->audio_client->port[OUT].buf;
+ struct snd_codec *codec = &compr->info.codec_param.codec;
struct audio_aio_read_param read_param;
int ret = 0;
int i;
@@ -419,6 +441,21 @@
if (prtd->enabled)
return ret;
read_param.len = prtd->pcm_count;
+
+ switch (codec->id) {
+ case SND_AUDIOCODEC_AMRWB:
+ pr_debug("SND_AUDIOCODEC_AMRWB\n");
+ ret = q6asm_enc_cfg_blk_amrwb(prtd->audio_client,
+ MAX_NUM_FRAMES_PER_BUFFER,
+ codec->options.generic.reserved[0] /*bitrate 0-8*/,
+ codec->options.generic.reserved[1] /*dtx mode 0/1*/);
+ if (ret < 0)
+ pr_err("%s: CMD Format block" \
+ "failed: %d\n", __func__, ret);
+ break;
+ default:
+ pr_debug("No config for codec %d\n", codec->id);
+ }
pr_debug("%s: Samp_rate = %d, Channel = %d, pcm_size = %d,\n"
"pcm_count = %d, periods = %d\n",
__func__, prtd->samp_rate, prtd->channel_mode,
@@ -426,8 +463,24 @@
for (i = 0; i < runtime->periods; i++) {
read_param.uid = i;
- read_param.paddr = (unsigned long)(buf[i].phys);
- q6asm_async_read_compressed(prtd->audio_client, &read_param);
+ switch (codec->id) {
+ case SND_AUDIOCODEC_AMRWB:
+ read_param.len = prtd->pcm_count
+ - COMPRE_CAPTURE_HEADER_SIZE;
+ read_param.paddr = (unsigned long)(buf[i].phys)
+ + COMPRE_CAPTURE_HEADER_SIZE;
+ pr_debug("Push buffer [%d] to DSP, "\
+ "paddr: %p, vaddr: %p\n",
+ i, (void *) read_param.paddr,
+ buf[i].data);
+ q6asm_async_read(prtd->audio_client, &read_param);
+ break;
+ default:
+ read_param.paddr = (unsigned long)(buf[i].phys);
+ q6asm_async_read_compressed(prtd->audio_client,
+ &read_param);
+ break;
+ }
}
prtd->periods = runtime->periods;
@@ -459,9 +512,16 @@
1);
}
} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
- msm_pcm_routing_reg_psthr_stream(
- soc_prtd->dai_link->be_id,
- prtd->session_id, substream->stream, 1);
+ switch (compr->info.codec_param.codec.id) {
+ case SND_AUDIOCODEC_AMRWB:
+ break;
+ default:
+ msm_pcm_routing_reg_psthr_stream(
+ soc_prtd->dai_link->be_id,
+ prtd->session_id, substream->stream,
+ 1);
+ break;
+ }
}
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
@@ -480,10 +540,16 @@
0);
}
} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
- msm_pcm_routing_reg_psthr_stream(
- soc_prtd->dai_link->be_id,
- prtd->session_id, substream->stream,
- 0);
+ switch (compr->info.codec_param.codec.id) {
+ case SND_AUDIOCODEC_AMRWB:
+ break;
+ default:
+ msm_pcm_routing_reg_psthr_stream(
+ soc_prtd->dai_link->be_id,
+ prtd->session_id, substream->stream,
+ 0);
+ break;
+ }
}
atomic_set(&prtd->start, 0);
break;
@@ -506,7 +572,7 @@
{
pr_debug("%s\n", __func__);
/* MP3 Block */
- compr->info.compr_cap.num_codecs = 1;
+ compr->info.compr_cap.num_codecs = 10;
compr->info.compr_cap.min_fragment_size = runtime->hw.period_bytes_min;
compr->info.compr_cap.max_fragment_size = runtime->hw.period_bytes_max;
compr->info.compr_cap.min_fragments = runtime->hw.periods_min;
@@ -519,7 +585,9 @@
compr->info.compr_cap.codecs[5] = SND_AUDIOCODEC_DTS;
compr->info.compr_cap.codecs[6] = SND_AUDIOCODEC_DTS_LBR;
compr->info.compr_cap.codecs[7] = SND_AUDIOCODEC_DTS_PASS_THROUGH;
- /* Add new codecs here */
+ compr->info.compr_cap.codecs[8] = SND_AUDIOCODEC_AMRWB;
+ compr->info.compr_cap.codecs[9] = SND_AUDIOCODEC_AMRWBPLUS;
+ /* Add new codecs here and update num_codecs*/
}
static int msm_compr_open(struct snd_pcm_substream *substream)
@@ -775,9 +843,29 @@
break;
}
} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
- ret = q6asm_open_read_compressed(prtd->audio_client,
- MAX_NUM_FRAMES_PER_BUFFER,
- COMPRESSED_META_DATA_MODE);
+ switch (compr->info.codec_param.codec.id) {
+ case SND_AUDIOCODEC_AMRWB:
+ pr_debug("q6asm_open_read(FORMAT_AMRWB)\n");
+ ret = q6asm_open_read(prtd->audio_client,
+ FORMAT_AMRWB);
+ if (ret < 0) {
+ pr_err("%s: compressed Session out open failed\n",
+ __func__);
+ return -ENOMEM;
+ }
+ pr_debug("msm_pcm_routing_reg_phy_stream\n");
+ msm_pcm_routing_reg_phy_stream(
+ soc_prtd->dai_link->be_id,
+ prtd->audio_client->perf_mode,
+ prtd->session_id, substream->stream);
+ break;
+ default:
+ pr_debug("q6asm_open_read_compressed(COMPRESSED_META_DATA_MODE)\n");
+ ret = q6asm_open_read_compressed(prtd->audio_client,
+ MAX_NUM_FRAMES_PER_BUFFER,
+ COMPRESSED_META_DATA_MODE);
+ break;
+ }
if (ret < 0) {
pr_err("%s: compressed Session out open failed\n",
@@ -785,12 +873,23 @@
return -ENOMEM;
}
}
+
ret = q6asm_set_io_mode(prtd->audio_client, ASYNC_IO_MODE);
if (ret < 0) {
pr_err("%s: Set IO mode failed\n", __func__);
return -ENOMEM;
}
-
+ /* Modifying kernel hardware params based on userspace config */
+ if (params_periods(params) > 0 &&
+ (params_periods(params) != runtime->hw.periods_max)) {
+ runtime->hw.periods_max = params_periods(params);
+ }
+ if (params_period_bytes(params) > 0 &&
+ (params_period_bytes(params) != runtime->hw.period_bytes_min)) {
+ runtime->hw.period_bytes_min = params_period_bytes(params);
+ }
+ runtime->hw.buffer_bytes_max =
+ runtime->hw.period_bytes_min * runtime->hw.periods_max;
ret = q6asm_audio_client_buf_alloc_contiguous(dir,
prtd->audio_client,
runtime->hw.period_bytes_min,
@@ -906,22 +1005,37 @@
pr_debug("SND_AUDIOCODEC_DTS\n");
compr->codec = FORMAT_DTS_LBR;
break;
- default:
- pr_debug("FORMAT_LINEAR_PCM\n");
- compr->codec = FORMAT_LINEAR_PCM;
+ case SND_AUDIOCODEC_AMRWB:
+ pr_debug("msm_compr_ioctl SND_AUDIOCODEC_AMRWB\n");
+ compr->codec = FORMAT_AMRWB;
break;
+ case SND_AUDIOCODEC_AMRWBPLUS:
+ pr_debug("msm_compr_ioctl SND_AUDIOCODEC_AMRWBPLUS\n");
+ compr->codec = FORMAT_AMR_WB_PLUS;
+ break;
+ default:
+ pr_err("msm_compr_ioctl failed..unknown codec\n");
+ return -EFAULT;
}
return 0;
case SNDRV_PCM_IOCTL1_RESET:
- prtd->cmd_ack = 0;
- rc = q6asm_cmd(prtd->audio_client, CMD_FLUSH);
- if (rc < 0)
- pr_err("%s: flush cmd failed rc=%d\n", __func__, rc);
- rc = wait_event_timeout(the_locks.eos_wait,
- prtd->cmd_ack, 5 * HZ);
- if (rc < 0)
- pr_err("Flush cmd timeout\n");
- prtd->pcm_irq_pos = 0;
+ pr_debug("SNDRV_PCM_IOCTL1_RESET\n");
+ /* Flush only when session is started during CAPTURE,
+ while PLAYBACK has no such restriction. */
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ||
+ (substream->stream == SNDRV_PCM_STREAM_CAPTURE &&
+ atomic_read(&prtd->start))) {
+ prtd->cmd_ack = 0;
+ rc = q6asm_cmd(prtd->audio_client, CMD_FLUSH);
+ if (rc < 0)
+ pr_err("%s: flush cmd failed rc=%d\n",
+ __func__, rc);
+ rc = wait_event_timeout(the_locks.eos_wait,
+ prtd->cmd_ack, 5 * HZ);
+ if (rc < 0)
+ pr_err("Flush cmd timeout\n");
+ prtd->pcm_irq_pos = 0;
+ }
break;
default:
break;
diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c
index 011ff29..011912e 100644
--- a/sound/soc/msm/msm-dai-fe.c
+++ b/sound/soc/msm/msm-dai-fe.c
@@ -82,7 +82,7 @@
SNDRV_PCM_RATE_KNOT),
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.channels_min = 1,
- .channels_max = 6,
+ .channels_max = 8,
.rate_min = 8000,
.rate_max = 48000,
},
@@ -173,7 +173,7 @@
SNDRV_PCM_RATE_KNOT),
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.channels_min = 1,
- .channels_max = 6,
+ .channels_max = 8,
.rate_min = 8000,
.rate_max = 48000,
},
diff --git a/sound/soc/msm/msm-dai-q6-hdmi.c b/sound/soc/msm/msm-dai-q6-hdmi.c
index c082ed7..2b3dd5f 100644
--- a/sound/soc/msm/msm-dai-q6-hdmi.c
+++ b/sound/soc/msm/msm-dai-q6-hdmi.c
@@ -111,6 +111,13 @@
dai_data->port_config.hdmi_multi_ch.channel_allocation =
channel_allocation;
break;
+ case 8:
+ channel_allocation = 0x1F;
+ hdmi_msm_audio_info_setup(1, MSM_HDMI_AUDIO_CHANNEL_8,
+ channel_allocation, level_shift, down_mix);
+ dai_data->port_config.hdmi_multi_ch.channel_allocation =
+ channel_allocation;
+ break;
default:
dev_err(dai->dev, "invalid Channels = %u\n",
dai_data->channels);
diff --git a/sound/soc/msm/msm-dai-q6.c b/sound/soc/msm/msm-dai-q6.c
index 89b709f..ee1ab79 100644
--- a/sound/soc/msm/msm-dai-q6.c
+++ b/sound/soc/msm/msm-dai-q6.c
@@ -465,6 +465,9 @@
dai_data->channels = params_channels(params);
switch (dai_data->channels) {
case 2:
+ case 4:
+ case 6:
+ case 8:
dai_data->port_config.mi2s.channel = MSM_AFE_STEREO;
break;
case 1:
diff --git a/sound/soc/msm/msm-multi-ch-pcm-q6.c b/sound/soc/msm/msm-multi-ch-pcm-q6.c
index a13d4da..6945a4f 100644
--- a/sound/soc/msm/msm-multi-ch-pcm-q6.c
+++ b/sound/soc/msm/msm-multi-ch-pcm-q6.c
@@ -28,6 +28,7 @@
#include <sound/pcm.h>
#include <sound/initval.h>
#include <sound/control.h>
+#include <sound/timer.h>
#include "msm-pcm-q6.h"
#include "msm-pcm-routing.h"
@@ -83,7 +84,7 @@
.rate_min = 8000,
.rate_max = 48000,
.channels_min = 1,
- .channels_max = 6,
+ .channels_max = 8,
.buffer_bytes_max = PLAYBACK_NUM_PERIODS * PLAYBACK_MAX_PERIOD_SIZE,
.period_bytes_min = PLAYBACK_MIN_PERIOD_SIZE,
.period_bytes_max = PLAYBACK_MAX_PERIOD_SIZE,
@@ -110,6 +111,9 @@
{
struct msm_audio *prtd = priv;
struct snd_pcm_substream *substream = prtd->substream;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct audio_aio_write_param param;
+ struct audio_buffer *buf = NULL;
uint32_t *ptrmem = (uint32_t *)payload;
int i = 0;
uint32_t idx = 0;
@@ -118,6 +122,7 @@
pr_debug("%s\n", __func__);
switch (opcode) {
case ASM_DATA_EVENT_WRITE_DONE: {
+ uint32_t *ptrmem = (uint32_t *)¶m;
pr_debug("ASM_DATA_EVENT_WRITE_DONE\n");
pr_debug("Buffer Consumed = 0x%08x\n", *ptrmem);
prtd->pcm_irq_pos += prtd->pcm_count;
@@ -129,14 +134,31 @@
break;
if (!prtd->mmap_flag)
break;
- if (q6asm_is_cpu_buf_avail_nolock(IN,
- prtd->audio_client,
- &size, &idx)) {
- pr_debug("%s:writing %d bytes of buffer to dsp 2\n",
- __func__, prtd->pcm_count);
- q6asm_write_nolock(prtd->audio_client,
- prtd->pcm_count, 0, 0, NO_TIMESTAMP);
- }
+ buf = prtd->audio_client->port[IN].buf;
+ pr_debug("%s:writing %d bytes of buffer[%d] to dsp 2\n",
+ __func__, prtd->pcm_count, prtd->out_head);
+ pr_debug("%s:writing buffer[%d] from 0x%08x\n",
+ __func__, prtd->out_head,
+ ((unsigned int)buf[0].phys
+ + (prtd->out_head * prtd->pcm_count)));
+ param.paddr = (unsigned long)buf[0].phys
+ + (prtd->out_head * prtd->pcm_count);
+ param.len = prtd->pcm_count;
+ param.msw_ts = 0;
+ param.lsw_ts = 0;
+ param.flags = NO_TIMESTAMP;
+ param.uid = (unsigned long)buf[0].phys
+ + (prtd->out_head * prtd->pcm_count);
+ for (i = 0; i < sizeof(struct audio_aio_write_param)/4;
+ i++, ++ptrmem)
+ pr_debug("cmd[%d]=0x%08x\n", i, *ptrmem);
+ if (q6asm_async_write(prtd->audio_client,
+ ¶m) < 0)
+ pr_err("%s:q6asm_async_write failed\n",
+ __func__);
+ else
+ prtd->out_head =
+ (prtd->out_head + 1) & (runtime->periods - 1);
break;
}
case ASM_DATA_CMDRSP_EOS:
@@ -173,27 +195,28 @@
atomic_set(&prtd->start, 1);
break;
}
- if (prtd->mmap_flag) {
- pr_debug("%s:writing %d bytes"
- " of buffer to dsp\n",
- __func__,
- prtd->pcm_count);
- q6asm_write_nolock(prtd->audio_client,
- prtd->pcm_count,
- 0, 0, NO_TIMESTAMP);
- } else {
- while (atomic_read(&prtd->out_needed)) {
- pr_debug("%s:writing %d bytes"
- " of buffer to dsp\n",
- __func__,
- prtd->pcm_count);
- q6asm_write_nolock(prtd->audio_client,
- prtd->pcm_count,
- 0, 0, NO_TIMESTAMP);
- atomic_dec(&prtd->out_needed);
- wake_up(&the_locks.write_wait);
- };
- }
+ pr_debug("%s:writing %d bytes"\
+ " of buffer[%d] to dsp\n",
+ __func__, prtd->pcm_count, prtd->out_head);
+ buf = prtd->audio_client->port[IN].buf;
+ pr_debug("%s:writing buffer[%d] from 0x%08x\n",
+ __func__, prtd->out_head,
+ ((unsigned int)buf[0].phys
+ + (prtd->out_head * prtd->pcm_count)));
+ param.paddr = (unsigned long)buf[prtd->out_head].phys;
+ param.len = prtd->pcm_count;
+ param.msw_ts = 0;
+ param.lsw_ts = 0;
+ param.flags = NO_TIMESTAMP;
+ param.uid = (unsigned long)buf[prtd->out_head].phys;
+ if (q6asm_async_write(prtd->audio_client,
+ ¶m) < 0)
+ pr_err("%s:q6asm_async_write failed\n",
+ __func__);
+ else
+ prtd->out_head =
+ (prtd->out_head + 1)
+ & (runtime->periods - 1);
atomic_set(&prtd->start, 1);
break;
default:
@@ -708,10 +731,12 @@
else
dir = OUT;
- /*
- *TODO : Need to Add Async IO changes. All period
- * size might not be supported.
- */
+ ret = q6asm_set_io_mode(prtd->audio_client, ASYNC_IO_MODE);
+ if (ret < 0) {
+ pr_err("%s: Set IO mode failed\n", __func__);
+ return -ENOMEM;
+ }
+
ret = q6asm_audio_client_buf_alloc_contiguous(dir,
prtd->audio_client,
(params_buffer_bytes(params) / params_periods(params)),
diff --git a/sound/soc/msm/msm-pcm-routing.c b/sound/soc/msm/msm-pcm-routing.c
index 374357d..6456b2a 100644
--- a/sound/soc/msm/msm-pcm-routing.c
+++ b/sound/soc/msm/msm-pcm-routing.c
@@ -1302,6 +1302,9 @@
SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_INT_BT_SCO_RX,
MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new int_fm_rx_mixer_controls[] = {
@@ -1317,6 +1320,9 @@
SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_INT_FM_RX,
MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_INT_FM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new afe_pcm_rx_mixer_controls[] = {
@@ -1332,6 +1338,9 @@
SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_AFE_PCM_RX,
MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_AFE_PCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new auxpcm_rx_mixer_controls[] = {
@@ -1347,6 +1356,9 @@
SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_AUXPCM_RX,
MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new sec_auxpcm_rx_mixer_controls[] = {
@@ -1407,6 +1419,18 @@
SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_AFE_PCM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_INT_BT_SCO_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
@@ -1414,6 +1438,9 @@
SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_MI2S_TX,
MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer)
};
static const struct snd_kcontrol_new pri_rx_voice_mixer_controls[] = {
@@ -2322,12 +2349,14 @@
{"MI2S_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
{"MI2S_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
{"MI2S_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"MI2S_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
{"MI2S_RX", NULL, "MI2S_RX Audio Mixer"},
{"MultiMedia1 Mixer", "PRI_TX", "PRI_I2S_TX"},
{"MultiMedia1 Mixer", "MI2S_TX", "MI2S_TX"},
{"MultiMedia2 Mixer", "MI2S_TX", "MI2S_TX"},
{"MultiMedia4 Mixer", "MI2S_TX", "MI2S_TX"},
+ {"MultiMedia4 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
{"MultiMedia1 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
{"MultiMedia1 Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
{"MultiMedia1 Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"},
@@ -2336,24 +2365,30 @@
{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
{"INT_BT_SCO_RX", NULL, "INTERNAL_BT_SCO_RX Audio Mixer"},
{"INTERNAL_FM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
{"INTERNAL_FM_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
{"INTERNAL_FM_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
{"INTERNAL_FM_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"INTERNAL_FM_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
{"INT_FM_RX", NULL, "INTERNAL_FM_RX Audio Mixer"},
{"AFE_PCM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
{"AFE_PCM_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
{"AFE_PCM_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
{"AFE_PCM_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"AFE_PCM_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
{"PCM_RX", NULL, "AFE_PCM_RX Audio Mixer"},
{"MultiMedia1 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+ {"MultiMedia5 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
{"MultiMedia1 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+ {"MultiMedia5 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
{"MultiMedia1 Mixer", "AFE_PCM_TX", "PCM_TX"},
+ {"MultiMedia5 Mixer", "AFE_PCM_TX", "PCM_TX"},
{"MM_UL1", NULL, "MultiMedia1 Mixer"},
{"MultiMedia2 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
{"MM_UL2", NULL, "MultiMedia2 Mixer"},
@@ -2364,6 +2399,7 @@
{"AUX_PCM_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
{"AUX_PCM_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
{"AUX_PCM_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"AUX_PCM_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
{"AUX_PCM_RX", NULL, "AUX_PCM_RX Audio Mixer"},
{"SEC_AUX_PCM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
diff --git a/sound/soc/msm/msm8930.c b/sound/soc/msm/msm8930.c
index a577b6a..c8d4b02 100644
--- a/sound/soc/msm/msm8930.c
+++ b/sound/soc/msm/msm8930.c
@@ -38,6 +38,7 @@
#define SPK_AMP_POS 0x1
#define SPK_AMP_NEG 0x2
#define SPKR_BOOST_GPIO 15
+#define LEFT_SPKR_AMPL_GPIO 15
#define DEFAULT_PMIC_SPK_GAIN 0x0D
#define SITAR_EXT_CLK_RATE 12288000
@@ -121,6 +122,24 @@
return 1;
}
+static int msm8930_cfg_spkr_gpio(int gpio,
+ int enable, const char *gpio_label)
+{
+ int ret = 0;
+
+ pr_debug("%s: Configure %s GPIO %u",
+ __func__, gpio_label, gpio);
+ ret = gpio_request(gpio, gpio_label);
+ if (ret)
+ return ret;
+
+ pr_debug("%s: Enable %s gpio %u\n",
+ __func__, gpio_label, gpio);
+ gpio_direction_output(gpio, enable);
+
+ return ret;
+}
+
static void msm8960_ext_spk_power_amp_on(u32 spk)
{
int ret = 0;
@@ -139,24 +158,30 @@
if ((msm8930_ext_spk_pamp & SPK_AMP_POS) &&
(msm8930_ext_spk_pamp & SPK_AMP_NEG)) {
- if (machine_is_msm8930_mtp()
- || machine_is_msm8930_fluid()) {
- pr_debug("%s: Configure Speaker Boost GPIO %u",
- __func__, SPKR_BOOST_GPIO);
- ret = gpio_request(SPKR_BOOST_GPIO,
- "SPKR_BOOST_EN");
+ if (socinfo_get_pmic_model() == PMIC_MODEL_PM8917) {
+ ret = msm8930_cfg_spkr_gpio(
+ LEFT_SPKR_AMPL_GPIO,
+ 1, "LEFT_SPKR_AMPL");
if (ret) {
- pr_err("%s: Failed to configure speaker boost "
- "gpio %u\n", __func__, SPKR_BOOST_GPIO);
+ pr_err("%s: Failed to config ampl gpio %u\n",
+ __func__, LEFT_SPKR_AMPL_GPIO);
return;
}
+ } else {
- pr_debug("%s: Enable Speaker boost gpio %u\n",
- __func__, SPKR_BOOST_GPIO);
- gpio_direction_output(SPKR_BOOST_GPIO, 1);
+ if (machine_is_msm8930_mtp()
+ || machine_is_msm8930_fluid()) {
+ ret = msm8930_cfg_spkr_gpio(
+ SPKR_BOOST_GPIO, 1, "SPKR_BOOST");
+ if (ret) {
+ pr_err("%s: Failure: spkr boost gpio %u\n",
+ __func__, SPKR_BOOST_GPIO);
+ return;
+ }
+ }
+ pm8xxx_spk_enable(MSM8930_SPK_ON);
}
- pm8xxx_spk_enable(MSM8930_SPK_ON);
pr_debug("%s: slepping 4 ms after turning on external "
" Left Speaker Ampl\n", __func__);
usleep_range(4000, 4000);
@@ -175,6 +200,13 @@
if (spk & (SPK_AMP_POS | SPK_AMP_NEG)) {
if (!msm8930_ext_spk_pamp)
return;
+
+ if (socinfo_get_pmic_model() == PMIC_MODEL_PM8917) {
+ gpio_free(LEFT_SPKR_AMPL_GPIO);
+ msm8930_ext_spk_pamp = 0;
+ return;
+ }
+
if (machine_is_msm8930_mtp()
|| machine_is_msm8930_fluid()) {
pr_debug("%s: Free speaker boost gpio %u\n",
@@ -463,7 +495,8 @@
{
int ret = 0;
msm8930_pmic_spk_gain = ucontrol->value.integer.value[0];
- ret = pm8xxx_spk_gain(msm8930_pmic_spk_gain);
+ if (socinfo_get_pmic_model() != PMIC_MODEL_PM8917)
+ ret = pm8xxx_spk_gain(msm8930_pmic_spk_gain);
pr_debug("%s: msm8930_pmic_spk_gain = %d"
" ucontrol->value.integer.value[0] = %d\n", __func__,
msm8930_pmic_spk_gain,
@@ -660,8 +693,10 @@
mbhc_cfg.gpio_irq = gpio_to_irq(mbhc_cfg.gpio);
sitar_hs_detect(codec, &mbhc_cfg);
- /* Initialize default PMIC speaker gain */
- pm8xxx_spk_gain(DEFAULT_PMIC_SPK_GAIN);
+ if (socinfo_get_pmic_model() != PMIC_MODEL_PM8917) {
+ /* Initialize default PMIC speaker gain */
+ pm8xxx_spk_gain(DEFAULT_PMIC_SPK_GAIN);
+ }
return 0;
}
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index 545a5b9..45b69ea 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -954,7 +954,7 @@
},
};
-struct snd_soc_card snd_soc_card_msm = {
+static struct snd_soc_card snd_soc_card_msm = {
.name = "msm8974-taiko-snd-card",
.dai_link = msm_dai,
.num_links = ARRAY_SIZE(msm_dai),
@@ -976,7 +976,7 @@
mutex_init(&cdc_mclk_mutex);
if (!machine_is_msm8974_sim()) {
- pr_err("%s: Not the right machine type\n", __func__);
+ pr_info("%s: Not msm8974 machine type\n", __func__);
return -ENODEV;
}
msm_snd_device = platform_device_alloc("soc-audio", 0);
diff --git a/sound/soc/msm/qdsp6/q6asm.c b/sound/soc/msm/qdsp6/q6asm.c
index 76940ee..1aac158 100644
--- a/sound/soc/msm/qdsp6/q6asm.c
+++ b/sound/soc/msm/qdsp6/q6asm.c
@@ -1526,6 +1526,14 @@
case FORMAT_DTS_LBR:
open.format = DTS_LBR;
break;
+ case FORMAT_AMRWB:
+ open.format = AMRWB_FS;
+ pr_debug("q6asm_open_write FORMAT_AMRWB");
+ break;
+ case FORMAT_AMR_WB_PLUS:
+ open.format = AMR_WB_PLUS;
+ pr_debug("q6asm_open_write FORMAT_AMR_WB_PLUS");
+ break;
default:
pr_err("%s: Invalid format[%d]\n", __func__, format);
goto fail_cmd;
@@ -2372,7 +2380,56 @@
return -EINVAL;
}
+int q6asm_media_format_block_amrwbplus(struct audio_client *ac,
+ struct asm_amrwbplus_cfg *cfg)
+{
+ struct asm_stream_media_format_update fmt;
+ int rc = 0;
+ pr_debug("q6asm_media_format_block_amrwbplus");
+ pr_debug("%s:session[%d]band-mode[%d]frame-fmt[%d]ch[%d]\n",
+ __func__,
+ ac->session,
+ cfg->amr_band_mode,
+ cfg->amr_frame_fmt,
+ cfg->num_channels);
+
+ q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
+
+ fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FORMAT_UPDATE;
+
+ fmt.format = AMR_WB_PLUS;
+ fmt.cfg_size = cfg->size_bytes;
+
+ fmt.write_cfg.amrwbplus_cfg.size_bytes = cfg->size_bytes;
+ fmt.write_cfg.amrwbplus_cfg.version = cfg->version;
+ fmt.write_cfg.amrwbplus_cfg.num_channels = cfg->num_channels;
+ fmt.write_cfg.amrwbplus_cfg.amr_band_mode = cfg->amr_band_mode;
+ fmt.write_cfg.amrwbplus_cfg.amr_dtx_mode = cfg->amr_dtx_mode;
+ fmt.write_cfg.amrwbplus_cfg.amr_frame_fmt = cfg->amr_frame_fmt;
+ fmt.write_cfg.amrwbplus_cfg.amr_lsf_idx = cfg->amr_lsf_idx;
+
+ pr_debug("%s: num_channels=%x amr_band_mode=%d amr_frame_fmt=%d\n",
+ __func__,
+ cfg->num_channels,
+ cfg->amr_band_mode,
+ cfg->amr_frame_fmt);
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
+ if (rc < 0) {
+ pr_err("%s:Comamnd media format update failed..\n", __func__);
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s:timeout. waited for FORMAT_UPDATE\n", __func__);
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return -EINVAL;
+}
int q6asm_media_format_block_multi_aac(struct audio_client *ac,
struct asm_aac_cfg *cfg)
{
@@ -2444,6 +2501,9 @@
case FORMAT_AMRWB:
fmt.format = AMRWB_FS;
break;
+ case FORMAT_AMR_WB_PLUS:
+ fmt.format = AMR_WB_PLUS;
+ break;
case FORMAT_AMRNB:
fmt.format = AMRNB_FS;
break;
diff --git a/tools/perf/Documentation/perf-script-json-export.txt b/tools/perf/Documentation/perf-script-json-export.txt
new file mode 100644
index 0000000..dd47c7c
--- /dev/null
+++ b/tools/perf/Documentation/perf-script-json-export.txt
@@ -0,0 +1,29 @@
+perf-script-json-export(1)
+====================
+
+NAME
+----
+perf-script-json-export - Export trace data to JSON
+
+SYNOPSIS
+--------
+[verse]
+'perf script' -g JSON:<script>
+'perf script' -g <script.json>
+'perf script' -s JSON:<script> [option]*
+'perf script' -s <script.json> [option]*
+
+DESCRIPTION
+-----------
+
+This perf script option is used to export perf script data using JSON
+format. JSON export extesion is identified either by the 'JSON:'
+prefix or the '.json' file extension.
+
+Both command forms export JSON fomatted data. The '-g'/'--gen-script'
+option does not include actual event data. Only Definitions. '-s'
+version includes events and definition data (by default).
+
+SEE ALSO
+--------
+linkperf:perf-script[1]
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 80f23c0..0cff0ca 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -633,6 +633,12 @@
endif
endif
+ifdef NO_JSON_EXPORT
+ BASIC_CFLAGS += -DNO_JSON_EXPORT
+else
+ LIB_OBJS += $(OUTPUT)util/scripting-engines/trace-event-json-export.o
+endif
+
ifdef NO_DEMANGLE
BASIC_CFLAGS += -DNO_DEMANGLE
else
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index 704d63a..f7f18c7 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -469,6 +469,7 @@
{
setup_perl_scripting();
setup_python_scripting();
+ setup_json_export();
scripting_ops = &default_scripting_ops;
}
diff --git a/tools/perf/util/scripting-engines/trace-event-json-export.c b/tools/perf/util/scripting-engines/trace-event-json-export.c
new file mode 100644
index 0000000..3fb6da7
--- /dev/null
+++ b/tools/perf/util/scripting-engines/trace-event-json-export.c
@@ -0,0 +1,322 @@
+/*
+ * trace-event-json-export. Export events to JSON format.
+ *
+ * derived from: trace-event-python.c
+ *
+ * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+ * Copyright (C) 2010 Tom Zanussi <tzanussi@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include "../../perf.h"
+#include "../util.h"
+#include "../trace-event.h"
+#include "../event.h"
+#include "../thread.h"
+
+#define FTRACE_MAX_EVENT \
+ ((1 << (sizeof(unsigned short) * 8)) - 1)
+
+FILE *ofp;
+struct event *events[FTRACE_MAX_EVENT];
+static char *cur_field_name;
+
+static void define_value(enum print_arg_type field_type,
+ int id,
+ const char *field_name,
+ const char *field_value,
+ const char *field_str)
+{
+ const char *handler_name = (field_type == PRINT_SYMBOL) ?
+ "define_symbol" : "define_flag";
+ unsigned long long value;
+
+ value = eval_flag(field_value);
+
+ fprintf(ofp , ",\n[\"%s\",%d,{\"field\":\"%s\",\"value\":%llu,
+ \"name\":\"%s\"}]",
+ handler_name, id, field_name, value, field_str);
+}
+
+static void define_values(enum print_arg_type field_type,
+ struct print_flag_sym *field,
+ int id,
+ const char *field_name)
+{
+ define_value(field_type, id, field_name, field->value,
+ field->str);
+
+ if (field->next)
+ define_values(field_type, field->next, id, field_name);
+}
+
+static void define_field(enum print_arg_type field_type,
+ int id,
+ const char *field_name,
+ const char *delim)
+{
+ if (field_type == PRINT_FLAGS) {
+ const char *handler_name = "define_flag_field";
+ fprintf(ofp , ",\n[\"%s\",%d,{\"field\":\"%s\",
+ \"delim\":\"%s\"}]",
+ handler_name, id, field_name, delim);
+ } else {
+ const char *handler_name = "define_symbol_field";
+ fprintf(ofp , ",\n[\"%s\",%d,{\"field\":\"%s\"}]",
+ handler_name, id, field_name);
+ }
+}
+
+static void define_event_symbols(struct event *event,
+ struct print_arg *args)
+{
+ switch (args->type) {
+ case PRINT_NULL:
+ break;
+ case PRINT_ATOM:
+ define_value(PRINT_FLAGS, event->id, cur_field_name, "0",
+ args->atom.atom);
+ break;
+ case PRINT_FIELD:
+ cur_field_name = args->field.name;
+ break;
+ case PRINT_FLAGS:
+ define_event_symbols(event, args->flags.field);
+ define_field(PRINT_FLAGS, event->id, cur_field_name,
+ args->flags.delim);
+ define_values(PRINT_FLAGS, args->flags.flags, event->id,
+ cur_field_name);
+ break;
+ case PRINT_SYMBOL:
+ define_event_symbols(event, args->symbol.field);
+ define_field(PRINT_SYMBOL, event->id, cur_field_name, NULL);
+ define_values(PRINT_SYMBOL, args->symbol.symbols, event->id,
+ cur_field_name);
+ break;
+ case PRINT_STRING:
+ break;
+ case PRINT_TYPE:
+ define_event_symbols(event, args->typecast.item);
+ break;
+ case PRINT_OP:
+ define_event_symbols(event, args->op.left);
+ define_event_symbols(event, args->op.right);
+ break;
+ default:
+ /* we should warn... */
+ return;
+ }
+
+ if (args->next)
+ define_event_symbols(event, args->next);
+}
+
+#define prefix(indx) (indx ? "," : "")
+static void define_event(struct event *event)
+{
+ const char *ev_system = event->system;
+ const char *ev_name = event->name;
+ int indx = 0;
+ const char *handler_name = "define_event";
+ struct format_field *field = 0;
+
+ fprintf(ofp , ",\n[\"%s\",%d,{\"system\":\"%s\",
+ \"name\":\"%s\",\"args\":{",
+ handler_name, event->id, ev_system, ev_name);
+
+ fprintf(ofp , "%s\"%s\":%d", prefix(indx), "common_s", indx);
+ indx++;
+ fprintf(ofp , "%s\"%s\":%d", prefix(indx), "common_ns", indx);
+ indx++;
+ fprintf(ofp , "%s\"%s\":%d", prefix(indx), "common_cpu", indx);
+ indx++;
+ fprintf(ofp , "%s\"%s\":%d", prefix(indx), "common_comm", indx);
+ indx++;
+ for (field = event->format.common_fields; field; field = field->next) {
+ fprintf(ofp , "%s\"%s\":%d", prefix(indx), field->name, indx);
+ indx++;
+ }
+ for (field = event->format.fields; field; field = field->next) {
+ fprintf(ofp , "%s\"%s\":%d", prefix(indx), field->name, indx);
+ indx++;
+ }
+ fprintf(ofp , "}}]");
+}
+
+static inline struct event *find_cache_event(int type)
+{
+ struct event *event;
+
+ if (events[type])
+ return events[type];
+
+ events[type] = event = trace_find_event(type);
+ if (!event)
+ return NULL;
+
+ define_event(event);
+ define_event_symbols(event, event->print_fmt.args);
+
+ return event;
+}
+
+static void json_process_field(int indx, void *data, struct format_field *field)
+{
+ unsigned long long val;
+
+ if (field->flags & FIELD_IS_STRING) {
+ int offset;
+ if (field->flags & FIELD_IS_DYNAMIC) {
+ offset = *(int *)(data + field->offset);
+ offset &= 0xffff;
+ } else
+ offset = field->offset;
+ fprintf(ofp , "%s\"%s\"", prefix(indx), (char *)data + offset);
+ } else { /* FIELD_IS_NUMERIC */
+ val = read_size(data + field->offset, field->size);
+ if (field->flags & FIELD_IS_SIGNED)
+ fprintf(ofp , "%s%lld", prefix(indx),
+ (long long int) val);
+ else
+ fprintf(ofp , "%s%llu", prefix(indx), val);
+ }
+}
+
+static void json_process_event(union perf_event *pevent __unused,
+ struct perf_sample *sample,
+ struct perf_evsel *evsel __unused,
+ struct machine *machine __unused,
+ struct thread *thread)
+{
+ struct format_field *field;
+ unsigned long s, ns;
+ struct event *event;
+ int type;
+ int indx = 0;
+ int cpu = sample->cpu;
+ void *data = sample->raw_data;
+ unsigned long long nsecs = sample->time;
+ char *comm = thread->comm;
+
+ type = trace_parse_common_type(data);
+
+ event = find_cache_event(type);
+ if (!event)
+ die("ug! no event found for type %d", type);
+
+ s = nsecs / NSECS_PER_SEC;
+ ns = nsecs - s * NSECS_PER_SEC;
+
+ fprintf(ofp , ",\n[\"event\",%d,[%lu,%lu,%d,\"%s\"",
+ type, s, ns, cpu, comm);
+
+ indx += 4;
+
+ for (field = event->format.common_fields; field; field = field->next)
+ json_process_field(indx++, data, field);
+
+ for (field = event->format.fields; field; field = field->next)
+ json_process_field(indx++, data, field);
+
+ fprintf(ofp , "]]");
+}
+
+/*
+ * Start trace script
+ */
+static int json_start_script(const char *script, int argc __unused,
+ const char **argv __unused)
+{
+ int err = 0;
+
+ if (script[0]) {
+ ofp = fopen(script, "w");
+ if (ofp == NULL) {
+ fprintf(stderr, "couldn't open %s\n", script);
+ return -EBADF;
+ }
+ } else
+ ofp = stdout;
+
+ fprintf(ofp , "[[\"trace_start\"]");
+
+ return err;
+}
+
+/*
+ * Stop trace script
+ */
+static int json_stop_script(void)
+{
+ int err = 0;
+
+ fprintf(ofp , ",\n[\"trace_end\"]]");
+
+ return err;
+}
+
+static int json_generate_script(const char *outfile)
+{
+ struct event *event = NULL;
+ char fname[PATH_MAX];
+
+ snprintf(fname, sizeof(fname), "%s.json", outfile);
+
+ ofp = fopen(fname, "w");
+
+ if (ofp == NULL) {
+ fprintf(stderr, "couldn't open %s\n", fname);
+ return -EBADF;
+ }
+ fprintf(ofp , "[[\"generate_start\"]");
+
+ while ((event = trace_find_next_event(event))) {
+ define_event(event);
+ define_event_symbols(event, event->print_fmt.args);
+ }
+
+ fprintf(ofp , ",\n[\"generate_end\"]]");
+
+ fclose(ofp);
+
+ fprintf(stderr, "generated json script: %s\n", fname);
+
+ return 0;
+}
+
+struct scripting_ops json_scripting_ops = {
+ .name = "JSON",
+ .start_script = json_start_script,
+ .stop_script = json_stop_script,
+ .process_event = json_process_event,
+ .generate_script = json_generate_script,
+};
+
+void setup_json_export(void)
+{
+ int err;
+ err = script_spec_register("JSON", &json_scripting_ops);
+ if (err)
+ die("error registering JSON export extension");
+}
+
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h
index 58ae14c..0a6009d 100644
--- a/tools/perf/util/trace-event.h
+++ b/tools/perf/util/trace-event.h
@@ -305,6 +305,7 @@
void setup_perl_scripting(void);
void setup_python_scripting(void);
+void setup_json_export(void);
struct scripting_context {
void *event_data;