Merge "input: gpio-keys: Accept device name from device node"
diff --git a/Documentation/devicetree/bindings/arm/msm/dcvs-core-info.txt b/Documentation/devicetree/bindings/arm/msm/dcvs-core-info.txt
index 5b4d3cf..b7dd427 100644
--- a/Documentation/devicetree/bindings/arm/msm/dcvs-core-info.txt
+++ b/Documentation/devicetree/bindings/arm/msm/dcvs-core-info.txt
@@ -7,10 +7,14 @@
- qcom,core-core-type: indicates whether this core is a CPU(0) or a GPU(1)
+- qcom,num-cores: The number of cores this entry represents
+- qcom,sensors: The vector of sensor ids for the cores
+
- qcom,algo-disable-pc-threshold: sets highest frequency at which DCVS
will allow the CPU to power collapse.
- qcom,algo-em-win-size-min-us: sets minimum Energy Minimization(EM)
window size.
+
- qcom,algo-em-win-size-max-us: sets maximum EM window size.
- qcom,algo-em-max-util-pct: sets maximum CPU utilization that will
not be exceeded by any core when
@@ -67,7 +71,7 @@
compatible = "qcom,dcvs-core-info";
- qcom,num_cores = <1>;
+ qcom,num-cores = <1>;
qcom,sensors = <0>;
qcom,core-core-type = <1>;
diff --git a/Documentation/devicetree/bindings/arm/msm/lpm-resources.txt b/Documentation/devicetree/bindings/arm/msm/lpm-resources.txt
index b16d40f..7f2a21b 100644
--- a/Documentation/devicetree/bindings/arm/msm/lpm-resources.txt
+++ b/Documentation/devicetree/bindings/arm/msm/lpm-resources.txt
@@ -8,13 +8,25 @@
that need to be monitored for usage requirement to check if a given low power
state can be entered.Each resource is identified by a combination of the name,
id,type and key which is also used by the RPM to identify a shared resource.
+The name and resource-type are required nodes; the type, id and key are
+optional nodes which are needed if the resource type is RPM shared resource
+(MSM_LPM_RPM_RS_TYPE).
-The required nodes for lpm-resources are:
+The nodes for lpm-resources are:
+
+Required Nodes:
- compatible: "qcom,lpm-resources"
- reg: The numeric level id
- qcom,name: The name of the low power resource represented
as a string.
+- qcom,resource-type: The type of the LPM resource.
+ MSM_LPM_RPM_RS_TYPE = 0
+ MSM_LPM_LOCAL_RS_TYPE = 1
+
+
+Optional Nodes:
+
- qcom,type: The type of resource used like smps or pxo
represented as a hex value.
- qcom,id: The id representing a device within a resource type.
@@ -25,6 +37,7 @@
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" */
diff --git a/Documentation/devicetree/bindings/gpu/adreno.txt b/Documentation/devicetree/bindings/gpu/adreno.txt
index 16925fb..38b2721 100644
--- a/Documentation/devicetree/bindings/gpu/adreno.txt
+++ b/Documentation/devicetree/bindings/gpu/adreno.txt
@@ -62,6 +62,7 @@
- qcom,chipid: If it exists this property is used to replace
the chip identification read from the GPU hardware.
This is used to override faulty hardware readings.
+- qcom,strtstp-sleepwake: Boolean. Enables use of GPU SLUMBER instead of SLEEP for power savings
Example of A330 GPU in MSM8974:
diff --git a/Documentation/devicetree/bindings/iommu/msm_iommu.txt b/Documentation/devicetree/bindings/iommu/msm_iommu.txt
index 7a90cc0..dcf023d 100644
--- a/Documentation/devicetree/bindings/iommu/msm_iommu.txt
+++ b/Documentation/devicetree/bindings/iommu/msm_iommu.txt
@@ -13,7 +13,6 @@
- qcom,iommu-ctx-sids : List of stream identifiers associated with this
translation context.
- label : Name of the context bank
- - qcom,iommu-smt-size : Number of SMR entries in the SMT of this HW block
- vdd-supply : vdd-supply: phandle to GDSC regulator controlling this IOMMU.
Optional properties:
diff --git a/Documentation/devicetree/bindings/platform/msm/qpnp-power-on.txt b/Documentation/devicetree/bindings/platform/msm/qpnp-power-on.txt
index 21d376a..adb93b8 100644
--- a/Documentation/devicetree/bindings/platform/msm/qpnp-power-on.txt
+++ b/Documentation/devicetree/bindings/platform/msm/qpnp-power-on.txt
@@ -11,18 +11,24 @@
- compatible: Must be "qcom,qpnp-power-on"
- reg: Specifies the SPMI address and size for this PON (power-on) peripheral
- interrupts: Specifies the interrupt associated with PON.
+- interrupt-names: Specify the interrupt names associated with interrupts. Must be
+ one of "kpdpwr", "kpdpwr-bark", "resin", "resin-bark", "cblpwr".
+ Bark interrupts are associated with system reset configuration
+ to allow default reset configuration to be activated. If system
+ reset configuration is not supported then bark interrupts are
+ nops.
Optional properties:
-- qcom,pon-dbc-delay The debouce delay for the power-key interrupt
- specifed in us. The value ranges from 2 seconds
+- qcom,pon-dbc-delay The debounce delay for the power-key interrupt
+ specified in us. The value ranges from 2 seconds
to 1/64 of a second. Possible values are -
- 2, 1, 1/2, 1/4, 1/8, 1/16, 1/32, 1/64
- Intermediate value is rounded down to the
nearest valid value.
- qcom,pon_1 ...pon_n These represent the child nodes which describe
the properties (reset, key) for each of the pon
- reset source. All the child nodes are optional,
- if none of them are specified the driver fails
+ reset source. All the child nodes are optional.
+ If none of them is specified, the driver fails
to register.
- qcom,system-reset Specifies that this PON peripheral can be used
to reset the system. This property can only be
@@ -32,32 +38,32 @@
All the below properties are in the sub-node section (properties of the child
node).
+Sub-node required properties:
+- qcom,pon-type The type of PON/RESET source. The driver
+ currently supports KPDPWR(0), RESIN(1) and
+ CBLPWR(2) pon/reset sources.
+
+Sub-node optional properties:
- qcom,pull-up The initial state of the reset pin under
consideration.
0 = No pull-up
1 = pull-up enabled
- This property is optional and is set to '0'
- if not specified.
-- qcom,pon-type The type of PON/RESET source. The driver
- currently supports KPDPWR(0) and RESIN(1)
- pon/reset sources. This property must be
- specified.
+ This property is set to '0' if not specified.
- qcom,support-reset Indicates if this PON source supports
reset functionality.
0 = Not supported
1 = Supported
- This property is optional and is set to '0'
- if not specified.
-- qcom,s1-timer The debouce timer for the BARK interrupt for
+ This property is set to '0' if not specified.
+- qcom,s1-timer The debounce timer for the BARK interrupt for
that reset source. Value is specified in ms.
Supported values are -
- 0, 32, 56, 80, 128, 184, 272, 408, 608, 904
1352, 2048, 3072, 4480, 6720, 10256
This property must be specified only if
'support-reset' is set to 1.
-- qcom,s2-timer The debouce timer for the S2 reset specified
+- qcom,s2-timer The debounce timer for the S2 reset specified
in ms. On the expiry of this timer, the PMIC
- executes the reset sequence. Supoprted values -
+ executes the reset sequence. Supported values -
- 0, 10, 50, 100, 250, 500, 1000, 2000
This property is required only if
'support-reset' is set to 1.
@@ -68,7 +74,7 @@
'support-reset' is set to 1.
- linux,code The input key-code associated with the reset source.
The reset source in its default configuration can be
- used to support standard keys. This property is optional.
+ used to support standard keys.
Example:
qcom,power-on@800 {
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
index 2864fd1..3c8cb1b 100644
--- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -123,16 +123,18 @@
- compatible : "qcom,msm-ocmem-audio"
- - qcom,msm-ocmem-audio-src-id: Master port id
+ - qcom,msm_bus,name: Client name
- - qcom,msm-ocmem-audio-dst-id: Slave port id
+ - qcom,msm_bus,num_cases: Total number of use cases
- - qcom,msm-ocmem-audio-ab: arbitrated bandwidth
- in Bytes/s
+ - qcom,msm_bus,active_only: Context flag for requests in active or
+ dual (active & sleep) contex
- - qcom,msm-ocmem-audio-ib: instantaneous bandwidth
- in Bytes/s
+ - qcom,msm_bus,num_paths: Total number of master-slave pairs
+ - qcom,msm_bus,vectors: Arrays of unsigned integers representing:
+ master-id, slave-id, arbitrated bandwidth,
+ instantaneous bandwidth
Example:
qcom,msm-pcm {
@@ -234,10 +236,13 @@
qcom,msm-ocmem-audio {
compatible = "qcom,msm-ocmem-audio";
- qcom,msm-ocmem-audio-src-id = <11>;
- qcom,msm-ocmem-audio-dst-id = <604>;
- qcom,msm-ocmem-audio-ab = <209715200>;
- qcom,msm-ocmem-audio-ib = <471859200>;
+ qcom,msm_bus,name = "audio-ocmem";
+ qcom,msm_bus,num_cases = <2>;
+ qcom,msm_bus,active_only = <0>;
+ qcom,msm_bus,num_paths = <1>;
+ qcom,msm_bus,vectors =
+ <11 604 0 0>,
+ <11 604 32505856 325058560>;
};
* MSM8974 ASoC Machine driver
diff --git a/Documentation/mmc/mmc-dev-attrs.txt b/Documentation/mmc/mmc-dev-attrs.txt
index 22ae844..08f7312 100644
--- a/Documentation/mmc/mmc-dev-attrs.txt
+++ b/Documentation/mmc/mmc-dev-attrs.txt
@@ -8,6 +8,23 @@
force_ro Enforce read-only access even if write protect switch is off.
+ num_wr_reqs_to_start_packing This attribute is used to determine
+ the trigger for activating the write packing, in case the write
+ packing control feature is enabled.
+
+ When the MMC manages to reach a point where num_wr_reqs_to_start_packing
+ write requests could be packed, it enables the write packing feature.
+ This allows us to start the write packing only when it is beneficial
+ and has minimum affect on the read latency.
+
+ The number of potential packed requests that will trigger the packing
+ can be configured via sysfs by writing the required value to:
+ /sys/block/<block_dev_name>/num_wr_reqs_to_start_packing.
+
+ The default value of num_wr_reqs_to_start_packing was determined by
+ running parallel lmdd write and lmdd read operations and calculating
+ the max number of packed writes requests.
+
SD and MMC Device Attributes
============================
diff --git a/arch/arm/boot/dts/msm-iommu.dtsi b/arch/arm/boot/dts/msm-iommu.dtsi
index e907de8..709f40a 100755
--- a/arch/arm/boot/dts/msm-iommu.dtsi
+++ b/arch/arm/boot/dts/msm-iommu.dtsi
@@ -18,7 +18,6 @@
ranges;
reg = <0xfda64000 0x10000>;
vdd-supply = <&gdsc_jpeg>;
- qcom,iommu-smt-size = <16>;
status = "disabled";
qcom,iommu-ctx@fda6c000 {
@@ -50,7 +49,6 @@
ranges;
reg = <0xfd928000 0x10000>;
vdd-supply = <&gdsc_mdss>;
- qcom,iommu-smt-size = <16>;
status = "disabled";
qcom,iommu-ctx@fd930000 {
@@ -75,7 +73,6 @@
ranges;
reg = <0xfdc84000 0x10000>;
vdd-supply = <&gdsc_venus>;
- qcom,iommu-smt-size = <16>;
qcom,needs-alt-core-clk;
status = "disabled";
@@ -108,10 +105,35 @@
ranges;
reg = <0xfdb10000 0x10000>;
vdd-supply = <&gdsc_oxili_cx>;
- qcom,iommu-smt-size = <32>;
qcom,needs-alt-core-clk;
status = "disabled";
+ qcom,iommu-bfb-regs = <0x204c
+ 0x2050
+ 0x2514
+ 0x2540
+ 0x256c
+ 0x20ac
+ 0x215c
+ 0x220c
+ 0x2314
+ 0x2394
+ 0x2414
+ 0x2008>;
+
+ qcom,iommu-bfb-data = <0xffffffff
+ 0xffffffff
+ 0x00000004
+ 0x00000010
+ 0x00000000
+ 0x00000000
+ 0x00000001
+ 0x00000021
+ 0x0
+ 0x1
+ 0x81
+ 0x0>;
+
qcom,iommu-ctx@fdb18000 {
reg = <0xfdb18000 0x1000>;
interrupts = <0 241 0>;
@@ -134,7 +156,6 @@
ranges;
reg = <0xfda44000 0x10000>;
vdd-supply = <&gdsc_vfe>;
- qcom,iommu-smt-size = <32>;
status = "disabled";
qcom,iommu-ctx@fda4c000 {
diff --git a/arch/arm/boot/dts/msm-pm8019.dtsi b/arch/arm/boot/dts/msm-pm8019.dtsi
index 3b06450..e70eb36 100755
--- a/arch/arm/boot/dts/msm-pm8019.dtsi
+++ b/arch/arm/boot/dts/msm-pm8019.dtsi
@@ -22,6 +22,21 @@
#address-cells = <1>;
#size-cells = <1>;
+ qcom,power_on@800 {
+ compatible = "qcom,qpnp-power-on";
+ reg = <0x800 0x100>;
+ interrupts = <0x0 0x8 0x2>;
+ interrupt-names = "cblpwr";
+ qcom,pon-dbc-delay = <15625>;
+ qcom,system-reset;
+
+ qcom,pon_1 {
+ qcom,pon-type = <2>;
+ qcom,pull-up = <1>;
+ linux,code = <116>;
+ };
+ };
+
clkdiv@5b00 {
reg = <0x5b00 0x100>;
compatible = "qcom,qpnp-clkdiv";
diff --git a/arch/arm/boot/dts/msm8910-sim.dts b/arch/arm/boot/dts/msm8910-sim.dts
new file mode 100644
index 0000000..268e1f8
--- /dev/null
+++ b/arch/arm/boot/dts/msm8910-sim.dts
@@ -0,0 +1,51 @@
+/* Copyright (c) 2012, 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/ "skeleton.dtsi"
+
+/ {
+ model = "Qualcomm MSM 8910 Simulator";
+ compatible = "qcom,msm8910-sim", "qcom,msm8910";
+ qcom,msm-id = <147 1 0>;
+ interrupt-parent = <&intc>;
+
+ intc: interrupt-controller@f9000000 {
+ compatible = "qcom,msm-qgic2";
+ interrupt-controller;
+ #interrupt-cells = <3>;
+ reg = <0xf9000000 0x1000>,
+ <0xf9002000 0x1000>;
+ };
+
+ msmgpio: gpio@fd510000 {
+ compatible = "qcom,msm-gpio";
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ reg = <0xfd510000 0x4000>;
+ #gpio-cells = <2>;
+ };
+
+ timer: msm-qtimer@f9021000 {
+ compatible = "qcom,msm-qtimer", "arm,armv7-timer";
+ reg = <0xf9021000 0x1000>;
+ interrupts = <0 7 0 0 8 0>;
+ irq-is-not-percpu;
+ clock-frequency = <19200000>;
+ };
+
+ serial@f991f000 {
+ compatible = "qcom,msm-lsuart-v14";
+ reg = <0xf991f000 0x1000>;
+ interrupts = <0 109 0>;
+ };
+};
diff --git a/arch/arm/boot/dts/msm8974-gpu.dtsi b/arch/arm/boot/dts/msm8974-gpu.dtsi
index 017aea9..6d00b01 100644
--- a/arch/arm/boot/dts/msm8974-gpu.dtsi
+++ b/arch/arm/boot/dts/msm8974-gpu.dtsi
@@ -25,6 +25,7 @@
qcom,idle-timeout = <83>; //<HZ/12>
qcom,nap-allowed = <1>;
+ qcom,strtstp-sleepwake;
qcom,clk-map = <0x00000016>; //KGSL_CLK_CORE | KGSL_CLK_IFACE | KGSL_CLK_MEM_IFACE
/* Bus Scale Settings */
@@ -85,6 +86,9 @@
compatible = "qcom,dcvs-core-info";
+ qcom,num-cores = <1>;
+ qcom,sensors = <0>;
+
qcom,core-core-type = <1>;
qcom,algo-disable-pc-threshold = <0>;
diff --git a/arch/arm/boot/dts/msm8974-ion.dtsi b/arch/arm/boot/dts/msm8974-ion.dtsi
index 1893ae4..9b5aaac 100644
--- a/arch/arm/boot/dts/msm8974-ion.dtsi
+++ b/arch/arm/boot/dts/msm8974-ion.dtsi
@@ -70,7 +70,7 @@
reg = <28>;
qcom,heap-align = <0x1000>;
qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
- qcom,memory-reservation-size = <0x2B4000>;
+ qcom,memory-reservation-size = <0x314000>;
};
};
};
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index b992e86..374c833 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -761,10 +761,13 @@
qcom,msm-ocmem-audio {
compatible = "qcom,msm-ocmem-audio";
- qcom,msm-ocmem-audio-src-id = <11>;
- qcom,msm-ocmem-audio-dst-id = <604>;
- qcom,msm-ocmem-audio-ab = <32505856>;
- qcom,msm-ocmem-audio-ib = <32505856>;
+ qcom,msm_bus,name = "audio-ocmem";
+ qcom,msm_bus,num_cases = <2>;
+ qcom,msm_bus,active_only = <0>;
+ qcom,msm_bus,num_paths = <1>;
+ qcom,msm_bus,vectors =
+ <11 604 0 0>,
+ <11 604 32505856 32505856>;
};
qcom,mss@fc880000 {
diff --git a/arch/arm/boot/dts/msm8974_pm.dtsi b/arch/arm/boot/dts/msm8974_pm.dtsi
index e39a72a..f108d37 100644
--- a/arch/arm/boot/dts/msm8974_pm.dtsi
+++ b/arch/arm/boot/dts/msm8974_pm.dtsi
@@ -130,6 +130,7 @@
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" */
@@ -138,6 +139,7 @@
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" */
@@ -146,10 +148,17 @@
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,lpm-resources@3 {
+ reg = <0x3>;
+ qcom,name = "l2";
+ qcom,resource-type = <1>;
+ };
};
qcom,lpm-levels {
diff --git a/arch/arm/boot/dts/msm9625-ion.dtsi b/arch/arm/boot/dts/msm9625-ion.dtsi
new file mode 100644
index 0000000..8183264
--- /dev/null
+++ b/arch/arm/boot/dts/msm9625-ion.dtsi
@@ -0,0 +1,35 @@
+/* Copyright (c) 2012, 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.
+ */
+
+/ {
+ qcom,ion {
+ compatible = "qcom,msm-ion";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,ion-heap@30 { /* SYSTEM HEAP */
+ reg = <30>;
+ };
+
+ qcom,ion-heap@25 { /* IOMMU HEAP */
+ reg = <25>;
+ };
+
+ qcom,ion-heap@28 { /* AUDIO HEAP */
+ compatible = "qcom,msm-ion-reserve";
+ reg = <28>;
+ qcom,heap-align = <0x1000>;
+ qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
+ qcom,memory-reservation-size = <0xAF000>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/msm9625-regulator.dtsi b/arch/arm/boot/dts/msm9625-regulator.dtsi
index c42af2c..9184dfe 100644
--- a/arch/arm/boot/dts/msm9625-regulator.dtsi
+++ b/arch/arm/boot/dts/msm9625-regulator.dtsi
@@ -10,154 +10,241 @@
* GNU General Public License for more details.
*/
-&spmi_bus {
- qcom,pm8019@1 {
- pm8019_s1: regulator@1400 {
+&rpm_bus {
+ rpm-regulator-smpa1 {
+ status = "okay";
+ pm8019_s1: regulator-s1 {
regulator-min-microvolt = <800000>;
regulator-max-microvolt = <1050000>;
- qcom,enable-time = <500>;
+ qcom,init-voltage = <1050000>;
status = "okay";
};
+ };
- pm8019_s2: regulator@1700 {
+ rpm-regulator-smpa2 {
+ status = "okay";
+ qcom,allow-atomic = <1>;
+ pm8019_s2: regulator-s2 {
regulator-min-microvolt = <1250000>;
regulator-max-microvolt = <1250000>;
+ qcom,init-voltage = <1250000>;
+ qcom,init-current = <100>;
qcom,system-load = <100000>;
- qcom,enable-time = <500>;
regulator-always-on;
status = "okay";
};
+ };
- pm8019_s3: regulator@1a00 {
- regulator-min-microvolt = <1100000>;
+ rpm-regulator-smpa3 {
+ status = "okay";
+ pm8019_s3: regulator-s3 {
+ regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <1100000>;
+ qcom,init-voltage = <1100000>;
+ qcom,init-current = <100>;
qcom,system-load = <100000>;
- qcom,enable-time = <500>;
regulator-always-on;
status = "okay";
};
+ pm8019_s3_ao: regulator-s3-ao {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8019_s3_ao";
+ qcom,set = <1>;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1100000>;
+ status = "okay";
+ };
+ };
- pm8019_s4: regulator@1d00 {
+ rpm-regulator-smpa4 {
+ status = "okay";
+ pm8019_s4: regulator-s4 {
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <2075000>;
+ qcom,init-voltage = <2075000>;
+ qcom,init-current = <100>;
qcom,system-load = <100000>;
- qcom,enable-time = <500>;
regulator-always-on;
status = "okay";
};
+ };
- pm8019_l1: regulator@4000 {
+ rpm-regulator-ldoa1 {
+ status = "okay";
+ pm8019_l1: regulator-l1 {
parent-supply = <&pm8019_s2>;
regulator-min-microvolt = <1225000>;
regulator-max-microvolt = <1225000>;
- qcom,enable-time = <200>;
+ qcom,init-voltage = <1225000>;
status = "okay";
};
+ };
- pm8019_l2: regulator@4100 {
+ rpm-regulator-ldoa2 {
+ status = "okay";
+ pm8019_l2: regulator-l2 {
parent-supply = <&pm8019_s4>;
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
- qcom,enable-time = <200>;
+ qcom,init-voltage = <1800000>;
status = "okay";
};
+ };
- pm8019_l3: regulator@4200 {
+ rpm-regulator-ldoa3 {
+ status = "okay";
+ pm8019_l3: regulator-l3 {
parent-supply = <&pm8019_s4>;
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
- qcom,enable-time = <200>;
+ qcom,init-voltage = <1800000>;
status = "okay";
};
+ };
- pm8019_l4: regulator@4300 {
+ rpm-regulator-ldoa4 {
+ status = "okay";
+ pm8019_l4: regulator-l4 {
regulator-min-microvolt = <3075000>;
regulator-max-microvolt = <3075000>;
- qcom,enable-time = <200>;
+ qcom,init-voltage = <3075000>;
status = "okay";
};
+ };
- pm8019_l5: regulator@4400 {
+ rpm-regulator-ldoa5 {
+ status = "okay";
+ pm8019_l5: regulator-l5 {
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <2850000>;
- qcom,enable-time = <200>;
+ qcom,init-voltage = <1800000>;
status = "okay";
};
+ };
- pm8019_l6: regulator@4500 {
+ rpm-regulator-ldoa6 {
+ status = "okay";
+ pm8019_l6: regulator-l6 {
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <2850000>;
- qcom,enable-time = <200>;
+ qcom,init-voltage = <1800000>;
status = "okay";
};
+ };
- pm8019_l7: regulator@4600 {
+ rpm-regulator-ldoa7 {
+ status = "okay";
+ pm8019_l7: regulator-l7 {
parent-supply = <&pm8019_s4>;
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
- qcom,enable-time = <200>;
+ qcom,init-voltage = <1800000>;
status = "okay";
};
+ };
- pm8019_l8: regulator@4700 {
+ rpm-regulator-ldoa8 {
+ status = "okay";
+ pm8019_l8: regulator-l8 {
parent-supply = <&pm8019_s4>;
regulator-min-microvolt = <2050000>;
regulator-max-microvolt = <2050000>;
- qcom,enable-time = <200>;
+ qcom,init-voltage = <2050000>;
status = "okay";
};
+ };
- pm8019_l9: regulator@4800 {
+ rpm-regulator-ldoa9 {
+ status = "okay";
+ pm8019_l9: regulator-l9 {
parent-supply = <&pm8019_s2>;
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <1200000>;
+ qcom,init-voltage = <1200000>;
+ qcom,init-current = <10>;
qcom,system-load = <10000>;
- qcom,enable-time = <200>;
regulator-always-on;
status = "okay";
};
+ };
- pm8019_l10: regulator@4900 {
+ rpm-regulator-ldoa10 {
+ status = "okay";
+ pm8019_l10: regulator-l10 {
parent-supply = <&pm8019_s3>;
- regulator-min-microvolt = <1050000>;
+ regulator-min-microvolt = <500000>;
regulator-max-microvolt = <1050000>;
- qcom,system-load = <10000>;
- qcom,enable-time = <200>;
- regulator-always-on;
status = "okay";
};
+ pm8019_l10_corner: regulator-l10-corner {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8019_l10_corner";
+ qcom,set = <3>;
+ regulator-min-microvolt = <1>;
+ regulator-max-microvolt = <7>;
+ qcom,use-voltage-corner;
+ status = "okay";
+ };
+ pm8019_l10_corner_ao: regulator-l10-corner-ao {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8019_l10_corner_ao";
+ qcom,set = <1>;
+ regulator-min-microvolt = <1>;
+ regulator-max-microvolt = <7>;
+ qcom,use-voltage-corner;
+ status = "okay";
+ };
+ };
- pm8019_l11: regulator@4a00 {
+ rpm-regulator-ldoa11 {
+ status = "okay";
+ pm8019_l11: regulator-l11 {
parent-supply = <&pm8019_s4>;
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
+ qcom,init-voltage = <1800000>;
+ qcom,init-current = <10>;
qcom,system-load = <10000>;
- qcom,enable-time = <200>;
regulator-always-on;
status = "okay";
};
+ };
- pm8019_l12: regulator@4b00 {
+ rpm-regulator-ldoa12 {
+ status = "okay";
+ pm8019_l12: regulator-l12 {
parent-supply = <&pm8019_s3>;
- regulator-min-microvolt = <1050000>;
+ regulator-min-microvolt = <750000>;
regulator-max-microvolt = <1050000>;
- qcom,system-load = <10000>;
- qcom,enable-time = <200>;
- regulator-always-on;
status = "okay";
};
+ pm8019_l12_ao: regulator-l12-ao {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8019_l12_ao";
+ qcom,set = <1>;
+ parent-supply = <&pm8019_s3_ao>;
+ regulator-min-microvolt = <750000>;
+ regulator-max-microvolt = <1050000>;
+ status = "okay";
+ };
+ };
- pm8019_l13: regulator@4c00 {
+ rpm-regulator-ldoa13 {
+ status = "okay";
+ pm8019_l13: regulator-l13 {
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <2950000>;
- qcom,enable-time = <200>;
+ qcom,init-voltage = <2950000>;
status = "okay";
};
+ };
- pm8019_l14: regulator@4d00 {
+ rpm-regulator-ldoa14 {
+ status = "okay";
+ pm8019_l14: regulator-l14 {
regulator-min-microvolt = <2700000>;
regulator-max-microvolt = <2700000>;
- qcom,enable-time = <200>;
+ qcom,init-voltage = <2700000>;
status = "okay";
};
};
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index f50d14f..a8a2bf1 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -11,6 +11,7 @@
*/
/include/ "skeleton.dtsi"
+/include/ "msm9625-ion.dtsi"
/ {
model = "Qualcomm MSM 9625";
diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c
index 9dd4347..6b8a374 100644
--- a/arch/arm/common/gic.c
+++ b/arch/arm/common/gic.c
@@ -1167,41 +1167,35 @@
/*
* Configure the GIC after we come out of power collapse.
* This function will configure some of the GIC registers so as to prepare the
- * core1 to receive an SPI(ACSR_MP_CORE_IPC1, (32 + 8)), which will bring
- * core1 out of GDFS.
+ * secondary cores to receive an SPI(ACSR_MP_CORE_IPC1/IPC2/IPC3, 40/92/93),
+ * which will bring cores out of GDFS.
*/
-void core1_gic_configure_and_raise(void)
+void gic_configure_and_raise(unsigned int irq, unsigned int cpu)
{
struct gic_chip_data *gic = &gic_data[0];
+ struct irq_data *d = irq_get_irq_data(irq);
void __iomem *base = gic_data_dist_base(gic);
- unsigned int value = 0;
+ unsigned int value = 0, byte_offset, offset, bit;
unsigned long flags;
+ offset = ((gic_irq(d) / 32) * 4);
+ bit = BIT(gic_irq(d) % 32);
+
raw_spin_lock_irqsave(&irq_controller_lock, flags);
- value = __raw_readl(base + GIC_DIST_ACTIVE_BIT + 0x4);
- value |= BIT(8);
- __raw_writel(value, base + GIC_DIST_ACTIVE_BIT + 0x4);
+ value = __raw_readl(base + GIC_DIST_ACTIVE_BIT + offset);
+ __raw_writel(value | bit, base + GIC_DIST_ACTIVE_BIT + offset);
mb();
- value = __raw_readl(base + GIC_DIST_TARGET + 0x24);
- value |= BIT(13);
- __raw_writel(value, base + GIC_DIST_TARGET + 0x24);
+ value = __raw_readl(base + GIC_DIST_TARGET + (gic_irq(d) / 4) * 4);
+ byte_offset = (gic_irq(d) % 4) * 8;
+ value |= 1 << (cpu + byte_offset);
+ __raw_writel(value, base + GIC_DIST_TARGET + (gic_irq(d) / 4) * 4);
mb();
- value = __raw_readl(base + GIC_DIST_TARGET + 0x28);
- value |= BIT(1);
- __raw_writel(value, base + GIC_DIST_TARGET + 0x28);
+ value = __raw_readl(base + GIC_DIST_ENABLE_SET + offset);
+ __raw_writel(value | bit, base + GIC_DIST_ENABLE_SET + offset);
mb();
- value = __raw_readl(base + GIC_DIST_ENABLE_SET + 0x4);
- value |= BIT(8);
- __raw_writel(value, base + GIC_DIST_ENABLE_SET + 0x4);
- mb();
-
- value = __raw_readl(base + GIC_DIST_PENDING_SET + 0x4);
- value |= BIT(8);
- __raw_writel(value, base + GIC_DIST_PENDING_SET + 0x4);
- mb();
raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
}
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index 45d52e4..6a6bfda 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -71,7 +71,8 @@
CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
CONFIG_MSM_AVS_HW=y
# CONFIG_MSM_HW3D is not set
-CONFIG_MSM_PIL_QDSP6V4=y
+CONFIG_MSM_PIL_LPASS_QDSP6V4=y
+CONFIG_MSM_PIL_MODEM_QDSP6V4=y
CONFIG_MSM_PIL_RIVA=y
CONFIG_MSM_PIL_TZAPPS=y
CONFIG_MSM_PIL_DSPS=y
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index 465598f..cf2dd23 100644
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -70,7 +70,8 @@
CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
CONFIG_MSM_AVS_HW=y
# CONFIG_MSM_HW3D is not set
-CONFIG_MSM_PIL_QDSP6V4=y
+CONFIG_MSM_PIL_LPASS_QDSP6V4=y
+CONFIG_MSM_PIL_MODEM_QDSP6V4=y
CONFIG_MSM_PIL_RIVA=y
CONFIG_MSM_PIL_TZAPPS=y
CONFIG_MSM_PIL_DSPS=y
diff --git a/arch/arm/configs/msm9625_defconfig b/arch/arm/configs/msm9625_defconfig
index 364a1bf..3121c13 100644
--- a/arch/arm/configs/msm9625_defconfig
+++ b/arch/arm/configs/msm9625_defconfig
@@ -35,6 +35,9 @@
CONFIG_CPU_HAS_L2_PMU=y
# CONFIG_MSM_FIQ_SUPPORT is not set
# CONFIG_MSM_PROC_COMM is not set
+CONFIG_MSM_SMD=y
+CONFIG_MSM_SMD_PKG4=y
+CONFIG_MSM_RPM_REGULATOR_SMD=y
CONFIG_MSM_DIRECT_SCLK_ACCESS=y
CONFIG_MSM_WATCHDOG_V2=y
CONFIG_NO_HZ=y
@@ -102,7 +105,9 @@
# CONFIG_HWMON is not set
CONFIG_REGULATOR=y
CONFIG_REGULATOR_QPNP=y
-# CONFIG_HID_SUPPORT is not set
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_SOC=y
CONFIG_USB_GADGET=y
CONFIG_USB_CI13XXX_MSM=y
CONFIG_USB_G_ANDROID=y
@@ -113,6 +118,7 @@
CONFIG_USB_BAM=y
CONFIG_SPS_SUPPORT_BAMDMA=y
CONFIG_SPS_SUPPORT_NDP_BAM=y
+CONFIG_QPNP_POWER_ON=y
CONFIG_VFAT_FS=y
CONFIG_TMPFS=y
CONFIG_YAFFS_FS=y
@@ -146,3 +152,12 @@
# CONFIG_CRYPTO_HW is not set
CONFIG_CRC_CCITT=y
CONFIG_LIBCRC32C=y
+CONFIG_MMC=y
+CONFIG_MMC_PERF_PROFILING=y
+CONFIG_MMC_CLKGATE=y
+CONFIG_MMC_PARANOID_SD_INIT=y
+CONFIG_MMC_BLOCK_MINORS=32
+CONFIG_MMC_TEST=m
+CONFIG_MMC_MSM=y
+CONFIG_MMC_MSM_SPS_SUPPORT=y
+CONFIG_MMC_UNSAFE_RESUME=y
diff --git a/arch/arm/include/asm/hardware/gic.h b/arch/arm/include/asm/hardware/gic.h
index ad12bcd..72c3c27 100644
--- a/arch/arm/include/asm/hardware/gic.h
+++ b/arch/arm/include/asm/hardware/gic.h
@@ -62,7 +62,7 @@
void msm_gic_save(void);
void msm_gic_restore(void);
-void core1_gic_configure_and_raise(void);
+void gic_configure_and_raise(unsigned int irq, unsigned int cpu);
#endif
#endif
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 2020422..7cfe205 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -355,10 +355,26 @@
select MSM_SMP
select CPU_V7
select MSM_GPIOMUX
+ select MSM_RPM_SMD
select MULTI_IRQ_HANDLER
select GPIO_MSM_V3
select MAY_HAVE_SPARSE_IRQ
select SPARSE_IRQ
+ select MSM_MULTIMEDIA_USE_ION
+
+config ARCH_MSM8910
+ bool "MSM8910"
+ select ARM_GIC
+ select GIC_SECURE
+ select SMP
+ select ARCH_MSM_CORTEXMP
+ select CPU_V7
+ select MSM_SCM if SMP
+ select MAY_HAVE_SPARSE_IRQ
+ select SPARSE_IRQ
+ select MULTI_IRQ_HANDLER
+ select GPIO_MSM_V3
+ select MSM_GPIOMUX
endmenu
choice
@@ -926,6 +942,7 @@
default "0x00000000" if ARCH_MSM8974
default "0x00000000" if ARCH_MPQ8092
default "0x00000000" if ARCH_MSM8226
+ default "0x00000000" if ARCH_MSM8910
default "0x10000000" if ARCH_FSM9XXX
default "0x00200000" if ARCH_MSM9625
default "0x00200000" if !MSM_STACKED_MEMORY
@@ -1914,13 +1931,25 @@
Support for booting and shutting down QDSP6v3 processors (hexagon).
The QDSP6 is a low power DSP used in audio software applications.
-config MSM_PIL_QDSP6V4
- tristate "QDSP6v4 (Hexagon) Boot Support"
+config MSM_PIL_LPASS_QDSP6V4
+ tristate "LPASS QDSP6v4 (Hexagon) Boot Support"
depends on MSM_PIL
help
- Support for booting and shutting down QDSP6v4 processors (hexagon).
- The QDSP6 is a low power DSP used in audio, modem firmware, and modem
- software applications.
+ Support for booting and shutting down QDSP6v4 processors (hexagon)
+ in low power audio subsystems. If you would like to record or
+ play audio then say Y here.
+
+ If unsure, say N.
+
+config MSM_PIL_MODEM_QDSP6V4
+ tristate "Modem QDSP6v4 (Hexagon) Boot Support"
+ depends on MSM_PIL
+ help
+ Support for booting and shutting down QDSP6v4 processors (hexagon)
+ in modem subsystems. If you would like to make or receive phone
+ calls then say Y here.
+
+ If unsure, say N.
config MSM_PIL_LPASS_QDSP6V5
tristate "LPASS QDSP6v5 (Hexagon) Boot Support"
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 7dece76..862607f 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -72,7 +72,8 @@
obj-$(CONFIG_MSM_PIL) += peripheral-loader.o
obj-$(CONFIG_MSM_PIL) += scm-pas.o
obj-$(CONFIG_MSM_PIL_QDSP6V3) += pil-q6v3.o
-obj-$(CONFIG_MSM_PIL_QDSP6V4) += pil-q6v4.o
+obj-$(CONFIG_MSM_PIL_LPASS_QDSP6V4) += pil-q6v4.o pil-q6v4-lpass.o
+obj-$(CONFIG_MSM_PIL_MODEM_QDSP6V4) += pil-q6v4.o pil-q6v4-mss.o
obj-$(CONFIG_MSM_PIL_LPASS_QDSP6V5) += pil-q6v5.o pil-q6v5-lpass.o
obj-$(CONFIG_MSM_PIL_MSS_QDSP6V5) += pil-q6v5.o pil-q6v5-mss.o
obj-$(CONFIG_MSM_PIL_MBA) += pil-mba.o
@@ -106,6 +107,7 @@
ifndef CONFIG_ARCH_MSM8226
ifndef CONFIG_ARCH_MSM9625
ifndef CONFIG_ARCH_MPQ8092
+ifndef CONFIG_ARCH_MSM8910
obj-y += nand_partitions.o
endif
endif
@@ -114,6 +116,7 @@
endif
endif
endif
+endif
obj-$(CONFIG_MSM_SDIO_TTY) += sdio_tty.o
obj-$(CONFIG_MSM_SMD_TTY) += smd_tty.o
obj-$(CONFIG_MSM_SMD_QMI) += smd_qmi.o
@@ -289,6 +292,7 @@
obj-$(CONFIG_ARCH_MSM8930) += acpuclock-8930.o acpuclock-8627.o acpuclock-8930aa.o
obj-$(CONFIG_ARCH_MPQ8092) += board-8092.o board-8092-gpiomux.o
obj-$(CONFIG_ARCH_MSM8226) += board-8226.o board-8226-gpiomux.o
+obj-$(CONFIG_ARCH_MSM8910) += board-8910.o
obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire.o board-sapphire-gpio.o
obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire-keypad.o board-sapphire-panel.o
@@ -346,9 +350,10 @@
obj-$(CONFIG_ARCH_MSM9625) += gpiomux-v2.o gpiomux.o
obj-$(CONFIG_ARCH_MPQ8092) += gpiomux-v2.o gpiomux.o
obj-$(CONFIG_ARCH_MSM8226) += gpiomux-v2.o gpiomux.o
+obj-$(CONFIG_ARCH_MSM8910) += gpiomux-v2.o gpiomux.o
obj-$(CONFIG_MSM_SLEEP_STATS_DEVICE) += idle_stats_device.o
-obj-$(CONFIG_MSM_DCVS) += msm_dcvs_scm.o msm_dcvs.o msm_dcvs_idle.o msm_mpdecision.o
+obj-$(CONFIG_MSM_DCVS) += msm_dcvs_scm.o msm_dcvs.o msm_mpdecision.o
obj-$(CONFIG_MSM_RUN_QUEUE_STATS) += msm_rq_stats.o
obj-$(CONFIG_MSM_SHOW_RESUME_IRQ) += msm_show_resume_irq.o
obj-$(CONFIG_BT_MSM_PINTEST) += btpintest.o
diff --git a/arch/arm/mach-msm/Makefile.boot b/arch/arm/mach-msm/Makefile.boot
index 9234b2c..cf1f401 100644
--- a/arch/arm/mach-msm/Makefile.boot
+++ b/arch/arm/mach-msm/Makefile.boot
@@ -65,3 +65,5 @@
# MPQ8092
zreladdr-$(CONFIG_ARCH_MPQ8092) := 0x00008000
+# MSM8910
+ zreladdr-$(CONFIG_ARCH_MSM8910) := 0x00008000
diff --git a/arch/arm/mach-msm/acpuclock-8064.c b/arch/arm/mach-msm/acpuclock-8064.c
index d10211bc..d1613d9 100644
--- a/arch/arm/mach-msm/acpuclock-8064.c
+++ b/arch/arm/mach-msm/acpuclock-8064.c
@@ -116,7 +116,7 @@
};
static struct l2_level l2_freq_tbl[] __initdata = {
- [0] = { { 384000, PLL_8, 0, 0x00 }, 1050000, 1050000, 1 },
+ [0] = { { 384000, PLL_8, 0, 0x00 }, 950000, 1050000, 1 },
[1] = { { 432000, HFPLL, 2, 0x20 }, 1050000, 1050000, 2 },
[2] = { { 486000, HFPLL, 2, 0x24 }, 1050000, 1050000, 2 },
[3] = { { 540000, HFPLL, 2, 0x28 }, 1050000, 1050000, 2 },
diff --git a/arch/arm/mach-msm/board-8064-gpu.c b/arch/arm/mach-msm/board-8064-gpu.c
index 3be7fc6..fad7092 100644
--- a/arch/arm/mach-msm/board-8064-gpu.c
+++ b/arch/arm/mach-msm/board-8064-gpu.c
@@ -31,11 +31,14 @@
};
static struct msm_dcvs_core_info grp3d_core_info = {
- .freq_tbl = &grp3d_freq[0],
- .core_param = {
+ .freq_tbl = &grp3d_freq[0],
+ .num_cores = 1,
+ .sensors = (int[]){0},
+ .thermal_poll_ms = 60000,
+ .core_param = {
.core_type = MSM_DCVS_CORE_TYPE_GPU,
},
- .algo_param = {
+ .algo_param = {
.disable_pc_threshold = 0,
.em_win_size_min_us = 100000,
.em_win_size_max_us = 300000,
@@ -51,8 +54,7 @@
.ss_iobusy_conv = 100,
},
-
- .energy_coeffs = {
+ .energy_coeffs = {
.leakage_coeff_a = -17720,
.leakage_coeff_b = 37,
.leakage_coeff_c = 3329,
@@ -63,7 +65,7 @@
.active_coeff_c = 0
},
- .power_param = {
+ .power_param = {
.current_temp = 25,
.num_freq = ARRAY_SIZE(grp3d_freq),
}
diff --git a/arch/arm/mach-msm/board-8064-regulator.c b/arch/arm/mach-msm/board-8064-regulator.c
index ef3c81d..2bef087 100644
--- a/arch/arm/mach-msm/board-8064-regulator.c
+++ b/arch/arm/mach-msm/board-8064-regulator.c
@@ -121,8 +121,6 @@
};
VREG_CONSUMERS(L23) = {
REGULATOR_SUPPLY("8921_l23", NULL),
- REGULATOR_SUPPLY("pll_vdd", "pil_qdsp6v4.1"),
- REGULATOR_SUPPLY("pll_vdd", "pil_qdsp6v4.2"),
REGULATOR_SUPPLY("HSUSB_1p8", "msm_ehci_host.0"),
REGULATOR_SUPPLY("HSUSB_1p8", "msm_ehci_host.1"),
};
@@ -141,15 +139,13 @@
};
VREG_CONSUMERS(L26) = {
REGULATOR_SUPPLY("8921_l26", NULL),
- REGULATOR_SUPPLY("core_vdd", "pil_qdsp6v4.0"),
+ REGULATOR_SUPPLY("core_vdd", "pil-q6v4-lpass"),
};
VREG_CONSUMERS(L27) = {
REGULATOR_SUPPLY("8921_l27", NULL),
- REGULATOR_SUPPLY("core_vdd", "pil_qdsp6v4.2"),
};
VREG_CONSUMERS(L28) = {
REGULATOR_SUPPLY("8921_l28", NULL),
- REGULATOR_SUPPLY("core_vdd", "pil_qdsp6v4.1"),
};
VREG_CONSUMERS(L29) = {
REGULATOR_SUPPLY("8921_l29", NULL),
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index cc9dcbb..b3add3b 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -605,6 +605,11 @@
#endif
}
+static void __init reserve_mpdcvs_memory(void)
+{
+ apq8064_reserve_table[MEMTYPE_EBI1].size += SZ_32K;
+}
+
static void __init apq8064_calculate_reserve_sizes(void)
{
size_pmem_devices();
@@ -613,6 +618,7 @@
reserve_mdp_memory();
reserve_rtb_memory();
reserve_cache_dump_memory();
+ reserve_mpdcvs_memory();
}
static struct reserve_info apq8064_reserve_info __initdata = {
@@ -2556,6 +2562,7 @@
&apq8064_rpm_device,
&apq8064_rpm_log_device,
&apq8064_rpm_stat_device,
+ &apq8064_rpm_master_stat_device,
&apq_device_tz_log,
&msm_bus_8064_apps_fabric,
&msm_bus_8064_sys_fabric,
@@ -2568,7 +2575,6 @@
&msm_pil_vidc,
&msm_gss,
&apq8064_rtb_device,
- &apq8064_cpu_idle_device,
&apq8064_msm_gov_device,
&apq8064_device_cache_erp,
&msm8960_device_ebi1_ch0_erp,
diff --git a/arch/arm/mach-msm/board-8910.c b/arch/arm/mach-msm/board-8910.c
new file mode 100644
index 0000000..18463e3
--- /dev/null
+++ b/arch/arm/mach-msm/board-8910.c
@@ -0,0 +1,94 @@
+/* Copyright (c) 2012, 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/errno.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/of_fdt.h>
+#include <linux/of_irq.h>
+#include <linux/memory.h>
+#include <asm/mach/map.h>
+#include <asm/arch_timer.h>
+#include <asm/hardware/gic.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+#include <mach/board.h>
+#include <mach/gpiomux.h>
+#include <mach/msm_iomap.h>
+#ifdef CONFIG_ION_MSM
+#include <mach/ion.h>
+#endif
+#include <mach/socinfo.h>
+#include <mach/board.h>
+#include <mach/clk-provider.h>
+#include "clock.h"
+
+static struct clk_lookup msm_clocks_dummy[] = {
+ CLK_DUMMY("core_clk", BLSP1_UART_CLK, "f991f000.serial", OFF),
+ CLK_DUMMY("iface_clk", BLSP1_UART_CLK, "f991f000.serial", OFF),
+};
+
+struct clock_init_data msm_dummy_clock_init_data __initdata = {
+ .table = msm_clocks_dummy,
+ .size = ARRAY_SIZE(msm_clocks_dummy),
+};
+
+static struct of_device_id irq_match[] __initdata = {
+ { .compatible = "qcom,msm-qgic2", .data = gic_of_init, },
+ { .compatible = "qcom,msm-gpio", .data = msm_gpio_of_init, },
+ {},
+};
+
+static void __init msm8910_dt_timer_init(void)
+{
+ arch_timer_of_register();
+}
+
+static struct sys_timer msm8910_dt_timer = {
+ .init = msm8910_dt_timer_init
+};
+
+void __init msm8910_init_irq(void)
+{
+ of_irq_init(irq_match);
+}
+
+void __init msm8910_init(void)
+{
+ msm_clock_init(&msm_dummy_clock_init_data);
+
+ if (socinfo_init() < 0)
+ pr_err("%s: socinfo_init() failed\n", __func__);
+
+ of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
+}
+
+static const char *msm8910_dt_match[] __initconst = {
+ "qcom,msm8910",
+ NULL
+};
+
+DT_MACHINE_START(MSM8910_DT, "Qualcomm MSM 8910 (Flattened Device Tree)")
+ .map_io = msm_map_msm8910_io,
+ .init_irq = msm8910_init_irq,
+ .init_machine = msm8910_init,
+ .handle_irq = gic_handle_irq,
+ .timer = &msm8910_dt_timer,
+ .dt_compat = msm8910_dt_match,
+MACHINE_END
diff --git a/arch/arm/mach-msm/board-8930-regulator-pm8038.c b/arch/arm/mach-msm/board-8930-regulator-pm8038.c
index 208f15b..16a82b4 100644
--- a/arch/arm/mach-msm/board-8930-regulator-pm8038.c
+++ b/arch/arm/mach-msm/board-8930-regulator-pm8038.c
@@ -117,7 +117,7 @@
};
VREG_CONSUMERS(L16) = {
REGULATOR_SUPPLY("8038_l16", NULL),
- REGULATOR_SUPPLY("core_vdd", "pil_qdsp6v4.2"),
+ REGULATOR_SUPPLY("sw_core_vdd", "pil-q6v4-modem"),
};
VREG_CONSUMERS(L17) = {
REGULATOR_SUPPLY("8038_l17", NULL),
@@ -127,7 +127,7 @@
};
VREG_CONSUMERS(L19) = {
REGULATOR_SUPPLY("8038_l19", NULL),
- REGULATOR_SUPPLY("core_vdd", "pil_qdsp6v4.1"),
+ REGULATOR_SUPPLY("fw_core_vdd", "pil-q6v4-modem"),
};
VREG_CONSUMERS(L20) = {
REGULATOR_SUPPLY("8038_l20", NULL),
@@ -151,8 +151,7 @@
REGULATOR_SUPPLY("hdmi_avdd", "hdmi_msm.0"),
REGULATOR_SUPPLY("hdmi_vcc", "hdmi_msm.0"),
REGULATOR_SUPPLY("pll_vdd", "pil_riva"),
- REGULATOR_SUPPLY("pll_vdd", "pil_qdsp6v4.1"),
- REGULATOR_SUPPLY("pll_vdd", "pil_qdsp6v4.2"),
+ REGULATOR_SUPPLY("pll_vdd", "pil-q6v4-modem"),
};
VREG_CONSUMERS(L24) = {
REGULATOR_SUPPLY("8038_l24", NULL),
@@ -166,7 +165,7 @@
};
VREG_CONSUMERS(L27) = {
REGULATOR_SUPPLY("8038_l27", NULL),
- REGULATOR_SUPPLY("core_vdd", "pil_qdsp6v4.0"),
+ REGULATOR_SUPPLY("core_vdd", "pil-q6v4-lpass"),
};
VREG_CONSUMERS(S1) = {
REGULATOR_SUPPLY("8038_s1", NULL),
diff --git a/arch/arm/mach-msm/board-8930-regulator-pm8917.c b/arch/arm/mach-msm/board-8930-regulator-pm8917.c
index db40e5d..b7f554c 100644
--- a/arch/arm/mach-msm/board-8930-regulator-pm8917.c
+++ b/arch/arm/mach-msm/board-8930-regulator-pm8917.c
@@ -547,7 +547,7 @@
RPM_SMPS(S2, 0, 1, 0, 1300000, 1300000, NULL, 0, 1p60, NONE, NONE),
RPM_SMPS(S3, 0, 1, 1, 500000, 1150000, NULL, 100000, 4p80, AUTO, LPM),
RPM_SMPS(S4, 1, 1, 0, 1800000, 1800000, NULL, 100000, 1p60, AUTO, LPM),
- RPM_SMPS(S7, 0, 1, 0, 1150000, 1150000, NULL, 100000, 3p20, NONE, NONE),
+ RPM_SMPS(S7, 0, 1, 0, 1150000, 1150000, NULL, 100000, 3p20, AUTO, AUTO),
RPM_SMPS(S8, 1, 1, 1, 2050000, 2050000, NULL, 100000, 1p60, NONE, NONE),
/* ID a_on pd ss min_uV max_uV supply sys_uA init_ip */
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index a6a90a7..f0f59ec 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -2347,8 +2347,7 @@
static struct platform_device *common_devices[] __initdata = {
&msm_8960_q6_lpass,
- &msm_8960_q6_mss_fw,
- &msm_8960_q6_mss_sw,
+ &msm_8960_q6_mss,
&msm_8960_riva,
&msm_pil_tzapps,
&msm_pil_vidc,
@@ -2398,6 +2397,7 @@
&msm8930_rpm_log_device,
&msm8930_rpm_rbcpr_device,
&msm8930_rpm_stat_device,
+ &msm8930_rpm_master_stat_device,
#ifdef CONFIG_ION_MSM
&msm8930_ion_dev,
#endif
@@ -2413,7 +2413,6 @@
&gpio_keys_8930,
#endif
&msm8930_rtb_device,
- &msm8930_cpu_idle_device,
&msm_bus_8930_apps_fabric,
&msm_bus_8930_sys_fabric,
&msm_bus_8930_mm_fabric,
diff --git a/arch/arm/mach-msm/board-8960-regulator.c b/arch/arm/mach-msm/board-8960-regulator.c
index 2fa98b6..a6c0bc7 100644
--- a/arch/arm/mach-msm/board-8960-regulator.c
+++ b/arch/arm/mach-msm/board-8960-regulator.c
@@ -120,8 +120,7 @@
REGULATOR_SUPPLY("dsi_pll_vddio", "mdp.0"),
REGULATOR_SUPPLY("hdmi_avdd", "hdmi_msm.0"),
REGULATOR_SUPPLY("pll_vdd", "pil_riva"),
- REGULATOR_SUPPLY("pll_vdd", "pil_qdsp6v4.1"),
- REGULATOR_SUPPLY("pll_vdd", "pil_qdsp6v4.2"),
+ REGULATOR_SUPPLY("pll_vdd", "pil-q6v4-modem"),
};
VREG_CONSUMERS(L24) = {
REGULATOR_SUPPLY("8921_l24", NULL),
@@ -136,15 +135,15 @@
};
VREG_CONSUMERS(L26) = {
REGULATOR_SUPPLY("8921_l26", NULL),
- REGULATOR_SUPPLY("core_vdd", "pil_qdsp6v4.0"),
+ REGULATOR_SUPPLY("core_vdd", "pil-q6v4-lpass"),
};
VREG_CONSUMERS(L27) = {
REGULATOR_SUPPLY("8921_l27", NULL),
- REGULATOR_SUPPLY("core_vdd", "pil_qdsp6v4.2"),
+ REGULATOR_SUPPLY("sw_core_vdd", "pil-q6v4-modem"),
};
VREG_CONSUMERS(L28) = {
REGULATOR_SUPPLY("8921_l28", NULL),
- REGULATOR_SUPPLY("core_vdd", "pil_qdsp6v4.1"),
+ REGULATOR_SUPPLY("fw_core_vdd", "pil-q6v4-modem"),
};
VREG_CONSUMERS(L29) = {
REGULATOR_SUPPLY("8921_l29", NULL),
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index 7115e40..7e96edf 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -2753,6 +2753,7 @@
&msm8960_rpm_device,
&msm8960_rpm_log_device,
&msm8960_rpm_stat_device,
+ &msm8960_rpm_master_stat_device,
&msm_device_tz_log,
&coresight_tpiu_device,
&coresight_etb_device,
@@ -2762,7 +2763,6 @@
&msm_device_dspcrashd_8960,
&msm8960_device_watchdog,
&msm8960_rtb_device,
- &msm8960_cpu_idle_device,
&msm8960_device_cache_erp,
&msm8960_device_ebi1_ch0_erp,
&msm8960_device_ebi1_ch1_erp,
@@ -3281,10 +3281,8 @@
msm8960_pm8921_gpio_mpp_init();
/* Don't add modem devices on APQ targets */
- if (socinfo_get_id() != 124) {
- platform_device_register(&msm_8960_q6_mss_fw);
- platform_device_register(&msm_8960_q6_mss_sw);
- }
+ if (socinfo_get_id() != 124)
+ platform_device_register(&msm_8960_q6_mss);
platform_add_devices(cdp_devices, ARRAY_SIZE(cdp_devices));
msm8960_init_smsc_hub();
msm8960_init_hsic();
diff --git a/arch/arm/mach-msm/board-9615.c b/arch/arm/mach-msm/board-9615.c
index ca95b62..43f34fe 100644
--- a/arch/arm/mach-msm/board-9615.c
+++ b/arch/arm/mach-msm/board-9615.c
@@ -933,6 +933,7 @@
&msm_bus_def_fab,
&msm9615_rpm_log_device,
&msm9615_rpm_stat_device,
+ &msm9615_rpm_master_stat_device,
&msm_tsens_device,
};
diff --git a/arch/arm/mach-msm/board-9625.c b/arch/arm/mach-msm/board-9625.c
index 37e93b6..ca9bdaa 100644
--- a/arch/arm/mach-msm/board-9625.c
+++ b/arch/arm/mach-msm/board-9625.c
@@ -32,7 +32,12 @@
#include <mach/clk-provider.h>
#include <mach/qpnp-int.h>
#include <mach/msm_memtypes.h>
+#include <mach/msm_iomap.h>
+#include <mach/msm_smd.h>
+#include <mach/rpm-smd.h>
+#include <mach/rpm-regulator-smd.h>
#include "clock.h"
+#include "modem_notifier.h"
#define MSM_KERNEL_EBI_SIZE 0x51000
@@ -134,6 +139,153 @@
msm_reserve();
}
+static struct resource smd_resource[] = {
+ {
+ .name = "modem_smd_in",
+ .start = 32 + 25, /* mss_sw_to_kpss_ipc_irq0 */
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "modem_smsm_in",
+ .start = 32 + 26, /* mss_sw_to_kpss_ipc_irq1 */
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "adsp_smd_in",
+ .start = 32 + 156, /* lpass_to_kpss_ipc_irq0 */
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "adsp_smsm_in",
+ .start = 32 + 157, /* lpass_to_kpss_ipc_irq1 */
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "rpm_smd_in",
+ .start = 32 + 168, /* rpm_to_kpss_ipc_irq4 */
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct smd_subsystem_config smd_config_list[] = {
+ {
+ .irq_config_id = SMD_MODEM,
+ .subsys_name = "modem",
+ .edge = SMD_APPS_MODEM,
+
+ .smd_int.irq_name = "modem_smd_in",
+ .smd_int.flags = IRQF_TRIGGER_RISING,
+ .smd_int.irq_id = -1,
+ .smd_int.device_name = "smd_dev",
+ .smd_int.dev_id = 0,
+ .smd_int.out_bit_pos = 1 << 12,
+ .smd_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
+ .smd_int.out_offset = 0x8,
+
+ .smsm_int.irq_name = "modem_smsm_in",
+ .smsm_int.flags = IRQF_TRIGGER_RISING,
+ .smsm_int.irq_id = -1,
+ .smsm_int.device_name = "smsm_dev",
+ .smsm_int.dev_id = 0,
+ .smsm_int.out_bit_pos = 1 << 13,
+ .smsm_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
+ .smsm_int.out_offset = 0x8,
+ },
+ {
+ .irq_config_id = SMD_Q6,
+ .subsys_name = "adsp",
+ .edge = SMD_APPS_QDSP,
+
+ .smd_int.irq_name = "adsp_smd_in",
+ .smd_int.flags = IRQF_TRIGGER_RISING,
+ .smd_int.irq_id = -1,
+ .smd_int.device_name = "smd_dev",
+ .smd_int.dev_id = 0,
+ .smd_int.out_bit_pos = 1 << 8,
+ .smd_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
+ .smd_int.out_offset = 0x8,
+
+ .smsm_int.irq_name = "adsp_smsm_in",
+ .smsm_int.flags = IRQF_TRIGGER_RISING,
+ .smsm_int.irq_id = -1,
+ .smsm_int.device_name = "smsm_dev",
+ .smsm_int.dev_id = 0,
+ .smsm_int.out_bit_pos = 1 << 9,
+ .smsm_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
+ .smsm_int.out_offset = 0x8,
+ },
+ {
+ .irq_config_id = SMD_RPM,
+ .subsys_name = NULL, /* do not use PIL to load RPM */
+ .edge = SMD_APPS_RPM,
+
+ .smd_int.irq_name = "rpm_smd_in",
+ .smd_int.flags = IRQF_TRIGGER_RISING,
+ .smd_int.irq_id = -1,
+ .smd_int.device_name = "smd_dev",
+ .smd_int.dev_id = 0,
+ .smd_int.out_bit_pos = 1 << 0,
+ .smd_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
+ .smd_int.out_offset = 0x8,
+
+ .smsm_int.irq_name = NULL, /* RPM does not support SMSM */
+ .smsm_int.flags = 0,
+ .smsm_int.irq_id = 0,
+ .smsm_int.device_name = NULL,
+ .smsm_int.dev_id = 0,
+ .smsm_int.out_bit_pos = 0,
+ .smsm_int.out_base = NULL,
+ .smsm_int.out_offset = 0,
+ },
+};
+
+static struct smd_smem_regions aux_smem_areas[] = {
+ {
+ .phys_addr = (void *)(0xfc428000),
+ .size = 0x4000,
+ },
+};
+
+static struct smd_subsystem_restart_config smd_ssr_cfg = {
+ .disable_smsm_reset_handshake = 1,
+};
+
+static struct smd_platform smd_platform_data = {
+ .num_ss_configs = ARRAY_SIZE(smd_config_list),
+ .smd_ss_configs = smd_config_list,
+ .smd_ssr_config = &smd_ssr_cfg,
+ .num_smem_areas = ARRAY_SIZE(aux_smem_areas),
+ .smd_smem_areas = aux_smem_areas,
+};
+
+struct platform_device msm_device_smd_9625 = {
+ .name = "msm_smd",
+ .id = -1,
+ .resource = smd_resource,
+ .num_resources = ARRAY_SIZE(smd_resource),
+ .dev = {
+ .platform_data = &smd_platform_data,
+ }
+};
+
+void __init msm9625_add_devices(void)
+{
+ platform_device_register(&msm_device_smd_9625);
+}
+
+/*
+ * Used to satisfy dependencies for devices that need to be
+ * run early or in a particular order. Most likely your device doesn't fall
+ * into this category, and thus the driver should not be added here.
+ * EPROBE_DEFER can satisfy most dependency problems.
+ */
+void __init msm9625_add_drivers(void)
+{
+ msm_init_modem_notifier_list();
+ msm_smd_init();
+ msm_rpm_driver_init();
+ rpm_regulator_smd_driver_init();
+}
void __init msm9625_init(void)
{
@@ -144,6 +296,8 @@
msm_clock_init(&msm_dummy_clock_init_data);
of_platform_populate(NULL, of_default_bus_match_table,
msm9625_auxdata_lookup, NULL);
+ msm9625_add_devices();
+ msm9625_add_drivers();
}
DT_MACHINE_START(MSM_DT, "Qualcomm MSM (Flattened Device Tree)")
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index 2cd2cd4..3a72be3 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -5216,9 +5216,7 @@
CLK_LOOKUP("pwm_clk", cxo_clk.c, "0-0048"),
CLK_LOOKUP("cxo", cxo_clk.c, "wcnss_wlan.0"),
CLK_LOOKUP("cxo", cxo_clk.c, "pil_riva"),
- CLK_LOOKUP("xo", pxo_clk.c, "pil_qdsp6v4.0"),
- CLK_LOOKUP("xo", cxo_clk.c, "pil_qdsp6v4.1"),
- CLK_LOOKUP("xo", cxo_clk.c, "pil_qdsp6v4.2"),
+ CLK_LOOKUP("xo", pxo_clk.c, "pil-q6v4-lpass"),
CLK_LOOKUP("xo", cxo_clk.c, "pil_gss"),
CLK_LOOKUP("xo", cxo_clk.c, "BAM_RMNT"),
CLK_LOOKUP("xo", cxo_clk.c, "msm_xo"),
@@ -5562,9 +5560,8 @@
CLK_LOOKUP("xo", pxo_a_clk.c, ""),
CLK_LOOKUP("cxo", cxo_clk.c, "wcnss_wlan.0"),
CLK_LOOKUP("cxo", cxo_clk.c, "pil_riva"),
- CLK_LOOKUP("xo", pxo_clk.c, "pil_qdsp6v4.0"),
- CLK_LOOKUP("xo", cxo_clk.c, "pil_qdsp6v4.1"),
- CLK_LOOKUP("xo", cxo_clk.c, "pil_qdsp6v4.2"),
+ CLK_LOOKUP("xo", pxo_clk.c, "pil-q6v4-lpass"),
+ CLK_LOOKUP("xo", cxo_clk.c, "pil-q6v4-modem"),
CLK_LOOKUP("xo", cxo_clk.c, "BAM_RMNT"),
CLK_LOOKUP("xo", cxo_clk.c, "msm_xo"),
CLK_LOOKUP("vref_buff", cxo_clk.c, "rpm-regulator"),
@@ -5915,9 +5912,8 @@
CLK_LOOKUP("xo", cxo_clk.c, "msm_xo"),
CLK_LOOKUP("cxo", cxo_clk.c, "wcnss_wlan.0"),
CLK_LOOKUP("cxo", cxo_clk.c, "pil_riva"),
- CLK_LOOKUP("xo", pxo_clk.c, "pil_qdsp6v4.0"),
- CLK_LOOKUP("xo", cxo_clk.c, "pil_qdsp6v4.1"),
- CLK_LOOKUP("xo", cxo_clk.c, "pil_qdsp6v4.2"),
+ CLK_LOOKUP("xo", pxo_clk.c, "pil-q6v4-lpass"),
+ CLK_LOOKUP("xo", cxo_clk.c, "pil-q6v4-modem"),
CLK_LOOKUP("xo", cxo_clk.c, "BAM_RMNT"),
CLK_LOOKUP("vref_buff", cxo_clk.c, "rpm-regulator"),
CLK_LOOKUP("pll2", pll2_clk.c, NULL),
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index e8baf6a..a49a145 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -101,6 +101,7 @@
#define PCIE20_SIZE SZ_4K
#define MSM8064_PC_CNTR_PHYS (APQ8064_IMEM_PHYS + 0x664)
#define MSM8064_PC_CNTR_SIZE 0x40
+#define MSM8064_RPM_MASTER_STATS_BASE 0x10BB00
static struct resource msm8064_resources_pccntr[] = {
{
@@ -2351,6 +2352,37 @@
},
};
+static struct resource resources_rpm_master_stats[] = {
+ {
+ .start = MSM8064_RPM_MASTER_STATS_BASE,
+ .end = MSM8064_RPM_MASTER_STATS_BASE + SZ_256,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static char *master_names[] = {
+ "KPSS",
+ "MPSS",
+ "LPASS",
+ "RIVA",
+ "DSPS",
+};
+
+static struct msm_rpm_master_stats_platform_data msm_rpm_master_stat_pdata = {
+ .masters = master_names,
+ .nomasters = ARRAY_SIZE(master_names),
+};
+
+struct platform_device apq8064_rpm_master_stat_device = {
+ .name = "msm_rpm_master_stat",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(resources_rpm_master_stats),
+ .resource = resources_rpm_master_stats,
+ .dev = {
+ .platform_data = &msm_rpm_master_stat_pdata,
+ },
+};
+
static struct msm_rpm_log_platform_data msm_rpm_log_pdata = {
.phys_addr_base = 0x0010C000,
.reg_offsets = {
@@ -2649,15 +2681,6 @@
.num_resources = ARRAY_SIZE(i2s_mdm_resources),
.resource = i2s_mdm_resources,
};
-static int apq8064_LPM_latency = 1000; /* >100 usec for WFI */
-
-struct platform_device apq8064_cpu_idle_device = {
- .name = "msm_cpu_idle",
- .id = -1,
- .dev = {
- .platform_data = &apq8064_LPM_latency,
- },
-};
static struct msm_dcvs_freq_entry apq8064_freq[] = {
{ 384000, 900, 0, 0, 0},
@@ -2670,11 +2693,14 @@
};
static struct msm_dcvs_core_info apq8064_core_info = {
- .freq_tbl = &apq8064_freq[0],
- .core_param = {
+ .freq_tbl = &apq8064_freq[0],
+ .num_cores = 4,
+ .sensors = (int[]){7, 8, 9, 10},
+ .thermal_poll_ms = 60000,
+ .core_param = {
.core_type = MSM_DCVS_CORE_TYPE_CPU,
},
- .algo_param = {
+ .algo_param = {
.disable_pc_threshold = 1458000,
.em_win_size_min_us = 100000,
.em_win_size_max_us = 300000,
@@ -2690,7 +2716,7 @@
.ss_win_size_max_us = 1000000,
.ss_util_pct = 95,
},
- .energy_coeffs = {
+ .energy_coeffs = {
.active_coeff_a = 336,
.active_coeff_b = 0,
.active_coeff_c = 0,
@@ -2700,17 +2726,24 @@
.leakage_coeff_c = 3329,
.leakage_coeff_d = -277,
},
- .power_param = {
+ .power_param = {
.current_temp = 25,
.num_freq = ARRAY_SIZE(apq8064_freq),
}
};
+#define APQ8064_LPM_LATENCY 1000 /* >100 usec for WFI */
+
+static struct msm_gov_platform_data gov_platform_data = {
+ .info = &apq8064_core_info,
+ .latency = APQ8064_LPM_LATENCY,
+};
+
struct platform_device apq8064_msm_gov_device = {
.name = "msm_dcvs_gov",
.id = -1,
.dev = {
- .platform_data = &apq8064_core_info,
+ .platform_data = &gov_platform_data,
},
};
diff --git a/arch/arm/mach-msm/devices-8930.c b/arch/arm/mach-msm/devices-8930.c
index d062ff4..30a99cd 100644
--- a/arch/arm/mach-msm/devices-8930.c
+++ b/arch/arm/mach-msm/devices-8930.c
@@ -38,6 +38,7 @@
#endif
#define MSM8930_PC_CNTR_PHYS (MSM8930_IMEM_PHYS + 0x664)
#define MSM8930_PC_CNTR_SIZE 0x40
+#define MSM8930_RPM_MASTER_STATS_BASE 0x10B100
static struct resource msm8930_resources_pccntr[] = {
{
@@ -558,6 +559,36 @@
},
};
+static struct resource resources_rpm_master_stats[] = {
+ {
+ .start = MSM8930_RPM_MASTER_STATS_BASE,
+ .end = MSM8930_RPM_MASTER_STATS_BASE + SZ_256,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static char *master_names[] = {
+ "KPSS",
+ "MPSS",
+ "LPASS",
+ "RIVA",
+};
+
+static struct msm_rpm_master_stats_platform_data msm_rpm_master_stat_pdata = {
+ .masters = master_names,
+ .nomasters = ARRAY_SIZE(master_names),
+};
+
+struct platform_device msm8930_rpm_master_stat_device = {
+ .name = "msm_rpm_master_stat",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(resources_rpm_master_stats),
+ .resource = resources_rpm_master_stats,
+ .dev = {
+ .platform_data = &msm_rpm_master_stat_pdata,
+ },
+};
+
static struct resource msm_rpm_rbcpr_resource = {
.start = 0x0010DB00,
.end = 0x0010DB00 + SZ_8K - 1,
@@ -583,16 +614,6 @@
.resource = &msm_rpm_rbcpr_resource,
};
-static int msm8930_LPM_latency = 1000; /* >100 usec for WFI */
-
-struct platform_device msm8930_cpu_idle_device = {
- .name = "msm_cpu_idle",
- .id = -1,
- .dev = {
- .platform_data = &msm8930_LPM_latency,
- },
-};
-
struct platform_device msm_bus_8930_sys_fabric = {
.name = "msm_bus_fabric",
.id = MSM_BUS_FAB_SYSTEM,
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index 72da3d8..db2c525 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -105,6 +105,7 @@
#define MSM8960_PC_CNTR_PHYS (MSM8960_IMEM_PHYS + 0x664)
#define MSM8960_PC_CNTR_SIZE 0x40
+#define MSM8960_RPM_MASTER_STATS_BASE 0x10BB00
static struct resource msm8960_resources_pccntr[] = {
{
@@ -1334,13 +1335,10 @@
},
};
-#define MSM_LPASS_QDSP6SS_PHYS 0x28800000
-#define SFAB_LPASS_Q6_ACLK_CTL (MSM_CLK_CTL_BASE + 0x23A0)
-
static struct resource msm_8960_q6_lpass_resources[] = {
{
- .start = MSM_LPASS_QDSP6SS_PHYS,
- .end = MSM_LPASS_QDSP6SS_PHYS + SZ_256 - 1,
+ .start = 0x28800000,
+ .end = 0x28800000 + SZ_256 - 1,
.flags = IORESOURCE_MEM,
},
};
@@ -1349,93 +1347,69 @@
.strap_tcm_base = 0x01460000,
.strap_ahb_upper = 0x00290000,
.strap_ahb_lower = 0x00000280,
- .aclk_reg = SFAB_LPASS_Q6_ACLK_CTL,
+ .aclk_reg = MSM_CLK_CTL_BASE + 0x23A0,
.name = "q6",
.pas_id = PAS_Q6,
.bus_port = MSM_BUS_MASTER_LPASS_PROC,
};
struct platform_device msm_8960_q6_lpass = {
- .name = "pil_qdsp6v4",
- .id = 0,
+ .name = "pil-q6v4-lpass",
+ .id = -1,
.num_resources = ARRAY_SIZE(msm_8960_q6_lpass_resources),
.resource = msm_8960_q6_lpass_resources,
.dev.platform_data = &msm_8960_q6_lpass_data,
};
-#define MSM_MSS_ENABLE_PHYS 0x08B00000
-#define MSM_FW_QDSP6SS_PHYS 0x08800000
-#define MSS_Q6FW_JTAG_CLK_CTL (MSM_CLK_CTL_BASE + 0x2C6C)
-#define SFAB_MSS_Q6_FW_ACLK_CTL (MSM_CLK_CTL_BASE + 0x2044)
-
-static struct resource msm_8960_q6_mss_fw_resources[] = {
+static struct resource msm_8960_q6_mss_resources[] = {
{
- .start = MSM_FW_QDSP6SS_PHYS,
- .end = MSM_FW_QDSP6SS_PHYS + SZ_256 - 1,
+ .start = 0x08800000,
+ .end = 0x08800000 + SZ_256 - 1,
.flags = IORESOURCE_MEM,
},
{
- .start = MSM_MSS_ENABLE_PHYS,
- .end = MSM_MSS_ENABLE_PHYS + 4 - 1,
+ .start = 0x08B00000,
+ .end = 0x08B00000 + SZ_256 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = 0x08900000,
+ .end = 0x08900000 + SZ_256 - 1,
.flags = IORESOURCE_MEM,
},
};
-static struct pil_q6v4_pdata msm_8960_q6_mss_fw_data = {
- .strap_tcm_base = 0x00400000,
- .strap_ahb_upper = 0x00090000,
- .strap_ahb_lower = 0x00000080,
- .aclk_reg = SFAB_MSS_Q6_FW_ACLK_CTL,
- .jtag_clk_reg = MSS_Q6FW_JTAG_CLK_CTL,
- .name = "modem_fw",
- .depends = "q6",
- .pas_id = PAS_MODEM_FW,
- .bus_port = MSM_BUS_MASTER_MSS_FW_PROC,
-};
-
-struct platform_device msm_8960_q6_mss_fw = {
- .name = "pil_qdsp6v4",
- .id = 1,
- .num_resources = ARRAY_SIZE(msm_8960_q6_mss_fw_resources),
- .resource = msm_8960_q6_mss_fw_resources,
- .dev.platform_data = &msm_8960_q6_mss_fw_data,
-};
-
-#define MSM_SW_QDSP6SS_PHYS 0x08900000
-#define SFAB_MSS_Q6_SW_ACLK_CTL (MSM_CLK_CTL_BASE + 0x2040)
-#define MSS_Q6SW_JTAG_CLK_CTL (MSM_CLK_CTL_BASE + 0x2C68)
-
-static struct resource msm_8960_q6_mss_sw_resources[] = {
+static struct pil_q6v4_pdata msm_8960_q6_mss_data[2] = {
{
- .start = MSM_SW_QDSP6SS_PHYS,
- .end = MSM_SW_QDSP6SS_PHYS + SZ_256 - 1,
- .flags = IORESOURCE_MEM,
+ .strap_tcm_base = 0x00400000,
+ .strap_ahb_upper = 0x00090000,
+ .strap_ahb_lower = 0x00000080,
+ .aclk_reg = MSM_CLK_CTL_BASE + 0x2C6C,
+ .jtag_clk_reg = MSM_CLK_CTL_BASE + 0x2044,
+ .name = "modem_fw",
+ .depends = "q6",
+ .pas_id = PAS_MODEM_FW,
+ .bus_port = MSM_BUS_MASTER_MSS_FW_PROC,
},
{
- .start = MSM_MSS_ENABLE_PHYS,
- .end = MSM_MSS_ENABLE_PHYS + 4 - 1,
- .flags = IORESOURCE_MEM,
- },
+ .strap_tcm_base = 0x00420000,
+ .strap_ahb_upper = 0x00090000,
+ .strap_ahb_lower = 0x00000080,
+ .aclk_reg = MSM_CLK_CTL_BASE + 0x2040,
+ .jtag_clk_reg = MSM_CLK_CTL_BASE + 0x2C68,
+ .name = "modem",
+ .depends = "modem_fw",
+ .pas_id = PAS_MODEM_SW,
+ .bus_port = MSM_BUS_MASTER_MSS_SW_PROC,
+ }
};
-static struct pil_q6v4_pdata msm_8960_q6_mss_sw_data = {
- .strap_tcm_base = 0x00420000,
- .strap_ahb_upper = 0x00090000,
- .strap_ahb_lower = 0x00000080,
- .aclk_reg = SFAB_MSS_Q6_SW_ACLK_CTL,
- .jtag_clk_reg = MSS_Q6SW_JTAG_CLK_CTL,
- .name = "modem",
- .depends = "modem_fw",
- .pas_id = PAS_MODEM_SW,
- .bus_port = MSM_BUS_MASTER_MSS_SW_PROC,
-};
-
-struct platform_device msm_8960_q6_mss_sw = {
- .name = "pil_qdsp6v4",
- .id = 2,
- .num_resources = ARRAY_SIZE(msm_8960_q6_mss_sw_resources),
- .resource = msm_8960_q6_mss_sw_resources,
- .dev.platform_data = &msm_8960_q6_mss_sw_data,
+struct platform_device msm_8960_q6_mss = {
+ .name = "pil-q6v4-modem",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(msm_8960_q6_mss_resources),
+ .resource = msm_8960_q6_mss_resources,
+ .dev.platform_data = msm_8960_q6_mss_data,
};
static struct resource msm_8960_riva_resources[] = {
@@ -3747,6 +3721,37 @@
},
};
+static struct resource resources_rpm_master_stats[] = {
+ {
+ .start = MSM8960_RPM_MASTER_STATS_BASE,
+ .end = MSM8960_RPM_MASTER_STATS_BASE + SZ_256,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static char *master_names[] = {
+ "KPSS",
+ "GPSS",
+ "LPASS",
+ "RIVA",
+ "DSPS",
+};
+
+static struct msm_rpm_master_stats_platform_data msm_rpm_master_stat_pdata = {
+ .masters = master_names,
+ .nomasters = ARRAY_SIZE(master_names),
+};
+
+struct platform_device msm8960_rpm_master_stat_device = {
+ .name = "msm_rpm_master_stat",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(resources_rpm_master_stats),
+ .resource = resources_rpm_master_stats,
+ .dev = {
+ .platform_data = &msm_rpm_master_stat_pdata,
+ },
+};
+
struct platform_device msm_bus_sys_fabric = {
.name = "msm_bus_fabric",
.id = MSM_BUS_FAB_SYSTEM,
@@ -4071,16 +4076,6 @@
.resource = msm_ebi1_ch1_erp_resources,
};
-static int msm8960_LPM_latency = 1000; /* >100 usec for WFI */
-
-struct platform_device msm8960_cpu_idle_device = {
- .name = "msm_cpu_idle",
- .id = -1,
- .dev = {
- .platform_data = &msm8960_LPM_latency,
- },
-};
-
static struct resource msm_cache_erp_resources[] = {
{
.name = "l1_irq",
diff --git a/arch/arm/mach-msm/devices-9615.c b/arch/arm/mach-msm/devices-9615.c
index 46853ac..6a43206 100644
--- a/arch/arm/mach-msm/devices-9615.c
+++ b/arch/arm/mach-msm/devices-9615.c
@@ -64,6 +64,7 @@
#define MSM_GPIO_I2C_CLK 16
#define MSM_GPIO_I2C_SDA 17
+#define MSM9615_RPM_MASTER_STATS_BASE 0x10A700
static struct msm_watchdog_pdata msm_watchdog_pdata = {
.pet_time = 10000,
@@ -1328,6 +1329,35 @@
},
};
+static struct resource resources_rpm_master_stats[] = {
+ {
+ .start = MSM9615_RPM_MASTER_STATS_BASE,
+ .end = MSM9615_RPM_MASTER_STATS_BASE + SZ_256,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static char *master_names[] = {
+ "KPSS",
+ "MPSS",
+ "LPASS",
+};
+
+static struct msm_rpm_master_stats_platform_data msm_rpm_master_stat_pdata = {
+ .masters = master_names,
+ .nomasters = ARRAY_SIZE(master_names),
+};
+
+struct platform_device msm9615_rpm_master_stat_device = {
+ .name = "msm_rpm_master_stat",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(resources_rpm_master_stats),
+ .resource = resources_rpm_master_stats,
+ .dev = {
+ .platform_data = &msm_rpm_master_stat_pdata,
+ },
+};
+
static struct msm_rpm_log_platform_data msm_rpm_log_pdata = {
.phys_addr_base = 0x0010AC00,
.reg_offsets = {
diff --git a/arch/arm/mach-msm/devices-msm7x2xa.h b/arch/arm/mach-msm/devices-msm7x2xa.h
index 8b59b14..614037c 100644
--- a/arch/arm/mach-msm/devices-msm7x2xa.h
+++ b/arch/arm/mach-msm/devices-msm7x2xa.h
@@ -33,6 +33,6 @@
void __init msm8x25_spm_device_init(void);
void __init msm_pm_register_cpr_ops(void);
void __init msm8x25_kgsl_3d0_init(void);
-void __iomem *core1_reset_base(void);
+void __iomem *core_reset_base(unsigned int);
extern void setup_mm_for_reboot(void);
#endif
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index 6f3dda3..84812b6 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -251,8 +251,7 @@
extern struct platform_device msm_pil_dsps;
extern struct platform_device msm_pil_vidc;
extern struct platform_device msm_8960_q6_lpass;
-extern struct platform_device msm_8960_q6_mss_fw;
-extern struct platform_device msm_8960_q6_mss_sw;
+extern struct platform_device msm_8960_q6_mss;
extern struct platform_device msm_8960_riva;
extern struct platform_device msm_gss;
@@ -335,10 +334,12 @@
extern struct platform_device msm8960_rpm_device;
extern struct platform_device msm8960_rpm_stat_device;
+extern struct platform_device msm8960_rpm_master_stat_device;
extern struct platform_device msm8960_rpm_log_device;
extern struct platform_device msm8930_rpm_device;
extern struct platform_device msm8930_rpm_stat_device;
+extern struct platform_device msm8930_rpm_master_stat_device;
extern struct platform_device msm8930_rpm_log_device;
extern struct platform_device msm8930_rpm_rbcpr_device;
@@ -348,10 +349,12 @@
extern struct platform_device msm9615_rpm_device;
extern struct platform_device msm9615_rpm_stat_device;
+extern struct platform_device msm9615_rpm_master_stat_device;
extern struct platform_device msm9615_rpm_log_device;
extern struct platform_device apq8064_rpm_device;
extern struct platform_device apq8064_rpm_stat_device;
+extern struct platform_device apq8064_rpm_master_stat_device;
extern struct platform_device apq8064_rpm_log_device;
extern struct platform_device msm_device_rng;
@@ -394,10 +397,6 @@
extern struct platform_device *msm_8974_stub_regulator_devices[];
extern int msm_8974_stub_regulator_devices_len;
-extern struct platform_device msm8960_cpu_idle_device;
-extern struct platform_device msm8930_cpu_idle_device;
-extern struct platform_device apq8064_cpu_idle_device;
-
extern struct platform_device apq8064_msm_gov_device;
extern struct platform_device msm_bus_8930_apps_fabric;
diff --git a/arch/arm/mach-msm/idle-v7.S b/arch/arm/mach-msm/idle-v7.S
index 8eed48d..1d8f313 100644
--- a/arch/arm/mach-msm/idle-v7.S
+++ b/arch/arm/mach-msm/idle-v7.S
@@ -330,9 +330,14 @@
ldr pc, [r1] /* jump */
ENTRY(msm_pm_set_l2_flush_flag)
- ldr r1, =msm_pm_flush_l2_flag
- str r0, [r1]
- bx lr
+ ldr r1, =msm_pm_flush_l2_flag
+ str r0, [r1]
+ bx lr
+
+ENTRY(msm_pm_get_l2_flush_flag)
+ ldr r1, =msm_pm_flush_l2_flag
+ ldr r0, [r1]
+ bx lr
.data
diff --git a/arch/arm/mach-msm/idle.h b/arch/arm/mach-msm/idle.h
index 4abdd04..7a939ab 100644
--- a/arch/arm/mach-msm/idle.h
+++ b/arch/arm/mach-msm/idle.h
@@ -38,6 +38,7 @@
#ifdef CONFIG_CPU_V7
void msm_pm_boot_entry(void);
void msm_pm_set_l2_flush_flag(unsigned int flag);
+int msm_pm_get_l2_flush_flag(void);
extern unsigned long msm_pm_pc_pgd;
extern unsigned long msm_pm_boot_vector[NR_CPUS];
extern uint32_t target_type;
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index 433fee3..0b53bad 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -586,6 +586,8 @@
void msm_map_msm8226_io(void);
void msm8226_init_irq(void);
void msm8226_init_gpiomux(void);
+void msm_map_msm8910_io(void);
+void msm8910_init_irq(void);
struct mmc_platform_data;
int msm_add_sdcc(unsigned int controller,
diff --git a/arch/arm/mach-msm/include/mach/iommu.h b/arch/arm/mach-msm/include/mach/iommu.h
index f63af64..41a59af6 100644
--- a/arch/arm/mach-msm/include/mach/iommu.h
+++ b/arch/arm/mach-msm/include/mach/iommu.h
@@ -88,7 +88,6 @@
* @aclk: Alternate clock for this IOMMU core, if any
* @name: Human-readable name of this IOMMU device
* @gdsc: Regulator needed to power this HW block (v2 only)
- * @nsmr: Size of the SMT on this HW block (v2 only)
* @bfb_settings: Optional BFB performance tuning parameters
*
* A msm_iommu_drvdata holds the global driver data about a single piece
@@ -103,7 +102,6 @@
struct clk *aclk;
const char *name;
struct regulator *gdsc;
- unsigned int nsmr;
struct msm_iommu_bfb_settings *bfb_settings;
};
diff --git a/arch/arm/mach-msm/include/mach/irqs-8910.h b/arch/arm/mach-msm/include/mach/irqs-8910.h
new file mode 100644
index 0000000..22fdc16
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/irqs-8910.h
@@ -0,0 +1,40 @@
+/* Copyright (c) 2012, 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 __ASM_ARCH_MSM_IRQS_8910_H
+#define __ASM_ARCH_MSM_IRQS_8910_H
+
+/* MSM ACPU Interrupt Numbers */
+
+/*
+ * 0-15: STI/SGI (software triggered/generated interrupts)
+ * 16-31: PPI (private peripheral interrupts)
+ * 32+: SPI (shared peripheral interrupts)
+ */
+
+#define GIC_PPI_START 16
+#define GIC_SPI_START 32
+
+#define INT_ARMQC_PERFMON (GIC_PPI_START + 10)
+
+#define APCC_QGICL2PERFMONIRPTREQ (GIC_SPI_START + 1)
+#define SC_SICL2PERFMONIRPTREQ APCC_QGICL2PERFMONIRPTREQ
+#define TLMM_MSM_SUMMARY_IRQ (GIC_SPI_START + 208)
+
+#define NR_MSM_IRQS 256
+#define NR_GPIO_IRQS 146
+#define NR_QPNP_IRQS 32768 /* SPARSE_IRQ is required to support this */
+#define NR_BOARD_IRQS NR_QPNP_IRQS
+#define NR_TLMM_MSM_DIR_CONN_IRQ 8
+#define NR_MSM_GPIOS NR_GPIO_IRQS
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/irqs.h b/arch/arm/mach-msm/include/mach/irqs.h
index f562c40..7aff770 100644
--- a/arch/arm/mach-msm/include/mach/irqs.h
+++ b/arch/arm/mach-msm/include/mach/irqs.h
@@ -60,6 +60,8 @@
#if defined(CONFIG_ARCH_MSM8974)
#include "irqs-8974.h"
+#elif defined(CONFIG_ARCH_MSM8910)
+#include "irqs-8910.h"
#elif defined(CONFIG_ARCH_MPQ8092)
#include "irqs-8092.h"
#elif defined(CONFIG_ARCH_MSM9615)
diff --git a/arch/arm/mach-msm/include/mach/msm_dcvs.h b/arch/arm/mach-msm/include/mach/msm_dcvs.h
index 490a34b..e81cee4 100644
--- a/arch/arm/mach-msm/include/mach/msm_dcvs.h
+++ b/arch/arm/mach-msm/include/mach/msm_dcvs.h
@@ -19,6 +19,10 @@
#define CORES_MAX (10)
#define CPU_OFFSET 1 /* used to notify TZ the core number */
+#define GPU_OFFSET (CORES_MAX * 2/3) /* there will be more cpus than gpus,
+ * let the GPU be assigned fewer core
+ * elements and start later
+ */
enum msm_core_idle_state {
MSM_DCVS_IDLE_ENTER,
@@ -32,43 +36,14 @@
MSM_DCVS_DISABLE_HIGH_LATENCY_MODES,
};
-/**
- * struct msm_dcvs_idle
- *
- * API for idle code to register and send idle enter/exit
- * notifications to msm_dcvs driver.
- */
-struct msm_dcvs_idle {
- const char *core_name;
- /* Enable/Disable idle state/notifications */
- int (*enable)(struct msm_dcvs_idle *self,
- enum msm_core_control_event event);
+struct msm_gov_platform_data {
+ struct msm_dcvs_core_info *info;
+ int latency;
};
/**
- * msm_dcvs_idle_source_register
- * @drv: Pointer to the source driver
- * @return: Handle to be used for sending idle state notifications.
- *
- * Register the idle driver with the msm_dcvs driver to send idle
- * state notifications for the core.
- */
-extern int msm_dcvs_idle_source_register(struct msm_dcvs_idle *drv);
-
-/**
- * msm_dcvs_idle_source_unregister
- * @drv: Pointer to the source driver
- * @return:
- * 0 on success
- * -EINVAL
- *
- * Description: Unregister the idle driver with the msm_dcvs driver
- */
-extern int msm_dcvs_idle_source_unregister(struct msm_dcvs_idle *drv);
-
-/**
* msm_dcvs_idle
- * @handle: Handle provided back at registration
+ * @dcvs_core_id: The id returned by msm_dcvs_register_core
* @state: The enter/exit idle state the core is in
* @iowaited: iowait in us
* on iMSM_DCVS_IDLE_EXIT.
@@ -80,7 +55,7 @@
*
* Send idle state notifications to the msm_dcvs driver
*/
-int msm_dcvs_idle(int handle, enum msm_core_idle_state state,
+int msm_dcvs_idle(int dcvs_core_id, enum msm_core_idle_state state,
uint32_t iowaited);
/**
@@ -90,6 +65,9 @@
* before the sink driver can be registered.
*/
struct msm_dcvs_core_info {
+ int num_cores;
+ int *sensors;
+ int thermal_poll_ms;
struct msm_dcvs_freq_entry *freq_tbl;
struct msm_dcvs_core_param core_param;
struct msm_dcvs_algo_param algo_param;
@@ -99,8 +77,10 @@
/**
* msm_dcvs_register_core
- * @core_name: Unique name identifier for the core.
+ * @type: whether this is a CPU or a GPU
+ * @type_core_num: The number of the core for a type
* @info: The core specific algorithm parameters.
+ * @sensor: The thermal sensor number of the core in question
* @return :
* 0 on success,
* -ENOSYS,
@@ -110,35 +90,28 @@
* msm_dcvs_freq_sink_register
* Cores that need to run synchronously must share the same group id.
*/
-extern int msm_dcvs_register_core(const char *core_name,
- struct msm_dcvs_core_info *info);
+extern int msm_dcvs_register_core(
+ enum msm_dcvs_core_type type,
+ int type_core_num,
+ struct msm_dcvs_core_info *info,
+ int (*set_frequency)(int type_core_num, unsigned int freq),
+ unsigned int (*get_frequency)(int type_core_num),
+ int (*idle_enable)(int type_core_num,
+ enum msm_core_control_event event),
+ int sensor);
/**
- * struct msm_dcvs_freq
- *
- * API for clock driver code to register and receive frequency change
- * request for the core from the msm_dcvs driver.
- */
-struct msm_dcvs_freq {
- const char *core_name;
- /* Callback from msm_dcvs to set the core frequency */
- int (*set_frequency)(struct msm_dcvs_freq *self,
- unsigned int freq);
- unsigned int (*get_frequency)(struct msm_dcvs_freq *self);
-};
-
-/**
- * msm_dcvs_freq_sink_register
+ * msm_dcvs_freq_sink_start
* @drv: The sink driver
* @return: Handle unique to the core.
*
* Register the clock driver code with the msm_dvs driver to get notified about
* frequency change requests.
*/
-extern int msm_dcvs_freq_sink_register(struct msm_dcvs_freq *drv);
+extern int msm_dcvs_freq_sink_start(int dcvs_core_id);
/**
- * msm_dcvs_freq_sink_unregister
+ * msm_dcvs_freq_sink_stop
* @drv: The sink driver
* @return:
* 0 on success,
@@ -147,6 +120,13 @@
* Unregister the sink driver for the core. This will cause the source driver
* for the core to stop sending idle pulses.
*/
-extern int msm_dcvs_freq_sink_unregister(struct msm_dcvs_freq *drv);
+extern int msm_dcvs_freq_sink_stop(int dcvs_core_id);
+/**
+ * msm_dcvs_update_limits
+ * @drv: The sink driver
+ *
+ * Update the frequency known to dcvs when the limits are changed.
+ */
+extern void msm_dcvs_update_limits(int dcvs_core_id);
#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-8910.h b/arch/arm/mach-msm/include/mach/msm_iomap-8910.h
new file mode 100644
index 0000000..e4cd312
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-8910.h
@@ -0,0 +1,41 @@
+/* Copyright (c) 2012, 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
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __ASM_ARCH_MSM_IOMAP_8910_H
+#define __ASM_ARCH_MSM_IOMAP_8910_H
+
+/* Physical base address and size of peripherals.
+ * Ordered by the virtual base addresses they will be mapped at.
+ *
+ * If you add or remove entries here, you'll want to edit the
+ * io desc array in arch/arm/mach-msm/io.c to reflect your
+ * changes.
+ *
+ */
+
+#define MSM8910_MSM_SHARED_RAM_PHYS 0x0FA00000
+
+#define MSM8910_APCS_GCC_PHYS 0xF9011000
+#define MSM8910_APCS_GCC_SIZE SZ_4K
+
+#define MSM8910_TLMM_PHYS 0xFD510000
+#define MSM8910_TLMM_SIZE SZ_16K
+
+#define MSM8910_IMEM_PHYS 0xFC42B000
+#define MSM8910_IMEM_SIZE SZ_4K
+
+#ifdef CONFIG_DEBUG_MSM8910_UART
+#define MSM_DEBUG_UART_BASE IOMEM(0xFA71E000)
+#define MSM_DEBUG_UART_PHYS 0xF991E000
+#endif
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap.h b/arch/arm/mach-msm/include/mach/msm_iomap.h
index 8dbd29c..f372b1e 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap.h
@@ -54,7 +54,7 @@
defined(CONFIG_ARCH_MSM7X25) || defined(CONFIG_ARCH_MSM7X01A) || \
defined(CONFIG_ARCH_MSM8625) || defined(CONFIG_ARCH_MSM7X30) || \
defined(CONFIG_ARCH_MSM9625) || defined(CONFIG_ARCH_MPQ8092) || \
- defined(CONFIG_ARCH_MSM8226)
+ defined(CONFIG_ARCH_MSM8226) || defined(CONFIG_ARCH_MSM8910)
/* Unified iomap */
@@ -122,6 +122,7 @@
#include "msm_iomap-9625.h"
#include "msm_iomap-8092.h"
#include "msm_iomap-8226.h"
+#include "msm_iomap-8910.h"
#else
/* Legacy single-target iomap */
diff --git a/arch/arm/mach-msm/include/mach/qdsp5v2/codec_utils.h b/arch/arm/mach-msm/include/mach/qdsp5v2/codec_utils.h
index 92dfe12..2cfdabf 100644
--- a/arch/arm/mach-msm/include/mach/qdsp5v2/codec_utils.h
+++ b/arch/arm/mach-msm/include/mach/qdsp5v2/codec_utils.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010, 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010, 2012, 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
@@ -123,7 +123,8 @@
uint64_t bytecount_given;
uint64_t bytecount_query;
- struct list_head pmem_region_queue; /* protected by lock */
+ struct list_head ion_region_queue; /* protected by lock */
+ struct ion_client *client;
int eq_enable;
int eq_needs_commit;
diff --git a/arch/arm/mach-msm/include/mach/qdsp6v2/apr_us.h b/arch/arm/mach-msm/include/mach/qdsp6v2/apr_us.h
index 487e814..da639ce 100644
--- a/arch/arm/mach-msm/include/mach/qdsp6v2/apr_us.h
+++ b/arch/arm/mach-msm/include/mach/qdsp6v2/apr_us.h
@@ -78,7 +78,7 @@
} __packed;
/* Max number of static located transparent data (bytes) */
-#define USM_MAX_CFG_DATA_SIZE 20
+#define USM_MAX_CFG_DATA_SIZE 100
struct usm_encode_cfg_blk {
u32 frames_per_buf;
u32 format_id;
diff --git a/arch/arm/mach-msm/include/mach/socinfo.h b/arch/arm/mach-msm/include/mach/socinfo.h
index 225440c..86045b9 100644
--- a/arch/arm/mach-msm/include/mach/socinfo.h
+++ b/arch/arm/mach-msm/include/mach/socinfo.h
@@ -54,6 +54,12 @@
of_machine_is_compatible("qcom,msm8226")
#define machine_is_msm8226_sim() \
of_machine_is_compatible("qcom,msm8226-sim")
+#define early_machine_is_msm8910() \
+ of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,msm8910")
+#define machine_is_msm8910() \
+ of_machine_is_compatible("qcom,msm8910")
+#define machine_is_msm8910_sim() \
+ of_machine_is_compatible("qcom,msm8910-sim")
#else
#define early_machine_is_msm8974() 0
#define machine_is_msm8974() 0
@@ -66,6 +72,9 @@
#define early_machine_is_msm8226() 0
#define machine_is_msm8226() 0
#define machine_is_msm8226_sim() 0
+#define early_machine_is_msm8910() 0
+#define machine_is_msm8910() 0
+#define machine_is_msm8910_sim() 0
#endif
@@ -99,7 +108,8 @@
MSM_CPU_8625,
MSM_CPU_9625,
MSM_CPU_8092,
- MSM_CPU_8226
+ MSM_CPU_8226,
+ MSM_CPU_8910,
};
enum pmic_model {
@@ -415,4 +425,15 @@
#endif
}
+static inline int cpu_is_msm8910(void)
+{
+#ifdef CONFIG_ARCH_MSM8910
+ enum msm_cpu cpu = socinfo_get_msm_cpu();
+
+ BUG_ON(cpu == MSM_CPU_UNKNOWN);
+ return cpu == MSM_CPU_8910;
+#else
+ return 0;
+#endif
+}
#endif
diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c
index 39ac253..8ebead8 100644
--- a/arch/arm/mach-msm/io.c
+++ b/arch/arm/mach-msm/io.c
@@ -529,3 +529,22 @@
msm_map_io(msm_8226_io_desc, ARRAY_SIZE(msm_8226_io_desc));
}
#endif /* CONFIG_ARCH_MSM8226 */
+
+#ifdef CONFIG_ARCH_MSM8910
+static struct map_desc msm8910_io_desc[] __initdata = {
+ MSM_CHIP_DEVICE(APCS_GCC, MSM8910),
+ MSM_CHIP_DEVICE(TLMM, MSM8910),
+ MSM_CHIP_DEVICE(IMEM, MSM8910),
+ {
+ .virtual = (unsigned long) MSM_SHARED_RAM_BASE,
+ .length = MSM_SHARED_RAM_SIZE,
+ .type = MT_DEVICE,
+ },
+};
+
+void __init msm_map_msm8910_io(void)
+{
+ msm_shared_ram_phys = MSM8910_MSM_SHARED_RAM_PHYS;
+ msm_map_io(msm8910_io_desc, ARRAY_SIZE(msm8910_io_desc));
+}
+#endif /* CONFIG_ARCH_MSM8910 */
diff --git a/arch/arm/mach-msm/lpm_resources.c b/arch/arm/mach-msm/lpm_resources.c
index 48d31f3..364f297 100644
--- a/arch/arm/mach-msm/lpm_resources.c
+++ b/arch/arm/mach-msm/lpm_resources.c
@@ -104,6 +104,11 @@
struct msm_rpm_request *handle;
};
+enum {
+ MSM_LPM_RPM_RS_TYPE = 0,
+ MSM_LPM_LOCAL_RS_TYPE = 1,
+};
+
struct msm_lpm_resource {
struct msm_lpm_rs_data rs_data;
uint32_t sleep_value;
@@ -126,7 +131,7 @@
.aggregate = msm_lpm_aggregate_l2,
.flush = msm_lpm_flush_l2,
.notify = NULL,
- .valid = true,
+ .valid = false,
.rs_data = {
.value = MSM_LPM_L2_CACHE_ACTIVE,
.default_value = MSM_LPM_L2_CACHE_ACTIVE,
@@ -787,6 +792,7 @@
struct msm_lpm_resource *rs = NULL;
const char *val;
int i;
+ uint32_t resource_type;
key = "qcom,name";
ret = of_property_read_string(node, key, &val);
@@ -810,49 +816,73 @@
continue;
}
- key = "qcom,type";
- ret = of_property_read_u32(node, key, &rs->rs_data.type);
+ key = "qcom,resource-type";
+ ret = of_property_read_u32(node, key, &resource_type);
if (ret) {
- pr_err("Failed to read type\n");
+ pr_err("Failed to read resource-type\n");
goto fail;
}
- key = "qcom,id";
- ret = of_property_read_u32(node, key, &rs->rs_data.id);
- if (ret) {
- pr_err("Failed to read id\n");
+ switch (resource_type) {
+ case MSM_LPM_RPM_RS_TYPE:
+ key = "qcom,type";
+ ret = of_property_read_u32(node, key,
+ &rs->rs_data.type);
+ if (ret) {
+ pr_err("Failed to read type\n");
+ goto fail;
+ }
+
+ key = "qcom,id";
+ ret = of_property_read_u32(node, key, &rs->rs_data.id);
+ if (ret) {
+ pr_err("Failed to read id\n");
+ goto fail;
+ }
+
+ key = "qcom,key";
+ ret = of_property_read_u32(node, key, &rs->rs_data.key);
+ if (ret) {
+ pr_err("Failed to read key\n");
+ goto fail;
+ }
+
+ rs->rs_data.handle = msm_lpm_create_rpm_request(
+ rs->rs_data.type,
+ rs->rs_data.id);
+
+ if (!rs->rs_data.handle) {
+ pr_err("%s: Failed to allocate handle for %s\n",
+ __func__, rs->name);
+ ret = -1;
+ goto fail;
+ }
+ /* fall through */
+
+ case MSM_LPM_LOCAL_RS_TYPE:
+ rs->valid = true;
+ break;
+ default:
+ pr_err("%s: Invalid resource type %d", __func__,
+ resource_type);
goto fail;
}
-
- key = "qcom,key";
- ret = of_property_read_u32(node, key, &rs->rs_data.key);
- if (ret) {
- pr_err("Failed to read key\n");
- goto fail;
- }
-
- rs->rs_data.handle = msm_lpm_create_rpm_request(
- rs->rs_data.type, rs->rs_data.id);
-
- if (!rs->rs_data.handle) {
- pr_err("%s: Failed to allocate handle for %s\n",
- __func__, rs->name);
- ret = -1;
- goto fail;
- }
-
- rs->valid = true;
}
msm_rpm_register_notifier(&msm_lpm_rpm_nblk);
msm_lpm_init_rpm_ctl();
- register_hotcpu_notifier(&msm_lpm_cpu_nblk);
- /* For UP mode, set the default to HSFS OPEN*/
- if (num_possible_cpus() == 1) {
- msm_lpm_l2.rs_data.default_value = MSM_LPM_L2_CACHE_HSFS_OPEN;
- msm_lpm_l2.rs_data.value = MSM_LPM_L2_CACHE_HSFS_OPEN;
- }
- msm_pm_set_l2_flush_flag(0);
- return 0;
+
+ if (msm_lpm_l2.valid) {
+ register_hotcpu_notifier(&msm_lpm_cpu_nblk);
+ /* For UP mode, set the default to HSFS OPEN*/
+ if (num_possible_cpus() == 1) {
+ msm_lpm_l2.rs_data.default_value =
+ MSM_LPM_L2_CACHE_HSFS_OPEN;
+ msm_lpm_l2.rs_data.value = MSM_LPM_L2_CACHE_HSFS_OPEN;
+ }
+ msm_pm_set_l2_flush_flag(0);
+ } else
+ msm_pm_set_l2_flush_flag(1);
+
fail:
return ret;
}
diff --git a/arch/arm/mach-msm/msm-krait-l2-accessors.c b/arch/arm/mach-msm/msm-krait-l2-accessors.c
index 3da155a..2c66ea0 100644
--- a/arch/arm/mach-msm/msm-krait-l2-accessors.c
+++ b/arch/arm/mach-msm/msm-krait-l2-accessors.c
@@ -18,75 +18,12 @@
DEFINE_RAW_SPINLOCK(l2_access_lock);
-#define L2CPMR 0x500
-#define L2CPUCPMR 0x501
-#define L2CPUVRF8 0x708
-#define CPUNDX_MASK (0x7 << 12)
-
-/*
- * For Krait versions found in APQ8064v1.x, save L2CPUVRF8 before
- * L2CPMR or L2CPUCPMR writes and restore it after to work around an
- * issue where L2CPUVRF8 becomes corrupt.
- */
-static bool l2cpuvrf8_needs_fix(u32 reg_addr)
-{
- switch (read_cpuid_id()) {
- case 0x510F06F0: /* KR28M4A10 */
- case 0x510F06F1: /* KR28M4A10B */
- case 0x510F06F2: /* KR28M4A11 */
- break;
- default:
- return false;
- };
-
- switch (reg_addr & ~CPUNDX_MASK) {
- case L2CPMR:
- case L2CPUCPMR:
- return true;
- default:
- return false;
- }
-}
-
-static u32 l2cpuvrf8_fix_save(u32 reg_addr, u32 *l2cpuvrf8_val)
-{
- u32 l2cpuvrf8_addr = L2CPUVRF8 | (reg_addr & CPUNDX_MASK);
-
- mb();
- asm volatile ("mcr p15, 3, %[l2cpselr], c15, c0, 6\n\t"
- "isb\n\t"
- "mrc p15, 3, %[l2cpdr], c15, c0, 7\n\t"
- : [l2cpdr]"=r" (*l2cpuvrf8_val)
- : [l2cpselr]"r" (l2cpuvrf8_addr)
- );
-
- return l2cpuvrf8_addr;
-}
-
-static void l2cpuvrf8_fix_restore(u32 l2cpuvrf8_addr, u32 l2cpuvrf8_val)
-{
- mb();
- asm volatile ("mcr p15, 3, %[l2cpselr], c15, c0, 6\n\t"
- "isb\n\t"
- "mcr p15, 3, %[l2cpdr], c15, c0, 7\n\t"
- "isb\n\t"
- :
- : [l2cpselr]"r" (l2cpuvrf8_addr),
- [l2cpdr]"r" (l2cpuvrf8_val)
- );
-}
-
u32 set_get_l2_indirect_reg(u32 reg_addr, u32 val)
{
unsigned long flags;
- u32 uninitialized_var(l2cpuvrf8_val), l2cpuvrf8_addr = 0;
u32 ret_val;
raw_spin_lock_irqsave(&l2_access_lock, flags);
-
- if (l2cpuvrf8_needs_fix(reg_addr))
- l2cpuvrf8_addr = l2cpuvrf8_fix_save(reg_addr, &l2cpuvrf8_val);
-
mb();
asm volatile ("mcr p15, 3, %[l2cpselr], c15, c0, 6\n\t"
"isb\n\t"
@@ -96,10 +33,6 @@
: [l2cpdr_read]"=r" (ret_val)
: [l2cpselr]"r" (reg_addr), [l2cpdr]"r" (val)
);
-
- if (l2cpuvrf8_addr)
- l2cpuvrf8_fix_restore(l2cpuvrf8_addr, l2cpuvrf8_val);
-
raw_spin_unlock_irqrestore(&l2_access_lock, flags);
return ret_val;
@@ -109,13 +42,8 @@
void set_l2_indirect_reg(u32 reg_addr, u32 val)
{
unsigned long flags;
- u32 uninitialized_var(l2cpuvrf8_val), l2cpuvrf8_addr = 0;
raw_spin_lock_irqsave(&l2_access_lock, flags);
-
- if (l2cpuvrf8_needs_fix(reg_addr))
- l2cpuvrf8_addr = l2cpuvrf8_fix_save(reg_addr, &l2cpuvrf8_val);
-
mb();
asm volatile ("mcr p15, 3, %[l2cpselr], c15, c0, 6\n\t"
"isb\n\t"
@@ -124,10 +52,6 @@
:
: [l2cpselr]"r" (reg_addr), [l2cpdr]"r" (val)
);
-
- if (l2cpuvrf8_addr)
- l2cpuvrf8_fix_restore(l2cpuvrf8_addr, l2cpuvrf8_val);
-
raw_spin_unlock_irqrestore(&l2_access_lock, flags);
}
EXPORT_SYMBOL(set_l2_indirect_reg);
diff --git a/arch/arm/mach-msm/msm_dcvs.c b/arch/arm/mach-msm/msm_dcvs.c
index 9601b7e..310197e 100644
--- a/arch/arm/mach-msm/msm_dcvs.c
+++ b/arch/arm/mach-msm/msm_dcvs.c
@@ -14,7 +14,6 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
-#include <linux/mutex.h>
#include <linux/kthread.h>
#include <linux/kobject.h>
#include <linux/ktime.h>
@@ -23,26 +22,18 @@
#include <linux/spinlock.h>
#include <linux/stringify.h>
#include <linux/debugfs.h>
+#include <linux/msm_tsens.h>
#include <asm/atomic.h>
#include <asm/page.h>
#include <mach/msm_dcvs.h>
+#include <trace/events/mpdcvs_trace.h>
#define CORE_HANDLE_OFFSET (0xA0)
#define __err(f, ...) pr_err("MSM_DCVS: %s: " f, __func__, __VA_ARGS__)
#define __info(f, ...) pr_info("MSM_DCVS: %s: " f, __func__, __VA_ARGS__)
#define MAX_PENDING (5)
-enum {
- MSM_DCVS_DEBUG_NOTIFIER = BIT(0),
- MSM_DCVS_DEBUG_IDLE_PULSE = BIT(1),
- MSM_DCVS_DEBUG_FREQ_CHANGE = BIT(2),
-};
-
struct core_attribs {
- struct kobj_attribute core_id;
- struct kobj_attribute idle_enabled;
- struct kobj_attribute freq_change_enabled;
- struct kobj_attribute actual_freq;
struct kobj_attribute freq_change_us;
struct kobj_attribute disable_pc_threshold;
@@ -68,12 +59,47 @@
struct kobj_attribute leakage_coeff_c;
struct kobj_attribute leakage_coeff_d;
+ struct kobj_attribute thermal_poll_ms;
+
struct attribute_group attrib_group;
};
+enum pending_freq_state {
+ /*
+ * used by the thread to check if pending_freq was updated while it was
+ * setting previous frequency - this is written to and used by the
+ * freq updating thread
+ */
+ NO_OUTSTANDING_FREQ_CHANGE = 0,
+
+ /*
+ * This request is set to indicate that the governor is stopped and no
+ * more frequency change requests are accepted untill it starts again.
+ * This is checked/used by the threads that want to change the freq
+ */
+ STOP_FREQ_CHANGE = -1,
+
+ /*
+ * Any other +ve value means that a freq change was requested and the
+ * thread has not gotten around to update it
+ *
+ * Any other -ve value means that this is the last freq change i.e. a
+ * freq change was requested but the thread has not run yet and
+ * meanwhile the governor was stopped.
+ */
+};
+
struct dcvs_core {
+ spinlock_t idle_state_change_lock;
+ /* 0 when not idle (busy) 1 when idle and -1 when governor starts and
+ * we dont know whether the next call is going to be idle enter or exit
+ */
+ int idle_entered;
+
+ enum msm_dcvs_core_type type;
+ /* this is the number in each type for example cpu 0,1,2 and gpu 0,1 */
+ int type_core_num;
char core_name[CORE_NAME_MAX];
- uint32_t new_freq[MAX_PENDING];
uint32_t actual_freq;
uint32_t freq_change_us;
@@ -81,122 +107,200 @@
struct msm_dcvs_algo_param algo_param;
struct msm_dcvs_energy_curve_coeffs coeffs;
- struct msm_dcvs_idle *idle_driver;
- struct msm_dcvs_freq *freq_driver;
/* private */
- int64_t time_start;
- struct mutex lock;
- spinlock_t cpu_lock;
+ ktime_t time_start;
struct task_struct *task;
struct core_attribs attrib;
- uint32_t handle;
- uint32_t freq_pending;
- struct hrtimer timer;
- int32_t timer_disabled;
- /* track if kthread for change_freq is active */
- int32_t change_freq_activated;
+ uint32_t dcvs_core_id;
struct msm_dcvs_core_info *info;
+ int sensor;
+ wait_queue_head_t wait_q;
+
+ int (*set_frequency)(int type_core_num, unsigned int freq);
+ unsigned int (*get_frequency)(int type_core_num);
+ int (*idle_enable)(int type_core_num,
+ enum msm_core_control_event event);
+
+ spinlock_t pending_freq_lock;
+ int pending_freq;
+
+ struct hrtimer slack_timer;
+ struct delayed_work temperature_work;
};
-static int msm_dcvs_debug;
static int msm_dcvs_enabled = 1;
module_param_named(enable, msm_dcvs_enabled, int, S_IRUGO | S_IWUSR | S_IWGRP);
-static struct dentry *debugfs_base;
+static struct dentry *debugfs_base;
static struct dcvs_core core_list[CORES_MAX];
-static DEFINE_MUTEX(core_list_lock);
static struct kobject *cores_kobj;
-static struct dcvs_core *core_handles[CORES_MAX];
-/* Change core frequency, called with core mutex locked */
+static void force_stop_slack_timer(struct dcvs_core *core)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&core->idle_state_change_lock, flags);
+ hrtimer_cancel(&core->slack_timer);
+ spin_unlock_irqrestore(&core->idle_state_change_lock, flags);
+}
+
+static void force_start_slack_timer(struct dcvs_core *core, int slack_us)
+{
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&core->idle_state_change_lock, flags);
+
+ /*
+ * only start the timer if governor is not stopped
+ */
+ if (slack_us != 0) {
+ ret = hrtimer_start(&core->slack_timer,
+ ktime_set(0, slack_us * 1000),
+ HRTIMER_MODE_REL_PINNED);
+ if (ret) {
+ pr_err("%s Failed to start timer ret = %d\n",
+ core->core_name, ret);
+ }
+ }
+
+ spin_unlock_irqrestore(&core->idle_state_change_lock, flags);
+}
+
+static void stop_slack_timer(struct dcvs_core *core)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&core->idle_state_change_lock, flags);
+ /* err only for cpu type's GPU's can do idle exit consecutively */
+ if (core->idle_entered == 1 && !(core->dcvs_core_id >= GPU_OFFSET))
+ __err("%s trying to reenter idle", core->core_name);
+ core->idle_entered = 1;
+ hrtimer_cancel(&core->slack_timer);
+ core->idle_entered = 1;
+ spin_unlock_irqrestore(&core->idle_state_change_lock, flags);
+}
+
+static void start_slack_timer(struct dcvs_core *core, int slack_us)
+{
+ unsigned long flags1, flags2;
+ int ret;
+
+ spin_lock_irqsave(&core->idle_state_change_lock, flags2);
+
+ spin_lock_irqsave(&core->pending_freq_lock, flags1);
+
+ /* err only for cpu type's GPU's can do idle enter consecutively */
+ if (core->idle_entered == 0 && !(core->dcvs_core_id >= GPU_OFFSET))
+ __err("%s trying to reexit idle", core->core_name);
+ core->idle_entered = 0;
+ /*
+ * only start the timer if governor is not stopped
+ */
+ if (slack_us != 0
+ && !(core->pending_freq < NO_OUTSTANDING_FREQ_CHANGE)) {
+ ret = hrtimer_start(&core->slack_timer,
+ ktime_set(0, slack_us * 1000),
+ HRTIMER_MODE_REL_PINNED);
+ if (ret) {
+ pr_err("%s Failed to start timer ret = %d\n",
+ core->core_name, ret);
+ }
+ }
+ spin_unlock_irqrestore(&core->pending_freq_lock, flags1);
+
+ spin_unlock_irqrestore(&core->idle_state_change_lock, flags2);
+}
+
+static void restart_slack_timer(struct dcvs_core *core, int slack_us)
+{
+ unsigned long flags1, flags2;
+ int ret;
+
+ spin_lock_irqsave(&core->idle_state_change_lock, flags2);
+
+ hrtimer_cancel(&core->slack_timer);
+
+ spin_lock_irqsave(&core->pending_freq_lock, flags1);
+
+ /*
+ * only start the timer if idle is not entered
+ * and governor is not stopped
+ */
+ if (slack_us != 0 && (core->idle_entered != 1)
+ && !(core->pending_freq < NO_OUTSTANDING_FREQ_CHANGE)) {
+ ret = hrtimer_start(&core->slack_timer,
+ ktime_set(0, slack_us * 1000),
+ HRTIMER_MODE_REL_PINNED);
+ if (ret) {
+ pr_err("%s Failed to start timer ret = %d\n",
+ core->core_name, ret);
+ }
+ }
+ spin_unlock_irqrestore(&core->pending_freq_lock, flags1);
+ spin_unlock_irqrestore(&core->idle_state_change_lock, flags2);
+}
+
static int __msm_dcvs_change_freq(struct dcvs_core *core)
{
int ret = 0;
unsigned long flags = 0;
- unsigned int requested_freq = 0;
- unsigned int prev_freq = 0;
- int64_t time_start = 0;
- int64_t time_end = 0;
+ int requested_freq = 0;
+ ktime_t time_start;
uint32_t slack_us = 0;
uint32_t ret1 = 0;
- if (!core->freq_driver || !core->freq_driver->set_frequency) {
- /* Core may have unregistered or hotplugged */
- return -ENODEV;
- }
+ spin_lock_irqsave(&core->pending_freq_lock, flags);
repeat:
- spin_lock_irqsave(&core->cpu_lock, flags);
- if (unlikely(!core->freq_pending)) {
- spin_unlock_irqrestore(&core->cpu_lock, flags);
- return ret;
- }
- requested_freq = core->new_freq[core->freq_pending - 1];
- if (unlikely(core->freq_pending > 1) &&
- (msm_dcvs_debug & MSM_DCVS_DEBUG_FREQ_CHANGE)) {
- int i;
- for (i = 0; i < core->freq_pending - 1; i++) {
- __info("Core %s missing freq %u\n",
- core->core_name, core->new_freq[i]);
- }
- }
+ BUG_ON(!core->pending_freq);
+ if (core->pending_freq == STOP_FREQ_CHANGE)
+ BUG();
+
+ requested_freq = core->pending_freq;
time_start = core->time_start;
- core->time_start = 0;
- core->freq_pending = 0;
- /**
- * Cancel the timers, we dont want the timer firing as we are
- * changing the clock rate. Dont let idle_exit and others setup
- * timers as well.
- */
- hrtimer_cancel(&core->timer);
- core->timer_disabled = 1;
- spin_unlock_irqrestore(&core->cpu_lock, flags);
+ core->time_start = ns_to_ktime(0);
+
+ if (requested_freq < 0) {
+ requested_freq = -1 * requested_freq;
+ core->pending_freq = STOP_FREQ_CHANGE;
+ } else {
+ core->pending_freq = NO_OUTSTANDING_FREQ_CHANGE;
+ }
if (requested_freq == core->actual_freq)
- return ret;
+ goto out;
+
+ spin_unlock_irqrestore(&core->pending_freq_lock, flags);
/**
* Call the frequency sink driver to change the frequency
* We will need to get back the actual frequency in KHz and
* the record the time taken to change it.
*/
- ret = core->freq_driver->set_frequency(core->freq_driver,
- requested_freq);
- if (ret <= 0) {
+ ret = core->set_frequency(core->type_core_num, requested_freq);
+ if (ret <= 0)
__err("Core %s failed to set freq %u\n",
core->core_name, requested_freq);
/* continue to call TZ to get updated slack timer */
- } else {
- prev_freq = core->actual_freq;
+ else
core->actual_freq = ret;
- }
- time_end = ktime_to_ns(ktime_get());
- if (msm_dcvs_debug & MSM_DCVS_DEBUG_FREQ_CHANGE)
- __info("Core %s Time end %llu Time start: %llu\n",
- core->core_name, time_end, time_start);
- time_end -= time_start;
- do_div(time_end, NSEC_PER_USEC);
- core->freq_change_us = (uint32_t)time_end;
+ core->freq_change_us = (uint32_t)ktime_to_us(
+ ktime_sub(ktime_get(), time_start));
/**
* Disable low power modes if the actual frequency is >
* disable_pc_threshold.
*/
- if (core->actual_freq >
- core->algo_param.disable_pc_threshold) {
- core->idle_driver->enable(core->idle_driver,
+ if (core->actual_freq > core->algo_param.disable_pc_threshold) {
+ core->idle_enable(core->type_core_num,
MSM_DCVS_DISABLE_HIGH_LATENCY_MODES);
- if (msm_dcvs_debug & MSM_DCVS_DEBUG_IDLE_PULSE)
- __info("Disabling LPM for %s\n", core->core_name);
- } else if (core->actual_freq <=
- core->algo_param.disable_pc_threshold) {
- core->idle_driver->enable(core->idle_driver,
+ } else if (core->actual_freq <= core->algo_param.disable_pc_threshold) {
+ core->idle_enable(core->type_core_num,
MSM_DCVS_ENABLE_HIGH_LATENCY_MODES);
- if (msm_dcvs_debug & MSM_DCVS_DEBUG_IDLE_PULSE)
- __info("Enabling LPM for %s\n", core->core_name);
}
/**
@@ -204,108 +308,165 @@
* to this frequency and that will get us the new slack
* timer
*/
- ret = msm_dcvs_scm_event(core->handle, MSM_DCVS_SCM_CLOCK_FREQ_UPDATE,
- core->actual_freq, (uint32_t)time_end, &slack_us, &ret1);
- if (!ret) {
- /* Reset the slack timer */
- if (slack_us) {
- core->timer_disabled = 0;
- ret = hrtimer_start(&core->timer,
- ktime_set(0, slack_us * 1000),
- HRTIMER_MODE_REL_PINNED);
- if (ret)
- __err("Failed to register timer for core %s\n",
- core->core_name);
- }
- } else {
- __err("Error sending core (%s) freq change (%u)\n",
- core->core_name, core->actual_freq);
+ ret = msm_dcvs_scm_event(core->dcvs_core_id,
+ MSM_DCVS_SCM_CLOCK_FREQ_UPDATE,
+ core->actual_freq, core->freq_change_us,
+ &slack_us, &ret1);
+ if (ret) {
+ __err("Error sending core (%s) dcvs_core_id = %d freq change (%u) reqfreq = %d slack_us=%d ret = %d\n",
+ core->core_name, core->dcvs_core_id,
+ core->actual_freq, requested_freq,
+ slack_us, ret);
}
- if (msm_dcvs_debug & MSM_DCVS_DEBUG_FREQ_CHANGE)
- __info("Freq %u requested for core %s (actual %u prev %u) "
- "change time %u us slack time %u us\n",
- requested_freq, core->core_name,
- core->actual_freq, prev_freq,
- core->freq_change_us, slack_us);
+ /* TODO confirm that we get a valid freq from SM even when the above
+ * FREQ_UPDATE fails
+ */
+ restart_slack_timer(core, slack_us);
+ spin_lock_irqsave(&core->pending_freq_lock, flags);
/**
* By the time we are done with freq changes, we could be asked to
* change again. Check before exiting.
*/
- if (core->freq_pending)
+ if (core->pending_freq != NO_OUTSTANDING_FREQ_CHANGE
+ && core->pending_freq != STOP_FREQ_CHANGE) {
goto repeat;
+ }
- core->change_freq_activated = 0;
+out: /* should always be jumped to with the spin_lock held */
+ spin_unlock_irqrestore(&core->pending_freq_lock, flags);
+
return ret;
}
+static void msm_dcvs_report_temp_work(struct work_struct *work)
+{
+ struct dcvs_core *core = container_of(work,
+ struct dcvs_core,
+ temperature_work.work);
+ struct msm_dcvs_core_info *info = core->info;
+ struct tsens_device tsens_dev;
+ int ret;
+ unsigned long temp = 0;
+ int interval_ms;
+
+ tsens_dev.sensor_num = core->sensor;
+ ret = tsens_get_temp(&tsens_dev, &temp);
+ if (!temp) {
+ tsens_dev.sensor_num = 0;
+ ret = tsens_get_temp(&tsens_dev, &temp);
+ if (!temp)
+ goto out;
+ }
+
+ if (temp == info->power_param.current_temp)
+ goto out;
+ info->power_param.current_temp = temp;
+
+ ret = msm_dcvs_scm_set_power_params(core->dcvs_core_id,
+ &info->power_param,
+ &info->freq_tbl[0], &core->coeffs);
+out:
+ if (info->thermal_poll_ms == 0)
+ interval_ms = 60000;
+ else if (info->thermal_poll_ms < 1000)
+ interval_ms = 1000;
+ else
+ interval_ms = info->thermal_poll_ms;
+
+ schedule_delayed_work(&core->temperature_work,
+ msecs_to_jiffies(interval_ms));
+}
+
static int msm_dcvs_do_freq(void *data)
{
struct dcvs_core *core = (struct dcvs_core *)data;
static struct sched_param param = {.sched_priority = MAX_RT_PRIO - 1};
sched_setscheduler(current, SCHED_FIFO, ¶m);
- set_current_state(TASK_UNINTERRUPTIBLE);
while (!kthread_should_stop()) {
- mutex_lock(&core->lock);
- __msm_dcvs_change_freq(core);
- mutex_unlock(&core->lock);
-
- schedule();
+ wait_event(core->wait_q, !(core->pending_freq == 0 ||
+ core->pending_freq == -1) ||
+ kthread_should_stop());
if (kthread_should_stop())
break;
- set_current_state(TASK_UNINTERRUPTIBLE);
+ __msm_dcvs_change_freq(core);
}
- __set_current_state(TASK_RUNNING);
-
return 0;
}
+/* freq_pending_lock should be held */
+static void request_freq_change(struct dcvs_core *core, int new_freq)
+{
+ if (new_freq == NO_OUTSTANDING_FREQ_CHANGE) {
+ if (core->pending_freq != STOP_FREQ_CHANGE) {
+ __err("%s gov started with earlier pending freq %d\n",
+ core->core_name, core->pending_freq);
+ }
+ core->pending_freq = NO_OUTSTANDING_FREQ_CHANGE;
+ return;
+ }
+
+ if (new_freq == STOP_FREQ_CHANGE) {
+ if (core->pending_freq == NO_OUTSTANDING_FREQ_CHANGE)
+ core->pending_freq = STOP_FREQ_CHANGE;
+ else if (core->pending_freq > 0)
+ core->pending_freq = -1 * core->pending_freq;
+ return;
+ }
+
+ if (core->pending_freq < 0) {
+ /* a value less than 0 means that the governor has stopped
+ * and no more freq changes should be requested
+ */
+ return;
+ }
+
+ if (core->actual_freq != new_freq && core->pending_freq != new_freq) {
+ core->pending_freq = new_freq;
+ core->time_start = ktime_get();
+ wake_up(&core->wait_q);
+ }
+}
+
static int msm_dcvs_update_freq(struct dcvs_core *core,
enum msm_dcvs_scm_event event, uint32_t param0,
- uint32_t *ret1, int *freq_changed)
+ uint32_t *ret1)
{
int ret = 0;
unsigned long flags = 0;
- uint32_t new_freq = 0;
+ uint32_t new_freq = -EINVAL;
- spin_lock_irqsave(&core->cpu_lock, flags);
- ret = msm_dcvs_scm_event(core->handle, event, param0,
+ spin_lock_irqsave(&core->pending_freq_lock, flags);
+
+ ret = msm_dcvs_scm_event(core->dcvs_core_id, event, param0,
core->actual_freq, &new_freq, ret1);
if (ret) {
- __err("Error (%d) sending SCM event %d for core %s\n",
+ if (ret == -13)
+ ret = 0;
+ else
+ __err("Error (%d) sending SCM event %d for core %s\n",
ret, event, core->core_name);
- goto freq_done;
+ goto out;
}
- if ((core->actual_freq != new_freq) &&
- (core->new_freq[core->freq_pending] != new_freq)) {
- if (core->freq_pending >= MAX_PENDING - 1)
- core->freq_pending = MAX_PENDING - 1;
- core->new_freq[core->freq_pending++] = new_freq;
- core->time_start = ktime_to_ns(ktime_get());
-
- /* Schedule the frequency change */
- if (!core->task)
- __err("Uninitialized task for core %s\n",
- core->core_name);
- else {
- if (freq_changed)
- *freq_changed = 1;
- core->change_freq_activated = 1;
- wake_up_process(core->task);
- }
- } else {
- if (freq_changed)
- *freq_changed = 0;
+ if (new_freq == 0) {
+ /*
+ * sometimes TZ gives us a 0 freq back,
+ * do not queue up a request
+ */
+ goto out;
}
-freq_done:
- spin_unlock_irqrestore(&core->cpu_lock, flags);
+
+ request_freq_change(core, new_freq);
+
+out:
+ spin_unlock_irqrestore(&core->pending_freq_lock, flags);
return ret;
}
@@ -313,19 +474,17 @@
static enum hrtimer_restart msm_dcvs_core_slack_timer(struct hrtimer *timer)
{
int ret = 0;
- struct dcvs_core *core = container_of(timer, struct dcvs_core, timer);
+ struct dcvs_core *core = container_of(timer,
+ struct dcvs_core, slack_timer);
uint32_t ret1;
- uint32_t ret2;
- if (msm_dcvs_debug & MSM_DCVS_DEBUG_FREQ_CHANGE)
- __info("Slack timer fired for core %s\n", core->core_name);
-
+ trace_printk("dcvs: Slack timer fired for core=%s\n", core->core_name);
/**
* Timer expired, notify TZ
* Dont care about the third arg.
*/
ret = msm_dcvs_update_freq(core, MSM_DCVS_SCM_QOS_TIMER_EXPIRED, 0,
- &ret1, &ret2);
+ &ret1);
if (ret)
__err("Timer expired for core %s but failed to notify.\n",
core->core_name);
@@ -346,6 +505,28 @@
return snprintf(buf, PAGE_SIZE, "%d\n", v); \
}
+#define DCVS_PARAM_STORE(_name) \
+static ssize_t msm_dcvs_attr_##_name##_show(struct kobject *kobj,\
+ struct kobj_attribute *attr, char *buf) \
+{ \
+ struct dcvs_core *core = CORE_FROM_ATTRIBS(attr, _name); \
+ return snprintf(buf, PAGE_SIZE, "%d\n", core->info->_name); \
+} \
+static ssize_t msm_dcvs_attr_##_name##_store(struct kobject *kobj, \
+ struct kobj_attribute *attr, const char *buf, size_t count) \
+{ \
+ int ret = 0; \
+ uint32_t val = 0; \
+ struct dcvs_core *core = CORE_FROM_ATTRIBS(attr, _name); \
+ ret = kstrtouint(buf, 10, &val); \
+ if (ret) { \
+ __err("Invalid input %s for %s\n", buf, __stringify(_name));\
+ } else { \
+ core->info->_name = val; \
+ } \
+ return count; \
+}
+
#define DCVS_ALGO_PARAM(_name) \
static ssize_t msm_dcvs_attr_##_name##_show(struct kobject *kobj,\
struct kobj_attribute *attr, char *buf) \
@@ -359,14 +540,13 @@
int ret = 0; \
uint32_t val = 0; \
struct dcvs_core *core = CORE_FROM_ATTRIBS(attr, _name); \
- mutex_lock(&core->lock); \
ret = kstrtouint(buf, 10, &val); \
if (ret) { \
__err("Invalid input %s for %s\n", buf, __stringify(_name));\
} else { \
uint32_t old_val = core->algo_param._name; \
core->algo_param._name = val; \
- ret = msm_dcvs_scm_set_algo_params(core->handle, \
+ ret = msm_dcvs_scm_set_algo_params(core->dcvs_core_id, \
&core->algo_param); \
if (ret) { \
core->algo_param._name = old_val; \
@@ -374,7 +554,6 @@
ret, val, __stringify(_name)); \
} \
} \
- mutex_unlock(&core->lock); \
return count; \
}
@@ -391,14 +570,13 @@
int ret = 0; \
int32_t val = 0; \
struct dcvs_core *core = CORE_FROM_ATTRIBS(attr, _name); \
- mutex_lock(&core->lock); \
ret = kstrtoint(buf, 10, &val); \
if (ret) { \
__err("Invalid input %s for %s\n", buf, __stringify(_name));\
} else { \
int32_t old_val = core->coeffs._name; \
core->coeffs._name = val; \
- ret = msm_dcvs_scm_set_power_params(core->handle, \
+ ret = msm_dcvs_scm_set_power_params(core->dcvs_core_id, \
&core->info->power_param, &core->info->freq_tbl[0], \
&core->coeffs); \
if (ret) { \
@@ -407,7 +585,6 @@
ret, val, __stringify(_name)); \
} \
} \
- mutex_unlock(&core->lock); \
return count; \
}
@@ -429,10 +606,6 @@
* Function declarations for different attributes.
* Gets used when setting the attribute show and store parameters.
*/
-DCVS_PARAM_SHOW(core_id, core->handle)
-DCVS_PARAM_SHOW(idle_enabled, (core->idle_driver != NULL))
-DCVS_PARAM_SHOW(freq_change_enabled, (core->freq_driver != NULL))
-DCVS_PARAM_SHOW(actual_freq, (core->actual_freq))
DCVS_PARAM_SHOW(freq_change_us, (core->freq_change_us))
DCVS_ALGO_PARAM(disable_pc_threshold)
@@ -458,11 +631,13 @@
DCVS_ENERGY_PARAM(leakage_coeff_c)
DCVS_ENERGY_PARAM(leakage_coeff_d)
+DCVS_PARAM_STORE(thermal_poll_ms)
+
static int msm_dcvs_setup_core_sysfs(struct dcvs_core *core)
{
int ret = 0;
struct kobject *core_kobj = NULL;
- const int attr_count = 27;
+ const int attr_count = 24;
BUG_ON(!cores_kobj);
@@ -474,37 +649,33 @@
goto done;
}
+ DCVS_RO_ATTRIB(0, freq_change_us);
- DCVS_RO_ATTRIB(0, core_id);
- DCVS_RO_ATTRIB(1, idle_enabled);
- DCVS_RO_ATTRIB(2, freq_change_enabled);
- DCVS_RO_ATTRIB(3, actual_freq);
- DCVS_RO_ATTRIB(4, freq_change_us);
+ DCVS_RW_ATTRIB(1, disable_pc_threshold);
+ DCVS_RW_ATTRIB(2, em_win_size_min_us);
+ DCVS_RW_ATTRIB(3, em_win_size_max_us);
+ DCVS_RW_ATTRIB(4, em_max_util_pct);
+ DCVS_RW_ATTRIB(5, group_id);
+ DCVS_RW_ATTRIB(6, max_freq_chg_time_us);
+ DCVS_RW_ATTRIB(7, slack_mode_dynamic);
+ DCVS_RW_ATTRIB(8, slack_weight_thresh_pct);
+ DCVS_RW_ATTRIB(9, slack_time_min_us);
+ DCVS_RW_ATTRIB(10, slack_time_max_us);
+ DCVS_RW_ATTRIB(11, ss_iobusy_conv);
+ DCVS_RW_ATTRIB(12, ss_win_size_min_us);
+ DCVS_RW_ATTRIB(13, ss_win_size_max_us);
+ DCVS_RW_ATTRIB(14, ss_util_pct);
- DCVS_RW_ATTRIB(5, disable_pc_threshold);
- DCVS_RW_ATTRIB(6, em_win_size_min_us);
- DCVS_RW_ATTRIB(7, em_win_size_max_us);
- DCVS_RW_ATTRIB(8, em_max_util_pct);
- DCVS_RW_ATTRIB(9, group_id);
- DCVS_RW_ATTRIB(10, max_freq_chg_time_us);
- DCVS_RW_ATTRIB(11, slack_mode_dynamic);
- DCVS_RW_ATTRIB(12, slack_time_min_us);
- DCVS_RW_ATTRIB(13, slack_time_max_us);
- DCVS_RW_ATTRIB(14, slack_weight_thresh_pct);
- DCVS_RW_ATTRIB(15, ss_iobusy_conv);
- DCVS_RW_ATTRIB(16, ss_win_size_min_us);
- DCVS_RW_ATTRIB(17, ss_win_size_max_us);
- DCVS_RW_ATTRIB(18, ss_util_pct);
+ DCVS_RW_ATTRIB(15, active_coeff_a);
+ DCVS_RW_ATTRIB(16, active_coeff_b);
+ DCVS_RW_ATTRIB(17, active_coeff_c);
+ DCVS_RW_ATTRIB(18, leakage_coeff_a);
+ DCVS_RW_ATTRIB(19, leakage_coeff_b);
+ DCVS_RW_ATTRIB(20, leakage_coeff_c);
+ DCVS_RW_ATTRIB(21, leakage_coeff_d);
+ DCVS_RW_ATTRIB(22, thermal_poll_ms);
- DCVS_RW_ATTRIB(19, active_coeff_a);
- DCVS_RW_ATTRIB(20, active_coeff_b);
- DCVS_RW_ATTRIB(21, active_coeff_c);
- DCVS_RW_ATTRIB(22, leakage_coeff_a);
- DCVS_RW_ATTRIB(23, leakage_coeff_b);
- DCVS_RW_ATTRIB(24, leakage_coeff_c);
- DCVS_RW_ATTRIB(25, leakage_coeff_d);
-
- core->attrib.attrib_group.attrs[26] = NULL;
+ core->attrib.attrib_group.attrs[23] = NULL;
core_kobj = kobject_create_and_add(core->core_name, cores_kobj);
if (!core_kobj) {
@@ -515,8 +686,6 @@
ret = sysfs_create_group(core_kobj, &core->attrib.attrib_group);
if (ret)
__err("Cannot create core %s attr group\n", core->core_name);
- else if (msm_dcvs_debug & MSM_DCVS_DEBUG_NOTIFIER)
- __info("Setting up attributes for core %s\n", core->core_name);
done:
if (ret) {
@@ -527,65 +696,95 @@
return ret;
}
-/* Return the core if found or add to list if @add_to_list is true */
-static struct dcvs_core *msm_dcvs_get_core(const char *name, int add_to_list)
+static int get_core_offset(enum msm_dcvs_core_type type, int num)
+{
+ int offset = -EINVAL;
+
+ switch (type) {
+ case MSM_DCVS_CORE_TYPE_CPU:
+ offset = CPU_OFFSET + num;
+ BUG_ON(offset >= GPU_OFFSET);
+ break;
+ case MSM_DCVS_CORE_TYPE_GPU:
+ offset = GPU_OFFSET + num;
+ BUG_ON(offset >= CORES_MAX);
+ break;
+ default:
+ BUG();
+ }
+
+ return offset;
+}
+
+/* Return the core and initialize non platform data specific numbers in it */
+static struct dcvs_core *msm_dcvs_add_core(enum msm_dcvs_core_type type,
+ int num)
{
struct dcvs_core *core = NULL;
int i;
- int empty = -1;
+ char name[CORE_NAME_MAX];
- if (!name[0] ||
- (strnlen(name, CORE_NAME_MAX - 1) == CORE_NAME_MAX - 1))
- return core;
-
- mutex_lock(&core_list_lock);
- for (i = 0; i < CORES_MAX; i++) {
- core = &core_list[i];
- if ((empty < 0) && !core->core_name[0]) {
- empty = i;
- continue;
- }
- if (!strncmp(name, core->core_name, CORE_NAME_MAX))
- break;
- }
-
- /* Check for core_list full */
- if ((i == CORES_MAX) && (empty < 0)) {
- mutex_unlock(&core_list_lock);
+ i = get_core_offset(type, num);
+ if (i < 0)
return NULL;
- }
- if (i == CORES_MAX && add_to_list) {
- core = &core_list[empty];
- strlcpy(core->core_name, name, CORE_NAME_MAX);
- mutex_init(&core->lock);
- spin_lock_init(&core->cpu_lock);
- core->handle = empty + CORE_HANDLE_OFFSET;
- hrtimer_init(&core->timer,
- CLOCK_MONOTONIC, HRTIMER_MODE_REL_PINNED);
- core->timer.function = msm_dcvs_core_slack_timer;
- }
- mutex_unlock(&core_list_lock);
+ if (type == MSM_DCVS_CORE_TYPE_CPU)
+ snprintf(name, CORE_NAME_MAX, "cpu%d", num);
+ else
+ snprintf(name, CORE_NAME_MAX, "gpu%d", num);
+ core = &core_list[i];
+ core->dcvs_core_id = i;
+ strlcpy(core->core_name, name, CORE_NAME_MAX);
+ spin_lock_init(&core->pending_freq_lock);
+ spin_lock_init(&core->idle_state_change_lock);
+ hrtimer_init(&core->slack_timer,
+ CLOCK_MONOTONIC, HRTIMER_MODE_REL_PINNED);
+ core->slack_timer.function = msm_dcvs_core_slack_timer;
return core;
}
-int msm_dcvs_register_core(const char *core_name,
- struct msm_dcvs_core_info *info)
+/* Return the core if found or add to list if @add_to_list is true */
+static struct dcvs_core *msm_dcvs_get_core(int offset)
+{
+ /* if the handle is still not set bug */
+ BUG_ON(core_list[offset].dcvs_core_id == -1);
+ return &core_list[offset];
+}
+
+
+int msm_dcvs_register_core(
+ enum msm_dcvs_core_type type,
+ int type_core_num,
+ struct msm_dcvs_core_info *info,
+ int (*set_frequency)(int type_core_num, unsigned int freq),
+ unsigned int (*get_frequency)(int type_core_num),
+ int (*idle_enable)(int type_core_num,
+ enum msm_core_control_event event),
+ int sensor)
{
int ret = -EINVAL;
+ int offset;
struct dcvs_core *core = NULL;
uint32_t ret1;
uint32_t ret2;
- if (!core_name || !core_name[0])
+ offset = get_core_offset(type, type_core_num);
+ if (offset < 0)
return ret;
+ if (core_list[offset].dcvs_core_id != -1)
+ return core_list[offset].dcvs_core_id;
- core = msm_dcvs_get_core(core_name, true);
+ core = msm_dcvs_add_core(type, type_core_num);
if (!core)
return ret;
- mutex_lock(&core->lock);
+ core->type = type;
+ core->type_core_num = type_core_num;
+ core->set_frequency = set_frequency;
+ core->get_frequency = get_frequency;
+ core->idle_enable = idle_enable;
+ core->pending_freq = STOP_FREQ_CHANGE;
core->info = info;
memcpy(&core->algo_param, &info->algo_param,
@@ -594,20 +793,39 @@
memcpy(&core->coeffs, &info->energy_coeffs,
sizeof(struct msm_dcvs_energy_curve_coeffs));
- ret = msm_dcvs_scm_register_core(core->handle, &info->core_param);
- if (ret)
- goto bail;
+ /*
+ * The tz expects cpu0 to represent bit 0 in the mask, however the
+ * dcvs_core_id needs to start from 1, dcvs_core_id = 0 is used to
+ * indicate that this request is not associated with any core.
+ * mpdecision
+ */
+ info->core_param.core_bitmask_id
+ = 1 << (core->dcvs_core_id - CPU_OFFSET);
+ core->sensor = sensor;
- ret = msm_dcvs_scm_set_algo_params(core->handle, &info->algo_param);
- if (ret)
+ ret = msm_dcvs_scm_register_core(core->dcvs_core_id, &info->core_param);
+ if (ret) {
+ __err("%s: scm register core fail handle = %d ret = %d\n",
+ __func__, core->dcvs_core_id, ret);
goto bail;
+ }
- ret = msm_dcvs_scm_set_power_params(core->handle, &info->power_param,
+ ret = msm_dcvs_scm_set_algo_params(core->dcvs_core_id,
+ &info->algo_param);
+ if (ret) {
+ __err("%s: scm algo params failed ret = %d\n", __func__, ret);
+ goto bail;
+ }
+
+ ret = msm_dcvs_scm_set_power_params(core->dcvs_core_id,
+ &info->power_param,
&info->freq_tbl[0], &core->coeffs);
- if (ret)
+ if (ret) {
+ __err("%s: scm power params failed ret = %d\n", __func__, ret);
goto bail;
+ }
- ret = msm_dcvs_scm_event(core->handle, MSM_DCVS_SCM_CORE_ONLINE,
+ ret = msm_dcvs_scm_event(core->dcvs_core_id, MSM_DCVS_SCM_CORE_ONLINE,
core->actual_freq, 0, &ret1, &ret2);
if (ret)
goto bail;
@@ -615,187 +833,164 @@
ret = msm_dcvs_setup_core_sysfs(core);
if (ret) {
__err("Unable to setup core %s sysfs\n", core->core_name);
- core_handles[core->handle - CORE_HANDLE_OFFSET] = NULL;
goto bail;
}
+ core->idle_entered = -1;
+ init_waitqueue_head(&core->wait_q);
+ core->task = kthread_run(msm_dcvs_do_freq, (void *)core,
+ "msm_dcvs/%d", core->dcvs_core_id);
+ ret = core->dcvs_core_id;
-bail:
- mutex_unlock(&core->lock);
+ INIT_DELAYED_WORK(&core->temperature_work, msm_dcvs_report_temp_work);
+ schedule_delayed_work(&core->temperature_work,
+ msecs_to_jiffies(info->thermal_poll_ms));
return ret;
+bail:
+ core->dcvs_core_id = -1;
+ return -EINVAL;
}
EXPORT_SYMBOL(msm_dcvs_register_core);
-int msm_dcvs_freq_sink_register(struct msm_dcvs_freq *drv)
+void msm_dcvs_update_limits(int dcvs_core_id)
+{
+ struct dcvs_core *core;
+
+ if (dcvs_core_id < CPU_OFFSET || dcvs_core_id > CORES_MAX) {
+ __err("%s invalid dcvs_core_id = %d returning -EINVAL\n",
+ __func__, dcvs_core_id);
+ return;
+ }
+
+ core = msm_dcvs_get_core(dcvs_core_id);
+ core->actual_freq = core->get_frequency(core->type_core_num);
+}
+
+int msm_dcvs_freq_sink_start(int dcvs_core_id)
{
int ret = -EINVAL;
struct dcvs_core *core = NULL;
uint32_t ret1;
- uint32_t ret2;
+ unsigned long flags;
+ int new_freq;
+ int timer_interval_us;
- if (!drv || !drv->core_name)
- return ret;
+ if (dcvs_core_id < CPU_OFFSET || dcvs_core_id > CORES_MAX) {
+ __err("%s invalid dcvs_core_id = %d returning -EINVAL\n",
+ __func__, dcvs_core_id);
+ return -EINVAL;
+ }
- core = msm_dcvs_get_core(drv->core_name, true);
+ core = msm_dcvs_get_core(dcvs_core_id);
if (!core)
return ret;
- mutex_lock(&core->lock);
- if (core->freq_driver && (msm_dcvs_debug & MSM_DCVS_DEBUG_NOTIFIER))
- __info("Frequency notifier for %s being replaced\n",
- core->core_name);
- core->freq_driver = drv;
- core->task = kthread_create(msm_dcvs_do_freq, (void *)core,
- "msm_dcvs/%d", core->handle);
- if (IS_ERR(core->task)) {
- mutex_unlock(&core->lock);
- return -EFAULT;
+ core->actual_freq = core->get_frequency(core->type_core_num);
+
+ spin_lock_irqsave(&core->pending_freq_lock, flags);
+ /* mark that we are ready to accept new frequencies */
+ request_freq_change(core, NO_OUTSTANDING_FREQ_CHANGE);
+ spin_unlock_irqrestore(&core->pending_freq_lock, flags);
+
+ spin_lock_irqsave(&core->idle_state_change_lock, flags);
+ core->idle_entered = -1;
+ spin_unlock_irqrestore(&core->idle_state_change_lock, flags);
+
+ /* Notify TZ to start receiving idle info for the core */
+ ret = msm_dcvs_update_freq(core, MSM_DCVS_SCM_DCVS_ENABLE, 1, &ret1);
+
+ ret = msm_dcvs_scm_event(
+ core->dcvs_core_id, MSM_DCVS_SCM_CORE_ONLINE, core->actual_freq,
+ 0, &new_freq, &timer_interval_us);
+ if (ret)
+ __err("Error (%d) DCVS sending online for %s\n",
+ ret, core->core_name);
+
+ if (new_freq != 0) {
+ spin_lock_irqsave(&core->pending_freq_lock, flags);
+ request_freq_change(core, new_freq);
+ spin_unlock_irqrestore(&core->pending_freq_lock, flags);
}
+ force_start_slack_timer(core, timer_interval_us);
- if (msm_dcvs_debug & MSM_DCVS_DEBUG_IDLE_PULSE)
- __info("Enabling idle pulse for %s\n", core->core_name);
- if (core->idle_driver) {
- core->actual_freq = core->freq_driver->get_frequency(drv);
- /* Notify TZ to start receiving idle info for the core */
- ret = msm_dcvs_update_freq(core, MSM_DCVS_SCM_DCVS_ENABLE, 1,
- &ret1, &ret2);
- core->idle_driver->enable(core->idle_driver,
- MSM_DCVS_ENABLE_IDLE_PULSE);
- }
-
- mutex_unlock(&core->lock);
-
- return core->handle;
+ core->idle_enable(core->type_core_num, MSM_DCVS_ENABLE_IDLE_PULSE);
+ return 0;
}
-EXPORT_SYMBOL(msm_dcvs_freq_sink_register);
+EXPORT_SYMBOL(msm_dcvs_freq_sink_start);
-int msm_dcvs_freq_sink_unregister(struct msm_dcvs_freq *drv)
+int msm_dcvs_freq_sink_stop(int dcvs_core_id)
{
int ret = -EINVAL;
struct dcvs_core *core = NULL;
uint32_t ret1;
- uint32_t ret2;
+ uint32_t freq;
+ unsigned long flags;
- if (!drv || !drv->core_name)
- return ret;
-
- core = msm_dcvs_get_core(drv->core_name, false);
- if (!core)
- return ret;
-
- mutex_lock(&core->lock);
- if (msm_dcvs_debug & MSM_DCVS_DEBUG_IDLE_PULSE)
- __info("Disabling idle pulse for %s\n", core->core_name);
- if (core->idle_driver) {
- core->idle_driver->enable(core->idle_driver,
- MSM_DCVS_DISABLE_IDLE_PULSE);
- /* Notify TZ to stop receiving idle info for the core */
- ret = msm_dcvs_update_freq(core, MSM_DCVS_SCM_DCVS_ENABLE, 0,
- &ret1, &ret2);
- hrtimer_cancel(&core->timer);
- core->idle_driver->enable(core->idle_driver,
- MSM_DCVS_ENABLE_HIGH_LATENCY_MODES);
- if (msm_dcvs_debug & MSM_DCVS_DEBUG_IDLE_PULSE)
- __info("Enabling LPM for %s\n", core->core_name);
+ if (dcvs_core_id < 0 || dcvs_core_id > CORES_MAX) {
+ pr_err("%s invalid dcvs_core_id = %d returning -EINVAL\n",
+ __func__, dcvs_core_id);
+ return -EINVAL;
}
- core->freq_pending = 0;
- core->freq_driver = NULL;
- mutex_unlock(&core->lock);
- kthread_stop(core->task);
+
+ core = msm_dcvs_get_core(dcvs_core_id);
+ if (!core) {
+ __err("couldn't find core for coreid = %d\n", dcvs_core_id);
+ return ret;
+ }
+
+ core->idle_enable(core->type_core_num, MSM_DCVS_DISABLE_IDLE_PULSE);
+ /* Notify TZ to stop receiving idle info for the core */
+ ret = msm_dcvs_scm_event(core->dcvs_core_id, MSM_DCVS_SCM_DCVS_ENABLE,
+ 0, core->actual_freq, &freq, &ret1);
+ core->idle_enable(core->type_core_num,
+ MSM_DCVS_ENABLE_HIGH_LATENCY_MODES);
+ spin_lock_irqsave(&core->pending_freq_lock, flags);
+ /* flush out all the pending freq changes */
+ request_freq_change(core, STOP_FREQ_CHANGE);
+ spin_unlock_irqrestore(&core->pending_freq_lock, flags);
+ force_stop_slack_timer(core);
return 0;
}
-EXPORT_SYMBOL(msm_dcvs_freq_sink_unregister);
+EXPORT_SYMBOL(msm_dcvs_freq_sink_stop);
-int msm_dcvs_idle_source_register(struct msm_dcvs_idle *drv)
-{
- int ret = -EINVAL;
- struct dcvs_core *core = NULL;
-
- if (!drv || !drv->core_name)
- return ret;
-
- core = msm_dcvs_get_core(drv->core_name, true);
- if (!core)
- return ret;
-
- mutex_lock(&core->lock);
- if (core->idle_driver && (msm_dcvs_debug & MSM_DCVS_DEBUG_NOTIFIER))
- __info("Idle notifier for %s being replaced\n",
- core->core_name);
- core->idle_driver = drv;
- mutex_unlock(&core->lock);
-
- return core->handle;
-}
-EXPORT_SYMBOL(msm_dcvs_idle_source_register);
-
-int msm_dcvs_idle_source_unregister(struct msm_dcvs_idle *drv)
-{
- int ret = -EINVAL;
- struct dcvs_core *core = NULL;
-
- if (!drv || !drv->core_name)
- return ret;
-
- core = msm_dcvs_get_core(drv->core_name, false);
- if (!core)
- return ret;
-
- mutex_lock(&core->lock);
- core->idle_driver = NULL;
- mutex_unlock(&core->lock);
-
- return 0;
-}
-EXPORT_SYMBOL(msm_dcvs_idle_source_unregister);
-
-int msm_dcvs_idle(int handle, enum msm_core_idle_state state, uint32_t iowaited)
+int msm_dcvs_idle(int dcvs_core_id, enum msm_core_idle_state state,
+ uint32_t iowaited)
{
int ret = 0;
struct dcvs_core *core = NULL;
uint32_t timer_interval_us = 0;
uint32_t r0, r1;
- uint32_t freq_changed = 0;
- if (handle >= CORE_HANDLE_OFFSET &&
- (handle - CORE_HANDLE_OFFSET) < CORES_MAX)
- core = &core_list[handle - CORE_HANDLE_OFFSET];
+ if (dcvs_core_id < CPU_OFFSET || dcvs_core_id > CORES_MAX) {
+ pr_err("invalid dcvs_core_id = %d ret -EINVAL\n", dcvs_core_id);
+ return -EINVAL;
+ }
- BUG_ON(!core);
-
- if (msm_dcvs_debug & MSM_DCVS_DEBUG_IDLE_PULSE)
- __info("Core %s idle state %d\n", core->core_name, state);
+ core = msm_dcvs_get_core(dcvs_core_id);
switch (state) {
case MSM_DCVS_IDLE_ENTER:
- hrtimer_cancel(&core->timer);
- ret = msm_dcvs_scm_event(core->handle,
+ stop_slack_timer(core);
+ ret = msm_dcvs_scm_event(core->dcvs_core_id,
MSM_DCVS_SCM_IDLE_ENTER, 0, 0, &r0, &r1);
- if (ret)
+ if (ret < 0 && ret != -13)
__err("Error (%d) sending idle enter for %s\n",
ret, core->core_name);
+ trace_msm_dcvs_idle("idle_enter_exit", core->core_name, 1);
break;
case MSM_DCVS_IDLE_EXIT:
- hrtimer_cancel(&core->timer);
ret = msm_dcvs_update_freq(core, MSM_DCVS_SCM_IDLE_EXIT,
- iowaited, &timer_interval_us, &freq_changed);
+ iowaited, &timer_interval_us);
if (ret)
__err("Error (%d) sending idle exit for %s\n",
ret, core->core_name);
- /* only start slack timer if change_freq won't */
- if (freq_changed || core->change_freq_activated)
- break;
- if (timer_interval_us && !core->timer_disabled) {
- ret = hrtimer_start(&core->timer,
- ktime_set(0, timer_interval_us * 1000),
- HRTIMER_MODE_REL_PINNED);
-
- if (ret)
- __err("Failed to register timer for core %s\n",
- core->core_name);
- }
+ start_slack_timer(core, timer_interval_us);
+ trace_msm_dcvs_idle("idle_enter_exit", core->core_name, 0);
+ trace_msm_dcvs_iowait("iowait", core->core_name, iowaited);
+ trace_msm_dcvs_slack_time("slack_timer_dcvs", core->core_name,
+ timer_interval_us);
break;
}
@@ -830,13 +1025,6 @@
goto err;
}
- if (!debugfs_create_u32("debug_mask", S_IRUGO | S_IWUSR,
- debugfs_base, &msm_dcvs_debug)) {
- __err("Cannot create debugfs entry %s\n", "debug_mask");
- ret = -ENOMEM;
- goto err;
- }
-
err:
if (ret) {
kobject_del(cores_kobj);
@@ -851,16 +1039,24 @@
static int __init msm_dcvs_early_init(void)
{
int ret = 0;
+ int i;
if (!msm_dcvs_enabled) {
__info("Not enabled (%d)\n", msm_dcvs_enabled);
return 0;
}
- ret = msm_dcvs_scm_init(10 * 1024);
- if (ret)
- __err("Unable to initialize DCVS err=%d\n", ret);
+ /* Only need about 32kBytes for normal operation */
+ ret = msm_dcvs_scm_init(SZ_32K);
+ if (ret) {
+ __err("Unable to initialize DCVS err=%d\n", ret);
+ goto done;
+ }
+
+ for (i = 0; i < CORES_MAX; i++)
+ core_list[i].dcvs_core_id = -1;
+done:
return ret;
}
postcore_initcall(msm_dcvs_early_init);
diff --git a/arch/arm/mach-msm/msm_dcvs_idle.c b/arch/arm/mach-msm/msm_dcvs_idle.c
deleted file mode 100644
index 179e170..0000000
--- a/arch/arm/mach-msm/msm_dcvs_idle.c
+++ /dev/null
@@ -1,170 +0,0 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/cpu_pm.h>
-#include <linux/platform_device.h>
-#include <linux/pm_qos.h>
-#include <linux/hrtimer.h>
-#include <linux/tick.h>
-#include <mach/msm_dcvs.h>
-
-struct cpu_idle_info {
- int cpu;
- int enabled;
- int handle;
- struct msm_dcvs_idle dcvs_notifier;
-};
-
-static DEFINE_PER_CPU_SHARED_ALIGNED(struct cpu_idle_info, cpu_idle_info);
-static DEFINE_PER_CPU_SHARED_ALIGNED(u64, iowait_on_cpu);
-static char core_name[NR_CPUS][10];
-static struct pm_qos_request qos_req;
-static uint32_t latency;
-
-static int msm_dcvs_idle_notifier(struct msm_dcvs_idle *self,
- enum msm_core_control_event event)
-{
- struct cpu_idle_info *info = container_of(self,
- struct cpu_idle_info, dcvs_notifier);
-
- switch (event) {
- case MSM_DCVS_ENABLE_IDLE_PULSE:
- info->enabled = true;
- break;
-
- case MSM_DCVS_DISABLE_IDLE_PULSE:
- info->enabled = false;
- break;
-
- case MSM_DCVS_ENABLE_HIGH_LATENCY_MODES:
- pm_qos_update_request(&qos_req, PM_QOS_DEFAULT_VALUE);
- break;
-
- case MSM_DCVS_DISABLE_HIGH_LATENCY_MODES:
- pm_qos_update_request(&qos_req, latency);
- break;
- }
-
- return 0;
-}
-
-static int msm_cpuidle_notifier(struct notifier_block *self, unsigned long cmd,
- void *v)
-{
- struct cpu_idle_info *info =
- &per_cpu(cpu_idle_info, smp_processor_id());
- u64 io_wait_us = 0;
- u64 prev_io_wait_us = 0;
- u64 last_update_time = 0;
- u64 val = 0;
- uint32_t iowaited = 0;
-
- if (!info->enabled)
- return NOTIFY_OK;
-
- switch (cmd) {
- case CPU_PM_ENTER:
- val = get_cpu_iowait_time_us(smp_processor_id(),
- &last_update_time);
- /* val could be -1 when NOHZ is not enabled */
- if (val == (u64)-1)
- val = 0;
- per_cpu(iowait_on_cpu, smp_processor_id()) = val;
- msm_dcvs_idle(info->handle, MSM_DCVS_IDLE_ENTER, 0);
- break;
-
- case CPU_PM_ENTER_FAILED:
- case CPU_PM_EXIT:
- prev_io_wait_us = per_cpu(iowait_on_cpu, smp_processor_id());
- val = get_cpu_iowait_time_us(smp_processor_id(),
- &last_update_time);
- if (val == (u64)-1)
- val = 0;
- io_wait_us = val;
- iowaited = (io_wait_us - prev_io_wait_us);
- msm_dcvs_idle(info->handle, MSM_DCVS_IDLE_EXIT, iowaited);
- break;
- }
-
- return NOTIFY_OK;
-}
-
-static struct notifier_block idle_nb = {
- .notifier_call = msm_cpuidle_notifier,
-};
-
-static int msm_dcvs_idle_probe(struct platform_device *pdev)
-{
- int cpu;
- struct cpu_idle_info *info = NULL;
- struct msm_dcvs_idle *inotify = NULL;
-
- for_each_possible_cpu(cpu) {
- info = &per_cpu(cpu_idle_info, cpu);
- info->cpu = cpu;
- inotify = &info->dcvs_notifier;
- snprintf(core_name[cpu], 10, "cpu%d", cpu);
- inotify->core_name = core_name[cpu];
- inotify->enable = msm_dcvs_idle_notifier;
- info->handle = msm_dcvs_idle_source_register(inotify);
- BUG_ON(info->handle < 0);
- }
-
- latency = *((uint32_t *)pdev->dev.platform_data);
- pm_qos_add_request(&qos_req, PM_QOS_CPU_DMA_LATENCY,
- PM_QOS_DEFAULT_VALUE);
-
- return cpu_pm_register_notifier(&idle_nb);
-}
-
-static int msm_dcvs_idle_remove(struct platform_device *pdev)
-{
- int ret = 0;
- int rc = 0;
- int cpu = 0;
- struct msm_dcvs_idle *inotify = NULL;
- struct cpu_idle_info *info = NULL;
-
- rc = cpu_pm_unregister_notifier(&idle_nb);
-
- for_each_possible_cpu(cpu) {
- info = &per_cpu(cpu_idle_info, cpu);
- inotify = &info->dcvs_notifier;
- ret = msm_dcvs_idle_source_unregister(inotify);
- if (ret) {
- rc = -EFAULT;
- pr_err("Error de-registering core %d idle notifier.\n",
- cpu);
- }
- }
-
- return rc;
-}
-
-static struct platform_driver idle_pdrv = {
- .probe = msm_dcvs_idle_probe,
- .remove = __devexit_p(msm_dcvs_idle_remove),
- .driver = {
- .name = "msm_cpu_idle",
- .owner = THIS_MODULE,
- },
-};
-
-static int msm_dcvs_idle_init(void)
-{
- return platform_driver_register(&idle_pdrv);
-}
-late_initcall(msm_dcvs_idle_init);
diff --git a/arch/arm/mach-msm/msm_dcvs_scm.c b/arch/arm/mach-msm/msm_dcvs_scm.c
index df6c44f..78d62ac 100644
--- a/arch/arm/mach-msm/msm_dcvs_scm.c
+++ b/arch/arm/mach-msm/msm_dcvs_scm.c
@@ -20,6 +20,7 @@
#include <mach/memory.h>
#include <mach/scm.h>
#include <mach/msm_dcvs_scm.h>
+#include <trace/events/mpdcvs_trace.h>
#define DCVS_CMD_REGISTER_CORE 2
#define DCVS_CMD_SET_ALGO_PARAM 3
@@ -225,6 +226,9 @@
ret = scm_call_atomic4_3(SCM_SVC_DCVS, DCVS_CMD_EVENT,
core_id, event_id, param0, param1, ret0, ret1);
+ trace_msm_dcvs_scm_event(core_id, (int)event_id, param0, param1,
+ *ret0, *ret1);
+
return ret;
}
EXPORT_SYMBOL(msm_dcvs_scm_event);
diff --git a/arch/arm/mach-msm/msm_mpdecision.c b/arch/arm/mach-msm/msm_mpdecision.c
index 056e4eb..9f6cc11 100644
--- a/arch/arm/mach-msm/msm_mpdecision.c
+++ b/arch/arm/mach-msm/msm_mpdecision.c
@@ -37,6 +37,8 @@
#include <asm/page.h>
#include <mach/msm_dcvs.h>
#include <mach/msm_dcvs_scm.h>
+#define CREATE_TRACE_POINTS
+#include <trace/events/mpdcvs_trace.h>
#define DEFAULT_RQ_AVG_POLL_MS (1)
@@ -168,6 +170,8 @@
if (nr > num_present_hundreds)
nr = num_present_hundreds;
+ trace_msm_mp_runq("nr_running", nr);
+
if (ok_to_update_tz(nr, last_nr)) {
hrtimer_try_to_cancel(&msm_mpd.slack_timer);
msm_mpd.data.nr = nr;
@@ -197,9 +201,6 @@
time_taken_ms = ktime_to_ms(ktime_get()) - cpu_action_time_ms;
if (time_taken_ms > hp_latencies.hp_up_max_ms)
hp_latencies.hp_up_max_ms = time_taken_ms;
- if (time_taken_ms > 5)
- pr_warn("cpu_up for cpu%d exceeded 5ms (%d)\n",
- cpu, time_taken_ms);
hp_latencies.hp_up_ms += time_taken_ms;
hp_latencies.hp_up_count++;
ret = msm_dcvs_scm_event(
@@ -228,9 +229,6 @@
time_taken_ms = ktime_to_ms(ktime_get()) - cpu_action_time_ms;
if (time_taken_ms > hp_latencies.hp_dw_max_ms)
hp_latencies.hp_dw_max_ms = time_taken_ms;
- if (time_taken_ms > 5)
- pr_warn("cpu_down for cpu%d exceeded 5ms (%d)\n",
- cpu, time_taken_ms);
hp_latencies.hp_dw_ms += time_taken_ms;
hp_latencies.hp_dw_count++;
ret = msm_dcvs_scm_event(
@@ -263,6 +261,8 @@
return ret;
}
+ trace_msm_mp_cpusonline("cpu_online_mp", req_cpu_mask);
+ trace_msm_mp_slacktime("slack_time_mp", slack_us);
msm_mpd.slack_us = slack_us;
atomic_set(&msm_mpd.algo_cpu_mask, req_cpu_mask);
msm_mpd.hpupdate = HPUPDATE_SCHEDULED;
@@ -286,6 +286,8 @@
{
unsigned long flags;
+ trace_printk("mpd:slack_timer_fired!\n");
+
spin_lock_irqsave(&rq_avg_lock, flags);
if (msm_mpd.data.event == MSM_DCVS_SCM_RUNQ_UPDATE)
goto out;
diff --git a/arch/arm/mach-msm/pil-q6v4-lpass.c b/arch/arm/mach-msm/pil-q6v4-lpass.c
new file mode 100644
index 0000000..222bd10
--- /dev/null
+++ b/arch/arm/mach-msm/pil-q6v4-lpass.c
@@ -0,0 +1,143 @@
+/* Copyright (c) 2012, 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/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include "peripheral-loader.h"
+#include "pil-q6v4.h"
+#include "scm-pas.h"
+
+static int pil_q6v4_lpass_boot(struct pil_desc *pil)
+{
+ struct q6v4_data *drv = pil_to_q6v4_data(pil);
+ int err;
+
+ err = pil_q6v4_power_up(drv);
+ if (err)
+ return err;
+
+ return pil_q6v4_boot(pil);
+}
+
+static int pil_q6v4_lpass_shutdown(struct pil_desc *pil)
+{
+ struct q6v4_data *drv = pil_to_q6v4_data(pil);
+ int ret;
+
+ ret = pil_q6v4_shutdown(pil);
+ if (ret)
+ return ret;
+ pil_q6v4_power_down(drv);
+ return 0;
+}
+
+static struct pil_reset_ops pil_q6v4_lpass_ops = {
+ .init_image = pil_q6v4_init_image,
+ .auth_and_reset = pil_q6v4_lpass_boot,
+ .shutdown = pil_q6v4_lpass_shutdown,
+ .proxy_vote = pil_q6v4_make_proxy_votes,
+ .proxy_unvote = pil_q6v4_remove_proxy_votes,
+};
+
+static struct pil_reset_ops pil_q6v4_lpass_ops_trusted = {
+ .init_image = pil_q6v4_init_image_trusted,
+ .auth_and_reset = pil_q6v4_boot_trusted,
+ .shutdown = pil_q6v4_shutdown_trusted,
+ .proxy_vote = pil_q6v4_make_proxy_votes,
+ .proxy_unvote = pil_q6v4_remove_proxy_votes,
+};
+
+static int __devinit pil_q6v4_lpass_driver_probe(struct platform_device *pdev)
+{
+ const struct pil_q6v4_pdata *pdata = pdev->dev.platform_data;
+ struct q6v4_data *drv;
+ struct pil_desc *desc;
+ struct resource *res;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -EINVAL;
+
+ drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
+ if (!drv)
+ return -ENOMEM;
+ platform_set_drvdata(pdev, drv);
+
+ drv->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+ if (!drv->base)
+ return -ENOMEM;
+
+ drv->vreg = devm_regulator_get(&pdev->dev, "core_vdd");
+ if (IS_ERR(drv->vreg))
+ return PTR_ERR(drv->vreg);
+
+ drv->xo = devm_clk_get(&pdev->dev, "xo");
+ if (IS_ERR(drv->xo))
+ return PTR_ERR(drv->xo);
+
+ desc = &drv->desc;
+ desc->name = pdata->name;
+ desc->dev = &pdev->dev;
+ desc->owner = THIS_MODULE;
+ desc->proxy_timeout = 10000;
+ pil_q6v4_init(drv, pdata);
+
+ if (pas_supported(pdata->pas_id) > 0) {
+ desc->ops = &pil_q6v4_lpass_ops_trusted;
+ dev_info(&pdev->dev, "using secure boot\n");
+ } else {
+ desc->ops = &pil_q6v4_lpass_ops;
+ dev_info(&pdev->dev, "using non-secure boot\n");
+ }
+
+ drv->pil = msm_pil_register(desc);
+ if (IS_ERR(drv->pil))
+ return PTR_ERR(drv->pil);
+ return 0;
+}
+
+static int __devexit pil_q6v4_lpass_driver_exit(struct platform_device *pdev)
+{
+ struct q6v4_data *drv = platform_get_drvdata(pdev);
+ msm_pil_unregister(drv->pil);
+ return 0;
+}
+
+static struct platform_driver pil_q6v4_lpass_driver = {
+ .probe = pil_q6v4_lpass_driver_probe,
+ .remove = __devexit_p(pil_q6v4_lpass_driver_exit),
+ .driver = {
+ .name = "pil-q6v4-lpass",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init pil_q6v4_lpass_init(void)
+{
+ return platform_driver_register(&pil_q6v4_lpass_driver);
+}
+module_init(pil_q6v4_lpass_init);
+
+static void __exit pil_q6v4_lpass_exit(void)
+{
+ platform_driver_unregister(&pil_q6v4_lpass_driver);
+}
+module_exit(pil_q6v4_lpass_exit);
+
+MODULE_DESCRIPTION("Support for booting QDSP6v4 (Hexagon) processors");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/pil-q6v4-mss.c b/arch/arm/mach-msm/pil-q6v4-mss.c
new file mode 100644
index 0000000..65b56d3
--- /dev/null
+++ b/arch/arm/mach-msm/pil-q6v4-mss.c
@@ -0,0 +1,264 @@
+/* Copyright (c) 2012, 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/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+
+#include <mach/msm_iomap.h>
+
+#include "peripheral-loader.h"
+#include "pil-q6v4.h"
+#include "scm-pas.h"
+
+#define MSS_S_HCLK_CTL (MSM_CLK_CTL_BASE + 0x2C70)
+#define MSS_SLP_CLK_CTL (MSM_CLK_CTL_BASE + 0x2C60)
+#define SFAB_MSS_M_ACLK_CTL (MSM_CLK_CTL_BASE + 0x2340)
+#define SFAB_MSS_S_HCLK_CTL (MSM_CLK_CTL_BASE + 0x2C00)
+#define MSS_RESET (MSM_CLK_CTL_BASE + 0x2C64)
+
+struct q6v4_modem {
+ struct q6v4_data q6_fw;
+ struct q6v4_data q6_sw;
+ void __iomem *modem_base;
+};
+
+static DEFINE_MUTEX(pil_q6v4_modem_lock);
+static unsigned pil_q6v4_modem_count;
+
+/* Bring modem subsystem out of reset */
+static void pil_q6v4_init_modem(void __iomem *base, void __iomem *jtag_clk)
+{
+ mutex_lock(&pil_q6v4_modem_lock);
+ if (!pil_q6v4_modem_count) {
+ /* Enable MSS clocks */
+ writel_relaxed(0x10, SFAB_MSS_M_ACLK_CTL);
+ writel_relaxed(0x10, SFAB_MSS_S_HCLK_CTL);
+ writel_relaxed(0x10, MSS_S_HCLK_CTL);
+ writel_relaxed(0x10, MSS_SLP_CLK_CTL);
+ /* Wait for clocks to enable */
+ mb();
+ udelay(10);
+
+ /* De-assert MSS reset */
+ writel_relaxed(0x0, MSS_RESET);
+ mb();
+ udelay(10);
+ /* Enable MSS */
+ writel_relaxed(0x7, base);
+ }
+
+ /* Enable JTAG clocks */
+ /* TODO: Remove if/when Q6 software enables them? */
+ writel_relaxed(0x10, jtag_clk);
+
+ pil_q6v4_modem_count++;
+ mutex_unlock(&pil_q6v4_modem_lock);
+}
+
+/* Put modem subsystem back into reset */
+static void pil_q6v4_shutdown_modem(void)
+{
+ mutex_lock(&pil_q6v4_modem_lock);
+ if (pil_q6v4_modem_count)
+ pil_q6v4_modem_count--;
+ if (pil_q6v4_modem_count == 0)
+ writel_relaxed(0x1, MSS_RESET);
+ mutex_unlock(&pil_q6v4_modem_lock);
+}
+
+static int pil_q6v4_modem_boot(struct pil_desc *pil)
+{
+ struct q6v4_data *drv = pil_to_q6v4_data(pil);
+ struct q6v4_modem *mdm = dev_get_drvdata(pil->dev);
+ int err;
+
+ err = pil_q6v4_power_up(drv);
+ if (err)
+ return err;
+
+ pil_q6v4_init_modem(mdm->modem_base, drv->jtag_clk_reg);
+ return pil_q6v4_boot(pil);
+}
+
+static int pil_q6v4_modem_shutdown(struct pil_desc *pil)
+{
+ struct q6v4_data *drv = pil_to_q6v4_data(pil);
+ int ret;
+
+ ret = pil_q6v4_shutdown(pil);
+ if (ret)
+ return ret;
+ pil_q6v4_shutdown_modem();
+ pil_q6v4_power_down(drv);
+ return 0;
+}
+
+static struct pil_reset_ops pil_q6v4_modem_ops = {
+ .init_image = pil_q6v4_init_image,
+ .auth_and_reset = pil_q6v4_modem_boot,
+ .shutdown = pil_q6v4_modem_shutdown,
+ .proxy_vote = pil_q6v4_make_proxy_votes,
+ .proxy_unvote = pil_q6v4_remove_proxy_votes,
+};
+
+static struct pil_reset_ops pil_q6v4_modem_ops_trusted = {
+ .init_image = pil_q6v4_init_image_trusted,
+ .auth_and_reset = pil_q6v4_boot_trusted,
+ .shutdown = pil_q6v4_shutdown_trusted,
+ .proxy_vote = pil_q6v4_make_proxy_votes,
+ .proxy_unvote = pil_q6v4_remove_proxy_votes,
+};
+
+static int __devinit
+pil_q6v4_proc_init(struct q6v4_data *drv, struct platform_device *pdev, int i)
+{
+ static const char *name[2] = { "fw", "sw" };
+ const struct pil_q6v4_pdata *pdata_p = pdev->dev.platform_data;
+ const struct pil_q6v4_pdata *pdata = pdata_p + i;
+ char reg_name[12];
+ struct pil_desc *desc;
+ struct resource *res;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1 + i);
+ if (!res)
+ return -EINVAL;
+
+ drv->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+ if (!drv->base)
+ return -ENOMEM;
+
+ snprintf(reg_name, sizeof(reg_name), "%s_core_vdd", name[i]);
+ drv->vreg = devm_regulator_get(&pdev->dev, reg_name);
+ if (IS_ERR(drv->vreg))
+ return PTR_ERR(drv->vreg);
+
+ drv->xo = devm_clk_get(&pdev->dev, "xo");
+ if (IS_ERR(drv->xo))
+ return PTR_ERR(drv->xo);
+
+ desc = &drv->desc;
+ desc->name = pdata->name;
+ desc->depends_on = pdata->depends;
+ desc->dev = &pdev->dev;
+ desc->owner = THIS_MODULE;
+ desc->proxy_timeout = 10000;
+ pil_q6v4_init(drv, pdata);
+
+ if (pas_supported(pdata->pas_id) > 0) {
+ desc->ops = &pil_q6v4_modem_ops_trusted;
+ dev_info(&pdev->dev, "using secure boot for %s\n", name[i]);
+ } else {
+ desc->ops = &pil_q6v4_modem_ops;
+ dev_info(&pdev->dev, "using non-secure boot for %s\n", name[i]);
+ }
+ return 0;
+}
+
+static int __devinit pil_q6v4_modem_driver_probe(struct platform_device *pdev)
+{
+ struct q6v4_data *drv_fw, *drv_sw;
+ struct q6v4_modem *drv;
+ struct resource *res;
+ struct regulator *pll_supply;
+ int ret;
+
+ drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
+ if (!drv)
+ return -ENOMEM;
+ platform_set_drvdata(pdev, drv);
+
+ drv_fw = &drv->q6_fw;
+ drv_sw = &drv->q6_sw;
+
+ ret = pil_q6v4_proc_init(drv_fw, pdev, 0);
+ if (ret)
+ return ret;
+
+ ret = pil_q6v4_proc_init(drv_sw, pdev, 1);
+ if (ret)
+ return ret;
+
+ pll_supply = devm_regulator_get(&pdev->dev, "pll_vdd");
+ drv_fw->pll_supply = drv_sw->pll_supply = pll_supply;
+ if (IS_ERR(pll_supply))
+ return PTR_ERR(pll_supply);
+
+ ret = regulator_set_voltage(pll_supply, 1800000, 1800000);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to set pll voltage\n");
+ return ret;
+ }
+
+ ret = regulator_set_optimum_mode(pll_supply, 100000);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to set pll optimum mode\n");
+ return ret;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -EINVAL;
+
+ drv->modem_base = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (!drv->modem_base)
+ return -ENOMEM;
+
+ drv_fw->pil = msm_pil_register(&drv_fw->desc);
+ if (IS_ERR(drv_fw->pil))
+ return PTR_ERR(drv_fw->pil);
+
+ drv_sw->pil = msm_pil_register(&drv_sw->desc);
+ if (IS_ERR(drv_sw->pil)) {
+ msm_pil_unregister(drv_fw->pil);
+ return PTR_ERR(drv_sw->pil);
+ }
+ return 0;
+}
+
+static int __devexit pil_q6v4_modem_driver_exit(struct platform_device *pdev)
+{
+ struct q6v4_modem *drv = platform_get_drvdata(pdev);
+ msm_pil_unregister(drv->q6_sw.pil);
+ msm_pil_unregister(drv->q6_fw.pil);
+ return 0;
+}
+
+static struct platform_driver pil_q6v4_modem_driver = {
+ .probe = pil_q6v4_modem_driver_probe,
+ .remove = __devexit_p(pil_q6v4_modem_driver_exit),
+ .driver = {
+ .name = "pil-q6v4-modem",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init pil_q6v4_modem_init(void)
+{
+ return platform_driver_register(&pil_q6v4_modem_driver);
+}
+module_init(pil_q6v4_modem_init);
+
+static void __exit pil_q6v4_modem_exit(void)
+{
+ platform_driver_unregister(&pil_q6v4_modem_driver);
+}
+module_exit(pil_q6v4_modem_exit);
+
+MODULE_DESCRIPTION("Support for booting QDSP6v4 (Hexagon) processors");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/pil-q6v4.c b/arch/arm/mach-msm/pil-q6v4.c
index 32cce1d..47033fc 100644
--- a/arch/arm/mach-msm/pil-q6v4.c
+++ b/arch/arm/mach-msm/pil-q6v4.c
@@ -22,7 +22,6 @@
#include <linux/clk.h>
#include <mach/msm_bus.h>
-#include <mach/msm_iomap.h>
#include "peripheral-loader.h"
#include "pil-q6v4.h"
@@ -35,12 +34,6 @@
#define QDSP6SS_GFMUX_CTL 0x30
#define QDSP6SS_PWR_CTL 0x38
-#define MSS_S_HCLK_CTL (MSM_CLK_CTL_BASE + 0x2C70)
-#define MSS_SLP_CLK_CTL (MSM_CLK_CTL_BASE + 0x2C60)
-#define SFAB_MSS_M_ACLK_CTL (MSM_CLK_CTL_BASE + 0x2340)
-#define SFAB_MSS_S_HCLK_CTL (MSM_CLK_CTL_BASE + 0x2C00)
-#define MSS_RESET (MSM_CLK_CTL_BASE + 0x2C64)
-
#define Q6SS_SS_ARES BIT(0)
#define Q6SS_CORE_ARES BIT(1)
#define Q6SS_ISDB_ARES BIT(2)
@@ -59,29 +52,19 @@
#define Q6SS_CLK_ENA BIT(1)
#define Q6SS_SRC_SWITCH_CLK_OVR BIT(8)
-struct q6v4_data {
- void __iomem *base;
- void __iomem *modem_base;
- unsigned long start_addr;
- struct regulator *vreg;
- struct regulator *pll_supply;
- bool vreg_enabled;
- struct clk *xo;
- struct pil_device *pil;
-};
-
-static int pil_q6v4_init_image(struct pil_desc *pil, const u8 *metadata,
+int pil_q6v4_init_image(struct pil_desc *pil, const u8 *metadata,
size_t size)
{
const struct elf32_hdr *ehdr = (struct elf32_hdr *)metadata;
- struct q6v4_data *drv = dev_get_drvdata(pil->dev);
+ struct q6v4_data *drv = pil_to_q6v4_data(pil);
drv->start_addr = ehdr->e_entry;
return 0;
}
+EXPORT_SYMBOL(pil_q6v4_init_image);
-static int pil_q6v4_make_proxy_votes(struct pil_desc *pil)
+int pil_q6v4_make_proxy_votes(struct pil_desc *pil)
{
- const struct q6v4_data *drv = dev_get_drvdata(pil->dev);
+ const struct q6v4_data *drv = pil_to_q6v4_data(pil);
int ret;
ret = clk_prepare_enable(drv->xo);
@@ -102,19 +85,21 @@
err:
return ret;
}
+EXPORT_SYMBOL(pil_q6v4_make_proxy_votes);
-static void pil_q6v4_remove_proxy_votes(struct pil_desc *pil)
+void pil_q6v4_remove_proxy_votes(struct pil_desc *pil)
{
- const struct q6v4_data *drv = dev_get_drvdata(pil->dev);
+ const struct q6v4_data *drv = pil_to_q6v4_data(pil);
if (drv->pll_supply)
regulator_disable(drv->pll_supply);
clk_disable_unprepare(drv->xo);
}
+EXPORT_SYMBOL(pil_q6v4_remove_proxy_votes);
-static int pil_q6v4_power_up(struct device *dev)
+int pil_q6v4_power_up(struct q6v4_data *drv)
{
int err;
- struct q6v4_data *drv = dev_get_drvdata(dev);
+ struct device *dev = drv->desc.dev;
err = regulator_set_voltage(drv->vreg, 743750, 743750);
if (err) {
@@ -141,68 +126,27 @@
drv->vreg_enabled = true;
return 0;
}
+EXPORT_SYMBOL(pil_q6v4_power_up);
-static DEFINE_MUTEX(pil_q6v4_modem_lock);
-static unsigned pil_q6v4_modem_count;
-
-/* Bring modem subsystem out of reset */
-static void pil_q6v4_init_modem(void __iomem *base, void __iomem *jtag_clk)
+void pil_q6v4_power_down(struct q6v4_data *drv)
{
- mutex_lock(&pil_q6v4_modem_lock);
- if (!pil_q6v4_modem_count) {
- /* Enable MSS clocks */
- writel_relaxed(0x10, SFAB_MSS_M_ACLK_CTL);
- writel_relaxed(0x10, SFAB_MSS_S_HCLK_CTL);
- writel_relaxed(0x10, MSS_S_HCLK_CTL);
- writel_relaxed(0x10, MSS_SLP_CLK_CTL);
- /* Wait for clocks to enable */
- mb();
- udelay(10);
-
- /* De-assert MSS reset */
- writel_relaxed(0x0, MSS_RESET);
- mb();
- udelay(10);
- /* Enable MSS */
- writel_relaxed(0x7, base);
+ if (drv->vreg_enabled) {
+ regulator_disable(drv->vreg);
+ drv->vreg_enabled = false;
}
-
- /* Enable JTAG clocks */
- /* TODO: Remove if/when Q6 software enables them? */
- writel_relaxed(0x10, jtag_clk);
-
- pil_q6v4_modem_count++;
- mutex_unlock(&pil_q6v4_modem_lock);
}
+EXPORT_SYMBOL(pil_q6v4_power_down);
-/* Put modem subsystem back into reset */
-static void pil_q6v4_shutdown_modem(void)
-{
- mutex_lock(&pil_q6v4_modem_lock);
- if (pil_q6v4_modem_count)
- pil_q6v4_modem_count--;
- if (pil_q6v4_modem_count == 0)
- writel_relaxed(0x1, MSS_RESET);
- mutex_unlock(&pil_q6v4_modem_lock);
-}
-
-static int pil_q6v4_reset(struct pil_desc *pil)
+int pil_q6v4_boot(struct pil_desc *pil)
{
u32 reg, err;
- const struct q6v4_data *drv = dev_get_drvdata(pil->dev);
- const struct pil_q6v4_pdata *pdata = pil->dev->platform_data;
+ const struct q6v4_data *drv = pil_to_q6v4_data(pil);
- err = pil_q6v4_power_up(pil->dev);
- if (err)
- return err;
/* Enable Q6 ACLK */
- writel_relaxed(0x10, pdata->aclk_reg);
-
- if (drv->modem_base)
- pil_q6v4_init_modem(drv->modem_base, pdata->jtag_clk_reg);
+ writel_relaxed(0x10, drv->aclk_reg);
/* Unhalt bus port */
- err = msm_bus_axi_portunhalt(pdata->bus_port);
+ err = msm_bus_axi_portunhalt(drv->bus_port);
if (err)
dev_err(pil->dev, "Failed to unhalt bus port\n");
@@ -216,8 +160,8 @@
drv->base + QDSP6SS_RST_EVB);
/* Program TCM and AHB address ranges */
- writel_relaxed(pdata->strap_tcm_base, drv->base + QDSP6SS_STRAP_TCM);
- writel_relaxed(pdata->strap_ahb_upper | pdata->strap_ahb_lower,
+ writel_relaxed(drv->strap_tcm_base, drv->base + QDSP6SS_STRAP_TCM);
+ writel_relaxed(drv->strap_ahb_upper | drv->strap_ahb_lower,
drv->base + QDSP6SS_STRAP_AHB);
/* Turn off Q6 core clock */
@@ -257,15 +201,15 @@
return 0;
}
+EXPORT_SYMBOL(pil_q6v4_boot);
-static int pil_q6v4_shutdown(struct pil_desc *pil)
+int pil_q6v4_shutdown(struct pil_desc *pil)
{
u32 reg;
- struct q6v4_data *drv = dev_get_drvdata(pil->dev);
- const struct pil_q6v4_pdata *pdata = pil->dev->platform_data;
+ struct q6v4_data *drv = pil_to_q6v4_data(pil);
/* Make sure bus port is halted */
- msm_bus_axi_porthalt(pdata->bus_port);
+ msm_bus_axi_porthalt(drv->bus_port);
/* Turn off Q6 core clock */
writel_relaxed(Q6SS_SRC_SWITCH_CLK_OVR,
@@ -279,188 +223,67 @@
/* Turn off Q6 memories */
writel_relaxed(Q6SS_CLAMP_IO, drv->base + QDSP6SS_PWR_CTL);
- if (drv->modem_base)
- pil_q6v4_shutdown_modem();
-
- if (drv->vreg_enabled) {
- regulator_disable(drv->vreg);
- drv->vreg_enabled = false;
- }
-
return 0;
}
+EXPORT_SYMBOL(pil_q6v4_shutdown);
-static struct pil_reset_ops pil_q6v4_ops = {
- .init_image = pil_q6v4_init_image,
- .auth_and_reset = pil_q6v4_reset,
- .shutdown = pil_q6v4_shutdown,
- .proxy_vote = pil_q6v4_make_proxy_votes,
- .proxy_unvote = pil_q6v4_remove_proxy_votes,
-};
-
-static int pil_q6v4_init_image_trusted(struct pil_desc *pil,
+int pil_q6v4_init_image_trusted(struct pil_desc *pil,
const u8 *metadata, size_t size)
{
- const struct pil_q6v4_pdata *pdata = pil->dev->platform_data;
- return pas_init_image(pdata->pas_id, metadata, size);
+ struct q6v4_data *drv = pil_to_q6v4_data(pil);
+ return pas_init_image(drv->pas_id, metadata, size);
}
+EXPORT_SYMBOL(pil_q6v4_init_image_trusted);
-static int pil_q6v4_reset_trusted(struct pil_desc *pil)
+int pil_q6v4_boot_trusted(struct pil_desc *pil)
{
- const struct pil_q6v4_pdata *pdata = pil->dev->platform_data;
+ struct q6v4_data *drv = pil_to_q6v4_data(pil);
int err;
- err = pil_q6v4_power_up(pil->dev);
+ err = pil_q6v4_power_up(drv);
if (err)
return err;
/* Unhalt bus port */
- err = msm_bus_axi_portunhalt(pdata->bus_port);
+ err = msm_bus_axi_portunhalt(drv->bus_port);
if (err)
dev_err(pil->dev, "Failed to unhalt bus port\n");
- return pas_auth_and_reset(pdata->pas_id);
+ return pas_auth_and_reset(drv->pas_id);
}
+EXPORT_SYMBOL(pil_q6v4_boot_trusted);
-static int pil_q6v4_shutdown_trusted(struct pil_desc *pil)
+int pil_q6v4_shutdown_trusted(struct pil_desc *pil)
{
int ret;
- struct q6v4_data *drv = dev_get_drvdata(pil->dev);
- struct pil_q6v4_pdata *pdata = pil->dev->platform_data;
+ struct q6v4_data *drv = pil_to_q6v4_data(pil);
/* Make sure bus port is halted */
- msm_bus_axi_porthalt(pdata->bus_port);
+ msm_bus_axi_porthalt(drv->bus_port);
- ret = pas_shutdown(pdata->pas_id);
+ ret = pas_shutdown(drv->pas_id);
if (ret)
return ret;
- if (drv->vreg_enabled) {
- regulator_disable(drv->vreg);
- drv->vreg_enabled = false;
- }
+ pil_q6v4_power_down(drv);
return ret;
}
+EXPORT_SYMBOL(pil_q6v4_shutdown_trusted);
-static struct pil_reset_ops pil_q6v4_ops_trusted = {
- .init_image = pil_q6v4_init_image_trusted,
- .auth_and_reset = pil_q6v4_reset_trusted,
- .shutdown = pil_q6v4_shutdown_trusted,
- .proxy_vote = pil_q6v4_make_proxy_votes,
- .proxy_unvote = pil_q6v4_remove_proxy_votes,
-};
-
-static int __devinit pil_q6v4_driver_probe(struct platform_device *pdev)
+void __devinit
+pil_q6v4_init(struct q6v4_data *drv, const struct pil_q6v4_pdata *pdata)
{
- const struct pil_q6v4_pdata *pdata = pdev->dev.platform_data;
- struct q6v4_data *drv;
- struct resource *res;
- struct pil_desc *desc;
- int ret;
+ drv->strap_tcm_base = pdata->strap_tcm_base;
+ drv->strap_ahb_upper = pdata->strap_ahb_upper;
+ drv->strap_ahb_lower = pdata->strap_ahb_lower;
+ drv->aclk_reg = pdata->aclk_reg;
+ drv->jtag_clk_reg = pdata->jtag_clk_reg;
+ drv->pas_id = pdata->pas_id;
+ drv->bus_port = pdata->bus_port;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- return -EINVAL;
-
- drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
- if (!drv)
- return -ENOMEM;
- platform_set_drvdata(pdev, drv);
-
- drv->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
- if (!drv->base)
- return -ENOMEM;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- if (res) {
- drv->modem_base = devm_ioremap(&pdev->dev, res->start,
- resource_size(res));
- if (!drv->modem_base)
- return -ENOMEM;
- }
-
- desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL);
- if (!desc)
- return -ENOMEM;
-
- drv->pll_supply = devm_regulator_get(&pdev->dev, "pll_vdd");
- if (IS_ERR(drv->pll_supply)) {
- drv->pll_supply = NULL;
- } else {
- ret = regulator_set_voltage(drv->pll_supply, 1800000, 1800000);
- if (ret) {
- dev_err(&pdev->dev, "failed to set pll voltage\n");
- return ret;
- }
-
- ret = regulator_set_optimum_mode(drv->pll_supply, 100000);
- if (ret < 0) {
- dev_err(&pdev->dev, "failed to set pll optimum mode\n");
- return ret;
- }
- }
-
- desc->name = pdata->name;
- desc->depends_on = pdata->depends;
- desc->dev = &pdev->dev;
- desc->owner = THIS_MODULE;
- desc->proxy_timeout = 10000;
-
- if (pas_supported(pdata->pas_id) > 0) {
- desc->ops = &pil_q6v4_ops_trusted;
- dev_info(&pdev->dev, "using secure boot\n");
- } else {
- desc->ops = &pil_q6v4_ops;
- dev_info(&pdev->dev, "using non-secure boot\n");
- }
-
- drv->vreg = devm_regulator_get(&pdev->dev, "core_vdd");
- if (IS_ERR(drv->vreg))
- return PTR_ERR(drv->vreg);
-
- ret = regulator_set_optimum_mode(drv->vreg, 100000);
- if (ret < 0) {
- dev_err(&pdev->dev, "Failed to set regulator's mode.\n");
- return ret;
- }
-
- drv->xo = devm_clk_get(&pdev->dev, "xo");
- if (IS_ERR(drv->xo))
- return PTR_ERR(drv->xo);
-
- drv->pil = msm_pil_register(desc);
- if (IS_ERR(drv->pil))
- return PTR_ERR(drv->pil);
- return 0;
+ regulator_set_optimum_mode(drv->vreg, 100000);
}
-
-static int __devexit pil_q6v4_driver_exit(struct platform_device *pdev)
-{
- struct q6v4_data *drv = platform_get_drvdata(pdev);
- msm_pil_unregister(drv->pil);
- return 0;
-}
-
-static struct platform_driver pil_q6v4_driver = {
- .probe = pil_q6v4_driver_probe,
- .remove = __devexit_p(pil_q6v4_driver_exit),
- .driver = {
- .name = "pil_qdsp6v4",
- .owner = THIS_MODULE,
- },
-};
-
-static int __init pil_q6v4_init(void)
-{
- return platform_driver_register(&pil_q6v4_driver);
-}
-module_init(pil_q6v4_init);
-
-static void __exit pil_q6v4_exit(void)
-{
- platform_driver_unregister(&pil_q6v4_driver);
-}
-module_exit(pil_q6v4_exit);
+EXPORT_SYMBOL(pil_q6v4_init);
MODULE_DESCRIPTION("Support for booting QDSP6v4 (Hexagon) processors");
MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/pil-q6v4.h b/arch/arm/mach-msm/pil-q6v4.h
index b0b97d0..d280d84 100644
--- a/arch/arm/mach-msm/pil-q6v4.h
+++ b/arch/arm/mach-msm/pil-q6v4.h
@@ -12,6 +12,8 @@
#ifndef __MSM_PIL_Q6V4_H
#define __MSM_PIL_Q6V4_H
+#include "peripheral-loader.h"
+
struct pil_q6v4_pdata {
const unsigned long strap_tcm_base;
const unsigned long strap_ahb_upper;
@@ -23,4 +25,50 @@
const unsigned pas_id;
int bus_port;
};
+
+struct clk;
+struct pil_device;
+struct regulator;
+
+/**
+ * struct q6v4_data - Q6 processor
+ */
+struct q6v4_data {
+ void __iomem *base;
+ unsigned long start_addr;
+ unsigned long strap_tcm_base;
+ unsigned long strap_ahb_upper;
+ unsigned long strap_ahb_lower;
+ void __iomem *aclk_reg;
+ void __iomem *jtag_clk_reg;
+ unsigned pas_id;
+ int bus_port;
+
+ struct regulator *vreg;
+ struct regulator *pll_supply;
+ bool vreg_enabled;
+ struct clk *xo;
+
+ struct pil_device *pil;
+ struct pil_desc desc;
+};
+
+#define pil_to_q6v4_data(p) container_of(p, struct q6v4_data, desc)
+
+extern int pil_q6v4_init_image(struct pil_desc *pil, const u8 *metadata,
+ size_t size);
+extern int pil_q6v4_make_proxy_votes(struct pil_desc *pil);
+extern void pil_q6v4_remove_proxy_votes(struct pil_desc *pil);
+extern int pil_q6v4_power_up(struct q6v4_data *drv);
+extern void pil_q6v4_power_down(struct q6v4_data *drv);
+extern int pil_q6v4_boot(struct pil_desc *pil);
+extern int pil_q6v4_shutdown(struct pil_desc *pil);
+
+extern int pil_q6v4_init_image_trusted(struct pil_desc *pil,
+ const u8 *metadata, size_t size);
+extern int pil_q6v4_boot_trusted(struct pil_desc *pil);
+extern int pil_q6v4_shutdown_trusted(struct pil_desc *pil);
+extern void __devinit
+pil_q6v4_init(struct q6v4_data *drv, const struct pil_q6v4_pdata *p);
+
#endif
diff --git a/arch/arm/mach-msm/pil-q6v5-mss.c b/arch/arm/mach-msm/pil-q6v5-mss.c
index 7b45a0e..9ff1234 100644
--- a/arch/arm/mach-msm/pil-q6v5-mss.c
+++ b/arch/arm/mach-msm/pil-q6v5-mss.c
@@ -79,7 +79,6 @@
static int pil_mss_enable_clks(struct q6v5_data *drv)
{
int ret;
- void __iomem *mpll1_config_ctl;
ret = clk_prepare_enable(drv->ahb_clk);
if (ret)
@@ -91,12 +90,6 @@
if (ret)
goto err_rom_clk;
- /* TODO: Remove when support for 8974v1.0 HW is dropped. */
- mpll1_config_ctl = ioremap(0xFC981034, 0x4);
- writel_relaxed(0x0300403D, mpll1_config_ctl);
- mb();
- iounmap(mpll1_config_ctl);
-
return 0;
err_rom_clk:
diff --git a/arch/arm/mach-msm/platsmp-8625.c b/arch/arm/mach-msm/platsmp-8625.c
index e8f8c59..3b31b9f 100644
--- a/arch/arm/mach-msm/platsmp-8625.c
+++ b/arch/arm/mach-msm/platsmp-8625.c
@@ -120,7 +120,7 @@
*/
write_pen_release(-1);
- /* clear the IPC1(SPI-8) pending SPI */
+ /* clear the IPC pending SPI */
if (power_collapsed) {
raise_clear_spi(cpu, false);
clear_pending_spi(cpu_data[cpu].ipc_irq);
@@ -173,9 +173,9 @@
return 0;
}
-void __iomem *core1_reset_base(void)
+void __iomem *core_reset_base(unsigned int cpu)
{
- return cpu_data[1].reset_core_base;
+ return cpu_data[cpu].reset_core_base;
}
int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
@@ -217,7 +217,7 @@
*/
if (power_collapsed) {
- core1_gic_configure_and_raise();
+ gic_configure_and_raise(cpu_data[cpu].ipc_irq, cpu);
raise_clear_spi(cpu, true);
} else {
gic_raise_softirq(cpumask_of(cpu), 1);
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index 60ee8f0..0339c21 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -30,6 +30,7 @@
#include <mach/system.h>
#include <mach/scm.h>
#include <mach/socinfo.h>
+#include <mach/msm-krait-l2-accessors.h>
#include <asm/cacheflush.h>
#include <asm/hardware/gic.h>
#include <asm/pgtable.h>
@@ -413,10 +414,63 @@
}
EXPORT_SYMBOL(msm_pm_set_max_sleep_time);
+struct reg_data {
+ uint32_t reg;
+ uint32_t val;
+};
-/******************************************************************************
- *
- *****************************************************************************/
+static struct reg_data reg_saved_state[] = {
+ { .reg = 0x4501, },
+ { .reg = 0x5501, },
+ { .reg = 0x6501, },
+ { .reg = 0x7501, },
+ { .reg = 0x0500, },
+};
+
+static unsigned int active_vdd;
+static bool msm_pm_save_cp15;
+static const unsigned int pc_vdd = 0x98;
+
+static void msm_pm_save_cpu_reg(void)
+{
+ int i;
+
+ /* Only on core0 */
+ if (smp_processor_id())
+ return;
+
+ /**
+ * On some targets, L2 PC will turn off may reset the core
+ * configuration for the mux and the default may not make the core
+ * happy when it resumes.
+ * Save the active vdd, and set the core vdd to QSB max vdd, so that
+ * when the core resumes, it is capable of supporting the current QSB
+ * rate. Then restore the active vdd before switching the acpuclk rate.
+ */
+ if (msm_pm_get_l2_flush_flag() == 1) {
+ active_vdd = msm_spm_get_vdd(0);
+ for (i = 0; i < ARRAY_SIZE(reg_saved_state); i++)
+ reg_saved_state[i].val =
+ get_l2_indirect_reg(reg_saved_state[i].reg);
+ msm_spm_set_vdd(0, pc_vdd);
+ }
+}
+
+static void msm_pm_restore_cpu_reg(void)
+{
+ int i;
+
+ /* Only on core0 */
+ if (smp_processor_id())
+ return;
+
+ if (msm_pm_get_l2_flush_flag() == 1) {
+ for (i = 0; i < ARRAY_SIZE(reg_saved_state); i++)
+ set_l2_indirect_reg(reg_saved_state[i].reg,
+ reg_saved_state[i].val);
+ msm_spm_set_vdd(0, active_vdd);
+ }
+}
static void *msm_pm_idle_rs_limits;
static bool msm_pm_use_qtimer;
@@ -558,8 +612,14 @@
pr_info("CPU%u: %s: change clock rate (old rate = %lu)\n",
cpu, __func__, saved_acpuclk_rate);
+ if (msm_pm_save_cp15)
+ msm_pm_save_cpu_reg();
+
collapsed = msm_pm_spm_power_collapse(cpu, from_idle, true);
+ if (msm_pm_save_cp15)
+ msm_pm_restore_cpu_reg();
+
if (cpu_online(cpu)) {
if (MSM_PM_DEBUG_CLOCK & msm_pm_debug_mask)
pr_info("CPU%u: %s: restore clock rate to %lu\n",
@@ -593,9 +653,12 @@
return collapsed;
}
-static void msm_pm_qtimer_available(void)
+static void msm_pm_target_init(void)
{
- if (machine_is_msm8974())
+ if (cpu_is_apq8064())
+ msm_pm_save_cp15 = true;
+
+ if (cpu_is_msm8974())
msm_pm_use_qtimer = true;
}
@@ -1087,7 +1150,7 @@
msm_pm_add_stats(enable_stats, ARRAY_SIZE(enable_stats));
suspend_set_ops(&msm_pm_ops);
- msm_pm_qtimer_available();
+ msm_pm_target_init();
hrtimer_init(&pm_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
msm_cpuidle_init();
platform_driver_register(&msm_pc_counter_driver);
diff --git a/arch/arm/mach-msm/pm-boot.c b/arch/arm/mach-msm/pm-boot.c
index ed15a0c..7bc4fe0 100644
--- a/arch/arm/mach-msm/pm-boot.c
+++ b/arch/arm/mach-msm/pm-boot.c
@@ -211,7 +211,10 @@
char *key = NULL;
uint32_t val = 0;
int ret = 0;
- int flag = 0;
+ uint32_t vaddr_val;
+
+ pdata.p_addr = 0;
+ vaddr_val = 0;
key = "qcom,mode";
ret = of_property_read_u32(pdev->dev.of_node, key, &val);
@@ -223,24 +226,43 @@
key = "qcom,phy-addr";
ret = of_property_read_u32(pdev->dev.of_node, key, &val);
- if (ret && pdata.mode == MSM_PM_BOOT_CONFIG_RESET_VECTOR_PHYS)
- goto fail;
- if (!ret) {
+ if (!ret)
pdata.p_addr = val;
- flag++;
- }
+
key = "qcom,virt-addr";
- ret = of_property_read_u32(pdev->dev.of_node, key, &val);
- if (ret && pdata.mode == MSM_PM_BOOT_CONFIG_RESET_VECTOR_VIRT)
- goto fail;
- if (!ret) {
- pdata.v_addr = (void *)val;
- flag++;
- }
+ ret = of_property_read_u32(pdev->dev.of_node, key, &vaddr_val);
- if (pdata.mode == MSM_PM_BOOT_CONFIG_REMAP_BOOT_ADDR && (flag != 2)) {
- key = "addresses for boot remap";
+ switch (pdata.mode) {
+ case MSM_PM_BOOT_CONFIG_RESET_VECTOR_PHYS:
+ if (!pdata.p_addr) {
+ key = "qcom,phy-addr";
+ goto fail;
+ }
+ break;
+ case MSM_PM_BOOT_CONFIG_RESET_VECTOR_VIRT:
+ if (!vaddr_val)
+ goto fail;
+
+ pdata.v_addr = (void *)vaddr_val;
+ break;
+ case MSM_PM_BOOT_CONFIG_REMAP_BOOT_ADDR:
+ if (!vaddr_val)
+ goto fail;
+
+ pdata.v_addr = ioremap_nocache(vaddr_val, SZ_8);
+
+ pdata.p_addr = allocate_contiguous_ebi_nomap(SZ_8, SZ_64K);
+ if (!pdata.p_addr) {
+ key = "qcom,phy-addr";
+ goto fail;
+ }
+ break;
+ case MSM_PM_BOOT_CONFIG_TZ:
+ break;
+ default:
+ pr_err("%s: Unsupported boot mode %d",
+ __func__, pdata.mode);
goto fail;
}
diff --git a/arch/arm/mach-msm/pm2.c b/arch/arm/mach-msm/pm2.c
index 10c5445..427e39f 100644
--- a/arch/arm/mach-msm/pm2.c
+++ b/arch/arm/mach-msm/pm2.c
@@ -487,7 +487,7 @@
void __iomem *base_ptr;
unsigned int value = 0;
- base_ptr = core1_reset_base();
+ base_ptr = core_reset_base(1);
if (!base_ptr)
return;
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_a2dp_in.c b/arch/arm/mach-msm/qdsp5v2/audio_a2dp_in.c
index 733b7a1..e396186 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_a2dp_in.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_a2dp_in.c
@@ -5,6 +5,7 @@
*
* Copyright (C) 2008 HTC Corporation
* Copyright (C) 2008 Google, Inc.
+ * Copyright (c) 2012 The Linux Foundation. All rights reserved.
*
* All source code in this file is licensed under the following license except
* where indicated.
@@ -34,7 +35,7 @@
#include <linux/dma-mapping.h>
#include <linux/msm_audio.h>
#include <linux/msm_audio_sbc.h>
-#include <linux/android_pmem.h>
+#include <linux/msm_ion.h>
#include <linux/memory_alloc.h>
#include <mach/iommu.h>
@@ -115,6 +116,8 @@
int stopped; /* set when stopped, cleared on flush */
int abort; /* set when error, like sample rate mismatch */
char *build_id;
+ struct ion_client *client;
+ struct ion_handle *output_buff_handle;
};
static struct audio_a2dp_in the_audio_a2dp_in;
@@ -848,10 +851,11 @@
audio->audrec = NULL;
audio->opened = 0;
if (audio->data) {
- iounmap(audio->msm_map);
- free_contiguous_memory_by_paddr(audio->phys);
+ ion_unmap_kernel(audio->client, audio->output_buff_handle);
+ ion_free(audio->client, audio->output_buff_handle);
audio->data = NULL;
}
+ ion_client_destroy(audio->client);
mutex_unlock(&audio->lock);
return 0;
}
@@ -861,6 +865,11 @@
struct audio_a2dp_in *audio = &the_audio_a2dp_in;
int rc;
int encid;
+ int len = 0;
+ unsigned long ionflag = 0;
+ ion_phys_addr_t addr = 0;
+ struct ion_handle *handle = NULL;
+ struct ion_client *client = NULL;
mutex_lock(&audio->lock);
if (audio->opened) {
@@ -868,22 +877,56 @@
goto done;
}
- audio->phys = allocate_contiguous_ebi_nomap(DMASZ, SZ_4K);
- if (audio->phys) {
- audio->msm_map = ioremap(audio->phys, DMASZ);
- if (IS_ERR(audio->msm_map)) {
- MM_ERR("could not map the phys address to kernel"
- "space\n");
+ client = msm_ion_client_create(UINT_MAX, "Audio_a2dp_in_client");
+ if (IS_ERR_OR_NULL(client)) {
+ MM_ERR("Unable to create ION client\n");
rc = -ENOMEM;
- free_contiguous_memory_by_paddr(audio->phys);
- goto done;
- }
- audio->data = (u8 *)audio->msm_map;
- } else {
- MM_ERR("could not allocate DMA buffers\n");
- rc = -ENOMEM;
- goto done;
+ goto client_create_error;
}
+ audio->client = client;
+
+ MM_DBG("allocating mem sz = %d\n", DMASZ);
+ handle = ion_alloc(client, DMASZ, SZ_4K,
+ ION_HEAP(ION_AUDIO_HEAP_ID), 0);
+ if (IS_ERR_OR_NULL(handle)) {
+ MM_ERR("Unable to create allocate O/P buffers\n");
+ rc = -ENOMEM;
+ goto output_buff_alloc_error;
+ }
+
+ audio->output_buff_handle = handle;
+
+ rc = ion_phys(client , handle, &addr, &len);
+ if (rc) {
+ MM_ERR("O/P buffers:Invalid phy: %x sz: %x\n",
+ (unsigned int) addr, (unsigned int) len);
+ rc = -ENOMEM;
+ goto output_buff_get_phys_error;
+ } else {
+ MM_INFO("O/P buffers:valid phy: %x sz: %x\n",
+ (unsigned int) addr, (unsigned int) len);
+ }
+ audio->phys = (int32_t)addr;
+
+ rc = ion_handle_get_flags(client, handle, &ionflag);
+ if (rc) {
+ MM_ERR("could not get flags for the handle\n");
+ rc = -ENOMEM;
+ goto output_buff_get_flags_error;
+ }
+
+ audio->msm_map = ion_map_kernel(client, handle);
+ if (IS_ERR(audio->data)) {
+ MM_ERR("could not map read buffers,freeing instance 0x%08x\n",
+ (int)audio);
+ rc = -ENOMEM;
+ goto output_buff_map_error;
+ }
+ MM_DBG("read buf: phy addr 0x%08x kernel addr 0x%08x\n",
+ audio->phys, (int)audio->data);
+
+ audio->data = (char *)audio->msm_map;
+
MM_DBG("Memory addr = 0x%8x phy addr = 0x%8x\n",\
(int) audio->data, (int) audio->phys);
@@ -953,6 +996,13 @@
mutex_unlock(&audio->lock);
return rc;
evt_error:
+output_buff_map_error:
+output_buff_get_phys_error:
+output_buff_get_flags_error:
+ ion_free(client, audio->output_buff_handle);
+output_buff_alloc_error:
+ ion_client_destroy(client);
+client_create_error:
msm_adsp_put(audio->audrec);
audpreproc_aenc_free(audio->enc_id);
mutex_unlock(&audio->lock);
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_lpa.c b/arch/arm/mach-msm/qdsp5v2/audio_lpa.c
index 60f43b9..7ec0617 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_lpa.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_lpa.c
@@ -2,7 +2,7 @@
*
* Copyright (C) 2008 Google, Inc.
* Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2012, 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
@@ -27,7 +27,7 @@
#include <linux/delay.h>
#include <linux/earlysuspend.h>
#include <linux/list.h>
-#include <linux/android_pmem.h>
+#include <linux/msm_ion.h>
#include <asm/atomic.h>
#include <asm/ioctls.h>
#include <mach/msm_adsp.h>
@@ -136,9 +136,9 @@
union msm_audio_event_payload payload;
};
-struct audlpa_pmem_region {
+struct audlpa_ion_region {
struct list_head list;
- struct file *file;
+ struct ion_handle *handle;
int fd;
void *vaddr;
unsigned long paddr;
@@ -170,7 +170,7 @@
static void audio_dsp_event(void *private, unsigned id, uint16_t *msg);
static void audlpa_post_event(struct audio *audio, int type,
union msm_audio_event_payload payload);
-static unsigned long audlpa_pmem_fixup(struct audio *audio, void *addr,
+static unsigned long audlpa_ion_fixup(struct audio *audio, void *addr,
unsigned long len, int ref_up);
static void audlpa_async_send_data(struct audio *audio, unsigned needed,
uint32_t *payload);
@@ -778,7 +778,7 @@
if (drv_evt->event_type == AUDIO_EVENT_WRITE_DONE ||
drv_evt->event_type == AUDIO_EVENT_READ_DONE) {
mutex_lock(&audio->lock);
- audlpa_pmem_fixup(audio, drv_evt->payload.aio_buf.buf_addr,
+ audlpa_ion_fixup(audio, drv_evt->payload.aio_buf.buf_addr,
drv_evt->payload.aio_buf.buf_len, 0);
mutex_unlock(&audio->lock);
}
@@ -788,94 +788,118 @@
return rc;
}
-static int audlpa_pmem_check(struct audio *audio,
+static int audlpa_ion_check(struct audio *audio,
void *vaddr, unsigned long len)
{
- struct audlpa_pmem_region *region_elt;
- struct audlpa_pmem_region t = { .vaddr = vaddr, .len = len };
+ struct audlpa_ion_region *region_elt;
+ struct audlpa_ion_region t = {.vaddr = vaddr, .len = len };
- list_for_each_entry(region_elt, &audio->pmem_region_queue, list) {
+ list_for_each_entry(region_elt, &audio->ion_region_queue, list) {
if (CONTAINS(region_elt, &t) || CONTAINS(&t, region_elt) ||
OVERLAPS(region_elt, &t)) {
- MM_ERR("region (vaddr %p len %ld)"
+ MM_ERR("[%p]:region (vaddr %p len %ld)"
" clashes with registered region"
" (vaddr %p paddr %p len %ld)\n",
- vaddr, len,
+ audio, vaddr, len,
region_elt->vaddr,
- (void *)region_elt->paddr,
- region_elt->len);
+ (void *)region_elt->paddr, region_elt->len);
return -EINVAL;
}
}
return 0;
}
-
-static int audlpa_pmem_add(struct audio *audio,
- struct msm_audio_pmem_info *info)
+static int audlpa_ion_add(struct audio *audio,
+ struct msm_audio_ion_info *info)
{
- unsigned long paddr, kvaddr, len;
- struct file *file;
- struct audlpa_pmem_region *region;
+ ion_phys_addr_t paddr;
+ size_t len;
+ unsigned long kvaddr;
+ struct audlpa_ion_region *region;
int rc = -EINVAL;
+ struct ion_handle *handle;
+ unsigned long ionflag;
- MM_DBG("\n"); /* Macro prints the file name and function */
+ MM_ERR("\n"); /* Macro prints the file name and function */
region = kmalloc(sizeof(*region), GFP_KERNEL);
if (!region) {
rc = -ENOMEM;
goto end;
}
-
- if (get_pmem_file(info->fd, &paddr, &kvaddr, &len, &file)) {
- kfree(region);
- goto end;
+ handle = ion_import_dma_buf(audio->client, info->fd);
+ if (IS_ERR_OR_NULL(handle)) {
+ pr_err("%s: could not get handle of the given fd\n", __func__);
+ goto import_error;
}
-
- rc = audlpa_pmem_check(audio, info->vaddr, len);
+ rc = ion_handle_get_flags(audio->client, handle, &ionflag);
+ if (rc) {
+ pr_err("%s: could not get flags for the handle\n", __func__);
+ goto flag_error;
+ }
+ kvaddr = (unsigned long)ion_map_kernel(audio->client, handle);
+ if (IS_ERR_OR_NULL((void *)kvaddr)) {
+ pr_err("%s: could not get virtual address\n", __func__);
+ goto map_error;
+ }
+ rc = ion_phys(audio->client, handle, &paddr, &len);
+ if (rc) {
+ pr_err("%s: could not get physical address\n", __func__);
+ goto ion_error;
+ }
+ rc = audlpa_ion_check(audio, info->vaddr, len);
if (rc < 0) {
- put_pmem_file(file);
- kfree(region);
- goto end;
+ MM_ERR("audpcm_ion_check failed\n");
+ goto ion_error;
}
-
+ region->handle = handle;
region->vaddr = info->vaddr;
region->fd = info->fd;
region->paddr = paddr;
region->kvaddr = kvaddr;
region->len = len;
- region->file = file;
region->ref_cnt = 0;
- MM_DBG("add region paddr %lx vaddr %p, len %lu\n", region->paddr,
- region->vaddr, region->len);
- list_add_tail(®ion->list, &audio->pmem_region_queue);
+ MM_DBG("[%p]:add region paddr %lx vaddr %p, len %lu kvaddr %lx\n",
+ audio, region->paddr, region->vaddr,
+ region->len, region->kvaddr);
+ list_add_tail(®ion->list, &audio->ion_region_queue);
+
+ return rc;
+
+ion_error:
+ ion_unmap_kernel(audio->client, handle);
+map_error:
+flag_error:
+ ion_free(audio->client, handle);
+import_error:
+ kfree(region);
end:
return rc;
}
-static int audlpa_pmem_remove(struct audio *audio,
- struct msm_audio_pmem_info *info)
+static int audlpa_ion_remove(struct audio *audio,
+ struct msm_audio_ion_info *info)
{
- struct audlpa_pmem_region *region;
+ struct audlpa_ion_region *region;
struct list_head *ptr, *next;
int rc = -EINVAL;
- MM_DBG("info fd %d vaddr %p\n", info->fd, info->vaddr);
+ list_for_each_safe(ptr, next, &audio->ion_region_queue) {
+ region = list_entry(ptr, struct audlpa_ion_region, list);
- list_for_each_safe(ptr, next, &audio->pmem_region_queue) {
- region = list_entry(ptr, struct audlpa_pmem_region, list);
-
- if ((region->fd == info->fd) &&
+ if (region != NULL && (region->fd == info->fd) &&
(region->vaddr == info->vaddr)) {
if (region->ref_cnt) {
- MM_DBG("region %p in use ref_cnt %d\n",
- region, region->ref_cnt);
+ MM_DBG("%s[%p]:region %p in use ref_cnt %d\n",
+ __func__, audio, region,
+ region->ref_cnt);
break;
}
MM_DBG("remove region fd %d vaddr %p\n",
info->fd, info->vaddr);
list_del(®ion->list);
- put_pmem_file(region->file);
+ ion_unmap_kernel(audio->client, region->handle);
+ ion_free(audio->client, region->handle);
kfree(region);
rc = 0;
break;
@@ -885,23 +909,20 @@
return rc;
}
-static int audlpa_pmem_lookup_vaddr(struct audio *audio, void *addr,
- unsigned long len, struct audlpa_pmem_region **region)
+static int audlpa_ion_lookup_vaddr(struct audio *audio, void *addr,
+ unsigned long len, struct audlpa_ion_region **region)
{
- struct audlpa_pmem_region *region_elt;
-
+ struct audlpa_ion_region *region_elt;
int match_count = 0;
-
*region = NULL;
/* returns physical address or zero */
- list_for_each_entry(region_elt, &audio->pmem_region_queue,
- list) {
+ list_for_each_entry(region_elt, &audio->ion_region_queue, list) {
if (addr >= region_elt->vaddr &&
addr < region_elt->vaddr + region_elt->len &&
addr + len <= region_elt->vaddr + region_elt->len) {
/* offset since we could pass vaddr inside a registerd
- * pmem buffer
+ * ion buffer
*/
match_count++;
@@ -911,13 +932,16 @@
}
if (match_count > 1) {
- MM_ERR("multiple hits for vaddr %p, len %ld\n", addr, len);
- list_for_each_entry(region_elt,
- &audio->pmem_region_queue, list) {
+ MM_ERR("%s[%p]:multiple hits for vaddr %p, len %ld\n",
+ __func__, audio, addr, len);
+ list_for_each_entry(region_elt, &audio->ion_region_queue,
+ list) {
if (addr >= region_elt->vaddr &&
addr < region_elt->vaddr + region_elt->len &&
addr + len <= region_elt->vaddr + region_elt->len)
- MM_ERR("\t%p, %ld --> %p\n", region_elt->vaddr,
+ MM_ERR("\t%s[%p]:%p, %ld --> %p\n",
+ __func__, audio,
+ region_elt->vaddr,
region_elt->len,
(void *)region_elt->paddr);
}
@@ -925,17 +949,17 @@
return *region ? 0 : -1;
}
-
-unsigned long audlpa_pmem_fixup(struct audio *audio, void *addr,
+static unsigned long audlpa_ion_fixup(struct audio *audio, void *addr,
unsigned long len, int ref_up)
{
- struct audlpa_pmem_region *region;
+ struct audlpa_ion_region *region;
unsigned long paddr;
int ret;
- ret = audlpa_pmem_lookup_vaddr(audio, addr, len, ®ion);
+ ret = audlpa_ion_lookup_vaddr(audio, addr, len, ®ion);
if (ret) {
- MM_ERR("lookup (%p, %ld) failed\n", addr, len);
+ MM_ERR("%s[%p]:lookup (%p, %ld) failed\n",
+ __func__, audio, addr, len);
return 0;
}
if (ref_up)
@@ -969,7 +993,7 @@
buf_node->buf.buf_addr, buf_node->buf.buf_len,
buf_node->buf.data_len);
- buf_node->paddr = audlpa_pmem_fixup(
+ buf_node->paddr = audlpa_ion_fixup(
audio, buf_node->buf.buf_addr,
buf_node->buf.buf_len, 1);
@@ -1269,25 +1293,26 @@
audio->drv_status &= ~ADRV_STATUS_PAUSE;
break;
- case AUDIO_REGISTER_PMEM: {
- struct msm_audio_pmem_info info;
- MM_DBG("AUDIO_REGISTER_PMEM\n");
- if (copy_from_user(&info, (void *) arg, sizeof(info)))
+ case AUDIO_REGISTER_ION: {
+ struct msm_audio_ion_info info;
+ MM_DBG("AUDIO_REGISTER_ION\n");
+ if (copy_from_user(&info, (void *) arg, sizeof(info)))
rc = -EFAULT;
else
- rc = audlpa_pmem_add(audio, &info);
+ rc = audlpa_ion_add(audio, &info);
break;
}
- case AUDIO_DEREGISTER_PMEM: {
- struct msm_audio_pmem_info info;
- MM_DBG("AUDIO_DEREGISTER_PMEM\n");
- if (copy_from_user(&info, (void *) arg, sizeof(info)))
+ case AUDIO_DEREGISTER_ION: {
+ struct msm_audio_ion_info info;
+ MM_DBG("AUDIO_DEREGISTER_ION\n");
+ if (copy_from_user(&info, (void *) arg, sizeof(info)))
rc = -EFAULT;
else
- rc = audlpa_pmem_remove(audio, &info);
+ rc = audlpa_ion_remove(audio, &info);
break;
}
+
case AUDIO_ASYNC_WRITE:
if (audio->drv_status & ADRV_STATUS_FSYNC)
rc = -EBUSY;
@@ -1373,15 +1398,16 @@
return audlpa_async_fsync(audio);
}
-static void audlpa_reset_pmem_region(struct audio *audio)
+static void audpcm_reset_ion_region(struct audio *audio)
{
- struct audlpa_pmem_region *region;
+ struct audlpa_ion_region *region;
struct list_head *ptr, *next;
- list_for_each_safe(ptr, next, &audio->pmem_region_queue) {
- region = list_entry(ptr, struct audlpa_pmem_region, list);
+ list_for_each_safe(ptr, next, &audio->ion_region_queue) {
+ region = list_entry(ptr, struct audlpa_ion_region, list);
list_del(®ion->list);
- put_pmem_file(region->file);
+ ion_unmap_kernel(audio->client, region->handle);
+ ion_free(audio->client, region->handle);
kfree(region);
}
@@ -1399,7 +1425,7 @@
auddev_unregister_evt_listner(AUDDEV_CLNT_DEC, audio->dec_id);
audio_disable(audio);
audlpa_async_flush(audio);
- audlpa_reset_pmem_region(audio);
+ audpcm_reset_ion_region(audio);
msm_adsp_put(audio->audplay);
audpp_adec_free(audio->dec_id);
@@ -1410,13 +1436,12 @@
audio->event_abort = 1;
wake_up(&audio->event_wait);
audlpa_reset_event_queue(audio);
- iounmap(audio->data);
- free_contiguous_memory_by_paddr(audio->phys);
mutex_unlock(&audio->lock);
#ifdef CONFIG_DEBUG_FS
if (audio->dentry)
debugfs_remove(audio->dentry);
#endif
+ ion_client_destroy(audio->client);
kfree(audio);
return 0;
}
@@ -1589,7 +1614,7 @@
spin_lock_init(&audio->dsp_lock);
init_waitqueue_head(&audio->write_wait);
INIT_LIST_HEAD(&audio->out_queue);
- INIT_LIST_HEAD(&audio->pmem_region_queue);
+ INIT_LIST_HEAD(&audio->ion_region_queue);
INIT_LIST_HEAD(&audio->free_event_queue);
INIT_LIST_HEAD(&audio->event_queue);
init_waitqueue_head(&audio->wait);
@@ -1650,13 +1675,19 @@
break;
}
}
+
+ audio->client = msm_ion_client_create(UINT_MAX, "Audio_LPA_Client");
+ if (IS_ERR_OR_NULL(audio->client)) {
+ pr_err("Unable to create ION client\n");
+ goto err;
+ }
+ MM_DBG("Ion client created\n");
+
done:
return rc;
event_err:
msm_adsp_put(audio->audplay);
err:
- iounmap(audio->data);
- free_contiguous_memory_by_paddr(audio->phys);
audpp_adec_free(audio->dec_id);
MM_INFO("audio instance 0x%08x freeing\n", (int)audio);
kfree(audio);
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_out.c b/arch/arm/mach-msm/qdsp5v2/audio_out.c
index 147ac77..e5c59ba 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_out.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_out.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2008 Google, Inc.
* Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-2012, 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
@@ -43,7 +43,7 @@
#include <mach/qdsp5v2/audio_dev_ctl.h>
#include <mach/msm_memtypes.h>
#include <mach/cpuidle.h>
-
+#include <linux/msm_ion.h>
#include <mach/htc_pwrsink.h>
#include <mach/debug_mm.h>
@@ -98,6 +98,8 @@
struct pm_qos_request pm_qos_req;
struct audpp_cmd_cfg_object_params_volume vol_pan;
+ struct ion_client *client;
+ struct ion_handle *buff_handle;
};
static void audio_out_listener(u32 evt_id, union auddev_evt_data *evt_payload,
@@ -702,19 +704,53 @@
static int __init audio_init(void)
{
- the_audio.phys = allocate_contiguous_ebi_nomap(DMASZ, SZ_4K);
- if (the_audio.phys) {
- the_audio.map_v_write = ioremap(the_audio.phys, DMASZ);
- if (IS_ERR(the_audio.map_v_write)) {
- MM_ERR("could not map physical buffers\n");
- free_contiguous_memory_by_paddr(the_audio.phys);
- return -ENOMEM;
- }
- the_audio.data = the_audio.map_v_write;
- } else {
- MM_ERR("could not allocate physical buffers\n");
- return -ENOMEM;
+ unsigned long ionflag = 0;
+ ion_phys_addr_t addr = 0;
+ int rc;
+ int len = 0;
+ struct ion_handle *handle = NULL;
+ struct ion_client *client = NULL;
+
+ client = msm_ion_client_create(UINT_MAX, "HostPCM");
+ if (IS_ERR_OR_NULL(client)) {
+ MM_ERR("Unable to create ION client\n");
+ rc = -ENOMEM;
+ goto client_create_error;
}
+ the_audio.client = client;
+
+ handle = ion_alloc(client, DMASZ, SZ_4K,
+ ION_HEAP(ION_AUDIO_HEAP_ID), 0);
+ if (IS_ERR_OR_NULL(handle)) {
+ MM_ERR("Unable to create allocate O/P buffers\n");
+ rc = -ENOMEM;
+ goto buff_alloc_error;
+ }
+ the_audio.buff_handle = handle;
+
+ rc = ion_phys(client, handle, &addr, &len);
+ if (rc) {
+ MM_ERR("O/P buffers:Invalid phy: %x sz: %x\n",
+ (unsigned int) addr, (unsigned int) len);
+ goto buff_get_phys_error;
+ } else
+ MM_INFO("O/P buffers:valid phy: %x sz: %x\n",
+ (unsigned int) addr, (unsigned int) len);
+ the_audio.phys = (int32_t)addr;
+
+ rc = ion_handle_get_flags(client, handle, &ionflag);
+ if (rc) {
+ MM_ERR("could not get flags for the handle\n");
+ goto buff_get_flags_error;
+ }
+
+ the_audio.map_v_write = ion_map_kernel(client, handle);
+ if (IS_ERR(the_audio.map_v_write)) {
+ MM_ERR("could not map write buffers\n");
+ rc = -ENOMEM;
+ goto buff_map_error;
+ }
+ the_audio.data = (char *)the_audio.map_v_write;
MM_DBG("Memory addr = 0x%8x phy addr = 0x%8x\n",\
(int) the_audio.data, (int) the_audio.phys);
mutex_init(&the_audio.lock);
@@ -725,6 +761,15 @@
pm_qos_add_request(&the_audio.pm_qos_req, PM_QOS_CPU_DMA_LATENCY,
PM_QOS_DEFAULT_VALUE);
return misc_register(&audio_misc);
+buff_map_error:
+buff_get_phys_error:
+buff_get_flags_error:
+ ion_free(client, the_audio.buff_handle);
+buff_alloc_error:
+ ion_client_destroy(client);
+client_create_error:
+ return rc;
+
}
late_initcall(audio_init);
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_pcm_in.c b/arch/arm/mach-msm/qdsp5v2/audio_pcm_in.c
index ce67ebb..ff3a696 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_pcm_in.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_pcm_in.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2008 Google, Inc.
* Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-2012, 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
@@ -27,7 +27,7 @@
#include <linux/wait.h>
#include <linux/dma-mapping.h>
#include <linux/msm_audio.h>
-#include <linux/android_pmem.h>
+#include <linux/msm_ion.h>
#include <linux/memory_alloc.h>
#include <mach/msm_memtypes.h>
@@ -121,6 +121,8 @@
int abort; /* set when error, like sample rate mismatch */
int dual_mic_config;
char *build_id;
+ struct ion_client *client;
+ struct ion_handle *output_buff_handle;
};
static struct audio_in the_audio_in;
@@ -842,10 +844,11 @@
audio->audrec = NULL;
audio->opened = 0;
if (audio->data) {
- iounmap(audio->map_v_read);
- free_contiguous_memory_by_paddr(audio->phys);
+ ion_unmap_kernel(audio->client, audio->output_buff_handle);
+ ion_free(audio->client, audio->output_buff_handle);
audio->data = NULL;
}
+ ion_client_destroy(audio->client);
mutex_unlock(&audio->lock);
return 0;
}
@@ -855,27 +858,68 @@
struct audio_in *audio = &the_audio_in;
int rc;
int encid;
+ int len = 0;
+ unsigned long ionflag = 0;
+ ion_phys_addr_t addr = 0;
+ struct ion_handle *handle = NULL;
+ struct ion_client *client = NULL;
mutex_lock(&audio->lock);
if (audio->opened) {
rc = -EBUSY;
goto done;
}
- audio->phys = allocate_contiguous_ebi_nomap(DMASZ, SZ_4K);
- if (audio->phys) {
- audio->map_v_read = ioremap(audio->phys, DMASZ);
- if (IS_ERR(audio->map_v_read)) {
- MM_ERR("could not map read phys buffers\n");
+
+ client = msm_ion_client_create(UINT_MAX, "Audio_PCM_in_client");
+ if (IS_ERR_OR_NULL(client)) {
+ MM_ERR("Unable to create ION client\n");
rc = -ENOMEM;
- free_contiguous_memory_by_paddr(audio->phys);
- goto done;
- }
- audio->data = audio->map_v_read;
- } else {
- MM_ERR("could not allocate read buffers\n");
- rc = -ENOMEM;
- goto done;
+ goto client_create_error;
}
+ audio->client = client;
+
+ MM_DBG("allocating mem sz = %d\n", DMASZ);
+ handle = ion_alloc(client, DMASZ, SZ_4K,
+ ION_HEAP(ION_AUDIO_HEAP_ID), 0);
+ if (IS_ERR_OR_NULL(handle)) {
+ MM_ERR("Unable to create allocate O/P buffers\n");
+ rc = -ENOMEM;
+ goto output_buff_alloc_error;
+ }
+
+ audio->output_buff_handle = handle;
+
+ rc = ion_phys(client , handle, &addr, &len);
+ if (rc) {
+ MM_ERR("O/P buffers:Invalid phy: %x sz: %x\n",
+ (unsigned int) addr, (unsigned int) len);
+ rc = -ENOMEM;
+ goto output_buff_get_phys_error;
+ } else {
+ MM_INFO("O/P buffers:valid phy: %x sz: %x\n",
+ (unsigned int) addr, (unsigned int) len);
+ }
+ audio->phys = (int32_t)addr;
+
+ rc = ion_handle_get_flags(client, handle, &ionflag);
+ if (rc) {
+ MM_ERR("could not get flags for the handle\n");
+ rc = -ENOMEM;
+ goto output_buff_get_flags_error;
+ }
+
+ audio->map_v_read = ion_map_kernel(client, handle);
+ if (IS_ERR(audio->data)) {
+ MM_ERR("could not map read buffers,freeing instance 0x%08x\n",
+ (int)audio);
+ rc = -ENOMEM;
+ goto output_buff_map_error;
+ }
+ MM_DBG("read buf: phy addr 0x%08x kernel addr 0x%08x\n",
+ audio->phys, (int)audio->data);
+
+ audio->data = (char *)audio->map_v_read;
+
MM_DBG("Memory addr = 0x%8x phy addr = 0x%8x\n",\
(int) audio->data, (int) audio->phys);
if ((file->f_mode & FMODE_WRITE) &&
@@ -941,6 +985,13 @@
mutex_unlock(&audio->lock);
return rc;
evt_error:
+output_buff_map_error:
+output_buff_get_phys_error:
+output_buff_get_flags_error:
+ ion_free(client, audio->output_buff_handle);
+output_buff_alloc_error:
+ ion_client_destroy(client);
+client_create_error:
msm_adsp_put(audio->audrec);
audpreproc_aenc_free(audio->enc_id);
mutex_unlock(&audio->lock);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_lpa.c b/arch/arm/mach-msm/qdsp6v2/audio_lpa.c
index 176f364..edf8f77 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_lpa.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_lpa.c
@@ -707,15 +707,6 @@
case RESET_EVENTS:
reset_device();
break;
- case APR_BASIC_RSP_RESULT:
- switch (payload[0]) {
- case ASM_STREAM_CMD_CLOSE:
- audlpa_unmap_ion_region(audio);
- break;
- default:
- break;
- }
- break;
default:
break;
}
@@ -1136,6 +1127,7 @@
audlpa_async_flush(audio);
audio->wflush = 0;
audio_disable(audio);
+ audlpa_unmap_ion_region(audio);
msm_clear_session_id(audio->ac->session);
auddev_unregister_evt_listner(AUDDEV_CLNT_DEC, audio->ac->session);
q6asm_audio_client_free(audio->ac);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
index 28bf5c6..d6abdda 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
@@ -403,7 +403,7 @@
return;
}
-void audio_aio_unmap_ion_region(struct q6audio_aio *audio)
+static void audio_aio_unmap_ion_region(struct q6audio_aio *audio)
{
struct audio_aio_ion_region *region;
struct list_head *ptr, *next;
@@ -436,6 +436,7 @@
audio->drv_ops.out_flush(audio);
audio->drv_ops.in_flush(audio);
audio_aio_disable(audio);
+ audio_aio_unmap_ion_region(audio);
audio_aio_reset_ion_region(audio);
ion_client_destroy(audio->client);
audio->event_abort = 1;
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.h b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.h
index 2b936c5..b2829c3 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.h
+++ b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.h
@@ -210,7 +210,6 @@
int audio_aio_fsync(struct file *file, loff_t start, loff_t end, int datasync);
void audio_aio_async_out_flush(struct q6audio_aio *audio);
void audio_aio_async_in_flush(struct q6audio_aio *audio);
-void audio_aio_unmap_ion_region(struct q6audio_aio *audio);
#ifdef CONFIG_DEBUG_FS
ssize_t audio_aio_debug_open(struct inode *inode, struct file *file);
ssize_t audio_aio_debug_read(struct file *file, char __user *buf,
diff --git a/arch/arm/mach-msm/qdsp6v2/q6audio_v1_aio.c b/arch/arm/mach-msm/qdsp6v2/q6audio_v1_aio.c
index b46e0d3..96f823f 100644
--- a/arch/arm/mach-msm/qdsp6v2/q6audio_v1_aio.c
+++ b/arch/arm/mach-msm/qdsp6v2/q6audio_v1_aio.c
@@ -37,7 +37,6 @@
case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
case ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY:
case ASM_DATA_EVENT_ENC_SR_CM_NOTIFY:
- case APR_BASIC_RSP_RESULT:
audio_aio_cb(opcode, token, payload, audio);
break;
default:
@@ -107,15 +106,6 @@
e_payload.stream_info.sample_rate = audio->pcm_cfg.sample_rate;
audio_aio_post_event(audio, AUDIO_EVENT_STREAM_INFO, e_payload);
break;
- case APR_BASIC_RSP_RESULT:
- switch (payload[0]) {
- case ASM_STREAM_CMD_CLOSE:
- audio_aio_unmap_ion_region(audio);
- break;
- default:
- break;
- }
- break;
default:
break;
}
diff --git a/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.c b/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.c
index 5400ccc..dce3812 100644
--- a/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.c
+++ b/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.c
@@ -515,6 +515,9 @@
case FORMAT_USRAW:
int_format = US_RAW_FORMAT;
break;
+ case FORMAT_USPROX:
+ int_format = US_PROX_FORMAT;
+ break;
default:
pr_err("%s: Invalid format[%d]\n", __func__, ext_format);
break;
diff --git a/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.h b/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.h
index 1338e86..1fe71bf 100644
--- a/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.h
+++ b/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.h
@@ -20,6 +20,7 @@
#define FORMAT_USPS_EPOS 0x00000000
#define FORMAT_USRAW 0x00000001
+#define FORMAT_USPROX 0x00000002
#define INVALID_FORMAT 0xffffffff
#define IN 0x000
diff --git a/arch/arm/mach-msm/rpm-smd.c b/arch/arm/mach-msm/rpm-smd.c
index 7c31e76..f97eb9a 100644
--- a/arch/arm/mach-msm/rpm-smd.c
+++ b/arch/arm/mach-msm/rpm-smd.c
@@ -943,7 +943,7 @@
static bool msm_rpm_set_standalone(void)
{
- if (machine_is_msm8974()) {
+ if (machine_is_msm9625()) {
pr_warn("%s(): Running in standalone mode, requests "
"will not be sent to RPM\n", __func__);
standalone = true;
diff --git a/arch/arm/mach-msm/rpm_stats.h b/arch/arm/mach-msm/rpm_stats.h
index 918d4fb..a3beaa4 100644
--- a/arch/arm/mach-msm/rpm_stats.h
+++ b/arch/arm/mach-msm/rpm_stats.h
@@ -20,4 +20,19 @@
phys_addr_t phys_addr_base;
u32 phys_size;
};
+
+struct msm_rpm_master_stats_platform_data {
+ phys_addr_t phys_addr_base;
+ u32 phys_size;
+ char **masters;
+ /*
+ * RPM maintains PC stats for each master in MSG RAM,
+ * it allocates 256 bytes for this use.
+ * No of masters differs for different targets.
+ * Based on the number of masters, linux rpm stat
+ * driver reads (32 * nomasters) bytes to display
+ * master stats.
+ */
+ u32 nomasters;
+};
#endif
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index ac077e9..969af98 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -286,6 +286,9 @@
/* 8092 IDs */
[146] = MSM_CPU_8092,
+ /* 8910 IDs */
+ [147] = MSM_CPU_8910,
+
/* 8064AB IDs */
[153] = MSM_CPU_8064AB,
@@ -732,6 +735,10 @@
dummy_socinfo.id = 146;
strlcpy(dummy_socinfo.build_id, "mpq8092 - ",
sizeof(dummy_socinfo.build_id));
+ } else if (early_machine_is_msm8910()) {
+ dummy_socinfo.id = 147;
+ strlcpy(dummy_socinfo.build_id, "msm8910 - ",
+ sizeof(dummy_socinfo.build_id));
}
strlcat(dummy_socinfo.build_id, "Dummy socinfo",
sizeof(dummy_socinfo.build_id));
diff --git a/drivers/cpufreq/cpufreq_gov_msm.c b/drivers/cpufreq/cpufreq_gov_msm.c
index 4eeff35..6ddbf4e 100644
--- a/drivers/cpufreq/cpufreq_gov_msm.c
+++ b/drivers/cpufreq/cpufreq_gov_msm.c
@@ -18,20 +18,114 @@
#include <linux/kobject.h>
#include <linux/cpufreq.h>
#include <linux/platform_device.h>
+#include <linux/cpu_pm.h>
+#include <linux/pm_qos.h>
+#include <linux/hrtimer.h>
+#include <linux/tick.h>
#include <mach/msm_dcvs.h>
+struct cpu_idle_info {
+ int enabled;
+ int dcvs_core_id;
+ struct pm_qos_request pm_qos_req;
+};
+
+static DEFINE_PER_CPU_SHARED_ALIGNED(struct cpu_idle_info, cpu_idle_info);
+static DEFINE_PER_CPU_SHARED_ALIGNED(u64, iowait_on_cpu);
+static uint32_t latency;
+
+static int msm_dcvs_idle_notifier(int core_num,
+ enum msm_core_control_event event)
+{
+ struct cpu_idle_info *info = &per_cpu(cpu_idle_info, core_num);
+
+ switch (event) {
+ case MSM_DCVS_ENABLE_IDLE_PULSE:
+ info->enabled = true;
+ break;
+
+ case MSM_DCVS_DISABLE_IDLE_PULSE:
+ info->enabled = false;
+ break;
+
+ case MSM_DCVS_ENABLE_HIGH_LATENCY_MODES:
+ pm_qos_update_request(&info->pm_qos_req, PM_QOS_DEFAULT_VALUE);
+ break;
+
+ case MSM_DCVS_DISABLE_HIGH_LATENCY_MODES:
+ pm_qos_update_request(&info->pm_qos_req, latency);
+ break;
+ }
+
+ return 0;
+}
+
+static int msm_cpuidle_notifier(struct notifier_block *self, unsigned long cmd,
+ void *v)
+{
+ struct cpu_idle_info *info =
+ &per_cpu(cpu_idle_info, smp_processor_id());
+ u64 io_wait_us = 0;
+ u64 prev_io_wait_us = 0;
+ u64 last_update_time = 0;
+ u64 val = 0;
+ uint32_t iowaited = 0;
+
+ if (!info->enabled)
+ return NOTIFY_OK;
+
+ switch (cmd) {
+ case CPU_PM_ENTER:
+ val = get_cpu_iowait_time_us(smp_processor_id(),
+ &last_update_time);
+ /* val could be -1 when NOHZ is not enabled */
+ if (val == (u64)-1)
+ val = 0;
+ per_cpu(iowait_on_cpu, smp_processor_id()) = val;
+ msm_dcvs_idle(info->dcvs_core_id, MSM_DCVS_IDLE_ENTER, 0);
+ break;
+
+ case CPU_PM_EXIT:
+ prev_io_wait_us = per_cpu(iowait_on_cpu, smp_processor_id());
+ val = get_cpu_iowait_time_us(smp_processor_id(),
+ &last_update_time);
+ if (val == (u64)-1)
+ val = 0;
+ io_wait_us = val;
+ iowaited = (io_wait_us - prev_io_wait_us);
+ msm_dcvs_idle(info->dcvs_core_id, MSM_DCVS_IDLE_EXIT, iowaited);
+ break;
+ }
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block idle_nb = {
+ .notifier_call = msm_cpuidle_notifier,
+};
+
+static void msm_gov_idle_source_init(int cpu, int dcvs_core_id)
+{
+ struct cpu_idle_info *info = NULL;
+
+ info = &per_cpu(cpu_idle_info, cpu);
+ info->dcvs_core_id = dcvs_core_id;
+
+ pm_qos_add_request(&info->pm_qos_req, PM_QOS_CPU_DMA_LATENCY,
+ PM_QOS_DEFAULT_VALUE);
+}
+
struct msm_gov {
- int cpu;
- unsigned int cur_freq;
- unsigned int min_freq;
- unsigned int max_freq;
- struct msm_dcvs_freq gov_notifier;
- struct cpufreq_policy *policy;
+ int cpu;
+ unsigned int cur_freq;
+ unsigned int min_freq;
+ unsigned int max_freq;
+ struct cpufreq_policy *policy;
+ int dcvs_core_id;
};
static DEFINE_PER_CPU_SHARED_ALIGNED(struct mutex, gov_mutex);
static DEFINE_PER_CPU_SHARED_ALIGNED(struct msm_gov, msm_gov_info);
-static char core_name[NR_CPUS][10];
static void msm_gov_check_limits(struct cpufreq_policy *policy)
{
@@ -40,7 +134,7 @@
if (policy->max < gov->cur_freq)
__cpufreq_driver_target(policy, policy->max,
CPUFREQ_RELATION_H);
- else if (policy->min > gov->min_freq)
+ else if (policy->min > gov->cur_freq)
__cpufreq_driver_target(policy, policy->min,
CPUFREQ_RELATION_L);
else
@@ -50,14 +144,14 @@
gov->cur_freq = policy->cur;
gov->min_freq = policy->min;
gov->max_freq = policy->max;
+ msm_dcvs_update_limits(gov->dcvs_core_id);
}
-static int msm_dcvs_freq_set(struct msm_dcvs_freq *self,
+static int msm_dcvs_freq_set(int core_num,
unsigned int freq)
{
int ret = -EINVAL;
- struct msm_gov *gov =
- container_of(self, struct msm_gov, gov_notifier);
+ struct msm_gov *gov = &per_cpu(msm_gov_info, core_num);
mutex_lock(&per_cpu(gov_mutex, gov->cpu));
@@ -66,23 +160,30 @@
if (freq > gov->max_freq)
freq = gov->max_freq;
- ret = __cpufreq_driver_target(gov->policy, freq, CPUFREQ_RELATION_L);
- gov->cur_freq = gov->policy->cur;
-
mutex_unlock(&per_cpu(gov_mutex, gov->cpu));
- if (!ret)
- return gov->cur_freq;
+ ret = cpufreq_driver_target(gov->policy, freq, CPUFREQ_RELATION_L);
+
+ if (!ret) {
+ gov->cur_freq = cpufreq_quick_get(gov->cpu);
+ if (freq != gov->cur_freq)
+ pr_err("cpu %d freq %u gov->cur_freq %u didn't match",
+ gov->cpu, freq, gov->cur_freq);
+ }
+ ret = gov->cur_freq;
return ret;
}
-static unsigned int msm_dcvs_freq_get(struct msm_dcvs_freq *self)
+static unsigned int msm_dcvs_freq_get(int core_num)
{
- struct msm_gov *gov =
- container_of(self, struct msm_gov, gov_notifier);
-
- return gov->cur_freq;
+ struct msm_gov *gov = &per_cpu(msm_gov_info, core_num);
+ /*
+ * the rw_sem in cpufreq is always held when this is called.
+ * The policy->cur won't be updated in this case - so it is safe to
+ * access policy->cur
+ */
+ return gov->policy->cur;
}
static int cpufreq_governor_msm(struct cpufreq_policy *policy,
@@ -92,8 +193,6 @@
int ret = 0;
int handle = 0;
struct msm_gov *gov = &per_cpu(msm_gov_info, policy->cpu);
- struct msm_dcvs_freq *dcvs_notifier =
- &(per_cpu(msm_gov_info, cpu).gov_notifier);
switch (event) {
case CPUFREQ_GOV_START:
@@ -103,19 +202,14 @@
mutex_lock(&per_cpu(gov_mutex, cpu));
per_cpu(msm_gov_info, cpu).cpu = cpu;
gov->policy = policy;
- dcvs_notifier->core_name = core_name[cpu];
- dcvs_notifier->set_frequency = msm_dcvs_freq_set;
- dcvs_notifier->get_frequency = msm_dcvs_freq_get;
- handle = msm_dcvs_freq_sink_register(dcvs_notifier);
+ handle = msm_dcvs_freq_sink_start(gov->dcvs_core_id);
BUG_ON(handle < 0);
msm_gov_check_limits(policy);
mutex_unlock(&per_cpu(gov_mutex, cpu));
break;
case CPUFREQ_GOV_STOP:
- mutex_lock(&per_cpu(gov_mutex, cpu));
- msm_dcvs_freq_sink_unregister(dcvs_notifier);
- mutex_unlock(&per_cpu(gov_mutex, cpu));
+ msm_dcvs_freq_sink_stop(gov->dcvs_core_id);
break;
case CPUFREQ_GOV_LIMITS:
@@ -136,20 +230,40 @@
static int __devinit msm_gov_probe(struct platform_device *pdev)
{
- int ret = 0;
int cpu;
struct msm_dcvs_core_info *core = NULL;
+ struct msm_dcvs_core_info *core_info = NULL;
+ struct msm_gov_platform_data *pdata = pdev->dev.platform_data;
+ int sensor = 0;
core = pdev->dev.platform_data;
+ core_info = pdata->info;
+ latency = pdata->latency;
for_each_possible_cpu(cpu) {
+ struct msm_gov *gov = &per_cpu(msm_gov_info, cpu);
+
mutex_init(&per_cpu(gov_mutex, cpu));
- snprintf(core_name[cpu], 10, "cpu%d", cpu);
- ret = msm_dcvs_register_core(core_name[cpu], core);
- if (ret)
+ if (cpu < core->num_cores)
+ sensor = core_info->sensors[cpu];
+ gov->dcvs_core_id = msm_dcvs_register_core(
+ MSM_DCVS_CORE_TYPE_CPU,
+ cpu,
+ core_info,
+ msm_dcvs_freq_set,
+ msm_dcvs_freq_get,
+ msm_dcvs_idle_notifier,
+ sensor);
+ if (gov->dcvs_core_id < 0) {
pr_err("Unable to register core for %d\n", cpu);
+ return -EINVAL;
+ }
+
+ msm_gov_idle_source_init(cpu, gov->dcvs_core_id);
}
+ cpu_pm_register_notifier(&idle_nb);
+
return cpufreq_register_governor(&cpufreq_gov_msm);
}
diff --git a/drivers/gpu/msm/a3xx_reg.h b/drivers/gpu/msm/a3xx_reg.h
index 6a010a9..2681836 100644
--- a/drivers/gpu/msm/a3xx_reg.h
+++ b/drivers/gpu/msm/a3xx_reg.h
@@ -531,7 +531,11 @@
#define RBBM_BLOCK_ID_MARB_3 0x2b
/* RBBM_CLOCK_CTL default value */
-#define A3XX_RBBM_CLOCK_CTL_DEFAULT 0xBFFFFFFF
+#define A305_RBBM_CLOCK_CTL_DEFAULT 0xAAAAAAAA
+#define A320_RBBM_CLOCK_CTL_DEFAULT 0xBFFFFFFF
+#define A330_RBBM_CLOCK_CTL_DEFAULT 0xAAAAAAAE
+
+#define A330_RBBM_GPR0_CTL_DEFAULT 0x0AE2B8AE
/* COUNTABLE FOR SP PERFCOUNTER */
#define SP_FS_FULL_ALU_INSTRUCTIONS 0x0E
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 573e0a6..4eca776 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -896,6 +896,19 @@
info->freq_tbl[index].leakage_energy_offset = 0;
}
+ if (adreno_of_read_property(node, "qcom,num-cores", &info->num_cores))
+ goto err;
+
+ info->sensors = kzalloc(info->num_cores *
+ sizeof(int),
+ GFP_KERNEL);
+
+ for (count = 0; count < info->num_cores; count++) {
+ if (adreno_of_read_property(node, "qcom,sensors",
+ &(info->sensors[count])))
+ goto err;
+ }
+
if (adreno_of_read_property(node, "qcom,core-core-type",
&info->core_param.core_type))
goto err;
@@ -1094,6 +1107,9 @@
&pdata->nap_allowed))
pdata->nap_allowed = 1;
+ pdata->strtstp_sleepwake = of_property_read_bool(pdev->dev.of_node,
+ "qcom,strtstp-sleepwake");
+
if (adreno_of_read_property(pdev->dev.of_node, "qcom,clk-map",
&pdata->clk_map))
goto err;
@@ -2247,12 +2263,15 @@
static uint io_cnt;
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
+ struct adreno_context *adreno_ctx = context->devctxt;
int retries = 0;
unsigned int ts_issued;
unsigned int context_id = _get_context_id(context);
unsigned int time_elapsed = 0;
unsigned int prev_reg_val[hang_detect_regs_count];
unsigned int wait;
+ unsigned int retry_ts_cmp = 0;
+ unsigned int retry_ts_cmp_msecs = KGSL_SYNCOBJ_SERVER_TIMEOUT;
memset(prev_reg_val, 0, sizeof(prev_reg_val));
@@ -2262,12 +2281,20 @@
if (msecs == KGSL_TIMEOUT_DEFAULT)
msecs = adreno_dev->wait_timeout;
+ /*
+ * With user generated ts, if this check fails perform this check
+ * again after 'retry_ts_cmp_msecs' milliseconds.
+ */
if (timestamp_cmp(timestamp, ts_issued) > 0) {
- KGSL_DRV_ERR(device, "Cannot wait for invalid ts <%d:0x%x>, "
- "last issued ts <%d:0x%x>\n",
- context_id, timestamp, context_id, ts_issued);
- status = -EINVAL;
- goto done;
+ if (!(adreno_ctx->flags & CTXT_FLAGS_USER_GENERATED_TS)) {
+ KGSL_DRV_ERR(device,
+ "Cannot wait for invalid ts <%d:0x%x>, "
+ "last issued ts <%d:0x%x>\n",
+ context_id, timestamp, context_id, ts_issued);
+ status = -EINVAL;
+ goto done;
+ } else
+ retry_ts_cmp = 1;
}
/*
@@ -2337,7 +2364,22 @@
time_elapsed += wait;
wait = KGSL_TIMEOUT_PART;
- retries++;
+ if (!retry_ts_cmp)
+ retries++;
+ else if (time_elapsed >= retry_ts_cmp_msecs) {
+ ts_issued =
+ adreno_dev->ringbuffer.timestamp[context_id];
+ if (timestamp_cmp(timestamp, ts_issued) > 0) {
+ KGSL_DRV_ERR(device,
+ "Cannot wait for user-generated ts <%d:0x%x>, "
+ "not submitted within server timeout period. "
+ "last issued ts <%d:0x%x>\n",
+ context_id, timestamp, context_id, ts_issued);
+ status = -EINVAL;
+ goto done;
+ }
+ retry_ts_cmp = 0;
+ }
} while (!msecs || time_elapsed < msecs);
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 66402fe..fd9a0c3 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -33,7 +33,7 @@
/* Flags to control command packet settings */
#define KGSL_CMD_FLAGS_NONE 0x00000000
#define KGSL_CMD_FLAGS_PMODE 0x00000001
-#define KGSL_CMD_FLAGS_DUMMY_INTR_CMD 0x00000002
+#define KGSL_CMD_FLAGS_INTERNAL_ISSUE 0x00000002
/* Command identifiers */
#define KGSL_CONTEXT_TO_MEM_IDENTIFIER 0x2EADBEEF
@@ -179,6 +179,8 @@
unsigned int value);
int adreno_dump(struct kgsl_device *device, int manual);
+unsigned int adreno_a3xx_rbbm_clock_ctl_default(struct adreno_device
+ *adreno_dev);
struct kgsl_memdesc *adreno_find_region(struct kgsl_device *device,
unsigned int pt_base,
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index 104baf8..4c7534c 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -433,6 +433,19 @@
tmp_ctx.cmd = cmd;
}
+unsigned int adreno_a3xx_rbbm_clock_ctl_default(struct adreno_device
+ *adreno_dev)
+{
+ if (adreno_is_a305(adreno_dev))
+ return A305_RBBM_CLOCK_CTL_DEFAULT;
+ else if (adreno_is_a320(adreno_dev))
+ return A320_RBBM_CLOCK_CTL_DEFAULT;
+ else if (adreno_is_a330(adreno_dev))
+ return A330_RBBM_CLOCK_CTL_DEFAULT;
+
+ BUG_ON(1);
+}
+
/* Copy GMEM contents to system memory shadow. */
static unsigned int *build_gmem2sys_cmds(struct adreno_device *adreno_dev,
struct adreno_context *drawctxt,
@@ -442,7 +455,7 @@
unsigned int *start = cmds;
*cmds++ = cp_type0_packet(A3XX_RBBM_CLOCK_CTL, 1);
- *cmds++ = A3XX_RBBM_CLOCK_CTL_DEFAULT;
+ *cmds++ = adreno_a3xx_rbbm_clock_ctl_default(adreno_dev);
*cmds++ = cp_type3_packet(CP_SET_CONSTANT, 3);
*cmds++ = CP_REG(A3XX_RB_MODE_CONTROL);
@@ -1238,7 +1251,7 @@
unsigned int *start = cmds;
*cmds++ = cp_type0_packet(A3XX_RBBM_CLOCK_CTL, 1);
- *cmds++ = A3XX_RBBM_CLOCK_CTL_DEFAULT;
+ *cmds++ = adreno_a3xx_rbbm_clock_ctl_default(adreno_dev);
*cmds++ = cp_type3_packet(CP_SET_CONSTANT, 5);
*cmds++ = CP_REG(A3XX_HLSQ_CONTROL_0_REG);
@@ -2826,7 +2839,11 @@
/* Enable Clock gating */
adreno_regwrite(device, A3XX_RBBM_CLOCK_CTL,
- A3XX_RBBM_CLOCK_CTL_DEFAULT);
+ adreno_a3xx_rbbm_clock_ctl_default(adreno_dev));
+
+ if (adreno_is_a330(adreno_dev))
+ adreno_regwrite(device, A3XX_RBBM_GPR0_CTL,
+ A330_RBBM_GPR0_CTL_DEFAULT);
/* Set the OCMEM base address for A330 */
if (adreno_is_a330(adreno_dev)) {
diff --git a/drivers/gpu/msm/adreno_a3xx_snapshot.c b/drivers/gpu/msm/adreno_a3xx_snapshot.c
index d49fc23..a410445 100644
--- a/drivers/gpu/msm/adreno_a3xx_snapshot.c
+++ b/drivers/gpu/msm/adreno_a3xx_snapshot.c
@@ -383,7 +383,7 @@
/* Enable Clock gating */
adreno_regwrite(device, A3XX_RBBM_CLOCK_CTL,
- A3XX_RBBM_CLOCK_CTL_DEFAULT);
+ adreno_a3xx_rbbm_clock_ctl_default(adreno_dev));
return snapshot;
}
diff --git a/drivers/gpu/msm/adreno_drawctxt.c b/drivers/gpu/msm/adreno_drawctxt.c
index 7cbc7a8..a107a27 100644
--- a/drivers/gpu/msm/adreno_drawctxt.c
+++ b/drivers/gpu/msm/adreno_drawctxt.c
@@ -169,6 +169,14 @@
if (flags & KGSL_CONTEXT_PER_CONTEXT_TS)
drawctxt->flags |= CTXT_FLAGS_PER_CONTEXT_TS;
+ if (flags & KGSL_CONTEXT_USER_GENERATED_TS) {
+ if (!(flags & KGSL_CONTEXT_PER_CONTEXT_TS)) {
+ ret = -EINVAL;
+ goto err;
+ }
+ drawctxt->flags |= CTXT_FLAGS_USER_GENERATED_TS;
+ }
+
ret = adreno_dev->gpudev->ctxt_create(adreno_dev, drawctxt);
if (ret)
goto err;
diff --git a/drivers/gpu/msm/adreno_drawctxt.h b/drivers/gpu/msm/adreno_drawctxt.h
index 034d6e9..58e4791 100644
--- a/drivers/gpu/msm/adreno_drawctxt.h
+++ b/drivers/gpu/msm/adreno_drawctxt.h
@@ -48,6 +48,8 @@
#define CTXT_FLAGS_GPU_HANG_RECOVERED BIT(12)
/* Context is being destroyed so dont save it */
#define CTXT_FLAGS_BEING_DESTROYED BIT(13)
+/* User mode generated timestamps enabled */
+#define CTXT_FLAGS_USER_GENERATED_TS BIT(14)
struct kgsl_device;
struct adreno_device;
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index 0dd140b..da9daf7 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -487,11 +487,10 @@
adreno_ringbuffer_addcmds(struct adreno_ringbuffer *rb,
struct adreno_context *context,
unsigned int flags, unsigned int *cmds,
- int sizedwords)
+ int sizedwords, uint32_t timestamp)
{
struct adreno_device *adreno_dev = ADRENO_DEVICE(rb->device);
unsigned int *ringcmds;
- unsigned int timestamp;
unsigned int total_sizedwords = sizedwords;
unsigned int i;
unsigned int rcmd_gpu;
@@ -506,19 +505,38 @@
if (context && context->flags & CTXT_FLAGS_PER_CONTEXT_TS)
context_id = context->id;
+ if ((context->flags & CTXT_FLAGS_USER_GENERATED_TS) &&
+ (!(flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE))) {
+ if (timestamp_cmp(rb->timestamp[context_id],
+ timestamp) >= 0) {
+ KGSL_DRV_ERR(rb->device,
+ "Invalid user generated ts <%d:0x%x>, "
+ "less than last issued ts <%d:0x%x>\n",
+ context_id, timestamp, context_id,
+ rb->timestamp[context_id]);
+ return -ERANGE;
+ }
+ }
+
/* reserve space to temporarily turn off protected mode
* error checking if needed
*/
total_sizedwords += flags & KGSL_CMD_FLAGS_PMODE ? 4 : 0;
/* 2 dwords to store the start of command sequence */
total_sizedwords += 2;
- total_sizedwords += context ? 7 : 0;
+ /*
+ * Add CP_COND_EXEC commands to generate CP_INTERRUPT only
+ * for submissions from userspace.
+ */
+ total_sizedwords += (context &&
+ !(flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE)) ? 7 : 0;
if (adreno_is_a3xx(adreno_dev))
total_sizedwords += 7;
total_sizedwords += 2; /* scratchpad ts for recovery */
- if (context && context->flags & CTXT_FLAGS_PER_CONTEXT_TS) {
+ if (context && context->flags & CTXT_FLAGS_PER_CONTEXT_TS &&
+ !(flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE)) {
total_sizedwords += 3; /* sop timestamp */
total_sizedwords += 4; /* eop timestamp */
total_sizedwords += 3; /* global timestamp without cache
@@ -564,10 +582,13 @@
/* always increment the global timestamp. once. */
rb->timestamp[KGSL_MEMSTORE_GLOBAL]++;
- if (context && !(flags & KGSL_CMD_FLAGS_DUMMY_INTR_CMD)) {
+ /* Do not update context's timestamp for internal submissions */
+ if (context && !(flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE)) {
if (context_id == KGSL_MEMSTORE_GLOBAL)
rb->timestamp[context->id] =
rb->timestamp[KGSL_MEMSTORE_GLOBAL];
+ else if (context->flags & CTXT_FLAGS_USER_GENERATED_TS)
+ rb->timestamp[context_id] = timestamp;
else
rb->timestamp[context_id]++;
}
@@ -591,7 +612,8 @@
GSL_RB_WRITE(ringcmds, rcmd_gpu, 0x00);
}
- if (context && context->flags & CTXT_FLAGS_PER_CONTEXT_TS) {
+ if (context && context->flags & CTXT_FLAGS_PER_CONTEXT_TS
+ && !(flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE)) {
/* start-of-pipeline timestamp */
GSL_RB_WRITE(ringcmds, rcmd_gpu,
cp_type3_packet(CP_MEM_WRITE, 2));
@@ -619,11 +641,13 @@
cp_type3_packet(CP_EVENT_WRITE, 3));
GSL_RB_WRITE(ringcmds, rcmd_gpu, CACHE_FLUSH_TS);
GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr +
- KGSL_MEMSTORE_OFFSET(context_id, eoptimestamp)));
- GSL_RB_WRITE(ringcmds, rcmd_gpu, rb->timestamp[context_id]);
+ KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
+ eoptimestamp)));
+ GSL_RB_WRITE(ringcmds, rcmd_gpu,
+ rb->timestamp[KGSL_MEMSTORE_GLOBAL]);
}
- if (context) {
+ if (context && !(flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE)) {
/* Conditional execution based on memory values */
GSL_RB_WRITE(ringcmds, rcmd_gpu,
cp_type3_packet(CP_COND_EXEC, 4));
@@ -675,8 +699,8 @@
device->state & KGSL_STATE_HUNG)
return;
- adreno_ringbuffer_addcmds(rb, a_ctxt, KGSL_CMD_FLAGS_DUMMY_INTR_CMD,
- cmds, sizedwords);
+ adreno_ringbuffer_addcmds(rb, a_ctxt, KGSL_CMD_FLAGS_INTERNAL_ISSUE,
+ cmds, sizedwords, 0);
}
unsigned int
@@ -692,7 +716,11 @@
if (device->state & KGSL_STATE_HUNG)
return kgsl_readtimestamp(device, KGSL_MEMSTORE_GLOBAL,
KGSL_TIMESTAMP_RETIRED);
- return adreno_ringbuffer_addcmds(rb, drawctxt, flags, cmds, sizedwords);
+
+ flags |= KGSL_CMD_FLAGS_INTERNAL_ISSUE;
+
+ return adreno_ringbuffer_addcmds(rb, drawctxt, flags, cmds,
+ sizedwords, 0);
}
static bool _parse_ibs(struct kgsl_device_private *dev_priv, uint gpuaddr,
@@ -973,8 +1001,9 @@
adreno_drawctxt_switch(adreno_dev, drawctxt, flags);
*timestamp = adreno_ringbuffer_addcmds(&adreno_dev->ringbuffer,
- drawctxt, 0,
- &link[0], (cmds - link));
+ drawctxt,
+ 0,
+ &link[0], (cmds - link), *timestamp);
KGSL_CMD_INFO(device, "<%d:0x%x> g %08x numibs %d\n",
context->id, *timestamp, (unsigned int)ibdesc, numibs);
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 5ba844a..0c61d7f 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -722,6 +722,7 @@
list_add(&private->list, &kgsl_driver.process_list);
kgsl_process_init_sysfs(private);
+ kgsl_process_init_debugfs(private);
out:
mutex_unlock(&kgsl_driver.process_mutex);
@@ -744,6 +745,7 @@
goto unlock;
kgsl_process_uninit_sysfs(private);
+ debugfs_remove_recursive(private->debug_root);
list_del(&private->list);
@@ -1080,6 +1082,7 @@
unsigned int cmd, void *data)
{
int result = 0;
+ int i = 0;
struct kgsl_ringbuffer_issueibcmds *param = data;
struct kgsl_ibdesc *ibdesc;
struct kgsl_context *context;
@@ -1141,6 +1144,16 @@
param->numibs = 1;
}
+ for (i = 0; i < param->numibs; i++) {
+ if (!kgsl_mmu_gpuaddr_in_range(ibdesc[i].gpuaddr)) {
+ result = -ERANGE;
+ KGSL_DRV_ERR(dev_priv->device,
+ "invalid ib base GPU virtual addr %x\n",
+ ibdesc[i].gpuaddr);
+ goto free_ibdesc;
+ }
+ }
+
result = dev_priv->device->ftbl->issueibcmds(dev_priv,
context,
ibdesc,
@@ -1632,11 +1645,16 @@
#endif
static int kgsl_setup_ion(struct kgsl_mem_entry *entry,
- struct kgsl_pagetable *pagetable, int fd)
+ struct kgsl_pagetable *pagetable, void *data)
{
struct ion_handle *handle;
struct scatterlist *s;
struct sg_table *sg_table;
+ struct kgsl_map_user_mem *param = data;
+ int fd = param->fd;
+
+ if (!param->len)
+ return -EINVAL;
if (IS_ERR_OR_NULL(kgsl_ion_client))
return -ENODEV;
@@ -1741,8 +1759,7 @@
entry->memtype = KGSL_MEM_ENTRY_ASHMEM;
break;
case KGSL_USER_MEM_TYPE_ION:
- result = kgsl_setup_ion(entry, private->pagetable,
- param->fd);
+ result = kgsl_setup_ion(entry, private->pagetable, data);
break;
default:
KGSL_CORE_ERR("Invalid memory type: %x\n", memtype);
diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h
index 416eda9..472474b 100644
--- a/drivers/gpu/msm/kgsl.h
+++ b/drivers/gpu/msm/kgsl.h
@@ -182,6 +182,8 @@
struct kgsl_process_private *private, unsigned int gpuaddr,
size_t size);
+void kgsl_get_memory_usage(char *str, size_t len, unsigned int memflags);
+
int kgsl_add_event(struct kgsl_device *device, u32 id, u32 ts,
void (*cb)(struct kgsl_device *, void *, u32, u32), void *priv,
void *owner);
diff --git a/drivers/gpu/msm/kgsl_debugfs.c b/drivers/gpu/msm/kgsl_debugfs.c
index 545d2b3..40ed7ca 100644
--- a/drivers/gpu/msm/kgsl_debugfs.c
+++ b/drivers/gpu/msm/kgsl_debugfs.c
@@ -16,6 +16,7 @@
#include "kgsl.h"
#include "kgsl_device.h"
+#include "kgsl_sharedmem.h"
/*default log levels is error for everything*/
#define KGSL_LOG_LEVEL_DEFAULT 3
@@ -23,6 +24,7 @@
struct dentry *kgsl_debugfs_dir;
static struct dentry *pm_d_debugfs;
+struct dentry *proc_d_debugfs;
static int pm_dump_set(void *data, u64 val)
{
@@ -146,9 +148,80 @@
}
+static const char * const memtype_strings[] = {
+ "gpumem",
+ "pmem",
+ "ashmem",
+ "usermap",
+ "ion",
+};
+
+static const char *memtype_str(int memtype)
+{
+ if (memtype < ARRAY_SIZE(memtype_strings))
+ return memtype_strings[memtype];
+ return "unknown";
+}
+
+static int process_mem_print(struct seq_file *s, void *unused)
+{
+ struct kgsl_mem_entry *entry;
+ struct rb_node *node;
+ struct kgsl_process_private *private = s->private;
+ char flags[3];
+ char usage[16];
+
+ spin_lock(&private->mem_lock);
+ seq_printf(s, "%8s %8s %5s %10s %16s %5s\n",
+ "gpuaddr", "size", "flags", "type", "usage", "sglen");
+ for (node = rb_first(&private->mem_rb); node; node = rb_next(node)) {
+ struct kgsl_memdesc *m;
+
+ entry = rb_entry(node, struct kgsl_mem_entry, node);
+ m = &entry->memdesc;
+
+ flags[0] = m->priv & KGSL_MEMFLAGS_GLOBAL ? 'g' : '-';
+ flags[1] = m->priv & KGSL_MEMFLAGS_GPUREADONLY ? 'r' : '-';
+ flags[2] = '\0';
+
+ kgsl_get_memory_usage(usage, sizeof(usage), m->priv);
+
+ seq_printf(s, "%08x %8d %5s %10s %16s %5d\n",
+ m->gpuaddr, m->size, flags,
+ memtype_str(entry->memtype), usage, m->sglen);
+ }
+ spin_unlock(&private->mem_lock);
+ return 0;
+}
+
+static int process_mem_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, process_mem_print, inode->i_private);
+}
+
+static const struct file_operations process_mem_fops = {
+ .open = process_mem_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+void
+kgsl_process_init_debugfs(struct kgsl_process_private *private)
+{
+ unsigned char name[16];
+
+ snprintf(name, sizeof(name), "%d", private->pid);
+
+ private->debug_root = debugfs_create_dir(name, proc_d_debugfs);
+ debugfs_create_file("mem", 0400, private->debug_root, private,
+ &process_mem_fops);
+}
+
void kgsl_core_debugfs_init(void)
{
kgsl_debugfs_dir = debugfs_create_dir("kgsl", 0);
+ proc_d_debugfs = debugfs_create_dir("proc", kgsl_debugfs_dir);
}
void kgsl_core_debugfs_close(void)
diff --git a/drivers/gpu/msm/kgsl_debugfs.h b/drivers/gpu/msm/kgsl_debugfs.h
index 5e10988..898c4e9 100644
--- a/drivers/gpu/msm/kgsl_debugfs.h
+++ b/drivers/gpu/msm/kgsl_debugfs.h
@@ -15,6 +15,7 @@
#define _KGSL_DEBUGFS_H
struct kgsl_device;
+struct kgsl_process_private;
#ifdef CONFIG_DEBUG_FS
void kgsl_core_debugfs_init(void);
@@ -28,11 +29,16 @@
return kgsl_debugfs_dir;
}
+int kgsl_process_init_debugfs(struct kgsl_process_private *);
#else
static inline void kgsl_core_debugfs_init(void) { }
static inline void kgsl_device_debugfs_init(struct kgsl_device *device) { }
static inline void kgsl_core_debugfs_close(void) { }
static inline struct dentry *kgsl_get_debugfs_dir(void) { return NULL; }
+static inline int kgsl_process_init_debugfs(struct kgsl_process_private *)
+{
+ return 0;
+}
#endif
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index dc597f5..4394118 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -251,6 +251,7 @@
struct kgsl_pagetable *pagetable;
struct list_head list;
struct kobject kobj;
+ struct dentry *debug_root;
struct {
unsigned int cur;
diff --git a/drivers/gpu/msm/kgsl_pwrscale_msm.c b/drivers/gpu/msm/kgsl_pwrscale_msm.c
index acf22ac..2e4ac3b 100644
--- a/drivers/gpu/msm/kgsl_pwrscale_msm.c
+++ b/drivers/gpu/msm/kgsl_pwrscale_msm.c
@@ -20,21 +20,21 @@
#include "kgsl_trace.h"
struct msm_priv {
- struct kgsl_device *device;
- int enabled;
- int handle;
- unsigned int cur_freq;
- struct msm_dcvs_idle idle_source;
- struct msm_dcvs_freq freq_sink;
- struct msm_dcvs_core_info *core_info;
- int gpu_busy;
+ struct kgsl_device *device;
+ int enabled;
+ unsigned int cur_freq;
+ struct msm_dcvs_core_info *core_info;
+ int gpu_busy;
+ int dcvs_core_id;
};
-static int msm_idle_enable(struct msm_dcvs_idle *self,
- enum msm_core_control_event event)
+/* reference to be used in idle and freq callbacks */
+static struct msm_priv *the_msm_priv;
+
+static int msm_idle_enable(int type_core_num,
+ enum msm_core_control_event event)
{
- struct msm_priv *priv = container_of(self, struct msm_priv,
- idle_source);
+ struct msm_priv *priv = the_msm_priv;
switch (event) {
case MSM_DCVS_ENABLE_IDLE_PULSE:
@@ -53,12 +53,10 @@
/* Set the requested frequency if it is within 5MHz (delta) of a
* supported frequency.
*/
-static int msm_set_freq(struct msm_dcvs_freq *self,
- unsigned int freq)
+static int msm_set_freq(int core_num, unsigned int freq)
{
int i, delta = 5000000;
- struct msm_priv *priv = container_of(self, struct msm_priv,
- freq_sink);
+ struct msm_priv *priv = the_msm_priv;
struct kgsl_device *device = priv->device;
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
@@ -79,10 +77,10 @@
return priv->cur_freq / 1000;
}
-static unsigned int msm_get_freq(struct msm_dcvs_freq *self)
+static unsigned int msm_get_freq(int core_num)
{
- struct msm_priv *priv = container_of(self, struct msm_priv,
- freq_sink);
+ struct msm_priv *priv = the_msm_priv;
+
/* return current frequency in kHz */
return priv->cur_freq / 1000;
}
@@ -92,7 +90,7 @@
{
struct msm_priv *priv = pwrscale->priv;
if (priv->enabled && !priv->gpu_busy) {
- msm_dcvs_idle(priv->handle, MSM_DCVS_IDLE_EXIT, 0);
+ msm_dcvs_idle(priv->dcvs_core_id, MSM_DCVS_IDLE_EXIT, 0);
trace_kgsl_mpdcvs(device, 1);
priv->gpu_busy = 1;
}
@@ -106,7 +104,8 @@
if (priv->enabled && priv->gpu_busy)
if (device->ftbl->isidle(device)) {
- msm_dcvs_idle(priv->handle, MSM_DCVS_IDLE_ENTER, 0);
+ msm_dcvs_idle(priv->dcvs_core_id,
+ MSM_DCVS_IDLE_ENTER, 0);
trace_kgsl_mpdcvs(device, 0);
priv->gpu_busy = 0;
}
@@ -119,7 +118,7 @@
struct msm_priv *priv = pwrscale->priv;
if (priv->enabled && priv->gpu_busy) {
- msm_dcvs_idle(priv->handle, MSM_DCVS_IDLE_ENTER, 0);
+ msm_dcvs_idle(priv->dcvs_core_id, MSM_DCVS_IDLE_ENTER, 0);
trace_kgsl_mpdcvs(device, 0);
priv->gpu_busy = 0;
}
@@ -154,47 +153,46 @@
{
struct msm_priv *priv;
struct msm_dcvs_freq_entry *tbl;
- int i, ret, low_level;
+ int i, ret = -EINVAL, low_level;
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
struct platform_device *pdev =
container_of(device->parentdev, struct platform_device, dev);
struct kgsl_device_platform_data *pdata = pdev->dev.platform_data;
- priv = pwrscale->priv = kzalloc(sizeof(struct msm_priv),
- GFP_KERNEL);
- if (pwrscale->priv == NULL)
- return -ENOMEM;
+ if (the_msm_priv) {
+ priv = pwrscale->priv = the_msm_priv;
+ } else {
+ priv = pwrscale->priv = kzalloc(sizeof(struct msm_priv),
+ GFP_KERNEL);
+ if (pwrscale->priv == NULL)
+ return -ENOMEM;
- priv->core_info = pdata->core_info;
- tbl = priv->core_info->freq_tbl;
- /* Fill in frequency table from low to high, reversing order. */
- low_level = pwr->num_pwrlevels - KGSL_PWRLEVEL_LAST_OFFSET;
- for (i = 0; i <= low_level; i++)
- tbl[i].freq = pwr->pwrlevels[low_level - i].gpu_freq / 1000;
- ret = msm_dcvs_register_core(device->name, priv->core_info);
- if (ret) {
- KGSL_PWR_ERR(device, "msm_dcvs_register_core failed");
- goto err;
+ priv->core_info = pdata->core_info;
+ tbl = priv->core_info->freq_tbl;
+ /* Fill in frequency table from low to high, reversing order. */
+ low_level = pwr->num_pwrlevels - KGSL_PWRLEVEL_LAST_OFFSET;
+ for (i = 0; i <= low_level; i++)
+ tbl[i].freq =
+ pwr->pwrlevels[low_level - i].gpu_freq / 1000;
+ priv->dcvs_core_id =
+ msm_dcvs_register_core(MSM_DCVS_CORE_TYPE_GPU,
+ 0,
+ priv->core_info,
+ msm_set_freq, msm_get_freq, msm_idle_enable,
+ priv->core_info->sensors[0]);
+ if (priv->dcvs_core_id < 0) {
+ KGSL_PWR_ERR(device, "msm_dcvs_register_core failed");
+ goto err;
+ }
+ the_msm_priv = priv;
}
-
priv->device = device;
- priv->idle_source.enable = msm_idle_enable;
- priv->idle_source.core_name = device->name;
- priv->handle = msm_dcvs_idle_source_register(&priv->idle_source);
- if (priv->handle < 0) {
- ret = priv->handle;
- KGSL_PWR_ERR(device, "msm_dcvs_idle_source_register failed\n");
- goto err;
- }
-
- priv->freq_sink.core_name = device->name;
- priv->freq_sink.set_frequency = msm_set_freq;
- priv->freq_sink.get_frequency = msm_get_freq;
- ret = msm_dcvs_freq_sink_register(&priv->freq_sink);
+ ret = msm_dcvs_freq_sink_start(priv->dcvs_core_id);
if (ret >= 0) {
if (device->ftbl->isidle(device)) {
priv->gpu_busy = 0;
- msm_dcvs_idle(priv->handle, MSM_DCVS_IDLE_ENTER, 0);
+ msm_dcvs_idle(priv->dcvs_core_id,
+ MSM_DCVS_IDLE_ENTER, 0);
} else {
priv->gpu_busy = 1;
}
@@ -203,10 +201,10 @@
}
KGSL_PWR_ERR(device, "msm_dcvs_freq_sink_register failed\n");
- msm_dcvs_idle_source_unregister(&priv->idle_source);
err:
- kfree(pwrscale->priv);
+ if (!the_msm_priv)
+ kfree(pwrscale->priv);
pwrscale->priv = NULL;
return ret;
@@ -219,9 +217,7 @@
if (pwrscale->priv == NULL)
return;
- msm_dcvs_idle_source_unregister(&priv->idle_source);
- msm_dcvs_freq_sink_unregister(&priv->freq_sink);
- kfree(pwrscale->priv);
+ msm_dcvs_freq_sink_stop(priv->dcvs_core_id);
pwrscale->priv = NULL;
msm_restore_io_fraction(device);
}
diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c
index bdc5686..d48337a 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.c
+++ b/drivers/gpu/msm/kgsl_sharedmem.c
@@ -919,3 +919,42 @@
return 0;
}
EXPORT_SYMBOL(kgsl_sharedmem_map_vma);
+
+static const char * const memtype_str[] = {
+ [KGSL_MEMTYPE_OBJECTANY] = "any(0)",
+ [KGSL_MEMTYPE_FRAMEBUFFER] = "framebuffer",
+ [KGSL_MEMTYPE_RENDERBUFFER] = "renderbuffer",
+ [KGSL_MEMTYPE_ARRAYBUFFER] = "arraybuffer",
+ [KGSL_MEMTYPE_ELEMENTARRAYBUFFER] = "elementarraybuffer",
+ [KGSL_MEMTYPE_VERTEXARRAYBUFFER] = "vertexarraybuffer",
+ [KGSL_MEMTYPE_TEXTURE] = "texture",
+ [KGSL_MEMTYPE_SURFACE] = "surface",
+ [KGSL_MEMTYPE_EGL_SURFACE] = "egl_surface",
+ [KGSL_MEMTYPE_GL] = "gl",
+ [KGSL_MEMTYPE_CL] = "cl",
+ [KGSL_MEMTYPE_CL_BUFFER_MAP] = "cl_buffer_map",
+ [KGSL_MEMTYPE_CL_BUFFER_NOMAP] = "cl_buffer_nomap",
+ [KGSL_MEMTYPE_CL_IMAGE_MAP] = "cl_image_map",
+ [KGSL_MEMTYPE_CL_IMAGE_NOMAP] = "cl_image_nomap",
+ [KGSL_MEMTYPE_CL_KERNEL_STACK] = "cl_kernel_stack",
+ [KGSL_MEMTYPE_COMMAND] = "command",
+ [KGSL_MEMTYPE_2D] = "2d",
+ [KGSL_MEMTYPE_EGL_IMAGE] = "egl_image",
+ [KGSL_MEMTYPE_EGL_SHADOW] = "egl_shadow",
+ [KGSL_MEMTYPE_MULTISAMPLE] = "egl_multisample",
+ /* KGSL_MEMTYPE_KERNEL handled below, to avoid huge array */
+};
+
+void kgsl_get_memory_usage(char *name, size_t name_size, unsigned int memflags)
+{
+ unsigned char type;
+
+ type = (memflags & KGSL_MEMTYPE_MASK) >> KGSL_MEMTYPE_SHIFT;
+ if (type == KGSL_MEMTYPE_KERNEL)
+ strlcpy(name, "kernel", name_size);
+ else if (type < ARRAY_SIZE(memtype_str) && memtype_str[type] != NULL)
+ strlcpy(name, memtype_str[type], name_size);
+ else
+ snprintf(name, name_size, "unknown(%3d)", type);
+}
+EXPORT_SYMBOL(kgsl_get_memory_usage);
diff --git a/drivers/gpu/msm/kgsl_trace.h b/drivers/gpu/msm/kgsl_trace.h
index bba06bc..81cb34f 100644
--- a/drivers/gpu/msm/kgsl_trace.h
+++ b/drivers/gpu/msm/kgsl_trace.h
@@ -316,17 +316,21 @@
__field(unsigned int, gpuaddr)
__field(unsigned int, size)
__field(unsigned int, tgid)
+ __array(char, usage, 16)
),
TP_fast_assign(
__entry->gpuaddr = mem_entry->memdesc.gpuaddr;
__entry->size = mem_entry->memdesc.size;
__entry->tgid = mem_entry->priv->pid;
+ kgsl_get_memory_usage(__entry->usage, sizeof(__entry->usage),
+ mem_entry->memdesc.priv);
),
TP_printk(
- "gpuaddr=0x%08x size=%d tgid=%d",
- __entry->gpuaddr, __entry->size, __entry->tgid
+ "gpuaddr=0x%08x size=%d tgid=%d usage=%s",
+ __entry->gpuaddr, __entry->size, __entry->tgid,
+ __entry->usage
)
);
@@ -342,6 +346,7 @@
__field(int, fd)
__field(int, type)
__field(unsigned int, tgid)
+ __array(char, usage, 16)
),
TP_fast_assign(
@@ -350,12 +355,15 @@
__entry->fd = fd;
__entry->type = mem_entry->memtype;
__entry->tgid = mem_entry->priv->pid;
+ kgsl_get_memory_usage(__entry->usage, sizeof(__entry->usage),
+ mem_entry->memdesc.priv);
),
TP_printk(
- "gpuaddr=0x%08x size=%d type=%d fd=%d tgid=%d",
+ "gpuaddr=0x%08x size=%d type=%d fd=%d tgid=%d usage %s",
__entry->gpuaddr, __entry->size,
- __entry->type, __entry->fd, __entry->tgid
+ __entry->type, __entry->fd, __entry->tgid,
+ __entry->usage
)
);
@@ -371,6 +379,7 @@
__field(int, type)
__field(int, fd)
__field(unsigned int, tgid)
+ __array(char, usage, 16)
),
TP_fast_assign(
@@ -378,12 +387,14 @@
__entry->size = mem_entry->memdesc.size;
__entry->type = mem_entry->memtype;
__entry->tgid = mem_entry->priv->pid;
+ kgsl_get_memory_usage(__entry->usage, sizeof(__entry->usage),
+ mem_entry->memdesc.priv);
),
TP_printk(
- "gpuaddr=0x%08x size=%d type=%d tgid=%d",
+ "gpuaddr=0x%08x size=%d type=%d tgid=%d usage=%s",
__entry->gpuaddr, __entry->size, __entry->type,
- __entry->tgid
+ __entry->tgid, __entry->usage
)
);
@@ -399,6 +410,7 @@
__field(unsigned int, gpuaddr)
__field(unsigned int, size)
__field(int, type)
+ __array(char, usage, 16)
__field(unsigned int, drawctxt_id)
__field(unsigned int, curr_ts)
__field(unsigned int, free_ts)
@@ -408,6 +420,8 @@
__assign_str(device_name, device->name);
__entry->gpuaddr = mem_entry->memdesc.gpuaddr;
__entry->size = mem_entry->memdesc.size;
+ kgsl_get_memory_usage(__entry->usage, sizeof(__entry->usage),
+ mem_entry->memdesc.priv);
__entry->drawctxt_id = id;
__entry->type = mem_entry->memtype;
__entry->curr_ts = curr_ts;
@@ -415,12 +429,13 @@
),
TP_printk(
- "d_name=%s gpuaddr=0x%08x size=%d type=%d ctx=%u"
+ "d_name=%s gpuaddr=0x%08x size=%d type=%d usage=%s ctx=%u"
" curr_ts=0x%x free_ts=0x%x",
__get_str(device_name),
__entry->gpuaddr,
__entry->size,
__entry->type,
+ __entry->usage,
__entry->drawctxt_id,
__entry->curr_ts,
__entry->free_ts
diff --git a/drivers/input/misc/pmic8xxx-pwrkey.c b/drivers/input/misc/pmic8xxx-pwrkey.c
index 775e95d..abd66f4 100644
--- a/drivers/input/misc/pmic8xxx-pwrkey.c
+++ b/drivers/input/misc/pmic8xxx-pwrkey.c
@@ -104,14 +104,75 @@
static SIMPLE_DEV_PM_OPS(pm8xxx_pwr_key_pm_ops,
pmic8xxx_pwrkey_suspend, pmic8xxx_pwrkey_resume);
+static int pmic8xxx_set_pon1(struct device *dev, u32 debounce_us, bool pull_up)
+{
+ int err;
+ u32 delay;
+ u8 pon_cntl;
+
+ /* Valid range of pwr key trigger delay is 1/64 sec to 2 seconds. */
+ if (debounce_us > USEC_PER_SEC * 2 ||
+ debounce_us < USEC_PER_SEC / 64) {
+ dev_err(dev, "invalid power key trigger delay\n");
+ return -EINVAL;
+ }
+
+ delay = (debounce_us << 6) / USEC_PER_SEC;
+ delay = ilog2(delay);
+
+ err = pm8xxx_readb(dev->parent, PON_CNTL_1, &pon_cntl);
+ if (err < 0) {
+ dev_err(dev, "failed reading PON_CNTL_1 err=%d\n", err);
+ return err;
+ }
+
+ pon_cntl &= ~PON_CNTL_TRIG_DELAY_MASK;
+ pon_cntl |= (delay & PON_CNTL_TRIG_DELAY_MASK);
+
+ if (pull_up)
+ pon_cntl |= PON_CNTL_PULL_UP;
+ else
+ pon_cntl &= ~PON_CNTL_PULL_UP;
+
+ err = pm8xxx_writeb(dev->parent, PON_CNTL_1, pon_cntl);
+ if (err < 0) {
+ dev_err(dev, "failed writing PON_CNTL_1 err=%d\n", err);
+ return err;
+ }
+
+ return 0;
+}
+
+static ssize_t pmic8xxx_debounce_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct pmic8xxx_pwrkey *pwrkey = dev_get_drvdata(dev);
+ int err;
+ unsigned long val;
+
+ if (size > 8)
+ return -EINVAL;
+
+ err = kstrtoul(buf, 10, &val);
+ if (err < 0)
+ return err;
+
+ err = pmic8xxx_set_pon1(dev, val, pwrkey->pdata->pull_up);
+ if (err < 0)
+ return err;
+
+ return size;
+}
+
+static DEVICE_ATTR(debounce_us, 0664, NULL, pmic8xxx_debounce_store);
+
static int __devinit pmic8xxx_pwrkey_probe(struct platform_device *pdev)
{
struct input_dev *pwr;
int key_release_irq = platform_get_irq(pdev, 0);
int key_press_irq = platform_get_irq(pdev, 1);
int err;
- unsigned int delay;
- u8 pon_cntl;
struct pmic8xxx_pwrkey *pwrkey;
const struct pm8xxx_pwrkey_platform_data *pdata =
dev_get_platdata(&pdev->dev);
@@ -121,13 +182,6 @@
return -EINVAL;
}
- /* Valid range of pwr key trigger delay is 1/64 sec to 2 seconds. */
- if (pdata->kpd_trigger_delay_us > USEC_PER_SEC * 2 ||
- pdata->kpd_trigger_delay_us < USEC_PER_SEC / 64) {
- dev_err(&pdev->dev, "invalid power key trigger delay\n");
- return -EINVAL;
- }
-
pwrkey = kzalloc(sizeof(*pwrkey), GFP_KERNEL);
if (!pwrkey)
return -ENOMEM;
@@ -147,25 +201,10 @@
pwr->phys = "pmic8xxx_pwrkey/input0";
pwr->dev.parent = &pdev->dev;
- delay = (pdata->kpd_trigger_delay_us << 6) / USEC_PER_SEC;
- delay = ilog2(delay);
-
- err = pm8xxx_readb(pdev->dev.parent, PON_CNTL_1, &pon_cntl);
- if (err < 0) {
- dev_err(&pdev->dev, "failed reading PON_CNTL_1 err=%d\n", err);
- goto free_input_dev;
- }
-
- pon_cntl &= ~PON_CNTL_TRIG_DELAY_MASK;
- pon_cntl |= (delay & PON_CNTL_TRIG_DELAY_MASK);
- if (pdata->pull_up)
- pon_cntl |= PON_CNTL_PULL_UP;
- else
- pon_cntl &= ~PON_CNTL_PULL_UP;
-
- err = pm8xxx_writeb(pdev->dev.parent, PON_CNTL_1, pon_cntl);
- if (err < 0) {
- dev_err(&pdev->dev, "failed writing PON_CNTL_1 err=%d\n", err);
+ err = pmic8xxx_set_pon1(&pdev->dev,
+ pdata->kpd_trigger_delay_us, pdata->pull_up);
+ if (err) {
+ dev_dbg(&pdev->dev, "Can't set PON CTRL1 register: %d\n", err);
goto free_input_dev;
}
@@ -211,12 +250,22 @@
goto free_press_irq;
}
+ err = device_create_file(&pdev->dev, &dev_attr_debounce_us);
+ if (err < 0) {
+ dev_err(&pdev->dev,
+ "dev file creation for debounce failed: %d\n",
+ err);
+ goto free_rel_irq;
+ }
+
device_init_wakeup(&pdev->dev, pdata->wakeup);
return 0;
+free_rel_irq:
+ free_irq(key_release_irq, pwrkey);
free_press_irq:
- free_irq(key_press_irq, NULL);
+ free_irq(key_press_irq, pwrkey);
unreg_input_dev:
platform_set_drvdata(pdev, NULL);
input_unregister_device(pwr);
@@ -236,6 +285,7 @@
device_init_wakeup(&pdev->dev, 0);
+ device_remove_file(&pdev->dev, &dev_attr_debounce_us);
free_irq(key_press_irq, pwrkey);
free_irq(key_release_irq, pwrkey);
input_unregister_device(pwrkey->pwr);
diff --git a/drivers/iommu/msm_iommu-v2.c b/drivers/iommu/msm_iommu-v2.c
index f49d009..9d88fdd 100644
--- a/drivers/iommu/msm_iommu-v2.c
+++ b/drivers/iommu/msm_iommu-v2.c
@@ -148,9 +148,9 @@
return ret;
}
-static void __reset_iommu(void __iomem *base, int smt_size)
+static void __reset_iommu(void __iomem *base)
{
- int i;
+ int i, smt_size;
SET_ACR(base, 0);
SET_NSACR(base, 0);
@@ -162,6 +162,7 @@
SET_PMCR(base, 0);
SET_SCR1(base, 0);
SET_SSDR_N(base, 0, 0);
+ smt_size = GET_IDR0_NUMSMRG(base);
for (i = 0; i < smt_size; i++)
SET_SMR_VALID(base, i, 0);
@@ -169,11 +170,11 @@
mb();
}
-static void __program_iommu(void __iomem *base, int smt_size,
+static void __program_iommu(void __iomem *base,
struct msm_iommu_bfb_settings *bfb_settings)
{
int i;
- __reset_iommu(base, smt_size);
+ __reset_iommu(base);
SET_CR0_SMCFCFG(base, 1);
SET_CR0_USFCFG(base, 1);
@@ -208,9 +209,10 @@
mb();
}
-static void __release_smg(void __iomem *base, int ctx, int smt_size)
+static void __release_smg(void __iomem *base, int ctx)
{
- int i;
+ int i, smt_size;
+ smt_size = GET_IDR0_NUMSMRG(base);
/* Invalidate any SMGs associated with this context */
for (i = 0; i < smt_size; i++)
@@ -221,14 +223,14 @@
static void __program_context(void __iomem *base, int ctx, int ncb,
phys_addr_t pgtable, int redirect,
- u32 *sids, int len, int smt_size)
+ u32 *sids, int len)
{
unsigned int prrr, nmrr;
unsigned int pn;
- int i, j, found, num = 0;
+ int i, j, found, num = 0, smt_size;
__reset_context(base, ctx);
-
+ smt_size = GET_IDR0_NUMSMRG(base);
pn = pgtable >> CB_TTBR0_ADDR_SHIFT;
SET_TTBCR(base, ctx, 0);
SET_CB_TTBR0_ADDR(base, ctx, pn);
@@ -435,13 +437,12 @@
}
if (!msm_iommu_ctx_attached(dev->parent))
- __program_iommu(iommu_drvdata->base, iommu_drvdata->nsmr,
+ __program_iommu(iommu_drvdata->base,
iommu_drvdata->bfb_settings);
__program_context(iommu_drvdata->base, ctx_drvdata->num,
iommu_drvdata->ncb, __pa(priv->pt.fl_table),
- priv->pt.redirect, ctx_drvdata->sids, ctx_drvdata->nsid,
- iommu_drvdata->nsmr);
+ priv->pt.redirect, ctx_drvdata->sids, ctx_drvdata->nsid);
__disable_clocks(iommu_drvdata);
list_add(&(ctx_drvdata->attached_elm), &priv->list_attached);
@@ -478,8 +479,7 @@
GET_CB_CONTEXTIDR_ASID(iommu_drvdata->base, ctx_drvdata->num));
__reset_context(iommu_drvdata->base, ctx_drvdata->num);
- __release_smg(iommu_drvdata->base, ctx_drvdata->num,
- iommu_drvdata->nsmr);
+ __release_smg(iommu_drvdata->base, ctx_drvdata->num);
__disable_clocks(iommu_drvdata);
diff --git a/drivers/iommu/msm_iommu_dev-v2.c b/drivers/iommu/msm_iommu_dev-v2.c
index 237d601..68612ba 100644
--- a/drivers/iommu/msm_iommu_dev-v2.c
+++ b/drivers/iommu/msm_iommu_dev-v2.c
@@ -94,7 +94,6 @@
{
struct device_node *child;
int ret = 0;
- u32 nsmr;
ret = device_move(&pdev->dev, &msm_iommu_root_dev->dev, DPM_ORDER_NONE);
if (ret)
@@ -104,18 +103,6 @@
if (ret)
goto fail;
- ret = of_property_read_u32(pdev->dev.of_node, "qcom,iommu-smt-size",
- &nsmr);
- if (ret)
- goto fail;
-
- if (nsmr > MAX_NUM_SMR) {
- pr_err("Invalid SMT size: %d\n", nsmr);
- ret = -EINVAL;
- goto fail;
- }
-
- drvdata->nsmr = nsmr;
for_each_child_of_node(pdev->dev.of_node, child) {
drvdata->ncb++;
if (!of_platform_device_create(child, NULL, &pdev->dev))
diff --git a/drivers/media/video/msm_vidc/msm_vdec.c b/drivers/media/video/msm_vidc/msm_vdec.c
index d843d87..e7b5caf 100644
--- a/drivers/media/video/msm_vidc/msm_vdec.c
+++ b/drivers/media/video/msm_vidc/msm_vdec.c
@@ -709,7 +709,6 @@
static inline int start_streaming(struct msm_vidc_inst *inst)
{
int rc = 0;
- unsigned long flags;
struct vb2_buf_entry *temp;
struct list_head *ptr, *next;
inst->in_reconfig = false;
@@ -737,7 +736,7 @@
goto fail_start;
}
- spin_lock_irqsave(&inst->lock, flags);
+ mutex_lock(&inst->sync_lock);
if (!list_empty(&inst->pendingq)) {
list_for_each_safe(ptr, next, &inst->pendingq) {
temp = list_entry(ptr, struct vb2_buf_entry, list);
@@ -751,7 +750,7 @@
kfree(temp);
}
}
- spin_unlock_irqrestore(&inst->lock, flags);
+ mutex_unlock(&inst->sync_lock);
return rc;
fail_start:
return rc;
diff --git a/drivers/media/video/msm_vidc/msm_venc.c b/drivers/media/video/msm_vidc/msm_venc.c
index 948676a..73a7f8b 100644
--- a/drivers/media/video/msm_vidc/msm_venc.c
+++ b/drivers/media/video/msm_vidc/msm_venc.c
@@ -626,7 +626,9 @@
}
*num_planes = 1;
spin_lock_irqsave(&inst->lock, flags);
- *num_buffers = inst->buff_req.buffer[0].buffer_count_actual;
+ *num_buffers = inst->buff_req.buffer[0].buffer_count_actual =
+ max(*num_buffers, inst->buff_req.buffer[0].
+ buffer_count_actual);
spin_unlock_irqrestore(&inst->lock, flags);
dprintk(VIDC_DBG, "size = %d, alignment = %d, count = %d\n",
inst->buff_req.buffer[0].buffer_size,
@@ -648,7 +650,6 @@
static inline int start_streaming(struct msm_vidc_inst *inst)
{
int rc = 0;
- unsigned long flags;
struct vb2_buf_entry *temp;
struct list_head *ptr, *next;
@@ -679,7 +680,7 @@
"Failed to move inst: %p to start done state\n", inst);
goto fail_start;
}
- spin_lock_irqsave(&inst->lock, flags);
+ mutex_lock(&inst->sync_lock);
if (!list_empty(&inst->pendingq)) {
list_for_each_safe(ptr, next, &inst->pendingq) {
temp = list_entry(ptr, struct vb2_buf_entry, list);
@@ -693,7 +694,7 @@
kfree(temp);
}
}
- spin_unlock_irqrestore(&inst->lock, flags);
+ mutex_unlock(&inst->sync_lock);
return rc;
fail_start:
return rc;
diff --git a/drivers/media/video/msm_vidc/msm_vidc_common.c b/drivers/media/video/msm_vidc/msm_vidc_common.c
index 1cad40f..a6805af 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_common.c
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.c
@@ -1451,7 +1451,6 @@
int rc = 0;
struct vb2_queue *q;
struct msm_vidc_inst *inst;
- unsigned long flags;
struct vb2_buf_entry *entry;
struct vidc_frame_data frame_data;
q = vb->vb2_queue;
@@ -1468,10 +1467,9 @@
goto err_no_mem;
}
entry->vb = vb;
- dprintk(VIDC_DBG, "Queueing buffer in pendingq\n");
- spin_lock_irqsave(&inst->lock, flags);
+ mutex_lock(&inst->sync_lock);
list_add_tail(&entry->list, &inst->pendingq);
- spin_unlock_irqrestore(&inst->lock, flags);
+ mutex_unlock(&inst->sync_lock);
} else {
int64_t time_usec = timeval_to_ns(&vb->v4l2_buf.timestamp);
do_div(time_usec, NSEC_PER_USEC);
@@ -1777,18 +1775,46 @@
int rc = 0;
bool ip_flush = false;
bool op_flush = false;
+ struct list_head *ptr, *next;
+ struct vb2_buf_entry *temp;
+ struct mutex *lock;
ip_flush = flags & V4L2_QCOM_CMD_FLUSH_OUTPUT;
op_flush = flags & V4L2_QCOM_CMD_FLUSH_CAPTURE;
-
if (ip_flush && !op_flush) {
dprintk(VIDC_WARN, "Input only flush not supported\n");
return 0;
}
mutex_lock(&inst->sync_lock);
if (inst->in_reconfig && !ip_flush && op_flush) {
+ if (!list_empty(&inst->pendingq)) {
+ /*Execution can never reach here since port reconfig
+ * wont happen unless pendingq is emptied out
+ * (both pendingq and flush being secured with same
+ * lock). Printing a message here incase this breaks.*/
+ dprintk(VIDC_WARN,
+ "FLUSH BUG: Pending q not empty! It should be empty\n");
+ }
rc = vidc_hal_session_flush(inst->session,
HAL_FLUSH_OUTPUT);
} else {
+ if (!list_empty(&inst->pendingq)) {
+ /*If flush is called after queueing buffers but before
+ * streamon driver should flush the pending queue*/
+ list_for_each_safe(ptr, next, &inst->pendingq) {
+ temp =
+ list_entry(ptr, struct vb2_buf_entry, list);
+ if (temp->vb->v4l2_buf.type ==
+ V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ lock = &inst->bufq[CAPTURE_PORT].lock;
+ else
+ lock = &inst->bufq[OUTPUT_PORT].lock;
+ mutex_lock(lock);
+ vb2_buffer_done(temp->vb, VB2_BUF_STATE_DONE);
+ mutex_unlock(lock);
+ list_del(&temp->list);
+ kfree(temp);
+ }
+ }
rc = vidc_hal_session_flush(inst->session,
HAL_FLUSH_ALL);
}
diff --git a/drivers/media/video/msm_vidc/msm_vidc_debug.c b/drivers/media/video/msm_vidc/msm_vidc_debug.c
index 7921f84..fa62988 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_debug.c
+++ b/drivers/media/video/msm_vidc/msm_vidc_debug.c
@@ -104,6 +104,7 @@
dprintk(VIDC_ERR, "debugfs_create_file: fail\n");
goto failed_create_dir;
}
+ msm_vidc_debug = 0x3;
failed_create_dir:
return dir;
}
diff --git a/drivers/media/video/msm_vidc/msm_vidc_debug.h b/drivers/media/video/msm_vidc/msm_vidc_debug.h
index b7928e9..f7aa742 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_debug.h
+++ b/drivers/media/video/msm_vidc/msm_vidc_debug.h
@@ -18,19 +18,24 @@
#define VIDC_DBG_TAG "msm_vidc: %d: "
+/*To enable messages OR these values and
+* echo the result to debugfs file*/
+
enum vidc_msg_prio {
- VIDC_ERR,
- VIDC_WARN,
- VIDC_INFO,
- VIDC_DBG,
+ VIDC_ERR = 0x0001,
+ VIDC_WARN = 0x0002,
+ VIDC_INFO = 0x0004,
+ VIDC_DBG = 0x0008,
+ VIDC_PROF = 0x0010,
+ VIDC_FW = 0x1000,
};
extern int msm_vidc_debug;
-#define dprintk(level, fmt, arg...) \
- do { \
- if (msm_vidc_debug >= level) \
- printk(KERN_DEBUG VIDC_DBG_TAG fmt, \
- level, ## arg); \
+#define dprintk(__level, __fmt, arg...) \
+ do { \
+ if (msm_vidc_debug & __level) \
+ printk(KERN_DEBUG VIDC_DBG_TAG __fmt,\
+ __level, ## arg); \
} while (0)
struct dentry *msm_vidc_debugfs_init_core(struct msm_vidc_core *core,
diff --git a/drivers/media/video/msm_vidc/vidc_hal.c b/drivers/media/video/msm_vidc/vidc_hal.c
index f0d0e73..8ac35d9 100644
--- a/drivers/media/video/msm_vidc/vidc_hal.c
+++ b/drivers/media/video/msm_vidc/vidc_hal.c
@@ -1437,6 +1437,7 @@
prop->multi_slice);
break;
}
+ hfi->slice_size = prop->slice_size;
pkt->size += sizeof(u32) + sizeof(struct
hfi_multi_slice_control);
break;
diff --git a/drivers/media/video/msm_vidc/vidc_hal_api.h b/drivers/media/video/msm_vidc/vidc_hal_api.h
index 659cf7e..879418d 100644
--- a/drivers/media/video/msm_vidc/vidc_hal_api.h
+++ b/drivers/media/video/msm_vidc/vidc_hal_api.h
@@ -210,7 +210,7 @@
enum hal_mpeg4_profile {
HAL_MPEG4_PROFILE_SIMPLE = 0x00000001,
- HAL_MPEG4_PROFILE_SIMPLESCALABLE = 0x00000002,
+ HAL_MPEG4_PROFILE_ADVANCEDSIMPLE = 0x00000002,
HAL_MPEG4_PROFILE_CORE = 0x00000004,
HAL_MPEG4_PROFILE_MAIN = 0x00000008,
HAL_MPEG4_PROFILE_NBIT = 0x00000010,
@@ -224,7 +224,7 @@
HAL_MPEG4_PROFILE_ADVANCEDCODING = 0x00001000,
HAL_MPEG4_PROFILE_ADVANCEDCORE = 0x00002000,
HAL_MPEG4_PROFILE_ADVANCEDSCALABLE = 0x00004000,
- HAL_MPEG4_PROFILE_ADVANCEDSIMPLE = 0x00008000,
+ HAL_MPEG4_PROFILE_SIMPLESCALABLE = 0x00008000,
HAL_UNUSED_MPEG4_PROFILE = 0x10000000,
};
diff --git a/drivers/media/video/vcap_v4l2.c b/drivers/media/video/vcap_v4l2.c
index 753171c..a160915 100644
--- a/drivers/media/video/vcap_v4l2.c
+++ b/drivers/media/video/vcap_v4l2.c
@@ -19,6 +19,8 @@
#include <linux/videodev2.h>
#include <linux/platform_device.h>
#include <linux/memory_alloc.h>
+#include <linux/ctype.h>
+#include <linux/debugfs.h>
#include <mach/board.h>
#include <mach/gpio.h>
@@ -51,13 +53,31 @@
static struct vcap_dev *vcap_ctrl;
-static unsigned debug;
-
-#define dprintk(level, fmt, arg...) \
- do { \
- if (debug >= level) \
- printk(KERN_DEBUG "VCAP: " fmt, ## arg); \
- } while (0)
+#ifdef CONFIG_DEBUG_FS
+static struct dentry *vcap_debugfs_base;
+static struct reg_range debug_reg_range[] = {
+ {
+ VCAP_REG_RANGE_1_MIN,
+ VCAP_REG_RANGE_1_MAX,
+ },
+ {
+ VCAP_REG_RANGE_2_MIN,
+ VCAP_REG_RANGE_2_MAX,
+ },
+ {
+ VCAP_REG_RANGE_3_MIN,
+ VCAP_REG_RANGE_3_MAX,
+ },
+ {
+ VCAP_REG_RANGE_4_MIN,
+ VCAP_REG_RANGE_4_MAX,
+ },
+ {
+ VCAP_REG_RANGE_5_MIN,
+ VCAP_REG_RANGE_5_MAX,
+ },
+};
+#endif
int vcap_reg_powerup(struct vcap_dev *dev)
{
@@ -91,7 +111,7 @@
int num_gpios = pdata->num_gpios;
unsigned *gpios = pdata->gpios;
- dprintk(4, "GPIO config start\n");
+ pr_debug("GPIO config start\n");
if (on) {
for (i = 0; i < num_gpios; i++) {
ret = gpio_request(gpios[i], "vcap:vc");
@@ -112,7 +132,7 @@
for (i = 0; i < num_gpios; i++)
gpio_free(gpios[i]);
}
- dprintk(4, "GPIO config exit\n");
+ pr_debug("GPIO config exit\n");
return 0;
gpio_failed:
for (i--; i >= 0; i--)
@@ -151,6 +171,7 @@
pr_err("%s: Failed core set_rate %d\n", __func__, ret);
goto fail_vcap_clk;
}
+ dev->dbg_p.clk_rate = (uint32_t) rate;
dev->vcap_npl_clk = clk_get(ddev, "vcap_npl_clk");
if (IS_ERR(dev->vcap_npl_clk)) {
@@ -198,6 +219,7 @@
dev->vcap_npl_clk = NULL;
fail_vcap_clk:
+ dev->dbg_p.clk_rate = 0;
clk_disable(dev->vcap_clk);
fail_vcap_clk_unprep:
clk_unprepare(dev->vcap_clk);
@@ -228,6 +250,8 @@
clk_put(dev->vcap_clk);
dev->vcap_clk = NULL;
}
+
+ dev->dbg_p.clk_rate = 0;
}
int vcap_get_bus_client_handle(struct vcap_dev *dev)
@@ -244,6 +268,7 @@
unsigned long rate)
{
int rc;
+ pr_debug("Enter %s", __func__);
rc = vcap_reg_powerup(dev);
if (rc < 0)
@@ -259,6 +284,7 @@
goto gpio_failed;
writel_relaxed(0x00030003, VCAP_OFFSET(0xD78));
writel_relaxed(0x00030003, VCAP_OFFSET(0xD7C));
+ pr_debug("Success Exit %s", __func__);
return 0;
gpio_failed:
@@ -274,10 +300,12 @@
int vcap_disable(struct vcap_dev *dev)
{
+ pr_debug("Enter %s", __func__);
config_gpios(0, dev->vcap_pdata);
msm_bus_scale_unregister_client(dev->bus_client_handle);
dev->bus_client_handle = 0;
+ dev->dbg_p.bw_request = 0;
vcap_clk_powerdown(dev);
vcap_reg_powerdown(dev);
return 0;
@@ -311,34 +339,34 @@
struct vb2_buffer *vb;
if (q->fileio) {
- dprintk(1, "%s: file io in progress\n", __func__);
+ pr_debug("%s: file io in progress\n", __func__);
return -EBUSY;
}
if (b->type != q->type) {
- dprintk(1, "%s: invalid buffer type\n", __func__);
+ pr_debug("%s: invalid buffer type\n", __func__);
return -EINVAL;
}
if (b->index >= q->num_buffers) {
- dprintk(1, "%s: buffer index out of range\n", __func__);
+ pr_debug("%s: buffer index out of range\n", __func__);
return -EINVAL;
}
vb = q->bufs[b->index];
if (NULL == vb) {
- dprintk(1, "%s: buffer is NULL\n", __func__);
+ pr_debug("%s: buffer is NULL\n", __func__);
return -EINVAL;
}
if (b->memory != q->memory) {
- dprintk(1, "%s: invalid memory type\n", __func__);
+ pr_debug("%s: invalid memory type\n", __func__);
return -EINVAL;
}
if (vb->state != VB2_BUF_STATE_DEQUEUED &&
vb->state != VB2_BUF_STATE_PREPARED) {
- dprintk(1, "%s: buffer already in use\n", __func__);
+ pr_err("%s: buffer already in use\n", __func__);
return -EINVAL;
}
@@ -361,17 +389,17 @@
unsigned long flags;
if (q->fileio) {
- dprintk(1, "%s: file io in progress\n", __func__);
+ pr_debug("%s: file io in progress\n", __func__);
return -EBUSY;
}
if (b->type != q->type) {
- dprintk(1, "%s: invalid buffer type\n", __func__);
+ pr_debug("%s: invalid buffer type\n", __func__);
return -EINVAL;
}
if (!q->streaming) {
- dprintk(1, "Streaming off, will not wait for buffers\n");
+ pr_debug("Streaming off, will not wait for buffers\n");
return -EINVAL;
}
@@ -384,13 +412,13 @@
switch (vb->state) {
case VB2_BUF_STATE_DONE:
- dprintk(3, "%s: Returning done buffer\n", __func__);
+ pr_debug("%s: Returning done buffer\n", __func__);
break;
case VB2_BUF_STATE_ERROR:
- dprintk(3, "%s: Ret done buf with err\n", __func__);
+ pr_debug("%s: Ret done buf with err\n", __func__);
break;
default:
- dprintk(1, "%s: Invalid buffer state\n", __func__);
+ pr_debug("%s: Invalid buffer state\n", __func__);
return -EINVAL;
}
@@ -402,7 +430,7 @@
return 0;
}
- dprintk(1, "No buffers to dequeue\n");
+ pr_debug("%s: No buffers to dequeue\n", __func__);
return -EAGAIN;
}
@@ -415,28 +443,28 @@
int rc;
if (q->fileio) {
- dprintk(1, "%s: file io in progress\n", __func__);
+ pr_debug("%s: file io in progress\n", __func__);
return -EBUSY;
}
if (b->type != q->type) {
- dprintk(1, "%s: invalid buffer type\n", __func__);
+ pr_debug("%s: invalid buffer type\n", __func__);
return -EINVAL;
}
if (b->index >= q->num_buffers) {
- dprintk(1, "%s: buffer index out of range\n", __func__);
+ pr_debug("%s: buffer index out of range\n", __func__);
return -EINVAL;
}
vb = q->bufs[b->index];
if (NULL == vb) {
- dprintk(1, "%s: buffer is NULL\n", __func__);
+ pr_debug("%s: buffer is NULL\n", __func__);
return -EINVAL;
}
if (vb->state != VB2_BUF_STATE_DEQUEUED) {
- dprintk(1, "%s: buffer already in use\n", __func__);
+ pr_debug("%s: buffer already in use\n", __func__);
return -EINVAL;
}
@@ -468,7 +496,7 @@
buf = container_of(vb, struct vcap_buffer, vb);
if (buf->ion_handle == NULL) {
- dprintk(1, "%s: no ION handle to free\n", __func__);
+ pr_debug("%s: no ION handle to free\n", __func__);
return;
}
buf->paddr = 0;
@@ -546,7 +574,7 @@
static int capture_start_streaming(struct vb2_queue *vq, unsigned int count)
{
struct vcap_client_data *c_data = vb2_get_drv_priv(vq);
- dprintk(2, "VC start streaming\n");
+ pr_debug("VC start streaming\n");
return vc_start_capture(c_data);
}
@@ -643,7 +671,7 @@
static int vp_in_start_streaming(struct vb2_queue *vq, unsigned int count)
{
- dprintk(2, "VP IN start streaming\n");
+ pr_debug("VP IN start streaming\n");
return 0;
}
@@ -652,7 +680,7 @@
struct vcap_client_data *c_data = vb2_get_drv_priv(vq);
struct vb2_buffer *vb;
- dprintk(2, "VP stop streaming\n");
+ pr_debug("VP IN stop streaming\n");
while (!list_empty(&c_data->vp_action.in_active)) {
struct vcap_buffer *buf;
@@ -749,7 +777,7 @@
struct vcap_client_data *c_data = vb2_get_drv_priv(vq);
struct vb2_buffer *vb;
- dprintk(2, "VP out q stop streaming\n");
+ pr_debug("VP OUT q stop streaming\n");
vp_stop_capture(c_data);
while (!list_empty(&c_data->vp_action.out_active)) {
@@ -890,7 +918,7 @@
struct vcap_dev *dev = c_data->dev;
int rc;
- dprintk(3, "In Req Buf %08x\n", (unsigned int)rb->type);
+ pr_debug("VCAP: In Req Buf %08x\n", (unsigned int)rb->type);
c_data->op_mode = determine_mode(c_data);
if (c_data->op_mode == UNKNOWN_VCAP_OP) {
pr_err("VCAP Error: %s: VCAP in unknown mode\n", __func__);
@@ -968,25 +996,25 @@
struct vb2_queue *q;
int rc;
- dprintk(3, "In Q Buf %08x\n", (unsigned int)p->type);
+ pr_debug("VCAP In Q Buf %08x\n", (unsigned int)p->type);
switch (p->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
if (c_data->op_mode == VC_AND_VP_VCAP_OP) {
/* If buffer in vp_in_q it will be coming back */
q = &c_data->vp_in_vidq;
if (p->index >= q->num_buffers) {
- dprintk(1, "qbuf: buffer index out of range\n");
+ pr_debug("VCAP qbuf: buffer index out of range\n");
return -EINVAL;
}
vb = q->bufs[p->index];
if (NULL == vb) {
- dprintk(1, "qbuf: buffer is NULL\n");
+ pr_debug("VCAP qbuf: buffer is NULL\n");
return -EINVAL;
}
if (vb->state != VB2_BUF_STATE_DEQUEUED) {
- dprintk(1, "qbuf: buffer already in use\n");
+ pr_debug("VCAP qbuf: buffer already in use\n");
return -EINVAL;
}
rc = get_phys_addr(c_data->dev, &c_data->vc_vidq, p);
@@ -1035,7 +1063,7 @@
struct vcap_client_data *c_data = to_client_data(file->private_data);
int rc;
- dprintk(3, "In DQ Buf %08x\n", (unsigned int)p->type);
+ pr_debug("VCAP In DQ Buf %08x\n", (unsigned int)p->type);
switch (p->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
if (c_data->op_mode == VC_AND_VP_VCAP_OP)
@@ -1072,18 +1100,18 @@
int streamon_validate_q(struct vb2_queue *q)
{
if (q->fileio) {
- dprintk(1, "streamon: file io in progress\n");
+ pr_debug("%s: file io in progress\n", __func__);
return -EBUSY;
}
if (q->streaming) {
- dprintk(1, "streamon: already streaming\n");
+ pr_debug("%s: already streaming\n", __func__);
return -EBUSY;
}
if (V4L2_TYPE_IS_OUTPUT(q->type)) {
if (list_empty(&q->queued_list)) {
- dprintk(1, "streamon: no output buffers queued\n");
+ pr_debug("%s: no output buffers queued\n", __func__);
return -EINVAL;
}
}
@@ -1103,10 +1131,11 @@
idx++;
} while (idx < length);
if (idx == length) {
- pr_err("VCAP: Defaulting to highest BW request\n");
+ pr_info("VCAP: Defaulting to highest BW request\n");
idx--;
}
msm_bus_scale_client_update_request(dev->bus_client_handle, idx);
+ dev->dbg_p.bw_request = bus_vectors[idx].vectors[0].ab;
return 0;
}
@@ -1118,7 +1147,7 @@
unsigned long rate;
long rate_rc;
- dprintk(3, "In Stream ON\n");
+ pr_debug("VCAP: In Stream ON\n");
if (determine_mode(c_data) != c_data->op_mode) {
pr_err("VCAP Error: %s: s_fmt called after req_buf", __func__);
return -ENOTRECOVERABLE;
@@ -1160,6 +1189,8 @@
if (rc < 0)
goto free_res;
+ dev->dbg_p.clk_rate = (uint32_t) rate;
+
rate = (c_data->vc_format.hactive_end -
c_data->vc_format.hactive_start);
@@ -1204,6 +1235,8 @@
}
rate = (unsigned long)rate_rc;
rc = clk_set_rate(dev->vcap_clk, rate);
+
+ dev->dbg_p.clk_rate = (uint32_t) rate;
if (rc < 0)
goto free_res;
@@ -1279,6 +1312,8 @@
if (rc < 0)
goto free_res;
+ dev->dbg_p.clk_rate = (uint32_t) rate;
+
rate = (c_data->vc_format.hactive_end -
c_data->vc_format.hactive_start);
@@ -1376,12 +1411,12 @@
int streamoff_validate_q(struct vb2_queue *q)
{
if (q->fileio) {
- dprintk(1, "streamoff: file io in progress\n");
+ pr_debug("%s: file io in progress\n", __func__);
return -EBUSY;
}
if (!q->streaming) {
- dprintk(1, "streamoff: not streaming\n");
+ pr_debug("%s: not streaming\n", __func__);
return -EINVAL;
}
return 0;
@@ -1791,7 +1826,7 @@
struct vb2_queue *q;
unsigned int mask = 0;
- dprintk(1, "Enter slect/poll\n");
+ pr_debug("%s: Enter slect/poll\n", __func__);
switch (c_data->op_mode) {
case VC_VCAP_OP:
@@ -1866,13 +1901,276 @@
return vc_handler(vcap_ctrl);
}
+#ifdef CONFIG_DEBUG_FS
+/* Query VCAP resource usage */
+static ssize_t read_dump_info(struct file *file, char __user *user_buf,
+ size_t len, loff_t *ppos)
+{
+ struct vcap_dev *dev = file->private_data;
+ char str_buf[512];
+ size_t tot_size = 0, size;
+
+ if (dev->vc_client) {
+ size = scnprintf(str_buf + tot_size, sizeof(str_buf) - tot_size,
+ "VCAP: VC\n");
+ tot_size += size;
+ size = scnprintf(str_buf + tot_size, sizeof(str_buf) - tot_size,
+ "vc_resourse = %d\n", dev->vc_resource);
+ tot_size += size;
+ size = scnprintf(str_buf + tot_size, sizeof(str_buf) - tot_size,
+ "vc_enabled = %d\n", atomic_read(&dev->vc_enabled));
+ tot_size += size;
+ size = scnprintf(str_buf + tot_size, sizeof(str_buf) - tot_size,
+ "vc_client id = %p\n", dev->vc_client);
+ tot_size += size;
+ size = scnprintf(str_buf + tot_size, sizeof(str_buf) - tot_size,
+ "vc_queue_count = %d\n",
+ atomic_read(&dev->vc_client->vc_vidq.queued_count));
+ tot_size += size;
+ size = scnprintf(str_buf + tot_size, sizeof(str_buf) - tot_size,
+ "vc_total_buffers = %d\n",
+ dev->vc_client->vc_action.tot_buf);
+ tot_size += size;
+ } else {
+ size = scnprintf(str_buf + tot_size, sizeof(str_buf) - tot_size,
+ "VCAP: VC not in use\n");
+ tot_size += size;
+ }
+ if (dev->vp_client) {
+ size = scnprintf(str_buf + tot_size, sizeof(str_buf) - tot_size,
+ "VCAP: VP\n");
+ tot_size += size;
+ size = scnprintf(str_buf + tot_size, sizeof(str_buf) - tot_size,
+ "vp_resourse = %d\n", dev->vp_resource);
+ tot_size += size;
+ size = scnprintf(str_buf + tot_size, sizeof(str_buf) - tot_size,
+ "vp_enabled = %d\n", atomic_read(&dev->vp_enabled));
+ tot_size += size;
+ size = scnprintf(str_buf + tot_size, sizeof(str_buf) - tot_size,
+ "vp_client id = %p\n", dev->vp_client);
+ tot_size += size;
+ size = scnprintf(str_buf + tot_size, sizeof(str_buf) - tot_size,
+ "vp_in_queue_count = %d\n",
+ atomic_read(
+ &dev->vp_client->vp_in_vidq.queued_count));
+ tot_size += size;
+ size = scnprintf(str_buf + tot_size, sizeof(str_buf) - tot_size,
+ "vp_out_queue_count = %d\n",
+ atomic_read(
+ &dev->vp_client->vp_out_vidq.queued_count));
+ tot_size += size;
+ } else {
+ size = scnprintf(str_buf + tot_size, sizeof(str_buf) - tot_size,
+ "VCAP: VP not in use\n");
+ tot_size += size;
+ }
+
+ return simple_read_from_buffer(user_buf, len, ppos, str_buf, tot_size);
+}
+
+static const struct file_operations dump_info_fops = {
+ .read = read_dump_info,
+ .open = simple_open,
+ .llseek = default_llseek,
+};
+
+static int vcap_debug_clk_rate_get(void *data, u64 *val)
+{
+ struct vcap_dev *dev = data;
+ *val = (u64)dev->dbg_p.clk_rate;
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(clk_rate_fops, vcap_debug_clk_rate_get,
+ NULL, "%llu\n");
+
+static int vcap_debug_bw_req_get(void *data, u64 *val)
+{
+ struct vcap_dev *dev = data;
+ *val = (u64)dev->dbg_p.bw_request;
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(bw_req_fops, vcap_debug_bw_req_get,
+ NULL, "%llu\n");
+
+static int vcap_debug_drop_frames_get(void *data, u64 *val)
+{
+ struct vcap_dev *dev = data;
+ struct timeval tv;
+ int drop_count;
+
+ if (!dev->vc_resource)
+ return -EPERM;
+ drop_count = atomic_read(&dev->dbg_p.vc_drop_count);
+ atomic_set(&dev->dbg_p.vc_drop_count, 0);
+
+ do_gettimeofday(&tv);
+ dev->dbg_p.vc_timestamp = (uint32_t) (tv.tv_sec * VCAP_USEC +
+ tv.tv_usec);
+
+ *val = (u64)drop_count;
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(tot_frame_drop_fops, vcap_debug_drop_frames_get,
+ NULL, "%llu\n");
+
+static int vcap_debug_drop_fps_get(void *data, u64 *val)
+{
+ struct vcap_dev *dev = data;
+ struct timeval tv;
+ int drop_count;
+ uint32_t new_ts;
+
+ if (!dev->vc_resource)
+ return -EPERM;
+ drop_count = atomic_read(&dev->dbg_p.vc_drop_count);
+ atomic_set(&dev->dbg_p.vc_drop_count, 0);
+
+ do_gettimeofday(&tv);
+ new_ts = (uint32_t) (tv.tv_sec * VCAP_USEC +
+ tv.tv_usec);
+
+ if ((new_ts - dev->dbg_p.vc_timestamp) / VCAP_USEC &&
+ new_ts > dev->dbg_p.vc_timestamp)
+ drop_count /= ((new_ts - dev->dbg_p.vc_timestamp) / VCAP_USEC);
+ else
+ drop_count = 0;
+
+ dev->dbg_p.vc_timestamp = new_ts;
+ *val = (u64)drop_count;
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(drop_fps_fops, vcap_debug_drop_fps_get,
+ NULL, "%llu\n");
+
+static int vcap_debug_vp_lat_get(void *data, u64 *val)
+{
+ struct vcap_dev *dev = data;
+
+ if (!dev->vp_resource)
+ return -EPERM;
+ *val = (u64)dev->dbg_p.vp_ewma;
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(vp_lat_fops, vcap_debug_vp_lat_get,
+ NULL, "%llu\n");
+
+/* Read/Write to VCAP Registers */
+static int vcap_debug_reg_set(void *data, u64 val)
+{
+ struct vcap_dev *dev = data;
+ int i;
+ for (i = 0; i < ARRAY_SIZE(debug_reg_range); i++) {
+ if (val >= debug_reg_range[i].min_val && val <=
+ debug_reg_range[i].max_val)
+ break;
+ }
+ if (i == ARRAY_SIZE(debug_reg_range))
+ return -EINVAL;
+ dev->dbg_p.reg_addr = (uint32_t) val;
+ return 0;
+}
+
+static int vcap_debug_reg_get(void *data, u64 *val)
+{
+ struct vcap_dev *dev = data;
+ *val = (u64)dev->dbg_p.reg_addr;
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(vcap_reg_fops, vcap_debug_reg_get,
+ vcap_debug_reg_set, "0x%08llx\n")
+
+static int vcap_debug_reg_rdwr_set(void *data, u64 val)
+{
+ struct vcap_dev *dev = data;
+ u32 reg_val = (u32) val;
+
+ writel_iowmb(reg_val, VCAP_OFFSET(dev->dbg_p.reg_addr));
+ return 0;
+}
+
+static int vcap_debug_reg_rdwr_get(void *data, u64 *val)
+{
+ struct vcap_dev *dev = data;
+ *val = (u64)readl_relaxed(VCAP_OFFSET(dev->dbg_p.reg_addr));
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(vcap_reg_rdwr_fops, vcap_debug_reg_rdwr_get,
+ vcap_debug_reg_rdwr_set, "0x%08llx\n");
+
+static int vcap_debugfs_init(struct vcap_dev *dev)
+{
+ vcap_debugfs_base = debugfs_create_dir("vcap", NULL);
+ if (!vcap_debugfs_base)
+ return -ENOMEM;
+
+ if (!debugfs_create_file("dump_info", S_IRUGO,
+ vcap_debugfs_base, dev, &dump_info_fops))
+ goto error;
+
+ if (!debugfs_create_file("vcap_core_clk_rate", S_IRUGO,
+ vcap_debugfs_base, dev, &clk_rate_fops))
+ goto error;
+
+ if (!debugfs_create_file("vcap_bw_req", S_IRUGO,
+ vcap_debugfs_base, dev, &bw_req_fops))
+ goto error;
+
+ if (!debugfs_create_file("vc_total_frames_drop", S_IRUGO,
+ vcap_debugfs_base, dev, &tot_frame_drop_fops))
+ goto error;
+
+ if (!debugfs_create_file("vc_drop_fps", S_IRUGO,
+ vcap_debugfs_base, dev, &drop_fps_fops))
+ goto error;
+
+ if (!debugfs_create_file("vp_avg_completion_t", S_IRUGO,
+ vcap_debugfs_base, dev, &vp_lat_fops))
+ goto error;
+
+ if (!debugfs_create_file("vcap_reg_addr", S_IRUGO | S_IWUSR,
+ vcap_debugfs_base, dev, &vcap_reg_fops))
+ goto error;
+
+ if (!debugfs_create_file("vcap_reg_val", S_IRUGO | S_IWUSR,
+ vcap_debugfs_base, dev, &vcap_reg_rdwr_fops))
+ goto error;
+ return 0;
+
+error:
+ debugfs_remove_recursive(vcap_debugfs_base);
+ vcap_debugfs_base = NULL;
+ return -ENOMEM;
+}
+
+static void vcap_debugfs_remove(void)
+{
+ if (vcap_debugfs_base) {
+ debugfs_remove_recursive(vcap_debugfs_base);
+ vcap_debugfs_base = NULL;
+ }
+}
+#else
+
+static int vcap_debugfs_init(struct vcap_dev *dev)
+{
+ return 0;
+}
+static void vcap_debugfs_remove(void) {}
+#endif
+
static int __devinit vcap_probe(struct platform_device *pdev)
{
struct vcap_dev *dev;
struct video_device *vfd;
int ret;
- dprintk(1, "Probe started\n");
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev)
return -ENOMEM;
@@ -1949,6 +2247,7 @@
if (ret)
goto unreg_dev;
msm_bus_scale_client_update_request(dev->bus_client_handle, 0);
+ dev->dbg_p.bw_request = 0;
ret = detect_vc(dev);
@@ -1987,6 +2286,11 @@
goto rel_vcap_wq;
}
+ atomic_set(&dev->dbg_p.vc_drop_count, 0);
+ ret = vcap_debugfs_init(dev);
+ if (ret < 0)
+ pr_err("VCAP debugfs failed to load");
+
dev->vc_tot_buf = 2;
atomic_set(&dev->vc_enabled, 0);
atomic_set(&dev->vp_enabled, 0);
@@ -1996,7 +2300,6 @@
init_waitqueue_head(&dev->vp_dummy_waitq);
vcap_disable(dev);
- dprintk(1, "Exit probe succesfully");
return 0;
rel_vcap_wq:
destroy_workqueue(dev->vcap_wq);
@@ -2020,6 +2323,7 @@
static int __devexit vcap_remove(struct platform_device *pdev)
{
struct vcap_dev *dev = vcap_ctrl;
+ vcap_debugfs_remove();
ion_client_destroy(dev->ion_client);
flush_workqueue(dev->vcap_wq);
destroy_workqueue(dev->vcap_wq);
diff --git a/drivers/media/video/vcap_vc.c b/drivers/media/video/vcap_vc.c
index 572c272..3d81161 100644
--- a/drivers/media/video/vcap_vc.c
+++ b/drivers/media/video/vcap_vc.c
@@ -27,14 +27,6 @@
#include <media/vcap_fmt.h>
#include "vcap_vc.h"
-static unsigned debug;
-
-#define dprintk(level, fmt, arg...) \
- do { \
- if (debug >= level) \
- printk(KERN_DEBUG "VC: " fmt, ## arg); \
- } while (0)
-
void config_buffer(struct vcap_client_data *c_data,
struct vcap_buffer *buf,
void __iomem *y_addr,
@@ -73,7 +65,7 @@
vb_vc = vp_work->cd->vc_vidq.bufs[p.index];
if (NULL == vb_vc) {
- dprintk(1, "%s: buffer is NULL\n", __func__);
+ pr_debug("%s: buffer is NULL\n", __func__);
vcvp_qbuf(&vp_work->cd->vc_vidq, &p);
return;
}
@@ -81,7 +73,7 @@
vb_vp = vp_work->cd->vp_in_vidq.bufs[p.index];
if (NULL == vb_vp) {
- dprintk(1, "%s: buffer is NULL\n", __func__);
+ pr_debug("%s: buffer is NULL\n", __func__);
vcvp_qbuf(&vp_work->cd->vc_vidq, &p);
return;
}
@@ -145,7 +137,7 @@
irq = readl_relaxed(VCAP_VC_INT_STATUS);
- dprintk(1, "%s: irq=0x%08x\n", __func__, irq);
+ pr_debug("%s: irq=0x%08x\n", __func__, irq);
c_data = dev->vc_client;
if (!c_data->streaming) {
@@ -254,6 +246,8 @@
v4l2_event_queue(dev->vfd, &v4l2_evt);
c_data->vc_action.top_field =
!c_data->vc_action.top_field;
+
+ atomic_inc(&dev->dbg_p.vc_drop_count);
continue;
}
buf = list_entry(c_data->vc_action.active.next,
@@ -296,12 +290,13 @@
{
struct vc_action *vc_action = &c_data->vc_action;
struct vcap_dev *dev;
+ struct timeval tv;
unsigned long flags = 0;
int rc, i, counter = 0;
struct vcap_buffer *buf;
dev = c_data->dev;
- dprintk(2, "Start Kickoff\n");
+ pr_debug("Start Kickoff\n");
if (dev->vc_client == NULL) {
pr_err("No active vc client\n");
@@ -344,6 +339,11 @@
c_data->vc_action.vc_ts.tv_usec =
c_data->vc_action.last_ts % VCAP_USEC;
+ atomic_set(&dev->dbg_p.vc_drop_count, 0);
+ do_gettimeofday(&tv);
+ dev->dbg_p.vc_timestamp = (uint32_t) (tv.tv_sec * VCAP_USEC +
+ tv.tv_usec);
+
rc = 0;
for (i = 0; i < c_data->vc_action.tot_buf; i++)
rc = rc << 1 | 0x2;
@@ -416,7 +416,7 @@
rc = readl_relaxed(VCAP_VC_NPL_CTRL);
writel_iowmb(0x00000002, VCAP_VC_NPL_CTRL);
- dprintk(2, "%s: Starting VC configuration\n", __func__);
+ pr_debug("%s: Starting VC configuration\n", __func__);
writel_iowmb(0x00000002, VCAP_VC_NPL_CTRL);
writel_iowmb(0x00000004 | vc_format->color_space << 1 |
vc_format->mode << 3 |
@@ -464,7 +464,7 @@
writel_relaxed(0x00006b38, VCAP_VC_IN_CTRL5);
writel_iowmb(0x00000001 , VCAP_OFFSET(0x0d00));
- dprintk(2, "%s: Done VC configuration\n", __func__);
+ pr_debug("%s: Done VC configuration\n", __func__);
return 0;
}
@@ -473,7 +473,7 @@
{
int result;
result = readl_relaxed(VCAP_HARDWARE_VERSION_REG);
- dprintk(1, "Hardware version: %08x\n", result);
+ pr_debug("Hardware version: %08x\n", result);
if (result != VCAP_HARDWARE_VERSION)
return -ENODEV;
INIT_WORK(&dev->vc_to_vp_work.work, mov_buf_to_vp);
diff --git a/drivers/media/video/vcap_vp.c b/drivers/media/video/vcap_vp.c
index a017cf2..c7de465 100644
--- a/drivers/media/video/vcap_vp.c
+++ b/drivers/media/video/vcap_vp.c
@@ -25,14 +25,6 @@
#include <media/vcap_fmt.h>
#include "vcap_vp.h"
-static unsigned debug;
-
-#define dprintk(level, fmt, arg...) \
- do { \
- if (debug >= level) \
- printk(KERN_DEBUG "VP: " fmt, ## arg); \
- } while (0)
-
void config_nr_buffer(struct vcap_client_data *c_data,
struct vcap_buffer *buf)
{
@@ -72,10 +64,10 @@
if (!c_data->streaming)
return -ENOEXEC;
dev = c_data->dev;
- dprintk(2, "Start setup buffers\n");
+ pr_debug("VP: Start setup buffers\n");
if (dev->vp_shutdown) {
- dprintk(1, "%s: VP shutting down, no buf setup\n",
+ pr_debug("%s: VP shutting down, no buf setup\n",
__func__);
return -EPERM;
}
@@ -86,7 +78,7 @@
spin_lock_irqsave(&dev->vp_client->cap_slock, flags);
if (list_empty(&vp_act->in_active)) {
spin_unlock_irqrestore(&dev->vp_client->cap_slock, flags);
- dprintk(1, "%s: VP We have no more input buffers\n",
+ pr_debug("%s: VP We have no more input buffers\n",
__func__);
return -EAGAIN;
}
@@ -94,7 +86,7 @@
if (list_empty(&vp_act->out_active)) {
spin_unlock_irqrestore(&dev->vp_client->cap_slock,
flags);
- dprintk(1, "%s: VP We have no more output buffers\n",
+ pr_debug("%s: VP We have no more output buffers\n",
__func__);
return -EAGAIN;
}
@@ -136,7 +128,7 @@
vb_vc = vp_work->cd->vc_vidq.bufs[p.index];
if (NULL == vb_vc) {
- dprintk(1, "%s: buffer is NULL\n", __func__);
+ pr_debug("%s: buffer is NULL\n", __func__);
vcvp_qbuf(&vp_work->cd->vp_in_vidq, &p);
return;
}
@@ -144,7 +136,7 @@
vb_vp = vp_work->cd->vp_in_vidq.bufs[p.index];
if (NULL == vb_vp) {
- dprintk(1, "%s: buffer is NULL\n", __func__);
+ pr_debug("%s: buffer is NULL\n", __func__);
vcvp_qbuf(&vp_work->cd->vp_in_vidq, &p);
return;
}
@@ -158,7 +150,7 @@
/* This call should not fail */
rc = vcvp_qbuf(&vp_work->cd->vc_vidq, &p);
if (rc < 0) {
- dprintk(1, "%s: qbuf to vc failed\n", __func__);
+ pr_err("%s: qbuf to vc failed\n", __func__);
buf_vp->ion_handle = buf_vc->ion_handle;
buf_vp->paddr = buf_vc->paddr;
buf_vc->ion_handle = NULL;
@@ -197,6 +189,7 @@
struct vp_work_t *vp_work = container_of(work, struct vp_work_t, work);
struct vcap_dev *dev;
struct vp_action *vp_act;
+ struct timeval tv;
unsigned long flags = 0;
uint32_t irq;
int rc;
@@ -278,6 +271,11 @@
writel_iowmb(0x00000000 | top_field, VCAP_VP_CTRL);
writel_iowmb(0x00010000 | top_field, VCAP_VP_CTRL);
enable_irq(dev->vpirq->start);
+
+ do_gettimeofday(&tv);
+ dev->dbg_p.vp_timestamp = (uint32_t) (tv.tv_sec * VCAP_USEC +
+ tv.tv_usec);
+
writel_iowmb(irq, VCAP_VP_INT_CLEAR);
}
@@ -288,6 +286,8 @@
struct v4l2_event v4l2_evt;
uint32_t irq;
int rc;
+ struct timeval tv;
+ uint32_t new_ts;
irq = readl_relaxed(VCAP_VP_INT_STATUS);
if (dev->vp_dummy_event == true) {
@@ -318,7 +318,7 @@
v4l2_event_queue(dev->vfd, &v4l2_evt);
}
- dprintk(1, "%s: irq=0x%08x\n", __func__, irq);
+ pr_debug("%s: irq=0x%08x\n", __func__, irq);
if (!(irq & (VP_PIC_DONE | VP_MODE_CHANGE))) {
writel_relaxed(irq, VCAP_VP_INT_CLEAR);
pr_err("VP IRQ shows some error\n");
@@ -341,6 +341,17 @@
return -EAGAIN;
}
+ do_gettimeofday(&tv);
+ new_ts = (uint32_t) (tv.tv_sec * VCAP_USEC +
+ tv.tv_usec);
+ if (new_ts > dev->dbg_p.vp_timestamp) {
+ dev->dbg_p.vp_ewma = ((new_ts - dev->dbg_p.vp_timestamp) /
+ 10 + (dev->dbg_p.vp_ewma / 10 * 9));
+ }
+
+ dev->dbg_p.vp_timestamp = (uint32_t) (tv.tv_sec * VCAP_USEC +
+ tv.tv_usec);
+
INIT_WORK(&dev->vp_work.work, vp_wq_fnc);
dev->vp_work.cd = c_data;
rc = queue_work(dev->vcap_wq, &dev->vp_work.work);
@@ -663,7 +674,7 @@
uint32_t reg;
int rc = 0;
- dprintk(2, "%s: Start VP dummy event\n", __func__);
+ pr_debug("%s: Start VP dummy event\n", __func__);
handle = ion_alloc(dev->ion_client, 0x1200, SZ_4K,
ION_HEAP(ION_CP_MM_HEAP_ID), 0);
if (IS_ERR_OR_NULL(handle)) {
@@ -723,7 +734,7 @@
c_data->vp_out_fmt.height = height;
ion_free(dev->ion_client, handle);
- dprintk(2, "%s: Exit VP dummy event\n", __func__);
+ pr_debug("%s: Exit VP dummy event\n", __func__);
return rc;
}
@@ -731,6 +742,7 @@
{
struct vcap_dev *dev;
struct vp_action *vp_act;
+ struct timeval tv;
unsigned long flags = 0;
unsigned int chroma_fmt = 0;
int size;
@@ -740,7 +752,7 @@
return -ENOEXEC;
dev = c_data->dev;
- dprintk(2, "Start Kickoff\n");
+ pr_debug("Start VP Kickoff\n");
if (dev->vp_client == NULL) {
pr_err("No active vp client\n");
@@ -815,6 +827,11 @@
writel_iowmb(0x00010000 | top_field, VCAP_VP_CTRL);
atomic_set(&c_data->dev->vp_enabled, 1);
enable_irq(dev->vpirq->start);
+
+ do_gettimeofday(&tv);
+ dev->dbg_p.vp_timestamp = (uint32_t) (tv.tv_sec * VCAP_USEC +
+ tv.tv_usec);
+
return 0;
}
@@ -822,10 +839,11 @@
{
struct vcap_dev *dev;
struct vp_action *vp_act;
+ struct timeval tv;
int rc;
bool top_field = 0;
- dprintk(2, "Start Continue\n");
+ pr_debug("Start VP Continue\n");
dev = c_data->dev;
if (dev->vp_client == NULL) {
@@ -854,5 +872,10 @@
atomic_set(&c_data->dev->vp_enabled, 1);
enable_irq(dev->vpirq->start);
+
+ do_gettimeofday(&tv);
+ dev->dbg_p.vp_timestamp = (uint32_t) (tv.tv_sec * VCAP_USEC +
+ tv.tv_usec);
+
return 0;
}
diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c
index 0ea843c..e7e11d0 100644
--- a/drivers/mfd/wcd9xxx-core.c
+++ b/drivers/mfd/wcd9xxx-core.c
@@ -263,6 +263,7 @@
{{0x0, 0x0, 0x2, 0x1}, taiko_devs, ARRAY_SIZE(taiko_devs)},
{{0x0, 0x0, 0x0, 0x1}, sitar_devs, ARRAY_SIZE(sitar_devs)},
{{0x1, 0x0, 0x1, 0x1}, sitar_devs, ARRAY_SIZE(sitar_devs)},
+ {{0x2, 0x0, 0x1, 0x1}, sitar_devs, ARRAY_SIZE(sitar_devs)},
};
static void wcd9xxx_bring_up(struct wcd9xxx *wcd9xxx)
@@ -314,18 +315,17 @@
struct mfd_cell **wcd9xxx_dev,
int *wcd9xxx_dev_size)
{
- struct wcd9xx_codec_type *cdc = wcd9xxx_codecs;
- int index;
+ int i;
int ret;
- index = WCD9XXX_A_CHIP_ID_BYTE_0;
- while (index <= WCD9XXX_A_CHIP_ID_BYTE_3) {
- ret = wcd9xxx_reg_read(wcd9xxx, index);
+ i = WCD9XXX_A_CHIP_ID_BYTE_0;
+ while (i <= WCD9XXX_A_CHIP_ID_BYTE_3) {
+ ret = wcd9xxx_reg_read(wcd9xxx, i);
if (ret < 0)
goto exit;
- wcd9xxx->idbyte[index-WCD9XXX_A_CHIP_ID_BYTE_0] = (u8)ret;
+ wcd9xxx->idbyte[i-WCD9XXX_A_CHIP_ID_BYTE_0] = (u8)ret;
pr_debug("%s: wcd9xx read = %x, byte = %x\n", __func__, ret,
- index);
- index++;
+ i);
+ i++;
}
/* Read codec version */
@@ -333,18 +333,19 @@
if (ret < 0)
goto exit;
wcd9xxx->version = (u8)ret & 0x1F;
-
- while (cdc < (cdc + ARRAY_SIZE(wcd9xxx_codecs)) && cdc != NULL) {
- if ((cdc->byte[0] == wcd9xxx->idbyte[0]) &&
- (cdc->byte[1] == wcd9xxx->idbyte[1]) &&
- (cdc->byte[2] == wcd9xxx->idbyte[2]) &&
- (cdc->byte[3] == wcd9xxx->idbyte[3])) {
- pr_info("%s: codec is %s", __func__, cdc->dev->name);
- *wcd9xxx_dev = cdc->dev;
- *wcd9xxx_dev_size = cdc->size;
+ i = 0;
+ while (i < ARRAY_SIZE(wcd9xxx_codecs)) {
+ if ((wcd9xxx_codecs[i].byte[0] == wcd9xxx->idbyte[0]) &&
+ (wcd9xxx_codecs[i].byte[1] == wcd9xxx->idbyte[1]) &&
+ (wcd9xxx_codecs[i].byte[2] == wcd9xxx->idbyte[2]) &&
+ (wcd9xxx_codecs[i].byte[3] == wcd9xxx->idbyte[3])) {
+ pr_info("%s: codec is %s", __func__,
+ wcd9xxx_codecs[i].dev->name);
+ *wcd9xxx_dev = wcd9xxx_codecs[i].dev;
+ *wcd9xxx_dev_size = wcd9xxx_codecs[i].size;
break;
}
- cdc++;
+ i++;
}
if (*wcd9xxx_dev == NULL || *wcd9xxx_dev_size == 0)
ret = -ENODEV;
diff --git a/drivers/mfd/wcd9xxx-irq.c b/drivers/mfd/wcd9xxx-irq.c
index 68c4557..e9b2ef3 100644
--- a/drivers/mfd/wcd9xxx-irq.c
+++ b/drivers/mfd/wcd9xxx-irq.c
@@ -25,6 +25,8 @@
#define BYTE_BIT_MASK(nr) (1UL << ((nr) % BITS_PER_BYTE))
#define BIT_BYTE(nr) ((nr) / BITS_PER_BYTE)
+#define WCD9XXX_SYSTEM_RESUME_TIMEOUT_MS 100
+
struct wcd9xxx_irq {
bool level;
};
@@ -106,11 +108,17 @@
{
enum wcd9xxx_pm_state os;
- /* wcd9xxx_{lock/unlock}_sleep will be called by wcd9xxx_irq_thread
+ /*
+ * wcd9xxx_{lock/unlock}_sleep will be called by wcd9xxx_irq_thread
* and its subroutines only motly.
* but btn0_lpress_fn is not wcd9xxx_irq_thread's subroutine and
- * it can race with wcd9xxx_irq_thread.
- * so need to embrace wlock_holders with mutex.
+ * It can race with wcd9xxx_irq_thread.
+ * So need to embrace wlock_holders with mutex.
+ *
+ * If system didn't resume, we can simply return false so codec driver's
+ * IRQ handler can return without handling IRQ.
+ * As interrupt line is still active, codec will have another IRQ to
+ * retry shortly.
*/
mutex_lock(&wcd9xxx->pm_lock);
if (wcd9xxx->wlock_holders++ == 0) {
@@ -124,11 +132,11 @@
WCD9XXX_PM_AWAKE)) ==
WCD9XXX_PM_SLEEPABLE ||
(os == WCD9XXX_PM_AWAKE)),
- 5 * HZ)) {
- pr_err("%s: system didn't resume within 5000ms, state %d, "
- "wlock %d\n", __func__, wcd9xxx->pm_state,
- wcd9xxx->wlock_holders);
- WARN_ON(1);
+ msecs_to_jiffies(WCD9XXX_SYSTEM_RESUME_TIMEOUT_MS))) {
+ pr_warn("%s: system didn't resume within %dms, s %d, w %d\n",
+ __func__,
+ WCD9XXX_SYSTEM_RESUME_TIMEOUT_MS, wcd9xxx->pm_state,
+ wcd9xxx->wlock_holders);
wcd9xxx_unlock_sleep(wcd9xxx);
return false;
}
@@ -141,8 +149,14 @@
{
mutex_lock(&wcd9xxx->pm_lock);
if (--wcd9xxx->wlock_holders == 0) {
- wcd9xxx->pm_state = WCD9XXX_PM_SLEEPABLE;
- pr_debug("%s: releasing wake lock\n", __func__);
+ pr_debug("%s: releasing wake lock pm_state %d -> %d\n",
+ __func__, wcd9xxx->pm_state, WCD9XXX_PM_SLEEPABLE);
+ /*
+ * if wcd9xxx_lock_sleep failed, pm_state would be still
+ * WCD9XXX_PM_ASLEEP, don't overwrite
+ */
+ if (likely(wcd9xxx->pm_state == WCD9XXX_PM_AWAKE))
+ wcd9xxx->pm_state = WCD9XXX_PM_SLEEPABLE;
pm_qos_update_request(&wcd9xxx->pm_qos_req,
PM_QOS_DEFAULT_VALUE);
}
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index a9f1b53..89e7af0 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -65,6 +65,11 @@
(rq_data_dir(req) == WRITE))
#define PACKED_CMD_VER 0x01
#define PACKED_CMD_WR 0x02
+#define MMC_BLK_UPDATE_STOP_REASON(stats, reason) \
+ do { \
+ if (stats->enabled) \
+ stats->pack_stop_reason[reason]++; \
+ } while (0)
static DEFINE_MUTEX(block_mutex);
@@ -115,6 +120,7 @@
unsigned int part_curr;
struct device_attribute force_ro;
struct device_attribute power_ro_lock;
+ struct device_attribute num_wr_reqs_to_start_packing;
int area_type;
};
@@ -279,6 +285,38 @@
return ret;
}
+static ssize_t
+num_wr_reqs_to_start_packing_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
+ int num_wr_reqs_to_start_packing;
+ int ret;
+
+ num_wr_reqs_to_start_packing = md->queue.num_wr_reqs_to_start_packing;
+
+ ret = snprintf(buf, PAGE_SIZE, "%d\n", num_wr_reqs_to_start_packing);
+
+ mmc_blk_put(md);
+ return ret;
+}
+
+static ssize_t
+num_wr_reqs_to_start_packing_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int value;
+ struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
+
+ sscanf(buf, "%d", &value);
+ if (value >= 0)
+ md->queue.num_wr_reqs_to_start_packing = value;
+
+ mmc_blk_put(md);
+ return count;
+}
+
static int mmc_blk_open(struct block_device *bdev, fmode_t mode)
{
struct mmc_blk_data *md = mmc_blk_get(bdev->bd_disk);
@@ -846,6 +884,9 @@
from = blk_rq_pos(req);
nr = blk_rq_sectors(req);
+ if (card->ext_csd.bkops_en)
+ card->bkops_info.sectors_changed += blk_rq_sectors(req);
+
if (mmc_can_discard(card))
arg = MMC_DISCARD_ARG;
else if (mmc_can_trim(card))
@@ -1324,6 +1365,78 @@
mmc_queue_bounce_pre(mqrq);
}
+static void mmc_blk_write_packing_control(struct mmc_queue *mq,
+ struct request *req)
+{
+ struct mmc_host *host = mq->card->host;
+ int data_dir;
+
+ if (!(host->caps2 & MMC_CAP2_PACKED_WR))
+ return;
+
+ /*
+ * In case the packing control is not supported by the host, it should
+ * not have an effect on the write packing. Therefore we have to enable
+ * the write packing
+ */
+ if (!(host->caps2 & MMC_CAP2_PACKED_WR_CONTROL)) {
+ mq->wr_packing_enabled = true;
+ return;
+ }
+
+ if (!req || (req && (req->cmd_flags & REQ_FLUSH))) {
+ if (mq->num_of_potential_packed_wr_reqs >
+ mq->num_wr_reqs_to_start_packing)
+ mq->wr_packing_enabled = true;
+ mq->num_of_potential_packed_wr_reqs = 0;
+ return;
+ }
+
+ data_dir = rq_data_dir(req);
+
+ if (data_dir == READ) {
+ mq->num_of_potential_packed_wr_reqs = 0;
+ mq->wr_packing_enabled = false;
+ return;
+ } else if (data_dir == WRITE) {
+ mq->num_of_potential_packed_wr_reqs++;
+ }
+
+ if (mq->num_of_potential_packed_wr_reqs >
+ mq->num_wr_reqs_to_start_packing)
+ mq->wr_packing_enabled = true;
+
+}
+
+struct mmc_wr_pack_stats *mmc_blk_get_packed_statistics(struct mmc_card *card)
+{
+ if (!card)
+ return NULL;
+
+ return &card->wr_pack_stats;
+}
+EXPORT_SYMBOL(mmc_blk_get_packed_statistics);
+
+void mmc_blk_init_packed_statistics(struct mmc_card *card)
+{
+ int max_num_of_packed_reqs = 0;
+
+ if (!card || !card->wr_pack_stats.packing_events)
+ return;
+
+ max_num_of_packed_reqs = card->ext_csd.max_packed_writes;
+
+ spin_lock(&card->wr_pack_stats.lock);
+ memset(card->wr_pack_stats.packing_events, 0,
+ (max_num_of_packed_reqs + 1) *
+ sizeof(*card->wr_pack_stats.packing_events));
+ memset(&card->wr_pack_stats.pack_stop_reason, 0,
+ sizeof(card->wr_pack_stats.pack_stop_reason));
+ card->wr_pack_stats.enabled = true;
+ spin_unlock(&card->wr_pack_stats.lock);
+}
+EXPORT_SYMBOL(mmc_blk_init_packed_statistics);
+
static u8 mmc_blk_prep_packed_list(struct mmc_queue *mq, struct request *req)
{
struct request_queue *q = mq->queue;
@@ -1336,6 +1449,7 @@
u8 put_back = 0;
u8 max_packed_rw = 0;
u8 reqs = 0;
+ struct mmc_wr_pack_stats *stats = &card->wr_pack_stats;
mmc_blk_clear_packed(mq->mqrq_cur);
@@ -1343,6 +1457,9 @@
!card->ext_csd.packed_event_en)
goto no_packed;
+ if (!mq->wr_packing_enabled)
+ goto no_packed;
+
if ((rq_data_dir(cur) == WRITE) &&
(card->host->caps2 & MMC_CAP2_PACKED_WR))
max_packed_rw = card->ext_csd.max_packed_writes;
@@ -1373,26 +1490,33 @@
phys_segments++;
}
+ spin_lock(&stats->lock);
+
while (reqs < max_packed_rw - 1) {
spin_lock_irq(q->queue_lock);
next = blk_fetch_request(q);
spin_unlock_irq(q->queue_lock);
- if (!next)
+ if (!next) {
+ MMC_BLK_UPDATE_STOP_REASON(stats, EMPTY_QUEUE);
break;
+ }
if (mmc_large_sec(card) &&
!IS_ALIGNED(blk_rq_sectors(next), 8)) {
+ MMC_BLK_UPDATE_STOP_REASON(stats, LARGE_SEC_ALIGN);
put_back = 1;
break;
}
if (next->cmd_flags & REQ_DISCARD ||
next->cmd_flags & REQ_FLUSH) {
+ MMC_BLK_UPDATE_STOP_REASON(stats, FLUSH_OR_DISCARD);
put_back = 1;
break;
}
if (rq_data_dir(cur) != rq_data_dir(next)) {
+ MMC_BLK_UPDATE_STOP_REASON(stats, WRONG_DATA_DIR);
put_back = 1;
break;
}
@@ -1400,22 +1524,32 @@
if (mmc_req_rel_wr(next) &&
(md->flags & MMC_BLK_REL_WR) &&
!en_rel_wr) {
+ MMC_BLK_UPDATE_STOP_REASON(stats, REL_WRITE);
put_back = 1;
break;
}
req_sectors += blk_rq_sectors(next);
if (req_sectors > max_blk_count) {
+ if (stats->enabled)
+ stats->pack_stop_reason[EXCEEDS_SECTORS]++;
put_back = 1;
break;
}
phys_segments += next->nr_phys_segments;
if (phys_segments > max_phys_segs) {
+ MMC_BLK_UPDATE_STOP_REASON(stats, EXCEEDS_SEGMENTS);
put_back = 1;
break;
}
+ if (rq_data_dir(next) == WRITE) {
+ mq->num_of_potential_packed_wr_reqs++;
+ if (card->ext_csd.bkops_en)
+ card->bkops_info.sectors_changed +=
+ blk_rq_sectors(next);
+ }
list_add_tail(&next->queuelist, &mq->mqrq_cur->packed_list);
cur = next;
reqs++;
@@ -1427,6 +1561,15 @@
spin_unlock_irq(q->queue_lock);
}
+ if (stats->enabled) {
+ if (reqs + 1 <= card->ext_csd.max_packed_writes)
+ stats->packing_events[reqs + 1]++;
+ if (reqs + 1 == max_packed_rw)
+ MMC_BLK_UPDATE_STOP_REASON(stats, THRESHOLD);
+ }
+
+ spin_unlock(&stats->lock);
+
if (reqs > 0) {
list_add(&req->queuelist, &mq->mqrq_cur->packed_list);
mq->mqrq_cur->packed_num = ++reqs;
@@ -1625,8 +1768,11 @@
if (!rqc && !mq->mqrq_prev->req)
return 0;
- if (rqc)
+ if (rqc) {
+ if ((card->ext_csd.bkops_en) && (rq_data_dir(rqc) == WRITE))
+ card->bkops_info.sectors_changed += blk_rq_sectors(rqc);
reqs = mmc_blk_prep_packed_list(mq, rqc);
+ }
do {
if (rqc) {
@@ -1797,6 +1943,8 @@
goto out;
}
+ mmc_blk_write_packing_control(mq, req);
+
if (req && req->cmd_flags & REQ_SANITIZE) {
/* complete ongoing async transfer before issuing sanitize */
if (card->host && card->host->areq)
@@ -2028,6 +2176,8 @@
if (md) {
card = md->queue.card;
+ device_remove_file(disk_to_dev(md->disk),
+ &md->num_wr_reqs_to_start_packing);
if (md->disk->flags & GENHD_FL_UP) {
device_remove_file(disk_to_dev(md->disk), &md->force_ro);
if ((md->area_type & MMC_BLK_DATA_AREA_BOOT) &&
@@ -2095,6 +2245,16 @@
goto power_ro_lock_fail;
}
+ md->num_wr_reqs_to_start_packing.show =
+ num_wr_reqs_to_start_packing_show;
+ md->num_wr_reqs_to_start_packing.store =
+ num_wr_reqs_to_start_packing_store;
+ sysfs_attr_init(&md->num_wr_reqs_to_start_packing.attr);
+ md->num_wr_reqs_to_start_packing.attr.name =
+ "num_wr_reqs_to_start_packing";
+ md->num_wr_reqs_to_start_packing.attr.mode = S_IRUGO | S_IWUSR;
+ ret = device_create_file(disk_to_dev(md->disk),
+ &md->num_wr_reqs_to_start_packing);
if (ret)
goto power_ro_lock_fail;
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index d818fc4..cc91646 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -25,6 +25,13 @@
#define MMC_QUEUE_SUSPENDED (1 << 0)
/*
+ * Based on benchmark tests the default num of requests to trigger the write
+ * packing was determined, to keep the read latency as low as possible and
+ * manage to keep the high write throughput.
+ */
+#define DEFAULT_NUM_REQS_TO_START_PACK 17
+
+/*
* Prepare a MMC request. This just filters out odd stuff.
*/
static int mmc_prep_request(struct request_queue *q, struct request *req)
@@ -52,6 +59,7 @@
struct mmc_queue *mq = d;
struct request_queue *q = mq->queue;
struct request *req;
+ struct mmc_card *card = mq->card;
current->flags |= PF_MEMALLOC;
@@ -67,6 +75,17 @@
spin_unlock_irq(q->queue_lock);
if (req || mq->mqrq_prev->req) {
+ /*
+ * If this is the first request, BKOPs might be in
+ * progress and needs to be stopped before issuing the
+ * request
+ */
+ if (card->ext_csd.bkops_en &&
+ card->bkops_info.started_delayed_bkops) {
+ card->bkops_info.started_delayed_bkops = false;
+ mmc_stop_bkops(card);
+ }
+
set_current_state(TASK_RUNNING);
mq->issue_fn(mq, req);
} else {
@@ -74,6 +93,7 @@
set_current_state(TASK_RUNNING);
break;
}
+ mmc_start_delayed_bkops(card);
up(&mq->thread_sem);
schedule();
down(&mq->thread_sem);
@@ -189,6 +209,7 @@
mq->mqrq_cur = mqrq_cur;
mq->mqrq_prev = mqrq_prev;
mq->queue->queuedata = mq;
+ mq->num_wr_reqs_to_start_packing = DEFAULT_NUM_REQS_TO_START_PACK;
blk_queue_prep_rq(mq->queue, mmc_prep_request);
queue_flag_set_unlocked(QUEUE_FLAG_NONROT, mq->queue);
diff --git a/drivers/mmc/card/queue.h b/drivers/mmc/card/queue.h
index 5e04938..93e4b59 100644
--- a/drivers/mmc/card/queue.h
+++ b/drivers/mmc/card/queue.h
@@ -45,6 +45,9 @@
struct mmc_queue_req mqrq[2];
struct mmc_queue_req *mqrq_cur;
struct mmc_queue_req *mqrq_prev;
+ bool wr_packing_enabled;
+ int num_of_potential_packed_wr_reqs;
+ int num_wr_reqs_to_start_packing;
};
extern int mmc_init_queue(struct mmc_queue *, struct mmc_card *, spinlock_t *,
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index 33f7d29..0592f9d 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -254,6 +254,8 @@
card->dev.release = mmc_release_card;
card->dev.type = type;
+ spin_lock_init(&card->wr_pack_stats.lock);
+
return card;
}
@@ -356,6 +358,8 @@
device_del(&card->dev);
}
+ kfree(card->wr_pack_stats.packing_events);
+
put_device(&card->dev);
}
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 9b316bb..9b9e8cc 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -280,9 +280,42 @@
}
/**
+ * mmc_start_delayed_bkops() - Start a delayed work to check for
+ * the need of non urgent BKOPS
+ *
+ * @card: MMC card to start BKOPS on
+ */
+void mmc_start_delayed_bkops(struct mmc_card *card)
+{
+ if (!card || !card->ext_csd.bkops_en || mmc_card_doing_bkops(card))
+ return;
+
+ if (card->bkops_info.sectors_changed <
+ BKOPS_MIN_SECTORS_TO_QUEUE_DELAYED_WORK)
+ return;
+
+ pr_debug("%s: %s: queueing delayed_bkops_work\n",
+ mmc_hostname(card->host), __func__);
+
+ card->bkops_info.sectors_changed = 0;
+
+ /*
+ * cancel_delayed_bkops_work will prevent a race condition between
+ * fetching a request by the mmcqd and the delayed work, in case
+ * it was removed from the queue work but not started yet
+ */
+ card->bkops_info.cancel_delayed_work = false;
+ card->bkops_info.started_delayed_bkops = true;
+ queue_delayed_work(system_nrt_wq, &card->bkops_info.dw,
+ msecs_to_jiffies(
+ card->bkops_info.delay_ms));
+}
+EXPORT_SYMBOL(mmc_start_delayed_bkops);
+
+/**
* mmc_start_bkops - start BKOPS for supported cards
* @card: MMC card to start BKOPS
- * @form_exception: A flag to indicate if this function was
+ * @from_exception: A flag to indicate if this function was
* called due to an exception raised by the card
*
* Start background operations whenever requested.
@@ -296,25 +329,47 @@
bool use_busy_signal;
BUG_ON(!card);
-
- if (!card->ext_csd.bkops_en || mmc_card_doing_bkops(card))
+ if (!card->ext_csd.bkops_en)
return;
+ mmc_claim_host(card->host);
+
+ if ((card->bkops_info.cancel_delayed_work) && !from_exception) {
+ pr_debug("%s: %s: cancel_delayed_work was set, exit\n",
+ mmc_hostname(card->host), __func__);
+ card->bkops_info.cancel_delayed_work = false;
+ goto out;
+ }
+
+ if (mmc_card_doing_bkops(card)) {
+ pr_debug("%s: %s: already doing bkops, exit\n",
+ mmc_hostname(card->host), __func__);
+ goto out;
+ }
+
err = mmc_read_bkops_status(card);
if (err) {
pr_err("%s: Failed to read bkops status: %d\n",
mmc_hostname(card->host), err);
- return;
+ goto out;
}
if (!card->ext_csd.raw_bkops_status)
- return;
+ goto out;
+ pr_info("%s: %s: card->ext_csd.raw_bkops_status = 0x%x\n",
+ mmc_hostname(card->host), __func__,
+ card->ext_csd.raw_bkops_status);
+
+ /*
+ * If the function was called due to exception but there is no need
+ * for urgent BKOPS, BKOPs will be performed by the delayed BKOPs
+ * work, before going to suspend
+ */
if (card->ext_csd.raw_bkops_status < EXT_CSD_BKOPS_LEVEL_2 &&
from_exception)
- return;
+ goto out;
- mmc_claim_host(card->host);
if (card->ext_csd.raw_bkops_status >= EXT_CSD_BKOPS_LEVEL_2) {
timeout = MMC_BKOPS_MAX_TIMEOUT;
use_busy_signal = true;
@@ -336,13 +391,108 @@
* bkops executed synchronously, otherwise
* the operation is in progress
*/
- if (!use_busy_signal)
+ if (!use_busy_signal) {
mmc_card_set_doing_bkops(card);
+ pr_debug("%s: %s: starting the polling thread\n",
+ mmc_hostname(card->host), __func__);
+ queue_work(system_nrt_wq,
+ &card->bkops_info.poll_for_completion);
+ }
+
out:
mmc_release_host(card->host);
}
EXPORT_SYMBOL(mmc_start_bkops);
+/**
+ * mmc_bkops_completion_polling() - Poll on the card status to
+ * wait for the non-blocking BKOPS completion
+ * @work: The completion polling work
+ *
+ * The on-going reading of the card status will prevent the card
+ * from getting into suspend while it is in the middle of
+ * performing BKOPS.
+ * Since the non blocking BKOPS can be interrupted by a fetched
+ * request we also check IF mmc_card_doing_bkops in each
+ * iteration.
+ */
+void mmc_bkops_completion_polling(struct work_struct *work)
+{
+ struct mmc_card *card = container_of(work, struct mmc_card,
+ bkops_info.poll_for_completion);
+ unsigned long timeout_jiffies = jiffies +
+ msecs_to_jiffies(BKOPS_COMPLETION_POLLING_TIMEOUT_MS);
+ u32 status;
+ int err;
+
+ /*
+ * Wait for the BKOPs to complete. Keep reading the status to prevent
+ * the host from getting into suspend
+ */
+ do {
+ mmc_claim_host(card->host);
+
+ if (!mmc_card_doing_bkops(card))
+ goto out;
+
+ err = mmc_send_status(card, &status);
+ if (err) {
+ pr_err("%s: error %d requesting status\n",
+ mmc_hostname(card->host), err);
+ goto out;
+ }
+
+ /*
+ * Some cards mishandle the status bits, so make sure to check
+ * both the busy indication and the card state.
+ */
+ if ((status & R1_READY_FOR_DATA) &&
+ (R1_CURRENT_STATE(status) != R1_STATE_PRG)) {
+ pr_debug("%s: %s: completed BKOPs, exit polling\n",
+ mmc_hostname(card->host), __func__);
+ mmc_card_clr_doing_bkops(card);
+ card->bkops_info.started_delayed_bkops = false;
+ goto out;
+ }
+
+ mmc_release_host(card->host);
+
+ /*
+ * Sleep before checking the card status again to allow the
+ * card to complete the BKOPs operation
+ */
+ msleep(BKOPS_COMPLETION_POLLING_INTERVAL_MS);
+ } while (time_before(jiffies, timeout_jiffies));
+
+ pr_err("%s: %s: exit polling due to timeout\n",
+ mmc_hostname(card->host), __func__);
+
+ return;
+out:
+ mmc_release_host(card->host);
+}
+
+/**
+ * mmc_start_idle_time_bkops() - check if a non urgent BKOPS is
+ * needed
+ * @work: The idle time BKOPS work
+ */
+void mmc_start_idle_time_bkops(struct work_struct *work)
+{
+ struct mmc_card *card = container_of(work, struct mmc_card,
+ bkops_info.dw.work);
+
+ /*
+ * Prevent a race condition between mmc_stop_bkops and the delayed
+ * BKOPS work in case the delayed work is executed on another CPU
+ */
+ if (card->bkops_info.cancel_delayed_work)
+ return;
+
+ mmc_start_bkops(card, false);
+}
+EXPORT_SYMBOL(mmc_start_idle_time_bkops);
+
static void mmc_wait_done(struct mmc_request *mrq)
{
complete(&mrq->completion);
@@ -599,6 +749,19 @@
int err = 0;
BUG_ON(!card);
+
+ mmc_claim_host(card->host);
+
+ /*
+ * Notify the delayed work to be cancelled, in case it was already
+ * removed from the queue, but was not started yet
+ */
+ card->bkops_info.cancel_delayed_work = true;
+ if (delayed_work_pending(&card->bkops_info.dw))
+ cancel_delayed_work_sync(&card->bkops_info.dw);
+ if (!mmc_card_doing_bkops(card))
+ goto out;
+
err = mmc_interrupt_hpi(card);
/*
@@ -610,6 +773,8 @@
err = 0;
}
+out:
+ mmc_release_host(card->host);
return err;
}
EXPORT_SYMBOL(mmc_stop_bkops);
@@ -2615,15 +2780,13 @@
switch (mode) {
case PM_HIBERNATION_PREPARE:
case PM_SUSPEND_PREPARE:
- if (host->card && mmc_card_mmc(host->card) &&
- mmc_card_doing_bkops(host->card)) {
+ if (host->card && mmc_card_mmc(host->card)) {
err = mmc_stop_bkops(host->card);
if (err) {
pr_err("%s: didn't stop bkops\n",
mmc_hostname(host));
return err;
}
- mmc_card_clr_doing_bkops(host->card);
}
spin_lock_irqsave(&host->lock, flags);
diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
index 9ab5b17..4022ccc 100644
--- a/drivers/mmc/core/debugfs.c
+++ b/drivers/mmc/core/debugfs.c
@@ -318,6 +318,172 @@
.llseek = default_llseek,
};
+static int mmc_wr_pack_stats_open(struct inode *inode, struct file *filp)
+{
+ struct mmc_card *card = inode->i_private;
+
+ filp->private_data = card;
+ card->wr_pack_stats.print_in_read = 1;
+ return 0;
+}
+
+#define TEMP_BUF_SIZE 256
+static ssize_t mmc_wr_pack_stats_read(struct file *filp, char __user *ubuf,
+ size_t cnt, loff_t *ppos)
+{
+ struct mmc_card *card = filp->private_data;
+ struct mmc_wr_pack_stats *pack_stats;
+ int i;
+ int max_num_of_packed_reqs = 0;
+ char *temp_buf;
+
+ if (!card)
+ return cnt;
+
+ if (!card->wr_pack_stats.print_in_read)
+ return 0;
+
+ if (!card->wr_pack_stats.enabled) {
+ pr_info("%s: write packing statistics are disabled\n",
+ mmc_hostname(card->host));
+ goto exit;
+ }
+
+ pack_stats = &card->wr_pack_stats;
+
+ if (!pack_stats->packing_events) {
+ pr_info("%s: NULL packing_events\n", mmc_hostname(card->host));
+ goto exit;
+ }
+
+ max_num_of_packed_reqs = card->ext_csd.max_packed_writes;
+
+ temp_buf = kmalloc(TEMP_BUF_SIZE, GFP_KERNEL);
+ if (!temp_buf)
+ goto exit;
+
+ spin_lock(&pack_stats->lock);
+
+ snprintf(temp_buf, TEMP_BUF_SIZE, "%s: write packing statistics:\n",
+ mmc_hostname(card->host));
+ strlcat(ubuf, temp_buf, cnt);
+
+ for (i = 1 ; i <= max_num_of_packed_reqs ; ++i) {
+ if (pack_stats->packing_events[i]) {
+ snprintf(temp_buf, TEMP_BUF_SIZE,
+ "%s: Packed %d reqs - %d times\n",
+ mmc_hostname(card->host), i,
+ pack_stats->packing_events[i]);
+ strlcat(ubuf, temp_buf, cnt);
+ }
+ }
+
+ snprintf(temp_buf, TEMP_BUF_SIZE,
+ "%s: stopped packing due to the following reasons:\n",
+ mmc_hostname(card->host));
+ strlcat(ubuf, temp_buf, cnt);
+
+ if (pack_stats->pack_stop_reason[EXCEEDS_SEGMENTS]) {
+ snprintf(temp_buf, TEMP_BUF_SIZE,
+ "%s: %d times: exceed max num of segments\n",
+ mmc_hostname(card->host),
+ pack_stats->pack_stop_reason[EXCEEDS_SEGMENTS]);
+ strlcat(ubuf, temp_buf, cnt);
+ }
+ if (pack_stats->pack_stop_reason[EXCEEDS_SECTORS]) {
+ snprintf(temp_buf, TEMP_BUF_SIZE,
+ "%s: %d times: exceed max num of sectors\n",
+ mmc_hostname(card->host),
+ pack_stats->pack_stop_reason[EXCEEDS_SECTORS]);
+ strlcat(ubuf, temp_buf, cnt);
+ }
+ if (pack_stats->pack_stop_reason[WRONG_DATA_DIR]) {
+ snprintf(temp_buf, TEMP_BUF_SIZE,
+ "%s: %d times: wrong data direction\n",
+ mmc_hostname(card->host),
+ pack_stats->pack_stop_reason[WRONG_DATA_DIR]);
+ strlcat(ubuf, temp_buf, cnt);
+ }
+ if (pack_stats->pack_stop_reason[FLUSH_OR_DISCARD]) {
+ snprintf(temp_buf, TEMP_BUF_SIZE,
+ "%s: %d times: flush or discard\n",
+ mmc_hostname(card->host),
+ pack_stats->pack_stop_reason[FLUSH_OR_DISCARD]);
+ strlcat(ubuf, temp_buf, cnt);
+ }
+ if (pack_stats->pack_stop_reason[EMPTY_QUEUE]) {
+ snprintf(temp_buf, TEMP_BUF_SIZE,
+ "%s: %d times: empty queue\n",
+ mmc_hostname(card->host),
+ pack_stats->pack_stop_reason[EMPTY_QUEUE]);
+ strlcat(ubuf, temp_buf, cnt);
+ }
+ if (pack_stats->pack_stop_reason[REL_WRITE]) {
+ snprintf(temp_buf, TEMP_BUF_SIZE,
+ "%s: %d times: rel write\n",
+ mmc_hostname(card->host),
+ pack_stats->pack_stop_reason[REL_WRITE]);
+ strlcat(ubuf, temp_buf, cnt);
+ }
+ if (pack_stats->pack_stop_reason[THRESHOLD]) {
+ snprintf(temp_buf, TEMP_BUF_SIZE,
+ "%s: %d times: Threshold\n",
+ mmc_hostname(card->host),
+ pack_stats->pack_stop_reason[THRESHOLD]);
+ strlcat(ubuf, temp_buf, cnt);
+ }
+
+ if (pack_stats->pack_stop_reason[LARGE_SEC_ALIGN]) {
+ snprintf(temp_buf, TEMP_BUF_SIZE,
+ "%s: %d times: Large sector alignment\n",
+ mmc_hostname(card->host),
+ pack_stats->pack_stop_reason[LARGE_SEC_ALIGN]);
+ strlcat(ubuf, temp_buf, cnt);
+ }
+
+ spin_unlock(&pack_stats->lock);
+
+ kfree(temp_buf);
+
+ pr_info("%s", ubuf);
+
+exit:
+ if (card->wr_pack_stats.print_in_read == 1) {
+ card->wr_pack_stats.print_in_read = 0;
+ return strnlen(ubuf, cnt);
+ }
+
+ return 0;
+}
+
+static ssize_t mmc_wr_pack_stats_write(struct file *filp,
+ const char __user *ubuf, size_t cnt,
+ loff_t *ppos)
+{
+ struct mmc_card *card = filp->private_data;
+ int value;
+
+ if (!card)
+ return cnt;
+
+ sscanf(ubuf, "%d", &value);
+ if (value) {
+ mmc_blk_init_packed_statistics(card);
+ } else {
+ spin_lock(&card->wr_pack_stats.lock);
+ card->wr_pack_stats.enabled = false;
+ spin_unlock(&card->wr_pack_stats.lock);
+ }
+
+ return cnt;
+}
+
+static const struct file_operations mmc_dbg_wr_pack_stats_fops = {
+ .open = mmc_wr_pack_stats_open,
+ .read = mmc_wr_pack_stats_read,
+ .write = mmc_wr_pack_stats_write,
+};
+
void mmc_add_card_debugfs(struct mmc_card *card)
{
struct mmc_host *host = card->host;
@@ -350,6 +516,12 @@
&mmc_dbg_ext_csd_fops))
goto err;
+ if (mmc_card_mmc(card) && (card->ext_csd.rev >= 6) &&
+ (card->host->caps2 & MMC_CAP2_PACKED_WR))
+ if (!debugfs_create_file("wr_pack_stats", S_IRUSR, root, card,
+ &mmc_dbg_wr_pack_stats_fops))
+ goto err;
+
return;
err:
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index e2172c5..457db7f 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1297,6 +1297,46 @@
} else {
card->ext_csd.packed_event_en = 1;
}
+
+ }
+
+ if (!oldcard) {
+ if ((host->caps2 & MMC_CAP2_PACKED_CMD) &&
+ (card->ext_csd.max_packed_writes > 0)) {
+ /*
+ * We would like to keep the statistics in an index
+ * that equals the num of packed requests
+ * (1 to max_packed_writes)
+ */
+ card->wr_pack_stats.packing_events = kzalloc(
+ (card->ext_csd.max_packed_writes + 1) *
+ sizeof(*card->wr_pack_stats.packing_events),
+ GFP_KERNEL);
+ if (!card->wr_pack_stats.packing_events)
+ goto free_card;
+ }
+
+ if (card->ext_csd.bkops_en) {
+ INIT_DELAYED_WORK(&card->bkops_info.dw,
+ mmc_start_idle_time_bkops);
+ INIT_WORK(&card->bkops_info.poll_for_completion,
+ mmc_bkops_completion_polling);
+
+ /*
+ * Calculate the time to start the BKOPs checking.
+ * The idle time of the host controller should be taken
+ * into account in order to prevent a race condition
+ * before starting BKOPs and going into suspend.
+ * If the host controller didn't set its idle time,
+ * a default value is used.
+ */
+ card->bkops_info.delay_ms = MMC_IDLE_BKOPS_TIME_MS;
+ if (card->bkops_info.host_suspend_tout_ms)
+ card->bkops_info.delay_ms = min(
+ card->bkops_info.delay_ms,
+ card->bkops_info.host_suspend_tout_ms/2);
+
+ }
}
if (!oldcard)
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index 357d290..4e92dd7 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -4145,25 +4145,35 @@
.hw_reset = msmsdcc_hw_reset,
};
+static void msmsdcc_enable_status_gpio(struct msmsdcc_host *host)
+{
+ unsigned int gpio_no = host->plat->status_gpio;
+ int status;
+
+ if (!gpio_is_valid(gpio_no))
+ return;
+
+ status = gpio_request(gpio_no, "SD_HW_Detect");
+ if (status)
+ pr_err("%s: %s: gpio_request(%d) failed\n",
+ mmc_hostname(host->mmc), __func__, gpio_no);
+}
+
+static void msmsdcc_disable_status_gpio(struct msmsdcc_host *host)
+{
+ if (gpio_is_valid(host->plat->status_gpio))
+ gpio_free(host->plat->status_gpio);
+}
+
static unsigned int
msmsdcc_slot_status(struct msmsdcc_host *host)
{
int status;
- unsigned int gpio_no = host->plat->status_gpio;
- status = gpio_request(gpio_no, "SD_HW_Detect");
- if (status) {
- pr_err("%s: %s: Failed to request GPIO %d\n",
- mmc_hostname(host->mmc), __func__, gpio_no);
- } else {
- status = gpio_direction_input(gpio_no);
- if (!status) {
- status = gpio_get_value_cansleep(gpio_no);
- if (host->plat->is_status_gpio_active_low)
- status = !status;
- }
- gpio_free(gpio_no);
- }
+ status = gpio_get_value_cansleep(host->plat->status_gpio);
+ if (host->plat->is_status_gpio_active_low)
+ status = !status;
+
return status;
}
@@ -5825,6 +5835,7 @@
MMC_CAP_SET_XPC_180);
mmc->caps2 |= MMC_CAP2_PACKED_WR;
+ mmc->caps2 |= MMC_CAP2_PACKED_WR_CONTROL;
mmc->caps2 |= (MMC_CAP2_BOOTPART_NOACC | MMC_CAP2_DETECT_ON_ERR);
mmc->caps2 |= MMC_CAP2_SANITIZE;
mmc->caps2 |= MMC_CAP2_CACHE_CTRL;
@@ -5911,11 +5922,12 @@
plat->wpswitch_gpio = -ENOENT;
if (plat->status || gpio_is_valid(plat->status_gpio)) {
- if (plat->status)
+ if (plat->status) {
host->oldstat = plat->status(mmc_dev(host->mmc));
- else
+ } else {
+ msmsdcc_enable_status_gpio(host);
host->oldstat = msmsdcc_slot_status(host);
-
+ }
host->eject = !host->oldstat;
}
@@ -6098,6 +6110,7 @@
if (plat->status_irq)
free_irq(plat->status_irq, host);
+ msmsdcc_disable_status_gpio(host);
sdiowakeup_irq_free:
wake_lock_destroy(&host->sdio_suspend_wlock);
if (plat->sdiowakeup_irq)
@@ -6194,6 +6207,7 @@
if (plat->status_irq)
free_irq(plat->status_irq, host);
+ msmsdcc_disable_status_gpio(host);
wake_lock_destroy(&host->sdio_suspend_wlock);
if (plat->sdiowakeup_irq) {
@@ -6522,8 +6536,10 @@
rc = 0;
goto out;
}
- if (host->plat->status_irq)
+ if (host->plat->status_irq) {
disable_irq(host->plat->status_irq);
+ msmsdcc_disable_status_gpio(host);
+ }
if (!pm_runtime_suspended(dev))
rc = msmsdcc_runtime_suspend(dev);
@@ -6579,6 +6595,7 @@
host->pending_resume = true;
if (host->plat->status_irq) {
+ msmsdcc_enable_status_gpio(host);
msmsdcc_check_status((unsigned long)host);
enable_irq(host->plat->status_irq);
}
diff --git a/drivers/platform/msm/qpnp-power-on.c b/drivers/platform/msm/qpnp-power-on.c
index 33b12ae..76a758b 100644
--- a/drivers/platform/msm/qpnp-power-on.c
+++ b/drivers/platform/msm/qpnp-power-on.c
@@ -39,8 +39,10 @@
#define QPNP_PON_RESIN_PULL_UP BIT(0)
#define QPNP_PON_KPDPWR_PULL_UP BIT(1)
+#define QPNP_PON_CBLPWR_PULL_UP BIT(2)
#define QPNP_PON_S2_CNTL_EN BIT(7)
#define QPNP_PON_S2_RESET_ENABLE BIT(7)
+#define QPNP_PON_DELAY_BIT_SHIFT 6
#define QPNP_PON_S1_TIMER_MASK (0xF)
#define QPNP_PON_S2_TIMER_MASK (0x7)
@@ -49,6 +51,7 @@
#define QPNP_PON_DBC_DELAY_MASK (0x7)
#define QPNP_PON_KPDPWR_N_SET BIT(0)
#define QPNP_PON_RESIN_N_SET BIT(1)
+#define QPNP_PON_CBLPWR_N_SET BIT(2)
#define QPNP_PON_RESIN_BARK_N_SET BIT(4)
#define QPNP_PON_RESET_EN BIT(7)
@@ -66,6 +69,7 @@
enum pon_type {
PON_KPDPWR,
PON_RESIN,
+ PON_CBLPWR,
};
struct qpnp_pon_config {
@@ -214,6 +218,9 @@
case PON_RESIN:
pon_rt_bit = QPNP_PON_RESIN_N_SET;
break;
+ case PON_CBLPWR:
+ pon_rt_bit = QPNP_PON_CBLPWR_N_SET;
+ break;
default:
return -EINVAL;
}
@@ -253,6 +260,18 @@
return IRQ_HANDLED;
}
+static irqreturn_t qpnp_cblpwr_irq(int irq, void *_pon)
+{
+ int rc;
+ struct qpnp_pon *pon = _pon;
+
+ rc = qpnp_pon_input_dispatch(pon, PON_CBLPWR);
+ if (rc)
+ dev_err(&pon->spmi->dev, "Unable to send input event\n");
+
+ return IRQ_HANDLED;
+}
+
static void bark_work_func(struct work_struct *work)
{
int rc;
@@ -351,6 +370,9 @@
case PON_RESIN:
pull_bit = QPNP_PON_RESIN_PULL_UP;
break;
+ case PON_CBLPWR:
+ pull_bit = QPNP_PON_CBLPWR_PULL_UP;
+ break;
default:
return -EINVAL;
}
@@ -489,6 +511,17 @@
}
}
break;
+ case PON_CBLPWR:
+ rc = devm_request_irq(&pon->spmi->dev, cfg->state_irq,
+ qpnp_cblpwr_irq,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+ "qpnp_cblpwr_status", pon);
+ if (rc < 0) {
+ dev_err(&pon->spmi->dev, "Can't request %d IRQ\n",
+ cfg->state_irq);
+ return rc;
+ }
+ break;
default:
return -EINVAL;
}
@@ -595,6 +628,15 @@
}
}
break;
+ case PON_CBLPWR:
+ cfg->state_irq = spmi_get_irq_byname(pon->spmi,
+ NULL, "cblpwr");
+ if (cfg->state_irq < 0) {
+ dev_err(&pon->spmi->dev,
+ "Unable to get cblpwr irq\n");
+ return rc;
+ }
+ break;
default:
dev_err(&pon->spmi->dev, "PON RESET %d not supported",
cfg->pon_type);
@@ -763,11 +805,13 @@
rc = of_property_read_u32(pon->spmi->dev.of_node,
"qcom,pon-dbc-delay", &delay);
- if (rc && rc != -EINVAL) {
- dev_err(&spmi->dev, "Unable to read debounce delay\n");
- return rc;
+ if (rc) {
+ if (rc != -EINVAL) {
+ dev_err(&spmi->dev, "Unable to read debounce delay\n");
+ return rc;
+ }
} else {
- delay = (delay << 6) / USEC_PER_SEC;
+ delay = (delay << QPNP_PON_DELAY_BIT_SHIFT) / USEC_PER_SEC;
delay = ilog2(delay);
rc = qpnp_pon_masked_write(pon, QPNP_PON_DBC_CTL(pon->base),
QPNP_PON_DBC_DELAY_MASK, delay);
diff --git a/drivers/platform/msm/qpnp-pwm.c b/drivers/platform/msm/qpnp-pwm.c
index 6f9af36..8809abe 100644
--- a/drivers/platform/msm/qpnp-pwm.c
+++ b/drivers/platform/msm/qpnp-pwm.c
@@ -856,7 +856,7 @@
return qpnp_lpg_save_and_write(value, mask,
&pwm->chip->qpnp_lpg_registers[QPNP_ENABLE_CONTROL],
- lpg_config->base_addr, QPNP_RAMP_CONTROL, 1, chip);
+ lpg_config->base_addr, QPNP_ENABLE_CONTROL, 1, chip);
}
static int qpnp_disable_pwm(struct pwm_device *pwm)
@@ -873,7 +873,7 @@
return qpnp_lpg_save_and_write(value, mask,
&pwm->chip->qpnp_lpg_registers[QPNP_ENABLE_CONTROL],
- lpg_config->base_addr, QPNP_RAMP_CONTROL, 1, chip);
+ lpg_config->base_addr, QPNP_ENABLE_CONTROL, 1, chip);
}
static int _pwm_config(struct pwm_device *pwm, int duty_us, int period_us)
diff --git a/drivers/platform/msm/sps/sps.c b/drivers/platform/msm/sps/sps.c
index 5bbcc84..25febff 100644
--- a/drivers/platform/msm/sps/sps.c
+++ b/drivers/platform/msm/sps/sps.c
@@ -1828,19 +1828,6 @@
if (virt_addr != NULL)
bam->props.virt_addr = virt_addr;
- if ((bam_props->manage & SPS_BAM_MGR_DEVICE_REMOTE) != 0 &&
- (bam_props->manage & SPS_BAM_MGR_MULTI_EE) != 0 &&
- bam_props->ee == 0) {
- /*
- * BAM global is owned by a remote processor, so force EE index
- * to a non-zero value to insure EE zero globals are not
- * modified.
- */
- SPS_DBG2("sps:Setting EE for BAM %x to non-zero",
- bam_props->phys_addr);
- bam->props.ee = 1;
- }
-
ok = sps_bam_device_init(bam);
mutex_unlock(&bam->lock);
if (ok) {
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index e6e2f30..a9b0dbb 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -2332,12 +2332,6 @@
return IRQ_HANDLED;
}
-static irqreturn_t pm8921_bms_vsense_avg_handler(int irq, void *data)
-{
- pr_debug("irq = %d triggered", irq);
- return IRQ_HANDLED;
-}
-
struct pm_bms_irq_init_data {
unsigned int irq_id;
char *name;
@@ -2366,8 +2360,6 @@
pm8921_bms_ocv_for_r_handler),
BMS_IRQ(PM8921_BMS_GOOD_OCV, IRQF_TRIGGER_RISING,
pm8921_bms_good_ocv_handler),
- BMS_IRQ(PM8921_BMS_VSENSE_AVG, IRQF_TRIGGER_RISING,
- pm8921_bms_vsense_avg_handler),
};
static void free_irqs(struct pm8921_bms_chip *chip)
diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index 19454ca..b4080df 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -2621,6 +2621,11 @@
pr_debug("USB charger active\n");
pm_chg_iusbmax_get(chip, &usb_ma);
+ if (usb_ma == 500 && !usb_target_ma) {
+ pr_debug("Stopping Unplug Check Worker USB == 500mA\n");
+ disable_input_voltage_regulation(chip);
+ return;
+ }
if (usb_ma <= 100) {
pr_debug(
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index a3f6e58..b2709d2 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -1021,6 +1021,9 @@
dev_vdbg(dwc->dev, "queing request %p to %s length %d\n",
request, ep->name, request->length);
+ WARN(!dep->direction && (request->length % ep->desc->wMaxPacketSize),
+ "trying to queue unaligned request (%d)\n", request->length);
+
spin_lock_irqsave(&dwc->lock, flags);
ret = __dwc3_gadget_ep_queue(dep, req);
spin_unlock_irqrestore(&dwc->lock, flags);
diff --git a/drivers/usb/gadget/f_accessory.c b/drivers/usb/gadget/f_accessory.c
index 108caf9..0353848 100644
--- a/drivers/usb/gadget/f_accessory.c
+++ b/drivers/usb/gadget/f_accessory.c
@@ -40,7 +40,7 @@
#define BULK_BUFFER_SIZE 16384
#define ACC_STRING_SIZE 256
-#define PROTOCOL_VERSION 1
+#define PROTOCOL_VERSION 2
/* String IDs */
#define INTERFACE_STRING_INDEX 0
@@ -78,6 +78,8 @@
/* set to 1 if we have a pending start request */
int start_requested;
+ int audio_mode;
+
/* synchronize access to our device file */
atomic_t open_excl;
@@ -510,6 +512,8 @@
break;
case ACCESSORY_IS_START_REQUESTED:
return dev->start_requested;
+ case ACCESSORY_GET_AUDIO_MODE:
+ return dev->audio_mode;
}
if (!src)
return -EINVAL;
@@ -586,6 +590,10 @@
cdev->gadget->ep0->driver_data = dev;
cdev->req->complete = acc_complete_set_string;
value = w_length;
+ } else if (b_request == ACCESSORY_SET_AUDIO_MODE &&
+ w_index == 0 && w_length == 0) {
+ dev->audio_mode = w_value;
+ value = 0;
}
} else if (b_requestType == (USB_DIR_IN | USB_TYPE_VENDOR)) {
if (b_request == ACCESSORY_GET_PROTOCOL) {
@@ -600,6 +608,7 @@
memset(dev->uri, 0, sizeof(dev->uri));
memset(dev->serial, 0, sizeof(dev->serial));
dev->start_requested = 0;
+ dev->audio_mode = 0;
}
}
diff --git a/drivers/usb/gadget/f_mtp.c b/drivers/usb/gadget/f_mtp.c
index 96790c5..ccbc330 100644
--- a/drivers/usb/gadget/f_mtp.c
+++ b/drivers/usb/gadget/f_mtp.c
@@ -463,6 +463,10 @@
if (count > MTP_BULK_BUFFER_SIZE)
return -EINVAL;
+ if (!IS_ALIGNED(count, dev->ep_out->maxpacket))
+ DBG(cdev, "%s - count(%d) not multiple of mtu(%d)\n", __func__,
+ count, dev->ep_out->maxpacket);
+
/* we will block until we're online */
DBG(cdev, "mtp_read: waiting for online state\n");
ret = wait_event_interruptible(dev->read_wq,
@@ -484,7 +488,7 @@
requeue_req:
/* queue a request */
req = dev->rx_req[0];
- req->length = count;
+ req->length = MTP_BULK_BUFFER_SIZE;
dev->rx_done = 0;
ret = usb_ep_queue(dev->ep_out, req, GFP_KERNEL);
if (ret < 0) {
@@ -751,6 +755,9 @@
count = dev->xfer_file_length;
DBG(cdev, "receive_file_work(%lld)\n", count);
+ if (!IS_ALIGNED(count, dev->ep_out->maxpacket))
+ DBG(cdev, "%s- count(%lld) not multiple of mtu(%d)\n", __func__,
+ count, dev->ep_out->maxpacket);
while (count > 0 || write_req) {
if (count > 0) {
@@ -758,8 +765,9 @@
read_req = dev->rx_req[cur_buf];
cur_buf = (cur_buf + 1) % RX_REQ_MAX;
- read_req->length = (count > MTP_BULK_BUFFER_SIZE
- ? MTP_BULK_BUFFER_SIZE : count);
+ /* some h/w expects size to be aligned to ep's MTU */
+ read_req->length = MTP_BULK_BUFFER_SIZE;
+
dev->rx_done = 0;
ret = usb_ep_queue(dev->ep_out, read_req, GFP_KERNEL);
if (ret < 0) {
@@ -795,6 +803,10 @@
usb_ep_dequeue(dev->ep_out, read_req);
break;
}
+ /* Check if we aligned the size due to MTU constraint */
+ if (count < read_req->length)
+ read_req->actual = (read_req->actual > count ?
+ count : read_req->actual);
/* if xfer_file_length is 0xFFFFFFFF, then we read until
* we get a zero length packet
*/
diff --git a/drivers/usb/misc/ks_bridge.c b/drivers/usb/misc/ks_bridge.c
index 656e379..61e6891 100644
--- a/drivers/usb/misc/ks_bridge.c
+++ b/drivers/usb/misc/ks_bridge.c
@@ -48,6 +48,7 @@
#define BOOT_BRIDGE_INDEX 0
#define EFS_BRIDGE_INDEX 1
#define MAX_DATA_PKT_SIZE 16384
+#define PENDING_URB_TIMEOUT 10
struct ks_bridge {
char *name;
@@ -58,7 +59,10 @@
struct list_head to_mdm_list;
struct list_head to_ks_list;
wait_queue_head_t ks_wait_q;
+ wait_queue_head_t pending_urb_wait;
struct miscdevice *fs_dev;
+ atomic_t tx_pending_cnt;
+ atomic_t rx_pending_cnt;
/* usb specific */
struct usb_device *udev;
@@ -207,13 +211,16 @@
dbg_log_event(ksb, "C TX_URB", urb->status, 0);
pr_debug("status:%d", urb->status);
- if (ksb->ifc)
+ if (test_bit(USB_DEV_CONNECTED, &ksb->flags))
usb_autopm_put_interface_async(ksb->ifc);
if (urb->status < 0)
pr_err_ratelimited("urb failed with err:%d", urb->status);
ksb_free_data_pkt(pkt);
+
+ atomic_dec(&ksb->tx_pending_cnt);
+ wake_up(&ksb->pending_urb_wait);
}
static void ksb_tomdm_work(struct work_struct *w)
@@ -252,6 +259,7 @@
dbg_log_event(ksb, "S TX_URB", pkt->len, 0);
+ atomic_inc(&ksb->tx_pending_cnt);
ret = usb_submit_urb(urb, GFP_KERNEL);
if (ret) {
pr_err("out urb submission failed");
@@ -259,6 +267,8 @@
usb_free_urb(urb);
ksb_free_data_pkt(pkt);
usb_autopm_put_interface(ksb->ifc);
+ atomic_dec(&ksb->tx_pending_cnt);
+ wake_up(&ksb->pending_urb_wait);
return;
}
@@ -420,8 +430,15 @@
ksb_rx_cb, pkt);
usb_anchor_urb(urb, &ksb->submitted);
- dbg_log_event(ksb, "S RX_URB", pkt->len, 0);
+ if (!test_bit(USB_DEV_CONNECTED, &ksb->flags)) {
+ usb_unanchor_urb(urb);
+ usb_free_urb(urb);
+ ksb_free_data_pkt(pkt);
+ ksb->alloced_read_pkts--;
+ return;
+ }
+ atomic_inc(&ksb->rx_pending_cnt);
ret = usb_submit_urb(urb, GFP_ATOMIC);
if (ret) {
pr_err("in urb submission failed");
@@ -429,9 +446,13 @@
usb_free_urb(urb);
ksb_free_data_pkt(pkt);
ksb->alloced_read_pkts--;
+ atomic_dec(&ksb->rx_pending_cnt);
+ wake_up(&ksb->pending_urb_wait);
return;
}
+ dbg_log_event(ksb, "S RX_URB", pkt->len, 0);
+
usb_free_urb(urb);
}
static void ksb_rx_cb(struct urb *urb)
@@ -454,7 +475,7 @@
urb->status);
ksb_free_data_pkt(pkt);
ksb->alloced_read_pkts--;
- return;
+ goto done;
}
if (urb->actual_length == 0) {
@@ -474,7 +495,9 @@
resubmit_urb:
submit_one_urb(ksb);
-
+done:
+ atomic_dec(&ksb->rx_pending_cnt);
+ wake_up(&ksb->pending_urb_wait);
}
static void ksb_start_rx_work(struct work_struct *w)
@@ -487,6 +510,10 @@
int ret;
for (i = 0; i < NO_RX_REQS; i++) {
+
+ if (!test_bit(USB_DEV_CONNECTED, &ksb->flags))
+ return;
+
pkt = ksb_alloc_data_pkt(MAX_DATA_PKT_SIZE, GFP_KERNEL, ksb);
if (IS_ERR(pkt)) {
pr_err("unable to allocate data pkt");
@@ -516,6 +543,7 @@
dbg_log_event(ksb, "S RX_URB", pkt->len, 0);
+ atomic_inc(&ksb->rx_pending_cnt);
ret = usb_submit_urb(urb, GFP_KERNEL);
if (ret) {
pr_err("in urb submission failed");
@@ -524,6 +552,8 @@
ksb_free_data_pkt(pkt);
ksb->alloced_read_pkts--;
usb_autopm_put_interface(ksb->ifc);
+ atomic_dec(&ksb->rx_pending_cnt);
+ wake_up(&ksb->pending_urb_wait);
return;
}
@@ -590,6 +620,8 @@
usb_set_intfdata(ifc, ksb);
set_bit(USB_DEV_CONNECTED, &ksb->flags);
+ atomic_set(&ksb->tx_pending_cnt, 0);
+ atomic_set(&ksb->rx_pending_cnt, 0);
dbg_log_event(ksb, "PID-ATT", id->idProduct, 0);
@@ -640,9 +672,16 @@
clear_bit(USB_DEV_CONNECTED, &ksb->flags);
wake_up(&ksb->ks_wait_q);
cancel_work_sync(&ksb->to_mdm_work);
+ cancel_work_sync(&ksb->start_rx_work);
usb_kill_anchored_urbs(&ksb->submitted);
+ wait_event_interruptible_timeout(
+ ksb->pending_urb_wait,
+ !atomic_read(&ksb->tx_pending_cnt) &&
+ !atomic_read(&ksb->rx_pending_cnt),
+ msecs_to_jiffies(PENDING_URB_TIMEOUT));
+
spin_lock_irqsave(&ksb->lock, flags);
while (!list_empty(&ksb->to_ks_list)) {
pkt = list_first_entry(&ksb->to_ks_list,
@@ -741,6 +780,7 @@
INIT_LIST_HEAD(&ksb->to_mdm_list);
INIT_LIST_HEAD(&ksb->to_ks_list);
init_waitqueue_head(&ksb->ks_wait_q);
+ init_waitqueue_head(&ksb->pending_urb_wait);
ksb->wq = create_singlethread_workqueue(ksb->name);
if (!ksb->wq) {
pr_err("unable to allocate workqueue");
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index 813fc94..f27e0eb 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -2041,6 +2041,8 @@
udelay(20);
break;
case SNPS_28NM_INTEGRATED_PHY:
+ /* disable DP and DM pull down resistors */
+ ulpi_write(phy, 0x6, 0xC);
/* Clear charger detecting control bits */
ulpi_write(phy, 0x1F, 0x86);
/* Clear alt interrupt latch and enable bits */
@@ -2120,8 +2122,7 @@
switch (motg->chg_state) {
case USB_CHG_STATE_UNDEFINED:
msm_chg_block_on(motg);
- if (motg->pdata->enable_dcd)
- msm_chg_enable_dcd(motg);
+ msm_chg_enable_dcd(motg);
msm_chg_enable_aca_det(motg);
motg->chg_state = USB_CHG_STATE_WAIT_FOR_DCD;
motg->dcd_retries = 0;
@@ -2148,12 +2149,10 @@
break;
}
}
- if (motg->pdata->enable_dcd)
- is_dcd = msm_chg_check_dcd(motg);
+ is_dcd = msm_chg_check_dcd(motg);
tmout = ++motg->dcd_retries == MSM_CHG_DCD_MAX_RETRIES;
if (is_dcd || tmout) {
- if (motg->pdata->enable_dcd)
- msm_chg_disable_dcd(motg);
+ msm_chg_disable_dcd(motg);
msm_chg_enable_primary_det(motg);
delay = MSM_CHG_PRIMARY_DET_TIME;
motg->chg_state = USB_CHG_STATE_DCD_DONE;
diff --git a/drivers/video/msm/mddi_quickvx.c b/drivers/video/msm/mddi_quickvx.c
index 95e7d41..37c147d 100644
--- a/drivers/video/msm/mddi_quickvx.c
+++ b/drivers/video/msm/mddi_quickvx.c
@@ -263,22 +263,10 @@
int ql_mddi_write(uint32 address, uint32 value)
{
- uint32 regval = 0;
int ret = 0;
ret = mddi_queue_register_write(address, value, TRUE, 0);
- if (!ret) {
- ret = mddi_queue_register_read(address, ®val, TRUE, 0);
- if (regval != value) {
- MDDI_MSG_DEBUG("\nMismatch: ql_mddi_write[0x%x]->0x%x "
- "r0x%x\n", address, value, regval);
- } else {
- MDDI_MSG_DEBUG("\nMatch: ql_mddi_write[0x%x]->0x%x "
- "r0x%x\n", address, value, regval);
- }
- }
-
return ret;
}
@@ -294,8 +282,6 @@
int ql_send_spi_cmd_to_lcd(uint32 index, uint32 cmd)
{
- int retry, ret;
- uint32 readval;
MDDI_MSG_DEBUG("\n %s(): index 0x%x, cmd 0x%x", __func__, index, cmd);
/* do the index phase */
@@ -308,18 +294,6 @@
/* set start */
ql_mddi_write(QUICKVX_SPI_CTRL_REG, QL_SPI_CTRL_LCD_START);
- retry = 0;
-
- do {
- ret = ql_mddi_read(QUICKVX_SPI_CTRL_REG, &readval);
-
- if (ret || ++retry > 5) {
- MDDI_MSG_DEBUG("\n ql_send_spi_cmd_to_lcd: retry "
- "timeout at index phase, ret = %d", ret);
- return -EIO;
- }
- mddi_wait(1);
- } while ((readval & QL_SPI_CTRL_MASK_rTxDone) == 0);
/* do the command phase */
/* send 24 bits in the cmd phase */
@@ -331,18 +305,6 @@
/* set start */
ql_mddi_write(QUICKVX_SPI_CTRL_REG, QL_SPI_CTRL_LCD_START);
- retry = 0;
-
- do {
- ret = ql_mddi_read(QUICKVX_SPI_CTRL_REG, &readval);
-
- if (ret || ++retry > 5) {
- MDDI_MSG_DEBUG("\n ql_send_spi_cmd_to_lcd: retry "
- "timeout at cmd phase, ret = %d", ret);
- return -EIO;
- }
- mddi_wait(1);
- } while ((readval & QL_SPI_CTRL_MASK_rTxDone) == 0);
return 0;
}
@@ -350,8 +312,6 @@
int ql_send_spi_data_from_lcd(uint32 index, uint32 *value)
{
- int retry, ret;
- uint32 readval;
MDDI_MSG_DEBUG("\n %s(): index 0x%x", __func__, index);
/* do the index phase */
@@ -364,19 +324,6 @@
/* set start */
ql_mddi_write(QUICKVX_SPI_CTRL_REG, QL_SPI_CTRL_LCD_START);
- retry = 0;
-
- do {
- ret = ql_mddi_read(QUICKVX_SPI_CTRL_REG, &readval);
-
- if (ret || ++retry > 5) {
- MDDI_MSG_DEBUG("\n ql_send_spi_cmd_to_lcd: retry "
- "timeout at index phase, ret = %d", ret);
- return -EIO;
- }
- mddi_wait(1);
- } while ((readval & QL_SPI_CTRL_MASK_rTxDone) == 0);
-
/* do the command phase */
/* send 8 bits and read 24 bits in the cmd phase, so total 32 bits */
ql_mddi_write(QUICKVX_SPI_TLEN_REG, 31);
@@ -387,29 +334,9 @@
/* set start */
ql_mddi_write(QUICKVX_SPI_CTRL_REG, QL_SPI_CTRL_LCD_START);
- retry = 0;
- do {
- ret = ql_mddi_read(QUICKVX_SPI_CTRL_REG, &readval);
+ return 0;
- if (ret || ++retry > 5) {
- MDDI_MSG_DEBUG("\n ql_send_spi_cmd_to_lcd: retry "
- "timeout at cmd phase, ret = %d", ret);
- return -EIO;
- }
- mddi_wait(1);
- } while ((readval & QL_SPI_CTRL_MASK_rTxDone) == 0);
-
- /* value will appear at lower 16 bits */
- ret = ql_mddi_read(QUICKVX_SPI_RX0_REG, value);
-
- if (!ret) {
- *value = *value & 0xffff;
- MDDI_MSG_DEBUG("\n QUICKVX_SPI_RX0_REG value = 0x%x", *value);
- } else
- MDDI_MSG_DEBUG("\n Read QUICKVX_SPI_RX0_REG Failed");
-
- return ret;
}
/* Global Variables */
diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c
index 6c0d08d..f8ccee9 100644
--- a/drivers/video/msm/mdp.c
+++ b/drivers/video/msm/mdp.c
@@ -2214,6 +2214,8 @@
mfd->panel.type == LCDC_PANEL ||
mfd->panel.type == LVDS_PANEL)
mdp4_lcdc_off(pdev);
+ else if (mfd->panel.type == MDDI_PANEL)
+ mdp4_mddi_off(pdev);
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
ret = panel_next_off(pdev);
@@ -2268,6 +2270,9 @@
mfd->panel.type == LCDC_PANEL ||
mfd->panel.type == LVDS_PANEL) {
mdp4_lcdc_on(pdev);
+ } else if (mfd->panel.type == MDDI_PANEL) {
+ mdp_vsync_cfg_regs(mfd, FALSE);
+ mdp4_mddi_on(pdev);
}
mdp_clk_ctrl(0);
@@ -2706,6 +2711,9 @@
mdp_vsync_resync_workqueue_handler);
mfd->hw_refresh = FALSE;
+ if (mfd->panel.type == MDDI_PANEL)
+ mdp4_mddi_rdptr_init(0);
+
if (mfd->panel.type == EXT_MDDI_PANEL) {
/* 15 fps -> 66 msec */
mfd->refresh_timer_duration = (66 * HZ / 1000);
diff --git a/drivers/video/msm/mdp.h b/drivers/video/msm/mdp.h
index d939c62..b4a7f79 100644
--- a/drivers/video/msm/mdp.h
+++ b/drivers/video/msm/mdp.h
@@ -796,6 +796,10 @@
{
return 0;
}
+static inline int mdp4_mddi_off(struct platform_device *pdev)
+{
+ return 0;
+}
static inline int mdp4_dsi_cmd_on(struct platform_device *pdev)
{
return 0;
@@ -808,6 +812,19 @@
{
return 0;
}
+static inline int mdp4_mddi_on(struct platform_device *pdev)
+{
+ return 0;
+}
+#endif
+
+
+#ifndef CONFIG_FB_MSM_MDDI
+static inline void mdp4_mddi_rdptr_init(int cndx)
+{
+ /* empty */
+}
+
#endif
void set_cont_splashScreen_status(int);
diff --git a/drivers/video/msm/mdp4.h b/drivers/video/msm/mdp4.h
index 180a18a..67a0429 100644
--- a/drivers/video/msm/mdp4.h
+++ b/drivers/video/msm/mdp4.h
@@ -596,9 +596,10 @@
int mdp4_overlay_pipe_staged(int mixer);
void mdp4_lcdc_primary_vsyn(void);
void mdp4_overlay0_done_lcdc(int cndx);
-void mdp4_overlay0_done_mddi(struct mdp_dma_data *dma);
+void mdp4_overlay0_done_mddi(int cndx);
void mdp4_dma_p_done_mddi(struct mdp_dma_data *dma);
void mdp4_dmap_done_dsi_cmd(int cndx);
+void mdp4_dmap_done_mddi(int cndx);
void mdp4_dmap_done_dsi_video(int cndx);
void mdp4_dmap_done_lcdc(int cndx);
void mdp4_overlay1_done_dtv(void);
@@ -672,6 +673,12 @@
void mdp4_dsi_video_overlay_blt(struct msm_fb_data_type *mfd,
struct msmfb_overlay_blt *req);
void mdp4_dsi_video_base_swap(int cndx, struct mdp4_overlay_pipe *pipe);
+static inline void mdp4_mddi_blt_start(struct msm_fb_data_type *mfd)
+{
+}
+static inline void mdp4_mddi_blt_stop(struct msm_fb_data_type *mfd)
+{
+}
#ifdef CONFIG_FB_MSM_MDP40
static inline void mdp3_dsi_cmd_dma_busy_wait(struct msm_fb_data_type *mfd)
@@ -680,6 +687,8 @@
}
#endif
#else /* CONFIG_FB_MSM_MIPI_DSI */
+void mdp4_mddi_blt_start(struct msm_fb_data_type *mfd);
+void mdp4_mddi_blt_stop(struct msm_fb_data_type *mfd);
int mdp4_mddi_overlay_blt_offset(struct msm_fb_data_type *mfd,
struct msmfb_overlay_blt *req);
void mdp4_mddi_overlay_blt(struct msm_fb_data_type *mfd,
@@ -687,6 +696,7 @@
int mdp4_mddi_overlay_blt_start(struct msm_fb_data_type *mfd);
int mdp4_mddi_overlay_blt_stop(struct msm_fb_data_type *mfd);
void mdp4_mddi_blt_dmap_busy_wait(struct msm_fb_data_type *mfd);
+void mdp4_mddi_rdptr_init(int cndx);
static inline int mdp4_dsi_overlay_blt_start(struct msm_fb_data_type *mfd)
{
return -ENODEV;
@@ -776,11 +786,37 @@
{
/* empty */
}
-#else /* CONFIG_FB_MSM_MIPI_DSI */
+#else /* CONFIG_FB_MSM_MDP303 */
void mdp4_dsi_cmd_del_timer(void);
+static inline int mdp4_mddi_on(struct platform_device *pdev)
+{
+ return 0;
+}
+static inline int mdp4_mddi_off(struct platform_device *pdev)
+{
+ return 0;
+}
+static inline void mdp4_mddi_wait4vsync(int cndx, long long *vtime)
+{
+}
+static inline void mdp4_mddi_vsync_ctrl(struct fb_info *info,
+ int enable)
+{
+}
+static inline void mdp4_mddi_pipe_queue(int cndx,
+ struct mdp4_overlay_pipe *pipe)
+{
+}
#endif
#else /* CONFIG_FB_MSM_MIPI_DSI */
+int mdp4_mddi_off(struct platform_device *pdev);
+int mdp4_mddi_on(struct platform_device *pdev);
+void mdp4_mddi_wait4vsync(int cndx, long long *vtime);
+void mdp4_mddi_vsync_ctrl(struct fb_info *info, int enable);
+void mdp4_mddi_pipe_queue(int cndx, struct mdp4_overlay_pipe *pipe);
+void mdp4_overlay_update_mddi(struct msm_fb_data_type *mfd);
+
static inline int mdp4_dsi_cmd_on(struct platform_device *pdev)
{
return 0;
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index 8499e3e..6faf3e7 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -1989,7 +1989,8 @@
if (s_pipe->pipe_type == OVERLAY_TYPE_VIDEO &&
((s_pipe->op_mode & MDP4_OP_SCALEY_EN) ||
(s_pipe->op_mode & MDP4_OP_SCALEX_EN)) &&
- !(s_pipe->op_mode & MDP4_OP_SCALEY_PIXEL_RPT))
+ !(s_pipe->op_mode & (MDP4_OP_SCALEX_PIXEL_RPT |
+ MDP4_OP_SCALEY_PIXEL_RPT)))
alpha_drop = 1;
d_pipe = mdp4_background_layer(mixer, s_pipe);
@@ -2868,6 +2869,8 @@
mdp4_dsi_video_blt_start(mfd);
else if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD)
mdp4_dsi_cmd_blt_start(mfd);
+ else if (ctrl->panel_mode & MDP4_PANEL_MDDI)
+ mdp4_mddi_blt_start(mfd);
pr_info("%s mixer0 start blt [%d] from %d to %d.\n",
__func__,
flag,
@@ -2916,6 +2919,8 @@
mdp4_dsi_video_blt_stop(mfd);
else if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD)
mdp4_dsi_cmd_blt_stop(mfd);
+ else if (ctrl->panel_mode & MDP4_PANEL_MDDI)
+ mdp4_mddi_blt_stop(mfd);
pr_info("%s mixer0 stop blt [%d] from %d to %d.\n",
__func__,
flag,
@@ -3180,20 +3185,14 @@
else {
/* mixer 0 */
ctrl->mixer0_played = 0;
- if (ctrl->panel_mode & MDP4_PANEL_MDDI) {
- if (mfd->panel_power_on)
- mdp4_mddi_blt_dmap_busy_wait(mfd);
- }
+
}
mdp4_overlay_reg_flush(pipe, 1);
mdp4_mixer_stage_down(pipe, 0);
if (pipe->mixer_num == MDP4_MIXER0) {
- if (ctrl->panel_mode & MDP4_PANEL_MDDI) {
- if (mfd->panel_power_on)
- mdp4_mddi_overlay_restore();
- }
+
} else { /* mixer1, DTV, ATV */
if (ctrl->panel_mode & MDP4_PANEL_DTV)
mdp4_overlay_dtv_unset(mfd, pipe);
@@ -3217,6 +3216,8 @@
mdp4_dsi_cmd_wait4vsync(0, vtime);
else if (ctrl->panel_mode & MDP4_PANEL_LCDC)
mdp4_lcdc_wait4vsync(0, vtime);
+ else if (ctrl->panel_mode & MDP4_PANEL_MDDI)
+ mdp4_mddi_wait4vsync(0, vtime);
} else if (hdmi_prim_display || info->node == 1) {
mdp4_dtv_wait4vsync(0, vtime);
}
@@ -3240,6 +3241,8 @@
mdp4_dsi_cmd_vsync_ctrl(info, cmd);
else if (ctrl->panel_mode & MDP4_PANEL_LCDC)
mdp4_lcdc_vsync_ctrl(info, cmd);
+ else if (ctrl->panel_mode & MDP4_PANEL_MDDI)
+ mdp4_mddi_vsync_ctrl(info, cmd);
} else if (hdmi_prim_display || info->node == 1)
mdp4_dtv_vsync_ctrl(info, cmd);
@@ -3460,9 +3463,6 @@
mdp4_overlay_mdp_perf_req(mfd, ctrl->plist);
- if (pipe->mixer_num == MDP4_MIXER2 ||
- ctrl->panel_mode & MDP4_PANEL_MDDI)
- goto mddi;
if (pipe->mixer_num == MDP4_MIXER0) {
if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD) {
@@ -3475,43 +3475,35 @@
/* cndx = 0 */
mdp4_lcdc_pipe_queue(0, pipe);
}
+ if (ctrl->panel_mode & MDP4_PANEL_MDDI) {
+ /* cndx = 0 */
+ mdp4_mddi_pipe_queue(0, pipe);
+ }
} else if (pipe->mixer_num == MDP4_MIXER1) {
if (ctrl->panel_mode & MDP4_PANEL_DTV)
mdp4_dtv_pipe_queue(0, pipe);/* cndx = 0 */
- }
+ } else if (pipe->mixer_num == MDP4_MIXER2) {
- mutex_unlock(&mfd->dma->ov_mutex);
- return ret;
+ if (pipe->pipe_type == OVERLAY_TYPE_VIDEO)
+ mdp4_overlay_vg_setup(pipe); /* video/graphic pipe */
+ else
+ mdp4_overlay_rgb_setup(pipe); /* rgb pipe */
-mddi:
- if (pipe->pipe_type == OVERLAY_TYPE_VIDEO) {
- mdp4_overlay_vg_setup(pipe); /* video/graphic pipe */
- } else {
- mdp4_overlay_rgb_setup(pipe); /* rgb pipe */
- }
+ mdp4_mixer_stage_up(pipe, 0);
- mdp4_mixer_stage_up(pipe, 0);
-
- if (pipe->mixer_num == MDP4_MIXER2) {
ctrl->mixer2_played++;
if (ctrl->panel_mode & MDP4_PANEL_WRITEBACK) {
mdp4_writeback_dma_busy_wait(mfd);
mdp4_writeback_kickoff_video(mfd, pipe);
}
- } else if (ctrl->panel_mode & MDP4_PANEL_MDDI) {
- if (pipe->flags & MDP_OV_PLAY_NOWAIT) {
- mdp4_stat.overlay_play[pipe->mixer_num]++;
- mutex_unlock(&mfd->dma->ov_mutex);
- goto end;
- }
- mdp4_mixer_stage_commit(pipe->mixer_num);
- mdp4_mddi_dma_busy_wait(mfd);
- mdp4_mddi_kickoff_video(mfd, pipe);
+
+ if (!(pipe->flags & MDP_OV_PLAY_NOWAIT))
+ mdp4_iommu_unmap(pipe);
+ mdp4_stat.overlay_play[pipe->mixer_num]++;
}
- if (!(pipe->flags & MDP_OV_PLAY_NOWAIT))
- mdp4_iommu_unmap(pipe);
- mdp4_stat.overlay_play[pipe->mixer_num]++;
+ mutex_unlock(&mfd->dma->ov_mutex);
+ return ret;
end:
mutex_unlock(&mfd->dma->ov_mutex);
diff --git a/drivers/video/msm/mdp4_overlay_mddi.c b/drivers/video/msm/mdp4_overlay_mddi.c
index be4a89a..ca84eca 100644
--- a/drivers/video/msm/mdp4_overlay_mddi.c
+++ b/drivers/video/msm/mdp4_overlay_mddi.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2009-2012, 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
@@ -17,38 +17,680 @@
#include <linux/time.h>
#include <linux/init.h>
#include <linux/interrupt.h>
-#include <linux/hrtimer.h>
#include <linux/delay.h>
-#include <mach/hardware.h>
#include <linux/io.h>
-
-#include <asm/system.h>
-#include <asm/mach-types.h>
#include <linux/semaphore.h>
#include <linux/spinlock.h>
-
#include <linux/fb.h>
+#include <asm/system.h>
+#include <asm/mach-types.h>
+#include <mach/hardware.h>
#include "mdp.h"
#include "msm_fb.h"
#include "mdp4.h"
-static struct mdp4_overlay_pipe *mddi_pipe;
-static struct msm_fb_data_type *mddi_mfd;
-static int busy_wait_cnt;
+static int mddi_state;
+
+#define TOUT_PERIOD HZ /* 1 second */
+#define MS_100 (HZ/10) /* 100 ms */
static int vsync_start_y_adjust = 4;
-static int dmap_vsync_enable;
+#define MAX_CONTROLLER 1
+#define VSYNC_EXPIRE_TICK 8
-void mdp_dmap_vsync_set(int enable)
+static struct vsycn_ctrl {
+ struct device *dev;
+ int inited;
+ int update_ndx;
+ int expire_tick;
+ int blt_wait;
+ u32 ov_koff;
+ u32 ov_done;
+ u32 dmap_koff;
+ u32 dmap_done;
+ uint32 rdptr_intr_tot;
+ uint32 rdptr_sirq_tot;
+ atomic_t suspend;
+ int wait_vsync_cnt;
+ int blt_change;
+ int blt_free;
+ int blt_end;
+ int uevent;
+ struct mutex update_lock;
+ struct completion ov_comp;
+ struct completion dmap_comp;
+ struct completion vsync_comp;
+ spinlock_t spin_lock;
+ struct msm_fb_data_type *mfd;
+ struct mdp4_overlay_pipe *base_pipe;
+ struct vsync_update vlist[2];
+ int vsync_enabled;
+ int clk_enabled;
+ int clk_control;
+ int new_update;
+ ktime_t vsync_time;
+ struct work_struct vsync_work;
+ struct work_struct clk_work;
+} vsync_ctrl_db[MAX_CONTROLLER];
+
+static void vsync_irq_enable(int intr, int term)
{
- dmap_vsync_enable = enable;
+ unsigned long flag;
+
+ spin_lock_irqsave(&mdp_spin_lock, flag);
+ /* no need to clear other interrupts for comamnd mode */
+ mdp_intr_mask |= intr;
+ outp32(MDP_INTR_ENABLE, mdp_intr_mask);
+ mdp_enable_irq(term);
+ spin_unlock_irqrestore(&mdp_spin_lock, flag);
}
-int mdp_dmap_vsync_get(void)
+static void vsync_irq_disable(int intr, int term)
{
- return dmap_vsync_enable;
+ unsigned long flag;
+
+ spin_lock_irqsave(&mdp_spin_lock, flag);
+ /* no need to clrear other interrupts for comamnd mode */
+ mdp_intr_mask &= ~intr;
+ outp32(MDP_INTR_ENABLE, mdp_intr_mask);
+ mdp_disable_irq_nosync(term);
+ spin_unlock_irqrestore(&mdp_spin_lock, flag);
+}
+
+static void mdp4_mddi_blt_ov_update(struct mdp4_overlay_pipe *pipe)
+{
+ uint32 off, addr;
+ int bpp;
+ char *overlay_base;
+
+ if (pipe->ov_blt_addr == 0)
+ return;
+
+ bpp = 3; /* overlay ouput is RGB888 */
+ off = 0;
+ if (pipe->ov_cnt & 0x01)
+ off = pipe->src_height * pipe->src_width * bpp;
+ addr = pipe->ov_blt_addr + off;
+ /* overlay 0 */
+ overlay_base = MDP_BASE + MDP4_OVERLAYPROC0_BASE;/* 0x10000 */
+ outpdw(overlay_base + 0x000c, addr);
+ outpdw(overlay_base + 0x001c, addr);
+}
+
+static void mdp4_mddi_blt_dmap_update(struct mdp4_overlay_pipe *pipe)
+{
+ uint32 off, addr;
+ int bpp;
+
+ if (pipe->ov_blt_addr == 0)
+ return;
+
+ bpp = 3; /* overlay ouput is RGB888 */
+ off = 0;
+ if (pipe->dmap_cnt & 0x01)
+ off = pipe->src_height * pipe->src_width * bpp;
+ addr = pipe->dma_blt_addr + off;
+
+ /* dmap */
+ MDP_OUTP(MDP_BASE + 0x90008, addr);
+}
+
+static void mdp4_mddi_wait4dmap(int cndx);
+static void mdp4_mddi_wait4ov(int cndx);
+
+static void mdp4_mddi_do_blt(struct msm_fb_data_type *mfd, int enable)
+{
+ unsigned long flags;
+ int cndx = 0;
+ struct vsycn_ctrl *vctrl;
+ struct mdp4_overlay_pipe *pipe;
+ int need_wait;
+
+ vctrl = &vsync_ctrl_db[cndx];
+ pipe = vctrl->base_pipe;
+
+ mdp4_allocate_writeback_buf(mfd, MDP4_MIXER0);
+
+ if (mfd->ov0_wb_buf->write_addr == 0) {
+ pr_err("%s: no blt_base assigned\n", __func__);
+ return;
+ }
+
+ spin_lock_irqsave(&vctrl->spin_lock, flags);
+ if (enable && pipe->ov_blt_addr == 0) {
+ vctrl->blt_change++;
+ if (vctrl->dmap_koff != vctrl->dmap_done) {
+ INIT_COMPLETION(vctrl->dmap_comp);
+ need_wait = 1;
+ }
+ } else if (enable == 0 && pipe->ov_blt_addr) {
+ vctrl->blt_change++;
+ if (vctrl->ov_koff != vctrl->dmap_done) {
+ INIT_COMPLETION(vctrl->dmap_comp);
+ need_wait = 1;
+ }
+ }
+ spin_unlock_irqrestore(&vctrl->spin_lock, flags);
+
+ if (need_wait)
+ mdp4_mddi_wait4dmap(0);
+
+ spin_lock_irqsave(&vctrl->spin_lock, flags);
+ if (enable && pipe->ov_blt_addr == 0) {
+ pipe->ov_blt_addr = mfd->ov0_wb_buf->write_addr;
+ pipe->dma_blt_addr = mfd->ov0_wb_buf->read_addr;
+ pipe->ov_cnt = 0;
+ pipe->dmap_cnt = 0;
+ vctrl->ov_koff = vctrl->dmap_koff;
+ vctrl->ov_done = vctrl->dmap_done;
+ vctrl->blt_free = 0;
+ vctrl->blt_wait = 0;
+ vctrl->blt_end = 0;
+ mdp4_stat.blt_mddi++;
+ } else if (enable == 0 && pipe->ov_blt_addr) {
+ pipe->ov_blt_addr = 0;
+ pipe->dma_blt_addr = 0;
+ vctrl->blt_end = 1;
+ vctrl->blt_free = 4; /* 4 commits to free wb buf */
+ }
+
+ pr_debug("%s: changed=%d enable=%d ov_blt_addr=%x\n", __func__,
+ vctrl->blt_change, enable, (int)pipe->ov_blt_addr);
+
+ spin_unlock_irqrestore(&vctrl->spin_lock, flags);
+}
+
+/*
+ * mdp4_mddi_do_update:
+ * called from thread context
+ */
+void mdp4_mddi_pipe_queue(int cndx, struct mdp4_overlay_pipe *pipe)
+{
+ struct vsycn_ctrl *vctrl;
+ struct vsync_update *vp;
+ struct mdp4_overlay_pipe *pp;
+ int undx;
+
+ if (cndx >= MAX_CONTROLLER) {
+ pr_err("%s: out or range: cndx=%d\n", __func__, cndx);
+ return;
+ }
+
+ vctrl = &vsync_ctrl_db[cndx];
+
+ if (atomic_read(&vctrl->suspend) > 0)
+ return;
+
+ mutex_lock(&vctrl->update_lock);
+ undx = vctrl->update_ndx;
+ vp = &vctrl->vlist[undx];
+
+ pp = &vp->plist[pipe->pipe_ndx - 1]; /* ndx start form 1 */
+
+ pr_debug("%s: vndx=%d pipe_ndx=%d expire=%x pid=%d\n", __func__,
+ undx, pipe->pipe_ndx, vctrl->expire_tick, current->pid);
+
+ *pp = *pipe; /* clone it */
+ vp->update_cnt++;
+
+ mutex_unlock(&vctrl->update_lock);
+ mdp4_stat.overlay_play[pipe->mixer_num]++;
+}
+
+static void mdp4_mddi_blt_ov_update(struct mdp4_overlay_pipe *pipe);
+
+int mdp4_mddi_pipe_commit(void)
+{
+ int i, undx;
+ int mixer = 0;
+ struct vsycn_ctrl *vctrl;
+ struct vsync_update *vp;
+ struct mdp4_overlay_pipe *pipe;
+ struct mdp4_overlay_pipe *real_pipe;
+ unsigned long flags;
+ int need_dmap_wait = 0;
+ int need_ov_wait = 0;
+ int cnt = 0;
+
+ vctrl = &vsync_ctrl_db[0];
+
+ mutex_lock(&vctrl->update_lock);
+ undx = vctrl->update_ndx;
+ vp = &vctrl->vlist[undx];
+ pipe = vctrl->base_pipe;
+ mixer = pipe->mixer_num;
+
+ if (vp->update_cnt == 0) {
+ mutex_unlock(&vctrl->update_lock);
+ return cnt;
+ }
+
+ vctrl->update_ndx++;
+ vctrl->update_ndx &= 0x01;
+ vp->update_cnt = 0; /* reset */
+ if (vctrl->blt_free) {
+ vctrl->blt_free--;
+ if (vctrl->blt_free == 0)
+ mdp4_free_writeback_buf(vctrl->mfd, mixer);
+ }
+ mutex_unlock(&vctrl->update_lock);
+
+ /* free previous committed iommu back to pool */
+ mdp4_overlay_iommu_unmap_freelist(mixer);
+
+ spin_lock_irqsave(&vctrl->spin_lock, flags);
+ if (pipe->ov_blt_addr) {
+ /* Blt */
+ if (vctrl->blt_wait)
+ need_dmap_wait = 1;
+ if (vctrl->ov_koff != vctrl->ov_done) {
+ INIT_COMPLETION(vctrl->ov_comp);
+ need_ov_wait = 1;
+ }
+ } else {
+ /* direct out */
+ if (vctrl->dmap_koff != vctrl->dmap_done) {
+ INIT_COMPLETION(vctrl->dmap_comp);
+ pr_debug("%s: wait, ok=%d od=%d dk=%d dd=%d cpu=%d\n",
+ __func__, vctrl->ov_koff, vctrl->ov_done,
+ vctrl->dmap_koff, vctrl->dmap_done, smp_processor_id());
+ need_dmap_wait = 1;
+ }
+ }
+ spin_unlock_irqrestore(&vctrl->spin_lock, flags);
+
+ if (need_dmap_wait) {
+ pr_debug("%s: wait4dmap\n", __func__);
+ mdp4_mddi_wait4dmap(0);
+ }
+
+ if (need_ov_wait) {
+ pr_debug("%s: wait4ov\n", __func__);
+ mdp4_mddi_wait4ov(0);
+ }
+
+ if (pipe->ov_blt_addr) {
+ if (vctrl->blt_end) {
+ vctrl->blt_end = 0;
+ pipe->ov_blt_addr = 0;
+ pipe->dma_blt_addr = 0;
+ }
+ }
+
+ if (vctrl->blt_change) {
+ mdp4_overlayproc_cfg(pipe);
+ mdp4_overlay_dmap_xy(pipe);
+ vctrl->blt_change = 0;
+ }
+
+ pipe = vp->plist;
+ for (i = 0; i < OVERLAY_PIPE_MAX; i++, pipe++) {
+ if (pipe->pipe_used) {
+ cnt++;
+ real_pipe = mdp4_overlay_ndx2pipe(pipe->pipe_ndx);
+ if (real_pipe && real_pipe->pipe_used) {
+ /* pipe not unset */
+ mdp4_overlay_vsync_commit(pipe);
+ }
+ /* free previous iommu to freelist
+ * which will be freed at next
+ * pipe_commit
+ */
+ mdp4_overlay_iommu_pipe_free(pipe->pipe_ndx, 0);
+ pipe->pipe_used = 0; /* clear */
+ }
+ }
+
+ mdp4_mixer_stage_commit(mixer);
+
+ pipe = vctrl->base_pipe;
+ spin_lock_irqsave(&vctrl->spin_lock, flags);
+ if (pipe->ov_blt_addr) {
+ mdp4_mddi_blt_ov_update(pipe);
+ pipe->ov_cnt++;
+ vctrl->ov_koff++;
+ vsync_irq_enable(INTR_OVERLAY0_DONE, MDP_OVERLAY0_TERM);
+ } else {
+ vsync_irq_enable(INTR_DMA_P_DONE, MDP_DMAP_TERM);
+ vctrl->dmap_koff++;
+ }
+ pr_debug("%s: kickoff\n", __func__);
+ /* kickoff overlay engine */
+ mdp4_stat.kickoff_ov0++;
+ outpdw(MDP_BASE + 0x0004, 0);
+ mb(); /* make sure kickoff ececuted */
+ spin_unlock_irqrestore(&vctrl->spin_lock, flags);
+
+ mdp4_stat.overlay_commit[pipe->mixer_num]++;
+
+ return cnt;
+}
+
+void mdp4_mddi_vsync_ctrl(struct fb_info *info, int enable)
+{
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+ struct vsycn_ctrl *vctrl;
+ unsigned long flags;
+ int clk_set_on = 0;
+ int cndx = 0;
+
+ vctrl = &vsync_ctrl_db[cndx];
+
+ pr_debug("%s: clk_enabled=%d vsycn_enabeld=%d req=%d\n", __func__,
+ vctrl->clk_enabled, vctrl->vsync_enabled, enable);
+
+ mutex_lock(&vctrl->update_lock);
+
+ if (vctrl->vsync_enabled == enable) {
+ mutex_unlock(&vctrl->update_lock);
+ return;
+ }
+
+ vctrl->vsync_enabled = enable;
+
+ if (enable) {
+ if (vctrl->clk_enabled == 0) {
+ pr_debug("%s: SET_CLK_ON\n", __func__);
+ mdp_clk_ctrl(1);
+ vctrl->clk_enabled = 1;
+ clk_set_on = 1;
+ }
+ spin_lock_irqsave(&vctrl->spin_lock, flags);
+ vctrl->clk_control = 0;
+ vctrl->expire_tick = 0;
+ vctrl->uevent = 1;
+ vctrl->new_update = 1;
+ if (clk_set_on) {
+ vsync_irq_enable(INTR_PRIMARY_RDPTR,
+ MDP_PRIM_RDPTR_TERM);
+ }
+ spin_unlock_irqrestore(&vctrl->spin_lock, flags);
+
+ mdp4_overlay_update_mddi(mfd);
+ } else {
+ spin_lock_irqsave(&vctrl->spin_lock, flags);
+ vctrl->clk_control = 1;
+ vctrl->uevent = 0;
+ if (vctrl->clk_enabled)
+ vctrl->expire_tick = VSYNC_EXPIRE_TICK;
+ spin_unlock_irqrestore(&vctrl->spin_lock, flags);
+ }
+ mutex_unlock(&vctrl->update_lock);
+}
+
+void mdp4_mddi_wait4vsync(int cndx, long long *vtime)
+{
+ struct vsycn_ctrl *vctrl;
+ struct mdp4_overlay_pipe *pipe;
+ unsigned long flags;
+
+ if (cndx >= MAX_CONTROLLER) {
+ pr_err("%s: out or range: cndx=%d\n", __func__, cndx);
+ return;
+ }
+
+ vctrl = &vsync_ctrl_db[cndx];
+ pipe = vctrl->base_pipe;
+
+ if (atomic_read(&vctrl->suspend) > 0) {
+ *vtime = -1;
+ return;
+ }
+
+ spin_lock_irqsave(&vctrl->spin_lock, flags);
+ if (vctrl->wait_vsync_cnt == 0)
+ INIT_COMPLETION(vctrl->vsync_comp);
+ vctrl->wait_vsync_cnt++;
+ spin_unlock_irqrestore(&vctrl->spin_lock, flags);
+
+ wait_for_completion(&vctrl->vsync_comp);
+ mdp4_stat.wait4vsync0++;
+
+ *vtime = ktime_to_ns(vctrl->vsync_time);
+}
+
+static void mdp4_mddi_wait4dmap(int cndx)
+{
+ struct vsycn_ctrl *vctrl;
+
+ if (cndx >= MAX_CONTROLLER) {
+ pr_err("%s: out or range: cndx=%d\n", __func__, cndx);
+ return;
+ }
+
+ vctrl = &vsync_ctrl_db[cndx];
+
+ if (atomic_read(&vctrl->suspend) > 0)
+ return;
+
+ wait_for_completion(&vctrl->dmap_comp);
+}
+
+static void mdp4_mddi_wait4ov(int cndx)
+{
+ struct vsycn_ctrl *vctrl;
+
+ if (cndx >= MAX_CONTROLLER) {
+ pr_err("%s: out or range: cndx=%d\n", __func__, cndx);
+ return;
+ }
+
+ vctrl = &vsync_ctrl_db[cndx];
+
+ if (atomic_read(&vctrl->suspend) > 0)
+ return;
+
+ wait_for_completion(&vctrl->ov_comp);
+}
+
+/*
+ * primary_rdptr_isr:
+ * called from interrupt context
+ */
+static void primary_rdptr_isr(int cndx)
+{
+ struct vsycn_ctrl *vctrl;
+
+ vctrl = &vsync_ctrl_db[cndx];
+ pr_debug("%s: ISR, cpu=%d\n", __func__, smp_processor_id());
+ vctrl->rdptr_intr_tot++;
+ vctrl->vsync_time = ktime_get();
+
+ spin_lock(&vctrl->spin_lock);
+
+ if (vctrl->uevent)
+ schedule_work(&vctrl->vsync_work);
+
+ if (vctrl->wait_vsync_cnt) {
+ complete(&vctrl->vsync_comp);
+ vctrl->wait_vsync_cnt = 0;
+ }
+
+ if (vctrl->expire_tick) {
+ vctrl->expire_tick--;
+ if (vctrl->expire_tick == 0)
+ schedule_work(&vctrl->clk_work);
+ }
+ spin_unlock(&vctrl->spin_lock);
+}
+
+void mdp4_dmap_done_mddi(int cndx)
+{
+ struct vsycn_ctrl *vctrl;
+ struct mdp4_overlay_pipe *pipe;
+ int diff;
+
+ vctrl = &vsync_ctrl_db[cndx];
+ pipe = vctrl->base_pipe;
+
+ /* blt enabled */
+ spin_lock(&vctrl->spin_lock);
+ vsync_irq_disable(INTR_DMA_P_DONE, MDP_DMAP_TERM);
+ vctrl->dmap_done++;
+ diff = vctrl->ov_done - vctrl->dmap_done;
+ pr_debug("%s: ov_koff=%d ov_done=%d dmap_koff=%d dmap_done=%d cpu=%d\n",
+ __func__, vctrl->ov_koff, vctrl->ov_done, vctrl->dmap_koff,
+ vctrl->dmap_done, smp_processor_id());
+ complete_all(&vctrl->dmap_comp);
+ if (diff <= 0) {
+ if (vctrl->blt_wait)
+ vctrl->blt_wait = 0;
+ spin_unlock(&vctrl->spin_lock);
+ return;
+ }
+
+ /* kick dmap */
+ mdp4_mddi_blt_dmap_update(pipe);
+ pipe->dmap_cnt++;
+ mdp4_stat.kickoff_dmap++;
+ vctrl->dmap_koff++;
+ vsync_irq_enable(INTR_DMA_P_DONE, MDP_DMAP_TERM);
+ outpdw(MDP_BASE + 0x000c, 0); /* kickoff dmap engine */
+ mb(); /* make sure kickoff executed */
+ spin_unlock(&vctrl->spin_lock);
+}
+
+/*
+ * mdp4_overlay0_done_mddi: called from isr
+ */
+void mdp4_overlay0_done_mddi(int cndx)
+{
+ struct vsycn_ctrl *vctrl;
+ struct mdp4_overlay_pipe *pipe;
+ int diff;
+
+ vctrl = &vsync_ctrl_db[cndx];
+ pipe = vctrl->base_pipe;
+
+ spin_lock(&vctrl->spin_lock);
+ vsync_irq_disable(INTR_OVERLAY0_DONE, MDP_OVERLAY0_TERM);
+ vctrl->ov_done++;
+ complete_all(&vctrl->ov_comp);
+ diff = vctrl->ov_done - vctrl->dmap_done;
+
+ pr_debug("%s: ov_koff=%d ov_done=%d dmap_koff=%d dmap_done=%d cpu=%d\n",
+ __func__, vctrl->ov_koff, vctrl->ov_done, vctrl->dmap_koff,
+ vctrl->dmap_done, smp_processor_id());
+
+ if (pipe->ov_blt_addr == 0) {
+ /* blt disabled */
+ spin_unlock(&vctrl->spin_lock);
+ return;
+ }
+
+ if (diff > 1) {
+ /*
+ * two overlay_done and none dmap_done yet
+ * let dmap_done kickoff dmap
+ * and put pipe_commit to wait
+ */
+ vctrl->blt_wait = 1;
+ pr_debug("%s: blt_wait set\n", __func__);
+ spin_unlock(&vctrl->spin_lock);
+ return;
+ }
+ mdp4_mddi_blt_dmap_update(pipe);
+ pipe->dmap_cnt++;
+ mdp4_stat.kickoff_dmap++;
+ vctrl->dmap_koff++;
+ vsync_irq_enable(INTR_DMA_P_DONE, MDP_DMAP_TERM);
+ outpdw(MDP_BASE + 0x000c, 0); /* kickoff dmap engine */
+ mb(); /* make sure kickoff executed */
+ spin_unlock(&vctrl->spin_lock);
+}
+
+static void clk_ctrl_work(struct work_struct *work)
+{
+ struct vsycn_ctrl *vctrl =
+ container_of(work, typeof(*vctrl), clk_work);
+ unsigned long flags;
+
+ mutex_lock(&vctrl->update_lock);
+ if (vctrl->clk_control && vctrl->clk_enabled) {
+ pr_debug("%s: SET_CLK_OFF\n", __func__);
+ mdp_clk_ctrl(0);
+ spin_lock_irqsave(&vctrl->spin_lock, flags);
+ vsync_irq_disable(INTR_PRIMARY_RDPTR, MDP_PRIM_RDPTR_TERM);
+ vctrl->clk_enabled = 0;
+ vctrl->clk_control = 0;
+ spin_unlock_irqrestore(&vctrl->spin_lock, flags);
+ }
+ mutex_unlock(&vctrl->update_lock);
+}
+
+static void send_vsync_work(struct work_struct *work)
+{
+ struct vsycn_ctrl *vctrl =
+ container_of(work, typeof(*vctrl), vsync_work);
+ char buf[64];
+ char *envp[2];
+
+ snprintf(buf, sizeof(buf), "VSYNC=%llu",
+ ktime_to_ns(vctrl->vsync_time));
+ envp[0] = buf;
+ envp[1] = NULL;
+ kobject_uevent_env(&vctrl->dev->kobj, KOBJ_CHANGE, envp);
+}
+
+
+void mdp4_mddi_rdptr_init(int cndx)
+{
+ struct vsycn_ctrl *vctrl;
+
+ if (cndx >= MAX_CONTROLLER) {
+ pr_err("%s: out or range: cndx=%d\n", __func__, cndx);
+ return;
+ }
+
+ vctrl = &vsync_ctrl_db[cndx];
+ if (vctrl->inited)
+ return;
+
+ vctrl->inited = 1;
+ vctrl->update_ndx = 0;
+ mutex_init(&vctrl->update_lock);
+ init_completion(&vctrl->ov_comp);
+ init_completion(&vctrl->dmap_comp);
+ init_completion(&vctrl->vsync_comp);
+ spin_lock_init(&vctrl->spin_lock);
+ INIT_WORK(&vctrl->vsync_work, send_vsync_work);
+ INIT_WORK(&vctrl->clk_work, clk_ctrl_work);
+}
+
+void mdp4_primary_rdptr(void)
+{
+ primary_rdptr_isr(0);
+}
+
+void mdp4_overlay_mddi_state_set(int state)
+{
+ unsigned long flag;
+
+ spin_lock_irqsave(&mdp_spin_lock, flag);
+ mddi_state = state;
+ spin_unlock_irqrestore(&mdp_spin_lock, flag);
+}
+
+int mdp4_overlay_mddi_state_get(void)
+{
+ return mddi_state;
+}
+
+static __u32 msm_fb_line_length(__u32 fb_index, __u32 xres, int bpp)
+{
+ /*
+ * The adreno GPU hardware requires that the pitch be aligned to
+ * 32 pixels for color buffers, so for the cases where the GPU
+ * is writing directly to fb0, the framebuffer pitch
+ * also needs to be 32 pixel aligned
+ */
+
+ if (fb_index == 0)
+ return ALIGN(xres, 32) * bpp;
+ else
+ return xres * bpp;
}
void mdp4_mddi_vsync_enable(struct msm_fb_data_type *mfd,
@@ -61,13 +703,6 @@
if ((mfd->use_mdp_vsync) && (mfd->ibuf.vsync_enable) &&
(mfd->panel_info.lcd.vsync_enable)) {
- if (mdp_hw_revision < MDP4_REVISION_V2_1) {
- /* need dmas dmap switch */
- if (which == 0 && dmap_vsync_enable == 0 &&
- mfd->panel_info.lcd.rev < 2) /* dma_p */
- return;
- }
-
if (vsync_start_y_adjust <= pipe->dst_y)
start_y = pipe->dst_y - vsync_start_y_adjust;
else
@@ -88,633 +723,337 @@
}
}
-#define WHOLESCREEN
+void mdp4_mddi_base_swap(int cndx, struct mdp4_overlay_pipe *pipe)
+{
+ struct vsycn_ctrl *vctrl;
-void mdp4_overlay_update_lcd(struct msm_fb_data_type *mfd)
+ if (cndx >= MAX_CONTROLLER) {
+ pr_err("%s: out or range: cndx=%d\n", __func__, cndx);
+ return;
+ }
+
+ vctrl = &vsync_ctrl_db[cndx];
+ vctrl->base_pipe = pipe;
+}
+
+static void mdp4_overlay_setup_pipe_addr(struct msm_fb_data_type *mfd,
+ struct mdp4_overlay_pipe *pipe)
{
MDPIBUF *iBuf = &mfd->ibuf;
+ struct fb_info *fbi;
+ int bpp;
uint8 *src;
+
+ /* whole screen for base layer */
+ src = (uint8 *) iBuf->buf;
+ fbi = mfd->fbi;
+
+ if (pipe->is_3d) {
+ bpp = fbi->var.bits_per_pixel / 8;
+ pipe->src_height = pipe->src_height_3d;
+ pipe->src_width = pipe->src_width_3d;
+ pipe->src_h = pipe->src_height_3d;
+ pipe->src_w = pipe->src_width_3d;
+ pipe->dst_h = pipe->src_height_3d;
+ pipe->dst_w = pipe->src_width_3d;
+ pipe->srcp0_ystride = msm_fb_line_length(0,
+ pipe->src_width, bpp);
+ } else {
+ /* 2D */
+ pipe->src_height = fbi->var.yres;
+ pipe->src_width = fbi->var.xres;
+ pipe->src_h = fbi->var.yres;
+ pipe->src_w = fbi->var.xres;
+ pipe->dst_h = fbi->var.yres;
+ pipe->dst_w = fbi->var.xres;
+ pipe->srcp0_ystride = fbi->fix.line_length;
+ }
+ pipe->src_y = 0;
+ pipe->src_x = 0;
+ pipe->dst_y = 0;
+ pipe->dst_x = 0;
+ pipe->srcp0_addr = (uint32)src;
+}
+
+void mdp4_overlay_update_mddi(struct msm_fb_data_type *mfd)
+{
int ptype;
uint32 mddi_ld_param;
uint16 mddi_vdo_packet_reg;
struct mdp4_overlay_pipe *pipe;
+ uint32 data;
int ret;
+ int cndx = 0;
+ struct vsycn_ctrl *vctrl;
if (mfd->key != MFD_KEY)
return;
- mddi_mfd = mfd; /* keep it */
+ vctrl = &vsync_ctrl_db[cndx];
- /* MDP cmd block enable */
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-
- if (mddi_pipe == NULL) {
+ if (vctrl->base_pipe == NULL) {
ptype = mdp4_overlay_format2type(mfd->fb_imgType);
+
if (ptype < 0)
- printk(KERN_INFO "%s: format2type failed\n", __func__);
+ pr_err("%s: format2type failed\n", __func__);
+
pipe = mdp4_overlay_pipe_alloc(ptype, MDP4_MIXER0);
- if (pipe == NULL)
- printk(KERN_INFO "%s: pipe_alloc failed\n", __func__);
+ if (pipe == NULL) {
+ pr_err("%s: pipe_alloc failed\n", __func__);
+ return;
+ }
pipe->pipe_used++;
+ pipe->mixer_stage = MDP4_MIXER_STAGE_BASE;
pipe->mixer_num = MDP4_MIXER0;
pipe->src_format = mfd->fb_imgType;
mdp4_overlay_panel_mode(pipe->mixer_num, MDP4_PANEL_MDDI);
ret = mdp4_overlay_format2pipe(pipe);
if (ret < 0)
- printk(KERN_INFO "%s: format2type failed\n", __func__);
+ pr_err("%s: format2type failed\n", __func__);
- mddi_pipe = pipe; /* keep it */
- mddi_ld_param = 0;
- mddi_vdo_packet_reg = mfd->panel_info.mddi.vdopkt;
-
- if (mdp_hw_revision == MDP4_REVISION_V2_1) {
- uint32 data;
-
- data = inpdw(MDP_BASE + 0x0028);
- data &= ~0x0300; /* bit 8, 9, MASTER4 */
- if (mfd->fbi->var.xres == 540) /* qHD, 540x960 */
- data |= 0x0200;
- else
- data |= 0x0100;
-
- MDP_OUTP(MDP_BASE + 0x00028, data);
- }
-
- if (mfd->panel_info.type == MDDI_PANEL) {
- if (mfd->panel_info.pdest == DISPLAY_1)
- mddi_ld_param = 0;
- else
- mddi_ld_param = 1;
- } else {
- mddi_ld_param = 2;
- }
-
- MDP_OUTP(MDP_BASE + 0x00090, mddi_ld_param);
-
- if (mfd->panel_info.bpp == 24)
- MDP_OUTP(MDP_BASE + 0x00094,
- (MDDI_VDO_PACKET_DESC_24 << 16) | mddi_vdo_packet_reg);
- else if (mfd->panel_info.bpp == 16)
- MDP_OUTP(MDP_BASE + 0x00094,
- (MDDI_VDO_PACKET_DESC_16 << 16) | mddi_vdo_packet_reg);
- else
- MDP_OUTP(MDP_BASE + 0x00094,
- (MDDI_VDO_PACKET_DESC << 16) | mddi_vdo_packet_reg);
-
- MDP_OUTP(MDP_BASE + 0x00098, 0x01);
+ vctrl->base_pipe = pipe; /* keep it */
mdp4_init_writeback_buf(mfd, MDP4_MIXER0);
pipe->ov_blt_addr = 0;
pipe->dma_blt_addr = 0;
} else {
- pipe = mddi_pipe;
+ pipe = vctrl->base_pipe;
}
- /* 0 for dma_p, client_id = 0 */
- MDP_OUTP(MDP_BASE + 0x00090, 0);
+ MDP_OUTP(MDP_BASE + 0x021c, 10); /* read pointer */
+ mddi_ld_param = 0;
+ mddi_vdo_packet_reg = mfd->panel_info.mddi.vdopkt;
- src = (uint8 *) iBuf->buf;
+ if (mdp_hw_revision == MDP4_REVISION_V2_1) {
+ data = inpdw(MDP_BASE + 0x0028);
+ data &= ~0x0300; /* bit 8, 9, MASTER4 */
+ if (mfd->fbi->var.xres == 540) /* qHD, 540x960 */
+ data |= 0x0200;
+ else
+ data |= 0x0100;
-#ifdef WHOLESCREEN
-
- {
- struct fb_info *fbi;
-
- fbi = mfd->fbi;
- pipe->src_height = fbi->var.yres;
- pipe->src_width = fbi->var.xres;
- pipe->src_h = fbi->var.yres;
- pipe->src_w = fbi->var.xres;
- pipe->src_y = 0;
- pipe->src_x = 0;
- pipe->dst_h = fbi->var.yres;
- pipe->dst_w = fbi->var.xres;
- pipe->dst_y = 0;
- pipe->dst_x = 0;
- pipe->srcp0_addr = (uint32)src;
- pipe->srcp0_ystride = fbi->fix.line_length;
+ MDP_OUTP(MDP_BASE + 0x00028, data);
}
-#else
- if (mdp4_overlay_active(MDP4_MIXER0)) {
- struct fb_info *fbi;
-
- fbi = mfd->fbi;
- pipe->src_height = fbi->var.yres;
- pipe->src_width = fbi->var.xres;
- pipe->src_h = fbi->var.yres;
- pipe->src_w = fbi->var.xres;
- pipe->src_y = 0;
- pipe->src_x = 0;
- pipe->dst_h = fbi->var.yres;
- pipe->dst_w = fbi->var.xres;
- pipe->dst_y = 0;
- pipe->dst_x = 0;
- pipe->srcp0_addr = (uint32) src;
- pipe->srcp0_ystride = fbi->fix.line_length;
+ if (mfd->panel_info.type == MDDI_PANEL) {
+ if (mfd->panel_info.pdest == DISPLAY_1)
+ mddi_ld_param = 0;
+ else
+ mddi_ld_param = 1;
} else {
- /* starting input address */
- src += (iBuf->dma_x + iBuf->dma_y * iBuf->ibuf_width)
- * iBuf->bpp;
-
- pipe->src_height = iBuf->dma_h;
- pipe->src_width = iBuf->dma_w;
- pipe->src_h = iBuf->dma_h;
- pipe->src_w = iBuf->dma_w;
- pipe->src_y = 0;
- pipe->src_x = 0;
- pipe->dst_h = iBuf->dma_h;
- pipe->dst_w = iBuf->dma_w;
- pipe->dst_y = iBuf->dma_y;
- pipe->dst_x = iBuf->dma_x;
- pipe->srcp0_addr = (uint32) src;
- pipe->srcp0_ystride = iBuf->ibuf_width * iBuf->bpp;
+ mddi_ld_param = 2;
}
-#endif
- pipe->mixer_stage = MDP4_MIXER_STAGE_BASE;
+ MDP_OUTP(MDP_BASE + 0x00090, mddi_ld_param);
+
+ if (mfd->panel_info.bpp == 24)
+ MDP_OUTP(MDP_BASE + 0x00094,
+ (MDDI_VDO_PACKET_DESC_24 << 16) | mddi_vdo_packet_reg);
+ else if (mfd->panel_info.bpp == 16)
+ MDP_OUTP(MDP_BASE + 0x00094,
+ (MDDI_VDO_PACKET_DESC_16 << 16) | mddi_vdo_packet_reg);
+ else
+ MDP_OUTP(MDP_BASE + 0x00094,
+ (MDDI_VDO_PACKET_DESC << 16) | mddi_vdo_packet_reg);
+
+ MDP_OUTP(MDP_BASE + 0x00098, 0x01);
+
+
+ mdp4_overlay_setup_pipe_addr(mfd, pipe);
mdp4_overlay_rgb_setup(pipe);
- mdp4_mixer_stage_up(pipe, 1);
+ mdp4_overlay_reg_flush(pipe, 1);
+
+ mdp4_mixer_stage_up(pipe, 0);
mdp4_overlayproc_cfg(pipe);
mdp4_overlay_dmap_xy(pipe);
mdp4_overlay_dmap_cfg(mfd, 0);
+
mdp4_mixer_stage_commit(pipe->mixer_num);
- mdp4_mddi_vsync_enable(mfd, pipe, 0);
- /* MDP cmd block disable */
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+ wmb();
}
-int mdp4_mddi_overlay_blt_start(struct msm_fb_data_type *mfd)
+void mdp4_mddi_blt_start(struct msm_fb_data_type *mfd)
{
- unsigned long flag;
-
- pr_debug("%s: blt_end=%d blt_addr=%x pid=%d\n",
- __func__, mddi_pipe->blt_end,
- (int)mddi_pipe->ov_blt_addr, current->pid);
-
- mdp4_allocate_writeback_buf(mfd, MDP4_MIXER0);
-
- if (mfd->ov0_wb_buf->write_addr == 0) {
- pr_info("%s: no blt_base assigned\n", __func__);
- return -EBUSY;
- }
-
- if (mddi_pipe->ov_blt_addr == 0) {
- mdp4_mddi_dma_busy_wait(mfd);
- spin_lock_irqsave(&mdp_spin_lock, flag);
- mddi_pipe->blt_end = 0;
- mddi_pipe->blt_cnt = 0;
- mddi_pipe->ov_cnt = 0;
- mddi_pipe->dmap_cnt = 0;
- mddi_pipe->ov_blt_addr = mfd->ov0_wb_buf->write_addr;
- mddi_pipe->dma_blt_addr = mfd->ov0_wb_buf->write_addr;
- mdp4_stat.blt_mddi++;
- spin_unlock_irqrestore(&mdp_spin_lock, flag);
- return 0;
+ mdp4_mddi_do_blt(mfd, 1);
}
- return -EBUSY;
-}
-
-int mdp4_mddi_overlay_blt_stop(struct msm_fb_data_type *mfd)
+void mdp4_mddi_blt_stop(struct msm_fb_data_type *mfd)
{
- unsigned long flag;
-
- pr_debug("%s: blt_end=%d blt_addr=%x\n",
- __func__, mddi_pipe->blt_end, (int)mddi_pipe->ov_blt_addr);
-
- if ((mddi_pipe->blt_end == 0) && mddi_pipe->ov_blt_addr) {
- spin_lock_irqsave(&mdp_spin_lock, flag);
- mddi_pipe->blt_end = 1; /* mark as end */
- spin_unlock_irqrestore(&mdp_spin_lock, flag);
- return 0;
- }
-
- return -EBUSY;
-}
-
-int mdp4_mddi_overlay_blt_offset(struct msm_fb_data_type *mfd,
- struct msmfb_overlay_blt *req)
-{
- req->offset = 0;
- req->width = mddi_pipe->src_width;
- req->height = mddi_pipe->src_height;
- req->bpp = mddi_pipe->bpp;
-
- return sizeof(*req);
+ mdp4_mddi_do_blt(mfd, 0);
}
void mdp4_mddi_overlay_blt(struct msm_fb_data_type *mfd,
struct msmfb_overlay_blt *req)
{
- if (req->enable)
- mdp4_mddi_overlay_blt_start(mfd);
- else if (req->enable == 0)
- mdp4_mddi_overlay_blt_stop(mfd);
-
+ mdp4_mddi_do_blt(mfd, req->enable);
}
-void mdp4_blt_xy_update(struct mdp4_overlay_pipe *pipe)
+int mdp4_mddi_on(struct platform_device *pdev)
{
- uint32 off, addr, addr2;
- int bpp;
- char *overlay_base;
+ int ret = 0;
+ int cndx = 0;
+ struct msm_fb_data_type *mfd;
+ struct vsycn_ctrl *vctrl;
- if (pipe->ov_blt_addr == 0)
- return;
+ pr_debug("%s+:\n", __func__);
+ mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
-#ifdef BLT_RGB565
- bpp = 2; /* overlay ouput is RGB565 */
-#else
- bpp = 3; /* overlay ouput is RGB888 */
-#endif
- off = 0;
- if (pipe->dmap_cnt & 0x01)
- off = pipe->src_height * pipe->src_width * bpp;
+ vctrl = &vsync_ctrl_db[cndx];
+ vctrl->mfd = mfd;
+ vctrl->dev = mfd->fbi->dev;
- addr = pipe->ov_blt_addr + off;
+ mdp_clk_ctrl(1);
+ mdp4_overlay_update_mddi(mfd);
+ mdp_clk_ctrl(0);
- /* dmap */
- MDP_OUTP(MDP_BASE + 0x90008, addr);
+ mdp4_iommu_attach();
- off = 0;
- if (pipe->ov_cnt & 0x01)
- off = pipe->src_height * pipe->src_width * bpp;
- addr2 = pipe->ov_blt_addr + off;
- /* overlay 0 */
- overlay_base = MDP_BASE + MDP4_OVERLAYPROC0_BASE;/* 0x10000 */
- outpdw(overlay_base + 0x000c, addr2);
- outpdw(overlay_base + 0x001c, addr2);
+ atomic_set(&vctrl->suspend, 0);
+ pr_debug("%s-:\n", __func__);
+
+ return ret;
}
-void mdp4_primary_rdptr(void)
+int mdp4_mddi_off(struct platform_device *pdev)
{
-}
+ int ret = 0;
+ int cndx = 0;
+ struct msm_fb_data_type *mfd;
+ struct vsycn_ctrl *vctrl;
+ struct mdp4_overlay_pipe *pipe;
-/*
- * mdp4_dmap_done_mddi: called from isr
- */
-void mdp4_dma_p_done_mddi(struct mdp_dma_data *dma)
-{
- int diff;
+ pr_debug("%s+:\n", __func__);
- mddi_pipe->dmap_cnt++;
- diff = mddi_pipe->ov_cnt - mddi_pipe->dmap_cnt;
- pr_debug("%s: ov_cnt=%d dmap_cnt=%d\n",
- __func__, mddi_pipe->ov_cnt, mddi_pipe->dmap_cnt);
+ mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
- if (diff <= 0) {
- spin_lock(&mdp_spin_lock);
- dma->dmap_busy = FALSE;
- complete(&dma->dmap_comp);
- spin_unlock(&mdp_spin_lock);
-
- if (mddi_pipe->blt_end) {
- mddi_pipe->blt_end = 0;
- mddi_pipe->ov_blt_addr = 0;
- mddi_pipe->dma_blt_addr = 0;
- pr_debug("%s: END, ov_cnt=%d dmap_cnt=%d\n", __func__,
- mddi_pipe->ov_cnt, mddi_pipe->dmap_cnt);
- mdp_intr_mask &= ~INTR_DMA_P_DONE;
- outp32(MDP_INTR_ENABLE, mdp_intr_mask);
- }
-
- mdp_pipe_ctrl(MDP_OVERLAY0_BLOCK, MDP_BLOCK_POWER_OFF, TRUE);
- mdp_disable_irq_nosync(MDP_DMA2_TERM); /* disable intr */
- return;
+ vctrl = &vsync_ctrl_db[cndx];
+ pipe = vctrl->base_pipe;
+ if (pipe == NULL) {
+ pr_err("%s: NO base pipe\n", __func__);
+ return ret;
}
- spin_lock(&mdp_spin_lock);
- dma->busy = FALSE;
- spin_unlock(&mdp_spin_lock);
- complete(&dma->comp);
- if (busy_wait_cnt)
- busy_wait_cnt--;
+ atomic_set(&vctrl->suspend, 1);
- pr_debug("%s: kickoff dmap\n", __func__);
+ /* sanity check, free pipes besides base layer */
+ mdp4_overlay_unset_mixer(pipe->mixer_num);
+ mdp4_mixer_stage_down(pipe, 1);
+ mdp4_overlay_pipe_free(pipe);
+ vctrl->base_pipe = NULL;
- mdp4_blt_xy_update(mddi_pipe);
- /* kick off dmap */
- outpdw(MDP_BASE + 0x000c, 0x0);
- mdp4_stat.kickoff_dmap++;
- mdp_pipe_ctrl(MDP_OVERLAY0_BLOCK, MDP_BLOCK_POWER_OFF, TRUE);
-}
-
-/*
- * mdp4_overlay0_done_mddi: called from isr
- */
-void mdp4_overlay0_done_mddi(struct mdp_dma_data *dma)
-{
- int diff;
-
- if (mddi_pipe->ov_blt_addr == 0) {
- mdp_pipe_ctrl(MDP_OVERLAY0_BLOCK, MDP_BLOCK_POWER_OFF, TRUE);
- spin_lock(&mdp_spin_lock);
- dma->busy = FALSE;
- spin_unlock(&mdp_spin_lock);
- complete(&dma->comp);
-
- if (busy_wait_cnt)
- busy_wait_cnt--;
- mdp_disable_irq_nosync(MDP_OVERLAY0_TERM);
-
- return;
+ if (vctrl->clk_enabled) {
+ /*
+ * in case of suspend, vsycn_ctrl off is not
+ * received from frame work which left clock on
+ * then, clock need to be turned off here
+ */
+ mdp_clk_ctrl(0);
}
- /* blt enabled */
- if (mddi_pipe->blt_end == 0)
- mddi_pipe->ov_cnt++;
+ vctrl->clk_enabled = 0;
+ vctrl->vsync_enabled = 0;
+ vctrl->clk_control = 0;
+ vctrl->expire_tick = 0;
+ vctrl->uevent = 0;
- pr_debug("%s: ov_cnt=%d dmap_cnt=%d\n",
- __func__, mddi_pipe->ov_cnt, mddi_pipe->dmap_cnt);
+ vsync_irq_disable(INTR_PRIMARY_RDPTR, MDP_PRIM_RDPTR_TERM);
- if (mddi_pipe->blt_cnt == 0) {
- /* first kickoff since blt enabled */
- mdp_intr_mask |= INTR_DMA_P_DONE;
- outp32(MDP_INTR_ENABLE, mdp_intr_mask);
- }
+ pr_debug("%s-:\n", __func__);
- mddi_pipe->blt_cnt++;
-
- diff = mddi_pipe->ov_cnt - mddi_pipe->dmap_cnt;
- if (diff >= 2) {
- mdp_disable_irq_nosync(MDP_OVERLAY0_TERM);
- return;
- }
-
- spin_lock(&mdp_spin_lock);
- dma->busy = FALSE;
- dma->dmap_busy = TRUE;
- spin_unlock(&mdp_spin_lock);
- complete(&dma->comp);
-
- if (busy_wait_cnt)
- busy_wait_cnt--;
-
- pr_debug("%s: kickoff dmap\n", __func__);
-
- mdp4_blt_xy_update(mddi_pipe);
- mdp_enable_irq(MDP_DMA2_TERM); /* enable intr */
- /* kick off dmap */
- outpdw(MDP_BASE + 0x000c, 0x0);
- mdp4_stat.kickoff_dmap++;
- mdp_disable_irq_nosync(MDP_OVERLAY0_TERM);
-}
-
-void mdp4_mddi_overlay_restore(void)
-{
- if (mddi_mfd == NULL)
- return;
-
- pr_debug("%s: resotre, pid=%d\n", __func__, current->pid);
-
- if (mddi_mfd->panel_power_on == 0)
- return;
- if (mddi_mfd && mddi_pipe) {
- mdp4_mddi_dma_busy_wait(mddi_mfd);
- mdp4_overlay_update_lcd(mddi_mfd);
-
- if (mddi_pipe->ov_blt_addr)
- mdp4_mddi_blt_dmap_busy_wait(mddi_mfd);
- mdp4_mddi_overlay_kickoff(mddi_mfd, mddi_pipe);
- mddi_mfd->dma_update_flag = 1;
- }
- if (mdp_hw_revision < MDP4_REVISION_V2_1) /* need dmas dmap switch */
- mdp4_mddi_overlay_dmas_restore();
-}
-
-void mdp4_mddi_blt_dmap_busy_wait(struct msm_fb_data_type *mfd)
-{
- unsigned long flag;
- int need_wait = 0;
-
- spin_lock_irqsave(&mdp_spin_lock, flag);
- if (mfd->dma->dmap_busy == TRUE) {
- INIT_COMPLETION(mfd->dma->dmap_comp);
- need_wait++;
- }
- spin_unlock_irqrestore(&mdp_spin_lock, flag);
-
- if (need_wait) {
- /* wait until DMA finishes the current job */
- wait_for_completion(&mfd->dma->dmap_comp);
- }
-}
-
-/*
- * mdp4_mddi_cmd_dma_busy_wait: check mddi link activity
- * mddi link is a shared resource and it can only be used
- * while it is in idle state.
- * ov_mutex need to be acquired before call this function.
- */
-void mdp4_mddi_dma_busy_wait(struct msm_fb_data_type *mfd)
-{
- unsigned long flag;
- int need_wait = 0;
-
- pr_debug("%s: START, pid=%d\n", __func__, current->pid);
- spin_lock_irqsave(&mdp_spin_lock, flag);
- if (mfd->dma->busy == TRUE) {
- if (busy_wait_cnt == 0)
- INIT_COMPLETION(mfd->dma->comp);
- busy_wait_cnt++;
- need_wait++;
- }
- spin_unlock_irqrestore(&mdp_spin_lock, flag);
-
-
- if (need_wait) {
- /* wait until DMA finishes the current job */
- pr_debug("%s: PENDING, pid=%d\n", __func__, current->pid);
- wait_for_completion(&mfd->dma->comp);
- }
- pr_debug("%s: DONE, pid=%d\n", __func__, current->pid);
-}
-
-void mdp4_mddi_kickoff_video(struct msm_fb_data_type *mfd,
- struct mdp4_overlay_pipe *pipe)
-{
/*
- * a video kickoff may happen before UI kickoff after
- * blt enabled. mdp4_overlay_update_lcd() need
- * to be called before kickoff.
- * vice versa for blt disabled.
+ * footswitch off
+ * this will casue all mdp register
+ * to be reset to default
+ * after footswitch on later
*/
- if (mddi_pipe->ov_blt_addr && mddi_pipe->blt_cnt == 0)
- mdp4_overlay_update_lcd(mfd); /* first time */
- else if (mddi_pipe->ov_blt_addr == 0 && mddi_pipe->blt_cnt) {
- mdp4_overlay_update_lcd(mfd); /* last time */
- mddi_pipe->blt_cnt = 0;
- }
- pr_debug("%s: blt_addr=%d blt_cnt=%d\n",
- __func__, (int)mddi_pipe->ov_blt_addr, mddi_pipe->blt_cnt);
-
- if (mddi_pipe->ov_blt_addr)
- mdp4_mddi_blt_dmap_busy_wait(mddi_mfd);
- mdp4_mddi_overlay_kickoff(mfd, pipe);
+ return ret;
}
-void mdp4_mddi_kickoff_ui(struct msm_fb_data_type *mfd,
- struct mdp4_overlay_pipe *pipe)
+void mdp_mddi_overlay_suspend(struct msm_fb_data_type *mfd)
{
- pr_debug("%s: pid=%d\n", __func__, current->pid);
- mdp4_mddi_overlay_kickoff(mfd, pipe);
-}
+ int cndx = 0;
+ struct vsycn_ctrl *vctrl;
+ struct mdp4_overlay_pipe *pipe;
+ vctrl = &vsync_ctrl_db[cndx];
+ pipe = vctrl->base_pipe;
+ /* dis-engage rgb0 from mixer0 */
+ if (pipe) {
+ if (mfd->ref_cnt == 0) {
+ /* adb stop */
+ if (pipe->pipe_type == OVERLAY_TYPE_BF)
+ mdp4_overlay_borderfill_stage_down(pipe);
-void mdp4_mddi_overlay_kickoff(struct msm_fb_data_type *mfd,
- struct mdp4_overlay_pipe *pipe)
-{
- unsigned long flag;
-
- mdp_enable_irq(MDP_OVERLAY0_TERM);
- spin_lock_irqsave(&mdp_spin_lock, flag);
- mfd->dma->busy = TRUE;
- if (mddi_pipe->ov_blt_addr)
- mfd->dma->dmap_busy = TRUE;
- spin_unlock_irqrestore(&mdp_spin_lock, flag);
- /* start OVERLAY pipe */
- mdp_pipe_kickoff(MDP_OVERLAY0_TERM, mfd);
- mdp4_stat.kickoff_ov0++;
-}
-
-void mdp4_dma_s_update_lcd(struct msm_fb_data_type *mfd,
- struct mdp4_overlay_pipe *pipe)
-{
- MDPIBUF *iBuf = &mfd->ibuf;
- uint32 outBpp = iBuf->bpp;
- uint16 mddi_vdo_packet_reg;
- uint32 dma_s_cfg_reg;
-
- dma_s_cfg_reg = 0;
-
- if (mfd->fb_imgType == MDP_RGBA_8888)
- dma_s_cfg_reg |= DMA_PACK_PATTERN_BGR; /* on purpose */
- else if (mfd->fb_imgType == MDP_BGR_565)
- dma_s_cfg_reg |= DMA_PACK_PATTERN_BGR;
- else
- dma_s_cfg_reg |= DMA_PACK_PATTERN_RGB;
-
- if (outBpp == 4)
- dma_s_cfg_reg |= (1 << 26); /* xRGB8888 */
- else if (outBpp == 2)
- dma_s_cfg_reg |= DMA_IBUF_FORMAT_RGB565;
-
- dma_s_cfg_reg |= DMA_DITHER_EN;
-
- /* MDP cmd block enable */
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
- /* PIXELSIZE */
- MDP_OUTP(MDP_BASE + 0xa0004, (pipe->dst_h << 16 | pipe->dst_w));
- MDP_OUTP(MDP_BASE + 0xa0008, pipe->srcp0_addr); /* ibuf address */
- MDP_OUTP(MDP_BASE + 0xa000c, pipe->srcp0_ystride);/* ystride */
-
- if (mfd->panel_info.bpp == 24) {
- dma_s_cfg_reg |= DMA_DSTC0G_8BITS | /* 666 18BPP */
- DMA_DSTC1B_8BITS | DMA_DSTC2R_8BITS;
- } else if (mfd->panel_info.bpp == 18) {
- dma_s_cfg_reg |= DMA_DSTC0G_6BITS | /* 666 18BPP */
- DMA_DSTC1B_6BITS | DMA_DSTC2R_6BITS;
- } else {
- dma_s_cfg_reg |= DMA_DSTC0G_6BITS | /* 565 16BPP */
- DMA_DSTC1B_5BITS | DMA_DSTC2R_5BITS;
- }
-
- MDP_OUTP(MDP_BASE + 0xa0010, (pipe->dst_y << 16) | pipe->dst_x);
-
- /* 1 for dma_s, client_id = 0 */
- MDP_OUTP(MDP_BASE + 0x00090, 1);
-
- mddi_vdo_packet_reg = mfd->panel_info.mddi.vdopkt;
-
- if (mfd->panel_info.bpp == 24)
- MDP_OUTP(MDP_BASE + 0x00094,
- (MDDI_VDO_PACKET_DESC_24 << 16) | mddi_vdo_packet_reg);
- else if (mfd->panel_info.bpp == 16)
- MDP_OUTP(MDP_BASE + 0x00094,
- (MDDI_VDO_PACKET_DESC_16 << 16) | mddi_vdo_packet_reg);
- else
- MDP_OUTP(MDP_BASE + 0x00094,
- (MDDI_VDO_PACKET_DESC << 16) | mddi_vdo_packet_reg);
-
- MDP_OUTP(MDP_BASE + 0x00098, 0x01);
-
- MDP_OUTP(MDP_BASE + 0xa0000, dma_s_cfg_reg);
-
- mdp4_mddi_vsync_enable(mfd, pipe, 1);
-
- /* MDP cmd block disable */
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
-}
-
-void mdp4_mddi_dma_s_kickoff(struct msm_fb_data_type *mfd,
- struct mdp4_overlay_pipe *pipe)
-{
- mdp_enable_irq(MDP_DMA_S_TERM);
-
- if (mddi_pipe->ov_blt_addr == 0)
- mfd->dma->busy = TRUE;
-
- mfd->ibuf_flushed = TRUE;
- /* start dma_s pipe */
- mdp_pipe_kickoff(MDP_DMA_S_TERM, mfd);
- mdp4_stat.kickoff_dmas++;
-
- /* wait until DMA finishes the current job */
- wait_for_completion(&mfd->dma->comp);
- mdp_disable_irq(MDP_DMA_S_TERM);
-}
-
-void mdp4_mddi_overlay_dmas_restore(void)
-{
- /* mutex held by caller */
- if (mddi_mfd && mddi_pipe) {
- mdp4_mddi_dma_busy_wait(mddi_mfd);
- mdp4_dma_s_update_lcd(mddi_mfd, mddi_pipe);
- mdp4_mddi_dma_s_kickoff(mddi_mfd, mddi_pipe);
- mddi_mfd->dma_update_flag = 1;
+ /* pipe == rgb1 */
+ mdp4_overlay_unset_mixer(pipe->mixer_num);
+ vctrl->base_pipe = NULL;
+ } else {
+ mdp4_mixer_stage_down(pipe, 1);
+ mdp4_overlay_iommu_pipe_free(pipe->pipe_ndx, 1);
+ }
}
}
void mdp4_mddi_overlay(struct msm_fb_data_type *mfd)
{
- mutex_lock(&mfd->dma->ov_mutex);
+ int cndx = 0;
+ struct vsycn_ctrl *vctrl;
+ struct mdp4_overlay_pipe *pipe;
+ unsigned long flags;
+ long long xx;
- if (mfd && mfd->panel_power_on) {
- mdp4_mddi_dma_busy_wait(mfd);
+ vctrl = &vsync_ctrl_db[cndx];
- if (mddi_pipe && mddi_pipe->ov_blt_addr)
- mdp4_mddi_blt_dmap_busy_wait(mfd);
- mdp4_overlay_mdp_perf_upd(mfd, 0);
- mdp4_overlay_update_lcd(mfd);
+ if (!mfd->panel_power_on)
+ return;
- mdp4_overlay_mdp_perf_upd(mfd, 1);
- if (mdp_hw_revision < MDP4_REVISION_V2_1) {
- /* dmas dmap switch */
- if (mdp4_overlay_mixer_play(mddi_pipe->mixer_num)
- == 0) {
- mdp4_dma_s_update_lcd(mfd, mddi_pipe);
- mdp4_mddi_dma_s_kickoff(mfd, mddi_pipe);
- } else
- mdp4_mddi_kickoff_ui(mfd, mddi_pipe);
- } else /* no dams dmap switch */
- mdp4_mddi_kickoff_ui(mfd, mddi_pipe);
-
- /* signal if pan function is waiting for the update completion */
- if (mfd->pan_waiting) {
- mfd->pan_waiting = FALSE;
- complete(&mfd->pan_comp);
- }
+ pipe = vctrl->base_pipe;
+ if (pipe == NULL) {
+ pr_err("%s: NO base pipe\n", __func__);
+ return;
}
+
+ mutex_lock(&vctrl->update_lock);
+ if (!vctrl->clk_enabled) {
+ pr_err("%s: mdp clocks disabled\n", __func__);
+ mutex_unlock(&vctrl->update_lock);
+ return;
+
+ }
+ mutex_unlock(&vctrl->update_lock);
+
+ spin_lock_irqsave(&vctrl->spin_lock, flags);
+ if (vctrl->expire_tick) {
+ /*
+ * in the middle of shutting clocks down
+ * delay to allow pan display to go through
+ */
+ vctrl->expire_tick = VSYNC_EXPIRE_TICK;
+ }
+ spin_unlock_irqrestore(&vctrl->spin_lock, flags);
+
+ if (pipe->mixer_stage == MDP4_MIXER_STAGE_BASE) {
+ mdp4_mddi_vsync_enable(mfd, pipe, 0);
+ mdp4_overlay_setup_pipe_addr(mfd, pipe);
+ mdp4_mddi_pipe_queue(0, pipe);
+ }
+
+ mdp4_overlay_mdp_perf_upd(mfd, 1);
+
+ mutex_lock(&mfd->dma->ov_mutex);
+ mdp4_mddi_pipe_commit();
mutex_unlock(&mfd->dma->ov_mutex);
+ mdp4_mddi_wait4vsync(0, &xx);
+
+ mdp4_overlay_mdp_perf_upd(mfd, 0);
}
int mdp4_mddi_overlay_cursor(struct fb_info *info, struct fb_cursor *cursor)
@@ -722,7 +1061,6 @@
struct msm_fb_data_type *mfd = info->par;
mutex_lock(&mfd->dma->ov_mutex);
if (mfd && mfd->panel_power_on) {
- mdp4_mddi_dma_busy_wait(mfd);
mdp_hw_cursor_update(info, cursor);
}
mutex_unlock(&mfd->dma->ov_mutex);
diff --git a/drivers/video/msm/mdp4_util.c b/drivers/video/msm/mdp4_util.c
index 87921e6..82b4e80 100644
--- a/drivers/video/msm/mdp4_util.c
+++ b/drivers/video/msm/mdp4_util.c
@@ -557,7 +557,7 @@
mdp4_dmap_done_dsi_cmd(0);
#else
else { /* MDDI */
- mdp4_dma_p_done_mddi(dma);
+ mdp4_dmap_done_mddi(0);
mdp_pipe_ctrl(MDP_DMA2_BLOCK,
MDP_BLOCK_POWER_OFF, TRUE);
complete(&dma->comp);
@@ -608,7 +608,7 @@
mdp4_overlay0_done_dsi_cmd(0);
#else
if (panel & MDP4_PANEL_MDDI)
- mdp4_overlay0_done_mddi(dma);
+ mdp4_overlay0_done_mddi(0);
#endif
}
mdp_hw_cursor_done();
diff --git a/drivers/video/msm/mdp_debugfs.c b/drivers/video/msm/mdp_debugfs.c
index 0fad0a7..54f5ef5 100644
--- a/drivers/video/msm/mdp_debugfs.c
+++ b/drivers/video/msm/mdp_debugfs.c
@@ -719,84 +719,6 @@
.write = pmdh_reg_write,
};
-
-
-#if defined(CONFIG_FB_MSM_OVERLAY) && defined(CONFIG_FB_MSM_MDDI)
-static int vsync_reg_open(struct inode *inode, struct file *file)
-{
- /* non-seekable */
- file->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE);
- return 0;
-}
-
-static int vsync_reg_release(struct inode *inode, struct file *file)
-{
- return 0;
-}
-
-static ssize_t vsync_reg_write(
- struct file *file,
- const char __user *buff,
- size_t count,
- loff_t *ppos)
-{
- uint32 enable;
- int cnt;
-
- if (count >= sizeof(debug_buf))
- return -EFAULT;
-
- if (copy_from_user(debug_buf, buff, count))
- return -EFAULT;
-
- debug_buf[count] = 0; /* end of string */
-
- cnt = sscanf(debug_buf, "%x", &enable);
-
- mdp_dmap_vsync_set(enable);
-
- return count;
-}
-
-static ssize_t vsync_reg_read(
- struct file *file,
- char __user *buff,
- size_t count,
- loff_t *ppos)
-{
- char *bp;
- int len = 0;
- int tot = 0;
- int dlen;
-
- if (*ppos)
- return 0; /* the end */
-
- bp = debug_buf;
- dlen = sizeof(debug_buf);
- len = snprintf(bp, dlen, "%x\n", mdp_dmap_vsync_get());
- tot += len;
- bp += len;
- *bp = 0;
- tot++;
-
- if (copy_to_user(buff, debug_buf, tot))
- return -EFAULT;
-
- *ppos += tot; /* increase offset */
-
- return tot;
-}
-
-
-static const struct file_operations vsync_fops = {
- .open = vsync_reg_open,
- .release = vsync_reg_release,
- .read = vsync_reg_read,
- .write = vsync_reg_write,
-};
-#endif
-
static ssize_t emdh_reg_write(
struct file *file,
const char __user *buff,
@@ -1342,15 +1264,6 @@
return -1;
}
-#if defined(CONFIG_FB_MSM_OVERLAY) && defined(CONFIG_FB_MSM_MDDI)
- if (debugfs_create_file("vsync", 0644, dent, 0, &vsync_fops)
- == NULL) {
- printk(KERN_ERR "%s(%d): debugfs_create_file: debug fail\n",
- __FILE__, __LINE__);
- return -1;
- }
-#endif
-
dent = debugfs_create_dir("emdh", NULL);
if (IS_ERR(dent)) {
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_sub.c b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
index 6e332ef..5fdee02 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_sub.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
@@ -920,7 +920,7 @@
u32 i;
u32 found = false;
- for (i = 0; i <= pool->count && !found; i++) {
+ for (i = 1; i <= pool->count && !found; i++) {
if (pool->entries[i].virtual == addr)
found = true;
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 0330dfb..257bcc0 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -187,6 +187,26 @@
#define SDIO_MAX_FUNCS 7
+enum mmc_packed_stop_reasons {
+ EXCEEDS_SEGMENTS = 0,
+ EXCEEDS_SECTORS,
+ WRONG_DATA_DIR,
+ FLUSH_OR_DISCARD,
+ EMPTY_QUEUE,
+ REL_WRITE,
+ THRESHOLD,
+ LARGE_SEC_ALIGN,
+ MAX_REASONS,
+};
+
+struct mmc_wr_pack_stats {
+ u32 *packing_events;
+ u32 pack_stop_reason[MAX_REASONS];
+ spinlock_t lock;
+ bool enabled;
+ bool print_in_read;
+};
+
/* The number of MMC physical partitions. These consist of:
* boot partitions (2), general purpose partitions (4) in MMC v4.4.
*/
@@ -209,6 +229,48 @@
#define MMC_BLK_DATA_AREA_GP (1<<2)
};
+/**
+ * struct mmc_bkops_info - BKOPS data
+ * @dw: Idle time bkops delayed work
+ * @host_suspend_tout_ms: The host controller idle time,
+ * before getting into suspend
+ * @delay_ms: The time to start the BKOPS
+ * delayed work once MMC thread is idle
+ * @poll_for_completion: Poll on BKOPS completion
+ * @cancel_delayed_work: A flag to indicate if the delayed work
+ * should be cancelled
+ * @started_delayed_bkops: A flag to indicate if the delayed
+ * work was scheduled
+ * @sectors_changed: number of sectors written or
+ * discard since the last idle BKOPS were scheduled
+ */
+struct mmc_bkops_info {
+ struct delayed_work dw;
+ unsigned int host_suspend_tout_ms;
+ unsigned int delay_ms;
+/*
+ * A default time for checking the need for non urgent BKOPS once mmcqd
+ * is idle.
+ */
+#define MMC_IDLE_BKOPS_TIME_MS 2000
+ struct work_struct poll_for_completion;
+/* Polling timeout and interval for waiting on non-blocking BKOPs completion */
+#define BKOPS_COMPLETION_POLLING_TIMEOUT_MS 10000 /* in ms */
+#define BKOPS_COMPLETION_POLLING_INTERVAL_MS 1000 /* in ms */
+ bool cancel_delayed_work;
+ bool started_delayed_bkops;
+ unsigned int sectors_changed;
+/*
+ * Since canceling the delayed work might have significant effect on the
+ * performance of small requests we won't queue the delayed work every time
+ * mmcqd thread is idle.
+ * The delayed work for idle BKOPS will be scheduled only after a significant
+ * amount of write or discard data.
+ * 100MB is chosen based on benchmark tests.
+ */
+#define BKOPS_MIN_SECTORS_TO_QUEUE_DELAYED_WORK 204800 /* 100MB */
+};
+
/*
* MMC device
*/
@@ -283,6 +345,9 @@
struct mmc_part part[MMC_NUM_PHY_PARTITION]; /* physical partitions */
unsigned int nr_parts;
+ struct mmc_wr_pack_stats wr_pack_stats; /* packed commands stats*/
+
+ struct mmc_bkops_info bkops_info;
};
/*
@@ -511,5 +576,8 @@
extern void mmc_fixup_device(struct mmc_card *card,
const struct mmc_fixup *table);
+extern struct mmc_wr_pack_stats *mmc_blk_get_packed_statistics(
+ struct mmc_card *card);
+extern void mmc_blk_init_packed_statistics(struct mmc_card *card);
#endif /* LINUX_MMC_CARD_H */
diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
index 3f26a80..2795734 100644
--- a/include/linux/mmc/core.h
+++ b/include/linux/mmc/core.h
@@ -149,6 +149,9 @@
extern int mmc_wait_for_app_cmd(struct mmc_host *, struct mmc_card *,
struct mmc_command *, int);
extern void mmc_start_bkops(struct mmc_card *card, bool from_exception);
+extern void mmc_start_delayed_bkops(struct mmc_card *card);
+extern void mmc_start_idle_time_bkops(struct work_struct *work);
+extern void mmc_bkops_completion_polling(struct work_struct *work);
extern int __mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int, bool);
extern int mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int);
extern int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd);
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 714cc76..9e536be 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -245,6 +245,8 @@
#define MMC_CAP2_PACKED_WR (1 << 11) /* Allow packed write */
#define MMC_CAP2_PACKED_CMD (MMC_CAP2_PACKED_RD | \
MMC_CAP2_PACKED_WR) /* Allow packed commands */
+#define MMC_CAP2_PACKED_WR_CONTROL (1 << 12) /* Allow write packing control */
+
#define MMC_CAP2_SANITIZE (1 << 13) /* Support Sanitize */
#define MMC_CAP2_INIT_BKOPS (1 << 15) /* Need to set BKOPS_EN */
#define MMC_CAP2_POWER_OFF_VCCQ_DURING_SUSPEND (1 << 16)
diff --git a/include/linux/msm_kgsl.h b/include/linux/msm_kgsl.h
index 5e1395e..62b8a73 100644
--- a/include/linux/msm_kgsl.h
+++ b/include/linux/msm_kgsl.h
@@ -2,7 +2,7 @@
#define _MSM_KGSL_H
#define KGSL_VERSION_MAJOR 3
-#define KGSL_VERSION_MINOR 13
+#define KGSL_VERSION_MINOR 14
/*context flags */
#define KGSL_CONTEXT_SAVE_GMEM 0x00000001
@@ -12,6 +12,7 @@
#define KGSL_CONTEXT_PREAMBLE 0x00000010
#define KGSL_CONTEXT_TRASH_STATE 0x00000020
#define KGSL_CONTEXT_PER_CONTEXT_TS 0x00000040
+#define KGSL_CONTEXT_USER_GENERATED_TS 0x00000080
#define KGSL_CONTEXT_INVALID 0xffffffff
@@ -66,6 +67,9 @@
#define KGSL_CLK_MEM_IFACE 0x00000010
#define KGSL_CLK_AXI 0x00000020
+/* Server Side Sync Timeout in milliseconds */
+#define KGSL_SYNCOBJ_SERVER_TIMEOUT 2000
+
/*
* Reset status values for context
*/
diff --git a/include/linux/usb/f_accessory.h b/include/linux/usb/f_accessory.h
index 5b2dcf9..ddb2fd0 100644
--- a/include/linux/usb/f_accessory.h
+++ b/include/linux/usb/f_accessory.h
@@ -36,13 +36,15 @@
#define ACCESSORY_STRING_URI 4
#define ACCESSORY_STRING_SERIAL 5
-/* Control request for retrieving device's protocol version (currently 1)
+/* Control request for retrieving device's protocol version
*
* requestType: USB_DIR_IN | USB_TYPE_VENDOR
* request: ACCESSORY_GET_PROTOCOL
* value: 0
* index: 0
* data version number (16 bits little endian)
+ * 1 for original accessory support
+ * 2 adds device to host audio support
*/
#define ACCESSORY_GET_PROTOCOL 51
@@ -70,6 +72,17 @@
*/
#define ACCESSORY_START 53
+/* Control request for setting the audio mode.
+ *
+ * requestType: USB_DIR_OUT | USB_TYPE_VENDOR
+ * request: ACCESSORY_SET_AUDIO_MODE
+ * value: 0 - no audio
+ * 1 - device to host, 44100 16-bit stereo PCM
+ * index: 0
+ * data none
+ */
+#define ACCESSORY_SET_AUDIO_MODE 58
+
/* ioctls for retrieving strings set by the host */
#define ACCESSORY_GET_STRING_MANUFACTURER _IOW('M', 1, char[256])
#define ACCESSORY_GET_STRING_MODEL _IOW('M', 2, char[256])
@@ -79,5 +92,7 @@
#define ACCESSORY_GET_STRING_SERIAL _IOW('M', 6, char[256])
/* returns 1 if there is a start request pending */
#define ACCESSORY_IS_START_REQUESTED _IO('M', 7)
+/* returns audio mode (set via the ACCESSORY_SET_AUDIO_MODE control request) */
+#define ACCESSORY_GET_AUDIO_MODE _IO('M', 8)
#endif /* __LINUX_USB_F_ACCESSORY_H */
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index 920cf77..d45889c 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -192,9 +192,6 @@
* @mhl_enable: indicates MHL connector or not.
* @disable_reset_on_disconnect: perform USB PHY and LINK reset
* on USB cable disconnection.
- * @enable_dcd: Enable Data Contact Detection circuit. if not set
- * wait for 600msec before proceeding to primary
- * detection.
* @enable_lpm_on_suspend: Enable the USB core to go into Low
* Power Mode, when USB bus is suspended but cable
* is connected.
@@ -216,7 +213,6 @@
unsigned int mpm_otgsessvld_int;
bool mhl_enable;
bool disable_reset_on_disconnect;
- bool enable_dcd;
bool enable_lpm_on_dev_suspend;
bool core_clk_always_on_workaround;
struct msm_bus_scale_pdata *bus_scale_table;
diff --git a/include/media/vcap_v4l2.h b/include/media/vcap_v4l2.h
index b2a538c..dd39124 100644
--- a/include/media/vcap_v4l2.h
+++ b/include/media/vcap_v4l2.h
@@ -41,6 +41,22 @@
#define VCAP_BASE (dev->vcapbase)
#define VCAP_OFFSET(off) (VCAP_BASE + off)
+struct reg_range {
+ u32 min_val;
+ u32 max_val;
+};
+
+#define VCAP_REG_RANGE_1_MIN 0x0
+#define VCAP_REG_RANGE_1_MAX 0x48
+#define VCAP_REG_RANGE_2_MIN 0x100
+#define VCAP_REG_RANGE_2_MAX 0x104
+#define VCAP_REG_RANGE_3_MIN 0x400
+#define VCAP_REG_RANGE_3_MAX 0x7F0
+#define VCAP_REG_RANGE_4_MIN 0x800
+#define VCAP_REG_RANGE_4_MAX 0x8A0
+#define VCAP_REG_RANGE_5_MIN 0xC00
+#define VCAP_REG_RANGE_5_MAX 0xDF0
+
#define VCAP_SW_RESET_REQ (VCAP_BASE + 0x024)
#define VCAP_SW_RESET_STATUS (VCAP_BASE + 0x028)
@@ -128,6 +144,16 @@
struct vcap_client_data *cd;
};
+struct vcap_debugfs_params {
+ atomic_t vc_drop_count;
+ uint32_t vc_timestamp;
+ uint32_t vp_timestamp;
+ uint32_t vp_ewma;/* Exponential moving average */
+ uint32_t clk_rate;
+ uint32_t bw_request;
+ uint32_t reg_addr;
+};
+
struct vcap_dev {
struct v4l2_device v4l2_dev;
@@ -176,6 +202,7 @@
struct nr_param nr_param;
bool nr_update;
+ struct vcap_debugfs_params dbg_p;
};
struct vp_format_data {
diff --git a/include/sound/apr_audio.h b/include/sound/apr_audio.h
index 90872c9..afbe7e0 100644
--- a/include/sound/apr_audio.h
+++ b/include/sound/apr_audio.h
@@ -1170,6 +1170,7 @@
#define MPEG4_MULTI_AAC 0x00010D86
#define US_POINT_EPOS_FORMAT 0x00012310
#define US_RAW_FORMAT 0x0001127C
+#define US_PROX_FORMAT 0x00012721
#define MULTI_CHANNEL_PCM 0x00010C66
#define ASM_ENCDEC_SBCRATE 0x00010C13
diff --git a/include/sound/q6asm.h b/include/sound/q6asm.h
index 32d3aef..9cc0de4 100644
--- a/include/sound/q6asm.h
+++ b/include/sound/q6asm.h
@@ -284,7 +284,8 @@
uint32_t rate, uint32_t channels);
int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac,
- uint32_t rate, uint32_t channels);
+ uint32_t rate, uint32_t channels,
+ char *channel_map);
int q6asm_media_format_block_aac(struct audio_client *ac,
struct asm_aac_cfg *cfg);
diff --git a/include/trace/events/mpdcvs_trace.h b/include/trace/events/mpdcvs_trace.h
new file mode 100644
index 0000000..0db1378
--- /dev/null
+++ b/include/trace/events/mpdcvs_trace.h
@@ -0,0 +1,156 @@
+/* Copyright (c) 2012, Free Software 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.
+ */
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM mpdcvs_trace
+
+#if !defined(_TRACE_MPDCVS_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_MPDCVS_H
+
+#include <linux/tracepoint.h>
+
+DECLARE_EVENT_CLASS(msm_mp,
+
+ TP_PROTO(const char *name, int mp_val),
+
+ TP_ARGS(name, mp_val),
+
+ TP_STRUCT__entry(
+ __string(name, name)
+ __field(int, mp_val)
+ ),
+
+ TP_fast_assign(
+ __assign_str(name, name);
+ __entry->mp_val = mp_val;
+ ),
+
+ TP_printk("ev_name=%s ev_level=%d",
+ __get_str(name),
+ __entry->mp_val)
+);
+
+/* Core function of run_q */
+
+DEFINE_EVENT(msm_mp, msm_mp_runq,
+
+ TP_PROTO(const char *name, int mp_val),
+
+ TP_ARGS(name, mp_val)
+);
+
+DEFINE_EVENT(msm_mp, msm_mp_cpusonline,
+
+ TP_PROTO(const char *name, int mp_val),
+
+ TP_ARGS(name, mp_val)
+);
+
+DEFINE_EVENT(msm_mp, msm_mp_slacktime,
+
+ TP_PROTO(const char *name, int mp_val),
+
+ TP_ARGS(name, mp_val)
+);
+
+DECLARE_EVENT_CLASS(msm_dcvs,
+
+ TP_PROTO(const char *name, const char *cpuid, int val),
+
+ TP_ARGS(name, cpuid, val),
+
+ TP_STRUCT__entry(
+ __string(name, name)
+ __string(cpuid, cpuid)
+ __field(int, val)
+ ),
+
+ TP_fast_assign(
+ __assign_str(name, name);
+ __assign_str(cpuid, cpuid);
+ __entry->val = val;
+ ),
+
+ TP_printk("ev_name=%s d_name=%s ev_level=%d",
+ __get_str(name),
+ __get_str(cpuid),
+ __entry->val)
+);
+
+/* Core function of dcvs */
+
+DEFINE_EVENT(msm_dcvs, msm_dcvs_idle,
+
+ TP_PROTO(const char *name, const char *cpuid, int val),
+
+ TP_ARGS(name, cpuid, val)
+);
+
+DEFINE_EVENT(msm_dcvs, msm_dcvs_iowait,
+
+ TP_PROTO(const char *name, const char *cpuid, int val),
+
+ TP_ARGS(name, cpuid, val)
+);
+
+DEFINE_EVENT(msm_dcvs, msm_dcvs_slack_time,
+
+ TP_PROTO(const char *name, const char *cpuid, int val),
+
+ TP_ARGS(name, cpuid, val)
+);
+
+DECLARE_EVENT_CLASS(msm_dcvs_scm,
+
+ TP_PROTO(unsigned long cpuid, int ev_type, unsigned long param0,
+ unsigned long param1, unsigned long ret0, unsigned long ret1),
+
+ TP_ARGS(cpuid, ev_type, param0, param1, ret0, ret1),
+
+ TP_STRUCT__entry(
+ __field(unsigned long, cpuid)
+ __field(int, ev_type)
+ __field(unsigned long, param0)
+ __field(unsigned long, param1)
+ __field(unsigned long, ret0)
+ __field(unsigned long, ret1)
+ ),
+
+ TP_fast_assign(
+ __entry->cpuid = cpuid;
+ __entry->ev_type = ev_type;
+ __entry->param0 = param0;
+ __entry->param1 = param1;
+ __entry->ret0 = ret0;
+ __entry->ret1 = ret1;
+ ),
+
+ TP_printk("dev=%lu ev_type=%d ev_param0=%lu ev_param1=%lu ev_ret0=%lu ev_ret1=%lu",
+ __entry->cpuid,
+ __entry->ev_type,
+ __entry->param0,
+ __entry->param1,
+ __entry->ret0,
+ __entry->ret1)
+);
+
+DEFINE_EVENT(msm_dcvs_scm, msm_dcvs_scm_event,
+
+ TP_PROTO(unsigned long cpuid, int ev_type, unsigned long param0,
+ unsigned long param1, unsigned long ret0, unsigned long ret1),
+
+ TP_ARGS(cpuid, ev_type, param0, param1, ret0, ret1)
+);
+
+#endif /* _TRACE_MPDCVS_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
diff --git a/kernel/rcutree.c b/kernel/rcutree.c
index d0c5baf..4eec66e 100644
--- a/kernel/rcutree.c
+++ b/kernel/rcutree.c
@@ -295,7 +295,9 @@
static int
cpu_needs_another_gp(struct rcu_state *rsp, struct rcu_data *rdp)
{
- return *rdp->nxttail[RCU_DONE_TAIL] && !rcu_gp_in_progress(rsp);
+ return *rdp->nxttail[RCU_DONE_TAIL +
+ ACCESS_ONCE(rsp->completed) != rdp->completed] &&
+ !rcu_gp_in_progress(rsp);
}
/*
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index 4c655c2..d2f60a0 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -1629,6 +1629,8 @@
$exec_file =~ /^.+\.ihex$/ or
$exec_file =~ /^.+\.hex$/ or
$exec_file =~ /^.+\.HEX$/ or
+ $exec_file =~ /^.+\.dts$/ or
+ $exec_file =~ /^.+\.dtsi$/ or
$exec_file =~ /^.+defconfig$/ or
$exec_file =~ /^Makefile$/ or
$exec_file =~ /^Kconfig$/) &&
diff --git a/sound/soc/codecs/wcd9304.c b/sound/soc/codecs/wcd9304.c
index b303878..e9e950f 100644
--- a/sound/soc/codecs/wcd9304.c
+++ b/sound/soc/codecs/wcd9304.c
@@ -41,6 +41,7 @@
#define ADC_DMIC_SEL_ADC 0
#define ADC_DMIC_SEL_DMIC 1
+#define NUM_AMIC 3
#define NUM_DECIMATORS 4
#define NUM_INTERPOLATORS 3
#define BITS_PER_REG 8
@@ -4860,6 +4861,7 @@
u8 flag = pdata->amic_settings.use_pdata;
u8 i = 0, j = 0;
u8 val_txfe = 0, value = 0;
+ int amic_reg_count = 0;
if (!pdata) {
rc = -ENODEV;
@@ -4905,7 +4907,8 @@
snd_soc_update_bits(codec, SITAR_A_MICB_2_CTL, 0x10,
(pdata->micbias.bias2_cap_mode << 4));
- for (i = 0; i < 6; j++, i += 2) {
+ amic_reg_count = (NUM_AMIC % 2) ? NUM_AMIC + 1 : NUM_AMIC;
+ for (i = 0; i < amic_reg_count; j++, i += 2) {
if (flag & (0x01 << i)) {
value = (leg_mode & (0x01 << i)) ? 0x10 : 0x00;
val_txfe = (txfe_bypass & (0x01 << i)) ? 0x20 : 0x00;
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index deddbe8..5a819c9 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -33,6 +33,9 @@
#include <linux/pm_runtime.h>
#include <linux/kernel.h>
#include <linux/gpio.h>
+#include <linux/irq.h>
+#include <linux/wakelock.h>
+#include <linux/suspend.h>
#include "wcd9310.h"
static int cfilt_adjust_ms = 10;
@@ -340,6 +343,9 @@
*/
struct work_struct hs_correct_plug_work_nogpio;
+ bool gpio_irq_resend;
+ struct wake_lock irq_resend_wlock;
+
#ifdef CONFIG_DEBUG_FS
struct dentry *debugfs_poke;
struct dentry *debugfs_mbhc;
@@ -7352,9 +7358,18 @@
{
int r = IRQ_HANDLED;
struct snd_soc_codec *codec = data;
+ struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
if (unlikely(wcd9xxx_lock_sleep(codec->control_data) == false)) {
pr_warn("%s: failed to hold suspend\n", __func__);
+ /*
+ * Give up this IRQ for now and resend this IRQ so IRQ can be
+ * handled after system resume
+ */
+ TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
+ tabla->gpio_irq_resend = true;
+ TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
+ wake_lock_timeout(&tabla->irq_resend_wlock, HZ);
r = IRQ_NONE;
} else {
tabla_hs_gpio_handler(codec);
@@ -8267,6 +8282,15 @@
goto err_hphr_ocp_irq;
}
wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_HPH_PA_OCPR_FAULT);
+
+ /*
+ * Register suspend lock and notifier to resend edge triggered
+ * gpio IRQs
+ */
+ wake_lock_init(&tabla->irq_resend_wlock, WAKE_LOCK_SUSPEND,
+ "tabla_gpio_irq_resend");
+ tabla->gpio_irq_resend = false;
+
for (i = 0; i < ARRAY_SIZE(tabla_dai); i++) {
switch (tabla_dai[i].id) {
case AIF1_PB:
@@ -8331,6 +8355,9 @@
{
int i;
struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+
+ wake_lock_destroy(&tabla->irq_resend_wlock);
+
wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_SLIMBUS, tabla);
wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
@@ -8380,11 +8407,29 @@
static int tabla_resume(struct device *dev)
{
+ int irq;
struct platform_device *pdev = to_platform_device(dev);
struct tabla_priv *tabla = platform_get_drvdata(pdev);
+
dev_dbg(dev, "%s: system resume tabla %p\n", __func__, tabla);
- if (tabla)
+ if (tabla) {
+ TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
tabla->mbhc_last_resume = jiffies;
+ if (tabla->gpio_irq_resend) {
+ WARN_ON(!tabla->mbhc_cfg.gpio_irq);
+ tabla->gpio_irq_resend = false;
+
+ irq = tabla->mbhc_cfg.gpio_irq;
+ pr_debug("%s: Resending GPIO IRQ %d\n", __func__, irq);
+ irq_set_pending(irq);
+ check_irq_resend(irq_to_desc(irq), irq);
+
+ /* release suspend lock */
+ wake_unlock(&tabla->irq_resend_wlock);
+ }
+ TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
+ }
+
return 0;
}
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index e8bb652..a0a272f 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -778,6 +778,9 @@
struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
u32 rate = taiko->comp_fs[w->shift];
+ pr_debug("%s: %s event %d enabled = %d", __func__, w->name,
+ event, taiko->comp_enabled[w->shift]);
+
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
if (taiko->comp_enabled[w->shift] != 0) {
@@ -3123,7 +3126,7 @@
{"LINEOUT4 DAC", NULL, "RX6 DSM MUX"},
{"SPK PA", NULL, "SPK DAC"},
- {"SPK DAC", NULL, "RX7 MIX1"},
+ {"SPK DAC", NULL, "RX7 MIX2"},
{"RX1 CHAIN", NULL, "RX1 MIX2"},
{"RX2 CHAIN", NULL, "RX2 MIX2"},
@@ -4297,13 +4300,17 @@
taiko_spk_dac_event,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIXER("RX1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("RX2 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("RX7 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+
SND_SOC_DAPM_MIXER_E("RX1 MIX2", TAIKO_A_CDC_CLK_RX_B1_CTL, 0, 0, NULL,
0, taiko_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_MIXER_E("RX2 MIX2", TAIKO_A_CDC_CLK_RX_B1_CTL, 1, 0, NULL,
0, taiko_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMU),
- SND_SOC_DAPM_MIXER_E("RX7 MIX2", TAIKO_A_CDC_CLK_RX_B1_CTL, 2, 0, NULL,
+ SND_SOC_DAPM_MIXER_E("RX3 MIX1", TAIKO_A_CDC_CLK_RX_B1_CTL, 2, 0, NULL,
0, taiko_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_MIXER_E("RX4 MIX1", TAIKO_A_CDC_CLK_RX_B1_CTL, 3, 0, NULL,
@@ -4315,14 +4322,10 @@
SND_SOC_DAPM_MIXER_E("RX6 MIX1", TAIKO_A_CDC_CLK_RX_B1_CTL, 5, 0, NULL,
0, taiko_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMU),
- SND_SOC_DAPM_MIXER_E("RX7 MIX1", TAIKO_A_CDC_CLK_RX_B1_CTL, 6, 0, NULL,
+ SND_SOC_DAPM_MIXER_E("RX7 MIX2", TAIKO_A_CDC_CLK_RX_B1_CTL, 6, 0, NULL,
0, taiko_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMU),
- SND_SOC_DAPM_MIXER("RX1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
- SND_SOC_DAPM_MIXER("RX2 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
- SND_SOC_DAPM_MIXER("RX3 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
-
SND_SOC_DAPM_MUX_E("RX4 DSM MUX", TAIKO_A_CDC_CLK_RX_B1_CTL, 3, 0,
&rx4_dsm_mux, taiko_codec_enable_interpolator,
SND_SOC_DAPM_PRE_PMU),
diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c
index 16a4aaa..dc8d9e6 100644
--- a/sound/soc/msm/msm-dai-fe.c
+++ b/sound/soc/msm/msm-dai-fe.c
@@ -270,9 +270,9 @@
.rates = SNDRV_PCM_RATE_8000_48000,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.channels_min = 1,
- .channels_max = 2,
+ .channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 192000,
},
.capture = {
.stream_name = "SLIMBUS0 Hostless Capture",
@@ -280,9 +280,9 @@
.rates = SNDRV_PCM_RATE_8000_48000,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.channels_min = 1,
- .channels_max = 2,
+ .channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 192000,
},
.ops = &msm_fe_dai_ops,
.name = "SLIMBUS0_HOSTLESS",
diff --git a/sound/soc/msm/msm-lowlatency-pcm-q6.c b/sound/soc/msm/msm-lowlatency-pcm-q6.c
index 129f69f..fcfcb66 100644
--- a/sound/soc/msm/msm-lowlatency-pcm-q6.c
+++ b/sound/soc/msm/msm-lowlatency-pcm-q6.c
@@ -218,8 +218,27 @@
if (prtd->enabled)
return 0;
+ if (!prtd->set_channel_map) {
+ memset(prtd->channel_map, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
+ if (prtd->channel_mode == 1) {
+ prtd->channel_map[0] = PCM_CHANNEL_FL;
+ } else if (prtd->channel_mode == 2) {
+ prtd->channel_map[0] = PCM_CHANNEL_FL;
+ prtd->channel_map[0] = PCM_CHANNEL_FR;
+ } else if (prtd->channel_mode == 6) {
+ prtd->channel_map[0] = PCM_CHANNEL_FC;
+ prtd->channel_map[0] = PCM_CHANNEL_FL;
+ prtd->channel_map[0] = PCM_CHANNEL_FR;
+ prtd->channel_map[0] = PCM_CHANNEL_LB;
+ prtd->channel_map[0] = PCM_CHANNEL_RB;
+ prtd->channel_map[0] = PCM_CHANNEL_LFE;
+ } else {
+ pr_err("%s: ERROR.unsupported num_ch = %u\n", __func__,
+ prtd->channel_mode);
+ }
+ }
ret = q6asm_media_format_block_multi_ch_pcm(prtd->audio_client,
- runtime->rate, runtime->channels);
+ runtime->rate, runtime->channels, prtd->channel_map);
if (ret < 0)
pr_info("%s: CMD Format block failed\n", __func__);
@@ -389,6 +408,7 @@
}
prtd->dsp_cnt = 0;
+ prtd->set_channel_map = false;
runtime->private_data = prtd;
pr_debug("substream->pcm->device = %d\n", substream->pcm->device);
pr_debug("soc_prtd->dai_link->be_id = %d\n", soc_prtd->dai_link->be_id);
diff --git a/sound/soc/msm/msm-multi-ch-pcm-q6.c b/sound/soc/msm/msm-multi-ch-pcm-q6.c
index 5b0759c..7d04f95 100644
--- a/sound/soc/msm/msm-multi-ch-pcm-q6.c
+++ b/sound/soc/msm/msm-multi-ch-pcm-q6.c
@@ -269,9 +269,29 @@
prtd->channel_mode = runtime->channels;
if (prtd->enabled)
return 0;
-
+ pr_debug("prtd->set_channel_map: %d", prtd->set_channel_map);
+ if (!prtd->set_channel_map) {
+ pr_debug("using default channel map");
+ memset(prtd->channel_map, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
+ if (prtd->channel_mode == 1) {
+ prtd->channel_map[0] = PCM_CHANNEL_FL;
+ } else if (prtd->channel_mode == 2) {
+ prtd->channel_map[1] = PCM_CHANNEL_FL;
+ prtd->channel_map[2] = PCM_CHANNEL_FR;
+ } else if (prtd->channel_mode == 6) {
+ prtd->channel_map[0] = PCM_CHANNEL_FC;
+ prtd->channel_map[1] = PCM_CHANNEL_FL;
+ prtd->channel_map[2] = PCM_CHANNEL_FR;
+ prtd->channel_map[3] = PCM_CHANNEL_LB;
+ prtd->channel_map[4] = PCM_CHANNEL_RB;
+ prtd->channel_map[5] = PCM_CHANNEL_LFE;
+ } else {
+ pr_err("%s: ERROR.unsupported num_ch = %u\n", __func__,
+ prtd->channel_mode);
+ }
+ }
ret = q6asm_media_format_block_multi_ch_pcm(prtd->audio_client,
- runtime->rate, runtime->channels);
+ runtime->rate, runtime->channels, prtd->channel_map);
if (ret < 0)
pr_info("%s: CMD Format block failed\n", __func__);
@@ -452,6 +472,7 @@
}
prtd->dsp_cnt = 0;
+ prtd->set_channel_map = false;
runtime->private_data = prtd;
pr_debug("substream->pcm->device = %d\n", substream->pcm->device);
pr_debug("soc_prtd->dai_link->be_id = %d\n", soc_prtd->dai_link->be_id);
@@ -492,6 +513,15 @@
return rc;
}
+void multi_ch_pcm_set_channel_map(char *channel_mapping)
+{
+ pr_debug("%s\n", __func__);
+ if (multi_ch_pcm_audio.prtd) {
+ multi_ch_pcm_audio.prtd->set_channel_map = true;
+ memcpy(multi_ch_pcm_audio.prtd->channel_map, channel_mapping,
+ PCM_FORMAT_MAX_NUM_CHANNEL);
+ }
+}
static int msm_pcm_playback_copy(struct snd_pcm_substream *substream, int a,
snd_pcm_uframes_t hwoff, void __user *buf, snd_pcm_uframes_t frames)
diff --git a/sound/soc/msm/msm-pcm-q6.h b/sound/soc/msm/msm-pcm-q6.h
index f1af99a..2678498 100644
--- a/sound/soc/msm/msm-pcm-q6.h
+++ b/sound/soc/msm/msm-pcm-q6.h
@@ -81,6 +81,8 @@
int periods;
int mmap_flag;
atomic_t pending_buffer;
+ bool set_channel_map;
+ char channel_map[8];
};
struct output_meta_data_st {
diff --git a/sound/soc/msm/msm-pcm-routing.c b/sound/soc/msm/msm-pcm-routing.c
index 4d0caa3..f28d01a 100644
--- a/sound/soc/msm/msm-pcm-routing.c
+++ b/sound/soc/msm/msm-pcm-routing.c
@@ -78,6 +78,7 @@
static const DECLARE_TLV_DB_LINEAR(compressed2_rx_vol_gain, 0,
INT_RX_VOL_MAX_STEPS);
static int msm_route_ec_ref_rx;
+static char channel_mapping[PCM_FORMAT_MAX_NUM_CHANNEL];
/* Equal to Frontend after last of the MULTIMEDIA SESSIONS */
#define MAX_EQ_SESSIONS MSM_FRONTEND_DAI_CS_VOICE
@@ -862,6 +863,27 @@
return 0;
}
+static int msm_routing_get_channel_map_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int i;
+ for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL; i++)
+ ucontrol->value.integer.value[i] = channel_mapping[i];
+ return 0;
+}
+
+static int msm_routing_put_channel_map_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int i;
+
+ for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL; i++)
+ channel_mapping[i] = (char)(ucontrol->value.integer.value[i]);
+ multi_ch_pcm_set_channel_map(channel_mapping);
+
+ return 0;
+}
+
static int msm_routing_set_compressed_vol_mixer(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -1891,6 +1913,12 @@
msm_routing_set_compressed2_vol_mixer, compressed2_rx_vol_gain),
};
+static const struct snd_kcontrol_new multi_ch_channel_map_mixer_controls[] = {
+ SOC_SINGLE_MULTI_EXT("Playback Channel Map", SND_SOC_NOPM, 0, 8,
+ 0, 8, msm_routing_get_channel_map_mixer,
+ msm_routing_put_channel_map_mixer),
+};
+
static const struct snd_kcontrol_new lpa_SRS_trumedia_controls[] = {
{.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "SRS TruMedia",
@@ -2867,6 +2895,10 @@
snd_soc_add_platform_controls(platform,
ec_ref_rx_mixer_controls,
ARRAY_SIZE(ec_ref_rx_mixer_controls));
+
+ snd_soc_add_platform_controls(platform,
+ multi_ch_channel_map_mixer_controls,
+ ARRAY_SIZE(multi_ch_channel_map_mixer_controls));
return 0;
}
diff --git a/sound/soc/msm/msm-pcm-routing.h b/sound/soc/msm/msm-pcm-routing.h
index 6b87475..14f330b 100644
--- a/sound/soc/msm/msm-pcm-routing.h
+++ b/sound/soc/msm/msm-pcm-routing.h
@@ -126,4 +126,6 @@
int compressed_set_volume(unsigned volume);
+void multi_ch_pcm_set_channel_map(char *channel_mapping);
+
#endif /*_MSM_PCM_H*/
diff --git a/sound/soc/msm/qdsp6/q6asm.c b/sound/soc/msm/qdsp6/q6asm.c
index 6865871..0aad217 100644
--- a/sound/soc/msm/qdsp6/q6asm.c
+++ b/sound/soc/msm/qdsp6/q6asm.c
@@ -2317,7 +2317,7 @@
}
int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac,
- uint32_t rate, uint32_t channels)
+ uint32_t rate, uint32_t channels, char *channel_map)
{
struct asm_stream_media_format_update fmt;
u8 *channel_mapping;
@@ -2340,39 +2340,7 @@
channel_mapping =
fmt.write_cfg.multi_ch_pcm_cfg.channel_mapping;
- memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
-
- if (channels == 1) {
- channel_mapping[0] = PCM_CHANNEL_FL;
- } else if (channels == 2) {
- channel_mapping[0] = PCM_CHANNEL_FL;
- channel_mapping[1] = PCM_CHANNEL_FR;
- } else if (channels == 4) {
- channel_mapping[0] = PCM_CHANNEL_FL;
- channel_mapping[1] = PCM_CHANNEL_FR;
- channel_mapping[1] = PCM_CHANNEL_LB;
- channel_mapping[1] = PCM_CHANNEL_RB;
- } else if (channels == 6) {
- channel_mapping[0] = PCM_CHANNEL_FC;
- channel_mapping[1] = PCM_CHANNEL_FL;
- channel_mapping[2] = PCM_CHANNEL_FR;
- channel_mapping[3] = PCM_CHANNEL_LB;
- channel_mapping[4] = PCM_CHANNEL_RB;
- channel_mapping[5] = PCM_CHANNEL_LFE;
- } else if (channels == 8) {
- channel_mapping[0] = PCM_CHANNEL_FC;
- channel_mapping[1] = PCM_CHANNEL_FL;
- channel_mapping[2] = PCM_CHANNEL_FR;
- channel_mapping[3] = PCM_CHANNEL_LB;
- channel_mapping[4] = PCM_CHANNEL_RB;
- channel_mapping[5] = PCM_CHANNEL_LFE;
- channel_mapping[6] = PCM_CHANNEL_FLC;
- channel_mapping[7] = PCM_CHANNEL_FRC;
- } else {
- pr_err("%s: ERROR.unsupported num_ch = %u\n", __func__,
- channels);
- return -EINVAL;
- }
+ memcpy(channel_mapping, channel_map, PCM_FORMAT_MAX_NUM_CHANNEL);
rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
if (rc < 0) {
diff --git a/sound/soc/msm/qdsp6v2/audio_ocmem.c b/sound/soc/msm/qdsp6v2/audio_ocmem.c
index 86a82e2..c046b63 100644
--- a/sound/soc/msm/qdsp6v2/audio_ocmem.c
+++ b/sound/soc/msm/qdsp6v2/audio_ocmem.c
@@ -106,9 +106,13 @@
break;
case OCMEM_ALLOC_GROW:
audio_ocmem_lcl.buf = data;
+ pr_debug("%s: Alloc grow request received buf->addr: 0x%ld\n",
+ __func__,
+ (audio_ocmem_lcl.buf)->addr);
atomic_set(&audio_ocmem_lcl.audio_state, OCMEM_STATE_GROW);
break;
case OCMEM_ALLOC_SHRINK:
+ pr_debug("%s: Alloc shrink request received\n", __func__);
atomic_set(&audio_ocmem_lcl.audio_state, OCMEM_STATE_SHRINK);
break;
default:
@@ -150,11 +154,14 @@
audio_ocmem_lcl.buf = buf;
atomic_set(&audio_ocmem_lcl.audio_exit, 0);
+ atomic_set(&audio_ocmem_lcl.audio_cond, 1);
+ pr_debug("%s: buf->len: %ld\n", __func__, buf->len);
if (!buf->len) {
+ pr_debug("%s: buf.len is 0, waiting for ocmem region\n",
+ __func__);
wait_event_interruptible(audio_ocmem_lcl.audio_wait,
(atomic_read(&audio_ocmem_lcl.audio_cond) == 0) ||
(atomic_read(&audio_ocmem_lcl.audio_exit) == 1));
-
if (atomic_read(&audio_ocmem_lcl.audio_exit)) {
pr_err("%s: audio playback ended while waiting for ocmem\n",
__func__);
@@ -162,6 +169,7 @@
goto fail_cmd;
}
}
+ pr_debug("%s: buf->len: %ld\n", __func__, (audio_ocmem_lcl.buf)->len);
if (audio_ocmem_lcl.lp_memseg_ptr == NULL) {
/* Retrieve low power segments */
ret = core_get_low_power_segments(
@@ -190,19 +198,28 @@
/* vote for ocmem bus bandwidth */
ret = msm_bus_scale_client_update_request(
audio_ocmem_lcl.audio_ocmem_bus_client,
- 0);
+ 1);
if (ret)
pr_err("%s: failed to vote for bus bandwidth\n", __func__);
atomic_set(&audio_ocmem_lcl.audio_state, OCMEM_STATE_MAP_TRANSITION);
+ pr_debug("%s: buf->addr: 0x%ld, len: %ld, audio_state[0x%x]\n",
+ __func__,
+ audio_ocmem_lcl.buf->addr,
+ audio_ocmem_lcl.buf->len,
+ atomic_read(&audio_ocmem_lcl.audio_state));
+
+ atomic_set(&audio_ocmem_lcl.audio_cond, 1);
ret = ocmem_map(cid, audio_ocmem_lcl.buf, &audio_ocmem_lcl.mlist);
if (ret) {
pr_err("%s: ocmem_map failed\n", __func__);
goto fail_cmd;
}
-
+ pr_debug("%s: audio_cond[%d] audio_state[0x%x]\n", __func__,
+ atomic_read(&audio_ocmem_lcl.audio_cond),
+ atomic_read(&audio_ocmem_lcl.audio_state));
while ((atomic_read(&audio_ocmem_lcl.audio_state) !=
OCMEM_STATE_EXIT)) {
@@ -219,6 +236,8 @@
atomic_set(&audio_ocmem_lcl.audio_cond, 1);
break;
case OCMEM_STATE_SHRINK:
+ pr_debug("%s: ocmem shrink request process\n",
+ __func__);
atomic_set(&audio_ocmem_lcl.audio_cond, 1);
ret = ocmem_unmap(cid, audio_ocmem_lcl.buf,
&audio_ocmem_lcl.mlist);
@@ -242,9 +261,11 @@
atomic_read(&audio_ocmem_lcl.audio_state));
goto fail_cmd;
}
-
+ atomic_set(&audio_ocmem_lcl.audio_cond, 1);
break;
case OCMEM_STATE_GROW:
+ pr_debug("%s: ocmem grow request process\n",
+ __func__);
atomic_set(&audio_ocmem_lcl.audio_cond, 1);
ret = ocmem_map(cid, audio_ocmem_lcl.buf,
&audio_ocmem_lcl.mlist);
@@ -260,6 +281,7 @@
atomic_read(&audio_ocmem_lcl.audio_cond) == 0);
atomic_set(&audio_ocmem_lcl.audio_state,
OCMEM_STATE_MAP_COMPL);
+ atomic_set(&audio_ocmem_lcl.audio_cond, 1);
break;
}
}
@@ -280,8 +302,10 @@
{
int ret;
+ pr_debug("%s: disable\n", __func__);
if (atomic_read(&audio_ocmem_lcl.audio_cond))
atomic_set(&audio_ocmem_lcl.audio_cond, 0);
+
pr_debug("%s: audio_cond[0x%x], audio_state[0x%x]\n", __func__,
atomic_read(&audio_ocmem_lcl.audio_cond),
atomic_read(&audio_ocmem_lcl.audio_state));
@@ -309,6 +333,7 @@
atomic_read(&audio_ocmem_lcl.audio_state));
goto fail_cmd;
}
+ atomic_set(&audio_ocmem_lcl.audio_state, OCMEM_STATE_EXIT);
pr_debug("%s: ocmem_free success\n", __func__);
default:
pr_debug("%s: state=%d", __func__,
@@ -316,6 +341,9 @@
break;
}
+ msm_bus_scale_client_update_request(
+ audio_ocmem_lcl.audio_ocmem_bus_client,
+ 0);
return 0;
fail_cmd:
return ret;
@@ -345,6 +373,7 @@
rc = -EINVAL;
}
+ return;
}
/**
* voice_ocmem_process_req() - disable/enable OCMEM during voice call
@@ -441,6 +470,7 @@
rc = -EINVAL;
}
+ return;
}
/**
@@ -484,86 +514,21 @@
static int audio_ocmem_platform_data_populate(struct platform_device *pdev)
{
- int ret;
- struct msm_bus_scale_pdata *audio_ocmem_bus_scale_pdata = NULL;
- struct msm_bus_vectors *audio_ocmem_bus_vectors = NULL;
- struct msm_bus_paths *ocmem_audio_bus_paths = NULL;
- u32 val;
+ struct msm_bus_scale_pdata *audio_ocmem_adata = NULL;
if (!pdev->dev.of_node) {
pr_err("%s: device tree information missing\n", __func__);
return -ENODEV;
}
-
- audio_ocmem_bus_vectors = kzalloc(sizeof(struct msm_bus_vectors),
- GFP_KERNEL);
- if (!audio_ocmem_bus_vectors) {
- dev_err(&pdev->dev, "Failed to allocate memory for platform data\n");
- return -ENOMEM;
+ audio_ocmem_adata = msm_bus_cl_get_pdata(pdev);
+ if (!audio_ocmem_adata) {
+ pr_err("%s: bus device tree allocation failed\n", __func__);
+ return -EINVAL;
}
- ret = of_property_read_u32(pdev->dev.of_node,
- "qcom,msm-ocmem-audio-src-id", &val);
- if (ret) {
- dev_err(&pdev->dev, "%s: qcom,msm-ocmem-audio-src-id missing in DT node\n",
- __func__);
- goto fail1;
- }
- audio_ocmem_bus_vectors->src = val;
- ret = of_property_read_u32(pdev->dev.of_node,
- "qcom,msm-ocmem-audio-dst-id", &val);
- if (ret) {
- dev_err(&pdev->dev, "%s: qcom,msm-ocmem-audio-dst-id missing in DT node\n",
- __func__);
- goto fail1;
- }
- audio_ocmem_bus_vectors->dst = val;
- ret = of_property_read_u32(pdev->dev.of_node,
- "qcom,msm-ocmem-audio-ab", &val);
- if (ret) {
- dev_err(&pdev->dev, "%s: qcom,msm-ocmem-audio-ab missing in DT node\n",
- __func__);
- goto fail1;
- }
- audio_ocmem_bus_vectors->ab = val;
- ret = of_property_read_u32(pdev->dev.of_node,
- "qcom,msm-ocmem-audio-ib", &val);
- if (ret) {
- dev_err(&pdev->dev, "%s: qcom,msm-ocmem-audio-ib missing in DT node\n",
- __func__);
- goto fail1;
- }
- audio_ocmem_bus_vectors->ib = val;
+ dev_set_drvdata(&pdev->dev, audio_ocmem_adata);
- ocmem_audio_bus_paths = kzalloc(sizeof(struct msm_bus_paths),
- GFP_KERNEL);
- if (!ocmem_audio_bus_paths) {
- dev_err(&pdev->dev, "Failed to allocate memory for platform data\n");
- goto fail1;
- }
- ocmem_audio_bus_paths->num_paths = 1;
- ocmem_audio_bus_paths->vectors = audio_ocmem_bus_vectors;
-
- audio_ocmem_bus_scale_pdata =
- kzalloc(sizeof(struct msm_bus_scale_pdata), GFP_KERNEL);
-
- if (!audio_ocmem_bus_scale_pdata) {
- dev_err(&pdev->dev, "Failed to allocate memory for platform data\n");
- goto fail2;
- }
-
- audio_ocmem_bus_scale_pdata->usecase = ocmem_audio_bus_paths;
- audio_ocmem_bus_scale_pdata->num_usecases = 1;
- audio_ocmem_bus_scale_pdata->name = "audio-ocmem";
-
- dev_set_drvdata(&pdev->dev, audio_ocmem_bus_scale_pdata);
- return ret;
-
-fail2:
- kfree(ocmem_audio_bus_paths);
-fail1:
- kfree(audio_ocmem_bus_vectors);
- return ret;
+ return 0;
}
static int ocmem_audio_client_probe(struct platform_device *pdev)
{
@@ -628,9 +593,7 @@
audio_ocmem_bus_scale_pdata = (struct msm_bus_scale_pdata *)
dev_get_drvdata(&pdev->dev);
- kfree(audio_ocmem_bus_scale_pdata->usecase->vectors);
- kfree(audio_ocmem_bus_scale_pdata->usecase);
- kfree(audio_ocmem_bus_scale_pdata);
+ msm_bus_cl_clear_pdata(audio_ocmem_bus_scale_pdata);
ocmem_notifier_unregister(audio_ocmem_lcl.audio_hdl,
&audio_ocmem_client_nb);
return 0;
diff --git a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
index bbd43f7..01a9538 100644
--- a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
@@ -34,6 +34,7 @@
#include "msm-compr-q6-v2.h"
#include "msm-pcm-routing-v2.h"
+#include "audio_ocmem.h"
#define COMPRE_CAPTURE_NUM_PERIODS 16
/* Allocate the worst case frame size for compressed audio */
@@ -440,6 +441,9 @@
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
prtd->pcm_irq_pos = 0;
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ audio_ocmem_process_req(AUDIO, true);
+
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
switch (compr->info.codec_param.codec.id) {
case SND_AUDIOCODEC_AMRWB:
@@ -459,6 +463,9 @@
break;
case SNDRV_PCM_TRIGGER_STOP:
pr_debug("SNDRV_PCM_TRIGGER_STOP\n");
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ audio_ocmem_process_req(AUDIO, false);
+
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
switch (compr->info.codec_param.codec.id) {
case SND_AUDIOCODEC_AMRWB:
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
index a6cdad2..dacd59c 100644
--- a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
@@ -1091,7 +1091,7 @@
SNDRV_PCM_RATE_16000,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.channels_min = 1,
- .channels_max = 2,
+ .channels_max = 8,
.rate_min = 8000,
.rate_max = 48000,
},
@@ -1106,7 +1106,7 @@
SNDRV_PCM_RATE_16000,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.channels_min = 1,
- .channels_max = 2,
+ .channels_max = 8,
.rate_min = 8000,
.rate_max = 48000,
},
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
index 7483bb6..af1e19c 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
@@ -56,7 +56,7 @@
.rate_min = 8000,
.rate_max = 48000,
.channels_min = 1,
- .channels_max = 2,
+ .channels_max = 4,
.buffer_bytes_max = CAPTURE_NUM_PERIODS * CAPTURE_PERIOD_SIZE,
.period_bytes_min = CAPTURE_PERIOD_SIZE,
.period_bytes_max = CAPTURE_PERIOD_SIZE,
@@ -297,7 +297,6 @@
static int msm_pcm_open(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
- struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
struct msm_audio *prtd;
int ret = 0;
@@ -315,36 +314,14 @@
kfree(prtd);
return -ENOMEM;
}
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- runtime->hw = msm_pcm_hardware_playback;
- ret = q6asm_open_write(prtd->audio_client, FORMAT_LINEAR_PCM);
- if (ret < 0) {
- pr_err("%s: pcm out open failed\n", __func__);
- q6asm_audio_client_free(prtd->audio_client);
- kfree(prtd);
- return -ENOMEM;
- }
- }
- /* Capture path */
- if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
- runtime->hw = msm_pcm_hardware_capture;
- ret = q6asm_open_read(prtd->audio_client, FORMAT_LINEAR_PCM);
- if (ret < 0) {
- pr_err("%s: pcm in open failed\n", __func__);
- q6asm_audio_client_free(prtd->audio_client);
- kfree(prtd);
- return -ENOMEM;
- }
- }
-
- pr_debug("%s: session ID %d\n", __func__, prtd->audio_client->session);
-
- prtd->session_id = prtd->audio_client->session;
- msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
- prtd->session_id, substream->stream);
-
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- prtd->cmd_ack = 1;
+ runtime->hw = msm_pcm_hardware_playback;
+ else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ runtime->hw = msm_pcm_hardware_capture;
+ else {
+ pr_err("Invalid Stream type %d\n", substream->stream);
+ return -EINVAL;
+ }
ret = snd_pcm_hw_constraint_list(runtime, 0,
SNDRV_PCM_HW_PARAM_RATE,
@@ -530,12 +507,15 @@
int dir = OUT;
pr_debug("%s\n", __func__);
- q6asm_cmd(prtd->audio_client, CMD_CLOSE);
- q6asm_audio_client_buf_free_contiguous(dir,
+ if (prtd->audio_client) {
+ q6asm_cmd(prtd->audio_client, CMD_CLOSE);
+ q6asm_audio_client_buf_free_contiguous(dir,
prtd->audio_client);
+ q6asm_audio_client_free(prtd->audio_client);
+ }
+
msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id,
- SNDRV_PCM_STREAM_CAPTURE);
- q6asm_audio_client_free(prtd->audio_client);
+ SNDRV_PCM_STREAM_CAPTURE);
kfree(prtd);
return 0;
@@ -617,13 +597,43 @@
struct snd_pcm_runtime *runtime = substream->runtime;
struct msm_audio *prtd = runtime->private_data;
struct snd_dma_buffer *dma_buf = &substream->dma_buffer;
+ struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
struct audio_buffer *buf;
int dir, ret;
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
dir = IN;
- else
+ pr_debug("%s Opening %d-ch PCM Write stream\n",
+ __func__, params_channels(params));
+
+ ret = q6asm_open_write(prtd->audio_client, FORMAT_LINEAR_PCM);
+ if (ret < 0) {
+ pr_err("%s: pcm out open failed\n", __func__);
+ q6asm_audio_client_free(prtd->audio_client);
+ kfree(prtd);
+ return -ENOMEM;
+ }
+ } else {
dir = OUT;
+ pr_debug("%s Opening %d-ch PCM read stream\n",
+ __func__, params_channels(params));
+ ret = q6asm_open_read(prtd->audio_client, FORMAT_LINEAR_PCM);
+ if (ret < 0) {
+ pr_err("%s: pcm in open failed\n", __func__);
+ q6asm_audio_client_free(prtd->audio_client);
+ prtd->audio_client = NULL;
+ return -ENOMEM;
+ }
+ }
+
+ pr_debug("%s: session ID %d\n", __func__, prtd->audio_client->session);
+ prtd->session_id = prtd->audio_client->session;
+ msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
+ prtd->session_id, substream->stream);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ prtd->cmd_ack = 1;
+
pr_debug("%s: before buf alloc\n", __func__);
ret = q6asm_audio_client_buf_alloc_contiguous(dir,
prtd->audio_client,
diff --git a/sound/soc/msm/qdsp6v2/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c
index 62257b4..0466eb6 100644
--- a/sound/soc/msm/qdsp6v2/q6adm.c
+++ b/sound/soc/msm/qdsp6v2/q6adm.c
@@ -116,8 +116,18 @@
wake_up(&this_adm.wait[index]);
break;
case ADM_CMD_SHARED_MEM_MAP_REGIONS:
- /* Block until memory handle comes back */
- /* via ADM_CMDRSP_SHARED_MEM_MAP_REGIONS */
+ pr_debug("%s: ADM_CMD_SHARED_MEM_MAP_REGIONS\n",
+ __func__);
+ /* Should only come here if there is an APR */
+ /* error or malformed APR packet. Otherwise */
+ /* response will be returned as */
+ /* ADM_CMDRSP_SHARED_MEM_MAP_REGIONS */
+ if (payload[1] != 0) {
+ pr_err("%s: ADM map error, resuming\n",
+ __func__);
+ atomic_set(&this_adm.copp_stat[0], 1);
+ wake_up(&this_adm.wait[index]);
+ }
break;
default:
pr_err("%s: Unknown Cmd: 0x%x\n", __func__,
@@ -247,24 +257,27 @@
get_audproc_cal(acdb_path, &aud_cal);
/* map & cache buffers used */
+ atomic_set(&mem_map_index, acdb_path);
if (((mem_addr_audproc[acdb_path].cal_paddr != aud_cal.cal_paddr) &&
(aud_cal.cal_size > 0)) ||
(aud_cal.cal_size > mem_addr_audproc[acdb_path].cal_size)) {
- atomic_set(&mem_map_index, acdb_path);
if (mem_addr_audproc[acdb_path].cal_paddr != 0)
adm_memory_unmap_regions(port_id,
&mem_addr_audproc[acdb_path].cal_paddr,
&size, 1);
result = adm_memory_map_regions(port_id, &aud_cal.cal_paddr,
- 0, &aud_cal.cal_size, 1);
- if (result < 0)
+ 0, &size, 1);
+ if (result < 0) {
pr_err("ADM audproc mmap did not work! path = %d, addr = 0x%x, size = %d\n",
acdb_path, aud_cal.cal_paddr,
aud_cal.cal_size);
- else
- mem_addr_audproc[acdb_path] = aud_cal;
+ } else {
+ mem_addr_audproc[acdb_path].cal_paddr =
+ aud_cal.cal_paddr;
+ mem_addr_audproc[acdb_path].cal_size = size;
+ }
}
if (!send_adm_cal_block(port_id, &aud_cal))
@@ -278,24 +291,27 @@
get_audvol_cal(acdb_path, &aud_cal);
/* map & cache buffers used */
+ atomic_set(&mem_map_index, (acdb_path + MAX_AUDPROC_TYPES));
if (((mem_addr_audvol[acdb_path].cal_paddr != aud_cal.cal_paddr) &&
(aud_cal.cal_size > 0)) ||
(aud_cal.cal_size > mem_addr_audvol[acdb_path].cal_size)) {
- atomic_set(&mem_map_index, (acdb_path + MAX_AUDPROC_TYPES));
if (mem_addr_audvol[acdb_path].cal_paddr != 0)
adm_memory_unmap_regions(port_id,
&mem_addr_audvol[acdb_path].cal_paddr,
&size, 1);
result = adm_memory_map_regions(port_id, &aud_cal.cal_paddr,
- 0, &aud_cal.cal_size, 1);
- if (result < 0)
+ 0, &size, 1);
+ if (result < 0) {
pr_err("ADM audvol mmap did not work! path = %d, addr = 0x%x, size = %d\n",
acdb_path, aud_cal.cal_paddr,
aud_cal.cal_size);
- else
- mem_addr_audvol[acdb_path] = aud_cal;
+ } else {
+ mem_addr_audvol[acdb_path].cal_paddr =
+ aud_cal.cal_paddr;
+ mem_addr_audvol[acdb_path].cal_size = size;
+ }
}
if (!send_adm_cal_block(port_id, &aud_cal))
@@ -454,6 +470,21 @@
} else if (channel_mode == 2) {
open.dev_channel_mapping[0] = PCM_CHANNEL_FL;
open.dev_channel_mapping[1] = PCM_CHANNEL_FR;
+ } else if (channel_mode == 3) {
+ open.dev_channel_mapping[0] = PCM_CHANNEL_FL;
+ open.dev_channel_mapping[0] = PCM_CHANNEL_FR;
+ open.dev_channel_mapping[1] = PCM_CHANNEL_FC;
+ } else if (channel_mode == 4) {
+ open.dev_channel_mapping[0] = PCM_CHANNEL_FL;
+ open.dev_channel_mapping[1] = PCM_CHANNEL_FR;
+ open.dev_channel_mapping[2] = PCM_CHANNEL_RB;
+ open.dev_channel_mapping[3] = PCM_CHANNEL_LB;
+ } else if (channel_mode == 5) {
+ open.dev_channel_mapping[0] = PCM_CHANNEL_FL;
+ open.dev_channel_mapping[1] = PCM_CHANNEL_FR;
+ open.dev_channel_mapping[2] = PCM_CHANNEL_FC;
+ open.dev_channel_mapping[3] = PCM_CHANNEL_LB;
+ open.dev_channel_mapping[4] = PCM_CHANNEL_RB;
} else if (channel_mode == 6) {
open.dev_channel_mapping[0] = PCM_CHANNEL_FL;
open.dev_channel_mapping[1] = PCM_CHANNEL_FR;
@@ -461,6 +492,15 @@
open.dev_channel_mapping[3] = PCM_CHANNEL_FC;
open.dev_channel_mapping[4] = PCM_CHANNEL_LB;
open.dev_channel_mapping[5] = PCM_CHANNEL_RB;
+ } else if (channel_mode == 8) {
+ open.dev_channel_mapping[0] = PCM_CHANNEL_FL;
+ open.dev_channel_mapping[1] = PCM_CHANNEL_FR;
+ open.dev_channel_mapping[2] = PCM_CHANNEL_LFE;
+ open.dev_channel_mapping[3] = PCM_CHANNEL_FC;
+ open.dev_channel_mapping[4] = PCM_CHANNEL_LB;
+ open.dev_channel_mapping[5] = PCM_CHANNEL_RB;
+ open.dev_channel_mapping[6] = PCM_CHANNEL_FLC;
+ open.dev_channel_mapping[7] = PCM_CHANNEL_FRC;
} else {
pr_err("%s invalid num_chan %d\n", __func__,
channel_mode);
@@ -664,8 +704,8 @@
APR_PKT_VER);
mmap_regions->hdr.pkt_size = cmd_size;
mmap_regions->hdr.src_port = 0;
- mmap_regions->hdr.dest_port = 0;
- mmap_regions->hdr.token = 0;
+ mmap_regions->hdr.dest_port = atomic_read(&this_adm.copp_id[index]);
+ mmap_regions->hdr.token = port_id;
mmap_regions->hdr.opcode = ADM_CMD_SHARED_MEM_MAP_REGIONS;
mmap_regions->mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL & 0x00ff;
mmap_regions->num_regions = bufcnt & 0x00ff;
@@ -733,8 +773,8 @@
APR_PKT_VER);
unmap_regions.hdr.pkt_size = cmd_size;
unmap_regions.hdr.src_port = 0;
- unmap_regions.hdr.dest_port = 0;
- unmap_regions.hdr.token = 0;
+ unmap_regions.hdr.dest_port = atomic_read(&this_adm.copp_id[index]);
+ unmap_regions.hdr.token = port_id;
unmap_regions.hdr.opcode = ADM_CMD_SHARED_MEM_UNMAP_REGIONS;
unmap_regions.mem_map_handle = atomic_read(&mem_map_handles[
atomic_read(&mem_map_index)]);
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index 0dd6faf..072e293 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -1693,7 +1693,7 @@
enc_cfg.bits_per_sample = 16;
enc_cfg.sample_rate = rate;
enc_cfg.is_signed = 1;
- channel_mapping = enc_cfg.channel_mapping; /* ??? PHANI */
+ channel_mapping = enc_cfg.channel_mapping;
memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
@@ -1743,7 +1743,8 @@
enc_cfg.bits_per_sample = 16;
enc_cfg.sample_rate = 0;/*rate;*/
enc_cfg.is_signed = 1;
- channel_mapping = enc_cfg.channel_mapping; /* ??? PHANI */
+ channel_mapping = enc_cfg.channel_mapping;
+
memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
@@ -1778,27 +1779,36 @@
lchannel_mapping[0] = PCM_CHANNEL_FL;
lchannel_mapping[1] = PCM_CHANNEL_FR;
} else if (channels == 3) {
- lchannel_mapping[0] = PCM_CHANNEL_FC;
- lchannel_mapping[1] = PCM_CHANNEL_FL;
- lchannel_mapping[2] = PCM_CHANNEL_FR;
+ lchannel_mapping[0] = PCM_CHANNEL_FL;
+ lchannel_mapping[1] = PCM_CHANNEL_FR;
+ lchannel_mapping[2] = PCM_CHANNEL_FC;
} else if (channels == 4) {
- lchannel_mapping[0] = PCM_CHANNEL_FC;
- lchannel_mapping[1] = PCM_CHANNEL_FL;
- lchannel_mapping[2] = PCM_CHANNEL_FR;
+ lchannel_mapping[0] = PCM_CHANNEL_FL;
+ lchannel_mapping[1] = PCM_CHANNEL_FR;
+ lchannel_mapping[2] = PCM_CHANNEL_RB;
lchannel_mapping[3] = PCM_CHANNEL_LB;
} else if (channels == 5) {
- lchannel_mapping[0] = PCM_CHANNEL_FC;
- lchannel_mapping[1] = PCM_CHANNEL_FL;
- lchannel_mapping[2] = PCM_CHANNEL_FR;
+ lchannel_mapping[0] = PCM_CHANNEL_FL;
+ lchannel_mapping[1] = PCM_CHANNEL_FR;
+ lchannel_mapping[2] = PCM_CHANNEL_FC;
lchannel_mapping[3] = PCM_CHANNEL_LB;
lchannel_mapping[4] = PCM_CHANNEL_RB;
} else if (channels == 6) {
- lchannel_mapping[0] = PCM_CHANNEL_FC;
- lchannel_mapping[1] = PCM_CHANNEL_FL;
- lchannel_mapping[2] = PCM_CHANNEL_FR;
- lchannel_mapping[3] = PCM_CHANNEL_LB;
- lchannel_mapping[4] = PCM_CHANNEL_RB;
- lchannel_mapping[5] = PCM_CHANNEL_LFE;
+ lchannel_mapping[0] = PCM_CHANNEL_FL;
+ lchannel_mapping[1] = PCM_CHANNEL_FR;
+ lchannel_mapping[2] = PCM_CHANNEL_LFE;
+ lchannel_mapping[3] = PCM_CHANNEL_FC;
+ lchannel_mapping[4] = PCM_CHANNEL_LB;
+ lchannel_mapping[5] = PCM_CHANNEL_RB;
+ } else if (channels == 6) {
+ lchannel_mapping[0] = PCM_CHANNEL_FL;
+ lchannel_mapping[1] = PCM_CHANNEL_FR;
+ lchannel_mapping[2] = PCM_CHANNEL_LFE;
+ lchannel_mapping[3] = PCM_CHANNEL_FC;
+ lchannel_mapping[4] = PCM_CHANNEL_LB;
+ lchannel_mapping[5] = PCM_CHANNEL_RB;
+ lchannel_mapping[6] = PCM_CHANNEL_FLC;
+ lchannel_mapping[7] = PCM_CHANNEL_FRC;
} else {
pr_err("%s: ERROR.unsupported num_ch = %u\n",
__func__, channels);