Merge "arm/dt: 8974-liquid: Add configuration for Rev B touch panels"
diff --git a/Documentation/devicetree/bindings/bluetooth/bluetooth_power.txt b/Documentation/devicetree/bindings/bluetooth/bluetooth_power.txt
new file mode 100644
index 0000000..88d69e0
--- /dev/null
+++ b/Documentation/devicetree/bindings/bluetooth/bluetooth_power.txt
@@ -0,0 +1,16 @@
+* Bluetooth Controller
+Bluetooth controller communicates with the Bluetooth Host using HCI Transport layer.
+HCI Transport layer can be based on UART or USB serial communication protocol.
+
+Required properties:
+ - compatible: Should be "qca,ar3002"
+ - qca,bt-reset-gpio: GPIO pin to bring BT Controller out of reset
+
+Optional properties:
+ None
+
+Example:
+ bt-ar3002 {
+ compatible = "qca,ar3002";
+ qca,bt-reset-gpio = <&pm8941_gpios 34 0>;
+ };
diff --git a/Documentation/devicetree/bindings/coresight/coresight.txt b/Documentation/devicetree/bindings/coresight/coresight.txt
index 9635972..c30515c 100644
--- a/Documentation/devicetree/bindings/coresight/coresight.txt
+++ b/Documentation/devicetree/bindings/coresight/coresight.txt
@@ -12,6 +12,7 @@
- compatible : name of the component used for driver matching
- reg : physical base address and length of the register set(s) of the component
+- reg-names: names corresponding to each reg property value
- coresight-id : unique integer identifier for the component
- coresight-name : unique descriptive name of the component
- coresight-nr-inports : number of input ports on the component
@@ -31,6 +32,7 @@
component
- coresight-child-ports : list of input port numbers of the children
- coresight-default-sink : represents the default compile time CoreSight sink
+- coresight-ctis : list of ctis that this component interacts with
- qcom,pc-save : program counter save implemented
- qcom,blk-size : block size for tmc-etr to usb transfers
- qcom,round-robin : indicates if per core etms are allowed round-robin access
@@ -41,7 +43,9 @@
1. Sinks
tmc_etr: tmc@fc322000 {
compatible = "arm,coresight-tmc";
- reg = <0xfc322000 0x1000>;
+ reg = <0xfc322000 0x1000>,
+ <0xfc37c000 0x3000>;
+ reg-names = "tmc-etr-base", "tmc-etr-bam-base";
coresight-id = <0>;
coresight-name = "coresight-tmc-etr";
@@ -52,6 +56,7 @@
tpiu: tpiu@fc318000 {
compatible = "arm,coresight-tpiu";
reg = <0xfc318000 0x1000>;
+ reg-names = "tpiu-base";
coresight-id = <1>;
coresight-name = "coresight-tpiu";
@@ -62,6 +67,7 @@
funnel_merg: funnel@fc31b000 {
compatible = "arm,coresight-funnel";
reg = <0xfc31b000 0x1000>;
+ reg-names = "funnel-merg-base";
coresight-id = <4>;
coresight-name = "coresight-funnel-merg";
@@ -74,6 +80,7 @@
funnel_in0: funnel@fc319000 {
compatible = "arm,coresight-funnel";
reg = <0xfc319000 0x1000>;
+ reg-names = "funnel-in0-base";
coresight-id = <5>;
coresight-name = "coresight-funnel-in0";
@@ -88,6 +95,7 @@
compatible = "arm,coresight-stm";
reg = <0xfc321000 0x1000>,
<0xfa280000 0x180000>;
+ reg-names = "stm-base", "stm-data-base";
coresight-id = <9>;
coresight-name = "coresight-stm";
@@ -100,6 +108,7 @@
etm0: etm@fc33c000 {
compatible = "arm,coresight-etm";
reg = <0xfc33c000 0x1000>;
+ reg-names = "etm0-base";
coresight-id = <10>;
coresight-name = "coresight-etm0";
@@ -110,3 +119,24 @@
qcom,pc-save;
qcom,round-robin;
};
+
+4. Miscellaneous
+ cti0: cti@fc308000 {
+ compatible = "arm,coresight-cti";
+ reg = <0xfc308000 0x1000>;
+ reg-names = "cti0-base";
+
+ coresight-id = <15>;
+ coresight-name = "coresight-cti0";
+ coresight-nr-inports = <0>;
+ };
+
+ cti1: cti@fc309000 {
+ compatible = "arm,coresight-cti";
+ reg = <0xfc309000 0x1000>;
+ reg-names = "cti1-base";
+
+ coresight-id = <16>;
+ coresight-name = "coresight-cti1";
+ coresight-nr-inports = <0>;
+ };
diff --git a/Documentation/devicetree/bindings/crypto/msm/qcedev.txt b/Documentation/devicetree/bindings/crypto/msm/qcedev.txt
index 2cc2696..bf97e80 100644
--- a/Documentation/devicetree/bindings/crypto/msm/qcedev.txt
+++ b/Documentation/devicetree/bindings/crypto/msm/qcedev.txt
@@ -6,6 +6,12 @@
- reg-names : should contain the crypto and bam base register names.
- interrupts : should contain crypto BAM interrupt.
- qcom,bam-pipe-pair : should contain crypto BAM pipe pair index.
+ - qcom,ce-hw-instance : should contain crypto HW instance.
+ - qcom,msm_bus,name: Should be "qcedev-noc"
+ - qcom,msm_bus,num_cases: Depends on the use cases for bus scaling
+ - qcom,msm_bus,active-only: Default vector index
+ - qcom,msm_bus,num_paths: The paths for source and destination ports
+ - qcom,msm_bus,vectors: Vectors for bus topology.
Example:
@@ -16,4 +22,12 @@
reg-names = "crypto-base","crypto-bam-base";
interrupts = <0 235 0>;
qcom,bam-pipe-pair = <0>;
+ qcom,ce-hw-instance = <1>;
+ qcom,msm-bus,name = "qcedev-noc";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,active-only = <0>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <56 512 0 0>,
+ <56 512 3936000 393600>,
};
diff --git a/Documentation/devicetree/bindings/crypto/msm/qcrypto.txt b/Documentation/devicetree/bindings/crypto/msm/qcrypto.txt
index 4f9dd06..c99262b 100644
--- a/Documentation/devicetree/bindings/crypto/msm/qcrypto.txt
+++ b/Documentation/devicetree/bindings/crypto/msm/qcrypto.txt
@@ -5,7 +5,13 @@
- reg : should contain crypto, BAM register map.
- reg-names : should contain the crypto and bam base register names.
- interrupts : should contain crypto BAM interrupt.
- - qcom,bam-pipe-pair : should contain crypto BAM pipe pair.
+ - qcom,bam-pipe-pair : should contain crypto BAM pipe pair index.
+ - qcom,ce-hw-instance : should contain crypto HW instance.
+ - qcom,msm_bus,name: Should be "qcrypto-noc"
+ - qcom,msm_bus,num_cases: Depends on the use cases for bus scaling
+ - qcom,msm_bus,active-only: Default vector index
+ - qcom,msm_bus,num_paths: The paths for source and destination ports
+ - qcom,msm_bus,vectors: Vectors for bus topology.
Example:
@@ -16,4 +22,12 @@
reg-names = "crypto-base","crypto-bam-base";
interrupts = <0 235 0>;
qcom,bam-pipe-pair = <1>;
+ qcom,ce-hw-instance = <1>;
+ qcom,msm-bus,name = "qcrypto-noc";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,active-only = <0>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <56 512 0 0>,
+ <56 512 3936000 393600>,
};
diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
index 94746b8..0588c5e 100644
--- a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
@@ -56,6 +56,7 @@
- qcom,enable-gpio: Specifies the panel lcd/display enable gpio.
- qcom,rst-gpio: Specifies the panel reset gpio.
- qcom,mdss-pan-broadcast-mode: Boolean used to enable broadcast mode.
+- qcom,cont-splash-enabled: Boolean used to enable continuous splash mode.
- qcom,mdss-pan-porch-values: An array of size 6 that specifies the panel blanking values.
- qcom,mdss-pan-underflow-clr: Specifies the controller settings for the panel underflow clear
settings. Default value is 0xff.
diff --git a/Documentation/devicetree/bindings/fb/msm-hdmi-tx.txt b/Documentation/devicetree/bindings/fb/msm-hdmi-tx.txt
index a30d1d6..a2b66f7 100644
--- a/Documentation/devicetree/bindings/fb/msm-hdmi-tx.txt
+++ b/Documentation/devicetree/bindings/fb/msm-hdmi-tx.txt
@@ -43,7 +43,7 @@
- compatible : "msm-hdmi-audio-codec-rx";
Example:
- qcom,hdmi_tx@fd922100 {
+ mdss_hdmi_tx: qcom,hdmi_tx@fd922100 {
cell-index = <0>;
compatible = "qcom,hdmi-tx";
reg = <0xfd922100 0x35C>,
diff --git a/Documentation/devicetree/bindings/i2c/sii8334-i2c.txt b/Documentation/devicetree/bindings/i2c/sii8334-i2c.txt
index ed45192..27a2149 100644
--- a/Documentation/devicetree/bindings/i2c/sii8334-i2c.txt
+++ b/Documentation/devicetree/bindings/i2c/sii8334-i2c.txt
@@ -7,6 +7,7 @@
- mhl-pwr-gpio: MHL power gpio required for power rails
- mhl-rst-gpio: MHL reset gpio going into sii8334 for toggling reset pin
- <supply-name>-supply: phandle to the regulator device tree node.
+- qcom,hdmi-tx-map: phandle to the hdmi tx device tree node.
Example:
i2c@f9967000 {
@@ -22,5 +23,6 @@
avcc_12-supply = <&pm8941_l2>;
smps3a-supply = <&pm8941_s3>;
vdda-supply = <&pm8941_l12>;
+ qcom,hdmi-tx-map = <&mdss_hdmi_tx>;
};
};
diff --git a/Documentation/devicetree/bindings/iommu/msm_iommu_v0.txt b/Documentation/devicetree/bindings/iommu/msm_iommu_v0.txt
index ea2d43a..cc1ffc2 100644
--- a/Documentation/devicetree/bindings/iommu/msm_iommu_v0.txt
+++ b/Documentation/devicetree/bindings/iommu/msm_iommu_v0.txt
@@ -7,6 +7,10 @@
- qcom,glb-offset : Offset for the global register base.
Optional properties:
+- interrupts : should contain the performance monitor overflow interrupt number.
+- qcom,iommu-pmu-ngroups: Number of Performance Monitor Unit (PMU) groups.
+- qcom,iommu-pmu-ncounters: Number of PMU counters per group.
+- qcom,iommu-pmu-event-classes: List of event classes supported.
- List of sub nodes, one for each of the translation context banks supported.
Each sub node has the following required properties:
@@ -28,6 +32,11 @@
ranges;
reg = <0xfd890000 0x10000>;
qcom,glb-offset = <0xF000>;
+ interrupts = <0 38 0>;
+ qcom,iommu-pmu-ngroups = <1>;
+ qcom,iommu-pmu-ncounters = <4>;
+ qcom,iommu-pmu-event-classes = <0x08
+ 0x11>;
qcom,iommu-ctx@fd000000 {
reg = <0xfd000000 0x1000>;
diff --git a/Documentation/devicetree/bindings/media/video/msm-cci.txt b/Documentation/devicetree/bindings/media/video/msm-cci.txt
index 6309068..a432fb5 100644
--- a/Documentation/devicetree/bindings/media/video/msm-cci.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-cci.txt
@@ -82,9 +82,6 @@
- qcom,is-vpe : should be enabled if VPE module is required for post processing
of this sensor
- 1 if required, 0 otherwise
-- qcom,led-flash-sd-index : should contain phandle to flash source node if flash
- is supported for this sensor
- - led_flash0, led_flash1
- qcom,mount-angle : should contain the physical mount angle of the sensor on
the target
- 0, 90, 180, 360
@@ -131,7 +128,8 @@
- 1 -> MASTER 1
- qcom,actuator-src : if auto focus is supported by this sensor, this
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
* Qualcomm MSM ACTUATOR
Required properties:
@@ -187,10 +185,10 @@
compatible = "qcom,s5k3l1yx";
reg = <0x6e 0x0>;
qcom,slave-id = <0x6e 0x0 0x3121>;
- qcom,led-flash-sd-index = <0>;
qcom,csiphy-sd-index = <2>;
qcom,csid-sd-index = <0>;
qcom,actuator-src = <&actuator0>;
+ qcom,led-flash-src = <&led_flash0>;
qcom,mount-angle = <90>;
qcom,sensor-name = "s5k3l1yx";
cam_vdig-supply = <&pm8941_l3>;
diff --git a/Documentation/devicetree/bindings/media/video/msm-cpp.txt b/Documentation/devicetree/bindings/media/video/msm-cpp.txt
index 5cf0154..9d176d8 100644
--- a/Documentation/devicetree/bindings/media/video/msm-cpp.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-cpp.txt
@@ -7,6 +7,8 @@
- reg : offset and length of the register set for the device
for the cpp operating in compatible mode.
- reg-names : should specify relevant names to each reg property defined.
+ - cpp - has CPP hardware register set.
+ - cpp_vbif - has VBIF core register set used by CPP.
- interrupts : should contain the cpp interrupt.
- interrupt-names : should specify relevant names to each interrupts
property defined.
@@ -18,7 +20,8 @@
cell-index = <0>;
compatible = "qcom,cpp";
reg = <0xfda04000 0x100>;
- reg-names = "cpp";
+ <0xfda40000 0x200>;
+ reg-names = "cpp", "cpp_vbif";
interrupts = <0 49 0>;
interrupt-names = "cpp";
vdd-supply = <&gdsc_vfe>;
diff --git a/Documentation/devicetree/bindings/platform/msm/ssm.txt b/Documentation/devicetree/bindings/platform/msm/ssm.txt
new file mode 100644
index 0000000..8fb3356
--- /dev/null
+++ b/Documentation/devicetree/bindings/platform/msm/ssm.txt
@@ -0,0 +1,30 @@
+* Qualcomm Secure Service Module (SSM)
+
+SSM provides an interface for OEM driver to communicate with Modem and
+trustzone.
+
+This module provides following features:
+ - Keyexchange between Modem and trustzone for encryption/Decryption
+ of mode information
+ - Interface to third party driver to send mode updates to modem
+ - Interface for loading the trustzone application
+
+Required properties:
+- compatible: Must be "qcom,ssm"
+
+Optional properties:
+- qcom,channel-name: Name of the SMD channel used for communication
+ between MODEM and SSM driver.
+- qcom,need-keyexhg This property controls initial key exchange
+ between APPS(application processor) and MODEM.
+ If not mentioned the initial key exchange is
+ not required.
+ If this property is mentioned then it is mandatory
+ for modem to perform initial key exchange with APPS.
+
+Example:
+ qcom,ssm {
+ compatible = "qcom,ssm";
+ qcom,channel-name = "SSM_RTR";
+ qcom,need-keyexhg;
+ }
diff --git a/arch/arm/boot/dts/msm-iommu-v0.dtsi b/arch/arm/boot/dts/msm-iommu-v0.dtsi
index 59b2a90..6ddeb68 100644
--- a/arch/arm/boot/dts/msm-iommu-v0.dtsi
+++ b/arch/arm/boot/dts/msm-iommu-v0.dtsi
@@ -17,8 +17,16 @@
#size-cells = <1>;
ranges;
reg = <0xfd000000 0x10000>;
+ interrupts = <0 248 0>;
qcom,glb-offset = <0xF000>;
label = "lpass_iommu";
+ qcom,iommu-pmu-ngroups = <1>;
+ qcom,iommu-pmu-ncounters = <4>;
+ qcom,iommu-pmu-event-classes = <0x08
+ 0x09
+ 0x10
+ 0x12
+ 0x80>;
status = "disabled";
lpass_q6_fw: qcom,iommu-ctx@fd000000 {
@@ -56,8 +64,16 @@
#size-cells = <1>;
ranges;
reg = <0xfd010000 0x10000>;
+ interrupts = <0 252 0>;
qcom,glb-offset = <0xF000>;
label = "copss_iommu";
+ qcom,iommu-pmu-ngroups = <1>;
+ qcom,iommu-pmu-ncounters = <4>;
+ qcom,iommu-pmu-event-classes = <0x08
+ 0x09
+ 0x10
+ 0x12
+ 0x80>;
status = "disabled";
qcom,iommu-ctx@fd010000 {
@@ -123,8 +139,16 @@
#size-cells = <1>;
ranges;
reg = <0xfd860000 0x10000>;
+ interrupts = <0 245 0>;
qcom,glb-offset = <0xF000>;
label = "mdpe_iommu";
+ qcom,iommu-pmu-ngroups = <1>;
+ qcom,iommu-pmu-ncounters = <4>;
+ qcom,iommu-pmu-event-classes = <0x08
+ 0x09
+ 0x10
+ 0x12
+ 0x80>;
status = "disabled";
qcom,iommu-ctx@fd860000 {
@@ -148,8 +172,16 @@
#size-cells = <1>;
ranges;
reg = <0xfd870000 0x10000>;
+ interrupts = <0 73 0>;
qcom,glb-offset = <0xF000>;
label = "mdps_iommu";
+ qcom,iommu-pmu-ngroups = <1>;
+ qcom,iommu-pmu-ncounters = <4>;
+ qcom,iommu-pmu-event-classes = <0x08
+ 0x09
+ 0x10
+ 0x12
+ 0x80>;
status = "disabled";
qcom,iommu-ctx@fd870000 {
@@ -173,8 +205,16 @@
#size-cells = <1>;
ranges;
reg = <0xfd880000 0x10000>;
+ interrupts = <0 38 0>;
qcom,glb-offset = <0xF000>;
label = "gfx_iommu";
+ qcom,iommu-pmu-ngroups = <1>;
+ qcom,iommu-pmu-ncounters = <4>;
+ qcom,iommu-pmu-event-classes = <0x08
+ 0x09
+ 0x10
+ 0x12
+ 0x80>;
status = "disabled";
qcom,iommu-ctx@fd880000 {
@@ -207,8 +247,16 @@
#size-cells = <1>;
ranges;
reg = <0xfd890000 0x10000>;
+ interrupts = <0 62 0>;
qcom,glb-offset = <0xF000>;
label = "vfe_iommu";
+ qcom,iommu-pmu-ngroups = <1>;
+ qcom,iommu-pmu-ncounters = <4>;
+ qcom,iommu-pmu-event-classes = <0x08
+ 0x09
+ 0x10
+ 0x12
+ 0x80>;
status = "disabled";
qcom,iommu-ctx@fd890000 {
diff --git a/arch/arm/boot/dts/msm-pm8226.dtsi b/arch/arm/boot/dts/msm-pm8226.dtsi
index ce4513b..de23f4c 100644
--- a/arch/arm/boot/dts/msm-pm8226.dtsi
+++ b/arch/arm/boot/dts/msm-pm8226.dtsi
@@ -121,6 +121,73 @@
qcom,pin-num = <8>;
};
};
+
+ pm8226_vadc: vadc@3100 {
+ compatible = "qcom,qpnp-vadc";
+ reg = <0x3100 0x100>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <0x0 0x31 0x0>;
+ interrupt-names = "eoc-int-en-set";
+ qcom,adc-bit-resolution = <15>;
+ qcom,adc-vdd-reference = <1800>;
+
+ chan@8 {
+ label = "die_temp";
+ reg = <8>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <3>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@9 {
+ label = "ref_625mv";
+ reg = <9>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@a {
+ label = "ref_1250v";
+ reg = <0xa>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+ };
+
+ iadc@3600 {
+ compatible = "qcom,qpnp-iadc";
+ reg = <0x3600 0x100>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <0x0 0x36 0x0>;
+ interrupt-names = "eoc-int-en-set";
+ qcom,adc-bit-resolution = <16>;
+ qcom,adc-vdd-reference = <1800>;
+ qcom,rsense = <1500>;
+
+ chan@0 {
+ label = "internal_rsense";
+ reg = <0>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <1>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+ };
};
qcom,pm8226@1 {
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index c1d8664..54f603d 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -632,7 +632,7 @@
qcom,pre-div-channel-scaling = <0>;
qcom,calibration-type = "ratiometric";
qcom,scale-function = <1>;
- qcom,hw-settle-time = <0>;
+ qcom,hw-settle-time = <2>;
qcom,fast-avg-setup = <0>;
};
@@ -643,7 +643,7 @@
qcom,pre-div-channel-scaling = <0>;
qcom,calibration-type = "ratiometric";
qcom,scale-function = <0>;
- qcom,hw-settle-time = <0>;
+ qcom,hw-settle-time = <2>;
qcom,fast-avg-setup = <0>;
};
@@ -654,7 +654,7 @@
qcom,pre-div-channel-scaling = <0>;
qcom,calibration-type = "ratiometric";
qcom,scale-function = <4>;
- qcom,hw-settle-time = <0>;
+ qcom,hw-settle-time = <2>;
qcom,fast-avg-setup = <0>;
};
@@ -665,7 +665,7 @@
qcom,pre-div-channel-scaling = <0>;
qcom,calibration-type = "ratiometric";
qcom,scale-function = <2>;
- qcom,hw-settle-time = <0>;
+ qcom,hw-settle-time = <2>;
qcom,fast-avg-setup = <0>;
};
@@ -676,7 +676,7 @@
qcom,pre-div-channel-scaling = <0>;
qcom,calibration-type = "ratiometric";
qcom,scale-function = <2>;
- qcom,hw-settle-time = <0>;
+ qcom,hw-settle-time = <2>;
qcom,fast-avg-setup = <0>;
};
@@ -687,7 +687,7 @@
qcom,pre-div-channel-scaling = <0>;
qcom,calibration-type = "ratiometric";
qcom,scale-function = <2>;
- qcom,hw-settle-time = <0>;
+ qcom,hw-settle-time = <2>;
qcom,fast-avg-setup = <0>;
};
@@ -698,7 +698,7 @@
qcom,pre-div-channel-scaling = <0>;
qcom,calibration-type = "ratiometric";
qcom,scale-function = <2>;
- qcom,hw-settle-time = <0>;
+ qcom,hw-settle-time = <2>;
qcom,fast-avg-setup = <0>;
};
@@ -709,7 +709,7 @@
qcom,pre-div-channel-scaling = <0>;
qcom,calibration-type = "ratiometric";
qcom,scale-function = <2>;
- qcom,hw-settle-time = <0>;
+ qcom,hw-settle-time = <2>;
qcom,fast-avg-setup = <0>;
};
@@ -720,7 +720,7 @@
qcom,pre-div-channel-scaling = <0>;
qcom,calibration-type = "ratiometric";
qcom,scale-function = <0>;
- qcom,hw-settle-time = <0>;
+ qcom,hw-settle-time = <2>;
qcom,fast-avg-setup = <0>;
};
};
@@ -770,7 +770,7 @@
qcom,pre-div-channel-scaling = <0>;
qcom,calibration-type = "ratiometric";
qcom,scale-function = <2>;
- qcom,hw-settle-time = <0>;
+ qcom,hw-settle-time = <2>;
qcom,fast-avg-setup = <0>;
qcom,btm-channel-number = <0x48>;
};
@@ -782,7 +782,7 @@
qcom,pre-div-channel-scaling = <0>;
qcom,calibration-type = "ratiometric";
qcom,scale-function = <1>;
- qcom,hw-settle-time = <0xf>;
+ qcom,hw-settle-time = <2>;
qcom,fast-avg-setup = <0>;
qcom,btm-channel-number = <0x68>;
};
@@ -794,7 +794,7 @@
qcom,pre-div-channel-scaling = <0>;
qcom,calibration-type = "absolute";
qcom,scale-function = <2>;
- qcom,hw-settle-time = <0>;
+ qcom,hw-settle-time = <2>;
qcom,fast-avg-setup = <0>;
qcom,btm-channel-number = <0x70>;
};
@@ -806,7 +806,7 @@
qcom,pre-div-channel-scaling = <0>;
qcom,calibration-type = "ratiometric";
qcom,scale-function = <2>;
- qcom,hw-settle-time = <0>;
+ qcom,hw-settle-time = <2>;
qcom,fast-avg-setup = <0>;
qcom,btm-channel-number = <0x78>;
};
@@ -818,7 +818,7 @@
qcom,pre-div-channel-scaling = <0>;
qcom,calibration-type = "ratiometric";
qcom,scale-function = <2>;
- qcom,hw-settle-time = <0>;
+ qcom,hw-settle-time = <2>;
qcom,fast-avg-setup = <0>;
qcom,btm-channel-number = <0x80>;
};
diff --git a/arch/arm/boot/dts/msm8226-cdp.dts b/arch/arm/boot/dts/msm8226-cdp.dts
new file mode 100644
index 0000000..7263e42
--- /dev/null
+++ b/arch/arm/boot/dts/msm8226-cdp.dts
@@ -0,0 +1,24 @@
+/* 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.
+ */
+
+/dts-v1/;
+/include/ "msm8226.dtsi"
+
+/ {
+ model = "Qualcomm MSM 8226 CDP";
+ compatible = "qcom,msm8226-cdp", "qcom,msm8226";
+ qcom,msm-id = <145 1 0>;
+
+ serial@f991f000 {
+ status = "disabled";
+ };
+};
diff --git a/arch/arm/boot/dts/msm8226-fluid.dts b/arch/arm/boot/dts/msm8226-fluid.dts
new file mode 100644
index 0000000..af86922
--- /dev/null
+++ b/arch/arm/boot/dts/msm8226-fluid.dts
@@ -0,0 +1,24 @@
+/* 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.
+ */
+
+/dts-v1/;
+/include/ "msm8226.dtsi"
+
+/ {
+ model = "Qualcomm MSM 8226 FLUID";
+ compatible = "qcom,msm8226-fluid", "qcom,msm8226";
+ qcom,msm-id = <145 3 0>;
+
+ serial@f991f000 {
+ status = "disabled";
+ };
+};
\ No newline at end of file
diff --git a/arch/arm/boot/dts/msm8226-gpu.dtsi b/arch/arm/boot/dts/msm8226-gpu.dtsi
index 76e934e..aa174bf 100644
--- a/arch/arm/boot/dts/msm8226-gpu.dtsi
+++ b/arch/arm/boot/dts/msm8226-gpu.dtsi
@@ -15,6 +15,8 @@
&msm_gpu {
qcom,chipid = <0x03000510>;
+ qcom,clk-map = <0x00000016>; /* KGSL_CLK_CORE | KGSL_CLK_IFACE | KGSL_CLK_MEM_IFACE */
+
qcom,msm-bus,vectors-KBps =
<26 512 0 0>, <89 604 0 0>,
<26 512 0 1600000>, <89 604 0 6400000>,
diff --git a/arch/arm/boot/dts/msm8226-iommu.dtsi b/arch/arm/boot/dts/msm8226-iommu.dtsi
index d23d324..9387bbd 100644
--- a/arch/arm/boot/dts/msm8226-iommu.dtsi
+++ b/arch/arm/boot/dts/msm8226-iommu.dtsi
@@ -28,6 +28,14 @@
qcom,iommu-secure-id = <0xFFFFFFFF>;
};
+&venus_ns {
+ qcom,iommu-ctx-sids = <0 1 2 3 4 5 7>;
+};
+
+&venus_cp {
+ qcom,iommu-ctx-sids = <0x80 0x81 0x82 0x83 0x84>;
+};
+
&kgsl_iommu {
status = "ok";
};
diff --git a/arch/arm/boot/dts/msm8226-mtp.dts b/arch/arm/boot/dts/msm8226-mtp.dts
new file mode 100644
index 0000000..dddb44b
--- /dev/null
+++ b/arch/arm/boot/dts/msm8226-mtp.dts
@@ -0,0 +1,24 @@
+/* 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.
+ */
+
+/dts-v1/;
+/include/ "msm8226.dtsi"
+
+/ {
+ model = "Qualcomm MSM 8226 MTP";
+ compatible = "qcom,msm8226-mtp", "qcom,msm8226";
+ qcom,msm-id = <145 7 0>;
+
+ serial@f991f000 {
+ status = "disabled";
+ };
+};
\ No newline at end of file
diff --git a/arch/arm/boot/dts/msm8226-pm.dtsi b/arch/arm/boot/dts/msm8226-pm.dtsi
index e107b36..4937efe 100644
--- a/arch/arm/boot/dts/msm8226-pm.dtsi
+++ b/arch/arm/boot/dts/msm8226-pm.dtsi
@@ -21,13 +21,13 @@
qcom,core-id = <0>;
qcom,saw2-ver-reg = <0xfd0>;
qcom,saw2-cfg = <0x01>;
- qcom,saw2-spm-dly= <0x20000400>;
+ qcom,saw2-spm-dly= <0x3c102800>;
qcom,saw2-spm-ctl = <0x1>;
- qcom,saw2-spm-cmd-wfi = [60 03 60 76 76 0b 0f];
- qcom,saw2-spm-cmd-spc = [00 20 10 80 90 5b 60 03 60 3b 76 76 94
- 5b 80 10 2b 30 06 26 30 0f];
- qcom,saw2-spm-cmd-pc = [00 20 10 80 90 5b 60 07 3b 76 76 0b 94
- 5b 80 10 2b 30 06 26 30 0f];
+ qcom,saw2-spm-cmd-wfi = [60 03 60 0b 0f];
+ qcom,saw2-spm-cmd-spc = [00 20 10 80 30 90 5b 60 03 60 3b 76 76
+ 0b 94 5b 80 10 2b 06 26 30 0f];
+ qcom,saw2-spm-cmd-pc = [00 20 10 80 30 90 5b 60 07 60 3b 76 76
+ 0b 94 5b 80 10 2b 06 26 30 0f];
};
qcom,spm@f9099000 {
@@ -38,13 +38,13 @@
qcom,core-id = <1>;
qcom,saw2-ver-reg = <0xfd0>;
qcom,saw2-cfg = <0x01>;
- qcom,saw2-spm-dly= <0x20000400>;
+ qcom,saw2-spm-dly= <0x3c102800>;
qcom,saw2-spm-ctl = <0x1>;
- qcom,saw2-spm-cmd-wfi = [60 03 60 76 76 0b 0f];
- qcom,saw2-spm-cmd-spc = [00 20 10 80 90 5b 60 03 60 3b 76 76 94
- 5b 80 10 2b 30 06 26 30 0f];
- qcom,saw2-spm-cmd-pc = [00 20 10 80 90 5b 60 07 3b 76 76 0b 94
- 5b 80 10 2b 30 06 26 30 0f];
+ qcom,saw2-spm-cmd-wfi = [60 03 60 0b 0f];
+ qcom,saw2-spm-cmd-spc = [00 20 10 80 30 90 5b 60 03 60 3b 76 76
+ 0b 94 5b 80 10 2b 06 26 30 0f];
+ qcom,saw2-spm-cmd-pc = [00 20 10 80 30 90 5b 60 07 60 3b 76 76
+ 0b 94 5b 80 10 2b 06 26 30 0f];
};
qcom,spm@f90a9000 {
@@ -55,13 +55,13 @@
qcom,core-id = <2>;
qcom,saw2-ver-reg = <0xfd0>;
qcom,saw2-cfg = <0x01>;
- qcom,saw2-spm-dly= <0x20000400>;
+ qcom,saw2-spm-dly= <0x3c102800>;
qcom,saw2-spm-ctl = <0x1>;
qcom,saw2-spm-cmd-wfi = [60 03 60 76 76 0b 0f];
- qcom,saw2-spm-cmd-spc = [00 20 10 80 90 5b 60 03 60 3b 76 76 94
- 5b 80 10 2b 30 06 26 30 0f];
- qcom,saw2-spm-cmd-pc = [00 20 10 80 90 5b 60 07 3b 76 76 0b 94
- 5b 80 10 2b 30 06 26 30 0f];
+ qcom,saw2-spm-cmd-spc = [00 20 10 80 30 90 5b 60 03 60 3b 76 76
+ 0b 94 5b 80 10 2b 06 26 30 0f];
+ qcom,saw2-spm-cmd-pc = [00 20 10 80 30 90 5b 60 07 60 3b 76 76
+ 0b 94 5b 80 10 2b 06 26 30 0f];
};
qcom,spm@f90b9000 {
@@ -72,13 +72,13 @@
qcom,core-id = <3>;
qcom,saw2-ver-reg = <0xfd0>;
qcom,saw2-cfg = <0x01>;
- qcom,saw2-spm-dly= <0x20000400>;
+ qcom,saw2-spm-dly= <0x3c102800>;
qcom,saw2-spm-ctl = <0x1>;
qcom,saw2-spm-cmd-wfi = [60 03 60 76 76 0b 0f];
- qcom,saw2-spm-cmd-spc = [00 20 10 80 90 5b 60 03 60 3b 76 76 94
- 5b 80 10 2b 30 06 26 30 0f];
- qcom,saw2-spm-cmd-pc = [00 20 10 80 90 5b 60 07 3b 76 76 0b 94
- 5b 80 10 2b 30 06 26 30 0f];
+ qcom,saw2-spm-cmd-spc = [00 20 10 80 30 90 5b 60 03 60 3b 76 76
+ 0b 94 5b 80 10 2b 06 26 30 0f];
+ qcom,saw2-spm-cmd-pc = [00 20 10 80 30 90 5b 60 07 60 3b 76 76
+ 0b 94 5b 80 10 2b 06 26 30 0f];
};
qcom,spm@f9012000 {
@@ -89,19 +89,19 @@
qcom,core-id = <0xffff>; /* L2/APCS SAW */
qcom,saw2-ver-reg = <0xfd0>;
qcom,saw2-cfg = <0x14>;
- qcom,saw2-spm-dly= <0x20000400>;
+ qcom,saw2-spm-dly= <0x3c102800>;
qcom,saw2-spm-ctl = <0x1>;
- qcom,saw2-pmic-data0 = <0x02030080>;
- qcom,saw2-pmic-data1 = <0x00030000>;
+ qcom,saw2-pmic-data0 = <0x0400009c>;
+ qcom,saw2-pmic-data1 = <0x0000001c>;
qcom,vctl-timeout-us = <50>;
qcom,vctl-port = <0x0>;
qcom,phase-port = <0x1>;
qcom,pfm-port = <0x2>;
- qcom,saw2-spm-cmd-ret = [0b 00 03 00 7b 0f];
- qcom,saw2-spm-cmd-gdhs = [00 20 32 60 70 80 0b 6b c0 e0 d0 42 07
+ qcom,saw2-spm-cmd-ret = [00 03 00 7b 0f];
+ qcom,saw2-spm-cmd-gdhs = [00 20 32 60 70 80 6b c0 e0 d0 42 07
78 1f 80 4e d0 e0 c0 22 6b 50 4b 60 02 32 50 7b
0f];
- qcom,saw2-spm-cmd-pc = [00 32 60 70 80 b0 0b 10 e0 d0 6b c0
+ qcom,saw2-spm-cmd-pc = [00 32 60 70 80 b0 10 e0 d0 6b c0
42 f0 11 07 01 b0 78 1f 80 4e c0 d0 12 e0 6b 50 4b
60 02 32 50 f0 7b 0f]; /*APCS_PMIC_OFF_L2RAM_OFF*/
};
@@ -382,13 +382,9 @@
<40 95>;
};
- qcom,pc-cntr@fe805664 {
- compatible = "qcom,pc-cntr";
- reg = <0xfe805664 0x40>;
- };
-
- qcom,pm-8x60 {
+ qcom,pm-8x60@fe805664 {
compatible = "qcom,pm-8x60";
+ reg = <0xfe805664 0x40>;
qcom,pc-mode = <0>; /*MSM_PC_TZ_L2_INT */
qcom,use-sync-timer;
};
diff --git a/arch/arm/boot/dts/msm8226-qrd.dts b/arch/arm/boot/dts/msm8226-qrd.dts
new file mode 100644
index 0000000..14bf60b
--- /dev/null
+++ b/arch/arm/boot/dts/msm8226-qrd.dts
@@ -0,0 +1,24 @@
+/* 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.
+ */
+
+/dts-v1/;
+/include/ "msm8226.dtsi"
+
+/ {
+ model = "Qualcomm MSM 8226 QRD";
+ compatible = "qcom,msm8226-qrd", "qcom,msm8226";
+ qcom,msm-id = <145 1 0>;
+
+ serial@f991f000 {
+ status = "disabled";
+ };
+};
\ No newline at end of file
diff --git a/arch/arm/boot/dts/msm8226-regulator.dtsi b/arch/arm/boot/dts/msm8226-regulator.dtsi
index 50d2dba..3c0dd1e 100644
--- a/arch/arm/boot/dts/msm8226-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8226-regulator.dtsi
@@ -13,7 +13,7 @@
/* Stub Regulators */
/ {
- pm8026_s1_corner: regulator-s1-corner {
+ pm8226_s1_corner: regulator-s1-corner {
compatible = "qcom,stub-regulator";
regulator-name = "8226_s1_corner";
qcom,hpm-min-load = <100000>;
@@ -35,8 +35,8 @@
qcom,enable-time = <500>;
qcom,system-load = <100000>;
regulator-always-on;
- regulator-min-microvolt = <1287500>;
- regulator-max-microvolt = <1287500>;
+ regulator-min-microvolt = <1150000>;
+ regulator-max-microvolt = <1150000>;
};
pm8226_s2: regulator@1700 {
@@ -104,8 +104,8 @@
qcom,system-load = <10000>;
regulator-always-on;
qcom,enable-time = <200>;
- regulator-min-microvolt = <1287500>;
- regulator-max-microvolt = <1287500>;
+ regulator-min-microvolt = <1150000>;
+ regulator-max-microvolt = <1150000>;
};
pm8226_l4: regulator@4300 {
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index 3ae69fd..3533d19 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -44,6 +44,10 @@
qcom,direct-connect-irqs = <8>;
};
+ aliases {
+ spi0 = &spi_0;
+ };
+
timer {
compatible = "arm,armv7-timer";
interrupts = <1 2 0 1 3 0>;
@@ -520,6 +524,7 @@
reg = <0xfe200000 0x00100>,
<0xfd485100 0x00010>;
reg-names = "qdsp6_base", "halt_base";
+ vdd_cx-supply = <&pm8226_s1_corner>;
interrupts = <0 162 1>;
qcom,firmware-name = "adsp";
@@ -527,7 +532,7 @@
qcom,msm-mem-hole {
compatible = "qcom,msm-mem-hole";
- qcom,memblock-remove = <0x8100000 0x7e00000>; /* Address and Size of Hole */
+ qcom,memblock-remove = <0x8400000 0x7b00000>; /* Address and Size of Hole */
};
tsens: tsens@fc4a8000 {
@@ -536,10 +541,43 @@
<0xfc4b8000 0x1000>;
reg-names = "tsens_physical", "tsens_eeprom_physical";
interrupts = <0 184 0>;
- qcom,sensors = <7>;
- qcom,slope = <3200 3200 3200 3200 3200 3200 3200>;
+ qcom,sensors = <6>;
+ qcom,slope = <3200 3200 3200 3200 3200 3200>;
qcom,calib-mode = "fuse_map2";
};
+
+ qcom,msm-thermal {
+ compatible = "qcom,msm-thermal";
+ qcom,sensor-id = <0>;
+ qcom,poll-ms = <250>;
+ qcom,limit-temp = <60>;
+ qcom,temp-hysteresis = <10>;
+ qcom,freq-step = <2>;
+ };
+
+ spi_0: spi@f9923000 { /* BLSP1 QUP1 */
+ compatible = "qcom,spi-qup-v2";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg-names = "spi_physical", "spi_bam_physical";
+ reg = <0xf9923000 0x1000>,
+ <0xf9904000 0xF000>;
+ interrupt-names = "spi_irq", "spi_bam_irq";
+ interrupts = <0 95 0>, <0 238 0>;
+ spi-max-frequency = <19200000>;
+
+ gpios = <&msmgpio 3 0>, /* CLK */
+ <&msmgpio 1 0>, /* MISO */
+ <&msmgpio 0 0>; /* MOSI */
+ cs-gpios = <&msmgpio 2 0>;
+
+ qcom,infinite-mode = <0>;
+ qcom,use-bam;
+ qcom,ver-reg-exists;
+ qcom,bam-consumer-pipe-index = <12>;
+ qcom,bam-producer-pipe-index = <13>;
+ };
+
};
&gdsc_venus {
@@ -568,3 +606,93 @@
/include/ "msm-pm8226.dtsi"
/include/ "msm8226-regulator.dtsi"
+
+&pm8226_vadc {
+ chan@0 {
+ label = "usb_in";
+ reg = <0>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <4>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@2 {
+ label = "vchg_sns";
+ reg = <2>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <3>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@5 {
+ label = "vcoin";
+ reg = <5>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <1>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@6 {
+ label = "vbat_sns";
+ reg = <6>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <1>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@7 {
+ label = "vph_pwr";
+ reg = <7>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <1>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@30 {
+ label = "batt_therm";
+ reg = <0x30>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <1>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@31 {
+ label = "batt_id";
+ reg = <0x31>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@b2 {
+ label = "xo_therm_pu2";
+ reg = <0xb2>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <4>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ };
+};
diff --git a/arch/arm/boot/dts/msm8610-pm.dtsi b/arch/arm/boot/dts/msm8610-pm.dtsi
index e107b36..feb3087 100644
--- a/arch/arm/boot/dts/msm8610-pm.dtsi
+++ b/arch/arm/boot/dts/msm8610-pm.dtsi
@@ -382,13 +382,9 @@
<40 95>;
};
- qcom,pc-cntr@fe805664 {
- compatible = "qcom,pc-cntr";
- reg = <0xfe805664 0x40>;
- };
-
- qcom,pm-8x60 {
+ qcom,pm-8x60@fe805664 {
compatible = "qcom,pm-8x60";
+ reg = <0xfe805664 0x40>;
qcom,pc-mode = <0>; /*MSM_PC_TZ_L2_INT */
qcom,use-sync-timer;
};
diff --git a/arch/arm/boot/dts/msm8610.dtsi b/arch/arm/boot/dts/msm8610.dtsi
index 9ff383f..ce6011b 100644
--- a/arch/arm/boot/dts/msm8610.dtsi
+++ b/arch/arm/boot/dts/msm8610.dtsi
@@ -41,6 +41,10 @@
qcom,direct-connect-irqs = <8>;
};
+ aliases {
+ spi0 = &spi_0;
+ };
+
timer {
compatible = "arm,armv7-timer";
interrupts = <1 2 0 1 3 0>;
@@ -283,6 +287,30 @@
qcom,i2c-bus-freq = <100000>;
};
+
+ spi_0: spi@f9923000 { /* BLSP1 QUP1 */
+ compatible = "qcom,spi-qup-v2";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg-names = "spi_physical", "spi_bam_physical";
+ reg = <0xf9923000 0x1000>,
+ <0xf9904000 0xF000>;
+ interrupt-names = "spi_irq", "spi_bam_irq";
+ interrupts = <0 95 0>, <0 238 0>;
+ spi-max-frequency = <19200000>;
+
+ gpios = <&msmgpio 3 0>, /* CLK */
+ <&msmgpio 1 0>, /* MISO */
+ <&msmgpio 0 0>; /* MOSI */
+ cs-gpios = <&msmgpio 2 0>;
+
+ qcom,infinite-mode = <0>;
+ qcom,use-bam;
+ qcom,ver-reg-exists;
+ qcom,bam-consumer-pipe-index = <12>;
+ qcom,bam-producer-pipe-index = <13>;
+ };
+
qcom,pronto@fb21b000 {
compatible = "qcom,pil-pronto";
reg = <0xfb21b000 0x3000>,
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-cdp-mtp.dtsi
similarity index 68%
rename from arch/arm/boot/dts/msm8974-camera-sensor.dtsi
rename to arch/arm/boot/dts/msm8974-camera-sensor-cdp-mtp.dtsi
index 85b90c2..fb2917c 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-cdp-mtp.dtsi
@@ -13,13 +13,19 @@
&cci {
+ actuator0: qcom,actuator@18 {
+ cell-index = <0>;
+ reg = <0x18 0x0>;
+ 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,flash-src-index = <&led_flash0>;
qcom,actuator-src = <&actuator0>;
qcom,mount-angle = <90>;
qcom,sensor-name = "s5k3l1yx";
@@ -35,12 +41,15 @@
qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
qcom,gpio-no-mux = <0>;
gpios = <&msmgpio 15 0>,
- <&msmgpio 90 0>;
+ <&msmgpio 90 0>,
+ <&msmgpio 89 0>;
qcom,gpio-reset = <1>;
- qcom,gpio-req-tbl-num = <0 1>;
- qcom,gpio-req-tbl-flags = <1 0>;
+ qcom,gpio-standby = <2>;
+ qcom,gpio-req-tbl-num = <0 1 2>;
+ qcom,gpio-req-tbl-flags = <1 0 0>;
qcom,gpio-req-tbl-label = "CAMIF_MCLK",
- "CAM_RESET1";
+ "CAM_RESET1",
+ "CAM_STANDBY";
qcom,gpio-set-tbl-num = <1 1>;
qcom,gpio-set-tbl-flags = <0 2>;
qcom,gpio-set-tbl-delay = <1000 30000>;
@@ -56,7 +65,6 @@
compatible = "qcom,ov2720";
reg = <0x6c 0x0>;
qcom,slave-id = <0x6c 0x300A 0x2720>;
- qcom,led-flash-sd-index = <0>;
qcom,csiphy-sd-index = <2>;
qcom,csid-sd-index = <0>;
qcom,mount-angle = <90>;
@@ -87,4 +95,38 @@
qcom,cci-master = <1>;
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 92 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-camera-sensor-fluid.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-fluid.dtsi
index 51c6712..4fe4220 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-fluid.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-fluid.dtsi
@@ -13,14 +13,21 @@
&cci {
+ actuator0: qcom,actuator@18 {
+ cell-index = <0>;
+ reg = <0x18 0x0>;
+ compatible = "qcom,actuator";
+ qcom,cci-master = <0>;
+ };
+
qcom,camera@6e {
compatible = "qcom,s5k3l1yx";
reg = <0x6e>;
qcom,slave-id = <0x6e 0x0 0x3121>;
qcom,csiphy-sd-index = <0>;
qcom,csid-sd-index = <0>;
- qcom,flash-src-index = <&led_flash0>;
qcom,actuator-src = <&actuator0>;
+ qcom,led-flash-src = <&led_flash0>;
qcom,mount-angle = <270>;
qcom,sensor-name = "s5k3l1yx";
cam_vdig-supply = <&pm8941_l3>;
@@ -35,12 +42,15 @@
qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
qcom,gpio-no-mux = <0>;
gpios = <&msmgpio 15 0>,
- <&msmgpio 90 0>;
+ <&msmgpio 90 0>,
+ <&msmgpio 89 0>;
qcom,gpio-reset = <1>;
- qcom,gpio-req-tbl-num = <0 1>;
- qcom,gpio-req-tbl-flags = <1 0>;
+ qcom,gpio-standby = <2>;
+ qcom,gpio-req-tbl-num = <0 1 2>;
+ qcom,gpio-req-tbl-flags = <1 0 0>;
qcom,gpio-req-tbl-label = "CAMIF_MCLK",
- "CAM_RESET1";
+ "CAM_RESET1",
+ "CAM_STANDBY";
qcom,gpio-set-tbl-num = <1 1>;
qcom,gpio-set-tbl-flags = <0 2>;
qcom,gpio-set-tbl-delay = <1000 30000>;
@@ -56,7 +66,6 @@
compatible = "qcom,ov2720";
reg = <0x6c>;
qcom,slave-id = <0x6c 0x300A 0x2720>;
- qcom,led-flash-sd-index = <0>;
qcom,csiphy-sd-index = <2>;
qcom,csid-sd-index = <0>;
qcom,mount-angle = <90>;
@@ -87,4 +96,38 @@
qcom,cci-master = <1>;
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 92 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-camera-sensor-liquid.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi
index dd85b3c..b313795 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi
@@ -14,13 +14,19 @@
&cci {
+ actuator0: qcom,actuator@18 {
+ cell-index = <0>;
+ reg = <0x18 0x0>;
+ 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,flash-src-index = <&led_flash0>;
qcom,mount-angle = <0>;
qcom,sensor-name = "s5k3l1yx";
cam_vdig-supply = <&pm8941_l3>;
@@ -56,7 +62,6 @@
compatible = "qcom,ov2720";
reg = <0x6c 0x0>;
qcom,slave-id = <0x6c 0x300A 0x2720>;
- qcom,led-flash-sd-index = <0>;
qcom,csiphy-sd-index = <2>;
qcom,csid-sd-index = <0>;
qcom,mount-angle = <180>;
@@ -87,4 +92,38 @@
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 92 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-camera.dtsi b/arch/arm/boot/dts/msm8974-camera.dtsi
index a550c0b..ea99aa3 100644
--- a/arch/arm/boot/dts/msm8974-camera.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera.dtsi
@@ -158,8 +158,9 @@
qcom,cpp@fda04000 {
cell-index = <0>;
compatible = "qcom,cpp";
- reg = <0xfda04000 0x100>;
- reg-names = "cpp";
+ reg = <0xfda04000 0x100>,
+ <0xfda40000 0x200>;
+ reg-names = "cpp", "cpp_vbif";
interrupts = <0 49 0>;
interrupt-names = "cpp";
vdd-supply = <&gdsc_vfe>;
@@ -202,54 +203,5 @@
qcom,hw-scl-stretch-en = <0>;
qcom,hw-trdhld = <6>;
qcom,hw-tsp = <1>;
-
- actuator0: qcom,actuator@18 {
- cell-index = <0>;
- reg = <0x18 0x0>;
- compatible = "qcom,actuator";
- qcom,cci-master = <0>;
- };
-
- qcom,camera@6e {
- status = "disable";
- };
-
- qcom,camera@6c {
- status = "disable";
- };
-
- 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 92 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-cdp.dtsi b/arch/arm/boot/dts/msm8974-cdp.dtsi
index c1a01b2..0acfaf6 100644
--- a/arch/arm/boot/dts/msm8974-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8974-cdp.dtsi
@@ -13,7 +13,7 @@
/include/ "dsi-panel-toshiba-720p-video.dtsi"
/include/ "dsi-panel-orise-720p-video.dtsi"
/include/ "msm8974-leds.dtsi"
-/include/ "msm8974-camera-sensor.dtsi"
+/include/ "msm8974-camera-sensor-cdp-mtp.dtsi"
/ {
serial@f991e000 {
@@ -203,6 +203,21 @@
startup-delay-us = <17000>;
enable-active-high;
};
+
+ hsic@f9a00000 {
+ compatible = "qcom,hsic-host";
+ reg = <0xf9a00000 0x400>;
+ interrupts = <0 136 0>, <0 148 0>;
+ interrupt-names = "core_irq", "async_irq";
+ HSIC_VDDCX-supply = <&pm8841_s2>;
+ HSIC_GDSC-supply = <&gdsc_usb_hsic>;
+ hsic,strobe-gpio = <&msmgpio 144 0x00>;
+ hsic,data-gpio = <&msmgpio 145 0x00>;
+ hsic,ignore-cal-pad-config;
+ hsic,strobe-pad-offset = <0x2050>;
+ hsic,data-pad-offset = <0x2054>;
+ };
+
};
&spmi_bus {
@@ -215,7 +230,7 @@
linux,default-trigger = "bkl-trigger";
qcom,cs-out-en;
qcom,op-fdbck;
- qcom,default-state = "off";
+ qcom,default-state = "on";
qcom,max-current = <25>;
qcom,ctrl-delay-us = <0>;
qcom,boost-curr-lim = <3>;
diff --git a/arch/arm/boot/dts/msm8974-coresight.dtsi b/arch/arm/boot/dts/msm8974-coresight.dtsi
index 427ef0b..5df8f10 100644
--- a/arch/arm/boot/dts/msm8974-coresight.dtsi
+++ b/arch/arm/boot/dts/msm8974-coresight.dtsi
@@ -15,6 +15,7 @@
compatible = "arm,coresight-tmc";
reg = <0xfc322000 0x1000>,
<0xfc37c000 0x3000>;
+ reg-names = "tmc-etr-base", "tmc-etr-bam-base";
qcom,memory-reservation-type = "EBI1";
qcom,memory-reservation-size = <0x100000>; /* 1M EBI1 buffer */
@@ -22,11 +23,13 @@
coresight-id = <0>;
coresight-name = "coresight-tmc-etr";
coresight-nr-inports = <1>;
+ coresight-ctis = <&cti0 &cti8>;
};
tpiu: tpiu@fc318000 {
compatible = "arm,coresight-tpiu";
reg = <0xfc318000 0x1000>;
+ reg-names = "tpiu-base";
coresight-id = <1>;
coresight-name = "coresight-tpiu";
@@ -36,6 +39,7 @@
replicator: replicator@fc31c000 {
compatible = "qcom,coresight-replicator";
reg = <0xfc31c000 0x1000>;
+ reg-names = "replicator-base";
coresight-id = <2>;
coresight-name = "coresight-replicator";
@@ -48,6 +52,7 @@
tmc_etf: tmc@fc307000 {
compatible = "arm,coresight-tmc";
reg = <0xfc307000 0x1000>;
+ reg-names = "tmc-etf-base";
coresight-id = <3>;
coresight-name = "coresight-tmc-etf";
@@ -56,11 +61,13 @@
coresight-child-list = <&replicator>;
coresight-child-ports = <0>;
coresight-default-sink;
+ coresight-ctis = <&cti0 &cti8>;
};
funnel_merg: funnel@fc31b000 {
compatible = "arm,coresight-funnel";
reg = <0xfc31b000 0x1000>;
+ reg-names = "funnel-merg-base";
coresight-id = <4>;
coresight-name = "coresight-funnel-merg";
@@ -73,6 +80,7 @@
funnel_in0: funnel@fc319000 {
compatible = "arm,coresight-funnel";
reg = <0xfc319000 0x1000>;
+ reg-names = "funnel-in0-base";
coresight-id = <5>;
coresight-name = "coresight-funnel-in0";
@@ -85,6 +93,7 @@
funnel_in1: funnel@fc31a000 {
compatible = "arm,coresight-funnel";
reg = <0xfc31a000 0x1000>;
+ reg-names = "funnel-in1-base";
coresight-id = <6>;
coresight-name = "coresight-funnel-in1";
@@ -97,6 +106,7 @@
funnel_kpss: funnel@fc345000 {
compatible = "arm,coresight-funnel";
reg = <0xfc345000 0x1000>;
+ reg-names = "funnel-kpss-base";
coresight-id = <7>;
coresight-name = "coresight-funnel-kpss";
@@ -109,6 +119,8 @@
funnel_mmss: funnel@fc364000 {
compatible = "arm,coresight-funnel";
reg = <0xfc364000 0x1000>;
+ reg-names = "funnel-mmss-base";
+
coresight-id = <8>;
coresight-name = "coresight-funnel-mmss";
@@ -122,6 +134,7 @@
compatible = "arm,coresight-stm";
reg = <0xfc321000 0x1000>,
<0xfa280000 0x180000>;
+ reg-names = "stm-base", "stm-data-base";
coresight-id = <9>;
coresight-name = "coresight-stm";
@@ -134,6 +147,7 @@
etm0: etm@fc33c000 {
compatible = "arm,coresight-etm";
reg = <0xfc33c000 0x1000>;
+ reg-names = "etm0-base";
coresight-id = <10>;
coresight-name = "coresight-etm0";
@@ -149,6 +163,7 @@
etm1: etm@fc33d000 {
compatible = "arm,coresight-etm";
reg = <0xfc33d000 0x1000>;
+ reg-names = "etm1-base";
coresight-id = <11>;
coresight-name = "coresight-etm1";
@@ -164,6 +179,7 @@
etm2: etm@fc33e000 {
compatible = "arm,coresight-etm";
reg = <0xfc33e000 0x1000>;
+ reg-names = "etm2-base";
coresight-id = <12>;
coresight-name = "coresight-etm2";
@@ -179,6 +195,7 @@
etm3: etm@fc33f000 {
compatible = "arm,coresight-etm";
reg = <0xfc33f000 0x1000>;
+ reg-names = "etm3-base";
coresight-id = <13>;
coresight-name = "coresight-etm3";
@@ -194,6 +211,7 @@
csr: csr@fc302000 {
compatible = "qcom,coresight-csr";
reg = <0xfc302000 0x1000>;
+ reg-names = "csr-base";
coresight-id = <14>;
coresight-name = "coresight-csr";
@@ -201,4 +219,144 @@
qcom,blk-size = <3>;
};
+
+ cti0: cti@fc308000 {
+ compatible = "arm,coresight-cti";
+ reg = <0xfc308000 0x1000>;
+ reg-names = "cti0-base";
+
+ coresight-id = <15>;
+ coresight-name = "coresight-cti0";
+ coresight-nr-inports = <0>;
+ };
+
+ cti1: cti@fc309000 {
+ compatible = "arm,coresight-cti";
+ reg = <0xfc309000 0x1000>;
+ reg-names = "cti1-base";
+
+ coresight-id = <16>;
+ coresight-name = "coresight-cti1";
+ coresight-nr-inports = <0>;
+ };
+
+ cti2: cti@fc30a000 {
+ compatible = "arm,coresight-cti";
+ reg = <0xfc30a000 0x1000>;
+ reg-names = "cti2-base";
+
+ coresight-id = <17>;
+ coresight-name = "coresight-cti2";
+ coresight-nr-inports = <0>;
+ };
+
+ cti3: cti@fc30b000 {
+ compatible = "arm,coresight-cti";
+ reg = <0xfc30b000 0x1000>;
+ reg-names = "cti3-base";
+
+ coresight-id = <18>;
+ coresight-name = "coresight-cti3";
+ coresight-nr-inports = <0>;
+ };
+
+ cti4: cti@fc30c000 {
+ compatible = "arm,coresight-cti";
+ reg = <0xfc30c000 0x1000>;
+ reg-names = "cti4-base";
+
+ coresight-id = <19>;
+ coresight-name = "coresight-cti4";
+ coresight-nr-inports = <0>;
+ };
+
+ cti5: cti@fc30d000 {
+ compatible = "arm,coresight-cti";
+ reg = <0xfc30d000 0x1000>;
+ reg-names = "cti5-base";
+
+ coresight-id = <20>;
+ coresight-name = "coresight-cti5";
+ coresight-nr-inports = <0>;
+ };
+
+ cti6: cti@fc30e000 {
+ compatible = "arm,coresight-cti";
+ reg = <0xfc30e000 0x1000>;
+ reg-names = "cti6-base";
+
+ coresight-id = <21>;
+ coresight-name = "coresight-cti6";
+ coresight-nr-inports = <0>;
+ };
+
+ cti7: cti@fc30f000 {
+ compatible = "arm,coresight-cti";
+ reg = <0xfc30f000 0x1000>;
+ reg-names = "cti7-base";
+
+ coresight-id = <22>;
+ coresight-name = "coresight-cti7";
+ coresight-nr-inports = <0>;
+ };
+
+ cti8: cti@fc310000 {
+ compatible = "arm,coresight-cti";
+ reg = <0xfc310000 0x1000>;
+ reg-names = "cti8-base";
+
+ coresight-id = <23>;
+ coresight-name = "coresight-cti8";
+ coresight-nr-inports = <0>;
+ };
+
+ cti_l2: cti@fc340000 {
+ compatible = "arm,coresight-cti";
+ reg = <0xfc340000 0x1000>;
+ reg-names = "cti-l2-base";
+
+ coresight-id = <24>;
+ coresight-name = "coresight-cti-l2";
+ coresight-nr-inports = <0>;
+ };
+
+ cti_cpu0: cti@fc341000 {
+ compatible = "arm,coresight-cti";
+ reg = <0xfc341000 0x1000>;
+ reg-names = "cti-cpu0-base";
+
+ coresight-id = <25>;
+ coresight-name = "coresight-cti-cpu0";
+ coresight-nr-inports = <0>;
+ };
+
+ cti_cpu1: cti@fc342000 {
+ compatible = "arm,coresight-cti";
+ reg = <0xfc342000 0x1000>;
+ reg-names = "cti-cpu1-base";
+
+ coresight-id = <26>;
+ coresight-name = "coresight-cti-cpu1";
+ coresight-nr-inports = <0>;
+ };
+
+ cti_cpu2: cti@fc343000 {
+ compatible = "arm,coresight-cti";
+ reg = <0xfc343000 0x1000>;
+ reg-names = "cti-cpu2-base";
+
+ coresight-id = <27>;
+ coresight-name = "coresight-cti-cpu2";
+ coresight-nr-inports = <0>;
+ };
+
+ cti_cpu3: cti@fc344000 {
+ compatible = "arm,coresight-cti";
+ reg = <0xfc344000 0x1000>;
+ reg-names = "cti-cpu3-base";
+
+ coresight-id = <28>;
+ coresight-name = "coresight-cti-cpu3";
+ coresight-nr-inports = <0>;
+ };
};
diff --git a/arch/arm/boot/dts/msm8974-fluid.dtsi b/arch/arm/boot/dts/msm8974-fluid.dtsi
index 11c835f..92a6e01 100644
--- a/arch/arm/boot/dts/msm8974-fluid.dtsi
+++ b/arch/arm/boot/dts/msm8974-fluid.dtsi
@@ -224,7 +224,7 @@
linux,default-trigger = "bkl-trigger";
qcom,cs-out-en;
qcom,op-fdbck;
- qcom,default-state = "off";
+ qcom,default-state = "on";
qcom,max-current = <25>;
qcom,ctrl-delay-us = <0>;
qcom,boost-curr-lim = <3>;
diff --git a/arch/arm/boot/dts/msm8974-liquid.dtsi b/arch/arm/boot/dts/msm8974-liquid.dtsi
index 77ee37c..68fed68 100644
--- a/arch/arm/boot/dts/msm8974-liquid.dtsi
+++ b/arch/arm/boot/dts/msm8974-liquid.dtsi
@@ -294,6 +294,11 @@
enable-active-high;
};
+ bt_ar3002 {
+ compatible = "qca,ar3002";
+ qca,bt-reset-gpio = <&pm8941_gpios 34 0>;
+ };
+
sound {
qcom,model = "msm8974-taiko-liquid-snd-card";
diff --git a/arch/arm/boot/dts/msm8974-mtp.dtsi b/arch/arm/boot/dts/msm8974-mtp.dtsi
index e21610b..c6935f4 100644
--- a/arch/arm/boot/dts/msm8974-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974-mtp.dtsi
@@ -11,7 +11,7 @@
*/
/include/ "dsi-panel-toshiba-720p-video.dtsi"
-/include/ "msm8974-camera-sensor.dtsi"
+/include/ "msm8974-camera-sensor-cdp-mtp.dtsi"
/include/ "msm8974-leds.dtsi"
/ {
@@ -199,7 +199,7 @@
linux,default-trigger = "bkl-trigger";
qcom,cs-out-en;
qcom,op-fdbck;
- qcom,default-state = "off";
+ qcom,default-state = "on";
qcom,max-current = <25>;
qcom,ctrl-delay-us = <0>;
qcom,boost-curr-lim = <3>;
diff --git a/arch/arm/boot/dts/msm8974-v1-pm.dtsi b/arch/arm/boot/dts/msm8974-pm.dtsi
similarity index 100%
rename from arch/arm/boot/dts/msm8974-v1-pm.dtsi
rename to arch/arm/boot/dts/msm8974-pm.dtsi
diff --git a/arch/arm/boot/dts/msm8974-rumi.dtsi b/arch/arm/boot/dts/msm8974-rumi.dtsi
index 932c11c..ce9d6c9 100644
--- a/arch/arm/boot/dts/msm8974-rumi.dtsi
+++ b/arch/arm/boot/dts/msm8974-rumi.dtsi
@@ -11,7 +11,7 @@
*/
/include/ "msm8974-leds.dtsi"
-/include/ "msm8974-camera-sensor.dtsi"
+/include/ "msm8974-camera-sensor-cdp-mtp.dtsi"
/ {
timer {
diff --git a/arch/arm/boot/dts/msm8974-sim.dtsi b/arch/arm/boot/dts/msm8974-sim.dtsi
index fb638f7..a5606b8 100644
--- a/arch/arm/boot/dts/msm8974-sim.dtsi
+++ b/arch/arm/boot/dts/msm8974-sim.dtsi
@@ -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
@@ -12,7 +12,7 @@
/include/ "dsi-panel-sim-video.dtsi"
/include/ "msm8974-leds.dtsi"
-/include/ "msm8974-camera-sensor.dtsi"
+/include/ "msm8974-camera-sensor-cdp-mtp.dtsi"
/ {
qcom,mdss_dsi@fd922800 {
diff --git a/arch/arm/boot/dts/msm8974-v1-cdp.dts b/arch/arm/boot/dts/msm8974-v1-cdp.dts
index 33bd1fb..8db99b2 100644
--- a/arch/arm/boot/dts/msm8974-v1-cdp.dts
+++ b/arch/arm/boot/dts/msm8974-v1-cdp.dts
@@ -19,6 +19,10 @@
model = "Qualcomm MSM 8974 CDP";
compatible = "qcom,msm8974-cdp", "qcom,msm8974";
qcom,msm-id = <126 1 0>;
+
+ qcom,mdss_dsi_toshiba_720p_video {
+ qcom,cont-splash-enabled;
+ };
};
&ehci {
diff --git a/arch/arm/boot/dts/msm8974-v1-fluid.dts b/arch/arm/boot/dts/msm8974-v1-fluid.dts
index 0b435a3..60f2c4b 100644
--- a/arch/arm/boot/dts/msm8974-v1-fluid.dts
+++ b/arch/arm/boot/dts/msm8974-v1-fluid.dts
@@ -19,4 +19,8 @@
model = "Qualcomm MSM 8974 FLUID";
compatible = "qcom,msm8974-fluid", "qcom,msm8974";
qcom,msm-id = <126 3 0>;
+
+ qcom,mdss_dsi_toshiba_720p_video {
+ qcom,cont-splash-enabled;
+ };
};
diff --git a/arch/arm/boot/dts/msm8974-v1-mtp.dts b/arch/arm/boot/dts/msm8974-v1-mtp.dts
index 01e9fe2..2d52f78 100644
--- a/arch/arm/boot/dts/msm8974-v1-mtp.dts
+++ b/arch/arm/boot/dts/msm8974-v1-mtp.dts
@@ -19,4 +19,8 @@
model = "Qualcomm MSM 8974 MTP";
compatible = "qcom,msm8974-mtp", "qcom,msm8974";
qcom,msm-id = <126 8 0>;
+
+ qcom,mdss_dsi_toshiba_720p_video {
+ qcom,cont-splash-enabled;
+ };
};
diff --git a/arch/arm/boot/dts/msm8974-v1.dtsi b/arch/arm/boot/dts/msm8974-v1.dtsi
index 7930547..37b2c45 100644
--- a/arch/arm/boot/dts/msm8974-v1.dtsi
+++ b/arch/arm/boot/dts/msm8974-v1.dtsi
@@ -18,7 +18,6 @@
/include/ "msm8974.dtsi"
/include/ "msm8974-v1-iommu.dtsi"
-/include/ "msm8974-v1-pm.dtsi"
/ {
android_usb@fc42b0c8 {
@@ -36,3 +35,74 @@
&tsens {
qcom,calibration-less-mode;
};
+
+/* I2C clock frequency overrides */
+&i2c_0 {
+ qcom,i2c-src-freq = <19200000>;
+};
+
+&i2c_2 {
+ qcom,i2c-src-freq = <19200000>;
+};
+
+/* CoreSight */
+&tmc_etr {
+ qcom,reset-flush-race;
+};
+
+&msm_vidc {
+ qcom,vidc-cp-map = <0x1000000 0x3f000000>;
+ qcom,vidc-ns-map = <0x40000000 0x40000000>;
+ qcom,load-freq-tbl = <979200 410000000>,
+ <783360 410000000>,
+ <489600 266670000>,
+ <244800 133330000>;
+ qcom,reg-presets = <0x80004 0x1>,
+ <0x80178 0x00001FFF>,
+ <0x8017c 0x1FFF1FFF>,
+ <0x800b0 0x10101001>,
+ <0x800b4 0x10101010>,
+ <0x800b8 0x10101010>,
+ <0x800bc 0x00000010>,
+ <0x800c0 0x1010100f>,
+ <0x800c4 0x10101010>,
+ <0x800c8 0x10101010>,
+ <0x800cc 0x00000010>,
+ <0x800d0 0x00001010>,
+ <0x800d4 0x00001010>,
+ <0x800f0 0x00000030>,
+ <0x800d8 0x00000707>,
+ <0x800dc 0x00000707>,
+ <0x80124 0x00000001>,
+ <0xE0020 0x5555556>,
+ <0xE0024 0x0>;
+ qcom,bus-ports = <1>;
+ qcom,enc-ocmem-ab-ib = <0 0>,
+ <138200 1222000>,
+ <414700 1222000>,
+ <940000 2444000>,
+ <1880000 2444000>,
+ <3008000 3910400>,
+ <3760000 4888000>;
+ qcom,dec-ocmem-ab-ib = <0 0>,
+ <176900 1556640>,
+ <456200 1556640>,
+ <864800 1556640>,
+ <1729600 3113280>,
+ <2767360 4981248>,
+ <3459200 6226560>;
+ qcom,enc-ddr-ab-ib = <0 0>,
+ <60000 664950>,
+ <181000 664950>,
+ <403000 664950>,
+ <806000 1329900>,
+ <1289600 2127840>,
+ <161200 6400000>;
+ qcom,dec-ddr-ab-ib = <0 0>,
+ <110000 909000>,
+ <268000 909000>,
+ <505000 909000>,
+ <1010000 1818000>,
+ <1616000 2908800>,
+ <2020000 6400000>;
+};
diff --git a/arch/arm/boot/dts/msm8974-v2-pm.dtsi b/arch/arm/boot/dts/msm8974-v2-pm.dtsi
deleted file mode 100644
index 0ed55ff..0000000
--- a/arch/arm/boot/dts/msm8974-v2-pm.dtsi
+++ /dev/null
@@ -1,426 +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/ "skeleton.dtsi"
-
-/ {
- qcom,spm@f9089000 {
- compatible = "qcom,spm-v2";
- #address-cells = <1>;
- #size-cells = <1>;
- reg = <0xf9089000 0x1000>;
- qcom,core-id = <0>;
- qcom,saw2-ver-reg = <0xfd0>;
- qcom,saw2-cfg = <0x01>;
- qcom,saw2-avs-ctl = <0>;
- qcom,saw2-avs-hysteresis = <0>;
- qcom,saw2-avs-limit = <0>;
- qcom,saw2-avs-dly= <0>;
- qcom,saw2-spm-dly= <0x20000400>;
- qcom,saw2-spm-ctl = <0x1>;
- qcom,saw2-spm-cmd-wfi = [03 0b 0f];
- qcom,saw2-spm-cmd-ret = [42 1b 00 d0 03 d4 5b 0b 00 42 1b 0f];
- qcom,saw2-spm-cmd-spc = [00 20 50 80 60 70 10 E0 03 6E 70 3B
- E4 5B 82 2B 50 10 0B 30 06 26 30 0F];
- qcom,saw2-spm-cmd-pc = [00 20 50 80 60 70 10 E0 07 6E 70 3B
- E4 5B 82 2B 50 10 0B 30 06 26 30 0F];
- };
-
- qcom,spm@f9099000 {
- compatible = "qcom,spm-v2";
- #address-cells = <1>;
- #size-cells = <1>;
- reg = <0xf9099000 0x1000>;
- qcom,core-id = <1>;
- qcom,saw2-ver-reg = <0xfd0>;
- qcom,saw2-cfg = <0x01>;
- qcom,saw2-avs-ctl = <0>;
- qcom,saw2-avs-hysteresis = <0>;
- qcom,saw2-avs-limit = <0>;
- qcom,saw2-avs-dly= <0>;
- qcom,saw2-spm-dly= <0x20000400>;
- qcom,saw2-spm-ctl = <0x1>;
- qcom,saw2-spm-cmd-wfi = [03 0b 0f];
- qcom,saw2-spm-cmd-ret = [42 1b 00 d0 03 d4 5b 0b 00 42 1b 0f];
- qcom,saw2-spm-cmd-spc = [00 20 50 80 60 70 10 E0 03 6E 70 3B
- E4 5B 82 2B 50 10 0B 30 06 26 30 0F];
- qcom,saw2-spm-cmd-pc = [00 20 50 80 60 70 10 E0 07 6E 70 3B
- E4 5B 82 2B 50 10 0B 30 06 26 30 0F];
- };
-
- qcom,spm@f90a9000 {
- compatible = "qcom,spm-v2";
- #address-cells = <1>;
- #size-cells = <1>;
- reg = <0xf90a9000 0x1000>;
- qcom,core-id = <2>;
- qcom,saw2-ver-reg = <0xfd0>;
- qcom,saw2-cfg = <0x01>;
- qcom,saw2-avs-ctl = <0>;
- qcom,saw2-avs-hysteresis = <0>;
- qcom,saw2-avs-limit = <0>;
- qcom,saw2-avs-dly= <0>;
- qcom,saw2-spm-dly= <0x20000400>;
- qcom,saw2-spm-ctl = <0x1>;
- qcom,saw2-spm-cmd-wfi = [03 0b 0f];
- qcom,saw2-spm-cmd-ret = [42 1b 00 d0 03 d4 5b 0b 00 42 1b 0f];
- qcom,saw2-spm-cmd-spc = [00 20 50 80 60 70 10 E0 03 6E 70 3B
- E4 5B 82 2B 50 10 0B 30 06 26 30 0F];
- qcom,saw2-spm-cmd-pc = [00 20 50 80 60 70 10 E0 07 6E 70 3B
- E4 5B 82 2B 50 10 0B 30 06 26 30 0F];
- };
-
- qcom,spm@f90b9000 {
- compatible = "qcom,spm-v2";
- #address-cells = <1>;
- #size-cells = <1>;
- reg = <0xf90b9000 0x1000>;
- qcom,core-id = <3>;
- qcom,saw2-ver-reg = <0xfd0>;
- qcom,saw2-cfg = <0x01>;
- qcom,saw2-avs-ctl = <0>;
- qcom,saw2-avs-hysteresis = <0>;
- qcom,saw2-avs-limit = <0>;
- qcom,saw2-avs-dly= <0>;
- qcom,saw2-spm-dly= <0x20000400>;
- qcom,saw2-spm-ctl = <0x1>;
- qcom,saw2-spm-cmd-wfi = [03 0b 0f];
- qcom,saw2-spm-cmd-ret = [42 1b 00 d0 03 d4 5b 0b 00 42 1b 0f];
- qcom,saw2-spm-cmd-spc = [00 20 50 80 60 70 10 E0 03 6E 70 3B
- E4 5B 82 2B 50 10 0B 30 06 26 30 0F];
- qcom,saw2-spm-cmd-pc = [00 20 50 80 60 70 10 E0 07 6E 70 3B
- E4 5B 82 2B 50 10 0B 30 06 26 30 0F];
- };
-
- qcom,spm@f9012000 {
- compatible = "qcom,spm-v2";
- #address-cells = <1>;
- #size-cells = <1>;
- reg = <0xf9012000 0x1000>;
- qcom,core-id = <0xffff>; /* L2/APCS SAW */
- qcom,saw2-ver-reg = <0xfd0>;
- qcom,saw2-cfg = <0x14>;
- qcom,saw2-avs-ctl = <0>;
- qcom,saw2-avs-hysteresis = <0>;
- qcom,saw2-avs-limit = <0>;
- qcom,saw2-avs-dly= <0>;
- qcom,saw2-spm-dly= <0x20000400>;
- qcom,saw2-spm-ctl = <0x1>;
- qcom,saw2-pmic-data0 = <0x02030080>;
- qcom,saw2-pmic-data1 = <0x00030000>;
- qcom,vctl-timeout-us = <50>;
- qcom,vctl-port = <0x0>;
- qcom,phase-port = <0x1>;
- qcom,pfm-port = <0x2>;
- qcom,saw2-spm-cmd-ret = [1f 00 20 03 22 00 0f];
- qcom,saw2-spm-cmd-gdhs = [00 20 32 60 70 80 42 07 78 80 44 22 50
- 3b 60 02 32 50 0f];
- qcom,saw2-spm-cmd-pc = [00 10 32 60 70 80 b0 11 42 07 01 b0 78
- 80 12 44 50 3b 60 02 32 50 0f];
- };
-
- qcom,lpm-resources {
- compatible = "qcom,lpm-resources";
- #address-cells = <1>;
- #size-cells = <0>;
-
- qcom,lpm-resources@0 {
- reg = <0x0>;
- qcom,name = "vdd-dig";
- qcom,resource-type = <0>;
- qcom,type = <0x62706d73>; /* "smpb" */
- qcom,id = <0x02>;
- qcom,key = <0x6e726f63>; /* "corn" */
- qcom,init-value = <5>; /* Super Turbo */
- };
-
- qcom,lpm-resources@1 {
- reg = <0x1>;
- qcom,name = "vdd-mem";
- qcom,resource-type = <0>;
- qcom,type = <0x62706d73>; /* "smpb" */
- qcom,id = <0x01>;
- qcom,key = <0x7675>; /* "uv" */
- qcom,init-value = <1050000>; /* Super Turbo */
- };
-
- qcom,lpm-resources@2 {
- reg = <0x2>;
- qcom,name = "pxo";
- qcom,resource-type = <0>;
- qcom,type = <0x306b6c63>; /* "clk0" */
- qcom,id = <0x00>;
- qcom,key = <0x62616e45>; /* "Enab" */
- qcom,init-value = <1>; /* On */
- };
-
- qcom,lpm-resources@3 {
- reg = <0x3>;
- qcom,name = "l2";
- qcom,resource-type = <1>;
- qcom,init-value = <2>; /* Retention */
- };
- };
-
- qcom,lpm-levels {
- compatible = "qcom,lpm-levels";
- #address-cells = <1>;
- #size-cells = <0>;
-
- qcom,lpm-level@0 {
- reg = <0x0>;
- qcom,mode = <0>; /* MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT */
- qcom,xo = <1>; /* ON */
- qcom,l2 = <2>; /* Retention */
- qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
- qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
- qcom,irqs-detectable;
- qcom.gpios-detectable;
- qcom,latency-us = <1>;
- qcom,ss-power = <784>;
- qcom,energy-overhead = <190000>;
- qcom,time-overhead = <100>;
- };
-
- qcom,lpm-level@1 {
- reg = <0x1>;
- qcom,mode = <4>; /* MSM_PM_SLEEP_MODE_RETENTION*/
- qcom,xo = <1>; /* ON */
- qcom,l2 = <2>; /* Retention */
- qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
- qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
- qcom,irqs-detectable;
- qcom.gpios-detectable;
- qcom,latency-us = <75>;
- qcom,ss-power = <735>;
- qcom,energy-overhead = <77341>;
- qcom,time-overhead = <105>;
- };
-
- qcom,lpm-level@2 {
- reg = <0x2>;
- qcom,mode = <2>; /* MSM_PM_SLEEP_MODE_STANDALONE_POWER_COLLAPSE */
- qcom,xo = <1>; /* ON */
- qcom,l2 = <2>; /* Retention */
- qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
- qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
- qcom,irqs-detectable;
- qcom.gpios-detectable;
- qcom,latency-us = <95>;
- qcom,ss-power = <725>;
- qcom,energy-overhead = <99500>;
- qcom,time-overhead = <130>;
- };
-
- qcom,lpm-level@3 {
- reg = <0x3>;
- qcom,mode = <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
- qcom,xo = <1>; /* ON */
- qcom,l2 = <1>; /* GDHS */
- qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
- qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
- qcom,irqs-detectable;
- qcom.gpios-detectable;
- qcom,latency-us = <2000>;
- qcom,ss-power = <138>;
- qcom,energy-overhead = <1208400>;
- qcom,time-overhead = <3200>;
- };
-
- qcom,lpm-level@4 {
- reg = <0x4>;
- qcom,mode = <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
- qcom,xo = <1>; /* ON */
- qcom,l2 = <1>; /* GDHS */
- qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <950000>; /* SVS SOC */
- qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <3>; /* SVS SOC */
- qcom,irqs-detectable;
- qcom.gpios-detectable;
- qcom,latency-us = <3000>;
- qcom,ss-power = <110>;
- qcom,energy-overhead = <1250300>;
- qcom,time-overhead = <3500>;
- };
-
- qcom,lpm-level@5 {
- reg = <0x5>;
- qcom,mode = <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
- qcom,xo = <0>; /* OFF */
- qcom,l2 = <1>; /* GDHS */
- qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
- qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
- qcom,latency-us = <3000>;
- qcom,ss-power = <68>;
- qcom,energy-overhead = <1350200>;
- qcom,time-overhead = <4000>;
- };
-
- qcom,lpm-level@6 {
- reg = <0x6>;
- qcom,mode= <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
- qcom,xo = <0>; /* OFF */
- qcom,l2 = <1>; /* GDHS */
- qcom,vdd-mem-upper-bound = <950000>; /* NORMAL */
- qcom,vdd-mem-lower-bound = <950000>; /* SVS SOC */
- qcom,vdd-dig-upper-bound = <4>; /* NORMAL */
- qcom,vdd-dig-lower-bound = <3>; /* SVS SOC */
- qcom,latency-us = <18000>;
- qcom,ss-power = <10>;
- qcom,energy-overhead = <3202600>;
- qcom,time-overhead = <27000>;
- };
-
- qcom,lpm-level@7 {
- reg = <0x7>;
- qcom,mode= <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
- qcom,xo = <0>; /* OFF */
- qcom,l2 = <0>; /* OFF */
- qcom,vdd-mem-upper-bound = <950000>; /* SVS SOC */
- qcom,vdd-mem-lower-bound = <675000>; /* RETENTION */
- qcom,vdd-dig-upper-bound = <3>; /* SVS SOC */
- qcom,vdd-dig-lower-bound = <1>; /* RETENTION */
- qcom,latency-us = <20000>;
- qcom,ss-power = <2>;
- qcom,energy-overhead = <4252000>;
- qcom,time-overhead = <32000>;
- };
- };
-
- qcom,pm-boot {
- compatible = "qcom,pm-boot";
- qcom,mode = <0>; /* MSM_PM_BOOT_CONFIG_TZ */
- };
-
- qcom,mpm@fc4281d0 {
- compatible = "qcom,mpm-v2";
- reg = <0xfc4281d0 0x1000>, /* MSM_RPM_MPM_BASE 4K */
- <0xf9011008 0x4>; /* MSM_APCS_GCC_BASE 4K */
- reg-names = "vmpm", "ipc";
- interrupts = <0 171 1>;
-
- qcom,ipc-bit-offset = <1>;
-
- qcom,gic-parent = <&intc>;
- qcom,gic-map = <47 172>, /* usb2_hsic_async_wakeup_irq */
- <53 104>, /* mdss_irq */
- <62 222>, /* ee0_krait_hlos_spmi_periph_irq */
- <0xff 57>, /* mss_to_apps_irq(0) */
- <0xff 58>, /* mss_to_apps_irq(1) */
- <0xff 59>, /* mss_to_apps_irq(2) */
- <0xff 60>, /* mss_to_apps_irq(3) */
- <0xff 173>, /* o_wcss_apss_smd_hi */
- <0xff 174>, /* o_wcss_apss_smd_med */
- <0xff 175>, /* o_wcss_apss_smd_low */
- <0xff 176>, /* o_wcss_apss_smsm_irq */
- <0xff 177>, /* o_wcss_apss_wlan_data_xfer_done */
- <0xff 178>, /* o_wcss_apss_wlan_rx_data_avail */
- <0xff 179>, /* o_wcss_apss_asic_intr
-
- <0xff 188>, /* lpass_irq_out_apcs(0) */
- <0xff 189>, /* lpass_irq_out_apcs(1) */
- <0xff 190>, /* lpass_irq_out_apcs(2) */
- <0xff 191>, /* lpass_irq_out_apcs(3) */
- <0xff 192>, /* lpass_irq_out_apcs(4) */
- <0xff 193>, /* lpass_irq_out_apcs(5) */
- <0xff 194>, /* lpass_irq_out_apcs(6) */
- <0xff 195>, /* lpass_irq_out_apcs(7) */
- <0xff 196>, /* lpass_irq_out_apcs(8) */
- <0xff 197>, /* lpass_irq_out_apcs(9) */
- <0xff 200>, /* rpm_ipc(4) */
- <0xff 201>, /* rpm_ipc(5) */
- <0xff 202>, /* rpm_ipc(6) */
- <0xff 203>, /* rpm_ipc(7) */
- <0xff 204>, /* rpm_ipc(24) */
- <0xff 205>, /* rpm_ipc(25) */
- <0xff 206>, /* rpm_ipc(26) */
- <0xff 207>, /* rpm_ipc(27) */
- <0xff 240>; /* summary_irq_kpss */
-
- qcom,gpio-parent = <&msmgpio>;
- qcom,gpio-map = <3 102>,
- <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>,
- <38 92>,
- <39 93>,
- <40 95>;
- };
-
- qcom,pm-8x60@fe805664 {
- compatible = "qcom,pm-8x60";
- reg = <0xfe805664 0x40>;
- qcom,pc-mode = <0>; /*MSM_PC_TZ_L2_INT */
- qcom,use-sync-timer;
- qcom,saw-turns-off-pll;
- };
-
- qcom,rpm-log@fc19dc00 {
- compatible = "qcom,rpm-log";
- reg = <0xfc19dc00 0x4000>;
- qcom,rpm-addr-phys = <0xfc000000>;
- qcom,offset-version = <4>;
- qcom,offset-page-buffer-addr = <36>;
- qcom,offset-log-len = <40>;
- qcom,offset-log-len-mask = <44>;
- qcom,offset-page-indices = <56>;
- };
-
- qcom,rpm-stats@0xfc19dbd0{
- compatible = "qcom,rpm-stats";
- reg = <0xfc19dbd0 0x1000>;
- reg-names = "phys_addr_base";
- qcom,sleep-stats-version = <2>;
- };
-};
diff --git a/arch/arm/boot/dts/msm8974-v2.dtsi b/arch/arm/boot/dts/msm8974-v2.dtsi
index a245d8a..f0b7f3f 100644
--- a/arch/arm/boot/dts/msm8974-v2.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2.dtsi
@@ -18,7 +18,6 @@
/include/ "msm8974.dtsi"
/include/ "msm8974-v2-iommu.dtsi"
-/include/ "msm8974-v2-pm.dtsi"
/ {
android_usb@fe8050c8 {
@@ -64,3 +63,50 @@
qcom,mdss-intf-off = <0x00012500 0x00012700
0x00012900 0x00012b00>;
};
+
+&msm_vidc {
+ qcom,vidc-ns-map = <0x40000000 0x40000000>;
+ qcom,load-freq-tbl = <979200 465000000>,
+ <783360 465000000>,
+ <489600 266670000>,
+ <244800 133330000>;
+ qcom,reg-presets = <0x80070 0x11FFF>,
+ <0x80074 0xA4>,
+ <0x800A8 0x1FFF>,
+ <0x80124 0x3>,
+ <0xE0020 0x5555556>,
+ <0xE0024 0x0>;
+ qcom,bus-ports = <1>;
+ qcom,enc-ocmem-ab-ib = <0 0>,
+ <138000 1034000>,
+ <414000 1034000>,
+ <940000 1034000>,
+ <1880000 2068000>,
+ <3008000 3309000>,
+ <3760000 4136000>,
+ <4468000 2457000>;
+ qcom,dec-ocmem-ab-ib = <0 0>,
+ <176000 519000>,
+ <456000 519000>,
+ <864000 519000>,
+ <1728000 1038000>,
+ <2766000 1661000>,
+ <3456000 2076000>,
+ <3662000 2198000>;
+ qcom,enc-ddr-ab-ib = <0 0>,
+ <60000 302000>,
+ <182000 302000>,
+ <402000 302000>,
+ <804000 604000>,
+ <1288000 967000>,
+ <2340000 1404000>,
+ <24940000 1496000>;
+ qcom,dec-ddr-ab-ib = <0 0>,
+ <104000 303000>,
+ <268000 303000>,
+ <506000 303000>,
+ <1012000 606000>,
+ <1620000 970000>,
+ <2024000 1212000>,
+ <2132000 1279000>;
+};
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 8138f20..68f1082 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -11,6 +11,7 @@
*/
/include/ "skeleton.dtsi"
+/include/ "msm8974-pm.dtsi"
/include/ "msm8974-camera.dtsi"
/include/ "msm8974-coresight.dtsi"
/include/ "msm-gdsc.dtsi"
@@ -70,65 +71,11 @@
reg = <0xfc4a3000 0x1000>;
};
- qcom,vidc@fdc00000 {
+ msm_vidc: qcom,vidc@fdc00000 {
compatible = "qcom,msm-vidc";
reg = <0xfdc00000 0xff000>;
interrupts = <0 44 0>;
- qcom,vidc-cp-map = <0x1000000 0x3f000000>;
- qcom,vidc-ns-map = <0x40000000 0x40000000>;
- qcom,load-freq-tbl = <979200 410000000>,
- <783360 410000000>,
- <489600 266670000>,
- <244800 133330000>;
qcom,hfi = "venus";
- qcom,reg-presets = <0x80004 0x1>,
- <0x80178 0x00001FFF>,
- <0x8017c 0x1FFF1FFF>,
- <0x800b0 0x10101001>,
- <0x800b4 0x10101010>,
- <0x800b8 0x10101010>,
- <0x800bc 0x00000010>,
- <0x800c0 0x1010100f>,
- <0x800c4 0x10101010>,
- <0x800c8 0x10101010>,
- <0x800cc 0x00000010>,
- <0x800d0 0x00001010>,
- <0x800d4 0x00001010>,
- <0x800f0 0x00000030>,
- <0x800d8 0x00000707>,
- <0x800dc 0x00000707>,
- <0x80124 0x00000001>,
- <0xE0020 0x5555556>,
- <0xE0024 0x0>;
- qcom,bus-ports = <1>;
- qcom,enc-ocmem-ab-ib = <0 0>,
- <138200 1222000>,
- <414700 1222000>,
- <940000 2444000>,
- <1880000 2444000>,
- <3008000 3910400>,
- <3760000 4888000>;
- qcom,dec-ocmem-ab-ib = <0 0>,
- <176900 1556640>,
- <456200 1556640>,
- <864800 1556640>,
- <1729600 3113280>,
- <2767360 4981248>,
- <3459200 6226560>;
- qcom,enc-ddr-ab-ib = <0 0>,
- <60000 664950>,
- <181000 664950>,
- <403000 664950>,
- <806000 1329900>,
- <1289600 2127840>,
- <161200 6400000>;
- qcom,dec-ddr-ab-ib = <0 0>,
- <110000 909000>,
- <268000 909000>,
- <505000 909000>,
- <1010000 1818000>,
- <1616000 2908800>,
- <2020000 6400000>;
};
qcom,wfd {
@@ -550,7 +497,7 @@
qcom,pmic-arb-channel = <0>;
};
- i2c@f9967000 { /* BLSP#11 */
+ i2c_0: i2c@f9967000 { /* BLSP#11 */
cell-index = <0>;
compatible = "qcom,i2c-qup";
reg = <0Xf9967000 0x1000>;
@@ -560,10 +507,10 @@
interrupts = <0 105 0>;
interrupt-names = "qup_err_intr";
qcom,i2c-bus-freq = <100000>;
- qcom,i2c-src-freq = <19200000>;
+ qcom,i2c-src-freq = <50000000>;
};
- i2c@f9924000 {
+ i2c_2: i2c@f9924000 {
cell-index = <2>;
compatible = "qcom,i2c-qup";
reg = <0xf9924000 0x1000>;
@@ -573,7 +520,7 @@
interrupts = <0 96 0>;
interrupt-names = "qup_err_intr";
qcom,i2c-bus-freq = <100000>;
- qcom,i2c-src-freq = <19200000>;
+ qcom,i2c-src-freq = <50000000>;
};
spi_0: spi@f9923000 {
@@ -1063,6 +1010,14 @@
reg-names = "crypto-base","crypto-bam-base";
interrupts = <0 236 0>;
qcom,bam-pipe-pair = <1>;
+ qcom,ce-hw-instance = <1>;
+ qcom,msm-bus,name = "qcedev-noc";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,active-only = <0>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <56 512 0 0>,
+ <56 512 3936000 393600>;
};
qcom,qcrypto@fd444000 {
@@ -1072,6 +1027,14 @@
reg-names = "crypto-base","crypto-bam-base";
interrupts = <0 236 0>;
qcom,bam-pipe-pair = <2>;
+ qcom,ce-hw-instance = <1>;
+ qcom,msm-bus,name = "qcrypto-noc";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,active-only = <0>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <56 512 0 0>,
+ <56 512 3936000 393600>;
};
qcom,usbbam@f9304000 {
@@ -1263,6 +1226,11 @@
qcom,bcl {
compatible = "qcom,bcl";
};
+
+ qcom,ssm {
+ compatible = "qcom,ssm";
+ qcom,channel-name = "SSM_RTR";
+ };
};
&gdsc_venus {
diff --git a/arch/arm/boot/dts/msm9625-coresight.dtsi b/arch/arm/boot/dts/msm9625-coresight.dtsi
index 7a5aa5c..0af8fa5 100644
--- a/arch/arm/boot/dts/msm9625-coresight.dtsi
+++ b/arch/arm/boot/dts/msm9625-coresight.dtsi
@@ -15,18 +15,21 @@
compatible = "arm,coresight-tmc";
reg = <0xfc322000 0x1000>,
<0xfc37c000 0x3000>;
+ reg-names = "tmc-etr-base", "tmc-etr-bam-base";
qcom,memory-reservation-type = "EBI1";
- qcom,memory-reservation-size = <0x100000>; /* 1M EBI1 buffer */
+ qcom,memory-reservation-size = <0x20000>; /* 128K EBI1 buffer */
coresight-id = <0>;
coresight-name = "coresight-tmc-etr";
coresight-nr-inports = <1>;
+ coresight-ctis = <&cti0 &cti8>;
};
tpiu: tpiu@fc318000 {
compatible = "arm,coresight-tpiu";
reg = <0xfc318000 0x1000>;
+ reg-names = "tpiu-base";
coresight-id = <1>;
coresight-name = "coresight-tpiu";
@@ -36,6 +39,7 @@
replicator: replicator@fc31c000 {
compatible = "qcom,coresight-replicator";
reg = <0xfc31c000 0x1000>;
+ reg-names = "replicator-base";
coresight-id = <2>;
coresight-name = "coresight-replicator";
@@ -48,6 +52,7 @@
tmc_etf: tmc@fc307000 {
compatible = "arm,coresight-tmc";
reg = <0xfc307000 0x1000>;
+ reg-names = "tmc-etf-base";
coresight-id = <3>;
coresight-name = "coresight-tmc-etf";
@@ -56,11 +61,13 @@
coresight-child-list = <&replicator>;
coresight-child-ports = <0>;
coresight-default-sink;
+ coresight-ctis = <&cti0 &cti8>;
};
funnel_merg: funnel@fc31b000 {
compatible = "arm,coresight-funnel";
reg = <0xfc31b000 0x1000>;
+ reg-names = "funnel-merg-base";
coresight-id = <4>;
coresight-name = "coresight-funnel-merg";
@@ -73,6 +80,7 @@
funnel_in0: funnel@fc319000 {
compatible = "arm,coresight-funnel";
reg = <0xfc319000 0x1000>;
+ reg-names = "funnel-in0-base";
coresight-id = <5>;
coresight-name = "coresight-funnel-in0";
@@ -85,6 +93,7 @@
funnel_in1: funnel@fc31a000 {
compatible = "arm,coresight-funnel";
reg = <0xfc31a000 0x1000>;
+ reg-names = "funnel-in1-base";
coresight-id = <6>;
coresight-name = "coresight-funnel-in1";
@@ -98,6 +107,7 @@
compatible = "arm,coresight-stm";
reg = <0xfc321000 0x1000>,
<0xfa280000 0x180000>;
+ reg-names = "stm-base", "stm-data-base";
coresight-id = <7>;
coresight-name = "coresight-stm";
@@ -110,6 +120,7 @@
etm: etm@fc332000 {
compatible = "arm,coresight-etm";
reg = <0xfc332000 0x1000>;
+ reg-names = "etm-base";
coresight-id = <8>;
coresight-name = "coresight-etm";
@@ -124,6 +135,7 @@
csr: csr@fc302000 {
compatible = "qcom,coresight-csr";
reg = <0xfc302000 0x1000>;
+ reg-names = "csr-base";
coresight-id = <9>;
coresight-name = "coresight-csr";
@@ -131,4 +143,104 @@
qcom,blk-size = <1>;
};
+
+ cti0: cti@fc308000 {
+ compatible = "arm,coresight-cti";
+ reg = <0xfc308000 0x1000>;
+ reg-names = "cti0-base";
+
+ coresight-id = <10>;
+ coresight-name = "coresight-cti0";
+ coresight-nr-inports = <0>;
+ };
+
+ cti1: cti@fc309000 {
+ compatible = "arm,coresight-cti";
+ reg = <0xfc309000 0x1000>;
+ reg-names = "cti1-base";
+
+ coresight-id = <11>;
+ coresight-name = "coresight-cti1";
+ coresight-nr-inports = <0>;
+ };
+
+ cti2: cti@fc30a000 {
+ compatible = "arm,coresight-cti";
+ reg = <0xfc30a000 0x1000>;
+ reg-names = "cti2-base";
+
+ coresight-id = <12>;
+ coresight-name = "coresight-cti2";
+ coresight-nr-inports = <0>;
+ };
+
+ cti3: cti@fc30b000 {
+ compatible = "arm,coresight-cti";
+ reg = <0xfc30b000 0x1000>;
+ reg-names = "cti3-base";
+
+ coresight-id = <13>;
+ coresight-name = "coresight-cti3";
+ coresight-nr-inports = <0>;
+ };
+
+ cti4: cti@fc30c000 {
+ compatible = "arm,coresight-cti";
+ reg = <0xfc30c000 0x1000>;
+ reg-names = "cti4-base";
+
+ coresight-id = <14>;
+ coresight-name = "coresight-cti4";
+ coresight-nr-inports = <0>;
+ };
+
+ cti5: cti@fc30d000 {
+ compatible = "arm,coresight-cti";
+ reg = <0xfc30d000 0x1000>;
+ reg-names = "cti5-base";
+
+ coresight-id = <15>;
+ coresight-name = "coresight-cti5";
+ coresight-nr-inports = <0>;
+ };
+
+ cti6: cti@fc30e000 {
+ compatible = "arm,coresight-cti";
+ reg = <0xfc30e000 0x1000>;
+ reg-names = "cti6-base";
+
+ coresight-id = <16>;
+ coresight-name = "coresight-cti6";
+ coresight-nr-inports = <0>;
+ };
+
+ cti7: cti@fc30f000 {
+ compatible = "arm,coresight-cti";
+ reg = <0xfc30f000 0x1000>;
+ reg-names = "cti7-base";
+
+ coresight-id = <17>;
+ coresight-name = "coresight-cti7";
+ coresight-nr-inports = <0>;
+ };
+
+ cti8: cti@fc310000 {
+ compatible = "arm,coresight-cti";
+ reg = <0xfc310000 0x1000>;
+ reg-names = "cti8-base";
+
+ coresight-id = <18>;
+ coresight-name = "coresight-cti8";
+ coresight-nr-inports = <0>;
+ };
+
+ cti_cpu: cti@fc333000 {
+ compatible = "arm,coresight-cti";
+ reg = <0xfc333000 0x1000>;
+ reg-names = "cti-cpu-base";
+
+ coresight-id = <19>;
+ coresight-name = "coresight-cti-cpu";
+ coresight-nr-inports = <0>;
+ };
};
diff --git a/arch/arm/boot/dts/msm9625-pm.dtsi b/arch/arm/boot/dts/msm9625-pm.dtsi
index a735609..1880965 100644
--- a/arch/arm/boot/dts/msm9625-pm.dtsi
+++ b/arch/arm/boot/dts/msm9625-pm.dtsi
@@ -265,6 +265,17 @@
qcom,use-sync-timer;
};
+ qcom,rpm-log@fc19dc00 {
+ compatible = "qcom,rpm-log";
+ reg = <0xfc19dc00 0x4000>;
+ qcom,rpm-addr-phys = <0xfc000000>;
+ qcom,offset-version = <4>;
+ qcom,offset-page-buffer-addr = <36>;
+ qcom,offset-log-len = <40>;
+ qcom,offset-log-len-mask = <44>;
+ qcom,offset-page-indices = <56>;
+ };
+
qcom,rpm-stats@fc19dbd0 {
compatible = "qcom,rpm-stats";
reg = <0xfc19dbd0 0x1000>;
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index 922616c..e9ca053 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -587,6 +587,28 @@
compatible = "qcom,msm-stub-codec";
};
+ qcom,msm-auxpcm {
+ compatible = "qcom,msm-auxpcm-resource";
+ qcom,msm-cpudai-auxpcm-clk = "pcm_clk";
+ qcom,msm-cpudai-auxpcm-mode = <0>, <0>;
+ qcom,msm-cpudai-auxpcm-sync = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-frame = <5>, <4>;
+ qcom,msm-cpudai-auxpcm-quant = <2>, <2>;
+ qcom,msm-cpudai-auxpcm-slot = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-data = <0>, <0>;
+ qcom,msm-cpudai-auxpcm-pcm-clk-rate = <2048000>, <2048000>;
+
+ qcom,msm-auxpcm-rx {
+ qcom,msm-auxpcm-dev-id = <4106>;
+ compatible = "qcom,msm-auxpcm-dev";
+ };
+
+ qcom,msm-auxpcm-tx {
+ qcom,msm-auxpcm-dev-id = <4107>;
+ compatible = "qcom,msm-auxpcm-dev";
+ };
+ };
+
qcom,msm-dai-mi2s {
compatible = "qcom,msm-dai-mi2s";
qcom,msm-dai-q6-mi2s-prim {
@@ -713,7 +735,7 @@
qcom,pre-div-channel-scaling = <0>;
qcom,calibration-type = "ratiometric";
qcom,scale-function = <0>;
- qcom,hw-settle-time = <0>;
+ qcom,hw-settle-time = <2>;
qcom,fast-avg-setup = <0>;
};
@@ -724,7 +746,7 @@
qcom,pre-div-channel-scaling = <0>;
qcom,calibration-type = "ratiometric";
qcom,scale-function = <2>;
- qcom,hw-settle-time = <0>;
+ qcom,hw-settle-time = <2>;
qcom,fast-avg-setup = <0>;
};
@@ -735,7 +757,7 @@
qcom,pre-div-channel-scaling = <0>;
qcom,calibration-type = "ratiometric";
qcom,scale-function = <2>;
- qcom,hw-settle-time = <0>;
+ qcom,hw-settle-time = <2>;
qcom,fast-avg-setup = <0>;
};
@@ -746,7 +768,7 @@
qcom,pre-div-channel-scaling = <0>;
qcom,calibration-type = "ratiometric";
qcom,scale-function = <4>;
- qcom,hw-settle-time = <0>;
+ qcom,hw-settle-time = <2>;
qcom,fast-avg-setup = <0>;
};
@@ -757,7 +779,7 @@
qcom,pre-div-channel-scaling = <0>;
qcom,calibration-type = "ratiometric";
qcom,scale-function = <4>;
- qcom,hw-settle-time = <0>;
+ qcom,hw-settle-time = <2>;
qcom,fast-avg-setup = <0>;
};
};
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index 2bf4630..bc0b939 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -77,6 +77,7 @@
CONFIG_VFP=y
CONFIG_NEON=y
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_WAKELOCK=y
CONFIG_PM_RUNTIME=y
CONFIG_NET=y
CONFIG_PACKET=y
@@ -141,11 +142,14 @@
CONFIG_WCD9306_CODEC=y
CONFIG_GPIO_QPNP_PIN=y
# CONFIG_HWMON is not set
+CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
+CONFIG_SENSORS_QPNP_ADC_CURRENT=y
CONFIG_REGULATOR=y
CONFIG_REGULATOR_STUB=y
CONFIG_REGULATOR_QPNP=y
CONFIG_ION=y
CONFIG_ION_MSM=y
+CONFIG_MSM_KGSL=y
CONFIG_FB=y
CONFIG_FB_VIRTUAL=y
CONFIG_SOUND=y
@@ -173,9 +177,13 @@
CONFIG_ANDROID_TIMED_GPIO=y
CONFIG_ANDROID_LOW_MEMORY_KILLER=y
CONFIG_MSM_IOMMU=y
+CONFIG_MSM_IOMMU_PMON=y
CONFIG_SPS=y
CONFIG_SPS_SUPPORT_NDP_BAM=y
CONFIG_MMC_MSM_SPS_SUPPORT=y
+CONFIG_RTC_CLASS=y
+# CONFIG_RTC_DRV_MSM is not set
+CONFIG_RTC_DRV_QPNP=y
CONFIG_EXT2_FS=y
CONFIG_EXT2_FS_XATTR=y
CONFIG_EXT3_FS=y
@@ -219,3 +227,4 @@
CONFIG_MSM_OCMEM_NONSECURE=y
CONFIG_THERMAL=y
CONFIG_THERMAL_TSENS8974=y
+CONFIG_THERMAL_MONITOR=y
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index 053e1ca..7362ea0 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -134,6 +134,8 @@
CONFIG_IP_PNP_DHCP=y
CONFIG_INET_AH=y
CONFIG_INET_ESP=y
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
# CONFIG_INET_LRO is not set
CONFIG_IPV6=y
CONFIG_IPV6_PRIVACY=y
@@ -522,6 +524,7 @@
CONFIG_CRYPTO_TEST=m
CONFIG_CRYPTO_CTR=y
CONFIG_CRYPTO_CTS=y
+CONFIG_CRYPTO_XCBC=y
CONFIG_CRYPTO_TWOFISH=y
CONFIG_CRYPTO_DEV_QCRYPTO=m
CONFIG_CRYPTO_DEV_QCE=m
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index 7b54eb4..bb34075 100644
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -139,6 +139,8 @@
CONFIG_IP_PNP_DHCP=y
CONFIG_INET_AH=y
CONFIG_INET_ESP=y
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
# CONFIG_INET_LRO is not set
CONFIG_IPV6=y
CONFIG_IPV6_PRIVACY=y
@@ -539,6 +541,7 @@
CONFIG_CRYPTO_TEST=m
CONFIG_CRYPTO_CTR=y
CONFIG_CRYPTO_CTS=y
+CONFIG_CRYPTO_XCBC=y
CONFIG_CRYPTO_TWOFISH=y
CONFIG_CRYPTO_DEV_QCRYPTO=m
CONFIG_CRYPTO_DEV_QCE=m
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index 70e72e8..952171c 100644
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -35,6 +35,8 @@
CONFIG_MODVERSIONS=y
CONFIG_PARTITION_ADVANCED=y
CONFIG_EFI_PARTITION=y
+CONFIG_IOSCHED_TEST=y
+CONFIG_DEFAULT_ROW=y
CONFIG_ARCH_MSM=y
CONFIG_ARCH_MSM8974=y
CONFIG_MSM_KRAIT_TBB_ABORT_HANDLER=y
@@ -106,14 +108,17 @@
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
+CONFIG_XFRM_USER=y
CONFIG_INET=y
CONFIG_IP_ADVANCED_ROUTER=y
CONFIG_IP_MULTIPLE_TABLES=y
CONFIG_IP_ROUTE_VERBOSE=y
CONFIG_IP_PNP=y
CONFIG_IP_PNP_DHCP=y
-# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+CONFIG_INET_AH=y
+CONFIG_INET_ESP=y
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
# CONFIG_INET_XFRM_MODE_BEET is not set
# CONFIG_INET_LRO is not set
CONFIG_IPV6=y
@@ -223,11 +228,12 @@
CONFIG_BT_HCISMD=y
CONFIG_MSM_BT_POWER=y
CONFIG_CFG80211=y
-CONFIG_CFG80211_DEFAULT_PS=y
CONFIG_NL80211_TESTMODE=y
CONFIG_RFKILL=y
CONFIG_GENLOCK=y
CONFIG_GENLOCK_MISCDEVICE=y
+CONFIG_SYNC=y
+CONFIG_SW_SYNC=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_RAM=y
CONFIG_HAPTIC_ISA1200=y
@@ -311,25 +317,24 @@
CONFIG_MEDIA_CONTROLLER=y
CONFIG_VIDEO_DEV=y
CONFIG_VIDEO_V4L2_SUBDEV_API=y
-CONFIG_VIDEOBUF2_MSM_MEM=y
-CONFIG_USB_VIDEO_CLASS=y
-CONFIG_V4L_PLATFORM_DRIVERS=y
-CONFIG_MSM_CAMERA=n
+# CONFIG_MSM_CAMERA is not set
CONFIG_MT9M114=y
-CONFIG_MSMB_CAMERA=y
-CONFIG_MSM_VIDC_V4L2=y
CONFIG_OV2720=y
-CONFIG_MSMB_JPEG=y
CONFIG_MSM_CAMERA_SENSOR=y
-CONFIG_MSM_JPEG=y
CONFIG_MSM_CCI=y
+CONFIG_MSM_CPP=y
CONFIG_MSM_CSI30_HEADER=y
CONFIG_MSM_CSIPHY=y
CONFIG_MSM_CSID=y
-CONFIG_MSM_CSI2_REGISTER=y
CONFIG_MSM_ISPIF=y
CONFIG_S5K3L1YX=y
+CONFIG_MSMB_CAMERA=y
+CONFIG_MSMB_JPEG=y
+CONFIG_MSM_VIDC_V4L2=y
CONFIG_MSM_WFD=y
+CONFIG_VIDEOBUF2_MSM_MEM=y
+CONFIG_USB_VIDEO_CLASS=y
+CONFIG_V4L_PLATFORM_DRIVERS=y
CONFIG_RADIO_IRIS=y
CONFIG_RADIO_IRIS_TRANSPORT=m
CONFIG_ION=y
@@ -351,10 +356,13 @@
CONFIG_SND_USB_AUDIO=y
CONFIG_SND_SOC=y
CONFIG_SND_SOC_MSM8974=y
+CONFIG_UHID=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_MAGICMOUSE=y
+CONFIG_HID_MICROSOFT=y
CONFIG_USB_SUSPEND=y
CONFIG_USB_XHCI_HCD=y
CONFIG_USB_EHCI_HCD=y
-CONFIG_USB_EHCI_ROOT_HUB_TT=y
CONFIG_USB_EHCI_EHSET=y
CONFIG_USB_EHCI_MSM=y
CONFIG_USB_EHCI_MSM_HSIC=y
@@ -385,12 +393,11 @@
CONFIG_MMC_BLOCK_MINORS=32
# CONFIG_MMC_BLOCK_BOUNCE is not set
CONFIG_MMC_TEST=m
+CONFIG_MMC_BLOCK_TEST=y
CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_PLTFM=y
CONFIG_MMC_MSM=y
CONFIG_MMC_MSM_SPS_SUPPORT=y
-CONFIG_IOSCHED_TEST=y
-CONFIG_MMC_BLOCK_TEST=y
CONFIG_LEDS_QPNP=y
CONFIG_LEDS_TRIGGERS=y
CONFIG_LEDS_TRIGGER_BACKLIGHT=y
@@ -414,6 +421,8 @@
CONFIG_QPNP_POWER_ON=y
CONFIG_QPNP_CLKDIV=y
CONFIG_MSM_IOMMU=y
+CONFIG_MOBICORE_SUPPORT=m
+CONFIG_MOBICORE_API=m
CONFIG_CORESIGHT=y
CONFIG_CORESIGHT_TMC=y
CONFIG_CORESIGHT_TPIU=y
@@ -446,15 +455,12 @@
CONFIG_DEBUG_USER=y
CONFIG_PID_IN_CONTEXTIDR=y
CONFIG_KEYS=y
+CONFIG_CRYPTO_NULL=y
CONFIG_CRYPTO_MD4=y
CONFIG_CRYPTO_ARC4=y
+CONFIG_CRYPTO_XCBC=y
CONFIG_CRYPTO_TWOFISH=y
CONFIG_CRYPTO_DEV_QCRYPTO=m
CONFIG_CRYPTO_DEV_QCE=m
CONFIG_CRYPTO_DEV_QCEDEV=m
CONFIG_CRC_CCITT=y
-CONFIG_SYNC=y
-CONFIG_SW_SYNC=y
-CONFIG_MOBICORE_SUPPORT=m
-CONFIG_MOBICORE_API=m
-CONFIG_DEFAULT_ROW=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index cd2593a..a3a4487 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -112,14 +112,17 @@
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
+CONFIG_XFRM_USER=y
CONFIG_INET=y
CONFIG_IP_ADVANCED_ROUTER=y
CONFIG_IP_MULTIPLE_TABLES=y
CONFIG_IP_ROUTE_VERBOSE=y
CONFIG_IP_PNP=y
CONFIG_IP_PNP_DHCP=y
-# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+CONFIG_INET_AH=y
+CONFIG_INET_ESP=y
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
# CONFIG_INET_XFRM_MODE_BEET is not set
# CONFIG_INET_LRO is not set
CONFIG_IPV6=y
@@ -325,6 +328,7 @@
CONFIG_OV2720=y
CONFIG_MSM_CAMERA_SENSOR=y
CONFIG_MSM_CCI=y
+CONFIG_MSM_CPP=y
CONFIG_MSM_CSI30_HEADER=y
CONFIG_MSM_CSIPHY=y
CONFIG_MSM_CSID=y
@@ -360,6 +364,10 @@
CONFIG_SND_USB_AUDIO=y
CONFIG_SND_SOC=y
CONFIG_SND_SOC_MSM8974=y
+CONFIG_UHID=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_MAGICMOUSE=y
+CONFIG_HID_MICROSOFT=y
CONFIG_USB_SUSPEND=y
CONFIG_USB_XHCI_HCD=y
CONFIG_USB_EHCI_HCD=y
@@ -467,10 +475,14 @@
CONFIG_CPU_FREQ_SWITCH_PROFILER=y
CONFIG_DYNAMIC_DEBUG=y
CONFIG_DEBUG_USER=y
+CONFIG_DEBUG_LL=y
+CONFIG_EARLY_PRINTK=y
CONFIG_PID_IN_CONTEXTIDR=y
CONFIG_KEYS=y
+CONFIG_CRYPTO_NULL=y
CONFIG_CRYPTO_MD4=y
CONFIG_CRYPTO_ARC4=y
+CONFIG_CRYPTO_XCBC=y
CONFIG_CRYPTO_TWOFISH=y
CONFIG_CRYPTO_DEV_QCRYPTO=m
CONFIG_CRYPTO_DEV_QCE=m
diff --git a/arch/arm/configs/msm9625_defconfig b/arch/arm/configs/msm9625_defconfig
index 0f93930..9a1f872 100644
--- a/arch/arm/configs/msm9625_defconfig
+++ b/arch/arm/configs/msm9625_defconfig
@@ -247,6 +247,7 @@
CONFIG_SPS_SUPPORT_NDP_BAM=y
CONFIG_QPNP_POWER_ON=y
CONFIG_IPA=y
+CONFIG_ECM_IPA=y
CONFIG_CORESIGHT=y
CONFIG_CORESIGHT_TMC=y
CONFIG_CORESIGHT_TPIU=y
@@ -321,3 +322,4 @@
CONFIG_SCSI_LOGGING=y
CONFIG_SCSI_SCAN_ASYNC=y
CONFIG_MSM_RTB=y
+CONFIG_MSM_MEMORY_DUMP=y
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index 8fb93d0..5311d74 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/arch/arm/kernel/perf_event.c
@@ -739,15 +739,14 @@
armpmu->type = ARM_PMU_DEVICE_CPU;
}
-static int cpu_has_active_perf(void)
+static int cpu_has_active_perf(int cpu)
{
struct pmu_hw_events *hw_events;
int enabled;
if (!cpu_pmu)
return 0;
-
- hw_events = cpu_pmu->get_hw_events();
+ hw_events = &per_cpu(cpu_hw_events, cpu);
enabled = bitmap_weight(hw_events->used_mask, cpu_pmu->num_events);
if (enabled)
@@ -780,7 +779,7 @@
{
int irq;
- if (cpu_has_active_perf()) {
+ if (cpu_has_active_perf((int)hcpu)) {
switch ((action & ~CPU_TASKS_FROZEN)) {
case CPU_DOWN_PREPARE:
@@ -855,7 +854,7 @@
{
switch (cmd) {
case CPU_PM_ENTER:
- if (cpu_has_active_perf()) {
+ if (cpu_has_active_perf((int)v)) {
armpmu_update_counters();
perf_pmu_disable(&cpu_pmu->pmu);
}
@@ -863,7 +862,7 @@
case CPU_PM_ENTER_FAILED:
case CPU_PM_EXIT:
- if (cpu_has_active_perf() && cpu_pmu->reset) {
+ if (cpu_has_active_perf((int)v) && cpu_pmu->reset) {
/*
* Flip this bit so armpmu_enable knows it needs
* to re-enable active counters.
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 5694a2e..32e9391 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -380,6 +380,7 @@
select CPU_HAS_L2_PMU
select MSM_JTAG_MM if CORESIGHT_ETM
select MEMORY_HOLE_CARVEOUT
+ select MSM_RPM_LOG
config ARCH_MSM8610
bool "MSM8610"
@@ -410,6 +411,7 @@
select CPU_FREQ_GOV_USERSPACE
select CPU_FREQ_GOV_ONDEMAND
select MSM_PIL
+ select MSM_RUN_QUEUE_STATS
config ARCH_MSM8226
bool "MSM8226"
@@ -435,6 +437,7 @@
select MSM_PM8X60 if PM
select MEMORY_HOLE_CARVEOUT
select DONT_MAP_HOLE_AFTER_MEMBANK0
+ select MSM_BUS_SCALING
endmenu
choice
diff --git a/arch/arm/mach-msm/acpuclock-8974.c b/arch/arm/mach-msm/acpuclock-8974.c
index d8f5425..5211c6e 100644
--- a/arch/arm/mach-msm/acpuclock-8974.c
+++ b/arch/arm/mach-msm/acpuclock-8974.c
@@ -266,11 +266,17 @@
[0][2] = { acpu_freq_tbl_pvs2, sizeof(acpu_freq_tbl_pvs2) },
[0][3] = { acpu_freq_tbl_pvs3, sizeof(acpu_freq_tbl_pvs3) },
[0][4] = { acpu_freq_tbl_pvs4, sizeof(acpu_freq_tbl_pvs4) },
+ [0][5] = { acpu_freq_tbl_pvs4, sizeof(acpu_freq_tbl_pvs4) },
+ [0][6] = { acpu_freq_tbl_pvs4, sizeof(acpu_freq_tbl_pvs4) },
+ [0][7] = { acpu_freq_tbl_pvs4, sizeof(acpu_freq_tbl_pvs4) },
[1][0] = { acpu_freq_tbl_pvs0, sizeof(acpu_freq_tbl_pvs0) },
[1][1] = { acpu_freq_tbl_pvs1, sizeof(acpu_freq_tbl_pvs1) },
[1][2] = { acpu_freq_tbl_pvs2, sizeof(acpu_freq_tbl_pvs2) },
[1][3] = { acpu_freq_tbl_pvs3, sizeof(acpu_freq_tbl_pvs3) },
[1][4] = { acpu_freq_tbl_pvs4, sizeof(acpu_freq_tbl_pvs4) },
+ [1][5] = { acpu_freq_tbl_pvs4, sizeof(acpu_freq_tbl_pvs4) },
+ [1][6] = { acpu_freq_tbl_pvs4, sizeof(acpu_freq_tbl_pvs4) },
+ [1][7] = { acpu_freq_tbl_pvs4, sizeof(acpu_freq_tbl_pvs4) },
};
static struct acpuclk_krait_params acpuclk_8974_params __initdata = {
diff --git a/arch/arm/mach-msm/acpuclock-cortex.c b/arch/arm/mach-msm/acpuclock-cortex.c
index 64e31ba..4ac1408 100644
--- a/arch/arm/mach-msm/acpuclock-cortex.c
+++ b/arch/arm/mach-msm/acpuclock-cortex.c
@@ -324,9 +324,9 @@
}
/* Improve boot time by ramping up CPU immediately */
- for (i = 0; acpuclk_init_data->freq_tbl[i].khz != 0 &&
- acpuclk_init_data->freq_tbl[i].use_for_scaling; i++)
- max_cpu_khz = acpuclk_init_data->freq_tbl[i].khz;
+ for (i = 0; acpuclk_init_data->freq_tbl[i].khz != 0; i++)
+ if (acpuclk_init_data->freq_tbl[i].use_for_scaling)
+ max_cpu_khz = acpuclk_init_data->freq_tbl[i].khz;
/* Initialize regulators */
rc = increase_vdd(acpuclk_init_data->freq_tbl[i].vdd_cpu,
@@ -346,6 +346,12 @@
goto err_vdd_cpu;
}
+ /*
+ * Select a state which is always a valid transition to align SW with
+ * the HW configuration set by the bootloaders.
+ */
+ acpuclk_cortex_set_rate(0, acpuclk_cortex_data.power_collapse_khz,
+ SETRATE_INIT);
acpuclk_cortex_set_rate(0, max_cpu_khz, SETRATE_INIT);
acpuclk_register(&acpuclk_cortex_data);
diff --git a/arch/arm/mach-msm/acpuclock-krait.h b/arch/arm/mach-msm/acpuclock-krait.h
index 00f64fc..11d58dd 100644
--- a/arch/arm/mach-msm/acpuclock-krait.h
+++ b/arch/arm/mach-msm/acpuclock-krait.h
@@ -50,7 +50,7 @@
PVS_NOMINAL = 1,
PVS_FAST = 3,
PVS_FASTER = 4,
- NUM_PVS = 7
+ NUM_PVS = 8
};
/**
diff --git a/arch/arm/mach-msm/bam_dmux.c b/arch/arm/mach-msm/bam_dmux.c
index cf2f464..7c2c463 100644
--- a/arch/arm/mach-msm/bam_dmux.c
+++ b/arch/arm/mach-msm/bam_dmux.c
@@ -1914,14 +1914,15 @@
* processing. We do not wat to access the bam hardware during SSR
* because a watchdog crash from a bus stall would likely occur.
*/
- if (code == SUBSYS_BEFORE_SHUTDOWN)
+ if (code == SUBSYS_BEFORE_SHUTDOWN) {
+ in_global_reset = 1;
in_ssr = 1;
+ bam_dmux_log("%s: begin\n", __func__);
+ flush_workqueue(bam_mux_rx_workqueue);
+ }
if (code != SUBSYS_AFTER_SHUTDOWN)
return NOTIFY_DONE;
- bam_dmux_log("%s: begin\n", __func__);
- in_global_reset = 1;
-
/* Handle uplink Powerdown */
write_lock_irqsave(&ul_wakeup_lock, flags);
if (bam_is_connected) {
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index beb064b..9ed71da 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -2887,6 +2887,7 @@
#ifdef CONFIG_MSM_ROTATOR
&msm_rotator_device,
#endif
+ &msm8064_cpu_slp_status,
};
static struct platform_device
diff --git a/arch/arm/mach-msm/board-8226-gpiomux.c b/arch/arm/mach-msm/board-8226-gpiomux.c
index e58cee7..8be5525 100644
--- a/arch/arm/mach-msm/board-8226-gpiomux.c
+++ b/arch/arm/mach-msm/board-8226-gpiomux.c
@@ -42,6 +42,12 @@
.pull = GPIOMUX_PULL_NONE,
};
+static struct gpiomux_setting gpio_spi_cs_config = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_6MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
static struct gpiomux_setting gpio_i2c_config = {
.func = GPIOMUX_FUNC_3,
.drv = GPIOMUX_DRV_2MA,
@@ -50,37 +56,37 @@
static struct msm_gpiomux_config msm_blsp_configs[] __initdata = {
{
- .gpio = 0, /* BLSP1 QUP2 SPI_DATA_MOSI */
+ .gpio = 0, /* BLSP1 QUP1 SPI_DATA_MOSI */
.settings = {
[GPIOMUX_SUSPENDED] = &gpio_spi_config,
},
},
{
- .gpio = 1, /* BLSP1 QUP2 SPI_DATA_MISO */
+ .gpio = 1, /* BLSP1 QUP1 SPI_DATA_MISO */
.settings = {
[GPIOMUX_SUSPENDED] = &gpio_spi_config,
},
},
{
- .gpio = 2, /* BLSP1 QUP2 SPI_CS_N */
+ .gpio = 2, /* BLSP1 QUP1 SPI_CS1 */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_spi_cs_config,
+ },
+ },
+ {
+ .gpio = 3, /* BLSP1 QUP1 SPI_CLK */
.settings = {
[GPIOMUX_SUSPENDED] = &gpio_spi_config,
},
},
{
- .gpio = 3, /* BLSP1 QUP2 SPI_CLK */
- .settings = {
- [GPIOMUX_SUSPENDED] = &gpio_spi_config,
- },
- },
- {
- .gpio = 14, /* BLSP-1 QUP-4 I2C_SDA */
+ .gpio = 14, /* BLSP1 QUP4 I2C_SDA */
.settings = {
[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
},
},
{
- .gpio = 15, /* BLSP-1 QUP-4 I2C_SCL */
+ .gpio = 15, /* BLSP1 QUP4 I2C_SCL */
.settings = {
[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
},
diff --git a/arch/arm/mach-msm/board-8610-gpiomux.c b/arch/arm/mach-msm/board-8610-gpiomux.c
index 5b3d30c..15d7679 100644
--- a/arch/arm/mach-msm/board-8610-gpiomux.c
+++ b/arch/arm/mach-msm/board-8610-gpiomux.c
@@ -23,19 +23,55 @@
.pull = GPIOMUX_PULL_NONE,
};
+static struct gpiomux_setting gpio_spi_config = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_6MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting gpio_spi_cs_config = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_6MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
static struct msm_gpiomux_config msm_blsp_configs[] __initdata = {
{
- .gpio = 10, /* BLSP-1 QUP-3 I2C_SDA */
+ .gpio = 10, /* BLSP1 QUP3 I2C_SDA */
.settings = {
[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
},
},
{
- .gpio = 11, /* BLSP-1 QUP-3 I2C_SCL */
+ .gpio = 11, /* BLSP1 QUP3 I2C_SCL */
.settings = {
[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
},
},
+ {
+ .gpio = 0, /* BLSP1 QUP1 SPI_DATA_MOSI */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_spi_config,
+ },
+ },
+ {
+ .gpio = 1, /* BLSP1 QUP1 SPI_DATA_MISO */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_spi_config,
+ },
+ },
+ {
+ .gpio = 3, /* BLSP1 QUP1 SPI_CLK */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_spi_config,
+ },
+ },
+ {
+ .gpio = 2, /* BLSP1 QUP1 SPI_CS1 */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_spi_cs_config,
+ },
+ },
};
void __init msm8610_init_gpiomux(void)
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index 25ba1aa..fbcc6f1 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -2473,6 +2473,7 @@
&msm8930_iommu_domain_device,
&msm_tsens_device,
&msm8930_cache_dump_device,
+ &msm8930_cpu_slp_status,
};
static struct platform_device *cdp_devices[] __initdata = {
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index 95f618a..819ccc5 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -2955,6 +2955,7 @@
&msm8960_cache_dump_device,
&msm8960_iommu_domain_device,
&msm_tsens_device,
+ &msm8960_cpu_slp_status,
};
static struct platform_device *cdp_devices[] __initdata = {
diff --git a/arch/arm/mach-msm/board-8974-gpiomux.c b/arch/arm/mach-msm/board-8974-gpiomux.c
index b3cc9b7..5240f38 100644
--- a/arch/arm/mach-msm/board-8974-gpiomux.c
+++ b/arch/arm/mach-msm/board-8974-gpiomux.c
@@ -115,6 +115,7 @@
.func = GPIOMUX_FUNC_GPIO,
.drv = GPIOMUX_DRV_8MA,
.pull = GPIOMUX_PULL_NONE,
+ .dir = GPIOMUX_OUT_HIGH,
};
static struct gpiomux_setting lcd_en_sus_cfg = {
@@ -385,6 +386,16 @@
},
};
+static struct msm_gpiomux_config msm_lcd_configs[] __initdata = {
+ {
+ .gpio = 58,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &lcd_en_act_cfg,
+ [GPIOMUX_SUSPENDED] = &lcd_en_sus_cfg,
+ },
+ },
+};
+
static struct msm_gpiomux_config msm_blsp_configs[] __initdata = {
#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
{
@@ -419,13 +430,6 @@
},
#endif
{
- .gpio = 58,
- .settings = {
- [GPIOMUX_ACTIVE] = &lcd_en_act_cfg,
- [GPIOMUX_SUSPENDED] = &lcd_en_sus_cfg,
- },
- },
- {
.gpio = 6, /* BLSP1 QUP2 I2C_DAT */
.settings = {
[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
@@ -1008,6 +1012,9 @@
msm_gpiomux_install(msm8974_pri_auxpcm_configs,
ARRAY_SIZE(msm8974_pri_auxpcm_configs));
+ msm_gpiomux_install_nowrite(msm_lcd_configs,
+ ARRAY_SIZE(msm_lcd_configs));
+
if (machine_is_msm8974_rumi())
msm_gpiomux_install(msm_rumi_blsp_configs,
ARRAY_SIZE(msm_rumi_blsp_configs));
diff --git a/arch/arm/mach-msm/board-8974.c b/arch/arm/mach-msm/board-8974.c
index cc73330..1de83a7 100644
--- a/arch/arm/mach-msm/board-8974.c
+++ b/arch/arm/mach-msm/board-8974.c
@@ -142,34 +142,6 @@
"msm_sdcc.3", NULL),
OF_DEV_AUXDATA("qcom,msm-sdcc", 0xF98E4000, \
"msm_sdcc.4", NULL),
- OF_DEV_AUXDATA("arm,coresight-tmc", 0xFC322000, \
- "coresight-tmc-etr", NULL),
- OF_DEV_AUXDATA("arm,coresight-tpiu", 0xFC318000, \
- "coresight-tpiu", NULL),
- OF_DEV_AUXDATA("qcom,coresight-replicator", 0xFC31C000, \
- "coresight-replicator", NULL),
- OF_DEV_AUXDATA("arm,coresight-tmc", 0xFC307000, \
- "coresight-tmc-etf", NULL),
- OF_DEV_AUXDATA("arm,coresight-funnel", 0xFC31B000, \
- "coresight-funnel-merg", NULL),
- OF_DEV_AUXDATA("arm,coresight-funnel", 0xFC319000, \
- "coresight-funnel-in0", NULL),
- OF_DEV_AUXDATA("arm,coresight-funnel", 0xFC31A000, \
- "coresight-funnel-in1", NULL),
- OF_DEV_AUXDATA("arm,coresight-funnel", 0xFC345000, \
- "coresight-funnel-kpss", NULL),
- OF_DEV_AUXDATA("arm,coresight-funnel", 0xFC364000, \
- "coresight-funnel-mmss", NULL),
- OF_DEV_AUXDATA("arm,coresight-stm", 0xFC321000, \
- "coresight-stm", NULL),
- OF_DEV_AUXDATA("arm,coresight-etm", 0xFC33C000, \
- "coresight-etm0", NULL),
- OF_DEV_AUXDATA("arm,coresight-etm", 0xFC33D000, \
- "coresight-etm1", NULL),
- OF_DEV_AUXDATA("arm,coresight-etm", 0xFC33E000, \
- "coresight-etm2", NULL),
- OF_DEV_AUXDATA("arm,coresight-etm", 0xFC33F000, \
- "coresight-etm3", NULL),
OF_DEV_AUXDATA("qcom,msm-rng", 0xF9BFF000, \
"msm_rng", NULL),
OF_DEV_AUXDATA("qcom,qseecom", 0xFE806000, \
diff --git a/arch/arm/mach-msm/clock-8226.c b/arch/arm/mach-msm/clock-8226.c
index f65b595..11ad9d9 100644
--- a/arch/arm/mach-msm/clock-8226.c
+++ b/arch/arm/mach-msm/clock-8226.c
@@ -330,7 +330,6 @@
#define OXILI_GFX3D_CBCR (0x4028)
#define OXILICX_AXI_CBCR (0x4038)
#define OXILICX_AHB_CBCR (0x403C)
-#define OCMEMCX_AHB_CBCR (0x405C)
#define MMPLL2_PLL_MODE (0x4100)
#define MMPLL2_PLL_STATUS (0x411C)
#define MMSS_MMSSNOC_AHB_CBCR (0x5024)
@@ -442,50 +441,9 @@
#define GP2_CMD_RCGR (0x1944)
#define GP3_CBCR (0x1980)
#define GP3_CMD_RCGR (0x1984)
-#define LPAAUDIO_PLL_MODE (0x0000)
-#define LPAAUDIO_PLL_L (0x0004)
-#define LPAAUDIO_PLL_M (0x0008)
-#define LPAAUDIO_PLL_N (0x000C)
-#define LPAAUDIO_PLL_USER_CTL (0x0010)
-#define LPAAUDIO_PLL_STATUS (0x001C)
-#define LPA_PLL_VOTE_APPS (0x2000)
#define Q6SS_BCR (0x6000)
-#define AUDIO_CORE_GDSCR (0x7000)
-#define LPAIF_SPKR_CMD_RCGR (0xA000)
-#define AUDIO_CORE_LPAIF_CODEC_SPKR_OSR_CBCR (0xA014)
-#define AUDIO_CORE_LPAIF_CODEC_SPKR_IBIT_CBCR (0xA018)
-#define AUDIO_CORE_LPAIF_CODEC_SPKR_EBIT_CBCR (0xA01C)
-#define LPAIF_PRI_CMD_RCGR (0xB000)
-#define AUDIO_CORE_LPAIF_PRI_OSR_CBCR (0xB014)
-#define AUDIO_CORE_LPAIF_PRI_IBIT_CBCR (0xB018)
-#define AUDIO_CORE_LPAIF_PRI_EBIT_CBCR (0xB01C)
-#define LPAIF_SEC_CMD_RCGR (0xC000)
-#define AUDIO_CORE_LPAIF_SEC_OSR_CBCR (0xC014)
-#define AUDIO_CORE_LPAIF_SEC_IBIT_CBCR (0xC018)
-#define AUDIO_CORE_LPAIF_SEC_EBIT_CBCR (0xC01C)
-#define LPAIF_TER_CMD_RCGR (0xD000)
-#define AUDIO_CORE_LPAIF_TER_OSR_CBCR (0xD014)
-#define AUDIO_CORE_LPAIF_TER_IBIT_CBCR (0xD018)
-#define AUDIO_CORE_LPAIF_TER_EBIT_CBCR (0xD01C)
-#define LPAIF_QUAD_CMD_RCGR (0xE000)
-#define AUDIO_CORE_LPAIF_QUAD_OSR_CBCR (0xE014)
-#define AUDIO_CORE_LPAIF_QUAD_IBIT_CBCR (0xE018)
-#define AUDIO_CORE_LPAIF_QUAD_EBIT_CBCR (0xE01C)
-#define LPAIF_PCM0_CMD_RCGR (0xF000)
-#define AUDIO_CORE_LPAIF_PCM0_IBIT_CBCR (0xF014)
-#define AUDIO_CORE_LPAIF_PCM0_EBIT_CBCR (0xF018)
-#define LPAIF_PCM1_CMD_RCGR (0x10000)
-#define AUDIO_CORE_LPAIF_PCM1_IBIT_CBCR (0x10014)
-#define AUDIO_CORE_LPAIF_PCM1_EBIT_CBCR (0x10018)
-#define SLIMBUS_CMD_RCGR (0x12000)
-#define AUDIO_CORE_SLIMBUS_CORE_CBCR (0x12014)
-#define AUDIO_CORE_SLIMBUS_LFABIF_CBCR (0x12018)
-#define LPAIF_PCMOE_CMD_RCGR (0x13000)
-#define AUDIO_CORE_LPAIF_PCM_DATA_OE_CBCR (0x13014)
-#define AUDIO_CORE_IXFABRIC_CBCR (0x1B000)
#define Q6SS_AHB_LFABIF_CBCR (0x22000)
#define Q6SS_AHBM_CBCR (0x22004)
-#define AUDIO_WRAPPER_BR_CBCR (0x24000)
#define Q6SS_XO_CBCR (0x26000)
static unsigned int soft_vote_gpll0;
@@ -540,7 +498,8 @@
};
static struct clk_freq_tbl ftbl_gcc_blsp1_qup1_6_i2c_apps_clk[] = {
- F_GCC( 19200000, xo, 0, 0, 0),
+ F_GCC( 19200000, xo, 1, 0, 0),
+ F_GCC( 50000000, gpll0, 12, 0, 0),
F_END
};
@@ -1733,7 +1692,7 @@
.dbg_name = "axi_clk_src",
.ops = &clk_ops_rcg,
VDD_DIG_FMAX_MAP3(LOW, 100000000, NOMINAL, 200000000, HIGH,
- 266670000),
+ 266670000),
CLK_INIT(axi_clk_src.c),
},
};
@@ -1810,7 +1769,7 @@
.dbg_name = "vfe0_clk_src",
.ops = &clk_ops_rcg,
VDD_DIG_FMAX_MAP3(LOW, 133330000, NOMINAL, 266670000, HIGH,
- 320000000),
+ 320000000),
CLK_INIT(vfe0_clk_src.c),
},
};
@@ -1837,7 +1796,7 @@
.dbg_name = "mdp_clk_src",
.ops = &clk_ops_rcg,
VDD_DIG_FMAX_MAP3(LOW, 92310000, NOMINAL, 177780000, HIGH,
- 200000000),
+ 200000000),
CLK_INIT(mdp_clk_src.c),
},
};
@@ -1862,7 +1821,7 @@
.dbg_name = "jpeg0_clk_src",
.ops = &clk_ops_rcg,
VDD_DIG_FMAX_MAP3(LOW, 133330000, NOMINAL, 266670000, HIGH,
- 320000000),
+ 320000000),
CLK_INIT(jpeg0_clk_src.c),
},
};
@@ -1891,6 +1850,7 @@
F_MMSS( 66700000, gpll0, 9, 0, 0),
F_MMSS( 100000000, gpll0, 6, 0, 0),
F_MMSS( 133330000, mmpll0_pll, 6, 0, 0),
+ F_MMSS( 160000000, mmpll0_pll, 5, 0, 0),
F_END
};
@@ -1904,7 +1864,7 @@
.dbg_name = "vcodec0_clk_src",
.ops = &clk_ops_rcg_mnd,
VDD_DIG_FMAX_MAP3(LOW, 66670000, NOMINAL, 133330000, HIGH,
- 160000000),
+ 160000000),
CLK_INIT(vcodec0_clk_src.c),
},
};
@@ -2050,7 +2010,7 @@
.dbg_name = "cpp_clk_src",
.ops = &clk_ops_rcg,
VDD_DIG_FMAX_MAP3(LOW, 133330000, NOMINAL, 266670000, HIGH,
- 320000000),
+ 320000000),
CLK_INIT(cpp_clk_src.c),
},
};
@@ -2618,17 +2578,6 @@
},
};
-static struct branch_clk ocmemcx_ahb_clk = {
- .cbcr_reg = OCMEMCX_AHB_CBCR,
- .has_sibling = 1,
- .base = &virt_bases[MMSS_BASE],
- .c = {
- .dbg_name = "ocmemcx_ahb_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(ocmemcx_ahb_clk.c),
- },
-};
-
static struct branch_clk oxili_gfx3d_clk = {
.cbcr_reg = OXILI_GFX3D_CBCR,
.has_sibling = 1,
@@ -2639,7 +2588,6 @@
.parent = &gfx3d_clk_src.c,
.ops = &clk_ops_branch,
CLK_INIT(oxili_gfx3d_clk.c),
- .depends = &oxilicx_axi_clk.c,
},
};
@@ -2707,7 +2655,6 @@
{ &mmss_misc_ahb_clk.c, MMSS_BASE, 0x0003 },
{ &mmss_mmssnoc_axi_clk.c, MMSS_BASE, 0x0004 },
{ &mmss_s0_axi_clk.c, MMSS_BASE, 0x0005 },
- { &ocmemcx_ahb_clk.c, MMSS_BASE, 0x000a },
{ &oxilicx_axi_clk.c, MMSS_BASE, 0x000b },
{ &oxilicx_ahb_clk.c, MMSS_BASE, 0x000c },
{ &oxili_gfx3d_clk.c, MMSS_BASE, 0x000d },
@@ -2755,226 +2702,6 @@
{&dummy_clk, N_BASES, 0x0000},
};
-static struct pll_vote_clk lpaaudio_pll = {
- .en_reg = (void __iomem *)LPA_PLL_VOTE_APPS,
- .en_mask = BIT(0),
- .status_reg = (void __iomem *)LPAAUDIO_PLL_STATUS,
- .status_mask = BIT(17),
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .rate = 491520000,
- .parent = &xo.c,
- .dbg_name = "lpaaudio_pll",
- .ops = &clk_ops_pll_vote,
- CLK_INIT(lpaaudio_pll.c),
- },
-};
-
-static struct clk_freq_tbl ftbl_audio_core_lpaif__osr_clk[] = {
- F_LPASS( 512000, lpaaudio_pll, 16, 1, 60),
- F_LPASS( 768000, lpaaudio_pll, 16, 1, 40),
- F_LPASS( 1024000, lpaaudio_pll, 16, 1, 30),
- F_LPASS( 1536000, lpaaudio_pll, 16, 1, 20),
- F_LPASS( 2048000, lpaaudio_pll, 16, 1, 15),
- F_LPASS( 3072000, lpaaudio_pll, 16, 1, 10),
- F_LPASS( 4096000, lpaaudio_pll, 15, 1, 8),
- F_LPASS( 6144000, lpaaudio_pll, 10, 1, 8),
- F_LPASS( 8192000, lpaaudio_pll, 15, 1, 4),
- F_LPASS( 12288000, lpaaudio_pll, 10, 1, 4),
- F_END
-};
-
-static struct rcg_clk lpaif_pri_clk_src = {
- .cmd_rcgr_reg = LPAIF_PRI_CMD_RCGR,
- .set_rate = set_rate_mnd,
- .freq_tbl = ftbl_audio_core_lpaif__osr_clk,
- .current_freq = &rcg_dummy_freq,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "lpaif_pri_clk_src",
- .ops = &clk_ops_rcg_mnd,
- VDD_DIG_FMAX_MAP2(LOW, 12290000, NOMINAL, 24580000),
- CLK_INIT(lpaif_pri_clk_src.c),
- },
-};
-
-static struct rcg_clk lpaif_quad_clk_src = {
- .cmd_rcgr_reg = LPAIF_QUAD_CMD_RCGR,
- .set_rate = set_rate_mnd,
- .freq_tbl = ftbl_audio_core_lpaif__osr_clk,
- .current_freq = &rcg_dummy_freq,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "lpaif_quad_clk_src",
- .ops = &clk_ops_rcg_mnd,
- VDD_DIG_FMAX_MAP2(LOW, 12290000, NOMINAL, 24580000),
- CLK_INIT(lpaif_quad_clk_src.c),
- },
-};
-
-static struct rcg_clk lpaif_sec_clk_src = {
- .cmd_rcgr_reg = LPAIF_SEC_CMD_RCGR,
- .set_rate = set_rate_mnd,
- .freq_tbl = ftbl_audio_core_lpaif__osr_clk,
- .current_freq = &rcg_dummy_freq,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "lpaif_sec_clk_src",
- .ops = &clk_ops_rcg_mnd,
- VDD_DIG_FMAX_MAP2(LOW, 12290000, NOMINAL, 24580000),
- CLK_INIT(lpaif_sec_clk_src.c),
- },
-};
-
-static struct rcg_clk lpaif_spkr_clk_src = {
- .cmd_rcgr_reg = LPAIF_SPKR_CMD_RCGR,
- .set_rate = set_rate_mnd,
- .freq_tbl = ftbl_audio_core_lpaif__osr_clk,
- .current_freq = &rcg_dummy_freq,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "lpaif_spkr_clk_src",
- .ops = &clk_ops_rcg_mnd,
- VDD_DIG_FMAX_MAP2(LOW, 12290000, NOMINAL, 24580000),
- CLK_INIT(lpaif_spkr_clk_src.c),
- },
-};
-
-static struct rcg_clk lpaif_ter_clk_src = {
- .cmd_rcgr_reg = LPAIF_TER_CMD_RCGR,
- .set_rate = set_rate_mnd,
- .freq_tbl = ftbl_audio_core_lpaif__osr_clk,
- .current_freq = &rcg_dummy_freq,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "lpaif_ter_clk_src",
- .ops = &clk_ops_rcg_mnd,
- VDD_DIG_FMAX_MAP2(LOW, 12290000, NOMINAL, 24580000),
- CLK_INIT(lpaif_ter_clk_src.c),
- },
-};
-
-static struct clk_freq_tbl ftbl_audio_core_lpaif_pcmoe_clk[] = {
- F_LPASS( 512000, lpaaudio_pll, 16, 1, 60),
- F_LPASS( 768000, lpaaudio_pll, 16, 1, 40),
- F_LPASS( 1024000, lpaaudio_pll, 16, 1, 30),
- F_LPASS( 1536000, lpaaudio_pll, 16, 1, 20),
- F_LPASS( 2048000, lpaaudio_pll, 16, 1, 15),
- F_LPASS( 3072000, lpaaudio_pll, 16, 1, 10),
- F_LPASS( 4096000, lpaaudio_pll, 15, 1, 8),
- F_LPASS( 6144000, lpaaudio_pll, 10, 1, 8),
- F_LPASS( 8192000, lpaaudio_pll, 15, 1, 4),
- F_LPASS( 12288000, lpaaudio_pll, 10, 1, 4),
- F_END
-};
-
-static struct rcg_clk lpaif_pcmoe_clk_src = {
- .cmd_rcgr_reg = LPAIF_PCMOE_CMD_RCGR,
- .set_rate = set_rate_mnd,
- .freq_tbl = ftbl_audio_core_lpaif_pcmoe_clk,
- .current_freq = &rcg_dummy_freq,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "lpaif_pcmoe_clk_src",
- .ops = &clk_ops_rcg_mnd,
- VDD_DIG_FMAX_MAP2(LOW, 12290000, NOMINAL, 24580000),
- CLK_INIT(lpaif_pcmoe_clk_src.c),
- },
-};
-
-static struct clk_freq_tbl ftbl_audio_core_lpaif_pcm0_1_ibit_clk[] = {
- F_LPASS( 512000, lpaaudio_pll, 16, 1, 60),
- F_LPASS( 768000, lpaaudio_pll, 16, 1, 40),
- F_LPASS( 1024000, lpaaudio_pll, 16, 1, 30),
- F_LPASS( 1536000, lpaaudio_pll, 16, 1, 20),
- F_LPASS( 2048000, lpaaudio_pll, 16, 1, 15),
- F_LPASS( 3072000, lpaaudio_pll, 16, 1, 10),
- F_LPASS( 4096000, lpaaudio_pll, 15, 1, 8),
- F_LPASS( 6144000, lpaaudio_pll, 10, 1, 8),
- F_LPASS( 8192000, lpaaudio_pll, 15, 1, 4),
- F_END
-};
-
-static struct rcg_clk lpaif_pcm0_clk_src = {
- .cmd_rcgr_reg = LPAIF_PCM0_CMD_RCGR,
- .set_rate = set_rate_mnd,
- .freq_tbl = ftbl_audio_core_lpaif_pcm0_1_ibit_clk,
- .current_freq = &rcg_dummy_freq,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "lpaif_pcm0_clk_src",
- .ops = &clk_ops_rcg_mnd,
- VDD_DIG_FMAX_MAP2(LOW, 4100000, NOMINAL, 8190000),
- CLK_INIT(lpaif_pcm0_clk_src.c),
- },
-};
-
-static struct rcg_clk lpaif_pcm1_clk_src = {
- .cmd_rcgr_reg = LPAIF_PCM1_CMD_RCGR,
- .set_rate = set_rate_mnd,
- .freq_tbl = ftbl_audio_core_lpaif_pcm0_1_ibit_clk,
- .current_freq = &rcg_dummy_freq,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "lpaif_pcm1_clk_src",
- .ops = &clk_ops_rcg_mnd,
- VDD_DIG_FMAX_MAP2(LOW, 4100000, NOMINAL, 8190000),
- CLK_INIT(lpaif_pcm1_clk_src.c),
- },
-};
-
-static struct clk_freq_tbl ftbl_audio_core_slimbus_core_clk[] = {
- F_LPASS( 24576000, lpaaudio_pll, 10, 1, 2),
- F_END
-};
-
-static struct rcg_clk slimbus_clk_src = {
- .cmd_rcgr_reg = SLIMBUS_CMD_RCGR,
- .set_rate = set_rate_mnd,
- .freq_tbl = ftbl_audio_core_slimbus_core_clk,
- .current_freq = &rcg_dummy_freq,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "slimbus_clk_src",
- .ops = &clk_ops_rcg_mnd,
- VDD_DIG_FMAX_MAP2(LOW, 13000000, NOMINAL, 26010000),
- CLK_INIT(slimbus_clk_src.c),
- },
-};
-
-static struct branch_clk audio_core_ixfabric_clk = {
- .cbcr_reg = AUDIO_CORE_IXFABRIC_CBCR,
- .has_sibling = 1,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "audio_core_ixfabric_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_ixfabric_clk.c),
- },
-};
-
-static struct branch_clk audio_core_slimbus_lfabif_clk = {
- .cbcr_reg = AUDIO_CORE_SLIMBUS_LFABIF_CBCR,
- .has_sibling = 1,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "audio_core_slimbus_lfabif_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_slimbus_lfabif_clk.c),
- },
-};
-
-static struct branch_clk audio_wrapper_br_clk = {
- .cbcr_reg = AUDIO_WRAPPER_BR_CBCR,
- .has_sibling = 1,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "audio_wrapper_br_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_wrapper_br_clk.c),
- },
-};
-
static struct branch_clk q6ss_ahb_lfabif_clk = {
.cbcr_reg = Q6SS_AHB_LFABIF_CBCR,
.has_sibling = 1,
@@ -2997,77 +2724,6 @@
},
};
-static struct branch_clk audio_core_lpaif_pcmoe_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_PCM_DATA_OE_CBCR,
- .has_sibling = 0,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "audio_core_lpaif_pcmoe_clk",
- .parent = &lpaif_pcmoe_clk_src.c,
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_pcmoe_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_pri_ebit_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_PRI_EBIT_CBCR,
- .has_sibling = 0,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "audio_core_lpaif_pri_ebit_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_pri_ebit_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_pri_ibit_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_PRI_IBIT_CBCR,
- .has_sibling = 1,
- .max_div = 15,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "audio_core_lpaif_pri_ibit_clk",
- .parent = &lpaif_pri_clk_src.c,
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_pri_ibit_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_pri_osr_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_PRI_OSR_CBCR,
- .has_sibling = 1,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "audio_core_lpaif_pri_osr_clk",
- .parent = &lpaif_pri_clk_src.c,
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_pri_osr_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_pcm0_ebit_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_PCM0_EBIT_CBCR,
- .has_sibling = 0,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "audio_core_lpaif_pcm0_ebit_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_pcm0_ebit_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_pcm0_ibit_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_PCM0_IBIT_CBCR,
- .has_sibling = 0,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "audio_core_lpaif_pcm0_ibit_clk",
- .parent = &lpaif_pcm0_clk_src.c,
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_pcm0_ibit_clk.c),
- },
-};
-
static struct branch_clk q6ss_xo_clk = {
.cbcr_reg = Q6SS_XO_CBCR,
.has_sibling = 1,
@@ -3081,203 +2737,10 @@
},
};
-static struct branch_clk audio_core_lpaif_quad_ebit_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_QUAD_EBIT_CBCR,
- .has_sibling = 0,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "audio_core_lpaif_quad_ebit_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_quad_ebit_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_quad_ibit_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_QUAD_IBIT_CBCR,
- .has_sibling = 1,
- .max_div = 15,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "audio_core_lpaif_quad_ibit_clk",
- .parent = &lpaif_quad_clk_src.c,
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_quad_ibit_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_quad_osr_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_QUAD_OSR_CBCR,
- .has_sibling = 1,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "audio_core_lpaif_quad_osr_clk",
- .parent = &lpaif_quad_clk_src.c,
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_quad_osr_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_sec_ebit_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_SEC_EBIT_CBCR,
- .has_sibling = 0,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "audio_core_lpaif_sec_ebit_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_sec_ebit_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_sec_ibit_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_SEC_IBIT_CBCR,
- .has_sibling = 1,
- .max_div = 15,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "audio_core_lpaif_sec_ibit_clk",
- .parent = &lpaif_sec_clk_src.c,
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_sec_ibit_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_sec_osr_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_SEC_OSR_CBCR,
- .has_sibling = 1,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "audio_core_lpaif_sec_osr_clk",
- .parent = &lpaif_sec_clk_src.c,
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_sec_osr_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_pcm1_ebit_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_PCM1_EBIT_CBCR,
- .has_sibling = 0,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "audio_core_lpaif_pcm1_ebit_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_pcm1_ebit_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_pcm1_ibit_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_PCM1_IBIT_CBCR,
- .has_sibling = 0,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "audio_core_lpaif_pcm1_ibit_clk",
- .parent = &lpaif_pcm1_clk_src.c,
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_pcm1_ibit_clk.c),
- },
-};
-
-static struct branch_clk audio_core_slimbus_core_clk = {
- .cbcr_reg = AUDIO_CORE_SLIMBUS_CORE_CBCR,
- .has_sibling = 0,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "audio_core_slimbus_core_clk",
- .parent = &slimbus_clk_src.c,
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_slimbus_core_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_codec_spkr_ebit_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_CODEC_SPKR_EBIT_CBCR,
- .has_sibling = 0,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "audio_core_lpaif_codec_spkr_ebit_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_codec_spkr_ebit_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_codec_spkr_ibit_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_CODEC_SPKR_IBIT_CBCR,
- .has_sibling = 1,
- .max_div = 15,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "audio_core_lpaif_codec_spkr_ibit_clk",
- .parent = &lpaif_spkr_clk_src.c,
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_codec_spkr_ibit_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_codec_spkr_osr_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_CODEC_SPKR_OSR_CBCR,
- .has_sibling = 1,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "audio_core_lpaif_codec_spkr_osr_clk",
- .parent = &lpaif_spkr_clk_src.c,
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_codec_spkr_osr_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_ter_ebit_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_TER_EBIT_CBCR,
- .has_sibling = 0,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "audio_core_lpaif_ter_ebit_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_ter_ebit_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_ter_ibit_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_TER_IBIT_CBCR,
- .has_sibling = 1,
- .max_div = 15,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "audio_core_lpaif_ter_ibit_clk",
- .parent = &lpaif_ter_clk_src.c,
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_ter_ibit_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_ter_osr_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_TER_OSR_CBCR,
- .has_sibling = 1,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "audio_core_lpaif_ter_osr_clk",
- .parent = &lpaif_ter_clk_src.c,
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_ter_osr_clk.c),
- },
-};
-
static struct measure_mux_entry measure_mux_LPASS[] = {
- { &lpaif_pcmoe_clk_src.c, LPASS_BASE, 0x000f },
- { &slimbus_clk_src.c, LPASS_BASE, 0x0011 },
- { &lpaif_pcm1_clk_src.c, LPASS_BASE, 0x0012 },
- { &lpaif_pcm0_clk_src.c, LPASS_BASE, 0x0013 },
- { &lpaif_quad_clk_src.c, LPASS_BASE, 0x0014 },
- { &lpaif_ter_clk_src.c, LPASS_BASE, 0x0015 },
- { &lpaif_sec_clk_src.c, LPASS_BASE, 0x0016 },
- { &lpaif_pri_clk_src.c, LPASS_BASE, 0x0017 },
- { &lpaif_spkr_clk_src.c, LPASS_BASE, 0x0018 },
{ &q6ss_ahbm_clk.c, LPASS_BASE, 0x001d },
{ &q6ss_ahb_lfabif_clk.c, LPASS_BASE, 0x001e },
- { &audio_wrapper_br_clk.c, LPASS_BASE, 0x0022 },
{ &q6ss_xo_clk.c, LPASS_BASE, 0x002b },
- { &audio_core_lpaif_pcmoe_clk.c, LPASS_BASE, 0x0030 },
- { &audio_core_slimbus_core_clk.c, LPASS_BASE, 0x003d },
- { &audio_core_slimbus_lfabif_clk.c, LPASS_BASE, 0x003e },
- { &audio_core_ixfabric_clk.c, LPASS_BASE, 0x0059 },
{&dummy_clk, N_BASES, 0x0000},
};
@@ -3388,24 +2851,26 @@
{
struct measure_clk *clk = to_measure_clk(c);
unsigned long flags;
- u32 regval, clk_sel;
+ u32 regval, clk_sel, found = 0;
int i;
- struct measure_mux_entry *array[] = {
+ static const struct measure_mux_entry *array[] = {
measure_mux_GCC,
measure_mux_MMSS,
measure_mux_LPASS,
measure_mux_APSS,
NULL
};
- struct measure_mux_entry *mux = array[0];
+ const struct measure_mux_entry *mux = array[0];
if (!parent)
return -EINVAL;
- for (i = 0; array[i]; i++) {
+ for (i = 0; array[i] && !found; i++) {
for (mux = array[i]; mux->c != &dummy_clk; mux++)
- if (mux->c == parent)
+ if (mux->c == parent) {
+ found = 1;
break;
+ }
}
if (mux->c == &dummy_clk)
@@ -3689,8 +3154,8 @@
CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f995e000.serial"),
CLK_LOOKUP("core_clk", gcc_blsp1_uart2_apps_clk.c, "f995e000.serial"),
- CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f9928000.spi"),
- CLK_LOOKUP("core_clk", gcc_blsp1_qup1_spi_apps_clk.c, "f9928000.spi"),
+ CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f9923000.spi"),
+ CLK_LOOKUP("core_clk", gcc_blsp1_qup1_spi_apps_clk.c, "f9923000.spi"),
CLK_LOOKUP("core_clk", gcc_ce1_clk.c, "qseecom"),
CLK_LOOKUP("iface_clk", gcc_ce1_ahb_clk.c, "qseecom"),
@@ -3732,7 +3197,6 @@
CLK_LOOKUP("mmpll0", mmpll0_pll.c, ""),
CLK_LOOKUP("mmpll1", mmpll1_pll.c, ""),
CLK_LOOKUP("mmpll2", mmpll2_pll.c, ""),
- CLK_LOOKUP("lpaaudio_pll", lpaaudio_pll.c, ""),
CLK_LOOKUP("core_clk", gcc_blsp1_qup1_i2c_apps_clk.c, ""),
CLK_LOOKUP("core_clk", gcc_blsp1_qup2_i2c_apps_clk.c, ""),
@@ -3880,13 +3344,14 @@
/* KGSL Clocks */
CLK_LOOKUP("core_clk", oxili_gfx3d_clk.c, "fdb00000.qcom,kgsl-3d0"),
CLK_LOOKUP("iface_clk", oxilicx_ahb_clk.c, "fdb00000.qcom,kgsl-3d0"),
+ CLK_LOOKUP("mem_iface_clk", oxilicx_axi_clk.c,
+ "fdb00000.qcom,kgsl-3d0"),
CLK_LOOKUP("alt_core_clk", oxili_gfx3d_clk.c, "fdb10000.qcom,iommu"),
CLK_LOOKUP("iface_clk", oxilicx_ahb_clk.c, "fdb10000.qcom,iommu"),
CLK_LOOKUP("core_clk", oxilicx_axi_clk.c, "fdb10000.qcom,iommu"),
CLK_LOOKUP("core_clk", ocmemgx_core_clk.c, "fdd00000.qcom,ocmem"),
- CLK_LOOKUP("br_clk", audio_wrapper_br_clk.c, "fdd00000.qcom,ocmem"),
/* Venus Clocks */
CLK_LOOKUP("core_clk", venus0_vcodec0_clk.c, "fdc00000.qcom,vidc"),
@@ -3906,65 +3371,6 @@
CLK_LOOKUP("", mmss_mmssnoc_bto_ahb_clk.c, ""),
CLK_LOOKUP("", mmss_mmssnoc_axi_clk.c, ""),
CLK_LOOKUP("", mmss_s0_axi_clk.c, ""),
- CLK_LOOKUP("", ocmemcx_ahb_clk.c, ""),
-
- /* LPASS CLOCKS */
- CLK_LOOKUP("core_clk", audio_core_slimbus_core_clk.c, "fe12f000.slim"),
- CLK_LOOKUP("iface_clk", audio_core_slimbus_lfabif_clk.c,
- "fe12f000.slim"),
-
- CLK_LOOKUP("core_clk", lpaif_quad_clk_src.c,
- "msm-dai-q6-mi2s.3"),
- CLK_LOOKUP("osr_clk", audio_core_lpaif_quad_osr_clk.c,
- "msm-dai-q6-mi2s.3"),
- CLK_LOOKUP("ebit_clk", audio_core_lpaif_quad_ebit_clk.c,
- "msm-dai-q6-mi2s.3"),
- CLK_LOOKUP("ibit_clk", audio_core_lpaif_quad_ibit_clk.c,
- "msm-dai-q6-mi2s.3"),
-
- CLK_LOOKUP("pcm_clk", lpaif_pcm0_clk_src.c,
- "msm-dai-q6.4106"),
- CLK_LOOKUP("ibit_clk", audio_core_lpaif_pcm0_ibit_clk.c,
- "msm-dai-q6.4106"),
- CLK_LOOKUP("core_oe_src_clk", lpaif_pcmoe_clk_src.c,
- "msm-dai-q6.4106"),
- CLK_LOOKUP("core_oe_clk", audio_core_lpaif_pcmoe_clk.c,
- "msm-dai-q6.4106"),
-
- CLK_LOOKUP("pcm_clk", lpaif_pcm0_clk_src.c,
- "msm-dai-q6.4107"),
- CLK_LOOKUP("ibit_clk", audio_core_lpaif_pcm0_ibit_clk.c,
- "msm-dai-q6.4107"),
- CLK_LOOKUP("core_oe_src_clk", lpaif_pcmoe_clk_src.c,
- "msm-dai-q6.4107"),
- CLK_LOOKUP("core_oe_clk", audio_core_lpaif_pcmoe_clk.c,
- "msm-dai-q6.4107"),
-
-
- CLK_LOOKUP("bus_clk", audio_core_ixfabric_clk.c, ""),
- CLK_LOOKUP("ebit_clk", audio_core_lpaif_pcm0_ebit_clk.c, ""),
- CLK_LOOKUP("core_clk", lpaif_pcm1_clk_src.c, ""),
- CLK_LOOKUP("ebit_clk", audio_core_lpaif_pcm1_ebit_clk.c, ""),
- CLK_LOOKUP("ibit_clk", audio_core_lpaif_pcm1_ibit_clk.c, ""),
- CLK_LOOKUP("core_clk", lpaif_spkr_clk_src.c, ""),
- CLK_LOOKUP("osr_clk", audio_core_lpaif_codec_spkr_osr_clk.c, ""),
- CLK_LOOKUP("ebit_clk", audio_core_lpaif_codec_spkr_ebit_clk.c, ""),
- CLK_LOOKUP("ibit_clk", audio_core_lpaif_codec_spkr_ibit_clk.c, ""),
- CLK_LOOKUP("core_clk", lpaif_pri_clk_src.c, ""),
- CLK_LOOKUP("osr_clk", audio_core_lpaif_pri_osr_clk.c, ""),
-
- CLK_LOOKUP("ebit_clk", audio_core_lpaif_pri_ebit_clk.c, ""),
- CLK_LOOKUP("ibit_clk", audio_core_lpaif_pri_ibit_clk.c, ""),
- CLK_LOOKUP("core_clk", lpaif_sec_clk_src.c, ""),
-
- CLK_LOOKUP("osr_clk", audio_core_lpaif_sec_osr_clk.c, ""),
- CLK_LOOKUP("ebit_clk", audio_core_lpaif_sec_ebit_clk.c, ""),
- CLK_LOOKUP("ibit_clk", audio_core_lpaif_sec_ibit_clk.c, ""),
-
- CLK_LOOKUP("core_clk", lpaif_ter_clk_src.c, ""),
- CLK_LOOKUP("osr_clk", audio_core_lpaif_ter_osr_clk.c, ""),
- CLK_LOOKUP("ebit_clk", audio_core_lpaif_ter_ebit_clk.c, ""),
- CLK_LOOKUP("ibit_clk", audio_core_lpaif_ter_ibit_clk.c, ""),
};
static struct clk_lookup msm_clocks_8226_rumi[] = {
@@ -4087,32 +3493,6 @@
.main_output_mask = BIT(0),
};
-static struct pll_config_regs lpapll0_regs __initdata = {
- .l_reg = (void __iomem *)LPAAUDIO_PLL_L,
- .m_reg = (void __iomem *)LPAAUDIO_PLL_M,
- .n_reg = (void __iomem *)LPAAUDIO_PLL_N,
- .config_reg = (void __iomem *)LPAAUDIO_PLL_USER_CTL,
- .mode_reg = (void __iomem *)LPAAUDIO_PLL_MODE,
- .base = &virt_bases[LPASS_BASE],
-};
-
-/* LPAPLL0 at 491.52 MHz, main output enabled. */
-static struct pll_config lpapll0_config __initdata = {
- .l = 0x33,
- .m = 0x1,
- .n = 0x5,
- .vco_val = 0x0,
- .vco_mask = BM(21, 20),
- .pre_div_val = BVAL(14, 12, 0x1),
- .pre_div_mask = BM(14, 12),
- .post_div_val = 0x0,
- .post_div_mask = BM(9, 8),
- .mn_ena_val = BIT(24),
- .mn_ena_mask = BIT(24),
- .main_output_val = BIT(0),
- .main_output_mask = BIT(0),
-};
-
#define PLL_AUX_OUTPUT_BIT 1
#define PLL_AUX2_OUTPUT_BIT 2
@@ -4138,8 +3518,7 @@
static void __init reg_init(void)
{
- u32 regval, status;
- int ret;
+ u32 regval;
if (!(readl_relaxed(GCC_REG_BASE(GPLL0_STATUS))
& gpll0.status_mask))
@@ -4151,7 +3530,6 @@
configure_sr_hpm_lp_pll(&mmpll0_config, &mmpll0_regs, 1);
configure_sr_hpm_lp_pll(&mmpll1_config, &mmpll1_regs, 1);
- configure_sr_hpm_lp_pll(&lpapll0_config, &lpapll0_regs, 1);
/* Enable GPLL0's aux outputs. */
regval = readl_relaxed(GCC_REG_BASE(GPLL0_USER_CTL));
@@ -4168,32 +3546,8 @@
* register.
*/
writel_relaxed(0x0, GCC_REG_BASE(APCS_CLOCK_SLEEP_ENA_VOTE));
-
- /*
- * TODO: The following sequence enables the LPASS audio core GDSC.
- * Remove when this becomes unnecessary.
- */
-
- /*
- * Disable HW trigger: collapse/restore occur based on registers writes
- * Disable SW override: Use hardware state-machine for sequencing.
- */
- regval = readl_relaxed(LPASS_REG_BASE(AUDIO_CORE_GDSCR));
- regval &= ~(HW_CONTROL_MASK | SW_OVERRIDE_MASK);
-
- /* Configure wait time between states. */
- regval &= ~(EN_REST_WAIT_MASK | EN_FEW_WAIT_MASK | CLK_DIS_WAIT_MASK);
- regval |= EN_REST_WAIT_VAL | EN_FEW_WAIT_VAL | CLK_DIS_WAIT_VAL;
- writel_relaxed(regval, LPASS_REG_BASE(AUDIO_CORE_GDSCR));
-
- regval = readl_relaxed(LPASS_REG_BASE(AUDIO_CORE_GDSCR));
- regval &= ~BIT(0);
- writel_relaxed(regval, LPASS_REG_BASE(AUDIO_CORE_GDSCR));
-
- ret = readl_poll_timeout(LPASS_REG_BASE(AUDIO_CORE_GDSCR), status,
- status & PWR_ON_MASK, 50, GDSC_TIMEOUT_US);
- WARN(ret, "LPASS Audio Core GDSC did not power on.\n");
}
+
static void __init msm8226_clock_post_init(void)
{
@@ -4212,8 +3566,6 @@
clk_set_rate(&mclk1_clk_src.c, mclk1_clk_src.freq_tbl[0].freq_hz);
clk_set_rate(&esc0_clk_src.c, esc0_clk_src.freq_tbl[0].freq_hz);
clk_set_rate(&vsync_clk_src.c, vsync_clk_src.freq_tbl[0].freq_hz);
- clk_set_rate(&slimbus_clk_src.c,
- slimbus_clk_src.freq_tbl[0].freq_hz);
}
#define GCC_CC_PHYS 0xFC400000
@@ -4307,13 +3659,6 @@
clk_set_rate(&axi_clk_src.c, 200000000);
clk_prepare_enable(&mmss_s0_axi_clk.c);
-
- /* TODO: Delete this code once bootloaders enable this clk
- * Temporarily enable a clock to allow access to LPASS core
- * registers. Possibly requires gdsc to be enabled.
- */
- clk_prepare_enable(&audio_core_ixfabric_clk.c);
-
/*
* TODO: Enable the gcc_bimc_clk smcbc, which is the parent of thhe
* mss_gcc_q6_bimc_axi_clk
diff --git a/arch/arm/mach-msm/clock-8610.c b/arch/arm/mach-msm/clock-8610.c
index 55427b5..5690730 100644
--- a/arch/arm/mach-msm/clock-8610.c
+++ b/arch/arm/mach-msm/clock-8610.c
@@ -3097,10 +3097,10 @@
CLK_LOOKUP("core_clk_src", sdcc1_apps_clk_src.c, ""),
CLK_LOOKUP("core_clk_src", sdcc2_apps_clk_src.c, ""),
CLK_LOOKUP("core_clk_src", usb_hs_system_clk_src.c, ""),
-
CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f9925000.i2c"),
+ CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f9923000.spi"),
CLK_LOOKUP("core_clk", gcc_blsp1_qup1_i2c_apps_clk.c, ""),
- CLK_LOOKUP("core_clk", gcc_blsp1_qup1_spi_apps_clk.c, ""),
+ CLK_LOOKUP("core_clk", gcc_blsp1_qup1_spi_apps_clk.c, "f9923000.spi"),
CLK_LOOKUP("core_clk", gcc_blsp1_qup2_i2c_apps_clk.c, ""),
CLK_LOOKUP("core_clk", gcc_blsp1_qup2_spi_apps_clk.c, ""),
CLK_LOOKUP("core_clk", gcc_blsp1_qup3_i2c_apps_clk.c, "f9925000.i2c"),
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index d26b4b2..aee0fd1 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -3008,7 +3008,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,
@@ -3016,6 +3018,7 @@
};
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,
@@ -3034,11 +3037,47 @@
static struct clk_ops clk_ops_pixel;
#define CFG_RCGR_DIV_MASK BM(4, 0)
+#define CFG_RCGR_REG(x) (*(x)->base + (x)->cmd_rcgr_reg + 0x4)
+#define M_REG(x) (*(x)->base + (x)->cmd_rcgr_reg + 0x8)
+#define N_REG(x) (*(x)->base + (x)->cmd_rcgr_reg + 0xC)
+#define MND_MODE_MASK BM(13, 12)
+#define MND_DUAL_EDGE_MODE_BVAL BVAL(13, 12, 0x2)
+#define CFG_RCGR_SRC_SEL_MASK BM(10, 8)
+
+static struct clk *get_parent_byte(struct clk *clk)
+{
+ struct rcg_clk *rcg = to_rcg_clk(clk);
+
+ /* The byte clock has only one known parent. */
+ if ((readl_relaxed(CFG_RCGR_REG(rcg)) & CFG_RCGR_SRC_SEL_MASK)
+ == BVAL(10, 8, dsipll0_byte_mm_source_val))
+ return &dsipll0_byte_clk_src;
+
+ return NULL;
+}
+
+static enum handoff byte_rcg_handoff(struct clk *clk)
+{
+ struct rcg_clk *rcg = to_rcg_clk(clk);
+ u32 div_val;
+ unsigned long pre_div_rate, parent_rate = clk_get_rate(clk->parent);
+
+ /* If the pre-divider is used, find the rate after the division */
+ div_val = readl_relaxed(CFG_RCGR_REG(rcg)) & CFG_RCGR_DIV_MASK;
+ if (div_val > 1)
+ pre_div_rate = parent_rate / ((div_val + 1) >> 1);
+ else
+ pre_div_rate = parent_rate;
+
+ clk->rate = pre_div_rate;
+
+ return HANDOFF_ENABLED_CLK;
+}
static int set_rate_byte(struct clk *clk, unsigned long rate)
{
struct rcg_clk *rcg = to_rcg_clk(clk);
- struct clk *pll = &dsipll0_byte_clk_src;
+ struct clk *pll = clk->parent;
unsigned long source_rate, div;
int rc;
@@ -3059,15 +3098,57 @@
byte_freq.div_src_val &= ~CFG_RCGR_DIV_MASK;
byte_freq.div_src_val |= BVAL(4, 0, div);
- set_rate_mnd(rcg, &byte_freq);
+ set_rate_hid(rcg, &byte_freq);
return 0;
}
+static struct clk *get_parent_pixel(struct clk *clk)
+{
+ struct rcg_clk *rcg = to_rcg_clk(clk);
+
+ /* The pixel clock has one known parent. */
+ if ((readl_relaxed(CFG_RCGR_REG(rcg)) & CFG_RCGR_SRC_SEL_MASK)
+ == BVAL(10, 8, dsipll0_pixel_mm_source_val))
+ return &dsipll0_pixel_clk_src;
+
+ return NULL;
+}
+
+static enum handoff pixel_rcg_handoff(struct clk *clk)
+{
+ struct rcg_clk *rcg = to_rcg_clk(clk);
+ u32 div_val, mval, nval, cfg_regval;
+ unsigned long pre_div_rate, parent_rate = clk_get_rate(clk->parent);
+
+ cfg_regval = readl_relaxed(CFG_RCGR_REG(rcg));
+
+ /* If the pre-divider is used, find the rate after the division */
+ div_val = cfg_regval & CFG_RCGR_DIV_MASK;
+ if (div_val > 1)
+ pre_div_rate = parent_rate / ((div_val + 1) >> 1);
+ else
+ pre_div_rate = parent_rate;
+
+ clk->rate = pre_div_rate;
+
+ /* 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));
+ nval = readl_relaxed(N_REG(rcg));
+ if (!nval)
+ return HANDOFF_DISABLED_CLK;
+ nval = (~nval) + mval;
+ clk->rate = (pre_div_rate * mval) / nval;
+ }
+
+ return HANDOFF_ENABLED_CLK;
+}
+
static int set_rate_pixel(struct clk *clk, unsigned long rate)
{
struct rcg_clk *rcg = to_rcg_clk(clk);
- struct clk *pll = &dsipll0_pixel_clk_src;
+ struct clk *pll = clk->parent;
unsigned long source_rate, div;
int rc;
@@ -3088,7 +3169,7 @@
pixel_freq.div_src_val &= ~CFG_RCGR_DIV_MASK;
pixel_freq.div_src_val |= BVAL(4, 0, div);
- set_rate_hid(rcg, &pixel_freq);
+ set_rate_mnd(rcg, &pixel_freq);
return 0;
}
@@ -5227,35 +5308,64 @@
CLK_LOOKUP("iface_clk", gcc_mmss_noc_cfg_ahb_clk.c, ""),
CLK_LOOKUP("iface_clk", gcc_ocmem_noc_cfg_ahb_clk.c, ""),
- CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-tmc-etr"),
- CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-tpiu"),
- CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-replicator"),
- CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-tmc-etf"),
- CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-funnel-merg"),
- CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-funnel-in0"),
- CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-funnel-in1"),
- CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-funnel-kpss"),
- CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-funnel-mmss"),
- CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-stm"),
- CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-etm0"),
- CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-etm1"),
- CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-etm2"),
- CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-etm3"),
+ /* CoreSight clocks */
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc322000.tmc"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc318000.tpiu"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc31c000.replicator"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc307000.tmc"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc31b000.funnel"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc319000.funnel"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc31a000.funnel"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc345000.funnel"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc364000.funnel"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc321000.stm"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc33c000.etm"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc33d000.etm"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc33e000.etm"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc33f000.etm"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc308000.cti"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc309000.cti"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc30a000.cti"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc30b000.cti"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc30c000.cti"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc30d000.cti"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc30e000.cti"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc30f000.cti"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc310000.cti"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc340000.cti"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc341000.cti"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc342000.cti"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc343000.cti"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc344000.cti"),
- CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-tmc-etr"),
- CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-tpiu"),
- CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-replicator"),
- CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-tmc-etf"),
- CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-funnel-merg"),
- CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-funnel-in0"),
- CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-funnel-in1"),
- CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-funnel-kpss"),
- CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-funnel-mmss"),
- CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-stm"),
- CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-etm0"),
- CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-etm1"),
- CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-etm2"),
- CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-etm3"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc322000.tmc"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc318000.tpiu"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc31c000.replicator"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc307000.tmc"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc31b000.funnel"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc319000.funnel"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc31a000.funnel"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc345000.funnel"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc364000.funnel"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc321000.stm"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc33c000.etm"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc33d000.etm"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc33e000.etm"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc33f000.etm"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc308000.cti"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc309000.cti"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc30a000.cti"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc30b000.cti"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc30c000.cti"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc30d000.cti"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc30e000.cti"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc30f000.cti"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc310000.cti"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc340000.cti"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc341000.cti"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc342000.cti"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc343000.cti"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc344000.cti"),
CLK_LOOKUP("l2_m_clk", l2_m_clk, ""),
CLK_LOOKUP("krait0_m_clk", krait0_m_clk, ""),
@@ -5429,16 +5539,24 @@
static void __init mdss_clock_setup(void)
{
- clk_ops_byte = clk_ops_rcg_mnd;
+ clk_ops_byte = clk_ops_rcg;
clk_ops_byte.set_rate = set_rate_byte;
+ clk_ops_byte.get_parent = get_parent_byte;
+ clk_ops_byte.handoff = byte_rcg_handoff;
- clk_ops_pixel = clk_ops_rcg;
+ clk_ops_pixel = clk_ops_rcg_mnd;
clk_ops_pixel.set_rate = set_rate_pixel;
+ clk_ops_pixel.get_parent = get_parent_pixel;
+ clk_ops_pixel.handoff = pixel_rcg_handoff;
clk_ops_rcg_hdmi = clk_ops_rcg;
clk_ops_rcg_hdmi.set_rate = rcg_clk_set_rate_hdmi;
- mdss_clk_ctrl_init();
+ /*
+ * MDSS needs the ahb clock and needs to init before we register the
+ * lookup table.
+ */
+ mdss_clk_ctrl_pre_init(&mdss_ahb_clk.c);
}
static void __init msm8974_clock_post_init(void)
@@ -5471,8 +5589,6 @@
clk_prepare_enable(&gcc_mmss_noc_cfg_ahb_clk.c);
clk_prepare_enable(&gcc_ocmem_noc_cfg_ahb_clk.c);
- mdss_clock_setup();
-
/* Set rates for single-rate clocks. */
clk_set_rate(&usb30_master_clk_src.c,
usb30_master_clk_src.freq_tbl[0].freq_hz);
@@ -5588,6 +5704,8 @@
for (i = 0; i < ARRAY_SIZE(qup_i2c_clks); i++)
qup_i2c_clks[i][0]->parent = qup_i2c_clks[i][1];
}
+
+ mdss_clock_setup();
}
static int __init msm8974_clock_late_init(void)
diff --git a/arch/arm/mach-msm/clock-9625.c b/arch/arm/mach-msm/clock-9625.c
index b5f5a4e..06a83b6 100644
--- a/arch/arm/mach-msm/clock-9625.c
+++ b/arch/arm/mach-msm/clock-9625.c
@@ -2260,7 +2260,7 @@
CLK_LOOKUP("a5_m_clk", a5_m_clk, ""),
- /* Coresight QDSS clocks */
+ /* CoreSight clocks */
CLK_LOOKUP("core_clk", qdss_clk.c, "fc322000.tmc"),
CLK_LOOKUP("core_clk", qdss_clk.c, "fc318000.tpiu"),
CLK_LOOKUP("core_clk", qdss_clk.c, "fc31c000.replicator"),
@@ -2271,17 +2271,37 @@
CLK_LOOKUP("core_clk", qdss_clk.c, "fc321000.stm"),
CLK_LOOKUP("core_clk", qdss_clk.c, "fc332000.etm"),
CLK_LOOKUP("core_clk", qdss_clk.c, "fc332000.jtagmm"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc308000.cti"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc309000.cti"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc30a000.cti"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc30b000.cti"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc30c000.cti"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc30d000.cti"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc30e000.cti"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc30f000.cti"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc310000.cti"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc333000.cti"),
- CLK_LOOKUP("core_a_clk", qdss_clk.c, "fc322000.tmc"),
- CLK_LOOKUP("core_a_clk", qdss_clk.c, "fc318000.tpiu"),
- CLK_LOOKUP("core_a_clk", qdss_clk.c, "fc31c000.replicator"),
- CLK_LOOKUP("core_a_clk", qdss_clk.c, "fc307000.tmc"),
- CLK_LOOKUP("core_a_clk", qdss_clk.c, "fc31b000.funnel"),
- CLK_LOOKUP("core_a_clk", qdss_clk.c, "fc319000.funnel"),
- CLK_LOOKUP("core_a_clk", qdss_clk.c, "fc31a000.funnel"),
- CLK_LOOKUP("core_a_clk", qdss_clk.c, "fc321000.stm"),
- CLK_LOOKUP("core_a_clk", qdss_clk.c, "fc332000.etm"),
- CLK_LOOKUP("core_a_clk", qdss_clk.c, "fc332000.jtagmm"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc322000.tmc"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc318000.tpiu"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc31c000.replicator"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc307000.tmc"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc31b000.funnel"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc319000.funnel"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc31a000.funnel"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc321000.stm"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc332000.etm"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc332000.jtagmm"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc308000.cti"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc309000.cti"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc30a000.cti"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc30b000.cti"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc30c000.cti"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc30d000.cti"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc30e000.cti"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc30f000.cti"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc310000.cti"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc333000.cti"),
};
diff --git a/arch/arm/mach-msm/clock-mdss-8974.c b/arch/arm/mach-msm/clock-mdss-8974.c
index 54fe11e..b752aeb 100644
--- a/arch/arm/mach-msm/clock-mdss-8974.c
+++ b/arch/arm/mach-msm/clock-mdss-8974.c
@@ -109,20 +109,14 @@
static void __iomem *hdmi_phy_pll_base;
static unsigned hdmi_pll_on;
-void __init mdss_clk_ctrl_init(void)
+void __init mdss_clk_ctrl_pre_init(struct clk *ahb_clk)
{
+ BUG_ON(ahb_clk == NULL);
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 = clk_get_sys("mdss_dsi_clk_ctrl", "iface_clk");
- if (!IS_ERR(mdss_dsi_ahb_clk)) {
- clk_prepare(mdss_dsi_ahb_clk);
- } else {
- mdss_dsi_ahb_clk = NULL;
- pr_err("%s:%d unable to get dsi iface clock\n",
- __func__, __LINE__);
- }
+ mdss_dsi_ahb_clk = ahb_clk;
hdmi_phy_base = ioremap(HDMI_PHY_PHYS, HDMI_PHY_SIZE);
if (!hdmi_phy_base)
@@ -133,6 +127,30 @@
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_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)
@@ -166,7 +184,7 @@
}
}
-static int mdss_dsi_pll_byte_set_rate(struct clk *c, unsigned long rate)
+static int __mdss_dsi_pll_byte_set_rate(struct clk *c, unsigned long rate)
{
int pll_divcfg1, pll_divcfg2;
int half_bitclk_rate;
@@ -175,14 +193,6 @@
if (pll_initialized)
return 0;
- if (!mdss_dsi_ahb_clk) {
- pr_err("%s: mdss_dsi_ahb_clk not initialized\n",
- __func__);
- return -EINVAL;
- }
-
- clk_enable(mdss_dsi_ahb_clk);
-
half_bitclk_rate = rate * 4;
pll_divcfg1 = (VCO_CLK / half_bitclk_rate) - 2;
@@ -233,13 +243,23 @@
pll_byte_clk_rate = 53000000;
pll_pclk_rate = 105000000;
- clk_disable(mdss_dsi_ahb_clk);
pr_debug("%s: **** PLL initialized success\n", __func__);
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 */
@@ -264,20 +284,12 @@
if (!pll_initialized) {
if (dsi_pll_rate)
- mdss_dsi_pll_byte_set_rate(c, 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__);
}
- if (!mdss_dsi_ahb_clk) {
- pr_err("%s: mdss_dsi_ahb_clk not initialized\n",
- __func__);
- return -EINVAL;
- }
-
- clk_enable(mdss_dsi_ahb_clk);
-
mdss_dsi_uniphy_pll_sw_reset();
/* PLL power up */
/* Add HW recommended delay between
@@ -329,25 +341,17 @@
if ((status & 0x01) != 1) {
pr_err("%s: DSI PLL status=%x failed to Lock\n",
__func__, status);
- clk_disable(mdss_dsi_ahb_clk);
return -EINVAL;
}
pr_debug("%s: **** PLL Lock success\n", __func__);
- clk_disable(mdss_dsi_ahb_clk);
return 0;
}
static void __mdss_dsi_pll_disable(void)
{
- if (!mdss_dsi_ahb_clk)
- pr_err("%s: mdss_dsi_ahb_clk not initialized\n",
- __func__);
-
- clk_enable(mdss_dsi_ahb_clk);
writel_relaxed(0x00, mdss_dsi_base + 0x0220); /* GLB CFG */
- clk_disable(mdss_dsi_ahb_clk);
pr_debug("%s: **** disable pll Initialize\n", __func__);
pll_initialized = 0;
}
@@ -386,13 +390,28 @@
return ret;
}
-static enum handoff mdss_dsi_pll_handoff(struct clk *c)
+static enum handoff mdss_dsi_pll_byte_handoff(struct clk *c)
{
- /*
- * FIXME: Continuous display is not implemented. So the display is
- * always off. Implement a poor man's handoff by always returning
- * "disabled".
- */
+ if (mdss_dsi_check_pll_lock()) {
+ c->rate = 53000000;
+ dsi_pll_rate = 53000000;
+ pll_byte_clk_rate = 53000000;
+ 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_dsi_check_pll_lock()) {
+ c->rate = 105000000;
+ dsipll_refcount++;
+ return HANDOFF_ENABLED_CLK;
+ }
+
return HANDOFF_DISABLED_CLK;
}
@@ -814,7 +833,7 @@
.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_handoff,
+ .handoff = mdss_dsi_pll_pixel_handoff,
};
struct clk_ops clk_ops_dsi_byte_pll = {
@@ -822,5 +841,5 @@
.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_handoff,
+ .handoff = mdss_dsi_pll_byte_handoff,
};
diff --git a/arch/arm/mach-msm/clock-mdss-8974.h b/arch/arm/mach-msm/clock-mdss-8974.h
index dbae988..e242669 100644
--- a/arch/arm/mach-msm/clock-mdss-8974.h
+++ b/arch/arm/mach-msm/clock-mdss-8974.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,7 +16,8 @@
extern struct clk_ops clk_ops_dsi_byte_pll;
extern struct clk_ops clk_ops_dsi_pixel_pll;
-void mdss_clk_ctrl_init(void);
+void mdss_clk_ctrl_pre_init(struct clk *ahb_clk);
+void mdss_clk_ctrl_post_init(void);
int hdmi_pll_enable(void);
void hdmi_pll_disable(void);
int hdmi_pll_set_rate(unsigned long rate);
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index 10ee1e3..b7707d7 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -41,6 +41,7 @@
#include <mach/msm_rtb.h>
#include <linux/msm_ion.h>
#include "clock.h"
+#include "pm.h"
#include "devices.h"
#include "footswitch.h"
#include "msm_watchdog.h"
@@ -141,6 +142,19 @@
},
};
+static struct msm_pm_sleep_status_data msm_pm_slp_sts_data = {
+ .base_addr = MSM_ACC0_BASE + 0x08,
+ .cpu_offset = MSM_ACC1_BASE - MSM_ACC0_BASE,
+ .mask = 1UL << 13,
+};
+struct platform_device msm8064_cpu_slp_status = {
+ .name = "cpu_slp_status",
+ .id = -1,
+ .dev = {
+ .platform_data = &msm_pm_slp_sts_data,
+ },
+};
+
static struct msm_watchdog_pdata msm_watchdog_pdata = {
.pet_time = 10000,
.bark_time = 11000,
diff --git a/arch/arm/mach-msm/devices-8930.c b/arch/arm/mach-msm/devices-8930.c
index 6fe8ccb..2f8f547 100644
--- a/arch/arm/mach-msm/devices-8930.c
+++ b/arch/arm/mach-msm/devices-8930.c
@@ -53,6 +53,20 @@
.retention_calls_tz = true,
};
+static struct msm_pm_sleep_status_data msm_pm_slp_sts_data = {
+ .base_addr = MSM_ACC0_BASE + 0x08,
+ .cpu_offset = MSM_ACC1_BASE - MSM_ACC0_BASE,
+ .mask = 1UL << 13,
+};
+
+struct platform_device msm8930_cpu_slp_status = {
+ .name = "cpu_slp_status",
+ .id = -1,
+ .dev = {
+ .platform_data = &msm_pm_slp_sts_data,
+ },
+};
+
struct platform_device msm8930_pm_8x60 = {
.name = "pm-8x60",
.id = -1,
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index 6a344be..2bd9dfe 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -1703,6 +1703,19 @@
.id = -1,
};
+static struct msm_pm_sleep_status_data msm_pm_slp_sts_data = {
+ .base_addr = MSM_ACC0_BASE + 0x08,
+ .cpu_offset = MSM_ACC1_BASE - MSM_ACC0_BASE,
+ .mask = 1UL << 13,
+};
+struct platform_device msm8960_cpu_slp_status = {
+ .name = "cpu_slp_status",
+ .id = -1,
+ .dev = {
+ .platform_data = &msm_pm_slp_sts_data,
+ },
+};
+
static struct msm_watchdog_pdata msm_watchdog_pdata = {
.pet_time = 10000,
.bark_time = 11000,
diff --git a/arch/arm/mach-msm/devices-msm8x60.c b/arch/arm/mach-msm/devices-msm8x60.c
index cfa9281..f9e7863 100644
--- a/arch/arm/mach-msm/devices-msm8x60.c
+++ b/arch/arm/mach-msm/devices-msm8x60.c
@@ -412,6 +412,7 @@
.uart_tx_gpio = 67,
.uart_rx_gpio = 66,
.line = 1,
+ .set_uart_clk_zero = true,
};
static struct resource msm_uart_gsbi9_resources[] = {
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index 53eca3e..327c11d 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -124,6 +124,10 @@
extern struct platform_device msm_device_hsusb_host2;
extern struct platform_device msm_device_hsic_host;
+extern struct platform_device msm8960_cpu_slp_status;
+extern struct platform_device msm8064_cpu_slp_status;
+extern struct platform_device msm8930_cpu_slp_status;
+
extern struct platform_device msm_device_otg;
extern struct platform_device msm_android_usb_device;
extern struct platform_device msm_android_usb_hsic_device;
diff --git a/arch/arm/mach-msm/gpiomux.c b/arch/arm/mach-msm/gpiomux.c
index 37ff421..4714210 100644
--- a/arch/arm/mach-msm/gpiomux.c
+++ b/arch/arm/mach-msm/gpiomux.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010, 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
@@ -24,13 +24,12 @@
static struct gpiomux_setting *msm_gpiomux_sets;
static unsigned msm_gpiomux_ngpio;
-int msm_gpiomux_write(unsigned gpio, enum msm_gpiomux_setting which,
+static int msm_gpiomux_store(unsigned gpio, enum msm_gpiomux_setting which,
struct gpiomux_setting *setting, struct gpiomux_setting *old_setting)
{
struct msm_gpiomux_rec *rec = msm_gpiomux_recs + gpio;
unsigned set_slot = gpio * GPIOMUX_NSETTINGS + which;
unsigned long irq_flags;
- struct gpiomux_setting *new_set;
int status = 0;
if (!msm_gpiomux_recs)
@@ -55,13 +54,31 @@
rec->sets[which] = NULL;
}
+ spin_unlock_irqrestore(&gpiomux_lock, irq_flags);
+ return status;
+}
+
+int msm_gpiomux_write(unsigned gpio, enum msm_gpiomux_setting which,
+ struct gpiomux_setting *setting, struct gpiomux_setting *old_setting)
+{
+ int ret;
+ unsigned long irq_flags;
+ struct gpiomux_setting *new_set;
+ struct msm_gpiomux_rec *rec = msm_gpiomux_recs + gpio;
+
+ ret = msm_gpiomux_store(gpio, which, setting, old_setting);
+ if (ret < 0)
+ return ret;
+
+ spin_lock_irqsave(&gpiomux_lock, irq_flags);
+
new_set = rec->ref ? rec->sets[GPIOMUX_ACTIVE] :
rec->sets[GPIOMUX_SUSPENDED];
if (new_set)
__msm_gpiomux_write(gpio, *new_set);
spin_unlock_irqrestore(&gpiomux_lock, irq_flags);
- return status;
+ return ret;
}
EXPORT_SYMBOL(msm_gpiomux_write);
@@ -134,6 +151,22 @@
}
EXPORT_SYMBOL(msm_gpiomux_init);
+void msm_gpiomux_install_nowrite(struct msm_gpiomux_config *configs,
+ unsigned nconfigs)
+{
+ unsigned c, s;
+ int rc;
+
+ for (c = 0; c < nconfigs; ++c) {
+ for (s = 0; s < GPIOMUX_NSETTINGS; ++s) {
+ rc = msm_gpiomux_store(configs[c].gpio, s,
+ configs[c].settings[s], NULL);
+ if (rc)
+ pr_err("%s: write failure: %d\n", __func__, rc);
+ }
+ }
+}
+
void msm_gpiomux_install(struct msm_gpiomux_config *configs, unsigned nconfigs)
{
unsigned c, s;
diff --git a/arch/arm/mach-msm/include/mach/ecm_ipa.h b/arch/arm/mach-msm/include/mach/ecm_ipa.h
new file mode 100644
index 0000000..008a659
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/ecm_ipa.h
@@ -0,0 +1,76 @@
+/* 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 _ECM_IPA_H_
+#define _ECM_IPA_H_
+
+#include <mach/ipa.h>
+
+/*
+ * @priv: private data given upon ipa_connect
+ * @evt: event enum, should be IPA_WRITE_DONE
+ * @data: for tx path the data field is the sent socket buffer.
+ */
+typedef void (*ecm_ipa_callback)(void *priv,
+ enum ipa_dp_evt_type evt,
+ unsigned long data);
+
+
+#ifdef CONFIG_ECM_IPA
+
+int ecm_ipa_init(ecm_ipa_callback * ecm_ipa_rx_dp_notify,
+ ecm_ipa_callback * ecm_ipa_tx_dp_notify,
+ void **priv);
+
+int ecm_ipa_configure(u8 host_ethaddr[], u8 device_ethaddr[],
+ void *priv);
+
+int ecm_ipa_connect(u32 usb_to_ipa_hdl, u32 ipa_to_usb_hdl,
+ void *priv);
+
+int ecm_ipa_disconnect(void *priv);
+
+void ecm_ipa_cleanup(void *priv);
+
+#else /* CONFIG_ECM_IPA*/
+
+static inline int ecm_ipa_init(ecm_ipa_callback *ecm_ipa_rx_dp_notify,
+ ecm_ipa_callback *ecm_ipa_tx_dp_notify,
+ void **priv)
+{
+ return 0;
+}
+
+static inline int ecm_ipa_configure(u8 host_ethaddr[], u8 device_ethaddr[],
+ void *priv)
+{
+ return 0;
+}
+
+static inline int ecm_ipa_connect(u32 usb_to_ipa_hdl, u32 ipa_to_usb_hdl,
+ void *priv)
+{
+ return 0;
+}
+
+static inline int ecm_ipa_disconnect(void *priv)
+{
+ return 0;
+}
+
+static inline void ecm_ipa_cleanup(void *priv)
+{
+
+}
+#endif /* CONFIG_ECM_IPA*/
+
+#endif /* _ECM_IPA_H_ */
diff --git a/arch/arm/mach-msm/include/mach/gpiomux.h b/arch/arm/mach-msm/include/mach/gpiomux.h
index 85bbbd1..5ffcabb 100644
--- a/arch/arm/mach-msm/include/mach/gpiomux.h
+++ b/arch/arm/mach-msm/include/mach/gpiomux.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
@@ -127,6 +127,12 @@
*/
void msm_gpiomux_install(struct msm_gpiomux_config *configs, unsigned nconfigs);
+/* Install a block of gpiomux configurations in gpiomux. Do not however write
+ * to hardware. Just store the settings to be retrieved at a later time
+ */
+void msm_gpiomux_install_nowrite(struct msm_gpiomux_config *configs,
+ unsigned nconfigs);
+
/* Increment a gpio's reference count, possibly activating the line. */
int __must_check msm_gpiomux_get(unsigned gpio);
diff --git a/arch/arm/mach-msm/include/mach/iommu_hw-v0.h b/arch/arm/mach-msm/include/mach/iommu_hw-v0.h
index 198f72f..68dec79 100644
--- a/arch/arm/mach-msm/include/mach/iommu_hw-v0.h
+++ b/arch/arm/mach-msm/include/mach/iommu_hw-v0.h
@@ -830,6 +830,11 @@
#define IDR (0xFF8)
#define RPU_ACR (0xFFC)
+/* Event Monitor (EM) Registers */
+#define EMMC (0xE000)
+#define EMCS (0xE004)
+#define EMCC_N (0xE100)
+#define EMC_N (0xE200)
/* Context Bank Registers */
#define SCTLR (0x000)
diff --git a/arch/arm/mach-msm/include/mach/iommu_hw-v1.h b/arch/arm/mach-msm/include/mach/iommu_hw-v1.h
index 4f08187..554f7e0 100644
--- a/arch/arm/mach-msm/include/mach/iommu_hw-v1.h
+++ b/arch/arm/mach-msm/include/mach/iommu_hw-v1.h
@@ -15,8 +15,6 @@
#define CTX_SHIFT 12
#define CTX_OFFSET 0x8000
-#define IMPLDEF_OFFSET 0x2000
-#define IMPLDEF_LENGTH 0xDFF
#define GET_GLOBAL_REG(reg, base) (readl_relaxed((base) + (reg)))
#define GET_CTX_REG(reg, base, ctx) \
diff --git a/arch/arm/mach-msm/include/mach/iommu_perfmon.h b/arch/arm/mach-msm/include/mach/iommu_perfmon.h
index 59f58c1..5a01bee 100644
--- a/arch/arm/mach-msm/include/mach/iommu_perfmon.h
+++ b/arch/arm/mach-msm/include/mach/iommu_perfmon.h
@@ -75,6 +75,7 @@
* @evt_irq: irq number for event overflow interrupt
* @iommu_dev: pointer to iommu device
* @ops: iommu access operations pointer.
+ * @hw_ops: iommu pm hw access operations pointer.
*/
struct iommu_info {
const char *iommu_name;
@@ -82,6 +83,7 @@
int evt_irq;
struct device *iommu_dev;
struct iommu_access_ops *ops;
+ struct iommu_pm_hw_ops *hw_ops;
};
/**
@@ -112,9 +114,63 @@
struct mutex lock;
};
-extern struct iommu_access_ops iommu_access_ops;
+/**
+ * struct iommu_hw_ops - Callbacks for accessing IOMMU HW
+ * @initialize_hw: Call to do any initialization before enabling ovf interrupts
+ * @is_hw_access_ok: Returns 1 if we can access HW, 0 otherwise
+ * @grp_enable: Call to enable a counter group
+ * @grp_disable: Call to disable a counter group
+ * @enable_pm: Call to enable PM
+ * @disable_pm: Call to disable PM
+ * @reset_counters: Call to reset counters
+ * @check_for_overflow: Call to check for overflow
+ * @evt_ovfl_int_handler: Overflow interrupt handler callback
+ * @counter_enable: Call to enable counters
+ * @counter_disable: Call to disable counters
+ * @ovfl_int_enable: Call to enable overflow interrupts
+ * @ovfl_int_disable: Call to disable overflow interrupts
+ * @set_event_class: Call to set event class
+ * @read_counter: Call to read a counter value
+ */
+struct iommu_pm_hw_ops {
+ void (*initialize_hw)(const struct iommu_pmon *);
+ unsigned int (*is_hw_access_OK)(const struct iommu_pmon *);
+ void (*grp_enable)(struct iommu_info *, unsigned int);
+ void (*grp_disable)(struct iommu_info *, unsigned int);
+ void (*enable_pm)(struct iommu_info *);
+ void (*disable_pm)(struct iommu_info *);
+ void (*reset_counters)(const struct iommu_info *);
+ void (*check_for_overflow)(struct iommu_pmon *);
+ irqreturn_t (*evt_ovfl_int_handler)(int, void *);
+ void (*counter_enable)(struct iommu_info *,
+ struct iommu_pmon_counter *);
+ void (*counter_disable)(struct iommu_info *,
+ struct iommu_pmon_counter *);
+ void (*ovfl_int_enable)(struct iommu_info *,
+ const struct iommu_pmon_counter *);
+ void (*ovfl_int_disable)(struct iommu_info *,
+ const struct iommu_pmon_counter *);
+ void (*set_event_class)(struct iommu_pmon *pmon, unsigned int,
+ unsigned int);
+ unsigned int (*read_counter)(struct iommu_pmon_counter *);
+};
+
+extern struct iommu_access_ops iommu_access_ops_v0;
+extern struct iommu_access_ops iommu_access_ops_v1;
+#define MSM_IOMMU_PMU_NO_EVENT_CLASS -1
#ifdef CONFIG_MSM_IOMMU_PMON
+
+/**
+ * Get pointer to PMU hardware access functions for IOMMUv0 PMU
+ */
+struct iommu_pm_hw_ops *iommu_pm_get_hw_ops_v0(void);
+
+/**
+ * Get pointer to PMU hardware access functions for IOMMUv1 PMU
+ */
+struct iommu_pm_hw_ops *iommu_pm_get_hw_ops_v1(void);
+
/**
* Allocate memory for performance monitor structure. Must
* be called before iommu_pm_iommu_register
@@ -150,6 +206,16 @@
*/
void msm_iommu_detached(struct device *dev);
#else
+static inline struct iommu_pm_hw_ops *iommu_pm_get_hw_ops_v0(void)
+{
+ return NULL;
+}
+
+static inline struct iommu_pm_hw_ops *iommu_pm_get_hw_ops_v1(void)
+{
+ return NULL;
+}
+
static inline struct iommu_pmon *msm_iommu_pm_alloc(struct device *iommu_dev)
{
return NULL;
diff --git a/arch/arm/mach-msm/include/mach/ipa.h b/arch/arm/mach-msm/include/mach/ipa.h
index 26a055d..564c523 100644
--- a/arch/arm/mach-msm/include/mach/ipa.h
+++ b/arch/arm/mach-msm/include/mach/ipa.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
@@ -354,6 +354,90 @@
IPA_BRIDGE_TYPE_MAX
};
+/**
+ * enum ipa_rm_resource_name - IPA RM clients identification names
+ *
+ * Add new mapping to ipa_rm_dep_prod_index() / ipa_rm_dep_cons_index()
+ * when adding new entry to this enum.
+ */
+enum ipa_rm_resource_name {
+ IPA_RM_RESOURCE_PROD = 0,
+ IPA_RM_RESOURCE_BRIDGE_PROD = IPA_RM_RESOURCE_PROD,
+ IPA_RM_RESOURCE_A2_PROD,
+ IPA_RM_RESOURCE_USB_PROD,
+ IPA_RM_RESOURCE_HSIC_PROD,
+ IPA_RM_RESOURCE_STD_ECM_PROD,
+ IPA_RM_RESOURCE_WWAN_0_PROD,
+ IPA_RM_RESOURCE_WWAN_1_PROD,
+ IPA_RM_RESOURCE_WWAN_2_PROD,
+ IPA_RM_RESOURCE_WWAN_3_PROD,
+ IPA_RM_RESOURCE_WWAN_4_PROD,
+ IPA_RM_RESOURCE_WWAN_5_PROD,
+ IPA_RM_RESOURCE_WWAN_6_PROD,
+ IPA_RM_RESOURCE_WWAN_7_PROD,
+ IPA_RM_RESOURCE_WLAN_PROD,
+ IPA_RM_RESOURCE_PROD_MAX,
+
+ IPA_RM_RESOURCE_A2_CONS = IPA_RM_RESOURCE_PROD_MAX,
+ IPA_RM_RESOURCE_USB_CONS,
+ IPA_RM_RESOURCE_HSIC_CONS,
+ IPA_RM_RESOURCE_MAX
+};
+
+/**
+ * enum ipa_rm_event - IPA RM events
+ *
+ * Indicate the resource state change
+ */
+enum ipa_rm_event {
+ IPA_RM_RESOURCE_GRANTED,
+ IPA_RM_RESOURCE_RELEASED
+};
+
+typedef void (*ipa_rm_notify_cb)(void *user_data,
+ enum ipa_rm_event event,
+ unsigned long data);
+/**
+ * struct ipa_rm_register_params - information needed to
+ * register IPA RM client with IPA RM
+ *
+ * @user_data: IPA RM client provided information
+ * to be passed to notify_cb callback below
+ * @notify_cb: callback which is called by resource
+ * to notify the IPA RM client about its state
+ * change IPA RM client is expected to perform non
+ * blocking operations only in notify_cb and
+ * release notification context as soon as
+ * possible.
+ */
+struct ipa_rm_register_params {
+ void *user_data;
+ ipa_rm_notify_cb notify_cb;
+};
+
+/**
+ * struct ipa_rm_create_params - information needed to initialize
+ * the resource
+ * @name: resource name
+ * @reg_params: register parameters, contains are ignored
+ * for consumer resource NULL should be provided
+ * for consumer resource
+ * @request_resource: function which should be called to request resource,
+ * NULL should be provided for producer resource
+ * @release_resource: function which should be called to release resource,
+ * NULL should be provided for producer resource
+ *
+ * IPA RM client is expected to perform non blocking operations only
+ * in request_resource and release_resource functions and
+ * release notification context as soon as possible.
+ */
+struct ipa_rm_create_params {
+ enum ipa_rm_resource_name name;
+ struct ipa_rm_register_params reg_params;
+ int (*request_resource)(void);
+ int (*release_resource)(void);
+};
+
#ifdef CONFIG_IPA
/*
@@ -489,6 +573,41 @@
int ipa_teardown_sys_pipe(u32 clnt_hdl);
+/*
+ * Resource manager
+ */
+int ipa_rm_create_resource(struct ipa_rm_create_params *create_params);
+
+int ipa_rm_register(enum ipa_rm_resource_name resource_name,
+ struct ipa_rm_register_params *reg_params);
+
+int ipa_rm_deregister(enum ipa_rm_resource_name resource_name,
+ struct ipa_rm_register_params *reg_params);
+
+int ipa_rm_add_dependency(enum ipa_rm_resource_name resource_name,
+ enum ipa_rm_resource_name depends_on_name);
+
+int ipa_rm_delete_dependency(enum ipa_rm_resource_name resource_name,
+ enum ipa_rm_resource_name depends_on_name);
+
+int ipa_rm_request_resource(enum ipa_rm_resource_name resource_name);
+
+int ipa_rm_release_resource(enum ipa_rm_resource_name resource_name);
+
+int ipa_rm_notify_completion(enum ipa_rm_event event,
+ enum ipa_rm_resource_name resource_name);
+
+int ipa_rm_inactivity_timer_init(enum ipa_rm_resource_name resource_name,
+ unsigned long msecs);
+
+int ipa_rm_inactivity_timer_destroy(enum ipa_rm_resource_name resource_name);
+
+int ipa_rm_inactivity_timer_request_resource(
+ enum ipa_rm_resource_name resource_name);
+
+int ipa_rm_inactivity_timer_release_resource(
+ enum ipa_rm_resource_name resource_name);
+
#else /* CONFIG_IPA */
/*
@@ -778,6 +897,84 @@
return -EPERM;
}
+/*
+ * Resource manager
+ */
+static inline int ipa_rm_create_resource(
+ struct ipa_rm_create_params *create_params)
+{
+ return -EPERM;
+}
+
+static inline int ipa_rm_register(enum ipa_rm_resource_name resource_name,
+ struct ipa_rm_register_params *reg_params)
+{
+ return -EPERM;
+}
+
+static inline int ipa_rm_deregister(enum ipa_rm_resource_name resource_name,
+ struct ipa_rm_register_params *reg_params)
+{
+ return -EPERM;
+}
+
+static inline int ipa_rm_add_dependency(
+ enum ipa_rm_resource_name resource_name,
+ enum ipa_rm_resource_name depends_on_name)
+{
+ return -EPERM;
+}
+
+static inline int ipa_rm_delete_dependency(
+ enum ipa_rm_resource_name resource_name,
+ enum ipa_rm_resource_name depends_on_name)
+{
+ return -EPERM;
+}
+
+static inline int ipa_rm_request_resource(
+ enum ipa_rm_resource_name resource_name)
+{
+ return -EPERM;
+}
+
+static inline int ipa_rm_release_resource(
+ enum ipa_rm_resource_name resource_name)
+{
+ return -EPERM;
+}
+
+static inline int ipa_rm_notify_completion(enum ipa_rm_event event,
+ enum ipa_rm_resource_name resource_name)
+{
+ return -EPERM;
+}
+
+static inline int ipa_rm_inactivity_timer_init(
+ enum ipa_rm_resource_name resource_name,
+ unsigned long msecs)
+{
+ return -EPERM;
+}
+
+static inline int ipa_rm_inactivity_timer_destroy(
+ enum ipa_rm_resource_name resource_name)
+{
+ return -EPERM;
+}
+
+static inline int ipa_rm_inactivity_timer_request_resource(
+ enum ipa_rm_resource_name resource_name)
+{
+ return -EPERM;
+}
+
+static inline int ipa_rm_inactivity_timer_release_resource(
+ enum ipa_rm_resource_name resource_name)
+{
+ return -EPERM;
+}
+
#endif /* CONFIG_IPA*/
#endif /* _IPA_H_ */
diff --git a/arch/arm/mach-msm/include/mach/msm_ipc_logging.h b/arch/arm/mach-msm/include/mach/msm_ipc_logging.h
index ec9fdb0..b675c00 100644
--- a/arch/arm/mach-msm/include/mach/msm_ipc_logging.h
+++ b/arch/arm/mach-msm/include/mach/msm_ipc_logging.h
@@ -113,7 +113,7 @@
* @ilctxt: Debug Log Context created using ipc_log_context_create()
* @fmt: Data specified using format specifiers
*/
-int ipc_log_string(void *ilctxt, const char *fmt, ...);
+int ipc_log_string(void *ilctxt, const char *fmt, ...) __printf(2, 3);
/*
* Print a string to decode context.
diff --git a/arch/arm/mach-msm/include/mach/msm_serial_hs_lite.h b/arch/arm/mach-msm/include/mach/msm_serial_hs_lite.h
index 7bdd35a..7a24190 100644
--- a/arch/arm/mach-msm/include/mach/msm_serial_hs_lite.h
+++ b/arch/arm/mach-msm/include/mach/msm_serial_hs_lite.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
@@ -23,6 +23,9 @@
* @uart_rx_gpio: GPIO number for UART Rx Line.
* @uart_cts_gpio: GPIO number for UART CTS Line.
* @uart_rfr_gpio: GPIO number for UART RFR Line.
+ * @set_uart_clk_zero: use this if setting UART Clock to zero is required
+ * It is mainly required where same UART is used across different processor.
+ * Make sure that Clock driver for platform support setting clock rate to zero.
* @use_pm: use this to enable power management
* @line: Used to set UART Port number.
*/
@@ -32,6 +35,7 @@
unsigned uart_rx_gpio;
unsigned uart_cts_gpio;
unsigned uart_rfr_gpio;
+ bool set_uart_clk_zero;
bool use_pm;
int line;
};
diff --git a/arch/arm/mach-msm/include/mach/socinfo.h b/arch/arm/mach-msm/include/mach/socinfo.h
index d9b0336..aeeaae6 100644
--- a/arch/arm/mach-msm/include/mach/socinfo.h
+++ b/arch/arm/mach-msm/include/mach/socinfo.h
@@ -58,6 +58,14 @@
of_machine_is_compatible("qcom,msm8226-sim")
#define machine_is_msm8226_rumi() \
of_machine_is_compatible("qcom,msm8226-rumi")
+#define machine_is_msm8226_cdp() \
+ of_machine_is_compatible("qcom,msm8226-cdp")
+#define machine_is_msm8226_fluid() \
+ of_machine_is_compatible("qcom,msm8226-fluid")
+#define machine_is_msm8226_mtp() \
+ of_machine_is_compatible("qcom,msm8226-mtp")
+#define machine_is_msm8226_qrd() \
+ of_machine_is_compatible("qcom,msm8226-qrd")
#define early_machine_is_msm8610() \
of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,msm8610")
#define machine_is_msm8610() \
diff --git a/arch/arm/mach-msm/ipc_router.c b/arch/arm/mach-msm/ipc_router.c
index 265435a..ea874bd 100644
--- a/arch/arm/mach-msm/ipc_router.c
+++ b/arch/arm/mach-msm/ipc_router.c
@@ -558,9 +558,9 @@
mutex_init(&port_ptr->port_rx_q_lock);
init_waitqueue_head(&port_ptr->port_rx_wait_q);
snprintf(port_ptr->rx_wakelock_name, MAX_WAKELOCK_NAME_SZ,
- "msm_ipc_read%08x:%08x",
- port_ptr->this_port.node_id,
- port_ptr->this_port.port_id);
+ "ipc%08x_%s",
+ port_ptr->this_port.port_id,
+ current->comm);
wake_lock_init(&port_ptr->port_rx_wake_lock,
WAKE_LOCK_SUSPEND, port_ptr->rx_wakelock_name);
diff --git a/arch/arm/mach-msm/ipc_socket.c b/arch/arm/mach-msm/ipc_socket.c
index d31af84..2cec5c5 100644
--- a/arch/arm/mach-msm/ipc_socket.c
+++ b/arch/arm/mach-msm/ipc_socket.c
@@ -400,6 +400,14 @@
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) {
+ pr_err("%s: Integer Overflow %d * %d\n",
+ __func__, sizeof(*srv_info),
+ server_arg.num_entries_in_array);
+ ret = -EINVAL;
+ break;
+ }
srv_info = kmalloc(srv_info_sz, GFP_KERNEL);
if (!srv_info) {
ret = -ENOMEM;
diff --git a/arch/arm/mach-msm/memory.c b/arch/arm/mach-msm/memory.c
index 90cb49e..806581d 100644
--- a/arch/arm/mach-msm/memory.c
+++ b/arch/arm/mach-msm/memory.c
@@ -1,7 +1,7 @@
/* arch/arm/mach-msm/memory.c
*
* Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -507,11 +507,10 @@
*/
void adjust_meminfo(unsigned long start, unsigned long size)
{
- int i, j;
+ int i;
- for (i = 0, j = 0; i < meminfo.nr_banks; i++) {
- struct membank *bank = &meminfo.bank[j];
- *bank = meminfo.bank[i];
+ for (i = 0; i < meminfo.nr_banks; i++) {
+ struct membank *bank = &meminfo.bank[i];
if (((start + size) <= (bank->start + bank->size)) &&
(start >= bank->start)) {
@@ -519,15 +518,15 @@
(meminfo.nr_banks - i) * sizeof(*bank));
meminfo.nr_banks++;
i++;
- bank[1].size -= (start + size);
- bank[1].start = (start + size);
- bank[1].highmem = 0;
- j++;
+
bank->size = start - bank->start;
+ bank[1].start = (start + size);
+ bank[1].size -= (bank->size + size);
+ bank[1].highmem = 0;
}
- j++;
}
}
+
unsigned long get_ddr_size(void)
{
unsigned int i;
diff --git a/arch/arm/mach-msm/msm_ipc_router_security.c b/arch/arm/mach-msm/msm_ipc_router_security.c
index 756e24e..69efd13 100644
--- a/arch/arm/mach-msm/msm_ipc_router_security.c
+++ b/arch/arm/mach-msm/msm_ipc_router_security.c
@@ -37,7 +37,7 @@
uint32_t instance_id;
unsigned reserved;
int num_group_info;
- int *group_id;
+ gid_t *group_id;
};
static DEFINE_MUTEX(security_rules_lock);
@@ -98,6 +98,7 @@
struct config_sec_rules_args sec_rules_arg;
struct security_rule *rule, *temp_rule;
int key;
+ int group_info_sz;
int ret;
if (current_euid())
@@ -111,14 +112,20 @@
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) {
+ pr_err("%s: Integer Overflow %d * %d\n", __func__,
+ sizeof(gid_t), sec_rules_arg.num_group_info);
+ return -EINVAL;
+ }
+
rule = kzalloc(sizeof(struct security_rule), GFP_KERNEL);
if (!rule) {
pr_err("%s: security_rule alloc failed\n", __func__);
return -ENOMEM;
}
- rule->group_id = kzalloc((sec_rules_arg.num_group_info * sizeof(int)),
- GFP_KERNEL);
+ rule->group_id = kzalloc(group_info_sz, GFP_KERNEL);
if (!rule->group_id) {
pr_err("%s: group_id alloc failed\n", __func__);
kfree(rule);
@@ -131,7 +138,7 @@
rule->num_group_info = sec_rules_arg.num_group_info;
ret = copy_from_user(rule->group_id,
((void *)(arg + sizeof(sec_rules_arg))),
- (rule->num_group_info * sizeof(uint32_t)));
+ group_info_sz);
if (ret) {
kfree(rule->group_id);
kfree(rule);
diff --git a/arch/arm/mach-msm/perf_debug.c b/arch/arm/mach-msm/perf_debug.c
index bbd0852..0579145 100644
--- a/arch/arm/mach-msm/perf_debug.c
+++ b/arch/arm/mach-msm/perf_debug.c
@@ -26,6 +26,7 @@
"1 Perf: Restore counter after powercollapse for generic ARM PMU's\n"
"2 Perf: Toggle PMU IRQ when CPU's are hotplugged\n"
"3 Perf: Correct irq for CPU hotplug detection\n"
+ "4 Perf: Check perf activity on correct CPU\n"
;
static ssize_t desc_read(struct file *fp, char __user *buf,
diff --git a/arch/arm/mach-msm/peripheral-loader.c b/arch/arm/mach-msm/peripheral-loader.c
index affb451..fc9a0fa 100644
--- a/arch/arm/mach-msm/peripheral-loader.c
+++ b/arch/arm/mach-msm/peripheral-loader.c
@@ -656,7 +656,8 @@
void pil_shutdown(struct pil_desc *desc)
{
struct pil_priv *priv = desc->priv;
- desc->ops->shutdown(desc);
+ if (desc->ops->shutdown)
+ desc->ops->shutdown(desc);
if (proxy_timeout_ms == 0 && desc->ops->proxy_unvote)
desc->ops->proxy_unvote(desc);
else
diff --git a/arch/arm/mach-msm/pil-q6v5-mss.c b/arch/arm/mach-msm/pil-q6v5-mss.c
index c1d4ab4..cd6aaf4 100644
--- a/arch/arm/mach-msm/pil-q6v5-mss.c
+++ b/arch/arm/mach-msm/pil-q6v5-mss.c
@@ -1,5 +1,5 @@
/*
- * 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
@@ -462,7 +462,7 @@
if (!drv->is_loadable)
return 0;
- /* MBA doesn't support shutdown */
+ pil_shutdown(&drv->desc);
pil_shutdown(&drv->q6->desc);
return 0;
}
@@ -578,7 +578,7 @@
if (!drv->is_loadable)
return;
- /* MBA doesn't support shutdown */
+ pil_shutdown(&drv->desc);
pil_shutdown(&drv->q6->desc);
}
diff --git a/arch/arm/mach-msm/pm.h b/arch/arm/mach-msm/pm.h
index af0744c..c77304d 100644
--- a/arch/arm/mach-msm/pm.h
+++ b/arch/arm/mach-msm/pm.h
@@ -65,6 +65,12 @@
uint32_t modified_time_us;
};
+struct msm_pm_sleep_status_data {
+ void *base_addr;
+ uint32_t cpu_offset;
+ uint32_t mask;
+};
+
struct msm_pm_platform_data {
u8 idle_supported; /* Allow device to enter mode during idle */
u8 suspend_supported; /* Allow device to enter mode during suspend */
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_multi_aac.c b/arch/arm/mach-msm/qdsp6v2/audio_multi_aac.c
index 658c07b..8153145 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_multi_aac.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_multi_aac.c
@@ -185,6 +185,25 @@
}
break;
}
+ case AUDIO_SET_AAC_MIX_CONFIG: {
+ pr_debug("%s, AUDIO_SET_AAC_MIX_CONFIG", __func__);
+ if (copy_from_user(audio->codec_cfg, (void *)arg,
+ sizeof(unsigned long))) {
+ rc = -EFAULT;
+ break;
+ } else {
+ unsigned long *mix_coeff =
+ (unsigned long *)audio->codec_cfg;
+ pr_debug("%s, value of coeff = %lu",
+ __func__, *mix_coeff);
+ q6asm_cfg_aac_sel_mix_coef(audio->ac, *mix_coeff);
+ if (rc < 0)
+ pr_err("%s asm aac_sel_mix_coef failed rc=%d\n",
+ __func__, rc);
+ break;
+ }
+ break;
+ }
default:
pr_debug("Calling utils ioctl\n");
rc = audio->codec_ioctl(file, cmd, arg);
diff --git a/arch/arm/mach-msm/qdsp6v2/ultrasound/version_b/q6usm_b.c b/arch/arm/mach-msm/qdsp6v2/ultrasound/version_b/q6usm_b.c
index 11b1405..ff7ba33 100644
--- a/arch/arm/mach-msm/qdsp6v2/ultrasound/version_b/q6usm_b.c
+++ b/arch/arm/mach-msm/qdsp6v2/ultrasound/version_b/q6usm_b.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
@@ -327,6 +327,7 @@
return usc;
fail:
+ kfree(p_mem_handle);
q6usm_us_client_free(usc);
return NULL;
fail_session:
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index 8725544..10e40b4 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -72,6 +72,7 @@
#define SMD_VERSION 0x00020000
#define SMSM_SNAPSHOT_CNT 64
#define SMSM_SNAPSHOT_SIZE ((SMSM_NUM_ENTRIES + 1) * 4)
+#define RSPIN_INIT_WAIT_MS 1000
uint32_t SMSM_NUM_ENTRIES = 8;
uint32_t SMSM_NUM_HOSTS = 3;
@@ -2534,6 +2535,18 @@
struct smem_shared *shared = (void *) MSM_SHARED_RAM_BASE;
int i;
struct smsm_size_info_type *smsm_size_info;
+ unsigned long flags;
+ unsigned long j_start;
+
+ /* Verify that remote spinlock is not deadlocked */
+ j_start = jiffies;
+ while (!remote_spin_trylock_irqsave(&remote_spinlock, flags)) {
+ if (jiffies_to_msecs(jiffies - j_start) > RSPIN_INIT_WAIT_MS) {
+ panic("%s: Remote processor %d will not release spinlock\n",
+ __func__, remote_spin_owner(&remote_spinlock));
+ }
+ }
+ remote_spin_unlock_irqrestore(&remote_spinlock, flags);
smsm_size_info = smem_alloc(SMEM_SMSM_SIZE_INFO,
sizeof(struct smsm_size_info_type));
diff --git a/arch/arm/mach-msm/smd_debug.c b/arch/arm/mach-msm/smd_debug.c
index 9206016..4dcf72f 100644
--- a/arch/arm/mach-msm/smd_debug.c
+++ b/arch/arm/mach-msm/smd_debug.c
@@ -1,7 +1,7 @@
/* arch/arm/mach-msm/smd_debug.c
*
* Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
* Author: Brian Swetland <swetland@google.com>
*
* This software is licensed under the terms of the GNU General Public
@@ -103,14 +103,14 @@
const char *subsys_name;
i += scnprintf(buf + i, max - i,
- " Subsystem | Interrupt ID | In | Out (Hardcoded) |"
- " Out (Configured) |\n");
+ " Subsystem | Interrupt ID | In | Out (Hardcoded) |"
+ " Out (Configured)|\n");
for (subsys = 0; subsys < NUM_SMD_SUBSYSTEMS; ++subsys) {
subsys_name = smd_pid_to_subsystem(subsys);
if (subsys_name) {
i += scnprintf(buf + i, max - i,
- "%-10s %4s | %9d | %9u | %9u | %9u |\n",
+ "%-10s %4s | %9d | %9u | %9u | %9u |\n",
smd_pid_to_subsystem(subsys), "smd",
stats->smd_interrupt_id,
stats->smd_in_count,
@@ -118,7 +118,7 @@
stats->smd_out_config_count);
i += scnprintf(buf + i, max - i,
- "%-10s %4s | %9d | %9u | %9u | %9u |\n",
+ "%-10s %4s | %9d | %9u | %9u | %9u |\n",
smd_pid_to_subsystem(subsys), "smsm",
stats->smsm_interrupt_id,
stats->smsm_in_count,
diff --git a/arch/arm/mach-msm/smp2p.c b/arch/arm/mach-msm/smp2p.c
index 0597411..8066005 100644
--- a/arch/arm/mach-msm/smp2p.c
+++ b/arch/arm/mach-msm/smp2p.c
@@ -1314,13 +1314,20 @@
}
/* Create and add it to the list */
- in->remote_pid = pid;
- strlcpy(in->name, name, SMP2P_MAX_ENTRY_NAME);
- RAW_INIT_NOTIFIER_HEAD(&in->in_notifier_list);
- list_add(&in->in_edge_list, &in_list[pid].list);
+ if (!in->notifier_count) {
+ in->remote_pid = pid;
+ strlcpy(in->name, name, SMP2P_MAX_ENTRY_NAME);
+ RAW_INIT_NOTIFIER_HEAD(&in->in_notifier_list);
+ list_add(&in->in_edge_list, &in_list[pid].list);
+ }
+
ret = raw_notifier_chain_register(&in->in_notifier_list,
in_notifier);
if (ret) {
+ if (!in->notifier_count) {
+ list_del(&in->in_edge_list);
+ kfree(in);
+ }
SMP2P_DBG("%s: '%s':%d failed %d\n", __func__, name, pid, ret);
goto bail;
}
diff --git a/arch/arm/mach-msm/smp2p_debug.c b/arch/arm/mach-msm/smp2p_debug.c
index 1a5c96e..a493cbe 100644
--- a/arch/arm/mach-msm/smp2p_debug.c
+++ b/arch/arm/mach-msm/smp2p_debug.c
@@ -233,7 +233,7 @@
if (in_ptr) {
in_entries = (struct smp2p_entry_v1 *)((void *)in_ptr +
sizeof(struct smp2p_smem));
- in_valid = SMP2P_GET_ENT_VALID(out_ptr->valid_total_ent);
+ in_valid = SMP2P_GET_ENT_VALID(in_ptr->valid_total_ent);
}
for (entry = 0; out_entries || in_entries; ++entry) {
diff --git a/arch/arm/mach-msm/smp2p_test.c b/arch/arm/mach-msm/smp2p_test.c
index 10f7575..18c9bfd 100644
--- a/arch/arm/mach-msm/smp2p_test.c
+++ b/arch/arm/mach-msm/smp2p_test.c
@@ -843,6 +843,116 @@
}
}
+/**
+ * smp2p_ut_local_in_multiple - Verify Multiple Inbound Registration.
+ *
+ * @s: pointer to output file
+ *
+ * This test verifies multiple clients registering for same inbound entries
+ * using the remote mock processor.
+ */
+static void smp2p_ut_local_in_multiple(struct seq_file *s)
+{
+ int failed = 0;
+ struct msm_smp2p_remote_mock *rmp = NULL;
+ int ret;
+ static struct mock_cb_data cb_in_1;
+ static struct mock_cb_data cb_in_2;
+ static struct mock_cb_data cb_out;
+
+ seq_printf(s, "Running %s\n", __func__);
+
+ mock_cb_data_init(&cb_in_1);
+ mock_cb_data_init(&cb_in_2);
+ mock_cb_data_init(&cb_out);
+
+ do {
+ /* Initialize mock edge */
+ ret = smp2p_reset_mock_edge();
+ UT_ASSERT_INT(ret, ==, 0);
+
+ rmp = msm_smp2p_get_remote_mock();
+ UT_ASSERT_PTR(rmp, !=, NULL);
+
+ rmp->rx_interrupt_count = 0;
+ memset(&rmp->remote_item, 0,
+ sizeof(struct smp2p_smem_item));
+ rmp->remote_item.header.magic = SMP2P_MAGIC;
+ SMP2P_SET_LOCAL_PID(
+ rmp->remote_item.header.rem_loc_proc_id,
+ SMP2P_REMOTE_MOCK_PROC);
+ SMP2P_SET_REMOTE_PID(
+ rmp->remote_item.header.rem_loc_proc_id,
+ SMP2P_APPS_PROC);
+ SMP2P_SET_VERSION(
+ rmp->remote_item.header.feature_version, 1);
+ SMP2P_SET_FEATURES(
+ rmp->remote_item.header.feature_version, 0);
+ SMP2P_SET_ENT_TOTAL(
+ rmp->remote_item.header.valid_total_ent, 1);
+ SMP2P_SET_ENT_VALID(
+ rmp->remote_item.header.valid_total_ent, 0);
+ rmp->remote_item.header.reserved = 0x0;
+ msm_smp2p_set_remote_mock_exists(true);
+
+ /* Create an Entry in the remote mock object */
+ scnprintf(rmp->remote_item.entries[0].name,
+ SMP2P_MAX_ENTRY_NAME, "smp2p%d", 1);
+ rmp->remote_item.entries[0].entry = 0;
+ rmp->tx_interrupt();
+
+ /* Register multiple clients for the inbound entry */
+ ret = msm_smp2p_in_register(SMP2P_REMOTE_MOCK_PROC,
+ rmp->remote_item.entries[0].name,
+ &cb_in_1.nb);
+ UT_ASSERT_INT(ret, ==, 0);
+ UT_ASSERT_INT(
+ (int)wait_for_completion_timeout(
+ &(cb_in_1.cb_completion), HZ / 2),
+ >, 0);
+ UT_ASSERT_INT(cb_in_1.cb_count, ==, 1);
+ UT_ASSERT_INT(cb_in_1.event_entry_update, ==, 0);
+
+ ret = msm_smp2p_in_register(SMP2P_REMOTE_MOCK_PROC,
+ rmp->remote_item.entries[0].name,
+ &cb_in_2.nb);
+ UT_ASSERT_INT(ret, ==, 0);
+ UT_ASSERT_INT(
+ (int)wait_for_completion_timeout(
+ &(cb_in_2.cb_completion), HZ / 2),
+ >, 0);
+ UT_ASSERT_INT(cb_in_2.cb_count, ==, 1);
+ UT_ASSERT_INT(cb_in_2.event_entry_update, ==, 0);
+
+
+ /* Unregister the clients */
+ ret = msm_smp2p_in_unregister(SMP2P_REMOTE_MOCK_PROC,
+ rmp->remote_item.entries[0].name,
+ &(cb_in_1.nb));
+ UT_ASSERT_INT(ret, ==, 0);
+
+ ret = msm_smp2p_in_unregister(SMP2P_REMOTE_MOCK_PROC,
+ rmp->remote_item.entries[0].name,
+ &(cb_in_2.nb));
+ UT_ASSERT_INT(ret, ==, 0);
+
+ seq_printf(s, "\tOK\n");
+ } while (0);
+
+ if (failed) {
+ pr_err("%s: Failed\n", __func__);
+ seq_printf(s, "\tFailed\n");
+
+ ret = msm_smp2p_in_unregister(SMP2P_REMOTE_MOCK_PROC,
+ rmp->remote_item.entries[0].name,
+ &(cb_in_1.nb));
+
+ ret = msm_smp2p_in_unregister(SMP2P_REMOTE_MOCK_PROC,
+ rmp->remote_item.entries[0].name,
+ &(cb_in_2.nb));
+ }
+}
+
static struct dentry *dent;
static int debugfs_show(struct seq_file *s, void *data)
@@ -907,6 +1017,8 @@
smp2p_ut_local_in_max_entries);
smp2p_debug_create("ut_remote_out_max_entries",
smp2p_ut_remote_out_max_entries);
+ smp2p_debug_create("ut_local_in_multiple",
+ smp2p_ut_local_in_multiple);
return 0;
}
diff --git a/arch/arm/mach-msm/subsystem_map.c b/arch/arm/mach-msm/subsystem_map.c
index 3269e50..116fc2e 100644
--- a/arch/arm/mach-msm/subsystem_map.c
+++ b/arch/arm/mach-msm/subsystem_map.c
@@ -256,6 +256,8 @@
subsys_domain = msm_get_iommu_domain(msm_subsystem_get_domain_no
(subsys_id));
+ if (!subsys_domain)
+ return -EINVAL;
return iommu_iova_to_phys(subsys_domain, iova);
}
@@ -429,15 +431,18 @@
return buf;
outiova:
- if (flags & MSM_SUBSYSTEM_MAP_IOVA)
- iommu_unmap(d, temp_va, SZ_4K);
+ if (flags & MSM_SUBSYSTEM_MAP_IOVA) {
+ if (d)
+ iommu_unmap(d, temp_va, SZ_4K);
+ }
outdomain:
if (flags & MSM_SUBSYSTEM_MAP_IOVA) {
/* Unmap the rest of the current domain, i */
- for (j -= SZ_4K, temp_va -= SZ_4K;
- j > 0; temp_va -= SZ_4K, j -= SZ_4K)
- iommu_unmap(d, temp_va, SZ_4K);
-
+ if (d) {
+ for (j -= SZ_4K, temp_va -= SZ_4K;
+ j > 0; temp_va -= SZ_4K, j -= SZ_4K)
+ iommu_unmap(d, temp_va, SZ_4K);
+ }
/* Unmap all the other domains */
for (i--; i >= 0; i--) {
unsigned int domain_no, partition_no;
@@ -447,10 +452,14 @@
partition_no = msm_subsystem_get_partition_no(
subsys_ids[i]);
- temp_va = buf->iova[i];
- for (j = length; j > 0; j -= SZ_4K,
- temp_va += SZ_4K)
- iommu_unmap(d, temp_va, SZ_4K);
+ d = msm_get_iommu_domain(domain_no);
+
+ if (d) {
+ temp_va = buf->iova[i];
+ for (j = length; j > 0; j -= SZ_4K,
+ temp_va += SZ_4K)
+ iommu_unmap(d, temp_va, SZ_4K);
+ }
msm_free_iova_address(buf->iova[i], domain_no,
partition_no, length);
}
@@ -506,6 +515,9 @@
msm_subsystem_get_domain_no(
node->subsystems[i]));
+ if (!subsys_domain)
+ continue;
+
domain_no = msm_subsystem_get_domain_no(
node->subsystems[i]);
partition_no = msm_subsystem_get_partition_no(
diff --git a/drivers/base/dma-contiguous.c b/drivers/base/dma-contiguous.c
index 81409b0..5064126 100644
--- a/drivers/base/dma-contiguous.c
+++ b/drivers/base/dma-contiguous.c
@@ -61,8 +61,8 @@
* Users, who want to set the size of global CMA area for their system
* should use cma= kernel parameter.
*/
-static const unsigned long size_bytes = CMA_SIZE_MBYTES * SZ_1M;
-static long size_cmdline = -1;
+static const phys_addr_t size_bytes = CMA_SIZE_MBYTES * SZ_1M;
+static phys_addr_t size_cmdline = -1;
static int __init early_cma(char *p)
{
@@ -74,7 +74,7 @@
#ifdef CONFIG_CMA_SIZE_PERCENTAGE
-static unsigned long __init __maybe_unused cma_early_percent_memory(void)
+static phys_addr_t __init __maybe_unused cma_early_percent_memory(void)
{
struct memblock_region *reg;
unsigned long total_pages = 0;
@@ -92,7 +92,7 @@
#else
-static inline __maybe_unused unsigned long cma_early_percent_memory(void)
+static inline __maybe_unused phys_addr_t cma_early_percent_memory(void)
{
return 0;
}
@@ -110,7 +110,7 @@
*/
void __init dma_contiguous_reserve(phys_addr_t limit)
{
- unsigned long selected_size = 0;
+ phys_addr_t selected_size = 0;
pr_debug("%s(limit %08lx)\n", __func__, (unsigned long)limit);
@@ -130,7 +130,7 @@
if (selected_size) {
pr_debug("%s: reserving %ld MiB for global area\n", __func__,
- selected_size / SZ_1M);
+ (unsigned long)selected_size / SZ_1M);
dma_declare_contiguous(NULL, selected_size, 0, limit);
}
@@ -231,11 +231,11 @@
* called by board specific code when early allocator (memblock or bootmem)
* is still activate.
*/
-int __init dma_declare_contiguous(struct device *dev, unsigned long size,
+int __init dma_declare_contiguous(struct device *dev, phys_addr_t size,
phys_addr_t base, phys_addr_t limit)
{
struct cma_reserved *r = &cma_reserved[cma_reserved_count];
- unsigned long alignment;
+ phys_addr_t alignment;
pr_debug("%s(size %lx, base %08lx, limit %08lx)\n", __func__,
(unsigned long)size, (unsigned long)base,
@@ -251,7 +251,7 @@
return -EINVAL;
/* Sanitise input arguments */
- alignment = PAGE_SIZE << max(MAX_ORDER, pageblock_order);
+ alignment = PAGE_SIZE << max(MAX_ORDER - 1, pageblock_order);
base = ALIGN(base, alignment);
size = ALIGN(size, alignment);
limit &= ~(alignment - 1);
@@ -272,10 +272,6 @@
if (!addr) {
base = -ENOMEM;
goto err;
- } else if (addr + size > ~(unsigned long)0) {
- memblock_free(addr, size);
- base = -EINVAL;
- goto err;
} else {
base = addr;
}
@@ -289,14 +285,14 @@
r->size = size;
r->dev = dev;
cma_reserved_count++;
- pr_info("CMA: reserved %ld MiB at %08lx\n", size / SZ_1M,
+ pr_info("CMA: reserved %ld MiB at %08lx\n", (unsigned long)size / SZ_1M,
(unsigned long)base);
/* Architecture specific contiguous memory fixup. */
dma_contiguous_early_fixup(base, size);
return 0;
err:
- pr_err("CMA: failed to reserve %ld MiB\n", size / SZ_1M);
+ pr_err("CMA: failed to reserve %ld MiB\n", (unsigned long)size / SZ_1M);
return base;
}
@@ -316,6 +312,7 @@
{
unsigned long mask, pfn, pageno, start = 0;
struct cma *cma = dev_get_cma_area(dev);
+ struct page *page = NULL;
int ret;
int tries = 0;
@@ -338,18 +335,17 @@
for (;;) {
pageno = bitmap_find_next_zero_area(cma->bitmap, cma->count,
start, count, mask);
- if (pageno >= cma->count) {
- ret = -ENOMEM;
- goto error;
- }
+ if (pageno >= cma->count)
+ break;
pfn = cma->base_pfn + pageno;
ret = alloc_contig_range(pfn, pfn + count, MIGRATE_CMA);
if (ret == 0) {
bitmap_set(cma->bitmap, pageno, count);
+ page = pfn_to_page(pfn);
break;
} else if (ret != -EBUSY) {
- goto error;
+ break;
}
tries++;
trace_dma_alloc_contiguous_retry(tries);
@@ -361,12 +357,8 @@
}
mutex_unlock(&cma_mutex);
-
- pr_debug("%s(): returned %p\n", __func__, pfn_to_page(pfn));
- return pfn_to_page(pfn);
-error:
- mutex_unlock(&cma_mutex);
- return NULL;
+ pr_debug("%s(): returned %p\n", __func__, page);
+ return page;
}
/**
diff --git a/drivers/base/sync.c b/drivers/base/sync.c
index a97a503..2e35996 100644
--- a/drivers/base/sync.c
+++ b/drivers/base/sync.c
@@ -616,9 +616,11 @@
}
if (fence->status == 0) {
- pr_info("fence timeout on [%p] after %dms\n", fence,
- jiffies_to_msecs(timeout));
- sync_dump();
+ if (timeout > 0) {
+ pr_info("fence timeout on [%p] after %dms\n", fence,
+ jiffies_to_msecs(timeout));
+ sync_dump();
+ }
return -ETIME;
}
diff --git a/drivers/bluetooth/bluetooth-power.c b/drivers/bluetooth/bluetooth-power.c
index 718df02..d7c69db 100644
--- a/drivers/bluetooth/bluetooth-power.c
+++ b/drivers/bluetooth/bluetooth-power.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2010, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2009-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
@@ -20,9 +20,43 @@
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/rfkill.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/delay.h>
+
+static struct of_device_id ar3002_match_table[] = {
+ { .compatible = "qca,ar3002" },
+ {}
+};
+
+static int bt_reset_gpio;
static bool previous;
+static int bluetooth_power(int on)
+{
+ int rc;
+
+ pr_debug("%s bt_gpio= %d\n", __func__, bt_reset_gpio);
+ if (on) {
+ rc = gpio_direction_output(bt_reset_gpio, 1);
+ if (rc) {
+ pr_err("%s: Unable to set direction\n", __func__);
+ return rc;
+ }
+ msleep(100);
+ } else {
+ gpio_set_value(bt_reset_gpio, 0);
+ rc = gpio_direction_input(bt_reset_gpio);
+ if (rc) {
+ pr_err("%s: Unable to set direction\n", __func__);
+ return rc;
+ }
+ msleep(100);
+ }
+ return 0;
+}
+
static int bluetooth_toggle_radio(void *data, bool blocked)
{
int ret = 0;
@@ -90,8 +124,36 @@
dev_dbg(&pdev->dev, "%s\n", __func__);
if (!pdev->dev.platform_data) {
- dev_err(&pdev->dev, "platform data not initialized\n");
- return -ENOSYS;
+ /* Update the platform data if the
+ device node exists as part of device tree.*/
+ if (pdev->dev.of_node) {
+ pdev->dev.platform_data = bluetooth_power;
+ } else {
+ dev_err(&pdev->dev, "device node not set\n");
+ return -ENOSYS;
+ }
+ }
+ if (pdev->dev.of_node) {
+ bt_reset_gpio = of_get_named_gpio(pdev->dev.of_node,
+ "qca,bt-reset-gpio", 0);
+ if (bt_reset_gpio < 0) {
+ pr_err("bt-reset-gpio not available");
+ return bt_reset_gpio;
+ }
+ }
+
+ ret = gpio_request(bt_reset_gpio, "bt sys_rst_n");
+ if (ret) {
+ pr_err("%s: unable to request gpio %d (%d)\n",
+ __func__, bt_reset_gpio, ret);
+ return ret;
+ }
+
+ /* When booting up, de-assert BT reset pin */
+ ret = gpio_direction_output(bt_reset_gpio, 0);
+ if (ret) {
+ pr_err("%s: Unable to set direction\n", __func__);
+ return ret;
}
ret = bluetooth_power_rfkill_probe(pdev);
@@ -114,6 +176,7 @@
.driver = {
.name = "bt_power",
.owner = THIS_MODULE,
+ .of_match_table = ar3002_match_table,
},
};
diff --git a/drivers/char/diag/diagfwd_hsic.c b/drivers/char/diag/diagfwd_hsic.c
index aa55578..616c498 100644
--- a/drivers/char/diag/diagfwd_hsic.c
+++ b/drivers/char/diag/diagfwd_hsic.c
@@ -45,6 +45,7 @@
struct diag_hsic_dev *hsic_struct = container_of(work,
struct diag_hsic_dev, diag_read_hsic_work);
int index = hsic_struct->id;
+ static DEFINE_RATELIMIT_STATE(rl, 10*HZ, 1);
if (!diag_hsic[index].hsic_ch) {
pr_err("DIAG in %s: diag_hsic[index].hsic_ch == 0\n", __func__);
@@ -103,7 +104,8 @@
diagmem_free(driver, buf_in_hsic,
index+POOL_TYPE_HSIC);
- pr_err_ratelimited("diag: Error initiating HSIC read, err: %d\n",
+ if (__ratelimit(&rl))
+ pr_err("diag: Error initiating HSIC read, err: %d\n",
err);
/*
* An error occurred, discontinue queuing
@@ -132,6 +134,7 @@
{
int err = -2;
int index = (int)ctxt;
+ static DEFINE_RATELIMIT_STATE(rl, 10*HZ, 1);
if (!diag_hsic[index].hsic_ch) {
/*
@@ -164,7 +167,8 @@
if (err) {
diagmem_free(driver, buf, index +
POOL_TYPE_HSIC);
- pr_err_ratelimited("diag: In %s, error calling diag_device_write, err: %d\n",
+ if (__ratelimit(&rl))
+ pr_err("diag: In %s, error calling diag_device_write, err: %d\n",
__func__, err);
}
}
diff --git a/drivers/coresight/Kconfig b/drivers/coresight/Kconfig
index c77df95..5e00570 100644
--- a/drivers/coresight/Kconfig
+++ b/drivers/coresight/Kconfig
@@ -24,6 +24,14 @@
config HAVE_CORESIGHT_SINK
bool
+config CORESIGHT_CTI
+ bool "CoreSight Cross Trigger Interface driver"
+ help
+ This driver provides support for Cross Trigger Interface that is
+ used to input or output i.e. pass cross trigger events from one
+ hardware component to another. It can also be used to pass
+ software generated events.
+
config CORESIGHT_CSR
bool "CoreSight Slave Register driver"
help
@@ -32,6 +40,7 @@
config CORESIGHT_TMC
bool "CoreSight Trace Memory Controller driver"
+ select CORESIGHT_CTI
select CORESIGHT_CSR
select HAVE_CORESIGHT_SINK
help
diff --git a/drivers/coresight/Makefile b/drivers/coresight/Makefile
index 8c73794..0595064 100644
--- a/drivers/coresight/Makefile
+++ b/drivers/coresight/Makefile
@@ -3,6 +3,7 @@
#
obj-$(CONFIG_CORESIGHT) += coresight.o
obj-$(CONFIG_OF) += of_coresight.o
+obj-$(CONFIG_CORESIGHT_CTI) += coresight-cti.o
obj-$(CONFIG_CORESIGHT_CSR) += coresight-csr.o
obj-$(CONFIG_CORESIGHT_TMC) += coresight-tmc.o
obj-$(CONFIG_CORESIGHT_TPIU) += coresight-tpiu.o
diff --git a/drivers/coresight/coresight-cti.c b/drivers/coresight/coresight-cti.c
new file mode 100644
index 0000000..e077edf
--- /dev/null
+++ b/drivers/coresight/coresight-cti.c
@@ -0,0 +1,481 @@
+/* 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/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/clk.h>
+#include <linux/of_coresight.h>
+#include <linux/coresight.h>
+#include <linux/coresight-cti.h>
+
+#include "coresight-priv.h"
+
+#define cti_writel(drvdata, val, off) __raw_writel((val), drvdata->base + off)
+#define cti_readl(drvdata, off) __raw_readl(drvdata->base + off)
+
+#define CTI_LOCK(drvdata) \
+do { \
+ mb(); \
+ cti_writel(drvdata, 0x0, CORESIGHT_LAR); \
+} while (0)
+#define CTI_UNLOCK(drvdata) \
+do { \
+ cti_writel(drvdata, CORESIGHT_UNLOCK, CORESIGHT_LAR); \
+ mb(); \
+} while (0)
+
+#define CTICONTROL (0x000)
+#define CTIINTACK (0x010)
+#define CTIAPPSET (0x014)
+#define CTIAPPCLEAR (0x018)
+#define CTIAPPPULSE (0x01C)
+#define CTIINEN(n) (0x020 + (n * 4))
+#define CTIOUTEN(n) (0x0A0 + (n * 4))
+#define CTITRIGINSTATUS (0x130)
+#define CTITRIGOUTSTATUS (0x134)
+#define CTICHINSTATUS (0x138)
+#define CTICHOUTSTATUS (0x13C)
+#define CTIGATE (0x140)
+#define ASICCTL (0x144)
+#define ITCHINACK (0xEDC)
+#define ITTRIGINACK (0xEE0)
+#define ITCHOUT (0xEE4)
+#define ITTRIGOUT (0xEE8)
+#define ITCHOUTACK (0xEEC)
+#define ITTRIGOUTACK (0xEF0)
+#define ITCHIN (0xEF4)
+#define ITTRIGIN (0xEF8)
+
+#define CTI_MAX_TRIGGERS (8)
+#define CTI_MAX_CHANNELS (4)
+
+#define to_cti_drvdata(c) container_of(c, struct cti_drvdata, cti)
+
+struct cti_drvdata {
+ void __iomem *base;
+ struct device *dev;
+ struct coresight_device *csdev;
+ struct clk *clk;
+ struct mutex mutex;
+ struct coresight_cti cti;
+ int refcnt;
+};
+
+static LIST_HEAD(cti_list);
+static DEFINE_MUTEX(cti_lock);
+
+static int cti_verify_bounds(int trig, int ch)
+{
+ if (trig >= CTI_MAX_TRIGGERS)
+ return -EINVAL;
+
+ if (ch >= CTI_MAX_CHANNELS)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int cti_enable(struct cti_drvdata *drvdata)
+{
+ int ret;
+
+ ret = clk_prepare_enable(drvdata->clk);
+ if (ret)
+ return ret;
+
+ CTI_UNLOCK(drvdata);
+
+ cti_writel(drvdata, 0x1, CTICONTROL);
+
+ CTI_LOCK(drvdata);
+ return 0;
+}
+
+static void __cti_map_trigin(struct cti_drvdata *drvdata, int trig, int ch)
+{
+ uint32_t ctien;
+
+ CTI_UNLOCK(drvdata);
+
+ ctien = cti_readl(drvdata, CTIINEN(trig));
+ cti_writel(drvdata, (ctien | 0x1 << ch), CTIINEN(trig));
+
+ CTI_LOCK(drvdata);
+}
+
+int coresight_cti_map_trigin(struct coresight_cti *cti, int trig, int ch)
+{
+ struct cti_drvdata *drvdata;
+ int ret = 0;
+
+ if (IS_ERR_OR_NULL(cti))
+ return -EINVAL;
+
+ ret = cti_verify_bounds(trig, ch);
+ if (ret)
+ return ret;
+
+ drvdata = to_cti_drvdata(cti);
+
+ mutex_lock(&drvdata->mutex);
+ if (drvdata->refcnt == 0) {
+ ret = cti_enable(drvdata);
+ if (ret)
+ goto err;
+ }
+ drvdata->refcnt++;
+
+ __cti_map_trigin(drvdata, trig, ch);
+err:
+ mutex_unlock(&drvdata->mutex);
+ return ret;
+}
+EXPORT_SYMBOL(coresight_cti_map_trigin);
+
+static void __cti_map_trigout(struct cti_drvdata *drvdata, int trig, int ch)
+{
+ uint32_t ctien;
+
+ CTI_UNLOCK(drvdata);
+
+ ctien = cti_readl(drvdata, CTIOUTEN(trig));
+ cti_writel(drvdata, (ctien | 0x1 << ch), CTIOUTEN(trig));
+
+ CTI_LOCK(drvdata);
+}
+
+int coresight_cti_map_trigout(struct coresight_cti *cti, int trig, int ch)
+{
+ struct cti_drvdata *drvdata;
+ int ret = 0;
+
+ if (IS_ERR_OR_NULL(cti))
+ return -EINVAL;
+
+ ret = cti_verify_bounds(trig, ch);
+ if (ret)
+ return ret;
+
+ drvdata = to_cti_drvdata(cti);
+
+ mutex_lock(&drvdata->mutex);
+ if (drvdata->refcnt == 0) {
+ ret = cti_enable(drvdata);
+ if (ret)
+ goto err;
+ }
+ drvdata->refcnt++;
+
+ __cti_map_trigout(drvdata, trig, ch);
+err:
+ mutex_unlock(&drvdata->mutex);
+ return ret;
+}
+EXPORT_SYMBOL(coresight_cti_map_trigout);
+
+static void cti_disable(struct cti_drvdata *drvdata)
+{
+ CTI_UNLOCK(drvdata);
+
+ cti_writel(drvdata, 0x1, CTICONTROL);
+
+ CTI_LOCK(drvdata);
+}
+
+static void __cti_unmap_trigin(struct cti_drvdata *drvdata, int trig, int ch)
+{
+ uint32_t ctien;
+
+ CTI_UNLOCK(drvdata);
+
+ ctien = cti_readl(drvdata, CTIINEN(trig));
+ cti_writel(drvdata, (ctien & ~(0x1 << ch)), CTIINEN(trig));
+
+ CTI_LOCK(drvdata);
+}
+
+void coresight_cti_unmap_trigin(struct coresight_cti *cti, int trig, int ch)
+{
+ struct cti_drvdata *drvdata;
+
+ if (IS_ERR_OR_NULL(cti))
+ return;
+
+ if (cti_verify_bounds(trig, ch))
+ return;
+
+ drvdata = to_cti_drvdata(cti);
+
+ mutex_lock(&drvdata->mutex);
+ __cti_unmap_trigin(drvdata, trig, ch);
+
+ if (drvdata->refcnt == 1)
+ cti_disable(drvdata);
+ drvdata->refcnt--;
+ mutex_unlock(&drvdata->mutex);
+
+ clk_disable_unprepare(drvdata->clk);
+}
+EXPORT_SYMBOL(coresight_cti_unmap_trigin);
+
+static void __cti_unmap_trigout(struct cti_drvdata *drvdata, int trig, int ch)
+{
+ uint32_t ctien;
+
+ CTI_UNLOCK(drvdata);
+
+ ctien = cti_readl(drvdata, CTIOUTEN(trig));
+ cti_writel(drvdata, (ctien & ~(0x1 << ch)), CTIOUTEN(trig));
+
+ CTI_LOCK(drvdata);
+}
+
+void coresight_cti_unmap_trigout(struct coresight_cti *cti, int trig, int ch)
+{
+ struct cti_drvdata *drvdata;
+
+ if (IS_ERR_OR_NULL(cti))
+ return;
+
+ if (cti_verify_bounds(trig, ch))
+ return;
+
+ drvdata = to_cti_drvdata(cti);
+
+ mutex_lock(&drvdata->mutex);
+ __cti_unmap_trigout(drvdata, trig, ch);
+
+ if (drvdata->refcnt == 1)
+ cti_disable(drvdata);
+ drvdata->refcnt--;
+ mutex_unlock(&drvdata->mutex);
+
+ clk_disable_unprepare(drvdata->clk);
+}
+EXPORT_SYMBOL(coresight_cti_unmap_trigout);
+
+struct coresight_cti *coresight_cti_get(const char *name)
+{
+ struct coresight_cti *cti;
+
+ mutex_lock(&cti_lock);
+ list_for_each_entry(cti, &cti_list, link) {
+ if (!strncmp(cti->name, name, strlen(cti->name) + 1)) {
+ mutex_unlock(&cti_lock);
+ return cti;
+ }
+ }
+ mutex_unlock(&cti_lock);
+
+ return ERR_PTR(-EINVAL);
+}
+EXPORT_SYMBOL(coresight_cti_get);
+
+void coresight_cti_put(struct coresight_cti *cti)
+{
+}
+EXPORT_SYMBOL(coresight_cti_put);
+
+static ssize_t cti_store_map_trigin(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ unsigned long val1, val2;
+ int ret;
+
+ if (sscanf(buf, "%lx %lx", &val1, &val2) != 2)
+ return -EINVAL;
+
+ ret = coresight_cti_map_trigin(&drvdata->cti, val1, val2);
+
+ if (ret)
+ return ret;
+ return size;
+}
+static DEVICE_ATTR(map_trigin, S_IWUSR, NULL, cti_store_map_trigin);
+
+static ssize_t cti_store_map_trigout(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ unsigned long val1, val2;
+ int ret;
+
+ if (sscanf(buf, "%lx %lx", &val1, &val2) != 2)
+ return -EINVAL;
+
+ ret = coresight_cti_map_trigout(&drvdata->cti, val1, val2);
+
+ if (ret)
+ return ret;
+ return size;
+}
+static DEVICE_ATTR(map_trigout, S_IWUSR, NULL, cti_store_map_trigout);
+
+static ssize_t cti_store_unmap_trigin(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ unsigned long val1, val2;
+
+ if (sscanf(buf, "%lx %lx", &val1, &val2) != 2)
+ return -EINVAL;
+
+ coresight_cti_unmap_trigin(&drvdata->cti, val1, val2);
+
+ return size;
+}
+static DEVICE_ATTR(unmap_trigin, S_IWUSR, NULL, cti_store_unmap_trigin);
+
+static ssize_t cti_store_unmap_trigout(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ unsigned long val1, val2;
+
+ if (sscanf(buf, "%lx %lx", &val1, &val2) != 2)
+ return -EINVAL;
+
+ coresight_cti_unmap_trigout(&drvdata->cti, val1, val2);
+
+ return size;
+}
+static DEVICE_ATTR(unmap_trigout, S_IWUSR, NULL, cti_store_unmap_trigout);
+
+static struct attribute *cti_attrs[] = {
+ &dev_attr_map_trigin.attr,
+ &dev_attr_map_trigout.attr,
+ &dev_attr_unmap_trigin.attr,
+ &dev_attr_unmap_trigout.attr,
+ NULL,
+};
+
+static struct attribute_group cti_attr_grp = {
+ .attrs = cti_attrs,
+};
+
+static const struct attribute_group *cti_attr_grps[] = {
+ &cti_attr_grp,
+ NULL,
+};
+
+static int __devinit cti_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct device *dev = &pdev->dev;
+ struct coresight_platform_data *pdata;
+ struct cti_drvdata *drvdata;
+ struct resource *res;
+ struct coresight_desc *desc;
+
+ if (pdev->dev.of_node) {
+ pdata = of_get_coresight_platform_data(dev, pdev->dev.of_node);
+ if (IS_ERR(pdata))
+ return PTR_ERR(pdata);
+ pdev->dev.platform_data = pdata;
+ }
+
+ drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
+ if (!drvdata)
+ return -ENOMEM;
+ /* Store the driver data pointer for use in exported functions */
+ drvdata->dev = &pdev->dev;
+ platform_set_drvdata(pdev, drvdata);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+
+ drvdata->base = devm_ioremap(dev, res->start, resource_size(res));
+ if (!drvdata->base)
+ return -ENOMEM;
+
+ mutex_init(&drvdata->mutex);
+
+ drvdata->clk = devm_clk_get(dev, "core_clk");
+ if (IS_ERR(drvdata->clk))
+ return PTR_ERR(drvdata->clk);
+
+ ret = clk_set_rate(drvdata->clk, CORESIGHT_CLK_RATE_TRACE);
+ if (ret)
+ return ret;
+
+ mutex_lock(&cti_lock);
+ drvdata->cti.name = ((struct coresight_platform_data *)
+ (pdev->dev.platform_data))->name;
+ list_add_tail(&drvdata->cti.link, &cti_list);
+ mutex_unlock(&cti_lock);
+
+ desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
+ if (!desc)
+ return -ENOMEM;
+ desc->type = CORESIGHT_DEV_TYPE_NONE;
+ desc->pdata = pdev->dev.platform_data;
+ desc->dev = &pdev->dev;
+ desc->groups = cti_attr_grps;
+ desc->owner = THIS_MODULE;
+ drvdata->csdev = coresight_register(desc);
+ if (IS_ERR(drvdata->csdev))
+ return PTR_ERR(drvdata->csdev);
+
+ dev_info(dev, "CTI initialized\n");
+ return 0;
+}
+
+static int __devexit cti_remove(struct platform_device *pdev)
+{
+ struct cti_drvdata *drvdata = platform_get_drvdata(pdev);
+
+ coresight_unregister(drvdata->csdev);
+ return 0;
+}
+
+static struct of_device_id cti_match[] = {
+ {.compatible = "arm,coresight-cti"},
+ {}
+};
+
+static struct platform_driver cti_driver = {
+ .probe = cti_probe,
+ .remove = __devexit_p(cti_remove),
+ .driver = {
+ .name = "coresight-cti",
+ .owner = THIS_MODULE,
+ .of_match_table = cti_match,
+ },
+};
+
+static int __init cti_init(void)
+{
+ return platform_driver_register(&cti_driver);
+}
+module_init(cti_init);
+
+static void __exit cti_exit(void)
+{
+ platform_driver_unregister(&cti_driver);
+}
+module_exit(cti_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CoreSight CTI driver");
diff --git a/drivers/coresight/coresight-tmc.c b/drivers/coresight/coresight-tmc.c
index 10eabca..d9ab7e4 100644
--- a/drivers/coresight/coresight-tmc.c
+++ b/drivers/coresight/coresight-tmc.c
@@ -29,6 +29,7 @@
#include <linux/of.h>
#include <linux/of_coresight.h>
#include <linux/coresight.h>
+#include <linux/coresight-cti.h>
#include <linux/usb/usb_qdss.h>
#include <mach/memory.h>
#include <mach/sps.h>
@@ -136,6 +137,8 @@
struct miscdevice miscdev;
struct clk *clk;
spinlock_t spinlock;
+ struct coresight_cti *cti_flush;
+ struct coresight_cti *cti_reset;
struct mutex read_lock;
int read_count;
bool reading;
@@ -372,7 +375,7 @@
TMC_UNLOCK(drvdata);
tmc_writel(drvdata, TMC_MODE_CIRCULAR_BUFFER, TMC_MODE);
- tmc_writel(drvdata, 0x133, TMC_FFCR);
+ tmc_writel(drvdata, 0x1133, TMC_FFCR);
tmc_writel(drvdata, drvdata->trigger_cntr, TMC_TRG);
__tmc_enable(drvdata);
@@ -430,7 +433,10 @@
return ret;
mutex_lock(&drvdata->usb_lock);
- if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
+ if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) {
+ coresight_cti_map_trigout(drvdata->cti_flush, 1, 0);
+ coresight_cti_map_trigin(drvdata->cti_reset, 0, 0);
+ } else if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
if (drvdata->out_mode == TMC_ETR_OUT_MODE_USB) {
drvdata->usbch = usb_qdss_open("qdss", drvdata,
usb_notifier);
@@ -440,6 +446,11 @@
goto err0;
}
}
+ } else {
+ if (mode == TMC_MODE_CIRCULAR_BUFFER) {
+ coresight_cti_map_trigout(drvdata->cti_flush, 1, 0);
+ coresight_cti_map_trigin(drvdata->cti_reset, 0, 0);
+ }
}
spin_lock_irqsave(&drvdata->spinlock, flags);
@@ -632,7 +643,6 @@
static void tmc_disable(struct tmc_drvdata *drvdata, enum tmc_mode mode)
{
unsigned long flags;
- bool etr_bam_disable = false;
mutex_lock(&drvdata->usb_lock);
spin_lock_irqsave(&drvdata->spinlock, flags);
@@ -645,27 +655,28 @@
if (drvdata->out_mode == TMC_ETR_OUT_MODE_MEM)
__tmc_etr_disable_to_mem(drvdata);
else if (drvdata->out_mode == TMC_ETR_OUT_MODE_USB)
- etr_bam_disable = true;
+ __tmc_etr_disable_to_bam(drvdata);
} else {
if (mode == TMC_MODE_CIRCULAR_BUFFER)
__tmc_etb_disable(drvdata);
else
__tmc_etf_disable(drvdata);
}
-out:
drvdata->enable = false;
spin_unlock_irqrestore(&drvdata->spinlock, flags);
- if (etr_bam_disable) {
- if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
- if (drvdata->out_mode == TMC_ETR_OUT_MODE_USB) {
- spin_lock_irqsave(&drvdata->spinlock, flags);
- __tmc_etr_disable_to_bam(drvdata);
- spin_unlock_irqrestore(&drvdata->spinlock,
- flags);
- tmc_etr_bam_disable(drvdata);
- usb_qdss_close(drvdata->usbch);
- }
+ if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) {
+ coresight_cti_unmap_trigin(drvdata->cti_reset, 0, 0);
+ coresight_cti_unmap_trigout(drvdata->cti_flush, 1, 0);
+ } else if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
+ if (drvdata->out_mode == TMC_ETR_OUT_MODE_USB) {
+ tmc_etr_bam_disable(drvdata);
+ usb_qdss_close(drvdata->usbch);
+ }
+ } else {
+ if (mode == TMC_MODE_CIRCULAR_BUFFER) {
+ coresight_cti_unmap_trigin(drvdata->cti_reset, 0, 0);
+ coresight_cti_unmap_trigout(drvdata->cti_flush, 1, 0);
}
}
mutex_unlock(&drvdata->usb_lock);
@@ -673,6 +684,15 @@
clk_disable_unprepare(drvdata->clk);
dev_info(drvdata->dev, "TMC disabled\n");
+ return;
+out:
+ drvdata->enable = false;
+ spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ mutex_unlock(&drvdata->usb_lock);
+
+ clk_disable_unprepare(drvdata->clk);
+
+ dev_info(drvdata->dev, "TMC disabled\n");
}
static void tmc_disable_sink(struct coresight_device *csdev)
@@ -1091,6 +1111,7 @@
static int count;
void *baddr;
struct msm_client_dump dump;
+ struct coresight_cti_data *ctidata;
struct coresight_desc *desc;
if (pdev->dev.of_node) {
@@ -1209,6 +1230,23 @@
}
count++;
+ if (pdev->dev.of_node) {
+ ctidata = of_get_coresight_cti_data(dev, pdev->dev.of_node);
+ if (IS_ERR(ctidata)) {
+ dev_err(dev, "invalid cti data\n");
+ } else if (ctidata && ctidata->nr_ctis == 2) {
+ drvdata->cti_flush = coresight_cti_get(
+ ctidata->names[0]);
+ if (IS_ERR(drvdata->cti_flush))
+ dev_err(dev, "failed to get flush cti\n");
+
+ drvdata->cti_reset = coresight_cti_get(
+ ctidata->names[1]);
+ if (IS_ERR(drvdata->cti_reset))
+ dev_err(dev, "failed to get reset cti\n");
+ }
+ }
+
desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
if (!desc) {
ret = -ENOMEM;
diff --git a/drivers/coresight/of_coresight.c b/drivers/coresight/of_coresight.c
index a9d0182..1eccd09 100644
--- a/drivers/coresight/of_coresight.c
+++ b/drivers/coresight/of_coresight.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
@@ -16,6 +16,7 @@
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/coresight.h>
+#include <linux/coresight-cti.h>
struct coresight_platform_data *of_get_coresight_platform_data(
struct device *dev, struct device_node *node)
@@ -97,3 +98,45 @@
return pdata;
}
EXPORT_SYMBOL_GPL(of_get_coresight_platform_data);
+
+struct coresight_cti_data *of_get_coresight_cti_data(
+ struct device *dev, struct device_node *node)
+{
+ int i, ret;
+ uint32_t ctis_len;
+ struct device_node *child_node;
+ struct coresight_cti_data *ctidata;
+
+ ctidata = devm_kzalloc(dev, sizeof(*ctidata), GFP_KERNEL);
+ if (!ctidata)
+ return ERR_PTR(-ENOMEM);
+
+ if (of_get_property(node, "coresight-ctis", &ctis_len))
+ ctidata->nr_ctis = ctis_len/sizeof(uint32_t);
+ else
+ return ERR_PTR(-EINVAL);
+
+ if (ctidata->nr_ctis) {
+ ctidata->names = devm_kzalloc(dev, ctidata->nr_ctis *
+ sizeof(*ctidata->names),
+ GFP_KERNEL);
+ if (!ctidata->names)
+ return ERR_PTR(-ENOMEM);
+
+ for (i = 0; i < ctidata->nr_ctis; i++) {
+ child_node = of_parse_phandle(node, "coresight-ctis",
+ i);
+ if (!child_node)
+ return ERR_PTR(-EINVAL);
+
+ ret = of_property_read_string(child_node,
+ "coresight-name",
+ &ctidata->names[i]);
+ of_node_put(child_node);
+ if (ret)
+ return ERR_PTR(ret);
+ }
+ }
+ return ctidata;
+}
+EXPORT_SYMBOL(of_get_coresight_cti_data);
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index 2f0083a..3e3e3e4 100644
--- a/drivers/cpuidle/cpuidle.c
+++ b/drivers/cpuidle/cpuidle.c
@@ -103,6 +103,34 @@
}
/**
+ * cpuidle_enter_state - enter the state and update stats
+ * @dev: cpuidle device for this cpu
+ * @drv: cpuidle driver for this cpu
+ * @next_state: index into drv->states of the state to enter
+ */
+int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv,
+ int next_state)
+{
+ int entered_state;
+
+ entered_state = cpuidle_enter_ops(dev, drv, next_state);
+
+ if (entered_state >= 0) {
+ /* Update cpuidle counters */
+ /* This can be moved to within driver enter routine
+ * but that results in multiple copies of same code.
+ */
+ dev->states_usage[entered_state].time +=
+ (unsigned long long)dev->last_residency;
+ dev->states_usage[entered_state].usage++;
+ } else {
+ dev->last_residency = 0;
+ }
+
+ return entered_state;
+}
+
+/**
* cpuidle_idle_call - the main idle loop
*
* NOTE: no locks or semaphores should be used here
@@ -143,23 +171,11 @@
trace_power_start_rcuidle(POWER_CSTATE, next_state, dev->cpu);
trace_cpu_idle_rcuidle(next_state, dev->cpu);
- entered_state = cpuidle_enter_ops(dev, drv, next_state);
+ entered_state = cpuidle_enter_state(dev, drv, next_state);
trace_power_end_rcuidle(dev->cpu);
trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, dev->cpu);
- if (entered_state >= 0) {
- /* Update cpuidle counters */
- /* This can be moved to within driver enter routine
- * but that results in multiple copies of same code.
- */
- dev->states_usage[entered_state].time +=
- (unsigned long long)dev->last_residency;
- dev->states_usage[entered_state].usage++;
- } else {
- dev->last_residency = 0;
- }
-
/* give the governor an opportunity to reflect on the outcome */
if (cpuidle_curr_governor->reflect)
cpuidle_curr_governor->reflect(dev, entered_state);
diff --git a/drivers/cpuidle/cpuidle.h b/drivers/cpuidle/cpuidle.h
index 7db1866..d8a3ccc 100644
--- a/drivers/cpuidle/cpuidle.h
+++ b/drivers/cpuidle/cpuidle.h
@@ -14,6 +14,8 @@
extern struct mutex cpuidle_lock;
extern spinlock_t cpuidle_driver_lock;
extern int cpuidle_disabled(void);
+extern int cpuidle_enter_state(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv, int next_state);
/* idle loop */
extern void cpuidle_install_idle_handler(void);
diff --git a/drivers/gpu/ion/Kconfig b/drivers/gpu/ion/Kconfig
index 5bb254b..39133b5 100644
--- a/drivers/gpu/ion/Kconfig
+++ b/drivers/gpu/ion/Kconfig
@@ -16,3 +16,12 @@
depends on ARCH_MSM && ION
help
Choose this option if you wish to use ion on an MSM target.
+
+config ION_LEAK_CHECK
+ bool "Check for leaked Ion buffers (debugging)"
+ depends on ION
+ help
+ Choose this option if you wish to enable checking for leaked
+ ion buffers at runtime. Choosing this option will also add a
+ debugfs node under the ion directory that can be used to
+ enable/disable the leak checking.
diff --git a/drivers/gpu/ion/ion.c b/drivers/gpu/ion/ion.c
index 82403d2..0904f9fe 100644
--- a/drivers/gpu/ion/ion.c
+++ b/drivers/gpu/ion/ion.c
@@ -1024,10 +1024,91 @@
return client;
}
+/**
+ * ion_mark_dangling_buffers_locked() - Mark dangling buffers
+ * @dev: the ion device whose buffers will be searched
+ *
+ * Sets marked=1 for all known buffers associated with `dev' that no
+ * longer have a handle pointing to them. dev->lock should be held
+ * across a call to this function (and should only be unlocked after
+ * checking for marked buffers).
+ */
+static void ion_mark_dangling_buffers_locked(struct ion_device *dev)
+{
+ struct rb_node *n, *n2;
+ /* mark all buffers as 1 */
+ for (n = rb_first(&dev->buffers); n; n = rb_next(n)) {
+ struct ion_buffer *buf = rb_entry(n, struct ion_buffer,
+ node);
+
+ buf->marked = 1;
+ }
+
+ /* now see which buffers we can access */
+ for (n = rb_first(&dev->clients); n; n = rb_next(n)) {
+ struct ion_client *client = rb_entry(n, struct ion_client,
+ node);
+
+ mutex_lock(&client->lock);
+ for (n2 = rb_first(&client->handles); n2; n2 = rb_next(n2)) {
+ struct ion_handle *handle
+ = rb_entry(n2, struct ion_handle, node);
+
+ handle->buffer->marked = 0;
+
+ }
+ mutex_unlock(&client->lock);
+
+ }
+}
+
+#ifdef CONFIG_ION_LEAK_CHECK
+static u32 ion_debug_check_leaks_on_destroy;
+
+static int ion_check_for_and_print_leaks(struct ion_device *dev)
+{
+ struct rb_node *n;
+ int num_leaks = 0;
+
+ if (!ion_debug_check_leaks_on_destroy)
+ return 0;
+
+ /* check for leaked buffers (those that no longer have a
+ * handle pointing to them) */
+ ion_mark_dangling_buffers_locked(dev);
+
+ /* Anyone still marked as a 1 means a leaked handle somewhere */
+ for (n = rb_first(&dev->buffers); n; n = rb_next(n)) {
+ struct ion_buffer *buf = rb_entry(n, struct ion_buffer,
+ node);
+
+ if (buf->marked == 1) {
+ pr_info("Leaked ion buffer at %p\n", buf);
+ num_leaks++;
+ }
+ }
+ return num_leaks;
+}
+static void setup_ion_leak_check(struct dentry *debug_root)
+{
+ debugfs_create_bool("check_leaks_on_destroy", 0664, debug_root,
+ &ion_debug_check_leaks_on_destroy);
+}
+#else
+static int ion_check_for_and_print_leaks(struct ion_device *dev)
+{
+ return 0;
+}
+static void setup_ion_leak_check(struct dentry *debug_root)
+{
+}
+#endif
+
void ion_client_destroy(struct ion_client *client)
{
struct ion_device *dev = client->dev;
struct rb_node *n;
+ int num_leaks;
pr_debug("%s: %d\n", __func__, __LINE__);
while ((n = rb_first(&client->handles))) {
@@ -1040,8 +1121,21 @@
put_task_struct(client->task);
rb_erase(&client->node, &dev->clients);
debugfs_remove_recursive(client->debug_root);
+
+ num_leaks = ion_check_for_and_print_leaks(dev);
+
mutex_unlock(&dev->lock);
+ if (num_leaks) {
+ struct task_struct *current_task = current;
+ char current_task_name[TASK_COMM_LEN];
+ get_task_comm(current_task_name, current_task);
+ WARN(1, "%s: Detected %d leaked ion buffer%s.\n",
+ __func__, num_leaks, num_leaks == 1 ? "" : "s");
+ pr_info("task name at time of leak: %s, pid: %d\n",
+ current_task_name, current_task->pid);
+ }
+
kfree(client->name);
kfree(client);
}
@@ -1126,33 +1220,17 @@
{
}
-static void ion_vma_open(struct vm_area_struct *vma)
-{
- struct ion_buffer *buffer = vma->vm_private_data;
-
- pr_debug("%s: %d\n", __func__, __LINE__);
-
- mutex_lock(&buffer->lock);
- buffer->umap_cnt++;
- mutex_unlock(&buffer->lock);
-}
-
static void ion_vma_close(struct vm_area_struct *vma)
{
struct ion_buffer *buffer = vma->vm_private_data;
pr_debug("%s: %d\n", __func__, __LINE__);
- mutex_lock(&buffer->lock);
- buffer->umap_cnt--;
- mutex_unlock(&buffer->lock);
-
if (buffer->heap->ops->unmap_user)
buffer->heap->ops->unmap_user(buffer->heap, buffer);
}
static struct vm_operations_struct ion_vm_ops = {
- .open = ion_vma_open,
.close = ion_vma_close,
};
@@ -1176,7 +1254,6 @@
pr_err("%s: failure mapping buffer to userspace\n",
__func__);
} else {
- buffer->umap_cnt++;
mutex_unlock(&buffer->lock);
vma->vm_ops = &ion_vm_ops;
@@ -1414,9 +1491,6 @@
case ION_IOC_CLEAN_INV_CACHES:
return client->dev->custom_ioctl(client,
ION_IOC_CLEAN_INV_CACHES, arg);
- case ION_IOC_GET_FLAGS:
- return client->dev->custom_ioctl(client,
- ION_IOC_GET_FLAGS, arg);
default:
return -ENOTTY;
}
@@ -1824,37 +1898,14 @@
{
struct ion_device *dev = s->private;
struct rb_node *n;
- struct rb_node *n2;
- /* mark all buffers as 1 */
seq_printf(s, "%16.s %16.s %16.s %16.s\n", "buffer", "heap", "size",
"ref cnt");
+
mutex_lock(&dev->lock);
- for (n = rb_first(&dev->buffers); n; n = rb_next(n)) {
- struct ion_buffer *buf = rb_entry(n, struct ion_buffer,
- node);
+ ion_mark_dangling_buffers_locked(dev);
- buf->marked = 1;
- }
-
- /* now see which buffers we can access */
- for (n = rb_first(&dev->clients); n; n = rb_next(n)) {
- struct ion_client *client = rb_entry(n, struct ion_client,
- node);
-
- mutex_lock(&client->lock);
- for (n2 = rb_first(&client->handles); n2; n2 = rb_next(n2)) {
- struct ion_handle *handle = rb_entry(n2,
- struct ion_handle, node);
-
- handle->buffer->marked = 0;
-
- }
- mutex_unlock(&client->lock);
-
- }
-
- /* And anyone still marked as a 1 means a leaked handle somewhere */
+ /* Anyone still marked as a 1 means a leaked handle somewhere */
for (n = rb_first(&dev->buffers); n; n = rb_next(n)) {
struct ion_buffer *buf = rb_entry(n, struct ion_buffer,
node);
@@ -1915,6 +1966,8 @@
idev->clients = RB_ROOT;
debugfs_create_file("check_leaked_fds", 0664, idev->debug_root, idev,
&debug_leak_fops);
+
+ setup_ion_leak_check(idev->debug_root);
return idev;
}
diff --git a/drivers/gpu/ion/ion_cp_heap.c b/drivers/gpu/ion/ion_cp_heap.c
index 83463ac..56ccc8f 100644
--- a/drivers/gpu/ion/ion_cp_heap.c
+++ b/drivers/gpu/ion/ion_cp_heap.c
@@ -490,39 +490,31 @@
struct sg_table *ion_cp_heap_create_sg_table(struct ion_buffer *buffer)
{
+ size_t chunk_size = buffer->size;
struct sg_table *table;
- int ret;
+ int ret, i, n_chunks;
+ struct scatterlist *sg;
struct ion_cp_buffer *buf = buffer->priv_virt;
+ if (ION_IS_CACHED(buffer->flags))
+ chunk_size = PAGE_SIZE;
+ else if (buf->is_secure && IS_ALIGNED(buffer->size, SZ_1M))
+ chunk_size = SZ_1M;
+
table = kzalloc(sizeof(struct sg_table), GFP_KERNEL);
if (!table)
return ERR_PTR(-ENOMEM);
- if (buf->is_secure && IS_ALIGNED(buffer->size, SZ_1M)) {
- int n_chunks;
- int i;
- struct scatterlist *sg;
+ n_chunks = DIV_ROUND_UP(buffer->size, chunk_size);
- /* Count number of 1MB chunks. Alignment is already checked. */
- n_chunks = buffer->size >> 20;
+ ret = sg_alloc_table(table, n_chunks, GFP_KERNEL);
+ if (ret)
+ goto err0;
- ret = sg_alloc_table(table, n_chunks, GFP_KERNEL);
- if (ret)
- goto err0;
-
- for_each_sg(table->sgl, sg, table->nents, i) {
- sg_dma_address(sg) = buf->buffer + i * SZ_1M;
- sg->length = SZ_1M;
- sg->offset = 0;
- }
- } else {
- ret = sg_alloc_table(table, 1, GFP_KERNEL);
- if (ret)
- goto err0;
-
- table->sgl->length = buffer->size;
- table->sgl->offset = 0;
- table->sgl->dma_address = buf->buffer;
+ for_each_sg(table->sgl, sg, table->nents, i) {
+ sg_dma_address(sg) = buf->buffer + i * chunk_size;
+ sg->length = chunk_size;
+ sg->offset = 0;
}
return table;
diff --git a/drivers/gpu/ion/ion_iommu_heap.c b/drivers/gpu/ion/ion_iommu_heap.c
index 304a39e..761fdde 100644
--- a/drivers/gpu/ion/ion_iommu_heap.c
+++ b/drivers/gpu/ion/ion_iommu_heap.c
@@ -70,13 +70,17 @@
int i;
for (i = 0; i < num_orders; i++) {
+ gfp_t gfp;
if (size < order_to_size(orders[i]))
continue;
if (max_order < orders[i])
continue;
- page = alloc_pages(GFP_KERNEL | __GFP_HIGHMEM | __GFP_COMP,
- orders[i]);
+ gfp = GFP_KERNEL | __GFP_HIGHMEM | __GFP_COMP;
+ if (orders[i])
+ gfp |= __GFP_NOWARN;
+
+ page = alloc_pages(gfp, orders[i]);
if (!page)
continue;
@@ -105,7 +109,7 @@
void *ptr = NULL;
unsigned int npages_to_vmap, total_pages, num_large_pages = 0;
long size_remaining = PAGE_ALIGN(size);
- unsigned int max_order = orders[0];
+ unsigned int max_order = ION_IS_CACHED(flags) ? 0 : orders[0];
data = kmalloc(sizeof(*data), GFP_KERNEL);
if (!data)
diff --git a/drivers/gpu/ion/ion_priv.h b/drivers/gpu/ion/ion_priv.h
index 77ecfa5..9d1e90e 100644
--- a/drivers/gpu/ion/ion_priv.h
+++ b/drivers/gpu/ion/ion_priv.h
@@ -98,7 +98,6 @@
void *vaddr;
int dmap_cnt;
struct sg_table *sg_table;
- int umap_cnt;
unsigned int iommu_map_cnt;
struct rb_root iommu_maps;
int marked;
diff --git a/drivers/gpu/ion/msm/msm_ion.c b/drivers/gpu/ion/msm/msm_ion.c
index b660968..1ca457f 100644
--- a/drivers/gpu/ion/msm/msm_ion.c
+++ b/drivers/gpu/ion/msm/msm_ion.c
@@ -734,22 +734,6 @@
break;
}
- case ION_IOC_GET_FLAGS:
- {
- struct ion_flag_data data;
- int ret;
- if (copy_from_user(&data, (void __user *)arg,
- sizeof(struct ion_flag_data)))
- return -EFAULT;
-
- ret = ion_handle_get_flags(client, data.handle, &data.flags);
- if (ret < 0)
- return ret;
- if (copy_to_user((void __user *)arg, &data,
- sizeof(struct ion_flag_data)))
- return -EFAULT;
- break;
- }
default:
return -ENOTTY;
}
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 08f19f7..b7d813c 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -298,7 +298,7 @@
uint32_t flags)
{
unsigned int pt_val, reg_pt_val;
- unsigned int link[250];
+ unsigned int link[230];
unsigned int *cmds = &link[0];
int sizedwords = 0;
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index bbe97de..a3739a2 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -2764,6 +2764,11 @@
};
static struct a3xx_vbif_data a305b_vbif[] = {
+ { A3XX_VBIF_IN_RD_LIM_CONF0, 0x00181818 },
+ { A3XX_VBIF_IN_WR_LIM_CONF0, 0x00181818 },
+ { A3XX_VBIF_OUT_RD_LIM_CONF0, 0x00000018 },
+ { A3XX_VBIF_OUT_WR_LIM_CONF0, 0x00000018 },
+ { A3XX_VBIF_DDR_OUT_MAX_BURST, 0x00000303 },
{ A3XX_VBIF_ROUND_ROBIN_QOS_ARB, 0x0003 },
{0, 0},
};
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 8078316..0dcbfdf 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -766,23 +766,23 @@
/* High latency clock maintenance. */
if ((pwr->pwrlevels[0].gpu_freq > 0) &&
(requested_state != KGSL_STATE_NAP)) {
- clk_set_rate(pwr->grp_clks[0],
- pwr->pwrlevels[pwr->num_pwrlevels - 1].
- gpu_freq);
for (i = KGSL_MAX_CLKS - 1; i > 0; i--)
if (pwr->grp_clks[i])
clk_unprepare(pwr->grp_clks[i]);
+ clk_set_rate(pwr->grp_clks[0],
+ pwr->pwrlevels[pwr->num_pwrlevels - 1].
+ gpu_freq);
}
kgsl_pwrctrl_busy_time(device, true);
} else if (requested_state == KGSL_STATE_SLEEP) {
/* High latency clock maintenance. */
+ for (i = KGSL_MAX_CLKS - 1; i > 0; i--)
+ if (pwr->grp_clks[i])
+ clk_unprepare(pwr->grp_clks[i]);
if ((pwr->pwrlevels[0].gpu_freq > 0))
clk_set_rate(pwr->grp_clks[0],
pwr->pwrlevels[pwr->num_pwrlevels - 1].
gpu_freq);
- for (i = KGSL_MAX_CLKS - 1; i > 0; i--)
- if (pwr->grp_clks[i])
- clk_unprepare(pwr->grp_clks[i]);
}
} else if (state == KGSL_PWRFLAGS_ON) {
if (!test_and_set_bit(KGSL_PWRFLAGS_CLK_ON,
@@ -790,15 +790,14 @@
trace_kgsl_clk(device, state);
/* High latency clock maintenance. */
if (device->state != KGSL_STATE_NAP) {
- for (i = KGSL_MAX_CLKS - 1; i > 0; i--)
- if (pwr->grp_clks[i])
- clk_prepare(pwr->grp_clks[i]);
-
if (pwr->pwrlevels[0].gpu_freq > 0)
clk_set_rate(pwr->grp_clks[0],
pwr->pwrlevels
[pwr->active_pwrlevel].
gpu_freq);
+ for (i = KGSL_MAX_CLKS - 1; i > 0; i--)
+ if (pwr->grp_clks[i])
+ clk_prepare(pwr->grp_clks[i]);
}
/* as last step, enable grp_clk
this is to let GPU interrupt to come */
diff --git a/drivers/gud/mobicore_driver/main.c b/drivers/gud/mobicore_driver/main.c
index 3fc9e17..df5675e 100644
--- a/drivers/gud/mobicore_driver/main.c
+++ b/drivers/gud/mobicore_driver/main.c
@@ -1112,7 +1112,7 @@
static struct miscdevice mc_admin_device = {
.name = MC_ADMIN_DEVNODE,
.mode = (S_IRWXU),
- .minor = MISC_DYNAMIC_MINOR,
+ .minor = 253,
.fops = &mc_admin_fops,
};
@@ -1128,7 +1128,7 @@
static struct miscdevice mc_user_device = {
.name = MC_USER_DEVNODE,
.mode = (S_IRWXU | S_IRWXG | S_IRWXO),
- .minor = MISC_DYNAMIC_MINOR,
+ .minor = 254,
.fops = &mc_user_fops,
};
diff --git a/drivers/hwmon/qpnp-adc-current.c b/drivers/hwmon/qpnp-adc-current.c
index 3fdc68f..2017c8d 100644
--- a/drivers/hwmon/qpnp-adc-current.c
+++ b/drivers/hwmon/qpnp-adc-current.c
@@ -131,7 +131,6 @@
struct qpnp_adc_drv *adc;
int32_t rsense;
struct device *iadc_hwmon;
- bool iadc_init_calib;
bool iadc_initialized;
int64_t die_temp_calib_offset;
struct delayed_work iadc_work;
@@ -392,10 +391,13 @@
struct qpnp_iadc_drv *iadc = qpnp_iadc;
uint32_t num = 0;
- num = iadc->adc->calib.offset_raw - iadc->adc->calib.offset_raw;
+ if ((iadc->adc->calib.gain_raw - iadc->adc->calib.offset_raw) == 0) {
+ pr_err("raw offset errors! raw_gain:0x%x and raw_offset:0x%x\n",
+ iadc->adc->calib.gain_raw, iadc->adc->calib.offset_raw);
+ return -EINVAL;
+ }
- iadc->adc->calib.offset_uv = (num * QPNP_ADC_GAIN_NV)/
- (iadc->adc->calib.gain_raw - iadc->adc->calib.offset_raw);
+ iadc->adc->calib.offset_uv = 0;
num = iadc->adc->calib.gain_raw - iadc->adc->calib.offset_raw;
@@ -413,6 +415,8 @@
uint16_t raw_data;
uint32_t mode_sel = 0;
+ mutex_lock(&iadc->adc->adc_lock);
+
rc = qpnp_iadc_configure(GAIN_CALIBRATION_17P857MV,
&raw_data, mode_sel);
if (rc < 0) {
@@ -436,6 +440,10 @@
}
rc = qpnp_convert_raw_offset_voltage();
+ if (rc < 0) {
+ pr_err("qpnp raw_voltage conversion failed\n");
+ goto fail;
+ }
rslt_msb = (raw_data & QPNP_RAW_CODE_16_BIT_MSB_MASK) >>
QPNP_BIT_SHIFT_8;
@@ -469,6 +477,7 @@
goto fail;
}
fail:
+ mutex_unlock(&iadc->adc->adc_lock);
return rc;
}
@@ -477,16 +486,12 @@
struct qpnp_iadc_drv *iadc = qpnp_iadc;
int rc = 0;
- mutex_lock(&iadc->adc->adc_lock);
-
rc = qpnp_iadc_calibrate_for_trim();
if (rc) {
pr_err("periodic IADC calibration failed\n");
iadc->iadc_err_cnt++;
}
- mutex_unlock(&iadc->adc->adc_lock);
-
if (iadc->iadc_err_cnt < QPNP_IADC_ERR_CHK_RATELIMIT)
schedule_delayed_work(&iadc->iadc_work,
round_jiffies_relative(msecs_to_jiffies
@@ -527,9 +532,13 @@
int32_t qpnp_iadc_get_rsense(int32_t *rsense)
{
+ struct qpnp_iadc_drv *iadc = qpnp_iadc;
uint8_t rslt_rsense;
int32_t rc, sign_bit = 0;
+ if (!iadc || !iadc->iadc_initialized)
+ return -EPROBE_DEFER;
+
rc = qpnp_iadc_read_reg(QPNP_IADC_NOMINAL_RSENSE, &rslt_rsense);
if (rc < 0) {
pr_err("qpnp adc rsense read failed with %d\n", rc);
@@ -552,11 +561,11 @@
}
EXPORT_SYMBOL(qpnp_iadc_get_rsense);
-int32_t qpnp_check_pmic_temp(void)
+static int32_t qpnp_check_pmic_temp(void)
{
struct qpnp_iadc_drv *iadc = qpnp_iadc;
struct qpnp_vadc_result result_pmic_therm;
- int rc;
+ int rc = 0;
rc = qpnp_vadc_read(DIE_TEMP, &result_pmic_therm);
if (rc < 0)
@@ -565,16 +574,12 @@
if (((uint64_t) (result_pmic_therm.physical -
iadc->die_temp_calib_offset))
> QPNP_IADC_DIE_TEMP_CALIB_OFFSET) {
- mutex_lock(&iadc->adc->adc_lock);
-
rc = qpnp_iadc_calibrate_for_trim();
if (rc)
pr_err("periodic IADC calibration failed\n");
-
- mutex_unlock(&iadc->adc->adc_lock);
}
- return 0;
+ return rc;
}
int32_t qpnp_iadc_read(enum qpnp_iadc_channels channel,
@@ -818,7 +823,6 @@
} else
enable_irq_wake(iadc->adc->adc_irq_eoc);
- iadc->iadc_init_calib = false;
dev_set_drvdata(&spmi->dev, iadc);
qpnp_iadc = iadc;
@@ -835,20 +839,17 @@
goto fail;
}
- rc = qpnp_iadc_calibrate_for_trim();
- if (rc) {
- dev_err(&spmi->dev, "failed to calibrate for USR trim\n");
- goto fail;
- }
- iadc->iadc_init_calib = true;
- INIT_DELAYED_WORK(&iadc->iadc_work, qpnp_iadc_work);
- schedule_delayed_work(&iadc->iadc_work,
- round_jiffies_relative(msecs_to_jiffies
- (QPNP_IADC_CALIB_SECONDS)));
mutex_init(&iadc->iadc_vadc_lock);
+ INIT_DELAYED_WORK(&iadc->iadc_work, qpnp_iadc_work);
iadc->iadc_err_cnt = 0;
iadc->iadc_initialized = true;
+ rc = qpnp_iadc_calibrate_for_trim();
+ if (rc)
+ dev_err(&spmi->dev, "failed to calibrate for USR trim\n");
+ schedule_delayed_work(&iadc->iadc_work,
+ round_jiffies_relative(msecs_to_jiffies
+ (QPNP_IADC_CALIB_SECONDS)));
return 0;
fail:
qpnp_iadc = NULL;
@@ -862,6 +863,7 @@
struct device_node *child;
int i = 0;
+ cancel_delayed_work(&iadc->iadc_work);
mutex_destroy(&iadc->iadc_vadc_lock);
for_each_child_of_node(node, child) {
device_remove_file(&spmi->dev,
diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index da43a08..5280cd8 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -675,7 +675,7 @@
int gpio_dat;
bool gpio_clk_status = false;
uint32_t status = readl_relaxed(dev->base + QUP_I2C_STATUS);
- struct gpiomux_setting old_gpio_setting;
+ struct gpiomux_setting old_gpio_setting[ARRAY_SIZE(i2c_rsrcs)];
if (dev->pdata->msm_i2c_config_gpio)
return;
@@ -695,7 +695,7 @@
disable_irq(dev->err_irq);
for (i = 0; i < ARRAY_SIZE(i2c_rsrcs); ++i) {
if (msm_gpiomux_write(dev->i2c_gpios[i], GPIOMUX_ACTIVE,
- &recovery_config, &old_gpio_setting)) {
+ &recovery_config, &old_gpio_setting[i])) {
dev_err(dev->dev, "GPIO pins have no active setting\n");
goto recovery_end;
}
@@ -725,7 +725,7 @@
/* Configure ALT funciton to QUP I2C*/
for (i = 0; i < ARRAY_SIZE(i2c_rsrcs); ++i) {
msm_gpiomux_write(dev->i2c_gpios[i], GPIOMUX_ACTIVE,
- &old_gpio_setting, NULL);
+ &old_gpio_setting[i], NULL);
}
udelay(10);
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 0c20815..6abfede 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -888,6 +888,17 @@
input_sync(input_dev);
}
+static void mxt_release_all(struct mxt_data *data)
+{
+ int id;
+
+ for (id = 0; id < MXT_MAX_FINGER; id++)
+ if (data->finger[id].status)
+ data->finger[id].status = MXT_RELEASE;
+
+ mxt_input_report(data, 0);
+}
+
static void mxt_input_touchevent(struct mxt_data *data,
struct mxt_message *message, int id)
{
@@ -899,6 +910,10 @@
int area;
int pressure;
+ if (status & MXT_SUPPRESS) {
+ mxt_release_all(data);
+ return;
+ }
/* Check the touch is present on the screen */
if (!(status & MXT_DETECT)) {
if (status & MXT_RELEASE) {
@@ -973,18 +988,7 @@
data->keyarray_old = data->keyarray_new;
}
-static void mxt_release_all(struct mxt_data *data)
-{
- int id;
-
- for (id = 0; id < MXT_MAX_FINGER; id++)
- if (data->finger[id].status)
- data->finger[id].status = MXT_RELEASE;
-
- mxt_input_report(data, 0);
-}
-
-static void mxt_handle_touch_supression(struct mxt_data *data, u8 status)
+static void mxt_handle_touch_suppression(struct mxt_data *data, u8 status)
{
dev_dbg(&data->client->dev, "touch suppression\n");
/* release all touches */
@@ -1039,7 +1043,7 @@
id = reportid - data->t9_min_reportid;
- /* check whether report id is part of T9,T15 or T42*/
+ /* check whether report id is part of T9, T15 or T42 */
if (reportid >= data->t9_min_reportid &&
reportid <= data->t9_max_reportid)
mxt_input_touchevent(data, &message, id);
@@ -1047,8 +1051,9 @@
reportid <= data->t15_max_reportid)
mxt_handle_key_array(data, &message);
else if (reportid >= data->t42_min_reportid &&
- reportid <= data->t42_max_reportid)
- mxt_handle_touch_supression(data, message.message[0]);
+ reportid <= data->t42_max_reportid)
+ mxt_handle_touch_suppression(data,
+ message.message[0]);
else
mxt_dump_message(dev, &message);
} while (reportid != 0xff);
diff --git a/drivers/input/touchscreen/synaptics_fw_update.c b/drivers/input/touchscreen/synaptics_fw_update.c
index abb5bbc..7452587 100644
--- a/drivers/input/touchscreen/synaptics_fw_update.c
+++ b/drivers/input/touchscreen/synaptics_fw_update.c
@@ -1714,5 +1714,4 @@
MODULE_AUTHOR("Synaptics, Inc.");
MODULE_DESCRIPTION("RMI4 FW Update Module");
-MODULE_LICENSE("GPL");
-MODULE_VERSION(SYNAPTICS_RMI4_DRIVER_VERSION_STRING);
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/input/touchscreen/synaptics_i2c_rmi4.c b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
index c68f730..7d6f3dd 100644
--- a/drivers/input/touchscreen/synaptics_i2c_rmi4.c
+++ b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
@@ -1507,10 +1507,6 @@
container_of(work, struct synaptics_rmi4_data,
det_work.work);
- queue_delayed_work(rmi4_data->det_workqueue,
- &rmi4_data->det_work,
- msecs_to_jiffies(EXP_FN_DET_INTERVAL));
-
mutex_lock(&exp_fn_list_mutex);
if (!list_empty(&exp_fn_list)) {
list_for_each_entry_safe(exp_fhandler,
@@ -1695,8 +1691,8 @@
rmi4_data->input_dev->name = DRIVER_NAME;
rmi4_data->input_dev->phys = INPUT_PHYS_NAME;
rmi4_data->input_dev->id.bustype = BUS_I2C;
- rmi4_data->input_dev->id.product = SYNAPTICS_RMI4_DRIVER_PRODUCT;
- rmi4_data->input_dev->id.version = SYNAPTICS_RMI4_DRIVER_VERSION;
+ rmi4_data->input_dev->id.product = SYNAPTICS_DSX_DRIVER_PRODUCT;
+ rmi4_data->input_dev->id.version = SYNAPTICS_DSX_DRIVER_VERSION;
rmi4_data->input_dev->dev.parent = &client->dev;
input_set_drvdata(rmi4_data->input_dev, rmi4_data);
@@ -2147,4 +2143,3 @@
MODULE_AUTHOR("Synaptics, Inc.");
MODULE_DESCRIPTION("Synaptics RMI4 I2C Touch Driver");
MODULE_LICENSE("GPL v2");
-MODULE_VERSION(SYNAPTICS_RMI4_DRIVER_VERSION_STRING);
diff --git a/drivers/input/touchscreen/synaptics_i2c_rmi4.h b/drivers/input/touchscreen/synaptics_i2c_rmi4.h
index eb8d5f2..3c37e54 100644
--- a/drivers/input/touchscreen/synaptics_i2c_rmi4.h
+++ b/drivers/input/touchscreen/synaptics_i2c_rmi4.h
@@ -20,11 +20,10 @@
#ifndef _SYNAPTICS_DSX_RMI4_H_
#define _SYNAPTICS_DSX_RMI4_H_
-#define SYNAPTICS_RMI4_DS4 0x0001
-#define SYNAPTICS_RMI4_DS5 0x0002
-#define SYNAPTICS_RMI4_DRIVER_PRODUCT SYNAPTICS_RMI4_DS4
-#define SYNAPTICS_RMI4_DRIVER_VERSION 0x1001
-#define SYNAPTICS_RMI4_DRIVER_VERSION_STRING "0x1001"
+#define SYNAPTICS_DS4 (1 << 0)
+#define SYNAPTICS_DS5 (1 << 1)
+#define SYNAPTICS_DSX_DRIVER_PRODUCT SYNAPTICS_DS4
+#define SYNAPTICS_DSX_DRIVER_VERSION 0x1002
#include <linux/version.h>
#ifdef CONFIG_HAS_EARLYSUSPEND
diff --git a/drivers/input/touchscreen/synaptics_rmi_dev.c b/drivers/input/touchscreen/synaptics_rmi_dev.c
index fbb6f5e..7f1aac5 100644
--- a/drivers/input/touchscreen/synaptics_rmi_dev.c
+++ b/drivers/input/touchscreen/synaptics_rmi_dev.c
@@ -706,5 +706,4 @@
MODULE_AUTHOR("Synaptics, Inc.");
MODULE_DESCRIPTION("RMI4 RMI_Dev Module");
-MODULE_LICENSE("GPL");
-MODULE_VERSION(SYNAPTICS_RMI4_DRIVER_VERSION_STRING);
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index b126aa2..db4ec9d 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -38,7 +38,7 @@
config MSM_IOMMU_PMON
bool "MSM IOMMU Perfomance Monitoring Support"
- depends on ARCH_MSM8974 && MSM_IOMMU
+ depends on (ARCH_MSM8974 || ARCH_MSM8610 || ARCH_MSM8226) && MSM_IOMMU
help
Support for monitoring IOMMUs performance on certain Qualcomm SOCs.
It captures TLB statistics per context bank of the IOMMU as an
diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile
index 112b62b..096b53e 100644
--- a/drivers/iommu/Makefile
+++ b/drivers/iommu/Makefile
@@ -3,7 +3,7 @@
ifdef CONFIG_OF
obj-$(CONFIG_MSM_IOMMU) += msm_iommu-v1.o msm_iommu_dev-v1.o msm_iommu_pagetable.o msm_iommu_sec.o
endif
-obj-$(CONFIG_MSM_IOMMU_PMON) += msm_iommu_perfmon.o
+obj-$(CONFIG_MSM_IOMMU_PMON) += msm_iommu_perfmon.o msm_iommu_perfmon-v0.o msm_iommu_perfmon-v1.o
obj-$(CONFIG_AMD_IOMMU) += amd_iommu.o amd_iommu_init.o
obj-$(CONFIG_AMD_IOMMU_V2) += amd_iommu_v2.o
obj-$(CONFIG_DMAR_TABLE) += dmar.o
diff --git a/drivers/iommu/msm_iommu-v0.c b/drivers/iommu/msm_iommu-v0.c
index 28f1516..6bf0220 100644
--- a/drivers/iommu/msm_iommu-v0.c
+++ b/drivers/iommu/msm_iommu-v0.c
@@ -27,6 +27,7 @@
#include <asm/cacheflush.h>
#include <asm/sizes.h>
+#include <mach/iommu_perfmon.h>
#include <mach/iommu_hw-v0.h>
#include <mach/iommu.h>
#include <mach/msm_smsm.h>
@@ -160,6 +161,41 @@
clk_disable_unprepare(drvdata->pclk);
}
+static int _iommu_power_on(void *data)
+{
+ struct msm_iommu_drvdata *drvdata;
+
+ drvdata = (struct msm_iommu_drvdata *)data;
+ return __enable_clocks(drvdata);
+}
+
+static int _iommu_power_off(void *data)
+{
+ struct msm_iommu_drvdata *drvdata;
+
+ drvdata = (struct msm_iommu_drvdata *)data;
+ __disable_clocks(drvdata);
+ return 0;
+}
+
+static void _iommu_lock_acquire(void)
+{
+ msm_iommu_lock();
+}
+
+static void _iommu_lock_release(void)
+{
+ msm_iommu_unlock();
+}
+
+struct iommu_access_ops iommu_access_ops_v0 = {
+ .iommu_power_on = _iommu_power_on,
+ .iommu_power_off = _iommu_power_off,
+ .iommu_lock_acquire = _iommu_lock_acquire,
+ .iommu_lock_release = _iommu_lock_release,
+};
+EXPORT_SYMBOL(iommu_access_ops_v0);
+
static int __flush_iotlb_va(struct iommu_domain *domain, unsigned int va)
{
struct msm_priv *priv = domain->priv;
@@ -468,6 +504,11 @@
list_add(&(ctx_drvdata->attached_elm), &priv->list_attached);
ctx_drvdata->attached_domain = domain;
+
+ mutex_unlock(&msm_iommu_lock);
+
+ msm_iommu_attached(dev->parent);
+ return ret;
unlock:
mutex_unlock(&msm_iommu_lock);
return ret;
@@ -481,6 +522,8 @@
struct msm_iommu_ctx_drvdata *ctx_drvdata;
int ret;
+ msm_iommu_detached(dev->parent);
+
mutex_lock(&msm_iommu_lock);
priv = domain->priv;
diff --git a/drivers/iommu/msm_iommu-v1.c b/drivers/iommu/msm_iommu-v1.c
index d15dc65..15a81ed 100644
--- a/drivers/iommu/msm_iommu-v1.c
+++ b/drivers/iommu/msm_iommu-v1.c
@@ -147,12 +147,13 @@
mutex_unlock(&msm_iommu_lock);
}
-struct iommu_access_ops iommu_access_ops = {
+struct iommu_access_ops iommu_access_ops_v1 = {
.iommu_power_on = _iommu_power_on,
.iommu_power_off = _iommu_power_off,
.iommu_lock_acquire = _iommu_lock_acquire,
.iommu_lock_release = _iommu_lock_release,
};
+EXPORT_SYMBOL(iommu_access_ops_v1);
void iommu_halt(const struct msm_iommu_drvdata *iommu_drvdata)
{
diff --git a/drivers/iommu/msm_iommu_dev-v0.c b/drivers/iommu/msm_iommu_dev-v0.c
index 3a9cc23..681d7b2 100644
--- a/drivers/iommu/msm_iommu_dev-v0.c
+++ b/drivers/iommu/msm_iommu_dev-v0.c
@@ -27,6 +27,7 @@
#include <linux/of_address.h>
#include <linux/of_device.h>
+#include <mach/iommu_perfmon.h>
#include <mach/iommu_hw-v0.h>
#include <mach/iommu.h>
@@ -134,6 +135,7 @@
struct device_node *child;
struct resource *r;
u32 glb_offset = 0;
+ int ret;
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!r) {
@@ -162,7 +164,12 @@
pr_err("Failed to create %s device\n", child->name);
}
- drvdata->name = dev_name(&pdev->dev);
+ ret = of_property_read_string(pdev->dev.of_node, "label",
+ &drvdata->name);
+ if (ret) {
+ pr_err("%s: Missing property label\n", __func__);
+ return -EINVAL;
+ }
drvdata->sec_id = -1;
drvdata->ttbr_split = 0;
#endif
@@ -255,8 +262,68 @@
return ret;
}
+static int msm_iommu_pmon_parse_dt(struct platform_device *pdev,
+ struct iommu_pmon *pmon_info)
+{
+ int ret = 0;
+ int irq = platform_get_irq(pdev, 0);
+ unsigned int cls_prop_size;
+
+ if (irq > 0) {
+ pmon_info->iommu.evt_irq = platform_get_irq(pdev, 0);
+
+ ret = of_property_read_u32(pdev->dev.of_node,
+ "qcom,iommu-pmu-ngroups",
+ &pmon_info->num_groups);
+ if (ret) {
+ pr_err("Error reading qcom,iommu-pmu-ngroups\n");
+ goto fail;
+ }
+ ret = of_property_read_u32(pdev->dev.of_node,
+ "qcom,iommu-pmu-ncounters",
+ &pmon_info->num_counters);
+ if (ret) {
+ pr_err("Error reading qcom,iommu-pmu-ncounters\n");
+ goto fail;
+ }
+
+ if (!of_get_property(pdev->dev.of_node,
+ "qcom,iommu-pmu-event-classes",
+ &cls_prop_size)) {
+ pr_err("Error reading qcom,iommu-pmu-event-classes\n");
+ return -EINVAL;
+ }
+
+ pmon_info->event_cls_supported =
+ devm_kzalloc(&pdev->dev, cls_prop_size, GFP_KERNEL);
+
+ if (!pmon_info->event_cls_supported) {
+ pr_err("Unable to get memory for event class array\n");
+ return -ENOMEM;
+ }
+
+ pmon_info->nevent_cls_supported = cls_prop_size / sizeof(u32);
+
+ ret = of_property_read_u32_array(pdev->dev.of_node,
+ "qcom,iommu-pmu-event-classes",
+ pmon_info->event_cls_supported,
+ pmon_info->nevent_cls_supported);
+ if (ret) {
+ pr_err("Error reading qcom,iommu-pmu-event-classes\n");
+ return ret;
+ }
+ } else {
+ pmon_info->iommu.evt_irq = -1;
+ ret = irq;
+ }
+
+fail:
+ return ret;
+}
+
static int msm_iommu_probe(struct platform_device *pdev)
{
+ struct iommu_pmon *pmon_info;
struct msm_iommu_drvdata *drvdata;
struct msm_iommu_dev *iommu_dev = pdev->dev.platform_data;
int ret;
@@ -339,6 +406,29 @@
__disable_clocks(drvdata);
+ pmon_info = msm_iommu_pm_alloc(&pdev->dev);
+ if (pmon_info != NULL) {
+ ret = msm_iommu_pmon_parse_dt(pdev, pmon_info);
+ if (ret) {
+ msm_iommu_pm_free(&pdev->dev);
+ pr_info("%s: pmon not available.\n", drvdata->name);
+ } else {
+ pmon_info->iommu.base = drvdata->base;
+ pmon_info->iommu.ops = &iommu_access_ops_v0;
+ pmon_info->iommu.hw_ops = iommu_pm_get_hw_ops_v0();
+ pmon_info->iommu.iommu_name = drvdata->name;
+ ret = msm_iommu_pm_iommu_register(pmon_info);
+ if (ret) {
+ pr_err("%s iommu register fail\n",
+ drvdata->name);
+ msm_iommu_pm_free(&pdev->dev);
+ } else {
+ pr_debug("%s iommu registered for pmon\n",
+ pmon_info->iommu.iommu_name);
+ }
+ }
+ }
+
return 0;
fail_clk:
diff --git a/drivers/iommu/msm_iommu_dev-v1.c b/drivers/iommu/msm_iommu_dev-v1.c
index 02fd133..f37e619 100644
--- a/drivers/iommu/msm_iommu_dev-v1.c
+++ b/drivers/iommu/msm_iommu_dev-v1.c
@@ -34,7 +34,7 @@
{
struct msm_iommu_bfb_settings *bfb_settings;
u32 nreg, nval;
- int ret, i;
+ int ret;
/*
* It is not valid for a device to have the qcom,iommu-bfb-regs
@@ -80,11 +80,6 @@
bfb_settings->length = nreg / sizeof(*bfb_settings->regs);
- for (i = 0; i < bfb_settings->length; i++)
- if (bfb_settings->regs[i] < IMPLDEF_OFFSET ||
- bfb_settings->regs[i] >= IMPLDEF_OFFSET + IMPLDEF_LENGTH)
- return -EINVAL;
-
drvdata->bfb_settings = bfb_settings;
return 0;
}
@@ -269,7 +264,8 @@
pr_info("%s: pmon not available.\n", drvdata->name);
} else {
pmon_info->iommu.base = drvdata->base;
- pmon_info->iommu.ops = &iommu_access_ops;
+ pmon_info->iommu.ops = &iommu_access_ops_v1;
+ pmon_info->iommu.hw_ops = iommu_pm_get_hw_ops_v1();
pmon_info->iommu.iommu_name = drvdata->name;
ret = msm_iommu_pm_iommu_register(pmon_info);
if (ret) {
diff --git a/drivers/iommu/msm_iommu_pagetable.c b/drivers/iommu/msm_iommu_pagetable.c
index 2ee9ba6..99841cd 100644
--- a/drivers/iommu/msm_iommu_pagetable.c
+++ b/drivers/iommu/msm_iommu_pagetable.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
@@ -110,6 +110,90 @@
return pgprot;
}
+static unsigned long *make_second_level(struct iommu_pt *pt,
+ unsigned long *fl_pte)
+{
+ unsigned long *sl;
+ sl = (unsigned long *) __get_free_pages(GFP_KERNEL,
+ get_order(SZ_4K));
+
+ if (!sl) {
+ pr_debug("Could not allocate second level table\n");
+ goto fail;
+ }
+ memset(sl, 0, SZ_4K);
+ clean_pte(sl, sl + NUM_SL_PTE, pt->redirect);
+
+ *fl_pte = ((((int)__pa(sl)) & FL_BASE_MASK) | \
+ FL_TYPE_TABLE);
+
+ clean_pte(fl_pte, fl_pte + 1, pt->redirect);
+fail:
+ return sl;
+}
+
+static int sl_4k(unsigned long *sl_pte, phys_addr_t pa, unsigned int pgprot)
+{
+ int ret = 0;
+
+ if (*sl_pte) {
+ ret = -EBUSY;
+ goto fail;
+ }
+
+ *sl_pte = (pa & SL_BASE_MASK_SMALL) | SL_NG | SL_SHARED
+ | SL_TYPE_SMALL | pgprot;
+fail:
+ return ret;
+}
+
+static int sl_64k(unsigned long *sl_pte, phys_addr_t pa, unsigned int pgprot)
+{
+ int ret = 0;
+
+ int i;
+
+ for (i = 0; i < 16; i++)
+ if (*(sl_pte+i)) {
+ ret = -EBUSY;
+ goto fail;
+ }
+
+ for (i = 0; i < 16; i++)
+ *(sl_pte+i) = (pa & SL_BASE_MASK_LARGE) | SL_NG
+ | SL_SHARED | SL_TYPE_LARGE | pgprot;
+
+fail:
+ return ret;
+}
+
+static inline int fl_1m(unsigned long *fl_pte, phys_addr_t pa, int pgprot)
+{
+ if (*fl_pte)
+ return -EBUSY;
+
+ *fl_pte = (pa & 0xFFF00000) | FL_NG | FL_TYPE_SECT | FL_SHARED
+ | pgprot;
+
+ return 0;
+}
+
+static inline int fl_16m(unsigned long *fl_pte, phys_addr_t pa, int pgprot)
+{
+ int i;
+ int ret = 0;
+ for (i = 0; i < 16; i++)
+ if (*(fl_pte+i)) {
+ ret = -EBUSY;
+ goto fail;
+ }
+ for (i = 0; i < 16; i++)
+ *(fl_pte+i) = (pa & 0xFF000000) | FL_SUPERSECTION
+ | FL_TYPE_SECT | FL_SHARED | FL_NG | pgprot;
+fail:
+ return ret;
+}
+
int msm_iommu_pagetable_map(struct iommu_pt *pt, unsigned long va,
phys_addr_t pa, size_t len, int prot)
{
@@ -144,28 +228,16 @@
fl_pte = pt->fl_table + fl_offset; /* int pointers, 4 bytes */
if (len == SZ_16M) {
- int i = 0;
-
- for (i = 0; i < 16; i++)
- if (*(fl_pte+i)) {
- ret = -EBUSY;
- goto fail;
- }
-
- for (i = 0; i < 16; i++)
- *(fl_pte+i) = (pa & 0xFF000000) | FL_SUPERSECTION |
- FL_TYPE_SECT | FL_SHARED | FL_NG | pgprot;
+ ret = fl_16m(fl_pte, pa, pgprot);
+ if (ret)
+ goto fail;
clean_pte(fl_pte, fl_pte + 16, pt->redirect);
}
if (len == SZ_1M) {
- if (*fl_pte) {
- ret = -EBUSY;
+ ret = fl_1m(fl_pte, pa, pgprot);
+ if (ret)
goto fail;
- }
-
- *fl_pte = (pa & 0xFFF00000) | FL_NG | FL_TYPE_SECT
- | FL_SHARED | pgprot;
clean_pte(fl_pte, fl_pte + 1, pt->redirect);
}
@@ -173,21 +245,10 @@
if (len == SZ_4K || len == SZ_64K) {
if (*fl_pte == 0) {
- unsigned long *sl;
- sl = (unsigned long *) __get_free_pages(GFP_KERNEL,
- get_order(SZ_4K));
-
- if (!sl) {
- pr_debug("Could not allocate second level table\n");
+ if (make_second_level(pt, fl_pte) == NULL) {
ret = -ENOMEM;
goto fail;
}
- memset(sl, 0, SZ_4K);
- clean_pte(sl, sl + NUM_SL_PTE, pt->redirect);
-
- *fl_pte = ((((int)__pa(sl)) & FL_BASE_MASK) | \
- FL_TYPE_TABLE);
- clean_pte(fl_pte, fl_pte + 1, pt->redirect);
}
if (!(*fl_pte & FL_TYPE_TABLE)) {
@@ -201,29 +262,16 @@
sl_pte = sl_table + sl_offset;
if (len == SZ_4K) {
- if (*sl_pte) {
- ret = -EBUSY;
+ ret = sl_4k(sl_pte, pa, pgprot);
+ if (ret)
goto fail;
- }
-
- *sl_pte = (pa & SL_BASE_MASK_SMALL) | SL_NG | SL_SHARED
- | SL_TYPE_SMALL | pgprot;
clean_pte(sl_pte, sl_pte + 1, pt->redirect);
}
if (len == SZ_64K) {
- int i;
-
- for (i = 0; i < 16; i++)
- if (*(sl_pte+i)) {
- ret = -EBUSY;
- goto fail;
- }
-
- for (i = 0; i < 16; i++)
- *(sl_pte+i) = (pa & SL_BASE_MASK_LARGE) | SL_NG
- | SL_SHARED | SL_TYPE_LARGE | pgprot;
-
+ ret = sl_64k(sl_pte, pa, pgprot);
+ if (ret)
+ goto fail;
clean_pte(sl_pte, sl_pte + 16, pt->redirect);
}
@@ -322,64 +370,99 @@
return pa;
}
+static inline int is_fully_aligned(unsigned int va, phys_addr_t pa, size_t len,
+ int align)
+{
+ return IS_ALIGNED(va, align) && IS_ALIGNED(pa, align)
+ && (len >= align);
+}
+
int msm_iommu_pagetable_map_range(struct iommu_pt *pt, unsigned int va,
struct scatterlist *sg, unsigned int len, int prot)
{
unsigned int pa;
unsigned int offset = 0;
- unsigned int pgprot;
unsigned long *fl_pte;
unsigned long fl_offset;
- unsigned long *sl_table;
+ unsigned long *sl_table = NULL;
unsigned long sl_offset, sl_start;
- unsigned int chunk_offset = 0;
- unsigned int chunk_pa;
+ unsigned int chunk_size, chunk_offset = 0;
int ret = 0;
+ unsigned int pgprot4k, pgprot64k, pgprot1m, pgprot16m;
BUG_ON(len & (SZ_4K - 1));
- pgprot = __get_pgprot(prot, SZ_4K);
- if (!pgprot) {
+ pgprot4k = __get_pgprot(prot, SZ_4K);
+ pgprot64k = __get_pgprot(prot, SZ_64K);
+ pgprot1m = __get_pgprot(prot, SZ_1M);
+ pgprot16m = __get_pgprot(prot, SZ_16M);
+ if (!pgprot4k || !pgprot64k || !pgprot1m || !pgprot16m) {
ret = -EINVAL;
goto fail;
}
fl_offset = FL_OFFSET(va); /* Upper 12 bits */
fl_pte = pt->fl_table + fl_offset; /* int pointers, 4 bytes */
-
- sl_table = (unsigned long *) __va(((*fl_pte) & FL_BASE_MASK));
- sl_offset = SL_OFFSET(va);
-
- chunk_pa = get_phys_addr(sg);
- if (chunk_pa == 0) {
- pr_debug("No dma address for sg %p\n", sg);
- ret = -EINVAL;
- goto fail;
- }
+ pa = get_phys_addr(sg);
while (offset < len) {
- /* Set up a 2nd level page table if one doesn't exist */
- if (*fl_pte == 0) {
- sl_table = (unsigned long *)
- __get_free_pages(GFP_KERNEL, get_order(SZ_4K));
+ chunk_size = SZ_4K;
- if (!sl_table) {
- pr_debug("Could not allocate second level table\n");
+ if (is_fully_aligned(va, pa, sg->length - chunk_offset,
+ SZ_16M))
+ chunk_size = SZ_16M;
+ else if (is_fully_aligned(va, pa, sg->length - chunk_offset,
+ SZ_1M))
+ chunk_size = SZ_1M;
+ /* 64k or 4k determined later */
+
+ /* for 1M and 16M, only first level entries are required */
+ if (chunk_size >= SZ_1M) {
+ if (chunk_size == SZ_16M) {
+ ret = fl_16m(fl_pte, pa, pgprot16m);
+ if (ret)
+ goto fail;
+ clean_pte(fl_pte, fl_pte + 16, pt->redirect);
+ fl_pte += 16;
+ } else if (chunk_size == SZ_1M) {
+ ret = fl_1m(fl_pte, pa, pgprot1m);
+ if (ret)
+ goto fail;
+ clean_pte(fl_pte, fl_pte + 1, pt->redirect);
+ fl_pte++;
+ }
+
+ offset += chunk_size;
+ chunk_offset += chunk_size;
+ va += chunk_size;
+ pa += chunk_size;
+
+ if (chunk_offset >= sg->length && offset < len) {
+ chunk_offset = 0;
+ sg = sg_next(sg);
+ pa = get_phys_addr(sg);
+ if (pa == 0) {
+ pr_debug("No dma address for sg %p\n",
+ sg);
+ ret = -EINVAL;
+ goto fail;
+ }
+ }
+ continue;
+ }
+ /* for 4K or 64K, make sure there is a second level table */
+ if (*fl_pte == 0) {
+ if (!make_second_level(pt, fl_pte)) {
ret = -ENOMEM;
goto fail;
}
-
- memset(sl_table, 0, SZ_4K);
- clean_pte(sl_table, sl_table + NUM_SL_PTE,
- pt->redirect);
-
- *fl_pte = ((((int)__pa(sl_table)) & FL_BASE_MASK) |
- FL_TYPE_TABLE);
- clean_pte(fl_pte, fl_pte + 1, pt->redirect);
- } else
- sl_table = (unsigned long *)
- __va(((*fl_pte) & FL_BASE_MASK));
-
+ }
+ if (!(*fl_pte & FL_TYPE_TABLE)) {
+ ret = -EBUSY;
+ goto fail;
+ }
+ sl_table = __va(((*fl_pte) & FL_BASE_MASK));
+ sl_offset = SL_OFFSET(va);
/* Keep track of initial position so we
* don't clean more than we have to
*/
@@ -387,21 +470,38 @@
/* Build the 2nd level page table */
while (offset < len && sl_offset < NUM_SL_PTE) {
- pa = chunk_pa + chunk_offset;
- sl_table[sl_offset] = (pa & SL_BASE_MASK_SMALL) |
- pgprot | SL_NG | SL_SHARED | SL_TYPE_SMALL;
- sl_offset++;
- offset += SZ_4K;
+ /* Map a large 64K page if the chunk is large enough and
+ * the pa and va are aligned
+ */
- chunk_offset += SZ_4K;
+ if (is_fully_aligned(va, pa, sg->length - chunk_offset,
+ SZ_64K))
+ chunk_size = SZ_64K;
+ else
+ chunk_size = SZ_4K;
+
+ if (chunk_size == SZ_4K) {
+ sl_4k(&sl_table[sl_offset], pa, pgprot4k);
+ sl_offset++;
+ } else {
+ BUG_ON(sl_offset + 16 > NUM_SL_PTE);
+ sl_64k(&sl_table[sl_offset], pa, pgprot64k);
+ sl_offset += 16;
+ }
+
+
+ offset += chunk_size;
+ chunk_offset += chunk_size;
+ va += chunk_size;
+ pa += chunk_size;
if (chunk_offset >= sg->length && offset < len) {
chunk_offset = 0;
sg = sg_next(sg);
- chunk_pa = get_phys_addr(sg);
- if (chunk_pa == 0) {
+ pa = get_phys_addr(sg);
+ if (pa == 0) {
pr_debug("No dma address for sg %p\n",
- sg);
+ sg);
ret = -EINVAL;
goto fail;
}
@@ -433,44 +533,53 @@
fl_offset = FL_OFFSET(va); /* Upper 12 bits */
fl_pte = pt->fl_table + fl_offset; /* int pointers, 4 bytes */
- sl_start = SL_OFFSET(va);
-
while (offset < len) {
- sl_table = (unsigned long *) __va(((*fl_pte) & FL_BASE_MASK));
- sl_end = ((len - offset) / SZ_4K) + sl_start;
+ if (*fl_pte & FL_TYPE_TABLE) {
+ sl_start = SL_OFFSET(va);
+ sl_table = __va(((*fl_pte) & FL_BASE_MASK));
+ sl_end = ((len - offset) / SZ_4K) + sl_start;
- if (sl_end > NUM_SL_PTE)
- sl_end = NUM_SL_PTE;
+ if (sl_end > NUM_SL_PTE)
+ sl_end = NUM_SL_PTE;
- memset(sl_table + sl_start, 0, (sl_end - sl_start) * 4);
- clean_pte(sl_table + sl_start, sl_table + sl_end,
- pt->redirect);
+ memset(sl_table + sl_start, 0, (sl_end - sl_start) * 4);
+ clean_pte(sl_table + sl_start, sl_table + sl_end,
+ pt->redirect);
- offset += (sl_end - sl_start) * SZ_4K;
+ offset += (sl_end - sl_start) * SZ_4K;
+ va += (sl_end - sl_start) * SZ_4K;
- /* Unmap and free the 2nd level table if all mappings in it
- * were removed. This saves memory, but the table will need
- * to be re-allocated the next time someone tries to map these
- * VAs.
- */
- used = 0;
+ /* Unmap and free the 2nd level table if all mappings
+ * in it were removed. This saves memory, but the table
+ * will need to be re-allocated the next time someone
+ * tries to map these VAs.
+ */
+ used = 0;
- /* If we just unmapped the whole table, don't bother
- * seeing if there are still used entries left.
- */
- if (sl_end - sl_start != NUM_SL_PTE)
- for (i = 0; i < NUM_SL_PTE; i++)
- if (sl_table[i]) {
- used = 1;
- break;
- }
- if (!used) {
- free_page((unsigned long)sl_table);
+ /* If we just unmapped the whole table, don't bother
+ * seeing if there are still used entries left.
+ */
+ if (sl_end - sl_start != NUM_SL_PTE)
+ for (i = 0; i < NUM_SL_PTE; i++)
+ if (sl_table[i]) {
+ used = 1;
+ break;
+ }
+ if (!used) {
+ free_page((unsigned long)sl_table);
+ *fl_pte = 0;
+
+ clean_pte(fl_pte, fl_pte + 1, pt->redirect);
+ }
+
+ sl_start = 0;
+ } else {
*fl_pte = 0;
clean_pte(fl_pte, fl_pte + 1, pt->redirect);
+ va += SZ_1M;
+ offset += SZ_1M;
+ sl_start = 0;
}
-
- sl_start = 0;
fl_pte++;
}
}
diff --git a/drivers/iommu/msm_iommu_perfmon-v0.c b/drivers/iommu/msm_iommu_perfmon-v0.c
new file mode 100644
index 0000000..c80d1e5
--- /dev/null
+++ b/drivers/iommu/msm_iommu_perfmon-v0.c
@@ -0,0 +1,310 @@
+/* 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.
+ */
+
+/**
+ * This file contains the part of the IOMMUv0 PMU driver that actually touches
+ * IOMMU PMU registers.
+ */
+
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <mach/iommu_hw-v0.h>
+#include <mach/iommu_perfmon.h>
+
+#define PM_RESET_MASK (0xF)
+#define PM_RESET_SHIFT (0x8)
+#define PM_RESET (PM_RESET_MASK << PM_RESET_SHIFT)
+
+#define PM_ENABLE_MASK (0x1)
+#define PM_ENABLE_SHIFT (0x0)
+#define PM_ENABLE (PM_ENABLE_MASK << PM_ENABLE_SHIFT)
+
+#define PM_OVFL_FLAG_MASK (0xF)
+#define PM_OVFL_FLAG_SHIFT (0x0)
+#define PM_OVFL_FLAG (PM_OVFL_FLAG_MASK << PM_OVFL_FLAG_SHIFT)
+
+#define PM_EVENT_TYPE_MASK (0x1F)
+#define PM_EVENT_TYPE_SHIFT (0x2)
+#define PM_EVENT_TYPE (PM_EVENT_TYPE_MASK << PM_EVENT_TYPE_SHIFT)
+
+#define PM_INT_EN_MASK (0x1)
+#define PM_INT_EN_SHIFT (0x0)
+#define PM_INT_EN (PM_INT_EN_MASK << PM_INT_EN_SHIFT)
+
+#define PM_INT_POL_MASK (0x1)
+#define PM_INT_POL_SHIFT (0x2)
+#define PM_INT_ACTIVE_HIGH (0x1)
+
+#define PMEVCNTR_(n) (EMC_N + n*4)
+#define PMEVTYPER_(n) (EMCC_N + n*4)
+
+/**
+ * Translate between SMMUv0 event classes and standard ARM SMMU event classes
+ */
+static int iommu_pm_event_class_translation_table[] = {
+ MSM_IOMMU_PMU_NO_EVENT_CLASS,
+ MSM_IOMMU_PMU_NO_EVENT_CLASS,
+ MSM_IOMMU_PMU_NO_EVENT_CLASS,
+ 0x8,
+ 0x9,
+ MSM_IOMMU_PMU_NO_EVENT_CLASS,
+ 0x80,
+ MSM_IOMMU_PMU_NO_EVENT_CLASS,
+ 0x12,
+ MSM_IOMMU_PMU_NO_EVENT_CLASS,
+ MSM_IOMMU_PMU_NO_EVENT_CLASS,
+ MSM_IOMMU_PMU_NO_EVENT_CLASS,
+ MSM_IOMMU_PMU_NO_EVENT_CLASS,
+ MSM_IOMMU_PMU_NO_EVENT_CLASS,
+ MSM_IOMMU_PMU_NO_EVENT_CLASS,
+ 0x10,
+};
+
+static int iommu_pm_translate_event_class(int event_class)
+{
+ const unsigned int TBL_LEN =
+ ARRAY_SIZE(iommu_pm_event_class_translation_table);
+ unsigned int i;
+
+ if (event_class < 0)
+ return event_class;
+
+ for (i = 0; i < TBL_LEN; ++i) {
+ if (iommu_pm_event_class_translation_table[i] == event_class)
+ return i;
+ }
+ return MSM_IOMMU_PMU_NO_EVENT_CLASS;
+}
+
+static unsigned int iommu_pm_is_hw_access_OK(const struct iommu_pmon *pmon)
+{
+ /*
+ * IOMMUv0 is in always ON domain so we don't care whether we are
+ * attached or not. We only care whether the PMU is enabled or
+ * not meaning clocks are turned on.
+ */
+ return pmon->enabled;
+}
+
+static void iommu_pm_grp_enable(struct iommu_info *iommu, unsigned int grp_no)
+{
+ /* No group concept in v0. */
+}
+
+static void iommu_pm_grp_disable(struct iommu_info *iommu, unsigned int grp_no)
+{
+ /* No group concept in v0. */
+}
+
+static void iommu_pm_set_int_active_high(const struct iommu_info *iommu)
+{
+ unsigned int emmc;
+ emmc = readl_relaxed(iommu->base + EMMC);
+ emmc |= (PM_INT_ACTIVE_HIGH & PM_INT_POL_MASK) << PM_INT_POL_SHIFT;
+ writel_relaxed(emmc, iommu->base + EMMC);
+}
+
+static void iommu_pm_enable(struct iommu_info *iommu)
+{
+ unsigned int emmc;
+ emmc = readl_relaxed(iommu->base + EMMC);
+ emmc |= PM_ENABLE;
+ writel_relaxed(emmc, iommu->base + EMMC);
+}
+
+static void iommu_pm_disable(struct iommu_info *iommu)
+{
+ unsigned int emmc;
+ emmc = readl_relaxed(iommu->base + EMMC);
+ emmc &= ~PM_ENABLE;
+ writel_relaxed(emmc, iommu->base + EMMC);
+}
+
+static void iommu_pm_reset_counters(const struct iommu_info *iommu)
+{
+ unsigned int emmc;
+ emmc = readl_relaxed(iommu->base + EMMC);
+ emmc |= PM_RESET;
+ writel_relaxed(emmc, iommu->base + EMMC);
+}
+
+static void iommu_pm_check_for_overflow(struct iommu_pmon *pmon)
+{
+ struct iommu_pmon_counter *counter;
+ struct iommu_info *iommu = &pmon->iommu;
+ unsigned int reg_value;
+ unsigned int j;
+ struct iommu_pmon_cnt_group *cnt_grp = &pmon->cnt_grp[0];
+
+ reg_value = readl_relaxed(iommu->base + EMCS);
+ reg_value &= PM_OVFL_FLAG;
+
+ for (j = 0; j < cnt_grp->num_counters; ++j) {
+ counter = &cnt_grp->counters[j];
+
+ if (counter->enabled) {
+ if (reg_value & (1 << counter->absolute_counter_no))
+ counter->overflow_count++;
+ }
+ }
+
+ /* Clear overflow */
+ writel_relaxed(reg_value, iommu->base + EMCS);
+}
+
+static irqreturn_t iommu_pm_evt_ovfl_int_handler(int irq, void *dev_id)
+{
+ struct iommu_pmon *pmon = dev_id;
+ struct iommu_info *iommu = &pmon->iommu;
+
+ mutex_lock(&pmon->lock);
+
+ if (!iommu_pm_is_hw_access_OK(pmon)) {
+ mutex_unlock(&pmon->lock);
+ goto out;
+ }
+
+ iommu->ops->iommu_lock_acquire();
+ iommu_pm_check_for_overflow(pmon);
+ iommu->ops->iommu_lock_release();
+
+ mutex_unlock(&pmon->lock);
+
+out:
+ return IRQ_HANDLED;
+}
+
+static void iommu_pm_counter_enable(struct iommu_info *iommu,
+ struct iommu_pmon_counter *counter)
+{
+ unsigned int bit_no = counter->absolute_counter_no;
+ unsigned int reg_value;
+
+ /* Clear overflow of counter */
+ reg_value = readl_relaxed(iommu->base + EMCS);
+ reg_value &= (1 << bit_no);
+ writel_relaxed(reg_value, iommu->base + EMCS);
+
+ /* Enable counter */
+ counter->enabled = 1;
+}
+
+static void iommu_pm_counter_disable(struct iommu_info *iommu,
+ struct iommu_pmon_counter *counter)
+{
+ unsigned int bit_no = counter->absolute_counter_no;
+ unsigned int reg_value;
+
+ /* Disable counter */
+ counter->enabled = 0;
+
+ /* Clear overflow of counter */
+ reg_value = readl_relaxed(iommu->base + EMCS);
+ reg_value &= (1 << bit_no);
+ writel_relaxed(reg_value, iommu->base + EMCS);
+}
+
+/*
+ * Must be called after iommu_start_access() is called
+ */
+static void iommu_pm_ovfl_int_enable(struct iommu_info *iommu,
+ const struct iommu_pmon_counter *counter)
+{
+ unsigned int reg_no = counter->absolute_counter_no;
+ unsigned int reg_value;
+
+ /* Enable overflow interrupt for counter */
+ reg_value = readl_relaxed(iommu->base + PMEVTYPER_(reg_no));
+ reg_value |= PM_INT_EN;
+ writel_relaxed(reg_value, iommu->base + PMEVTYPER_(reg_no));
+}
+
+/*
+ * Must be called after iommu_start_access() is called
+ */
+static void iommu_pm_ovfl_int_disable(struct iommu_info *iommu,
+ const struct iommu_pmon_counter *counter)
+{
+ unsigned int reg_no = counter->absolute_counter_no;
+ unsigned int reg_value;
+
+ /* Disable overflow interrupt for counter */
+ reg_value = readl_relaxed(iommu->base + PMEVTYPER_(reg_no));
+ reg_value &= ~PM_INT_EN;
+ writel_relaxed(reg_value, iommu->base + PMEVTYPER_(reg_no));
+}
+
+static void iommu_pm_set_event_class(struct iommu_pmon *pmon,
+ unsigned int count_no,
+ unsigned int event_class)
+{
+ unsigned int reg_no = count_no;
+ unsigned int reg_value;
+ int event = iommu_pm_translate_event_class(event_class);
+
+ if (event == MSM_IOMMU_PMU_NO_EVENT_CLASS)
+ event = 0;
+
+ reg_value = readl_relaxed(pmon->iommu.base + PMEVTYPER_(reg_no));
+ reg_value &= ~(PM_EVENT_TYPE_MASK << PM_EVENT_TYPE_SHIFT);
+ reg_value |= (event & PM_EVENT_TYPE_MASK) << PM_EVENT_TYPE_SHIFT;
+ writel_relaxed(reg_value, pmon->iommu.base + PMEVTYPER_(reg_no));
+}
+
+static unsigned int iommu_pm_read_counter(struct iommu_pmon_counter *counter)
+{
+ struct iommu_pmon *pmon = counter->cnt_group->pmon;
+ struct iommu_info *info = &pmon->iommu;
+ unsigned int cnt_no = counter->absolute_counter_no;
+ return readl_relaxed(info->base + PMEVCNTR_(cnt_no));
+}
+
+static void iommu_pm_initialize_hw(const struct iommu_pmon *pmon)
+{
+ const struct iommu_info *iommu = &pmon->iommu;
+ struct msm_iommu_drvdata *iommu_drvdata =
+ dev_get_drvdata(iommu->iommu_dev);
+
+ /* This is called during bootup device initialization so no need
+ * for locking here.
+ */
+ iommu->ops->iommu_power_on(iommu_drvdata);
+ iommu_pm_set_int_active_high(iommu);
+ iommu->ops->iommu_power_off(iommu_drvdata);
+}
+
+static struct iommu_pm_hw_ops iommu_pm_hw_ops = {
+ .initialize_hw = iommu_pm_initialize_hw,
+ .is_hw_access_OK = iommu_pm_is_hw_access_OK,
+ .grp_enable = iommu_pm_grp_enable,
+ .grp_disable = iommu_pm_grp_disable,
+ .enable_pm = iommu_pm_enable,
+ .disable_pm = iommu_pm_disable,
+ .reset_counters = iommu_pm_reset_counters,
+ .check_for_overflow = iommu_pm_check_for_overflow,
+ .evt_ovfl_int_handler = iommu_pm_evt_ovfl_int_handler,
+ .counter_enable = iommu_pm_counter_enable,
+ .counter_disable = iommu_pm_counter_disable,
+ .ovfl_int_enable = iommu_pm_ovfl_int_enable,
+ .ovfl_int_disable = iommu_pm_ovfl_int_disable,
+ .set_event_class = iommu_pm_set_event_class,
+ .read_counter = iommu_pm_read_counter,
+};
+
+struct iommu_pm_hw_ops *iommu_pm_get_hw_ops_v0(void)
+{
+ return &iommu_pm_hw_ops;
+}
+EXPORT_SYMBOL(iommu_pm_get_hw_ops_v0);
+
diff --git a/drivers/iommu/msm_iommu_perfmon-v1.c b/drivers/iommu/msm_iommu_perfmon-v1.c
new file mode 100644
index 0000000..d76ee7f
--- /dev/null
+++ b/drivers/iommu/msm_iommu_perfmon-v1.c
@@ -0,0 +1,269 @@
+/* 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.
+ */
+
+/**
+ * This file contains the part of the IOMMUv1 PMU driver that actually touches
+ * IOMMU PMU registers.
+ */
+
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <mach/iommu_hw-v1.h>
+#include <mach/iommu_perfmon.h>
+
+#define PMCR_P_MASK (0x1)
+#define PMCR_P_SHIFT (1)
+#define PMCR_P (PMCR_P_MASK << PMCR_P_SHIFT)
+#define PMCFGR_NCG_MASK (0xFF)
+#define PMCFGR_NCG_SHIFT (24)
+#define PMCFGR_NCG (PMCFGR_NCG_MASK << PMCFGR_NCG_SHIFT)
+#define PMCFGR_N_MASK (0xFF)
+#define PMCFGR_N_SHIFT (0)
+#define PMCFGR_N (PMCFGR_N_MASK << PMCFGR_N_SHIFT)
+#define CR_E 0x1
+#define CGCR_CEN 0x800
+#define CGCR_CEN_SHFT (1 << 11)
+#define PMCGCR_CGNC_MASK (0x0F)
+#define PMCGCR_CGNC_SHIFT (24)
+#define PMCGCR_CGNC (PMCGCR_CGNC_MASK << PMCGCR_CGNC_SHIFT)
+#define PMCGCR_(group) (PMCGCR_N + group*4)
+
+#define PMOVSCLR_(n) (PMOVSCLR_N + n*4)
+#define PMCNTENSET_(n) (PMCNTENSET_N + n*4)
+#define PMCNTENCLR_(n) (PMCNTENCLR_N + n*4)
+#define PMINTENSET_(n) (PMINTENSET_N + n*4)
+#define PMINTENCLR_(n) (PMINTENCLR_N + n*4)
+
+#define PMEVCNTR_(n) (PMEVCNTR_N + n*4)
+#define PMEVTYPER_(n) (PMEVTYPER_N + n*4)
+
+
+static unsigned int iommu_pm_is_hw_access_OK(const struct iommu_pmon *pmon)
+{
+ /*
+ * IOMMUv1 is not in the always on domain so we need to make sure
+ * the regulators are turned on in addition to clocks before we allow
+ * access to the hardware thus we check if we have attached to the
+ * IOMMU in addition to checking if we have enabled PMU.
+ */
+ return pmon->enabled && (pmon->iommu_attach_count > 0);
+}
+
+static void iommu_pm_grp_enable(struct iommu_info *iommu, unsigned int grp_no)
+{
+ unsigned int pmcgcr;
+ pmcgcr = readl_relaxed(iommu->base + PMCGCR_(grp_no));
+ pmcgcr |= CGCR_CEN;
+ writel_relaxed(pmcgcr, iommu->base + PMCGCR_(grp_no));
+}
+
+static void iommu_pm_grp_disable(struct iommu_info *iommu, unsigned int grp_no)
+{
+ unsigned int pmcgcr;
+ pmcgcr = readl_relaxed(iommu->base + PMCGCR_(grp_no));
+ pmcgcr &= ~CGCR_CEN;
+ writel_relaxed(pmcgcr, iommu->base + PMCGCR_(grp_no));
+}
+
+static void iommu_pm_enable(struct iommu_info *iommu)
+{
+ unsigned int pmcr;
+ pmcr = readl_relaxed(iommu->base + PMCR);
+ pmcr |= CR_E;
+ writel_relaxed(pmcr, iommu->base + PMCR);
+}
+
+static void iommu_pm_disable(struct iommu_info *iommu)
+{
+ unsigned int pmcr;
+ pmcr = readl_relaxed(iommu->base + PMCR);
+ pmcr &= ~CR_E;
+ writel_relaxed(pmcr, iommu->base + PMCR);
+}
+
+static void iommu_pm_reset_counters(const struct iommu_info *iommu)
+{
+ unsigned int pmcr;
+ pmcr = readl_relaxed(iommu->base + PMCR);
+ pmcr |= PMCR_P;
+ writel_relaxed(pmcr, iommu->base + PMCR);
+}
+
+static void iommu_pm_check_for_overflow(struct iommu_pmon *pmon)
+{
+ struct iommu_pmon_counter *counter;
+ struct iommu_info *iommu = &pmon->iommu;
+ unsigned int reg_no = 0;
+ unsigned int bit_no;
+ unsigned int reg_value;
+ unsigned int i;
+ unsigned int j;
+ unsigned int curr_reg = 0;
+
+ reg_value = readl_relaxed(iommu->base + PMOVSCLR_(curr_reg));
+
+ for (i = 0; i < pmon->num_groups; ++i) {
+ struct iommu_pmon_cnt_group *cnt_grp = &pmon->cnt_grp[i];
+ for (j = 0; j < cnt_grp->num_counters; ++j) {
+ counter = &cnt_grp->counters[j];
+ reg_no = counter->absolute_counter_no / 32;
+ bit_no = counter->absolute_counter_no % 32;
+ if (reg_no != curr_reg) {
+ /* Clear overflow bits */
+ writel_relaxed(reg_value, iommu->base +
+ PMOVSCLR_(reg_no));
+ curr_reg = reg_no;
+ reg_value = readl_relaxed(iommu->base +
+ PMOVSCLR_(curr_reg));
+ }
+
+ if (counter->enabled) {
+ if (reg_value & (1 << bit_no))
+ counter->overflow_count++;
+ }
+ }
+ }
+
+ /* Clear overflow */
+ writel_relaxed(reg_value, iommu->base + PMOVSCLR_(reg_no));
+}
+
+static irqreturn_t iommu_pm_evt_ovfl_int_handler(int irq, void *dev_id)
+{
+ struct iommu_pmon *pmon = dev_id;
+ struct iommu_info *iommu = &pmon->iommu;
+
+ mutex_lock(&pmon->lock);
+
+ if (!iommu_pm_is_hw_access_OK(pmon)) {
+ mutex_unlock(&pmon->lock);
+ goto out;
+ }
+
+ iommu->ops->iommu_lock_acquire();
+ iommu_pm_check_for_overflow(pmon);
+ iommu->ops->iommu_lock_release();
+
+ mutex_unlock(&pmon->lock);
+
+out:
+ return IRQ_HANDLED;
+}
+
+static void iommu_pm_counter_enable(struct iommu_info *iommu,
+ struct iommu_pmon_counter *counter)
+{
+ unsigned int reg_no = counter->absolute_counter_no / 32;
+ unsigned int bit_no = counter->absolute_counter_no % 32;
+ unsigned int reg_value;
+
+ /* Clear overflow of counter */
+ reg_value = 1 << bit_no;
+ writel_relaxed(reg_value, iommu->base + PMOVSCLR_(reg_no));
+
+ /* Enable counter */
+ writel_relaxed(reg_value, iommu->base + PMCNTENSET_(reg_no));
+ counter->enabled = 1;
+}
+
+static void iommu_pm_counter_disable(struct iommu_info *iommu,
+ struct iommu_pmon_counter *counter)
+{
+ unsigned int reg_no = counter->absolute_counter_no / 32;
+ unsigned int bit_no = counter->absolute_counter_no % 32;
+ unsigned int reg_value;
+
+ counter->enabled = 0;
+
+ /* Disable counter */
+ reg_value = 1 << bit_no;
+ writel_relaxed(reg_value, iommu->base + PMCNTENCLR_(reg_no));
+
+ /* Clear overflow of counter */
+ writel_relaxed(reg_value, iommu->base + PMOVSCLR_(reg_no));
+}
+
+/*
+ * Must be called after iommu_start_access() is called
+ */
+static void iommu_pm_ovfl_int_enable(struct iommu_info *iommu,
+ const struct iommu_pmon_counter *counter)
+{
+ unsigned int reg_no = counter->absolute_counter_no / 32;
+ unsigned int bit_no = counter->absolute_counter_no % 32;
+ unsigned int reg_value;
+
+ /* Enable overflow interrupt for counter */
+ reg_value = (1 << bit_no);
+ writel_relaxed(reg_value, iommu->base + PMINTENSET_(reg_no));
+}
+
+/*
+ * Must be called after iommu_start_access() is called
+ */
+static void iommu_pm_ovfl_int_disable(struct iommu_info *iommu,
+ const struct iommu_pmon_counter *counter)
+{
+ unsigned int reg_no = counter->absolute_counter_no / 32;
+ unsigned int bit_no = counter->absolute_counter_no % 32;
+ unsigned int reg_value;
+
+ /* Disable overflow interrupt for counter */
+ reg_value = 1 << bit_no;
+ writel_relaxed(reg_value, iommu->base + PMINTENCLR_(reg_no));
+}
+
+static void iommu_pm_set_event_class(struct iommu_pmon *pmon,
+ unsigned int count_no,
+ unsigned int event_class)
+{
+ writel_relaxed(event_class, pmon->iommu.base + PMEVTYPER_(count_no));
+}
+
+static unsigned int iommu_pm_read_counter(struct iommu_pmon_counter *counter)
+{
+ struct iommu_pmon *pmon = counter->cnt_group->pmon;
+ struct iommu_info *info = &pmon->iommu;
+ unsigned int cnt_no = counter->absolute_counter_no;
+ return readl_relaxed(info->base + PMEVCNTR_(cnt_no));
+}
+
+static void iommu_pm_initialize_hw(const struct iommu_pmon *pmon)
+{
+ /* No initialization needed */
+}
+
+static struct iommu_pm_hw_ops iommu_pm_hw_ops = {
+ .initialize_hw = iommu_pm_initialize_hw,
+ .is_hw_access_OK = iommu_pm_is_hw_access_OK,
+ .grp_enable = iommu_pm_grp_enable,
+ .grp_disable = iommu_pm_grp_disable,
+ .enable_pm = iommu_pm_enable,
+ .disable_pm = iommu_pm_disable,
+ .reset_counters = iommu_pm_reset_counters,
+ .check_for_overflow = iommu_pm_check_for_overflow,
+ .evt_ovfl_int_handler = iommu_pm_evt_ovfl_int_handler,
+ .counter_enable = iommu_pm_counter_enable,
+ .counter_disable = iommu_pm_counter_disable,
+ .ovfl_int_enable = iommu_pm_ovfl_int_enable,
+ .ovfl_int_disable = iommu_pm_ovfl_int_disable,
+ .set_event_class = iommu_pm_set_event_class,
+ .read_counter = iommu_pm_read_counter,
+};
+
+struct iommu_pm_hw_ops *iommu_pm_get_hw_ops_v1(void)
+{
+ return &iommu_pm_hw_ops;
+}
+EXPORT_SYMBOL(iommu_pm_get_hw_ops_v1);
+
diff --git a/drivers/iommu/msm_iommu_perfmon.c b/drivers/iommu/msm_iommu_perfmon.c
index 97bd660..41df1ed 100644
--- a/drivers/iommu/msm_iommu_perfmon.c
+++ b/drivers/iommu/msm_iommu_perfmon.c
@@ -20,40 +20,12 @@
#include <linux/interrupt.h>
#include <linux/bitops.h>
#include <linux/debugfs.h>
-#include <mach/iommu_hw-v1.h>
#include <mach/iommu.h>
#include <mach/iommu_perfmon.h>
-#define PMCR_P_MASK (0x1)
-#define PMCR_P_SHIFT (1)
-#define PMCR_P (PMCR_P_MASK << PMCR_P_SHIFT)
-#define PMCFGR_NCG_MASK (0xFF)
-#define PMCFGR_NCG_SHIFT (24)
-#define PMCFGR_NCG (PMCFGR_NCG_MASK << PMCFGR_NCG_SHIFT)
-#define PMCFGR_N_MASK (0xFF)
-#define PMCFGR_N_SHIFT (0)
-#define PMCFGR_N (PMCFGR_N_MASK << PMCFGR_N_SHIFT)
-#define CR_E 0x1
-#define CGCR_CEN 0x800
-#define CGCR_CEN_SHFT (1 << 11)
-#define PMCGCR_CGNC_MASK (0x0F)
-#define PMCGCR_CGNC_SHIFT (24)
-#define PMCGCR_CGNC (PMCGCR_CGNC_MASK << PMCGCR_CGNC_SHIFT)
-#define PMCGCR_(group) (PMCGCR_N + group*4)
-
-#define PMOVSCLR_(n) (PMOVSCLR_N + n*4)
-#define PMCNTENSET_(n) (PMCNTENSET_N + n*4)
-#define PMCNTENCLR_(n) (PMCNTENCLR_N + n*4)
-#define PMINTENSET_(n) (PMINTENSET_N + n*4)
-#define PMINTENCLR_(n) (PMINTENCLR_N + n*4)
-
-#define PMEVCNTR_(n) (PMEVCNTR_N + n*4)
-#define PMEVTYPER_(n) (PMEVTYPER_N + n*4)
-
static LIST_HEAD(iommu_list);
static struct dentry *msm_iommu_root_debugfs_dir;
static const char *NO_EVENT_CLASS_NAME = "none";
-static int NO_EVENT_CLASS = -1;
static const unsigned int MAX_EVEN_CLASS_NAME_LEN = 36;
struct event_class {
@@ -81,11 +53,6 @@
{ 0xb1, "tot_num_pred_axi_htw_read_req" },
};
-static unsigned int iommu_pm_is_hw_access_OK(const struct iommu_pmon *pmon)
-{
- return pmon->enabled && (pmon->iommu_attach_count > 0);
-}
-
static unsigned int iommu_pm_create_sup_cls_str(char **buf,
struct iommu_pmon *pmon)
{
@@ -151,7 +118,7 @@
size_t array_len;
struct event_class *ptr;
int i;
- int event_class = NO_EVENT_CLASS;
+ int event_class = MSM_IOMMU_PMU_NO_EVENT_CLASS;
if (strcmp(event_class_name, NO_EVENT_CLASS_NAME) == 0)
goto out;
@@ -194,170 +161,6 @@
return NULL;
}
-static void iommu_pm_grp_enable(struct iommu_info *iommu, unsigned int grp_no)
-{
- unsigned int pmcgcr;
- pmcgcr = readl_relaxed(iommu->base + PMCGCR_(grp_no));
- pmcgcr |= CGCR_CEN;
- writel_relaxed(pmcgcr, iommu->base + PMCGCR_(grp_no));
-}
-
-static void iommu_pm_grp_disable(struct iommu_info *iommu, unsigned int grp_no)
-{
- unsigned int pmcgcr;
- pmcgcr = readl_relaxed(iommu->base + PMCGCR_(grp_no));
- pmcgcr &= ~CGCR_CEN;
- writel_relaxed(pmcgcr, iommu->base + PMCGCR_(grp_no));
-}
-
-static void iommu_pm_enable(struct iommu_info *iommu)
-{
- unsigned int pmcr;
- pmcr = readl_relaxed(iommu->base + PMCR);
- pmcr |= CR_E;
- writel_relaxed(pmcr, iommu->base + PMCR);
-}
-
-static void iommu_pm_disable(struct iommu_info *iommu)
-{
- unsigned int pmcr;
- pmcr = readl_relaxed(iommu->base + PMCR);
- pmcr &= ~CR_E;
- writel_relaxed(pmcr, iommu->base + PMCR);
-}
-
-static void iommu_pm_reset_counters(const struct iommu_info *iommu)
-{
- unsigned int pmcr;
- pmcr = readl_relaxed(iommu->base + PMCR);
- pmcr |= PMCR_P;
- writel_relaxed(pmcr, iommu->base + PMCR);
-}
-
-static void iommu_pm_check_for_overflow(struct iommu_pmon *pmon)
-{
- struct iommu_pmon_counter *counter;
- struct iommu_info *iommu = &pmon->iommu;
- unsigned int reg_no = 0;
- unsigned int bit_no;
- unsigned int reg_value;
- unsigned int i;
- unsigned int j;
- unsigned int curr_reg = 0;
-
- reg_value = readl_relaxed(iommu->base + PMOVSCLR_(curr_reg));
-
- for (i = 0; i < pmon->num_groups; ++i) {
- struct iommu_pmon_cnt_group *cnt_grp = &pmon->cnt_grp[i];
- for (j = 0; j < cnt_grp->num_counters; ++j) {
- counter = &cnt_grp->counters[j];
- reg_no = counter->absolute_counter_no / 32;
- bit_no = counter->absolute_counter_no % 32;
- if (reg_no != curr_reg) {
- /* Clear overflow bits */
- writel_relaxed(reg_value, iommu->base +
- PMOVSCLR_(reg_no));
- curr_reg = reg_no;
- reg_value = readl_relaxed(iommu->base +
- PMOVSCLR_(curr_reg));
- }
-
- if (counter->enabled) {
- if (reg_value & (1 << bit_no))
- counter->overflow_count++;
- }
- }
- }
-
- /* Clear overflow */
- writel_relaxed(reg_value, iommu->base + PMOVSCLR_(reg_no));
-}
-
-irqreturn_t iommu_pm_evt_ovfl_int_handler(int irq, void *dev_id)
-{
- struct iommu_pmon *pmon = dev_id;
- struct iommu_info *iommu = &pmon->iommu;
-
- mutex_lock(&pmon->lock);
-
- if (!iommu_pm_is_hw_access_OK(pmon)) {
- mutex_unlock(&pmon->lock);
- goto out;
- }
-
- iommu->ops->iommu_lock_acquire();
- iommu_pm_check_for_overflow(pmon);
- iommu->ops->iommu_lock_release();
-
- mutex_unlock(&pmon->lock);
-
-out:
- return IRQ_HANDLED;
-}
-
-static void iommu_pm_counter_enable(struct iommu_info *iommu,
- struct iommu_pmon_counter *counter)
-{
- unsigned int reg_no = counter->absolute_counter_no / 32;
- unsigned int bit_no = counter->absolute_counter_no % 32;
- unsigned int reg_value;
-
- /* Clear overflow of counter */
- reg_value = 1 << bit_no;
- writel_relaxed(reg_value, iommu->base + PMOVSCLR_(reg_no));
-
- /* Enable counter */
- writel_relaxed(reg_value, iommu->base + PMCNTENSET_(reg_no));
- counter->enabled = 1;
-}
-
-static void iommu_pm_counter_disable(struct iommu_info *iommu,
- struct iommu_pmon_counter *counter)
-{
- unsigned int reg_no = counter->absolute_counter_no / 32;
- unsigned int bit_no = counter->absolute_counter_no % 32;
- unsigned int reg_value;
-
- counter->enabled = 0;
-
- /* Disable counter */
- reg_value = 1 << bit_no;
- writel_relaxed(reg_value, iommu->base + PMCNTENCLR_(reg_no));
-
- /* Clear overflow of counter */
- writel_relaxed(reg_value, iommu->base + PMOVSCLR_(reg_no));
-}
-
-/*
- * Must be called after iommu_start_access() is called
- */
-static void iommu_pm_ovfl_int_enable(struct iommu_info *iommu,
- const struct iommu_pmon_counter *counter)
-{
- unsigned int reg_no = counter->absolute_counter_no / 32;
- unsigned int bit_no = counter->absolute_counter_no % 32;
- unsigned int reg_value;
-
- /* Enable overflow interrupt for counter */
- reg_value = (1 << bit_no);
- writel_relaxed(reg_value, iommu->base + PMINTENSET_(reg_no));
-}
-
-/*
- * Must be called after iommu_start_access() is called
- */
-static void iommu_pm_ovfl_int_disable(struct iommu_info *iommu,
- const struct iommu_pmon_counter *counter)
-{
- unsigned int reg_no = counter->absolute_counter_no / 32;
- unsigned int bit_no = counter->absolute_counter_no % 32;
- unsigned int reg_value;
-
- /* Disable overflow interrupt for counter */
- reg_value = 1 << bit_no;
- writel_relaxed(reg_value, iommu->base + PMINTENCLR_(reg_no));
-}
-
static void iommu_pm_set_event_type(struct iommu_pmon *pmon,
struct iommu_pmon_counter *counter)
{
@@ -368,12 +171,12 @@
event_class = counter->current_event_class;
count_no = counter->absolute_counter_no;
- if (event_class == NO_EVENT_CLASS) {
- if (iommu_pm_is_hw_access_OK(pmon)) {
+ if (event_class == MSM_IOMMU_PMU_NO_EVENT_CLASS) {
+ if (iommu->hw_ops->is_hw_access_OK(pmon)) {
iommu->ops->iommu_lock_acquire();
- iommu_pm_counter_disable(iommu, counter);
- iommu_pm_ovfl_int_disable(iommu, counter);
- writel_relaxed(0, iommu->base + PMEVTYPER_(count_no));
+ iommu->hw_ops->counter_disable(iommu, counter);
+ iommu->hw_ops->ovfl_int_disable(iommu, counter);
+ iommu->hw_ops->set_event_class(pmon, count_no, 0);
iommu->ops->iommu_lock_release();
}
counter->overflow_count = 0;
@@ -381,12 +184,12 @@
} else {
counter->overflow_count = 0;
counter->value = 0;
- if (iommu_pm_is_hw_access_OK(pmon)) {
+ if (iommu->hw_ops->is_hw_access_OK(pmon)) {
iommu->ops->iommu_lock_acquire();
- writel_relaxed(event_class,
- iommu->base + PMEVTYPER_(count_no));
- iommu_pm_ovfl_int_enable(iommu, counter);
- iommu_pm_counter_enable(iommu, counter);
+ iommu->hw_ops->set_event_class(pmon, count_no,
+ event_class);
+ iommu->hw_ops->ovfl_int_enable(iommu, counter);
+ iommu->hw_ops->counter_enable(iommu, counter);
iommu->ops->iommu_lock_release();
}
}
@@ -405,19 +208,6 @@
}
}
-static unsigned int iommu_pm_read_counter(struct iommu_pmon_counter *counter)
-{
- struct iommu_pmon *pmon = counter->cnt_group->pmon;
- struct iommu_info *info = &pmon->iommu;
- unsigned int cnt_no = counter->absolute_counter_no;
- unsigned int pmevcntr;
-
- pmevcntr = readl_relaxed(info->base + PMEVCNTR_(cnt_no));
-
- return pmevcntr;
-
-}
-
static void iommu_pm_set_all_counters(struct iommu_pmon *pmon)
{
unsigned int i;
@@ -433,12 +223,13 @@
{
unsigned int i;
unsigned int j;
+ struct iommu_info *iommu = &pmon->iommu;
for (i = 0; i < pmon->num_groups; ++i) {
struct iommu_pmon_cnt_group *cnt_grp = &pmon->cnt_grp[i];
for (j = 0; j < cnt_grp->num_counters; ++j) {
struct iommu_pmon_counter *counter;
counter = &cnt_grp->counters[j];
- counter->value = iommu_pm_read_counter(counter);
+ counter->value = iommu->hw_ops->read_counter(counter);
}
}
}
@@ -452,6 +243,12 @@
iommu->ops->iommu_power_on(iommu_drvdata);
+ /* Reset counters in HW */
+ iommu->ops->iommu_lock_acquire();
+ iommu->hw_ops->reset_counters(&pmon->iommu);
+ iommu->ops->iommu_lock_release();
+
+ /* Reset SW counters */
iommu_pm_reset_counts(pmon);
pmon->enabled = 1;
@@ -462,10 +259,10 @@
/* enable all counter group */
for (i = 0; i < pmon->num_groups; ++i)
- iommu_pm_grp_enable(iommu, i);
+ iommu->hw_ops->grp_enable(iommu, i);
/* enable global counters */
- iommu_pm_enable(iommu);
+ iommu->hw_ops->enable_pm(iommu);
iommu->ops->iommu_lock_release();
pr_info("%s: TLB performance monitoring turned ON\n",
@@ -484,14 +281,14 @@
iommu->ops->iommu_lock_acquire();
/* disable global counters */
- iommu_pm_disable(iommu);
+ iommu->hw_ops->disable_pm(iommu);
/* Check if we overflowed just before turning off pmon */
- iommu_pm_check_for_overflow(pmon);
+ iommu->hw_ops->check_for_overflow(pmon);
/* disable all counter group */
for (i = 0; i < pmon->num_groups; ++i)
- iommu_pm_grp_disable(iommu, i);
+ iommu->hw_ops->grp_disable(iommu, i);
/* Update cached copy of counters before turning off power */
iommu_pm_read_all_counters(pmon);
@@ -524,9 +321,9 @@
mutex_lock(&pmon->lock);
- if (iommu_pm_is_hw_access_OK(pmon)) {
+ if (iommu->hw_ops->is_hw_access_OK(pmon)) {
iommu->ops->iommu_lock_acquire();
- counter->value = iommu_pm_read_counter(counter);
+ counter->value = iommu->hw_ops->read_counter(counter);
iommu->ops->iommu_lock_release();
}
full_count = (unsigned long long) counter->value +
@@ -631,9 +428,9 @@
buf[wr_cnt-1] = '\0';
rv = kstrtoul(buf, 10, &cmd);
if (!rv && (cmd == 1)) {
- if (iommu_pm_is_hw_access_OK(pmon)) {
+ if (iommu->hw_ops->is_hw_access_OK(pmon)) {
iommu->ops->iommu_lock_acquire();
- iommu_pm_reset_counters(&pmon->iommu);
+ iommu->hw_ops->reset_counters(&pmon->iommu);
iommu->ops->iommu_lock_release();
}
iommu_pm_reset_counts(pmon);
@@ -761,7 +558,8 @@
(*abs_counter_no)++;
cnt_grp->counters[j].value = 0;
cnt_grp->counters[j].overflow_count = 0;
- cnt_grp->counters[j].current_event_class = NO_EVENT_CLASS;
+ cnt_grp->counters[j].current_event_class =
+ MSM_IOMMU_PMU_NO_EVENT_CLASS;
snprintf(name, 20, "counter%u", j);
@@ -894,11 +692,13 @@
if (ret)
goto free_mem;
+ iommu->hw_ops->initialize_hw(pmon_entry);
+
if (iommu->evt_irq > 0) {
ret = request_threaded_irq(iommu->evt_irq, NULL,
- iommu_pm_evt_ovfl_int_handler,
+ iommu->hw_ops->evt_ovfl_int_handler,
IRQF_ONESHOT | IRQF_SHARED,
- "msm_iommu_nonsecure_irq", pmon_entry);
+ "msm_iommu_pmon_nonsecure_irq", pmon_entry);
if (ret) {
pr_err("Request IRQ %d failed with ret=%d\n",
iommu->evt_irq,
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
index d714ffb..69d523c 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
@@ -77,8 +77,6 @@
void (*process_axi_irq) (struct vfe_device *vfe_dev,
uint32_t irq_status0, uint32_t irq_status1,
struct msm_isp_timestamp *ts);
- void (*process_error_irq) (struct vfe_device *vfe_dev,
- uint32_t irq_status0, uint32_t irq_status1);
void (*process_stats_irq) (struct vfe_device *vfe_dev,
uint32_t irq_status0, uint32_t irq_status1,
struct msm_isp_timestamp *ts);
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
index 8f00e80..b981653 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
@@ -17,11 +17,13 @@
#include "msm_isp32.h"
#include "msm_isp_util.h"
#include "msm_isp_axi_util.h"
+#include "msm_isp_stats_util.h"
#include "msm_isp.h"
#include "msm.h"
#include "msm_camera_io_util.h"
-#define VFE32_BURST_LEN 4
+#define VFE32_BURST_LEN 3
+#define VFE32_UB_SIZE 1024
#define VFE32_EQUAL_SLICE_UB 117
#define VFE32_WM_BASE(idx) (0x4C + 0x18 * idx)
#define VFE32_RDI_BASE(idx) (idx ? 0x734 + 0x4 * (idx - 1) : 0x06FC)
@@ -30,6 +32,13 @@
#define VFE32_PING_PONG_BASE(wm, ping_pong) \
(VFE32_WM_BASE(wm) + 0x4 * (1 + (~(ping_pong >> wm) & 0x1)))
+#define VFE32_NUM_STATS_TYPE 7
+#define VFE32_STATS_PING_PONG_OFFSET 7
+#define VFE32_STATS_BASE(idx) (0xF4 + 0xC * idx)
+#define VFE32_STATS_PING_PONG_BASE(idx, ping_pong) \
+ (VFE32_STATS_BASE(idx) + 0x4 * \
+ (~(ping_pong >> (idx + VFE32_STATS_PING_PONG_OFFSET)) & 0x1))
+
/*Temporary use fixed bus vectors in VFE */
static struct msm_bus_vectors msm_vfe32_init_vectors[] = {
{
@@ -177,17 +186,16 @@
ISP_DBG("%s: PIX0 frame id: %lu\n", __func__,
vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id);
msm_isp_sof_notify(vfe_dev, VFE_PIX_0, ts);
+ ISP_DBG("%s: SOF IRQ\n", __func__);
+ if (vfe_dev->axi_data.src_info[VFE_PIX_0].raw_stream_count > 0
+ && vfe_dev->axi_data.src_info[VFE_PIX_0].
+ pix_stream_count == 0) {
+ msm_isp_sof_notify(vfe_dev, VFE_PIX_0, ts);
+ msm_isp_update_framedrop_reg(vfe_dev);
+ }
}
}
-static void msm_vfe32_process_stats_irq(struct vfe_device *vfe_dev,
- uint32_t irq_status0, uint32_t irq_status1,
- struct msm_isp_timestamp *ts)
-{
- /* todo: add stats specific code */
- return;
-}
-
static void msm_vfe32_process_violation_status(struct vfe_device *vfe_dev)
{
uint32_t violation_status = vfe_dev->error_info.violation_status;
@@ -326,12 +334,22 @@
if (!(irq_status0 & 0x20) && !(irq_status1 & 0x1C000000))
return;
+ if (irq_status0 & BIT(5))
+ msm_isp_sof_notify(vfe_dev, VFE_PIX_0, ts);
+ if (irq_status1 & BIT(26))
+ msm_isp_sof_notify(vfe_dev, VFE_RAW_0, ts);
+ if (irq_status1 & BIT(27))
+ msm_isp_sof_notify(vfe_dev, VFE_RAW_1, ts);
+ if (irq_status1 & BIT(28))
+ msm_isp_sof_notify(vfe_dev, VFE_RAW_2, ts);
+
if (vfe_dev->axi_data.stream_update)
msm_isp_axi_stream_update(vfe_dev);
-
msm_isp_update_framedrop_reg(vfe_dev);
msm_isp_update_error_frame_count(vfe_dev);
+ vfe_dev->hw_info->vfe_ops.core_ops.
+ reg_update(vfe_dev);
return;
}
@@ -462,6 +480,46 @@
}
}
+static void msm_vfe32_cfg_io_format(struct vfe_device *vfe_dev,
+ struct msm_vfe_axi_stream_request_cmd *stream_req_cmd)
+{
+ int bpp, bpp_reg = 0;
+ uint32_t io_format_reg;
+ bpp = msm_isp_get_bit_per_pixel(stream_req_cmd->output_format);
+
+ switch (bpp) {
+ case 8:
+ bpp_reg = 0;
+ break;
+ case 10:
+ bpp_reg = 1 << 0;
+ break;
+ case 12:
+ bpp_reg = 1 << 1;
+ break;
+ }
+ io_format_reg = msm_camera_io_r(vfe_dev->vfe_base + 0x6F8);
+ switch (stream_req_cmd->stream_src) {
+ case CAMIF_RAW:
+ io_format_reg &= 0xFFFFCFFF;
+ io_format_reg |= bpp_reg << 12;
+ break;
+ case IDEAL_RAW:
+ io_format_reg &= 0xFFFFFFC8;
+ io_format_reg |= bpp_reg << 4;
+ break;
+ case PIX_ENCODER:
+ case PIX_VIEWFINDER:
+ case RDI_INTF_0:
+ case RDI_INTF_1:
+ case RDI_INTF_2:
+ default:
+ pr_err("%s: Invalid stream source\n", __func__);
+ return;
+ }
+ msm_camera_io_w(io_format_reg, vfe_dev->vfe_base + 0x6F8);
+}
+
static void msm_vfe32_cfg_camif(struct vfe_device *vfe_dev,
struct msm_vfe_pix_cfg *pix_cfg)
{
@@ -481,10 +539,10 @@
camif_cfg->pixels_per_line,
vfe_dev->vfe_base + 0x1EC);
- msm_camera_io_w(ISP_SUB(first_pixel) << 16 | ISP_SUB(last_pixel),
+ msm_camera_io_w(first_pixel << 16 | last_pixel,
vfe_dev->vfe_base + 0x1F0);
- msm_camera_io_w(ISP_SUB(first_line) << 16 | ISP_SUB(last_line),
+ msm_camera_io_w(first_line << 16 | last_line,
vfe_dev->vfe_base + 0x1F4);
val = msm_camera_io_r(vfe_dev->vfe_base + 0x6FC);
@@ -518,6 +576,9 @@
} else if (update_state == DISABLE_CAMIF) {
msm_camera_io_w_mb(0x0, vfe_dev->vfe_base + 0x1E0);
vfe_dev->axi_data.src_info[VFE_PIX_0].active = 0;
+ } else if (update_state == DISABLE_CAMIF_IMMEDIATELY) {
+ msm_camera_io_w_mb(0x2, vfe_dev->vfe_base + 0x1E0);
+ vfe_dev->axi_data.src_info[VFE_PIX_0].active = 0;
}
}
@@ -723,7 +784,28 @@
static int msm_vfe32_get_stats_idx(enum msm_isp_stats_type stats_type)
{
- return 0;
+ switch (stats_type) {
+ case MSM_ISP_STATS_AEC:
+ case MSM_ISP_STATS_BG:
+ return 0;
+ case MSM_ISP_STATS_AF:
+ case MSM_ISP_STATS_BF:
+ return 1;
+ case MSM_ISP_STATS_AWB:
+ return 2;
+ case MSM_ISP_STATS_RS:
+ return 3;
+ case MSM_ISP_STATS_CS:
+ return 4;
+ case MSM_ISP_STATS_IHIST:
+ return 5;
+ case MSM_ISP_STATS_SKIN:
+ case MSM_ISP_STATS_BHIST:
+ return 6;
+ default:
+ pr_err("%s: Invalid stats type\n", __func__);
+ return -EINVAL;
+ }
}
static void msm_vfe32_stats_cfg_comp_mask(struct vfe_device *vfe_dev)
@@ -734,60 +816,120 @@
static void msm_vfe32_stats_cfg_wm_irq_mask(struct vfe_device *vfe_dev,
struct msm_vfe_stats_stream *stream_info)
{
+ uint32_t irq_mask;
+ irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x1C);
+ irq_mask |= BIT(STATS_IDX(stream_info->stream_handle) + 13);
+ msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x1C);
return;
}
static void msm_vfe32_stats_clear_wm_irq_mask(struct vfe_device *vfe_dev,
struct msm_vfe_stats_stream *stream_info)
{
+ uint32_t irq_mask;
+ irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x1C);
+ irq_mask &= ~(BIT(STATS_IDX(stream_info->stream_handle) + 13));
+ msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x1C);
return;
}
static void msm_vfe32_stats_cfg_wm_reg(struct vfe_device *vfe_dev,
struct msm_vfe_stats_stream *stream_info)
{
+ /*Nothing to configure for VFE3.x*/
return;
}
static void msm_vfe32_stats_clear_wm_reg(struct vfe_device *vfe_dev,
struct msm_vfe_stats_stream *stream_info)
{
+ /*Nothing to configure for VFE3.x*/
return;
}
static void msm_vfe32_stats_cfg_ub(struct vfe_device *vfe_dev)
{
+ int i;
+ uint32_t ub_offset = VFE32_UB_SIZE;
+ uint32_t ub_size[VFE32_NUM_STATS_TYPE] = {
+ 64, /*MSM_ISP_STATS_BG*/
+ 64, /*MSM_ISP_STATS_BF*/
+ 16, /*MSM_ISP_STATS_AWB*/
+ 8, /*MSM_ISP_STATS_RS*/
+ 16, /*MSM_ISP_STATS_CS*/
+ 16, /*MSM_ISP_STATS_IHIST*/
+ 16, /*MSM_ISP_STATS_BHIST*/
+ };
+
+ for (i = 0; i < VFE32_NUM_STATS_TYPE; i++) {
+ ub_offset -= ub_size[i];
+ msm_camera_io_w(ub_offset << 16 | (ub_size[i] - 1),
+ vfe_dev->vfe_base + VFE32_STATS_BASE(i) + 0x8);
+ }
return;
}
static void msm_vfe32_stats_enable_module(struct vfe_device *vfe_dev,
uint32_t stats_mask, uint8_t enable)
{
- return;
+ int i;
+ uint32_t module_cfg, module_cfg_mask = 0;
+
+ for (i = 0; i < VFE32_NUM_STATS_TYPE; i++) {
+ if ((stats_mask >> i) & 0x1) {
+ switch (i) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ module_cfg_mask |= 1 << (5 + i);
+ break;
+ case 5:
+ module_cfg_mask |= 1 << 16;
+ break;
+ case 6:
+ module_cfg_mask |= 1 << 19;
+ break;
+ default:
+ pr_err("%s: Invalid stats mask\n", __func__);
+ return;
+ }
+ }
+ }
+
+ module_cfg = msm_camera_io_r(vfe_dev->vfe_base + 0x10);
+ if (enable)
+ module_cfg |= module_cfg_mask;
+ else
+ module_cfg &= ~module_cfg_mask;
+ msm_camera_io_w(module_cfg, vfe_dev->vfe_base + 0x10);
}
static void msm_vfe32_stats_update_ping_pong_addr(struct vfe_device *vfe_dev,
struct msm_vfe_stats_stream *stream_info, uint32_t pingpong_status,
unsigned long paddr)
{
- return;
+ int stats_idx = STATS_IDX(stream_info->stream_handle);
+ msm_camera_io_w(paddr, vfe_dev->vfe_base +
+ VFE32_STATS_PING_PONG_BASE(stats_idx, pingpong_status));
}
static uint32_t msm_vfe32_stats_get_wm_mask(uint32_t irq_status0,
uint32_t irq_status1)
{
- return 0;
+ return (irq_status0 >> 13) & 0x7F;
}
static uint32_t msm_vfe32_stats_get_comp_mask(uint32_t irq_status0,
uint32_t irq_status1)
{
- return 0;
+ return (irq_status0 >> 24) & 0x1;
}
static uint32_t msm_vfe32_stats_get_frame_id(struct vfe_device *vfe_dev)
{
- return 0;
+ return vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id;
}
static int msm_vfe32_get_platform_data(struct vfe_device *vfe_dev)
@@ -850,6 +992,18 @@
.num_rdi_master = 3,
};
+static struct msm_vfe_stats_hardware_info msm_vfe32_stats_hw_info = {
+ .stats_capability_mask =
+ 1 << MSM_ISP_STATS_AEC | 1 << MSM_ISP_STATS_BG |
+ 1 << MSM_ISP_STATS_AF | 1 << MSM_ISP_STATS_BF |
+ 1 << MSM_ISP_STATS_AWB | 1 << MSM_ISP_STATS_IHIST |
+ 1 << MSM_ISP_STATS_RS | 1 << MSM_ISP_STATS_CS |
+ 1 << MSM_ISP_STATS_SKIN | 1 << MSM_ISP_STATS_BHIST,
+ .stats_ping_pong_offset = VFE32_STATS_PING_PONG_OFFSET,
+ .num_stats_type = VFE32_NUM_STATS_TYPE,
+ .num_stats_comp_mask = 0,
+};
+
static struct v4l2_subdev_core_ops msm_vfe32_subdev_core_ops = {
.ioctl = msm_isp_ioctl,
.subscribe_event = msm_isp_subscribe_event,
@@ -875,11 +1029,12 @@
.process_halt_irq = msm_vfe32_process_halt_irq,
.process_reg_update = msm_vfe32_process_reg_update,
.process_axi_irq = msm_isp_process_axi_irq,
- .process_stats_irq = msm_vfe32_process_stats_irq,
+ .process_stats_irq = msm_isp_process_stats_irq,
},
.axi_ops = {
.reload_wm = msm_vfe32_axi_reload_wm,
.enable_wm = msm_vfe32_axi_enable_wm,
+ .cfg_io_format = msm_vfe32_cfg_io_format,
.cfg_comp_mask = msm_vfe32_axi_cfg_comp_mask,
.clear_comp_mask = msm_vfe32_axi_clear_comp_mask,
.cfg_wm_irq_mask = msm_vfe32_axi_cfg_wm_irq_mask,
@@ -930,6 +1085,7 @@
},
.dmi_reg_offset = 0x5A0,
.axi_hw_info = &msm_vfe32_axi_hw_info,
+ .stats_hw_info = &msm_vfe32_stats_hw_info,
.subdev_ops = &msm_vfe32_subdev_ops,
.subdev_internal_ops = &msm_vfe32_internal_ops,
};
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
index fa0bf18..f08644f 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
@@ -369,15 +369,10 @@
msm_isp_send_event(vfe_dev, ISP_EVENT_SOF, &sof_event);
}
-void msm_isp_calculate_framedrop(
- struct msm_vfe_axi_shared_data *axi_data,
- struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd)
+uint32_t msm_isp_get_framedrop_period(
+ enum msm_vfe_frame_skip_pattern frame_skip_pattern)
{
- struct msm_vfe_axi_stream *stream_info =
- &axi_data->stream_info[
- (stream_cfg_cmd->axi_stream_handle & 0xFF)];
- uint32_t framedrop_period = 1;
- switch (stream_cfg_cmd->frame_skip_pattern) {
+ switch (frame_skip_pattern) {
case NO_SKIP:
case EVERY_2FRAME:
case EVERY_3FRAME:
@@ -386,18 +381,28 @@
case EVERY_6FRAME:
case EVERY_7FRAME:
case EVERY_8FRAME:
- framedrop_period = stream_cfg_cmd->frame_skip_pattern + 1;
- break;
+ return frame_skip_pattern + 1;
case EVERY_16FRAME:
- framedrop_period = 16;
+ return 16;
break;
case EVERY_32FRAME:
- framedrop_period = 32;
+ return 32;
break;
default:
- framedrop_period = 1;
- break;
+ return 1;
}
+ return 1;
+}
+
+void msm_isp_calculate_framedrop(
+ struct msm_vfe_axi_shared_data *axi_data,
+ struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd)
+{
+ struct msm_vfe_axi_stream *stream_info =
+ &axi_data->stream_info[
+ (stream_cfg_cmd->axi_stream_handle & 0xFF)];
+ uint32_t framedrop_period = msm_isp_get_framedrop_period(
+ stream_cfg_cmd->frame_skip_pattern);
stream_info->framedrop_pattern = 0x1;
stream_info->framedrop_period = framedrop_period - 1;
@@ -911,8 +916,16 @@
stream_info->bufq_handle,
MSM_ISP_BUFFER_FLUSH_DIVERTED);
break;
- case UPDATE_STREAM_FRAMEDROP_PATTERN:
+ case UPDATE_STREAM_FRAMEDROP_PATTERN: {
+ uint32_t framedrop_period =
+ msm_isp_get_framedrop_period(update_cmd->skip_pattern);
+ stream_info->runtime_init_frame_drop = 0;
+ stream_info->framedrop_pattern = 0x1;
+ stream_info->framedrop_period = framedrop_period - 1;
+ vfe_dev->hw_info->vfe_ops.axi_ops.
+ cfg_framedrop(vfe_dev, stream_info);
break;
+ }
default:
pr_err("%s: Invalid update type\n", __func__);
return -EINVAL;
diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
index 7d0f9cb..691edc3 100644
--- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
+++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
@@ -94,6 +94,13 @@
if (data > 0x1) {
unsigned long jiffes = msecs_to_jiffies(500);
long lrc = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ispif->auto_complete_lock, flags);
+ ispif->wait_timeout = 0;
+ init_completion(&ispif->reset_complete);
+ spin_unlock_irqrestore(&ispif->auto_complete_lock, flags);
+
if (params->vfe_intf == VFE0)
msm_camera_io_w(data, ispif->base + ISPIF_RST_CMD_ADDR);
else
@@ -104,6 +111,11 @@
if (lrc < 0 || !lrc) {
pr_err("%s: wait timeout ret = %ld\n", __func__, lrc);
rc = -EIO;
+
+ spin_lock_irqsave(&ispif->auto_complete_lock, flags);
+ ispif->wait_timeout = 1;
+ spin_unlock_irqrestore(
+ &ispif->auto_complete_lock, flags);
}
}
return rc;
@@ -114,6 +126,12 @@
int rc = 0;
long lrc = 0;
unsigned long jiffes = msecs_to_jiffies(500);
+ unsigned long flags;
+
+ spin_lock_irqsave(&ispif->auto_complete_lock, flags);
+ ispif->wait_timeout = 0;
+ init_completion(&ispif->reset_complete);
+ spin_unlock_irqrestore(&ispif->auto_complete_lock, flags);
BUG_ON(!ispif);
@@ -125,14 +143,17 @@
msm_camera_io_w_mb(ISPIF_RST_CMD_1_MASK, ispif->base +
ISPIF_RST_CMD_1_ADDR);
- CDBG("%s: Sending reset\n", __func__);
lrc = wait_for_completion_interruptible_timeout(
&ispif->reset_complete, jiffes);
+
if (lrc < 0 || !lrc) {
pr_err("%s: wait timeout ret = %ld\n", __func__, lrc);
rc = -EIO;
+
+ spin_lock_irqsave(&ispif->auto_complete_lock, flags);
+ ispif->wait_timeout = 1;
+ spin_unlock_irqrestore(&ispif->auto_complete_lock, flags);
}
- CDBG("%s: reset returned\n", __func__);
return rc;
}
@@ -571,8 +592,14 @@
ispif->base + ISPIF_IRQ_CLEAR_2_ADDR);
if (out[VFE0].ispifIrqStatus0 & ISPIF_IRQ_STATUS_MASK) {
- if (out[VFE0].ispifIrqStatus0 & RESET_DONE_IRQ)
- complete(&ispif->reset_complete);
+ if (out[VFE0].ispifIrqStatus0 & RESET_DONE_IRQ) {
+ unsigned long flags;
+ spin_lock_irqsave(&ispif->auto_complete_lock, flags);
+ if (ispif->wait_timeout == 0)
+ complete(&ispif->reset_complete);
+ spin_unlock_irqrestore(
+ &ispif->auto_complete_lock, flags);
+ }
if (out[VFE0].ispifIrqStatus0 & PIX_INTF_0_OVERFLOW_IRQ)
pr_err("%s: VFE0 pix0 overflow.\n", __func__);
@@ -709,8 +736,6 @@
goto error_irq;
}
- init_completion(&ispif->reset_complete);
-
rc = msm_ispif_reset(ispif);
if (rc == 0) {
ispif->ispif_state = ISPIF_POWER_UP;
@@ -830,13 +855,8 @@
struct ispif_device *ispif = v4l2_get_subdevdata(sd);
mutex_lock(&ispif->mutex);
- if (ispif->open_cnt > 0) {
- CDBG("%s: dev already open\n", __func__);
- goto end;
- }
/* mem remap is done in init when the clock is on */
ispif->open_cnt++;
-end:
mutex_unlock(&ispif->mutex);
return 0;
}
@@ -940,7 +960,8 @@
ispif->pdev = pdev;
ispif->ispif_state = ISPIF_POWER_DOWN;
ispif->open_cnt = 0;
-
+ spin_lock_init(&ispif->auto_complete_lock);
+ ispif->wait_timeout = 0;
return 0;
error:
diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.h b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.h
index c4418c1..f8c3cce 100644
--- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.h
+++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.h
@@ -48,6 +48,8 @@
struct mutex mutex;
uint8_t start_ack_pending;
struct completion reset_complete;
+ spinlock_t auto_complete_lock;
+ uint8_t wait_timeout;
uint32_t csid_version;
int enb_dump_reg;
uint32_t open_cnt;
diff --git a/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c b/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c
index 9af6674..77dc6f5 100644
--- a/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c
+++ b/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c
@@ -35,7 +35,9 @@
}
new_entry->session_id = buf_info->session_id;
new_entry->stream_id = buf_info->stream_id;
+ mutex_lock(&buf_mngr_dev->buf_q_lock);
list_add_tail(&new_entry->entry, &buf_mngr_dev->buf_qhead);
+ mutex_unlock(&buf_mngr_dev->buf_q_lock);
buf_info->index = new_entry->vb2_buf->v4l2_buf.index;
return 0;
}
@@ -55,7 +57,9 @@
(bufs->vb2_buf,
buf_info->session_id,
buf_info->stream_id);
+ mutex_lock(&buf_mngr_dev->buf_q_lock);
list_del_init(&bufs->entry);
+ mutex_unlock(&buf_mngr_dev->buf_q_lock);
kfree(bufs);
break;
}
@@ -76,7 +80,9 @@
(bufs->vb2_buf->v4l2_buf.index == buf_info->index)) {
ret = buf_mngr_dev->vb2_ops.put_buf(bufs->vb2_buf,
buf_info->session_id, buf_info->stream_id);
+ mutex_lock(&buf_mngr_dev->buf_q_lock);
list_del_init(&bufs->entry);
+ mutex_unlock(&buf_mngr_dev->buf_q_lock);
kfree(bufs);
break;
}
@@ -156,12 +162,14 @@
&msm_buf_mngr_dev->vb2_ops);
INIT_LIST_HEAD(&msm_buf_mngr_dev->buf_qhead);
+ mutex_init(&msm_buf_mngr_dev->buf_q_lock);
end:
return rc;
}
static void __exit msm_buf_mngr_exit(void)
{
+ mutex_destroy(&msm_buf_mngr_dev->buf_q_lock);
kfree(msm_buf_mngr_dev);
}
diff --git a/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.h b/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.h
index 7e588cc..a2b3a7e 100644
--- a/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.h
+++ b/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.h
@@ -33,6 +33,7 @@
struct msm_buf_mngr_device {
struct list_head buf_qhead;
+ struct mutex buf_q_lock;
struct msm_sd_subdev subdev;
struct msm_sd_req_vb2_q vb2_ops;
};
diff --git a/drivers/media/platform/msm/camera_v2/sensor/Makefile b/drivers/media/platform/msm/camera_v2/sensor/Makefile
index d0b6c62..f6011ba 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/Makefile
+++ b/drivers/media/platform/msm/camera_v2/sensor/Makefile
@@ -3,7 +3,7 @@
ccflags-y += -Idrivers/media/platform/msm/camera_v2/camera
ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io
ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/cci
-obj-$(CONFIG_MSMB_CAMERA) += cci/ io/ csiphy/ csid/ actuator/
+obj-$(CONFIG_MSMB_CAMERA) += cci/ io/ csiphy/ csid/ actuator/ flash/
obj-$(CONFIG_MSM_CAMERA_SENSOR) += msm_sensor.o
obj-$(CONFIG_S5K3L1YX) += s5k3l1yx.o
obj-$(CONFIG_OV2720) += ov2720.o
diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/Makefile b/drivers/media/platform/msm/camera_v2/sensor/flash/Makefile
new file mode 100644
index 0000000..4ce7372
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/flash/Makefile
@@ -0,0 +1,4 @@
+ccflags-y += -Idrivers/media/platform/msm/camera_v2
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io
+obj-$(CONFIG_MSMB_CAMERA) += msm_led_flash.o
+obj-$(CONFIG_MSMB_CAMERA) += msm_led_trigger.o
diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.c b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.c
index ba2c87d..9119a13 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.c
@@ -27,7 +27,6 @@
unsigned int cmd, void *arg)
{
struct msm_led_flash_ctrl_t *fctrl = NULL;
- int32_t rc = 0;
void __user *argp = (void __user *)arg;
if (!sd) {
pr_err("sd NULL\n");
@@ -39,9 +38,10 @@
return -EINVAL;
}
switch (cmd) {
+ case VIDIOC_MSM_SENSOR_GET_SUBDEV_ID:
+ return fctrl->func_tbl->flash_get_subdev_id(fctrl, argp);
case VIDIOC_MSM_FLASH_LED_DATA_CFG:
- rc = fctrl->func_tbl->flash_led_config(fctrl, argp);
- return 0;
+ return fctrl->func_tbl->flash_led_config(fctrl, argp);
default:
pr_err("invalid cmd %d\n", cmd);
return -ENOIOCTLCMD;
diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.h b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.h
index 76c58d2..76aa695 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.h
+++ b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.h
@@ -24,6 +24,7 @@
struct msm_led_flash_ctrl_t;
struct msm_flash_fn_t {
+ int32_t (*flash_get_subdev_id)(struct msm_led_flash_ctrl_t *, void *);
int32_t (*flash_led_config)(struct msm_led_flash_ctrl_t *, void *);
int32_t (*flash_led_init)(struct msm_led_flash_ctrl_t *);
int32_t (*flash_led_release)(struct msm_led_flash_ctrl_t *);
diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_trigger.c b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_trigger.c
index 9d8981f..1a75a5a 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_trigger.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_trigger.c
@@ -28,6 +28,19 @@
static struct msm_led_flash_ctrl_t fctrl;
+static int32_t msm_led_trigger_get_subdev_id(struct msm_led_flash_ctrl_t *fctrl,
+ void *arg)
+{
+ uint32_t *subdev_id = (uint32_t *)arg;
+ if (!subdev_id) {
+ pr_err("%s:%d failed\n", __func__, __LINE__);
+ return -EINVAL;
+ }
+ *subdev_id = fctrl->pdev->id;
+ CDBG("%s:%d subdev_id %d\n", __func__, __LINE__, *subdev_id);
+ return 0;
+}
+
static int32_t msm_led_trigger_config(struct msm_led_flash_ctrl_t *fctrl,
void *data)
{
@@ -158,6 +171,7 @@
}
static struct msm_flash_fn_t msm_led_trigger_func_tbl = {
+ .flash_get_subdev_id = msm_led_trigger_get_subdev_id,
.flash_led_config = msm_led_trigger_config,
};
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 9062a9c..453b14a 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c
@@ -90,17 +90,21 @@
sensordata->sensor_info->subdev_id[SUB_MODULE_EEPROM] = val;
}
- if (of_property_read_bool(of_node, "qcom,led-flash-sd-index") ==
- true) {
- rc = of_property_read_u32(of_node, "qcom,led-flash-sd-index",
- &val);
- CDBG("%s qcom,led-flash-sd-index %d, rc %d\n", __func__, val,
- rc);
+ src_node = of_parse_phandle(of_node, "qcom,led-flash-src", 0);
+ if (!src_node) {
+ CDBG("%s:%d src_node NULL\n", __func__, __LINE__);
+ } else {
+ rc = of_property_read_u32(src_node, "cell-index", &val);
+ CDBG("%s qcom,led flash cell index %d, rc %d\n", __func__,
+ val, rc);
if (rc < 0) {
- pr_err("%s:%d failed rc %d\n", __func__, __LINE__, rc);
+ pr_err("%s:%d failed %d\n", __func__, __LINE__, rc);
goto ERROR;
}
- sensordata->sensor_info->subdev_id[SUB_MODULE_LED_FLASH] = val;
+ sensordata->sensor_info->
+ subdev_id[SUB_MODULE_LED_FLASH] = val;
+ of_node_put(src_node);
+ src_node = NULL;
}
if (of_property_read_bool(of_node, "qcom,strobe-flash-sd-index") ==
diff --git a/drivers/media/platform/msm/camera_v2/sensor/s5k3l1yx.c b/drivers/media/platform/msm/camera_v2/sensor/s5k3l1yx.c
index 9c36b5b..21a7369 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/s5k3l1yx.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/s5k3l1yx.c
@@ -54,6 +54,18 @@
.delay = 30,
},
{
+ .seq_type = SENSOR_GPIO,
+ .seq_val = SENSOR_GPIO_STANDBY,
+ .config_val = GPIO_OUT_LOW,
+ .delay = 1,
+ },
+ {
+ .seq_type = SENSOR_GPIO,
+ .seq_val = SENSOR_GPIO_STANDBY,
+ .config_val = GPIO_OUT_HIGH,
+ .delay = 30,
+ },
+ {
.seq_type = SENSOR_CLK,
.seq_val = SENSOR_CAM_MCLK,
.config_val = 0,
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 63ec1cf..9d89a7e 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
@@ -18,7 +18,7 @@
#include "mpq_dmx_plugin_common.h"
#include "mpq_sdmx.h"
-#define SDMX_MAJOR_VERSION_MATCH (2)
+#define SDMX_MAJOR_VERSION_MATCH (3)
#define TS_PACKET_HEADER_LENGTH (4)
@@ -847,7 +847,7 @@
mpq_dmx_info.devices = NULL;
mpq_dmx_info.ion_client = NULL;
- mpq_sdmx_check_app_loaded();
+ mpq_dmx_info.secure_demux_app_loaded = 0;
/*
* TODO: the following should be set based on the decoder:
@@ -4610,6 +4610,16 @@
int mpq_sdmx_is_loaded(void)
{
- return mpq_bypass_sdmx ? 0 : mpq_dmx_info.secure_demux_app_loaded;
+ static int sdmx_load_checked;
+
+ if (mpq_bypass_sdmx)
+ return 0;
+
+ if (!sdmx_load_checked) {
+ mpq_sdmx_check_app_loaded();
+ sdmx_load_checked = 1;
+ }
+
+ return mpq_dmx_info.secure_demux_app_loaded;
}
EXPORT_SYMBOL(mpq_sdmx_is_loaded);
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_sdmx.h b/drivers/media/platform/msm/dvb/demux/mpq_sdmx.h
index 0bd04e8..d292992 100644
--- a/drivers/media/platform/msm/dvb/demux/mpq_sdmx.h
+++ b/drivers/media/platform/msm/dvb/demux/mpq_sdmx.h
@@ -43,6 +43,7 @@
/* Filter-level status indicators */
#define SDMX_FILTER_STATUS_EOS BIT(0)
+#define SDMX_FILTER_STATUS_WR_PTR_CHANGED BIT(1)
/* Filter-level flags */
#define SDMX_FILTER_FLAG_VERIFY_SECTION_CRC BIT(0)
@@ -91,10 +92,9 @@
SDMX_STATUS_SINGLE_PID_RAW_FILTER = -11,
SDMX_STATUS_INP_BUF_INVALID_PARAMS = -12,
SDMX_STATUS_INVALID_FILTER_CFG = -13,
- SDMX_STATUS_ILLEGAL_WR_PTR_CHANGE = -14,
- SDMX_STATUS_STALLED_IN_PULL_MODE = -15,
- SDMX_STATUS_SECURITY_FAULT = -16,
- SDMX_STATUS_NS_BUFFER_ERROR = -17,
+ SDMX_STATUS_STALLED_IN_PULL_MODE = -14,
+ SDMX_STATUS_SECURITY_FAULT = -15,
+ SDMX_STATUS_NS_BUFFER_ERROR = -16,
};
enum sdmx_filter {
diff --git a/drivers/media/platform/msm/vidc/hfi_packetization.c b/drivers/media/platform/msm/vidc/hfi_packetization.c
index 1cabc3e..8593760 100644
--- a/drivers/media/platform/msm/vidc/hfi_packetization.c
+++ b/drivers/media/platform/msm/vidc/hfi_packetization.c
@@ -57,6 +57,27 @@
return 0;
}
+int create_pkt_cmd_sys_debug_config(
+ struct hfi_cmd_sys_set_property_packet *pkt,
+ u32 mode)
+{
+ struct hfi_debug_config *hfi;
+ if (!pkt)
+ return -EINVAL;
+
+ pkt->size = sizeof(struct hfi_cmd_sys_set_property_packet) +
+ sizeof(struct hfi_debug_config) + sizeof(u32);
+ pkt->packet_type = HFI_CMD_SYS_SET_PROPERTY;
+ pkt->num_properties = 1;
+ pkt->rg_property_data[0] = HFI_PROPERTY_SYS_DEBUG_CONFIG;
+ hfi = (struct hfi_debug_config *) &pkt->rg_property_data[1];
+ hfi->debug_config = mode;
+ hfi->debug_mode = HFI_DEBUG_MODE_QUEUE;
+ if (msm_fw_debug_mode <= HFI_DEBUG_MODE_QDSS)
+ hfi->debug_mode = msm_fw_debug_mode;
+ return 0;
+}
+
int create_pkt_set_cmd_sys_resource(
struct hfi_cmd_sys_set_resource_packet *pkt,
struct vidc_resource_hdr *resource_hdr,
diff --git a/drivers/media/platform/msm/vidc/hfi_packetization.h b/drivers/media/platform/msm/vidc/hfi_packetization.h
index 8c61a40..df93906 100644
--- a/drivers/media/platform/msm/vidc/hfi_packetization.h
+++ b/drivers/media/platform/msm/vidc/hfi_packetization.h
@@ -31,6 +31,10 @@
struct vidc_resource_hdr *resource_hdr,
void *resource_value);
+int create_pkt_cmd_sys_debug_config(
+ struct hfi_cmd_sys_set_property_packet *pkt,
+ u32 mode);
+
int create_pkt_cmd_sys_release_resource(
struct hfi_cmd_sys_release_resource_packet *pkt,
struct vidc_resource_hdr *resource_hdr);
diff --git a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
index 5d360bb..181b2b6 100644
--- a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
@@ -497,6 +497,14 @@
b->m.planes[i].reserved[0],
b->m.planes[i].reserved[1],
b->m.planes[i].length);
+ rc = msm_smem_cache_operations(v4l2_inst->mem_client,
+ binfo->handle[i], SMEM_CACHE_CLEAN);
+ if (rc)
+ dprintk(VIDC_WARN,
+ "CACHE Clean failed: %d, %d, %d\n",
+ b->m.planes[i].reserved[0],
+ b->m.planes[i].reserved[1],
+ b->m.planes[i].length);
}
b->m.planes[i].m.userptr = binfo->device_addr[i];
}
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index c7dfb97..cee48c7 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -88,27 +88,6 @@
"High Latency",
};
-static const char *const mpeg_video_vidc_extradata[] = {
- "Extradata none",
- "Extradata MB Quantization",
- "Extradata Interlace Video",
- "Extradata VC1 Framedisp",
- "Extradata VC1 Seqdisp",
- "Extradata timestamp",
- "Extradata S3D Frame Packing",
- "Extradata Frame Rate",
- "Extradata Panscan Window",
- "Extradata Recovery point SEI",
- "Extradata Closed Caption UD",
- "Extradata AFD UD",
- "Extradata Multislice info",
- "Extradata number of concealed MB",
- "Extradata metadata filler",
- "Extradata input crop",
- "Extradata digital zoom",
- "Extradata aspect ratio",
-};
-
enum msm_venc_ctrl_cluster {
MSM_VENC_CTRL_CLUSTER_QP = 1,
MSM_VENC_CTRL_CLUSTER_INTRA_PERIOD,
@@ -567,34 +546,16 @@
.cluster = 0,
},
{
- .id = V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA,
- .name = "Extradata Type",
- .type = V4L2_CTRL_TYPE_MENU,
- .minimum = V4L2_MPEG_VIDC_EXTRADATA_NONE,
- .maximum = V4L2_MPEG_VIDC_INDEX_EXTRADATA_ASPECT_RATIO,
- .default_value = V4L2_MPEG_VIDC_EXTRADATA_NONE,
- .menu_skip_mask = ~(
- (1 << V4L2_MPEG_VIDC_EXTRADATA_NONE) |
- (1 << V4L2_MPEG_VIDC_EXTRADATA_MB_QUANTIZATION) |
- (1 << V4L2_MPEG_VIDC_EXTRADATA_INTERLACE_VIDEO) |
- (1 << V4L2_MPEG_VIDC_EXTRADATA_VC1_FRAMEDISP) |
- (1 << V4L2_MPEG_VIDC_EXTRADATA_VC1_SEQDISP) |
- (1 << V4L2_MPEG_VIDC_EXTRADATA_TIMESTAMP) |
- (1 << V4L2_MPEG_VIDC_EXTRADATA_S3D_FRAME_PACKING) |
- (1 << V4L2_MPEG_VIDC_EXTRADATA_FRAME_RATE) |
- (1 << V4L2_MPEG_VIDC_EXTRADATA_PANSCAN_WINDOW) |
- (1 << V4L2_MPEG_VIDC_EXTRADATA_RECOVERY_POINT_SEI) |
- (1 << V4L2_MPEG_VIDC_EXTRADATA_CLOSED_CAPTION_UD) |
- (1 << V4L2_MPEG_VIDC_EXTRADATA_AFD_UD) |
- (1 << V4L2_MPEG_VIDC_EXTRADATA_MULTISLICE_INFO) |
- (1 << V4L2_MPEG_VIDC_EXTRADATA_NUM_CONCEALED_MB) |
- (1 << V4L2_MPEG_VIDC_EXTRADATA_METADATA_FILLER) |
- (1 << V4L2_MPEG_VIDC_INDEX_EXTRADATA_INPUT_CROP) |
- (1 << V4L2_MPEG_VIDC_INDEX_EXTRADATA_DIGITAL_ZOOM) |
- (1 << V4L2_MPEG_VIDC_INDEX_EXTRADATA_ASPECT_RATIO)
- ),
- .qmenu = mpeg_video_vidc_extradata,
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_SECURE,
+ .name = "Secure mode",
+ .type = V4L2_CTRL_TYPE_BUTTON,
+ .minimum = 0,
+ .maximum = 0,
+ .default_value = 0,
.step = 0,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ .cluster = 0,
},
};
@@ -630,7 +591,7 @@
.name = "Mpeg4",
.description = "Mpeg4 compressed format",
.fourcc = V4L2_PIX_FMT_MPEG4,
- .num_planes = 2,
+ .num_planes = 1,
.get_frame_size = get_frame_size_compressed,
.type = CAPTURE_PORT,
},
@@ -638,7 +599,7 @@
.name = "H263",
.description = "H263 compressed format",
.fourcc = V4L2_PIX_FMT_H263,
- .num_planes = 2,
+ .num_planes = 1,
.get_frame_size = get_frame_size_compressed,
.type = CAPTURE_PORT,
},
@@ -646,7 +607,7 @@
.name = "H264",
.description = "H264 compressed format",
.fourcc = V4L2_PIX_FMT_H264,
- .num_planes = 2,
+ .num_planes = 1,
.get_frame_size = get_frame_size_compressed,
.type = CAPTURE_PORT,
},
@@ -654,7 +615,7 @@
.name = "VP8",
.description = "VP8 compressed format",
.fourcc = V4L2_PIX_FMT_VP8,
- .num_planes = 2,
+ .num_planes = 1,
.get_frame_size = get_frame_size_compressed,
.type = CAPTURE_PORT,
},
@@ -701,11 +662,6 @@
sizes[i] = inst->fmts[CAPTURE_PORT]->get_frame_size(
i, inst->prop.height, inst->prop.width);
}
- property_id = HAL_PARAM_BUFFER_COUNT_ACTUAL;
- new_buf_count.buffer_type = HAL_BUFFER_OUTPUT;
- new_buf_count.buffer_count_actual = *num_buffers;
- rc = call_hfi_op(hdev, session_set_property, inst->session,
- property_id, &new_buf_count);
break;
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
@@ -1490,15 +1446,10 @@
}
pdata = &enable;
break;
- case V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA:
- {
- struct hal_extradata_enable extra;
- property_id = HAL_PARAM_INDEX_EXTRADATA;
- extra.index = msm_comm_get_hal_extradata_index(ctrl->val);
- extra.enable = 1;
- pdata = &extra;
+ case V4L2_CID_MPEG_VIDC_VIDEO_SECURE:
+ inst->mode = VIDC_SECURE;
+ dprintk(VIDC_INFO, "Setting secure mode to :%d\n", inst->mode);
break;
- }
default:
rc = -ENOTSUPP;
break;
@@ -1815,7 +1766,6 @@
const struct msm_vidc_format *fmt = NULL;
int rc = 0;
int i;
- int extra_idx = 0;
if (!inst || !f) {
dprintk(VIDC_ERR,
"Invalid input, inst = %p, format = %p\n", inst, f);
@@ -1836,16 +1786,6 @@
fmt->get_frame_size(i, inst->prop.height,
inst->prop.width);
}
- extra_idx = EXTRADATA_IDX(fmt->num_planes);
- if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) {
- f->fmt.pix_mp.plane_fmt[extra_idx].sizeimage =
- inst->buff_req.buffer
- [HAL_BUFFER_EXTRADATA_OUTPUT].buffer_size;
- }
- for (i = 0; i < fmt->num_planes; ++i) {
- inst->bufq[CAPTURE_PORT].vb2_bufq.plane_sizes[i] =
- f->fmt.pix_mp.plane_fmt[i].sizeimage;
- }
} else {
dprintk(VIDC_ERR,
"Buf type not recognized, type = %d\n", f->type);
@@ -1885,7 +1825,6 @@
int i;
struct vidc_buffer_addr_info buffer_info;
struct hfi_device *hdev;
- int extra_idx = 0;
if (!inst || !inst->core || !inst->core->device) {
dprintk(VIDC_ERR, "%s invalid parameters", __func__);
@@ -1898,41 +1837,24 @@
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
- if (b->length != inst->fmts[CAPTURE_PORT]->num_planes) {
- dprintk(VIDC_ERR,
- "Planes mismatch: needed: %d, allocated: %d\n",
- inst->fmts[CAPTURE_PORT]->num_planes,
- b->length);
- rc = -EINVAL;
- break;
- }
-
- for (i = 0; (i < b->length) && (i < VIDEO_MAX_PLANES); i++) {
- dprintk(VIDC_DBG, "device_addr = 0x%lx, size = %d\n",
+ for (i = 0; i < b->length; i++) {
+ dprintk(VIDC_DBG,
+ "device_addr = %ld, size = %d\n",
b->m.planes[i].m.userptr,
b->m.planes[i].length);
- }
- buffer_info.buffer_size = b->m.planes[0].length;
- buffer_info.buffer_type = HAL_BUFFER_OUTPUT;
- buffer_info.num_buffers = 1;
- buffer_info.align_device_addr =
- b->m.planes[0].m.userptr;
-
- extra_idx = EXTRADATA_IDX(b->length);
- if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) {
- buffer_info.extradata_addr =
- b->m.planes[extra_idx].m.userptr;
- dprintk(VIDC_DBG, "extradata: 0x%lx\n",
- b->m.planes[extra_idx].m.userptr);
- buffer_info.extradata_size =
- b->m.planes[extra_idx].length;
- }
-
- rc = call_hfi_op(hdev, session_set_buffers,
+ buffer_info.buffer_size = b->m.planes[i].length;
+ buffer_info.buffer_type = HAL_BUFFER_OUTPUT;
+ buffer_info.num_buffers = 1;
+ buffer_info.align_device_addr =
+ b->m.planes[i].m.userptr;
+ buffer_info.extradata_size = 0;
+ buffer_info.extradata_addr = 0;
+ rc = call_hfi_op(hdev, session_set_buffers,
(void *)inst->session, &buffer_info);
- if (rc)
- dprintk(VIDC_ERR,
+ if (rc)
+ dprintk(VIDC_ERR,
"vidc_hal_session_set_buffers failed");
+ }
break;
default:
dprintk(VIDC_ERR,
@@ -1945,7 +1867,8 @@
int msm_venc_release_buf(struct msm_vidc_inst *inst,
struct v4l2_buffer *b)
{
- int i, rc = 0, extra_idx = 0;
+ int rc = 0;
+ int i;
struct vidc_buffer_addr_info buffer_info;
struct hfi_device *hdev;
@@ -1966,36 +1889,24 @@
switch (b->type) {
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
break;
- case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: {
- if (b->length !=
- inst->fmts[CAPTURE_PORT]->num_planes) {
- dprintk(VIDC_ERR,
- "Planes mismatch: needed: %d, to release: %d\n",
- inst->fmts[CAPTURE_PORT]->num_planes,
- b->length);
- rc = -EINVAL;
- break;
- }
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
for (i = 0; i < b->length; i++) {
dprintk(VIDC_DBG,
- "Release device_addr = 0x%lx, size = %d, %d\n",
+ "Release device_addr = %ld, size = %d, %d\n",
b->m.planes[i].m.userptr,
b->m.planes[i].length, inst->state);
- }
- buffer_info.buffer_size = b->m.planes[0].length;
- buffer_info.buffer_type = HAL_BUFFER_OUTPUT;
- buffer_info.num_buffers = 1;
- buffer_info.align_device_addr =
- b->m.planes[0].m.userptr;
- extra_idx = EXTRADATA_IDX(b->length);
- if (extra_idx && (extra_idx < VIDEO_MAX_PLANES))
- buffer_info.extradata_addr =
- b->m.planes[extra_idx].m.userptr;
- buffer_info.response_required = false;
- rc = call_hfi_op(hdev, session_release_buffers,
+ buffer_info.buffer_size = b->m.planes[i].length;
+ buffer_info.buffer_type = HAL_BUFFER_OUTPUT;
+ buffer_info.num_buffers = 1;
+ buffer_info.align_device_addr =
+ b->m.planes[i].m.userptr;
+ buffer_info.extradata_size = 0;
+ buffer_info.extradata_addr = 0;
+ buffer_info.response_required = false;
+ rc = call_hfi_op(hdev, session_release_buffers,
(void *)inst->session, &buffer_info);
- if (rc)
- dprintk(VIDC_ERR,
+ if (rc)
+ dprintk(VIDC_ERR,
"vidc_hal_session_release_buffers failed\n");
}
break;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 6a83334..d43e5ba 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -362,7 +362,9 @@
struct msm_vidc_cb_cmd_done *response = data;
struct msm_vidc_inst *inst;
struct v4l2_event dqevent;
+ struct v4l2_control control = {0};
struct msm_vidc_cb_event *event_notify;
+ int rc = 0;
if (response) {
inst = (struct msm_vidc_inst *)response->session_id;
dqevent.id = 0;
@@ -370,7 +372,16 @@
switch (event_notify->hal_event_type) {
case HAL_EVENT_SEQ_CHANGED_SUFFICIENT_RESOURCES:
dqevent.type =
- V4L2_EVENT_SEQ_CHANGED_SUFFICIENT;
+ 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)
+ dqevent.type =
+ V4L2_EVENT_SEQ_CHANGED_SUFFICIENT;
break;
case HAL_EVENT_SEQ_CHANGED_INSUFFICIENT_RESOURCES:
dqevent.type =
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index 6d07165..af8b761 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -892,20 +892,16 @@
static int venus_hfi_sys_set_debug(struct venus_hfi_device *device, int debug)
{
- struct hfi_debug_config *hfi;
u8 packet[VIDC_IFACEQ_VAR_SMALL_PKT_SIZE];
+ int rc = 0;
struct hfi_cmd_sys_set_property_packet *pkt =
(struct hfi_cmd_sys_set_property_packet *) &packet;
- pkt->size = sizeof(struct hfi_cmd_sys_set_property_packet) +
- sizeof(struct hfi_debug_config) + sizeof(u32);
- pkt->packet_type = HFI_CMD_SYS_SET_PROPERTY;
- pkt->num_properties = 1;
- pkt->rg_property_data[0] = HFI_PROPERTY_SYS_DEBUG_CONFIG;
- hfi = (struct hfi_debug_config *) &pkt->rg_property_data[1];
- hfi->debug_config = debug;
- hfi->debug_mode = HFI_DEBUG_MODE_QUEUE;
- if (msm_fw_debug_mode <= HFI_DEBUG_MODE_QDSS)
- hfi->debug_mode = msm_fw_debug_mode;
+ rc = create_pkt_cmd_sys_debug_config(pkt, debug);
+ if (rc) {
+ dprintk(VIDC_WARN,
+ "Debug mode setting to FW failed\n");
+ return -ENOTEMPTY;
+ }
if (venus_hfi_iface_cmdq_write(device, pkt))
return -ENOTEMPTY;
return 0;
diff --git a/drivers/media/platform/msm/wfd/enc-subdev.h b/drivers/media/platform/msm/wfd/enc-subdev.h
index 93c0079..8bfb884 100644
--- a/drivers/media/platform/msm/wfd/enc-subdev.h
+++ b/drivers/media/platform/msm/wfd/enc-subdev.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
@@ -76,6 +76,8 @@
(a->offset == b->offset);
else if (a->kvaddr || b->kvaddr)
return a->kvaddr == b->kvaddr;
+ else if (a->paddr || b->paddr)
+ return a->paddr == b->paddr;
else
return false;
}
@@ -107,6 +109,7 @@
#define ENC_MMAP _IOWR('V', 25, struct mem_region_map *)
#define ENC_MUNMAP _IOWR('V', 26, struct mem_region_map *)
#define SET_FRAMERATE_MODE _IO('V', 27)
+#define ENC_SECURE _IO('V', 28)
extern int venc_init(struct v4l2_subdev *sd, u32 val);
extern int venc_load_fw(struct v4l2_subdev *sd);
diff --git a/drivers/media/platform/msm/wfd/enc-venus-subdev.c b/drivers/media/platform/msm/wfd/enc-venus-subdev.c
index 73a3d8e..d37576d 100644
--- a/drivers/media/platform/msm/wfd/enc-venus-subdev.c
+++ b/drivers/media/platform/msm/wfd/enc-venus-subdev.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
@@ -252,12 +252,23 @@
return msm_vidc_s_ctrl(inst->vidc_context, &ctrl);
}
+static long get_iommu_domain(struct venc_inst *inst)
+{
+ struct msm_vidc_iommu_info maps[MAX_MAP];
+ int rc = msm_vidc_get_iommu_maps(inst->vidc_context, maps);
+ if (rc) {
+ WFD_MSG_ERR("Failed to retreive domain mappings\n");
+ return rc;
+ }
+
+ return maps[inst->secure ? CP_MAP : NS_MAP].domain;
+}
+
static long venc_open(struct v4l2_subdev *sd, void *arg)
{
struct venc_inst *inst = NULL;
struct venc_msg_ops *vmops = arg;
struct v4l2_event_subscription event = {0};
- struct msm_vidc_iommu_info maps[MAX_MAP];
int rc = 0;
if (!vmops) {
@@ -305,15 +316,12 @@
goto vidc_subscribe_fail;
}
- rc = msm_vidc_get_iommu_maps(inst->vidc_context, maps);
- if (rc) {
- WFD_MSG_ERR("Failed to retreive domain mappings\n");
- rc = -ENODATA;
+ inst->domain = get_iommu_domain(inst);
+ if (inst->domain < 0) {
+ WFD_MSG_ERR("Failed to get domain\n");
goto vidc_subscribe_fail;
}
- inst->domain = maps[inst->secure ? CP_MAP : NS_MAP].domain;
-
inst->callback_thread = kthread_run(venc_vidc_callback_thread, inst,
"venc_vidc_callback_thread");
if (IS_ERR(inst->callback_thread)) {
@@ -477,7 +485,8 @@
}
bufreq->count = v4l2_bufreq.count;
- bufreq->size = v4l2_format.fmt.pix_mp.plane_fmt[0].sizeimage;
+ bufreq->size = ALIGN(v4l2_format.fmt.pix_mp.plane_fmt[0].sizeimage,
+ inst->secure ? SZ_1M : SZ_4K);
inst->free_input_indices.size_bits = bufreq->count;
inst->free_input_indices.size = roundup(bufreq->count,
@@ -549,12 +558,30 @@
return rc;
}
+static void populate_planes(struct v4l2_plane *planes, int num_planes,
+ void *userptr, int size)
+{
+ int c = 0;
+
+ planes[0] = (struct v4l2_plane) {
+ .length = size,
+ .m.userptr = (int)userptr,
+ };
+
+ for (c = 1; c < num_planes - 1; ++c) {
+ planes[c] = (struct v4l2_plane) {
+ .length = 0,
+ .m.userptr = (int)NULL,
+ };
+ }
+}
+
static long venc_set_input_buffer(struct v4l2_subdev *sd, void *arg)
{
int rc = 0;
struct venc_inst *inst = NULL;
struct v4l2_buffer buf = {0};
- struct v4l2_plane plane = {0};
+ struct v4l2_plane *planes = NULL;
struct mem_region *mregion = arg;
if (!sd) {
@@ -575,20 +602,21 @@
}
mregion = kzalloc(sizeof(*mregion), GFP_KERNEL);
- *mregion = *(struct mem_region *)arg;
+ planes = kzalloc(sizeof(*planes) * inst->num_input_planes, GFP_KERNEL);
+ if (!mregion || !planes)
+ return -ENOMEM;
- plane = (struct v4l2_plane) {
- .length = mregion->size,
- .m.userptr = (u32)mregion->paddr,
- };
+ *mregion = *(struct mem_region *)arg;
+ populate_planes(planes, inst->num_input_planes,
+ mregion->paddr, mregion->size);
buf = (struct v4l2_buffer) {
.index = get_list_len(&inst->registered_input_bufs),
.type = BUF_TYPE_INPUT,
.bytesused = 0,
.memory = V4L2_MEMORY_USERPTR,
- .m.planes = &plane,
- .length = 1,
+ .m.planes = planes,
+ .length = inst->num_input_planes,
};
WFD_MSG_DBG("Prepare %p with index, %d",
@@ -600,9 +628,12 @@
}
list_add_tail(&mregion->list, &inst->registered_input_bufs.list);
+
+ kfree(planes);
return 0;
set_input_buffer_fail:
kfree(mregion);
+ kfree(planes);
return rc;
}
@@ -610,12 +641,19 @@
struct mem_region *mregion)
{
int rc = 0;
- unsigned long flags = 0, size = 0;
+ unsigned long flags = 0, size = 0, align_req = 0;
if (!mregion) {
rc = -EINVAL;
goto venc_map_fail;
}
+ align_req = inst->secure ? SZ_1M : SZ_4K;
+ if (mregion->size % align_req != 0) {
+ WFD_MSG_ERR("Memregion not aligned to %ld\n", align_req);
+ rc = -EINVAL;
+ goto venc_map_fail;
+ }
+
mregion->ion_handle = ion_import_dma_buf(venc_ion_client, mregion->fd);
if (IS_ERR_OR_NULL(mregion->ion_handle)) {
rc = PTR_ERR(mregion->ion_handle);
@@ -631,20 +669,31 @@
goto venc_map_fail;
}
- mregion->kvaddr = ion_map_kernel(venc_ion_client,
+ if (!inst->secure) {
+ mregion->kvaddr = ion_map_kernel(venc_ion_client,
mregion->ion_handle);
-
- if (IS_ERR_OR_NULL(mregion->kvaddr)) {
- WFD_MSG_ERR("Failed to map buffer into kernel\n");
- rc = PTR_ERR(mregion->kvaddr);
+ if (IS_ERR_OR_NULL(mregion->kvaddr)) {
+ WFD_MSG_ERR("Failed to map buffer into kernel\n");
+ rc = PTR_ERR(mregion->kvaddr);
+ mregion->kvaddr = NULL;
+ goto venc_map_fail;
+ }
+ } else {
mregion->kvaddr = NULL;
- goto venc_map_fail;
+ }
+
+ if (inst->secure) {
+ rc = msm_ion_secure_buffer(venc_ion_client,
+ mregion->ion_handle, VIDEO_BITSTREAM, 0);
+ if (rc) {
+ WFD_MSG_ERR("Failed to secure output buffer\n");
+ goto venc_map_iommu_map_fail;
+ }
}
rc = ion_map_iommu(venc_ion_client, mregion->ion_handle,
- inst->domain, 0, SZ_4K, 0,
+ inst->domain, 0, align_req, 0,
(unsigned long *)&mregion->paddr, &size, flags, 0);
-
if (rc) {
WFD_MSG_ERR("Failed to map into iommu\n");
goto venc_map_iommu_map_fail;
@@ -657,8 +706,12 @@
venc_map_iommu_size_fail:
ion_unmap_iommu(venc_ion_client, mregion->ion_handle,
inst->domain, 0);
+
+ if (inst->secure)
+ msm_ion_unsecure_buffer(venc_ion_client, mregion->ion_handle);
venc_map_iommu_map_fail:
- ion_unmap_kernel(venc_ion_client, mregion->ion_handle);
+ if (!inst->secure)
+ ion_unmap_kernel(venc_ion_client, mregion->ion_handle);
venc_map_fail:
return rc;
}
@@ -680,6 +733,8 @@
mregion->kvaddr = NULL;
}
+ if (inst->secure)
+ msm_ion_unsecure_buffer(venc_ion_client, mregion->ion_handle);
return 0;
}
@@ -689,7 +744,7 @@
int rc = 0;
struct venc_inst *inst = NULL;
struct v4l2_buffer buf = {0};
- struct v4l2_plane plane = {0};
+ struct v4l2_plane *planes = NULL;
struct mem_region *mregion = arg;
if (!sd) {
@@ -712,8 +767,9 @@
}
mregion = kzalloc(sizeof(*mregion), GFP_KERNEL);
+ planes = kzalloc(sizeof(*planes) * inst->num_output_planes, GFP_KERNEL);
- if (!mregion) {
+ if (!mregion || !planes) {
WFD_MSG_ERR("Failed to allocate memory\n");
goto venc_set_output_buffer_fail;
}
@@ -727,18 +783,16 @@
goto venc_set_output_buffer_map_fail;
}
- plane = (struct v4l2_plane) {
- .length = mregion->size,
- .m.userptr = (u32)mregion->paddr,
- };
+ populate_planes(planes, inst->num_output_planes,
+ mregion->paddr, mregion->size);
buf = (struct v4l2_buffer) {
.index = get_list_len(&inst->registered_output_bufs),
.type = BUF_TYPE_OUTPUT,
.bytesused = 0,
.memory = V4L2_MEMORY_USERPTR,
- .m.planes = &plane,
- .length = 1,
+ .m.planes = planes,
+ .length = inst->num_output_planes,
};
WFD_MSG_DBG("Prepare %p with index, %d",
@@ -750,11 +804,14 @@
}
list_add_tail(&mregion->list, &inst->registered_output_bufs.list);
- return rc;
+
+ kfree(planes);
+ return 0;
venc_set_output_buffer_prepare_fail:
venc_unmap_user_to_kernel(inst, mregion);
venc_set_output_buffer_map_fail:
kfree(mregion);
+ kfree(planes);
venc_set_output_buffer_fail:
return rc;
}
@@ -763,7 +820,7 @@
{
struct venc_inst *inst = NULL;
struct v4l2_format *fmt = arg, temp;
- int rc = 0;
+ int rc = 0, align_req = 0;
if (!sd) {
WFD_MSG_ERR("Subdevice required for %s\n", __func__);
@@ -799,7 +856,10 @@
rc = -EINVAL;
goto venc_set_format_fail;
}
- fmt->fmt.pix.sizeimage = temp.fmt.pix_mp.plane_fmt[0].sizeimage;
+
+ align_req = inst->secure ? SZ_1M : SZ_4K;
+ fmt->fmt.pix.sizeimage = ALIGN(temp.fmt.pix_mp.plane_fmt[0].sizeimage,
+ align_req);
inst->num_output_planes = temp.fmt.pix_mp.num_planes;
temp.type = BUF_TYPE_INPUT;
@@ -971,7 +1031,6 @@
WFD_MSG_ERR("Trying to free a buffer of unknown type\n");
return -EINVAL;
}
-
mregion = get_registered_mregion(buf_list, to_free);
if (!mregion) {
@@ -1091,7 +1150,7 @@
{
struct mem_region_map *mmap = arg;
struct mem_region *mregion = NULL;
- unsigned long rc = 0, size = 0;
+ unsigned long rc = 0, size = 0, align_req = 0;
void *paddr = NULL;
struct venc_inst *inst = NULL;
@@ -1105,24 +1164,47 @@
inst = (struct venc_inst *)sd->dev_priv;
mregion = mmap->mregion;
- if (mregion->size % SZ_4K != 0) {
- WFD_MSG_ERR("Memregion not aligned to %d\n", SZ_4K);
- return -EINVAL;
+
+ align_req = inst->secure ? SZ_1M : SZ_4K;
+ if (mregion->size % align_req != 0) {
+ WFD_MSG_ERR("Memregion not aligned to %ld\n", align_req);
+ rc = -EINVAL;
+ goto venc_map_bad_align;
+ }
+
+ if (inst->secure) {
+ rc = msm_ion_secure_buffer(mmap->ion_client,
+ mregion->ion_handle, VIDEO_PIXEL, 0);
+ if (rc) {
+ WFD_MSG_ERR("Failed to secure input buffer\n");
+ goto venc_map_bad_align;
+ }
}
rc = ion_map_iommu(mmap->ion_client, mregion->ion_handle,
- inst->domain, 0, SZ_4K, 0, (unsigned long *)&paddr,
+ inst->domain, 0, align_req, 0, (unsigned long *)&paddr,
&size, 0, 0);
if (rc) {
- WFD_MSG_ERR("Failed to get physical addr\n");
+ WFD_MSG_ERR("Failed to get physical addr %ld\n", rc);
paddr = NULL;
+ goto venc_map_bad_align;
} else if (size < mregion->size) {
WFD_MSG_ERR("Failed to map enough memory\n");
rc = -ENOMEM;
+ goto venc_map_iommu_size_fail;
}
mregion->paddr = paddr;
+ return 0;
+
+venc_map_iommu_size_fail:
+ ion_unmap_iommu(venc_ion_client, mregion->ion_handle,
+ inst->domain, 0);
+
+ if (inst->secure)
+ msm_ion_unsecure_buffer(mmap->ion_client, mregion->ion_handle);
+venc_map_bad_align:
return rc;
}
@@ -1143,8 +1225,13 @@
inst = (struct venc_inst *)sd->dev_priv;
mregion = mmap->mregion;
- ion_unmap_iommu(mmap->ion_client, mregion->ion_handle,
+ if (mregion->paddr)
+ ion_unmap_iommu(mmap->ion_client, mregion->ion_handle,
inst->domain, 0);
+
+ if (inst->secure)
+ msm_ion_unsecure_buffer(mmap->ion_client, mregion->ion_handle);
+
return 0;
}
@@ -1157,6 +1244,55 @@
return 0;
}
+static long secure_toggle(struct venc_inst *inst, bool secure)
+{
+ if (inst->secure == secure)
+ return 0;
+
+ if (!list_empty(&inst->registered_input_bufs.list) ||
+ !list_empty(&inst->registered_output_bufs.list)) {
+ WFD_MSG_ERR(
+ "Attempt to (un)secure encoder not allowed after registering buffers"
+ );
+ return -EEXIST;
+ }
+
+ inst->secure = secure;
+ inst->domain = get_iommu_domain(inst);
+ return 0;
+}
+
+static long venc_secure(struct v4l2_subdev *sd)
+{
+ struct venc_inst *inst = NULL;
+ struct v4l2_control ctrl;
+ int rc = 0;
+
+ if (!sd) {
+ WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+ return -EINVAL;
+ }
+
+ inst = sd->dev_priv;
+ rc = secure_toggle(inst, true);
+ if (rc) {
+ WFD_MSG_ERR("Failed to toggle into secure mode\n");
+ goto secure_fail;
+ }
+
+ ctrl.id = V4L2_CID_MPEG_VIDC_VIDEO_SECURE;
+ rc = msm_vidc_s_ctrl(inst->vidc_context, &ctrl);
+ if (rc) {
+ WFD_MSG_ERR("Failed to move vidc into secure mode\n");
+ goto secure_fail;
+ }
+
+ return 0;
+secure_fail:
+ secure_toggle(sd->dev_priv, false);
+ return rc;
+}
+
long venc_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
{
long rc = 0;
@@ -1229,6 +1365,9 @@
case SET_FRAMERATE_MODE:
rc = venc_set_framerate_mode(sd, arg);
break;
+ case ENC_SECURE:
+ rc = venc_secure(sd);
+ break;
default:
WFD_MSG_ERR("Unknown ioctl %d to enc-subdev\n", cmd);
rc = -ENOTSUPP;
diff --git a/drivers/media/platform/msm/wfd/mdp-5-subdev.c b/drivers/media/platform/msm/wfd/mdp-5-subdev.c
index 5b49498..be705df 100644
--- a/drivers/media/platform/msm/wfd/mdp-5-subdev.c
+++ b/drivers/media/platform/msm/wfd/mdp-5-subdev.c
@@ -47,6 +47,10 @@
WFD_MSG_ERR("Invalid arguments\n");
rc = -EINVAL;
goto mdp_open_fail;
+ } else if (mops->secure) {
+ /* Deprecated API; use MDP_SECURE ioctl */
+ WFD_MSG_ERR("Deprecated API for securing subdevice\n");
+ return -ENOTSUPP;
}
fbi = msm_fb_get_writeback_fb();
@@ -120,6 +124,8 @@
struct fb_info *fbi = NULL;
if (inst) {
fbi = (struct fb_info *)inst->mdp;
+ if (inst->secure)
+ msm_fb_writeback_set_secure(inst->mdp, false);
msm_fb_writeback_terminate(fbi);
kfree(inst);
/* Unregister wfd node from switch driver */
@@ -193,7 +199,7 @@
int mdp_mmap(struct v4l2_subdev *sd, void *arg)
{
- int rc = 0;
+ int rc = 0, align = 0;
struct mem_region_map *mmap = arg;
struct mem_region *mregion;
bool domain = -1;
@@ -206,17 +212,39 @@
inst = mmap->cookie;
mregion = mmap->mregion;
- if (mregion->size % SZ_4K != 0) {
- WFD_MSG_ERR("Memregion not aligned to %d\n", SZ_4K);
+ align = inst->secure ? SZ_1M : SZ_4K;
+ if (mregion->size % align != 0) {
+ WFD_MSG_ERR("Memregion not aligned to %d\n", align);
return -EINVAL;
}
- domain = msm_fb_get_iommu_domain();
+ if (inst->secure) {
+ rc = msm_ion_secure_buffer(mmap->ion_client,
+ mregion->ion_handle, VIDEO_PIXEL, 0);
+ if (rc) {
+ WFD_MSG_ERR("Failed to secure input buffer\n");
+ goto secure_fail;
+ }
+ }
+
+ domain = msm_fb_get_iommu_domain(inst->mdp,
+ inst->secure ? MDP_IOMMU_DOMAIN_CP :
+ MDP_IOMMU_DOMAIN_NS);
+
rc = ion_map_iommu(mmap->ion_client, mregion->ion_handle,
- domain, 0, SZ_4K, 0,
+ domain, 0, align, 0,
(unsigned long *)&mregion->paddr,
(unsigned long *)&mregion->size,
0, 0);
+ if (rc) {
+ WFD_MSG_ERR("Failed to map into %ssecure domain: %d\n",
+ !inst->secure ? "non" : "", rc);
+ goto iommu_fail;
+ }
+iommu_fail:
+ if (inst->secure)
+ msm_ion_unsecure_buffer(mmap->ion_client, mregion->ion_handle);
+secure_fail:
return rc;
}
@@ -235,13 +263,37 @@
inst = mmap->cookie;
mregion = mmap->mregion;
- domain = msm_fb_get_iommu_domain();
+ domain = msm_fb_get_iommu_domain(inst->mdp,
+ inst->secure ? MDP_IOMMU_DOMAIN_CP :
+ MDP_IOMMU_DOMAIN_NS);
ion_unmap_iommu(mmap->ion_client,
mregion->ion_handle,
domain, 0);
+
+ if (inst->secure)
+ msm_ion_unsecure_buffer(mmap->ion_client, mregion->ion_handle);
+
return 0;
}
+int mdp_secure(struct v4l2_subdev *sd, void *arg)
+{
+ struct mdp_instance *inst = NULL;
+ int rc = 0;
+
+ if (!arg) {
+ WFD_MSG_ERR("Invalid argument\n");
+ return -EINVAL;
+ }
+
+ inst = arg;
+ rc = msm_fb_writeback_set_secure(inst->mdp, true);
+ if (!rc)
+ inst->secure = true;
+
+ return rc;
+}
+
long mdp_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
{
int rc = 0;
@@ -277,6 +329,9 @@
case MDP_MUNMAP:
rc = mdp_munmap(sd, arg);
break;
+ case MDP_SECURE:
+ rc = mdp_secure(sd, arg);
+ break;
default:
WFD_MSG_ERR("IOCTL: %u not supported\n", cmd);
rc = -EINVAL;
diff --git a/drivers/media/platform/msm/wfd/mdp-dummy-subdev.c b/drivers/media/platform/msm/wfd/mdp-dummy-subdev.c
index b2db208..2242c76 100644
--- a/drivers/media/platform/msm/wfd/mdp-dummy-subdev.c
+++ b/drivers/media/platform/msm/wfd/mdp-dummy-subdev.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
@@ -28,11 +28,12 @@
struct mutex mutex;
};
-int mdp_init(struct v4l2_subdev *sd, u32 val)
+static int mdp_init(struct v4l2_subdev *sd, u32 val)
{
return 0;
}
-int mdp_open(struct v4l2_subdev *sd, void *arg)
+
+static int mdp_open(struct v4l2_subdev *sd, void *arg)
{
struct mdp_instance *inst = kzalloc(sizeof(struct mdp_instance),
GFP_KERNEL);
@@ -50,49 +51,54 @@
return rc;
}
-int mdp_start(struct v4l2_subdev *sd, void *arg)
+static int mdp_start(struct v4l2_subdev *sd, void *arg)
{
return 0;
}
-int mdp_stop(struct v4l2_subdev *sd, void *arg)
+
+static int mdp_stop(struct v4l2_subdev *sd, void *arg)
{
return 0;
}
-int mdp_close(struct v4l2_subdev *sd, void *arg)
+
+static int mdp_close(struct v4l2_subdev *sd, void *arg)
{
return 0;
}
-int mdp_q_buffer(struct v4l2_subdev *sd, void *arg)
+
+static int mdp_q_buffer(struct v4l2_subdev *sd, void *arg)
{
static int foo;
int rc = 0;
struct mdp_buf_info *binfo = arg;
struct mdp_instance *inst = NULL;
+ struct mdp_buf_queue *new_entry = NULL;
if (!binfo || !binfo->inst || !binfo->cookie) {
WFD_MSG_ERR("Invalid argument\n");
return -EINVAL;
}
-
inst = binfo->inst;
- if (binfo->kvaddr) {
- struct mdp_buf_queue *new_entry = kzalloc(sizeof(*new_entry),
- GFP_KERNEL);
- memset((void *)binfo->kvaddr, foo++, 1024);
- new_entry->mdp_buf_info = *binfo;
- mutex_lock(&inst->mutex);
- list_add_tail(&new_entry->node, &inst->mdp_bufs.node);
- mutex_unlock(&inst->mutex);
- WFD_MSG_DBG("Queue %p with cookie %p\n",
- (void *)binfo->paddr, (void *)binfo->cookie);
- } else {
- rc = -EINVAL;
- }
+ new_entry = kzalloc(sizeof(*new_entry), GFP_KERNEL);
+ if (!new_entry)
+ return -ENOMEM;
+ new_entry->mdp_buf_info = *binfo;
+ if (binfo->kvaddr)
+ memset((void *)binfo->kvaddr, foo++, 1024);
+
+
+ mutex_lock(&inst->mutex);
+ list_add_tail(&new_entry->node, &inst->mdp_bufs.node);
+ mutex_unlock(&inst->mutex);
+
+ WFD_MSG_DBG("Queue %p with cookie %p\n",
+ (void *)binfo->paddr, (void *)binfo->cookie);
return rc;
}
-int mdp_dq_buffer(struct v4l2_subdev *sd, void *arg)
+
+static int mdp_dq_buffer(struct v4l2_subdev *sd, void *arg)
{
struct mdp_buf_info *binfo = arg;
struct mdp_buf_queue *head = NULL;
@@ -121,12 +127,13 @@
return 0;
}
-int mdp_set_prop(struct v4l2_subdev *sd, void *arg)
+
+static int mdp_set_prop(struct v4l2_subdev *sd, void *arg)
{
return 0;
}
-int mdp_mmap(struct v4l2_subdev *sd, void *arg)
+static int mdp_mmap(struct v4l2_subdev *sd, void *arg)
{
int rc = 0;
struct mem_region_map *mmap = arg;
@@ -137,12 +144,17 @@
return rc;
}
-int mdp_munmap(struct v4l2_subdev *sd, void *arg)
+static int mdp_munmap(struct v4l2_subdev *sd, void *arg)
{
/* Whatever */
return 0;
}
+static int mdp_secure(struct v4l2_subdev *sd)
+{
+ return 0;
+}
+
long mdp_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
{
int rc = 0;
@@ -178,6 +190,9 @@
case MDP_MUNMAP:
rc = mdp_munmap(sd, arg);
break;
+ case MDP_SECURE:
+ rc = mdp_secure(sd);
+ break;
default:
WFD_MSG_ERR("IOCTL: %u not supported\n", cmd);
rc = -EINVAL;
diff --git a/drivers/media/platform/msm/wfd/mdp-subdev.h b/drivers/media/platform/msm/wfd/mdp-subdev.h
index b04d448..f2c6fb1 100644
--- a/drivers/media/platform/msm/wfd/mdp-subdev.h
+++ b/drivers/media/platform/msm/wfd/mdp-subdev.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
@@ -59,6 +59,7 @@
#define MDP_STOP _IOR(MDP_MAGIC_IOCTL, 7, void *)
#define MDP_MMAP _IOR(MDP_MAGIC_IOCTL, 8, struct mem_region_map *)
#define MDP_MUNMAP _IOR(MDP_MAGIC_IOCTL, 9, struct mem_region_map *)
+#define MDP_SECURE _IO(MDP_MAGIC_IOCTL, 9)
extern int mdp_init(struct v4l2_subdev *sd, u32 val);
diff --git a/drivers/media/platform/msm/wfd/wfd-ioctl.c b/drivers/media/platform/msm/wfd/wfd-ioctl.c
index 3b732ae..9fb7c6d 100644
--- a/drivers/media/platform/msm/wfd/wfd-ioctl.c
+++ b/drivers/media/platform/msm/wfd/wfd-ioctl.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
@@ -52,7 +52,7 @@
struct v4l2_subdev enc_sdev;
struct v4l2_subdev vsg_sdev;
struct ion_client *ion_client;
- bool secure_device;
+ bool secure;
bool in_use;
bool mdp_iommu_split_domain;
};
@@ -154,16 +154,16 @@
{
struct ion_handle *handle = NULL;
void *kvaddr = NULL;
- unsigned int alloc_regions = 0;
- unsigned int ion_flags = 0;
+ unsigned int alloc_regions = 0, ion_flags = 0, align = 0;
int rc = 0;
alloc_regions = ION_HEAP(ION_CP_MM_HEAP_ID);
alloc_regions |= secure ? 0 :
ION_HEAP(ION_IOMMU_HEAP_ID);
ion_flags |= secure ? ION_SECURE : 0;
- handle = ion_alloc(client,
- mregion->size, SZ_4K, alloc_regions, ion_flags);
+ align = secure ? SZ_1M : SZ_4K;
+ handle = ion_alloc(client, mregion->size, align,
+ alloc_regions, ion_flags);
if (IS_ERR_OR_NULL(handle)) {
WFD_MSG_ERR("Failed to allocate input buffer\n");
@@ -171,12 +171,16 @@
goto alloc_fail;
}
- kvaddr = ion_map_kernel(client, handle);
+ if (!secure) {
+ kvaddr = ion_map_kernel(client, handle);
- if (IS_ERR_OR_NULL(kvaddr)) {
- WFD_MSG_ERR("Failed to get virtual addr\n");
- rc = PTR_ERR(kvaddr);
- goto alloc_fail;
+ if (IS_ERR_OR_NULL(kvaddr)) {
+ WFD_MSG_ERR("Failed to get virtual addr\n");
+ rc = PTR_ERR(kvaddr);
+ goto alloc_fail;
+ }
+ } else {
+ kvaddr = NULL;
}
mregion->kvaddr = kvaddr;
@@ -206,7 +210,8 @@
"Invalid client or region");
return -EINVAL;
}
- ion_unmap_kernel(client, mregion->ion_handle);
+ if (mregion->kvaddr)
+ ion_unmap_kernel(client, mregion->ion_handle);
ion_free(client, mregion->ion_handle);
return 0;
}
@@ -256,7 +261,7 @@
enc_mregion->size = ALIGN(inst->input_buf_size, SZ_4K);
rc = wfd_allocate_ion_buffer(wfd_dev->ion_client,
- wfd_dev->secure_device, enc_mregion);
+ wfd_dev->secure, enc_mregion);
if (rc) {
WFD_MSG_ERR("Failed to allocate input memory\n");
goto alloc_fail;
@@ -391,6 +396,7 @@
&inst->input_mem_list) {
mpair = list_entry(ptr, struct mem_region_pair,
list);
+
rc = v4l2_subdev_call(&wfd_dev->enc_sdev,
core, ioctl, FREE_INPUT_BUFFER,
(void *)mpair->enc);
@@ -1004,8 +1010,31 @@
{
int rc = 0;
struct wfd_device *wfd_dev = video_drvdata(filp);
- rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core,
- ioctl, SET_PROP, a);
+ struct wfd_inst *inst = filp->private_data;
+
+ switch (a->id) {
+ case V4L2_CID_MPEG_VIDC_VIDEO_SECURE:
+ rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core,
+ ioctl, ENC_SECURE, NULL);
+ if (rc) {
+ WFD_MSG_ERR("Couldn't secure encoder");
+ break;
+ }
+
+ rc = v4l2_subdev_call(&wfd_dev->mdp_sdev, core,
+ ioctl, MDP_SECURE, (void *)inst->mdp_inst);
+ if (rc) {
+ WFD_MSG_ERR("Couldn't secure MDP");
+ break;
+ }
+
+ wfd_dev->secure = true;
+ break;
+ default:
+ rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core,
+ ioctl, SET_PROP, a);
+ }
+
if (rc)
WFD_MSG_ERR("Failed to set encoder property\n");
return rc;
@@ -1355,7 +1384,7 @@
wfd_stats_init(&inst->stats, MINOR(filp->f_dentry->d_inode->i_rdev));
- mdp_mops.secure = wfd_dev->secure_device;
+ mdp_mops.secure = wfd_dev->secure;
mdp_mops.iommu_split_domain = wfd_dev->mdp_iommu_split_domain;
rc = v4l2_subdev_call(&wfd_dev->mdp_sdev, core, ioctl, MDP_OPEN,
(void *)&mdp_mops);
@@ -1373,7 +1402,7 @@
enc_mops.op_buffer_done = venc_op_buffer_done;
enc_mops.ip_buffer_done = venc_ip_buffer_done;
enc_mops.cbdata = filp;
- enc_mops.secure = wfd_dev->secure_device;
+ enc_mops.secure = wfd_dev->secure;
rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl, OPEN,
(void *)&enc_mops);
if (rc || !enc_mops.cookie) {
@@ -1421,22 +1450,21 @@
inst = filp->private_data;
if (inst) {
wfdioc_streamoff(filp, NULL, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+ vb2_queue_release(&inst->vid_bufq);
+ wfd_free_input_buffers(wfd_dev, inst);
+
rc = v4l2_subdev_call(&wfd_dev->mdp_sdev, core, ioctl,
MDP_CLOSE, (void *)inst->mdp_inst);
if (rc)
WFD_MSG_ERR("Failed to CLOSE mdp subdevice: %d\n", rc);
- vb2_queue_release(&inst->vid_bufq);
- wfd_free_input_buffers(wfd_dev, inst);
rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl,
CLOSE, (void *)inst->venc_inst);
-
if (rc)
WFD_MSG_ERR("Failed to CLOSE enc subdev: %d\n", rc);
rc = v4l2_subdev_call(&wfd_dev->vsg_sdev, core, ioctl,
VSG_CLOSE, NULL);
-
if (rc)
WFD_MSG_ERR("Failed to CLOSE vsg subdev: %d\n", rc);
@@ -1604,7 +1632,7 @@
switch (WFD_DEVICE_NUMBER_BASE + c) {
case WFD_DEVICE_SECURE:
- wfd_dev[c].secure_device = true;
+ wfd_dev[c].secure = true;
break;
default:
break;
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index 2910a37..8aa4758 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -1604,8 +1604,8 @@
int qseecom_shutdown_app(struct qseecom_handle **handle)
{
int ret = -EINVAL;
- struct qseecom_dev_handle *data =
- (struct qseecom_dev_handle *) ((*handle)->dev);
+ struct qseecom_dev_handle *data;
+
struct qseecom_registered_kclient_list *kclient = NULL;
unsigned long flags = 0;
bool found_handle = false;
@@ -1614,11 +1614,11 @@
pr_err("This functionality is UNSUPPORTED in version 1.3\n");
return -EINVAL;
}
- if (*handle == NULL) {
+ if ((handle == NULL) || (*handle == NULL)) {
pr_err("Handle is not initialized\n");
return -EINVAL;
}
-
+ data = (struct qseecom_dev_handle *) ((*handle)->dev);
spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
list_for_each_entry(kclient, &qseecom.registered_kclient_list_head,
list) {
diff --git a/drivers/misc/tspp.c b/drivers/misc/tspp.c
index 9a53817..9598d45 100644
--- a/drivers/misc/tspp.c
+++ b/drivers/misc/tspp.c
@@ -763,6 +763,11 @@
/*** Clock functions ***/
static int tspp_clock_start(struct tspp_device *device)
{
+ if (device == NULL) {
+ pr_err("tspp: Can't start clocks, invalid device\n");
+ return -EINVAL;
+ }
+
if (device->tsif_pclk && clk_prepare_enable(device->tsif_pclk) != 0) {
pr_err("tspp: Can't start pclk");
return -EBUSY;
@@ -780,11 +785,16 @@
static void tspp_clock_stop(struct tspp_device *device)
{
+ if (device == NULL) {
+ pr_err("tspp: Can't stop clocks, invalid device\n");
+ return;
+ }
+
if (device->tsif_pclk)
- clk_disable(device->tsif_pclk);
+ clk_disable_unprepare(device->tsif_pclk);
if (device->tsif_ref_clk)
- clk_disable(device->tsif_ref_clk);
+ clk_disable_unprepare(device->tsif_ref_clk);
}
/*** TSIF functions ***/
@@ -1458,7 +1468,10 @@
/* start the clocks if needed */
if (tspp_channels_in_use(pdev) == 0) {
- tspp_clock_start(pdev);
+ rc = tspp_clock_start(pdev);
+ if (rc)
+ return rc;
+
wake_lock(&pdev->wake_lock);
}
@@ -1637,6 +1650,8 @@
tspp_clock_stop(pdev);
}
+ pm_runtime_put(&pdev->pdev->dev);
+
return 0;
}
EXPORT_SYMBOL(tspp_close_channel);
@@ -3021,6 +3036,7 @@
{
struct tspp_channel *channel;
u32 i;
+ int rc;
struct tspp_device *device = platform_get_drvdata(pdev);
@@ -3033,9 +3049,11 @@
}
/* de-registering BAM device requires clocks */
- tspp_clock_start(device);
- sps_deregister_bam_device(device->bam_handle);
- tspp_clock_stop(device);
+ rc = tspp_clock_start(device);
+ if (rc == 0) {
+ sps_deregister_bam_device(device->bam_handle);
+ tspp_clock_stop(device);
+ }
for (i = 0; i < TSPP_TSIF_INSTANCES; i++) {
tsif_debugfs_exit(&device->tsif[i]);
@@ -3058,7 +3076,7 @@
clk_put(device->tsif_pclk);
pm_runtime_disable(&pdev->dev);
- pm_runtime_put(&pdev->dev);
+
kfree(device);
return 0;
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index b386266..9edb20d 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -6116,7 +6116,6 @@
mmc->caps2 |= (MMC_CAP2_BOOTPART_NOACC | MMC_CAP2_DETECT_ON_ERR);
mmc->caps2 |= MMC_CAP2_SANITIZE;
mmc->caps2 |= MMC_CAP2_CACHE_CTRL;
- mmc->caps2 |= MMC_CAP2_INIT_BKOPS;
mmc->caps2 |= MMC_CAP2_POWEROFF_NOTIFY;
if (plat->nonremovable)
diff --git a/drivers/mmc/host/msm_sdcc.h b/drivers/mmc/host/msm_sdcc.h
index abb54fe..b5522fb 100644
--- a/drivers/mmc/host/msm_sdcc.h
+++ b/drivers/mmc/host/msm_sdcc.h
@@ -504,10 +504,8 @@
host->hw_caps |= MSMSDCC_SW_RST | MSMSDCC_SW_RST_CFG |
MSMSDCC_AUTO_CMD21 |
MSMSDCC_DATA_PEND_FOR_CMD53 |
- MSMSDCC_TESTBUS_DEBUG;
-
- if ((step == 0x2b) || (step == 0x38))
- host->hw_caps |= MSMSDCC_SW_RST_CFG_BROKEN;
+ MSMSDCC_TESTBUS_DEBUG |
+ MSMSDCC_SW_RST_CFG_BROKEN;
}
int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave);
diff --git a/drivers/net/ethernet/msm/Kconfig b/drivers/net/ethernet/msm/Kconfig
index 3fced2d..e15f4a9 100644
--- a/drivers/net/ethernet/msm/Kconfig
+++ b/drivers/net/ethernet/msm/Kconfig
@@ -50,3 +50,9 @@
This driver supports Ethernet in the FSM9xxx.
To compile this driver as a module, choose M here: the
module will be called qfec.
+
+config ECM_IPA
+ tristate "STD ECM LAN Driver support"
+ depends on IPA
+ help
+ Allows LAN between Apps and tethered HOST on STD ECM
diff --git a/drivers/net/ethernet/msm/Makefile b/drivers/net/ethernet/msm/Makefile
index 7d9d4c6..e152ec7 100644
--- a/drivers/net/ethernet/msm/Makefile
+++ b/drivers/net/ethernet/msm/Makefile
@@ -7,3 +7,4 @@
obj-$(CONFIG_MSM_RMNET_BAM) += msm_rmnet_bam.o
obj-$(CONFIG_MSM_RMNET_SMUX) += msm_rmnet_smux.o
obj-$(CONFIG_QFEC) += qfec.o
+obj-$(CONFIG_ECM_IPA) += ecm_ipa.o
diff --git a/drivers/net/ethernet/msm/ecm_ipa.c b/drivers/net/ethernet/msm/ecm_ipa.c
new file mode 100644
index 0000000..605fd84
--- /dev/null
+++ b/drivers/net/ethernet/msm/ecm_ipa.c
@@ -0,0 +1,1105 @@
+/* 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/debugfs.h>
+#include <linux/errno.h>
+#include <linux/etherdevice.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <mach/ecm_ipa.h>
+
+#define DRIVER_NAME "ecm_ipa"
+#define DRIVER_VERSION "19-Feb-2013"
+#define ECM_IPA_IPV4_HDR_NAME "ecm_eth_ipv4"
+#define ECM_IPA_IPV6_HDR_NAME "ecm_eth_ipv6"
+#define IPA_TO_USB_CLIENT IPA_CLIENT_USB_CONS
+#define INACTIVITY_MSEC_DELAY 100
+#define ECM_IPA_ERROR(fmt, args...) \
+ pr_err(DRIVER_NAME "@%s@%d@ctx:%s: "\
+ fmt, __func__, __LINE__, current->comm, ## args)
+#ifdef ECM_IPA_DEBUG_ON
+#define ECM_IPA_DEBUG(fmt, args...) \
+ pr_err(DRIVER_NAME "@%s@%d@ctx:%s: "\
+ fmt, __func__, __LINE__, current->comm, ## args)
+#else /* ECM_IPA_DEBUG_ON */
+#define ECM_IPA_DEBUG(fmt, args...)
+#endif /* ECM_IPA_DEBUG_ON */
+
+#define NULL_CHECK(ptr) \
+ do { \
+ if (!(ptr)) { \
+ ECM_IPA_ERROR("null pointer #ptr\n"); \
+ return -EINVAL; \
+ } \
+ } \
+ while (0)
+
+#define ECM_IPA_LOG_ENTRY() ECM_IPA_DEBUG("begin\n")
+#define ECM_IPA_LOG_EXIT() ECM_IPA_DEBUG("end\n")
+
+/**
+ * struct ecm_ipa_dev - main driver context parameters
+ * @ack_spinlock: protect last sent skb
+ * @last_out_skb: last sent skb saved until Tx notify is received from IPA
+ * @net: network interface struct implemented by this driver
+ * @folder: debugfs folder for various debuging switches
+ * @tx_enable: flag that enable/disable Tx path to continue to IPA
+ * @rx_enable: flag that enable/disable Rx path to continue to IPA
+ * @rm_enable: flag that enable/disable Resource manager request prior to Tx
+ * @dma_enable: flag that allow on-the-fly DMA mode for IPA
+ * @tx_file: saved debugfs entry to allow cleanup
+ * @rx_file: saved debugfs entry to allow cleanup
+ * @rm_file: saved debugfs entry to allow cleanup
+ * @dma_file: saved debugfs entry to allow cleanup
+ * @eth_ipv4_hdr_hdl: saved handle for ipv4 header-insertion table
+ * @eth_ipv6_hdr_hdl: saved handle for ipv6 header-insertion table
+ * @usb_to_ipa_hdl: save handle for IPA pipe operations
+ * @ipa_to_usb_hdl: save handle for IPA pipe operations
+ */
+struct ecm_ipa_dev {
+ spinlock_t ack_spinlock;
+ struct sk_buff *last_out_skb;
+ struct net_device *net;
+ bool tx_enable;
+ bool rx_enable;
+ bool rm_enable;
+ bool dma_enable;
+ struct dentry *folder;
+ struct dentry *tx_file;
+ struct dentry *rx_file;
+ struct dentry *rm_file;
+ struct dentry *dma_file;
+ uint32_t eth_ipv4_hdr_hdl;
+ uint32_t eth_ipv6_hdr_hdl;
+ u32 usb_to_ipa_hdl;
+ u32 ipa_to_usb_hdl;
+};
+
+/**
+ * struct ecm_ipa_ctx - saved pointer for the std ecm network device
+ * which allow ecm_ipa to be a singleton
+ */
+static struct ecm_ipa_dev *ecm_ipa_ctx;
+
+static int ecm_ipa_ep_registers_cfg(u32 usb_to_ipa_hdl, u32 ipa_to_usb_hdl);
+static void sk_buff_print(struct sk_buff *skb);
+static int ecm_ipa_set_device_ethernet_addr(
+ u8 *dev_ethaddr, u8 device_ethaddr[]);
+static void ecm_ipa_packet_receive_notify(void *priv,
+ enum ipa_dp_evt_type evt,
+ unsigned long data);
+static void ecm_ipa_tx_complete_notify(void *priv,
+ enum ipa_dp_evt_type evt,
+ unsigned long data);
+static int ecm_ipa_ep_registers_dma_cfg(u32 usb_to_ipa_hdl);
+static int ecm_ipa_open(struct net_device *net);
+static int ecm_ipa_stop(struct net_device *net);
+static netdev_tx_t ecm_ipa_start_xmit(struct sk_buff *skb,
+ struct net_device *net);
+static void ecm_ipa_rm_notify(void *user_data, enum ipa_rm_event event,
+ unsigned long data);
+static int ecm_ipa_create_rm_resource(struct ecm_ipa_dev *dev);
+static void ecm_ipa_destory_rm_resource(void);
+static bool rx_filter(struct sk_buff *skb);
+static bool tx_filter(struct sk_buff *skb);
+static bool rm_enabled(struct ecm_ipa_dev *dev);
+
+static int ecm_ipa_rules_cfg(struct ecm_ipa_dev *dev,
+ const void *dst_mac, const void *src_mac);
+static int ecm_ipa_register_tx(struct ecm_ipa_dev *dev);
+static void ecm_ipa_deregister_tx(struct ecm_ipa_dev *dev);
+static int ecm_ipa_debugfs_init(struct ecm_ipa_dev *dev);
+static void ecm_ipa_debugfs_destroy(struct ecm_ipa_dev *dev);
+static int ecm_ipa_debugfs_tx_open(struct inode *inode, struct file *file);
+static int ecm_ipa_debugfs_rx_open(struct inode *inode, struct file *file);
+static int ecm_ipa_debugfs_rm_open(struct inode *inode, struct file *file);
+static int ecm_ipa_debugfs_dma_open(struct inode *inode, struct file *file);
+static ssize_t ecm_ipa_debugfs_enable_read(struct file *file,
+ char __user *ubuf, size_t count, loff_t *ppos);
+static ssize_t ecm_ipa_debugfs_enable_write(struct file *file,
+ const char __user *buf, size_t count, loff_t *ppos);
+static ssize_t ecm_ipa_debugfs_enable_write_dma(struct file *file,
+ const char __user *buf, size_t count, loff_t *ppos);
+static void eth_get_drvinfo(struct net_device *net,
+ struct ethtool_drvinfo *drv_info);
+
+static const struct net_device_ops ecm_ipa_netdev_ops = {
+ .ndo_open = ecm_ipa_open,
+ .ndo_stop = ecm_ipa_stop,
+ .ndo_start_xmit = ecm_ipa_start_xmit,
+ .ndo_set_mac_address = eth_mac_addr,
+};
+static const struct ethtool_ops ops = {
+ .get_drvinfo = eth_get_drvinfo,
+ .get_link = ethtool_op_get_link,
+};
+const struct file_operations ecm_ipa_debugfs_tx_ops = {
+ .open = ecm_ipa_debugfs_tx_open,
+ .read = ecm_ipa_debugfs_enable_read,
+ .write = ecm_ipa_debugfs_enable_write,
+};
+const struct file_operations ecm_ipa_debugfs_rx_ops = {
+ .open = ecm_ipa_debugfs_rx_open,
+ .read = ecm_ipa_debugfs_enable_read,
+ .write = ecm_ipa_debugfs_enable_write,
+};
+const struct file_operations ecm_ipa_debugfs_rm_ops = {
+ .open = ecm_ipa_debugfs_rm_open,
+ .read = ecm_ipa_debugfs_enable_read,
+ .write = ecm_ipa_debugfs_enable_write,
+};
+const struct file_operations ecm_ipa_debugfs_dma_ops = {
+ .open = ecm_ipa_debugfs_dma_open,
+ .read = ecm_ipa_debugfs_enable_read,
+ .write = ecm_ipa_debugfs_enable_write_dma,
+};
+
+/**
+ * ecm_ipa_init() - initializes internal data structures
+ * @ecm_ipa_rx_dp_notify: supplied callback to be called by the IPA
+ * driver upon data packets received from USB pipe into IPA core.
+ * @ecm_ipa_rt_dp_notify: supplied callback to be called by the IPA
+ * driver upon exception packets sent from IPA pipe into USB core.
+ * @priv: should be passed later on to ecm_ipa_configure, hold the network
+ * structure allocated for STD ECM interface.
+ *
+ * Shall be called prior to pipe connection.
+ * The out parameters (the callbacks) shall be supplied to ipa_connect.
+ * Detailed description:
+ * - set the callbacks to be used by the caller upon ipa_connect
+ * - allocate the network device
+ * - set the priv argument with a reference to the network device
+ *
+ * Returns negative errno, or zero on success
+ */
+int ecm_ipa_init(ecm_ipa_callback *ecm_ipa_rx_dp_notify,
+ ecm_ipa_callback *ecm_ipa_tx_dp_notify,
+ void **priv)
+{
+ int ret = 0;
+ struct net_device *net;
+ struct ecm_ipa_dev *dev;
+ ECM_IPA_LOG_ENTRY();
+ ECM_IPA_DEBUG("%s version %s\n", DRIVER_NAME, DRIVER_VERSION);
+ NULL_CHECK(ecm_ipa_rx_dp_notify);
+ NULL_CHECK(ecm_ipa_tx_dp_notify);
+ NULL_CHECK(priv);
+ net = alloc_etherdev(sizeof(struct ecm_ipa_dev));
+ if (!net) {
+ ret = -ENOMEM;
+ ECM_IPA_ERROR("fail to allocate etherdev\n");
+ goto fail_alloc_etherdev;
+ }
+ ECM_IPA_DEBUG("etherdev was successfully allocated\n");
+ dev = netdev_priv(net);
+ memset(dev, 0, sizeof(*dev));
+ dev->tx_enable = true;
+ dev->rx_enable = true;
+ spin_lock_init(&dev->ack_spinlock);
+ dev->net = net;
+ ecm_ipa_ctx = dev;
+ *priv = (void *)dev;
+ snprintf(net->name, sizeof(net->name), "%s%%d", "ecm");
+ net->netdev_ops = &ecm_ipa_netdev_ops;
+ ECM_IPA_DEBUG("internal data structures were intialized\n");
+ ret = ecm_ipa_debugfs_init(dev);
+ if (ret)
+ goto fail_debugfs;
+ ECM_IPA_DEBUG("debugfs entries were created\n");
+ *ecm_ipa_rx_dp_notify = ecm_ipa_packet_receive_notify;
+ *ecm_ipa_tx_dp_notify = ecm_ipa_tx_complete_notify;
+ ECM_IPA_LOG_EXIT();
+ return 0;
+fail_debugfs:
+ free_netdev(net);
+fail_alloc_etherdev:
+ return ret;
+}
+EXPORT_SYMBOL(ecm_ipa_init);
+
+/**
+ * ecm_ipa_rules_cfg() - set header insertion and register Tx/Rx properties
+ * Headers will be commited to HW
+ * @dev: main driver context parameters
+ * @dst_mac: destination MAC address
+ * @src_mac: source MAC address
+ *
+ * Returns negative errno, or zero on success
+ */
+static int ecm_ipa_rules_cfg(struct ecm_ipa_dev *dev,
+ const void *dst_mac, const void *src_mac)
+{
+ struct ipa_ioc_add_hdr *hdrs;
+ struct ipa_hdr_add *ipv4_hdr;
+ struct ipa_hdr_add *ipv6_hdr;
+ struct ethhdr *eth_ipv4;
+ struct ethhdr *eth_ipv6;
+ int result = 0;
+
+ ECM_IPA_LOG_ENTRY();
+ hdrs = kzalloc(sizeof(*hdrs) + sizeof(*ipv4_hdr) + sizeof(*ipv6_hdr),
+ GFP_KERNEL);
+ if (!hdrs) {
+ result = -ENOMEM;
+ goto out;
+ }
+ ipv4_hdr = &hdrs->hdr[0];
+ eth_ipv4 = (struct ethhdr *)ipv4_hdr->hdr;
+ ipv6_hdr = &hdrs->hdr[1];
+ eth_ipv6 = (struct ethhdr *)ipv6_hdr->hdr;
+ strlcpy(ipv4_hdr->name, ECM_IPA_IPV4_HDR_NAME, IPA_RESOURCE_NAME_MAX);
+ memcpy(eth_ipv4->h_dest, dst_mac, ETH_ALEN);
+ memcpy(eth_ipv4->h_source, src_mac, ETH_ALEN);
+ eth_ipv4->h_proto = ETH_P_IP;
+ ipv4_hdr->hdr_len = ETH_HLEN;
+ ipv4_hdr->is_partial = 0;
+ strlcpy(ipv6_hdr->name, ECM_IPA_IPV6_HDR_NAME, IPA_RESOURCE_NAME_MAX);
+ memcpy(eth_ipv6->h_dest, dst_mac, ETH_ALEN);
+ memcpy(eth_ipv6->h_source, src_mac, ETH_ALEN);
+ eth_ipv6->h_proto = ETH_P_IPV6;
+ ipv6_hdr->hdr_len = ETH_HLEN;
+ ipv6_hdr->is_partial = 0;
+ hdrs->commit = 1;
+ hdrs->num_hdrs = 2;
+ result = ipa_add_hdr(hdrs);
+ if (result) {
+ ECM_IPA_ERROR("Fail on Header-Insertion(%d)\n", result);
+ goto out_free_mem;
+ }
+ if (ipv4_hdr->status) {
+ ECM_IPA_ERROR("Fail on Header-Insertion ipv4(%d)\n",
+ ipv4_hdr->status);
+ result = ipv4_hdr->status;
+ goto out_free_mem;
+ }
+ if (ipv6_hdr->status) {
+ ECM_IPA_ERROR("Fail on Header-Insertion ipv6(%d)\n",
+ ipv6_hdr->status);
+ result = ipv6_hdr->status;
+ goto out_free_mem;
+ }
+ dev->eth_ipv4_hdr_hdl = ipv4_hdr->hdr_hdl;
+ dev->eth_ipv6_hdr_hdl = ipv6_hdr->hdr_hdl;
+ ECM_IPA_LOG_EXIT();
+out_free_mem:
+ kfree(hdrs);
+out:
+ return result;
+}
+
+static void ecm_ipa_rules_destroy(struct ecm_ipa_dev *dev)
+{
+ struct ipa_ioc_del_hdr *del_hdr;
+ struct ipa_hdr_del *ipv4;
+ struct ipa_hdr_del *ipv6;
+ int result;
+ del_hdr = kzalloc(sizeof(*del_hdr) + sizeof(*ipv4) +
+ sizeof(*ipv6), GFP_KERNEL);
+ if (!del_hdr)
+ return;
+ del_hdr->commit = 1;
+ del_hdr->num_hdls = 2;
+ ipv4 = &del_hdr->hdl[0];
+ ipv4->hdl = dev->eth_ipv4_hdr_hdl;
+ ipv6 = &del_hdr->hdl[1];
+ ipv6->hdl = dev->eth_ipv6_hdr_hdl;
+ result = ipa_del_hdr(del_hdr);
+ if (result || ipv4->status || ipv6->status)
+ ECM_IPA_ERROR("ipa_del_hdr failed");
+}
+
+static int ecm_ipa_register_tx(struct ecm_ipa_dev *dev)
+{
+ struct ipa_tx_intf tx_properties = {0};
+ struct ipa_ioc_tx_intf_prop properties[2] = { {0}, {0} };
+ struct ipa_ioc_tx_intf_prop *ipv4_property;
+ struct ipa_ioc_tx_intf_prop *ipv6_property;
+ int result = 0;
+ ECM_IPA_LOG_ENTRY();
+ tx_properties.prop = properties;
+ ipv4_property = &tx_properties.prop[0];
+ ipv4_property->ip = IPA_IP_v4;
+ ipv4_property->dst_pipe = IPA_TO_USB_CLIENT;
+ strlcpy(ipv4_property->hdr_name, ECM_IPA_IPV4_HDR_NAME,
+ IPA_RESOURCE_NAME_MAX);
+ ipv6_property = &tx_properties.prop[1];
+ ipv6_property->ip = IPA_IP_v6;
+ ipv6_property->dst_pipe = IPA_TO_USB_CLIENT;
+ strlcpy(ipv6_property->hdr_name, ECM_IPA_IPV6_HDR_NAME,
+ IPA_RESOURCE_NAME_MAX);
+ tx_properties.num_props = 2;
+ result = ipa_register_intf(dev->net->name, &tx_properties, NULL);
+ if (result)
+ ECM_IPA_ERROR("fail on Tx_prop registration\n");
+ ECM_IPA_LOG_EXIT();
+ return result;
+}
+
+static void ecm_ipa_deregister_tx(struct ecm_ipa_dev *dev)
+{
+ int result;
+ ECM_IPA_LOG_ENTRY();
+ result = ipa_deregister_intf(dev->net->name);
+ if (result)
+ ECM_IPA_DEBUG("Fail on Tx prop deregister\n");
+ ECM_IPA_LOG_EXIT();
+ return;
+}
+
+/**
+ * ecm_ipa_configure() - make IPA core end-point specific configuration
+ * @usb_to_ipa_hdl: handle of usb_to_ipa end-point for IPA driver
+ * @ipa_to_usb_hdl: handle of ipa_to_usb end-point for IPA driver
+ * @host_ethaddr: host Ethernet address in network order
+ * @device_ethaddr: device Ethernet address in network order
+ *
+ * Configure the usb_to_ipa and ipa_to_usb end-point registers
+ * - USB->IPA end-point: disable de-aggregation, enable link layer
+ * header removal (Ethernet removal), source NATing and default routing.
+ * - IPA->USB end-point: disable aggregation, add link layer header (Ethernet)
+ * - allocate Ethernet device
+ * - register to Linux network stack
+ *
+ * Returns negative errno, or zero on success
+ */
+int ecm_ipa_configure(u8 host_ethaddr[], u8 device_ethaddr[],
+ void *priv)
+{
+ struct ecm_ipa_dev *dev = priv;
+ struct net_device *net;
+ int result;
+ ECM_IPA_LOG_ENTRY();
+ NULL_CHECK(host_ethaddr);
+ NULL_CHECK(host_ethaddr);
+ NULL_CHECK(dev);
+ net = dev->net;
+ NULL_CHECK(net);
+ ECM_IPA_DEBUG("host_ethaddr=%pM device_ethaddr=%pM\n",
+ host_ethaddr, device_ethaddr);
+ result = ecm_ipa_create_rm_resource(dev);
+ if (result) {
+ ECM_IPA_ERROR("fail on RM create\n");
+ return -EINVAL;
+ }
+ ECM_IPA_DEBUG("RM resource was created\n");
+ netif_carrier_off(dev->net);
+ result = ecm_ipa_set_device_ethernet_addr(net->dev_addr,
+ device_ethaddr);
+ if (result) {
+ ECM_IPA_ERROR("set device MAC failed\n");
+ goto fail_set_device_ethernet;
+ }
+ result = ecm_ipa_rules_cfg(dev, host_ethaddr, device_ethaddr);
+ if (result) {
+ ECM_IPA_ERROR("fail on ipa rules set\n");
+ goto fail_set_device_ethernet;
+ }
+ ECM_IPA_DEBUG("Ethernet header insertion was set\n");
+ result = ecm_ipa_register_tx(dev);
+ if (result) {
+ ECM_IPA_ERROR("fail on properties set\n");
+ goto fail_register_tx;
+ }
+ ECM_IPA_DEBUG("ECM Tx properties were registered\n");
+ result = register_netdev(net);
+ if (result) {
+ ECM_IPA_ERROR("register_netdev failed: %d\n", result);
+ goto fail_register_netdev;
+ }
+ ECM_IPA_DEBUG("register_netdev succeeded\n");
+ ECM_IPA_LOG_EXIT();
+ return 0;
+fail_register_netdev:
+ ecm_ipa_deregister_tx(dev);
+fail_register_tx:
+fail_set_device_ethernet:
+ ecm_ipa_rules_destroy(dev);
+ ecm_ipa_destory_rm_resource();
+ free_netdev(net);
+ return result;
+}
+EXPORT_SYMBOL(ecm_ipa_configure);
+
+int ecm_ipa_connect(u32 usb_to_ipa_hdl, u32 ipa_to_usb_hdl,
+ void *priv)
+{
+ struct ecm_ipa_dev *dev = priv;
+ ECM_IPA_LOG_ENTRY();
+ NULL_CHECK(priv);
+ ECM_IPA_DEBUG("usb_to_ipa_hdl = %d, ipa_to_usb_hdl = %d\n",
+ usb_to_ipa_hdl, ipa_to_usb_hdl);
+ if (!usb_to_ipa_hdl || usb_to_ipa_hdl >= IPA_CLIENT_MAX) {
+ ECM_IPA_ERROR("usb_to_ipa_hdl(%d) is not a valid ipa handle\n",
+ usb_to_ipa_hdl);
+ return -EINVAL;
+ }
+ if (!ipa_to_usb_hdl || ipa_to_usb_hdl >= IPA_CLIENT_MAX) {
+ ECM_IPA_ERROR("ipa_to_usb_hdl(%d) is not a valid ipa handle\n",
+ ipa_to_usb_hdl);
+ return -EINVAL;
+ }
+ dev->ipa_to_usb_hdl = ipa_to_usb_hdl;
+ dev->usb_to_ipa_hdl = usb_to_ipa_hdl;
+ ecm_ipa_ep_registers_cfg(usb_to_ipa_hdl, ipa_to_usb_hdl);
+ netif_carrier_on(dev->net);
+ if (!netif_carrier_ok(dev->net)) {
+ ECM_IPA_ERROR("netif_carrier_ok error\n");
+ return -EBUSY;
+ }
+ ECM_IPA_LOG_EXIT();
+ return 0;
+}
+EXPORT_SYMBOL(ecm_ipa_connect);
+
+int ecm_ipa_disconnect(void *priv)
+{
+ struct ecm_ipa_dev *dev = priv;
+ ECM_IPA_LOG_ENTRY();
+ NULL_CHECK(dev);
+ netif_carrier_off(dev->net);
+ ECM_IPA_LOG_EXIT();
+ return 0;
+}
+EXPORT_SYMBOL(ecm_ipa_disconnect);
+
+
+static void ecm_ipa_rm_notify(void *user_data, enum ipa_rm_event event,
+ unsigned long data)
+{
+ struct ecm_ipa_dev *dev = user_data;
+ ECM_IPA_LOG_ENTRY();
+ if (event == IPA_RM_RESOURCE_GRANTED &&
+ netif_queue_stopped(dev->net)) {
+ ECM_IPA_DEBUG("Resource Granted - waking queue\n");
+ netif_wake_queue(dev->net);
+ } else {
+ ECM_IPA_DEBUG("Resource released\n");
+ }
+ ECM_IPA_LOG_EXIT();
+}
+
+static int ecm_ipa_create_rm_resource(struct ecm_ipa_dev *dev)
+{
+ struct ipa_rm_create_params create_params = {0};
+ int result;
+ ECM_IPA_LOG_ENTRY();
+ create_params.name = IPA_RM_RESOURCE_STD_ECM_PROD;
+ create_params.reg_params.user_data = dev;
+ create_params.reg_params.notify_cb = ecm_ipa_rm_notify;
+ result = ipa_rm_create_resource(&create_params);
+ if (result) {
+ ECM_IPA_ERROR("Fail on ipa_rm_create_resource\n");
+ goto fail_rm_create;
+ }
+ ECM_IPA_DEBUG("rm client was created");
+
+ result = ipa_rm_inactivity_timer_init(IPA_RM_RESOURCE_STD_ECM_PROD,
+ INACTIVITY_MSEC_DELAY);
+ if (result) {
+ ECM_IPA_ERROR("Fail on ipa_rm_inactivity_timer_init\n");
+ goto fail_it;
+ }
+ ECM_IPA_DEBUG("rm_it client was created");
+ ECM_IPA_LOG_EXIT();
+ return 0;
+fail_it:
+fail_rm_create:
+ return result;
+}
+
+static void ecm_ipa_destory_rm_resource(void)
+{
+ ECM_IPA_LOG_ENTRY();
+ ipa_rm_inactivity_timer_destroy(IPA_RM_RESOURCE_STD_ECM_PROD);
+ ECM_IPA_LOG_EXIT();
+}
+
+static bool rx_filter(struct sk_buff *skb)
+{
+ struct ecm_ipa_dev *dev = netdev_priv(skb->dev);
+ return !dev->rx_enable;
+}
+
+static bool tx_filter(struct sk_buff *skb)
+{
+ struct ecm_ipa_dev *dev = netdev_priv(skb->dev);
+ return !dev->tx_enable;
+}
+
+static bool rm_enabled(struct ecm_ipa_dev *dev)
+{
+ return dev->rm_enable;
+}
+
+static int ecm_ipa_open(struct net_device *net)
+{
+ ECM_IPA_LOG_ENTRY();
+ netif_start_queue(net);
+ ECM_IPA_LOG_EXIT();
+ return 0;
+}
+
+static int ecm_ipa_stop(struct net_device *net)
+{
+ ECM_IPA_LOG_ENTRY();
+ ECM_IPA_DEBUG("stopping net device\n");
+ netif_stop_queue(net);
+ ECM_IPA_LOG_EXIT();
+ return 0;
+}
+
+/**
+ * ecm_ipa_cleanup() - destroys all
+ * ecm information
+ * @priv: main driver context parameters
+ *
+ */
+void ecm_ipa_cleanup(void *priv)
+{
+ struct ecm_ipa_dev *dev = priv;
+ ECM_IPA_LOG_ENTRY();
+ if (!dev) {
+ ECM_IPA_ERROR("dev NULL pointer\n");
+ return;
+ }
+ if (rm_enabled(dev)) {
+ ecm_ipa_destory_rm_resource();
+ ecm_ipa_debugfs_destroy(dev);
+ }
+ if (!dev->net) {
+ unregister_netdev(dev->net);
+ free_netdev(dev->net);
+ }
+ ECM_IPA_DEBUG("cleanup done\n");
+ ecm_ipa_ctx = NULL;
+ ECM_IPA_LOG_EXIT();
+ return ;
+}
+EXPORT_SYMBOL(ecm_ipa_cleanup);
+
+static int resource_request(struct ecm_ipa_dev *dev)
+{
+ int result = 0;
+ ECM_IPA_LOG_ENTRY();
+ if (!rm_enabled(dev))
+ goto out;
+ result = ipa_rm_inactivity_timer_request_resource(
+ IPA_RM_RESOURCE_STD_ECM_PROD);
+out:
+ ECM_IPA_LOG_EXIT();
+ return result;
+}
+
+static void resource_release(struct ecm_ipa_dev *dev)
+{
+ ECM_IPA_LOG_ENTRY();
+ if (!rm_enabled(dev))
+ goto out;
+ ipa_rm_inactivity_timer_release_resource(IPA_RM_RESOURCE_STD_ECM_PROD);
+out:
+ ECM_IPA_LOG_EXIT();
+}
+
+/**
+ * ecm_ipa_start_xmit() - send data from APPs to USB core via IPA core
+ * @skb: packet received from Linux stack
+ * @net: the network device being used to send this packet
+ *
+ * Several conditions needed in order to send the packet to IPA:
+ * - we are in a valid state were the queue is not stopped
+ * - Filter Tx switch is turned off
+ * - The resources required for actual Tx are all up
+ *
+ */
+static netdev_tx_t ecm_ipa_start_xmit(struct sk_buff *skb,
+ struct net_device *net)
+{
+ int ret;
+ netdev_tx_t status = NETDEV_TX_BUSY;
+ struct ecm_ipa_dev *dev = netdev_priv(net);
+ unsigned long flags;
+ ECM_IPA_LOG_ENTRY();
+ if (unlikely(netif_queue_stopped(net))) {
+ ECM_IPA_ERROR("interface queue is stopped\n");
+ goto out;
+ }
+ ECM_IPA_DEBUG("send (proto=0x%04x)\n", ntohs(skb->protocol));
+ if (unlikely(tx_filter(skb))) {
+ dev_kfree_skb_any(skb);
+ ECM_IPA_ERROR("packet got filtered out on Tx path\n");
+ status = NETDEV_TX_OK;
+ goto out;
+ }
+ ret = resource_request(dev);
+ if (ret) {
+ ECM_IPA_DEBUG("Waiting to resource\n");
+ netif_stop_queue(net);
+ goto resource_busy;
+ }
+ ECM_IPA_DEBUG("taking ack_lock\n");
+ spin_lock_irqsave(&dev->ack_spinlock, flags);
+ ECM_IPA_DEBUG("ack_lock taken\n");
+ if (dev->last_out_skb) {
+ ECM_IPA_DEBUG("No Tx-ack received for previous packet\n");
+ ECM_IPA_DEBUG("releasing ack_lock\n");
+ spin_unlock_irqrestore(&dev->ack_spinlock, flags);
+ ECM_IPA_DEBUG("ack_lock released\n");
+ netif_stop_queue(net);
+ status = -NETDEV_TX_BUSY;
+ goto out;
+ } else {
+ dev->last_out_skb = skb;
+ }
+ ECM_IPA_DEBUG("releasing ack_lock\n");
+ spin_unlock_irqrestore(&dev->ack_spinlock, flags);
+ ECM_IPA_DEBUG("ack_lock released\n");
+ sk_buff_print(skb);
+ ECM_IPA_DEBUG("ipa_tx_dp is called (dst_client=%d)\n",
+ IPA_TO_USB_CLIENT);
+ ret = ipa_tx_dp(IPA_TO_USB_CLIENT, skb, NULL);
+ if (ret) {
+ ECM_IPA_ERROR("ipa transmit failed (%d)\n", ret);
+ goto fail_tx_packet;
+ }
+ net->stats.tx_packets++;
+ net->stats.tx_bytes += skb->len;
+ ECM_IPA_LOG_EXIT();
+ status = NETDEV_TX_OK;
+ goto out;
+fail_tx_packet:
+out:
+ resource_release(dev);
+resource_busy:
+ ECM_IPA_LOG_EXIT();
+ return status;
+}
+
+/**
+ * ecm_ipa_packet_receive_notify() - Rx notify
+ *
+ * @priv: ecm driver context
+ * @evt: event type
+ * @data: data provided with event
+ *
+ * IPA will pass a packet with skb->data pointing to Ethernet packet frame
+ */
+void ecm_ipa_packet_receive_notify(void *priv,
+ enum ipa_dp_evt_type evt,
+ unsigned long data)
+{
+ struct sk_buff *skb = (struct sk_buff *)data;
+ struct ecm_ipa_dev *dev = priv;
+ int result;
+ ECM_IPA_LOG_ENTRY();
+ if (evt != IPA_RECEIVE) {
+ ECM_IPA_ERROR("A none IPA_RECEIVE event in ecm_ipa_receive\n");
+ return;
+ }
+ ECM_IPA_DEBUG("receive\n");
+ sk_buff_print(skb);
+ skb->dev = dev->net;
+ skb->protocol = eth_type_trans(skb, dev->net);
+ if (rx_filter(skb)) {
+ ECM_IPA_ERROR("packet got filtered out on Rx path\n");
+ dev_kfree_skb_any(skb);
+ return;
+ }
+ ECM_IPA_DEBUG("kernel stack Rx is called\n");
+ result = netif_rx(skb);
+ if (result)
+ ECM_IPA_ERROR("fail on netif_rx\n");
+ dev->net->stats.rx_packets++;
+ dev->net->stats.rx_bytes += skb->len;
+ ECM_IPA_LOG_EXIT();
+ return;
+}
+
+/**
+ * ecm_ipa_tx_complete_notify() - Rx notify
+ *
+ * @priv: ecm driver context
+ * @evt: event type
+ * @data: data provided with event
+ *
+ * Check that the packet is the one we sent and release it
+ * This function will be called in defered context in IPA wq.
+ */
+void ecm_ipa_tx_complete_notify(void *priv,
+ enum ipa_dp_evt_type evt,
+ unsigned long data)
+{
+ struct sk_buff *skb = (struct sk_buff *)data;
+ struct ecm_ipa_dev *dev = priv;
+ unsigned long flags;
+ ECM_IPA_LOG_ENTRY();
+
+ if (!dev) {
+ ECM_IPA_ERROR("dev is NULL pointer\n");
+ return;
+ }
+ if (evt != IPA_WRITE_DONE) {
+ ECM_IPA_ERROR("unsupported event on Tx callback\n");
+ return;
+ }
+ ECM_IPA_DEBUG("taking ack_lock\n");
+ spin_lock_irqsave(&dev->ack_spinlock, flags);
+ ECM_IPA_DEBUG("ack_lock taken\n");
+ if (skb != dev->last_out_skb)
+ ECM_IPA_ERROR("ACKed/Sent not the same(FIFO expected)\n");
+ dev->last_out_skb = NULL;
+ ECM_IPA_DEBUG("releasing ack_lock\n");
+ spin_unlock_irqrestore(&dev->ack_spinlock, flags);
+ ECM_IPA_DEBUG("ack_lock released\n");
+ if (netif_queue_stopped(dev->net)) {
+ ECM_IPA_DEBUG("waking up queue\n");
+ netif_wake_queue(dev->net);
+ }
+ dev_kfree_skb_any(skb);
+ ECM_IPA_LOG_EXIT();
+ return;
+}
+
+static int ecm_ipa_debugfs_tx_open(struct inode *inode, struct file *file)
+{
+ struct ecm_ipa_dev *dev = inode->i_private;
+ ECM_IPA_LOG_ENTRY();
+ file->private_data = &(dev->tx_enable);
+ ECM_IPA_LOG_ENTRY();
+ return 0;
+}
+
+static int ecm_ipa_debugfs_rx_open(struct inode *inode, struct file *file)
+{
+ struct ecm_ipa_dev *dev = inode->i_private;
+ ECM_IPA_LOG_ENTRY();
+ file->private_data = &(dev->rx_enable);
+ ECM_IPA_LOG_EXIT();
+ return 0;
+}
+
+static int ecm_ipa_debugfs_rm_open(struct inode *inode, struct file *file)
+{
+ struct ecm_ipa_dev *dev = inode->i_private;
+ ECM_IPA_LOG_ENTRY();
+ file->private_data = &(dev->rm_enable);
+ ECM_IPA_LOG_EXIT();
+ return 0;
+}
+
+static ssize_t ecm_ipa_debugfs_enable_write_dma(struct file *file,
+ const char __user *buf, size_t count, loff_t *ppos)
+{
+ struct ecm_ipa_dev *dev = file->private_data;
+ int result;
+ ECM_IPA_LOG_ENTRY();
+ file->private_data = &dev->dma_enable;
+ result = ecm_ipa_debugfs_enable_write(file, buf, count, ppos);
+ if (dev->dma_enable)
+ ecm_ipa_ep_registers_dma_cfg(dev->usb_to_ipa_hdl);
+ else
+ ecm_ipa_ep_registers_cfg(dev->usb_to_ipa_hdl,
+ dev->usb_to_ipa_hdl);
+ ECM_IPA_LOG_EXIT();
+ return result;
+}
+
+static int ecm_ipa_debugfs_dma_open(struct inode *inode, struct file *file)
+{
+ struct ecm_ipa_dev *dev = inode->i_private;
+ ECM_IPA_LOG_ENTRY();
+ file->private_data = dev;
+ ECM_IPA_LOG_EXIT();
+ return 0;
+}
+
+static ssize_t ecm_ipa_debugfs_enable_write(struct file *file,
+ const char __user *buf, size_t count, loff_t *ppos)
+{
+ unsigned long missing;
+ char input;
+ bool *enable = file->private_data;
+ if (count != sizeof(input) + 1) {
+ ECM_IPA_ERROR("wrong input length(%zd)\n", count);
+ return -EINVAL;
+ }
+ if (!buf) {
+ ECM_IPA_ERROR("Bad argument\n");
+ return -EINVAL;
+ }
+ missing = copy_from_user(&input, buf, 1);
+ if (missing)
+ return -EFAULT;
+ ECM_IPA_DEBUG("input received %c\n", input);
+ *enable = input - '0';
+ ECM_IPA_DEBUG("value was set to %d\n", *enable);
+ return count;
+}
+
+static ssize_t ecm_ipa_debugfs_enable_read(struct file *file,
+ char __user *ubuf, size_t count, loff_t *ppos)
+{
+ int nbytes;
+ int size = 0;
+ int ret;
+ loff_t pos;
+ u8 enable_str[sizeof(char)*3] = {0};
+ bool *enable = file->private_data;
+ pos = *ppos;
+ nbytes = scnprintf(enable_str, sizeof(enable_str), "%d\n", *enable);
+ ret = simple_read_from_buffer(ubuf, count, ppos, enable_str, nbytes);
+ if (ret < 0) {
+ ECM_IPA_ERROR("simple_read_from_buffer problem");
+ return ret;
+ }
+ size += ret;
+ count -= nbytes;
+ *ppos = pos + size;
+ return size;
+}
+
+static int ecm_ipa_debugfs_init(struct ecm_ipa_dev *dev)
+{
+ const mode_t flags = S_IRUSR | S_IRGRP | S_IROTH |
+ S_IWUSR | S_IWGRP | S_IWOTH;
+ int ret = -EINVAL;
+ ECM_IPA_LOG_ENTRY();
+ if (!dev)
+ return -EINVAL;
+ dev->folder = debugfs_create_dir("ecm_ipa", NULL);
+ if (!dev->folder) {
+ ECM_IPA_ERROR("could not create debugfs folder entry\n");
+ ret = -EFAULT;
+ goto fail_folder;
+ }
+ dev->tx_file = debugfs_create_file("tx_enable", flags, dev->folder, dev,
+ &ecm_ipa_debugfs_tx_ops);
+ if (!dev->tx_file) {
+ ECM_IPA_ERROR("could not create debugfs tx file\n");
+ ret = -EFAULT;
+ goto fail_file;
+ }
+ dev->rx_file = debugfs_create_file("rx_enable", flags, dev->folder, dev,
+ &ecm_ipa_debugfs_rx_ops);
+ if (!dev->rx_file) {
+ ECM_IPA_ERROR("could not create debugfs rx file\n");
+ ret = -EFAULT;
+ goto fail_file;
+ }
+ dev->rm_file = debugfs_create_file("rm_enable", flags, dev->folder, dev,
+ &ecm_ipa_debugfs_rm_ops);
+ if (!dev->rm_file) {
+ ECM_IPA_ERROR("could not create debugfs rm file\n");
+ ret = -EFAULT;
+ goto fail_file;
+ }
+ dev->dma_file = debugfs_create_file("dma_enable", flags, dev->folder,
+ dev, &ecm_ipa_debugfs_dma_ops);
+ if (!dev->dma_file) {
+ ECM_IPA_ERROR("could not create debugfs dma file\n");
+ ret = -EFAULT;
+ goto fail_file;
+ }
+ ECM_IPA_LOG_EXIT();
+ return 0;
+fail_file:
+ debugfs_remove_recursive(dev->folder);
+fail_folder:
+ return ret;
+}
+
+static void ecm_ipa_debugfs_destroy(struct ecm_ipa_dev *dev)
+{
+ debugfs_remove_recursive(dev->folder);
+}
+
+static void eth_get_drvinfo(struct net_device *net,
+ struct ethtool_drvinfo *drv_info)
+{
+ ECM_IPA_LOG_ENTRY();
+ strlcpy(drv_info->driver, DRIVER_NAME, sizeof(drv_info->driver));
+ strlcpy(drv_info->version, DRIVER_VERSION, sizeof(drv_info->version));
+ ECM_IPA_LOG_EXIT();
+}
+
+
+/**
+ * ecm_ipa_ep_cfg() - configure the USB endpoints for ECM
+ *
+ *usb_to_ipa_hdl: handle received from ipa_connect
+ *ipa_to_usb_hdl: handle received from ipa_connect
+ *
+ * USB to IPA pipe:
+ * - No de-aggregation
+ * - Remove Ethernet header
+ * - SRC NAT
+ * - Default routing(0)
+ * IPA to USB Pipe:
+ * - No aggregation
+ * - Add Ethernet header
+ */
+int ecm_ipa_ep_registers_cfg(u32 usb_to_ipa_hdl, u32 ipa_to_usb_hdl)
+{
+ int result = 0;
+ struct ipa_ep_cfg usb_to_ipa_ep_cfg;
+ struct ipa_ep_cfg ipa_to_usb_ep_cfg;
+ ECM_IPA_LOG_ENTRY();
+ memset(&usb_to_ipa_ep_cfg, 0 , sizeof(struct ipa_ep_cfg));
+ usb_to_ipa_ep_cfg.aggr.aggr_en = IPA_BYPASS_AGGR;
+ usb_to_ipa_ep_cfg.hdr.hdr_len = ETH_HLEN;
+ usb_to_ipa_ep_cfg.nat.nat_en = IPA_SRC_NAT;
+ usb_to_ipa_ep_cfg.route.rt_tbl_hdl = 0;
+ usb_to_ipa_ep_cfg.mode.dst = IPA_CLIENT_A5_LAN_WAN_CONS;
+ usb_to_ipa_ep_cfg.mode.mode = IPA_BASIC;
+ result = ipa_cfg_ep(usb_to_ipa_hdl, &usb_to_ipa_ep_cfg);
+ if (result) {
+ ECM_IPA_ERROR("failed to configure USB to IPA point\n");
+ goto out;
+ }
+ memset(&ipa_to_usb_ep_cfg, 0 , sizeof(struct ipa_ep_cfg));
+ ipa_to_usb_ep_cfg.aggr.aggr_en = IPA_BYPASS_AGGR;
+ ipa_to_usb_ep_cfg.hdr.hdr_len = ETH_HLEN;
+ ipa_to_usb_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
+ result = ipa_cfg_ep(ipa_to_usb_hdl, &ipa_to_usb_ep_cfg);
+ if (result) {
+ ECM_IPA_ERROR("failed to configure IPA to USB end-point\n");
+ goto out;
+ }
+ ECM_IPA_DEBUG("end-point registers successfully configured\n");
+out:
+ ECM_IPA_LOG_EXIT();
+ return result;
+}
+
+/**
+ * ecm_ipa_ep_registers_dma_cfg() - configure the USB endpoints for ECM
+ * DMA
+ * @usb_to_ipa_hdl: handle received from ipa_connect
+ *
+ * This function will override the previous configuration
+ * which is needed for cores that does not support blocks logic
+ * Note that client handles are the actual pipe index
+ */
+int ecm_ipa_ep_registers_dma_cfg(u32 usb_to_ipa_hdl)
+{
+ int result = 0;
+ struct ipa_ep_cfg_mode cfg_mode;
+ u32 apps_to_ipa_hdl = 2;
+ ECM_IPA_LOG_ENTRY();
+ /* Apps to IPA - override the configuration made by IPA driver
+ * in order to allow data path on older platforms*/
+ memset(&cfg_mode, 0 , sizeof(cfg_mode));
+ cfg_mode.mode = IPA_DMA;
+ cfg_mode.dst = IPA_CLIENT_USB_CONS;
+ result = ipa_cfg_ep_mode(apps_to_ipa_hdl, &cfg_mode);
+ if (result) {
+ ECM_IPA_ERROR("failed to configure Apps to IPA\n");
+ goto out;
+ }
+ memset(&cfg_mode, 0 , sizeof(cfg_mode));
+ cfg_mode.mode = IPA_DMA;
+ cfg_mode.dst = IPA_CLIENT_A5_LAN_WAN_CONS;
+ result = ipa_cfg_ep_mode(usb_to_ipa_hdl, &cfg_mode);
+ if (result) {
+ ECM_IPA_ERROR("failed to configure USB to IPA\n");
+ goto out;
+ }
+ ECM_IPA_DEBUG("end-point registers successfully configured\n");
+out:
+ ECM_IPA_LOG_EXIT();
+ return result;
+}
+
+static void ecm_ipa_dump_buff(u8 *buff, u32 byte_size)
+{
+ int i;
+ ECM_IPA_DEBUG("ofst(hex), addr(hex), data(hex), value(char):\n");
+ for (i = 0 ; i < byte_size; i += 4) {
+ ECM_IPA_DEBUG("%2x %p %02x %02x %02x %02x | %c %c %c %c\n",
+ i, &buff[i],
+ buff[i], buff[i+1], buff[i+2], buff[i+3],
+ buff[i], buff[i+1], buff[i+2], buff[i+3]);
+ }
+}
+
+/**
+ * sk_buff_print() - detailed sk_buff printouts
+ * @skb: the socket buff
+ */
+void sk_buff_print(struct sk_buff *skb)
+{
+ ECM_IPA_DEBUG("called by: %s\n", current->comm);
+ ECM_IPA_DEBUG("skb->next=0x%p, skb->prev=0x%p, skb->sk=0x%p\n",
+ skb->next, skb->prev, skb->sk);
+ ECM_IPA_DEBUG("skb->len=0x%x, skb->data_len=0x%x protocol=0x%04x\n",
+ skb->len, skb->data_len, skb->protocol);
+ ECM_IPA_DEBUG("skb->mac_len=0x%x, skb->hdr_len=0x%x, skb->csum=%x\n",
+ skb->mac_len, skb->hdr_len, skb->csum);
+
+ ECM_IPA_DEBUG("mac_header = 0x%p\n", skb_mac_header(skb));
+ ECM_IPA_DEBUG("network_header = 0x%p\n", skb_network_header(skb));
+ ECM_IPA_DEBUG("transport_header=0x%p\n", skb_transport_header(skb));
+
+ ECM_IPA_DEBUG("skb->head=0x%p\n", skb->head);
+ ECM_IPA_DEBUG("skb->data=0x%p\n", skb->data);
+ ECM_IPA_DEBUG("tail=0x%p\n", skb_tail_pointer(skb));
+ ECM_IPA_DEBUG("end =0x%p\n", skb_end_pointer(skb));
+ ECM_IPA_DEBUG("skb->truesize=0x%x (buffer size)\n",
+ skb->truesize);
+ ecm_ipa_dump_buff(skb->data, skb->len);
+}
+
+/**
+ * ecm_ipa_set_device_ethernet_addr() - set device etherenet address
+ * @dev_ethaddr: device etherenet address
+ *
+ * Returns 0 for success, negative otherwise
+ */
+int ecm_ipa_set_device_ethernet_addr(u8 *dev_ethaddr, u8 device_ethaddr[])
+{
+ if (!is_valid_ether_addr(device_ethaddr))
+ return -EINVAL;
+ memcpy(dev_ethaddr, device_ethaddr, ETH_ALEN);
+ ECM_IPA_DEBUG("device ethernet address: %pM\n", dev_ethaddr);
+ return 0;
+}
+
+/**
+ * ecm_ipa_init_module() - module initialization
+ *
+ */
+static int ecm_ipa_init_module(void)
+{
+ ECM_IPA_LOG_ENTRY();
+ ECM_IPA_LOG_EXIT();
+ return 0;
+}
+
+/**
+ * ecm_ipa_cleanup_module() - module cleanup
+ *
+ */
+static void ecm_ipa_cleanup_module(void)
+{
+ ECM_IPA_LOG_ENTRY();
+ ECM_IPA_LOG_EXIT();
+ return;
+}
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("ECM IPA network interface");
+
+late_initcall(ecm_ipa_init_module);
+module_exit(ecm_ipa_cleanup_module);
diff --git a/drivers/net/wireless/wcnss/wcnss_vreg.c b/drivers/net/wireless/wcnss/wcnss_vreg.c
index 025410a..6a315d2 100644
--- a/drivers/net/wireless/wcnss/wcnss_vreg.c
+++ b/drivers/net/wireless/wcnss/wcnss_vreg.c
@@ -156,11 +156,16 @@
goto fail;
}
- pr_debug("wcnss: Indicate NV bin download\n");
- spare_reg = msm_wcnss_base + spare_offset;
- reg = readl_relaxed(spare_reg);
- reg |= NVBIN_DLND_BIT;
- writel_relaxed(reg, spare_reg);
+ /* power on thru SSR should not set NV bit,
+ * during SSR, NV bin is downloaded by WLAN driver
+ */
+ if (!wcnss_cold_boot_done()) {
+ pr_debug("wcnss: Indicate NV bin download\n");
+ spare_reg = msm_wcnss_base + spare_offset;
+ reg = readl_relaxed(spare_reg);
+ reg |= NVBIN_DLND_BIT;
+ writel_relaxed(reg, spare_reg);
+ }
pmu_conf_reg = msm_wcnss_base + pmu_offset;
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index 439b1f8..91ecad7 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -157,6 +157,7 @@
const struct dev_pm_ops *pm_ops;
int triggered;
int smd_channel_ready;
+ int cold_boot_done;
smd_channel_t *smd_ch;
unsigned char wcnss_version[WCNSS_VERSION_LEN];
unsigned int serial_number;
@@ -727,6 +728,16 @@
}
EXPORT_SYMBOL(wcnss_hardware_type);
+int wcnss_cold_boot_done(void)
+{
+ if (penv)
+ return penv->cold_boot_done;
+ else
+ return -ENODEV;
+}
+EXPORT_SYMBOL(wcnss_cold_boot_done);
+
+
static int wcnss_smd_tx(void *data, int len)
{
int ret = 0;
@@ -1062,6 +1073,7 @@
goto fail_ioremap;
}
}
+ penv->cold_boot_done = 1;
return 0;
diff --git a/drivers/platform/msm/Kconfig b/drivers/platform/msm/Kconfig
index f4dff66..76e3175 100644
--- a/drivers/platform/msm/Kconfig
+++ b/drivers/platform/msm/Kconfig
@@ -101,4 +101,14 @@
This driver gets the Q6 out of power collapsed state and
exposes ioctl control to read avtimer tick.
+config SSM
+ tristate "Qualcomm Secure Service Module"
+ depends on QSEECOM
+ depends on MSM_SMD
+ help
+ Provides an interface for OEM driver to communicate with Trustzone
+ and modem for key exchange and mode change.
+ This driver uses Secure Channel Manager interface for trustzone
+ communication and communicates with modem over SMD channel.
+
endmenu
diff --git a/drivers/platform/msm/Makefile b/drivers/platform/msm/Makefile
index a679fb9..289ece9 100644
--- a/drivers/platform/msm/Makefile
+++ b/drivers/platform/msm/Makefile
@@ -10,3 +10,4 @@
obj-$(CONFIG_QPNP_VIBRATOR) += qpnp-vibrator.o
obj-$(CONFIG_QPNP_CLKDIV) += qpnp-clkdiv.o
obj-$(CONFIG_MSM_AVTIMER) += avtimer.o
+obj-$(CONFIG_SSM) += ssm.o
diff --git a/drivers/platform/msm/ipa/Makefile b/drivers/platform/msm/ipa/Makefile
index c541eb7..a25c799 100644
--- a/drivers/platform/msm/ipa/Makefile
+++ b/drivers/platform/msm/ipa/Makefile
@@ -1,3 +1,4 @@
obj-$(CONFIG_IPA) += ipat.o
ipat-y := ipa.o ipa_debugfs.o ipa_hdr.o ipa_flt.o ipa_rt.o ipa_dp.o ipa_client.o \
- ipa_utils.o ipa_nat.o rmnet_bridge.o a2_service.o ipa_bridge.o ipa_intf.o
+ ipa_utils.o ipa_nat.o rmnet_bridge.o a2_service.o ipa_bridge.o ipa_intf.o \
+ ipa_rm.o ipa_rm_dependency_graph.o ipa_rm_peers_list.o ipa_rm_resource.o ipa_rm_inactivity_timer.o
diff --git a/drivers/platform/msm/ipa/ipa.c b/drivers/platform/msm/ipa/ipa.c
index 7690b21..ccf5f96 100644
--- a/drivers/platform/msm/ipa/ipa.c
+++ b/drivers/platform/msm/ipa/ipa.c
@@ -26,6 +26,7 @@
#include <mach/msm_bus.h>
#include <mach/msm_bus_board.h>
#include "ipa_i.h"
+#include "ipa_rm_i.h"
#define IPA_SUMMING_THRESHOLD (0x10)
#define IPA_PIPE_MEM_START_OFST (0x0)
@@ -1528,6 +1529,7 @@
* - Create empty routing table in system memory(no committing)
* - Initialize pipes memory pool with ipa_pipe_mem_init for supported platforms
* - Create a char-device for IPA
+* - Initialize IPA RM (resource manager)
*/
static int ipa_init(const struct ipa_plat_drv_res *resource_p)
{
@@ -1870,10 +1872,20 @@
if (ipa_ctx->ipa_hw_mode == IPA_HW_MODE_NORMAL)
ipa_disable_clks();
+ /* Initialize IPA RM (resource manager) */
+ result = ipa_rm_initialize();
+ if (result) {
+ IPAERR(":cdev_add err=%d\n", -result);
+ result = -ENODEV;
+ goto fail_ipa_rm_init;
+ }
+
IPADBG(":IPA driver init OK.\n");
return 0;
+fail_ipa_rm_init:
+ cdev_del(&ipa_ctx->cdev);
fail_cdev_add:
device_destroy(ipa_ctx->class, ipa_ctx->dev_num);
fail_device_create:
diff --git a/drivers/platform/msm/ipa/ipa_rm.c b/drivers/platform/msm/ipa/ipa_rm.c
new file mode 100644
index 0000000..99b19cc
--- /dev/null
+++ b/drivers/platform/msm/ipa/ipa_rm.c
@@ -0,0 +1,374 @@
+/* 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/slab.h>
+#include <linux/workqueue.h>
+#include <mach/ipa.h>
+#include "ipa_i.h"
+#include "ipa_rm_dependency_graph.h"
+#include "ipa_rm_i.h"
+#include "ipa_rm_resource.h"
+
+struct ipa_rm_context_type {
+ struct ipa_rm_dep_graph *dep_graph;
+ struct workqueue_struct *ipa_rm_wq;
+};
+static struct ipa_rm_context_type *ipa_rm_ctx;
+
+/**
+ * ipa_rm_create_resource() - create resource
+ * @create_params: [in] parameters needed
+ * for resource initialization
+ *
+ * Returns: 0 on success, negative on failure
+ *
+ * This function is called by IPA RM client to initialize client's resources.
+ * This API should be called before any other IPA RM API
+ * on given resource name.
+ *
+ */
+int ipa_rm_create_resource(struct ipa_rm_create_params *create_params)
+{
+ struct ipa_rm_resource *resource;
+ int result;
+
+ if (!create_params) {
+ result = -EINVAL;
+ goto bail;
+ }
+ if (ipa_rm_dep_graph_get_resource(ipa_rm_ctx->dep_graph,
+ create_params->name,
+ &resource) == 0) {
+ result = -EPERM;
+ goto bail;
+ }
+ result = ipa_rm_resource_create(create_params,
+ &resource);
+ if (result)
+ goto bail;
+ result = ipa_rm_dep_graph_add(ipa_rm_ctx->dep_graph, resource);
+ if (result)
+ ipa_rm_resource_delete(resource);
+bail:
+ return result;
+}
+EXPORT_SYMBOL(ipa_rm_create_resource);
+
+/**
+ * ipa_rm_add_dependency() - create dependency
+ * between 2 resources
+ * @resource_name: name of dependent resource
+ * @depends_on_name: name of its dependency
+ *
+ * Returns: 0 on success, negative on failure
+ *
+ * Side effects: IPA_RM_RESORCE_GRANTED could be generated
+ * in case client registered with IPA RM
+ */
+int ipa_rm_add_dependency(enum ipa_rm_resource_name resource_name,
+ enum ipa_rm_resource_name depends_on_name)
+{
+ return ipa_rm_dep_graph_add_dependency(
+ ipa_rm_ctx->dep_graph,
+ resource_name,
+ depends_on_name);
+}
+EXPORT_SYMBOL(ipa_rm_add_dependency);
+
+/**
+ * ipa_rm_delete_dependency() - create dependency
+ * between 2 resources
+ * @resource_name: name of dependent resource
+ * @depends_on_name: name of its dependency
+ *
+ * Returns: 0 on success, negative on failure
+ *
+ * Side effects: IPA_RM_RESORCE_GRANTED could be generated
+ * in case client registered with IPA RM
+ */
+int ipa_rm_delete_dependency(enum ipa_rm_resource_name resource_name,
+ enum ipa_rm_resource_name depends_on_name)
+{
+ return ipa_rm_dep_graph_delete_dependency(
+ ipa_rm_ctx->dep_graph,
+ resource_name,
+ depends_on_name);
+}
+EXPORT_SYMBOL(ipa_rm_delete_dependency);
+
+/**
+ * ipa_rm_request_resource() - request resource
+ * @resource_name: [in] name of the requested resource
+ *
+ * Returns: 0 on success, negative on failure
+ *
+ * All registered callbacks are called with IPA_RM_RESOURCE_GRANTED
+ * on successful completion of this operation.
+ */
+int ipa_rm_request_resource(enum ipa_rm_resource_name resource_name)
+{
+ struct ipa_rm_resource *resource;
+ int result;
+ IPADBG("IPA RM ::ipa_rm_request_resource ENTER\n");
+
+ if (!IPA_RM_RESORCE_IS_PROD(resource_name)) {
+ result = -EINVAL;
+ goto bail;
+ }
+ if (ipa_rm_dep_graph_get_resource(ipa_rm_ctx->dep_graph,
+ resource_name,
+ &resource) != 0) {
+ result = -EPERM;
+ goto bail;
+ }
+ result = ipa_rm_resource_producer_request(
+ (struct ipa_rm_resource_prod *)resource);
+
+bail:
+ IPADBG("IPA RM ::ipa_rm_request_resource EXIT [%d]\n", result);
+
+ return result;
+}
+EXPORT_SYMBOL(ipa_rm_request_resource);
+
+/**
+ * ipa_rm_release_resource() - release resource
+ * @resource_name: [in] name of the requested resource
+ *
+ * Returns: 0 on success, negative on failure
+ *
+ * All registered callbacks are called with IPA_RM_RESOURCE_RELEASED
+ * on successful completion of this operation.
+ */
+int ipa_rm_release_resource(enum ipa_rm_resource_name resource_name)
+{
+ struct ipa_rm_resource *resource;
+ int result;
+ IPADBG("IPA RM ::ipa_rm_release_resource ENTER\n");
+
+ if (!IPA_RM_RESORCE_IS_PROD(resource_name)) {
+ result = -EINVAL;
+ goto bail;
+ }
+ if (ipa_rm_dep_graph_get_resource(ipa_rm_ctx->dep_graph,
+ resource_name,
+ &resource) != 0) {
+ result = -EPERM;
+ goto bail;
+ }
+ result = ipa_rm_resource_producer_release(
+ (struct ipa_rm_resource_prod *)resource);
+
+bail:
+ IPADBG("IPA RM ::ipa_rm_release_resource EXIT [%d]\n", result);
+ return result;
+}
+EXPORT_SYMBOL(ipa_rm_release_resource);
+
+/**
+ * ipa_rm_register() - register for event
+ * @resource_name: resource name
+ * @reg_params: [in] registration parameters
+ *
+ * Returns: 0 on success, negative on failure
+ *
+ * Registration parameters provided here should be the same
+ * as provided later in ipa_rm_deregister() call.
+ */
+int ipa_rm_register(enum ipa_rm_resource_name resource_name,
+ struct ipa_rm_register_params *reg_params)
+{
+ int result;
+ struct ipa_rm_resource *resource;
+ if (!IPA_RM_RESORCE_IS_PROD(resource_name)) {
+ result = -EINVAL;
+ goto bail;
+ }
+ if (ipa_rm_dep_graph_get_resource(ipa_rm_ctx->dep_graph,
+ resource_name,
+ &resource) != 0) {
+ result = -EPERM;
+ goto bail;
+ }
+ result = ipa_rm_resource_producer_register(
+ (struct ipa_rm_resource_prod *)resource,
+ reg_params);
+bail:
+ return result;
+}
+EXPORT_SYMBOL(ipa_rm_register);
+
+/**
+ * ipa_rm_deregister() - cancel the registration
+ * @resource_name: resource name
+ * @reg_params: [in] registration parameters
+ *
+ * Returns: 0 on success, negative on failure
+ *
+ * Registration parameters provided here should be the same
+ * as provided in ipa_rm_register() call.
+ */
+int ipa_rm_deregister(enum ipa_rm_resource_name resource_name,
+ struct ipa_rm_register_params *reg_params)
+{
+ int result;
+ struct ipa_rm_resource *resource;
+ if (!IPA_RM_RESORCE_IS_PROD(resource_name)) {
+ result = -EINVAL;
+ goto bail;
+ }
+ if (ipa_rm_dep_graph_get_resource(ipa_rm_ctx->dep_graph,
+ resource_name,
+ &resource) != 0) {
+ result = -EPERM;
+ goto bail;
+ }
+ result = ipa_rm_resource_producer_deregister(
+ (struct ipa_rm_resource_prod *)resource,
+ reg_params);
+bail:
+ return result;
+}
+EXPORT_SYMBOL(ipa_rm_deregister);
+
+/**
+ * ipa_rm_notify_completion() -
+ * consumer driver notification for
+ * request_resource / release_resource operations
+ * completion
+ * @event: notified event
+ * @resource_name: resource name
+ *
+ * Returns: 0 on success, negative on failure
+ */
+int ipa_rm_notify_completion(enum ipa_rm_event event,
+ enum ipa_rm_resource_name resource_name)
+{
+ int result;
+ if (!IPA_RM_RESORCE_IS_CONS(resource_name)) {
+ result = -EINVAL;
+ goto bail;
+ }
+ ipa_rm_wq_send_cmd(IPA_RM_WQ_RESOURCE_CB,
+ resource_name,
+ event);
+ result = 0;
+bail:
+ return result;
+}
+EXPORT_SYMBOL(ipa_rm_notify_completion);
+
+static void ipa_rm_wq_handler(struct work_struct *work)
+{
+ struct ipa_rm_resource *resource;
+ struct ipa_rm_wq_work_type *ipa_rm_work =
+ container_of(work,
+ struct ipa_rm_wq_work_type,
+ work);
+ switch (ipa_rm_work->wq_cmd) {
+ case IPA_RM_WQ_NOTIFY_PROD:
+ if (!IPA_RM_RESORCE_IS_PROD(ipa_rm_work->resource_name))
+ return;
+ if (ipa_rm_dep_graph_get_resource(ipa_rm_ctx->dep_graph,
+ ipa_rm_work->resource_name,
+ &resource) != 0)
+ return;
+ ipa_rm_resource_producer_notify_clients(
+ (struct ipa_rm_resource_prod *)resource,
+ ipa_rm_work->event);
+
+ break;
+ case IPA_RM_WQ_NOTIFY_CONS:
+ break;
+ case IPA_RM_WQ_RESOURCE_CB:
+ if (ipa_rm_dep_graph_get_resource(ipa_rm_ctx->dep_graph,
+ ipa_rm_work->resource_name,
+ &resource) != 0)
+ return;
+ ipa_rm_resource_consumer_handle_cb(
+ (struct ipa_rm_resource_cons *)resource,
+ ipa_rm_work->event);
+ break;
+ default:
+ break;
+ }
+
+ kfree((void *) work);
+}
+
+/**
+ * ipa_rm_wq_send_cmd() - send a command for deferred work
+ * @wq_cmd: command that should be executed
+ * @resource_name: resource on which command should be executed
+ *
+ * Returns: 0 on success, negative otherwise
+ */
+int ipa_rm_wq_send_cmd(enum ipa_rm_wq_cmd wq_cmd,
+ enum ipa_rm_resource_name resource_name,
+ enum ipa_rm_event event)
+{
+ int result = -ENOMEM;
+ struct ipa_rm_wq_work_type *work = kzalloc(sizeof(*work), GFP_KERNEL);
+ if (work) {
+ INIT_WORK((struct work_struct *)work, ipa_rm_wq_handler);
+ work->wq_cmd = wq_cmd;
+ work->resource_name = resource_name;
+ work->event = event;
+ result = queue_work(ipa_rm_ctx->ipa_rm_wq,
+ (struct work_struct *)work);
+ }
+ return result;
+}
+
+/**
+ * ipa_rm_initialize() - initialize IPA RM component
+ *
+ * Returns: 0 on success, negative otherwise
+ */
+int ipa_rm_initialize(void)
+{
+ int result;
+
+ ipa_rm_ctx = kzalloc(sizeof(*ipa_rm_ctx), GFP_KERNEL);
+ if (!ipa_rm_ctx) {
+ result = -ENOMEM;
+ goto bail;
+ }
+ ipa_rm_ctx->ipa_rm_wq = create_singlethread_workqueue("ipa_rm_wq");
+ if (!ipa_rm_ctx->ipa_rm_wq) {
+ result = -ENOMEM;
+ goto create_wq_fail;
+ }
+ result = ipa_rm_dep_graph_create(&(ipa_rm_ctx->dep_graph));
+ if (result)
+ goto graph_alloc_fail;
+ IPADBG("IPA RM ipa_rm_initialize SUCCESS\n");
+ return 0;
+
+graph_alloc_fail:
+ destroy_workqueue(ipa_rm_ctx->ipa_rm_wq);
+create_wq_fail:
+ kfree(ipa_rm_ctx);
+bail:
+ return result;
+}
+
+/**
+ * ipa_rm_exit() - free all IPA RM resources
+ */
+void ipa_rm_exit(void)
+{
+ ipa_rm_dep_graph_delete(ipa_rm_ctx->dep_graph);
+ destroy_workqueue(ipa_rm_ctx->ipa_rm_wq);
+ kfree(ipa_rm_ctx);
+ ipa_rm_ctx = NULL;
+}
diff --git a/drivers/platform/msm/ipa/ipa_rm_dependency_graph.c b/drivers/platform/msm/ipa/ipa_rm_dependency_graph.c
new file mode 100644
index 0000000..6afab42
--- /dev/null
+++ b/drivers/platform/msm/ipa/ipa_rm_dependency_graph.c
@@ -0,0 +1,208 @@
+/* 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/slab.h>
+#include "ipa_rm_dependency_graph.h"
+#include "ipa_rm_i.h"
+
+static int ipa_rm_dep_get_index(enum ipa_rm_resource_name resource_name)
+{
+ int resource_index = IPA_RM_INDEX_INVALID;
+ if (IPA_RM_RESORCE_IS_PROD(resource_name))
+ resource_index = ipa_rm_prod_index(resource_name);
+ else if (IPA_RM_RESORCE_IS_CONS(resource_name))
+ resource_index = ipa_rm_cons_index(resource_name);
+
+ return resource_index;
+}
+
+/**
+ * ipa_rm_dep_graph_create() - creates graph
+ * @dep_graph: [out] created dependency graph
+ *
+ * Returns: dependency graph on success, NULL on failure
+ */
+int ipa_rm_dep_graph_create(struct ipa_rm_dep_graph **dep_graph)
+{
+ int result = 0;
+ *dep_graph = kzalloc(sizeof(**dep_graph), GFP_KERNEL);
+ if (!*dep_graph) {
+ result = -ENOMEM;
+ goto bail;
+ }
+ rwlock_init(&((*dep_graph)->lock));
+bail:
+ return result;
+}
+
+/**
+ * ipa_rm_dep_graph_delete() - destroyes the graph
+ * @graph: [in] dependency graph
+ *
+ * Frees all resources.
+ */
+void ipa_rm_dep_graph_delete(struct ipa_rm_dep_graph *graph)
+{
+ int resource_index;
+ if (!graph)
+ return;
+ write_lock(&graph->lock);
+ for (resource_index = 0;
+ resource_index < IPA_RM_RESOURCE_MAX;
+ resource_index++)
+ kfree(graph->resource_table[resource_index]);
+ write_unlock(&graph->lock);
+ memset(graph->resource_table, 0, sizeof(graph->resource_table));
+}
+
+/**
+ * ipa_rm_dep_graph_get_resource() - provides a resource by name
+ * @graph: [in] dependency graph
+ * @name: [in] name of the resource
+ * @resource: [out] resource in case of success
+ *
+ * Returns: 0 on success, negative on failure
+ */
+int ipa_rm_dep_graph_get_resource(
+ struct ipa_rm_dep_graph *graph,
+ enum ipa_rm_resource_name resource_name,
+ struct ipa_rm_resource **resource)
+{
+ int result;
+ int resource_index;
+ if (!graph) {
+ result = -EINVAL;
+ goto bail;
+ }
+ resource_index = ipa_rm_dep_get_index(resource_name);
+ if (resource_index == IPA_RM_INDEX_INVALID) {
+ result = -EINVAL;
+ goto bail;
+ }
+ read_lock(&graph->lock);
+ *resource = graph->resource_table[resource_index];
+ read_unlock(&graph->lock);
+ if (!*resource) {
+ result = -EINVAL;
+ goto bail;
+ }
+ result = 0;
+bail:
+ return result;
+}
+
+/**
+ * ipa_rm_dep_graph_add() - adds resource to graph
+ * @graph: [in] dependency graph
+ * @resource: [in] resource to add
+ *
+ * Returns: 0 on success, negative on failure
+ */
+int ipa_rm_dep_graph_add(struct ipa_rm_dep_graph *graph,
+ struct ipa_rm_resource *resource)
+{
+ int result = 0;
+ int resource_index;
+ if (!graph || !resource) {
+ result = -EINVAL;
+ goto bail;
+ }
+ resource_index = ipa_rm_dep_get_index(resource->name);
+ if (resource_index == IPA_RM_INDEX_INVALID) {
+ result = -EINVAL;
+ goto bail;
+ }
+ write_lock(&graph->lock);
+ graph->resource_table[resource_index] = resource;
+ write_unlock(&graph->lock);
+bail:
+ return result;
+}
+
+/**
+ * ipa_rm_dep_graph_add_dependency() - adds dependency between
+ * two nodes in graph
+ * @graph: [in] dependency graph
+ * @resource_name: [in] resource to add
+ * @depends_on_name: [in] resource to add
+ *
+ * Returns: 0 on success, negative on failure
+ */
+int ipa_rm_dep_graph_add_dependency(struct ipa_rm_dep_graph *graph,
+ enum ipa_rm_resource_name resource_name,
+ enum ipa_rm_resource_name depends_on_name)
+{
+ struct ipa_rm_resource *dependant = NULL;
+ struct ipa_rm_resource *dependency = NULL;
+ int result;
+ if (!graph ||
+ !IPA_RM_RESORCE_IS_PROD(resource_name) ||
+ !IPA_RM_RESORCE_IS_CONS(depends_on_name)) {
+ result = -EINVAL;
+ goto bail;
+ }
+ if (ipa_rm_dep_graph_get_resource(graph,
+ resource_name,
+ &dependant)) {
+ result = -EINVAL;
+ goto bail;
+ }
+ if (ipa_rm_dep_graph_get_resource(graph,
+ depends_on_name,
+ &dependency)) {
+ result = -EINVAL;
+ goto bail;
+ }
+ result = ipa_rm_resource_add_dependency(dependant, dependency);
+bail:
+ return result;
+}
+
+/**
+ * ipa_rm_dep_graph_delete_dependency() - deleted dependency between
+ * two nodes in graph
+ * @graph: [in] dependency graph
+ * @resource_name: [in] resource to delete
+ * @depends_on_name: [in] resource to delete
+ *
+ * Returns: 0 on success, negative on failure
+ *
+ */
+int ipa_rm_dep_graph_delete_dependency(struct ipa_rm_dep_graph *graph,
+ enum ipa_rm_resource_name resource_name,
+ enum ipa_rm_resource_name depends_on_name)
+{
+ struct ipa_rm_resource *dependant = NULL;
+ struct ipa_rm_resource *dependency = NULL;
+ int result;
+ if (!graph ||
+ !IPA_RM_RESORCE_IS_PROD(resource_name) ||
+ !IPA_RM_RESORCE_IS_CONS(depends_on_name)) {
+ result = -EINVAL;
+ goto bail;
+ }
+ if (ipa_rm_dep_graph_get_resource(graph,
+ resource_name,
+ &dependant)) {
+ result = -EINVAL;
+ goto bail;
+ }
+ if (ipa_rm_dep_graph_get_resource(graph,
+ depends_on_name,
+ &dependency)) {
+ result = -EINVAL;
+ goto bail;
+ }
+ result = ipa_rm_resource_delete_dependency(dependant, dependency);
+bail:
+ return result;
+}
diff --git a/drivers/platform/msm/ipa/ipa_rm_dependency_graph.h b/drivers/platform/msm/ipa/ipa_rm_dependency_graph.h
new file mode 100644
index 0000000..19d9461
--- /dev/null
+++ b/drivers/platform/msm/ipa/ipa_rm_dependency_graph.h
@@ -0,0 +1,45 @@
+/* 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 _IPA_RM_DEPENDENCY_GRAPH_H_
+#define _IPA_RM_DEPENDENCY_GRAPH_H_
+
+#include <linux/list.h>
+#include <mach/ipa.h>
+#include "ipa_rm_resource.h"
+
+struct ipa_rm_dep_graph {
+ struct ipa_rm_resource *resource_table[IPA_RM_RESOURCE_MAX];
+ rwlock_t lock;
+};
+
+int ipa_rm_dep_graph_get_resource(
+ struct ipa_rm_dep_graph *graph,
+ enum ipa_rm_resource_name name,
+ struct ipa_rm_resource **resource);
+
+int ipa_rm_dep_graph_create(struct ipa_rm_dep_graph **dep_graph);
+
+void ipa_rm_dep_graph_delete(struct ipa_rm_dep_graph *graph);
+
+int ipa_rm_dep_graph_add(struct ipa_rm_dep_graph *graph,
+ struct ipa_rm_resource *resource);
+
+int ipa_rm_dep_graph_add_dependency(struct ipa_rm_dep_graph *graph,
+ enum ipa_rm_resource_name resource_name,
+ enum ipa_rm_resource_name depends_on_name);
+
+int ipa_rm_dep_graph_delete_dependency(struct ipa_rm_dep_graph *graph,
+ enum ipa_rm_resource_name resource_name,
+ enum ipa_rm_resource_name depends_on_name);
+
+#endif /* _IPA_RM_DEPENDENCY_GRAPH_H_ */
diff --git a/drivers/platform/msm/ipa/ipa_rm_i.h b/drivers/platform/msm/ipa/ipa_rm_i.h
new file mode 100644
index 0000000..141a442
--- /dev/null
+++ b/drivers/platform/msm/ipa/ipa_rm_i.h
@@ -0,0 +1,64 @@
+/* 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 _IPA_RM_I_H_
+#define _IPA_RM_I_H_
+
+#include <linux/workqueue.h>
+#include <mach/ipa.h>
+
+#define IPA_RM_RESOURCE_CONS_MAX \
+ (IPA_RM_RESOURCE_MAX - IPA_RM_RESOURCE_PROD_MAX)
+#define IPA_RM_RESORCE_IS_PROD(x) \
+ (x >= IPA_RM_RESOURCE_PROD && x < IPA_RM_RESOURCE_PROD_MAX)
+#define IPA_RM_RESORCE_IS_CONS(x) \
+ (x >= IPA_RM_RESOURCE_PROD_MAX && x < IPA_RM_RESOURCE_MAX)
+#define IPA_RM_INDEX_INVALID (-1)
+
+int ipa_rm_prod_index(enum ipa_rm_resource_name resource_name);
+int ipa_rm_cons_index(enum ipa_rm_resource_name resource_name);
+
+/**
+ * enum ipa_rm_wq_cmd - workqueue commands
+ */
+enum ipa_rm_wq_cmd {
+ IPA_RM_WQ_NOTIFY_PROD,
+ IPA_RM_WQ_NOTIFY_CONS,
+ IPA_RM_WQ_RESOURCE_CB
+};
+
+/**
+ * struct ipa_rm_wq_work_type - IPA RM worqueue specific
+ * work type
+ * @work: work struct
+ * @wq_cmd: command that should be processed in workqueue context
+ * @resource_name: name of the resource on which this work
+ * should be done
+ * @dep_graph: data structure to search for resource if exists
+ * @event: event to notify
+ */
+struct ipa_rm_wq_work_type {
+ struct work_struct work;
+ enum ipa_rm_wq_cmd wq_cmd;
+ enum ipa_rm_resource_name resource_name;
+ enum ipa_rm_event event;
+};
+
+int ipa_rm_wq_send_cmd(enum ipa_rm_wq_cmd wq_cmd,
+ enum ipa_rm_resource_name resource_name,
+ enum ipa_rm_event event);
+
+int ipa_rm_initialize(void);
+
+void ipa_rm_exit(void);
+
+#endif /* _IPA_RM_I_H_ */
diff --git a/drivers/platform/msm/ipa/ipa_rm_inactivity_timer.c b/drivers/platform/msm/ipa/ipa_rm_inactivity_timer.c
new file mode 100644
index 0000000..2a3b8d3
--- /dev/null
+++ b/drivers/platform/msm/ipa/ipa_rm_inactivity_timer.c
@@ -0,0 +1,249 @@
+/* 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/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/timer.h>
+#include <linux/unistd.h>
+#include <linux/workqueue.h>
+#include <mach/ipa.h>
+#include "ipa_i.h"
+
+/**
+ * struct ipa_rm_it_private - IPA RM Inactivity Timer private
+ * data
+ * @initied: indicates if instance was initialized
+ * @lock - spinlock for mutual exclusion
+ * @resource_name - resource name
+ * @work: delayed work object for running delayed releas
+ * function
+ * @release_in_prog: boolean flag indicates if release resource
+ * is scheduled for happen in the future.
+ * @jiffies: number of jiffies for timeout
+ *
+ * WWAN private - holds all relevant info about WWAN driver
+ */
+struct ipa_rm_it_private {
+ bool initied;
+ enum ipa_rm_resource_name resource_name;
+ spinlock_t lock;
+ struct delayed_work work;
+ bool release_in_prog;
+ unsigned long jiffies;
+};
+
+static struct ipa_rm_it_private ipa_rm_it_handles[IPA_RM_RESOURCE_MAX];
+
+/**
+ * ipa_rm_inactivity_timer_func() - called when timer expired in
+ * the context of the shared workqueue. Checks internally is
+ * release_in_prog flag is set and calls to
+ * ipa_rm_release_resource(). release_in_prog is cleared when
+ * calling to ipa_rm_inactivity_timer_request_resource(). In
+ * this situation this function shall not call to
+ * ipa_rm_release_resource() since the resource needs to remain
+ * up
+ *
+ * @work: work object provided by the work queue
+ *
+ * Return codes:
+ * None
+ */
+static void ipa_rm_inactivity_timer_func(struct work_struct *work)
+{
+
+ struct ipa_rm_it_private *me = container_of(to_delayed_work(work),
+ struct ipa_rm_it_private,
+ work);
+ unsigned long flags;
+
+ IPADBG("%s: timer expired for resource %d!\n", __func__,
+ me->resource_name);
+
+ /* check that release still need to be performed */
+ spin_lock_irqsave(
+ &ipa_rm_it_handles[me->resource_name].lock, flags);
+ if (ipa_rm_it_handles[me->resource_name].release_in_prog) {
+ IPADBG("%s: calling release_resource on resource %d!\n",
+ __func__, me->resource_name);
+ ipa_rm_release_resource(me->resource_name);
+ ipa_rm_it_handles[me->resource_name].release_in_prog = false;
+ }
+ spin_unlock_irqrestore(
+ &ipa_rm_it_handles[me->resource_name].lock, flags);
+}
+
+/**
+* ipa_rm_inactivity_timer_init() - Init function for IPA RM
+* inactivity timer. This function shall be called prior calling
+* any other API of IPA RM inactivity timer.
+*
+* @resource_name: Resource name. @see ipa_rm.h
+* @msecs: time in miliseccond, that IPA RM inactivity timer
+* shall wait prior calling to ipa_rm_release_resource().
+*
+* Return codes:
+* 0: success
+* -EINVAL: invalid parameters
+*/
+int ipa_rm_inactivity_timer_init(enum ipa_rm_resource_name resource_name,
+ unsigned long msecs)
+{
+ IPADBG("%s: resource %d\n", __func__, resource_name);
+
+ if (resource_name < 0 ||
+ resource_name >= IPA_RM_RESOURCE_MAX) {
+ IPAERR("%s: Invalid parameter\n", __func__);
+ return -EINVAL;
+ }
+
+ if (ipa_rm_it_handles[resource_name].initied) {
+ IPAERR("%s: resource %d already inited\n",
+ __func__, resource_name);
+ return -EINVAL;
+ }
+
+ spin_lock_init(&ipa_rm_it_handles[resource_name].lock);
+ ipa_rm_it_handles[resource_name].resource_name = resource_name;
+ ipa_rm_it_handles[resource_name].jiffies = msecs_to_jiffies(msecs);
+ ipa_rm_it_handles[resource_name].release_in_prog = false;
+
+ INIT_DELAYED_WORK(&ipa_rm_it_handles[resource_name].work,
+ ipa_rm_inactivity_timer_func);
+ ipa_rm_it_handles[resource_name].initied = 1;
+
+ return 0;
+}
+
+/**
+* ipa_rm_inactivity_timer_destroy() - De-Init function for IPA
+* RM inactivity timer.
+*
+* @resource_name: Resource name. @see ipa_rm.h
+*
+* Return codes:
+* 0: success
+* -EINVAL: invalid parameters
+*/
+int ipa_rm_inactivity_timer_destroy(enum ipa_rm_resource_name resource_name)
+{
+ IPADBG("%s: resource %d\n", __func__, resource_name);
+
+ if (resource_name < 0 ||
+ resource_name >= IPA_RM_RESOURCE_MAX) {
+ IPAERR("%s: Invalid parameter\n", __func__);
+ return -EINVAL;
+ }
+
+ if (!ipa_rm_it_handles[resource_name].initied) {
+ IPAERR("%s: resource %d already inited\n",
+ __func__, resource_name);
+ return -EINVAL;
+ }
+
+ memset(&ipa_rm_it_handles[resource_name], 0,
+ sizeof(struct ipa_rm_it_private));
+
+ return 0;
+}
+
+/**
+* ipa_rm_inactivity_timer_request_resource() - Same as
+* ipa_rm_request_resource(), with a difference that calling to
+* this function will also cancel the inactivity timer, if
+* ipa_rm_inactivity_timer_release_resource() was called earlier.
+*
+* @resource_name: Resource name. @see ipa_rm.h
+*
+* Return codes:
+* 0: success
+* -EINVAL: invalid parameters
+*/
+int ipa_rm_inactivity_timer_request_resource(
+ enum ipa_rm_resource_name resource_name)
+{
+ int ret;
+ unsigned long flags;
+ IPADBG("%s: resource %d\n", __func__, resource_name);
+
+ if (resource_name < 0 ||
+ resource_name >= IPA_RM_RESOURCE_MAX) {
+ IPAERR("%s: Invalid parameter\n", __func__);
+ return -EINVAL;
+ }
+
+ if (!ipa_rm_it_handles[resource_name].initied) {
+ IPAERR("%s: Not initialized\n", __func__);
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&ipa_rm_it_handles[resource_name].lock, flags);
+ cancel_delayed_work(&ipa_rm_it_handles[resource_name].work);
+ ipa_rm_it_handles[resource_name].release_in_prog = false;
+ spin_unlock_irqrestore(&ipa_rm_it_handles[resource_name].lock, flags);
+ ret = ipa_rm_request_resource(resource_name);
+ IPADBG("%s: resource %d: returning %d\n", __func__, resource_name, ret);
+ return ret;
+}
+
+/**
+* ipa_rm_inactivity_timer_release_resource() - Sets the
+* inactivity timer to the timeout set by
+* ipa_rm_inactivity_timer_init(). When the timeout expires, IPA
+* RM inactivity timer will call to ipa_rm_release_resource().
+* If a call to ipa_rm_inactivity_timer_request_resource() was
+* made BEFORE the timout has expired, rge timer will be
+* cancelled.
+*
+* @resource_name: Resource name. @see ipa_rm.h
+*
+* Return codes:
+* 0: success
+* -EINVAL: invalid parameters
+*/
+int ipa_rm_inactivity_timer_release_resource(
+ enum ipa_rm_resource_name resource_name)
+{
+ unsigned long flags;
+ IPADBG("%s: resource %d\n", __func__, resource_name);
+
+ if (resource_name < 0 ||
+ resource_name >= IPA_RM_RESOURCE_MAX) {
+ IPAERR("%s: Invalid parameter\n", __func__);
+ return -EINVAL;
+ }
+
+ if (!ipa_rm_it_handles[resource_name].initied) {
+ IPAERR("%s: Not initialized\n", __func__);
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&ipa_rm_it_handles[resource_name].lock, flags);
+ if (ipa_rm_it_handles[resource_name].release_in_prog) {
+ IPADBG("%s: Timer already set, not scheduling again %d\n",
+ __func__, resource_name);
+ spin_unlock_irqrestore(
+ &ipa_rm_it_handles[resource_name].lock, flags);
+ return 0;
+ }
+ ipa_rm_it_handles[resource_name].release_in_prog = true;
+ spin_unlock_irqrestore(&ipa_rm_it_handles[resource_name].lock, flags);
+
+ IPADBG("%s: setting delayed work\n", __func__);
+ schedule_delayed_work(&ipa_rm_it_handles[resource_name].work,
+ ipa_rm_it_handles[resource_name].jiffies);
+
+ return 0;
+}
+
diff --git a/drivers/platform/msm/ipa/ipa_rm_peers_list.c b/drivers/platform/msm/ipa/ipa_rm_peers_list.c
new file mode 100644
index 0000000..55f8239
--- /dev/null
+++ b/drivers/platform/msm/ipa/ipa_rm_peers_list.c
@@ -0,0 +1,247 @@
+/* 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/slab.h>
+#include "ipa_i.h"
+#include "ipa_rm_i.h"
+#include "ipa_rm_resource.h"
+
+/**
+ * ipa_rm_peers_list_get_resource_index() - resource name to index
+ * of this resource in corresponding peers list
+ * @resource_name: [in] resource name
+ *
+ * Returns: resource index mapping, IPA_RM_INDEX_INVALID
+ * in case provided resource name isn't contained in enum
+ * ipa_rm_resource_name.
+ *
+ */
+static int ipa_rm_peers_list_get_resource_index(
+ enum ipa_rm_resource_name resource_name)
+{
+ int resource_index = IPA_RM_INDEX_INVALID;
+ if (IPA_RM_RESORCE_IS_PROD(resource_name))
+ resource_index = ipa_rm_prod_index(resource_name);
+ else if (IPA_RM_RESORCE_IS_CONS(resource_name)) {
+ resource_index = ipa_rm_cons_index(resource_name);
+ if (resource_index != IPA_RM_INDEX_INVALID)
+ resource_index =
+ resource_index - IPA_RM_RESOURCE_PROD_MAX;
+ }
+
+ return resource_index;
+}
+
+static bool ipa_rm_peers_list_check_index(int index,
+ struct ipa_rm_peers_list *peers_list)
+{
+ return !(index > peers_list->max_peers || index < 0);
+}
+
+/**
+ * ipa_rm_peers_list_create() - creates the peers list
+ *
+ * @max_peers: maximum number of peers in new list
+ * @peers_list: [out] newly created peers list
+ *
+ * Returns: 0 in case of SUCCESS, negative otherwise
+ */
+int ipa_rm_peers_list_create(int max_peers,
+ struct ipa_rm_peers_list **peers_list)
+{
+ int result;
+ *peers_list = kzalloc(sizeof(**peers_list), GFP_KERNEL);
+ if (!*peers_list) {
+ result = -ENOMEM;
+ goto bail;
+ }
+ rwlock_init(&(*peers_list)->peers_lock);
+ (*peers_list)->max_peers = max_peers;
+ (*peers_list)->peers = kzalloc((*peers_list)->max_peers *
+ sizeof(struct ipa_rm_resource *), GFP_KERNEL);
+ if (!((*peers_list)->peers)) {
+ result = -ENOMEM;
+ goto list_alloc_fail;
+ }
+ return 0;
+
+list_alloc_fail:
+ kfree(*peers_list);
+bail:
+ return result;
+}
+
+/**
+ * ipa_rm_peers_list_delete() - deletes the peers list
+ *
+ * @peers_list: peers list
+ *
+ */
+void ipa_rm_peers_list_delete(struct ipa_rm_peers_list *peers_list)
+{
+ if (peers_list) {
+ kfree(peers_list->peers);
+ kfree(peers_list);
+ }
+}
+
+/**
+ * ipa_rm_peers_list_remove_peer() - removes peer from the list
+ *
+ * @peers_list: peers list
+ * @resource_name: name of the resource to remove
+ *
+ */
+void ipa_rm_peers_list_remove_peer(
+ struct ipa_rm_peers_list *peers_list,
+ enum ipa_rm_resource_name resource_name)
+{
+ if (!peers_list)
+ return;
+ write_lock(&peers_list->peers_lock);
+ peers_list->peers[ipa_rm_peers_list_get_resource_index(
+ resource_name)] = NULL;
+ peers_list->peers_count--;
+ write_unlock(&peers_list->peers_lock);
+}
+
+/**
+ * ipa_rm_peers_list_add_peer() - adds peer to the list
+ *
+ * @peers_list: peers list
+ * @resource: resource to add
+ *
+ */
+void ipa_rm_peers_list_add_peer(
+ struct ipa_rm_peers_list *peers_list,
+ struct ipa_rm_resource *resource)
+{
+ if (!peers_list || !resource)
+ return;
+ read_lock(&peers_list->peers_lock);
+ peers_list->peers[ipa_rm_peers_list_get_resource_index(
+ resource->name)] =
+ resource;
+ peers_list->peers_count++;
+ read_unlock(&peers_list->peers_lock);
+}
+
+/**
+ * ipa_rm_peers_list_is_empty() - checks
+ * if resource peers list is empty
+ *
+ * @peers_list: peers list
+ *
+ * Returns: true if the list is empty, false otherwise
+ */
+bool ipa_rm_peers_list_is_empty(struct ipa_rm_peers_list *peers_list)
+{
+ bool result = true;
+ if (!peers_list)
+ goto bail;
+ read_lock(&peers_list->peers_lock);
+ if (peers_list->peers_count > 0)
+ result = false;
+ read_unlock(&peers_list->peers_lock);
+bail:
+ return result;
+}
+
+/**
+ * ipa_rm_peers_list_has_last_peer() - checks
+ * if resource peers list has exactly one peer
+ *
+ * @peers_list: peers list
+ *
+ * Returns: true if the list has exactly one peer, false otherwise
+ */
+bool ipa_rm_peers_list_has_last_peer(
+ struct ipa_rm_peers_list *peers_list)
+{
+ bool result = true;
+ if (!peers_list)
+ goto bail;
+ read_lock(&peers_list->peers_lock);
+ if (peers_list->peers_count == 1)
+ result = false;
+ read_unlock(&peers_list->peers_lock);
+bail:
+ return result;
+}
+
+/**
+ * ipa_rm_peers_list_check_dependency() - check dependency
+ * between 2 peer lists
+ * @resource_peers: first peers list
+ * @resource_name: first peers list resource name
+ * @depends_on_peers: second peers list
+ * @depends_on_name: second peers list resource name
+ *
+ * Returns: true if there is dependency, false otherwise
+ *
+ */
+bool ipa_rm_peers_list_check_dependency(
+ struct ipa_rm_peers_list *resource_peers,
+ enum ipa_rm_resource_name resource_name,
+ struct ipa_rm_peers_list *depends_on_peers,
+ enum ipa_rm_resource_name depends_on_name)
+{
+ bool result = false;
+ if (!resource_peers || !depends_on_peers)
+ return result;
+ read_lock(&resource_peers->peers_lock);
+ if (resource_peers->peers[ipa_rm_peers_list_get_resource_index(
+ depends_on_name)] != NULL)
+ result = true;
+ read_unlock(&resource_peers->peers_lock);
+
+ read_lock(&depends_on_peers->peers_lock);
+ if (depends_on_peers->peers[ipa_rm_peers_list_get_resource_index(
+ resource_name)] != NULL)
+ result = true;
+ read_unlock(&depends_on_peers->peers_lock);
+
+ return result;
+}
+
+/**
+ * ipa_rm_peers_list_get_resource() - get resource by
+ * resource index
+ * @resource_index: resource index
+ * @resource_peers: peers list
+ *
+ * Returns: the resource if found, NULL otherwise
+ */
+struct ipa_rm_resource *ipa_rm_peers_list_get_resource(int resource_index,
+ struct ipa_rm_peers_list *resource_peers)
+{
+ struct ipa_rm_resource *result = NULL;
+ if (!ipa_rm_peers_list_check_index(resource_index, resource_peers))
+ goto bail;
+ read_lock(&resource_peers->peers_lock);
+ result = resource_peers->peers[resource_index];
+ read_unlock(&resource_peers->peers_lock);
+bail:
+ return result;
+}
+
+/**
+ * ipa_rm_peers_list_get_size() - get peers list sise
+ *
+ * @peers_list: peers list
+ *
+ * Returns: the size of the peers list
+ */
+int ipa_rm_peers_list_get_size(struct ipa_rm_peers_list *peers_list)
+{
+ return peers_list->max_peers;
+}
diff --git a/drivers/platform/msm/ipa/ipa_rm_peers_list.h b/drivers/platform/msm/ipa/ipa_rm_peers_list.h
new file mode 100644
index 0000000..f8fd1ca
--- /dev/null
+++ b/drivers/platform/msm/ipa/ipa_rm_peers_list.h
@@ -0,0 +1,55 @@
+/* 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 _IPA_RM_PEERS_LIST_H_
+#define _IPA_RM_PEERS_LIST_H_
+
+#include "ipa_rm_resource.h"
+
+/**
+ * struct ipa_rm_peers_list - IPA RM resource peers list
+ * @peers: the list of references to resources dependent on this resource
+ * in case of producer or list of dependencies in case of consumer
+ * @max_peers: maximum number of peers for this resource
+ * @peers_count: actual number of peers for this resource
+ * @peers_lock: RW lock for peers container
+ */
+struct ipa_rm_peers_list {
+ struct ipa_rm_resource **peers;
+ int max_peers;
+ int peers_count;
+ rwlock_t peers_lock;
+};
+
+int ipa_rm_peers_list_create(int max_peers,
+ struct ipa_rm_peers_list **peers_list);
+void ipa_rm_peers_list_delete(struct ipa_rm_peers_list *peers_list);
+void ipa_rm_peers_list_remove_peer(
+ struct ipa_rm_peers_list *peers_list,
+ enum ipa_rm_resource_name resource_name);
+void ipa_rm_peers_list_add_peer(
+ struct ipa_rm_peers_list *peers_list,
+ struct ipa_rm_resource *resource);
+bool ipa_rm_peers_list_check_dependency(
+ struct ipa_rm_peers_list *resource_peers,
+ enum ipa_rm_resource_name resource_name,
+ struct ipa_rm_peers_list *depends_on_peers,
+ enum ipa_rm_resource_name depends_on_name);
+struct ipa_rm_resource *ipa_rm_peers_list_get_resource(int resource_index,
+ struct ipa_rm_peers_list *peers_list);
+int ipa_rm_peers_list_get_size(struct ipa_rm_peers_list *peers_list);
+bool ipa_rm_peers_list_is_empty(struct ipa_rm_peers_list *peers_list);
+bool ipa_rm_peers_list_has_last_peer(
+ struct ipa_rm_peers_list *peers_list);
+
+
+#endif /* _IPA_RM_PEERS_LIST_H_ */
diff --git a/drivers/platform/msm/ipa/ipa_rm_resource.c b/drivers/platform/msm/ipa/ipa_rm_resource.c
new file mode 100644
index 0000000..3ba8e84
--- /dev/null
+++ b/drivers/platform/msm/ipa/ipa_rm_resource.c
@@ -0,0 +1,809 @@
+/* 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/slab.h>
+#include "ipa_i.h"
+#include "ipa_rm_resource.h"
+#include "ipa_rm_i.h"
+
+/**
+ * ipa_rm_dep_prod_index() - producer name to producer index mapping
+ * @resource_name: [in] resource name (should be of producer)
+ *
+ * Returns: resource index mapping, IPA_RM_INDEX_INVALID
+ * in case provided resource name isn't contained
+ * in enum ipa_rm_resource_name or is not of producers.
+ *
+ */
+int ipa_rm_prod_index(enum ipa_rm_resource_name resource_name)
+{
+ int result = resource_name;
+ switch (resource_name) {
+ case IPA_RM_RESOURCE_BRIDGE_PROD:
+ case IPA_RM_RESOURCE_A2_PROD:
+ case IPA_RM_RESOURCE_USB_PROD:
+ case IPA_RM_RESOURCE_HSIC_PROD:
+ case IPA_RM_RESOURCE_STD_ECM_PROD:
+ case IPA_RM_RESOURCE_WWAN_0_PROD:
+ case IPA_RM_RESOURCE_WWAN_1_PROD:
+ case IPA_RM_RESOURCE_WWAN_2_PROD:
+ case IPA_RM_RESOURCE_WWAN_3_PROD:
+ case IPA_RM_RESOURCE_WWAN_4_PROD:
+ case IPA_RM_RESOURCE_WWAN_5_PROD:
+ case IPA_RM_RESOURCE_WWAN_6_PROD:
+ case IPA_RM_RESOURCE_WWAN_7_PROD:
+ case IPA_RM_RESOURCE_WLAN_PROD:
+ break;
+ default:
+ result = IPA_RM_INDEX_INVALID;
+ break;
+ }
+ return result;
+}
+
+/**
+ * ipa_rm_cons_index() - consumer name to consumer index mapping
+ * @resource_name: [in] resource name (should be of consumer)
+ *
+ * Returns: resource index mapping, IPA_RM_INDEX_INVALID
+ * in case provided resource name isn't contained
+ * in enum ipa_rm_resource_name or is not of consumers.
+ *
+ */
+int ipa_rm_cons_index(enum ipa_rm_resource_name resource_name)
+{
+ int result = resource_name;
+ switch (resource_name) {
+ case IPA_RM_RESOURCE_A2_CONS:
+ case IPA_RM_RESOURCE_USB_CONS:
+ case IPA_RM_RESOURCE_HSIC_CONS:
+ break;
+ default:
+ result = IPA_RM_INDEX_INVALID;
+ break;
+ }
+ return result;
+}
+
+static int ipa_rm_resource_consumer_request(
+ struct ipa_rm_resource_cons *consumer)
+{
+ int result = 0;
+ int driver_result;
+ unsigned long flags;
+ IPADBG("IPA RM ::ipa_rm_resource_consumer_request ENTER\n");
+ spin_lock_irqsave(&consumer->resource.state_lock, flags);
+ switch (consumer->resource.state) {
+ case IPA_RM_RELEASED:
+ case IPA_RM_RELEASE_IN_PROGRESS:
+ {
+ enum ipa_rm_resource_state prev_state =
+ consumer->resource.state;
+ consumer->resource.state = IPA_RM_REQUEST_IN_PROGRESS;
+ spin_unlock_irqrestore(&consumer->resource.state_lock, flags);
+ driver_result = consumer->request_resource();
+ spin_lock_irqsave(&consumer->resource.state_lock, flags);
+ if (driver_result == 0)
+ consumer->resource.state = IPA_RM_GRANTED;
+ else if (driver_result != -EINPROGRESS) {
+ consumer->resource.state = prev_state;
+ result = driver_result;
+ goto bail;
+ }
+ result = driver_result;
+ break;
+ }
+ case IPA_RM_GRANTED:
+ break;
+ case IPA_RM_REQUEST_IN_PROGRESS:
+ result = -EINPROGRESS;
+ break;
+ default:
+ result = -EPERM;
+ goto bail;
+ }
+ consumer->usage_count++;
+bail:
+ spin_unlock_irqrestore(&consumer->resource.state_lock, flags);
+ IPADBG("IPA RM ::ipa_rm_resource_consumer_request EXIT [%d]\n", result);
+ return result;
+}
+
+static int ipa_rm_resource_consumer_release(
+ struct ipa_rm_resource_cons *consumer)
+{
+ int result = 0;
+ int driver_result;
+ unsigned long flags;
+ enum ipa_rm_resource_state save_state;
+ IPADBG("IPA RM ::ipa_rm_resource_consumer_release ENTER\n");
+ spin_lock_irqsave(&consumer->resource.state_lock, flags);
+ switch (consumer->resource.state) {
+ case IPA_RM_RELEASED:
+ break;
+ case IPA_RM_GRANTED:
+ case IPA_RM_REQUEST_IN_PROGRESS:
+ if (consumer->usage_count > 0)
+ consumer->usage_count--;
+ if (consumer->usage_count == 0) {
+ save_state = consumer->resource.state;
+ consumer->resource.state = IPA_RM_RELEASE_IN_PROGRESS;
+ spin_unlock_irqrestore(&consumer->resource.state_lock,
+ flags);
+ driver_result = consumer->release_resource();
+ spin_lock_irqsave(&consumer->resource.state_lock,
+ flags);
+ if (driver_result == 0)
+ consumer->resource.state = IPA_RM_RELEASED;
+ else if (driver_result != -EINPROGRESS)
+ consumer->resource.state = save_state;
+ result = driver_result;
+ }
+ break;
+ case IPA_RM_RELEASE_IN_PROGRESS:
+ if (consumer->usage_count > 0)
+ consumer->usage_count--;
+ result = -EINPROGRESS;
+ break;
+ default:
+ result = -EPERM;
+ goto bail;
+ }
+bail:
+ spin_unlock_irqrestore(&consumer->resource.state_lock, flags);
+ IPADBG("IPA RM ::ipa_rm_resource_consumer_release EXIT [%d]\n", result);
+ return result;
+}
+
+/**
+ * ipa_rm_resource_producer_notify_clients() - notify
+ * all registered clients of given producer
+ * @producer: producer
+ * @event: event to notify
+ */
+void ipa_rm_resource_producer_notify_clients(
+ struct ipa_rm_resource_prod *producer,
+ enum ipa_rm_event event)
+{
+ struct ipa_rm_notification_info *reg_info, *reg_info_cloned;
+ struct list_head *pos, *q;
+ LIST_HEAD(cloned_list);
+ read_lock(&producer->event_listeners_lock);
+ list_for_each(pos, &(producer->event_listeners)) {
+ reg_info = list_entry(pos,
+ struct ipa_rm_notification_info,
+ link);
+ reg_info_cloned = kzalloc(sizeof(*reg_info_cloned), GFP_ATOMIC);
+ if (!reg_info_cloned)
+ goto clone_list_failed;
+ reg_info_cloned->reg_params.notify_cb =
+ reg_info->reg_params.notify_cb;
+ reg_info_cloned->reg_params.user_data =
+ reg_info->reg_params.user_data;
+ list_add(®_info_cloned->link, &cloned_list);
+ }
+ read_unlock(&producer->event_listeners_lock);
+ list_for_each_safe(pos, q, &cloned_list) {
+ reg_info = list_entry(pos,
+ struct ipa_rm_notification_info,
+ link);
+ reg_info->reg_params.notify_cb(
+ reg_info->reg_params.user_data,
+ event,
+ 0);
+ list_del(pos);
+ kfree(reg_info);
+ }
+ return;
+clone_list_failed:
+ read_unlock(&producer->event_listeners_lock);
+}
+
+static int ipa_rm_resource_producer_create(struct ipa_rm_resource **resource,
+ struct ipa_rm_resource_prod **producer,
+ struct ipa_rm_create_params *create_params,
+ int *max_peers)
+{
+ int result = 0;
+ *producer = kzalloc(sizeof(**producer), GFP_KERNEL);
+ if (*producer == NULL) {
+ result = -ENOMEM;
+ goto bail;
+ }
+ rwlock_init(&(*producer)->event_listeners_lock);
+ INIT_LIST_HEAD(&((*producer)->event_listeners));
+ result = ipa_rm_resource_producer_register(*producer,
+ &(create_params->reg_params));
+ if (result)
+ goto register_fail;
+ (*resource) = (struct ipa_rm_resource *) (*producer);
+ (*resource)->type = IPA_RM_PRODUCER;
+ *max_peers = IPA_RM_RESOURCE_CONS_MAX;
+ goto bail;
+register_fail:
+ kfree(*producer);
+bail:
+ return result;
+}
+
+static void ipa_rm_resource_producer_delete(
+ struct ipa_rm_resource_prod *producer)
+{
+ struct ipa_rm_notification_info *reg_info;
+ struct list_head *pos, *q;
+ write_lock(&producer->event_listeners_lock);
+ list_for_each_safe(pos, q, &(producer->event_listeners)) {
+ reg_info = list_entry(pos,
+ struct ipa_rm_notification_info,
+ link);
+ list_del(pos);
+ kfree(reg_info);
+ }
+ write_unlock(&producer->event_listeners_lock);
+}
+
+static int ipa_rm_resource_consumer_create(struct ipa_rm_resource **resource,
+ struct ipa_rm_resource_cons **consumer,
+ struct ipa_rm_create_params *create_params,
+ int *max_peers)
+{
+ int result = 0;
+ *consumer = kzalloc(sizeof(**consumer), GFP_KERNEL);
+ if (*consumer == NULL) {
+ result = -ENOMEM;
+ goto bail;
+ }
+ (*consumer)->request_resource = create_params->request_resource;
+ (*consumer)->release_resource = create_params->release_resource;
+ (*resource) = (struct ipa_rm_resource *) (*consumer);
+ (*resource)->type = IPA_RM_CONSUMER;
+ *max_peers = IPA_RM_RESOURCE_PROD_MAX;
+bail:
+ return result;
+}
+
+/**
+ * ipa_rm_resource_create() - creates resource
+ * @create_params: [in] parameters needed
+ * for resource initialization with IPA RM
+ * @resource: [out] created resource
+ *
+ * Returns: 0 on success, negative on failure
+ */
+int ipa_rm_resource_create(
+ struct ipa_rm_create_params *create_params,
+ struct ipa_rm_resource **resource)
+{
+ struct ipa_rm_resource_cons *consumer;
+ struct ipa_rm_resource_prod *producer;
+ int max_peers;
+ int result = 0;
+
+ if (!create_params) {
+ result = -EINVAL;
+ goto bail;
+ }
+ if (IPA_RM_RESORCE_IS_PROD(create_params->name)) {
+ result = ipa_rm_resource_producer_create(resource,
+ &producer,
+ create_params,
+ &max_peers);
+ if (result)
+ goto bail;
+ } else if (IPA_RM_RESORCE_IS_CONS(create_params->name)) {
+ result = ipa_rm_resource_consumer_create(resource,
+ &consumer,
+ create_params,
+ &max_peers);
+ if (result)
+ goto bail;
+ } else {
+ result = -EPERM;
+ goto bail;
+ }
+ result = ipa_rm_peers_list_create(max_peers,
+ &((*resource)->peers_list));
+ if (result)
+ goto peers_alloc_fail;
+ (*resource)->name = create_params->name;
+ (*resource)->state = IPA_RM_RELEASED;
+ spin_lock_init(&((*resource)->state_lock));
+ goto bail;
+peers_alloc_fail:
+ ipa_rm_resource_delete(*resource);
+bail:
+ return result;
+}
+
+/**
+ * ipa_rm_resource_delete() - deletes resource
+ * @resource: [in] resource
+ * for resource initialization with IPA RM
+ */
+void ipa_rm_resource_delete(struct ipa_rm_resource *resource)
+{
+ if (!resource)
+ return;
+ if (resource->peers_list)
+ ipa_rm_peers_list_delete(resource->peers_list);
+ if (resource->type == IPA_RM_PRODUCER) {
+ ipa_rm_resource_producer_delete(
+ (struct ipa_rm_resource_prod *) resource);
+ kfree((struct ipa_rm_resource_prod *) resource);
+ } else
+ kfree((struct ipa_rm_resource_cons *) resource);
+}
+
+/**
+ * ipa_rm_resource_register() - register resource
+ * @resource: [in] resource
+ * @reg_params: [in] registration parameters
+ *
+ * Returns: 0 on success, negative on failure
+ *
+ * Producer resource is expected for this call.
+ *
+ */
+int ipa_rm_resource_producer_register(struct ipa_rm_resource_prod *producer,
+ struct ipa_rm_register_params *reg_params)
+{
+ int result = 0;
+ struct ipa_rm_notification_info *reg_info;
+ struct list_head *pos;
+ if (!producer || !reg_params) {
+ result = -EPERM;
+ goto bail;
+ }
+ read_lock(&producer->event_listeners_lock);
+ list_for_each(pos, &(producer->event_listeners)) {
+ reg_info = list_entry(pos,
+ struct ipa_rm_notification_info,
+ link);
+ if (reg_info->reg_params.notify_cb ==
+ reg_params->notify_cb) {
+ result = -EPERM;
+ read_unlock(&producer->event_listeners_lock);
+ goto bail;
+ }
+
+ }
+ read_unlock(&producer->event_listeners_lock);
+ reg_info = kzalloc(sizeof(*reg_info), GFP_KERNEL);
+ if (reg_info == NULL) {
+ result = -ENOMEM;
+ goto bail;
+ }
+ reg_info->reg_params.user_data = reg_params->user_data;
+ reg_info->reg_params.notify_cb = reg_params->notify_cb;
+ INIT_LIST_HEAD(®_info->link);
+ write_lock(&producer->event_listeners_lock);
+ list_add(®_info->link, &producer->event_listeners);
+ write_unlock(&producer->event_listeners_lock);
+bail:
+ return result;
+}
+
+/**
+ * ipa_rm_resource_deregister() - register resource
+ * @resource: [in] resource
+ * @reg_params: [in] registration parameters
+ *
+ * Returns: 0 on success, negative on failure
+ *
+ * Producer resource is expected for this call.
+ * This function deleted only single instance of
+ * registration info.
+ *
+ */
+int ipa_rm_resource_producer_deregister(struct ipa_rm_resource_prod *producer,
+ struct ipa_rm_register_params *reg_params)
+{
+ int result = -EINVAL;
+ struct ipa_rm_notification_info *reg_info;
+ struct list_head *pos, *q;
+ if (!producer || !reg_params)
+ return -EINVAL;
+ write_lock(&producer->event_listeners_lock);
+ list_for_each_safe(pos, q, &(producer->event_listeners)) {
+ reg_info = list_entry(pos,
+ struct ipa_rm_notification_info,
+ link);
+ if (reg_info->reg_params.notify_cb ==
+ reg_params->notify_cb) {
+ list_del(pos);
+ kfree(reg_info);
+ result = 0;
+ goto bail;
+ }
+
+ }
+bail:
+ write_unlock(&producer->event_listeners_lock);
+ return result;
+}
+
+/**
+ * ipa_rm_resource_add_dependency() - add dependency between two
+ * given resources
+ * @resource: [in] resource resource
+ * @depends_on: [in] depends_on resource
+ *
+ * Returns: 0 on success, negative on failure
+ */
+int ipa_rm_resource_add_dependency(struct ipa_rm_resource *resource,
+ struct ipa_rm_resource *depends_on)
+{
+ int result = 0;
+ unsigned long flags;
+ int consumer_result;
+ if (!resource || !depends_on)
+ return -EINVAL;
+ if (ipa_rm_peers_list_check_dependency(resource->peers_list,
+ resource->name,
+ depends_on->peers_list,
+ depends_on->name))
+ return -EINVAL;
+ ipa_rm_peers_list_add_peer(resource->peers_list, depends_on);
+ ipa_rm_peers_list_add_peer(depends_on->peers_list, resource);
+ spin_lock_irqsave(&resource->state_lock, flags);
+ switch (resource->state) {
+ case IPA_RM_RELEASED:
+ case IPA_RM_RELEASE_IN_PROGRESS:
+ break;
+ case IPA_RM_GRANTED:
+ case IPA_RM_REQUEST_IN_PROGRESS:
+ {
+ enum ipa_rm_resource_state prev_state = resource->state;
+ resource->state = IPA_RM_REQUEST_IN_PROGRESS;
+ ((struct ipa_rm_resource_prod *)
+ resource)->pending_request++;
+ spin_unlock_irqrestore(&resource->state_lock, flags);
+ consumer_result = ipa_rm_resource_consumer_request(
+ (struct ipa_rm_resource_cons *)depends_on);
+ spin_lock_irqsave(&resource->state_lock, flags);
+ if (consumer_result != -EINPROGRESS)
+ resource->state = prev_state;
+ ((struct ipa_rm_resource_prod *)
+ resource)->pending_request--;
+ result = consumer_result;
+ break;
+ }
+ default:
+ result = -EPERM;
+ goto bail;
+ }
+bail:
+ spin_unlock_irqrestore(&resource->state_lock, flags);
+ IPADBG("IPA RM ipa_rm_resource_add_dependency name[%d]count[%d]EXIT\n",
+ resource->name, resource->peers_list->peers_count);
+ IPADBG("IPA RM ipa_rm_resource_add_dependency name[%d]count[%d]EXIT\n",
+ depends_on->name, depends_on->peers_list->peers_count);
+ return result;
+}
+
+/**
+ * ipa_rm_resource_delete_dependency() - add dependency between two
+ * given resources
+ * @resource: [in] resource resource
+ * @depends_on: [in] depends_on resource
+ *
+ * Returns: 0 on success, negative on failure
+ * EINPROGRESS is returned in case this is the last dependency
+ * of given resource and IPA RM client should receive the RELEASED cb
+ */
+int ipa_rm_resource_delete_dependency(struct ipa_rm_resource *resource,
+ struct ipa_rm_resource *depends_on)
+{
+ int result = 0;
+ unsigned long flags;
+ if (!resource || !depends_on)
+ return -EINVAL;
+ if (ipa_rm_peers_list_check_dependency(resource->peers_list,
+ resource->name,
+ depends_on->peers_list,
+ depends_on->name))
+ return -EINVAL;
+ spin_lock_irqsave(&resource->state_lock, flags);
+ switch (resource->state) {
+ case IPA_RM_RELEASED:
+ case IPA_RM_GRANTED:
+ 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--;
+ break;
+ case IPA_RM_REQUEST_IN_PROGRESS:
+ if (((struct ipa_rm_resource_prod *)
+ resource)->pending_request > 0)
+ ((struct ipa_rm_resource_prod *)
+ resource)->pending_request--;
+ break;
+ default:
+ result = -EINVAL;
+ spin_unlock_irqrestore(&resource->state_lock, flags);
+ goto bail;
+ }
+ spin_unlock_irqrestore(&resource->state_lock, flags);
+ (void) ipa_rm_resource_consumer_release(
+ (struct ipa_rm_resource_cons *)depends_on);
+ if (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);
+ result = -EINPROGRESS;
+ }
+ ipa_rm_peers_list_remove_peer(resource->peers_list,
+ depends_on->name);
+ ipa_rm_peers_list_remove_peer(depends_on->peers_list,
+ resource->name);
+bail:
+ return result;
+}
+
+/**
+ * ipa_rm_resource_producer_request() - producer resource request
+ * @producer: [in] producer
+ *
+ * Returns: 0 on success, negative on failure
+ */
+int ipa_rm_resource_producer_request(struct ipa_rm_resource_prod *producer)
+{
+ int peers_index;
+ int result = 0;
+ unsigned long flags;
+ struct ipa_rm_resource *consumer;
+ int consumer_result;
+ IPADBG("IPA RM ::ipa_rm_resource_producer_request [%d] ENTER\n",
+ producer->resource.name);
+ if (ipa_rm_peers_list_is_empty(producer->resource.peers_list)) {
+ spin_lock_irqsave(&producer->resource.state_lock, flags);
+ producer->resource.state = IPA_RM_GRANTED;
+ spin_unlock_irqrestore(&producer->resource.state_lock, flags);
+ return 0;
+ }
+ spin_lock_irqsave(&producer->resource.state_lock, flags);
+ IPADBG("IPA RM ::ipa_rm_resource_producer_request state [%d]\n",
+ producer->resource.state);
+ switch (producer->resource.state) {
+ case IPA_RM_RELEASED:
+ case IPA_RM_RELEASE_IN_PROGRESS:
+ producer->resource.state = IPA_RM_REQUEST_IN_PROGRESS;
+ break;
+ case IPA_RM_GRANTED:
+ goto unlock_and_bail;
+ case IPA_RM_REQUEST_IN_PROGRESS:
+ result = -EINPROGRESS;
+ goto unlock_and_bail;
+ default:
+ result = -EINVAL;
+ goto unlock_and_bail;
+ }
+ producer->pending_request = 0;
+ spin_unlock_irqrestore(&producer->resource.state_lock, flags);
+ for (peers_index = 0;
+ peers_index < ipa_rm_peers_list_get_size(
+ producer->resource.peers_list);
+ peers_index++) {
+ consumer = ipa_rm_peers_list_get_resource(peers_index,
+ producer->resource.peers_list);
+ if (consumer) {
+ spin_lock_irqsave(
+ &producer->resource.state_lock, flags);
+ producer->pending_request++;
+ spin_unlock_irqrestore(
+ &producer->resource.state_lock, flags);
+ consumer_result = ipa_rm_resource_consumer_request(
+ (struct ipa_rm_resource_cons *)consumer);
+ if (consumer_result == -EINPROGRESS) {
+ result = -EINPROGRESS;
+ } else {
+ spin_lock_irqsave(
+ &producer->resource.state_lock, flags);
+ producer->pending_request--;
+ spin_unlock_irqrestore(
+ &producer->resource.state_lock, flags);
+ if (consumer_result != 0) {
+ result = consumer_result;
+ goto bail;
+ }
+ }
+ }
+ }
+ spin_lock_irqsave(&producer->resource.state_lock, flags);
+ if (producer->pending_request == 0)
+ producer->resource.state = IPA_RM_GRANTED;
+ spin_unlock_irqrestore(&producer->resource.state_lock, flags);
+ return result;
+unlock_and_bail:
+ spin_unlock_irqrestore(&producer->resource.state_lock, flags);
+bail:
+ IPADBG("IPA RM ::ipa_rm_resource_producer_request EXIT[%d]\n", result);
+ return result;
+}
+
+/**
+ * ipa_rm_resource_producer_release() - producer resource release
+ * producer: [in] producer resource
+ *
+ * Returns: 0 on success, negative on failure
+ *
+ */
+int ipa_rm_resource_producer_release(struct ipa_rm_resource_prod *producer)
+{
+ int peers_index;
+ int result = 0;
+ unsigned long flags;
+ struct ipa_rm_resource *consumer;
+ int consumer_result;
+ IPADBG("IPA RM ::ipa_rm_resource_producer_release ENTER\n");
+ if (ipa_rm_peers_list_is_empty(producer->resource.peers_list)) {
+ spin_lock_irqsave(&producer->resource.state_lock, flags);
+ producer->resource.state = IPA_RM_RELEASED;
+ spin_unlock_irqrestore(&producer->resource.state_lock, flags);
+ return 0;
+ }
+ spin_lock_irqsave(&producer->resource.state_lock, flags);
+ switch (producer->resource.state) {
+ case IPA_RM_RELEASED:
+ goto bail;
+ case IPA_RM_GRANTED:
+ case IPA_RM_REQUEST_IN_PROGRESS:
+ producer->resource.state = IPA_RM_RELEASE_IN_PROGRESS;
+ break;
+ case IPA_RM_RELEASE_IN_PROGRESS:
+ result = -EINPROGRESS;
+ goto bail;
+ default:
+ result = -EPERM;
+ goto bail;
+ }
+ producer->pending_release = 0;
+ spin_unlock_irqrestore(&producer->resource.state_lock, flags);
+ for (peers_index = 0;
+ peers_index < ipa_rm_peers_list_get_size(
+ producer->resource.peers_list);
+ peers_index++) {
+ consumer = ipa_rm_peers_list_get_resource(peers_index,
+ producer->resource.peers_list);
+ if (consumer) {
+ spin_lock_irqsave(
+ &producer->resource.state_lock, flags);
+ producer->pending_release++;
+ spin_unlock_irqrestore(
+ &producer->resource.state_lock, flags);
+ consumer_result = ipa_rm_resource_consumer_release(
+ (struct ipa_rm_resource_cons *)consumer);
+ if (consumer_result == -EINPROGRESS) {
+ result = -EINPROGRESS;
+ } else {
+ spin_lock_irqsave(
+ &producer->resource.state_lock, flags);
+ producer->pending_release--;
+ spin_unlock_irqrestore(
+ &producer->resource.state_lock, flags);
+ }
+ }
+ }
+ spin_lock_irqsave(&producer->resource.state_lock, flags);
+ if (producer->pending_release == 0)
+ producer->resource.state = IPA_RM_RELEASED;
+ spin_unlock_irqrestore(&producer->resource.state_lock, flags);
+ return result;
+bail:
+ spin_unlock_irqrestore(&producer->resource.state_lock, flags);
+ IPADBG("IPA RM ::ipa_rm_resource_producer_release EXIT[%d]\n", result);
+ return result;
+}
+
+static void ipa_rm_resource_producer_handle_cb(
+ struct ipa_rm_resource_prod *producer,
+ enum ipa_rm_event event)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&producer->resource.state_lock, flags);
+ switch (producer->resource.state) {
+ case IPA_RM_REQUEST_IN_PROGRESS:
+ if (event != IPA_RM_RESOURCE_GRANTED)
+ goto unlock_and_bail;
+ if (producer->pending_request > 0) {
+ producer->pending_request--;
+ if (producer->pending_request == 0) {
+ producer->resource.state =
+ IPA_RM_GRANTED;
+ spin_unlock_irqrestore(
+ &producer->resource.state_lock, flags);
+ ipa_rm_resource_producer_notify_clients(
+ producer,
+ IPA_RM_RESOURCE_GRANTED);
+ goto bail;
+ }
+ }
+ break;
+ case IPA_RM_RELEASE_IN_PROGRESS:
+ if (event != IPA_RM_RESOURCE_RELEASED)
+ goto unlock_and_bail;
+ if (producer->pending_release > 0) {
+ producer->pending_release--;
+ if (producer->pending_release == 0) {
+ producer->resource.state =
+ IPA_RM_RELEASED;
+ spin_unlock_irqrestore(
+ &producer->resource.state_lock, flags);
+ ipa_rm_resource_producer_notify_clients(
+ producer,
+ IPA_RM_RESOURCE_RELEASED);
+ goto bail;
+ }
+ }
+ break;
+ case IPA_RM_GRANTED:
+ case IPA_RM_RELEASED:
+ default:
+ goto unlock_and_bail;
+ }
+unlock_and_bail:
+ spin_unlock_irqrestore(&producer->resource.state_lock, flags);
+bail:
+ return;
+}
+
+/**
+ * ipa_rm_resource_consumer_handle_cb() - propagates resource
+ * notification to all dependent producers
+ * @consumer: [in] notifying resource
+ *
+ */
+void ipa_rm_resource_consumer_handle_cb(struct ipa_rm_resource_cons *consumer,
+ enum ipa_rm_event event)
+{
+ int peers_index;
+ struct ipa_rm_resource *producer;
+ unsigned long flags;
+ if (!consumer)
+ return;
+ spin_lock_irqsave(&consumer->resource.state_lock, flags);
+ switch (consumer->resource.state) {
+ case IPA_RM_REQUEST_IN_PROGRESS:
+ if (event == IPA_RM_RESOURCE_RELEASED)
+ goto bail;
+ consumer->resource.state = IPA_RM_GRANTED;
+ break;
+ case IPA_RM_RELEASE_IN_PROGRESS:
+ if (event == IPA_RM_RESOURCE_GRANTED)
+ goto bail;
+ consumer->resource.state = IPA_RM_RELEASED;
+ break;
+ case IPA_RM_GRANTED:
+ case IPA_RM_RELEASED:
+ default:
+ goto bail;
+ }
+ spin_unlock_irqrestore(&consumer->resource.state_lock, flags);
+ for (peers_index = 0;
+ peers_index < ipa_rm_peers_list_get_size(
+ consumer->resource.peers_list);
+ peers_index++) {
+ producer = ipa_rm_peers_list_get_resource(peers_index,
+ consumer->resource.peers_list);
+ if (producer)
+ ipa_rm_resource_producer_handle_cb(
+ (struct ipa_rm_resource_prod *)
+ producer,
+ event);
+ }
+ return;
+bail:
+ spin_unlock_irqrestore(&consumer->resource.state_lock, flags);
+ return;
+}
diff --git a/drivers/platform/msm/ipa/ipa_rm_resource.h b/drivers/platform/msm/ipa/ipa_rm_resource.h
new file mode 100644
index 0000000..b9c2e91
--- /dev/null
+++ b/drivers/platform/msm/ipa/ipa_rm_resource.h
@@ -0,0 +1,127 @@
+/* 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 _IPA_RM_RESOURCE_H_
+#define _IPA_RM_RESOURCE_H_
+
+#include <linux/list.h>
+#include <mach/ipa.h>
+#include "ipa_rm_peers_list.h"
+
+/**
+ * enum ipa_rm_resource_state - resource state
+ */
+enum ipa_rm_resource_state {
+ IPA_RM_RELEASED,
+ IPA_RM_REQUEST_IN_PROGRESS,
+ IPA_RM_GRANTED,
+ IPA_RM_RELEASE_IN_PROGRESS
+};
+
+/**
+ * enum ipa_rm_resource_type - IPA resource manager resource type
+ */
+enum ipa_rm_resource_type {
+ IPA_RM_PRODUCER,
+ IPA_RM_CONSUMER
+};
+
+/**
+ * struct ipa_rm_notification_info - notification information
+ * of IPA RM client
+ * @reg_params: registration parameters
+ * @link: link to the list of all registered clients information
+ */
+struct ipa_rm_notification_info {
+ struct ipa_rm_register_params reg_params;
+ struct list_head link;
+};
+
+/**
+ * struct ipa_rm_resource - IPA RM resource
+ * @name: name identifying resource
+ * @state: state of the resource
+ * @state_lock: lock for all resource state related variables
+ * @peers_list: list of the peers of the resource
+ */
+struct ipa_rm_resource {
+ enum ipa_rm_resource_name name;
+ enum ipa_rm_resource_type type;
+ enum ipa_rm_resource_state state;
+ spinlock_t state_lock;
+ struct ipa_rm_peers_list *peers_list;
+};
+
+/**
+ * struct ipa_rm_resource_cons - IPA RM consumer
+ * @resource: resource
+ * @usage_count: number of producers in GRANTED / REQUESTED state
+ * using this consumer
+ * @request_resource: function which should be called to request resource
+ * from resource manager
+ * @release_resource: function which should be called to release resource
+ * from resource manager
+ * Add new fields after @resource only.
+ */
+struct ipa_rm_resource_cons {
+ struct ipa_rm_resource resource;
+ int usage_count;
+ int (*request_resource)(void);
+ int (*release_resource)(void);
+};
+
+/**
+ * struct ipa_rm_resource_prod - IPA RM producer
+ * @resource: resource
+ * @event_listeners: clients registered with this producer
+ * for notifications in resource state
+ * @event_listeners_lock: RW lock protecting the event listeners list
+ * Add new fields after @resource only.
+ */
+struct ipa_rm_resource_prod {
+ struct ipa_rm_resource resource;
+ struct list_head event_listeners;
+ rwlock_t event_listeners_lock;
+ int pending_request;
+ int pending_release;
+};
+
+int ipa_rm_resource_create(
+ struct ipa_rm_create_params *create_params,
+ struct ipa_rm_resource **resource);
+
+void ipa_rm_resource_delete(struct ipa_rm_resource *resource);
+
+int ipa_rm_resource_producer_register(struct ipa_rm_resource_prod *producer,
+ struct ipa_rm_register_params *reg_params);
+
+int ipa_rm_resource_producer_deregister(struct ipa_rm_resource_prod *producer,
+ struct ipa_rm_register_params *reg_params);
+
+int ipa_rm_resource_add_dependency(struct ipa_rm_resource *resource,
+ struct ipa_rm_resource *depends_on);
+
+int ipa_rm_resource_delete_dependency(struct ipa_rm_resource *resource,
+ struct ipa_rm_resource *depends_on);
+
+int ipa_rm_resource_producer_request(struct ipa_rm_resource_prod *producer);
+
+int ipa_rm_resource_producer_release(struct ipa_rm_resource_prod *producer);
+
+void ipa_rm_resource_consumer_handle_cb(struct ipa_rm_resource_cons *consumer,
+ enum ipa_rm_event event);
+
+void ipa_rm_resource_producer_notify_clients(
+ struct ipa_rm_resource_prod *producer,
+ enum ipa_rm_event event);
+
+#endif /* _IPA_RM_RESOURCE_H_ */
diff --git a/drivers/platform/msm/ssm.c b/drivers/platform/msm/ssm.c
new file mode 100644
index 0000000..c57bb91
--- /dev/null
+++ b/drivers/platform/msm/ssm.c
@@ -0,0 +1,931 @@
+/* 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.
+ */
+/*
+ * Qualcomm Secure Service Module(SSM) driver
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/of.h>
+#include <linux/cdev.h>
+#include <linux/uaccess.h>
+#include <linux/mutex.h>
+#include <linux/ion.h>
+#include <linux/types.h>
+#include <linux/firmware.h>
+#include <linux/elf.h>
+#include <linux/platform_device.h>
+#include <linux/msm_ion.h>
+#include <linux/platform_data/qcom_ssm.h>
+#include <mach/scm.h>
+#include <mach/msm_smd.h>
+
+#include "ssm.h"
+
+/* Macros */
+#define SSM_DEV_NAME "ssm"
+#define MPSS_SUBSYS 0
+#define SSM_INFO_CMD_ID 1
+#define QSEOS_CHECK_VERSION_CMD 0x00001803
+
+#define MAX_APP_NAME_SIZE 32
+#define SSM_MSG_LEN (104 + 4) /* bytes + pad */
+#define SSM_MSG_FIELD_LEN 11
+#define SSM_HEADER_LEN (SSM_MSG_FIELD_LEN * 4)
+#define ATOM_MSG_LEN (SSM_HEADER_LEN + SSM_MSG_LEN)
+#define FIRMWARE_NAME "ssmapp"
+#define TZAPP_NAME "SsmApp"
+#define CHANNEL_NAME "SSM_RTR"
+
+#define ALIGN_BUFFER(size) ((size + 4095) & ~4095)
+
+/* SSM driver structure.*/
+struct ssm_driver {
+ int32_t app_id;
+ int32_t app_status;
+ int32_t update_status;
+ int32_t atom_replay;
+ int32_t mtoa_replay;
+ uint32_t buff_len;
+ unsigned char *channel_name;
+ unsigned char *smd_buffer;
+ struct ion_client *ssm_ion_client;
+ struct ion_handle *ssm_ion_handle;
+ struct tzapp_get_mode_info_rsp *resp;
+ struct device *dev;
+ smd_channel_t *ch;
+ ion_phys_addr_t buff_phys;
+ ion_virt_addr_t buff_virt;
+ dev_t ssm_device_no;
+ struct work_struct ipc_work;
+ struct mutex mutex;
+ bool key_status;
+ bool ready;
+};
+
+static struct ssm_driver *ssm_drv;
+
+static unsigned int getint(char *buff, unsigned long *res)
+{
+ char value[SSM_MSG_FIELD_LEN];
+
+ memcpy(value, buff, SSM_MSG_FIELD_LEN);
+ value[SSM_MSG_FIELD_LEN - 1] = '\0';
+
+ return kstrtoul(skip_spaces(value), 10, res);
+}
+
+/*
+ * Send packet to modem over SMD channel.
+ */
+static int update_modem(enum ssm_ipc_req ipc_req, struct ssm_driver *ssm,
+ int length, char *data)
+{
+ unsigned int packet_len = SSM_HEADER_LEN + length + 1;
+ int rc = 0;
+
+ ssm->atom_replay += 1;
+ snprintf(ssm->smd_buffer, SSM_HEADER_LEN + 1, "%10u|%10u|%10u|%10u|"
+ , packet_len, ssm->atom_replay, ipc_req, length);
+ memcpy(ssm->smd_buffer + SSM_HEADER_LEN, data, length);
+
+ ssm->smd_buffer[packet_len - 1] = '|';
+
+ if (smd_write_avail(ssm->ch) < packet_len) {
+ dev_err(ssm->dev, "Not enough space dropping request\n");
+ rc = -ENOSPC;
+ }
+
+ rc = smd_write(ssm->ch, ssm->smd_buffer, packet_len);
+ if (rc < packet_len) {
+ dev_err(ssm->dev, "smd_write failed for %d\n", ipc_req);
+ rc = -EIO;
+ }
+
+ return rc;
+}
+
+/*
+ * Header Format
+ * Each member of header is of 10 byte (ASCII).
+ * Each entry is separated by '|' delimiter.
+ * |<-10 bytes->|<-10 bytes->|<-10 bytes->|<-10 bytes->|<-10 bytes->|
+ * |-----------------------------------------------------------------
+ * | length | replay no. | request | msg_len | message |
+ * |-----------------------------------------------------------------
+ *
+ */
+static int decode_header(char *buffer, int length,
+ struct ssm_common_msg *pkt)
+{
+ int rc;
+
+ rc = getint(buffer, &pkt->pktlen);
+ if (rc < 0)
+ return -EINVAL;
+
+ buffer += SSM_MSG_FIELD_LEN;
+ rc = getint(buffer, &pkt->replaynum);
+ if (rc < 0)
+ return -EINVAL;
+
+ buffer += SSM_MSG_FIELD_LEN;
+ rc = getint(buffer, (unsigned long *)&pkt->ipc_req);
+ if (rc < 0)
+ return -EINVAL;
+
+ buffer += SSM_MSG_FIELD_LEN;
+ rc = getint(buffer, &pkt->msg_len);
+ if ((rc < 0) || (pkt->msg_len > SSM_MSG_LEN))
+ return -EINVAL;
+
+ pkt->msg = buffer + SSM_MSG_FIELD_LEN;
+
+ dev_dbg(ssm_drv->dev, "len %lu rep %lu req %d msg_len %lu\n",
+ pkt->pktlen, pkt->replaynum, pkt->ipc_req,
+ pkt->msg_len);
+ return 0;
+}
+
+/*
+ * Decode address for storing the decryption key.
+ * Only for Key Exchange
+ * Message Format
+ * |Length@Address|
+ */
+static int decode_message(char *msg, unsigned int len, unsigned long *length,
+ unsigned long *address)
+{
+ int i = 0, rc = 0;
+ char *buff;
+
+ buff = kzalloc(len, GFP_KERNEL);
+ if (!buff)
+ return -ENOMEM;
+ while (i < len) {
+ if (msg[i] == '@')
+ break;
+ i++;
+ }
+ if ((i < len) && (msg[i] == '@')) {
+ memcpy(buff, msg, i);
+ buff[i] = '\0';
+ rc = kstrtoul(skip_spaces(buff), 10, length);
+ if (rc || (length <= 0)) {
+ rc = -EINVAL;
+ goto exit;
+ }
+ memcpy(buff, &msg[i + 1], len - (i + 1));
+ buff[len - i] = '\0';
+ rc = kstrtoul(skip_spaces(buff), 10, address);
+ } else
+ rc = -EINVAL;
+
+exit:
+ kfree(buff);
+ return rc;
+}
+
+static void process_message(int cmd, char *msg, int len,
+ struct ssm_driver *ssm)
+{
+ int rc;
+ unsigned long key_len = 0, key_add = 0, val;
+ struct ssm_keyexchg_req req;
+
+ switch (cmd) {
+ case SSM_MTOA_KEY_EXCHANGE:
+ if (len < 3) {
+ dev_err(ssm->dev, "Invalid message\n");
+ break;
+ }
+
+ if (ssm->key_status) {
+ dev_err(ssm->dev, "Key exchange already done\n");
+ break;
+ }
+
+ rc = decode_message(msg, len, &key_len, &key_add);
+ if (rc) {
+ rc = update_modem(SSM_ATOM_KEY_STATUS, ssm,
+ 1, "1");
+ break;
+ }
+
+ /*
+ * We are doing key-exchange part here as it is very
+ * specific for this case. For all other tz
+ * communication we have generic function.
+ */
+ req.ssid = MPSS_SUBSYS;
+ req.address = (void *)key_add;
+ req.length = key_len;
+ req.status = (uint32_t *)ssm->buff_phys;
+
+ *(unsigned int *)ssm->buff_virt = -1;
+ rc = scm_call(KEY_EXCHANGE, 0x1, &req,
+ sizeof(struct ssm_keyexchg_req), NULL, 0);
+ if (rc) {
+ dev_err(ssm->dev, "Call for key exchg failed %d", rc);
+ rc = update_modem(SSM_ATOM_KEY_STATUS, ssm,
+ 1, "1");
+ } else {
+ /* Success encode packet and update modem */
+ rc = update_modem(SSM_ATOM_KEY_STATUS, ssm,
+ 1, "0");
+ ssm->key_status = true;
+ }
+ break;
+
+ case SSM_MTOA_MODE_UPDATE_STATUS:
+ msg[len] = '\0';
+ rc = kstrtoul(skip_spaces(msg), 10, &val);
+ if (val) {
+ dev_err(ssm->dev, "Modem mode update failed\n");
+ ssm->update_status = FAILED;
+ } else
+ ssm->update_status = SUCCESS;
+
+ dev_dbg(ssm->dev, "Modem mode update status %lu\n", val);
+ break;
+
+ default:
+ dev_dbg(ssm->dev, "Invalid message\n");
+ break;
+ };
+}
+
+/*
+ * Work function to handle and process packets coming from modem.
+ */
+static void ssm_app_modem_work_fn(struct work_struct *work)
+{
+ int sz, rc;
+ struct ssm_common_msg pkt;
+ struct ssm_driver *ssm;
+
+ ssm = container_of(work, struct ssm_driver, ipc_work);
+
+ mutex_lock(&ssm->mutex);
+ sz = smd_cur_packet_size(ssm->ch);
+ if ((sz <= 0) || (sz > ATOM_MSG_LEN)) {
+ dev_dbg(ssm_drv->dev, "Garbled message size\n");
+ goto unlock;
+ }
+
+ if (smd_read_avail(ssm->ch) < sz) {
+ dev_err(ssm_drv->dev, "SMD error data in channel\n");
+ goto unlock;
+ }
+
+ if (sz < SSM_HEADER_LEN) {
+ dev_err(ssm_drv->dev, "Invalid packet\n");
+ goto unlock;
+ }
+
+ if (smd_read(ssm->ch, ssm->smd_buffer, sz) != sz) {
+ dev_err(ssm_drv->dev, "Incomplete data\n");
+ goto unlock;
+ }
+
+ rc = decode_header(ssm->smd_buffer, sz, &pkt);
+ if (rc < 0) {
+ dev_err(ssm_drv->dev, "Corrupted header\n");
+ goto unlock;
+ }
+
+ /* Check validity of message */
+ if (ssm->mtoa_replay >= (int)pkt.replaynum) {
+ dev_err(ssm_drv->dev, "Replay attack...\n");
+ goto unlock;
+ }
+
+ if (pkt.msg[pkt.msg_len] != '|') {
+ dev_err(ssm_drv->dev, "Garbled message\n");
+ goto unlock;
+ }
+
+ ssm->mtoa_replay = pkt.replaynum;
+ process_message(pkt.ipc_req, pkt.msg, pkt.msg_len, ssm);
+
+unlock:
+ mutex_unlock(&ssm->mutex);
+}
+
+/*
+ * MODEM-APPS smd channel callback function.
+ */
+static void modem_request(void *ctxt, unsigned event)
+{
+ struct ssm_driver *ssm;
+
+ ssm = (struct ssm_driver *)ctxt;
+
+ switch (event) {
+ case SMD_EVENT_OPEN:
+ case SMD_EVENT_CLOSE:
+ dev_info(ssm->dev, "Port %s\n",
+ (event == SMD_EVENT_OPEN) ? "opened" : "closed");
+ break;
+ case SMD_EVENT_DATA:
+ if (smd_read_avail(ssm->ch) > 0)
+ schedule_work(&ssm->ipc_work);
+ break;
+ };
+}
+
+/*
+ * Communication interface between ssm driver and TZ.
+ */
+static int tz_scm_call(struct ssm_driver *ssm, void *tz_req, int tz_req_len,
+ void **tz_resp, int tz_resp_len)
+{
+ int rc;
+ struct common_req req;
+ struct common_resp resp;
+
+ memcpy((void *)ssm->buff_virt, tz_req, tz_req_len);
+
+ req.cmd_id = CLIENT_SEND_DATA_COMMAND;
+ req.app_id = ssm->app_id;
+ req.req_ptr = (void *)ssm->buff_phys;
+ req.req_len = tz_req_len;
+ req.resp_ptr = (void *)(ssm->buff_phys + tz_req_len);
+ req.resp_len = tz_resp_len;
+
+ rc = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *) &req,
+ sizeof(req), (void *)&resp, sizeof(resp));
+ if (rc) {
+ dev_err(ssm->dev, "SCM call failed for data command\n");
+ return rc;
+ }
+
+ if (resp.result != RESULT_SUCCESS) {
+ dev_err(ssm->dev, "Data command response failure %d\n",
+ resp.result);
+ return -EINVAL;
+ }
+
+ *tz_resp = (void *)(ssm->buff_virt + tz_req_len);
+
+ return rc;
+}
+
+/*
+ * Load SSM application in TZ and start application:
+ * 1. Check if SSM application is already loaded.
+ * 2. Load SSM application firmware.
+ * 3. Start SSM application in TZ.
+ */
+static int ssm_load_app(struct ssm_driver *ssm)
+{
+ unsigned char name[MAX_APP_NAME_SIZE], *pos;
+ int rc, i, fw_count;
+ uint32_t buff_len, size = 0, ion_len;
+ struct check_app_req app_req;
+ struct scm_resp app_resp;
+ struct load_app app_img_info;
+ const struct firmware **fw, *fw_mdt;
+ const struct elf32_hdr *ehdr;
+ const struct elf32_phdr *phdr;
+ struct ion_handle *ion_handle;
+ ion_phys_addr_t buff_phys;
+ ion_virt_addr_t buff_virt;
+
+ /* Check if TZ app already loaded */
+ app_req.cmd_id = APP_LOOKUP_COMMAND;
+ memcpy(app_req.app_name, TZAPP_NAME, MAX_APP_NAME_SIZE);
+
+ rc = scm_call(SCM_SVC_TZSCHEDULER, 1, &app_req,
+ sizeof(struct check_app_req),
+ &app_resp, sizeof(app_resp));
+ if (rc) {
+ dev_err(ssm->dev, "SCM call failed for LOOKUP COMMAND\n");
+ return -EINVAL;
+ }
+
+ if (app_resp.result == RESULT_FAILURE)
+ ssm->app_id = 0;
+ else
+ ssm->app_id = app_resp.data;
+
+ if (ssm->app_id) {
+ rc = 0;
+ dev_info(ssm->dev, "TZAPP already loaded...\n");
+ goto out;
+ }
+
+ /* APP not loaded get the firmware */
+ /* Get .mdt first */
+ rc = request_firmware(&fw_mdt, FIRMWARE_NAME".mdt", ssm->dev);
+ if (rc) {
+ dev_err(ssm->dev, "Unable to get mdt file %s\n",
+ FIRMWARE_NAME".mdt");
+ rc = -EIO;
+ goto out;
+ }
+
+ if (fw_mdt->size < sizeof(*ehdr)) {
+ dev_err(ssm->dev, "Not big enough to be an elf header\n");
+ rc = -EIO;
+ goto release_mdt;
+ }
+
+ ehdr = (struct elf32_hdr *)fw_mdt->data;
+ if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
+ dev_err(ssm->dev, "Not an elf header\n");
+ rc = -EIO;
+ goto release_mdt;
+ }
+
+ if (ehdr->e_phnum == 0) {
+ dev_err(ssm->dev, "No loadable segments\n");
+ rc = -EIO;
+ goto release_mdt;
+ }
+
+ phdr = (const struct elf32_phdr *)(fw_mdt->data +
+ sizeof(struct elf32_hdr));
+
+ fw = kzalloc((sizeof(struct firmware *) * ehdr->e_phnum), GFP_KERNEL);
+ if (!fw) {
+ rc = -ENOMEM;
+ goto release_mdt;
+ }
+
+ /* Valid .mdt now we need to load other parts .b0* */
+ for (fw_count = 0; fw_count < ehdr->e_phnum ; fw_count++) {
+ snprintf(name, MAX_APP_NAME_SIZE, FIRMWARE_NAME".b%02d",
+ fw_count);
+ rc = request_firmware(&fw[fw_count], name, ssm->dev);
+ if (rc < 0) {
+ rc = -EIO;
+ dev_err(ssm->dev, "Unable to get blob file\n");
+ goto release_blob;
+ }
+
+ if (fw[fw_count]->size != phdr->p_filesz) {
+ dev_err(ssm->dev, "Blob size %u doesn't match %u\n",
+ fw[fw_count]->size, phdr->p_filesz);
+ rc = -EIO;
+ goto release_blob;
+ }
+
+ phdr++;
+ size += fw[fw_count]->size;
+ }
+
+ /* Ion allocation for loading tzapp */
+ /* ION buffer size 4k aligned */
+ ion_len = ALIGN_BUFFER(size);
+ ion_handle = ion_alloc(ssm_drv->ssm_ion_client,
+ ion_len, SZ_4K, ION_HEAP(ION_QSECOM_HEAP_ID), 0);
+ if (IS_ERR_OR_NULL(ion_handle)) {
+ rc = PTR_ERR(ion_handle);
+ dev_err(ssm->dev, "Unable to get ion handle\n");
+ goto release_blob;
+ }
+
+ rc = ion_phys(ssm_drv->ssm_ion_client, ion_handle,
+ &buff_phys, &buff_len);
+ if (rc < 0) {
+ dev_err(ssm->dev, "Unable to get ion physical address\n");
+ goto ion_free;
+ }
+
+ if (buff_len < size) {
+ rc = -ENOMEM;
+ goto ion_free;
+ }
+
+ buff_virt =
+ (ion_virt_addr_t)ion_map_kernel(ssm_drv->ssm_ion_client,
+ ion_handle);
+ if (IS_ERR_OR_NULL((void *)buff_virt)) {
+ rc = PTR_ERR((void *)buff_virt);
+ dev_err(ssm->dev, "Unable to get ion virtual address\n");
+ goto ion_free;
+ }
+
+ /* Copy firmware to ION memory */
+ memcpy((unsigned char *)buff_virt, fw_mdt->data, fw_mdt->size);
+ pos = (unsigned char *)buff_virt + fw_mdt->size;
+ for (i = 0; i < ehdr->e_phnum; i++) {
+ memcpy(pos, fw[i]->data, fw[i]->size);
+ pos += fw[i]->size;
+ }
+
+ /* Loading app */
+ app_img_info.cmd_id = APP_START_COMMAND;
+ app_img_info.mdt_len = fw_mdt->size;
+ app_img_info.img_len = size;
+ app_img_info.phy_addr = buff_phys;
+
+ /* SCM call to load the TZ APP */
+ rc = scm_call(SCM_SVC_TZSCHEDULER, 1, &app_img_info,
+ sizeof(struct load_app), &app_resp, sizeof(app_resp));
+ if (rc) {
+ rc = -EIO;
+ dev_err(ssm->dev, "SCM call to load APP failed\n");
+ goto ion_unmap;
+ }
+
+ if (app_resp.result == RESULT_FAILURE) {
+ rc = -EIO;
+ dev_err(ssm->dev, "SCM command to load TzAPP failed\n");
+ goto ion_unmap;
+ }
+
+ ssm->app_id = app_resp.data;
+ ssm->app_status = SUCCESS;
+
+ion_unmap:
+ ion_unmap_kernel(ssm_drv->ssm_ion_client, ion_handle);
+ion_free:
+ ion_free(ssm_drv->ssm_ion_client, ion_handle);
+release_blob:
+ while (--fw_count >= 0)
+ release_firmware(fw[fw_count]);
+ kfree(fw);
+release_mdt:
+ release_firmware(fw_mdt);
+out:
+ return rc;
+}
+
+/*
+ * Allocate buffer for transactions.
+ */
+static int ssm_setup_ion(struct ssm_driver *ssm)
+{
+ int rc = 0;
+ unsigned int size;
+
+ size = ALIGN_BUFFER(ATOM_MSG_LEN);
+
+ /* ION client for communicating with TZ */
+ ssm->ssm_ion_client = msm_ion_client_create(UINT_MAX,
+ "ssm-kernel");
+ if (IS_ERR_OR_NULL(ssm->ssm_ion_client)) {
+ rc = PTR_ERR(ssm->ssm_ion_client);
+ dev_err(ssm->dev, "Ion client not created\n");
+ return rc;
+ }
+
+ /* Setup a small ION buffer for tz communication */
+ ssm->ssm_ion_handle = ion_alloc(ssm->ssm_ion_client,
+ size, SZ_4K, ION_HEAP(ION_QSECOM_HEAP_ID), 0);
+ if (IS_ERR_OR_NULL(ssm->ssm_ion_handle)) {
+ rc = PTR_ERR(ssm->ssm_ion_handle);
+ dev_err(ssm->dev, "Unable to get ion handle\n");
+ goto out;
+ }
+
+ rc = ion_phys(ssm->ssm_ion_client, ssm->ssm_ion_handle,
+ &ssm->buff_phys, &ssm->buff_len);
+ if (rc < 0) {
+ dev_err(ssm->dev,
+ "Unable to get ion buffer physical address\n");
+ goto ion_free;
+ }
+
+ if (ssm->buff_len < size) {
+ rc = -ENOMEM;
+ goto ion_free;
+ }
+
+ ssm->buff_virt =
+ (ion_virt_addr_t)ion_map_kernel(ssm->ssm_ion_client,
+ ssm->ssm_ion_handle);
+ if (IS_ERR_OR_NULL((void *)ssm->buff_virt)) {
+ rc = PTR_ERR((void *)ssm->buff_virt);
+ dev_err(ssm->dev,
+ "Unable to get ion buffer virtual address\n");
+ goto ion_free;
+ }
+
+ return rc;
+
+ion_free:
+ ion_free(ssm->ssm_ion_client, ssm->ssm_ion_handle);
+out:
+ ion_client_destroy(ssm_drv->ssm_ion_client);
+ return rc;
+}
+
+static struct ssm_platform_data *populate_ssm_pdata(struct device *dev)
+{
+ struct ssm_platform_data *pdata;
+ int rc;
+
+ pdata = devm_kzalloc(dev, sizeof(struct ssm_platform_data),
+ GFP_KERNEL);
+ if (!pdata)
+ return NULL;
+
+ pdata->need_key_exchg =
+ of_property_read_bool(dev->of_node, "qcom,need-keyexhg");
+
+ rc = of_property_read_string(dev->of_node, "qcom,channel-name",
+ &pdata->channel_name);
+ if (rc && rc != -EINVAL) {
+ dev_err(dev, "Error reading channel_name property %d\n", rc);
+ return NULL;
+ } else if (rc == -EINVAL)
+ pdata->channel_name = CHANNEL_NAME;
+
+ return pdata;
+}
+
+static int __devinit ssm_probe(struct platform_device *pdev)
+{
+ int rc;
+ uint32_t system_call_id;
+ char legacy = '\0';
+ struct ssm_platform_data *pdata;
+ struct ssm_driver *drv;
+
+ if (pdev->dev.of_node)
+ pdata = populate_ssm_pdata(&pdev->dev);
+ else
+ pdata = pdev->dev.platform_data;
+
+ if (!pdata) {
+ dev_err(&pdev->dev, "Empty platform data\n");
+ return -ENOMEM;
+ }
+
+ drv = devm_kzalloc(&pdev->dev, sizeof(struct ssm_driver),
+ GFP_KERNEL);
+ if (!drv) {
+ dev_err(&pdev->dev, "Unable to allocate memory\n");
+ return -ENOMEM;
+ }
+
+ /* Initialize the driver structure */
+ drv->atom_replay = -1;
+ drv->mtoa_replay = -1;
+ drv->app_id = -1;
+ drv->app_status = RETRY;
+ drv->ready = false;
+ drv->update_status = FAILED;
+ mutex_init(&drv->mutex);
+ drv->key_status = !pdata->need_key_exchg;
+ drv->channel_name = (char *)pdata->channel_name;
+ INIT_WORK(&drv->ipc_work, ssm_app_modem_work_fn);
+
+ /* Allocate memory for smd buffer */
+ drv->smd_buffer = devm_kzalloc(&pdev->dev,
+ (sizeof(char) * ATOM_MSG_LEN), GFP_KERNEL);
+ if (!drv->smd_buffer) {
+ rc = -ENOMEM;
+ goto exit;
+ }
+
+ /* Allocate response buffer */
+ drv->resp = devm_kzalloc(&pdev->dev,
+ sizeof(struct tzapp_get_mode_info_rsp),
+ GFP_KERNEL);
+ if (!drv->resp) {
+ rc = -ENOMEM;
+ goto exit;
+ }
+
+
+ /* Check for TZ version */
+ system_call_id = QSEOS_CHECK_VERSION_CMD;
+ rc = scm_call(SCM_SVC_INFO, SSM_INFO_CMD_ID, &system_call_id,
+ sizeof(system_call_id), &legacy, sizeof(legacy));
+ if (rc) {
+ dev_err(&pdev->dev, "Get version failed %d\n", rc);
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ /* This driver only support 1.4 TZ and QSEOS */
+ if (!legacy) {
+ dev_err(&pdev->dev,
+ "Driver doesn't support legacy version\n");
+ rc = -EINVAL;
+ goto exit;
+
+ }
+
+ /* Setup the ion buffer for transaction */
+ rc = ssm_setup_ion(drv);
+ if (rc < 0)
+ goto exit;
+
+ drv->dev = &pdev->dev;
+ ssm_drv = drv;
+ platform_set_drvdata(pdev, ssm_drv);
+
+ dev_dbg(&pdev->dev, "probe success\n");
+ return 0;
+
+exit:
+ mutex_destroy(&drv->mutex);
+ platform_set_drvdata(pdev, NULL);
+ return rc;
+
+}
+
+static int __devexit ssm_remove(struct platform_device *pdev)
+{
+ int rc;
+
+ struct scm_shutdown_req req;
+ struct scm_resp resp;
+
+ if (!ssm_drv)
+ return 0;
+ /*
+ * Step to exit
+ * 1. set ready to 0 (oem access closed).
+ * 2. Close SMD modem connection closed.
+ * 3. cleanup ion.
+ */
+ ssm_drv->ready = false;
+ smd_close(ssm_drv->ch);
+ flush_work_sync(&ssm_drv->ipc_work);
+
+ /* ION clean up*/
+ ion_unmap_kernel(ssm_drv->ssm_ion_client, ssm_drv->ssm_ion_handle);
+ ion_free(ssm_drv->ssm_ion_client, ssm_drv->ssm_ion_handle);
+ ion_client_destroy(ssm_drv->ssm_ion_client);
+
+ /* Shutdown tzapp */
+ req.app_id = ssm_drv->app_id;
+ req.cmd_id = APP_SHUTDOWN_COMMAND;
+ rc = scm_call(SCM_SVC_TZSCHEDULER, 1, &req, sizeof(req),
+ &resp, sizeof(resp));
+ if (rc)
+ dev_err(&pdev->dev, "TZ_app Unload failed\n");
+
+ return rc;
+}
+
+static struct of_device_id ssm_match_table[] = {
+ {
+ .compatible = "qcom,ssm",
+ },
+ {}
+};
+
+static struct platform_driver ssm_pdriver = {
+ .probe = ssm_probe,
+ .remove = __devexit_p(ssm_remove),
+ .driver = {
+ .name = SSM_DEV_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = ssm_match_table,
+ },
+};
+module_platform_driver(ssm_pdriver);
+
+/*
+ * Interface for external OEM driver.
+ * This interface supports following functionalities:
+ * 1. Get TZAPP ID.
+ * 2. Set default mode.
+ * 3. Set mode (encrypted mode and it's length is passed as parameter).
+ * 4. Set mode from TZ.
+ * 5. Get status of mode update.
+ *
+ */
+int ssm_oem_driver_intf(int cmd, char *mode, int len)
+{
+ int rc, req_len, resp_len;
+ struct tzapp_get_mode_info_req get_mode_req;
+ struct tzapp_get_mode_info_rsp *get_mode_resp;
+
+ /* If ssm_drv is NULL, probe failed */
+ if (!ssm_drv)
+ return -ENODEV;
+
+ mutex_lock(&ssm_drv->mutex);
+
+ if (ssm_drv->app_status == RETRY) {
+ /* Load TZAPP */
+ rc = ssm_load_app(ssm_drv);
+ if (rc) {
+ rc = -ENODEV;
+ ssm_drv->app_status = FAILED;
+ goto unlock;
+ }
+ } else if (ssm_drv->app_status == FAILED) {
+ rc = -ENODEV;
+ goto unlock;
+ }
+
+ /* Open modem SMD interface */
+ if (!ssm_drv->ready) {
+ rc = smd_open(ssm_drv->channel_name, &ssm_drv->ch, ssm_drv,
+ modem_request);
+ if (rc) {
+ rc = -EAGAIN;
+ goto unlock;
+ } else
+ ssm_drv->ready = true;
+ }
+
+ /* Try again modem key-exchange not yet done.*/
+ if (!ssm_drv->key_status) {
+ rc = -EAGAIN;
+ goto unlock;
+ }
+
+ /* Set return status to success */
+ rc = 0;
+
+ switch (cmd) {
+ case SSM_READY:
+ break;
+
+ case SSM_GET_APP_ID:
+ rc = ssm_drv->app_id;
+ break;
+
+ case SSM_MODE_INFO_READY:
+ ssm_drv->update_status = RETRY;
+ /* Fill command structure */
+ req_len = sizeof(struct tzapp_get_mode_info_req);
+ resp_len = sizeof(struct tzapp_get_mode_info_rsp);
+ get_mode_req.tzapp_ssm_cmd = GET_ENC_MODE;
+ rc = tz_scm_call(ssm_drv, (void *)&get_mode_req,
+ req_len, (void **)&get_mode_resp, resp_len);
+ if (rc) {
+ ssm_drv->update_status = FAILED;
+ break;
+ }
+
+ /* Send mode_info to modem */
+ rc = update_modem(SSM_ATOM_MODE_UPDATE, ssm_drv,
+ get_mode_resp->enc_mode_len,
+ get_mode_resp->enc_mode_info);
+ if (rc)
+ ssm_drv->update_status = FAILED;
+ break;
+
+ case SSM_SET_MODE:
+ ssm_drv->update_status = RETRY;
+
+ if (len > ENC_MODE_MAX_SIZE) {
+ ssm_drv->update_status = FAILED;
+ rc = -EINVAL;
+ break;
+ }
+ memcpy(ssm_drv->resp->enc_mode_info, mode, len);
+ ssm_drv->resp->enc_mode_len = len;
+
+ /* Send mode_info to modem */
+ rc = update_modem(SSM_ATOM_MODE_UPDATE, ssm_drv,
+ ssm_drv->resp->enc_mode_len,
+ ssm_drv->resp->enc_mode_info);
+ if (rc)
+ ssm_drv->update_status = FAILED;
+ break;
+
+ case SSM_GET_MODE_STATUS:
+ rc = ssm_drv->update_status;
+ break;
+
+ case SSM_SET_DEFAULT_MODE:
+ /* Modem does not send response for this */
+ ssm_drv->update_status = RETRY;
+ rc = update_modem(SSM_ATOM_SET_DEFAULT_MODE, ssm_drv,
+ 1, "0");
+ if (rc)
+ ssm_drv->update_status = FAILED;
+ else
+ /* For default mode we don't get any resp
+ * from modem.
+ */
+ ssm_drv->update_status = SUCCESS;
+ break;
+ default:
+ rc = -EINVAL;
+ dev_err(ssm_drv->dev, "Invalid command\n");
+ break;
+ };
+
+unlock:
+ mutex_unlock(&ssm_drv->mutex);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(ssm_oem_driver_intf);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Qualcomm Secure Service Module");
+
diff --git a/drivers/platform/msm/ssm.h b/drivers/platform/msm/ssm.h
new file mode 100644
index 0000000..97add11
--- /dev/null
+++ b/drivers/platform/msm/ssm.h
@@ -0,0 +1,160 @@
+/* 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 __SSM_H_
+#define __SSM_H_
+
+#define MAX_APP_NAME_SIZE 32
+#define MODE_INFO_MAX_SIZE 4
+#define ENC_MODE_MAX_SIZE (100 + MODE_INFO_MAX_SIZE)
+
+/* tzapp response.*/
+enum tz_response {
+ RESULT_SUCCESS = 0,
+ RESULT_FAILURE = 0xFFFFFFFF,
+};
+
+/* tzapp command list.*/
+enum tz_commands {
+ ENC_MODE,
+ GET_ENC_MODE,
+ KEY_EXCHANGE = 11,
+};
+
+/* Command list for QSEOS.*/
+enum qceos_cmd_id {
+ APP_START_COMMAND = 0x01,
+ APP_SHUTDOWN_COMMAND,
+ APP_LOOKUP_COMMAND,
+ CLIENT_SEND_DATA_COMMAND = 0x6,
+ QSEOS_CMD_MAX = 0xEFFFFFFF,
+};
+
+/* MODEM/SSM command list.*/
+enum ssm_ipc_req {
+ SSM_MTOA_KEY_EXCHANGE = 0x0000AAAA,
+ SSM_ATOM_KEY_STATUS,
+ SSM_ATOM_MODE_UPDATE,
+ SSM_MTOA_MODE_UPDATE_STATUS,
+ SSM_MTOA_PREV_INVALID,
+ SSM_ATOM_PREV_INVALID,
+ SSM_ATOM_SET_DEFAULT_MODE,
+ SSM_INVALID_REQ,
+};
+
+/* OEM reuest commands list.*/
+enum oem_req {
+ SSM_READY,
+ SSM_GET_APP_ID,
+ SSM_MODE_INFO_READY,
+ SSM_SET_MODE,
+ SSM_GET_MODE_STATUS,
+ SSM_SET_DEFAULT_MODE,
+ SSM_INVALID,
+};
+
+/* Modem mode update status.*/
+enum modem_mode_status {
+ SUCCESS,
+ RETRY,
+ FAILED = -1,
+};
+
+__packed struct load_app {
+ uint32_t cmd_id;
+ uint32_t mdt_len;
+ uint32_t img_len;
+ uint32_t phy_addr;
+ char app_name[MAX_APP_NAME_SIZE];
+};
+
+/* Stop tzapp reuest.*/
+__packed struct scm_shutdown_req {
+ uint32_t cmd_id;
+ uint32_t app_id;
+};
+
+/* Common tzos response.*/
+__packed struct scm_resp {
+ uint32_t result;
+ enum tz_response resp_type;
+ unsigned int data;
+};
+
+/* tzos request.*/
+__packed struct check_app_req {
+ uint32_t cmd_id;
+ char app_name[MAX_APP_NAME_SIZE];
+};
+
+/* tzapp encode mode reuest.*/
+__packed struct tzapp_mode_enc_req {
+ uint32_t tzapp_ssm_cmd;
+ uint8_t mode_info[4];
+};
+
+/* tzapp encode mode response.*/
+__packed struct tzapp_mode_enc_rsp {
+ uint32_t tzapp_ssm_cmd;
+ uint8_t enc_mode_info[ENC_MODE_MAX_SIZE];
+ uint32_t enc_mode_len;
+ long status;
+};
+
+/* tzapp get mode request.*/
+__packed struct tzapp_get_mode_info_req {
+ uint32_t tzapp_ssm_cmd;
+};
+
+/* tzapp get mode response.*/
+__packed struct tzapp_get_mode_info_rsp {
+ uint32_t tzapp_ssm_cmd;
+ uint8_t enc_mode_info[ENC_MODE_MAX_SIZE];
+ uint32_t enc_mode_len;
+ long status;
+};
+
+/* tzos key exchange request.*/
+__packed struct ssm_keyexchg_req {
+ uint32_t ssid;
+ void *address;
+ uint32_t length;
+ uint32_t *status;
+};
+
+/* tzos common request.*/
+__packed struct common_req {
+ uint32_t cmd_id;
+ uint32_t app_id;
+ void *req_ptr;
+ uint32_t req_len;
+ void *resp_ptr;
+ uint32_t resp_len;
+};
+
+/* tzos common response.*/
+__packed struct common_resp {
+ uint32_t result;
+ uint32_t type;
+ uint32_t data;
+};
+
+/* Modem/SSM packet format.*/
+struct ssm_common_msg {
+ unsigned long pktlen;
+ unsigned long replaynum;
+ enum ssm_ipc_req ipc_req;
+ unsigned long msg_len;
+ char *msg;
+};
+
+#endif
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index 13e23e8..c5b1db4 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -128,7 +128,6 @@
int catch_up_time_us;
enum battery_type batt_type;
uint16_t ocv_reading_at_100;
- int cc_reading_at_100;
int max_voltage_uv;
int chg_term_ua;
@@ -1042,10 +1041,8 @@
}
/* stop faking 100% after an OCV event */
- if (chip->ocv_reading_at_100 != raw->last_good_ocv_raw) {
+ if (chip->ocv_reading_at_100 != raw->last_good_ocv_raw)
chip->ocv_reading_at_100 = OCV_RAW_UNINITIALIZED;
- chip->cc_reading_at_100 = 0;
- }
pr_debug("0p625 = %duV\n", chip->xoadc_v0625);
pr_debug("1p25 = %duV\n", chip->xoadc_v125);
pr_debug("last_good_ocv_raw= 0x%x, last_good_ocv_uv= %duV\n",
@@ -1185,10 +1182,7 @@
int64_t cc_voltage_uv, cc_pvh, cc_uah;
cc_voltage_uv = cc;
- cc_voltage_uv -= chip->cc_reading_at_100;
- pr_debug("cc = %d. after subtracting 0x%x cc = %lld\n",
- cc, chip->cc_reading_at_100,
- cc_voltage_uv);
+ pr_debug("cc = %d\n", cc);
cc_voltage_uv = cc_to_microvolt(chip, cc_voltage_uv);
cc_voltage_uv = pm8xxx_cc_adjust_for_gain(cc_voltage_uv);
pr_debug("cc_voltage_uv = %lld microvolts\n", cc_voltage_uv);
@@ -1513,10 +1507,7 @@
/* calculate cc micro_volt_hour */
calculate_cc_uah(chip, raw->cc, cc_uah);
- pr_debug("cc_uah = %duAh raw->cc = %x cc = %lld after subtracting %x\n",
- *cc_uah, raw->cc,
- (int64_t)raw->cc - chip->cc_reading_at_100,
- chip->cc_reading_at_100);
+ pr_debug("cc_uah = %duAh raw->cc = %x\n", *cc_uah, raw->cc);
soc_rbatt = ((*remaining_charge_uah - *cc_uah) * 100) / *fcc_uah;
if (soc_rbatt < 0)
@@ -2653,19 +2644,20 @@
if (is_battery_full) {
the_chip->ocv_reading_at_100 = raw.last_good_ocv_raw;
- the_chip->cc_reading_at_100 = raw.cc;
the_chip->last_ocv_uv = the_chip->max_voltage_uv;
raw.last_good_ocv_uv = the_chip->max_voltage_uv;
+ raw.cc = 0;
+ /* reset the cc in h/w */
+ reset_cc(the_chip);
the_chip->last_ocv_temp_decidegc = batt_temp;
/*
* since we are treating this as an ocv event
* forget the old cc value
*/
the_chip->last_cc_uah = 0;
- pr_debug("EOC BATT_FULL ocv_reading = 0x%x cc = 0x%x\n",
- the_chip->ocv_reading_at_100,
- the_chip->cc_reading_at_100);
+ pr_debug("EOC BATT_FULL ocv_reading = 0x%x\n",
+ the_chip->ocv_reading_at_100);
}
the_chip->end_percent = calculate_state_of_charge(the_chip, &raw,
diff --git a/drivers/thermal/msm8974-tsens.c b/drivers/thermal/msm8974-tsens.c
index e37b3c4..482d383 100644
--- a/drivers/thermal/msm8974-tsens.c
+++ b/drivers/thermal/msm8974-tsens.c
@@ -63,7 +63,7 @@
#define TSENS_SN_REMOTE_CONFIG(n) ((n) + 0x3c)
#define TSENS_EEPROM(n) ((n) + 0xd0)
-#define TSENS_EEPROM_REDUNDANCY_SEL(n) ((n) + 0x1cc)
+#define TSENS_EEPROM_REDUNDANCY_SEL(n) ((n) + 0x444)
#define TSENS_EEPROM_BACKUP_REGION(n) ((n) + 0x440)
#define TSENS_MAIN_CALIB_ADDR_RANGE 6
diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c
index a27322e..c982587 100644
--- a/drivers/tty/serial/msm_serial_hs.c
+++ b/drivers/tty/serial/msm_serial_hs.c
@@ -2861,7 +2861,7 @@
if (unlikely(msm_uport->wakeup.irq < 0)) {
ret = -ENXIO;
- goto unmap_memory;
+ goto deregister_bus_client;
}
if (is_blsp_uart(msm_uport)) {
@@ -2878,7 +2878,7 @@
IORESOURCE_DMA, "uartdm_channels");
if (unlikely(!resource)) {
ret = -ENXIO;
- goto unmap_memory;
+ goto deregister_bus_client;
}
msm_uport->dma_tx_channel = resource->start;
@@ -2888,7 +2888,7 @@
IORESOURCE_DMA, "uartdm_crci");
if (unlikely(!resource)) {
ret = -ENXIO;
- goto unmap_memory;
+ goto deregister_bus_client;
}
msm_uport->dma_tx_crci = resource->start;
@@ -2905,7 +2905,7 @@
msm_uport->clk = clk_get(&pdev->dev, "core_clk");
if (IS_ERR(msm_uport->clk)) {
ret = PTR_ERR(msm_uport->clk);
- goto unmap_memory;
+ goto deregister_bus_client;
}
msm_uport->pclk = clk_get(&pdev->dev, "iface_clk");
@@ -2919,7 +2919,7 @@
ret = clk_set_rate(msm_uport->clk, uport->uartclk);
if (ret) {
printk(KERN_WARNING "Error setting clock rate on UART\n");
- goto unmap_memory;
+ goto put_clk;
}
msm_uport->hsuart_wq = alloc_workqueue("k_hsuart",
@@ -2928,7 +2928,7 @@
pr_err("%s(): Unable to create workqueue hsuart_wq\n",
__func__);
ret = -ENOMEM;
- goto unmap_memory;
+ goto put_clk;
}
INIT_WORK(&msm_uport->clock_off_w, hsuart_clock_off_work);
@@ -2946,7 +2946,7 @@
ret = msm_hs_sps_init(msm_uport);
if (unlikely(ret)) {
pr_err("SPS Initialization failed ! err=%d", ret);
- goto workqueue_destroy;
+ goto destroy_mutex;
}
}
@@ -2989,7 +2989,6 @@
uport->line = pdata->userid;
ret = uart_add_one_port(&msm_hs_driver, uport);
if (!ret) {
-
msm_hs_bus_voting(msm_uport, BUS_RESET);
clk_disable_unprepare(msm_uport->clk);
if (msm_uport->pclk)
@@ -3003,8 +3002,21 @@
clk_disable_unprepare(msm_uport->clk);
if (msm_uport->pclk)
clk_disable_unprepare(msm_uport->pclk);
-workqueue_destroy:
+
+destroy_mutex:
+ mutex_destroy(&msm_uport->clk_mutex);
destroy_workqueue(msm_uport->hsuart_wq);
+
+put_clk:
+ if (msm_uport->pclk)
+ clk_put(msm_uport->pclk);
+
+ if (msm_uport->clk)
+ clk_put(msm_uport->clk);
+
+deregister_bus_client:
+ if (is_blsp_uart(msm_uport))
+ msm_bus_scale_unregister_client(msm_uport->bus_perf_client);
unmap_memory:
iounmap(uport->membase);
if (is_blsp_uart(msm_uport))
diff --git a/drivers/tty/serial/msm_serial_hs_lite.c b/drivers/tty/serial/msm_serial_hs_lite.c
index c9f4199..8069b35 100644
--- a/drivers/tty/serial/msm_serial_hs_lite.c
+++ b/drivers/tty/serial/msm_serial_hs_lite.c
@@ -2,7 +2,7 @@
* drivers/serial/msm_serial.c - driver for msm7k serial device and console
*
* Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -1257,6 +1257,9 @@
{
int ret;
struct msm_hsl_port *msm_hsl_port = UART_TO_MSM(port);
+ struct platform_device *pdev = to_platform_device(port->dev);
+ const struct msm_serial_hslite_platform_data *pdata =
+ pdev->dev.platform_data;
switch (state) {
case 0:
@@ -1268,9 +1271,11 @@
break;
case 3:
clk_en(port, 0);
- ret = clk_set_rate(msm_hsl_port->clk, 0);
- if (ret)
- pr_err("Error setting UART clock rate to zero.\n");
+ if (pdata && pdata->set_uart_clk_zero) {
+ ret = clk_set_rate(msm_hsl_port->clk, 0);
+ if (ret)
+ pr_err("Error setting UART clock rate to zero.\n");
+ }
break;
default:
pr_err("Unknown PM state %d\n", state);
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index 76d75ea..8e25780 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -53,7 +53,9 @@
#include "f_rmnet_sdio.c"
#include "f_rmnet_smd_sdio.c"
#include "f_rmnet.c"
+#ifdef CONFIG_SND_PCM
#include "f_audio_source.c"
+#endif
#include "f_mass_storage.c"
#include "u_serial.c"
#include "u_sdio.c"
@@ -1591,6 +1593,7 @@
.ctrlrequest = accessory_function_ctrlrequest,
};
+#ifdef CONFIG_SND_PCM
static int audio_source_function_init(struct android_usb_function *f,
struct usb_composite_dev *cdev)
{
@@ -1652,6 +1655,7 @@
.unbind_config = audio_source_function_unbind_config,
.attributes = audio_source_function_attributes,
};
+#endif
static int android_uasp_connect_cb(bool connect)
{
@@ -1722,7 +1726,9 @@
&ecm_function,
&mass_storage_function,
&accessory_function,
+#ifdef CONFIG_SND_PCM
&audio_source_function,
+#endif
&uasp_function,
NULL
};
@@ -2045,6 +2051,7 @@
struct android_configuration *conf;
int enabled = 0;
bool audio_enabled = false;
+ static DEFINE_RATELIMIT_STATE(rl, 10*HZ, 1);
if (!cdev)
return -ENODEV;
@@ -2090,7 +2097,7 @@
f_holder->f->disable(f_holder->f);
}
dev->enabled = false;
- } else {
+ } else if (__ratelimit(&rl)) {
pr_err("android_usb: already %s\n",
dev->enabled ? "enabled" : "disabled");
}
diff --git a/drivers/usb/gadget/f_adb.c b/drivers/usb/gadget/f_adb.c
index a55f0e5..ff2287e 100644
--- a/drivers/usb/gadget/f_adb.c
+++ b/drivers/usb/gadget/f_adb.c
@@ -463,7 +463,10 @@
static int adb_open(struct inode *ip, struct file *fp)
{
- pr_info("adb_open\n");
+ static DEFINE_RATELIMIT_STATE(rl, 10*HZ, 1);
+
+ if (__ratelimit(&rl))
+ pr_info("adb_open\n");
if (!_adb_dev)
return -ENODEV;
@@ -486,7 +489,10 @@
static int adb_release(struct inode *ip, struct file *fp)
{
- pr_info("adb_release\n");
+ static DEFINE_RATELIMIT_STATE(rl, 10*HZ, 1);
+
+ if (__ratelimit(&rl))
+ pr_info("adb_release\n");
/*
* ADB daemon closes the device file after I/O error. The
diff --git a/drivers/usb/gadget/f_mbim.c b/drivers/usb/gadget/f_mbim.c
index d69e850..ff0bdaf 100644
--- a/drivers/usb/gadget/f_mbim.c
+++ b/drivers/usb/gadget/f_mbim.c
@@ -295,6 +295,7 @@
/* MBIM control descriptors */
(struct usb_descriptor_header *) &mbim_control_intf,
(struct usb_descriptor_header *) &mbim_header_desc,
+ (struct usb_descriptor_header *) &mbim_union_desc,
(struct usb_descriptor_header *) &mbb_desc,
(struct usb_descriptor_header *) &ext_mbb_desc,
(struct usb_descriptor_header *) &fs_mbim_notify_desc,
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 38a3c15..323b481 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -145,29 +145,37 @@
*/
static void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring)
{
- union xhci_trb *next;
unsigned long long addr;
ring->deq_updates++;
- /* If this is not event ring, there is one more usable TRB */
+ /*
+ * If this is not event ring, and the dequeue pointer
+ * is not on a link TRB, there is one more usable TRB
+ */
if (ring->type != TYPE_EVENT &&
!last_trb(xhci, ring, ring->deq_seg, ring->dequeue))
ring->num_trbs_free++;
- next = ++(ring->dequeue);
- /* Update the dequeue pointer further if that was a link TRB or we're at
- * the end of an event ring segment (which doesn't have link TRBS)
- */
- while (last_trb(xhci, ring, ring->deq_seg, next)) {
- if (ring->type == TYPE_EVENT && last_trb_on_last_seg(xhci,
- ring, ring->deq_seg, next)) {
- ring->cycle_state = (ring->cycle_state ? 0 : 1);
+ do {
+ /*
+ * Update the dequeue pointer further if that was a link TRB or
+ * we're at the end of an event ring segment (which doesn't have
+ * link TRBS)
+ */
+ if (last_trb(xhci, ring, ring->deq_seg, ring->dequeue)) {
+ if (ring->type == TYPE_EVENT &&
+ last_trb_on_last_seg(xhci, ring,
+ ring->deq_seg, ring->dequeue)) {
+ ring->cycle_state = (ring->cycle_state ? 0 : 1);
+ }
+ ring->deq_seg = ring->deq_seg->next;
+ ring->dequeue = ring->deq_seg->trbs;
+ } else {
+ ring->dequeue++;
}
- ring->deq_seg = ring->deq_seg->next;
- ring->dequeue = ring->deq_seg->trbs;
- next = ring->dequeue;
- }
+ } while (last_trb(xhci, ring, ring->deq_seg, ring->dequeue));
+
addr = (unsigned long long) xhci_trb_virt_to_dma(ring->deq_seg, ring->dequeue);
}
@@ -885,6 +893,17 @@
num_trbs_free_temp = ep_ring->num_trbs_free;
dequeue_temp = ep_ring->dequeue;
+ /* If we get two back-to-back stalls, and the first stalled transfer
+ * ends just before a link TRB, the dequeue pointer will be left on
+ * the link TRB by the code in the while loop. So we have to update
+ * the dequeue pointer one segment further, or we'll jump off
+ * the segment into la-la-land.
+ */
+ if (last_trb(xhci, ep_ring, ep_ring->deq_seg, ep_ring->dequeue)) {
+ ep_ring->deq_seg = ep_ring->deq_seg->next;
+ ep_ring->dequeue = ep_ring->deq_seg->trbs;
+ }
+
while (ep_ring->dequeue != dev->eps[ep_index].queued_deq_ptr) {
/* We have more usable TRBs */
ep_ring->num_trbs_free++;
diff --git a/drivers/video/msm/mdss/mdss_dsi.c b/drivers/video/msm/mdss/mdss_dsi.c
index 54eaabb..99eea82 100644
--- a/drivers/video/msm/mdss/mdss_dsi.c
+++ b/drivers/video/msm/mdss/mdss_dsi.c
@@ -135,8 +135,8 @@
pr_err("%s: Failed to enable regulator.\n", __func__);
return ret;
}
-
- mdss_dsi_panel_reset(pdata, 1);
+ if (pdata->panel_info.panel_power_on == 0)
+ mdss_dsi_panel_reset(pdata, 1);
} else {
@@ -222,6 +222,13 @@
return -EINVAL;
}
+ if (!pdata->panel_info.panel_power_on) {
+ pr_warn("%s:%d Panel already off.\n", __func__, __LINE__);
+ return -EPERM;
+ }
+
+ pdata->panel_info.panel_power_on = 0;
+
ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
panel_data);
mdss_dsi_clk_disable(pdata);
@@ -241,7 +248,38 @@
return ret;
}
-static int mdss_dsi_on(struct mdss_panel_data *pdata)
+int mdss_dsi_cont_splash_on(struct mdss_panel_data *pdata)
+{
+ int ret = 0;
+ struct mipi_panel_info *mipi;
+
+ pr_info("%s:%d DSI on for continuous splash.\n", __func__, __LINE__);
+
+ if (pdata == NULL) {
+ pr_err("%s: Invalid input data\n", __func__);
+ return -EINVAL;
+ }
+
+ mipi = &pdata->panel_info.mipi;
+
+ ret = mdss_dsi_panel_power_on(pdata, 1);
+ if (ret) {
+ pr_err("%s: Panel power on failed\n", __func__);
+ return ret;
+ }
+ mdss_dsi_sw_reset(pdata);
+ mdss_dsi_host_init(mipi, pdata);
+
+ pdata->panel_info.panel_power_on = 1;
+
+ mdss_dsi_op_mode_config(mipi->mode, pdata);
+
+ pr_debug("%s-:End\n", __func__);
+ return ret;
+}
+
+
+int mdss_dsi_on(struct mdss_panel_data *pdata)
{
int ret = 0;
u32 clk_rate;
@@ -257,6 +295,11 @@
return -EINVAL;
}
+ if (pdata->panel_info.panel_power_on) {
+ pr_warn("%s:%d Panel already on.\n", __func__, __LINE__);
+ return 0;
+ }
+
ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
panel_data);
pinfo = &pdata->panel_info;
@@ -267,6 +310,8 @@
return ret;
}
+ pdata->panel_info.panel_power_on = 1;
+
mdss_dsi_phy_sw_reset((ctrl_pdata->ctrl_base));
mdss_dsi_phy_init(pdata);
@@ -394,6 +439,16 @@
}
rc = mdss_dsi_off(pdata);
break;
+ case MDSS_EVENT_CONT_SPLASH_FINISH:
+ if (ctrl_pdata->on_cmds->ctrl_state == DSI_LP_MODE) {
+ rc = mdss_dsi_cont_splash_on(pdata);
+ } else {
+ pr_debug("%s:event=%d, Dsi On not called: ctrl_state: %d\n",
+ __func__, event,
+ ctrl_pdata->on_cmds->ctrl_state);
+ rc = -EINVAL;
+ }
+ break;
default:
pr_debug("%s: unhandled event=%d\n", __func__, event);
break;
@@ -542,6 +597,7 @@
struct platform_device *ctrl_pdev = NULL;
unsigned char *ctrl_addr;
bool broadcast;
+ bool cont_splash_enabled = false;
h_period = ((panel_data->panel_info.lcdc.h_pulse_width)
+ (panel_data->panel_info.lcdc.h_back_porch)
@@ -649,13 +705,6 @@
gpio_free(ctrl_pdata->disp_en_gpio);
return -ENODEV;
}
- rc = gpio_direction_output(ctrl_pdata->disp_en_gpio, 1);
- if (rc) {
- pr_err("set_direction for disp_en gpio failed, rc=%d\n",
- rc);
- gpio_free(ctrl_pdata->disp_en_gpio);
- return -ENODEV;
- }
}
ctrl_pdata->rst_gpio = of_get_named_gpio(pdev->dev.of_node,
@@ -705,6 +754,28 @@
/*
* register in mdp driver
*/
+
+ cont_splash_enabled = of_property_read_bool(pdev->dev.of_node,
+ "qcom,cont-splash-enabled");
+ if (!cont_splash_enabled) {
+ pr_info("%s:%d Continous splash flag not found.\n",
+ __func__, __LINE__);
+ ctrl_pdata->panel_data.panel_info.cont_splash_enabled = 0;
+ ctrl_pdata->panel_data.panel_info.panel_power_on = 0;
+ } else {
+ pr_info("%s:%d Continous splash flag enabled.\n",
+ __func__, __LINE__);
+
+ ctrl_pdata->panel_data.panel_info.cont_splash_enabled = 1;
+ ctrl_pdata->panel_data.panel_info.panel_power_on = 1;
+ }
+
+
+ if (ctrl_pdata->panel_data.panel_info.cont_splash_enabled) {
+ mdss_dsi_prepare_clocks(ctrl_pdata);
+ mdss_dsi_clk_enable(&(ctrl_pdata->panel_data));
+ }
+
rc = mdss_register_panel(ctrl_pdev, &(ctrl_pdata->panel_data));
if (rc) {
dev_err(&pdev->dev, "unable to register MIPI DSI panel\n");
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index 5c89938..bb29842 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -732,11 +732,9 @@
return -ENOMEM;
}
phys = memory_pool_node_paddr(virt);
- if (is_mdss_iommu_attached()) {
- dom = mdss_get_iommu_domain(MDSS_IOMMU_DOMAIN_UNSECURE);
- msm_iommu_map_contig_buffer(phys, dom, 0, size, SZ_4K,
- 0, &(mfd->iova));
- }
+ dom = mdss_get_iommu_domain(MDSS_IOMMU_DOMAIN_UNSECURE);
+ msm_iommu_map_contig_buffer(phys, dom, 0, size, SZ_4K,
+ 0, &(mfd->iova));
pr_info("allocating %u bytes at %p (%lx phys) for fb %d\n",
size, virt, phys, mfd->index);
} else {
@@ -1063,7 +1061,8 @@
static void mdss_fb_signal_timeline_locked(struct msm_fb_data_type *mfd)
{
- if (mfd->timeline) {
+ if (mfd->timeline && !list_empty((const struct list_head *)
+ (&(mfd->timeline->obj.active_list_head)))) {
sw_sync_timeline_inc(mfd->timeline, 1);
mfd->timeline_value++;
}
@@ -1449,32 +1448,32 @@
switch (mdp_pp.op) {
case mdp_op_pa_cfg:
- ret = mdss_mdp_pa_config(&mdp_pp.data.pa_cfg_data,
+ ret = mdss_mdp_pa_config(mfd->ctl, &mdp_pp.data.pa_cfg_data,
©back);
break;
case mdp_op_pcc_cfg:
- ret = mdss_mdp_pcc_config(&mdp_pp.data.pcc_cfg_data,
+ ret = mdss_mdp_pcc_config(mfd->ctl, &mdp_pp.data.pcc_cfg_data,
©back);
break;
case mdp_op_lut_cfg:
switch (mdp_pp.data.lut_cfg_data.lut_type) {
case mdp_lut_igc:
- ret = mdss_mdp_igc_lut_config(
+ ret = mdss_mdp_igc_lut_config(mfd->ctl,
(struct mdp_igc_lut_data *)
&mdp_pp.data.lut_cfg_data.data,
©back);
break;
case mdp_lut_pgc:
- ret = mdss_mdp_argc_config(
+ ret = mdss_mdp_argc_config(mfd->ctl,
&mdp_pp.data.lut_cfg_data.data.pgc_lut_data,
©back);
break;
case mdp_lut_hist:
- ret = mdss_mdp_hist_lut_config(
+ ret = mdss_mdp_hist_lut_config(mfd->ctl,
(struct mdp_hist_lut_data *)
&mdp_pp.data.lut_cfg_data.data, ©back);
break;
@@ -1485,12 +1484,12 @@
}
break;
case mdp_op_dither_cfg:
- ret = mdss_mdp_dither_config(&mdp_pp.data.dither_cfg_data,
- ©back);
+ ret = mdss_mdp_dither_config(mfd->ctl,
+ &mdp_pp.data.dither_cfg_data, ©back);
break;
case mdp_op_gamut_cfg:
- ret = mdss_mdp_gamut_config(&mdp_pp.data.gamut_cfg_data,
- ©back);
+ ret = mdss_mdp_gamut_config(mfd->ctl,
+ &mdp_pp.data.gamut_cfg_data, ©back);
break;
case mdp_bl_scale_cfg:
ret = mdss_bl_scale_config(mfd, (struct mdp_bl_scale_data *)
@@ -1676,7 +1675,7 @@
if (ret)
return ret;
- ret = mdss_mdp_hist_collect(info, &hist, &hist_data_addr);
+ ret = mdss_mdp_hist_collect(mfd->ctl, &hist, &hist_data_addr);
if ((ret == 0) && hist_data_addr) {
ret = copy_to_user(hist.c0, (u32 *)hist_data_addr,
sizeof(u32) * hist.bin_cnt);
@@ -1694,7 +1693,7 @@
if (ret)
return ret;
- ret = mdss_mdp_histogram_start(&hist_req);
+ ret = mdss_mdp_histogram_start(mfd->ctl, &hist_req);
break;
case MSMFB_HISTOGRAM_STOP:
@@ -1702,7 +1701,7 @@
if (ret)
return ret;
- ret = mdss_mdp_histogram_stop(block);
+ ret = mdss_mdp_histogram_stop(mfd->ctl, block);
break;
case MSMFB_GET_PAGE_PROTECTION:
@@ -1844,6 +1843,16 @@
fb_pdev->dev.platform_data = pdata;
}
+ /*
+ * Clocks are already on if continuous splash is enabled,
+ * increasing ref_cnt to help balance clocks once done.
+ */
+ if (pdata->panel_info.cont_splash_enabled) {
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+ mdss_mdp_footswitch_ctrl_splash(1);
+ mdss_mdp_copy_splash_screen(pdata);
+ }
+
mdss_notfound:
of_node_put(node);
diff --git a/drivers/video/msm/mdss/mdss_hdmi_edid.c b/drivers/video/msm/mdss/mdss_hdmi_edid.c
index 1aae22e..08be337 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_edid.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_edid.c
@@ -240,6 +240,8 @@
if (edid_ctrl->sink_data.num_of_elements) {
u32 *video_mode = edid_ctrl->sink_data.disp_mode_list;
for (i = 0; i < edid_ctrl->sink_data.num_of_elements; ++i) {
+ if (!hdmi_get_supported_mode(*video_mode))
+ continue;
if (ret > 0)
ret += snprintf(buf+ret, PAGE_SIZE-ret, ",%d",
*video_mode++ + 1);
diff --git a/drivers/video/msm/mdss/mdss_hdmi_mhl.h b/drivers/video/msm/mdss/mdss_hdmi_mhl.h
new file mode 100644
index 0000000..8fef63e
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_hdmi_mhl.h
@@ -0,0 +1,27 @@
+/* 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 __MDSS_HDMI_MHL_H__
+#define __MDSS_HDMI_MHL_H__
+
+#include <linux/platform_device.h>
+
+struct msm_hdmi_mhl_ops {
+ u8 (*tmds_enabled)(struct platform_device *pdev);
+ int (*set_mhl_max_pclk)(struct platform_device *pdev, u32 max_val);
+};
+
+int msm_hdmi_register_mhl(struct platform_device *pdev,
+ struct msm_hdmi_mhl_ops *ops);
+
+#endif /* __MDSS_HDMI_MHL_H__ */
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.c b/drivers/video/msm/mdss/mdss_hdmi_tx.c
index b6dec99..5404000 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.c
@@ -30,6 +30,7 @@
#include "mdss_hdmi_hdcp.h"
#include "mdss.h"
#include "mdss_panel.h"
+#include "mdss_hdmi_mhl.h"
#define DRV_NAME "hdmi-tx"
#define COMPATIBLE_NAME "qcom,hdmi-tx"
@@ -629,6 +630,30 @@
hdmi_set_supported_mode(HDMI_VFRMT_4096x2160p24_16_9);
} /* hdmi_tx_setup_video_mode_lut */
+/* Table tuned to indicate video formats supported by the MHL Tx */
+/* Valid pclk rates (Mhz): 25.2, 27, 27.03, 74.25 */
+static void hdmi_tx_setup_mhl_video_mode_lut(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+ u32 i;
+ struct hdmi_disp_mode_timing_type *temp_timing;
+
+ if (!hdmi_ctrl->mhl_max_pclk) {
+ DEV_WARN("%s: mhl max pclk not set!\n", __func__);
+ return;
+ }
+ DEV_DBG("%s: max mode set to [%u]\n",
+ __func__, hdmi_ctrl->mhl_max_pclk);
+ for (i = 0; i < HDMI_VFRMT_MAX; i++) {
+ temp_timing =
+ (struct hdmi_disp_mode_timing_type *)hdmi_get_supported_mode(i);
+ if (!temp_timing)
+ continue;
+ /* formats that exceed max mhl line clk bw */
+ if (temp_timing->pixel_freq > hdmi_ctrl->mhl_max_pclk)
+ hdmi_del_supported_mode(i);
+ }
+} /* hdmi_tx_setup_mhl_video_mode_lut */
+
static int hdmi_tx_read_sink_info(struct hdmi_tx_ctrl *hdmi_ctrl)
{
int status;
@@ -1758,12 +1783,65 @@
hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID], blk);
} /* hdmi_tx_get_audio_edid_blk */
+static u8 hdmi_tx_tmds_enabled(struct platform_device *pdev)
+{
+ struct hdmi_tx_ctrl *hdmi_ctrl = platform_get_drvdata(pdev);
+
+ if (!hdmi_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return -ENODEV;
+ }
+
+ /* status of tmds */
+ return (hdmi_ctrl->timing_gen_on == true);
+}
+
+static int hdmi_tx_set_mhl_max_pclk(struct platform_device *pdev, u32 max_val)
+{
+ struct hdmi_tx_ctrl *hdmi_ctrl = NULL;
+
+ hdmi_ctrl = platform_get_drvdata(pdev);
+
+ if (!hdmi_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return -ENODEV;
+ }
+ if (max_val) {
+ hdmi_ctrl->mhl_max_pclk = max_val;
+ hdmi_tx_setup_mhl_video_mode_lut(hdmi_ctrl);
+ } else {
+ DEV_ERR("%s: invalid max pclk val\n", __func__);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+int msm_hdmi_register_mhl(struct platform_device *pdev,
+ struct msm_hdmi_mhl_ops *ops)
+{
+ struct hdmi_tx_ctrl *hdmi_ctrl = platform_get_drvdata(pdev);
+
+ if (!hdmi_ctrl) {
+ DEV_ERR("%s: invalid pdev\n", __func__);
+ return -ENODEV;
+ }
+
+ if (!ops) {
+ DEV_ERR("%s: invalid ops\n", __func__);
+ return -EINVAL;
+ }
+
+ ops->tmds_enabled = hdmi_tx_tmds_enabled;
+ ops->set_mhl_max_pclk = hdmi_tx_set_mhl_max_pclk;
+ return 0;
+}
+
int msm_hdmi_register_audio_codec(struct platform_device *pdev,
struct msm_hdmi_audio_codec_ops *ops)
{
struct hdmi_tx_ctrl *hdmi_ctrl = platform_get_drvdata(pdev);
- if (!hdmi_ctrl) {
+ if (!hdmi_ctrl || !ops) {
DEV_ERR("%s: invalid input\n", __func__);
return -ENODEV;
}
@@ -2436,6 +2514,7 @@
DEV_ERR("%s: hdcp auth failed. rc=%d\n",
__func__, rc);
}
+ hdmi_ctrl->timing_gen_on = true;
break;
case MDSS_EVENT_SUSPEND:
@@ -2463,6 +2542,7 @@
break;
case MDSS_EVENT_TIMEGEN_OFF:
+ hdmi_ctrl->timing_gen_on = false;
break;
case MDSS_EVENT_CLOSE:
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.h b/drivers/video/msm/mdss/mdss_hdmi_tx.h
index ba5ee5b..06ae427 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.h
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.h
@@ -58,6 +58,8 @@
u32 hpd_off_pending;
u32 hpd_feature_on;
u32 hpd_initialized;
+ u8 timing_gen_on;
+ u32 mhl_max_pclk;
struct completion hpd_done;
struct work_struct hpd_int_work;
diff --git a/drivers/video/msm/mdss/mdss_hdmi_util.c b/drivers/video/msm/mdss/mdss_hdmi_util.c
index 13e2c9b..07c2336 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_util.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_util.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
@@ -34,6 +34,16 @@
}
} /* hdmi_init_supported_video_timings */
+void hdmi_del_supported_mode(u32 mode)
+{
+ struct hdmi_disp_mode_timing_type *ret = NULL;
+ DEV_DBG("%s: removing %s\n", __func__,
+ hdmi_get_video_fmt_2string(mode));
+ ret = &hdmi_supported_video_mode_lut[mode];
+ if (ret != NULL && ret->supported)
+ ret->supported = false;
+}
+
const struct hdmi_disp_mode_timing_type *hdmi_get_supported_mode(u32 mode)
{
const struct hdmi_disp_mode_timing_type *ret = NULL;
diff --git a/drivers/video/msm/mdss/mdss_hdmi_util.h b/drivers/video/msm/mdss/mdss_hdmi_util.h
index d621616..914aac1 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_util.h
+++ b/drivers/video/msm/mdss/mdss_hdmi_util.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
@@ -430,6 +430,7 @@
int hdmi_get_video_id_code(struct hdmi_disp_mode_timing_type *timing_in);
const struct hdmi_disp_mode_timing_type *hdmi_get_supported_mode(u32 mode);
void hdmi_set_supported_mode(u32 mode);
+void hdmi_del_supported_mode(u32 mode);
const char *hdmi_get_video_fmt_2string(u32 format);
ssize_t hdmi_get_video_3d_fmt_2string(u32 format, char *buf);
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index 308ae87..49a1daa 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -54,6 +54,9 @@
struct mdss_data_type *mdss_res;
+#define IB_QUOTA 800000000
+#define AB_QUOTA 800000000
+
static DEFINE_SPINLOCK(mdp_lock);
static DEFINE_MUTEX(mdp_clk_lock);
@@ -644,7 +647,7 @@
int i;
if (mdata->iommu_attached) {
- pr_warn("mdp iommu already attached\n");
+ pr_debug("mdp iommu already attached\n");
return 0;
}
@@ -751,7 +754,7 @@
return 0;
}
-static int mdss_hw_init(struct mdss_data_type *mdata)
+int mdss_hw_init(struct mdss_data_type *mdata)
{
int i, j;
char *offset;
@@ -823,6 +826,21 @@
return rc;
}
+void mdss_mdp_footswitch_ctrl_splash(int on)
+{
+ if (mdss_res != NULL) {
+ if (on) {
+ pr_debug("Enable MDP FS for splash.\n");
+ regulator_enable(mdss_res->fs);
+ } else {
+ pr_debug("Disable MDP FS for splash.\n");
+ regulator_disable(mdss_res->fs);
+ }
+ } else {
+ pr_warn("mdss mdata not initialized\n");
+ }
+}
+
static int mdss_mdp_probe(struct platform_device *pdev)
{
struct resource *res;
@@ -915,6 +933,7 @@
pr_err("unable to register bus scaling\n");
goto probe_done;
}
+ mdss_mdp_bus_scale_set_quota(AB_QUOTA, IB_QUOTA);
rc = mdss_mdp_debug_init(mdata);
if (rc) {
@@ -1330,16 +1349,16 @@
if (!mdata->fs)
return;
- if (on && !mdata->fs_ena) {
+ if (on) {
pr_debug("Enable MDP FS\n");
- regulator_enable(mdata->fs);
- mdss_iommu_attach(mdata);
- mdss_hw_init(mdata);
+ if (!mdata->fs_ena)
+ regulator_enable(mdata->fs);
mdata->fs_ena = true;
- } else if (!on && mdata->fs_ena) {
+ } else {
pr_debug("Disable MDP FS\n");
mdss_iommu_dettach(mdata);
- regulator_disable(mdata->fs);
+ if (mdata->fs_ena)
+ regulator_disable(mdata->fs);
mdata->fs_ena = false;
}
}
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index 5158974..4c70770 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -1,4 +1,5 @@
-/* Copyright (c) 2012-2013, 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
@@ -26,7 +27,7 @@
#define MDSS_MDP_CURSOR_HEIGHT 64
#define MDSS_MDP_CURSOR_SIZE (MDSS_MDP_CURSOR_WIDTH*MDSS_MDP_CURSOR_WIDTH*4)
-#define MDP_CLK_DEFAULT_RATE 37500000
+#define MDP_CLK_DEFAULT_RATE 200000000
#define PHASE_STEP_SHIFT 21
#define MAX_MIXER_WIDTH 2048
#define MAX_MIXER_HEIGHT 2400
@@ -129,6 +130,7 @@
u32 bus_ab_quota;
u32 bus_ib_quota;
u32 clk_rate;
+ u32 perf_changed;
struct mdss_data_type *mdata;
struct msm_fb_data_type *mfd;
@@ -142,6 +144,7 @@
int (*stop_fnc) (struct mdss_mdp_ctl *ctl);
int (*prepare_fnc) (struct mdss_mdp_ctl *ctl, void *arg);
int (*display_fnc) (struct mdss_mdp_ctl *ctl, void *arg);
+ int (*wait_fnc) (struct mdss_mdp_ctl *ctl, void *arg);
int (*set_vsync_handler) (struct mdss_mdp_ctl *, mdp_vsync_handler_t);
void *priv_data;
@@ -292,6 +295,8 @@
}
irqreturn_t mdss_mdp_isr(int irq, void *ptr);
+int mdss_iommu_attach(struct mdss_data_type *mdata);
+int mdss_mdp_copy_splash_screen(struct mdss_panel_data *pdata);
int mdss_mdp_irq_enable(u32 intr_type, u32 intf_num);
void mdss_mdp_irq_disable(u32 intr_type, u32 intf_num);
int mdss_mdp_hist_irq_enable(u32 irq);
@@ -300,6 +305,7 @@
int mdss_mdp_set_intr_callback(u32 intr_type, u32 intf_num,
void (*fnc_ptr)(void *), void *arg);
+void mdss_mdp_footswitch_ctrl_splash(int on);
int mdss_mdp_bus_scale_set_quota(u64 ab_quota, u64 ib_quota);
void mdss_mdp_set_clk_rate(unsigned long min_clk_rate);
unsigned long mdss_mdp_get_clk_rate(u32 clk_idx);
@@ -332,6 +338,7 @@
int mdss_mdp_mixer_pipe_update(struct mdss_mdp_pipe *pipe, int params_changed);
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_csc_setup(u32 block, u32 blk_idx, u32 tbl_idx, u32 csc_type);
int mdss_mdp_csc_setup_data(u32 block, u32 blk_idx, u32 tbl_idx,
@@ -339,25 +346,45 @@
int mdss_mdp_pp_init(struct device *dev);
void mdss_mdp_pp_term(struct device *dev);
+
int mdss_mdp_pp_resume(u32 mixer_num);
int mdss_mdp_pp_setup(struct mdss_mdp_ctl *ctl);
+int mdss_mdp_pp_setup_locked(struct mdss_mdp_ctl *ctl);
int mdss_mdp_pipe_pp_setup(struct mdss_mdp_pipe *pipe, u32 *op);
int mdss_mdp_pipe_sspp_setup(struct mdss_mdp_pipe *pipe, u32 *op);
void mdss_mdp_pipe_sspp_term(struct mdss_mdp_pipe *pipe);
-int mdss_mdp_pa_config(struct mdp_pa_cfg_data *config, u32 *copyback);
-int mdss_mdp_pcc_config(struct mdp_pcc_cfg_data *cfg_ptr, u32 *copyback);
-int mdss_mdp_igc_lut_config(struct mdp_igc_lut_data *config, u32 *copyback);
-int mdss_mdp_argc_config(struct mdp_pgc_lut_data *config, u32 *copyback);
-int mdss_mdp_hist_lut_config(struct mdp_hist_lut_data *config, u32 *copyback);
-int mdss_mdp_dither_config(struct mdp_dither_cfg_data *config, u32 *copyback);
-int mdss_mdp_gamut_config(struct mdp_gamut_cfg_data *config, u32 *copyback);
+int mdss_hw_init(struct mdss_data_type *mdata);
-int mdss_mdp_histogram_start(struct mdp_histogram_start_req *req);
-int mdss_mdp_histogram_stop(u32 block);
-int mdss_mdp_hist_collect(struct fb_info *info,
- struct mdp_histogram_data *hist, u32 *hist_data_addr);
+int mdss_mdp_pa_config(struct mdss_mdp_ctl *ctl,
+ struct mdp_pa_cfg_data *config,
+ u32 *copyback);
+int mdss_mdp_pcc_config(struct mdss_mdp_ctl *ctl,
+ struct mdp_pcc_cfg_data *cfg_ptr,
+ u32 *copyback);
+int mdss_mdp_igc_lut_config(struct mdss_mdp_ctl *ctl,
+ struct mdp_igc_lut_data *config,
+ u32 *copyback);
+int mdss_mdp_argc_config(struct mdss_mdp_ctl *ctl,
+ struct mdp_pgc_lut_data *config,
+ u32 *copyback);
+int mdss_mdp_hist_lut_config(struct mdss_mdp_ctl *ctl,
+ struct mdp_hist_lut_data *config,
+ u32 *copyback);
+int mdss_mdp_dither_config(struct mdss_mdp_ctl *ctl,
+ struct mdp_dither_cfg_data *config,
+ u32 *copyback);
+int mdss_mdp_gamut_config(struct mdss_mdp_ctl *ctl,
+ struct mdp_gamut_cfg_data *config,
+ u32 *copyback);
+
+int mdss_mdp_histogram_start(struct mdss_mdp_ctl *ctl,
+ struct mdp_histogram_start_req *req);
+int mdss_mdp_histogram_stop(struct mdss_mdp_ctl *ctl, u32 block);
+int mdss_mdp_hist_collect(struct mdss_mdp_ctl *ctl,
+ struct mdp_histogram_data *hist,
+ u32 *hist_data_addr);
void mdss_mdp_hist_intr_done(u32 isr);
struct mdss_mdp_pipe *mdss_mdp_pipe_alloc(struct mdss_mdp_mixer *mixer,
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index 0f52125..c640c73 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -177,7 +177,7 @@
*clk_rate, *bus_ab_quota, *bus_ib_quota);
}
-static int mdss_mdp_ctl_perf_update(struct mdss_mdp_ctl *ctl, u32 *flags)
+static int mdss_mdp_ctl_perf_update(struct mdss_mdp_ctl *ctl)
{
int ret = MDSS_MDP_PERF_UPDATE_SKIP;
u32 clk_rate, ab_quota, ib_quota;
@@ -200,19 +200,17 @@
max_clk_rate = clk_rate;
}
- /* request minimum bandwidth for dsi commands */
- if ((total_ib_quota == 0) && (ctl->intf_type == MDSS_INTF_DSI))
+ /* request minimum bandwidth to have bus clock on when display is on */
+ if (total_ib_quota == 0)
total_ib_quota = SZ_16M >> MDSS_MDP_BUS_FACTOR_SHIFT;
- *flags = 0;
-
if (max_clk_rate != ctl->clk_rate) {
if (max_clk_rate > ctl->clk_rate)
ret = MDSS_MDP_PERF_UPDATE_EARLY;
else
ret = MDSS_MDP_PERF_UPDATE_LATE;
ctl->clk_rate = max_clk_rate;
- *flags |= MDSS_MDP_PERF_UPDATE_CLK;
+ ctl->perf_changed |= MDSS_MDP_PERF_UPDATE_CLK;
}
if ((total_ab_quota != ctl->bus_ab_quota) ||
@@ -225,7 +223,7 @@
}
ctl->bus_ab_quota = total_ab_quota;
ctl->bus_ib_quota = total_ib_quota;
- *flags |= MDSS_MDP_PERF_UPDATE_BUS;
+ ctl->perf_changed |= MDSS_MDP_PERF_UPDATE_BUS;
}
return ret;
@@ -280,7 +278,7 @@
}
static struct mdss_mdp_mixer *mdss_mdp_mixer_alloc(
- struct mdss_mdp_ctl *ctl, u32 type)
+ struct mdss_mdp_ctl *ctl, u32 type, int mux)
{
struct mdss_mdp_mixer *mixer = NULL;
u32 nmixers_intf;
@@ -297,7 +295,6 @@
nmixers_wb = ctl->mdata->nmixers_wb;
switch (type) {
-
case MDSS_MDP_MIXER_TYPE_INTF:
mixer_pool = ctl->mdata->mixer_intf;
nmixers = nmixers_intf;
@@ -314,6 +311,15 @@
break;
}
+ /* early mdp revision only supports mux of dual pipe on mixers 0 and 1,
+ * need to ensure that these pipes are readily available by using
+ * mixer 2 if available and mux is not required */
+ if (!mux && (ctl->mdata->mdp_rev == MDSS_MDP_HW_REV_100) &&
+ (type == MDSS_MDP_MIXER_TYPE_INTF) &&
+ (nmixers >= MDSS_MDP_INTF_LAYERMIXER2) &&
+ (mixer_pool[MDSS_MDP_INTF_LAYERMIXER2].ref_cnt == 0))
+ mixer_pool += MDSS_MDP_INTF_LAYERMIXER2;
+
for (i = 0; i < nmixers; i++) {
mixer = mixer_pool + i;
if (mixer->ref_cnt == 0) {
@@ -358,7 +364,7 @@
if (!ctl)
return NULL;
- mixer = mdss_mdp_mixer_alloc(ctl, MDSS_MDP_MIXER_TYPE_WRITEBACK);
+ mixer = mdss_mdp_mixer_alloc(ctl, MDSS_MDP_MIXER_TYPE_WRITEBACK, false);
if (!mixer)
goto error;
@@ -463,7 +469,8 @@
if (!ctl->mixer_left) {
ctl->mixer_left =
- mdss_mdp_mixer_alloc(ctl, MDSS_MDP_MIXER_TYPE_INTF);
+ mdss_mdp_mixer_alloc(ctl, MDSS_MDP_MIXER_TYPE_INTF,
+ (width > MAX_MIXER_WIDTH));
if (!ctl->mixer_left) {
pr_err("unable to allocate layer mixer\n");
return -ENOMEM;
@@ -484,7 +491,7 @@
if (width < ctl->width) {
if (ctl->mixer_right == NULL) {
ctl->mixer_right = mdss_mdp_mixer_alloc(ctl,
- MDSS_MDP_MIXER_TYPE_INTF);
+ MDSS_MDP_MIXER_TYPE_INTF, true);
if (!ctl->mixer_right) {
pr_err("unable to allocate right mixer\n");
if (ctl->mixer_left)
@@ -559,6 +566,12 @@
ctl->opmode |= (ctl->intf_num << 4);
+ ret = mdss_mdp_ctl_setup(ctl);
+ if (ret) {
+ pr_err("unable to setup control path %d\n", ctl->num);
+ goto ctl_init_fail;
+ }
+
if (ctl->intf_num == MDSS_MDP_NO_INTF) {
ctl->dst_format = pdata->panel_info.out_format;
} else {
@@ -580,7 +593,7 @@
ctl->dst_format = MDSS_MDP_PANEL_FORMAT_RGB888;
break;
}
- mdss_mdp_dither_config(&dither, NULL);
+ mdss_mdp_dither_config(ctl, &dither, NULL);
}
return ctl;
@@ -619,14 +632,15 @@
sctl->width = pdata->panel_info.xres;
sctl->height = pdata->panel_info.yres;
- ctl->mixer_left = mdss_mdp_mixer_alloc(ctl, MDSS_MDP_MIXER_TYPE_INTF);
+ ctl->mixer_left = mdss_mdp_mixer_alloc(ctl, MDSS_MDP_MIXER_TYPE_INTF,
+ false);
if (!ctl->mixer_left) {
pr_err("unable to allocate layer mixer\n");
mdss_mdp_ctl_destroy(sctl);
return -ENOMEM;
}
- mixer = mdss_mdp_mixer_alloc(sctl, MDSS_MDP_MIXER_TYPE_INTF);
+ mixer = mdss_mdp_mixer_alloc(sctl, MDSS_MDP_MIXER_TYPE_INTF, false);
if (!mixer) {
pr_err("unable to allocate layer mixer\n");
mdss_mdp_ctl_destroy(sctl);
@@ -758,14 +772,15 @@
struct mdss_mdp_ctl *sctl;
int ret = 0;
+ if (ctl->power_on) {
+ pr_debug("%s:%d already on!\n", __func__, __LINE__);
+ return 0;
+ }
+
ret = mdss_mdp_ctl_setup(ctl);
if (ret)
return ret;
- if (ctl->power_on) {
- WARN(1, "already on!\n");
- return 0;
- }
sctl = mdss_mdp_get_split_ctl(ctl);
@@ -815,7 +830,7 @@
int ret = 0;
if (!ctl->power_on) {
- WARN(1, "already off!\n");
+ pr_debug("%s %d already off!\n", __func__, __LINE__);
return 0;
}
@@ -868,7 +883,7 @@
struct mdss_mdp_pipe *pipe;
u32 off, blend_op, blend_stage;
u32 mixercfg = 0, blend_color_out = 0, bgalpha = 0;
- int stage;
+ int stage, secure = 0;
if (!mixer)
return -ENODEV;
@@ -882,6 +897,7 @@
mixercfg = 1 << (3 * pipe->num);
if (pipe->src_fmt->alpha_enable)
bgalpha = 1;
+ secure = pipe->flags & MDP_SECURE_OVERLAY_SESSION;
}
for (stage = MDSS_MDP_STAGE_0; stage < MDSS_MDP_MAX_STAGE; stage++) {
@@ -899,7 +915,8 @@
if (pipe->is_fg) {
bgalpha = 0;
- mixercfg = MDSS_MDP_LM_BORDER_COLOR;
+ if (!secure)
+ mixercfg = MDSS_MDP_LM_BORDER_COLOR;
blend_op = (MDSS_MDP_BLEND_FG_ALPHA_FG_CONST |
MDSS_MDP_BLEND_BG_ALPHA_BG_CONST);
@@ -1149,13 +1166,38 @@
return 0;
}
+int mdss_mdp_display_wait4comp(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_fnc)
+ ret = ctl->wait_fnc(ctl, NULL);
+
+ if (ctl->perf_changed) {
+ mdss_mdp_ctl_perf_commit(ctl->mdata, ctl->perf_changed);
+ ctl->perf_changed = 0;
+ }
+
+ mutex_unlock(&ctl->lock);
+
+ return ret;
+}
+
int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg)
{
struct mdss_mdp_ctl *sctl = NULL;
int mixer1_changed, mixer2_changed;
int ret = 0;
int perf_update = MDSS_MDP_PERF_UPDATE_SKIP;
- u32 update_flags = 0;
if (!ctl) {
pr_err("display function not set\n");
@@ -1180,7 +1222,7 @@
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
if (mixer1_changed || mixer2_changed) {
- perf_update = mdss_mdp_ctl_perf_update(ctl, &update_flags);
+ perf_update = mdss_mdp_ctl_perf_update(ctl);
if (ctl->prepare_fnc)
ret = ctl->prepare_fnc(ctl, arg);
@@ -1189,8 +1231,10 @@
goto done;
}
- if (perf_update == MDSS_MDP_PERF_UPDATE_EARLY)
- mdss_mdp_ctl_perf_commit(ctl->mdata, update_flags);
+ if (perf_update == MDSS_MDP_PERF_UPDATE_EARLY) {
+ mdss_mdp_ctl_perf_commit(ctl->mdata, ctl->perf_changed);
+ ctl->perf_changed = 0;
+ }
if (mixer1_changed)
mdss_mdp_mixer_update(ctl->mixer_left);
@@ -1208,10 +1252,10 @@
}
/* postprocessing setup, including dspp */
- mdss_mdp_pp_setup(ctl);
+ mdss_mdp_pp_setup_locked(ctl);
mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_FLUSH, ctl->flush_bits);
if (sctl) {
- mdss_mdp_pp_setup(sctl);
+ mdss_mdp_pp_setup_locked(sctl);
mdss_mdp_ctl_write(sctl, MDSS_MDP_REG_CTL_FLUSH,
sctl->flush_bits);
}
@@ -1225,9 +1269,6 @@
ctl->play_cnt++;
- if (perf_update == MDSS_MDP_PERF_UPDATE_LATE)
- mdss_mdp_ctl_perf_commit(ctl->mdata, update_flags);
-
done:
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
diff --git a/drivers/video/msm/mdss/mdss_mdp_hwio.h b/drivers/video/msm/mdss/mdss_mdp_hwio.h
index 1c5c4b8..d4ffaff 100644
--- a/drivers/video/msm/mdss/mdss_mdp_hwio.h
+++ b/drivers/video/msm/mdss/mdss_mdp_hwio.h
@@ -221,6 +221,7 @@
#define MDSS_MDP_SCALE_FILTER_CA 0x3
#define MDSS_MDP_SCALEY_EN BIT(1)
#define MDSS_MDP_SCALEX_EN BIT(0)
+#define MDSS_MDP_FMT_SOLID_FILL 0x4037FF
#define MDSS_MDP_NUM_REG_MIXERS 3
#define MDSS_MDP_NUM_WB_MIXERS 2
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_video.c b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
index 0d4037c..e2c3b23 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_video.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
@@ -46,6 +46,7 @@
u8 timegen_en;
struct completion vsync_comp;
+ int wait_pending;
atomic_t vsync_ref;
spinlock_t vsync_lock;
@@ -271,13 +272,38 @@
pr_debug("intr ctl=%d\n", ctl->num);
- complete(&ctx->vsync_comp);
+ complete_all(&ctx->vsync_comp);
spin_lock(&ctx->vsync_lock);
if (ctx->vsync_handler)
ctx->vsync_handler(ctl, vsync_time);
spin_unlock(&ctx->vsync_lock);
}
+static int mdss_mdp_video_wait4comp(struct mdss_mdp_ctl *ctl, void *arg)
+{
+ struct mdss_mdp_video_ctx *ctx;
+ int rc;
+
+ ctx = (struct mdss_mdp_video_ctx *) ctl->priv_data;
+ if (!ctx) {
+ pr_err("invalid ctx\n");
+ return -ENODEV;
+ }
+
+ WARN(!ctx->wait_pending, "waiting without commit! ctl=%d", ctl->num);
+
+ rc = wait_for_completion_interruptible_timeout(&ctx->vsync_comp,
+ VSYNC_TIMEOUT);
+ WARN(rc <= 0, "vsync timed out (%d) ctl=%d\n", rc, ctl->num);
+
+ if (ctx->wait_pending) {
+ ctx->wait_pending = 0;
+ video_vsync_irq_disable(ctl);
+ }
+
+ return rc;
+}
+
static int mdss_mdp_video_display(struct mdss_mdp_ctl *ctl, void *arg)
{
struct mdss_mdp_video_ctx *ctx;
@@ -290,8 +316,14 @@
pr_err("invalid ctx\n");
return -ENODEV;
}
- INIT_COMPLETION(ctx->vsync_comp);
- video_vsync_irq_enable(ctl);
+
+ if (!ctx->wait_pending) {
+ ctx->wait_pending++;
+ INIT_COMPLETION(ctx->vsync_comp);
+ video_vsync_irq_enable(ctl);
+ } else {
+ WARN(1, "commit without wait! ctl=%d", ctl->num);
+ }
if (!ctx->timegen_en) {
rc = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_UNBLANK, NULL);
@@ -302,20 +334,17 @@
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
mdp_video_write(ctx, MDSS_MDP_REG_INTF_TIMING_ENGINE_EN, 1);
wmb();
- }
- rc = wait_for_completion_interruptible_timeout(&ctx->vsync_comp,
- VSYNC_TIMEOUT);
- WARN(rc <= 0, "vsync timed out (%d) ctl=%d\n", rc, ctl->num);
+ rc = wait_for_completion_interruptible_timeout(&ctx->vsync_comp,
+ VSYNC_TIMEOUT);
+ WARN(rc <= 0, "timeout (%d) enabling timegen on ctl=%d\n",
+ rc, ctl->num);
- if (!ctx->timegen_en) {
ctx->timegen_en = true;
rc = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_TIMEGEN_ON, NULL);
WARN(rc, "intf %d timegen on error (%d)\n", ctl->intf_num, rc);
}
- video_vsync_irq_disable(ctl);
-
return 0;
}
@@ -385,6 +414,7 @@
ctl->stop_fnc = mdss_mdp_video_stop;
ctl->display_fnc = mdss_mdp_video_display;
+ ctl->wait_fnc = mdss_mdp_video_wait4comp;
ctl->set_vsync_handler = mdss_mdp_video_set_vsync_handler;
return 0;
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index 2ae4830..6862c0e 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -20,9 +20,11 @@
#include <linux/module.h>
#include <linux/pm_runtime.h>
#include <linux/uaccess.h>
+#include <linux/delay.h>
#include <mach/iommu_domains.h>
+#include "mdss.h"
#include "mdss_fb.h"
#include "mdss_mdp.h"
#include "mdss_mdp_rotator.h"
@@ -498,6 +500,130 @@
return 0;
}
+int mdss_mdp_copy_splash_screen(struct mdss_panel_data *pdata)
+{
+ void *virt = NULL;
+ unsigned long bl_fb_addr = 0;
+ unsigned long *bl_fb_addr_va;
+ unsigned long pipe_addr, pipe_src_size;
+ u32 height, width, rgb_size, bpp;
+ size_t size;
+ static struct ion_handle *ihdl;
+ struct ion_client *iclient = mdss_get_ionclient();
+ static ion_phys_addr_t phys;
+
+ pipe_addr = MDSS_MDP_REG_SSPP_OFFSET(3) +
+ MDSS_MDP_REG_SSPP_SRC0_ADDR;
+ pipe_src_size =
+ MDSS_MDP_REG_SSPP_OFFSET(3) + MDSS_MDP_REG_SSPP_SRC_SIZE;
+
+ bpp = 3;
+ rgb_size = MDSS_MDP_REG_READ(pipe_src_size);
+ bl_fb_addr = MDSS_MDP_REG_READ(pipe_addr);
+
+ height = (rgb_size >> 16) & 0xffff;
+ width = rgb_size & 0xffff;
+ size = PAGE_ALIGN(height * width * bpp);
+ pr_debug("%s:%d splash_height=%d splash_width=%d Buffer size=%d\n",
+ __func__, __LINE__, height, width, size);
+
+ ihdl = ion_alloc(iclient, size, SZ_1M,
+ ION_HEAP(ION_QSECOM_HEAP_ID), 0);
+ if (IS_ERR_OR_NULL(ihdl)) {
+ pr_err("unable to alloc fbmem from ion (%p)\n", ihdl);
+ return -ENOMEM;
+ }
+
+ pdata->panel_info.splash_ihdl = ihdl;
+
+ virt = ion_map_kernel(iclient, ihdl);
+ ion_phys(iclient, ihdl, &phys, &size);
+
+ pr_debug("%s %d Allocating %u bytes at 0x%lx (%lx phys)\n",
+ __func__, __LINE__, size,
+ (unsigned long int)virt, phys);
+
+ bl_fb_addr_va = (unsigned long *)ioremap(bl_fb_addr, size);
+
+ memcpy(virt, bl_fb_addr_va, size);
+
+ MDSS_MDP_REG_WRITE(pipe_addr, phys);
+ MDSS_MDP_REG_WRITE(MDSS_MDP_REG_CTL_FLUSH + MDSS_MDP_REG_CTL_OFFSET(0),
+ 0x48);
+
+ return 0;
+
+}
+
+int mdss_mdp_reconfigure_splash_done(struct mdss_mdp_ctl *ctl)
+{
+ struct ion_client *iclient = mdss_get_ionclient();
+ struct mdss_panel_data *pdata;
+ int ret = 0, off;
+
+ off = 0;
+
+ pdata = ctl->panel_data;
+
+ pdata->panel_info.cont_splash_enabled = 0;
+
+ ion_free(iclient, pdata->panel_info.splash_ihdl);
+
+ mdss_mdp_ctl_write(ctl, 0, MDSS_MDP_LM_BORDER_COLOR);
+ off = MDSS_MDP_REG_INTF_OFFSET(ctl->intf_num);
+
+ /* wait for 1 VSYNC for the pipe to be unstaged */
+ msleep(20);
+ MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_INTF_TIMING_ENGINE_EN, 0);
+ ret = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_CONT_SPLASH_FINISH,
+ NULL);
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+ mdss_mdp_footswitch_ctrl_splash(0);
+ return ret;
+}
+
+static int mdss_mdp_overlay_start(struct msm_fb_data_type *mfd)
+{
+ int rc;
+
+ if (mfd->ctl->power_on)
+ return 0;
+
+ pr_debug("starting overlay\n");
+
+ rc = pm_runtime_get_sync(&mfd->pdev->dev);
+ if (rc) {
+ pr_err("unable to resume with pm_runtime_get_sync (%d)\n", rc);
+ return rc;
+ }
+
+ if (mfd->panel_info->cont_splash_enabled)
+ mdss_mdp_reconfigure_splash_done(mfd->ctl);
+
+ if (!is_mdss_iommu_attached()) {
+ mdss_iommu_attach(mdss_res);
+ mdss_hw_init(mdss_res);
+ }
+
+ rc = mdss_mdp_ctl_start(mfd->ctl);
+ if (rc == 0) {
+ atomic_inc(&ov_active_panels);
+
+ if (mfd->vsync_pending) {
+ mfd->vsync_pending = 0;
+ mdss_mdp_overlay_vsync_ctrl(mfd, mfd->vsync_pending);
+ }
+ } else {
+ pr_err("overlay start failed.\n");
+ mdss_mdp_ctl_destroy(mfd->ctl);
+ mfd->ctl = NULL;
+
+ pm_runtime_put(&mfd->pdev->dev);
+ }
+
+ return rc;
+}
+
int mdss_mdp_overlay_kickoff(struct mdss_mdp_ctl *ctl)
{
struct msm_fb_data_type *mfd = ctl->mfd;
@@ -516,17 +642,20 @@
}
}
}
- mutex_unlock(&mfd->lock);
if (mfd->kickoff_fnc)
ret = mfd->kickoff_fnc(ctl);
else
ret = mdss_mdp_display_commit(ctl, NULL);
+ mutex_unlock(&mfd->lock);
+
if (IS_ERR_VALUE(ret)) {
mutex_unlock(&mfd->ov_lock);
return ret;
}
+ ret = mdss_mdp_display_wait4comp(ctl);
+
complete(&mfd->update.comp);
mutex_lock(&mfd->no_update.lock);
if (mfd->no_update.timer.function)
@@ -740,6 +869,12 @@
return -EPERM;
}
+ ret = mdss_mdp_overlay_start(mfd);
+ if (ret) {
+ pr_err("unable to start overlay %d (%d)\n", mfd->index, ret);
+ return ret;
+ }
+
if (req->id & MDSS_MDP_ROT_SESSION_MASK) {
ret = mdss_mdp_overlay_rotate(mfd, req);
} else if (req->id == BORDERFILL_NDX) {
@@ -1283,7 +1418,7 @@
static int mdss_mdp_overlay_on(struct msm_fb_data_type *mfd)
{
- int rc;
+ int rc = 0;
if (!mfd)
return -ENODEV;
@@ -1319,23 +1454,6 @@
mfd->ctl = ctl;
}
- pm_runtime_get_sync(&mfd->pdev->dev);
-
- rc = mdss_mdp_ctl_start(mfd->ctl);
- if (rc == 0) {
- atomic_inc(&ov_active_panels);
-
- if (mfd->vsync_pending) {
- mfd->vsync_pending = 0;
- mdss_mdp_overlay_vsync_ctrl(mfd, mfd->vsync_pending);
- }
- } else {
- mdss_mdp_ctl_destroy(mfd->ctl);
- mfd->ctl = NULL;
-
- pm_runtime_put(&mfd->pdev->dev);
- }
-
return rc;
}
@@ -1354,6 +1472,9 @@
return -ENODEV;
}
+ if (!mfd->ctl->power_on)
+ return 0;
+
mdss_mdp_overlay_release_all(mfd);
rc = mdss_mdp_ctl_stop(mfd->ctl);
@@ -1367,7 +1488,9 @@
if (atomic_dec_return(&ov_active_panels) == 0)
mdss_mdp_rotator_release_all();
- pm_runtime_put(&mfd->pdev->dev);
+ rc = pm_runtime_put(&mfd->pdev->dev);
+ if (rc)
+ pr_err("unable to suspend w/pm_runtime_put (%d)\n", rc);
}
return rc;
diff --git a/drivers/video/msm/mdss/mdss_mdp_pipe.c b/drivers/video/msm/mdss/mdss_mdp_pipe.c
index 0a52561..8c88646 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pipe.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pipe.c
@@ -98,6 +98,9 @@
num_blks = DIV_ROUND_UP(2 * ps.ystride[i],
mdss_res->smp_mb_size);
+ if (mdss_res->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);
reserved = mdss_mdp_smp_mmb_reserve(&pipe->smp[i], num_blks);
@@ -709,6 +712,28 @@
return 0;
}
+static int mdss_mdp_pipe_solidfill_setup(struct mdss_mdp_pipe *pipe)
+{
+ int ret;
+ u32 secure, format;
+
+ pr_debug("solid fill setup on pnum=%d\n", pipe->num);
+
+ ret = mdss_mdp_image_setup(pipe);
+ if (ret) {
+ pr_err("image setup error for pnum=%d\n", pipe->num);
+ return ret;
+ }
+
+ format = MDSS_MDP_FMT_SOLID_FILL;
+ secure = (pipe->flags & MDP_SECURE_OVERLAY_SESSION ? 0xF : 0x0);
+
+ mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_FORMAT, format);
+ mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_ADDR_SW_STATUS, secure);
+
+ return 0;
+}
+
int mdss_mdp_pipe_queue_data(struct mdss_mdp_pipe *pipe,
struct mdss_mdp_data *src_data)
{
@@ -731,6 +756,11 @@
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
params_changed = pipe->params_changed;
+ if (src_data == NULL) {
+ mdss_mdp_pipe_solidfill_setup(pipe);
+ goto update_nobuf;
+ }
+
if (params_changed) {
pipe->params_changed = 0;
@@ -768,6 +798,7 @@
goto done;
}
+update_nobuf:
mdss_mdp_mixer_pipe_update(pipe, params_changed);
pipe->play_cnt++;
diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c
index 851d608..59d760b 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pp.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -610,15 +610,21 @@
struct pp_sts_type *pp_sts;
u32 data, col_state;
unsigned long flag;
- int i;
+ int i, ret = 0;
+
+ if (!mixer || !ctl)
+ return -EINVAL;
dspp_num = mixer->num;
/* no corresponding dspp */
if ((mixer->type != MDSS_MDP_MIXER_TYPE_INTF) ||
(dspp_num >= MDSS_MDP_MAX_DSPP))
- return 0;
+ return -EINVAL;
base = MDSS_MDP_REG_DSPP_OFFSET(dspp_num);
hist_info = &mdss_pp_res->dspp_hist[dspp_num];
+
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+
if (hist_info->col_en) {
/* HIST_EN & AUTO_CLEAR */
opmode |= (1 << 16) | (1 << 17);
@@ -634,7 +640,6 @@
MDSS_MDP_REG_DSPP_HIST_CTL_BASE, 1);
hist_info->col_state = HIST_START;
}
- hist_info->is_kick_ready = true;
spin_unlock_irqrestore(&mdss_hist_lock, flag);
mutex_unlock(&mdss_mdp_hist_mutex);
}
@@ -646,7 +651,7 @@
/* nothing to update */
if ((!flags) && (!(hist_info->col_en)))
- return 0;
+ goto dspp_exit;
pp_sts = &mdss_pp_res->pp_dspp_sts[dspp_num];
@@ -734,12 +739,36 @@
opmode |= (1 << 22);
MDSS_MDP_REG_WRITE(base + MDSS_MDP_REG_DSPP_OP_MODE, opmode);
- ctl->flush_bits |= BIT(13 + dspp_num); /* DSPP */
- return 0;
+ mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_FLUSH, BIT(13 + dspp_num));
+ wmb();
+dspp_exit:
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+ return ret;
}
int mdss_mdp_pp_setup(struct mdss_mdp_ctl *ctl)
{
+ int ret = 0;
+
+ if ((!ctl->mfd) || (!mdss_pp_res))
+ return -EINVAL;
+
+ /* TODO: have some sort of reader/writer lock to prevent unclocked
+ * access while display power is toggled */
+ if (!ctl->mfd->panel_power_on) {
+ ret = -EPERM;
+ goto error;
+ }
+ mutex_lock(&ctl->mfd->lock);
+ ret = mdss_mdp_pp_setup_locked(ctl);
+ mutex_unlock(&ctl->mfd->lock);
+error:
+ return ret;
+}
+
+/* call only when holding and mfd->lock */
+int mdss_mdp_pp_setup_locked(struct mdss_mdp_ctl *ctl)
+{
u32 disp_num;
if ((!ctl->mfd) || (!mdss_pp_res))
return -EINVAL;
@@ -887,11 +916,15 @@
return 0;
}
-int mdss_mdp_pa_config(struct mdp_pa_cfg_data *config, u32 *copyback)
+int mdss_mdp_pa_config(struct mdss_mdp_ctl *ctl, struct mdp_pa_cfg_data *config,
+ u32 *copyback)
{
int ret = 0;
u32 pa_offset, disp_num, dspp_num = 0;
+ if (!ctl)
+ return -EINVAL;
+
if ((config->block < MDP_LOGICAL_BLOCK_DISP_0) ||
(config->block >= MDP_BLOCK_MAX))
return -EINVAL;
@@ -925,6 +958,8 @@
pa_config_exit:
mutex_unlock(&mdss_pp_mutex);
+ if (!ret)
+ mdss_mdp_pp_setup(ctl);
return ret;
}
@@ -1054,11 +1089,16 @@
MDSS_MDP_REG_WRITE(offset + 8, cfg_ptr->b.rgb_1);
}
-int mdss_mdp_pcc_config(struct mdp_pcc_cfg_data *config, u32 *copyback)
+int mdss_mdp_pcc_config(struct mdss_mdp_ctl *ctl,
+ struct mdp_pcc_cfg_data *config,
+ u32 *copyback)
{
int ret = 0;
u32 base, disp_num, dspp_num = 0;
+ if (!ctl)
+ return -EINVAL;
+
if ((config->block < MDP_LOGICAL_BLOCK_DISP_0) ||
(config->block >= MDP_BLOCK_MAX))
return -EINVAL;
@@ -1088,8 +1128,9 @@
pcc_config_exit:
mutex_unlock(&mdss_pp_mutex);
+ if (!ret)
+ mdss_mdp_pp_setup(ctl);
return ret;
-
}
static void pp_read_igc_lut(struct mdp_igc_lut_data *cfg,
@@ -1146,12 +1187,17 @@
MDSS_MDP_REG_WRITE(offset, (cfg->c2_data[i] & 0xFFF) | data);
}
-int mdss_mdp_igc_lut_config(struct mdp_igc_lut_data *config, u32 *copyback)
+int mdss_mdp_igc_lut_config(struct mdss_mdp_ctl *ctl,
+ struct mdp_igc_lut_data *config,
+ u32 *copyback)
{
int ret = 0;
u32 tbl_idx, igc_offset, disp_num, dspp_num = 0;
struct mdp_igc_lut_data local_cfg;
+ if (!ctl)
+ return -EINVAL;
+
if ((config->block < MDP_LOGICAL_BLOCK_DISP_0) ||
(config->block >= MDP_BLOCK_MAX))
return -EINVAL;
@@ -1213,6 +1259,8 @@
igc_config_exit:
mutex_unlock(&mdss_pp_mutex);
+ if (!ret)
+ mdss_mdp_pp_setup(ctl);
return ret;
}
static void pp_update_gc_one_lut(u32 offset,
@@ -1310,7 +1358,9 @@
MDSS_MDP_REG_WRITE(offset + 4, 1);
}
-int mdss_mdp_argc_config(struct mdp_pgc_lut_data *config, u32 *copyback)
+int mdss_mdp_argc_config(struct mdss_mdp_ctl *ctl,
+ struct mdp_pgc_lut_data *config,
+ u32 *copyback)
{
int ret = 0;
u32 argc_offset = 0, disp_num, dspp_num = 0;
@@ -1318,6 +1368,9 @@
struct mdp_pgc_lut_data *pgc_ptr;
u32 tbl_size;
+ if (!ctl)
+ return -EINVAL;
+
if ((PP_BLOCK(config->block) < MDP_LOGICAL_BLOCK_DISP_0) ||
(PP_BLOCK(config->block) >= MDP_BLOCK_MAX))
return -EINVAL;
@@ -1407,13 +1460,20 @@
}
argc_config_exit:
mutex_unlock(&mdss_pp_mutex);
+ if (!ret)
+ mdss_mdp_pp_setup(ctl);
return ret;
}
-int mdss_mdp_hist_lut_config(struct mdp_hist_lut_data *config, u32 *copyback)
+int mdss_mdp_hist_lut_config(struct mdss_mdp_ctl *ctl,
+ struct mdp_hist_lut_data *config,
+ u32 *copyback)
{
int i, ret = 0;
u32 hist_offset, disp_num, dspp_num = 0;
+ if (!ctl)
+ return -EINVAL;
+
if ((config->block < MDP_LOGICAL_BLOCK_DISP_0) ||
(config->block >= MDP_BLOCK_MAX))
return -EINVAL;
@@ -1456,12 +1516,19 @@
}
enhist_config_exit:
mutex_unlock(&mdss_pp_mutex);
+ if (!ret)
+ mdss_mdp_pp_setup(ctl);
return ret;
}
-int mdss_mdp_dither_config(struct mdp_dither_cfg_data *config, u32 *copyback)
+int mdss_mdp_dither_config(struct mdss_mdp_ctl *ctl,
+ struct mdp_dither_cfg_data *config,
+ u32 *copyback)
{
u32 disp_num;
+ if (!ctl)
+ return -EINVAL;
+
if ((config->block < MDP_LOGICAL_BLOCK_DISP_0) ||
(config->block >= MDP_BLOCK_MAX))
return -EINVAL;
@@ -1473,16 +1540,22 @@
mdss_pp_res->dither_disp_cfg[disp_num] = *config;
mdss_pp_res->pp_disp_flags[disp_num] |= PP_FLAGS_DIRTY_DITHER;
mutex_unlock(&mdss_pp_mutex);
+ mdss_mdp_pp_setup(ctl);
return 0;
}
-int mdss_mdp_gamut_config(struct mdp_gamut_cfg_data *config, u32 *copyback)
+int mdss_mdp_gamut_config(struct mdss_mdp_ctl *ctl,
+ struct mdp_gamut_cfg_data *config,
+ u32 *copyback)
{
int i, j, size_total = 0, ret = 0;
u32 offset, disp_num, dspp_num = 0;
uint16_t *tbl_off;
struct mdp_gamut_cfg_data local_cfg;
+ if (!ctl)
+ return -EINVAL;
+
if ((config->block < MDP_LOGICAL_BLOCK_DISP_0) ||
(config->block >= MDP_BLOCK_MAX))
return -EINVAL;
@@ -1560,6 +1633,8 @@
}
gamut_config_exit:
mutex_unlock(&mdss_pp_mutex);
+ if (!ret)
+ mdss_mdp_pp_setup(ctl);
return ret;
}
static void pp_hist_read(u32 v_base, struct pp_hist_col_info *hist_info)
@@ -1576,7 +1651,8 @@
hist_info->hist_cnt_read++;
}
-int mdss_mdp_histogram_start(struct mdp_histogram_start_req *req)
+int mdss_mdp_histogram_start(struct mdss_mdp_ctl *ctl,
+ struct mdp_histogram_start_req *req)
{
u32 ctl_base, done_shift_bit;
struct pp_hist_col_info *hist_info;
@@ -1585,6 +1661,9 @@
u32 mixer_cnt, mixer_id[MDSS_MDP_INTF_MAX_LAYERMIXER];
unsigned long flag;
+ if (!ctl)
+ return -EINVAL;
+
if ((req->block < MDP_LOGICAL_BLOCK_DISP_0) ||
(req->block >= MDP_BLOCK_MAX))
return -EINVAL;
@@ -1642,10 +1721,24 @@
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
hist_start_exit:
mutex_unlock(&mdss_mdp_hist_mutex);
+ if (!ret) {
+ mdss_mdp_pp_setup(ctl);
+ /* wait for a frame to let histrogram enable itself */
+ usleep(41666);
+ for (i = 0; i < mixer_cnt; i++) {
+ dspp_num = mixer_id[i];
+ hist_info = &mdss_pp_res->dspp_hist[dspp_num];
+ mutex_lock(&mdss_mdp_hist_mutex);
+ spin_lock_irqsave(&mdss_hist_lock, flag);
+ hist_info->is_kick_ready = true;
+ spin_unlock_irqrestore(&mdss_hist_lock, flag);
+ mutex_unlock(&mdss_mdp_hist_mutex);
+ }
+ }
return ret;
}
-int mdss_mdp_histogram_stop(u32 block)
+int mdss_mdp_histogram_stop(struct mdss_mdp_ctl *ctl, u32 block)
{
int i, ret = 0;
u32 dspp_num, disp_num, ctl_base, done_bit;
@@ -1653,6 +1746,9 @@
u32 mixer_cnt, mixer_id[MDSS_MDP_INTF_MAX_LAYERMIXER];
unsigned long flag;
+ if (!ctl)
+ return -EINVAL;
+
if ((block < MDP_LOGICAL_BLOCK_DISP_0) ||
(block >= MDP_BLOCK_MAX))
return -EINVAL;
@@ -1699,11 +1795,14 @@
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
hist_stop_exit:
mutex_unlock(&mdss_mdp_hist_mutex);
+ if (!ret)
+ mdss_mdp_pp_setup(ctl);
return ret;
}
-int mdss_mdp_hist_collect(struct fb_info *info,
- struct mdp_histogram_data *hist, u32 *hist_data_addr)
+int mdss_mdp_hist_collect(struct mdss_mdp_ctl *ctl,
+ struct mdp_histogram_data *hist,
+ u32 *hist_data_addr)
{
int i, j, wait_ret, ret = 0;
u32 timeout, v_base;
@@ -1712,6 +1811,9 @@
u32 mixer_cnt, mixer_id[MDSS_MDP_INTF_MAX_LAYERMIXER];
unsigned long flag;
+ if (!ctl)
+ return -EINVAL;
+
if ((hist->block < MDP_LOGICAL_BLOCK_DISP_0) ||
(hist->block >= MDP_BLOCK_MAX))
return -EINVAL;
@@ -1750,6 +1852,8 @@
spin_unlock_irqrestore(&mdss_hist_lock, flag);
timeout = HIST_WAIT_TIMEOUT(hist_info->frame_cnt);
mutex_unlock(&mdss_mdp_hist_mutex);
+ /* flush updates before wait*/
+ mdss_mdp_pp_setup(ctl);
wait_ret = wait_for_completion_killable_timeout(
&(hist_info->comp), timeout);
@@ -1779,8 +1883,8 @@
}
if (hist_info->col_state != HIST_READY) {
ret = -ENODATA;
- pr_debug("%s: collection state is not ready: %d",
- __func__, hist_info->col_state);
+ pr_debug("%s: state is not ready: %d",
+ __func__, hist_info->col_state);
goto hist_collect_exit;
}
} else {
diff --git a/drivers/video/msm/mdss/mdss_mdp_wb.c b/drivers/video/msm/mdss/mdss_mdp_wb.c
index 23efcb8..1d55fa9 100644
--- a/drivers/video/msm/mdss/mdss_mdp_wb.c
+++ b/drivers/video/msm/mdss/mdss_mdp_wb.c
@@ -26,7 +26,6 @@
#include "mdss_mdp.h"
#include "mdss_fb.h"
-#define DEBUG_WRITEBACK
enum mdss_mdp_wb_state {
WB_OPEN,
@@ -43,6 +42,8 @@
struct list_head register_queue;
wait_queue_head_t wait_q;
u32 state;
+ int is_secure;
+ struct mdss_mdp_pipe *secure_pipe;
};
enum mdss_mdp_wb_node_state {
@@ -121,6 +122,72 @@
}
#endif
+int mdss_mdp_wb_set_secure(struct msm_fb_data_type *mfd, int enable)
+{
+ struct mdss_mdp_wb *wb;
+ struct mdss_mdp_pipe *pipe;
+ struct mdss_mdp_mixer *mixer;
+
+ pr_debug("setting secure=%d\n", enable);
+
+ wb = mfd->wb;
+ if (wb == NULL) {
+ pr_err("Invalid writeback session\n");
+ return -ENODEV;
+ }
+
+ wb->is_secure = enable;
+ pipe = wb->secure_pipe;
+
+ if (!enable) {
+ if (pipe) {
+ /* unset pipe */
+ mdss_mdp_mixer_pipe_unstage(pipe);
+ mdss_mdp_pipe_destroy(pipe);
+ wb->secure_pipe = NULL;
+ }
+ return 0;
+ }
+
+ mixer = mdss_mdp_mixer_get(mfd->ctl, MDSS_MDP_MIXER_MUX_DEFAULT);
+ if (!mixer) {
+ pr_err("Unable to find mixer for wb\n");
+ return -ENOENT;
+ }
+
+ if (!pipe) {
+ pipe = mdss_mdp_pipe_alloc(mixer, MDSS_MDP_PIPE_TYPE_RGB);
+ if (!pipe)
+ pipe = mdss_mdp_pipe_alloc(mixer,
+ MDSS_MDP_PIPE_TYPE_VIG);
+ if (!pipe) {
+ pr_err("Unable to get pipe to set secure session\n");
+ return -ENOMEM;
+ }
+
+ pipe->src_fmt = mdss_mdp_get_format_params(MDP_RGBA_8888);
+
+ pipe->mfd = mfd;
+ pipe->mixer_stage = MDSS_MDP_STAGE_BASE;
+ wb->secure_pipe = pipe;
+ }
+
+ pipe->img_height = mixer->height;
+ pipe->img_width = mixer->width;
+ pipe->src.x = 0;
+ pipe->src.y = 0;
+ pipe->src.w = pipe->img_width;
+ pipe->src.h = pipe->img_height;
+ pipe->dst = pipe->src;
+
+ pipe->flags = (enable ? MDP_SECURE_OVERLAY_SESSION : 0);
+ pipe->params_changed++;
+
+ pr_debug("setting secure pipe=%d flags=%x\n", pipe->num, pipe->flags);
+
+ return mdss_mdp_pipe_queue_data(pipe, NULL);
+}
+
static int mdss_mdp_wb_init(struct msm_fb_data_type *mfd)
{
struct mdss_mdp_wb *wb;
@@ -173,6 +240,10 @@
kfree(node);
}
}
+
+ wb->is_secure = false;
+ if (wb->secure_pipe)
+ mdss_mdp_pipe_destroy(wb->secure_pipe);
mutex_unlock(&wb->lock);
mfd->wb = NULL;
@@ -257,6 +328,8 @@
buf = &node->buf_data.p[0];
buf->addr = (u32) (data->iova + data->offset);
buf->len = UINT_MAX; /* trusted source */
+ if (wb->is_secure)
+ buf->flags |= MDP_SECURE_OVERLAY_SESSION;
ret = mdss_mdp_wb_register_node(wb, node);
if (IS_ERR_VALUE(ret)) {
pr_err("error registering wb node\n");
@@ -284,6 +357,8 @@
node->buf_data.num_planes = 1;
buf = &node->buf_data.p[0];
+ if (wb->is_secure)
+ buf->flags |= MDP_SECURE_OVERLAY_SESSION;
ret = mdss_mdp_get_img(data, buf);
if (IS_ERR_VALUE(ret)) {
pr_err("error getting buffer info\n");
@@ -419,6 +494,9 @@
wb = ctl->mfd->wb;
if (wb) {
mutex_lock(&wb->lock);
+ /* in case of reinit of control path need to reset secure */
+ if (ctl->play_cnt == 0)
+ mdss_mdp_wb_set_secure(ctl->mfd, wb->is_secure);
if (!list_empty(&wb->free_queue) && wb->state != WB_STOPING &&
wb->state != WB_STOP) {
node = list_first_entry(&wb->free_queue,
@@ -568,8 +646,31 @@
}
EXPORT_SYMBOL(msm_fb_writeback_terminate);
-int msm_fb_get_iommu_domain(void)
+int msm_fb_get_iommu_domain(struct fb_info *info, int domain)
{
- return mdss_get_iommu_domain(MDSS_IOMMU_DOMAIN_UNSECURE);
+ int mdss_domain;
+ switch (domain) {
+ case MDP_IOMMU_DOMAIN_CP:
+ mdss_domain = MDSS_IOMMU_DOMAIN_SECURE;
+ break;
+ case MDP_IOMMU_DOMAIN_NS:
+ mdss_domain = MDSS_IOMMU_DOMAIN_UNSECURE;
+ break;
+ default:
+ pr_err("Invalid mdp iommu domain (%d)\n", domain);
+ return -EINVAL;
+ }
+ return mdss_get_iommu_domain(mdss_domain);
}
EXPORT_SYMBOL(msm_fb_get_iommu_domain);
+
+int msm_fb_writeback_set_secure(struct fb_info *info, int enable)
+{
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *) info->par;
+
+ if (!mfd)
+ return -ENODEV;
+
+ return mdss_mdp_wb_set_secure(mfd, enable);
+}
+EXPORT_SYMBOL(msm_fb_writeback_set_secure);
diff --git a/drivers/video/msm/mdss/mdss_panel.h b/drivers/video/msm/mdss/mdss_panel.h
index 40131eb..31fb2e7 100644
--- a/drivers/video/msm/mdss/mdss_panel.h
+++ b/drivers/video/msm/mdss/mdss_panel.h
@@ -65,6 +65,7 @@
MDSS_EVENT_SUSPEND,
MDSS_EVENT_RESUME,
MDSS_EVENT_CHECK_PARAMS,
+ MDSS_EVENT_CONT_SPLASH_FINISH,
MDSS_EVENT_FB_REGISTERED,
};
@@ -183,6 +184,10 @@
u32 out_format;
u32 vic; /* video identification code */
+ u32 cont_splash_enabled;
+ struct ion_handle *splash_ihdl;
+ u32 panel_power_on;
+
struct lcd_panel_info lcd;
struct lcdc_panel_info lcdc;
struct mipi_panel_info mipi;
diff --git a/drivers/video/msm/mdss/mhl_msc.c b/drivers/video/msm/mdss/mhl_msc.c
index 3d3fff9..add65ac 100644
--- a/drivers/video/msm/mdss/mhl_msc.c
+++ b/drivers/video/msm/mdss/mhl_msc.c
@@ -16,6 +16,7 @@
#include <linux/vmalloc.h>
#include <linux/input.h>
#include "mhl_msc.h"
+#include "mdss_hdmi_mhl.h"
static struct mhl_tx_ctrl *mhl_ctrl;
static DEFINE_MUTEX(msc_send_workqueue_mutex);
@@ -39,6 +40,18 @@
"Reserved ",
};
+static bool mhl_check_tmds_enabled(struct mhl_tx_ctrl *mhl_ctrl)
+{
+ if (mhl_ctrl && mhl_ctrl->hdmi_mhl_ops) {
+ struct msm_hdmi_mhl_ops *ops = mhl_ctrl->hdmi_mhl_ops;
+ struct platform_device *pdev = mhl_ctrl->pdata->hdmi_pdev;
+ return (ops->tmds_enabled(pdev) == true);
+ } else {
+ pr_err("%s: invalid input\n", __func__);
+ return false;
+ }
+}
+
static void mhl_print_devcap(u8 offset, u8 devcap)
{
switch (offset) {
@@ -398,10 +411,12 @@
static int mhl_rap_recv(struct mhl_tx_ctrl *mhl_ctrl, u8 action_code)
{
u8 error_code;
+ bool tmds_en;
switch (action_code) {
case MHL_RAP_POLL:
- if (mhl_ctrl->tmds_enabled())
+ tmds_en = mhl_check_tmds_enabled(mhl_ctrl);
+ if (tmds_en)
error_code = MHL_RAPK_NO_ERROR;
else
error_code = MHL_RAPK_UNSUPPORTED_ACTION_CODE;
@@ -513,6 +528,8 @@
int mhl_msc_recv_write_stat(struct mhl_tx_ctrl *mhl_ctrl,
u8 offset, u8 value)
{
+ bool tmds_en;
+
if (offset >= 2)
return -EFAULT;
@@ -543,10 +560,11 @@
* changed and PATH ENABLED
* bit set
*/
+ tmds_en = mhl_check_tmds_enabled(mhl_ctrl);
if ((value ^ mhl_ctrl->path_en_state)
& MHL_STATUS_PATH_ENABLED) {
if (value & MHL_STATUS_PATH_ENABLED) {
- if (mhl_ctrl->tmds_enabled() &&
+ if (tmds_en &&
(mhl_ctrl->devcap[offset] &
MHL_FEATURE_RAP_SUPPORT)) {
mhl_msc_send_msc_msg(
diff --git a/drivers/video/msm/mdss/mhl_sii8334.c b/drivers/video/msm/mdss/mhl_sii8334.c
index 4d6af15..30dd471 100644
--- a/drivers/video/msm/mdss/mhl_sii8334.c
+++ b/drivers/video/msm/mdss/mhl_sii8334.c
@@ -30,6 +30,7 @@
#include "mdss_panel.h"
#include "mdss_io_util.h"
#include "mhl_msc.h"
+#include "mdss_hdmi_mhl.h"
#define MHL_DRIVER_NAME "sii8334"
#define COMPATIBLE_NAME "qcom,mhl-sii8334"
@@ -193,8 +194,6 @@
static void mhl_init_reg_settings(struct mhl_tx_ctrl *mhl_ctrl,
bool mhl_disc_en);
-static uint8_t store_tmds_state;
-
int mhl_i2c_reg_read(struct i2c_client *client,
uint8_t slave_addr_index, uint8_t reg_offset)
{
@@ -239,6 +238,8 @@
int i, rc = 0;
struct device_node *of_node = NULL;
struct dss_gpio *temp_gpio = NULL;
+ struct platform_device *hdmi_pdev = NULL;
+ struct device_node *hdmi_tx_node = NULL;
int dt_gpio;
i = 0;
@@ -316,6 +317,23 @@
temp_gpio->gpio);
pdata->gpios[MHL_TX_INTR_GPIO] = temp_gpio;
+ /* parse phandle for hdmi tx */
+ hdmi_tx_node = of_parse_phandle(of_node, "qcom,hdmi-tx-map", 0);
+ if (!hdmi_tx_node) {
+ pr_err("%s: can't find hdmi phandle\n", __func__);
+ goto error;
+ }
+
+ hdmi_pdev = of_find_device_by_node(hdmi_tx_node);
+ if (!hdmi_pdev) {
+ pr_err("%s: can't find the device by node\n", __func__);
+ goto error;
+ }
+ pr_debug("%s: hdmi_pdev [0X%x] to pdata->pdev\n",
+ __func__, (unsigned int)hdmi_pdev);
+
+ pdata->hdmi_pdev = hdmi_pdev;
+
return 0;
error:
pr_err("%s: ret due to err\n", __func__);
@@ -719,10 +737,6 @@
}
}
-uint8_t check_tmds_enabled(void)
-{
- return store_tmds_state;
-}
void mhl_tmds_ctrl(struct mhl_tx_ctrl *mhl_ctrl, uint8_t on)
{
@@ -730,16 +744,8 @@
if (on) {
MHL_SII_REG_NAME_MOD(REG_TMDS_CCTRL, BIT4, BIT4);
mhl_drive_hpd(mhl_ctrl, HPD_UP);
- /*
- * store the state to be used
- * before responding to RAP msgs
- * this needs to be obtained from
- * hdmi driver
- */
- store_tmds_state = 1;
} else {
MHL_SII_REG_NAME_MOD(REG_TMDS_CCTRL, BIT4, 0x00);
- store_tmds_state = 0;
}
}
@@ -1007,7 +1013,10 @@
*/
cbus_stat = MHL_SII_CBUS_RD(0x0D);
if (BIT6 & cbus_stat)
- mhl_tmds_ctrl(mhl_ctrl, TMDS_ENABLE);
+ mhl_drive_hpd(mhl_ctrl, HPD_UP);
+ else
+ mhl_drive_hpd(mhl_ctrl, HPD_DOWN);
+
}
}
@@ -1636,6 +1645,7 @@
struct mhl_tx_platform_data *pdata = NULL;
struct mhl_tx_ctrl *mhl_ctrl;
struct usb_ext_notification *mhl_info = NULL;
+ struct msm_hdmi_mhl_ops *hdmi_mhl_ops = NULL;
mhl_ctrl = devm_kzalloc(&client->dev, sizeof(*mhl_ctrl), GFP_KERNEL);
if (!mhl_ctrl) {
@@ -1784,25 +1794,63 @@
goto failed_probe;
}
+ hdmi_mhl_ops = devm_kzalloc(&client->dev,
+ sizeof(struct msm_hdmi_mhl_ops),
+ GFP_KERNEL);
+ if (!hdmi_mhl_ops) {
+ pr_err("%s: alloc hdmi mhl ops failed\n", __func__);
+ rc = -ENOMEM;
+ goto failed_probe_pwr;
+ }
+
pr_debug("%s: i2c client addr is [%x]\n", __func__, client->addr);
+ if (mhl_ctrl->pdata->hdmi_pdev) {
+ rc = msm_hdmi_register_mhl(mhl_ctrl->pdata->hdmi_pdev,
+ hdmi_mhl_ops);
+ if (rc) {
+ pr_err("%s: register with hdmi failed\n", __func__);
+ rc = -EPROBE_DEFER;
+ goto failed_probe_pwr;
+ }
+ }
+
+ if (!hdmi_mhl_ops || !hdmi_mhl_ops->tmds_enabled ||
+ !hdmi_mhl_ops->set_mhl_max_pclk) {
+ pr_err("%s: func ptr is NULL\n", __func__);
+ rc = -EINVAL;
+ goto failed_probe_pwr;
+ }
+ mhl_ctrl->hdmi_mhl_ops = hdmi_mhl_ops;
+
+ rc = hdmi_mhl_ops->set_mhl_max_pclk(
+ mhl_ctrl->pdata->hdmi_pdev, MAX_MHL_PCLK);
+ if (rc) {
+ pr_err("%s: can't set max mhl pclk\n", __func__);
+ goto failed_probe_pwr;
+ }
mhl_info = devm_kzalloc(&client->dev, sizeof(*mhl_info), GFP_KERNEL);
if (!mhl_info) {
pr_err("%s: alloc mhl info failed\n", __func__);
- goto failed_probe;
+ rc = -ENOMEM;
+ goto failed_probe_pwr;
}
mhl_info->ctxt = mhl_ctrl;
mhl_info->notify = mhl_sii_device_discovery;
if (msm_register_usb_ext_notification(mhl_info)) {
pr_err("%s: register for usb notifcn failed\n", __func__);
- goto failed_probe;
+ rc = -EPROBE_DEFER;
+ goto failed_probe_pwr;
}
mhl_ctrl->mhl_info = mhl_info;
mhl_register_msc(mhl_ctrl);
- mhl_ctrl->tmds_enabled = check_tmds_enabled;
return 0;
+
+failed_probe_pwr:
+ power_supply_unregister(&mhl_ctrl->mhl_psy);
failed_probe:
+ free_irq(mhl_ctrl->i2c_handle->irq, mhl_ctrl);
mhl_gpio_config(mhl_ctrl, 0);
mhl_vreg_config(mhl_ctrl, 0);
/* do not deep-free */
@@ -1814,6 +1862,9 @@
failed_no_mem:
if (mhl_ctrl)
devm_kfree(&client->dev, mhl_ctrl);
+ mhl_info = NULL;
+ pdata = NULL;
+ mhl_ctrl = NULL;
pr_err("%s: PROBE FAILED, rc=%d\n", __func__, rc);
return rc;
}
diff --git a/include/asm-generic/dma-contiguous.h b/include/asm-generic/dma-contiguous.h
index c544356..294b1e7 100644
--- a/include/asm-generic/dma-contiguous.h
+++ b/include/asm-generic/dma-contiguous.h
@@ -18,7 +18,7 @@
{
if (dev)
dev->cma_area = cma;
- if (!dev || !dma_contiguous_default_area)
+ if (!dev && !dma_contiguous_default_area)
dma_contiguous_default_area = cma;
}
diff --git a/include/linux/coresight-cti.h b/include/linux/coresight-cti.h
new file mode 100644
index 0000000..7f2da3f
--- /dev/null
+++ b/include/linux/coresight-cti.h
@@ -0,0 +1,59 @@
+/* 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 _LINUX_CORESIGHT_CTI_H
+#define _LINUX_CORESIGHT_CTI_H
+
+struct coresight_cti_data {
+ int nr_ctis;
+ const char **names;
+};
+
+struct coresight_cti {
+ const char *name;
+ struct list_head link;
+};
+
+#ifdef CONFIG_CORESIGHT_CTI
+extern struct coresight_cti *coresight_cti_get(const char *name);
+extern void coresight_cti_put(struct coresight_cti *cti);
+extern int coresight_cti_map_trigin(
+ struct coresight_cti *cti, int trig, int ch);
+extern int coresight_cti_map_trigout(
+ struct coresight_cti *cti, int trig, int ch);
+extern void coresight_cti_unmap_trigin(
+ struct coresight_cti *cti, int trig, int ch);
+extern void coresight_cti_unmap_trigout(
+ struct coresight_cti *cti, int trig, int ch);
+#else
+static inline struct coresight_cti *coresight_cti_get(const char *name)
+{
+ return NULL;
+}
+static inline void coresight_cti_put(struct coresight_cti *cti) {}
+static inline int coresight_cti_map_trigin(
+ struct coresight_cti *cti, int trig, int ch)
+{
+ return -ENOSYS;
+}
+static inline int coresight_cti_map_trigout(
+ struct coresight_cti *cti, int trig, int ch)
+{
+ return -ENOSYS;
+}
+static inline void coresight_cti_unmap_trigin(
+ struct coresight_cti *cti, int trig, int ch) {}
+static inline void coresight_cti_unmap_trigout(
+ struct coresight_cti *cti, int trig, int ch) {}
+#endif
+
+#endif
diff --git a/include/linux/dma-contiguous.h b/include/linux/dma-contiguous.h
index 2f303e4..01b5c84 100644
--- a/include/linux/dma-contiguous.h
+++ b/include/linux/dma-contiguous.h
@@ -68,7 +68,7 @@
extern struct cma *dma_contiguous_default_area;
void dma_contiguous_reserve(phys_addr_t addr_limit);
-int dma_declare_contiguous(struct device *dev, unsigned long size,
+int dma_declare_contiguous(struct device *dev, phys_addr_t size,
phys_addr_t base, phys_addr_t limit);
struct page *dma_alloc_from_contiguous(struct device *dev, int count,
@@ -83,7 +83,7 @@
static inline void dma_contiguous_reserve(phys_addr_t limit) { }
static inline
-int dma_declare_contiguous(struct device *dev, unsigned long size,
+int dma_declare_contiguous(struct device *dev, phys_addr_t size,
phys_addr_t base, phys_addr_t limit)
{
return -ENOSYS;
diff --git a/include/linux/ion.h b/include/linux/ion.h
index f27782f..f159fe2 100644
--- a/include/linux/ion.h
+++ b/include/linux/ion.h
@@ -2,7 +2,7 @@
* include/linux/ion.h
*
* Copyright (C) 2011 Google, Inc.
- * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -482,6 +482,10 @@
return -ENODEV;
}
+static inline void ion_mark_dangling_buffers_locked(struct ion_device *dev)
+{
+}
+
static inline int msm_ion_do_cache_op(struct ion_client *client,
struct ion_handle *handle, void *vaddr,
unsigned long len, unsigned int cmd)
diff --git a/include/linux/mhl_8334.h b/include/linux/mhl_8334.h
index 75e6546..d6f8356 100644
--- a/include/linux/mhl_8334.h
+++ b/include/linux/mhl_8334.h
@@ -50,6 +50,8 @@
u8 data[MHL_SCRATCHPAD_SIZE];
};
+/* MHL 8334 supports a max HD pixel clk of 75 MHz */
+#define MAX_MHL_PCLK 75000
/* USB driver interface */
@@ -124,6 +126,7 @@
struct dss_gpio *gpios[MHL_TX_MAX_GPIO];
struct dss_vreg *vregs[MHL_TX_MAX_VREG];
int irq;
+ struct platform_device *hdmi_pdev;
};
struct mhl_tx_ctrl {
@@ -144,7 +147,7 @@
uint8_t devcap[16];
uint8_t devcap_state;
uint8_t path_en_state;
- uint8_t (*tmds_enabled)(void);
+ void *hdmi_mhl_ops;
struct work_struct mhl_msc_send_work;
struct list_head list_cmd;
struct input_dev *input;
diff --git a/include/linux/msm_audio_aac.h b/include/linux/msm_audio_aac.h
index ee71c3e..88024d9 100644
--- a/include/linux/msm_audio_aac.h
+++ b/include/linux/msm_audio_aac.h
@@ -14,6 +14,9 @@
#define AUDIO_GET_AAC_ENC_CONFIG _IOR(AUDIO_IOCTL_MAGIC, \
(AUDIO_MAX_COMMON_IOCTL_NUM+4), struct msm_audio_aac_enc_config)
+#define AUDIO_SET_AAC_MIX_CONFIG _IOR(AUDIO_IOCTL_MAGIC, \
+(AUDIO_MAX_COMMON_IOCTL_NUM+5), unsigned)
+
#define AUDIO_AAC_FORMAT_ADTS -1
#define AUDIO_AAC_FORMAT_RAW 0x0000
#define AUDIO_AAC_FORMAT_PSUEDO_RAW 0x0001
diff --git a/include/linux/msm_ion.h b/include/linux/msm_ion.h
index 409bcc8..2593154 100644
--- a/include/linux/msm_ion.h
+++ b/include/linux/msm_ion.h
@@ -281,6 +281,20 @@
{
return -ENODEV;
}
+
+static inline int msm_ion_secure_buffer(struct ion_client *client,
+ struct ion_handle *handle,
+ enum cp_mem_usage usage,
+ int flags)
+{
+ return -ENODEV;
+}
+
+static inline int msm_ion_unsecure_buffer(struct ion_client *client,
+ struct ion_handle *handle)
+{
+ return -ENODEV;
+}
#endif /* CONFIG_ION */
#endif /* __KERNEL */
@@ -305,19 +319,6 @@
unsigned int length;
};
-/* struct ion_flag_data - information about flags for this buffer
- *
- * @handle: handle to get flags from
- * @flags: flags of this handle
- *
- * Takes handle as an input and outputs the flags from the handle
- * in the flag field.
- */
-struct ion_flag_data {
- struct ion_handle *handle;
- unsigned long flags;
-};
-
#define ION_IOC_MSM_MAGIC 'M'
/**
@@ -342,13 +343,4 @@
#define ION_IOC_CLEAN_INV_CACHES _IOWR(ION_IOC_MSM_MAGIC, 2, \
struct ion_flush_data)
-/**
- * DOC: ION_IOC_GET_FLAGS - get the flags of the handle
- *
- * Gets the flags of the current handle which indicate cachability,
- * secure state etc.
- */
-#define ION_IOC_GET_FLAGS _IOWR(ION_IOC_MSM_MAGIC, 3, \
- struct ion_flag_data)
-
#endif
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index bc35d14..404ea52 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -646,8 +646,13 @@
ROTATOR_SUBSYSTEM_ID,
};
+enum {
+ MDP_IOMMU_DOMAIN_CP,
+ MDP_IOMMU_DOMAIN_NS,
+};
+
#ifdef __KERNEL__
-int msm_fb_get_iommu_domain(void);
+int msm_fb_get_iommu_domain(struct fb_info *info, int domain);
/* get the framebuffer physical address information */
int get_fb_phys_info(unsigned long *start, unsigned long *len, int fb_num,
int subsys_id);
@@ -660,6 +665,7 @@
struct msmfb_data *data);
int msm_fb_writeback_stop(struct fb_info *info);
int msm_fb_writeback_terminate(struct fb_info *info);
+int msm_fb_writeback_set_secure(struct fb_info *info, int enable);
#endif
#endif /*_MSM_MDP_H_*/
diff --git a/include/linux/of_coresight.h b/include/linux/of_coresight.h
index 6a5e4d4..0943dda 100644
--- a/include/linux/of_coresight.h
+++ b/include/linux/of_coresight.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,12 +16,19 @@
#ifdef CONFIG_OF
extern struct coresight_platform_data *of_get_coresight_platform_data(
struct device *dev, struct device_node *node);
+extern struct coresight_cti_data *of_get_coresight_cti_data(
+ struct device *dev, struct device_node *node);
#else
static inline struct coresight_platform_data *of_get_coresight_platform_data(
struct device *dev, struct device_node *node)
{
return NULL;
}
+static inline struct coresight_cti_data *of_get_coresight_cti_data(
+ struct device *dev, struct device_node *node)
+{
+ return NULL;
+}
#endif
#endif
diff --git a/include/linux/platform_data/qcom_ssm.h b/include/linux/platform_data/qcom_ssm.h
new file mode 100644
index 0000000..03ac67a
--- /dev/null
+++ b/include/linux/platform_data/qcom_ssm.h
@@ -0,0 +1,21 @@
+/* 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 __QCOM_SSM_H_
+#define __QCOM_SSM_H_
+
+struct ssm_platform_data {
+ bool need_key_exchg;
+ const char *channel_name;
+};
+
+#endif /* __QCOM_SSM_H_ */
diff --git a/include/linux/wcnss_wlan.h b/include/linux/wcnss_wlan.h
index 2b9a7c7..2319c48 100644
--- a/include/linux/wcnss_wlan.h
+++ b/include/linux/wcnss_wlan.h
@@ -65,6 +65,7 @@
void wcnss_resume_notify(void);
void wcnss_riva_log_debug_regs(void);
void wcnss_pronto_log_debug_regs(void);
+int wcnss_cold_boot_done(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/sound/apr_audio.h b/include/sound/apr_audio.h
index de41c6e..40b0e1e 100644
--- a/include/sound/apr_audio.h
+++ b/include/sound/apr_audio.h
@@ -1,6 +1,6 @@
/*
*
- * 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
@@ -1513,6 +1513,17 @@
struct asm_dual_mono channel_map;
} __packed;
+#define ASM_PARAM_ID_AAC_STEREO_MIX_COEFF_SELECTION_FLAG 0x00010DD8
+
+/* Structure for AAC decoder stereo coefficient setting. */
+
+struct asm_aac_stereo_mix_coeff_selection_param {
+ struct apr_hdr hdr;
+ u32 param_id;
+ u32 param_size;
+ u32 aac_stereo_mix_coeff_flag;
+} __packed;
+
#define ASM_ENCDEC_DEC_CHAN_MAP 0x00010D82
struct asm_stream_cmd_encdec_channelmap {
struct apr_hdr hdr;
diff --git a/include/sound/q6asm-v2.h b/include/sound/q6asm-v2.h
index dc30cd6..5744a43 100644
--- a/include/sound/q6asm-v2.h
+++ b/include/sound/q6asm-v2.h
@@ -249,6 +249,8 @@
int q6asm_cfg_dual_mono_aac(struct audio_client *ac,
uint16_t sce_left, uint16_t sce_right);
+int q6asm_cfg_aac_sel_mix_coef(struct audio_client *ac, uint32_t mix_coeff);
+
int q6asm_enc_cfg_blk_qcelp(struct audio_client *ac, uint32_t frames_per_buf,
uint16_t min_rate, uint16_t max_rate,
uint16_t reduced_rate_level, uint16_t rate_modulation_cmd);
diff --git a/include/sound/q6asm.h b/include/sound/q6asm.h
index 42c9120..406407d 100644
--- a/include/sound/q6asm.h
+++ b/include/sound/q6asm.h
@@ -86,18 +86,18 @@
#define SESSION_MAX 0x08
-#define SOFT_PAUSE_PERIOD 30 /* ramp up/down for 30ms */
+#define SOFT_PAUSE_PERIOD 30 /* ramp up/down for 30ms */
#define SOFT_PAUSE_STEP_LINEAR 0 /* Step value 0ms or 0us */
-#define SOFT_PAUSE_STEP 2000 /* Step value 2000ms or 2000us */
+#define SOFT_PAUSE_STEP 0 /* Step value 0ms or 0us */
enum {
SOFT_PAUSE_CURVE_LINEAR = 0,
SOFT_PAUSE_CURVE_EXP,
SOFT_PAUSE_CURVE_LOG,
};
-#define SOFT_VOLUME_PERIOD 30 /* ramp up/down for 30ms */
+#define SOFT_VOLUME_PERIOD 30 /* ramp up/down for 30ms */
#define SOFT_VOLUME_STEP_LINEAR 0 /* Step value 0ms or 0us */
-#define SOFT_VOLUME_STEP 2000 /* Step value 2000ms or 2000us */
+#define SOFT_VOLUME_STEP 0 /* Step value 0ms or 0us */
enum {
SOFT_VOLUME_CURVE_LINEAR = 0,
SOFT_VOLUME_CURVE_EXP,
@@ -273,6 +273,8 @@
int q6asm_cfg_dual_mono_aac(struct audio_client *ac,
uint16_t sce_left, uint16_t sce_right);
+int q6asm_cfg_aac_sel_mix_coef(struct audio_client *ac, uint32_t mix_coeff);
+
int q6asm_set_encdec_chan_map(struct audio_client *ac,
uint32_t num_channels);
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 7ecbc70..9962c88 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1474,6 +1474,8 @@
hdev->sniff_max_interval = 800;
hdev->sniff_min_interval = 80;
+ set_bit(HCI_SETUP, &hdev->flags);
+
tasklet_init(&hdev->cmd_task, hci_cmd_task, (unsigned long) hdev);
tasklet_init(&hdev->rx_task, hci_rx_task, (unsigned long) hdev);
tasklet_init(&hdev->tx_task, hci_tx_task, (unsigned long) hdev);
@@ -1542,7 +1544,6 @@
}
set_bit(HCI_AUTO_OFF, &hdev->flags);
- set_bit(HCI_SETUP, &hdev->flags);
queue_work(hdev->workqueue, &hdev->power_on);
hci_notify(hdev, HCI_DEV_REG);
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index a1f2955..8658b94 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -383,23 +383,30 @@
err = cmd_status(sk, index, MGMT_OP_SET_POWERED, EBUSY);
goto failed;
}
+ /* Avoid queing power_on/off when the set up is going on via
+ * hci_register_dev
+ */
+ if (!test_bit(HCI_SETUP, &hdev->flags)) {
+ cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, index, data,
+ len);
+ if (!cmd) {
+ err = -ENOMEM;
+ goto failed;
+ }
- cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, index, data, len);
- if (!cmd) {
- err = -ENOMEM;
+ hci_dev_unlock_bh(hdev);
+
+ if (cp->val)
+ queue_work(hdev->workqueue, &hdev->power_on);
+ else
+ queue_work(hdev->workqueue, &hdev->power_off);
+
+ err = 0;
+ hci_dev_put(hdev);
+ } else {
+ err = cmd_status(sk, index, MGMT_OP_SET_POWERED, ENODEV);
goto failed;
}
-
- hci_dev_unlock_bh(hdev);
-
- if (cp->val)
- queue_work(hdev->workqueue, &hdev->power_on);
- else
- queue_work(hdev->workqueue, &hdev->power_off);
-
- err = 0;
- hci_dev_put(hdev);
-
return err;
failed:
diff --git a/sound/soc/codecs/msm8x10-wcd.c b/sound/soc/codecs/msm8x10-wcd.c
index 4bcea07..c8647fb1 100644
--- a/sound/soc/codecs/msm8x10-wcd.c
+++ b/sound/soc/codecs/msm8x10-wcd.c
@@ -50,9 +50,9 @@
#define MSM8X10_WCD_I2S_MASTER_MODE_MASK 0x08
#define MSM8X10_DINO_CODEC_BASE_ADDR 0xFE043000
-#define MAX_MSM8X10_WCD_DEVICE 2
+#define MAX_MSM8X10_WCD_DEVICE 4
#define CODEC_DT_MAX_PROP_SIZE 40
-#define MSM8X10_WCD_I2C_GSBI_SLAVE_ID "2-000d"
+#define MSM8X10_WCD_I2C_GSBI_SLAVE_ID "1-000d"
enum {
MSM8X10_WCD_I2C_TOP_LEVEL = 0,
@@ -88,6 +88,7 @@
IIR2,
IIR_MAX,
};
+
/* Codec supports 5 bands */
enum {
BAND1 = 0,
@@ -119,7 +120,6 @@
struct wcd9xxx_mbhc mbhc;
};
-
static unsigned short rx_digital_gain_reg[] = {
MSM8X10_WCD_A_CDC_RX1_VOL_CTL_B2_CTL,
MSM8X10_WCD_A_CDC_RX2_VOL_CTL_B2_CTL,
@@ -171,7 +171,7 @@
return rtn;
}
-static int msm8x10_wcd_abh_write_device(u16 reg, u8 *value, u32 bytes)
+static int msm8x10_wcd_abh_write_device(u16 reg, unsigned int *value, u32 bytes)
{
u32 temp = ((u32)(*value)) & 0x000000FF;
u32 offset = (((u32)(reg)) ^ 0x00000400) & 0x00000FFF;
@@ -179,10 +179,10 @@
return 0;
}
-static int msm8x10_wcd_abh_read_device(u16 reg, u32 bytes, u8 *value)
+static int msm8x10_wcd_abh_read_device(u16 reg, u32 bytes, unsigned int *value)
{
u32 offset = (((u32)(reg)) ^ 0x00000400) & 0x00000FFF;
- *value = (u8)ioread32(ioremap(MSM8X10_DINO_CODEC_BASE_ADDR +
+ *value = ioread32(ioremap(MSM8X10_DINO_CODEC_BASE_ADDR +
offset, 4));
return 0;
}
@@ -194,10 +194,10 @@
int ret;
u8 reg_addr = 0;
u8 data[bytes + 1];
- struct msm8x10_wcd_i2c *msm8x10_wcd;
+ struct msm8x10_wcd_i2c *msm8x10_wcd = NULL;
ret = get_i2c_msm8x10_wcd_device_info(reg, &msm8x10_wcd);
- if (!ret) {
+ if (ret) {
pr_err("%s: Invalid register address\n", __func__);
return ret;
}
@@ -219,7 +219,7 @@
/* Try again if the write fails */
if (ret != 1) {
ret = i2c_transfer(msm8x10_wcd->client->adapter,
- msm8x10_wcd->xfer_msg, 1);
+ msm8x10_wcd->xfer_msg, 1);
if (ret != 1) {
pr_err("failed to write the device\n");
return ret;
@@ -235,11 +235,11 @@
struct i2c_msg *msg;
int ret = 0;
u8 reg_addr = 0;
- struct msm8x10_wcd_i2c *msm8x10_wcd;
+ struct msm8x10_wcd_i2c *msm8x10_wcd = NULL;
u8 i = 0;
ret = get_i2c_msm8x10_wcd_device_info(reg, &msm8x10_wcd);
- if (!ret) {
+ if (ret) {
pr_err("%s: Invalid register address\n", __func__);
return ret;
}
@@ -256,7 +256,6 @@
msg->len = 1;
msg->flags = 0;
msg->buf = ®_addr;
-
msg = &msm8x10_wcd->xfer_msg[1];
msg->addr = msm8x10_wcd->client->addr;
msg->len = 1;
@@ -275,38 +274,45 @@
}
}
}
+ pr_debug("%s: Reg 0x%x = 0x%x\n", __func__, reg, *dest);
return 0;
}
-static int msm8x10_wcd_reg_read(struct msm8x10_wcd *msm8x10_wcd, u16 reg)
+int msm8x10_wcd_i2c_read(unsigned short reg, int bytes, void *dest)
{
- u8 val;
+ return msm8x10_wcd_i2c_read_device(reg, bytes, dest);
+}
+
+int msm8x10_wcd_i2c_write(unsigned short reg, int bytes, void *src)
+{
+ return msm8x10_wcd_i2c_write_device(reg, src, bytes);
+}
+
+static int msm8x10_wcd_reg_read(struct msm8x10_wcd *msm8x10_wcd,
+ u16 reg, unsigned int *val)
+{
int ret = -EINVAL;
/* check if use I2C interface for Helicon or AHB for Dino */
mutex_lock(&msm8x10_wcd->io_lock);
if (MSM8X10_WCD_IS_HELICON_REG(reg))
- ret = msm8x10_wcd_i2c_read_device(reg, 1, &val);
+ ret = msm8x10_wcd_i2c_read(reg, 1, val);
else if (MSM8X10_WCD_IS_DINO_REG(reg))
- ret = msm8x10_wcd_abh_read_device(reg, 1, &val);
+ ret = msm8x10_wcd_abh_read_device(reg, 1, val);
mutex_unlock(&msm8x10_wcd->io_lock);
-
- if (ret < 0)
- return ret;
- else
- return val;
+ return ret;
}
static int msm8x10_wcd_reg_write(struct msm8x10_wcd *msm8x10_wcd, u16 reg,
- u8 val)
+ unsigned int val)
{
int ret = -EINVAL;
/* check if use I2C interface for Helicon or AHB for Dino */
mutex_lock(&msm8x10_wcd->io_lock);
if (MSM8X10_WCD_IS_HELICON_REG(reg))
- ret = msm8x10_wcd_i2c_write_device(reg, &val, 1);
+ ret = msm8x10_wcd_i2c_write(reg, 1, &val);
else if (MSM8X10_WCD_IS_DINO_REG(reg))
ret = msm8x10_wcd_abh_write_device(reg, &val, 1);
mutex_unlock(&msm8x10_wcd->io_lock);
@@ -331,12 +337,13 @@
return rtn;
}
-static int msm8x10_wcd_volatile(struct snd_soc_codec *ssc, unsigned int reg)
+static int msm8x10_wcd_volatile(struct snd_soc_codec *codec, unsigned int reg)
{
/*
* Registers lower than 0x100 are top level registers which can be
* written by the Taiko core driver.
*/
+ dev_dbg(codec->dev, "%s: reg 0x%x\n", __func__, reg);
if ((reg >= MSM8X10_WCD_A_CDC_MBHC_EN_CTL) || (reg < 0x100))
return 1;
@@ -373,7 +380,7 @@
unsigned int value)
{
int ret;
-
+ dev_dbg(codec->dev, "%s: Write from reg 0x%x\n", __func__, reg);
if (reg == SND_SOC_NOPM)
return 0;
@@ -395,6 +402,7 @@
unsigned int val;
int ret;
+ dev_dbg(codec->dev, "%s: Read from reg 0x%x\n", __func__, reg);
if (reg == SND_SOC_NOPM)
return 0;
@@ -411,7 +419,7 @@
reg, ret);
}
- val = msm8x10_wcd_reg_read(codec->control_data, reg);
+ ret = msm8x10_wcd_reg_read(codec->control_data, reg, &val);
return val;
}
@@ -431,7 +439,7 @@
if (!regnode) {
dev_err(dev, "Looking up %s property in node %s failed",
- prop_name, dev->of_node->full_name);
+ prop_name, dev->of_node->full_name);
return -ENODEV;
}
vreg->name = vreg_name;
@@ -442,7 +450,7 @@
if (!prop || (len != (2 * sizeof(__be32)))) {
dev_err(dev, "%s %s property\n",
- prop ? "invalid format" : "no", prop_name);
+ prop ? "invalid format" : "no", prop_name);
return -ENODEV;
} else {
vreg->min_uV = be32_to_cpup(&prop[0]);
@@ -450,18 +458,18 @@
}
snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
- "qcom,%s-current", vreg_name);
+ "qcom,%s-current", vreg_name);
ret = of_property_read_u32(dev->of_node, prop_name, &prop_val);
if (ret) {
dev_err(dev, "Looking up %s property in node %s failed",
- prop_name, dev->of_node->full_name);
+ prop_name, dev->of_node->full_name);
return -ENODEV;
}
vreg->optimum_uA = prop_val;
dev_info(dev, "%s: vol=[%d %d]uV, curr=[%d]uA\n", vreg->name,
- vreg->min_uV, vreg->max_uV, vreg->optimum_uA);
+ vreg->min_uV, vreg->max_uV, vreg->optimum_uA);
return 0;
}
@@ -473,7 +481,7 @@
u32 prop_val;
snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
- "qcom,cdc-micbias-ldoh-v");
+ "qcom,cdc-micbias-ldoh-v");
ret = of_property_read_u32(dev->of_node, prop_name, &prop_val);
if (ret) {
dev_err(dev, "Looking up %s property in node %s failed",
@@ -483,7 +491,7 @@
micbias->ldoh_v = (u8)prop_val;
snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
- "qcom,cdc-micbias-cfilt1-mv");
+ "qcom,cdc-micbias-cfilt1-mv");
ret = of_property_read_u32(dev->of_node, prop_name,
&micbias->cfilt1_mv);
if (ret) {
@@ -493,7 +501,7 @@
}
snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
- "qcom,cdc-micbias1-cfilt-sel");
+ "qcom,cdc-micbias1-cfilt-sel");
ret = of_property_read_u32(dev->of_node, prop_name, &prop_val);
if (ret) {
dev_err(dev, "Looking up %s property in node %s failed",
@@ -508,7 +516,7 @@
MICBIAS_EXT_BYP_CAP : MICBIAS_NO_EXT_BYP_CAP);
dev_dbg(dev, "ldoh_v %u cfilt1_mv %u\n",
- (u32)micbias->ldoh_v, (u32)micbias->cfilt1_mv);
+ (u32)micbias->ldoh_v, (u32)micbias->cfilt1_mv);
dev_dbg(dev, "bias1_cfilt_sel %u\n", (u32)micbias->bias1_cfilt_sel);
dev_dbg(dev, "bias1_ext_cap %d\n", micbias->bias1_cap_mode);
@@ -533,13 +541,14 @@
num_of_supplies = ARRAY_SIZE(msm8x10_wcd_supplies);
} else {
dev_err(dev, "%s unsupported device %s\n",
- __func__, dev_name(dev));
+ __func__, dev_name(dev));
goto err;
}
if (num_of_supplies > ARRAY_SIZE(pdata->regulator)) {
dev_err(dev, "%s: Num of supplies %u > max supported %u\n",
- __func__, num_of_supplies, ARRAY_SIZE(pdata->regulator));
+ __func__, num_of_supplies,
+ ARRAY_SIZE(pdata->regulator));
goto err;
}
@@ -574,8 +583,8 @@
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = w->codec;
+ dev_dbg(codec->dev, "%s: event = %d\n", __func__, event);
- pr_debug("%s %d\n", __func__, event);
switch (event) {
case SND_SOC_DAPM_POST_PMU:
/* Enable charge pump clock*/
@@ -623,13 +632,11 @@
} else if (ear_pa_gain == 0x04) {
ucontrol->value.integer.value[0] = 1;
} else {
- pr_err("%s: ERROR: Unsupported Ear Gain = 0x%x\n",
- __func__, ear_pa_gain);
+ dev_err(codec->dev, "%s: ERROR: Unsupported Ear Gain = 0x%x\n",
+ __func__, ear_pa_gain);
return -EINVAL;
}
-
- pr_debug("%s: ear_pa_gain = 0x%x\n", __func__, ear_pa_gain);
-
+ dev_dbg(codec->dev, "%s: ear_pa_gain = 0x%x\n", __func__, ear_pa_gain);
return 0;
}
@@ -639,8 +646,8 @@
u8 ear_pa_gain;
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
- pr_debug("%s: ucontrol->value.integer.value[0] = %ld\n",
- __func__, ucontrol->value.integer.value[0]);
+ dev_dbg(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
+ __func__, ucontrol->value.integer.value[0]);
switch (ucontrol->value.integer.value[0]) {
case 0:
@@ -673,7 +680,7 @@
(MSM8X10_WCD_A_CDC_IIR1_CTL + 64 * iir_idx)) &
(1 << band_idx);
- pr_debug("%s: IIR #%d band #%d enable %d\n", __func__,
+ dev_dbg(codec->dev, "%s: IIR #%d band #%d enable %d\n", __func__,
iir_idx, band_idx,
(uint32_t)ucontrol->value.integer.value[0]);
return 0;
@@ -692,15 +699,15 @@
/* Mask first 5 bits, 6-8 are reserved */
snd_soc_update_bits(codec, (MSM8X10_WCD_A_CDC_IIR1_CTL + 64 * iir_idx),
- (1 << band_idx), (value << band_idx));
+ (1 << band_idx), (value << band_idx));
- pr_debug("%s: IIR #%d band #%d enable %d\n", __func__,
+ dev_dbg(codec->dev, "%s: IIR #%d band #%d enable %d\n", __func__,
iir_idx, band_idx, value);
return 0;
}
static uint32_t get_iir_band_coeff(struct snd_soc_codec *codec,
- int iir_idx, int band_idx,
- int coeff_idx)
+ int iir_idx, int band_idx,
+ int coeff_idx)
{
/* Address does not automatically update if reading */
snd_soc_write(codec,
@@ -734,7 +741,7 @@
ucontrol->value.integer.value[4] =
get_iir_band_coeff(codec, iir_idx, band_idx, 4);
- pr_debug("%s: IIR #%d band #%d b0 = 0x%x\n"
+ dev_dbg(codec->dev, "%s: IIR #%d band #%d b0 = 0x%x\n"
"%s: IIR #%d band #%d b1 = 0x%x\n"
"%s: IIR #%d band #%d b2 = 0x%x\n"
"%s: IIR #%d band #%d a1 = 0x%x\n"
@@ -780,17 +787,17 @@
kcontrol->private_value)->shift;
set_iir_band_coeff(codec, iir_idx, band_idx, 0,
- ucontrol->value.integer.value[0]);
+ ucontrol->value.integer.value[0]);
set_iir_band_coeff(codec, iir_idx, band_idx, 1,
- ucontrol->value.integer.value[1]);
+ ucontrol->value.integer.value[1]);
set_iir_band_coeff(codec, iir_idx, band_idx, 2,
- ucontrol->value.integer.value[2]);
+ ucontrol->value.integer.value[2]);
set_iir_band_coeff(codec, iir_idx, band_idx, 3,
- ucontrol->value.integer.value[3]);
+ ucontrol->value.integer.value[3]);
set_iir_band_coeff(codec, iir_idx, band_idx, 4,
- ucontrol->value.integer.value[4]);
+ ucontrol->value.integer.value[4]);
- pr_debug("%s: IIR #%d band #%d b0 = 0x%x\n"
+ dev_dbg(codec->dev, "%s: IIR #%d band #%d b0 = 0x%x\n"
"%s: IIR #%d band #%d b1 = 0x%x\n"
"%s: IIR #%d band #%d b2 = 0x%x\n"
"%s: IIR #%d band #%d a1 = 0x%x\n"
@@ -970,7 +977,6 @@
"ZERO", "ADC1", "ADC2", "DMIC1", "DMIC2"
};
-
static const char * const anc_mux_text[] = {
"ZERO", "ADC1", "ADC2", "ADC3", "ADC4", "ADC5", "ADC6", "ADC_MB",
"RSVD_1", "DMIC1", "DMIC2", "DMIC3", "DMIC4", "DMIC5", "DMIC6"
@@ -1076,14 +1082,16 @@
dec_name = strsep(&widget_name, " ");
widget_name = temp;
if (!dec_name) {
- pr_err("%s: Invalid decimator = %s\n", __func__, w->name);
+ dev_err(codec->dev, "%s: Invalid decimator = %s\n",
+ __func__, w->name);
ret = -EINVAL;
goto out;
}
ret = kstrtouint(strpbrk(dec_name, "12"), 10, &decimator);
if (ret < 0) {
- pr_err("%s: Invalid decimator = %s\n", __func__, dec_name);
+ dev_err(codec->dev, "%s: Invalid decimator = %s\n",
+ __func__, dec_name);
ret = -EINVAL;
goto out;
}
@@ -1100,7 +1108,8 @@
adc_dmic_sel = 0x0;
break;
default:
- pr_err("%s: Invalid Decimator = %u\n", __func__, decimator);
+ dev_err(codec->dev, "%s: Invalid Decimator = %u\n",
+ __func__, decimator);
ret = -EINVAL;
goto out;
}
@@ -1204,18 +1213,18 @@
static void msm8x10_wcd_codec_enable_adc_block(struct snd_soc_codec *codec,
int enable)
{
- struct msm8x10_wcd_priv *taiko = snd_soc_codec_get_drvdata(codec);
+ struct msm8x10_wcd_priv *wcd8x10 = snd_soc_codec_get_drvdata(codec);
- pr_debug("%s %d\n", __func__, enable);
+ dev_dbg(codec->dev, "%s %d\n", __func__, enable);
if (enable) {
- taiko->adc_count++;
+ wcd8x10->adc_count++;
snd_soc_update_bits(codec,
MSM8X10_WCD_A_CDC_ANA_CLK_CTL,
0x20, 0x20);
} else {
- taiko->adc_count--;
- if (!taiko->adc_count)
+ wcd8x10->adc_count--;
+ if (!wcd8x10->adc_count)
snd_soc_update_bits(codec,
MSM8X10_WCD_A_CDC_ANA_CLK_CTL,
0x20, 0x0);
@@ -1229,7 +1238,7 @@
u16 adc_reg;
u8 init_bit_shift;
- pr_debug("%s %d\n", __func__, event);
+ dev_dbg(codec->dev, "%s %d\n", __func__, event);
adc_reg = MSM8X10_WCD_A_TX_1_2_TEST_CTL;
if (w->reg == MSM8X10_WCD_A_TX_1_EN)
@@ -1237,7 +1246,8 @@
else if (adc_reg == MSM8X10_WCD_A_TX_2_EN)
init_bit_shift = 6;
else {
- pr_err("%s: Error, invalid adc register\n", __func__);
+ dev_err(codec->dev, "%s: Error, invalid adc register\n",
+ __func__);
return -EINVAL;
}
@@ -1263,14 +1273,15 @@
struct snd_soc_codec *codec = w->codec;
u16 lineout_gain_reg;
- pr_debug("%s %d %s\n", __func__, event, w->name);
+ dev_dbg(codec->dev, "%s %d %s\n", __func__, event, w->name);
switch (w->shift) {
case 0:
lineout_gain_reg = MSM8X10_WCD_A_RX_LINE_1_GAIN;
break;
default:
- pr_err("%s: Error, incorrect lineout register value\n",
+ dev_err(codec->dev,
+ "%s: Error, incorrect lineout register value\n",
__func__);
return -EINVAL;
}
@@ -1280,8 +1291,8 @@
snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x40);
break;
case SND_SOC_DAPM_POST_PMU:
- pr_debug("%s: sleeping 16 ms after %s PA turn on\n",
- __func__, w->name);
+ dev_dbg(codec->dev, "%s: sleeping 16 ms after %s PA turn on\n",
+ __func__, w->name);
usleep_range(16000, 16100);
break;
case SND_SOC_DAPM_POST_PMD:
@@ -1294,7 +1305,7 @@
static int msm8x10_wcd_codec_enable_spk_pa(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
- pr_debug("%s %d %s\n", __func__, event, w->name);
+ dev_dbg(w->codec->dev, "%s %d %s\n", __func__, event, w->name);
return 0;
}
@@ -1311,7 +1322,8 @@
ret = kstrtouint(strpbrk(w->name, "12"), 10, &dmic);
if (ret < 0) {
- pr_err("%s: Invalid DMIC line on the codec\n", __func__);
+ dev_err(codec->dev,
+ "%s: Invalid DMIC line on the codec\n", __func__);
return -EINVAL;
}
@@ -1321,11 +1333,12 @@
dmic_clk_en = 0x01;
dmic_clk_cnt = &(msm8x10_wcd->dmic_1_2_clk_cnt);
dmic_clk_reg = MSM8X10_WCD_A_CDC_CLK_DMIC_B1_CTL;
- pr_debug("%s() event %d DMIC%d dmic_1_2_clk_cnt %d\n",
+ dev_dbg(codec->dev,
+ "%s() event %d DMIC%d dmic_1_2_clk_cnt %d\n",
__func__, event, dmic, *dmic_clk_cnt);
break;
default:
- pr_err("%s: Invalid DMIC Selection\n", __func__);
+ dev_err(codec->dev, "%s: Invalid DMIC Selection\n", __func__);
return -EINVAL;
}
@@ -1360,7 +1373,7 @@
char *internal3_text = "Internal3";
enum wcd9xxx_notify_event e_post_off, e_pre_on, e_post_on;
- pr_debug("%s %d\n", __func__, event);
+ dev_dbg(codec->dev, "%s %d\n", __func__, event);
switch (w->reg) {
case MSM8X10_WCD_A_MICB_1_CTL:
micb_int_reg = MSM8X10_WCD_A_MICB_1_INT_RBIAS;
@@ -1371,7 +1384,8 @@
e_post_off = WCD9XXX_EVENT_POST_MICBIAS_1_OFF;
break;
default:
- pr_err("%s: Error, invalid micbias register\n", __func__);
+ dev_err(codec->dev,
+ "%s: Error, invalid micbias register\n", __func__);
return -EINVAL;
}
@@ -1432,7 +1446,7 @@
u8 dec_hpf_cut_of_freq;
int offset;
- pr_debug("%s %d\n", __func__, event);
+ dev_dbg(codec->dev, "%s %d\n", __func__, event);
widget_name = kstrndup(w->name, 15, GFP_KERNEL);
if (!widget_name)
@@ -1442,26 +1456,29 @@
dec_name = strsep(&widget_name, " ");
widget_name = temp;
if (!dec_name) {
- pr_err("%s: Invalid decimator = %s\n", __func__, w->name);
+ dev_err(codec->dev,
+ "%s: Invalid decimator = %s\n", __func__, w->name);
ret = -EINVAL;
goto out;
}
ret = kstrtouint(strpbrk(dec_name, "12"), 10, &decimator);
if (ret < 0) {
- pr_err("%s: Invalid decimator = %s\n", __func__, dec_name);
+ dev_err(codec->dev,
+ "%s: Invalid decimator = %s\n", __func__, dec_name);
ret = -EINVAL;
goto out;
}
- pr_debug("%s(): widget = %s dec_name = %s decimator = %u\n", __func__,
- w->name, dec_name, decimator);
+ dev_dbg(codec->dev,
+ "%s(): widget = %s dec_name = %s decimator = %u\n", __func__,
+ w->name, dec_name, decimator);
if (w->reg == MSM8X10_WCD_A_CDC_CLK_TX_CLK_EN_B1_CTL) {
dec_reset_reg = MSM8X10_WCD_A_CDC_CLK_TX_RESET_B1_CTL;
offset = 0;
} else {
- pr_err("%s: Error, incorrect dec\n", __func__);
+ dev_err(codec->dev, "%s: Error, incorrect dec\n", __func__);
ret = -EINVAL;
goto out;
}
@@ -1531,11 +1548,12 @@
}
static int msm8x10_wcd_codec_enable_interpolator(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
+ struct snd_kcontrol *kcontrol,
+ int event)
{
struct snd_soc_codec *codec = w->codec;
- pr_debug("%s %d %s\n", __func__, event, w->name);
+ dev_dbg(codec->dev, "%s %d %s\n", __func__, event, w->name);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
@@ -1565,7 +1583,7 @@
struct snd_soc_codec *codec = w->codec;
struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
- pr_debug("%s %d\n", __func__, event);
+ dev_dbg(codec->dev, "%s %d\n", __func__, event);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
@@ -1583,7 +1601,7 @@
{
struct snd_soc_codec *codec = w->codec;
- pr_debug("%s %s %d\n", __func__, w->name, event);
+ dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
@@ -1603,7 +1621,7 @@
struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
enum wcd9xxx_notify_event e_pre_on, e_post_off;
- pr_debug("%s: %s event = %d\n", __func__, w->name, event);
+ dev_dbg(codec->dev, "%s: %s event = %d\n", __func__, w->name, event);
if (w->shift == 5) {
e_pre_on = WCD9XXX_EVENT_PRE_HPHR_PA_ON;
e_post_off = WCD9XXX_EVENT_POST_HPHR_PA_OFF;
@@ -1611,7 +1629,8 @@
e_pre_on = WCD9XXX_EVENT_PRE_HPHL_PA_ON;
e_post_off = WCD9XXX_EVENT_POST_HPHL_PA_OFF;
} else {
- pr_err("%s: Invalid w->shift %d\n", __func__, w->shift);
+ dev_err(codec->dev,
+ "%s: Invalid w->shift %d\n", __func__, w->shift);
return -EINVAL;
}
@@ -1635,8 +1654,9 @@
* would have been locked while snd_soc_jack_report also
* attempts to acquire same lock.
*/
- pr_debug("%s: sleep 10 ms after %s PA disable.\n", __func__,
- w->name);
+ dev_dbg(codec->dev,
+ "%s: sleep 10 ms after %s PA disable.\n", __func__,
+ w->name);
usleep_range(10000, 10100);
break;
}
@@ -1648,7 +1668,7 @@
{
struct snd_soc_codec *codec = w->codec;
- pr_debug("%s %s %d\n", __func__, w->name, event);
+ dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
@@ -1665,7 +1685,7 @@
static int msm8x10_wcd_spk_dac_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
- pr_debug("%s %s %d\n", __func__, w->name, event);
+ dev_dbg(w->codec->dev, "%s %s %d\n", __func__, w->name, event);
return 0;
}
@@ -1812,14 +1832,14 @@
{"MIC BIAS1 External", NULL, "LDO_H"},
};
-
static int msm8x10_wcd_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct msm8x10_wcd *msm8x10_wcd_core =
dev_get_drvdata(dai->codec->dev);
- pr_debug("%s(): substream = %s stream = %d\n" , __func__,
- substream->name, substream->stream);
+ dev_dbg(dai->codec->dev, "%s(): substream = %s stream = %d\n",
+ __func__,
+ substream->name, substream->stream);
if ((msm8x10_wcd_core != NULL) &&
(msm8x10_wcd_core->dev != NULL))
pm_runtime_get_sync(msm8x10_wcd_core->dev);
@@ -1832,8 +1852,9 @@
{
struct msm8x10_wcd *msm8x10_wcd_core =
dev_get_drvdata(dai->codec->dev);
- pr_debug("%s(): substream = %s stream = %d\n" , __func__,
- substream->name, substream->stream);
+ dev_dbg(dai->codec->dev,
+ "%s(): substream = %s stream = %d\n" , __func__,
+ substream->name, substream->stream);
if ((msm8x10_wcd_core != NULL) &&
(msm8x10_wcd_core->dev != NULL)) {
pm_runtime_mark_last_busy(msm8x10_wcd_core->dev);
@@ -1846,9 +1867,9 @@
{
struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
- pr_debug("%s: mclk_enable = %u, dapm = %d\n", __func__, mclk_enable,
- dapm);
-
+ dev_dbg(codec->dev,
+ "%s: mclk_enable = %u, dapm = %d\n", __func__,
+ mclk_enable, dapm);
WCD9XXX_BCL_LOCK(&msm8x10_wcd->resmgr);
if (mclk_enable) {
wcd9xxx_resmgr_get_bandgap(&msm8x10_wcd->resmgr,
@@ -1870,13 +1891,13 @@
static int msm8x10_wcd_set_dai_sysclk(struct snd_soc_dai *dai,
int clk_id, unsigned int freq, int dir)
{
- pr_debug("%s\n", __func__);
+ dev_dbg(dai->codec->dev, "%s\n", __func__);
return 0;
}
static int msm8x10_wcd_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
- pr_debug("%s\n", __func__);
+ dev_dbg(dai->codec->dev, "%s\n", __func__);
return 0;
}
@@ -1885,7 +1906,7 @@
unsigned int rx_num, unsigned int *rx_slot)
{
- pr_debug("%s\n", __func__);
+ dev_dbg(dai->codec->dev, "%s\n", __func__);
return 0;
}
@@ -1894,7 +1915,7 @@
unsigned int *rx_num, unsigned int *rx_slot)
{
- pr_debug("%s\n", __func__);
+ dev_dbg(dai->codec->dev, "%s\n", __func__);
return 0;
}
@@ -1917,7 +1938,8 @@
u8 tx_fs_rate, rx_fs_rate;
int ret;
- pr_debug("%s: dai_name = %s DAI-ID %x rate %d num_ch %d\n", __func__,
+ dev_dbg(dai->codec->dev,
+ "%s: dai_name = %s DAI-ID %x rate %d num_ch %d\n", __func__,
dai->name, dai->id, params_rate(params),
params_channels(params));
@@ -1947,7 +1969,8 @@
rx_fs_rate = 0xA0;
break;
default:
- pr_err("%s: Invalid sampling rate %d\n", __func__,
+ dev_err(dai->codec->dev,
+ "%s: Invalid sampling rate %d\n", __func__,
params_rate(params));
return -EINVAL;
}
@@ -1957,7 +1980,8 @@
ret = msm8x10_wcd_set_decimator_rate(dai, tx_fs_rate,
params_rate(params));
if (ret < 0) {
- pr_err("%s: set decimator rate failed %d\n", __func__,
+ dev_err(dai->codec->dev,
+ "%s: set decimator rate failed %d\n", __func__,
ret);
return ret;
}
@@ -1966,13 +1990,15 @@
ret = msm8x10_wcd_set_interpolator_rate(dai, rx_fs_rate,
params_rate(params));
if (ret < 0) {
- pr_err("%s: set decimator rate failed %d\n", __func__,
+ dev_err(dai->codec->dev,
+ "%s: set decimator rate failed %d\n", __func__,
ret);
return ret;
}
break;
default:
- pr_err("%s: Invalid stream type %d\n", __func__,
+ dev_err(dai->codec->dev,
+ "%s: Invalid stream type %d\n", __func__,
substream->stream);
return -EINVAL;
}
@@ -2026,13 +2052,15 @@
{
switch (event) {
case SND_SOC_DAPM_POST_PMU:
- pr_debug("%s: Sleeping 20ms after enabling EAR PA\n",
- __func__);
+ dev_dbg(w->codec->dev,
+ "%s: Sleeping 20ms after enabling EAR PA\n",
+ __func__);
msleep(20);
break;
case SND_SOC_DAPM_POST_PMD:
- pr_debug("%s: Sleeping 20ms after disabling EAR PA\n",
- __func__);
+ dev_dbg(w->codec->dev,
+ "%s: Sleeping 20ms after disabling EAR PA\n",
+ __func__);
msleep(20);
break;
}
@@ -2310,11 +2338,12 @@
static int msm8x10_wcd_codec_probe(struct snd_soc_codec *codec)
{
- msm8x10_wcd_codec_init_reg(codec);
+ dev_dbg(codec->dev, "%s()\n", __func__);
+ codec->control_data = dev_get_drvdata(codec->dev);
+ msm8x10_wcd_codec_init_reg(codec);
msm8x10_wcd_update_reg_defaults(codec);
- dev_dbg(codec->dev, "%s()\n", __func__);
return 0;
}
@@ -2324,6 +2353,18 @@
return 0;
}
+static int msm8x10_wcd_device_init(struct msm8x10_wcd *msm8x10)
+{
+
+ mutex_init(&msm8x10->io_lock);
+ mutex_init(&msm8x10->xfer_lock);
+ mutex_init(&msm8x10->pm_lock);
+ msm8x10->wlock_holders = 0;
+
+ return 0;
+}
+
+
static struct snd_soc_codec_driver soc_codec_dev_msm8x10_wcd = {
.probe = msm8x10_wcd_codec_probe,
.remove = msm8x10_wcd_codec_remove,
@@ -2349,8 +2390,21 @@
static int __devinit msm8x10_wcd_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
- int ret;
+ int ret = 0;
+ struct msm8x10_wcd *msm8x10 = NULL;
struct msm8x10_wcd_pdata *pdata;
+ static int device_id;
+ struct device *dev;
+
+ dev_dbg(&client->dev, "%s:slave addr = 0x%x device_id = %d\n",
+ __func__, client->addr, device_id);
+
+ if (device_id > 0) {
+ msm8x10_wcd_modules[device_id++].client = client;
+ return ret;
+ }
+
+ dev = &client->dev;
if (client->dev.of_node) {
dev_dbg(&client->dev, "%s:Platform data from device tree\n",
__func__);
@@ -2362,16 +2416,50 @@
pdata = client->dev.platform_data;
}
- ret = snd_soc_register_codec(&client->dev,
- &soc_codec_dev_msm8x10_wcd,
- msm8x10_wcd_i2s_dai, ARRAY_SIZE(msm8x10_wcd_i2s_dai));
- dev_dbg(&client->dev, "%s:ret = 0x%x\n", __func__, ret);
+ msm8x10 = kzalloc(sizeof(struct msm8x10_wcd), GFP_KERNEL);
+ if (msm8x10 == NULL) {
+ dev_err(&client->dev,
+ "%s: error, allocation failed\n", __func__);
+ ret = -ENOMEM;
+ goto fail;
+ }
+ msm8x10->dev = &client->dev;
+ msm8x10_wcd_modules[device_id++].client = client;
+ msm8x10->read_dev = msm8x10_wcd_reg_read;
+ msm8x10->write_dev = msm8x10_wcd_reg_write;
+ ret = msm8x10_wcd_device_init(msm8x10);
+ if (ret) {
+ dev_err(&client->dev,
+ "%s:msm8x10_wcd_device_init failed with error %d\n",
+ __func__, ret);
+ goto fail;
+ }
+ dev_set_drvdata(&client->dev, msm8x10);
+ ret = snd_soc_register_codec(&client->dev, &soc_codec_dev_msm8x10_wcd,
+ msm8x10_wcd_i2s_dai,
+ ARRAY_SIZE(msm8x10_wcd_i2s_dai));
+ if (ret)
+ dev_err(&client->dev,
+ "%s:snd_soc_register_codec failed with error %d\n",
+ __func__, ret);
+fail:
return ret;
}
+static void msm8x10_wcd_device_exit(struct msm8x10_wcd *msm8x10)
+{
+ mutex_destroy(&msm8x10->pm_lock);
+ mutex_destroy(&msm8x10->io_lock);
+ mutex_destroy(&msm8x10->xfer_lock);
+ kfree(msm8x10);
+}
+
static int __devexit msm8x10_wcd_i2c_remove(struct i2c_client *client)
{
+ struct msm8x10_wcd *msm8x10 = dev_get_drvdata(&client->dev);
+
+ msm8x10_wcd_device_exit(msm8x10);
return 0;
}
@@ -2407,8 +2495,8 @@
pr_debug("%s:\n", __func__);
ret = i2c_add_driver(&msm8x10_wcd_i2c_driver);
if (ret != 0)
- pr_err("%s: Failed to add msm8x10 wcd I2C driver - error code %d\n",
- __func__, ret);
+ pr_err("%s: Failed to add msm8x10 wcd I2C driver - error %d\n",
+ __func__, ret);
return ret;
}
diff --git a/sound/soc/codecs/msm8x10-wcd.h b/sound/soc/codecs/msm8x10-wcd.h
index 365d526..44e8a6d 100644
--- a/sound/soc/codecs/msm8x10-wcd.h
+++ b/sound/soc/codecs/msm8x10-wcd.h
@@ -196,6 +196,10 @@
u8 version;
int reset_gpio;
+ int (*read_dev)(struct msm8x10_wcd *msm8x10,
+ unsigned short reg, unsigned int *val);
+ int (*write_dev)(struct msm8x10_wcd *msm8x10,
+ unsigned short reg, unsigned int val);
u32 num_of_supplies;
struct regulator_bulk_data *supplies;
diff --git a/sound/soc/msm/mdm9625.c b/sound/soc/msm/mdm9625.c
index 8eac69e..eb7366c 100644
--- a/sound/soc/msm/mdm9625.c
+++ b/sound/soc/msm/mdm9625.c
@@ -27,6 +27,7 @@
#include <mach/socinfo.h>
#include <qdsp6v2/msm-pcm-routing-v2.h>
#include "../codecs/wcd9320.h"
+#include <linux/io.h>
/* Spk control */
#define MDM9625_SPK_ON 1
@@ -38,9 +39,16 @@
#define MDM_MCLK_CLK_12P288MHZ 12288000
#define MDM_MCLK_CLK_9P6HZ 9600000
#define MDM_IBIT_CLK_DIV_1P56MHZ 7
-#define MDM_MI2S_PRIM_INTF 0
-#define MDM_MI2S_SEC_INTF 1
+#define MDM_MI2S_AUXPCM_PRIM_INTF 0
+#define MDM_MI2S_AUXPCM_SEC_INTF 1
+#define LPAIF_OFFSET 0xFE000000
+#define LPAIF_PRI_MODE_MUXSEL (LPAIF_OFFSET + 0x2B000)
+#define LPAIF_SEC_MODE_MUXSEL (LPAIF_OFFSET + 0x2C000)
+
+#define I2S_SEL 0
+#define I2S_PCM_SEL 1
+#define I2S_PCM_SEL_OFFSET 1
/* Machine driver Name*/
#define MDM9625_MACHINE_DRV_NAME "mdm9625-asoc-taiko"
@@ -77,6 +85,8 @@
#define GPIO_NAME_INDEX 0
#define DT_PARSE_INDEX 1
+static int mdm9625_auxpcm_rate = 8000;
+void *lpaif_pri_muxsel_virt_addr;
static char *mdm_i2s_gpio_name[][2] = {
{"PRIM_MI2S_WS", "prim-i2s-gpio-ws"},
@@ -93,6 +103,7 @@
static int mdm9625_mi2s_rx_ch = 1;
static int mdm9625_mi2s_tx_ch = 1;
static int msm_spk_control;
+static atomic_t aux_ref_count;
static atomic_t mi2s_ref_count;
static int mdm9625_enable_codec_ext_clk(struct snd_soc_codec *codec,
@@ -117,7 +128,8 @@
#define WCD9XXX_MBHC_DEF_BUTTONS 8
#define WCD9XXX_MBHC_DEF_RLOADS 5
-static int mdm9625_set_mi2s_gpio(struct snd_pcm_substream *substream, u32 intf)
+static int mdm9625_set_gpio(struct snd_pcm_substream *substream,
+ u32 intf)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_card *card = rtd->card;
@@ -134,8 +146,9 @@
goto err;
}
- if (intf == MDM_MI2S_PRIM_INTF)
+ if (intf == MDM_MI2S_AUXPCM_PRIM_INTF) {
i2s_ctrl = pdata->pri_ctrl;
+ }
else {
pr_err("%s: Wrong I2S Interface\n", __func__);
rtn = -EINVAL;
@@ -186,8 +199,9 @@
rtn = -EINVAL;
goto err;
}
- if (intf == MDM_MI2S_PRIM_INTF)
+ if (intf == MDM_MI2S_AUXPCM_PRIM_INTF) {
i2s_ctrl = pdata->pri_ctrl;
+ }
else {
pr_debug("%s: Wrong Interface\n", __func__);
rtn = -EINVAL;
@@ -264,7 +278,7 @@
struct snd_soc_pcm_runtime *rtd = substream->private_data;
int ret;
if (atomic_dec_return(&mi2s_ref_count) == 0) {
- mdm9625_mi2s_free_gpios(substream, MDM_MI2S_PRIM_INTF);
+ mdm9625_mi2s_free_gpios(substream, MDM_MI2S_AUXPCM_PRIM_INTF);
ret = mdm9625_mi2s_clk_ctl(rtd, false);
if (ret < 0)
pr_err("%s:clock disable failed\n", __func__);
@@ -279,7 +293,17 @@
int ret = 0;
if (atomic_inc_return(&mi2s_ref_count) == 1) {
- mdm9625_set_mi2s_gpio(substream, MDM_MI2S_PRIM_INTF);
+ if (lpaif_pri_muxsel_virt_addr != NULL)
+ iowrite32(I2S_SEL << I2S_PCM_SEL_OFFSET,
+ lpaif_pri_muxsel_virt_addr);
+ else
+ pr_err("%s lpaif_pri_muxsel_virt_addr is NULL\n",
+ __func__);
+ ret = mdm9625_set_gpio(substream, MDM_MI2S_AUXPCM_PRIM_INTF);
+ if (ret < 0) {
+ pr_err("%s, GPIO setup failed\n", __func__);
+ return ret;
+ }
ret = mdm9625_mi2s_clk_ctl(rtd, true);
if (ret < 0) {
pr_err("set format for codec dai failed\n");
@@ -470,6 +494,83 @@
return 0;
}
+static int mdm9625_auxpcm_startup(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ int ret = 0;
+
+ if (atomic_inc_return(&aux_ref_count) == 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 = mdm9625_set_gpio(substream, MDM_MI2S_AUXPCM_PRIM_INTF);
+ if (ret < 0) {
+ pr_err("%s, GPIO setup failed\n", __func__);
+ return ret;
+ }
+ ret = mdm9625_mi2s_clk_ctl(rtd, true);
+ if (ret < 0) {
+ pr_err("set format for codec dai failed\n");
+ return ret;
+ }
+ }
+ return ret;
+}
+
+static void mdm9625_auxpcm_snd_shutdown(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ int ret;
+
+ if (atomic_dec_return(&aux_ref_count) == 0) {
+ mdm9625_mi2s_free_gpios(substream, MDM_MI2S_AUXPCM_PRIM_INTF);
+ ret = mdm9625_mi2s_clk_ctl(rtd, false);
+ if (ret < 0)
+ pr_err("%s:clock disable failed\n", __func__);
+ }
+}
+
+static int mdm9625_auxpcm_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = mdm9625_auxpcm_rate;
+ return 0;
+}
+
+static int mdm9625_auxpcm_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ switch (ucontrol->value.integer.value[0]) {
+ case 0:
+ mdm9625_auxpcm_rate = 8000;
+ break;
+ case 1:
+ mdm9625_auxpcm_rate = 16000;
+ break;
+ default:
+ mdm9625_auxpcm_rate = 8000;
+ break;
+ }
+ return 0;
+}
+
+static int mdm9625_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 = mdm9625_auxpcm_rate;
+ channels->min = channels->max = 1;
+
+ return 0;
+}
static const struct snd_soc_dapm_widget mdm9625_dapm_widgets[] = {
@@ -494,23 +595,28 @@
static const char *const spk_function[] = {"Off", "On"};
static const char *const mi2s_rx_ch_text[] = {"One", "Two"};
static const char *const mi2s_tx_ch_text[] = {"One", "Two"};
+static const char *const auxpcm_rate_text[] = {"rate_8000", "rate_16000"};
static const struct soc_enum mdm9625_enum[] = {
SOC_ENUM_SINGLE_EXT(2, spk_function),
SOC_ENUM_SINGLE_EXT(2, mi2s_rx_ch_text),
SOC_ENUM_SINGLE_EXT(2, mi2s_tx_ch_text),
+ SOC_ENUM_SINGLE_EXT(2, auxpcm_rate_text),
};
static const struct snd_kcontrol_new mdm_snd_controls[] = {
- SOC_ENUM_EXT("Speaker Function", mdm9625_enum[0],
+ SOC_ENUM_EXT("Speaker Function", mdm9625_enum[0],
mdm9625_mi2s_get_spk,
mdm9625_mi2s_set_spk),
- SOC_ENUM_EXT("MI2S_RX Channels", mdm9625_enum[1],
+ SOC_ENUM_EXT("MI2S_RX Channels", mdm9625_enum[1],
mdm9625_mi2s_rx_ch_get,
mdm9625_mi2s_rx_ch_put),
- SOC_ENUM_EXT("MI2S_TX Channels", mdm9625_enum[2],
+ SOC_ENUM_EXT("MI2S_TX Channels", mdm9625_enum[2],
mdm9625_mi2s_tx_ch_get,
mdm9625_mi2s_tx_ch_put),
+ SOC_ENUM_EXT("AUX PCM SampleRate", mdm9625_enum[3],
+ mdm9625_auxpcm_rate_get,
+ mdm9625_auxpcm_rate_put),
};
static int mdm9625_mi2s_audrx_init(struct snd_soc_pcm_runtime *rtd)
@@ -631,6 +737,11 @@
.shutdown = mdm9625_mi2s_snd_shutdown,
};
+static struct snd_soc_ops mdm9625_auxpcm_be_ops = {
+ .startup = mdm9625_auxpcm_startup,
+ .shutdown = mdm9625_auxpcm_snd_shutdown,
+};
+
/* Digital audio interface connects codec <---> CPU */
static struct snd_soc_dai_link mdm9625_dai[] = {
/* FrontEnd DAI Links */
@@ -799,6 +910,32 @@
.no_pcm = 1,
.be_id = MSM_BACKEND_DAI_AFE_PCM_TX,
},
+ {
+ .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 = mdm9625_auxpcm_be_params_fixup,
+ .ops = &mdm9625_auxpcm_be_ops,
+ .ignore_pmdown_time = 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 = mdm9625_auxpcm_be_params_fixup,
+ .ops = &mdm9625_auxpcm_be_ops,
+ },
};
static struct snd_soc_card snd_soc_card_mdm9625 = {
@@ -807,7 +944,7 @@
.num_links = ARRAY_SIZE(mdm9625_dai),
};
-static int mdm9625_dtparse_mi2s(struct platform_device *pdev,
+static int mdm9625_dtparse(struct platform_device *pdev,
struct mdm9625_machine_data **pdata)
{
int ret = 0, i = 0;
@@ -920,10 +1057,10 @@
ret = -ENOMEM;
goto err;
}
- ret = mdm9625_dtparse_mi2s(pdev, &pdata);
+ ret = mdm9625_dtparse(pdev, &pdata);
if (ret) {
dev_err(&pdev->dev,
- "%s: mi2s Pin data parse failed",
+ "%s: mi2s-aux Pin data parse failed",
__func__);
goto err;
}
@@ -960,6 +1097,14 @@
ret);
goto err;
}
+
+ lpaif_pri_muxsel_virt_addr = ioremap(LPAIF_PRI_MODE_MUXSEL, 4);
+ 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:
devm_kfree(&pdev->dev, pdata);
diff --git a/sound/soc/msm/msm-pcm-host-voice.c b/sound/soc/msm/msm-pcm-host-voice.c
index 7cb309e3..36826cc 100644
--- a/sound/soc/msm/msm-pcm-host-voice.c
+++ b/sound/soc/msm/msm-pcm-host-voice.c
@@ -28,7 +28,7 @@
#include "qdsp6/q6voice.h"
-#define HPCM_MAX_Q_LEN 2
+#define HPCM_MAX_Q_LEN 10
#define HPCM_MIN_VOC_PKT_SIZE 320
#define HPCM_MAX_VOC_PKT_SIZE 640
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index 91e5e67..c5cfa11 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -27,7 +27,7 @@
#include <asm/mach-types.h>
#include <mach/socinfo.h>
#include <sound/pcm_params.h>
-#include <qdsp6v2/msm-pcm-routing-v2.h>
+#include "qdsp6v2/msm-pcm-routing-v2.h"
#include "../codecs/wcd9320.h"
#include <linux/io.h>
diff --git a/sound/soc/msm/msm8x10.c b/sound/soc/msm/msm8x10.c
index 981a9a7..4dd85fc 100644
--- a/sound/soc/msm/msm8x10.c
+++ b/sound/soc/msm/msm8x10.c
@@ -114,8 +114,8 @@
.stream_name = "Primary MI2S Playback",
.cpu_dai_name = "msm-dai-q6-mi2s.0",
.platform_name = "msm-pcm-routing",
- .codec_name = "msm-stub-codec.1",
- .codec_dai_name = "msm-stub-tx",
+ .codec_name = "msm8x10-wcd-i2c-core.1-000d",
+ .codec_dai_name = "msm8x10_wcd_i2s_rx1",
.no_pcm = 1,
.be_id = MSM_BACKEND_DAI_MI2S_RX,
.init = &msm_audrx_init,
@@ -127,8 +127,8 @@
.stream_name = "Secondary MI2S Capture",
.cpu_dai_name = "msm-dai-q6-mi2s.1",
.platform_name = "msm-pcm-routing",
- .codec_name = "msm-stub-codec.1",
- .codec_dai_name = "msm-stub-tx",
+ .codec_name = "msm8x10-wcd-i2c-core.1-000d",
+ .codec_dai_name = "msm8x10_wcd_i2s_tx1",
.no_pcm = 1,
.be_id = MSM_BACKEND_DAI_SECONDARY_MI2S_TX,
.be_hw_params_fixup = msm_be_hw_params_fixup,
diff --git a/sound/soc/msm/qdsp6/q6asm.c b/sound/soc/msm/qdsp6/q6asm.c
index 35c215c..a55700c 100644
--- a/sound/soc/msm/qdsp6/q6asm.c
+++ b/sound/soc/msm/qdsp6/q6asm.c
@@ -2205,6 +2205,39 @@
return -EINVAL;
}
+int q6asm_cfg_aac_sel_mix_coef(struct audio_client *ac, uint32_t mix_coeff)
+{
+ struct asm_aac_stereo_mix_coeff_selection_param aac_mix_coeff;
+ int rc = 0;
+ q6asm_add_hdr(ac, &aac_mix_coeff.hdr, sizeof(aac_mix_coeff), TRUE);
+ aac_mix_coeff.hdr.opcode =
+ ASM_STREAM_CMD_SET_ENCDEC_PARAM;
+ aac_mix_coeff.param_id =
+ ASM_PARAM_ID_AAC_STEREO_MIX_COEFF_SELECTION_FLAG;
+ aac_mix_coeff.param_size =
+ sizeof(struct asm_aac_stereo_mix_coeff_selection_param);
+ aac_mix_coeff.aac_stereo_mix_coeff_flag = mix_coeff;
+ pr_debug("%s, mix_coeff = %u", __func__, mix_coeff);
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &aac_mix_coeff);
+ if (rc < 0) {
+ pr_err("%s:Command opcode[0x%x]paramid[0x%x] failed\n",
+ __func__, ASM_STREAM_CMD_SET_ENCDEC_PARAM,
+ ASM_PARAM_ID_AAC_STEREO_MIX_COEFF_SELECTION_FLAG);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s:timeout opcode[0x%x]\n", __func__,
+ aac_mix_coeff.hdr.opcode);
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return -EINVAL;
+}
+
int q6asm_set_encdec_chan_map(struct audio_client *ac,
uint32_t num_channels)
{
diff --git a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
index 33b72e8..b3107a4 100644
--- a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
@@ -121,6 +121,7 @@
int i = 0;
int time_stamp_flag = 0;
int buffer_length = 0;
+ int stop_playback = 0;
pr_debug("%s opcode =%08x\n", __func__, opcode);
switch (opcode) {
@@ -141,6 +142,23 @@
break;
} else
atomic_set(&prtd->pending_buffer, 0);
+
+ /*
+ * check for underrun
+ */
+ snd_pcm_stream_lock_irq(substream);
+ if (snd_pcm_playback_empty(substream)) {
+ atomic_set(&prtd->pending_buffer, 1);
+ runtime->render_flag |= SNDRV_RENDER_STOPPED;
+ stop_playback = 1;
+ }
+ snd_pcm_stream_unlock_irq(substream);
+
+ if (stop_playback) {
+ pr_err("%s empty buffer, stop writes\n", __func__);
+ break;
+ }
+
buf = prtd->audio_client->port[IN].buf;
pr_debug("%s:writing %d bytes of buffer[%d] to dsp 2\n",
__func__, prtd->pcm_count, prtd->out_head);
@@ -519,6 +537,7 @@
}
prtd = &compr->prtd;
prtd->substream = substream;
+ runtime->render_flag = SNDRV_DMA_MODE;
prtd->audio_client = q6asm_audio_client_alloc(
(app_cb)compr_event_handler, compr);
if (!prtd->audio_client) {
@@ -674,6 +693,7 @@
pr_debug("%s\n", __func__);
prtd->mmap_flag = 1;
+ runtime->render_flag = SNDRV_NON_DMA_MODE;
if (runtime->dma_addr && runtime->dma_bytes) {
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
result = remap_pfn_range(vma, vma->vm_start,
@@ -800,6 +820,9 @@
}
runtime->hw.buffer_bytes_max =
runtime->hw.period_bytes_min * runtime->hw.periods_max;
+ pr_debug("allocate %d buffers each of size %d\n",
+ runtime->hw.period_bytes_min,
+ runtime->hw.periods_max);
ret = q6asm_audio_client_buf_alloc_contiguous(dir,
prtd->audio_client,
runtime->hw.period_bytes_min,
@@ -957,6 +980,70 @@
return snd_pcm_lib_ioctl(substream, cmd, arg);
}
+static int msm_compr_restart(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct compr_audio *compr = runtime->private_data;
+ struct msm_audio *prtd = &compr->prtd;
+ struct audio_aio_write_param param;
+ struct audio_buffer *buf = NULL;
+ struct output_meta_data_st output_meta_data;
+ int time_stamp_flag = 0;
+ int buffer_length = 0;
+
+ pr_debug("%s, trigger restart\n", __func__);
+
+ if (runtime->render_flag & SNDRV_RENDER_STOPPED) {
+ buf = prtd->audio_client->port[IN].buf;
+ pr_debug("%s:writing %d bytes of buffer[%d] to dsp 2\n",
+ __func__, prtd->pcm_count, prtd->out_head);
+ pr_debug("%s:writing buffer[%d] from 0x%08x\n",
+ __func__, prtd->out_head,
+ ((unsigned int)buf[0].phys
+ + (prtd->out_head * prtd->pcm_count)));
+
+ if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE)
+ time_stamp_flag = SET_TIMESTAMP;
+ else
+ time_stamp_flag = NO_TIMESTAMP;
+ memcpy(&output_meta_data, (char *)(buf->data +
+ prtd->out_head * prtd->pcm_count),
+ COMPRE_OUTPUT_METADATA_SIZE);
+
+ buffer_length = output_meta_data.frame_size;
+ pr_debug("meta_data_length: %d, frame_length: %d\n",
+ output_meta_data.meta_data_length,
+ output_meta_data.frame_size);
+ pr_debug("timestamp_msw: %d, timestamp_lsw: %d\n",
+ output_meta_data.timestamp_msw,
+ output_meta_data.timestamp_lsw);
+
+ param.paddr = (unsigned long)buf[0].phys
+ + (prtd->out_head * prtd->pcm_count)
+ + output_meta_data.meta_data_length;
+ param.len = buffer_length;
+ param.msw_ts = output_meta_data.timestamp_msw;
+ param.lsw_ts = output_meta_data.timestamp_lsw;
+ param.flags = time_stamp_flag;
+ param.uid = (unsigned long)buf[0].phys
+ + (prtd->out_head * prtd->pcm_count
+ + output_meta_data.meta_data_length);
+ if (q6asm_async_write(prtd->audio_client,
+ ¶m) < 0)
+ pr_err("%s:q6asm_async_write failed\n",
+ __func__);
+ else
+ prtd->out_head =
+ (prtd->out_head + 1) & (runtime->periods - 1);
+
+ runtime->render_flag &= ~SNDRV_RENDER_STOPPED;
+ atomic_set(&prtd->pending_buffer, 0);
+ return 0;
+ }
+ return 0;
+}
+
+
static struct snd_pcm_ops msm_compr_ops = {
.open = msm_compr_open,
.hw_params = msm_compr_hw_params,
@@ -966,6 +1053,7 @@
.trigger = msm_compr_trigger,
.pointer = msm_compr_pointer,
.mmap = msm_compr_mmap,
+ .restart = msm_compr_restart,
};
static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c
index 74a3af9..91bb09b 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c
@@ -333,8 +333,8 @@
prtd->audio_client = q6afe_audio_client_alloc(prtd);
if (!prtd->audio_client) {
pr_debug("%s: Could not allocate memory\n", __func__);
- kfree(prtd);
mutex_unlock(&prtd->lock);
+ kfree(prtd);
return -ENOMEM;
}
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index 87990a9..5be62cc 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -2091,6 +2091,13 @@
return -EINVAL;
}
+/* Support for selecting stereo mixing coefficients for B family not done */
+int q6asm_cfg_aac_sel_mix_coef(struct audio_client *ac, uint32_t mix_coeff)
+{
+ /* To Be Done */
+ return 0;
+}
+
int q6asm_enc_cfg_blk_qcelp(struct audio_client *ac, uint32_t frames_per_buf,
uint16_t min_rate, uint16_t max_rate,
uint16_t reduced_rate_level, uint16_t rate_modulation_cmd)
diff --git a/sound/soc/msm/qdsp6v2/q6voice.c b/sound/soc/msm/qdsp6v2/q6voice.c
index 6a65880..12e83b0 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.c
+++ b/sound/soc/msm/qdsp6v2/q6voice.c
@@ -2765,13 +2765,14 @@
uint64_t *enc_buf;
void *apr_cvs;
u16 cvs_handle;
- dec_buf = (uint64_t *)v->shmem_info.sh_buf.buf[0].phys;
- enc_buf = (uint64_t *)v->shmem_info.sh_buf.buf[1].phys;
if (v == NULL) {
pr_err("%s: v is NULL\n", __func__);
return -EINVAL;
}
+ dec_buf = (uint64_t *)v->shmem_info.sh_buf.buf[0].phys;
+ enc_buf = (uint64_t *)v->shmem_info.sh_buf.buf[1].phys;
+
apr_cvs = common.apr_q6_cvs;
if (!apr_cvs) {
@@ -4618,6 +4619,10 @@
struct voice_data *v = voice_get_session(
common.voice[VOC_PATH_FULL].session_id);
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
v->shmem_info.sh_buf.client = msm_ion_client_create(UINT_MAX,
"voip_client");
if (IS_ERR_OR_NULL((void *)v->shmem_info.sh_buf.client)) {
@@ -4686,6 +4691,10 @@
struct voice_data *v = voice_get_session(
common.voice[VOC_PATH_FULL].session_id);
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
v->shmem_info.memtbl.client = msm_ion_client_create(UINT_MAX,
"voip_client");
if (IS_ERR_OR_NULL((void *)v->shmem_info.memtbl.client)) {