Merge "arm/dt: msm8610: Add ADC_TM node"
diff --git a/Documentation/devicetree/bindings/arm/msm/memory-reserve.txt b/Documentation/devicetree/bindings/arm/msm/memory-reserve.txt
index c1b79ae..6dac1b7 100644
--- a/Documentation/devicetree/bindings/arm/msm/memory-reserve.txt
+++ b/Documentation/devicetree/bindings/arm/msm/memory-reserve.txt
@@ -69,3 +69,20 @@
This region is assumed to be a part of a separate hole that has been removed
and this binding specifies the fixed location and size of the region within
that hole.
+
+
+Some drivers may only wish to reserve memory from the system. Reserved memory
+is still tracked internally by the Linux page allocator. The memory is reserved
+from the buddy allocator at bootup but may be freed back at a later point in
+time with memblock_free and free_bootmem_late.
+
+Required parameters:
+-qcom,memblock-reserve: base and size of block to be reserved. Drivers should
+call memblock_is_reserved before attempting to use the base address to ensure
+the memory was completely reserved.
+
+ qcom,a-driver {
+ compatible = "qcom,a-driver";
+ /* reserve a 4MB region @ 0x200000 for use later */
+ qcom,memblock-reserve = <0x200000 0x400000>;
+ };
diff --git a/Documentation/devicetree/bindings/arm/msm/msm_tspp.txt b/Documentation/devicetree/bindings/arm/msm/msm_tspp.txt
index cfda474..5692ad2 100644
--- a/Documentation/devicetree/bindings/arm/msm/msm_tspp.txt
+++ b/Documentation/devicetree/bindings/arm/msm/msm_tspp.txt
@@ -34,6 +34,13 @@
Some hardware platforms (e.g. 8974-v2) require the voltage of the rail
supplying power to the TSIF hardware block to be elevated before
enabling the TSIF clocks.
+- Refer to "Documentation/devicetree/bindings/arm/msm/msm_bus.txt" for
+ the below optional properties:
+ - qcom,msm-bus,name
+ - qcom,msm-bus,num-cases
+ - qcom,msm-bus,active-only
+ - qcom,msm-bus,num-paths
+ - qcom,msm-bus,vectors-KBps
Example (for 8974 platform, avaialble at msm8974.dtsi):
@@ -75,6 +82,14 @@
"tsif_data",
"tsif_sync";
qcom,gpios-func = <1>;
+
+ qcom,msm-bus,name = "tsif";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,active-only = <0>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <82 512 0 0>, /* No vote */
+ <82 512 12288 24576>; /* Max. bandwidth, 2xTSIF, each max of 96Mbps */
};
diff --git a/Documentation/devicetree/bindings/crypto/msm/qcedev.txt b/Documentation/devicetree/bindings/crypto/msm/qcedev.txt
index 7eb65d2..3ca9080 100644
--- a/Documentation/devicetree/bindings/crypto/msm/qcedev.txt
+++ b/Documentation/devicetree/bindings/crypto/msm/qcedev.txt
@@ -15,8 +15,7 @@
Optional properties:
- qcom,ce-hw-shared : optional, indicates if the hardware is shared between EE.
-
-
+ - qcom,ce-hw-key : optional, indicates if the hardware supports use of HW KEY.
Example:
diff --git a/Documentation/devicetree/bindings/crypto/msm/qcrypto.txt b/Documentation/devicetree/bindings/crypto/msm/qcrypto.txt
index 79dc287..01cc798 100644
--- a/Documentation/devicetree/bindings/crypto/msm/qcrypto.txt
+++ b/Documentation/devicetree/bindings/crypto/msm/qcrypto.txt
@@ -15,7 +15,7 @@
Optional properties:
- qcom,ce-hw-shared : optional, indicates if the hardware is shared between EE.
-
+ - qcom,ce-hw-key : optional, indicates if the hardware supports use of HW KEY.
Example:
diff --git a/Documentation/devicetree/bindings/iommu/msm_iommu_v1.txt b/Documentation/devicetree/bindings/iommu/msm_iommu_v1.txt
index ed45979..b3f1aef 100644
--- a/Documentation/devicetree/bindings/iommu/msm_iommu_v1.txt
+++ b/Documentation/devicetree/bindings/iommu/msm_iommu_v1.txt
@@ -28,7 +28,10 @@
- compatible : "qcom,msm-smmu-v1-ctx"
- reg : offset and length of the register set for the context bank.
- - interrupts : should contain the context bank interrupt.
+ - interrupts : should contain the context bank interrupt. If this is
+ a secure context bank, this should be a list of 2 3-tuples where
+ the first is the non-secure interrupt, and the second is the
+ secure interrupt.
- qcom,iommu-ctx-sids : List of stream identifiers associated with this
translation context.
- label : Name of the context bank
diff --git a/Documentation/devicetree/bindings/media/video/msm-cci.txt b/Documentation/devicetree/bindings/media/video/msm-cci.txt
index 1836867..a2503cd 100644
--- a/Documentation/devicetree/bindings/media/video/msm-cci.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-cci.txt
@@ -51,9 +51,6 @@
- qcom,sensor-name : should contain unique sensor name to differentiate from
other sensor
- "s5k3l1yx"
-- qcom,vdd-cx-supply : should contain regulator from which cx voltage is
- supplied
-- qcom,vdd-cx-name : should contain names of cx regulator
- cam_vdig-supply : should contain regulator from which digital voltage is
supplied
- cam_vana-supply : should contain regulator from which analog voltage is
@@ -133,6 +130,10 @@
property should contain phandle of respective actuator node
- qcom,led-flash-src : if LED flash is supported by this sensor, this
property should contain phandle of respective LED flash node
+- qcom,vdd-cx-supply : should contain regulator from which cx voltage is
+ supplied
+- qcom,vdd-cx-name : should contain names of cx regulator
+
* Qualcomm MSM ACTUATOR
Required properties:
diff --git a/Documentation/devicetree/bindings/power/qpnp-charger.txt b/Documentation/devicetree/bindings/power/qpnp-charger.txt
index 43df9cc..6e125f2 100644
--- a/Documentation/devicetree/bindings/power/qpnp-charger.txt
+++ b/Documentation/devicetree/bindings/power/qpnp-charger.txt
@@ -63,7 +63,7 @@
"bpd_thm_id". "bpd_thm" selects the temperature
pin, "bpd_id" uses the id pin for battery presence
detection, "bpd_thm_id" selects both.
- If the property is not set the hw default will
+ If the property is not set, the temperatue pin will
be used.
- otg-parent-supply Specify a phandle to a parent supply regulator
for the OTG regulator.
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
index 74ea2cd..4c6569e 100644
--- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -467,6 +467,12 @@
- qcom,headset-jack-type-NO: Adjust GPIO level based on the headset jack type.
+
+* APQ8074 ASoC Machine driver
+
+Required properties:
+- compatible : "qcom,apq8074-audio-taiko"
+
Example:
sound {
@@ -686,6 +692,9 @@
prim-gpio-prim : Primary AUXPCM shares GPIOs with Primary MI2S
prim-gpio-tert : Primary AUXPCM shares GPIOs with Tertiary MI2S
+Optional Properties:
+- qcom,us-euro-gpios : GPIO on which gnd/mic swap signal is coming.
+
Example:
sound {
@@ -697,4 +706,5 @@
qcom,prim-auxpcm-gpio-din = <&msmgpio 65 0>;
qcom,prim-auxpcm-gpio-dout = <&msmgpio 66 0>;
qcom,prim-auxpcm-gpio-set = "prim-gpio-prim";
+ qcom,cdc-us-euro-gpios = <&msmgpio 69 0>;
};
diff --git a/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt b/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt
index 6df1efe..d0bbc47 100644
--- a/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt
+++ b/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt
@@ -18,12 +18,14 @@
- qcom,iris-vddpa-supply : regulator to supply RF PA.
- qcom,iris-vdddig-supply : regulator to supply RF digital(BT/FM).
- gpios: gpio numbers to configure 5-wire interface of WLAN connectivity
-- qcom,has_48mhz_xo: boolean flag to determine the usage of 24MHz XO from RF
-- qcom,has_pronto_hw: boolean flag to determine the revId of the WLAN subsystem
+- qcom,has-48mhz-xo: boolean flag to determine the usage of 24MHz XO from RF
+- qcom,has-pronto-hw: boolean flag to determine the revId of the WLAN subsystem
Optional properties:
-- qcom,has_autodetect_xo: boolean flag to determine whether Iris XO auto detect
+- qcom,has-autodetect-xo: boolean flag to determine whether Iris XO auto detect
should be performed during boot up.
+- qcom,wlan-rx-buff-count: WLAN RX buffer count is a configurable value,
+using a smaller count for this buffer will reduce the memory usage.
Example:
@@ -45,6 +47,6 @@
gpios = <&msmgpio 36 0>, <&msmgpio 37 0>, <&msmgpio 38 0>,
<&msmgpio 39 0>, <&msmgpio 40 0>;
- qcom,has_48mhz_xo;
- qcom,has_pronto_hw;
+ qcom,has-48mhz-xo;
+ qcom,has-pronto-hw;
};
diff --git a/arch/arm/boot/dts/apq8074-dragonboard.dtsi b/arch/arm/boot/dts/apq8074-dragonboard.dtsi
index 5700b8d..8e4f368 100644
--- a/arch/arm/boot/dts/apq8074-dragonboard.dtsi
+++ b/arch/arm/boot/dts/apq8074-dragonboard.dtsi
@@ -11,9 +11,10 @@
*/
/include/ "dsi-panel-sharp-qhd-video.dtsi"
+/include/ "msm8974-camera-sensor-dragonboard.dtsi"
/include/ "msm8974-leds.dtsi"
-/ {
+&soc {
serial@f991e000 {
status = "ok";
};
@@ -539,12 +540,12 @@
qcom,cs-out-en;
qcom,op-fdbck = <1>;
qcom,default-state = "on";
- qcom,max-current = <25>;
+ qcom,max-current = <20>;
qcom,ctrl-delay-us = <0>;
qcom,boost-curr-lim = <3>;
qcom,cp-sel = <0>;
qcom,switch-freq = <2>;
- qcom,ovp-val = <2>;
+ qcom,ovp-val = <1>;
qcom,num-strings = <1>;
qcom,id = <0>;
};
@@ -555,25 +556,25 @@
&pm8941_chg {
status = "ok";
- qcom,chg-charging-disabled;
+ qcom,charging-disabled;
- qcom,chg-chgr@1000 {
+ qcom,chgr@1000 {
status = "ok";
};
- qcom,chg-buck@1100 {
+ qcom,buck@1100 {
status = "ok";
};
- qcom,chg-usb-chgpth@1300 {
+ qcom,usb-chgpth@1300 {
status = "ok";
};
- qcom,chg-dc-chgpth@1400 {
+ qcom,dc-chgpth@1400 {
status = "ok";
};
- qcom,chg-boost@1500 {
+ qcom,boost@1500 {
status = "ok";
};
diff --git a/arch/arm/boot/dts/apq8074-v2.dtsi b/arch/arm/boot/dts/apq8074-v2.dtsi
index 9c93ed4..76eb14b 100644
--- a/arch/arm/boot/dts/apq8074-v2.dtsi
+++ b/arch/arm/boot/dts/apq8074-v2.dtsi
@@ -36,6 +36,10 @@
<55 512 3936000 393600>,
<55 512 3936000 393600>;
};
+
+ sound {
+ compatible = "qcom,apq8074-audio-taiko";
+ };
};
&memory_hole {
diff --git a/arch/arm/boot/dts/mpq8092.dtsi b/arch/arm/boot/dts/mpq8092.dtsi
index 4dea9e0..946b54d 100644
--- a/arch/arm/boot/dts/mpq8092.dtsi
+++ b/arch/arm/boot/dts/mpq8092.dtsi
@@ -130,6 +130,15 @@
reg = <0xfc580000 0x17c>;
interrupts = <0 243 0>;
};
+
+ qcom,wdt@f9017000 {
+ compatible = "qcom,msm-watchdog";
+ reg = <0xf9017000 0x1000>;
+ interrupts = <0 3 0>, <0 4 0>;
+ qcom,bark-time = <11000>;
+ qcom,pet-time = <10000>;
+ qcom,ipi-ping;
+ };
};
&gdsc_venus {
@@ -144,10 +153,6 @@
status = "ok";
};
-&gdsc_vfe {
- status = "ok";
-};
-
&gdsc_oxili_gx {
status = "ok";
};
diff --git a/arch/arm/boot/dts/msm-iommu-v1.dtsi b/arch/arm/boot/dts/msm-iommu-v1.dtsi
index ab46861..d497259 100644
--- a/arch/arm/boot/dts/msm-iommu-v1.dtsi
+++ b/arch/arm/boot/dts/msm-iommu-v1.dtsi
@@ -183,7 +183,7 @@
qcom,iommu-ctx@fd931000 {
compatible = "qcom,msm-smmu-v1-ctx";
reg = <0xfd931000 0x1000>;
- interrupts = <0 47 0>;
+ interrupts = <0 47 0>, <0 46 0>;
qcom,iommu-ctx-sids = <1>;
label = "mdp_1";
qcom,secure-context;
@@ -192,7 +192,7 @@
qcom,iommu-ctx@fd932000 {
compatible = "qcom,msm-smmu-v1-ctx";
reg = <0xfd932000 0x1000>;
- interrupts = <0 47 0>;
+ interrupts = <0 47 0>, <0 46 0>;
qcom,iommu-ctx-sids = <>;
label = "mdp_2";
qcom,secure-context;
@@ -295,7 +295,7 @@
venus_cp: qcom,iommu-ctx@fdc8d000 {
compatible = "qcom,msm-smmu-v1-ctx";
reg = <0xfdc8d000 0x1000>;
- interrupts = <0 42 0>;
+ interrupts = <0 42 0>, <0 43 0>;
qcom,iommu-ctx-sids = <0x80 0x81 0x82 0x83 0x84 0x85>;
label = "venus_cp";
qcom,secure-context;
@@ -304,7 +304,7 @@
venus_fw: qcom,iommu-ctx@fdc8e000 {
compatible = "qcom,msm-smmu-v1-ctx";
reg = <0xfdc8e000 0x1000>;
- interrupts = <0 42 0>;
+ interrupts = <0 42 0>, <0 43 0>;
qcom,iommu-ctx-sids = <0xc0 0xc6>;
label = "venus_fw";
qcom,secure-context;
diff --git a/arch/arm/boot/dts/msm-pm8226.dtsi b/arch/arm/boot/dts/msm-pm8226.dtsi
index 128d90c..fe0000a 100644
--- a/arch/arm/boot/dts/msm-pm8226.dtsi
+++ b/arch/arm/boot/dts/msm-pm8226.dtsi
@@ -125,7 +125,7 @@
};
- qcom,usb-chgpth@1300 {
+ pm8226_chg_otg: qcom,usb-chgpth@1300 {
status = "disabled";
reg = <0x1300 0x100>;
interrupts = <0 0x13 0x0>,
@@ -137,7 +137,7 @@
"chg-gone";
};
- qcom,boost@1500 {
+ pm8226_chg_boost: qcom,boost@1500 {
status = "disabled";
reg = <0x1500 0x100>;
interrupts = <0x0 0x15 0x0>,
@@ -415,6 +415,15 @@
qcom,adc-vdd-reference = <1800>;
};
+ qcom,temp-alarm@2400 {
+ compatible = "qcom,qpnp-temp-alarm";
+ reg = <0x2400 0x100>;
+ interrupts = <0x0 0x24 0x0>;
+ label = "pm8226_tz";
+ qcom,channel-num = <8>;
+ qcom,threshold-set = <0>;
+ };
+
qcom,pm8226_rtc {
spmi-dev-container;
compatible = "qcom,qpnp-rtc";
diff --git a/arch/arm/boot/dts/msm8226-mtp.dtsi b/arch/arm/boot/dts/msm8226-mtp.dtsi
index af443d5..9ea9bd7 100644
--- a/arch/arm/boot/dts/msm8226-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8226-mtp.dtsi
@@ -419,6 +419,5 @@
&slim_msm {
tapan_codec {
qcom,cdc-micbias1-ext-cap;
- qcom,cdc-micbias2-ext-cap;
};
};
diff --git a/arch/arm/boot/dts/msm8226-qrd.dtsi b/arch/arm/boot/dts/msm8226-qrd.dtsi
index 3c70368..1698ac1 100644
--- a/arch/arm/boot/dts/msm8226-qrd.dtsi
+++ b/arch/arm/boot/dts/msm8226-qrd.dtsi
@@ -100,6 +100,7 @@
qcom,cdc-mclk-gpios = <&pm8226_gpios 1 0>;
qcom,cdc-vdd-spkr-gpios = <&pm8226_gpios 2 0>;
+ qcom,cdc-us-euro-gpios = <&msmgpio 69 0>;
};
};
diff --git a/arch/arm/boot/dts/msm8226-regulator.dtsi b/arch/arm/boot/dts/msm8226-regulator.dtsi
index a7dc865..f3b9779 100644
--- a/arch/arm/boot/dts/msm8226-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8226-regulator.dtsi
@@ -421,3 +421,10 @@
};
};
};
+
+&pm8226_chg_boost {
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ regulator-name = "8226_smbbp_boost";
+};
+
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index dfb9c43..26e834f 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -26,7 +26,7 @@
memory {
secure_mem: secure_region {
linux,contiguous-region;
- reg = <0 0x3800000>;
+ reg = <0 0x6D00000>;
label = "secure_mem";
};
@@ -547,8 +547,8 @@
qcom,iris-vdddig-supply = <&pm8226_l24>;
gpios = <&msmgpio 40 0>, <&msmgpio 41 0>, <&msmgpio 42 0>, <&msmgpio 43 0>, <&msmgpio 44 0>;
- qcom,has_pronto_hw;
- qcom,has_autodetect_xo;
+ qcom,has-pronto-hw;
+ qcom,has-autodetect-xo;
};
qcom,msm-adsp-sensors {
@@ -642,6 +642,10 @@
rpm-channel-type = <15>; /* SMD_APPS_RPM */
};
+ qcom,bcl {
+ compatible = "qcom,bcl";
+ };
+
sdcc1: qcom,sdcc@f9824000 {
cell-index = <1>; /* SDC1 eMMC slot */
compatible = "qcom,msm-sdcc";
diff --git a/arch/arm/boot/dts/msm8610-cdp.dts b/arch/arm/boot/dts/msm8610-cdp.dts
index 257a41c..cdad6a7 100644
--- a/arch/arm/boot/dts/msm8610-cdp.dts
+++ b/arch/arm/boot/dts/msm8610-cdp.dts
@@ -192,6 +192,7 @@
qcom,id = <6>;
qcom,source-sel = <1>;
qcom,mode-ctrl = <0x60>;
+ qcom,mode = "manual";
};
};
@@ -206,6 +207,7 @@
qcom,id = <6>;
qcom,source-sel = <1>;
qcom,mode-ctrl = <0x10>;
+ qcom,mode = "manual";
};
};
};
diff --git a/arch/arm/boot/dts/msm8610-mtp.dts b/arch/arm/boot/dts/msm8610-mtp.dts
index abd4228..222c4cb 100644
--- a/arch/arm/boot/dts/msm8610-mtp.dts
+++ b/arch/arm/boot/dts/msm8610-mtp.dts
@@ -192,6 +192,7 @@
qcom,id = <6>;
qcom,source-sel = <1>;
qcom,mode-ctrl = <0x60>;
+ qcom,mode = "manual";
};
};
@@ -206,6 +207,7 @@
qcom,id = <6>;
qcom,source-sel = <1>;
qcom,mode-ctrl = <0x10>;
+ qcom,mode = "manual";
};
};
};
diff --git a/arch/arm/boot/dts/msm8610.dtsi b/arch/arm/boot/dts/msm8610.dtsi
index cb98b9e..6c3985f 100644
--- a/arch/arm/boot/dts/msm8610.dtsi
+++ b/arch/arm/boot/dts/msm8610.dtsi
@@ -668,7 +668,8 @@
qcom,iris-vdddig-supply = <&pm8110_l5>;
gpios = <&msmgpio 23 0>, <&msmgpio 24 0>, <&msmgpio 25 0>, <&msmgpio 26 0>, <&msmgpio 27 0>;
- qcom,has_pronto_hw;
+ qcom,has-pronto-hw;
+ qcom,wlan-rx-buff-count = <256>;
};
qcom,mss@fc880000 {
diff --git a/arch/arm/mach-msm/clock-mdss-8226.h b/arch/arm/boot/dts/msm8926-cdp.dts
similarity index 62%
copy from arch/arm/mach-msm/clock-mdss-8226.h
copy to arch/arm/boot/dts/msm8926-cdp.dts
index dcf4f92..7a91d40 100644
--- a/arch/arm/mach-msm/clock-mdss-8226.h
+++ b/arch/arm/boot/dts/msm8926-cdp.dts
@@ -10,13 +10,13 @@
* GNU General Public License for more details.
*/
-#ifndef __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226
-#define __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226
-extern struct clk_ops clk_ops_dsi_byte_pll;
-extern struct clk_ops clk_ops_dsi_pixel_pll;
+/dts-v1/;
+/include/ "msm8926.dtsi"
+/include/ "msm8226-cdp.dtsi"
-void mdss_clk_ctrl_pre_init(struct clk *ahb_clk);
-void mdss_clk_ctrl_post_init(void);
-
-#endif /* __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226 */
+/ {
+ model = "Qualcomm MSM 8926 CDP";
+ compatible = "qcom,msm8926-cdp", "qcom,msm8926", "qcom,cdp";
+ qcom,msm-id = <200 1 0>;
+};
diff --git a/arch/arm/mach-msm/clock-mdss-8226.h b/arch/arm/boot/dts/msm8926-mtp.dts
similarity index 62%
copy from arch/arm/mach-msm/clock-mdss-8226.h
copy to arch/arm/boot/dts/msm8926-mtp.dts
index dcf4f92..fea925d 100644
--- a/arch/arm/mach-msm/clock-mdss-8226.h
+++ b/arch/arm/boot/dts/msm8926-mtp.dts
@@ -10,13 +10,13 @@
* GNU General Public License for more details.
*/
-#ifndef __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226
-#define __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226
-extern struct clk_ops clk_ops_dsi_byte_pll;
-extern struct clk_ops clk_ops_dsi_pixel_pll;
+/dts-v1/;
+/include/ "msm8926.dtsi"
+/include/ "msm8226-mtp.dtsi"
-void mdss_clk_ctrl_pre_init(struct clk *ahb_clk);
-void mdss_clk_ctrl_post_init(void);
-
-#endif /* __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226 */
+/ {
+ model = "Qualcomm MSM 8926 MTP";
+ compatible = "qcom,msm8926-mtp", "qcom,msm8926", "qcom,mtp";
+ qcom,msm-id = <200 8 0>;
+};
diff --git a/arch/arm/mach-msm/clock-mdss-8226.h b/arch/arm/boot/dts/msm8926-qrd.dts
similarity index 62%
copy from arch/arm/mach-msm/clock-mdss-8226.h
copy to arch/arm/boot/dts/msm8926-qrd.dts
index dcf4f92..e056b7e 100644
--- a/arch/arm/mach-msm/clock-mdss-8226.h
+++ b/arch/arm/boot/dts/msm8926-qrd.dts
@@ -10,13 +10,12 @@
* GNU General Public License for more details.
*/
-#ifndef __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226
-#define __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226
+/dts-v1/;
+/include/ "msm8926.dtsi"
+/include/ "msm8226-qrd.dtsi"
-extern struct clk_ops clk_ops_dsi_byte_pll;
-extern struct clk_ops clk_ops_dsi_pixel_pll;
-
-void mdss_clk_ctrl_pre_init(struct clk *ahb_clk);
-void mdss_clk_ctrl_post_init(void);
-
-#endif /* __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226 */
+/ {
+ model = "Qualcomm MSM 8926 QRD";
+ compatible = "qcom,msm8926-qrd", "qcom,msm8926", "qcom,qrd";
+ qcom,msm-id = <200 11 0>;
+};
diff --git a/arch/arm/mach-msm/clock-mdss-8226.h b/arch/arm/boot/dts/msm8926.dtsi
similarity index 62%
rename from arch/arm/mach-msm/clock-mdss-8226.h
rename to arch/arm/boot/dts/msm8926.dtsi
index dcf4f92..390bcc1 100644
--- a/arch/arm/mach-msm/clock-mdss-8226.h
+++ b/arch/arm/boot/dts/msm8926.dtsi
@@ -10,13 +10,15 @@
* GNU General Public License for more details.
*/
-#ifndef __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226
-#define __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226
+/*
+ * Only 8926-specific property overrides should be placed inside this
+ * file. Device definitions should be placed inside the msm8226.dtsi
+ * file.
+ */
-extern struct clk_ops clk_ops_dsi_byte_pll;
-extern struct clk_ops clk_ops_dsi_pixel_pll;
+/include/ "msm8226.dtsi"
-void mdss_clk_ctrl_pre_init(struct clk *ahb_clk);
-void mdss_clk_ctrl_post_init(void);
-
-#endif /* __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226 */
+/ {
+ model = "Qualcomm MSM 8926";
+ compatible = "qcom,msm8926";
+};
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-dragonboard.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-dragonboard.dtsi
new file mode 100644
index 0000000..e84a47d
--- /dev/null
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-dragonboard.dtsi
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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.
+ */
+
+&cci {
+
+ actuator0: qcom,actuator@18 {
+ cell-index = <0>;
+ reg = <0x18 0x0>;
+ compatible = "qcom,actuator";
+ qcom,cci-master = <0>;
+ };
+
+ actuator1: qcom,actuator@36 {
+ cell-index = <1>;
+ reg = <0x36>;
+ compatible = "qcom,actuator";
+ qcom,cci-master = <0>;
+ };
+
+ qcom,camera@6e {
+ compatible = "qcom,s5k3l1yx";
+ reg = <0x6e 0x0>;
+ qcom,slave-id = <0x6e 0x0 0x3121>;
+ qcom,csiphy-sd-index = <0>;
+ qcom,csid-sd-index = <0>;
+ qcom,mount-angle = <0>;
+ qcom,actuator-src = <&actuator0>;
+ 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_vio", "cam_vana",
+ "cam_vaf";
+ qcom,cam-vreg-type = <0 1 0 0>;
+ qcom,cam-vreg-min-voltage = <1225000 0 2850000 3000000>;
+ qcom,cam-vreg-max-voltage = <1225000 0 2850000 3000000>;
+ qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
+ qcom,gpio-no-mux = <0>;
+ gpios = <&msmgpio 15 0>,
+ <&msmgpio 90 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-req-tbl-num = <0 1>;
+ qcom,gpio-req-tbl-flags = <1 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+ "CAM_RESET1";
+ qcom,gpio-set-tbl-num = <1 1>;
+ 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,sensor-position = <0>;
+ qcom,sensor-mode = <1>;
+ qcom,cci-master = <0>;
+ status = "ok";
+ };
+
+ qcom,camera@20 {
+ compatible = "qcom,imx135";
+ reg = <0x20>;
+ qcom,slave-id = <0x20 0x0016 0x0135>;
+ qcom,csiphy-sd-index = <0>;
+ qcom,csid-sd-index = <0>;
+ qcom,mount-angle = <0>;
+ qcom,sensor-name = "imx135";
+ qcom,actuator-src = <&actuator1>;
+ 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_vio", "cam_vana",
+ "cam_vaf";
+ qcom,cam-vreg-type = <0 1 0 0>;
+ qcom,cam-vreg-min-voltage = <1225000 0 2850000 3000000>;
+ qcom,cam-vreg-max-voltage = <1225000 0 2850000 3000000>;
+ qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
+ qcom,gpio-no-mux = <0>;
+ gpios = <&msmgpio 15 0>,
+ <&msmgpio 90 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-req-tbl-num = <0 1>;
+ qcom,gpio-req-tbl-flags = <1 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+ "CAM_RESET1";
+ qcom,gpio-set-tbl-num = <1 1>;
+ 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,sensor-position = <0>;
+ qcom,sensor-mode = <1>;
+ qcom,cci-master = <0>;
+ status = "ok";
+ };
+
+ qcom,camera@6c {
+ compatible = "qcom,ov2720";
+ reg = <0x6c 0x0>;
+ qcom,slave-id = <0x6c 0x300A 0x2720>;
+ qcom,csiphy-sd-index = <2>;
+ qcom,csid-sd-index = <0>;
+ qcom,mount-angle = <180>;
+ 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 17 0>,
+ <&msmgpio 18 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-req-tbl-num = <0 1>;
+ qcom,gpio-req-tbl-flags = <1 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+ "CAM_RESET1";
+ qcom,gpio-set-tbl-num = <1 1>;
+ 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,sensor-position = <1>;
+ qcom,sensor-mode = <1>;
+ qcom,cci-master = <0>;
+ status = "ok";
+ };
+
+ qcom,camera@90 {
+ compatible = "qcom,mt9m114";
+ reg = <0x90 0x0>;
+ qcom,slave-id = <0x90 0x0 0x2481>;
+ qcom,csiphy-sd-index = <1>;
+ qcom,csid-sd-index = <0>;
+ qcom,mount-angle = <0>;
+ qcom,sensor-name = "mt9m114";
+ 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 94 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-req-tbl-num = <0 1>;
+ qcom,gpio-req-tbl-flags = <1 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+ "CAM_RESET1";
+ qcom,gpio-set-tbl-num = <1 1>;
+ qcom,gpio-set-tbl-flags = <0 2>;
+ qcom,gpio-set-tbl-delay = <1000 4000>;
+ qcom,csi-lane-assign = <0x4320>;
+ qcom,csi-lane-mask = <0x3>;
+ qcom,sensor-position = <1>;
+ qcom,sensor-mode = <1>;
+ qcom,cci-master = <0>;
+ };
+};
diff --git a/arch/arm/boot/dts/msm8974-v2-iommu.dtsi b/arch/arm/boot/dts/msm8974-v2-iommu.dtsi
index b5652d1..64eff43 100644
--- a/arch/arm/boot/dts/msm8974-v2-iommu.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2-iommu.dtsi
@@ -78,7 +78,7 @@
venus_sec_pixel: qcom,iommu-ctx@fdc8f000 {
compatible = "qcom,msm-smmu-v1-ctx";
reg = <0xfdc8f000 0x1000>;
- interrupts = <0 42 0>;
+ interrupts = <0 42 0>, <0 43 0>;
qcom,iommu-ctx-sids = <0x85>;
label = "venus_sec_pixel";
qcom,secure-context;
@@ -87,7 +87,7 @@
venus_sec_non_pixel: qcom,iommu-ctx@fdc90000 {
compatible = "qcom,msm-smmu-v1-ctx";
reg = <0xfdc90000 0x1000>;
- interrupts = <0 42 0>;
+ interrupts = <0 42 0>, <0 43 0>;
qcom,iommu-ctx-sids = <0x87 0xA0>;
label = "venus_sec_non_pixel";
qcom,secure-context;
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 4367807..a585586 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -237,8 +237,8 @@
qcom,msm-bus,num-cases = <2>;
qcom,msm-bus,num-paths = <1>;
qcom,msm-bus,vectors-KBps =
- <84 512 0 0>,
- <84 512 500 800>;
+ <86 512 0 0>,
+ <86 512 500 800>;
};
usb_otg: usb@f9a55000 {
@@ -629,6 +629,14 @@
"tsif_data",
"tsif_sync";
qcom,gpios-func = <1>;
+
+ qcom,msm-bus,name = "tsif";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,active-only = <0>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <82 512 0 0>, /* No vote */
+ <82 512 12288 24576>; /* Max. bandwidth, 2xTSIF, each max of 96Mbps */
};
slim_msm: slim@fe12f000 {
@@ -645,7 +653,9 @@
elemental-addr = [00 01 A0 00 17 02];
interrupt-parent = <&wcd9xxx_intc>;
- interrupts = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28>;
+ interrupts = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
+ 17 18 19 20 21 22 23 24 25 26 27 28 29
+ 30>;
qcom,cdc-reset-gpio = <&msmgpio 63 0>;
@@ -1213,8 +1223,8 @@
qcom,iris-vdddig-supply = <&pm8941_l3>;
gpios = <&msmgpio 36 0>, <&msmgpio 37 0>, <&msmgpio 38 0>, <&msmgpio 39 0>, <&msmgpio 40 0>;
- qcom,has_48mhz_xo;
- qcom,has_pronto_hw;
+ qcom,has-48mhz-xo;
+ qcom,has-pronto-hw;
};
qcom,ocmem@fdd00000 {
diff --git a/arch/arm/boot/dts/msm9625-pm.dtsi b/arch/arm/boot/dts/msm9625-pm.dtsi
index 1d10f8c..673b640 100644
--- a/arch/arm/boot/dts/msm9625-pm.dtsi
+++ b/arch/arm/boot/dts/msm9625-pm.dtsi
@@ -237,40 +237,40 @@
<0xff 240>; /* summary_irq_kpss */
qcom,gpio-parent = <&msmgpio>;
- qcom,gpio-map = <4 1>,
- <5 5>,
- <6 9>,
- <7 18>,
- <8 20>,
- <9 24>,
- <10 27>,
- <11 28>,
- <12 34>,
- <13 35>,
- <14 37>,
- <15 42>,
- <16 44>,
- <17 46>,
- <18 50>,
- <19 54>,
- <20 59>,
- <21 61>,
- <22 62>,
- <23 64>,
- <24 65>,
- <25 66>,
- <26 67>,
- <27 68>,
- <28 71>,
- <29 72>,
- <30 73>,
- <31 74>,
- <32 75>,
- <33 77>,
- <34 79>,
- <35 80>,
- <36 82>,
- <37 86>;
+ qcom,gpio-map = <4 0>,
+ <5 1>,
+ <6 2>,
+ <7 3>,
+ <8 4>,
+ <9 5>,
+ <10 6>,
+ <11 7>,
+ <12 8>,
+ <13 9>,
+ <14 10>,
+ <15 11>,
+ <16 12>,
+ <17 13>,
+ <18 14>,
+ <19 15>,
+ <20 16>,
+ <21 17>,
+ <22 18>,
+ <23 19>,
+ <24 20>,
+ <25 21>,
+ <26 24>,
+ <27 25>,
+ <28 51>,
+ <29 61>,
+ <30 62>,
+ <31 63>,
+ <32 64>,
+ <33 65>,
+ <34 66>,
+ <35 67>,
+ <36 69>,
+ <37 71>;
};
qcom,pm-8x60 {
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index c865c58..947364c 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -256,8 +256,8 @@
qcom,peer-bam = <2>;
qcom,dst-bam-physical-address = <0xf9a04000>;
qcom,dst-bam-pipe-index = <3>;
- qcom,data-fifo-size = <0xD480>;
- qcom,descriptor-fifo-size = <0x3200>;
+ qcom,data-fifo-size = <0xF800>;
+ qcom,descriptor-fifo-size = <0x3A58>;
qcom,reset-bam-on-connect;
};
qcom,pipe4 {
@@ -269,8 +269,8 @@
qcom,usb-bam-mem-type = <2>;
qcom,dst-bam-physical-address = <0xf9a04000>;
qcom,dst-bam-pipe-index = <4>;
- qcom,data-fifo-size = <0xD480>;
- qcom,descriptor-fifo-size = <0x3200>;
+ qcom,data-fifo-size = <0xF800>;
+ qcom,descriptor-fifo-size = <0x3A58>;
qcom,reset-bam-on-connect;
};
qcom,pipe5 {
@@ -282,8 +282,8 @@
qcom,peer-bam = <2>;
qcom,dst-bam-physical-address = <0xf9a04000>;
qcom,dst-bam-pipe-index = <5>;
- qcom,data-fifo-size = <0xD480>;
- qcom,descriptor-fifo-size = <0x3200>;
+ qcom,data-fifo-size = <0xF800>;
+ qcom,descriptor-fifo-size = <0x3A58>;
qcom,reset-bam-on-connect;
};
qcom,pipe6 {
@@ -295,8 +295,8 @@
qcom,peer-bam = <2>;
qcom,dst-bam-physical-address = <0xf9a04000>;
qcom,dst-bam-pipe-index = <6>;
- qcom,data-fifo-size = <0xD480>;
- qcom,descriptor-fifo-size = <0x3200>;
+ qcom,data-fifo-size = <0xF800>;
+ qcom,descriptor-fifo-size = <0x3A58>;
qcom,reset-bam-on-connect;
};
qcom,pipe7 {
diff --git a/arch/arm/configs/msm8226_defconfig b/arch/arm/configs/msm8226_defconfig
index 7bf54ce..42becba 100644
--- a/arch/arm/configs/msm8226_defconfig
+++ b/arch/arm/configs/msm8226_defconfig
@@ -205,6 +205,7 @@
CONFIG_DM_CRYPT=y
CONFIG_NETDEVICES=y
CONFIG_DUMMY=y
+CONFIG_TUN=y
# CONFIG_MSM_RMNET is not set
CONFIG_MSM_RMNET_BAM=y
CONFIG_WCNSS_CORE=y
@@ -241,6 +242,7 @@
CONFIG_GPIO_SYSFS=y
CONFIG_GPIO_QPNP_PIN=y
CONFIG_POWER_SUPPLY=y
+CONFIG_BATTERY_BCL=y
CONFIG_QPNP_CHARGER=y
CONFIG_QPNP_BMS=y
CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
@@ -248,6 +250,7 @@
CONFIG_THERMAL=y
CONFIG_THERMAL_TSENS8974=y
CONFIG_THERMAL_MONITOR=y
+CONFIG_THERMAL_QPNP=y
CONFIG_THERMAL_QPNP_ADC_TM=y
CONFIG_WCD9306_CODEC=y
CONFIG_REGULATOR_STUB=y
@@ -384,4 +387,4 @@
CONFIG_CRYPTO_HW=y
CONFIG_CRYPTO_DEV_QCRYPTO=m
CONFIG_CRYPTO_DEV_QCE=y
-CONFIG_CRYPTO_DEV_QCEDEV=m
\ No newline at end of file
+CONFIG_CRYPTO_DEV_QCEDEV=m
diff --git a/arch/arm/configs/msm8610-perf_defconfig b/arch/arm/configs/msm8610-perf_defconfig
index 73bf4f9..c0253da 100644
--- a/arch/arm/configs/msm8610-perf_defconfig
+++ b/arch/arm/configs/msm8610-perf_defconfig
@@ -208,6 +208,7 @@
CONFIG_DM_CRYPT=y
CONFIG_NETDEVICES=y
CONFIG_DUMMY=y
+CONFIG_TUN=y
# CONFIG_MSM_RMNET is not set
CONFIG_MSM_RMNET_BAM=y
CONFIG_WCNSS_CORE=y
@@ -245,6 +246,7 @@
CONFIG_GPIO_SYSFS=y
CONFIG_GPIO_QPNP_PIN=y
CONFIG_POWER_SUPPLY=y
+CONFIG_BATTERY_BCL=y
CONFIG_QPNP_CHARGER=y
CONFIG_QPNP_BMS=y
CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
@@ -281,6 +283,7 @@
CONFIG_ION=y
CONFIG_ION_MSM=y
CONFIG_MSM_KGSL=y
+CONFIG_KGSL_PER_PROCESS_PAGE_TABLE=y
CONFIG_FB=y
CONFIG_FB_VIRTUAL=y
CONFIG_FB_MSM=y
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index 7bb3629..ce5ee8d 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -206,6 +206,7 @@
CONFIG_DM_CRYPT=y
CONFIG_NETDEVICES=y
CONFIG_DUMMY=y
+CONFIG_TUN=y
# CONFIG_MSM_RMNET is not set
CONFIG_MSM_RMNET_BAM=y
CONFIG_WCNSS_CORE=y
@@ -243,6 +244,7 @@
CONFIG_GPIO_SYSFS=y
CONFIG_GPIO_QPNP_PIN=y
CONFIG_POWER_SUPPLY=y
+CONFIG_BATTERY_BCL=y
CONFIG_QPNP_CHARGER=y
CONFIG_QPNP_BMS=y
CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
@@ -280,6 +282,7 @@
CONFIG_ION=y
CONFIG_ION_MSM=y
CONFIG_MSM_KGSL=y
+CONFIG_KGSL_PER_PROCESS_PAGE_TABLE=y
CONFIG_FB=y
CONFIG_FB_MSM=y
# CONFIG_FB_MSM_BACKLIGHT is not set
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index 6c18a97..fe62c19 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -95,6 +95,8 @@
CONFIG_MSM_L2_ERP_2BIT_PANIC=y
CONFIG_MSM_DCVS=y
CONFIG_MSM_HSIC_SYSMON=y
+CONFIG_WALL_CLK=m
+CONFIG_WALL_CLK_SYSFS=m
CONFIG_STRICT_MEMORY_RWX=y
CONFIG_PCI=y
CONFIG_PCI_MSI=y
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index 72032dc..b933faa 100644
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -368,6 +368,7 @@
CONFIG_SND_USB_AUDIO=y
CONFIG_SND_SOC=y
CONFIG_SND_SOC_MSM8974=y
+CONFIG_SND_SOC_APQ8074=y
CONFIG_UHID=y
CONFIG_HID_APPLE=y
CONFIG_HID_MAGICMOUSE=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index 091cdd9..cfdbb29a 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -374,6 +374,7 @@
CONFIG_SND_USB_AUDIO=y
CONFIG_SND_SOC=y
CONFIG_SND_SOC_MSM8974=y
+CONFIG_SND_SOC_APQ8074=y
CONFIG_UHID=y
CONFIG_HID_APPLE=y
CONFIG_HID_MAGICMOUSE=y
diff --git a/arch/arm/include/asm/system_misc.h b/arch/arm/include/asm/system_misc.h
index 5a85f14..71f4827 100644
--- a/arch/arm/include/asm/system_misc.h
+++ b/arch/arm/include/asm/system_misc.h
@@ -23,6 +23,7 @@
extern void disable_hlt(void);
extern void enable_hlt(void);
+extern int get_hlt(void);
#endif /* !__ASSEMBLY__ */
diff --git a/arch/arm/kernel/devtree.c b/arch/arm/kernel/devtree.c
index bee7f9d..24bc80b 100644
--- a/arch/arm/kernel/devtree.c
+++ b/arch/arm/kernel/devtree.c
@@ -26,6 +26,18 @@
void __init early_init_dt_add_memory_arch(u64 base, u64 size)
{
+#ifndef CONFIG_ARM_LPAE
+ if (base > ((phys_addr_t)~0)) {
+ pr_crit("Ignoring memory at 0x%08llx due to lack of LPAE support\n",
+ base);
+ return;
+ }
+
+ if (size > ((phys_addr_t)~0))
+ size = ((phys_addr_t)~0);
+
+ /* arm_add_memory() already checks for the case of base + size > 4GB */
+#endif
arm_add_memory(base, size);
}
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index e7a9237..fe97ff2 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -86,6 +86,12 @@
EXPORT_SYMBOL(enable_hlt);
+int get_hlt(void)
+{
+ return hlt_counter;
+}
+EXPORT_SYMBOL(get_hlt);
+
static int __init nohlt_setup(char *__unused)
{
hlt_counter = 1;
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 6b62269..22891b8 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -3024,4 +3024,21 @@
suggestions in efuse as initial settings. It converts corner vote
to voltage value before writing to a voltage regulator API, such as
that provided by spm-regulator driver.
+
+config WALL_CLK
+ tristate "Wall Clock hardware block simulation"
+ depends on ARCH_APQ8064
+ help
+ This driver simulates the wall-clock hardware block on fsm8064_ep
+ femto emulation platform. This block will be used to provide
+ clock information to the LTE Layer 2 module running on the hexagon
+ processor.
+
+config WALL_CLK_SYSFS
+ tristate "Wall Clock SysFS Support"
+ depends on SYSFS && WALL_CLK
+ help
+ Support the wallclk directory in sysfs filesystem to enable the
+ wall clock simulation and read the current SFN.
+
endif
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index fa3344d..9a34d87 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -111,31 +111,15 @@
obj-$(CONFIG_MSM_IPC_LOGGING) += ipc_logging_debug.o
endif
obj-y += socinfo.o
-ifndef CONFIG_ARCH_MSM8960
-ifndef CONFIG_ARCH_MSM8X60
-ifndef CONFIG_ARCH_APQ8064
-ifndef CONFIG_ARCH_MSM8974
-ifndef CONFIG_ARCH_MSM8226
-ifndef CONFIG_ARCH_MSM9625
-ifndef CONFIG_ARCH_MPQ8092
-ifndef CONFIG_ARCH_MSM8610
-ifndef CONFIG_ARCH_APQ8084
-ifndef CONFIG_ARCH_MSMKRYPTON
-ifndef CONFIG_ARCH_FSM9900
-ifndef CONFIG_ARCH_MSMSAMARIUM
- obj-y += nand_partitions.o
-endif
-endif
-endif
-endif
-endif
-endif
-endif
-endif
-endif
-endif
-endif
-endif
+obj-$(CONFIG_ARCH_MSM7X01A) += nand_partitions.o
+obj-$(CONFIG_ARCH_MSM7X25) += nand_partitions.o
+obj-$(CONFIG_ARCH_MSM7X27) += nand_partitions.o
+obj-$(CONFIG_ARCH_MSM7X30) += nand_partitions.o
+obj-$(CONFIG_ARCH_QSD8X50) += nand_partitions.o
+obj-$(CONFIG_ARCH_FSM9XXX) += nand_partitions.o
+obj-$(CONFIG_ARCH_MSM9615) += nand_partitions.o
+obj-$(CONFIG_ARCH_MSM8625) += nand_partitions.o
+obj-$(CONFIG_ARCH_MSM7X27A) += nand_partitions.o
obj-$(CONFIG_MSM_SDIO_TTY) += sdio_tty.o
obj-$(CONFIG_MSM_SMD_TTY) += smd_tty.o
obj-$(CONFIG_MSM_SMD_QMI) += smd_qmi.o
@@ -310,6 +294,7 @@
obj-$(CONFIG_ARCH_MSM9625) += gdsc.o
obj-$(CONFIG_ARCH_MSM8226) += gdsc.o
obj-$(CONFIG_ARCH_MSM8610) += gdsc.o
+obj-$(CONFIG_ARCH_MPQ8092) += gdsc.o
obj-$(CONFIG_ARCH_MSM8974) += krait-regulator.o
obj-$(CONFIG_ARCH_MSMKRYPTON) += board-krypton.o board-krypton-gpiomux.o
obj-$(CONFIG_ARCH_MSMSAMARIUM) += board-samarium.o board-samarium-gpiomux.o
@@ -319,7 +304,7 @@
obj-$(CONFIG_ARCH_MPQ8092) += board-8092.o board-8092-gpiomux.o
obj-$(CONFIG_ARCH_MPQ8092) += clock-8092.o
obj-$(CONFIG_ARCH_MSM8226) += board-8226.o board-8226-gpiomux.o
-obj-$(CONFIG_ARCH_MSM8226) += clock-local2.o clock-pll.o clock-8226.o clock-rpm.o clock-voter.o clock-mdss-8226.o
+obj-$(CONFIG_ARCH_MSM8226) += clock-local2.o clock-pll.o clock-8226.o clock-rpm.o clock-voter.o clock-mdss-8974.o
obj-$(CONFIG_ARCH_MSM8226) += acpuclock-8226.o acpuclock-cortex.o
obj-$(CONFIG_ARCH_MSM8610) += board-8610.o board-8610-gpiomux.o
obj-$(CONFIG_ARCH_MSM8610) += clock-local2.o clock-pll.o clock-8610.o clock-rpm.o clock-voter.o
@@ -439,3 +424,6 @@
obj-$(CONFIG_ARCH_MSM8974) += msm_mpmctr.o
obj-$(CONFIG_MSM_CPR_REGULATOR) += cpr-regulator.o
obj-$(CONFIG_CPU_FREQ_MSM) += cpufreq.o
+
+obj-$(CONFIG_WALL_CLK) += wallclk.o
+obj-$(CONFIG_WALL_CLK_SYSFS) += wallclk_sysfs.o
diff --git a/arch/arm/mach-msm/Makefile.boot b/arch/arm/mach-msm/Makefile.boot
index b40c70a..e1fd642 100644
--- a/arch/arm/mach-msm/Makefile.boot
+++ b/arch/arm/mach-msm/Makefile.boot
@@ -87,6 +87,9 @@
dtb-$(CONFIG_ARCH_MSM8226) += msm8226-cdp.dtb
dtb-$(CONFIG_ARCH_MSM8226) += msm8226-mtp.dtb
dtb-$(CONFIG_ARCH_MSM8226) += msm8226-qrd.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += msm8926-cdp.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += msm8926-mtp.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += msm8926-qrd.dtb
# FSM9XXX
zreladdr-$(CONFIG_ARCH_FSM9XXX) := 0x10008000
diff --git a/arch/arm/mach-msm/acpuclock-8226.c b/arch/arm/mach-msm/acpuclock-8226.c
index 5793326..733c7a8 100644
--- a/arch/arm/mach-msm/acpuclock-8226.c
+++ b/arch/arm/mach-msm/acpuclock-8226.c
@@ -66,7 +66,7 @@
*/
static struct clkctl_acpu_speed acpu_freq_tbl_8226[] = {
{ 1, 300000, PLL0, 4, 2, CPR_CORNER_SVS, 0, 4 },
- { 1, 384000, ACPUPLL, 5, 0, CPR_CORNER_SVS, 0, 4 },
+ { 1, 384000, ACPUPLL, 5, 2, CPR_CORNER_SVS, 0, 4 },
{ 1, 600000, PLL0, 4, 0, CPR_CORNER_NORMAL, 0, 6 },
{ 1, 787200, ACPUPLL, 5, 0, CPR_CORNER_NORMAL, 0, 7 },
{ 1, 998400, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 0, 7 },
@@ -77,7 +77,7 @@
static struct clkctl_acpu_speed acpu_freq_tbl_8610[] = {
{ 1, 300000, PLL0, 4, 2, CPR_CORNER_SVS, 0, 3 },
- { 1, 384000, ACPUPLL, 5, 0, CPR_CORNER_SVS, 0, 3 },
+ { 1, 384000, ACPUPLL, 5, 2, CPR_CORNER_SVS, 0, 3 },
{ 1, 600000, PLL0, 4, 0, CPR_CORNER_NORMAL, 0, 4 },
{ 1, 787200, ACPUPLL, 5, 0, CPR_CORNER_NORMAL, 0, 4 },
{ 1, 998400, ACPUPLL, 5, 0, CPR_CORNER_TURBO, 0, 5 },
diff --git a/arch/arm/mach-msm/acpuclock-cortex.c b/arch/arm/mach-msm/acpuclock-cortex.c
index 0c80a56..afa6909 100644
--- a/arch/arm/mach-msm/acpuclock-cortex.c
+++ b/arch/arm/mach-msm/acpuclock-cortex.c
@@ -160,7 +160,8 @@
static int set_speed(struct clkctl_acpu_speed *tgt_s)
{
int rc = 0;
- unsigned int tgt_freq_hz = tgt_s->khz * 1000;
+ unsigned int div = tgt_s->src_div ? tgt_s->src_div : 1;
+ unsigned int tgt_freq_hz = tgt_s->khz * 1000 * div;
struct clkctl_acpu_speed *strt_s = priv->current_speed;
struct clkctl_acpu_speed *cxo_s = &priv->freq_tbl[0];
struct clk *strt = priv->src_clocks[strt_s->src].clk;
diff --git a/arch/arm/mach-msm/board-8064-pmic.c b/arch/arm/mach-msm/board-8064-pmic.c
index 5ab4a53..b2dcd7a 100644
--- a/arch/arm/mach-msm/board-8064-pmic.c
+++ b/arch/arm/mach-msm/board-8064-pmic.c
@@ -478,6 +478,10 @@
.high_ocv_correction_limit_uv = 50,
.low_ocv_correction_limit_uv = 100,
.hold_soc_est = 3,
+ .enable_fcc_learning = 1,
+ .min_fcc_learning_soc = 20,
+ .min_fcc_ocv_pc = 30,
+ .max_fcc_learning_samples = 5,
};
static struct pm8921_platform_data
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index 372f8ba..f5a9070 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -89,6 +89,7 @@
#define MHL_GPIO_INT 30
#define MHL_GPIO_RESET 35
+#include "sysmon.h"
#define MSM_PMEM_ADSP_SIZE 0x7800000
#define MSM_PMEM_AUDIO_SIZE 0x4CF000
@@ -1901,6 +1902,8 @@
.peripheral_platform_device = &apq8064_device_hsic_host,
.ramdump_timeout_ms = 120000,
.mdm2ap_status_gpio_run_cfg = &mdm2ap_status_gpio_run_cfg,
+ .sysmon_subsys_id_valid = 1,
+ .sysmon_subsys_id = SYSMON_SS_EXT_MODEM,
};
static struct tsens_platform_data apq_tsens_pdata = {
diff --git a/arch/arm/mach-msm/board-8226.c b/arch/arm/mach-msm/board-8226.c
index 521898e..0205919 100644
--- a/arch/arm/mach-msm/board-8226.c
+++ b/arch/arm/mach-msm/board-8226.c
@@ -135,6 +135,7 @@
static const char *msm8226_dt_match[] __initconst = {
"qcom,msm8226",
+ "qcom,msm8926",
NULL
};
diff --git a/arch/arm/mach-msm/board-8610-gpiomux.c b/arch/arm/mach-msm/board-8610-gpiomux.c
index 8303992..593e2b1 100644
--- a/arch/arm/mach-msm/board-8610-gpiomux.c
+++ b/arch/arm/mach-msm/board-8610-gpiomux.c
@@ -75,7 +75,7 @@
static struct gpiomux_setting lcd_en_sus_cfg = {
.func = GPIOMUX_FUNC_GPIO,
.drv = GPIOMUX_DRV_2MA,
- .pull = GPIOMUX_PULL_UP,
+ .pull = GPIOMUX_PULL_DOWN,
};
static struct gpiomux_setting gpio_keys_active = {
diff --git a/arch/arm/mach-msm/board-8930-pmic.c b/arch/arm/mach-msm/board-8930-pmic.c
index ef65613..d7e678e 100644
--- a/arch/arm/mach-msm/board-8930-pmic.c
+++ b/arch/arm/mach-msm/board-8930-pmic.c
@@ -481,6 +481,10 @@
.high_ocv_correction_limit_uv = 50,
.low_ocv_correction_limit_uv = 100,
.hold_soc_est = 3,
+ .enable_fcc_learning = 1,
+ .min_fcc_learning_soc = 20,
+ .min_fcc_ocv_pc = 30,
+ .max_fcc_learning_samples = 5,
};
static struct pm8038_platform_data pm8038_platform_data __devinitdata = {
diff --git a/arch/arm/mach-msm/board-8960-pmic.c b/arch/arm/mach-msm/board-8960-pmic.c
index c87d966..8e758bf 100644
--- a/arch/arm/mach-msm/board-8960-pmic.c
+++ b/arch/arm/mach-msm/board-8960-pmic.c
@@ -438,6 +438,10 @@
.high_ocv_correction_limit_uv = 50,
.low_ocv_correction_limit_uv = 100,
.hold_soc_est = 3,
+ .enable_fcc_learning = 1,
+ .min_fcc_learning_soc = 20,
+ .min_fcc_ocv_pc = 30,
+ .max_fcc_learning_samples = 5,
};
#define PM8921_LC_LED_MAX_CURRENT 4 /* I = 4mA */
diff --git a/arch/arm/mach-msm/board-fsm9900.c b/arch/arm/mach-msm/board-fsm9900.c
index 7177355..6e85ece 100644
--- a/arch/arm/mach-msm/board-fsm9900.c
+++ b/arch/arm/mach-msm/board-fsm9900.c
@@ -44,6 +44,22 @@
CLK_DUMMY("iface_clk", BLSP2_UART_CLK, "f9960000.serial", OFF),
CLK_DUMMY("core_clk", BLSP1_UART_CLK, "f991f000.serial", OFF),
CLK_DUMMY("iface_clk", BLSP1_UART_CLK, "f991f000.serial", OFF),
+ CLK_DUMMY("core_clk", BLSP2_I2C_CLK, "f9966000.i2c", OFF),
+ CLK_DUMMY("iface_clk", BLSP2_I2C_CLK, "f9966000.i2c", OFF),
+ CLK_DUMMY("core_clk", BLSP1_I2C_CLK, "f9924000.i2c", OFF),
+ CLK_DUMMY("iface_clk", BLSP1_I2C_CLK, "f9924000.i2c", OFF),
+ CLK_DUMMY("core_clk", NULL, "f9a55000.usb", OFF),
+ CLK_DUMMY("iface_clk", NULL, "f9a55000.usb", OFF),
+ CLK_DUMMY("phy_clk", NULL, "f9a55000.usb", OFF),
+ CLK_DUMMY("xo", NULL, "f9a55000.usb", OFF),
+ CLK_DUMMY("core_clk", NULL, "msm_ehci_host", OFF),
+ CLK_DUMMY("iface_clk", NULL, "msm_ehci_host", OFF),
+ CLK_DUMMY("sleep_clk", NULL, "msm_ehci_host", OFF),
+ CLK_DUMMY("xo", NULL, "msm_ehci_host", OFF),
+ CLK_DUMMY("core_clk", NULL, "f9824900.sdhci_msm", OFF),
+ CLK_DUMMY("iface_clk", NULL, "f9824900.sdhci_msm", OFF),
+ CLK_DUMMY("core_clk", NULL, "f98a4900.sdhci_msm", OFF),
+ CLK_DUMMY("iface_clk", NULL, "f98a4900.sdhci_msm", OFF),
};
static struct clock_init_data msm_dummy_clock_init_data __initdata = {
diff --git a/arch/arm/mach-msm/board-samarium.c b/arch/arm/mach-msm/board-samarium.c
index 00d63a3..a656cee 100644
--- a/arch/arm/mach-msm/board-samarium.c
+++ b/arch/arm/mach-msm/board-samarium.c
@@ -34,6 +34,10 @@
static struct clk_lookup msm_clocks_dummy[] = {
CLK_DUMMY("core_clk", BLSP1_UART_CLK, "f991f000.serial", OFF),
CLK_DUMMY("iface_clk", BLSP1_UART_CLK, "f991f000.serial", OFF),
+ CLK_DUMMY("core_clk", SDC1_CLK, "msm_sdcc.1", OFF),
+ CLK_DUMMY("iface_clk", SDC1_P_CLK, "msm_sdcc.1", OFF),
+ CLK_DUMMY("core_clk", SDC2_CLK, "msm_sdcc.2", OFF),
+ CLK_DUMMY("iface_clk", SDC2_P_CLK, "msm_sdcc.2", OFF),
};
static struct clock_init_data msm_dummy_clock_init_data __initdata = {
@@ -42,6 +46,10 @@
};
static struct of_dev_auxdata msmsamarium_auxdata_lookup[] __initdata = {
+ OF_DEV_AUXDATA("qcom,msm-sdcc", 0xF9824000, \
+ "msm_sdcc.1", NULL),
+ OF_DEV_AUXDATA("qcom,msm-sdcc", 0xF98A4000, \
+ "msm_sdcc.2", NULL),
{},
};
diff --git a/arch/arm/mach-msm/clock-8226.c b/arch/arm/mach-msm/clock-8226.c
index 1f0d328..1477541 100644
--- a/arch/arm/mach-msm/clock-8226.c
+++ b/arch/arm/mach-msm/clock-8226.c
@@ -24,6 +24,7 @@
#include <mach/rpm-regulator-smd.h>
#include <mach/socinfo.h>
#include <mach/rpm-smd.h>
+#include <mach/clock-generic.h>
#include "clock-local2.h"
#include "clock-pll.h"
@@ -1789,27 +1790,73 @@
},
};
-static struct branch_clk mdss_ahb_clk;
-static struct clk dsipll0_byte_clk_src = {
- .depends = &mdss_ahb_clk.c,
- .parent = &xo.c,
- .dbg_name = "dsipll0_byte_clk_src",
- .ops = &clk_ops_dsi_byte_pll,
- CLK_INIT(dsipll0_byte_clk_src),
-};
+struct clk_ops clk_ops_pixel_clock;
-static struct clk dsipll0_pixel_clk_src = {
- .depends = &mdss_ahb_clk.c,
- .parent = &xo.c,
- .dbg_name = "dsipll0_pixel_clk_src",
- .ops = &clk_ops_dsi_pixel_pll,
- CLK_INIT(dsipll0_pixel_clk_src),
-};
+static long round_rate_pixel(struct clk *clk, unsigned long rate)
+{
+ int frac_num[] = {3, 2, 4, 1};
+ int frac_den[] = {8, 9, 9, 1};
+ int delta = 100000;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(frac_num); i++) {
+ unsigned long request = (rate * frac_den[i]) / frac_num[i];
+ unsigned long src_rate;
+
+ src_rate = clk_round_rate(clk->parent, request);
+ if ((src_rate < (request - delta)) ||
+ (src_rate > (request + delta)))
+ continue;
+
+ return (src_rate * frac_num[i]) / frac_den[i];
+ }
+
+ return -EINVAL;
+}
+
+
+static int set_rate_pixel(struct clk *clk, unsigned long rate)
+{
+ struct rcg_clk *rcg = to_rcg_clk(clk);
+ struct clk_freq_tbl *pixel_freq = rcg->current_freq;
+ int frac_num[] = {3, 2, 4, 1};
+ int frac_den[] = {8, 9, 9, 1};
+ int delta = 100000;
+ int i, rc;
+
+ for (i = 0; i < ARRAY_SIZE(frac_num); i++) {
+ unsigned long request = (rate * frac_den[i]) / frac_num[i];
+ unsigned long src_rate;
+
+ src_rate = clk_round_rate(clk->parent, request);
+ if ((src_rate < (request - delta)) ||
+ (src_rate > (request + delta)))
+ continue;
+
+ rc = clk_set_rate(clk->parent, src_rate);
+ if (rc)
+ return rc;
+
+ pixel_freq->div_src_val &= ~BM(4, 0);
+ if (frac_den[i] == frac_num[i]) {
+ pixel_freq->m_val = 0;
+ pixel_freq->n_val = 0;
+ } else {
+ pixel_freq->m_val = frac_num[i];
+ pixel_freq->n_val = ~(frac_den[i] - frac_num[i]);
+ pixel_freq->d_val = ~frac_den[i];
+ }
+ set_rate_mnd(rcg, pixel_freq);
+ return 0;
+ }
+ return -EINVAL;
+}
static struct clk_freq_tbl pixel_freq_tbl[] = {
{
- .src_clk = &dsipll0_pixel_clk_src,
- .div_src_val = BVAL(10, 8, dsipll0_pixel_mm_source_val),
+ .src_clk = &pixel_clk_src_8226.c,
+ .div_src_val = BVAL(10, 8, dsipll0_pixel_mm_source_val)
+ | BVAL(4, 0, 0),
},
F_END
};
@@ -1819,7 +1866,7 @@
.current_freq = pixel_freq_tbl,
.base = &virt_bases[MMSS_BASE],
.c = {
- .parent = &dsipll0_pixel_clk_src,
+ .parent = &pixel_clk_src_8226.c,
.dbg_name = "pclk0_clk_src",
.ops = &clk_ops_pixel,
VDD_DIG_FMAX_MAP2(LOW, 83330000, NOMINAL, 166670000),
@@ -2006,7 +2053,7 @@
static struct clk_freq_tbl byte_freq_tbl[] = {
{
- .src_clk = &dsipll0_byte_clk_src,
+ .src_clk = &byte_clk_src_8226.c,
.div_src_val = BVAL(10, 8, dsipll0_byte_mm_source_val),
},
F_END
@@ -2017,7 +2064,7 @@
.current_freq = byte_freq_tbl,
.base = &virt_bases[MMSS_BASE],
.c = {
- .parent = &dsipll0_byte_clk_src,
+ .parent = &byte_clk_src_8226.c,
.dbg_name = "byte0_clk_src",
.ops = &clk_ops_byte,
VDD_DIG_FMAX_MAP2(LOW, 62500000, NOMINAL, 125000000),
@@ -2764,7 +2811,7 @@
vdd_sr2_levels, NULL);
static struct pll_freq_tbl apcs_pll_freq[] = {
- F_APCS_PLL( 384000000, 20, 0x0, 0x1, 0x0, 0x0, 0x0),
+ F_APCS_PLL( 768000000, 40, 0x0, 0x1, 0x0, 0x0, 0x0),
F_APCS_PLL( 787200000, 41, 0x0, 0x1, 0x0, 0x0, 0x0),
F_APCS_PLL( 998400000, 52, 0x0, 0x1, 0x0, 0x0, 0x0),
F_APCS_PLL(1094400000, 57, 0x0, 0x1, 0x0, 0x0, 0x0),
@@ -3465,6 +3512,13 @@
CLK_LOOKUP("bus_clk", gcc_ce1_axi_clk.c, "fd404000.qcom,qcrypto"),
CLK_LOOKUP("core_clk_src", ce1_clk_src.c, "fd404000.qcom,qcrypto"),
+ /* DSI PLL clocks */
+ CLK_LOOKUP("", dsi_vco_clk_8226.c, ""),
+ CLK_LOOKUP("", analog_postdiv_clk_8226.c, ""),
+ CLK_LOOKUP("", indirect_path_div2_clk_8226.c, ""),
+ CLK_LOOKUP("", pixel_clk_src_8226.c, ""),
+ CLK_LOOKUP("", byte_mux_8226.c, ""),
+ CLK_LOOKUP("", byte_clk_src_8226.c, ""),
};
static struct clk_lookup msm_clocks_8226_rumi[] = {
@@ -3508,6 +3562,9 @@
*/
clk_prepare_enable(&xo_a_clk.c);
+ /* Set an initial rate (fmax at nominal) on the MMSSNOC AXI clock */
+ clk_set_rate(&axi_clk_src.c, 200000000);
+
/* Set rates for single-rate clocks. */
clk_set_rate(&usb_hs_system_clk_src.c,
usb_hs_system_clk_src.freq_tbl[0].freq_hz);
@@ -3587,9 +3644,6 @@
*/
clk_set_rate(&mmssnoc_ahb_a_clk.c, 40000000);
- /* Set an initial rate (fmax at nominal) on the MMSSNOC AXI clock */
- clk_set_rate(&axi_clk_src.c, 200000000);
-
enable_rpm_scaling();
reg_init();
@@ -3600,6 +3654,10 @@
vfe0_clk_src.c.fmax = camss_vfe_vfe0_fmax_v2;
}
+ clk_ops_pixel_clock = clk_ops_pixel;
+ clk_ops_pixel_clock.set_rate = set_rate_pixel;
+ clk_ops_pixel_clock.round_rate = round_rate_pixel;
+
/*
* MDSS needs the ahb clock and needs to init before we register the
* lookup table.
diff --git a/arch/arm/mach-msm/clock-8610.c b/arch/arm/mach-msm/clock-8610.c
index 5df3f3e..7c7d629 100644
--- a/arch/arm/mach-msm/clock-8610.c
+++ b/arch/arm/mach-msm/clock-8610.c
@@ -543,7 +543,7 @@
vdd_sr2_levels, NULL);
static struct pll_freq_tbl apcs_pll_freq[] = {
- F_APCS_PLL( 384000000, 20, 0x0, 0x1, 0x0, 0x0, 0x0),
+ F_APCS_PLL( 768000000, 40, 0x0, 0x1, 0x0, 0x0, 0x0),
F_APCS_PLL( 787200000, 41, 0x0, 0x1, 0x0, 0x0, 0x0),
F_APCS_PLL( 998400000, 52, 0x0, 0x1, 0x0, 0x0, 0x0),
F_APCS_PLL(1190400000, 62, 0x0, 0x1, 0x0, 0x0, 0x0),
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index 9ee4476..9a1611e 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -3526,6 +3526,7 @@
/*Shared by 8064, and 8930*/
static struct clk_freq_tbl clk_tbl_gfx3d[] = {
F_GFX3D( 0, gnd, 0, 0),
+ F_GFX3D( 1800000, pxo, 1, 15),
F_GFX3D( 27000000, pxo, 0, 0),
F_GFX3D( 48000000, pll8, 1, 8),
F_GFX3D( 54857000, pll8, 1, 7),
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index 53e35ef..3aef106 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -24,6 +24,7 @@
#include <mach/rpm-regulator-smd.h>
#include <mach/socinfo.h>
#include <mach/rpm-smd.h>
+#include <mach/clock-generic.h>
#include "clock-local2.h"
#include "clock-pll.h"
@@ -784,6 +785,7 @@
static DEFINE_CLK_VOTER(snoc_msmbus_clk, &snoc_clk.c, LONG_MAX);
static DEFINE_CLK_VOTER(cnoc_msmbus_clk, &cnoc_clk.c, LONG_MAX);
static DEFINE_CLK_VOTER(pnoc_msmbus_a_clk, &pnoc_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(pnoc_pm_clk, &pnoc_clk.c, LONG_MAX);
static DEFINE_CLK_VOTER(snoc_msmbus_a_clk, &snoc_a_clk.c, LONG_MAX);
static DEFINE_CLK_VOTER(cnoc_msmbus_a_clk, &cnoc_a_clk.c, LONG_MAX);
@@ -3011,26 +3013,9 @@
},
};
-static struct branch_clk mdss_ahb_clk;
-static struct clk dsipll0_byte_clk_src = {
- .depends = &mdss_ahb_clk.c,
- .parent = &cxo_clk_src.c,
- .dbg_name = "dsipll0_byte_clk_src",
- .ops = &clk_ops_dsi_byte_pll,
- CLK_INIT(dsipll0_byte_clk_src),
-};
-
-static struct clk dsipll0_pixel_clk_src = {
- .depends = &mdss_ahb_clk.c,
- .parent = &cxo_clk_src.c,
- .dbg_name = "dsipll0_pixel_clk_src",
- .ops = &clk_ops_dsi_pixel_pll,
- CLK_INIT(dsipll0_pixel_clk_src),
-};
-
static struct clk_freq_tbl byte_freq_tbl[] = {
{
- .src_clk = &dsipll0_byte_clk_src,
+ .src_clk = &byte_clk_src_8974.c,
.div_src_val = BVAL(10, 8, dsipll0_byte_mm_source_val),
},
F_END
@@ -3041,7 +3026,7 @@
.current_freq = byte_freq_tbl,
.base = &virt_bases[MMSS_BASE],
.c = {
- .parent = &dsipll0_byte_clk_src,
+ .parent = &byte_clk_src_8974.c,
.dbg_name = "byte0_clk_src",
.ops = &clk_ops_byte,
VDD_DIG_FMAX_MAP3(LOW, 93800000, NOMINAL, 187500000,
@@ -3055,7 +3040,7 @@
.current_freq = byte_freq_tbl,
.base = &virt_bases[MMSS_BASE],
.c = {
- .parent = &dsipll0_byte_clk_src,
+ .parent = &byte_clk_src_8974.c,
.dbg_name = "byte1_clk_src",
.ops = &clk_ops_byte,
VDD_DIG_FMAX_MAP3(LOW, 93800000, NOMINAL, 187500000,
@@ -3235,10 +3220,73 @@
},
};
+struct clk_ops clk_ops_pixel_clock;
+
+static long round_rate_pixel(struct clk *clk, unsigned long rate)
+{
+ int frac_num[] = {3, 2, 4, 1};
+ int frac_den[] = {8, 9, 9, 1};
+ int delta = 100000;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(frac_num); i++) {
+ unsigned long request = (rate * frac_den[i]) / frac_num[i];
+ unsigned long src_rate;
+
+ src_rate = clk_round_rate(clk->parent, request);
+ if ((src_rate < (request - delta)) ||
+ (src_rate > (request + delta)))
+ continue;
+
+ return (src_rate * frac_num[i]) / frac_den[i];
+ }
+
+ return -EINVAL;
+}
+
+
+static int set_rate_pixel(struct clk *clk, unsigned long rate)
+{
+ struct rcg_clk *rcg = to_rcg_clk(clk);
+ struct clk_freq_tbl *pixel_freq = rcg->current_freq;
+ int frac_num[] = {3, 2, 4, 1};
+ int frac_den[] = {8, 9, 9, 1};
+ int delta = 100000;
+ int i, rc;
+
+ for (i = 0; i < ARRAY_SIZE(frac_num); i++) {
+ unsigned long request = (rate * frac_den[i]) / frac_num[i];
+ unsigned long src_rate;
+
+ src_rate = clk_round_rate(clk->parent, request);
+ if ((src_rate < (request - delta)) ||
+ (src_rate > (request + delta)))
+ continue;
+
+ rc = clk_set_rate(clk->parent, src_rate);
+ if (rc)
+ return rc;
+
+ pixel_freq->div_src_val &= ~BM(4, 0);
+ if (frac_den[i] == frac_num[i]) {
+ pixel_freq->m_val = 0;
+ pixel_freq->n_val = 0;
+ } else {
+ pixel_freq->m_val = frac_num[i];
+ pixel_freq->n_val = ~(frac_den[i] - frac_num[i]);
+ pixel_freq->d_val = ~frac_den[i];
+ }
+ set_rate_mnd(rcg, pixel_freq);
+ return 0;
+ }
+ return -EINVAL;
+}
+
static struct clk_freq_tbl pixel_freq_tbl[] = {
{
- .src_clk = &dsipll0_pixel_clk_src,
- .div_src_val = BVAL(10, 8, dsipll0_pixel_mm_source_val),
+ .src_clk = &pixel_clk_src_8974.c,
+ .div_src_val = BVAL(10, 8, dsipll0_pixel_mm_source_val)
+ | BVAL(4, 0, 0),
},
F_END
};
@@ -3248,9 +3296,9 @@
.current_freq = pixel_freq_tbl,
.base = &virt_bases[MMSS_BASE],
.c = {
- .parent = &dsipll0_pixel_clk_src,
+ .parent = &pixel_clk_src_8974.c,
.dbg_name = "pclk0_clk_src",
- .ops = &clk_ops_pixel,
+ .ops = &clk_ops_pixel_clock,
VDD_DIG_FMAX_MAP2(LOW, 125000000, NOMINAL, 250000000),
CLK_INIT(pclk0_clk_src.c),
},
@@ -3261,9 +3309,9 @@
.current_freq = pixel_freq_tbl,
.base = &virt_bases[MMSS_BASE],
.c = {
- .parent = &dsipll0_pixel_clk_src,
+ .parent = &pixel_clk_src_8974.c,
.dbg_name = "pclk1_clk_src",
- .ops = &clk_ops_pixel,
+ .ops = &clk_ops_pixel_clock,
VDD_DIG_FMAX_MAP2(LOW, 125000000, NOMINAL, 250000000),
CLK_INIT(pclk1_clk_src.c),
},
@@ -5171,6 +5219,7 @@
CLK_LOOKUP("bus_clk", snoc_msmbus_clk.c, "msm_sys_noc"),
CLK_LOOKUP("bus_a_clk", snoc_msmbus_a_clk.c, "msm_sys_noc"),
CLK_LOOKUP("bus_clk", pnoc_msmbus_clk.c, "msm_periph_noc"),
+ CLK_LOOKUP("bus_clk", pnoc_pm_clk.c, "pm_8x60"),
CLK_LOOKUP("bus_a_clk", pnoc_msmbus_a_clk.c, "msm_periph_noc"),
CLK_LOOKUP("mem_clk", bimc_msmbus_clk.c, "msm_bimc"),
CLK_LOOKUP("mem_a_clk", bimc_msmbus_a_clk.c, "msm_bimc"),
@@ -5252,6 +5301,14 @@
CLK_LOOKUP("krait1_m_clk", krait1_m_clk, ""),
CLK_LOOKUP("krait2_m_clk", krait2_m_clk, ""),
CLK_LOOKUP("krait3_m_clk", krait3_m_clk, ""),
+
+ /* DSI PLL clocks */
+ CLK_LOOKUP("", dsi_vco_clk_8974.c, ""),
+ CLK_LOOKUP("", analog_postdiv_clk_8974.c, ""),
+ CLK_LOOKUP("", indirect_path_div2_clk_8974.c, ""),
+ CLK_LOOKUP("", pixel_clk_src_8974.c, ""),
+ CLK_LOOKUP("", byte_mux_8974.c, ""),
+ CLK_LOOKUP("", byte_clk_src_8974.c, ""),
};
static struct pll_config_regs mmpll0_regs __initdata = {
@@ -5534,6 +5591,10 @@
qup_i2c_clks[i][0]->parent = qup_i2c_clks[i][1];
}
+ clk_ops_pixel_clock = clk_ops_pixel;
+ clk_ops_pixel_clock.set_rate = set_rate_pixel;
+ clk_ops_pixel_clock.round_rate = round_rate_pixel;
+
/*
* MDSS needs the ahb clock and needs to init before we register the
* lookup table.
diff --git a/arch/arm/mach-msm/clock-local2.c b/arch/arm/mach-msm/clock-local2.c
index 24af44e..fd790e2 100644
--- a/arch/arm/mach-msm/clock-local2.c
+++ b/arch/arm/mach-msm/clock-local2.c
@@ -698,7 +698,7 @@
enum handoff pixel_rcg_handoff(struct clk *clk)
{
struct rcg_clk *rcg = to_rcg_clk(clk);
- u32 div_val, mval, nval, cfg_regval;
+ u32 div_val = 0, mval = 0, nval = 0, cfg_regval;
unsigned long pre_div_rate, parent_rate = clk_get_rate(clk->parent);
cfg_regval = readl_relaxed(CFG_RCGR_REG(rcg));
@@ -712,6 +712,15 @@
clk->rate = pre_div_rate;
+ /*
+ * Pixel clocks have one frequency entry in their frequency table.
+ * Update that entry.
+ */
+ if (rcg->current_freq) {
+ rcg->current_freq->div_src_val &= ~CFG_RCGR_DIV_MASK;
+ rcg->current_freq->div_src_val |= div_val;
+ }
+
/* If MND is used, find the rate after the MND division */
if ((cfg_regval & MND_MODE_MASK) == MND_DUAL_EDGE_MODE_BVAL) {
mval = readl_relaxed(M_REG(rcg));
@@ -719,6 +728,11 @@
if (!nval)
return HANDOFF_DISABLED_CLK;
nval = (~nval) + mval;
+ if (rcg->current_freq) {
+ rcg->current_freq->n_val = ~(nval - mval);
+ rcg->current_freq->m_val = mval;
+ rcg->current_freq->d_val = ~nval;
+ }
clk->rate = (pre_div_rate * mval) / nval;
}
diff --git a/arch/arm/mach-msm/clock-local2.h b/arch/arm/mach-msm/clock-local2.h
index f307a2f..cee5b8c 100644
--- a/arch/arm/mach-msm/clock-local2.h
+++ b/arch/arm/mach-msm/clock-local2.h
@@ -34,9 +34,9 @@
struct clk_freq_tbl {
unsigned long freq_hz;
struct clk *src_clk;
- const u32 m_val;
- const u32 n_val;
- const u32 d_val;
+ u32 m_val;
+ u32 n_val;
+ u32 d_val;
u32 div_src_val;
const unsigned sys_vdd;
};
diff --git a/arch/arm/mach-msm/clock-mdss-8226.c b/arch/arm/mach-msm/clock-mdss-8226.c
deleted file mode 100644
index edfaf90..0000000
--- a/arch/arm/mach-msm/clock-mdss-8226.c
+++ /dev/null
@@ -1,454 +0,0 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * 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/kernel.h>
-#include <linux/io.h>
-#include <linux/err.h>
-#include <linux/delay.h>
-#include <linux/string.h>
-#include <linux/iopoll.h>
-#include <linux/clk.h>
-
-#include <asm/processor.h>
-#include <mach/msm_iomap.h>
-#include <mach/clk-provider.h>
-
-#include "clock-mdss-8226.h"
-
-#define REG_R(addr) readl_relaxed(addr)
-#define REG_W(data, addr) writel_relaxed(data, addr)
-
-#define GDSC_PHYS 0xFD8C2304
-#define GDSC_SIZE 0x4
-
-#define DSI_PHY_PHYS 0xFD922800
-#define DSI_PHY_SIZE 0x00000800
-
-static unsigned char *mdss_dsi_base;
-static unsigned char *gdsc_base;
-static int pll_byte_clk_rate;
-static int pll_pclk_rate;
-static int pll_initialized;
-static struct clk *mdss_dsi_ahb_clk;
-static unsigned long dsi_pll_rate;
-
-void __init mdss_clk_ctrl_pre_init(struct clk *ahb_clk)
-{
- BUG_ON(ahb_clk == NULL);
-
- gdsc_base = ioremap(GDSC_PHYS, GDSC_SIZE);
- if (!gdsc_base)
- pr_err("%s: unable to remap gdsc base", __func__);
-
- mdss_dsi_base = ioremap(DSI_PHY_PHYS, DSI_PHY_SIZE);
- if (!mdss_dsi_base)
- pr_err("%s: unable to remap dsi base", __func__);
-
- mdss_dsi_ahb_clk = ahb_clk;
-}
-
-#define PLL_POLL_MAX_READS 10
-#define PLL_POLL_TIMEOUT_US 50
-
-static int mdss_gdsc_enabled(void)
-{
- if (!gdsc_base)
- return 0;
-
- return !!(readl_relaxed(gdsc_base) & BIT(31));
-}
-
-static int mdss_dsi_check_pll_lock(void)
-{
- u32 status;
-
- /* poll for PLL ready status */
- if (readl_poll_timeout_noirq((mdss_dsi_base + 0x02c0),
- status,
- ((status & BIT(0)) == 1),
- PLL_POLL_MAX_READS, PLL_POLL_TIMEOUT_US)) {
- pr_err("%s: DSI PLL status=%x failed to Lock\n",
- __func__, status);
- pll_initialized = 0;
- } else {
- pll_initialized = 1;
- }
-
- return pll_initialized;
-}
-
-static long mdss_dsi_pll_byte_round_rate(struct clk *c, unsigned long rate)
-{
- if (pll_initialized) {
- return pll_byte_clk_rate;
- } else {
- pr_err("%s: DSI PLL not configured\n", __func__);
- return -EINVAL;
- }
-}
-
-static long mdss_dsi_pll_pixel_round_rate(struct clk *c, unsigned long rate)
-{
- if (pll_initialized) {
- return pll_pclk_rate;
- } else {
- pr_err("%s: Configure Byte clk first\n", __func__);
- return -EINVAL;
- }
-}
-
-static int mdss_dsi_pll_pixel_set_rate(struct clk *c, unsigned long rate)
-{
- if (pll_initialized) {
- pll_pclk_rate = rate;
- pr_debug("%s: pll_pclk_rate=%d\n", __func__, pll_pclk_rate);
- return 0;
- } else {
- pr_err("%s: Configure Byte clk first\n", __func__);
- return -EINVAL;
- }
-}
-
-static int __mdss_dsi_pll_byte_set_rate(struct clk *c, unsigned long rate)
-{
- pr_debug("%s: rate=%ld\n", __func__, rate);
-
- if (pll_initialized)
- return 0;
-
- REG_W(0x70, mdss_dsi_base + 0x0230); /* LPFC1 CFG */
- REG_W(0x08, mdss_dsi_base + 0x022c); /* LPFR CFG */
- REG_W(0x02, mdss_dsi_base + 0x0210); /* VREG CFG */
- REG_W(0x00, mdss_dsi_base + 0x0204); /* postDiv1 */
- REG_W(0x01, mdss_dsi_base + 0x0200); /* REFCLK CFG */
- REG_W(0x03, mdss_dsi_base + 0x0224); /* postDiv2 */
- REG_W(0x00, mdss_dsi_base + 0x0238); /* SDM CFG0 */
- REG_W(0x0b, mdss_dsi_base + 0x023c); /* SDM CFG1 */
- REG_W(0x00, mdss_dsi_base + 0x0240); /* SDM CFG2 */
- REG_W(0x6c, mdss_dsi_base + 0x0244); /* SDM CFG3 */
- REG_W(0x02, mdss_dsi_base + 0x0208); /* ChgPump */
- REG_W(0x31, mdss_dsi_base + 0x020c); /* VCOLPF CFG */
- REG_W(0x15, mdss_dsi_base + 0x0234); /* LPFC2 CFG */
-
- REG_W(0x30, mdss_dsi_base + 0x0284); /* CAL CFG6 */
- REG_W(0x00, mdss_dsi_base + 0x0288); /* CAL CFG7 */
- REG_W(0x60, mdss_dsi_base + 0x028c); /* CAL CFG8 */
- REG_W(0x00, mdss_dsi_base + 0x0290); /* CAL CFG9 */
- REG_W(0xdd, mdss_dsi_base + 0x0294); /* CAL CFG10 */
- REG_W(0x01, mdss_dsi_base + 0x0298); /* CAL CFG11 */
-
- REG_W(0x05, mdss_dsi_base + 0x0228); /* postDiv3 */
- REG_W(0x2b, mdss_dsi_base + 0x0278); /* Cal CFG3 */
- REG_W(0x66, mdss_dsi_base + 0x027c); /* Cal CFG4 */
- REG_W(0x05, mdss_dsi_base + 0x0264); /* LKDET CFG2 */
- REG_W(0x00, mdss_dsi_base + 0x0248); /* SDM CFG4 */
- REG_W(0x00, mdss_dsi_base + 0x0214); /* PWRGEN CFG */
- REG_W(0x0a, mdss_dsi_base + 0x026c); /* CAL CFG0 */
- REG_W(0x20, mdss_dsi_base + 0x029c); /* EFUSE CFG */
-
- dsi_pll_rate = rate;
- pll_byte_clk_rate = rate;
-
- pr_debug("%s: PLL initialized. bcl=%d\n", __func__, pll_byte_clk_rate);
- pll_initialized = 1;
-
- return 0;
-}
-
-static int mdss_dsi_pll_byte_set_rate(struct clk *c, unsigned long rate)
-{
- int ret;
-
- clk_prepare_enable(mdss_dsi_ahb_clk);
- ret = __mdss_dsi_pll_byte_set_rate(c, rate);
- clk_disable_unprepare(mdss_dsi_ahb_clk);
-
- return ret;
-}
-
-static void mdss_dsi_uniphy_pll_sw_reset(void)
-{
- /*
- * Add hardware recommended delays after toggling the
- * software reset bit off and back on.
- */
- REG_W(0x01, mdss_dsi_base + 0x0268); /* PLL TEST CFG */
- udelay(300);
- REG_W(0x00, mdss_dsi_base + 0x0268); /* PLL TEST CFG */
- udelay(300);
-}
-
-static void mdss_dsi_pll_enable_casem(void)
-{
- int i;
-
- /*
- * Add hardware recommended delays between register writes for
- * the updates to take effect. These delays are necessary for the
- * PLL to successfully lock.
- */
- REG_W(0x01, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(200);
- REG_W(0x05, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(200);
- REG_W(0x0f, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(1000);
-
- for (i = 0; (i < 3) && !mdss_dsi_check_pll_lock(); i++) {
- REG_W(0x07, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(1);
-
- REG_W(0x0f, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(1000);
- }
-
- if (pll_initialized)
- pr_debug("%s: PLL Locked after %d attempts\n", __func__, i);
- else
- pr_debug("%s: PLL failed to lock\n", __func__);
-}
-
-static void mdss_dsi_pll_enable_casef1(void)
-{
- /*
- * Add hardware recommended delays between register writes for
- * the updates to take effect. These delays are necessary for the
- * PLL to successfully lock.
- */
- REG_W(0x01, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(200);
- REG_W(0x05, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(200);
- REG_W(0x0f, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(200);
- REG_W(0x0d, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(200);
- REG_W(0x0f, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(1000);
-
- if (mdss_dsi_check_pll_lock())
- pr_debug("%s: PLL Locked\n", __func__);
- else
- pr_debug("%s: PLL failed to lock\n", __func__);
-}
-
-static void mdss_dsi_pll_enable_cased(void)
-{
- /*
- * Add hardware recommended delays between register writes for
- * the updates to take effect. These delays are necessary for the
- * PLL to successfully lock.
- */
- REG_W(0x01, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(1);
- REG_W(0x05, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(1);
- REG_W(0x07, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(1);
- REG_W(0x05, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(1);
- REG_W(0x07, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(1);
- REG_W(0x0f, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(1);
-
- if (mdss_dsi_check_pll_lock())
- pr_debug("%s: PLL Locked\n", __func__);
- else
- pr_debug("%s: PLL failed to lock\n", __func__);
-}
-
-static void mdss_dsi_pll_enable_casec(void)
-{
- /*
- * Add hardware recommended delays between register writes for
- * the updates to take effect. These delays are necessary for the
- * PLL to successfully lock.
- */
- REG_W(0x01, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(200);
- REG_W(0x05, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(200);
- REG_W(0x0f, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(1000);
-
- if (mdss_dsi_check_pll_lock())
- pr_debug("%s: PLL Locked\n", __func__);
- else
- pr_debug("%s: PLL failed to lock\n", __func__);
-}
-
-static void mdss_dsi_pll_enable_casee(void)
-{
- /*
- * Add hardware recommended delays between register writes for
- * the updates to take effect. These delays are necessary for the
- * PLL to successfully lock.
- */
- REG_W(0x01, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(200);
- REG_W(0x05, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(200);
- REG_W(0x0d, mdss_dsi_base + 0x0220); /* GLB CFG */
- REG_W(0x0f, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(1000);
-
- if (mdss_dsi_check_pll_lock())
- pr_debug("%s: PLL Locked\n", __func__);
- else
- pr_debug("%s: PLL failed to lock\n", __func__);
-}
-
-static int __mdss_dsi_pll_enable(struct clk *c)
-{
- if (!pll_initialized) {
- if (dsi_pll_rate)
- __mdss_dsi_pll_byte_set_rate(c, dsi_pll_rate);
- else
- pr_err("%s: Calling clk_en before set_rate\n",
- __func__);
- }
-
- /*
- * Try all PLL power-up sequences one-by-one until
- * PLL lock is detected
- */
- mdss_dsi_uniphy_pll_sw_reset();
- mdss_dsi_pll_enable_casem();
- if (pll_initialized)
- goto pll_locked;
-
- mdss_dsi_uniphy_pll_sw_reset();
- mdss_dsi_pll_enable_cased();
- if (pll_initialized)
- goto pll_locked;
-
- mdss_dsi_uniphy_pll_sw_reset();
- mdss_dsi_pll_enable_cased();
- if (pll_initialized)
- goto pll_locked;
-
- mdss_dsi_uniphy_pll_sw_reset();
- mdss_dsi_pll_enable_casef1();
- if (pll_initialized)
- goto pll_locked;
-
- mdss_dsi_uniphy_pll_sw_reset();
- mdss_dsi_pll_enable_casec();
- if (pll_initialized)
- goto pll_locked;
-
- mdss_dsi_uniphy_pll_sw_reset();
- mdss_dsi_pll_enable_casee();
- if (pll_initialized)
- goto pll_locked;
-
- pr_err("%s: DSI PLL failed to Lock\n", __func__);
- return -EINVAL;
-
-pll_locked:
- pr_debug("%s: PLL Lock success\n", __func__);
-
- return 0;
-}
-
-static void __mdss_dsi_pll_disable(void)
-{
- writel_relaxed(0x00, mdss_dsi_base + 0x0220); /* GLB CFG */
- pr_debug("%s: PLL disabled\n", __func__);
- pll_initialized = 0;
-}
-
-static DEFINE_SPINLOCK(dsipll_lock);
-static int dsipll_refcount;
-
-static void mdss_dsi_pll_disable(struct clk *c)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&dsipll_lock, flags);
- if (WARN(dsipll_refcount == 0, "DSI PLL clock is unbalanced"))
- goto out;
- if (dsipll_refcount == 1)
- __mdss_dsi_pll_disable();
- dsipll_refcount--;
-out:
- spin_unlock_irqrestore(&dsipll_lock, flags);
-}
-
-static int mdss_dsi_pll_enable(struct clk *c)
-{
- unsigned long flags;
- int ret = 0;
-
- spin_lock_irqsave(&dsipll_lock, flags);
- if (dsipll_refcount == 0) {
- ret = __mdss_dsi_pll_enable(c);
- if (ret < 0)
- goto out;
- }
- dsipll_refcount++;
-out:
- spin_unlock_irqrestore(&dsipll_lock, flags);
- return ret;
-}
-
-/* todo: Adjust these values appropriately */
-static enum handoff mdss_dsi_pll_byte_handoff(struct clk *c)
-{
- if (mdss_gdsc_enabled()) {
- clk_prepare_enable(mdss_dsi_ahb_clk);
- if (mdss_dsi_check_pll_lock()) {
- c->rate = 59000000;
- dsi_pll_rate = 59000000;
- pll_byte_clk_rate = 59000000;
- pll_pclk_rate = 117000000;
- dsipll_refcount++;
- return HANDOFF_ENABLED_CLK;
- }
- clk_disable_unprepare(mdss_dsi_ahb_clk);
- }
-
- return HANDOFF_DISABLED_CLK;
-}
-
-/* todo: Adjust these values appropriately */
-static enum handoff mdss_dsi_pll_pixel_handoff(struct clk *c)
-{
- if (mdss_gdsc_enabled()) {
- clk_prepare_enable(mdss_dsi_ahb_clk);
- if (mdss_dsi_check_pll_lock()) {
- c->rate = 117000000;
- dsipll_refcount++;
- return HANDOFF_ENABLED_CLK;
- }
- clk_disable_unprepare(mdss_dsi_ahb_clk);
- }
-
- return HANDOFF_DISABLED_CLK;
-}
-
-struct clk_ops clk_ops_dsi_pixel_pll = {
- .enable = mdss_dsi_pll_enable,
- .disable = mdss_dsi_pll_disable,
- .set_rate = mdss_dsi_pll_pixel_set_rate,
- .round_rate = mdss_dsi_pll_pixel_round_rate,
- .handoff = mdss_dsi_pll_pixel_handoff,
-};
-
-struct clk_ops clk_ops_dsi_byte_pll = {
- .enable = mdss_dsi_pll_enable,
- .disable = mdss_dsi_pll_disable,
- .set_rate = mdss_dsi_pll_byte_set_rate,
- .round_rate = mdss_dsi_pll_byte_round_rate,
- .handoff = mdss_dsi_pll_byte_handoff,
-};
diff --git a/arch/arm/mach-msm/clock-mdss-8974.c b/arch/arm/mach-msm/clock-mdss-8974.c
index 17a6801..1245287 100644
--- a/arch/arm/mach-msm/clock-mdss-8974.c
+++ b/arch/arm/mach-msm/clock-mdss-8974.c
@@ -21,17 +21,21 @@
#include <asm/processor.h>
#include <mach/msm_iomap.h>
#include <mach/clk-provider.h>
+#include <mach/clk.h>
+#include <mach/clock-generic.h>
#include "clock-mdss-8974.h"
-#define REG_R(addr) readl_relaxed(addr)
-#define REG_W(data, addr) writel_relaxed(data, addr)
+#define REG_R(addr) readl_relaxed(addr)
+#define REG_W(data, addr) writel_relaxed(data, addr)
+#define DSS_REG_W(base, offset, data) REG_W((data), (base) + (offset))
+#define DSS_REG_R(base, offset) REG_R((base) + (offset))
#define GDSC_PHYS 0xFD8C2304
#define GDSC_SIZE 0x4
-#define DSI_PHY_PHYS 0xFD922800
-#define DSI_PHY_SIZE 0x00000800
+#define DSI_PHY_PHYS 0xFD922A00
+#define DSI_PHY_SIZE 0x000000D4
#define HDMI_PHY_PHYS 0xFD922500
#define HDMI_PHY_SIZE 0x0000007C
@@ -100,45 +104,60 @@
#define HDMI_UNI_PLL_CAL_CFG11 (0x0098)
#define HDMI_UNI_PLL_STATUS (0x00C0)
-#define VCO_CLK 424000000
+#define DSI_0_PHY_PLL_UNIPHY_PLL_REFCLK_CFG (0x00000000)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_POSTDIV1_CFG (0x00000004)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_CHGPUMP_CFG (0x00000008)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_VCOLPF_CFG (0x0000000C)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_VREG_CFG (0x00000010)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_PWRGEN_CFG (0x00000014)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_DMUX_CFG (0x00000018)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_AMUX_CFG (0x0000001C)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG (0x00000020)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_POSTDIV2_CFG (0x00000024)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_POSTDIV3_CFG (0x00000028)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_LPFR_CFG (0x0000002C)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_LPFC1_CFG (0x00000030)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_LPFC2_CFG (0x00000034)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_SDM_CFG0 (0x00000038)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_SDM_CFG1 (0x0000003C)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_SDM_CFG2 (0x00000040)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_SDM_CFG3 (0x00000044)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_SDM_CFG4 (0x00000048)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_SSC_CFG0 (0x0000004C)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_SSC_CFG1 (0x00000050)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_SSC_CFG2 (0x00000054)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_SSC_CFG3 (0x00000058)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_LKDET_CFG0 (0x0000005C)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_LKDET_CFG1 (0x00000060)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_LKDET_CFG2 (0x00000064)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_TEST_CFG (0x00000068)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG0 (0x0000006C)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG1 (0x00000070)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG2 (0x00000074)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG3 (0x00000078)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG4 (0x0000007C)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG5 (0x00000080)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG6 (0x00000084)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG7 (0x00000088)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG8 (0x0000008C)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG9 (0x00000090)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG10 (0x00000094)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG11 (0x00000098)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_EFUSE_CFG (0x0000009C)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_STATUS (0x000000C0)
+
+#define PLL_POLL_MAX_READS 10
+#define PLL_POLL_TIMEOUT_US 50
+
+static long vco_cached_rate;
static unsigned char *mdss_dsi_base;
static unsigned char *gdsc_base;
-static int pll_byte_clk_rate;
-static int pll_pclk_rate;
-static int pll_initialized;
-static struct clk *mdss_dsi_ahb_clk;
-static unsigned long dsi_pll_rate;
+static struct clk *mdss_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_pre_init(struct clk *ahb_clk)
-{
- BUG_ON(ahb_clk == NULL);
-
- gdsc_base = ioremap(GDSC_PHYS, GDSC_SIZE);
- if (!gdsc_base)
- pr_err("%s: unable to remap gdsc base", __func__);
-
- mdss_dsi_base = ioremap(DSI_PHY_PHYS, DSI_PHY_SIZE);
- if (!mdss_dsi_base)
- pr_err("%s: unable to remap dsi base", __func__);
-
- mdss_dsi_ahb_clk = ahb_clk;
-
- 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__);
-}
-
-#define PLL_POLL_MAX_READS 10
-#define PLL_POLL_TIMEOUT_US 50
-
static int mdss_gdsc_enabled(void)
{
if (!gdsc_base)
@@ -147,297 +166,13 @@
return !!(readl_relaxed(gdsc_base) & BIT(31));
}
-static int mdss_dsi_check_pll_lock(void)
-{
- u32 status;
-
- clk_prepare_enable(mdss_dsi_ahb_clk);
- /* poll for PLL ready status */
- if (readl_poll_timeout_noirq((mdss_dsi_base + 0x02c0),
- status,
- ((status & BIT(0)) == 1),
- PLL_POLL_MAX_READS, PLL_POLL_TIMEOUT_US)) {
- pr_err("%s: DSI PLL status=%x failed to Lock\n",
- __func__, status);
- pll_initialized = 0;
- } else {
- pll_initialized = 1;
- }
- clk_disable_unprepare(mdss_dsi_ahb_clk);
-
- return pll_initialized;
-}
-
-static long mdss_dsi_pll_byte_round_rate(struct clk *c, unsigned long rate)
-{
- if (pll_initialized)
- return pll_byte_clk_rate;
- else {
- pr_err("%s: DSI PLL not configured\n",
- __func__);
- return -EINVAL;
- }
-}
-
-static long mdss_dsi_pll_pixel_round_rate(struct clk *c, unsigned long rate)
-{
- if (pll_initialized)
- return pll_pclk_rate;
- else {
- pr_err("%s: Configure Byte clk first\n",
- __func__);
- return -EINVAL;
- }
-}
-
-static int mdss_dsi_pll_pixel_set_rate(struct clk *c, unsigned long rate)
-{
- if (pll_initialized) {
- pll_pclk_rate = rate;
- pr_debug("%s: pll_pclk_rate=%d\n", __func__, pll_pclk_rate);
- return 0;
- } else {
- pr_err("%s: Configure Byte clk first\n", __func__);
- return -EINVAL;
- }
-}
-
-static int __mdss_dsi_pll_byte_set_rate(struct clk *c, unsigned long rate)
-{
- int pll_divcfg1, pll_divcfg2;
- int half_bitclk_rate;
-
- pr_debug("%s:\n", __func__);
- if (pll_initialized)
- return 0;
-
- half_bitclk_rate = rate * 4;
-
- pll_divcfg1 = (VCO_CLK / half_bitclk_rate) - 2;
-
- /* Configuring the VCO to 424 Mhz */
- /* Configuring the half rate Bit clk to 212 Mhz */
-
- pll_divcfg2 = 3; /* ByteClk is 1/4 the half-bitClk rate */
-
- /* Configure the Loop filter */
- /* Loop filter resistance value */
- REG_W(0x08, mdss_dsi_base + 0x022c);
- /* Loop filter capacitance values : c1 and c2 */
- REG_W(0x70, mdss_dsi_base + 0x0230);
- REG_W(0x15, mdss_dsi_base + 0x0234);
-
- 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(0x05, mdss_dsi_base + 0x0228); /* postDiv3 */
-
- REG_W(0x2b, mdss_dsi_base + 0x0278); /* Cal CFG3 */
- REG_W(0x66, mdss_dsi_base + 0x027c); /* Cal CFG4 */
- REG_W(0x05, mdss_dsi_base + 0x0264); /* LKDET CFG2 */
-
- 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 */
-
- REG_W(0x01, mdss_dsi_base + 0x0200); /* REFCLK CFG */
- REG_W(0x00, mdss_dsi_base + 0x0214); /* PWRGEN CFG */
- REG_W(0x71, mdss_dsi_base + 0x020c); /* VCOLPF CFG */
- REG_W(0x02, mdss_dsi_base + 0x0210); /* VREG CFG */
- REG_W(0x00, mdss_dsi_base + 0x0238); /* SDM CFG0 */
-
- 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 */
-
- dsi_pll_rate = rate;
- pll_byte_clk_rate = rate;
-
- pr_debug("%s: PLL initialized. bcl=%d\n", __func__, pll_byte_clk_rate);
- pll_initialized = 1;
-
- return 0;
-}
-
-static int mdss_dsi_pll_byte_set_rate(struct clk *c, unsigned long rate)
-{
- int ret;
-
- clk_prepare_enable(mdss_dsi_ahb_clk);
- ret = __mdss_dsi_pll_byte_set_rate(c, rate);
- clk_disable_unprepare(mdss_dsi_ahb_clk);
-
- return ret;
-}
-
-static void mdss_dsi_uniphy_pll_lock_detect_setting(void)
-{
- REG_W(0x04, mdss_dsi_base + 0x0264); /* LKDetect CFG2 */
- udelay(100);
- REG_W(0x05, mdss_dsi_base + 0x0264); /* LKDetect CFG2 */
- udelay(500);
-}
-
-static void mdss_dsi_uniphy_pll_sw_reset(void)
-{
- REG_W(0x01, mdss_dsi_base + 0x0268); /* PLL TEST CFG */
- udelay(1);
- REG_W(0x00, mdss_dsi_base + 0x0268); /* PLL TEST CFG */
- udelay(1);
-}
-
-static int __mdss_dsi_pll_enable(struct clk *c)
-{
- u32 status;
- u32 max_reads, timeout_us;
- int i;
-
- if (!pll_initialized) {
- if (dsi_pll_rate)
- __mdss_dsi_pll_byte_set_rate(c, dsi_pll_rate);
- else
- pr_err("%s: Calling clk_en before set_rate\n",
- __func__);
- }
-
- mdss_dsi_uniphy_pll_sw_reset();
- /* PLL power up */
- /* Add HW recommended delay between
- register writes for the update to propagate */
- REG_W(0x01, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(1000);
- REG_W(0x05, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(1000);
- REG_W(0x07, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(1000);
- REG_W(0x0f, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(1000);
-
- for (i = 0; i < 3; i++) {
- mdss_dsi_uniphy_pll_lock_detect_setting();
- /* poll for PLL ready status */
- max_reads = 5;
- timeout_us = 100;
- if (readl_poll_timeout_noirq((mdss_dsi_base + 0x02c0),
- status,
- ((status & 0x01) == 1),
- max_reads, timeout_us)) {
- pr_debug("%s: DSI PLL status=%x failed to Lock\n",
- __func__, status);
- pr_debug("%s:Trying to power UP PLL again\n",
- __func__);
- } else
- break;
-
- mdss_dsi_uniphy_pll_sw_reset();
- udelay(1000);
- /* Add HW recommended delay between
- register writes for the update to propagate */
- REG_W(0x01, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(1000);
- REG_W(0x05, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(1000);
- REG_W(0x07, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(1000);
- REG_W(0x05, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(1000);
- REG_W(0x07, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(1000);
- REG_W(0x0f, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(2000);
-
- }
-
- if ((status & 0x01) != 1) {
- pr_err("%s: DSI PLL status=%x failed to Lock\n",
- __func__, status);
- return -EINVAL;
- }
-
- pr_debug("%s: **** PLL Lock success\n", __func__);
-
- return 0;
-}
-
-static void __mdss_dsi_pll_disable(void)
-{
- writel_relaxed(0x00, mdss_dsi_base + 0x0220); /* GLB CFG */
- pr_debug("%s: **** disable pll Initialize\n", __func__);
- pll_initialized = 0;
-}
-
-static DEFINE_SPINLOCK(dsipll_lock);
-static int dsipll_refcount;
-
-static void mdss_dsi_pll_disable(struct clk *c)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&dsipll_lock, flags);
- if (WARN(dsipll_refcount == 0, "DSI PLL clock is unbalanced"))
- goto out;
- if (dsipll_refcount == 1)
- __mdss_dsi_pll_disable();
- dsipll_refcount--;
-out:
- spin_unlock_irqrestore(&dsipll_lock, flags);
-}
-
-static int mdss_dsi_pll_enable(struct clk *c)
-{
- unsigned long flags;
- int ret = 0;
-
- spin_lock_irqsave(&dsipll_lock, flags);
- if (dsipll_refcount == 0) {
- ret = __mdss_dsi_pll_enable(c);
- if (ret < 0)
- goto out;
- }
- dsipll_refcount++;
-out:
- spin_unlock_irqrestore(&dsipll_lock, flags);
- return ret;
-}
-
-static enum handoff mdss_dsi_pll_byte_handoff(struct clk *c)
-{
- if (mdss_gdsc_enabled() && mdss_dsi_check_pll_lock()) {
- c->rate = 52954560;
- dsi_pll_rate = 52954560;
- pll_byte_clk_rate = 52954560;
- pll_pclk_rate = 105000000;
- dsipll_refcount++;
- return HANDOFF_ENABLED_CLK;
- }
-
- return HANDOFF_DISABLED_CLK;
-}
-
-static enum handoff mdss_dsi_pll_pixel_handoff(struct clk *c)
-{
- if (mdss_gdsc_enabled() && mdss_dsi_check_pll_lock()) {
- c->rate = 105000000;
- dsipll_refcount++;
- return HANDOFF_ENABLED_CLK;
- }
-
- return HANDOFF_DISABLED_CLK;
-}
-
void hdmi_pll_disable(void)
{
- clk_enable(mdss_dsi_ahb_clk);
+ clk_enable(mdss_ahb_clk);
REG_W(0x0, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
udelay(5);
REG_W(0x0, hdmi_phy_base + HDMI_PHY_GLB_CFG);
- clk_disable(mdss_dsi_ahb_clk);
+ clk_disable(mdss_ahb_clk);
hdmi_pll_on = 0;
} /* hdmi_pll_disable */
@@ -447,7 +182,7 @@
u32 status;
u32 max_reads, timeout_us;
- clk_enable(mdss_dsi_ahb_clk);
+ clk_enable(mdss_ahb_clk);
/* Global Enable */
REG_W(0x81, hdmi_phy_base + HDMI_PHY_GLB_CFG);
/* Power up power gen */
@@ -473,7 +208,7 @@
pr_err("%s: hdmi phy pll status=%x failed to Lock\n",
__func__, status);
hdmi_pll_disable();
- clk_disable(mdss_dsi_ahb_clk);
+ clk_disable(mdss_ahb_clk);
return -EINVAL;
}
pr_debug("%s: hdmi phy pll is locked\n", __func__);
@@ -487,11 +222,11 @@
pr_err("%s: hdmi phy status=%x failed to Lock\n",
__func__, status);
hdmi_pll_disable();
- clk_disable(mdss_dsi_ahb_clk);
+ clk_disable(mdss_ahb_clk);
return -EINVAL;
}
pr_debug("%s: hdmi phy is locked\n", __func__);
- clk_disable(mdss_dsi_ahb_clk);
+ clk_disable(mdss_ahb_clk);
hdmi_pll_on = 1;
@@ -507,7 +242,7 @@
set_power_dwn = 1;
}
- clk_enable(mdss_dsi_ahb_clk);
+ clk_enable(mdss_ahb_clk);
pr_debug("%s: rate=%ld\n", __func__, rate);
switch (rate) {
case 0:
@@ -922,7 +657,7 @@
/* Make sure writes complete before disabling iface clock */
mb();
- clk_disable(mdss_dsi_ahb_clk);
+ clk_disable(mdss_ahb_clk);
if (set_power_dwn)
hdmi_pll_enable();
@@ -930,18 +665,977 @@
return 0;
} /* hdmi_pll_set_rate */
-struct clk_ops clk_ops_dsi_pixel_pll = {
- .enable = mdss_dsi_pll_enable,
- .disable = mdss_dsi_pll_disable,
- .set_rate = mdss_dsi_pll_pixel_set_rate,
- .round_rate = mdss_dsi_pll_pixel_round_rate,
- .handoff = mdss_dsi_pll_pixel_handoff,
+/* Auto PLL calibaration */
+int mdss_ahb_clk_enable(int enable)
+{
+ int rc = 0;
+
+ /* todo: Ideally, we should enable/disable GDSC whenever we are
+ * attempting to enable/disable MDSS AHB clock.
+ * For now, just return error if GDSC is not enabled.
+ */
+ if (!mdss_gdsc_enabled())
+ return -EPERM;
+
+ if (enable)
+ rc = clk_prepare_enable(mdss_ahb_clk);
+ else
+ clk_disable_unprepare(mdss_ahb_clk);
+
+ return rc;
+}
+
+int set_byte_mux_sel(struct mux_clk *clk, int sel)
+{
+ pr_debug("%s: byte mux set to %s mode\n", __func__,
+ sel ? "indirect" : "direct");
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_VREG_CFG,
+ (sel << 1));
+ return 0;
+}
+
+int get_byte_mux_sel(struct mux_clk *clk)
+{
+ int mux_mode;
+
+ if (mdss_ahb_clk_enable(1)) {
+ pr_debug("%s: Failed to enable mdss ahb clock\n", __func__);
+ return 0;
+ }
+
+ mux_mode = DSS_REG_R(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_VREG_CFG)
+ & BIT(1);
+ pr_debug("%s: byte mux mode = %s", __func__,
+ mux_mode ? "indirect" : "direct");
+
+ mdss_ahb_clk_enable(0);
+ return !!mux_mode;
+}
+
+static inline struct dsi_pll_vco_clk *to_vco_clk(struct clk *clk)
+{
+ return container_of(clk, struct dsi_pll_vco_clk, c);
+}
+
+/*
+ * When the display is turned off, the display registers are wiped out.
+ * Temporarily use the prepare ops to restore the register values.
+ *
+*/
+int div_prepare(struct clk *c)
+{
+ struct div_clk *div = to_div_clk(c);
+ /* Restore the divider's value */
+ return div->ops->set_div(div, div->div);
+}
+
+int mux_prepare(struct clk *c)
+{
+ struct mux_clk *mux = to_mux_clk(c);
+ int i, rc, sel = 0;
+
+ rc = mdss_ahb_clk_enable(1);
+ if (rc) {
+ pr_err("%s: failed to enable mdss ahb clock. rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ for (i = 0; i < mux->num_parents; i++)
+ if (mux->parents[i].src == c->parent) {
+ sel = mux->parents[i].sel;
+ break;
+ }
+
+ if (i == mux->num_parents) {
+ rc = -EINVAL;
+ goto error;
+ }
+
+ /* Restore the mux source select value */
+ rc = mux->ops->set_mux_sel(mux, sel);
+
+error:
+ mdss_ahb_clk_enable(0);
+ return rc;
+}
+
+static int fixed_4div_set_div(struct div_clk *clk, int div)
+{
+ int rc = 0;
+
+ rc = mdss_ahb_clk_enable(1);
+ if (rc) {
+ pr_err("%s: failed to enable mdss ahb clock. rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_POSTDIV2_CFG,
+ (div - 1));
+
+ mdss_ahb_clk_enable(0);
+ return 0;
+}
+
+static int fixed_4div_get_div(struct div_clk *clk)
+{
+ int div = 0;
+
+ if (mdss_ahb_clk_enable(1)) {
+ pr_debug("%s: Failed to enable mdss ahb clock\n", __func__);
+ return 1;
+ }
+ div = DSS_REG_R(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_POSTDIV2_CFG);
+ mdss_ahb_clk_enable(0);
+ return div + 1;
+}
+
+static int digital_set_div(struct div_clk *clk, int div)
+{
+ int rc = 0;
+
+ rc = mdss_ahb_clk_enable(1);
+ if (rc) {
+ pr_err("%s: failed to enable mdss ahb clock. rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_POSTDIV3_CFG,
+ (div - 1));
+
+ mdss_ahb_clk_enable(0);
+ return 0;
+}
+
+static int digital_get_div(struct div_clk *clk)
+{
+ int div = 0;
+
+ if (mdss_ahb_clk_enable(1)) {
+ pr_debug("%s: Failed to enable mdss ahb clock\n", __func__);
+ return 1;
+ }
+ div = DSS_REG_R(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_POSTDIV3_CFG);
+ mdss_ahb_clk_enable(0);
+ return div + 1;
+}
+
+static int analog_set_div(struct div_clk *clk, int div)
+{
+ int rc = 0;
+
+ rc = mdss_ahb_clk_enable(1);
+ if (rc) {
+ pr_err("%s: failed to enable mdss ahb clock. rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_POSTDIV1_CFG,
+ div - 1);
+
+ mdss_ahb_clk_enable(0);
+ return 0;
+}
+
+static int analog_get_div(struct div_clk *clk)
+{
+ int div = 0;
+
+ if (mdss_ahb_clk_enable(1)) {
+ pr_debug("%s: Failed to enable mdss ahb clock\n", __func__);
+ return 1;
+ }
+ div = DSS_REG_R(mdss_dsi_base,
+ DSI_0_PHY_PLL_UNIPHY_PLL_POSTDIV1_CFG) + 1;
+ mdss_ahb_clk_enable(0);
+ return div;
+}
+
+static int dsi_pll_lock_status(void)
+{
+ u32 status;
+ int pll_locked = 0;
+
+ /* poll for PLL ready status */
+ if (readl_poll_timeout_noirq((mdss_dsi_base +
+ DSI_0_PHY_PLL_UNIPHY_PLL_STATUS),
+ status,
+ ((status & BIT(0)) == 1),
+ PLL_POLL_MAX_READS, PLL_POLL_TIMEOUT_US)) {
+ pr_debug("%s: DSI PLL status=%x failed to Lock\n",
+ __func__, status);
+ pll_locked = 0;
+ } else {
+ pll_locked = 1;
+ }
+
+ return pll_locked;
+}
+
+static void dsi_pll_software_reset(void)
+{
+ /*
+ * Add HW recommended delays after toggling the software
+ * reset bit off and back on.
+ */
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_TEST_CFG, 0x01);
+ udelay(1000);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_TEST_CFG, 0x00);
+ udelay(1000);
+}
+
+static int dsi_pll_enable_seq_m(void)
+{
+ int i = 0;
+ int pll_locked = 0;
+
+ dsi_pll_software_reset();
+
+ /*
+ * Add hardware recommended delays between register writes for
+ * the updates to take effect. These delays are necessary for the
+ * PLL to successfully lock
+ */
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x01);
+ udelay(200);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x05);
+ udelay(200);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0f);
+ udelay(1000);
+
+ do {
+ pll_locked = dsi_pll_lock_status();
+ if (!pll_locked) {
+ DSS_REG_W(mdss_dsi_base,
+ DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x07);
+ udelay(1);
+ DSS_REG_W(mdss_dsi_base,
+ DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0f);
+ udelay(1000);
+ i++;
+ }
+ } while ((i < 3) && !pll_locked);
+
+ if (pll_locked)
+ pr_debug("%s: PLL Locked at attempt #%d\n", __func__, i);
+ else
+ pr_debug("%s: PLL failed to lock after %d attempt(s)\n",
+ __func__, i);
+
+ return pll_locked ? 0 : -EINVAL;
+}
+
+static int dsi_pll_enable_seq_d(void)
+{
+ int pll_locked = 0;
+
+ dsi_pll_software_reset();
+
+ /*
+ * Add hardware recommended delays between register writes for
+ * the updates to take effect. These delays are necessary for the
+ * PLL to successfully lock
+ */
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x01);
+ udelay(1);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x05);
+ udelay(1);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x07);
+ udelay(1);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x05);
+ udelay(1);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x07);
+ udelay(1);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0f);
+ udelay(1);
+
+ pll_locked = dsi_pll_lock_status();
+ pr_debug("%s: PLL status = %s\n", __func__,
+ pll_locked ? "Locked" : "Unlocked");
+
+ return pll_locked ? 0 : -EINVAL;
+}
+
+static int dsi_pll_enable_seq_f1(void)
+{
+ int pll_locked = 0;
+
+ dsi_pll_software_reset();
+
+ /*
+ * Add hardware recommended delays between register writes for
+ * the updates to take effect. These delays are necessary for the
+ * PLL to successfully lock
+ */
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x01);
+ udelay(200);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x05);
+ udelay(200);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0f);
+ udelay(200);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0d);
+ udelay(200);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0f);
+ udelay(1000);
+
+ pll_locked = dsi_pll_lock_status();
+ pr_debug("%s: PLL status = %s\n", __func__,
+ pll_locked ? "Locked" : "Unlocked");
+
+ return pll_locked ? 0 : -EINVAL;
+}
+
+static int dsi_pll_enable_seq_c(void)
+{
+ int pll_locked = 0;
+
+ dsi_pll_software_reset();
+
+ /*
+ * Add hardware recommended delays between register writes for
+ * the updates to take effect. These delays are necessary for the
+ * PLL to successfully lock
+ */
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x01);
+ udelay(200);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x05);
+ udelay(200);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0f);
+ udelay(1000);
+
+ pll_locked = dsi_pll_lock_status();
+ pr_debug("%s: PLL status = %s\n", __func__,
+ pll_locked ? "Locked" : "Unlocked");
+
+ return pll_locked ? 0 : -EINVAL;
+}
+
+static int dsi_pll_enable_seq_e(void)
+{
+ int pll_locked = 0;
+
+ dsi_pll_software_reset();
+
+ /*
+ * Add hardware recommended delays between register writes for
+ * the updates to take effect. These delays are necessary for the
+ * PLL to successfully lock
+ */
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x01);
+ udelay(200);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x05);
+ udelay(200);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0d);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0f);
+ udelay(1000);
+
+ pll_locked = dsi_pll_lock_status();
+ pr_debug("%s: PLL status = %s\n", __func__,
+ pll_locked ? "Locked" : "Unlocked");
+
+ return pll_locked ? 0 : -EINVAL;
+}
+
+static int dsi_pll_enable_seq_8974(void)
+{
+ int i, rc = 0;
+ u32 status, max_reads, timeout_us;
+
+ dsi_pll_software_reset();
+
+ /*
+ * PLL power up sequence.
+ * Add necessary delays recommeded by hardware.
+ */
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x01);
+ udelay(1000);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x05);
+ udelay(1000);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x07);
+ udelay(1000);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0f);
+ udelay(1000);
+
+ for (i = 0; i < 3; i++) {
+ /* DSI Uniphy lock detect setting */
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_LKDET_CFG2,
+ 0x04);
+ udelay(100);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_LKDET_CFG2,
+ 0x05);
+ udelay(500);
+ /* poll for PLL ready status */
+ max_reads = 5;
+ timeout_us = 100;
+ if (readl_poll_timeout_noirq((mdss_dsi_base +
+ DSI_0_PHY_PLL_UNIPHY_PLL_STATUS),
+ status,
+ ((status & 0x01) == 1),
+ max_reads, timeout_us)) {
+ pr_debug("%s: DSI PLL status=%x failed to Lock\n",
+ __func__, status);
+ pr_debug("%s:Trying to power UP PLL again\n",
+ __func__);
+ } else {
+ break;
+ }
+
+ dsi_pll_software_reset();
+ /*
+ * PLL power up sequence.
+ * Add necessary delays recommeded by hardware.
+ */
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x1);
+ udelay(1000);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x5);
+ udelay(1000);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x7);
+ udelay(1000);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x5);
+ udelay(1000);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x7);
+ udelay(1000);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0xf);
+ udelay(2000);
+
+ }
+
+ if ((status & 0x01) != 1) {
+ pr_debug("%s: DSI PLL status=%x failed to Lock\n",
+ __func__, status);
+ rc = -EINVAL;
+ goto error;
+ }
+
+ pr_debug("%s: DSI PLL Lock success\n", __func__);
+
+error:
+ return rc;
+}
+
+static int vco_enable(struct clk *c)
+{
+ int i, rc = 0;
+ struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+
+ rc = clk_enable(mdss_ahb_clk);
+ if (rc) {
+ pr_err("%s: failed to enable mdss ahb clock. rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ /* Try all enable sequences until one succeeds */
+ for (i = 0; i < vco->pll_en_seq_cnt; i++) {
+ rc = vco->pll_enable_seqs[i]();
+ pr_debug("%s: DSI PLL %s after sequence #%d\n", __func__,
+ rc ? "unlocked" : "locked", i + 1);
+ if (!rc)
+ break;
+ }
+ clk_disable(mdss_ahb_clk);
+
+ if (rc)
+ pr_err("%s: DSI PLL failed to lock\n", __func__);
+
+ return rc;
+}
+
+static void vco_disable(struct clk *c)
+{
+ int rc = 0;
+
+ rc = clk_enable(mdss_ahb_clk);
+ if (rc) {
+ pr_err("%s: failed to enable mdss ahb clock. rc=%d\n",
+ __func__, rc);
+ return;
+ }
+
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x00);
+
+ clk_disable(mdss_ahb_clk);
+ pr_debug("%s: DSI PLL Disabled\n", __func__);
+ return;
+}
+
+static int vco_set_rate(struct clk *c, unsigned long rate)
+{
+ s64 vco_clk_rate = rate;
+ s32 rem;
+ s64 refclk_cfg, frac_n_mode, ref_doubler_en_b;
+ s64 ref_clk_to_pll, div_fbx1000, frac_n_value;
+ s64 sdm_cfg0, sdm_cfg1, sdm_cfg2, sdm_cfg3;
+ s64 gen_vco_clk, cal_cfg10, cal_cfg11;
+ u32 res;
+ int i, rc = 0;
+ struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+
+ rc = mdss_ahb_clk_enable(1);
+ if (rc) {
+ pr_err("%s: failed to enable mdss ahb clock. rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ /* Configure the Loop filter resistance */
+ for (i = 0; i < vco->lpfr_lut_size; i++)
+ if (vco_clk_rate <= vco->lpfr_lut[i].vco_rate)
+ break;
+ if (i == vco->lpfr_lut_size) {
+ pr_err("%s: unable to get loop filter resistance. vco=%ld\n",
+ __func__, rate);
+ rc = -EINVAL;
+ goto error;
+ }
+ res = vco->lpfr_lut[i].r;
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_LPFR_CFG, res);
+
+ /* Loop filter capacitance values : c1 and c2 */
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_LPFC1_CFG, 0x70);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_LPFC2_CFG, 0x15);
+
+ div_s64_rem(vco_clk_rate, vco->ref_clk_rate, &rem);
+ if (rem) {
+ refclk_cfg = 0x1;
+ frac_n_mode = 1;
+ ref_doubler_en_b = 0;
+ } else {
+ refclk_cfg = 0x0;
+ frac_n_mode = 0;
+ ref_doubler_en_b = 1;
+ }
+
+ pr_debug("%s:refclk_cfg = %lld\n", __func__, refclk_cfg);
+
+ ref_clk_to_pll = ((vco->ref_clk_rate * 2 * (refclk_cfg))
+ + (ref_doubler_en_b * vco->ref_clk_rate));
+ div_fbx1000 = div_s64((vco_clk_rate * 1000), ref_clk_to_pll);
+
+ div_s64_rem(div_fbx1000, 1000, &rem);
+ frac_n_value = div_s64((rem * (1 << 16)), 1000);
+ gen_vco_clk = div_s64(div_fbx1000 * ref_clk_to_pll, 1000);
+
+ pr_debug("%s:ref_clk_to_pll = %lld\n", __func__, ref_clk_to_pll);
+ pr_debug("%s:div_fb = %lld\n", __func__, div_fbx1000);
+ pr_debug("%s:frac_n_value = %lld\n", __func__, frac_n_value);
+
+ pr_debug("%s:Generated VCO Clock: %lld\n", __func__, gen_vco_clk);
+ rem = 0;
+ if (frac_n_mode) {
+ sdm_cfg0 = (0x0 << 5);
+ sdm_cfg0 |= (0x0 & 0x3f);
+ sdm_cfg1 = (div_s64(div_fbx1000, 1000) & 0x3f) - 1;
+ sdm_cfg3 = div_s64_rem(frac_n_value, 256, &rem);
+ sdm_cfg2 = rem;
+ } else {
+ sdm_cfg0 = (0x1 << 5);
+ sdm_cfg0 |= (div_s64(div_fbx1000, 1000) & 0x3f) - 1;
+ sdm_cfg1 = (0x0 & 0x3f);
+ sdm_cfg2 = 0;
+ sdm_cfg3 = 0;
+ }
+
+ pr_debug("%s: sdm_cfg0=%lld\n", __func__, sdm_cfg0);
+ pr_debug("%s: sdm_cfg1=%lld\n", __func__, sdm_cfg1);
+ pr_debug("%s: sdm_cfg2=%lld\n", __func__, sdm_cfg2);
+ pr_debug("%s: sdm_cfg3=%lld\n", __func__, sdm_cfg3);
+
+ cal_cfg11 = div_s64_rem(gen_vco_clk, 256 * 1000000, &rem);
+ cal_cfg10 = rem / 1000000;
+ pr_debug("%s: cal_cfg10=%lld, cal_cfg11=%lld\n", __func__,
+ cal_cfg10, cal_cfg11);
+
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_CHGPUMP_CFG, 0x02);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG3, 0x2b);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG4, 0x66);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_LKDET_CFG2, 0x05);
+
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_SDM_CFG1,
+ (u32)(sdm_cfg1 & 0xff));
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_SDM_CFG2,
+ (u32)(sdm_cfg2 & 0xff));
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_SDM_CFG3,
+ (u32)(sdm_cfg3 & 0xff));
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_SDM_CFG4, 0x00);
+
+ /* Add hardware recommended delay for correct PLL configuration */
+ udelay(1000);
+
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_REFCLK_CFG,
+ (u32)refclk_cfg);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_PWRGEN_CFG, 0x00);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_VCOLPF_CFG, 0x71);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_SDM_CFG0,
+ (u32)sdm_cfg0);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG0, 0x0a);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG6, 0x30);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG7, 0x00);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG8, 0x60);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG9, 0x00);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG10,
+ (u32)(cal_cfg10 & 0xff));
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG11,
+ (u32)(cal_cfg11 & 0xff));
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_EFUSE_CFG, 0x20);
+
+error:
+ mdss_ahb_clk_enable(0);
+ return rc;
+}
+
+/* rate is the bit clk rate */
+static long vco_round_rate(struct clk *c, unsigned long rate)
+{
+ unsigned long rrate = rate;
+ struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+
+ if (rate < vco->min_rate)
+ rrate = vco->min_rate;
+ if (rate > vco->max_rate)
+ rrate = vco->max_rate;
+
+ return rrate;
+}
+
+static unsigned long vco_get_rate(struct clk *c)
+{
+ u32 sdm0, doubler, sdm_byp_div;
+ u64 vco_rate;
+ u32 sdm_dc_off, sdm_freq_seed, sdm2, sdm3;
+ struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+ u64 ref_clk = vco->ref_clk_rate;
+
+ /* Check to see if the ref clk doubler is enabled */
+ doubler = DSS_REG_R(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_REFCLK_CFG)
+ & BIT(0);
+ ref_clk += (doubler * vco->ref_clk_rate);
+
+ /* see if it is integer mode or sdm mode */
+ sdm0 = DSS_REG_R(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_SDM_CFG0);
+ if (sdm0 & BIT(6)) {
+ /* integer mode */
+ sdm_byp_div = (DSS_REG_R(mdss_dsi_base,
+ DSI_0_PHY_PLL_UNIPHY_PLL_SDM_CFG0) & 0x3f) + 1;
+ vco_rate = ref_clk * sdm_byp_div;
+ } else {
+ /* sdm mode */
+ sdm_dc_off = DSS_REG_R(mdss_dsi_base,
+ DSI_0_PHY_PLL_UNIPHY_PLL_SDM_CFG1) & 0xFF;
+ pr_debug("%s: sdm_dc_off = %d\n", __func__, sdm_dc_off);
+ sdm2 = DSS_REG_R(mdss_dsi_base,
+ DSI_0_PHY_PLL_UNIPHY_PLL_SDM_CFG2) & 0xFF;
+ sdm3 = DSS_REG_R(mdss_dsi_base,
+ DSI_0_PHY_PLL_UNIPHY_PLL_SDM_CFG3) & 0xFF;
+ sdm_freq_seed = (sdm3 << 8) | sdm2;
+ pr_debug("%s: sdm_freq_seed = %d\n", __func__, sdm_freq_seed);
+
+ vco_rate = (ref_clk * (sdm_dc_off + 1)) +
+ mult_frac(ref_clk, sdm_freq_seed, BIT(16));
+ pr_debug("%s: vco rate = %lld", __func__, vco_rate);
+ }
+
+ pr_debug("%s: returning vco rate = %lu\n", __func__,
+ (unsigned long)vco_rate);
+ return (unsigned long)vco_rate;
+}
+
+static enum handoff vco_handoff(struct clk *c)
+{
+ int rc = 0;
+ enum handoff ret = HANDOFF_DISABLED_CLK;
+
+ rc = mdss_ahb_clk_enable(1);
+ if (rc) {
+ pr_err("%s: failed to enable mdss ahb clock. rc=%d\n",
+ __func__, rc);
+ return ret;
+ }
+ if (dsi_pll_lock_status()) {
+ c->rate = vco_get_rate(c);
+ ret = HANDOFF_ENABLED_CLK;
+ }
+
+ mdss_ahb_clk_enable(0);
+ return ret;
+}
+
+static int vco_prepare(struct clk *c)
+{
+ return vco_set_rate(c, vco_cached_rate);
+}
+
+static void vco_unprepare(struct clk *c)
+{
+ vco_cached_rate = c->rate;
+}
+
+/* Op structures */
+
+static struct clk_ops clk_ops_dsi_vco = {
+ .enable = vco_enable,
+ .disable = vco_disable,
+ .set_rate = vco_set_rate,
+ .round_rate = vco_round_rate,
+ .handoff = vco_handoff,
+ .prepare = vco_prepare,
+ .unprepare = vco_unprepare,
};
-struct clk_ops clk_ops_dsi_byte_pll = {
- .enable = mdss_dsi_pll_enable,
- .disable = mdss_dsi_pll_disable,
- .set_rate = mdss_dsi_pll_byte_set_rate,
- .round_rate = mdss_dsi_pll_byte_round_rate,
- .handoff = mdss_dsi_pll_byte_handoff,
+static struct clk_div_ops fixed_2div_ops;
+
+static struct clk_div_ops fixed_4div_ops = {
+ .set_div = fixed_4div_set_div,
+ .get_div = fixed_4div_get_div,
};
+
+static struct clk_div_ops analog_postdiv_ops = {
+ .set_div = analog_set_div,
+ .get_div = analog_get_div,
+};
+
+static struct clk_div_ops digital_postdiv_ops = {
+ .set_div = digital_set_div,
+ .get_div = digital_get_div,
+};
+
+struct clk_mux_ops byte_mux_ops = {
+ .set_mux_sel = set_byte_mux_sel,
+ .get_mux_sel = get_byte_mux_sel,
+};
+
+struct clk_ops byte_mux_clk_ops;
+
+static struct clk_ops pixel_clk_src_ops;
+static struct clk_ops byte_clk_src_ops;
+static struct clk_ops analog_potsdiv_clk_ops;
+
+/* Display clocks */
+
+struct dsi_pll_vco_clk dsi_vco_clk_8226 = {
+ .ref_clk_rate = 19200000,
+ .min_rate = 350000000,
+ .max_rate = 750000000,
+ .pll_en_seq_cnt = 6,
+ .pll_enable_seqs[0] = dsi_pll_enable_seq_m,
+ .pll_enable_seqs[1] = dsi_pll_enable_seq_d,
+ .pll_enable_seqs[2] = dsi_pll_enable_seq_d,
+ .pll_enable_seqs[3] = dsi_pll_enable_seq_f1,
+ .pll_enable_seqs[4] = dsi_pll_enable_seq_c,
+ .pll_enable_seqs[5] = dsi_pll_enable_seq_e,
+ .lpfr_lut_size = 10,
+ .lpfr_lut = (struct lpfr_cfg[]){
+ {479500000, 8},
+ {480000000, 11},
+ {575500000, 8},
+ {576000000, 12},
+ {610500000, 8},
+ {659500000, 9},
+ {671500000, 10},
+ {672000000, 14},
+ {708500000, 10},
+ {750000000, 11},
+ },
+ .c = {
+ .dbg_name = "dsi_vco_clk",
+ .ops = &clk_ops_dsi_vco,
+ CLK_INIT(dsi_vco_clk_8226.c),
+ },
+};
+
+struct div_clk analog_postdiv_clk_8226 = {
+ .max_div = 255,
+ .min_div = 1,
+ .ops = &analog_postdiv_ops,
+ .c = {
+ .parent = &dsi_vco_clk_8226.c,
+ .dbg_name = "analog_postdiv_clk",
+ .ops = &analog_potsdiv_clk_ops,
+ .flags = CLKFLAG_NO_RATE_CACHE,
+ CLK_INIT(analog_postdiv_clk_8226.c),
+ },
+};
+
+struct div_clk indirect_path_div2_clk_8226 = {
+ .ops = &fixed_2div_ops,
+ .div = 2,
+ .c = {
+ .parent = &analog_postdiv_clk_8226.c,
+ .dbg_name = "indirect_path_div2_clk",
+ .ops = &clk_ops_div,
+ .flags = CLKFLAG_NO_RATE_CACHE,
+ CLK_INIT(indirect_path_div2_clk_8226.c),
+ },
+};
+
+struct div_clk pixel_clk_src_8226 = {
+ .max_div = 255,
+ .min_div = 1,
+ .ops = &digital_postdiv_ops,
+ .c = {
+ .parent = &dsi_vco_clk_8226.c,
+ .dbg_name = "pixel_clk_src",
+ .ops = &pixel_clk_src_ops,
+ .flags = CLKFLAG_NO_RATE_CACHE,
+ CLK_INIT(pixel_clk_src_8226.c),
+ },
+};
+
+struct mux_clk byte_mux_8226 = {
+ .num_parents = 2,
+ .parents = (struct clk_src[]){
+ {&dsi_vco_clk_8226.c, 0},
+ {&indirect_path_div2_clk_8226.c, 1},
+ },
+ .ops = &byte_mux_ops,
+ .c = {
+ .parent = &dsi_vco_clk_8226.c,
+ .dbg_name = "byte_mux",
+ .ops = &byte_mux_clk_ops,
+ CLK_INIT(byte_mux_8226.c),
+ },
+};
+
+struct div_clk byte_clk_src_8226 = {
+ .ops = &fixed_4div_ops,
+ .min_div = 4,
+ .max_div = 4,
+ .c = {
+ .parent = &byte_mux_8226.c,
+ .dbg_name = "byte_clk_src",
+ .ops = &byte_clk_src_ops,
+ CLK_INIT(byte_clk_src_8226.c),
+ },
+};
+
+struct dsi_pll_vco_clk dsi_vco_clk_8974 = {
+ .ref_clk_rate = 19200000,
+ .min_rate = 350000000,
+ .max_rate = 750000000,
+ .pll_en_seq_cnt = 3,
+ .pll_enable_seqs[0] = dsi_pll_enable_seq_8974,
+ .pll_enable_seqs[1] = dsi_pll_enable_seq_8974,
+ .pll_enable_seqs[2] = dsi_pll_enable_seq_8974,
+ .lpfr_lut_size = 10,
+ .lpfr_lut = (struct lpfr_cfg[]){
+ {479500000, 8},
+ {480000000, 11},
+ {575500000, 8},
+ {576000000, 12},
+ {610500000, 8},
+ {659500000, 9},
+ {671500000, 10},
+ {672000000, 14},
+ {708500000, 10},
+ {750000000, 11},
+ },
+ .c = {
+ .dbg_name = "dsi_vco_clk",
+ .ops = &clk_ops_dsi_vco,
+ CLK_INIT(dsi_vco_clk_8974.c),
+ },
+};
+
+struct div_clk analog_postdiv_clk_8974 = {
+ .max_div = 255,
+ .min_div = 1,
+ .ops = &analog_postdiv_ops,
+ .c = {
+ .parent = &dsi_vco_clk_8974.c,
+ .dbg_name = "analog_postdiv_clk",
+ .ops = &analog_potsdiv_clk_ops,
+ .flags = CLKFLAG_NO_RATE_CACHE,
+ CLK_INIT(analog_postdiv_clk_8974.c),
+ },
+};
+
+struct div_clk indirect_path_div2_clk_8974 = {
+ .ops = &fixed_2div_ops,
+ .div = 2,
+ .c = {
+ .parent = &analog_postdiv_clk_8974.c,
+ .dbg_name = "indirect_path_div2_clk",
+ .ops = &clk_ops_div,
+ .flags = CLKFLAG_NO_RATE_CACHE,
+ CLK_INIT(indirect_path_div2_clk_8974.c),
+ },
+};
+
+struct div_clk pixel_clk_src_8974 = {
+ .max_div = 255,
+ .min_div = 1,
+ .ops = &digital_postdiv_ops,
+ .c = {
+ .parent = &dsi_vco_clk_8974.c,
+ .dbg_name = "pixel_clk_src",
+ .ops = &pixel_clk_src_ops,
+ .flags = CLKFLAG_NO_RATE_CACHE,
+ CLK_INIT(pixel_clk_src_8974.c),
+ },
+};
+
+struct mux_clk byte_mux_8974 = {
+ .num_parents = 2,
+ .parents = (struct clk_src[]){
+ {&dsi_vco_clk_8974.c, 0},
+ {&indirect_path_div2_clk_8974.c, 1},
+ },
+ .ops = &byte_mux_ops,
+ .c = {
+ .parent = &dsi_vco_clk_8974.c,
+ .dbg_name = "byte_mux",
+ .ops = &byte_mux_clk_ops,
+ CLK_INIT(byte_mux_8974.c),
+ },
+};
+
+struct div_clk byte_clk_src_8974 = {
+ .ops = &fixed_4div_ops,
+ .min_div = 4,
+ .max_div = 4,
+ .c = {
+ .parent = &byte_mux_8974.c,
+ .dbg_name = "byte_clk_src",
+ .ops = &byte_clk_src_ops,
+ CLK_INIT(byte_clk_src_8974.c),
+ },
+};
+
+void __init mdss_clk_ctrl_pre_init(struct clk *ahb_clk)
+{
+ BUG_ON(ahb_clk == NULL);
+
+ gdsc_base = ioremap(GDSC_PHYS, GDSC_SIZE);
+ if (!gdsc_base)
+ pr_err("%s: unable to remap gdsc base", __func__);
+
+ mdss_dsi_base = ioremap(DSI_PHY_PHYS, DSI_PHY_SIZE);
+ if (!mdss_dsi_base)
+ pr_err("%s: unable to remap dsi base", __func__);
+
+ mdss_ahb_clk = ahb_clk;
+
+ 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__);
+
+ pixel_clk_src_ops = clk_ops_slave_div;
+ pixel_clk_src_ops.prepare = div_prepare;
+
+ byte_clk_src_ops = clk_ops_div;
+ byte_clk_src_ops.prepare = div_prepare;
+
+ analog_potsdiv_clk_ops = clk_ops_div;
+ analog_potsdiv_clk_ops.prepare = div_prepare;
+
+ byte_mux_clk_ops = clk_ops_gen_mux;
+ byte_mux_clk_ops.prepare = mux_prepare;
+}
+
diff --git a/arch/arm/mach-msm/clock-mdss-8974.h b/arch/arm/mach-msm/clock-mdss-8974.h
index e242669..9fd3026 100644
--- a/arch/arm/mach-msm/clock-mdss-8974.h
+++ b/arch/arm/mach-msm/clock-mdss-8974.h
@@ -13,6 +13,10 @@
#ifndef __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8974
#define __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8974
+#include <linux/clk.h>
+
+#define MAX_DSI_PLL_EN_SEQS 10
+
extern struct clk_ops clk_ops_dsi_byte_pll;
extern struct clk_ops clk_ops_dsi_pixel_pll;
@@ -22,4 +26,35 @@
void hdmi_pll_disable(void);
int hdmi_pll_set_rate(unsigned long rate);
+struct lpfr_cfg {
+ unsigned long vco_rate;
+ u32 r;
+};
+
+struct dsi_pll_vco_clk {
+ unsigned long ref_clk_rate;
+ unsigned long min_rate;
+ unsigned long max_rate;
+ int (*pll_enable_seqs[MAX_DSI_PLL_EN_SEQS])(void);
+ u32 pll_en_seq_cnt;
+ struct lpfr_cfg *lpfr_lut;
+ u32 lpfr_lut_size;
+
+ struct clk c;
+};
+
+extern struct dsi_pll_vco_clk dsi_vco_clk_8974;
+extern struct div_clk analog_postdiv_clk_8974;
+extern struct div_clk indirect_path_div2_clk_8974;
+extern struct div_clk pixel_clk_src_8974;
+extern struct mux_clk byte_mux_8974;
+extern struct div_clk byte_clk_src_8974;
+
+extern struct dsi_pll_vco_clk dsi_vco_clk_8226;
+extern struct div_clk analog_postdiv_clk_8226;
+extern struct div_clk indirect_path_div2_clk_8226;
+extern struct div_clk pixel_clk_src_8226;
+extern struct mux_clk byte_mux_8226;
+extern struct div_clk byte_clk_src_8226;
+
#endif
diff --git a/arch/arm/mach-msm/clock-pll.c b/arch/arm/mach-msm/clock-pll.c
index 8d99ad1..fcdcb29 100644
--- a/arch/arm/mach-msm/clock-pll.c
+++ b/arch/arm/mach-msm/clock-pll.c
@@ -15,6 +15,7 @@
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/err.h>
+#include <linux/clk.h>
#include <linux/remote_spinlock.h>
#include <mach/scm-io.h>
@@ -262,11 +263,31 @@
struct pll_clk *pll = to_pll_clk(c);
u32 mode = readl_relaxed(PLL_MODE_REG(pll));
u32 mask = PLL_BYPASSNL | PLL_RESET_N | PLL_OUTCTRL;
+ unsigned long parent_rate;
+ u32 lval, mval, nval, userval;
- if ((mode & mask) == mask)
+ if ((mode & mask) != mask)
+ return HANDOFF_DISABLED_CLK;
+
+ /* Assume bootloaders configure PLL to c->rate */
+ if (c->rate)
return HANDOFF_ENABLED_CLK;
- return HANDOFF_DISABLED_CLK;
+ parent_rate = clk_get_rate(c->parent);
+ lval = readl_relaxed(PLL_L_REG(pll));
+ mval = readl_relaxed(PLL_M_REG(pll));
+ nval = readl_relaxed(PLL_N_REG(pll));
+ userval = readl_relaxed(PLL_CONFIG_REG(pll));
+
+ c->rate = parent_rate * lval;
+
+ if (pll->masks.mn_en_mask && userval) {
+ if (!nval)
+ nval = 1;
+ c->rate += (parent_rate * mval) / nval;
+ }
+
+ return HANDOFF_ENABLED_CLK;
}
static int local_pll_clk_set_rate(struct clk *c, unsigned long rate)
diff --git a/arch/arm/mach-msm/footswitch-8x60.c b/arch/arm/mach-msm/footswitch-8x60.c
index 76ad9b8..581c563 100644
--- a/arch/arm/mach-msm/footswitch-8x60.c
+++ b/arch/arm/mach-msm/footswitch-8x60.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -52,7 +52,7 @@
#define GFS_DELAY_CNT 31
-#define RESET_DELAY_US 1
+#define DEFAULT_RESET_DELAY_US 1
/* Clock rate to use if one has not previously been set. */
#define DEFAULT_RATE 27000000
#define MAX_CLKS 10
@@ -72,6 +72,7 @@
bool is_claimed;
struct fs_clk_data *clk_data;
struct clk *core_clk;
+ unsigned long reset_delay_us;
};
static int setup_clocks(struct footswitch *fs)
@@ -181,7 +182,7 @@
for (clock--; clock >= fs->clk_data; clock--)
clk_reset(clock->clk, CLK_RESET_ASSERT);
/* Wait for synchronous resets to propagate. */
- udelay(RESET_DELAY_US);
+ udelay(fs->reset_delay_us);
/* Enable the power rail at the footswitch. */
regval |= ENABLE_BIT;
@@ -200,9 +201,9 @@
/* Toggle core reset again after first power-on (required for GFX3D). */
if (fs->desc.id == FS_GFX3D) {
clk_reset(fs->core_clk, CLK_RESET_ASSERT);
- udelay(RESET_DELAY_US);
+ udelay(fs->reset_delay_us);
clk_reset(fs->core_clk, CLK_RESET_DEASSERT);
- udelay(RESET_DELAY_US);
+ udelay(fs->reset_delay_us);
}
/* Prevent core memory from collapsing when its clock is gated. */
@@ -265,7 +266,7 @@
for (clock--; clock >= fs->clk_data; clock--)
clk_reset(clock->clk, CLK_RESET_ASSERT);
/* Wait for synchronous resets to propagate. */
- udelay(RESET_DELAY_US);
+ udelay(fs->reset_delay_us);
/*
* Return clocks to their state before this function. For robustness
@@ -339,7 +340,7 @@
for (clock--; clock >= fs->clk_data; clock--)
clk_reset(clock->clk, CLK_RESET_ASSERT);
/* Wait for synchronous resets to propagate. */
- udelay(RESET_DELAY_US);
+ udelay(fs->reset_delay_us);
/* Enable the power rail at the footswitch. */
regval |= ENABLE_BIT;
@@ -354,7 +355,7 @@
/* Deassert resets for all clocks in the power domain. */
for (clock = fs->clk_data; clock->clk; clock++)
clk_reset(clock->clk, CLK_RESET_DEASSERT);
- udelay(RESET_DELAY_US);
+ udelay(fs->reset_delay_us);
/* Re-enable core clock. */
clk_prepare_enable(fs->core_clk);
@@ -497,6 +498,8 @@
fs->clk_data = driver_data->clks;
fs->bus_port0 = driver_data->bus_port0;
fs->bus_port1 = driver_data->bus_port1;
+ fs->reset_delay_us =
+ driver_data->reset_delay_us ? : DEFAULT_RESET_DELAY_US;
for (clock = fs->clk_data; clock->name; clock++) {
clock->clk = clk_get(&pdev->dev, clock->name);
diff --git a/arch/arm/mach-msm/footswitch.h b/arch/arm/mach-msm/footswitch.h
index 2a49426..57e8eba 100644
--- a/arch/arm/mach-msm/footswitch.h
+++ b/arch/arm/mach-msm/footswitch.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2013 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -41,6 +41,7 @@
struct fs_driver_data {
int bus_port0, bus_port1;
struct fs_clk_data *clks;
+ unsigned long reset_delay_us;
};
#define FS_GENERIC(_drv_name, _id, _name, _dev_id, _data) \
diff --git a/arch/arm/mach-msm/hotplug.c b/arch/arm/mach-msm/hotplug.c
index 0e97c27..e9a4af0 100644
--- a/arch/arm/mach-msm/hotplug.c
+++ b/arch/arm/mach-msm/hotplug.c
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2002 ARM Ltd.
* All Rights Reserved
- * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -29,6 +29,9 @@
unsigned int warm_boot;
};
+
+static cpumask_t cpu_dying_mask;
+
static DEFINE_PER_CPU_SHARED_ALIGNED(struct msm_hotplug_device,
msm_hotplug_devices);
@@ -70,12 +73,12 @@
int platform_cpu_kill(unsigned int cpu)
{
- int ret;
+ int ret = 0;
- ret = msm_pm_wait_cpu_shutdown(cpu);
- if (ret)
- return 0;
- return 1;
+ if (cpumask_test_and_clear_cpu(cpu, &cpu_dying_mask))
+ ret = msm_pm_wait_cpu_shutdown(cpu);
+
+ return ret ? 0 : 1;
}
/*
@@ -142,6 +145,7 @@
uncached_logk(LOGK_HOTPLUG, (void *)(cpudata | this_cpumask));
break;
case CPU_DYING:
+ cpumask_set_cpu((unsigned long)hcpu, &cpu_dying_mask);
uncached_logk(LOGK_HOTPLUG, (void *)(cpudata & ~this_cpumask));
break;
default:
diff --git a/arch/arm/mach-msm/include/mach/iommu.h b/arch/arm/mach-msm/include/mach/iommu.h
index 06f5215..70c696c 100644
--- a/arch/arm/mach-msm/include/mach/iommu.h
+++ b/arch/arm/mach-msm/include/mach/iommu.h
@@ -209,6 +209,7 @@
*/
irqreturn_t msm_iommu_fault_handler(int irq, void *dev_id);
irqreturn_t msm_iommu_fault_handler_v2(int irq, void *dev_id);
+irqreturn_t msm_iommu_secure_fault_handler_v2(int irq, void *dev_id);
enum {
PROC_APPS,
diff --git a/arch/arm/mach-msm/include/mach/ipa.h b/arch/arm/mach-msm/include/mach/ipa.h
index db5e126..697de5e 100644
--- a/arch/arm/mach-msm/include/mach/ipa.h
+++ b/arch/arm/mach-msm/include/mach/ipa.h
@@ -186,6 +186,16 @@
};
/**
+ * struct ipa_ep_cfg_holb - head of line blocking configuration in IPA end-point
+ * @en: enable(1 => ok to drop pkt)/disable(0 => never drop pkt)
+ * @tmr_val: duration in units of 128 IPA clk clock cyles [0,511], 1 clk=1.28us
+ */
+struct ipa_ep_cfg_holb {
+ u16 en;
+ u16 tmr_val;
+};
+
+/**
* struct ipa_ep_cfg - configuration of IPA end-point
* @nat: NAT parmeters
* @hdr: Header parameters
@@ -485,6 +495,11 @@
int ipa_cfg_ep_route(u32 clnt_hdl, const struct ipa_ep_cfg_route *ipa_ep_cfg);
+int ipa_cfg_ep_holb(u32 clnt_hdl, const struct ipa_ep_cfg_holb *ipa_ep_cfg);
+
+int ipa_cfg_ep_holb_by_client(enum ipa_client_type client,
+ const struct ipa_ep_cfg_holb *ipa_ep_cfg);
+
/*
* Header removal / addition
*/
@@ -754,6 +769,12 @@
return -EPERM;
}
+static inline int ipa_cfg_ep_holb(u32 clnt_hdl,
+ const struct ipa_ep_cfg_holb *ipa_ep_cfg)
+{
+ return -EPERM;
+}
+
/*
* Header removal / addition
*/
diff --git a/arch/arm/mach-msm/include/mach/mdm2.h b/arch/arm/mach-msm/include/mach/mdm2.h
index 46069d2..c6c03e4 100644
--- a/arch/arm/mach-msm/include/mach/mdm2.h
+++ b/arch/arm/mach-msm/include/mach/mdm2.h
@@ -12,6 +12,7 @@
#ifndef _ARCH_ARM_MACH_MSM_MDM2_H
#define _ARCH_ARM_MACH_MSM_MDM2_H
+#include "sysmon.h"
struct mdm_vddmin_resource {
int rpm_id;
@@ -35,6 +36,9 @@
int image_upgrade_supported;
struct gpiomux_setting *mdm2ap_status_gpio_run_cfg;
int send_shdn;
+ int cascading_ssr;
+ int sysmon_subsys_id_valid;
+ enum subsys_id sysmon_subsys_id;
};
#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_ipc_router.h b/arch/arm/mach-msm/include/mach/msm_ipc_router.h
index 5dc1095..a87380c 100644
--- a/arch/arm/mach-msm/include/mach/msm_ipc_router.h
+++ b/arch/arm/mach-msm/include/mach/msm_ipc_router.h
@@ -47,7 +47,7 @@
struct comm_mode_info mode_info;
struct list_head port_rx_q;
- struct mutex port_rx_q_lock;
+ struct mutex port_rx_q_lock_lhb3;
char rx_wakelock_name[MAX_WAKELOCK_NAME_SZ];
struct wake_lock port_rx_wake_lock;
wait_queue_head_t port_rx_wait_q;
diff --git a/arch/arm/mach-msm/include/mach/msm_smsm.h b/arch/arm/mach-msm/include/mach/msm_smsm.h
index 733f5a9..f97d5e4 100644
--- a/arch/arm/mach-msm/include/mach/msm_smsm.h
+++ b/arch/arm/mach-msm/include/mach/msm_smsm.h
@@ -39,12 +39,16 @@
};
#endif
+/*
+ * Ordered by when processors adopted the SMSM protocol. May not be 1-to-1
+ * with SMEM PIDs, despite initial expectations.
+ */
enum {
SMSM_APPS = SMEM_APPS,
SMSM_MODEM = SMEM_MODEM,
SMSM_Q6 = SMEM_Q6,
- SMSM_DSPS = SMEM_DSPS,
- SMSM_WCNSS = SMEM_WCNSS,
+ SMSM_WCNSS,
+ SMSM_DSPS,
};
extern uint32_t SMSM_NUM_HOSTS;
diff --git a/arch/arm/mach-msm/include/mach/socinfo.h b/arch/arm/mach-msm/include/mach/socinfo.h
index 99bff66..5aaab18 100644
--- a/arch/arm/mach-msm/include/mach/socinfo.h
+++ b/arch/arm/mach-msm/include/mach/socinfo.h
@@ -38,6 +38,9 @@
#define of_board_is_liquid() of_machine_is_compatible("qcom,liquid")
#define of_board_is_dragonboard() \
of_machine_is_compatible("qcom,dragonboard")
+#define of_board_is_cdp() of_machine_is_compatible("qcom,cdp")
+#define of_board_is_mtp() of_machine_is_compatible("qcom,mtp")
+#define of_board_is_qrd() of_machine_is_compatible("qcom,qrd")
#define machine_is_msm8974() of_machine_is_compatible("qcom,msm8974")
#define machine_is_msm9625() of_machine_is_compatible("qcom,msm9625")
@@ -63,6 +66,9 @@
#define of_board_is_fluid() 0
#define of_board_is_liquid() 0
#define of_board_is_dragonboard() 0
+#define of_board_is_cdp() 0
+#define of_board_is_mtp() 0
+#define of_board_is_qrd() 0
#define machine_is_msm8974() 0
#define machine_is_msm9625() 0
diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c
index 7fb2c88..f736b30 100644
--- a/arch/arm/mach-msm/io.c
+++ b/arch/arm/mach-msm/io.c
@@ -562,6 +562,7 @@
{
msm_shared_ram_phys = MPQ8092_MSM_SHARED_RAM_PHYS;
msm_map_io(mpq8092_io_desc, ARRAY_SIZE(mpq8092_io_desc));
+ of_scan_flat_dt(msm_scan_dt_map_imem, NULL);
}
#endif /* CONFIG_ARCH_MPQ8092 */
diff --git a/arch/arm/mach-msm/ipc_router.c b/arch/arm/mach-msm/ipc_router.c
index 573b9a3..41fd485 100644
--- a/arch/arm/mach-msm/ipc_router.c
+++ b/arch/arm/mach-msm/ipc_router.c
@@ -27,6 +27,7 @@
#include <linux/platform_device.h>
#include <linux/uaccess.h>
#include <linux/debugfs.h>
+#include <linux/rwsem.h>
#include <asm/uaccess.h>
#include <asm/byteorder.h>
@@ -99,11 +100,11 @@
#define IPC_ROUTER_LOG_EVENT_RX 0x12
static LIST_HEAD(control_ports);
-static DEFINE_MUTEX(control_ports_lock);
+static DECLARE_RWSEM(control_ports_lock_lha5);
#define LP_HASH_SIZE 32
static struct list_head local_ports[LP_HASH_SIZE];
-static DEFINE_MUTEX(local_ports_lock);
+static DECLARE_RWSEM(local_ports_lock_lha2);
/*
* Server info is organized as a hash table. The server's service ID is
@@ -114,7 +115,7 @@
*/
#define SRV_HASH_SIZE 32
static struct list_head server_list[SRV_HASH_SIZE];
-static DEFINE_MUTEX(server_list_lock);
+static DECLARE_RWSEM(server_list_lock_lha2);
struct msm_ipc_server {
struct list_head list;
@@ -143,11 +144,11 @@
struct list_head list;
uint32_t node_id;
uint32_t port_id;
- uint32_t restart_state;
uint32_t tx_quota_cnt;
- struct mutex quota_lock;
+ struct mutex quota_lock_lhb2;
struct list_head resume_tx_port_list;
void *sec_rule;
+ struct msm_ipc_server *server;
};
struct msm_ipc_router_xprt_info {
@@ -157,8 +158,8 @@
uint32_t initialized;
struct list_head pkt_list;
struct wake_lock wakelock;
- struct mutex rx_lock;
- struct mutex tx_lock;
+ struct mutex rx_lock_lhb2;
+ struct mutex tx_lock_lhb2;
uint32_t need_len;
uint32_t abort_data_read;
struct work_struct read_data;
@@ -172,36 +173,25 @@
uint32_t neighbor_node_id;
struct list_head remote_port_list[RP_HASH_SIZE];
struct msm_ipc_router_xprt_info *xprt_info;
- struct mutex lock;
+ struct rw_semaphore lock_lha4;
unsigned long num_tx_bytes;
unsigned long num_rx_bytes;
};
static struct list_head routing_table[RT_HASH_SIZE];
-static DEFINE_MUTEX(routing_table_lock);
+static DECLARE_RWSEM(routing_table_lock_lha3);
static int routing_table_inited;
static void do_read_data(struct work_struct *work);
-#define RR_STATE_IDLE 0
-#define RR_STATE_HEADER 1
-#define RR_STATE_BODY 2
-#define RR_STATE_ERROR 3
-
-#define RESTART_NORMAL 0
-#define RESTART_PEND 1
-
-/* State for remote ep following restart */
-#define RESTART_QUOTA_ABORT 1
-
static LIST_HEAD(xprt_info_list);
-static DEFINE_MUTEX(xprt_info_list_lock);
+static DECLARE_RWSEM(xprt_info_list_lock_lha5);
static DECLARE_COMPLETION(msm_ipc_local_router_up);
#define IPC_ROUTER_INIT_TIMEOUT (10 * HZ)
static uint32_t next_port_id;
-static DEFINE_MUTEX(next_port_id_lock);
+static DEFINE_MUTEX(next_port_id_lock_lha1);
static atomic_t pending_close_count = ATOMIC_INIT(0);
static wait_queue_head_t subsystem_restart_wait;
static struct workqueue_struct *msm_ipc_router_workqueue;
@@ -235,13 +225,13 @@
for (i = 0; i < RP_HASH_SIZE; i++)
INIT_LIST_HEAD(&rt_entry->remote_port_list[i]);
- mutex_init(&rt_entry->lock);
+ init_rwsem(&rt_entry->lock_lha4);
rt_entry->node_id = node_id;
rt_entry->xprt_info = NULL;
return rt_entry;
}
-/*Please take routing_table_lock before calling this function*/
+/* Must be called with routing_table_lock_lha3 locked. */
static int add_routing_table_entry(
struct msm_ipc_routing_table_entry *rt_entry)
{
@@ -255,7 +245,7 @@
return 0;
}
-/*Please take routing_table_lock before calling this function*/
+/* Must be called with routing_table_lock_lha3 locked. */
static struct msm_ipc_routing_table_entry *lookup_routing_table(
uint32_t node_id)
{
@@ -276,16 +266,16 @@
if (!xprt_info)
return NULL;
- mutex_lock(&xprt_info->rx_lock);
+ mutex_lock(&xprt_info->rx_lock_lhb2);
if (xprt_info->abort_data_read) {
- mutex_unlock(&xprt_info->rx_lock);
+ mutex_unlock(&xprt_info->rx_lock_lhb2);
pr_err("%s detected SSR & exiting now\n",
xprt_info->xprt->name);
return NULL;
}
if (list_empty(&xprt_info->pkt_list)) {
- mutex_unlock(&xprt_info->rx_lock);
+ mutex_unlock(&xprt_info->rx_lock_lhb2);
return NULL;
}
@@ -294,7 +284,7 @@
list_del(&temp_pkt->list);
if (list_empty(&xprt_info->pkt_list))
wake_unlock(&xprt_info->wakelock);
- mutex_unlock(&xprt_info->rx_lock);
+ mutex_unlock(&xprt_info->rx_lock_lhb2);
return temp_pkt;
}
@@ -490,13 +480,13 @@
}
}
- mutex_lock(&port_ptr->port_rx_q_lock);
+ mutex_lock(&port_ptr->port_rx_q_lock_lhb3);
wake_lock(&port_ptr->port_rx_wake_lock);
list_add_tail(&temp_pkt->list, &port_ptr->port_rx_q);
wake_up(&port_ptr->port_rx_wait_q);
if (port_ptr->notify)
port_ptr->notify(MSM_IPC_ROUTER_READ_CB, port_ptr->priv);
- mutex_unlock(&port_ptr->port_rx_q_lock);
+ mutex_unlock(&port_ptr->port_rx_q_lock_lhb3);
return 0;
}
@@ -507,10 +497,10 @@
if (!pkt)
return -EINVAL;
- mutex_lock(&control_ports_lock);
+ down_read(&control_ports_lock_lha5);
list_for_each_entry(port_ptr, &control_ports, list)
post_pkt_to_port(port_ptr, pkt, 1);
- mutex_unlock(&control_ports_lock);
+ up_read(&control_ports_lock_lha5);
return 0;
}
@@ -519,9 +509,9 @@
uint32_t port_id = 0, prev_port_id, key;
struct msm_ipc_port *port_ptr;
- mutex_lock(&next_port_id_lock);
+ mutex_lock(&next_port_id_lock_lha1);
prev_port_id = next_port_id;
- mutex_lock(&local_ports_lock);
+ down_read(&local_ports_lock_lha2);
do {
next_port_id++;
if ((next_port_id & 0xFFFFFFFE) == 0xFFFFFFFE)
@@ -544,8 +534,8 @@
}
port_id = 0;
} while (next_port_id != prev_port_id);
- mutex_unlock(&local_ports_lock);
- mutex_unlock(&next_port_id_lock);
+ up_read(&local_ports_lock_lha2);
+ mutex_unlock(&next_port_id_lock_lha1);
return port_id;
}
@@ -558,9 +548,9 @@
return;
key = (port_ptr->this_port.port_id & (LP_HASH_SIZE - 1));
- mutex_lock(&local_ports_lock);
+ down_write(&local_ports_lock_lha2);
list_add_tail(&port_ptr->list, &local_ports[key]);
- mutex_unlock(&local_ports_lock);
+ up_write(&local_ports_lock_lha2);
}
struct msm_ipc_port *msm_ipc_router_create_raw_port(void *endpoint,
@@ -583,7 +573,7 @@
spin_lock_init(&port_ptr->port_lock);
INIT_LIST_HEAD(&port_ptr->port_rx_q);
- mutex_init(&port_ptr->port_rx_q_lock);
+ mutex_init(&port_ptr->port_rx_q_lock_lhb3);
init_waitqueue_head(&port_ptr->port_rx_wait_q);
snprintf(port_ptr->rx_wakelock_name, MAX_WAKELOCK_NAME_SZ,
"ipc%08x_%s",
@@ -600,9 +590,7 @@
return port_ptr;
}
-/*
- * Should be called with local_ports_lock locked
- */
+/* Must be called with local_ports_lock_lha2 locked. */
static struct msm_ipc_port *msm_ipc_router_lookup_local_port(uint32_t port_id)
{
int key = (port_id & (LP_HASH_SIZE - 1));
@@ -616,6 +604,7 @@
return NULL;
}
+/* Must be called with routing_table_lock_lha3 locked. */
static struct msm_ipc_router_remote_port *msm_ipc_router_lookup_remote_port(
uint32_t node_id,
uint32_t port_id)
@@ -624,30 +613,25 @@
struct msm_ipc_routing_table_entry *rt_entry;
int key = (port_id & (RP_HASH_SIZE - 1));
- mutex_lock(&routing_table_lock);
rt_entry = lookup_routing_table(node_id);
if (!rt_entry) {
- mutex_unlock(&routing_table_lock);
pr_err("%s: Node is not up\n", __func__);
return NULL;
}
- mutex_lock(&rt_entry->lock);
+ down_read(&rt_entry->lock_lha4);
list_for_each_entry(rport_ptr,
&rt_entry->remote_port_list[key], list) {
if (rport_ptr->port_id == port_id) {
- if (rport_ptr->restart_state != RESTART_NORMAL)
- rport_ptr = NULL;
- mutex_unlock(&rt_entry->lock);
- mutex_unlock(&routing_table_lock);
+ up_read(&rt_entry->lock_lha4);
return rport_ptr;
}
}
- mutex_unlock(&rt_entry->lock);
- mutex_unlock(&routing_table_lock);
+ up_read(&rt_entry->lock_lha4);
return NULL;
}
+/* Must be called with routing_table_lock_lha3 locked. */
static struct msm_ipc_router_remote_port *msm_ipc_router_create_remote_port(
uint32_t node_id,
uint32_t port_id)
@@ -656,34 +640,29 @@
struct msm_ipc_routing_table_entry *rt_entry;
int key = (port_id & (RP_HASH_SIZE - 1));
- mutex_lock(&routing_table_lock);
rt_entry = lookup_routing_table(node_id);
if (!rt_entry) {
- mutex_unlock(&routing_table_lock);
pr_err("%s: Node is not up\n", __func__);
return NULL;
}
- mutex_lock(&rt_entry->lock);
rport_ptr = kmalloc(sizeof(struct msm_ipc_router_remote_port),
GFP_KERNEL);
if (!rport_ptr) {
- mutex_unlock(&rt_entry->lock);
- mutex_unlock(&routing_table_lock);
pr_err("%s: Remote port alloc failed\n", __func__);
return NULL;
}
rport_ptr->port_id = port_id;
rport_ptr->node_id = node_id;
- rport_ptr->restart_state = RESTART_NORMAL;
rport_ptr->sec_rule = NULL;
+ rport_ptr->server = NULL;
rport_ptr->tx_quota_cnt = 0;
- mutex_init(&rport_ptr->quota_lock);
+ mutex_init(&rport_ptr->quota_lock_lhb2);
INIT_LIST_HEAD(&rport_ptr->resume_tx_port_list);
+ down_write(&rt_entry->lock_lha4);
list_add_tail(&rport_ptr->list,
&rt_entry->remote_port_list[key]);
- mutex_unlock(&rt_entry->lock);
- mutex_unlock(&routing_table_lock);
+ up_write(&rt_entry->lock_lha4);
return rport_ptr;
}
@@ -694,7 +673,7 @@
* This function deletes all the resume_tx ports associated with a remote port
* and frees the memory allocated to each resume_tx port.
*
- * Must be called with rport_ptr->quota_lock locked.
+ * Must be called with rport_ptr->quota_lock_lhb2 locked.
*/
static void msm_ipc_router_free_resume_tx_port(
struct msm_ipc_router_remote_port *rport_ptr)
@@ -719,7 +698,7 @@
* remote port's resume_tx list. This function is used to ensure that
* the same port is not added to the remote_port's resume_tx list repeatedly.
*
- * Must be called with rport_ptr->quota_lock locked.
+ * Must be called with rport_ptr->quota_lock_lhb2 locked.
*/
static int msm_ipc_router_lookup_resume_tx_port(
struct msm_ipc_router_remote_port *rport_ptr, uint32_t port_id)
@@ -744,7 +723,7 @@
* function sequentially deletes each entry in the resume_tx_port_list of the
* remote port.
*
- * Must be called with rport_ptr->quota_lock locked.
+ * Must be called with rport_ptr->quota_lock_lhb2 locked.
*/
static void post_resume_tx(struct msm_ipc_router_remote_port *rport_ptr,
struct rr_packet *pkt)
@@ -754,17 +733,16 @@
list_for_each_entry_safe(rtx_port, tmp_rtx_port,
&rport_ptr->resume_tx_port_list, list) {
- mutex_lock(&local_ports_lock);
local_port =
msm_ipc_router_lookup_local_port(rtx_port->port_id);
if (local_port)
post_pkt_to_port(local_port, pkt, 1);
- mutex_unlock(&local_ports_lock);
list_del(&rtx_port->list);
kfree(rtx_port);
}
}
+/* Must be called with routing_table_lock_lha3 locked. */
static void msm_ipc_router_destroy_remote_port(
struct msm_ipc_router_remote_port *rport_ptr)
{
@@ -775,21 +753,18 @@
return;
node_id = rport_ptr->node_id;
- mutex_lock(&routing_table_lock);
rt_entry = lookup_routing_table(node_id);
if (!rt_entry) {
- mutex_unlock(&routing_table_lock);
pr_err("%s: Node %d is not up\n", __func__, node_id);
return;
}
- mutex_lock(&rport_ptr->quota_lock);
- msm_ipc_router_free_resume_tx_port(rport_ptr);
- mutex_unlock(&rport_ptr->quota_lock);
- mutex_lock(&rt_entry->lock);
+ down_write(&rt_entry->lock_lha4);
list_del(&rport_ptr->list);
+ up_write(&rt_entry->lock_lha4);
+ mutex_lock(&rport_ptr->quota_lock_lhb2);
+ msm_ipc_router_free_resume_tx_port(rport_ptr);
+ mutex_unlock(&rport_ptr->quota_lock_lhb2);
kfree(rport_ptr);
- mutex_unlock(&rt_entry->lock);
- mutex_unlock(&routing_table_lock);
return;
}
@@ -802,7 +777,7 @@
*
* @return: If found Pointer to server structure, else NULL.
*
- * Note1: Lock the server_list_lock before accessing this function.
+ * Note1: Lock the server_list_lock_lha2 before accessing this function.
* Note2: If the <node_id:port_id> are <0:0>, then the lookup is restricted
* to <service:instance>. Used only when a client wants to send a
* message to any QMI server.
@@ -850,7 +825,7 @@
* This function adds the server info to the hash table. If the same
* server(i.e. <service_id:instance_id>) is hosted in different nodes,
* they are maintained as list of "server_port" under "server" structure.
- * Note: Lock the server_list_lock before accessing this function.
+ * Note: Lock the server_list_lock_lha2 before accessing this function.
*/
static struct msm_ipc_server *msm_ipc_router_create_server(
uint32_t service,
@@ -916,7 +891,7 @@
* from the server structure. If the server_port list under server structure
* is empty after removal, then remove the server structure from the server
* hash table.
- * Note: Lock the server_list_lock before accessing this function.
+ * Note: Lock the server_list_lock_lha2 before accessing this function.
*/
static void msm_ipc_router_destroy_server(struct msm_ipc_server *server,
uint32_t node_id, uint32_t port_id)
@@ -1011,9 +986,9 @@
pkt->pkt_fragment_q = pkt_fragment_q;
pkt->length = pkt_size;
- mutex_lock(&xprt_info->tx_lock);
+ mutex_lock(&xprt_info->tx_lock_lhb2);
ret = xprt_info->xprt->write(pkt, pkt_size, xprt_info->xprt);
- mutex_unlock(&xprt_info->tx_lock);
+ mutex_unlock(&xprt_info->tx_lock_lhb2);
release_pkt(pkt);
return ret;
@@ -1148,11 +1123,11 @@
{
struct msm_ipc_router_xprt_info *xprt_info;
- mutex_lock(&xprt_info_list_lock);
+ down_read(&xprt_info_list_lock_lha5);
list_for_each_entry(xprt_info, &xprt_info_list, list) {
msm_ipc_router_send_control_msg(xprt_info, ctl);
}
- mutex_unlock(&xprt_info_list_lock);
+ up_read(&xprt_info_list_lock_lha5);
return 0;
}
@@ -1165,12 +1140,12 @@
if (!xprt_info || !ctl)
return -EINVAL;
- mutex_lock(&xprt_info_list_lock);
+ down_read(&xprt_info_list_lock_lha5);
list_for_each_entry(fwd_xprt_info, &xprt_info_list, list) {
if (xprt_info->xprt->link_id != fwd_xprt_info->xprt->link_id)
msm_ipc_router_send_control_msg(fwd_xprt_info, ctl);
}
- mutex_unlock(&xprt_info_list_lock);
+ up_read(&xprt_info_list_lock_lha5);
return 0;
}
@@ -1183,15 +1158,15 @@
if (!xprt_info || !pkt)
return -EINVAL;
- mutex_lock(&xprt_info_list_lock);
+ down_read(&xprt_info_list_lock_lha5);
list_for_each_entry(fwd_xprt_info, &xprt_info_list, list) {
- mutex_lock(&fwd_xprt_info->tx_lock);
+ mutex_lock(&fwd_xprt_info->tx_lock_lhb2);
if (xprt_info->xprt->link_id != fwd_xprt_info->xprt->link_id)
fwd_xprt_info->xprt->write(pkt, pkt->length,
fwd_xprt_info->xprt);
- mutex_unlock(&fwd_xprt_info->tx_lock);
+ mutex_unlock(&fwd_xprt_info->tx_lock_lhb2);
}
- mutex_unlock(&xprt_info_list_lock);
+ up_read(&xprt_info_list_lock_lha5);
return 0;
}
@@ -1203,6 +1178,7 @@
struct rr_header *hdr;
struct msm_ipc_router_xprt_info *fwd_xprt_info;
struct msm_ipc_routing_table_entry *rt_entry;
+ int ret = 0;
if (!xprt_info || !pkt)
return -EINVAL;
@@ -1213,38 +1189,34 @@
hdr = (struct rr_header *)head_pkt->data;
dst_node_id = hdr->dst_node_id;
- mutex_lock(&routing_table_lock);
+ down_read(&routing_table_lock_lha3);
rt_entry = lookup_routing_table(dst_node_id);
if (!(rt_entry) || !(rt_entry->xprt_info)) {
- mutex_unlock(&routing_table_lock);
+ up_read(&routing_table_lock_lha3);
pr_err("%s: Routing table not initialized\n", __func__);
return -ENODEV;
}
- mutex_lock(&rt_entry->lock);
+ down_read(&rt_entry->lock_lha4);
fwd_xprt_info = rt_entry->xprt_info;
- mutex_lock(&fwd_xprt_info->tx_lock);
if (xprt_info->remote_node_id == fwd_xprt_info->remote_node_id) {
- mutex_unlock(&fwd_xprt_info->tx_lock);
- mutex_unlock(&rt_entry->lock);
- mutex_unlock(&routing_table_lock);
pr_err("%s: Discarding Command to route back\n", __func__);
- return -EINVAL;
+ ret = -EINVAL;
+ goto fwd_msg_out;
}
if (xprt_info->xprt->link_id == fwd_xprt_info->xprt->link_id) {
- mutex_unlock(&fwd_xprt_info->tx_lock);
- mutex_unlock(&rt_entry->lock);
- mutex_unlock(&routing_table_lock);
pr_err("%s: DST in the same cluster\n", __func__);
- return 0;
+ goto fwd_msg_out;
}
+ mutex_lock(&fwd_xprt_info->tx_lock_lhb2);
fwd_xprt_info->xprt->write(pkt, pkt->length, fwd_xprt_info->xprt);
- mutex_unlock(&fwd_xprt_info->tx_lock);
- mutex_unlock(&rt_entry->lock);
- mutex_unlock(&routing_table_lock);
+ mutex_unlock(&fwd_xprt_info->tx_lock_lhb2);
+fwd_msg_out:
+ up_read(&rt_entry->lock_lha4);
+ up_read(&routing_table_lock_lha3);
- return 0;
+ return ret;
}
static int msm_ipc_router_send_remove_client(struct comm_mode_info *mode_info,
@@ -1268,14 +1240,14 @@
msg.cli.port_id = port_id;
if ((mode == SINGLE_LINK_MODE) && xprt_info) {
- mutex_lock(&xprt_info_list_lock);
+ down_read(&xprt_info_list_lock_lha5);
list_for_each_entry(tmp_xprt_info, &xprt_info_list, list) {
if (tmp_xprt_info != xprt_info)
continue;
msm_ipc_router_send_control_msg(tmp_xprt_info, &msg);
break;
}
- mutex_unlock(&xprt_info_list_lock);
+ up_read(&xprt_info_list_lock_lha5);
} else if ((mode == SINGLE_LINK_MODE) && !xprt_info) {
broadcast_ctl_msg_locally(&msg);
} else if (mode == MULTI_LINK_MODE) {
@@ -1308,141 +1280,52 @@
return;
}
-static void reset_remote_port_info(uint32_t node_id, uint32_t port_id)
+static void cleanup_rmt_server(struct msm_ipc_router_xprt_info *xprt_info,
+ struct msm_ipc_router_remote_port *rport_ptr)
{
- struct msm_ipc_router_remote_port *rport_ptr;
-
- rport_ptr = msm_ipc_router_lookup_remote_port(node_id, port_id);
- if (!rport_ptr) {
- pr_err("%s: No such remote port %08x:%08x\n",
- __func__, node_id, port_id);
- return;
- }
- mutex_lock(&rport_ptr->quota_lock);
- rport_ptr->restart_state = RESTART_PEND;
- msm_ipc_router_free_resume_tx_port(rport_ptr);
- mutex_unlock(&rport_ptr->quota_lock);
- return;
-}
-
-static void msm_ipc_cleanup_remote_server_info(
- struct msm_ipc_router_xprt_info *xprt_info)
-{
- struct msm_ipc_server *svr, *tmp_svr;
- struct msm_ipc_server_port *svr_port, *tmp_svr_port;
- int i;
union rr_control_msg ctl;
+ struct msm_ipc_server *server = rport_ptr->server;
- if (!xprt_info) {
- pr_err("%s: Invalid xprt_info\n", __func__);
- return;
- }
-
+ D("Remove server %08x:%08x - %08x:%08x",
+ server->name.service, server->name.instance,
+ rport_ptr->node_id, rport_ptr->port_id);
ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
- mutex_lock(&server_list_lock);
- for (i = 0; i < SRV_HASH_SIZE; i++) {
- list_for_each_entry_safe(svr, tmp_svr, &server_list[i], list) {
- ctl.srv.service = svr->name.service;
- ctl.srv.instance = svr->name.instance;
- list_for_each_entry_safe(svr_port, tmp_svr_port,
- &svr->server_port_list, list) {
- if (svr_port->xprt_info != xprt_info)
- continue;
- D("Remove server %08x:%08x - %08x:%08x",
- ctl.srv.service, ctl.srv.instance,
- svr_port->server_addr.node_id,
- svr_port->server_addr.port_id);
- reset_remote_port_info(
- svr_port->server_addr.node_id,
- svr_port->server_addr.port_id);
- ctl.srv.node_id = svr_port->server_addr.node_id;
- ctl.srv.port_id = svr_port->server_addr.port_id;
- relay_ctl_msg(xprt_info, &ctl);
- broadcast_ctl_msg_locally(&ctl);
- platform_device_unregister(&svr_port->pdev);
- list_del(&svr_port->list);
- kfree(svr_port);
- }
- if (list_empty(&svr->server_port_list)) {
- list_del(&svr->list);
- kfree(svr);
- }
- }
- }
- mutex_unlock(&server_list_lock);
+ ctl.srv.service = server->name.service;
+ ctl.srv.instance = server->name.instance;
+ ctl.srv.node_id = rport_ptr->node_id;
+ ctl.srv.port_id = rport_ptr->port_id;
+ relay_ctl_msg(xprt_info, &ctl);
+ broadcast_ctl_msg_locally(&ctl);
+ msm_ipc_router_destroy_server(server,
+ rport_ptr->node_id, rport_ptr->port_id);
}
-static void msm_ipc_cleanup_remote_client_info(
- struct msm_ipc_router_xprt_info *xprt_info)
+static void cleanup_rmt_ports(struct msm_ipc_router_xprt_info *xprt_info,
+ struct msm_ipc_routing_table_entry *rt_entry)
{
- struct msm_ipc_routing_table_entry *rt_entry;
- struct msm_ipc_router_remote_port *rport_ptr;
- int i, j;
- union rr_control_msg ctl;
-
- if (!xprt_info) {
- pr_err("%s: Invalid xprt_info\n", __func__);
- return;
- }
-
- ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT;
- mutex_lock(&routing_table_lock);
- for (i = 0; i < RT_HASH_SIZE; i++) {
- list_for_each_entry(rt_entry, &routing_table[i], list) {
- mutex_lock(&rt_entry->lock);
- if (rt_entry->xprt_info != xprt_info) {
- mutex_unlock(&rt_entry->lock);
- continue;
- }
- for (j = 0; j < RP_HASH_SIZE; j++) {
- list_for_each_entry(rport_ptr,
- &rt_entry->remote_port_list[j], list) {
- if (rport_ptr->restart_state ==
- RESTART_PEND)
- continue;
- mutex_lock(&rport_ptr->quota_lock);
- rport_ptr->restart_state = RESTART_PEND;
- msm_ipc_router_free_resume_tx_port(
- rport_ptr);
- mutex_unlock(&rport_ptr->quota_lock);
- ctl.cli.node_id = rport_ptr->node_id;
- ctl.cli.port_id = rport_ptr->port_id;
- broadcast_ctl_msg_locally(&ctl);
- }
- }
- mutex_unlock(&rt_entry->lock);
- }
- }
- mutex_unlock(&routing_table_lock);
-}
-
-static void msm_ipc_cleanup_remote_port_info(uint32_t node_id)
-{
- struct msm_ipc_routing_table_entry *rt_entry, *tmp_rt_entry;
struct msm_ipc_router_remote_port *rport_ptr, *tmp_rport_ptr;
- int i, j;
+ union rr_control_msg ctl;
+ int j;
- mutex_lock(&routing_table_lock);
- for (i = 0; i < RT_HASH_SIZE; i++) {
- list_for_each_entry_safe(rt_entry, tmp_rt_entry,
- &routing_table[i], list) {
- mutex_lock(&rt_entry->lock);
- if (rt_entry->neighbor_node_id != node_id) {
- mutex_unlock(&rt_entry->lock);
- continue;
- }
- for (j = 0; j < RP_HASH_SIZE; j++) {
- list_for_each_entry_safe(rport_ptr,
- tmp_rport_ptr,
- &rt_entry->remote_port_list[j], list) {
- list_del(&rport_ptr->list);
- kfree(rport_ptr);
- }
- }
- mutex_unlock(&rt_entry->lock);
+ for (j = 0; j < RP_HASH_SIZE; j++) {
+ list_for_each_entry_safe(rport_ptr, tmp_rport_ptr,
+ &rt_entry->remote_port_list[j], list) {
+ list_del(&rport_ptr->list);
+ mutex_lock(&rport_ptr->quota_lock_lhb2);
+ msm_ipc_router_free_resume_tx_port(rport_ptr);
+ mutex_unlock(&rport_ptr->quota_lock_lhb2);
+
+ if (rport_ptr->server)
+ cleanup_rmt_server(xprt_info, rport_ptr);
+
+ ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT;
+ ctl.cli.node_id = rport_ptr->node_id;
+ ctl.cli.port_id = rport_ptr->port_id;
+ relay_ctl_msg(xprt_info, &ctl);
+ broadcast_ctl_msg_locally(&ctl);
+ kfree(rport_ptr);
}
}
- mutex_unlock(&routing_table_lock);
}
static void msm_ipc_cleanup_routing_table(
@@ -1456,29 +1339,22 @@
return;
}
- mutex_lock(&routing_table_lock);
+ down_write(&server_list_lock_lha2);
+ down_write(&routing_table_lock_lha3);
for (i = 0; i < RT_HASH_SIZE; i++) {
list_for_each_entry(rt_entry, &routing_table[i], list) {
- mutex_lock(&rt_entry->lock);
- if (rt_entry->xprt_info == xprt_info)
- rt_entry->xprt_info = NULL;
- mutex_unlock(&rt_entry->lock);
+ down_write(&rt_entry->lock_lha4);
+ if (rt_entry->xprt_info != xprt_info) {
+ up_write(&rt_entry->lock_lha4);
+ continue;
+ }
+ cleanup_rmt_ports(xprt_info, rt_entry);
+ rt_entry->xprt_info = NULL;
+ up_write(&rt_entry->lock_lha4);
}
}
- mutex_unlock(&routing_table_lock);
-}
-
-static void modem_reset_cleanup(struct msm_ipc_router_xprt_info *xprt_info)
-{
-
- if (!xprt_info) {
- pr_err("%s: Invalid xprt_info\n", __func__);
- return;
- }
-
- msm_ipc_cleanup_remote_server_info(xprt_info);
- msm_ipc_cleanup_remote_client_info(xprt_info);
- msm_ipc_cleanup_routing_table(xprt_info);
+ up_write(&routing_table_lock_lha3);
+ up_write(&server_list_lock_lha2);
}
/**
@@ -1494,6 +1370,7 @@
struct msm_ipc_server_port *server_port;
struct msm_ipc_router_remote_port *rport_ptr = NULL;
+ down_read(&routing_table_lock_lha3);
list_for_each_entry(server_port, &server->server_port_list, list) {
rport_ptr = msm_ipc_router_lookup_remote_port(
server_port->server_addr.node_id,
@@ -1502,6 +1379,7 @@
continue;
rport_ptr->sec_rule = rule;
}
+ up_read(&routing_table_lock_lha3);
server->synced_sec_rule = 1;
}
@@ -1521,7 +1399,7 @@
int key = (service & (SRV_HASH_SIZE - 1));
struct msm_ipc_server *server;
- mutex_lock(&server_list_lock);
+ down_write(&server_list_lock_lha2);
list_for_each_entry(server, &server_list[key], list) {
if (server->name.service != service)
continue;
@@ -1540,7 +1418,7 @@
sync_sec_rule(server, rule);
}
- mutex_unlock(&server_list_lock);
+ up_write(&server_list_lock_lha2);
}
/**
@@ -1558,7 +1436,7 @@
int key;
struct msm_ipc_server *server;
- mutex_lock(&server_list_lock);
+ down_write(&server_list_lock_lha2);
for (key = 0; key < SRV_HASH_SIZE; key++) {
list_for_each_entry(server, &server_list[key], list) {
if (server->synced_sec_rule)
@@ -1567,7 +1445,7 @@
sync_sec_rule(server, rule);
}
}
- mutex_unlock(&server_list_lock);
+ up_write(&server_list_lock_lha2);
}
static int process_hello_msg(struct msm_ipc_router_xprt_info *xprt_info,
@@ -1590,25 +1468,22 @@
* an entry. Update the entry with the Node ID that it corresponds
* to and the XPRT through which it can be reached.
*/
- mutex_lock(&routing_table_lock);
+ down_write(&routing_table_lock_lha3);
rt_entry = lookup_routing_table(hdr->src_node_id);
if (!rt_entry) {
rt_entry = alloc_routing_table_entry(hdr->src_node_id);
if (!rt_entry) {
- mutex_unlock(&routing_table_lock);
+ up_write(&routing_table_lock_lha3);
pr_err("%s: rt_entry allocation failed\n", __func__);
return -ENOMEM;
}
add_routing_table_entry(rt_entry);
}
- mutex_lock(&rt_entry->lock);
+ down_write(&rt_entry->lock_lha4);
rt_entry->neighbor_node_id = xprt_info->remote_node_id;
rt_entry->xprt_info = xprt_info;
- mutex_unlock(&rt_entry->lock);
- mutex_unlock(&routing_table_lock);
-
- /* Cleanup any remote ports, if the node is coming out of reset */
- msm_ipc_cleanup_remote_port_info(xprt_info->remote_node_id);
+ up_write(&rt_entry->lock_lha4);
+ up_write(&routing_table_lock_lha3);
/* Send a reply HELLO message */
memset(&ctl, 0, sizeof(ctl));
@@ -1624,8 +1499,8 @@
* Send list of servers from the local node and from nodes
* outside the mesh network in which this XPRT is part of.
*/
- mutex_lock(&server_list_lock);
- mutex_lock(&routing_table_lock);
+ down_read(&server_list_lock_lha2);
+ down_read(&routing_table_lock_lha3);
for (i = 0; i < RT_HASH_SIZE; i++) {
list_for_each_entry(rt_entry, &routing_table[i], list) {
if ((rt_entry->node_id != IPC_ROUTER_NID_LOCAL) &&
@@ -1636,14 +1511,14 @@
rc = msm_ipc_router_send_server_list(rt_entry->node_id,
xprt_info);
if (rc < 0) {
- mutex_unlock(&routing_table_lock);
- mutex_unlock(&server_list_lock);
+ up_read(&routing_table_lock_lha3);
+ up_read(&server_list_lock_lha2);
return rc;
}
}
}
- mutex_unlock(&routing_table_lock);
- mutex_unlock(&server_list_lock);
+ up_read(&routing_table_lock_lha3);
+ up_read(&server_list_lock_lha2);
RR("HELLO message processed\n");
return rc;
}
@@ -1652,19 +1527,26 @@
struct rr_packet *pkt)
{
struct msm_ipc_router_remote_port *rport_ptr;
+ int ret = 0;
RR("o RESUME_TX id=%d:%08x\n", msg->cli.node_id, msg->cli.port_id);
+ down_read(&local_ports_lock_lha2);
+ down_read(&routing_table_lock_lha3);
rport_ptr = msm_ipc_router_lookup_remote_port(msg->cli.node_id,
msg->cli.port_id);
if (!rport_ptr) {
pr_err("%s: Unable to resume client\n", __func__);
- return -ENODEV;
+ ret = -ENODEV;
+ goto prtm_out;
}
- mutex_lock(&rport_ptr->quota_lock);
+ mutex_lock(&rport_ptr->quota_lock_lhb2);
rport_ptr->tx_quota_cnt = 0;
post_resume_tx(rport_ptr, pkt);
- mutex_unlock(&rport_ptr->quota_lock);
+ mutex_unlock(&rport_ptr->quota_lock_lhb2);
+prtm_out:
+ up_read(&routing_table_lock_lha3);
+ up_read(&local_ports_lock_lha2);
return 0;
}
@@ -1690,22 +1572,22 @@
* allocate an entry. Update the entry with the Node ID that it
* corresponds to and the XPRT through which it can be reached.
*/
- mutex_lock(&routing_table_lock);
+ down_write(&routing_table_lock_lha3);
rt_entry = lookup_routing_table(msg->srv.node_id);
if (!rt_entry) {
rt_entry = alloc_routing_table_entry(msg->srv.node_id);
if (!rt_entry) {
- mutex_unlock(&routing_table_lock);
+ up_write(&routing_table_lock_lha3);
pr_err("%s: rt_entry allocation failed\n", __func__);
return -ENOMEM;
}
- mutex_lock(&rt_entry->lock);
+ down_write(&rt_entry->lock_lha4);
rt_entry->neighbor_node_id = xprt_info->remote_node_id;
rt_entry->xprt_info = xprt_info;
- mutex_unlock(&rt_entry->lock);
+ up_write(&rt_entry->lock_lha4);
add_routing_table_entry(rt_entry);
}
- mutex_unlock(&routing_table_lock);
+ up_write(&routing_table_lock_lha3);
/*
* If the service does not exist already in the database, create and
@@ -1713,7 +1595,7 @@
* the service is hosted and cache the security rule for the service
* in that remote port structure.
*/
- mutex_lock(&server_list_lock);
+ down_write(&server_list_lock_lha2);
server = msm_ipc_router_lookup_server(msg->srv.service,
msg->srv.instance, msg->srv.node_id, msg->srv.port_id);
if (!server) {
@@ -1721,25 +1603,29 @@
msg->srv.service, msg->srv.instance,
msg->srv.node_id, msg->srv.port_id, xprt_info);
if (!server) {
- mutex_unlock(&server_list_lock);
+ up_write(&server_list_lock_lha2);
pr_err("%s: Server Create failed\n", __func__);
return -ENOMEM;
}
+ down_read(&routing_table_lock_lha3);
if (!msm_ipc_router_lookup_remote_port(
msg->srv.node_id, msg->srv.port_id)) {
rport_ptr = msm_ipc_router_create_remote_port(
msg->srv.node_id, msg->srv.port_id);
if (!rport_ptr) {
- mutex_unlock(&server_list_lock);
+ up_read(&routing_table_lock_lha3);
+ up_write(&server_list_lock_lha2);
return -ENOMEM;
}
+ rport_ptr->server = server;
rport_ptr->sec_rule = msm_ipc_get_security_rule(
msg->srv.service,
msg->srv.instance);
}
+ up_read(&routing_table_lock_lha3);
}
- mutex_unlock(&server_list_lock);
+ up_write(&server_list_lock_lha2);
/*
* Relay the new server message to other subsystems that do not belong
@@ -1758,7 +1644,7 @@
RR("o REMOVE_SERVER service=%08x:%d\n",
msg->srv.service, msg->srv.instance);
- mutex_lock(&server_list_lock);
+ down_write(&server_list_lock_lha2);
server = msm_ipc_router_lookup_server(msg->srv.service,
msg->srv.instance, msg->srv.node_id, msg->srv.port_id);
if (server) {
@@ -1772,7 +1658,7 @@
relay_msg(xprt_info, pkt);
post_control_ports(pkt);
}
- mutex_unlock(&server_list_lock);
+ up_write(&server_list_lock_lha2);
return 0;
}
@@ -1782,10 +1668,12 @@
struct msm_ipc_router_remote_port *rport_ptr;
RR("o REMOVE_CLIENT id=%d:%08x\n", msg->cli.node_id, msg->cli.port_id);
+ down_write(&routing_table_lock_lha3);
rport_ptr = msm_ipc_router_lookup_remote_port(msg->cli.node_id,
msg->cli.port_id);
if (rport_ptr)
msm_ipc_router_destroy_remote_port(rport_ptr);
+ up_write(&routing_table_lock_lha3);
relay_msg(xprt_info, pkt);
post_control_ports(pkt);
@@ -1920,19 +1808,19 @@
resume_tx_node_id = hdr->dst_node_id;
resume_tx_port_id = hdr->dst_port_id;
- rport_ptr = msm_ipc_router_lookup_remote_port(hdr->src_node_id,
- hdr->src_port_id);
-
- mutex_lock(&local_ports_lock);
+ down_read(&local_ports_lock_lha2);
port_ptr = msm_ipc_router_lookup_local_port(hdr->dst_port_id);
if (!port_ptr) {
pr_err("%s: No local port id %08x\n", __func__,
hdr->dst_port_id);
- mutex_unlock(&local_ports_lock);
+ up_read(&local_ports_lock_lha2);
release_pkt(pkt);
goto process_done;
}
+ down_read(&routing_table_lock_lha3);
+ rport_ptr = msm_ipc_router_lookup_remote_port(hdr->src_node_id,
+ hdr->src_port_id);
if (!rport_ptr) {
rport_ptr = msm_ipc_router_create_remote_port(
hdr->src_node_id,
@@ -1941,13 +1829,14 @@
pr_err("%s: Rmt Prt %08x:%08x create failed\n",
__func__, hdr->src_node_id,
hdr->src_port_id);
- mutex_unlock(&local_ports_lock);
+ up_read(&routing_table_lock_lha3);
+ up_read(&local_ports_lock_lha2);
goto process_done;
}
}
-
+ up_read(&routing_table_lock_lha3);
post_pkt_to_port(port_ptr, pkt, 0);
- mutex_unlock(&local_ports_lock);
+ up_read(&local_ports_lock_lha2);
process_done:
if (resume_tx) {
@@ -1983,13 +1872,13 @@
if (name->addrtype != MSM_IPC_ADDR_NAME)
return -EINVAL;
- mutex_lock(&server_list_lock);
+ down_write(&server_list_lock_lha2);
server = msm_ipc_router_lookup_server(name->addr.port_name.service,
name->addr.port_name.instance,
IPC_ROUTER_NID_LOCAL,
port_ptr->this_port.port_id);
if (server) {
- mutex_unlock(&server_list_lock);
+ up_write(&server_list_lock_lha2);
pr_err("%s: Server already present\n", __func__);
return -EINVAL;
}
@@ -2000,7 +1889,7 @@
port_ptr->this_port.port_id,
NULL);
if (!server) {
- mutex_unlock(&server_list_lock);
+ up_write(&server_list_lock_lha2);
pr_err("%s: Server Creation failed\n", __func__);
return -EINVAL;
}
@@ -2010,7 +1899,7 @@
ctl.srv.instance = server->name.instance;
ctl.srv.node_id = IPC_ROUTER_NID_LOCAL;
ctl.srv.port_id = port_ptr->this_port.port_id;
- mutex_unlock(&server_list_lock);
+ up_write(&server_list_lock_lha2);
broadcast_ctl_msg(&ctl);
spin_lock_irqsave(&port_ptr->port_lock, flags);
port_ptr->type = SERVER_PORT;
@@ -2042,13 +1931,13 @@
return -EINVAL;
}
- mutex_lock(&server_list_lock);
+ down_write(&server_list_lock_lha2);
server = msm_ipc_router_lookup_server(port_ptr->port_name.service,
port_ptr->port_name.instance,
port_ptr->this_port.node_id,
port_ptr->this_port.port_id);
if (!server) {
- mutex_unlock(&server_list_lock);
+ up_write(&server_list_lock_lha2);
pr_err("%s: Server lookup failed\n", __func__);
return -ENODEV;
}
@@ -2060,7 +1949,7 @@
ctl.srv.port_id = port_ptr->this_port.port_id;
msm_ipc_router_destroy_server(server, port_ptr->this_port.node_id,
port_ptr->this_port.port_id);
- mutex_unlock(&server_list_lock);
+ up_write(&server_list_lock_lha2);
broadcast_ctl_msg(&ctl);
spin_lock_irqsave(&port_ptr->port_lock, flags);
port_ptr->type = CLIENT_PORT;
@@ -2111,11 +2000,11 @@
hdr->dst_port_id = port_id;
pkt->length += IPC_ROUTER_HDR_SIZE;
- mutex_lock(&local_ports_lock);
+ down_read(&local_ports_lock_lha2);
port_ptr = msm_ipc_router_lookup_local_port(port_id);
if (!port_ptr) {
pr_err("%s: Local port %d not present\n", __func__, port_id);
- mutex_unlock(&local_ports_lock);
+ up_read(&local_ports_lock_lha2);
release_pkt(pkt);
return -ENODEV;
}
@@ -2123,7 +2012,7 @@
ret_len = pkt->length;
post_pkt_to_port(port_ptr, pkt, 0);
update_comm_mode_info(&src->mode_info, NULL);
- mutex_unlock(&local_ports_lock);
+ up_read(&local_ports_lock_lha2);
return ret_len;
}
@@ -2162,15 +2051,11 @@
hdr->dst_port_id = rport_ptr->port_id;
pkt->length += IPC_ROUTER_HDR_SIZE;
- mutex_lock(&rport_ptr->quota_lock);
- if (rport_ptr->restart_state != RESTART_NORMAL) {
- mutex_unlock(&rport_ptr->quota_lock);
- return -ENETRESET;
- }
+ mutex_lock(&rport_ptr->quota_lock_lhb2);
if (rport_ptr->tx_quota_cnt == IPC_ROUTER_DEFAULT_RX_QUOTA) {
if (msm_ipc_router_lookup_resume_tx_port(
rport_ptr, src->this_port.port_id)) {
- mutex_unlock(&rport_ptr->quota_lock);
+ mutex_unlock(&rport_ptr->quota_lock_lhb2);
return -EAGAIN;
}
resume_tx_port =
@@ -2179,7 +2064,7 @@
if (!resume_tx_port) {
pr_err("%s: Resume_Tx port allocation failed\n",
__func__);
- mutex_unlock(&rport_ptr->quota_lock);
+ mutex_unlock(&rport_ptr->quota_lock_lhb2);
return -ENOMEM;
}
INIT_LIST_HEAD(&resume_tx_port->list);
@@ -2187,29 +2072,26 @@
resume_tx_port->node_id = src->this_port.node_id;
list_add_tail(&resume_tx_port->list,
&rport_ptr->resume_tx_port_list);
- mutex_unlock(&rport_ptr->quota_lock);
+ mutex_unlock(&rport_ptr->quota_lock_lhb2);
return -EAGAIN;
}
rport_ptr->tx_quota_cnt++;
if (rport_ptr->tx_quota_cnt == IPC_ROUTER_DEFAULT_RX_QUOTA)
hdr->confirm_rx = 1;
- mutex_unlock(&rport_ptr->quota_lock);
+ mutex_unlock(&rport_ptr->quota_lock_lhb2);
- mutex_lock(&routing_table_lock);
rt_entry = lookup_routing_table(hdr->dst_node_id);
if (!rt_entry || !rt_entry->xprt_info) {
- mutex_unlock(&routing_table_lock);
pr_err("%s: Remote node %d not up\n",
__func__, hdr->dst_node_id);
return -ENODEV;
}
- mutex_lock(&rt_entry->lock);
+ down_read(&rt_entry->lock_lha4);
xprt_info = rt_entry->xprt_info;
- mutex_lock(&xprt_info->tx_lock);
+ mutex_lock(&xprt_info->tx_lock_lhb2);
ret = xprt_info->xprt->write(pkt, pkt->length, xprt_info->xprt);
- mutex_unlock(&xprt_info->tx_lock);
- mutex_unlock(&rt_entry->lock);
- mutex_unlock(&routing_table_lock);
+ mutex_unlock(&xprt_info->tx_lock_lhb2);
+ up_read(&rt_entry->lock_lha4);
if (ret < 0) {
pr_err("%s: Write on XPRT failed\n", __func__);
@@ -2265,13 +2147,13 @@
dst_node_id = dest->addr.port_addr.node_id;
dst_port_id = dest->addr.port_addr.port_id;
} else if (dest->addrtype == MSM_IPC_ADDR_NAME) {
- mutex_lock(&server_list_lock);
+ down_read(&server_list_lock_lha2);
server = msm_ipc_router_lookup_server(
dest->addr.port_name.service,
dest->addr.port_name.instance,
0, 0);
if (!server) {
- mutex_unlock(&server_list_lock);
+ up_read(&server_list_lock_lha2);
pr_err("%s: Destination not reachable\n", __func__);
return -ENODEV;
}
@@ -2280,16 +2162,18 @@
list);
dst_node_id = server_port->server_addr.node_id;
dst_port_id = server_port->server_addr.port_id;
- mutex_unlock(&server_list_lock);
+ up_read(&server_list_lock_lha2);
}
if (dst_node_id == IPC_ROUTER_NID_LOCAL) {
ret = loopback_data(src, dst_port_id, data);
return ret;
}
+ down_read(&routing_table_lock_lha3);
rport_ptr = msm_ipc_router_lookup_remote_port(dst_node_id,
dst_port_id);
if (!rport_ptr) {
+ up_read(&routing_table_lock_lha3);
pr_err("%s: Remote port not found\n", __func__);
return -ENODEV;
}
@@ -2297,6 +2181,7 @@
if (src->check_send_permissions) {
ret = src->check_send_permissions(rport_ptr->sec_rule);
if (ret <= 0) {
+ up_read(&routing_table_lock_lha3);
pr_err("%s: permission failure for %s\n",
__func__, current->comm);
return -EPERM;
@@ -2305,11 +2190,13 @@
pkt = create_pkt(data);
if (!pkt) {
+ up_read(&routing_table_lock_lha3);
pr_err("%s: Pkt creation failed\n", __func__);
return -ENOMEM;
}
ret = msm_ipc_router_write_pkt(src, rport_ptr, pkt);
+ up_read(&routing_table_lock_lha3);
release_pkt(pkt);
return ret;
@@ -2347,15 +2234,15 @@
if (!port_ptr || !data)
return -EINVAL;
- mutex_lock(&port_ptr->port_rx_q_lock);
+ mutex_lock(&port_ptr->port_rx_q_lock_lhb3);
if (list_empty(&port_ptr->port_rx_q)) {
- mutex_unlock(&port_ptr->port_rx_q_lock);
+ mutex_unlock(&port_ptr->port_rx_q_lock_lhb3);
return -EAGAIN;
}
pkt = list_first_entry(&port_ptr->port_rx_q, struct rr_packet, list);
if ((buf_len) && ((pkt->length - IPC_ROUTER_HDR_SIZE) > buf_len)) {
- mutex_unlock(&port_ptr->port_rx_q_lock);
+ mutex_unlock(&port_ptr->port_rx_q_lock_lhb3);
return -ETOOSMALL;
}
list_del(&pkt->list);
@@ -2364,7 +2251,7 @@
*data = pkt->pkt_fragment_q;
ret = pkt->length;
kfree(pkt);
- mutex_unlock(&port_ptr->port_rx_q_lock);
+ mutex_unlock(&port_ptr->port_rx_q_lock_lhb3);
return ret;
}
@@ -2384,9 +2271,9 @@
}
*data = NULL;
- mutex_lock(&port_ptr->port_rx_q_lock);
+ mutex_lock(&port_ptr->port_rx_q_lock_lhb3);
while (list_empty(&port_ptr->port_rx_q)) {
- mutex_unlock(&port_ptr->port_rx_q_lock);
+ mutex_unlock(&port_ptr->port_rx_q_lock_lhb3);
if (timeout < 0) {
ret = wait_event_interruptible(
port_ptr->port_rx_wait_q,
@@ -2403,9 +2290,9 @@
}
if (timeout == 0)
return -ETIMEDOUT;
- mutex_lock(&port_ptr->port_rx_q_lock);
+ mutex_lock(&port_ptr->port_rx_q_lock_lhb3);
}
- mutex_unlock(&port_ptr->port_rx_q_lock);
+ mutex_unlock(&port_ptr->port_rx_q_lock_lhb3);
ret = msm_ipc_router_read(port_ptr, data, 0);
if (ret <= 0 || !(*data))
@@ -2483,9 +2370,9 @@
return -EINVAL;
if (port_ptr->type == SERVER_PORT || port_ptr->type == CLIENT_PORT) {
- mutex_lock(&local_ports_lock);
+ down_write(&local_ports_lock_lha2);
list_del(&port_ptr->list);
- mutex_unlock(&local_ports_lock);
+ up_write(&local_ports_lock_lha2);
if (port_ptr->type == SERVER_PORT) {
msg.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
@@ -2510,25 +2397,25 @@
port_ptr->this_port.node_id,
port_ptr->this_port.port_id);
} else if (port_ptr->type == CONTROL_PORT) {
- mutex_lock(&control_ports_lock);
+ down_write(&control_ports_lock_lha5);
list_del(&port_ptr->list);
- mutex_unlock(&control_ports_lock);
+ up_write(&control_ports_lock_lha5);
} else if (port_ptr->type == IRSC_PORT) {
- mutex_lock(&local_ports_lock);
+ down_write(&local_ports_lock_lha2);
list_del(&port_ptr->list);
- mutex_unlock(&local_ports_lock);
+ up_write(&local_ports_lock_lha2);
signal_irsc_completion();
}
- mutex_lock(&port_ptr->port_rx_q_lock);
+ mutex_lock(&port_ptr->port_rx_q_lock_lhb3);
list_for_each_entry_safe(pkt, temp_pkt, &port_ptr->port_rx_q, list) {
list_del(&pkt->list);
release_pkt(pkt);
}
- mutex_unlock(&port_ptr->port_rx_q_lock);
+ mutex_unlock(&port_ptr->port_rx_q_lock_lhb3);
if (port_ptr->type == SERVER_PORT) {
- mutex_lock(&server_list_lock);
+ down_write(&server_list_lock_lha2);
server = msm_ipc_router_lookup_server(
port_ptr->port_name.service,
port_ptr->port_name.instance,
@@ -2538,7 +2425,7 @@
msm_ipc_router_destroy_server(server,
port_ptr->this_port.node_id,
port_ptr->this_port.port_id);
- mutex_unlock(&server_list_lock);
+ up_write(&server_list_lock_lha2);
}
wake_lock_destroy(&port_ptr->port_rx_wake_lock);
@@ -2554,13 +2441,13 @@
if (!port_ptr)
return -EINVAL;
- mutex_lock(&port_ptr->port_rx_q_lock);
+ mutex_lock(&port_ptr->port_rx_q_lock_lhb3);
if (!list_empty(&port_ptr->port_rx_q)) {
pkt = list_first_entry(&port_ptr->port_rx_q,
struct rr_packet, list);
rc = pkt->length;
}
- mutex_unlock(&port_ptr->port_rx_q_lock);
+ mutex_unlock(&port_ptr->port_rx_q_lock_lhb3);
return rc;
}
@@ -2570,13 +2457,13 @@
if (!port_ptr)
return -EINVAL;
- mutex_lock(&local_ports_lock);
+ down_write(&local_ports_lock_lha2);
list_del(&port_ptr->list);
- mutex_unlock(&local_ports_lock);
+ up_write(&local_ports_lock_lha2);
port_ptr->type = CONTROL_PORT;
- mutex_lock(&control_ports_lock);
+ down_write(&control_ports_lock_lha5);
list_add_tail(&port_ptr->list, &control_ports);
- mutex_unlock(&control_ports_lock);
+ up_write(&control_ports_lock_lha5);
return 0;
}
@@ -2600,7 +2487,7 @@
return -EINVAL;
}
- mutex_lock(&server_list_lock);
+ down_read(&server_list_lock_lha2);
if (!lookup_mask)
lookup_mask = 0xFFFFFFFF;
key = (srv_name->service & (SRV_HASH_SIZE - 1));
@@ -2623,7 +2510,7 @@
i++;
}
}
- mutex_unlock(&server_list_lock);
+ up_read(&server_list_lock_lha2);
return i;
}
@@ -2632,14 +2519,14 @@
{
struct msm_ipc_router_xprt_info *xprt_info, *tmp_xprt_info;
- mutex_lock(&xprt_info_list_lock);
+ down_write(&xprt_info_list_lock_lha5);
list_for_each_entry_safe(xprt_info, tmp_xprt_info,
&xprt_info_list, list) {
xprt_info->xprt->close(xprt_info->xprt);
list_del(&xprt_info->list);
kfree(xprt_info);
}
- mutex_unlock(&xprt_info_list_lock);
+ up_write(&xprt_info_list_lock_lha5);
return 0;
}
@@ -2650,9 +2537,9 @@
struct msm_ipc_routing_table_entry *rt_entry;
for (j = 0; j < RT_HASH_SIZE; j++) {
- mutex_lock(&routing_table_lock);
+ down_read(&routing_table_lock_lha3);
list_for_each_entry(rt_entry, &routing_table[j], list) {
- mutex_lock(&rt_entry->lock);
+ down_read(&rt_entry->lock_lha4);
i += scnprintf(buf + i, max - i,
"Node Id: 0x%08x\n", rt_entry->node_id);
if (rt_entry->node_id == IPC_ROUTER_NID_LOCAL) {
@@ -2669,9 +2556,9 @@
rt_entry->xprt_info->remote_node_id);
}
i += scnprintf(buf + i, max - i, "\n");
- mutex_unlock(&rt_entry->lock);
+ up_read(&rt_entry->lock_lha4);
}
- mutex_unlock(&routing_table_lock);
+ up_read(&routing_table_lock_lha3);
}
return i;
@@ -2682,7 +2569,7 @@
int i = 0;
struct msm_ipc_router_xprt_info *xprt_info;
- mutex_lock(&xprt_info_list_lock);
+ down_read(&xprt_info_list_lock_lha5);
list_for_each_entry(xprt_info, &xprt_info_list, list) {
i += scnprintf(buf + i, max - i, "XPRT Name: %s\n",
xprt_info->xprt->name);
@@ -2694,7 +2581,7 @@
xprt_info->remote_node_id);
i += scnprintf(buf + i, max - i, "\n");
}
- mutex_unlock(&xprt_info_list_lock);
+ up_read(&xprt_info_list_lock_lha5);
return i;
}
@@ -2705,7 +2592,7 @@
struct msm_ipc_server *server;
struct msm_ipc_server_port *server_port;
- mutex_lock(&server_list_lock);
+ down_read(&server_list_lock_lha2);
for (j = 0; j < SRV_HASH_SIZE; j++) {
list_for_each_entry(server, &server_list[j], list) {
list_for_each_entry(server_port,
@@ -2725,7 +2612,7 @@
}
}
}
- mutex_unlock(&server_list_lock);
+ up_read(&server_list_lock_lha2);
return i;
}
@@ -2737,9 +2624,9 @@
struct msm_ipc_routing_table_entry *rt_entry;
for (j = 0; j < RT_HASH_SIZE; j++) {
- mutex_lock(&routing_table_lock);
+ down_read(&routing_table_lock_lha3);
list_for_each_entry(rt_entry, &routing_table[j], list) {
- mutex_lock(&rt_entry->lock);
+ down_read(&rt_entry->lock_lha4);
for (k = 0; k < RP_HASH_SIZE; k++) {
list_for_each_entry(rport_ptr,
&rt_entry->remote_port_list[k],
@@ -2756,9 +2643,9 @@
i += scnprintf(buf + i, max - i, "\n");
}
}
- mutex_unlock(&rt_entry->lock);
+ up_read(&rt_entry->lock_lha4);
}
- mutex_unlock(&routing_table_lock);
+ up_read(&routing_table_lock_lha3);
}
return i;
@@ -2769,7 +2656,7 @@
int i = 0;
struct msm_ipc_port *port_ptr;
- mutex_lock(&control_ports_lock);
+ down_read(&control_ports_lock_lha5);
list_for_each_entry(port_ptr, &control_ports, list) {
i += scnprintf(buf + i, max - i, "Node_id: 0x%08x\n",
port_ptr->this_port.node_id);
@@ -2777,7 +2664,7 @@
port_ptr->this_port.port_id);
i += scnprintf(buf + i, max - i, "\n");
}
- mutex_unlock(&control_ports_lock);
+ up_read(&control_ports_lock_lha5);
return i;
}
@@ -2788,7 +2675,7 @@
unsigned long flags;
struct msm_ipc_port *port_ptr;
- mutex_lock(&local_ports_lock);
+ down_read(&local_ports_lock_lha2);
for (j = 0; j < LP_HASH_SIZE; j++) {
list_for_each_entry(port_ptr, &local_ports[j], list) {
spin_lock_irqsave(&port_ptr->port_lock, flags);
@@ -2808,7 +2695,7 @@
i += scnprintf(buf + i, max - i, "\n");
}
}
- mutex_unlock(&local_ports_lock);
+ up_read(&local_ports_lock_lha2);
return i;
}
@@ -2882,8 +2769,8 @@
xprt_info->initialized = 0;
xprt_info->remote_node_id = -1;
INIT_LIST_HEAD(&xprt_info->pkt_list);
- mutex_init(&xprt_info->rx_lock);
- mutex_init(&xprt_info->tx_lock);
+ mutex_init(&xprt_info->rx_lock_lhb2);
+ mutex_init(&xprt_info->tx_lock_lhb2);
wake_lock_init(&xprt_info->wakelock,
WAKE_LOCK_SUSPEND, xprt->name);
xprt_info->need_len = 0;
@@ -2902,18 +2789,18 @@
xprt_info->initialized = 1;
}
- mutex_lock(&xprt_info_list_lock);
+ down_write(&xprt_info_list_lock_lha5);
list_add_tail(&xprt_info->list, &xprt_info_list);
- mutex_unlock(&xprt_info_list_lock);
+ up_write(&xprt_info_list_lock_lha5);
- mutex_lock(&routing_table_lock);
+ down_write(&routing_table_lock_lha3);
if (!routing_table_inited) {
init_routing_table();
rt_entry = alloc_routing_table_entry(IPC_ROUTER_NID_LOCAL);
add_routing_table_entry(rt_entry);
routing_table_inited = 1;
}
- mutex_unlock(&routing_table_lock);
+ up_write(&routing_table_lock_lha3);
xprt->priv = xprt_info;
@@ -2927,13 +2814,13 @@
if (xprt && xprt->priv) {
xprt_info = xprt->priv;
- mutex_lock(&xprt_info->rx_lock);
+ mutex_lock(&xprt_info->rx_lock_lhb2);
xprt_info->abort_data_read = 1;
- mutex_unlock(&xprt_info->rx_lock);
+ mutex_unlock(&xprt_info->rx_lock_lhb2);
- mutex_lock(&xprt_info_list_lock);
+ down_write(&xprt_info_list_lock_lha5);
list_del(&xprt_info->list);
- mutex_unlock(&xprt_info_list_lock);
+ up_write(&xprt_info_list_lock_lha5);
flush_workqueue(xprt_info->workqueue);
destroy_workqueue(xprt_info->workqueue);
@@ -2964,7 +2851,7 @@
struct msm_ipc_router_xprt_work *xprt_work =
container_of(work, struct msm_ipc_router_xprt_work, work);
- modem_reset_cleanup(xprt_work->xprt->priv);
+ msm_ipc_cleanup_routing_table(xprt_work->xprt->priv);
msm_ipc_router_remove_xprt(xprt_work->xprt);
if (atomic_dec_return(&pending_close_count) == 0)
@@ -3034,10 +2921,10 @@
if (!pkt)
return;
- mutex_lock(&xprt_info->rx_lock);
+ mutex_lock(&xprt_info->rx_lock_lhb2);
list_add_tail(&pkt->list, &xprt_info->pkt_list);
wake_lock(&xprt_info->wakelock);
- mutex_unlock(&xprt_info->rx_lock);
+ mutex_unlock(&xprt_info->rx_lock_lhb2);
queue_work(xprt_info->workqueue, &xprt_info->read_data);
}
@@ -3105,14 +2992,14 @@
for (i = 0; i < LP_HASH_SIZE; i++)
INIT_LIST_HEAD(&local_ports[i]);
- mutex_lock(&routing_table_lock);
+ down_write(&routing_table_lock_lha3);
if (!routing_table_inited) {
init_routing_table();
rt_entry = alloc_routing_table_entry(IPC_ROUTER_NID_LOCAL);
add_routing_table_entry(rt_entry);
routing_table_inited = 1;
}
- mutex_unlock(&routing_table_lock);
+ up_write(&routing_table_lock_lha3);
init_waitqueue_head(&subsystem_restart_wait);
ret = msm_ipc_router_init_sockets();
diff --git a/arch/arm/mach-msm/ipc_router.h b/arch/arm/mach-msm/ipc_router.h
index 32832dd..502cac1 100644
--- a/arch/arm/mach-msm/ipc_router.h
+++ b/arch/arm/mach-msm/ipc_router.h
@@ -107,7 +107,6 @@
struct msm_ipc_sock {
struct sock sk;
struct msm_ipc_port *port;
- void *default_pil;
};
struct msm_ipc_router_xprt {
@@ -159,15 +158,4 @@
void msm_ipc_sync_default_sec_rule(void *rule);
-#if defined CONFIG_MSM_IPC_ROUTER_SMD_XPRT
-extern void *msm_ipc_load_default_node(void);
-
-extern void msm_ipc_unload_default_node(void *pil);
-#else
-static inline void *msm_ipc_load_default_node(void)
-{ return NULL; }
-
-static inline void msm_ipc_unload_default_node(void *pil) { }
-#endif
-
#endif
diff --git a/arch/arm/mach-msm/ipc_router_smd_xprt.c b/arch/arm/mach-msm/ipc_router_smd_xprt.c
index b2ec816..c7c2298 100644
--- a/arch/arm/mach-msm/ipc_router_smd_xprt.c
+++ b/arch/arm/mach-msm/ipc_router_smd_xprt.c
@@ -475,31 +475,6 @@
return 0;
}
-void *msm_ipc_load_default_node(void)
-{
- void *pil = NULL;
- const char *peripheral;
-
- peripheral = smd_edge_to_subsystem(SMD_APPS_MODEM);
- if (peripheral && !strncmp(peripheral, "modem", 6)) {
- pil = subsystem_get(peripheral);
- if (IS_ERR(pil)) {
- pr_err("%s: Failed to load %s\n",
- __func__, peripheral);
- pil = NULL;
- }
- }
- return pil;
-}
-EXPORT_SYMBOL(msm_ipc_load_default_node);
-
-void msm_ipc_unload_default_node(void *pil)
-{
- if (pil)
- subsystem_put(pil);
-}
-EXPORT_SYMBOL(msm_ipc_unload_default_node);
-
static struct platform_driver msm_ipc_router_smd_remote_driver[] = {
{
.probe = msm_ipc_router_smd_remote_probe,
diff --git a/arch/arm/mach-msm/ipc_socket.c b/arch/arm/mach-msm/ipc_socket.c
index 64d8fed..3409867 100644
--- a/arch/arm/mach-msm/ipc_socket.c
+++ b/arch/arm/mach-msm/ipc_socket.c
@@ -55,6 +55,10 @@
} \
} while (0) \
+#ifndef SIZE_MAX
+#define SIZE_MAX ((size_t)-1)
+#endif
+
static int sockets_enabled;
static struct proto msm_ipc_proto;
static const struct proto_ops msm_ipc_proto_ops;
@@ -264,7 +268,6 @@
{
struct sock *sk;
struct msm_ipc_port *port_ptr;
- void *pil;
if (unlikely(protocol != 0)) {
pr_err("%s: Protocol not supported\n", __func__);
@@ -297,9 +300,7 @@
sock_init_data(sock, sk);
sk->sk_rcvtimeo = DEFAULT_RCV_TIMEO;
- pil = msm_ipc_load_default_node();
msm_ipc_sk(sk)->port = port_ptr;
- msm_ipc_sk(sk)->default_pil = pil;
return 0;
}
@@ -407,9 +408,9 @@
lock_sock(sk);
timeout = sk->sk_rcvtimeo;
- mutex_lock(&port_ptr->port_rx_q_lock);
+ mutex_lock(&port_ptr->port_rx_q_lock_lhb3);
while (list_empty(&port_ptr->port_rx_q)) {
- mutex_unlock(&port_ptr->port_rx_q_lock);
+ mutex_unlock(&port_ptr->port_rx_q_lock_lhb3);
release_sock(sk);
if (timeout < 0) {
ret = wait_event_interruptible(
@@ -431,9 +432,9 @@
return 0;
}
lock_sock(sk);
- mutex_lock(&port_ptr->port_rx_q_lock);
+ mutex_lock(&port_ptr->port_rx_q_lock_lhb3);
}
- mutex_unlock(&port_ptr->port_rx_q_lock);
+ mutex_unlock(&port_ptr->port_rx_q_lock_lhb3);
ret = msm_ipc_router_read(port_ptr, &msg, buf_len);
if (ret <= 0 || !msg) {
@@ -458,7 +459,8 @@
struct msm_ipc_port *port_ptr;
struct server_lookup_args server_arg;
struct msm_ipc_server_info *srv_info = NULL;
- unsigned int n, srv_info_sz = 0;
+ unsigned int n;
+ size_t srv_info_sz = 0;
int ret;
if (!sk)
@@ -499,16 +501,16 @@
break;
}
if (server_arg.num_entries_in_array) {
- srv_info_sz = server_arg.num_entries_in_array *
- sizeof(*srv_info);
- if ((srv_info_sz / sizeof(*srv_info)) !=
- server_arg.num_entries_in_array) {
+ if (server_arg.num_entries_in_array >
+ (SIZE_MAX / sizeof(*srv_info))) {
pr_err("%s: Integer Overflow %d * %d\n",
__func__, sizeof(*srv_info),
server_arg.num_entries_in_array);
ret = -EINVAL;
break;
}
+ srv_info_sz = server_arg.num_entries_in_array *
+ sizeof(*srv_info);
srv_info = kmalloc(srv_info_sz, GFP_KERNEL);
if (!srv_info) {
ret = -ENOMEM;
@@ -580,12 +582,10 @@
{
struct sock *sk = sock->sk;
struct msm_ipc_port *port_ptr = msm_ipc_sk_port(sk);
- void *pil = msm_ipc_sk(sk)->default_pil;
int ret;
lock_sock(sk);
ret = msm_ipc_router_close_port(port_ptr);
- msm_ipc_unload_default_node(pil);
release_sock(sk);
sock_put(sk);
sock->sk = NULL;
diff --git a/arch/arm/mach-msm/mdm2.c b/arch/arm/mach-msm/mdm2.c
index c8d6d5a..e43a0e27 100644
--- a/arch/arm/mach-msm/mdm2.c
+++ b/arch/arm/mach-msm/mdm2.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -28,6 +28,7 @@
#include <linux/debugfs.h>
#include <linux/completion.h>
#include <linux/workqueue.h>
+#include <linux/clk.h>
#include <linux/mfd/pmic8058.h>
#include <asm/mach-types.h>
#include <asm/uaccess.h>
@@ -38,26 +39,24 @@
#include <linux/msm_charm.h>
#include "msm_watchdog.h"
#include "devices.h"
+#include "clock.h"
#include "mdm_private.h"
#define MDM_PBLRDY_CNT 20
static int mdm_debug_mask;
-static int power_on_count;
-static int hsic_peripheral_status;
-static DEFINE_MUTEX(hsic_status_lock);
static void mdm_peripheral_connect(struct mdm_modem_drv *mdm_drv)
{
if (!mdm_drv->pdata->peripheral_platform_device)
return;
- mutex_lock(&hsic_status_lock);
- if (hsic_peripheral_status)
+ mutex_lock(&mdm_drv->peripheral_status_lock);
+ if (mdm_drv->peripheral_status)
goto out;
platform_device_add(mdm_drv->pdata->peripheral_platform_device);
- hsic_peripheral_status = 1;
+ mdm_drv->peripheral_status = 1;
out:
- mutex_unlock(&hsic_status_lock);
+ mutex_unlock(&mdm_drv->peripheral_status_lock);
}
static void mdm_peripheral_disconnect(struct mdm_modem_drv *mdm_drv)
@@ -65,13 +64,13 @@
if (!mdm_drv->pdata->peripheral_platform_device)
return;
- mutex_lock(&hsic_status_lock);
- if (!hsic_peripheral_status)
+ mutex_lock(&mdm_drv->peripheral_status_lock);
+ if (!mdm_drv->peripheral_status)
goto out;
platform_device_del(mdm_drv->pdata->peripheral_platform_device);
- hsic_peripheral_status = 0;
+ mdm_drv->peripheral_status = 0;
out:
- mutex_unlock(&hsic_status_lock);
+ mutex_unlock(&mdm_drv->peripheral_status_lock);
}
/* This function can be called from atomic context. */
@@ -112,8 +111,8 @@
for (i = 20; i > 0; i--) {
if (gpio_get_value(mdm_drv->mdm2ap_status_gpio) == 0) {
if (mdm_debug_mask & MDM_DEBUG_MASK_SHDN_LOG)
- pr_info("%s: mdm2ap_status went low, i = %d\n",
- __func__, i);
+ pr_debug("%s:id %d: mdm2ap_statuswent low, i=%d\n",
+ __func__, mdm_drv->device_id, i);
break;
}
msleep(100);
@@ -123,8 +122,10 @@
gpio_direction_output(mdm_drv->ap2mdm_soft_reset_gpio,
soft_reset_direction);
if (i == 0) {
- pr_err("%s: MDM2AP_STATUS never went low. Doing a hard reset\n",
- __func__);
+ pr_debug("%s:id %d: MDM2AP_STATUS never went low. Doing a hard reset\n",
+ __func__, mdm_drv->device_id);
+ gpio_direction_output(mdm_drv->ap2mdm_soft_reset_gpio,
+ soft_reset_direction);
/*
* Currently, there is a debounce timer on the charm PMIC. It is
* necessary to hold the PMIC RESET low for ~3.5 seconds
@@ -139,13 +140,14 @@
{
int i;
int pblrdy;
- if (power_on_count != 1) {
- pr_err("%s: Calling fn when power_on_count != 1\n",
- __func__);
+ if (mdm_drv->power_on_count != 1) {
+ pr_debug("%s:id %d: Calling fn when power_on_count != 1\n",
+ __func__, mdm_drv->device_id);
return;
}
- pr_err("%s: Powering on modem for the first time\n", __func__);
+ pr_debug("%s:id %d: Powering on modem for the first time\n",
+ __func__, mdm_drv->device_id);
mdm_peripheral_disconnect(mdm_drv);
/* If this is the first power-up after a panic, the modem may still
@@ -159,13 +161,15 @@
/* Pull AP2MDM_KPDPWR gpio high and wait for PS_HOLD to settle,
* then pull it back low.
*/
- pr_debug("%s: Pulling AP2MDM_KPDPWR gpio high\n", __func__);
+ pr_debug("%s:id %d: Pulling AP2MDM_KPDPWR gpio high\n",
+ __func__, mdm_drv->device_id);
gpio_direction_output(mdm_drv->ap2mdm_kpdpwr_n_gpio, 1);
gpio_direction_output(mdm_drv->ap2mdm_status_gpio, 1);
msleep(1000);
gpio_direction_output(mdm_drv->ap2mdm_kpdpwr_n_gpio, 0);
- } else
+ } else {
gpio_direction_output(mdm_drv->ap2mdm_status_gpio, 1);
+ }
if (!GPIO_IS_VALID(mdm_drv->mdm2ap_pblrdy))
goto start_mdm_peripheral;
@@ -176,7 +180,8 @@
break;
usleep_range(5000, 5000);
}
- pr_debug("%s: i:%d\n", __func__, i);
+ pr_debug("%s: id %d: pblrdy i:%d\n", __func__,
+ mdm_drv->device_id, i);
start_mdm_peripheral:
mdm_peripheral_connect(mdm_drv);
@@ -188,7 +193,8 @@
int i;
int pblrdy;
- pr_err("%s: soft resetting mdm modem\n", __func__);
+ pr_debug("%s: id %d: soft resetting mdm modem\n",
+ __func__, mdm_drv->device_id);
mdm_peripheral_disconnect(mdm_drv);
mdm_toggle_soft_reset(mdm_drv);
@@ -202,7 +208,8 @@
usleep_range(5000, 5000);
}
- pr_debug("%s: i:%d\n", __func__, i);
+ pr_debug("%s: id %d: pblrdy i:%d\n", __func__,
+ mdm_drv->device_id, i);
start_mdm_peripheral:
mdm_peripheral_connect(mdm_drv);
@@ -211,7 +218,7 @@
static void mdm_power_on_common(struct mdm_modem_drv *mdm_drv)
{
- power_on_count++;
+ mdm_drv->power_on_count++;
/* this gpio will be used to indicate apq readiness,
* de-assert it now so that it can be asserted later.
@@ -226,10 +233,10 @@
* user space but we're already powered on. Ignore it.
*/
if (mdm_drv->pdata->early_power_on &&
- (power_on_count == 2))
+ (mdm_drv->power_on_count == 2))
return;
- if (power_on_count == 1)
+ if (mdm_drv->power_on_count == 1)
mdm_do_first_power_on(mdm_drv);
else
mdm_do_soft_power_on(mdm_drv);
@@ -242,7 +249,8 @@
static void mdm_status_changed(struct mdm_modem_drv *mdm_drv, int value)
{
- pr_debug("%s: value:%d\n", __func__, value);
+ pr_debug("%s: id %d: value:%d\n", __func__,
+ value, mdm_drv->device_id);
if (value) {
mdm_peripheral_disconnect(mdm_drv);
@@ -256,13 +264,15 @@
{
switch (type) {
case APQ_CONTROLLED_UPGRADE:
- pr_debug("%s APQ controlled modem image upgrade\n", __func__);
- mdm_drv->mdm_ready = 0;
+ pr_debug("%s: id %d: APQ controlled modem image upgrade\n",
+ __func__, mdm_drv->device_id);
+ atomic_set(&mdm_drv->mdm_ready, 0);
mdm_toggle_soft_reset(mdm_drv);
break;
case MDM_CONTROLLED_UPGRADE:
- pr_debug("%s MDM controlled modem image upgrade\n", __func__);
- mdm_drv->mdm_ready = 0;
+ pr_debug("%s: id %d: MDM controlled modem image upgrade\n",
+ __func__, mdm_drv->device_id);
+ atomic_set(&mdm_drv->mdm_ready, 0);
/*
* If we have no image currently present on the modem, then we
* would be in PBL, in which case the status gpio would not go
@@ -270,15 +280,19 @@
*/
mdm_drv->disable_status_check = 1;
if (GPIO_IS_VALID(mdm_drv->usb_switch_gpio)) {
- pr_info("%s Switching usb control to MDM\n", __func__);
+ pr_debug("%s: id %d: Switching usb control to MDM\n",
+ __func__, mdm_drv->device_id);
gpio_direction_output(mdm_drv->usb_switch_gpio, 1);
} else
- pr_err("%s usb switch gpio unavailable\n", __func__);
+ pr_err("%s: id %d: usb switch gpio unavailable\n",
+ __func__, mdm_drv->device_id);
break;
default:
- pr_err("%s invalid upgrade type\n", __func__);
+ pr_err("%s: id %d: invalid upgrade type\n",
+ __func__, mdm_drv->device_id);
}
}
+
static struct mdm_ops mdm_cb = {
.power_on_mdm_cb = mdm_power_on_common,
.reset_mdm_cb = mdm_power_on_common,
@@ -289,44 +303,10 @@
.image_upgrade_cb = mdm_image_upgrade,
};
-static int __init mdm_modem_probe(struct platform_device *pdev)
+int mdm_get_ops(struct mdm_ops **mdm_ops)
{
- return mdm_common_create(pdev, &mdm_cb);
+ *mdm_ops = &mdm_cb;
+ return 0;
}
-static int __devexit mdm_modem_remove(struct platform_device *pdev)
-{
- return mdm_common_modem_remove(pdev);
-}
-static void mdm_modem_shutdown(struct platform_device *pdev)
-{
- mdm_common_modem_shutdown(pdev);
-}
-
-static struct platform_driver mdm_modem_driver = {
- .remove = mdm_modem_remove,
- .shutdown = mdm_modem_shutdown,
- .driver = {
- .name = "mdm2_modem",
- .owner = THIS_MODULE
- },
-};
-
-static int __init mdm_modem_init(void)
-{
- return platform_driver_probe(&mdm_modem_driver, mdm_modem_probe);
-}
-
-static void __exit mdm_modem_exit(void)
-{
- platform_driver_unregister(&mdm_modem_driver);
-}
-
-module_init(mdm_modem_init);
-module_exit(mdm_modem_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("mdm modem driver");
-MODULE_VERSION("2.0");
-MODULE_ALIAS("mdm_modem");
diff --git a/arch/arm/mach-msm/mdm_common.c b/arch/arm/mach-msm/mdm_common.c
index de46be8..5e12a0d 100644
--- a/arch/arm/mach-msm/mdm_common.c
+++ b/arch/arm/mach-msm/mdm_common.c
@@ -49,22 +49,15 @@
#define MDM_RDUMP_TIMEOUT 120000L
#define MDM2AP_STATUS_TIMEOUT_MS 60000L
-static unsigned int mdm_debug_mask;
-static struct workqueue_struct *mdm_queue;
-static struct workqueue_struct *mdm_sfr_queue;
-static unsigned int dump_timeout_ms;
-static int vddmin_gpios_sent;
-
+/* Allow a maximum device id of this many digits */
+#define MAX_DEVICE_DIGITS 10
#define EXTERNAL_MODEM "external_modem"
+#define SUBSYS_NAME_LENGTH \
+ (sizeof(EXTERNAL_MODEM) + MAX_DEVICE_DIGITS)
-static struct mdm_modem_drv *mdm_drv;
-static struct subsys_device *mdm_subsys_dev;
-
-DECLARE_COMPLETION(mdm_needs_reload);
-DECLARE_COMPLETION(mdm_boot);
-DECLARE_COMPLETION(mdm_ram_dumps);
-
-static int first_boot = 1;
+#define DEVICE_BASE_NAME "mdm"
+#define DEVICE_NAME_LENGTH \
+ (sizeof(DEVICE_BASE_NAME) + MAX_DEVICE_DIGITS)
#define RD_BUF_SIZE 100
#define SFR_MAX_RETRIES 10
@@ -74,58 +67,211 @@
GPIO_UPDATE_BOOTING_CONFIG = 1,
GPIO_UPDATE_RUNNING_CONFIG,
};
-static int mdm2ap_status_valid_old_config;
-static struct gpiomux_setting mdm2ap_status_old_config;
+
+struct mdm_device {
+ struct list_head link;
+ struct mdm_modem_drv mdm_data;
+
+ int mdm2ap_status_valid_old_config;
+ struct gpiomux_setting mdm2ap_status_old_config;
+ int first_boot;
+ struct workqueue_struct *mdm_queue;
+ struct workqueue_struct *mdm_sfr_queue;
+ unsigned int dump_timeout_ms;
+
+ char subsys_name[SUBSYS_NAME_LENGTH];
+ struct subsys_desc mdm_subsys;
+ struct subsys_device *mdm_subsys_dev;
+
+ char device_name[DEVICE_NAME_LENGTH];
+ struct miscdevice misc_device;
+
+ struct completion mdm_needs_reload;
+ struct completion mdm_boot;
+ struct completion mdm_ram_dumps;
+ int mdm_errfatal_irq;
+ int mdm_status_irq;
+ int mdm_pblrdy_irq;
+
+ struct delayed_work mdm2ap_status_check_work;
+ struct work_struct mdm_status_work;
+ struct work_struct sfr_reason_work;
+
+ struct notifier_block mdm_panic_blk;
+
+ int ssr_started_internally;
+};
+
+static struct list_head mdm_devices;
+static DEFINE_SPINLOCK(mdm_devices_lock);
+
+static int ssr_count;
+static DEFINE_SPINLOCK(ssr_lock);
+
+static unsigned int mdm_debug_mask;
+int vddmin_gpios_sent;
+static struct mdm_ops *mdm_ops;
+
+static void mdm_device_list_add(struct mdm_device *mdev)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&mdm_devices_lock, flags);
+ list_add_tail(&mdev->link, &mdm_devices);
+ spin_unlock_irqrestore(&mdm_devices_lock, flags);
+}
+
+static void mdm_device_list_remove(struct mdm_device *mdev)
+{
+ unsigned long flags;
+ struct mdm_device *lmdev, *tmp;
+
+ spin_lock_irqsave(&mdm_devices_lock, flags);
+ list_for_each_entry_safe(lmdev, tmp, &mdm_devices, link) {
+ if (mdev && mdev == lmdev) {
+ pr_debug("%s: removing device id %d\n",
+ __func__, mdev->mdm_data.device_id);
+ list_del(&mdev->link);
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&mdm_devices_lock, flags);
+}
+
+/* If the platform's cascading_ssr flag is set, the subsystem
+ * restart module will restart the other modems so stop
+ * monitoring them as well.
+ * This function can be called from interrupt context.
+ */
+static void mdm_start_ssr(struct mdm_device *mdev)
+{
+ unsigned long flags;
+ int start_ssr = 1;
+
+ spin_lock_irqsave(&ssr_lock, flags);
+ if (mdev->mdm_data.pdata->cascading_ssr &&
+ ssr_count > 0) {
+ start_ssr = 0;
+ } else {
+ ssr_count++;
+ mdev->ssr_started_internally = 1;
+ }
+ spin_unlock_irqrestore(&ssr_lock, flags);
+
+ if (start_ssr) {
+ atomic_set(&mdev->mdm_data.mdm_ready, 0);
+ pr_debug("%s: Resetting mdm id %d due to mdm error\n",
+ __func__, mdev->mdm_data.device_id);
+ subsystem_restart_dev(mdev->mdm_subsys_dev);
+ } else {
+ pr_debug("%s: Another modem is already in SSR\n",
+ __func__);
+ }
+}
+
+/* Increment the reference count to handle the case where
+ * subsystem restart is initiated by the SSR service.
+ */
+static void mdm_ssr_started(struct mdm_device *mdev)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ssr_lock, flags);
+ ssr_count++;
+ atomic_set(&mdev->mdm_data.mdm_ready, 0);
+ spin_unlock_irqrestore(&ssr_lock, flags);
+}
+
+/* mdm_ssr_completed assumes that mdm_ssr_started has previously
+ * been called.
+ */
+static void mdm_ssr_completed(struct mdm_device *mdev)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ssr_lock, flags);
+ ssr_count--;
+ if (mdev->ssr_started_internally) {
+ mdev->ssr_started_internally = 0;
+ ssr_count--;
+ }
+
+ if (ssr_count < 0) {
+ pr_err("%s: ssr_count = %d\n",
+ __func__, ssr_count);
+ panic("%s: ssr_count = %d < 0\n",
+ __func__, ssr_count);
+ }
+ spin_unlock_irqrestore(&ssr_lock, flags);
+}
static irqreturn_t mdm_vddmin_change(int irq, void *dev_id)
{
- int value = gpio_get_value(
- mdm_drv->pdata->vddmin_resource->mdm2ap_vddmin_gpio);
+ struct mdm_device *mdev = (struct mdm_device *)dev_id;
+ struct mdm_vddmin_resource *vddmin_res;
+ int value;
+ if (!mdev)
+ goto handled;
+
+ vddmin_res = mdev->mdm_data.pdata->vddmin_resource;
+ if (!vddmin_res)
+ goto handled;
+
+ value = gpio_get_value(
+ vddmin_res->mdm2ap_vddmin_gpio);
if (value == 0)
- pr_info("External Modem entered Vddmin\n");
+ pr_debug("External Modem id %d entered Vddmin\n",
+ mdev->mdm_data.device_id);
else
- pr_info("External Modem exited Vddmin\n");
-
+ pr_debug("External Modem id %d exited Vddmin\n",
+ mdev->mdm_data.device_id);
+handled:
return IRQ_HANDLED;
}
+/* The vddmin_res resource may not be supported by some platforms. */
static void mdm_setup_vddmin_gpios(void)
{
+ unsigned long flags;
struct msm_rpm_iv_pair req;
+ struct mdm_device *mdev;
struct mdm_vddmin_resource *vddmin_res;
int irq, ret;
- /* This resource may not be supported by some platforms. */
- vddmin_res = mdm_drv->pdata->vddmin_resource;
- if (!vddmin_res)
- return;
+ spin_lock_irqsave(&mdm_devices_lock, flags);
+ list_for_each_entry(mdev, &mdm_devices, link) {
+ vddmin_res = mdev->mdm_data.pdata->vddmin_resource;
+ if (!vddmin_res)
+ continue;
- pr_info("Enabling vddmin logging\n");
- req.id = vddmin_res->rpm_id;
- req.value = ((uint32_t)vddmin_res->ap2mdm_vddmin_gpio & 0x0000FFFF)
- << 16;
- req.value |= ((uint32_t)vddmin_res->modes & 0x000000FF) << 8;
- req.value |= (uint32_t)vddmin_res->drive_strength & 0x000000FF;
+ pr_debug("Enabling vddmin logging on modem id %d\n",
+ mdev->mdm_data.device_id);
+ req.id = vddmin_res->rpm_id;
+ req.value =
+ ((uint32_t)vddmin_res->ap2mdm_vddmin_gpio & 0x0000FFFF)
+ << 16;
+ req.value |= ((uint32_t)vddmin_res->modes & 0x000000FF) << 8;
+ req.value |= (uint32_t)vddmin_res->drive_strength & 0x000000FF;
- msm_rpm_set(MSM_RPM_CTX_SET_0, &req, 1);
+ msm_rpm_set(MSM_RPM_CTX_SET_0, &req, 1);
- /* Start monitoring low power gpio from mdm */
- irq = MSM_GPIO_TO_INT(vddmin_res->mdm2ap_vddmin_gpio);
- if (irq < 0) {
- pr_err("%s: could not get LPM POWER IRQ resource.\n",
- __func__);
- goto error_end;
+ /* Start monitoring low power gpio from mdm */
+ irq = gpio_to_irq(vddmin_res->mdm2ap_vddmin_gpio);
+ if (irq < 0)
+ pr_err("%s: could not get LPM POWER IRQ resource mdm id %d.\n",
+ __func__, mdev->mdm_data.device_id);
+ else {
+ ret = request_threaded_irq(irq, NULL, mdm_vddmin_change,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+ "mdm lpm", mdev);
+
+ if (ret < 0)
+ pr_err("%s: MDM LPM IRQ#%d request failed with error=%d",
+ __func__, irq, ret);
+ }
}
-
- ret = request_threaded_irq(irq, NULL, mdm_vddmin_change,
- IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
- "mdm lpm", NULL);
-
- if (ret < 0)
- pr_err("%s: MDM LPM IRQ#%d request failed with error=%d",
- __func__, irq, ret);
-error_end:
+ spin_unlock_irqrestore(&mdm_devices_lock, flags);
return;
}
@@ -133,48 +279,53 @@
{
int ret, ntries = 0;
char sfr_buf[RD_BUF_SIZE];
+ struct mdm_platform_data *pdata;
+ struct mdm_device *mdev = container_of(work,
+ struct mdm_device, sfr_reason_work);
- do {
- msleep(SFR_RETRY_INTERVAL);
- ret = sysmon_get_reason(SYSMON_SS_EXT_MODEM,
+ pdata = mdev->mdm_data.pdata;
+ if (pdata->sysmon_subsys_id_valid) {
+ do {
+ ret = sysmon_get_reason(pdata->sysmon_subsys_id,
sfr_buf, sizeof(sfr_buf));
- if (ret) {
- /*
- * The sysmon device may not have been probed as yet
- * after the restart.
+ if (!ret) {
+ pr_err("mdm restart reason: %s\n", sfr_buf);
+ return;
+ }
+ /* Wait for the modem to be fully booted after a
+ * subsystem restart. This may take several seconds.
*/
- pr_err("%s: Error retrieving mdm restart reason, ret = %d, "
- "%d/%d tries\n", __func__, ret,
- ntries + 1, SFR_MAX_RETRIES);
- } else {
- pr_err("mdm restart reason: %s\n", sfr_buf);
- break;
- }
- } while (++ntries < SFR_MAX_RETRIES);
+ msleep(SFR_RETRY_INTERVAL);
+ } while (++ntries < SFR_MAX_RETRIES);
+ pr_debug("%s: Error retrieving restart reason: %d\n",
+ __func__, ret);
+ }
}
-static DECLARE_WORK(sfr_reason_work, mdm_restart_reason_fn);
-
static void mdm2ap_status_check(struct work_struct *work)
{
+ struct mdm_device *mdev =
+ container_of(work, struct mdm_device,
+ mdm2ap_status_check_work.work);
+ struct mdm_modem_drv *mdm_drv = &mdev->mdm_data;
/*
* If the mdm modem did not pull the MDM2AP_STATUS gpio
* high then call subsystem_restart.
*/
if (!mdm_drv->disable_status_check) {
if (gpio_get_value(mdm_drv->mdm2ap_status_gpio) == 0) {
- pr_err("%s: MDM2AP_STATUS gpio did not go high\n",
- __func__);
- mdm_drv->mdm_ready = 0;
- subsystem_restart_dev(mdm_subsys_dev);
+ pr_debug("%s: MDM2AP_STATUS did not go high on mdm id %d\n",
+ __func__, mdev->mdm_data.device_id);
+ mdm_start_ssr(mdev);
}
}
}
-static DECLARE_DELAYED_WORK(mdm2ap_status_check_work, mdm2ap_status_check);
-
-static void mdm_update_gpio_configs(enum gpio_update_config gpio_config)
+static void mdm_update_gpio_configs(struct mdm_device *mdev,
+ enum gpio_update_config gpio_config)
{
+ struct mdm_modem_drv *mdm_drv = &mdev->mdm_data;
+
/* Some gpio configuration may need updating after modem bootup.*/
switch (gpio_config) {
case GPIO_UPDATE_RUNNING_CONFIG:
@@ -182,20 +333,20 @@
if (msm_gpiomux_write(mdm_drv->mdm2ap_status_gpio,
GPIOMUX_ACTIVE,
mdm_drv->pdata->mdm2ap_status_gpio_run_cfg,
- &mdm2ap_status_old_config))
- pr_err("%s: failed updating running gpio config\n",
- __func__);
+ &mdev->mdm2ap_status_old_config))
+ pr_err("%s: failed updating running gpio config mdm id %d\n",
+ __func__, mdev->mdm_data.device_id);
else
- mdm2ap_status_valid_old_config = 1;
+ mdev->mdm2ap_status_valid_old_config = 1;
}
break;
case GPIO_UPDATE_BOOTING_CONFIG:
- if (mdm2ap_status_valid_old_config) {
+ if (mdev->mdm2ap_status_valid_old_config) {
msm_gpiomux_write(mdm_drv->mdm2ap_status_gpio,
GPIOMUX_ACTIVE,
- &mdm2ap_status_old_config,
+ &mdev->mdm2ap_status_old_config,
NULL);
- mdm2ap_status_valid_old_config = 0;
+ mdev->mdm2ap_status_valid_old_config = 0;
}
break;
default:
@@ -204,21 +355,27 @@
}
}
-long mdm_modem_ioctl(struct file *filp, unsigned int cmd,
+static long mdm_modem_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg)
{
int status, ret = 0;
+ struct mdm_device *mdev = filp->private_data;
+ struct mdm_modem_drv *mdm_drv;
if (_IOC_TYPE(cmd) != CHARM_CODE) {
- pr_err("%s: invalid ioctl code\n", __func__);
+ pr_err("%s: invalid ioctl code to mdm id %d\n",
+ __func__, mdev->mdm_data.device_id);
return -EINVAL;
}
- pr_debug("%s: Entering ioctl cmd = %d\n", __func__, _IOC_NR(cmd));
+ mdm_drv = &mdev->mdm_data;
+ pr_debug("%s: Entering ioctl cmd = %d, mdm id = %d\n",
+ __func__, _IOC_NR(cmd), mdev->mdm_data.device_id);
switch (cmd) {
case WAKE_CHARM:
- pr_info("%s: Powering on mdm\n", __func__);
- mdm_drv->ops->power_on_mdm_cb(mdm_drv);
+ pr_debug("%s: Powering on mdm id %d\n",
+ __func__, mdev->mdm_data.device_id);
+ mdm_ops->power_on_mdm_cb(mdm_drv);
break;
case CHECK_FOR_BOOT:
if (gpio_get_value(mdm_drv->mdm2ap_status_gpio) == 0)
@@ -227,30 +384,33 @@
put_user(0, (unsigned long __user *) arg);
break;
case NORMAL_BOOT_DONE:
- pr_debug("%s: check if mdm is booted up\n", __func__);
+ pr_debug("%s: check if mdm id %d is booted up\n",
+ __func__, mdev->mdm_data.device_id);
get_user(status, (unsigned long __user *) arg);
if (status) {
- pr_debug("%s: normal boot failed\n", __func__);
+ pr_debug("%s: normal boot of mdm id %d failed\n",
+ __func__, mdev->mdm_data.device_id);
mdm_drv->mdm_boot_status = -EIO;
} else {
- pr_info("%s: normal boot done\n", __func__);
+ pr_debug("%s: normal boot of mdm id %d done\n",
+ __func__, mdev->mdm_data.device_id);
mdm_drv->mdm_boot_status = 0;
}
- mdm_drv->mdm_ready = 1;
+ atomic_set(&mdm_drv->mdm_ready, 1);
- if (mdm_drv->ops->normal_boot_done_cb != NULL)
- mdm_drv->ops->normal_boot_done_cb(mdm_drv);
+ if (mdm_ops->normal_boot_done_cb != NULL)
+ mdm_ops->normal_boot_done_cb(mdm_drv);
- if (!first_boot)
- complete(&mdm_boot);
+ if (!mdev->first_boot)
+ complete(&mdev->mdm_boot);
else
- first_boot = 0;
+ mdev->first_boot = 0;
/* If successful, start a timer to check that the mdm2ap_status
* gpio goes high.
*/
if (!status && gpio_get_value(mdm_drv->mdm2ap_status_gpio) == 0)
- schedule_delayed_work(&mdm2ap_status_check_work,
+ schedule_delayed_work(&mdev->mdm2ap_status_check_work,
msecs_to_jiffies(MDM2AP_STATUS_TIMEOUT_MS));
break;
case RAM_DUMP_DONE:
@@ -259,24 +419,26 @@
if (status)
mdm_drv->mdm_ram_dump_status = -EIO;
else {
- pr_info("%s: ramdump collection completed\n", __func__);
+ pr_debug("%s: ramdump collection completed\n",
+ __func__);
mdm_drv->mdm_ram_dump_status = 0;
}
- complete(&mdm_ram_dumps);
+ complete(&mdev->mdm_ram_dumps);
break;
case WAIT_FOR_RESTART:
pr_debug("%s: wait for mdm to need images reloaded\n",
__func__);
- ret = wait_for_completion_interruptible(&mdm_needs_reload);
+ ret = wait_for_completion_interruptible(
+ &mdev->mdm_needs_reload);
if (!ret)
put_user(mdm_drv->boot_type,
(unsigned long __user *) arg);
- INIT_COMPLETION(mdm_needs_reload);
+ init_completion(&mdev->mdm_needs_reload);
break;
case GET_DLOAD_STATUS:
pr_debug("getting status of mdm2ap_errfatal_gpio\n");
if (gpio_get_value(mdm_drv->mdm2ap_errfatal_gpio) == 1 &&
- !mdm_drv->mdm_ready)
+ !atomic_read(&mdm_drv->mdm_ready))
put_user(1, (unsigned long __user *) arg);
else
put_user(0, (unsigned long __user *) arg);
@@ -284,18 +446,18 @@
case IMAGE_UPGRADE:
pr_debug("%s Image upgrade ioctl recieved\n", __func__);
if (mdm_drv->pdata->image_upgrade_supported &&
- mdm_drv->ops->image_upgrade_cb) {
+ mdm_ops->image_upgrade_cb) {
get_user(status, (unsigned long __user *) arg);
- mdm_drv->ops->image_upgrade_cb(mdm_drv, status);
+ mdm_ops->image_upgrade_cb(mdm_drv, status);
} else
pr_debug("%s Image upgrade not supported\n", __func__);
break;
case SHUTDOWN_CHARM:
if (!mdm_drv->pdata->send_shdn)
break;
- mdm_drv->mdm_ready = 0;
+ atomic_set(&mdm_drv->mdm_ready, 0);
if (mdm_debug_mask & MDM_DEBUG_MASK_SHDN_LOG)
- pr_info("Sending shutdown request to mdm\n");
+ pr_debug("Sending shutdown request to mdm\n");
ret = sysmon_send_shutdown(SYSMON_SS_EXT_MODEM);
if (ret)
pr_err("%s: Graceful shutdown of the external modem failed, ret = %d\n",
@@ -307,68 +469,76 @@
ret = -EINVAL;
break;
}
-
return ret;
}
static void mdm_status_fn(struct work_struct *work)
{
+ struct mdm_device *mdev =
+ container_of(work, struct mdm_device, mdm_status_work);
+ struct mdm_modem_drv *mdm_drv = &mdev->mdm_data;
int value = gpio_get_value(mdm_drv->mdm2ap_status_gpio);
pr_debug("%s: status:%d\n", __func__, value);
- if (mdm_drv->mdm_ready && mdm_drv->ops->status_cb)
- mdm_drv->ops->status_cb(mdm_drv, value);
+ if (atomic_read(&mdm_drv->mdm_ready) && mdm_ops->status_cb)
+ mdm_ops->status_cb(mdm_drv, value);
/* Update gpio configuration to "running" config. */
- mdm_update_gpio_configs(GPIO_UPDATE_RUNNING_CONFIG);
+ mdm_update_gpio_configs(mdev, GPIO_UPDATE_RUNNING_CONFIG);
}
-static DECLARE_WORK(mdm_status_work, mdm_status_fn);
-
-static void mdm_disable_irqs(void)
+static void mdm_disable_irqs(struct mdm_device *mdev)
{
- disable_irq_nosync(mdm_drv->mdm_errfatal_irq);
- disable_irq_nosync(mdm_drv->mdm_status_irq);
+ if (!mdev)
+ return;
+ disable_irq_nosync(mdev->mdm_errfatal_irq);
+ disable_irq_nosync(mdev->mdm_status_irq);
+ disable_irq_nosync(mdev->mdm_pblrdy_irq);
}
static irqreturn_t mdm_errfatal(int irq, void *dev_id)
{
- pr_debug("%s: mdm got errfatal interrupt\n", __func__);
- if (mdm_drv->mdm_ready &&
+ struct mdm_modem_drv *mdm_drv;
+ struct mdm_device *mdev = (struct mdm_device *)dev_id;
+ if (!mdev)
+ return IRQ_HANDLED;
+
+ pr_debug("%s: mdm id %d sent errfatal interrupt\n",
+ __func__, mdev->mdm_data.device_id);
+ mdm_drv = &mdev->mdm_data;
+ if (atomic_read(&mdm_drv->mdm_ready) &&
(gpio_get_value(mdm_drv->mdm2ap_status_gpio) == 1)) {
- pr_info("%s: Reseting the mdm due to an errfatal\n", __func__);
- mdm_drv->mdm_ready = 0;
- subsystem_restart_dev(mdm_subsys_dev);
+ pr_debug("%s: Received err fatal from mdm id %d\n",
+ __func__, mdev->mdm_data.device_id);
+ mdm_start_ssr(mdev);
}
return IRQ_HANDLED;
}
+/* set the mdm_device as the file's private data */
static int mdm_modem_open(struct inode *inode, struct file *file)
{
+ struct miscdevice *misc = file->private_data;
+ struct mdm_device *mdev = container_of(misc,
+ struct mdm_device, misc_device);
+
+ file->private_data = mdev;
return 0;
}
-static const struct file_operations mdm_modem_fops = {
- .owner = THIS_MODULE,
- .open = mdm_modem_open,
- .unlocked_ioctl = mdm_modem_ioctl,
-};
-
-
-static struct miscdevice mdm_modem_misc = {
- .minor = MISC_DYNAMIC_MINOR,
- .name = "mdm",
- .fops = &mdm_modem_fops
-};
-
static int mdm_panic_prep(struct notifier_block *this,
unsigned long event, void *ptr)
{
int i;
+ struct mdm_modem_drv *mdm_drv;
+ struct mdm_device *mdev =
+ container_of(this, struct mdm_device, mdm_panic_blk);
+
+ mdm_drv = &mdev->mdm_data;
pr_debug("%s: setting AP2MDM_ERRFATAL high for a non graceful reset\n",
__func__);
- mdm_disable_irqs();
+ mdm_disable_irqs(mdev);
gpio_set_value(mdm_drv->ap2mdm_errfatal_gpio, 1);
for (i = MDM_MODEM_TIMEOUT; i > 0; i -= MDM_MODEM_DELTA) {
@@ -380,49 +550,67 @@
if (i <= 0) {
pr_err("%s: MDM2AP_STATUS never went low\n", __func__);
/* Reset the modem so that it will go into download mode. */
- if (mdm_drv && mdm_drv->ops->atomic_reset_mdm_cb)
- mdm_drv->ops->atomic_reset_mdm_cb(mdm_drv);
+ if (mdm_drv && mdm_ops->atomic_reset_mdm_cb)
+ mdm_ops->atomic_reset_mdm_cb(mdm_drv);
}
return NOTIFY_DONE;
}
-static struct notifier_block mdm_panic_blk = {
- .notifier_call = mdm_panic_prep,
-};
-
static irqreturn_t mdm_status_change(int irq, void *dev_id)
{
- int value = gpio_get_value(mdm_drv->mdm2ap_status_gpio);
+ struct mdm_modem_drv *mdm_drv;
+ struct mdm_device *mdev = (struct mdm_device *)dev_id;
+ int value;
+ if (!mdev)
+ return IRQ_HANDLED;
+
+ mdm_drv = &mdev->mdm_data;
+ value = gpio_get_value(mdm_drv->mdm2ap_status_gpio);
if ((mdm_debug_mask & MDM_DEBUG_MASK_SHDN_LOG) && (value == 0))
- pr_info("%s: mdm2ap_status went low\n", __func__);
+ pr_debug("%s: mdm2ap_status went low\n", __func__);
- pr_debug("%s: mdm sent status change interrupt\n", __func__);
- if (value == 0 && mdm_drv->mdm_ready == 1) {
- pr_info("%s: unexpected reset external modem\n", __func__);
+ pr_debug("%s: mdm id %d sent status change interrupt\n",
+ __func__, mdev->mdm_data.device_id);
+ if (value == 0 && atomic_read(&mdm_drv->mdm_ready)) {
+ pr_debug("%s: unexpected reset external modem id %d\n",
+ __func__, mdev->mdm_data.device_id);
mdm_drv->mdm_unexpected_reset_occurred = 1;
- mdm_drv->mdm_ready = 0;
- subsystem_restart_dev(mdm_subsys_dev);
+ mdm_start_ssr(mdev);
} else if (value == 1) {
- cancel_delayed_work(&mdm2ap_status_check_work);
- pr_info("%s: status = 1: mdm is now ready\n", __func__);
- queue_work(mdm_queue, &mdm_status_work);
+ cancel_delayed_work(&mdev->mdm2ap_status_check_work);
+ pr_debug("%s: status = 1: mdm id %d is now ready\n",
+ __func__, mdev->mdm_data.device_id);
+ queue_work(mdev->mdm_queue, &mdev->mdm_status_work);
}
return IRQ_HANDLED;
}
static irqreturn_t mdm_pblrdy_change(int irq, void *dev_id)
{
- pr_info("%s: pbl ready:%d\n", __func__,
- gpio_get_value(mdm_drv->mdm2ap_pblrdy));
+ struct mdm_modem_drv *mdm_drv;
+ struct mdm_device *mdev = (struct mdm_device *)dev_id;
+ if (!mdev)
+ return IRQ_HANDLED;
+ mdm_drv = &mdev->mdm_data;
+ pr_debug("%s: mdm id %d: pbl ready:%d\n",
+ __func__, mdev->mdm_data.device_id,
+ gpio_get_value(mdm_drv->mdm2ap_pblrdy));
return IRQ_HANDLED;
}
static int mdm_subsys_shutdown(const struct subsys_desc *crashed_subsys)
{
- mdm_drv->mdm_ready = 0;
- cancel_delayed_work(&mdm2ap_status_check_work);
+ struct mdm_device *mdev =
+ container_of(crashed_subsys, struct mdm_device, mdm_subsys);
+ struct mdm_modem_drv *mdm_drv = &mdev->mdm_data;
+
+ pr_debug("%s: ssr on modem id %d\n", __func__,
+ mdev->mdm_data.device_id);
+
+ mdm_ssr_started(mdev);
+ cancel_delayed_work(&mdev->mdm2ap_status_check_work);
gpio_direction_output(mdm_drv->ap2mdm_errfatal_gpio, 1);
if (mdm_drv->pdata->ramdump_delay_ms > 0) {
/* Wait for the external modem to complete
@@ -431,9 +619,9 @@
msleep(mdm_drv->pdata->ramdump_delay_ms);
}
if (!mdm_drv->mdm_unexpected_reset_occurred) {
- mdm_drv->ops->reset_mdm_cb(mdm_drv);
+ mdm_ops->reset_mdm_cb(mdm_drv);
/* Update gpio configuration to "booting" config. */
- mdm_update_gpio_configs(GPIO_UPDATE_BOOTING_CONFIG);
+ mdm_update_gpio_configs(mdev, GPIO_UPDATE_BOOTING_CONFIG);
} else {
mdm_drv->mdm_unexpected_reset_occurred = 0;
}
@@ -442,63 +630,76 @@
static int mdm_subsys_powerup(const struct subsys_desc *crashed_subsys)
{
+ struct mdm_device *mdev =
+ container_of(crashed_subsys, struct mdm_device,
+ mdm_subsys);
+ struct mdm_modem_drv *mdm_drv = &mdev->mdm_data;
+
+ pr_debug("%s: ssr on modem id %d\n",
+ __func__, mdev->mdm_data.device_id);
+
gpio_direction_output(mdm_drv->ap2mdm_errfatal_gpio, 0);
gpio_direction_output(mdm_drv->ap2mdm_status_gpio, 1);
if (mdm_drv->pdata->ps_hold_delay_ms > 0)
msleep(mdm_drv->pdata->ps_hold_delay_ms);
- mdm_drv->ops->power_on_mdm_cb(mdm_drv);
+ mdm_ops->power_on_mdm_cb(mdm_drv);
mdm_drv->boot_type = CHARM_NORMAL_BOOT;
- complete(&mdm_needs_reload);
- if (!wait_for_completion_timeout(&mdm_boot,
+ mdm_ssr_completed(mdev);
+ complete(&mdev->mdm_needs_reload);
+ if (!wait_for_completion_timeout(&mdev->mdm_boot,
msecs_to_jiffies(MDM_BOOT_TIMEOUT))) {
mdm_drv->mdm_boot_status = -ETIMEDOUT;
- pr_info("%s: mdm modem restart timed out.\n", __func__);
+ pr_debug("%s: mdm modem restart timed out.\n", __func__);
} else {
- pr_info("%s: mdm modem has been restarted\n", __func__);
+ pr_debug("%s: id %d: mdm modem has been restarted\n",
+ __func__, mdm_drv->device_id);
/* Log the reason for the restart */
if (mdm_drv->pdata->sfr_query)
- queue_work(mdm_sfr_queue, &sfr_reason_work);
+ queue_work(mdev->mdm_sfr_queue, &mdev->sfr_reason_work);
}
- INIT_COMPLETION(mdm_boot);
+ init_completion(&mdev->mdm_boot);
return mdm_drv->mdm_boot_status;
}
static int mdm_subsys_ramdumps(int want_dumps,
const struct subsys_desc *crashed_subsys)
{
+ struct mdm_device *mdev =
+ container_of(crashed_subsys, struct mdm_device,
+ mdm_subsys);
+ struct mdm_modem_drv *mdm_drv = &mdev->mdm_data;
+
+ pr_debug("%s: ssr on modem id %d\n", __func__,
+ mdev->mdm_data.device_id);
+
mdm_drv->mdm_ram_dump_status = 0;
- cancel_delayed_work(&mdm2ap_status_check_work);
+ cancel_delayed_work(&mdev->mdm2ap_status_check_work);
if (want_dumps) {
mdm_drv->boot_type = CHARM_RAM_DUMPS;
- complete(&mdm_needs_reload);
- if (!wait_for_completion_timeout(&mdm_ram_dumps,
- msecs_to_jiffies(dump_timeout_ms))) {
+ complete(&mdev->mdm_needs_reload);
+ if (!wait_for_completion_timeout(&mdev->mdm_ram_dumps,
+ msecs_to_jiffies(mdev->dump_timeout_ms))) {
mdm_drv->mdm_ram_dump_status = -ETIMEDOUT;
- pr_info("%s: mdm modem ramdumps timed out.\n",
+ mdm_ssr_completed(mdev);
+ pr_err("%s: mdm modem ramdumps timed out.\n",
__func__);
} else
- pr_info("%s: mdm modem ramdumps completed.\n",
+ pr_debug("%s: mdm modem ramdumps completed.\n",
__func__);
- INIT_COMPLETION(mdm_ram_dumps);
+ init_completion(&mdev->mdm_ram_dumps);
if (!mdm_drv->pdata->no_powerdown_after_ramdumps) {
- mdm_drv->ops->power_down_mdm_cb(mdm_drv);
+ mdm_ops->power_down_mdm_cb(mdm_drv);
/* Update gpio configuration to "booting" config. */
- mdm_update_gpio_configs(GPIO_UPDATE_BOOTING_CONFIG);
+ mdm_update_gpio_configs(mdev,
+ GPIO_UPDATE_BOOTING_CONFIG);
}
}
return mdm_drv->mdm_ram_dump_status;
}
-static struct subsys_desc mdm_subsystem = {
- .shutdown = mdm_subsys_shutdown,
- .ramdump = mdm_subsys_ramdumps,
- .powerup = mdm_subsys_powerup,
- .name = EXTERNAL_MODEM,
-};
-
/* Once the gpios are sent to RPM and debugging
* starts, there is no way to stop it without
* rebooting the device.
@@ -512,8 +713,8 @@
}
mdm_debug_mask = val;
- if (mdm_drv->ops->debug_state_changed_cb)
- mdm_drv->ops->debug_state_changed_cb(mdm_debug_mask);
+ if (mdm_ops->debug_state_changed_cb)
+ mdm_ops->debug_state_changed_cb(mdm_debug_mask);
return 0;
}
@@ -540,11 +741,55 @@
return 0;
}
-static void mdm_modem_initialize_data(struct platform_device *pdev,
- struct mdm_ops *mdm_ops)
+static const struct file_operations mdm_modem_fops = {
+ .owner = THIS_MODULE,
+ .open = mdm_modem_open,
+ .unlocked_ioctl = mdm_modem_ioctl,
+};
+
+static void mdm_modem_initialize_data(struct platform_device *pdev,
+ struct mdm_device *mdev)
{
+ struct mdm_modem_drv *mdm_drv = &mdev->mdm_data;
struct resource *pres;
+ mdm_drv->pdata = pdev->dev.platform_data;
+ if (pdev->id < 0)
+ mdm_drv->device_id = 0;
+ else
+ mdm_drv->device_id = pdev->id;
+
+ memset((void *)&mdev->mdm_subsys, 0,
+ sizeof(struct subsys_desc));
+ if (mdev->mdm_data.device_id <= 0)
+ snprintf(mdev->subsys_name, sizeof(mdev->subsys_name),
+ "%s", EXTERNAL_MODEM);
+ else
+ snprintf(mdev->subsys_name, sizeof(mdev->subsys_name),
+ "%s.%d", EXTERNAL_MODEM, mdev->mdm_data.device_id);
+ mdev->mdm_subsys.shutdown = mdm_subsys_shutdown;
+ mdev->mdm_subsys.ramdump = mdm_subsys_ramdumps;
+ mdev->mdm_subsys.powerup = mdm_subsys_powerup;
+ mdev->mdm_subsys.name = mdev->subsys_name;
+
+ memset((void *)&mdev->misc_device, 0,
+ sizeof(struct miscdevice));
+ if (mdev->mdm_data.device_id <= 0)
+ snprintf(mdev->device_name, sizeof(mdev->device_name),
+ "%s", DEVICE_BASE_NAME);
+ else
+ snprintf(mdev->device_name, sizeof(mdev->device_name),
+ "%s%d", DEVICE_BASE_NAME, mdev->mdm_data.device_id);
+ mdev->misc_device.minor = MISC_DYNAMIC_MINOR;
+ mdev->misc_device.name = mdev->device_name;
+ mdev->misc_device.fops = &mdm_modem_fops;
+
+ memset((void *)&mdev->mdm_panic_blk, 0,
+ sizeof(struct notifier_block));
+ mdev->mdm_panic_blk.notifier_call = mdm_panic_prep;
+ atomic_notifier_chain_register(&panic_notifier_list,
+ &mdev->mdm_panic_blk);
+
/* MDM2AP_ERRFATAL */
pres = platform_get_resource_byname(pdev, IORESOURCE_IO,
"MDM2AP_ERRFATAL");
@@ -602,26 +847,49 @@
mdm_drv->boot_type = CHARM_NORMAL_BOOT;
- mdm_drv->ops = mdm_ops;
- mdm_drv->pdata = pdev->dev.platform_data;
- dump_timeout_ms = mdm_drv->pdata->ramdump_timeout_ms > 0 ?
+ mdm_drv->dump_timeout_ms = mdm_drv->pdata->ramdump_timeout_ms > 0 ?
mdm_drv->pdata->ramdump_timeout_ms : MDM_RDUMP_TIMEOUT;
+
+ init_completion(&mdev->mdm_needs_reload);
+ init_completion(&mdev->mdm_boot);
+ init_completion(&mdev->mdm_ram_dumps);
+
+ mdev->first_boot = 1;
+ mutex_init(&mdm_drv->peripheral_status_lock);
}
-int mdm_common_create(struct platform_device *pdev,
- struct mdm_ops *p_mdm_cb)
+static void mdm_deconfigure_ipc(struct mdm_device *mdev)
{
- int ret = -1, irq;
+ struct mdm_modem_drv *mdm_drv = &mdev->mdm_data;
- mdm_drv = kzalloc(sizeof(struct mdm_modem_drv), GFP_KERNEL);
- if (mdm_drv == NULL) {
- pr_err("%s: kzalloc fail.\n", __func__);
- goto alloc_err;
+ gpio_free(mdm_drv->ap2mdm_status_gpio);
+ gpio_free(mdm_drv->ap2mdm_errfatal_gpio);
+ if (GPIO_IS_VALID(mdm_drv->ap2mdm_kpdpwr_n_gpio))
+ gpio_free(mdm_drv->ap2mdm_kpdpwr_n_gpio);
+ if (GPIO_IS_VALID(mdm_drv->ap2mdm_pmic_pwr_en_gpio))
+ gpio_free(mdm_drv->ap2mdm_pmic_pwr_en_gpio);
+ gpio_free(mdm_drv->mdm2ap_status_gpio);
+ gpio_free(mdm_drv->mdm2ap_errfatal_gpio);
+ if (GPIO_IS_VALID(mdm_drv->ap2mdm_soft_reset_gpio))
+ gpio_free(mdm_drv->ap2mdm_soft_reset_gpio);
+
+ if (GPIO_IS_VALID(mdm_drv->ap2mdm_wakeup_gpio))
+ gpio_free(mdm_drv->ap2mdm_wakeup_gpio);
+
+ if (mdev->mdm_queue) {
+ destroy_workqueue(mdev->mdm_queue);
+ mdev->mdm_queue = NULL;
}
+ if (mdev->mdm_sfr_queue) {
+ destroy_workqueue(mdev->mdm_sfr_queue);
+ mdev->mdm_sfr_queue = NULL;
+ }
+}
- mdm_modem_initialize_data(pdev, p_mdm_cb);
- if (mdm_drv->ops->debug_state_changed_cb)
- mdm_drv->ops->debug_state_changed_cb(mdm_debug_mask);
+static int mdm_configure_ipc(struct mdm_device *mdev)
+{
+ struct mdm_modem_drv *mdm_drv = &mdev->mdm_data;
+ int ret = -1, irq;
gpio_request(mdm_drv->ap2mdm_status_gpio, "AP2MDM_STATUS");
gpio_request(mdm_drv->ap2mdm_errfatal_gpio, "AP2MDM_ERRFATAL");
@@ -648,7 +916,6 @@
mdm_drv->usb_switch_gpio = -1;
}
}
-
gpio_direction_output(mdm_drv->ap2mdm_status_gpio, 0);
gpio_direction_output(mdm_drv->ap2mdm_errfatal_gpio, 0);
@@ -658,97 +925,88 @@
gpio_direction_input(mdm_drv->mdm2ap_status_gpio);
gpio_direction_input(mdm_drv->mdm2ap_errfatal_gpio);
- mdm_queue = create_singlethread_workqueue("mdm_queue");
- if (!mdm_queue) {
- pr_err("%s: could not create workqueue. All mdm "
- "functionality will be disabled\n",
- __func__);
+ mdev->mdm_queue = alloc_workqueue("mdm_queue", 0, 0);
+ if (!mdev->mdm_queue) {
+ pr_err("%s: could not create mdm_queue for mdm id %d\n",
+ __func__, mdev->mdm_data.device_id);
ret = -ENOMEM;
goto fatal_err;
}
- mdm_sfr_queue = alloc_workqueue("mdm_sfr_queue", 0, 0);
- if (!mdm_sfr_queue) {
- pr_err("%s: could not create workqueue mdm_sfr_queue."
- " All mdm functionality will be disabled\n",
- __func__);
+ mdev->mdm_sfr_queue = alloc_workqueue("mdm_sfr_queue", 0, 0);
+ if (!mdev->mdm_sfr_queue) {
+ pr_err("%s: could not create mdm_sfr_queue for mdm id %d\n",
+ __func__, mdev->mdm_data.device_id);
ret = -ENOMEM;
- destroy_workqueue(mdm_queue);
goto fatal_err;
}
- atomic_notifier_chain_register(&panic_notifier_list, &mdm_panic_blk);
- mdm_debugfs_init();
-
/* Register subsystem handlers */
- mdm_subsys_dev = subsys_register(&mdm_subsystem);
- if (IS_ERR(mdm_subsys_dev)) {
- ret = PTR_ERR(mdm_subsys_dev);
+ mdev->mdm_subsys_dev = subsys_register(&mdev->mdm_subsys);
+ if (IS_ERR(mdev->mdm_subsys_dev)) {
+ ret = PTR_ERR(mdev->mdm_subsys_dev);
goto fatal_err;
}
- subsys_default_online(mdm_subsys_dev);
+ subsys_default_online(mdev->mdm_subsys_dev);
/* ERR_FATAL irq. */
- irq = MSM_GPIO_TO_INT(mdm_drv->mdm2ap_errfatal_gpio);
+ irq = gpio_to_irq(mdm_drv->mdm2ap_errfatal_gpio);
if (irq < 0) {
- pr_err("%s: could not get MDM2AP_ERRFATAL IRQ resource. "
- "error=%d No IRQ will be generated on errfatal.",
- __func__, irq);
+ pr_err("%s: bad MDM2AP_ERRFATAL IRQ resource, err = %d\n",
+ __func__, irq);
goto errfatal_err;
}
ret = request_irq(irq, mdm_errfatal,
- IRQF_TRIGGER_RISING , "mdm errfatal", NULL);
+ IRQF_TRIGGER_RISING , "mdm errfatal", mdev);
if (ret < 0) {
- pr_err("%s: MDM2AP_ERRFATAL IRQ#%d request failed with error=%d"
- ". No IRQ will be generated on errfatal.",
- __func__, irq, ret);
+ pr_err("%s: MDM2AP_ERRFATAL IRQ#%d request failed, err=%d\n",
+ __func__, irq, ret);
goto errfatal_err;
}
- mdm_drv->mdm_errfatal_irq = irq;
+ mdev->mdm_errfatal_irq = irq;
errfatal_err:
- /* status irq */
- irq = MSM_GPIO_TO_INT(mdm_drv->mdm2ap_status_gpio);
+ /* status irq */
+ irq = gpio_to_irq(mdm_drv->mdm2ap_status_gpio);
if (irq < 0) {
- pr_err("%s: could not get MDM2AP_STATUS IRQ resource. "
- "error=%d No IRQ will be generated on status change.",
- __func__, irq);
+ pr_err("%s: bad MDM2AP_STATUS IRQ resource, err = %d\n",
+ __func__, irq);
goto status_err;
}
ret = request_threaded_irq(irq, NULL, mdm_status_change,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_SHARED,
- "mdm status", mdm_drv);
+ "mdm status", mdev);
if (ret < 0) {
- pr_err("%s: MDM2AP_STATUS IRQ#%d request failed with error=%d"
- ". No IRQ will be generated on status change.",
- __func__, irq, ret);
+ pr_err("%s: MDM2AP_STATUS IRQ#%d request failed, err=%d",
+ __func__, irq, ret);
goto status_err;
}
- mdm_drv->mdm_status_irq = irq;
+ mdev->mdm_status_irq = irq;
status_err:
if (GPIO_IS_VALID(mdm_drv->mdm2ap_pblrdy)) {
- irq = MSM_GPIO_TO_INT(mdm_drv->mdm2ap_pblrdy);
+ irq = gpio_to_irq(mdm_drv->mdm2ap_pblrdy);
if (irq < 0) {
- pr_err("%s: could not get MDM2AP_PBLRDY IRQ resource",
- __func__);
+ pr_err("%s: could not get MDM2AP_PBLRDY IRQ resource\n",
+ __func__);
goto pblrdy_err;
}
ret = request_threaded_irq(irq, NULL, mdm_pblrdy_change,
- IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
- IRQF_SHARED,
- "mdm pbl ready", mdm_drv);
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
+ IRQF_SHARED,
+ "mdm pbl ready", mdev);
if (ret < 0) {
- pr_err("%s: MDM2AP_PBL IRQ#%d request failed error=%d",
+ pr_err("%s: MDM2AP_PBL IRQ#%d request failed error=%d\n",
__func__, irq, ret);
goto pblrdy_err;
}
+ mdev->mdm_pblrdy_irq = irq;
}
pblrdy_err:
@@ -759,67 +1017,136 @@
if (GPIO_IS_VALID(mdm_drv->ap2mdm_pmic_pwr_en_gpio))
gpio_direction_output(mdm_drv->ap2mdm_pmic_pwr_en_gpio, 1);
- /* Perform early powerup of the external modem in order to
- * allow tabla devices to be found.
- */
- if (mdm_drv->pdata->early_power_on)
- mdm_drv->ops->power_on_mdm_cb(mdm_drv);
-
- pr_info("%s: Registering mdm modem\n", __func__);
- return misc_register(&mdm_modem_misc);
+ return 0;
fatal_err:
- gpio_free(mdm_drv->ap2mdm_status_gpio);
- gpio_free(mdm_drv->ap2mdm_errfatal_gpio);
- if (GPIO_IS_VALID(mdm_drv->ap2mdm_kpdpwr_n_gpio))
- gpio_free(mdm_drv->ap2mdm_kpdpwr_n_gpio);
- if (GPIO_IS_VALID(mdm_drv->ap2mdm_pmic_pwr_en_gpio))
- gpio_free(mdm_drv->ap2mdm_pmic_pwr_en_gpio);
- gpio_free(mdm_drv->mdm2ap_status_gpio);
- gpio_free(mdm_drv->mdm2ap_errfatal_gpio);
- if (GPIO_IS_VALID(mdm_drv->ap2mdm_soft_reset_gpio))
- gpio_free(mdm_drv->ap2mdm_soft_reset_gpio);
-
- if (GPIO_IS_VALID(mdm_drv->ap2mdm_wakeup_gpio))
- gpio_free(mdm_drv->ap2mdm_wakeup_gpio);
-
- kfree(mdm_drv);
- ret = -ENODEV;
-
-alloc_err:
+ mdm_deconfigure_ipc(mdev);
return ret;
}
-int mdm_common_modem_remove(struct platform_device *pdev)
+static int __devinit mdm_modem_probe(struct platform_device *pdev)
+{
+ struct mdm_device *mdev = NULL;
+ int ret = -1;
+
+ mdev = kzalloc(sizeof(struct mdm_device), GFP_KERNEL);
+ if (!mdev) {
+ pr_err("%s: kzalloc fail.\n", __func__);
+ ret = -ENOMEM;
+ goto init_err;
+ }
+
+ platform_set_drvdata(pdev, mdev);
+ mdm_modem_initialize_data(pdev, mdev);
+
+ if (mdm_ops->debug_state_changed_cb)
+ mdm_ops->debug_state_changed_cb(mdm_debug_mask);
+
+ if (mdm_configure_ipc(mdev)) {
+ pr_err("%s: mdm_configure_ipc failed, id = %d\n",
+ __func__, mdev->mdm_data.device_id);
+ goto init_err;
+ }
+
+ pr_debug("%s: Registering mdm id %d\n", __func__,
+ mdev->mdm_data.device_id);
+ ret = misc_register(&mdev->misc_device);
+ if (ret) {
+ pr_err("%s: failed registering mdm id %d, ret = %d\n",
+ __func__, mdev->mdm_data.device_id, ret);
+ mdm_deconfigure_ipc(mdev);
+ goto init_err;
+ } else {
+ pr_err("%s: registered mdm id %d\n",
+ __func__, mdev->mdm_data.device_id);
+
+ mdm_device_list_add(mdev);
+ INIT_DELAYED_WORK(&mdev->mdm2ap_status_check_work,
+ mdm2ap_status_check);
+ INIT_WORK(&mdev->mdm_status_work, mdm_status_fn);
+ INIT_WORK(&mdev->sfr_reason_work, mdm_restart_reason_fn);
+
+ /* Perform early powerup of the external modem in order to
+ * allow tabla devices to be found.
+ */
+ if (mdev->mdm_data.pdata->early_power_on)
+ mdm_ops->power_on_mdm_cb(&mdev->mdm_data);
+ }
+
+ return ret;
+
+init_err:
+ kfree(mdev);
+ return ret;
+}
+
+static int __devexit mdm_modem_remove(struct platform_device *pdev)
{
int ret;
+ struct mdm_device *mdev = platform_get_drvdata(pdev);
- gpio_free(mdm_drv->ap2mdm_status_gpio);
- gpio_free(mdm_drv->ap2mdm_errfatal_gpio);
- if (GPIO_IS_VALID(mdm_drv->ap2mdm_kpdpwr_n_gpio))
- gpio_free(mdm_drv->ap2mdm_kpdpwr_n_gpio);
- if (GPIO_IS_VALID(mdm_drv->ap2mdm_pmic_pwr_en_gpio))
- gpio_free(mdm_drv->ap2mdm_pmic_pwr_en_gpio);
- gpio_free(mdm_drv->mdm2ap_status_gpio);
- gpio_free(mdm_drv->mdm2ap_errfatal_gpio);
- if (GPIO_IS_VALID(mdm_drv->ap2mdm_soft_reset_gpio))
- gpio_free(mdm_drv->ap2mdm_soft_reset_gpio);
-
- if (GPIO_IS_VALID(mdm_drv->ap2mdm_wakeup_gpio))
- gpio_free(mdm_drv->ap2mdm_wakeup_gpio);
-
- kfree(mdm_drv);
-
- ret = misc_deregister(&mdm_modem_misc);
+ pr_debug("%s: removing device id %d\n",
+ __func__, mdev->mdm_data.device_id);
+ mdm_deconfigure_ipc(mdev);
+ ret = misc_deregister(&mdev->misc_device);
+ mdm_device_list_remove(mdev);
+ kfree(mdev);
return ret;
}
-void mdm_common_modem_shutdown(struct platform_device *pdev)
+static void mdm_modem_shutdown(struct platform_device *pdev)
{
- mdm_disable_irqs();
+ struct mdm_modem_drv *mdm_drv;
+ struct mdm_device *mdev = platform_get_drvdata(pdev);
- mdm_drv->ops->power_down_mdm_cb(mdm_drv);
+ pr_debug("%s: shutting down device id %d\n",
+ __func__, mdev->mdm_data.device_id);
+
+ mdm_disable_irqs(mdev);
+ mdm_drv = &mdev->mdm_data;
+ mdm_ops->power_down_mdm_cb(mdm_drv);
if (GPIO_IS_VALID(mdm_drv->ap2mdm_pmic_pwr_en_gpio))
gpio_direction_output(mdm_drv->ap2mdm_pmic_pwr_en_gpio, 0);
}
+static struct of_device_id mdm_match_table[] = {
+ {.compatible = "qcom,mdm2_modem,mdm2_modem.1"},
+ {},
+};
+
+static struct platform_driver mdm_modem_driver = {
+ .probe = mdm_modem_probe,
+ .remove = __devexit_p(mdm_modem_remove),
+ .shutdown = mdm_modem_shutdown,
+ .driver = {
+ .name = "mdm2_modem",
+ .owner = THIS_MODULE,
+ .of_match_table = mdm_match_table,
+ },
+};
+
+static int __init mdm_modem_init(void)
+{
+ int ret;
+
+ ret = mdm_get_ops(&mdm_ops);
+ if (ret)
+ return ret;
+
+ INIT_LIST_HEAD(&mdm_devices);
+ mdm_debugfs_init();
+ return platform_driver_register(&mdm_modem_driver);
+}
+
+static void __exit mdm_modem_exit(void)
+{
+ platform_driver_unregister(&mdm_modem_driver);
+}
+
+module_init(mdm_modem_init);
+module_exit(mdm_modem_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("mdm modem driver");
+MODULE_VERSION("2.0");
+MODULE_ALIAS("mdm_modem");
diff --git a/arch/arm/mach-msm/mdm_private.h b/arch/arm/mach-msm/mdm_private.h
index 92fb141..5a91cf9 100644
--- a/arch/arm/mach-msm/mdm_private.h
+++ b/arch/arm/mach-msm/mdm_private.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -44,25 +44,22 @@
unsigned mdm2ap_pblrdy;
unsigned usb_switch_gpio;
- int mdm_errfatal_irq;
- int mdm_status_irq;
- int mdm_ready;
+ atomic_t mdm_ready;
int mdm_boot_status;
int mdm_ram_dump_status;
enum charm_boot_type boot_type;
int mdm_debug_on;
int mdm_unexpected_reset_occurred;
int disable_status_check;
+ unsigned int dump_timeout_ms;
+ int power_on_count;
+ int peripheral_status;
+ struct mutex peripheral_status_lock;
+ int device_id;
- struct mdm_ops *ops;
struct mdm_platform_data *pdata;
};
-
-int mdm_common_create(struct platform_device *pdev,
- struct mdm_ops *mdm_cb);
-int mdm_common_modem_remove(struct platform_device *pdev);
-void mdm_common_modem_shutdown(struct platform_device *pdev);
-void mdm_common_set_debug_state(int value);
+int mdm_get_ops(struct mdm_ops **mdm_ops);
#endif
diff --git a/arch/arm/mach-msm/memory.c b/arch/arm/mach-msm/memory.c
index d7d3081..7a7fb99 100644
--- a/arch/arm/mach-msm/memory.c
+++ b/arch/arm/mach-msm/memory.c
@@ -315,6 +315,8 @@
unsigned long memory_remove_prop_length;
unsigned long memory_size_prop_length;
unsigned int *memory_size_prop;
+ unsigned int *memory_reserve_prop;
+ unsigned long memory_reserve_prop_length;
unsigned int memory_size;
unsigned int memory_start;
int ret;
@@ -326,7 +328,11 @@
"qcom,memblock-remove",
&memory_remove_prop_length);
- if (memory_name_prop || memory_remove_prop) {
+ memory_reserve_prop = of_get_flat_dt_prop(node,
+ "qcom,memblock-reserve",
+ &memory_reserve_prop_length);
+
+ if (memory_name_prop || memory_remove_prop || memory_reserve_prop) {
if (!check_for_compat(node))
goto out;
} else {
@@ -365,7 +371,7 @@
if (memory_remove_prop) {
if (memory_remove_prop_length != (2*sizeof(unsigned int))) {
WARN(1, "Memory remove malformed\n");
- goto out;
+ goto mem_reserve;
}
memory_start = be32_to_cpu(memory_remove_prop[0]);
@@ -380,6 +386,26 @@
memory_start, memory_start+memory_size);
}
+mem_reserve:
+
+ if (memory_reserve_prop) {
+ if (memory_reserve_prop_length != (2*sizeof(unsigned int))) {
+ WARN(1, "Memory reserve malformed\n");
+ goto out;
+ }
+
+ memory_start = be32_to_cpu(memory_reserve_prop[0]);
+ memory_size = be32_to_cpu(memory_reserve_prop[1]);
+
+ ret = memblock_reserve(memory_start, memory_size);
+ if (ret)
+ WARN(1, "Failed to reserve memory %x-%x\n",
+ memory_start, memory_start+memory_size);
+ else
+ pr_info("Node %s memblock_reserve memory %x-%x\n",
+ uname, memory_start, memory_start+memory_size);
+ }
+
out:
return 0;
}
diff --git a/arch/arm/mach-msm/msm_ipc_router_security.c b/arch/arm/mach-msm/msm_ipc_router_security.c
index 69efd13..5897e1f 100644
--- a/arch/arm/mach-msm/msm_ipc_router_security.c
+++ b/arch/arm/mach-msm/msm_ipc_router_security.c
@@ -22,6 +22,7 @@
#include <linux/uaccess.h>
#include <linux/kernel.h>
#include <linux/msm_ipc.h>
+#include <linux/rwsem.h>
#include <asm/uaccess.h>
@@ -31,6 +32,11 @@
#define IRSC_COMPLETION_TIMEOUT_MS 30000
#define SEC_RULES_HASH_SZ 32
+
+#ifndef SIZE_MAX
+#define SIZE_MAX ((size_t)-1)
+#endif
+
struct security_rule {
struct list_head list;
uint32_t service_id;
@@ -40,7 +46,7 @@
gid_t *group_id;
};
-static DEFINE_MUTEX(security_rules_lock);
+static DECLARE_RWSEM(security_rules_lock_lha4);
static struct list_head security_rules[SEC_RULES_HASH_SZ];
static DECLARE_COMPLETION(irsc_completion);
@@ -98,7 +104,7 @@
struct config_sec_rules_args sec_rules_arg;
struct security_rule *rule, *temp_rule;
int key;
- int group_info_sz;
+ size_t group_info_sz;
int ret;
if (current_euid())
@@ -112,12 +118,12 @@
if (sec_rules_arg.num_group_info <= 0)
return -EINVAL;
- group_info_sz = sec_rules_arg.num_group_info * sizeof(gid_t);
- if ((group_info_sz / sizeof(gid_t)) != sec_rules_arg.num_group_info) {
+ if (sec_rules_arg.num_group_info > (SIZE_MAX / sizeof(gid_t))) {
pr_err("%s: Integer Overflow %d * %d\n", __func__,
sizeof(gid_t), sec_rules_arg.num_group_info);
return -EINVAL;
}
+ group_info_sz = sec_rules_arg.num_group_info * sizeof(gid_t);
rule = kzalloc(sizeof(struct security_rule), GFP_KERNEL);
if (!rule) {
@@ -146,7 +152,7 @@
}
key = rule->service_id & (SEC_RULES_HASH_SZ - 1);
- mutex_lock(&security_rules_lock);
+ down_write(&security_rules_lock_lha4);
if (rule->service_id == ALL_SERVICE) {
temp_rule = list_first_entry(&security_rules[key],
struct security_rule, list);
@@ -155,7 +161,7 @@
kfree(temp_rule);
}
list_add_tail(&rule->list, &security_rules[key]);
- mutex_unlock(&security_rules_lock);
+ up_write(&security_rules_lock_lha4);
if (rule->service_id == ALL_SERVICE)
msm_ipc_sync_default_sec_rule((void *)rule);
@@ -198,10 +204,10 @@
rule->instance_id = ALL_INSTANCE;
rule->num_group_info = 1;
*(rule->group_id) = AID_NET_RAW;
- mutex_lock(&security_rules_lock);
+ down_write(&security_rules_lock_lha4);
key = (ALL_SERVICE & (SEC_RULES_HASH_SZ - 1));
list_add_tail(&rule->list, &security_rules[key]);
- mutex_unlock(&security_rules_lock);
+ up_write(&security_rules_lock_lha4);
return 0;
}
@@ -222,12 +228,12 @@
struct security_rule *rule;
key = (service_id & (SEC_RULES_HASH_SZ - 1));
- mutex_lock(&security_rules_lock);
+ down_read(&security_rules_lock_lha4);
/* Return the rule for a specific <service:instance>, if found. */
list_for_each_entry(rule, &security_rules[key], list) {
if ((rule->service_id == service_id) &&
(rule->instance_id == instance_id)) {
- mutex_unlock(&security_rules_lock);
+ up_read(&security_rules_lock_lha4);
return (void *)rule;
}
}
@@ -236,7 +242,7 @@
list_for_each_entry(rule, &security_rules[key], list) {
if ((rule->service_id == service_id) &&
(rule->instance_id == ALL_INSTANCE)) {
- mutex_unlock(&security_rules_lock);
+ up_read(&security_rules_lock_lha4);
return (void *)rule;
}
}
@@ -246,10 +252,11 @@
list_for_each_entry(rule, &security_rules[key], list) {
if ((rule->service_id == ALL_SERVICE) &&
(rule->instance_id == ALL_INSTANCE)) {
- mutex_unlock(&security_rules_lock);
+ up_read(&security_rules_lock_lha4);
return (void *)rule;
}
}
+ up_read(&security_rules_lock_lha4);
return NULL;
}
EXPORT_SYMBOL(msm_ipc_get_security_rule);
diff --git a/arch/arm/mach-msm/nohlt.c b/arch/arm/mach-msm/nohlt.c
index e598ed0..94cbc4b 100644
--- a/arch/arm/mach-msm/nohlt.c
+++ b/arch/arm/mach-msm/nohlt.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2009, 2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -28,11 +28,18 @@
return 0;
}
-DEFINE_SIMPLE_ATTRIBUTE(nohalt_ops, NULL, set_nohalt, "%llu\n");
+static int get_nohalt(void *data, u64 *val)
+{
+ *val = (unsigned int)get_hlt();
+
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(nohalt_ops, get_nohalt, set_nohalt, "%llu\n");
static int __init init_hlt_debug(void)
{
- debugfs_create_file("nohlt", 0200, NULL, NULL, &nohalt_ops);
+ debugfs_create_file("nohlt", 0600, NULL, NULL, &nohalt_ops);
return 0;
}
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index 4a54dd4..7792276 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -30,6 +30,7 @@
#include <linux/of_platform.h>
#include <linux/regulator/krait-regulator.h>
#include <linux/cpu.h>
+#include <linux/clk.h>
#include <mach/msm_iomap.h>
#include <mach/socinfo.h>
#include <mach/system.h>
@@ -131,6 +132,7 @@
static bool msm_no_ramp_down_pc;
static struct msm_pm_sleep_status_data *msm_pm_slp_sts;
static bool msm_pm_pc_reset_timer;
+static struct clk *pnoc_clk;
static int msm_pm_get_pc_mode(struct device_node *node,
const char *key, uint32_t *pc_mode_val)
@@ -884,7 +886,11 @@
case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE:
collapsed = msm_pm_power_collapse_standalone(true);
- exit_stat = MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE;
+ if (collapsed)
+ exit_stat = MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE;
+ else
+ exit_stat
+ = MSM_PM_STAT_IDLE_FAILED_STANDALONE_POWER_COLLAPSE;
break;
case MSM_PM_SLEEP_MODE_POWER_COLLAPSE:
@@ -894,7 +900,11 @@
collapsed = msm_pm_power_collapse(true);
timer_halted = true;
- exit_stat = MSM_PM_STAT_IDLE_POWER_COLLAPSE;
+ if (collapsed)
+ exit_stat = MSM_PM_STAT_IDLE_POWER_COLLAPSE;
+ else
+ exit_stat = MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE;
+
msm_pm_timer_exit_idle(timer_halted);
break;
@@ -930,13 +940,13 @@
int msm_pm_wait_cpu_shutdown(unsigned int cpu)
{
- int timeout = 10;
+ int timeout = 0;
if (!msm_pm_slp_sts)
return 0;
if (!msm_pm_slp_sts[cpu].base_addr)
return 0;
- while (timeout--) {
+ while (1) {
/*
* Check for the SPM of the core being hotplugged to set
* its sleep state.The SPM sleep state indicates that the
@@ -947,10 +957,10 @@
if (acc_sts & msm_pm_slp_sts[cpu].mask)
return 0;
udelay(100);
+ WARN(++timeout == 10, "CPU%u didn't collape within 1ms\n",
+ cpu);
}
- pr_info("%s(): Timed out waiting for CPU %u SPM to enter sleep state",
- __func__, cpu);
return -EBUSY;
}
@@ -1048,6 +1058,7 @@
int ret = -ENODEV;
uint32_t power;
uint32_t msm_pm_max_sleep_time = 0;
+ int collapsed = 0;
if (MSM_PM_DEBUG_SUSPEND & msm_pm_debug_mask)
pr_info("%s: power collapse\n", __func__);
@@ -1071,7 +1082,7 @@
msm_pm_max_sleep_time,
rs_limits, false, true);
if (!ret) {
- int collapsed = msm_pm_power_collapse(false);
+ collapsed = msm_pm_power_collapse(false);
if (pm_sleep_ops.exit_sleep) {
pm_sleep_ops.exit_sleep(rs_limits,
false, true, collapsed);
@@ -1082,7 +1093,10 @@
__func__);
}
time = msm_pm_timer_exit_suspend(time, period);
- msm_pm_add_stat(MSM_PM_STAT_SUSPEND, time);
+ if (collapsed)
+ msm_pm_add_stat(MSM_PM_STAT_SUSPEND, time);
+ else
+ msm_pm_add_stat(MSM_PM_STAT_FAILED_SUSPEND, time);
} else if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE]) {
if (MSM_PM_DEBUG_SUSPEND & msm_pm_debug_mask)
pr_info("%s: standalone power collapse\n", __func__);
@@ -1110,9 +1124,24 @@
pm_sleep_ops = *ops;
}
+int msm_suspend_prepare(void)
+{
+ if (pnoc_clk != NULL)
+ clk_disable_unprepare(pnoc_clk);
+ return 0;
+}
+
+void msm_suspend_wake(void)
+{
+ if (pnoc_clk != NULL)
+ clk_prepare_enable(pnoc_clk);
+}
+
static const struct platform_suspend_ops msm_pm_ops = {
.enter = msm_pm_enter,
.valid = suspend_valid_only_mem,
+ .prepare_late = msm_suspend_prepare,
+ .wake = msm_suspend_wake,
};
static int __devinit msm_pm_snoc_client_probe(struct platform_device *pdev)
@@ -1595,6 +1624,18 @@
return rc;
}
+ pnoc_clk = clk_get_sys("pm_8x60", "bus_clk");
+
+ if (IS_ERR(pnoc_clk))
+ pnoc_clk = NULL;
+ else {
+ clk_set_rate(pnoc_clk, 19200000);
+ rc = clk_prepare_enable(pnoc_clk);
+
+ if (rc)
+ pr_err("%s: PNOC clock enable failed\n", __func__);
+ }
+
return platform_driver_register(&msm_pm_8x60_driver);
}
device_initcall(msm_pm_8x60_init);
diff --git a/arch/arm/mach-msm/qdsp6v2/apr.c b/arch/arm/mach-msm/qdsp6v2/apr.c
index 6e60db1..8d9ad29 100644
--- a/arch/arm/mach-msm/qdsp6v2/apr.c
+++ b/arch/arm/mach-msm/qdsp6v2/apr.c
@@ -118,7 +118,7 @@
},
{
.name = "LSM",
- .idx = 9,
+ .idx = 10,
.id = APR_SVC_LSM,
.client_id = APR_CLIENT_AUDIO,
},
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index a177593..4649390 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -73,7 +73,6 @@
#endif
#define MODULE_NAME "msm_smd"
-#define SMEM_VERSION 0x000B
#define SMD_VERSION 0x00020000
#define SMSM_SNAPSHOT_CNT 64
#define SMSM_SNAPSHOT_SIZE ((SMSM_NUM_ENTRIES + 1) * 4)
@@ -3802,6 +3801,9 @@
{
int ret;
+ if (!smem_initialized_check())
+ return -ENODEV;
+
SMD_INFO("smd probe\n");
INIT_WORK(&probe_work, smd_channel_probe_worker);
diff --git a/arch/arm/mach-msm/smem.c b/arch/arm/mach-msm/smem.c
index 2204609..bbb6ce0 100644
--- a/arch/arm/mach-msm/smem.c
+++ b/arch/arm/mach-msm/smem.c
@@ -35,6 +35,10 @@
#define OVERFLOW_ADD_UNSIGNED(type, a, b) \
(((type)~0 - (a)) < (b) ? true : false)
+#define MODEM_SBL_VERSION_INDEX 7
+#define SMEM_VERSION_INFO_SIZE (32 * 4)
+#define SMEM_VERSION 0x000B
+
enum {
MSM_SMEM_DEBUG = 1U << 0,
MSM_SMEM_INFO = 1U << 1,
@@ -57,6 +61,7 @@
static void *smem_ramdump_dev;
static DEFINE_MUTEX(spinlock_init_lock);
+static DEFINE_SPINLOCK(smem_init_check_lock);
struct restart_notifier_block {
unsigned processor;
@@ -187,12 +192,48 @@
}
EXPORT_SYMBOL(smem_alloc);
-void *smem_find(unsigned id, unsigned size_in)
+static void *__smem_get_entry(unsigned id, unsigned *size, bool skip_init_check)
+{
+ struct smem_shared *shared = (void *) MSM_SHARED_RAM_BASE;
+ struct smem_heap_entry *toc = shared->heap_toc;
+ int use_spinlocks = spinlocks_initialized;
+ void *ret = 0;
+ unsigned long flags = 0;
+
+ if (!skip_init_check && !smem_initialized_check())
+ return ret;
+
+ if (id >= SMEM_NUM_ITEMS)
+ return ret;
+
+ if (use_spinlocks)
+ remote_spin_lock_irqsave(&remote_spinlock, flags);
+ /* toc is in device memory and cannot be speculatively accessed */
+ if (toc[id].allocated) {
+ phys_addr_t phys_base;
+
+ *size = toc[id].size;
+ barrier();
+
+ phys_base = toc[id].reserved & BASE_ADDR_MASK;
+ if (!phys_base)
+ phys_base = (phys_addr_t)msm_shared_ram_phys;
+ ret = smem_phys_to_virt(phys_base, toc[id].offset);
+ } else {
+ *size = 0;
+ }
+ if (use_spinlocks)
+ remote_spin_unlock_irqrestore(&remote_spinlock, flags);
+
+ return ret;
+}
+
+static void *__smem_find(unsigned id, unsigned size_in, bool skip_init_check)
{
unsigned size;
void *ptr;
- ptr = smem_get_entry(id, &size);
+ ptr = __smem_get_entry(id, &size, skip_init_check);
if (!ptr)
return 0;
@@ -205,6 +246,11 @@
return ptr;
}
+
+void *smem_find(unsigned id, unsigned size_in)
+{
+ return __smem_find(id, size_in, false);
+}
EXPORT_SYMBOL(smem_find);
/* smem_alloc2 returns the pointer to smem item. If it is not allocated,
@@ -218,10 +264,8 @@
void *ret = NULL;
int rc;
- if (!shared->heap_info.initialized) {
- pr_err("%s: smem heap info not initialized\n", __func__);
+ if (!smem_initialized_check())
return NULL;
- }
if (id >= SMEM_NUM_ITEMS)
return NULL;
@@ -268,35 +312,7 @@
void *smem_get_entry(unsigned id, unsigned *size)
{
- struct smem_shared *shared = (void *) MSM_SHARED_RAM_BASE;
- struct smem_heap_entry *toc = shared->heap_toc;
- int use_spinlocks = spinlocks_initialized;
- void *ret = 0;
- unsigned long flags = 0;
-
- if (id >= SMEM_NUM_ITEMS)
- return ret;
-
- if (use_spinlocks)
- remote_spin_lock_irqsave(&remote_spinlock, flags);
- /* toc is in device memory and cannot be speculatively accessed */
- if (toc[id].allocated) {
- phys_addr_t phys_base;
-
- *size = toc[id].size;
- barrier();
-
- phys_base = toc[id].reserved & BASE_ADDR_MASK;
- if (!phys_base)
- phys_base = (phys_addr_t)msm_shared_ram_phys;
- ret = smem_phys_to_virt(phys_base, toc[id].offset);
- } else {
- *size = 0;
- }
- if (use_spinlocks)
- remote_spin_unlock_irqrestore(&remote_spinlock, flags);
-
- return ret;
+ return __smem_get_entry(id, size, false);
}
EXPORT_SYMBOL(smem_get_entry);
@@ -341,6 +357,62 @@
return rc;
}
+/**
+ * smem_initialized_check - Reentrant check that smem has been initialized
+ *
+ * @returns: true if initialized, false if not.
+ */
+bool smem_initialized_check(void)
+{
+ static int checked;
+ static int is_inited;
+ unsigned long flags;
+ struct smem_shared *smem;
+ int *version_array;
+
+ if (likely(checked)) {
+ if (unlikely(!is_inited))
+ pr_err("%s: smem not initialized\n", __func__);
+ return is_inited;
+ }
+
+ spin_lock_irqsave(&smem_init_check_lock, flags);
+ if (checked) {
+ spin_unlock_irqrestore(&smem_init_check_lock, flags);
+ if (unlikely(!is_inited))
+ pr_err("%s: smem not initialized\n", __func__);
+ return is_inited;
+ }
+
+ smem = (void *)MSM_SHARED_RAM_BASE;
+
+ if (smem->heap_info.initialized != 1)
+ goto failed;
+ if (smem->heap_info.reserved != 0)
+ goto failed;
+
+ version_array = __smem_find(SMEM_VERSION_INFO, SMEM_VERSION_INFO_SIZE,
+ true);
+ if (version_array == NULL)
+ goto failed;
+ if (version_array[MODEM_SBL_VERSION_INDEX] != SMEM_VERSION << 16)
+ goto failed;
+
+ is_inited = 1;
+ checked = 1;
+ spin_unlock_irqrestore(&smem_init_check_lock, flags);
+ return is_inited;
+
+failed:
+ is_inited = 0;
+ checked = 1;
+ spin_unlock_irqrestore(&smem_init_check_lock, flags);
+ pr_err("%s: bootloader failure detected, shared memory not inited\n",
+ __func__);
+ return is_inited;
+}
+EXPORT_SYMBOL(smem_initialized_check);
+
static int restart_notifier_cb(struct notifier_block *this,
unsigned long code,
void *data)
diff --git a/arch/arm/mach-msm/smem_private.h b/arch/arm/mach-msm/smem_private.h
index b631e7c..c4f9a77 100644
--- a/arch/arm/mach-msm/smem_private.h
+++ b/arch/arm/mach-msm/smem_private.h
@@ -71,4 +71,6 @@
* spinlock init code appears non-reentrant
*/
int init_smem_remote_spinlock(void);
+
+bool smem_initialized_check(void);
#endif /* _ARCH_ARM_MACH_MSM_SMEM_PRIVATE_H_ */
diff --git a/arch/arm/mach-msm/subsystem_restart.c b/arch/arm/mach-msm/subsystem_restart.c
index b956649..8e507ff 100644
--- a/arch/arm/mach-msm/subsystem_restart.c
+++ b/arch/arm/mach-msm/subsystem_restart.c
@@ -427,8 +427,10 @@
ret = wait_for_completion_timeout(&subsys->err_ready,
msecs_to_jiffies(10000));
- if (!ret)
+ if (!ret) {
+ pr_err("[%s]: Error ready timed out\n", subsys->desc->name);
return -ETIMEDOUT;
+ }
return 0;
}
diff --git a/arch/arm/mach-msm/wallclk.c b/arch/arm/mach-msm/wallclk.c
new file mode 100644
index 0000000..9624795
--- /dev/null
+++ b/arch/arm/mach-msm/wallclk.c
@@ -0,0 +1,475 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/semaphore.h>
+#include <linux/kthread.h>
+#include <linux/sched.h>
+#include <linux/hrtimer.h>
+#include <linux/timer.h>
+#include <linux/io.h>
+#include <linux/ctype.h>
+#include <linux/uaccess.h>
+#include <linux/errno.h>
+
+#include <mach/msm_iomap.h>
+
+#include "wallclk.h"
+
+#define WALLCLK_MODULE_NAME "wallclk"
+#define WALLCLK_MODULE_NAME_LEN 10
+
+#define FLAG_WALLCLK_INITED 0x1
+#define FLAG_WALLCLK_SFN_REF_SET 0x2
+#define FLAG_WALLCLK_ENABLED 0x4
+
+#define WALLCLK_TIMER_INTERVAL_NS 100000
+
+#define WALLCLK_SHARED_MEM_SIZE 1024
+#define ALIGN_64(addr) (((addr) + 7) & ~0x7)
+
+#define GPS_EPOCH_DIFF 315964800
+
+struct wallclk_cnt {
+ u32 pulse;
+ u32 clk;
+};
+
+struct wallclk_reg {
+ u32 ctrl;
+ u32 pulse_cnt;
+ u32 snapshot_clock_cnt;
+ u32 clock_cnt;
+ u32 __unused__[5];
+ u32 base_time0;
+ u32 base_time1;
+};
+
+struct wallclk_sm {
+ struct wallclk_reg reg;
+ u32 sfn_ref;
+};
+
+struct wallclk_cfg {
+ u32 ppns;
+ u32 clk_rate;
+ u32 clk_rate_v; /* clk_rate = clk_rate_v x clk_rate_p */
+ u32 clk_rate_p; /* power of 10 */
+ u32 ns_per_clk_rate_v;
+};
+
+struct wallclk {
+ struct wallclk_sm *shm;
+
+ struct wallclk_cfg cfg;
+
+ struct timespec tv;
+
+ struct hrtimer timer;
+ ktime_t interval;
+
+ spinlock_t lock;
+ u32 flags;
+
+ char name[WALLCLK_MODULE_NAME_LEN];
+};
+
+static struct wallclk wall_clk;
+
+static inline int is_valid_register(u32 offset)
+{
+ int rc = 0;
+
+ switch (offset) {
+ case CTRL_REG_OFFSET:
+ case PULSE_CNT_REG_OFFSET:
+ case CLK_CNT_SNAPSHOT_REG_OFFSET:
+ case CLK_CNT_REG_OFFSET:
+ case CLK_BASE_TIME0_OFFSET:
+ case CLK_BASE_TIME1_OFFSET:
+ rc = 1;
+ break;
+ default:
+ break;
+ }
+ return rc;
+}
+
+static inline void wallclk_ctrl_reg_set(struct wallclk *wclk, u32 v)
+{
+ struct wallclk_reg *reg = &wclk->shm->reg;
+
+ if (v & CTRL_ENABLE_MASK) {
+ if (!(wclk->flags & FLAG_WALLCLK_ENABLED)) {
+ getnstimeofday(&wclk->tv);
+ __raw_writel(0, ®->snapshot_clock_cnt);
+ __raw_writel(0, ®->clock_cnt);
+ __raw_writel(0, ®->pulse_cnt);
+ hrtimer_start(&wclk->timer,
+ wclk->interval,
+ HRTIMER_MODE_REL);
+ wclk->flags |= FLAG_WALLCLK_ENABLED;
+ }
+ } else {
+ if (wclk->flags & FLAG_WALLCLK_ENABLED) {
+ hrtimer_cancel(&wclk->timer);
+ wclk->flags &= ~FLAG_WALLCLK_ENABLED;
+ }
+ }
+
+ __raw_writel(v, ®->ctrl);
+}
+
+static inline void wallclk_cfg_init(struct wallclk_cfg *cfg,
+ u32 ppns,
+ u32 clk_rate)
+{
+ cfg->ppns = ppns;
+ cfg->clk_rate = clk_rate;
+ cfg->clk_rate_v = clk_rate;
+ cfg->clk_rate_p = 1;
+ cfg->ns_per_clk_rate_v = 1000000000;
+
+ while (!(cfg->clk_rate_v % 10)) {
+ cfg->clk_rate_v /= 10;
+ cfg->clk_rate_p *= 10;
+ cfg->ns_per_clk_rate_v /= 10;
+ }
+}
+
+static inline struct timespec timestamp_convert(const struct timespec *tv)
+{
+ struct timespec rc;
+
+ rc.tv_sec = tv->tv_sec - GPS_EPOCH_DIFF;
+ rc.tv_nsec = tv->tv_nsec;
+
+ return rc;
+}
+
+static inline void timespec_delta_to_wclk_cnt(const struct timespec *tv,
+ const struct wallclk_cfg *cfg,
+ struct wallclk_cnt *wclk_cnt)
+{
+ long ns;
+
+ wclk_cnt->pulse = tv->tv_sec / cfg->ppns;
+ wclk_cnt->clk = (tv->tv_sec % cfg->ppns) * cfg->clk_rate;
+
+ ns = tv->tv_nsec;
+ while (ns >= cfg->ns_per_clk_rate_v) {
+ ns -= cfg->ns_per_clk_rate_v;
+ wclk_cnt->clk += cfg->clk_rate_v;
+ }
+
+ wclk_cnt->clk += (ns * cfg->clk_rate_v)/cfg->ns_per_clk_rate_v;
+}
+
+static inline u32 wallclk_cnt_to_sfn(const struct wallclk_cnt *cnt,
+ const struct wallclk_cfg *cfg)
+{
+ u32 sfn;
+ u32 delta, p;
+
+ sfn = SFN_PER_SECOND * cnt->pulse * cfg->ppns;
+ if (cfg->clk_rate_p > 100) {
+ p = cfg->clk_rate_p/100;
+ delta = cnt->clk/(cfg->clk_rate_v * p);
+ } else {
+ p = 100/cfg->clk_rate_p;
+ delta = (cnt->clk * p)/cfg->clk_rate_v;
+ }
+ sfn += delta;
+
+ return sfn;
+}
+
+static void update_wallclk(struct wallclk *wclk)
+{
+ struct timespec tv;
+ struct timespec delta_tv;
+ struct wallclk_cnt cnt;
+ struct wallclk_reg *reg = &wclk->shm->reg;
+
+ spin_lock(&wclk->lock);
+ getnstimeofday(&tv);
+ delta_tv = timespec_sub(tv, wclk->tv);
+ timespec_delta_to_wclk_cnt(&delta_tv, &wclk->cfg, &cnt);
+ __raw_writel(cnt.pulse, ®->pulse_cnt);
+ __raw_writel(cnt.clk, ®->clock_cnt);
+ __raw_writel(cnt.clk, ®->snapshot_clock_cnt);
+
+ spin_unlock(&wclk->lock);
+}
+
+static int set_sfn(struct wallclk *wclk, u16 sfn)
+{
+ int rc = 0;
+ struct wallclk_reg *reg = &wclk->shm->reg;
+ u32 v;
+ struct timespec ts;
+
+ if (sfn > MAX_SFN) {
+ rc = -EINVAL;
+ goto out;
+ }
+
+ if (!(wclk->flags & FLAG_WALLCLK_INITED)) {
+ rc = -EIO;
+ goto out;
+ }
+
+ spin_lock_bh(&wclk->lock);
+
+ v = __raw_readl(®->ctrl);
+ wallclk_ctrl_reg_set(wclk, v & ~CTRL_ENABLE_MASK);
+
+ getnstimeofday(&wclk->tv);
+ ts = timestamp_convert(&wclk->tv);
+ __raw_writel(ts.tv_sec, ®->base_time0);
+ __raw_writel(ts.tv_nsec, ®->base_time1);
+
+ wclk->shm->sfn_ref = sfn;
+ wclk->flags |= FLAG_WALLCLK_SFN_REF_SET;
+
+ __raw_writel(0, ®->pulse_cnt);
+ __raw_writel(0, ®->clock_cnt);
+ __raw_writel(0, ®->snapshot_clock_cnt);
+ hrtimer_start(&wclk->timer, wclk->interval, HRTIMER_MODE_REL);
+ wclk->flags |= FLAG_WALLCLK_ENABLED;
+ __raw_writel(v | CTRL_ENABLE_MASK, ®->ctrl);
+
+ spin_unlock_bh(&wclk->lock);
+
+out:
+ return rc;
+}
+
+static int get_sfn(struct wallclk *wclk)
+{
+ struct wallclk_cnt cnt;
+ int rc = 0;
+ u32 sfn;
+
+ if (!(wclk->flags & FLAG_WALLCLK_INITED)) {
+ rc = -EIO;
+ goto out;
+ }
+
+ spin_lock_bh(&wclk->lock);
+
+ if (!(wclk->flags & FLAG_WALLCLK_ENABLED) ||
+ !(wclk->flags & FLAG_WALLCLK_SFN_REF_SET)) {
+ rc = -EIO;
+ goto unlock;
+ }
+
+ cnt.pulse = __raw_readl(&(wclk->shm->reg.pulse_cnt));
+ cnt.clk = __raw_readl(&(wclk->shm->reg.clock_cnt));
+ sfn = wallclk_cnt_to_sfn(&cnt, &wclk->cfg);
+
+ sfn += wclk->shm->sfn_ref;
+ rc = sfn & MAX_SFN;
+
+unlock:
+ spin_unlock_bh(&wclk->lock);
+out:
+ return rc;
+}
+
+enum hrtimer_restart wallclk_timer_cb(struct hrtimer *timer)
+{
+ update_wallclk(&wall_clk);
+ hrtimer_forward_now(timer, wall_clk.interval);
+ return HRTIMER_RESTART;
+}
+
+int wallclk_set_sfn(u16 sfn)
+{
+ return set_sfn(&wall_clk, sfn);
+}
+EXPORT_SYMBOL_GPL(wallclk_set_sfn);
+
+int wallclk_get_sfn(void)
+{
+ return get_sfn(&wall_clk);
+}
+EXPORT_SYMBOL_GPL(wallclk_get_sfn);
+
+int wallclk_set_sfn_ref(u16 sfn)
+{
+ int rc = 0;
+
+ if (sfn > MAX_SFN) {
+ rc = -EINVAL;
+ goto out;
+ }
+
+ if (!(wall_clk.flags & FLAG_WALLCLK_INITED)) {
+ rc = -EIO;
+ goto out;
+ }
+
+ spin_lock_bh(&wall_clk.lock);
+
+ wall_clk.shm->sfn_ref = sfn;
+ wall_clk.flags |= FLAG_WALLCLK_SFN_REF_SET;
+
+ spin_unlock_bh(&wall_clk.lock);
+
+out:
+ return rc;
+}
+EXPORT_SYMBOL_GPL(wallclk_set_sfn_ref);
+
+int wallclk_get_sfn_ref(void)
+{
+ int rc = 0;
+
+ if (!(wall_clk.flags & FLAG_WALLCLK_INITED)) {
+ rc = -EIO;
+ goto out;
+ }
+
+ spin_lock_bh(&wall_clk.lock);
+
+ if (!(wall_clk.flags & FLAG_WALLCLK_SFN_REF_SET)) {
+ rc = -EAGAIN;
+ goto unlock;
+ }
+ rc = wall_clk.shm->sfn_ref;
+
+unlock:
+ spin_unlock_bh(&wall_clk.lock);
+out:
+ return rc;
+}
+EXPORT_SYMBOL_GPL(wallclk_get_sfn_ref);
+
+int wallclk_reg_read(u32 offset, u32 *p)
+{
+ int rc = 0;
+
+ if (!(wall_clk.flags & FLAG_WALLCLK_INITED)) {
+ rc = -EIO;
+ goto out;
+ }
+
+ if (!is_valid_register(offset)) {
+ rc = -EINVAL;
+ goto out;
+ }
+
+ spin_lock_bh(&wall_clk.lock);
+ *p = __raw_readl((char *)&wall_clk.shm->reg + offset);
+ spin_unlock_bh(&wall_clk.lock);
+out:
+ return rc;
+}
+EXPORT_SYMBOL_GPL(wallclk_reg_read);
+
+int wallclk_reg_write(u32 offset, u32 val)
+{
+ int rc = 0;
+ char *p;
+
+ if (!(wall_clk.flags & FLAG_WALLCLK_INITED)) {
+ rc = -EIO;
+ goto out;
+ }
+
+ p = (char *)&wall_clk.shm->reg;
+
+ spin_lock_bh(&wall_clk.lock);
+ switch (offset) {
+ case CTRL_REG_OFFSET:
+ wallclk_ctrl_reg_set(&wall_clk, val);
+ break;
+ case PULSE_CNT_REG_OFFSET:
+ case CLK_BASE_TIME0_OFFSET:
+ case CLK_BASE_TIME1_OFFSET:
+ __raw_writel(val, p + offset);
+ break;
+ case CLK_CNT_REG_OFFSET:
+ __raw_writel(val, p + CLK_CNT_REG_OFFSET);
+ __raw_writel(val, p + CLK_CNT_SNAPSHOT_REG_OFFSET);
+ break;
+ case CLK_CNT_SNAPSHOT_REG_OFFSET:
+ rc = -EIO;
+ break;
+ default:
+ rc = -EINVAL;
+ break;
+ }
+
+ spin_unlock_bh(&wall_clk.lock);
+out:
+ return rc;
+}
+EXPORT_SYMBOL_GPL(wallclk_reg_write);
+
+static int __init wallclk_init(void)
+{
+ int rc = 0;
+ u32 addr;
+
+ memset(&wall_clk, 0, sizeof(wall_clk));
+
+ addr = (u32)MSM_SHARED_RAM_BASE + MSM_SHARED_RAM_SIZE -
+ WALLCLK_SHARED_MEM_SIZE;
+ wall_clk.shm = (struct wallclk_sm *)ALIGN_64(addr);
+
+ __raw_writel(0, &(wall_clk.shm->reg.ctrl));
+ __raw_writel(0, &(wall_clk.shm->reg.pulse_cnt));
+ __raw_writel(0, &(wall_clk.shm->reg.snapshot_clock_cnt));
+ __raw_writel(0, &(wall_clk.shm->reg.clock_cnt));
+ __raw_writel(0, &(wall_clk.shm->reg.clock_cnt));
+ __raw_writel(0, &(wall_clk.shm->reg.base_time0));
+ __raw_writel(0, &(wall_clk.shm->reg.base_time1));
+
+ wall_clk.shm->sfn_ref = 0;
+
+ wallclk_cfg_init(&wall_clk.cfg, PPNS_PULSE, CLK_RATE);
+
+ strlcpy(wall_clk.name, WALLCLK_MODULE_NAME, WALLCLK_MODULE_NAME_LEN);
+
+ hrtimer_init(&wall_clk.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ wall_clk.timer.function = wallclk_timer_cb;
+ wall_clk.interval = ns_to_ktime(WALLCLK_TIMER_INTERVAL_NS);
+ spin_lock_init(&wall_clk.lock);
+
+ wall_clk.flags |= FLAG_WALLCLK_INITED;
+
+ printk(KERN_INFO "%s: clk_rate=%u ppns=%u clk_reg_addr=0x%x\n",
+ wall_clk.name, wall_clk.cfg.clk_rate, wall_clk.cfg.ppns,
+ (int)(&wall_clk.shm->reg));
+ return rc;
+}
+
+static void __exit wallclk_exit(void)
+{
+ if (wall_clk.flags & FLAG_WALLCLK_INITED) {
+ spin_lock_bh(&wall_clk.lock);
+ wallclk_ctrl_reg_set(&wall_clk, 0);
+ wall_clk.flags = 0;
+ spin_unlock_bh(&wall_clk.lock);
+ }
+}
+
+module_init(wallclk_init);
+module_exit(wallclk_exit);
+
+MODULE_DESCRIPTION("Wall clock");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/wallclk.h b/arch/arm/mach-msm/wallclk.h
new file mode 100644
index 0000000..1794395
--- /dev/null
+++ b/arch/arm/mach-msm/wallclk.h
@@ -0,0 +1,46 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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 _WALLCLK_H
+#define _WALLCLK_H
+
+/* wallclock register offset */
+#define CTRL_REG_OFFSET 0x0
+#define PULSE_CNT_REG_OFFSET 0x4
+#define CLK_CNT_SNAPSHOT_REG_OFFSET 0x8
+#define CLK_CNT_REG_OFFSET 0xC
+#define CLK_BASE_TIME0_OFFSET 0x24
+#define CLK_BASE_TIME1_OFFSET 0x28
+
+/* ctrl register bitmap */
+#define CTRL_TIME_SRC_POS 0
+#define CTRL_TIME_SRC_MASK 0x0000000F
+#define CTRL_SW_BITS_POS 4
+#define CTRL_SW_BITS_MASK 0x7FFFFFF0
+#define CTRL_ENA_DIS_POS 31
+#define CTRL_ENABLE_MASK 0x80000000
+
+/* clock rate from time source */
+#define CLK_RATE 122880000 /* 122.88 Mhz */
+#define PPNS_PULSE 2 /* PP2S */
+
+#define MAX_SFN 1023
+#define SFN_PER_SECOND 100
+
+extern int wallclk_set_sfn(u16 sfn);
+extern int wallclk_get_sfn(void);
+extern int wallclk_set_sfn_ref(u16 sfn);
+extern int wallclk_get_sfn_ref(void);
+extern int wallclk_reg_read(u32 offset, u32 *p);
+extern int wallclk_reg_write(u32 offset, u32 value);
+
+#endif /* _WALLCLK_H */
diff --git a/arch/arm/mach-msm/wallclk_sysfs.c b/arch/arm/mach-msm/wallclk_sysfs.c
new file mode 100644
index 0000000..9274137
--- /dev/null
+++ b/arch/arm/mach-msm/wallclk_sysfs.c
@@ -0,0 +1,308 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/semaphore.h>
+#include <linux/kthread.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/ctype.h>
+#include <linux/uaccess.h>
+#include <linux/errno.h>
+
+#include "wallclk.h"
+
+#define WALLCLK_SYSFS_MODULE_NAME "wallclk_sysfs"
+
+static struct kobject *wallclk_kobj;
+
+static ssize_t sfn_show(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ char *buf)
+{
+ int rc;
+
+ rc = wallclk_get_sfn();
+ if (rc < 0)
+ return rc;
+ return snprintf(buf, 10, "%d\n", rc);
+}
+
+static ssize_t sfn_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ u16 sfn;
+ int rc;
+
+ if (kstrtou16(buf, 0, &sfn)) {
+ printk(KERN_ERR "%s: sfn input is not a valid u16 value\n",
+ WALLCLK_SYSFS_MODULE_NAME);
+ rc = -EINVAL;
+ goto out;
+ }
+
+ rc = wallclk_set_sfn(sfn);
+
+ if (rc) {
+ printk(KERN_ERR "%s: fail to set sfn\n",
+ WALLCLK_SYSFS_MODULE_NAME);
+ goto out;
+ }
+ rc = count;
+
+out:
+ return rc;
+}
+
+static struct kobj_attribute sfn_attribute =
+ __ATTR(sfn, 0666, sfn_show, sfn_store);
+
+static ssize_t sfn_ref_show(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ char *buf)
+{
+ int rc;
+
+ rc = wallclk_get_sfn_ref();
+ if (rc < 0)
+ return rc;
+ return snprintf(buf, 10, "%d\n", rc);
+}
+
+static ssize_t sfn_ref_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ u16 sfn_ref;
+ int rc;
+
+ if (kstrtou16(buf, 0, &sfn_ref)) {
+ printk(KERN_ERR "%s: sfn_ref input is not a valid u16 value\n",
+ WALLCLK_SYSFS_MODULE_NAME);
+ rc = -EINVAL;
+ goto out;
+ }
+
+ rc = wallclk_set_sfn_ref(sfn_ref);
+
+ if (rc) {
+ printk(KERN_ERR "%s: fail to set sfn_ref\n",
+ WALLCLK_SYSFS_MODULE_NAME);
+ goto out;
+ }
+ rc = count;
+
+out:
+ return rc;
+}
+
+static struct kobj_attribute sfn_ref_attribute =
+ __ATTR(sfn_ref, 0666, sfn_ref_show, sfn_ref_store);
+
+static ssize_t reg_show(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ char *buf,
+ u32 offset)
+{
+ int rc;
+ u32 val;
+
+ rc = wallclk_reg_read(offset, &val);
+ if (rc)
+ return rc;
+
+ return snprintf(buf, 20, "%08x\n", val);
+}
+
+static ssize_t reg_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf,
+ const size_t count,
+ u32 offset)
+{
+ u32 v;
+ int rc;
+
+ if (kstrtou32(buf, 0, &v)) {
+ printk(KERN_ERR "%s: input is not a valid u32 value\n",
+ WALLCLK_SYSFS_MODULE_NAME);
+ rc = -EINVAL;
+ goto out;
+ }
+
+ rc = wallclk_reg_write(offset, v);
+
+ if (rc) {
+ printk(KERN_ERR "%s: fail to set register(offset=0x%x)\n",
+ WALLCLK_SYSFS_MODULE_NAME, offset);
+ goto out;
+ }
+ rc = count;
+
+out:
+ return rc;
+}
+
+static ssize_t ctrl_reg_show(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ char *buf)
+{
+ return reg_show(kobj, attr, buf, CTRL_REG_OFFSET);
+}
+
+static ssize_t ctrl_reg_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf,
+ const size_t count)
+{
+ return reg_store(kobj, attr, buf, count, CTRL_REG_OFFSET);
+}
+
+static struct kobj_attribute ctrl_reg_attribute =
+ __ATTR(ctrl_reg, 0666, ctrl_reg_show, ctrl_reg_store);
+
+static ssize_t basetime0_reg_show(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ char *buf)
+{
+ return reg_show(kobj, attr, buf, CLK_BASE_TIME0_OFFSET);
+}
+
+static ssize_t basetime0_reg_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ return reg_store(kobj, attr, buf, count, CLK_BASE_TIME0_OFFSET);
+}
+
+static struct kobj_attribute basetime0_reg_attribute =
+ __ATTR(base_time0_reg, 0666, basetime0_reg_show, basetime0_reg_store);
+
+static ssize_t basetime1_reg_show(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ char *buf)
+{
+ return reg_show(kobj, attr, buf, CLK_BASE_TIME1_OFFSET);
+}
+
+static ssize_t basetime1_reg_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ return reg_store(kobj, attr, buf, count, CLK_BASE_TIME1_OFFSET);
+}
+
+static struct kobj_attribute basetime1_reg_attribute =
+ __ATTR(base_time1_reg, 0666, basetime1_reg_show, basetime1_reg_store);
+
+static ssize_t pulse_cnt_reg_show(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ char *buf)
+{
+ return reg_show(kobj, attr, buf, PULSE_CNT_REG_OFFSET);
+}
+
+static ssize_t pulse_cnt_reg_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ return reg_store(kobj, attr, buf, count, PULSE_CNT_REG_OFFSET);
+}
+
+static struct kobj_attribute pulse_cnt_reg_attribute =
+ __ATTR(pulse_cnt_reg, 0666, pulse_cnt_reg_show, pulse_cnt_reg_store);
+
+static ssize_t clk_cnt_reg_show(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ char *buf)
+{
+ return reg_show(kobj, attr, buf, CLK_CNT_REG_OFFSET);
+}
+
+static ssize_t clk_cnt_reg_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ return reg_store(kobj, attr, buf, count, CLK_CNT_REG_OFFSET);
+}
+
+static struct kobj_attribute clk_cnt_reg_attribute =
+ __ATTR(clock_cnt_reg, 0666, clk_cnt_reg_show, clk_cnt_reg_store);
+
+static ssize_t clk_cnt_snapshot_reg_show(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ char *buf)
+{
+ return reg_show(kobj, attr, buf, CLK_CNT_SNAPSHOT_REG_OFFSET);
+}
+
+static struct kobj_attribute clk_cnt_snapshot_reg_attribute =
+ __ATTR(clock_cnt_snapshot_reg, 0444, clk_cnt_snapshot_reg_show, NULL);
+
+static struct attribute *wallclk_attrs[] = {
+ &sfn_attribute.attr,
+ &sfn_ref_attribute.attr,
+ &ctrl_reg_attribute.attr,
+ &pulse_cnt_reg_attribute.attr,
+ &clk_cnt_snapshot_reg_attribute.attr,
+ &clk_cnt_reg_attribute.attr,
+ &basetime0_reg_attribute.attr,
+ &basetime1_reg_attribute.attr,
+ NULL
+};
+
+static struct attribute_group wallclk_attr_group = {
+ .attrs = wallclk_attrs,
+};
+
+static int __init wallclk_sysfs_init(void)
+{
+ int rc;
+
+ wallclk_kobj = kobject_create_and_add("wallclk", kernel_kobj);
+ if (!wallclk_kobj) {
+ printk(KERN_ERR "%s: failed to create kobject\n",
+ WALLCLK_SYSFS_MODULE_NAME);
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ rc = sysfs_create_group(wallclk_kobj, &wallclk_attr_group);
+ if (rc) {
+ kobject_put(wallclk_kobj);
+ printk(KERN_ERR "%s: failed to create sysfs group\n",
+ WALLCLK_SYSFS_MODULE_NAME);
+ }
+
+out:
+ return rc;
+}
+
+static void __exit wallclk_sysfs_exit(void)
+{
+ kobject_put(wallclk_kobj);
+}
+
+module_init(wallclk_sysfs_init);
+module_exit(wallclk_sysfs_exit);
+
+MODULE_DESCRIPTION("Wall clock SysFS");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c
index 682d876..9b404c6 100644
--- a/drivers/char/diag/diag_dci.c
+++ b/drivers/char/diag/diag_dci.c
@@ -58,14 +58,14 @@
pr_debug("diag: bytes read = %d, single dci pkt len = %d\n",
read_bytes, dci_pkt_len);
/* print_hex_dump(KERN_DEBUG, "Single DCI packet :",
- DUMP_PREFIX_ADDRESS, 16, 1, buf, 5 + dci_pkt_len, 1);*/
+ DUMP_PREFIX_ADDRESS, 16, 1, buf, 5 + dci_pkt_len, 1); */
recv_pkt_cmd_code = *(uint8_t *)(buf+4);
if (recv_pkt_cmd_code == LOG_CMD_CODE)
extract_dci_log(buf+4);
else if (recv_pkt_cmd_code == EVENT_CMD_CODE)
extract_dci_events(buf+4);
else
- extract_dci_pkt_rsp(buf); /* pkt response */
+ extract_dci_pkt_rsp(smd_info, buf); /* pkt response */
read_bytes += 5 + dci_pkt_len;
buf += 5 + dci_pkt_len; /* advance to next DCI pkt */
}
@@ -83,7 +83,7 @@
return 0;
}
-void extract_dci_pkt_rsp(unsigned char *buf)
+void extract_dci_pkt_rsp(struct diag_smd_info *smd_info, unsigned char *buf)
{
int i = 0, index = -1, cmd_code_len = 1;
int curr_client_pid = 0, write_len;
@@ -95,6 +95,7 @@
if (recv_pkt_cmd_code != DCI_PKT_RSP_CODE)
cmd_code_len = 4; /* delayed response */
write_len = (int)(*(uint16_t *)(buf+2)) - cmd_code_len;
+
pr_debug("diag: len = %d\n", write_len);
/* look up DCI client with tag */
for (i = 0; i < dci_max_reg; i++) {
@@ -139,8 +140,7 @@
buf+4+cmd_code_len, write_len);
entry->data_len += write_len;
/* delete immediate response entry */
- if (driver->smd_dci[MODEM_DATA].
- buf_in_1[8+cmd_code_len] != 0x80)
+ if (smd_info->buf_in_1[8+cmd_code_len] != 0x80)
driver->req_tracking_tbl[index].pid = 0;
}
}
@@ -372,26 +372,6 @@
} /* end of loop for all DCI clients */
}
-static int diag_dci_probe(struct platform_device *pdev)
-{
- int err = 0;
- int index;
-
- if (pdev->id == SMD_APPS_MODEM) {
- index = MODEM_DATA;
- err = smd_open("DIAG_2", &driver->smd_dci[index].ch,
- &driver->smd_dci[index],
- diag_smd_notify);
- driver->smd_dci[index].ch_save =
- driver->smd_dci[index].ch;
- if (err)
- pr_err("diag: In %s, cannot open DCI port, Id = %d, err: %d\n",
- __func__, pdev->id, err);
- }
-
- return err;
-}
-
int diag_send_dci_pkt(struct diag_master_table entry, unsigned char *buf,
int len, int index)
{
@@ -418,9 +398,12 @@
driver->apps_dci_buf[9+len] = CONTROL_CHAR; /* end */
for (i = 0; i < NUM_SMD_DCI_CHANNELS; i++) {
- if (entry.client_id == driver->smd_dci[i].peripheral) {
- if (driver->smd_dci[i].ch) {
- smd_write(driver->smd_dci[i].ch,
+ struct diag_smd_info *smd_info = driver->separate_cmdrsp[i] ?
+ &driver->smd_dci_cmd[i] :
+ &driver->smd_dci[i];
+ if (entry.client_id == smd_info->peripheral) {
+ if (smd_info->ch) {
+ smd_write(smd_info->ch,
driver->apps_dci_buf, len + 10);
status = DIAG_DCI_NO_ERROR;
}
@@ -1000,6 +983,49 @@
memset(tbl_buf, 0, 512);
}
+static int diag_dci_probe(struct platform_device *pdev)
+{
+ int err = 0;
+ int index;
+
+ if (pdev->id == SMD_APPS_MODEM) {
+ index = MODEM_DATA;
+ err = smd_open("DIAG_2",
+ &driver->smd_dci[index].ch,
+ &driver->smd_dci[index],
+ diag_smd_notify);
+ driver->smd_dci[index].ch_save =
+ driver->smd_dci[index].ch;
+ if (err)
+ pr_err("diag: In %s, cannot open DCI port, Id = %d, err: %d\n",
+ __func__, pdev->id, err);
+ }
+
+ return err;
+}
+
+static int diag_dci_cmd_probe(struct platform_device *pdev)
+{
+ int err = 0;
+ int index;
+
+ if (pdev->id == SMD_APPS_MODEM) {
+ index = MODEM_DATA;
+ err = smd_named_open_on_edge("DIAG_2_CMD",
+ pdev->id,
+ &driver->smd_dci_cmd[index].ch,
+ &driver->smd_dci_cmd[index],
+ diag_smd_notify);
+ driver->smd_dci_cmd[index].ch_save =
+ driver->smd_dci_cmd[index].ch;
+ if (err)
+ pr_err("diag: In %s, cannot open DCI port, Id = %d, err: %d\n",
+ __func__, pdev->id, err);
+ }
+
+ return err;
+}
+
static int diag_dci_runtime_suspend(struct device *dev)
{
dev_dbg(dev, "pm_runtime: suspending...\n");
@@ -1020,9 +1046,18 @@
struct platform_driver msm_diag_dci_driver = {
.probe = diag_dci_probe,
.driver = {
- .name = "DIAG_2",
- .owner = THIS_MODULE,
- .pm = &diag_dci_dev_pm_ops,
+ .name = "DIAG_2",
+ .owner = THIS_MODULE,
+ .pm = &diag_dci_dev_pm_ops,
+ },
+};
+
+struct platform_driver msm_diag_dci_cmd_driver = {
+ .probe = diag_dci_cmd_probe,
+ .driver = {
+ .name = "DIAG_2_CMD",
+ .owner = THIS_MODULE,
+ .pm = &diag_dci_dev_pm_ops,
},
};
@@ -1040,12 +1075,21 @@
mutex_init(&dci_health_mutex);
for (i = 0; i < NUM_SMD_DCI_CHANNELS; i++) {
- success = diag_smd_constructor(&driver->smd_dci[i],
- i, SMD_DCI_TYPE);
+ success = diag_smd_constructor(&driver->smd_dci[i], i,
+ SMD_DCI_TYPE);
if (!success)
goto err;
}
+ if (driver->supports_separate_cmdrsp) {
+ for (i = 0; i < NUM_SMD_DCI_CMD_CHANNELS; i++) {
+ success = diag_smd_constructor(&driver->smd_dci_cmd[i],
+ i, SMD_DCI_CMD_TYPE);
+ if (!success)
+ goto err;
+ }
+ }
+
if (driver->req_tracking_tbl == NULL) {
driver->req_tracking_tbl = kzalloc(dci_max_reg *
sizeof(struct dci_pkt_req_tracking_tbl), GFP_KERNEL);
@@ -1069,6 +1113,13 @@
pr_err("diag: Could not register DCI driver\n");
goto err;
}
+ if (driver->supports_separate_cmdrsp) {
+ success = platform_driver_register(&msm_diag_dci_cmd_driver);
+ if (success) {
+ pr_err("diag: Could not register DCI cmd driver\n");
+ goto err;
+ }
+ }
return DIAG_DCI_NO_ERROR;
err:
pr_err("diag: Could not initialize diag DCI buffers");
@@ -1077,6 +1128,11 @@
kfree(driver->apps_dci_buf);
for (i = 0; i < NUM_SMD_DCI_CHANNELS; i++)
diag_smd_destructor(&driver->smd_dci[i]);
+
+ if (driver->supports_separate_cmdrsp)
+ for (i = 0; i < NUM_SMD_DCI_CMD_CHANNELS; i++)
+ diag_smd_destructor(&driver->smd_dci_cmd[i]);
+
if (driver->diag_dci_wq)
destroy_workqueue(driver->diag_dci_wq);
return DIAG_DCI_NO_REG;
@@ -1096,6 +1152,12 @@
kfree(driver->dci_client_tbl[i].dci_data);
}
+ if (driver->supports_separate_cmdrsp) {
+ for (i = 0; i < NUM_SMD_DCI_CMD_CHANNELS; i++)
+ diag_smd_destructor(&driver->smd_dci_cmd[i]);
+
+ platform_driver_unregister(&msm_diag_dci_cmd_driver);
+ }
kfree(driver->req_tracking_tbl);
kfree(driver->dci_client_tbl);
kfree(driver->apps_dci_buf);
diff --git a/drivers/char/diag/diag_dci.h b/drivers/char/diag/diag_dci.h
index 260cdf3..4dc1bfc 100644
--- a/drivers/char/diag/diag_dci.h
+++ b/drivers/char/diag/diag_dci.h
@@ -95,7 +95,7 @@
int diag_process_dci_transaction(unsigned char *buf, int len);
int diag_send_dci_pkt(struct diag_master_table entry, unsigned char *buf,
int len, int index);
-void extract_dci_pkt_rsp(unsigned char *buf);
+void extract_dci_pkt_rsp(struct diag_smd_info *smd_info, unsigned char *buf);
int diag_dci_find_client_index(int client_id);
/* DCI Log streaming functions */
void create_dci_log_mask_tbl(unsigned char *tbl_buf);
diff --git a/drivers/char/diag/diag_debugfs.c b/drivers/char/diag/diag_debugfs.c
index 76490c8..6e948b7 100644
--- a/drivers/char/diag/diag_debugfs.c
+++ b/drivers/char/diag/diag_debugfs.c
@@ -44,12 +44,18 @@
"modem cntl_ch: 0x%x\n"
"lpass cntl_ch: 0x%x\n"
"riva cntl_ch: 0x%x\n"
+ "modem cmd ch: 0x%x\n"
+ "dci cmd ch: 0x%x\n"
"CPU Tools id: %d\n"
"Apps only: %d\n"
"Apps master: %d\n"
"Check Polling Response: %d\n"
"polling_reg_flag: %d\n"
"uses device tree: %d\n"
+ "supports separate cmdrsp: %d\n"
+ "Modem separate cmdrsp: %d\n"
+ "LPASS separate cmdrsp: %d\n"
+ "RIVA separate cmdrsp: %d\n"
"Modem in_busy_1: %d\n"
"Modem in_busy_2: %d\n"
"LPASS in_busy_1: %d\n"
@@ -57,6 +63,9 @@
"RIVA in_busy_1: %d\n"
"RIVA in_busy_2: %d\n"
"DCI Modem in_busy_1: %d\n"
+ "Modem CMD in_busy_1: %d\n"
+ "Modem CMD in_busy_2: %d\n"
+ "DCI CMD Modem in_busy_1: %d\n"
"logging_mode: %d\n",
(unsigned int)driver->smd_data[MODEM_DATA].ch,
(unsigned int)driver->smd_data[LPASS_DATA].ch,
@@ -65,12 +74,18 @@
(unsigned int)driver->smd_cntl[MODEM_DATA].ch,
(unsigned int)driver->smd_cntl[LPASS_DATA].ch,
(unsigned int)driver->smd_cntl[WCNSS_DATA].ch,
+ (unsigned int)driver->smd_cmd[MODEM_DATA].ch,
+ (unsigned int)driver->smd_dci_cmd[MODEM_DATA].ch,
chk_config_get_id(),
chk_apps_only(),
chk_apps_master(),
chk_polling_response(),
driver->polling_reg_flag,
driver->use_device_tree,
+ driver->supports_separate_cmdrsp,
+ driver->separate_cmdrsp[MODEM_DATA],
+ driver->separate_cmdrsp[LPASS_DATA],
+ driver->separate_cmdrsp[WCNSS_DATA],
driver->smd_data[MODEM_DATA].in_busy_1,
driver->smd_data[MODEM_DATA].in_busy_2,
driver->smd_data[LPASS_DATA].in_busy_1,
@@ -78,6 +93,9 @@
driver->smd_data[WCNSS_DATA].in_busy_1,
driver->smd_data[WCNSS_DATA].in_busy_2,
driver->smd_dci[MODEM_DATA].in_busy_1,
+ driver->smd_cmd[MODEM_DATA].in_busy_1,
+ driver->smd_cmd[MODEM_DATA].in_busy_2,
+ driver->smd_dci_cmd[MODEM_DATA].in_busy_1,
driver->logging_mode);
#ifdef CONFIG_DIAG_OVER_USB
diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c
index 04c3300..5aed793 100644
--- a/drivers/char/diag/diag_masks.c
+++ b/drivers/char/diag/diag_masks.c
@@ -27,7 +27,6 @@
#define MAX_SSID_PER_RANGE 100
#define FEATURE_MASK_LEN_BYTES 1
-#define APPS_RESPOND_LOG_ON_DEMAND 0x04
struct mask_info {
int equip_id;
@@ -48,13 +47,6 @@
msg_mask_tbl_ptr += MAX_SSID_PER_RANGE * sizeof(int); \
} while (0)
-#define WAIT_FOR_SMD(num_delays, delay_time) \
-do { \
- int count; \
- for (count = 0; count < (num_delays); count++) \
- udelay((delay_time)); \
-} while (0)
-
static void diag_print_mask_table(void)
{
/* Enable this to print mask table when updated */
@@ -312,7 +304,7 @@
smd_info->peripheral);
diag_send_log_mask_update(smd_info->ch, ALL_EQUIP_ID);
diag_send_event_mask_update(smd_info->ch, diag_event_num_bytes);
- diag_send_feature_mask_update(smd_info->ch, smd_info->peripheral);
+ diag_send_feature_mask_update(smd_info);
if (smd_info->notify_context == SMD_EVENT_OPEN)
diag_send_diag_mode_update_by_smd(smd_info, MODE_REALTIME);
@@ -352,7 +344,7 @@
header_size + size);
if (wr_size == -ENOMEM) {
retry_count++;
- WAIT_FOR_SMD(5, 2000);
+ usleep_range(10000, 10100);
} else
break;
}
@@ -397,7 +389,7 @@
wr_size = smd_write(ch, buf, header_size + num_bytes);
if (wr_size == -ENOMEM) {
retry_count++;
- WAIT_FOR_SMD(5, 2000);
+ usleep_range(10000, 10100);
} else
break;
}
@@ -447,7 +439,7 @@
4*(driver->msg_mask->msg_mask_size));
if (size == -ENOMEM) {
retry_count++;
- WAIT_FOR_SMD(5, 2000);
+ usleep_range(10000, 10100);
} else
break;
}
@@ -468,12 +460,25 @@
mutex_unlock(&driver->diag_cntl_mutex);
}
-void diag_send_feature_mask_update(smd_channel_t *ch, int proc)
+void diag_send_feature_mask_update(struct diag_smd_info *smd_info)
{
void *buf = driver->buf_feature_mask_update;
int header_size = sizeof(struct diag_ctrl_feature_mask);
- int wr_size = -ENOMEM, retry_count = 0, timer;
+ int wr_size = -ENOMEM, retry_count = 0;
uint8_t feature_byte = 0;
+ int total_len = 0;
+
+ if (!smd_info) {
+ pr_err("diag: In %s, null smd info pointer\n",
+ __func__);
+ return;
+ }
+
+ if (!smd_info->ch) {
+ pr_err("diag: In %s, smd channel not open for peripheral: %d, type: %d\n",
+ __func__, smd_info->peripheral, smd_info->type);
+ return;
+ }
mutex_lock(&driver->diag_cntl_mutex);
/* send feature mask update */
@@ -482,27 +487,32 @@
driver->feature_mask->feature_mask_len = FEATURE_MASK_LEN_BYTES;
memcpy(buf, driver->feature_mask, header_size);
feature_byte |= F_DIAG_INT_FEATURE_MASK;
- feature_byte |= APPS_RESPOND_LOG_ON_DEMAND;
+ feature_byte |= F_DIAG_LOG_ON_DEMAND_RSP_ON_MASTER;
+ feature_byte |= driver->supports_separate_cmdrsp ?
+ F_DIAG_REQ_RSP_CHANNEL : 0;
memcpy(buf+header_size, &feature_byte, FEATURE_MASK_LEN_BYTES);
+ total_len = header_size + FEATURE_MASK_LEN_BYTES;
- if (ch) {
- while (retry_count < 3) {
- wr_size = smd_write(ch, buf, header_size +
- FEATURE_MASK_LEN_BYTES);
- if (wr_size == -ENOMEM) {
- retry_count++;
- for (timer = 0; timer < 5; timer++)
- udelay(2000);
- } else
- break;
- }
- if (wr_size != header_size + FEATURE_MASK_LEN_BYTES)
- pr_err("diag: proc %d fail feature update %d, tried %d",
- proc, wr_size, header_size + FEATURE_MASK_LEN_BYTES);
- } else
- pr_err("diag: ch invalid, feature update on proc %d\n", proc);
+ while (retry_count < 3) {
+ wr_size = smd_write(smd_info->ch, buf, total_len);
+ if (wr_size == -ENOMEM) {
+ retry_count++;
+ /*
+ * The smd channel is full. Delay while
+ * smd processes existing data and smd
+ * has memory become available. The delay
+ * of 10000 was determined empirically as
+ * best value to use.
+ */
+ usleep_range(10000, 10100);
+ } else
+ break;
+ }
+ if (wr_size != total_len)
+ pr_err("diag: In %s, peripheral %d fail feature update, size: %d, tried: %d",
+ __func__, smd_info->peripheral, wr_size, total_len);
+
mutex_unlock(&driver->diag_cntl_mutex);
-
}
int diag_process_apps_masks(unsigned char *buf, int len)
diff --git a/drivers/char/diag/diag_masks.h b/drivers/char/diag/diag_masks.h
index 53f72e8..c66a4b6 100644
--- a/drivers/char/diag/diag_masks.h
+++ b/drivers/char/diag/diag_masks.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -21,7 +21,7 @@
int ssid_last, int proc);
void diag_send_log_mask_update(smd_channel_t *, int);
void diag_mask_update_fn(struct work_struct *work);
-void diag_send_feature_mask_update(smd_channel_t *ch, int proc);
+void diag_send_feature_mask_update(struct diag_smd_info *smd_info);
int diag_process_apps_masks(unsigned char *buf, int len);
void diag_masks_init(void);
void diag_masks_exit(void);
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index 292a0be..b05bcef 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -82,12 +82,16 @@
#define MODE_NONREALTIME 0
#define NUM_SMD_DATA_CHANNELS 3
-#define NUM_SMD_CONTROL_CHANNELS 3
+#define NUM_SMD_CONTROL_CHANNELS NUM_SMD_DATA_CHANNELS
#define NUM_SMD_DCI_CHANNELS 1
+#define NUM_SMD_CMD_CHANNELS 1
+#define NUM_SMD_DCI_CMD_CHANNELS 1
#define SMD_DATA_TYPE 0
#define SMD_CNTL_TYPE 1
#define SMD_DCI_TYPE 2
+#define SMD_CMD_TYPE 3
+#define SMD_DCI_CMD_TYPE 4
/* Maximum number of pkt reg supported at initialization*/
extern int diag_max_reg;
@@ -221,6 +225,7 @@
struct diag_write_device *buf_tbl;
unsigned int buf_tbl_size;
int use_device_tree;
+ int supports_separate_cmdrsp;
/* DCI related variables */
struct dci_pkt_req_tracking_tbl *req_tracking_tbl;
struct diag_dci_client_tbl *dci_client_tbl;
@@ -263,6 +268,9 @@
struct diag_smd_info smd_data[NUM_SMD_DATA_CHANNELS];
struct diag_smd_info smd_cntl[NUM_SMD_CONTROL_CHANNELS];
struct diag_smd_info smd_dci[NUM_SMD_DCI_CHANNELS];
+ struct diag_smd_info smd_cmd[NUM_SMD_CMD_CHANNELS];
+ struct diag_smd_info smd_dci_cmd[NUM_SMD_DCI_CMD_CHANNELS];
+ int separate_cmdrsp[NUM_SMD_CONTROL_CHANNELS];
unsigned char *usb_buf_out;
unsigned char *apps_rsp_buf;
/* buffer for updating mask to peripherals */
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 96e8b11..66e1abc 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -782,7 +782,7 @@
int diag_switch_logging(unsigned long ioarg)
{
- int i, temp, success = -EINVAL, status;
+ int temp = 0, success = -EINVAL, status = 0;
int temp_realtime_mode = driver->real_time_mode;
int requested_mode = (int)ioarg;
@@ -857,24 +857,13 @@
if (temp == MEMORY_DEVICE_MODE && driver->logging_mode
== NO_LOGGING_MODE) {
- for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
- driver->smd_data[i].in_busy_1 = 0;
- driver->smd_data[i].in_busy_2 = 0;
- }
+ diag_reset_smd_data(RESET_AND_NO_QUEUE);
diag_cmp_logging_modes_sdio_pipe(temp, driver->logging_mode);
diag_cmp_logging_modes_diagfwd_bridge(temp,
driver->logging_mode);
} else if (temp == NO_LOGGING_MODE && driver->logging_mode
== MEMORY_DEVICE_MODE) {
- for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
- driver->smd_data[i].in_busy_1 = 0;
- driver->smd_data[i].in_busy_2 = 0;
- /* Poll SMD channels to check for data*/
- if (driver->smd_data[i].ch)
- queue_work(driver->diag_wq,
- &(driver->smd_data[i].
- diag_read_smd_work));
- }
+ diag_reset_smd_data(RESET_AND_QUEUE);
diag_cmp_logging_modes_sdio_pipe(temp,
driver->logging_mode);
diag_cmp_logging_modes_diagfwd_bridge(temp,
@@ -892,15 +881,7 @@
} else if (temp == USB_MODE && driver->logging_mode
== MEMORY_DEVICE_MODE) {
diagfwd_disconnect();
- for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
- driver->smd_data[i].in_busy_1 = 0;
- driver->smd_data[i].in_busy_2 = 0;
- /* Poll SMD channels to check for data*/
- if (driver->smd_data[i].ch)
- queue_work(driver->diag_wq,
- &(driver->smd_data[i].
- diag_read_smd_work));
- }
+ diag_reset_smd_data(RESET_AND_QUEUE);
diag_cmp_logging_modes_sdio_pipe(temp, driver->logging_mode);
diag_cmp_logging_modes_diagfwd_bridge(temp,
driver->logging_mode);
@@ -964,9 +945,13 @@
return -EFAULT;
}
mutex_lock(&driver->dci_mutex);
- if (!(driver->num_dci_client))
+ if (!(driver->num_dci_client)) {
for (i = 0; i < NUM_SMD_DCI_CHANNELS; i++)
driver->smd_dci[i].in_busy_1 = 0;
+ if (driver->supports_separate_cmdrsp)
+ for (i = 0; i < NUM_SMD_DCI_CMD_CHANNELS; i++)
+ driver->smd_dci_cmd[i].in_busy_1 = 0;
+ }
driver->num_dci_client++;
pr_debug("diag: In %s, id = %d\n",
__func__, driver->dci_client_id);
@@ -1206,7 +1191,7 @@
}
}
- /* copy modem data */
+ /* Copy peripheral data */
for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
struct diag_smd_info *data = &driver->smd_data[i];
if (data->in_busy_1 == 1) {
@@ -1240,6 +1225,37 @@
data->in_busy_2 = 0;
}
}
+ if (driver->supports_separate_cmdrsp) {
+ for (i = 0; i < NUM_SMD_CMD_CHANNELS; i++) {
+ struct diag_smd_info *data =
+ &driver->smd_cmd[i];
+ if (!driver->separate_cmdrsp[i])
+ continue;
+
+ if (data->in_busy_1 == 1) {
+ num_data++;
+ /*Copy the length of data being passed*/
+ COPY_USER_SPACE_OR_EXIT(buf+ret,
+ (data->write_ptr_1->length), 4);
+ /*Copy the actual data being passed*/
+ COPY_USER_SPACE_OR_EXIT(buf+ret,
+ *(data->buf_in_1),
+ data->write_ptr_1->length);
+ data->in_busy_1 = 0;
+ }
+ if (data->in_busy_2 == 1) {
+ num_data++;
+ /*Copy the length of data being passed*/
+ COPY_USER_SPACE_OR_EXIT(buf+ret,
+ (data->write_ptr_2->length), 4);
+ /*Copy the actual data being passed*/
+ COPY_USER_SPACE_OR_EXIT(buf+ret,
+ *(data->buf_in_2),
+ data->write_ptr_2->length);
+ data->in_busy_2 = 0;
+ }
+ }
+ }
#ifdef CONFIG_DIAG_SDIO_PIPE
/* copy 9K data over SDIO */
if (driver->in_busy_sdio == 1) {
@@ -1360,6 +1376,17 @@
queue_work(driver->diag_dci_wq,
&(driver->smd_dci[i].diag_read_smd_work));
}
+ if (driver->supports_separate_cmdrsp) {
+ for (i = 0; i < NUM_SMD_DCI_CMD_CHANNELS; i++) {
+ if (!driver->separate_cmdrsp[i])
+ continue;
+ driver->smd_dci_cmd[i].in_busy_1 = 0;
+ if (driver->smd_dci_cmd[i].ch)
+ queue_work(driver->diag_dci_wq,
+ &(driver->smd_dci_cmd[i].
+ diag_read_smd_work));
+ }
+ }
goto exit;
}
exit:
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index 9c2c8b1..6851fd8 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -321,6 +321,19 @@
{
struct diag_request *write_ptr_modem = NULL;
int *in_busy_ptr = 0;
+ int err = 0;
+
+ /*
+ * Do not process data on command channel if the
+ * channel is not designated to do so
+ */
+ if ((smd_info->type == SMD_CMD_TYPE) &&
+ !driver->separate_cmdrsp[smd_info->peripheral]) {
+ /* This print is for debugging */
+ pr_err("diag, In %s, received data on non-designated command channel: %d\n",
+ __func__, smd_info->peripheral);
+ return 0;
+ }
if (smd_info->buf_in_1 == buf) {
write_ptr_modem = smd_info->write_ptr_1;
@@ -335,7 +348,14 @@
if (write_ptr_modem) {
write_ptr_modem->length = total_recd;
*in_busy_ptr = 1;
- diag_device_write(buf, smd_info->peripheral, write_ptr_modem);
+ err = diag_device_write(buf, smd_info->peripheral,
+ write_ptr_modem);
+ if (err) {
+ /* Free up the buffer for future use */
+ *in_busy_ptr = 0;
+ pr_err_ratelimited("diag: In %s, diag_device_write error: %d\n",
+ __func__, err);
+ }
}
return 0;
@@ -356,7 +376,8 @@
if (!smd_info->in_busy_1)
buf = smd_info->buf_in_1;
- else if ((smd_info->type == SMD_DATA_TYPE) && !smd_info->in_busy_2)
+ else if (!smd_info->in_busy_2 &&
+ (smd_info->type == SMD_DATA_TYPE))
buf = smd_info->buf_in_2;
if (smd_info->ch && buf) {
@@ -526,12 +547,20 @@
} else
return -EINVAL;
} else if (driver->logging_mode == NO_LOGGING_MODE) {
- if ((data_type >= 0) && (data_type < NUM_SMD_DATA_CHANNELS)) {
+ if ((data_type >= MODEM_DATA) && (data_type <= WCNSS_DATA)) {
driver->smd_data[data_type].in_busy_1 = 0;
driver->smd_data[data_type].in_busy_2 = 0;
queue_work(driver->diag_wq,
&(driver->smd_data[data_type].
diag_read_smd_work));
+ if (data_type == MODEM_DATA &&
+ driver->separate_cmdrsp[data_type]) {
+ driver->smd_cmd[data_type].in_busy_1 = 0;
+ driver->smd_cmd[data_type].in_busy_2 = 0;
+ queue_work(driver->diag_wq,
+ &(driver->smd_cmd[data_type].
+ diag_read_smd_work));
+ }
}
#ifdef CONFIG_DIAG_SDIO_PIPE
else if (data_type == SDIO_DATA) {
@@ -564,8 +593,8 @@
driver->write_ptr_svc);
} else
err = -1;
- } else if ((data_type >= 0) &&
- (data_type < NUM_SMD_DATA_CHANNELS)) {
+ } else if ((data_type >= MODEM_DATA) &&
+ (data_type <= WCNSS_DATA)) {
write_ptr->buf = buf;
#ifdef DIAG_DEBUG
printk(KERN_INFO "writing data to USB,"
@@ -701,21 +730,30 @@
} else {
if (len > 0) {
if (entry.client_id < NUM_SMD_DATA_CHANNELS) {
+ struct diag_smd_info *smd_info;
int index = entry.client_id;
- if (driver->smd_data[index].ch) {
- if ((index == MODEM_DATA) &&
- diag_check_mode_reset(buf)) {
- return;
- }
- mutex_lock(&driver->smd_data[index].
- smd_ch_mutex);
- smd_write(driver->smd_data[index].ch,
- buf, len);
- mutex_unlock(&driver->smd_data[index].
- smd_ch_mutex);
+ /*
+ * Mode reset should work even if
+ * modem is down
+ */
+ if ((index == MODEM_DATA) &&
+ diag_check_mode_reset(buf)) {
+ return;
+ }
+ smd_info = (driver->separate_cmdrsp[index] &&
+ index < NUM_SMD_CMD_CHANNELS) ?
+ &driver->smd_cmd[index] :
+ &driver->smd_data[index];
+
+ if (smd_info->ch) {
+ mutex_lock(&smd_info->smd_ch_mutex);
+ smd_write(smd_info->ch, buf, len);
+ mutex_unlock(&smd_info->smd_ch_mutex);
} else {
- pr_err("diag: In %s, smd channel %d not open\n",
- __func__, index);
+ pr_err("diag: In %s, smd channel %d not open, peripheral: %d, type: %d\n",
+ __func__, index,
+ smd_info->peripheral,
+ smd_info->type);
}
} else {
pr_alert("diag: In %s, incorrect channel: %d",
@@ -1284,9 +1322,37 @@
mutex_unlock(&driver->diag_hdlc_mutex);
}
+void diag_reset_smd_data(int queue)
+{
+ int i;
+
+ for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
+ driver->smd_data[i].in_busy_1 = 0;
+ driver->smd_data[i].in_busy_2 = 0;
+ if (queue)
+ /* Poll SMD data channels to check for data */
+ queue_work(driver->diag_wq,
+ &(driver->smd_data[i].diag_read_smd_work));
+ }
+
+ if (driver->supports_separate_cmdrsp) {
+ for (i = 0; i < NUM_SMD_CMD_CHANNELS; i++) {
+ driver->smd_cmd[i].in_busy_1 = 0;
+ driver->smd_cmd[i].in_busy_2 = 0;
+ if (queue)
+ /* Poll SMD data channels to check for data */
+ queue_work(driver->diag_wq,
+ &(driver->smd_cmd[i].
+ diag_read_smd_work));
+ }
+ }
+}
+
#ifdef CONFIG_DIAG_OVER_USB
/* 2+1 for modem ; 2 for LPASS ; 1 for WCNSS */
#define N_LEGACY_WRITE (driver->poolsize + 6)
+/* Additionally support number of command data and dci channels */
+#define N_LEGACY_WRITE_CMD ((N_LEGACY_WRITE) + 4)
#define N_LEGACY_READ 1
static void diag_usb_connect_work_fn(struct work_struct *w)
@@ -1305,18 +1371,16 @@
int i;
printk(KERN_DEBUG "diag: USB connected\n");
- err = usb_diag_alloc_req(driver->legacy_ch, N_LEGACY_WRITE,
+ err = usb_diag_alloc_req(driver->legacy_ch,
+ (driver->supports_separate_cmdrsp ?
+ N_LEGACY_WRITE_CMD : N_LEGACY_WRITE),
N_LEGACY_READ);
if (err)
printk(KERN_ERR "diag: unable to alloc USB req on legacy ch");
driver->usb_connected = 1;
+ diag_reset_smd_data(RESET_AND_QUEUE);
for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
- driver->smd_data[i].in_busy_1 = 0;
- driver->smd_data[i].in_busy_2 = 0;
- /* Poll SMD data channels to check for data */
- queue_work(driver->diag_wq,
- &(driver->smd_data[i].diag_read_smd_work));
/* Poll SMD CNTL channels to check for data */
diag_smd_notify(&(driver->smd_cntl[i]), SMD_EVENT_DATA);
}
@@ -1347,6 +1411,13 @@
driver->smd_data[i].in_busy_1 = 1;
driver->smd_data[i].in_busy_2 = 1;
}
+
+ if (driver->supports_separate_cmdrsp) {
+ for (i = 0; i < NUM_SMD_CMD_CHANNELS; i++) {
+ driver->smd_cmd[i].in_busy_1 = 1;
+ driver->smd_cmd[i].in_busy_2 = 1;
+ }
+ }
}
#ifdef CONFIG_DIAG_SDIO_PIPE
if (machine_is_msm8x60_fusion() || machine_is_msm8x60_fusn_ffa())
@@ -1357,30 +1428,44 @@
return 0;
}
-int diagfwd_write_complete(struct diag_request *diag_write_ptr)
+static int diagfwd_check_buf_match(int num_channels,
+ struct diag_smd_info *data, unsigned char *buf)
{
- unsigned char *buf = diag_write_ptr->buf;
- int found_it = 0;
int i;
+ int found_it = 0;
- /* Determine if the write complete is for data from modem/apps/q6 */
- /* Need a context variable here instead */
- for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
- struct diag_smd_info *data = &(driver->smd_data[i]);
- if (buf == (void *)data->buf_in_1) {
- data->in_busy_1 = 0;
+ for (i = 0; i < num_channels; i++) {
+ if (buf == (void *)data[i].buf_in_1) {
+ data[i].in_busy_1 = 0;
queue_work(driver->diag_wq,
- &(data->diag_read_smd_work));
+ &(data[i].diag_read_smd_work));
found_it = 1;
break;
- } else if (buf == (void *)data->buf_in_2) {
- data->in_busy_2 = 0;
+ } else if (buf == (void *)data[i].buf_in_2) {
+ data[i].in_busy_2 = 0;
queue_work(driver->diag_wq,
- &(data->diag_read_smd_work));
+ &(data[i].diag_read_smd_work));
found_it = 1;
break;
}
}
+
+ return found_it;
+}
+
+int diagfwd_write_complete(struct diag_request *diag_write_ptr)
+{
+ unsigned char *buf = diag_write_ptr->buf;
+ int found_it = 0;
+
+ /* Determine if the write complete is for data from modem/apps/q6 */
+ found_it = diagfwd_check_buf_match(NUM_SMD_DATA_CHANNELS,
+ driver->smd_data, buf);
+
+ if (!found_it && driver->supports_separate_cmdrsp)
+ found_it = diagfwd_check_buf_match(NUM_SMD_CMD_CHANNELS,
+ driver->smd_cmd, buf);
+
#ifdef CONFIG_DIAG_SDIO_PIPE
if (!found_it) {
if (buf == (void *)driver->buf_in_sdio) {
@@ -1528,7 +1613,8 @@
wake_up(&driver->smd_wait_q);
- if (smd_info->type == SMD_DCI_TYPE)
+ if (smd_info->type == SMD_DCI_TYPE ||
+ smd_info->type == SMD_DCI_CMD_TYPE)
queue_work(driver->diag_dci_wq,
&(smd_info->diag_read_smd_work));
else
@@ -1539,40 +1625,66 @@
{
int r = 0;
int index = -1;
+ const char *channel_name = NULL;
if (pdev->id == SMD_APPS_MODEM) {
index = MODEM_DATA;
- r = smd_open("DIAG", &driver->smd_data[index].ch,
- &driver->smd_data[index],
- diag_smd_notify);
- driver->smd_data[index].ch_save =
- driver->smd_data[index].ch;
+ channel_name = "DIAG";
}
#if defined(CONFIG_MSM_N_WAY_SMD)
- if (pdev->id == SMD_APPS_QDSP) {
+ else if (pdev->id == SMD_APPS_QDSP) {
index = LPASS_DATA;
- r = smd_named_open_on_edge("DIAG", SMD_APPS_QDSP,
- &driver->smd_data[index].ch,
- &driver->smd_data[index],
- diag_smd_notify);
- driver->smd_data[index].ch_save =
- driver->smd_data[index].ch;
+ channel_name = "DIAG";
}
#endif
- if (pdev->id == SMD_APPS_WCNSS) {
+ else if (pdev->id == SMD_APPS_WCNSS) {
index = WCNSS_DATA;
- r = smd_named_open_on_edge("APPS_RIVA_DATA",
- SMD_APPS_WCNSS,
+ channel_name = "APPS_RIVA_DATA";
+ }
+
+ if (index != -1) {
+ r = smd_named_open_on_edge(channel_name,
+ pdev->id,
&driver->smd_data[index].ch,
&driver->smd_data[index],
diag_smd_notify);
- driver->smd_data[index].ch_save =
- driver->smd_data[index].ch;
+ driver->smd_data[index].ch_save = driver->smd_data[index].ch;
}
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
- pr_debug("diag: open SMD port, Id = %d, r = %d\n", pdev->id, r);
+ pr_debug("diag: In %s, open SMD port, Id = %d, r = %d\n",
+ __func__, pdev->id, r);
+
+ return 0;
+}
+
+static int diag_smd_cmd_probe(struct platform_device *pdev)
+{
+ int r = 0;
+ int index = -1;
+ const char *channel_name = NULL;
+
+ if (!driver->supports_separate_cmdrsp)
+ return 0;
+
+ if (pdev->id == SMD_APPS_MODEM) {
+ index = MODEM_DATA;
+ channel_name = "DIAG_CMD";
+ }
+
+ if (index != -1) {
+ r = smd_named_open_on_edge(channel_name,
+ pdev->id,
+ &driver->smd_cmd[index].ch,
+ &driver->smd_cmd[index],
+ diag_smd_notify);
+ driver->smd_cmd[index].ch_save =
+ driver->smd_cmd[index].ch;
+ }
+
+ pr_debug("diag: In %s, open SMD CMD port, Id = %d, r = %d\n",
+ __func__, pdev->id, r);
return 0;
}
@@ -1614,6 +1726,24 @@
},
};
+static struct platform_driver
+ smd_lite_data_cmd_drivers[NUM_SMD_CMD_CHANNELS] = {
+ {
+ /* Modem data */
+ .probe = diag_smd_cmd_probe,
+ .driver = {
+ .name = "DIAG_CMD",
+ .owner = THIS_MODULE,
+ .pm = &diag_smd_dev_pm_ops,
+ },
+ }
+};
+
+int device_supports_separate_cmdrsp(void)
+{
+ return driver->use_device_tree;
+}
+
void diag_smd_destructor(struct diag_smd_info *smd_info)
{
if (smd_info->type == SMD_DATA_TYPE)
@@ -1699,16 +1829,22 @@
* information to the update function.
*/
smd_info->notify_context = 0;
- if (type == SMD_DATA_TYPE)
+ switch (type) {
+ case SMD_DATA_TYPE:
+ case SMD_CMD_TYPE:
INIT_WORK(&(smd_info->diag_notify_update_smd_work),
- diag_clean_reg_fn);
- else if (type == SMD_CNTL_TYPE)
+ diag_clean_reg_fn);
+ break;
+ case SMD_CNTL_TYPE:
INIT_WORK(&(smd_info->diag_notify_update_smd_work),
- diag_mask_update_fn);
- else if (type == SMD_DCI_TYPE)
+ diag_mask_update_fn);
+ break;
+ case SMD_DCI_TYPE:
+ case SMD_DCI_CMD_TYPE:
INIT_WORK(&(smd_info->diag_notify_update_smd_work),
- diag_update_smd_dci_work_fn);
- else {
+ diag_update_smd_dci_work_fn);
+ break;
+ default:
pr_err("diag: In %s, unknown type, type: %d\n", __func__, type);
goto err;
}
@@ -1717,15 +1853,21 @@
* Set function ptr for function to call to process the data that
* was just read from the smd channel
*/
- if (type == SMD_DATA_TYPE)
+ switch (type) {
+ case SMD_DATA_TYPE:
+ case SMD_CMD_TYPE:
smd_info->process_smd_read_data = diag_process_smd_read_data;
- else if (type == SMD_CNTL_TYPE)
+ break;
+ case SMD_CNTL_TYPE:
smd_info->process_smd_read_data =
diag_process_smd_cntl_read_data;
- else if (type == SMD_DCI_TYPE)
+ break;
+ case SMD_DCI_TYPE:
+ case SMD_DCI_CMD_TYPE:
smd_info->process_smd_read_data =
diag_process_smd_dci_read_data;
- else {
+ break;
+ default:
pr_err("diag: In %s, unknown type, type: %d\n", __func__, type);
goto err;
}
@@ -1781,23 +1923,28 @@
*/
driver->buf_tbl_size = (buf_tbl_size < driver->poolsize_hdlc) ?
driver->poolsize_hdlc : buf_tbl_size;
+ driver->supports_separate_cmdrsp = device_supports_separate_cmdrsp();
mutex_init(&driver->diag_hdlc_mutex);
mutex_init(&driver->diag_cntl_mutex);
- success = diag_smd_constructor(&driver->smd_data[MODEM_DATA],
- MODEM_DATA, SMD_DATA_TYPE);
- if (!success)
- goto err;
+ for (i = 0; i < NUM_SMD_CONTROL_CHANNELS; i++)
+ driver->separate_cmdrsp[i] = 0;
- success = diag_smd_constructor(&driver->smd_data[LPASS_DATA],
- LPASS_DATA, SMD_DATA_TYPE);
- if (!success)
- goto err;
+ for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
+ success = diag_smd_constructor(&driver->smd_data[i], i,
+ SMD_DATA_TYPE);
+ if (!success)
+ goto err;
+ }
- success = diag_smd_constructor(&driver->smd_data[WCNSS_DATA],
- WCNSS_DATA, SMD_DATA_TYPE);
- if (!success)
- goto err;
+ if (driver->supports_separate_cmdrsp) {
+ for (i = 0; i < NUM_SMD_CMD_CHANNELS; i++) {
+ success = diag_smd_constructor(&driver->smd_cmd[i], i,
+ SMD_CMD_TYPE);
+ if (!success)
+ goto err;
+ }
+ }
if (driver->usb_buf_out == NULL &&
(driver->usb_buf_out = kzalloc(USB_MAX_OUT_BUF,
@@ -1867,6 +2014,12 @@
#endif
platform_driver_register(&msm_smd_ch1_driver);
platform_driver_register(&diag_smd_lite_driver);
+
+ if (driver->supports_separate_cmdrsp) {
+ for (i = 0; i < NUM_SMD_CMD_CHANNELS; i++)
+ platform_driver_register(&smd_lite_data_cmd_drivers[i]);
+ }
+
return;
err:
pr_err("diag: Could not initialize diag buffers");
@@ -1874,6 +2027,9 @@
for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++)
diag_smd_destructor(&driver->smd_data[i]);
+ for (i = 0; i < NUM_SMD_CMD_CHANNELS; i++)
+ diag_smd_destructor(&driver->smd_cmd[i]);
+
kfree(driver->buf_msg_mask_update);
kfree(driver->buf_log_mask_update);
kfree(driver->buf_event_mask_update);
@@ -1903,9 +2059,16 @@
usb_diag_close(driver->legacy_ch);
#endif
platform_driver_unregister(&msm_smd_ch1_driver);
- platform_driver_unregister(&msm_diag_dci_driver);
platform_driver_unregister(&diag_smd_lite_driver);
+ if (driver->supports_separate_cmdrsp) {
+ for (i = 0; i < NUM_SMD_CMD_CHANNELS; i++) {
+ diag_smd_destructor(&driver->smd_cmd[i]);
+ platform_driver_unregister(
+ &smd_lite_data_cmd_drivers[i]);
+ }
+ }
+
kfree(driver->buf_msg_mask_update);
kfree(driver->buf_log_mask_update);
kfree(driver->buf_event_mask_update);
diff --git a/drivers/char/diag/diagfwd.h b/drivers/char/diag/diagfwd.h
index 09f2f5e..c6e1273 100644
--- a/drivers/char/diag/diagfwd.h
+++ b/drivers/char/diag/diagfwd.h
@@ -16,6 +16,9 @@
#define NO_PROCESS 0
#define NON_APPS_PROC -1
+#define RESET_AND_NO_QUEUE 0
+#define RESET_AND_QUEUE 1
+
#define CHK_OVERFLOW(bufStart, start, end, length) \
((((bufStart) <= (start)) && ((end) - (start) >= (length))) ? 1 : 0)
@@ -49,6 +52,7 @@
void diag_cmp_logging_modes_sdio_pipe(int old_mode, int new_mode);
void diag_cmp_logging_modes_diagfwd_bridge(int old_mode, int new_mode);
int diag_process_apps_pkt(unsigned char *buf, int len);
+void diag_reset_smd_data(int queue);
/* State for diag forwarding */
#ifdef CONFIG_DIAG_OVER_USB
int diagfwd_connect(void);
diff --git a/drivers/char/diag/diagfwd_cntl.c b/drivers/char/diag/diagfwd_cntl.c
index 2776c58..960fdb9 100644
--- a/drivers/char/diag/diagfwd_cntl.c
+++ b/drivers/char/diag/diagfwd_cntl.c
@@ -45,7 +45,6 @@
int total_recd)
{
int data_len = 0, type = -1, count_bytes = 0, j, flag = 0;
- int feature_mask_len;
struct bindpkt_params_per_process *pkt_params =
kzalloc(sizeof(struct bindpkt_params_per_process), GFP_KERNEL);
struct diag_ctrl_msg *msg;
@@ -116,11 +115,32 @@
pr_err("diag: drop reg proc %d\n",
smd_info->peripheral);
kfree(pkt_params->params);
- } else if ((type == DIAG_CTRL_MSG_FEATURE) &&
- (smd_info->peripheral == MODEM_DATA)) {
- feature_mask_len = *(int *)(buf + 8);
- driver->log_on_demand_support = (*(uint8_t *)
- (buf + 12)) & 0x04;
+ } else if (type == DIAG_CTRL_MSG_FEATURE &&
+ total_recd >= count_bytes) {
+ uint8_t feature_mask = 0;
+ int feature_mask_len = *(int *)(buf+8);
+ if (feature_mask_len > 0) {
+ feature_mask = *(uint8_t *)(buf+12);
+ if (smd_info->peripheral == MODEM_DATA)
+ driver->log_on_demand_support =
+ feature_mask &
+ F_DIAG_LOG_ON_DEMAND_RSP_ON_MASTER;
+ /*
+ * If apps supports separate cmd/rsp channels
+ * and the peripheral supports separate cmd/rsp
+ * channels
+ */
+ if (driver->supports_separate_cmdrsp &&
+ (feature_mask & F_DIAG_REQ_RSP_CHANNEL))
+ driver->separate_cmdrsp
+ [smd_info->peripheral] =
+ ENABLE_SEPARATE_CMDRSP;
+ else
+ driver->separate_cmdrsp
+ [smd_info->peripheral] =
+ DISABLE_SEPARATE_CMDRSP;
+ }
+ flag = 1;
} else if (type != DIAG_CTRL_MSG_REG) {
flag = 1;
}
@@ -212,39 +232,38 @@
{
int r = 0;
int index = -1;
+ const char *channel_name = NULL;
/* open control ports only on 8960 & newer targets */
if (chk_apps_only()) {
if (pdev->id == SMD_APPS_MODEM) {
index = MODEM_DATA;
- r = smd_open("DIAG_CNTL",
- &driver->smd_cntl[index].ch,
- &driver->smd_cntl[index],
- diag_smd_notify);
- driver->smd_cntl[index].ch_save =
- driver->smd_cntl[index].ch;
- } else if (pdev->id == SMD_APPS_QDSP) {
+ channel_name = "DIAG_CNTL";
+ }
+#if defined(CONFIG_MSM_N_WAY_SMD)
+ else if (pdev->id == SMD_APPS_QDSP) {
index = LPASS_DATA;
- r = smd_named_open_on_edge("DIAG_CNTL",
- SMD_APPS_QDSP,
- &driver->smd_cntl[index].ch,
- &driver->smd_cntl[index],
- diag_smd_notify);
- driver->smd_cntl[index].ch_save =
- driver->smd_cntl[index].ch;
- } else if (pdev->id == SMD_APPS_WCNSS) {
+ channel_name = "DIAG_CNTL";
+ }
+#endif
+ else if (pdev->id == SMD_APPS_WCNSS) {
index = WCNSS_DATA;
- r = smd_named_open_on_edge("APPS_RIVA_CTRL",
- SMD_APPS_WCNSS,
- &driver->smd_cntl[index].ch,
- &driver->smd_cntl[index],
- diag_smd_notify);
- driver->smd_cntl[index].ch_save =
- driver->smd_cntl[index].ch;
+ channel_name = "APPS_RIVA_CTRL";
}
- pr_debug("diag: open CNTL port, ID = %d,r = %d\n", pdev->id, r);
+ if (index != -1) {
+ r = smd_named_open_on_edge(channel_name,
+ pdev->id,
+ &driver->smd_cntl[index].ch,
+ &driver->smd_cntl[index],
+ diag_smd_notify);
+ driver->smd_cntl[index].ch_save =
+ driver->smd_cntl[index].ch;
+ }
+ pr_debug("diag: In %s, open SMD CNTL port, Id = %d, r = %d\n",
+ __func__, pdev->id, r);
}
+
return 0;
}
@@ -269,20 +288,20 @@
.probe = diag_smd_cntl_probe,
.driver = {
- .name = "DIAG_CNTL",
- .owner = THIS_MODULE,
- .pm = &diagfwd_cntl_dev_pm_ops,
- },
+ .name = "DIAG_CNTL",
+ .owner = THIS_MODULE,
+ .pm = &diagfwd_cntl_dev_pm_ops,
+ },
};
static struct platform_driver diag_smd_lite_cntl_driver = {
.probe = diag_smd_cntl_probe,
.driver = {
- .name = "APPS_RIVA_CTRL",
- .owner = THIS_MODULE,
- .pm = &diagfwd_cntl_dev_pm_ops,
- },
+ .name = "APPS_RIVA_CTRL",
+ .owner = THIS_MODULE,
+ .pm = &diagfwd_cntl_dev_pm_ops,
+ },
};
void diagfwd_cntl_init(void)
@@ -295,20 +314,12 @@
driver->log_on_demand_support = 1;
driver->diag_cntl_wq = create_singlethread_workqueue("diag_cntl_wq");
- success = diag_smd_constructor(&driver->smd_cntl[MODEM_DATA],
- MODEM_DATA, SMD_CNTL_TYPE);
- if (!success)
- goto err;
-
- success = diag_smd_constructor(&driver->smd_cntl[LPASS_DATA],
- LPASS_DATA, SMD_CNTL_TYPE);
- if (!success)
- goto err;
-
- success = diag_smd_constructor(&driver->smd_cntl[WCNSS_DATA],
- WCNSS_DATA, SMD_CNTL_TYPE);
- if (!success)
- goto err;
+ for (i = 0; i < NUM_SMD_CONTROL_CHANNELS; i++) {
+ success = diag_smd_constructor(&driver->smd_cntl[i], i,
+ SMD_CNTL_TYPE);
+ if (!success)
+ goto err;
+ }
platform_driver_register(&msm_smd_ch1_cntl_driver);
platform_driver_register(&diag_smd_lite_cntl_driver);
diff --git a/drivers/char/diag/diagfwd_cntl.h b/drivers/char/diag/diagfwd_cntl.h
index f58ab24..02b9757 100644
--- a/drivers/char/diag/diagfwd_cntl.h
+++ b/drivers/char/diag/diagfwd_cntl.h
@@ -37,7 +37,17 @@
#define DIAG_CTRL_MSG_LAST DIAG_CTRL_MSG_F3_MASK_WITH_PRESET_ID
/* Denotes that we support sending/receiving the feature mask */
-#define F_DIAG_INT_FEATURE_MASK 0x01
+#define F_DIAG_INT_FEATURE_MASK 0x01
+/* Denotes that we support responding to "Log on Demand" */
+#define F_DIAG_LOG_ON_DEMAND_RSP_ON_MASTER 0x04
+/*
+ * Supports dedicated main request/response on
+ * new Data Rx and DCI Rx channels
+ */
+#define F_DIAG_REQ_RSP_CHANNEL 0x10
+
+#define ENABLE_SEPARATE_CMDRSP 1
+#define DISABLE_SEPARATE_CMDRSP 0
struct cmd_code_range {
uint16_t cmd_code_lo;
@@ -110,6 +120,7 @@
void diagfwd_cntl_init(void);
void diagfwd_cntl_exit(void);
void diag_read_smd_cntl_work_fn(struct work_struct *);
+void diag_notify_ctrl_update_fn(struct work_struct *work);
void diag_clean_reg_fn(struct work_struct *work);
int diag_process_smd_cntl_read_data(struct diag_smd_info *smd_info, void *buf,
int total_recd);
diff --git a/drivers/char/msm_rotator.c b/drivers/char/msm_rotator.c
index 9a43ea4..156a2a5 100644
--- a/drivers/char/msm_rotator.c
+++ b/drivers/char/msm_rotator.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -351,6 +351,7 @@
case MDP_RGBA_8888:
case MDP_BGRA_8888:
case MDP_RGBX_8888:
+ case MDP_BGRX_8888:
return 4;
case MDP_Y_CBCR_H2V2:
@@ -407,6 +408,7 @@
case MDP_RGBA_8888:
case MDP_BGRA_8888:
case MDP_RGBX_8888:
+ case MDP_BGRX_8888:
case MDP_RGB_888:
case MDP_RGB_565:
case MDP_BGR_565:
@@ -811,6 +813,7 @@
break;
case MDP_BGRA_8888:
+ case MDP_BGRX_8888:
iowrite32(GET_PACK_PATTERN(CLR_ALPHA, CLR_B, CLR_G,
CLR_R, 8),
MSM_ROTATOR_SRC_UNPACK_PATTERN1);
@@ -1118,6 +1121,7 @@
case MDP_XRGB_8888:
case MDP_BGRA_8888:
case MDP_RGBX_8888:
+ case MDP_BGRX_8888:
case MDP_YCBCR_H1V1:
case MDP_YCRCB_H1V1:
rc = msm_rotator_rgb_types(msm_rotator_dev->img_info[s],
@@ -1275,6 +1279,7 @@
case MDP_XRGB_8888:
case MDP_RGBX_8888:
case MDP_BGRA_8888:
+ case MDP_BGRX_8888:
is_rgb = 1;
info.dst.format = info.src.format;
break;
diff --git a/drivers/crypto/msm/ota_crypto.c b/drivers/crypto/msm/ota_crypto.c
index af53543..5051a3a 100644
--- a/drivers/crypto/msm/ota_crypto.c
+++ b/drivers/crypto/msm/ota_crypto.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -42,7 +42,7 @@
struct ota_dev_control;
struct ota_async_req {
- struct list_head list;
+ struct list_head rlist;
struct completion complete;
int err;
enum qce_ota_oper_enum op;
@@ -52,7 +52,7 @@
struct qce_f8_multi_pkt_req f8_mp_req;
} req;
- struct ota_dev_control *podev;
+ struct ota_qce_dev *pqce;
};
/*
@@ -68,19 +68,29 @@
/* misc device */
struct miscdevice miscdevice;
+ struct list_head ready_commands;
+ unsigned magic;
+ struct list_head qce_dev;
+ spinlock_t lock;
+ struct mutex register_lock;
+ bool registered;
+ uint32_t total_units;
+};
+struct ota_qce_dev {
+ struct list_head qlist;
/* qce handle */
void *qce;
/* platform device */
struct platform_device *pdev;
- unsigned magic;
-
- struct list_head ready_commands;
struct ota_async_req *active_command;
- spinlock_t lock;
struct tasklet_struct done_tasklet;
+ struct ota_dev_control *podev;
+ uint32_t unit;
+ u32 totalReq;
+ u32 errReq;
};
#define OTA_MAGIC 0x4f544143
@@ -89,7 +99,7 @@
unsigned cmd, unsigned long arg);
static int qcota_open(struct inode *inode, struct file *file);
static int qcota_release(struct inode *inode, struct file *file);
-static int start_req(struct ota_dev_control *podev);
+static int start_req(struct ota_qce_dev *pqce, struct ota_async_req *areq);
static const struct file_operations qcota_fops = {
.owner = THIS_MODULE,
@@ -98,35 +108,15 @@
.release = qcota_release,
};
-static struct ota_dev_control qcota_dev[] = {
- {
- .miscdevice = {
+static struct ota_dev_control qcota_dev = {
+ .miscdevice = {
.minor = MISC_DYNAMIC_MINOR,
.name = "qcota0",
.fops = &qcota_fops,
- },
- .magic = OTA_MAGIC,
},
- {
- .miscdevice = {
- .minor = MISC_DYNAMIC_MINOR,
- .name = "qcota1",
- .fops = &qcota_fops,
- },
- .magic = OTA_MAGIC,
- },
- {
- .miscdevice = {
- .minor = MISC_DYNAMIC_MINOR,
- .name = "qcota2",
- .fops = &qcota_fops,
- },
- .magic = OTA_MAGIC,
- }
+ .magic = OTA_MAGIC,
};
-#define MAX_OTA_DEVICE ARRAY_SIZE(qcota_dev)
-
#define DEBUG_MAX_FNAME 16
#define DEBUG_MAX_RW_BUF 1024
@@ -141,27 +131,22 @@
u32 f9_op_success;
u32 f9_op_fail;
};
-static struct qcota_stat _qcota_stat[MAX_OTA_DEVICE];
+static struct qcota_stat _qcota_stat;
static struct dentry *_debug_dent;
static char _debug_read_buf[DEBUG_MAX_RW_BUF];
-static int _debug_qcota[MAX_OTA_DEVICE];
+static int _debug_qcota;
-static struct ota_dev_control *qcota_minor_to_control(unsigned n)
+static struct ota_dev_control *qcota_control(void)
{
- int i;
- for (i = 0; i < MAX_OTA_DEVICE; i++) {
- if (qcota_dev[i].miscdevice.minor == n)
- return &qcota_dev[i];
- }
- return NULL;
+ return &qcota_dev;
}
static int qcota_open(struct inode *inode, struct file *file)
{
struct ota_dev_control *podev;
- podev = qcota_minor_to_control(MINOR(inode->i_rdev));
+ podev = qcota_control();
if (podev == NULL) {
pr_err("%s: no such device %d\n", __func__,
MINOR(inode->i_rdev));
@@ -191,38 +176,52 @@
static void req_done(unsigned long data)
{
- struct ota_dev_control *podev = (struct ota_dev_control *)data;
+ struct ota_qce_dev *pqce = (struct ota_qce_dev *)data;
+ struct ota_dev_control *podev = pqce->podev;
struct ota_async_req *areq;
unsigned long flags;
struct ota_async_req *new_req = NULL;
int ret = 0;
+
spin_lock_irqsave(&podev->lock, flags);
- areq = podev->active_command;
- podev->active_command = NULL;
+
+ areq = pqce->active_command;
+ if (unlikely(areq == NULL))
+ pr_err("ota_crypto: req_done, no active request\n");
+ pqce->active_command = NULL;
again:
if (!list_empty(&podev->ready_commands)) {
new_req = container_of(podev->ready_commands.next,
- struct ota_async_req, list);
- list_del(&new_req->list);
- podev->active_command = new_req;
+ struct ota_async_req, rlist);
+ list_del(&new_req->rlist);
+ pqce->active_command = new_req;
+ spin_unlock_irqrestore(&podev->lock, flags);
+
new_req->err = 0;
- ret = start_req(podev);
- }
+ ret = start_req(pqce, new_req); /* start a new request */
- spin_unlock_irqrestore(&podev->lock, flags);
+ } else {
+ spin_unlock_irqrestore(&podev->lock, flags);
+ };
- if (areq)
+ if (areq) {
complete(&areq->complete);
-
- if (new_req && ret) {
- complete(&new_req->complete);
- spin_lock_irqsave(&podev->lock, flags);
- podev->active_command = NULL;
areq = NULL;
+ };
+
+ /* if error from issuing request */
+ if (unlikely(new_req && ret)) {
+ new_req->err = ret;
+ complete(&new_req->complete);
ret = 0;
new_req = NULL;
+
+ spin_lock_irqsave(&podev->lock, flags);
+ pqce->active_command = NULL;
+
+ /* try to get next new request */
goto again;
}
@@ -233,64 +232,61 @@
int ret)
{
struct ota_async_req *areq = (struct ota_async_req *) cookie;
- struct ota_dev_control *podev;
- struct qcota_stat *pstat;
+ struct ota_qce_dev *pqce;
- podev = areq->podev;
- pstat = &_qcota_stat[podev->pdev->id];
+ pqce = areq->pqce;
areq->req.f9_req.mac_i = (uint32_t) icv;
- if (ret)
+ if (ret) {
+ pqce->errReq++;
areq->err = -ENXIO;
- else
+ } else
areq->err = 0;
- tasklet_schedule(&podev->done_tasklet);
-};
+ tasklet_schedule(&pqce->done_tasklet);
+}
static void f8_cb(void *cookie, unsigned char *icv, unsigned char *iv,
int ret)
{
struct ota_async_req *areq = (struct ota_async_req *) cookie;
- struct ota_dev_control *podev;
- struct qcota_stat *pstat;
+ struct ota_qce_dev *pqce;
- podev = areq->podev;
- pstat = &_qcota_stat[podev->pdev->id];
+ pqce = areq->pqce;
- if (ret)
+ if (ret) {
+ pqce->errReq++;
areq->err = -ENXIO;
- else
+ } else {
areq->err = 0;
+ }
- tasklet_schedule(&podev->done_tasklet);
-};
+ tasklet_schedule(&pqce->done_tasklet);
+}
-static int start_req(struct ota_dev_control *podev)
+static int start_req(struct ota_qce_dev *pqce, struct ota_async_req *areq)
{
- struct ota_async_req *areq;
struct qce_f9_req *pf9;
struct qce_f8_multi_pkt_req *p_mp_f8;
struct qce_f8_req *pf8;
int ret = 0;
- /* start the command on the podev->active_command */
- areq = podev->active_command;
- areq->podev = podev;
+ /* command should be on the podev->active_command */
+ areq->pqce = pqce;
switch (areq->op) {
case QCE_OTA_F8_OPER:
pf8 = &areq->req.f8_req;
- ret = qce_f8_req(podev->qce, pf8, areq, f8_cb);
+ ret = qce_f8_req(pqce->qce, pf8, areq, f8_cb);
break;
case QCE_OTA_MPKT_F8_OPER:
p_mp_f8 = &areq->req.f8_mp_req;
- ret = qce_f8_multi_pkt_req(podev->qce, p_mp_f8, areq, f8_cb);
+ ret = qce_f8_multi_pkt_req(pqce->qce, p_mp_f8, areq, f8_cb);
break;
case QCE_OTA_F9_OPER:
pf9 = &areq->req.f9_req;
- ret = qce_f9_req(podev->qce, pf9, areq, f9_cb);
+ ret = qce_f9_req(pqce->qce, pf9, areq, f9_cb);
break;
default:
@@ -298,32 +294,60 @@
break;
};
areq->err = ret;
+ pqce->totalReq++;
+ if (ret)
+ pqce->errReq++;
return ret;
-};
+}
+
+static struct ota_qce_dev *schedule_qce(struct ota_dev_control *podev)
+{
+ /* do this function with spinlock set */
+ struct ota_qce_dev *p;
+
+ if (unlikely(list_empty(&podev->qce_dev))) {
+ pr_err("%s: no valid qce to schedule\n", __func__);
+ return NULL;
+ }
+
+ list_for_each_entry(p, &podev->qce_dev, qlist) {
+ if (p->active_command == NULL)
+ return p;
+ }
+ return NULL;
+}
static int submit_req(struct ota_async_req *areq, struct ota_dev_control *podev)
{
unsigned long flags;
int ret = 0;
struct qcota_stat *pstat;
+ struct ota_qce_dev *pqce;
areq->err = 0;
- spin_lock_irqsave(&podev->lock, flags);
- if (podev->active_command == NULL) {
- podev->active_command = areq;
- ret = start_req(podev);
- } else {
- list_add_tail(&areq->list, &podev->ready_commands);
- }
- if (ret != 0)
- podev->active_command = NULL;
- spin_unlock_irqrestore(&podev->lock, flags);
+ spin_lock_irqsave(&podev->lock, flags);
+ pqce = schedule_qce(podev);
+ if (pqce) {
+ pqce->active_command = areq;
+ spin_unlock_irqrestore(&podev->lock, flags);
+
+ ret = start_req(pqce, areq);
+ if (ret != 0) {
+ spin_lock_irqsave(&podev->lock, flags);
+ pqce->active_command = NULL;
+ spin_unlock_irqrestore(&podev->lock, flags);
+ }
+
+ } else {
+ list_add_tail(&areq->rlist, &podev->ready_commands);
+ spin_unlock_irqrestore(&podev->lock, flags);
+ }
if (ret == 0)
wait_for_completion(&areq->complete);
- pstat = &_qcota_stat[podev->pdev->id];
+ pstat = &_qcota_stat;
switch (areq->op) {
case QCE_OTA_F8_OPER:
if (areq->err)
@@ -350,7 +374,7 @@
};
return areq->err;
-};
+}
static long qcota_ioctl(struct file *file,
unsigned cmd, unsigned long arg)
@@ -377,7 +401,7 @@
init_completion(&areq.complete);
- pstat = &_qcota_stat[podev->pdev->id];
+ pstat = &_qcota_stat;
switch (cmd) {
case QCOTA_F9_REQ:
@@ -523,67 +547,112 @@
int rc = 0;
struct ota_dev_control *podev;
struct ce_hw_support ce_support;
+ struct ota_qce_dev *pqce;
+ unsigned long flags;
- if (pdev->id >= MAX_OTA_DEVICE) {
- pr_err("%s: device id %d exceeds allowed %d\n",
- __func__, pdev->id, MAX_OTA_DEVICE);
- return -ENOENT;
+ podev = &qcota_dev;
+ pqce = kzalloc(sizeof(*pqce), GFP_KERNEL);
+ if (!pqce) {
+ pr_err("qcota_probe: Memory allocation FAIL\n");
+ return -ENOMEM;
}
- podev = &qcota_dev[pdev->id];
-
- INIT_LIST_HEAD(&podev->ready_commands);
- podev->active_command = NULL;
- spin_lock_init(&podev->lock);
- tasklet_init(&podev->done_tasklet, req_done, (unsigned long)podev);
+ pqce->podev = podev;
+ pqce->active_command = NULL;
+ tasklet_init(&pqce->done_tasklet, req_done, (unsigned long)pqce);
/* open qce */
handle = qce_open(pdev, &rc);
if (handle == NULL) {
- pr_err("%s: device id %d, can not open qce\n",
- __func__, pdev->id);
- platform_set_drvdata(pdev, NULL);
- return rc;
+ pr_err("%s: device %s, can not open qce\n",
+ __func__, pdev->name);
+ goto err;
}
if (qce_hw_support(handle, &ce_support) < 0 ||
ce_support.ota == false) {
- pr_err("%s: device id %d, qce does not support ota capability\n",
- __func__, pdev->id);
+ pr_err("%s: device %s, qce does not support ota capability\n",
+ __func__, pdev->name);
rc = -ENODEV;
goto err;
}
- podev->qce = handle;
- podev->pdev = pdev;
- platform_set_drvdata(pdev, podev);
+ pqce->qce = handle;
+ pqce->pdev = pdev;
+ pqce->totalReq = 0;
+ pqce->errReq = 0;
+ platform_set_drvdata(pdev, pqce);
- rc = misc_register(&podev->miscdevice);
- if (rc < 0)
+ mutex_lock(&podev->register_lock);
+ rc = 0;
+ if (podev->registered == false) {
+ rc = misc_register(&podev->miscdevice);
+ if (rc == 0) {
+ pqce->unit = podev->total_units;
+ podev->total_units++;
+ podev->registered = true;
+ };
+ } else {
+ pqce->unit = podev->total_units;
+ podev->total_units++;
+ }
+ mutex_unlock(&podev->register_lock);
+ if (rc) {
+ pr_err("ion: failed to register misc device.\n");
goto err;
+ }
+
+ spin_lock_irqsave(&podev->lock, flags);
+ list_add_tail(&pqce->qlist, &podev->qce_dev);
+ spin_unlock_irqrestore(&podev->lock, flags);
return 0;
err:
if (handle)
qce_close(handle);
+
platform_set_drvdata(pdev, NULL);
- podev->qce = NULL;
- podev->pdev = NULL;
+ tasklet_kill(&pqce->done_tasklet);
+ kfree(pqce);
return rc;
-};
+}
static int qcota_remove(struct platform_device *pdev)
{
struct ota_dev_control *podev;
+ struct ota_qce_dev *pqce;
+ unsigned long flags;
- podev = platform_get_drvdata(pdev);
- if (!podev)
+ pqce = platform_get_drvdata(pdev);
+ if (!pqce)
return 0;
- if (podev->qce)
- qce_close(podev->qce);
+ if (pqce->qce)
+ qce_close(pqce->qce);
- if (podev->miscdevice.minor != MISC_DYNAMIC_MINOR)
- misc_deregister(&podev->miscdevice);
- tasklet_kill(&podev->done_tasklet);
+ podev = pqce->podev;
+ if (!podev)
+ goto ret;
+
+ spin_lock_irqsave(&podev->lock, flags);
+ list_del(&pqce->qlist);
+ spin_unlock_irqrestore(&podev->lock, flags);
+
+ mutex_lock(&podev->register_lock);
+ if (--podev->total_units == 0) {
+ if (podev->miscdevice.minor != MISC_DYNAMIC_MINOR)
+ misc_deregister(&podev->miscdevice);
+ podev->registered = false;
+ }
+ mutex_unlock(&podev->register_lock);
+ret:
+
+ tasklet_kill(&pqce->done_tasklet);
+ kfree(pqce);
return 0;
+}
+
+static struct of_device_id qcota_match[] = {
+ { .compatible = "qcom,qcota",
+ },
+ {}
};
static struct platform_driver qcota_plat_driver = {
@@ -592,18 +661,21 @@
.driver = {
.name = "qcota",
.owner = THIS_MODULE,
+ .of_match_table = qcota_match,
},
};
-static int _disp_stats(int id)
+static int _disp_stats(void)
{
struct qcota_stat *pstat;
int len = 0;
+ struct ota_dev_control *podev = &qcota_dev;
+ unsigned long flags;
+ struct ota_qce_dev *p;
- pstat = &_qcota_stat[id];
+ pstat = &_qcota_stat;
len = snprintf(_debug_read_buf, DEBUG_MAX_RW_BUF - 1,
- "\nQualcomm OTA crypto accelerator %d Statistics:\n",
- id + 1);
+ "\nQualcomm OTA crypto accelerator Statistics:\n");
len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" F8 request : %d\n",
@@ -635,6 +707,27 @@
" F9 operation fail : %d\n",
pstat->f9_op_fail);
+ spin_lock_irqsave(&podev->lock, flags);
+
+ list_for_each_entry(p, &podev->qce_dev, qlist) {
+ len += snprintf(
+ _debug_read_buf + len,
+ DEBUG_MAX_RW_BUF - len - 1,
+ " Engine %d Req : %d\n",
+ p->unit,
+ p->totalReq
+ );
+ len += snprintf(
+ _debug_read_buf + len,
+ DEBUG_MAX_RW_BUF - len - 1,
+ " Engine %d Req Error : %d\n",
+ p->unit,
+ p->errReq
+ );
+ }
+
+ spin_unlock_irqrestore(&podev->lock, flags);
+
return len;
}
@@ -648,10 +741,9 @@
size_t count, loff_t *ppos)
{
int rc = -EINVAL;
- int qcota = *((int *) file->private_data);
int len;
- len = _disp_stats(qcota);
+ len = _disp_stats();
rc = simple_read_from_buffer((void __user *) buf, len,
ppos, (void *) _debug_read_buf, len);
@@ -662,12 +754,23 @@
static ssize_t _debug_stats_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
+ struct ota_dev_control *podev = &qcota_dev;
+ unsigned long flags;
+ struct ota_qce_dev *p;
- int qcota = *((int *) file->private_data);
+ memset((char *)&_qcota_stat, 0, sizeof(struct qcota_stat));
- memset((char *)&_qcota_stat[qcota], 0, sizeof(struct qcota_stat));
+ spin_lock_irqsave(&podev->lock, flags);
+
+ list_for_each_entry(p, &podev->qce_dev, qlist) {
+ p->totalReq = 0;
+ p->errReq = 0;
+ }
+
+ spin_unlock_irqrestore(&podev->lock, flags);
+
return count;
-};
+}
static const struct file_operations _debug_stats_ops = {
.open = _debug_stats_open,
@@ -679,7 +782,6 @@
{
int rc;
char name[DEBUG_MAX_FNAME];
- int i;
struct dentry *dent;
_debug_dent = debugfs_create_dir("qcota", NULL);
@@ -689,17 +791,15 @@
return PTR_ERR(_debug_dent);
}
- for (i = 0; i < MAX_OTA_DEVICE; i++) {
- snprintf(name, DEBUG_MAX_FNAME-1, "stats-%d", i+1);
- _debug_qcota[i] = i;
- dent = debugfs_create_file(name, 0644, _debug_dent,
- &_debug_qcota[i], &_debug_stats_ops);
- if (dent == NULL) {
- pr_err("qcota debugfs_create_file fail, error %ld\n",
+ snprintf(name, DEBUG_MAX_FNAME-1, "stats-0");
+ _debug_qcota = 0;
+ dent = debugfs_create_file(name, 0644, _debug_dent,
+ &_debug_qcota, &_debug_stats_ops);
+ if (dent == NULL) {
+ pr_err("qcota debugfs_create_file fail, error %ld\n",
PTR_ERR(dent));
- rc = PTR_ERR(dent);
- goto err;
- }
+ rc = PTR_ERR(dent);
+ goto err;
}
return 0;
err:
@@ -710,10 +810,20 @@
static int __init qcota_init(void)
{
int rc;
+ struct ota_dev_control *podev;
rc = _qcota_debug_init();
if (rc)
return rc;
+
+ podev = &qcota_dev;
+ INIT_LIST_HEAD(&podev->ready_commands);
+ INIT_LIST_HEAD(&podev->qce_dev);
+ spin_lock_init(&podev->lock);
+ mutex_init(&podev->register_lock);
+ podev->registered = false;
+ podev->total_units = 0;
+
return platform_driver_register(&qcota_plat_driver);
}
static void __exit qcota_exit(void)
@@ -725,7 +835,7 @@
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Rohit Vaswani <rvaswani@codeaurora.org>");
MODULE_DESCRIPTION("Qualcomm Ota Crypto driver");
-MODULE_VERSION("1.01");
+MODULE_VERSION("1.02");
module_init(qcota_init);
module_exit(qcota_exit);
diff --git a/drivers/crypto/msm/qce.h b/drivers/crypto/msm/qce.h
index cf75e93..b9b7a4e 100644
--- a/drivers/crypto/msm/qce.h
+++ b/drivers/crypto/msm/qce.h
@@ -1,6 +1,6 @@
/* Qualcomm Crypto Engine driver API
*
- * Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -116,6 +116,7 @@
bool aligned_only;
bool bam;
bool is_shared;
+ bool hw_key;
};
/* Sha operation parameters */
diff --git a/drivers/crypto/msm/qce50.c b/drivers/crypto/msm/qce50.c
index a3a662a..044bce2 100644
--- a/drivers/crypto/msm/qce50.c
+++ b/drivers/crypto/msm/qce50.c
@@ -63,6 +63,7 @@
int memsize; /* Memory allocated */
int is_shared; /* CE HW is shared */
bool support_cmd_dscr;
+ bool support_hw_key;
void __iomem *iobase; /* Virtual io base of CE HW */
unsigned int phy_iobase; /* Physical io base of CE HW */
@@ -1858,7 +1859,7 @@
* Set flag to indicate BAM global device control is managed
* remotely.
*/
- if (pce_dev->support_cmd_dscr == false)
+ if ((pce_dev->support_cmd_dscr == false) || (pce_dev->is_shared))
bam.manage = SPS_BAM_MGR_DEVICE_REMOTE;
else
bam.manage = SPS_BAM_MGR_LOCAL;
@@ -3311,6 +3312,8 @@
pce_dev->is_shared = of_property_read_bool((&pdev->dev)->of_node,
"qcom,ce-hw-shared");
+ pce_dev->support_hw_key = of_property_read_bool((&pdev->dev)->of_node,
+ "qcom,ce-hw-key");
if (of_property_read_u32((&pdev->dev)->of_node,
"qcom,bam-pipe-pair",
&pce_dev->ce_sps.pipe_pair_index)) {
@@ -3639,6 +3642,7 @@
ce_support->ota = false;
ce_support->bam = true;
ce_support->is_shared = (pce_dev->is_shared == 1) ? true : false;
+ ce_support->hw_key = pce_dev->support_hw_key;
ce_support->aes_ccm = true;
if (pce_dev->ce_sps.minor_version)
ce_support->aligned_only = false;
diff --git a/drivers/crypto/msm/qcedev.c b/drivers/crypto/msm/qcedev.c
index a18fb8b..d069f2e 100644
--- a/drivers/crypto/msm/qcedev.c
+++ b/drivers/crypto/msm/qcedev.c
@@ -1937,9 +1937,10 @@
rc = misc_register(&podev->miscdevice);
qce_hw_support(podev->qce, &podev->ce_support);
if (podev->ce_support.bam) {
- podev->platform_support.ce_shared = 0;
+ podev->platform_support.ce_shared = podev->ce_support.is_shared;
podev->platform_support.shared_ce_resource = 0;
- podev->platform_support.hw_key_support = 0;
+ podev->platform_support.hw_key_support =
+ podev->ce_support.hw_key;
podev->platform_support.bus_scale_table = NULL;
podev->platform_support.sha_hmac = 1;
diff --git a/drivers/crypto/msm/qcrypto.c b/drivers/crypto/msm/qcrypto.c
index 375516b..d2f511d 100644
--- a/drivers/crypto/msm/qcrypto.c
+++ b/drivers/crypto/msm/qcrypto.c
@@ -3387,9 +3387,9 @@
cp->pdev = pdev;
qce_hw_support(cp->qce, &cp->ce_support);
if (cp->ce_support.bam) {
- cp->platform_support.ce_shared = 0;
+ cp->platform_support.ce_shared = cp->ce_support.is_shared;
cp->platform_support.shared_ce_resource = 0;
- cp->platform_support.hw_key_support = 0;
+ cp->platform_support.hw_key_support = cp->ce_support.hw_key;
cp->platform_support.bus_scale_table = NULL;
cp->platform_support.sha_hmac = 1;
diff --git a/drivers/gpu/ion/msm/ion_cp_common.c b/drivers/gpu/ion/msm/ion_cp_common.c
index 58eca24..623a174 100644
--- a/drivers/gpu/ion/msm/ion_cp_common.c
+++ b/drivers/gpu/ion/msm/ion_cp_common.c
@@ -13,6 +13,7 @@
*/
#include <linux/memory_alloc.h>
+#include <linux/slab.h>
#include <linux/types.h>
#include <mach/scm.h>
#include <linux/highmem.h>
@@ -97,18 +98,17 @@
nchunks = size / V2_CHUNK_SIZE;
- chunk_list = allocate_contiguous_ebi(sizeof(unsigned long)*nchunks,
- SZ_4K, 0);
+ chunk_list = kmalloc(sizeof(unsigned long)*nchunks, GFP_KERNEL);
if (!chunk_list)
return -ENOMEM;
for (i = 0; i < nchunks; i++)
chunk_list[i] = phy_base + i * V2_CHUNK_SIZE;
- ret = ion_cp_change_chunks_state(memory_pool_node_paddr(chunk_list),
+ ret = ion_cp_change_chunks_state(__pa(chunk_list),
nchunks, V2_CHUNK_SIZE, usage, lock);
- free_contiguous_memory(chunk_list);
+ kfree(chunk_list);
return ret;
}
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index aad2882..d7bf193 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -603,10 +603,10 @@
static unsigned int _adreno_iommu_setstate_v0(struct kgsl_device *device,
unsigned int *cmds_orig,
- unsigned int pt_val,
+ phys_addr_t pt_val,
int num_iommu_units, uint32_t flags)
{
- unsigned int reg_pt_val;
+ phys_addr_t reg_pt_val;
unsigned int *cmds = cmds_orig;
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
int i;
@@ -632,8 +632,10 @@
* IOMMU units
*/
for (i = 0; i < num_iommu_units; i++) {
- reg_pt_val = (pt_val + kgsl_mmu_get_pt_lsb(&device->mmu,
- i, KGSL_IOMMU_CONTEXT_USER));
+ reg_pt_val = kgsl_mmu_get_default_ttbr0(&device->mmu,
+ i, KGSL_IOMMU_CONTEXT_USER);
+ reg_pt_val &= ~KGSL_IOMMU_CTX_TTBR0_ADDR_MASK;
+ reg_pt_val |= (pt_val & KGSL_IOMMU_CTX_TTBR0_ADDR_MASK);
/*
* Set address of the new pagetable by writng to IOMMU
* TTBR0 register
@@ -662,8 +664,11 @@
* tlb flush
*/
for (i = 0; i < num_iommu_units; i++) {
- reg_pt_val = (pt_val + kgsl_mmu_get_pt_lsb(&device->mmu,
+ reg_pt_val = (pt_val + kgsl_mmu_get_default_ttbr0(
+ &device->mmu,
i, KGSL_IOMMU_CONTEXT_USER));
+ reg_pt_val &= ~KGSL_IOMMU_CTX_TTBR0_ADDR_MASK;
+ reg_pt_val |= (pt_val & KGSL_IOMMU_CTX_TTBR0_ADDR_MASK);
*cmds++ = cp_type3_packet(CP_MEM_WRITE, 2);
*cmds++ = kgsl_mmu_get_reg_gpuaddr(&device->mmu, i,
@@ -707,17 +712,20 @@
static unsigned int _adreno_iommu_setstate_v1(struct kgsl_device *device,
unsigned int *cmds_orig,
- unsigned int pt_val,
+ phys_addr_t pt_val,
int num_iommu_units, uint32_t flags)
{
+ phys_addr_t ttbr0_val;
unsigned int reg_pt_val;
unsigned int *cmds = cmds_orig;
int i;
unsigned int ttbr0, tlbiall, tlbstatus, tlbsync, mmu_ctrl;
for (i = 0; i < num_iommu_units; i++) {
- reg_pt_val = (pt_val + kgsl_mmu_get_pt_lsb(&device->mmu,
- i, KGSL_IOMMU_CONTEXT_USER));
+ ttbr0_val = kgsl_mmu_get_default_ttbr0(&device->mmu,
+ i, KGSL_IOMMU_CONTEXT_USER);
+ ttbr0_val &= ~KGSL_IOMMU_CTX_TTBR0_ADDR_MASK;
+ ttbr0_val |= (pt_val & KGSL_IOMMU_CTX_TTBR0_ADDR_MASK);
if (flags & KGSL_MMUFLAGS_PTUPDATE) {
mmu_ctrl = kgsl_mmu_get_reg_ahbaddr(
&device->mmu, i,
@@ -753,8 +761,19 @@
KGSL_IOMMU_IMPLDEF_MICRO_MMU_CTRL_IDLE, 0xF);
}
/* set ttbr0 */
- *cmds++ = cp_type0_packet(ttbr0, 1);
- *cmds++ = reg_pt_val;
+ if (sizeof(phys_addr_t) > sizeof(unsigned long)) {
+ reg_pt_val = ttbr0_val & 0xFFFFFFFF;
+ *cmds++ = cp_type0_packet(ttbr0, 1);
+ *cmds++ = reg_pt_val;
+ reg_pt_val = (unsigned int)
+ ((ttbr0_val & 0xFFFFFFFF00000000ULL) >> 32);
+ *cmds++ = cp_type0_packet(ttbr0 + 1, 1);
+ *cmds++ = reg_pt_val;
+ } else {
+ reg_pt_val = ttbr0_val;
+ *cmds++ = cp_type0_packet(ttbr0, 1);
+ *cmds++ = reg_pt_val;
+ }
if (kgsl_mmu_hw_halt_supported(&device->mmu, i)) {
/* unlock the IOMMU lock */
*cmds++ = cp_type3_packet(CP_REG_RMW, 3);
@@ -796,7 +815,7 @@
unsigned int context_id,
uint32_t flags)
{
- unsigned int pt_val;
+ phys_addr_t pt_val;
unsigned int link[230];
unsigned int *cmds = &link[0];
int sizedwords = 0;
@@ -808,7 +827,8 @@
if (!adreno_dev->drawctxt_active ||
KGSL_STATE_ACTIVE != device->state ||
- !device->active_cnt) {
+ !device->active_cnt ||
+ device->cff_dump_enable) {
kgsl_mmu_device_setstate(&device->mmu, flags);
return;
}
@@ -891,7 +911,7 @@
* writes For CFF dump we must idle and use the registers so that it is
* easier to filter out the mmu accesses from the dump
*/
- if (!kgsl_cff_dump_enable && adreno_dev->drawctxt_active) {
+ if (!device->cff_dump_enable && adreno_dev->drawctxt_active) {
context = idr_find(&device->context_idr, context_id);
if (context == NULL)
return;
@@ -1814,7 +1834,7 @@
/* Power down the device */
kgsl_pwrctrl_disable(device);
- kgsl_cffdump_close(device->id);
+ kgsl_cffdump_close(device);
return 0;
}
@@ -1861,11 +1881,11 @@
while ((context = idr_get_next(&device->context_idr, &next))) {
temp_adreno_context = context->devctxt;
if (temp_adreno_context->flags & CTXT_FLAGS_GPU_HANG) {
- kgsl_sharedmem_writel(&device->memstore,
+ kgsl_sharedmem_writel(device, &device->memstore,
KGSL_MEMSTORE_OFFSET(context->id,
soptimestamp),
rb->timestamp[context->id]);
- kgsl_sharedmem_writel(&device->memstore,
+ kgsl_sharedmem_writel(device, &device->memstore,
KGSL_MEMSTORE_OFFSET(context->id,
eoptimestamp),
rb->timestamp[context->id]);
@@ -2542,7 +2562,7 @@
else
device->mmu.hwpagetable = device->mmu.defaultpagetable;
rb->timestamp[KGSL_MEMSTORE_GLOBAL] = timestamp;
- kgsl_sharedmem_writel(&device->memstore,
+ kgsl_sharedmem_writel(device, &device->memstore,
KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
eoptimestamp),
rb->timestamp[KGSL_MEMSTORE_GLOBAL]);
@@ -2581,6 +2601,7 @@
INIT_COMPLETION(device->ft_gate);
/* Detected a hang */
+ kgsl_cffdump_hang(device);
/* Run fault tolerance at max power level */
curr_pwrlevel = pwr->active_pwrlevel;
kgsl_pwrctrl_pwrlevel_change(device, pwr->max_pwrlevel);
@@ -2822,7 +2843,7 @@
memset(prev_reg_val, 0, sizeof(prev_reg_val));
- kgsl_cffdump_regpoll(device->id,
+ kgsl_cffdump_regpoll(device,
adreno_dev->gpudev->reg_rbbm_status << 2,
0x00000000, 0x80000000);
@@ -2944,7 +2965,7 @@
/* Find a memory structure attached to an adreno context */
struct kgsl_memdesc *adreno_find_ctxtmem(struct kgsl_device *device,
- unsigned int pt_base, unsigned int gpuaddr, unsigned int size)
+ phys_addr_t pt_base, unsigned int gpuaddr, unsigned int size)
{
struct kgsl_context *context;
struct adreno_context *adreno_context = NULL;
@@ -2976,7 +2997,7 @@
}
struct kgsl_memdesc *adreno_find_region(struct kgsl_device *device,
- unsigned int pt_base,
+ phys_addr_t pt_base,
unsigned int gpuaddr,
unsigned int size)
{
@@ -3005,7 +3026,7 @@
return adreno_find_ctxtmem(device, pt_base, gpuaddr, size);
}
-uint8_t *adreno_convertaddr(struct kgsl_device *device, unsigned int pt_base,
+uint8_t *adreno_convertaddr(struct kgsl_device *device, phys_addr_t pt_base,
unsigned int gpuaddr, unsigned int size)
{
struct kgsl_memdesc *memdesc;
@@ -3079,7 +3100,7 @@
kgsl_trace_regwrite(device, offsetwords, value);
- kgsl_cffdump_regwrite(device->id, offsetwords << 2, value);
+ kgsl_cffdump_regwrite(device, offsetwords << 2, value);
reg = (unsigned int *)(device->reg_virt + (offsetwords << 2));
/*ensure previous writes post before this one,
@@ -3139,18 +3160,18 @@
/* Make sure the memstore read has posted */
mb();
if (timestamp_cmp(ref_ts, timestamp) >= 0) {
- kgsl_sharedmem_writel(&device->memstore,
+ kgsl_sharedmem_writel(device, &device->memstore,
KGSL_MEMSTORE_OFFSET(context_id,
ref_wait_ts), timestamp);
/* Make sure the memstore write is posted */
wmb();
}
} else {
- kgsl_sharedmem_writel(&device->memstore,
+ kgsl_sharedmem_writel(device, &device->memstore,
KGSL_MEMSTORE_OFFSET(context_id,
ref_wait_ts), timestamp);
enableflag = 1;
- kgsl_sharedmem_writel(&device->memstore,
+ kgsl_sharedmem_writel(device, &device->memstore,
KGSL_MEMSTORE_OFFSET(context_id,
ts_cmp_enable), enableflag);
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 77b654b..816940f 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -302,15 +302,15 @@
*adreno_dev);
struct kgsl_memdesc *adreno_find_region(struct kgsl_device *device,
- unsigned int pt_base,
+ phys_addr_t pt_base,
unsigned int gpuaddr,
unsigned int size);
uint8_t *adreno_convertaddr(struct kgsl_device *device,
- unsigned int pt_base, unsigned int gpuaddr, unsigned int size);
+ phys_addr_t pt_base, unsigned int gpuaddr, unsigned int size);
struct kgsl_memdesc *adreno_find_ctxtmem(struct kgsl_device *device,
- unsigned int pt_base, unsigned int gpuaddr, unsigned int size);
+ phys_addr_t pt_base, unsigned int gpuaddr, unsigned int size);
void *adreno_snapshot(struct kgsl_device *device, void *snapshot, int *remain,
int hang);
diff --git a/drivers/gpu/msm/adreno_a2xx.c b/drivers/gpu/msm/adreno_a2xx.c
index dd9bdc3..b0a1fe8 100644
--- a/drivers/gpu/msm/adreno_a2xx.c
+++ b/drivers/gpu/msm/adreno_a2xx.c
@@ -1364,8 +1364,9 @@
drawctxt->flags |= CTXT_FLAGS_GMEM_SHADOW;
/* blank out gmem shadow. */
- kgsl_sharedmem_set(&drawctxt->context_gmem_shadow.gmemshadow, 0, 0,
- drawctxt->context_gmem_shadow.size);
+ kgsl_sharedmem_set(drawctxt->dev_priv->device,
+ &drawctxt->context_gmem_shadow.gmemshadow, 0, 0,
+ drawctxt->context_gmem_shadow.size);
/* build quad vertex buffer */
build_quad_vtxbuff(drawctxt, &drawctxt->context_gmem_shadow,
@@ -1388,7 +1389,7 @@
kgsl_cache_range_op(&drawctxt->context_gmem_shadow.gmemshadow,
KGSL_CACHE_OP_FLUSH);
- kgsl_cffdump_syncmem(NULL,
+ kgsl_cffdump_syncmem(drawctxt->dev_priv,
&drawctxt->context_gmem_shadow.gmemshadow,
drawctxt->context_gmem_shadow.gmemshadow.gpuaddr,
drawctxt->context_gmem_shadow.gmemshadow.size, false);
@@ -1414,8 +1415,8 @@
if (ret)
return ret;
- kgsl_sharedmem_set(&drawctxt->gpustate, 0, 0,
- _context_size(adreno_dev));
+ kgsl_sharedmem_set(drawctxt->dev_priv->device, &drawctxt->gpustate, 0,
+ 0, _context_size(adreno_dev));
tmp_ctx.cmd = tmp_ctx.start
= (unsigned int *)((char *)drawctxt->gpustate.hostptr + CMD_OFFSET);
@@ -1439,7 +1440,7 @@
kgsl_cache_range_op(&drawctxt->gpustate,
KGSL_CACHE_OP_FLUSH);
- kgsl_cffdump_syncmem(NULL, &drawctxt->gpustate,
+ kgsl_cffdump_syncmem(drawctxt->dev_priv, &drawctxt->gpustate,
drawctxt->gpustate.gpuaddr,
drawctxt->gpustate.size, false);
@@ -1515,7 +1516,7 @@
"Current active context has caused gpu hang\n");
if (!(context->flags & CTXT_FLAGS_PREAMBLE)) {
- kgsl_cffdump_syncmem(NULL, &context->gpustate,
+ kgsl_cffdump_syncmem(context->dev_priv, &context->gpustate,
context->reg_save[1],
context->reg_save[2] << 2, true);
/* save registers and constants. */
@@ -1524,7 +1525,8 @@
context->reg_save, 3);
if (context->flags & CTXT_FLAGS_SHADER_SAVE) {
- kgsl_cffdump_syncmem(NULL, &context->gpustate,
+ kgsl_cffdump_syncmem(context->dev_priv,
+ &context->gpustate,
context->shader_save[1],
context->shader_save[2] << 2, true);
/* save shader partitioning and instructions. */
@@ -1532,7 +1534,8 @@
KGSL_CMD_FLAGS_PMODE,
context->shader_save, 3);
- kgsl_cffdump_syncmem(NULL, &context->gpustate,
+ kgsl_cffdump_syncmem(context->dev_priv,
+ &context->gpustate,
context->shader_fixup[1],
context->shader_fixup[2] << 2, true);
/*
@@ -1549,7 +1552,7 @@
if ((context->flags & CTXT_FLAGS_GMEM_SAVE) &&
(context->flags & CTXT_FLAGS_GMEM_SHADOW)) {
- kgsl_cffdump_syncmem(NULL, &context->gpustate,
+ kgsl_cffdump_syncmem(context->dev_priv, &context->gpustate,
context->context_gmem_shadow.gmem_save[1],
context->context_gmem_shadow.gmem_save[2] << 2, true);
/* save gmem.
@@ -1559,7 +1562,7 @@
KGSL_CMD_FLAGS_PMODE,
context->context_gmem_shadow.gmem_save, 3);
- kgsl_cffdump_syncmem(NULL, &context->gpustate,
+ kgsl_cffdump_syncmem(context->dev_priv, &context->gpustate,
context->chicken_restore[1],
context->chicken_restore[2] << 2, true);
@@ -1603,7 +1606,7 @@
* (note: changes shader. shader must not already be restored.)
*/
if (context->flags & CTXT_FLAGS_GMEM_RESTORE) {
- kgsl_cffdump_syncmem(NULL, &context->gpustate,
+ kgsl_cffdump_syncmem(context->dev_priv, &context->gpustate,
context->context_gmem_shadow.gmem_restore[1],
context->context_gmem_shadow.gmem_restore[2] << 2,
true);
@@ -1613,7 +1616,8 @@
context->context_gmem_shadow.gmem_restore, 3);
if (!(context->flags & CTXT_FLAGS_PREAMBLE)) {
- kgsl_cffdump_syncmem(NULL, &context->gpustate,
+ kgsl_cffdump_syncmem(context->dev_priv,
+ &context->gpustate,
context->chicken_restore[1],
context->chicken_restore[2] << 2, true);
@@ -1627,7 +1631,7 @@
}
if (!(context->flags & CTXT_FLAGS_PREAMBLE)) {
- kgsl_cffdump_syncmem(NULL, &context->gpustate,
+ kgsl_cffdump_syncmem(context->dev_priv, &context->gpustate,
context->reg_restore[1],
context->reg_restore[2] << 2, true);
@@ -1637,7 +1641,8 @@
/* restore shader instructions & partitioning. */
if (context->flags & CTXT_FLAGS_SHADER_RESTORE) {
- kgsl_cffdump_syncmem(NULL, &context->gpustate,
+ kgsl_cffdump_syncmem(context->dev_priv,
+ &context->gpustate,
context->shader_restore[1],
context->shader_restore[2] << 2, true);
@@ -1862,54 +1867,56 @@
cmds_gpu = rb->buffer_desc.gpuaddr + sizeof(uint)*(rb->wptr-19);
- GSL_RB_WRITE(cmds, cmds_gpu, cp_type3_packet(CP_ME_INIT, 18));
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu, cp_type3_packet(CP_ME_INIT,
+ 18));
/* All fields present (bits 9:0) */
- GSL_RB_WRITE(cmds, cmds_gpu, 0x000003ff);
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu, 0x000003ff);
/* Disable/Enable Real-Time Stream processing (present but ignored) */
- GSL_RB_WRITE(cmds, cmds_gpu, 0x00000000);
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu, 0x00000000);
/* Enable (2D <-> 3D) implicit synchronization (present but ignored) */
- GSL_RB_WRITE(cmds, cmds_gpu, 0x00000000);
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu, 0x00000000);
- GSL_RB_WRITE(cmds, cmds_gpu,
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu,
SUBBLOCK_OFFSET(REG_RB_SURFACE_INFO));
- GSL_RB_WRITE(cmds, cmds_gpu,
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu,
SUBBLOCK_OFFSET(REG_PA_SC_WINDOW_OFFSET));
- GSL_RB_WRITE(cmds, cmds_gpu,
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu,
SUBBLOCK_OFFSET(REG_VGT_MAX_VTX_INDX));
- GSL_RB_WRITE(cmds, cmds_gpu,
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu,
SUBBLOCK_OFFSET(REG_SQ_PROGRAM_CNTL));
- GSL_RB_WRITE(cmds, cmds_gpu,
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu,
SUBBLOCK_OFFSET(REG_RB_DEPTHCONTROL));
- GSL_RB_WRITE(cmds, cmds_gpu,
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu,
SUBBLOCK_OFFSET(REG_PA_SU_POINT_SIZE));
- GSL_RB_WRITE(cmds, cmds_gpu,
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu,
SUBBLOCK_OFFSET(REG_PA_SC_LINE_CNTL));
- GSL_RB_WRITE(cmds, cmds_gpu,
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu,
SUBBLOCK_OFFSET(REG_PA_SU_POLY_OFFSET_FRONT_SCALE));
/* Instruction memory size: */
- GSL_RB_WRITE(cmds, cmds_gpu,
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu,
(adreno_encode_istore_size(adreno_dev)
| adreno_dev->pix_shader_start));
/* Maximum Contexts */
- GSL_RB_WRITE(cmds, cmds_gpu, 0x00000001);
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu, 0x00000001);
/* Write Confirm Interval and The CP will wait the
* wait_interval * 16 clocks between polling */
- GSL_RB_WRITE(cmds, cmds_gpu, 0x00000000);
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu, 0x00000000);
/* NQ and External Memory Swap */
- GSL_RB_WRITE(cmds, cmds_gpu, 0x00000000);
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu, 0x00000000);
/* Protected mode error checking
* If iommu is used then protection needs to be turned off
* to enable context bank switching */
if (KGSL_MMU_TYPE_IOMMU == kgsl_mmu_get_mmutype())
- GSL_RB_WRITE(cmds, cmds_gpu, 0);
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu, 0);
else
- GSL_RB_WRITE(cmds, cmds_gpu, GSL_RB_PROTECTED_MODE_CONTROL);
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu,
+ GSL_RB_PROTECTED_MODE_CONTROL);
/* Disable header dumping and Header dump address */
- GSL_RB_WRITE(cmds, cmds_gpu, 0x00000000);
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu, 0x00000000);
/* Header dump size */
- GSL_RB_WRITE(cmds, cmds_gpu, 0x00000000);
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu, 0x00000000);
adreno_ringbuffer_submit(rb);
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index 1cdc87a..884b72b 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -2360,7 +2360,8 @@
if (ret)
return ret;
- kgsl_sharedmem_set(&drawctxt->gpustate, 0, 0, CONTEXT_SIZE);
+ kgsl_sharedmem_set(&adreno_dev->dev, &drawctxt->gpustate, 0, 0,
+ CONTEXT_SIZE);
tmp_ctx.cmd = drawctxt->gpustate.hostptr + CMD_OFFSET;
if (!(drawctxt->flags & CTXT_FLAGS_PREAMBLE)) {
@@ -2419,7 +2420,7 @@
* already be saved.)
*/
- kgsl_cffdump_syncmem(NULL,
+ kgsl_cffdump_syncmem(context->dev_priv,
&context->gpustate,
context->context_gmem_shadow.gmem_save[1],
context->context_gmem_shadow.gmem_save[2] << 2, true);
@@ -2461,7 +2462,7 @@
*/
if (context->flags & CTXT_FLAGS_GMEM_RESTORE) {
- kgsl_cffdump_syncmem(NULL,
+ kgsl_cffdump_syncmem(context->dev_priv,
&context->gpustate,
context->context_gmem_shadow.gmem_restore[1],
context->context_gmem_shadow.gmem_restore[2] << 2,
@@ -2509,25 +2510,26 @@
cmds_gpu = rb->buffer_desc.gpuaddr + sizeof(uint) * (rb->wptr - 18);
- GSL_RB_WRITE(cmds, cmds_gpu, cp_type3_packet(CP_ME_INIT, 17));
- GSL_RB_WRITE(cmds, cmds_gpu, 0x000003f7);
- GSL_RB_WRITE(cmds, cmds_gpu, 0x00000000);
- GSL_RB_WRITE(cmds, cmds_gpu, 0x00000000);
- GSL_RB_WRITE(cmds, cmds_gpu, 0x00000000);
- GSL_RB_WRITE(cmds, cmds_gpu, 0x00000080);
- GSL_RB_WRITE(cmds, cmds_gpu, 0x00000100);
- GSL_RB_WRITE(cmds, cmds_gpu, 0x00000180);
- GSL_RB_WRITE(cmds, cmds_gpu, 0x00006600);
- GSL_RB_WRITE(cmds, cmds_gpu, 0x00000150);
- GSL_RB_WRITE(cmds, cmds_gpu, 0x0000014e);
- GSL_RB_WRITE(cmds, cmds_gpu, 0x00000154);
- GSL_RB_WRITE(cmds, cmds_gpu, 0x00000001);
- GSL_RB_WRITE(cmds, cmds_gpu, 0x00000000);
- GSL_RB_WRITE(cmds, cmds_gpu, 0x00000000);
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu,
+ cp_type3_packet(CP_ME_INIT, 17));
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu, 0x000003f7);
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu, 0x00000000);
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu, 0x00000000);
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu, 0x00000000);
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu, 0x00000080);
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu, 0x00000100);
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu, 0x00000180);
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu, 0x00006600);
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu, 0x00000150);
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu, 0x0000014e);
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu, 0x00000154);
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu, 0x00000001);
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu, 0x00000000);
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu, 0x00000000);
/* Protected mode control - turned off for A3XX */
- GSL_RB_WRITE(cmds, cmds_gpu, 0x00000000);
- GSL_RB_WRITE(cmds, cmds_gpu, 0x00000000);
- GSL_RB_WRITE(cmds, cmds_gpu, 0x00000000);
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu, 0x00000000);
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu, 0x00000000);
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu, 0x00000000);
adreno_ringbuffer_submit(rb);
diff --git a/drivers/gpu/msm/adreno_debugfs.c b/drivers/gpu/msm/adreno_debugfs.c
index 980ff13..12b9e7c 100644
--- a/drivers/gpu/msm/adreno_debugfs.c
+++ b/drivers/gpu/msm/adreno_debugfs.c
@@ -19,27 +19,12 @@
#include "kgsl.h"
#include "adreno.h"
+#include "kgsl_cffdump.h"
#include "a2xx_reg.h"
unsigned int kgsl_cff_dump_enable;
-static int kgsl_cff_dump_enable_set(void *data, u64 val)
-{
-#ifdef CONFIG_MSM_KGSL_CFF_DUMP
- kgsl_cff_dump_enable = (val != 0);
- return 0;
-#else
- return -EINVAL;
-#endif
-}
-
-static int kgsl_cff_dump_enable_get(void *data, u64 *val)
-{
- *val = kgsl_cff_dump_enable;
- return 0;
-}
-
DEFINE_SIMPLE_ATTRIBUTE(kgsl_cff_dump_enable_fops, kgsl_cff_dump_enable_get,
kgsl_cff_dump_enable_set, "%llu\n");
diff --git a/drivers/gpu/msm/adreno_drawctxt.c b/drivers/gpu/msm/adreno_drawctxt.c
index 176717d..b32cdae 100644
--- a/drivers/gpu/msm/adreno_drawctxt.c
+++ b/drivers/gpu/msm/adreno_drawctxt.c
@@ -192,19 +192,20 @@
drawctxt->type =
(*flags & KGSL_CONTEXT_TYPE_MASK) >> KGSL_CONTEXT_TYPE_SHIFT;
+ drawctxt->dev_priv = context->dev_priv;
ret = adreno_dev->gpudev->ctxt_create(adreno_dev, drawctxt);
if (ret)
goto err;
- kgsl_sharedmem_writel(&device->memstore,
+ kgsl_sharedmem_writel(device, &device->memstore,
KGSL_MEMSTORE_OFFSET(drawctxt->id, ref_wait_ts),
KGSL_INIT_REFTIMESTAMP);
- kgsl_sharedmem_writel(&device->memstore,
+ kgsl_sharedmem_writel(device, &device->memstore,
KGSL_MEMSTORE_OFFSET(drawctxt->id, ts_cmp_enable), 0);
- kgsl_sharedmem_writel(&device->memstore,
+ kgsl_sharedmem_writel(device, &device->memstore,
KGSL_MEMSTORE_OFFSET(drawctxt->id, soptimestamp), 0);
- kgsl_sharedmem_writel(&device->memstore,
+ kgsl_sharedmem_writel(device, &device->memstore,
KGSL_MEMSTORE_OFFSET(drawctxt->id, eoptimestamp), 0);
context->devctxt = drawctxt;
diff --git a/drivers/gpu/msm/adreno_drawctxt.h b/drivers/gpu/msm/adreno_drawctxt.h
index f0f3b6b..2b8e600 100644
--- a/drivers/gpu/msm/adreno_drawctxt.h
+++ b/drivers/gpu/msm/adreno_drawctxt.h
@@ -131,6 +131,7 @@
struct kgsl_memdesc constant_load_commands[3];
struct kgsl_memdesc cond_execs[4];
struct kgsl_memdesc hlsqcontrol_restore_commands[1];
+ struct kgsl_device_private *dev_priv;
};
int adreno_drawctxt_create(struct kgsl_device *device,
diff --git a/drivers/gpu/msm/adreno_postmortem.c b/drivers/gpu/msm/adreno_postmortem.c
index 2249907..c7b6b5b 100644
--- a/drivers/gpu/msm/adreno_postmortem.c
+++ b/drivers/gpu/msm/adreno_postmortem.c
@@ -190,8 +190,9 @@
}
}
-static void dump_ib(struct kgsl_device *device, char* buffId, uint32_t pt_base,
- uint32_t base_offset, uint32_t ib_base, uint32_t ib_size, bool dump)
+static void dump_ib(struct kgsl_device *device, char *buffId,
+ phys_addr_t pt_base, uint32_t base_offset, uint32_t ib_base,
+ uint32_t ib_size, bool dump)
{
uint8_t *base_addr = adreno_convertaddr(device, pt_base,
ib_base, ib_size*sizeof(uint32_t));
@@ -214,7 +215,7 @@
uint32_t offsets[IB_LIST_SIZE];
};
-static void dump_ib1(struct kgsl_device *device, uint32_t pt_base,
+static void dump_ib1(struct kgsl_device *device, phys_addr_t pt_base,
uint32_t base_offset,
uint32_t ib1_base, uint32_t ib1_size,
struct ib_list *ib_list, bool dump)
@@ -719,7 +720,7 @@
{
unsigned int cp_ib1_base, cp_ib1_bufsz;
unsigned int cp_ib2_base, cp_ib2_bufsz;
- unsigned int pt_base, cur_pt_base;
+ phys_addr_t pt_base, cur_pt_base;
unsigned int cp_rb_base, cp_rb_ctrl, rb_count;
unsigned int cp_rb_wptr, cp_rb_rptr;
unsigned int i;
@@ -862,20 +863,20 @@
&device->mmu, 0,
KGSL_IOMMU_CONTEXT_USER,
KGSL_IOMMU_CTX_TTBR0), 1))) {
- KGSL_LOG_DUMP(device, "Current pagetable: %x\t"
- "pagetable base: %x\n",
+ KGSL_LOG_DUMP(device,
+ "Current pagetable: %x\t pagetable base: %pa\n",
kgsl_mmu_get_ptname_from_ptbase(&device->mmu,
cur_pt_base),
- cur_pt_base);
+ &cur_pt_base);
/* Set cur_pt_base to the new pagetable base */
cur_pt_base = rb_copy[read_idx++];
- KGSL_LOG_DUMP(device, "New pagetable: %x\t"
- "pagetable base: %x\n",
+ KGSL_LOG_DUMP(device,
+ "New pagetable: %x\t pagetable base: %pa\n",
kgsl_mmu_get_ptname_from_ptbase(&device->mmu,
cur_pt_base),
- cur_pt_base);
+ &cur_pt_base);
}
}
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index 61ea916..4e95e93 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -76,7 +76,8 @@
cmds = (unsigned int *)rb->buffer_desc.hostptr + rb->wptr;
cmds_gpu = rb->buffer_desc.gpuaddr + sizeof(uint)*rb->wptr;
- GSL_RB_WRITE(cmds, cmds_gpu, cp_nop_packet(nopcount));
+ GSL_RB_WRITE(rb->device, cmds, cmds_gpu,
+ cp_nop_packet(nopcount));
/* Make sure that rptr is not 0 before submitting
* commands at the end of ringbuffer. We do not
@@ -331,10 +332,10 @@
if (rb->flags & KGSL_FLAGS_STARTED)
return 0;
- kgsl_sharedmem_set(&rb->memptrs_desc, 0, 0,
+ kgsl_sharedmem_set(rb->device, &rb->memptrs_desc, 0, 0,
sizeof(struct kgsl_rbmemptrs));
- kgsl_sharedmem_set(&rb->buffer_desc, 0, 0xAA,
+ kgsl_sharedmem_set(rb->device, &rb->buffer_desc, 0, 0xAA,
(rb->sizedwords << 2));
if (adreno_is_a2xx(adreno_dev)) {
@@ -612,12 +613,13 @@
rcmd_gpu = rb->buffer_desc.gpuaddr
+ sizeof(uint)*(rb->wptr-total_sizedwords);
- GSL_RB_WRITE(ringcmds, rcmd_gpu, cp_nop_packet(1));
- GSL_RB_WRITE(ringcmds, rcmd_gpu, KGSL_CMD_IDENTIFIER);
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, cp_nop_packet(1));
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, KGSL_CMD_IDENTIFIER);
if (flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE) {
- GSL_RB_WRITE(ringcmds, rcmd_gpu, cp_nop_packet(1));
- GSL_RB_WRITE(ringcmds, rcmd_gpu, KGSL_CMD_INTERNAL_IDENTIFIER);
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, cp_nop_packet(1));
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
+ KGSL_CMD_INTERNAL_IDENTIFIER);
}
/* always increment the global timestamp. once. */
@@ -636,32 +638,35 @@
timestamp = rb->timestamp[context_id];
/* scratchpad ts for fault tolerance */
- GSL_RB_WRITE(ringcmds, rcmd_gpu, cp_type0_packet(REG_CP_TIMESTAMP, 1));
- GSL_RB_WRITE(ringcmds, rcmd_gpu, rb->timestamp[KGSL_MEMSTORE_GLOBAL]);
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
+ cp_type0_packet(REG_CP_TIMESTAMP, 1));
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
+ rb->timestamp[KGSL_MEMSTORE_GLOBAL]);
/* start-of-pipeline timestamp */
- GSL_RB_WRITE(ringcmds, rcmd_gpu, cp_type3_packet(CP_MEM_WRITE, 2));
- GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr +
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
+ cp_type3_packet(CP_MEM_WRITE, 2));
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, (gpuaddr +
KGSL_MEMSTORE_OFFSET(context_id, soptimestamp)));
- GSL_RB_WRITE(ringcmds, rcmd_gpu, timestamp);
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, timestamp);
if (flags & KGSL_CMD_FLAGS_PMODE) {
/* disable protected mode error checking */
- GSL_RB_WRITE(ringcmds, rcmd_gpu,
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
cp_type3_packet(CP_SET_PROTECTED_MODE, 1));
- GSL_RB_WRITE(ringcmds, rcmd_gpu, 0);
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, 0);
}
for (i = 0; i < sizedwords; i++) {
- GSL_RB_WRITE(ringcmds, rcmd_gpu, *cmds);
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, *cmds);
cmds++;
}
if (flags & KGSL_CMD_FLAGS_PMODE) {
/* re-enable protected mode error checking */
- GSL_RB_WRITE(ringcmds, rcmd_gpu,
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
cp_type3_packet(CP_SET_PROTECTED_MODE, 1));
- GSL_RB_WRITE(ringcmds, rcmd_gpu, 1);
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, 1);
}
/* HW Workaround for MMU Page fault
@@ -669,9 +674,9 @@
* GPU completes it.
*/
if (adreno_is_a2xx(adreno_dev)) {
- GSL_RB_WRITE(ringcmds, rcmd_gpu,
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
cp_type3_packet(CP_WAIT_FOR_IDLE, 1));
- GSL_RB_WRITE(ringcmds, rcmd_gpu, 0x00);
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, 0x00);
}
if (adreno_is_a3xx(adreno_dev)) {
@@ -680,12 +685,13 @@
* resources pending for indirect loads after the timestamp
*/
- GSL_RB_WRITE(ringcmds, rcmd_gpu,
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
cp_type3_packet(CP_EVENT_WRITE, 1));
- GSL_RB_WRITE(ringcmds, rcmd_gpu, 0x07); /* HLSQ_FLUSH */
- GSL_RB_WRITE(ringcmds, rcmd_gpu,
+ GSL_RB_WRITE(rb->device, ringcmds,
+ rcmd_gpu, 0x07); /* HLSQ_FLUSH */
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
cp_type3_packet(CP_WAIT_FOR_IDLE, 1));
- GSL_RB_WRITE(ringcmds, rcmd_gpu, 0x00);
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, 0x00);
}
/*
@@ -693,62 +699,64 @@
* enabled, then context_id will be KGSL_MEMSTORE_GLOBAL so all
* eop timestamps will work out.
*/
- GSL_RB_WRITE(ringcmds, rcmd_gpu, cp_type3_packet(CP_EVENT_WRITE, 3));
- GSL_RB_WRITE(ringcmds, rcmd_gpu, CACHE_FLUSH_TS);
- GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr +
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
+ cp_type3_packet(CP_EVENT_WRITE, 3));
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, CACHE_FLUSH_TS);
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, (gpuaddr +
KGSL_MEMSTORE_OFFSET(context_id, eoptimestamp)));
- GSL_RB_WRITE(ringcmds, rcmd_gpu, timestamp);
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, timestamp);
if (KGSL_MEMSTORE_GLOBAL != context_id) {
- GSL_RB_WRITE(ringcmds, rcmd_gpu,
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
cp_type3_packet(CP_MEM_WRITE, 2));
- GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr +
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, (gpuaddr +
KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
eoptimestamp)));
- GSL_RB_WRITE(ringcmds, rcmd_gpu,
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
rb->timestamp[KGSL_MEMSTORE_GLOBAL]);
}
if (adreno_is_a20x(adreno_dev)) {
- GSL_RB_WRITE(ringcmds, rcmd_gpu,
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
cp_type3_packet(CP_EVENT_WRITE, 1));
- GSL_RB_WRITE(ringcmds, rcmd_gpu, CACHE_FLUSH);
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, CACHE_FLUSH);
}
if (context) {
/* Conditional execution based on memory values */
- GSL_RB_WRITE(ringcmds, rcmd_gpu,
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
cp_type3_packet(CP_COND_EXEC, 4));
- GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr +
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, (gpuaddr +
KGSL_MEMSTORE_OFFSET(
context_id, ts_cmp_enable)) >> 2);
- GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr +
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, (gpuaddr +
KGSL_MEMSTORE_OFFSET(
context_id, ref_wait_ts)) >> 2);
- GSL_RB_WRITE(ringcmds, rcmd_gpu, timestamp);
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, timestamp);
/* # of conditional command DWORDs */
- GSL_RB_WRITE(ringcmds, rcmd_gpu, 8);
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, 8);
/* Clear the ts_cmp_enable for the context */
- GSL_RB_WRITE(ringcmds, rcmd_gpu,
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
cp_type3_packet(CP_MEM_WRITE, 2));
- GSL_RB_WRITE(ringcmds, rcmd_gpu, gpuaddr +
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, gpuaddr +
KGSL_MEMSTORE_OFFSET(
context_id, ts_cmp_enable));
- GSL_RB_WRITE(ringcmds, rcmd_gpu, 0x0);
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, 0x0);
/* Clear the ts_cmp_enable for the global timestamp */
- GSL_RB_WRITE(ringcmds, rcmd_gpu,
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
cp_type3_packet(CP_MEM_WRITE, 2));
- GSL_RB_WRITE(ringcmds, rcmd_gpu, gpuaddr +
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, gpuaddr +
KGSL_MEMSTORE_OFFSET(
KGSL_MEMSTORE_GLOBAL, ts_cmp_enable));
- GSL_RB_WRITE(ringcmds, rcmd_gpu, 0x0);
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, 0x0);
/* Trigger the interrupt */
- GSL_RB_WRITE(ringcmds, rcmd_gpu,
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
cp_type3_packet(CP_INTERRUPT, 1));
- GSL_RB_WRITE(ringcmds, rcmd_gpu, CP_INT_CNTL__RB_INT_MASK);
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
+ CP_INT_CNTL__RB_INT_MASK);
}
/*
@@ -758,24 +766,25 @@
if ((context) && (context->flags & CTXT_FLAGS_PER_CONTEXT_TS) &&
(flags & (KGSL_CMD_FLAGS_INTERNAL_ISSUE |
KGSL_CMD_FLAGS_GET_INT))) {
- GSL_RB_WRITE(ringcmds, rcmd_gpu,
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
cp_type3_packet(CP_INTERRUPT, 1));
- GSL_RB_WRITE(ringcmds, rcmd_gpu,
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
CP_INT_CNTL__RB_INT_MASK);
}
if (adreno_is_a3xx(adreno_dev)) {
/* Dummy set-constant to trigger context rollover */
- GSL_RB_WRITE(ringcmds, rcmd_gpu,
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
cp_type3_packet(CP_SET_CONSTANT, 2));
- GSL_RB_WRITE(ringcmds, rcmd_gpu,
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
(0x4<<16)|(A3XX_HLSQ_CL_KERNEL_GROUP_X_REG - 0x2000));
- GSL_RB_WRITE(ringcmds, rcmd_gpu, 0);
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, 0);
}
if (flags & KGSL_CMD_FLAGS_EOF) {
- GSL_RB_WRITE(ringcmds, rcmd_gpu, cp_nop_packet(1));
- GSL_RB_WRITE(ringcmds, rcmd_gpu, KGSL_END_OF_FRAME_IDENTIFIER);
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, cp_nop_packet(1));
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
+ KGSL_END_OF_FRAME_IDENTIFIER);
}
adreno_ringbuffer_submit(rb);
@@ -1150,7 +1159,8 @@
if (val[i] == cp_nop_packet(4)) {
temp_rb_rptr = adreno_ringbuffer_dec_wrapped(
temp_rb_rptr, size);
- kgsl_sharedmem_writel(&rb->buffer_desc,
+ kgsl_sharedmem_writel(rb->device,
+ &rb->buffer_desc,
temp_rb_rptr, cp_nop_packet(1));
}
KGSL_FT_INFO(rb->device,
@@ -1312,7 +1322,7 @@
ringcmds = (unsigned int *)rb->buffer_desc.hostptr + rb->wptr;
rcmd_gpu = rb->buffer_desc.gpuaddr + sizeof(unsigned int) * rb->wptr;
for (i = 0; i < num_rb_contents; i++)
- GSL_RB_WRITE(ringcmds, rcmd_gpu, rb_buff[i]);
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, rb_buff[i]);
rb->wptr += num_rb_contents;
adreno_ringbuffer_submit(rb);
}
diff --git a/drivers/gpu/msm/adreno_ringbuffer.h b/drivers/gpu/msm/adreno_ringbuffer.h
index e563ec7..115533e 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.h
+++ b/drivers/gpu/msm/adreno_ringbuffer.h
@@ -60,11 +60,11 @@
};
-#define GSL_RB_WRITE(ring, gpuaddr, data) \
+#define GSL_RB_WRITE(device, ring, gpuaddr, data) \
do { \
*ring = data; \
wmb(); \
- kgsl_cffdump_setmem(gpuaddr, data, 4); \
+ kgsl_cffdump_setmem(device, gpuaddr, data, 4); \
ring++; \
gpuaddr += sizeof(uint); \
} while (0)
diff --git a/drivers/gpu/msm/adreno_snapshot.c b/drivers/gpu/msm/adreno_snapshot.c
index 144c3d6..d6ce298 100644
--- a/drivers/gpu/msm/adreno_snapshot.c
+++ b/drivers/gpu/msm/adreno_snapshot.c
@@ -34,7 +34,7 @@
static struct kgsl_snapshot_obj {
int type;
uint32_t gpuaddr;
- uint32_t ptbase;
+ phys_addr_t ptbase;
void *ptr;
int dwords;
} objbuf[SNAPSHOT_OBJ_BUFSIZE];
@@ -43,7 +43,8 @@
static int objbufptr;
/* Push a new buffer object onto the list */
-static void push_object(struct kgsl_device *device, int type, uint32_t ptbase,
+static void push_object(struct kgsl_device *device, int type,
+ phys_addr_t ptbase,
uint32_t gpuaddr, int dwords)
{
int index;
@@ -94,7 +95,7 @@
* to be dumped
*/
-static int find_object(int type, unsigned int gpuaddr, unsigned int ptbase)
+static int find_object(int type, unsigned int gpuaddr, phys_addr_t ptbase)
{
int index;
@@ -184,7 +185,7 @@
};
static int ib_parse_load_state(struct kgsl_device *device, unsigned int *pkt,
- unsigned int ptbase)
+ phys_addr_t ptbase)
{
unsigned int block, source, type;
int ret = 0;
@@ -243,7 +244,7 @@
*/
static int ib_parse_set_bin_data(struct kgsl_device *device, unsigned int *pkt,
- unsigned int ptbase)
+ phys_addr_t ptbase)
{
int ret;
@@ -276,7 +277,7 @@
*/
static int ib_parse_mem_write(struct kgsl_device *device, unsigned int *pkt,
- unsigned int ptbase)
+ phys_addr_t ptbase)
{
int ret;
@@ -307,7 +308,7 @@
*/
static int ib_parse_draw_indx(struct kgsl_device *device, unsigned int *pkt,
- unsigned int ptbase)
+ phys_addr_t ptbase)
{
int ret = 0, i;
@@ -439,7 +440,7 @@
*/
static int ib_parse_type3(struct kgsl_device *device, unsigned int *ptr,
- unsigned int ptbase)
+ phys_addr_t ptbase)
{
int opcode = cp_type3_opcode(*ptr);
@@ -464,7 +465,7 @@
*/
static void ib_parse_type0(struct kgsl_device *device, unsigned int *ptr,
- unsigned int ptbase)
+ phys_addr_t ptbase)
{
int size = type0_pkt_size(*ptr);
int offset = type0_pkt_offset(*ptr);
@@ -542,12 +543,12 @@
}
}
-static inline int parse_ib(struct kgsl_device *device, unsigned int ptbase,
+static inline int parse_ib(struct kgsl_device *device, phys_addr_t ptbase,
unsigned int gpuaddr, unsigned int dwords);
/* Add an IB as a GPU object, but first, parse it to find more goodies within */
-static int ib_add_gpu_object(struct kgsl_device *device, unsigned int ptbase,
+static int ib_add_gpu_object(struct kgsl_device *device, phys_addr_t ptbase,
unsigned int gpuaddr, unsigned int dwords)
{
int i, ret, rem = dwords;
@@ -625,7 +626,7 @@
* access the dynamic data from the sysfs file. Push all other IBs on the
* dynamic list
*/
-static inline int parse_ib(struct kgsl_device *device, unsigned int ptbase,
+static inline int parse_ib(struct kgsl_device *device, phys_addr_t ptbase,
unsigned int gpuaddr, unsigned int dwords)
{
unsigned int ib1base, ib2base;
@@ -657,7 +658,8 @@
unsigned int *data = snapshot + sizeof(*header);
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
- unsigned int ptbase, rptr, *rbptr, ibbase;
+ unsigned int rptr, *rbptr, ibbase;
+ phys_addr_t ptbase;
int index, size, i;
int parse_ibs = 0, ib_parse_start;
@@ -824,7 +826,7 @@
struct kgsl_snapshot_replay_mem_list *header = snapshot;
struct kgsl_process_private *private = NULL;
struct kgsl_process_private *tmp_private;
- unsigned int ptbase;
+ phys_addr_t ptbase;
struct rb_node *node;
struct kgsl_mem_entry *entry = NULL;
int num_mem;
@@ -861,7 +863,7 @@
return 0;
}
header->num_entries = num_mem;
- header->ptbase = ptbase;
+ header->ptbase = (__u32)ptbase;
/*
* Walk throught the memory list and store the
* tuples(gpuaddr, size, memtype) in snapshot
@@ -897,7 +899,7 @@
/* Write the sub-header for the section */
header->gpuaddr = obj->gpuaddr;
- header->ptbase = obj->ptbase;
+ header->ptbase = (__u32)obj->ptbase;
header->size = obj->dwords;
/* Write the contents of the ib */
@@ -957,8 +959,9 @@
int hang)
{
int i;
- uint32_t ptbase, ibbase, ibsize;
+ uint32_t ibbase, ibsize;
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+ phys_addr_t ptbase;
/* Reset the list of objects */
objbufptr = 0;
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 9de3410..94754be 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -18,14 +18,13 @@
#include <linux/uaccess.h>
#include <linux/interrupt.h>
#include <linux/workqueue.h>
-
+#include <linux/dma-buf.h>
#include <linux/vmalloc.h>
#include <linux/pm_runtime.h>
#include <linux/genlock.h>
#include <linux/rbtree.h>
#include <linux/ashmem.h>
#include <linux/major.h>
-#include <linux/msm_ion.h>
#include <linux/io.h>
#include <mach/socinfo.h>
#include <linux/mman.h>
@@ -53,7 +52,11 @@
MODULE_PARM_DESC(ksgl_mmu_type,
"Type of MMU to be used for graphics. Valid values are 'iommu' or 'gpummu' or 'nommu'");
-static struct ion_client *kgsl_ion_client;
+struct kgsl_dma_buf_meta {
+ struct dma_buf_attachment *attach;
+ struct dma_buf *dmabuf;
+ struct sg_table *table;
+};
/**
* kgsl_trace_issueibcmds() - Call trace_issueibcmds by proxy
@@ -151,8 +154,8 @@
*/
struct kgsl_mem_entry * __must_check
-kgsl_get_mem_entry(struct kgsl_device *device, unsigned int ptbase,
- unsigned int gpuaddr, unsigned int size)
+kgsl_get_mem_entry(struct kgsl_device *device,
+ phys_addr_t ptbase, unsigned int gpuaddr, unsigned int size)
{
struct kgsl_process_private *priv;
struct kgsl_mem_entry *entry;
@@ -188,6 +191,14 @@
return entry;
}
+static void kgsl_destroy_ion(struct kgsl_dma_buf_meta *meta)
+{
+ dma_buf_unmap_attachment(meta->attach, meta->table, DMA_FROM_DEVICE);
+ dma_buf_detach(meta->dmabuf, meta->attach);
+ dma_buf_put(meta->dmabuf);
+ kfree(meta);
+}
+
void
kgsl_mem_entry_destroy(struct kref *kref)
{
@@ -217,7 +228,7 @@
fput(entry->priv_data);
break;
case KGSL_MEM_ENTRY_ION:
- ion_free(kgsl_ion_client, entry->priv_data);
+ kgsl_destroy_ion(entry->priv_data);
break;
}
@@ -803,6 +814,27 @@
return private;
}
+int kgsl_close_device(struct kgsl_device *device)
+{
+ int result = 0;
+ device->open_count--;
+ if (device->open_count == 0) {
+ BUG_ON(device->active_cnt > 1);
+ result = device->ftbl->stop(device);
+ kgsl_pwrctrl_set_state(device, KGSL_STATE_INIT);
+ /*
+ * active_cnt special case: we just stopped the device,
+ * so no need to use kgsl_active_count_put()
+ */
+ device->active_cnt--;
+ } else {
+ kgsl_active_count_put(device);
+ }
+ return result;
+
+}
+EXPORT_SYMBOL(kgsl_close_device);
+
static int kgsl_release(struct inode *inodep, struct file *filep)
{
int result = 0;
@@ -822,8 +854,10 @@
if (context == NULL)
break;
- if (context->dev_priv == dev_priv)
+ if (context->dev_priv == dev_priv) {
kgsl_context_detach(context);
+ context->dev_priv = NULL;
+ }
next = next + 1;
}
@@ -835,19 +869,7 @@
*/
kgsl_cancel_events(device, dev_priv);
- device->open_count--;
- if (device->open_count == 0) {
- BUG_ON(device->active_cnt > 1);
- result = device->ftbl->stop(device);
- kgsl_pwrctrl_set_state(device, KGSL_STATE_INIT);
- /*
- * active_cnt special case: we just stopped the device,
- * so no need to use kgsl_active_count_put()
- */
- device->active_cnt--;
- } else {
- kgsl_active_count_put(device);
- }
+ result = kgsl_close_device(device);
mutex_unlock(&device->mutex);
kfree(dev_priv);
@@ -857,6 +879,43 @@
return result;
}
+int kgsl_open_device(struct kgsl_device *device)
+{
+ int result = 0;
+ if (device->open_count == 0) {
+ /*
+ * active_cnt special case: we are starting up for the first
+ * time, so use this sequence instead of the kgsl_pwrctrl_wake()
+ * which will be called by kgsl_active_count_get().
+ */
+ device->active_cnt++;
+ kgsl_sharedmem_set(device, &device->memstore, 0, 0,
+ device->memstore.size);
+
+ result = device->ftbl->init(device);
+ if (result)
+ goto err;
+
+ result = device->ftbl->start(device);
+ if (result)
+ goto err;
+ /*
+ * Make sure the gates are open, so they don't block until
+ * we start suspend or FT.
+ */
+ complete_all(&device->ft_gate);
+ complete_all(&device->hwaccess_gate);
+ kgsl_pwrctrl_set_state(device, KGSL_STATE_ACTIVE);
+ kgsl_active_count_put(device);
+ }
+ device->open_count++;
+err:
+ if (result)
+ device->active_cnt--;
+ return result;
+}
+EXPORT_SYMBOL(kgsl_open_device);
+
static int kgsl_open(struct inode *inodep, struct file *filep)
{
int result;
@@ -894,33 +953,9 @@
mutex_lock(&device->mutex);
- if (device->open_count == 0) {
- /*
- * active_cnt special case: we are starting up for the first
- * time, so use this sequence instead of the kgsl_pwrctrl_wake()
- * which will be called by kgsl_active_count_get().
- */
- device->active_cnt++;
- kgsl_sharedmem_set(&device->memstore, 0, 0,
- device->memstore.size);
-
- result = device->ftbl->init(device);
- if (result)
- goto err_freedevpriv;
-
- result = device->ftbl->start(device);
- if (result)
- goto err_freedevpriv;
- /*
- * Make sure the gates are open, so they don't block until
- * we start suspend or FT.
- */
- complete_all(&device->ft_gate);
- complete_all(&device->hwaccess_gate);
- kgsl_pwrctrl_set_state(device, KGSL_STATE_ACTIVE);
- kgsl_active_count_put(device);
- }
- device->open_count++;
+ result = kgsl_open_device(device);
+ if (result)
+ goto err_freedevpriv;
mutex_unlock(&device->mutex);
/*
@@ -948,11 +983,9 @@
kgsl_pwrctrl_enable(device);
result = device->ftbl->stop(device);
kgsl_pwrctrl_set_state(device, KGSL_STATE_INIT);
+ device->active_cnt--;
}
err_freedevpriv:
- /* only the first open takes an active count */
- if (device->open_count == 0)
- device->active_cnt--;
mutex_unlock(&device->mutex);
filep->private_data = NULL;
kfree(dev_priv);
@@ -1844,38 +1877,55 @@
#endif
static int kgsl_setup_ion(struct kgsl_mem_entry *entry,
- struct kgsl_pagetable *pagetable, void *data)
+ struct kgsl_pagetable *pagetable, void *data,
+ struct kgsl_device *device)
{
- struct ion_handle *handle;
struct scatterlist *s;
struct sg_table *sg_table;
struct kgsl_map_user_mem *param = data;
int fd = param->fd;
+ struct dma_buf *dmabuf;
+ struct dma_buf_attachment *attach;
+ struct kgsl_dma_buf_meta *meta;
+ int ret;
if (!param->len)
return -EINVAL;
- if (IS_ERR_OR_NULL(kgsl_ion_client))
- return -ENODEV;
+ meta = kzalloc(sizeof(*meta), GFP_KERNEL);
+ if (!meta)
+ return -ENOMEM;
- handle = ion_import_dma_buf(kgsl_ion_client, fd);
- if (IS_ERR(handle))
- return PTR_ERR(handle);
- else if (!handle)
- return -EINVAL;
+ dmabuf = dma_buf_get(fd);
+ if (IS_ERR_OR_NULL(dmabuf)) {
+ ret = PTR_ERR(dmabuf);
+ goto err1;
+ }
+
+ attach = dma_buf_attach(dmabuf, device->dev);
+ if (IS_ERR_OR_NULL(attach)) {
+ ret = PTR_ERR(attach);
+ goto err2;
+ }
+
+ meta->dmabuf = dmabuf;
+ meta->attach = attach;
entry->memtype = KGSL_MEM_ENTRY_ION;
- entry->priv_data = handle;
+ entry->priv_data = meta;
entry->memdesc.pagetable = pagetable;
entry->memdesc.size = 0;
/* USE_CPU_MAP is not impemented for ION. */
entry->memdesc.flags &= ~KGSL_MEMFLAGS_USE_CPU_MAP;
- sg_table = ion_sg_table(kgsl_ion_client, handle);
+ sg_table = dma_buf_map_attachment(attach, DMA_TO_DEVICE);
- if (IS_ERR_OR_NULL(sg_table))
- goto err;
+ if (IS_ERR_OR_NULL(sg_table)) {
+ ret = PTR_ERR(sg_table);
+ goto err3;
+ }
+ meta->table = sg_table;
entry->memdesc.sg = sg_table->sgl;
/* Calculate the size of the memdesc from the sglist */
@@ -1890,9 +1940,13 @@
entry->memdesc.size = PAGE_ALIGN(entry->memdesc.size);
return 0;
-err:
- ion_free(kgsl_ion_client, handle);
- return -ENOMEM;
+err3:
+ dma_buf_detach(dmabuf, attach);
+err2:
+ dma_buf_put(dmabuf);
+err1:
+ kfree(meta);
+ return ret;
}
static long kgsl_ioctl_map_user_mem(struct kgsl_device_private *dev_priv,
@@ -1980,7 +2034,8 @@
entry->memtype = KGSL_MEM_ENTRY_ASHMEM;
break;
case KGSL_USER_MEM_TYPE_ION:
- result = kgsl_setup_ion(entry, private->pagetable, data);
+ result = kgsl_setup_ion(entry, private->pagetable, data,
+ dev_priv->device);
break;
default:
KGSL_CORE_ERR("Invalid memory type: %x\n", memtype);
@@ -2027,7 +2082,7 @@
fput(entry->priv_data);
break;
case KGSL_MEM_ENTRY_ION:
- ion_free(kgsl_ion_client, entry->priv_data);
+ kgsl_destroy_ion(entry->priv_data);
break;
default:
break;
@@ -2405,7 +2460,8 @@
int result = 0;
struct kgsl_cff_user_event *param = data;
- kgsl_cffdump_user_event(param->cff_opcode, param->op1, param->op2,
+ kgsl_cffdump_user_event(dev_priv->device, param->cff_opcode,
+ param->op1, param->op2,
param->op3, param->op4, param->op5);
return result;
@@ -2904,16 +2960,17 @@
ret = ALIGN(ret, (1 << align));
/*make sure there isn't a GPU only mapping at this address */
- if (kgsl_sharedmem_region_empty(private, ret, len))
+ if (kgsl_sharedmem_region_empty(private, ret, orig_len))
break;
- trace_kgsl_mem_unmapped_area_collision(entry, addr, len, ret);
+ trace_kgsl_mem_unmapped_area_collision(entry, addr, orig_len,
+ ret);
/*
* If we collided, bump the hint address so that
* get_umapped_area knows to look somewhere else.
*/
- addr = (addr == 0) ? ret + len : addr + len;
+ addr = (addr == 0) ? ret + orig_len : addr + orig_len;
/*
* The addr hint can be set by userspace to be near
@@ -3132,8 +3189,6 @@
if (status)
goto error;
- kgsl_ion_client = msm_ion_client_create(UINT_MAX, KGSL_NAME);
-
/* Get starting physical address of device registers */
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
device->iomemname);
@@ -3277,7 +3332,7 @@
BUG_ON(device == NULL);
- kgsl_cffdump_hang(device->id);
+ kgsl_cffdump_hang(device);
/* For a manual dump, make sure that the system is idle */
diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h
index de3f619..4a1f291 100644
--- a/drivers/gpu/msm/kgsl.h
+++ b/drivers/gpu/msm/kgsl.h
@@ -207,7 +207,7 @@
int kgsl_postmortem_dump(struct kgsl_device *device, int manual);
struct kgsl_mem_entry *kgsl_get_mem_entry(struct kgsl_device *device,
- unsigned int ptbase, unsigned int gpuaddr, unsigned int size);
+ phys_addr_t ptbase, unsigned int gpuaddr, unsigned int size);
struct kgsl_mem_entry *kgsl_sharedmem_find_region(
struct kgsl_process_private *private, unsigned int gpuaddr,
@@ -238,6 +238,10 @@
unsigned int timestamp, unsigned int flags,
int result, unsigned int type);
+int kgsl_open_device(struct kgsl_device *device);
+
+int kgsl_close_device(struct kgsl_device *device);
+
#ifdef CONFIG_MSM_KGSL_DRM
extern int kgsl_drm_init(struct platform_device *dev);
extern void kgsl_drm_exit(void);
diff --git a/drivers/gpu/msm/kgsl_cffdump.c b/drivers/gpu/msm/kgsl_cffdump.c
index c3bdf80..99f4235 100644
--- a/drivers/gpu/msm/kgsl_cffdump.c
+++ b/drivers/gpu/msm/kgsl_cffdump.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2012,2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -335,8 +335,6 @@
return;
}
- kgsl_cff_dump_enable = 0;
-
spin_lock_init(&cffdump_lock);
dir = debugfs_create_dir("cff", debugfs_dir);
@@ -360,53 +358,54 @@
void kgsl_cffdump_open(struct kgsl_device *device)
{
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
- if (!kgsl_cff_dump_enable)
+ if (!device->cff_dump_enable)
return;
if (KGSL_MMU_TYPE_IOMMU == kgsl_mmu_get_mmutype()) {
- kgsl_cffdump_memory_base(device->id,
+ kgsl_cffdump_memory_base(device,
KGSL_PAGETABLE_BASE,
KGSL_IOMMU_GLOBAL_MEM_BASE +
KGSL_IOMMU_GLOBAL_MEM_SIZE -
KGSL_PAGETABLE_BASE,
adreno_dev->gmem_size);
} else {
- kgsl_cffdump_memory_base(device->id,
+ kgsl_cffdump_memory_base(device,
kgsl_mmu_get_base_addr(&device->mmu),
kgsl_mmu_get_ptsize(&device->mmu),
adreno_dev->gmem_size);
}
}
-void kgsl_cffdump_memory_base(enum kgsl_deviceid device_id, unsigned int base,
+void kgsl_cffdump_memory_base(struct kgsl_device *device, unsigned int base,
unsigned int range, unsigned gmemsize)
{
- if (!kgsl_cff_dump_enable)
+ if (!device->cff_dump_enable)
return;
- cffdump_printline(device_id, CFF_OP_MEMORY_BASE, base,
+ cffdump_printline(device->id, CFF_OP_MEMORY_BASE, base,
range, gmemsize, 0, 0);
}
-void kgsl_cffdump_hang(enum kgsl_deviceid device_id)
+void kgsl_cffdump_hang(struct kgsl_device *device)
{
- if (!kgsl_cff_dump_enable)
+ if (!device->cff_dump_enable)
return;
- cffdump_printline(device_id, CFF_OP_HANG, 0, 0, 0, 0, 0);
+ cffdump_printline(device->id, CFF_OP_HANG, 0, 0, 0, 0, 0);
}
-void kgsl_cffdump_close(enum kgsl_deviceid device_id)
+void kgsl_cffdump_close(struct kgsl_device *device)
{
- if (!kgsl_cff_dump_enable)
+ if (!device->cff_dump_enable)
return;
- cffdump_printline(device_id, CFF_OP_EOF, 0, 0, 0, 0, 0);
+ cffdump_printline(device->id, CFF_OP_EOF, 0, 0, 0, 0, 0);
}
-void kgsl_cffdump_user_event(unsigned int cff_opcode, unsigned int op1,
+void kgsl_cffdump_user_event(struct kgsl_device *device,
+ unsigned int cff_opcode, unsigned int op1,
unsigned int op2, unsigned int op3,
unsigned int op4, unsigned int op5)
{
- if (!kgsl_cff_dump_enable)
+ if (!device->cff_dump_enable)
return;
cffdump_printline(-1, cff_opcode, op1, op2, op3, op4, op5);
}
@@ -415,9 +414,10 @@
struct kgsl_memdesc *memdesc, uint gpuaddr, uint sizebytes,
bool clean_cache)
{
+ struct kgsl_device *device = dev_priv->device;
const void *src;
- if (!kgsl_cff_dump_enable)
+ if (!device->cff_dump_enable)
return;
total_syncmem += sizebytes;
@@ -437,9 +437,9 @@
}
src = (uint *)kgsl_gpuaddr_to_vaddr(memdesc, gpuaddr);
if (memdesc->hostptr == NULL) {
- KGSL_CORE_ERR("no kernel mapping for "
- "gpuaddr: 0x%08x, m->host: 0x%p, phys: 0x%08x\n",
- gpuaddr, memdesc->hostptr, memdesc->physaddr);
+ KGSL_CORE_ERR(
+ "no kernel map for gpuaddr: 0x%08x, m->host: 0x%p, phys: %pa\n",
+ gpuaddr, memdesc->hostptr, &memdesc->physaddr);
return;
}
@@ -465,9 +465,10 @@
0, 0, 0);
}
-void kgsl_cffdump_setmem(uint addr, uint value, uint sizebytes)
+void kgsl_cffdump_setmem(struct kgsl_device *device,
+ uint addr, uint value, uint sizebytes)
{
- if (!kgsl_cff_dump_enable)
+ if (!device || !device->cff_dump_enable)
return;
while (sizebytes > 3) {
@@ -483,37 +484,37 @@
0, 0, 0);
}
-void kgsl_cffdump_regwrite(enum kgsl_deviceid device_id, uint addr,
+void kgsl_cffdump_regwrite(struct kgsl_device *device, uint addr,
uint value)
{
- if (!kgsl_cff_dump_enable)
+ if (!device->cff_dump_enable)
return;
- cffdump_printline(device_id, CFF_OP_WRITE_REG, addr, value,
+ cffdump_printline(device->id, CFF_OP_WRITE_REG, addr, value,
0, 0, 0);
}
-void kgsl_cffdump_regpoll(enum kgsl_deviceid device_id, uint addr,
+void kgsl_cffdump_regpoll(struct kgsl_device *device, uint addr,
uint value, uint mask)
{
- if (!kgsl_cff_dump_enable)
+ if (!device->cff_dump_enable)
return;
- cffdump_printline(device_id, CFF_OP_POLL_REG, addr, value,
+ cffdump_printline(device->id, CFF_OP_POLL_REG, addr, value,
mask, 0, 0);
}
-void kgsl_cffdump_slavewrite(uint addr, uint value)
+void kgsl_cffdump_slavewrite(struct kgsl_device *device, uint addr, uint value)
{
- if (!kgsl_cff_dump_enable)
+ if (!device->cff_dump_enable)
return;
cffdump_printline(-1, CFF_OP_WRITE_REG, addr, value, 0, 0, 0);
}
-int kgsl_cffdump_waitirq(void)
+int kgsl_cffdump_waitirq(struct kgsl_device *device)
{
- if (!kgsl_cff_dump_enable)
+ if (!device->cff_dump_enable)
return 0;
cffdump_printline(-1, CFF_OP_WAIT_IRQ, 0, 0, 0, 0, 0);
@@ -614,3 +615,59 @@
}
}
+int kgsl_cff_dump_enable_set(void *data, u64 val)
+{
+ int ret = 0;
+ struct kgsl_device *device = (struct kgsl_device *)data;
+ int i;
+
+ mutex_lock(&kgsl_driver.devlock);
+ /*
+ * If CFF dump enabled then set active count to prevent device
+ * from restarting because simulator cannot run device restarts
+ */
+ if (val) {
+ /* Check if CFF is on for some other device already */
+ for (i = 0; i < KGSL_DEVICE_MAX; i++) {
+ if (kgsl_driver.devp[i]) {
+ struct kgsl_device *device_temp =
+ kgsl_driver.devp[i];
+ if (device_temp->cff_dump_enable &&
+ device != device_temp) {
+ KGSL_CORE_ERR(
+ "CFF is on for another device %d\n",
+ device_temp->id);
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+ }
+ if (!device->cff_dump_enable) {
+ mutex_lock(&device->mutex);
+ device->cff_dump_enable = 1;
+ ret = kgsl_open_device(device);
+ if (!ret)
+ ret = kgsl_active_count_get(device);
+ if (ret)
+ device->cff_dump_enable = 0;
+ mutex_unlock(&device->mutex);
+ }
+ } else if (device->cff_dump_enable && !val) {
+ mutex_lock(&device->mutex);
+ ret = kgsl_close_device(device);
+ device->cff_dump_enable = 0;
+ mutex_unlock(&device->mutex);
+ }
+done:
+ mutex_unlock(&kgsl_driver.devlock);
+ return ret;
+}
+EXPORT_SYMBOL(kgsl_cff_dump_enable_set);
+
+int kgsl_cff_dump_enable_get(void *data, u64 *val)
+{
+ struct kgsl_device *device = (struct kgsl_device *)data;
+ *val = device->cff_dump_enable;
+ return 0;
+}
+EXPORT_SYMBOL(kgsl_cff_dump_enable_get);
diff --git a/drivers/gpu/msm/kgsl_cffdump.h b/drivers/gpu/msm/kgsl_cffdump.h
index d5656f8..641348e 100644
--- a/drivers/gpu/msm/kgsl_cffdump.h
+++ b/drivers/gpu/msm/kgsl_cffdump.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2011,2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -14,6 +14,8 @@
#ifndef __KGSL_CFFDUMP_H
#define __KGSL_CFFDUMP_H
+extern unsigned int kgsl_cff_dump_enable;
+
#ifdef CONFIG_MSM_KGSL_CFF_DUMP
#include <linux/types.h>
@@ -23,46 +25,64 @@
void kgsl_cffdump_init(void);
void kgsl_cffdump_destroy(void);
void kgsl_cffdump_open(struct kgsl_device *device);
-void kgsl_cffdump_close(enum kgsl_deviceid device_id);
+void kgsl_cffdump_close(struct kgsl_device *device);
void kgsl_cffdump_syncmem(struct kgsl_device_private *dev_priv,
struct kgsl_memdesc *memdesc, uint physaddr, uint sizebytes,
bool clean_cache);
-void kgsl_cffdump_setmem(uint addr, uint value, uint sizebytes);
-void kgsl_cffdump_regwrite(enum kgsl_deviceid device_id, uint addr,
+void kgsl_cffdump_setmem(struct kgsl_device *device, uint addr,
+ uint value, uint sizebytes);
+void kgsl_cffdump_regwrite(struct kgsl_device *device, uint addr,
uint value);
-void kgsl_cffdump_regpoll(enum kgsl_deviceid device_id, uint addr,
+void kgsl_cffdump_regpoll(struct kgsl_device *device, uint addr,
uint value, uint mask);
bool kgsl_cffdump_parse_ibs(struct kgsl_device_private *dev_priv,
const struct kgsl_memdesc *memdesc, uint gpuaddr, int sizedwords,
bool check_only);
-void kgsl_cffdump_user_event(unsigned int cff_opcode, unsigned int op1,
+void kgsl_cffdump_user_event(struct kgsl_device *device,
+ unsigned int cff_opcode, unsigned int op1,
unsigned int op2, unsigned int op3,
unsigned int op4, unsigned int op5);
static inline bool kgsl_cffdump_flags_no_memzero(void) { return true; }
-void kgsl_cffdump_memory_base(enum kgsl_deviceid device_id, unsigned int base,
+void kgsl_cffdump_memory_base(struct kgsl_device *device, unsigned int base,
unsigned int range, unsigned int gmemsize);
-void kgsl_cffdump_hang(enum kgsl_deviceid device_id);
+void kgsl_cffdump_hang(struct kgsl_device *device);
+int kgsl_cff_dump_enable_set(void *data, u64 val);
+int kgsl_cff_dump_enable_get(void *data, u64 *val);
#else
#define kgsl_cffdump_init() (void)0
#define kgsl_cffdump_destroy() (void)0
#define kgsl_cffdump_open(device) (void)0
-#define kgsl_cffdump_close(device_id) (void)0
+#define kgsl_cffdump_close(device) (void)0
#define kgsl_cffdump_syncmem(dev_priv, memdesc, addr, sizebytes, clean_cache) \
(void) 0
-#define kgsl_cffdump_setmem(addr, value, sizebytes) (void)0
-#define kgsl_cffdump_regwrite(device_id, addr, value) (void)0
-#define kgsl_cffdump_regpoll(device_id, addr, value, mask) (void)0
+#define kgsl_cffdump_setmem(device, addr, value, sizebytes) (void)0
+#define kgsl_cffdump_regwrite(device, addr, value) (void)0
+#define kgsl_cffdump_regpoll(device, addr, value, mask) (void)0
#define kgsl_cffdump_parse_ibs(dev_priv, memdesc, gpuaddr, \
sizedwords, check_only) true
#define kgsl_cffdump_flags_no_memzero() true
-#define kgsl_cffdump_memory_base(base, range, gmemsize) (void)0
-#define kgsl_cffdump_hang(device_id) (void)0
-#define kgsl_cffdump_user_event(cff_opcode, op1, op2, op3, op4, op5) \
- (void)param
+#define kgsl_cffdump_memory_base(davice, base, range, gmemsize) (void)0
+#define kgsl_cffdump_hang(device) (void)0
+static inline void kgsl_cffdump_user_event(struct kgsl_device *device,
+ unsigned int cff_opcode, unsigned int op1,
+ unsigned int op2, unsigned int op3,
+ unsigned int op4, unsigned int op5)
+{
+ return;
+}
+static inline int kgsl_cff_dump_enable_set(void *data, u64 val)
+{
+ return -EINVAL;
+}
+
+static inline int kgsl_cff_dump_enable_get(void *data, u64 *val)
+{
+ return -EINVAL;
+}
#endif /* CONFIG_MSM_KGSL_CFF_DUMP */
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index 3ee9e4e..6477cbd 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -226,6 +226,7 @@
int pm_ib_enabled;
int reset_counter; /* Track how many GPU core resets have occured */
+ int cff_dump_enable;
};
void kgsl_process_events(struct work_struct *work);
diff --git a/drivers/gpu/msm/kgsl_gpummu.c b/drivers/gpu/msm/kgsl_gpummu.c
index 6f139b9..68052b1 100644
--- a/drivers/gpu/msm/kgsl_gpummu.c
+++ b/drivers/gpu/msm/kgsl_gpummu.c
@@ -359,7 +359,7 @@
int kgsl_gpummu_pt_equal(struct kgsl_mmu *mmu,
struct kgsl_pagetable *pt,
- unsigned int pt_base)
+ phys_addr_t pt_base)
{
struct kgsl_gpummu_pt *gpummu_pt = pt ? pt->priv : NULL;
return gpummu_pt && pt_base && (gpummu_pt->base.gpuaddr == pt_base);
@@ -458,15 +458,20 @@
if (gpummu_pt->base.hostptr == NULL)
goto err_flushfilter;
+ /* Do a check before truncating phys_addr_t to unsigned 32 */
+ if (sizeof(phys_addr_t) > sizeof(unsigned int)) {
+ WARN_ONCE(1, "Cannot use LPAE with gpummu\n");
+ goto err_flushfilter;
+ }
+ gpummu_pt->base.gpuaddr = gpummu_pt->base.physaddr;
+ gpummu_pt->base.size = KGSL_PAGETABLE_SIZE;
+
/* ptpool allocations are from coherent memory, so update the
device statistics acordingly */
KGSL_STATS_ADD(KGSL_PAGETABLE_SIZE, kgsl_driver.stats.coherent,
kgsl_driver.stats.coherent_max);
- gpummu_pt->base.gpuaddr = gpummu_pt->base.physaddr;
- gpummu_pt->base.size = KGSL_PAGETABLE_SIZE;
-
return (void *)gpummu_pt;
err_flushfilter:
@@ -576,7 +581,7 @@
kgsl_regwrite(device, MH_INTERRUPT_MASK,
GSL_MMU_INT_MASK | MH_INTERRUPT_MASK__MMU_PAGE_FAULT);
- kgsl_sharedmem_set(&mmu->setstate_memory, 0, 0,
+ kgsl_sharedmem_set(device, &mmu->setstate_memory, 0, 0,
mmu->setstate_memory.size);
/* TRAN_ERROR needs a 32 byte (32 byte aligned) chunk of memory
@@ -723,7 +728,7 @@
return 0;
}
-static unsigned int
+static phys_addr_t
kgsl_gpummu_get_current_ptbase(struct kgsl_mmu *mmu)
{
unsigned int ptbase;
@@ -731,7 +736,7 @@
return ptbase;
}
-static unsigned int
+static phys_addr_t
kgsl_gpummu_get_pt_base_addr(struct kgsl_mmu *mmu,
struct kgsl_pagetable *pt)
{
@@ -757,7 +762,7 @@
.mmu_get_pt_base_addr = kgsl_gpummu_get_pt_base_addr,
.mmu_enable_clk = NULL,
.mmu_disable_clk_on_ts = NULL,
- .mmu_get_pt_lsb = NULL,
+ .mmu_get_default_ttbr0 = NULL,
.mmu_get_reg_gpuaddr = NULL,
.mmu_get_reg_ahbaddr = NULL,
.mmu_get_num_iommu_units = kgsl_gpummu_get_num_iommu_units,
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index 513fb90..b86e0e1 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -242,7 +242,7 @@
list_for_each_entry(private, &kgsl_driver.process_list, list) {
- if (private->pagetable->name != id)
+ if (private->pagetable && (private->pagetable->name != id))
continue;
spin_lock(&private->mem_lock);
@@ -609,11 +609,12 @@
*/
static int kgsl_iommu_pt_equal(struct kgsl_mmu *mmu,
struct kgsl_pagetable *pt,
- unsigned int pt_base)
+ phys_addr_t pt_base)
{
struct kgsl_iommu_pt *iommu_pt = pt ? pt->priv : NULL;
- unsigned int domain_ptbase = iommu_pt ?
+ phys_addr_t domain_ptbase = iommu_pt ?
iommu_get_pt_base_addr(iommu_pt->domain) : 0;
+
/* Only compare the valid address bits of the pt_base */
domain_ptbase &= KGSL_IOMMU_CTX_TTBR0_ADDR_MASK;
@@ -920,15 +921,15 @@
iommu_access_ops = get_iommu_access_ops_v0();
- if (iommu_access_ops && iommu_access_ops->iommu_lock_initialize)
- lock_phy_addr = (iommu_access_ops->iommu_lock_initialize()
- - MSM_SHARED_RAM_BASE + msm_shared_ram_phys);
-
- if (!lock_phy_addr) {
- iommu_access_ops = NULL;
- KGSL_DRV_ERR(mmu->device,
- "GPU CPU sync lock is not supported by kernel\n");
- return -ENXIO;
+ if (iommu_access_ops && iommu_access_ops->iommu_lock_initialize) {
+ lock_phy_addr = (uint32_t)
+ iommu_access_ops->iommu_lock_initialize();
+ if (!lock_phy_addr) {
+ iommu_access_ops = NULL;
+ return status;
+ }
+ lock_phy_addr = lock_phy_addr - (uint32_t)MSM_SHARED_RAM_BASE +
+ (uint32_t)msm_shared_ram_phys;
}
/* Align the physical address to PAGE boundary and store the offset */
@@ -1152,7 +1153,7 @@
* Return - actual pagetable address that the ttbr0 register is programmed
* with
*/
-static unsigned int kgsl_iommu_get_pt_base_addr(struct kgsl_mmu *mmu,
+static phys_addr_t kgsl_iommu_get_pt_base_addr(struct kgsl_mmu *mmu,
struct kgsl_pagetable *pt)
{
struct kgsl_iommu_pt *iommu_pt = pt->priv;
@@ -1161,17 +1162,15 @@
}
/*
- * kgsl_iommu_get_pt_lsb - Return the lsb of the ttbr0 IOMMU register
+ * kgsl_iommu_get_default_ttbr0 - Return the ttbr0 value programmed by
+ * iommu driver
* @mmu - Pointer to mmu structure
* @hostptr - Pointer to the IOMMU register map. This is used to match
* the iommu device whose lsb value is to be returned
* @ctx_id - The context bank whose lsb valus is to be returned
- * Return - returns the lsb which is the last 14 bits of the ttbr0 IOMMU
- * register. ttbr0 is the actual PTBR for of the IOMMU. The last 14 bits
- * are only programmed once in the beginning when a domain is attached
- * does not change.
+ * Return - returns the ttbr0 value programmed by iommu driver
*/
-static int kgsl_iommu_get_pt_lsb(struct kgsl_mmu *mmu,
+static phys_addr_t kgsl_iommu_get_default_ttbr0(struct kgsl_mmu *mmu,
unsigned int unit_id,
enum kgsl_iommu_context_id ctx_id)
{
@@ -1182,7 +1181,7 @@
for (j = 0; j < iommu_unit->dev_count; j++)
if (unit_id == i &&
ctx_id == iommu_unit->dev[j].ctx_id)
- return iommu_unit->dev[j].pt_lsb;
+ return iommu_unit->dev[j].default_ttbr0;
}
return 0;
}
@@ -1386,7 +1385,7 @@
/* A nop is required in an indirect buffer when switching
* pagetables in-stream */
- kgsl_sharedmem_writel(&mmu->setstate_memory,
+ kgsl_sharedmem_writel(mmu->device, &mmu->setstate_memory,
KGSL_IOMMU_SETSTATE_NOP_OFFSET,
cp_nop_packet(1));
@@ -1626,18 +1625,26 @@
for (i = 0; i < iommu->unit_count; i++) {
struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
for (j = 0; j < iommu_unit->dev_count; j++) {
- iommu_unit->dev[j].pt_lsb = KGSL_IOMMMU_PT_LSB(iommu,
+ if (sizeof(phys_addr_t) > sizeof(unsigned long)) {
+ iommu_unit->dev[j].default_ttbr0 =
+ KGSL_IOMMU_GET_CTX_REG_LL(iommu,
+ iommu_unit,
+ iommu_unit->dev[j].ctx_id,
+ TTBR0);
+ } else {
+ iommu_unit->dev[j].default_ttbr0 =
KGSL_IOMMU_GET_CTX_REG(iommu,
iommu_unit,
iommu_unit->dev[j].ctx_id,
- TTBR0));
+ TTBR0);
+ }
}
}
kgsl_iommu_lock_rb_in_tlb(mmu);
_iommu_unlock();
/* For complete CFF */
- kgsl_cffdump_setmem(mmu->setstate_memory.gpuaddr +
+ kgsl_cffdump_setmem(mmu->device, mmu->setstate_memory.gpuaddr +
KGSL_IOMMU_SETSTATE_NOP_OFFSET,
cp_nop_packet(1), sizeof(unsigned int));
@@ -1806,10 +1813,10 @@
return 0;
}
-static unsigned int
+static phys_addr_t
kgsl_iommu_get_current_ptbase(struct kgsl_mmu *mmu)
{
- unsigned int pt_base;
+ phys_addr_t pt_base;
struct kgsl_iommu *iommu = mmu->priv;
/* We cannot enable or disable the clocks in interrupt context, this
function is called from interrupt context if there is an axi error */
@@ -1842,16 +1849,14 @@
struct kgsl_iommu *iommu = mmu->priv;
int temp;
int i;
- unsigned int pt_base = kgsl_iommu_get_pt_base_addr(mmu,
+ phys_addr_t pt_base = kgsl_iommu_get_pt_base_addr(mmu,
mmu->hwpagetable);
- unsigned int pt_val;
+ phys_addr_t pt_val;
if (kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER)) {
KGSL_DRV_ERR(mmu->device, "Failed to enable iommu clocks\n");
return;
}
- /* Mask off the lsb of the pt base address since lsb will not change */
- pt_base &= KGSL_IOMMU_CTX_TTBR0_ADDR_MASK;
/* For v0 SMMU GPU needs to be idle for tlb invalidate as well */
if (msm_soc_version_supports_iommu_v0())
@@ -1866,12 +1871,21 @@
for (i = 0; i < iommu->unit_count; i++) {
/* get the lsb value which should not change when
* changing ttbr0 */
- pt_val = kgsl_iommu_get_pt_lsb(mmu, i,
+ pt_val = kgsl_iommu_get_default_ttbr0(mmu, i,
KGSL_IOMMU_CONTEXT_USER);
- pt_val += pt_base;
- KGSL_IOMMU_SET_CTX_REG(iommu, (&iommu->iommu_units[i]),
- KGSL_IOMMU_CONTEXT_USER, TTBR0, pt_val);
+ pt_base &= KGSL_IOMMU_CTX_TTBR0_ADDR_MASK;
+ pt_val &= ~KGSL_IOMMU_CTX_TTBR0_ADDR_MASK;
+ pt_val |= pt_base;
+ if (sizeof(phys_addr_t) > sizeof(unsigned long)) {
+ KGSL_IOMMU_SET_CTX_REG_LL(iommu,
+ (&iommu->iommu_units[i]),
+ KGSL_IOMMU_CONTEXT_USER, TTBR0, pt_val);
+ } else {
+ KGSL_IOMMU_SET_CTX_REG(iommu,
+ (&iommu->iommu_units[i]),
+ KGSL_IOMMU_CONTEXT_USER, TTBR0, pt_val);
+ }
mb();
temp = KGSL_IOMMU_GET_CTX_REG(iommu,
@@ -1976,7 +1990,7 @@
.mmu_get_current_ptbase = kgsl_iommu_get_current_ptbase,
.mmu_enable_clk = kgsl_iommu_enable_clk,
.mmu_disable_clk_on_ts = kgsl_iommu_disable_clk_on_ts,
- .mmu_get_pt_lsb = kgsl_iommu_get_pt_lsb,
+ .mmu_get_default_ttbr0 = kgsl_iommu_get_default_ttbr0,
.mmu_get_reg_gpuaddr = kgsl_iommu_get_reg_gpuaddr,
.mmu_get_reg_ahbaddr = kgsl_iommu_get_reg_ahbaddr,
.mmu_get_num_iommu_units = kgsl_iommu_get_num_iommu_units,
diff --git a/drivers/gpu/msm/kgsl_iommu.h b/drivers/gpu/msm/kgsl_iommu.h
index b1b83c0..53b3946 100644
--- a/drivers/gpu/msm/kgsl_iommu.h
+++ b/drivers/gpu/msm/kgsl_iommu.h
@@ -47,7 +47,12 @@
#define KGSL_IOMMU_V1_FSYNR0_WNR_SHIFT 4
/* TTBR0 register fields */
+#ifdef CONFIG_ARM_LPAE
+#define KGSL_IOMMU_CTX_TTBR0_ADDR_MASK_LPAE 0x000000FFFFFFFFE0ULL
+#define KGSL_IOMMU_CTX_TTBR0_ADDR_MASK KGSL_IOMMU_CTX_TTBR0_ADDR_MASK_LPAE
+#else
#define KGSL_IOMMU_CTX_TTBR0_ADDR_MASK 0xFFFFC000
+#endif
/* TLBSTATUS register fields */
#define KGSL_IOMMU_CTX_TLBSTATUS_SACTIVE BIT(0)
@@ -102,6 +107,20 @@
#define KGSL_IOMMU_MAX_DEVS_PER_UNIT 2
/* Macros to read/write IOMMU registers */
+#define KGSL_IOMMU_SET_CTX_REG_LL(iommu, iommu_unit, ctx, REG, val) \
+ writell_relaxed(val, \
+ iommu_unit->reg_map.hostptr + \
+ iommu->iommu_reg_list[KGSL_IOMMU_CTX_##REG].reg_offset +\
+ (ctx << KGSL_IOMMU_CTX_SHIFT) + \
+ iommu->ctx_offset)
+
+#define KGSL_IOMMU_GET_CTX_REG_LL(iommu, iommu_unit, ctx, REG) \
+ readl_relaxed( \
+ iommu_unit->reg_map.hostptr + \
+ iommu->iommu_reg_list[KGSL_IOMMU_CTX_##REG].reg_offset +\
+ (ctx << KGSL_IOMMU_CTX_SHIFT) + \
+ iommu->ctx_offset)
+
#define KGSL_IOMMU_SET_CTX_REG(iommu, iommu_unit, ctx, REG, val) \
writel_relaxed(val, \
iommu_unit->reg_map.hostptr + \
@@ -128,8 +147,7 @@
* @dev: Device pointer to iommu context
* @attached: Indicates whether this iommu context is presently attached to
* a pagetable/domain or not
- * @pt_lsb: The LSB of IOMMU_TTBR0 register which is the pagetable
- * register
+ * @default_ttbr0: The TTBR0 value set by iommu driver on start up
* @ctx_id: This iommu units context id. It can be either 0 or 1
* @clk_enabled: If set indicates that iommu clocks of this iommu context
* are on, else the clocks are off
@@ -139,7 +157,7 @@
struct kgsl_iommu_device {
struct device *dev;
bool attached;
- unsigned int pt_lsb;
+ phys_addr_t default_ttbr0;
enum kgsl_iommu_context_id ctx_id;
bool clk_enabled;
struct kgsl_device *kgsldev;
diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c
index 3ebfdcd..12a4b25 100644
--- a/drivers/gpu/msm/kgsl_mmu.c
+++ b/drivers/gpu/msm/kgsl_mmu.c
@@ -314,7 +314,7 @@
}
int
-kgsl_mmu_get_ptname_from_ptbase(struct kgsl_mmu *mmu, unsigned int pt_base)
+kgsl_mmu_get_ptname_from_ptbase(struct kgsl_mmu *mmu, phys_addr_t pt_base)
{
struct kgsl_pagetable *pt;
int ptid = -1;
@@ -335,7 +335,7 @@
EXPORT_SYMBOL(kgsl_mmu_get_ptname_from_ptbase);
unsigned int
-kgsl_mmu_log_fault_addr(struct kgsl_mmu *mmu, unsigned int pt_base,
+kgsl_mmu_log_fault_addr(struct kgsl_mmu *mmu, phys_addr_t pt_base,
unsigned int addr)
{
struct kgsl_pagetable *pt;
@@ -372,7 +372,7 @@
status = kgsl_allocate_contiguous(&mmu->setstate_memory, PAGE_SIZE);
if (status)
return status;
- kgsl_sharedmem_set(&mmu->setstate_memory, 0, 0,
+ kgsl_sharedmem_set(device, &mmu->setstate_memory, 0, 0,
mmu->setstate_memory.size);
if (KGSL_MMU_TYPE_NONE == kgsl_mmu_type) {
@@ -410,7 +410,8 @@
static void mh_axi_error(struct kgsl_device *device, const char* type)
{
- unsigned int reg, gpu_err, phys_err, pt_base;
+ unsigned int reg, gpu_err, phys_err;
+ phys_addr_t pt_base;
kgsl_regread(device, MH_AXI_ERROR, ®);
pt_base = kgsl_mmu_get_current_ptbase(&device->mmu);
@@ -423,8 +424,8 @@
kgsl_regwrite(device, MH_DEBUG_CTRL, 45);
kgsl_regread(device, MH_DEBUG_DATA, &phys_err);
KGSL_MEM_CRIT(device,
- "axi %s error: %08x pt %08x gpu %08x phys %08x\n",
- type, reg, pt_base, gpu_err, phys_err);
+ "axi %s error: %08x pt %pa gpu %08x phys %08x\n",
+ type, reg, &pt_base, gpu_err, phys_err);
}
void kgsl_mh_intrcallback(struct kgsl_device *device)
diff --git a/drivers/gpu/msm/kgsl_mmu.h b/drivers/gpu/msm/kgsl_mmu.h
index 02cde94..a4fffec 100644
--- a/drivers/gpu/msm/kgsl_mmu.h
+++ b/drivers/gpu/msm/kgsl_mmu.h
@@ -139,13 +139,13 @@
void (*mmu_device_setstate) (struct kgsl_mmu *mmu,
uint32_t flags);
void (*mmu_pagefault) (struct kgsl_mmu *mmu);
- unsigned int (*mmu_get_current_ptbase)
+ phys_addr_t (*mmu_get_current_ptbase)
(struct kgsl_mmu *mmu);
void (*mmu_disable_clk_on_ts)
(struct kgsl_mmu *mmu, uint32_t ts, bool ts_valid);
int (*mmu_enable_clk)
(struct kgsl_mmu *mmu, int ctx_id);
- int (*mmu_get_pt_lsb)(struct kgsl_mmu *mmu,
+ phys_addr_t (*mmu_get_default_ttbr0)(struct kgsl_mmu *mmu,
unsigned int unit_id,
enum kgsl_iommu_context_id ctx_id);
unsigned int (*mmu_get_reg_gpuaddr)(struct kgsl_mmu *mmu,
@@ -156,8 +156,8 @@
int (*mmu_get_num_iommu_units)(struct kgsl_mmu *mmu);
int (*mmu_pt_equal) (struct kgsl_mmu *mmu,
struct kgsl_pagetable *pt,
- unsigned int pt_base);
- unsigned int (*mmu_get_pt_base_addr)
+ phys_addr_t pt_base);
+ phys_addr_t (*mmu_get_pt_base_addr)
(struct kgsl_mmu *mmu,
struct kgsl_pagetable *pt);
int (*mmu_setup_pt) (struct kgsl_mmu *mmu,
@@ -228,9 +228,9 @@
void kgsl_setstate(struct kgsl_mmu *mmu, unsigned int context_id,
uint32_t flags);
int kgsl_mmu_get_ptname_from_ptbase(struct kgsl_mmu *mmu,
- unsigned int pt_base);
+ phys_addr_t pt_base);
unsigned int kgsl_mmu_log_fault_addr(struct kgsl_mmu *mmu,
- unsigned int pt_base, unsigned int addr);
+ phys_addr_t pt_base, unsigned int addr);
int kgsl_mmu_pt_get_flags(struct kgsl_pagetable *pt,
enum kgsl_deviceid id);
void kgsl_mmu_ptpool_destroy(void *ptpool);
@@ -246,7 +246,7 @@
* of as wrappers around the actual function
*/
-static inline unsigned int kgsl_mmu_get_current_ptbase(struct kgsl_mmu *mmu)
+static inline phys_addr_t kgsl_mmu_get_current_ptbase(struct kgsl_mmu *mmu)
{
if (mmu->mmu_ops && mmu->mmu_ops->mmu_get_current_ptbase)
return mmu->mmu_ops->mmu_get_current_ptbase(mmu);
@@ -277,7 +277,7 @@
static inline int kgsl_mmu_pt_equal(struct kgsl_mmu *mmu,
struct kgsl_pagetable *pt,
- unsigned int pt_base)
+ phys_addr_t pt_base)
{
if (mmu->mmu_ops && mmu->mmu_ops->mmu_pt_equal)
return mmu->mmu_ops->mmu_pt_equal(mmu, pt, pt_base);
@@ -285,7 +285,7 @@
return 1;
}
-static inline unsigned int kgsl_mmu_get_pt_base_addr(struct kgsl_mmu *mmu,
+static inline phys_addr_t kgsl_mmu_get_pt_base_addr(struct kgsl_mmu *mmu,
struct kgsl_pagetable *pt)
{
if (mmu->mmu_ops && mmu->mmu_ops->mmu_get_pt_base_addr)
@@ -294,12 +294,13 @@
return 0;
}
-static inline int kgsl_mmu_get_pt_lsb(struct kgsl_mmu *mmu,
+static inline phys_addr_t kgsl_mmu_get_default_ttbr0(struct kgsl_mmu *mmu,
unsigned int unit_id,
enum kgsl_iommu_context_id ctx_id)
{
- if (mmu->mmu_ops && mmu->mmu_ops->mmu_get_pt_lsb)
- return mmu->mmu_ops->mmu_get_pt_lsb(mmu, unit_id, ctx_id);
+ if (mmu->mmu_ops && mmu->mmu_ops->mmu_get_default_ttbr0)
+ return mmu->mmu_ops->mmu_get_default_ttbr0(mmu, unit_id,
+ ctx_id);
else
return 0;
}
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 05d24e9..5b386b3 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -1061,6 +1061,7 @@
pwr->active_pwrlevel = pdata->init_level;
pwr->default_pwrlevel = pdata->init_level;
+ pwr->init_pwrlevel = pdata->init_level;
for (i = 0; i < pdata->num_levels; i++) {
pwr->pwrlevels[i].gpu_freq =
(pdata->pwrlevel[i].gpu_freq > 0) ?
@@ -1466,8 +1467,10 @@
void kgsl_pwrctrl_enable(struct kgsl_device *device)
{
+ struct kgsl_pwrctrl *pwr = &device->pwrctrl;
/* Order pwrrail/clk sequence based upon platform */
kgsl_pwrctrl_pwrrail(device, KGSL_PWRFLAGS_ON);
+ kgsl_pwrctrl_pwrlevel_change(device, pwr->default_pwrlevel);
kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_ON, KGSL_STATE_ACTIVE);
kgsl_pwrctrl_axi(device, KGSL_PWRFLAGS_ON);
}
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.h b/drivers/gpu/msm/kgsl_pwrctrl.h
index 7bc849d..5cadaa7 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.h
+++ b/drivers/gpu/msm/kgsl_pwrctrl.h
@@ -47,6 +47,8 @@
* @pwrlevels - List of supported power levels
* @active_pwrlevel - The currently active power level
* @thermal_pwrlevel - maximum powerlevel constraint from thermal
+ * @default_pwrlevel - device wake up power level
+ * @init_pwrlevel - device inital power level
* @max_pwrlevel - maximum allowable powerlevel per the user
* @min_pwrlevel - minimum allowable powerlevel per the user
* @num_pwrlevels - number of available power levels
@@ -74,6 +76,7 @@
unsigned int active_pwrlevel;
int thermal_pwrlevel;
unsigned int default_pwrlevel;
+ unsigned int init_pwrlevel;
unsigned int max_pwrlevel;
unsigned int min_pwrlevel;
unsigned int num_pwrlevels;
diff --git a/drivers/gpu/msm/kgsl_pwrscale.c b/drivers/gpu/msm/kgsl_pwrscale.c
index afef62e..e5e23f0 100644
--- a/drivers/gpu/msm/kgsl_pwrscale.c
+++ b/drivers/gpu/msm/kgsl_pwrscale.c
@@ -306,6 +306,8 @@
kgsl_pwrctrl_pwrlevel_change(device,
device->pwrctrl.max_pwrlevel);
+ device->pwrctrl.default_pwrlevel =
+ device->pwrctrl.max_pwrlevel;
}
device->pwrscale.policy = NULL;
}
@@ -338,6 +340,8 @@
device->pwrscale.policy = policy;
+ device->pwrctrl.default_pwrlevel =
+ device->pwrctrl.init_pwrlevel;
/* Pwrscale is enabled by default at attach time */
kgsl_pwrscale_enable(device);
diff --git a/drivers/gpu/msm/kgsl_pwrscale_trustzone.c b/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
index 5d5d5b1..cfc409c 100644
--- a/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
+++ b/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
@@ -110,8 +110,12 @@
else if (!strncmp(str, "performance", 11))
priv->governor = TZ_GOVERNOR_PERFORMANCE;
- if (priv->governor == TZ_GOVERNOR_PERFORMANCE)
+ if (priv->governor == TZ_GOVERNOR_PERFORMANCE) {
kgsl_pwrctrl_pwrlevel_change(device, pwr->max_pwrlevel);
+ pwr->default_pwrlevel = pwr->max_pwrlevel;
+ } else {
+ pwr->default_pwrlevel = pwr->init_pwrlevel;
+ }
mutex_unlock(&device->mutex);
return count;
diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c
index 1691762..01f0768 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.c
+++ b/drivers/gpu/msm/kgsl_sharedmem.c
@@ -879,7 +879,8 @@
EXPORT_SYMBOL(kgsl_sharedmem_readl);
int
-kgsl_sharedmem_writel(const struct kgsl_memdesc *memdesc,
+kgsl_sharedmem_writel(struct kgsl_device *device,
+ const struct kgsl_memdesc *memdesc,
unsigned int offsetbytes,
uint32_t src)
{
@@ -892,7 +893,8 @@
WARN_ON(offsetbytes + sizeof(uint32_t) > memdesc->size);
if (offsetbytes + sizeof(uint32_t) > memdesc->size)
return -ERANGE;
- kgsl_cffdump_setmem(memdesc->gpuaddr + offsetbytes,
+ kgsl_cffdump_setmem(device,
+ memdesc->gpuaddr + offsetbytes,
src, sizeof(uint32_t));
dst = (uint32_t *)(memdesc->hostptr + offsetbytes);
*dst = src;
@@ -901,14 +903,16 @@
EXPORT_SYMBOL(kgsl_sharedmem_writel);
int
-kgsl_sharedmem_set(const struct kgsl_memdesc *memdesc, unsigned int offsetbytes,
- unsigned int value, unsigned int sizebytes)
+kgsl_sharedmem_set(struct kgsl_device *device,
+ const struct kgsl_memdesc *memdesc, unsigned int offsetbytes,
+ unsigned int value, unsigned int sizebytes)
{
BUG_ON(memdesc == NULL || memdesc->hostptr == NULL);
BUG_ON(offsetbytes + sizebytes > memdesc->size);
- kgsl_cffdump_setmem(memdesc->gpuaddr + offsetbytes, value,
- sizebytes);
+ kgsl_cffdump_setmem(device,
+ memdesc->gpuaddr + offsetbytes, value,
+ sizebytes);
memset(memdesc->hostptr + offsetbytes, value, sizebytes);
return 0;
}
diff --git a/drivers/gpu/msm/kgsl_sharedmem.h b/drivers/gpu/msm/kgsl_sharedmem.h
index 14ae0dc..985b9b8 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.h
+++ b/drivers/gpu/msm/kgsl_sharedmem.h
@@ -55,11 +55,13 @@
uint32_t *dst,
unsigned int offsetbytes);
-int kgsl_sharedmem_writel(const struct kgsl_memdesc *memdesc,
+int kgsl_sharedmem_writel(struct kgsl_device *device,
+ const struct kgsl_memdesc *memdesc,
unsigned int offsetbytes,
uint32_t src);
-int kgsl_sharedmem_set(const struct kgsl_memdesc *memdesc,
+int kgsl_sharedmem_set(struct kgsl_device *device,
+ const struct kgsl_memdesc *memdesc,
unsigned int offsetbytes, unsigned int value,
unsigned int sizebytes);
@@ -154,7 +156,7 @@
static inline int
memdesc_sg_phys(struct kgsl_memdesc *memdesc,
- unsigned int physaddr, unsigned int size)
+ phys_addr_t physaddr, unsigned int size)
{
memdesc->sg = kgsl_sg_alloc(1);
if (memdesc->sg == NULL)
diff --git a/drivers/gpu/msm/kgsl_snapshot.c b/drivers/gpu/msm/kgsl_snapshot.c
index 6fcd912..d3edbba 100644
--- a/drivers/gpu/msm/kgsl_snapshot.c
+++ b/drivers/gpu/msm/kgsl_snapshot.c
@@ -27,7 +27,7 @@
struct kgsl_snapshot_object {
unsigned int gpuaddr;
- unsigned int ptbase;
+ phys_addr_t ptbase;
unsigned int size;
unsigned int offset;
int type;
@@ -140,6 +140,7 @@
int hang = (int) priv;
int ctxtcount = 0;
int size = sizeof(*header);
+ phys_addr_t temp_ptbase;
/* Figure out how many active contexts there are - these will
* be appended on the end of the structure */
@@ -181,11 +182,14 @@
kgsl_sharedmem_readl(&device->memstore, &header->current_context,
KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL, current_context));
+
/* Get the current PT base */
- header->ptbase = kgsl_mmu_get_current_ptbase(&device->mmu);
+ temp_ptbase = kgsl_mmu_get_current_ptbase(&device->mmu);
+ /* Truncate to 32 bits in case LPAE is used */
+ header->ptbase = (__u32)temp_ptbase;
/* And the PID for the task leader */
pid = header->pid = kgsl_mmu_get_ptname_from_ptbase(&device->mmu,
- header->ptbase);
+ temp_ptbase);
task = find_task_by_vpid(pid);
@@ -267,7 +271,7 @@
header.size = ALIGN(obj->size, 4) >> 2;
header.gpuaddr = obj->gpuaddr;
- header.ptbase = obj->ptbase;
+ header.ptbase = (__u32)obj->ptbase;
header.type = obj->type;
ret = obj_itr_out(itr, &header, sizeof(header));
@@ -309,7 +313,7 @@
* Return 1 if the object is already in the list - this can save us from
* having to parse the sme thing over again.
*/
-int kgsl_snapshot_have_object(struct kgsl_device *device, unsigned int ptbase,
+int kgsl_snapshot_have_object(struct kgsl_device *device, phys_addr_t ptbase,
unsigned int gpuaddr, unsigned int size)
{
struct kgsl_snapshot_object *obj;
@@ -339,7 +343,7 @@
* size of the object being frozen
*/
-int kgsl_snapshot_get_object(struct kgsl_device *device, unsigned int ptbase,
+int kgsl_snapshot_get_object(struct kgsl_device *device, phys_addr_t ptbase,
unsigned int gpuaddr, unsigned int size, unsigned int type)
{
struct kgsl_mem_entry *entry;
diff --git a/drivers/gpu/msm/kgsl_snapshot.h b/drivers/gpu/msm/kgsl_snapshot.h
index 4db2815..61a3b22 100644
--- a/drivers/gpu/msm/kgsl_snapshot.h
+++ b/drivers/gpu/msm/kgsl_snapshot.h
@@ -320,10 +320,10 @@
unsigned int data, unsigned int start, unsigned int count);
/* Freeze a GPU buffer so it can be dumped in the snapshot */
-int kgsl_snapshot_get_object(struct kgsl_device *device, unsigned int ptbase,
+int kgsl_snapshot_get_object(struct kgsl_device *device, phys_addr_t ptbase,
unsigned int gpuaddr, unsigned int size, unsigned int type);
-int kgsl_snapshot_have_object(struct kgsl_device *device, unsigned int ptbase,
+int kgsl_snapshot_have_object(struct kgsl_device *device, phys_addr_t ptbase,
unsigned int gpuaddr, unsigned int size);
#endif
diff --git a/drivers/gpu/msm/z180.c b/drivers/gpu/msm/z180.c
index 49265fc..7004ad7 100644
--- a/drivers/gpu/msm/z180.c
+++ b/drivers/gpu/msm/z180.c
@@ -467,10 +467,10 @@
addmarker(&z180_dev->ringbuffer, z180_dev->current_timestamp);
/* monkey patch the IB so that it jumps back to the ringbuffer */
- kgsl_sharedmem_writel(&entry->memdesc,
+ kgsl_sharedmem_writel(device, &entry->memdesc,
((sizedwords + 1) * sizeof(unsigned int)),
rb_gpuaddr(z180_dev, z180_dev->current_timestamp));
- kgsl_sharedmem_writel(&entry->memdesc,
+ kgsl_sharedmem_writel(device, &entry->memdesc,
((sizedwords + 2) * sizeof(unsigned int)),
nextcnt);
@@ -710,7 +710,7 @@
BUG_ON(offsetwords*sizeof(uint32_t) >= device->reg_len);
reg = (unsigned int *)(device->reg_virt + (offsetwords << 2));
- kgsl_cffdump_regwrite(device->id, offsetwords << 2, value);
+ kgsl_cffdump_regwrite(device, offsetwords << 2, value);
/*ensure previous writes post before this one,
* i.e. act like normal writel() */
wmb();
diff --git a/drivers/gpu/msm/z180_postmortem.c b/drivers/gpu/msm/z180_postmortem.c
index 55b8faa..5d929cf 100644
--- a/drivers/gpu/msm/z180_postmortem.c
+++ b/drivers/gpu/msm/z180_postmortem.c
@@ -118,7 +118,7 @@
int rb_slot_num = -1;
struct z180_device *z180_dev = Z180_DEVICE(device);
struct kgsl_mem_entry *entry = NULL;
- unsigned int pt_base;
+ phys_addr_t pt_base;
unsigned int i;
unsigned int j;
char linebuf[CHARS_PER_LINE];
diff --git a/drivers/hwmon/qpnp-adc-current.c b/drivers/hwmon/qpnp-adc-current.c
index f6ab3c2..de7b0e9 100644
--- a/drivers/hwmon/qpnp-adc-current.c
+++ b/drivers/hwmon/qpnp-adc-current.c
@@ -646,13 +646,15 @@
{
struct qpnp_iadc_drv *iadc = qpnp_iadc;
uint8_t rslt_rsense;
- int32_t rc, sign_bit = 0;
+ int32_t rc = 0, sign_bit = 0;
if (!iadc || !iadc->iadc_initialized)
return -EPROBE_DEFER;
- if (iadc->external_rsense)
+ if (iadc->external_rsense) {
*rsense = iadc->rsense;
+ return rc;
+ }
rc = qpnp_iadc_read_reg(QPNP_IADC_NOMINAL_RSENSE, &rslt_rsense);
if (rc < 0) {
diff --git a/drivers/iommu/msm_iommu_dev-v1.c b/drivers/iommu/msm_iommu_dev-v1.c
index c0e05f4..958b7b1 100644
--- a/drivers/iommu/msm_iommu_dev-v1.c
+++ b/drivers/iommu/msm_iommu_dev-v1.c
@@ -359,7 +359,20 @@
ctx_drvdata->secure_context = of_property_read_bool(pdev->dev.of_node,
"qcom,secure-context");
- if (!ctx_drvdata->secure_context) {
+ if (ctx_drvdata->secure_context) {
+ irq = platform_get_irq(pdev, 1);
+ if (irq > 0) {
+ ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+ msm_iommu_secure_fault_handler_v2,
+ IRQF_ONESHOT | IRQF_SHARED,
+ "msm_iommu_secure_irq", pdev);
+ if (ret) {
+ pr_err("Request IRQ %d failed with ret=%d\n",
+ irq, ret);
+ return ret;
+ }
+ }
+ } else {
irq = platform_get_irq(pdev, 0);
if (irq > 0) {
ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
diff --git a/drivers/iommu/msm_iommu_sec.c b/drivers/iommu/msm_iommu_sec.c
index 74d8b48..a17a4e8 100644
--- a/drivers/iommu/msm_iommu_sec.c
+++ b/drivers/iommu/msm_iommu_sec.c
@@ -38,6 +38,7 @@
/* bitmap of the page sizes currently supported */
#define MSM_IOMMU_PGSIZES (SZ_4K | SZ_64K | SZ_1M | SZ_16M)
+/* commands for SCM_SVC_MP */
#define IOMMU_SECURE_CFG 2
#define IOMMU_SECURE_PTBL_SIZE 3
#define IOMMU_SECURE_PTBL_INIT 4
@@ -47,6 +48,9 @@
#define IOMMU_SECURE_UNMAP2 0x0C
#define IOMMU_TLBINVAL_FLAG 0x00000001
+/* commands for SCM_SVC_UTIL */
+#define IOMMU_DUMP_SMMU_FAULT_REGS 0X0C
+
static struct iommu_access_ops *iommu_access_ops;
struct msm_scm_paddr_list {
@@ -73,11 +77,154 @@
unsigned int flags;
};
+struct msm_scm_fault_regs_dump {
+ uint32_t dump_size;
+ uint32_t fsr_addr;
+ uint32_t fsr;
+ uint32_t far0_addr;
+ uint32_t far0;
+ uint32_t far1_addr;
+ uint32_t far1;
+ uint32_t par0_addr;
+ uint32_t par0;
+ uint32_t par1_addr;
+ uint32_t par1;
+ uint32_t fsyn0_addr;
+ uint32_t fsyn0;
+ uint32_t fsyn1_addr;
+ uint32_t fsyn1;
+ uint32_t ttbr0_addr;
+ uint32_t ttbr0;
+ uint32_t ttbr1_addr;
+ uint32_t ttbr1;
+ uint32_t ttbcr_addr;
+ uint32_t ttbcr;
+ uint32_t sctlr_addr;
+ uint32_t sctlr;
+ uint32_t actlr_addr;
+ uint32_t actlr;
+ uint32_t prrr_addr;
+ uint32_t prrr;
+ uint32_t nmrr_addr;
+ uint32_t nmrr;
+};
+
void msm_iommu_sec_set_access_ops(struct iommu_access_ops *access_ops)
{
iommu_access_ops = access_ops;
}
+static int msm_iommu_dump_fault_regs(int smmu_id, int cb_num,
+ struct msm_scm_fault_regs_dump *regs)
+{
+ int ret;
+
+ struct msm_scm_fault_regs_dump_req {
+ uint32_t id;
+ uint32_t cb_num;
+ phys_addr_t buff;
+ uint32_t len;
+ } req_info;
+ int resp;
+
+ req_info.id = smmu_id;
+ req_info.cb_num = cb_num;
+ req_info.buff = virt_to_phys(regs);
+ req_info.len = sizeof(*regs);
+
+ ret = scm_call(SCM_SVC_UTIL, IOMMU_DUMP_SMMU_FAULT_REGS,
+ &req_info, sizeof(req_info), &resp, 1);
+
+ return ret;
+}
+
+irqreturn_t msm_iommu_secure_fault_handler_v2(int irq, void *dev_id)
+{
+ struct platform_device *pdev = dev_id;
+ struct msm_iommu_drvdata *drvdata;
+ struct msm_iommu_ctx_drvdata *ctx_drvdata;
+ struct msm_scm_fault_regs_dump *regs;
+ int tmp, ret = IRQ_HANDLED;
+
+ iommu_access_ops->iommu_lock_acquire();
+
+ BUG_ON(!pdev);
+
+ drvdata = dev_get_drvdata(pdev->dev.parent);
+ BUG_ON(!drvdata);
+
+ ctx_drvdata = dev_get_drvdata(&pdev->dev);
+ BUG_ON(!ctx_drvdata);
+
+ regs = kmalloc(sizeof(*regs), GFP_KERNEL);
+ if (!regs) {
+ pr_err("%s: Couldn't allocate memory\n", __func__);
+ goto lock_release;
+ }
+
+ if (!drvdata->ctx_attach_count) {
+ pr_err("Unexpected IOMMU page fault from secure context bank!\n");
+ pr_err("name = %s\n", drvdata->name);
+ pr_err("Power is OFF. Unable to read page fault information\n");
+ /*
+ * We cannot determine which context bank caused the issue so
+ * we just return handled here to ensure IRQ handler code is
+ * happy
+ */
+ goto free_regs;
+ }
+
+ iommu_access_ops->iommu_clk_on(drvdata);
+ tmp = msm_iommu_dump_fault_regs(drvdata->sec_id,
+ ctx_drvdata->num, regs);
+ iommu_access_ops->iommu_clk_off(drvdata);
+
+ if (tmp) {
+ pr_err("%s: Couldn't dump fault registers!\n", __func__);
+ goto free_regs;
+ } else if (regs->fsr) {
+ struct msm_iommu_context_regs ctx_regs = {
+ .far = regs->far0,
+ .par = regs->par0,
+ .fsr = regs->fsr,
+ .fsynr0 = regs->fsyn0,
+ .fsynr1 = regs->fsyn1,
+ .ttbr0 = regs->ttbr0,
+ .ttbr1 = regs->ttbr1,
+ .sctlr = regs->sctlr,
+ .actlr = regs->actlr,
+ .prrr = regs->prrr,
+ .nmrr = regs->nmrr,
+ };
+
+ if (!ctx_drvdata->attached_domain) {
+ pr_err("Bad domain in interrupt handler\n");
+ tmp = -ENOSYS;
+ } else {
+ tmp = report_iommu_fault(ctx_drvdata->attached_domain,
+ &ctx_drvdata->pdev->dev,
+ regs->far0, 0);
+ }
+
+ /* if the fault wasn't handled by someone else: */
+ if (tmp == -ENOSYS) {
+ pr_err("Unexpected IOMMU page fault from secure context bank!\n");
+ pr_err("name = %s\n", drvdata->name);
+ pr_err("context = %s (%d)\n", ctx_drvdata->name,
+ ctx_drvdata->num);
+ pr_err("Interesting registers:\n");
+ print_ctx_regs(&ctx_regs);
+ }
+ } else {
+ ret = IRQ_NONE;
+ }
+free_regs:
+ kfree(regs);
+lock_release:
+ iommu_access_ops->iommu_lock_release();
+ return ret;
+}
+
static int msm_iommu_sec_ptbl_init(void)
{
struct device_node *np;
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
index b8c3c44..bd4344b 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -442,6 +442,45 @@
}
EXPORT_SYMBOL(dvb_dmx_video_pattern_search);
+/**
+ * dvb_dmx_notify_section_event() - Notify demux event for all filters of a
+ * specified section feed.
+ *
+ * @feed: dvb_demux_feed object
+ * @event: demux event to notify
+ * @should_lock: specifies whether the function should lock the demux
+ *
+ * Caller is responsible for locking the demux properly, either by doing the
+ * locking itself and setting 'should_lock' to 0, or have the function do it
+ * by setting 'should_lock' to 1.
+ */
+int dvb_dmx_notify_section_event(struct dvb_demux_feed *feed,
+ struct dmx_data_ready *event, int should_lock)
+{
+ struct dvb_demux_filter *f;
+
+ if (feed == NULL || event == NULL || feed->type != DMX_TYPE_SEC)
+ return -EINVAL;
+
+ if (!should_lock && !spin_is_locked(&feed->demux->lock))
+ return -EINVAL;
+
+ if (should_lock)
+ spin_lock(&feed->demux->lock);
+
+ f = feed->filter;
+ while (f && feed->feed.sec.is_filtering) {
+ feed->data_ready_cb.sec(&f->filter, event);
+ f = f->next;
+ }
+
+ if (should_lock)
+ spin_unlock(&feed->demux->lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(dvb_dmx_notify_section_event);
+
static int dvb_dmx_check_pes_end(struct dvb_demux_feed *feed)
{
struct dmx_data_ready data;
@@ -1310,8 +1349,7 @@
dmx_data_ready.scrambling_bits.new_value = scrambling_bits;
if (feed->type == DMX_TYPE_SEC)
- feed->data_ready_cb.sec(&feed->filter->filter,
- &dmx_data_ready);
+ dvb_dmx_notify_section_event(feed, &dmx_data_ready, 0);
else
feed->data_ready_cb.ts(&feed->feed.ts, &dmx_data_ready);
}
@@ -2735,7 +2773,7 @@
struct dvb_demux_feed *feed = (struct dvb_demux_feed *)section_feed;
struct dvb_demux *dvbdmx = feed->demux;
struct dmx_data_ready data;
- int ret;
+ int ret = 0;
data.data_length = 0;
@@ -2760,13 +2798,11 @@
switch (cmd->type) {
case DMX_OOB_CMD_EOS:
data.status = DMX_OK_EOS;
- ret = feed->data_ready_cb.sec(&feed->filter->filter, &data);
break;
case DMX_OOB_CMD_MARKER:
data.status = DMX_OK_MARKER;
data.marker.id = cmd->params.marker.id;
- ret = feed->data_ready_cb.sec(&feed->filter->filter, &data);
break;
default:
@@ -2774,6 +2810,9 @@
break;
}
+ if (!ret)
+ ret = dvb_dmx_notify_section_event(feed, &data, 1);
+
mutex_unlock(&dvbdmx->mutex);
return ret;
}
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.h b/drivers/media/dvb/dvb-core/dvb_demux.h
index 9fb1a12..aeafa57 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.h
+++ b/drivers/media/dvb/dvb-core/dvb_demux.h
@@ -325,6 +325,8 @@
u64 curr_match_tsp, u64 prev_match_tsp,
u64 curr_pusi_tsp, u64 prev_pusi_tsp);
void dvb_dmx_notify_idx_events(struct dvb_demux_feed *feed);
+int dvb_dmx_notify_section_event(struct dvb_demux_feed *feed,
+ struct dmx_data_ready *event, int should_lock);
/**
* dvb_dmx_is_video_feed - Returns whether the PES feed
diff --git a/drivers/media/platform/msm/camera_v2/Kconfig b/drivers/media/platform/msm/camera_v2/Kconfig
index 52864ae..525a545 100644
--- a/drivers/media/platform/msm/camera_v2/Kconfig
+++ b/drivers/media/platform/msm/camera_v2/Kconfig
@@ -36,6 +36,16 @@
This config macro is required targets based on 8960,
8930 and 8064 platforms.
+config MSM_CSI22_HEADER
+ bool "Qualcomm MSM CSI 2.2 Header"
+ depends on MSMB_CAMERA
+ ---help---
+ Enable support for CSI drivers to include 2.2
+ header. This header has register macros and its
+ values and bit mask for register configuration bits
+ This config macro is required targets based on 8610
+ platform.
+
config MSM_CSI30_HEADER
bool "Qualcomm MSM CSI 3.0 Header"
depends on MSMB_CAMERA
@@ -82,6 +92,15 @@
of any CID of CSID can be routed to of of pixel or raw
data interface in VFE.
+config MSM_ISPIF_V1
+ bool "Qualcomm MSM Image Signal Processing interface support"
+ depends on MSMB_CAMERA
+ ---help---
+ Enable support for Image Signal Processing interface module.
+ This module acts as a crossbar between CSID and VFE. Output
+ of any CID of MSM_CSI22_HEADER can be routed to of pixel
+ or raw data interface in VFE.
+
config S5K3L1YX
bool "Sensor S5K3L1YX (BAYER 12M)"
depends on MSMB_CAMERA
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
index 88f2f08..74a920c 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
@@ -567,11 +567,18 @@
if (buf_state == MSM_ISP_BUFFER_STATE_DIVERTED) {
buf_info = msm_isp_get_buf_ptr(buf_mgr,
info->handle, info->buf_idx);
- if (info->dirty_buf)
- msm_isp_put_buf(buf_mgr, info->handle, info->buf_idx);
- else
- msm_isp_buf_done(buf_mgr, info->handle, info->buf_idx,
- buf_info->tv, buf_info->frame_id);
+ if (info->dirty_buf) {
+ rc = msm_isp_put_buf(buf_mgr,
+ info->handle, info->buf_idx);
+ } else {
+ if (BUF_SRC(bufq->stream_id))
+ pr_err("%s: Invalid native buffer state\n",
+ __func__);
+ else
+ rc = msm_isp_buf_done(buf_mgr,
+ info->handle, info->buf_idx,
+ buf_info->tv, buf_info->frame_id);
+ }
} else {
bufq = msm_isp_get_bufq(buf_mgr, info->handle);
if (BUF_SRC(bufq->stream_id)) {
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
index c4a1b63..7bf8511 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
@@ -29,8 +29,9 @@
#define CDBG(fmt, args...) do { } while (0)
#endif
-#define VFE40_V1_VERSION 0x10000018
-#define VFE40_V2_VERSION 0x1001001A
+#define VFE40_8974V1_VERSION 0x10000018
+#define VFE40_8974V2_VERSION 0x1001001A
+#define VFE40_8x26_VERSION 0x20000013
#define VFE40_BURST_LEN 3
#define VFE40_STATS_BURST_LEN 2
@@ -90,7 +91,8 @@
static void msm_vfe40_init_qos_parms(struct vfe_device *vfe_dev)
{
void __iomem *vfebase = vfe_dev->vfe_base;
- if (vfe_dev->vfe_hw_version == VFE40_V1_VERSION) {
+ if (vfe_dev->vfe_hw_version == VFE40_8974V1_VERSION ||
+ vfe_dev->vfe_hw_version == VFE40_8x26_VERSION) {
msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_0);
msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_1);
msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_2);
@@ -99,7 +101,7 @@
msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_5);
msm_camera_io_w(0xAAAAAAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_6);
msm_camera_io_w(0x0002AAAA, vfebase + VFE40_BUS_BDG_QOS_CFG_7);
- } else if (vfe_dev->vfe_hw_version == VFE40_V2_VERSION) {
+ } else if (vfe_dev->vfe_hw_version == VFE40_8974V2_VERSION) {
msm_camera_io_w(0xAAA9AAA9, vfebase + VFE40_BUS_BDG_QOS_CFG_0);
msm_camera_io_w(0xAAA9AAA9, vfebase + VFE40_BUS_BDG_QOS_CFG_1);
msm_camera_io_w(0xAAA9AAA9, vfebase + VFE40_BUS_BDG_QOS_CFG_2);
@@ -108,81 +110,138 @@
msm_camera_io_w(0xAAA9AAA9, vfebase + VFE40_BUS_BDG_QOS_CFG_5);
msm_camera_io_w(0xAAA9AAA9, vfebase + VFE40_BUS_BDG_QOS_CFG_6);
msm_camera_io_w(0x0001AAA9, vfebase + VFE40_BUS_BDG_QOS_CFG_7);
+ } else {
+ BUG();
+ pr_err("%s: QOS is NOT configured for HW Version %x\n",
+ __func__, vfe_dev->vfe_hw_version);
}
}
+static void msm_vfe40_init_vbif_parms_8974_v1(struct vfe_device *vfe_dev)
+{
+ void __iomem *vfe_vbif_base = vfe_dev->vfe_vbif_base;
+ msm_camera_io_w(0x1,
+ vfe_vbif_base + VFE40_VBIF_CLKON);
+ msm_camera_io_w(0x01010101,
+ vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF0);
+ msm_camera_io_w(0x01010101,
+ vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF1);
+ msm_camera_io_w(0x10010110,
+ vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF2);
+ msm_camera_io_w(0x10101010,
+ vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF0);
+ msm_camera_io_w(0x10101010,
+ vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF1);
+ msm_camera_io_w(0x10101010,
+ vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF2);
+ msm_camera_io_w(0x00001010,
+ vfe_vbif_base + VFE40_VBIF_OUT_RD_LIM_CONF0);
+ msm_camera_io_w(0x00001010,
+ vfe_vbif_base + VFE40_VBIF_OUT_WR_LIM_CONF0);
+ msm_camera_io_w(0x00000707,
+ vfe_vbif_base + VFE40_VBIF_DDR_OUT_MAX_BURST);
+ msm_camera_io_w(0x00000707,
+ vfe_vbif_base + VFE40_VBIF_OCMEM_OUT_MAX_BURST);
+ msm_camera_io_w(0x00000030,
+ vfe_vbif_base + VFE40_VBIF_ARB_CTL);
+ msm_camera_io_w(0x00000FFF,
+ vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO_EN);
+ msm_camera_io_w(0x0FFF0FFF,
+ vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO);
+ msm_camera_io_w(0x00000001,
+ vfe_vbif_base + VFE40_VBIF_ROUND_ROBIN_QOS_ARB);
+ msm_camera_io_w(0x22222222,
+ vfe_vbif_base + VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF0);
+ msm_camera_io_w(0x00002222,
+ vfe_vbif_base + VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF1);
+ return;
+}
+
+static void msm_vfe40_init_vbif_parms_8974_v2(struct vfe_device *vfe_dev)
+{
+ void __iomem *vfe_vbif_base = vfe_dev->vfe_vbif_base;
+ msm_camera_io_w(0x1,
+ vfe_vbif_base + VFE40_VBIF_CLKON);
+ msm_camera_io_w(0x10101010,
+ vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF0);
+ msm_camera_io_w(0x10101010,
+ vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF1);
+ msm_camera_io_w(0x10101010,
+ vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF2);
+ msm_camera_io_w(0x10101010,
+ vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF0);
+ msm_camera_io_w(0x10101010,
+ vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF1);
+ msm_camera_io_w(0x10101010,
+ vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF2);
+ msm_camera_io_w(0x00000010,
+ vfe_vbif_base + VFE40_VBIF_OUT_RD_LIM_CONF0);
+ msm_camera_io_w(0x00000010,
+ vfe_vbif_base + VFE40_VBIF_OUT_WR_LIM_CONF0);
+ msm_camera_io_w(0x00000707,
+ vfe_vbif_base + VFE40_VBIF_DDR_OUT_MAX_BURST);
+ msm_camera_io_w(0x00000010,
+ vfe_vbif_base + VFE40_VBIF_ARB_CTL);
+ msm_camera_io_w(0x00000FFF,
+ vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO_EN);
+ msm_camera_io_w(0x0FFF0FFF,
+ vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO);
+ msm_camera_io_w(0x00000003,
+ vfe_vbif_base + VFE40_VBIF_ROUND_ROBIN_QOS_ARB);
+ msm_camera_io_w(0x22222222,
+ vfe_vbif_base + VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF0);
+ msm_camera_io_w(0x00002222,
+ vfe_vbif_base + VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF1);
+ return;
+}
+
+static void msm_vfe40_init_vbif_parms_8x26(struct vfe_device *vfe_dev)
+{
+ void __iomem *vfe_vbif_base = vfe_dev->vfe_vbif_base;
+ msm_camera_io_w(0x10101010,
+ vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF0);
+ msm_camera_io_w(0x10101010,
+ vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF1);
+ msm_camera_io_w(0x10101010,
+ vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF0);
+ msm_camera_io_w(0x10101010,
+ vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF1);
+ msm_camera_io_w(0x00000010,
+ vfe_vbif_base + VFE40_VBIF_OUT_RD_LIM_CONF0);
+ msm_camera_io_w(0x00000010,
+ vfe_vbif_base + VFE40_VBIF_OUT_WR_LIM_CONF0);
+ msm_camera_io_w(0x00000707,
+ vfe_vbif_base + VFE40_VBIF_DDR_OUT_MAX_BURST);
+ msm_camera_io_w(0x000000FF,
+ vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO_EN);
+ msm_camera_io_w(0x00FF00FF,
+ vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO);
+ msm_camera_io_w(0x00000003,
+ vfe_vbif_base + VFE40_VBIF_ROUND_ROBIN_QOS_ARB);
+ msm_camera_io_w(0x22222222,
+ vfe_vbif_base + VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF0);
+ return;
+}
+
static void msm_vfe40_init_vbif_parms(struct vfe_device *vfe_dev)
{
- void __iomem *vfe_vbif_base = vfe_dev->vfe_vbif_base;
- if (vfe_dev->vfe_hw_version == VFE40_V1_VERSION) {
- msm_camera_io_w(0x1,
- vfe_vbif_base + VFE40_VBIF_CLKON);
- msm_camera_io_w(0x01010101,
- vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF0);
- msm_camera_io_w(0x01010101,
- vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF1);
- msm_camera_io_w(0x10010110,
- vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF2);
- msm_camera_io_w(0x10101010,
- vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF0);
- msm_camera_io_w(0x10101010,
- vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF1);
- msm_camera_io_w(0x10101010,
- vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF2);
- msm_camera_io_w(0x00001010,
- vfe_vbif_base + VFE40_VBIF_OUT_RD_LIM_CONF0);
- msm_camera_io_w(0x00001010,
- vfe_vbif_base + VFE40_VBIF_OUT_WR_LIM_CONF0);
- msm_camera_io_w(0x00000707,
- vfe_vbif_base + VFE40_VBIF_DDR_OUT_MAX_BURST);
- msm_camera_io_w(0x00000707,
- vfe_vbif_base + VFE40_VBIF_OCMEM_OUT_MAX_BURST);
- msm_camera_io_w(0x00000030,
- vfe_vbif_base + VFE40_VBIF_ARB_CTL);
- msm_camera_io_w(0x00000FFF,
- vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO_EN);
- msm_camera_io_w(0x0FFF0FFF,
- vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO);
- msm_camera_io_w(0x00000001,
- vfe_vbif_base + VFE40_VBIF_ROUND_ROBIN_QOS_ARB);
- msm_camera_io_w(0x22222222,
- vfe_vbif_base + VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF0);
- msm_camera_io_w(0x00002222,
- vfe_vbif_base + VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF1);
- } else if (vfe_dev->vfe_hw_version == VFE40_V2_VERSION) {
- msm_camera_io_w(0x1,
- vfe_vbif_base + VFE40_VBIF_CLKON);
- msm_camera_io_w(0x10101010,
- vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF0);
- msm_camera_io_w(0x10101010,
- vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF1);
- msm_camera_io_w(0x10101010,
- vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF2);
- msm_camera_io_w(0x10101010,
- vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF0);
- msm_camera_io_w(0x10101010,
- vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF1);
- msm_camera_io_w(0x10101010,
- vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF2);
- msm_camera_io_w(0x00000010,
- vfe_vbif_base + VFE40_VBIF_OUT_RD_LIM_CONF0);
- msm_camera_io_w(0x00000010,
- vfe_vbif_base + VFE40_VBIF_OUT_WR_LIM_CONF0);
- msm_camera_io_w(0x00000707,
- vfe_vbif_base + VFE40_VBIF_DDR_OUT_MAX_BURST);
- msm_camera_io_w(0x00000010,
- vfe_vbif_base + VFE40_VBIF_ARB_CTL);
- msm_camera_io_w(0x00000FFF,
- vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO_EN);
- msm_camera_io_w(0x0FFF0FFF,
- vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO);
- msm_camera_io_w(0x00000003,
- vfe_vbif_base + VFE40_VBIF_ROUND_ROBIN_QOS_ARB);
- msm_camera_io_w(0x22222222,
- vfe_vbif_base + VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF0);
- msm_camera_io_w(0x00002222,
- vfe_vbif_base + VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF1);
+ switch (vfe_dev->vfe_hw_version) {
+ case VFE40_8974V1_VERSION:
+ msm_vfe40_init_vbif_parms_8974_v1(vfe_dev);
+ break;
+ case VFE40_8974V2_VERSION:
+ msm_vfe40_init_vbif_parms_8974_v2(vfe_dev);
+ break;
+ case VFE40_8x26_VERSION:
+ msm_vfe40_init_vbif_parms_8x26(vfe_dev);
+ break;
+ default:
+ BUG();
+ pr_err("%s: VBIF is NOT configured for HW Version %x\n",
+ __func__, vfe_dev->vfe_hw_version);
+ break;
}
+
}
static int msm_vfe40_init_hardware(struct vfe_device *vfe_dev)
diff --git a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c
index f3da41c..1c8662b 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c
@@ -307,10 +307,10 @@
}
if (read_cfg->addr_type == MSM_CAMERA_I2C_BYTE_ADDR)
- val = CCI_I2C_WRITE_CMD | (read_cfg->addr_type << 4) |
+ val = CCI_I2C_WRITE_DISABLE_P_CMD | (read_cfg->addr_type << 4) |
((read_cfg->addr & 0xFF) << 8);
if (read_cfg->addr_type == MSM_CAMERA_I2C_WORD_ADDR)
- val = CCI_I2C_WRITE_CMD | (read_cfg->addr_type << 4) |
+ val = CCI_I2C_WRITE_DISABLE_P_CMD | (read_cfg->addr_type << 4) |
(((read_cfg->addr & 0xFF00) >> 8) << 8) |
((read_cfg->addr & 0xFF) << 16);
rc = msm_cci_write_i2c_queue(cci_dev, val, master, queue);
diff --git a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c
index ebce745..68c7d23 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c
@@ -616,7 +616,7 @@
static int32_t msm_sensor_get_dt_data(struct platform_device *pdev,
struct msm_sensor_ctrl_t *s_ctrl)
{
- int32_t rc = 0, i = 0;
+ int32_t rc = 0, i = 0, ret = 0;
struct device_node *of_node = pdev->dev.of_node;
struct msm_camera_gpio_conf *gconf = NULL;
struct msm_camera_sensor_board_info *sensordata = NULL;
@@ -777,14 +777,11 @@
sensordata->slave_info->sensor_id_reg_addr = id_info[1];
sensordata->slave_info->sensor_id = id_info[2];
- rc = of_property_read_string(of_node, "qcom,vdd-cx-name",
+ /*Optional property, don't return error if absent */
+ ret = of_property_read_string(of_node, "qcom,vdd-cx-name",
&sensordata->misc_regulator);
CDBG("%s qcom,misc_regulator %s, rc %d\n", __func__,
- sensordata->misc_regulator, rc);
- if (rc < 0) {
- pr_err("%s failed %d\n", __func__, __LINE__);
- goto ERROR9;
- }
+ sensordata->misc_regulator, ret);
kfree(gpio_array);
@@ -1327,6 +1324,127 @@
kfree(reg_setting);
break;
}
+ case CFG_SLAVE_READ_I2C: {
+ struct msm_camera_i2c_read_config read_config;
+ uint16_t local_data = 0;
+ uint16_t orig_slave_addr = 0, read_slave_addr = 0;
+ if (copy_from_user(&read_config,
+ (void *)cdata->cfg.setting,
+ sizeof(struct msm_camera_i2c_read_config))) {
+ pr_err("%s:%d failed\n", __func__, __LINE__);
+ rc = -EFAULT;
+ break;
+ }
+ read_slave_addr = read_config.slave_addr;
+ CDBG("%s:CFG_SLAVE_READ_I2C:", __func__);
+ CDBG("%s:slave_addr=0x%x reg_addr=0x%x, data_type=%d\n",
+ __func__, read_config.slave_addr,
+ read_config.reg_addr, read_config.data_type);
+ if (s_ctrl->sensor_i2c_client->cci_client) {
+ orig_slave_addr =
+ s_ctrl->sensor_i2c_client->cci_client->sid;
+ s_ctrl->sensor_i2c_client->cci_client->sid =
+ read_slave_addr >> 1;
+ } else if (s_ctrl->sensor_i2c_client->client) {
+ orig_slave_addr =
+ s_ctrl->sensor_i2c_client->client->addr;
+ s_ctrl->sensor_i2c_client->client->addr =
+ read_slave_addr >> 1;
+ } else {
+ pr_err("%s: error: no i2c/cci client found.", __func__);
+ rc = -EFAULT;
+ break;
+ }
+ CDBG("%s:orig_slave_addr=0x%x, new_slave_addr=0x%x",
+ __func__, orig_slave_addr,
+ read_slave_addr >> 1);
+ rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_read(
+ s_ctrl->sensor_i2c_client,
+ read_config.reg_addr,
+ &local_data, read_config.data_type);
+ if (rc < 0) {
+ pr_err("%s:%d: i2c_read failed\n", __func__, __LINE__);
+ break;
+ }
+ if (copy_to_user((void __user *)read_config.data,
+ (void *)&local_data, sizeof(uint16_t))) {
+ pr_err("%s:%d copy failed\n", __func__, __LINE__);
+ rc = -EFAULT;
+ break;
+ }
+ break;
+ }
+ case CFG_SLAVE_WRITE_I2C_ARRAY: {
+ struct msm_camera_i2c_array_write_config write_config;
+ struct msm_camera_i2c_reg_array *reg_setting = NULL;
+ uint16_t write_slave_addr = 0;
+ uint16_t orig_slave_addr = 0;
+
+ if (copy_from_user(&write_config,
+ (void *)cdata->cfg.setting,
+ sizeof(struct msm_camera_i2c_array_write_config))) {
+ pr_err("%s:%d failed\n", __func__, __LINE__);
+ rc = -EFAULT;
+ break;
+ }
+ CDBG("%s:CFG_SLAVE_WRITE_I2C_ARRAY:", __func__);
+ CDBG("%s:slave_addr=0x%x, array_size=%d\n", __func__,
+ write_config.slave_addr,
+ write_config.conf_array.size);
+ reg_setting = kzalloc(write_config.conf_array.size *
+ (sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL);
+ if (!reg_setting) {
+ pr_err("%s:%d failed\n", __func__, __LINE__);
+ rc = -ENOMEM;
+ break;
+ }
+ if (copy_from_user(reg_setting,
+ (void *)(write_config.conf_array.reg_setting),
+ write_config.conf_array.size *
+ sizeof(struct msm_camera_i2c_reg_array))) {
+ pr_err("%s:%d failed\n", __func__, __LINE__);
+ kfree(reg_setting);
+ rc = -EFAULT;
+ break;
+ }
+ write_config.conf_array.reg_setting = reg_setting;
+ write_slave_addr = write_config.slave_addr;
+ if (s_ctrl->sensor_i2c_client->cci_client) {
+ orig_slave_addr =
+ s_ctrl->sensor_i2c_client->cci_client->sid;
+ s_ctrl->sensor_i2c_client->cci_client->sid =
+ write_slave_addr >> 1;
+ } else if (s_ctrl->sensor_i2c_client->client) {
+ orig_slave_addr =
+ s_ctrl->sensor_i2c_client->client->addr;
+ s_ctrl->sensor_i2c_client->client->addr =
+ write_slave_addr >> 1;
+ } else {
+ pr_err("%s: error: no i2c/cci client found.", __func__);
+ kfree(reg_setting);
+ rc = -EFAULT;
+ break;
+ }
+ CDBG("%s:orig_slave_addr=0x%x, new_slave_addr=0x%x",
+ __func__, orig_slave_addr,
+ write_slave_addr >> 1);
+ rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write_table(
+ s_ctrl->sensor_i2c_client, &(write_config.conf_array));
+ if (s_ctrl->sensor_i2c_client->cci_client) {
+ s_ctrl->sensor_i2c_client->cci_client->sid =
+ orig_slave_addr;
+ } else if (s_ctrl->sensor_i2c_client->client) {
+ s_ctrl->sensor_i2c_client->client->addr =
+ orig_slave_addr;
+ } else {
+ pr_err("%s: error: no i2c/cci client found.", __func__);
+ kfree(reg_setting);
+ rc = -EFAULT;
+ break;
+ }
+ kfree(reg_setting);
+ break;
+ }
case CFG_WRITE_I2C_SEQ_ARRAY: {
struct msm_camera_i2c_seq_reg_setting conf_array;
struct msm_camera_i2c_seq_reg_array *reg_setting = NULL;
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
index d07387e..a63fccf 100644
--- a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
+++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
@@ -4055,11 +4055,13 @@
pes_event.pes_end.start_gap = 0;
pes_event.data_length = 0;
- /* Parse error indicators - TODO: these should be per filter */
+ /* Parse error indicators */
if (sts->error_indicators & SDMX_FILTER_ERR_INVALID_PES_LEN)
pes_event.pes_end.pes_length_mismatch = 1;
- if (sts->error_indicators & SDMX_FILTER_ERR_CONT_CNT_INVALID)
- pes_event.pes_end.disc_indicator_set = 0;
+ else
+ pes_event.pes_end.pes_length_mismatch = 0;
+
+ pes_event.pes_end.disc_indicator_set = 0;
pes_event.pes_end.stc = 0;
pes_event.pes_end.tei_counter = counters.transport_err_count;
@@ -4109,7 +4111,7 @@
MPQ_DVB_DBG_PRINT("%s: Notify CRC err event\n", __func__);
event.status = DMX_CRC_ERROR;
event.data_length = 0;
- feed->data_ready_cb.sec(&feed->filter->filter, &event);
+ dvb_dmx_notify_section_event(feed, &event, 1);
}
if (sts->error_indicators & SDMX_FILTER_ERR_D_BUF_FULL)
@@ -4143,12 +4145,7 @@
if (sts->status_indicators & SDMX_FILTER_STATUS_EOS) {
event.data_length = 0;
event.status = DMX_OK_EOS;
- f = feed->filter;
-
- while (f && sec->is_filtering) {
- feed->data_ready_cb.sec(&f->filter, &event);
- f = f->next;
- }
+ dvb_dmx_notify_section_event(feed, &event, 1);
}
}
@@ -4469,10 +4466,12 @@
{
int i;
int j;
+ int sdmx_filters;
struct sdmx_filter_status *sts;
struct mpq_feed *mpq_feed;
- for (i = 0; i < mpq_demux->sdmx_filter_count; i++) {
+ sdmx_filters = mpq_demux->sdmx_filter_count;
+ for (i = 0; i < sdmx_filters; i++) {
/*
* MPQ_TODO: review lookup optimization
* Can have the related mpq_feed index already associated with
@@ -4815,21 +4814,11 @@
event.status = DMX_OK_MARKER;
event.marker.id = cmd->params.marker.id;
- if (feed->type == DMX_TYPE_SEC) {
- struct dvb_demux_filter *f = feed->filter;
- struct dmx_section_feed *sec = &feed->feed.sec;
-
- while (f && sec->is_filtering) {
- ret = feed->data_ready_cb.sec(&f->filter,
- &event);
- if (ret)
- break;
- f = f->next;
- }
- } else {
+ if (feed->type == DMX_TYPE_SEC)
+ ret = dvb_dmx_notify_section_event(feed, &event, 1);
+ else
/* MPQ_TODO: Notify decoder via the stream buffer */
ret = feed->data_ready_cb.ts(&feed->feed.ts, &event);
- }
break;
default:
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index c3cfe76..8866b34 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -1730,12 +1730,11 @@
}
case V4L2_CID_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO:
{
- struct v4l2_ctrl *rc_mode, *frame_rate;
+ struct v4l2_ctrl *rc_mode;
bool cfr = false;
property_id = HAL_PARAM_VENC_H264_VUI_TIMING_INFO;
rc_mode = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL);
- frame_rate = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_FRAME_RATE);
switch (rc_mode->val) {
case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_CFR:
@@ -1752,20 +1751,9 @@
vui_timing_info.enable = 0;
break;
case V4L2_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO_ENABLED:
- /* Only support this in CFR mode because we
- * don't really know how to fill out vui_timing_info.
- * time_scale in vfr mode. The assumed framerate
- * might be incorrect. */
- if (!cfr) {
- dprintk(VIDC_ERR, "Can't set %x in VFR mode\n",
- ctrl->id);
- rc = -ENOTSUPP;
- break;
- }
-
vui_timing_info.enable = 1;
vui_timing_info.fixed_frame_rate = cfr;
- vui_timing_info.time_scale = frame_rate->val;
+ vui_timing_info.time_scale = inst->prop.fps;
}
pdata = &vui_timing_info;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 91fcdb6..fd29994 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -393,6 +393,7 @@
{
struct msm_vidc_cb_cmd_done *response = data;
struct msm_vidc_inst *inst;
+ struct v4l2_control control = {0};
struct msm_vidc_cb_event *event_notify;
int event = V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT;
int rc = 0;
@@ -401,7 +402,15 @@
event_notify = (struct msm_vidc_cb_event *) response->data;
switch (event_notify->hal_event_type) {
case HAL_EVENT_SEQ_CHANGED_SUFFICIENT_RESOURCES:
- event = V4L2_EVENT_SEQ_CHANGED_SUFFICIENT;
+ event = V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT;
+ control.id =
+ V4L2_CID_MPEG_VIDC_VIDEO_CONTINUE_DATA_TRANSFER;
+ rc = v4l2_g_ctrl(&inst->ctrl_handler, &control);
+ if (rc)
+ dprintk(VIDC_WARN,
+ "Failed to get Smooth streamng flag\n");
+ if (!rc && control.value == true)
+ event = V4L2_EVENT_SEQ_CHANGED_SUFFICIENT;
break;
case HAL_EVENT_SEQ_CHANGED_INSUFFICIENT_RESOURCES:
event = V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT;
@@ -543,6 +552,7 @@
struct msm_vidc_cb_cmd_done *response = data;
struct msm_vidc_inst *inst = NULL ;
struct msm_vidc_core *core = NULL;
+ subsystem_crashed("venus");
if (response) {
core = get_vidc_core(response->device_id);
dprintk(VIDC_WARN, "SYS_ERROR received for core %p\n", core);
diff --git a/drivers/media/platform/msm/wfd/enc-venus-subdev.c b/drivers/media/platform/msm/wfd/enc-venus-subdev.c
index 722aa8f..e6568f1 100644
--- a/drivers/media/platform/msm/wfd/enc-venus-subdev.c
+++ b/drivers/media/platform/msm/wfd/enc-venus-subdev.c
@@ -19,6 +19,7 @@
#include <linux/mutex.h>
#include <linux/wait.h>
#include <linux/slab.h>
+#include <linux/workqueue.h>
#include <mach/iommu_domains.h>
#include <media/msm_vidc.h>
#include <media/v4l2-subdev.h>
@@ -48,6 +49,13 @@
bool callback_thread_running;
struct completion dq_complete, cmd_complete;
bool secure;
+ struct workqueue_struct *fill_buf_wq;
+};
+
+struct fill_buf_work {
+ struct venc_inst *inst;
+ struct mem_region *mregion;
+ struct work_struct work;
};
static const int subscribed_events[] = {
@@ -331,6 +339,14 @@
init_completion(&inst->dq_complete);
init_completion(&inst->cmd_complete);
mutex_init(&inst->lock);
+
+ inst->fill_buf_wq = create_singlethread_workqueue("venc_vidc_ftb_wq");
+ if (!inst->fill_buf_wq) {
+ WFD_MSG_ERR("Failed to create ftb wq\n");
+ rc = -ENOMEM;
+ goto vidc_wq_create_fail;
+ }
+
inst->vidc_context = msm_vidc_open(MSM_VIDC_CORE_0, MSM_VIDC_ENCODER);
if (!inst->vidc_context) {
WFD_MSG_ERR("Failed to create vidc context\n");
@@ -362,6 +378,8 @@
vidc_subscribe_fail:
msm_vidc_close(inst->vidc_context);
vidc_open_fail:
+ destroy_workqueue(inst->fill_buf_wq);
+vidc_wq_create_fail:
kfree(inst);
venc_open_fail:
return rc;
@@ -385,6 +403,7 @@
wait_for_completion(&inst->cmd_complete);
+ destroy_workqueue(inst->fill_buf_wq);
if (inst->callback_thread && inst->callback_thread_running)
kthread_stop(inst->callback_thread);
@@ -551,6 +570,7 @@
inst = (struct venc_inst *)sd->dev_priv;
+ flush_workqueue(inst->fill_buf_wq);
rc = msm_vidc_streamoff(inst->vidc_context, BUF_TYPE_INPUT);
if (rc) {
WFD_MSG_ERR("Failed to streamoff vidc's input port");
@@ -938,25 +958,12 @@
return msm_vidc_s_parm(inst->vidc_context, &p);
}
-static long venc_fill_outbuf(struct v4l2_subdev *sd, void *arg)
+static long fill_outbuf(struct venc_inst *inst, struct mem_region *mregion)
{
- struct venc_inst *inst = NULL;
- struct mem_region *mregion = NULL;
struct v4l2_buffer buffer = {0};
struct v4l2_plane plane = {0};
int index = 0, rc = 0;
- if (!sd) {
- WFD_MSG_ERR("Subdevice required for %s\n", __func__);
- return -EINVAL;
- } else if (!arg) {
- WFD_MSG_ERR("Invalid output buffer ot fill\n");
- return -EINVAL;
- }
-
- inst = (struct venc_inst *)sd->dev_priv;
- mregion = get_registered_mregion(&inst->registered_output_bufs, arg);
-
if (!mregion) {
WFD_MSG_ERR("Output buffer not registered\n");
return -ENOENT;
@@ -994,8 +1001,77 @@
mark_index_busy(&inst->free_output_indices, index);
mutex_unlock(&inst->lock);
}
- return rc;
+ return rc;
+}
+
+static void fill_outbuf_helper(struct work_struct *work)
+{
+ int rc;
+ struct fill_buf_work *fbw =
+ container_of(work, struct fill_buf_work, work);
+
+ rc = fill_outbuf(fbw->inst, fbw->mregion);
+ if (rc) {
+ struct vb2_buffer *vb = NULL;
+
+ WFD_MSG_ERR("Failed to fill buffer async\n");
+ vb = (struct vb2_buffer *)fbw->mregion->cookie;
+ vb->v4l2_buf.flags = 0;
+ vb->v4l2_buf.timestamp = ns_to_timeval(-1);
+ vb->v4l2_planes[0].bytesused = 0;
+
+ fbw->inst->vmops.op_buffer_done(
+ fbw->inst->vmops.cbdata, rc, vb);
+ }
+
+ kfree(fbw);
+}
+
+static long venc_fill_outbuf(struct v4l2_subdev *sd, void *arg)
+{
+ struct fill_buf_work *fbw;
+ struct venc_inst *inst = NULL;
+ struct mem_region *mregion;
+
+ if (!sd) {
+ WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+ return -EINVAL;
+ } else if (!arg) {
+ WFD_MSG_ERR("Invalid output buffer ot fill\n");
+ return -EINVAL;
+ }
+
+ inst = (struct venc_inst *)sd->dev_priv;
+ mregion = get_registered_mregion(&inst->registered_output_bufs, arg);
+ if (!mregion) {
+ WFD_MSG_ERR("Output buffer not registered\n");
+ return -ENOENT;
+ }
+
+ fbw = kzalloc(sizeof(*fbw), GFP_KERNEL);
+ if (!fbw) {
+ WFD_MSG_ERR("Couldn't allocate memory\n");
+ return -ENOMEM;
+ }
+
+ INIT_WORK(&fbw->work, fill_outbuf_helper);
+ fbw->inst = inst;
+ fbw->mregion = mregion;
+ /* XXX: The need for a wq to qbuf to vidc is necessitated as a
+ * workaround for a bug in the v4l2 framework. VIDIOC_QBUF from
+ * triggers a down_read(current->mm->mmap_sem). There is another
+ * _read(..) as msm_vidc_qbuf() depends on videobuf2 framework
+ * as well. However, a _write(..) after the first _read() by a
+ * different driver will prevent the second _read(...) from
+ * suceeding.
+ *
+ * As we can't modify the framework, we're working around by issue
+ * by queuing in a different thread effectively.
+ */
+ queue_work(inst->fill_buf_wq, &fbw->work);
+
+ return 0;
}
static long venc_encode_frame(struct v4l2_subdev *sd, void *arg)
@@ -1127,6 +1203,8 @@
inst = (struct venc_inst *)sd->dev_priv;
+ flush_workqueue(inst->fill_buf_wq);
+
enc_cmd.cmd = V4L2_ENC_QCOM_CMD_FLUSH;
enc_cmd.flags = V4L2_QCOM_CMD_FLUSH_OUTPUT |
V4L2_QCOM_CMD_FLUSH_CAPTURE;
diff --git a/drivers/media/platform/msm/wfd/wfd-ioctl.c b/drivers/media/platform/msm/wfd/wfd-ioctl.c
index d44792c..cc309aa 100644
--- a/drivers/media/platform/msm/wfd/wfd-ioctl.c
+++ b/drivers/media/platform/msm/wfd/wfd-ioctl.c
@@ -1258,7 +1258,7 @@
WFD_MSG_DBG("yay!! got callback\n");
mutex_lock(&inst->vb2_lock);
- vb2_buffer_done(buf, VB2_BUF_STATE_DONE);
+ vb2_buffer_done(buf, status ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
mutex_unlock(&inst->vb2_lock);
}
diff --git a/drivers/misc/tspp.c b/drivers/misc/tspp.c
index e0fffbd..a395b7c 100644
--- a/drivers/misc/tspp.c
+++ b/drivers/misc/tspp.c
@@ -46,6 +46,7 @@
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/string.h>
+#include <mach/msm_bus.h>
/*
* General defines
@@ -437,6 +438,7 @@
struct list_head devlist; /* list of all devices */
struct platform_device *pdev;
void __iomem *base;
+ uint32_t tsif_bus_client;
unsigned int tspp_irq;
unsigned int bam_irq;
u32 bam_handle;
@@ -773,12 +775,24 @@
return -EINVAL;
}
+ if (device->tsif_bus_client) {
+ rc = msm_bus_scale_client_update_request(
+ device->tsif_bus_client, 1);
+ if (rc) {
+ pr_err("tspp: Can't enable bus\n");
+ return -EBUSY;
+ }
+ }
+
if (device->tsif_vreg) {
rc = regulator_set_voltage(device->tsif_vreg,
RPM_REGULATOR_CORNER_SUPER_TURBO,
RPM_REGULATOR_CORNER_SUPER_TURBO);
if (rc) {
pr_err("Unable to set CX voltage.\n");
+ if (device->tsif_bus_client)
+ msm_bus_scale_client_update_request(
+ device->tsif_bus_client, 0);
return rc;
}
}
@@ -791,6 +805,10 @@
RPM_REGULATOR_CORNER_SVS_SOC,
RPM_REGULATOR_CORNER_SUPER_TURBO);
}
+
+ if (device->tsif_bus_client)
+ msm_bus_scale_client_update_request(
+ device->tsif_bus_client, 0);
return -EBUSY;
}
@@ -803,6 +821,10 @@
RPM_REGULATOR_CORNER_SVS_SOC,
RPM_REGULATOR_CORNER_SUPER_TURBO);
}
+
+ if (device->tsif_bus_client)
+ msm_bus_scale_client_update_request(
+ device->tsif_bus_client, 0);
return -EBUSY;
}
@@ -831,6 +853,13 @@
if (rc)
pr_err("Unable to set CX voltage.\n");
}
+
+ if (device->tsif_bus_client) {
+ rc = msm_bus_scale_client_update_request(
+ device->tsif_bus_client, 0);
+ if (rc)
+ pr_err("tspp: Can't disable bus\n");
+ }
}
/*** TSIF functions ***/
@@ -2851,6 +2880,7 @@
struct resource *mem_tspp;
struct resource *mem_bam;
struct tspp_channel *channel;
+ struct msm_bus_scale_pdata *tspp_bus_pdata = NULL;
if (pdev->dev.of_node) {
/* get information from device tree */
@@ -2862,9 +2892,12 @@
pdev->id = -1;
pdev->dev.platform_data = data;
+
+ tspp_bus_pdata = msm_bus_cl_get_pdata(pdev);
} else {
/* must have platform data */
data = pdev->dev.platform_data;
+ tspp_bus_pdata = NULL;
}
if (!data) {
pr_err("tspp: Platform data not available");
@@ -2891,6 +2924,16 @@
device->pdev = pdev;
platform_set_drvdata(pdev, device);
+ /* register bus client */
+ if (tspp_bus_pdata) {
+ device->tsif_bus_client =
+ msm_bus_scale_register_client(tspp_bus_pdata);
+ if (!device->tsif_bus_client)
+ pr_err("tspp: Unable to register bus client\n");
+ } else {
+ device->tsif_bus_client = 0;
+ }
+
/* map regulators */
if (data->tsif_vreg_present) {
device->tsif_vreg = devm_regulator_get(&pdev->dev, "vdd_cx");
@@ -3108,6 +3151,8 @@
if (device->tsif_vreg)
regulator_disable(device->tsif_vreg);
err_regultaor:
+ if (device->tsif_bus_client)
+ msm_bus_scale_unregister_client(device->tsif_bus_client);
kfree(device);
out:
@@ -3143,6 +3188,9 @@
free_irq(device->tsif[i].tsif_irq, &device->tsif[i]);
}
+ if (device->tsif_bus_client)
+ msm_bus_scale_unregister_client(device->tsif_bus_client);
+
wake_lock_destroy(&device->wake_lock);
free_irq(device->tspp_irq, device);
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 21e65b9..f01ddab 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -3122,6 +3122,37 @@
#endif
}
+static void mmc_blk_shutdown(struct mmc_card *card)
+{
+ struct mmc_blk_data *part_md;
+ struct mmc_blk_data *md = mmc_get_drvdata(card);
+ int rc;
+
+ /* Silent the block layer */
+ if (md) {
+ rc = mmc_queue_suspend(&md->queue);
+ if (rc)
+ goto suspend_error;
+ list_for_each_entry(part_md, &md->part, part) {
+ rc = mmc_queue_suspend(&part_md->queue);
+ if (rc)
+ goto suspend_error;
+ }
+ }
+
+ /* send power off notification */
+ if (mmc_card_mmc(card)) {
+ mmc_rpm_hold(card->host, &card->dev);
+ mmc_send_long_pon(card);
+ mmc_rpm_release(card->host, &card->dev);
+ }
+ return;
+
+suspend_error:
+ pr_err("%s: mmc_queue_suspend returned error = %d",
+ mmc_hostname(card->host), rc);
+}
+
#ifdef CONFIG_PM
static int mmc_blk_suspend(struct mmc_card *card)
{
@@ -3181,6 +3212,7 @@
.remove = mmc_blk_remove,
.suspend = mmc_blk_suspend,
.resume = mmc_blk_resume,
+ .shutdown = mmc_blk_shutdown,
};
static int __init mmc_blk_init(void)
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index 7b9e133..ac2ecbb 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -123,6 +123,15 @@
return 0;
}
+static void mmc_bus_shutdown(struct device *dev)
+{
+ struct mmc_driver *drv = to_mmc_driver(dev->driver);
+ struct mmc_card *card = mmc_dev_to_card(dev);
+
+ if (drv->shutdown)
+ drv->shutdown(card);
+}
+
#ifdef CONFIG_PM_SLEEP
static int mmc_bus_suspend(struct device *dev)
{
@@ -153,10 +162,18 @@
{
struct mmc_card *card = mmc_dev_to_card(dev);
- if (mmc_use_core_runtime_pm(card->host))
- return 0;
- else
+ if (mmc_use_core_runtime_pm(card->host)) {
+ /*
+ * If idle time bkops is running on the card, let's not get
+ * into suspend.
+ */
+ if (mmc_card_doing_bkops(card) && mmc_card_is_prog_state(card))
+ return -EBUSY;
+ else
+ return 0;
+ } else {
return mmc_power_save_host(card->host);
+ }
}
static int mmc_runtime_resume(struct device *dev)
@@ -238,6 +255,7 @@
.uevent = mmc_bus_uevent,
.probe = mmc_bus_probe,
.remove = mmc_bus_remove,
+ .shutdown = mmc_bus_shutdown,
.pm = &mmc_bus_pm_ops,
};
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 9fc599b..3d525e1 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -487,11 +487,6 @@
mmc_card_clr_need_bkops(card);
mmc_card_set_doing_bkops(card);
- pr_debug("%s: %s: starting the polling thread\n",
- mmc_hostname(card->host), __func__);
- queue_work(system_nrt_wq,
- &card->bkops_info.poll_for_completion);
-
out:
mmc_release_host(card->host);
mmc_rpm_release(card->host, &card->dev);
@@ -499,81 +494,6 @@
EXPORT_SYMBOL(mmc_start_bkops);
/**
- * mmc_bkops_completion_polling() - Poll on the card status to
- * wait for the non-blocking BKOPS completion
- * @work: The completion polling work
- *
- * The on-going reading of the card status will prevent the card
- * from getting into suspend while it is in the middle of
- * performing BKOPS.
- * Since the non blocking BKOPS can be interrupted by a fetched
- * request we also check IF mmc_card_doing_bkops in each
- * iteration.
- */
-void mmc_bkops_completion_polling(struct work_struct *work)
-{
- struct mmc_card *card = container_of(work, struct mmc_card,
- bkops_info.poll_for_completion);
- unsigned long timeout_jiffies = jiffies +
- msecs_to_jiffies(BKOPS_COMPLETION_POLLING_TIMEOUT_MS);
- u32 status;
- int err;
-
- /*
- * Wait for the BKOPs to complete. Keep reading the status to prevent
- * the host from getting into suspend
- */
- do {
- mmc_rpm_hold(card->host, &card->dev);
- mmc_claim_host(card->host);
-
- if (!mmc_card_doing_bkops(card))
- goto out;
-
- err = mmc_send_status(card, &status);
- if (err) {
- pr_err("%s: error %d requesting status\n",
- mmc_hostname(card->host), err);
- goto out;
- }
-
- /*
- * Some cards mishandle the status bits, so make sure to check
- * both the busy indication and the card state.
- */
- if ((status & R1_READY_FOR_DATA) &&
- (R1_CURRENT_STATE(status) != R1_STATE_PRG)) {
- pr_debug("%s: %s: completed BKOPs, exit polling\n",
- mmc_hostname(card->host), __func__);
- mmc_card_clr_doing_bkops(card);
- card->bkops_info.sectors_changed = 0;
- goto out;
- }
-
- mmc_release_host(card->host);
- mmc_rpm_release(card->host, &card->dev);
-
- /*
- * Sleep before checking the card status again to allow the
- * card to complete the BKOPs operation
- */
- msleep(BKOPS_COMPLETION_POLLING_INTERVAL_MS);
- } while (time_before(jiffies, timeout_jiffies));
-
- pr_err("%s: %s: exit polling due to timeout, stop bkops\n",
- mmc_hostname(card->host), __func__);
- err = mmc_stop_bkops(card);
- if (err)
- pr_err("%s: %s: mmc_stop_bkops failed, err=%d\n",
- mmc_hostname(card->host), __func__, err);
-
- return;
-out:
- mmc_release_host(card->host);
- mmc_rpm_release(card->host, &card->dev);
-}
-
-/**
* mmc_start_idle_time_bkops() - check if a non urgent BKOPS is
* needed
* @work: The idle time BKOPS work
@@ -1066,6 +986,36 @@
}
EXPORT_SYMBOL(mmc_wait_for_req);
+bool mmc_card_is_prog_state(struct mmc_card *card)
+{
+ bool rc;
+ struct mmc_command cmd;
+
+ mmc_claim_host(card->host);
+ memset(&cmd, 0, sizeof(struct mmc_command));
+ cmd.opcode = MMC_SEND_STATUS;
+ if (!mmc_host_is_spi(card->host))
+ cmd.arg = card->rca << 16;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+
+ rc = mmc_wait_for_cmd(card->host, &cmd, 0);
+ if (rc) {
+ pr_err("%s: Get card status fail. rc=%d\n",
+ mmc_hostname(card->host), rc);
+ rc = false;
+ goto out;
+ }
+
+ if (R1_CURRENT_STATE(cmd.resp[0]) == R1_STATE_PRG)
+ rc = true;
+ else
+ rc = false;
+out:
+ mmc_release_host(card->host);
+ return rc;
+}
+EXPORT_SYMBOL(mmc_card_is_prog_state);
+
/**
* mmc_interrupt_hpi - Issue for High priority Interrupt
* @card: the MMC card associated with the HPI transfer
@@ -1189,6 +1139,17 @@
if (!mmc_card_doing_bkops(card))
goto out;
+ /*
+ * If idle time bkops is running on the card, let's not get into
+ * suspend.
+ */
+ if (!mmc_use_core_runtime_pm(card->host) && mmc_card_doing_bkops(card)
+ && (card->host->parent->power.runtime_status == RPM_SUSPENDING)
+ && mmc_card_is_prog_state(card)) {
+ err = -EBUSY;
+ goto out;
+ }
+
err = mmc_interrupt_hpi(card);
/*
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index 6c03bfc..edd6a5d 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -253,11 +253,19 @@
* mmc_host_may_gate_card - check if this card may be gated
* @card: card to check.
*/
-static bool mmc_host_may_gate_card(struct mmc_card *card)
+bool mmc_host_may_gate_card(struct mmc_card *card)
{
/* If there is no card we may gate it */
if (!card)
return true;
+
+ /*
+ * SDIO3.0 card allows the clock to be gated off so check if
+ * that is the case or not.
+ */
+ if (mmc_card_sdio(card) && card->cccr.async_intr_sup)
+ return true;
+
/*
* Don't gate SDIO cards! These need to be clocked at all times
* since they may be independent systems generating interrupts
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 89f8c91..9b9c1ed 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -18,6 +18,7 @@
#include <linux/mmc/card.h>
#include <linux/mmc/mmc.h>
#include <linux/pm_runtime.h>
+#include <linux/reboot.h>
#include "core.h"
#include "bus.h"
@@ -900,6 +901,20 @@
return err;
}
+static int mmc_reboot_notify(struct notifier_block *notify_block,
+ unsigned long event, void *unused)
+{
+ struct mmc_card *card = container_of(
+ notify_block, struct mmc_card, reboot_notify);
+
+ if (event != SYS_RESTART)
+ card->issue_long_pon = true;
+ else
+ card->issue_long_pon = false;
+
+ return NOTIFY_OK;
+}
+
/*
* Handle the detection and initialisation of a card.
*
@@ -979,6 +994,7 @@
card->type = MMC_TYPE_MMC;
card->rca = 1;
memcpy(card->raw_cid, cid, sizeof(card->raw_cid));
+ card->reboot_notify.notifier_call = mmc_reboot_notify;
}
/*
@@ -1400,8 +1416,6 @@
if (card->ext_csd.bkops_en) {
INIT_DELAYED_WORK(&card->bkops_info.dw,
mmc_start_idle_time_bkops);
- INIT_WORK(&card->bkops_info.poll_for_completion,
- mmc_bkops_completion_polling);
/*
* Calculate the time to start the BKOPs checking.
@@ -1462,6 +1476,22 @@
return err;
}
+int mmc_send_long_pon(struct mmc_card *card)
+{
+ int err = 0;
+ struct mmc_host *host = card->host;
+
+ mmc_claim_host(host);
+ if (card->issue_long_pon && mmc_can_poweroff_notify(card)) {
+ err = mmc_poweroff_notify(host->card, EXT_CSD_POWER_OFF_LONG);
+ if (err)
+ pr_warning("%s: error %d sending Long PON",
+ mmc_hostname(host), err);
+ }
+ mmc_release_host(host);
+ return err;
+}
+
/*
* Host is being removed. Free up the current card.
*/
@@ -1470,6 +1500,7 @@
BUG_ON(!host);
BUG_ON(!host->card);
+ unregister_reboot_notifier(&host->card->reboot_notify);
mmc_remove_card(host->card);
mmc_claim_host(host);
@@ -1736,6 +1767,8 @@
mmc_init_clk_scaling(host);
+ register_reboot_notifier(&host->card->reboot_notify);
+
return 0;
remove_card:
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index 4e76f61..91e23ca 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -187,6 +187,23 @@
card->sw_caps.sd3_drv_type |= SD_DRIVER_TYPE_C;
if (data & SDIO_DRIVE_SDTD)
card->sw_caps.sd3_drv_type |= SD_DRIVER_TYPE_D;
+
+ ret = mmc_io_rw_direct(card, 0, 0,
+ SDIO_CCCR_INTERRUPT_EXTENSION, 0, &data);
+ if (ret)
+ goto out;
+ if (data & SDIO_SUPPORT_ASYNC_INTR) {
+ if (card->host->caps2 &
+ MMC_CAP2_ASYNC_SDIO_IRQ_4BIT_MODE) {
+ data |= SDIO_ENABLE_ASYNC_INTR;
+ ret = mmc_io_rw_direct(card, 1, 0,
+ SDIO_CCCR_INTERRUPT_EXTENSION,
+ data, NULL);
+ if (ret)
+ goto out;
+ card->cccr.async_intr_sup = 1;
+ }
+ }
}
/* if no uhs mode ensure we check for high speed */
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index caf5fe4..3986cdd 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -87,6 +87,10 @@
static int msmsdcc_prep_xfer(struct msmsdcc_host *host, struct mmc_data
*data);
+static void msmsdcc_msm_bus_cancel_work_and_set_vote(struct msmsdcc_host *host,
+ struct mmc_ios *ios);
+static void msmsdcc_msm_bus_queue_work(struct msmsdcc_host *host);
+
static u64 dma_mask = DMA_BIT_MASK(32);
static unsigned int msmsdcc_pwrsave = 1;
@@ -2731,12 +2735,14 @@
int rc = 0;
if (enable && !atomic_read(&host->clks_on)) {
+ msmsdcc_msm_bus_cancel_work_and_set_vote(host, &host->mmc->ios);
+
if (!IS_ERR_OR_NULL(host->bus_clk)) {
rc = clk_prepare_enable(host->bus_clk);
if (rc) {
pr_err("%s: %s: failed to enable the bus-clock with error %d\n",
mmc_hostname(host->mmc), __func__, rc);
- goto out;
+ goto remove_vote;
}
}
if (!IS_ERR(host->pclk)) {
@@ -2764,6 +2770,18 @@
clk_disable_unprepare(host->pclk);
if (!IS_ERR_OR_NULL(host->bus_clk))
clk_disable_unprepare(host->bus_clk);
+
+ /*
+ * If clock gating is enabled, then remove the vote
+ * immediately because clocks will be disabled only
+ * after MSM_MMC_CLK_GATE_DELAY and thus no additional
+ * delay is required to remove the bus vote.
+ */
+ if (host->mmc->clkgate_delay)
+ msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
+ else
+ msmsdcc_msm_bus_queue_work(host);
+
atomic_set(&host->clks_on, 0);
}
goto out;
@@ -2774,6 +2792,8 @@
disable_bus:
if (!IS_ERR_OR_NULL(host->bus_clk))
clk_disable_unprepare(host->bus_clk);
+remove_vote:
+ msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
out:
return rc;
}
@@ -3388,6 +3408,14 @@
(1 + ((3 * USEC_PER_SEC) /
(host->clk_rate ? host->clk_rate :
msmsdcc_get_min_sup_clk_rate(host))));
+ spin_unlock_irqrestore(&host->lock, flags);
+ /*
+ * Update bus vote incase of frequency change due to
+ * clock scaling.
+ */
+ msmsdcc_msm_bus_cancel_work_and_set_vote(host,
+ &mmc->ios);
+ spin_lock_irqsave(&host->lock, flags);
}
/*
* give atleast 2 MCLK cycles delay for clocks
@@ -3404,7 +3432,7 @@
else
clk |= MCI_CLK_WIDEBUS_1;
- if (msmsdcc_is_pwrsave(host))
+ if (msmsdcc_is_pwrsave(host) && mmc_host_may_gate_card(host->mmc->card))
clk |= MCI_CLK_PWRSAVE;
clk |= MCI_CLK_FLOWENA;
@@ -3625,7 +3653,6 @@
return rc;
}
out:
- msmsdcc_msm_bus_cancel_work_and_set_vote(host, &mmc->ios);
return 0;
}
@@ -3654,7 +3681,6 @@
}
out:
- msmsdcc_msm_bus_queue_work(host);
return rc;
}
#else
@@ -3690,7 +3716,6 @@
msmsdcc_pm_qos_update_latency(host, 0);
return rc;
}
- msmsdcc_msm_bus_cancel_work_and_set_vote(host, &mmc->ios);
return 0;
}
@@ -3713,7 +3738,6 @@
return rc;
}
out:
- msmsdcc_msm_bus_queue_work(host);
return rc;
}
#endif
@@ -6065,6 +6089,17 @@
msmsdcc_get_min_sup_clk_rate(host)));
atomic_set(&host->clks_on, 1);
+
+ ret = msmsdcc_msm_bus_register(host);
+ if (ret)
+ goto clk_disable;
+
+ if (host->msm_bus_vote.client_handle)
+ INIT_DELAYED_WORK(&host->msm_bus_vote.vote_work,
+ msmsdcc_msm_bus_work);
+
+ msmsdcc_msm_bus_cancel_work_and_set_vote(host, &mmc->ios);
+
/* Apply Hard reset to SDCC to put it in power on default state */
msmsdcc_hard_reset(host);
@@ -6077,18 +6112,10 @@
pm_qos_add_request(&host->pm_qos_req_dma,
PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
- ret = msmsdcc_msm_bus_register(host);
- if (ret)
- goto pm_qos_remove;
-
- if (host->msm_bus_vote.client_handle)
- INIT_DELAYED_WORK(&host->msm_bus_vote.vote_work,
- msmsdcc_msm_bus_work);
-
ret = msmsdcc_vreg_init(host, true);
if (ret) {
pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
- goto clk_disable;
+ goto pm_qos_remove;
}
@@ -6147,6 +6174,7 @@
mmc->caps2 |= MMC_CAP2_CACHE_CTRL;
mmc->caps2 |= MMC_CAP2_POWEROFF_NOTIFY;
mmc->caps2 |= MMC_CAP2_STOP_REQUEST;
+ mmc->caps2 |= MMC_CAP2_ASYNC_SDIO_IRQ_4BIT_MODE;
if (plat->nonremovable)
mmc->caps |= MMC_CAP_NONREMOVABLE;
@@ -6438,12 +6466,13 @@
msmsdcc_sps_exit(host);
vreg_deinit:
msmsdcc_vreg_init(host, false);
- clk_disable:
- clk_disable_unprepare(host->clk);
- msmsdcc_msm_bus_unregister(host);
pm_qos_remove:
if (host->cpu_dma_latency)
pm_qos_remove_request(&host->pm_qos_req_dma);
+ msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
+ msmsdcc_msm_bus_unregister(host);
+ clk_disable:
+ clk_disable_unprepare(host->clk);
clk_put:
clk_put(host->clk);
pclk_disable:
@@ -6764,8 +6793,13 @@
}
pr_debug("%s: %s: ends with err=%d\n", mmc_hostname(mmc), __func__, rc);
out:
- /* set bus bandwidth to 0 immediately */
- msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
+ /*
+ * Remove the vote immediately only if clocks are off in which
+ * case we might have queued work to remove vote but it may not
+ * be completed before runtime suspend or system suspend.
+ */
+ if (!atomic_read(&host->clks_on))
+ msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
msmsdcc_print_pm_stats(host, start, __func__, rc);
return rc;
}
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index d850782..3c0576e 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -1418,10 +1418,20 @@
return;
bw = sdhci_get_bw_required(host, ios);
- if (enable)
+ if (enable) {
sdhci_msm_bus_cancel_work_and_set_vote(host, bw);
- else
- sdhci_msm_bus_queue_work(host);
+ } else {
+ /*
+ * If clock gating is enabled, then remove the vote
+ * immediately because clocks will be disabled only
+ * after SDHCI_MSM_MMC_CLK_GATE_DELAY and thus no
+ * additional delay is required to remove the bus vote.
+ */
+ if (host->mmc->clkgate_delay)
+ sdhci_msm_bus_cancel_work_and_set_vote(host, 0);
+ else
+ sdhci_msm_bus_queue_work(host);
+ }
}
/* Regulator utility functions */
@@ -1942,12 +1952,15 @@
if (enable && !atomic_read(&msm_host->clks_on)) {
pr_debug("%s: request to enable clocks\n",
mmc_hostname(host->mmc));
+
+ sdhci_msm_bus_voting(host, 1);
+
if (!IS_ERR_OR_NULL(msm_host->bus_clk)) {
rc = clk_prepare_enable(msm_host->bus_clk);
if (rc) {
pr_err("%s: %s: failed to enable the bus-clock with error %d\n",
mmc_hostname(host->mmc), __func__, rc);
- goto out;
+ goto remove_vote;
}
}
if (!IS_ERR(msm_host->pclk)) {
@@ -1976,6 +1989,8 @@
clk_disable_unprepare(msm_host->pclk);
if (!IS_ERR_OR_NULL(msm_host->bus_clk))
clk_disable_unprepare(msm_host->bus_clk);
+
+ sdhci_msm_bus_voting(host, 0);
}
atomic_set(&msm_host->clks_on, enable);
goto out;
@@ -1985,6 +2000,9 @@
disable_bus_clk:
if (!IS_ERR_OR_NULL(msm_host->bus_clk))
clk_disable_unprepare(msm_host->bus_clk);
+remove_vote:
+ if (msm_host->msm_bus_vote.client_handle)
+ sdhci_msm_bus_cancel_work_and_set_vote(host, 0);
out:
return rc;
}
@@ -2031,6 +2049,11 @@
}
msm_host->clk_rate = sup_clock;
host->clock = clock;
+ /*
+ * Update the bus vote in case of frequency change due to
+ * clock scaling.
+ */
+ sdhci_msm_bus_voting(host, 1);
}
}
@@ -2122,7 +2145,6 @@
.toggle_cdr = sdhci_msm_toggle_cdr,
.get_max_segments = sdhci_msm_max_segs,
.set_clock = sdhci_msm_set_clock,
- .platform_bus_voting = sdhci_msm_bus_voting,
.get_min_clock = sdhci_msm_get_min_clock,
.get_max_clock = sdhci_msm_get_max_clock,
.disable_data_xfer = sdhci_msm_disable_data_xfer,
@@ -2226,11 +2248,20 @@
msm_host->clk_rate = sdhci_msm_get_min_clock(host);
atomic_set(&msm_host->clks_on, 1);
+ ret = sdhci_msm_bus_register(msm_host, pdev);
+ if (ret)
+ goto clk_disable;
+
+ if (msm_host->msm_bus_vote.client_handle)
+ INIT_DELAYED_WORK(&msm_host->msm_bus_vote.vote_work,
+ sdhci_msm_bus_work);
+ sdhci_msm_bus_voting(host, 1);
+
/* Setup regulators */
ret = sdhci_msm_vreg_init(&pdev->dev, msm_host->pdata, true);
if (ret) {
dev_err(&pdev->dev, "Regulator setup failed (%d)\n", ret);
- goto clk_disable;
+ goto bus_unregister;
}
/* Reset the core and Enable SDHC mode */
@@ -2377,14 +2408,6 @@
host->cpu_dma_latency_us = msm_host->pdata->cpu_dma_latency_us;
- ret = sdhci_msm_bus_register(msm_host, pdev);
- if (ret)
- goto vreg_deinit;
-
- if (msm_host->msm_bus_vote.client_handle)
- INIT_DELAYED_WORK(&msm_host->msm_bus_vote.vote_work,
- sdhci_msm_bus_work);
-
init_completion(&msm_host->pwr_irq_completion);
if (gpio_is_valid(msm_host->pdata->status_gpio)) {
@@ -2393,7 +2416,7 @@
if (ret) {
dev_err(&pdev->dev, "%s: Failed to request card detection IRQ %d\n",
__func__, ret);
- goto bus_unregister;
+ goto vreg_deinit;
}
}
@@ -2436,10 +2459,12 @@
free_cd_gpio:
if (gpio_is_valid(msm_host->pdata->status_gpio))
mmc_cd_gpio_free(msm_host->mmc);
-bus_unregister:
- sdhci_msm_bus_unregister(msm_host);
vreg_deinit:
sdhci_msm_vreg_init(&pdev->dev, msm_host->pdata, false);
+bus_unregister:
+ if (msm_host->msm_bus_vote.client_handle)
+ sdhci_msm_bus_cancel_work_and_set_vote(host, 0);
+ sdhci_msm_bus_unregister(msm_host);
clk_disable:
if (!IS_ERR(msm_host->clk))
clk_disable_unprepare(msm_host->clk);
@@ -2495,6 +2520,16 @@
disable_irq(host->irq);
disable_irq(msm_host->pwr_irq);
+ /*
+ * Remove the vote immediately only if clocks are off in which
+ * case we might have queued work to remove vote but it may not
+ * be completed before runtime suspend or system suspend.
+ */
+ if (!atomic_read(&msm_host->clks_on)) {
+ if (msm_host->msm_bus_vote.client_handle)
+ sdhci_msm_bus_cancel_work_and_set_vote(host, 0);
+ }
+
return 0;
}
@@ -2528,9 +2563,6 @@
goto out;
}
- if (msm_host->msm_bus_vote.client_handle)
- sdhci_msm_bus_cancel_work_and_set_vote(host, 0);
-
return sdhci_msm_runtime_suspend(dev);
out:
return ret;
diff --git a/drivers/mtd/devices/msm_qpic_nand.c b/drivers/mtd/devices/msm_qpic_nand.c
index 5fda343..efa09f6 100644
--- a/drivers/mtd/devices/msm_qpic_nand.c
+++ b/drivers/mtd/devices/msm_qpic_nand.c
@@ -89,6 +89,7 @@
/* QPIC NANDc (NAND Controller) Register Set */
#define MSM_NAND_REG(info, off) (info->nand_phys + off)
+#define MSM_NAND_QPIC_VERSION(info) MSM_NAND_REG(info, 0x20100)
#define MSM_NAND_FLASH_CMD(info) MSM_NAND_REG(info, 0x30000)
#define MSM_NAND_ADDR0(info) MSM_NAND_REG(info, 0x30004)
#define MSM_NAND_ADDR1(info) MSM_NAND_REG(info, 0x30008)
@@ -138,7 +139,7 @@
#define MSM_NAND_CTRL(info) MSM_NAND_REG(info, 0x30F00)
#define BAM_MODE_EN 0
-
+#define MSM_NAND_VERSION(info) MSM_NAND_REG(info, 0x30F08)
#define MSM_NAND_READ_LOCATION_0(info) MSM_NAND_REG(info, 0x30F20)
#define MSM_NAND_READ_LOCATION_1(info) MSM_NAND_REG(info, 0x30F24)
@@ -152,6 +153,12 @@
#define MSM_NAND_CMD_BLOCK_ERASE 0x3A
#define MSM_NAND_CMD_FETCH_ID 0x0B
+/* Version Mask */
+#define MSM_NAND_VERSION_MAJOR_MASK 0xF0000000
+#define MSM_NAND_VERSION_MAJOR_SHIFT 28
+#define MSM_NAND_VERSION_MINOR_MASK 0x0FFF0000
+#define MSM_NAND_VERSION_MINOR_SHIFT 16
+
/* Structure that defines a NAND SPS command element */
struct msm_nand_sps_cmd {
struct sps_command_element ce;
@@ -623,6 +630,48 @@
uint32_t ecc_bch_cfg;
};
+struct version {
+ uint16_t nand_major;
+ uint16_t nand_minor;
+ uint16_t qpic_major;
+ uint16_t qpic_minor;
+};
+
+static int msm_nand_version_check(struct msm_nand_info *info,
+ struct version *nandc_version)
+{
+ uint32_t qpic_ver = 0, nand_ver = 0;
+ int err = 0;
+
+ /* Lookup the version to identify supported features */
+ err = msm_nand_flash_rd_reg(info, MSM_NAND_VERSION(info),
+ &nand_ver);
+ if (err) {
+ pr_err("Failed to read NAND_VERSION, err=%d\n", err);
+ goto out;
+ }
+ nandc_version->nand_major = (nand_ver & MSM_NAND_VERSION_MAJOR_MASK) >>
+ MSM_NAND_VERSION_MAJOR_SHIFT;
+ nandc_version->nand_minor = (nand_ver & MSM_NAND_VERSION_MINOR_MASK) >>
+ MSM_NAND_VERSION_MINOR_SHIFT;
+
+ err = msm_nand_flash_rd_reg(info, MSM_NAND_QPIC_VERSION(info),
+ &qpic_ver);
+ if (err) {
+ pr_err("Failed to read QPIC_VERSION, err=%d\n", err);
+ goto out;
+ }
+ nandc_version->qpic_major = (qpic_ver & MSM_NAND_VERSION_MAJOR_MASK) >>
+ MSM_NAND_VERSION_MAJOR_SHIFT;
+ nandc_version->qpic_minor = (qpic_ver & MSM_NAND_VERSION_MINOR_MASK) >>
+ MSM_NAND_VERSION_MINOR_SHIFT;
+ pr_info("nand_major:%d, nand_minor:%d, qpic_major:%d, qpic_minor:%d\n",
+ nandc_version->nand_major, nandc_version->nand_minor,
+ nandc_version->qpic_major, nandc_version->qpic_minor);
+out:
+ return err;
+}
+
/*
* Function to identify whether the attached NAND flash device is
* complaint to ONFI spec or not. If yes, then it reads the ONFI parameter
@@ -661,6 +710,18 @@
uint32_t flash_status;
} *dma_buffer;
+
+ /* Lookup the version to identify supported features */
+ struct version nandc_version = {0};
+
+ ret = msm_nand_version_check(info, &nandc_version);
+ if (!ret && !(nandc_version.nand_major == 1 &&
+ nandc_version.nand_minor == 1 &&
+ nandc_version.qpic_major == 1 &&
+ nandc_version.qpic_minor == 1)) {
+ ret = -EPERM;
+ goto out;
+ }
wait_event(chip->dma_wait_queue, (onfi_param_info_buf =
msm_nand_get_dma_buffer(chip, ONFI_PARAM_INFO_LENGTH)));
dma_addr_param_info = msm_virt_to_dma(chip, onfi_param_info_buf);
@@ -839,6 +900,7 @@
msm_nand_release_dma_buffer(chip, dma_buffer, sizeof(*dma_buffer));
msm_nand_release_dma_buffer(chip, onfi_param_info_buf,
ONFI_PARAM_INFO_LENGTH);
+out:
return ret;
}
diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c
index af4fe8c..72ced9d 100644
--- a/drivers/mtd/nand/nand_ids.c
+++ b/drivers/mtd/nand/nand_ids.c
@@ -161,6 +161,7 @@
BBT_AUTO_REFRESH
},
+ {"NAND 4GiB 1,8V 8-bit", 0xAC, 2048, 4096, 0x20000, 0},
{NULL,}
};
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index 220fa12..e8b8fc2 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -103,6 +103,8 @@
#define CCU_PRONTO_LAST_ADDR1_OFFSET 0x10
#define CCU_PRONTO_LAST_ADDR2_OFFSET 0x14
+#define WCNSS_DEF_WLAN_RX_BUFF_COUNT 1024
+
#define WCNSS_CTRL_CHANNEL "WCNSS_CTRL"
#define WCNSS_MAX_FRAME_SIZE (4*1024)
#define WCNSS_VERSION_LEN 30
@@ -258,6 +260,7 @@
const struct dev_pm_ops *pm_ops;
int triggered;
int smd_channel_ready;
+ u32 wlan_rx_buff_count;
smd_channel_t *smd_ch;
unsigned char wcnss_version[WCNSS_VERSION_LEN];
unsigned char fw_major;
@@ -977,6 +980,17 @@
return -ENODEV;
}
+u32 wcnss_get_wlan_rx_buff_count(void)
+{
+ if (penv)
+ return penv->wlan_rx_buff_count;
+ else
+ return WCNSS_DEF_WLAN_RX_BUFF_COUNT;
+
+}
+EXPORT_SYMBOL(wcnss_get_wlan_rx_buff_count);
+
+
static int wcnss_smd_tx(void *data, int len)
{
int ret = 0;
@@ -1498,7 +1512,12 @@
int size = 0;
struct resource *res;
int has_pronto_hw = of_property_read_bool(pdev->dev.of_node,
- "qcom,has_pronto_hw");
+ "qcom,has-pronto-hw");
+
+ if (of_property_read_u32(pdev->dev.of_node,
+ "qcom,wlan-rx-buff-count", &penv->wlan_rx_buff_count)) {
+ penv->wlan_rx_buff_count = WCNSS_DEF_WLAN_RX_BUFF_COUNT;
+ }
/* make sure we are only triggered once */
if (penv->triggered)
@@ -1510,7 +1529,7 @@
if (WCNSS_CONFIG_UNSPECIFIED == has_48mhz_xo) {
if (has_pronto_hw) {
has_48mhz_xo = of_property_read_bool(pdev->dev.of_node,
- "qcom,has_48mhz_xo");
+ "qcom,has-48mhz-xo");
} else {
has_48mhz_xo = pdata->has_48mhz_xo;
}
@@ -1520,7 +1539,7 @@
if (WCNSS_CONFIG_UNSPECIFIED == has_autodetect_xo && has_pronto_hw) {
has_autodetect_xo = of_property_read_bool(pdev->dev.of_node,
- "qcom,has_autodetect_xo");
+ "qcom,has-autodetect-xo");
}
penv->thermal_mitigation = 0;
@@ -1664,6 +1683,9 @@
{
struct platform_device *pdev;
+ if (!penv)
+ return -EFAULT;
+
/* first open is only to trigger WCNSS platform driver */
if (!penv->triggered) {
pr_info(DEVICE " triggered by userspace\n");
@@ -1691,7 +1713,7 @@
{
int rc = 0;
- if (!penv->device_opened)
+ if (!penv || !penv->device_opened)
return -EFAULT;
rc = wait_event_interruptible(penv->read_wait, penv->fw_cal_rcvd
@@ -1730,7 +1752,7 @@
int rc = 0;
int size = 0;
- if (!penv->device_opened || penv->user_cal_available)
+ if (!penv || !penv->device_opened || penv->user_cal_available)
return -EFAULT;
if (penv->user_cal_rcvd == 0 && count >= 4
diff --git a/drivers/platform/msm/ipa/ipa.c b/drivers/platform/msm/ipa/ipa.c
index 6495db4..67c86b9 100644
--- a/drivers/platform/msm/ipa/ipa.c
+++ b/drivers/platform/msm/ipa/ipa.c
@@ -50,12 +50,6 @@
#define IPA_AGGR_STR_IN_BYTES(str) \
(strnlen((str), IPA_AGGR_MAX_STR_LENGTH - 1) + 1)
-/*
- * This equals a timer value of 162.56us. This value was
- * determined empirically and shows good bi-directional
- * WLAN throughputs
- */
-#define IPA_HOLB_TMR_DEFAULT_VAL 0x7f
static struct ipa_plat_drv_res ipa_res = {0, };
static struct of_device_id ipa_plat_drv_match[] = {
@@ -1603,8 +1597,6 @@
result = -ENOMEM;
goto fail_mem;
}
- ipa_ctx->hol_en = 0x1;
- ipa_ctx->hol_timer = IPA_HOLB_TMR_DEFAULT_VAL;
IPADBG("polling_mode=%u delay_ms=%u\n", polling_mode, polling_delay_ms);
ipa_ctx->polling_mode = polling_mode;
diff --git a/drivers/platform/msm/ipa/ipa_client.c b/drivers/platform/msm/ipa/ipa_client.c
index b0fb940..6c81504 100644
--- a/drivers/platform/msm/ipa/ipa_client.c
+++ b/drivers/platform/msm/ipa/ipa_client.c
@@ -13,8 +13,14 @@
#include <linux/delay.h>
#include "ipa_i.h"
+/*
+ * These values were determined empirically and shows good E2E bi-
+ * directional throughputs
+ */
#define IPA_A2_HOLB_TMR_EN 0x1
#define IPA_A2_HOLB_TMR_DEFAULT_VAL 0xff
+#define IPA_WLAN_HOLB_TMR_EN 0x1
+#define IPA_WLAN_HOLB_TMR_DEFAULT_VAL 0x7f
static void ipa_enable_data_path(u32 clnt_hdl)
{
@@ -180,8 +186,7 @@
static void ipa_program_holb(struct ipa_ep_context *ep, int ipa_ep_idx)
{
- u32 hol_en;
- u32 hol_tmr;
+ struct ipa_ep_cfg_holb holb;
if (IPA_CLIENT_IS_PROD(ep->client))
return;
@@ -189,18 +194,14 @@
switch (ep->client) {
case IPA_CLIENT_A2_TETHERED_CONS:
case IPA_CLIENT_A2_EMBEDDED_CONS:
- hol_en = IPA_A2_HOLB_TMR_EN;
- hol_tmr = IPA_A2_HOLB_TMR_DEFAULT_VAL;
+ holb.en = IPA_A2_HOLB_TMR_EN;
+ holb.tmr_val = IPA_A2_HOLB_TMR_DEFAULT_VAL;
break;
default:
return;
}
- IPADBG("disable holb for ep=%d tmr=%d\n", ipa_ep_idx, hol_tmr);
- ipa_write_reg(ipa_ctx->mmio,
- IPA_ENDP_INIT_HOL_BLOCK_EN_n_OFST(ipa_ep_idx), hol_en);
- ipa_write_reg(ipa_ctx->mmio,
- IPA_ENDP_INIT_HOL_BLOCK_TIMER_n_OFST(ipa_ep_idx), hol_tmr);
+ ipa_cfg_ep_holb(ipa_ep_idx, &holb);
}
/**
diff --git a/drivers/platform/msm/ipa/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_debugfs.c
index b11c7da..cec92e8 100644
--- a/drivers/platform/msm/ipa/ipa_debugfs.c
+++ b/drivers/platform/msm/ipa/ipa_debugfs.c
@@ -94,8 +94,7 @@
static struct dentry *dent;
static struct dentry *dfile_gen_reg;
static struct dentry *dfile_ep_reg;
-static struct dentry *dfile_ep_hol_en;
-static struct dentry *dfile_ep_hol_timer;
+static struct dentry *dfile_ep_holb;
static struct dentry *dfile_hdr;
static struct dentry *dfile_ip4_rt;
static struct dentry *dfile_ip6_rt;
@@ -147,11 +146,15 @@
return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, nbytes);
}
-static ssize_t ipa_write_ep_hol_en_reg(struct file *file,
+static ssize_t ipa_write_ep_holb(struct file *file,
const char __user *buf, size_t count, loff_t *ppos)
{
- u32 endp_reg_val;
+ struct ipa_ep_cfg_holb holb;
+ u32 en;
+ u32 tmr_val;
+ u32 ep_idx;
unsigned long missing;
+ char *sptr, *token;
if (sizeof(dbg_buff) < count + 1)
return -EFAULT;
@@ -161,40 +164,31 @@
return -EFAULT;
dbg_buff[count] = '\0';
- if (kstrtou32(dbg_buff, 16, &endp_reg_val))
- return -EFAULT;
- ipa_write_reg(ipa_ctx->mmio,
- IPA_ENDP_INIT_HOL_BLOCK_EN_n_OFST(ep_reg_idx),
- endp_reg_val);
+ sptr = dbg_buff;
- ipa_ctx->hol_en = endp_reg_val;
+ token = strsep(&sptr, " ");
+ if (!token)
+ return -EINVAL;
+ if (kstrtou32(token, 0, &ep_idx))
+ return -EINVAL;
- return count;
-}
+ token = strsep(&sptr, " ");
+ if (!token)
+ return -EINVAL;
+ if (kstrtou32(token, 0, &en))
+ return -EINVAL;
-static ssize_t ipa_write_ep_hol_timer_reg(struct file *file,
- const char __user *buf, size_t count, loff_t *ppos)
-{
- u32 endp_reg_val;
- unsigned long missing;
+ token = strsep(&sptr, " ");
+ if (!token)
+ return -EINVAL;
+ if (kstrtou32(token, 0, &tmr_val))
+ return -EINVAL;
- if (sizeof(dbg_buff) < count + 1)
- return -EFAULT;
+ holb.en = en;
+ holb.tmr_val = tmr_val;
- missing = copy_from_user(dbg_buff, buf, count);
- if (missing)
- return -EFAULT;
-
- dbg_buff[count] = '\0';
- if (kstrtou32(dbg_buff, 16, &endp_reg_val))
- return -EFAULT;
-
- ipa_write_reg(ipa_ctx->mmio,
- IPA_ENDP_INIT_HOL_BLOCK_TIMER_n_OFST(ep_reg_idx),
- endp_reg_val);
-
- ipa_ctx->hol_timer = endp_reg_val;
+ ipa_cfg_ep_holb(ep_idx, &holb);
return count;
}
@@ -964,11 +958,8 @@
.write = ipa_write_ep_reg,
};
-const struct file_operations ipa_ep_hol_en_ops = {
- .write = ipa_write_ep_hol_en_reg,
-};
-const struct file_operations ipa_ep_hol_timer_ops = {
- .write = ipa_write_ep_hol_timer_reg,
+const struct file_operations ipa_ep_holb_ops = {
+ .write = ipa_write_ep_holb,
};
const struct file_operations ipa_hdr_ops = {
@@ -1029,20 +1020,13 @@
goto fail;
}
- dfile_ep_hol_en = debugfs_create_file("hol_en", write_only_mode, dent,
- 0, &ipa_ep_hol_en_ops);
- if (!dfile_ep_hol_en || IS_ERR(dfile_ep_hol_en)) {
+ dfile_ep_holb = debugfs_create_file("holb", write_only_mode, dent,
+ 0, &ipa_ep_holb_ops);
+ if (!dfile_ep_holb || IS_ERR(dfile_ep_holb)) {
IPAERR("fail to create file for debug_fs dfile_ep_hol_en\n");
goto fail;
}
- dfile_ep_hol_timer = debugfs_create_file("hol_timer", write_only_mode,
- dent, 0, &ipa_ep_hol_timer_ops);
- if (!dfile_ep_hol_timer || IS_ERR(dfile_ep_hol_timer)) {
- IPAERR("fail to create file for debug_fs dfile_ep_hol_timer\n");
- goto fail;
- }
-
dfile_hdr = debugfs_create_file("hdr", read_only_mode, dent, 0,
&ipa_hdr_ops);
if (!dfile_hdr || IS_ERR(dfile_hdr)) {
diff --git a/drivers/platform/msm/ipa/ipa_i.h b/drivers/platform/msm/ipa/ipa_i.h
index a818931..790898a 100644
--- a/drivers/platform/msm/ipa/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_i.h
@@ -350,6 +350,7 @@
enum ipa_client_type client;
struct sps_pipe *ep_hdl;
struct ipa_ep_cfg cfg;
+ struct ipa_ep_cfg_holb holb;
u32 dst_pipe_index;
u32 rt_tbl_idx;
struct sps_connect connect;
@@ -686,9 +687,6 @@
/* featurize if memory footprint becomes a concern */
struct ipa_stats stats;
void *smem_pipe_mem;
- /* store HOLB configuration for WLAN TX pipes */
- u32 hol_en;
- u32 hol_timer;
struct sk_buff_head rx_list;
};
diff --git a/drivers/platform/msm/ipa/ipa_rm_peers_list.c b/drivers/platform/msm/ipa/ipa_rm_peers_list.c
index 55f8239..4beb2b8 100644
--- a/drivers/platform/msm/ipa/ipa_rm_peers_list.c
+++ b/drivers/platform/msm/ipa/ipa_rm_peers_list.c
@@ -167,12 +167,12 @@
bool ipa_rm_peers_list_has_last_peer(
struct ipa_rm_peers_list *peers_list)
{
- bool result = true;
+ bool result = false;
if (!peers_list)
goto bail;
read_lock(&peers_list->peers_lock);
if (peers_list->peers_count == 1)
- result = false;
+ result = true;
read_unlock(&peers_list->peers_lock);
bail:
return result;
diff --git a/drivers/platform/msm/ipa/ipa_rm_resource.c b/drivers/platform/msm/ipa/ipa_rm_resource.c
index 8655d89..fd67292 100644
--- a/drivers/platform/msm/ipa/ipa_rm_resource.c
+++ b/drivers/platform/msm/ipa/ipa_rm_resource.c
@@ -551,6 +551,9 @@
{
int result = 0;
unsigned long flags;
+ unsigned long consumer_flags;
+ bool state_changed = false;
+ bool release_consumer = false;
if (!resource || !depends_on)
return -EINVAL;
IPADBG("IPA RM: %s from %d to %d ENTER\n",
@@ -565,38 +568,59 @@
spin_lock_irqsave(&resource->state_lock, flags);
switch (resource->state) {
case IPA_RM_RELEASED:
+ break;
case IPA_RM_GRANTED:
+ release_consumer = true;
break;
case IPA_RM_RELEASE_IN_PROGRESS:
if (((struct ipa_rm_resource_prod *)
- resource)->pending_release > 0)
- ((struct ipa_rm_resource_prod *)
+ resource)->pending_release > 0)
+ ((struct ipa_rm_resource_prod *)
resource)->pending_release--;
+ spin_lock_irqsave(&depends_on->state_lock, consumer_flags);
+ if (depends_on->state == IPA_RM_RELEASE_IN_PROGRESS &&
+ ((struct ipa_rm_resource_prod *)
+ resource)->pending_release == 0) {
+ resource->state = IPA_RM_RELEASED;
+ state_changed = true;
+ }
+ spin_unlock_irqrestore(&depends_on->state_lock, consumer_flags);
break;
case IPA_RM_REQUEST_IN_PROGRESS:
+ release_consumer = true;
if (((struct ipa_rm_resource_prod *)
- resource)->pending_request > 0)
- ((struct ipa_rm_resource_prod *)
+ resource)->pending_request > 0)
+ ((struct ipa_rm_resource_prod *)
resource)->pending_request--;
+ spin_lock_irqsave(&depends_on->state_lock, consumer_flags);
+ if (depends_on->state == IPA_RM_REQUEST_IN_PROGRESS &&
+ ((struct ipa_rm_resource_prod *)
+ resource)->pending_request == 0) {
+ resource->state = IPA_RM_GRANTED;
+ state_changed = true;
+ }
+ spin_unlock_irqrestore(&depends_on->state_lock, consumer_flags);
break;
default:
result = -EINVAL;
spin_unlock_irqrestore(&resource->state_lock, flags);
goto bail;
}
- spin_unlock_irqrestore(&resource->state_lock, flags);
- if (ipa_rm_peers_list_has_last_peer(resource->peers_list)) {
+ if (state_changed &&
+ ipa_rm_peers_list_has_last_peer(resource->peers_list)) {
(void) ipa_rm_wq_send_cmd(IPA_RM_WQ_NOTIFY_PROD,
resource->name,
- IPA_RM_RESOURCE_RELEASED);
+ resource->state);
result = -EINPROGRESS;
}
+ spin_unlock_irqrestore(&resource->state_lock, flags);
ipa_rm_peers_list_remove_peer(resource->peers_list,
depends_on->name);
ipa_rm_peers_list_remove_peer(depends_on->peers_list,
resource->name);
- (void) ipa_rm_resource_consumer_release(
- (struct ipa_rm_resource_cons *)depends_on);
+ if (release_consumer)
+ (void) ipa_rm_resource_consumer_release(
+ (struct ipa_rm_resource_cons *)depends_on);
IPADBG("IPA RM: %s from %d to %d SUCCESS\n",
__func__,
resource->name,
diff --git a/drivers/platform/msm/ipa/ipa_utils.c b/drivers/platform/msm/ipa/ipa_utils.c
index 046c4d4..912d93c 100644
--- a/drivers/platform/msm/ipa/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_utils.c
@@ -931,6 +931,73 @@
EXPORT_SYMBOL(ipa_cfg_ep_route);
/**
+ * ipa_cfg_ep_holb() - IPA end-point holb configuration
+ *
+ * If an IPA producer pipe is full, IPA HW by default will block
+ * indefinitely till space opens up. During this time no packets
+ * including those from unrelated pipes will be processed. Enabling
+ * HOLB means IPA HW will be allowed to drop packets as/when needed
+ * and indefinite blocking is avoided.
+ *
+ * @clnt_hdl: [in] opaque client handle assigned by IPA to client
+ * @ipa_ep_cfg: [in] IPA end-point configuration params
+ *
+ * Returns: 0 on success, negative on failure
+ */
+int ipa_cfg_ep_holb(u32 clnt_hdl, const struct ipa_ep_cfg_holb *ipa_ep_cfg)
+{
+ if (clnt_hdl >= IPA_NUM_PIPES || ipa_ctx->ep[clnt_hdl].valid == 0 ||
+ ipa_ep_cfg == NULL || ipa_ep_cfg->tmr_val > 511 ||
+ ipa_ep_cfg->en > 1) {
+ IPAERR("bad parm.\n");
+ return -EINVAL;
+ }
+
+ if (IPA_CLIENT_IS_PROD(ipa_ctx->ep[clnt_hdl].client)) {
+ IPAERR("HOLB does not apply to IPA in EP %d\n", clnt_hdl);
+ return -EINVAL;
+ }
+
+ if (ipa_ctx->ipa_hw_type == IPA_HW_v1_0) {
+ IPAERR("per EP HOLB not supported\n");
+ return -EPERM;
+ } else {
+ ipa_ctx->ep[clnt_hdl].holb = *ipa_ep_cfg;
+ ipa_write_reg(ipa_ctx->mmio,
+ IPA_ENDP_INIT_HOL_BLOCK_EN_n_OFST(clnt_hdl),
+ ipa_ep_cfg->en);
+ ipa_write_reg(ipa_ctx->mmio,
+ IPA_ENDP_INIT_HOL_BLOCK_TIMER_n_OFST(clnt_hdl),
+ ipa_ep_cfg->tmr_val);
+ IPAERR("cfg holb %u ep=%d tmr=%d\n", ipa_ep_cfg->en, clnt_hdl,
+ ipa_ep_cfg->tmr_val);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(ipa_cfg_ep_holb);
+
+/**
+ * ipa_cfg_ep_holb_by_client() - IPA end-point holb configuration
+ *
+ * Wrapper function for ipa_cfg_ep_holb() with client name instead of
+ * client handle. This function is used for clients that does not have
+ * client handle.
+ *
+ * @client: [in] client name
+ * @ipa_ep_cfg: [in] IPA end-point configuration params
+ *
+ * Returns: 0 on success, negative on failure
+ */
+int ipa_cfg_ep_holb_by_client(enum ipa_client_type client,
+ const struct ipa_ep_cfg_holb *ipa_ep_cfg)
+{
+ return ipa_cfg_ep_holb(ipa_get_ep_mapping(ipa_ctx->mode, client),
+ ipa_ep_cfg);
+}
+EXPORT_SYMBOL(ipa_cfg_ep_holb_by_client);
+
+/**
* ipa_dump_buff_internal() - dumps buffer for debug purposes
* @base: buffer base address
* @phy_base: buffer physical base address
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index 9b3973b..e244df4 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -79,6 +79,14 @@
int last_good_ocv_uv;
};
+struct fcc_data {
+ int fcc_new;
+ int chargecycles;
+ int batt_temp;
+ int fcc_real;
+ int temp_real;
+};
+
/**
* struct pm8921_bms_chip -
* @bms_output_lock: lock to prevent concurrent bms reads
@@ -144,7 +152,16 @@
int pon_ocv_uv;
int last_cc_uah;
unsigned long tm_sec;
+
int enable_fcc_learning;
+ int min_fcc_learning_soc;
+ int min_fcc_ocv_pc;
+ int max_fcc_learning_samples;
+ struct fcc_data *fcc_table;
+ int fcc_new;
+ int start_real_soc;
+ int pc_at_start_charge;
+
int shutdown_soc;
int shutdown_iavg_ua;
struct delayed_work calculate_soc_delayed_work;
@@ -194,18 +211,28 @@
#define DEFAULT_OCV_MICROVOLTS 3900000
#define DEFAULT_CHARGE_CYCLES 0
+#define DELTA_FCC_PERCENT 5
+#define MIN_START_PERCENT_FOR_LEARNING 20
+#define MIN_START_OCV_PERCENT_FOR_LEARNING 30
+#define MAX_FCC_LEARNING_COUNT 5
+#define VALID_FCC_CHGCYL_RANGE 50
+
static int last_usb_cal_delta_uv = 1800;
module_param(last_usb_cal_delta_uv, int, 0644);
static int last_chargecycles = DEFAULT_CHARGE_CYCLES;
static int last_charge_increase;
+static int last_fcc_update_count;
+static int max_fcc_cycles = -EINVAL;
module_param(last_chargecycles, int, 0644);
module_param(last_charge_increase, int, 0644);
+module_param(last_fcc_update_count, int, 0644);
static int calculated_soc = -EINVAL;
static int last_soc = -EINVAL;
static int last_real_fcc_mah = -EINVAL;
static int last_real_fcc_batt_temp = -EINVAL;
+static int battery_removed;
static int pm8921_battery_gauge_alarm_notify(struct notifier_block *nb,
unsigned long status, void *unused);
@@ -214,20 +241,20 @@
.notifier_call = pm8921_battery_gauge_alarm_notify,
};
-static int bms_ops_set(const char *val, const struct kernel_param *kp)
+static int bms_ro_ops_set(const char *val, const struct kernel_param *kp)
{
- if (*(int *)kp->arg == -EINVAL)
- return param_set_int(val, kp);
- else
- return 0;
+ return -EINVAL;
}
static struct kernel_param_ops bms_param_ops = {
- .set = bms_ops_set,
+ .set = bms_ro_ops_set,
.get = param_get_int,
};
-
+/* Make last_soc as read only as it is already calculated from shutdown_soc */
module_param_cb(last_soc, &bms_param_ops, &last_soc, 0644);
+module_param_cb(battery_removed, &bms_param_ops, &battery_removed, 0644);
+module_param_cb(max_fcc_cycles, &bms_param_ops,
+ &max_fcc_cycles, 0644);
/*
* bms_fake_battery is set in setups where a battery emulator is used instead
@@ -245,11 +272,6 @@
static int bms_end_ocv_uv;
static int bms_end_cc_uah;
-static int bms_ro_ops_set(const char *val, const struct kernel_param *kp)
-{
- return -EINVAL;
-}
-
static struct kernel_param_ops bms_ro_param_ops = {
.set = bms_ro_ops_set,
.get = param_get_int,
@@ -267,6 +289,9 @@
struct single_row_lut *temp, *old;
int i, fcc, ratio;
+ if (!the_chip->enable_fcc_learning || battery_removed)
+ return;
+
if (!the_chip->fcc_temp_lut) {
pr_err("The static fcc lut table is NULL\n");
return;
@@ -301,6 +326,9 @@
{
int rc = 0;
+ if (battery_removed)
+ return rc;
+
if (last_real_fcc_mah == -EINVAL)
rc = param_set_int(val, kp);
if (rc) {
@@ -323,6 +351,9 @@
{
int rc = 0;
+ if (battery_removed)
+ return rc;
+
if (last_real_fcc_batt_temp == -EINVAL)
rc = param_set_int(val, kp);
if (rc) {
@@ -1552,33 +1583,6 @@
pr_debug("UUC = %uuAh\n", *unusable_charge_uah);
}
-static int calculate_real_fcc_uah(struct pm8921_bms_chip *chip,
- struct pm8921_soc_params *raw,
- int batt_temp, int chargecycles,
- int *ret_fcc_uah)
-{
- int fcc_uah, unusable_charge_uah;
- int remaining_charge_uah;
- int cc_uah;
- int real_fcc_uah;
- int rbatt;
- int iavg_ua;
-
- calculate_soc_params(chip, raw, batt_temp, chargecycles,
- &fcc_uah,
- &unusable_charge_uah,
- &remaining_charge_uah,
- &cc_uah,
- &rbatt,
- &iavg_ua);
-
- real_fcc_uah = remaining_charge_uah - cc_uah;
- *ret_fcc_uah = fcc_uah;
- pr_debug("real_fcc = %d, RC = %d CC = %d fcc = %d\n",
- real_fcc_uah, remaining_charge_uah, cc_uah, fcc_uah);
- return real_fcc_uah;
-}
-
int pm8921_bms_get_simultaneous_battery_voltage_and_current(int *ibat_ua,
int *vbat_uv)
{
@@ -2575,6 +2579,12 @@
/* store invalid soc */
pm8xxx_writeb(the_chip->dev->parent, TEMP_SOC_STORAGE, 0);
+ /* fcc learning cleanup */
+ if (the_chip->enable_fcc_learning) {
+ battery_removed = 1;
+ sysfs_notify(&the_chip->dev->kobj, NULL, "fcc_data");
+ }
+
/* UUC related data is left as is - use the same historical load avg */
update_power_supply(the_chip);
}
@@ -2598,6 +2608,14 @@
int calculate_soc = 0;
struct pm8921_bms_chip *chip = the_chip;
+ /* clean up the fcc learning table */
+ if (!the_chip)
+ the_chip->adjusted_fcc_temp_lut = NULL;
+ last_fcc_update_count = 0;
+ last_real_fcc_mah = -EINVAL;
+ last_real_fcc_batt_temp = -EINVAL;
+ battery_removed = 1;
+
pr_debug("Invalidating shutdown soc - the battery was removed\n");
if (shutdown_soc_invalid)
return;
@@ -2719,6 +2737,20 @@
return calculate_fcc_uah(the_chip, batt_temp, last_chargecycles);
}
EXPORT_SYMBOL_GPL(pm8921_bms_get_fcc);
+
+static void calculate_real_soc(struct pm8921_bms_chip *chip, int *soc,
+ int batt_temp, struct pm8921_soc_params *raw, int cc_uah)
+{
+ int fcc_uah = 0, rc_uah = 0;
+
+ fcc_uah = calculate_fcc_uah(chip, batt_temp, last_chargecycles);
+ rc_uah = calculate_remaining_charge_uah(chip, raw,
+ fcc_uah, batt_temp, last_chargecycles);
+ *soc = ((rc_uah - cc_uah) * 100) / fcc_uah;
+ pr_debug("fcc = %d, rc = %d, cc = %d Real SOC = %d\n",
+ fcc_uah, rc_uah, cc_uah, *soc);
+}
+
void pm8921_bms_charging_began(void)
{
struct pm8921_soc_params raw;
@@ -2742,12 +2774,123 @@
the_chip->soc_at_cv = -EINVAL;
the_chip->prev_chg_soc = -EINVAL;
+ if (the_chip->enable_fcc_learning) {
+ calculate_real_soc(the_chip, &the_chip->start_real_soc,
+ batt_temp, &raw, bms_start_cc_uah);
+ the_chip->pc_at_start_charge =
+ interpolate_pc(the_chip->pc_temp_ocv_lut, batt_temp,
+ bms_start_ocv_uv / 1000);
+ pr_debug("Start real soc = %d, start pc = %d\n",
+ the_chip->start_real_soc, the_chip->pc_at_start_charge);
+ }
+
pr_debug("start_percent = %u%%\n", the_chip->start_percent);
}
EXPORT_SYMBOL_GPL(pm8921_bms_charging_began);
-#define DELTA_FCC_PERCENT 3
-#define MIN_START_PERCENT_FOR_LEARNING 30
+static void invalidate_fcc(struct pm8921_bms_chip *chip)
+{
+ memset(chip->fcc_table, 0, chip->max_fcc_learning_samples *
+ sizeof(*(chip->fcc_table)));
+ last_fcc_update_count = 0;
+ chip->adjusted_fcc_temp_lut = NULL;
+ last_real_fcc_mah = -EINVAL;
+ last_real_fcc_batt_temp = -EINVAL;
+ last_chargecycles = 0;
+ last_charge_increase = 0;
+}
+
+static void update_fcc_table_for_temp(struct pm8921_bms_chip *chip,
+ int batt_temp_final)
+{
+ int i, fcc_t1, fcc_t2, fcc_final;
+ struct fcc_data *ft;
+
+ /* Interpolate all the FCC entries to the same temperature */
+ for (i = 0; i < chip->max_fcc_learning_samples; i++) {
+ ft = &chip->fcc_table[i];
+ if (ft->batt_temp == batt_temp_final)
+ continue;
+ fcc_t1 = interpolate_fcc(chip->fcc_temp_lut, ft->batt_temp);
+ fcc_t2 = interpolate_fcc(chip->fcc_temp_lut, batt_temp_final);
+ fcc_final = (ft->fcc_new / fcc_t1) * fcc_t2;
+ ft->fcc_new = fcc_final;
+ ft->batt_temp = batt_temp_final;
+ }
+}
+
+static void update_fcc_learning_table(struct pm8921_bms_chip *chip,
+ int fcc_uah, int new_fcc_uah, int chargecycles, int batt_temp)
+{
+ int i, temp_fcc_avg = 0, new_fcc_avg = 0, temp_fcc_delta = 0, count;
+ struct fcc_data *ft;
+
+ count = last_fcc_update_count % chip->max_fcc_learning_samples;
+ ft = &chip->fcc_table[count];
+ ft->fcc_new = ft->fcc_real = new_fcc_uah;
+ ft->batt_temp = ft->temp_real = batt_temp;
+ ft->chargecycles = chargecycles;
+ chip->fcc_new = new_fcc_uah;
+ last_fcc_update_count++;
+ /* update userspace with the new data */
+ sysfs_notify(&chip->dev->kobj, NULL, "fcc_data");
+
+ pr_debug("Updated fcc table. new_fcc=%d, chargecycle=%d, temp=%d fcc_update_count=%d\n",
+ new_fcc_uah, chargecycles, batt_temp, last_fcc_update_count);
+
+ if (last_fcc_update_count < chip->max_fcc_learning_samples) {
+ pr_debug("Not enough FCC samples. Current count = %d\n",
+ last_fcc_update_count);
+ return; /* Not enough samples to update fcc */
+ }
+
+ /* reject entries if they are > 50 chargecycles apart */
+ for (i = 0; i < chip->max_fcc_learning_samples; i++) {
+ if ((chip->fcc_table[i].chargecycles + VALID_FCC_CHGCYL_RANGE)
+ < chargecycles) {
+ pr_debug("Charge cycle too old (> %d cycles apart)\n",
+ VALID_FCC_CHGCYL_RANGE);
+ return; /* Samples old, > 50 cycles apart*/
+ }
+ }
+ /* update the fcc table for temperature difference*/
+ update_fcc_table_for_temp(chip, batt_temp);
+
+ /* Calculate the avg. and SD for all the fcc entries */
+ for (i = 0; i < chip->max_fcc_learning_samples; i++)
+ temp_fcc_avg += chip->fcc_table[i].fcc_new;
+
+ temp_fcc_avg /= chip->max_fcc_learning_samples;
+ temp_fcc_delta = div_u64(temp_fcc_avg * DELTA_FCC_PERCENT, 100);
+
+ /* fix the fcc if its an outlier i.e. > 5% of the average */
+ for (i = 0; i < chip->max_fcc_learning_samples; i++) {
+ ft = &chip->fcc_table[i];
+ if (abs(ft->fcc_new - temp_fcc_avg) > temp_fcc_delta)
+ ft->fcc_new = temp_fcc_avg;
+ new_fcc_avg += ft->fcc_new;
+ }
+ new_fcc_avg /= chip->max_fcc_learning_samples;
+
+ last_real_fcc_mah = new_fcc_avg/1000;
+ last_real_fcc_batt_temp = batt_temp;
+
+ pr_debug("FCC update: last_real_fcc_mah=%d, last_real_fcc_batt_temp=%d\n",
+ new_fcc_avg, batt_temp);
+ readjust_fcc_table();
+}
+
+static bool is_new_fcc_valid(int new_fcc_uah, int fcc_uah)
+{
+ /* reject the new fcc if < 50% and > 105% of nominal fcc */
+ if ((new_fcc_uah >= (fcc_uah / 2)) &&
+ ((new_fcc_uah * 100) <= (fcc_uah * 105)))
+ return true;
+
+ pr_debug("FCC rejected - not within valid limit\n");
+ return false;
+}
+
void pm8921_bms_charging_end(int is_battery_full)
{
int batt_temp;
@@ -2766,37 +2909,27 @@
bms_end_ocv_uv = raw.last_good_ocv_uv;
- if (is_battery_full && the_chip->enable_fcc_learning
- && the_chip->start_percent <= MIN_START_PERCENT_FOR_LEARNING) {
- int fcc_uah, new_fcc_uah, delta_fcc_uah;
+ pr_debug("battery_full = %d, fcc_learning = %d, pc_start_chg = %d\n",
+ is_battery_full, the_chip->enable_fcc_learning,
+ the_chip->pc_at_start_charge);
+ if (is_battery_full && the_chip->enable_fcc_learning &&
+ (the_chip->start_percent <= the_chip->min_fcc_learning_soc) &&
+ (the_chip->pc_at_start_charge <= the_chip->min_fcc_ocv_pc)) {
- new_fcc_uah = calculate_real_fcc_uah(the_chip, &raw,
- batt_temp, last_chargecycles,
- &fcc_uah);
- delta_fcc_uah = new_fcc_uah - fcc_uah;
- if (delta_fcc_uah < 0)
- delta_fcc_uah = -delta_fcc_uah;
+ int fcc_uah, new_fcc_uah, delta_cc_uah, delta_soc;
+ /* new_fcc = (cc_end - cc_start) / (end_soc - start_soc) */
+ delta_soc = 100 - the_chip->start_real_soc;
+ delta_cc_uah = abs(bms_end_cc_uah - bms_start_cc_uah);
+ new_fcc_uah = div_u64(delta_cc_uah * 100, delta_soc);
- if (delta_fcc_uah * 100 > (DELTA_FCC_PERCENT * fcc_uah)) {
- /* new_fcc_uah is outside the scope limit it */
- if (new_fcc_uah > fcc_uah)
- new_fcc_uah
- = (fcc_uah +
- (DELTA_FCC_PERCENT * fcc_uah) / 100);
- else
- new_fcc_uah
- = (fcc_uah -
- (DELTA_FCC_PERCENT * fcc_uah) / 100);
-
- pr_debug("delta_fcc=%d > %d percent of fcc=%d"
- "restring it to %d\n",
- delta_fcc_uah, DELTA_FCC_PERCENT,
- fcc_uah, new_fcc_uah);
- }
-
- last_real_fcc_mah = new_fcc_uah/1000;
- last_real_fcc_batt_temp = batt_temp;
- readjust_fcc_table();
+ fcc_uah = calculate_fcc_uah(the_chip, batt_temp,
+ last_chargecycles);
+ pr_info("start_real_soc = %d, end_real_soc = 100, start_cc = %d, end_cc = %d, nominal_fcc = %d, new_fcc = %d\n",
+ the_chip->start_real_soc, bms_start_cc_uah,
+ bms_end_cc_uah, fcc_uah, new_fcc_uah);
+ if (is_new_fcc_valid(new_fcc_uah, fcc_uah))
+ update_fcc_learning_table(the_chip, fcc_uah,
+ new_fcc_uah, last_chargecycles, batt_temp);
}
if (is_battery_full) {
@@ -3350,6 +3483,127 @@
}
}
+static ssize_t fcc_data_set(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct pm8921_bms_chip *chip = dev_get_drvdata(dev);
+ static int i;
+ int fcc_new = 0, rc;
+
+ if (battery_removed) {
+ pr_debug("Invalid FCC table. Possible battery removal\n");
+ last_fcc_update_count = 0;
+ return count;
+ }
+
+ i %= chip->max_fcc_learning_samples;
+ rc = sscanf(buf, "%d", &fcc_new);
+ if (rc != 1)
+ return -EINVAL;
+ chip->fcc_table[i].fcc_new = fcc_new;
+ chip->fcc_table[i].fcc_real = fcc_new;
+ pr_debug("Rcvd: [%d] fcc_new=%d\n", i, fcc_new);
+ i++;
+
+ return count;
+}
+
+static ssize_t fcc_data_get(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int count = 0;
+ struct pm8921_bms_chip *chip = dev_get_drvdata(dev);
+
+ if (battery_removed) {
+ pr_debug("Invalidate the fcc table\n");
+ invalidate_fcc(chip);
+ battery_removed = 0;
+ return count;
+ }
+
+ count = snprintf(buf, PAGE_SIZE, "%d", chip->fcc_new);
+
+ pr_debug("Sent: fcc_new=%d\n", chip->fcc_new);
+
+ return count;
+}
+
+static ssize_t fcc_temp_set(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ static int i;
+ int batt_temp = 0, rc;
+ struct pm8921_bms_chip *chip = dev_get_drvdata(dev);
+
+ i %= chip->max_fcc_learning_samples;
+ rc = sscanf(buf, "%d", &batt_temp);
+ if (rc != 1)
+ return -EINVAL;
+ chip->fcc_table[i].batt_temp = batt_temp;
+ chip->fcc_table[i].temp_real = batt_temp;
+ pr_debug("Rcvd: [%d] batt_temp=%d\n", i, batt_temp);
+ i++;
+
+ return count;
+}
+
+static ssize_t fcc_chgcyl_set(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ static int i;
+ int chargecycle = 0, rc;
+ struct pm8921_bms_chip *chip = dev_get_drvdata(dev);
+
+ i %= chip->max_fcc_learning_samples;
+ rc = sscanf(buf, "%d", &chargecycle);
+ if (rc != 1)
+ return -EINVAL;
+ chip->fcc_table[i].chargecycles = chargecycle;
+ pr_debug("Rcvd: [%d] chargecycle=%d\n", i, chargecycle);
+ i++;
+
+ return count;
+}
+
+static ssize_t fcc_list_get(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct pm8921_bms_chip *chip = dev_get_drvdata(dev);
+ struct fcc_data *ft;
+ int i = 0, j, count = 0;
+
+ if (last_fcc_update_count < chip->max_fcc_learning_samples)
+ i = last_fcc_update_count;
+ else
+ i = chip->max_fcc_learning_samples;
+
+ for (j = 0; j < i; j++) {
+ ft = &chip->fcc_table[j];
+ count += snprintf(buf + count, PAGE_SIZE - count,
+ "%d %d %d %d %d\n", ft->fcc_new, ft->chargecycles,
+ ft->batt_temp, ft->fcc_real, ft->temp_real);
+ }
+
+ return count;
+}
+
+static DEVICE_ATTR(fcc_data, 0664, fcc_data_get, fcc_data_set);
+static DEVICE_ATTR(fcc_temp, 0664, NULL, fcc_temp_set);
+static DEVICE_ATTR(fcc_chgcyl, 0664, NULL, fcc_chgcyl_set);
+static DEVICE_ATTR(fcc_list, 0664, fcc_list_get, NULL);
+
+static struct attribute *fcc_attrs[] = {
+ &dev_attr_fcc_data.attr,
+ &dev_attr_fcc_temp.attr,
+ &dev_attr_fcc_chgcyl.attr,
+ &dev_attr_fcc_list.attr,
+ NULL
+};
+
+static const struct attribute_group fcc_attr_group = {
+ .attrs = fcc_attrs,
+};
+
#define REG_SBI_CONFIG 0x04F
#define PAGE3_ENABLE_MASK 0x6
#define PROGRAM_REV_MASK 0x0F
@@ -3477,6 +3731,34 @@
chip->batt_id_channel = pdata->bms_cdata.batt_id_channel;
chip->revision = pm8xxx_get_revision(chip->dev->parent);
chip->enable_fcc_learning = pdata->enable_fcc_learning;
+ chip->min_fcc_learning_soc = pdata->min_fcc_learning_soc;
+ chip->min_fcc_ocv_pc = pdata->min_fcc_ocv_pc;
+ chip->max_fcc_learning_samples = pdata->max_fcc_learning_samples;
+ if (chip->enable_fcc_learning) {
+ if (!chip->min_fcc_learning_soc)
+ chip->min_fcc_learning_soc =
+ MIN_START_PERCENT_FOR_LEARNING;
+ if (!chip->min_fcc_ocv_pc)
+ chip->min_fcc_ocv_pc =
+ MIN_START_OCV_PERCENT_FOR_LEARNING;
+ if (!chip->max_fcc_learning_samples ||
+ chip->max_fcc_learning_samples > MAX_FCC_LEARNING_COUNT)
+ chip->max_fcc_learning_samples = MAX_FCC_LEARNING_COUNT;
+
+ max_fcc_cycles = chip->max_fcc_learning_samples;
+ chip->fcc_table = kzalloc(sizeof(struct fcc_data) *
+ chip->max_fcc_learning_samples, GFP_KERNEL);
+ if (!chip->fcc_table) {
+ pr_err("Unable to allocate table for fcc learning\n");
+ rc = -ENOMEM;
+ goto free_chip;
+ }
+ rc = sysfs_create_group(&pdev->dev.kobj, &fcc_attr_group);
+ if (rc) {
+ pr_err("Unable to create sysfs entries\n");
+ goto free_chip;
+ }
+ }
chip->disable_flat_portion_ocv = pdata->disable_flat_portion_ocv;
chip->ocv_dis_high_soc = pdata->ocv_dis_high_soc;
diff --git a/drivers/power/qpnp-bms.c b/drivers/power/qpnp-bms.c
index 03aa280..816aa4f 100644
--- a/drivers/power/qpnp-bms.c
+++ b/drivers/power/qpnp-bms.c
@@ -168,6 +168,7 @@
uint16_t ocv_reading_at_100;
uint16_t prev_last_good_ocv_raw;
int last_ocv_uv;
+ int charging_adjusted_ocv;
int last_ocv_temp;
int last_cc_uah;
unsigned long last_soc_change_sec;
@@ -1523,7 +1524,7 @@
soc = chip->last_soc + soc_change;
}
- if (chip->last_soc != soc)
+ if (chip->last_soc != soc && !chip->last_soc_unbound)
chip->last_soc_change_sec = last_change_sec;
pr_debug("last_soc = %d, calculated_soc = %d, soc = %d, time since last change = %d\n",
@@ -1610,9 +1611,8 @@
chip->prev_chg_soc = chg_soc;
find_ocv_for_soc(chip, params, batt_temp, chg_soc, &new_ocv_uv);
- chip->last_ocv_uv = new_ocv_uv;
- pr_debug("CC CHG ADJ OCV = %d CHG SOC %d\n",
- new_ocv_uv,
+ chip->charging_adjusted_ocv = new_ocv_uv;
+ pr_debug("CC CHG ADJ OCV = %d CHG SOC %d\n", new_ocv_uv,
chip->prev_chg_soc);
}
@@ -2286,7 +2286,13 @@
if (get_battery_status(chip) == POWER_SUPPLY_STATUS_FULL) {
chip->done_charging = true;
chip->last_soc_invalid = true;
+ } else if (chip->charging_adjusted_ocv > 0) {
+ pr_debug("Charging stopped before full, adjusted OCV = %d\n",
+ chip->charging_adjusted_ocv);
+ chip->last_ocv_uv = chip->charging_adjusted_ocv;
}
+ chip->charging_adjusted_ocv = -EINVAL;
+
mutex_unlock(&chip->last_ocv_uv_mutex);
}
@@ -3048,7 +3054,7 @@
{
int rc;
int soc_calc_period;
- int time_until_next_recalc;
+ int time_until_next_recalc = 0;
unsigned long time_since_last_recalc;
unsigned long tm_now_sec;
struct qpnp_bms_chip *chip = dev_get_drvdata(dev);
@@ -3056,26 +3062,24 @@
rc = get_current_time(&tm_now_sec);
if (rc) {
pr_err("Could not read current time: %d\n", rc);
- } else if (tm_now_sec > chip->last_recalc_time) {
- time_since_last_recalc = tm_now_sec - chip->last_recalc_time;
- pr_debug("Time since last recalc: %lu\n",
- time_since_last_recalc);
+ } else {
if (chip->calculated_soc < chip->low_soc_calc_threshold)
soc_calc_period = chip->low_soc_calculate_soc_ms;
else
soc_calc_period = chip->calculate_soc_ms;
-
+ time_since_last_recalc = tm_now_sec - chip->last_recalc_time;
+ pr_debug("Time since last recalc: %lu\n",
+ time_since_last_recalc);
time_until_next_recalc = max(0, soc_calc_period
- (int)(time_since_last_recalc * 1000));
-
- if (!wake_lock_active(&chip->soc_wake_lock)
- && time_until_next_recalc == 0)
- wake_lock(&chip->soc_wake_lock);
-
- schedule_delayed_work(&chip->calculate_soc_delayed_work,
- round_jiffies_relative(msecs_to_jiffies
- (time_until_next_recalc)));
}
+
+ if (!wake_lock_active(&chip->soc_wake_lock)
+ && time_until_next_recalc == 0)
+ wake_lock(&chip->soc_wake_lock);
+ schedule_delayed_work(&chip->calculate_soc_delayed_work,
+ round_jiffies_relative(msecs_to_jiffies
+ (time_until_next_recalc)));
return 0;
}
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index 352889d..9a53367 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -285,6 +285,8 @@
unsigned int safe_voltage_mv;
unsigned int max_voltage_mv;
unsigned int min_voltage_mv;
+ int set_vddmax_mv;
+ int delta_vddmax_mv;
unsigned int warm_bat_mv;
unsigned int cool_bat_mv;
unsigned int resume_delta_mv;
@@ -320,20 +322,24 @@
{}
};
-#define BPD_MAX 3
+enum bpd_type {
+ BPD_TYPE_BAT_ID,
+ BPD_TYPE_BAT_THM,
+ BPD_TYPE_BAT_THM_BAT_ID,
+};
-static const char *bpd_list[BPD_MAX] = {
- "bpd_thm",
- "bpd_id",
- "bpd_thm_id",
+static const char * const bpd_label[] = {
+ [BPD_TYPE_BAT_ID] = "bpd_id",
+ [BPD_TYPE_BAT_THM] = "bpd_thm",
+ [BPD_TYPE_BAT_THM_BAT_ID] = "bpd_thm_id",
};
static inline int
get_bpd(const char *name)
{
int i = 0;
- for (i = 0 ; i < BPD_MAX; i++) {
- if (strcmp(name, bpd_list[i]) == 0)
+ for (i = 0; i < ARRAY_SIZE(bpd_label); i++) {
+ if (strcmp(bpd_label[i], name) == 0)
return i;
}
return -EINVAL;
@@ -1497,10 +1503,11 @@
pr_err("bad mV=%d asked to set\n", voltage);
return -EINVAL;
}
+ chip->set_vddmax_mv = voltage + chip->delta_vddmax_mv;
- temp = (voltage - QPNP_CHG_V_MIN_MV) / QPNP_CHG_V_STEP_MV;
+ temp = (chip->set_vddmax_mv - QPNP_CHG_V_MIN_MV) / QPNP_CHG_V_STEP_MV;
- pr_debug("voltage=%d setting %02x\n", voltage, temp);
+ pr_debug("voltage=%d setting %02x\n", chip->set_vddmax_mv, temp);
return qpnp_chg_write(chip, &temp, chip->chgr_base + CHGR_VDD_MAX, 1);
}
@@ -1830,6 +1837,31 @@
.list_voltage = qpnp_chg_regulator_boost_list_voltage,
};
+#define MIN_DELTA_MV_TO_INCREASE_VDD_MAX 13
+#define MAX_DELTA_VDD_MAX_MV 30
+static void
+qpnp_chg_adjust_vddmax(struct qpnp_chg_chip *chip, int vbat_mv)
+{
+ int delta_mv, closest_delta_mv, sign;
+
+ delta_mv = chip->max_voltage_mv - vbat_mv;
+ if (delta_mv > 0 && delta_mv < MIN_DELTA_MV_TO_INCREASE_VDD_MAX) {
+ pr_debug("vbat is not low enough to increase vdd\n");
+ return;
+ }
+
+ sign = delta_mv > 0 ? 1 : -1;
+ closest_delta_mv = ((delta_mv + sign * QPNP_CHG_V_STEP_MV / 2)
+ / QPNP_CHG_V_STEP_MV) * QPNP_CHG_V_STEP_MV;
+ pr_debug("max_voltage = %d, vbat_mv = %d, delta_mv = %d, closest = %d\n",
+ chip->max_voltage_mv, vbat_mv,
+ delta_mv, closest_delta_mv);
+ chip->delta_vddmax_mv = clamp(chip->delta_vddmax_mv + closest_delta_mv,
+ -MAX_DELTA_VDD_MAX_MV, MAX_DELTA_VDD_MAX_MV);
+ pr_debug("using delta_vddmax_mv = %d\n", chip->delta_vddmax_mv);
+ qpnp_chg_set_appropriate_vddmax(chip);
+}
+
#define CONSECUTIVE_COUNT 3
static void
qpnp_eoc_work(struct work_struct *work)
@@ -1875,12 +1907,30 @@
|| chg_sts & TRKL_CHG_ON_IRQ)) {
ibat_ma = get_prop_current_now(chip) / 1000;
vbat_mv = get_prop_battery_voltage_now(chip) / 1000;
- pr_debug("ibat_ma: %d term_current =%d\n",
- ibat_ma, chip->term_current);
- if (ibat_ma > chip->term_current) {
- pr_debug("charging but increase in current demand\n");
+
+ pr_debug("ibat_ma = %d vbat_mv = %d term_current_ma = %d\n",
+ ibat_ma, vbat_mv, chip->term_current);
+
+ if ((!(chg_sts & VBAT_DET_LOW_IRQ)) && (vbat_mv <
+ (chip->max_voltage_mv - chip->resume_delta_mv))) {
+ pr_debug("woke up too early\n");
+ qpnp_chg_enable_irq(&chip->chg_vbatdet_lo);
+ goto stop_eoc;
+ }
+
+ if (buck_sts & VDD_LOOP_IRQ)
+ qpnp_chg_adjust_vddmax(chip, vbat_mv);
+
+ if (!(buck_sts & VDD_LOOP_IRQ)) {
+ pr_debug("Not in CV\n");
count = 0;
- } else if ((ibat_ma * -1) < chip->term_current) {
+ } else if ((ibat_ma * -1) > chip->term_current) {
+ pr_debug("Not at EOC, battery current too high\n");
+ count = 0;
+ } else if (ibat_ma > 0) {
+ pr_debug("Charging but system demand increased\n");
+ count = 0;
+ } else {
if (count == CONSECUTIVE_COUNT) {
pr_info("End of Charging\n");
qpnp_chg_charge_en(chip, 0);
@@ -1892,11 +1942,6 @@
count += 1;
pr_debug("EOC count = %d\n", count);
}
- } else if ((!(chg_sts & VBAT_DET_LOW_IRQ)) && (vbat_mv <
- (chip->max_voltage_mv - chip->resume_delta_mv))) {
- pr_debug("woke up too early\n");
- qpnp_chg_enable_irq(&chip->chg_vbatdet_lo);
- goto stop_eoc;
}
} else {
pr_debug("not charging\n");
@@ -2300,10 +2345,20 @@
case SMBBP_BAT_IF_SUBTYPE:
case SMBCL_BAT_IF_SUBTYPE:
/* Select battery presence detection */
- if (chip->bpd_detection == 1)
+ switch (chip->bpd_detection) {
+ case BPD_TYPE_BAT_THM:
+ reg = BAT_THM_EN;
+ break;
+ case BPD_TYPE_BAT_ID:
reg = BAT_ID_EN;
- else if (chip->bpd_detection == 2)
- reg = BAT_ID_EN | BAT_THM_EN;
+ break;
+ case BPD_TYPE_BAT_THM_BAT_ID:
+ reg = BAT_THM_EN | BAT_ID_EN;
+ break;
+ default:
+ reg = BAT_THM_EN;
+ break;
+ }
rc = qpnp_chg_masked_write(chip,
chip->bat_if_base + BAT_IF_BPD_CTRL,
@@ -2501,7 +2556,8 @@
rc = of_property_read_string(chip->spmi->dev.of_node,
"qcom,bpd-detection", &bpd);
if (rc) {
- pr_debug("no bpd-detection specified, ignored\n");
+ /* Select BAT_THM as default BPD scheme */
+ chip->bpd_detection = BPD_TYPE_BAT_THM;
} else {
chip->bpd_detection = get_bpd(bpd);
if (chip->bpd_detection < 0) {
@@ -2819,6 +2875,7 @@
qpnp_chg_charge_en(chip, !chip->charging_disabled);
qpnp_chg_force_run_on_batt(chip, chip->charging_disabled);
+ qpnp_chg_set_appropriate_vddmax(chip);
rc = qpnp_chg_request_irqs(chip);
if (rc) {
diff --git a/drivers/rtc/alarm-dev.c b/drivers/rtc/alarm-dev.c
index bfcaebc..1d60e97 100644
--- a/drivers/rtc/alarm-dev.c
+++ b/drivers/rtc/alarm-dev.c
@@ -98,6 +98,8 @@
wake_unlock(&alarm_wake_lock);
}
alarm_enabled &= ~alarm_type_mask;
+ if (alarm_type == ANDROID_ALARM_RTC_WAKEUP)
+ set_power_on_alarm(0);
spin_unlock_irqrestore(&alarm_slock, flags);
break;
@@ -125,6 +127,10 @@
alarm_start_range(&alarms[alarm_type],
timespec_to_ktime(new_alarm_time),
timespec_to_ktime(new_alarm_time));
+ if ((alarm_type == ANDROID_ALARM_RTC_WAKEUP) &&
+ (ANDROID_ALARM_BASE_CMD(cmd) ==
+ ANDROID_ALARM_SET(0)))
+ set_power_on_alarm(new_alarm_time.tv_sec);
spin_unlock_irqrestore(&alarm_slock, flags);
if (ANDROID_ALARM_BASE_CMD(cmd) != ANDROID_ALARM_SET_AND_WAIT(0)
&& cmd != ANDROID_ALARM_SET_AND_WAIT_OLD)
diff --git a/drivers/rtc/alarm.c b/drivers/rtc/alarm.c
index 9340af7..e318ecf 100644
--- a/drivers/rtc/alarm.c
+++ b/drivers/rtc/alarm.c
@@ -68,6 +68,13 @@
static struct platform_device *alarm_platform_dev;
struct alarm_queue alarms[ANDROID_ALARM_TYPE_COUNT];
static bool suspended;
+static long power_on_alarm;
+
+void set_power_on_alarm(long secs)
+{
+ power_on_alarm = secs;
+}
+
static void update_timer_locked(struct alarm_queue *base, bool head_removed)
{
@@ -486,6 +493,45 @@
return 0;
}
+static void alarm_shutdown(struct platform_device *dev)
+{
+ struct timespec wall_time;
+ struct rtc_time rtc_time;
+ struct rtc_wkalrm alarm;
+ unsigned long flags;
+ long rtc_secs, alarm_delta, alarm_time;
+ int rc;
+
+ spin_lock_irqsave(&alarm_slock, flags);
+
+ if (!power_on_alarm)
+ goto disable_alarm;
+
+ rtc_read_time(alarm_rtc_dev, &rtc_time);
+ getnstimeofday(&wall_time);
+ rtc_tm_to_time(&rtc_time, &rtc_secs);
+ alarm_delta = wall_time.tv_sec - rtc_secs;
+ alarm_time = power_on_alarm - alarm_delta;
+ if (alarm_time <= rtc_secs)
+ goto disable_alarm;
+
+ rtc_time_to_tm(alarm_time, &alarm.time);
+ alarm.enabled = 1;
+ rc = rtc_set_alarm(alarm_rtc_dev, &alarm);
+ if (rc)
+ pr_alarm(ERROR, "Unable to set power-on alarm\n");
+ else
+ pr_alarm(FLOW, "Power-on alarm set to %lu\n",
+ alarm_time);
+
+ spin_unlock_irqrestore(&alarm_slock, flags);
+ return;
+
+disable_alarm:
+ rtc_alarm_irq_enable(alarm_rtc_dev, 0);
+ spin_unlock_irqrestore(&alarm_slock, flags);
+}
+
static struct rtc_task alarm_rtc_task = {
.func = alarm_triggered_func
};
@@ -545,6 +591,7 @@
static struct platform_driver alarm_driver = {
.suspend = alarm_suspend,
.resume = alarm_resume,
+ .shutdown = alarm_shutdown,
.driver = {
.name = "alarm"
}
diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c
index c5aa7e5..18dd054 100644
--- a/drivers/spi/spi_qsd.c
+++ b/drivers/spi/spi_qsd.c
@@ -39,11 +39,16 @@
#include <linux/sched.h>
#include <linux/mutex.h>
#include <linux/atomic.h>
+#include <linux/pm_runtime.h>
#include <mach/msm_spi.h>
#include <mach/sps.h>
#include <mach/dma.h>
#include "spi_qsd.h"
+static int msm_spi_pm_resume_runtime(struct device *device);
+static int msm_spi_pm_suspend_runtime(struct device *device);
+
+
static inline int msm_spi_configure_gsbi(struct msm_spi *dd,
struct platform_device *pdev)
{
@@ -859,6 +864,10 @@
u32 op, ret = IRQ_NONE;
struct msm_spi *dd = dev_id;
+ if (pm_runtime_suspended(dd->dev)) {
+ dev_warn(dd->dev, "QUP: pm runtime suspend, irq:%d\n", irq);
+ return ret;
+ }
if (readl_relaxed(dd->base + SPI_ERROR_FLAGS) ||
readl_relaxed(dd->base + QUP_ERROR_FLAGS)) {
struct spi_master *master = dev_get_drvdata(dd->dev);
@@ -1705,36 +1714,22 @@
container_of(work, struct msm_spi, work_data);
unsigned long flags;
u32 status_error = 0;
- int rc = 0;
+
+ pm_runtime_get_sync(dd->dev);
mutex_lock(&dd->core_lock);
- /* Don't allow power collapse until we release mutex */
- if (pm_qos_request_active(&qos_req_list))
- pm_qos_update_request(&qos_req_list,
- dd->pm_lat);
+ /*
+ * Counter-part of system-suspend when runtime-pm is not enabled.
+ * This way, resume can be left empty and device will be put in
+ * active mode only if client requests anything on the bus
+ */
+ if (!pm_runtime_enabled(dd->dev))
+ msm_spi_pm_resume_runtime(dd->dev);
+
if (dd->use_rlock)
remote_mutex_lock(&dd->r_lock);
- /* Configure the spi clk, miso, mosi and cs gpio */
- if (dd->pdata->gpio_config) {
- rc = dd->pdata->gpio_config();
- if (rc) {
- dev_err(dd->dev,
- "%s: error configuring GPIOs\n",
- __func__);
- status_error = 1;
- }
- }
-
- rc = msm_spi_request_gpios(dd);
- if (rc)
- status_error = 1;
-
- clk_prepare_enable(dd->clk);
- clk_prepare_enable(dd->pclk);
- msm_spi_enable_irqs(dd);
-
if (!msm_spi_is_valid_state(dd)) {
dev_err(dd->dev, "%s: SPI operational state not valid\n",
__func__);
@@ -1742,6 +1737,7 @@
}
spin_lock_irqsave(&dd->queue_lock, flags);
+ dd->transfer_pending = 1;
while (!list_empty(&dd->queue)) {
dd->cur_msg = list_entry(dd->queue.next,
struct spi_message, queue);
@@ -1758,24 +1754,14 @@
dd->transfer_pending = 0;
spin_unlock_irqrestore(&dd->queue_lock, flags);
- msm_spi_disable_irqs(dd);
- clk_disable_unprepare(dd->clk);
- clk_disable_unprepare(dd->pclk);
-
- /* Free the spi clk, miso, mosi, cs gpio */
- if (!rc && dd->pdata && dd->pdata->gpio_release)
- dd->pdata->gpio_release();
- if (!rc)
- msm_spi_free_gpios(dd);
-
if (dd->use_rlock)
remote_mutex_unlock(&dd->r_lock);
- if (pm_qos_request_active(&qos_req_list))
- pm_qos_update_request(&qos_req_list,
- PM_QOS_DEFAULT_VALUE);
-
mutex_unlock(&dd->core_lock);
+
+ pm_runtime_mark_last_busy(dd->dev);
+ pm_runtime_put_autosuspend(dd->dev);
+
/* If needed, this can be done after the current message is complete,
and work can be continued upon resume. No motivation for now. */
if (dd->suspended)
@@ -1789,8 +1775,6 @@
struct spi_transfer *tr;
dd = spi_master_get_devdata(spi->master);
- if (dd->suspended)
- return -EBUSY;
if (list_empty(&msg->transfers) || !msg->complete)
return -EINVAL;
@@ -1810,11 +1794,6 @@
}
spin_lock_irqsave(&dd->queue_lock, flags);
- if (dd->suspended) {
- spin_unlock_irqrestore(&dd->queue_lock, flags);
- return -EBUSY;
- }
- dd->transfer_pending = 1;
list_add_tail(&msg->queue, &dd->queue);
spin_unlock_irqrestore(&dd->queue_lock, flags);
queue_work(dd->workqueue, &dd->work_data);
@@ -1845,7 +1824,14 @@
dd = spi_master_get_devdata(spi->master);
+ pm_runtime_get_sync(dd->dev);
+
mutex_lock(&dd->core_lock);
+
+ /* Counter-part of system-suspend when runtime-pm is not enabled. */
+ if (!pm_runtime_enabled(dd->dev))
+ msm_spi_pm_resume_runtime(dd->dev);
+
if (dd->suspended) {
mutex_unlock(&dd->core_lock);
return -EBUSY;
@@ -1854,27 +1840,6 @@
if (dd->use_rlock)
remote_mutex_lock(&dd->r_lock);
- /* Configure the spi clk, miso, mosi, cs gpio */
- if (dd->pdata->gpio_config) {
- rc = dd->pdata->gpio_config();
- if (rc) {
- dev_err(&spi->dev,
- "%s: error configuring GPIOs\n",
- __func__);
- rc = -ENXIO;
- goto err_setup_gpio;
- }
- }
-
- rc = msm_spi_request_gpios(dd);
- if (rc) {
- rc = -ENXIO;
- goto err_setup_gpio;
- }
-
- clk_prepare_enable(dd->clk);
- clk_prepare_enable(dd->pclk);
-
spi_ioc = readl_relaxed(dd->base + SPI_IO_CONTROL);
mask = SPI_IO_C_CS_N_POLARITY_0 << spi->chip_select;
if (spi->mode & SPI_CS_HIGH)
@@ -1892,18 +1857,19 @@
/* Ensure previous write completed before disabling the clocks */
mb();
- clk_disable_unprepare(dd->clk);
- clk_disable_unprepare(dd->pclk);
- /* Free the spi clk, miso, mosi, cs gpio */
- if (dd->pdata && dd->pdata->gpio_release)
- dd->pdata->gpio_release();
- msm_spi_free_gpios(dd);
-
-err_setup_gpio:
if (dd->use_rlock)
remote_mutex_unlock(&dd->r_lock);
+
+ /* Counter-part of system-resume when runtime-pm is not enabled. */
+ if (!pm_runtime_enabled(dd->dev))
+ msm_spi_pm_suspend_runtime(dd->dev);
+
mutex_unlock(&dd->core_lock);
+
+ pm_runtime_mark_last_busy(dd->dev);
+ pm_runtime_put_autosuspend(dd->dev);
+
err_setup_exit:
return rc;
}
@@ -2729,7 +2695,7 @@
clk_enabled = 0;
pclk_enabled = 0;
- dd->suspended = 0;
+ dd->suspended = 1;
dd->transfer_pending = 0;
dd->multi_xfr = 0;
dd->mode = SPI_MODE_NONE;
@@ -2745,6 +2711,10 @@
mutex_unlock(&dd->core_lock);
locked = 0;
+ pm_runtime_set_autosuspend_delay(&pdev->dev, MSEC_PER_SEC);
+ pm_runtime_use_autosuspend(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+
rc = spi_register_master(master);
if (rc)
goto err_probe_reg_master;
@@ -2762,6 +2732,7 @@
err_attrs:
spi_unregister_master(master);
err_probe_reg_master:
+ pm_runtime_disable(&pdev->dev);
err_probe_irq:
err_probe_state:
if (dd->dma_teardown)
@@ -2795,48 +2766,130 @@
}
#ifdef CONFIG_PM
-static int msm_spi_suspend(struct platform_device *pdev, pm_message_t state)
+static int msm_spi_pm_suspend_runtime(struct device *device)
{
+ struct platform_device *pdev = to_platform_device(device);
struct spi_master *master = platform_get_drvdata(pdev);
- struct msm_spi *dd;
- unsigned long flags;
+ struct msm_spi *dd;
+ unsigned long flags;
+ dev_dbg(device, "pm_runtime: suspending...\n");
if (!master)
goto suspend_exit;
dd = spi_master_get_devdata(master);
if (!dd)
goto suspend_exit;
- /* Make sure nothing is added to the queue while we're suspending */
+ if (dd->suspended)
+ return 0;
+
+ /*
+ * Make sure nothing is added to the queue while we're
+ * suspending
+ */
spin_lock_irqsave(&dd->queue_lock, flags);
dd->suspended = 1;
spin_unlock_irqrestore(&dd->queue_lock, flags);
/* Wait for transactions to end, or time out */
- wait_event_interruptible(dd->continue_suspend, !dd->transfer_pending);
+ wait_event_interruptible(dd->continue_suspend,
+ !dd->transfer_pending);
+ msm_spi_disable_irqs(dd);
+ clk_disable_unprepare(dd->clk);
+ clk_disable_unprepare(dd->pclk);
+
+ /* Free the spi clk, miso, mosi, cs gpio */
+ if (dd->pdata && dd->pdata->gpio_release)
+ dd->pdata->gpio_release();
+
+ msm_spi_free_gpios(dd);
+
+ if (pm_qos_request_active(&qos_req_list))
+ pm_qos_update_request(&qos_req_list,
+ PM_QOS_DEFAULT_VALUE);
suspend_exit:
return 0;
}
-static int msm_spi_resume(struct platform_device *pdev)
+static int msm_spi_pm_resume_runtime(struct device *device)
{
+ struct platform_device *pdev = to_platform_device(device);
struct spi_master *master = platform_get_drvdata(pdev);
- struct msm_spi *dd;
+ struct msm_spi *dd;
+ int ret = 0;
+ dev_dbg(device, "pm_runtime: resuming...\n");
if (!master)
goto resume_exit;
dd = spi_master_get_devdata(master);
if (!dd)
goto resume_exit;
+ if (!dd->suspended)
+ return 0;
+
+ if (pm_qos_request_active(&qos_req_list))
+ pm_qos_update_request(&qos_req_list,
+ dd->pm_lat);
+
+ /* Configure the spi clk, miso, mosi and cs gpio */
+ if (dd->pdata->gpio_config) {
+ ret = dd->pdata->gpio_config();
+ if (ret) {
+ dev_err(dd->dev,
+ "%s: error configuring GPIOs\n",
+ __func__);
+ return ret;
+ }
+ }
+
+ ret = msm_spi_request_gpios(dd);
+ if (ret)
+ return ret;
+
+ clk_prepare_enable(dd->clk);
+ clk_prepare_enable(dd->pclk);
+ msm_spi_enable_irqs(dd);
dd->suspended = 0;
resume_exit:
return 0;
}
+
+static int msm_spi_suspend(struct device *device)
+{
+ if (!pm_runtime_enabled(device) || !pm_runtime_suspended(device)) {
+ struct platform_device *pdev = to_platform_device(device);
+ struct spi_master *master = platform_get_drvdata(pdev);
+ struct msm_spi *dd;
+
+ dev_dbg(device, "system suspend");
+ if (!master)
+ goto suspend_exit;
+ dd = spi_master_get_devdata(master);
+ if (!dd)
+ goto suspend_exit;
+ msm_spi_pm_suspend_runtime(device);
+ }
+suspend_exit:
+ return 0;
+}
+
+static int msm_spi_resume(struct device *device)
+{
+ /*
+ * Rely on runtime-PM to call resume in case it is enabled
+ * Even if it's not enabled, rely on 1st client transaction to do
+ * clock ON and gpio configuration
+ */
+ dev_dbg(device, "system resume");
+ return 0;
+}
#else
#define msm_spi_suspend NULL
#define msm_spi_resume NULL
+#define msm_spi_pm_suspend_runtime NULL
+#define msm_spi_pm_resume_runtime NULL
#endif /* CONFIG_PM */
static int __devexit msm_spi_remove(struct platform_device *pdev)
@@ -2850,6 +2903,8 @@
if (dd->dma_teardown)
dd->dma_teardown(dd);
+ pm_runtime_disable(&pdev->dev);
+ pm_runtime_set_suspended(&pdev->dev);
clk_put(dd->clk);
clk_put(dd->pclk);
destroy_workqueue(dd->workqueue);
@@ -2867,14 +2922,19 @@
{}
};
+static const struct dev_pm_ops msm_spi_dev_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(msm_spi_suspend, msm_spi_resume)
+ SET_RUNTIME_PM_OPS(msm_spi_pm_suspend_runtime,
+ msm_spi_pm_resume_runtime, NULL)
+};
+
static struct platform_driver msm_spi_driver = {
.driver = {
.name = SPI_DRV_NAME,
.owner = THIS_MODULE,
+ .pm = &msm_spi_dev_pm_ops,
.of_match_table = msm_spi_dt_match,
},
- .suspend = msm_spi_suspend,
- .resume = msm_spi_resume,
.remove = __exit_p(msm_spi_remove),
};
diff --git a/drivers/spmi/spmi-dbgfs.c b/drivers/spmi/spmi-dbgfs.c
index b825ade..27df09333 100644
--- a/drivers/spmi/spmi-dbgfs.c
+++ b/drivers/spmi/spmi-dbgfs.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -24,7 +24,6 @@
* /spmi-#
*/
-#define DEBUG
#define pr_fmt(fmt) "%s:%d: " fmt, __func__, __LINE__
#include <linux/kernel.h>
@@ -582,7 +581,7 @@
{
struct dentry *root, *file;
- pr_debug("Creating SPMI debugfs file-system at\n");
+ pr_debug("Creating SPMI debugfs file-system\n");
root = debugfs_create_dir(DFS_ROOT_NAME, NULL);
if (IS_ERR(root)) {
pr_err("Error creating top level directory err:%ld",
@@ -697,6 +696,41 @@
}
/*
+ * spmi_dfs_del_controller: deletes spmi controller entry
+ * @return zero on success
+ */
+int spmi_dfs_del_controller(struct spmi_controller *ctrl)
+{
+ int rc;
+ struct list_head *pos, *tmp;
+ struct spmi_ctrl_data *ctrl_data;
+
+ pr_debug("Deleting controller %s\n", ctrl->dev.kobj.name);
+
+ rc = mutex_lock_interruptible(&dbgfs_data.lock);
+ if (rc)
+ return rc;
+
+ list_for_each_safe(pos, tmp, &dbgfs_data.ctrl) {
+ ctrl_data = list_entry(pos, struct spmi_ctrl_data, node);
+
+ if (ctrl_data->ctrl == ctrl) {
+ debugfs_remove_recursive(ctrl_data->dir);
+ list_del(pos);
+ kfree(ctrl_data);
+ rc = 0;
+ goto done;
+ }
+ }
+ rc = -EINVAL;
+ pr_debug("Unknown controller %s\n", ctrl->dev.kobj.name);
+
+done:
+ mutex_unlock(&dbgfs_data.lock);
+ return rc;
+}
+
+/*
* spmi_dfs_create_file: creates a new file in the SPMI debugfs
* @returns valid dentry pointer on success or NULL
*/
diff --git a/drivers/spmi/spmi-dbgfs.h b/drivers/spmi/spmi-dbgfs.h
index 2a0d815..10e98b9 100644
--- a/drivers/spmi/spmi-dbgfs.h
+++ b/drivers/spmi/spmi-dbgfs.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -16,8 +16,10 @@
#ifdef CONFIG_DEBUG_FS
int spmi_dfs_add_controller(struct spmi_controller *ctrl);
+int spmi_dfs_del_controller(struct spmi_controller *ctrl);
#else
static int spmi_dfs_add_controller(struct spmi_controller *ctrl) { return 0; }
+static int spmi_dfs_del_controller(struct spmi_controller *ctrl) { return 0; }
#endif
struct dentry *spmi_dfs_create_file(struct spmi_controller *ctrl,
diff --git a/drivers/spmi/spmi.c b/drivers/spmi/spmi.c
index 49a27c7..fc21fbb 100644
--- a/drivers/spmi/spmi.c
+++ b/drivers/spmi/spmi.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -31,11 +31,9 @@
static DEFINE_MUTEX(board_lock);
static LIST_HEAD(board_list);
-static LIST_HEAD(spmi_ctrl_list);
static DEFINE_IDR(ctrl_idr);
-static struct device_type spmi_ctrl_type = { 0 };
-
-#define to_spmi(dev) platform_get_drvdata(to_platform_device(dev))
+static struct device_type spmi_dev_type;
+static struct device_type spmi_ctrl_type;
/* Forward declarations */
struct bus_type spmi_bus_type;
@@ -51,14 +49,10 @@
struct spmi_controller *ctrl;
mutex_lock(&board_lock);
- list_for_each_entry(ctrl, &spmi_ctrl_list, list) {
- if (bus_num == ctrl->nr) {
- mutex_unlock(&board_lock);
- return ctrl;
- }
- }
+ ctrl = idr_find(&ctrl_idr, bus_num);
mutex_unlock(&board_lock);
- return NULL;
+
+ return ctrl;
}
EXPORT_SYMBOL_GPL(spmi_busnum_to_ctrl);
@@ -74,6 +68,9 @@
int id;
int status;
+ if (!ctrl)
+ return -EINVAL;
+
pr_debug("adding controller for bus %d (0x%p)\n", ctrl->nr, ctrl);
if (ctrl->nr & ~MAX_ID_MASK) {
@@ -90,7 +87,7 @@
mutex_lock(&board_lock);
status = idr_get_new_above(&ctrl_idr, ctrl, ctrl->nr, &id);
if (status == 0 && id != ctrl->nr) {
- status = -EAGAIN;
+ status = -EBUSY;
idr_remove(&ctrl_idr, id);
}
mutex_unlock(&board_lock);
@@ -103,18 +100,70 @@
}
EXPORT_SYMBOL_GPL(spmi_add_controller);
+/* Remove a device associated with a controller */
+static int spmi_ctrl_remove_device(struct device *dev, void *data)
+{
+ struct spmi_device *spmidev = to_spmi_device(dev);
+ struct spmi_controller *ctrl = data;
+
+ if (dev->type == &spmi_dev_type && spmidev->ctrl == ctrl)
+ spmi_remove_device(spmidev);
+
+ return 0;
+}
+
/**
* spmi_del_controller: Controller tear-down.
- * @ctrl: controller to which this device is to be added to.
+ * @ctrl: controller to be removed.
*
* Controller added with the above API is torn down using this API.
*/
int spmi_del_controller(struct spmi_controller *ctrl)
{
- return -ENXIO;
+ struct spmi_controller *found;
+
+ if (!ctrl)
+ return -EINVAL;
+
+ /* Check that the ctrl has been added */
+ mutex_lock(&board_lock);
+ found = idr_find(&ctrl_idr, ctrl->nr);
+ mutex_unlock(&board_lock);
+ if (found != ctrl)
+ return -EINVAL;
+
+ /* Remove all the clients associated with this controller */
+ mutex_lock(&board_lock);
+ bus_for_each_dev(&spmi_bus_type, NULL, ctrl, spmi_ctrl_remove_device);
+ mutex_unlock(&board_lock);
+
+ spmi_dfs_del_controller(ctrl);
+
+ mutex_lock(&board_lock);
+ idr_remove(&ctrl_idr, ctrl->nr);
+ mutex_unlock(&board_lock);
+
+ init_completion(&ctrl->dev_released);
+ device_unregister(&ctrl->dev);
+ wait_for_completion(&ctrl->dev_released);
+
+ return 0;
}
EXPORT_SYMBOL_GPL(spmi_del_controller);
+#define spmi_ctrl_attr_gr NULL
+static void spmi_ctrl_release(struct device *dev)
+{
+ struct spmi_controller *ctrl = to_spmi_controller(dev);
+
+ complete(&ctrl->dev_released);
+}
+
+static struct device_type spmi_ctrl_type = {
+ .groups = spmi_ctrl_attr_gr,
+ .release = spmi_ctrl_release,
+};
+
#define spmi_device_attr_gr NULL
#define spmi_device_uevent NULL
static void spmi_dev_release(struct device *dev)
@@ -146,7 +195,7 @@
{
struct spmi_device *spmidev;
- if (!ctrl) {
+ if (!ctrl || !spmi_busnum_to_ctrl(ctrl->nr)) {
pr_err("Missing SPMI controller\n");
return NULL;
}
@@ -179,12 +228,15 @@
if (dev->bus != &spmi_bus_type || dev->type != &spmi_dev_type)
return NULL;
+ if (!spmidev->ctrl || !spmi_busnum_to_ctrl(spmidev->ctrl->nr))
+ return NULL;
+
return dev;
}
/**
* spmi_add_device: Add a new device without register board info.
- * @ctrl: controller to which this device is to be added to.
+ * @spmi_dev: spmi_device to be added (registered).
*
* Called when device doesn't have an explicit client-driver to be probed, or
* the client-driver is a module installed dynamically.
@@ -195,7 +247,7 @@
struct device *dev = get_valid_device(spmidev);
if (!dev) {
- pr_err("%s: invalid SPMI device\n", __func__);
+ pr_err("invalid SPMI device\n");
return -EINVAL;
}
@@ -259,7 +311,6 @@
}
EXPORT_SYMBOL_GPL(spmi_remove_device);
-/* If controller is not present, only add to boards list */
static void spmi_match_ctrl_to_boardinfo(struct spmi_controller *ctrl,
struct spmi_boardinfo *bi)
{
@@ -278,27 +329,29 @@
* @n: number of entries.
* API enumerates respective devices on corresponding controller.
* Called from board-init function.
+ * If controller is not present, only add to boards list
*/
int spmi_register_board_info(int busnum,
struct spmi_boardinfo const *info, unsigned n)
{
int i;
struct spmii_boardinfo *bi;
+ struct spmi_controller *ctrl;
bi = kzalloc(n * sizeof(*bi), GFP_KERNEL);
if (!bi)
return -ENOMEM;
+ ctrl = spmi_busnum_to_ctrl(busnum);
+
for (i = 0; i < n; i++, bi++, info++) {
- struct spmi_controller *ctrl;
memcpy(&bi->board_info, info, sizeof(*info));
mutex_lock(&board_lock);
list_add_tail(&bi->list, &board_list);
- list_for_each_entry(ctrl, &spmi_ctrl_list, list)
- if (ctrl->nr == busnum)
- spmi_match_ctrl_to_boardinfo(ctrl,
- &bi->board_info);
+
+ if (ctrl)
+ spmi_match_ctrl_to_boardinfo(ctrl, &bi->board_info);
mutex_unlock(&board_lock);
}
return 0;
@@ -753,10 +806,6 @@
dev_dbg(&ctrl->dev, "Bus spmi-%d registered: dev:%x\n",
ctrl->nr, (u32)&ctrl->dev);
- mutex_lock(&board_lock);
- list_add_tail(&ctrl->list, &spmi_ctrl_list);
- mutex_unlock(&board_lock);
-
spmi_dfs_add_controller(ctrl);
return 0;
diff --git a/drivers/staging/android/logger.c b/drivers/staging/android/logger.c
index eb3d4ca..e1e886c 100644
--- a/drivers/staging/android/logger.c
+++ b/drivers/staging/android/logger.c
@@ -728,10 +728,10 @@
.size = SIZE, \
};
-DEFINE_LOGGER_DEVICE(log_main, LOGGER_LOG_MAIN, 256*1024)
-DEFINE_LOGGER_DEVICE(log_events, LOGGER_LOG_EVENTS, 256*1024)
-DEFINE_LOGGER_DEVICE(log_radio, LOGGER_LOG_RADIO, 256*1024)
-DEFINE_LOGGER_DEVICE(log_system, LOGGER_LOG_SYSTEM, 256*1024)
+DEFINE_LOGGER_DEVICE(log_main, LOGGER_LOG_MAIN, 64*1024)
+DEFINE_LOGGER_DEVICE(log_events, LOGGER_LOG_EVENTS, 64*1024)
+DEFINE_LOGGER_DEVICE(log_radio, LOGGER_LOG_RADIO, 64*1024)
+DEFINE_LOGGER_DEVICE(log_system, LOGGER_LOG_SYSTEM, 64*1024)
static struct logger_log *get_log_from_minor(int minor)
{
diff --git a/drivers/thermal/msm_thermal.c b/drivers/thermal/msm_thermal.c
index ab59864..51a11a4 100644
--- a/drivers/thermal/msm_thermal.c
+++ b/drivers/thermal/msm_thermal.c
@@ -1435,6 +1435,8 @@
char *key = NULL;
struct device_node *child_node = NULL;
+ rails = NULL;
+
key = "qcom,vdd-restriction-temp";
ret = of_property_read_u32(node, key, &data->vdd_rstr_temp_degC);
if (ret)
@@ -1531,6 +1533,8 @@
int j = 0;
char *key = NULL;
+ psm_rails = NULL;
+
key = "qcom,pmic-sw-mode-temp";
ret = of_property_read_u32(node, key, &data->psm_temp_degC);
if (ret)
diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c
index 890a897..4d464c1 100644
--- a/drivers/tty/serial/msm_serial_hs.c
+++ b/drivers/tty/serial/msm_serial_hs.c
@@ -1974,7 +1974,8 @@
switch (msm_uport->clk_state) {
case MSM_HS_CLK_OFF:
wake_lock(&msm_uport->dma_wake_lock);
- disable_irq_nosync(msm_uport->wakeup.irq);
+ if (use_low_power_wakeup(msm_uport))
+ disable_irq_nosync(msm_uport->wakeup.irq);
spin_unlock_irqrestore(&uport->lock, flags);
/* Vote for PNOC BUS Scaling */
@@ -2348,7 +2349,8 @@
free_uart_irq:
free_irq(uport->irq, msm_uport);
free_wake_irq:
- irq_set_irq_wake(msm_uport->wakeup.irq, 0);
+ if (use_low_power_wakeup(msm_uport))
+ irq_set_irq_wake(msm_uport->wakeup.irq, 0);
sps_disconnect_rx:
if (is_blsp_uart(msm_uport))
sps_disconnect(sps_pipe_handle_rx);
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index fab5219..04da6f8 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -241,7 +241,13 @@
for (i = 0; i < num; i++) {
struct dwc3_event_buffer *evt;
- evt = dwc3_alloc_one_event_buffer(dwc, length);
+ /*
+ * As SW workaround, allocate 8 bytes more than size of event
+ * buffer given to USB Controller to avoid possible memory
+ * corruption caused by event buffer overflow when Hw writes
+ * Vendor Device test event which could be of 12 bytes.
+ */
+ evt = dwc3_alloc_one_event_buffer(dwc, (length + 8));
if (IS_ERR(evt)) {
dev_err(dwc->dev, "can't allocate event buffer\n");
return PTR_ERR(evt);
@@ -276,7 +282,7 @@
dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n),
upper_32_bits(evt->dma));
dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n),
- evt->length & 0xffff);
+ (evt->length - 8) & 0xffff);
dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0);
}
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index bc1fa07..36a43c3 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -91,6 +91,7 @@
#include "u_uac1.c"
#include "f_uac1.c"
#endif
+#include "f_ncm.c"
MODULE_AUTHOR("Mike Lockwood");
MODULE_DESCRIPTION("Android Composite USB Driver");
@@ -524,7 +525,7 @@
data->opened = false;
- if (data->enabled)
+ if (data->enabled && dev)
android_disable(dev);
data->dev = NULL;
@@ -792,7 +793,103 @@
.bind_config = gps_function_bind_config,
};
+/* ncm */
+struct ncm_function_config {
+ u8 ethaddr[ETH_ALEN];
+};
+static int
+ncm_function_init(struct android_usb_function *f, struct usb_composite_dev *c)
+{
+ f->config = kzalloc(sizeof(struct ncm_function_config), GFP_KERNEL);
+ if (!f->config)
+ return -ENOMEM;
+ return 0;
+}
+
+static void ncm_function_cleanup(struct android_usb_function *f)
+{
+ kfree(f->config);
+ f->config = NULL;
+}
+
+static int
+ncm_function_bind_config(struct android_usb_function *f,
+ struct usb_configuration *c)
+{
+ struct ncm_function_config *ncm = f->config;
+ int ret;
+
+ if (!ncm) {
+ pr_err("%s: ncm config is null\n", __func__);
+ return -EINVAL;
+ }
+
+ pr_info("%s MAC: %02X:%02X:%02X:%02X:%02X:%02X\n", __func__,
+ ncm->ethaddr[0], ncm->ethaddr[1], ncm->ethaddr[2],
+ ncm->ethaddr[3], ncm->ethaddr[4], ncm->ethaddr[5]);
+
+ ret = gether_setup_name(c->cdev->gadget, ncm->ethaddr, "ncm");
+ if (ret) {
+ pr_err("%s: gether setup failed err:%d\n", __func__, ret);
+ return ret;
+ }
+
+ ret = ncm_bind_config(c, ncm->ethaddr);
+ if (ret) {
+ pr_err("%s: ncm bind config failed err:%d", __func__, ret);
+ gether_cleanup();
+ return ret;
+ }
+
+ return ret;
+}
+
+static void ncm_function_unbind_config(struct android_usb_function *f,
+ struct usb_configuration *c)
+{
+ gether_cleanup();
+}
+
+static ssize_t ncm_ethaddr_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct android_usb_function *f = dev_get_drvdata(dev);
+ struct ncm_function_config *ncm = f->config;
+ return snprintf(buf, PAGE_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x\n",
+ ncm->ethaddr[0], ncm->ethaddr[1], ncm->ethaddr[2],
+ ncm->ethaddr[3], ncm->ethaddr[4], ncm->ethaddr[5]);
+}
+
+static ssize_t ncm_ethaddr_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ struct android_usb_function *f = dev_get_drvdata(dev);
+ struct ncm_function_config *ncm = f->config;
+
+ if (sscanf(buf, "%02x:%02x:%02x:%02x:%02x:%02x\n",
+ (int *)&ncm->ethaddr[0], (int *)&ncm->ethaddr[1],
+ (int *)&ncm->ethaddr[2], (int *)&ncm->ethaddr[3],
+ (int *)&ncm->ethaddr[4], (int *)&ncm->ethaddr[5]) == 6)
+ return size;
+ return -EINVAL;
+}
+
+static DEVICE_ATTR(ncm_ethaddr, S_IRUGO | S_IWUSR, ncm_ethaddr_show,
+ ncm_ethaddr_store);
+static struct device_attribute *ncm_function_attributes[] = {
+ &dev_attr_ncm_ethaddr,
+ NULL
+};
+
+static struct android_usb_function ncm_function = {
+ .name = "ncm",
+ .init = ncm_function_init,
+ .cleanup = ncm_function_cleanup,
+ .bind_config = ncm_function_bind_config,
+ .unbind_config = ncm_function_unbind_config,
+ .attributes = ncm_function_attributes,
+};
/* ecm transport string */
static char ecm_transports[MAX_XPORT_STR_LEN];
@@ -1857,6 +1954,7 @@
&rndis_function,
&rndis_qc_function,
&ecm_function,
+ &ncm_function,
&mass_storage_function,
&accessory_function,
#ifdef CONFIG_SND_PCM
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index af82656..a258c30 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -3281,7 +3281,13 @@
del_timer(&mEp->prime_timer);
mEp->prime_timer_count = 0;
dbg_event(_usb_addr(mEp), "FFLUSH", 0);
- hw_ep_flush(mEp->num, mEp->dir);
+ /*
+ * _ep_nuke() takes care of flushing the endpoint.
+ * some function drivers expect udc to retire all
+ * pending requests upon flushing an endpoint. There
+ * is no harm in doing it.
+ */
+ _ep_nuke(mEp);
spin_unlock_irqrestore(mEp->lock, flags);
}
diff --git a/drivers/usb/gadget/f_mbim.c b/drivers/usb/gadget/f_mbim.c
index e48f94c..aaacd43 100644
--- a/drivers/usb/gadget/f_mbim.c
+++ b/drivers/usb/gadget/f_mbim.c
@@ -63,10 +63,10 @@
};
enum mbim_notify_state {
- NCM_NOTIFY_NONE,
- NCM_NOTIFY_CONNECT,
- NCM_NOTIFY_SPEED,
- NCM_NOTIFY_RESPONSE_AVAILABLE,
+ MBIM_NOTIFY_NONE,
+ MBIM_NOTIFY_CONNECT,
+ MBIM_NOTIFY_SPEED,
+ MBIM_NOTIFY_RESPONSE_AVAILABLE,
};
struct f_mbim {
@@ -95,7 +95,7 @@
u8 ctrl_id, data_id;
u8 data_alt_int;
- struct ndp_parser_opts *parser_opts;
+ struct mbim_ndp_parser_opts *parser_opts;
spinlock_t lock;
@@ -140,24 +140,24 @@
/*-------------------------------------------------------------------------*/
-#define NTB_DEFAULT_IN_SIZE (0x4000)
-#define NTB_OUT_SIZE (0x1000)
-#define NDP_IN_DIVISOR (0x4)
+#define MBIM_NTB_DEFAULT_IN_SIZE (0x4000)
+#define MBIM_NTB_OUT_SIZE (0x1000)
+#define MBIM_NDP_IN_DIVISOR (0x4)
#define NTB_DEFAULT_IN_SIZE_IPA (0x2000)
-#define NTB_OUT_SIZE_IPA (0x2000)
+#define MBIM_NTB_OUT_SIZE_IPA (0x2000)
-#define FORMATS_SUPPORTED USB_CDC_NCM_NTB16_SUPPORTED
+#define MBIM_FORMATS_SUPPORTED USB_CDC_NCM_NTB16_SUPPORTED
-static struct usb_cdc_ncm_ntb_parameters ntb_parameters = {
- .wLength = sizeof ntb_parameters,
- .bmNtbFormatsSupported = cpu_to_le16(FORMATS_SUPPORTED),
- .dwNtbInMaxSize = cpu_to_le32(NTB_DEFAULT_IN_SIZE),
- .wNdpInDivisor = cpu_to_le16(NDP_IN_DIVISOR),
+static struct usb_cdc_ncm_ntb_parameters mbim_ntb_parameters = {
+ .wLength = sizeof mbim_ntb_parameters,
+ .bmNtbFormatsSupported = cpu_to_le16(MBIM_FORMATS_SUPPORTED),
+ .dwNtbInMaxSize = cpu_to_le32(MBIM_NTB_DEFAULT_IN_SIZE),
+ .wNdpInDivisor = cpu_to_le16(MBIM_NDP_IN_DIVISOR),
.wNdpInPayloadRemainder = cpu_to_le16(0),
.wNdpInAlignment = cpu_to_le16(4),
- .dwNtbOutMaxSize = cpu_to_le32(NTB_OUT_SIZE),
+ .dwNtbOutMaxSize = cpu_to_le32(MBIM_NTB_OUT_SIZE),
.wNdpOutDivisor = cpu_to_le16(4),
.wNdpOutPayloadRemainder = cpu_to_le16(0),
.wNdpOutAlignment = cpu_to_le16(4),
@@ -444,7 +444,7 @@
* and switch pointers to the structures when the format is changed.
*/
-struct ndp_parser_opts {
+struct mbim_ndp_parser_opts {
u32 nth_sign;
u32 ndp_sign;
unsigned nth_size;
@@ -487,8 +487,8 @@
.next_fp_index = 2, \
}
-static struct ndp_parser_opts ndp16_opts = INIT_NDP16_OPTS;
-static struct ndp_parser_opts ndp32_opts = INIT_NDP32_OPTS;
+static struct mbim_ndp_parser_opts mbim_ndp16_opts = INIT_NDP16_OPTS;
+static struct mbim_ndp_parser_opts mbim_ndp32_opts = INIT_NDP32_OPTS;
static inline int mbim_lock(atomic_t *excl)
{
@@ -630,7 +630,7 @@
return 0;
}
- if (dev->not_port.notify_state != NCM_NOTIFY_RESPONSE_AVAILABLE) {
+ if (dev->not_port.notify_state != MBIM_NOTIFY_RESPONSE_AVAILABLE) {
pr_err("dev:%p state=%d, recover!!\n", dev,
dev->not_port.notify_state);
mbim_free_ctrl_pkt(cpkt);
@@ -670,12 +670,14 @@
int ret = 0;
aggr_params.dl.aggr_prot = TETH_AGGR_PROTOCOL_MBIM;
- aggr_params.dl.max_datagrams = ntb_parameters.wNtbOutMaxDatagrams;
- aggr_params.dl.max_transfer_size_byte = ntb_parameters.dwNtbInMaxSize;
+ aggr_params.dl.max_datagrams = mbim_ntb_parameters.wNtbOutMaxDatagrams;
+ aggr_params.dl.max_transfer_size_byte =
+ mbim_ntb_parameters.dwNtbInMaxSize;
aggr_params.ul.aggr_prot = TETH_AGGR_PROTOCOL_MBIM;
- aggr_params.ul.max_datagrams = ntb_parameters.wNtbOutMaxDatagrams;
- aggr_params.ul.max_transfer_size_byte = ntb_parameters.dwNtbOutMaxSize;
+ aggr_params.ul.max_datagrams = mbim_ntb_parameters.wNtbOutMaxDatagrams;
+ aggr_params.ul.max_transfer_size_byte =
+ mbim_ntb_parameters.dwNtbOutMaxSize;
ret = teth_bridge_set_aggr_params(&aggr_params);
if (ret)
@@ -731,9 +733,9 @@
static inline void mbim_reset_values(struct f_mbim *mbim)
{
- mbim->parser_opts = &ndp16_opts;
+ mbim->parser_opts = &mbim_ndp16_opts;
- mbim->ntb_input_size = NTB_DEFAULT_IN_SIZE;
+ mbim->ntb_input_size = MBIM_NTB_DEFAULT_IN_SIZE;
atomic_set(&mbim->online, 0);
}
@@ -809,15 +811,15 @@
switch (mbim->not_port.notify_state) {
- case NCM_NOTIFY_NONE:
+ case MBIM_NOTIFY_NONE:
if (atomic_read(&mbim->not_port.notify_count) > 0)
- pr_err("Pending notifications in NCM_NOTIFY_NONE\n");
+ pr_err("Pending notifications in MBIM_NOTIFY_NONE\n");
else
pr_debug("No pending notifications\n");
return;
- case NCM_NOTIFY_RESPONSE_AVAILABLE:
+ case MBIM_NOTIFY_RESPONSE_AVAILABLE:
pr_debug("Notification %02x sent\n", event->bNotificationType);
if (atomic_read(&mbim->not_port.notify_count) <= 0) {
@@ -874,7 +876,7 @@
case -ECONNRESET:
case -ESHUTDOWN:
/* connection gone */
- mbim->not_port.notify_state = NCM_NOTIFY_NONE;
+ mbim->not_port.notify_state = MBIM_NOTIFY_NONE;
atomic_set(&mbim->not_port.notify_count, 0);
pr_info("ESHUTDOWN/ECONNRESET, connection gone");
spin_unlock(&mbim->lock);
@@ -913,7 +915,7 @@
if (req->length == 4) {
in_size = get_unaligned_le32(req->buf);
if (in_size < USB_CDC_NCM_NTB_MIN_IN_SIZE ||
- in_size > le32_to_cpu(ntb_parameters.dwNtbInMaxSize)) {
+ in_size > le32_to_cpu(mbim_ntb_parameters.dwNtbInMaxSize)) {
pr_err("Illegal INPUT SIZE (%d) from host\n", in_size);
goto invalid;
}
@@ -921,7 +923,7 @@
ntb = (struct mbim_ntb_input_size *)req->buf;
in_size = get_unaligned_le32(&(ntb->ntb_input_size));
if (in_size < USB_CDC_NCM_NTB_MIN_IN_SIZE ||
- in_size > le32_to_cpu(ntb_parameters.dwNtbInMaxSize)) {
+ in_size > le32_to_cpu(mbim_ntb_parameters.dwNtbInMaxSize)) {
pr_err("Illegal INPUT SIZE (%d) from host\n", in_size);
goto invalid;
}
@@ -1080,9 +1082,9 @@
if (w_length == 0 || w_value != 0 || w_index != mbim->ctrl_id)
break;
- value = w_length > sizeof ntb_parameters ?
- sizeof ntb_parameters : w_length;
- memcpy(req->buf, &ntb_parameters, value);
+ value = w_length > sizeof mbim_ntb_parameters ?
+ sizeof mbim_ntb_parameters : w_length;
+ memcpy(req->buf, &mbim_ntb_parameters, value);
break;
case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
@@ -1129,7 +1131,7 @@
if (w_length < 2 || w_value != 0 || w_index != mbim->ctrl_id)
break;
- format = (mbim->parser_opts == &ndp16_opts) ? 0x0000 : 0x0001;
+ format = (mbim->parser_opts == &mbim_ndp16_opts) ? 0 : 1;
put_unaligned_le16(format, req->buf);
value = 2;
pr_debug("NTB FORMAT: sending %d\n", format);
@@ -1145,11 +1147,11 @@
break;
switch (w_value) {
case 0x0000:
- mbim->parser_opts = &ndp16_opts;
+ mbim->parser_opts = &mbim_ndp16_opts;
pr_debug("NCM16 selected\n");
break;
case 0x0001:
- mbim->parser_opts = &ndp32_opts;
+ mbim->parser_opts = &mbim_ndp32_opts;
pr_debug("NCM32 selected\n");
break;
default:
@@ -1343,7 +1345,7 @@
mbim->data_alt_int = alt;
spin_lock(&mbim->lock);
- mbim->not_port.notify_state = NCM_NOTIFY_RESPONSE_AVAILABLE;
+ mbim->not_port.notify_state = MBIM_NOTIFY_RESPONSE_AVAILABLE;
spin_unlock(&mbim->lock);
} else {
goto fail;
@@ -1387,7 +1389,7 @@
pr_info("SET DEVICE OFFLINE");
atomic_set(&mbim->online, 0);
- mbim->not_port.notify_state = NCM_NOTIFY_NONE;
+ mbim->not_port.notify_state = MBIM_NOTIFY_NONE;
mbim_clear_queues(mbim);
mbim_reset_function_queue(mbim);
@@ -1655,12 +1657,13 @@
mbim->xport = USB_GADGET_XPORT_BAM2BAM;
} else {
/* For IPA we use limit of 16 */
- ntb_parameters.wNtbOutMaxDatagrams = 16;
+ mbim_ntb_parameters.wNtbOutMaxDatagrams = 16;
/* For IPA this is proven to give maximum throughput */
- ntb_parameters.dwNtbInMaxSize =
+ mbim_ntb_parameters.dwNtbInMaxSize =
cpu_to_le32(NTB_DEFAULT_IN_SIZE_IPA);
- ntb_parameters.dwNtbOutMaxSize = cpu_to_le32(NTB_OUT_SIZE_IPA);
- ntb_parameters.wNdpInDivisor = 1;
+ mbim_ntb_parameters.dwNtbOutMaxSize =
+ cpu_to_le32(MBIM_NTB_OUT_SIZE_IPA);
+ mbim_ntb_parameters.wNdpInDivisor = 1;
}
INIT_LIST_HEAD(&mbim->cpkt_req_q);
diff --git a/drivers/usb/gadget/f_ncm.c b/drivers/usb/gadget/f_ncm.c
index aab8ede..cdf86fd 100644
--- a/drivers/usb/gadget/f_ncm.c
+++ b/drivers/usb/gadget/f_ncm.c
@@ -24,6 +24,21 @@
#include "u_ether.h"
+#undef DBG
+#undef VDBG
+#undef ERROR
+#undef INFO
+
+#define DBG(d, fmt, args...) \
+ dev_dbg(&(d)->gadget->dev , fmt , ## args)
+#define VDBG(d, fmt, args...) \
+ dev_vdbg(&(d)->gadget->dev , fmt , ## args)
+#define ERROR(d, fmt, args...) \
+ dev_err(&(d)->gadget->dev , fmt , ## args)
+#define WARNING(d, fmt, args...) \
+ dev_warn(&(d)->gadget->dev , fmt , ## args)
+#define INFO(d, fmt, args...) \
+ dev_info(&(d)->gadget->dev , fmt , ## args)
/*
* This function is a "CDC Network Control Model" (CDC NCM) Ethernet link.
* NCM is intended to be used with high-speed network attachments.
@@ -124,7 +139,7 @@
#define LOG2_STATUS_INTERVAL_MSEC 5 /* 1 << 5 == 32 msec */
#define NCM_STATUS_BYTECOUNT 16 /* 8 byte header + data */
-static struct usb_interface_assoc_descriptor ncm_iad_desc __initdata = {
+static struct usb_interface_assoc_descriptor ncm_iad_desc = {
.bLength = sizeof ncm_iad_desc,
.bDescriptorType = USB_DT_INTERFACE_ASSOCIATION,
@@ -138,7 +153,7 @@
/* interface descriptor: */
-static struct usb_interface_descriptor ncm_control_intf __initdata = {
+static struct usb_interface_descriptor ncm_control_intf = {
.bLength = sizeof ncm_control_intf,
.bDescriptorType = USB_DT_INTERFACE,
@@ -150,7 +165,7 @@
/* .iInterface = DYNAMIC */
};
-static struct usb_cdc_header_desc ncm_header_desc __initdata = {
+static struct usb_cdc_header_desc ncm_header_desc = {
.bLength = sizeof ncm_header_desc,
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubType = USB_CDC_HEADER_TYPE,
@@ -158,7 +173,7 @@
.bcdCDC = cpu_to_le16(0x0110),
};
-static struct usb_cdc_union_desc ncm_union_desc __initdata = {
+static struct usb_cdc_union_desc ncm_union_desc = {
.bLength = sizeof(ncm_union_desc),
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubType = USB_CDC_UNION_TYPE,
@@ -166,8 +181,8 @@
/* .bSlaveInterface0 = DYNAMIC */
};
-static struct usb_cdc_ether_desc ecm_desc __initdata = {
- .bLength = sizeof ecm_desc,
+static struct usb_cdc_ether_desc necm_desc = {
+ .bLength = sizeof necm_desc,
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubType = USB_CDC_ETHERNET_TYPE,
@@ -181,7 +196,7 @@
#define NCAPS (USB_CDC_NCM_NCAP_ETH_FILTER | USB_CDC_NCM_NCAP_CRC_MODE)
-static struct usb_cdc_ncm_desc ncm_desc __initdata = {
+static struct usb_cdc_ncm_desc ncm_desc = {
.bLength = sizeof ncm_desc,
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubType = USB_CDC_NCM_TYPE,
@@ -193,7 +208,7 @@
/* the default data interface has no endpoints ... */
-static struct usb_interface_descriptor ncm_data_nop_intf __initdata = {
+static struct usb_interface_descriptor ncm_data_nop_intf = {
.bLength = sizeof ncm_data_nop_intf,
.bDescriptorType = USB_DT_INTERFACE,
@@ -208,7 +223,7 @@
/* ... but the "real" data interface has two bulk endpoints */
-static struct usb_interface_descriptor ncm_data_intf __initdata = {
+static struct usb_interface_descriptor ncm_data_intf = {
.bLength = sizeof ncm_data_intf,
.bDescriptorType = USB_DT_INTERFACE,
@@ -223,7 +238,7 @@
/* full speed support: */
-static struct usb_endpoint_descriptor fs_ncm_notify_desc __initdata = {
+static struct usb_endpoint_descriptor fs_ncm_notify_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
@@ -233,7 +248,7 @@
.bInterval = 1 << LOG2_STATUS_INTERVAL_MSEC,
};
-static struct usb_endpoint_descriptor fs_ncm_in_desc __initdata = {
+static struct usb_endpoint_descriptor fs_ncm_in_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
@@ -241,7 +256,7 @@
.bmAttributes = USB_ENDPOINT_XFER_BULK,
};
-static struct usb_endpoint_descriptor fs_ncm_out_desc __initdata = {
+static struct usb_endpoint_descriptor fs_ncm_out_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
@@ -249,13 +264,13 @@
.bmAttributes = USB_ENDPOINT_XFER_BULK,
};
-static struct usb_descriptor_header *ncm_fs_function[] __initdata = {
+static struct usb_descriptor_header *ncm_fs_function[] = {
(struct usb_descriptor_header *) &ncm_iad_desc,
/* CDC NCM control descriptors */
(struct usb_descriptor_header *) &ncm_control_intf,
(struct usb_descriptor_header *) &ncm_header_desc,
(struct usb_descriptor_header *) &ncm_union_desc,
- (struct usb_descriptor_header *) &ecm_desc,
+ (struct usb_descriptor_header *) &necm_desc,
(struct usb_descriptor_header *) &ncm_desc,
(struct usb_descriptor_header *) &fs_ncm_notify_desc,
/* data interface, altsettings 0 and 1 */
@@ -268,7 +283,7 @@
/* high speed support: */
-static struct usb_endpoint_descriptor hs_ncm_notify_desc __initdata = {
+static struct usb_endpoint_descriptor hs_ncm_notify_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
@@ -277,7 +292,7 @@
.wMaxPacketSize = cpu_to_le16(NCM_STATUS_BYTECOUNT),
.bInterval = LOG2_STATUS_INTERVAL_MSEC + 4,
};
-static struct usb_endpoint_descriptor hs_ncm_in_desc __initdata = {
+static struct usb_endpoint_descriptor hs_ncm_in_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
@@ -286,7 +301,7 @@
.wMaxPacketSize = cpu_to_le16(512),
};
-static struct usb_endpoint_descriptor hs_ncm_out_desc __initdata = {
+static struct usb_endpoint_descriptor hs_ncm_out_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
@@ -295,13 +310,13 @@
.wMaxPacketSize = cpu_to_le16(512),
};
-static struct usb_descriptor_header *ncm_hs_function[] __initdata = {
+static struct usb_descriptor_header *ncm_hs_function[] = {
(struct usb_descriptor_header *) &ncm_iad_desc,
/* CDC NCM control descriptors */
(struct usb_descriptor_header *) &ncm_control_intf,
(struct usb_descriptor_header *) &ncm_header_desc,
(struct usb_descriptor_header *) &ncm_union_desc,
- (struct usb_descriptor_header *) &ecm_desc,
+ (struct usb_descriptor_header *) &necm_desc,
(struct usb_descriptor_header *) &ncm_desc,
(struct usb_descriptor_header *) &hs_ncm_notify_desc,
/* data interface, altsettings 0 and 1 */
@@ -316,13 +331,13 @@
#define STRING_CTRL_IDX 0
#define STRING_MAC_IDX 1
-#define STRING_DATA_IDX 2
+#define NCM_STRING_DATA_IDX 2
#define STRING_IAD_IDX 3
static struct usb_string ncm_string_defs[] = {
[STRING_CTRL_IDX].s = "CDC Network Control Model (NCM)",
[STRING_MAC_IDX].s = NULL /* DYNAMIC */,
- [STRING_DATA_IDX].s = "CDC Network Data",
+ [NCM_STRING_DATA_IDX].s = "CDC Network Data",
[STRING_IAD_IDX].s = "CDC NCM",
{ } /* end of list */
};
@@ -1148,7 +1163,7 @@
/* ethernet function driver setup/binding */
-static int __init
+static int
ncm_bind(struct usb_configuration *c, struct usb_function *f)
{
struct usb_composite_dev *cdev = c->cdev;
@@ -1299,7 +1314,7 @@
* Caller must have called @gether_setup(). Caller is also responsible
* for calling @gether_cleanup() before module unload.
*/
-int __init ncm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
+int ncm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
{
struct f_ncm *ncm;
int status;
@@ -1321,7 +1336,7 @@
status = usb_string_id(c->cdev);
if (status < 0)
return status;
- ncm_string_defs[STRING_DATA_IDX].id = status;
+ ncm_string_defs[NCM_STRING_DATA_IDX].id = status;
ncm_data_nop_intf.iInterface = status;
ncm_data_intf.iInterface = status;
@@ -1330,7 +1345,7 @@
if (status < 0)
return status;
ncm_string_defs[STRING_MAC_IDX].id = status;
- ecm_desc.iMACAddress = status;
+ necm_desc.iMACAddress = status;
/* IAD */
status = usb_string_id(c->cdev);
diff --git a/drivers/usb/gadget/f_qc_ecm.c b/drivers/usb/gadget/f_qc_ecm.c
index 4f9cbf1..a6b443f 100644
--- a/drivers/usb/gadget/f_qc_ecm.c
+++ b/drivers/usb/gadget/f_qc_ecm.c
@@ -75,6 +75,7 @@
struct usb_request *notify_req;
u8 notify_state;
bool is_open;
+ struct data_port bam_port;
};
static struct ecm_ipa_params ipa_params;
@@ -111,8 +112,9 @@
#define ECM_QC_LOG2_STATUS_INTERVAL_MSEC 5 /* 1 << 5 == 32 msec */
#define ECM_QC_STATUS_BYTECOUNT 16 /* 8 byte header + data */
-/* currently only one std ecm instance is supported */
+/* Currently only one std ecm instance is supported - port index 0. */
#define ECM_QC_NO_PORTS 1
+#define ECM_QC_ACTIVE_PORT 0
/* interface descriptor: */
@@ -296,8 +298,6 @@
NULL,
};
-static struct data_port ecm_qc_bam_port;
-
static void ecm_qc_do_notify(struct f_ecm_qc *ecm)
{
struct usb_request *req = ecm->notify_req;
@@ -388,10 +388,10 @@
enum peer_bam peer_bam = (dev->xport == USB_GADGET_XPORT_BAM2BAM_IPA) ?
IPA_P_BAM : A2_P_BAM;
- ecm_qc_bam_port.cdev = cdev;
- ecm_qc_bam_port.func = &dev->port.func;
- ecm_qc_bam_port.in = dev->port.in_ep;
- ecm_qc_bam_port.out = dev->port.out_ep;
+ dev->bam_port.cdev = cdev;
+ dev->bam_port.func = &dev->port.func;
+ dev->bam_port.in = dev->port.in_ep;
+ dev->bam_port.out = dev->port.out_ep;
/* currently we use the first connection */
src_connection_idx = usb_bam_get_connection_idx(gadget->name, peer_bam,
@@ -402,7 +402,7 @@
pr_err("%s: usb_bam_get_connection_idx failed\n", __func__);
return ret;
}
- ret = bam_data_connect(&ecm_qc_bam_port, 0, dev->xport,
+ ret = bam_data_connect(&dev->bam_port, 0, dev->xport,
src_connection_idx, dst_connection_idx, USB_FUNC_ECM);
if (ret) {
pr_err("bam_data_connect failed: err:%d\n", ret);
@@ -421,7 +421,7 @@
{
pr_debug("dev:%p. Disconnect BAM.\n", dev);
- bam_data_disconnect(&ecm_qc_bam_port, 0);
+ bam_data_disconnect(&dev->bam_port, 0);
return 0;
}
@@ -656,6 +656,20 @@
}
}
+static void ecm_qc_suspend(struct usb_function *f)
+{
+ pr_debug("ecm suspended\n");
+
+ bam_data_suspend(ECM_QC_ACTIVE_PORT);
+}
+
+static void ecm_qc_resume(struct usb_function *f)
+{
+ pr_debug("ecm resumed\n");
+
+ bam_data_resume(ECM_QC_ACTIVE_PORT);
+}
+
/*-------------------------------------------------------------------------*/
/*
@@ -939,6 +953,8 @@
ecm->port.func.get_alt = ecm_qc_get_alt;
ecm->port.func.setup = ecm_qc_setup;
ecm->port.func.disable = ecm_qc_disable;
+ ecm->port.func.suspend = ecm_qc_suspend;
+ ecm->port.func.resume = ecm_qc_resume;
status = usb_add_function(c, &ecm->port.func);
if (status) {
diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c
index 32d4011..7903764 100644
--- a/drivers/usb/gadget/f_rndis.c
+++ b/drivers/usb/gadget/f_rndis.c
@@ -66,10 +66,10 @@
* - MS-Windows drivers sometimes emit undocumented requests.
*/
-static bool rndis_multipacket_dl_disable;
-module_param(rndis_multipacket_dl_disable, bool, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(rndis_multipacket_dl_disable,
- "Disable RNDIS Multi-packet support in DownLink");
+static unsigned int rndis_dl_max_pkt_per_xfer = 3;
+module_param(rndis_dl_max_pkt_per_xfer, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(rndis_dl_max_pkt_per_xfer,
+ "Maximum packets per transfer for DL aggregation");
static unsigned int rndis_ul_max_pkt_per_xfer = 3;
module_param(rndis_ul_max_pkt_per_xfer, uint, S_IRUGO | S_IWUSR);
@@ -488,7 +488,7 @@
__func__, buf->MaxTransferSize,
rndis->port.multi_pkt_xfer ? "enabled" :
"disabled");
- if (rndis_multipacket_dl_disable)
+ if (rndis_dl_max_pkt_per_xfer <= 1)
rndis->port.multi_pkt_xfer = 0;
}
// spin_unlock(&dev->lock);
@@ -952,6 +952,7 @@
rndis->port.wrap = rndis_add_header;
rndis->port.unwrap = rndis_rm_hdr;
rndis->port.ul_max_pkts_per_xfer = rndis_ul_max_pkt_per_xfer;
+ rndis->port.dl_max_pkts_per_xfer = rndis_dl_max_pkt_per_xfer;
rndis->port.func.name = "rndis";
rndis->port.func.strings = rndis_strings;
diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c
index dbffa4e..9961d00 100644
--- a/drivers/usb/gadget/u_ether.c
+++ b/drivers/usb/gadget/u_ether.c
@@ -71,6 +71,7 @@
unsigned header_len;
unsigned int ul_max_pkts_per_xfer;
+ unsigned int dl_max_pkts_per_xfer;
struct sk_buff *(*wrap)(struct gether *, struct sk_buff *skb);
int (*unwrap)(struct gether *,
struct sk_buff *skb,
@@ -585,12 +586,12 @@
return cdc_filter & USB_CDC_PACKET_TYPE_PROMISCUOUS;
}
-static void alloc_tx_buffer(struct eth_dev *dev)
+static int alloc_tx_buffer(struct eth_dev *dev)
{
struct list_head *act;
struct usb_request *req;
- dev->tx_req_bufsize = (TX_SKB_HOLD_THRESHOLD *
+ dev->tx_req_bufsize = (dev->dl_max_pkts_per_xfer *
(dev->net->mtu
+ sizeof(struct ethhdr)
/* size of rndis_packet_msg_type */
@@ -602,7 +603,19 @@
if (!req->buf)
req->buf = kmalloc(dev->tx_req_bufsize,
GFP_ATOMIC);
+ if (!req->buf)
+ goto free_buf;
}
+ return 0;
+
+free_buf:
+ /* tx_req_bufsize = 0 retries mem alloc on next eth_start_xmit */
+ dev->tx_req_bufsize = 0;
+ list_for_each(act, &dev->tx_reqs) {
+ req = container_of(act, struct usb_request, list);
+ kfree(req->buf);
+ }
+ return -ENOMEM;
}
static netdev_tx_t eth_start_xmit(struct sk_buff *skb,
@@ -634,8 +647,11 @@
}
/* Allocate memory for tx_reqs to support multi packet transfer */
- if (multi_pkt_xfer && !dev->tx_req_bufsize)
- alloc_tx_buffer(dev);
+ if (multi_pkt_xfer && !dev->tx_req_bufsize) {
+ retval = alloc_tx_buffer(dev);
+ if (retval < 0)
+ return -ENOMEM;
+ }
/* apply outgoing CDC or RNDIS filters */
if (!is_promisc(cdc_filter)) {
@@ -704,7 +720,7 @@
dev_kfree_skb_any(skb);
spin_lock_irqsave(&dev->req_lock, flags);
- if (dev->tx_skb_hold_count < TX_SKB_HOLD_THRESHOLD) {
+ if (dev->tx_skb_hold_count < dev->dl_max_pkts_per_xfer) {
if (dev->no_tx_req_used > TX_REQ_THRESHOLD) {
list_add(&req->list, &dev->tx_reqs);
spin_unlock_irqrestore(&dev->req_lock, flags);
@@ -1082,6 +1098,7 @@
dev->unwrap = link->unwrap;
dev->wrap = link->wrap;
dev->ul_max_pkts_per_xfer = link->ul_max_pkts_per_xfer;
+ dev->dl_max_pkts_per_xfer = link->dl_max_pkts_per_xfer;
spin_lock(&dev->lock);
dev->tx_skb_hold_count = 0;
diff --git a/drivers/usb/gadget/u_ether.h b/drivers/usb/gadget/u_ether.h
index 7040ab0..05984d8 100644
--- a/drivers/usb/gadget/u_ether.h
+++ b/drivers/usb/gadget/u_ether.h
@@ -55,8 +55,7 @@
u32 fixed_in_len;
unsigned ul_max_pkts_per_xfer;
-/* Max number of SKB packets to be used to create Multi Packet RNDIS */
-#define TX_SKB_HOLD_THRESHOLD 3
+ unsigned dl_max_pkts_per_xfer;
bool multi_pkt_xfer;
struct sk_buff *(*wrap)(struct gether *port,
struct sk_buff *skb);
diff --git a/drivers/usb/gadget/u_rmnet_ctrl_smd.c b/drivers/usb/gadget/u_rmnet_ctrl_smd.c
index caea4ef..5a34679 100644
--- a/drivers/usb/gadget/u_rmnet_ctrl_smd.c
+++ b/drivers/usb/gadget/u_rmnet_ctrl_smd.c
@@ -604,6 +604,11 @@
pr_debug("%s: requested ports:%d\n", __func__, count);
+ if (client_num >= NR_CTRL_CLIENTS) {
+ pr_err("%s: Invalid client:%d\n", __func__, client_num);
+ return -EINVAL;
+ }
+
if (!count || count > MAX_CTRL_PER_CLIENT) {
pr_err("%s: Invalid num of ports count:%d\n",
__func__, count);
diff --git a/drivers/usb/gadget/u_sdio.c b/drivers/usb/gadget/u_sdio.c
index a0cdde2..52b707e 100644
--- a/drivers/usb/gadget/u_sdio.c
+++ b/drivers/usb/gadget/u_sdio.c
@@ -232,7 +232,7 @@
{
unsigned avail;
char *packet;
- unsigned size = req->actual;
+ unsigned size;
unsigned n;
int ret = 0;
@@ -271,6 +271,7 @@
return -ENODEV;
}
+ size = req->actual;
packet = req->buf;
n = port->n_read;
if (n) {
diff --git a/drivers/video/msm/mdss/mdp3.c b/drivers/video/msm/mdss/mdp3.c
index 65c9e90..0ff19a2 100644
--- a/drivers/video/msm/mdss/mdp3.c
+++ b/drivers/video/msm/mdss/mdp3.c
@@ -393,7 +393,8 @@
-int mdp3_clk_set_rate(int clk_type, unsigned long clk_rate)
+int mdp3_clk_set_rate(int clk_type, unsigned long clk_rate,
+ int client)
{
int ret = 0;
unsigned long rounded_rate;
@@ -407,6 +408,19 @@
mutex_unlock(&mdp3_res->res_mutex);
return -EINVAL;
}
+ if (clk_type == MDP3_CLK_CORE) {
+ if (client == MDP3_CLIENT_DMA_P) {
+ mdp3_res->dma_core_clk_request = rounded_rate;
+ } else if (client == MDP3_CLIENT_PPP) {
+ mdp3_res->ppp_core_clk_request = rounded_rate;
+ } else {
+ pr_err("unrecognized client=%d\n", client);
+ mutex_unlock(&mdp3_res->res_mutex);
+ return -EINVAL;
+ }
+ rounded_rate = max(mdp3_res->dma_core_clk_request,
+ mdp3_res->ppp_core_clk_request);
+ }
if (rounded_rate != clk_get_rate(clk)) {
ret = clk_set_rate(clk, rounded_rate);
if (ret)
@@ -948,7 +962,7 @@
{
int rc;
rc = mdp3_ctrl_init(mfd);
- rc |= mdp3_ppp_res_init();
+ rc |= mdp3_ppp_res_init(mfd);
return rc;
}
diff --git a/drivers/video/msm/mdss/mdp3.h b/drivers/video/msm/mdss/mdp3.h
index e52f7bc..31fcd0e 100644
--- a/drivers/video/msm/mdss/mdp3.h
+++ b/drivers/video/msm/mdss/mdp3.h
@@ -141,7 +141,7 @@
void mdp3_irq_disable(int type);
void mdp3_irq_disable_nosync(int type);
int mdp3_set_intr_callback(u32 type, struct mdp3_intr_cb *cb);
-int mdp3_clk_set_rate(int clk_type, unsigned long clk_rate);
+int mdp3_clk_set_rate(int clk_type, unsigned long clk_rate, int client);
int mdp3_clk_enable(int enable);
int mdp3_bus_scale_set_quota(int client, u64 ab_quota, u64 ib_quota);
int mdp3_put_img(struct mdp3_img_data *data);
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.c b/drivers/video/msm/mdss/mdp3_ctrl.c
index 037ab51..ce68013 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.c
+++ b/drivers/video/msm/mdss/mdp3_ctrl.c
@@ -29,6 +29,7 @@
#define VSYNC_PERIOD 16
static void mdp3_ctrl_pan_display(struct msm_fb_data_type *mfd);
+static int mdp3_overlay_unset(struct msm_fb_data_type *mfd, int ndx);
static void mdp3_bufq_init(struct mdp3_buffer_queue *bufq)
{
@@ -129,52 +130,41 @@
return 0;
}
-static int mdp3_ctrl_blit_req(struct msm_fb_data_type *mfd, void __user *p)
+static int mdp3_ctrl_async_blit_req(struct msm_fb_data_type *mfd,
+ void __user *p)
{
- const int MAX_LIST_WINDOW = 16;
- struct mdp_blit_req req_list[MAX_LIST_WINDOW];
- struct mdp_blit_req_list req_list_header;
- int rc, count, i, req_list_count;
+ struct mdp_async_blit_req_list req_list_header;
+ int rc, count;
+ void __user *p_req;
if (copy_from_user(&req_list_header, p, sizeof(req_list_header)))
return -EFAULT;
- p += sizeof(req_list_header);
+ p_req = p + sizeof(req_list_header);
count = req_list_header.count;
if (count < 0 || count >= MAX_BLIT_REQ)
return -EINVAL;
- while (count > 0) {
- /*
- * Access the requests through a narrow window to decrease copy
- * overhead and make larger requests accessible to the
- * coherency management code.
- * NOTE: The window size is intended to be larger than the
- * typical request size, but not require more than 2
- * kbytes of stack storage.
- */
- req_list_count = count;
- if (req_list_count > MAX_LIST_WINDOW)
- req_list_count = MAX_LIST_WINDOW;
- if (copy_from_user(&req_list, p,
- sizeof(struct mdp_blit_req)*req_list_count))
- return -EFAULT;
- /*
- * Do the blit DMA, if required -- returning early only if
- * there is a failure.
- */
- for (i = 0; i < req_list_count; i++) {
- if (!(req_list[i].flags & MDP_NO_BLIT)) {
- /* Do the actual blit. */
- rc = mdp3_ppp_start_blit(mfd, &(req_list[i]));
- if (rc)
- return rc;
- }
- }
+ rc = mdp3_ppp_parse_req(p_req, &req_list_header, 1);
+ if (!rc)
+ rc = copy_to_user(p, &req_list_header, sizeof(req_list_header));
+ return rc;
+}
- /* Go to next window of requests. */
- count -= req_list_count;
- p += sizeof(struct mdp_blit_req)*req_list_count;
- }
- return 0;
+static int mdp3_ctrl_blit_req(struct msm_fb_data_type *mfd, void __user *p)
+{
+ struct mdp_async_blit_req_list req_list_header;
+ int rc, count;
+ void __user *p_req;
+
+ if (copy_from_user(&(req_list_header.count), p,
+ sizeof(struct mdp_blit_req_list)))
+ return -EFAULT;
+ p_req = p + sizeof(struct mdp_blit_req_list);
+ count = req_list_header.count;
+ if (count < 0 || count >= MAX_BLIT_REQ)
+ return -EINVAL;
+ req_list_header.sync.acq_fen_fd_cnt = 0;
+ rc = mdp3_ppp_parse_req(p_req, &req_list_header, 0);
+ return rc;
}
static ssize_t mdp3_vsync_show_event(struct device *dev,
@@ -238,8 +228,10 @@
int rc = 0;
if (status) {
- mdp3_clk_set_rate(MDP3_CLK_CORE, MDP_CORE_CLK_RATE);
- mdp3_clk_set_rate(MDP3_CLK_VSYNC, MDP_VSYNC_CLK_RATE);
+ mdp3_clk_set_rate(MDP3_CLK_CORE, MDP_CORE_CLK_RATE,
+ MDP3_CLIENT_DMA_P);
+ mdp3_clk_set_rate(MDP3_CLK_VSYNC, MDP_VSYNC_CLK_RATE,
+ MDP3_CLIENT_DMA_P);
rc = mdp3_clk_enable(true);
if (rc)
@@ -503,8 +495,9 @@
pr_err("mdp clock resource release failed\n");
off_error:
mdp3_session->status = 0;
-
mutex_unlock(&mdp3_session->lock);
+ if (mdp3_session->overlay.id != MSMFB_NEW_REQUEST)
+ mdp3_overlay_unset(mfd, mdp3_session->overlay.id);
return 0;
}
@@ -743,6 +736,9 @@
rc = -EFAULT;
}
break;
+ case MSMFB_ASYNC_BLIT:
+ rc = mdp3_ctrl_async_blit_req(mfd, argp);
+ break;
case MSMFB_BLIT:
rc = mdp3_ctrl_blit_req(mfd, argp);
break;
diff --git a/drivers/video/msm/mdss/mdp3_ppp.c b/drivers/video/msm/mdss/mdp3_ppp.c
index 7164086..3f31932 100644
--- a/drivers/video/msm/mdss/mdp3_ppp.c
+++ b/drivers/video/msm/mdss/mdp3_ppp.c
@@ -20,6 +20,8 @@
#include <linux/uaccess.h>
#include <linux/sched.h>
#include <linux/mutex.h>
+#include <linux/sync.h>
+#include <linux/sw_sync.h>
#include "linux/proc_fs.h"
#include "mdss_fb.h"
@@ -28,6 +30,10 @@
#include "mdp3.h"
#define MDP_IS_IMGTYPE_BAD(x) ((x) >= MDP_IMGTYPE_LIMIT)
+#define MDP_BLIT_CLK_RATE 200000000
+#define MDP_PPP_MAX_BPP 4
+#define MDP_PPP_DYNAMIC_FACTOR 3
+#define MDP_PPP_MAX_READ_WRITE 3
static const bool valid_fmt[MDP_IMGTYPE_LIMIT] = {
[MDP_RGB_565] = true,
@@ -47,11 +53,45 @@
[MDP_Y_CRCB_H2V1] = true,
};
+#define MAX_LIST_WINDOW 16
+#define MDP3_PPP_MAX_LIST_REQ 8
+
+struct blit_req_list {
+ int count;
+ struct mdp_blit_req req_list[MAX_LIST_WINDOW];
+ struct mdp3_img_data src_data[MAX_LIST_WINDOW];
+ struct mdp3_img_data dst_data[MAX_LIST_WINDOW];
+ struct sync_fence *acq_fen[MDP_MAX_FENCE_FD];
+ u32 acq_fen_cnt;
+ int cur_rel_fen_fd;
+ struct sync_pt *cur_rel_sync_pt;
+ struct sync_fence *cur_rel_fence;
+ struct sync_fence *last_rel_fence;
+};
+
+struct blit_req_queue {
+ struct blit_req_list req[MDP3_PPP_MAX_LIST_REQ];
+ int count;
+ int push_idx;
+ int pop_idx;
+};
+
struct ppp_status {
int busy;
+ bool wait_for_pop;
spinlock_t ppp_lock;
struct completion ppp_comp;
- struct mutex config_mutex;
+ struct completion pop_q_comp;
+ struct mutex req_mutex; /* Protect request queue */
+ struct mutex config_ppp_mutex; /* Only one client configure register */
+ struct msm_fb_data_type *mfd;
+
+ struct work_struct blit_work;
+ struct blit_req_queue req_q;
+
+ struct sw_sync_timeline *timeline;
+ int timeline_value;
+
};
static struct ppp_status *ppp_stat;
@@ -295,24 +335,22 @@
mdp3_ppp_pipe_wait();
}
-int mdp3_ppp_turnon(struct ppp_blit_op *blit_op, int on_off)
+int mdp3_ppp_turnon(struct msm_fb_data_type *mfd, int on_off)
{
- unsigned long clk_rate = 0, dst_rate = 0, src_rate = 0;
- int ab = 0;
- int ib = 0;
- if (on_off) {
- dst_rate = blit_op->dst.roi.width * blit_op->dst.roi.height;
- src_rate = blit_op->src.roi.width * blit_op->src.roi.height;
- clk_rate = max(dst_rate, src_rate);
- clk_rate = clk_rate * 36 * 12;
+ struct mdss_panel_info *panel_info = mfd->panel_info;
+ int ab = 0, ib = 0;
+ int rate = 0;
- ab = blit_op->dst.roi.width * blit_op->dst.roi.height *
- ppp_bpp(blit_op->dst.color_fmt) * 2 +
- blit_op->src.roi.width * blit_op->src.roi.height *
- ppp_bpp(blit_op->src.color_fmt);
- ab = ab * 120;
+ if (on_off) {
+ rate = MDP_BLIT_CLK_RATE;
+ ab = panel_info->xres * panel_info->yres *
+ panel_info->mipi.frame_rate *
+ MDP_PPP_MAX_BPP *
+ MDP_PPP_DYNAMIC_FACTOR *
+ MDP_PPP_MAX_READ_WRITE;
ib = (ab * 3) / 2;
}
+ mdp3_clk_set_rate(MDP3_CLK_CORE, rate, MDP3_CLIENT_PPP);
mdp3_clk_enable(on_off);
mdp3_bus_scale_set_quota(MDP3_CLIENT_PPP, ab, ib);
return 0;
@@ -322,10 +360,8 @@
{
/* Wait for the pipe to clear */
do { } while (mdp3_ppp_pipe_wait() <= 0);
- mutex_lock(&ppp_stat->config_mutex);
config_ppp_op_mode(blit_op);
mdp3_ppp_kickoff();
- mutex_unlock(&ppp_stat->config_mutex);
}
static void mdp3_ppp_process_req(struct ppp_blit_op *blit_op,
@@ -504,7 +540,7 @@
}
}
-static int mdp3_ppp_blit_addr(struct msm_fb_data_type *mfd,
+static int mdp3_ppp_blit(struct msm_fb_data_type *mfd,
struct mdp_blit_req *req, struct mdp3_img_data *src_data,
struct mdp3_img_data *dst_data)
{
@@ -524,8 +560,6 @@
mdp3_ppp_process_req(&blit_op, req, src_data, dst_data);
- mdp3_ppp_turnon(&blit_op, 1);
-
if (((blit_op.mdp_op & (MDPOP_TRANSP | MDPOP_ALPHAB)) ||
(req->src.format == MDP_ARGB_8888) ||
(req->src.format == MDP_BGRA_8888) ||
@@ -536,41 +570,13 @@
mdp3_start_ppp(&blit_op);
}
- /* MDP cmd block disable */
- mdp3_ppp_turnon(&blit_op, 0);
-
return 0;
}
-static int mdp3_ppp_blit(struct msm_fb_data_type *mfd, struct mdp_blit_req *req)
-{
- struct mdp3_img_data src_data;
- struct mdp3_img_data dst_data;
- int rc;
- mdp3_ppp_iommu_attach();
-
- mdp3_ppp_get_img(&req->src, req, &src_data);
- if (src_data.len == 0) {
- pr_err("mdp_ppp: couldn't retrieve src img from mem\n");
- return -EINVAL;
- }
-
- mdp3_ppp_get_img(&req->dst, req, &dst_data);
- if (dst_data.len == 0) {
- mdp3_put_img(&src_data);
- pr_err("mdp_ppp: couldn't retrieve dest img from mem\n");
- return -EINVAL;
- }
-
- rc = mdp3_ppp_blit_addr(mfd, req, &src_data, &dst_data);
- mdp3_put_img(&src_data);
- mdp3_put_img(&dst_data);
- mdp3_ppp_iommu_dettach();
- return rc;
-}
-
static int mdp3_ppp_blit_workaround(struct msm_fb_data_type *mfd,
- struct mdp_blit_req *req, unsigned int remainder)
+ struct mdp_blit_req *req, unsigned int remainder,
+ struct mdp3_img_data *src_data,
+ struct mdp3_img_data *dst_data)
{
int ret;
struct mdp_blit_req splitreq;
@@ -669,7 +675,7 @@
}
/* No need to split in height */
- ret = mdp3_ppp_blit(mfd, &splitreq);
+ ret = mdp3_ppp_blit(mfd, &splitreq, src_data, dst_data);
if (ret)
return ret;
@@ -698,11 +704,13 @@
}
/* No need to split in height ... just width */
- return mdp3_ppp_blit(mfd, &splitreq);
+ return mdp3_ppp_blit(mfd, &splitreq, src_data, dst_data);
}
int mdp3_ppp_start_blit(struct msm_fb_data_type *mfd,
- struct mdp_blit_req *req)
+ struct mdp_blit_req *req,
+ struct mdp3_img_data *src_data,
+ struct mdp3_img_data *dst_data)
{
int ret;
unsigned int remainder = 0, is_bpp_4 = 0;
@@ -742,19 +750,316 @@
is_bpp_4 = (ret == 4) ? 1 : 0;
if ((is_bpp_4 && (remainder == 6 || remainder == 14)))
- ret = mdp3_ppp_blit_workaround(mfd, req, remainder);
+ ret = mdp3_ppp_blit_workaround(mfd, req, remainder,
+ src_data, dst_data);
else
- ret = mdp3_ppp_blit(mfd, req);
+ ret = mdp3_ppp_blit(mfd, req, src_data, dst_data);
+ mdp3_put_img(src_data);
+ mdp3_put_img(dst_data);
return ret;
}
-int mdp3_ppp_res_init(void)
+void mdp3_ppp_wait_for_fence(struct blit_req_list *req)
{
- ppp_stat = kmalloc(sizeof(struct ppp_status), GFP_KERNEL);
+ int i, ret = 0;
+ /* buf sync */
+ for (i = 0; i < req->acq_fen_cnt; i++) {
+ ret = sync_fence_wait(req->acq_fen[i],
+ WAIT_FENCE_FINAL_TIMEOUT);
+ if (ret < 0) {
+ pr_err("%s: sync_fence_wait failed! ret = %x\n",
+ __func__, ret);
+ break;
+ }
+ sync_fence_put(req->acq_fen[i]);
+ }
+
+ if (ret < 0) {
+ while (i < req->acq_fen_cnt) {
+ sync_fence_put(req->acq_fen[i]);
+ i++;
+ }
+ }
+ req->acq_fen_cnt = 0;
+}
+
+void mdp3_ppp_signal_timeline(struct blit_req_list *req)
+{
+ sw_sync_timeline_inc(ppp_stat->timeline, 1);
+ req->last_rel_fence = req->cur_rel_fence;
+ req->cur_rel_fence = 0;
+}
+
+
+static void mdp3_ppp_deinit_buf_sync(struct blit_req_list *req)
+{
+ int i;
+
+ put_unused_fd(req->cur_rel_fen_fd);
+ sync_fence_put(req->cur_rel_fence);
+ req->cur_rel_fence = NULL;
+ req->cur_rel_fen_fd = 0;
+ ppp_stat->timeline_value--;
+ for (i = 0; i < req->acq_fen_cnt; i++)
+ sync_fence_put(req->acq_fen[i]);
+ req->acq_fen_cnt = 0;
+}
+
+static int mdp3_ppp_handle_buf_sync(struct blit_req_list *req,
+ struct mdp_buf_sync *buf_sync)
+{
+ int i, fence_cnt = 0, ret = 0;
+ int acq_fen_fd[MDP_MAX_FENCE_FD];
+ struct sync_fence *fence;
+
+ if ((buf_sync->acq_fen_fd_cnt > MDP_MAX_FENCE_FD) ||
+ (ppp_stat->timeline == NULL))
+ return -EINVAL;
+
+ if (buf_sync->acq_fen_fd_cnt)
+ ret = copy_from_user(acq_fen_fd, buf_sync->acq_fen_fd,
+ buf_sync->acq_fen_fd_cnt * sizeof(int));
+ if (ret) {
+ pr_err("%s: copy_from_user failed\n", __func__);
+ return ret;
+ }
+ for (i = 0; i < buf_sync->acq_fen_fd_cnt; i++) {
+ fence = sync_fence_fdget(acq_fen_fd[i]);
+ if (fence == NULL) {
+ pr_info("%s: null fence! i=%d fd=%d\n", __func__, i,
+ acq_fen_fd[i]);
+ ret = -EINVAL;
+ break;
+ }
+ req->acq_fen[i] = fence;
+ }
+ fence_cnt = i;
+ if (ret)
+ goto buf_sync_err_1;
+ req->acq_fen_cnt = fence_cnt;
+ if (buf_sync->flags & MDP_BUF_SYNC_FLAG_WAIT)
+ mdp3_ppp_wait_for_fence(req);
+
+ req->cur_rel_sync_pt = sw_sync_pt_create(ppp_stat->timeline,
+ ppp_stat->timeline_value++);
+ if (req->cur_rel_sync_pt == NULL) {
+ pr_err("%s: cannot create sync point\n", __func__);
+ ret = -ENOMEM;
+ goto buf_sync_err_2;
+ }
+ /* create fence */
+ req->cur_rel_fence = sync_fence_create("ppp-fence",
+ req->cur_rel_sync_pt);
+ if (req->cur_rel_fence == NULL) {
+ sync_pt_free(req->cur_rel_sync_pt);
+ req->cur_rel_sync_pt = NULL;
+ pr_err("%s: cannot create fence\n", __func__);
+ ret = -ENOMEM;
+ goto buf_sync_err_2;
+ }
+ /* create fd */
+ return ret;
+buf_sync_err_2:
+ ppp_stat->timeline_value--;
+buf_sync_err_1:
+ for (i = 0; i < fence_cnt; i++)
+ sync_fence_put(req->acq_fen[i]);
+ req->acq_fen_cnt = 0;
+ return ret;
+}
+
+void mdp3_ppp_req_push(struct blit_req_queue *req_q, struct blit_req_list *req)
+{
+ int idx = req_q->push_idx;
+ req_q->req[idx] = *req;
+ req_q->count++;
+ req_q->push_idx = (req_q->push_idx + 1) % MDP3_PPP_MAX_LIST_REQ;
+}
+
+struct blit_req_list *mdp3_ppp_next_req(struct blit_req_queue *req_q)
+{
+ struct blit_req_list *req;
+ if (req_q->count == 0)
+ return NULL;
+ req = &req_q->req[req_q->pop_idx];
+ return req;
+}
+
+void mdp3_ppp_req_pop(struct blit_req_queue *req_q)
+{
+ req_q->count--;
+ req_q->pop_idx = (req_q->pop_idx + 1) % MDP3_PPP_MAX_LIST_REQ;
+}
+
+static void mdp3_ppp_blit_wq_handler(struct work_struct *work)
+{
+ struct msm_fb_data_type *mfd = ppp_stat->mfd;
+ struct blit_req_list *req;
+ int i, rc;
+
+ req = mdp3_ppp_next_req(&ppp_stat->req_q);
+ mutex_lock(&ppp_stat->config_ppp_mutex);
+
+ mdp3_ppp_iommu_attach();
+ mdp3_ppp_turnon(mfd, 1);
+ while (req) {
+ mdp3_ppp_wait_for_fence(req);
+ for (i = 0; i < req->count; i++) {
+ if (!(req->req_list[i].flags & MDP_NO_BLIT)) {
+ /* Do the actual blit. */
+ rc = mdp3_ppp_start_blit(mfd,
+ &(req->req_list[i]),
+ &req->src_data[i],
+ &req->dst_data[i]);
+ if (rc)
+ break;
+ }
+ }
+ /* Signal to release fence */
+ mutex_lock(&ppp_stat->req_mutex);
+ mdp3_ppp_signal_timeline(req);
+ mdp3_ppp_req_pop(&ppp_stat->req_q);
+ req = mdp3_ppp_next_req(&ppp_stat->req_q);
+ if (ppp_stat->wait_for_pop)
+ complete(&ppp_stat->pop_q_comp);
+ mutex_unlock(&ppp_stat->req_mutex);
+ }
+ mdp3_ppp_turnon(mfd, 0);
+ mdp3_ppp_iommu_dettach();
+ mutex_unlock(&ppp_stat->config_ppp_mutex);
+}
+
+int mdp3_ppp_parse_req(void __user *p,
+ struct mdp_async_blit_req_list *req_list_header,
+ int async)
+{
+ struct blit_req_list *req;
+ struct blit_req_queue *req_q = &ppp_stat->req_q;
+ struct sync_fence *fence = NULL;
+ int count, rc, idx, i;
+ count = req_list_header->count;
+
+ mutex_lock(&ppp_stat->req_mutex);
+ while (req_q->count >= MDP3_PPP_MAX_LIST_REQ) {
+ ppp_stat->wait_for_pop = true;
+ mutex_unlock(&ppp_stat->req_mutex);
+ rc = wait_for_completion_interruptible_timeout(
+ &ppp_stat->pop_q_comp, 5 * HZ);
+ if (rc == 0) {
+ /* This will only occur if there is serious problem */
+ pr_err("%s: timeout exiting queuing request\n",
+ __func__);
+ return -EBUSY;
+ }
+ mutex_lock(&ppp_stat->req_mutex);
+ ppp_stat->wait_for_pop = false;
+ }
+ idx = req_q->push_idx;
+ req = &req_q->req[idx];
+
+ if (copy_from_user(&req->req_list, p,
+ sizeof(struct mdp_blit_req) * count))
+ return -EFAULT;
+
+ rc = mdp3_ppp_handle_buf_sync(req, &req_list_header->sync);
+ if (rc < 0) {
+ pr_err("%s: Failed create sync point\n", __func__);
+ return rc;
+ }
+ req->count = count;
+
+ /* We need to grab ion handle while client thread */
+ for (i = 0; i < count; i++) {
+ rc = mdp3_ppp_get_img(&req->req_list[i].src,
+ &req->req_list[i], &req->src_data[i]);
+ if (rc < 0 || req->src_data[i].len == 0) {
+ pr_err("mdp_ppp: couldn't retrieve src img from mem\n");
+ goto parse_err_1;
+ }
+
+ rc = mdp3_ppp_get_img(&req->req_list[i].dst,
+ &req->req_list[i], &req->dst_data[i]);
+ if (rc < 0 || req->dst_data[i].len == 0) {
+ mdp3_put_img(&req->src_data[i]);
+ pr_err("mdp_ppp: couldn't retrieve dest img from mem\n");
+ goto parse_err_1;
+ }
+ }
+
+ if (async) {
+ req->cur_rel_fen_fd = get_unused_fd_flags(0);
+ if (req->cur_rel_fen_fd < 0) {
+ pr_err("%s: get_unused_fd_flags failed\n", __func__);
+ rc = -ENOMEM;
+ goto parse_err_2;
+ }
+ sync_fence_install(req->cur_rel_fence, req->cur_rel_fen_fd);
+ rc = copy_to_user(req_list_header->sync.rel_fen_fd,
+ &req->cur_rel_fen_fd, sizeof(int));
+ if (rc) {
+ pr_err("%s:copy_to_user failed\n", __func__);
+ goto parse_err_3;
+ }
+ } else {
+ fence = req->cur_rel_fence;
+ }
+
+ mdp3_ppp_req_push(req_q, req);
+ mutex_unlock(&ppp_stat->req_mutex);
+ schedule_work(&ppp_stat->blit_work);
+ if (!async) {
+ /* wait for release fence */
+ rc = sync_fence_wait(fence,
+ 5 * MSEC_PER_SEC);
+ if (rc < 0)
+ pr_err("%s: sync blit! rc = %x\n", __func__, rc);
+
+ sync_fence_put(fence);
+ fence = NULL;
+ }
+ return 0;
+
+parse_err_3:
+ put_unused_fd(req->cur_rel_fen_fd);
+parse_err_2:
+ sync_fence_put(req->cur_rel_fence);
+ req->cur_rel_fence = NULL;
+ req->cur_rel_fen_fd = 0;
+parse_err_1:
+ for (i--; i >= 0; i--) {
+ mdp3_put_img(&req->src_data[i]);
+ mdp3_put_img(&req->dst_data[i]);
+ }
+ mdp3_ppp_deinit_buf_sync(req);
+ return rc;
+}
+
+int mdp3_ppp_res_init(struct msm_fb_data_type *mfd)
+{
+ const char timeline_name[] = "mdp3_ppp";
+ ppp_stat = kzalloc(sizeof(struct ppp_status), GFP_KERNEL);
+ if (!ppp_stat) {
+ pr_err("%s: kmalloc failed\n", __func__);
+ return -ENOMEM;
+ }
+
+ /*Setup sync_pt timeline for ppp*/
+ ppp_stat->timeline = sw_sync_timeline_create(timeline_name);
+ if (ppp_stat->timeline == NULL) {
+ pr_err("%s: cannot create time line\n", __func__);
+ return -ENOMEM;
+ } else {
+ ppp_stat->timeline_value = 1;
+ }
+
+ INIT_WORK(&ppp_stat->blit_work, mdp3_ppp_blit_wq_handler);
+ init_completion(&ppp_stat->pop_q_comp);
spin_lock_init(&ppp_stat->ppp_lock);
- mutex_init(&ppp_stat->config_mutex);
+ mutex_init(&ppp_stat->req_mutex);
+ mutex_init(&ppp_stat->config_ppp_mutex);
ppp_stat->busy = false;
+ ppp_stat->mfd = mfd;
mdp3_ppp_callback_setup();
return 0;
}
diff --git a/drivers/video/msm/mdss/mdp3_ppp.h b/drivers/video/msm/mdss/mdp3_ppp.h
index afac419..b4252ca 100644
--- a/drivers/video/msm/mdss/mdp3_ppp.h
+++ b/drivers/video/msm/mdss/mdp3_ppp.h
@@ -18,7 +18,7 @@
#define PPP_WRITEL(val, off) MDP3_REG_WRITE(off, val)
-#define MAX_BLIT_REQ 256
+#define MAX_BLIT_REQ 16
#define PPP_UPSCALE_MAX 64
#define PPP_BLUR_SCALE_MAX 128
#define PPP_LUT_MAX 256
@@ -403,11 +403,12 @@
void ppp_load_x_scale_table(int idx);
void ppp_load_y_scale_table(int idx);
-int mdp3_ppp_start_blit(struct msm_fb_data_type *mfd,
- struct mdp_blit_req *req);
-int mdp3_ppp_res_init(void);
+int mdp3_ppp_res_init(struct msm_fb_data_type *mfd);
int mdp3_ppp_init(void);
int config_ppp_op_mode(struct ppp_blit_op *blit_op);
void ppp_enable(void);
+int mdp3_ppp_parse_req(void __user *p,
+ struct mdp_async_blit_req_list *req_list_header,
+ int async);
#endif
diff --git a/drivers/video/msm/mdss/mdss_debug.c b/drivers/video/msm/mdss/mdss_debug.c
index 0918db1..13fba26 100644
--- a/drivers/video/msm/mdss/mdss_debug.c
+++ b/drivers/video/msm/mdss/mdss_debug.c
@@ -14,6 +14,7 @@
#define pr_fmt(fmt) "%s: " fmt, __func__
#include <linux/debugfs.h>
+#include <linux/iopoll.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/printk.h>
@@ -438,3 +439,151 @@
return 0;
}
+
+static struct mdss_mdp_misr_map {
+ u32 ctrl_reg;
+ u32 value_reg;
+ u32 crc_op_mode;
+ u32 crc_index;
+ u32 crc_value[MISR_CRC_BATCH_SIZE];
+} mdss_mdp_misr_table[DISPLAY_MISR_MAX] = {
+ [DISPLAY_MISR_DSI0] = {
+ .ctrl_reg = MDSS_MDP_LP_MISR_CTRL_DSI0,
+ .value_reg = MDSS_MDP_LP_MISR_SIGN_DSI0,
+ },
+ [DISPLAY_MISR_DSI1] = {
+ .ctrl_reg = MDSS_MDP_LP_MISR_CTRL_DSI1,
+ .value_reg = MDSS_MDP_LP_MISR_SIGN_DSI1,
+ },
+ [DISPLAY_MISR_EDP] = {
+ .ctrl_reg = MDSS_MDP_LP_MISR_CTRL_EDP,
+ .value_reg = MDSS_MDP_LP_MISR_SIGN_EDP,
+ },
+ [DISPLAY_MISR_HDMI] = {
+ .ctrl_reg = MDSS_MDP_LP_MISR_CTRL_HDMI,
+ .value_reg = MDSS_MDP_LP_MISR_SIGN_HDMI,
+ },
+};
+
+static inline struct mdss_mdp_misr_map *mdss_misr_get_map(u32 block_id)
+{
+ struct mdss_mdp_misr_map *map;
+
+ if (block_id > DISPLAY_MISR_LCDC) {
+ pr_err("MISR Block id (%d) out of range\n", block_id);
+ return NULL;
+ }
+
+ map = mdss_mdp_misr_table + block_id;
+ if ((map->ctrl_reg == 0) || (map->value_reg == 0)) {
+ pr_err("MISR Block id (%d) config not found\n", block_id);
+ return NULL;
+ }
+
+ return map;
+}
+
+int mdss_misr_crc_set(struct mdss_data_type *mdata, struct mdp_misr *req)
+{
+ struct mdss_mdp_misr_map *map;
+ u32 config = 0;
+
+ map = mdss_misr_get_map(req->block_id);
+ if (!map) {
+ pr_err("Invalid MISR Block=%d\n", req->block_id);
+ return -EINVAL;
+ }
+
+ map->crc_op_mode = req->crc_op_mode;
+ memset(map->crc_value, 0, sizeof(map->crc_value));
+
+ pr_debug("MISR Config (BlockId %d) (Frame Count = %d)\n",
+ req->block_id, req->frame_count);
+
+ config = (MDSS_MDP_LP_MISR_CTRL_FRAME_COUNT_MASK & req->frame_count) |
+ (MDSS_MDP_LP_MISR_CTRL_ENABLE);
+
+ writel_relaxed(MDSS_MDP_LP_MISR_CTRL_STATUS_CLEAR,
+ mdata->mdp_base + map->ctrl_reg);
+ /* ensure clear is done */
+ wmb();
+ if (MISR_OP_BM == map->crc_op_mode) {
+ writel_relaxed(MISR_CRC_BATCH_CFG,
+ mdata->mdp_base + map->ctrl_reg);
+ } else {
+ writel_relaxed(config,
+ mdata->mdp_base + map->ctrl_reg);
+
+ config = readl_relaxed(mdata->mdp_base + map->ctrl_reg);
+ pr_debug("MISR_CTRL = 0x%x", config);
+ }
+ return 0;
+}
+
+int mdss_misr_crc_get(struct mdss_data_type *mdata, struct mdp_misr *resp)
+{
+ struct mdss_mdp_misr_map *map;
+ u32 status;
+ int ret = 0;
+ int i;
+
+ map = mdss_misr_get_map(resp->block_id);
+ if (!map) {
+ pr_err("Invalid MISR Block=%d\n", resp->block_id);
+ return -EINVAL;
+ }
+
+ switch (map->crc_op_mode) {
+ case MISR_OP_SFM:
+ case MISR_OP_MFM:
+ ret = readl_poll_timeout(mdata->mdp_base + map->ctrl_reg,
+ status, status & MDSS_MDP_LP_MISR_CTRL_STATUS,
+ MISR_POLL_SLEEP, MISR_POLL_TIMEOUT);
+
+ pr_debug("Status of Get MISR_CTRL = 0x%x", status);
+ if (ret == 0) {
+ resp->crc_value[0] =
+ readl_relaxed(mdata->mdp_base + map->value_reg);
+ pr_debug("CRC %d=0x%x\n", resp->block_id,
+ resp->crc_value[0]);
+ } else {
+ pr_warn("MISR %d busy with status 0x%x\n",
+ resp->block_id, status);
+ }
+ break;
+ case MISR_OP_BM:
+ for (i = 0; i < MISR_CRC_BATCH_SIZE; i++)
+ resp->crc_value[i] = map->crc_value[i];
+ map->crc_index = 0;
+ break;
+ default:
+ ret = -ENOSYS;
+ break;
+ }
+
+ return ret;
+}
+
+/* This function is expected to be called from interrupt context */
+void mdss_misr_crc_collect(struct mdss_data_type *mdata, int block_id)
+{
+ struct mdss_mdp_misr_map *map;
+ u32 status, config;
+
+ map = mdss_misr_get_map(block_id);
+ if (!map || (map->crc_op_mode != MISR_OP_BM))
+ return;
+
+ config = MISR_CRC_BATCH_CFG;
+
+ status = readl_relaxed(mdata->mdp_base + map->ctrl_reg);
+ if (status & MDSS_MDP_LP_MISR_CTRL_STATUS) {
+ map->crc_value[map->crc_index] =
+ readl_relaxed(mdata->mdp_base + map->value_reg);
+ map->crc_index++;
+ if (map->crc_index == MISR_CRC_BATCH_SIZE)
+ map->crc_index = 0;
+ config |= MDSS_MDP_LP_MISR_CTRL_STATUS_CLEAR;
+ }
+ writel_relaxed(config, mdata->mdp_base + map->ctrl_reg);
+}
diff --git a/drivers/video/msm/mdss/mdss_debug.h b/drivers/video/msm/mdss/mdss_debug.h
index 167fa8a..29eb16c 100644
--- a/drivers/video/msm/mdss/mdss_debug.h
+++ b/drivers/video/msm/mdss/mdss_debug.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -16,24 +16,30 @@
#include "mdss.h"
+#define MISR_POLL_SLEEP 2000
+#define MISR_POLL_TIMEOUT 32000
+#define MISR_CRC_BATCH_SIZE 32
+#define MISR_CRC_BATCH_CFG 0x101
+
#ifdef CONFIG_DEBUG_FS
int mdss_debugfs_init(struct mdss_data_type *mdata);
int mdss_debugfs_remove(struct mdss_data_type *mdata);
int mdss_debug_register_base(const char *name, void __iomem *base,
size_t max_offset);
+int mdss_misr_crc_set(struct mdss_data_type *mdata, struct mdp_misr *req);
+int mdss_misr_crc_get(struct mdss_data_type *mdata, struct mdp_misr *resp);
+void mdss_misr_crc_collect(struct mdss_data_type *mdata, int block_id);
#else
-static inline int mdss_debugfs_init(struct mdss_data_type *mdata)
-{
- return 0;
-}
+static inline int mdss_debugfs_init(struct mdss_data_type *mdata) { return 0; }
static inline int mdss_debugfs_remove(struct mdss_data_type *mdata)
-{
- return 0;
-}
+{ return 0; }
static inline int mdss_debug_register_base(const char *name, void __iomem *base,
- size_t max_offset)
-{
- return 0;
-}
+ size_t max_offset) { return 0; }
+static inline int mdss_misr_crc_set(struct mdss_data_type *mdata,
+ struct mdp_misr *reg) { return 0; }
+static inline int mdss_misr_crc_get(struct mdss_data_type *mdata,
+ struct mdp_misr *resp) { return 0; }
+static inline void mdss_misr_crc_collect(struct mdss_data_type *mdata,
+ int block_id) { }
#endif
#endif /* MDSS_DEBUG_H */
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index 5445137..fbd9ef6 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -127,7 +127,6 @@
return (ret > 0) ? 0 : ret;
}
-#define MAX_BACKLIGHT_BRIGHTNESS 255
static int lcd_backlight_registered;
static void mdss_fb_set_bl_brightness(struct led_classdev *led_cdev,
@@ -136,13 +135,13 @@
struct msm_fb_data_type *mfd = dev_get_drvdata(led_cdev->dev->parent);
int bl_lvl;
- if (value > MAX_BACKLIGHT_BRIGHTNESS)
- value = MAX_BACKLIGHT_BRIGHTNESS;
+ if (value > MDSS_MAX_BL_BRIGHTNESS)
+ value = MDSS_MAX_BL_BRIGHTNESS;
/* This maps android backlight level 0 to 255 into
driver backlight level 0 to bl_max with rounding */
bl_lvl = (2 * value * mfd->panel_info->bl_max +
- MAX_BACKLIGHT_BRIGHTNESS) / (2 * MAX_BACKLIGHT_BRIGHTNESS);
+ MDSS_MAX_BL_BRIGHTNESS) / (2 * MDSS_MAX_BL_BRIGHTNESS);
if (!bl_lvl && value)
bl_lvl = 1;
@@ -154,7 +153,7 @@
static struct led_classdev backlight_led = {
.name = "lcd-backlight",
- .brightness = MAX_BACKLIGHT_BRIGHTNESS,
+ .brightness = MDSS_MAX_BL_BRIGHTNESS,
.brightness_set = mdss_fb_set_bl_brightness,
};
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.c b/drivers/video/msm/mdss/mdss_hdmi_tx.c
index fe10189..287f2cd 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.c
@@ -391,6 +391,10 @@
return rc;
}
+ if (hdmi_ctrl->mhl_max_pclk && hpd &&
+ (!hdmi_ctrl->mhl_hpd_on || hdmi_ctrl->hpd_feature_on))
+ return 0;
+
if (0 == hpd && hdmi_ctrl->hpd_feature_on) {
rc = hdmi_tx_sysfs_enable_hpd(hdmi_ctrl, false);
} else if (1 == hpd && !hdmi_ctrl->hpd_feature_on) {
@@ -2508,6 +2512,9 @@
return -EINVAL;
}
+ /* mhl status should override */
+ hdmi_ctrl->mhl_hpd_on = on;
+
if (!on && hdmi_ctrl->hpd_feature_on) {
rc = hdmi_tx_sysfs_enable_hpd(hdmi_ctrl, false);
} else if (on && !hdmi_ctrl->hpd_feature_on) {
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.h b/drivers/video/msm/mdss/mdss_hdmi_tx.h
index ce3c00c..d4f8e67 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.h
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -62,6 +62,7 @@
u32 hpd_initialized;
u8 timing_gen_on;
u32 mhl_max_pclk;
+ u8 mhl_hpd_on;
struct completion hpd_done;
struct work_struct hpd_int_work;
diff --git a/drivers/video/msm/mdss/mdss_io_util.c b/drivers/video/msm/mdss/mdss_io_util.c
index ff52e4c..809db43 100644
--- a/drivers/video/msm/mdss/mdss_io_util.c
+++ b/drivers/video/msm/mdss/mdss_io_util.c
@@ -276,15 +276,17 @@
DEV_DBG("%pS->%s: %s disable\n",
__builtin_return_address(0), __func__,
in_gpio[i].gpio_name);
-
- gpio_free(in_gpio[i].gpio);
+ if (in_gpio[i].gpio)
+ gpio_free(in_gpio[i].gpio);
}
}
return rc;
disable_gpio:
for (i--; i >= 0; i--)
- gpio_free(in_gpio[i].gpio);
+ if (in_gpio[i].gpio)
+ gpio_free(in_gpio[i].gpio);
+
return rc;
} /* msm_dss_enable_gpio */
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index 772545f..d8ca555 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -977,6 +977,7 @@
goto probe_done;
}
mdata->irq = res->start;
+ mdss_mdp_hw.ptr = mdata;
/*populate hw iomem base info from device tree*/
rc = mdss_mdp_parse_dt(pdev);
@@ -1023,6 +1024,7 @@
probe_done:
if (IS_ERR_VALUE(rc)) {
+ mdss_mdp_hw.ptr = NULL;
mdss_res = NULL;
mdss_mdp_pp_term(&pdev->dev);
}
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index f3b5acec..d9ec19b 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -157,6 +157,7 @@
int (*prepare_fnc) (struct mdss_mdp_ctl *ctl, void *arg);
int (*display_fnc) (struct mdss_mdp_ctl *ctl, void *arg);
int (*wait_fnc) (struct mdss_mdp_ctl *ctl, void *arg);
+ int (*wait_pingpong) (struct mdss_mdp_ctl *ctl, void *arg);
u32 (*read_line_cnt_fnc) (struct mdss_mdp_ctl *);
int (*add_vsync_handler) (struct mdss_mdp_ctl *,
struct mdss_mdp_vsync_handler *);
@@ -264,6 +265,9 @@
u32 last_str;
u32 last_bl;
u32 calc_itr;
+ uint32_t bl_bright_shift;
+ uint32_t bl_lin[AD_BL_LIN_LEN];
+ uint32_t bl_lin_inv[AD_BL_LIN_LEN];
};
struct pp_sts_type {
@@ -436,6 +440,7 @@
int mdss_mdp_mixer_pipe_unstage(struct mdss_mdp_pipe *pipe);
int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg);
int mdss_mdp_display_wait4comp(struct mdss_mdp_ctl *ctl);
+int mdss_mdp_display_wait4pingpong(struct mdss_mdp_ctl *ctl);
int mdss_mdp_display_wakeup_time(struct mdss_mdp_ctl *ctl,
ktime_t *wakeup_time);
@@ -503,6 +508,7 @@
int mdss_mdp_smp_reserve(struct mdss_mdp_pipe *pipe);
void mdss_mdp_smp_unreserve(struct mdss_mdp_pipe *pipe);
+void mdss_mdp_smp_release(struct mdss_mdp_pipe *pipe);
int mdss_mdp_pipe_addr_setup(struct mdss_data_type *mdata, u32 *offsets,
u32 *ftch_y_id, u32 type, u32 num_base, u32 len);
@@ -536,6 +542,7 @@
int mdss_panel_register_done(struct mdss_panel_data *pdata);
int mdss_mdp_limited_lut_igc_config(struct mdss_mdp_ctl *ctl);
+int mdss_mdp_calib_config(struct mdp_calib_config_data *cfg, u32 *copyback);
#define mfd_to_mdp5_data(mfd) (mfd->mdp.private1)
#define mfd_to_mdata(mfd) (((struct mdss_overlay_private *)\
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index 4b763aa..5d9050c 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -1442,6 +1442,27 @@
return ret;
}
+int mdss_mdp_display_wait4pingpong(struct mdss_mdp_ctl *ctl)
+{
+ int ret;
+
+ ret = mutex_lock_interruptible(&ctl->lock);
+ if (ret)
+ return ret;
+
+ if (!ctl->power_on) {
+ mutex_unlock(&ctl->lock);
+ return 0;
+ }
+
+ if (ctl->wait_pingpong)
+ ret = ctl->wait_pingpong(ctl, NULL);
+
+ mutex_unlock(&ctl->lock);
+
+ return ret;
+}
+
int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg)
{
struct mdss_mdp_ctl *sctl = NULL;
diff --git a/drivers/video/msm/mdss/mdss_mdp_hwio.h b/drivers/video/msm/mdss/mdss_mdp_hwio.h
index 6ec5b63..741c7a7 100644
--- a/drivers/video/msm/mdss/mdss_mdp_hwio.h
+++ b/drivers/video/msm/mdss/mdss_mdp_hwio.h
@@ -515,4 +515,33 @@
MDSS_MDP_SMP_CLIENT_RGB2_FETCH,
};
-#endif /* MDSS_MDP_HWIO_H */
+#define MDSS_MDP_LP_MISR_SEL 0x450
+#define MDSS_MDP_LP_MISR_CTRL_MDP 0x454
+#define MDSS_MDP_LP_MISR_CTRL_HDMI 0x458
+#define MDSS_MDP_LP_MISR_CTRL_EDP 0x45C
+#define MDSS_MDP_LP_MISR_CTRL_DSI0 0x460
+#define MDSS_MDP_LP_MISR_CTRL_DSI1 0x464
+
+#define MDSS_MDP_LP_MISR_SIGN_MDP 0x468
+#define MDSS_MDP_LP_MISR_SIGN_EDP 0x46C
+#define MDSS_MDP_LP_MISR_SIGN_HDMI 0x470
+#define MDSS_MDP_LP_MISR_SIGN_DSI0 0x474
+#define MDSS_MDP_LP_MISR_SIGN_DSI1 0x478
+
+#define MDSS_MDP_LP_MISR_CTRL_FRAME_COUNT_MASK 0xFF
+#define MDSS_MDP_LP_MISR_CTRL_ENABLE BIT(8)
+#define MDSS_MDP_LP_MISR_CTRL_STATUS BIT(9)
+#define MDSS_MDP_LP_MISR_CTRL_STATUS_CLEAR BIT(10)
+
+#define MDSS_MDP_LP_MISR_SEL_LMIX0_BLEND 0x08
+#define MDSS_MDP_LP_MISR_SEL_LMIX0_GC 0x09
+#define MDSS_MDP_LP_MISR_SEL_LMIX1_BLEND 0x0A
+#define MDSS_MDP_LP_MISR_SEL_LMIX1_GC 0x0B
+#define MDSS_MDP_LP_MISR_SEL_LMIX2_BLEND 0x0C
+#define MDSS_MDP_LP_MISR_SEL_LMIX2_GC 0x0D
+#define MDSS_MDP_LP_MISR_SEL_LMIX3_BLEND 0x0E
+#define MDSS_MDP_LP_MISR_SEL_LMIX3_GC 0x0F
+#define MDSS_MDP_LP_MISR_SEL_LMIX4_BLEND 0x10
+#define MDSS_MDP_LP_MISR_SEL_LMIX4_GC 0x11
+
+#endif
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
index afbbe55..238170d 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
@@ -335,32 +335,12 @@
mutex_unlock(&ctx->clk_mtx);
}
-static int mdss_mdp_cmd_wait4comp(struct mdss_mdp_ctl *ctl, void *arg)
-{
- struct mdss_mdp_cmd_ctx *ctx;
- int rc;
-
- ctx = (struct mdss_mdp_cmd_ctx *) ctl->priv_data;
- if (!ctx) {
- pr_err("invalid ctx\n");
- return -ENODEV;
- }
-
- pr_debug("%s: intf_num=%d ctx=%p\n", __func__, ctl->intf_num, ctx);
-
- rc = wait_for_completion_interruptible_timeout(&ctx->vsync_comp,
- KOFF_TIMEOUT);
- WARN(rc <= 0, "cmd kickoff timed out (%d) ctl=%d\n", rc, ctl->num);
-
- return 0;
-}
-
-int mdss_mdp_cmd_kickoff(struct mdss_mdp_ctl *ctl, void *arg)
+static int mdss_mdp_cmd_wait4pingpong(struct mdss_mdp_ctl *ctl, void *arg)
{
struct mdss_mdp_cmd_ctx *ctx;
unsigned long flags;
int need_wait = 0;
- int rc;
+ int rc = 0;
ctx = (struct mdss_mdp_cmd_ctx *) ctl->priv_data;
if (!ctx) {
@@ -377,11 +357,29 @@
__func__, need_wait, ctl->intf_num, ctx);
if (need_wait) {
- rc = wait_for_completion_interruptible_timeout(
+ rc = wait_for_completion_timeout(
&ctx->pp_comp, KOFF_TIMEOUT);
- WARN(rc <= 0, "cmd kickoff timed out (%d) ctl=%d\n",
+ if (rc <= 0) {
+ WARN(1, "cmd kickoff timed out (%d) ctl=%d\n",
rc, ctl->num);
+ rc = -EPERM;
+ } else
+ rc = 0;
+ }
+
+ return rc;
+}
+
+int mdss_mdp_cmd_kickoff(struct mdss_mdp_ctl *ctl, void *arg)
+{
+ struct mdss_mdp_cmd_ctx *ctx;
+ int rc;
+
+ ctx = (struct mdss_mdp_cmd_ctx *) ctl->priv_data;
+ if (!ctx) {
+ pr_err("invalid ctx\n");
+ return -ENODEV;
}
if (ctx->panel_on == 0) {
@@ -456,6 +454,12 @@
ret = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_PANEL_OFF, NULL);
WARN(ret, "intf %d unblank error (%d)\n", ctl->intf_num, ret);
+ ctl->stop_fnc = NULL;
+ ctl->display_fnc = NULL;
+ ctl->wait_pingpong = NULL;
+ ctl->add_vsync_handler = NULL;
+ ctl->remove_vsync_handler = NULL;
+
pr_debug("%s:-\n", __func__);
return 0;
@@ -519,7 +523,7 @@
ctl->stop_fnc = mdss_mdp_cmd_stop;
ctl->display_fnc = mdss_mdp_cmd_kickoff;
- ctl->wait_fnc = mdss_mdp_cmd_wait4comp;
+ ctl->wait_pingpong = mdss_mdp_cmd_wait4pingpong;
ctl->add_vsync_handler = mdss_mdp_cmd_vsync_ctrl;
ctl->remove_vsync_handler = mdss_mdp_cmd_vsync_ctrl;
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index 4a03e13..0152d87 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -27,6 +27,7 @@
#include <mach/event_timer.h>
#include "mdss.h"
+#include "mdss_debug.h"
#include "mdss_fb.h"
#include "mdss_mdp.h"
#include "mdss_mdp_rotator.h"
@@ -701,6 +702,14 @@
mutex_lock(&mdp5_data->ov_lock);
mutex_lock(&mfd->lock);
+
+ ret = mdss_mdp_display_wait4pingpong(mdp5_data->ctl);
+ if (ret) {
+ mutex_unlock(&mfd->lock);
+ mutex_unlock(&mdp5_data->ov_lock);
+ return ret;
+ }
+
list_for_each_entry(pipe, &mdp5_data->pipes_used, used_list) {
struct mdss_mdp_data *buf;
if (pipe->back_buf.num_planes) {
@@ -1548,8 +1557,13 @@
copyback = 1;
}
break;
+ case mdp_op_calib_cfg:
+ ret = mdss_mdp_calib_config((struct mdp_calib_config_data *)
+ &mdp_pp.data.calib_cfg, ©back);
+ break;
default:
- pr_err("Unsupported request to MDP_PP IOCTL.\n");
+ pr_err("Unsupported request to MDP_PP IOCTL. %d = op\n",
+ mdp_pp.op);
ret = -EINVAL;
break;
}
@@ -1608,6 +1622,7 @@
static int mdss_fb_set_metadata(struct msm_fb_data_type *mfd,
struct msmfb_metadata *metadata)
{
+ struct mdss_data_type *mdata = mfd_to_mdata(mfd);
int ret = 0;
switch (metadata->op) {
case metadata_op_vic:
@@ -1617,6 +1632,11 @@
else
ret = -EINVAL;
break;
+ case metadata_op_crc:
+ if (!mfd->panel_power_on)
+ return -EPERM;
+ ret = mdss_misr_crc_set(mdata, &metadata->data.misr_request);
+ break;
default:
pr_warn("unsupported request to MDP META IOCTL\n");
ret = -EINVAL;
@@ -1643,6 +1663,7 @@
static int mdss_fb_get_metadata(struct msm_fb_data_type *mfd,
struct msmfb_metadata *metadata)
{
+ struct mdss_data_type *mdata = mfd_to_mdata(mfd);
int ret = 0;
switch (metadata->op) {
case metadata_op_frame_rate:
@@ -1652,6 +1673,11 @@
case metadata_op_get_caps:
ret = mdss_fb_get_hw_caps(mfd, &metadata->data.caps);
break;
+ case metadata_op_crc:
+ if (!mfd->panel_power_on)
+ return -EPERM;
+ ret = mdss_misr_crc_get(mdata, &metadata->data.misr_request);
+ break;
default:
pr_warn("Unsupported request to MDP META IOCTL.\n");
ret = -EINVAL;
diff --git a/drivers/video/msm/mdss/mdss_mdp_pipe.c b/drivers/video/msm/mdss/mdss_mdp_pipe.c
index 4f9ab81..3ae01dc 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pipe.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pipe.c
@@ -139,7 +139,7 @@
u32 num_blks = 0, reserved = 0;
struct mdss_mdp_plane_sizes ps;
int i;
- int rc = 0;
+ int rc = 0, rot_mode = 0;
u32 nlines;
if (pipe->bwc_mode) {
@@ -153,23 +153,32 @@
ps.num_planes = 2;
ps.ystride[0] = pipe->src.w >> pipe->horz_deci;
ps.ystride[1] = pipe->src.h >> pipe->vert_deci;
- } else if (pipe->src_fmt->fetch_planes == MDSS_MDP_PLANE_INTERLEAVED) {
- ps.ystride[0] = max(pipe->mixer->width, pipe->src.w) * MAX_BPP;
- ps.num_planes = 1;
} else {
rc = mdss_mdp_get_plane_sizes(pipe->src_fmt->format,
pipe->src.w, pipe->src.h, &ps, 0);
if (rc)
return rc;
+
+ if (pipe->mixer && pipe->mixer->rotator_mode)
+ rot_mode = 1;
+ else if (ps.num_planes == 1)
+ ps.ystride[0] = MAX_BPP *
+ max(pipe->mixer->width, pipe->src.w);
}
+ nlines = pipe->bwc_mode ? 1 : 2;
+
mutex_lock(&mdss_mdp_smp_lock);
for (i = 0; i < ps.num_planes; i++) {
- nlines = pipe->bwc_mode ? ps.rau_h[i] : 2;
- num_blks = DIV_ROUND_UP(nlines * ps.ystride[i], SMP_MB_SIZE);
+ if (rot_mode) {
+ num_blks = 1;
+ } else {
+ num_blks = DIV_ROUND_UP(ps.ystride[i] * nlines,
+ SMP_MB_SIZE);
- if (mdata->mdp_rev == MDSS_MDP_HW_REV_100)
- num_blks = roundup_pow_of_two(num_blks);
+ if (mdata->mdp_rev == MDSS_MDP_HW_REV_100)
+ num_blks = roundup_pow_of_two(num_blks);
+ }
pr_debug("reserving %d mmb for pnum=%d plane=%d\n",
num_blks, pipe->num, i);
@@ -206,6 +215,13 @@
return 0;
}
+void mdss_mdp_smp_release(struct mdss_mdp_pipe *pipe)
+{
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+ mdss_mdp_smp_free(pipe);
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+}
+
int mdss_mdp_smp_setup(struct mdss_data_type *mdata, u32 cnt, u32 size)
{
if (!mdata)
diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c
index 9d28265..13c01af 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pp.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -190,6 +190,7 @@
#define PP_AD_STATE_DATA 0x8
#define PP_AD_STATE_RUN 0x10
#define PP_AD_STATE_VSYNC 0x20
+#define PP_AD_STATE_BL_LIN 0x40
#define PP_AD_STATE_IS_INITCFG(st) (((st) & PP_AD_STATE_INIT) &&\
((st) & PP_AD_STATE_CFG))
@@ -217,6 +218,8 @@
#define MDSS_AD_MODE_DATA_MATCH(mode, data) ((1 << (mode)) & (data))
#define MDSS_AD_RUNNING_AUTO_BL(ad) (((ad)->state & PP_AD_STATE_RUN) &&\
((ad)->cfg.mode == MDSS_AD_MODE_AUTO_BL))
+#define MDSS_AD_RUNNING_AUTO_STR(ad) (((ad)->state & PP_AD_STATE_RUN) &&\
+ ((ad)->cfg.mode == MDSS_AD_MODE_AUTO_STR))
#define SHARP_STRENGTH_DEFAULT 32
#define SHARP_EDGE_THR_DEFAULT 112
@@ -1199,7 +1202,7 @@
*/
int mdss_mdp_pp_resume(struct mdss_mdp_ctl *ctl, u32 dspp_num)
{
- u32 flags = 0, disp_num;
+ u32 flags = 0, disp_num, bl;
struct pp_sts_type pp_sts;
struct mdss_ad_info *ad;
struct mdss_data_type *mdata = ctl->mdata;
@@ -1216,8 +1219,15 @@
pp_ad_cfg_write(ad);
if (PP_AD_STATE_INIT & ad->state)
pp_ad_init_write(ad);
- if (PP_AD_STATE_DATA & ad->state)
- pp_ad_input_write(ad, ctl->mfd->bl_level);
+ if (PP_AD_STATE_DATA & ad->state) {
+ bl = ctl->mfd->bl_level;
+ ad->last_bl = bl;
+ if (ad->state & PP_AD_STATE_BL_LIN) {
+ bl = ad->bl_lin[bl >> ad->bl_bright_shift];
+ bl = bl << ad->bl_bright_shift;
+ }
+ pp_ad_input_write(ad, bl);
+ }
if ((PP_AD_STATE_VSYNC & ad->state) && ad->calc_itr)
ctl->add_vsync_handler(ctl, &ad->handle);
}
@@ -1652,6 +1662,9 @@
(config->block >= MDP_BLOCK_MAX))
return -EINVAL;
+ if (config->len != IGC_LUT_ENTRIES)
+ return -EINVAL;
+
mutex_lock(&mdss_pp_mutex);
disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0;
@@ -2744,7 +2757,7 @@
struct mdss_ad_input input;
ad = mdss_mdp_get_ad(mfd);
- if (!ad)
+ if (!ad || ad->cfg.mode == MDSS_AD_MODE_AUTO_BL)
return -EINVAL;
pr_debug("backlight level changed, trigger update to AD");
@@ -2762,6 +2775,8 @@
{
struct mdss_ad_info *ad;
struct mdss_mdp_ctl *ctl;
+ int lin_ret = -1, inv_ret = -1, ret = 0;
+ u32 ratio_temp, shift = 0;
ad = mdss_mdp_get_ad(mfd);
if (!ad)
@@ -2771,6 +2786,29 @@
if (init_cfg->ops & MDP_PP_AD_INIT) {
memcpy(&ad->init, &init_cfg->params.init,
sizeof(struct mdss_ad_init));
+ if (init_cfg->params.init.bl_lin_len == AD_BL_LIN_LEN) {
+ lin_ret = copy_from_user(&ad->bl_lin,
+ init_cfg->params.init.bl_lin,
+ AD_BL_LIN_LEN * sizeof(uint32_t));
+ inv_ret = copy_from_user(&ad->bl_lin_inv,
+ init_cfg->params.init.bl_lin_inv,
+ AD_BL_LIN_LEN * sizeof(uint32_t));
+ if (lin_ret || inv_ret)
+ ret = -ENOMEM;
+ ratio_temp = mfd->panel_info->bl_max / AD_BL_LIN_LEN;
+ while (ratio_temp > 0) {
+ ratio_temp = ratio_temp >> 1;
+ shift++;
+ }
+ ad->bl_bright_shift = shift;
+ } else if (init_cfg->params.init.bl_lin_len) {
+ ret = -EINVAL;
+ }
+ if (!lin_ret && !inv_ret)
+ ad->state |= PP_AD_STATE_BL_LIN;
+ else
+ ad->state &= !PP_AD_STATE_BL_LIN;
+
ad->sts |= PP_AD_STS_DIRTY_INIT;
} else if (init_cfg->ops & MDP_PP_AD_CFG) {
memcpy(&ad->cfg, &init_cfg->params.cfg,
@@ -2783,17 +2821,21 @@
ad->sts |= PP_AD_STS_DIRTY_CFG;
}
- if (init_cfg->ops & MDP_PP_OPS_DISABLE) {
+ if (!ret && (init_cfg->ops & MDP_PP_OPS_DISABLE)) {
ad->sts &= ~PP_STS_ENABLE;
+ mutex_unlock(&ad->lock);
+ cancel_work_sync(&ad->calc_work);
+ mutex_lock(&ad->lock);
ad->mfd = NULL;
- } else if (init_cfg->ops & MDP_PP_OPS_ENABLE) {
+ } else if (!ret && (init_cfg->ops & MDP_PP_OPS_ENABLE)) {
ad->sts |= PP_STS_ENABLE;
ad->mfd = mfd;
}
mutex_unlock(&ad->lock);
ctl = mfd_to_ctl(mfd);
- mdss_mdp_pp_setup(ctl);
- return 0;
+ if (!ret)
+ mdss_mdp_pp_setup(ctl);
+ return ret;
}
int mdss_mdp_ad_input(struct msm_fb_data_type *mfd,
@@ -2992,7 +3034,7 @@
struct mdss_ad_info *ad;
struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd);
char __iomem *base;
- u32 bypass = MDSS_PP_AD_BYPASS_DEF;
+ u32 bypass = MDSS_PP_AD_BYPASS_DEF, bl;
ad = mdss_mdp_get_ad(mfd);
if (!ad)
@@ -3008,9 +3050,7 @@
ad->state);
}
if (!PP_AD_STS_IS_DIRTY(ad->sts) &&
- (ad->sts & PP_AD_STS_DIRTY_DATA ||
- (ad->state & PP_AD_STATE_RUN &&
- (ad->cfg.mode == MDSS_AD_MODE_AUTO_STR)))) {
+ (ad->sts & PP_AD_STS_DIRTY_DATA)) {
/*
* Write inputs to regs when the data has been updated or
* Assertive Display is up and running as long as there are
@@ -3018,12 +3058,22 @@
*/
ad->sts &= ~PP_AD_STS_DIRTY_DATA;
ad->state |= PP_AD_STATE_DATA;
- if (mfd->bl_level != ad->last_bl) {
- ad->last_bl = mfd->bl_level;
- ad->calc_itr = ad->cfg.stab_itr;
- ad->sts |= PP_AD_STS_DIRTY_VSYNC;
+ bl = 0;
+ if (MDSS_AD_RUNNING_AUTO_STR(ad) || ad->last_bl == 0) {
+ mutex_lock(&mfd->bl_lock);
+ bl = mfd->bl_level;
+ if (bl != ad->last_bl) {
+ ad->last_bl = bl;
+ ad->calc_itr = ad->cfg.stab_itr;
+ ad->sts |= PP_AD_STS_DIRTY_VSYNC;
+ }
+ if (ad->state & PP_AD_STATE_BL_LIN) {
+ bl = ad->bl_lin[bl >> ad->bl_bright_shift];
+ bl = bl << ad->bl_bright_shift;
+ }
+ mutex_unlock(&mfd->bl_lock);
}
- pp_ad_input_write(ad, mfd->bl_level);
+ pp_ad_input_write(ad, bl);
}
if (ad->sts & PP_AD_STS_DIRTY_CFG) {
@@ -3055,7 +3105,23 @@
} else {
if (ad->state & PP_AD_STATE_RUN) {
ret = 1;
+ /* Clear state and regs when going to off state*/
+ ad->sts = 0;
ad->sts |= PP_AD_STS_DIRTY_VSYNC;
+ ad->state &= !PP_AD_STATE_INIT;
+ ad->state &= !PP_AD_STATE_CFG;
+ ad->state &= !PP_AD_STATE_DATA;
+ ad->state &= !PP_AD_STATE_BL_LIN;
+ ad->bl_bright_shift = 0;
+ ad->ad_data = 0;
+ ad->ad_data_mode = 0;
+ ad->calc_itr = 0;
+ memset(&ad->bl_lin, 0, sizeof(uint32_t) *
+ AD_BL_LIN_LEN);
+ memset(&ad->bl_lin_inv, 0, sizeof(uint32_t) *
+ AD_BL_LIN_LEN);
+ memset(&ad->init, 0, sizeof(struct mdss_ad_init));
+ memset(&ad->cfg, 0, sizeof(struct mdss_ad_cfg));
mutex_lock(&mfd->bl_lock);
mfd->mdp.update_ad_input = NULL;
mutex_unlock(&mfd->bl_lock);
@@ -3067,7 +3133,8 @@
if (PP_AD_STS_DIRTY_VSYNC & ad->sts) {
pr_debug("dirty vsync, calc_itr = %d", ad->calc_itr);
ad->sts &= ~PP_AD_STS_DIRTY_VSYNC;
- if (!(PP_AD_STATE_VSYNC & ad->state) && ad->calc_itr) {
+ if (!(PP_AD_STATE_VSYNC & ad->state) && ad->calc_itr &&
+ (ad->state & PP_AD_STATE_RUN)) {
ctl->add_vsync_handler(ctl, &ad->handle);
ad->state |= PP_AD_STATE_VSYNC;
} else if ((PP_AD_STATE_VSYNC & ad->state) &&
@@ -3092,11 +3159,18 @@
{
struct mdss_ad_info *ad;
struct mdss_mdp_ctl *ctl;
+ struct msm_fb_data_type *mfd;
u32 bl, calc_done = 0;
ad = container_of(work, struct mdss_ad_info, calc_work);
- ctl = mfd_to_ctl(ad->mfd);
mutex_lock(&ad->lock);
+ if (!ad->mfd || !(ad->sts & PP_STS_ENABLE)) {
+ mutex_unlock(&ad->lock);
+ return;
+ }
+ mfd = ad->mfd;
+ ctl = mfd_to_ctl(ad->mfd);
+
if (PP_AD_STATE_RUN & ad->state) {
/* Kick off calculation */
ad->calc_itr--;
@@ -3115,6 +3189,13 @@
if (MDSS_AD_RUNNING_AUTO_BL(ad)) {
bl = 0xFFFF & readl_relaxed(ad->base +
MDSS_MDP_REG_AD_BL_OUT);
+ if (ad->state & PP_AD_STATE_BL_LIN) {
+ bl = bl >> ad->bl_bright_shift;
+ bl = min_t(u32, bl,
+ MDSS_MAX_BL_BRIGHTNESS);
+ bl = ad->bl_lin_inv[bl];
+ bl = bl << ad->bl_bright_shift;
+ }
pr_debug("calc bl = %d", bl);
ad->last_str |= bl << 16;
mutex_lock(&ad->mfd->bl_lock);
@@ -3135,9 +3216,9 @@
ctl->remove_vsync_handler(ctl, &ad->handle);
}
mutex_unlock(&ad->lock);
- mutex_lock(&ad->mfd->lock);
+ mutex_lock(&mfd->lock);
mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_FLUSH, BIT(13 + ad->num));
- mutex_unlock(&ad->mfd->lock);
+ mutex_unlock(&mfd->lock);
}
#define PP_AD_LUT_LEN 33
@@ -3181,3 +3262,88 @@
}
return rc;
}
+
+static int is_valid_calib_addr(void *addr)
+{
+ int ret = 0;
+ unsigned int ptr;
+ ptr = (unsigned int) addr;
+ /* if request is outside the MDP reg-map or is not aligned 4 */
+ if (ptr == 0x0 || ptr > 0x5138 || ptr % 0x4)
+ goto end;
+ if (ptr >= 0x100 && ptr <= 0x5138) {
+ /* if ptr is in dspp range */
+ if (ptr >= 0x4600 && ptr <= 0x5138) {
+ /* if ptr is in dspp0 range*/
+ if (ptr >= 0x4600 && ptr <= 0x4938)
+ ptr -= 0x4600;
+ /* if ptr is in dspp1 range */
+ else if (ptr >= 0x4a00 && ptr <= 0x4d38)
+ ptr -= 0x4a00;
+ /* if ptr is in dspp2 range */
+ else if (ptr >= 0x4e00 && ptr <= 0x5138)
+ ptr -= 0x4e00;
+ /* if ptr is in pcc plane rgb coeff.range */
+ if (ptr >= 0x30 && ptr <= 0xe8)
+ ret = 1;
+ /* if ptr is in ARLUT red range */
+ else if (ptr >= 0x2b0 && ptr <= 0x2b8)
+ ret = 1;
+ /* if ptr is in PA range */
+ else if (ptr >= 0x238 && ptr <= 0x244)
+ ret = 1;
+ /* if ptr is in ARLUT green range */
+ else if (ptr >= 0x2c0 && ptr <= 0x2c8)
+ ret = 1;
+ /* if ptr is in ARLUT blue range or
+ gamut map table range */
+ else if (ptr >= 0x2d0 && ptr <= 0x338)
+ ret = 1;
+ /* if ptr is dspp0,dspp1,dspp2 op mode
+ register */
+ else if (ptr == 0)
+ ret = 1;
+ } else if (ptr >= 0x600 && ptr <= 0x608)
+ ret = 1;
+ else if (ptr >= 0x400 && ptr <= 0x408)
+ ret = 1;
+ else if ((ptr == 0x1830) || (ptr == 0x1c30) ||
+ (ptr == 0x1430) || (ptr == 0x1e38))
+ ret = 1;
+ else if ((ptr == 0x1e3c) || (ptr == 0x1e30))
+ ret = 1;
+ else if (ptr >= 0x3220 && ptr <= 0x3228)
+ ret = 1;
+ else if (ptr >= 0x3200 || ptr == 0x100)
+ ret = 1;
+ }
+end:
+ return ret;
+}
+
+
+
+
+int mdss_mdp_calib_config(struct mdp_calib_config_data *cfg, u32 *copyback)
+{
+ int ret = -1;
+ void *ptr = (void *) cfg->addr;
+
+ if (is_valid_calib_addr(ptr))
+ ret = 0;
+ else
+ return ret;
+ ptr = (void *)(((unsigned int) ptr) + (mdss_res->mdp_base));
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+
+ if (cfg->ops & MDP_PP_OPS_READ) {
+ cfg->data = readl_relaxed(ptr);
+ *copyback = 1;
+ ret = 0;
+ } else if (cfg->ops & MDP_PP_OPS_WRITE) {
+ writel_relaxed(cfg->data, ptr);
+ ret = 0;
+ }
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+ return ret;
+}
diff --git a/drivers/video/msm/mdss/mdss_mdp_rotator.c b/drivers/video/msm/mdss/mdss_mdp_rotator.c
index 5d9396a..f9894cc 100644
--- a/drivers/video/msm/mdss/mdss_mdp_rotator.c
+++ b/drivers/video/msm/mdss/mdss_mdp_rotator.c
@@ -99,6 +99,7 @@
pr_debug("waiting for rot=%d to complete\n", rot->pipe->num);
mdss_mdp_display_wait4comp(ctl);
rot->busy = false;
+ mdss_mdp_smp_release(rot->pipe);
}
mutex_unlock(&rot->lock);
diff --git a/drivers/video/msm/mdss/mdss_mdp_util.c b/drivers/video/msm/mdss/mdss_mdp_util.c
index d1f0c8d..27b2104 100644
--- a/drivers/video/msm/mdss/mdss_mdp_util.c
+++ b/drivers/video/msm/mdss/mdss_mdp_util.c
@@ -27,7 +27,7 @@
#include "mdss_fb.h"
#include "mdss_mdp.h"
#include "mdss_mdp_formats.h"
-
+#include "mdss_debug.h"
#define DEFAULT_FRAME_RATE 60
enum {
@@ -124,6 +124,7 @@
irqreturn_t mdss_mdp_isr(int irq, void *ptr)
{
+ struct mdss_data_type *mdata = ptr;
u32 isr, mask, hist_isr, hist_mask;
@@ -172,17 +173,25 @@
if (isr & MDSS_MDP_INTR_PING_PONG_2_RD_PTR)
mdss_mdp_intr_done(MDP_INTR_PING_PONG_2_RD_PTR);
- if (isr & MDSS_MDP_INTR_INTF_0_VSYNC)
+ if (isr & MDSS_MDP_INTR_INTF_0_VSYNC) {
mdss_mdp_intr_done(MDP_INTR_VSYNC_INTF_0);
+ mdss_misr_crc_collect(mdata, DISPLAY_MISR_EDP);
+ }
- if (isr & MDSS_MDP_INTR_INTF_1_VSYNC)
+ if (isr & MDSS_MDP_INTR_INTF_1_VSYNC) {
mdss_mdp_intr_done(MDP_INTR_VSYNC_INTF_1);
+ mdss_misr_crc_collect(mdata, DISPLAY_MISR_DSI0);
+ }
- if (isr & MDSS_MDP_INTR_INTF_2_VSYNC)
+ if (isr & MDSS_MDP_INTR_INTF_2_VSYNC) {
mdss_mdp_intr_done(MDP_INTR_VSYNC_INTF_2);
+ mdss_misr_crc_collect(mdata, DISPLAY_MISR_DSI1);
+ }
- if (isr & MDSS_MDP_INTR_INTF_3_VSYNC)
+ if (isr & MDSS_MDP_INTR_INTF_3_VSYNC) {
mdss_mdp_intr_done(MDP_INTR_VSYNC_INTF_3);
+ mdss_misr_crc_collect(mdata, DISPLAY_MISR_HDMI);
+ }
if (isr & MDSS_MDP_INTR_WB_0_DONE)
mdss_mdp_intr_done(MDP_INTR_WB_0);
@@ -225,7 +234,6 @@
struct mdss_mdp_format_params *fmt,
struct mdss_mdp_plane_sizes *ps)
{
- u32 stride_off;
if (fmt->is_yuv) {
ps->rau_cnt = DIV_ROUND_UP(w, 64);
ps->ystride[0] = 64 * 4;
@@ -249,9 +257,8 @@
return -EINVAL;
}
- stride_off = DIV_ROUND_UP(ps->rau_cnt, 8);
- ps->ystride[0] = ps->ystride[0] * ps->rau_cnt + stride_off;
- ps->ystride[1] = ps->ystride[1] * ps->rau_cnt + stride_off;
+ ps->ystride[0] *= ps->rau_cnt;
+ ps->ystride[1] *= ps->rau_cnt;
ps->num_planes = 2;
return 0;
@@ -277,9 +284,16 @@
memset(ps, 0, sizeof(struct mdss_mdp_plane_sizes));
if (bwc_mode) {
+ u32 meta_size;
+
rc = mdss_mdp_get_rau_strides(w, h, fmt, ps);
if (rc)
return rc;
+
+ meta_size = DIV_ROUND_UP(ps->rau_cnt, 8);
+ ps->ystride[0] += meta_size;
+ ps->ystride[1] += meta_size;
+
ystride0_off = DIV_ROUND_UP(h, ps->rau_h[0]);
ystride1_off = DIV_ROUND_UP(h, ps->rau_h[1]);
ps->plane_size[0] = (ps->ystride[0] * ystride0_off) +
diff --git a/drivers/video/msm/mdss/mhl_sii8334.c b/drivers/video/msm/mdss/mhl_sii8334.c
index a1053fb..9cae431 100644
--- a/drivers/video/msm/mdss/mhl_sii8334.c
+++ b/drivers/video/msm/mdss/mhl_sii8334.c
@@ -361,7 +361,7 @@
pr_debug("%s:%u\n", __func__, __LINE__);
INIT_COMPLETION(mhl_ctrl->rgnd_done);
timeout = wait_for_completion_interruptible_timeout
- (&mhl_ctrl->rgnd_done, HZ/2);
+ (&mhl_ctrl->rgnd_done, HZ);
if (!timeout) {
/* most likely nothing plugged in USB */
/* USB HOST connected or already in USB mode */
@@ -377,6 +377,12 @@
{
int rc;
struct mhl_tx_ctrl *mhl_ctrl = data;
+ struct i2c_client *client = mhl_ctrl->i2c_handle;
+ unsigned long flags;
+
+ enable_irq(client->irq);
+ /* wait for i2c interrupt line to be activated */
+ msleep(300);
if (id) {
/* When MHL cable is disconnected we get a sii8334
@@ -396,11 +402,16 @@
mhl_ctrl->notify_usb_online = usb_notify_cb;
if (!mhl_ctrl->disc_enabled) {
+ spin_lock_irqsave(&mhl_ctrl->lock, flags);
+ mhl_ctrl->tx_powered_off = false;
+ spin_unlock_irqrestore(&mhl_ctrl->lock, flags);
mhl_sii_reset_pin(mhl_ctrl, 0);
msleep(50);
mhl_sii_reset_pin(mhl_ctrl, 1);
- /* TX PR-guide requires a 100 ms wait here */
- msleep(100);
+ /* chipset PR recommends waiting for at least 100 ms
+ * the chipset needs longer to come out of D3 state.
+ */
+ msleep(300);
mhl_init_reg_settings(mhl_ctrl, true);
rc = mhl_sii_wait_for_rgnd(mhl_ctrl);
} else {
@@ -690,8 +701,8 @@
MHL_SII_PAGE3_WR(0x3C, 0x80);
- if (mhl_ctrl->cur_state != POWER_STATE_D3)
- MHL_SII_REG_NAME_MOD(REG_INT_CTRL, BIT6 | BIT5 | BIT4, BIT4);
+ MHL_SII_REG_NAME_MOD(REG_INT_CTRL,
+ (BIT6 | BIT5 | BIT4), (BIT6 | BIT4));
/* Enable Auto Soft RESET */
MHL_SII_REG_NAME_WR(REG_SRST, 0x084);
@@ -858,11 +869,6 @@
static void mhl_msm_disconnection(struct mhl_tx_ctrl *mhl_ctrl)
{
struct i2c_client *client = mhl_ctrl->i2c_handle;
- unsigned long flags;
-
- spin_lock_irqsave(&mhl_ctrl->lock, flags);
- mhl_ctrl->dwnstream_hpd &= ~BIT6;
- spin_unlock_irqrestore(&mhl_ctrl->lock, flags);
/* disabling Tx termination */
MHL_SII_REG_NAME_WR(REG_MHLTX_CTL1, 0xD0);
@@ -870,7 +876,7 @@
mhl_msc_clear(mhl_ctrl);
}
-static int mhl_msm_read_rgnd_int(struct mhl_tx_ctrl *mhl_ctrl)
+static int mhl_msm_read_rgnd_int(struct mhl_tx_ctrl *mhl_ctrl)
{
uint8_t rgnd_imp;
struct i2c_client *client = mhl_ctrl->i2c_handle;
@@ -967,12 +973,12 @@
if ((0x00 == status) &&\
(mhl_ctrl->cur_state == POWER_STATE_D3)) {
- pr_err("%s: invalid intr\n", __func__);
+ pr_warn("%s: invalid intr\n", __func__);
return 0;
}
if (0xFF == status) {
- pr_debug("%s: invalid intr 0xff\n", __func__);
+ pr_warn("%s: invalid intr 0xff\n", __func__);
MHL_SII_REG_NAME_WR(REG_INTR4, status);
return 0;
}
@@ -999,13 +1005,14 @@
power_supply_changed(&mhl_ctrl->mhl_psy);
if (mhl_ctrl->notify_usb_online)
mhl_ctrl->notify_usb_online(0);
- return -EACCES;
+ return 0;
}
if (status & BIT5) {
/* clr intr - reg int4 */
pr_debug("%s: mhl discon: int4 st=%02X\n", __func__,
(int)status);
+ mhl_ctrl->mhl_det_discon = true;
reg = MHL_SII_REG_NAME_RD(REG_INTR4);
MHL_SII_REG_NAME_WR(REG_INTR4, reg);
@@ -1013,7 +1020,7 @@
power_supply_changed(&mhl_ctrl->mhl_psy);
if (mhl_ctrl->notify_usb_online)
mhl_ctrl->notify_usb_online(0);
- return -EACCES;
+ return 0;
}
if ((mhl_ctrl->cur_state != POWER_STATE_D0_NO_MHL) &&\
@@ -1054,6 +1061,32 @@
MHL_SII_REG_NAME_WR(REG_INTR5, intr_5_stat);
}
+static void mhl_tx_down(struct mhl_tx_ctrl *mhl_ctrl)
+{
+ struct i2c_client *client = mhl_ctrl->i2c_handle;
+ unsigned long flags;
+ uint8_t reg;
+
+ switch_mode(mhl_ctrl, POWER_STATE_D3, true);
+
+ reg = MHL_SII_REG_NAME_RD(REG_INTR1);
+ MHL_SII_REG_NAME_WR(REG_INTR1, reg);
+
+ reg = MHL_SII_REG_NAME_RD(REG_INTR4);
+ MHL_SII_REG_NAME_WR(REG_INTR4, reg);
+
+ /* disable INTR1 and INTR4 */
+ MHL_SII_REG_NAME_MOD(REG_INTR1_MASK, BIT6, 0x0);
+ MHL_SII_REG_NAME_MOD(REG_INTR4_MASK,
+ (BIT0 | BIT1 | BIT2 | BIT3 | BIT4 | BIT5 | BIT6), 0x0);
+
+ MHL_SII_PAGE1_MOD(0x003D, BIT0, 0x00);
+ spin_lock_irqsave(&mhl_ctrl->lock, flags);
+ mhl_ctrl->tx_powered_off = true;
+ spin_unlock_irqrestore(&mhl_ctrl->lock, flags);
+ pr_debug("%s: disabled\n", __func__);
+ disable_irq_nosync(client->irq);
+}
static void mhl_hpd_stat_isr(struct mhl_tx_ctrl *mhl_ctrl)
{
@@ -1085,20 +1118,24 @@
spin_lock_irqsave(&mhl_ctrl->lock, flags);
t = mhl_ctrl->dwnstream_hpd;
+ pr_debug("%s: %u: dwnstrm_hpd=0x%02x\n",
+ __func__, __LINE__, mhl_ctrl->dwnstream_hpd);
spin_unlock_irqrestore(&mhl_ctrl->lock, flags);
if (BIT6 & (cbus_stat ^ t)) {
u8 status = cbus_stat & BIT6;
mhl_drive_hpd(mhl_ctrl, status ? HPD_UP : HPD_DOWN);
- if (!status) {
- MHL_SII_PAGE1_MOD(0x003D, BIT0, 0x00);
- spin_lock_irqsave(&mhl_ctrl->lock, flags);
- mhl_ctrl->tx_powered_off = true;
- spin_unlock_irqrestore(&mhl_ctrl->lock, flags);
+ if (!status && mhl_ctrl->mhl_det_discon) {
+ pr_debug("%s:%u: power_down\n",
+ __func__, __LINE__);
+ mhl_tx_down(mhl_ctrl);
}
spin_lock_irqsave(&mhl_ctrl->lock, flags);
mhl_ctrl->dwnstream_hpd = cbus_stat;
+ pr_debug("%s: %u: dwnstrm_hpd=0x%02x\n",
+ __func__, __LINE__, mhl_ctrl->dwnstream_hpd);
spin_unlock_irqrestore(&mhl_ctrl->lock, flags);
+ mhl_ctrl->mhl_det_discon = false;
}
}
}
@@ -1252,6 +1289,7 @@
uint8_t cmd_data = 0x0;
int msc_msg_recved = 0;
int rc = -1;
+ unsigned long flags;
struct i2c_client *client = mhl_ctrl->i2c_handle;
regval = MHL_SII_REG_NAME_RD(REG_CBUS_INTR_STATUS);
@@ -1292,6 +1330,14 @@
intr = MHL_SII_REG_NAME_RD(REG_CBUS_SET_INT_0);
MHL_SII_REG_NAME_WR(REG_CBUS_SET_INT_0, intr);
mhl_msc_recv_set_int(mhl_ctrl, 0, intr);
+ if (intr & MHL_INT_DCAP_CHG) {
+ /* No need to go to low power mode */
+ spin_lock_irqsave(&mhl_ctrl->lock, flags);
+ mhl_ctrl->dwnstream_hpd = 0x00;
+ pr_debug("%s: %u: dwnstrm_hpd=0x%02x\n",
+ __func__, __LINE__, mhl_ctrl->dwnstream_hpd);
+ spin_unlock_irqrestore(&mhl_ctrl->lock, flags);
+ }
pr_debug("%s: MHL_INT_0 = %02x\n", __func__, intr);
intr = MHL_SII_REG_NAME_RD(REG_CBUS_SET_INT_1);
@@ -1337,8 +1383,18 @@
{
int rc;
struct mhl_tx_ctrl *mhl_ctrl = (struct mhl_tx_ctrl *)data;
+ unsigned long flags;
+
pr_debug("%s: Getting Interrupts\n", __func__);
+ spin_lock_irqsave(&mhl_ctrl->lock, flags);
+ if (mhl_ctrl->tx_powered_off) {
+ pr_warn("%s: powered off\n", __func__);
+ spin_unlock_irqrestore(&mhl_ctrl->lock, flags);
+ return IRQ_HANDLED;
+ }
+ spin_unlock_irqrestore(&mhl_ctrl->lock, flags);
+
/*
* Check RGND, MHL_EST, CBUS_LOCKOUT, SCDT
* interrupts. In D3, we get only RGND
@@ -1398,6 +1454,8 @@
*/
mhl_init_reg_settings(mhl_ctrl, true);
switch_mode(mhl_ctrl, POWER_STATE_D3, true);
+ pr_debug("%s:%u: power_down\n", __func__, __LINE__);
+ mhl_tx_down(mhl_ctrl);
return 0;
}
diff --git a/include/linux/android_alarm.h b/include/linux/android_alarm.h
index cbfeafc..096f777 100644
--- a/include/linux/android_alarm.h
+++ b/include/linux/android_alarm.h
@@ -70,6 +70,7 @@
void alarm_start_range(struct alarm *alarm, ktime_t start, ktime_t end);
int alarm_try_to_cancel(struct alarm *alarm);
int alarm_cancel(struct alarm *alarm);
+void set_power_on_alarm(long secs);
ktime_t alarm_get_elapsed_realtime(void);
/* set rtc while preserving elapsed realtime */
diff --git a/include/linux/mfd/pm8xxx/pm8921-bms.h b/include/linux/mfd/pm8xxx/pm8921-bms.h
index a19c0b6..7562166 100644
--- a/include/linux/mfd/pm8xxx/pm8921-bms.h
+++ b/include/linux/mfd/pm8xxx/pm8921-bms.h
@@ -37,6 +37,12 @@
* is considered empty(mV)
* @enable_fcc_learning: if set the driver will learn full charge
* capacity of the battery upon end of charge
+ * @min_fcc_learning_soc: minimum SOC as which CC counting for FCC
+ * learning can start
+ * @min_fcc_ocv_pc: minimum PC (lookup(OCV)) at which CC counting
+ * for FCC learning can start
+ * @max_fcc_learning_samples: Maximum number of FCC measurement cycles to be
+ * used for FCC update
* @normal_voltage_calc_ms: The period of soc calculation in ms when battery
* voltage higher than cutoff voltage
* @low_voltage_calc_ms: The period of soc calculation in ms when battery
@@ -66,6 +72,9 @@
unsigned int alarm_low_mv;
unsigned int alarm_high_mv;
int enable_fcc_learning;
+ int min_fcc_learning_soc;
+ int min_fcc_ocv_pc;
+ int max_fcc_learning_samples;
int shutdown_soc_valid_limit;
int ignore_shutdown_soc;
int adjust_soc_low_threshold;
diff --git a/include/linux/mhl_8334.h b/include/linux/mhl_8334.h
index f04bf80..7297ff3 100644
--- a/include/linux/mhl_8334.h
+++ b/include/linux/mhl_8334.h
@@ -162,6 +162,7 @@
spinlock_t lock;
bool tx_powered_off;
uint8_t dwnstream_hpd;
+ bool mhl_det_discon;
};
int mhl_i2c_reg_read(struct i2c_client *client,
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 9a4e61d..2cb297e 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -13,6 +13,7 @@
#include <linux/device.h>
#include <linux/mmc/core.h>
#include <linux/mod_devicetable.h>
+#include <linux/notifier.h>
struct mmc_cid {
unsigned int manfid;
@@ -173,7 +174,8 @@
wide_bus:1,
high_power:1,
high_speed:1,
- disable_cd:1;
+ disable_cd:1,
+ async_intr_sup:1;
};
struct sdio_cis {
@@ -276,7 +278,6 @@
* percentage of sectors that should issue check for
* BKOPS need
* @bkops_stats: BKOPS statistics
- * @poll_for_completion: Poll on BKOPS completion
* @cancel_delayed_work: A flag to indicate if the delayed work
* should be cancelled
* @sectors_changed: number of sectors written or
@@ -294,10 +295,6 @@
* is idle.
*/
#define MMC_IDLE_BKOPS_TIME_MS 200
- struct work_struct poll_for_completion;
-/* Polling timeout and interval for waiting on non-blocking BKOPs completion */
-#define BKOPS_COMPLETION_POLLING_TIMEOUT_MS (4 * 60 * 1000) /* in ms */
-#define BKOPS_COMPLETION_POLLING_INTERVAL_MS 1000 /* in ms */
bool cancel_delayed_work;
unsigned int sectors_changed;
/*
@@ -388,6 +385,8 @@
struct device_attribute rpm_attrib;
unsigned int idle_timeout;
+ struct notifier_block reboot_notify;
+ bool issue_long_pon;
};
/*
@@ -608,6 +607,7 @@
void (*remove)(struct mmc_card *);
int (*suspend)(struct mmc_card *);
int (*resume)(struct mmc_card *);
+ void (*shutdown)(struct mmc_card *);
};
extern int mmc_register_driver(struct mmc_driver *);
@@ -619,4 +619,5 @@
struct mmc_card *card);
extern void mmc_blk_init_packed_statistics(struct mmc_card *card);
extern void mmc_blk_disable_wr_packing(struct mmc_queue *mq);
+extern int mmc_send_long_pon(struct mmc_card *card);
#endif /* LINUX_MMC_CARD_H */
diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
index 995f8a2..f548721 100644
--- a/include/linux/mmc/core.h
+++ b/include/linux/mmc/core.h
@@ -146,6 +146,7 @@
extern int mmc_stop_bkops(struct mmc_card *);
extern int mmc_read_bkops_status(struct mmc_card *);
+extern bool mmc_card_is_prog_state(struct mmc_card *);
extern struct mmc_async_req *mmc_start_req(struct mmc_host *,
struct mmc_async_req *, int *);
extern int mmc_interrupt_hpi(struct mmc_card *);
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 48be19a..27b0c4b 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -292,6 +292,8 @@
#define MMC_CAP2_STOP_REQUEST (1 << 18) /* Allow stop ongoing request */
/* Use runtime PM framework provided by MMC core */
#define MMC_CAP2_CORE_RUNTIME_PM (1 << 19)
+/* Allows Asynchronous SDIO irq while card is in 4-bit mode */
+#define MMC_CAP2_ASYNC_SDIO_IRQ_4BIT_MODE (1 << 20)
mmc_pm_flag_t pm_caps; /* supported pm features */
int clk_requests; /* internal reference counter */
@@ -414,6 +416,7 @@
};
extern struct mmc_host *mmc_alloc_host(int extra, struct device *);
+extern bool mmc_host_may_gate_card(struct mmc_card *);
extern int mmc_add_host(struct mmc_host *);
extern void mmc_remove_host(struct mmc_host *);
extern void mmc_free_host(struct mmc_host *);
diff --git a/include/linux/mmc/sdio.h b/include/linux/mmc/sdio.h
index 58e52d4..961a4e1 100644
--- a/include/linux/mmc/sdio.h
+++ b/include/linux/mmc/sdio.h
@@ -162,6 +162,10 @@
#define SDIO_DTSx_SET_TYPE_A (1 << SDIO_DRIVE_DTSx_SHIFT)
#define SDIO_DTSx_SET_TYPE_C (2 << SDIO_DRIVE_DTSx_SHIFT)
#define SDIO_DTSx_SET_TYPE_D (3 << SDIO_DRIVE_DTSx_SHIFT)
+
+#define SDIO_CCCR_INTERRUPT_EXTENSION 0x16
+#define SDIO_SUPPORT_ASYNC_INTR (1<<0)
+#define SDIO_ENABLE_ASYNC_INTR (1<<1)
/*
* Function Basic Registers (FBR)
*/
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index e4df414..6d41c13 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -78,6 +78,7 @@
#define MSMFB_METADATA_GET _IOW(MSMFB_IOCTL_MAGIC, 166, struct msmfb_metadata)
#define MSMFB_WRITEBACK_SET_MIRRORING_HINT _IOW(MSMFB_IOCTL_MAGIC, 167, \
unsigned int)
+#define MSMFB_ASYNC_BLIT _IOW(MSMFB_IOCTL_MAGIC, 168, unsigned int)
#define FB_TYPE_3D_PANEL 0x10101010
#define MDP_IMGTYPE2_START 0x10000
@@ -436,6 +437,31 @@
uint32_t *b;
};
+enum {
+ DISPLAY_MISR_EDP,
+ DISPLAY_MISR_DSI0,
+ DISPLAY_MISR_DSI1,
+ DISPLAY_MISR_HDMI,
+ DISPLAY_MISR_LCDC,
+ DISPLAY_MISR_ATV,
+ DISPLAY_MISR_DSI_CMD,
+ DISPLAY_MISR_MAX
+};
+
+enum {
+ MISR_OP_NONE,
+ MISR_OP_SFM,
+ MISR_OP_MFM,
+ MISR_OP_BM,
+ MISR_OP_MAX
+};
+
+struct mdp_misr {
+ uint32_t block_id;
+ uint32_t frame_count;
+ uint32_t crc_op_mode;
+ uint32_t crc_value[32];
+};
/*
@@ -574,6 +600,9 @@
uint32_t data;
};
+#define MDSS_MAX_BL_BRIGHTNESS 255
+#define AD_BL_LIN_LEN (MDSS_MAX_BL_BRIGHTNESS + 1)
+
#define MDSS_AD_MODE_AUTO_BL 0x0
#define MDSS_AD_MODE_AUTO_STR 0x1
#define MDSS_AD_MODE_TARG_STR 0x3
@@ -600,6 +629,9 @@
uint16_t frame_h;
uint8_t logo_v;
uint8_t logo_h;
+ uint32_t bl_lin_len;
+ uint32_t *bl_lin;
+ uint32_t *bl_lin_inv;
};
struct mdss_ad_cfg {
@@ -635,6 +667,11 @@
uint32_t output;
};
+struct mdss_calib_cfg {
+ uint32_t ops;
+ uint32_t calib_mask;
+};
+
enum {
mdp_op_pcc_cfg,
mdp_op_csc_cfg,
@@ -647,6 +684,7 @@
mdp_op_calib_cfg,
mdp_op_ad_cfg,
mdp_op_ad_input,
+ mdp_op_calib_mode,
mdp_op_max,
};
@@ -672,6 +710,7 @@
struct mdp_gamut_cfg_data gamut_cfg_data;
struct mdp_calib_config_data calib_cfg;
struct mdss_ad_init_cfg ad_init_cfg;
+ struct mdss_calib_cfg mdss_calib_cfg;
struct mdss_ad_input ad_input;
} data;
};
@@ -684,6 +723,7 @@
metadata_op_vic,
metadata_op_wb_format,
metadata_op_get_caps,
+ metadata_op_crc,
metadata_op_max
};
@@ -708,6 +748,7 @@
uint32_t op;
uint32_t flags;
union {
+ struct mdp_misr misr_request;
struct mdp_blend_cfg blend_cfg;
struct mdp_mixer_cfg mixer_cfg;
uint32_t panel_frame_rate;
@@ -726,6 +767,12 @@
int *rel_fen_fd;
};
+struct mdp_async_blit_req_list {
+ struct mdp_buf_sync sync;
+ uint32_t count;
+ struct mdp_blit_req req[];
+};
+
#define MDP_DISPLAY_COMMIT_OVERLAY 1
struct mdp_buf_fence {
uint32_t flags;
diff --git a/include/linux/spmi.h b/include/linux/spmi.h
index d179eab..e8e932e 100644
--- a/include/linux/spmi.h
+++ b/include/linux/spmi.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -54,7 +54,7 @@
struct spmi_controller {
struct device dev;
unsigned int nr;
- struct list_head list;
+ struct completion dev_released;
int (*cmd)(struct spmi_controller *, u8 opcode, u8 sid);
int (*read_cmd)(struct spmi_controller *,
u8 opcode, u8 sid, u16 addr, u8 bc, u8 *buf);
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 323f1e7..e883ad7 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -1671,13 +1671,6 @@
/* MPEG-class control IDs specific to the Samsung MFC 5.1 driver as defined by V4L2 */
#define V4L2_CID_MPEG_MFC51_BASE (V4L2_CTRL_CLASS_MPEG | 0x1100)
-#define V4L2_CID_MPEG_QCOM_BASE (V4L2_CTRL_CLASS_MPEG | 0x2100)
-
-#define V4L2_CID_MPEG_QCOM_SET_PERF_LEVEL (V4L2_CID_MPEG_QCOM_BASE + 0)
-enum v3l2_mpeg_qcom_perf_level {
- V4L2_CID_MPEG_QCOM_PERF_LEVEL_PERFORMANCE = 0,
- V4L2_CID_MPEG_QCOM_PERF_LEVEL_TURBO = 1,
-};
#define V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY (V4L2_CID_MPEG_MFC51_BASE+0)
#define V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY_ENABLE (V4L2_CID_MPEG_MFC51_BASE+1)
diff --git a/include/linux/wcnss_wlan.h b/include/linux/wcnss_wlan.h
index 2a53114..2ba585e 100644
--- a/include/linux/wcnss_wlan.h
+++ b/include/linux/wcnss_wlan.h
@@ -34,6 +34,7 @@
#define HAVE_WCNSS_SUSPEND_RESUME_NOTIFY 1
#define HAVE_WCNSS_RESET_INTR 1
#define HAVE_WCNSS_CAL_DOWNLOAD 1
+#define HAVE_WCNSS_RX_BUFF_COUNT 1
struct device *wcnss_wlan_get_device(void);
struct resource *wcnss_wlan_get_memory_map(struct device *dev);
@@ -69,6 +70,7 @@
int wcnss_device_ready(void);
void wcnss_riva_dump_pmic_regs(void);
int wcnss_xo_auto_detect_enabled(void);
+u32 wcnss_get_wlan_rx_buff_count(void);
#define wcnss_wlan_get_drvdata(dev) dev_get_drvdata(dev)
#define wcnss_wlan_set_drvdata(dev, data) dev_set_drvdata((dev), (data))
diff --git a/include/media/msm_cam_sensor.h b/include/media/msm_cam_sensor.h
index 47cf184..31798d6 100644
--- a/include/media/msm_cam_sensor.h
+++ b/include/media/msm_cam_sensor.h
@@ -184,6 +184,18 @@
uint16_t delay;
};
+struct msm_camera_i2c_array_write_config {
+ struct msm_camera_i2c_reg_setting conf_array;
+ uint16_t slave_addr;
+};
+
+struct msm_camera_i2c_read_config {
+ uint16_t slave_addr;
+ uint16_t reg_addr;
+ enum msm_camera_i2c_data_type data_type;
+ uint16_t *data;
+};
+
struct msm_camera_csid_vc_cfg {
uint8_t cid;
uint8_t dt;
@@ -320,7 +332,9 @@
enum msm_sensor_cfg_type_t {
CFG_SET_SLAVE_INFO,
+ CFG_SLAVE_READ_I2C,
CFG_WRITE_I2C_ARRAY,
+ CFG_SLAVE_WRITE_I2C_ARRAY,
CFG_WRITE_I2C_SEQ_ARRAY,
CFG_POWER_UP,
CFG_POWER_DOWN,
diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index 028e683..8984405 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -447,6 +447,7 @@
#endif
#endif
struct snd_kcontrol *chmap_kctl; /* channel-mapping controls */
+ struct snd_kcontrol *vol_kctl; /* volume controls */
};
struct snd_pcm {
@@ -1128,4 +1129,28 @@
unsigned long private_value,
struct snd_pcm_chmap **info_ret);
+/*
+ * PCM Volume control API
+ */
+/* array element of volume */
+struct snd_pcm_volume_elem {
+ int volume;
+};
+
+/* pp information; retrieved via snd_kcontrol_chip() */
+struct snd_pcm_volume {
+ struct snd_pcm *pcm; /* assigned PCM instance */
+ int stream; /* PLAYBACK or CAPTURE */
+ struct snd_kcontrol *kctl;
+ const struct snd_pcm_volume_elem *volume;
+ int max_length;
+ void *private_data; /* optional: private data pointer */
+};
+
+int snd_pcm_add_volume_ctls(struct snd_pcm *pcm, int stream,
+ const struct snd_pcm_volume_elem *volume,
+ int max_length,
+ unsigned long private_value,
+ struct snd_pcm_volume **info_ret);
+
#endif /* __SOUND_PCM_H */
diff --git a/include/sound/q6adm-v2.h b/include/sound/q6adm-v2.h
index 449694e..795bb99 100644
--- a/include/sound/q6adm-v2.h
+++ b/include/sound/q6adm-v2.h
@@ -54,6 +54,8 @@
int adm_connect_afe_port(int mode, int session_id, int port_id);
+void adm_ec_ref_rx_id(int port_id);
+
int adm_get_copp_id(int port_id);
void adm_set_multi_ch_map(char *channel_map);
diff --git a/include/sound/q6afe-v2.h b/include/sound/q6afe-v2.h
index 1389b2a..2e4c7c1 100644
--- a/include/sound/q6afe-v2.h
+++ b/include/sound/q6afe-v2.h
@@ -197,6 +197,8 @@
enum afe_mad_type afe_port_get_mad_type(u16 port_id);
int afe_set_config(enum afe_config_type config_type, void *config_data,
int arg);
+void afe_clear_config(enum afe_config_type config);
+bool afe_has_config(enum afe_config_type config);
void afe_set_aanc_info(struct aanc_data *aanc_info);
#endif /* __Q6AFE_V2_H__ */
diff --git a/include/sound/q6lsm.h b/include/sound/q6lsm.h
index e9ca91d..d7a01a0 100644
--- a/include/sound/q6lsm.h
+++ b/include/sound/q6lsm.h
@@ -124,6 +124,7 @@
int q6lsm_start(struct lsm_client *client, bool wait);
int q6lsm_stop(struct lsm_client *client, bool wait);
int q6lsm_snd_model_buf_alloc(struct lsm_client *client, uint32_t len);
+int q6lsm_snd_model_buf_free(struct lsm_client *client);
int q6lsm_close(struct lsm_client *client);
int q6lsm_register_sound_model(struct lsm_client *client,
enum lsm_detection_mode mode, u16 minkeyword,
diff --git a/sound/core/pcm.c b/sound/core/pcm.c
index d98e160..2e8d6f4 100644
--- a/sound/core/pcm.c
+++ b/sound/core/pcm.c
@@ -1199,6 +1199,10 @@
snd_ctl_remove(pcm->card, pcm->streams[cidx].chmap_kctl);
pcm->streams[cidx].chmap_kctl = NULL;
}
+ if (pcm->streams[cidx].vol_kctl) {
+ snd_ctl_remove(pcm->card, pcm->streams[cidx].vol_kctl);
+ pcm->streams[cidx].vol_kctl = NULL;
+ }
}
unlock:
mutex_unlock(®ister_mutex);
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index e0ab899..06d617b 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -31,6 +31,8 @@
#include <sound/pcm_params.h>
#include <sound/timer.h>
+#define STRING_LENGTH_OF_INT 12
+
/*
* fill ring buffer with silence
* runtime->silence_start: starting pointer to silence area
@@ -2444,6 +2446,23 @@
kfree(info);
}
+static int pcm_volume_ctl_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 0x2000;
+ return 0;
+}
+
+static void pcm_volume_ctl_private_free(struct snd_kcontrol *kcontrol)
+{
+ struct snd_pcm_volume *info = snd_kcontrol_chip(kcontrol);
+ info->pcm->streams[info->stream].vol_kctl = NULL;
+ kfree(info);
+}
+
/**
* snd_pcm_add_chmap_ctls - create channel-mapping control elements
* @pcm: the assigned PCM instance
@@ -2503,3 +2522,74 @@
return 0;
}
EXPORT_SYMBOL_GPL(snd_pcm_add_chmap_ctls);
+
+/**
+ * snd_pcm_add_volume_ctls - create volume control elements
+ * @pcm: the assigned PCM instance
+ * @stream: stream direction
+ * @max_length: the max length of the volume parameter of stream
+ * @private_value: the value passed to each kcontrol's private_value field
+ * @info_ret: store struct snd_pcm_volume instance if non-NULL
+ *
+ * Create volume control elements assigned to the given PCM stream(s).
+ * Returns zero if succeed, or a negative error value.
+ */
+int snd_pcm_add_volume_ctls(struct snd_pcm *pcm, int stream,
+ const struct snd_pcm_volume_elem *volume,
+ int max_length,
+ unsigned long private_value,
+ struct snd_pcm_volume **info_ret)
+{
+ struct snd_pcm_volume *info;
+ struct snd_kcontrol_new knew = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |
+ SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = pcm_volume_ctl_info,
+ };
+ int err;
+ int size;
+
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+ info->pcm = pcm;
+ info->stream = stream;
+ info->volume = volume;
+ info->max_length = max_length;
+ size = sizeof("Playback ") + sizeof(" Volume") +
+ STRING_LENGTH_OF_INT*sizeof(char) + 1;
+ knew.name = kzalloc(size, GFP_KERNEL);
+ if (!knew.name) {
+ kfree(info);
+ return -ENOMEM;
+ }
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+ snprintf(knew.name, size, "%s %d %s",
+ "Playback", pcm->device, "Volume");
+ else
+ snprintf(knew.name, size, "%s %d %s",
+ "Capture", pcm->device, "Volume");
+ knew.device = pcm->device;
+ knew.count = pcm->streams[stream].substream_count;
+ knew.private_value = private_value;
+ info->kctl = snd_ctl_new1(&knew, info);
+ if (!info->kctl) {
+ kfree(info);
+ kfree(knew.name);
+ return -ENOMEM;
+ }
+ info->kctl->private_free = pcm_volume_ctl_private_free;
+ err = snd_ctl_add(pcm->card, info->kctl);
+ if (err < 0) {
+ kfree(info);
+ kfree(knew.name);
+ return -ENOMEM;
+ }
+ pcm->streams[stream].vol_kctl = info->kctl;
+ if (info_ret)
+ *info_ret = info;
+ kfree(knew.name);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_pcm_add_volume_ctls);
diff --git a/sound/soc/codecs/msm8x10-wcd.c b/sound/soc/codecs/msm8x10-wcd.c
index 1a11997..435f285 100644
--- a/sound/soc/codecs/msm8x10-wcd.c
+++ b/sound/soc/codecs/msm8x10-wcd.c
@@ -616,7 +616,7 @@
0x00);
snd_soc_update_bits(codec,
MSM8X10_WCD_A_CDC_CLK_OTHR_RESET_B1_CTL,
- 0x01, 0x01);
+ 0x01, 0x00);
snd_soc_update_bits(codec,
MSM8X10_WCD_A_CP_STATIC, 0x08, 0x00);
break;
@@ -2280,7 +2280,6 @@
/* Reduce LINE DAC bias to 70% */
MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_RX_LINE_BIAS_PA, 0x78),
-
/* Disable TX7 internal biasing path which can cause leakage */
MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_BIAS_CURR_CTL_2, 0x04),
MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_MICB_CFILT_1_VAL, 0x60),
@@ -2288,6 +2287,13 @@
MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_TX_COM_BIAS, 0xE0),
MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_TX_1_EN, 0x32),
MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_TX_2_EN, 0x32),
+
+ /* ClassG fine tuning setting for 16 ohm HPH */
+ MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_CLSG_FREQ_THRESH_B1_CTL, 0x05),
+ MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_CLSG_FREQ_THRESH_B2_CTL, 0x0C),
+ MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_CLSG_FREQ_THRESH_B3_CTL, 0x1A),
+ MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_CLSG_FREQ_THRESH_B4_CTL, 0x47),
+ MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_CLSG_GAIN_THRESH_CTL, 0x23),
};
static void msm8x10_wcd_update_reg_defaults(struct snd_soc_codec *codec)
diff --git a/sound/soc/codecs/wcd9306.c b/sound/soc/codecs/wcd9306.c
index d35d8c4..6cdbb8c 100644
--- a/sound/soc/codecs/wcd9306.c
+++ b/sound/soc/codecs/wcd9306.c
@@ -1865,7 +1865,7 @@
release_firmware(fw);
break;
- case SND_SOC_DAPM_POST_PMD:
+ case SND_SOC_DAPM_PRE_PMD:
msleep(40);
snd_soc_update_bits(codec, TAPAN_A_CDC_ANC1_B1_CTL, 0x01, 0x00);
snd_soc_update_bits(codec, TAPAN_A_CDC_ANC2_B1_CTL, 0x02, 0x00);
@@ -2337,12 +2337,11 @@
snd_soc_update_bits(codec,
TAPAN_A_RX_HPH_CNP_EN, 0x30, 0x00);
msleep(40);
- }
- if (w->shift == 5) {
snd_soc_update_bits(codec,
TAPAN_A_TX_7_MBHC_EN, 0x80, 00);
ret |= tapan_codec_enable_anc(w, kcontrol, event);
}
+ break;
case SND_SOC_DAPM_POST_PMD:
ret = tapan_hph_pa_event(w, kcontrol, event);
break;
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index 51948bd..67c03d6 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -506,6 +506,9 @@
/* class h specific data */
struct wcd9xxx_clsh_cdc_data clsh_d;
+
+ int (*machine_codec_event_cb)(struct snd_soc_codec *codec,
+ enum wcd9xxx_codec_event);
};
static const u32 comp_shift[] = {
@@ -3785,13 +3788,15 @@
{"RX7 MIX1 INP2", "RX6", "SLIM RX6"},
{"RX7 MIX1 INP2", "RX7", "SLIM RX7"},
{"RX7 MIX1 INP2", "IIR1", "IIR1"},
+ {"RX7 MIX1 INP2", "IIR2", "IIR2"},
+
+ /* IIR1, IIR2 inputs to Second RX Mixer on RX1, RX2 and RX7 chains. */
{"RX1 MIX2 INP1", "IIR1", "IIR1"},
{"RX1 MIX2 INP2", "IIR1", "IIR1"},
{"RX2 MIX2 INP1", "IIR1", "IIR1"},
{"RX2 MIX2 INP2", "IIR1", "IIR1"},
{"RX7 MIX2 INP1", "IIR1", "IIR1"},
{"RX7 MIX2 INP2", "IIR1", "IIR1"},
- {"RX7 MIX1 INP2", "IIR2", "IIR2"},
{"RX1 MIX2 INP1", "IIR2", "IIR2"},
{"RX1 MIX2 INP2", "IIR2", "IIR2"},
{"RX2 MIX2 INP1", "IIR2", "IIR2"},
@@ -3869,6 +3874,13 @@
{"IIR1 INP1 MUX", "DEC8", "DEC8 MUX"},
{"IIR1 INP1 MUX", "DEC9", "DEC9 MUX"},
{"IIR1 INP1 MUX", "DEC10", "DEC10 MUX"},
+ {"IIR1 INP1 MUX", "RX1", "SLIM RX1"},
+ {"IIR1 INP1 MUX", "RX2", "SLIM RX2"},
+ {"IIR1 INP1 MUX", "RX3", "SLIM RX3"},
+ {"IIR1 INP1 MUX", "RX4", "SLIM RX4"},
+ {"IIR1 INP1 MUX", "RX5", "SLIM RX5"},
+ {"IIR1 INP1 MUX", "RX6", "SLIM RX6"},
+ {"IIR1 INP1 MUX", "RX7", "SLIM RX7"},
{"IIR2", NULL, "IIR2 INP1 MUX"},
{"IIR2 INP1 MUX", "DEC1", "DEC1 MUX"},
@@ -3881,6 +3893,13 @@
{"IIR2 INP1 MUX", "DEC8", "DEC8 MUX"},
{"IIR2 INP1 MUX", "DEC9", "DEC9 MUX"},
{"IIR2 INP1 MUX", "DEC10", "DEC10 MUX"},
+ {"IIR2 INP1 MUX", "RX1", "SLIM RX1"},
+ {"IIR2 INP1 MUX", "RX2", "SLIM RX2"},
+ {"IIR2 INP1 MUX", "RX3", "SLIM RX3"},
+ {"IIR2 INP1 MUX", "RX4", "SLIM RX4"},
+ {"IIR2 INP1 MUX", "RX5", "SLIM RX5"},
+ {"IIR2 INP1 MUX", "RX6", "SLIM RX6"},
+ {"IIR2 INP1 MUX", "RX7", "SLIM RX7"},
{"MIC BIAS1 Internal1", NULL, "LDO_H"},
{"MIC BIAS1 Internal2", NULL, "LDO_H"},
@@ -5478,10 +5497,10 @@
/* Sidetone */
SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
- SND_SOC_DAPM_PGA("IIR1", TAIKO_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("IIR1", TAIKO_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
SND_SOC_DAPM_MUX("IIR2 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir2_inp1_mux),
- SND_SOC_DAPM_PGA("IIR2", TAIKO_A_CDC_CLK_SD_CTL, 1, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("IIR2", TAIKO_A_CDC_CLK_SD_CTL, 1, 0, NULL, 0),
/* AUX PGA */
SND_SOC_DAPM_ADC_E("AUX_PGA_Left", NULL, TAIKO_A_RX_AUX_SW_CTL, 7, 0,
@@ -6123,6 +6142,16 @@
}
EXPORT_SYMBOL_GPL(taiko_hs_detect);
+void taiko_event_register(
+ int (*machine_event_cb)(struct snd_soc_codec *codec,
+ enum wcd9xxx_codec_event),
+ struct snd_soc_codec *codec)
+{
+ struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
+ taiko->machine_codec_event_cb = machine_event_cb;
+}
+EXPORT_SYMBOL_GPL(taiko_event_register);
+
static void taiko_init_slim_slave_cfg(struct snd_soc_codec *codec)
{
struct taiko_priv *priv = snd_soc_codec_get_drvdata(codec);
@@ -6198,6 +6227,8 @@
taiko->mbhc_started = true;
}
}
+ taiko->machine_codec_event_cb(codec, WCD9XXX_CODEC_EVENT_CODEC_UP);
+
mutex_unlock(&codec->mutex);
return ret;
}
diff --git a/sound/soc/codecs/wcd9320.h b/sound/soc/codecs/wcd9320.h
index a4dbd7a..8f222ad 100644
--- a/sound/soc/codecs/wcd9320.h
+++ b/sound/soc/codecs/wcd9320.h
@@ -18,6 +18,7 @@
#include <linux/mfd/wcd9xxx/wcd9xxx-slimslave.h>
#include "wcd9xxx-mbhc.h"
#include "wcd9xxx-resmgr.h"
+#include "wcd9xxx-common.h"
#define TAIKO_NUM_REGISTERS 0x400
#define TAIKO_MAX_REGISTER (TAIKO_NUM_REGISTERS-1)
@@ -148,4 +149,9 @@
extern void *taiko_get_afe_config(struct snd_soc_codec *codec,
enum afe_config_type config_type);
+extern void taiko_event_register(
+ int (*machine_event_cb)(struct snd_soc_codec *codec,
+ enum wcd9xxx_codec_event),
+ struct snd_soc_codec *codec);
+
#endif
diff --git a/sound/soc/codecs/wcd9xxx-common.h b/sound/soc/codecs/wcd9xxx-common.h
index 6bc581c..316742d 100644
--- a/sound/soc/codecs/wcd9xxx-common.h
+++ b/sound/soc/codecs/wcd9xxx-common.h
@@ -73,4 +73,8 @@
extern void wcd9xxx_clsh_init(struct wcd9xxx_clsh_cdc_data *clsh,
struct wcd9xxx_resmgr *resmgr);
+enum wcd9xxx_codec_event {
+ WCD9XXX_CODEC_EVENT_CODEC_UP = 0,
+};
+
#endif
diff --git a/sound/soc/msm/Kconfig b/sound/soc/msm/Kconfig
index 7fd62f1..40661ff 100644
--- a/sound/soc/msm/Kconfig
+++ b/sound/soc/msm/Kconfig
@@ -190,6 +190,23 @@
the machine drivers and the corresponding
DAI-links.
+config SND_SOC_APQ8074
+ tristate "SoC Machine driver for APQ8O74 boards"
+ depends on ARCH_MSM8974
+ select SND_SOC_QDSP6V2
+ select SND_SOC_MSM_STUB
+ select SND_SOC_MSM_HOSTLESS_PCM
+ select SND_SOC_WCD9320
+ select SND_SOC_MSM_HDMI_CODEC_RX
+ select SND_DYNAMIC_MINORS
+ select AUDIO_OCMEM
+ help
+ To add support for SoC audio on APQ8074.
+ This will enable sound soc drivers which
+ interfaces with DSP, also it will enable
+ the machine drivers and the corresponding
+ DAI-links.
+
config SND_SOC_MSM8226
tristate "SoC Machine driver for MSM8226 boards"
depends on ARCH_MSM8226
diff --git a/sound/soc/msm/Makefile b/sound/soc/msm/Makefile
index 7ab4811..e206812 100644
--- a/sound/soc/msm/Makefile
+++ b/sound/soc/msm/Makefile
@@ -84,6 +84,10 @@
snd-soc-qdsp6v2-objs := msm-dai-fe.o
obj-$(CONFIG_SND_SOC_QDSP6V2) += snd-soc-qdsp6v2.o
+# for APQ 8074 sound card driver
+snd-soc-apq8074-objs := apq8074.o
+obj-$(CONFIG_SND_SOC_APQ8074) += snd-soc-apq8074.o
+
#for MDM9625 sound card driver
snd-soc-mdm9625-objs := mdm9625.o
obj-$(CONFIG_SND_SOC_MDM9625) += snd-soc-mdm9625.o
diff --git a/sound/soc/msm/apq8074.c b/sound/soc/msm/apq8074.c
new file mode 100644
index 0000000..9a2f83b
--- /dev/null
+++ b/sound/soc/msm/apq8074.c
@@ -0,0 +1,2486 @@
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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/of_gpio.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/mfd/pm8xxx/pm8921.h>
+#include <linux/qpnp/clkdiv.h>
+#include <linux/regulator/consumer.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+#include <sound/jack.h>
+#include <sound/q6afe-v2.h>
+#include <asm/mach-types.h>
+#include <mach/socinfo.h>
+#include <sound/pcm_params.h>
+#include "qdsp6v2/msm-pcm-routing-v2.h"
+#include "../codecs/wcd9320.h"
+#include <linux/io.h>
+
+#define DRV_NAME "apq8074-asoc-taiko"
+
+#define APQ8074_SPK_ON 1
+#define APQ8074_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
+
+static int slim0_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE;
+static int hdmi_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE;
+
+#define SAMPLING_RATE_48KHZ 48000
+#define SAMPLING_RATE_96KHZ 96000
+#define SAMPLING_RATE_192KHZ 192000
+
+static int apq8074_auxpcm_rate = 8000;
+#define LO_1_SPK_AMP 0x1
+#define LO_3_SPK_AMP 0x2
+#define LO_2_SPK_AMP 0x4
+#define LO_4_SPK_AMP 0x8
+
+#define LPAIF_OFFSET 0xFE000000
+#define LPAIF_PRI_MODE_MUXSEL (LPAIF_OFFSET + 0x2B000)
+#define LPAIF_SEC_MODE_MUXSEL (LPAIF_OFFSET + 0x2C000)
+#define LPAIF_TER_MODE_MUXSEL (LPAIF_OFFSET + 0x2D000)
+#define LPAIF_QUAD_MODE_MUXSEL (LPAIF_OFFSET + 0x2E000)
+
+#define I2S_PCM_SEL 1
+#define I2S_PCM_SEL_OFFSET 1
+
+
+#define WCD9XXX_MBHC_DEF_BUTTONS 8
+#define WCD9XXX_MBHC_DEF_RLOADS 5
+#define TAIKO_EXT_CLK_RATE 9600000
+
+/* It takes about 13ms for Class-D PAs to ramp-up */
+#define EXT_CLASS_D_EN_DELAY 13000
+#define EXT_CLASS_D_DIS_DELAY 3000
+#define EXT_CLASS_D_DELAY_DELTA 2000
+
+/* It takes about 13ms for Class-AB PAs to ramp-up */
+#define EXT_CLASS_AB_EN_DELAY 10000
+#define EXT_CLASS_AB_DIS_DELAY 1000
+#define EXT_CLASS_AB_DELAY_DELTA 1000
+
+#define NUM_OF_AUXPCM_GPIOS 4
+
+static inline int param_is_mask(int p)
+{
+ return ((p >= SNDRV_PCM_HW_PARAM_FIRST_MASK) &&
+ (p <= SNDRV_PCM_HW_PARAM_LAST_MASK));
+}
+
+static inline struct snd_mask *param_to_mask(struct snd_pcm_hw_params *p, int n)
+{
+ return &(p->masks[n - SNDRV_PCM_HW_PARAM_FIRST_MASK]);
+}
+
+static void param_set_mask(struct snd_pcm_hw_params *p, int n, unsigned bit)
+{
+ if (bit >= SNDRV_MASK_MAX)
+ return;
+ if (param_is_mask(n)) {
+ struct snd_mask *m = param_to_mask(p, n);
+ m->bits[0] = 0;
+ m->bits[1] = 0;
+ m->bits[bit >> 5] |= (1 << (bit & 31));
+ }
+}
+
+static const char *const auxpcm_rate_text[] = {"rate_8000", "rate_16000"};
+static const struct soc_enum apq8074_auxpcm_enum[] = {
+ SOC_ENUM_SINGLE_EXT(2, auxpcm_rate_text),
+};
+
+static void *def_taiko_mbhc_cal(void);
+static int msm_snd_enable_codec_ext_clk(struct snd_soc_codec *codec, int enable,
+ bool dapm);
+
+static struct wcd9xxx_mbhc_config mbhc_cfg = {
+ .read_fw_bin = false,
+ .calibration = NULL,
+ .micbias = MBHC_MICBIAS2,
+ .mclk_cb_fn = msm_snd_enable_codec_ext_clk,
+ .mclk_rate = TAIKO_EXT_CLK_RATE,
+ .gpio = 0,
+ .gpio_irq = 0,
+ .gpio_level_insert = 1,
+ .detect_extn_cable = true,
+ .insert_detect = true,
+ .swap_gnd_mic = NULL,
+};
+
+struct msm_auxpcm_gpio {
+ unsigned gpio_no;
+ const char *gpio_name;
+};
+
+struct msm_auxpcm_ctrl {
+ struct msm_auxpcm_gpio *pin_data;
+ u32 cnt;
+};
+
+struct apq8074_asoc_mach_data {
+ int mclk_gpio;
+ u32 mclk_freq;
+ int us_euro_gpio;
+ struct msm_auxpcm_ctrl *pri_auxpcm_ctrl;
+};
+
+#define GPIO_NAME_INDEX 0
+#define DT_PARSE_INDEX 1
+
+static char *msm_prim_auxpcm_gpio_name[][2] = {
+ {"PRIM_AUXPCM_CLK", "qcom,prim-auxpcm-gpio-clk"},
+ {"PRIM_AUXPCM_SYNC", "qcom,prim-auxpcm-gpio-sync"},
+ {"PRIM_AUXPCM_DIN", "qcom,prim-auxpcm-gpio-din"},
+ {"PRIM_AUXPCM_DOUT", "qcom,prim-auxpcm-gpio-dout"},
+};
+
+static void *lpaif_pri_muxsel_virt_addr;
+
+struct apq8074_liquid_dock_dev {
+ int dock_plug_gpio;
+ int dock_plug_irq;
+ struct snd_soc_dapm_context *dapm;
+ struct work_struct irq_work;
+};
+
+static struct apq8074_liquid_dock_dev *apq8074_liquid_dock_dev;
+static int dock_plug_det = -1;
+
+/* 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_2_RX_1 = 147, /* HDMI RX */
+ SLIM_3_RX_1 = 148, /* In-call recording RX */
+ SLIM_3_RX_2 = 149, /* In-call recording RX */
+ SLIM_4_TX_1 = 150, /* In-call musid delivery TX */
+};
+
+static struct platform_device *spdev;
+static struct regulator *ext_spk_amp_regulator;
+static int ext_spk_amp_gpio = -1;
+static int ext_ult_spk_amp_gpio = -1;
+static int apq8074_spk_control = 1;
+static int apq8074_ext_spk_pamp;
+static int msm_slim_0_rx_ch = 1;
+static int msm_slim_0_tx_ch = 1;
+
+static int msm_btsco_rate = BTSCO_RATE_8KHZ;
+static int msm_btsco_ch = 1;
+static int msm_hdmi_rx_ch = 2;
+static int slim0_rx_sample_rate = SAMPLING_RATE_48KHZ;
+static int msm_proxy_rx_ch = 2;
+
+static struct mutex cdc_mclk_mutex;
+static struct clk *codec_clk;
+static int clk_users;
+static atomic_t prim_auxpcm_rsc_ref;
+
+static int apq8074_liquid_ext_spk_power_amp_init(void)
+{
+ int ret = 0;
+
+ ext_spk_amp_gpio = of_get_named_gpio(spdev->dev.of_node,
+ "qcom,ext-spk-amp-gpio", 0);
+ if (ext_spk_amp_gpio >= 0) {
+ ret = gpio_request(ext_spk_amp_gpio, "ext_spk_amp_gpio");
+ if (ret) {
+ pr_err("%s: gpio_request failed for ext_spk_amp_gpio.\n",
+ __func__);
+ return -EINVAL;
+ }
+ gpio_direction_output(ext_spk_amp_gpio, 0);
+
+ if (ext_spk_amp_regulator == NULL) {
+ ext_spk_amp_regulator = regulator_get(&spdev->dev,
+ "qcom,ext-spk-amp");
+
+ if (IS_ERR(ext_spk_amp_regulator)) {
+ pr_err("%s: Cannot get regulator %s.\n",
+ __func__, "qcom,ext-spk-amp");
+
+ gpio_free(ext_spk_amp_gpio);
+ return PTR_ERR(ext_spk_amp_regulator);
+ }
+ }
+ }
+
+ ext_ult_spk_amp_gpio = of_get_named_gpio(spdev->dev.of_node,
+ "qcom,ext-ult-spk-amp-gpio", 0);
+
+ if (ext_ult_spk_amp_gpio >= 0) {
+ ret = gpio_request(ext_ult_spk_amp_gpio,
+ "ext_ult_spk_amp_gpio");
+ if (ret) {
+ pr_err("%s: gpio_request failed for ext-ult_spk-amp-gpio.\n",
+ __func__);
+ return -EINVAL;
+ }
+ gpio_direction_output(ext_ult_spk_amp_gpio, 0);
+ }
+
+ return 0;
+}
+
+static void apq8074_liquid_ext_ult_spk_power_amp_enable(u32 on)
+{
+ if (on) {
+ regulator_enable(ext_spk_amp_regulator);
+ gpio_direction_output(ext_ult_spk_amp_gpio, 1);
+ /* time takes enable the external power class AB amplifier */
+ usleep_range(EXT_CLASS_AB_EN_DELAY,
+ EXT_CLASS_AB_EN_DELAY + EXT_CLASS_AB_DELAY_DELTA);
+ } else {
+ gpio_direction_output(ext_ult_spk_amp_gpio, 0);
+ regulator_disable(ext_spk_amp_regulator);
+ /* time takes disable the external power class AB amplifier */
+ usleep_range(EXT_CLASS_AB_DIS_DELAY,
+ EXT_CLASS_AB_DIS_DELAY + EXT_CLASS_AB_DELAY_DELTA);
+ }
+
+ pr_debug("%s: %s external ultrasound SPKR_DRV PAs.\n", __func__,
+ on ? "Enable" : "Disable");
+}
+
+static void apq8074_liquid_ext_spk_power_amp_enable(u32 on)
+{
+ if (on) {
+ regulator_enable(ext_spk_amp_regulator);
+ gpio_direction_output(ext_spk_amp_gpio, on);
+ /*time takes enable the external power amplifier*/
+ usleep_range(EXT_CLASS_D_EN_DELAY,
+ EXT_CLASS_D_EN_DELAY + EXT_CLASS_D_DELAY_DELTA);
+ } else {
+ gpio_direction_output(ext_spk_amp_gpio, on);
+ regulator_disable(ext_spk_amp_regulator);
+ /*time takes disable the external power amplifier*/
+ usleep_range(EXT_CLASS_D_DIS_DELAY,
+ EXT_CLASS_D_DIS_DELAY + EXT_CLASS_D_DELAY_DELTA);
+ }
+
+ pr_debug("%s: %s external speaker PAs.\n", __func__,
+ on ? "Enable" : "Disable");
+}
+
+static void apq8074_liquid_docking_irq_work(struct work_struct *work)
+{
+ struct apq8074_liquid_dock_dev *dock_dev =
+ container_of(work,
+ struct apq8074_liquid_dock_dev,
+ irq_work);
+
+ struct snd_soc_dapm_context *dapm = dock_dev->dapm;
+
+
+ mutex_lock(&dapm->codec->mutex);
+ dock_plug_det =
+ gpio_get_value(dock_dev->dock_plug_gpio);
+
+
+ if (0 == dock_plug_det) {
+ if ((apq8074_ext_spk_pamp & LO_1_SPK_AMP) &&
+ (apq8074_ext_spk_pamp & LO_3_SPK_AMP) &&
+ (apq8074_ext_spk_pamp & LO_2_SPK_AMP) &&
+ (apq8074_ext_spk_pamp & LO_4_SPK_AMP))
+ apq8074_liquid_ext_spk_power_amp_enable(1);
+ } else {
+ if ((apq8074_ext_spk_pamp & LO_1_SPK_AMP) &&
+ (apq8074_ext_spk_pamp & LO_3_SPK_AMP) &&
+ (apq8074_ext_spk_pamp & LO_2_SPK_AMP) &&
+ (apq8074_ext_spk_pamp & LO_4_SPK_AMP))
+ apq8074_liquid_ext_spk_power_amp_enable(0);
+ }
+
+ mutex_unlock(&dapm->codec->mutex);
+
+}
+
+static irqreturn_t apq8074_liquid_docking_irq_handler(int irq, void *dev)
+{
+ struct apq8074_liquid_dock_dev *dock_dev = dev;
+
+ /* switch speakers should not run in interrupt context */
+ schedule_work(&dock_dev->irq_work);
+
+ return IRQ_HANDLED;
+}
+
+static int apq8074_liquid_init_docking(struct snd_soc_dapm_context *dapm)
+{
+ int ret = 0;
+ int dock_plug_gpio = 0;
+
+ /* plug in docking speaker+plug in device OR unplug one of them */
+ u32 dock_plug_irq_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;
+
+ dock_plug_det = 0;
+ dock_plug_gpio = of_get_named_gpio(spdev->dev.of_node,
+ "qcom,dock-plug-det-irq", 0);
+
+ if (dock_plug_gpio >= 0) {
+
+ apq8074_liquid_dock_dev =
+ kzalloc(sizeof(*apq8074_liquid_dock_dev), GFP_KERNEL);
+
+ if (!apq8074_liquid_dock_dev) {
+ pr_err("apq8074_liquid_dock_dev alloc fail.\n");
+ return -ENOMEM;
+ }
+
+ apq8074_liquid_dock_dev->dock_plug_gpio = dock_plug_gpio;
+
+ ret = gpio_request(apq8074_liquid_dock_dev->dock_plug_gpio,
+ "dock-plug-det-irq");
+ if (ret) {
+ pr_err("%s:failed request apq8074_liquid_dock_plug_gpio.\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ dock_plug_det =
+ gpio_get_value(apq8074_liquid_dock_dev->dock_plug_gpio);
+
+ apq8074_liquid_dock_dev->dock_plug_irq =
+ gpio_to_irq(apq8074_liquid_dock_dev->dock_plug_gpio);
+
+ apq8074_liquid_dock_dev->dapm = dapm;
+
+ ret = request_irq(apq8074_liquid_dock_dev->dock_plug_irq,
+ apq8074_liquid_docking_irq_handler,
+ dock_plug_irq_flags,
+ "liquid_dock_plug_irq",
+ apq8074_liquid_dock_dev);
+
+ INIT_WORK(
+ &apq8074_liquid_dock_dev->irq_work,
+ apq8074_liquid_docking_irq_work);
+ }
+
+ return 0;
+}
+
+static int apq8074_liquid_ext_spk_power_amp_on(u32 spk)
+{
+ int rc;
+
+ if (spk & (LO_1_SPK_AMP | LO_3_SPK_AMP | LO_2_SPK_AMP | LO_4_SPK_AMP)) {
+ pr_debug("%s: External speakers are already on. spk = 0x%x\n",
+ __func__, spk);
+
+ apq8074_ext_spk_pamp |= spk;
+ if ((apq8074_ext_spk_pamp & LO_1_SPK_AMP) &&
+ (apq8074_ext_spk_pamp & LO_3_SPK_AMP) &&
+ (apq8074_ext_spk_pamp & LO_2_SPK_AMP) &&
+ (apq8074_ext_spk_pamp & LO_4_SPK_AMP))
+ if (ext_spk_amp_gpio >= 0 &&
+ dock_plug_det == 0)
+ apq8074_liquid_ext_spk_power_amp_enable(1);
+ rc = 0;
+ } else {
+ pr_err("%s: Invalid external speaker ampl. spk = 0x%x\n",
+ __func__, spk);
+ rc = -EINVAL;
+ }
+
+ return rc;
+}
+
+
+static void apq8074_ext_spk_power_amp_on(u32 spk)
+{
+ if (gpio_is_valid(ext_spk_amp_gpio))
+ apq8074_liquid_ext_spk_power_amp_on(spk);
+}
+
+static void apq8074_liquid_ext_spk_power_amp_off(u32 spk)
+{
+
+ if (spk & (LO_1_SPK_AMP |
+ LO_3_SPK_AMP |
+ LO_2_SPK_AMP |
+ LO_4_SPK_AMP)) {
+
+ pr_debug("%s Left and right speakers case spk = 0x%08x",
+ __func__, spk);
+
+ if (!apq8074_ext_spk_pamp) {
+ if (ext_spk_amp_gpio >= 0 &&
+ dock_plug_det == 0)
+ apq8074_liquid_ext_spk_power_amp_enable(0);
+ apq8074_ext_spk_pamp = 0;
+ }
+
+ } else {
+
+ pr_err("%s: ERROR : Invalid Ext Spk Ampl. spk = 0x%08x\n",
+ __func__, spk);
+ return;
+ }
+}
+
+static void apq8074_ext_spk_power_amp_off(u32 spk)
+{
+ if (gpio_is_valid(ext_spk_amp_gpio))
+ apq8074_liquid_ext_spk_power_amp_off(spk);
+}
+
+static void apq8074_ext_control(struct snd_soc_codec *codec)
+{
+ struct snd_soc_dapm_context *dapm = &codec->dapm;
+
+ mutex_lock(&dapm->codec->mutex);
+
+ pr_debug("%s: apq8074_spk_control = %d", __func__, apq8074_spk_control);
+ if (apq8074_spk_control == APQ8074_SPK_ON) {
+ snd_soc_dapm_enable_pin(dapm, "Lineout_1 amp");
+ snd_soc_dapm_enable_pin(dapm, "Lineout_3 amp");
+ snd_soc_dapm_enable_pin(dapm, "Lineout_2 amp");
+ snd_soc_dapm_enable_pin(dapm, "Lineout_4 amp");
+ } else {
+ snd_soc_dapm_disable_pin(dapm, "Lineout_1 amp");
+ snd_soc_dapm_disable_pin(dapm, "Lineout_3 amp");
+ snd_soc_dapm_disable_pin(dapm, "Lineout_2 amp");
+ snd_soc_dapm_disable_pin(dapm, "Lineout_4 amp");
+ }
+
+ snd_soc_dapm_sync(dapm);
+ mutex_unlock(&dapm->codec->mutex);
+}
+
+static int apq8074_get_spk(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: apq8074_spk_control = %d", __func__, apq8074_spk_control);
+ ucontrol->value.integer.value[0] = apq8074_spk_control;
+ return 0;
+}
+
+static int apq8074_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 (apq8074_spk_control == ucontrol->value.integer.value[0])
+ return 0;
+
+ apq8074_spk_control = ucontrol->value.integer.value[0];
+ apq8074_ext_control(codec);
+ return 1;
+}
+
+
+static int msm_ext_spkramp_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
+{
+ pr_debug("%s()\n", __func__);
+
+ if (SND_SOC_DAPM_EVENT_ON(event)) {
+ if (!strncmp(w->name, "Lineout_1 amp", 14))
+ apq8074_ext_spk_power_amp_on(LO_1_SPK_AMP);
+ else if (!strncmp(w->name, "Lineout_3 amp", 14))
+ apq8074_ext_spk_power_amp_on(LO_3_SPK_AMP);
+ else if (!strncmp(w->name, "Lineout_2 amp", 14))
+ apq8074_ext_spk_power_amp_on(LO_2_SPK_AMP);
+ else if (!strncmp(w->name, "Lineout_4 amp", 14))
+ apq8074_ext_spk_power_amp_on(LO_4_SPK_AMP);
+ else {
+ pr_err("%s() Invalid Speaker Widget = %s\n",
+ __func__, w->name);
+ return -EINVAL;
+ }
+ } else {
+ if (!strncmp(w->name, "Lineout_1 amp", 14))
+ apq8074_ext_spk_power_amp_off(LO_1_SPK_AMP);
+ else if (!strncmp(w->name, "Lineout_3 amp", 14))
+ apq8074_ext_spk_power_amp_off(LO_3_SPK_AMP);
+ else if (!strncmp(w->name, "Lineout_2 amp", 14))
+ apq8074_ext_spk_power_amp_off(LO_2_SPK_AMP);
+ else if (!strncmp(w->name, "Lineout_4 amp", 14))
+ apq8074_ext_spk_power_amp_off(LO_4_SPK_AMP);
+ else {
+ pr_err("%s() Invalid Speaker Widget = %s\n",
+ __func__, w->name);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+
+}
+
+static int msm_ext_spkramp_ultrasound_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
+{
+
+ pr_debug("%s()\n", __func__);
+
+ if (!strncmp(w->name, "SPK_ultrasound amp", 19)) {
+ if (!gpio_is_valid(ext_ult_spk_amp_gpio)) {
+ pr_err("%s: ext_ult_spk_amp_gpio isn't configured\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ if (SND_SOC_DAPM_EVENT_ON(event))
+ apq8074_liquid_ext_ult_spk_power_amp_enable(1);
+ else
+ apq8074_liquid_ext_ult_spk_power_amp_enable(0);
+
+ } else {
+ pr_err("%s() Invalid Speaker Widget = %s\n",
+ __func__, w->name);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int msm_snd_enable_codec_ext_clk(struct snd_soc_codec *codec, int enable,
+ bool dapm)
+{
+ int ret = 0;
+ pr_debug("%s: enable = %d clk_users = %d\n",
+ __func__, enable, clk_users);
+
+ mutex_lock(&cdc_mclk_mutex);
+ if (enable) {
+ if (!codec_clk) {
+ dev_err(codec->dev, "%s: did not get Taiko MCLK\n",
+ __func__);
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ clk_users++;
+ if (clk_users != 1)
+ goto exit;
+
+ if (codec_clk) {
+ clk_set_rate(codec_clk, TAIKO_EXT_CLK_RATE);
+ clk_prepare_enable(codec_clk);
+ taiko_mclk_enable(codec, 1, dapm);
+ } else {
+ pr_err("%s: Error setting Taiko MCLK\n", __func__);
+ clk_users--;
+ goto exit;
+ }
+ } else {
+ if (clk_users > 0) {
+ clk_users--;
+ if (clk_users == 0) {
+ taiko_mclk_enable(codec, 0, dapm);
+ clk_disable_unprepare(codec_clk);
+ }
+ } else {
+ pr_err("%s: Error releasing Taiko MCLK\n", __func__);
+ ret = -EINVAL;
+ goto exit;
+ }
+ }
+exit:
+ mutex_unlock(&cdc_mclk_mutex);
+ return ret;
+}
+
+static int apq8074_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:
+ return msm_snd_enable_codec_ext_clk(w->codec, 1, true);
+ case SND_SOC_DAPM_POST_PMD:
+ return msm_snd_enable_codec_ext_clk(w->codec, 0, true);
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget apq8074_dapm_widgets[] = {
+
+ SND_SOC_DAPM_SUPPLY("MCLK", SND_SOC_NOPM, 0, 0,
+ apq8074_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_SPK("Lineout_1 amp", msm_ext_spkramp_event),
+ SND_SOC_DAPM_SPK("Lineout_3 amp", msm_ext_spkramp_event),
+
+ SND_SOC_DAPM_SPK("Lineout_2 amp", msm_ext_spkramp_event),
+ SND_SOC_DAPM_SPK("Lineout_4 amp", msm_ext_spkramp_event),
+ SND_SOC_DAPM_SPK("SPK_ultrasound amp",
+ msm_ext_spkramp_ultrasound_event),
+
+ SND_SOC_DAPM_MIC("Handset Mic", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_MIC("ANCRight Headset Mic", NULL),
+ SND_SOC_DAPM_MIC("ANCLeft Headset Mic", NULL),
+ SND_SOC_DAPM_MIC("Analog Mic4", NULL),
+ SND_SOC_DAPM_MIC("Analog Mic6", NULL),
+ SND_SOC_DAPM_MIC("Analog Mic7", NULL),
+
+ 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 char *const spk_function[] = {"Off", "On"};
+static const char *const slim0_rx_ch_text[] = {"One", "Two"};
+static const char *const slim0_tx_ch_text[] = {"One", "Two", "Three", "Four",
+ "Five"};
+static char const *hdmi_rx_ch_text[] = {"Two", "Three", "Four", "Five",
+ "Six", "Seven", "Eight"};
+static char const *rx_bit_format_text[] = {"S16_LE", "S24_LE"};
+static char const *slim0_rx_sample_rate_text[] = {"KHZ_48", "KHZ_96",
+ "KHZ_192"};
+static const char *const proxy_rx_ch_text[] = {"One", "Two", "Three", "Four",
+ "Five", "Six", "Seven", "Eight"};
+
+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 slim0_rx_sample_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int sample_rate_val = 0;
+
+ switch (slim0_rx_sample_rate) {
+ case SAMPLING_RATE_192KHZ:
+ sample_rate_val = 2;
+ break;
+
+ case SAMPLING_RATE_96KHZ:
+ sample_rate_val = 1;
+ break;
+
+ case SAMPLING_RATE_48KHZ:
+ default:
+ sample_rate_val = 0;
+ break;
+ }
+
+ ucontrol->value.integer.value[0] = sample_rate_val;
+ pr_debug("%s: slim0_rx_sample_rate = %d\n", __func__,
+ slim0_rx_sample_rate);
+
+ return 0;
+}
+
+static int slim0_rx_sample_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: ucontrol value = %ld\n", __func__,
+ ucontrol->value.integer.value[0]);
+
+ switch (ucontrol->value.integer.value[0]) {
+ case 2:
+ slim0_rx_sample_rate = SAMPLING_RATE_192KHZ;
+ break;
+ case 1:
+ slim0_rx_sample_rate = SAMPLING_RATE_96KHZ;
+ break;
+ case 0:
+ default:
+ slim0_rx_sample_rate = SAMPLING_RATE_48KHZ;
+ }
+
+ pr_debug("%s: slim0_rx_sample_rate = %d\n", __func__,
+ slim0_rx_sample_rate);
+
+ return 0;
+}
+
+static int slim0_rx_bit_format_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+
+ switch (slim0_rx_bit_format) {
+ case SNDRV_PCM_FORMAT_S24_LE:
+ ucontrol->value.integer.value[0] = 1;
+ break;
+
+ case SNDRV_PCM_FORMAT_S16_LE:
+ default:
+ ucontrol->value.integer.value[0] = 0;
+ break;
+ }
+
+ pr_debug("%s: slim0_rx_bit_format = %d, ucontrol value = %ld\n",
+ __func__, slim0_rx_bit_format,
+ ucontrol->value.integer.value[0]);
+
+ return 0;
+}
+
+static int slim0_rx_bit_format_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ switch (ucontrol->value.integer.value[0]) {
+ case 1:
+ slim0_rx_bit_format = SNDRV_PCM_FORMAT_S24_LE;
+ break;
+ case 0:
+ default:
+ slim0_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE;
+ break;
+ }
+ return 0;
+}
+
+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_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 0:
+ msm_btsco_rate = BTSCO_RATE_8KHZ;
+ break;
+ case 1:
+ 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 hdmi_rx_bit_format_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+
+ switch (hdmi_rx_bit_format) {
+ case SNDRV_PCM_FORMAT_S24_LE:
+ ucontrol->value.integer.value[0] = 1;
+ break;
+
+ case SNDRV_PCM_FORMAT_S16_LE:
+ default:
+ ucontrol->value.integer.value[0] = 0;
+ break;
+ }
+
+ pr_debug("%s: hdmi_rx_bit_format = %d, ucontrol value = %ld\n",
+ __func__, hdmi_rx_bit_format,
+ ucontrol->value.integer.value[0]);
+
+ return 0;
+}
+
+static int hdmi_rx_bit_format_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ switch (ucontrol->value.integer.value[0]) {
+ case 1:
+ hdmi_rx_bit_format = SNDRV_PCM_FORMAT_S24_LE;
+ break;
+ case 0:
+ default:
+ hdmi_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE;
+ break;
+ }
+ pr_debug("%s: hdmi_rx_bit_format = %d, ucontrol value = %ld\n",
+ __func__, hdmi_rx_bit_format,
+ ucontrol->value.integer.value[0]);
+ return 0;
+}
+
+static int msm_hdmi_rx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: msm_hdmi_rx_ch = %d\n", __func__,
+ msm_hdmi_rx_ch);
+ ucontrol->value.integer.value[0] = msm_hdmi_rx_ch - 2;
+
+ return 0;
+}
+
+static int msm_hdmi_rx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ msm_hdmi_rx_ch = ucontrol->value.integer.value[0] + 2;
+ if (msm_hdmi_rx_ch > 8) {
+ pr_err("%s: channels exceeded 8.Limiting to max channels-8\n",
+ __func__);
+ msm_hdmi_rx_ch = 8;
+ }
+ pr_debug("%s: msm_hdmi_rx_ch = %d\n", __func__, msm_hdmi_rx_ch);
+
+ return 1;
+}
+
+static const struct snd_kcontrol_new int_btsco_rate_mixer_controls[] = {
+ SOC_ENUM_EXT("Internal BTSCO SampleRate", msm_btsco_enum[0],
+ msm_btsco_rate_get, msm_btsco_rate_put),
+};
+
+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 apq8074_auxpcm_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = apq8074_auxpcm_rate;
+ return 0;
+}
+
+static int apq8074_auxpcm_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ switch (ucontrol->value.integer.value[0]) {
+ case 0:
+ apq8074_auxpcm_rate = 8000;
+ break;
+ case 1:
+ apq8074_auxpcm_rate = 16000;
+ break;
+ default:
+ apq8074_auxpcm_rate = 8000;
+ break;
+ }
+ return 0;
+}
+static int msm_proxy_rx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: msm_proxy_rx_ch = %d\n", __func__,
+ msm_proxy_rx_ch);
+ ucontrol->value.integer.value[0] = msm_proxy_rx_ch - 1;
+ return 0;
+}
+
+static int msm_proxy_rx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ msm_proxy_rx_ch = ucontrol->value.integer.value[0] + 1;
+ pr_debug("%s: msm_proxy_rx_ch = %d\n", __func__,
+ msm_proxy_rx_ch);
+ return 1;
+}
+
+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);
+
+ rate->min = rate->max = apq8074_auxpcm_rate;
+ channels->min = channels->max = 1;
+
+ return 0;
+}
+
+static int msm_proxy_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: msm_proxy_rx_ch =%d\n", __func__, msm_proxy_rx_ch);
+
+ if (channels->max < 2)
+ channels->min = channels->max = 2;
+ channels->min = channels->max = msm_proxy_rx_ch;
+ rate->min = rate->max = 48000;
+ return 0;
+}
+
+static int msm_proxy_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);
+
+ rate->min = rate->max = 48000;
+ return 0;
+}
+
+static int apq8074_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);
+
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ hdmi_rx_bit_format);
+ if (channels->max < 2)
+ channels->min = channels->max = 2;
+ rate->min = rate->max = 48000;
+ channels->min = channels->max = msm_hdmi_rx_ch;
+
+ return 0;
+}
+
+static int msm_aux_pcm_get_gpios(struct msm_auxpcm_ctrl *auxpcm_ctrl)
+{
+ struct msm_auxpcm_gpio *pin_data = NULL;
+ int ret = 0;
+ int i;
+ int j;
+
+ pin_data = auxpcm_ctrl->pin_data;
+ for (i = 0; i < auxpcm_ctrl->cnt; i++, pin_data++) {
+ ret = gpio_request(pin_data->gpio_no,
+ pin_data->gpio_name);
+ pr_debug("%s: gpio = %d, gpio name = %s\n"
+ "ret = %d\n", __func__,
+ pin_data->gpio_no,
+ pin_data->gpio_name,
+ ret);
+ if (ret) {
+ pr_err("%s: Failed to request gpio %d\n",
+ __func__, pin_data->gpio_no);
+ /* Release all GPIOs on failure */
+ for (j = i; j >= 0; j--)
+ gpio_free(pin_data->gpio_no);
+ return ret;
+ }
+ }
+ return 0;
+}
+
+static int msm_aux_pcm_free_gpios(struct msm_auxpcm_ctrl *auxpcm_ctrl)
+{
+ struct msm_auxpcm_gpio *pin_data = NULL;
+ int i;
+ int ret = 0;
+
+ if (auxpcm_ctrl == NULL || auxpcm_ctrl->pin_data == NULL) {
+ pr_err("%s: Ctrl pointers are NULL\n", __func__);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ pin_data = auxpcm_ctrl->pin_data;
+ for (i = 0; i < auxpcm_ctrl->cnt; i++, pin_data++) {
+ gpio_free(pin_data->gpio_no);
+ pr_debug("%s: gpio = %d, gpio_name = %s\n",
+ __func__, pin_data->gpio_no,
+ pin_data->gpio_name);
+ }
+err:
+ return ret;
+}
+
+static int msm_prim_auxpcm_startup(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_card *card = rtd->card;
+ struct apq8074_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+ struct msm_auxpcm_ctrl *auxpcm_ctrl = NULL;
+ int ret = 0;
+
+ pr_debug("%s(): substream = %s, prim_auxpcm_rsc_ref counter = %d\n",
+ __func__, substream->name, atomic_read(&prim_auxpcm_rsc_ref));
+
+ auxpcm_ctrl = pdata->pri_auxpcm_ctrl;
+
+ if (auxpcm_ctrl == NULL || auxpcm_ctrl->pin_data == NULL) {
+ pr_err("%s: Ctrl pointers are NULL\n", __func__);
+ ret = -EINVAL;
+ goto err;
+ }
+ if (atomic_inc_return(&prim_auxpcm_rsc_ref) == 1) {
+ if (lpaif_pri_muxsel_virt_addr != NULL)
+ iowrite32(I2S_PCM_SEL << I2S_PCM_SEL_OFFSET,
+ lpaif_pri_muxsel_virt_addr);
+ else
+ pr_err("%s lpaif_pri_muxsel_virt_addr is NULL\n",
+ __func__);
+ ret = msm_aux_pcm_get_gpios(auxpcm_ctrl);
+ }
+ if (ret < 0) {
+ pr_err("%s: Aux PCM GPIO request failed\n", __func__);
+ return -EINVAL;
+ }
+err:
+ return ret;
+}
+
+static void msm_prim_auxpcm_shutdown(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_card *card = rtd->card;
+ struct apq8074_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+ struct msm_auxpcm_ctrl *auxpcm_ctrl = NULL;
+
+ pr_debug("%s(): substream = %s, prim_auxpcm_rsc_ref counter = %d\n",
+ __func__, substream->name, atomic_read(&prim_auxpcm_rsc_ref));
+
+ auxpcm_ctrl = pdata->pri_auxpcm_ctrl;
+
+ if (atomic_dec_return(&prim_auxpcm_rsc_ref) == 0)
+ msm_aux_pcm_free_gpios(auxpcm_ctrl);
+}
+static struct snd_soc_ops msm_auxpcm_be_ops = {
+ .startup = msm_prim_auxpcm_startup,
+ .shutdown = msm_prim_auxpcm_shutdown,
+};
+
+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__);
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ slim0_rx_bit_format);
+ rate->min = rate->max = slim0_rx_sample_rate;
+ channels->min = channels->max = msm_slim_0_rx_ch;
+
+ pr_debug("%s: format = %d, rate = %d, channels = %d\n",
+ __func__, params_format(params), params_rate(params),
+ 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_5_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ int rc;
+ void *config;
+ struct snd_soc_codec *codec = rtd->codec;
+ 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 enter\n", __func__);
+ rate->min = rate->max = 16000;
+ channels->min = channels->max = 1;
+
+ config = taiko_get_afe_config(codec, AFE_SLIMBUS_SLAVE_PORT_CONFIG);
+ rc = afe_set_config(AFE_SLIMBUS_SLAVE_PORT_CONFIG, config,
+ SLIMBUS_5_TX);
+ if (rc) {
+ pr_err("%s: Failed to set slimbus slave port config %d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ 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 const struct soc_enum msm_snd_enum[] = {
+ SOC_ENUM_SINGLE_EXT(2, spk_function),
+ SOC_ENUM_SINGLE_EXT(2, slim0_rx_ch_text),
+ SOC_ENUM_SINGLE_EXT(5, slim0_tx_ch_text),
+ SOC_ENUM_SINGLE_EXT(7, hdmi_rx_ch_text),
+ SOC_ENUM_SINGLE_EXT(2, rx_bit_format_text),
+ SOC_ENUM_SINGLE_EXT(3, slim0_rx_sample_rate_text),
+ SOC_ENUM_SINGLE_EXT(8, proxy_rx_ch_text),
+};
+
+static const struct snd_kcontrol_new msm_snd_controls[] = {
+ SOC_ENUM_EXT("Speaker Function", msm_snd_enum[0], apq8074_get_spk,
+ apq8074_set_spk),
+ SOC_ENUM_EXT("SLIM_0_RX Channels", msm_snd_enum[1],
+ msm_slim_0_rx_ch_get, msm_slim_0_rx_ch_put),
+ SOC_ENUM_EXT("SLIM_0_TX Channels", msm_snd_enum[2],
+ msm_slim_0_tx_ch_get, msm_slim_0_tx_ch_put),
+ SOC_ENUM_EXT("AUX PCM SampleRate", apq8074_auxpcm_enum[0],
+ apq8074_auxpcm_rate_get, apq8074_auxpcm_rate_put),
+ SOC_ENUM_EXT("HDMI_RX Channels", msm_snd_enum[3],
+ msm_hdmi_rx_ch_get, msm_hdmi_rx_ch_put),
+ SOC_ENUM_EXT("SLIM_0_RX Format", msm_snd_enum[4],
+ slim0_rx_bit_format_get, slim0_rx_bit_format_put),
+ SOC_ENUM_EXT("SLIM_0_RX SampleRate", msm_snd_enum[5],
+ slim0_rx_sample_rate_get, slim0_rx_sample_rate_put),
+ SOC_ENUM_EXT("HDMI_RX Bit Format", msm_snd_enum[4],
+ hdmi_rx_bit_format_get, hdmi_rx_bit_format_put),
+ SOC_ENUM_EXT("PROXY_RX Channels", msm_snd_enum[6],
+ msm_proxy_rx_ch_get, msm_proxy_rx_ch_put),
+};
+
+static bool apq8074_swap_gnd_mic(struct snd_soc_codec *codec)
+{
+ struct snd_soc_card *card = codec->card;
+ struct apq8074_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+ int value = gpio_get_value_cansleep(pdata->us_euro_gpio);
+ pr_debug("%s: swap select switch %d to %d\n", __func__, value, !value);
+ gpio_set_value_cansleep(pdata->us_euro_gpio, !value);
+ return true;
+}
+
+static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
+{
+ int err;
+ void *config_data;
+ struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_dapm_context *dapm = &codec->dapm;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+
+ /* Taiko SLIMBUS configuration
+ * RX1, RX2, RX3, RX4, RX5, RX6, RX7, RX8, RX9, RX10, RX11, RX12, RX13
+ * TX1, TX2, TX3, TX4, TX5, TX6, TX7, TX8, TX9, TX10, TX11, TX12, TX13
+ * TX14, TX15, TX16
+ */
+ unsigned int rx_ch[TAIKO_RX_MAX] = {144, 145, 146, 147, 148, 149, 150,
+ 151, 152, 153, 154, 155, 156};
+ unsigned int tx_ch[TAIKO_TX_MAX] = {128, 129, 130, 131, 132, 133,
+ 134, 135, 136, 137, 138, 139,
+ 140, 141, 142, 143};
+
+
+ pr_info("%s(), dev_name%s\n", __func__, dev_name(cpu_dai->dev));
+
+ rtd->pmdown_time = 0;
+
+ err = snd_soc_add_codec_controls(codec, msm_snd_controls,
+ ARRAY_SIZE(msm_snd_controls));
+ if (err < 0)
+ return err;
+
+ err = apq8074_liquid_ext_spk_power_amp_init();
+ if (err) {
+ pr_err("%s: LiQUID 8974 CLASS_D PAs init failed (%d)\n",
+ __func__, err);
+ return err;
+ }
+
+ err = apq8074_liquid_init_docking(dapm);
+ if (err) {
+ pr_err("%s: LiQUID 8974 init Docking stat IRQ failed (%d)\n",
+ __func__, err);
+ return err;
+ }
+
+ snd_soc_dapm_new_controls(dapm, apq8074_dapm_widgets,
+ ARRAY_SIZE(apq8074_dapm_widgets));
+
+ snd_soc_dapm_enable_pin(dapm, "Lineout_1 amp");
+ snd_soc_dapm_enable_pin(dapm, "Lineout_3 amp");
+ snd_soc_dapm_enable_pin(dapm, "Lineout_2 amp");
+ snd_soc_dapm_enable_pin(dapm, "Lineout_4 amp");
+
+
+ snd_soc_dapm_sync(dapm);
+
+ codec_clk = clk_get(cpu_dai->dev, "osr_clk");
+
+ snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch),
+ tx_ch, ARRAY_SIZE(rx_ch), rx_ch);
+
+
+ config_data = taiko_get_afe_config(codec, AFE_CDC_REGISTERS_CONFIG);
+ err = afe_set_config(AFE_CDC_REGISTERS_CONFIG, config_data, 0);
+ if (err) {
+ pr_err("%s: Failed to set codec registers config %d\n",
+ __func__, err);
+ goto out;
+ }
+
+ config_data = taiko_get_afe_config(codec, AFE_SLIMBUS_SLAVE_CONFIG);
+ err = afe_set_config(AFE_SLIMBUS_SLAVE_CONFIG, config_data, 0);
+ if (err) {
+ pr_err("%s: Failed to set slimbus slave config %d\n", __func__,
+ err);
+ goto out;
+ }
+
+ config_data = taiko_get_afe_config(codec, AFE_AANC_VERSION);
+ err = afe_set_config(AFE_AANC_VERSION, config_data, 0);
+ if (err) {
+ pr_err("%s: Failed to set aanc version %d\n",
+ __func__, err);
+ goto out;
+ }
+ config_data = taiko_get_afe_config(codec,
+ AFE_CDC_CLIP_REGISTERS_CONFIG);
+ if (config_data) {
+ err = afe_set_config(AFE_CDC_CLIP_REGISTERS_CONFIG,
+ config_data, 0);
+ if (err) {
+ pr_err("%s: Failed to set clip registers %d\n",
+ __func__, err);
+ return err;
+ }
+ }
+ config_data = taiko_get_afe_config(codec, AFE_CLIP_BANK_SEL);
+ if (config_data) {
+ err = afe_set_config(AFE_CLIP_BANK_SEL, config_data, 0);
+ if (err) {
+ pr_err("%s: Failed to set AFE bank selection %d\n",
+ __func__, err);
+ return err;
+ }
+ }
+ /* start mbhc */
+ mbhc_cfg.calibration = def_taiko_mbhc_cal();
+ if (mbhc_cfg.calibration) {
+ err = taiko_hs_detect(codec, &mbhc_cfg);
+ if (err)
+ goto out;
+ else
+ return err;
+ } else {
+ err = -ENOMEM;
+ goto out;
+ }
+out:
+ clk_put(codec_clk);
+ return err;
+}
+
+static int apq8074_snd_startup(struct snd_pcm_substream *substream)
+{
+ pr_debug("%s(): substream = %s stream = %d\n", __func__,
+ substream->name, substream->stream);
+ return 0;
+}
+
+static void *def_taiko_mbhc_cal(void)
+{
+ void *taiko_cal;
+ struct wcd9xxx_mbhc_btn_detect_cfg *btn_cfg;
+ u16 *btn_low, *btn_high;
+ u8 *n_ready, *n_cic, *gain;
+
+ taiko_cal = kzalloc(WCD9XXX_MBHC_CAL_SIZE(WCD9XXX_MBHC_DEF_BUTTONS,
+ WCD9XXX_MBHC_DEF_RLOADS),
+ GFP_KERNEL);
+ if (!taiko_cal) {
+ pr_err("%s: out of memory\n", __func__);
+ return NULL;
+ }
+
+#define S(X, Y) ((WCD9XXX_MBHC_CAL_GENERAL_PTR(taiko_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) ((WCD9XXX_MBHC_CAL_PLUG_DET_PTR(taiko_cal)->X) = (Y))
+ S(mic_current, TAIKO_PID_MIC_5_UA);
+ S(hph_current, TAIKO_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) ((WCD9XXX_MBHC_CAL_PLUG_TYPE_PTR(taiko_cal)->X) = (Y))
+ S(v_no_mic, 30);
+ S(v_hs_max, 2400);
+#undef S
+#define S(X, Y) ((WCD9XXX_MBHC_CAL_BTN_DET_PTR(taiko_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, WCD9XXX_MBHC_DEF_BUTTONS);
+ S(v_btn_press_delta_sta, 100);
+ S(v_btn_press_delta_cic, 50);
+#undef S
+ btn_cfg = WCD9XXX_MBHC_CAL_BTN_DET_PTR(taiko_cal);
+ btn_low = wcd9xxx_mbhc_cal_btn_det_mp(btn_cfg, MBHC_BTN_DET_V_BTN_LOW);
+ btn_high = wcd9xxx_mbhc_cal_btn_det_mp(btn_cfg,
+ MBHC_BTN_DET_V_BTN_HIGH);
+ btn_low[0] = -50;
+ btn_high[0] = 20;
+ btn_low[1] = 21;
+ btn_high[1] = 61;
+ btn_low[2] = 62;
+ btn_high[2] = 104;
+ btn_low[3] = 105;
+ btn_high[3] = 148;
+ btn_low[4] = 149;
+ btn_high[4] = 189;
+ btn_low[5] = 190;
+ btn_high[5] = 228;
+ btn_low[6] = 229;
+ btn_high[6] = 269;
+ btn_low[7] = 270;
+ btn_high[7] = 500;
+ n_ready = wcd9xxx_mbhc_cal_btn_det_mp(btn_cfg, MBHC_BTN_DET_N_READY);
+ n_ready[0] = 80;
+ n_ready[1] = 68;
+ n_cic = wcd9xxx_mbhc_cal_btn_det_mp(btn_cfg, MBHC_BTN_DET_N_CIC);
+ n_cic[0] = 60;
+ n_cic[1] = 47;
+ gain = wcd9xxx_mbhc_cal_btn_det_mp(btn_cfg, MBHC_BTN_DET_GAIN);
+ gain[0] = 11;
+ gain[1] = 9;
+
+ return taiko_cal;
+}
+
+static int msm_snd_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 user_set_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;
+ }
+ } else {
+
+ pr_debug("%s: %s_tx_dai_id_%d_ch=%d\n", __func__,
+ codec_dai->name, codec_dai->id, user_set_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;
+ }
+ /* For tabla_tx1 case */
+ if (codec_dai->id == 1)
+ user_set_tx_ch = msm_slim_0_tx_ch;
+ /* For tabla_tx2 case */
+ else if (codec_dai->id == 3)
+ user_set_tx_ch = params_channels(params);
+ else
+ user_set_tx_ch = tx_ch_cnt;
+
+ pr_debug("%s: msm_slim_0_tx_ch(%d)user_set_tx_ch(%d)tx_ch_cnt(%d)\n",
+ __func__, msm_slim_0_tx_ch, user_set_tx_ch, tx_ch_cnt);
+
+ ret = snd_soc_dai_set_channel_map(cpu_dai,
+ user_set_tx_ch, tx_ch, 0 , 0);
+ if (ret < 0) {
+ pr_err("%s: failed to set cpu chan map\n", __func__);
+ goto end;
+ }
+ }
+end:
+ return ret;
+}
+
+static void apq8074_snd_shudown(struct snd_pcm_substream *substream)
+{
+ pr_debug("%s(): substream = %s stream = %d\n", __func__,
+ substream->name, substream->stream);
+
+}
+
+static struct snd_soc_ops apq8074_be_ops = {
+ .startup = apq8074_snd_startup,
+ .hw_params = msm_snd_hw_params,
+ .shutdown = apq8074_snd_shudown,
+};
+
+
+
+static int apq8074_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;
+ }
+ } 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;
+ }
+ }
+end:
+ return ret;
+}
+
+
+static struct snd_soc_ops apq8074_slimbus_2_be_ops = {
+ .startup = apq8074_snd_startup,
+ .hw_params = apq8074_slimbus_2_hw_params,
+ .shutdown = apq8074_snd_shudown,
+};
+
+/* Digital audio interface glue - connects codec <---> CPU */
+static struct snd_soc_dai_link apq8074_common_dai_links[] = {
+ /* FrontEnd DAI Links */
+ {
+ .name = "MSM8974 Media1",
+ .stream_name = "MultiMedia1",
+ .cpu_dai_name = "MultiMedia1",
+ .platform_name = "msm-pcm-dsp.0",
+ .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,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA1
+ },
+ {
+ .name = "MSM8974 Media2",
+ .stream_name = "MultiMedia2",
+ .cpu_dai_name = "MultiMedia2",
+ .platform_name = "msm-pcm-dsp.0",
+ .dynamic = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .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,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .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,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_VOIP,
+ },
+ {
+ .name = "MSM8974 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,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA3,
+ },
+ /* Hostless PCM 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, /* dai link has playback support */
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {
+ .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,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {
+ .name = "MSM AFE-PCM RX",
+ .stream_name = "AFE-PROXY RX",
+ .cpu_dai_name = "msm-dai-q6-dev.241",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .platform_name = "msm-pcm-afe",
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ },
+ {
+ .name = "MSM AFE-PCM TX",
+ .stream_name = "AFE-PROXY TX",
+ .cpu_dai_name = "msm-dai-q6-dev.240",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .platform_name = "msm-pcm-afe",
+ .ignore_suspend = 1,
+ },
+ {
+ .name = "MSM8974 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,
+ /* this dainlink has 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,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {
+ .name = "SLIMBUS_1 Hostless",
+ .stream_name = "SLIMBUS_1 Hostless",
+ .cpu_dai_name = "SLIMBUS1_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, /* dai link has playback support */
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {
+ .name = "SLIMBUS_3 Hostless",
+ .stream_name = "SLIMBUS_3 Hostless",
+ .cpu_dai_name = "SLIMBUS3_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, /* dai link has playback support */
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {
+ .name = "SLIMBUS_4 Hostless",
+ .stream_name = "SLIMBUS_4 Hostless",
+ .cpu_dai_name = "SLIMBUS4_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, /* dai link has playback support */
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {
+ .name = "VoLTE",
+ .stream_name = "VoLTE",
+ .cpu_dai_name = "VoLTE",
+ .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,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_VOLTE,
+ },
+ {
+ .name = "MSM8974 LowLatency",
+ .stream_name = "MultiMedia5",
+ .cpu_dai_name = "MultiMedia5",
+ .platform_name = "msm-pcm-dsp.1",
+ .dynamic = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA5,
+ },
+ /* LSM FE */
+ {
+ .name = "Listen Audio Service",
+ .stream_name = "Listen Audio Service",
+ .cpu_dai_name = "LSM",
+ .platform_name = "msm-lsm-client",
+ .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,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_LSM1,
+ },
+ /* Backend BT/FM DAI Links */
+ {
+ .name = LPASS_BE_INT_BT_SCO_RX,
+ .stream_name = "Internal BT-SCO Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.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,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_INT_BT_SCO_TX,
+ .stream_name = "Internal BT-SCO Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.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,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_INT_FM_RX,
+ .stream_name = "Internal FM Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.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,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_INT_FM_TX,
+ .stream_name = "Internal FM Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.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,
+ .ignore_suspend = 1,
+ },
+ /* Backend AFE DAI Links */
+ {
+ .name = LPASS_BE_AFE_PCM_RX,
+ .stream_name = "AFE Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.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_rx_be_hw_params_fixup,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_AFE_PCM_TX,
+ .stream_name = "AFE Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.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_tx_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+ /* 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,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ /* AUX PCM Backend DAI Links */
+ {
+ .name = LPASS_BE_AUXPCM_RX,
+ .stream_name = "AUX PCM Playback",
+ .cpu_dai_name = "msm-dai-q6.4106",
+ .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,
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ },
+ {
+ .name = LPASS_BE_AUXPCM_TX,
+ .stream_name = "AUX PCM Capture",
+ .cpu_dai_name = "msm-dai-q6.4107",
+ .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,
+ .ops = &msm_auxpcm_be_ops,
+ .ignore_suspend = 1,
+ },
+ /* Backend DAI Links */
+ {
+ .name = LPASS_BE_SLIMBUS_0_RX,
+ .stream_name = "Slimbus Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16384",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "taiko_codec",
+ .codec_dai_name = "taiko_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 = &apq8074_be_ops,
+ .ignore_pmdown_time = 1, /* dai link has playback support */
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_0_TX,
+ .stream_name = "Slimbus Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16385",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "taiko_codec",
+ .codec_dai_name = "taiko_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 = &apq8074_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_1_RX,
+ .stream_name = "Slimbus1 Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16386",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "taiko_codec",
+ .codec_dai_name = "taiko_rx1",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_1_RX,
+ .be_hw_params_fixup = msm_slim_0_rx_be_hw_params_fixup,
+ .ops = &apq8074_be_ops,
+ /* dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_1_TX,
+ .stream_name = "Slimbus1 Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16387",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "taiko_codec",
+ .codec_dai_name = "taiko_tx1",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_1_TX,
+ .be_hw_params_fixup = msm_slim_0_tx_be_hw_params_fixup,
+ .ops = &apq8074_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_3_RX,
+ .stream_name = "Slimbus3 Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16390",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "taiko_codec",
+ .codec_dai_name = "taiko_rx1",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_3_RX,
+ .be_hw_params_fixup = msm_slim_0_rx_be_hw_params_fixup,
+ .ops = &apq8074_be_ops,
+ /* dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_3_TX,
+ .stream_name = "Slimbus3 Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16391",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "taiko_codec",
+ .codec_dai_name = "taiko_tx1",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_3_TX,
+ .be_hw_params_fixup = msm_slim_0_tx_be_hw_params_fixup,
+ .ops = &apq8074_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_4_RX,
+ .stream_name = "Slimbus4 Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16392",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "taiko_codec",
+ .codec_dai_name = "taiko_rx1",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_4_RX,
+ .be_hw_params_fixup = msm_slim_0_rx_be_hw_params_fixup,
+ .ops = &apq8074_be_ops,
+ /* dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_4_TX,
+ .stream_name = "Slimbus4 Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16393",
+ .platform_name = "msm-pcm-hostless",
+ .codec_name = "taiko_codec",
+ .codec_dai_name = "taiko_vifeedback",
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_4_TX,
+ .be_hw_params_fixup = msm_slim_0_tx_be_hw_params_fixup,
+ .ops = &apq8074_be_ops,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ },
+ /* Incall Record Uplink BACK END DAI Link */
+ {
+ .name = LPASS_BE_INCALL_RECORD_TX,
+ .stream_name = "Voice Uplink Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.32772",
+ .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_INCALL_RECORD_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+ /* Incall Record Downlink BACK END DAI Link */
+ {
+ .name = LPASS_BE_INCALL_RECORD_RX,
+ .stream_name = "Voice Downlink Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.32771",
+ .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_INCALL_RECORD_RX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+ /* MAD BE */
+ {
+ .name = LPASS_BE_SLIMBUS_5_TX,
+ .stream_name = "Slimbus5 Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16395",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "taiko_codec",
+ .codec_dai_name = "taiko_mad1",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_5_TX,
+ .be_hw_params_fixup = msm_slim_5_tx_be_hw_params_fixup,
+ .ops = &apq8074_be_ops,
+ },
+ /* Incall Music BACK END DAI Link */
+ {
+ .name = LPASS_BE_VOICE_PLAYBACK_TX,
+ .stream_name = "Voice Farend Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.32773",
+ .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_VOICE_PLAYBACK_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+ /* Ultrasound RX Back End DAI Link */
+ {
+ .name = "SLIMBUS_2 Hostless Playback",
+ .stream_name = "SLIMBUS_2 Hostless Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16388",
+ .platform_name = "msm-pcm-hostless",
+ .codec_name = "taiko_codec",
+ .codec_dai_name = "taiko_rx2",
+ .ignore_suspend = 1,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ops = &apq8074_slimbus_2_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-dev.16389",
+ .platform_name = "msm-pcm-hostless",
+ .codec_name = "taiko_codec",
+ .codec_dai_name = "taiko_tx2",
+ .ignore_suspend = 1,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ops = &apq8074_slimbus_2_be_ops,
+ },
+};
+
+static struct snd_soc_dai_link apq8074_hdmi_dai_link[] = {
+/* 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-hdmi-audio-codec-rx",
+ .codec_dai_name = "msm_hdmi_audio_codec_rx_dai",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_HDMI_RX,
+ .be_hw_params_fixup = apq8074_hdmi_be_hw_params_fixup,
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+};
+
+static struct snd_soc_dai_link apq8074_dai_links[
+ ARRAY_SIZE(apq8074_common_dai_links) +
+ ARRAY_SIZE(apq8074_hdmi_dai_link)];
+
+struct snd_soc_card snd_soc_card_apq8074 = {
+ .name = "apq8074-taiko-snd-card",
+};
+
+static int apq8074_dtparse_auxpcm(struct platform_device *pdev,
+ struct msm_auxpcm_ctrl **auxpcm_ctrl,
+ char *msm_auxpcm_gpio_name[][2])
+{
+ int ret = 0;
+ int i = 0;
+ struct msm_auxpcm_gpio *pin_data = NULL;
+ struct msm_auxpcm_ctrl *ctrl;
+ unsigned int gpio_no[NUM_OF_AUXPCM_GPIOS];
+ enum of_gpio_flags flags = OF_GPIO_ACTIVE_LOW;
+ int auxpcm_cnt = 0;
+
+ pin_data = devm_kzalloc(&pdev->dev, (ARRAY_SIZE(gpio_no) *
+ sizeof(struct msm_auxpcm_gpio)),
+ GFP_KERNEL);
+ if (!pin_data) {
+ dev_err(&pdev->dev, "No memory for gpio\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(gpio_no); i++) {
+ gpio_no[i] = of_get_named_gpio_flags(pdev->dev.of_node,
+ msm_auxpcm_gpio_name[i][DT_PARSE_INDEX],
+ 0, &flags);
+
+ if (gpio_no[i] > 0) {
+ pin_data[i].gpio_name =
+ msm_auxpcm_gpio_name[auxpcm_cnt][GPIO_NAME_INDEX];
+ pin_data[i].gpio_no = gpio_no[i];
+ dev_dbg(&pdev->dev, "%s:GPIO gpio[%s] =\n"
+ "0x%x\n", __func__,
+ pin_data[i].gpio_name,
+ pin_data[i].gpio_no);
+ auxpcm_cnt++;
+ } else {
+ dev_err(&pdev->dev, "%s:Invalid AUXPCM GPIO[%s]= %x\n",
+ __func__,
+ msm_auxpcm_gpio_name[i][GPIO_NAME_INDEX],
+ gpio_no[i]);
+ ret = -ENODEV;
+ goto err;
+ }
+ }
+
+ ctrl = devm_kzalloc(&pdev->dev,
+ sizeof(struct msm_auxpcm_ctrl), GFP_KERNEL);
+ if (!ctrl) {
+ dev_err(&pdev->dev, "No memory for gpio\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ ctrl->pin_data = pin_data;
+ ctrl->cnt = auxpcm_cnt;
+ *auxpcm_ctrl = ctrl;
+ return ret;
+
+err:
+ if (pin_data)
+ devm_kfree(&pdev->dev, pin_data);
+ return ret;
+}
+
+static int apq8074_prepare_codec_mclk(struct snd_soc_card *card)
+{
+ struct apq8074_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+ int ret;
+ if (pdata->mclk_gpio) {
+ ret = gpio_request(pdata->mclk_gpio, "TAIKO_CODEC_PMIC_MCLK");
+ if (ret) {
+ dev_err(card->dev,
+ "%s: Failed to request taiko mclk gpio %d\n",
+ __func__, pdata->mclk_gpio);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int apq8074_prepare_us_euro(struct snd_soc_card *card)
+{
+ struct apq8074_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+ int ret;
+ if (pdata->us_euro_gpio) {
+ dev_dbg(card->dev, "%s : us_euro gpio request %d", __func__,
+ pdata->us_euro_gpio);
+ ret = gpio_request(pdata->us_euro_gpio, "TAIKO_CODEC_US_EURO");
+ if (ret) {
+ dev_err(card->dev,
+ "%s: Failed to request taiko US/EURO gpio %d error %d\n",
+ __func__, pdata->us_euro_gpio, ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static __devinit int apq8074_asoc_machine_probe(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = &snd_soc_card_apq8074;
+ struct apq8074_asoc_mach_data *pdata;
+ int ret;
+ const char *auxpcm_pri_gpio_set = NULL;
+
+ if (!pdev->dev.of_node) {
+ dev_err(&pdev->dev, "No platform supplied from device tree\n");
+ return -EINVAL;
+ }
+
+ pdata = devm_kzalloc(&pdev->dev,
+ sizeof(struct apq8074_asoc_mach_data), GFP_KERNEL);
+ if (!pdata) {
+ dev_err(&pdev->dev, "Can't allocate apq8074_asoc_mach_data\n");
+ return -ENOMEM;
+ }
+
+ /* Parse AUXPCM info from DT */
+ ret = apq8074_dtparse_auxpcm(pdev, &pdata->pri_auxpcm_ctrl,
+ msm_prim_auxpcm_gpio_name);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "%s: Auxpcm pin data parse failed\n", __func__);
+ goto err;
+ }
+
+ card->dev = &pdev->dev;
+ platform_set_drvdata(pdev, card);
+ snd_soc_card_set_drvdata(card, pdata);
+
+ ret = snd_soc_of_parse_card_name(card, "qcom,model");
+ if (ret)
+ goto err;
+
+ ret = snd_soc_of_parse_audio_routing(card,
+ "qcom,audio-routing");
+ if (ret)
+ goto err;
+
+ ret = of_property_read_u32(pdev->dev.of_node,
+ "qcom,taiko-mclk-clk-freq", &pdata->mclk_freq);
+ if (ret) {
+ dev_err(&pdev->dev, "Looking up %s property in node %s failed",
+ "qcom,taiko-mclk-clk-freq",
+ pdev->dev.of_node->full_name);
+ goto err;
+ }
+
+ if (pdata->mclk_freq != 9600000) {
+ dev_err(&pdev->dev, "unsupported taiko mclk freq %u\n",
+ pdata->mclk_freq);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ pdata->mclk_gpio = of_get_named_gpio(pdev->dev.of_node,
+ "qcom,cdc-mclk-gpios", 0);
+ if (pdata->mclk_gpio < 0) {
+ dev_err(&pdev->dev,
+ "Looking up %s property in node %s failed %d\n",
+ "qcom, cdc-mclk-gpios", pdev->dev.of_node->full_name,
+ pdata->mclk_gpio);
+ ret = -ENODEV;
+ goto err;
+ }
+
+
+ ret = apq8074_prepare_codec_mclk(card);
+ if (ret)
+ goto err;
+
+ if (of_property_read_bool(pdev->dev.of_node, "qcom,hdmi-audio-rx")) {
+ dev_info(&pdev->dev, "%s(): hdmi audio support present\n",
+ __func__);
+
+ memcpy(apq8074_dai_links, apq8074_common_dai_links,
+ sizeof(apq8074_common_dai_links));
+
+ memcpy(apq8074_dai_links + ARRAY_SIZE(apq8074_common_dai_links),
+ apq8074_hdmi_dai_link, sizeof(apq8074_hdmi_dai_link));
+
+ card->dai_link = apq8074_dai_links;
+ card->num_links = ARRAY_SIZE(apq8074_dai_links);
+ } else {
+ dev_info(&pdev->dev, "%s(): No hdmi audio support\n", __func__);
+
+ card->dai_link = apq8074_common_dai_links;
+ card->num_links = ARRAY_SIZE(apq8074_common_dai_links);
+ }
+
+ pdata->us_euro_gpio = of_get_named_gpio(pdev->dev.of_node,
+ "qcom,us-euro-gpios", 0);
+ if (pdata->us_euro_gpio < 0) {
+ dev_err(&pdev->dev, "Looking up %s property in node %s failed",
+ "qcom,us-euro-gpios",
+ pdev->dev.of_node->full_name);
+ } else {
+ dev_dbg(&pdev->dev, "%s detected %d",
+ "qcom,us-euro-gpios", pdata->us_euro_gpio);
+ mbhc_cfg.swap_gnd_mic = apq8074_swap_gnd_mic;
+ }
+
+ ret = apq8074_prepare_us_euro(card);
+ if (ret)
+ dev_err(&pdev->dev, "apq8074_prepare_us_euro failed (%d)\n",
+ ret);
+
+ mutex_init(&cdc_mclk_mutex);
+ atomic_set(&prim_auxpcm_rsc_ref, 0);
+ spdev = pdev;
+ ext_spk_amp_regulator = NULL;
+ apq8074_liquid_dock_dev = NULL;
+
+ ret = snd_soc_register_card(card);
+ if (ret) {
+ dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
+ ret);
+ goto err;
+ }
+
+ ret = of_property_read_string(pdev->dev.of_node,
+ "qcom,prim-auxpcm-gpio-set", &auxpcm_pri_gpio_set);
+ if (ret) {
+ dev_err(&pdev->dev, "Looking up %s property in node %s failed",
+ "qcom,prim-auxpcm-gpio-set",
+ pdev->dev.of_node->full_name);
+ goto err;
+ }
+ if (!strcmp(auxpcm_pri_gpio_set, "prim-gpio-prim")) {
+ lpaif_pri_muxsel_virt_addr =
+ ioremap(LPAIF_PRI_MODE_MUXSEL, 4);
+ } else if (!strcmp(auxpcm_pri_gpio_set, "prim-gpio-tert")) {
+ lpaif_pri_muxsel_virt_addr =
+ ioremap(LPAIF_TER_MODE_MUXSEL, 4);
+ } else {
+ dev_err(&pdev->dev, "Invalid value %s for AUXPCM GPIO set\n",
+ auxpcm_pri_gpio_set);
+ ret = -EINVAL;
+ goto err;
+ }
+ if (lpaif_pri_muxsel_virt_addr == NULL) {
+ pr_err("%s Pri muxsel virt addr is null\n", __func__);
+ ret = -EINVAL;
+ goto err;
+ }
+ return 0;
+
+err:
+ if (pdata->mclk_gpio > 0) {
+ dev_dbg(&pdev->dev, "%s free gpio %d\n",
+ __func__, pdata->mclk_gpio);
+ gpio_free(pdata->mclk_gpio);
+ pdata->mclk_gpio = 0;
+ }
+ if (pdata->us_euro_gpio > 0) {
+ dev_dbg(&pdev->dev, "%s free us_euro gpio %d\n",
+ __func__, pdata->us_euro_gpio);
+ gpio_free(pdata->us_euro_gpio);
+ pdata->us_euro_gpio = 0;
+ }
+ devm_kfree(&pdev->dev, pdata);
+ return ret;
+}
+
+static int __devexit apq8074_asoc_machine_remove(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+ struct apq8074_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+
+ if (ext_spk_amp_regulator)
+ regulator_put(ext_spk_amp_regulator);
+
+ if (gpio_is_valid(ext_ult_spk_amp_gpio))
+ gpio_free(ext_ult_spk_amp_gpio);
+
+ gpio_free(pdata->mclk_gpio);
+ gpio_free(pdata->us_euro_gpio);
+ if (gpio_is_valid(ext_spk_amp_gpio))
+ gpio_free(ext_spk_amp_gpio);
+
+ if (apq8074_liquid_dock_dev != NULL) {
+ if (apq8074_liquid_dock_dev->dock_plug_gpio)
+ gpio_free(apq8074_liquid_dock_dev->dock_plug_gpio);
+
+ if (apq8074_liquid_dock_dev->dock_plug_irq)
+ free_irq(apq8074_liquid_dock_dev->dock_plug_irq,
+ apq8074_liquid_dock_dev);
+
+ kfree(apq8074_liquid_dock_dev);
+ apq8074_liquid_dock_dev = NULL;
+ }
+
+ iounmap(lpaif_pri_muxsel_virt_addr);
+ snd_soc_unregister_card(card);
+
+ return 0;
+}
+
+static const struct of_device_id apq8074_asoc_machine_of_match[] = {
+ { .compatible = "qcom,apq8074-audio-taiko", },
+ {},
+};
+
+static struct platform_driver apq8074_asoc_machine_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ .pm = &snd_soc_pm_ops,
+ .of_match_table = apq8074_asoc_machine_of_match,
+ },
+ .probe = apq8074_asoc_machine_probe,
+ .remove = __devexit_p(apq8074_asoc_machine_remove),
+};
+module_platform_driver(apq8074_asoc_machine_driver);
+
+MODULE_DESCRIPTION("ALSA SoC msm");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRV_NAME);
+MODULE_DEVICE_TABLE(of, apq8074_asoc_machine_of_match);
diff --git a/sound/soc/msm/mdm9625.c b/sound/soc/msm/mdm9625.c
index f3ccb33..fd21c38 100644
--- a/sound/soc/msm/mdm9625.c
+++ b/sound/soc/msm/mdm9625.c
@@ -309,18 +309,18 @@
pr_err("set format for codec dai failed\n");
return ret;
}
- }
- /* This sets the CONFIG PARAMETER WS_SRC.
- * 1 means internal clock master mode.
- * 0 means external clock slave mode.
- */
- ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBS_CFS);
- if (ret < 0)
- pr_err("set fmt cpu dai failed\n");
+ /* This sets the CONFIG PARAMETER WS_SRC.
+ * 1 means internal clock master mode.
+ * 0 means external clock slave mode.
+ */
+ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBS_CFS);
+ if (ret < 0)
+ pr_err("set fmt cpu dai failed\n");
- ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_CBS_CFS);
- if (ret < 0)
- pr_err("set fmt for codec dai failed\n");
+ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_CBS_CFS);
+ if (ret < 0)
+ pr_err("set fmt for codec dai failed\n");
+ }
return ret;
}
diff --git a/sound/soc/msm/msm-pcm-loopback.c b/sound/soc/msm/msm-pcm-loopback.c
index 84ea9c6..ecf8394 100644
--- a/sound/soc/msm/msm-pcm-loopback.c
+++ b/sound/soc/msm/msm-pcm-loopback.c
@@ -22,11 +22,17 @@
#include <sound/pcm.h>
#include <sound/initval.h>
#include <sound/control.h>
+#include <sound/tlv.h>
#include <asm/dma.h>
#include <linux/dma-mapping.h>
#include "msm-pcm-routing.h"
+#define LOOPBACK_VOL_MAX_STEPS 0x2000
+
+static const DECLARE_TLV_DB_LINEAR(loopback_rx_vol_gain, 0,
+ LOOPBACK_VOL_MAX_STEPS);
+
struct msm_pcm_loopback {
struct snd_pcm_substream *playback_substream;
struct snd_pcm_substream *capture_substream;
@@ -42,6 +48,7 @@
int capture_start;
int session_id;
struct audio_client *audio_client;
+ int volume;
};
static void stop_pcm(struct msm_pcm_loopback *pcm);
@@ -99,6 +106,24 @@
}
}
+static int pcm_loopback_set_volume(struct msm_pcm_loopback *prtd, int volume)
+{
+ int rc = 0;
+
+ pr_debug("%s Setting volume 0x%x\n", __func__, volume);
+
+ if (prtd) {
+ rc = q6asm_set_volume(prtd->audio_client, volume);
+ if (rc < 0) {
+ pr_err("%s: Send Volume command failed rc = %d\n",
+ __func__, rc);
+ return rc;
+ }
+ prtd->volume = volume;
+ }
+ return rc;
+}
+
static int msm_pcm_open(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
@@ -111,6 +136,7 @@
mutex_lock(&pcm->lock);
snd_soc_set_runtime_hwparams(substream, &dummy_pcm_hardware);
+ pcm->volume = 0x2000;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
pcm->playback_substream = substream;
@@ -155,6 +181,13 @@
pcm->audio_client->perf_mode,
pcm->session_id, pcm->playback_substream->stream,
event);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ pcm->playback_substream = substream;
+ ret = pcm_loopback_set_volume(pcm, pcm->volume);
+ if (ret < 0)
+ dev_err(rtd->platform->dev,
+ "Error %d setting volume", ret);
+ }
}
dev_info(rtd->platform->dev, "%s: Instance = %d, Stream ID = %s\n",
__func__ , pcm->instance, substream->pcm->id);
@@ -290,6 +323,38 @@
.trigger = msm_pcm_trigger,
};
+static int msm_pcm_volume_ctl_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int rc = 0;
+ struct snd_pcm_volume *vol = kcontrol->private_data;
+ struct snd_pcm_substream *substream = vol->pcm->streams[0].substream;
+ struct msm_pcm_loopback *prtd = substream->runtime->private_data;
+ int volume = ucontrol->value.integer.value[0];
+
+ rc = pcm_loopback_set_volume(prtd, volume);
+ return rc;
+}
+
+static int msm_pcm_add_controls(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_pcm *pcm = rtd->pcm->streams[0].pcm;
+ struct snd_pcm_volume *volume_info;
+ struct snd_kcontrol *kctl;
+ int ret = 0;
+
+ dev_dbg(rtd->dev, "%s, Volume cntrl add\n", __func__);
+ ret = snd_pcm_add_volume_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ NULL, 1,
+ rtd->dai_link->be_id,
+ &volume_info);
+ if (ret < 0)
+ return ret;
+ kctl = volume_info->kctl;
+ kctl->put = msm_pcm_volume_ctl_put;
+ kctl->tlv.p = loopback_rx_vol_gain;
+ return 0;
+}
static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
{
@@ -298,6 +363,10 @@
if (!card->dev->coherent_dma_mask)
card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+
+ ret = msm_pcm_add_controls(rtd);
+ if (ret)
+ dev_err(rtd->dev, "%s, kctl add failed\n", __func__);
return ret;
}
diff --git a/sound/soc/msm/msm8226.c b/sound/soc/msm/msm8226.c
index da3a8e0..1d3779f 100644
--- a/sound/soc/msm/msm8226.c
+++ b/sound/soc/msm/msm8226.c
@@ -91,6 +91,7 @@
int mclk_gpio;
u32 mclk_freq;
struct msm_auxpcm_ctrl *auxpcm_ctrl;
+ u32 us_euro_gpio;
};
#define GPIO_NAME_INDEX 0
@@ -1353,6 +1354,44 @@
return 0;
}
+static bool msm8226_swap_gnd_mic(struct snd_soc_codec *codec)
+{
+ struct snd_soc_card *card = codec->card;
+ struct msm8226_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+ int value = gpio_get_value_cansleep(pdata->us_euro_gpio);
+
+ pr_debug("%s: swap select switch %d to %d\n", __func__, value, !value);
+ gpio_direction_output(pdata->us_euro_gpio, !value);
+
+ return true;
+}
+
+static int msm8226_setup_hs_jack(struct platform_device *pdev,
+ struct msm8226_asoc_mach_data *pdata)
+{
+ int rc;
+
+ pdata->us_euro_gpio = of_get_named_gpio(pdev->dev.of_node,
+ "qcom,cdc-us-euro-gpios", 0);
+ if (pdata->us_euro_gpio < 0) {
+ dev_info(&pdev->dev,
+ "property %s in node %s not found %d\n",
+ "qcom,cdc-us-euro-gpios", pdev->dev.of_node->full_name,
+ pdata->us_euro_gpio);
+ } else {
+ rc = gpio_request(pdata->us_euro_gpio,
+ "TAPAN_CODEC_US_EURO_GPIO");
+ if (rc) {
+ dev_err(&pdev->dev,
+ "%s: Failed to request tapan us-euro gpio %d\n",
+ __func__, pdata->us_euro_gpio);
+ } else {
+ mbhc_cfg.swap_gnd_mic = msm8226_swap_gnd_mic;
+ }
+ }
+ return 0;
+}
+
static __devinit int msm8226_asoc_machine_probe(struct platform_device *pdev)
{
struct snd_soc_card *card = &snd_soc_card_msm8226;
@@ -1442,6 +1481,7 @@
mbhc_cfg.gpio_level_insert = of_property_read_bool(pdev->dev.of_node,
"qcom,headset-jack-type-NO");
+ msm8226_setup_hs_jack(pdev, pdata);
ret = msm8226_prepare_codec_mclk(card);
if (ret)
@@ -1505,6 +1545,9 @@
gpio_free(pdata->mclk_gpio);
gpio_free(vdd_spkr_gpio);
+ if (pdata->us_euro_gpio > 0)
+ gpio_free(pdata->us_euro_gpio);
+
vdd_spkr_gpio = -1;
snd_soc_unregister_card(card);
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index 5d9aa53..c25eb86 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -19,18 +19,20 @@
#include <linux/mfd/pm8xxx/pm8921.h>
#include <linux/qpnp/clkdiv.h>
#include <linux/regulator/consumer.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/pcm.h>
#include <sound/jack.h>
#include <sound/q6afe-v2.h>
-#include <asm/mach-types.h>
-#include <mach/socinfo.h>
#include <sound/pcm_params.h>
+#include <asm/mach-types.h>
+#include <mach/subsystem_notif.h>
#include "qdsp6v2/msm-pcm-routing-v2.h"
+#include "qdsp6v2/q6core.h"
+#include "../codecs/wcd9xxx-common.h"
#include "../codecs/wcd9320.h"
-#include <linux/io.h>
#define DRV_NAME "msm8974-asoc-taiko"
@@ -82,6 +84,10 @@
#define NUM_OF_AUXPCM_GPIOS 4
+static void *adsp_state_notifier;
+
+#define ADSP_STATE_READY_TIMEOUT_MS 3000
+
static inline int param_is_mask(int p)
{
return ((p >= SNDRV_PCM_HW_PARAM_FIRST_MASK) &&
@@ -1357,6 +1363,101 @@
return true;
}
+static int msm_afe_set_config(struct snd_soc_codec *codec)
+{
+ int rc;
+ void *config_data;
+
+ pr_debug("%s: enter\n", __func__);
+ config_data = taiko_get_afe_config(codec, AFE_CDC_REGISTERS_CONFIG);
+ rc = afe_set_config(AFE_CDC_REGISTERS_CONFIG, config_data, 0);
+ if (rc) {
+ pr_err("%s: Failed to set codec registers config %d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ config_data = taiko_get_afe_config(codec, AFE_SLIMBUS_SLAVE_CONFIG);
+ rc = afe_set_config(AFE_SLIMBUS_SLAVE_CONFIG, config_data, 0);
+ if (rc) {
+ pr_err("%s: Failed to set slimbus slave config %d\n", __func__,
+ rc);
+ return rc;
+ }
+
+ return 0;
+}
+
+static void msm_afe_clear_config(void)
+{
+ afe_clear_config(AFE_CDC_REGISTERS_CONFIG);
+ afe_clear_config(AFE_SLIMBUS_SLAVE_CONFIG);
+}
+
+static int msm8974_adsp_state_callback(struct notifier_block *nb,
+ unsigned long value, void *priv)
+{
+ if (value == SUBSYS_BEFORE_SHUTDOWN) {
+ pr_debug("%s: ADSP is about to shutdown. Clearing AFE config\n",
+ __func__);
+ msm_afe_clear_config();
+ } else if (value == SUBSYS_AFTER_POWERUP) {
+ pr_debug("%s: ADSP is up\n", __func__);
+ }
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block adsp_state_notifier_block = {
+ .notifier_call = msm8974_adsp_state_callback,
+ .priority = -INT_MAX,
+};
+
+static int msm8974_taiko_codec_up(struct snd_soc_codec *codec)
+{
+ int err;
+ unsigned long timeout;
+ int adsp_ready = 0;
+
+ timeout = jiffies +
+ msecs_to_jiffies(ADSP_STATE_READY_TIMEOUT_MS);
+
+ do {
+ if (!q6core_is_adsp_ready()) {
+ pr_err("%s: ADSP Audio isn't ready\n", __func__);
+ } else {
+ pr_debug("%s: ADSP Audio is ready\n", __func__);
+ adsp_ready = 1;
+ break;
+ }
+ } while (time_after(timeout, jiffies));
+
+ if (!adsp_ready) {
+ pr_err("%s: timed out waiting for ADSP Audio\n", __func__);
+ return -ETIMEDOUT;
+ }
+
+ err = msm_afe_set_config(codec);
+ if (err)
+ pr_err("%s: Failed to set AFE config. err %d\n",
+ __func__, err);
+ return err;
+}
+
+static int msm8974_taiko_event_cb(struct snd_soc_codec *codec,
+ enum wcd9xxx_codec_event codec_event)
+{
+ switch (codec_event) {
+ case WCD9XXX_CODEC_EVENT_CODEC_UP:
+ return msm8974_taiko_codec_up(codec);
+ break;
+ default:
+ pr_err("%s: UnSupported codec event %d\n",
+ __func__, codec_event);
+ return -EINVAL;
+ }
+}
+
static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
{
int err;
@@ -1418,19 +1519,9 @@
tx_ch, ARRAY_SIZE(rx_ch), rx_ch);
- config_data = taiko_get_afe_config(codec, AFE_CDC_REGISTERS_CONFIG);
- err = afe_set_config(AFE_CDC_REGISTERS_CONFIG, config_data, 0);
+ err = msm_afe_set_config(codec);
if (err) {
- pr_err("%s: Failed to set codec registers config %d\n",
- __func__, err);
- goto out;
- }
-
- config_data = taiko_get_afe_config(codec, AFE_SLIMBUS_SLAVE_CONFIG);
- err = afe_set_config(AFE_SLIMBUS_SLAVE_CONFIG, config_data, 0);
- if (err) {
- pr_err("%s: Failed to set slimbus slave config %d\n", __func__,
- err);
+ pr_err("%s: Failed to set AFE config %d\n", __func__, err);
goto out;
}
@@ -1467,12 +1558,22 @@
err = taiko_hs_detect(codec, &mbhc_cfg);
if (err)
goto out;
- else
- return err;
} else {
err = -ENOMEM;
goto out;
}
+ adsp_state_notifier =
+ subsys_notif_register_notifier("adsp",
+ &adsp_state_notifier_block);
+ if (!adsp_state_notifier) {
+ pr_err("%s: Failed to register adsp state notifier\n",
+ __func__);
+ err = -EFAULT;
+ goto out;
+ }
+
+ taiko_event_register(msm8974_taiko_event_cb, rtd->codec);
+ return 0;
out:
clk_put(codec_clk);
return err;
diff --git a/sound/soc/msm/msm8x10.c b/sound/soc/msm/msm8x10.c
index 02f6ff1..96f78d9 100644
--- a/sound/soc/msm/msm8x10.c
+++ b/sound/soc/msm/msm8x10.c
@@ -38,6 +38,7 @@
static int msm_btsco_ch = 1;
static int msm_proxy_rx_ch = 2;
+static struct snd_soc_jack hs_jack;
#define MSM8X10_DINO_LPASS_AUDIO_CORE_DIG_CODEC_CLK_SEL 0xFE03B004
#define MSM8X10_DINO_LPASS_DIGCODEC_CMD_RCGR 0xFE02C000
@@ -386,6 +387,15 @@
snd_soc_dapm_sync(dapm);
ret = msm_enable_mclk_root(AFE_PORT_ID_SECONDARY_MI2S_RX,
&digital_cdc_clk);
+
+ ret = snd_soc_jack_new(codec, "Headset Jack",
+ SND_JACK_HEADSET, &hs_jack);
+
+ if (ret) {
+ pr_err("%s: Failed to create headset jack\n", __func__);
+ return ret;
+ }
+
exit:
return ret;
}
@@ -652,7 +662,6 @@
.codec_dai_name = "msm8x10_wcd_i2s_tx1",
.no_pcm = 1,
.be_id = MSM_BACKEND_DAI_PRI_MI2S_TX,
- .init = &msm_audrx_init,
.be_hw_params_fixup = msm_be_hw_params_fixup,
.ops = &msm8x10_mi2s_be_ops,
.ignore_suspend = 1,
diff --git a/sound/soc/msm/qdsp6v2/msm-lsm-client.c b/sound/soc/msm/qdsp6v2/msm-lsm-client.c
index 363fb15..f76d455 100644
--- a/sound/soc/msm/qdsp6v2/msm-lsm-client.c
+++ b/sound/soc/msm/qdsp6v2/msm-lsm-client.c
@@ -117,8 +117,8 @@
if (copy_from_user(prtd->lsm_client->sound_model.data,
snd_model.data, snd_model.data_size)) {
- pr_err("%s: copy from user data failed size %d\n",
- __func__, snd_model.data_size);
+ pr_err("%s: copy from user data failed data %p size %d\n",
+ __func__, snd_model.data, snd_model.data_size);
rc = -EFAULT;
break;
}
@@ -128,9 +128,12 @@
snd_model.min_keyw_confidence,
snd_model.min_user_confidence,
snd_model.detect_failure);
- if (rc < 0)
+ if (rc < 0) {
pr_err("%s: q6lsm_register_sound_model failed =%d\n",
__func__, rc);
+ q6lsm_snd_model_buf_free(prtd->lsm_client);
+ }
+
break;
case SNDRV_LSM_DEREG_SND_MODEL:
@@ -213,11 +216,10 @@
pr_debug("%s: Stopping LSM client session\n", __func__);
if (prtd->lsm_client->started) {
ret = q6lsm_stop(prtd->lsm_client, true);
- if (!ret) {
- prtd->lsm_client->started = false;
- pr_debug("%s: LSM client session stopped\n",
- __func__);
- }
+ if (!ret)
+ pr_debug("%s: LSM client session stopped %d\n",
+ __func__, ret);
+ prtd->lsm_client->started = false;
}
break;
@@ -258,10 +260,10 @@
}
ret = q6lsm_open(prtd->lsm_client);
if (ret < 0) {
- pr_err("%s: lsm out open failed\n", __func__);
+ pr_err("%s: lsm open failed, %d\n", __func__, ret);
q6lsm_client_free(prtd->lsm_client);
kfree(prtd);
- return -ENOMEM;
+ return ret;
}
pr_debug("%s: Session ID %d\n", __func__, prtd->lsm_client->session);
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index d7148f1..997946d 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -58,6 +58,7 @@
static int srs_alsa_ctrl_ever_called;
static int lsm_mux_slim_port;
static int slim0_rx_aanc_fb_port;
+static int msm_route_ec_ref_rx = 3; /* NONE */
enum {
MADNONE,
@@ -1347,6 +1348,51 @@
return 0;
}
+static int msm_routing_ec_ref_rx_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: ec_ref_rx = %d", __func__, msm_route_ec_ref_rx);
+ ucontrol->value.integer.value[0] = msm_route_ec_ref_rx;
+ return 0;
+}
+
+static int msm_routing_ec_ref_rx_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ec_ref_port_id;
+ mutex_lock(&routing_lock);
+ switch (ucontrol->value.integer.value[0]) {
+ case 0:
+ msm_route_ec_ref_rx = 0;
+ ec_ref_port_id = SLIMBUS_0_RX;
+ break;
+ case 1:
+ msm_route_ec_ref_rx = 1;
+ ec_ref_port_id = PRIMARY_I2S_RX;
+ break;
+ default:
+ msm_route_ec_ref_rx = 3; /* NONE */
+ ec_ref_port_id = -1;
+ break;
+ }
+ adm_ec_ref_rx_id(ec_ref_port_id);
+ pr_debug("%s: msm_route_ec_ref_rx = %d\n",
+ __func__, msm_route_ec_ref_rx);
+ mutex_unlock(&routing_lock);
+ return 0;
+}
+
+static const char *const ec_ref_rx[] = { "SLIM_RX", "I2S_RX", "PROXY_RX",
+ "NONE" };
+static const struct soc_enum msm_route_ec_ref_rx_enum[] = {
+ SOC_ENUM_SINGLE_EXT(4, ec_ref_rx),
+};
+
+static const struct snd_kcontrol_new ec_ref_rx_mixer_controls[] = {
+ SOC_ENUM_EXT("EC_REF_RX", msm_route_ec_ref_rx_enum[0],
+ msm_routing_ec_ref_rx_get, msm_routing_ec_ref_rx_put),
+};
+
static const struct snd_kcontrol_new pri_i2s_rx_mixer_controls[] = {
SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_PRI_I2S_RX ,
MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
@@ -1897,6 +1943,9 @@
SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_SLIMBUS_0_RX ,
MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_SLIMBUS_0_RX ,
MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
@@ -2161,6 +2210,15 @@
SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_MI2S_TX,
MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_AUXPCM_TX,
+ MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_SEC_AUXPCM_TX,
+ MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+ MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
};
static const struct snd_kcontrol_new sbus_0_rx_port_mixer_controls[] = {
@@ -2179,6 +2237,9 @@
SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_SLIMBUS_0_RX,
MSM_BACKEND_DAI_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_BACKEND_DAI_INT_BT_SCO_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
};
static const struct snd_kcontrol_new auxpcm_rx_port_mixer_controls[] = {
@@ -2217,6 +2278,9 @@
SOC_SINGLE_EXT("SLIM_1_TX", MSM_BACKEND_DAI_INT_BT_SCO_RX,
MSM_BACKEND_DAI_SLIMBUS_1_TX, 1, 0, msm_routing_get_port_mixer,
msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+ MSM_BACKEND_DAI_SLIMBUS_0_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
};
static const struct snd_kcontrol_new afe_pcm_rx_port_mixer_controls[] = {
@@ -3192,6 +3256,7 @@
{"SLIM_0_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
{"SLIM_0_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"SLIM_0_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
+ {"SLIM_0_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
{"SLIMBUS_0_RX", NULL, "SLIM_0_RX_Voice Mixer"},
{"INTERNAL_BT_SCO_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
@@ -3213,12 +3278,14 @@
{"AUX_PCM_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
{"AUX_PCM_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"AUX_PCM_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
+ {"AUX_PCM_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
{"AUX_PCM_RX", NULL, "AUX_PCM_RX_Voice Mixer"},
{"SEC_AUX_PCM_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
{"SEC_AUX_PCM_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
{"SEC_AUX_PCM_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"SEC_AUX_PCM_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
+ {"SEC_AUX_PCM_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
{"SEC_AUX_PCM_RX", NULL, "SEC_AUX_PCM_RX_Voice Mixer"},
{"HDMI_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
@@ -3310,6 +3377,7 @@
{"SLIMBUS_0_RX Port Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
{"SLIMBUS_0_RX Port Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"},
{"SLIMBUS_0_RX Port Mixer", "MI2S_TX", "MI2S_TX"},
+ {"SLIMBUS_0_RX Port Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
{"SLIMBUS_0_RX", NULL, "SLIMBUS_0_RX Port Mixer"},
{"AFE_PCM_RX Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
{"PCM_RX", NULL, "AFE_PCM_RX Port Mixer"},
@@ -3326,7 +3394,10 @@
{"Voice Stub Tx Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"},
{"Voice Stub Tx Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
{"Voice Stub Tx Mixer", "STUB_1_TX_HL", "STUB_1_TX"},
+ {"Voice Stub Tx Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
+ {"Voice Stub Tx Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"},
{"Voice Stub Tx Mixer", "MI2S_TX", "MI2S_TX"},
+ {"Voice Stub Tx Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
{"VOICE_STUB_UL", NULL, "Voice Stub Tx Mixer"},
{"STUB_RX Mixer", "Voice Stub", "VOICE_STUB_DL"},
@@ -3340,6 +3411,7 @@
{"SLIMBUS_1_RX Port Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
{"SLIMBUS_1_RX", NULL, "SLIMBUS_1_RX Port Mixer"},
{"INTERNAL_BT_SCO_RX Port Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"},
+ {"INTERNAL_BT_SCO_RX Port Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
{"INT_BT_SCO_RX", NULL, "INTERNAL_BT_SCO_RX Port Mixer"},
{"SLIMBUS_3_RX Port Mixer", "INTERNAL_BT_SCO_RX", "INT_BT_SCO_RX"},
{"SLIMBUS_3_RX Port Mixer", "MI2S_TX", "MI2S_TX"},
@@ -3664,6 +3736,9 @@
dolby_dap_param_end_point_controls,
ARRAY_SIZE(dolby_dap_param_end_point_controls));
+ snd_soc_add_platform_controls(platform,
+ ec_ref_rx_mixer_controls,
+ ARRAY_SIZE(ec_ref_rx_mixer_controls));
return 0;
}
diff --git a/sound/soc/msm/qdsp6v2/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c
index 5f9d4db..bdb0e13 100644
--- a/sound/soc/msm/qdsp6v2/q6adm.c
+++ b/sound/soc/msm/qdsp6v2/q6adm.c
@@ -55,6 +55,7 @@
atomic_t mem_map_cal_index;
int set_custom_topology;
+ int ec_ref_rx;
};
static struct adm_ctl this_adm;
@@ -965,7 +966,13 @@
open.mode_of_operation = path;
open.endpoint_id_1 = tmp_port;
- open.endpoint_id_2 = 0xFFFF;
+
+ if (this_adm.ec_ref_rx == -1) {
+ open.endpoint_id_2 = 0xFFFF;
+ } else if (this_adm.ec_ref_rx && (path != 1)) {
+ open.endpoint_id_2 = this_adm.ec_ref_rx;
+ this_adm.ec_ref_rx = -1;
+ }
open.topology_id = topology;
if ((open.topology_id == VPM_TX_SM_ECNS_COPP_TOPOLOGY) ||
@@ -1366,6 +1373,12 @@
return atomic_read(&this_adm.copp_id[port_index]);
}
+void adm_ec_ref_rx_id(int port_id)
+{
+ this_adm.ec_ref_rx = port_id;
+ pr_debug("%s ec_ref_rx:%d", __func__, this_adm.ec_ref_rx);
+}
+
int adm_close(int port_id, bool perf_mode)
{
struct apr_hdr close;
@@ -1471,6 +1484,7 @@
int i = 0;
this_adm.apr = NULL;
this_adm.set_custom_topology = 1;
+ this_adm.ec_ref_rx = -1;
for (i = 0; i < AFE_MAX_PORTS; i++) {
atomic_set(&this_adm.copp_id[i], RESET_COPP_ID);
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
index 7de058d..3bb31f9 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -50,6 +50,7 @@
};
static atomic_t afe_ports_mad_type[SLIMBUS_PORT_LAST - SLIMBUS_0_RX];
+static unsigned long afe_configured_cmd;
static struct afe_ctl this_afe;
@@ -1053,10 +1054,28 @@
ret = -EINVAL;
}
+ if (!ret)
+ set_bit(config_type, &afe_configured_cmd);
+
pr_debug("%s: leave ret %d\n", __func__, ret);
return ret;
}
+/*
+ * afe_clear_config - If SSR happens ADSP loses AFE configs, let AFE driver know
+ * about the state so client driver can wait until AFE is
+ * reconfigured.
+ */
+void afe_clear_config(enum afe_config_type config)
+{
+ clear_bit(config, &afe_configured_cmd);
+}
+
+bool afe_has_config(enum afe_config_type config)
+{
+ return !!test_bit(config, &afe_configured_cmd);
+}
+
static int afe_send_cmd_port_start(u16 port_id)
{
struct afe_port_cmd_device_start start;
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index ac26d0c..5136cb9 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -578,7 +578,8 @@
void *q6asm_mmap_apr_reg(void)
{
- if (atomic_read(&this_mmap.ref_cnt) == 0) {
+ if ((atomic_read(&this_mmap.ref_cnt) == 0) ||
+ (this_mmap.apr == NULL)) {
this_mmap.apr = apr_register("ADSP", "ASM", \
(apr_fn)q6asm_mmapcallback,\
0x0FFFFFFFF, &this_mmap);
diff --git a/sound/soc/msm/qdsp6v2/q6core.c b/sound/soc/msm/qdsp6v2/q6core.c
index 5fec0c1..e9352df 100644
--- a/sound/soc/msm/qdsp6v2/q6core.c
+++ b/sound/soc/msm/qdsp6v2/q6core.c
@@ -30,6 +30,7 @@
wait_queue_head_t bus_bw_req_wait;
u32 bus_bw_resp_received;
struct avcs_cmd_rsp_get_low_power_segments_info_t lp_ocm_payload;
+ u32 param;
};
static struct q6core_str q6core_lcl;
@@ -102,6 +103,17 @@
break;
}
+ case AVCS_CMDRSP_ADSP_EVENT_GET_STATE:
+ payload1 = data->payload;
+ q6core_lcl.param = payload1[0];
+ pr_debug("%s: Received ADSP get state response 0x%x\n",
+ __func__, q6core_lcl.param);
+ /* ensure .param is updated prior to .bus_bw_resp_received */
+ wmb();
+ q6core_lcl.bus_bw_resp_received = 1;
+ wake_up(&q6core_lcl.bus_bw_req_wait);
+ break;
+
default:
pr_err("Message id from adsp core svc: %d\n", data->opcode);
break;
@@ -197,6 +209,39 @@
return ret;
}
+bool q6core_is_adsp_ready(void)
+{
+ int rc;
+ bool ret = false;
+ struct apr_hdr hdr;
+
+ pr_debug("%s: enter\n", __func__);
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE, 0);
+ hdr.opcode = AVCS_CMD_ADSP_EVENT_GET_STATE;
+
+ ocm_core_open();
+ q6core_lcl.bus_bw_resp_received = 0;
+ rc = apr_send_pkt(q6core_lcl.core_handle_q, (uint32_t *)&hdr);
+ if (rc < 0) {
+ pr_err("%s: Get ADSP state APR packet send event\n", __func__);
+ goto bail;
+ }
+
+ rc = wait_event_timeout(q6core_lcl.bus_bw_req_wait,
+ (q6core_lcl.bus_bw_resp_received == 1),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (rc > 0 && q6core_lcl.bus_bw_resp_received) {
+ /* ensure to read updated param by callback thread */
+ rmb();
+ ret = !!q6core_lcl.param;
+ }
+bail:
+ pr_debug("%s: leave, rc %d, adsp ready %d\n", __func__, rc, ret);
+ return ret;
+}
static int __init core_init(void)
{
diff --git a/sound/soc/msm/qdsp6v2/q6core.h b/sound/soc/msm/qdsp6v2/q6core.h
index 39bf4ab..e5a59bc 100644
--- a/sound/soc/msm/qdsp6v2/q6core.h
+++ b/sound/soc/msm/qdsp6v2/q6core.h
@@ -25,6 +25,9 @@
#define AVCS_CMDRSP_GET_LOW_POWER_SEGMENTS_INFO 0x00012904
+#define AVCS_CMD_ADSP_EVENT_GET_STATE 0x0001290C
+#define AVCS_CMDRSP_ADSP_EVENT_GET_STATE 0x0001290D
+
/* @brief AVCS_CMDRSP_GET_LOW_POWER_SEGMENTS_INFO payload
* structure. Payload for this event comprises one instance of
* avcs_cmd_rsp_get_low_power_segments_info_t, followed
@@ -89,6 +92,7 @@
int core_get_low_power_segments(
struct avcs_cmd_rsp_get_low_power_segments_info_t **);
+bool q6core_is_adsp_ready(void);
#define ADSP_CMD_SET_DOLBY_MANUFACTURER_ID 0x00012918
diff --git a/sound/soc/msm/qdsp6v2/q6lsm.c b/sound/soc/msm/qdsp6v2/q6lsm.c
index 49e5ede..c5483ee 100644
--- a/sound/soc/msm/qdsp6v2/q6lsm.c
+++ b/sound/soc/msm/qdsp6v2/q6lsm.c
@@ -31,6 +31,7 @@
#include <mach/memory.h>
#include <mach/debug_mm.h>
#include "audio_acdb.h"
+#include "q6core.h"
#define APR_TIMEOUT (5 * HZ)
#define LSM_CAL_SIZE 4096
@@ -70,7 +71,6 @@
static int q6lsm_mmapcallback(struct apr_client_data *data, void *priv);
static int q6lsm_send_cal(struct lsm_client *client);
-static int q6lsm_snd_model_buf_free(struct lsm_client *client);
static int q6lsm_callback(struct apr_client_data *data, void *priv)
{
@@ -83,6 +83,13 @@
return -EINVAL;
}
+ if (data->opcode == RESET_EVENTS) {
+ pr_debug("%s: SSR event received 0x%x, event 0x%x, proc 0x%x\n",
+ __func__, data->opcode, data->reset_event,
+ data->reset_proc);
+ return 0;
+ }
+
payload = data->payload;
pr_debug("%s: Session %d opcode 0x%x token 0x%x payload size %d\n",
__func__, client->session,
@@ -311,6 +318,13 @@
int rc;
struct lsm_stream_cmd_open_tx open;
+ if (!afe_has_config(AFE_CDC_REGISTERS_CONFIG) ||
+ !afe_has_config(AFE_SLIMBUS_SLAVE_CONFIG)) {
+ pr_err("%s: AFE isn't configured yet\n", __func__);
+ rc = -EAGAIN;
+ goto exit;
+ }
+
memset(&open, 0, sizeof(open));
q6lsm_add_hdr(client, &open.hdr, sizeof(open), true);
@@ -323,6 +337,7 @@
pr_err("%s: Open failed opcode 0x%x, rc %d\n",
__func__, open.hdr.opcode, rc);
+exit:
pr_debug("%s: leave %d\n", __func__, rc);
return rc;
}
@@ -461,9 +476,10 @@
cmd.hdr.opcode, rc);
} else {
pr_debug("%s: Deregister sound model succeeded\n", __func__);
- q6lsm_snd_model_buf_free(client);
}
+ q6lsm_snd_model_buf_free(client);
+
return rc;
}
@@ -493,8 +509,8 @@
int rc;
int cmd_size = 0;
- pr_debug("%s: dma_addr_p 0x%x, dma_buf_sz %d, session %d\n",
- __func__, dma_addr_p, dma_buf_sz, client->session);
+ pr_debug("%s: dma_addr_p 0x%x, dma_buf_sz %d, mmap_p 0x%p, session %d\n",
+ __func__, dma_addr_p, dma_buf_sz, mmap_p, client->session);
cmd_size = sizeof(struct avs_cmd_shared_mem_map_regions) +
sizeof(struct avs_shared_map_region_payload);
@@ -530,6 +546,29 @@
return rc;
}
+static int q6lsm_memory_unmap_regions(struct lsm_client *client,
+ uint32_t handle)
+{
+ struct avs_cmd_shared_mem_unmap_regions unmap;
+ int rc = 0;
+ int cmd_size = 0;
+
+ cmd_size = sizeof(struct avs_cmd_shared_mem_unmap_regions);
+ q6lsm_add_mmaphdr(client, &unmap.hdr, cmd_size,
+ true, (client->session << 8));
+ unmap.hdr.opcode = LSM_SESSION_CMD_SHARED_MEM_UNMAP_REGIONS;
+ unmap.mem_map_handle = handle;
+
+ pr_debug("%s: unmap handle 0x%x\n", __func__, unmap.mem_map_handle);
+ rc = q6lsm_apr_send_pkt(client, client->mmap_apr, &unmap, true,
+ NULL);
+ if (rc)
+ pr_err("%s: Failed mmap_regions opcode 0x%x rc %d\n",
+ __func__, unmap.hdr.opcode, rc);
+
+ return rc;
+}
+
static int q6lsm_send_cal(struct lsm_client *client)
{
int rc;
@@ -550,15 +589,20 @@
/* Cache mmap address, only map once or if new addr */
if ((lsm_common.lsm_cal_addr != lsm_cal.cal_paddr) ||
(lsm_cal.cal_size > lsm_common.lsm_cal_size)) {
- if (lsm_common.lsm_cal_addr != 0)
- afe_cmd_memory_unmap(lsm_cal.cal_paddr);
+ if (lsm_common.lsm_cal_addr != 0) {
+ rc = q6lsm_memory_unmap_regions(client,
+ lsm_common.mmap_handle_for_cal);
+ if (rc)
+ pr_warn("%s: Unmapping %x failed, %d\n",
+ __func__, lsm_common.lsm_cal_addr, rc);
+ }
rc = q6lsm_memory_map_regions(client, lsm_cal.cal_paddr,
LSM_CAL_SIZE,
&lsm_common.mmap_handle_for_cal);
if (rc < 0) {
- pr_err("%s: Calibration data memory map failed\n",
- __func__);
+ pr_err("%s: Calibration data memory map failed, %d\n",
+ __func__, rc);
goto bail;
}
lsm_common.lsm_cal_addr = lsm_cal.cal_paddr;
@@ -582,38 +626,18 @@
return rc;
}
-static int q6lsm_memory_unmap_regions(struct lsm_client *client)
-{
- struct avs_cmd_shared_mem_unmap_regions unmap;
- int rc = 0;
- int cmd_size = 0;
-
- cmd_size = sizeof(struct avs_cmd_shared_mem_unmap_regions);
- q6lsm_add_mmaphdr(client, &unmap.hdr, cmd_size,
- true, (client->session << 8));
- unmap.hdr.opcode = LSM_SESSION_CMD_SHARED_MEM_UNMAP_REGIONS;
- unmap.mem_map_handle = client->sound_model.mem_map_handle;
-
- pr_debug("%s: unmap handle 0x%x\n", __func__, unmap.mem_map_handle);
- rc = q6lsm_apr_send_pkt(client, client->mmap_apr, &unmap, true,
- NULL);
- if (rc)
- pr_err("%s: Failed mmap_regions opcode 0x%x rc %d\n",
- __func__, unmap.hdr.opcode, rc);
-
- return rc;
-}
-
-static int q6lsm_snd_model_buf_free(struct lsm_client *client)
+int q6lsm_snd_model_buf_free(struct lsm_client *client)
{
int rc;
pr_debug("%s: Session id %d\n", __func__, client->session);
mutex_lock(&client->cmd_lock);
- rc = q6lsm_memory_unmap_regions(client);
- if (rc < 0) {
+ rc = q6lsm_memory_unmap_regions(client,
+ client->sound_model.mem_map_handle);
+ if (rc < 0)
pr_err("%s CMD Memory_unmap_regions failed\n", __func__);
- } else if (client->sound_model.data) {
+
+ if (client->sound_model.data) {
ion_unmap_kernel(client->sound_model.client,
client->sound_model.handle);
ion_free(client->sound_model.client,
@@ -649,12 +673,22 @@
static int q6lsm_mmapcallback(struct apr_client_data *data, void *priv)
{
unsigned long flags;
- uint32_t sid = 0;
+ uint32_t command;
+ uint32_t retcode;
+ uint32_t sid;
const uint32_t *payload = data->payload;
- const uint32_t command = payload[0];
- const uint32_t retcode = payload[1];
struct lsm_client *client = NULL;
+ if (data->opcode == RESET_EVENTS) {
+ pr_debug("%s: SSR event received 0x%x, event 0x%x, proc 0x%x\n",
+ __func__, data->opcode, data->reset_event,
+ data->reset_proc);
+ lsm_common.lsm_cal_addr = 0;
+ return 0;
+ }
+
+ command = payload[0];
+ retcode = payload[1];
pr_debug("%s: opcode 0x%x command 0x%x return code 0x%x\n", __func__,
data->opcode, command, retcode);
@@ -710,6 +744,7 @@
if (IS_ERR_OR_NULL(client->sound_model.client)) {
pr_err("%s: ION create client for AUDIO failed\n",
__func__);
+ mutex_unlock(&client->cmd_lock);
goto fail;
}
client->sound_model.handle =
@@ -718,6 +753,7 @@
if (IS_ERR_OR_NULL(client->sound_model.handle)) {
pr_err("%s: ION memory allocation for AUDIO failed\n",
__func__);
+ mutex_unlock(&client->cmd_lock);
goto fail;
}
@@ -728,6 +764,7 @@
if (rc) {
pr_err("%s: ION get physical mem failed, rc%d\n",
__func__, rc);
+ mutex_unlock(&client->cmd_lock);
goto fail;
}
@@ -736,6 +773,7 @@
client->sound_model.handle);
if (IS_ERR_OR_NULL(client->sound_model.data)) {
pr_err("%s: ION memory mapping failed\n", __func__);
+ mutex_unlock(&client->cmd_lock);
goto fail;
}
memset(client->sound_model.data, 0, len);
diff --git a/sound/soc/msm/qdsp6v2/q6voice.c b/sound/soc/msm/qdsp6v2/q6voice.c
index 26d9d48..8888e41 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.c
+++ b/sound/soc/msm/qdsp6v2/q6voice.c
@@ -56,7 +56,7 @@
static int voice_send_disable_vocproc_cmd(struct voice_data *v);
static int voice_send_vol_index_cmd(struct voice_data *v);
static int voice_send_mvm_unmap_memory_physical_cmd(struct voice_data *v,
- unsigned int bufcnt);
+ uint32_t mem_handle);
static int voice_send_mvm_cal_network_cmd(struct voice_data *v);
static int voice_send_mvm_media_type_cmd(struct voice_data *v);
static int voice_send_cvs_data_exchange_mode_cmd(struct voice_data *v);
@@ -227,6 +227,29 @@
return (session_id == common.voice[VOC_PATH_VOICE2_PASSIVE].session_id);
}
+static bool is_other_session_active(u16 session_id)
+{
+ int i;
+ bool ret = false;
+
+ /* Check if there is other active session except the input one */
+ for (i = 0; i < MAX_VOC_SESSIONS; i++) {
+ if (common.voice[i].session_id == session_id)
+ continue;
+
+ if ((common.voice[i].voc_state == VOC_RUN) ||
+ (common.voice[i].voc_state == VOC_CHANGE) ||
+ (common.voice[i].voc_state == VOC_STANDBY)) {
+ ret = true;
+ break;
+ }
+ }
+ pr_debug("%s: ret %d\n", __func__, ret);
+
+ return ret;
+
+}
+
static int voice_apr_register(void)
{
void *modem_mvm, *modem_cvs, *modem_cvp;
@@ -676,7 +699,7 @@
cvs_handle = voice_get_cvs_handle(v);
/* MVM, CVS sessions are destroyed only for Full control sessions. */
- if (is_voip_session(v->session_id) || v->voc_state == VOC_ERROR) {
+ if (is_voip_session(v->session_id)) {
pr_debug("%s: MVM detach stream, VOC_STATE: %d\n", __func__,
v->voc_state);
@@ -698,6 +721,7 @@
if (ret < 0) {
pr_err("%s: Error %d sending DETACH_STREAM\n",
__func__, ret);
+
goto fail;
}
ret = wait_event_timeout(v->mvm_wait,
@@ -705,9 +729,25 @@
msecs_to_jiffies(TIMEOUT_MS));
if (!ret) {
pr_err("%s: wait event timeout\n", __func__);
+
goto fail;
}
+ /* Unmap memory */
+ if (v->shmem_info.mem_handle != 0) {
+ ret = voice_send_mvm_unmap_memory_physical_cmd(v,
+ v->shmem_info.mem_handle);
+ if (ret < 0) {
+ pr_err("%s Memory_unmap for voip failed %d\n",
+ __func__, ret);
+
+ goto fail;
+ }
+ v->shmem_info.mem_handle = 0;
+ }
+ }
+
+ if (is_voip_session(v->session_id) || v->voc_state == VOC_ERROR) {
/* Destroy CVS. */
pr_debug("%s: CVS destroy session\n", __func__);
@@ -726,6 +766,7 @@
if (ret < 0) {
pr_err("%s: Error %d sending CVS DESTROY\n",
__func__, ret);
+
goto fail;
}
ret = wait_event_timeout(v->cvs_wait,
@@ -739,11 +780,21 @@
cvs_handle = 0;
voice_set_cvs_handle(v, cvs_handle);
- ret = voice_send_mvm_unmap_memory_physical_cmd(v,
- NUM_OF_BUFFERS);
- if (ret < 0) {
- pr_err("%s CMD Memory_unmap_regions failed %d\n",
- __func__, ret);
+ /* Unmap physical memory for calibration */
+ pr_debug("%s: cal_mem_handle %d\n", __func__,
+ common.cal_mem_handle);
+
+ if (!is_other_session_active(v->session_id) &&
+ (common.cal_mem_handle != 0)) {
+ ret = voice_send_mvm_unmap_memory_physical_cmd(v,
+ common.cal_mem_handle);
+ if (ret < 0) {
+ pr_err("%s Fail at cal mem unmap %d\n",
+ __func__, ret);
+
+ goto fail;
+ }
+ common.cal_mem_handle = 0;
}
/* Destroy MVM. */
@@ -2673,7 +2724,7 @@
}
static int voice_send_mvm_unmap_memory_physical_cmd(struct voice_data *v,
- unsigned int bufcnt)
+ uint32_t mem_handle)
{
struct vss_imemory_cmd_unmap_t mem_unmap;
int ret = 0;
@@ -2701,7 +2752,7 @@
mem_unmap.hdr.dest_port = mvm_handle;
mem_unmap.hdr.token = 0;
mem_unmap.hdr.opcode = VSS_IMEMORY_CMD_UNMAP;
- mem_unmap.mem_handle = v->shmem_info.mem_handle;
+ mem_unmap.mem_handle = mem_handle;
pr_debug("%s: mem_handle: ox%x\n", __func__, mem_unmap.mem_handle);