Merge "ASoC: msm8974: Fix the issue accessing memroy after freed"
diff --git a/Documentation/devicetree/bindings/arm/msm/debug-pc-cntr.txt b/Documentation/devicetree/bindings/arm/msm/debug-pc-cntr.txt
deleted file mode 100644
index 01301be..0000000
--- a/Documentation/devicetree/bindings/arm/msm/debug-pc-cntr.txt
+++ /dev/null
@@ -1,18 +0,0 @@
-* MSM PC Debug Counters
-
-MSM PC debug counter reserves 16 registers in the IMEM memory space which
-maintains a count on the state of power collapse on each core. This count
-will be useful to debug the power collapse state on each core.
-
-The required nodes for MSM PC Debug Counters are:
-
-- compatible: "qcom,pc-cntr"
-- reg: physical IMEM address reserved for PC counters
-
-Example:
-
-qcom,pc-cntr@fe800000 {
- compatible = "qcom,pc-cntr";
- reg = <0xfe800664 0x40>;
- };
-
diff --git a/Documentation/devicetree/bindings/arm/msm/mpm_counter.txt b/Documentation/devicetree/bindings/arm/msm/mpm_counter.txt
new file mode 100644
index 0000000..e62b9ec
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/mpm_counter.txt
@@ -0,0 +1,17 @@
+* MSM Timetick counter (mpm-v2)
+
+The MPM provides a timetick that starts when the device is powered up and
+is not reset by any of the boot loaders or the HLOS. The MPM timetick counter
+driver provides an api to get this value.
+
+The required nodes for the MPM timetick counter driver are:
+
+- compatible: "qcom,mpm-counter"
+- reg: Specifies the physical address of the timetick count register.
+
+Example:
+ qcom,mpm-counter@fc4a3000 {
+ compatible = "qcom,mpm-counter";
+ reg = <0xfc4a3000 0x1000>;
+ };
+
diff --git a/Documentation/devicetree/bindings/arm/msm/pm-8x60.txt b/Documentation/devicetree/bindings/arm/msm/pm-8x60.txt
index b429072..a372912 100644
--- a/Documentation/devicetree/bindings/arm/msm/pm-8x60.txt
+++ b/Documentation/devicetree/bindings/arm/msm/pm-8x60.txt
@@ -5,6 +5,9 @@
the kernel to be notified of idle and suspend states and when called, follows
through the set of instructions in putting the application cores to the lowest
power mode possible.
+The PC debug counter reserves 16 registers in the IMEM memory space which maintains
+a count on the state of power collapse on each core. This count will be useful to
+debug the power collapse state on each core.
The required properties for PM-8x60 are:
@@ -12,17 +15,22 @@
The optional properties are:
+- reg: physical IMEM address reserved for PC counters and the size
- qcom,use-sync-timer: Indicates whether the target uses the synchronized QTimer.
- qcom,pc-mode: Indicates the type of power collapse used by the target. The
- valid values for this are:
+ valid values for this are:
0 (Power collapse terminates in TZ; integrated L2 cache controller)
1, (Power collapse doesn't terminate in TZ; external L2 cache controller)
2 (Power collapse terminates in TZ; external L2 cache controller)
+- qcom,saw-turns-off-pll: Version of SAW2.1 or can turn off the HFPLL, when
+ doing power collapse and so the core need to switch to Global PLL before
+ PC.
Example:
-qcom,pm-8x60 {
+qcom,pm-8x60@fe800664 {
compatible = "qcom,pm-8x60";
+ reg = <0xfe800664 0x40>;
qcom,pc-mode = <0>;
qcom,use-sync-timer;
};
diff --git a/Documentation/devicetree/bindings/bluetooth/bluetooth_power.txt b/Documentation/devicetree/bindings/bluetooth/bluetooth_power.txt
new file mode 100644
index 0000000..88d69e0
--- /dev/null
+++ b/Documentation/devicetree/bindings/bluetooth/bluetooth_power.txt
@@ -0,0 +1,16 @@
+* Bluetooth Controller
+Bluetooth controller communicates with the Bluetooth Host using HCI Transport layer.
+HCI Transport layer can be based on UART or USB serial communication protocol.
+
+Required properties:
+ - compatible: Should be "qca,ar3002"
+ - qca,bt-reset-gpio: GPIO pin to bring BT Controller out of reset
+
+Optional properties:
+ None
+
+Example:
+ bt-ar3002 {
+ compatible = "qca,ar3002";
+ qca,bt-reset-gpio = <&pm8941_gpios 34 0>;
+ };
diff --git a/Documentation/devicetree/bindings/coresight/coresight.txt b/Documentation/devicetree/bindings/coresight/coresight.txt
index 9635972..0519aef 100644
--- a/Documentation/devicetree/bindings/coresight/coresight.txt
+++ b/Documentation/devicetree/bindings/coresight/coresight.txt
@@ -12,6 +12,7 @@
- compatible : name of the component used for driver matching
- reg : physical base address and length of the register set(s) of the component
+- reg-names: names corresponding to each reg property value
- coresight-id : unique integer identifier for the component
- coresight-name : unique descriptive name of the component
- coresight-nr-inports : number of input ports on the component
@@ -41,7 +42,9 @@
1. Sinks
tmc_etr: tmc@fc322000 {
compatible = "arm,coresight-tmc";
- reg = <0xfc322000 0x1000>;
+ reg = <0xfc322000 0x1000>,
+ <0xfc37c000 0x3000>;
+ reg-names = "tmc-etr-base", "tmc-etr-bam-base";
coresight-id = <0>;
coresight-name = "coresight-tmc-etr";
@@ -52,6 +55,7 @@
tpiu: tpiu@fc318000 {
compatible = "arm,coresight-tpiu";
reg = <0xfc318000 0x1000>;
+ reg-names = "tpiu-base";
coresight-id = <1>;
coresight-name = "coresight-tpiu";
@@ -62,6 +66,7 @@
funnel_merg: funnel@fc31b000 {
compatible = "arm,coresight-funnel";
reg = <0xfc31b000 0x1000>;
+ reg-names = "funnel-merg-base";
coresight-id = <4>;
coresight-name = "coresight-funnel-merg";
@@ -74,6 +79,7 @@
funnel_in0: funnel@fc319000 {
compatible = "arm,coresight-funnel";
reg = <0xfc319000 0x1000>;
+ reg-names = "funnel-in0-base";
coresight-id = <5>;
coresight-name = "coresight-funnel-in0";
@@ -88,6 +94,7 @@
compatible = "arm,coresight-stm";
reg = <0xfc321000 0x1000>,
<0xfa280000 0x180000>;
+ reg-names = "stm-base", "stm-data-base";
coresight-id = <9>;
coresight-name = "coresight-stm";
@@ -100,6 +107,7 @@
etm0: etm@fc33c000 {
compatible = "arm,coresight-etm";
reg = <0xfc33c000 0x1000>;
+ reg-names = "etm0-base";
coresight-id = <10>;
coresight-name = "coresight-etm0";
diff --git a/Documentation/devicetree/bindings/fb/msm-hdmi-tx.txt b/Documentation/devicetree/bindings/fb/msm-hdmi-tx.txt
index a30d1d6..a2b66f7 100644
--- a/Documentation/devicetree/bindings/fb/msm-hdmi-tx.txt
+++ b/Documentation/devicetree/bindings/fb/msm-hdmi-tx.txt
@@ -43,7 +43,7 @@
- compatible : "msm-hdmi-audio-codec-rx";
Example:
- qcom,hdmi_tx@fd922100 {
+ mdss_hdmi_tx: qcom,hdmi_tx@fd922100 {
cell-index = <0>;
compatible = "qcom,hdmi-tx";
reg = <0xfd922100 0x35C>,
diff --git a/Documentation/devicetree/bindings/gpu/adreno.txt b/Documentation/devicetree/bindings/gpu/adreno.txt
index 2ea9ba9..1e47c02 100644
--- a/Documentation/devicetree/bindings/gpu/adreno.txt
+++ b/Documentation/devicetree/bindings/gpu/adreno.txt
@@ -62,6 +62,7 @@
Optional Properties:
- qcom,initial-powerlevel: This value indicates which qcom,gpu-pwrlevel should be used at start time
and when coming back out of resume
+- qcom,step-pwrlevel: How many qcom,gpu-pwrlevel should be decremented at once
- qcom,idle-timeout: This property represents the time in microseconds for idle timeout.
- qcom,nap-allowed: Boolean. <0> or <1> to disable/enable nap.
- qcom,chipid: If it exists this property is used to replace
diff --git a/Documentation/devicetree/bindings/i2c/sii8334-i2c.txt b/Documentation/devicetree/bindings/i2c/sii8334-i2c.txt
index ed45192..27a2149 100644
--- a/Documentation/devicetree/bindings/i2c/sii8334-i2c.txt
+++ b/Documentation/devicetree/bindings/i2c/sii8334-i2c.txt
@@ -7,6 +7,7 @@
- mhl-pwr-gpio: MHL power gpio required for power rails
- mhl-rst-gpio: MHL reset gpio going into sii8334 for toggling reset pin
- <supply-name>-supply: phandle to the regulator device tree node.
+- qcom,hdmi-tx-map: phandle to the hdmi tx device tree node.
Example:
i2c@f9967000 {
@@ -22,5 +23,6 @@
avcc_12-supply = <&pm8941_l2>;
smps3a-supply = <&pm8941_s3>;
vdda-supply = <&pm8941_l12>;
+ qcom,hdmi-tx-map = <&mdss_hdmi_tx>;
};
};
diff --git a/Documentation/devicetree/bindings/iommu/msm_iommu_v0.txt b/Documentation/devicetree/bindings/iommu/msm_iommu_v0.txt
index ea2d43a..cc1ffc2 100644
--- a/Documentation/devicetree/bindings/iommu/msm_iommu_v0.txt
+++ b/Documentation/devicetree/bindings/iommu/msm_iommu_v0.txt
@@ -7,6 +7,10 @@
- qcom,glb-offset : Offset for the global register base.
Optional properties:
+- interrupts : should contain the performance monitor overflow interrupt number.
+- qcom,iommu-pmu-ngroups: Number of Performance Monitor Unit (PMU) groups.
+- qcom,iommu-pmu-ncounters: Number of PMU counters per group.
+- qcom,iommu-pmu-event-classes: List of event classes supported.
- List of sub nodes, one for each of the translation context banks supported.
Each sub node has the following required properties:
@@ -28,6 +32,11 @@
ranges;
reg = <0xfd890000 0x10000>;
qcom,glb-offset = <0xF000>;
+ interrupts = <0 38 0>;
+ qcom,iommu-pmu-ngroups = <1>;
+ qcom,iommu-pmu-ncounters = <4>;
+ qcom,iommu-pmu-event-classes = <0x08
+ 0x11>;
qcom,iommu-ctx@fd000000 {
reg = <0xfd000000 0x1000>;
diff --git a/Documentation/devicetree/bindings/media/video/msm-cci.txt b/Documentation/devicetree/bindings/media/video/msm-cci.txt
index 6309068..a432fb5 100644
--- a/Documentation/devicetree/bindings/media/video/msm-cci.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-cci.txt
@@ -82,9 +82,6 @@
- qcom,is-vpe : should be enabled if VPE module is required for post processing
of this sensor
- 1 if required, 0 otherwise
-- qcom,led-flash-sd-index : should contain phandle to flash source node if flash
- is supported for this sensor
- - led_flash0, led_flash1
- qcom,mount-angle : should contain the physical mount angle of the sensor on
the target
- 0, 90, 180, 360
@@ -131,7 +128,8 @@
- 1 -> MASTER 1
- qcom,actuator-src : if auto focus is supported by this sensor, this
property should contain phandle of respective actuator node
-
+- qcom,led-flash-src : if LED flash is supported by this sensor, this
+ property should contain phandle of respective LED flash node
* Qualcomm MSM ACTUATOR
Required properties:
@@ -187,10 +185,10 @@
compatible = "qcom,s5k3l1yx";
reg = <0x6e 0x0>;
qcom,slave-id = <0x6e 0x0 0x3121>;
- qcom,led-flash-sd-index = <0>;
qcom,csiphy-sd-index = <2>;
qcom,csid-sd-index = <0>;
qcom,actuator-src = <&actuator0>;
+ qcom,led-flash-src = <&led_flash0>;
qcom,mount-angle = <90>;
qcom,sensor-name = "s5k3l1yx";
cam_vdig-supply = <&pm8941_l3>;
diff --git a/Documentation/devicetree/bindings/media/video/msm-cpp.txt b/Documentation/devicetree/bindings/media/video/msm-cpp.txt
index 5cf0154..9d176d8 100644
--- a/Documentation/devicetree/bindings/media/video/msm-cpp.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-cpp.txt
@@ -7,6 +7,8 @@
- reg : offset and length of the register set for the device
for the cpp operating in compatible mode.
- reg-names : should specify relevant names to each reg property defined.
+ - cpp - has CPP hardware register set.
+ - cpp_vbif - has VBIF core register set used by CPP.
- interrupts : should contain the cpp interrupt.
- interrupt-names : should specify relevant names to each interrupts
property defined.
@@ -18,7 +20,8 @@
cell-index = <0>;
compatible = "qcom,cpp";
reg = <0xfda04000 0x100>;
- reg-names = "cpp";
+ <0xfda40000 0x200>;
+ reg-names = "cpp", "cpp_vbif";
interrupts = <0 49 0>;
interrupt-names = "cpp";
vdd-supply = <&gdsc_vfe>;
diff --git a/Documentation/devicetree/bindings/platform/msm/qpnp-vibrator.txt b/Documentation/devicetree/bindings/platform/msm/qpnp-vibrator.txt
new file mode 100644
index 0000000..87fa8d9
--- /dev/null
+++ b/Documentation/devicetree/bindings/platform/msm/qpnp-vibrator.txt
@@ -0,0 +1,25 @@
+QPNP Vibrator
+
+QPNP (Qualcomm Plug N Play) vibrator is a peripheral on
+Qualcomm PMICs. The PMIC is connected to Host processor
+via SPMI bus.
+
+Required Properties:
+ - status: default status is set to "disabled. Must be "okay"
+ - compatible: must be "qcom,qpnp-vibrator"
+ - label: name which describes the device
+ - reg: address of device
+
+Optional Properties:
+ - qcom,vib-timeout-ms: timeout of vibrator, in ms. Default 15000 ms
+ - qcom,vib-vtg-level-mV: voltage level, in mV. Default 3100 mV
+
+Example:
+ qcom,vib@c000 {
+ status = "okay";
+ compatible = "qcom,qpnp-vibrator";
+ reg = <0xc000 0x100>;
+ label = "vibrator";
+ qcom,vib-timeout-ms = <15000>;
+ qcom,vib-vtg-level-mV = <3100>;
+ };
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
index 232ddec..fed8cb4 100644
--- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -6,6 +6,21 @@
- compatible : "qcom,msm-pcm-dsp"
+ - qcom,msm-pcm-dsp-id : device node id
+
+* msm-pcm-low-latency
+
+Required properties:
+
+ - compatible : "qcom,msm-pcm-dsp"
+
+ - qcom,msm-pcm-dsp-id : device node id
+
+ Optional properties
+
+ - qcom,msm-pcm-low-latency : Flag indicating whether
+ the device node is of type low latency.
+
* msm-pcm-routing
Required properties:
@@ -212,7 +227,14 @@
Example:
qcom,msm-pcm {
- compatible = "qcom,msm-pcm-dsp";
+ compatible = "qcom,msm-pcm-dsp";
+ qcom,msm-pcm-dsp-id = <0>;
+ };
+
+ qcom,msm-pcm-low-latency {
+ compatible = "qcom,msm-pcm-dsp";
+ qcom,msm-pcm-dsp-id = <1>;
+ qcom,msm-pcm-low-latency;
};
qcom,msm-pcm-routing {
diff --git a/Documentation/devicetree/bindings/spi/spi_qsd.txt b/Documentation/devicetree/bindings/spi/spi_qsd.txt
index 939f77b..4b912f3 100644
--- a/Documentation/devicetree/bindings/spi/spi_qsd.txt
+++ b/Documentation/devicetree/bindings/spi/spi_qsd.txt
@@ -1,25 +1,51 @@
Qualcomm Serial Peripheral Interface (SPI)
Required properties:
-- compatible : should be "qcom,spi-qup-v2".
-- reg : offset and length of the QUP register map.
-- interrupts : should contain the QUP core interrupt.
-- spi-max-frequency : specifies maximum SPI clock frequency, Units - Hz.
+- compatible : Should be "qcom,spi-qup-v2".
+- reg : Offset and length of the register regions for the device
+- reg-names : Register region names referenced in reg above.
+ Required register resource entries are:
+ "spi_physical" : Physical address of controller register blocks.
+- interrupts : Interrupt numbers used by this controller
+- interrupt-names : Interrupt resource names referenced in interrupts above.
+ Required interrupt resource entries are:
+ "spi_irq" : QUP-core interrupt.
+- spi-max-frequency : Specifies maximum SPI clock frequency, Units - Hz.
+
+Required alias:
+- The desired bus-number is specified via an alias with the following format
+ 'spi{n}' where n is the bus number.
Optional properties:
-- gpios : specifies the gpio pins to be used for SPI CLK, MISO, MOSI in
+- gpios : Specifies the gpio pins to be used for SPI CLK, MISO, MOSI in
that order.
-- cs-gpios : specifies the gpio pins to be used for chipselects.
+- cs-gpios : Specifies the gpio pins to be used for chipselects.
+- qcom,infinite-mode: When missing or set to zero, QUP uses infinite-mode. When
+ value is non-zero, the value is the number of words in maximum transfer
+ length.
-SPI slave nodes must be children of the SPI master node and contain
+Optional properties which are required for support of BAM-mode:
+- qcom,ver-reg-exists : Boolean. When present, allows driver to verify if HW
+ version support latest features (e.g. BAM) and then enable them. Should be
+ removed for legacy HW.
+- qcom,use-bam : Boolean. When present, enables BAM-mode.
+- qcom,bam-consumer-pipe-index : BAM consumer-pipe index.
+- qcom,bam-producer-pipe-index : BAM producer-pipe index.
+- reg-names : register region names referenced in reg.
+ Required register resource for BAM are:
+ "spi_bam_physical" : Physical address of BAM for this controller.
+- interrupt-names : interrupt resource names referenced in interrupts.
+ Required interrupt resource from BAM are:
+ "spi_bam_irq" : BAM interrupt used by the controller.
+
+Optional SPI slave nodes must be children of the SPI master node and contain
the following properties.
-- reg : (required) chip select address of device.
-- compatible : (required) name of SPI device following generic names
- recommended practice
+- reg: (required) chip-select address of the device.
+- compatible : (required) Name of SPI device following generic names.
- spi-max-frequency : (required) Maximum SPI clocking speed of device in Hz
-- interrupts : (recommended) should contain the SPI slave interrupt number
+- interrupts : (recommended) Should contain the SPI slave interrupt number
encoded depending on the type of the interrupt controller.
-- interrupt-parent : (recommended) the phandle for the interrupt controller
+- interrupt-parent : (recommended) The phandle for the interrupt controller
that services interrupts for this device.
- spi-cpol : (optional) Empty property indicating device requires inverse
clock polarity (CPOL) mode
@@ -29,18 +55,30 @@
chip select active high
Example:
- spi@f9924000 {
- compatible = "qcom,spi-qup-v2";
- reg = <0xf9924000 0x1000>;
- interrupts = <0 96 0>;
- spi-max-frequency = <24000000>;
- #address-cells = <1>;
- #size-cells = <0>;
-
- device@0 {
- compatible = "spidev";
- reg = <0>;
- spi-max-frequency = <5000000>;
- };
+ aliases {
+ spi0 = &spi_0;
};
+ spi_0: spi@f9923000 {
+ compatible = "qcom,spi-qup-v2";
+
+ reg-names = "spi_physical", "spi_bam_physical";
+ reg = <0xf9923000 0x1000>,
+ <0xf9904000 0x10000>;
+ interrupt-names = "spi_irq", "spi_bam_irq";
+ interrupts = <0 95 0>, <0 238 0>;
+
+ spi-max-frequency = <19200000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ gpios = <&msmgpio 3 0>, /* CLK */
+ <&msmgpio 1 0>, /* MISO */
+ <&msmgpio 0 0>; /* MOSI */
+ cs-gpios = <&msmgpio 9 0>;
+
+ qcom,infinite-mode = <0>;
+ qcom,use-bam;
+ qcom,bam-consumer-pipe-index = <12>;
+ qcom,bam-producer-pipe-index = <13>;
+ qcom,ver-reg-exists;
+ };
diff --git a/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi b/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi
index 6ebab2b..1c3cf29 100644
--- a/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi
@@ -41,18 +41,18 @@
qcom,mdss-pan-dsi-mdp-tr = <0x0>;
qcom,mdss-pan-dsi-dma-tr = <0x04>;
qcom,mdss-pan-frame-rate = <60>;
- qcom,panel-phy-regulatorSettings = [03 01 01 00 /* Regualotor settings */
+ qcom,panel-phy-regulatorSettings = [07 09 03 00 /* Regualotor settings */
20 00 01];
- qcom,panel-phy-timingSettings = [69 29 1f 00 55 55
- 19 2a 2a 03 04 00];
- qcom,panel-phy-strengthCtrl = [77 06];
+ qcom,panel-phy-timingSettings = [b0 23 1b 00 94 93
+ 1e 25 15 03 04 00];
+ qcom,panel-phy-strengthCtrl = [ff 06];
qcom,panel-phy-bistCtrl = [00 00 b1 ff /* BIST Ctrl settings */
00 00];
- qcom,panel-phy-laneConfig = [00 c2 45 00 00 00 00 01 75 /* lane0 config */
- 00 c2 45 00 00 00 00 01 75 /* lane1 config */
- 00 c2 45 00 00 00 00 01 75 /* lane2 config */
- 00 c2 45 00 00 00 00 01 75 /* lane3 config */
- 00 02 45 00 00 00 00 01 97]; /* Clk ln config */
+ qcom,panel-phy-laneConfig = [00 00 00 00 00 00 00 01 97 /* lane0 config */
+ 00 00 00 00 05 00 00 01 97 /* lane1 config */
+ 00 00 00 00 0a 00 00 01 97 /* lane2 config */
+ 00 00 00 00 0f 00 00 01 97 /* lane3 config */
+ 00 c0 00 00 00 00 00 01 bb]; /* Clk ln config */
qcom,panel-on-cmds = [23 01 00 00 0a 02 b0 00
23 01 00 00 0a 02 b2 00
diff --git a/arch/arm/boot/dts/msm-iommu-v0.dtsi b/arch/arm/boot/dts/msm-iommu-v0.dtsi
index c6eb1b9..6ddeb68 100644
--- a/arch/arm/boot/dts/msm-iommu-v0.dtsi
+++ b/arch/arm/boot/dts/msm-iommu-v0.dtsi
@@ -17,8 +17,16 @@
#size-cells = <1>;
ranges;
reg = <0xfd000000 0x10000>;
+ interrupts = <0 248 0>;
qcom,glb-offset = <0xF000>;
label = "lpass_iommu";
+ qcom,iommu-pmu-ngroups = <1>;
+ qcom,iommu-pmu-ncounters = <4>;
+ qcom,iommu-pmu-event-classes = <0x08
+ 0x09
+ 0x10
+ 0x12
+ 0x80>;
status = "disabled";
lpass_q6_fw: qcom,iommu-ctx@fd000000 {
@@ -56,8 +64,16 @@
#size-cells = <1>;
ranges;
reg = <0xfd010000 0x10000>;
+ interrupts = <0 252 0>;
qcom,glb-offset = <0xF000>;
label = "copss_iommu";
+ qcom,iommu-pmu-ngroups = <1>;
+ qcom,iommu-pmu-ncounters = <4>;
+ qcom,iommu-pmu-event-classes = <0x08
+ 0x09
+ 0x10
+ 0x12
+ 0x80>;
status = "disabled";
qcom,iommu-ctx@fd010000 {
@@ -123,21 +139,29 @@
#size-cells = <1>;
ranges;
reg = <0xfd860000 0x10000>;
+ interrupts = <0 245 0>;
qcom,glb-offset = <0xF000>;
label = "mdpe_iommu";
+ qcom,iommu-pmu-ngroups = <1>;
+ qcom,iommu-pmu-ncounters = <4>;
+ qcom,iommu-pmu-event-classes = <0x08
+ 0x09
+ 0x10
+ 0x12
+ 0x80>;
status = "disabled";
qcom,iommu-ctx@fd860000 {
reg = <0xfd860000 0x1000>;
interrupts = <0 247 0>;
- qcom,iommu-ctx-mids = <>;
+ qcom,iommu-ctx-mids = <0 1 3>;
label = "mdpe_0";
};
qcom,iommu-ctx@fd861000 {
reg = <0xfd861000 0x1000>;
interrupts = <0 247 0>;
- qcom,iommu-ctx-mids = <>;
+ qcom,iommu-ctx-mids = <2>;
label = "mdpe_1";
};
};
@@ -148,21 +172,29 @@
#size-cells = <1>;
ranges;
reg = <0xfd870000 0x10000>;
+ interrupts = <0 73 0>;
qcom,glb-offset = <0xF000>;
label = "mdps_iommu";
+ qcom,iommu-pmu-ngroups = <1>;
+ qcom,iommu-pmu-ncounters = <4>;
+ qcom,iommu-pmu-event-classes = <0x08
+ 0x09
+ 0x10
+ 0x12
+ 0x80>;
status = "disabled";
qcom,iommu-ctx@fd870000 {
reg = <0xfd870000 0x1000>;
interrupts = <0 247 0>;
- qcom,iommu-ctx-mids = <>;
+ qcom,iommu-ctx-mids = <0>;
label = "mdps_0";
};
qcom,iommu-ctx@fd871000 {
reg = <0xfd871000 0x1000>;
interrupts = <0 247 0>;
- qcom,iommu-ctx-mids = <>;
+ qcom,iommu-ctx-mids = <1>;
label = "mdps_1";
};
};
@@ -173,8 +205,16 @@
#size-cells = <1>;
ranges;
reg = <0xfd880000 0x10000>;
+ interrupts = <0 38 0>;
qcom,glb-offset = <0xF000>;
label = "gfx_iommu";
+ qcom,iommu-pmu-ngroups = <1>;
+ qcom,iommu-pmu-ncounters = <4>;
+ qcom,iommu-pmu-event-classes = <0x08
+ 0x09
+ 0x10
+ 0x12
+ 0x80>;
status = "disabled";
qcom,iommu-ctx@fd880000 {
@@ -207,8 +247,16 @@
#size-cells = <1>;
ranges;
reg = <0xfd890000 0x10000>;
+ interrupts = <0 62 0>;
qcom,glb-offset = <0xF000>;
label = "vfe_iommu";
+ qcom,iommu-pmu-ngroups = <1>;
+ qcom,iommu-pmu-ncounters = <4>;
+ qcom,iommu-pmu-event-classes = <0x08
+ 0x09
+ 0x10
+ 0x12
+ 0x80>;
status = "disabled";
qcom,iommu-ctx@fd890000 {
diff --git a/arch/arm/boot/dts/msm-pm8226.dtsi b/arch/arm/boot/dts/msm-pm8226.dtsi
index 0e06ac5..de23f4c 100644
--- a/arch/arm/boot/dts/msm-pm8226.dtsi
+++ b/arch/arm/boot/dts/msm-pm8226.dtsi
@@ -16,6 +16,180 @@
interrupt-controller;
#interrupt-cells = <3>;
+ qcom,pm8226@0 {
+ spmi-slave-container;
+ reg = <0x0>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ pm8226_gpios: gpios {
+ spmi-dev-container;
+ compatible = "qcom,qpnp-pin";
+ gpio-controller;
+ #gpio-cells = <2>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ label = "pm8226-gpio";
+
+ gpio@c000 {
+ reg = <0xc000 0x100>;
+ qcom,pin-num = <1>;
+ };
+
+ gpio@c100 {
+ reg = <0xc100 0x100>;
+ qcom,pin-num = <2>;
+ };
+
+ gpio@c200 {
+ reg = <0xc200 0x100>;
+ qcom,pin-num = <3>;
+ };
+
+ gpio@c300 {
+ reg = <0xc300 0x100>;
+ qcom,pin-num = <4>;
+ };
+
+ gpio@c400 {
+ reg = <0xc400 0x100>;
+ qcom,pin-num = <5>;
+ };
+
+ gpio@c500 {
+ reg = <0xc500 0x100>;
+ qcom,pin-num = <6>;
+ };
+
+ gpio@c600 {
+ reg = <0xc600 0x100>;
+ qcom,pin-num = <7>;
+ };
+
+ gpio@c700 {
+ reg = <0xc700 0x100>;
+ qcom,pin-num = <8>;
+ };
+ };
+
+ pm8226_mpps: mpps {
+ spmi-dev-container;
+ compatible = "qcom,qpnp-pin";
+ gpio-controller;
+ #gpio-cells = <2>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ label = "pm8226-mpp";
+
+ mpp@a000 {
+ reg = <0xa000 0x100>;
+ qcom,pin-num = <1>;
+ };
+
+ mpp@a100 {
+ reg = <0xa100 0x100>;
+ qcom,pin-num = <2>;
+ };
+
+ mpp@a200 {
+ reg = <0xa200 0x100>;
+ qcom,pin-num = <3>;
+ };
+
+ mpp@a300 {
+ reg = <0xa300 0x100>;
+ qcom,pin-num = <4>;
+ };
+
+ mpp@a400 {
+ reg = <0xa400 0x100>;
+ qcom,pin-num = <5>;
+ };
+
+ mpp@a500 {
+ reg = <0xa500 0x100>;
+ qcom,pin-num = <6>;
+ };
+
+ mpp@a600 {
+ reg = <0xa600 0x100>;
+ qcom,pin-num = <7>;
+ };
+
+ mpp@a700 {
+ reg = <0xa700 0x100>;
+ qcom,pin-num = <8>;
+ };
+ };
+
+ pm8226_vadc: vadc@3100 {
+ compatible = "qcom,qpnp-vadc";
+ reg = <0x3100 0x100>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <0x0 0x31 0x0>;
+ interrupt-names = "eoc-int-en-set";
+ qcom,adc-bit-resolution = <15>;
+ qcom,adc-vdd-reference = <1800>;
+
+ chan@8 {
+ label = "die_temp";
+ reg = <8>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <3>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@9 {
+ label = "ref_625mv";
+ reg = <9>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@a {
+ label = "ref_1250v";
+ reg = <0xa>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+ };
+
+ iadc@3600 {
+ compatible = "qcom,qpnp-iadc";
+ reg = <0x3600 0x100>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <0x0 0x36 0x0>;
+ interrupt-names = "eoc-int-en-set";
+ qcom,adc-bit-resolution = <16>;
+ qcom,adc-vdd-reference = <1800>;
+ qcom,rsense = <1500>;
+
+ chan@0 {
+ label = "internal_rsense";
+ reg = <0>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <1>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+ };
+ };
+
qcom,pm8226@1 {
spmi-slave-container;
reg = <0x1>;
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index 2886038..c1d8664 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -1103,6 +1103,13 @@
status = "disabled";
};
+ qcom,vibrator@c000 {
+ compatible = "qcom,qpnp-vibrator";
+ reg = <0xc000 0x100>;
+ label = "vibrator";
+ status = "disabled";
+ };
+
qcom,leds@d000 {
compatible = "qcom,leds-qpnp";
reg = <0xd000 0x100>;
diff --git a/arch/arm/boot/dts/msm8226-cdp.dts b/arch/arm/boot/dts/msm8226-cdp.dts
new file mode 100644
index 0000000..7263e42
--- /dev/null
+++ b/arch/arm/boot/dts/msm8226-cdp.dts
@@ -0,0 +1,24 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+/include/ "msm8226.dtsi"
+
+/ {
+ model = "Qualcomm MSM 8226 CDP";
+ compatible = "qcom,msm8226-cdp", "qcom,msm8226";
+ qcom,msm-id = <145 1 0>;
+
+ serial@f991f000 {
+ status = "disabled";
+ };
+};
diff --git a/arch/arm/boot/dts/msm8226-fluid.dts b/arch/arm/boot/dts/msm8226-fluid.dts
new file mode 100644
index 0000000..af86922
--- /dev/null
+++ b/arch/arm/boot/dts/msm8226-fluid.dts
@@ -0,0 +1,24 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+/include/ "msm8226.dtsi"
+
+/ {
+ model = "Qualcomm MSM 8226 FLUID";
+ compatible = "qcom,msm8226-fluid", "qcom,msm8226";
+ qcom,msm-id = <145 3 0>;
+
+ serial@f991f000 {
+ status = "disabled";
+ };
+};
\ No newline at end of file
diff --git a/arch/arm/boot/dts/msm8226-gpu.dtsi b/arch/arm/boot/dts/msm8226-gpu.dtsi
index 76e934e..aa174bf 100644
--- a/arch/arm/boot/dts/msm8226-gpu.dtsi
+++ b/arch/arm/boot/dts/msm8226-gpu.dtsi
@@ -15,6 +15,8 @@
&msm_gpu {
qcom,chipid = <0x03000510>;
+ qcom,clk-map = <0x00000016>; /* KGSL_CLK_CORE | KGSL_CLK_IFACE | KGSL_CLK_MEM_IFACE */
+
qcom,msm-bus,vectors-KBps =
<26 512 0 0>, <89 604 0 0>,
<26 512 0 1600000>, <89 604 0 6400000>,
diff --git a/arch/arm/boot/dts/msm8226-mtp.dts b/arch/arm/boot/dts/msm8226-mtp.dts
new file mode 100644
index 0000000..dddb44b
--- /dev/null
+++ b/arch/arm/boot/dts/msm8226-mtp.dts
@@ -0,0 +1,24 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+/include/ "msm8226.dtsi"
+
+/ {
+ model = "Qualcomm MSM 8226 MTP";
+ compatible = "qcom,msm8226-mtp", "qcom,msm8226";
+ qcom,msm-id = <145 7 0>;
+
+ serial@f991f000 {
+ status = "disabled";
+ };
+};
\ No newline at end of file
diff --git a/arch/arm/boot/dts/msm8226-pm.dtsi b/arch/arm/boot/dts/msm8226-pm.dtsi
index e107b36..4937efe 100644
--- a/arch/arm/boot/dts/msm8226-pm.dtsi
+++ b/arch/arm/boot/dts/msm8226-pm.dtsi
@@ -21,13 +21,13 @@
qcom,core-id = <0>;
qcom,saw2-ver-reg = <0xfd0>;
qcom,saw2-cfg = <0x01>;
- qcom,saw2-spm-dly= <0x20000400>;
+ qcom,saw2-spm-dly= <0x3c102800>;
qcom,saw2-spm-ctl = <0x1>;
- qcom,saw2-spm-cmd-wfi = [60 03 60 76 76 0b 0f];
- qcom,saw2-spm-cmd-spc = [00 20 10 80 90 5b 60 03 60 3b 76 76 94
- 5b 80 10 2b 30 06 26 30 0f];
- qcom,saw2-spm-cmd-pc = [00 20 10 80 90 5b 60 07 3b 76 76 0b 94
- 5b 80 10 2b 30 06 26 30 0f];
+ qcom,saw2-spm-cmd-wfi = [60 03 60 0b 0f];
+ qcom,saw2-spm-cmd-spc = [00 20 10 80 30 90 5b 60 03 60 3b 76 76
+ 0b 94 5b 80 10 2b 06 26 30 0f];
+ qcom,saw2-spm-cmd-pc = [00 20 10 80 30 90 5b 60 07 60 3b 76 76
+ 0b 94 5b 80 10 2b 06 26 30 0f];
};
qcom,spm@f9099000 {
@@ -38,13 +38,13 @@
qcom,core-id = <1>;
qcom,saw2-ver-reg = <0xfd0>;
qcom,saw2-cfg = <0x01>;
- qcom,saw2-spm-dly= <0x20000400>;
+ qcom,saw2-spm-dly= <0x3c102800>;
qcom,saw2-spm-ctl = <0x1>;
- qcom,saw2-spm-cmd-wfi = [60 03 60 76 76 0b 0f];
- qcom,saw2-spm-cmd-spc = [00 20 10 80 90 5b 60 03 60 3b 76 76 94
- 5b 80 10 2b 30 06 26 30 0f];
- qcom,saw2-spm-cmd-pc = [00 20 10 80 90 5b 60 07 3b 76 76 0b 94
- 5b 80 10 2b 30 06 26 30 0f];
+ qcom,saw2-spm-cmd-wfi = [60 03 60 0b 0f];
+ qcom,saw2-spm-cmd-spc = [00 20 10 80 30 90 5b 60 03 60 3b 76 76
+ 0b 94 5b 80 10 2b 06 26 30 0f];
+ qcom,saw2-spm-cmd-pc = [00 20 10 80 30 90 5b 60 07 60 3b 76 76
+ 0b 94 5b 80 10 2b 06 26 30 0f];
};
qcom,spm@f90a9000 {
@@ -55,13 +55,13 @@
qcom,core-id = <2>;
qcom,saw2-ver-reg = <0xfd0>;
qcom,saw2-cfg = <0x01>;
- qcom,saw2-spm-dly= <0x20000400>;
+ qcom,saw2-spm-dly= <0x3c102800>;
qcom,saw2-spm-ctl = <0x1>;
qcom,saw2-spm-cmd-wfi = [60 03 60 76 76 0b 0f];
- qcom,saw2-spm-cmd-spc = [00 20 10 80 90 5b 60 03 60 3b 76 76 94
- 5b 80 10 2b 30 06 26 30 0f];
- qcom,saw2-spm-cmd-pc = [00 20 10 80 90 5b 60 07 3b 76 76 0b 94
- 5b 80 10 2b 30 06 26 30 0f];
+ qcom,saw2-spm-cmd-spc = [00 20 10 80 30 90 5b 60 03 60 3b 76 76
+ 0b 94 5b 80 10 2b 06 26 30 0f];
+ qcom,saw2-spm-cmd-pc = [00 20 10 80 30 90 5b 60 07 60 3b 76 76
+ 0b 94 5b 80 10 2b 06 26 30 0f];
};
qcom,spm@f90b9000 {
@@ -72,13 +72,13 @@
qcom,core-id = <3>;
qcom,saw2-ver-reg = <0xfd0>;
qcom,saw2-cfg = <0x01>;
- qcom,saw2-spm-dly= <0x20000400>;
+ qcom,saw2-spm-dly= <0x3c102800>;
qcom,saw2-spm-ctl = <0x1>;
qcom,saw2-spm-cmd-wfi = [60 03 60 76 76 0b 0f];
- qcom,saw2-spm-cmd-spc = [00 20 10 80 90 5b 60 03 60 3b 76 76 94
- 5b 80 10 2b 30 06 26 30 0f];
- qcom,saw2-spm-cmd-pc = [00 20 10 80 90 5b 60 07 3b 76 76 0b 94
- 5b 80 10 2b 30 06 26 30 0f];
+ qcom,saw2-spm-cmd-spc = [00 20 10 80 30 90 5b 60 03 60 3b 76 76
+ 0b 94 5b 80 10 2b 06 26 30 0f];
+ qcom,saw2-spm-cmd-pc = [00 20 10 80 30 90 5b 60 07 60 3b 76 76
+ 0b 94 5b 80 10 2b 06 26 30 0f];
};
qcom,spm@f9012000 {
@@ -89,19 +89,19 @@
qcom,core-id = <0xffff>; /* L2/APCS SAW */
qcom,saw2-ver-reg = <0xfd0>;
qcom,saw2-cfg = <0x14>;
- qcom,saw2-spm-dly= <0x20000400>;
+ qcom,saw2-spm-dly= <0x3c102800>;
qcom,saw2-spm-ctl = <0x1>;
- qcom,saw2-pmic-data0 = <0x02030080>;
- qcom,saw2-pmic-data1 = <0x00030000>;
+ qcom,saw2-pmic-data0 = <0x0400009c>;
+ qcom,saw2-pmic-data1 = <0x0000001c>;
qcom,vctl-timeout-us = <50>;
qcom,vctl-port = <0x0>;
qcom,phase-port = <0x1>;
qcom,pfm-port = <0x2>;
- qcom,saw2-spm-cmd-ret = [0b 00 03 00 7b 0f];
- qcom,saw2-spm-cmd-gdhs = [00 20 32 60 70 80 0b 6b c0 e0 d0 42 07
+ qcom,saw2-spm-cmd-ret = [00 03 00 7b 0f];
+ qcom,saw2-spm-cmd-gdhs = [00 20 32 60 70 80 6b c0 e0 d0 42 07
78 1f 80 4e d0 e0 c0 22 6b 50 4b 60 02 32 50 7b
0f];
- qcom,saw2-spm-cmd-pc = [00 32 60 70 80 b0 0b 10 e0 d0 6b c0
+ qcom,saw2-spm-cmd-pc = [00 32 60 70 80 b0 10 e0 d0 6b c0
42 f0 11 07 01 b0 78 1f 80 4e c0 d0 12 e0 6b 50 4b
60 02 32 50 f0 7b 0f]; /*APCS_PMIC_OFF_L2RAM_OFF*/
};
@@ -382,13 +382,9 @@
<40 95>;
};
- qcom,pc-cntr@fe805664 {
- compatible = "qcom,pc-cntr";
- reg = <0xfe805664 0x40>;
- };
-
- qcom,pm-8x60 {
+ qcom,pm-8x60@fe805664 {
compatible = "qcom,pm-8x60";
+ reg = <0xfe805664 0x40>;
qcom,pc-mode = <0>; /*MSM_PC_TZ_L2_INT */
qcom,use-sync-timer;
};
diff --git a/arch/arm/boot/dts/msm8226-qrd.dts b/arch/arm/boot/dts/msm8226-qrd.dts
new file mode 100644
index 0000000..14bf60b
--- /dev/null
+++ b/arch/arm/boot/dts/msm8226-qrd.dts
@@ -0,0 +1,24 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+/include/ "msm8226.dtsi"
+
+/ {
+ model = "Qualcomm MSM 8226 QRD";
+ compatible = "qcom,msm8226-qrd", "qcom,msm8226";
+ qcom,msm-id = <145 1 0>;
+
+ serial@f991f000 {
+ status = "disabled";
+ };
+};
\ No newline at end of file
diff --git a/arch/arm/boot/dts/msm8226-regulator.dtsi b/arch/arm/boot/dts/msm8226-regulator.dtsi
index f2269d5..50d2dba 100644
--- a/arch/arm/boot/dts/msm8226-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8226-regulator.dtsi
@@ -10,275 +10,300 @@
* GNU General Public License for more details.
*/
- /* Stub Regulators */
+/* Stub Regulators */
- / {
- pm8026_s1: regulator-s1 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8026_s1";
- qcom,hpm-min-load = <100000>;
- regulator-min-microvolt = <1150000>;
- regulator-max-microvolt = <1150000>;
- };
-
+/ {
pm8026_s1_corner: regulator-s1-corner {
compatible = "qcom,stub-regulator";
- regulator-name = "8026_s1_corner";
+ regulator-name = "8226_s1_corner";
qcom,hpm-min-load = <100000>;
regulator-min-microvolt = <1>;
regulator-max-microvolt = <7>;
qcom,consumer-supplies = "vdd_dig", "";
};
+};
- pm8026_s2: regulator-s2 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8026_s2";
- qcom,hpm-min-load = <100000>;
- regulator-min-microvolt = <1050000>;
- regulator-max-microvolt = <1050000>;
- };
+/* QPNP controlled regulators: */
- pm8026_s3: regulator-s3 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8026_s3";
- qcom,hpm-min-load = <100000>;
- regulator-min-microvolt = <1300000>;
- regulator-max-microvolt = <1300000>;
- };
+&spmi_bus {
- pm8026_s4: regulator-s4 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8026_s4";
- qcom,hpm-min-load = <100000>;
- regulator-min-microvolt = <2100000>;
- regulator-max-microvolt = <2100000>;
- };
+ qcom,pm8226@1 {
- pm8026_s5: regulator-s5 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8026_s5";
- qcom,hpm-min-load = <100000>;
- regulator-min-microvolt = <1150000>;
- regulator-max-microvolt = <1150000>;
- };
+ pm8226_s1: regulator@1400 {
+ status = "okay";
+ regulator-name = "8226_s1";
+ qcom,enable-time = <500>;
+ qcom,system-load = <100000>;
+ regulator-always-on;
+ regulator-min-microvolt = <1287500>;
+ regulator-max-microvolt = <1287500>;
+ };
- pm8026_l1: regulator-l1 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8026_l1";
- parent-supply = <&pm8026_s3>;
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1225000>;
- regulator-max-microvolt = <1225000>;
- };
+ pm8226_s2: regulator@1700 {
+ status = "okay";
+ regulator-name = "8226_s2";
+ qcom,enable-time = <500>;
+ qcom,system-load = <100000>;
+ regulator-always-on;
+ regulator-min-microvolt = <1150000>;
+ regulator-max-microvolt = <1150000>;
+ };
- pm8026_l2: regulator-l2 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8026_l2";
- parent-supply = <&pm8026_s3>;
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1200000>;
- regulator-max-microvolt = <1200000>;
- };
+ pm8226_s3: regulator@1a00 {
+ status = "okay";
+ regulator-name = "8226_s3";
+ qcom,enable-time = <500>;
+ qcom,system-load = <100000>;
+ regulator-always-on;
+ regulator-min-microvolt = <1300000>;
+ regulator-max-microvolt = <1300000>;
+ };
- pm8026_l3: regulator-l3 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8026_l3";
- parent-supply = <&pm8026_s3>;
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1150000>;
- regulator-max-microvolt = <1150000>;
- };
+ pm8226_s4: regulator@1d00 {
+ status = "okay";
+ regulator-name = "8226_s4";
+ qcom,enable-time = <500>;
+ qcom,system-load = <100000>;
+ regulator-always-on;
+ regulator-min-microvolt = <2100000>;
+ regulator-max-microvolt = <2100000>;
+ };
- pm8026_l4: regulator-l4 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8026_l4";
- parent-supply = <&pm8026_s3>;
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1200000>;
- regulator-max-microvolt = <1200000>;
- };
+ pm8226_s5: regulator@2000 {
+ status = "okay";
+ regulator-name = "8226_s5";
+ qcom,enable-time = <500>;
+ regulator-min-microvolt = <1150000>;
+ regulator-max-microvolt = <1150000>;
+ };
- pm8026_l5: regulator-l5 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8026_l5";
- parent-supply = <&pm8026_s3>;
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1200000>;
- regulator-max-microvolt = <1200000>;
- };
+ pm8226_l1: regulator@4000 {
+ status = "okay";
+ regulator-name = "8226_l1";
+ parent-supply = <&pm8226_s3>;
+ qcom,enable-time = <200>;
+ regulator-min-microvolt = <1225000>;
+ regulator-max-microvolt = <1225000>;
+ };
- pm8026_l6: regulator-l6 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8026_l6";
- parent-supply = <&pm8026_s4>;
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- };
+ pm8226_l2: regulator@4100 {
+ status = "okay";
+ regulator-name = "8226_l2";
+ parent-supply = <&pm8226_s3>;
+ regulator-always-on;
+ qcom,enable-time = <200>;
+ qcom,system-load = <10000>;
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ };
- pm8026_l7: regulator-l7 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8026_l7";
- parent-supply = <&pm8026_s4>;
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1850000>;
- regulator-max-microvolt = <1850000>;
- };
+ pm8226_l3: regulator@4200 {
+ status = "okay";
+ regulator-name = "8226_l3";
+ parent-supply = <&pm8226_s3>;
+ qcom,system-load = <10000>;
+ regulator-always-on;
+ qcom,enable-time = <200>;
+ regulator-min-microvolt = <1287500>;
+ regulator-max-microvolt = <1287500>;
+ };
- pm8026_l8: regulator-l8 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8026_l8";
- parent-supply = <&pm8026_s4>;
- qcom,hpm-min-load = <5000>;
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- qcom,consumer-supplies = "vdd_sr2_pll", "";
- };
+ pm8226_l4: regulator@4300 {
+ status = "okay";
+ regulator-name = "8226_l4";
+ parent-supply = <&pm8226_s3>;
+ qcom,enable-time = <200>;
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ };
- pm8026_l9: regulator-l9 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8026_l9";
- parent-supply = <&pm8026_s4>;
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <2050000>;
- regulator-max-microvolt = <2050000>;
- };
+ pm8226_l5: regulator@4400 {
+ status = "okay";
+ regulator-name = "8226_l5";
+ parent-supply = <&pm8226_s3>;
+ qcom,enable-time = <200>;
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ };
- pm8026_l10: regulator-l10 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8026_l10";
- parent-supply = <&pm8026_s4>;
- qcom,hpm-min-load = <5000>;
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- };
+ pm8226_l6: regulator@4500 {
+ status = "okay";
+ regulator-name = "8226_l6";
+ parent-supply = <&pm8226_s4>;
+ qcom,system-load = <10000>;
+ regulator-always-on;
+ qcom,enable-time = <200>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
- pm8026_l12: regulator-l12 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8026_l12";
- qcom,hpm-min-load = <5000>;
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- };
+ pm8226_l7: regulator@4600 {
+ status = "okay";
+ regulator-name = "8226_l7";
+ parent-supply = <&pm8226_s4>;
+ qcom,enable-time = <200>;
+ regulator-min-microvolt = <1850000>;
+ regulator-max-microvolt = <1850000>;
+ };
- pm8026_l14: regulator-l14 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8026_l14";
- qcom,hpm-min-load = <5000>;
- regulator-min-microvolt = <2750000>;
- regulator-max-microvolt = <2750000>;
- };
+ pm8226_l8: regulator@4700 {
+ status = "okay";
+ regulator-name = "8226_l8";
+ parent-supply = <&pm8226_s4>;
+ qcom,enable-time = <200>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,consumer-supplies = "vdd_sr2_pll", "";
+ };
- pm8026_l15: regulator-l15 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8026_l15";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <2800000>;
- regulator-max-microvolt = <2800000>;
- };
+ pm8226_l9: regulator@4800 {
+ status = "okay";
+ regulator-name = "8226_l9";
+ parent-supply = <&pm8226_s4>;
+ qcom,enable-time = <200>;
+ regulator-min-microvolt = <2050000>;
+ regulator-max-microvolt = <2050000>;
+ };
- pm8026_l16: regulator-l16 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8026_l16";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <3000000>;
- regulator-max-microvolt = <3000000>;
- };
+ pm8226_l10: regulator@4900 {
+ status = "okay";
+ regulator-name = "8226_l10";
+ parent-supply = <&pm8226_s4>;
+ qcom,enable-time = <200>;
+ qcom,system-load = <5000>;
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
- pm8026_l17: regulator-l17 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8026_l17";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <2950000>;
- regulator-max-microvolt = <2950000>;
- };
+ pm8226_l12: regulator@4b00 {
+ status = "okay";
+ regulator-name = "8226_l12";
+ qcom,enable-time = <200>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
- pm8026_l18: regulator-l18 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8026_l18";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <2950000>;
- regulator-max-microvolt = <2950000>;
- };
+ pm8226_l14: regulator@4d00 {
+ status = "okay";
+ regulator-name = "8226_l14";
+ qcom,enable-time = <200>;
+ regulator-min-microvolt = <2750000>;
+ regulator-max-microvolt = <2750000>;
+ };
- pm8026_l19: regulator-l19 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8026_l19";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <2850000>;
- regulator-max-microvolt = <2850000>;
- };
+ pm8226_l15: regulator@4e00 {
+ status = "okay";
+ regulator-name = "8226_l15";
+ qcom,enable-time = <200>;
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ };
- pm8026_l20: regulator-l20 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8026_l20";
- qcom,hpm-min-load = <5000>;
- regulator-min-microvolt = <3075000>;
- regulator-max-microvolt = <3075000>;
- };
+ pm8226_l16: regulator@4f00 {
+ status = "okay";
+ regulator-name = "8226_l16";
+ qcom,enable-time = <200>;
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3300000>;
+ };
- pm8026_l21: regulator-l21 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8026_l21";
- qcom,hpm-min-load = <5000>;
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <2950000>;
- };
+ pm8226_l17: regulator@5000 {
+ status = "okay";
+ regulator-name = "8226_l17";
+ qcom,enable-time = <200>;
+ regulator-min-microvolt = <2950000>;
+ regulator-max-microvolt = <2950000>;
+ };
- pm8026_l22: regulator-l22 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8026_l22";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <2950000>;
- };
+ pm8226_l18: regulator@5100 {
+ status = "okay";
+ regulator-name = "8226_l18";
+ qcom,enable-time = <200>;
+ regulator-min-microvolt = <2950000>;
+ regulator-max-microvolt = <2950000>;
+ };
- pm8026_l23: regulator-l23 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8026_l23";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <2950000>;
- };
+ pm8226_l19: regulator@5200 {
+ status = "okay";
+ regulator-name = "8226_l19";
+ qcom,enable-time = <200>;
+ regulator-min-microvolt = <2850000>;
+ regulator-max-microvolt = <2850000>;
+ };
- pm8026_l24: regulator-l24 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8026_l24";
- parent-supply = <&pm8026_s3>;
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1300000>;
- regulator-max-microvolt = <1300000>;
- };
+ pm8226_l20: regulator@5300 {
+ status = "okay";
+ regulator-name = "8226_l20";
+ qcom,enable-time = <200>;
+ regulator-min-microvolt = <3075000>;
+ regulator-max-microvolt = <3075000>;
+ };
- pm8026_l26: regulator-l26 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8026_l26";
- parent-supply = <&pm8026_s3>;
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1225000>;
- regulator-max-microvolt = <1225000>;
- };
+ pm8226_l21: regulator@5400 {
+ status = "okay";
+ regulator-name = "8226_l21";
+ qcom,enable-time = <200>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2950000>;
+ };
- pm8026_l27: regulator-l27 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8026_l27";
- parent-supply = <&pm8026_s4>;
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <2050000>;
- regulator-max-microvolt = <2050000>;
- };
+ pm8226_l22: regulator@5500 {
+ status = "okay";
+ regulator-name = "8226_l22";
+ qcom,enable-time = <200>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2950000>;
+ };
- pm8026_l28: regulator-l28 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8026_l28";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <2950000>;
- };
+ pm8226_l23: regulator@5600 {
+ status = "okay";
+ regulator-name = "8226_l23";
+ qcom,enable-time = <200>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2950000>;
+ };
- pm8026_lvs1: regulator-lvs1 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8026_lvs1";
- parent-supply = <&pm8026_l6>;
+ pm8226_l24: regulator@5700 {
+ status = "okay";
+ regulator-name = "8226_l24";
+ parent-supply = <&pm8226_s3>;
+ qcom,enable-time = <200>;
+ regulator-min-microvolt = <1300000>;
+ regulator-max-microvolt = <1300000>;
+ };
+
+ pm8226_l26: regulator@5900 {
+ status = "okay";
+ regulator-name = "8226_l26";
+ parent-supply = <&pm8226_s3>;
+ qcom,enable-time = <200>;
+ regulator-min-microvolt = <1225000>;
+ regulator-max-microvolt = <1225000>;
+ };
+
+ pm8226_l27: regulator@5a00 {
+ status = "okay";
+ regulator-name = "8226_l27";
+ parent-supply = <&pm8226_s4>;
+ qcom,enable-time = <200>;
+ regulator-min-microvolt = <2050000>;
+ regulator-max-microvolt = <2050000>;
+ };
+
+ pm8226_l28: regulator@5b00 {
+ status = "okay";
+ regulator-name = "8226_l28";
+ qcom,enable-time = <200>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2950000>;
+ };
+
+ pm8226_lvs1: regulator@8000 {
+ status = "okay";
+ regulator-name = "8226_lvs1";
+ parent-supply = <&pm8226_l6>;
+ qcom,enable-time = <200>;
+ };
};
};
diff --git a/arch/arm/boot/dts/msm8226-sim.dts b/arch/arm/boot/dts/msm8226-sim.dts
index 9a0ec17..f9ab957 100644
--- a/arch/arm/boot/dts/msm8226-sim.dts
+++ b/arch/arm/boot/dts/msm8226-sim.dts
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -39,8 +39,8 @@
qcom,pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
- vdd-supply = <&pm8026_l17>;
- vdd-io-supply = <&pm8026_l6>;
+ vdd-supply = <&pm8226_l17>;
+ vdd-io-supply = <&pm8226_l6>;
qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
qcom,sup-voltages = <2950 2950>;
@@ -50,8 +50,8 @@
};
&sdcc2 {
- vdd-supply = <&pm8026_l18>;
- vdd-io-supply = <&pm8026_l21>;
+ vdd-supply = <&pm8226_l18>;
+ vdd-io-supply = <&pm8226_l21>;
qcom,vdd-voltage-level = <2950000 2950000>;
qcom,vdd-current-level = <9000 800000>;
@@ -74,3 +74,57 @@
status = "ok";
};
+
+&pm8226_gpios {
+ gpio@c000 { /* GPIO 1 */
+ };
+
+ gpio@c100 { /* GPIO 2 */
+ };
+
+ gpio@c200 { /* GPIO 3 */
+ };
+
+ gpio@c300 { /* GPIO 4 */
+ };
+
+ gpio@c400 { /* GPIO 5 */
+ };
+
+ gpio@c500 { /* GPIO 6 */
+ };
+
+ gpio@c600 { /* GPIO 7 */
+ };
+
+ gpio@c700 { /* GPIO 8 */
+ };
+};
+
+&pm8226_mpps {
+ mpp@a000 { /* MPP 1 */
+ };
+
+ mpp@a100 { /* MPP 2 */
+ };
+
+ mpp@a200 { /* MPP 3 */
+ };
+
+ mpp@a300 { /* MPP 4 */
+ };
+
+ mpp@a400 { /* MPP 5 */
+ };
+
+ mpp@a500 { /* MPP 6 */
+ };
+
+ mpp@a600 { /* MPP 7 */
+ };
+
+ mpp@a700 { /* MPP 8 */
+ };
+};
+
+
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index 5227004..de4e571 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -44,6 +44,10 @@
qcom,direct-connect-irqs = <8>;
};
+ aliases {
+ spi0 = &spi_0;
+ };
+
timer {
compatible = "arm,armv7-timer";
interrupts = <1 2 0 1 3 0>;
@@ -81,9 +85,9 @@
reg = <0xf9a55000 0x400>;
interrupts = <0 134 0>, <0 140 0>;
interrupt-names = "core_irq", "async_irq";
- HSUSB_VDDCX-supply = <&pm8026_s1>;
- HSUSB_1p8-supply = <&pm8026_l10>;
- HSUSB_3p3-supply = <&pm8026_l20>;
+ HSUSB_VDDCX-supply = <&pm8226_s1>;
+ HSUSB_1p8-supply = <&pm8226_l10>;
+ HSUSB_3p3-supply = <&pm8226_l20>;
qcom,hsusb-otg-phy-type = <2>;
qcom,hsusb-otg-mode = <1>;
@@ -123,23 +127,23 @@
17 18 19 20 21 22 23 24 25 26 27 28>;
qcom,cdc-reset-gpio = <&msmgpio 72 0>;
- cdc-vdd-buck-supply = <&pm8026_s4>;
+ cdc-vdd-buck-supply = <&pm8226_s4>;
qcom,cdc-vdd-buck-voltage = <2100000 2100000>;
qcom,cdc-vdd-buck-current = <650000>;
- cdc-vdd-h-supply = <&pm8026_l6>;
+ cdc-vdd-h-supply = <&pm8226_l6>;
qcom,cdc-vdd-h-voltage = <1800000 1800000>;
qcom,cdc-vdd-h-current = <25000>;
- cdc-vdd-px-supply = <&pm8026_l6>;
+ cdc-vdd-px-supply = <&pm8226_l6>;
qcom,cdc-vdd-px-voltage = <1800000 1800000>;
qcom,cdc-vdd-px-current = <25000>;
- cdc-vdd-a-1p2v-supply = <&pm8026_l4>;
+ cdc-vdd-a-1p2v-supply = <&pm8226_l4>;
qcom,cdc-vdd-a-1p2v-voltage = <1200000 1200000>;
qcom,cdc-vdd-a-1p2v-current = <10000>;
- cdc-vdd-cx-supply = <&pm8026_l4>;
+ cdc-vdd-cx-supply = <&pm8226_l4>;
qcom,cdc-vdd-cx-voltage = <1200000 1200000>;
qcom,cdc-vdd-cx-current = <10000>;
@@ -466,8 +470,8 @@
compatible = "qcom,acpuclk-a7";
reg = <0xf9011050 0x8>;
reg-names = "rcg_base";
- a7_cpu-supply = <&pm8026_s2>;
- a7_mem-supply = <&pm8026_l3>;
+ a7_cpu-supply = <&pm8226_s2>;
+ a7_mem-supply = <&pm8226_l3>;
};
qcom,ocmem@fdd00000 {
@@ -510,7 +514,7 @@
<0xfd485300 0xc>;
reg-names = "pmu_base", "clk_base", "halt_base";
interrupts = <0 149 1>;
- vdd_pronto_pll-supply = <&pm8026_l8>;
+ vdd_pronto_pll-supply = <&pm8226_l8>;
qcom,firmware-name = "wcnss";
};
@@ -520,6 +524,7 @@
reg = <0xfe200000 0x00100>,
<0xfd485100 0x00010>;
reg-names = "qdsp6_base", "halt_base";
+ vdd_cx-supply = <&pm8026_s1_corner>;
interrupts = <0 162 1>;
qcom,firmware-name = "adsp";
@@ -540,6 +545,39 @@
qcom,slope = <3200 3200 3200 3200 3200 3200 3200>;
qcom,calib-mode = "fuse_map2";
};
+
+ qcom,msm-thermal {
+ compatible = "qcom,msm-thermal";
+ qcom,sensor-id = <0>;
+ qcom,poll-ms = <250>;
+ qcom,limit-temp = <60>;
+ qcom,temp-hysteresis = <10>;
+ qcom,freq-step = <2>;
+ };
+
+ spi_0: spi@f9923000 { /* BLSP1 QUP1 */
+ compatible = "qcom,spi-qup-v2";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg-names = "spi_physical", "spi_bam_physical";
+ reg = <0xf9923000 0x1000>,
+ <0xf9904000 0xF000>;
+ interrupt-names = "spi_irq", "spi_bam_irq";
+ interrupts = <0 95 0>, <0 238 0>;
+ spi-max-frequency = <19200000>;
+
+ gpios = <&msmgpio 3 0>, /* CLK */
+ <&msmgpio 1 0>, /* MISO */
+ <&msmgpio 0 0>; /* MOSI */
+ cs-gpios = <&msmgpio 2 0>;
+
+ qcom,infinite-mode = <0>;
+ qcom,use-bam;
+ qcom,ver-reg-exists;
+ qcom,bam-consumer-pipe-index = <12>;
+ qcom,bam-producer-pipe-index = <13>;
+ };
+
};
&gdsc_venus {
@@ -566,5 +604,95 @@
status = "ok";
};
-/include/ "msm8226-regulator.dtsi"
/include/ "msm-pm8226.dtsi"
+/include/ "msm8226-regulator.dtsi"
+
+&pm8226_vadc {
+ chan@0 {
+ label = "usb_in";
+ reg = <0>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <4>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@2 {
+ label = "vchg_sns";
+ reg = <2>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <3>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@5 {
+ label = "vcoin";
+ reg = <5>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <1>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@6 {
+ label = "vbat_sns";
+ reg = <6>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <1>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@7 {
+ label = "vph_pwr";
+ reg = <7>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <1>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@30 {
+ label = "batt_therm";
+ reg = <0x30>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <1>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@31 {
+ label = "batt_id";
+ reg = <0x31>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@b2 {
+ label = "xo_therm_pu2";
+ reg = <0xb2>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <4>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+};
diff --git a/arch/arm/boot/dts/msm8610-pm.dtsi b/arch/arm/boot/dts/msm8610-pm.dtsi
index e107b36..feb3087 100644
--- a/arch/arm/boot/dts/msm8610-pm.dtsi
+++ b/arch/arm/boot/dts/msm8610-pm.dtsi
@@ -382,13 +382,9 @@
<40 95>;
};
- qcom,pc-cntr@fe805664 {
- compatible = "qcom,pc-cntr";
- reg = <0xfe805664 0x40>;
- };
-
- qcom,pm-8x60 {
+ qcom,pm-8x60@fe805664 {
compatible = "qcom,pm-8x60";
+ reg = <0xfe805664 0x40>;
qcom,pc-mode = <0>; /*MSM_PC_TZ_L2_INT */
qcom,use-sync-timer;
};
diff --git a/arch/arm/boot/dts/msm8610.dtsi b/arch/arm/boot/dts/msm8610.dtsi
index 9ff383f..ce6011b 100644
--- a/arch/arm/boot/dts/msm8610.dtsi
+++ b/arch/arm/boot/dts/msm8610.dtsi
@@ -41,6 +41,10 @@
qcom,direct-connect-irqs = <8>;
};
+ aliases {
+ spi0 = &spi_0;
+ };
+
timer {
compatible = "arm,armv7-timer";
interrupts = <1 2 0 1 3 0>;
@@ -283,6 +287,30 @@
qcom,i2c-bus-freq = <100000>;
};
+
+ spi_0: spi@f9923000 { /* BLSP1 QUP1 */
+ compatible = "qcom,spi-qup-v2";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg-names = "spi_physical", "spi_bam_physical";
+ reg = <0xf9923000 0x1000>,
+ <0xf9904000 0xF000>;
+ interrupt-names = "spi_irq", "spi_bam_irq";
+ interrupts = <0 95 0>, <0 238 0>;
+ spi-max-frequency = <19200000>;
+
+ gpios = <&msmgpio 3 0>, /* CLK */
+ <&msmgpio 1 0>, /* MISO */
+ <&msmgpio 0 0>; /* MOSI */
+ cs-gpios = <&msmgpio 2 0>;
+
+ qcom,infinite-mode = <0>;
+ qcom,use-bam;
+ qcom,ver-reg-exists;
+ qcom,bam-consumer-pipe-index = <12>;
+ qcom,bam-producer-pipe-index = <13>;
+ };
+
qcom,pronto@fb21b000 {
compatible = "qcom,pil-pronto";
reg = <0xfb21b000 0x3000>,
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-cdp-mtp.dtsi
similarity index 68%
rename from arch/arm/boot/dts/msm8974-camera-sensor.dtsi
rename to arch/arm/boot/dts/msm8974-camera-sensor-cdp-mtp.dtsi
index 85b90c2..fb2917c 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-cdp-mtp.dtsi
@@ -13,13 +13,19 @@
&cci {
+ actuator0: qcom,actuator@18 {
+ cell-index = <0>;
+ reg = <0x18 0x0>;
+ compatible = "qcom,actuator";
+ qcom,cci-master = <0>;
+ };
+
qcom,camera@6e {
compatible = "qcom,s5k3l1yx";
reg = <0x6e 0x0>;
qcom,slave-id = <0x6e 0x0 0x3121>;
qcom,csiphy-sd-index = <0>;
qcom,csid-sd-index = <0>;
- qcom,flash-src-index = <&led_flash0>;
qcom,actuator-src = <&actuator0>;
qcom,mount-angle = <90>;
qcom,sensor-name = "s5k3l1yx";
@@ -35,12 +41,15 @@
qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
qcom,gpio-no-mux = <0>;
gpios = <&msmgpio 15 0>,
- <&msmgpio 90 0>;
+ <&msmgpio 90 0>,
+ <&msmgpio 89 0>;
qcom,gpio-reset = <1>;
- qcom,gpio-req-tbl-num = <0 1>;
- qcom,gpio-req-tbl-flags = <1 0>;
+ qcom,gpio-standby = <2>;
+ qcom,gpio-req-tbl-num = <0 1 2>;
+ qcom,gpio-req-tbl-flags = <1 0 0>;
qcom,gpio-req-tbl-label = "CAMIF_MCLK",
- "CAM_RESET1";
+ "CAM_RESET1",
+ "CAM_STANDBY";
qcom,gpio-set-tbl-num = <1 1>;
qcom,gpio-set-tbl-flags = <0 2>;
qcom,gpio-set-tbl-delay = <1000 30000>;
@@ -56,7 +65,6 @@
compatible = "qcom,ov2720";
reg = <0x6c 0x0>;
qcom,slave-id = <0x6c 0x300A 0x2720>;
- qcom,led-flash-sd-index = <0>;
qcom,csiphy-sd-index = <2>;
qcom,csid-sd-index = <0>;
qcom,mount-angle = <90>;
@@ -87,4 +95,38 @@
qcom,cci-master = <1>;
status = "ok";
};
+
+ qcom,camera@90 {
+ compatible = "qcom,mt9m114";
+ reg = <0x90 0x0>;
+ qcom,slave-id = <0x90 0x0 0x2481>;
+ qcom,csiphy-sd-index = <1>;
+ qcom,csid-sd-index = <0>;
+ qcom,mount-angle = <0>;
+ qcom,sensor-name = "mt9m114";
+ cam_vdig-supply = <&pm8941_l3>;
+ cam_vana-supply = <&pm8941_l17>;
+ cam_vio-supply = <&pm8941_lvs3>;
+ qcom,cam-vreg-name = "cam_vdig", "cam_vana", "cam_vio";
+ qcom,cam-vreg-type = <0 0 1>;
+ qcom,cam-vreg-min-voltage = <1225000 2850000 0>;
+ qcom,cam-vreg-max-voltage = <1225000 2850000 0>;
+ qcom,cam-vreg-op-mode = <105000 80000 0>;
+ qcom,gpio-no-mux = <0>;
+ gpios = <&msmgpio 16 0>,
+ <&msmgpio 92 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-req-tbl-num = <0 1>;
+ qcom,gpio-req-tbl-flags = <1 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+ "CAM_RESET1";
+ qcom,gpio-set-tbl-num = <1 1>;
+ qcom,gpio-set-tbl-flags = <0 2>;
+ qcom,gpio-set-tbl-delay = <1000 4000>;
+ qcom,csi-lane-assign = <0x4320>;
+ qcom,csi-lane-mask = <0x3>;
+ qcom,sensor-position = <1>;
+ qcom,sensor-mode = <1>;
+ qcom,cci-master = <0>;
+ };
};
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-fluid.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-fluid.dtsi
index 51c6712..4fe4220 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-fluid.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-fluid.dtsi
@@ -13,14 +13,21 @@
&cci {
+ actuator0: qcom,actuator@18 {
+ cell-index = <0>;
+ reg = <0x18 0x0>;
+ compatible = "qcom,actuator";
+ qcom,cci-master = <0>;
+ };
+
qcom,camera@6e {
compatible = "qcom,s5k3l1yx";
reg = <0x6e>;
qcom,slave-id = <0x6e 0x0 0x3121>;
qcom,csiphy-sd-index = <0>;
qcom,csid-sd-index = <0>;
- qcom,flash-src-index = <&led_flash0>;
qcom,actuator-src = <&actuator0>;
+ qcom,led-flash-src = <&led_flash0>;
qcom,mount-angle = <270>;
qcom,sensor-name = "s5k3l1yx";
cam_vdig-supply = <&pm8941_l3>;
@@ -35,12 +42,15 @@
qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
qcom,gpio-no-mux = <0>;
gpios = <&msmgpio 15 0>,
- <&msmgpio 90 0>;
+ <&msmgpio 90 0>,
+ <&msmgpio 89 0>;
qcom,gpio-reset = <1>;
- qcom,gpio-req-tbl-num = <0 1>;
- qcom,gpio-req-tbl-flags = <1 0>;
+ qcom,gpio-standby = <2>;
+ qcom,gpio-req-tbl-num = <0 1 2>;
+ qcom,gpio-req-tbl-flags = <1 0 0>;
qcom,gpio-req-tbl-label = "CAMIF_MCLK",
- "CAM_RESET1";
+ "CAM_RESET1",
+ "CAM_STANDBY";
qcom,gpio-set-tbl-num = <1 1>;
qcom,gpio-set-tbl-flags = <0 2>;
qcom,gpio-set-tbl-delay = <1000 30000>;
@@ -56,7 +66,6 @@
compatible = "qcom,ov2720";
reg = <0x6c>;
qcom,slave-id = <0x6c 0x300A 0x2720>;
- qcom,led-flash-sd-index = <0>;
qcom,csiphy-sd-index = <2>;
qcom,csid-sd-index = <0>;
qcom,mount-angle = <90>;
@@ -87,4 +96,38 @@
qcom,cci-master = <1>;
status = "ok";
};
+
+ qcom,camera@90 {
+ compatible = "qcom,mt9m114";
+ reg = <0x90 0x0>;
+ qcom,slave-id = <0x90 0x0 0x2481>;
+ qcom,csiphy-sd-index = <1>;
+ qcom,csid-sd-index = <0>;
+ qcom,mount-angle = <0>;
+ qcom,sensor-name = "mt9m114";
+ cam_vdig-supply = <&pm8941_l3>;
+ cam_vana-supply = <&pm8941_l17>;
+ cam_vio-supply = <&pm8941_lvs3>;
+ qcom,cam-vreg-name = "cam_vdig", "cam_vana", "cam_vio";
+ qcom,cam-vreg-type = <0 0 1>;
+ qcom,cam-vreg-min-voltage = <1225000 2850000 0>;
+ qcom,cam-vreg-max-voltage = <1225000 2850000 0>;
+ qcom,cam-vreg-op-mode = <105000 80000 0>;
+ qcom,gpio-no-mux = <0>;
+ gpios = <&msmgpio 16 0>,
+ <&msmgpio 92 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-req-tbl-num = <0 1>;
+ qcom,gpio-req-tbl-flags = <1 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+ "CAM_RESET1";
+ qcom,gpio-set-tbl-num = <1 1>;
+ qcom,gpio-set-tbl-flags = <0 2>;
+ qcom,gpio-set-tbl-delay = <1000 4000>;
+ qcom,csi-lane-assign = <0x4320>;
+ qcom,csi-lane-mask = <0x3>;
+ qcom,sensor-position = <1>;
+ qcom,sensor-mode = <1>;
+ qcom,cci-master = <0>;
+ };
};
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi
index dd85b3c..b313795 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi
@@ -14,13 +14,19 @@
&cci {
+ actuator0: qcom,actuator@18 {
+ cell-index = <0>;
+ reg = <0x18 0x0>;
+ compatible = "qcom,actuator";
+ qcom,cci-master = <0>;
+ };
+
qcom,camera@6e {
compatible = "qcom,s5k3l1yx";
reg = <0x6e 0x0>;
qcom,slave-id = <0x6e 0x0 0x3121>;
qcom,csiphy-sd-index = <0>;
qcom,csid-sd-index = <0>;
- qcom,flash-src-index = <&led_flash0>;
qcom,mount-angle = <0>;
qcom,sensor-name = "s5k3l1yx";
cam_vdig-supply = <&pm8941_l3>;
@@ -56,7 +62,6 @@
compatible = "qcom,ov2720";
reg = <0x6c 0x0>;
qcom,slave-id = <0x6c 0x300A 0x2720>;
- qcom,led-flash-sd-index = <0>;
qcom,csiphy-sd-index = <2>;
qcom,csid-sd-index = <0>;
qcom,mount-angle = <180>;
@@ -87,4 +92,38 @@
qcom,cci-master = <0>;
status = "ok";
};
+
+ qcom,camera@90 {
+ compatible = "qcom,mt9m114";
+ reg = <0x90 0x0>;
+ qcom,slave-id = <0x90 0x0 0x2481>;
+ qcom,csiphy-sd-index = <1>;
+ qcom,csid-sd-index = <0>;
+ qcom,mount-angle = <0>;
+ qcom,sensor-name = "mt9m114";
+ cam_vdig-supply = <&pm8941_l3>;
+ cam_vana-supply = <&pm8941_l17>;
+ cam_vio-supply = <&pm8941_lvs3>;
+ qcom,cam-vreg-name = "cam_vdig", "cam_vana", "cam_vio";
+ qcom,cam-vreg-type = <0 0 1>;
+ qcom,cam-vreg-min-voltage = <1225000 2850000 0>;
+ qcom,cam-vreg-max-voltage = <1225000 2850000 0>;
+ qcom,cam-vreg-op-mode = <105000 80000 0>;
+ qcom,gpio-no-mux = <0>;
+ gpios = <&msmgpio 16 0>,
+ <&msmgpio 92 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-req-tbl-num = <0 1>;
+ qcom,gpio-req-tbl-flags = <1 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+ "CAM_RESET1";
+ qcom,gpio-set-tbl-num = <1 1>;
+ qcom,gpio-set-tbl-flags = <0 2>;
+ qcom,gpio-set-tbl-delay = <1000 4000>;
+ qcom,csi-lane-assign = <0x4320>;
+ qcom,csi-lane-mask = <0x3>;
+ qcom,sensor-position = <1>;
+ qcom,sensor-mode = <1>;
+ qcom,cci-master = <0>;
+ };
};
diff --git a/arch/arm/boot/dts/msm8974-camera.dtsi b/arch/arm/boot/dts/msm8974-camera.dtsi
index a550c0b..ea99aa3 100644
--- a/arch/arm/boot/dts/msm8974-camera.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera.dtsi
@@ -158,8 +158,9 @@
qcom,cpp@fda04000 {
cell-index = <0>;
compatible = "qcom,cpp";
- reg = <0xfda04000 0x100>;
- reg-names = "cpp";
+ reg = <0xfda04000 0x100>,
+ <0xfda40000 0x200>;
+ reg-names = "cpp", "cpp_vbif";
interrupts = <0 49 0>;
interrupt-names = "cpp";
vdd-supply = <&gdsc_vfe>;
@@ -202,54 +203,5 @@
qcom,hw-scl-stretch-en = <0>;
qcom,hw-trdhld = <6>;
qcom,hw-tsp = <1>;
-
- actuator0: qcom,actuator@18 {
- cell-index = <0>;
- reg = <0x18 0x0>;
- compatible = "qcom,actuator";
- qcom,cci-master = <0>;
- };
-
- qcom,camera@6e {
- status = "disable";
- };
-
- qcom,camera@6c {
- status = "disable";
- };
-
- qcom,camera@90 {
- compatible = "qcom,mt9m114";
- reg = <0x90 0x0>;
- qcom,slave-id = <0x90 0x0 0x2481>;
- qcom,csiphy-sd-index = <1>;
- qcom,csid-sd-index = <0>;
- qcom,mount-angle = <0>;
- qcom,sensor-name = "mt9m114";
- cam_vdig-supply = <&pm8941_l3>;
- cam_vana-supply = <&pm8941_l17>;
- cam_vio-supply = <&pm8941_lvs3>;
- qcom,cam-vreg-name = "cam_vdig", "cam_vana", "cam_vio";
- qcom,cam-vreg-type = <0 0 1>;
- qcom,cam-vreg-min-voltage = <1225000 2850000 0>;
- qcom,cam-vreg-max-voltage = <1225000 2850000 0>;
- qcom,cam-vreg-op-mode = <105000 80000 0>;
- qcom,gpio-no-mux = <0>;
- gpios = <&msmgpio 16 0>,
- <&msmgpio 92 0>;
- qcom,gpio-reset = <1>;
- qcom,gpio-req-tbl-num = <0 1>;
- qcom,gpio-req-tbl-flags = <1 0>;
- qcom,gpio-req-tbl-label = "CAMIF_MCLK",
- "CAM_RESET1";
- qcom,gpio-set-tbl-num = <1 1>;
- qcom,gpio-set-tbl-flags = <0 2>;
- qcom,gpio-set-tbl-delay = <1000 4000>;
- qcom,csi-lane-assign = <0x4320>;
- qcom,csi-lane-mask = <0x3>;
- qcom,sensor-position = <1>;
- qcom,sensor-mode = <1>;
- qcom,cci-master = <0>;
- };
};
};
diff --git a/arch/arm/boot/dts/msm8974-cdp.dtsi b/arch/arm/boot/dts/msm8974-cdp.dtsi
index 12804fb..f5f7fbd 100644
--- a/arch/arm/boot/dts/msm8974-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8974-cdp.dtsi
@@ -13,7 +13,7 @@
/include/ "dsi-panel-toshiba-720p-video.dtsi"
/include/ "dsi-panel-orise-720p-video.dtsi"
/include/ "msm8974-leds.dtsi"
-/include/ "msm8974-camera-sensor.dtsi"
+/include/ "msm8974-camera-sensor-cdp-mtp.dtsi"
/ {
serial@f991e000 {
@@ -203,6 +203,21 @@
startup-delay-us = <17000>;
enable-active-high;
};
+
+ hsic@f9a00000 {
+ compatible = "qcom,hsic-host";
+ reg = <0xf9a00000 0x400>;
+ interrupts = <0 136 0>, <0 148 0>;
+ interrupt-names = "core_irq", "async_irq";
+ HSIC_VDDCX-supply = <&pm8841_s2>;
+ HSIC_GDSC-supply = <&gdsc_usb_hsic>;
+ hsic,strobe-gpio = <&msmgpio 144 0x00>;
+ hsic,data-gpio = <&msmgpio 145 0x00>;
+ hsic,ignore-cal-pad-config;
+ hsic,strobe-pad-offset = <0x2050>;
+ hsic,data-pad-offset = <0x2054>;
+ };
+
};
&spmi_bus {
@@ -283,11 +298,6 @@
status = "ok";
};
-&ehci {
- status = "ok";
- vbus-supply = <&usb2_otg_sw>;
-};
-
&usb3 {
qcom,otg-capability;
};
@@ -534,3 +544,11 @@
mpp@a300 { /* MPP 4 */
};
};
+
+&slim_msm {
+ taiko_codec {
+ qcom,cdc-micbias1-ext-cap;
+ qcom,cdc-micbias3-ext-cap;
+ qcom,cdc-micbias4-ext-cap;
+ };
+};
diff --git a/arch/arm/boot/dts/msm8974-coresight.dtsi b/arch/arm/boot/dts/msm8974-coresight.dtsi
index 427ef0b..91de30e 100644
--- a/arch/arm/boot/dts/msm8974-coresight.dtsi
+++ b/arch/arm/boot/dts/msm8974-coresight.dtsi
@@ -15,6 +15,7 @@
compatible = "arm,coresight-tmc";
reg = <0xfc322000 0x1000>,
<0xfc37c000 0x3000>;
+ reg-names = "tmc-etr-base", "tmc-etr-bam-base";
qcom,memory-reservation-type = "EBI1";
qcom,memory-reservation-size = <0x100000>; /* 1M EBI1 buffer */
@@ -27,6 +28,7 @@
tpiu: tpiu@fc318000 {
compatible = "arm,coresight-tpiu";
reg = <0xfc318000 0x1000>;
+ reg-names = "tpiu-base";
coresight-id = <1>;
coresight-name = "coresight-tpiu";
@@ -36,6 +38,7 @@
replicator: replicator@fc31c000 {
compatible = "qcom,coresight-replicator";
reg = <0xfc31c000 0x1000>;
+ reg-names = "replicator-base";
coresight-id = <2>;
coresight-name = "coresight-replicator";
@@ -48,6 +51,7 @@
tmc_etf: tmc@fc307000 {
compatible = "arm,coresight-tmc";
reg = <0xfc307000 0x1000>;
+ reg-names = "tmc-etf-base";
coresight-id = <3>;
coresight-name = "coresight-tmc-etf";
@@ -61,6 +65,7 @@
funnel_merg: funnel@fc31b000 {
compatible = "arm,coresight-funnel";
reg = <0xfc31b000 0x1000>;
+ reg-names = "funnel-merg-base";
coresight-id = <4>;
coresight-name = "coresight-funnel-merg";
@@ -73,6 +78,7 @@
funnel_in0: funnel@fc319000 {
compatible = "arm,coresight-funnel";
reg = <0xfc319000 0x1000>;
+ reg-names = "funnel-in0-base";
coresight-id = <5>;
coresight-name = "coresight-funnel-in0";
@@ -85,6 +91,7 @@
funnel_in1: funnel@fc31a000 {
compatible = "arm,coresight-funnel";
reg = <0xfc31a000 0x1000>;
+ reg-names = "funnel-in1-base";
coresight-id = <6>;
coresight-name = "coresight-funnel-in1";
@@ -97,6 +104,7 @@
funnel_kpss: funnel@fc345000 {
compatible = "arm,coresight-funnel";
reg = <0xfc345000 0x1000>;
+ reg-names = "funnel-kpss-base";
coresight-id = <7>;
coresight-name = "coresight-funnel-kpss";
@@ -109,6 +117,8 @@
funnel_mmss: funnel@fc364000 {
compatible = "arm,coresight-funnel";
reg = <0xfc364000 0x1000>;
+ reg-names = "funnel-mmss-base";
+
coresight-id = <8>;
coresight-name = "coresight-funnel-mmss";
@@ -122,6 +132,7 @@
compatible = "arm,coresight-stm";
reg = <0xfc321000 0x1000>,
<0xfa280000 0x180000>;
+ reg-names = "stm-base", "stm-data-base";
coresight-id = <9>;
coresight-name = "coresight-stm";
@@ -134,6 +145,7 @@
etm0: etm@fc33c000 {
compatible = "arm,coresight-etm";
reg = <0xfc33c000 0x1000>;
+ reg-names = "etm0-base";
coresight-id = <10>;
coresight-name = "coresight-etm0";
@@ -149,6 +161,7 @@
etm1: etm@fc33d000 {
compatible = "arm,coresight-etm";
reg = <0xfc33d000 0x1000>;
+ reg-names = "etm1-base";
coresight-id = <11>;
coresight-name = "coresight-etm1";
@@ -164,6 +177,7 @@
etm2: etm@fc33e000 {
compatible = "arm,coresight-etm";
reg = <0xfc33e000 0x1000>;
+ reg-names = "etm2-base";
coresight-id = <12>;
coresight-name = "coresight-etm2";
@@ -179,6 +193,7 @@
etm3: etm@fc33f000 {
compatible = "arm,coresight-etm";
reg = <0xfc33f000 0x1000>;
+ reg-names = "etm3-base";
coresight-id = <13>;
coresight-name = "coresight-etm3";
@@ -194,6 +209,7 @@
csr: csr@fc302000 {
compatible = "qcom,coresight-csr";
reg = <0xfc302000 0x1000>;
+ reg-names = "csr-base";
coresight-id = <14>;
coresight-name = "coresight-csr";
diff --git a/arch/arm/boot/dts/msm8974-fluid.dtsi b/arch/arm/boot/dts/msm8974-fluid.dtsi
index 7cc10e2..11c835f 100644
--- a/arch/arm/boot/dts/msm8974-fluid.dtsi
+++ b/arch/arm/boot/dts/msm8974-fluid.dtsi
@@ -207,7 +207,10 @@
&slim_msm {
taiko_codec {
+ qcom,cdc-micbias1-ext-cap;
qcom,cdc-micbias2-ext-cap;
+ qcom,cdc-micbias3-ext-cap;
+ qcom,cdc-micbias4-ext-cap;
};
};
diff --git a/arch/arm/boot/dts/msm8974-gpu.dtsi b/arch/arm/boot/dts/msm8974-gpu.dtsi
index ef4f611..ceba72f 100644
--- a/arch/arm/boot/dts/msm8974-gpu.dtsi
+++ b/arch/arm/boot/dts/msm8974-gpu.dtsi
@@ -22,7 +22,8 @@
qcom,chipid = <0x03030000>;
- qcom,initial-pwrlevel = <1>;
+ qcom,initial-pwrlevel = <2>;
+ qcom,step-pwrlevel = <2>;
qcom,idle-timeout = <8>; //<HZ/12>
qcom,nap-allowed = <1>;
@@ -31,13 +32,15 @@
/* Bus Scale Settings */
qcom,msm-bus,name = "grp3d";
- qcom,msm-bus,num-cases = <4>;
+ qcom,msm-bus,num-cases = <6>;
qcom,msm-bus,active-only = <0>;
qcom,msm-bus,num-paths = <2>;
qcom,msm-bus,vectors-KBps =
<26 512 0 0>, <89 604 0 0>,
<26 512 0 2200000>, <89 604 0 3000000>,
+ <26 512 0 4000000>, <89 604 0 3000000>,
<26 512 0 4000000>, <89 604 0 4500000>,
+ <26 512 0 6400000>, <89 604 0 4500000>,
<26 512 0 6400000>, <89 604 0 7600000>;
/* GDSC oxili regulators */
@@ -58,26 +61,40 @@
qcom,gpu-pwrlevel@0 {
reg = <0>;
qcom,gpu-freq = <450000000>;
- qcom,bus-freq = <3>;
+ qcom,bus-freq = <5>;
qcom,io-fraction = <0>;
};
qcom,gpu-pwrlevel@1 {
reg = <1>;
qcom,gpu-freq = <300000000>;
- qcom,bus-freq = <2>;
+ qcom,bus-freq = <4>;
qcom,io-fraction = <33>;
};
qcom,gpu-pwrlevel@2 {
reg = <2>;
+ qcom,gpu-freq = <300000000>;
+ qcom,bus-freq = <3>;
+ qcom,io-fraction = <33>;
+ };
+
+ qcom,gpu-pwrlevel@3 {
+ reg = <3>;
+ qcom,gpu-freq = <200000000>;
+ qcom,bus-freq = <2>;
+ qcom,io-fraction = <100>;
+ };
+
+ qcom,gpu-pwrlevel@4 {
+ reg = <4>;
qcom,gpu-freq = <200000000>;
qcom,bus-freq = <1>;
qcom,io-fraction = <100>;
};
- qcom,gpu-pwrlevel@3 {
- reg = <3>;
+ qcom,gpu-pwrlevel@5 {
+ reg = <5>;
qcom,gpu-freq = <27000000>;
qcom,bus-freq = <0>;
qcom,io-fraction = <0>;
diff --git a/arch/arm/boot/dts/msm8974-ion.dtsi b/arch/arm/boot/dts/msm8974-ion.dtsi
index 7bb2837..f55cff2 100644
--- a/arch/arm/boot/dts/msm8974-ion.dtsi
+++ b/arch/arm/boot/dts/msm8974-ion.dtsi
@@ -37,7 +37,7 @@
reg = <27>;
qcom,heap-align = <0x1000>;
qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
- qcom,memory-reservation-size = <0x780000>;
+ qcom,memory-reservation-size = <0x1100000>;
};
qcom,ion-heap@28 { /* AUDIO HEAP */
diff --git a/arch/arm/boot/dts/msm8974-liquid.dtsi b/arch/arm/boot/dts/msm8974-liquid.dtsi
index 76b23a1..08e4236 100644
--- a/arch/arm/boot/dts/msm8974-liquid.dtsi
+++ b/arch/arm/boot/dts/msm8974-liquid.dtsi
@@ -210,6 +210,11 @@
enable-active-high;
};
+ bt_ar3002 {
+ compatible = "qca,ar3002";
+ qca,bt-reset-gpio = <&pm8941_gpios 34 0>;
+ };
+
sound {
qcom,model = "msm8974-taiko-liquid-snd-card";
@@ -585,6 +590,7 @@
&slim_msm {
taiko_codec {
qcom,cdc-micbias2-ext-cap;
+ qcom,cdc-micbias3-ext-cap;
};
};
diff --git a/arch/arm/boot/dts/msm8974-mtp.dtsi b/arch/arm/boot/dts/msm8974-mtp.dtsi
index ea57389..50fd6ff 100644
--- a/arch/arm/boot/dts/msm8974-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974-mtp.dtsi
@@ -11,7 +11,7 @@
*/
/include/ "dsi-panel-toshiba-720p-video.dtsi"
-/include/ "msm8974-camera-sensor.dtsi"
+/include/ "msm8974-camera-sensor-cdp-mtp.dtsi"
/include/ "msm8974-leds.dtsi"
/ {
@@ -512,7 +512,9 @@
&slim_msm {
taiko_codec {
+ qcom,cdc-micbias1-ext-cap;
qcom,cdc-micbias2-ext-cap;
+ qcom,cdc-micbias4-ext-cap;
};
};
diff --git a/arch/arm/boot/dts/msm8974-rumi.dtsi b/arch/arm/boot/dts/msm8974-rumi.dtsi
index 932c11c..ce9d6c9 100644
--- a/arch/arm/boot/dts/msm8974-rumi.dtsi
+++ b/arch/arm/boot/dts/msm8974-rumi.dtsi
@@ -11,7 +11,7 @@
*/
/include/ "msm8974-leds.dtsi"
-/include/ "msm8974-camera-sensor.dtsi"
+/include/ "msm8974-camera-sensor-cdp-mtp.dtsi"
/ {
timer {
diff --git a/arch/arm/boot/dts/msm8974-sim.dtsi b/arch/arm/boot/dts/msm8974-sim.dtsi
index fb638f7..a5606b8 100644
--- a/arch/arm/boot/dts/msm8974-sim.dtsi
+++ b/arch/arm/boot/dts/msm8974-sim.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -12,7 +12,7 @@
/include/ "dsi-panel-sim-video.dtsi"
/include/ "msm8974-leds.dtsi"
-/include/ "msm8974-camera-sensor.dtsi"
+/include/ "msm8974-camera-sensor-cdp-mtp.dtsi"
/ {
qcom,mdss_dsi@fd922800 {
diff --git a/arch/arm/boot/dts/msm8974-v1-cdp.dts b/arch/arm/boot/dts/msm8974-v1-cdp.dts
index 15ff424..33bd1fb 100644
--- a/arch/arm/boot/dts/msm8974-v1-cdp.dts
+++ b/arch/arm/boot/dts/msm8974-v1-cdp.dts
@@ -20,3 +20,8 @@
compatible = "qcom,msm8974-cdp", "qcom,msm8974";
qcom,msm-id = <126 1 0>;
};
+
+&ehci {
+ status = "ok";
+ vbus-supply = <&usb2_otg_sw>;
+};
diff --git a/arch/arm/boot/dts/msm8974-v1-pm.dtsi b/arch/arm/boot/dts/msm8974-v1-pm.dtsi
index f9b9e33..2de5fad 100644
--- a/arch/arm/boot/dts/msm8974-v1-pm.dtsi
+++ b/arch/arm/boot/dts/msm8974-v1-pm.dtsi
@@ -419,13 +419,9 @@
<40 95>;
};
- qcom,pc-cntr@fe805664 {
- compatible = "qcom,pc-cntr";
- reg = <0xfe805664 0x40>;
- };
-
- qcom,pm-8x60 {
+ qcom,pm-8x60@fe805664 {
compatible = "qcom,pm-8x60";
+ reg = <0xfe805664 0x40>;
qcom,pc-mode = <0>; /*MSM_PC_TZ_L2_INT */
qcom,use-sync-timer;
};
diff --git a/arch/arm/boot/dts/msm8974-v1.dtsi b/arch/arm/boot/dts/msm8974-v1.dtsi
index 7930547..b85c7a5 100644
--- a/arch/arm/boot/dts/msm8974-v1.dtsi
+++ b/arch/arm/boot/dts/msm8974-v1.dtsi
@@ -36,3 +36,12 @@
&tsens {
qcom,calibration-less-mode;
};
+
+/* I2C clock frequency overrides */
+&i2c_0 {
+ qcom,i2c-src-freq = <19200000>;
+};
+
+&i2c_2 {
+ qcom,i2c-src-freq = <19200000>;
+};
diff --git a/arch/arm/boot/dts/msm8974-v2-iommu.dtsi b/arch/arm/boot/dts/msm8974-v2-iommu.dtsi
index 584869d..c974884 100644
--- a/arch/arm/boot/dts/msm8974-v2-iommu.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2-iommu.dtsi
@@ -71,6 +71,7 @@
};
venus_sec_bitstream: qcom,iommu-ctx@fdc8d000 {
+ qcom,iommu-ctx-sids = <0x80 0x81 0x82 0x83 0x84>;
label = "venus_sec_bitstream";
};
diff --git a/arch/arm/boot/dts/msm8974-v2.dtsi b/arch/arm/boot/dts/msm8974-v2.dtsi
index 95a1de8..a245d8a 100644
--- a/arch/arm/boot/dts/msm8974-v2.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2.dtsi
@@ -43,9 +43,13 @@
/* Off */
<26 512 0 0>, <89 604 0 0>,
/* SVS */
- <26 512 0 2504000>, <89 604 0 2400000>,
+ <26 512 0 2400000>, <89 604 0 3000000>,
+ /* Nominal / SVS */
+ <26 512 0 4656000>, <89 604 0 3000000>,
/* Nominal */
- <26 512 0 5016000>, <89 604 0 5334880>,
+ <26 512 0 4656000>, <89 604 0 5334880>,
+ /* Turbo / Nominal */
+ <26 512 0 7464000>, <89 604 0 5334880>,
/* Turbo */
<26 512 0 7464000>, <89 604 0 6400000>;
};
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 3be174f..3b5b062 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -25,6 +25,11 @@
compatible = "qcom,msm8974";
interrupt-parent = <&intc>;
+ aliases {
+ spi0 = &spi_0;
+ spi7 = &spi_7;
+ };
+
intc: interrupt-controller@F9000000 {
compatible = "qcom,msm-qgic2";
interrupt-controller;
@@ -60,6 +65,11 @@
clock-frequency = <19200000>;
};
+ qcom,mpm-counter@fc4a3000 {
+ compatible = "qcom,mpm-counter";
+ reg = <0xfc4a3000 0x1000>;
+ };
+
qcom,vidc@fdc00000 {
compatible = "qcom,msm-vidc";
reg = <0xfdc00000 0xff000>;
@@ -376,9 +386,8 @@
qcom,bam-dma-res-pipes = <6>;
};
- spi_epm: spi@f9966000 {
+ spi_7: spi_epm: spi@f9966000 {
compatible = "qcom,spi-qup-v2";
- cell-index = <7>;
reg = <0xf9966000 0x1000>;
interrupts = <0 104 0>;
spi-max-frequency = <19200000>;
@@ -541,7 +550,7 @@
qcom,pmic-arb-channel = <0>;
};
- i2c@f9967000 { /* BLSP#11 */
+ i2c_0: i2c@f9967000 { /* BLSP#11 */
cell-index = <0>;
compatible = "qcom,i2c-qup";
reg = <0Xf9967000 0x1000>;
@@ -551,10 +560,10 @@
interrupts = <0 105 0>;
interrupt-names = "qup_err_intr";
qcom,i2c-bus-freq = <100000>;
- qcom,i2c-src-freq = <19200000>;
+ qcom,i2c-src-freq = <50000000>;
};
- i2c@f9924000 {
+ i2c_2: i2c@f9924000 {
cell-index = <2>;
compatible = "qcom,i2c-qup";
reg = <0xf9924000 0x1000>;
@@ -564,11 +573,10 @@
interrupts = <0 96 0>;
interrupt-names = "qup_err_intr";
qcom,i2c-bus-freq = <100000>;
- qcom,i2c-src-freq = <19200000>;
+ qcom,i2c-src-freq = <50000000>;
};
- spi@f9923000 {
- cell-index = <0>;
+ spi_0: spi@f9923000 {
compatible = "qcom,spi-qup-v2";
reg = <0xf9923000 0x1000>;
interrupts = <0 95 0>;
@@ -662,6 +670,13 @@
qcom,msm-pcm {
compatible = "qcom,msm-pcm-dsp";
+ qcom,msm-pcm-dsp-id = <0>;
+ };
+
+ qcom,msm-pcm-low-latency {
+ compatible = "qcom,msm-pcm-dsp";
+ qcom,msm-pcm-dsp-id = <1>;
+ qcom,msm-pcm-low-latency;
};
qcom,msm-pcm-routing {
@@ -940,15 +955,9 @@
};
partition@80000 {
- reg = <0x80000 0xA0000>;
+ reg = <0x100000 0x80000>;
qcom,ocmem-part-name = "lp_audio";
- qcom,ocmem-part-min = <0xA0000>;
- };
-
- partition@E0000 {
- reg = <0x120000 0x20000>;
- qcom,ocmem-part-name = "other_os";
- qcom,ocmem-part-min = <0x20000>;
+ qcom,ocmem-part-min = <0x80000>;
};
partition@100000 {
@@ -957,11 +966,6 @@
qcom,ocmem-part-min = <0x55000>;
};
- partition@140000 {
- reg = <0x140000 0x40000>;
- qcom,ocmem-part-name = "sensors";
- qcom,ocmem-part-min = <0x40000>;
- };
};
rpm_bus: qcom,rpm-smd {
diff --git a/arch/arm/boot/dts/msm9625-coresight.dtsi b/arch/arm/boot/dts/msm9625-coresight.dtsi
index 7a5aa5c..6a52361 100644
--- a/arch/arm/boot/dts/msm9625-coresight.dtsi
+++ b/arch/arm/boot/dts/msm9625-coresight.dtsi
@@ -15,9 +15,10 @@
compatible = "arm,coresight-tmc";
reg = <0xfc322000 0x1000>,
<0xfc37c000 0x3000>;
+ reg-names = "tmc-etr-base", "tmc-etr-bam-base";
qcom,memory-reservation-type = "EBI1";
- qcom,memory-reservation-size = <0x100000>; /* 1M EBI1 buffer */
+ qcom,memory-reservation-size = <0x20000>; /* 128K EBI1 buffer */
coresight-id = <0>;
coresight-name = "coresight-tmc-etr";
@@ -27,6 +28,7 @@
tpiu: tpiu@fc318000 {
compatible = "arm,coresight-tpiu";
reg = <0xfc318000 0x1000>;
+ reg-names = "tpiu-base";
coresight-id = <1>;
coresight-name = "coresight-tpiu";
@@ -36,6 +38,7 @@
replicator: replicator@fc31c000 {
compatible = "qcom,coresight-replicator";
reg = <0xfc31c000 0x1000>;
+ reg-names = "replicator-base";
coresight-id = <2>;
coresight-name = "coresight-replicator";
@@ -48,6 +51,7 @@
tmc_etf: tmc@fc307000 {
compatible = "arm,coresight-tmc";
reg = <0xfc307000 0x1000>;
+ reg-names = "tmc-etf-base";
coresight-id = <3>;
coresight-name = "coresight-tmc-etf";
@@ -61,6 +65,7 @@
funnel_merg: funnel@fc31b000 {
compatible = "arm,coresight-funnel";
reg = <0xfc31b000 0x1000>;
+ reg-names = "funnel-merg-base";
coresight-id = <4>;
coresight-name = "coresight-funnel-merg";
@@ -73,6 +78,7 @@
funnel_in0: funnel@fc319000 {
compatible = "arm,coresight-funnel";
reg = <0xfc319000 0x1000>;
+ reg-names = "funnel-in0-base";
coresight-id = <5>;
coresight-name = "coresight-funnel-in0";
@@ -85,6 +91,7 @@
funnel_in1: funnel@fc31a000 {
compatible = "arm,coresight-funnel";
reg = <0xfc31a000 0x1000>;
+ reg-names = "funnel-in1-base";
coresight-id = <6>;
coresight-name = "coresight-funnel-in1";
@@ -98,6 +105,7 @@
compatible = "arm,coresight-stm";
reg = <0xfc321000 0x1000>,
<0xfa280000 0x180000>;
+ reg-names = "stm-base", "stm-data-base";
coresight-id = <7>;
coresight-name = "coresight-stm";
@@ -110,6 +118,7 @@
etm: etm@fc332000 {
compatible = "arm,coresight-etm";
reg = <0xfc332000 0x1000>;
+ reg-names = "etm-base";
coresight-id = <8>;
coresight-name = "coresight-etm";
@@ -124,6 +133,7 @@
csr: csr@fc302000 {
compatible = "qcom,coresight-csr";
reg = <0xfc302000 0x1000>;
+ reg-names = "csr-base";
coresight-id = <9>;
coresight-name = "coresight-csr";
diff --git a/arch/arm/boot/dts/msm9625-pm.dtsi b/arch/arm/boot/dts/msm9625-pm.dtsi
index 793d27b..1880965 100644
--- a/arch/arm/boot/dts/msm9625-pm.dtsi
+++ b/arch/arm/boot/dts/msm9625-pm.dtsi
@@ -189,8 +189,38 @@
qcom,gic-parent = <&intc>;
qcom,gic-map = <47 172>, /* usb2_hsic_async_wakeup_irq */
- <62 222>, /* ee0_krait_hlos_spmi_periph_irq */
- <0xff 208>; /* summary_irq_kpss */
+ <41 180>, /* usb_async_wakeup_irq */
+ <62 222>, /* ee0_krait_hlos_spmi_periph_irq */
+ <0xff 57>, /* mss_to_apps_irq(0) */
+ <0xff 58>, /* mss_to_apps_irq(1) */
+ <0xff 59>, /* mss_to_apps_irq(2) */
+ <0xff 60>, /* mss_to_apps_irq(3) */
+ <0xff 173>, /* o_wcss_apss_smd_hi */
+ <0xff 174>, /* o_wcss_apss_smd_med */
+ <0xff 175>, /* o_wcss_apss_smd_lo */
+ <0xff 176>, /* o_wcss_apss_smsm_irq */
+ <0xff 177>, /* o_wcss_apss_wlan_data_xfer_done */
+ <0xff 178>, /* o_wcss_apss_wlan_rx_data_avail */
+ <0xff 179>, /* o_wcss_apss_asic_intr */
+ <0xff 188>, /* q6ss_irq_out(4) */
+ <0xff 189>, /* q6ss_irq_out(5) */
+ <0xff 190>, /* q6ss_irq_out(6) */
+ <0xff 191>, /* q6ss_irq_out(7) */
+ <0xff 192>, /* audio_out0_irq */
+ <0xff 193>, /* midi_arm_irq */
+ <0xff 194>, /* q6ss_wdog_exp_irq */
+ <0xff 195>, /* slimbus_core_ee1_irq */
+ <0xff 196>, /* bam_irq(1) */
+ <0xff 197>, /* qdss_irq_out(7) */
+ <0xff 200>, /* rpm_ipc(4) */
+ <0xff 201>, /* rpm_ipc(5) */
+ <0xff 202>, /* rpm_ipc(6) */
+ <0xff 203>, /* rpm_ipc(7) */
+ <0xff 204>, /* rpm_ipc(24) */
+ <0xff 205>, /* rpm_ipc(25) */
+ <0xff 206>, /* rpm_ipc(26) */
+ <0xff 207>, /* rpm_ipc(27) */
+ <0xff 240>; /* summary_irq_kpss */
qcom,gpio-parent = <&msmgpio>;
qcom,gpio-map = <4 1>,
@@ -235,6 +265,17 @@
qcom,use-sync-timer;
};
+ qcom,rpm-log@fc19dc00 {
+ compatible = "qcom,rpm-log";
+ reg = <0xfc19dc00 0x4000>;
+ qcom,rpm-addr-phys = <0xfc000000>;
+ qcom,offset-version = <4>;
+ qcom,offset-page-buffer-addr = <36>;
+ qcom,offset-log-len = <40>;
+ qcom,offset-log-len-mask = <44>;
+ qcom,offset-page-indices = <56>;
+ };
+
qcom,rpm-stats@fc19dbd0 {
compatible = "qcom,rpm-stats";
reg = <0xfc19dbd0 0x1000>;
diff --git a/arch/arm/boot/dts/msm9625-v2-1-cdp.dts b/arch/arm/boot/dts/msm9625-v2-1-cdp.dts
new file mode 100644
index 0000000..8702184
--- /dev/null
+++ b/arch/arm/boot/dts/msm9625-v2-1-cdp.dts
@@ -0,0 +1,99 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+/include/ "msm9625-v2-1.dtsi"
+
+/ {
+ model = "Qualcomm MSM 9625V2.1 CDP";
+ compatible = "qcom,msm9625-cdp", "qcom,msm9625";
+ qcom,msm-id = <134 1 0x20001>, <152 1 0x20001>, <149 1 0x20001>,
+ <150 1 0x20001>, <151 1 0x20001>, <148 1 0x20001>,
+ <173 1 0x20001>, <174 1 0x20001>, <175 1 0x20001>;
+
+ i2c@f9925000 {
+ charger@57 {
+ compatible = "summit,smb137c";
+ reg = <0x57>;
+ summit,chg-current-ma = <1500>;
+ summit,term-current-ma = <50>;
+ summit,pre-chg-current-ma = <100>;
+ summit,float-voltage-mv = <4200>;
+ summit,thresh-voltage-mv = <3000>;
+ summit,recharge-thresh-mv = <75>;
+ summit,system-voltage-mv = <4250>;
+ summit,charging-timeout = <382>;
+ summit,pre-charge-timeout = <48>;
+ summit,therm-current-ua = <10>;
+ summit,temperature-min = <4>; /* 0 C */
+ summit,temperature-max = <3>; /* 45 C */
+ };
+ };
+
+ wlan0: qca,wlan {
+ cell-index = <0>;
+ compatible = "qca,ar6004-sdio";
+ qca,chip-pwd-l-gpios = <&msmgpio 62 0>;
+ qca,pm-enable-gpios = <&pm8019_gpios 3 0x0>;
+ qca,ar6004-vdd-io-supply = <&pm8019_l11>;
+ };
+};
+
+/* PM8019 GPIO and MPP configuration */
+&pm8019_gpios {
+ gpio@c000 { /* GPIO 1 */
+ };
+
+ gpio@c100 { /* GPIO 2 */
+ };
+
+ gpio@c200 { /* GPIO 3 */
+ };
+
+ gpio@c300 { /* GPIO 4 */
+ /* ext_2p95v regulator enable config */
+ qcom,mode = <1>; /* Digital output */
+ qcom,output-type = <0>; /* CMOS */
+ qcom,invert = <0>; /* Output low */
+ qcom,out-strength = <1>; /* Low */
+ qcom,vin-sel = <2>; /* PM8019 L11 - 1.8V */
+ qcom,src-sel = <0>; /* Constant */
+ qcom,master-en = <1>; /* Enable GPIO */
+ };
+
+ gpio@c400 { /* GPIO 5 */
+ };
+
+ gpio@c500 { /* GPIO 6 */
+ };
+};
+
+&pm8019_mpps {
+ mpp@a000 { /* MPP 1 */
+ };
+
+ mpp@a100 { /* MPP 2 */
+ };
+
+ mpp@a200 { /* MPP 3 */
+ };
+
+ mpp@a300 { /* MPP 4 */
+ };
+
+ mpp@a400 { /* MPP 5 */
+ };
+
+ mpp@a500 { /* MPP 6 */
+ };
+};
diff --git a/arch/arm/boot/dts/msm9625-v2-1-mtp.dts b/arch/arm/boot/dts/msm9625-v2-1-mtp.dts
new file mode 100644
index 0000000..2dc040c
--- /dev/null
+++ b/arch/arm/boot/dts/msm9625-v2-1-mtp.dts
@@ -0,0 +1,99 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+/include/ "msm9625-v2-1.dtsi"
+
+/ {
+ model = "Qualcomm MSM 9625V2.1 MTP";
+ compatible = "qcom,msm9625-mtp", "qcom,msm9625";
+ qcom,msm-id = <134 7 0x20001>, <152 7 0x20001>, <149 7 0x20001>,
+ <150 7 0x20001>, <151 7 0x20001>, <148 7 0x20001>,
+ <173 7 0x20001>, <174 7 0x20001>, <175 7 0x20001>;
+
+ i2c@f9925000 {
+ charger@57 {
+ compatible = "summit,smb137c";
+ reg = <0x57>;
+ summit,chg-current-ma = <1500>;
+ summit,term-current-ma = <50>;
+ summit,pre-chg-current-ma = <100>;
+ summit,float-voltage-mv = <4200>;
+ summit,thresh-voltage-mv = <3000>;
+ summit,recharge-thresh-mv = <75>;
+ summit,system-voltage-mv = <4250>;
+ summit,charging-timeout = <382>;
+ summit,pre-charge-timeout = <48>;
+ summit,therm-current-ua = <10>;
+ summit,temperature-min = <4>; /* 0 C */
+ summit,temperature-max = <3>; /* 45 C */
+ };
+ };
+
+ wlan0: qca,wlan {
+ cell-index = <0>;
+ compatible = "qca,ar6004-sdio";
+ qca,chip-pwd-l-gpios = <&msmgpio 62 0>;
+ qca,pm-enable-gpios = <&pm8019_gpios 3 0x0>;
+ qca,ar6004-vdd-io-supply = <&pm8019_l11>;
+ };
+};
+
+/* PM8019 GPIO and MPP configuration */
+&pm8019_gpios {
+ gpio@c000 { /* GPIO 1 */
+ };
+
+ gpio@c100 { /* GPIO 2 */
+ };
+
+ gpio@c200 { /* GPIO 3 */
+ };
+
+ gpio@c300 { /* GPIO 4 */
+ /* ext_2p95v regulator enable config */
+ qcom,mode = <1>; /* Digital output */
+ qcom,output-type = <0>; /* CMOS */
+ qcom,invert = <0>; /* Output low */
+ qcom,out-strength = <1>; /* Low */
+ qcom,vin-sel = <2>; /* PM8019 L11 - 1.8V */
+ qcom,src-sel = <0>; /* Constant */
+ qcom,master-en = <1>; /* Enable GPIO */
+ };
+
+ gpio@c400 { /* GPIO 5 */
+ };
+
+ gpio@c500 { /* GPIO 6 */
+ };
+};
+
+&pm8019_mpps {
+ mpp@a000 { /* MPP 1 */
+ };
+
+ mpp@a100 { /* MPP 2 */
+ };
+
+ mpp@a200 { /* MPP 3 */
+ };
+
+ mpp@a300 { /* MPP 4 */
+ };
+
+ mpp@a400 { /* MPP 5 */
+ };
+
+ mpp@a500 { /* MPP 6 */
+ };
+};
diff --git a/arch/arm/boot/dts/msm9625-v2-1.dtsi b/arch/arm/boot/dts/msm9625-v2-1.dtsi
new file mode 100644
index 0000000..c3c2c49
--- /dev/null
+++ b/arch/arm/boot/dts/msm9625-v2-1.dtsi
@@ -0,0 +1,36 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * As a general rule, only version-specific property overrides should be placed
+ * inside this file. However, device definitions should be placed inside the
+ * msm9625.dtsi file.
+ */
+
+/include/ "msm9625.dtsi"
+
+/ {
+ qcom,msm-imem@fe807800 {
+ compatible = "qcom,msm-imem";
+ reg = <0xfe807800 0x1000>; /* Address and size of IMEM */
+ };
+
+ android_usb@fe8078c8 {
+ compatible = "qcom,android-usb";
+ reg = <0xfe8078c8 0xc8>;
+ qcom,android-usb-swfi-latency = <100>;
+ };
+};
+
+&ipa_hw {
+ qcom,ipa-hw-ver = <2>; /* IPA h-w revision */
+};
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index d5a33ee..9247826 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -21,6 +21,10 @@
compatible = "qcom,msm9625";
interrupt-parent = <&intc>;
+ aliases {
+ spi0 = &spi_0;
+ };
+
intc: interrupt-controller@F9000000 {
compatible = "qcom,msm-qgic2";
interrupt-controller;
@@ -186,8 +190,7 @@
interrupt-names = "bam_irq";
};
- spi@f9924000 {
- cell-index = <0>;
+ spi_0: spi@f9924000 {
compatible = "qcom,spi-qup-v2";
reg = <0xf9924000 0x1000>;
interrupts = <0 96 0>;
@@ -584,6 +587,28 @@
compatible = "qcom,msm-stub-codec";
};
+ qcom,msm-auxpcm {
+ compatible = "qcom,msm-auxpcm-resource";
+ qcom,msm-cpudai-auxpcm-clk = "pcm_clk";
+ qcom,msm-cpudai-auxpcm-mode = <0>, <0>;
+ qcom,msm-cpudai-auxpcm-sync = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-frame = <5>, <4>;
+ qcom,msm-cpudai-auxpcm-quant = <2>, <2>;
+ qcom,msm-cpudai-auxpcm-slot = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-data = <0>, <0>;
+ qcom,msm-cpudai-auxpcm-pcm-clk-rate = <2048000>, <2048000>;
+
+ qcom,msm-auxpcm-rx {
+ qcom,msm-auxpcm-dev-id = <4106>;
+ compatible = "qcom,msm-auxpcm-dev";
+ };
+
+ qcom,msm-auxpcm-tx {
+ qcom,msm-auxpcm-dev-id = <4107>;
+ compatible = "qcom,msm-auxpcm-dev";
+ };
+ };
+
qcom,msm-dai-mi2s {
compatible = "qcom,msm-dai-mi2s";
qcom,msm-dai-q6-mi2s-prim {
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index 1623d45..896055d 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -139,12 +139,16 @@
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_QUP=y
CONFIG_WCD9306_CODEC=y
+CONFIG_GPIO_QPNP_PIN=y
# CONFIG_HWMON is not set
+CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
+CONFIG_SENSORS_QPNP_ADC_CURRENT=y
CONFIG_REGULATOR=y
CONFIG_REGULATOR_STUB=y
CONFIG_REGULATOR_QPNP=y
CONFIG_ION=y
CONFIG_ION_MSM=y
+CONFIG_MSM_KGSL=y
CONFIG_FB=y
CONFIG_FB_VIRTUAL=y
CONFIG_SOUND=y
@@ -172,6 +176,7 @@
CONFIG_ANDROID_TIMED_GPIO=y
CONFIG_ANDROID_LOW_MEMORY_KILLER=y
CONFIG_MSM_IOMMU=y
+CONFIG_MSM_IOMMU_PMON=y
CONFIG_SPS=y
CONFIG_SPS_SUPPORT_NDP_BAM=y
CONFIG_MMC_MSM_SPS_SUPPORT=y
@@ -218,3 +223,4 @@
CONFIG_MSM_OCMEM_NONSECURE=y
CONFIG_THERMAL=y
CONFIG_THERMAL_TSENS8974=y
+CONFIG_THERMAL_MONITOR=y
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index 053e1ca..7362ea0 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -134,6 +134,8 @@
CONFIG_IP_PNP_DHCP=y
CONFIG_INET_AH=y
CONFIG_INET_ESP=y
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
# CONFIG_INET_LRO is not set
CONFIG_IPV6=y
CONFIG_IPV6_PRIVACY=y
@@ -522,6 +524,7 @@
CONFIG_CRYPTO_TEST=m
CONFIG_CRYPTO_CTR=y
CONFIG_CRYPTO_CTS=y
+CONFIG_CRYPTO_XCBC=y
CONFIG_CRYPTO_TWOFISH=y
CONFIG_CRYPTO_DEV_QCRYPTO=m
CONFIG_CRYPTO_DEV_QCE=m
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index 7b54eb4..bb34075 100644
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -139,6 +139,8 @@
CONFIG_IP_PNP_DHCP=y
CONFIG_INET_AH=y
CONFIG_INET_ESP=y
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
# CONFIG_INET_LRO is not set
CONFIG_IPV6=y
CONFIG_IPV6_PRIVACY=y
@@ -539,6 +541,7 @@
CONFIG_CRYPTO_TEST=m
CONFIG_CRYPTO_CTR=y
CONFIG_CRYPTO_CTS=y
+CONFIG_CRYPTO_XCBC=y
CONFIG_CRYPTO_TWOFISH=y
CONFIG_CRYPTO_DEV_QCRYPTO=m
CONFIG_CRYPTO_DEV_QCE=m
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index bd7c1a0..952171c 100644
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -35,6 +35,8 @@
CONFIG_MODVERSIONS=y
CONFIG_PARTITION_ADVANCED=y
CONFIG_EFI_PARTITION=y
+CONFIG_IOSCHED_TEST=y
+CONFIG_DEFAULT_ROW=y
CONFIG_ARCH_MSM=y
CONFIG_ARCH_MSM8974=y
CONFIG_MSM_KRAIT_TBB_ABORT_HANDLER=y
@@ -69,7 +71,6 @@
CONFIG_MSM_OCMEM=y
CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y
CONFIG_MSM_OCMEM_DEBUG=y
-CONFIG_MSM_OCMEM_NONSECURE=y
CONFIG_MSM_RTB=y
CONFIG_MSM_RTB_SEPARATE_CPUS=y
CONFIG_MSM_CACHE_ERP=y
@@ -107,14 +108,17 @@
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
+CONFIG_XFRM_USER=y
CONFIG_INET=y
CONFIG_IP_ADVANCED_ROUTER=y
CONFIG_IP_MULTIPLE_TABLES=y
CONFIG_IP_ROUTE_VERBOSE=y
CONFIG_IP_PNP=y
CONFIG_IP_PNP_DHCP=y
-# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+CONFIG_INET_AH=y
+CONFIG_INET_ESP=y
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
# CONFIG_INET_XFRM_MODE_BEET is not set
# CONFIG_INET_LRO is not set
CONFIG_IPV6=y
@@ -224,11 +228,12 @@
CONFIG_BT_HCISMD=y
CONFIG_MSM_BT_POWER=y
CONFIG_CFG80211=y
-CONFIG_CFG80211_DEFAULT_PS=y
CONFIG_NL80211_TESTMODE=y
CONFIG_RFKILL=y
CONFIG_GENLOCK=y
CONFIG_GENLOCK_MISCDEVICE=y
+CONFIG_SYNC=y
+CONFIG_SW_SYNC=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_RAM=y
CONFIG_HAPTIC_ISA1200=y
@@ -312,25 +317,24 @@
CONFIG_MEDIA_CONTROLLER=y
CONFIG_VIDEO_DEV=y
CONFIG_VIDEO_V4L2_SUBDEV_API=y
-CONFIG_VIDEOBUF2_MSM_MEM=y
-CONFIG_USB_VIDEO_CLASS=y
-CONFIG_V4L_PLATFORM_DRIVERS=y
-CONFIG_MSM_CAMERA=n
+# CONFIG_MSM_CAMERA is not set
CONFIG_MT9M114=y
-CONFIG_MSMB_CAMERA=y
-CONFIG_MSM_VIDC_V4L2=y
CONFIG_OV2720=y
-CONFIG_MSMB_JPEG=y
CONFIG_MSM_CAMERA_SENSOR=y
-CONFIG_MSM_JPEG=y
CONFIG_MSM_CCI=y
+CONFIG_MSM_CPP=y
CONFIG_MSM_CSI30_HEADER=y
CONFIG_MSM_CSIPHY=y
CONFIG_MSM_CSID=y
-CONFIG_MSM_CSI2_REGISTER=y
CONFIG_MSM_ISPIF=y
CONFIG_S5K3L1YX=y
+CONFIG_MSMB_CAMERA=y
+CONFIG_MSMB_JPEG=y
+CONFIG_MSM_VIDC_V4L2=y
CONFIG_MSM_WFD=y
+CONFIG_VIDEOBUF2_MSM_MEM=y
+CONFIG_USB_VIDEO_CLASS=y
+CONFIG_V4L_PLATFORM_DRIVERS=y
CONFIG_RADIO_IRIS=y
CONFIG_RADIO_IRIS_TRANSPORT=m
CONFIG_ION=y
@@ -352,10 +356,13 @@
CONFIG_SND_USB_AUDIO=y
CONFIG_SND_SOC=y
CONFIG_SND_SOC_MSM8974=y
+CONFIG_UHID=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_MAGICMOUSE=y
+CONFIG_HID_MICROSOFT=y
CONFIG_USB_SUSPEND=y
CONFIG_USB_XHCI_HCD=y
CONFIG_USB_EHCI_HCD=y
-CONFIG_USB_EHCI_ROOT_HUB_TT=y
CONFIG_USB_EHCI_EHSET=y
CONFIG_USB_EHCI_MSM=y
CONFIG_USB_EHCI_MSM_HSIC=y
@@ -386,12 +393,11 @@
CONFIG_MMC_BLOCK_MINORS=32
# CONFIG_MMC_BLOCK_BOUNCE is not set
CONFIG_MMC_TEST=m
+CONFIG_MMC_BLOCK_TEST=y
CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_PLTFM=y
CONFIG_MMC_MSM=y
CONFIG_MMC_MSM_SPS_SUPPORT=y
-CONFIG_IOSCHED_TEST=y
-CONFIG_MMC_BLOCK_TEST=y
CONFIG_LEDS_QPNP=y
CONFIG_LEDS_TRIGGERS=y
CONFIG_LEDS_TRIGGER_BACKLIGHT=y
@@ -415,6 +421,8 @@
CONFIG_QPNP_POWER_ON=y
CONFIG_QPNP_CLKDIV=y
CONFIG_MSM_IOMMU=y
+CONFIG_MOBICORE_SUPPORT=m
+CONFIG_MOBICORE_API=m
CONFIG_CORESIGHT=y
CONFIG_CORESIGHT_TMC=y
CONFIG_CORESIGHT_TPIU=y
@@ -447,15 +455,12 @@
CONFIG_DEBUG_USER=y
CONFIG_PID_IN_CONTEXTIDR=y
CONFIG_KEYS=y
+CONFIG_CRYPTO_NULL=y
CONFIG_CRYPTO_MD4=y
CONFIG_CRYPTO_ARC4=y
+CONFIG_CRYPTO_XCBC=y
CONFIG_CRYPTO_TWOFISH=y
CONFIG_CRYPTO_DEV_QCRYPTO=m
CONFIG_CRYPTO_DEV_QCE=m
CONFIG_CRYPTO_DEV_QCEDEV=m
CONFIG_CRC_CCITT=y
-CONFIG_SYNC=y
-CONFIG_SW_SYNC=y
-CONFIG_MOBICORE_SUPPORT=m
-CONFIG_MOBICORE_API=m
-CONFIG_DEFAULT_ROW=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index 6780761..a259414 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -35,6 +35,7 @@
CONFIG_PARTITION_ADVANCED=y
CONFIG_EFI_PARTITION=y
CONFIG_IOSCHED_TEST=y
+CONFIG_DEFAULT_ROW=y
CONFIG_ARCH_MSM=y
CONFIG_ARCH_MSM8974=y
CONFIG_MSM_KRAIT_TBB_ABORT_HANDLER=y
@@ -69,7 +70,6 @@
CONFIG_MSM_OCMEM=y
CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y
CONFIG_MSM_OCMEM_DEBUG=y
-CONFIG_MSM_OCMEM_NONSECURE=y
CONFIG_MSM_RTB=y
CONFIG_MSM_RTB_SEPARATE_CPUS=y
CONFIG_MSM_CACHE_ERP=y
@@ -112,14 +112,17 @@
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
+CONFIG_XFRM_USER=y
CONFIG_INET=y
CONFIG_IP_ADVANCED_ROUTER=y
CONFIG_IP_MULTIPLE_TABLES=y
CONFIG_IP_ROUTE_VERBOSE=y
CONFIG_IP_PNP=y
CONFIG_IP_PNP_DHCP=y
-# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+CONFIG_INET_AH=y
+CONFIG_INET_ESP=y
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
# CONFIG_INET_XFRM_MODE_BEET is not set
# CONFIG_INET_LRO is not set
CONFIG_IPV6=y
@@ -325,6 +328,7 @@
CONFIG_OV2720=y
CONFIG_MSM_CAMERA_SENSOR=y
CONFIG_MSM_CCI=y
+CONFIG_MSM_CPP=y
CONFIG_MSM_CSI30_HEADER=y
CONFIG_MSM_CSIPHY=y
CONFIG_MSM_CSID=y
@@ -360,6 +364,10 @@
CONFIG_SND_USB_AUDIO=y
CONFIG_SND_SOC=y
CONFIG_SND_SOC_MSM8974=y
+CONFIG_UHID=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_MAGICMOUSE=y
+CONFIG_HID_MICROSOFT=y
CONFIG_USB_SUSPEND=y
CONFIG_USB_XHCI_HCD=y
CONFIG_USB_EHCI_HCD=y
@@ -469,11 +477,12 @@
CONFIG_DEBUG_USER=y
CONFIG_PID_IN_CONTEXTIDR=y
CONFIG_KEYS=y
+CONFIG_CRYPTO_NULL=y
CONFIG_CRYPTO_MD4=y
CONFIG_CRYPTO_ARC4=y
+CONFIG_CRYPTO_XCBC=y
CONFIG_CRYPTO_TWOFISH=y
CONFIG_CRYPTO_DEV_QCRYPTO=m
CONFIG_CRYPTO_DEV_QCE=m
CONFIG_CRYPTO_DEV_QCEDEV=m
CONFIG_CRC_CCITT=y
-CONFIG_DEFAULT_ROW=y
diff --git a/arch/arm/configs/msm9625_defconfig b/arch/arm/configs/msm9625_defconfig
index 0f93930..ecf43bb 100644
--- a/arch/arm/configs/msm9625_defconfig
+++ b/arch/arm/configs/msm9625_defconfig
@@ -321,3 +321,4 @@
CONFIG_SCSI_LOGGING=y
CONFIG_SCSI_SCAN_ASYNC=y
CONFIG_MSM_RTB=y
+CONFIG_MSM_MEMORY_DUMP=y
diff --git a/arch/arm/include/asm/thread_info.h b/arch/arm/include/asm/thread_info.h
index 0f04d84..67d6443 100644
--- a/arch/arm/include/asm/thread_info.h
+++ b/arch/arm/include/asm/thread_info.h
@@ -153,7 +153,7 @@
#define TIF_MEMDIE 18 /* is terminating due to OOM killer */
#define TIF_RESTORE_SIGMASK 20
#define TIF_SECCOMP 21
-
+#define TIF_MM_RELEASED 22 /* task MM has been released */
#define _TIF_SIGPENDING (1 << TIF_SIGPENDING)
#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED)
#define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME)
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index 85b1bb3..5311d74 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/arch/arm/kernel/perf_event.c
@@ -739,15 +739,14 @@
armpmu->type = ARM_PMU_DEVICE_CPU;
}
-static int cpu_has_active_perf(void)
+static int cpu_has_active_perf(int cpu)
{
struct pmu_hw_events *hw_events;
int enabled;
if (!cpu_pmu)
return 0;
-
- hw_events = cpu_pmu->get_hw_events();
+ hw_events = &per_cpu(cpu_hw_events, cpu);
enabled = bitmap_weight(hw_events->used_mask, cpu_pmu->num_events);
if (enabled)
@@ -780,7 +779,7 @@
{
int irq;
- if (cpu_has_active_perf()) {
+ if (cpu_has_active_perf((int)hcpu)) {
switch ((action & ~CPU_TASKS_FROZEN)) {
case CPU_DOWN_PREPARE:
@@ -790,7 +789,7 @@
*/
if (cpu_pmu &&
cpu_pmu->plat_device->dev.platform_data) {
- irq = platform_get_irq(cpu_pmu->plat_device, 1);
+ irq = platform_get_irq(cpu_pmu->plat_device, 0);
smp_call_function_single((int)hcpu,
disable_irq_callback, &irq, 1);
}
@@ -803,7 +802,7 @@
*/
if (cpu_pmu &&
cpu_pmu->plat_device->dev.platform_data) {
- irq = platform_get_irq(cpu_pmu->plat_device, 1);
+ irq = platform_get_irq(cpu_pmu->plat_device, 0);
smp_call_function_single((int)hcpu,
enable_irq_callback, &irq, 1);
}
@@ -855,7 +854,7 @@
{
switch (cmd) {
case CPU_PM_ENTER:
- if (cpu_has_active_perf()) {
+ if (cpu_has_active_perf((int)v)) {
armpmu_update_counters();
perf_pmu_disable(&cpu_pmu->pmu);
}
@@ -863,7 +862,7 @@
case CPU_PM_ENTER_FAILED:
case CPU_PM_EXIT:
- if (cpu_has_active_perf() && cpu_pmu->reset) {
+ if (cpu_has_active_perf((int)v) && cpu_pmu->reset) {
/*
* Flip this bit so armpmu_enable knows it needs
* to re-enable active counters.
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 5694a2e..e35a806 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -380,6 +380,7 @@
select CPU_HAS_L2_PMU
select MSM_JTAG_MM if CORESIGHT_ETM
select MEMORY_HOLE_CARVEOUT
+ select MSM_RPM_LOG
config ARCH_MSM8610
bool "MSM8610"
@@ -435,6 +436,7 @@
select MSM_PM8X60 if PM
select MEMORY_HOLE_CARVEOUT
select DONT_MAP_HOLE_AFTER_MEMBANK0
+ select MSM_BUS_SCALING
endmenu
choice
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index ecea32b..cb5e712 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -411,3 +411,5 @@
obj-$(CONFIG_MSM_SMCMOD) += smcmod.o
obj-$(CONFIG_MSM_CPU_PWRCTL) += msm_cpu_pwrctl.o
+
+obj-$(CONFIG_ARCH_MSM8974) += msm_mpmctr.o
diff --git a/arch/arm/mach-msm/Makefile.boot b/arch/arm/mach-msm/Makefile.boot
index b451d08..202b8dd 100644
--- a/arch/arm/mach-msm/Makefile.boot
+++ b/arch/arm/mach-msm/Makefile.boot
@@ -68,6 +68,8 @@
dtb-$(CONFIG_ARCH_MSM9625) += msm9625-v1-rumi.dtb
dtb-$(CONFIG_ARCH_MSM9625) += msm9625-v2-cdp.dtb
dtb-$(CONFIG_ARCH_MSM9625) += msm9625-v2-mtp.dtb
+ dtb-$(CONFIG_ARCH_MSM9625) += msm9625-v2-1-mtp.dtb
+ dtb-$(CONFIG_ARCH_MSM9625) += msm9625-v2-1-cdp.dtb
# MSM8226
zreladdr-$(CONFIG_ARCH_MSM8226) := 0x00008000
diff --git a/arch/arm/mach-msm/acpuclock-8974.c b/arch/arm/mach-msm/acpuclock-8974.c
index d8f5425..5211c6e 100644
--- a/arch/arm/mach-msm/acpuclock-8974.c
+++ b/arch/arm/mach-msm/acpuclock-8974.c
@@ -266,11 +266,17 @@
[0][2] = { acpu_freq_tbl_pvs2, sizeof(acpu_freq_tbl_pvs2) },
[0][3] = { acpu_freq_tbl_pvs3, sizeof(acpu_freq_tbl_pvs3) },
[0][4] = { acpu_freq_tbl_pvs4, sizeof(acpu_freq_tbl_pvs4) },
+ [0][5] = { acpu_freq_tbl_pvs4, sizeof(acpu_freq_tbl_pvs4) },
+ [0][6] = { acpu_freq_tbl_pvs4, sizeof(acpu_freq_tbl_pvs4) },
+ [0][7] = { acpu_freq_tbl_pvs4, sizeof(acpu_freq_tbl_pvs4) },
[1][0] = { acpu_freq_tbl_pvs0, sizeof(acpu_freq_tbl_pvs0) },
[1][1] = { acpu_freq_tbl_pvs1, sizeof(acpu_freq_tbl_pvs1) },
[1][2] = { acpu_freq_tbl_pvs2, sizeof(acpu_freq_tbl_pvs2) },
[1][3] = { acpu_freq_tbl_pvs3, sizeof(acpu_freq_tbl_pvs3) },
[1][4] = { acpu_freq_tbl_pvs4, sizeof(acpu_freq_tbl_pvs4) },
+ [1][5] = { acpu_freq_tbl_pvs4, sizeof(acpu_freq_tbl_pvs4) },
+ [1][6] = { acpu_freq_tbl_pvs4, sizeof(acpu_freq_tbl_pvs4) },
+ [1][7] = { acpu_freq_tbl_pvs4, sizeof(acpu_freq_tbl_pvs4) },
};
static struct acpuclk_krait_params acpuclk_8974_params __initdata = {
diff --git a/arch/arm/mach-msm/acpuclock-krait.h b/arch/arm/mach-msm/acpuclock-krait.h
index 00f64fc..11d58dd 100644
--- a/arch/arm/mach-msm/acpuclock-krait.h
+++ b/arch/arm/mach-msm/acpuclock-krait.h
@@ -50,7 +50,7 @@
PVS_NOMINAL = 1,
PVS_FAST = 3,
PVS_FASTER = 4,
- NUM_PVS = 7
+ NUM_PVS = 8
};
/**
diff --git a/arch/arm/mach-msm/bms-batterydata-desay.c b/arch/arm/mach-msm/bms-batterydata-desay.c
index 5b72a3f..dd3f346 100644
--- a/arch/arm/mach-msm/bms-batterydata-desay.c
+++ b/arch/arm/mach-msm/bms-batterydata-desay.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -83,4 +83,5 @@
.pc_temp_ocv_lut = &desay_5200_pc_temp_ocv,
.pc_sf_lut = &desay_5200_pc_sf,
.default_rbatt_mohm = 156,
+ .rbatt_capacitive_mohm = 50,
};
diff --git a/arch/arm/mach-msm/bms-batterydata.c b/arch/arm/mach-msm/bms-batterydata.c
index 824cf6b..0c39df6 100644
--- a/arch/arm/mach-msm/bms-batterydata.c
+++ b/arch/arm/mach-msm/bms-batterydata.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -105,4 +105,5 @@
.pc_temp_ocv_lut = &pc_temp_ocv,
.rbatt_sf_lut = &rbatt_sf,
.default_rbatt_mohm = 236,
+ .rbatt_capacitive_mohm = 50,
};
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index a89ea61..beb064b 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -2723,7 +2723,6 @@
&apq8064_device_uart_gsbi1,
&apq8064_device_uart_gsbi4,
&msm_device_sps_apq8064,
- &msm8064_pc_cntr,
};
static struct platform_device *common_i2s_devices[] __initdata = {
@@ -2888,7 +2887,6 @@
#ifdef CONFIG_MSM_ROTATOR
&msm_rotator_device,
#endif
- &msm8064_pc_cntr,
};
static struct platform_device
@@ -3861,11 +3859,13 @@
if (cpu_is_apq8064ab())
apq8064ab_update_krait_spm();
if (cpu_is_krait_v3()) {
- msm_pm_set_tz_retention_flag(0);
+ struct msm_pm_init_data_type *pdata =
+ msm8064_pm_8x60.dev.platform_data;
+ pdata->retention_calls_tz = false;
apq8064ab_update_retention_spm();
- } else {
- msm_pm_set_tz_retention_flag(1);
}
+ platform_device_register(&msm8064_pm_8x60);
+
msm_spm_init(msm_spm_data, ARRAY_SIZE(msm_spm_data));
msm_spm_l2_init(msm_spm_l2_data);
BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
diff --git a/arch/arm/mach-msm/board-8226-gpiomux.c b/arch/arm/mach-msm/board-8226-gpiomux.c
index e58cee7..8be5525 100644
--- a/arch/arm/mach-msm/board-8226-gpiomux.c
+++ b/arch/arm/mach-msm/board-8226-gpiomux.c
@@ -42,6 +42,12 @@
.pull = GPIOMUX_PULL_NONE,
};
+static struct gpiomux_setting gpio_spi_cs_config = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_6MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
static struct gpiomux_setting gpio_i2c_config = {
.func = GPIOMUX_FUNC_3,
.drv = GPIOMUX_DRV_2MA,
@@ -50,37 +56,37 @@
static struct msm_gpiomux_config msm_blsp_configs[] __initdata = {
{
- .gpio = 0, /* BLSP1 QUP2 SPI_DATA_MOSI */
+ .gpio = 0, /* BLSP1 QUP1 SPI_DATA_MOSI */
.settings = {
[GPIOMUX_SUSPENDED] = &gpio_spi_config,
},
},
{
- .gpio = 1, /* BLSP1 QUP2 SPI_DATA_MISO */
+ .gpio = 1, /* BLSP1 QUP1 SPI_DATA_MISO */
.settings = {
[GPIOMUX_SUSPENDED] = &gpio_spi_config,
},
},
{
- .gpio = 2, /* BLSP1 QUP2 SPI_CS_N */
+ .gpio = 2, /* BLSP1 QUP1 SPI_CS1 */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_spi_cs_config,
+ },
+ },
+ {
+ .gpio = 3, /* BLSP1 QUP1 SPI_CLK */
.settings = {
[GPIOMUX_SUSPENDED] = &gpio_spi_config,
},
},
{
- .gpio = 3, /* BLSP1 QUP2 SPI_CLK */
- .settings = {
- [GPIOMUX_SUSPENDED] = &gpio_spi_config,
- },
- },
- {
- .gpio = 14, /* BLSP-1 QUP-4 I2C_SDA */
+ .gpio = 14, /* BLSP1 QUP4 I2C_SDA */
.settings = {
[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
},
},
{
- .gpio = 15, /* BLSP-1 QUP-4 I2C_SCL */
+ .gpio = 15, /* BLSP1 QUP4 I2C_SCL */
.settings = {
[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
},
diff --git a/arch/arm/mach-msm/board-8610-gpiomux.c b/arch/arm/mach-msm/board-8610-gpiomux.c
index 5b3d30c..15d7679 100644
--- a/arch/arm/mach-msm/board-8610-gpiomux.c
+++ b/arch/arm/mach-msm/board-8610-gpiomux.c
@@ -23,19 +23,55 @@
.pull = GPIOMUX_PULL_NONE,
};
+static struct gpiomux_setting gpio_spi_config = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_6MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting gpio_spi_cs_config = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_6MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
static struct msm_gpiomux_config msm_blsp_configs[] __initdata = {
{
- .gpio = 10, /* BLSP-1 QUP-3 I2C_SDA */
+ .gpio = 10, /* BLSP1 QUP3 I2C_SDA */
.settings = {
[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
},
},
{
- .gpio = 11, /* BLSP-1 QUP-3 I2C_SCL */
+ .gpio = 11, /* BLSP1 QUP3 I2C_SCL */
.settings = {
[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
},
},
+ {
+ .gpio = 0, /* BLSP1 QUP1 SPI_DATA_MOSI */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_spi_config,
+ },
+ },
+ {
+ .gpio = 1, /* BLSP1 QUP1 SPI_DATA_MISO */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_spi_config,
+ },
+ },
+ {
+ .gpio = 3, /* BLSP1 QUP1 SPI_CLK */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_spi_config,
+ },
+ },
+ {
+ .gpio = 2, /* BLSP1 QUP1 SPI_CS1 */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_spi_cs_config,
+ },
+ },
};
void __init msm8610_init_gpiomux(void)
diff --git a/arch/arm/mach-msm/board-8930-storage.c b/arch/arm/mach-msm/board-8930-storage.c
index d974452..d045040 100644
--- a/arch/arm/mach-msm/board-8930-storage.c
+++ b/arch/arm/mach-msm/board-8930-storage.c
@@ -63,11 +63,9 @@
* hardware revisions - maybe once that is done, this can be
* reverted.
*/
- .always_on = 1,
.lpm_sup = 1,
.hpm_uA = 800000, /* 800mA */
.lpm_uA = 9000,
- .reset_at_init = true,
},
};
@@ -311,13 +309,11 @@
* This change to the boards will be true for newer versions of the SoC
* as well.
*/
- if ((SOCINFO_VERSION_MAJOR(socinfo_get_version()) >= 1 &&
- SOCINFO_VERSION_MINOR(socinfo_get_version()) >= 2) ||
- machine_is_msm8930_cdp()) {
- msm8960_sdc3_data.vreg_data->vdd_data->always_on = false;
- msm8960_sdc3_data.vreg_data->vdd_data->reset_at_init = false;
+ if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 1 &&
+ SOCINFO_VERSION_MINOR(socinfo_get_version()) < 2) {
+ msm8960_sdc3_data.vreg_data->vdd_data->always_on = true;
+ msm8960_sdc3_data.vreg_data->vdd_data->reset_at_init = true;
}
-
/* SDC3: External card slot */
if (!machine_is_msm8930_cdp()) {
msm8960_sdc3_data.wpswitch_gpio = 0;
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index a8e117f..25ba1aa 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -2473,7 +2473,6 @@
&msm8930_iommu_domain_device,
&msm_tsens_device,
&msm8930_cache_dump_device,
- &msm8930_pc_cntr,
};
static struct platform_device *cdp_devices[] __initdata = {
@@ -2955,11 +2954,14 @@
msm8930_i2c_init();
msm8930_init_gpu();
if (cpu_is_krait_v3()) {
- msm_pm_set_tz_retention_flag(0);
+ struct msm_pm_init_data_type *pdata =
+ msm8930_pm_8x60.dev.platform_data;
+ pdata->retention_calls_tz = false;
msm8930ab_update_retention_spm();
- } else {
- msm_pm_set_tz_retention_flag(1);
}
+
+ platform_device_register(&msm8930_pm_8x60);
+
msm_spm_init(msm_spm_data, ARRAY_SIZE(msm_spm_data));
msm_spm_l2_init(msm_spm_l2_data);
msm8930_init_buses();
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index 6524832..95f618a 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -2955,7 +2955,6 @@
&msm8960_cache_dump_device,
&msm8960_iommu_domain_device,
&msm_tsens_device,
- &msm8960_pc_cntr,
};
static struct platform_device *cdp_devices[] __initdata = {
@@ -3488,11 +3487,13 @@
if (cpu_is_msm8960ab())
msm8960ab_update_krait_spm();
if (cpu_is_krait_v3()) {
- msm_pm_set_tz_retention_flag(0);
+ struct msm_pm_init_data_type *pdata =
+ msm8960_pm_8x60.dev.platform_data;
+ pdata->retention_calls_tz = false;
msm8960ab_update_retention_spm();
- } else {
- msm_pm_set_tz_retention_flag(1);
}
+ platform_device_register(&msm8960_pm_8x60);
+
msm_spm_init(msm_spm_data, ARRAY_SIZE(msm_spm_data));
msm_spm_l2_init(msm_spm_l2_data);
diff --git a/arch/arm/mach-msm/board-8974-gpiomux.c b/arch/arm/mach-msm/board-8974-gpiomux.c
index eb99073..b3cc9b7 100644
--- a/arch/arm/mach-msm/board-8974-gpiomux.c
+++ b/arch/arm/mach-msm/board-8974-gpiomux.c
@@ -258,12 +258,6 @@
.dir = GPIOMUX_OUT_HIGH,
};
-static struct gpiomux_setting mhl_active_2_cfg = {
- .func = GPIOMUX_FUNC_1,
- .drv = GPIOMUX_DRV_2MA,
- .pull = GPIOMUX_PULL_UP,
-};
-
static struct gpiomux_setting hdmi_suspend_cfg = {
.func = GPIOMUX_FUNC_GPIO,
.drv = GPIOMUX_DRV_2MA,
@@ -299,14 +293,6 @@
[GPIOMUX_ACTIVE] = &mhl_active_1_cfg,
},
},
- {
- /* mhl-sii8334 reset */
- .gpio = 8,
- .settings = {
- [GPIOMUX_SUSPENDED] = &mhl_suspend_config,
- [GPIOMUX_ACTIVE] = &mhl_active_2_cfg,
- },
- },
};
diff --git a/arch/arm/mach-msm/board-8974.c b/arch/arm/mach-msm/board-8974.c
index cc73330..1de83a7 100644
--- a/arch/arm/mach-msm/board-8974.c
+++ b/arch/arm/mach-msm/board-8974.c
@@ -142,34 +142,6 @@
"msm_sdcc.3", NULL),
OF_DEV_AUXDATA("qcom,msm-sdcc", 0xF98E4000, \
"msm_sdcc.4", NULL),
- OF_DEV_AUXDATA("arm,coresight-tmc", 0xFC322000, \
- "coresight-tmc-etr", NULL),
- OF_DEV_AUXDATA("arm,coresight-tpiu", 0xFC318000, \
- "coresight-tpiu", NULL),
- OF_DEV_AUXDATA("qcom,coresight-replicator", 0xFC31C000, \
- "coresight-replicator", NULL),
- OF_DEV_AUXDATA("arm,coresight-tmc", 0xFC307000, \
- "coresight-tmc-etf", NULL),
- OF_DEV_AUXDATA("arm,coresight-funnel", 0xFC31B000, \
- "coresight-funnel-merg", NULL),
- OF_DEV_AUXDATA("arm,coresight-funnel", 0xFC319000, \
- "coresight-funnel-in0", NULL),
- OF_DEV_AUXDATA("arm,coresight-funnel", 0xFC31A000, \
- "coresight-funnel-in1", NULL),
- OF_DEV_AUXDATA("arm,coresight-funnel", 0xFC345000, \
- "coresight-funnel-kpss", NULL),
- OF_DEV_AUXDATA("arm,coresight-funnel", 0xFC364000, \
- "coresight-funnel-mmss", NULL),
- OF_DEV_AUXDATA("arm,coresight-stm", 0xFC321000, \
- "coresight-stm", NULL),
- OF_DEV_AUXDATA("arm,coresight-etm", 0xFC33C000, \
- "coresight-etm0", NULL),
- OF_DEV_AUXDATA("arm,coresight-etm", 0xFC33D000, \
- "coresight-etm1", NULL),
- OF_DEV_AUXDATA("arm,coresight-etm", 0xFC33E000, \
- "coresight-etm2", NULL),
- OF_DEV_AUXDATA("arm,coresight-etm", 0xFC33F000, \
- "coresight-etm3", NULL),
OF_DEV_AUXDATA("qcom,msm-rng", 0xF9BFF000, \
"msm_rng", NULL),
OF_DEV_AUXDATA("qcom,qseecom", 0xFE806000, \
diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c
index c45cf11..02a753a 100644
--- a/arch/arm/mach-msm/board-msm8x60.c
+++ b/arch/arm/mach-msm/board-msm8x60.c
@@ -5299,6 +5299,7 @@
&msm_device_tz_log,
&msm_rtb_device,
&msm8660_iommu_domain_device,
+ &msm8660_pm_8x60,
};
#ifdef CONFIG_ION_MSM
diff --git a/arch/arm/mach-msm/clock-8226.c b/arch/arm/mach-msm/clock-8226.c
index f65b595..2cb75dd 100644
--- a/arch/arm/mach-msm/clock-8226.c
+++ b/arch/arm/mach-msm/clock-8226.c
@@ -3388,24 +3388,26 @@
{
struct measure_clk *clk = to_measure_clk(c);
unsigned long flags;
- u32 regval, clk_sel;
+ u32 regval, clk_sel, found = 0;
int i;
- struct measure_mux_entry *array[] = {
+ static const struct measure_mux_entry *array[] = {
measure_mux_GCC,
measure_mux_MMSS,
measure_mux_LPASS,
measure_mux_APSS,
NULL
};
- struct measure_mux_entry *mux = array[0];
+ const struct measure_mux_entry *mux = array[0];
if (!parent)
return -EINVAL;
- for (i = 0; array[i]; i++) {
+ for (i = 0; array[i] && !found; i++) {
for (mux = array[i]; mux->c != &dummy_clk; mux++)
- if (mux->c == parent)
+ if (mux->c == parent) {
+ found = 1;
break;
+ }
}
if (mux->c == &dummy_clk)
@@ -3689,8 +3691,8 @@
CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f995e000.serial"),
CLK_LOOKUP("core_clk", gcc_blsp1_uart2_apps_clk.c, "f995e000.serial"),
- CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f9928000.spi"),
- CLK_LOOKUP("core_clk", gcc_blsp1_qup1_spi_apps_clk.c, "f9928000.spi"),
+ CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f9923000.spi"),
+ CLK_LOOKUP("core_clk", gcc_blsp1_qup1_spi_apps_clk.c, "f9923000.spi"),
CLK_LOOKUP("core_clk", gcc_ce1_clk.c, "qseecom"),
CLK_LOOKUP("iface_clk", gcc_ce1_ahb_clk.c, "qseecom"),
@@ -3880,6 +3882,8 @@
/* KGSL Clocks */
CLK_LOOKUP("core_clk", oxili_gfx3d_clk.c, "fdb00000.qcom,kgsl-3d0"),
CLK_LOOKUP("iface_clk", oxilicx_ahb_clk.c, "fdb00000.qcom,kgsl-3d0"),
+ CLK_LOOKUP("mem_iface_clk", oxilicx_axi_clk.c,
+ "fdb00000.qcom,kgsl-3d0"),
CLK_LOOKUP("alt_core_clk", oxili_gfx3d_clk.c, "fdb10000.qcom,iommu"),
CLK_LOOKUP("iface_clk", oxilicx_ahb_clk.c, "fdb10000.qcom,iommu"),
diff --git a/arch/arm/mach-msm/clock-8610.c b/arch/arm/mach-msm/clock-8610.c
index 55427b5..5690730 100644
--- a/arch/arm/mach-msm/clock-8610.c
+++ b/arch/arm/mach-msm/clock-8610.c
@@ -3097,10 +3097,10 @@
CLK_LOOKUP("core_clk_src", sdcc1_apps_clk_src.c, ""),
CLK_LOOKUP("core_clk_src", sdcc2_apps_clk_src.c, ""),
CLK_LOOKUP("core_clk_src", usb_hs_system_clk_src.c, ""),
-
CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f9925000.i2c"),
+ CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f9923000.spi"),
CLK_LOOKUP("core_clk", gcc_blsp1_qup1_i2c_apps_clk.c, ""),
- CLK_LOOKUP("core_clk", gcc_blsp1_qup1_spi_apps_clk.c, ""),
+ CLK_LOOKUP("core_clk", gcc_blsp1_qup1_spi_apps_clk.c, "f9923000.spi"),
CLK_LOOKUP("core_clk", gcc_blsp1_qup2_i2c_apps_clk.c, ""),
CLK_LOOKUP("core_clk", gcc_blsp1_qup2_spi_apps_clk.c, ""),
CLK_LOOKUP("core_clk", gcc_blsp1_qup3_i2c_apps_clk.c, "f9925000.i2c"),
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index c3e1e3e..6f970f5 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -526,7 +526,6 @@
#define mm_gnd_source_val 6
#define gpll1_hsic_source_val 4
#define cxo_lpass_source_val 0
-#define lpapll0_lpass_source_val 1
#define gpll0_lpass_source_val 5
#define edppll_270_mm_source_val 4
#define edppll_350_mm_source_val 4
@@ -742,21 +741,6 @@
},
};
-static struct pll_vote_clk lpapll0_clk_src = {
- .en_reg = (void __iomem *)LPASS_LPA_PLL_VOTE_APPS_REG,
- .en_mask = BIT(0),
- .status_reg = (void __iomem *)LPAPLL_STATUS_REG,
- .status_mask = BIT(17),
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .parent = &cxo_clk_src.c,
- .rate = 491520000,
- .dbg_name = "lpapll0_clk_src",
- .ops = &clk_ops_pll_vote,
- CLK_INIT(lpapll0_clk_src.c),
- },
-};
-
static struct pll_vote_clk mmpll0_clk_src = {
.en_reg = (void __iomem *)MMSS_PLL_VOTE_APCS_REG,
.en_mask = BIT(0),
@@ -4350,411 +4334,6 @@
},
};
-static struct clk_freq_tbl ftbl_audio_core_slimbus_core_clock[] = {
- F_LPASS(24576000, lpapll0, 4, 1, 5),
- F_END
-};
-
-static struct rcg_clk audio_core_slimbus_core_clk_src = {
- .cmd_rcgr_reg = SLIMBUS_CMD_RCGR,
- .set_rate = set_rate_mnd,
- .freq_tbl = ftbl_audio_core_slimbus_core_clock,
- .current_freq = &rcg_dummy_freq,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "audio_core_slimbus_core_clk_src",
- .ops = &clk_ops_rcg_mnd,
- VDD_DIG_FMAX_MAP2(LOW, 70000000, NOMINAL, 140000000),
- CLK_INIT(audio_core_slimbus_core_clk_src.c),
- },
-};
-
-static struct branch_clk audio_core_slimbus_core_clk = {
- .cbcr_reg = AUDIO_CORE_SLIMBUS_CORE_CBCR,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .parent = &audio_core_slimbus_core_clk_src.c,
- .dbg_name = "audio_core_slimbus_core_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_slimbus_core_clk.c),
- },
-};
-
-static struct branch_clk audio_core_slimbus_lfabif_clk = {
- .cbcr_reg = AUDIO_CORE_SLIMBUS_LFABIF_CBCR,
- .has_sibling = 1,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "audio_core_slimbus_lfabif_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_slimbus_lfabif_clk.c),
- },
-};
-
-static struct clk_freq_tbl ftbl_audio_core_lpaif_clock[] = {
- F_LPASS( 512000, lpapll0, 16, 1, 60),
- F_LPASS( 768000, lpapll0, 16, 1, 40),
- F_LPASS( 1024000, lpapll0, 16, 1, 30),
- F_LPASS( 1536000, lpapll0, 16, 1, 20),
- F_LPASS( 2048000, lpapll0, 16, 1, 15),
- F_LPASS( 3072000, lpapll0, 16, 1, 10),
- F_LPASS( 4096000, lpapll0, 15, 1, 8),
- F_LPASS( 6144000, lpapll0, 10, 1, 8),
- F_LPASS( 8192000, lpapll0, 15, 1, 4),
- F_LPASS(12288000, lpapll0, 10, 1, 4),
- F_END
-};
-
-static struct rcg_clk audio_core_lpaif_codec_spkr_clk_src = {
- .cmd_rcgr_reg = LPAIF_SPKR_CMD_RCGR,
- .set_rate = set_rate_mnd,
- .freq_tbl = ftbl_audio_core_lpaif_clock,
- .current_freq = &rcg_dummy_freq,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "audio_core_lpaif_codec_spkr_clk_src",
- .ops = &clk_ops_rcg_mnd,
- VDD_DIG_FMAX_MAP2(LOW, 12000000, NOMINAL, 25000000),
- CLK_INIT(audio_core_lpaif_codec_spkr_clk_src.c),
- },
-};
-
-static struct rcg_clk audio_core_lpaif_pri_clk_src = {
- .cmd_rcgr_reg = LPAIF_PRI_CMD_RCGR,
- .set_rate = set_rate_mnd,
- .freq_tbl = ftbl_audio_core_lpaif_clock,
- .current_freq = &rcg_dummy_freq,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "audio_core_lpaif_pri_clk_src",
- .ops = &clk_ops_rcg_mnd,
- VDD_DIG_FMAX_MAP2(LOW, 12000000, NOMINAL, 25000000),
- CLK_INIT(audio_core_lpaif_pri_clk_src.c),
- },
-};
-
-static struct rcg_clk audio_core_lpaif_sec_clk_src = {
- .cmd_rcgr_reg = LPAIF_SEC_CMD_RCGR,
- .set_rate = set_rate_mnd,
- .freq_tbl = ftbl_audio_core_lpaif_clock,
- .current_freq = &rcg_dummy_freq,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "audio_core_lpaif_sec_clk_src",
- .ops = &clk_ops_rcg_mnd,
- VDD_DIG_FMAX_MAP2(LOW, 12000000, NOMINAL, 25000000),
- CLK_INIT(audio_core_lpaif_sec_clk_src.c),
- },
-};
-
-static struct rcg_clk audio_core_lpaif_ter_clk_src = {
- .cmd_rcgr_reg = LPAIF_TER_CMD_RCGR,
- .set_rate = set_rate_mnd,
- .freq_tbl = ftbl_audio_core_lpaif_clock,
- .current_freq = &rcg_dummy_freq,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "audio_core_lpaif_ter_clk_src",
- .ops = &clk_ops_rcg_mnd,
- VDD_DIG_FMAX_MAP2(LOW, 12000000, NOMINAL, 25000000),
- CLK_INIT(audio_core_lpaif_ter_clk_src.c),
- },
-};
-
-static struct rcg_clk audio_core_lpaif_quad_clk_src = {
- .cmd_rcgr_reg = LPAIF_QUAD_CMD_RCGR,
- .set_rate = set_rate_mnd,
- .freq_tbl = ftbl_audio_core_lpaif_clock,
- .current_freq = &rcg_dummy_freq,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "audio_core_lpaif_quad_clk_src",
- .ops = &clk_ops_rcg_mnd,
- VDD_DIG_FMAX_MAP2(LOW, 12000000, NOMINAL, 25000000),
- CLK_INIT(audio_core_lpaif_quad_clk_src.c),
- },
-};
-
-static struct rcg_clk audio_core_lpaif_pcm0_clk_src = {
- .cmd_rcgr_reg = LPAIF_PCM0_CMD_RCGR,
- .set_rate = set_rate_mnd,
- .freq_tbl = ftbl_audio_core_lpaif_clock,
- .current_freq = &rcg_dummy_freq,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "audio_core_lpaif_pcm0_clk_src",
- .ops = &clk_ops_rcg_mnd,
- VDD_DIG_FMAX_MAP2(LOW, 12000000, NOMINAL, 25000000),
- CLK_INIT(audio_core_lpaif_pcm0_clk_src.c),
- },
-};
-
-static struct rcg_clk audio_core_lpaif_pcm1_clk_src = {
- .cmd_rcgr_reg = LPAIF_PCM1_CMD_RCGR,
- .set_rate = set_rate_mnd,
- .freq_tbl = ftbl_audio_core_lpaif_clock,
- .current_freq = &rcg_dummy_freq,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "audio_core_lpaif_pcm1_clk_src",
- .ops = &clk_ops_rcg_mnd,
- VDD_DIG_FMAX_MAP2(LOW, 12000000, NOMINAL, 25000000),
- CLK_INIT(audio_core_lpaif_pcm1_clk_src.c),
- },
-};
-
-struct rcg_clk audio_core_lpaif_pcmoe_clk_src = {
- .cmd_rcgr_reg = LPAIF_PCMOE_CMD_RCGR,
- .set_rate = set_rate_mnd,
- .freq_tbl = ftbl_audio_core_lpaif_clock,
- .current_freq = &rcg_dummy_freq,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "audio_core_lpaif_pcmoe_clk_src",
- .ops = &clk_ops_rcg_mnd,
- VDD_DIG_FMAX_MAP1(LOW, 12290000),
- CLK_INIT(audio_core_lpaif_pcmoe_clk_src.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_codec_spkr_osr_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_CODEC_SPKR_OSR_CBCR,
- .has_sibling = 1,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .parent = &audio_core_lpaif_codec_spkr_clk_src.c,
- .dbg_name = "audio_core_lpaif_codec_spkr_osr_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_codec_spkr_osr_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_codec_spkr_ebit_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_CODEC_SPKR_EBIT_CBCR,
- .has_sibling = 1,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "audio_core_lpaif_codec_spkr_ebit_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_codec_spkr_ebit_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_codec_spkr_ibit_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_CODEC_SPKR_IBIT_CBCR,
- .has_sibling = 1,
- .max_div = 15,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .parent = &audio_core_lpaif_codec_spkr_clk_src.c,
- .dbg_name = "audio_core_lpaif_codec_spkr_ibit_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_codec_spkr_ibit_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_pri_osr_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_PRI_OSR_CBCR,
- .has_sibling = 1,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .parent = &audio_core_lpaif_pri_clk_src.c,
- .dbg_name = "audio_core_lpaif_pri_osr_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_pri_osr_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_pri_ebit_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_PRI_EBIT_CBCR,
- .has_sibling = 1,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "audio_core_lpaif_pri_ebit_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_pri_ebit_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_pri_ibit_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_PRI_IBIT_CBCR,
- .has_sibling = 1,
- .max_div = 15,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .parent = &audio_core_lpaif_pri_clk_src.c,
- .dbg_name = "audio_core_lpaif_pri_ibit_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_pri_ibit_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_sec_osr_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_SEC_OSR_CBCR,
- .has_sibling = 1,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .parent = &audio_core_lpaif_sec_clk_src.c,
- .dbg_name = "audio_core_lpaif_sec_osr_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_sec_osr_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_sec_ebit_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_SEC_EBIT_CBCR,
- .has_sibling = 1,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "audio_core_lpaif_sec_ebit_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_sec_ebit_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_sec_ibit_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_SEC_IBIT_CBCR,
- .has_sibling = 1,
- .max_div = 15,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .parent = &audio_core_lpaif_sec_clk_src.c,
- .dbg_name = "audio_core_lpaif_sec_ibit_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_sec_ibit_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_ter_osr_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_TER_OSR_CBCR,
- .has_sibling = 1,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .parent = &audio_core_lpaif_ter_clk_src.c,
- .dbg_name = "audio_core_lpaif_ter_osr_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_ter_osr_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_ter_ebit_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_TER_EBIT_CBCR,
- .has_sibling = 1,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "audio_core_lpaif_ter_ebit_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_ter_ebit_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_ter_ibit_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_TER_IBIT_CBCR,
- .has_sibling = 1,
- .max_div = 15,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .parent = &audio_core_lpaif_ter_clk_src.c,
- .dbg_name = "audio_core_lpaif_ter_ibit_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_ter_ibit_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_quad_osr_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_QUAD_OSR_CBCR,
- .has_sibling = 1,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .parent = &audio_core_lpaif_quad_clk_src.c,
- .dbg_name = "audio_core_lpaif_quad_osr_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_quad_osr_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_quad_ebit_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_QUAD_EBIT_CBCR,
- .has_sibling = 1,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "audio_core_lpaif_quad_ebit_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_quad_ebit_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_quad_ibit_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_QUAD_IBIT_CBCR,
- .has_sibling = 1,
- .max_div = 15,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .parent = &audio_core_lpaif_quad_clk_src.c,
- .dbg_name = "audio_core_lpaif_quad_ibit_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_quad_ibit_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_pcm0_ebit_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_PCM0_EBIT_CBCR,
- .has_sibling = 1,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "audio_core_lpaif_pcm0_ebit_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_pcm0_ebit_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_pcm0_ibit_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_PCM0_IBIT_CBCR,
- .has_sibling = 1,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .parent = &audio_core_lpaif_pcm0_clk_src.c,
- .dbg_name = "audio_core_lpaif_pcm0_ibit_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_pcm0_ibit_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_pcm1_ebit_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_PCM1_EBIT_CBCR,
- .has_sibling = 1,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .parent = &audio_core_lpaif_pcm1_clk_src.c,
- .dbg_name = "audio_core_lpaif_pcm1_ebit_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_pcm1_ebit_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_pcm1_ibit_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_PCM1_IBIT_CBCR,
- .has_sibling = 1,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .parent = &audio_core_lpaif_pcm1_clk_src.c,
- .dbg_name = "audio_core_lpaif_pcm1_ibit_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_pcm1_ibit_clk.c),
- },
-};
-
-struct branch_clk audio_core_lpaif_pcmoe_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_PCM_DATA_OE_CBCR,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .parent = &audio_core_lpaif_pcmoe_clk_src.c,
- .dbg_name = "audio_core_lpaif_pcmoe_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_pcmoe_clk.c),
- },
-};
-
static struct branch_clk q6ss_ahb_lfabif_clk = {
.cbcr_reg = LPASS_Q6SS_AHB_LFABIF_CBCR,
.has_sibling = 1,
@@ -4766,16 +4345,6 @@
},
};
-static struct branch_clk audio_core_ixfabric_clk = {
- .cbcr_reg = AUDIO_CORE_IXFABRIC_CBCR,
- .has_sibling = 1,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "audio_core_ixfabric_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_ixfabric_clk.c),
- },
-};
static struct branch_clk gcc_lpass_q6_axi_clk = {
.cbcr_reg = LPASS_Q6_AXI_CBCR,
@@ -4811,17 +4380,6 @@
},
};
-static struct branch_clk audio_wrapper_br_clk = {
- .cbcr_reg = AUDIO_WRAPPER_BR_CBCR,
- .has_sibling = 1,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "audio_wrapper_br_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_wrapper_br_clk.c),
- },
-};
-
static DEFINE_CLK_MEASURE(l2_m_clk);
static DEFINE_CLK_MEASURE(krait0_m_clk);
static DEFINE_CLK_MEASURE(krait1_m_clk);
@@ -5004,20 +4562,9 @@
{&mdss_hdmi_ahb_clk.c, MMSS_BASE, 0x0023},
{&mdss_pclk0_clk.c, MMSS_BASE, 0x0016},
{&mdss_pclk1_clk.c, MMSS_BASE, 0x0017},
- {&audio_core_lpaif_pri_clk_src.c, LPASS_BASE, 0x0017},
- {&audio_core_lpaif_sec_clk_src.c, LPASS_BASE, 0x0016},
- {&audio_core_lpaif_ter_clk_src.c, LPASS_BASE, 0x0015},
- {&audio_core_lpaif_quad_clk_src.c, LPASS_BASE, 0x0014},
- {&audio_core_lpaif_pcm0_clk_src.c, LPASS_BASE, 0x0013},
- {&audio_core_lpaif_pcm1_clk_src.c, LPASS_BASE, 0x0012},
- {&audio_core_lpaif_pcmoe_clk_src.c, LPASS_BASE, 0x000f},
- {&audio_core_slimbus_core_clk.c, LPASS_BASE, 0x003d},
- {&audio_core_slimbus_lfabif_clk.c, LPASS_BASE, 0x003e},
{&q6ss_xo_clk.c, LPASS_BASE, 0x002b},
{&q6ss_ahb_lfabif_clk.c, LPASS_BASE, 0x001e},
{&q6ss_ahbm_clk.c, LPASS_BASE, 0x001d},
- {&audio_core_ixfabric_clk.c, LPASS_BASE, 0x0059},
- {&audio_wrapper_br_clk.c, LPASS_BASE, 0x0022},
{&krait0_m_clk, APCS_BASE, M_ACPU0},
{&krait1_m_clk, APCS_BASE, M_ACPU1},
@@ -5639,57 +5186,6 @@
/* LPASS clocks */
- CLK_LOOKUP("bus_clk", audio_core_ixfabric_clk.c, ""),
- CLK_LOOKUP("core_clk", audio_core_slimbus_core_clk.c, "fe12f000.slim"),
- CLK_LOOKUP("iface_clk", audio_core_slimbus_lfabif_clk.c,
- "fe12f000.slim"),
- CLK_LOOKUP("core_clk", audio_core_lpaif_codec_spkr_clk_src.c, ""),
- CLK_LOOKUP("osr_clk", audio_core_lpaif_codec_spkr_osr_clk.c, ""),
- CLK_LOOKUP("ebit_clk", audio_core_lpaif_codec_spkr_ebit_clk.c, ""),
- CLK_LOOKUP("ibit_clk", audio_core_lpaif_codec_spkr_ibit_clk.c, ""),
- CLK_LOOKUP("core_clk", audio_core_lpaif_pri_clk_src.c, ""),
- CLK_LOOKUP("osr_clk", audio_core_lpaif_pri_osr_clk.c, ""),
- CLK_LOOKUP("ebit_clk", audio_core_lpaif_pri_ebit_clk.c, ""),
- CLK_LOOKUP("ibit_clk", audio_core_lpaif_pri_ibit_clk.c, ""),
- CLK_LOOKUP("core_clk", audio_core_lpaif_sec_clk_src.c, ""),
- CLK_LOOKUP("osr_clk", audio_core_lpaif_sec_osr_clk.c, ""),
- CLK_LOOKUP("ebit_clk", audio_core_lpaif_sec_ebit_clk.c, ""),
- CLK_LOOKUP("ibit_clk", audio_core_lpaif_sec_ibit_clk.c, ""),
- CLK_LOOKUP("core_clk", audio_core_lpaif_ter_clk_src.c, ""),
- CLK_LOOKUP("osr_clk", audio_core_lpaif_ter_osr_clk.c, ""),
- CLK_LOOKUP("ebit_clk", audio_core_lpaif_ter_ebit_clk.c, ""),
- CLK_LOOKUP("ibit_clk", audio_core_lpaif_ter_ibit_clk.c, ""),
- CLK_LOOKUP("core_clk", audio_core_lpaif_quad_clk_src.c,
- "msm-dai-q6-mi2s.3"),
- CLK_LOOKUP("osr_clk", audio_core_lpaif_quad_osr_clk.c,
- "msm-dai-q6-mi2s.3"),
- CLK_LOOKUP("ebit_clk", audio_core_lpaif_quad_ebit_clk.c,
- "msm-dai-q6-mi2s.3"),
- CLK_LOOKUP("ibit_clk", audio_core_lpaif_quad_ibit_clk.c,
- "msm-dai-q6-mi2s.3"),
- CLK_LOOKUP("pcm_clk", audio_core_lpaif_pcm0_clk_src.c,
- "msm-dai-q6.4106"),
- CLK_LOOKUP("ebit_clk", audio_core_lpaif_pcm0_ebit_clk.c, ""),
- CLK_LOOKUP("ibit_clk", audio_core_lpaif_pcm0_ibit_clk.c,
- "msm-dai-q6.4106"),
- CLK_LOOKUP("ibit_clk", audio_core_lpaif_pcm0_ibit_clk.c, ""),
- CLK_LOOKUP("core_clk", audio_core_lpaif_pcm1_clk_src.c, ""),
- CLK_LOOKUP("ebit_clk", audio_core_lpaif_pcm1_ebit_clk.c, ""),
- CLK_LOOKUP("ibit_clk", audio_core_lpaif_pcm1_ibit_clk.c, ""),
- CLK_LOOKUP("core_oe_src_clk", audio_core_lpaif_pcmoe_clk_src.c,
- "msm-dai-q6.4106"),
- CLK_LOOKUP("core_oe_clk", audio_core_lpaif_pcmoe_clk.c,
- "msm-dai-q6.4106"),
- CLK_LOOKUP("pcm_clk", audio_core_lpaif_pcm0_clk_src.c,
- "msm-dai-q6.4107"),
- CLK_LOOKUP("ibit_clk", audio_core_lpaif_pcm0_ibit_clk.c,
- "msm-dai-q6.4107"),
- CLK_LOOKUP("core_oe_src_clk", audio_core_lpaif_pcmoe_clk_src.c,
- "msm-dai-q6.4107"),
- CLK_LOOKUP("core_oe_clk", audio_core_lpaif_pcmoe_clk.c,
- "msm-dai-q6.4107"),
- CLK_LOOKUP("br_clk", audio_wrapper_br_clk.c, "fdd00000.qcom,ocmem"),
-
CLK_LOOKUP("bus_clk", gcc_mss_q6_bimc_axi_clk.c, "fc880000.qcom,mss"),
CLK_LOOKUP("iface_clk", gcc_mss_cfg_ahb_clk.c, "fc880000.qcom,mss"),
CLK_LOOKUP("mem_clk", gcc_boot_rom_ahb_clk.c, "fc880000.qcom,mss"),
@@ -5731,35 +5227,36 @@
CLK_LOOKUP("iface_clk", gcc_mmss_noc_cfg_ahb_clk.c, ""),
CLK_LOOKUP("iface_clk", gcc_ocmem_noc_cfg_ahb_clk.c, ""),
- CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-tmc-etr"),
- CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-tpiu"),
- CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-replicator"),
- CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-tmc-etf"),
- CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-funnel-merg"),
- CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-funnel-in0"),
- CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-funnel-in1"),
- CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-funnel-kpss"),
- CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-funnel-mmss"),
- CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-stm"),
- CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-etm0"),
- CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-etm1"),
- CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-etm2"),
- CLK_LOOKUP("core_clk", qdss_clk.c, "coresight-etm3"),
+ /* CoreSight clocks */
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc322000.tmc"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc318000.tpiu"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc31c000.replicator"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc307000.tmc"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc31b000.funnel"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc319000.funnel"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc31a000.funnel"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc345000.funnel"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc364000.funnel"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc321000.stm"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc33c000.etm"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc33d000.etm"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc33e000.etm"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc33f000.etm"),
- CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-tmc-etr"),
- CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-tpiu"),
- CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-replicator"),
- CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-tmc-etf"),
- CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-funnel-merg"),
- CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-funnel-in0"),
- CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-funnel-in1"),
- CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-funnel-kpss"),
- CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-funnel-mmss"),
- CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-stm"),
- CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-etm0"),
- CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-etm1"),
- CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-etm2"),
- CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "coresight-etm3"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc322000.tmc"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc318000.tpiu"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc31c000.replicator"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc307000.tmc"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc31b000.funnel"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc319000.funnel"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc31a000.funnel"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc345000.funnel"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc364000.funnel"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc321000.stm"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc33c000.etm"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc33d000.etm"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc33e000.etm"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc33f000.etm"),
CLK_LOOKUP("l2_m_clk", l2_m_clk, ""),
CLK_LOOKUP("krait0_m_clk", krait0_m_clk, ""),
@@ -5880,32 +5377,6 @@
.main_output_mask = BIT(0),
};
-static struct pll_config_regs lpapll0_regs __initdata = {
- .l_reg = (void __iomem *)LPAPLL_L_REG,
- .m_reg = (void __iomem *)LPAPLL_M_REG,
- .n_reg = (void __iomem *)LPAPLL_N_REG,
- .config_reg = (void __iomem *)LPAPLL_USER_CTL_REG,
- .mode_reg = (void __iomem *)LPAPLL_MODE_REG,
- .base = &virt_bases[LPASS_BASE],
-};
-
-/* LPAPLL0 at 491.52 MHz, main output enabled. */
-static struct pll_config lpapll0_config __initdata = {
- .l = 0x33,
- .m = 0x1,
- .n = 0x5,
- .vco_val = 0x0,
- .vco_mask = BM(21, 20),
- .pre_div_val = BVAL(14, 12, 0x1),
- .pre_div_mask = BM(14, 12),
- .post_div_val = 0x0,
- .post_div_mask = BM(9, 8),
- .mn_ena_val = BIT(24),
- .mn_ena_mask = BIT(24),
- .main_output_val = BIT(0),
- .main_output_mask = BIT(0),
-};
-
#define PWR_ON_MASK BIT(31)
#define EN_REST_WAIT_MASK (0xF << 20)
#define EN_FEW_WAIT_MASK (0xF << 16)
@@ -5922,8 +5393,7 @@
static void __init reg_init(void)
{
- u32 regval, status;
- int ret;
+ u32 regval;
configure_sr_hpm_lp_pll(&mmpll0_config, &mmpll0_regs, 1);
@@ -5934,7 +5404,6 @@
configure_sr_hpm_lp_pll(&mmpll1_config, &mmpll1_regs, 1);
configure_sr_hpm_lp_pll(&mmpll3_config, &mmpll3_regs, 0);
}
- configure_sr_hpm_lp_pll(&lpapll0_config, &lpapll0_regs, 1);
/* Vote for GPLL0 to turn on. Needed by acpuclock. */
regval = readl_relaxed(GCC_REG_BASE(APCS_GPLL_ENA_VOTE_REG));
@@ -5957,31 +5426,6 @@
* register.
*/
writel_relaxed(0x0, GCC_REG_BASE(APCS_CLOCK_SLEEP_ENA_VOTE));
-
- /*
- * TODO: The following sequence enables the LPASS audio core GDSC.
- * Remove when this becomes unnecessary.
- */
-
- /*
- * Disable HW trigger: collapse/restore occur based on registers writes.
- * Disable SW override: Use hardware state-machine for sequencing.
- */
- regval = readl_relaxed(LPASS_REG_BASE(AUDIO_CORE_GDSCR));
- regval &= ~(HW_CONTROL_MASK | SW_OVERRIDE_MASK);
-
- /* Configure wait time between states. */
- regval &= ~(EN_REST_WAIT_MASK | EN_FEW_WAIT_MASK | CLK_DIS_WAIT_MASK);
- regval |= EN_REST_WAIT_VAL | EN_FEW_WAIT_VAL | CLK_DIS_WAIT_VAL;
- writel_relaxed(regval, LPASS_REG_BASE(AUDIO_CORE_GDSCR));
-
- regval = readl_relaxed(LPASS_REG_BASE(AUDIO_CORE_GDSCR));
- regval &= ~BIT(0);
- writel_relaxed(regval, LPASS_REG_BASE(AUDIO_CORE_GDSCR));
-
- ret = readl_poll_timeout(LPASS_REG_BASE(AUDIO_CORE_GDSCR), status,
- status & PWR_ON_MASK, 50, GDSC_TIMEOUT_US);
- WARN(ret, "LPASS Audio Core GDSC did not power on.\n");
}
static void __init mdss_clock_setup(void)
@@ -6021,11 +5465,6 @@
*/
clk_prepare_enable(&cxo_a_clk_src.c);
- /* TODO: Temporarily enable a clock to allow access to LPASS core
- * registers.
- */
- clk_prepare_enable(&audio_core_ixfabric_clk.c);
-
/*
* TODO: Temporarily enable NOC configuration AHB clocks. Remove when
* the bus driver is ready.
@@ -6060,8 +5499,6 @@
clk_set_rate(&esc1_clk_src.c, esc1_clk_src.freq_tbl[0].freq_hz);
clk_set_rate(&hdmi_clk_src.c, hdmi_clk_src.freq_tbl[0].freq_hz);
clk_set_rate(&vsync_clk_src.c, vsync_clk_src.freq_tbl[0].freq_hz);
- clk_set_rate(&audio_core_slimbus_core_clk_src.c,
- audio_core_slimbus_core_clk_src.freq_tbl[0].freq_hz);
}
#define GCC_CC_PHYS 0xFC400000
diff --git a/arch/arm/mach-msm/clock-9625.c b/arch/arm/mach-msm/clock-9625.c
index b5f5a4e..2bfb323 100644
--- a/arch/arm/mach-msm/clock-9625.c
+++ b/arch/arm/mach-msm/clock-9625.c
@@ -2260,7 +2260,7 @@
CLK_LOOKUP("a5_m_clk", a5_m_clk, ""),
- /* Coresight QDSS clocks */
+ /* CoreSight clocks */
CLK_LOOKUP("core_clk", qdss_clk.c, "fc322000.tmc"),
CLK_LOOKUP("core_clk", qdss_clk.c, "fc318000.tpiu"),
CLK_LOOKUP("core_clk", qdss_clk.c, "fc31c000.replicator"),
@@ -2272,16 +2272,16 @@
CLK_LOOKUP("core_clk", qdss_clk.c, "fc332000.etm"),
CLK_LOOKUP("core_clk", qdss_clk.c, "fc332000.jtagmm"),
- CLK_LOOKUP("core_a_clk", qdss_clk.c, "fc322000.tmc"),
- CLK_LOOKUP("core_a_clk", qdss_clk.c, "fc318000.tpiu"),
- CLK_LOOKUP("core_a_clk", qdss_clk.c, "fc31c000.replicator"),
- CLK_LOOKUP("core_a_clk", qdss_clk.c, "fc307000.tmc"),
- CLK_LOOKUP("core_a_clk", qdss_clk.c, "fc31b000.funnel"),
- CLK_LOOKUP("core_a_clk", qdss_clk.c, "fc319000.funnel"),
- CLK_LOOKUP("core_a_clk", qdss_clk.c, "fc31a000.funnel"),
- CLK_LOOKUP("core_a_clk", qdss_clk.c, "fc321000.stm"),
- CLK_LOOKUP("core_a_clk", qdss_clk.c, "fc332000.etm"),
- CLK_LOOKUP("core_a_clk", qdss_clk.c, "fc332000.jtagmm"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc322000.tmc"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc318000.tpiu"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc31c000.replicator"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc307000.tmc"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc31b000.funnel"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc319000.funnel"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc31a000.funnel"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc321000.stm"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc332000.etm"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc332000.jtagmm"),
};
diff --git a/arch/arm/mach-msm/clock-mdss-8974.c b/arch/arm/mach-msm/clock-mdss-8974.c
index aca6494..54fe11e 100644
--- a/arch/arm/mach-msm/clock-mdss-8974.c
+++ b/arch/arm/mach-msm/clock-mdss-8974.c
@@ -205,19 +205,17 @@
REG_W(0x03, mdss_dsi_base + 0x0228); /* postDiv3 */
REG_W(0x2b, mdss_dsi_base + 0x0278); /* Cal CFG3 */
- REG_W(0x06, mdss_dsi_base + 0x027c); /* Cal CFG4 */
- REG_W(0x05, mdss_dsi_base + 0x0264); /* Cal CFG4 */
+ REG_W(0x66, mdss_dsi_base + 0x027c); /* Cal CFG4 */
+ REG_W(0x05, mdss_dsi_base + 0x0264); /* LKDET CFG2 */
REG_W(0x0a, mdss_dsi_base + 0x023c); /* SDM CFG1 */
REG_W(0xab, mdss_dsi_base + 0x0240); /* SDM CFG2 */
REG_W(0x0a, mdss_dsi_base + 0x0244); /* SDM CFG3 */
REG_W(0x00, mdss_dsi_base + 0x0248); /* SDM CFG4 */
- udelay(10);
-
REG_W(0x01, mdss_dsi_base + 0x0200); /* REFCLK CFG */
REG_W(0x00, mdss_dsi_base + 0x0214); /* PWRGEN CFG */
- REG_W(0x01, mdss_dsi_base + 0x020c); /* VCOLPF CFG */
+ REG_W(0x71, mdss_dsi_base + 0x020c); /* VCOLPF CFG */
REG_W(0x02, mdss_dsi_base + 0x0210); /* VREG CFG */
REG_W(0x00, mdss_dsi_base + 0x0238); /* SDM CFG0 */
@@ -242,6 +240,22 @@
return 0;
}
+static void mdss_dsi_uniphy_pll_lock_detect_setting(void)
+{
+ REG_W(0x04, mdss_dsi_base + 0x0264); /* LKDetect CFG2 */
+ udelay(100);
+ REG_W(0x05, mdss_dsi_base + 0x0264); /* LKDetect CFG2 */
+ udelay(500);
+}
+
+static void mdss_dsi_uniphy_pll_sw_reset(void)
+{
+ REG_W(0x01, mdss_dsi_base + 0x0268); /* PLL TEST CFG */
+ udelay(1);
+ REG_W(0x00, mdss_dsi_base + 0x0268); /* PLL TEST CFG */
+ udelay(1);
+}
+
static int __mdss_dsi_pll_enable(struct clk *c)
{
u32 status;
@@ -264,17 +278,23 @@
clk_enable(mdss_dsi_ahb_clk);
+ mdss_dsi_uniphy_pll_sw_reset();
/* PLL power up */
- for (i = 0; i < 3; i++) {
- REG_W(0x01, mdss_dsi_base + 0x0220); /* GLB CFG */
- REG_W(0x05, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(20);
- REG_W(0x07, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(20);
- REG_W(0x0f, mdss_dsi_base + 0x0220); /* GLB CFG */
+ /* Add HW recommended delay between
+ register writes for the update to propagate */
+ REG_W(0x01, mdss_dsi_base + 0x0220); /* GLB CFG */
+ udelay(1000);
+ REG_W(0x05, mdss_dsi_base + 0x0220); /* GLB CFG */
+ udelay(1000);
+ REG_W(0x07, mdss_dsi_base + 0x0220); /* GLB CFG */
+ udelay(1000);
+ REG_W(0x0f, mdss_dsi_base + 0x0220); /* GLB CFG */
+ udelay(1000);
+ for (i = 0; i < 3; i++) {
+ mdss_dsi_uniphy_pll_lock_detect_setting();
/* poll for PLL ready status */
- max_reads = 20;
+ max_reads = 5;
timeout_us = 100;
if (readl_poll_timeout_noirq((mdss_dsi_base + 0x02c0),
status,
@@ -286,6 +306,24 @@
__func__);
} else
break;
+
+ mdss_dsi_uniphy_pll_sw_reset();
+ udelay(1000);
+ /* Add HW recommended delay between
+ register writes for the update to propagate */
+ REG_W(0x01, mdss_dsi_base + 0x0220); /* GLB CFG */
+ udelay(1000);
+ REG_W(0x05, mdss_dsi_base + 0x0220); /* GLB CFG */
+ udelay(1000);
+ REG_W(0x07, mdss_dsi_base + 0x0220); /* GLB CFG */
+ udelay(1000);
+ REG_W(0x05, mdss_dsi_base + 0x0220); /* GLB CFG */
+ udelay(1000);
+ REG_W(0x07, mdss_dsi_base + 0x0220); /* GLB CFG */
+ udelay(1000);
+ REG_W(0x0f, mdss_dsi_base + 0x0220); /* GLB CFG */
+ udelay(2000);
+
}
if ((status & 0x01) != 1) {
diff --git a/arch/arm/mach-msm/clock-rpm.c b/arch/arm/mach-msm/clock-rpm.c
index c1cc27b..ee91a34 100644
--- a/arch/arm/mach-msm/clock-rpm.c
+++ b/arch/arm/mach-msm/clock-rpm.c
@@ -245,6 +245,14 @@
return rc;
}
+static int rpm_branch_clk_set_rate(struct clk *clk, unsigned long rate)
+{
+ if (rate == clk->rate)
+ return 0;
+
+ return -EPERM;
+}
+
static unsigned long rpm_clk_get_rate(struct clk *clk)
{
struct rpm_clk *r = to_rpm_clk(clk);
@@ -335,6 +343,7 @@
struct clk_ops clk_ops_rpm_branch = {
.prepare = rpm_clk_prepare,
.unprepare = rpm_clk_unprepare,
+ .set_rate = rpm_branch_clk_set_rate,
.is_local = rpm_clk_is_local,
.handoff = rpm_clk_handoff,
};
diff --git a/arch/arm/mach-msm/cpuidle.c b/arch/arm/mach-msm/cpuidle.c
index 77c91b8..e87c7b5 100644
--- a/arch/arm/mach-msm/cpuidle.c
+++ b/arch/arm/mach-msm/cpuidle.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -72,18 +72,19 @@
struct cpuidle_device *dev, struct cpuidle_driver *drv, int index)
{
int ret = 0;
- int i = 0;
+ int i;
enum msm_pm_sleep_mode pm_mode;
- struct cpuidle_state_usage *st_usage = NULL;
cpu_pm_enter();
- pm_mode = msm_pm_idle_prepare(dev, drv, index);
- dev->last_residency = msm_pm_idle_enter(pm_mode);
+ pm_mode = msm_pm_idle_enter(dev, drv, index);
+
for (i = 0; i < dev->state_count; i++) {
- st_usage = &dev->states_usage[i];
- if ((enum msm_pm_sleep_mode) cpuidle_get_statedata(st_usage)
- == pm_mode) {
+ struct cpuidle_state_usage *st_usage = &dev->states_usage[i];
+ enum msm_pm_sleep_mode last_mode =
+ (enum msm_pm_sleep_mode)cpuidle_get_statedata(st_usage);
+
+ if (last_mode == pm_mode) {
ret = i;
break;
}
@@ -95,7 +96,7 @@
return ret;
}
-static void __init msm_cpuidle_set_states(void)
+static void __devinit msm_cpuidle_set_states(void)
{
int i = 0;
int state_count = 0;
@@ -151,7 +152,7 @@
dev->state_count = state_count; /* Per cpu state count */
}
-int __init msm_cpuidle_init(void)
+int __devinit msm_cpuidle_init(void)
{
unsigned int cpu = 0;
int ret = 0;
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index f87c540..10ee1e3 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -49,6 +49,7 @@
#include <mach/mpm.h>
#include <mach/iommu_domains.h>
#include <mach/msm_cache_dump.h>
+#include "pm.h"
/* Address of GSBI blocks */
#define MSM_GSBI1_PHYS 0x12440000
@@ -120,11 +121,24 @@
},
};
-struct platform_device msm8064_pc_cntr = {
- .name = "pc-cntr",
+static uint32_t msm_pm_cp15_regs[] = {0x4501, 0x5501, 0x6501, 0x7501, 0x0500};
+
+static struct msm_pm_init_data_type msm_pm_data = {
+ .retention_calls_tz = true,
+ .cp15_data.save_cp15 = true,
+ .cp15_data.qsb_pc_vdd = 0x98,
+ .cp15_data.reg_data = &msm_pm_cp15_regs[0],
+ .cp15_data.reg_saved_state_size = ARRAY_SIZE(msm_pm_cp15_regs),
+};
+
+struct platform_device msm8064_pm_8x60 = {
+ .name = "pm-8x60",
.id = -1,
.num_resources = ARRAY_SIZE(msm8064_resources_pccntr),
.resource = msm8064_resources_pccntr,
+ .dev = {
+ .platform_data = &msm_pm_data,
+ },
};
static struct msm_watchdog_pdata msm_watchdog_pdata = {
diff --git a/arch/arm/mach-msm/devices-8930.c b/arch/arm/mach-msm/devices-8930.c
index aad512e..6fe8ccb 100644
--- a/arch/arm/mach-msm/devices-8930.c
+++ b/arch/arm/mach-msm/devices-8930.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -32,6 +32,7 @@
#include "rpm_rbcpr_stats.h"
#include "footswitch.h"
#include "acpuclock-krait.h"
+#include "pm.h"
#ifdef CONFIG_MSM_MPM
#include <mach/mpm.h>
@@ -48,11 +49,18 @@
},
};
-struct platform_device msm8930_pc_cntr = {
- .name = "pc-cntr",
+static struct msm_pm_init_data_type msm_pm_data = {
+ .retention_calls_tz = true,
+};
+
+struct platform_device msm8930_pm_8x60 = {
+ .name = "pm-8x60",
.id = -1,
.num_resources = ARRAY_SIZE(msm8930_resources_pccntr),
.resource = msm8930_resources_pccntr,
+ .dev = {
+ .platform_data = &msm_pm_data,
+ },
};
struct msm_rpm_platform_data msm8930_rpm_data __initdata = {
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index c3748fa..6a344be 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -53,6 +53,7 @@
#include <mach/msm_dcvs.h>
#include <mach/iommu_domains.h>
#include <mach/socinfo.h>
+#include "pm.h"
#ifdef CONFIG_MSM_MPM
#include <mach/mpm.h>
@@ -116,11 +117,18 @@
},
};
-struct platform_device msm8960_pc_cntr = {
- .name = "pc-cntr",
+static struct msm_pm_init_data_type msm_pm_data = {
+ .retention_calls_tz = true,
+};
+
+struct platform_device msm8960_pm_8x60 = {
+ .name = "pm-8x60",
.id = -1,
.num_resources = ARRAY_SIZE(msm8960_resources_pccntr),
.resource = msm8960_resources_pccntr,
+ .dev = {
+ .platform_data = &msm_pm_data,
+ },
};
static struct resource resources_otg[] = {
diff --git a/arch/arm/mach-msm/devices-msm8x60.c b/arch/arm/mach-msm/devices-msm8x60.c
index 58416c7..cfa9281 100644
--- a/arch/arm/mach-msm/devices-msm8x60.c
+++ b/arch/arm/mach-msm/devices-msm8x60.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -3181,3 +3181,9 @@
.platform_data = &msm8660_iommu_domain_pdata,
}
};
+
+struct platform_device msm8660_pm_8x60 = {
+ .name = "pm-8x60",
+ .id = -1,
+};
+
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index d3810a2..53eca3e 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -1,7 +1,7 @@
/* linux/arch/arm/mach-msm/devices.h
*
* Copyright (C) 2008 Google, Inc.
- * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -113,11 +113,11 @@
extern struct platform_device msm_device_sdc3;
extern struct platform_device msm_device_sdc4;
+extern struct platform_device msm8960_pm_8x60;
+extern struct platform_device msm8064_pm_8x60;
+extern struct platform_device msm8930_pm_8x60;
extern struct platform_device msm9615_pm_8x60;
-
-extern struct platform_device msm8960_pc_cntr;
-extern struct platform_device msm8064_pc_cntr;
-extern struct platform_device msm8930_pc_cntr;
+extern struct platform_device msm8660_pm_8x60;
extern struct platform_device msm_device_gadget_peripheral;
extern struct platform_device msm_device_hsusb_host;
diff --git a/arch/arm/mach-msm/include/mach/iommu_hw-v0.h b/arch/arm/mach-msm/include/mach/iommu_hw-v0.h
index 198f72f..68dec79 100644
--- a/arch/arm/mach-msm/include/mach/iommu_hw-v0.h
+++ b/arch/arm/mach-msm/include/mach/iommu_hw-v0.h
@@ -830,6 +830,11 @@
#define IDR (0xFF8)
#define RPU_ACR (0xFFC)
+/* Event Monitor (EM) Registers */
+#define EMMC (0xE000)
+#define EMCS (0xE004)
+#define EMCC_N (0xE100)
+#define EMC_N (0xE200)
/* Context Bank Registers */
#define SCTLR (0x000)
diff --git a/arch/arm/mach-msm/include/mach/iommu_perfmon.h b/arch/arm/mach-msm/include/mach/iommu_perfmon.h
index 59f58c1..5a01bee 100644
--- a/arch/arm/mach-msm/include/mach/iommu_perfmon.h
+++ b/arch/arm/mach-msm/include/mach/iommu_perfmon.h
@@ -75,6 +75,7 @@
* @evt_irq: irq number for event overflow interrupt
* @iommu_dev: pointer to iommu device
* @ops: iommu access operations pointer.
+ * @hw_ops: iommu pm hw access operations pointer.
*/
struct iommu_info {
const char *iommu_name;
@@ -82,6 +83,7 @@
int evt_irq;
struct device *iommu_dev;
struct iommu_access_ops *ops;
+ struct iommu_pm_hw_ops *hw_ops;
};
/**
@@ -112,9 +114,63 @@
struct mutex lock;
};
-extern struct iommu_access_ops iommu_access_ops;
+/**
+ * struct iommu_hw_ops - Callbacks for accessing IOMMU HW
+ * @initialize_hw: Call to do any initialization before enabling ovf interrupts
+ * @is_hw_access_ok: Returns 1 if we can access HW, 0 otherwise
+ * @grp_enable: Call to enable a counter group
+ * @grp_disable: Call to disable a counter group
+ * @enable_pm: Call to enable PM
+ * @disable_pm: Call to disable PM
+ * @reset_counters: Call to reset counters
+ * @check_for_overflow: Call to check for overflow
+ * @evt_ovfl_int_handler: Overflow interrupt handler callback
+ * @counter_enable: Call to enable counters
+ * @counter_disable: Call to disable counters
+ * @ovfl_int_enable: Call to enable overflow interrupts
+ * @ovfl_int_disable: Call to disable overflow interrupts
+ * @set_event_class: Call to set event class
+ * @read_counter: Call to read a counter value
+ */
+struct iommu_pm_hw_ops {
+ void (*initialize_hw)(const struct iommu_pmon *);
+ unsigned int (*is_hw_access_OK)(const struct iommu_pmon *);
+ void (*grp_enable)(struct iommu_info *, unsigned int);
+ void (*grp_disable)(struct iommu_info *, unsigned int);
+ void (*enable_pm)(struct iommu_info *);
+ void (*disable_pm)(struct iommu_info *);
+ void (*reset_counters)(const struct iommu_info *);
+ void (*check_for_overflow)(struct iommu_pmon *);
+ irqreturn_t (*evt_ovfl_int_handler)(int, void *);
+ void (*counter_enable)(struct iommu_info *,
+ struct iommu_pmon_counter *);
+ void (*counter_disable)(struct iommu_info *,
+ struct iommu_pmon_counter *);
+ void (*ovfl_int_enable)(struct iommu_info *,
+ const struct iommu_pmon_counter *);
+ void (*ovfl_int_disable)(struct iommu_info *,
+ const struct iommu_pmon_counter *);
+ void (*set_event_class)(struct iommu_pmon *pmon, unsigned int,
+ unsigned int);
+ unsigned int (*read_counter)(struct iommu_pmon_counter *);
+};
+
+extern struct iommu_access_ops iommu_access_ops_v0;
+extern struct iommu_access_ops iommu_access_ops_v1;
+#define MSM_IOMMU_PMU_NO_EVENT_CLASS -1
#ifdef CONFIG_MSM_IOMMU_PMON
+
+/**
+ * Get pointer to PMU hardware access functions for IOMMUv0 PMU
+ */
+struct iommu_pm_hw_ops *iommu_pm_get_hw_ops_v0(void);
+
+/**
+ * Get pointer to PMU hardware access functions for IOMMUv1 PMU
+ */
+struct iommu_pm_hw_ops *iommu_pm_get_hw_ops_v1(void);
+
/**
* Allocate memory for performance monitor structure. Must
* be called before iommu_pm_iommu_register
@@ -150,6 +206,16 @@
*/
void msm_iommu_detached(struct device *dev);
#else
+static inline struct iommu_pm_hw_ops *iommu_pm_get_hw_ops_v0(void)
+{
+ return NULL;
+}
+
+static inline struct iommu_pm_hw_ops *iommu_pm_get_hw_ops_v1(void)
+{
+ return NULL;
+}
+
static inline struct iommu_pmon *msm_iommu_pm_alloc(struct device *iommu_dev)
{
return NULL;
diff --git a/arch/arm/mach-msm/include/mach/ipa.h b/arch/arm/mach-msm/include/mach/ipa.h
index c37b518..26a055d 100644
--- a/arch/arm/mach-msm/include/mach/ipa.h
+++ b/arch/arm/mach-msm/include/mach/ipa.h
@@ -201,6 +201,9 @@
struct ipa_ep_cfg_route route;
};
+typedef void (*ipa_notify_cb)(void *priv, enum ipa_dp_evt_type evt,
+ unsigned long data);
+
/**
* struct ipa_connect_params - low-level client connect input parameters. Either
* client allocates the data and desc FIFO and specifies that in data+desc OR
@@ -228,8 +231,7 @@
u32 client_bam_hdl;
u32 client_ep_idx;
void *priv;
- void (*notify)(void *priv, enum ipa_dp_evt_type evt,
- unsigned long data);
+ ipa_notify_cb notify;
u32 desc_fifo_sz;
u32 data_fifo_sz;
bool pipe_mem_preferred;
@@ -290,22 +292,7 @@
enum ipa_client_type client;
u32 desc_fifo_sz;
void *priv;
- void (*notify)(void *priv,
- enum ipa_dp_evt_type evt,
- unsigned long data);
-};
-
-/**
- * struct ipa_msg_meta_wrapper - message meta-data wrapper
- * @meta: the meta-data itself
- * @link: opaque to client
- * @meta_wrapper_free: function to free the metadata wrapper when IPA driver
- * is done with it
- */
-struct ipa_msg_meta_wrapper {
- struct ipa_msg_meta meta;
- struct list_head link;
- void (*meta_wrapper_free)(struct ipa_msg_meta_wrapper *buff);
+ ipa_notify_cb notify;
};
/**
@@ -319,32 +306,53 @@
};
/**
- * struct ipa_msg_wrapper - message wrapper
- * @msg: the message buffer itself, MUST exist after call returns, will
- * be freed by IPA driver when it is done with it
- * @link: opaque to client
- * @msg_free: function to free the message when IPA driver is done with it
- * @msg_wrapper_free: function to free the message wrapper when IPA driver is
- * done with it
+ * typedef ipa_msg_free_fn - callback function
+ * @param buff - [in] the message payload to free
+ * @param len - [in] size of message payload
+ * @param type - [in] the message type
+ *
+ * Message callback registered by kernel client with IPA driver to
+ * free message payload after IPA driver processing is complete
+ *
+ * No return value
*/
-struct ipa_msg_wrapper {
- void *msg;
- struct list_head link;
- void (*msg_free)(void *msg);
- void (*msg_wrapper_free)(struct ipa_msg_wrapper *buff);
+typedef void (*ipa_msg_free_fn)(void *buff, u32 len, u32 type);
+
+/**
+ * typedef ipa_msg_pull_fn - callback function
+ * @param buff - [in] where to copy message payload
+ * @param len - [in] size of buffer to copy payload into
+ * @param type - [in] the message type
+ *
+ * Message callback registered by kernel client with IPA driver for
+ * IPA driver to pull messages from the kernel client upon demand from
+ * user-space
+ *
+ * Returns how many bytes were copied into the buffer.
+ */
+typedef int (*ipa_msg_pull_fn)(void *buff, u32 len, u32 type);
+
+/**
+ * enum ipa_bridge_dir - direction of the bridge from air interface perspective
+ *
+ * IPA bridge direction
+ */
+enum ipa_bridge_dir {
+ IPA_BRIDGE_DIR_DL,
+ IPA_BRIDGE_DIR_UL,
+ IPA_BRIDGE_DIR_MAX
};
/**
- * typedef ipa_pull_fn - callback function
- * @buf - [in] the buffer to populate the message into
- * @sz - [in] the size of the buffer
+ * enum ipa_bridge_type - type of SW bridge
*
- * callback function registered by kernel client with IPA driver for IPA driver
- * to be able to pull messages from the kernel client asynchronously.
- *
- * Returns how many bytes were copied into the buffer, negative on failure.
+ * IPA bridge type
*/
-typedef int (*ipa_pull_fn)(void *buf, uint16_t sz);
+enum ipa_bridge_type {
+ IPA_BRIDGE_TYPE_TETHERED,
+ IPA_BRIDGE_TYPE_EMBEDDED,
+ IPA_BRIDGE_TYPE_MAX
+};
#ifdef CONFIG_IPA
@@ -425,6 +433,21 @@
int ipa_nat_del_cmd(struct ipa_ioc_v4_nat_del *del);
/*
+ * Messaging
+ */
+int ipa_send_msg(struct ipa_msg_meta *meta, void *buff,
+ ipa_msg_free_fn callback);
+int ipa_register_pull_msg(struct ipa_msg_meta *meta, ipa_msg_pull_fn callback);
+int ipa_deregister_pull_msg(struct ipa_msg_meta *meta);
+
+/*
+ * Interface
+ */
+int ipa_register_intf(const char *name, const struct ipa_tx_intf *tx,
+ const struct ipa_rx_intf *rx);
+int ipa_deregister_intf(const char *name);
+
+/*
* Aggregation
*/
int ipa_set_aggr_mode(enum ipa_aggr_mode mode);
@@ -445,6 +468,15 @@
int wwan_logical_channel_id);
/*
+ * SW bridge (between IPA and A2)
+ */
+int ipa_bridge_setup(enum ipa_bridge_dir dir, enum ipa_bridge_type type,
+ struct ipa_sys_connect_params *sys_in, u32 *clnt_hdl);
+int ipa_bridge_teardown(enum ipa_bridge_dir dir, enum ipa_bridge_type type,
+ u32 clnt_hdl);
+
+
+/*
* Data path
*/
int ipa_tx_dp(enum ipa_client_type dst, struct sk_buff *skb,
@@ -473,7 +505,6 @@
return -EPERM;
}
-
/*
* Configuration
*/
@@ -483,42 +514,36 @@
return -EPERM;
}
-
static inline int ipa_cfg_ep_nat(u32 clnt_hdl,
const struct ipa_ep_cfg_nat *ipa_ep_cfg)
{
return -EPERM;
}
-
static inline int ipa_cfg_ep_hdr(u32 clnt_hdl,
const struct ipa_ep_cfg_hdr *ipa_ep_cfg)
{
return -EPERM;
}
-
static inline int ipa_cfg_ep_mode(u32 clnt_hdl,
const struct ipa_ep_cfg_mode *ipa_ep_cfg)
{
return -EPERM;
}
-
static inline int ipa_cfg_ep_aggr(u32 clnt_hdl,
const struct ipa_ep_cfg_aggr *ipa_ep_cfg)
{
return -EPERM;
}
-
static inline int ipa_cfg_ep_route(u32 clnt_hdl,
const struct ipa_ep_cfg_route *ipa_ep_cfg)
{
return -EPERM;
}
-
/*
* Header removal / addition
*/
@@ -527,43 +552,36 @@
return -EPERM;
}
-
static inline int ipa_del_hdr(struct ipa_ioc_del_hdr *hdls)
{
return -EPERM;
}
-
static inline int ipa_commit_hdr(void)
{
return -EPERM;
}
-
static inline int ipa_reset_hdr(void)
{
return -EPERM;
}
-
static inline int ipa_get_hdr(struct ipa_ioc_get_hdr *lookup)
{
return -EPERM;
}
-
static inline int ipa_put_hdr(u32 hdr_hdl)
{
return -EPERM;
}
-
static inline int ipa_copy_hdr(struct ipa_ioc_copy_hdr *copy)
{
return -EPERM;
}
-
/*
* Routing
*/
@@ -572,37 +590,31 @@
return -EPERM;
}
-
static inline int ipa_del_rt_rule(struct ipa_ioc_del_rt_rule *hdls)
{
return -EPERM;
}
-
static inline int ipa_commit_rt(enum ipa_ip_type ip)
{
return -EPERM;
}
-
static inline int ipa_reset_rt(enum ipa_ip_type ip)
{
return -EPERM;
}
-
static inline int ipa_get_rt_tbl(struct ipa_ioc_get_rt_tbl *lookup)
{
return -EPERM;
}
-
static inline int ipa_put_rt_tbl(u32 rt_tbl_hdl)
{
return -EPERM;
}
-
/*
* Filtering
*/
@@ -611,25 +623,21 @@
return -EPERM;
}
-
static inline int ipa_del_flt_rule(struct ipa_ioc_del_flt_rule *hdls)
{
return -EPERM;
}
-
static inline int ipa_commit_flt(enum ipa_ip_type ip)
{
return -EPERM;
}
-
static inline int ipa_reset_flt(enum ipa_ip_type ip)
{
return -EPERM;
}
-
/*
* NAT
*/
@@ -656,6 +664,40 @@
return -EPERM;
}
+/*
+ * Messaging
+ */
+static inline int ipa_send_msg(struct ipa_msg_meta *meta, void *buff,
+ ipa_msg_free_fn callback)
+{
+ return -EPERM;
+}
+
+static inline int ipa_register_pull_msg(struct ipa_msg_meta *meta,
+ ipa_msg_pull_fn callback)
+{
+ return -EPERM;
+}
+
+static inline int ipa_deregister_pull_msg(struct ipa_msg_meta *meta)
+{
+ return -EPERM;
+}
+
+/*
+ * Interface
+ */
+static inline int ipa_register_intf(const char *name,
+ const struct ipa_tx_intf *tx,
+ const struct ipa_rx_intf *rx)
+{
+ return -EPERM;
+}
+
+static inline int ipa_deregister_intf(const char *name)
+{
+ return -EPERM;
+}
/*
* Aggregation
@@ -665,19 +707,16 @@
return -EPERM;
}
-
static inline int ipa_set_qcncm_ndp_sig(char sig[3])
{
return -EPERM;
}
-
static inline int ipa_set_single_ndp_per_mbim(bool enable)
{
return -EPERM;
}
-
/*
* rmnet bridge
*/
@@ -686,13 +725,11 @@
return -EPERM;
}
-
static inline int rmnet_bridge_disconnect(void)
{
return -EPERM;
}
-
static inline int rmnet_bridge_connect(u32 producer_hdl,
u32 consumer_hdl,
int wwan_logical_channel_id)
@@ -700,6 +737,23 @@
return -EPERM;
}
+/*
+ * SW bridge (between IPA and A2)
+ */
+static inline int ipa_bridge_setup(enum ipa_bridge_dir dir,
+ enum ipa_bridge_type type,
+ struct ipa_sys_connect_params *sys_in,
+ u32 *clnt_hdl)
+{
+ return -EPERM;
+}
+
+static inline int ipa_bridge_teardown(enum ipa_bridge_dir dir,
+ enum ipa_bridge_type type,
+ u32 clnt_hdl)
+{
+ return -EPERM;
+}
/*
* Data path
@@ -710,7 +764,6 @@
return -EPERM;
}
-
/*
* System pipes
*/
@@ -720,13 +773,11 @@
return -EPERM;
}
-
static inline int ipa_teardown_sys_pipe(u32 clnt_hdl)
{
return -EPERM;
}
-
#endif /* CONFIG_IPA*/
#endif /* _IPA_H_ */
diff --git a/arch/arm/mach-msm/include/mach/kgsl.h b/arch/arm/mach-msm/include/mach/kgsl.h
index 2447e81..b68aff8 100644
--- a/arch/arm/mach-msm/include/mach/kgsl.h
+++ b/arch/arm/mach-msm/include/mach/kgsl.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -21,7 +21,7 @@
#define KGSL_CLK_MEM_IFACE 0x00000010
#define KGSL_CLK_AXI 0x00000020
-#define KGSL_MAX_PWRLEVELS 5
+#define KGSL_MAX_PWRLEVELS 10
#define KGSL_CONVERT_TO_MBPS(val) \
(val*1000*1000U)
@@ -73,6 +73,7 @@
unsigned int nap_allowed;
unsigned int clk_map;
unsigned int idle_needed;
+ unsigned int step_mul;
struct msm_bus_scale_pdata *bus_scale_table;
struct kgsl_device_iommu_data *iommu_data;
int iommu_count;
diff --git a/arch/arm/mach-msm/include/mach/msm_mpmctr.h b/arch/arm/mach-msm/include/mach/msm_mpmctr.h
new file mode 100644
index 0000000..d3d853f
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_mpmctr.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#ifndef __MSM_MPMCTR_H__
+#define __MSM_MPMCTR_H__
+
+/*
+ * returns the count value of the mpm timetick.
+ */
+uint32_t msm_mpm_get_count(void);
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/socinfo.h b/arch/arm/mach-msm/include/mach/socinfo.h
index d9b0336..aeeaae6 100644
--- a/arch/arm/mach-msm/include/mach/socinfo.h
+++ b/arch/arm/mach-msm/include/mach/socinfo.h
@@ -58,6 +58,14 @@
of_machine_is_compatible("qcom,msm8226-sim")
#define machine_is_msm8226_rumi() \
of_machine_is_compatible("qcom,msm8226-rumi")
+#define machine_is_msm8226_cdp() \
+ of_machine_is_compatible("qcom,msm8226-cdp")
+#define machine_is_msm8226_fluid() \
+ of_machine_is_compatible("qcom,msm8226-fluid")
+#define machine_is_msm8226_mtp() \
+ of_machine_is_compatible("qcom,msm8226-mtp")
+#define machine_is_msm8226_qrd() \
+ of_machine_is_compatible("qcom,msm8226-qrd")
#define early_machine_is_msm8610() \
of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,msm8610")
#define machine_is_msm8610() \
diff --git a/arch/arm/mach-msm/include/mach/usb_gadget_xport.h b/arch/arm/mach-msm/include/mach/usb_gadget_xport.h
index 9cd4f3f..a183f0e 100644
--- a/arch/arm/mach-msm/include/mach/usb_gadget_xport.h
+++ b/arch/arm/mach-msm/include/mach/usb_gadget_xport.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -19,6 +19,7 @@
USB_GADGET_XPORT_TTY,
USB_GADGET_XPORT_SDIO,
USB_GADGET_XPORT_SMD,
+ USB_GADGET_XPORT_QTI,
USB_GADGET_XPORT_BAM,
USB_GADGET_XPORT_BAM2BAM,
USB_GADGET_XPORT_BAM2BAM_IPA,
@@ -38,6 +39,8 @@
return "SDIO";
case USB_GADGET_XPORT_SMD:
return "SMD";
+ case USB_GADGET_XPORT_QTI:
+ return "QTI";
case USB_GADGET_XPORT_BAM:
return "BAM";
case USB_GADGET_XPORT_BAM2BAM:
@@ -63,6 +66,8 @@
return USB_GADGET_XPORT_SDIO;
if (!strncasecmp("SMD", name, XPORT_STR_LEN))
return USB_GADGET_XPORT_SMD;
+ if (!strncasecmp("QTI", name, XPORT_STR_LEN))
+ return USB_GADGET_XPORT_QTI;
if (!strncasecmp("BAM", name, XPORT_STR_LEN))
return USB_GADGET_XPORT_BAM;
if (!strncasecmp("BAM2BAM", name, XPORT_STR_LEN))
diff --git a/arch/arm/mach-msm/ipc_router.c b/arch/arm/mach-msm/ipc_router.c
index 265435a..ea874bd 100644
--- a/arch/arm/mach-msm/ipc_router.c
+++ b/arch/arm/mach-msm/ipc_router.c
@@ -558,9 +558,9 @@
mutex_init(&port_ptr->port_rx_q_lock);
init_waitqueue_head(&port_ptr->port_rx_wait_q);
snprintf(port_ptr->rx_wakelock_name, MAX_WAKELOCK_NAME_SZ,
- "msm_ipc_read%08x:%08x",
- port_ptr->this_port.node_id,
- port_ptr->this_port.port_id);
+ "ipc%08x_%s",
+ port_ptr->this_port.port_id,
+ current->comm);
wake_lock_init(&port_ptr->port_rx_wake_lock,
WAKE_LOCK_SUSPEND, port_ptr->rx_wakelock_name);
diff --git a/arch/arm/mach-msm/krait-regulator.c b/arch/arm/mach-msm/krait-regulator.c
index 52aa43a..0c1e279 100644
--- a/arch/arm/mach-msm/krait-regulator.c
+++ b/arch/arm/mach-msm/krait-regulator.c
@@ -291,6 +291,11 @@
int krait_power_mdd_enable(int cpu_num, bool on)
{
+ /*
+ * Expected to be called when the cpu goes to retention mode as a part
+ * of idle power collapse. IT is guaranteed that cpu won't be put in
+ * retention while being hotplugged out
+ */
struct krait_power_vreg *kvreg = per_cpu(krait_vregs, cpu_num);
if (!on && kvreg->mode == LDO_MODE) {
@@ -298,7 +303,7 @@
return -EINVAL;
}
- if ((on && kvreg->mode == LDO_MODE) || (!on && kvreg->mode == HS_MODE))
+ if (on && kvreg->mode == LDO_MODE)
return 0;
__krait_power_mdd_enable(kvreg, on);
@@ -801,6 +806,8 @@
int rc;
mutex_lock(&pvreg->krait_power_vregs_lock);
+ if (kvreg->mode == LDO_MODE)
+ __krait_power_mdd_enable(kvreg, true);
kvreg->online = true;
rc = _get_optimum_mode(rdev, kvreg->uV, kvreg->uV, kvreg->load_uA);
if (rc < 0)
@@ -830,6 +837,8 @@
goto dis_err;
rc = _set_voltage(rdev, kvreg->uV, kvreg->uV);
+ if (kvreg->mode == LDO_MODE)
+ __krait_power_mdd_enable(kvreg, false);
dis_err:
mutex_unlock(&pvreg->krait_power_vregs_lock);
return rc;
diff --git a/arch/arm/mach-msm/lpm_levels.c b/arch/arm/mach-msm/lpm_levels.c
index dec62f0..539a4fe 100644
--- a/arch/arm/mach-msm/lpm_levels.c
+++ b/arch/arm/mach-msm/lpm_levels.c
@@ -66,18 +66,12 @@
atomic_notifier_call_chain(&__get_cpu_var(lpm_notify_head),
MSM_LPM_STATE_ENTER, &sleep_data);
- ret = msm_rpm_enter_sleep();
- if (ret) {
- pr_warn("%s(): RPM failed to enter sleep err:%d\n",
- __func__, ret);
- goto bail;
- }
if (from_idle)
debug_mask = msm_lpm_lvl_dbg_msk &
- MSM_LPM_LVL_DBG_IDLE_LIMITS;
+ MSM_LPM_LVL_DBG_IDLE_LIMITS;
else
debug_mask = msm_lpm_lvl_dbg_msk &
- MSM_LPM_LVL_DBG_SUSPEND_LIMITS;
+ MSM_LPM_LVL_DBG_SUSPEND_LIMITS;
if (debug_mask)
pr_info("%s(): pxo:%d l2:%d mem:0x%x(0x%x) dig:0x%x(0x%x)\n",
@@ -88,6 +82,19 @@
l->vdd_dig_upper_bound);
ret = msm_lpmrs_enter_sleep(sclk_count, l, from_idle, notify_rpm);
+ if (ret) {
+ pr_warn("%s() LPM resources failed to enter sleep\n",
+ __func__);
+ goto bail;
+ }
+ if (notify_rpm) {
+ ret = msm_rpm_enter_sleep(debug_mask);
+ if (ret) {
+ pr_warn("%s(): RPM failed to enter sleep err:%d\n",
+ __func__, ret);
+ goto bail;
+ }
+ }
bail:
return ret;
}
@@ -95,9 +102,11 @@
static void msm_lpm_exit_sleep(void *limits, bool from_idle,
bool notify_rpm, bool collapsed)
{
- msm_rpm_exit_sleep();
+
msm_lpmrs_exit_sleep((struct msm_rpmrs_limits *)limits,
from_idle, notify_rpm, collapsed);
+ if (notify_rpm)
+ msm_rpm_exit_sleep();
atomic_notifier_call_chain(&__get_cpu_var(lpm_notify_head),
MSM_LPM_STATE_EXIT, NULL);
}
diff --git a/arch/arm/mach-msm/lpm_resources.c b/arch/arm/mach-msm/lpm_resources.c
index 5d7fc94..60184b4 100644
--- a/arch/arm/mach-msm/lpm_resources.c
+++ b/arch/arm/mach-msm/lpm_resources.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -108,6 +108,12 @@
MSM_LPM_LOCAL_RS_TYPE = 1,
};
+enum {
+ MSM_SCM_L2_ON = 0,
+ MSM_SCM_L2_OFF = 1,
+ MSM_SCM_L2_GDHS = 3,
+};
+
struct msm_lpm_resource {
struct msm_lpm_rs_data rs_data;
uint32_t sleep_value;
@@ -407,15 +413,16 @@
{
int lpm, rc;
- msm_pm_set_l2_flush_flag(0);
+ msm_pm_set_l2_flush_flag(MSM_SCM_L2_ON);
switch (sleep_mode) {
case MSM_LPM_L2_CACHE_HSFS_OPEN:
lpm = MSM_SPM_L2_MODE_POWER_COLLAPSE;
- msm_pm_set_l2_flush_flag(1);
+ msm_pm_set_l2_flush_flag(MSM_SCM_L2_OFF);
break;
case MSM_LPM_L2_CACHE_GDHS:
lpm = MSM_SPM_L2_MODE_GDHS;
+ msm_pm_set_l2_flush_flag(MSM_SCM_L2_GDHS);
break;
case MSM_LPM_L2_CACHE_RETENTION:
lpm = MSM_SPM_L2_MODE_RETENTION;
@@ -668,7 +675,8 @@
}
msm_lpm_get_rpm_notif = true;
- msm_mpm_enter_sleep(sclk_count, from_idle);
+ if (notify_rpm)
+ msm_mpm_enter_sleep(sclk_count, from_idle);
return ret;
}
diff --git a/arch/arm/mach-msm/msm_mpmctr.c b/arch/arm/mach-msm/msm_mpmctr.c
new file mode 100644
index 0000000..4ab82ab
--- /dev/null
+++ b/arch/arm/mach-msm/msm_mpmctr.c
@@ -0,0 +1,99 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/smp.h>
+#include <linux/clk.h>
+#include <linux/cpu.h>
+#include <linux/sched.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <mach/msm_mpmctr.h>
+
+static void __iomem *mpm_timer_base;
+
+uint32_t msm_mpm_get_count(void)
+{
+ uint32_t count;
+ if (!mpm_timer_base)
+ return 0;
+
+ count = __raw_readl_no_log(mpm_timer_base);
+ pr_debug("mpm sclk sync:(%u)", count);
+ return count;
+}
+EXPORT_SYMBOL(msm_mpm_get_count);
+
+static inline void msm_mpmctr_show_count(void)
+{
+ unsigned long long t;
+ unsigned long nsec_rem;
+
+ t = sched_clock();
+
+ nsec_rem = do_div(t, 1000000000)/1000;
+
+ printk(KERN_INFO "mpm_counter: [%5lu.%06lu]:(%u)\n",
+ (unsigned long)t, nsec_rem,
+ msm_mpm_get_count());
+
+}
+
+static struct of_device_id msm_mpmctr_of_match[] = {
+ {.compatible = "qcom,mpm-counter"},
+ {}
+};
+
+static struct platform_driver msm_mpmctr_driver = {
+ .driver = {
+ .name = "msm_mpctr",
+ .owner = THIS_MODULE,
+ .of_match_table = msm_mpmctr_of_match,
+ },
+};
+
+static int __init mpmctr_set_register(struct device_node *np)
+{
+ if (of_get_address(np, 0, NULL, NULL)) {
+ mpm_timer_base = of_iomap(np, 0);
+ if (!mpm_timer_base) {
+ pr_err("%s: cannot map timer base\n", __func__);
+ return -ENOMEM;
+ }
+ }
+ return 0;
+}
+
+static int __init msm_mpmctr_probe(struct platform_device *pdev)
+{
+ if (!pdev->dev.of_node)
+ return -ENODEV;
+
+ if (mpmctr_set_register(pdev->dev.of_node))
+ return -ENODEV;
+
+ msm_mpmctr_show_count();
+
+ return 0;
+}
+
+static int __init mpmctr_init(void)
+{
+ return platform_driver_probe(&msm_mpmctr_driver, msm_mpmctr_probe);
+}
+
+module_init(mpmctr_init)
diff --git a/arch/arm/mach-msm/no-pm.c b/arch/arm/mach-msm/no-pm.c
index 0db6e68..a8d4fdb 100644
--- a/arch/arm/mach-msm/no-pm.c
+++ b/arch/arm/mach-msm/no-pm.c
@@ -37,15 +37,11 @@
void msm_pm_set_irq_extns(struct msm_pm_irq_calls *irq_calls) {}
-int msm_pm_idle_prepare(struct cpuidle_device *dev,
+enum msm_pm_sleep_mode msm_pm_idle_enter(struct cpuidle_device *dev,
struct cpuidle_driver *drv, int index)
{
return -ENOSYS;
}
-int msm_pm_idle_enter(enum msm_pm_sleep_mode sleep_mode)
-{
- return -ENOSYS;
-}
-
void msm_pm_enable_retention(bool enable) {}
+
diff --git a/arch/arm/mach-msm/ocmem_rdm.c b/arch/arm/mach-msm/ocmem_rdm.c
index 4190aea..4ff7212 100644
--- a/arch/arm/mach-msm/ocmem_rdm.c
+++ b/arch/arm/mach-msm/ocmem_rdm.c
@@ -206,6 +206,11 @@
return rc;
}
+ /* Clear DM Mask */
+ ocmem_write(DM_MASK_RESET, dm_base + DM_INTR_MASK);
+ /* Clear DM Interrupts */
+ ocmem_write(DM_INTR_RESET, dm_base + DM_INTR_CLR);
+
for (i = 0, j = slot; i < num_chunks; i++, j++) {
struct ocmem_chunk *chunk = &clist->chunks[i];
diff --git a/arch/arm/mach-msm/perf_debug.c b/arch/arm/mach-msm/perf_debug.c
index 8c942ad..0579145 100644
--- a/arch/arm/mach-msm/perf_debug.c
+++ b/arch/arm/mach-msm/perf_debug.c
@@ -25,6 +25,8 @@
"0 msm: perf: add debug patch logging framework\n"
"1 Perf: Restore counter after powercollapse for generic ARM PMU's\n"
"2 Perf: Toggle PMU IRQ when CPU's are hotplugged\n"
+ "3 Perf: Correct irq for CPU hotplug detection\n"
+ "4 Perf: Check perf activity on correct CPU\n"
;
static ssize_t desc_read(struct file *fp, char __user *buf,
diff --git a/arch/arm/mach-msm/pil-q6v5.c b/arch/arm/mach-msm/pil-q6v5.c
index 7f8d3b9..0263faf 100644
--- a/arch/arm/mach-msm/pil-q6v5.c
+++ b/arch/arm/mach-msm/pil-q6v5.c
@@ -167,7 +167,7 @@
/* Assert Q6 resets */
val = readl_relaxed(drv->reg_base + QDSP6SS_RESET);
- val = (Q6SS_CORE_ARES | Q6SS_BUS_ARES_ENA);
+ val |= (Q6SS_CORE_ARES | Q6SS_BUS_ARES_ENA);
writel_relaxed(val, drv->reg_base + QDSP6SS_RESET);
/* Kill power at block headswitch */
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index 0b08238..b52d284 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -11,6 +11,7 @@
*
*/
+#include <linux/debugfs.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
@@ -40,7 +41,6 @@
#ifdef CONFIG_VFP
#include <asm/vfp.h>
#endif
-
#include "acpuclock.h"
#include "clock.h"
#include "avs.h"
@@ -54,9 +54,27 @@
#include <mach/event_timer.h>
#define CREATE_TRACE_POINTS
#include "trace_msm_low_power.h"
-/******************************************************************************
- * Debug Definitions
- *****************************************************************************/
+
+#define SCM_L2_RETENTION (0x2)
+#define SCM_CMD_TERMINATE_PC (0x2)
+
+#define GET_CPU_OF_ATTR(attr) \
+ (container_of(attr, struct msm_pm_kobj_attribute, ka)->cpu)
+
+#define SCLK_HZ (32768)
+#define MSM_PM_SLEEP_TICK_LIMIT (0x6DDD000)
+
+#define NUM_OF_COUNTERS 3
+#define MAX_BUF_SIZE 512
+
+static int msm_pm_debug_mask = 1;
+module_param_named(
+ debug_mask, msm_pm_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP
+);
+
+static int msm_pm_sleep_time_override;
+module_param_named(sleep_time_override,
+ msm_pm_sleep_time_override, int, S_IRUGO | S_IWUSR | S_IWGRP);
enum {
MSM_PM_DEBUG_SUSPEND = BIT(0),
@@ -70,24 +88,12 @@
MSM_PM_DEBUG_HOTPLUG = BIT(8),
};
-static int msm_pm_debug_mask = 1;
-module_param_named(
- debug_mask, msm_pm_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP
-);
-static int msm_pm_retention_tz_call;
-
-/******************************************************************************
- * Sleep Modes and Parameters
- *****************************************************************************/
enum {
MSM_PM_MODE_ATTR_SUSPEND,
MSM_PM_MODE_ATTR_IDLE,
MSM_PM_MODE_ATTR_NR,
};
-#define SCM_L2_RETENTION (0x2)
-#define SCM_CMD_TERMINATE_PC (0x2)
-
static char *msm_pm_mode_attr_labels[MSM_PM_MODE_ATTR_NR] = {
[MSM_PM_MODE_ATTR_SUSPEND] = "suspend_enabled",
[MSM_PM_MODE_ATTR_IDLE] = "idle_enabled",
@@ -98,9 +104,6 @@
struct kobj_attribute ka;
};
-#define GET_CPU_OF_ATTR(attr) \
- (container_of(attr, struct msm_pm_kobj_attribute, ka)->cpu)
-
struct msm_pm_sysfs_sleep_mode {
struct kobject *kobj;
struct attribute_group attr_group;
@@ -116,10 +119,15 @@
"standalone_power_collapse",
};
-static struct msm_pm_init_data_type msm_pm_init_data;
static struct hrtimer pm_hrtimer;
static struct msm_pm_sleep_ops pm_sleep_ops;
static bool msm_pm_ldo_retention_enabled = true;
+static bool msm_pm_use_sync_timer;
+static struct msm_pm_cp15_save_data cp15_data;
+static bool msm_pm_retention_calls_tz;
+static uint32_t msm_pm_max_sleep_time;
+static bool msm_no_ramp_down_pc;
+
/*
* Write out the attribute.
*/
@@ -166,9 +174,6 @@
return ret;
}
-/*
- * Read in the new attribute value.
- */
static ssize_t msm_pm_mode_attr_store(struct kobject *kobj,
struct kobj_attribute *attr, const char *buf, size_t count)
{
@@ -205,10 +210,7 @@
return ret ? ret : count;
}
-/*
- * Add sysfs entries for one cpu.
- */
-static int __init msm_pm_mode_sysfs_add_cpu(
+static int __devinit msm_pm_mode_sysfs_add_cpu(
unsigned int cpu, struct kobject *modes_kobj)
{
char cpu_name[8];
@@ -291,10 +293,7 @@
return ret;
}
-/*
- * Add sysfs entries for the sleep modes.
- */
-static int __init msm_pm_mode_sysfs_add(void)
+int __devinit msm_pm_mode_sysfs_add(void)
{
struct kobject *module_kobj;
struct kobject *modes_kobj;
@@ -328,10 +327,6 @@
return ret;
}
-/******************************************************************************
- * Configure Hardware before/after Low Power Mode
- *****************************************************************************/
-
/*
* Configure hardware registers in preparation for Apps power down.
*/
@@ -374,22 +369,6 @@
return;
}
-
-/******************************************************************************
- * Suspend Max Sleep Time
- *****************************************************************************/
-
-#ifdef CONFIG_MSM_SLEEP_TIME_OVERRIDE
-static int msm_pm_sleep_time_override;
-module_param_named(sleep_time_override,
- msm_pm_sleep_time_override, int, S_IRUGO | S_IWUSR | S_IWGRP);
-#endif
-
-#define SCLK_HZ (32768)
-#define MSM_PM_SLEEP_TICK_LIMIT (0x6DDD000)
-
-static uint32_t msm_pm_max_sleep_time;
-
/*
* Convert time from nanoseconds to slow clock ticks, then cap it to the
* specified limit
@@ -408,36 +387,21 @@
if (max_sleep_time_ns == 0) {
msm_pm_max_sleep_time = 0;
} else {
- msm_pm_max_sleep_time = (uint32_t)msm_pm_convert_and_cap_time(
+ msm_pm_max_sleep_time =
+ (uint32_t)msm_pm_convert_and_cap_time(
max_sleep_time_ns, MSM_PM_SLEEP_TICK_LIMIT);
if (msm_pm_max_sleep_time == 0)
msm_pm_max_sleep_time = 1;
}
- if (msm_pm_debug_mask & MSM_PM_DEBUG_SUSPEND)
+ if (MSM_PM_DEBUG_SUSPEND & msm_pm_debug_mask)
pr_info("%s: Requested %lld ns Giving %u sclk ticks\n",
- __func__, max_sleep_time_ns, msm_pm_max_sleep_time);
+ __func__, max_sleep_time_ns,
+ msm_pm_max_sleep_time);
}
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;
@@ -455,11 +419,12 @@
* 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);
+ cp15_data.active_vdd = msm_spm_get_vdd(0);
+ for (i = 0; i < cp15_data.reg_saved_state_size; i++)
+ cp15_data.reg_val[i] =
+ get_l2_indirect_reg(
+ cp15_data.reg_data[i]);
+ msm_spm_set_vdd(0, cp15_data.qsb_pc_vdd);
}
}
@@ -472,22 +437,20 @@
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);
+ for (i = 0; i < cp15_data.reg_saved_state_size; i++)
+ set_l2_indirect_reg(
+ cp15_data.reg_data[i],
+ cp15_data.reg_val[i]);
+ msm_spm_set_vdd(0, cp15_data.active_vdd);
}
}
-static void *msm_pm_idle_rs_limits;
-
static void msm_pm_swfi(void)
{
msm_pm_config_hw_before_swfi();
msm_arch_idle();
}
-
static void msm_pm_retention(void)
{
int ret = 0;
@@ -496,7 +459,7 @@
ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_POWER_RETENTION, false);
WARN_ON(ret);
- if (msm_pm_retention_tz_call)
+ if (msm_pm_retention_calls_tz)
scm_call_atomic1(SCM_SVC_BOOT, SCM_CMD_TERMINATE_PC,
SCM_L2_RETENTION);
else
@@ -567,7 +530,7 @@
static bool msm_pm_power_collapse(bool from_idle)
{
unsigned int cpu = smp_processor_id();
- unsigned long saved_acpuclk_rate;
+ unsigned long saved_acpuclk_rate = 0;
unsigned int avsdscr;
unsigned int avscsr;
bool collapsed;
@@ -584,28 +547,28 @@
avscsr = avs_get_avscsr();
avs_set_avscsr(0); /* Disable AVS */
- if (cpu_online(cpu))
+ if (cpu_online(cpu) && !msm_no_ramp_down_pc)
saved_acpuclk_rate = acpuclk_power_collapse();
- else
- saved_acpuclk_rate = 0;
if (MSM_PM_DEBUG_CLOCK & msm_pm_debug_mask)
pr_info("CPU%u: %s: change clock rate (old rate = %lu)\n",
cpu, __func__, saved_acpuclk_rate);
- if (msm_pm_save_cp15)
+ if (cp15_data.save_cp15)
msm_pm_save_cpu_reg();
collapsed = msm_pm_spm_power_collapse(cpu, from_idle, true);
- if (msm_pm_save_cp15)
+ if (cp15_data.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",
cpu, __func__, saved_acpuclk_rate);
- if (acpuclk_set_rate(cpu, saved_acpuclk_rate, SETRATE_PC) < 0)
+ if (!msm_no_ramp_down_pc &&
+ acpuclk_set_rate(cpu, saved_acpuclk_rate, SETRATE_PC)
+ < 0)
pr_err("CPU%u: %s: failed to restore clock rate(%lu)\n",
cpu, __func__, saved_acpuclk_rate);
} else {
@@ -635,15 +598,9 @@
return collapsed;
}
-static void msm_pm_target_init(void)
-{
- if (cpu_is_apq8064())
- msm_pm_save_cp15 = true;
-}
-
static int64_t msm_pm_timer_enter_idle(void)
{
- if (msm_pm_init_data.use_sync_timer)
+ if (msm_pm_use_sync_timer)
return ktime_to_ns(tick_nohz_get_sleep_length());
return msm_timer_enter_idle();
@@ -651,7 +608,7 @@
static void msm_pm_timer_exit_idle(bool timer_halted)
{
- if (msm_pm_init_data.use_sync_timer)
+ if (msm_pm_use_sync_timer)
return;
msm_timer_exit_idle((int) timer_halted);
@@ -661,7 +618,7 @@
{
int64_t time = 0;
- if (msm_pm_init_data.use_sync_timer)
+ if (msm_pm_use_sync_timer)
return ktime_to_ns(ktime_get());
time = msm_timer_get_sclk_time(period);
@@ -673,7 +630,7 @@
static int64_t msm_pm_timer_exit_suspend(int64_t time, int64_t period)
{
- if (msm_pm_init_data.use_sync_timer)
+ if (msm_pm_use_sync_timer)
return ktime_to_ns(ktime_get()) - time;
if (time != 0) {
@@ -765,8 +722,9 @@
}
}
-int msm_pm_idle_prepare(struct cpuidle_device *dev,
- struct cpuidle_driver *drv, int index)
+static int msm_pm_idle_prepare(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv, int index,
+ void **msm_pm_idle_rs_limits)
{
int i;
unsigned int power_usage = -1;
@@ -793,9 +751,9 @@
struct cpuidle_state_usage *st_usage = &dev->states_usage[i];
enum msm_pm_sleep_mode mode;
bool allow;
- void *rs_limits = NULL;
uint32_t power;
int idx;
+ void *rs_limits = NULL;
mode = (enum msm_pm_sleep_mode) cpuidle_get_statedata(st_usage);
idx = MSM_PM_MODE(dev->cpu, mode);
@@ -805,11 +763,9 @@
switch (mode) {
case MSM_PM_SLEEP_MODE_POWER_COLLAPSE:
- if (num_online_cpus() > 1) {
+ if (num_online_cpus() > 1)
allow = false;
- break;
- }
- /* fall through */
+ break;
case MSM_PM_SLEEP_MODE_RETENTION:
/*
* The Krait BHS regulator doesn't have enough head
@@ -817,62 +773,41 @@
* has disabled retention
*/
if (!msm_pm_ldo_retention_enabled)
- break;
-
- if (!allow)
- break;
-
- if (msm_pm_retention_tz_call &&
- num_online_cpus() > 1) {
allow = false;
- break;
- }
- /* fall through */
- case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE:
- if (!allow)
- break;
- /* fall through */
-
- case MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT:
- if (!allow)
- break;
- /* fall through */
-
- if (pm_sleep_ops.lowest_limits)
- rs_limits = pm_sleep_ops.lowest_limits(true,
- mode, &time_param, &power);
-
- if (MSM_PM_DEBUG_IDLE & msm_pm_debug_mask)
- pr_info("CPU%u: %s: %s, latency %uus, "
- "sleep %uus, limit %p\n",
- dev->cpu, __func__, state->desc,
- time_param.latency_us,
- time_param.sleep_us, rs_limits);
-
- if (!rs_limits)
+ if (msm_pm_retention_calls_tz && num_online_cpus() > 1)
allow = false;
break;
-
+ case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE:
+ case MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT:
+ break;
default:
allow = false;
break;
}
+ if (!allow)
+ continue;
+
+ if (pm_sleep_ops.lowest_limits)
+ rs_limits = pm_sleep_ops.lowest_limits(true,
+ mode, &time_param, &power);
+
if (MSM_PM_DEBUG_IDLE & msm_pm_debug_mask)
- pr_info("CPU%u: %s: allow %s: %d\n",
- dev->cpu, __func__, state->desc, (int)allow);
+ pr_info("CPU%u:%s:%s, latency %uus, slp %uus, lim %p\n",
+ dev->cpu, __func__, state->desc,
+ time_param.latency_us,
+ time_param.sleep_us, rs_limits);
+ if (!rs_limits)
+ continue;
- if (allow) {
- if (power < power_usage) {
- power_usage = power;
- modified_time_us = time_param.modified_time_us;
- ret = mode;
- }
-
- if (MSM_PM_SLEEP_MODE_POWER_COLLAPSE == mode)
- msm_pm_idle_rs_limits = rs_limits;
+ if (power < power_usage) {
+ power_usage = power;
+ modified_time_us = time_param.modified_time_us;
+ ret = mode;
+ *msm_pm_idle_rs_limits = rs_limits;
}
+
}
if (modified_time_us && !dev->cpu)
@@ -885,11 +820,27 @@
return ret;
}
-int msm_pm_idle_enter(enum msm_pm_sleep_mode sleep_mode)
+enum msm_pm_sleep_mode msm_pm_idle_enter(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv, int index)
{
int64_t time;
- int exit_stat;
bool collapsed = 1;
+ int exit_stat = -1;
+ enum msm_pm_sleep_mode sleep_mode;
+ void *msm_pm_idle_rs_limits = NULL;
+ int sleep_delay = 1;
+ int ret = -ENODEV;
+ int64_t timer_expiration = 0;
+ int notify_rpm = false;
+ bool timer_halted = false;
+
+ sleep_mode = msm_pm_idle_prepare(dev, drv, index,
+ &msm_pm_idle_rs_limits);
+
+ if (!msm_pm_idle_rs_limits) {
+ sleep_mode = MSM_PM_SLEEP_MODE_NOT_SELECTED;
+ goto cpuidle_enter_bail;
+ }
if (MSM_PM_DEBUG_IDLE & msm_pm_debug_mask)
pr_info("CPU%u: %s: mode %d\n",
@@ -897,6 +848,22 @@
time = ktime_to_ns(ktime_get());
+ if (sleep_mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE) {
+ notify_rpm = true;
+ timer_expiration = msm_pm_timer_enter_idle();
+
+ sleep_delay = (uint32_t) msm_pm_convert_and_cap_time(
+ timer_expiration, MSM_PM_SLEEP_TICK_LIMIT);
+ if (sleep_delay == 0) /* 0 would mean infinite time */
+ sleep_delay = 1;
+ }
+
+ if (pm_sleep_ops.enter_sleep)
+ ret = pm_sleep_ops.enter_sleep(sleep_delay,
+ msm_pm_idle_rs_limits, true, notify_rpm);
+ if (ret)
+ goto cpuidle_enter_bail;
+
switch (sleep_mode) {
case MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT:
msm_pm_swfi();
@@ -913,39 +880,16 @@
exit_stat = MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE;
break;
- case MSM_PM_SLEEP_MODE_POWER_COLLAPSE: {
- int64_t timer_expiration = 0;
- bool timer_halted = false;
- uint32_t sleep_delay;
- int ret = -ENODEV;
- int notify_rpm =
- (sleep_mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE);
- timer_expiration = msm_pm_timer_enter_idle();
-
- sleep_delay = (uint32_t) msm_pm_convert_and_cap_time(
- timer_expiration, MSM_PM_SLEEP_TICK_LIMIT);
- if (sleep_delay == 0) /* 0 would mean infinite time */
- sleep_delay = 1;
-
+ case MSM_PM_SLEEP_MODE_POWER_COLLAPSE:
if (MSM_PM_DEBUG_IDLE_CLK & msm_pm_debug_mask)
clock_debug_print_enabled();
- if (pm_sleep_ops.enter_sleep)
- ret = pm_sleep_ops.enter_sleep(sleep_delay,
- msm_pm_idle_rs_limits,
- true, notify_rpm);
- if (!ret) {
- collapsed = msm_pm_power_collapse(true);
- timer_halted = true;
+ collapsed = msm_pm_power_collapse(true);
+ timer_halted = true;
- if (pm_sleep_ops.exit_sleep)
- pm_sleep_ops.exit_sleep(msm_pm_idle_rs_limits,
- true, notify_rpm, collapsed);
- }
- msm_pm_timer_exit_idle(timer_halted);
exit_stat = MSM_PM_STAT_IDLE_POWER_COLLAPSE;
+ msm_pm_timer_exit_idle(timer_halted);
break;
- }
case MSM_PM_SLEEP_MODE_NOT_SELECTED:
goto cpuidle_enter_bail;
@@ -957,16 +901,24 @@
break;
}
- time = ktime_to_ns(ktime_get()) - time;
- msm_pm_add_stat(exit_stat, time);
- msm_pm_ftrace_lpm_exit(smp_processor_id(), sleep_mode,
- collapsed);
+ if (pm_sleep_ops.exit_sleep)
+ pm_sleep_ops.exit_sleep(msm_pm_idle_rs_limits, true,
+ notify_rpm, collapsed);
+ time = ktime_to_ns(ktime_get()) - time;
+ msm_pm_ftrace_lpm_exit(smp_processor_id(), sleep_mode, collapsed);
+ if (exit_stat >= 0)
+ msm_pm_add_stat(exit_stat, time);
do_div(time, 1000);
- return (int) time;
+ dev->last_residency = (int) time;
+ return sleep_mode;
cpuidle_enter_bail:
- return 0;
+ dev->last_residency = 0;
+ if (sleep_mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE)
+ msm_pm_timer_exit_idle(timer_halted);
+ sleep_mode = MSM_PM_SLEEP_MODE_NOT_SELECTED;
+ return sleep_mode;
}
void msm_pm_cpu_enter_lowpower(unsigned int cpu)
@@ -1060,17 +1012,16 @@
clock_debug_print_enabled();
-#ifdef CONFIG_MSM_SLEEP_TIME_OVERRIDE
if (msm_pm_sleep_time_override > 0) {
int64_t ns = NSEC_PER_SEC *
(int64_t) msm_pm_sleep_time_override;
msm_pm_set_max_sleep_time(ns);
msm_pm_sleep_time_override = 0;
}
-#endif /* CONFIG_MSM_SLEEP_TIME_OVERRIDE */
+
if (pm_sleep_ops.lowest_limits)
rs_limits = pm_sleep_ops.lowest_limits(false,
- MSM_PM_SLEEP_MODE_POWER_COLLAPSE, &time_param, &power);
+ MSM_PM_SLEEP_MODE_POWER_COLLAPSE, &time_param, &power);
if (rs_limits) {
if (pm_sleep_ops.enter_sleep)
@@ -1104,7 +1055,6 @@
msm_pm_swfi();
}
-
enter_exit:
if (MSM_PM_DEBUG_SUSPEND & msm_pm_debug_mask)
pr_info("%s: return\n", __func__);
@@ -1112,66 +1062,18 @@
return 0;
}
-static struct platform_suspend_ops msm_pm_ops = {
- .enter = msm_pm_enter,
- .valid = suspend_valid_only_mem,
-};
-
-/******************************************************************************
- * Initialization routine
- *****************************************************************************/
void msm_pm_set_sleep_ops(struct msm_pm_sleep_ops *ops)
{
if (ops)
pm_sleep_ops = *ops;
}
-void __init msm_pm_set_tz_retention_flag(unsigned int flag)
-{
- msm_pm_retention_tz_call = flag;
-}
-
-static int __devinit msm_pc_debug_probe(struct platform_device *pdev)
-{
- struct resource *res = NULL;
- int i ;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- goto fail;
-
- msm_pc_debug_counters_phys = res->start;
- WARN_ON(resource_size(res) < SZ_64);
- msm_pc_debug_counters = devm_ioremap_nocache(&pdev->dev, res->start,
- resource_size(res));
-
- if (!msm_pc_debug_counters)
- goto fail;
-
- for (i = 0; i < resource_size(res)/4; i++)
- __raw_writel(0, msm_pc_debug_counters + i * 4);
- return 0;
-fail:
- msm_pc_debug_counters = 0;
- msm_pc_debug_counters_phys = 0;
- return -EFAULT;
-}
-
-static struct of_device_id msm_pc_debug_table[] = {
- {.compatible = "qcom,pc-cntr"},
- {},
+static const struct platform_suspend_ops msm_pm_ops = {
+ .enter = msm_pm_enter,
+ .valid = suspend_valid_only_mem,
};
-static struct platform_driver msm_pc_counter_driver = {
- .probe = msm_pc_debug_probe,
- .driver = {
- .name = "pc-cntr",
- .owner = THIS_MODULE,
- .of_match_table = msm_pc_debug_table,
- },
-};
-
-static int __init msm_pm_init(void)
+static int __devinit msm_pm_init(void)
{
pgd_t *pc_pgd;
pmd_t *pmd;
@@ -1186,7 +1088,6 @@
unsigned long exit_phys;
/* Page table for cores to come back up safely. */
-
pc_pgd = pgd_alloc(&init_mm);
if (!pc_pgd)
return -ENOMEM;
@@ -1225,18 +1126,13 @@
msm_pm_mode_sysfs_add();
msm_pm_add_stats(enable_stats, ARRAY_SIZE(enable_stats));
-
suspend_set_ops(&msm_pm_ops);
- msm_pm_target_init();
hrtimer_init(&pm_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
msm_cpuidle_init();
- platform_driver_register(&msm_pc_counter_driver);
return 0;
}
-late_initcall(msm_pm_init);
-
static void __devinit msm_pm_set_flush_fn(uint32_t pc_mode)
{
msm_pm_disable_l2_fn = NULL;
@@ -1249,41 +1145,203 @@
}
}
+struct msm_pc_debug_counters_buffer {
+ void __iomem *reg;
+ u32 len;
+ char buf[MAX_BUF_SIZE];
+};
+
+static inline u32 msm_pc_debug_counters_read_register(
+ void __iomem *reg, int index , int offset)
+{
+ return readl_relaxed(reg + (index * 4 + offset) * 4);
+}
+
+static char *counter_name[] = {
+ "PC Entry Counter",
+ "Warmboot Entry Counter",
+ "PC Bailout Counter"
+};
+
+static int msm_pc_debug_counters_copy(
+ struct msm_pc_debug_counters_buffer *data)
+{
+ int j;
+ u32 stat;
+ unsigned int cpu;
+
+ for_each_possible_cpu(cpu) {
+ data->len += scnprintf(data->buf + data->len,
+ sizeof(data->buf)-data->len,
+ "CPU%d\n", cpu);
+
+ for (j = 0; j < NUM_OF_COUNTERS; j++) {
+ stat = msm_pc_debug_counters_read_register(
+ data->reg, cpu, j);
+ data->len += scnprintf(data->buf + data->len,
+ sizeof(data->buf)-data->len,
+ "\t%s : %d\n", counter_name[j],
+ stat);
+ }
+
+ }
+
+ return data->len;
+}
+
+static int msm_pc_debug_counters_file_read(struct file *file,
+ char __user *bufu, size_t count, loff_t *ppos)
+{
+ struct msm_pc_debug_counters_buffer *data;
+
+ data = file->private_data;
+
+ if (!data)
+ return -EINVAL;
+
+ if (!bufu || count < 0)
+ return -EINVAL;
+
+ if (!access_ok(VERIFY_WRITE, bufu, count))
+ return -EFAULT;
+
+ if (*ppos >= data->len && data->len == 0)
+ data->len = msm_pc_debug_counters_copy(data);
+
+ return simple_read_from_buffer(bufu, count, ppos,
+ data->buf, data->len);
+}
+
+static int msm_pc_debug_counters_file_open(struct inode *inode,
+ struct file *file)
+{
+ struct msm_pc_debug_counters_buffer *buf;
+ void __iomem *msm_pc_debug_counters_reg;
+
+ msm_pc_debug_counters_reg = inode->i_private;
+
+ if (!msm_pc_debug_counters_reg)
+ return -EINVAL;
+
+ file->private_data = kzalloc(
+ sizeof(struct msm_pc_debug_counters_buffer), GFP_KERNEL);
+
+ if (!file->private_data) {
+ pr_err("%s: ERROR kmalloc failed to allocate %d bytes\n",
+ __func__, sizeof(struct msm_pc_debug_counters_buffer));
+
+ return -ENOMEM;
+ }
+
+ buf = file->private_data;
+ buf->reg = msm_pc_debug_counters_reg;
+
+ return 0;
+}
+
+static int msm_pc_debug_counters_file_close(struct inode *inode,
+ struct file *file)
+{
+ kfree(file->private_data);
+ return 0;
+}
+
+static const struct file_operations msm_pc_debug_counters_fops = {
+ .open = msm_pc_debug_counters_file_open,
+ .read = msm_pc_debug_counters_file_read,
+ .release = msm_pc_debug_counters_file_close,
+ .llseek = no_llseek,
+};
+
static int __devinit msm_pm_8x60_probe(struct platform_device *pdev)
{
char *key = NULL;
+ struct dentry *dent = NULL;
uint32_t val = 0;
+ struct resource *res = NULL;
+ int i ;
+ struct msm_pm_init_data_type pdata_local;
int ret = 0;
+ memset(&pdata_local, 0, sizeof(struct msm_pm_init_data_type));
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res) {
+ msm_pc_debug_counters_phys = res->start;
+ WARN_ON(resource_size(res) < SZ_64);
+ msm_pc_debug_counters = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (msm_pc_debug_counters)
+ for (i = 0; i < resource_size(res)/4; i++)
+ __raw_writel(0, msm_pc_debug_counters + i * 4);
+
+ }
+
+ if (!msm_pc_debug_counters) {
+ msm_pc_debug_counters = 0;
+ msm_pc_debug_counters_phys = 0;
+ } else {
+ dent = debugfs_create_file("pc_debug_counter", S_IRUGO, NULL,
+ msm_pc_debug_counters,
+ &msm_pc_debug_counters_fops);
+ if (!dent)
+ pr_err("%s: ERROR debugfs_create_file failed\n",
+ __func__);
+ }
+
if (!pdev->dev.of_node) {
struct msm_pm_init_data_type *d = pdev->dev.platform_data;
if (!d)
goto pm_8x60_probe_done;
- msm_pm_init_data.pc_mode = d->pc_mode;
- msm_pm_set_flush_fn(msm_pm_init_data.pc_mode);
- msm_pm_init_data.use_sync_timer = d->use_sync_timer;
+ memcpy(&pdata_local, d, sizeof(struct msm_pm_init_data_type));
+
} else {
key = "qcom,pc-mode";
ret = of_property_read_u32(pdev->dev.of_node, key, &val);
-
if (ret) {
pr_debug("%s: Cannot read %s,defaulting to 0",
__func__, key);
val = MSM_PM_PC_TZ_L2_INT;
ret = 0;
}
-
- msm_pm_init_data.pc_mode = val;
- msm_pm_set_flush_fn(msm_pm_init_data.pc_mode);
+ pdata_local.pc_mode = val;
key = "qcom,use-sync-timer";
- msm_pm_init_data.use_sync_timer =
+ pdata_local.use_sync_timer =
of_property_read_bool(pdev->dev.of_node, key);
+
+ key = "qcom,saw-turns-off-pll";
+ msm_no_ramp_down_pc = of_property_read_bool(pdev->dev.of_node,
+ key);
}
+ if (pdata_local.cp15_data.reg_data &&
+ pdata_local.cp15_data.reg_saved_state_size > 0) {
+ cp15_data.reg_data = kzalloc(sizeof(uint32_t) *
+ pdata_local.cp15_data.reg_saved_state_size,
+ GFP_KERNEL);
+ if (!cp15_data.reg_data)
+ return -ENOMEM;
+
+ cp15_data.reg_val = kzalloc(sizeof(uint32_t) *
+ pdata_local.cp15_data.reg_saved_state_size,
+ GFP_KERNEL);
+ if (cp15_data.reg_val)
+ return -ENOMEM;
+
+ memcpy(cp15_data.reg_data, pdata_local.cp15_data.reg_data,
+ pdata_local.cp15_data.reg_saved_state_size *
+ sizeof(uint32_t));
+ }
+
+ msm_pm_set_flush_fn(pdata_local.pc_mode);
+ msm_pm_use_sync_timer = pdata_local.use_sync_timer;
+ msm_pm_retention_calls_tz = pdata_local.retention_calls_tz;
+
pm_8x60_probe_done:
+ msm_pm_init();
return ret;
}
@@ -1305,4 +1363,4 @@
{
return platform_driver_register(&msm_pm_8x60_driver);
}
-module_init(msm_pm_8x60_init);
+device_initcall(msm_pm_8x60_init);
diff --git a/arch/arm/mach-msm/pm.h b/arch/arm/mach-msm/pm.h
index 399194a..af0744c 100644
--- a/arch/arm/mach-msm/pm.h
+++ b/arch/arm/mach-msm/pm.h
@@ -97,8 +97,19 @@
external L2 cache controller */
};
+struct msm_pm_cp15_save_data {
+ bool save_cp15;
+ uint32_t active_vdd;
+ uint32_t qsb_pc_vdd;
+ uint32_t reg_saved_state_size;
+ uint32_t *reg_data;
+ uint32_t *reg_val;
+};
+
struct msm_pm_init_data_type {
enum msm_pm_pc_mode_type pc_mode;
+ bool retention_calls_tz;
+ struct msm_pm_cp15_save_data cp15_data;
bool use_sync_timer;
};
@@ -108,10 +119,9 @@
};
void msm_pm_set_platform_data(struct msm_pm_platform_data *data, int count);
-int msm_pm_idle_prepare(struct cpuidle_device *dev,
+enum msm_pm_sleep_mode msm_pm_idle_enter(struct cpuidle_device *dev,
struct cpuidle_driver *drv, int index);
void msm_pm_set_irq_extns(struct msm_pm_irq_calls *irq_calls);
-int msm_pm_idle_enter(enum msm_pm_sleep_mode sleep_mode);
void msm_pm_cpu_enter_lowpower(unsigned int cpu);
void __init msm_pm_set_tz_retention_flag(unsigned int flag);
void msm_pm_enable_retention(bool enable);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
index 654f547..e6b9549 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
@@ -897,6 +897,11 @@
struct audio_client *ac;
struct audio_aio_write_param param;
+ if (!audio || !buf_node) {
+ pr_err("%s NULL pointer audio=[0x%p], buf_node=[0x%p]\n",
+ __func__, audio, buf_node);
+ return;
+ }
pr_debug("%s[%p]: Send write buff %p phy %lx len %d meta_enable = %d\n",
__func__, audio, buf_node, buf_node->paddr,
buf_node->buf.data_len,
@@ -922,8 +927,7 @@
if (!audio->buf_cfg.meta_info_enable)
param.flags = 0xFF00;
- if ((buf_node != NULL) &&
- (buf_node->meta_info.meta_in.nflags & AUDIO_DEC_EOF_SET))
+ if (buf_node->meta_info.meta_in.nflags & AUDIO_DEC_EOF_SET)
param.flags |= AUDIO_DEC_EOF_SET;
param.uid = param.paddr;
diff --git a/arch/arm/mach-msm/rpm-notifier.h b/arch/arm/mach-msm/rpm-notifier.h
index b9815a5..16de77e 100644
--- a/arch/arm/mach-msm/rpm-notifier.h
+++ b/arch/arm/mach-msm/rpm-notifier.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -40,8 +40,12 @@
/**
* msm_rpm_enter_sleep - Notify RPM driver to prepare for entering sleep
+ *
+ * @bool - flag to enable print contents of sleep buffer.
+ *
+ * return 0 on success errno on failure.
*/
-int msm_rpm_enter_sleep(void);
+int msm_rpm_enter_sleep(bool print);
/**
* msm_rpm_exit_sleep - Notify RPM driver about resuming from power collapse
diff --git a/arch/arm/mach-msm/rpm-smd.c b/arch/arm/mach-msm/rpm-smd.c
index 4295fd4..b84ade9 100644
--- a/arch/arm/mach-msm/rpm-smd.c
+++ b/arch/arm/mach-msm/rpm-smd.c
@@ -32,6 +32,7 @@
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_platform.h>
+#include <linux/rbtree.h>
#include <mach/socinfo.h>
#include <mach/msm_smd.h>
#include <mach/rpm-smd.h>
@@ -62,6 +63,9 @@
};
#define DEFAULT_BUFFER_SIZE 256
+#define DEBUG_PRINT_BUFFER_SIZE 512
+#define MAX_SLEEP_BUFFER 128
+
#define GFP_FLAG(noirq) (noirq ? GFP_ATOMIC : GFP_KERNEL)
#define INV_RSC "resource does not exist"
#define ERR "err\0"
@@ -106,6 +110,11 @@
uint32_t data_len;
};
+struct kvp {
+ unsigned int k;
+ unsigned int s;
+};
+
struct msm_rpm_kvp_data {
uint32_t key;
uint32_t nbytes; /* number of bytes */
@@ -113,6 +122,301 @@
bool valid;
};
+struct slp_buf {
+ struct rb_node node;
+ char ubuf[MAX_SLEEP_BUFFER];
+ char *buf;
+ bool valid;
+};
+static struct rb_root tr_root = RB_ROOT;
+
+static int msm_rpm_send_smd_buffer(char *buf, int size, bool noirq);
+static uint32_t msm_rpm_get_next_msg_id(void);
+
+static inline unsigned int get_rsc_type(char *buf)
+{
+ struct rpm_message_header *h;
+ h = (struct rpm_message_header *)
+ (buf + sizeof(struct rpm_request_header));
+ return h->resource_type;
+}
+
+static inline unsigned int get_rsc_id(char *buf)
+{
+ struct rpm_message_header *h;
+ h = (struct rpm_message_header *)
+ (buf + sizeof(struct rpm_request_header));
+ return h->resource_id;
+}
+
+#define get_data_len(buf) \
+ (((struct rpm_message_header *) \
+ (buf + sizeof(struct rpm_request_header)))->data_len)
+
+#define get_req_len(buf) \
+ (((struct rpm_request_header *)(buf))->request_len)
+
+#define get_msg_id(buf) \
+ (((struct rpm_message_header *) \
+ (buf + sizeof(struct rpm_request_header)))->msg_id)
+
+
+static inline int get_buf_len(char *buf)
+{
+ return get_req_len(buf) + sizeof(struct rpm_request_header);
+}
+
+static inline struct kvp *get_first_kvp(char *buf)
+{
+ return (struct kvp *)(buf + sizeof(struct rpm_request_header)
+ + sizeof(struct rpm_message_header));
+}
+
+static inline struct kvp *get_next_kvp(struct kvp *k)
+{
+ return (struct kvp *)((void *)k + sizeof(*k) + k->s);
+}
+
+static inline void *get_data(struct kvp *k)
+{
+ return (void *)k + sizeof(*k);
+}
+
+
+static void delete_kvp(char *msg, struct kvp *d)
+{
+ struct kvp *n;
+ int dec, size;
+
+ n = get_next_kvp(d);
+ dec = (void *)n - (void *)d;
+ size = get_data_len(msg) - ((void *)n - (void *)get_first_kvp(msg));
+
+ memcpy((void *)d, (void *)n, size);
+
+ get_data_len(msg) -= dec;
+ get_req_len(msg) -= dec;
+}
+
+static inline void update_kvp_data(struct kvp *dest, struct kvp *src)
+{
+ memcpy(get_data(dest), get_data(src), src->s);
+}
+
+static void add_kvp(char *buf, struct kvp *n)
+{
+ int inc = sizeof(*n) + n->s;
+ BUG_ON((get_req_len(buf) + inc) > MAX_SLEEP_BUFFER);
+
+ memcpy(buf + get_buf_len(buf), n, inc);
+
+ get_data_len(buf) += inc;
+ get_req_len(buf) += inc;
+}
+
+static struct slp_buf *tr_search(struct rb_root *root, char *slp)
+{
+ unsigned int type = get_rsc_type(slp);
+ unsigned int id = get_rsc_id(slp);
+
+ struct rb_node *node = root->rb_node;
+
+ while (node) {
+ struct slp_buf *cur = rb_entry(node, struct slp_buf, node);
+ unsigned int ctype = get_rsc_type(cur->buf);
+ unsigned int cid = get_rsc_id(cur->buf);
+
+ if (type < ctype)
+ node = node->rb_left;
+ else if (type > ctype)
+ node = node->rb_right;
+ else if (id < cid)
+ node = node->rb_left;
+ else if (id > cid)
+ node = node->rb_right;
+ else
+ return cur;
+ }
+ return NULL;
+}
+
+static int tr_insert(struct rb_root *root, struct slp_buf *slp)
+{
+ unsigned int type = get_rsc_type(slp->buf);
+ unsigned int id = get_rsc_id(slp->buf);
+
+ struct rb_node **node = &(root->rb_node), *parent = NULL;
+
+ while (*node) {
+ struct slp_buf *curr = rb_entry(*node, struct slp_buf, node);
+ unsigned int ctype = get_rsc_type(curr->buf);
+ unsigned int cid = get_rsc_id(curr->buf);
+
+ parent = *node;
+
+ if (type < ctype)
+ node = &((*node)->rb_left);
+ else if (type > ctype)
+ node = &((*node)->rb_right);
+ else if (id < cid)
+ node = &((*node)->rb_left);
+ else if (id > cid)
+ node = &((*node)->rb_right);
+ else
+ return -EINVAL;
+ }
+
+ rb_link_node(&slp->node, parent, node);
+ rb_insert_color(&slp->node, root);
+ slp->valid = true;
+ return 0;
+}
+
+#define for_each_kvp(buf, k) \
+ for (k = (struct kvp *)get_first_kvp(buf); \
+ ((void *)k - (void *)get_first_kvp(buf)) < get_data_len(buf);\
+ k = get_next_kvp(k))
+
+
+static void tr_update(struct slp_buf *s, char *buf)
+{
+ struct kvp *e, *n;
+
+ for_each_kvp(buf, n) {
+ for_each_kvp(s->buf, e) {
+ if (n->k == e->k) {
+ if (n->s == e->s) {
+ void *e_data = get_data(e);
+ void *n_data = get_data(n);
+ if (memcmp(e_data, n_data, n->s)) {
+ update_kvp_data(e, n);
+ s->valid = true;
+ }
+ } else {
+ delete_kvp(s->buf, e);
+ add_kvp(s->buf, n);
+ s->valid = true;
+ }
+ break;
+ }
+ }
+ }
+}
+
+int msm_rpm_smd_buffer_request(char *buf, int size, gfp_t flag)
+{
+ struct slp_buf *slp;
+ static DEFINE_SPINLOCK(slp_buffer_lock);
+ unsigned long flags;
+
+ if (size > MAX_SLEEP_BUFFER)
+ return -ENOMEM;
+
+ spin_lock_irqsave(&slp_buffer_lock, flags);
+ slp = tr_search(&tr_root, buf);
+
+ if (!slp) {
+ slp = kzalloc(sizeof(struct slp_buf), GFP_ATOMIC);
+ if (!slp) {
+ spin_unlock_irqrestore(&slp_buffer_lock, flags);
+ return -ENOMEM;
+ }
+ slp->buf = PTR_ALIGN(&slp->ubuf[0], sizeof(u32));
+ memcpy(slp->buf, buf, size);
+ if (tr_insert(&tr_root, slp))
+ pr_err("%s(): Error updating sleep request\n",
+ __func__);
+ } else {
+ /* handle unsent requests */
+ tr_update(slp, buf);
+ }
+
+ spin_unlock_irqrestore(&slp_buffer_lock, flags);
+
+ return 0;
+}
+static void msm_rpm_print_sleep_buffer(struct slp_buf *s)
+{
+ char buf[DEBUG_PRINT_BUFFER_SIZE] = {0};
+ int pos;
+ int buflen = DEBUG_PRINT_BUFFER_SIZE;
+ char ch[5] = {0};
+ u32 type;
+ struct kvp *e;
+
+ if (!s)
+ return;
+
+ if (!s->valid)
+ return;
+
+ type = get_rsc_type(s->buf);
+ memcpy(ch, &type, sizeof(u32));
+
+ pos = scnprintf(buf, buflen,
+ "Sleep request type = 0x%08x(%s)",
+ get_rsc_type(s->buf), ch);
+ pos += scnprintf(buf + pos, buflen - pos, " id = 0%x",
+ get_rsc_id(s->buf));
+ for_each_kvp(s->buf, e) {
+ int i;
+ char *data = get_data(e);
+
+ memcpy(ch, &e->k, sizeof(u32));
+
+ pos += scnprintf(buf + pos, buflen - pos,
+ "\n\t\tkey = 0x%08x(%s)",
+ e->k, ch);
+ pos += scnprintf(buf + pos, buflen - pos,
+ " sz= %d data =", e->s);
+
+ for (i = 0; i < e->s; i++)
+ pos += scnprintf(buf + pos, buflen - pos,
+ " 0x%02X", data[i]);
+ }
+ pos += scnprintf(buf + pos, buflen - pos, "\n");
+ printk(buf);
+}
+
+static int msm_rpm_flush_requests(bool print)
+{
+ struct rb_node *t;
+ int ret;
+
+ for (t = rb_first(&tr_root); t; t = rb_next(t)) {
+
+ struct slp_buf *s = rb_entry(t, struct slp_buf, node);
+
+ if (!s->valid)
+ continue;
+
+ if (print)
+ msm_rpm_print_sleep_buffer(s);
+
+ get_msg_id(s->buf) = msm_rpm_get_next_msg_id();
+ ret = msm_rpm_send_smd_buffer(s->buf,
+ get_buf_len(s->buf), true);
+ /* By not adding the message to a wait list we can reduce
+ * latency involved in waiting for a ACK from RPM. The ACK
+ * messages will be processed when we wakeup from sleep but
+ * processing should be minimal
+ * msm_rpm_wait_for_ack_noirq(get_msg_id(s->buf));
+ */
+
+ WARN_ON(ret != get_buf_len(s->buf));
+
+ trace_rpm_send_message(true, MSM_RPM_CTX_SLEEP_SET,
+ get_rsc_type(s->buf),
+ get_rsc_id(s->buf),
+ get_msg_id(s->buf));
+
+ s->valid = false;
+ }
+ return 0;
+
+}
+
+
static atomic_t msm_rpm_msg_id = ATOMIC_INIT(0);
static struct msm_rpm_driver_data msm_rpm_data;
@@ -450,7 +754,12 @@
}
elem = NULL;
}
- WARN_ON(!elem);
+ /* Special case where the sleep driver doesn't
+ * wait for ACKs. This would decrease the latency involved with
+ * entering RPM assisted power collapse.
+ */
+ if (!elem)
+ trace_rpm_ack_recd(0, msg_id);
spin_unlock_irqrestore(&msm_rpm_list_lock, flags);
}
@@ -544,8 +853,6 @@
}
}
-#define DEBUG_PRINT_BUFFER_SIZE 512
-
static void msm_rpm_log_request(struct msm_rpm_request *cdata)
{
char buf[DEBUG_PRINT_BUFFER_SIZE];
@@ -677,13 +984,42 @@
pos += scnprintf(buf + pos, buflen - pos, "\n");
printk(buf);
}
+static int msm_rpm_send_smd_buffer(char *buf, int size, bool noirq)
+{
+ unsigned long flags;
+ int ret;
+ spin_lock_irqsave(&msm_rpm_data.smd_lock_write, flags);
+ ret = smd_write_avail(msm_rpm_data.ch_info);
+
+ while ((ret = smd_write_avail(msm_rpm_data.ch_info)) < size) {
+ if (ret < 0)
+ break;
+ if (!noirq) {
+ spin_unlock_irqrestore(&msm_rpm_data.smd_lock_write,
+ flags);
+ cpu_relax();
+ spin_lock_irqsave(&msm_rpm_data.smd_lock_write, flags);
+ } else
+ udelay(5);
+ }
+
+ if (ret < 0) {
+ pr_err("%s(): SMD not initialized\n", __func__);
+ spin_unlock_irqrestore(&msm_rpm_data.smd_lock_write, flags);
+ return ret;
+ }
+
+ ret = smd_write(msm_rpm_data.ch_info, buf, size);
+ spin_unlock_irqrestore(&msm_rpm_data.smd_lock_write, flags);
+ return ret;
+
+}
static int msm_rpm_send_data(struct msm_rpm_request *cdata,
int msg_type, bool noirq)
{
uint8_t *tmpbuff;
int i, ret, msg_size;
- unsigned long flags;
int req_hdr_sz, msg_hdr_sz;
@@ -695,8 +1031,6 @@
cdata->req_hdr.service_type = msm_rpm_request_service[msg_type];
- cdata->msg_hdr.msg_id = msm_rpm_get_next_msg_id();
-
cdata->req_hdr.request_len = cdata->msg_hdr.data_len + msg_hdr_sz;
msg_size = cdata->req_hdr.request_len + req_hdr_sz;
@@ -714,8 +1048,6 @@
tmpbuff = cdata->buf;
- memcpy(tmpbuff, &cdata->req_hdr, req_hdr_sz + msg_hdr_sz);
-
tmpbuff += req_hdr_sz + msg_hdr_sz;
for (i = 0; (i < cdata->write_idx); i++) {
@@ -740,6 +1072,17 @@
}
+ memcpy(cdata->buf, &cdata->req_hdr, req_hdr_sz + msg_hdr_sz);
+
+ if ((cdata->msg_hdr.set == MSM_RPM_CTX_SLEEP_SET) &&
+ !msm_rpm_smd_buffer_request(cdata->buf, msg_size,
+ GFP_FLAG(noirq)))
+ return 1;
+
+ cdata->msg_hdr.msg_id = msm_rpm_get_next_msg_id();
+
+ memcpy(cdata->buf + req_hdr_sz, &cdata->msg_hdr, msg_hdr_sz);
+
if (msm_rpm_debug_mask
& (MSM_RPM_LOG_REQUEST_PRETTY | MSM_RPM_LOG_REQUEST_RAW))
msm_rpm_log_request(cdata);
@@ -755,29 +1098,7 @@
msm_rpm_add_wait_list(cdata->msg_hdr.msg_id);
- spin_lock_irqsave(&msm_rpm_data.smd_lock_write, flags);
-
- ret = smd_write_avail(msm_rpm_data.ch_info);
-
- if (ret < 0) {
- pr_err("%s(): SMD not initialized\n", __func__);
- spin_unlock_irqrestore(&msm_rpm_data.smd_lock_write, flags);
- return 0;
- }
-
- while ((ret < msg_size)) {
- if (!noirq) {
- spin_unlock_irqrestore(&msm_rpm_data.smd_lock_write,
- flags);
- cpu_relax();
- spin_lock_irqsave(&msm_rpm_data.smd_lock_write, flags);
- } else
- udelay(5);
- ret = smd_write_avail(msm_rpm_data.ch_info);
- }
-
- ret = smd_write(msm_rpm_data.ch_info, &cdata->buf[0], msg_size);
- spin_unlock_irqrestore(&msm_rpm_data.smd_lock_write, flags);
+ ret = msm_rpm_send_smd_buffer(&cdata->buf[0], msg_size, noirq);
if (ret == msg_size) {
trace_rpm_send_message(noirq, cdata->msg_hdr.set,
@@ -958,11 +1279,13 @@
* During power collapse, the rpm driver disables the SMD interrupts to make
* sure that the interrupt doesn't wakes us from sleep.
*/
-int msm_rpm_enter_sleep(void)
+int msm_rpm_enter_sleep(bool print)
{
if (standalone)
return 0;
+ msm_rpm_flush_requests(print);
+
return smd_mask_receive_interrupt(msm_rpm_data.ch_info, true);
}
EXPORT_SYMBOL(msm_rpm_enter_sleep);
diff --git a/arch/arm/mach-msm/smd_debug.c b/arch/arm/mach-msm/smd_debug.c
index 9206016..4dcf72f 100644
--- a/arch/arm/mach-msm/smd_debug.c
+++ b/arch/arm/mach-msm/smd_debug.c
@@ -1,7 +1,7 @@
/* arch/arm/mach-msm/smd_debug.c
*
* Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
* Author: Brian Swetland <swetland@google.com>
*
* This software is licensed under the terms of the GNU General Public
@@ -103,14 +103,14 @@
const char *subsys_name;
i += scnprintf(buf + i, max - i,
- " Subsystem | Interrupt ID | In | Out (Hardcoded) |"
- " Out (Configured) |\n");
+ " Subsystem | Interrupt ID | In | Out (Hardcoded) |"
+ " Out (Configured)|\n");
for (subsys = 0; subsys < NUM_SMD_SUBSYSTEMS; ++subsys) {
subsys_name = smd_pid_to_subsystem(subsys);
if (subsys_name) {
i += scnprintf(buf + i, max - i,
- "%-10s %4s | %9d | %9u | %9u | %9u |\n",
+ "%-10s %4s | %9d | %9u | %9u | %9u |\n",
smd_pid_to_subsystem(subsys), "smd",
stats->smd_interrupt_id,
stats->smd_in_count,
@@ -118,7 +118,7 @@
stats->smd_out_config_count);
i += scnprintf(buf + i, max - i,
- "%-10s %4s | %9d | %9u | %9u | %9u |\n",
+ "%-10s %4s | %9d | %9u | %9u | %9u |\n",
smd_pid_to_subsystem(subsys), "smsm",
stats->smsm_interrupt_id,
stats->smsm_in_count,
diff --git a/arch/arm/mach-msm/smp2p.c b/arch/arm/mach-msm/smp2p.c
index 0597411..8066005 100644
--- a/arch/arm/mach-msm/smp2p.c
+++ b/arch/arm/mach-msm/smp2p.c
@@ -1314,13 +1314,20 @@
}
/* Create and add it to the list */
- in->remote_pid = pid;
- strlcpy(in->name, name, SMP2P_MAX_ENTRY_NAME);
- RAW_INIT_NOTIFIER_HEAD(&in->in_notifier_list);
- list_add(&in->in_edge_list, &in_list[pid].list);
+ if (!in->notifier_count) {
+ in->remote_pid = pid;
+ strlcpy(in->name, name, SMP2P_MAX_ENTRY_NAME);
+ RAW_INIT_NOTIFIER_HEAD(&in->in_notifier_list);
+ list_add(&in->in_edge_list, &in_list[pid].list);
+ }
+
ret = raw_notifier_chain_register(&in->in_notifier_list,
in_notifier);
if (ret) {
+ if (!in->notifier_count) {
+ list_del(&in->in_edge_list);
+ kfree(in);
+ }
SMP2P_DBG("%s: '%s':%d failed %d\n", __func__, name, pid, ret);
goto bail;
}
diff --git a/arch/arm/mach-msm/smp2p_test.c b/arch/arm/mach-msm/smp2p_test.c
index 10f7575..18c9bfd 100644
--- a/arch/arm/mach-msm/smp2p_test.c
+++ b/arch/arm/mach-msm/smp2p_test.c
@@ -843,6 +843,116 @@
}
}
+/**
+ * smp2p_ut_local_in_multiple - Verify Multiple Inbound Registration.
+ *
+ * @s: pointer to output file
+ *
+ * This test verifies multiple clients registering for same inbound entries
+ * using the remote mock processor.
+ */
+static void smp2p_ut_local_in_multiple(struct seq_file *s)
+{
+ int failed = 0;
+ struct msm_smp2p_remote_mock *rmp = NULL;
+ int ret;
+ static struct mock_cb_data cb_in_1;
+ static struct mock_cb_data cb_in_2;
+ static struct mock_cb_data cb_out;
+
+ seq_printf(s, "Running %s\n", __func__);
+
+ mock_cb_data_init(&cb_in_1);
+ mock_cb_data_init(&cb_in_2);
+ mock_cb_data_init(&cb_out);
+
+ do {
+ /* Initialize mock edge */
+ ret = smp2p_reset_mock_edge();
+ UT_ASSERT_INT(ret, ==, 0);
+
+ rmp = msm_smp2p_get_remote_mock();
+ UT_ASSERT_PTR(rmp, !=, NULL);
+
+ rmp->rx_interrupt_count = 0;
+ memset(&rmp->remote_item, 0,
+ sizeof(struct smp2p_smem_item));
+ rmp->remote_item.header.magic = SMP2P_MAGIC;
+ SMP2P_SET_LOCAL_PID(
+ rmp->remote_item.header.rem_loc_proc_id,
+ SMP2P_REMOTE_MOCK_PROC);
+ SMP2P_SET_REMOTE_PID(
+ rmp->remote_item.header.rem_loc_proc_id,
+ SMP2P_APPS_PROC);
+ SMP2P_SET_VERSION(
+ rmp->remote_item.header.feature_version, 1);
+ SMP2P_SET_FEATURES(
+ rmp->remote_item.header.feature_version, 0);
+ SMP2P_SET_ENT_TOTAL(
+ rmp->remote_item.header.valid_total_ent, 1);
+ SMP2P_SET_ENT_VALID(
+ rmp->remote_item.header.valid_total_ent, 0);
+ rmp->remote_item.header.reserved = 0x0;
+ msm_smp2p_set_remote_mock_exists(true);
+
+ /* Create an Entry in the remote mock object */
+ scnprintf(rmp->remote_item.entries[0].name,
+ SMP2P_MAX_ENTRY_NAME, "smp2p%d", 1);
+ rmp->remote_item.entries[0].entry = 0;
+ rmp->tx_interrupt();
+
+ /* Register multiple clients for the inbound entry */
+ ret = msm_smp2p_in_register(SMP2P_REMOTE_MOCK_PROC,
+ rmp->remote_item.entries[0].name,
+ &cb_in_1.nb);
+ UT_ASSERT_INT(ret, ==, 0);
+ UT_ASSERT_INT(
+ (int)wait_for_completion_timeout(
+ &(cb_in_1.cb_completion), HZ / 2),
+ >, 0);
+ UT_ASSERT_INT(cb_in_1.cb_count, ==, 1);
+ UT_ASSERT_INT(cb_in_1.event_entry_update, ==, 0);
+
+ ret = msm_smp2p_in_register(SMP2P_REMOTE_MOCK_PROC,
+ rmp->remote_item.entries[0].name,
+ &cb_in_2.nb);
+ UT_ASSERT_INT(ret, ==, 0);
+ UT_ASSERT_INT(
+ (int)wait_for_completion_timeout(
+ &(cb_in_2.cb_completion), HZ / 2),
+ >, 0);
+ UT_ASSERT_INT(cb_in_2.cb_count, ==, 1);
+ UT_ASSERT_INT(cb_in_2.event_entry_update, ==, 0);
+
+
+ /* Unregister the clients */
+ ret = msm_smp2p_in_unregister(SMP2P_REMOTE_MOCK_PROC,
+ rmp->remote_item.entries[0].name,
+ &(cb_in_1.nb));
+ UT_ASSERT_INT(ret, ==, 0);
+
+ ret = msm_smp2p_in_unregister(SMP2P_REMOTE_MOCK_PROC,
+ rmp->remote_item.entries[0].name,
+ &(cb_in_2.nb));
+ UT_ASSERT_INT(ret, ==, 0);
+
+ seq_printf(s, "\tOK\n");
+ } while (0);
+
+ if (failed) {
+ pr_err("%s: Failed\n", __func__);
+ seq_printf(s, "\tFailed\n");
+
+ ret = msm_smp2p_in_unregister(SMP2P_REMOTE_MOCK_PROC,
+ rmp->remote_item.entries[0].name,
+ &(cb_in_1.nb));
+
+ ret = msm_smp2p_in_unregister(SMP2P_REMOTE_MOCK_PROC,
+ rmp->remote_item.entries[0].name,
+ &(cb_in_2.nb));
+ }
+}
+
static struct dentry *dent;
static int debugfs_show(struct seq_file *s, void *data)
@@ -907,6 +1017,8 @@
smp2p_ut_local_in_max_entries);
smp2p_debug_create("ut_remote_out_max_entries",
smp2p_ut_remote_out_max_entries);
+ smp2p_debug_create("ut_local_in_multiple",
+ smp2p_ut_local_in_multiple);
return 0;
}
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index 19e48759..56623c9 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -134,6 +134,16 @@
uint32_t pmic_die_revision;
};
+struct socinfo_v8 {
+ struct socinfo_v7 v7;
+
+ /* only valid when format==8*/
+ uint32_t pmic_model_1;
+ uint32_t pmic_die_revision_1;
+ uint32_t pmic_model_2;
+ uint32_t pmic_die_revision_2;
+};
+
static union {
struct socinfo_v1 v1;
struct socinfo_v2 v2;
@@ -142,6 +152,7 @@
struct socinfo_v5 v5;
struct socinfo_v6 v6;
struct socinfo_v7 v7;
+ struct socinfo_v8 v8;
} *socinfo;
static enum msm_cpu cpu_of_id[] = {
@@ -865,6 +876,7 @@
device_create_file(msm_soc_device, &msm_soc_attr_vendor);
switch (legacy_format) {
+ case 8:
case 7:
device_create_file(msm_soc_device,
&msm_soc_attr_pmic_model);
@@ -1054,6 +1066,7 @@
socinfo->v5.accessory_chip,
socinfo->v6.hw_platform_subtype);
break;
+ case 8:
case 7:
pr_info("%s: v%u, id=%u, ver=%u.%u, raw_id=%u, raw_ver=%u, hw_plat=%u, hw_plat_ver=%u\n accessory_chip=%u, hw_plat_subtype=%u, pmic_model=%u, pmic_die_revision=%u\n",
__func__,
@@ -1076,7 +1089,11 @@
int __init socinfo_init(void)
{
- socinfo = smem_alloc(SMEM_HW_SW_BUILD_ID, sizeof(struct socinfo_v7));
+ socinfo = smem_alloc(SMEM_HW_SW_BUILD_ID, sizeof(struct socinfo_v8));
+
+ if (!socinfo)
+ socinfo = smem_alloc(SMEM_HW_SW_BUILD_ID,
+ sizeof(struct socinfo_v7));
if (!socinfo)
socinfo = smem_alloc(SMEM_HW_SW_BUILD_ID,
diff --git a/arch/arm/mach-msm/subsystem_map.c b/arch/arm/mach-msm/subsystem_map.c
index 3269e50..116fc2e 100644
--- a/arch/arm/mach-msm/subsystem_map.c
+++ b/arch/arm/mach-msm/subsystem_map.c
@@ -256,6 +256,8 @@
subsys_domain = msm_get_iommu_domain(msm_subsystem_get_domain_no
(subsys_id));
+ if (!subsys_domain)
+ return -EINVAL;
return iommu_iova_to_phys(subsys_domain, iova);
}
@@ -429,15 +431,18 @@
return buf;
outiova:
- if (flags & MSM_SUBSYSTEM_MAP_IOVA)
- iommu_unmap(d, temp_va, SZ_4K);
+ if (flags & MSM_SUBSYSTEM_MAP_IOVA) {
+ if (d)
+ iommu_unmap(d, temp_va, SZ_4K);
+ }
outdomain:
if (flags & MSM_SUBSYSTEM_MAP_IOVA) {
/* Unmap the rest of the current domain, i */
- for (j -= SZ_4K, temp_va -= SZ_4K;
- j > 0; temp_va -= SZ_4K, j -= SZ_4K)
- iommu_unmap(d, temp_va, SZ_4K);
-
+ if (d) {
+ for (j -= SZ_4K, temp_va -= SZ_4K;
+ j > 0; temp_va -= SZ_4K, j -= SZ_4K)
+ iommu_unmap(d, temp_va, SZ_4K);
+ }
/* Unmap all the other domains */
for (i--; i >= 0; i--) {
unsigned int domain_no, partition_no;
@@ -447,10 +452,14 @@
partition_no = msm_subsystem_get_partition_no(
subsys_ids[i]);
- temp_va = buf->iova[i];
- for (j = length; j > 0; j -= SZ_4K,
- temp_va += SZ_4K)
- iommu_unmap(d, temp_va, SZ_4K);
+ d = msm_get_iommu_domain(domain_no);
+
+ if (d) {
+ temp_va = buf->iova[i];
+ for (j = length; j > 0; j -= SZ_4K,
+ temp_va += SZ_4K)
+ iommu_unmap(d, temp_va, SZ_4K);
+ }
msm_free_iova_address(buf->iova[i], domain_no,
partition_no, length);
}
@@ -506,6 +515,9 @@
msm_subsystem_get_domain_no(
node->subsystems[i]));
+ if (!subsys_domain)
+ continue;
+
domain_no = msm_subsystem_get_domain_no(
node->subsystems[i]);
partition_no = msm_subsystem_get_partition_no(
diff --git a/block/row-iosched.c b/block/row-iosched.c
index bdb6abd..098c7b0 100644
--- a/block/row-iosched.c
+++ b/block/row-iosched.c
@@ -87,7 +87,7 @@
static const struct row_queue_params row_queues_def[] = {
/* idling_enabled, quantum, is_urgent */
{true, 10, true}, /* ROWQ_PRIO_HIGH_READ */
- {false, 1, true}, /* ROWQ_PRIO_HIGH_SWRITE */
+ {false, 1, false}, /* ROWQ_PRIO_HIGH_SWRITE */
{true, 100, true}, /* ROWQ_PRIO_REG_READ */
{false, 1, false}, /* ROWQ_PRIO_REG_SWRITE */
{false, 1, false}, /* ROWQ_PRIO_REG_WRITE */
@@ -165,8 +165,11 @@
* @nr_reqs: nr_reqs[0] holds the number of all READ requests in
* scheduler, nr_reqs[1] holds the number of all WRITE
* requests in scheduler
- * @nr_urgent_in_flight: number of uncompleted urgent requests
- * (both reads and writes)
+ * @urgent_in_flight: flag indicating that there is an urgent
+ * request that was dispatched to driver and is yet to
+ * complete.
+ * @pending_urgent_rq: pointer to the pending urgent request
+ * @last_served_ioprio_class: I/O priority class that was last dispatched from
* @cycle_flags: used for marking unserved queueus
*
*/
@@ -177,8 +180,9 @@
struct idling_data rd_idle_data;
unsigned int nr_reqs[2];
- unsigned int nr_urgent_in_flight;
-
+ bool urgent_in_flight;
+ struct request *pending_urgent_rq;
+ int last_served_ioprio_class;
unsigned int cycle_flags;
};
@@ -303,10 +307,20 @@
}
if (row_queues_def[rqueue->prio].is_urgent &&
row_rowq_unserved(rd, rqueue->prio)) {
- row_log_rowq(rd, rqueue->prio,
- "added urgent request (total on queue=%d)",
- rqueue->nr_req);
- rq->cmd_flags |= REQ_URGENT;
+ if (!rd->pending_urgent_rq && !rd->urgent_in_flight) {
+ row_log_rowq(rd, rqueue->prio,
+ "added urgent request (total on queue=%d)",
+ rqueue->nr_req);
+ rq->cmd_flags |= REQ_URGENT;
+ rd->pending_urgent_rq = rq;
+ if (rqueue->prio < ROWQ_REG_PRIO_IDX)
+ rd->last_served_ioprio_class = IOPRIO_CLASS_RT;
+ else if (rqueue->prio < ROWQ_LOW_PRIO_IDX)
+ rd->last_served_ioprio_class = IOPRIO_CLASS_BE;
+ else
+ rd->last_served_ioprio_class =
+ IOPRIO_CLASS_IDLE;
+ }
} else
row_log_rowq(rd, rqueue->prio,
"added request (total on queue=%d)", rqueue->nr_req);
@@ -342,6 +356,17 @@
row_log_rowq(rd, rqueue->prio,
"request reinserted (total on queue=%d)", rqueue->nr_req);
+ if (rq->cmd_flags & REQ_URGENT) {
+ if (!rd->urgent_in_flight) {
+ pr_err("ROW BUG: %s() nr_urgent_in_flight = F",
+ __func__);
+ } else {
+ rd->urgent_in_flight = false;
+ pr_err("ROW BUG: %s() reinserting URGENT %s req",
+ __func__,
+ (rq_data_dir(rq) == READ ? "READ" : "WRITE"));
+ }
+ }
return 0;
}
@@ -350,12 +375,12 @@
struct row_data *rd = q->elevator->elevator_data;
if (rq->cmd_flags & REQ_URGENT) {
- if (!rd->nr_urgent_in_flight) {
- pr_err("ROW BUG: %s() nr_urgent_in_flight = 0",
+ if (!rd->urgent_in_flight) {
+ pr_err("ROW BUG: %s() URGENT req but urgent_in_flight = F",
__func__);
return;
}
- rd->nr_urgent_in_flight--;
+ rd->urgent_in_flight = false;
}
}
@@ -367,27 +392,17 @@
static bool row_urgent_pending(struct request_queue *q)
{
struct row_data *rd = q->elevator->elevator_data;
- int i;
- if (rd->nr_urgent_in_flight) {
+ if (rd->urgent_in_flight) {
row_log(rd->dispatch_queue, "%d urgent requests in flight",
- rd->nr_urgent_in_flight);
+ rd->urgent_in_flight);
return false;
}
- for (i = ROWQ_HIGH_PRIO_IDX; i < ROWQ_REG_PRIO_IDX; i++)
- if (!list_empty(&rd->row_queues[i].fifo)) {
- row_log_rowq(rd, i,
- "Urgent (high prio) request pending");
- return true;
- }
-
- for (i = ROWQ_REG_PRIO_IDX; i < ROWQ_MAX_PRIO; i++)
- if (row_queues_def[i].is_urgent && row_rowq_unserved(rd, i) &&
- !list_empty(&rd->row_queues[i].fifo)) {
- row_log_rowq(rd, i, "Urgent request pending");
- return true;
- }
+ if (rd->pending_urgent_rq) {
+ row_log(rd->dispatch_queue, "Urgent request pending");
+ return true;
+ }
return false;
}
@@ -412,25 +427,21 @@
/*
* row_dispatch_insert() - move request to dispatch queue
* @rd: pointer to struct row_data
- * @queue_idx: index of the row_queue to dispatch from
+ * @rq: the request to dispatch
*
- * This function moves the next request to dispatch from
- * the given queue (row_queues[queue_idx]) to the dispatch queue
+ * This function moves the given request to the dispatch queue
*
*/
-static void row_dispatch_insert(struct row_data *rd, int queue_idx)
+static void row_dispatch_insert(struct row_data *rd, struct request *rq)
{
- struct request *rq;
+ struct row_queue *rqueue = RQ_ROWQ(rq);
- rq = rq_entry_fifo(rd->row_queues[queue_idx].fifo.next);
row_remove_request(rd->dispatch_queue, rq);
elv_dispatch_add_tail(rd->dispatch_queue, rq);
- rd->row_queues[queue_idx].nr_dispatched++;
- row_clear_rowq_unserved(rd, queue_idx);
- row_log_rowq(rd, queue_idx, " Dispatched request nr_disp = %d",
- rd->row_queues[queue_idx].nr_dispatched);
- if (rq->cmd_flags & REQ_URGENT)
- rd->nr_urgent_in_flight++;
+ rqueue->nr_dispatched++;
+ row_clear_rowq_unserved(rd, rqueue->prio);
+ row_log_rowq(rd, rqueue->prio, " Dispatched request nr_disp = %d",
+ rqueue->nr_dispatched);
}
/*
@@ -595,6 +606,15 @@
rd->rd_idle_data.idling_queue_idx = ROWQ_MAX_PRIO;
}
+ if (rd->pending_urgent_rq) {
+ row_log(rd->dispatch_queue, "Urgent pending for dispatch");
+ row_dispatch_insert(rd, rd->pending_urgent_rq);
+ rd->pending_urgent_rq = NULL;
+ rd->urgent_in_flight = true;
+ ret = 1;
+ goto done;
+ }
+
ioprio_class_to_serve = row_get_ioprio_class_to_serve(rd, force);
row_log(rd->dispatch_queue, "Dispatching from %d priority class",
ioprio_class_to_serve);
@@ -623,7 +643,9 @@
/* Dispatch */
if (currq >= 0) {
- row_dispatch_insert(rd, currq);
+ row_dispatch_insert(rd,
+ rq_entry_fifo(rd->row_queues[currq].fifo.next));
+ rd->last_served_ioprio_class = ioprio_class_to_serve;
ret = 1;
}
done:
@@ -672,7 +694,7 @@
rdata->rd_idle_data.hr_timer.function = &row_idle_hrtimer_fn;
INIT_WORK(&rdata->rd_idle_data.idle_work, kick_queue);
-
+ rdata->last_served_ioprio_class = IOPRIO_CLASS_NONE;
rdata->rd_idle_data.idling_queue_idx = ROWQ_MAX_PRIO;
rdata->dispatch_queue = q;
@@ -722,7 +744,8 @@
* dispatched from later on)
*
*/
-static enum row_queue_prio row_get_queue_prio(struct request *rq)
+static enum row_queue_prio row_get_queue_prio(struct request *rq,
+ struct row_data *rd)
{
const int data_dir = rq_data_dir(rq);
const bool is_sync = rq_is_sync(rq);
@@ -740,7 +763,15 @@
rq->rq_disk->disk_name, __func__);
q_type = ROWQ_PRIO_REG_WRITE;
}
- rq->cmd_flags |= REQ_URGENT;
+ if (row_queues_def[q_type].is_urgent &&
+ rd->last_served_ioprio_class != IOPRIO_CLASS_RT &&
+ !rd->pending_urgent_rq && !rd->urgent_in_flight) {
+ row_log_rowq(rd, q_type,
+ "added (high prio) urgent request");
+ rq->cmd_flags |= REQ_URGENT;
+ rd->pending_urgent_rq = rq;
+ rd->last_served_ioprio_class = IOPRIO_CLASS_RT;
+ }
break;
case IOPRIO_CLASS_IDLE:
if (data_dir == READ)
@@ -783,7 +814,7 @@
spin_lock_irqsave(q->queue_lock, flags);
rq->elv.priv[0] =
- (void *)(&rd->row_queues[row_get_queue_prio(rq)]);
+ (void *)(&rd->row_queues[row_get_queue_prio(rq, rd)]);
spin_unlock_irqrestore(q->queue_lock, flags);
return 0;
diff --git a/drivers/base/sync.c b/drivers/base/sync.c
index 809d02b..2e35996 100644
--- a/drivers/base/sync.c
+++ b/drivers/base/sync.c
@@ -324,7 +324,6 @@
new_pt->fence = dst;
list_add(&new_pt->pt_list, &dst->pt_list_head);
- sync_pt_activate(new_pt);
}
return 0;
@@ -356,7 +355,6 @@
new_pt->fence = dst;
list_replace(&dst_pt->pt_list,
&new_pt->pt_list);
- sync_pt_activate(new_pt);
sync_pt_free(dst_pt);
}
collapsed = true;
@@ -372,7 +370,6 @@
new_pt->fence = dst;
list_add(&new_pt->pt_list, &dst->pt_list_head);
- sync_pt_activate(new_pt);
}
}
@@ -453,6 +450,7 @@
struct sync_fence *a, struct sync_fence *b)
{
struct sync_fence *fence;
+ struct list_head *pos;
int err;
fence = sync_fence_alloc(name);
@@ -467,6 +465,12 @@
if (err < 0)
goto err;
+ list_for_each(pos, &fence->pt_list_head) {
+ struct sync_pt *pt =
+ container_of(pos, struct sync_pt, pt_list);
+ sync_pt_activate(pt);
+ }
+
/*
* signal the fence in case one of it's pts were activated before
* they were activated
@@ -612,9 +616,11 @@
}
if (fence->status == 0) {
- pr_info("fence timeout on [%p] after %dms\n", fence,
- jiffies_to_msecs(timeout));
- sync_dump();
+ if (timeout > 0) {
+ pr_info("fence timeout on [%p] after %dms\n", fence,
+ jiffies_to_msecs(timeout));
+ sync_dump();
+ }
return -ETIME;
}
diff --git a/drivers/bluetooth/bluetooth-power.c b/drivers/bluetooth/bluetooth-power.c
index 718df02..d7c69db 100644
--- a/drivers/bluetooth/bluetooth-power.c
+++ b/drivers/bluetooth/bluetooth-power.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2010, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2009-2010, 2013 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -20,9 +20,43 @@
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/rfkill.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/delay.h>
+
+static struct of_device_id ar3002_match_table[] = {
+ { .compatible = "qca,ar3002" },
+ {}
+};
+
+static int bt_reset_gpio;
static bool previous;
+static int bluetooth_power(int on)
+{
+ int rc;
+
+ pr_debug("%s bt_gpio= %d\n", __func__, bt_reset_gpio);
+ if (on) {
+ rc = gpio_direction_output(bt_reset_gpio, 1);
+ if (rc) {
+ pr_err("%s: Unable to set direction\n", __func__);
+ return rc;
+ }
+ msleep(100);
+ } else {
+ gpio_set_value(bt_reset_gpio, 0);
+ rc = gpio_direction_input(bt_reset_gpio);
+ if (rc) {
+ pr_err("%s: Unable to set direction\n", __func__);
+ return rc;
+ }
+ msleep(100);
+ }
+ return 0;
+}
+
static int bluetooth_toggle_radio(void *data, bool blocked)
{
int ret = 0;
@@ -90,8 +124,36 @@
dev_dbg(&pdev->dev, "%s\n", __func__);
if (!pdev->dev.platform_data) {
- dev_err(&pdev->dev, "platform data not initialized\n");
- return -ENOSYS;
+ /* Update the platform data if the
+ device node exists as part of device tree.*/
+ if (pdev->dev.of_node) {
+ pdev->dev.platform_data = bluetooth_power;
+ } else {
+ dev_err(&pdev->dev, "device node not set\n");
+ return -ENOSYS;
+ }
+ }
+ if (pdev->dev.of_node) {
+ bt_reset_gpio = of_get_named_gpio(pdev->dev.of_node,
+ "qca,bt-reset-gpio", 0);
+ if (bt_reset_gpio < 0) {
+ pr_err("bt-reset-gpio not available");
+ return bt_reset_gpio;
+ }
+ }
+
+ ret = gpio_request(bt_reset_gpio, "bt sys_rst_n");
+ if (ret) {
+ pr_err("%s: unable to request gpio %d (%d)\n",
+ __func__, bt_reset_gpio, ret);
+ return ret;
+ }
+
+ /* When booting up, de-assert BT reset pin */
+ ret = gpio_direction_output(bt_reset_gpio, 0);
+ if (ret) {
+ pr_err("%s: Unable to set direction\n", __func__);
+ return ret;
}
ret = bluetooth_power_rfkill_probe(pdev);
@@ -114,6 +176,7 @@
.driver = {
.name = "bt_power",
.owner = THIS_MODULE,
+ .of_match_table = ar3002_match_table,
},
};
diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c
index 822da91..73fe5d6 100644
--- a/drivers/char/adsprpc.c
+++ b/drivers/char/adsprpc.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -11,8 +11,106 @@
* GNU General Public License for more details.
*
*/
+#include "adsprpc_shared.h"
+
+#include <linux/slab.h>
+#include <linux/completion.h>
+#include <linux/pagemap.h>
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/module.h>
+#include <linux/cdev.h>
+#include <linux/list.h>
+#include <linux/hash.h>
+#include <linux/msm_ion.h>
+#include <mach/msm_smd.h>
+#include <mach/ion.h>
#include <linux/scatterlist.h>
-#include "adsprpc.h"
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <linux/device.h>
+
+#ifndef ION_ADSPRPC_HEAP_ID
+#define ION_ADSPRPC_HEAP_ID ION_AUDIO_HEAP_ID
+#endif /*ION_ADSPRPC_HEAP_ID*/
+
+#define RPC_TIMEOUT (5 * HZ)
+#define RPC_HASH_BITS 5
+#define RPC_HASH_SZ (1 << RPC_HASH_BITS)
+#define BALIGN 32
+
+#define LOCK_MMAP(kernel)\
+ do {\
+ if (!kernel)\
+ down_read(¤t->mm->mmap_sem);\
+ } while (0)
+
+#define UNLOCK_MMAP(kernel)\
+ do {\
+ if (!kernel)\
+ up_read(¤t->mm->mmap_sem);\
+ } while (0)
+
+
+static inline uint32_t buf_page_start(void *buf)
+{
+ uint32_t start = (uint32_t) buf & PAGE_MASK;
+ return start;
+}
+
+static inline uint32_t buf_page_offset(void *buf)
+{
+ uint32_t offset = (uint32_t) buf & (PAGE_SIZE - 1);
+ return offset;
+}
+
+static inline int buf_num_pages(void *buf, int len)
+{
+ uint32_t start = buf_page_start(buf) >> PAGE_SHIFT;
+ uint32_t end = (((uint32_t) buf + len - 1) & PAGE_MASK) >> PAGE_SHIFT;
+ int nPages = end - start + 1;
+ return nPages;
+}
+
+static inline uint32_t buf_page_size(uint32_t size)
+{
+ uint32_t sz = (size + (PAGE_SIZE - 1)) & PAGE_MASK;
+ return sz > PAGE_SIZE ? sz : PAGE_SIZE;
+}
+
+static inline int buf_get_pages(void *addr, int sz, int nr_pages, int access,
+ struct smq_phy_page *pages, int nr_elems)
+{
+ struct vm_area_struct *vma;
+ uint32_t start = buf_page_start(addr);
+ uint32_t len = nr_pages << PAGE_SHIFT;
+ unsigned long pfn;
+ int n = -1, err = 0;
+
+ VERIFY(err, 0 != access_ok(access ? VERIFY_WRITE : VERIFY_READ,
+ (void __user *)start, len));
+ if (err)
+ goto bail;
+ VERIFY(err, 0 != (vma = find_vma(current->mm, start)));
+ if (err)
+ goto bail;
+ VERIFY(err, ((uint32_t)addr + sz) <= vma->vm_end);
+ if (err)
+ goto bail;
+ n = 0;
+ VERIFY(err, 0 == follow_pfn(vma, start, &pfn));
+ if (err)
+ goto bail;
+ VERIFY(err, nr_elems > 0);
+ if (err)
+ goto bail;
+ pages->addr = __pfn_to_phys(pfn);
+ pages->size = len;
+ n++;
+ bail:
+ return n;
+}
struct smq_invoke_ctx {
struct completion work;
@@ -32,6 +130,8 @@
struct completion work;
struct ion_client *iclient;
struct cdev cdev;
+ struct class *class;
+ struct device *dev;
dev_t dev_no;
spinlock_t wrlock;
spinlock_t hlock;
@@ -249,7 +349,6 @@
args = (void *)((char *)pbuf->virt + used);
rlen = pbuf->size - used;
for (i = 0; i < inbufs + outbufs; ++i) {
- int num;
rpra[i].buf.len = pra[i].buf.len;
if (!rpra[i].buf.len)
@@ -276,18 +375,12 @@
args = pbuf->virt;
rlen = pbuf->size;
}
- num = buf_num_pages(args, pra[i].buf.len);
- if (pbuf == ibuf) {
- list[i].num = num;
- list[i].pgidx = 0;
- } else {
- list[i].num = 1;
- pages[list[i].pgidx].addr =
- buf_page_start((void *)(pbuf->phys +
- (pbuf->size - rlen)));
- pages[list[i].pgidx].size =
- buf_page_size(pra[i].buf.len);
- }
+ list[i].num = 1;
+ pages[list[i].pgidx].addr =
+ buf_page_start((void *)(pbuf->phys +
+ (pbuf->size - rlen)));
+ pages[list[i].pgidx].size =
+ buf_page_size(pra[i].buf.len);
if (i < inbufs) {
if (!kernel) {
VERIFY(err, 0 == copy_from_user(args,
@@ -485,9 +578,9 @@
static void free_dev(struct fastrpc_device *dev)
{
if (dev) {
- module_put(THIS_MODULE);
free_mem(&dev->buf);
kfree(dev);
+ module_put(THIS_MODULE);
}
}
@@ -609,8 +702,10 @@
wait_for_completion(&ctx->work);
}
context_free(ctx);
+
for (i = 0, b = abufs; i < nbufs; ++i, ++b)
free_mem(b);
+
kfree(abufs);
if (dev) {
add_dev(me, dev);
@@ -768,11 +863,24 @@
VERIFY(err, 0 == cdev_add(&me->cdev, MKDEV(MAJOR(me->dev_no), 0), 1));
if (err)
goto bail;
- pr_info("'mknod /dev/%s c %d 0'\n", DEVICE_NAME, MAJOR(me->dev_no));
+ me->class = class_create(THIS_MODULE, "chardrv");
+ VERIFY(err, !IS_ERR(me->class));
+ if (err)
+ goto bail;
+ me->dev = device_create(me->class, NULL, MKDEV(MAJOR(me->dev_no), 0),
+ NULL, DEVICE_NAME);
+ VERIFY(err, !IS_ERR(me->dev));
+ if (err)
+ goto bail;
+ pr_info("'created /dev/%s c %d 0'\n", DEVICE_NAME, MAJOR(me->dev_no));
bail:
if (err) {
if (me->dev_no)
unregister_chrdev_region(me->dev_no, 1);
+ if (me->class)
+ class_destroy(me->class);
+ if (me->cdev.owner)
+ cdev_del(&me->cdev);
fastrpc_deinit();
}
return err;
@@ -783,6 +891,8 @@
struct fastrpc_apps *me = &gfa;
fastrpc_deinit();
+ device_destroy(me->class, MKDEV(MAJOR(me->dev_no), 0));
+ class_destroy(me->class);
cdev_del(&me->cdev);
unregister_chrdev_region(me->dev_no, 1);
}
diff --git a/drivers/char/adsprpc.h b/drivers/char/adsprpc.h
deleted file mode 100644
index 3f1b4a7..0000000
--- a/drivers/char/adsprpc.h
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * 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 ADSPRPC_H
-#define ADSPRPC_H
-
-#include <linux/slab.h>
-#include <linux/completion.h>
-#include <linux/pagemap.h>
-#include <linux/mm.h>
-#include <linux/fs.h>
-#include <linux/sched.h>
-#include <linux/module.h>
-#include <linux/cdev.h>
-#include <linux/list.h>
-#include <linux/hash.h>
-#include <linux/msm_ion.h>
-#include <mach/msm_smd.h>
-#include <mach/ion.h>
-#include "adsprpc_shared.h"
-
-#ifndef ION_ADSPRPC_HEAP_ID
-#define ION_ADSPRPC_HEAP_ID ION_AUDIO_HEAP_ID
-#endif
-
-#define RPC_TIMEOUT (5 * HZ)
-#define RPC_HASH_BITS 5
-#define RPC_HASH_SZ (1 << RPC_HASH_BITS)
-#define BALIGN 32
-
-#define LOCK_MMAP(kernel)\
- do {\
- if (!kernel)\
- down_read(¤t->mm->mmap_sem);\
- } while (0)
-
-#define UNLOCK_MMAP(kernel)\
- do {\
- if (!kernel)\
- up_read(¤t->mm->mmap_sem);\
- } while (0)
-
-
-static inline uint32_t buf_page_start(void *buf)
-{
- uint32_t start = (uint32_t) buf & PAGE_MASK;
- return start;
-}
-
-static inline uint32_t buf_page_offset(void *buf)
-{
- uint32_t offset = (uint32_t) buf & (PAGE_SIZE - 1);
- return offset;
-}
-
-static inline int buf_num_pages(void *buf, int len)
-{
- uint32_t start = buf_page_start(buf) >> PAGE_SHIFT;
- uint32_t end = (((uint32_t) buf + len - 1) & PAGE_MASK) >> PAGE_SHIFT;
- int nPages = end - start + 1;
- return nPages;
-}
-
-static inline uint32_t buf_page_size(uint32_t size)
-{
- uint32_t sz = (size + (PAGE_SIZE - 1)) & PAGE_MASK;
- return sz > PAGE_SIZE ? sz : PAGE_SIZE;
-}
-
-static inline int buf_get_pages(void *addr, int sz, int nr_pages, int access,
- struct smq_phy_page *pages, int nr_elems)
-{
- struct vm_area_struct *vma;
- uint32_t start = buf_page_start(addr);
- uint32_t len = nr_pages << PAGE_SHIFT;
- unsigned long pfn;
- int n = -1, err = 0;
-
- VERIFY(err, 0 != access_ok(access ? VERIFY_WRITE : VERIFY_READ,
- (void __user *)start, len));
- if (err)
- goto bail;
- VERIFY(err, 0 != (vma = find_vma(current->mm, start)));
- if (err)
- goto bail;
- VERIFY(err, ((uint32_t)addr + sz) <= vma->vm_end);
- if (err)
- goto bail;
- n = 0;
- VERIFY(err, 0 == follow_pfn(vma, start, &pfn));
- if (err)
- goto bail;
- VERIFY(err, nr_elems > 0);
- if (err)
- goto bail;
- pages->addr = __pfn_to_phys(pfn);
- pages->size = len;
- n++;
- bail:
- return n;
-}
-
-#endif
diff --git a/drivers/char/adsprpc_shared.h b/drivers/char/adsprpc_shared.h
index dc6ab6f..8932d3c 100644
--- a/drivers/char/adsprpc_shared.h
+++ b/drivers/char/adsprpc_shared.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -14,6 +14,8 @@
#ifndef ADSPRPC_SHARED_H
#define ADSPRPC_SHARED_H
+#include <linux/types.h>
+
#define FASTRPC_IOCTL_INVOKE _IOWR('R', 1, struct fastrpc_ioctl_invoke)
#define FASTRPC_SMD_GUID "fastrpcsmd-apps-dsp"
#define DEVICE_NAME "adsprpc-smd"
diff --git a/drivers/gpu/ion/ion_iommu_heap.c b/drivers/gpu/ion/ion_iommu_heap.c
index 304a39e..c5fef5b 100644
--- a/drivers/gpu/ion/ion_iommu_heap.c
+++ b/drivers/gpu/ion/ion_iommu_heap.c
@@ -70,13 +70,17 @@
int i;
for (i = 0; i < num_orders; i++) {
+ gfp_t gfp;
if (size < order_to_size(orders[i]))
continue;
if (max_order < orders[i])
continue;
- page = alloc_pages(GFP_KERNEL | __GFP_HIGHMEM | __GFP_COMP,
- orders[i]);
+ gfp = GFP_KERNEL | __GFP_HIGHMEM | __GFP_COMP;
+ if (orders[i])
+ gfp |= __GFP_NOWARN;
+
+ page = alloc_pages(gfp, orders[i]);
if (!page)
continue;
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index a8384d5..b7d813c 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -298,7 +298,7 @@
uint32_t flags)
{
unsigned int pt_val, reg_pt_val;
- unsigned int link[250];
+ unsigned int link[230];
unsigned int *cmds = &link[0];
int sizedwords = 0;
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
@@ -759,6 +759,10 @@
&pdata->init_level))
pdata->init_level = 1;
+ if (adreno_of_read_property(parent, "qcom,step-pwrlevel",
+ &pdata->step_mul))
+ pdata->step_mul = 1;
+
if (pdata->init_level < 0 || pdata->init_level > pdata->num_levels) {
KGSL_CORE_ERR("Initial power level out of range\n");
pdata->init_level = 1;
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index d4cccbd..c43ac51 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -435,6 +435,8 @@
/* CP ROQ queue sizes (bytes) - RB:16, ST:16, IB1:32, IB2:64 */
if (adreno_is_a305(adreno_dev) || adreno_is_a320(adreno_dev))
adreno_regwrite(device, REG_CP_QUEUE_THRESHOLDS, 0x000E0602);
+ else if (adreno_is_a330(adreno_dev) || adreno_is_a305b(adreno_dev))
+ adreno_regwrite(device, REG_CP_QUEUE_THRESHOLDS, 0x003E2008);
rb->rptr = 0;
rb->wptr = 0;
diff --git a/drivers/gpu/msm/kgsl_drm.c b/drivers/gpu/msm/kgsl_drm.c
index 764b044..ba88a42 100644
--- a/drivers/gpu/msm/kgsl_drm.c
+++ b/drivers/gpu/msm/kgsl_drm.c
@@ -465,8 +465,11 @@
}
ret = kgsl_gem_init_obj(dev, file_priv, obj, &handle);
- if (ret)
+ if (ret) {
+ drm_gem_object_release(obj);
+ DRM_ERROR("Unable to initialize GEM object ret = %d\n", ret);
return ret;
+ }
create->handle = handle;
return 0;
@@ -539,6 +542,106 @@
}
int
+kgsl_gem_create_from_ion_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ struct drm_kgsl_gem_create_from_ion *args = data;
+ struct drm_gem_object *obj;
+ struct ion_handle *ion_handle;
+ struct drm_kgsl_gem_object *priv;
+ struct sg_table *sg_table;
+ struct scatterlist *s;
+ int ret, handle;
+ unsigned long size;
+
+ ion_handle = ion_import_dma_buf(kgsl_drm_ion_client, args->ion_fd);
+ if (IS_ERR_OR_NULL(ion_handle)) {
+ DRM_ERROR("Unable to import dmabuf. Error number = %d\n",
+ (int)PTR_ERR(ion_handle));
+ return -EINVAL;
+ }
+
+ ion_handle_get_size(kgsl_drm_ion_client, ion_handle, &size);
+
+ if (size == 0) {
+ ion_free(kgsl_drm_ion_client, ion_handle);
+ DRM_ERROR(
+ "cannot create GEM object from zero size ION buffer\n");
+ return -EINVAL;
+ }
+
+ obj = drm_gem_object_alloc(dev, size);
+
+ if (obj == NULL) {
+ ion_free(kgsl_drm_ion_client, ion_handle);
+ DRM_ERROR("Unable to allocate the GEM object\n");
+ return -ENOMEM;
+ }
+
+ ret = kgsl_gem_init_obj(dev, file_priv, obj, &handle);
+ if (ret) {
+ ion_free(kgsl_drm_ion_client, ion_handle);
+ drm_gem_object_release(obj);
+ DRM_ERROR("Unable to initialize GEM object ret = %d\n", ret);
+ return ret;
+ }
+
+ priv = obj->driver_private;
+ priv->ion_handle = ion_handle;
+
+ priv->type = DRM_KGSL_GEM_TYPE_KMEM;
+ list_add(&priv->list, &kgsl_mem_list);
+
+ priv->pagetable = kgsl_mmu_getpagetable(KGSL_MMU_GLOBAL_PT);
+
+ priv->memdesc.pagetable = priv->pagetable;
+
+ sg_table = ion_sg_table(kgsl_drm_ion_client,
+ priv->ion_handle);
+ if (IS_ERR_OR_NULL(priv->ion_handle)) {
+ DRM_ERROR("Unable to get ION sg table\n");
+ ion_free(kgsl_drm_ion_client,
+ priv->ion_handle);
+ priv->ion_handle = NULL;
+ kgsl_mmu_putpagetable(priv->pagetable);
+ drm_gem_object_release(obj);
+ kfree(priv);
+ return -ENOMEM;
+ }
+
+ priv->memdesc.sg = sg_table->sgl;
+
+ /* Calculate the size of the memdesc from the sglist */
+
+ priv->memdesc.sglen = 0;
+
+ for (s = priv->memdesc.sg; s != NULL; s = sg_next(s)) {
+ priv->memdesc.size += s->length;
+ priv->memdesc.sglen++;
+ }
+
+ ret = kgsl_mmu_map(priv->pagetable, &priv->memdesc,
+ GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
+ if (ret) {
+ DRM_ERROR("kgsl_mmu_map failed. ret = %d\n", ret);
+ ion_free(kgsl_drm_ion_client,
+ priv->ion_handle);
+ priv->ion_handle = NULL;
+ kgsl_mmu_putpagetable(priv->pagetable);
+ drm_gem_object_release(obj);
+ kfree(priv);
+ return -ENOMEM;
+ }
+
+ priv->bufs[0].offset = 0;
+ priv->bufs[0].gpuaddr = priv->memdesc.gpuaddr;
+ priv->flags |= DRM_KGSL_GEM_FLAG_MAPPED;
+
+ args->handle = handle;
+ return 0;
+}
+
+int
kgsl_gem_get_ion_fd_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
@@ -563,6 +666,12 @@
if (priv->ion_handle) {
args->ion_fd = ion_share_dma_buf(
kgsl_drm_ion_client, priv->ion_handle);
+ if (args->ion_fd < 0) {
+ DRM_ERROR(
+ "Could not share ion buffer. Error = %d\n",
+ args->ion_fd);
+ ret = -EINVAL;
+ }
} else {
DRM_ERROR("GEM object has no ion memory allocated.\n");
ret = -EINVAL;
@@ -1266,6 +1375,8 @@
DRM_IOCTL_DEF_DRV(KGSL_GEM_MMAP, kgsl_gem_mmap_ioctl, 0),
DRM_IOCTL_DEF_DRV(KGSL_GEM_GET_BUFINFO, kgsl_gem_get_bufinfo_ioctl, 0),
DRM_IOCTL_DEF_DRV(KGSL_GEM_GET_ION_FD, kgsl_gem_get_ion_fd_ioctl, 0),
+ DRM_IOCTL_DEF_DRV(KGSL_GEM_CREATE_FROM_ION,
+ kgsl_gem_create_from_ion_ioctl, 0),
DRM_IOCTL_DEF_DRV(KGSL_GEM_SET_BUFCOUNT,
kgsl_gem_set_bufcount_ioctl, 0),
DRM_IOCTL_DEF_DRV(KGSL_GEM_SET_ACTIVE, kgsl_gem_set_active_ioctl, 0),
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 2945b7b..0dcbfdf 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -357,13 +357,13 @@
return snprintf(buf, PAGE_SIZE, "%d\n", pwr->num_pwrlevels - 1);
}
-/* Given a GPU clock value, return the nearest powerlevel */
+/* Given a GPU clock value, return the lowest matching powerlevel */
static int _get_nearest_pwrlevel(struct kgsl_pwrctrl *pwr, unsigned int clock)
{
int i;
- for (i = 0; i < pwr->num_pwrlevels - 1; i++) {
+ for (i = pwr->num_pwrlevels - 1; i >= 0; i--) {
if (abs(pwr->pwrlevels[i].gpu_freq - clock) < 5000000)
return i;
}
@@ -766,23 +766,23 @@
/* High latency clock maintenance. */
if ((pwr->pwrlevels[0].gpu_freq > 0) &&
(requested_state != KGSL_STATE_NAP)) {
- clk_set_rate(pwr->grp_clks[0],
- pwr->pwrlevels[pwr->num_pwrlevels - 1].
- gpu_freq);
for (i = KGSL_MAX_CLKS - 1; i > 0; i--)
if (pwr->grp_clks[i])
clk_unprepare(pwr->grp_clks[i]);
+ clk_set_rate(pwr->grp_clks[0],
+ pwr->pwrlevels[pwr->num_pwrlevels - 1].
+ gpu_freq);
}
kgsl_pwrctrl_busy_time(device, true);
} else if (requested_state == KGSL_STATE_SLEEP) {
/* High latency clock maintenance. */
+ for (i = KGSL_MAX_CLKS - 1; i > 0; i--)
+ if (pwr->grp_clks[i])
+ clk_unprepare(pwr->grp_clks[i]);
if ((pwr->pwrlevels[0].gpu_freq > 0))
clk_set_rate(pwr->grp_clks[0],
pwr->pwrlevels[pwr->num_pwrlevels - 1].
gpu_freq);
- for (i = KGSL_MAX_CLKS - 1; i > 0; i--)
- if (pwr->grp_clks[i])
- clk_unprepare(pwr->grp_clks[i]);
}
} else if (state == KGSL_PWRFLAGS_ON) {
if (!test_and_set_bit(KGSL_PWRFLAGS_CLK_ON,
@@ -790,15 +790,14 @@
trace_kgsl_clk(device, state);
/* High latency clock maintenance. */
if (device->state != KGSL_STATE_NAP) {
- for (i = KGSL_MAX_CLKS - 1; i > 0; i--)
- if (pwr->grp_clks[i])
- clk_prepare(pwr->grp_clks[i]);
-
if (pwr->pwrlevels[0].gpu_freq > 0)
clk_set_rate(pwr->grp_clks[0],
pwr->pwrlevels
[pwr->active_pwrlevel].
gpu_freq);
+ for (i = KGSL_MAX_CLKS - 1; i > 0; i--)
+ if (pwr->grp_clks[i])
+ clk_prepare(pwr->grp_clks[i]);
}
/* as last step, enable grp_clk
this is to let GPU interrupt to come */
@@ -1000,8 +999,11 @@
}
}
+ /* Set the power level step multiplier with 1 as the default */
+ pwr->step_mul = pdata->step_mul ? pdata->step_mul : 1;
+
/* Set the CPU latency to 501usec to allow low latency PC modes */
- pwr->pm_qos_latency = 3;
+ pwr->pm_qos_latency = 501;
pm_runtime_enable(device->parentdev);
register_early_suspend(&device->display_off);
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.h b/drivers/gpu/msm/kgsl_pwrctrl.h
index 72ad4d1..ced52e1 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.h
+++ b/drivers/gpu/msm/kgsl_pwrctrl.h
@@ -62,6 +62,7 @@
* @clk_stats - structure of clock statistics
* @pm_qos_req_dma - the power management quality of service structure
* @pm_qos_latency - allowed CPU latency in microseconds
+ * @step_mul - multiplier for moving between power levels
*/
struct kgsl_pwrctrl {
@@ -89,6 +90,7 @@
struct kgsl_clk_stats clk_stats;
struct pm_qos_request pm_qos_req_dma;
unsigned int pm_qos_latency;
+ unsigned int step_mul;
};
void kgsl_pwrctrl_irq(struct kgsl_device *device, int state);
diff --git a/drivers/gpu/msm/kgsl_pwrscale_trustzone.c b/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
index a647361..9b2ac70 100644
--- a/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
+++ b/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -179,6 +179,12 @@
}
priv->bin.total_time = 0;
priv->bin.busy_time = 0;
+
+ /* If the decision is to move to a lower level, make sure the GPU
+ * frequency drops.
+ */
+ if (val > 0)
+ val *= pwr->step_mul;
if (val)
kgsl_pwrctrl_pwrlevel_change(device,
pwr->active_pwrlevel + val);
diff --git a/drivers/gud/mobicore_driver/main.c b/drivers/gud/mobicore_driver/main.c
index 3fc9e17..df5675e 100644
--- a/drivers/gud/mobicore_driver/main.c
+++ b/drivers/gud/mobicore_driver/main.c
@@ -1112,7 +1112,7 @@
static struct miscdevice mc_admin_device = {
.name = MC_ADMIN_DEVNODE,
.mode = (S_IRWXU),
- .minor = MISC_DYNAMIC_MINOR,
+ .minor = 253,
.fops = &mc_admin_fops,
};
@@ -1128,7 +1128,7 @@
static struct miscdevice mc_user_device = {
.name = MC_USER_DEVNODE,
.mode = (S_IRWXU | S_IRWXG | S_IRWXO),
- .minor = MISC_DYNAMIC_MINOR,
+ .minor = 254,
.fops = &mc_user_fops,
};
diff --git a/drivers/hwmon/qpnp-adc-current.c b/drivers/hwmon/qpnp-adc-current.c
index 3fdc68f..e4a9e30 100644
--- a/drivers/hwmon/qpnp-adc-current.c
+++ b/drivers/hwmon/qpnp-adc-current.c
@@ -131,7 +131,6 @@
struct qpnp_adc_drv *adc;
int32_t rsense;
struct device *iadc_hwmon;
- bool iadc_init_calib;
bool iadc_initialized;
int64_t die_temp_calib_offset;
struct delayed_work iadc_work;
@@ -413,6 +412,8 @@
uint16_t raw_data;
uint32_t mode_sel = 0;
+ mutex_lock(&iadc->adc->adc_lock);
+
rc = qpnp_iadc_configure(GAIN_CALIBRATION_17P857MV,
&raw_data, mode_sel);
if (rc < 0) {
@@ -469,6 +470,7 @@
goto fail;
}
fail:
+ mutex_unlock(&iadc->adc->adc_lock);
return rc;
}
@@ -477,16 +479,12 @@
struct qpnp_iadc_drv *iadc = qpnp_iadc;
int rc = 0;
- mutex_lock(&iadc->adc->adc_lock);
-
rc = qpnp_iadc_calibrate_for_trim();
if (rc) {
pr_err("periodic IADC calibration failed\n");
iadc->iadc_err_cnt++;
}
- mutex_unlock(&iadc->adc->adc_lock);
-
if (iadc->iadc_err_cnt < QPNP_IADC_ERR_CHK_RATELIMIT)
schedule_delayed_work(&iadc->iadc_work,
round_jiffies_relative(msecs_to_jiffies
@@ -527,9 +525,13 @@
int32_t qpnp_iadc_get_rsense(int32_t *rsense)
{
+ struct qpnp_iadc_drv *iadc = qpnp_iadc;
uint8_t rslt_rsense;
int32_t rc, sign_bit = 0;
+ if (!iadc || !iadc->iadc_initialized)
+ return -EPROBE_DEFER;
+
rc = qpnp_iadc_read_reg(QPNP_IADC_NOMINAL_RSENSE, &rslt_rsense);
if (rc < 0) {
pr_err("qpnp adc rsense read failed with %d\n", rc);
@@ -552,7 +554,7 @@
}
EXPORT_SYMBOL(qpnp_iadc_get_rsense);
-int32_t qpnp_check_pmic_temp(void)
+static int32_t qpnp_check_pmic_temp(void)
{
struct qpnp_iadc_drv *iadc = qpnp_iadc;
struct qpnp_vadc_result result_pmic_therm;
@@ -565,13 +567,9 @@
if (((uint64_t) (result_pmic_therm.physical -
iadc->die_temp_calib_offset))
> QPNP_IADC_DIE_TEMP_CALIB_OFFSET) {
- mutex_lock(&iadc->adc->adc_lock);
-
rc = qpnp_iadc_calibrate_for_trim();
if (rc)
pr_err("periodic IADC calibration failed\n");
-
- mutex_unlock(&iadc->adc->adc_lock);
}
return 0;
@@ -818,7 +816,6 @@
} else
enable_irq_wake(iadc->adc->adc_irq_eoc);
- iadc->iadc_init_calib = false;
dev_set_drvdata(&spmi->dev, iadc);
qpnp_iadc = iadc;
@@ -835,20 +832,17 @@
goto fail;
}
- rc = qpnp_iadc_calibrate_for_trim();
- if (rc) {
- dev_err(&spmi->dev, "failed to calibrate for USR trim\n");
- goto fail;
- }
- iadc->iadc_init_calib = true;
- INIT_DELAYED_WORK(&iadc->iadc_work, qpnp_iadc_work);
- schedule_delayed_work(&iadc->iadc_work,
- round_jiffies_relative(msecs_to_jiffies
- (QPNP_IADC_CALIB_SECONDS)));
mutex_init(&iadc->iadc_vadc_lock);
+ INIT_DELAYED_WORK(&iadc->iadc_work, qpnp_iadc_work);
iadc->iadc_err_cnt = 0;
iadc->iadc_initialized = true;
+ rc = qpnp_iadc_calibrate_for_trim();
+ if (rc)
+ dev_err(&spmi->dev, "failed to calibrate for USR trim\n");
+ schedule_delayed_work(&iadc->iadc_work,
+ round_jiffies_relative(msecs_to_jiffies
+ (QPNP_IADC_CALIB_SECONDS)));
return 0;
fail:
qpnp_iadc = NULL;
@@ -862,6 +856,7 @@
struct device_node *child;
int i = 0;
+ cancel_delayed_work(&iadc->iadc_work);
mutex_destroy(&iadc->iadc_vadc_lock);
for_each_child_of_node(node, child) {
device_remove_file(&spmi->dev,
diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index 717f763..da43a08 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -128,6 +128,7 @@
};
#define QUP_MAX_CLK_STATE_RETRIES 300
+#define DEFAULT_CLK_RATE (19200000)
static char const * const i2c_rsrcs[] = {"i2c_clk", "i2c_sda"};
@@ -191,14 +192,18 @@
qup_i2c_interrupt(int irq, void *devid)
{
struct qup_i2c_dev *dev = devid;
- uint32_t status = readl_relaxed(dev->base + QUP_I2C_STATUS);
- uint32_t status1 = readl_relaxed(dev->base + QUP_ERROR_FLAGS);
- uint32_t op_flgs = readl_relaxed(dev->base + QUP_OPERATIONAL);
+ uint32_t status = 0;
+ uint32_t status1 = 0;
+ uint32_t op_flgs = 0;
int err = 0;
if (pm_runtime_suspended(dev->dev))
return IRQ_NONE;
+ status = readl_relaxed(dev->base + QUP_I2C_STATUS);
+ status1 = readl_relaxed(dev->base + QUP_ERROR_FLAGS);
+ op_flgs = readl_relaxed(dev->base + QUP_OPERATIONAL);
+
if (!dev->msg || !dev->complete) {
/* Clear Error interrupt if it's a level triggered interrupt*/
if (dev->num_irqs == 1) {
@@ -1235,18 +1240,26 @@
dev->clk_ctl = 0;
dev->pos = 0;
+ if (dev->pdata->src_clk_rate <= 0) {
+ dev_info(&pdev->dev,
+ "No src_clk_rate specified in platfrom data or "
+ "qcom,i2c-src-freq in DT\n");
+ dev_info(&pdev->dev, "Using default clock rate %dHz\n",
+ DEFAULT_CLK_RATE);
+ dev->pdata->src_clk_rate = DEFAULT_CLK_RATE;
+ }
+
+ ret = clk_set_rate(dev->clk, dev->pdata->src_clk_rate);
+ if (ret)
+ dev_info(&pdev->dev, "clk_set_rate(core_clk, %dHz):%d\n",
+ dev->pdata->src_clk_rate, ret);
+
+ clk_prepare_enable(dev->clk);
+ clk_prepare_enable(dev->pclk);
/*
* If bootloaders leave a pending interrupt on certain GSBI's,
* then we reset the core before registering for interrupts.
*/
-
- if (dev->pdata->src_clk_rate > 0)
- clk_set_rate(dev->clk, dev->pdata->src_clk_rate);
- else
- dev->pdata->src_clk_rate = 19200000;
-
- clk_prepare_enable(dev->clk);
- clk_prepare_enable(dev->pclk);
writel_relaxed(1, dev->base + QUP_SW_RESET);
if (qup_i2c_poll_state(dev, 0, true) != 0)
goto err_reset_failed;
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index c78eec3..b43c13e 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -999,4 +999,13 @@
To compile this driver as a module, choose M here: the
module will be called synaptics_dsx_fw_update.
+config SECURE_TOUCH
+ bool "Secure Touch"
+ depends on TOUCHSCREEN_ATMEL_MXT
+ help
+ Say Y here to enable Secure Touch support in the Atmel MXT
+ driver.
+
+ If unsure, say N.
+
endif
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 1d56a0a..0c20815 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -38,6 +38,14 @@
#define MXT_SUSPEND_LEVEL 1
#endif
+#if defined(CONFIG_SECURE_TOUCH)
+#include <linux/completion.h>
+#include <linux/pm_runtime.h>
+#include <linux/errno.h>
+#include <asm/system.h>
+#include <linux/atomic.h>
+#endif
+
/* Family ID */
#define MXT224_ID 0x80
#define MXT224E_ID 0x81
@@ -383,6 +391,11 @@
bool update_cfg;
const char *fw_name;
bool no_force_update;
+#if defined(CONFIG_SECURE_TOUCH)
+ atomic_t st_enabled;
+ atomic_t st_pending_irqs;
+ struct completion st_completion;
+#endif
};
static struct dentry *debug_base;
@@ -979,6 +992,23 @@
mxt_release_all(data);
}
+#if defined(CONFIG_SECURE_TOUCH)
+static irqreturn_t mxt_filter_interrupt(struct mxt_data *data)
+{
+ if (atomic_read(&data->st_enabled)) {
+ atomic_cmpxchg(&data->st_pending_irqs, 0, 1);
+ complete(&data->st_completion);
+ return IRQ_HANDLED;
+ }
+ return IRQ_NONE;
+}
+#else
+static irqreturn_t mxt_filter_interrupt(struct mxt_data *data)
+{
+ return IRQ_NONE;
+}
+#endif
+
static irqreturn_t mxt_interrupt(int irq, void *dev_id)
{
struct mxt_data *data = dev_id;
@@ -992,6 +1022,9 @@
return IRQ_HANDLED;
}
+ if (IRQ_HANDLED == mxt_filter_interrupt(data))
+ goto end;
+
do {
if (mxt_read_message(data, &message)) {
dev_err(dev, "Failed to read message\n");
@@ -1910,6 +1943,100 @@
return count;
}
+#if defined(CONFIG_SECURE_TOUCH)
+
+static ssize_t mxt_secure_touch_enable_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct mxt_data *data = dev_get_drvdata(dev);
+ return scnprintf(buf, PAGE_SIZE, "%d", atomic_read(&data->st_enabled));
+}
+/*
+ * Accept only "0" and "1" valid values.
+ * "0" will reset the st_enabled flag, then wake up the reading process.
+ * The bus driver is notified via pm_runtime that it is not required to stay
+ * awake anymore.
+ * It will also make sure the queue of events is emptied in the controller,
+ * in case a touch happened in between the secure touch being disabled and
+ * the local ISR being ungated.
+ * "1" will set the st_enabled flag and clear the st_pending_irqs flag.
+ * The bus driver is requested via pm_runtime to stay awake.
+ */
+static ssize_t mxt_secure_touch_enable_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct mxt_data *data = dev_get_drvdata(dev);
+ unsigned long value;
+ int err = 0;
+
+ if (count > 2)
+ return -EINVAL;
+
+ err = kstrtoul(buf, 10, &value);
+ if (err != 0)
+ return err;
+
+ err = count;
+
+ switch (value) {
+ case 0:
+ if (atomic_read(&data->st_enabled) == 0)
+ break;
+
+ pm_runtime_put(&data->client->adapter->dev);
+ atomic_set(&data->st_enabled, 0);
+ complete(&data->st_completion);
+ mxt_interrupt(data->client->irq, data);
+ break;
+ case 1:
+ if (atomic_read(&data->st_enabled)) {
+ err = -EBUSY;
+ break;
+ }
+
+ if (pm_runtime_get(data->client->adapter->dev.parent) < 0) {
+ dev_err(&data->client->dev, "pm_runtime_get failed\n");
+ err = -EIO;
+ break;
+ }
+ atomic_set(&data->st_pending_irqs, 0);
+ atomic_set(&data->st_enabled, 1);
+ break;
+ default:
+ dev_err(&data->client->dev, "unsupported value: %lu\n", value);
+ err = -EINVAL;
+ break;
+ }
+
+ return err;
+}
+
+static ssize_t mxt_secure_touch_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct mxt_data *data = dev_get_drvdata(dev);
+ int err;
+
+ if (atomic_read(&data->st_enabled) == 0)
+ return -EBADF;
+
+ err = wait_for_completion_interruptible(&data->st_completion);
+
+ if (err)
+ return err;
+
+ if (atomic_cmpxchg(&data->st_pending_irqs, 1, 0) != 1)
+ return -EBADF;
+
+ return scnprintf(buf, PAGE_SIZE, "%u", 1);
+}
+
+static DEVICE_ATTR(secure_touch_enable, 0666, mxt_secure_touch_enable_show,
+ mxt_secure_touch_enable_store);
+static DEVICE_ATTR(secure_touch, 0444, mxt_secure_touch_show, NULL);
+#endif
+
static DEVICE_ATTR(object, 0444, mxt_object_show, NULL);
static DEVICE_ATTR(update_fw, 0664, NULL, mxt_update_fw_store);
static DEVICE_ATTR(force_cfg_update, 0664, NULL, mxt_force_cfg_update_store);
@@ -1918,6 +2045,10 @@
&dev_attr_object.attr,
&dev_attr_update_fw.attr,
&dev_attr_force_cfg_update.attr,
+#if defined(CONFIG_SECURE_TOUCH)
+ &dev_attr_secure_touch_enable.attr,
+ &dev_attr_secure_touch.attr,
+#endif
NULL
};
@@ -2655,6 +2786,17 @@
#endif
+#if defined(CONFIG_SECURE_TOUCH)
+static void __devinit secure_touch_init(struct mxt_data *data)
+{
+ init_completion(&data->st_completion);
+}
+#else
+static void __devinit secure_touch_init(struct mxt_data *data)
+{
+}
+#endif
+
static int __devinit mxt_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -2840,6 +2982,8 @@
mxt_debugfs_init(data);
+ secure_touch_init(data);
+
return 0;
err_unregister_device:
diff --git a/drivers/input/touchscreen/synaptics_fw_update.c b/drivers/input/touchscreen/synaptics_fw_update.c
index c447231..7452587 100644
--- a/drivers/input/touchscreen/synaptics_fw_update.c
+++ b/drivers/input/touchscreen/synaptics_fw_update.c
@@ -1529,7 +1529,7 @@
static ssize_t fwu_sysfs_config_id_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- unsigned char config_id[8];
+ unsigned char config_id[4];
/* device config id */
fwu->fn_ptr->read(fwu->rmi4_data,
fwu->f34_fd.ctrl_base_addr,
@@ -1714,5 +1714,4 @@
MODULE_AUTHOR("Synaptics, Inc.");
MODULE_DESCRIPTION("RMI4 FW Update Module");
-MODULE_LICENSE("GPL");
-MODULE_VERSION(SYNAPTICS_RMI4_DRIVER_VERSION_STRING);
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/input/touchscreen/synaptics_i2c_rmi4.c b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
index c68f730..7d6f3dd 100644
--- a/drivers/input/touchscreen/synaptics_i2c_rmi4.c
+++ b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
@@ -1507,10 +1507,6 @@
container_of(work, struct synaptics_rmi4_data,
det_work.work);
- queue_delayed_work(rmi4_data->det_workqueue,
- &rmi4_data->det_work,
- msecs_to_jiffies(EXP_FN_DET_INTERVAL));
-
mutex_lock(&exp_fn_list_mutex);
if (!list_empty(&exp_fn_list)) {
list_for_each_entry_safe(exp_fhandler,
@@ -1695,8 +1691,8 @@
rmi4_data->input_dev->name = DRIVER_NAME;
rmi4_data->input_dev->phys = INPUT_PHYS_NAME;
rmi4_data->input_dev->id.bustype = BUS_I2C;
- rmi4_data->input_dev->id.product = SYNAPTICS_RMI4_DRIVER_PRODUCT;
- rmi4_data->input_dev->id.version = SYNAPTICS_RMI4_DRIVER_VERSION;
+ rmi4_data->input_dev->id.product = SYNAPTICS_DSX_DRIVER_PRODUCT;
+ rmi4_data->input_dev->id.version = SYNAPTICS_DSX_DRIVER_VERSION;
rmi4_data->input_dev->dev.parent = &client->dev;
input_set_drvdata(rmi4_data->input_dev, rmi4_data);
@@ -2147,4 +2143,3 @@
MODULE_AUTHOR("Synaptics, Inc.");
MODULE_DESCRIPTION("Synaptics RMI4 I2C Touch Driver");
MODULE_LICENSE("GPL v2");
-MODULE_VERSION(SYNAPTICS_RMI4_DRIVER_VERSION_STRING);
diff --git a/drivers/input/touchscreen/synaptics_i2c_rmi4.h b/drivers/input/touchscreen/synaptics_i2c_rmi4.h
index eb8d5f2..3c37e54 100644
--- a/drivers/input/touchscreen/synaptics_i2c_rmi4.h
+++ b/drivers/input/touchscreen/synaptics_i2c_rmi4.h
@@ -20,11 +20,10 @@
#ifndef _SYNAPTICS_DSX_RMI4_H_
#define _SYNAPTICS_DSX_RMI4_H_
-#define SYNAPTICS_RMI4_DS4 0x0001
-#define SYNAPTICS_RMI4_DS5 0x0002
-#define SYNAPTICS_RMI4_DRIVER_PRODUCT SYNAPTICS_RMI4_DS4
-#define SYNAPTICS_RMI4_DRIVER_VERSION 0x1001
-#define SYNAPTICS_RMI4_DRIVER_VERSION_STRING "0x1001"
+#define SYNAPTICS_DS4 (1 << 0)
+#define SYNAPTICS_DS5 (1 << 1)
+#define SYNAPTICS_DSX_DRIVER_PRODUCT SYNAPTICS_DS4
+#define SYNAPTICS_DSX_DRIVER_VERSION 0x1002
#include <linux/version.h>
#ifdef CONFIG_HAS_EARLYSUSPEND
diff --git a/drivers/input/touchscreen/synaptics_rmi_dev.c b/drivers/input/touchscreen/synaptics_rmi_dev.c
index fbb6f5e..7f1aac5 100644
--- a/drivers/input/touchscreen/synaptics_rmi_dev.c
+++ b/drivers/input/touchscreen/synaptics_rmi_dev.c
@@ -706,5 +706,4 @@
MODULE_AUTHOR("Synaptics, Inc.");
MODULE_DESCRIPTION("RMI4 RMI_Dev Module");
-MODULE_LICENSE("GPL");
-MODULE_VERSION(SYNAPTICS_RMI4_DRIVER_VERSION_STRING);
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index b126aa2..db4ec9d 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -38,7 +38,7 @@
config MSM_IOMMU_PMON
bool "MSM IOMMU Perfomance Monitoring Support"
- depends on ARCH_MSM8974 && MSM_IOMMU
+ depends on (ARCH_MSM8974 || ARCH_MSM8610 || ARCH_MSM8226) && MSM_IOMMU
help
Support for monitoring IOMMUs performance on certain Qualcomm SOCs.
It captures TLB statistics per context bank of the IOMMU as an
diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile
index 112b62b..096b53e 100644
--- a/drivers/iommu/Makefile
+++ b/drivers/iommu/Makefile
@@ -3,7 +3,7 @@
ifdef CONFIG_OF
obj-$(CONFIG_MSM_IOMMU) += msm_iommu-v1.o msm_iommu_dev-v1.o msm_iommu_pagetable.o msm_iommu_sec.o
endif
-obj-$(CONFIG_MSM_IOMMU_PMON) += msm_iommu_perfmon.o
+obj-$(CONFIG_MSM_IOMMU_PMON) += msm_iommu_perfmon.o msm_iommu_perfmon-v0.o msm_iommu_perfmon-v1.o
obj-$(CONFIG_AMD_IOMMU) += amd_iommu.o amd_iommu_init.o
obj-$(CONFIG_AMD_IOMMU_V2) += amd_iommu_v2.o
obj-$(CONFIG_DMAR_TABLE) += dmar.o
diff --git a/drivers/iommu/msm_iommu-v0.c b/drivers/iommu/msm_iommu-v0.c
index 28f1516..6bf0220 100644
--- a/drivers/iommu/msm_iommu-v0.c
+++ b/drivers/iommu/msm_iommu-v0.c
@@ -27,6 +27,7 @@
#include <asm/cacheflush.h>
#include <asm/sizes.h>
+#include <mach/iommu_perfmon.h>
#include <mach/iommu_hw-v0.h>
#include <mach/iommu.h>
#include <mach/msm_smsm.h>
@@ -160,6 +161,41 @@
clk_disable_unprepare(drvdata->pclk);
}
+static int _iommu_power_on(void *data)
+{
+ struct msm_iommu_drvdata *drvdata;
+
+ drvdata = (struct msm_iommu_drvdata *)data;
+ return __enable_clocks(drvdata);
+}
+
+static int _iommu_power_off(void *data)
+{
+ struct msm_iommu_drvdata *drvdata;
+
+ drvdata = (struct msm_iommu_drvdata *)data;
+ __disable_clocks(drvdata);
+ return 0;
+}
+
+static void _iommu_lock_acquire(void)
+{
+ msm_iommu_lock();
+}
+
+static void _iommu_lock_release(void)
+{
+ msm_iommu_unlock();
+}
+
+struct iommu_access_ops iommu_access_ops_v0 = {
+ .iommu_power_on = _iommu_power_on,
+ .iommu_power_off = _iommu_power_off,
+ .iommu_lock_acquire = _iommu_lock_acquire,
+ .iommu_lock_release = _iommu_lock_release,
+};
+EXPORT_SYMBOL(iommu_access_ops_v0);
+
static int __flush_iotlb_va(struct iommu_domain *domain, unsigned int va)
{
struct msm_priv *priv = domain->priv;
@@ -468,6 +504,11 @@
list_add(&(ctx_drvdata->attached_elm), &priv->list_attached);
ctx_drvdata->attached_domain = domain;
+
+ mutex_unlock(&msm_iommu_lock);
+
+ msm_iommu_attached(dev->parent);
+ return ret;
unlock:
mutex_unlock(&msm_iommu_lock);
return ret;
@@ -481,6 +522,8 @@
struct msm_iommu_ctx_drvdata *ctx_drvdata;
int ret;
+ msm_iommu_detached(dev->parent);
+
mutex_lock(&msm_iommu_lock);
priv = domain->priv;
diff --git a/drivers/iommu/msm_iommu-v1.c b/drivers/iommu/msm_iommu-v1.c
index d15dc65..15a81ed 100644
--- a/drivers/iommu/msm_iommu-v1.c
+++ b/drivers/iommu/msm_iommu-v1.c
@@ -147,12 +147,13 @@
mutex_unlock(&msm_iommu_lock);
}
-struct iommu_access_ops iommu_access_ops = {
+struct iommu_access_ops iommu_access_ops_v1 = {
.iommu_power_on = _iommu_power_on,
.iommu_power_off = _iommu_power_off,
.iommu_lock_acquire = _iommu_lock_acquire,
.iommu_lock_release = _iommu_lock_release,
};
+EXPORT_SYMBOL(iommu_access_ops_v1);
void iommu_halt(const struct msm_iommu_drvdata *iommu_drvdata)
{
diff --git a/drivers/iommu/msm_iommu_dev-v0.c b/drivers/iommu/msm_iommu_dev-v0.c
index 3a9cc23..681d7b2 100644
--- a/drivers/iommu/msm_iommu_dev-v0.c
+++ b/drivers/iommu/msm_iommu_dev-v0.c
@@ -27,6 +27,7 @@
#include <linux/of_address.h>
#include <linux/of_device.h>
+#include <mach/iommu_perfmon.h>
#include <mach/iommu_hw-v0.h>
#include <mach/iommu.h>
@@ -134,6 +135,7 @@
struct device_node *child;
struct resource *r;
u32 glb_offset = 0;
+ int ret;
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!r) {
@@ -162,7 +164,12 @@
pr_err("Failed to create %s device\n", child->name);
}
- drvdata->name = dev_name(&pdev->dev);
+ ret = of_property_read_string(pdev->dev.of_node, "label",
+ &drvdata->name);
+ if (ret) {
+ pr_err("%s: Missing property label\n", __func__);
+ return -EINVAL;
+ }
drvdata->sec_id = -1;
drvdata->ttbr_split = 0;
#endif
@@ -255,8 +262,68 @@
return ret;
}
+static int msm_iommu_pmon_parse_dt(struct platform_device *pdev,
+ struct iommu_pmon *pmon_info)
+{
+ int ret = 0;
+ int irq = platform_get_irq(pdev, 0);
+ unsigned int cls_prop_size;
+
+ if (irq > 0) {
+ pmon_info->iommu.evt_irq = platform_get_irq(pdev, 0);
+
+ ret = of_property_read_u32(pdev->dev.of_node,
+ "qcom,iommu-pmu-ngroups",
+ &pmon_info->num_groups);
+ if (ret) {
+ pr_err("Error reading qcom,iommu-pmu-ngroups\n");
+ goto fail;
+ }
+ ret = of_property_read_u32(pdev->dev.of_node,
+ "qcom,iommu-pmu-ncounters",
+ &pmon_info->num_counters);
+ if (ret) {
+ pr_err("Error reading qcom,iommu-pmu-ncounters\n");
+ goto fail;
+ }
+
+ if (!of_get_property(pdev->dev.of_node,
+ "qcom,iommu-pmu-event-classes",
+ &cls_prop_size)) {
+ pr_err("Error reading qcom,iommu-pmu-event-classes\n");
+ return -EINVAL;
+ }
+
+ pmon_info->event_cls_supported =
+ devm_kzalloc(&pdev->dev, cls_prop_size, GFP_KERNEL);
+
+ if (!pmon_info->event_cls_supported) {
+ pr_err("Unable to get memory for event class array\n");
+ return -ENOMEM;
+ }
+
+ pmon_info->nevent_cls_supported = cls_prop_size / sizeof(u32);
+
+ ret = of_property_read_u32_array(pdev->dev.of_node,
+ "qcom,iommu-pmu-event-classes",
+ pmon_info->event_cls_supported,
+ pmon_info->nevent_cls_supported);
+ if (ret) {
+ pr_err("Error reading qcom,iommu-pmu-event-classes\n");
+ return ret;
+ }
+ } else {
+ pmon_info->iommu.evt_irq = -1;
+ ret = irq;
+ }
+
+fail:
+ return ret;
+}
+
static int msm_iommu_probe(struct platform_device *pdev)
{
+ struct iommu_pmon *pmon_info;
struct msm_iommu_drvdata *drvdata;
struct msm_iommu_dev *iommu_dev = pdev->dev.platform_data;
int ret;
@@ -339,6 +406,29 @@
__disable_clocks(drvdata);
+ pmon_info = msm_iommu_pm_alloc(&pdev->dev);
+ if (pmon_info != NULL) {
+ ret = msm_iommu_pmon_parse_dt(pdev, pmon_info);
+ if (ret) {
+ msm_iommu_pm_free(&pdev->dev);
+ pr_info("%s: pmon not available.\n", drvdata->name);
+ } else {
+ pmon_info->iommu.base = drvdata->base;
+ pmon_info->iommu.ops = &iommu_access_ops_v0;
+ pmon_info->iommu.hw_ops = iommu_pm_get_hw_ops_v0();
+ pmon_info->iommu.iommu_name = drvdata->name;
+ ret = msm_iommu_pm_iommu_register(pmon_info);
+ if (ret) {
+ pr_err("%s iommu register fail\n",
+ drvdata->name);
+ msm_iommu_pm_free(&pdev->dev);
+ } else {
+ pr_debug("%s iommu registered for pmon\n",
+ pmon_info->iommu.iommu_name);
+ }
+ }
+ }
+
return 0;
fail_clk:
diff --git a/drivers/iommu/msm_iommu_dev-v1.c b/drivers/iommu/msm_iommu_dev-v1.c
index 02fd133..f0d2de2 100644
--- a/drivers/iommu/msm_iommu_dev-v1.c
+++ b/drivers/iommu/msm_iommu_dev-v1.c
@@ -269,7 +269,8 @@
pr_info("%s: pmon not available.\n", drvdata->name);
} else {
pmon_info->iommu.base = drvdata->base;
- pmon_info->iommu.ops = &iommu_access_ops;
+ pmon_info->iommu.ops = &iommu_access_ops_v1;
+ pmon_info->iommu.hw_ops = iommu_pm_get_hw_ops_v1();
pmon_info->iommu.iommu_name = drvdata->name;
ret = msm_iommu_pm_iommu_register(pmon_info);
if (ret) {
diff --git a/drivers/iommu/msm_iommu_perfmon-v0.c b/drivers/iommu/msm_iommu_perfmon-v0.c
new file mode 100644
index 0000000..c80d1e5
--- /dev/null
+++ b/drivers/iommu/msm_iommu_perfmon-v0.c
@@ -0,0 +1,310 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/**
+ * This file contains the part of the IOMMUv0 PMU driver that actually touches
+ * IOMMU PMU registers.
+ */
+
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <mach/iommu_hw-v0.h>
+#include <mach/iommu_perfmon.h>
+
+#define PM_RESET_MASK (0xF)
+#define PM_RESET_SHIFT (0x8)
+#define PM_RESET (PM_RESET_MASK << PM_RESET_SHIFT)
+
+#define PM_ENABLE_MASK (0x1)
+#define PM_ENABLE_SHIFT (0x0)
+#define PM_ENABLE (PM_ENABLE_MASK << PM_ENABLE_SHIFT)
+
+#define PM_OVFL_FLAG_MASK (0xF)
+#define PM_OVFL_FLAG_SHIFT (0x0)
+#define PM_OVFL_FLAG (PM_OVFL_FLAG_MASK << PM_OVFL_FLAG_SHIFT)
+
+#define PM_EVENT_TYPE_MASK (0x1F)
+#define PM_EVENT_TYPE_SHIFT (0x2)
+#define PM_EVENT_TYPE (PM_EVENT_TYPE_MASK << PM_EVENT_TYPE_SHIFT)
+
+#define PM_INT_EN_MASK (0x1)
+#define PM_INT_EN_SHIFT (0x0)
+#define PM_INT_EN (PM_INT_EN_MASK << PM_INT_EN_SHIFT)
+
+#define PM_INT_POL_MASK (0x1)
+#define PM_INT_POL_SHIFT (0x2)
+#define PM_INT_ACTIVE_HIGH (0x1)
+
+#define PMEVCNTR_(n) (EMC_N + n*4)
+#define PMEVTYPER_(n) (EMCC_N + n*4)
+
+/**
+ * Translate between SMMUv0 event classes and standard ARM SMMU event classes
+ */
+static int iommu_pm_event_class_translation_table[] = {
+ MSM_IOMMU_PMU_NO_EVENT_CLASS,
+ MSM_IOMMU_PMU_NO_EVENT_CLASS,
+ MSM_IOMMU_PMU_NO_EVENT_CLASS,
+ 0x8,
+ 0x9,
+ MSM_IOMMU_PMU_NO_EVENT_CLASS,
+ 0x80,
+ MSM_IOMMU_PMU_NO_EVENT_CLASS,
+ 0x12,
+ MSM_IOMMU_PMU_NO_EVENT_CLASS,
+ MSM_IOMMU_PMU_NO_EVENT_CLASS,
+ MSM_IOMMU_PMU_NO_EVENT_CLASS,
+ MSM_IOMMU_PMU_NO_EVENT_CLASS,
+ MSM_IOMMU_PMU_NO_EVENT_CLASS,
+ MSM_IOMMU_PMU_NO_EVENT_CLASS,
+ 0x10,
+};
+
+static int iommu_pm_translate_event_class(int event_class)
+{
+ const unsigned int TBL_LEN =
+ ARRAY_SIZE(iommu_pm_event_class_translation_table);
+ unsigned int i;
+
+ if (event_class < 0)
+ return event_class;
+
+ for (i = 0; i < TBL_LEN; ++i) {
+ if (iommu_pm_event_class_translation_table[i] == event_class)
+ return i;
+ }
+ return MSM_IOMMU_PMU_NO_EVENT_CLASS;
+}
+
+static unsigned int iommu_pm_is_hw_access_OK(const struct iommu_pmon *pmon)
+{
+ /*
+ * IOMMUv0 is in always ON domain so we don't care whether we are
+ * attached or not. We only care whether the PMU is enabled or
+ * not meaning clocks are turned on.
+ */
+ return pmon->enabled;
+}
+
+static void iommu_pm_grp_enable(struct iommu_info *iommu, unsigned int grp_no)
+{
+ /* No group concept in v0. */
+}
+
+static void iommu_pm_grp_disable(struct iommu_info *iommu, unsigned int grp_no)
+{
+ /* No group concept in v0. */
+}
+
+static void iommu_pm_set_int_active_high(const struct iommu_info *iommu)
+{
+ unsigned int emmc;
+ emmc = readl_relaxed(iommu->base + EMMC);
+ emmc |= (PM_INT_ACTIVE_HIGH & PM_INT_POL_MASK) << PM_INT_POL_SHIFT;
+ writel_relaxed(emmc, iommu->base + EMMC);
+}
+
+static void iommu_pm_enable(struct iommu_info *iommu)
+{
+ unsigned int emmc;
+ emmc = readl_relaxed(iommu->base + EMMC);
+ emmc |= PM_ENABLE;
+ writel_relaxed(emmc, iommu->base + EMMC);
+}
+
+static void iommu_pm_disable(struct iommu_info *iommu)
+{
+ unsigned int emmc;
+ emmc = readl_relaxed(iommu->base + EMMC);
+ emmc &= ~PM_ENABLE;
+ writel_relaxed(emmc, iommu->base + EMMC);
+}
+
+static void iommu_pm_reset_counters(const struct iommu_info *iommu)
+{
+ unsigned int emmc;
+ emmc = readl_relaxed(iommu->base + EMMC);
+ emmc |= PM_RESET;
+ writel_relaxed(emmc, iommu->base + EMMC);
+}
+
+static void iommu_pm_check_for_overflow(struct iommu_pmon *pmon)
+{
+ struct iommu_pmon_counter *counter;
+ struct iommu_info *iommu = &pmon->iommu;
+ unsigned int reg_value;
+ unsigned int j;
+ struct iommu_pmon_cnt_group *cnt_grp = &pmon->cnt_grp[0];
+
+ reg_value = readl_relaxed(iommu->base + EMCS);
+ reg_value &= PM_OVFL_FLAG;
+
+ for (j = 0; j < cnt_grp->num_counters; ++j) {
+ counter = &cnt_grp->counters[j];
+
+ if (counter->enabled) {
+ if (reg_value & (1 << counter->absolute_counter_no))
+ counter->overflow_count++;
+ }
+ }
+
+ /* Clear overflow */
+ writel_relaxed(reg_value, iommu->base + EMCS);
+}
+
+static irqreturn_t iommu_pm_evt_ovfl_int_handler(int irq, void *dev_id)
+{
+ struct iommu_pmon *pmon = dev_id;
+ struct iommu_info *iommu = &pmon->iommu;
+
+ mutex_lock(&pmon->lock);
+
+ if (!iommu_pm_is_hw_access_OK(pmon)) {
+ mutex_unlock(&pmon->lock);
+ goto out;
+ }
+
+ iommu->ops->iommu_lock_acquire();
+ iommu_pm_check_for_overflow(pmon);
+ iommu->ops->iommu_lock_release();
+
+ mutex_unlock(&pmon->lock);
+
+out:
+ return IRQ_HANDLED;
+}
+
+static void iommu_pm_counter_enable(struct iommu_info *iommu,
+ struct iommu_pmon_counter *counter)
+{
+ unsigned int bit_no = counter->absolute_counter_no;
+ unsigned int reg_value;
+
+ /* Clear overflow of counter */
+ reg_value = readl_relaxed(iommu->base + EMCS);
+ reg_value &= (1 << bit_no);
+ writel_relaxed(reg_value, iommu->base + EMCS);
+
+ /* Enable counter */
+ counter->enabled = 1;
+}
+
+static void iommu_pm_counter_disable(struct iommu_info *iommu,
+ struct iommu_pmon_counter *counter)
+{
+ unsigned int bit_no = counter->absolute_counter_no;
+ unsigned int reg_value;
+
+ /* Disable counter */
+ counter->enabled = 0;
+
+ /* Clear overflow of counter */
+ reg_value = readl_relaxed(iommu->base + EMCS);
+ reg_value &= (1 << bit_no);
+ writel_relaxed(reg_value, iommu->base + EMCS);
+}
+
+/*
+ * Must be called after iommu_start_access() is called
+ */
+static void iommu_pm_ovfl_int_enable(struct iommu_info *iommu,
+ const struct iommu_pmon_counter *counter)
+{
+ unsigned int reg_no = counter->absolute_counter_no;
+ unsigned int reg_value;
+
+ /* Enable overflow interrupt for counter */
+ reg_value = readl_relaxed(iommu->base + PMEVTYPER_(reg_no));
+ reg_value |= PM_INT_EN;
+ writel_relaxed(reg_value, iommu->base + PMEVTYPER_(reg_no));
+}
+
+/*
+ * Must be called after iommu_start_access() is called
+ */
+static void iommu_pm_ovfl_int_disable(struct iommu_info *iommu,
+ const struct iommu_pmon_counter *counter)
+{
+ unsigned int reg_no = counter->absolute_counter_no;
+ unsigned int reg_value;
+
+ /* Disable overflow interrupt for counter */
+ reg_value = readl_relaxed(iommu->base + PMEVTYPER_(reg_no));
+ reg_value &= ~PM_INT_EN;
+ writel_relaxed(reg_value, iommu->base + PMEVTYPER_(reg_no));
+}
+
+static void iommu_pm_set_event_class(struct iommu_pmon *pmon,
+ unsigned int count_no,
+ unsigned int event_class)
+{
+ unsigned int reg_no = count_no;
+ unsigned int reg_value;
+ int event = iommu_pm_translate_event_class(event_class);
+
+ if (event == MSM_IOMMU_PMU_NO_EVENT_CLASS)
+ event = 0;
+
+ reg_value = readl_relaxed(pmon->iommu.base + PMEVTYPER_(reg_no));
+ reg_value &= ~(PM_EVENT_TYPE_MASK << PM_EVENT_TYPE_SHIFT);
+ reg_value |= (event & PM_EVENT_TYPE_MASK) << PM_EVENT_TYPE_SHIFT;
+ writel_relaxed(reg_value, pmon->iommu.base + PMEVTYPER_(reg_no));
+}
+
+static unsigned int iommu_pm_read_counter(struct iommu_pmon_counter *counter)
+{
+ struct iommu_pmon *pmon = counter->cnt_group->pmon;
+ struct iommu_info *info = &pmon->iommu;
+ unsigned int cnt_no = counter->absolute_counter_no;
+ return readl_relaxed(info->base + PMEVCNTR_(cnt_no));
+}
+
+static void iommu_pm_initialize_hw(const struct iommu_pmon *pmon)
+{
+ const struct iommu_info *iommu = &pmon->iommu;
+ struct msm_iommu_drvdata *iommu_drvdata =
+ dev_get_drvdata(iommu->iommu_dev);
+
+ /* This is called during bootup device initialization so no need
+ * for locking here.
+ */
+ iommu->ops->iommu_power_on(iommu_drvdata);
+ iommu_pm_set_int_active_high(iommu);
+ iommu->ops->iommu_power_off(iommu_drvdata);
+}
+
+static struct iommu_pm_hw_ops iommu_pm_hw_ops = {
+ .initialize_hw = iommu_pm_initialize_hw,
+ .is_hw_access_OK = iommu_pm_is_hw_access_OK,
+ .grp_enable = iommu_pm_grp_enable,
+ .grp_disable = iommu_pm_grp_disable,
+ .enable_pm = iommu_pm_enable,
+ .disable_pm = iommu_pm_disable,
+ .reset_counters = iommu_pm_reset_counters,
+ .check_for_overflow = iommu_pm_check_for_overflow,
+ .evt_ovfl_int_handler = iommu_pm_evt_ovfl_int_handler,
+ .counter_enable = iommu_pm_counter_enable,
+ .counter_disable = iommu_pm_counter_disable,
+ .ovfl_int_enable = iommu_pm_ovfl_int_enable,
+ .ovfl_int_disable = iommu_pm_ovfl_int_disable,
+ .set_event_class = iommu_pm_set_event_class,
+ .read_counter = iommu_pm_read_counter,
+};
+
+struct iommu_pm_hw_ops *iommu_pm_get_hw_ops_v0(void)
+{
+ return &iommu_pm_hw_ops;
+}
+EXPORT_SYMBOL(iommu_pm_get_hw_ops_v0);
+
diff --git a/drivers/iommu/msm_iommu_perfmon-v1.c b/drivers/iommu/msm_iommu_perfmon-v1.c
new file mode 100644
index 0000000..d76ee7f
--- /dev/null
+++ b/drivers/iommu/msm_iommu_perfmon-v1.c
@@ -0,0 +1,269 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/**
+ * This file contains the part of the IOMMUv1 PMU driver that actually touches
+ * IOMMU PMU registers.
+ */
+
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <mach/iommu_hw-v1.h>
+#include <mach/iommu_perfmon.h>
+
+#define PMCR_P_MASK (0x1)
+#define PMCR_P_SHIFT (1)
+#define PMCR_P (PMCR_P_MASK << PMCR_P_SHIFT)
+#define PMCFGR_NCG_MASK (0xFF)
+#define PMCFGR_NCG_SHIFT (24)
+#define PMCFGR_NCG (PMCFGR_NCG_MASK << PMCFGR_NCG_SHIFT)
+#define PMCFGR_N_MASK (0xFF)
+#define PMCFGR_N_SHIFT (0)
+#define PMCFGR_N (PMCFGR_N_MASK << PMCFGR_N_SHIFT)
+#define CR_E 0x1
+#define CGCR_CEN 0x800
+#define CGCR_CEN_SHFT (1 << 11)
+#define PMCGCR_CGNC_MASK (0x0F)
+#define PMCGCR_CGNC_SHIFT (24)
+#define PMCGCR_CGNC (PMCGCR_CGNC_MASK << PMCGCR_CGNC_SHIFT)
+#define PMCGCR_(group) (PMCGCR_N + group*4)
+
+#define PMOVSCLR_(n) (PMOVSCLR_N + n*4)
+#define PMCNTENSET_(n) (PMCNTENSET_N + n*4)
+#define PMCNTENCLR_(n) (PMCNTENCLR_N + n*4)
+#define PMINTENSET_(n) (PMINTENSET_N + n*4)
+#define PMINTENCLR_(n) (PMINTENCLR_N + n*4)
+
+#define PMEVCNTR_(n) (PMEVCNTR_N + n*4)
+#define PMEVTYPER_(n) (PMEVTYPER_N + n*4)
+
+
+static unsigned int iommu_pm_is_hw_access_OK(const struct iommu_pmon *pmon)
+{
+ /*
+ * IOMMUv1 is not in the always on domain so we need to make sure
+ * the regulators are turned on in addition to clocks before we allow
+ * access to the hardware thus we check if we have attached to the
+ * IOMMU in addition to checking if we have enabled PMU.
+ */
+ return pmon->enabled && (pmon->iommu_attach_count > 0);
+}
+
+static void iommu_pm_grp_enable(struct iommu_info *iommu, unsigned int grp_no)
+{
+ unsigned int pmcgcr;
+ pmcgcr = readl_relaxed(iommu->base + PMCGCR_(grp_no));
+ pmcgcr |= CGCR_CEN;
+ writel_relaxed(pmcgcr, iommu->base + PMCGCR_(grp_no));
+}
+
+static void iommu_pm_grp_disable(struct iommu_info *iommu, unsigned int grp_no)
+{
+ unsigned int pmcgcr;
+ pmcgcr = readl_relaxed(iommu->base + PMCGCR_(grp_no));
+ pmcgcr &= ~CGCR_CEN;
+ writel_relaxed(pmcgcr, iommu->base + PMCGCR_(grp_no));
+}
+
+static void iommu_pm_enable(struct iommu_info *iommu)
+{
+ unsigned int pmcr;
+ pmcr = readl_relaxed(iommu->base + PMCR);
+ pmcr |= CR_E;
+ writel_relaxed(pmcr, iommu->base + PMCR);
+}
+
+static void iommu_pm_disable(struct iommu_info *iommu)
+{
+ unsigned int pmcr;
+ pmcr = readl_relaxed(iommu->base + PMCR);
+ pmcr &= ~CR_E;
+ writel_relaxed(pmcr, iommu->base + PMCR);
+}
+
+static void iommu_pm_reset_counters(const struct iommu_info *iommu)
+{
+ unsigned int pmcr;
+ pmcr = readl_relaxed(iommu->base + PMCR);
+ pmcr |= PMCR_P;
+ writel_relaxed(pmcr, iommu->base + PMCR);
+}
+
+static void iommu_pm_check_for_overflow(struct iommu_pmon *pmon)
+{
+ struct iommu_pmon_counter *counter;
+ struct iommu_info *iommu = &pmon->iommu;
+ unsigned int reg_no = 0;
+ unsigned int bit_no;
+ unsigned int reg_value;
+ unsigned int i;
+ unsigned int j;
+ unsigned int curr_reg = 0;
+
+ reg_value = readl_relaxed(iommu->base + PMOVSCLR_(curr_reg));
+
+ for (i = 0; i < pmon->num_groups; ++i) {
+ struct iommu_pmon_cnt_group *cnt_grp = &pmon->cnt_grp[i];
+ for (j = 0; j < cnt_grp->num_counters; ++j) {
+ counter = &cnt_grp->counters[j];
+ reg_no = counter->absolute_counter_no / 32;
+ bit_no = counter->absolute_counter_no % 32;
+ if (reg_no != curr_reg) {
+ /* Clear overflow bits */
+ writel_relaxed(reg_value, iommu->base +
+ PMOVSCLR_(reg_no));
+ curr_reg = reg_no;
+ reg_value = readl_relaxed(iommu->base +
+ PMOVSCLR_(curr_reg));
+ }
+
+ if (counter->enabled) {
+ if (reg_value & (1 << bit_no))
+ counter->overflow_count++;
+ }
+ }
+ }
+
+ /* Clear overflow */
+ writel_relaxed(reg_value, iommu->base + PMOVSCLR_(reg_no));
+}
+
+static irqreturn_t iommu_pm_evt_ovfl_int_handler(int irq, void *dev_id)
+{
+ struct iommu_pmon *pmon = dev_id;
+ struct iommu_info *iommu = &pmon->iommu;
+
+ mutex_lock(&pmon->lock);
+
+ if (!iommu_pm_is_hw_access_OK(pmon)) {
+ mutex_unlock(&pmon->lock);
+ goto out;
+ }
+
+ iommu->ops->iommu_lock_acquire();
+ iommu_pm_check_for_overflow(pmon);
+ iommu->ops->iommu_lock_release();
+
+ mutex_unlock(&pmon->lock);
+
+out:
+ return IRQ_HANDLED;
+}
+
+static void iommu_pm_counter_enable(struct iommu_info *iommu,
+ struct iommu_pmon_counter *counter)
+{
+ unsigned int reg_no = counter->absolute_counter_no / 32;
+ unsigned int bit_no = counter->absolute_counter_no % 32;
+ unsigned int reg_value;
+
+ /* Clear overflow of counter */
+ reg_value = 1 << bit_no;
+ writel_relaxed(reg_value, iommu->base + PMOVSCLR_(reg_no));
+
+ /* Enable counter */
+ writel_relaxed(reg_value, iommu->base + PMCNTENSET_(reg_no));
+ counter->enabled = 1;
+}
+
+static void iommu_pm_counter_disable(struct iommu_info *iommu,
+ struct iommu_pmon_counter *counter)
+{
+ unsigned int reg_no = counter->absolute_counter_no / 32;
+ unsigned int bit_no = counter->absolute_counter_no % 32;
+ unsigned int reg_value;
+
+ counter->enabled = 0;
+
+ /* Disable counter */
+ reg_value = 1 << bit_no;
+ writel_relaxed(reg_value, iommu->base + PMCNTENCLR_(reg_no));
+
+ /* Clear overflow of counter */
+ writel_relaxed(reg_value, iommu->base + PMOVSCLR_(reg_no));
+}
+
+/*
+ * Must be called after iommu_start_access() is called
+ */
+static void iommu_pm_ovfl_int_enable(struct iommu_info *iommu,
+ const struct iommu_pmon_counter *counter)
+{
+ unsigned int reg_no = counter->absolute_counter_no / 32;
+ unsigned int bit_no = counter->absolute_counter_no % 32;
+ unsigned int reg_value;
+
+ /* Enable overflow interrupt for counter */
+ reg_value = (1 << bit_no);
+ writel_relaxed(reg_value, iommu->base + PMINTENSET_(reg_no));
+}
+
+/*
+ * Must be called after iommu_start_access() is called
+ */
+static void iommu_pm_ovfl_int_disable(struct iommu_info *iommu,
+ const struct iommu_pmon_counter *counter)
+{
+ unsigned int reg_no = counter->absolute_counter_no / 32;
+ unsigned int bit_no = counter->absolute_counter_no % 32;
+ unsigned int reg_value;
+
+ /* Disable overflow interrupt for counter */
+ reg_value = 1 << bit_no;
+ writel_relaxed(reg_value, iommu->base + PMINTENCLR_(reg_no));
+}
+
+static void iommu_pm_set_event_class(struct iommu_pmon *pmon,
+ unsigned int count_no,
+ unsigned int event_class)
+{
+ writel_relaxed(event_class, pmon->iommu.base + PMEVTYPER_(count_no));
+}
+
+static unsigned int iommu_pm_read_counter(struct iommu_pmon_counter *counter)
+{
+ struct iommu_pmon *pmon = counter->cnt_group->pmon;
+ struct iommu_info *info = &pmon->iommu;
+ unsigned int cnt_no = counter->absolute_counter_no;
+ return readl_relaxed(info->base + PMEVCNTR_(cnt_no));
+}
+
+static void iommu_pm_initialize_hw(const struct iommu_pmon *pmon)
+{
+ /* No initialization needed */
+}
+
+static struct iommu_pm_hw_ops iommu_pm_hw_ops = {
+ .initialize_hw = iommu_pm_initialize_hw,
+ .is_hw_access_OK = iommu_pm_is_hw_access_OK,
+ .grp_enable = iommu_pm_grp_enable,
+ .grp_disable = iommu_pm_grp_disable,
+ .enable_pm = iommu_pm_enable,
+ .disable_pm = iommu_pm_disable,
+ .reset_counters = iommu_pm_reset_counters,
+ .check_for_overflow = iommu_pm_check_for_overflow,
+ .evt_ovfl_int_handler = iommu_pm_evt_ovfl_int_handler,
+ .counter_enable = iommu_pm_counter_enable,
+ .counter_disable = iommu_pm_counter_disable,
+ .ovfl_int_enable = iommu_pm_ovfl_int_enable,
+ .ovfl_int_disable = iommu_pm_ovfl_int_disable,
+ .set_event_class = iommu_pm_set_event_class,
+ .read_counter = iommu_pm_read_counter,
+};
+
+struct iommu_pm_hw_ops *iommu_pm_get_hw_ops_v1(void)
+{
+ return &iommu_pm_hw_ops;
+}
+EXPORT_SYMBOL(iommu_pm_get_hw_ops_v1);
+
diff --git a/drivers/iommu/msm_iommu_perfmon.c b/drivers/iommu/msm_iommu_perfmon.c
index 97bd660..41df1ed 100644
--- a/drivers/iommu/msm_iommu_perfmon.c
+++ b/drivers/iommu/msm_iommu_perfmon.c
@@ -20,40 +20,12 @@
#include <linux/interrupt.h>
#include <linux/bitops.h>
#include <linux/debugfs.h>
-#include <mach/iommu_hw-v1.h>
#include <mach/iommu.h>
#include <mach/iommu_perfmon.h>
-#define PMCR_P_MASK (0x1)
-#define PMCR_P_SHIFT (1)
-#define PMCR_P (PMCR_P_MASK << PMCR_P_SHIFT)
-#define PMCFGR_NCG_MASK (0xFF)
-#define PMCFGR_NCG_SHIFT (24)
-#define PMCFGR_NCG (PMCFGR_NCG_MASK << PMCFGR_NCG_SHIFT)
-#define PMCFGR_N_MASK (0xFF)
-#define PMCFGR_N_SHIFT (0)
-#define PMCFGR_N (PMCFGR_N_MASK << PMCFGR_N_SHIFT)
-#define CR_E 0x1
-#define CGCR_CEN 0x800
-#define CGCR_CEN_SHFT (1 << 11)
-#define PMCGCR_CGNC_MASK (0x0F)
-#define PMCGCR_CGNC_SHIFT (24)
-#define PMCGCR_CGNC (PMCGCR_CGNC_MASK << PMCGCR_CGNC_SHIFT)
-#define PMCGCR_(group) (PMCGCR_N + group*4)
-
-#define PMOVSCLR_(n) (PMOVSCLR_N + n*4)
-#define PMCNTENSET_(n) (PMCNTENSET_N + n*4)
-#define PMCNTENCLR_(n) (PMCNTENCLR_N + n*4)
-#define PMINTENSET_(n) (PMINTENSET_N + n*4)
-#define PMINTENCLR_(n) (PMINTENCLR_N + n*4)
-
-#define PMEVCNTR_(n) (PMEVCNTR_N + n*4)
-#define PMEVTYPER_(n) (PMEVTYPER_N + n*4)
-
static LIST_HEAD(iommu_list);
static struct dentry *msm_iommu_root_debugfs_dir;
static const char *NO_EVENT_CLASS_NAME = "none";
-static int NO_EVENT_CLASS = -1;
static const unsigned int MAX_EVEN_CLASS_NAME_LEN = 36;
struct event_class {
@@ -81,11 +53,6 @@
{ 0xb1, "tot_num_pred_axi_htw_read_req" },
};
-static unsigned int iommu_pm_is_hw_access_OK(const struct iommu_pmon *pmon)
-{
- return pmon->enabled && (pmon->iommu_attach_count > 0);
-}
-
static unsigned int iommu_pm_create_sup_cls_str(char **buf,
struct iommu_pmon *pmon)
{
@@ -151,7 +118,7 @@
size_t array_len;
struct event_class *ptr;
int i;
- int event_class = NO_EVENT_CLASS;
+ int event_class = MSM_IOMMU_PMU_NO_EVENT_CLASS;
if (strcmp(event_class_name, NO_EVENT_CLASS_NAME) == 0)
goto out;
@@ -194,170 +161,6 @@
return NULL;
}
-static void iommu_pm_grp_enable(struct iommu_info *iommu, unsigned int grp_no)
-{
- unsigned int pmcgcr;
- pmcgcr = readl_relaxed(iommu->base + PMCGCR_(grp_no));
- pmcgcr |= CGCR_CEN;
- writel_relaxed(pmcgcr, iommu->base + PMCGCR_(grp_no));
-}
-
-static void iommu_pm_grp_disable(struct iommu_info *iommu, unsigned int grp_no)
-{
- unsigned int pmcgcr;
- pmcgcr = readl_relaxed(iommu->base + PMCGCR_(grp_no));
- pmcgcr &= ~CGCR_CEN;
- writel_relaxed(pmcgcr, iommu->base + PMCGCR_(grp_no));
-}
-
-static void iommu_pm_enable(struct iommu_info *iommu)
-{
- unsigned int pmcr;
- pmcr = readl_relaxed(iommu->base + PMCR);
- pmcr |= CR_E;
- writel_relaxed(pmcr, iommu->base + PMCR);
-}
-
-static void iommu_pm_disable(struct iommu_info *iommu)
-{
- unsigned int pmcr;
- pmcr = readl_relaxed(iommu->base + PMCR);
- pmcr &= ~CR_E;
- writel_relaxed(pmcr, iommu->base + PMCR);
-}
-
-static void iommu_pm_reset_counters(const struct iommu_info *iommu)
-{
- unsigned int pmcr;
- pmcr = readl_relaxed(iommu->base + PMCR);
- pmcr |= PMCR_P;
- writel_relaxed(pmcr, iommu->base + PMCR);
-}
-
-static void iommu_pm_check_for_overflow(struct iommu_pmon *pmon)
-{
- struct iommu_pmon_counter *counter;
- struct iommu_info *iommu = &pmon->iommu;
- unsigned int reg_no = 0;
- unsigned int bit_no;
- unsigned int reg_value;
- unsigned int i;
- unsigned int j;
- unsigned int curr_reg = 0;
-
- reg_value = readl_relaxed(iommu->base + PMOVSCLR_(curr_reg));
-
- for (i = 0; i < pmon->num_groups; ++i) {
- struct iommu_pmon_cnt_group *cnt_grp = &pmon->cnt_grp[i];
- for (j = 0; j < cnt_grp->num_counters; ++j) {
- counter = &cnt_grp->counters[j];
- reg_no = counter->absolute_counter_no / 32;
- bit_no = counter->absolute_counter_no % 32;
- if (reg_no != curr_reg) {
- /* Clear overflow bits */
- writel_relaxed(reg_value, iommu->base +
- PMOVSCLR_(reg_no));
- curr_reg = reg_no;
- reg_value = readl_relaxed(iommu->base +
- PMOVSCLR_(curr_reg));
- }
-
- if (counter->enabled) {
- if (reg_value & (1 << bit_no))
- counter->overflow_count++;
- }
- }
- }
-
- /* Clear overflow */
- writel_relaxed(reg_value, iommu->base + PMOVSCLR_(reg_no));
-}
-
-irqreturn_t iommu_pm_evt_ovfl_int_handler(int irq, void *dev_id)
-{
- struct iommu_pmon *pmon = dev_id;
- struct iommu_info *iommu = &pmon->iommu;
-
- mutex_lock(&pmon->lock);
-
- if (!iommu_pm_is_hw_access_OK(pmon)) {
- mutex_unlock(&pmon->lock);
- goto out;
- }
-
- iommu->ops->iommu_lock_acquire();
- iommu_pm_check_for_overflow(pmon);
- iommu->ops->iommu_lock_release();
-
- mutex_unlock(&pmon->lock);
-
-out:
- return IRQ_HANDLED;
-}
-
-static void iommu_pm_counter_enable(struct iommu_info *iommu,
- struct iommu_pmon_counter *counter)
-{
- unsigned int reg_no = counter->absolute_counter_no / 32;
- unsigned int bit_no = counter->absolute_counter_no % 32;
- unsigned int reg_value;
-
- /* Clear overflow of counter */
- reg_value = 1 << bit_no;
- writel_relaxed(reg_value, iommu->base + PMOVSCLR_(reg_no));
-
- /* Enable counter */
- writel_relaxed(reg_value, iommu->base + PMCNTENSET_(reg_no));
- counter->enabled = 1;
-}
-
-static void iommu_pm_counter_disable(struct iommu_info *iommu,
- struct iommu_pmon_counter *counter)
-{
- unsigned int reg_no = counter->absolute_counter_no / 32;
- unsigned int bit_no = counter->absolute_counter_no % 32;
- unsigned int reg_value;
-
- counter->enabled = 0;
-
- /* Disable counter */
- reg_value = 1 << bit_no;
- writel_relaxed(reg_value, iommu->base + PMCNTENCLR_(reg_no));
-
- /* Clear overflow of counter */
- writel_relaxed(reg_value, iommu->base + PMOVSCLR_(reg_no));
-}
-
-/*
- * Must be called after iommu_start_access() is called
- */
-static void iommu_pm_ovfl_int_enable(struct iommu_info *iommu,
- const struct iommu_pmon_counter *counter)
-{
- unsigned int reg_no = counter->absolute_counter_no / 32;
- unsigned int bit_no = counter->absolute_counter_no % 32;
- unsigned int reg_value;
-
- /* Enable overflow interrupt for counter */
- reg_value = (1 << bit_no);
- writel_relaxed(reg_value, iommu->base + PMINTENSET_(reg_no));
-}
-
-/*
- * Must be called after iommu_start_access() is called
- */
-static void iommu_pm_ovfl_int_disable(struct iommu_info *iommu,
- const struct iommu_pmon_counter *counter)
-{
- unsigned int reg_no = counter->absolute_counter_no / 32;
- unsigned int bit_no = counter->absolute_counter_no % 32;
- unsigned int reg_value;
-
- /* Disable overflow interrupt for counter */
- reg_value = 1 << bit_no;
- writel_relaxed(reg_value, iommu->base + PMINTENCLR_(reg_no));
-}
-
static void iommu_pm_set_event_type(struct iommu_pmon *pmon,
struct iommu_pmon_counter *counter)
{
@@ -368,12 +171,12 @@
event_class = counter->current_event_class;
count_no = counter->absolute_counter_no;
- if (event_class == NO_EVENT_CLASS) {
- if (iommu_pm_is_hw_access_OK(pmon)) {
+ if (event_class == MSM_IOMMU_PMU_NO_EVENT_CLASS) {
+ if (iommu->hw_ops->is_hw_access_OK(pmon)) {
iommu->ops->iommu_lock_acquire();
- iommu_pm_counter_disable(iommu, counter);
- iommu_pm_ovfl_int_disable(iommu, counter);
- writel_relaxed(0, iommu->base + PMEVTYPER_(count_no));
+ iommu->hw_ops->counter_disable(iommu, counter);
+ iommu->hw_ops->ovfl_int_disable(iommu, counter);
+ iommu->hw_ops->set_event_class(pmon, count_no, 0);
iommu->ops->iommu_lock_release();
}
counter->overflow_count = 0;
@@ -381,12 +184,12 @@
} else {
counter->overflow_count = 0;
counter->value = 0;
- if (iommu_pm_is_hw_access_OK(pmon)) {
+ if (iommu->hw_ops->is_hw_access_OK(pmon)) {
iommu->ops->iommu_lock_acquire();
- writel_relaxed(event_class,
- iommu->base + PMEVTYPER_(count_no));
- iommu_pm_ovfl_int_enable(iommu, counter);
- iommu_pm_counter_enable(iommu, counter);
+ iommu->hw_ops->set_event_class(pmon, count_no,
+ event_class);
+ iommu->hw_ops->ovfl_int_enable(iommu, counter);
+ iommu->hw_ops->counter_enable(iommu, counter);
iommu->ops->iommu_lock_release();
}
}
@@ -405,19 +208,6 @@
}
}
-static unsigned int iommu_pm_read_counter(struct iommu_pmon_counter *counter)
-{
- struct iommu_pmon *pmon = counter->cnt_group->pmon;
- struct iommu_info *info = &pmon->iommu;
- unsigned int cnt_no = counter->absolute_counter_no;
- unsigned int pmevcntr;
-
- pmevcntr = readl_relaxed(info->base + PMEVCNTR_(cnt_no));
-
- return pmevcntr;
-
-}
-
static void iommu_pm_set_all_counters(struct iommu_pmon *pmon)
{
unsigned int i;
@@ -433,12 +223,13 @@
{
unsigned int i;
unsigned int j;
+ struct iommu_info *iommu = &pmon->iommu;
for (i = 0; i < pmon->num_groups; ++i) {
struct iommu_pmon_cnt_group *cnt_grp = &pmon->cnt_grp[i];
for (j = 0; j < cnt_grp->num_counters; ++j) {
struct iommu_pmon_counter *counter;
counter = &cnt_grp->counters[j];
- counter->value = iommu_pm_read_counter(counter);
+ counter->value = iommu->hw_ops->read_counter(counter);
}
}
}
@@ -452,6 +243,12 @@
iommu->ops->iommu_power_on(iommu_drvdata);
+ /* Reset counters in HW */
+ iommu->ops->iommu_lock_acquire();
+ iommu->hw_ops->reset_counters(&pmon->iommu);
+ iommu->ops->iommu_lock_release();
+
+ /* Reset SW counters */
iommu_pm_reset_counts(pmon);
pmon->enabled = 1;
@@ -462,10 +259,10 @@
/* enable all counter group */
for (i = 0; i < pmon->num_groups; ++i)
- iommu_pm_grp_enable(iommu, i);
+ iommu->hw_ops->grp_enable(iommu, i);
/* enable global counters */
- iommu_pm_enable(iommu);
+ iommu->hw_ops->enable_pm(iommu);
iommu->ops->iommu_lock_release();
pr_info("%s: TLB performance monitoring turned ON\n",
@@ -484,14 +281,14 @@
iommu->ops->iommu_lock_acquire();
/* disable global counters */
- iommu_pm_disable(iommu);
+ iommu->hw_ops->disable_pm(iommu);
/* Check if we overflowed just before turning off pmon */
- iommu_pm_check_for_overflow(pmon);
+ iommu->hw_ops->check_for_overflow(pmon);
/* disable all counter group */
for (i = 0; i < pmon->num_groups; ++i)
- iommu_pm_grp_disable(iommu, i);
+ iommu->hw_ops->grp_disable(iommu, i);
/* Update cached copy of counters before turning off power */
iommu_pm_read_all_counters(pmon);
@@ -524,9 +321,9 @@
mutex_lock(&pmon->lock);
- if (iommu_pm_is_hw_access_OK(pmon)) {
+ if (iommu->hw_ops->is_hw_access_OK(pmon)) {
iommu->ops->iommu_lock_acquire();
- counter->value = iommu_pm_read_counter(counter);
+ counter->value = iommu->hw_ops->read_counter(counter);
iommu->ops->iommu_lock_release();
}
full_count = (unsigned long long) counter->value +
@@ -631,9 +428,9 @@
buf[wr_cnt-1] = '\0';
rv = kstrtoul(buf, 10, &cmd);
if (!rv && (cmd == 1)) {
- if (iommu_pm_is_hw_access_OK(pmon)) {
+ if (iommu->hw_ops->is_hw_access_OK(pmon)) {
iommu->ops->iommu_lock_acquire();
- iommu_pm_reset_counters(&pmon->iommu);
+ iommu->hw_ops->reset_counters(&pmon->iommu);
iommu->ops->iommu_lock_release();
}
iommu_pm_reset_counts(pmon);
@@ -761,7 +558,8 @@
(*abs_counter_no)++;
cnt_grp->counters[j].value = 0;
cnt_grp->counters[j].overflow_count = 0;
- cnt_grp->counters[j].current_event_class = NO_EVENT_CLASS;
+ cnt_grp->counters[j].current_event_class =
+ MSM_IOMMU_PMU_NO_EVENT_CLASS;
snprintf(name, 20, "counter%u", j);
@@ -894,11 +692,13 @@
if (ret)
goto free_mem;
+ iommu->hw_ops->initialize_hw(pmon_entry);
+
if (iommu->evt_irq > 0) {
ret = request_threaded_irq(iommu->evt_irq, NULL,
- iommu_pm_evt_ovfl_int_handler,
+ iommu->hw_ops->evt_ovfl_int_handler,
IRQF_ONESHOT | IRQF_SHARED,
- "msm_iommu_nonsecure_irq", pmon_entry);
+ "msm_iommu_pmon_nonsecure_irq", pmon_entry);
if (ret) {
pr_err("Request IRQ %d failed with ret=%d\n",
iommu->evt_irq,
diff --git a/drivers/leds/leds-qpnp.c b/drivers/leds/leds-qpnp.c
index bea6842..fb1882c 100644
--- a/drivers/leds/leds-qpnp.c
+++ b/drivers/leds/leds-qpnp.c
@@ -27,6 +27,7 @@
#define WLED_MOD_EN_REG(base, n) (base + 0x60 + n*0x10)
#define WLED_IDAC_DLY_REG(base, n) (WLED_MOD_EN_REG(base, n) + 0x01)
#define WLED_FULL_SCALE_REG(base, n) (WLED_IDAC_DLY_REG(base, n) + 0x01)
+#define WLED_MOD_SRC_SEL_REG(base, n) (WLED_FULL_SCALE_REG(base, n) + 0x01)
/* wled control registers */
#define WLED_BRIGHTNESS_CNTL_LSB(base, n) (base + 0x40 + 2*n)
@@ -83,7 +84,7 @@
#define FLASH_LED_1_CURR(base) (base + 0x43)
#define FLASH_CLAMP_CURR(base) (base + 0x44)
#define FLASH_LED_TMR_CTRL(base) (base + 0x48)
-#define FLASH_HEADROOM(base) (base + 0x49)
+#define FLASH_HEADROOM(base) (base + 0x4A)
#define FLASH_STARTUP_DELAY(base) (base + 0x4B)
#define FLASH_MASK_ENABLE(base) (base + 0x4C)
#define FLASH_VREG_OK_FORCE(base) (base + 0x4F)
@@ -111,7 +112,7 @@
#define FLASH_ENABLE_MODULE 0x80
#define FLASH_ENABLE_MODULE_MASK 0x80
#define FLASH_DISABLE_ALL 0x00
-#define FLASH_ENABLE_MASK 0x60
+#define FLASH_ENABLE_MASK 0xE0
#define FLASH_ENABLE_LED_0 0x40
#define FLASH_ENABLE_LED_1 0x20
#define FLASH_INIT_MASK 0xE0
@@ -454,6 +455,14 @@
/* Set led current */
if (val > 0) {
+ rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
+ FLASH_ENABLE_MODULE_MASK, FLASH_ENABLE_MODULE);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Enable reg write failed(%d)\n", rc);
+ return rc;
+ }
+
rc = qpnp_led_masked_write(led, led->flash_cfg->current_addr,
FLASH_CURRENT_MASK, led->flash_cfg->current_prgm);
if (rc) {
@@ -487,6 +496,13 @@
"LED %d flash write failed(%d)\n", led->id, rc);
return rc;
}
+ rc = qpnp_led_masked_write(led, FLASH_VREG_OK_FORCE(led->base),
+ FLASH_VREG_MASK, FLASH_HW_VREG_OK);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Vreg OK reg write failed(%d)\n", rc);
+ return rc;
+ }
} else {
rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
FLASH_ENABLE_MASK,
@@ -755,7 +771,7 @@
if (led->wled_cfg->dig_mod_gen_en) {
rc = qpnp_led_masked_write(led,
- WLED_MOD_EN_REG(led->base, i),
+ WLED_MOD_SRC_SEL_REG(led->base, i),
WLED_NO_MASK, WLED_USE_EXT_GEN_MOD_SRC);
if (rc) {
dev_err(&led->spmi_dev->dev,
@@ -883,7 +899,7 @@
}
rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
- FLASH_ENABLE_MODULE_MASK, FLASH_ENABLE_MODULE);
+ FLASH_ENABLE_MODULE_MASK, FLASH_DISABLE_ALL);
if (rc) {
dev_err(&led->spmi_dev->dev,
"Enable reg write failed(%d)\n", rc);
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
index d412435..d714ffb 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
@@ -54,27 +54,34 @@
DISABLE_CAMIF_IMMEDIATELY
};
+struct msm_isp_timestamp {
+ /*Monotonic clock for v4l2 buffer*/
+ struct timeval buf_time;
+ /*Wall clock for userspace event*/
+ struct timeval event_time;
+};
+
struct msm_vfe_irq_ops {
void (*read_irq_status) (struct vfe_device *vfe_dev,
uint32_t *irq_status0, uint32_t *irq_status1);
void (*process_reg_update) (struct vfe_device *vfe_dev,
uint32_t irq_status0, uint32_t irq_status1,
- struct timeval *tv);
+ struct msm_isp_timestamp *ts);
void (*process_reset_irq) (struct vfe_device *vfe_dev,
uint32_t irq_status0, uint32_t irq_status1);
void (*process_halt_irq) (struct vfe_device *vfe_dev,
uint32_t irq_status0, uint32_t irq_status1);
void (*process_camif_irq) (struct vfe_device *vfe_dev,
uint32_t irq_status0, uint32_t irq_status1,
- struct timeval *tv);
+ struct msm_isp_timestamp *ts);
void (*process_axi_irq) (struct vfe_device *vfe_dev,
uint32_t irq_status0, uint32_t irq_status1,
- struct timeval *tv);
+ struct msm_isp_timestamp *ts);
void (*process_error_irq) (struct vfe_device *vfe_dev,
uint32_t irq_status0, uint32_t irq_status1);
void (*process_stats_irq) (struct vfe_device *vfe_dev,
uint32_t irq_status0, uint32_t irq_status1,
- struct timeval *tv);
+ struct msm_isp_timestamp *ts);
};
struct msm_vfe_axi_ops {
@@ -109,10 +116,6 @@
void (*clear_wm_xbar_reg) (struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx);
- void (*cfg_rdi_reg) (struct vfe_device *vfe_dev,
- struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd,
- uint8_t plane_idx);
-
void (*cfg_ub) (struct vfe_device *vfe_dev);
void (*update_ping_pong_addr) (struct vfe_device *vfe_dev,
@@ -125,7 +128,7 @@
};
struct msm_vfe_core_ops {
- void (*reg_update) (struct vfe_device *vfe_dev, uint32_t update_mask);
+ void (*reg_update) (struct vfe_device *vfe_dev);
long (*reset_hw) (struct vfe_device *vfe_dev);
int (*init_hw) (struct vfe_device *vfe_dev);
void (*init_hw_reg) (struct vfe_device *vfe_dev);
@@ -134,6 +137,9 @@
struct msm_vfe_pix_cfg *pix_cfg);
void (*update_camif_state) (struct vfe_device *vfe_dev,
enum msm_isp_camif_update_state update_state);
+ void (*cfg_rdi_reg) (struct vfe_device *vfe_dev,
+ struct msm_vfe_rdi_cfg *rdi_cfg,
+ enum msm_vfe_input_src input_src);
int (*get_platform_data) (struct vfe_device *vfe_dev);
void (*get_error_mask) (uint32_t *error_mask0, uint32_t *error_mask1);
void (*process_error_status) (struct vfe_device *vfe_dev);
@@ -224,8 +230,6 @@
enum msm_vfe_axi_stream_src stream_src;
uint8_t num_planes;
uint8_t wm[MAX_PLANES_PER_STREAM];
- uint8_t rdi[MAX_PLANES_PER_STREAM];
- uint8_t rdi_master[MAX_PLANES_PER_STREAM];
uint8_t comp_mask_index;
struct msm_isp_buffer *buf[2];
uint32_t session_id;
@@ -235,13 +239,18 @@
uint8_t buf_divert;
enum msm_vfe_axi_stream_type stream_type;
+ uint32_t frame_based;
uint32_t framedrop_period;
uint32_t framedrop_pattern;
+ uint32_t num_burst_capture;/*number of frame to capture*/
uint32_t init_frame_drop;
uint32_t burst_frame_count;/*number of sof before burst stop*/
- uint32_t num_burst_capture;/*number of frame to capture*/
- uint8_t auto_trigger_stop;
uint8_t framedrop_update;
+
+ /*Run time update variables*/
+ uint32_t runtime_init_frame_drop;
+ uint32_t runtime_burst_frame_count;/*number of sof before burst stop*/
+ uint8_t runtime_framedrop_update;
};
struct msm_vfe_axi_composite_info {
@@ -270,9 +279,6 @@
uint32_t wm_image_size[MAX_NUM_WM];
enum msm_wm_ub_cfg_type wm_ub_cfg_policy;
uint8_t num_used_wm;
- uint8_t free_rdi[MAX_NUM_RDI];
- uint8_t free_rdi_master[MAX_NUM_RDI][MAX_NUM_RDI_MASTER];
- uint8_t num_used_rdi;
uint8_t num_active_stream;
struct msm_vfe_axi_composite_info
composite_info[MAX_NUM_COMPOSITE_MASK];
@@ -325,7 +331,7 @@
struct list_head list;
uint32_t vfeInterruptStatus0;
uint32_t vfeInterruptStatus1;
- struct timeval tv;
+ struct msm_isp_timestamp ts;
uint8_t cmd_used;
};
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
index 750963c..8f00e80 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
@@ -24,10 +24,7 @@
#define VFE32_BURST_LEN 4
#define VFE32_EQUAL_SLICE_UB 117
#define VFE32_WM_BASE(idx) (0x4C + 0x18 * idx)
-#define VFE32_RDI_BASE(idx) (0x734 + 0x4 * idx)
-#define VFE32_RDI_MN_BASE(m) (0x734 + 0x4 * m/3)
-#define VFE32_RDI_MN_SEL_SHIFT(m) (4*(m%3) + 4)
-#define VFE32_RDI_MN_FB_SHIFT(m) ((m%3) + 16)
+#define VFE32_RDI_BASE(idx) (idx ? 0x734 + 0x4 * (idx - 1) : 0x06FC)
#define VFE32_XBAR_BASE(idx) (0x40 + 0x4 * (idx / 4))
#define VFE32_XBAR_SHIFT(idx) ((idx % 4) * 8)
#define VFE32_PING_PONG_BASE(wm, ping_pong) \
@@ -170,7 +167,8 @@
}
static void msm_vfe32_process_camif_irq(struct vfe_device *vfe_dev,
- uint32_t irq_status0, uint32_t irq_status1, struct timeval *tv)
+ uint32_t irq_status0, uint32_t irq_status1,
+ struct msm_isp_timestamp *ts)
{
if (!(irq_status0 & 0x1F))
return;
@@ -178,12 +176,13 @@
if (irq_status0 & BIT(0)) {
ISP_DBG("%s: PIX0 frame id: %lu\n", __func__,
vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id);
- msm_isp_sof_notify(vfe_dev, VFE_PIX_0, tv);
+ msm_isp_sof_notify(vfe_dev, VFE_PIX_0, ts);
}
}
static void msm_vfe32_process_stats_irq(struct vfe_device *vfe_dev,
- uint32_t irq_status0, uint32_t irq_status1, struct timeval *tv)
+ uint32_t irq_status0, uint32_t irq_status1,
+ struct msm_isp_timestamp *ts)
{
/* todo: add stats specific code */
return;
@@ -321,7 +320,8 @@
}
static void msm_vfe32_process_reg_update(struct vfe_device *vfe_dev,
- uint32_t irq_status0, uint32_t irq_status1, struct timeval *tv)
+ uint32_t irq_status0, uint32_t irq_status1,
+ struct msm_isp_timestamp *ts)
{
if (!(irq_status0 & 0x20) && !(irq_status1 & 0x1C000000))
return;
@@ -336,9 +336,9 @@
}
static void msm_vfe32_reg_update(
- struct vfe_device *vfe_dev, uint32_t update_mask)
+ struct vfe_device *vfe_dev)
{
- msm_camera_io_w_mb(update_mask, vfe_dev->vfe_base + 0x260);
+ msm_camera_io_w_mb(0xF, vfe_dev->vfe_base + 0x260);
}
static long msm_vfe32_reset_hardware(struct vfe_device *vfe_dev)
@@ -358,12 +358,14 @@
static void msm_vfe32_axi_enable_wm(struct vfe_device *vfe_dev,
uint8_t wm_idx, uint8_t enable)
{
+ uint32_t val = msm_camera_io_r(
+ vfe_dev->vfe_base + VFE32_WM_BASE(wm_idx));
if (enable)
- msm_camera_io_w_mb(0x1,
- vfe_dev->vfe_base + VFE32_WM_BASE(wm_idx));
+ val |= 0x1;
else
- msm_camera_io_w_mb(0x0,
- vfe_dev->vfe_base + VFE32_WM_BASE(wm_idx));
+ val &= ~0x1;
+ msm_camera_io_w_mb(val,
+ vfe_dev->vfe_base + VFE32_WM_BASE(wm_idx));
}
static void msm_vfe32_axi_cfg_comp_mask(struct vfe_device *vfe_dev,
@@ -423,13 +425,13 @@
{
uint32_t framedrop_pattern = 0, framedrop_period = 0;
- if (stream_info->init_frame_drop == 0) {
+ if (stream_info->runtime_init_frame_drop == 0) {
framedrop_pattern = stream_info->framedrop_pattern;
framedrop_period = stream_info->framedrop_period;
}
if (stream_info->stream_type == BURST_STREAM &&
- stream_info->burst_frame_count == 0) {
+ stream_info->runtime_burst_frame_count == 0) {
framedrop_pattern = 0;
framedrop_period = 0;
}
@@ -519,6 +521,27 @@
}
}
+static void msm_vfe32_cfg_rdi_reg(struct vfe_device *vfe_dev,
+ struct msm_vfe_rdi_cfg *rdi_cfg, enum msm_vfe_input_src input_src)
+{
+ uint8_t rdi = input_src - VFE_RAW_0;
+ uint32_t rdi_reg_cfg;
+ rdi_reg_cfg = msm_camera_io_r(
+ vfe_dev->vfe_base + VFE32_RDI_BASE(0));
+ rdi_reg_cfg &= ~(BIT(16 + rdi));
+ rdi_reg_cfg |= rdi_cfg->frame_based << (16 + rdi);
+ msm_camera_io_w(rdi_reg_cfg,
+ vfe_dev->vfe_base + VFE32_RDI_BASE(0));
+
+ rdi_reg_cfg = msm_camera_io_r(
+ vfe_dev->vfe_base + VFE32_RDI_BASE(rdi));
+ rdi_reg_cfg &= 0x70003;
+ rdi_reg_cfg |= (rdi * 3) << 28 | rdi_cfg->cid << 4 | 0x4;
+ msm_camera_io_w(
+ rdi_reg_cfg, vfe_dev->vfe_base + VFE32_RDI_BASE(rdi));
+
+}
+
static void msm_vfe32_axi_cfg_wm_reg(
struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd,
@@ -531,22 +554,37 @@
(stream_cfg_cmd->axi_stream_handle & 0xFF)];
uint32_t wm_base = VFE32_WM_BASE(stream_info->wm[plane_idx]);
- /*WR_IMAGE_SIZE*/
- val =
- ((msm_isp_cal_word_per_line(stream_cfg_cmd->output_format,
- stream_cfg_cmd->plane_cfg[
- plane_idx].output_width)+1)/2 - 1) << 16 |
- (stream_cfg_cmd->plane_cfg[plane_idx].output_height - 1);
- msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x10);
+ if (!stream_info->frame_based) {
+ /*WR_IMAGE_SIZE*/
+ val =
+ ((msm_isp_cal_word_per_line(
+ stream_cfg_cmd->output_format,
+ stream_cfg_cmd->plane_cfg[plane_idx].
+ output_width)+1)/2 - 1) << 16 |
+ (stream_cfg_cmd->plane_cfg[plane_idx].
+ output_height - 1);
+ msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x10);
- /*WR_BUFFER_CFG*/
- val =
- msm_isp_cal_word_per_line(stream_cfg_cmd->output_format,
- stream_cfg_cmd->plane_cfg[plane_idx].output_stride) << 16 |
- (stream_cfg_cmd->plane_cfg[
- plane_idx].output_scan_lines - 1) << 4 |
- VFE32_BURST_LEN >> 2;
- msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14);
+ /*WR_BUFFER_CFG*/
+ val =
+ msm_isp_cal_word_per_line(
+ stream_cfg_cmd->output_format,
+ stream_cfg_cmd->plane_cfg[plane_idx].
+ output_stride) << 16 |
+ (stream_cfg_cmd->plane_cfg[plane_idx].
+ output_height - 1) << 4 | VFE32_BURST_LEN >> 2;
+ msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14);
+ } else {
+ msm_camera_io_w(0x2, vfe_dev->vfe_base + wm_base);
+ val =
+ msm_isp_cal_word_per_line(
+ stream_cfg_cmd->output_format,
+ stream_cfg_cmd->plane_cfg[plane_idx].
+ output_width) << 16 |
+ (stream_cfg_cmd->plane_cfg[plane_idx].
+ output_height - 1) << 4 | VFE32_BURST_LEN >> 2;
+ msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14);
+ }
return;
}
@@ -563,36 +601,6 @@
return;
}
-static void msm_vfe32_axi_cfg_rdi_reg(
- struct vfe_device *vfe_dev,
- struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd,
- uint8_t plane_idx)
-{
- struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
- struct msm_vfe_axi_stream *stream_info =
- &axi_data->stream_info[(stream_cfg_cmd->axi_stream_handle & 0xFF)];
- struct msm_vfe_axi_plane_cfg *plane_cfg =
- &stream_cfg_cmd->plane_cfg[plane_idx];
- uint8_t rdi = stream_info->rdi[plane_idx];
- uint8_t rdi_master = stream_info->rdi_master[plane_idx];
- uint32_t rdi_reg_cfg;
-
- rdi_reg_cfg = msm_camera_io_r(vfe_dev->vfe_base + VFE32_RDI_BASE(rdi));
- rdi_reg_cfg = (rdi_reg_cfg & 0xFFFFFFF) | rdi_master << 28;
- msm_camera_io_w(rdi_reg_cfg, vfe_dev->vfe_base + VFE32_RDI_BASE(rdi));
-
- rdi_reg_cfg = msm_camera_io_r(
- vfe_dev->vfe_base + VFE32_RDI_MN_BASE(rdi_master));
- rdi_reg_cfg &= ~((0xF << VFE32_RDI_MN_SEL_SHIFT(rdi_master)) |
- BIT(VFE32_RDI_MN_FB_SHIFT(rdi_master)));
- rdi_reg_cfg |= (plane_cfg->rdi_cid <<
- VFE32_RDI_MN_SEL_SHIFT(rdi_master) |
- (stream_cfg_cmd->frame_base <<
- VFE32_RDI_MN_FB_SHIFT(rdi_master)));
- msm_camera_io_w(rdi_reg_cfg, vfe_dev->vfe_base +
- VFE32_RDI_MN_BASE(rdi_master));
-}
-
static void msm_vfe32_axi_cfg_wm_xbar_reg(
struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd,
@@ -633,13 +641,14 @@
case IDEAL_RAW:
xbar_cfg = 0x80;
break;
- case RDI:
- if (stream_info->rdi[plane_idx] == 0)
- xbar_cfg = 0xA0;
- else if (stream_info->rdi[plane_idx] == 1)
- xbar_cfg = 0xC0;
- else if (stream_info->rdi[plane_idx] == 2)
- xbar_cfg = 0xE0;
+ case RDI_INTF_0:
+ xbar_cfg = 0xA0;
+ break;
+ case RDI_INTF_1:
+ xbar_cfg = 0xC0;
+ break;
+ case RDI_INTF_2:
+ xbar_cfg = 0xE0;
break;
default:
pr_err("%s: Invalid stream src\n", __func__);
@@ -881,7 +890,6 @@
.clear_wm_reg = msm_vfe32_axi_clear_wm_reg,
.cfg_wm_xbar_reg = msm_vfe32_axi_cfg_wm_xbar_reg,
.clear_wm_xbar_reg = msm_vfe32_axi_clear_wm_xbar_reg,
- .cfg_rdi_reg = msm_vfe32_axi_cfg_rdi_reg,
.cfg_ub = msm_vfe32_cfg_axi_ub,
.update_ping_pong_addr =
msm_vfe32_update_ping_pong_addr,
@@ -894,6 +902,7 @@
.reg_update = msm_vfe32_reg_update,
.cfg_camif = msm_vfe32_cfg_camif,
.update_camif_state = msm_vfe32_update_camif_state,
+ .cfg_rdi_reg = msm_vfe32_cfg_rdi_reg,
.reset_hw = msm_vfe32_reset_hardware,
.init_hw = msm_vfe32_init_hardware,
.init_hw_reg = msm_vfe32_init_hardware_reg,
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
index ed4aa7f..1d931df 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
@@ -30,13 +30,11 @@
#endif
#define VFE40_BURST_LEN 3
+#define VFE40_STATS_BURST_LEN 2
#define VFE40_UB_SIZE 1536
-#define VFE40_EQUAL_SLICE_UB 304
+#define VFE40_EQUAL_SLICE_UB 286
#define VFE40_WM_BASE(idx) (0x6C + 0x24 * idx)
#define VFE40_RDI_BASE(idx) (0x2E8 + 0x4 * idx)
-#define VFE40_RDI_MN_BASE(m) (0x2E8 + 0x4 * m/3)
-#define VFE40_RDI_MN_SEL_SHIFT(m) (4*(m%3) + 4)
-#define VFE40_RDI_MN_FB_SHIFT(m) ((m%3) + 16)
#define VFE40_XBAR_BASE(idx) (0x58 + 0x4 * (idx / 2))
#define VFE40_XBAR_SHIFT(idx) ((idx%2) ? 16 : 0)
#define VFE40_PING_PONG_BASE(wm, ping_pong) \
@@ -284,7 +282,8 @@
}
static void msm_vfe40_process_camif_irq(struct vfe_device *vfe_dev,
- uint32_t irq_status0, uint32_t irq_status1, struct timeval *tv)
+ uint32_t irq_status0, uint32_t irq_status1,
+ struct msm_isp_timestamp *ts)
{
if (!(irq_status0 & 0xF))
return;
@@ -294,7 +293,7 @@
if (vfe_dev->axi_data.src_info[VFE_PIX_0].raw_stream_count > 0
&& vfe_dev->axi_data.src_info[VFE_PIX_0].
pix_stream_count == 0) {
- msm_isp_sof_notify(vfe_dev, VFE_PIX_0, tv);
+ msm_isp_sof_notify(vfe_dev, VFE_PIX_0, ts);
msm_isp_update_framedrop_reg(vfe_dev);
}
}
@@ -445,35 +444,33 @@
}
static void msm_vfe40_process_reg_update(struct vfe_device *vfe_dev,
- uint32_t irq_status0, uint32_t irq_status1, struct timeval *tv)
+ uint32_t irq_status0, uint32_t irq_status1,
+ struct msm_isp_timestamp *ts)
{
- uint32_t update_mask = 0xF;
if (!(irq_status0 & 0xF0))
return;
if (irq_status0 & BIT(4))
- msm_isp_sof_notify(vfe_dev, VFE_PIX_0, tv);
+ msm_isp_sof_notify(vfe_dev, VFE_PIX_0, ts);
if (irq_status0 & BIT(5))
- msm_isp_sof_notify(vfe_dev, VFE_RAW_0, tv);
+ msm_isp_sof_notify(vfe_dev, VFE_RAW_0, ts);
if (irq_status0 & BIT(6))
- msm_isp_sof_notify(vfe_dev, VFE_RAW_1, tv);
+ msm_isp_sof_notify(vfe_dev, VFE_RAW_1, ts);
if (irq_status0 & BIT(7))
- msm_isp_sof_notify(vfe_dev, VFE_RAW_2, tv);
+ msm_isp_sof_notify(vfe_dev, VFE_RAW_2, ts);
if (vfe_dev->axi_data.stream_update)
msm_isp_axi_stream_update(vfe_dev);
msm_isp_update_framedrop_reg(vfe_dev);
msm_isp_update_error_frame_count(vfe_dev);
- vfe_dev->hw_info->vfe_ops.core_ops.
- reg_update(vfe_dev, update_mask);
+ vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev);
return;
}
-static void msm_vfe40_reg_update(
- struct vfe_device *vfe_dev, uint32_t update_mask)
+static void msm_vfe40_reg_update(struct vfe_device *vfe_dev)
{
- msm_camera_io_w_mb(update_mask, vfe_dev->vfe_base + 0x378);
+ msm_camera_io_w_mb(0xF, vfe_dev->vfe_base + 0x378);
}
static long msm_vfe40_reset_hardware(struct vfe_device *vfe_dev)
@@ -493,12 +490,14 @@
static void msm_vfe40_axi_enable_wm(struct vfe_device *vfe_dev,
uint8_t wm_idx, uint8_t enable)
{
+ uint32_t val;
+ val = msm_camera_io_r(vfe_dev->vfe_base + VFE40_WM_BASE(wm_idx));
if (enable)
- msm_camera_io_w_mb(0x1,
- vfe_dev->vfe_base + VFE40_WM_BASE(wm_idx));
+ val |= 0x1;
else
- msm_camera_io_w_mb(0x0,
- vfe_dev->vfe_base + VFE40_WM_BASE(wm_idx));
+ val &= ~0x1;
+ msm_camera_io_w_mb(val,
+ vfe_dev->vfe_base + VFE40_WM_BASE(wm_idx));
}
static void msm_vfe40_axi_cfg_comp_mask(struct vfe_device *vfe_dev,
@@ -559,13 +558,13 @@
uint32_t i, temp;
uint32_t framedrop_pattern = 0, framedrop_period = 0;
- if (stream_info->init_frame_drop == 0) {
+ if (stream_info->runtime_init_frame_drop == 0) {
framedrop_pattern = stream_info->framedrop_pattern;
framedrop_period = stream_info->framedrop_period;
}
if (stream_info->stream_type == BURST_STREAM &&
- stream_info->burst_frame_count == 0) {
+ stream_info->runtime_burst_frame_count == 0) {
framedrop_pattern = 0;
framedrop_period = 0;
}
@@ -622,7 +621,9 @@
break;
case PIX_ENCODER:
case PIX_VIEWFINDER:
- case RDI:
+ case RDI_INTF_0:
+ case RDI_INTF_1:
+ case RDI_INTF_2:
default:
pr_err("%s: Invalid stream source\n", __func__);
return;
@@ -707,6 +708,27 @@
}
}
+static void msm_vfe40_cfg_rdi_reg(
+ struct vfe_device *vfe_dev, struct msm_vfe_rdi_cfg *rdi_cfg,
+ enum msm_vfe_input_src input_src)
+{
+ uint8_t rdi = input_src - VFE_RAW_0;
+ uint32_t rdi_reg_cfg;
+ rdi_reg_cfg = msm_camera_io_r(
+ vfe_dev->vfe_base + VFE40_RDI_BASE(0));
+ rdi_reg_cfg &= ~(BIT(16 + rdi));
+ rdi_reg_cfg |= rdi_cfg->frame_based << (16 + rdi);
+ msm_camera_io_w(rdi_reg_cfg,
+ vfe_dev->vfe_base + VFE40_RDI_BASE(0));
+
+ rdi_reg_cfg = msm_camera_io_r(
+ vfe_dev->vfe_base + VFE40_RDI_BASE(rdi));
+ rdi_reg_cfg &= 0x70003;
+ rdi_reg_cfg |= (rdi * 3) << 28 | rdi_cfg->cid << 4 | 0x4;
+ msm_camera_io_w(
+ rdi_reg_cfg, vfe_dev->vfe_base + VFE40_RDI_BASE(rdi));
+}
+
static void msm_vfe40_axi_cfg_wm_reg(
struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd,
@@ -719,24 +741,37 @@
(stream_cfg_cmd->axi_stream_handle & 0xFF)];
uint32_t wm_base = VFE40_WM_BASE(stream_info->wm[plane_idx]);
- /*WR_IMAGE_SIZE*/
- val =
- ((msm_isp_cal_word_per_line(stream_cfg_cmd->output_format,
- stream_cfg_cmd->plane_cfg[plane_idx].
- output_width)+1)/2 - 1) << 16 |
- (stream_cfg_cmd->plane_cfg[plane_idx].
- output_height - 1);
- msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14);
+ if (!stream_info->frame_based) {
+ /*WR_IMAGE_SIZE*/
+ val =
+ ((msm_isp_cal_word_per_line(
+ stream_cfg_cmd->output_format,
+ stream_cfg_cmd->plane_cfg[plane_idx].
+ output_width)+1)/2 - 1) << 16 |
+ (stream_cfg_cmd->plane_cfg[plane_idx].
+ output_height - 1);
+ msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14);
- /*WR_BUFFER_CFG*/
- val =
- msm_isp_cal_word_per_line(stream_cfg_cmd->output_format,
- stream_cfg_cmd->plane_cfg[
- plane_idx].output_stride) << 16 |
- (stream_cfg_cmd->plane_cfg[
- plane_idx].output_height - 1) << 4 |
- VFE40_BURST_LEN;
- msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x18);
+ /*WR_BUFFER_CFG*/
+ val =
+ msm_isp_cal_word_per_line(stream_cfg_cmd->output_format,
+ stream_cfg_cmd->plane_cfg[
+ plane_idx].output_stride) << 16 |
+ (stream_cfg_cmd->plane_cfg[
+ plane_idx].output_height - 1) << 4 |
+ VFE40_BURST_LEN;
+ msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x18);
+ } else {
+ msm_camera_io_w(0x2, vfe_dev->vfe_base + wm_base);
+ val =
+ msm_isp_cal_word_per_line(stream_cfg_cmd->output_format,
+ stream_cfg_cmd->plane_cfg[
+ plane_idx].output_width) << 16 |
+ (stream_cfg_cmd->plane_cfg[
+ plane_idx].output_height - 1) << 4 |
+ VFE40_BURST_LEN;
+ msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x18);
+ }
/*WR_IRQ_SUBSAMPLE_PATTERN*/
msm_camera_io_w(0xFFFFFFFF,
@@ -762,40 +797,6 @@
return;
}
-static void msm_vfe40_axi_cfg_rdi_reg(
- struct vfe_device *vfe_dev,
- struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd,
- uint8_t plane_idx)
-{
- struct msm_vfe_axi_shared_data *axi_data =
- &vfe_dev->axi_data;
- struct msm_vfe_axi_stream *stream_info =
- &axi_data->stream_info[
- (stream_cfg_cmd->axi_stream_handle & 0xFF)];
- struct msm_vfe_axi_plane_cfg *plane_cfg =
- &stream_cfg_cmd->plane_cfg[plane_idx];
- uint8_t rdi = stream_info->rdi[plane_idx];
- uint8_t rdi_master = stream_info->rdi_master[plane_idx];
- uint32_t rdi_reg_cfg;
-
- rdi_reg_cfg = msm_camera_io_r(
- vfe_dev->vfe_base + VFE40_RDI_BASE(rdi));
- rdi_reg_cfg = (rdi_reg_cfg & 0xFFFFFFF) | rdi_master << 28;
- msm_camera_io_w(
- rdi_reg_cfg, vfe_dev->vfe_base + VFE40_RDI_BASE(rdi));
-
- rdi_reg_cfg = msm_camera_io_r(
- vfe_dev->vfe_base + VFE40_RDI_MN_BASE(rdi_master));
- rdi_reg_cfg &= ~((0xF << VFE40_RDI_MN_SEL_SHIFT(rdi_master)) |
- (0x1 << VFE40_RDI_MN_FB_SHIFT(rdi_master)));
- rdi_reg_cfg |=
- (plane_cfg->rdi_cid << VFE40_RDI_MN_SEL_SHIFT(rdi_master) |
- (stream_cfg_cmd->frame_base <<
- VFE40_RDI_MN_FB_SHIFT(rdi_master)));
- msm_camera_io_w(rdi_reg_cfg,
- vfe_dev->vfe_base + VFE40_RDI_MN_BASE(rdi_master));
-}
-
static void msm_vfe40_axi_cfg_wm_xbar_reg(
struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd,
@@ -837,13 +838,14 @@
case IDEAL_RAW:
xbar_cfg = 0x400;
break;
- case RDI:
- if (stream_info->rdi[plane_idx] == 0)
- xbar_cfg = 0x500;
- else if (stream_info->rdi[plane_idx] == 1)
- xbar_cfg = 0x600;
- else if (stream_info->rdi[plane_idx] == 2)
- xbar_cfg = 0x700;
+ case RDI_INTF_0:
+ xbar_cfg = 0x500;
+ break;
+ case RDI_INTF_1:
+ xbar_cfg = 0x600;
+ break;
+ case RDI_INTF_2:
+ xbar_cfg = 0x700;
break;
default:
pr_err("%s: Invalid stream src\n", __func__);
@@ -1063,8 +1065,8 @@
uint32_t ub_offset = VFE40_UB_SIZE;
uint32_t ub_size[VFE40_NUM_STATS_TYPE] = {
64, /*MSM_ISP_STATS_BE*/
- 64, /*MSM_ISP_STATS_BG*/
- 64, /*MSM_ISP_STATS_BF*/
+ 128, /*MSM_ISP_STATS_BG*/
+ 128, /*MSM_ISP_STATS_BF*/
16, /*MSM_ISP_STATS_AWB*/
8, /*MSM_ISP_STATS_RS*/
16, /*MSM_ISP_STATS_CS*/
@@ -1074,7 +1076,7 @@
for (i = 0; i < VFE40_NUM_STATS_TYPE; i++) {
ub_offset -= ub_size[i];
- msm_camera_io_w(VFE40_BURST_LEN << 30 |
+ msm_camera_io_w(VFE40_STATS_BURST_LEN << 30 |
ub_offset << 16 | (ub_size[i] - 1),
vfe_dev->vfe_base + VFE40_STATS_BASE(i) + 0xC);
}
@@ -1264,7 +1266,6 @@
.clear_wm_reg = msm_vfe40_axi_clear_wm_reg,
.cfg_wm_xbar_reg = msm_vfe40_axi_cfg_wm_xbar_reg,
.clear_wm_xbar_reg = msm_vfe40_axi_clear_wm_xbar_reg,
- .cfg_rdi_reg = msm_vfe40_axi_cfg_rdi_reg,
.cfg_ub = msm_vfe40_cfg_axi_ub,
.update_ping_pong_addr =
msm_vfe40_update_ping_pong_addr,
@@ -1277,6 +1278,7 @@
.reg_update = msm_vfe40_reg_update,
.cfg_camif = msm_vfe40_cfg_camif,
.update_camif_state = msm_vfe40_update_camif_state,
+ .cfg_rdi_reg = msm_vfe40_cfg_rdi_reg,
.reset_hw = msm_vfe40_reset_hardware,
.init_hw = msm_vfe40_init_hardware,
.init_hw_reg = msm_vfe40_init_hardware_reg,
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
index ac3ce0a..fa0bf18 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
@@ -14,6 +14,10 @@
#include "msm_isp_util.h"
#include "msm_isp_axi_util.h"
+#define SRC_TO_INTF(src) \
+ ((src < RDI_INTF_0) ? VFE_PIX_0 : \
+ (VFE_RAW_0 + src - RDI_INTF_0))
+
int msm_isp_axi_create_stream(
struct msm_vfe_axi_shared_data *axi_data,
struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd)
@@ -78,6 +82,18 @@
case V4L2_PIX_FMT_SGBRG12:
case V4L2_PIX_FMT_SGRBG12:
case V4L2_PIX_FMT_SRGGB12:
+ case V4L2_PIX_FMT_QBGGR8:
+ case V4L2_PIX_FMT_QGBRG8:
+ case V4L2_PIX_FMT_QGRBG8:
+ case V4L2_PIX_FMT_QRGGB8:
+ case V4L2_PIX_FMT_QBGGR10:
+ case V4L2_PIX_FMT_QGBRG10:
+ case V4L2_PIX_FMT_QGRBG10:
+ case V4L2_PIX_FMT_QRGGB10:
+ case V4L2_PIX_FMT_QBGGR12:
+ case V4L2_PIX_FMT_QGBRG12:
+ case V4L2_PIX_FMT_QGRBG12:
+ case V4L2_PIX_FMT_QRGGB12:
stream_info->num_planes = 1;
break;
case V4L2_PIX_FMT_NV12:
@@ -103,14 +119,6 @@
return rc;
}
- if (stream_cfg_cmd->stream_src == RDI) {
- if (axi_data->hw_info->num_rdi -
- axi_data->num_used_rdi < stream_info->num_planes) {
- pr_err("%s: No free RDI\n", __func__);
- return rc;
- }
- }
-
if (stream_cfg_cmd->init_frame_drop >= MAX_INIT_FRAME_DROP) {
pr_err("%s: Invalid skip pattern\n", __func__);
return rc;
@@ -122,6 +130,7 @@
}
stream_info->stream_src = stream_cfg_cmd->stream_src;
+ stream_info->frame_based = stream_cfg_cmd->frame_base;
return 0;
}
@@ -135,6 +144,10 @@
case V4L2_PIX_FMT_SGBRG8:
case V4L2_PIX_FMT_SGRBG8:
case V4L2_PIX_FMT_SRGGB8:
+ case V4L2_PIX_FMT_QBGGR8:
+ case V4L2_PIX_FMT_QGBRG8:
+ case V4L2_PIX_FMT_QGRBG8:
+ case V4L2_PIX_FMT_QRGGB8:
size = plane_cfg[plane_idx].output_height *
plane_cfg[plane_idx].output_width;
break;
@@ -142,6 +155,10 @@
case V4L2_PIX_FMT_SGBRG10:
case V4L2_PIX_FMT_SGRBG10:
case V4L2_PIX_FMT_SRGGB10:
+ case V4L2_PIX_FMT_QBGGR10:
+ case V4L2_PIX_FMT_QGBRG10:
+ case V4L2_PIX_FMT_QGRBG10:
+ case V4L2_PIX_FMT_QRGGB10:
/* TODO: fix me */
size = plane_cfg[plane_idx].output_height *
plane_cfg[plane_idx].output_width;
@@ -150,6 +167,10 @@
case V4L2_PIX_FMT_SGBRG12:
case V4L2_PIX_FMT_SGRBG12:
case V4L2_PIX_FMT_SRGGB12:
+ case V4L2_PIX_FMT_QBGGR12:
+ case V4L2_PIX_FMT_QGBRG12:
+ case V4L2_PIX_FMT_QGRBG12:
+ case V4L2_PIX_FMT_QRGGB12:
/* TODO: fix me */
size = plane_cfg[plane_idx].output_height *
plane_cfg[plane_idx].output_width;
@@ -205,38 +226,6 @@
}
}
-void msm_isp_axi_reserve_rdi(struct msm_vfe_axi_shared_data *axi_data,
- struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd)
-{
- int i, j;
- struct msm_vfe_axi_stream *stream_info =
- &axi_data->stream_info[(stream_cfg_cmd->axi_stream_handle & 0xFF)];
-
- for (i = 0; i < stream_info->num_planes; i++) {
- uint8_t csid = stream_cfg_cmd->plane_cfg[i].csid_src;
-
- for (j = 0; j < axi_data->hw_info->num_rdi; j++) {
- if (!axi_data->free_rdi[j]) {
- axi_data->free_rdi[j] = 1;
- axi_data->num_used_rdi++;
- break;
- }
- }
- stream_info->rdi[i] = j;
-
- for (j = 0; j < axi_data->hw_info->num_rdi; j++) {
- if (!axi_data->free_rdi_master[csid][j]) {
- axi_data->free_rdi_master[csid][j] = 1;
- axi_data->num_used_rdi++;
- break;
- }
- }
- stream_info->rdi_master[i] =
- csid * axi_data->hw_info->num_rdi_master + j;
- }
- return;
-}
-
void msm_isp_axi_reserve_comp_mask(
struct msm_vfe_axi_shared_data *axi_data,
struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd)
@@ -277,8 +266,7 @@
struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd)
{
- int rc = 0, i, j;
- uint8_t src_state;
+ int rc = 0, i;
struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
struct msm_vfe_axi_stream *stream_info;
enum msm_vfe_axi_state valid_state =
@@ -292,24 +280,6 @@
rc = -EINVAL;
break;
}
- /*
- * For RDI stream, if multiple RDIs are used
- * check if all the RDI srcs are in the same state, on/off
- */
- if (stream_info->stream_src == RDI) {
- src_state = axi_data->src_info[
- stream_info->rdi[0]+1].active;
- for (j = 0; j < stream_info->num_planes; j++) {
- if (src_state !=
- axi_data->src_info[
- stream_info->rdi[j]+1].active) {
- pr_err("%s: RDI stream has inconsistent state\n",
- __func__);
- rc = -EINVAL;
- break;
- }
- }
- }
if (stream_cfg_cmd->cmd == START_STREAM) {
stream_info->bufq_handle =
@@ -334,74 +304,46 @@
struct msm_vfe_axi_stream *stream_info;
for (i = 0; i < MAX_NUM_STREAM; i++) {
stream_info = &axi_data->stream_info[i];
- if (stream_info->framedrop_update) {
- if (stream_info->init_frame_drop == 0) {
- stream_info->framedrop_update = 0;
+ if (stream_info->state != ACTIVE)
+ continue;
+
+ if (stream_info->runtime_framedrop_update) {
+ stream_info->runtime_init_frame_drop--;
+ if (stream_info->runtime_init_frame_drop == 0) {
+ stream_info->runtime_framedrop_update = 0;
vfe_dev->hw_info->vfe_ops.axi_ops.
cfg_framedrop(vfe_dev, stream_info);
}
}
if (stream_info->stream_type == BURST_STREAM) {
- if (stream_info->burst_frame_count == 0 &&
- stream_info->state == ACTIVE) {
+ stream_info->runtime_burst_frame_count--;
+ if (stream_info->runtime_burst_frame_count == 0) {
vfe_dev->hw_info->vfe_ops.axi_ops.
cfg_framedrop(vfe_dev, stream_info);
- if (stream_info->stream_src == RDI) {
- uint32_t wm_reload_mask = 0,
- reg_update_mask = 0;
- stream_info->state = STOP_PENDING;
- msm_isp_axi_stream_enable_cfg(
- vfe_dev, stream_info,
- &wm_reload_mask,
- ®_update_mask);
- }
+ vfe_dev->hw_info->vfe_ops.core_ops.
+ reg_update(vfe_dev);
}
}
}
}
-void msm_isp_update_framedrop_count(
- struct vfe_device *vfe_dev)
+static void msm_isp_reset_framedrop(struct vfe_device *vfe_dev,
+ struct msm_vfe_axi_stream *stream_info)
{
- int i;
- struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
- struct msm_vfe_axi_stream *stream_info;
- for (i = 0; i < MAX_NUM_STREAM; i++) {
- stream_info = &axi_data->stream_info[i];
- if (stream_info->framedrop_update) {
- stream_info->init_frame_drop--;
- if (stream_info->init_frame_drop == 1) {
- vfe_dev->hw_info->vfe_ops.core_ops.
- reg_update(vfe_dev, 0xF);
- }
- }
- if (stream_info->stream_type == BURST_STREAM) {
- stream_info->burst_frame_count--;
- if (stream_info->burst_frame_count == 1) {
- vfe_dev->hw_info->vfe_ops.core_ops.
- reg_update(vfe_dev, 0xF);
- } else if (stream_info->burst_frame_count == 0) {
- if (stream_info->stream_src != RDI) {
- vfe_dev->hw_info->vfe_ops.core_ops.
- update_camif_state(vfe_dev,
- DISABLE_CAMIF);
- pr_err("%s: pending burst_cnt = %d, disable camif\n",
- __func__,
- stream_info->burst_frame_count);
- }
- }
- }
- }
+ stream_info->runtime_init_frame_drop = stream_info->init_frame_drop;
+ stream_info->runtime_burst_frame_count =
+ stream_info->burst_frame_count;
+ stream_info->runtime_framedrop_update = stream_info->framedrop_update;
+ vfe_dev->hw_info->vfe_ops.axi_ops.cfg_framedrop(vfe_dev, stream_info);
}
void msm_isp_sof_notify(struct vfe_device *vfe_dev,
- enum msm_vfe_input_src frame_src, struct timeval *tv) {
+ enum msm_vfe_input_src frame_src, struct msm_isp_timestamp *ts) {
struct msm_isp_event_data sof_event;
switch (frame_src) {
case VFE_PIX_0:
ISP_DBG("%s: PIX0 frame id: %lu\n", __func__,
vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id);
- msm_isp_update_framedrop_count(vfe_dev);
vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id++;
if (vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id == 0)
vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id = 1;
@@ -409,6 +351,12 @@
case VFE_RAW_0:
case VFE_RAW_1:
case VFE_RAW_2:
+ ISP_DBG("%s: RDI%d frame id: %lu\n",
+ __func__, frame_src - VFE_RAW_0,
+ vfe_dev->axi_data.src_info[frame_src].frame_id);
+ vfe_dev->axi_data.src_info[frame_src].frame_id++;
+ if (vfe_dev->axi_data.src_info[frame_src].frame_id == 0)
+ vfe_dev->axi_data.src_info[frame_src].frame_id = 1;
break;
default:
pr_err("%s: invalid frame src %d received\n",
@@ -417,7 +365,7 @@
}
sof_event.frame_id = vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id;
- sof_event.timestamp = *tv;
+ sof_event.timestamp = ts->event_time;
msm_isp_send_event(vfe_dev, ISP_EVENT_SOF, &sof_event);
}
@@ -501,13 +449,10 @@
return rc;
}
- msm_isp_axi_reserve_wm(&vfe_dev->axi_data, stream_cfg_cmd);
- if (stream_cfg_cmd->stream_src == RDI)
- msm_isp_axi_reserve_rdi(&vfe_dev->axi_data, stream_cfg_cmd);
-
stream_info =
&vfe_dev->axi_data.
stream_info[(stream_cfg_cmd->axi_stream_handle & 0xFF)];
+ msm_isp_axi_reserve_wm(&vfe_dev->axi_data, stream_cfg_cmd);
if (stream_cfg_cmd->stream_src == CAMIF_RAW ||
stream_cfg_cmd->stream_src == IDEAL_RAW)
@@ -515,7 +460,6 @@
cfg_io_format(vfe_dev, stream_cfg_cmd);
msm_isp_calculate_framedrop(&vfe_dev->axi_data, stream_cfg_cmd);
- vfe_dev->hw_info->vfe_ops.axi_ops.cfg_framedrop(vfe_dev, stream_info);
if (stream_info->num_planes > 1) {
msm_isp_axi_reserve_comp_mask(
@@ -531,12 +475,8 @@
vfe_dev->hw_info->vfe_ops.axi_ops.
cfg_wm_reg(vfe_dev, stream_cfg_cmd, i);
- vfe_dev->hw_info->vfe_ops.axi_ops.
- cfg_wm_xbar_reg(vfe_dev, stream_cfg_cmd, i);
-
- if (stream_cfg_cmd->stream_src == RDI)
vfe_dev->hw_info->vfe_ops.axi_ops.
- cfg_rdi_reg(vfe_dev, stream_cfg_cmd, i);
+ cfg_wm_xbar_reg(vfe_dev, stream_cfg_cmd, i);
}
return rc;
}
@@ -590,7 +530,7 @@
void msm_isp_axi_stream_enable_cfg(
struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream *stream_info,
- uint32_t *wm_reload_mask, uint32_t *reg_update_mask)
+ uint32_t *wm_reload_mask)
{
int i;
struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
@@ -605,10 +545,9 @@
vfe_dev->hw_info->vfe_ops.axi_ops.
enable_wm(vfe_dev, stream_info->wm[i], 0);
- *wm_reload_mask |= (1 << stream_info->wm[i]);
- if (stream_info->stream_src == RDI)
- *reg_update_mask |= (1 << stream_info->rdi[i]);
+ *wm_reload_mask |= (1 << stream_info->wm[i]);
}
+
if (stream_info->state == START_PENDING) {
axi_data->num_active_stream++;
stream_info->state = ACTIVE;
@@ -622,14 +561,14 @@
{
int i;
struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
- uint32_t wm_reload_mask = 0x0, reg_update_mask = 0x1;
+ uint32_t wm_reload_mask = 0x0;
for (i = 0; i < MAX_NUM_STREAM; i++) {
if (axi_data->stream_info[i].state == START_PENDING ||
axi_data->stream_info[i].state ==
STOP_PENDING) {
msm_isp_axi_stream_enable_cfg(
vfe_dev, &axi_data->stream_info[i],
- &wm_reload_mask, ®_update_mask);
+ &wm_reload_mask);
if (axi_data->stream_info[i].state == STOP_PENDING)
axi_data->stream_info[i].state = STOPPING;
}
@@ -637,10 +576,8 @@
/*Reload AXI*/
vfe_dev->hw_info->vfe_ops.axi_ops.
reload_wm(vfe_dev, wm_reload_mask);
- /*Reg update per src*/
- vfe_dev->hw_info->vfe_ops.core_ops.
- reg_update(vfe_dev, reg_update_mask);
if (vfe_dev->axi_data.stream_update) {
+ vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev);
ISP_DBG("%s: send update complete\n", __func__);
vfe_dev->axi_data.stream_update = 0;
complete(&vfe_dev->stream_config_complete);
@@ -714,17 +651,20 @@
static void msm_isp_process_done_buf(struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream *stream_info, struct msm_isp_buffer *buf,
- struct timeval *tv)
+ struct msm_isp_timestamp *ts)
{
struct msm_isp_event_data buf_event;
+ uint32_t stream_idx = stream_info->stream_handle & 0xFF;
uint32_t frame_id = vfe_dev->axi_data.
- src_info[stream_info->stream_src].frame_id;
- if (buf && tv) {
+ src_info[SRC_TO_INTF(stream_info->stream_src)].frame_id;
+
+ if (buf && ts) {
if (stream_info->buf_divert) {
vfe_dev->buf_mgr->ops->buf_divert(vfe_dev->buf_mgr,
- buf->bufq_handle, buf->buf_idx, tv, frame_id);
+ buf->bufq_handle, buf->buf_idx,
+ &ts->buf_time, frame_id);
buf_event.frame_id = frame_id;
- buf_event.timestamp = *tv;
+ buf_event.timestamp = ts->buf_time;
buf_event.u.buf_done.session_id =
stream_info->session_id;
buf_event.u.buf_done.stream_id =
@@ -732,11 +672,12 @@
buf_event.u.buf_done.handle =
stream_info->bufq_handle;
buf_event.u.buf_done.buf_idx = buf->buf_idx;
- msm_isp_send_event(
- vfe_dev, ISP_EVENT_BUF_DIVERT, &buf_event);
+ msm_isp_send_event(vfe_dev, ISP_EVENT_BUF_DIVERT +
+ stream_idx, &buf_event);
} else {
vfe_dev->buf_mgr->ops->buf_done(vfe_dev->buf_mgr,
- buf->bufq_handle, buf->buf_idx, tv, frame_id);
+ buf->bufq_handle, buf->buf_idx,
+ &ts->buf_time, frame_id);
}
}
}
@@ -758,7 +699,7 @@
stream_info =
&axi_data->stream_info[
(stream_cfg_cmd->stream_handle[i] & 0xFF)];
- if (stream_info->stream_src != RDI)
+ if (stream_info->stream_src < RDI_INTF_0)
pix_stream_cnt++;
if (stream_info->stream_src == PIX_ENCODER ||
stream_info->stream_src == PIX_VIEWFINDER) {
@@ -830,7 +771,7 @@
{
int rc = 0, i;
struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd = arg;
- uint32_t wm_reload_mask = 0x0, reg_update_mask = 0x1;
+ uint32_t wm_reload_mask = 0x0;
struct msm_vfe_axi_stream *stream_info;
struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
uint8_t src_state;
@@ -866,17 +807,19 @@
&axi_data->stream_info[
(stream_cfg_cmd->stream_handle[i] & 0xFF)];
- if (stream_info->stream_src == RDI)
- src_state =
- axi_data->src_info[
- stream_info->rdi[0]+1].active;
- else
+ if (stream_info->stream_src < RDI_INTF_0)
src_state = axi_data->src_info[0].active;
+ else
+ src_state = axi_data->src_info[
+ (stream_info->stream_src - RDI_INTF_0)].active;
stream_info->state = (stream_cfg_cmd->cmd == START_STREAM) ?
START_PENDING : STOP_PENDING;
if (stream_cfg_cmd->cmd == START_STREAM) {
+ /*Configure framedrop*/
+ msm_isp_reset_framedrop(vfe_dev, stream_info);
+
/*Set address for both PING & PONG register */
rc = msm_isp_cfg_ping_pong_address(vfe_dev,
stream_info, VFE_PONG_FLAG);
@@ -900,14 +843,13 @@
if (src_state && camif_update != DISABLE_CAMIF) {
/*On the fly stream start/stop */
wait_for_complete = 1;
- reg_update_mask = 0xF; /*TD: Maybe set this per src*/
} else {
- if (vfe_dev->dump_reg)
+ if (vfe_dev->dump_reg &&
+ stream_cfg_cmd->cmd == START_STREAM)
msm_camera_io_dump_2(vfe_dev->vfe_base, 0x900);
/*Configure AXI start bits to start immediately*/
msm_isp_axi_stream_enable_cfg(
- vfe_dev, stream_info,
- &wm_reload_mask, ®_update_mask);
+ vfe_dev, stream_info, &wm_reload_mask);
}
}
if (!wait_for_complete) {
@@ -915,9 +857,9 @@
if (stream_cfg_cmd->cmd == START_STREAM)
vfe_dev->hw_info->vfe_ops.axi_ops.
reload_wm(vfe_dev, wm_reload_mask);
- /*Reg update per src*/
+
vfe_dev->hw_info->vfe_ops.core_ops.
- reg_update(vfe_dev, reg_update_mask);
+ reg_update(vfe_dev);
if (camif_update == ENABLE_CAMIF)
vfe_dev->hw_info->vfe_ops.core_ops.
@@ -932,15 +874,15 @@
if (stream_cfg_cmd->cmd == START_STREAM)
vfe_dev->hw_info->vfe_ops.axi_ops.
reload_wm(vfe_dev, wm_reload_mask);
- /*Reg update per src*/
- vfe_dev->hw_info->vfe_ops.core_ops.
- reg_update(vfe_dev, reg_update_mask);
+ vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev);
rc = wait_for_completion_interruptible_timeout(
&vfe_dev->stream_config_complete,
msecs_to_jiffies(500));
if (rc == 0) {
pr_err("%s: wait timeout\n", __func__);
rc = -1;
+ } else {
+ rc = 0;
}
}
return rc;
@@ -980,7 +922,7 @@
void msm_isp_process_axi_irq(struct vfe_device *vfe_dev,
uint32_t irq_status0, uint32_t irq_status1,
- struct timeval *tv)
+ struct msm_isp_timestamp *ts)
{
int i, rc = 0;
struct msm_isp_buffer *done_buf = NULL;
@@ -1026,7 +968,7 @@
}
if (done_buf && !rc)
msm_isp_process_done_buf(vfe_dev,
- stream_info, done_buf, tv);
+ stream_info, done_buf, ts);
}
}
wm_mask &= ~(comp_info->stream_composite_mask);
@@ -1041,6 +983,9 @@
}
stream_idx = axi_data->free_wm[i] & 0xFF;
stream_info = &axi_data->stream_info[stream_idx];
+ ISP_DBG("%s: stream%d frame id: 0x%x\n",
+ __func__,
+ stream_idx, stream_info->frame_id);
stream_info->frame_id++;
msm_isp_get_done_buf(vfe_dev, stream_info,
pingpong_status, &done_buf);
@@ -1051,7 +996,7 @@
}
if (done_buf && !rc)
msm_isp_process_done_buf(vfe_dev,
- stream_info, done_buf, tv);
+ stream_info, done_buf, ts);
}
}
return;
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h
index 9765ae2..ba845bc 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h
@@ -48,15 +48,14 @@
void msm_isp_axi_stream_enable_cfg(struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream *stream_info,
- uint32_t *wm_reload_mask, uint32_t *reg_update_mask);
+ uint32_t *wm_reload_mask);
void msm_isp_axi_stream_update(struct vfe_device *vfe_dev);
void msm_isp_update_framedrop_reg(struct vfe_device *vfe_dev);
-void msm_isp_update_framedrop_count(struct vfe_device *vfe_dev);
void msm_isp_sof_notify(struct vfe_device *vfe_dev,
- enum msm_vfe_input_src frame_src, struct timeval *tv);
+ enum msm_vfe_input_src frame_src, struct msm_isp_timestamp *ts);
void msm_isp_process_axi_irq(struct vfe_device *vfe_dev,
uint32_t irq_status0, uint32_t irq_status1,
- struct timeval *tv);
+ struct msm_isp_timestamp *ts);
#endif /* __MSM_ISP_AXI_UTIL_H__ */
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
index bf348d0..a29fe9c 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
@@ -58,7 +58,7 @@
void msm_isp_process_stats_irq(struct vfe_device *vfe_dev,
uint32_t irq_status0, uint32_t irq_status1,
- struct timeval *tv)
+ struct msm_isp_timestamp *ts)
{
int i;
struct msm_isp_event_data buf_event;
@@ -98,13 +98,17 @@
done_buf->buf_idx;
vfe_dev->buf_mgr->ops->buf_divert(vfe_dev->buf_mgr,
done_buf->bufq_handle, done_buf->buf_idx,
- tv, 0);
+ &ts->buf_time, vfe_dev->axi_data.
+ src_info[VFE_PIX_0].frame_id);
}
}
if (stats_event->stats_mask) {
- buf_event.timestamp = *tv;
- msm_isp_send_event(vfe_dev, ISP_EVENT_STATS_NOTIFY, &buf_event);
+ buf_event.timestamp = ts->event_time;
+ buf_event.frame_id =
+ vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id;
+ msm_isp_send_event(vfe_dev, ISP_EVENT_STATS_NOTIFY +
+ stream_info->stats_type, &buf_event);
}
}
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.h
index 2f51b7b..13e1fd6 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.h
@@ -17,7 +17,7 @@
void msm_isp_process_stats_irq(struct vfe_device *vfe_dev,
uint32_t irq_status0, uint32_t irq_status1,
- struct timeval *tv);
+ struct msm_isp_timestamp *ts);
int msm_isp_cfg_stats_stream(struct vfe_device *vfe_dev, void *arg);
int msm_isp_release_stats_stream(struct vfe_device *vfe_dev, void *arg);
int msm_isp_request_stats_stream(struct vfe_device *vfe_dev, void *arg);
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
index e181b53..bbdfaa6 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
@@ -20,13 +20,13 @@
#define MAX_ISP_V4l2_EVENTS 100
-void msm_isp_gettimeofday(struct timeval *tv)
+static inline void msm_isp_get_timestamp(struct msm_isp_timestamp *time_stamp)
{
struct timespec ts;
-
ktime_get_ts(&ts);
- tv->tv_sec = ts.tv_sec;
- tv->tv_usec = ts.tv_nsec/1000;
+ time_stamp->buf_time.tv_sec = ts.tv_sec;
+ time_stamp->buf_time.tv_usec = ts.tv_nsec/1000;
+ do_gettimeofday(&(time_stamp->event_time));
}
int msm_isp_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
@@ -81,6 +81,18 @@
return rc;
}
+int msm_isp_cfg_rdi(struct vfe_device *vfe_dev,
+ struct msm_vfe_rdi_cfg *rdi_cfg, enum msm_vfe_input_src input_src)
+{
+ int rc = 0;
+ /*TD Validate config info
+ * should check if all streams are off */
+
+ vfe_dev->hw_info->vfe_ops.core_ops.
+ cfg_rdi_reg(vfe_dev, rdi_cfg, input_src);
+ return rc;
+}
+
int msm_isp_cfg_input(struct vfe_device *vfe_dev, void *arg)
{
int rc = 0;
@@ -93,6 +105,9 @@
case VFE_RAW_0:
case VFE_RAW_1:
case VFE_RAW_2:
+ msm_isp_cfg_rdi(vfe_dev, &input_cfg->d.rdi_cfg,
+ input_cfg->input_src);
+ break;
case VFE_SRC_MAX:
break;
}
@@ -102,56 +117,59 @@
long msm_isp_ioctl(struct v4l2_subdev *sd,
unsigned int cmd, void *arg)
{
+ long rc = 0;
struct vfe_device *vfe_dev = v4l2_get_subdevdata(sd);
mutex_lock(&vfe_dev->mutex);
ISP_DBG("%s cmd: %d\n", __func__, cmd);
-
switch (cmd) {
case VIDIOC_MSM_VFE_REG_CFG: {
- msm_isp_proc_cmd(vfe_dev, arg);
+ rc = msm_isp_proc_cmd(vfe_dev, arg);
break;
}
case VIDIOC_MSM_ISP_REQUEST_BUF:
case VIDIOC_MSM_ISP_ENQUEUE_BUF:
case VIDIOC_MSM_ISP_RELEASE_BUF: {
- msm_isp_proc_buf_cmd(vfe_dev->buf_mgr, cmd, arg);
+ rc = msm_isp_proc_buf_cmd(vfe_dev->buf_mgr, cmd, arg);
break;
}
case VIDIOC_MSM_ISP_REQUEST_STREAM:
- msm_isp_request_axi_stream(vfe_dev, arg);
+ rc = msm_isp_request_axi_stream(vfe_dev, arg);
break;
case VIDIOC_MSM_ISP_RELEASE_STREAM:
- msm_isp_release_axi_stream(vfe_dev, arg);
+ rc = msm_isp_release_axi_stream(vfe_dev, arg);
break;
case VIDIOC_MSM_ISP_CFG_STREAM:
- msm_isp_cfg_axi_stream(vfe_dev, arg);
+ rc = msm_isp_cfg_axi_stream(vfe_dev, arg);
break;
case VIDIOC_MSM_ISP_INPUT_CFG:
- msm_isp_cfg_input(vfe_dev, arg);
+ rc = msm_isp_cfg_input(vfe_dev, arg);
break;
case VIDIOC_MSM_ISP_SET_SRC_STATE:
msm_isp_set_src_state(vfe_dev, arg);
break;
case VIDIOC_MSM_ISP_REQUEST_STATS_STREAM:
- msm_isp_request_stats_stream(vfe_dev, arg);
+ rc = msm_isp_request_stats_stream(vfe_dev, arg);
break;
case VIDIOC_MSM_ISP_RELEASE_STATS_STREAM:
- msm_isp_release_stats_stream(vfe_dev, arg);
+ rc = msm_isp_release_stats_stream(vfe_dev, arg);
break;
case VIDIOC_MSM_ISP_CFG_STATS_STREAM:
- msm_isp_cfg_stats_stream(vfe_dev, arg);
+ rc = msm_isp_cfg_stats_stream(vfe_dev, arg);
break;
case VIDIOC_MSM_ISP_CFG_STATS_COMP_POLICY:
- msm_isp_cfg_stats_comp_policy(vfe_dev, arg);
+ rc = msm_isp_cfg_stats_comp_policy(vfe_dev, arg);
break;
case VIDIOC_MSM_ISP_UPDATE_STREAM:
- msm_isp_update_axi_stream(vfe_dev, arg);
+ rc = msm_isp_update_axi_stream(vfe_dev, arg);
break;
+ default:
+ pr_err("%s: Invalid ISP command\n", __func__);
+ rc = -EINVAL;
}
mutex_unlock(&vfe_dev->mutex);
- return 0;
+ return rc;
}
static int msm_isp_send_hw_cmd(struct vfe_device *vfe_dev,
@@ -366,18 +384,34 @@
case V4L2_PIX_FMT_SGBRG8:
case V4L2_PIX_FMT_SGRBG8:
case V4L2_PIX_FMT_SRGGB8:
+ case V4L2_PIX_FMT_QBGGR8:
+ case V4L2_PIX_FMT_QGBRG8:
+ case V4L2_PIX_FMT_QGRBG8:
+ case V4L2_PIX_FMT_QRGGB8:
val = CAL_WORD(pixel_per_line, 1, 8);
break;
case V4L2_PIX_FMT_SBGGR10:
case V4L2_PIX_FMT_SGBRG10:
case V4L2_PIX_FMT_SGRBG10:
case V4L2_PIX_FMT_SRGGB10:
- val = CAL_WORD(pixel_per_line, 1, 6);
+ val = CAL_WORD(pixel_per_line, 5, 32);
break;
case V4L2_PIX_FMT_SBGGR12:
case V4L2_PIX_FMT_SGBRG12:
case V4L2_PIX_FMT_SGRBG12:
case V4L2_PIX_FMT_SRGGB12:
+ val = CAL_WORD(pixel_per_line, 3, 16);
+ break;
+ case V4L2_PIX_FMT_QBGGR10:
+ case V4L2_PIX_FMT_QGBRG10:
+ case V4L2_PIX_FMT_QGRBG10:
+ case V4L2_PIX_FMT_QRGGB10:
+ val = CAL_WORD(pixel_per_line, 1, 6);
+ break;
+ case V4L2_PIX_FMT_QBGGR12:
+ case V4L2_PIX_FMT_QGBRG12:
+ case V4L2_PIX_FMT_QGRBG12:
+ case V4L2_PIX_FMT_QRGGB12:
val = CAL_WORD(pixel_per_line, 1, 5);
break;
case V4L2_PIX_FMT_NV12:
@@ -399,16 +433,28 @@
case V4L2_PIX_FMT_SGBRG8:
case V4L2_PIX_FMT_SGRBG8:
case V4L2_PIX_FMT_SRGGB8:
+ case V4L2_PIX_FMT_QBGGR8:
+ case V4L2_PIX_FMT_QGBRG8:
+ case V4L2_PIX_FMT_QGRBG8:
+ case V4L2_PIX_FMT_QRGGB8:
return 8;
case V4L2_PIX_FMT_SBGGR10:
case V4L2_PIX_FMT_SGBRG10:
case V4L2_PIX_FMT_SGRBG10:
case V4L2_PIX_FMT_SRGGB10:
+ case V4L2_PIX_FMT_QBGGR10:
+ case V4L2_PIX_FMT_QGBRG10:
+ case V4L2_PIX_FMT_QGRBG10:
+ case V4L2_PIX_FMT_QRGGB10:
return 10;
case V4L2_PIX_FMT_SBGGR12:
case V4L2_PIX_FMT_SGBRG12:
case V4L2_PIX_FMT_SGRBG12:
case V4L2_PIX_FMT_SRGGB12:
+ case V4L2_PIX_FMT_QBGGR12:
+ case V4L2_PIX_FMT_QGBRG12:
+ case V4L2_PIX_FMT_QGRBG12:
+ case V4L2_PIX_FMT_QRGGB12:
return 12;
case V4L2_PIX_FMT_NV12:
case V4L2_PIX_FMT_NV21:
@@ -504,7 +550,7 @@
}
queue_cmd->vfeInterruptStatus0 = irq_status0;
queue_cmd->vfeInterruptStatus1 = irq_status1;
- msm_isp_gettimeofday(&queue_cmd->tv);
+ msm_isp_get_timestamp(&queue_cmd->ts);
queue_cmd->cmd_used = 1;
vfe_dev->taskletq_idx =
(vfe_dev->taskletq_idx + 1) % MSM_VFE_TASKLETQ_SIZE;
@@ -520,7 +566,7 @@
struct vfe_device *vfe_dev = (struct vfe_device *) data;
struct msm_vfe_irq_ops *irq_ops = &vfe_dev->hw_info->vfe_ops.irq_ops;
struct msm_vfe_tasklet_queue_cmd *queue_cmd;
- struct timeval tv;
+ struct msm_isp_timestamp ts;
uint32_t irq_status0, irq_status1;
while (atomic_read(&vfe_dev->irq_cnt)) {
spin_lock_irqsave(&vfe_dev->tasklet_lock, flags);
@@ -536,7 +582,7 @@
queue_cmd->cmd_used = 0;
irq_status0 = queue_cmd->vfeInterruptStatus0;
irq_status1 = queue_cmd->vfeInterruptStatus1;
- tv = queue_cmd->tv;
+ ts = queue_cmd->ts;
spin_unlock_irqrestore(&vfe_dev->tasklet_lock, flags);
ISP_DBG("%s: status0: 0x%x status1: 0x%x\n",
__func__, irq_status0, irq_status1);
@@ -545,13 +591,13 @@
irq_ops->process_halt_irq(vfe_dev,
irq_status0, irq_status1);
irq_ops->process_camif_irq(vfe_dev,
- irq_status0, irq_status1, &tv);
+ irq_status0, irq_status1, &ts);
irq_ops->process_axi_irq(vfe_dev,
- irq_status0, irq_status1, &tv);
+ irq_status0, irq_status1, &ts);
irq_ops->process_stats_irq(vfe_dev,
- irq_status0, irq_status1, &tv);
+ irq_status0, irq_status1, &ts);
irq_ops->process_reg_update(vfe_dev,
- irq_status0, irq_status1, &tv);
+ irq_status0, irq_status1, &ts);
msm_isp_process_error_info(vfe_dev);
}
}
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.h
index 6c2a88c..3dac7e0 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.h
@@ -22,8 +22,6 @@
#define ISP_DBG(fmt, args...) pr_debug(fmt, ##args)
#endif
-void msm_isp_gettimeofday(struct timeval *tv);
-
int msm_isp_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
struct v4l2_event_subscription *sub);
diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
index 50e685a..7d0f9cb 100644
--- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
+++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
@@ -405,10 +405,10 @@
} else {
/* zero 2 bits */
ispif->applied_intf_cmd[vfe_intf].intf_cmd &=
- ~(0x3 << (vc * 2 + vfe_intf * 8));
+ ~(0x3 << (vc * 2 + intf_type * 8));
/* set cmd bits */
ispif->applied_intf_cmd[vfe_intf].intf_cmd |=
- (cmd_bits << (vc * 2 + vfe_intf * 8));
+ (cmd_bits << (vc * 2 + intf_type * 8));
}
}
}
diff --git a/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c b/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c
index a47d178..9af6674 100644
--- a/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c
+++ b/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c
@@ -33,6 +33,8 @@
kfree(new_entry);
return -EINVAL;
}
+ new_entry->session_id = buf_info->session_id;
+ new_entry->stream_id = buf_info->stream_id;
list_add_tail(&new_entry->entry, &buf_mngr_dev->buf_qhead);
buf_info->index = new_entry->vb2_buf->v4l2_buf.index;
return 0;
@@ -44,8 +46,11 @@
struct msm_get_bufs *bufs, *save;
int ret = -EINVAL;
list_for_each_entry_safe(bufs, save, &buf_mngr_dev->buf_qhead, entry) {
- if (bufs->vb2_buf->v4l2_buf.index == buf_info->index) {
+ if ((bufs->session_id == buf_info->session_id) &&
+ (bufs->stream_id == buf_info->stream_id) &&
+ (bufs->vb2_buf->v4l2_buf.index == buf_info->index)) {
bufs->vb2_buf->v4l2_buf.sequence = buf_info->frame_id;
+ bufs->vb2_buf->v4l2_buf.timestamp = buf_info->timestamp;
ret = buf_mngr_dev->vb2_ops.buf_done
(bufs->vb2_buf,
buf_info->session_id,
@@ -66,7 +71,9 @@
int ret = -EINVAL;
list_for_each_entry_safe(bufs, save, &buf_mngr_dev->buf_qhead, entry) {
- if (bufs->vb2_buf->v4l2_buf.index == buf_info->index) {
+ if ((bufs->session_id == buf_info->session_id) &&
+ (bufs->stream_id == buf_info->stream_id) &&
+ (bufs->vb2_buf->v4l2_buf.index == buf_info->index)) {
ret = buf_mngr_dev->vb2_ops.put_buf(bufs->vb2_buf,
buf_info->session_id, buf_info->stream_id);
list_del_init(&bufs->entry);
diff --git a/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.h b/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.h
index c38a424..7e588cc 100644
--- a/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.h
+++ b/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.h
@@ -27,6 +27,8 @@
struct msm_get_bufs {
struct list_head entry;
struct vb2_buffer *vb2_buf;
+ uint32_t session_id;
+ uint32_t stream_id;
};
struct msm_buf_mngr_device {
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
index 4b1b1c7..9f0ad19 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
@@ -122,6 +122,7 @@
CPP_DBG("Read failed\n");
tmp = 0xDEADBEEF;
}
+
return tmp;
}
@@ -207,6 +208,48 @@
return IRQ_HANDLED;
}
+static void msm_cpp_boot_hw(struct cpp_device *cpp_dev)
+{
+ disable_irq(cpp_dev->irq->start);
+
+ msm_camera_io_w(0x1, cpp_dev->base + MSM_CPP_MICRO_CLKEN_CTL);
+ msm_camera_io_w(0x1, cpp_dev->base +
+ MSM_CPP_MICRO_BOOT_START);
+ msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_CMD);
+
+ /*Trigger MC to jump to start address*/
+ msm_cpp_write(MSM_CPP_CMD_EXEC_JUMP, cpp_dev->base);
+ msm_cpp_write(MSM_CPP_JUMP_ADDRESS, cpp_dev->base);
+
+ msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_CMD);
+ msm_cpp_poll(cpp_dev->base, 0x1);
+ msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_JUMP_ACK);
+ msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_TRAILER);
+
+ /*Get Bootloader Version*/
+ msm_cpp_write(MSM_CPP_CMD_GET_BOOTLOADER_VER, cpp_dev->base);
+ pr_info("MC Bootloader Version: 0x%x\n",
+ msm_cpp_read(cpp_dev->base));
+
+ /*Get Firmware Version*/
+ msm_cpp_write(MSM_CPP_CMD_GET_FW_VER, cpp_dev->base);
+ msm_cpp_write(MSM_CPP_MSG_ID_CMD, cpp_dev->base);
+ msm_cpp_write(0x1, cpp_dev->base);
+ msm_cpp_write(MSM_CPP_CMD_GET_FW_VER, cpp_dev->base);
+ msm_cpp_write(MSM_CPP_MSG_ID_TRAILER, cpp_dev->base);
+
+ msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_CMD);
+ msm_cpp_poll(cpp_dev->base, 0x2);
+ msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_FW_VER);
+ pr_info("CPP FW Version: 0x%x\n", msm_cpp_read(cpp_dev->base));
+ msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_TRAILER);
+ enable_irq(cpp_dev->irq->start);
+ msm_camera_io_w_mb(0x8, cpp_dev->base +
+ MSM_CPP_MICRO_IRQGEN_MASK);
+ msm_camera_io_w_mb(0xFFFF, cpp_dev->base +
+ MSM_CPP_MICRO_IRQGEN_CLR);
+}
+
static int cpp_init_hardware(struct cpp_device *cpp_dev)
{
int rc = 0;
@@ -261,7 +304,8 @@
}
msm_camera_io_w(0x1, cpp_dev->vbif_base + 0x4);
-
+ if (cpp_dev->is_firmware_loaded == 1)
+ msm_cpp_boot_hw(cpp_dev);
return rc;
req_irq_fail:
iounmap(cpp_dev->vbif_base);
@@ -365,6 +409,9 @@
pr_info("CPP FW Version: 0x%x\n", msm_cpp_read(cpp_dev->base));
msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_TRAILER);
+ /*Disable MC clock*/
+ /*msm_camera_io_w(0x0, cpp_dev->base +
+ MSM_CPP_MICRO_CLKEN_CTL);*/
}
static int cpp_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
@@ -398,16 +445,6 @@
if (cpp_dev->cpp_open_cnt == 1) {
cpp_init_hardware(cpp_dev);
cpp_init_mem(cpp_dev);
- disable_irq(cpp_dev->irq->start);
-
- cpp_load_fw(cpp_dev);
-
- enable_irq(cpp_dev->irq->start);
-
- msm_camera_io_w_mb(0x8, cpp_dev->base +
- MSM_CPP_MICRO_IRQGEN_MASK);
- msm_camera_io_w_mb(0xFFFF, cpp_dev->base +
- MSM_CPP_MICRO_IRQGEN_CLR);
cpp_dev->state = CPP_STATE_IDLE;
}
mutex_unlock(&cpp_dev->mutex);
@@ -657,6 +694,15 @@
mutex_lock(&cpp_dev->mutex);
CPP_DBG("E cmd: %d\n", cmd);
switch (cmd) {
+ case VIDIOC_MSM_CPP_LOAD_FIRMWARE: {
+ if (cpp_dev->is_firmware_loaded == 0) {
+ disable_irq(cpp_dev->irq->start);
+ cpp_load_fw(cpp_dev);
+ enable_irq(cpp_dev->irq->start);
+ cpp_dev->is_firmware_loaded = 1;
+ }
+ break;
+ }
case VIDIOC_MSM_CPP_CFG:
rc = msm_cpp_cfg(cpp_dev, ioctl_ptr);
break;
@@ -899,6 +945,7 @@
msm_queue_init(&cpp_dev->realtime_q, "frame");
msm_queue_init(&cpp_dev->processing_q, "frame");
cpp_dev->cpp_open_cnt = 0;
+ cpp_dev->is_firmware_loaded = 0;
return rc;
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h
index 8deff72..e8e37ed 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h
@@ -131,6 +131,7 @@
struct regulator *fs_cpp;
struct mutex mutex;
enum cpp_state state;
+ uint8_t is_firmware_loaded;
int domain_num;
struct iommu_domain *domain;
diff --git a/drivers/media/platform/msm/camera_v2/sensor/Makefile b/drivers/media/platform/msm/camera_v2/sensor/Makefile
index d0b6c62..f6011ba 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/Makefile
+++ b/drivers/media/platform/msm/camera_v2/sensor/Makefile
@@ -3,7 +3,7 @@
ccflags-y += -Idrivers/media/platform/msm/camera_v2/camera
ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io
ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/cci
-obj-$(CONFIG_MSMB_CAMERA) += cci/ io/ csiphy/ csid/ actuator/
+obj-$(CONFIG_MSMB_CAMERA) += cci/ io/ csiphy/ csid/ actuator/ flash/
obj-$(CONFIG_MSM_CAMERA_SENSOR) += msm_sensor.o
obj-$(CONFIG_S5K3L1YX) += s5k3l1yx.o
obj-$(CONFIG_OV2720) += ov2720.o
diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/Makefile b/drivers/media/platform/msm/camera_v2/sensor/flash/Makefile
new file mode 100644
index 0000000..4ce7372
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/flash/Makefile
@@ -0,0 +1,4 @@
+ccflags-y += -Idrivers/media/platform/msm/camera_v2
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io
+obj-$(CONFIG_MSMB_CAMERA) += msm_led_flash.o
+obj-$(CONFIG_MSMB_CAMERA) += msm_led_trigger.o
diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.c b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.c
index ba2c87d..9119a13 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.c
@@ -27,7 +27,6 @@
unsigned int cmd, void *arg)
{
struct msm_led_flash_ctrl_t *fctrl = NULL;
- int32_t rc = 0;
void __user *argp = (void __user *)arg;
if (!sd) {
pr_err("sd NULL\n");
@@ -39,9 +38,10 @@
return -EINVAL;
}
switch (cmd) {
+ case VIDIOC_MSM_SENSOR_GET_SUBDEV_ID:
+ return fctrl->func_tbl->flash_get_subdev_id(fctrl, argp);
case VIDIOC_MSM_FLASH_LED_DATA_CFG:
- rc = fctrl->func_tbl->flash_led_config(fctrl, argp);
- return 0;
+ return fctrl->func_tbl->flash_led_config(fctrl, argp);
default:
pr_err("invalid cmd %d\n", cmd);
return -ENOIOCTLCMD;
diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.h b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.h
index 76c58d2..76aa695 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.h
+++ b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.h
@@ -24,6 +24,7 @@
struct msm_led_flash_ctrl_t;
struct msm_flash_fn_t {
+ int32_t (*flash_get_subdev_id)(struct msm_led_flash_ctrl_t *, void *);
int32_t (*flash_led_config)(struct msm_led_flash_ctrl_t *, void *);
int32_t (*flash_led_init)(struct msm_led_flash_ctrl_t *);
int32_t (*flash_led_release)(struct msm_led_flash_ctrl_t *);
diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_trigger.c b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_trigger.c
index 9d8981f..1a75a5a 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_trigger.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_trigger.c
@@ -28,6 +28,19 @@
static struct msm_led_flash_ctrl_t fctrl;
+static int32_t msm_led_trigger_get_subdev_id(struct msm_led_flash_ctrl_t *fctrl,
+ void *arg)
+{
+ uint32_t *subdev_id = (uint32_t *)arg;
+ if (!subdev_id) {
+ pr_err("%s:%d failed\n", __func__, __LINE__);
+ return -EINVAL;
+ }
+ *subdev_id = fctrl->pdev->id;
+ CDBG("%s:%d subdev_id %d\n", __func__, __LINE__, *subdev_id);
+ return 0;
+}
+
static int32_t msm_led_trigger_config(struct msm_led_flash_ctrl_t *fctrl,
void *data)
{
@@ -158,6 +171,7 @@
}
static struct msm_flash_fn_t msm_led_trigger_func_tbl = {
+ .flash_get_subdev_id = msm_led_trigger_get_subdev_id,
.flash_led_config = msm_led_trigger_config,
};
diff --git a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c
index 9062a9c..453b14a 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c
@@ -90,17 +90,21 @@
sensordata->sensor_info->subdev_id[SUB_MODULE_EEPROM] = val;
}
- if (of_property_read_bool(of_node, "qcom,led-flash-sd-index") ==
- true) {
- rc = of_property_read_u32(of_node, "qcom,led-flash-sd-index",
- &val);
- CDBG("%s qcom,led-flash-sd-index %d, rc %d\n", __func__, val,
- rc);
+ src_node = of_parse_phandle(of_node, "qcom,led-flash-src", 0);
+ if (!src_node) {
+ CDBG("%s:%d src_node NULL\n", __func__, __LINE__);
+ } else {
+ rc = of_property_read_u32(src_node, "cell-index", &val);
+ CDBG("%s qcom,led flash cell index %d, rc %d\n", __func__,
+ val, rc);
if (rc < 0) {
- pr_err("%s:%d failed rc %d\n", __func__, __LINE__, rc);
+ pr_err("%s:%d failed %d\n", __func__, __LINE__, rc);
goto ERROR;
}
- sensordata->sensor_info->subdev_id[SUB_MODULE_LED_FLASH] = val;
+ sensordata->sensor_info->
+ subdev_id[SUB_MODULE_LED_FLASH] = val;
+ of_node_put(src_node);
+ src_node = NULL;
}
if (of_property_read_bool(of_node, "qcom,strobe-flash-sd-index") ==
diff --git a/drivers/media/platform/msm/camera_v2/sensor/s5k3l1yx.c b/drivers/media/platform/msm/camera_v2/sensor/s5k3l1yx.c
index 9c36b5b..21a7369 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/s5k3l1yx.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/s5k3l1yx.c
@@ -54,6 +54,18 @@
.delay = 30,
},
{
+ .seq_type = SENSOR_GPIO,
+ .seq_val = SENSOR_GPIO_STANDBY,
+ .config_val = GPIO_OUT_LOW,
+ .delay = 1,
+ },
+ {
+ .seq_type = SENSOR_GPIO,
+ .seq_val = SENSOR_GPIO_STANDBY,
+ .config_val = GPIO_OUT_HIGH,
+ .delay = 30,
+ },
+ {
.seq_type = SENSOR_CLK,
.seq_val = SENSOR_CAM_MCLK,
.config_val = 0,
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
index 4701f69..63ec1cf 100644
--- a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
+++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
@@ -18,6 +18,8 @@
#include "mpq_dmx_plugin_common.h"
#include "mpq_sdmx.h"
+#define SDMX_MAJOR_VERSION_MATCH (2)
+
#define TS_PACKET_HEADER_LENGTH (4)
/* Length of mandatory fields that must exist in header of video PES */
@@ -776,6 +778,7 @@
static void mpq_sdmx_check_app_loaded(void)
{
int session;
+ u32 version;
int ret;
ret = sdmx_open_session(&session);
@@ -787,6 +790,24 @@
return;
}
+ /* Check proper sdmx major version */
+ ret = sdmx_get_version(session, &version);
+ if (ret != SDMX_SUCCESS) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: Could not get sdmx version. ret = %d\n",
+ __func__, ret);
+ } else {
+ if ((version >> 8) != SDMX_MAJOR_VERSION_MATCH)
+ MPQ_DVB_ERR_PRINT(
+ "%s: sdmx major version does not match. expected=%d, actual=%d\n",
+ __func__, SDMX_MAJOR_VERSION_MATCH,
+ (version >> 8));
+ else
+ MPQ_DVB_DBG_PRINT(
+ "%s: sdmx major version is ok = %d\n",
+ __func__, SDMX_MAJOR_VERSION_MATCH);
+ }
+
mpq_dmx_info.secure_demux_app_loaded = 1;
sdmx_close_session(session);
}
diff --git a/drivers/media/platform/msm/vidc/msm_smem.c b/drivers/media/platform/msm/vidc/msm_smem.c
index 8e2aa30..125c699 100644
--- a/drivers/media/platform/msm/vidc/msm_smem.c
+++ b/drivers/media/platform/msm/vidc/msm_smem.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -26,7 +26,7 @@
unsigned long align, unsigned long *iova,
unsigned long *buffer_size, int flags)
{
- int rc;
+ int rc = 0;
if (!iova || !buffer_size || !hndl || !clnt) {
dprintk(VIDC_ERR, "Invalid params: %p, %p, %p, %p\n",
clnt, hndl, iova, buffer_size);
@@ -71,6 +71,7 @@
struct ion_handle *hndl;
unsigned long iova = 0;
unsigned long buffer_size = 0;
+ unsigned long ionflags = 0;
int rc = 0;
int align = SZ_4K;
hndl = ion_import_dma_buf(client->clnt, fd);
@@ -84,7 +85,20 @@
mem->domain = domain;
mem->partition_num = partition;
mem->flags = flags;
-
+ rc = ion_handle_get_flags(client->clnt, hndl, &ionflags);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to get ion flags: %d\n", rc);
+ goto fail_map;
+ }
+ if (ION_IS_CACHED(ionflags)) {
+ mem->kvaddr = ion_map_kernel(client->clnt, hndl);
+ if (!mem->kvaddr) {
+ dprintk(VIDC_ERR,
+ "Failed to map shared mem in kernel\n");
+ rc = -EIO;
+ goto fail_map;
+ }
+ }
if (flags & SMEM_SECURE)
align = ALIGN(align, SZ_1M);
@@ -103,7 +117,9 @@
mem->device_addr, mem->size);
return rc;
fail_device_address:
- ion_unmap_kernel(client->clnt, hndl);
+ if (mem->kvaddr)
+ ion_unmap_kernel(client->clnt, hndl);
+fail_map:
ion_free(client->clnt, hndl);
fail_import_fd:
return rc;
@@ -243,31 +259,79 @@
return mem;
}
-static int ion_mem_clean_invalidate(struct smem_client *clt,
- struct msm_smem *mem)
+static int ion_cache_operations(struct smem_client *client,
+ struct msm_smem *mem, enum smem_cache_ops cache_op)
{
- /*
- * Note: We're always mapping into iommu as uncached
- * as a result we don't need to flush/clean anything
- */
- return 0;
+ unsigned long ionflag = 0;
+ int rc = 0;
+ int msm_cache_ops = 0;
+ if (!mem || !client) {
+ dprintk(VIDC_ERR, "Invalid params: %p, %p\n",
+ mem, client);
+ return -EINVAL;
+ }
+ rc = ion_handle_get_flags(client->clnt, mem->smem_priv,
+ &ionflag);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "ion_handle_get_flags failed: %d\n", rc);
+ goto cache_op_failed;
+ }
+ if (ION_IS_CACHED(ionflag)) {
+ switch (cache_op) {
+ case SMEM_CACHE_CLEAN:
+ msm_cache_ops = ION_IOC_CLEAN_CACHES;
+ break;
+ case SMEM_CACHE_INVALIDATE:
+ msm_cache_ops = ION_IOC_INV_CACHES;
+ break;
+ case SMEM_CACHE_CLEAN_INVALIDATE:
+ msm_cache_ops = ION_IOC_CLEAN_INV_CACHES;
+ break;
+ default:
+ dprintk(VIDC_ERR, "cache operation not supported\n");
+ rc = -EINVAL;
+ goto cache_op_failed;
+ }
+ if (mem->kvaddr) {
+ rc = msm_ion_do_cache_op(client->clnt,
+ (struct ion_handle *)mem->smem_priv,
+ (unsigned long *) mem->kvaddr,
+ (unsigned long)mem->size,
+ msm_cache_ops);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "cache operation failed %d\n", rc);
+ goto cache_op_failed;
+ }
+ } else {
+ dprintk(VIDC_WARN,
+ "cache operation failed as no kernel mapping\n");
+ }
+ }
+cache_op_failed:
+ return rc;
}
-int msm_smem_clean_invalidate(void *clt, struct msm_smem *mem)
+int msm_smem_cache_operations(void *clt, struct msm_smem *mem,
+ enum smem_cache_ops cache_op)
{
struct smem_client *client = clt;
- int rc;
- if (!client || !mem) {
- dprintk(VIDC_ERR, "Invalid client/handle passed\n");
+ int rc = 0;
+ if (!client) {
+ dprintk(VIDC_ERR, "Invalid params: %p\n",
+ client);
return -EINVAL;
}
switch (client->mem_type) {
case SMEM_ION:
- rc = ion_mem_clean_invalidate(client, mem);
+ rc = ion_cache_operations(client, mem, cache_op);
+ if (rc)
+ dprintk(VIDC_ERR,
+ "Failed cache operations: %d\n", rc);
break;
default:
dprintk(VIDC_ERR, "Mem type not supported\n");
- rc = -EINVAL;
break;
}
return rc;
diff --git a/drivers/media/platform/msm/vidc/msm_smem.h b/drivers/media/platform/msm/vidc/msm_smem.h
index 6e40bef..d1c8293 100644
--- a/drivers/media/platform/msm/vidc/msm_smem.h
+++ b/drivers/media/platform/msm/vidc/msm_smem.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -37,6 +37,13 @@
void *smem_priv;
};
+enum smem_cache_ops {
+ SMEM_CACHE_CLEAN,
+ SMEM_CACHE_INVALIDATE,
+ SMEM_CACHE_CLEAN_INVALIDATE,
+};
+
+
void *msm_smem_new_client(enum smem_type mtype);
struct msm_smem *msm_smem_alloc(void *clt, size_t size, u32 align, u32 flags,
int domain, int partition, int map_kernel);
@@ -44,5 +51,6 @@
void msm_smem_delete_client(void *clt);
struct msm_smem *msm_smem_user_to_kernel(void *clt, int fd, u32 offset, int
domain, int partition, int flags);
-int msm_smem_clean_invalidate(void *clt, struct msm_smem *mem);
+int msm_smem_cache_operations(void *clt, struct msm_smem *mem,
+ enum smem_cache_ops);
#endif
diff --git a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
index 6480bf5..5d360bb 100644
--- a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
@@ -181,10 +181,12 @@
err_invalid_input:
return ret;
}
-static u32 device_to_uvaddr(struct list_head *list, u32 device_addr)
+
+static struct buffer_info *device_to_uvaddr(
+ struct list_head *list, u32 device_addr)
{
- struct buffer_info *temp;
- u32 uvaddr = 0;
+ struct buffer_info *temp = NULL;
+ int found = 0;
int i;
if (!list || !device_addr) {
dprintk(VIDC_ERR, "Invalid input\n");
@@ -198,16 +200,16 @@
== device_addr) {
dprintk(VIDC_INFO,
"Found same fd buffer\n");
- uvaddr = temp->uvaddr[i];
+ found = 1;
break;
}
}
- if (uvaddr)
+ if (found)
break;
}
}
err_invalid_input:
- return uvaddr;
+ return temp;
}
static int msm_v4l2_open(struct file *filp)
@@ -544,9 +546,10 @@
b->m.planes[i].m.userptr = binfo->device_addr[i];
dprintk(VIDC_DBG, "Queueing device address = 0x%x\n",
binfo->device_addr[i]);
- if (binfo->handle[i]) {
- rc = msm_smem_clean_invalidate(v4l2_inst->mem_client,
- binfo->handle[i]);
+ if (binfo->handle[i] &&
+ (b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)) {
+ rc = msm_smem_cache_operations(v4l2_inst->mem_client,
+ binfo->handle[i], SMEM_CACHE_CLEAN);
if (rc) {
dprintk(VIDC_ERR,
"Failed to clean caches: %d\n", rc);
@@ -566,6 +569,7 @@
int i;
struct msm_v4l2_vid_inst *v4l2_inst;
struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+ struct buffer_info *buffer_info;
if (b->length > VIDEO_MAX_PLANES) {
dprintk(VIDC_ERR, "num planes exceed maximum: %d\n",
b->length);
@@ -585,9 +589,10 @@
!b->m.planes[i].m.userptr) {
continue;
}
- b->m.planes[i].m.userptr = device_to_uvaddr(
+ buffer_info = device_to_uvaddr(
&v4l2_inst->registered_bufs,
b->m.planes[i].m.userptr);
+ b->m.planes[i].m.userptr = buffer_info->uvaddr[i];
if (!b->m.planes[i].m.userptr) {
dprintk(VIDC_ERR,
"Failed to find user virtual address, 0x%lx, %d, %d\n",
@@ -595,6 +600,16 @@
rc = -EINVAL;
goto fail_dq_buf;
}
+ if (buffer_info->handle[i] &&
+ (b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)) {
+ rc = msm_smem_cache_operations(v4l2_inst->mem_client,
+ buffer_info->handle[i], SMEM_CACHE_INVALIDATE);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to clean caches: %d\n", rc);
+ goto fail_dq_buf;
+ }
+ }
}
fail_dq_buf:
return rc;
@@ -864,10 +879,14 @@
res->iommu_maps_size = MAX_MAP;
for (i = 0; i < MAX_MAP; i++) {
num_elements = get_u32_array_num_elements(pdev, names[i]);
- if (num_elements == 0) {
- dprintk(VIDC_ERR,
- "no elements in iommu map :%s\n", names[i]);
- goto error;
+ if ((num_elements == 0)) {
+ if (i == NS_MAP) {
+ dprintk(VIDC_ERR,
+ "Domain not found in dtsi file :%s\n",
+ names[i]);
+ goto error;
+ } else
+ continue;
}
memcpy(&res->iommu_maps[i].name, names[i],
strlen(names[i]));
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index 12469a5..c7dfb97 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -88,6 +88,27 @@
"High Latency",
};
+static const char *const mpeg_video_vidc_extradata[] = {
+ "Extradata none",
+ "Extradata MB Quantization",
+ "Extradata Interlace Video",
+ "Extradata VC1 Framedisp",
+ "Extradata VC1 Seqdisp",
+ "Extradata timestamp",
+ "Extradata S3D Frame Packing",
+ "Extradata Frame Rate",
+ "Extradata Panscan Window",
+ "Extradata Recovery point SEI",
+ "Extradata Closed Caption UD",
+ "Extradata AFD UD",
+ "Extradata Multislice info",
+ "Extradata number of concealed MB",
+ "Extradata metadata filler",
+ "Extradata input crop",
+ "Extradata digital zoom",
+ "Extradata aspect ratio",
+};
+
enum msm_venc_ctrl_cluster {
MSM_VENC_CTRL_CLUSTER_QP = 1,
MSM_VENC_CTRL_CLUSTER_INTRA_PERIOD,
@@ -198,13 +219,13 @@
.type = V4L2_CTRL_TYPE_MENU,
.minimum = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
.maximum = V4L2_MPEG_VIDEO_BITRATE_MODE_CBR,
- .default_value = V4L2_MPEG_VIDEO_BITRATE_MODE_CBR,
+ .default_value = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
.step = 0,
.menu_skip_mask = ~(
(1 << V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) |
(1 << V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
),
- .qmenu = mpeg_video_rate_control,
+ .qmenu = NULL,
.cluster = MSM_VENC_CTRL_CLUSTER_BITRATE,
},
{
@@ -544,7 +565,37 @@
(1 << V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_I_FRAME)
),
.cluster = 0,
- }
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA,
+ .name = "Extradata Type",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDC_EXTRADATA_NONE,
+ .maximum = V4L2_MPEG_VIDC_INDEX_EXTRADATA_ASPECT_RATIO,
+ .default_value = V4L2_MPEG_VIDC_EXTRADATA_NONE,
+ .menu_skip_mask = ~(
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_NONE) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_MB_QUANTIZATION) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_INTERLACE_VIDEO) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_VC1_FRAMEDISP) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_VC1_SEQDISP) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_TIMESTAMP) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_S3D_FRAME_PACKING) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_FRAME_RATE) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_PANSCAN_WINDOW) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_RECOVERY_POINT_SEI) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_CLOSED_CAPTION_UD) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_AFD_UD) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_MULTISLICE_INFO) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_NUM_CONCEALED_MB) |
+ (1 << V4L2_MPEG_VIDC_EXTRADATA_METADATA_FILLER) |
+ (1 << V4L2_MPEG_VIDC_INDEX_EXTRADATA_INPUT_CROP) |
+ (1 << V4L2_MPEG_VIDC_INDEX_EXTRADATA_DIGITAL_ZOOM) |
+ (1 << V4L2_MPEG_VIDC_INDEX_EXTRADATA_ASPECT_RATIO)
+ ),
+ .qmenu = mpeg_video_vidc_extradata,
+ .step = 0,
+ },
};
#define NUM_CTRLS ARRAY_SIZE(msm_venc_ctrls)
@@ -579,7 +630,7 @@
.name = "Mpeg4",
.description = "Mpeg4 compressed format",
.fourcc = V4L2_PIX_FMT_MPEG4,
- .num_planes = 1,
+ .num_planes = 2,
.get_frame_size = get_frame_size_compressed,
.type = CAPTURE_PORT,
},
@@ -587,7 +638,7 @@
.name = "H263",
.description = "H263 compressed format",
.fourcc = V4L2_PIX_FMT_H263,
- .num_planes = 1,
+ .num_planes = 2,
.get_frame_size = get_frame_size_compressed,
.type = CAPTURE_PORT,
},
@@ -595,7 +646,7 @@
.name = "H264",
.description = "H264 compressed format",
.fourcc = V4L2_PIX_FMT_H264,
- .num_planes = 1,
+ .num_planes = 2,
.get_frame_size = get_frame_size_compressed,
.type = CAPTURE_PORT,
},
@@ -603,7 +654,7 @@
.name = "VP8",
.description = "VP8 compressed format",
.fourcc = V4L2_PIX_FMT_VP8,
- .num_planes = 1,
+ .num_planes = 2,
.get_frame_size = get_frame_size_compressed,
.type = CAPTURE_PORT,
},
@@ -650,6 +701,11 @@
sizes[i] = inst->fmts[CAPTURE_PORT]->get_frame_size(
i, inst->prop.height, inst->prop.width);
}
+ property_id = HAL_PARAM_BUFFER_COUNT_ACTUAL;
+ new_buf_count.buffer_type = HAL_BUFFER_OUTPUT;
+ new_buf_count.buffer_count_actual = *num_buffers;
+ rc = call_hfi_op(hdev, session_set_property, inst->session,
+ property_id, &new_buf_count);
break;
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
@@ -913,7 +969,7 @@
case V4L2_MPEG_VIDEO_H264_LEVEL_4_2:
return HAL_H264_LEVEL_42;
case V4L2_MPEG_VIDEO_H264_LEVEL_5_0:
- return HAL_H264_LEVEL_3;
+ return HAL_H264_LEVEL_5;
case V4L2_MPEG_VIDEO_H264_LEVEL_5_1:
return HAL_H264_LEVEL_51;
default:
@@ -1434,6 +1490,15 @@
}
pdata = &enable;
break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA:
+ {
+ struct hal_extradata_enable extra;
+ property_id = HAL_PARAM_INDEX_EXTRADATA;
+ extra.index = msm_comm_get_hal_extradata_index(ctrl->val);
+ extra.enable = 1;
+ pdata = &extra;
+ break;
+ }
default:
rc = -ENOTSUPP;
break;
@@ -1750,6 +1815,7 @@
const struct msm_vidc_format *fmt = NULL;
int rc = 0;
int i;
+ int extra_idx = 0;
if (!inst || !f) {
dprintk(VIDC_ERR,
"Invalid input, inst = %p, format = %p\n", inst, f);
@@ -1770,6 +1836,16 @@
fmt->get_frame_size(i, inst->prop.height,
inst->prop.width);
}
+ extra_idx = EXTRADATA_IDX(fmt->num_planes);
+ if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) {
+ f->fmt.pix_mp.plane_fmt[extra_idx].sizeimage =
+ inst->buff_req.buffer
+ [HAL_BUFFER_EXTRADATA_OUTPUT].buffer_size;
+ }
+ for (i = 0; i < fmt->num_planes; ++i) {
+ inst->bufq[CAPTURE_PORT].vb2_bufq.plane_sizes[i] =
+ f->fmt.pix_mp.plane_fmt[i].sizeimage;
+ }
} else {
dprintk(VIDC_ERR,
"Buf type not recognized, type = %d\n", f->type);
@@ -1809,6 +1885,7 @@
int i;
struct vidc_buffer_addr_info buffer_info;
struct hfi_device *hdev;
+ int extra_idx = 0;
if (!inst || !inst->core || !inst->core->device) {
dprintk(VIDC_ERR, "%s invalid parameters", __func__);
@@ -1821,24 +1898,41 @@
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
- for (i = 0; i < b->length; i++) {
- dprintk(VIDC_DBG,
- "device_addr = %ld, size = %d\n",
+ if (b->length != inst->fmts[CAPTURE_PORT]->num_planes) {
+ dprintk(VIDC_ERR,
+ "Planes mismatch: needed: %d, allocated: %d\n",
+ inst->fmts[CAPTURE_PORT]->num_planes,
+ b->length);
+ rc = -EINVAL;
+ break;
+ }
+
+ for (i = 0; (i < b->length) && (i < VIDEO_MAX_PLANES); i++) {
+ dprintk(VIDC_DBG, "device_addr = 0x%lx, size = %d\n",
b->m.planes[i].m.userptr,
b->m.planes[i].length);
- buffer_info.buffer_size = b->m.planes[i].length;
- buffer_info.buffer_type = HAL_BUFFER_OUTPUT;
- buffer_info.num_buffers = 1;
- buffer_info.align_device_addr =
- b->m.planes[i].m.userptr;
- buffer_info.extradata_size = 0;
- buffer_info.extradata_addr = 0;
- rc = call_hfi_op(hdev, session_set_buffers,
- (void *)inst->session, &buffer_info);
- if (rc)
- dprintk(VIDC_ERR,
- "vidc_hal_session_set_buffers failed");
}
+ buffer_info.buffer_size = b->m.planes[0].length;
+ buffer_info.buffer_type = HAL_BUFFER_OUTPUT;
+ buffer_info.num_buffers = 1;
+ buffer_info.align_device_addr =
+ b->m.planes[0].m.userptr;
+
+ extra_idx = EXTRADATA_IDX(b->length);
+ if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) {
+ buffer_info.extradata_addr =
+ b->m.planes[extra_idx].m.userptr;
+ dprintk(VIDC_DBG, "extradata: 0x%lx\n",
+ b->m.planes[extra_idx].m.userptr);
+ buffer_info.extradata_size =
+ b->m.planes[extra_idx].length;
+ }
+
+ rc = call_hfi_op(hdev, session_set_buffers,
+ (void *)inst->session, &buffer_info);
+ if (rc)
+ dprintk(VIDC_ERR,
+ "vidc_hal_session_set_buffers failed");
break;
default:
dprintk(VIDC_ERR,
@@ -1851,8 +1945,7 @@
int msm_venc_release_buf(struct msm_vidc_inst *inst,
struct v4l2_buffer *b)
{
- int rc = 0;
- int i;
+ int i, rc = 0, extra_idx = 0;
struct vidc_buffer_addr_info buffer_info;
struct hfi_device *hdev;
@@ -1873,24 +1966,36 @@
switch (b->type) {
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
break;
- case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: {
+ if (b->length !=
+ inst->fmts[CAPTURE_PORT]->num_planes) {
+ dprintk(VIDC_ERR,
+ "Planes mismatch: needed: %d, to release: %d\n",
+ inst->fmts[CAPTURE_PORT]->num_planes,
+ b->length);
+ rc = -EINVAL;
+ break;
+ }
for (i = 0; i < b->length; i++) {
dprintk(VIDC_DBG,
- "Release device_addr = %ld, size = %d, %d\n",
+ "Release device_addr = 0x%lx, size = %d, %d\n",
b->m.planes[i].m.userptr,
b->m.planes[i].length, inst->state);
- buffer_info.buffer_size = b->m.planes[i].length;
- buffer_info.buffer_type = HAL_BUFFER_OUTPUT;
- buffer_info.num_buffers = 1;
- buffer_info.align_device_addr =
- b->m.planes[i].m.userptr;
- buffer_info.extradata_size = 0;
- buffer_info.extradata_addr = 0;
- buffer_info.response_required = false;
- rc = call_hfi_op(hdev, session_release_buffers,
+ }
+ buffer_info.buffer_size = b->m.planes[0].length;
+ buffer_info.buffer_type = HAL_BUFFER_OUTPUT;
+ buffer_info.num_buffers = 1;
+ buffer_info.align_device_addr =
+ b->m.planes[0].m.userptr;
+ extra_idx = EXTRADATA_IDX(b->length);
+ if (extra_idx && (extra_idx < VIDEO_MAX_PLANES))
+ buffer_info.extradata_addr =
+ b->m.planes[extra_idx].m.userptr;
+ buffer_info.response_required = false;
+ rc = call_hfi_op(hdev, session_release_buffers,
(void *)inst->session, &buffer_info);
- if (rc)
- dprintk(VIDC_ERR,
+ if (rc)
+ dprintk(VIDC_ERR,
"vidc_hal_session_release_buffers failed\n");
}
break;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 9f5f5af..d43e5ba 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -1929,6 +1929,12 @@
rc = -ENOMEM;
goto err_no_mem;
}
+ rc = msm_smem_cache_operations(inst->mem_client,
+ handle, SMEM_CACHE_CLEAN);
+ if (rc) {
+ dprintk(VIDC_WARN,
+ "Failed to clean cache may cause undefined behavior\n");
+ }
binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
if (!binfo) {
dprintk(VIDC_ERR, "Out of memory\n");
@@ -2014,6 +2020,12 @@
rc = -ENOMEM;
goto err_no_mem;
}
+ rc = msm_smem_cache_operations(inst->mem_client,
+ handle, SMEM_CACHE_CLEAN);
+ if (rc) {
+ dprintk(VIDC_WARN,
+ "Failed to clean cache may cause undefined behavior\n");
+ }
binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
if (!binfo) {
dprintk(VIDC_ERR, "Out of memory\n");
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index 80fc832..6d07165 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -353,20 +353,19 @@
rc = -ENOMEM;
goto fail_smem_alloc;
}
- rc = msm_smem_clean_invalidate(clnt, alloc);
- if (rc) {
- dprintk(VIDC_ERR, "NOTE: Failed to clean caches\n");
- goto fail_clean_cache;
- }
dprintk(VIDC_DBG, "venus_hfi_alloc:ptr=%p,size=%d",
alloc->kvaddr, size);
+ rc = msm_smem_cache_operations(clnt, alloc,
+ SMEM_CACHE_CLEAN);
+ if (rc) {
+ dprintk(VIDC_WARN, "Failed to clean cache\n");
+ dprintk(VIDC_WARN, "This may result in undefined behavior\n");
+ }
vmem->mem_size = alloc->size;
vmem->mem_data = alloc;
vmem->align_virtual_addr = (u8 *) alloc->kvaddr;
vmem->align_device_addr = (u8 *)alloc->device_addr;
return rc;
-fail_clean_cache:
- msm_smem_free(clnt, alloc);
fail_smem_alloc:
return rc;
}
@@ -2064,6 +2063,8 @@
sizeof(io_map[NS_MAP].ctx));
for (i = 0; i < MAX_MAP; i++) {
+ if (!res->iommu_maps[i].addr_range[1])
+ continue;
memcpy(io_map[i].addr_range, &res->iommu_maps[i].addr_range,
sizeof(u32) * 2);
@@ -2482,6 +2483,8 @@
for (i = 0; i < MAX_MAP; i++) {
io_map = &device->resources.io_map[i];
+ if (!io_map->domain)
+ continue;
dev = msm_iommu_get_ctx(io_map->ctx);
domain = msm_get_iommu_domain(io_map->domain);
if (IS_ERR_OR_NULL(domain)) {
@@ -2566,7 +2569,6 @@
unsigned int resp = 0;
int rc = 0;
struct msm_vidc_iommu_info *io_map;
-
if (!device)
return -EINVAL;
@@ -2575,6 +2577,8 @@
dprintk(VIDC_ERR, "invalid params: %p\n", io_map);
return -EINVAL;
}
+ if (!io_map[CP_MAP].addr_range[1])
+ return 0;
memprot.cp_start = 0x0;
memprot.cp_size = io_map[CP_MAP].addr_range[0] +
io_map[CP_MAP].addr_range[1];
@@ -2601,6 +2605,12 @@
return -EINVAL;
}
+ rc = venus_hfi_iommu_attach(device);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to attach iommu");
+ goto fail_iommu_attach;
+ }
+
if (!device->resources.fw.cookie)
device->resources.fw.cookie = subsystem_get("venus");
@@ -2620,21 +2630,18 @@
rc = protect_cp_mem(device);
if (rc) {
dprintk(VIDC_ERR, "Failed to protect memory\n");
- goto fail_iommu_attach;
+ goto fail_protect_mem;
}
- rc = venus_hfi_iommu_attach(device);
- if (rc) {
- dprintk(VIDC_ERR, "Failed to attach iommu");
- goto fail_iommu_attach;
- }
return rc;
-fail_iommu_attach:
+fail_protect_mem:
venus_hfi_disable_clks(device);
fail_enable_clks:
subsystem_put(device->resources.fw.cookie);
device->resources.fw.cookie = NULL;
fail_load_fw:
+ venus_hfi_iommu_detach(device);
+fail_iommu_attach:
return rc;
}
@@ -2647,9 +2654,9 @@
return;
}
if (device->resources.fw.cookie) {
- venus_hfi_iommu_detach(device);
venus_hfi_disable_clks(device);
subsystem_put(device->resources.fw.cookie);
+ venus_hfi_iommu_detach(device);
device->resources.fw.cookie = NULL;
}
}
diff --git a/drivers/media/platform/msm/wfd/enc-venus-subdev.c b/drivers/media/platform/msm/wfd/enc-venus-subdev.c
index 73a3d8e..00d0d07 100644
--- a/drivers/media/platform/msm/wfd/enc-venus-subdev.c
+++ b/drivers/media/platform/msm/wfd/enc-venus-subdev.c
@@ -549,12 +549,30 @@
return rc;
}
+static void populate_planes(struct v4l2_plane *planes, int num_planes,
+ void *userptr, int size)
+{
+ int c = 0;
+
+ planes[0] = (struct v4l2_plane) {
+ .length = size,
+ .m.userptr = (int)userptr,
+ };
+
+ for (c = 1; c < num_planes - 1; ++c) {
+ planes[c] = (struct v4l2_plane) {
+ .length = 0,
+ .m.userptr = (int)NULL,
+ };
+ }
+}
+
static long venc_set_input_buffer(struct v4l2_subdev *sd, void *arg)
{
int rc = 0;
struct venc_inst *inst = NULL;
struct v4l2_buffer buf = {0};
- struct v4l2_plane plane = {0};
+ struct v4l2_plane *planes = NULL;
struct mem_region *mregion = arg;
if (!sd) {
@@ -575,20 +593,21 @@
}
mregion = kzalloc(sizeof(*mregion), GFP_KERNEL);
- *mregion = *(struct mem_region *)arg;
+ planes = kzalloc(sizeof(*planes) * inst->num_input_planes, GFP_KERNEL);
+ if (!mregion || !planes)
+ return -ENOMEM;
- plane = (struct v4l2_plane) {
- .length = mregion->size,
- .m.userptr = (u32)mregion->paddr,
- };
+ *mregion = *(struct mem_region *)arg;
+ populate_planes(planes, inst->num_input_planes,
+ mregion->paddr, mregion->size);
buf = (struct v4l2_buffer) {
.index = get_list_len(&inst->registered_input_bufs),
.type = BUF_TYPE_INPUT,
.bytesused = 0,
.memory = V4L2_MEMORY_USERPTR,
- .m.planes = &plane,
- .length = 1,
+ .m.planes = planes,
+ .length = inst->num_input_planes,
};
WFD_MSG_DBG("Prepare %p with index, %d",
@@ -600,9 +619,12 @@
}
list_add_tail(&mregion->list, &inst->registered_input_bufs.list);
+
+ kfree(planes);
return 0;
set_input_buffer_fail:
kfree(mregion);
+ kfree(planes);
return rc;
}
@@ -689,7 +711,7 @@
int rc = 0;
struct venc_inst *inst = NULL;
struct v4l2_buffer buf = {0};
- struct v4l2_plane plane = {0};
+ struct v4l2_plane *planes = NULL;
struct mem_region *mregion = arg;
if (!sd) {
@@ -712,8 +734,9 @@
}
mregion = kzalloc(sizeof(*mregion), GFP_KERNEL);
+ planes = kzalloc(sizeof(*planes) * inst->num_output_planes, GFP_KERNEL);
- if (!mregion) {
+ if (!mregion || !planes) {
WFD_MSG_ERR("Failed to allocate memory\n");
goto venc_set_output_buffer_fail;
}
@@ -727,18 +750,16 @@
goto venc_set_output_buffer_map_fail;
}
- plane = (struct v4l2_plane) {
- .length = mregion->size,
- .m.userptr = (u32)mregion->paddr,
- };
+ populate_planes(planes, inst->num_output_planes,
+ mregion->paddr, mregion->size);
buf = (struct v4l2_buffer) {
.index = get_list_len(&inst->registered_output_bufs),
.type = BUF_TYPE_OUTPUT,
.bytesused = 0,
.memory = V4L2_MEMORY_USERPTR,
- .m.planes = &plane,
- .length = 1,
+ .m.planes = planes,
+ .length = inst->num_output_planes,
};
WFD_MSG_DBG("Prepare %p with index, %d",
@@ -750,11 +771,14 @@
}
list_add_tail(&mregion->list, &inst->registered_output_bufs.list);
- return rc;
+
+ kfree(planes);
+ return 0;
venc_set_output_buffer_prepare_fail:
venc_unmap_user_to_kernel(inst, mregion);
venc_set_output_buffer_map_fail:
kfree(mregion);
+ kfree(planes);
venc_set_output_buffer_fail:
return rc;
}
diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c
index 4ea7013..6c60e04 100644
--- a/drivers/mfd/wcd9xxx-core.c
+++ b/drivers/mfd/wcd9xxx-core.c
@@ -59,12 +59,12 @@
};
static char *taiko_supplies[] = {
- "cdc-vdd-buck", "cdc-vdd-tx-h", "cdc-vdd-rx-h", "cdc-vddpx-1",
+ WCD9XXX_SUPPLY_BUCK_NAME, "cdc-vdd-tx-h", "cdc-vdd-rx-h", "cdc-vddpx-1",
"cdc-vdd-a-1p2v", "cdc-vddcx-1", "cdc-vddcx-2",
};
static char *tapan_supplies[] = {
- "cdc-vdd-buck", "cdc-vdd-h", "cdc-vdd-px",
+ WCD9XXX_SUPPLY_BUCK_NAME, "cdc-vdd-h", "cdc-vdd-px",
"cdc-vdd-a-1p2v", "cdc-vdd-cx"
};
diff --git a/drivers/mfd/wcd9xxx-slimslave.c b/drivers/mfd/wcd9xxx-slimslave.c
index 0bce766..f2d71b6 100644
--- a/drivers/mfd/wcd9xxx-slimslave.c
+++ b/drivers/mfd/wcd9xxx-slimslave.c
@@ -214,7 +214,7 @@
prop.dataf = SLIM_CH_DATAF_NOT_DEFINED;
prop.auxf = SLIM_CH_AUXF_NOT_APPLICABLE;
prop.ratem = (rate/4000);
- prop.sampleszbits = 16;
+ prop.sampleszbits = bit_width;
pr_debug("Before slim_define_ch:\n"
"ch_cnt %d,ch_h[0] %d ch_h[1] %d, grph %d\n",
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index 2910a37..8aa4758 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -1604,8 +1604,8 @@
int qseecom_shutdown_app(struct qseecom_handle **handle)
{
int ret = -EINVAL;
- struct qseecom_dev_handle *data =
- (struct qseecom_dev_handle *) ((*handle)->dev);
+ struct qseecom_dev_handle *data;
+
struct qseecom_registered_kclient_list *kclient = NULL;
unsigned long flags = 0;
bool found_handle = false;
@@ -1614,11 +1614,11 @@
pr_err("This functionality is UNSUPPORTED in version 1.3\n");
return -EINVAL;
}
- if (*handle == NULL) {
+ if ((handle == NULL) || (*handle == NULL)) {
pr_err("Handle is not initialized\n");
return -EINVAL;
}
-
+ data = (struct qseecom_dev_handle *) ((*handle)->dev);
spin_lock_irqsave(&qseecom.registered_kclient_list_lock, flags);
list_for_each_entry(kclient, &qseecom.registered_kclient_list_head,
list) {
diff --git a/drivers/misc/tspp.c b/drivers/misc/tspp.c
index 9a53817..9598d45 100644
--- a/drivers/misc/tspp.c
+++ b/drivers/misc/tspp.c
@@ -763,6 +763,11 @@
/*** Clock functions ***/
static int tspp_clock_start(struct tspp_device *device)
{
+ if (device == NULL) {
+ pr_err("tspp: Can't start clocks, invalid device\n");
+ return -EINVAL;
+ }
+
if (device->tsif_pclk && clk_prepare_enable(device->tsif_pclk) != 0) {
pr_err("tspp: Can't start pclk");
return -EBUSY;
@@ -780,11 +785,16 @@
static void tspp_clock_stop(struct tspp_device *device)
{
+ if (device == NULL) {
+ pr_err("tspp: Can't stop clocks, invalid device\n");
+ return;
+ }
+
if (device->tsif_pclk)
- clk_disable(device->tsif_pclk);
+ clk_disable_unprepare(device->tsif_pclk);
if (device->tsif_ref_clk)
- clk_disable(device->tsif_ref_clk);
+ clk_disable_unprepare(device->tsif_ref_clk);
}
/*** TSIF functions ***/
@@ -1458,7 +1468,10 @@
/* start the clocks if needed */
if (tspp_channels_in_use(pdev) == 0) {
- tspp_clock_start(pdev);
+ rc = tspp_clock_start(pdev);
+ if (rc)
+ return rc;
+
wake_lock(&pdev->wake_lock);
}
@@ -1637,6 +1650,8 @@
tspp_clock_stop(pdev);
}
+ pm_runtime_put(&pdev->pdev->dev);
+
return 0;
}
EXPORT_SYMBOL(tspp_close_channel);
@@ -3021,6 +3036,7 @@
{
struct tspp_channel *channel;
u32 i;
+ int rc;
struct tspp_device *device = platform_get_drvdata(pdev);
@@ -3033,9 +3049,11 @@
}
/* de-registering BAM device requires clocks */
- tspp_clock_start(device);
- sps_deregister_bam_device(device->bam_handle);
- tspp_clock_stop(device);
+ rc = tspp_clock_start(device);
+ if (rc == 0) {
+ sps_deregister_bam_device(device->bam_handle);
+ tspp_clock_stop(device);
+ }
for (i = 0; i < TSPP_TSIF_INSTANCES; i++) {
tsif_debugfs_exit(&device->tsif[i]);
@@ -3058,7 +3076,7 @@
clk_put(device->tsif_pclk);
pm_runtime_disable(&pdev->dev);
- pm_runtime_put(&pdev->dev);
+
kfree(device);
return 0;
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index a8e5c97..b386266 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -1888,7 +1888,9 @@
* will take care of signaling sdio irq during
* mmc_sdio_resume().
*/
- if (host->sdcc_suspended) {
+ if (host->sdcc_suspended &&
+ (host->plat->mpm_sdiowakeup_int ||
+ host->plat->sdiowakeup_irq)) {
/*
* This is a wakeup interrupt so hold wakelock
* until SDCC resume is handled.
@@ -2198,6 +2200,7 @@
{
struct msmsdcc_host *host = mmc_priv(mmc);
unsigned long flags;
+ unsigned int error = 0;
int retries = 5;
/*
@@ -2207,6 +2210,18 @@
if (host->plat->is_sdio_al_client)
msmsdcc_sdio_al_lpm(mmc, false);
+ /*
+ * Don't start the request if SDCC is not in proper state to handle it
+ * BAM state is checked below if applicable
+ */
+ if (!host->pwr || !atomic_read(&host->clks_on) ||
+ host->sdcc_irq_disabled) {
+ WARN(1, "%s: %s: SDCC is in bad state. don't process new request (CMD%d)\n",
+ mmc_hostname(host->mmc), __func__, mrq->cmd->opcode);
+ error = EIO;
+ goto bad_state;
+ }
+
/* check if sps bam needs to be reset */
if (is_sps_mode(host) && host->sps.reset_bam) {
while (retries) {
@@ -2215,6 +2230,14 @@
pr_err("%s: msmsdcc_bam_dml_reset_and_restore returned error. %d attempts left.\n",
mmc_hostname(host->mmc), --retries);
}
+
+ /* check if BAM reset succeeded or not */
+ if (host->sps.reset_bam) {
+ pr_err("%s: bam reset failed. Not processing the new request (CMD%d)\n",
+ mmc_hostname(host->mmc), mrq->cmd->opcode);
+ error = EAGAIN;
+ goto bad_state;
+ }
}
/*
@@ -2233,33 +2256,9 @@
MMC_SEND_TUNING_BLOCK_HS200);
}
- spin_lock_irqsave(&host->lock, flags);
-
if (host->eject) {
- mrq->cmd->error = -ENOMEDIUM;
- spin_unlock_irqrestore(&host->lock, flags);
- mmc_request_done(mmc, mrq);
- return;
- }
-
- /*
- * Don't start the request if SDCC is not in proper state to handle it
- */
- if (!host->pwr || !atomic_read(&host->clks_on) ||
- host->sdcc_irq_disabled ||
- host->sps.reset_bam) {
- WARN(1, "%s: %s: SDCC is in bad state. don't process"
- " new request (CMD%d)\n", mmc_hostname(host->mmc),
- __func__, mrq->cmd->opcode);
- msmsdcc_dump_sdcc_state(host);
- mrq->cmd->error = -EIO;
- if (mrq->data) {
- mrq->data->error = -EIO;
- mrq->data->bytes_xfered = 0;
- }
- spin_unlock_irqrestore(&host->lock, flags);
- mmc_request_done(mmc, mrq);
- return;
+ error = ENOMEDIUM;
+ goto card_ejected;
}
WARN(host->curr.mrq, "%s: %s: New request (CMD%d) received while"
@@ -2267,6 +2266,8 @@
mmc_hostname(host->mmc), __func__,
mrq->cmd->opcode, host->curr.mrq->cmd->opcode);
+ spin_lock_irqsave(&host->lock, flags);
+
/*
* Set timeout value to 10 secs (or more in case of buggy cards)
*/
@@ -2305,8 +2306,18 @@
}
msmsdcc_request_start(host, mrq);
-
spin_unlock_irqrestore(&host->lock, flags);
+ return;
+
+bad_state:
+ msmsdcc_dump_sdcc_state(host);
+card_ejected:
+ mrq->cmd->error = -error;
+ if (mrq->data) {
+ mrq->data->error = -error;
+ mrq->data->bytes_xfered = 0;
+ }
+ mmc_request_done(mmc, mrq);
}
static inline int msmsdcc_vreg_set_voltage(struct msm_mmc_reg_data *vreg,
@@ -6160,8 +6171,6 @@
}
if (plat->sdiowakeup_irq) {
- wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
- mmc_hostname(mmc));
ret = request_irq(plat->sdiowakeup_irq,
msmsdcc_platform_sdiowakeup_irq,
IRQF_SHARED | IRQF_TRIGGER_LOW,
@@ -6180,7 +6189,7 @@
}
}
- if (host->plat->mpm_sdiowakeup_int) {
+ if (plat->sdiowakeup_irq || plat->mpm_sdiowakeup_int) {
wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
mmc_hostname(mmc));
}
@@ -6385,12 +6394,12 @@
free_irq(plat->status_irq, host);
msmsdcc_disable_status_gpio(host);
sdiowakeup_irq_free:
+ if (plat->sdiowakeup_irq || plat->mpm_sdiowakeup_int)
+ wake_lock_destroy(&host->sdio_wlock);
wake_lock_destroy(&host->sdio_suspend_wlock);
if (plat->sdiowakeup_irq)
free_irq(plat->sdiowakeup_irq, host);
pio_irq_free:
- if (plat->sdiowakeup_irq)
- wake_lock_destroy(&host->sdio_wlock);
free_irq(core_irqres->start, host);
irq_free:
free_irq(core_irqres->start, host);
@@ -6484,11 +6493,13 @@
wake_lock_destroy(&host->sdio_suspend_wlock);
if (plat->sdiowakeup_irq) {
- wake_lock_destroy(&host->sdio_wlock);
irq_set_irq_wake(plat->sdiowakeup_irq, 0);
free_irq(plat->sdiowakeup_irq, host);
}
+ if (plat->sdiowakeup_irq || plat->mpm_sdiowakeup_int)
+ wake_lock_destroy(&host->sdio_wlock);
+
free_irq(host->core_irqres->start, host);
free_irq(host->core_irqres->start, host);
diff --git a/drivers/mmc/host/msm_sdcc.h b/drivers/mmc/host/msm_sdcc.h
index abb54fe..b5522fb 100644
--- a/drivers/mmc/host/msm_sdcc.h
+++ b/drivers/mmc/host/msm_sdcc.h
@@ -504,10 +504,8 @@
host->hw_caps |= MSMSDCC_SW_RST | MSMSDCC_SW_RST_CFG |
MSMSDCC_AUTO_CMD21 |
MSMSDCC_DATA_PEND_FOR_CMD53 |
- MSMSDCC_TESTBUS_DEBUG;
-
- if ((step == 0x2b) || (step == 0x38))
- host->hw_caps |= MSMSDCC_SW_RST_CFG_BROKEN;
+ MSMSDCC_TESTBUS_DEBUG |
+ MSMSDCC_SW_RST_CFG_BROKEN;
}
int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave);
diff --git a/drivers/platform/msm/Kconfig b/drivers/platform/msm/Kconfig
index 9394986..f4dff66 100644
--- a/drivers/platform/msm/Kconfig
+++ b/drivers/platform/msm/Kconfig
@@ -73,6 +73,15 @@
PMIC. These clocks are typically wired through alternate functions
on gpio pins.
+config QPNP_VIBRATOR
+ tristate "Vibrator support for QPNP PMIC"
+ depends on OF_SPMI
+ help
+ This option enables device driver support for the vibrator
+ on the Qualcomm's QPNP PMICs. The vibrator is connected on the
+ VIB_DRV_N line and can be controlled manually or by the DTEST lines.
+ It uses the android timed-output framework.
+
config IPA
tristate "IPA support"
depends on SPS
diff --git a/drivers/platform/msm/Makefile b/drivers/platform/msm/Makefile
index 919c07f..a679fb9 100644
--- a/drivers/platform/msm/Makefile
+++ b/drivers/platform/msm/Makefile
@@ -7,5 +7,6 @@
obj-$(CONFIG_SPS) += sps/
obj-$(CONFIG_QPNP_PWM) += qpnp-pwm.o
obj-$(CONFIG_QPNP_POWER_ON) += qpnp-power-on.o
+obj-$(CONFIG_QPNP_VIBRATOR) += qpnp-vibrator.o
obj-$(CONFIG_QPNP_CLKDIV) += qpnp-clkdiv.o
obj-$(CONFIG_MSM_AVTIMER) += avtimer.o
diff --git a/drivers/platform/msm/ipa/Makefile b/drivers/platform/msm/ipa/Makefile
index ded5b50..c541eb7 100644
--- a/drivers/platform/msm/ipa/Makefile
+++ b/drivers/platform/msm/ipa/Makefile
@@ -1,3 +1,3 @@
obj-$(CONFIG_IPA) += ipat.o
ipat-y := ipa.o ipa_debugfs.o ipa_hdr.o ipa_flt.o ipa_rt.o ipa_dp.o ipa_client.o \
- ipa_utils.o ipa_nat.o rmnet_bridge.o a2_service.o ipa_bridge.o
+ ipa_utils.o ipa_nat.o rmnet_bridge.o a2_service.o ipa_bridge.o ipa_intf.o
diff --git a/drivers/platform/msm/ipa/ipa.c b/drivers/platform/msm/ipa/ipa.c
index 4a01c44..7690b21 100644
--- a/drivers/platform/msm/ipa/ipa.c
+++ b/drivers/platform/msm/ipa/ipa.c
@@ -23,12 +23,13 @@
#include <linux/platform_device.h>
#include <linux/rbtree.h>
#include <linux/uaccess.h>
+#include <mach/msm_bus.h>
+#include <mach/msm_bus_board.h>
#include "ipa_i.h"
#define IPA_SUMMING_THRESHOLD (0x10)
#define IPA_PIPE_MEM_START_OFST (0x0)
#define IPA_PIPE_MEM_SIZE (0x0)
-#define IPA_READ_MAX (16)
#define IPA_MOBILE_AP_MODE(x) (x == IPA_MODE_MOBILE_AP_ETH || \
x == IPA_MODE_MOBILE_AP_WAN || \
x == IPA_MODE_MOBILE_AP_WLAN)
@@ -39,7 +40,6 @@
#define IPA_DMA_POOL_SIZE (512)
#define IPA_DMA_POOL_ALIGNMENT (4)
#define IPA_DMA_POOL_BOUNDARY (1024)
-#define WLAN_AMPDU_TX_EP (15)
#define IPA_ROUTING_RULE_BYTE_SIZE (4)
#define IPA_BAM_CNFG_BITS_VAL (0x7FFFE004)
@@ -63,8 +63,45 @@
static struct clk *sys_noc_ipa_axi_clk;
static struct clk *ipa_cnoc_clk;
static struct clk *ipa_inactivity_clk;
-static struct device *ipa_dev;
+static struct msm_bus_vectors ipa_init_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_IPA,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 0,
+ .ib = 0,
+ },
+};
+
+static struct msm_bus_vectors ipa_max_perf_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_IPA,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 50000000,
+ .ib = 960000000,
+ },
+};
+
+static struct msm_bus_paths ipa_usecases[] = {
+ {
+ ARRAY_SIZE(ipa_init_vectors),
+ ipa_init_vectors,
+ },
+ {
+ ARRAY_SIZE(ipa_max_perf_vectors),
+ ipa_max_perf_vectors,
+ },
+};
+
+static struct msm_bus_scale_pdata ipa_bus_client_pdata = {
+ ipa_usecases,
+ ARRAY_SIZE(ipa_usecases),
+ .name = "ipa",
+};
+
+static uint32_t ipa_bus_hdl;
+
+static struct device *ipa_dev;
struct ipa_context *ipa_ctx;
static bool polling_mode;
@@ -103,28 +140,6 @@
static void ipa_set_aggregation_params(void);
-static ssize_t ipa_read(struct file *filp, char __user *buf, size_t count,
- loff_t *f_pos)
-{
- u32 reg_val = 0xfeedface;
- char str[IPA_READ_MAX];
- int result;
- static int read_cnt;
-
- if (read_cnt) {
- IPAERR("only supports one call to read\n");
- return 0;
- }
-
- reg_val = ipa_read_reg(ipa_ctx->mmio, IPA_COMP_HW_VERSION_OFST);
- result = scnprintf(str, IPA_READ_MAX, "%x\n", reg_val);
- if (copy_to_user(buf, str, result))
- return -EFAULT;
- read_cnt = 1;
-
- return result;
-}
-
static int ipa_open(struct inode *inode, struct file *filp)
{
struct ipa_context *ctx = NULL;
@@ -145,6 +160,7 @@
struct ipa_ioc_nat_alloc_mem nat_mem;
struct ipa_ioc_v4_nat_init nat_init;
struct ipa_ioc_v4_nat_del nat_del;
+ size_t sz;
IPADBG("cmd=%x nr=%d\n", cmd, _IOC_NR(cmd));
@@ -475,6 +491,107 @@
break;
}
break;
+ case IPA_IOC_QUERY_INTF:
+ if (copy_from_user(header, (u8 *)arg,
+ sizeof(struct ipa_ioc_query_intf))) {
+ retval = -EFAULT;
+ break;
+ }
+ if (ipa_query_intf((struct ipa_ioc_query_intf *)header)) {
+ retval = -1;
+ break;
+ }
+ if (copy_to_user((u8 *)arg, header,
+ sizeof(struct ipa_ioc_query_intf))) {
+ retval = -EFAULT;
+ break;
+ }
+ break;
+ case IPA_IOC_QUERY_INTF_TX_PROPS:
+ sz = sizeof(struct ipa_ioc_query_intf_tx_props);
+ if (copy_from_user(header, (u8 *)arg, sz)) {
+ retval = -EFAULT;
+ break;
+ }
+ pyld_sz = sz + ((struct ipa_ioc_query_intf_tx_props *)
+ header)->num_tx_props *
+ sizeof(struct ipa_ioc_tx_intf_prop);
+ param = kzalloc(pyld_sz, GFP_KERNEL);
+ if (!param) {
+ retval = -ENOMEM;
+ break;
+ }
+ if (copy_from_user(param, (u8 *)arg, pyld_sz)) {
+ retval = -EFAULT;
+ break;
+ }
+ if (ipa_query_intf_tx_props(
+ (struct ipa_ioc_query_intf_tx_props *)param)) {
+ retval = -1;
+ break;
+ }
+ if (copy_to_user((u8 *)arg, param, pyld_sz)) {
+ retval = -EFAULT;
+ break;
+ }
+ break;
+ case IPA_IOC_QUERY_INTF_RX_PROPS:
+ sz = sizeof(struct ipa_ioc_query_intf_rx_props);
+ if (copy_from_user(header, (u8 *)arg, sz)) {
+ retval = -EFAULT;
+ break;
+ }
+ pyld_sz = sz + ((struct ipa_ioc_query_intf_rx_props *)
+ header)->num_rx_props *
+ sizeof(struct ipa_ioc_rx_intf_prop);
+ param = kzalloc(pyld_sz, GFP_KERNEL);
+ if (!param) {
+ retval = -ENOMEM;
+ break;
+ }
+ if (copy_from_user(param, (u8 *)arg, pyld_sz)) {
+ retval = -EFAULT;
+ break;
+ }
+ if (ipa_query_intf_rx_props(
+ (struct ipa_ioc_query_intf_rx_props *)param)) {
+ retval = -1;
+ break;
+ }
+ if (copy_to_user((u8 *)arg, param, pyld_sz)) {
+ retval = -EFAULT;
+ break;
+ }
+ break;
+ case IPA_IOC_PULL_MSG:
+ if (copy_from_user(header, (u8 *)arg,
+ sizeof(struct ipa_msg_meta))) {
+ retval = -EFAULT;
+ break;
+ }
+ pyld_sz = sizeof(struct ipa_msg_meta) +
+ ((struct ipa_msg_meta *)header)->msg_len;
+ param = kzalloc(pyld_sz, GFP_KERNEL);
+ if (!param) {
+ retval = -ENOMEM;
+ break;
+ }
+ if (copy_from_user(param, (u8 *)arg, pyld_sz)) {
+ retval = -EFAULT;
+ break;
+ }
+ if (ipa_pull_msg((struct ipa_msg_meta *)param,
+ (char *)param + sizeof(struct ipa_msg_meta),
+ ((struct ipa_msg_meta *)param)->msg_len) !=
+ ((struct ipa_msg_meta *)param)->msg_len) {
+ retval = -1;
+ break;
+ }
+ if (copy_to_user((u8 *)arg, param, pyld_sz)) {
+ retval = -EFAULT;
+ break;
+ }
+ break;
default: /* redundant, as cmd was checked against MAXNR */
return -ENOTTY;
}
@@ -572,7 +689,7 @@
hdr_entry->hdr_len = 1;
hdr_entry->hdr[0] = 0;
} else {
- hdr_entry->hdr_len = IPA_DEFAULT_HEADER_LENGTH;
+ hdr_entry->hdr_len = IPA_DEFAULT_HEADER_LENGTH;
}
/*
@@ -609,14 +726,16 @@
return ret;
}
-static void ipa_handle_tx_poll_for_pipe(struct ipa_sys_context *sys)
+static int ipa_handle_tx_poll_for_pipe(struct ipa_sys_context *sys,
+ bool process_all)
{
struct ipa_tx_pkt_wrapper *tx_pkt, *t;
struct sps_iovec iov;
unsigned long irq_flags;
int ret;
+ int cnt = 0;
- while (1) {
+ do {
iov.addr = 0;
ret = sps_get_iovec(sys->ep->ep_hdl, &iov);
if (ret) {
@@ -633,6 +752,7 @@
switch (tx_pkt->cnt) {
case 1:
ipa_wq_write_done(&tx_pkt->work);
+ ++cnt;
break;
case 0xFFFF:
/* reached end of set */
@@ -647,6 +767,7 @@
struct ipa_tx_pkt_wrapper, link);
spin_unlock_irqrestore(&sys->spinlock, irq_flags);
ipa_wq_write_done(&tx_pkt->work);
+ ++cnt;
break;
default:
/* keep looping till reach the end of the set */
@@ -657,9 +778,12 @@
&sys->wait_desc_list);
spin_unlock_irqrestore(&sys->spinlock,
irq_flags);
+ ++cnt;
break;
}
- }
+ } while (process_all);
+
+ return cnt;
}
static void ipa_poll_function(struct work_struct *work)
@@ -669,19 +793,26 @@
IPA_A5_WLAN_AMPDU_OUT };
int i;
int num_tx_pipes;
-
- /* check all the system pipes for tx completions and rx available */
- if (ipa_ctx->sys[IPA_A5_LAN_WAN_IN].ep->valid)
- ipa_handle_rx_core();
+ int cnt;
num_tx_pipes = sizeof(tx_pipes) / sizeof(tx_pipes[0]);
if (!IPA_MOBILE_AP_MODE(ipa_ctx->mode))
num_tx_pipes--;
- for (i = 0; i < num_tx_pipes; i++)
- if (ipa_ctx->sys[tx_pipes[i]].ep->valid)
- ipa_handle_tx_poll_for_pipe(&ipa_ctx->sys[tx_pipes[i]]);
+ do {
+ cnt = 0;
+
+ /* check all the system pipes for tx comp and rx avail */
+ if (ipa_ctx->sys[IPA_A5_LAN_WAN_IN].ep->valid)
+ cnt |= ipa_handle_rx_core(false);
+
+ for (i = 0; i < num_tx_pipes; i++)
+ if (ipa_ctx->sys[tx_pipes[i]].ep->valid)
+ cnt |= ipa_handle_tx_poll_for_pipe(
+ &ipa_ctx->sys[tx_pipes[i]],
+ false);
+ } while (cnt);
/* re-post the poll work */
INIT_DELAYED_WORK(&ipa_ctx->poll_work, ipa_poll_function);
@@ -763,6 +894,12 @@
fail_data_out:
ipa_teardown_sys_pipe(ipa_ctx->clnt_hdl_data_in);
fail_schedule_delayed_work:
+ if (ipa_ctx->dflt_v6_rt_rule_hdl)
+ __ipa_del_rt_rule(ipa_ctx->dflt_v6_rt_rule_hdl);
+ if (ipa_ctx->dflt_v4_rt_rule_hdl)
+ __ipa_del_rt_rule(ipa_ctx->dflt_v4_rt_rule_hdl);
+ if (ipa_ctx->excp_hdr_hdl)
+ __ipa_del_hdr(ipa_ctx->excp_hdr_hdl);
ipa_teardown_sys_pipe(ipa_ctx->clnt_hdl_cmd);
fail_cmd:
return result;
@@ -773,6 +910,9 @@
cancel_delayed_work(&ipa_ctx->poll_work);
ipa_teardown_sys_pipe(ipa_ctx->clnt_hdl_data_out);
ipa_teardown_sys_pipe(ipa_ctx->clnt_hdl_data_in);
+ __ipa_del_rt_rule(ipa_ctx->dflt_v6_rt_rule_hdl);
+ __ipa_del_rt_rule(ipa_ctx->dflt_v4_rt_rule_hdl);
+ __ipa_del_hdr(ipa_ctx->excp_hdr_hdl);
ipa_teardown_sys_pipe(ipa_ctx->clnt_hdl_cmd);
}
@@ -1235,6 +1375,9 @@
clk_enable(ipa_inactivity_clk);
else
WARN_ON(1);
+
+ if (msm_bus_scale_client_update_request(ipa_bus_hdl, 1))
+ WARN_ON(1);
}
/**
@@ -1264,6 +1407,9 @@
clk_disable_unprepare(ipa_cnoc_clk);
else
WARN_ON(1);
+
+ if (msm_bus_scale_client_update_request(ipa_bus_hdl, 0))
+ WARN_ON(1);
}
static int ipa_setup_bam_cfg(const struct ipa_plat_drv_res *res)
@@ -1282,6 +1428,76 @@
}
return 0;
}
+
+static int ipa_init_flt_block(void)
+{
+ int result = 0;
+
+ /*
+ * SW workaround for Improper Filter Behaviour when neiher Global nor
+ * Pipe Rules are present => configure dummy global filter rule
+ * always which results in a miss
+ */
+ struct ipa_ioc_add_flt_rule *rules;
+ struct ipa_flt_rule_add *rule;
+ struct ipa_ioc_get_rt_tbl rt_lookup;
+ enum ipa_ip_type ip;
+
+ if (ipa_ctx->ipa_hw_type == IPA_HW_v1_1) {
+ size_t sz = sizeof(struct ipa_ioc_add_flt_rule) +
+ sizeof(struct ipa_flt_rule_add);
+
+ rules = kmalloc(sz, GFP_KERNEL);
+ if (rules == NULL) {
+ IPAERR("fail to alloc mem for dummy filter rule\n");
+ return -ENOMEM;
+ }
+
+ for (ip = IPA_IP_v4; ip < IPA_IP_MAX; ip++) {
+ memset(&rt_lookup, 0,
+ sizeof(struct ipa_ioc_get_rt_tbl));
+ rt_lookup.ip = ip;
+ strlcpy(rt_lookup.name, IPA_DFLT_RT_TBL_NAME,
+ IPA_RESOURCE_NAME_MAX);
+ ipa_get_rt_tbl(&rt_lookup);
+ ipa_put_rt_tbl(rt_lookup.hdl);
+
+ memset(rules, 0, sz);
+ rule = &rules->rules[0];
+ rules->commit = 1;
+ rules->ip = ip;
+ rules->global = 1;
+ rules->num_rules = 1;
+ rule->at_rear = 1;
+ if (ip == IPA_IP_v4) {
+ rule->rule.attrib.attrib_mask =
+ IPA_FLT_PROTOCOL;
+ rule->rule.attrib.u.v4.protocol =
+ IPA_INVALID_L4_PROTOCOL;
+ } else if (ip == IPA_IP_v6) {
+ rule->rule.attrib.attrib_mask =
+ IPA_FLT_NEXT_HDR;
+ rule->rule.attrib.u.v6.next_hdr =
+ IPA_INVALID_L4_PROTOCOL;
+ } else {
+ result = -EINVAL;
+ WARN_ON(1);
+ break;
+ }
+ rule->rule.action = IPA_PASS_TO_ROUTING;
+ rule->rule.rt_tbl_hdl = rt_lookup.hdl;
+
+ if (ipa_add_flt_rule(rules) || rules->rules[0].status) {
+ result = -EINVAL;
+ WARN_ON(1);
+ break;
+ }
+ }
+ kfree(rules);
+ }
+ return result;
+}
+
/**
* ipa_init() - Initialize the IPA Driver
*@resource_p: contain platform specific values from DST file
@@ -1340,8 +1556,10 @@
ipa_ctx->ip6_rt_tbl_lcl = ip6_rt_tbl_lcl;
ipa_ctx->ip4_flt_tbl_lcl = ip4_flt_tbl_lcl;
ipa_ctx->ip6_flt_tbl_lcl = ip6_flt_tbl_lcl;
+
ipa_ctx->ipa_wrapper_base = resource_p->ipa_mem_base;
ipa_ctx->ipa_hw_type = resource_p->ipa_hw_type;
+ ipa_ctx->ipa_hw_mode = resource_p->ipa_hw_mode;
/* setup IPA register access */
ipa_ctx->mmio = ioremap(resource_p->ipa_mem_base + IPA_REG_BASE_OFST,
@@ -1420,7 +1638,7 @@
}
/* set up the default op mode */
- ipa_ctx->mode = IPA_MODE_USB_DONGLE;
+ ipa_ctx->mode = IPA_MODE_MOBILE_AP_WAN;
/* init the lookaside cache */
ipa_ctx->flt_rule_cache = kmem_cache_create("IPA FLT",
@@ -1529,6 +1747,12 @@
rset = &ipa_ctx->reap_rt_tbl_set[IPA_IP_v6];
INIT_LIST_HEAD(&rset->head_rt_tbl_list);
+ INIT_LIST_HEAD(&ipa_ctx->intf_list);
+ INIT_LIST_HEAD(&ipa_ctx->msg_list);
+ INIT_LIST_HEAD(&ipa_ctx->pull_msg_list);
+ init_waitqueue_head(&ipa_ctx->msg_waitq);
+ mutex_init(&ipa_ctx->msg_lock);
+
mutex_init(&ipa_ctx->lock);
mutex_init(&ipa_ctx->nat_mem.lock);
@@ -1560,6 +1784,7 @@
ipa_ctx->rt_rule_hdl_tree = RB_ROOT;
ipa_ctx->rt_tbl_hdl_tree = RB_ROOT;
ipa_ctx->flt_rule_hdl_tree = RB_ROOT;
+ ipa_ctx->tag_tree = RB_ROOT;
atomic_set(&ipa_ctx->ipa_active_clients, 0);
@@ -1579,6 +1804,12 @@
ipa_replenish_rx_cache();
+ if (ipa_init_flt_block()) {
+ IPAERR("fail to setup dummy filter rules\n");
+ result = -ENODEV;
+ goto fail_empty_rt_tbl;
+ }
+
/*
* setup an empty routing table in system memory, this will be used
* to delete a routing table cleanly and safely
@@ -1634,10 +1865,12 @@
ipa_ctx->aggregation_type = IPA_MBIM_16;
ipa_ctx->aggregation_byte_limit = 1;
ipa_ctx->aggregation_time_limit = 0;
- IPADBG(":IPA driver init OK.\n");
/* gate IPA clocks */
- ipa_disable_clks();
+ if (ipa_ctx->ipa_hw_mode == IPA_HW_MODE_NORMAL)
+ ipa_disable_clks();
+
+ IPADBG(":IPA driver init OK.\n");
return 0;
@@ -1695,7 +1928,8 @@
ipa_ctx = NULL;
fail_mem:
/* gate IPA clocks */
- ipa_disable_clks();
+ if (ipa_ctx->ipa_hw_mode == IPA_HW_MODE_NORMAL)
+ ipa_disable_clks();
return result;
}
@@ -1710,6 +1944,7 @@
ipa_res.ipa_pipe_mem_start_ofst = IPA_PIPE_MEM_START_OFST;
ipa_res.ipa_pipe_mem_size = IPA_PIPE_MEM_SIZE;
ipa_res.ipa_hw_type = 0;
+ ipa_res.ipa_hw_mode = 0;
result = ipa_load_pipe_connection(pdev_p,
A2_TO_IPA,
@@ -1789,6 +2024,15 @@
}
IPADBG(": found ipa_res.ipa_hw_type = %d", ipa_res.ipa_hw_type);
+ /* Get IPA HW mode */
+ result = of_property_read_u32(pdev_p->dev.of_node, "ipa-hw-mode",
+ &ipa_res.ipa_hw_mode);
+
+ if (result)
+ IPADBG("using default (IPA_MODE_NORMAL) for ipa-hw-mode\n");
+ else
+ IPADBG(": found ipa_res.ipa_hw_mode = %d", ipa_res.ipa_hw_mode);
+
IPADBG(":ipa_mem_base = 0x%x, ipa_mem_size = 0x%x\n",
ipa_res.ipa_mem_base, ipa_res.ipa_mem_size);
IPADBG(":bam_mem_base = 0x%x, bam_mem_size = 0x%x\n",
@@ -1802,12 +2046,24 @@
/* stash the IPA dev ptr */
ipa_dev = &pdev_p->dev;
- /* get IPA clocks */
- if (ipa_get_clks(ipa_dev) != 0)
- return -ENODEV;
+ if (ipa_res.ipa_hw_mode == IPA_HW_MODE_NORMAL) {
+ /* get IPA clocks */
+ if (ipa_get_clks(ipa_dev) != 0) {
+ IPAERR(":fail to get clk handle's!\n");
+ return -ENODEV;
+ }
- /* enable IPA clocks */
- ipa_enable_clks();
+ /* get BUS handle */
+ ipa_bus_hdl =
+ msm_bus_scale_register_client(&ipa_bus_client_pdata);
+ if (!ipa_bus_hdl) {
+ IPAERR(":fail to register with bus mgr!\n");
+ return -ENODEV;
+ }
+
+ /* enable IPA clocks */
+ ipa_enable_clks();
+ }
/* Proceed to real initialization */
result = ipa_init(&ipa_res);
@@ -1841,11 +2097,6 @@
},
};
-static int ipa_plat_drv_init(void)
-{
- return platform_driver_register(&ipa_plat_drv);
-}
-
struct ipa_context *ipa_get_ctx(void)
{
return ipa_ctx;
@@ -1856,9 +2107,11 @@
int result = 0;
IPADBG("IPA module init\n");
- ipa_debugfs_init();
+
/* Register as a platform device driver */
- result = ipa_plat_drv_init();
+ platform_driver_register(&ipa_plat_drv);
+
+ ipa_debugfs_init();
return result;
}
diff --git a/drivers/platform/msm/ipa/ipa_bridge.c b/drivers/platform/msm/ipa/ipa_bridge.c
index a3de3ac..56e9b0d 100644
--- a/drivers/platform/msm/ipa/ipa_bridge.c
+++ b/drivers/platform/msm/ipa/ipa_bridge.c
@@ -14,23 +14,26 @@
#include <linux/ratelimit.h>
#include "ipa_i.h"
-enum ipa_bridge_id {
+#define A2_EMBEDDED_PIPE_TX 4
+#define A2_EMBEDDED_PIPE_RX 5
+
+enum ipa_pipe_type {
IPA_DL_FROM_A2,
IPA_DL_TO_IPA,
IPA_UL_FROM_IPA,
IPA_UL_TO_A2,
- IPA_BRIDGE_ID_MAX
+ IPA_PIPE_TYPE_MAX
};
-static int polling_min_sleep[IPA_DIR_MAX] = { 950, 950 };
-static int polling_max_sleep[IPA_DIR_MAX] = { 1050, 1050 };
-static int polling_inactivity[IPA_DIR_MAX] = { 4, 4 };
+static int polling_min_sleep[IPA_BRIDGE_DIR_MAX] = { 950, 950 };
+static int polling_max_sleep[IPA_BRIDGE_DIR_MAX] = { 1050, 1050 };
+static int polling_inactivity[IPA_BRIDGE_DIR_MAX] = { 4, 4 };
struct ipa_pkt_info {
void *buffer;
dma_addr_t dma_address;
uint32_t len;
- struct list_head list_node;
+ struct list_head link;
};
struct ipa_bridge_pipe_context {
@@ -45,48 +48,59 @@
struct list_head free_desc_list;
};
-static struct ipa_bridge_pipe_context bridge[IPA_BRIDGE_ID_MAX];
+struct ipa_bridge_context {
+ struct ipa_bridge_pipe_context pipe[IPA_PIPE_TYPE_MAX];
+ struct workqueue_struct *ul_wq;
+ struct workqueue_struct *dl_wq;
+ struct work_struct ul_work;
+ struct work_struct dl_work;
+ enum ipa_bridge_type type;
+};
-static struct workqueue_struct *ipa_ul_workqueue;
-static struct workqueue_struct *ipa_dl_workqueue;
-static void ipa_do_bridge_work(enum ipa_bridge_dir dir);
+static struct ipa_bridge_context bridge[IPA_BRIDGE_TYPE_MAX];
-static u32 alloc_cnt[IPA_DIR_MAX];
+static void ipa_do_bridge_work(enum ipa_bridge_dir dir,
+ struct ipa_bridge_context *ctx);
static void ul_work_func(struct work_struct *work)
{
- ipa_do_bridge_work(IPA_UL);
+ struct ipa_bridge_context *ctx = container_of(work,
+ struct ipa_bridge_context, ul_work);
+ ipa_do_bridge_work(IPA_BRIDGE_DIR_UL, ctx);
}
static void dl_work_func(struct work_struct *work)
{
- ipa_do_bridge_work(IPA_DL);
+ struct ipa_bridge_context *ctx = container_of(work,
+ struct ipa_bridge_context, dl_work);
+ ipa_do_bridge_work(IPA_BRIDGE_DIR_DL, ctx);
}
-static DECLARE_WORK(ul_work, ul_work_func);
-static DECLARE_WORK(dl_work, dl_work_func);
-
-static int ipa_switch_to_intr_mode(enum ipa_bridge_dir dir)
+static int ipa_switch_to_intr_mode(enum ipa_bridge_dir dir,
+ struct ipa_bridge_context *ctx)
{
int ret;
- struct ipa_bridge_pipe_context *sys = &bridge[2 * dir];
+ struct ipa_bridge_pipe_context *sys = &ctx->pipe[2 * dir];
ret = sps_get_config(sys->pipe, &sys->connection);
if (ret) {
- IPAERR("sps_get_config() failed %d\n", ret);
+ IPAERR("sps_get_config() failed %d type=%d dir=%d\n",
+ ret, ctx->type, dir);
goto fail;
}
sys->register_event.options = SPS_O_EOT;
ret = sps_register_event(sys->pipe, &sys->register_event);
if (ret) {
- IPAERR("sps_register_event() failed %d\n", ret);
+ IPAERR("sps_register_event() failed %d type=%d dir=%d\n",
+ ret, ctx->type, dir);
goto fail;
}
sys->connection.options =
SPS_O_AUTO_ENABLE | SPS_O_ACK_TRANSFERS | SPS_O_EOT;
ret = sps_set_config(sys->pipe, &sys->connection);
if (ret) {
- IPAERR("sps_set_config() failed %d\n", ret);
+ IPAERR("sps_set_config() failed %d type=%d dir=%d\n",
+ ret, ctx->type, dir);
goto fail;
}
ret = 0;
@@ -94,21 +108,24 @@
return ret;
}
-static int ipa_switch_to_poll_mode(enum ipa_bridge_dir dir)
+static int ipa_switch_to_poll_mode(enum ipa_bridge_dir dir,
+ enum ipa_bridge_type type)
{
int ret;
- struct ipa_bridge_pipe_context *sys = &bridge[2 * dir];
+ struct ipa_bridge_pipe_context *sys = &bridge[type].pipe[2 * dir];
ret = sps_get_config(sys->pipe, &sys->connection);
if (ret) {
- IPAERR("sps_get_config() failed %d\n", ret);
+ IPAERR("sps_get_config() failed %d type=%d dir=%d\n",
+ ret, type, dir);
goto fail;
}
sys->connection.options =
SPS_O_AUTO_ENABLE | SPS_O_ACK_TRANSFERS | SPS_O_POLL;
ret = sps_set_config(sys->pipe, &sys->connection);
if (ret) {
- IPAERR("sps_set_config() failed %d\n", ret);
+ IPAERR("sps_set_config() failed %d type=%d dir=%d\n",
+ ret, type, dir);
goto fail;
}
ret = 0;
@@ -116,43 +133,47 @@
return ret;
}
-static int queue_rx_single(enum ipa_bridge_dir dir)
+static int queue_rx_single(enum ipa_bridge_dir dir, enum ipa_bridge_type type)
{
- struct ipa_bridge_pipe_context *sys_rx = &bridge[2 * dir];
+ struct ipa_bridge_pipe_context *sys_rx = &bridge[type].pipe[2 * dir];
struct ipa_pkt_info *info;
int ret;
info = kmalloc(sizeof(struct ipa_pkt_info), GFP_KERNEL);
if (!info) {
- IPAERR("unable to alloc rx_pkt_info\n");
+ IPAERR("unable to alloc rx_pkt_info type=%d dir=%d\n",
+ type, dir);
goto fail_pkt;
}
info->buffer = kmalloc(IPA_RX_SKB_SIZE, GFP_KERNEL | GFP_DMA);
if (!info->buffer) {
- IPAERR("unable to alloc rx_pkt_buffer\n");
+ IPAERR("unable to alloc rx_pkt_buffer type=%d dir=%d\n",
+ type, dir);
goto fail_buffer;
}
info->dma_address = dma_map_single(NULL, info->buffer, IPA_RX_SKB_SIZE,
DMA_BIDIRECTIONAL);
if (info->dma_address == 0 || info->dma_address == ~0) {
- IPAERR("dma_map_single failure %p for %p\n",
- (void *)info->dma_address, info->buffer);
+ IPAERR("dma_map_single failure %p for %p type=%d dir=%d\n",
+ (void *)info->dma_address, info->buffer,
+ type, dir);
goto fail_dma;
}
info->len = ~0;
- list_add_tail(&info->list_node, &sys_rx->head_desc_list);
+ list_add_tail(&info->link, &sys_rx->head_desc_list);
ret = sps_transfer_one(sys_rx->pipe, info->dma_address,
IPA_RX_SKB_SIZE, info,
SPS_IOVEC_FLAG_INT | SPS_IOVEC_FLAG_EOT);
if (ret) {
- list_del(&info->list_node);
+ list_del(&info->link);
dma_unmap_single(NULL, info->dma_address, IPA_RX_SKB_SIZE,
DMA_BIDIRECTIONAL);
- IPAERR("sps_transfer_one failed %d\n", ret);
+ IPAERR("sps_transfer_one failed %d type=%d dir=%d\n", ret,
+ type, dir);
goto fail_dma;
}
sys_rx->len++;
@@ -163,7 +184,7 @@
fail_buffer:
kfree(info);
fail_pkt:
- IPAERR("failed\n");
+ IPAERR("failed type=%d dir=%d\n", type, dir);
return -ENOMEM;
}
@@ -182,8 +203,8 @@
} else {
tx_pkt = list_first_entry(&sys_tx->head_desc_list,
struct ipa_pkt_info,
- list_node);
- list_move_tail(&tx_pkt->list_node,
+ link);
+ list_move_tail(&tx_pkt->link,
&sys_tx->free_desc_list);
sys_tx->len--;
sys_tx->free_len++;
@@ -195,10 +216,11 @@
return cnt;
}
-static void ipa_do_bridge_work(enum ipa_bridge_dir dir)
+static void ipa_do_bridge_work(enum ipa_bridge_dir dir,
+ struct ipa_bridge_context *ctx)
{
- struct ipa_bridge_pipe_context *sys_rx = &bridge[2 * dir];
- struct ipa_bridge_pipe_context *sys_tx = &bridge[2 * dir + 1];
+ struct ipa_bridge_pipe_context *sys_rx = &ctx->pipe[2 * dir];
+ struct ipa_bridge_pipe_context *sys_tx = &ctx->pipe[2 * dir + 1];
struct ipa_pkt_info *tx_pkt;
struct ipa_pkt_info *rx_pkt;
struct ipa_pkt_info *tmp_pkt;
@@ -221,8 +243,8 @@
rx_pkt = list_first_entry(&sys_rx->head_desc_list,
struct ipa_pkt_info,
- list_node);
- list_del(&rx_pkt->list_node);
+ link);
+ list_del(&rx_pkt->link);
sys_rx->len--;
rx_pkt->len = iov.size;
@@ -231,8 +253,8 @@
tmp_pkt = kmalloc(sizeof(struct ipa_pkt_info),
GFP_KERNEL);
if (!tmp_pkt) {
- pr_debug_ratelimited("%s: unable to alloc tx_pkt_info\n",
- __func__);
+ pr_debug_ratelimited("%s: unable to alloc tx_pkt_info type=%d dir=%d\n",
+ __func__, ctx->type, dir);
usleep_range(polling_min_sleep[dir],
polling_max_sleep[dir]);
goto retry_alloc_tx;
@@ -241,8 +263,8 @@
tmp_pkt->buffer = kmalloc(IPA_RX_SKB_SIZE,
GFP_KERNEL | GFP_DMA);
if (!tmp_pkt->buffer) {
- pr_debug_ratelimited("%s: unable to alloc tx_pkt_buffer\n",
- __func__);
+ pr_debug_ratelimited("%s: unable to alloc tx_pkt_buffer type=%d dir=%d\n",
+ __func__, ctx->type, dir);
kfree(tmp_pkt);
usleep_range(polling_min_sleep[dir],
polling_max_sleep[dir]);
@@ -255,28 +277,26 @@
DMA_BIDIRECTIONAL);
if (tmp_pkt->dma_address == 0 ||
tmp_pkt->dma_address == ~0) {
- pr_debug_ratelimited("%s: dma_map_single failure %p for %p\n",
+ pr_debug_ratelimited("%s: dma_map_single failure %p for %p type=%d dir=%d\n",
__func__,
(void *)tmp_pkt->dma_address,
- tmp_pkt->buffer);
+ tmp_pkt->buffer, ctx->type, dir);
}
- list_add_tail(&tmp_pkt->list_node,
+ list_add_tail(&tmp_pkt->link,
&sys_tx->free_desc_list);
sys_tx->free_len++;
- alloc_cnt[dir]++;
-
tmp_pkt->len = ~0;
}
tx_pkt = list_first_entry(&sys_tx->free_desc_list,
struct ipa_pkt_info,
- list_node);
- list_del(&tx_pkt->list_node);
+ link);
+ list_del(&tx_pkt->link);
sys_tx->free_len--;
retry_add_rx:
- list_add_tail(&tx_pkt->list_node,
+ list_add_tail(&tx_pkt->link,
&sys_rx->head_desc_list);
ret = sps_transfer_one(sys_rx->pipe,
tx_pkt->dma_address,
@@ -285,9 +305,9 @@
SPS_IOVEC_FLAG_INT |
SPS_IOVEC_FLAG_EOT);
if (ret) {
- list_del(&tx_pkt->list_node);
- pr_debug_ratelimited("%s: sps_transfer_one failed %d\n",
- __func__, ret);
+ list_del(&tx_pkt->link);
+ pr_debug_ratelimited("%s: sps_transfer_one failed %d type=%d dir=%d\n",
+ __func__, ret, ctx->type, dir);
usleep_range(polling_min_sleep[dir],
polling_max_sleep[dir]);
goto retry_add_rx;
@@ -295,7 +315,7 @@
sys_rx->len++;
retry_add_tx:
- list_add_tail(&rx_pkt->list_node,
+ list_add_tail(&rx_pkt->link,
&sys_tx->head_desc_list);
ret = sps_transfer_one(sys_tx->pipe,
rx_pkt->dma_address,
@@ -304,19 +324,21 @@
SPS_IOVEC_FLAG_INT |
SPS_IOVEC_FLAG_EOT);
if (ret) {
- pr_debug_ratelimited("%s: fail to add to TX dir=%d\n",
- __func__, dir);
- list_del(&rx_pkt->list_node);
+ pr_debug_ratelimited("%s: fail to add to TX type=%d dir=%d\n",
+ __func__, ctx->type, dir);
+ list_del(&rx_pkt->link);
ipa_reclaim_tx(sys_tx, true);
usleep_range(polling_min_sleep[dir],
polling_max_sleep[dir]);
goto retry_add_tx;
}
sys_tx->len++;
+ IPA_STATS_INC_BRIDGE_CNT(ctx->type, dir,
+ ipa_ctx->stats.bridged_pkts);
}
if (inactive_cycles >= polling_inactivity[dir]) {
- ipa_switch_to_intr_mode(dir);
+ ipa_switch_to_intr_mode(dir, ctx);
break;
}
}
@@ -324,47 +346,64 @@
static void ipa_sps_irq_rx_notify(struct sps_event_notify *notify)
{
+ enum ipa_bridge_type type = (enum ipa_bridge_type) notify->user;
+
switch (notify->event_id) {
case SPS_EVENT_EOT:
- ipa_switch_to_poll_mode(IPA_UL);
- queue_work(ipa_ul_workqueue, &ul_work);
+ ipa_switch_to_poll_mode(IPA_BRIDGE_DIR_UL, type);
+ queue_work(bridge[type].ul_wq, &bridge[type].ul_work);
break;
default:
- IPAERR("recieved unexpected event id %d\n", notify->event_id);
+ IPAERR("recieved unexpected event id %d type %d\n",
+ notify->event_id, type);
}
}
-static int setup_bridge_to_ipa(enum ipa_bridge_dir dir)
+static int setup_bridge_to_ipa(enum ipa_bridge_dir dir,
+ enum ipa_bridge_type type,
+ struct ipa_sys_connect_params *props,
+ u32 *clnt_hdl)
{
struct ipa_bridge_pipe_context *sys;
- struct ipa_ep_cfg_mode mode;
dma_addr_t dma_addr;
+ enum ipa_pipe_type pipe_type;
int ipa_ep_idx;
int ret;
int i;
- if (dir == IPA_DL) {
- ipa_ep_idx = ipa_get_ep_mapping(ipa_ctx->mode,
- IPA_CLIENT_A2_TETHERED_PROD);
- if (ipa_ep_idx == -1) {
- IPAERR("Invalid client.\n");
- ret = -EINVAL;
- goto tx_alloc_endpoint_failed;
- }
+ ipa_ep_idx = ipa_get_ep_mapping(ipa_ctx->mode, props->client);
+ if (ipa_ep_idx == -1) {
+ IPAERR("Invalid client=%d mode=%d type=%d dir=%d\n",
+ props->client, ipa_ctx->mode, type, dir);
+ ret = -EINVAL;
+ goto alloc_endpoint_failed;
+ }
- sys = &bridge[IPA_DL_TO_IPA];
- sys->pipe = sps_alloc_endpoint();
- if (sys->pipe == NULL) {
- IPAERR("tx alloc endpoint failed\n");
- ret = -ENOMEM;
- goto tx_alloc_endpoint_failed;
- }
- ret = sps_get_config(sys->pipe, &sys->connection);
- if (ret) {
- IPAERR("tx get config failed %d\n", ret);
- goto tx_get_config_failed;
- }
+ if (ipa_ctx->ep[ipa_ep_idx].valid) {
+ IPAERR("EP %d already allocated type=%d dir=%d\n", ipa_ep_idx,
+ type, dir);
+ ret = -EINVAL;
+ goto alloc_endpoint_failed;
+ }
+ pipe_type = (dir == IPA_BRIDGE_DIR_DL) ? IPA_DL_TO_IPA :
+ IPA_UL_FROM_IPA;
+
+ sys = &bridge[type].pipe[pipe_type];
+ sys->pipe = sps_alloc_endpoint();
+ if (sys->pipe == NULL) {
+ IPAERR("alloc endpoint failed type=%d dir=%d\n", type, dir);
+ ret = -ENOMEM;
+ goto alloc_endpoint_failed;
+ }
+ ret = sps_get_config(sys->pipe, &sys->connection);
+ if (ret) {
+ IPAERR("get config failed %d type=%d dir=%d\n", ret, type, dir);
+ ret = -EINVAL;
+ goto get_config_failed;
+ }
+
+ if (dir == IPA_BRIDGE_DIR_DL) {
sys->connection.source = SPS_DEV_HANDLE_MEM;
sys->connection.src_pipe_index = ipa_ctx->a5_pipe_index++;
sys->connection.destination = ipa_ctx->bam_handle;
@@ -372,435 +411,453 @@
sys->connection.mode = SPS_MODE_DEST;
sys->connection.options =
SPS_O_AUTO_ENABLE | SPS_O_ACK_TRANSFERS | SPS_O_POLL;
- sys->desc_mem_buf.size = IPA_SYS_DESC_FIFO_SZ; /* 2k */
- sys->desc_mem_buf.base = dma_alloc_coherent(NULL,
- sys->desc_mem_buf.size,
- &dma_addr,
- 0);
- if (sys->desc_mem_buf.base == NULL) {
- IPAERR("tx memory alloc failed\n");
- ret = -ENOMEM;
- goto tx_get_config_failed;
- }
- sys->desc_mem_buf.phys_base = dma_addr;
- memset(sys->desc_mem_buf.base, 0x0, sys->desc_mem_buf.size);
- sys->connection.desc = sys->desc_mem_buf;
- sys->connection.event_thresh = IPA_EVENT_THRESHOLD;
-
- ret = sps_connect(sys->pipe, &sys->connection);
- if (ret < 0) {
- IPAERR("tx connect error %d\n", ret);
- goto tx_connect_failed;
- }
-
- INIT_LIST_HEAD(&sys->head_desc_list);
- INIT_LIST_HEAD(&sys->free_desc_list);
- spin_lock_init(&sys->spinlock);
-
- ipa_ctx->ep[ipa_ep_idx].valid = 1;
-
- mode.mode = IPA_DMA;
- mode.dst = IPA_CLIENT_USB_CONS;
- ret = ipa_cfg_ep_mode(ipa_ep_idx, &mode);
- if (ret < 0) {
- IPAERR("DMA mode set error %d\n", ret);
- goto tx_mode_set_failed;
- }
-
- return 0;
-
-tx_mode_set_failed:
- sps_disconnect(sys->pipe);
-tx_connect_failed:
- dma_free_coherent(NULL, sys->desc_mem_buf.size,
- sys->desc_mem_buf.base,
- sys->desc_mem_buf.phys_base);
-tx_get_config_failed:
- sps_free_endpoint(sys->pipe);
-tx_alloc_endpoint_failed:
- return ret;
} else {
-
- ipa_ep_idx = ipa_get_ep_mapping(ipa_ctx->mode,
- IPA_CLIENT_A2_TETHERED_CONS);
- if (ipa_ep_idx == -1) {
- IPAERR("Invalid client.\n");
- ret = -EINVAL;
- goto rx_alloc_endpoint_failed;
- }
-
- sys = &bridge[IPA_UL_FROM_IPA];
- sys->pipe = sps_alloc_endpoint();
- if (sys->pipe == NULL) {
- IPAERR("rx alloc endpoint failed\n");
- ret = -ENOMEM;
- goto rx_alloc_endpoint_failed;
- }
- ret = sps_get_config(sys->pipe, &sys->connection);
- if (ret) {
- IPAERR("rx get config failed %d\n", ret);
- goto rx_get_config_failed;
- }
-
sys->connection.source = ipa_ctx->bam_handle;
- sys->connection.src_pipe_index = 7;
+ sys->connection.src_pipe_index = ipa_ep_idx;
sys->connection.destination = SPS_DEV_HANDLE_MEM;
sys->connection.dest_pipe_index = ipa_ctx->a5_pipe_index++;
sys->connection.mode = SPS_MODE_SRC;
sys->connection.options = SPS_O_AUTO_ENABLE | SPS_O_EOT |
SPS_O_ACK_TRANSFERS;
- sys->desc_mem_buf.size = IPA_SYS_DESC_FIFO_SZ; /* 2k */
- sys->desc_mem_buf.base = dma_alloc_coherent(NULL,
- sys->desc_mem_buf.size,
- &dma_addr,
- 0);
- if (sys->desc_mem_buf.base == NULL) {
- IPAERR("rx memory alloc failed\n");
- ret = -ENOMEM;
- goto rx_get_config_failed;
- }
- sys->desc_mem_buf.phys_base = dma_addr;
- memset(sys->desc_mem_buf.base, 0x0, sys->desc_mem_buf.size);
- sys->connection.desc = sys->desc_mem_buf;
- sys->connection.event_thresh = IPA_EVENT_THRESHOLD;
+ }
- ret = sps_connect(sys->pipe, &sys->connection);
- if (ret < 0) {
- IPAERR("rx connect error %d\n", ret);
- goto rx_connect_failed;
- }
+ sys->desc_mem_buf.size = props->desc_fifo_sz;
+ sys->desc_mem_buf.base = dma_alloc_coherent(NULL,
+ sys->desc_mem_buf.size,
+ &dma_addr,
+ 0);
+ if (sys->desc_mem_buf.base == NULL) {
+ IPAERR("memory alloc failed type=%d dir=%d\n", type, dir);
+ ret = -ENOMEM;
+ goto get_config_failed;
+ }
+ sys->desc_mem_buf.phys_base = dma_addr;
+ memset(sys->desc_mem_buf.base, 0x0, sys->desc_mem_buf.size);
+ sys->connection.desc = sys->desc_mem_buf;
+ sys->connection.event_thresh = IPA_EVENT_THRESHOLD;
+ ret = sps_connect(sys->pipe, &sys->connection);
+ if (ret < 0) {
+ IPAERR("connect error %d type=%d dir=%d\n", ret, type, dir);
+ goto connect_failed;
+ }
+
+ INIT_LIST_HEAD(&sys->head_desc_list);
+ INIT_LIST_HEAD(&sys->free_desc_list);
+ spin_lock_init(&sys->spinlock);
+
+ memset(&ipa_ctx->ep[ipa_ep_idx], 0,
+ sizeof(struct ipa_ep_context));
+
+ ipa_ctx->ep[ipa_ep_idx].valid = 1;
+ ipa_ctx->ep[ipa_ep_idx].client_notify = props->notify;
+ ipa_ctx->ep[ipa_ep_idx].priv = props->priv;
+
+ ret = ipa_cfg_ep(ipa_ep_idx, &props->ipa_ep_cfg);
+ if (ret < 0) {
+ IPAERR("ep cfg set error %d type=%d dir=%d\n", ret, type, dir);
+ ipa_ctx->ep[ipa_ep_idx].valid = 0;
+ goto event_reg_failed;
+ }
+
+ if (dir == IPA_BRIDGE_DIR_UL) {
sys->register_event.options = SPS_O_EOT;
sys->register_event.mode = SPS_TRIGGER_CALLBACK;
sys->register_event.xfer_done = NULL;
sys->register_event.callback = ipa_sps_irq_rx_notify;
- sys->register_event.user = NULL;
+ sys->register_event.user = (void *)type;
ret = sps_register_event(sys->pipe, &sys->register_event);
if (ret < 0) {
- IPAERR("tx register event error %d\n", ret);
- goto rx_event_reg_failed;
+ IPAERR("register event error %d type=%d dir=%d\n", ret,
+ type, dir);
+ goto event_reg_failed;
}
- INIT_LIST_HEAD(&sys->head_desc_list);
- INIT_LIST_HEAD(&sys->free_desc_list);
- spin_lock_init(&sys->spinlock);
-
for (i = 0; i < IPA_RX_POOL_CEIL; i++) {
- ret = queue_rx_single(dir);
+ ret = queue_rx_single(dir, type);
if (ret < 0)
- IPAERR("queue fail %d %d\n", dir, i);
+ IPAERR("queue fail dir=%d type=%d iter=%d\n",
+ dir, type, i);
}
-
- return 0;
-
-rx_event_reg_failed:
- sps_disconnect(sys->pipe);
-rx_connect_failed:
- dma_free_coherent(NULL,
- sys->desc_mem_buf.size,
- sys->desc_mem_buf.base,
- sys->desc_mem_buf.phys_base);
-rx_get_config_failed:
- sps_free_endpoint(sys->pipe);
-rx_alloc_endpoint_failed:
- return ret;
}
+
+ *clnt_hdl = ipa_ep_idx;
+
+ return 0;
+
+event_reg_failed:
+ sps_disconnect(sys->pipe);
+connect_failed:
+ dma_free_coherent(NULL,
+ sys->desc_mem_buf.size,
+ sys->desc_mem_buf.base,
+ sys->desc_mem_buf.phys_base);
+get_config_failed:
+ sps_free_endpoint(sys->pipe);
+alloc_endpoint_failed:
+ return ret;
}
static void bam_mux_rx_notify(struct sps_event_notify *notify)
{
+ enum ipa_bridge_type type = (enum ipa_bridge_type) notify->user;
+
switch (notify->event_id) {
case SPS_EVENT_EOT:
- ipa_switch_to_poll_mode(IPA_DL);
- queue_work(ipa_dl_workqueue, &dl_work);
+ ipa_switch_to_poll_mode(IPA_BRIDGE_DIR_DL, type);
+ queue_work(bridge[type].dl_wq, &bridge[type].dl_work);
break;
default:
- IPAERR("recieved unexpected event id %d\n", notify->event_id);
+ IPAERR("recieved unexpected event id %d type %d\n",
+ notify->event_id, type);
}
}
-static int setup_bridge_to_a2(enum ipa_bridge_dir dir)
+static int setup_bridge_to_a2(enum ipa_bridge_dir dir,
+ enum ipa_bridge_type type,
+ u32 desc_fifo_sz)
{
struct ipa_bridge_pipe_context *sys;
- struct a2_mux_pipe_connection pipe_conn = { 0, };
+ struct a2_mux_pipe_connection pipe_conn = { 0 };
dma_addr_t dma_addr;
u32 a2_handle;
+ enum a2_mux_pipe_direction pipe_dir;
+ enum ipa_pipe_type pipe_type;
+ u32 pa;
int ret;
int i;
- if (dir == IPA_UL) {
- ret = ipa_get_a2_mux_pipe_info(IPA_TO_A2, &pipe_conn);
- if (ret) {
- IPAERR("ipa_get_a2_mux_pipe_info failed IPA_TO_A2\n");
- goto tx_alloc_endpoint_failed;
- }
+ pipe_dir = (dir == IPA_BRIDGE_DIR_UL) ? IPA_TO_A2 : A2_TO_IPA;
- ret = sps_phy2h(pipe_conn.dst_phy_addr, &a2_handle);
- if (ret) {
- IPAERR("sps_phy2h failed (A2 BAM) %d\n", ret);
- goto tx_alloc_endpoint_failed;
- }
+ ret = ipa_get_a2_mux_pipe_info(pipe_dir, &pipe_conn);
+ if (ret) {
+ IPAERR("ipa_get_a2_mux_pipe_info failed type=%d dir=%d\n",
+ type, dir);
+ ret = -EINVAL;
+ goto alloc_endpoint_failed;
+ }
- sys = &bridge[IPA_UL_TO_A2];
- sys->pipe = sps_alloc_endpoint();
- if (sys->pipe == NULL) {
- IPAERR("tx alloc endpoint failed\n");
- ret = -ENOMEM;
- goto tx_alloc_endpoint_failed;
- }
- ret = sps_get_config(sys->pipe, &sys->connection);
- if (ret) {
- IPAERR("tx get config failed %d\n", ret);
- goto tx_get_config_failed;
- }
+ pa = (dir == IPA_BRIDGE_DIR_UL) ? pipe_conn.dst_phy_addr :
+ pipe_conn.src_phy_addr;
+ ret = sps_phy2h(pa, &a2_handle);
+ if (ret) {
+ IPAERR("sps_phy2h failed (A2 BAM) %d type=%d dir=%d\n",
+ ret, type, dir);
+ ret = -EINVAL;
+ goto alloc_endpoint_failed;
+ }
+
+ pipe_type = (dir == IPA_BRIDGE_DIR_UL) ? IPA_UL_TO_A2 : IPA_DL_FROM_A2;
+
+ sys = &bridge[type].pipe[pipe_type];
+ sys->pipe = sps_alloc_endpoint();
+ if (sys->pipe == NULL) {
+ IPAERR("alloc endpoint failed type=%d dir=%d\n", type, dir);
+ ret = -ENOMEM;
+ goto alloc_endpoint_failed;
+ }
+ ret = sps_get_config(sys->pipe, &sys->connection);
+ if (ret) {
+ IPAERR("get config failed %d type=%d dir=%d\n", ret, type, dir);
+ ret = -EINVAL;
+ goto get_config_failed;
+ }
+
+ if (dir == IPA_BRIDGE_DIR_UL) {
sys->connection.source = SPS_DEV_HANDLE_MEM;
sys->connection.src_pipe_index = ipa_ctx->a5_pipe_index++;
sys->connection.destination = a2_handle;
- sys->connection.dest_pipe_index = pipe_conn.dst_pipe_index;
+ if (type == IPA_BRIDGE_TYPE_TETHERED)
+ sys->connection.dest_pipe_index =
+ pipe_conn.dst_pipe_index;
+ else
+ sys->connection.dest_pipe_index = A2_EMBEDDED_PIPE_TX;
sys->connection.mode = SPS_MODE_DEST;
sys->connection.options =
SPS_O_AUTO_ENABLE | SPS_O_ACK_TRANSFERS | SPS_O_POLL;
- sys->desc_mem_buf.size = IPA_SYS_DESC_FIFO_SZ; /* 2k */
- sys->desc_mem_buf.base = dma_alloc_coherent(NULL,
- sys->desc_mem_buf.size,
- &dma_addr,
- 0);
- if (sys->desc_mem_buf.base == NULL) {
- IPAERR("tx memory alloc failed\n");
- ret = -ENOMEM;
- goto tx_get_config_failed;
- }
- sys->desc_mem_buf.phys_base = dma_addr;
- memset(sys->desc_mem_buf.base, 0x0, sys->desc_mem_buf.size);
- sys->connection.desc = sys->desc_mem_buf;
- sys->connection.event_thresh = IPA_EVENT_THRESHOLD;
-
- ret = sps_connect(sys->pipe, &sys->connection);
- if (ret < 0) {
- IPAERR("tx connect error %d\n", ret);
- goto tx_connect_failed;
- }
-
- INIT_LIST_HEAD(&sys->head_desc_list);
- INIT_LIST_HEAD(&sys->free_desc_list);
- spin_lock_init(&sys->spinlock);
-
- return 0;
-
-tx_connect_failed:
- dma_free_coherent(NULL,
- sys->desc_mem_buf.size,
- sys->desc_mem_buf.base,
- sys->desc_mem_buf.phys_base);
-tx_get_config_failed:
- sps_free_endpoint(sys->pipe);
-tx_alloc_endpoint_failed:
- return ret;
- } else { /* dir == IPA_UL */
-
- ret = ipa_get_a2_mux_pipe_info(A2_TO_IPA, &pipe_conn);
- if (ret) {
- IPAERR("ipa_get_a2_mux_pipe_info failed A2_TO_IPA\n");
- goto rx_alloc_endpoint_failed;
- }
-
- ret = sps_phy2h(pipe_conn.src_phy_addr, &a2_handle);
- if (ret) {
- IPAERR("sps_phy2h failed (A2 BAM) %d\n", ret);
- goto rx_alloc_endpoint_failed;
- }
-
- sys = &bridge[IPA_DL_FROM_A2];
- sys->pipe = sps_alloc_endpoint();
- if (sys->pipe == NULL) {
- IPAERR("rx alloc endpoint failed\n");
- ret = -ENOMEM;
- goto rx_alloc_endpoint_failed;
- }
- ret = sps_get_config(sys->pipe, &sys->connection);
- if (ret) {
- IPAERR("rx get config failed %d\n", ret);
- goto rx_get_config_failed;
- }
-
+ } else {
sys->connection.source = a2_handle;
- sys->connection.src_pipe_index = pipe_conn.src_pipe_index;
+ if (type == IPA_BRIDGE_TYPE_TETHERED)
+ sys->connection.src_pipe_index =
+ pipe_conn.src_pipe_index;
+ else
+ sys->connection.src_pipe_index = A2_EMBEDDED_PIPE_RX;
sys->connection.destination = SPS_DEV_HANDLE_MEM;
sys->connection.dest_pipe_index = ipa_ctx->a5_pipe_index++;
sys->connection.mode = SPS_MODE_SRC;
sys->connection.options = SPS_O_AUTO_ENABLE | SPS_O_EOT |
SPS_O_ACK_TRANSFERS;
- sys->desc_mem_buf.size = IPA_SYS_DESC_FIFO_SZ; /* 2k */
- sys->desc_mem_buf.base = dma_alloc_coherent(NULL,
- sys->desc_mem_buf.size,
- &dma_addr,
- 0);
- if (sys->desc_mem_buf.base == NULL) {
- IPAERR("rx memory alloc failed\n");
- ret = -ENOMEM;
- goto rx_get_config_failed;
- }
- sys->desc_mem_buf.phys_base = dma_addr;
- memset(sys->desc_mem_buf.base, 0x0, sys->desc_mem_buf.size);
- sys->connection.desc = sys->desc_mem_buf;
- sys->connection.event_thresh = IPA_EVENT_THRESHOLD;
+ }
- ret = sps_connect(sys->pipe, &sys->connection);
- if (ret < 0) {
- IPAERR("rx connect error %d\n", ret);
- goto rx_connect_failed;
- }
+ sys->desc_mem_buf.size = desc_fifo_sz;
+ sys->desc_mem_buf.base = dma_alloc_coherent(NULL,
+ sys->desc_mem_buf.size,
+ &dma_addr,
+ 0);
+ if (sys->desc_mem_buf.base == NULL) {
+ IPAERR("memory alloc failed type=%d dir=%d\n", type, dir);
+ ret = -ENOMEM;
+ goto get_config_failed;
+ }
+ sys->desc_mem_buf.phys_base = dma_addr;
+ memset(sys->desc_mem_buf.base, 0x0, sys->desc_mem_buf.size);
+ sys->connection.desc = sys->desc_mem_buf;
+ sys->connection.event_thresh = IPA_EVENT_THRESHOLD;
+ ret = sps_connect(sys->pipe, &sys->connection);
+ if (ret < 0) {
+ IPAERR("connect error %d type=%d dir=%d\n", ret, type, dir);
+ ret = -EINVAL;
+ goto connect_failed;
+ }
+
+ INIT_LIST_HEAD(&sys->head_desc_list);
+ INIT_LIST_HEAD(&sys->free_desc_list);
+ spin_lock_init(&sys->spinlock);
+
+ if (dir == IPA_BRIDGE_DIR_DL) {
sys->register_event.options = SPS_O_EOT;
sys->register_event.mode = SPS_TRIGGER_CALLBACK;
sys->register_event.xfer_done = NULL;
sys->register_event.callback = bam_mux_rx_notify;
- sys->register_event.user = NULL;
+ sys->register_event.user = (void *)type;
ret = sps_register_event(sys->pipe, &sys->register_event);
if (ret < 0) {
- IPAERR("tx register event error %d\n", ret);
- goto rx_event_reg_failed;
+ IPAERR("register event error %d type=%d dir=%d\n",
+ ret, type, dir);
+ ret = -EINVAL;
+ goto event_reg_failed;
}
- INIT_LIST_HEAD(&sys->head_desc_list);
- INIT_LIST_HEAD(&sys->free_desc_list);
- spin_lock_init(&sys->spinlock);
-
-
for (i = 0; i < IPA_RX_POOL_CEIL; i++) {
- ret = queue_rx_single(dir);
+ ret = queue_rx_single(dir, type);
if (ret < 0)
- IPAERR("queue fail %d %d\n", dir, i);
+ IPAERR("queue fail dir=%d type=%d iter=%d\n",
+ dir, type, i);
}
-
- return 0;
-
-rx_event_reg_failed:
- sps_disconnect(sys->pipe);
-rx_connect_failed:
- dma_free_coherent(NULL,
- sys->desc_mem_buf.size,
- sys->desc_mem_buf.base,
- sys->desc_mem_buf.phys_base);
-rx_get_config_failed:
- sps_free_endpoint(sys->pipe);
-rx_alloc_endpoint_failed:
- return ret;
}
+
+ return 0;
+
+event_reg_failed:
+ sps_disconnect(sys->pipe);
+connect_failed:
+ dma_free_coherent(NULL,
+ sys->desc_mem_buf.size,
+ sys->desc_mem_buf.base,
+ sys->desc_mem_buf.phys_base);
+get_config_failed:
+ sps_free_endpoint(sys->pipe);
+alloc_endpoint_failed:
+ return ret;
}
/**
- * ipa_bridge_init() - initialize the tethered bridge, allocate UL and DL
- * workqueues
+ * ipa_bridge_init() - create workqueues and work items serving SW bridges
*
* Return codes: 0: success, -ENOMEM: failure
*/
int ipa_bridge_init(void)
{
int ret;
+ int i;
- ipa_ul_workqueue = alloc_workqueue("ipa_ul",
+ bridge[IPA_BRIDGE_TYPE_TETHERED].ul_wq = alloc_workqueue("ipa_ul_teth",
WQ_MEM_RECLAIM | WQ_CPU_INTENSIVE, 1);
- if (!ipa_ul_workqueue) {
- IPAERR("ipa ul wq alloc failed\n");
+ if (!bridge[IPA_BRIDGE_TYPE_TETHERED].ul_wq) {
+ IPAERR("ipa ul teth wq alloc failed\n");
ret = -ENOMEM;
- goto fail_ul;
+ goto fail_ul_teth;
}
- ipa_dl_workqueue = alloc_workqueue("ipa_dl",
+ bridge[IPA_BRIDGE_TYPE_TETHERED].dl_wq = alloc_workqueue("ipa_dl_teth",
WQ_MEM_RECLAIM | WQ_CPU_INTENSIVE, 1);
- if (!ipa_dl_workqueue) {
- IPAERR("ipa dl wq alloc failed\n");
+ if (!bridge[IPA_BRIDGE_TYPE_TETHERED].dl_wq) {
+ IPAERR("ipa dl teth wq alloc failed\n");
ret = -ENOMEM;
- goto fail_dl;
+ goto fail_dl_teth;
+ }
+
+ bridge[IPA_BRIDGE_TYPE_EMBEDDED].ul_wq = alloc_workqueue("ipa_ul_emb",
+ WQ_MEM_RECLAIM | WQ_CPU_INTENSIVE, 1);
+ if (!bridge[IPA_BRIDGE_TYPE_EMBEDDED].ul_wq) {
+ IPAERR("ipa ul emb wq alloc failed\n");
+ ret = -ENOMEM;
+ goto fail_ul_emb;
+ }
+
+ bridge[IPA_BRIDGE_TYPE_EMBEDDED].dl_wq = alloc_workqueue("ipa_dl_emb",
+ WQ_MEM_RECLAIM | WQ_CPU_INTENSIVE, 1);
+ if (!bridge[IPA_BRIDGE_TYPE_EMBEDDED].dl_wq) {
+ IPAERR("ipa dl emb wq alloc failed\n");
+ ret = -ENOMEM;
+ goto fail_dl_emb;
+ }
+
+ for (i = 0; i < IPA_BRIDGE_TYPE_MAX; i++) {
+ INIT_WORK(&bridge[i].ul_work, ul_work_func);
+ INIT_WORK(&bridge[i].dl_work, dl_work_func);
+ bridge[i].type = i;
}
return 0;
-fail_dl:
- destroy_workqueue(ipa_ul_workqueue);
-fail_ul:
+
+fail_dl_emb:
+ destroy_workqueue(bridge[IPA_BRIDGE_TYPE_EMBEDDED].ul_wq);
+fail_ul_emb:
+ destroy_workqueue(bridge[IPA_BRIDGE_TYPE_TETHERED].dl_wq);
+fail_dl_teth:
+ destroy_workqueue(bridge[IPA_BRIDGE_TYPE_TETHERED].ul_wq);
+fail_ul_teth:
return ret;
}
/**
- * ipa_bridge_setup() - setup tethered SW bridge in specified direction
+ * ipa_bridge_setup() - setup SW bridge leg
* @dir: downlink or uplink (from air interface perspective)
+ * @type: tethered or embedded bridge
+ * @props: bridge leg properties (EP config, callbacks, etc)
+ * @clnt_hdl: [out] handle of IPA EP belonging to bridge leg
+ *
+ * NOTE: IT IS CALLER'S RESPONSIBILITY TO ENSURE BAMs ARE
+ * OPERATIONAL AS LONG AS BRIDGE REMAINS UP
*
* Return codes:
* 0: success
* various negative error codes on errors
*/
-int ipa_bridge_setup(enum ipa_bridge_dir dir)
+int ipa_bridge_setup(enum ipa_bridge_dir dir, enum ipa_bridge_type type,
+ struct ipa_sys_connect_params *props, u32 *clnt_hdl)
{
int ret;
- if (atomic_inc_return(&ipa_ctx->ipa_active_clients) == 1)
- ipa_enable_clks();
-
- if (setup_bridge_to_a2(dir)) {
- IPAERR("fail to setup SYS pipe to A2 %d\n", dir);
- ret = -EINVAL;
- goto bail_a2;
+ if (props == NULL || clnt_hdl == NULL ||
+ type >= IPA_BRIDGE_TYPE_MAX || dir >= IPA_BRIDGE_DIR_MAX ||
+ props->client >= IPA_CLIENT_MAX || props->desc_fifo_sz == 0) {
+ IPAERR("Bad param props=%p clnt_hdl=%p type=%d dir=%d\n",
+ props, clnt_hdl, type, dir);
+ return -EINVAL;
}
- if (setup_bridge_to_ipa(dir)) {
- IPAERR("fail to setup SYS pipe to IPA %d\n", dir);
+ if (atomic_inc_return(&ipa_ctx->ipa_active_clients) == 1) {
+ if (ipa_ctx->ipa_hw_mode == IPA_HW_MODE_NORMAL)
+ ipa_enable_clks();
+ }
+
+ if (setup_bridge_to_ipa(dir, type, props, clnt_hdl)) {
+ IPAERR("fail to setup SYS pipe to IPA dir=%d type=%d\n",
+ dir, type);
ret = -EINVAL;
goto bail_ipa;
}
- return 0;
-
-bail_ipa:
- if (dir == IPA_UL)
- sps_disconnect(bridge[IPA_UL_TO_A2].pipe);
- else
- sps_disconnect(bridge[IPA_DL_FROM_A2].pipe);
-bail_a2:
- if (atomic_dec_return(&ipa_ctx->ipa_active_clients) == 0)
- ipa_disable_clks();
-
- return ret;
-}
-
-/**
- * ipa_bridge_teardown() - teardown the tethered bridge in the specified dir
- * @dir: downlink or uplink (from air interface perspective)
- *
- * Return codes:
- * 0: always
- */
-int ipa_bridge_teardown(enum ipa_bridge_dir dir)
-{
- struct ipa_bridge_pipe_context *sys;
-
- if (dir == IPA_UL) {
- sys = &bridge[IPA_UL_TO_A2];
- sps_disconnect(sys->pipe);
- sys = &bridge[IPA_UL_FROM_IPA];
- sps_disconnect(sys->pipe);
- } else {
- sys = &bridge[IPA_DL_FROM_A2];
- sps_disconnect(sys->pipe);
- sys = &bridge[IPA_DL_TO_IPA];
- sps_disconnect(sys->pipe);
+ if (setup_bridge_to_a2(dir, type, props->desc_fifo_sz)) {
+ IPAERR("fail to setup SYS pipe to A2 dir=%d type=%d\n",
+ dir, type);
+ ret = -EINVAL;
+ goto bail_a2;
}
- if (atomic_dec_return(&ipa_ctx->ipa_active_clients) == 0)
- ipa_disable_clks();
return 0;
+
+bail_a2:
+ ipa_bridge_teardown(dir, type, *clnt_hdl);
+bail_ipa:
+ if (atomic_dec_return(&ipa_ctx->ipa_active_clients) == 0) {
+ if (ipa_ctx->ipa_hw_mode == IPA_HW_MODE_NORMAL)
+ ipa_disable_clks();
+ }
+ return ret;
+}
+EXPORT_SYMBOL(ipa_bridge_setup);
+
+static void ipa_bridge_free_pkt(struct ipa_pkt_info *pkt)
+{
+ list_del(&pkt->link);
+ dma_unmap_single(NULL, pkt->dma_address, IPA_RX_SKB_SIZE,
+ DMA_BIDIRECTIONAL);
+ kfree(pkt->buffer);
+ kfree(pkt);
+}
+
+static void ipa_bridge_free_resources(struct ipa_bridge_pipe_context *pipe)
+{
+ struct ipa_pkt_info *pkt;
+ struct ipa_pkt_info *n;
+
+ list_for_each_entry_safe(pkt, n, &pipe->head_desc_list, link)
+ ipa_bridge_free_pkt(pkt);
+
+ list_for_each_entry_safe(pkt, n, &pipe->free_desc_list, link)
+ ipa_bridge_free_pkt(pkt);
}
/**
- * ipa_bridge_cleanup() - de-initialize the tethered bridge
+ * ipa_bridge_teardown() - teardown SW bridge leg
+ * @dir: downlink or uplink (from air interface perspective)
+ * @type: tethered or embedded bridge
+ * @clnt_hdl: handle of IPA EP
+ *
+ * Return codes:
+ * 0: success
+ * various negative error codes on errors
+ */
+int ipa_bridge_teardown(enum ipa_bridge_dir dir, enum ipa_bridge_type type,
+ u32 clnt_hdl)
+{
+ struct ipa_bridge_pipe_context *sys;
+ int lo;
+ int hi;
+
+ if (dir >= IPA_BRIDGE_DIR_MAX || type >= IPA_BRIDGE_TYPE_MAX ||
+ clnt_hdl >= IPA_NUM_PIPES || ipa_ctx->ep[clnt_hdl].valid == 0) {
+ IPAERR("Bad param dir=%d type=%d\n", dir, type);
+ return -EINVAL;
+ }
+
+ if (dir == IPA_BRIDGE_DIR_UL) {
+ lo = IPA_UL_FROM_IPA;
+ hi = IPA_UL_TO_A2;
+ } else {
+ lo = IPA_DL_FROM_A2;
+ hi = IPA_DL_TO_IPA;
+ }
+
+ for (; lo <= hi; lo++) {
+ sys = &bridge[type].pipe[lo];
+ sps_disconnect(sys->pipe);
+ dma_free_coherent(NULL, sys->desc_mem_buf.size,
+ sys->desc_mem_buf.base,
+ sys->desc_mem_buf.phys_base);
+ sps_free_endpoint(sys->pipe);
+ ipa_bridge_free_resources(sys);
+ }
+
+ memset(&ipa_ctx->ep[clnt_hdl], 0, sizeof(struct ipa_ep_context));
+
+ if (atomic_dec_return(&ipa_ctx->ipa_active_clients) == 0) {
+ if (ipa_ctx->ipa_hw_mode == IPA_HW_MODE_NORMAL)
+ ipa_disable_clks();
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(ipa_bridge_teardown);
+
+/**
+ * ipa_bridge_cleanup() - destroy workqueues serving the SW bridges
*
* Return codes:
* None
*/
void ipa_bridge_cleanup(void)
{
- destroy_workqueue(ipa_dl_workqueue);
- destroy_workqueue(ipa_ul_workqueue);
+ int i;
+
+ for (i = 0; i < IPA_BRIDGE_TYPE_MAX; i++) {
+ destroy_workqueue(bridge[i].dl_wq);
+ destroy_workqueue(bridge[i].ul_wq);
+ }
}
diff --git a/drivers/platform/msm/ipa/ipa_client.c b/drivers/platform/msm/ipa/ipa_client.c
index caa419b..4b9a0fd 100644
--- a/drivers/platform/msm/ipa/ipa_client.c
+++ b/drivers/platform/msm/ipa/ipa_client.c
@@ -10,8 +10,94 @@
* GNU General Public License for more details.
*/
+#include <linux/delay.h>
#include "ipa_i.h"
+static void ipa_enable_data_path(u32 clnt_hdl)
+{
+ struct ipa_ep_context *ep = &ipa_ctx->ep[clnt_hdl];
+
+ if (ipa_ctx->ipa_hw_mode == IPA_HW_MODE_VIRTUAL) {
+ /* IPA_HW_MODE_VIRTUAL lacks support for TAG IC & EP suspend */
+ return;
+ }
+
+ if (ipa_ctx->ipa_hw_type == IPA_HW_v1_1 && ep->suspended) {
+ ipa_write_reg(ipa_ctx->mmio,
+ IPA_ENDP_INIT_CTRL_n_OFST(clnt_hdl), 0);
+ ep->suspended = false;
+ }
+}
+
+static int ipa_disable_data_path(u32 clnt_hdl)
+{
+ DECLARE_COMPLETION_ONSTACK(tag_rsp);
+ struct ipa_desc desc = {0};
+ struct ipa_ip_packet_tag cmd;
+ struct ipa_ep_context *ep = &ipa_ctx->ep[clnt_hdl];
+ struct ipa_tree_node *node;
+ int result = 0;
+
+ if (ipa_ctx->ipa_hw_mode == IPA_HW_MODE_VIRTUAL) {
+ /* IPA_HW_MODE_VIRTUAL lacks support for TAG IC & EP suspend */
+ return 0;
+ }
+
+ node = kmem_cache_zalloc(ipa_ctx->tree_node_cache, GFP_KERNEL);
+ if (!node) {
+ IPAERR("failed to alloc tree node object\n");
+ result = -ENOMEM;
+ goto fail_alloc;
+ }
+
+ if (ipa_ctx->ipa_hw_type == IPA_HW_v1_1 && !ep->suspended) {
+ ipa_write_reg(ipa_ctx->mmio,
+ IPA_ENDP_INIT_CTRL_n_OFST(clnt_hdl), 1);
+
+ cmd.tag = (u32) &tag_rsp;
+
+ desc.pyld = &cmd;
+ desc.len = sizeof(struct ipa_ip_packet_tag);
+ desc.type = IPA_IMM_CMD_DESC;
+ desc.opcode = IPA_IP_PACKET_TAG;
+
+ IPADBG("Wait on TAG %p clnt=%d\n", &tag_rsp, clnt_hdl);
+
+ node->hdl = cmd.tag;
+ mutex_lock(&ipa_ctx->lock);
+ if (ipa_insert(&ipa_ctx->tag_tree, node)) {
+ IPAERR("failed to add to tree\n");
+ result = -EINVAL;
+ mutex_unlock(&ipa_ctx->lock);
+ goto fail_insert;
+ }
+ mutex_unlock(&ipa_ctx->lock);
+
+ if (ipa_send_cmd(1, &desc)) {
+ ipa_write_reg(ipa_ctx->mmio,
+ IPA_ENDP_INIT_CTRL_n_OFST(clnt_hdl), 0);
+ IPAERR("fail to send TAG command\n");
+ result = -EPERM;
+ goto fail_send;
+ }
+ wait_for_completion(&tag_rsp);
+ if (IPA_CLIENT_IS_CONS(ep->client) &&
+ ep->cfg.aggr.aggr_en == IPA_ENABLE_AGGR &&
+ ep->cfg.aggr.aggr_time_limit)
+ msleep(ep->cfg.aggr.aggr_time_limit);
+ ep->suspended = true;
+ }
+
+ return 0;
+
+fail_send:
+ rb_erase(&node->node, &ipa_ctx->tag_tree);
+fail_insert:
+ kmem_cache_free(ipa_ctx->tree_node_cache, node);
+fail_alloc:
+ return result;
+}
+
static int ipa_connect_configure_sps(const struct ipa_connect_params *in,
struct ipa_ep_context *ep, int ipa_ep_idx)
{
@@ -94,7 +180,6 @@
return 0;
}
-
/**
* ipa_connect() - low-level IPA client connect
* @in: [in] input parameters from client
@@ -114,16 +199,15 @@
u32 *clnt_hdl)
{
int ipa_ep_idx;
- int ipa_ep_idx_dst;
int result = -EFAULT;
struct ipa_ep_context *ep;
if (atomic_inc_return(&ipa_ctx->ipa_active_clients) == 1)
- ipa_enable_clks();
+ if (ipa_ctx->ipa_hw_mode == IPA_HW_MODE_NORMAL)
+ ipa_enable_clks();
if (in == NULL || sps == NULL || clnt_hdl == NULL ||
in->client >= IPA_CLIENT_MAX ||
- in->ipa_ep_cfg.mode.dst >= IPA_CLIENT_MAX ||
in->desc_fifo_sz == 0 || in->data_fifo_sz == 0) {
IPAERR("bad parm.\n");
result = -EINVAL;
@@ -143,16 +227,6 @@
goto fail;
}
- if (IPA_CLIENT_IS_PROD(in->client) &&
- (in->ipa_ep_cfg.mode.mode == IPA_DMA)) {
- ipa_ep_idx_dst = ipa_get_ep_mapping(ipa_ctx->mode,
- in->ipa_ep_cfg.mode.dst);
- if ((ipa_ep_idx_dst == -1) ||
- (ipa_ctx->ep[ipa_ep_idx_dst].valid)) {
- IPADBG("dst EP for IPA input pipe doesn't yet exist\n");
- }
- }
-
memset(&ipa_ctx->ep[ipa_ep_idx], 0, sizeof(struct ipa_ep_context));
ep->valid = 1;
@@ -247,13 +321,14 @@
ipa_cfg_ep_fail:
memset(&ipa_ctx->ep[ipa_ep_idx], 0, sizeof(struct ipa_ep_context));
fail:
- if (atomic_dec_return(&ipa_ctx->ipa_active_clients) == 0)
- ipa_disable_clks();
+ if (atomic_dec_return(&ipa_ctx->ipa_active_clients) == 0) {
+ if (ipa_ctx->ipa_hw_mode == IPA_HW_MODE_NORMAL)
+ ipa_disable_clks();
+ }
return result;
}
EXPORT_SYMBOL(ipa_connect);
-
/**
* ipa_disconnect() - low-level IPA client disconnect
* @clnt_hdl: [in] opaque client handle assigned by IPA to client
@@ -278,6 +353,13 @@
ep = &ipa_ctx->ep[clnt_hdl];
+ result = ipa_disable_data_path(clnt_hdl);
+ if (result) {
+ IPAERR("disable data path failed res=%d clnt=%d.\n", result,
+ clnt_hdl);
+ return -EPERM;
+ }
+
result = sps_disconnect(ep->ep_hdl);
if (result) {
IPAERR("SPS disconnect failed.\n");
@@ -314,11 +396,68 @@
return -EPERM;
}
+ ipa_enable_data_path(clnt_hdl);
memset(&ipa_ctx->ep[clnt_hdl], 0, sizeof(struct ipa_ep_context));
- if (atomic_dec_return(&ipa_ctx->ipa_active_clients) == 0)
- ipa_disable_clks();
+ if (atomic_dec_return(&ipa_ctx->ipa_active_clients) == 0) {
+ if (ipa_ctx->ipa_hw_mode == IPA_HW_MODE_NORMAL)
+ ipa_disable_clks();
+ }
return 0;
}
EXPORT_SYMBOL(ipa_disconnect);
+
+/**
+ * ipa_connection_suspend() - suspend B2B connection to/from IPA
+ * @clnt_hdl: [in] opaque client handle assigned by IPA to client
+ *
+ * Should be called by the driver of the peripheral that wants to suspend
+ * its BAM-BAM connection to/from IPA in BAM-BAM mode. The pipe is not
+ * disconnected and must later be resumed before data transfer can begin
+ *
+ * Returns: 0 on success, negative on failure
+ *
+ * Note: Should not be called from atomic context
+ */
+int ipa_connection_suspend(u32 clnt_hdl)
+{
+ int result;
+
+ if (clnt_hdl >= IPA_NUM_PIPES || ipa_ctx->ep[clnt_hdl].valid == 0) {
+ IPAERR("bad parm.\n");
+ return -EINVAL;
+ }
+ result = ipa_disable_data_path(clnt_hdl);
+ if (result)
+ IPAERR("disable data path failed res=%d clnt=%d.\n", result,
+ clnt_hdl);
+
+ return result;
+}
+EXPORT_SYMBOL(ipa_connection_suspend);
+
+/**
+ * ipa_connection_resume() - resume B2B connection to/from IPA
+ * @clnt_hdl: [in] opaque client handle assigned by IPA to client
+ *
+ * Should be called by the driver of the peripheral that wants to resume
+ * its previously suspended BAM-BAM connection to/from IPA in BAM-BAM mode.
+ *
+ * Returns: 0 on success, negative on failure
+ *
+ * Note: Should not be called from atomic context
+ */
+int ipa_connection_resume(u32 clnt_hdl)
+{
+ if (clnt_hdl >= IPA_NUM_PIPES || ipa_ctx->ep[clnt_hdl].valid == 0) {
+ IPAERR("bad parm.\n");
+ return -EINVAL;
+ }
+
+ ipa_enable_data_path(clnt_hdl);
+
+ return 0;
+}
+EXPORT_SYMBOL(ipa_connection_resume);
+
diff --git a/drivers/platform/msm/ipa/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_debugfs.c
index 17e9cc0..ec83653 100644
--- a/drivers/platform/msm/ipa/ipa_debugfs.c
+++ b/drivers/platform/msm/ipa/ipa_debugfs.c
@@ -13,10 +13,38 @@
#ifdef CONFIG_DEBUG_FS
#include <linux/debugfs.h>
+#include <linux/stringify.h>
#include "ipa_i.h"
-#define IPA_MAX_MSG_LEN 1024
+#define IPA_MAX_MSG_LEN 4096
+
+const char *ipa_client_name[] = {
+ __stringify(IPA_CLIENT_HSIC1_PROD),
+ __stringify(IPA_CLIENT_HSIC2_PROD),
+ __stringify(IPA_CLIENT_HSIC3_PROD),
+ __stringify(IPA_CLIENT_HSIC4_PROD),
+ __stringify(IPA_CLIENT_HSIC5_PROD),
+ __stringify(IPA_CLIENT_USB_PROD),
+ __stringify(IPA_CLIENT_A5_WLAN_AMPDU_PROD),
+ __stringify(IPA_CLIENT_A2_EMBEDDED_PROD),
+ __stringify(IPA_CLIENT_A2_TETHERED_PROD),
+ __stringify(IPA_CLIENT_A5_LAN_WAN_PROD),
+ __stringify(IPA_CLIENT_A5_CMD_PROD),
+ __stringify(IPA_CLIENT_Q6_LAN_PROD),
+ __stringify(IPA_CLIENT_HSIC1_CONS),
+ __stringify(IPA_CLIENT_HSIC2_CONS),
+ __stringify(IPA_CLIENT_HSIC3_CONS),
+ __stringify(IPA_CLIENT_HSIC4_CONS),
+ __stringify(IPA_CLIENT_HSIC5_CONS),
+ __stringify(IPA_CLIENT_USB_CONS),
+ __stringify(IPA_CLIENT_A2_EMBEDDED_CONS),
+ __stringify(IPA_CLIENT_A2_TETHERED_CONS),
+ __stringify(IPA_CLIENT_A5_LAN_WAN_CONS),
+ __stringify(IPA_CLIENT_Q6_LAN_CONS),
+ __stringify(IPA_CLIENT_MAX),
+};
+
static struct dentry *dent;
static struct dentry *dfile_gen_reg;
static struct dentry *dfile_ep_reg;
@@ -25,6 +53,7 @@
static struct dentry *dfile_ip6_rt;
static struct dentry *dfile_ip4_flt;
static struct dentry *dfile_ip6_flt;
+static struct dentry *dfile_stats;
static char dbg_buff[IPA_MAX_MSG_LEN];
static s8 ep_reg_idx;
@@ -365,9 +394,10 @@
hdr_ofst = 0;
nbytes = scnprintf(dbg_buff + cnt,
IPA_MAX_MSG_LEN - cnt,
- "tbl_idx:%d tbl_name:%s tbl_ref:%u rule_idx:%d dst:%d ep:%d S:%u hdr_ofst[words]:%u attrib_mask:%08x ",
+ "tbl_idx:%d tbl_name:%s tbl_ref:%u rule_idx:%d dst:%d name:%s ep:%d S:%u hdr_ofst[words]:%u attrib_mask:%08x ",
entry->tbl->idx, entry->tbl->name,
entry->tbl->ref_cnt, i, entry->rule.dst,
+ ipa_client_name[entry->rule.dst],
ipa_get_ep_mapping(ipa_ctx->mode,
entry->rule.dst),
!ipa_ctx->hdr_tbl_lcl,
@@ -393,19 +423,25 @@
int cnt = 0;
int i;
int j;
+ int k;
struct ipa_flt_tbl *tbl;
struct ipa_flt_entry *entry;
enum ipa_ip_type ip = (enum ipa_ip_type)file->private_data;
struct ipa_rt_tbl *rt_tbl;
+ u32 rt_tbl_idx;
tbl = &ipa_ctx->glob_flt_tbl[ip];
mutex_lock(&ipa_ctx->lock);
i = 0;
list_for_each_entry(entry, &tbl->head_flt_rule_list, link) {
rt_tbl = (struct ipa_rt_tbl *)entry->rule.rt_tbl_hdl;
+ if (rt_tbl == NULL)
+ rt_tbl_idx = ~0;
+ else
+ rt_tbl_idx = rt_tbl->idx;
nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt,
"ep_idx:global rule_idx:%d act:%d rt_tbl_idx:%d attrib_mask:%08x ",
- i, entry->rule.action, rt_tbl->idx,
+ i, entry->rule.action, rt_tbl_idx,
entry->rule.attrib.attrib_mask);
cnt += nbytes;
cnt += ipa_attrib_dump(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt,
@@ -418,10 +454,16 @@
i = 0;
list_for_each_entry(entry, &tbl->head_flt_rule_list, link) {
rt_tbl = (struct ipa_rt_tbl *)entry->rule.rt_tbl_hdl;
+ if (rt_tbl == NULL)
+ rt_tbl_idx = ~0;
+ else
+ rt_tbl_idx = rt_tbl->idx;
+ k = ipa_get_client_mapping(ipa_ctx->mode, j);
nbytes = scnprintf(dbg_buff + cnt,
IPA_MAX_MSG_LEN - cnt,
- "ep_idx:%d rule_idx:%d act:%d rt_tbl_idx:%d attrib_mask:%08x ",
- j, i, entry->rule.action, rt_tbl->idx,
+ "ep_idx:%d name:%s rule_idx:%d act:%d rt_tbl_idx:%d attrib_mask:%08x ",
+ j, ipa_client_name[k], i,
+ entry->rule.action, rt_tbl_idx,
entry->rule.attrib.attrib_mask);
cnt += nbytes;
cnt +=
@@ -437,6 +479,51 @@
return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, cnt);
}
+static ssize_t ipa_read_stats(struct file *file, char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ int nbytes;
+ int i;
+ int cnt = 0;
+
+ nbytes = scnprintf(dbg_buff, IPA_MAX_MSG_LEN,
+ "sw_tx=%u\n"
+ "hw_tx=%u\n"
+ "rx=%u\n",
+ ipa_ctx->stats.tx_sw_pkts,
+ ipa_ctx->stats.tx_hw_pkts,
+ ipa_ctx->stats.rx_pkts);
+ cnt += nbytes;
+
+ for (i = 0; i < MAX_NUM_EXCP; i++) {
+ nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt,
+ "rx_excp[%u]=%u\n", i,
+ ipa_ctx->stats.rx_excp_pkts[i]);
+ cnt += nbytes;
+ }
+
+ for (i = 0; i < IPA_BRIDGE_TYPE_MAX; i++) {
+ nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt,
+ "bridged_pkt[%u][dl]=%u\n"
+ "bridged_pkt[%u][ul]=%u\n",
+ i,
+ ipa_ctx->stats.bridged_pkts[i][0],
+ i,
+ ipa_ctx->stats.bridged_pkts[i][1]);
+ cnt += nbytes;
+ }
+
+ for (i = 0; i < MAX_NUM_IMM_CMD; i++) {
+ nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN - cnt,
+ "IC[%u]=%u\n", i,
+ ipa_ctx->stats.imm_cmds[i]);
+ cnt += nbytes;
+ }
+
+ return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, cnt);
+}
+
+
const struct file_operations ipa_gen_reg_ops = {
.read = ipa_read_gen_reg,
};
@@ -460,6 +547,10 @@
.open = ipa_open_dbg,
};
+const struct file_operations ipa_stats_ops = {
+ .read = ipa_read_stats,
+};
+
void ipa_debugfs_init(void)
{
const mode_t read_only_mode = S_IRUSR | S_IRGRP | S_IROTH;
@@ -521,6 +612,13 @@
goto fail;
}
+ dfile_stats = debugfs_create_file("stats", read_only_mode, dent, 0,
+ &ipa_stats_ops);
+ if (!dfile_stats || IS_ERR(dfile_stats)) {
+ IPAERR("fail to create file for debug_fs stats\n");
+ goto fail;
+ }
+
return;
fail:
diff --git a/drivers/platform/msm/ipa/ipa_dp.c b/drivers/platform/msm/ipa/ipa_dp.c
index e4173aa..52ed428 100644
--- a/drivers/platform/msm/ipa/ipa_dp.c
+++ b/drivers/platform/msm/ipa/ipa_dp.c
@@ -18,7 +18,7 @@
#define list_next_entry(pos, member) \
list_entry(pos->member.next, typeof(*pos), member)
-#define IPA_LAST_DESC_COOKIE 0xFFFF
+#define IPA_LAST_DESC_CNT 0xFFFF
/**
* ipa_write_done() - this function will be (eventually) called when a Tx
* operation is complete
@@ -49,7 +49,7 @@
if (unlikely(cnt == 0))
WARN_ON(1);
- if (cnt > 1 && cnt != IPA_LAST_DESC_COOKIE)
+ if (cnt > 1 && cnt != IPA_LAST_DESC_CNT)
mult = tx_pkt->mult;
for (i = 0; i < cnt; i++) {
@@ -93,6 +93,7 @@
* ipa_send_one() - Send a single descriptor
* @sys: system pipe context
* @desc: descriptor to send
+ * @in_atomic: whether caller is in atomic context
*
* - Allocate tx_packet wrapper
* - Allocate a bounce buffer due to HW constrains
@@ -104,7 +105,8 @@
*
* Return codes: 0: success, -EFAULT: failure
*/
-int ipa_send_one(struct ipa_sys_context *sys, struct ipa_desc *desc)
+int ipa_send_one(struct ipa_sys_context *sys, struct ipa_desc *desc,
+ bool in_atomic)
{
struct ipa_tx_pkt_wrapper *tx_pkt;
unsigned long irq_flags;
@@ -112,8 +114,12 @@
u16 sps_flags = SPS_IOVEC_FLAG_EOT | SPS_IOVEC_FLAG_INT;
dma_addr_t dma_address;
u16 len;
+ u32 mem_flag = GFP_KERNEL;
- tx_pkt = kmem_cache_zalloc(ipa_ctx->tx_pkt_wrapper_cache, GFP_KERNEL);
+ if (in_atomic)
+ mem_flag = GFP_ATOMIC;
+
+ tx_pkt = kmem_cache_zalloc(ipa_ctx->tx_pkt_wrapper_cache, mem_flag);
if (!tx_pkt) {
IPAERR("failed to alloc tx wrapper\n");
goto fail_mem_alloc;
@@ -128,7 +134,7 @@
*/
tx_pkt->bounce = dma_pool_alloc(
ipa_ctx->one_kb_no_straddle_pool,
- GFP_KERNEL, &dma_address);
+ mem_flag, &dma_address);
if (!tx_pkt->bounce) {
dma_address = 0;
} else {
@@ -210,6 +216,7 @@
* @sys: system pipe context
* @num_desc: number of packets
* @desc: packets to send (may be immediate command or data)
+ * @in_atomic: whether caller is in atomic context
*
* This function is used for system-to-bam connection.
* - SPS driver expect struct sps_transfer which will contain all the data
@@ -226,7 +233,8 @@
*
* Return codes: 0: success, -EFAULT: failure
*/
-int ipa_send(struct ipa_sys_context *sys, u16 num_desc, struct ipa_desc *desc)
+int ipa_send(struct ipa_sys_context *sys, u16 num_desc, struct ipa_desc *desc,
+ bool in_atomic)
{
struct ipa_tx_pkt_wrapper *tx_pkt;
struct ipa_tx_pkt_wrapper *next_pkt;
@@ -239,6 +247,10 @@
int result;
int fail_dma_wrap = 0;
uint size = num_desc * sizeof(struct sps_iovec);
+ u32 mem_flag = GFP_KERNEL;
+
+ if (likely(in_atomic))
+ mem_flag = GFP_ATOMIC;
transfer.iovec = dma_alloc_coherent(NULL, size, &dma_addr, 0);
transfer.iovec_phys = dma_addr;
@@ -251,7 +263,7 @@
for (i = 0; i < num_desc; i++) {
fail_dma_wrap = 0;
tx_pkt = kmem_cache_zalloc(ipa_ctx->tx_pkt_wrapper_cache,
- GFP_KERNEL);
+ mem_flag);
if (!tx_pkt) {
IPAERR("failed to alloc tx wrapper\n");
goto failure;
@@ -287,7 +299,8 @@
* packet does not cross a 1KB boundary
*/
tx_pkt->bounce =
- dma_pool_alloc(ipa_ctx->one_kb_no_straddle_pool, GFP_KERNEL,
+ dma_pool_alloc(ipa_ctx->one_kb_no_straddle_pool,
+ mem_flag,
&tx_pkt->mem.phys_base);
if (!tx_pkt->bounce) {
tx_pkt->mem.phys_base = 0;
@@ -341,7 +354,7 @@
iovec->flags |= (SPS_IOVEC_FLAG_EOT |
SPS_IOVEC_FLAG_INT);
/* "mark" the last desc */
- tx_pkt->cnt = IPA_LAST_DESC_COOKIE;
+ tx_pkt->cnt = IPA_LAST_DESC_CNT;
}
}
@@ -414,6 +427,11 @@
int ipa_send_cmd(u16 num_desc, struct ipa_desc *descr)
{
struct ipa_desc *desc;
+ int result = 0;
+
+ if (atomic_inc_return(&ipa_ctx->ipa_active_clients) == 1)
+ if (ipa_ctx->ipa_hw_mode == IPA_HW_MODE_NORMAL)
+ ipa_enable_clks();
if (num_desc == 1) {
init_completion(&descr->xfer_done);
@@ -423,9 +441,10 @@
descr->callback = ipa_sps_irq_cmd_ack;
descr->user1 = descr;
- if (ipa_send_one(&ipa_ctx->sys[IPA_A5_CMD], descr)) {
+ if (ipa_send_one(&ipa_ctx->sys[IPA_A5_CMD], descr, false)) {
IPAERR("fail to send immediate command\n");
- return -EFAULT;
+ result = -EFAULT;
+ goto bail;
}
wait_for_completion(&descr->xfer_done);
} else {
@@ -437,14 +456,21 @@
desc->callback = ipa_sps_irq_cmd_ack;
desc->user1 = desc;
- if (ipa_send(&ipa_ctx->sys[IPA_A5_CMD], num_desc, descr)) {
+ if (ipa_send(&ipa_ctx->sys[IPA_A5_CMD], num_desc,
+ descr, false)) {
IPAERR("fail to send multiple immediate command set\n");
- return -EFAULT;
+ result = -EFAULT;
+ goto bail;
}
wait_for_completion(&desc->xfer_done);
}
- return 0;
+ IPA_STATS_INC_IC_CNT(num_desc, descr, ipa_ctx->stats.imm_cmds);
+bail:
+ if (atomic_dec_return(&ipa_ctx->ipa_active_clients) == 0)
+ if (ipa_ctx->ipa_hw_mode == IPA_HW_MODE_NORMAL)
+ ipa_disable_clks();
+ return result;
}
/**
@@ -486,7 +512,7 @@
* - Call the endpoints notify function, passing the skb in the parameters
* - Replenish the rx cache
*/
-void ipa_handle_rx_core(void)
+int ipa_handle_rx_core(bool process_all)
{
struct ipa_a5_mux_hdr *mux_hdr;
struct ipa_rx_pkt_wrapper *rx_pkt;
@@ -498,6 +524,9 @@
int ret;
struct ipa_sys_context *sys = &ipa_ctx->sys[IPA_A5_LAN_WAN_IN];
struct ipa_ep_context *ep;
+ int cnt = 0;
+ struct completion *compl;
+ struct ipa_tree_node *node;
do {
ret = sps_get_iovec(sys->ep->ep_hdl, &iov);
@@ -546,6 +575,38 @@
IPA_DUMP_BUFF(rx_skb->data, 0, rx_skb->len);
+ IPA_STATS_INC_CNT(ipa_ctx->stats.rx_pkts);
+ IPA_STATS_EXCP_CNT(mux_hdr->flags, ipa_ctx->stats.rx_excp_pkts);
+
+ if (unlikely(mux_hdr->flags & IPA_A5_MUX_HDR_EXCP_FLAG_TAG)) {
+ if (ipa_ctx->ipa_hw_mode != IPA_HW_MODE_VIRTUAL) {
+ /* retrieve the compl object from tag value */
+ mux_hdr++;
+ compl = (struct completion *)
+ ntohl(*((u32 *)mux_hdr));
+ IPADBG("%x %x %p\n", *(u32 *)mux_hdr,
+ *((u32 *)mux_hdr + 1), compl);
+
+ mutex_lock(&ipa_ctx->lock);
+ node = ipa_search(&ipa_ctx->tag_tree,
+ (u32)compl);
+ if (node) {
+ complete_all(compl);
+ rb_erase(&node->node,
+ &ipa_ctx->tag_tree);
+ kmem_cache_free(
+ ipa_ctx->tree_node_cache, node);
+ } else {
+ WARN_ON(1);
+ }
+ mutex_unlock(&ipa_ctx->lock);
+ }
+ dev_kfree_skb_any(rx_skb);
+ ipa_replenish_rx_cache();
+ ++cnt;
+ continue;
+ }
+
if (mux_hdr->src_pipe_index >= IPA_NUM_PIPES ||
!ipa_ctx->ep[mux_hdr->src_pipe_index].valid ||
!ipa_ctx->ep[mux_hdr->src_pipe_index].client_notify) {
@@ -555,6 +616,7 @@
ipa_ctx->ep[mux_hdr->src_pipe_index].client_notify);
dev_kfree_skb_any(rx_skb);
ipa_replenish_rx_cache();
+ ++cnt;
continue;
}
@@ -575,7 +637,10 @@
ep->client_notify(ep->priv, IPA_RECEIVE,
(unsigned long)(rx_skb));
ipa_replenish_rx_cache();
- } while (1);
+ cnt++;
+ } while (process_all);
+
+ return cnt;
}
/**
@@ -612,7 +677,7 @@
IPAERR("sps_set_config() failed %d\n", ret);
return;
}
- ipa_handle_rx_core();
+ ipa_handle_rx_core(true);
ipa_ctx->curr_polling_state = 0;
}
@@ -719,6 +784,8 @@
ipa_ctx->ep[ipa_ep_idx].valid = 1;
ipa_ctx->ep[ipa_ep_idx].client = sys_in->client;
+ ipa_ctx->ep[ipa_ep_idx].client_notify = sys_in->notify;
+ ipa_ctx->ep[ipa_ep_idx].priv = sys_in->priv;
if (ipa_cfg_ep(ipa_ep_idx, &sys_in->ipa_ep_cfg)) {
IPAERR("fail to configure EP.\n");
@@ -795,7 +862,7 @@
case 3:
sys_idx = ipa_ep_idx;
break;
- case 15:
+ case WLAN_AMPDU_TX_EP:
sys_idx = IPA_A5_WLAN_AMPDU_OUT;
break;
default:
@@ -870,8 +937,7 @@
* @user1
* @user2
*
- * This notified callback (client_notify) is for
- * the destination client.
+ * This notified callback is for the destination client.
* This function is supplied in ipa_connect.
*/
static void ipa_tx_comp_usr_notify_release(void *user1, void *user2)
@@ -881,6 +947,9 @@
IPADBG("skb=%p ep=%d\n", skb, ep_idx);
+ IPA_STATS_INC_TX_CNT(ep_idx, ipa_ctx->stats.tx_sw_pkts,
+ ipa_ctx->stats.tx_hw_pkts);
+
if (ipa_ctx->ep[ep_idx].client_notify)
ipa_ctx->ep[ep_idx].client_notify(ipa_ctx->ep[ep_idx].priv,
IPA_WRITE_DONE, (unsigned long)skb);
@@ -888,6 +957,12 @@
dev_kfree_skb_any(skb);
}
+static void ipa_tx_cmd_comp(void *user1, void *user2)
+{
+ IPA_STATS_INC_CNT(ipa_ctx->stats.imm_cmds[IPA_IP_PACKET_INIT]);
+ kfree(user1);
+}
+
/**
* ipa_tx_dp() - Data-path tx handler
* @dst: [in] which IPA destination to route tx packets to
@@ -911,7 +986,7 @@
* get notified by the supplied callback - ipa_sps_irq_tx_comp()
*
* ipa_sps_irq_tx_comp will call to the user supplied
- * callback (supplied in ipa_connect())
+ * callback (from ipa_connect)
*
* Returns: 0 on success, negative on failure
*/
@@ -925,23 +1000,22 @@
memset(&desc, 0, 2 * sizeof(struct ipa_desc));
ipa_ep_idx = ipa_get_ep_mapping(ipa_ctx->mode, dst);
- if (ipa_ep_idx == -1) {
+ if (unlikely(ipa_ep_idx == -1)) {
IPAERR("dest EP does not exist.\n");
goto fail_gen;
}
- if (ipa_ctx->ep[ipa_ep_idx].valid == 0) {
+ if (unlikely(ipa_ctx->ep[ipa_ep_idx].valid == 0)) {
IPAERR("dest EP not valid.\n");
goto fail_gen;
}
if (IPA_CLIENT_IS_CONS(dst)) {
- cmd = kzalloc(sizeof(struct ipa_ip_packet_init), GFP_KERNEL);
+ cmd = kzalloc(sizeof(struct ipa_ip_packet_init), GFP_ATOMIC);
if (!cmd) {
IPAERR("failed to alloc immediate command object\n");
goto fail_mem_alloc;
}
- memset(cmd, 0x00, sizeof(*cmd));
cmd->destination_pipe_index = ipa_ep_idx;
if (meta && meta->mbim_stream_id_valid)
@@ -950,6 +1024,8 @@
desc[0].pyld = cmd;
desc[0].len = sizeof(struct ipa_ip_packet_init);
desc[0].type = IPA_IMM_CMD_DESC;
+ desc[0].callback = ipa_tx_cmd_comp;
+ desc[0].user1 = cmd;
desc[1].pyld = skb->data;
desc[1].len = skb->len;
desc[1].type = IPA_DATA_DESC_SKB;
@@ -957,7 +1033,8 @@
desc[1].user1 = skb;
desc[1].user2 = (void *)ipa_ep_idx;
- if (ipa_send(&ipa_ctx->sys[IPA_A5_LAN_WAN_OUT], 2, desc)) {
+ if (ipa_send(&ipa_ctx->sys[IPA_A5_LAN_WAN_OUT], 2, desc,
+ true)) {
IPAERR("fail to send immediate command\n");
goto fail_send;
}
@@ -970,7 +1047,7 @@
desc[0].user2 = (void *)ipa_ep_idx;
if (ipa_send_one(&ipa_ctx->sys[IPA_A5_WLAN_AMPDU_OUT],
- &desc[0])) {
+ &desc[0], true)) {
IPAERR("fail to send skb\n");
goto fail_gen;
}
@@ -999,7 +1076,7 @@
*/
void ipa_wq_handle_rx(struct work_struct *work)
{
- ipa_handle_rx_core();
+ ipa_handle_rx_core(true);
ipa_rx_switch_to_intr_mode();
}
@@ -1030,8 +1107,7 @@
rx_len_cached = sys->len;
spin_unlock_irqrestore(&sys->spinlock, irq_flags);
- /* true RX data path is not currently exercised so drop the ceil */
- while (rx_len_cached < (IPA_RX_POOL_CEIL >> 3)) {
+ while (rx_len_cached < IPA_RX_POOL_CEIL) {
rx_pkt = kmem_cache_zalloc(ipa_ctx->rx_pkt_wrapper_cache,
GFP_KERNEL);
if (!rx_pkt) {
diff --git a/drivers/platform/msm/ipa/ipa_flt.c b/drivers/platform/msm/ipa/ipa_flt.c
index 337b016..b63b939 100644
--- a/drivers/platform/msm/ipa/ipa_flt.c
+++ b/drivers/platform/msm/ipa/ipa_flt.c
@@ -55,7 +55,11 @@
start = buf;
hdr = (struct ipa_flt_rule_hw_hdr *)buf;
hdr->u.hdr.action = entry->rule.action;
- hdr->u.hdr.rt_tbl_idx = entry->rt_tbl->idx;
+ if (entry->rt_tbl)
+ hdr->u.hdr.rt_tbl_idx = entry->rt_tbl->idx;
+ else
+ /* for excp action flt rules, rt tbl index is meaningless */
+ hdr->u.hdr.rt_tbl_idx = 0;
hdr->u.hdr.rsvd = 0;
buf += sizeof(struct ipa_flt_rule_hw_hdr);
@@ -505,19 +509,23 @@
struct ipa_flt_entry *entry;
struct ipa_tree_node *node;
- if (!rule->rt_tbl_hdl) {
- IPAERR("flt rule does not point to valid RT tbl\n");
- goto error;
- }
+ if (rule->action != IPA_PASS_TO_EXCEPTION) {
+ if (!rule->rt_tbl_hdl) {
+ IPAERR("flt rule does not point to valid RT tbl\n");
+ goto error;
+ }
- if (ipa_search(&ipa_ctx->rt_tbl_hdl_tree, rule->rt_tbl_hdl) == NULL) {
- IPAERR("RT tbl not found\n");
- goto error;
- }
+ if (ipa_search(&ipa_ctx->rt_tbl_hdl_tree,
+ rule->rt_tbl_hdl) == NULL) {
+ IPAERR("RT tbl not found\n");
+ goto error;
+ }
- if (((struct ipa_rt_tbl *)rule->rt_tbl_hdl)->cookie != IPA_COOKIE) {
- IPAERR("flt rule cookie is invalid\n");
- goto error;
+ if (((struct ipa_rt_tbl *)rule->rt_tbl_hdl)->cookie !=
+ IPA_COOKIE) {
+ IPAERR("RT table cookie is invalid\n");
+ goto error;
+ }
}
node = kmem_cache_zalloc(ipa_ctx->tree_node_cache, GFP_KERNEL);
@@ -541,7 +549,8 @@
else
list_add(&entry->link, &tbl->head_flt_rule_list);
tbl->rule_cnt++;
- entry->rt_tbl->ref_cnt++;
+ if (entry->rt_tbl)
+ entry->rt_tbl->ref_cnt++;
*rule_hdl = (u32)entry;
IPADBG("add flt rule rule_cnt=%d\n", tbl->rule_cnt);
@@ -565,20 +574,23 @@
struct ipa_flt_entry *entry = (struct ipa_flt_entry *)rule_hdl;
struct ipa_tree_node *node;
+ node = ipa_search(&ipa_ctx->flt_rule_hdl_tree, rule_hdl);
+ if (node == NULL) {
+ IPAERR("lookup failed\n");
+
+ return -EINVAL;
+ }
+
if (entry == NULL || (entry->cookie != IPA_COOKIE)) {
IPAERR("bad params\n");
return -EINVAL;
}
- node = ipa_search(&ipa_ctx->flt_rule_hdl_tree, rule_hdl);
- if (node == NULL) {
- IPAERR("lookup failed\n");
- return -EPERM;
- }
list_del(&entry->link);
entry->tbl->rule_cnt--;
- entry->rt_tbl->ref_cnt--;
+ if (entry->rt_tbl)
+ entry->rt_tbl->ref_cnt--;
IPADBG("del flt rule rule_cnt=%d\n", entry->tbl->rule_cnt);
entry->cookie = 0;
kmem_cache_free(ipa_ctx->flt_rule_cache, entry);
@@ -595,6 +607,12 @@
{
struct ipa_flt_tbl *tbl;
+ if (rule == NULL || rule_hdl == NULL) {
+ IPAERR("bad parms rule=%p rule_hdl=%p\n", rule, rule_hdl);
+
+ return -EINVAL;
+ }
+
tbl = &ipa_ctx->glob_flt_tbl[ip];
IPADBG("add global flt rule ip=%d\n", ip);
@@ -608,16 +626,16 @@
struct ipa_flt_tbl *tbl;
int ipa_ep_idx;
- if (ip >= IPA_IP_MAX || rule == NULL || rule_hdl == NULL ||
- ep >= IPA_CLIENT_MAX) {
- IPAERR("bad parms\n");
+ if (rule == NULL || rule_hdl == NULL || ep >= IPA_CLIENT_MAX) {
+ IPAERR("bad parms rule=%p rule_hdl=%p ep=%d\n", rule,
+ rule_hdl, ep);
return -EINVAL;
}
ipa_ep_idx = ipa_get_ep_mapping(ipa_ctx->mode, ep);
if (ipa_ep_idx == IPA_FLT_TABLE_INDEX_NOT_FOUND ||
ipa_ctx->ep[ipa_ep_idx].valid == 0) {
- IPAERR("bad parms\n");
+ IPAERR("ep not valid and/or connected ep_idx=%d\n", ipa_ep_idx);
return -EINVAL;
}
@@ -695,7 +713,6 @@
if (hdls == NULL || hdls->num_hdls == 0 || hdls->ip >= IPA_IP_MAX) {
IPAERR("bad parm\n");
-
return -EINVAL;
}
@@ -736,6 +753,11 @@
{
int result;
+ if (ip >= IPA_IP_MAX) {
+ IPAERR("bad parm\n");
+ return -EINVAL;
+ }
+
mutex_lock(&ipa_ctx->lock);
if (__ipa_commit_flt(ip)) {
@@ -768,6 +790,11 @@
struct ipa_tree_node *node;
int i;
+ if (ip >= IPA_IP_MAX) {
+ IPAERR("bad parm\n");
+ return -EINVAL;
+ }
+
tbl = &ipa_ctx->glob_flt_tbl[ip];
mutex_lock(&ipa_ctx->lock);
IPADBG("reset flt ip=%d\n", ip);
@@ -775,9 +802,21 @@
node = ipa_search(&ipa_ctx->flt_rule_hdl_tree, (u32)entry);
if (node == NULL)
WARN_ON(1);
+
+ if ((ip == IPA_IP_v4 &&
+ entry->rule.attrib.attrib_mask == IPA_FLT_PROTOCOL &&
+ entry->rule.attrib.u.v4.protocol ==
+ IPA_INVALID_L4_PROTOCOL) ||
+ (ip == IPA_IP_v6 &&
+ entry->rule.attrib.attrib_mask == IPA_FLT_NEXT_HDR &&
+ entry->rule.attrib.u.v6.next_hdr ==
+ IPA_INVALID_L4_PROTOCOL))
+ continue;
+
list_del(&entry->link);
entry->tbl->rule_cnt--;
- entry->rt_tbl->ref_cnt--;
+ if (entry->rt_tbl)
+ entry->rt_tbl->ref_cnt--;
entry->cookie = 0;
kmem_cache_free(ipa_ctx->flt_rule_cache, entry);
@@ -796,7 +835,8 @@
WARN_ON(1);
list_del(&entry->link);
entry->tbl->rule_cnt--;
- entry->rt_tbl->ref_cnt--;
+ if (entry->rt_tbl)
+ entry->rt_tbl->ref_cnt--;
entry->cookie = 0;
kmem_cache_free(ipa_ctx->flt_rule_cache, entry);
diff --git a/drivers/platform/msm/ipa/ipa_hdr.c b/drivers/platform/msm/ipa/ipa_hdr.c
index 4b9a500..0439a69 100644
--- a/drivers/platform/msm/ipa/ipa_hdr.c
+++ b/drivers/platform/msm/ipa/ipa_hdr.c
@@ -12,7 +12,7 @@
#include "ipa_i.h"
-static const u32 ipa_hdr_bin_sz[IPA_HDR_BIN_MAX] = { 8, 16, 32, 64 };
+static const u32 ipa_hdr_bin_sz[IPA_HDR_BIN_MAX] = { 8, 16, 24, 36 };
/**
* ipa_generate_hdr_hw_tbl() - generates the headers table
@@ -234,20 +234,21 @@
return -EPERM;
}
-static int __ipa_del_hdr(u32 hdr_hdl)
+int __ipa_del_hdr(u32 hdr_hdl)
{
struct ipa_hdr_entry *entry = (struct ipa_hdr_entry *)hdr_hdl;
struct ipa_tree_node *node;
struct ipa_hdr_tbl *htbl = &ipa_ctx->hdr_tbl;
- if (!entry || (entry->cookie != IPA_COOKIE) || (entry->ref_cnt != 0)) {
- IPAERR("bad parm\n");
- return -EINVAL;
- }
node = ipa_search(&ipa_ctx->hdr_hdl_tree, hdr_hdl);
if (node == NULL) {
IPAERR("lookup failed\n");
- return -EPERM;
+ return -EINVAL;
+ }
+
+ if (!entry || (entry->cookie != IPA_COOKIE) || (entry->ref_cnt != 0)) {
+ IPAERR("bad parm\n");
+ return -EINVAL;
}
IPADBG("del hdr of sz=%d hdr_cnt=%d ofst=%d\n", entry->hdr_len,
@@ -545,17 +546,21 @@
struct ipa_tree_node *node;
int result = -EFAULT;
- if (entry == NULL || entry->cookie != IPA_COOKIE ||
- entry->ref_cnt == 0) {
- IPAERR("bad params\n");
- return -EINVAL;
- }
+ mutex_lock(&ipa_ctx->lock);
node = ipa_search(&ipa_ctx->hdr_hdl_tree, hdr_hdl);
if (node == NULL) {
IPAERR("lookup failed\n");
- return -EPERM;
+ result = -EINVAL;
+ goto bail;
}
- mutex_lock(&ipa_ctx->lock);
+
+ if (entry == NULL || entry->cookie != IPA_COOKIE ||
+ entry->ref_cnt == 0) {
+ IPAERR("bad params\n");
+ result = -EINVAL;
+ goto bail;
+ }
+
entry->ref_cnt--;
if (entry->ref_cnt == 0) {
if (__ipa_del_hdr(hdr_hdl)) {
diff --git a/drivers/platform/msm/ipa/ipa_hw_defs.h b/drivers/platform/msm/ipa/ipa_hw_defs.h
index 3131a84..3b9ce3d 100644
--- a/drivers/platform/msm/ipa/ipa_hw_defs.h
+++ b/drivers/platform/msm/ipa/ipa_hw_defs.h
@@ -164,12 +164,12 @@
u64 rsvd:32;
};
-#define IPA_A5_MUX_HDR_EXCP_FLAG_IP BIT(0)
-#define IPA_A5_MUX_HDR_EXCP_FLAG_NAT BIT(1)
-#define IPA_A5_MUX_HDR_EXCP_FLAG_SW_FLT BIT(2)
-#define IPA_A5_MUX_HDR_EXCP_FLAG_TAG BIT(3)
-#define IPA_A5_MUX_HDR_EXCP_FLAG_REPLICATED BIT(4)
-#define IPA_A5_MUX_HDR_EXCP_FLAG_IHL BIT(5)
+#define IPA_A5_MUX_HDR_EXCP_FLAG_IP BIT(7)
+#define IPA_A5_MUX_HDR_EXCP_FLAG_NAT BIT(6)
+#define IPA_A5_MUX_HDR_EXCP_FLAG_SW_FLT BIT(5)
+#define IPA_A5_MUX_HDR_EXCP_FLAG_TAG BIT(4)
+#define IPA_A5_MUX_HDR_EXCP_FLAG_REPLICATED BIT(3)
+#define IPA_A5_MUX_HDR_EXCP_FLAG_IHL BIT(2)
/**
* struct ipa_a5_mux_hdr - A5 MUX header definition
@@ -255,4 +255,12 @@
u64 public_ip_addr:32;
};
+/**
+ * struct ipa_ip_packet_tag - IPA_IP_PACKET_TAG command payload
+ * @tag: tag value returned with response
+ */
+struct ipa_ip_packet_tag {
+ u32 tag;
+};
+
#endif /* _IPA_HW_DEFS_H */
diff --git a/drivers/platform/msm/ipa/ipa_i.h b/drivers/platform/msm/ipa/ipa_i.h
index f6e1cb5..1b5b339 100644
--- a/drivers/platform/msm/ipa/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_i.h
@@ -34,11 +34,54 @@
#ifdef IPA_DEBUG
#define IPADBG(fmt, args...) \
- pr_debug(DRV_NAME " %s:%d " fmt, __func__, __LINE__, ## args)
+ pr_err(DRV_NAME " %s:%d " fmt, __func__, __LINE__, ## args)
+/* pr_debug(DRV_NAME " %s:%d " fmt, __func__, __LINE__, ## args) */
#else
#define IPADBG(fmt, args...)
#endif
+#define WLAN_AMPDU_TX_EP (15)
+#define MAX_NUM_EXCP (8)
+#define MAX_NUM_IMM_CMD (17)
+
+#define IPA_STATS
+
+#ifdef IPA_STATS
+#define IPA_STATS_INC_CNT(val) do { \
+ ++val; \
+ } while (0)
+#define IPA_STATS_INC_CNT_SAFE(val) do { \
+ atomic_inc(&val); \
+ } while (0)
+#define IPA_STATS_EXCP_CNT(flags, base) do { \
+ int i; \
+ for (i = 0; i < MAX_NUM_EXCP; i++) \
+ if (flags & BIT(i)) \
+ ++base[i]; \
+ } while (0)
+#define IPA_STATS_INC_TX_CNT(ep, sw, hw) do { \
+ if (ep == WLAN_AMPDU_TX_EP) \
+ ++hw; \
+ else \
+ ++sw; \
+ } while (0)
+#define IPA_STATS_INC_IC_CNT(num, base, stat_base) do { \
+ int i; \
+ for (i = 0; i < num; i++) \
+ ++stat_base[base[i].opcode]; \
+ } while (0)
+#define IPA_STATS_INC_BRIDGE_CNT(type, dir, base) do { \
+ ++base[type][dir]; \
+ } while (0)
+#else
+#define IPA_STATS_INC_CNT(x) do { } while (0)
+#define IPA_STATS_INC_CNT_SAFE(x) do { } while (0)
+#define IPA_STATS_EXCP_CNT(flags, base) do { } while (0)
+#define IPA_STATS_INC_TX_CNT(ep, sw, hw) do { } while (0)
+#define IPA_STATS_INC_IC_CNT(num, base, stat_base) do { } while (0)
+#define IPA_STATS_INC_BRIDGE_CNT(type, dir, base) do { } while (0)
+#endif
+
#define IPAERR(fmt, args...) \
pr_err(DRV_NAME " %s:%d " fmt, __func__, __LINE__, ## args)
@@ -71,6 +114,8 @@
#define IPA_RX_SKB_SIZE 2048
#define IPA_DFLT_HDR_NAME "ipa_excp_hdr"
+#define IPA_INVALID_L4_PROTOCOL 0xFF
+
#define IPA_CLIENT_IS_PROD(x) (x >= IPA_CLIENT_PROD && x < IPA_CLIENT_CONS)
#define IPA_CLIENT_IS_CONS(x) (x >= IPA_CLIENT_CONS && x < IPA_CLIENT_MAX)
@@ -110,17 +155,6 @@
};
/**
- * enum ipa_bridge_dir - direction of the bridge from air interface perspective
- *
- * IPA bridge direction
- */
-enum ipa_bridge_dir {
- IPA_DL,
- IPA_UL,
- IPA_DIR_MAX
-};
-
-/**
* struct ipa_mem_buffer - IPA memory buffer
* @base: base
* @phys_base: physical base address
@@ -298,13 +332,15 @@
* @connect: SPS connect
* @priv: user provided information which will forwarded once the user is
* notified for new data avail
- * @client_notify: user provided CB for EP events notification
+ * @client_notify: user provided CB for EP events notification, the event is
+ * data revived.
* @desc_fifo_in_pipe_mem: flag indicating if descriptors FIFO uses pipe memory
* @data_fifo_in_pipe_mem: flag indicating if data FIFO uses pipe memory
* @desc_fifo_pipe_mem_ofst: descriptors FIFO pipe memory offset
* @data_fifo_pipe_mem_ofst: data FIFO pipe memory offset
* @desc_fifo_client_allocated: if descriptors FIFO was allocated by a client
* @data_fifo_client_allocated: if data FIFO was allocated by a client
+ * @suspended: valid for B2B pipes, whether IPA EP is suspended
*/
struct ipa_ep_context {
int valid;
@@ -323,6 +359,7 @@
u32 data_fifo_pipe_mem_ofst;
bool desc_fifo_client_allocated;
bool data_fifo_client_allocated;
+ bool suspended;
};
/**
@@ -358,8 +395,7 @@
/**
* struct ipa_tx_pkt_wrapper - IPA Tx packet wrapper
- * @type: specify if this packet is a data packet (skb) or
- * an immediate command
+ * @type: specify if this packet is for the skb or immediate command
* @mem: memory buffer used by this Tx packet
* @work: work struct for current Tx packet
* @link: linked to the wrappers on that pipe
@@ -472,6 +508,28 @@
};
/**
+ * enum ipa_hw_mode - IPA hardware mode
+ * @IPA_HW_Normal: Regular IPA hardware
+ * @IPA_HW_Virtual: IPA hardware supporting virtual memory allocation
+ * @IPA_HW_PCIE: IPA hardware supporting memory allocation over PCIE Bridge
+ */
+enum ipa_hw_mode {
+ IPA_HW_MODE_NORMAL = 0,
+ IPA_HW_MODE_VIRTUAL = 1,
+ IPA_HW_MODE_PCIE = 2
+};
+
+
+struct ipa_stats {
+ u32 imm_cmds[MAX_NUM_IMM_CMD];
+ u32 tx_sw_pkts;
+ u32 tx_hw_pkts;
+ u32 rx_pkts;
+ u32 rx_excp_pkts[MAX_NUM_EXCP];
+ u32 bridged_pkts[IPA_BRIDGE_TYPE_MAX][IPA_BRIDGE_DIR_MAX];
+};
+
+/**
* struct ipa_context - IPA context
* @class: pointer to the struct class
* @dev_num: device number
@@ -524,6 +582,8 @@
* @empty_rt_tbl_mem: empty routing tables memory
* @pipe_mem_pool: pipe memory pool
* @one_kb_no_straddle_pool: one kb no straddle pool
+ * @ipa_hw_type: type of IPA HW type (e.g. IPA 1.0, IPA 1.1 etc')
+ * @ipa_hw_mode: mode of IPA HW mode (e.g. Normal, Virtual or over PCIe)
*
* IPA context - holds all relevant info about IPA driver and its state
*/
@@ -560,6 +620,7 @@
struct rb_root rt_rule_hdl_tree;
struct rb_root rt_tbl_hdl_tree;
struct rb_root flt_rule_hdl_tree;
+ struct rb_root tag_tree;
struct ipa_nat_mem nat_mem;
u32 excp_hdr_hdl;
u32 dflt_v4_rt_rule_hdl;
@@ -584,7 +645,15 @@
u32 clnt_hdl_data_in;
u32 clnt_hdl_data_out;
u8 a5_pipe_index;
+ struct list_head intf_list;
+ struct list_head msg_list;
+ struct list_head pull_msg_list;
+ struct mutex msg_lock;
+ wait_queue_head_t msg_waitq;
enum ipa_hw_type ipa_hw_type;
+ enum ipa_hw_mode ipa_hw_mode;
+ /* featurize if memory footprint becomes a concern */
+ struct ipa_stats stats;
};
/**
@@ -655,6 +724,7 @@
u32 ipa_pipe_mem_start_ofst;
u32 ipa_pipe_mem_size;
enum ipa_hw_type ipa_hw_type;
+ enum ipa_hw_mode ipa_hw_mode;
struct a2_mux_pipe_connection a2_to_ipa_pipe;
struct a2_mux_pipe_connection ipa_to_a2_pipe;
};
@@ -665,10 +735,13 @@
struct a2_mux_pipe_connection *pipe_connect);
void rmnet_bridge_get_client_handles(u32 *producer_handle,
u32 *consumer_handle);
-int ipa_send_one(struct ipa_sys_context *sys, struct ipa_desc *desc);
-int ipa_send(struct ipa_sys_context *sys, u16 num_desc, struct ipa_desc *desc);
+int ipa_send_one(struct ipa_sys_context *sys, struct ipa_desc *desc,
+ bool in_atomic);
+int ipa_send(struct ipa_sys_context *sys, u16 num_desc, struct ipa_desc *desc,
+ bool in_atomic);
int ipa_get_ep_mapping(enum ipa_operating_mode mode,
enum ipa_client_type client);
+int ipa_get_client_mapping(enum ipa_operating_mode mode, int pipe_idx);
int ipa_generate_hw_rule(enum ipa_ip_type ip,
const struct ipa_rule_attrib *attrib,
u8 **buf,
@@ -688,30 +761,6 @@
void ipa_debugfs_init(void);
void ipa_debugfs_remove(void);
-/*
- * below functions read from/write to IPA local memory a.k.a. device memory.
- * the order of the arguments is deliberately different from the ipa_write*
- * functions which operate on system memory
- */
-void ipa_write_dev_8(u8 val, u16 ofst_ipa_sram);
-void ipa_write_dev_16(u16 val, u16 ofst_ipa_sram);
-void ipa_write_dev_32(u32 val, u16 ofst_ipa_sram);
-unsigned int ipa_read_dev_8(u16 ofst_ipa_sram);
-unsigned int ipa_read_dev_16(u16 ofst_ipa_sram);
-unsigned int ipa_read_dev_32(u16 ofst_ipa_sram);
-void ipa_write_dev_8rep(u16 ofst_ipa_sram, const void *buf,
- unsigned long count);
-void ipa_write_dev_16rep(u16 ofst_ipa_sram, const void *buf,
- unsigned long count);
-void ipa_write_dev_32rep(u16 ofst_ipa_sram, const void *buf,
- unsigned long count);
-void ipa_read_dev_8rep(u16 ofst_ipa_sram, void *buf, unsigned long count);
-void ipa_read_dev_16rep(u16 ofst_ipa_sram, void *buf, unsigned long count);
-void ipa_read_dev_32rep(u16 ofst_ipa_sram, void *buf, unsigned long count);
-void ipa_memset_dev(u16 ofst_ipa_sram, u8 value, unsigned int count);
-void ipa_memcpy_from_dev(void *dest, u16 ofst_ipa_sram, unsigned int count);
-void ipa_memcpy_to_dev(u16 ofst_ipa_sram, void *source, unsigned int count);
-
int ipa_insert(struct rb_root *root, struct ipa_tree_node *data);
struct ipa_tree_node *ipa_search(struct rb_root *root, u32 hdl);
void ipa_dump_buff_internal(void *base, dma_addr_t phy_base, u32 size);
@@ -730,7 +779,7 @@
int ipa_cfg_filter(u32 disable);
void ipa_wq_write_done(struct work_struct *work);
void ipa_wq_handle_rx(struct work_struct *work);
-void ipa_handle_rx_core(void);
+int ipa_handle_rx_core(bool process_all);
int ipa_pipe_mem_init(u32 start_ofst, u32 size);
int ipa_pipe_mem_alloc(u32 *ofst, u32 size);
int ipa_pipe_mem_free(u32 ofst, u32 size);
@@ -738,6 +787,8 @@
struct ipa_context *ipa_get_ctx(void);
void ipa_enable_clks(void);
void ipa_disable_clks(void);
+int __ipa_del_rt_rule(u32 rule_hdl);
+int __ipa_del_hdr(u32 hdr_hdl);
static inline u32 ipa_read_reg(void *base, u32 offset)
{
@@ -756,7 +807,12 @@
int ipa_bridge_init(void);
void ipa_bridge_cleanup(void);
-int ipa_bridge_setup(enum ipa_bridge_dir dir);
-int ipa_bridge_teardown(enum ipa_bridge_dir dir);
+
+ssize_t ipa_read(struct file *filp, char __user *buf, size_t count,
+ loff_t *f_pos);
+int ipa_pull_msg(struct ipa_msg_meta *meta, char *buff, size_t count);
+int ipa_query_intf(struct ipa_ioc_query_intf *lookup);
+int ipa_query_intf_tx_props(struct ipa_ioc_query_intf_tx_props *tx);
+int ipa_query_intf_rx_props(struct ipa_ioc_query_intf_rx_props *rx);
#endif /* _IPA_I_H_ */
diff --git a/drivers/platform/msm/ipa/ipa_intf.c b/drivers/platform/msm/ipa/ipa_intf.c
new file mode 100644
index 0000000..9876650
--- /dev/null
+++ b/drivers/platform/msm/ipa/ipa_intf.c
@@ -0,0 +1,490 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include "ipa_i.h"
+
+struct ipa_intf {
+ char name[IPA_RESOURCE_NAME_MAX];
+ struct list_head link;
+ u32 num_tx_props;
+ u32 num_rx_props;
+ struct ipa_ioc_tx_intf_prop *tx;
+ struct ipa_ioc_rx_intf_prop *rx;
+};
+
+struct ipa_push_msg {
+ struct ipa_msg_meta meta;
+ ipa_msg_free_fn callback;
+ void *buff;
+ struct list_head link;
+};
+
+struct ipa_pull_msg {
+ struct ipa_msg_meta meta;
+ ipa_msg_pull_fn callback;
+ struct list_head link;
+};
+
+/**
+ * ipa_register_intf() - register "logical" interface
+ * @name: [in] interface name
+ * @tx: [in] TX properties of the interface
+ * @rx: [in] RX properties of the interface
+ *
+ * Register an interface and its tx and rx properties, this allows
+ * configuration of rules from user-space
+ *
+ * Returns: 0 on success, negative on failure
+ *
+ * Note: Should not be called from atomic context
+ */
+int ipa_register_intf(const char *name, const struct ipa_tx_intf *tx,
+ const struct ipa_rx_intf *rx)
+{
+ struct ipa_intf *intf;
+ u32 len;
+
+ if (name == NULL || (tx == NULL && rx == NULL)) {
+ IPAERR("invalid params name=%p tx=%p rx=%p\n", name, tx, rx);
+ return -EINVAL;
+ }
+
+ len = sizeof(struct ipa_intf);
+ intf = kzalloc(len, GFP_KERNEL);
+ if (intf == NULL) {
+ IPAERR("fail to alloc 0x%x bytes\n", len);
+ return -ENOMEM;
+ }
+
+ strlcpy(intf->name, name, IPA_RESOURCE_NAME_MAX);
+
+ if (tx) {
+ intf->num_tx_props = tx->num_props;
+ len = tx->num_props * sizeof(struct ipa_ioc_tx_intf_prop);
+ intf->tx = kzalloc(len, GFP_KERNEL);
+ if (intf->tx == NULL) {
+ IPAERR("fail to alloc 0x%x bytes\n", len);
+ kfree(intf);
+ return -ENOMEM;
+ }
+ memcpy(intf->tx, tx->prop, len);
+ }
+
+ if (rx) {
+ intf->num_rx_props = rx->num_props;
+ len = rx->num_props * sizeof(struct ipa_ioc_rx_intf_prop);
+ intf->rx = kzalloc(len, GFP_KERNEL);
+ if (intf->rx == NULL) {
+ IPAERR("fail to alloc 0x%x bytes\n", len);
+ kfree(intf->tx);
+ kfree(intf);
+ return -ENOMEM;
+ }
+ memcpy(intf->rx, rx->prop, len);
+ }
+
+ mutex_lock(&ipa_ctx->lock);
+ list_add_tail(&intf->link, &ipa_ctx->intf_list);
+ mutex_unlock(&ipa_ctx->lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(ipa_register_intf);
+
+/**
+ * ipa_deregister_intf() - de-register previously registered logical interface
+ * @name: [in] interface name
+ *
+ * De-register a previously registered interface
+ *
+ * Returns: 0 on success, negative on failure
+ *
+ * Note: Should not be called from atomic context
+ */
+int ipa_deregister_intf(const char *name)
+{
+ struct ipa_intf *entry;
+ struct ipa_intf *next;
+ int result = -EINVAL;
+
+ if (name == NULL) {
+ IPAERR("invalid param name=%p\n", name);
+ return result;
+ }
+
+ mutex_lock(&ipa_ctx->lock);
+ list_for_each_entry_safe(entry, next, &ipa_ctx->intf_list, link) {
+ if (!strncmp(entry->name, name, IPA_RESOURCE_NAME_MAX)) {
+ list_del(&entry->link);
+ kfree(entry->rx);
+ kfree(entry->tx);
+ kfree(entry);
+ result = 0;
+ break;
+ }
+ }
+ mutex_unlock(&ipa_ctx->lock);
+ return result;
+}
+EXPORT_SYMBOL(ipa_deregister_intf);
+
+/**
+ * ipa_query_intf() - query logical interface properties
+ * @lookup: [inout] interface name and number of properties
+ *
+ * Obtain the handle and number of tx and rx properties for the named
+ * interface, used as part of querying the tx and rx properties for
+ * configuration of various rules from user-space
+ *
+ * Returns: 0 on success, negative on failure
+ *
+ * Note: Should not be called from atomic context
+ */
+int ipa_query_intf(struct ipa_ioc_query_intf *lookup)
+{
+ struct ipa_intf *entry;
+ int result = -EINVAL;
+
+ if (lookup == NULL) {
+ IPAERR("invalid param lookup=%p\n", lookup);
+ return result;
+ }
+
+ mutex_lock(&ipa_ctx->lock);
+ list_for_each_entry(entry, &ipa_ctx->intf_list, link) {
+ if (!strncmp(entry->name, lookup->name,
+ IPA_RESOURCE_NAME_MAX)) {
+ lookup->num_tx_props = entry->num_tx_props;
+ lookup->num_rx_props = entry->num_rx_props;
+ result = 0;
+ break;
+ }
+ }
+ mutex_unlock(&ipa_ctx->lock);
+ return result;
+}
+
+/**
+ * ipa_query_intf_tx_props() - qeury TX props of an interface
+ * @tx: [inout] interface tx attributes
+ *
+ * Obtain the tx properties for the specifed interface
+ *
+ * Returns: 0 on success, negative on failure
+ *
+ * Note: Should not be called from atomic context
+ */
+int ipa_query_intf_tx_props(struct ipa_ioc_query_intf_tx_props *tx)
+{
+ struct ipa_intf *entry;
+ int result = -EINVAL;
+
+ if (tx == NULL) {
+ IPAERR("invalid param tx=%p\n", tx);
+ return result;
+ }
+
+ mutex_lock(&ipa_ctx->lock);
+ list_for_each_entry(entry, &ipa_ctx->intf_list, link) {
+ if (!strncmp(entry->name, tx->name, IPA_RESOURCE_NAME_MAX)) {
+ memcpy(tx->tx, entry->tx, entry->num_tx_props *
+ sizeof(struct ipa_ioc_tx_intf_prop));
+ result = 0;
+ break;
+ }
+ }
+ mutex_unlock(&ipa_ctx->lock);
+ return result;
+}
+
+/**
+ * ipa_query_intf_rx_props() - qeury RX props of an interface
+ * @rx: [inout] interface rx attributes
+ *
+ * Obtain the rx properties for the specifed interface
+ *
+ * Returns: 0 on success, negative on failure
+ *
+ * Note: Should not be called from atomic context
+ */
+int ipa_query_intf_rx_props(struct ipa_ioc_query_intf_rx_props *rx)
+{
+ struct ipa_intf *entry;
+ int result = -EINVAL;
+
+ if (rx == NULL) {
+ IPAERR("invalid param rx=%p\n", rx);
+ return result;
+ }
+
+ mutex_lock(&ipa_ctx->lock);
+ list_for_each_entry(entry, &ipa_ctx->intf_list, link) {
+ if (!strncmp(entry->name, rx->name, IPA_RESOURCE_NAME_MAX)) {
+ memcpy(rx->rx, entry->rx, entry->num_rx_props *
+ sizeof(struct ipa_ioc_rx_intf_prop));
+ result = 0;
+ break;
+ }
+ }
+ mutex_unlock(&ipa_ctx->lock);
+ return result;
+}
+
+/**
+ * ipa_send_msg() - Send "message" from kernel client to IPA driver
+ * @meta: [in] message meta-data
+ * @buff: [in] the payload for message
+ * @callback: [in] free callback
+ *
+ * Client supplies the message meta-data and payload which IPA driver buffers
+ * till read by user-space. After read from user space IPA driver invokes the
+ * callback supplied to free the message payload. Client must not touch/free
+ * the message payload after calling this API.
+ *
+ * Returns: 0 on success, negative on failure
+ *
+ * Note: Should not be called from atomic context
+ */
+int ipa_send_msg(struct ipa_msg_meta *meta, void *buff,
+ ipa_msg_free_fn callback)
+{
+ struct ipa_push_msg *msg;
+
+ if (meta == NULL || (buff == NULL && callback != NULL) ||
+ (buff != NULL && callback == NULL)) {
+ IPAERR("invalid param meta=%p buff=%p, callback=%p\n",
+ meta, buff, callback);
+ return -EINVAL;
+ }
+
+ msg = kzalloc(sizeof(struct ipa_push_msg), GFP_KERNEL);
+ if (msg == NULL) {
+ IPAERR("fail to alloc ipa_msg container\n");
+ return -ENOMEM;
+ }
+
+ msg->meta = *meta;
+ msg->buff = buff;
+ msg->callback = callback;
+
+ mutex_lock(&ipa_ctx->msg_lock);
+ list_add_tail(&msg->link, &ipa_ctx->msg_list);
+ mutex_unlock(&ipa_ctx->msg_lock);
+
+ wake_up(&ipa_ctx->msg_waitq);
+
+ return 0;
+}
+EXPORT_SYMBOL(ipa_send_msg);
+
+/**
+ * ipa_register_pull_msg() - register pull message type
+ * @meta: [in] message meta-data
+ * @callback: [in] pull callback
+ *
+ * Register message callback by kernel client with IPA driver for IPA driver to
+ * pull message on-demand.
+ *
+ * Returns: 0 on success, negative on failure
+ *
+ * Note: Should not be called from atomic context
+ */
+int ipa_register_pull_msg(struct ipa_msg_meta *meta, ipa_msg_pull_fn callback)
+{
+ struct ipa_pull_msg *msg;
+
+ if (meta == NULL || callback == NULL) {
+ IPAERR("invalid param meta=%p callback=%p\n", meta, callback);
+ return -EINVAL;
+ }
+
+ msg = kzalloc(sizeof(struct ipa_pull_msg), GFP_KERNEL);
+ if (msg == NULL) {
+ IPAERR("fail to alloc ipa_msg container\n");
+ return -ENOMEM;
+ }
+
+ msg->meta = *meta;
+ msg->callback = callback;
+
+ mutex_lock(&ipa_ctx->msg_lock);
+ list_add_tail(&msg->link, &ipa_ctx->pull_msg_list);
+ mutex_unlock(&ipa_ctx->msg_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(ipa_register_pull_msg);
+
+/**
+ * ipa_deregister_pull_msg() - De-register pull message type
+ * @meta: [in] message meta-data
+ *
+ * De-register "message" by kernel client from IPA driver
+ *
+ * Returns: 0 on success, negative on failure
+ *
+ * Note: Should not be called from atomic context
+ */
+int ipa_deregister_pull_msg(struct ipa_msg_meta *meta)
+{
+ struct ipa_pull_msg *entry;
+ struct ipa_pull_msg *next;
+ int result = -EINVAL;
+
+ if (meta == NULL) {
+ IPAERR("invalid param name=%p\n", meta);
+ return result;
+ }
+
+ mutex_lock(&ipa_ctx->msg_lock);
+ list_for_each_entry_safe(entry, next, &ipa_ctx->pull_msg_list, link) {
+ if (entry->meta.msg_len == meta->msg_len &&
+ entry->meta.msg_type == meta->msg_type) {
+ list_del(&entry->link);
+ kfree(entry);
+ result = 0;
+ break;
+ }
+ }
+ mutex_unlock(&ipa_ctx->msg_lock);
+ return result;
+}
+EXPORT_SYMBOL(ipa_deregister_pull_msg);
+
+/**
+ * ipa_read() - read message from IPA device
+ * @filp: [in] file pointer
+ * @buf: [out] buffer to read into
+ * @count: [in] size of above buffer
+ * @f_pos: [inout] file position
+ *
+ * Uer-space should continually read from /dev/ipa, read wll block when there
+ * are no messages to read. Upon return, user-space should read the ipa_msg_meta
+ * from the start of the buffer to know what type of message was read and its
+ * length in the remainder of the buffer. Buffer supplied must be big enough to
+ * hold the message meta-data and the largest defined message type
+ *
+ * Returns: how many bytes copied to buffer
+ *
+ * Note: Should not be called from atomic context
+ */
+ssize_t ipa_read(struct file *filp, char __user *buf, size_t count,
+ loff_t *f_pos)
+{
+ char __user *start;
+ struct ipa_push_msg *msg = NULL;
+ int ret;
+ DEFINE_WAIT(wait);
+ int locked;
+
+ start = buf;
+
+ while (1) {
+ prepare_to_wait(&ipa_ctx->msg_waitq, &wait, TASK_INTERRUPTIBLE);
+
+ mutex_lock(&ipa_ctx->msg_lock);
+ locked = 1;
+ if (!list_empty(&ipa_ctx->msg_list)) {
+ msg = list_first_entry(&ipa_ctx->msg_list,
+ struct ipa_push_msg, link);
+ list_del(&msg->link);
+ }
+
+ IPADBG("msg=%p\n", msg);
+
+ if (msg) {
+ locked = 0;
+ mutex_unlock(&ipa_ctx->msg_lock);
+ if (copy_to_user(buf, &msg->meta,
+ sizeof(struct ipa_msg_meta))) {
+ ret = -EFAULT;
+ break;
+ }
+ buf += sizeof(struct ipa_msg_meta);
+ count -= sizeof(struct ipa_msg_meta);
+ if (msg->buff) {
+ if (copy_to_user(buf, msg->buff,
+ msg->meta.msg_len)) {
+ ret = -EFAULT;
+ break;
+ }
+ buf += msg->meta.msg_len;
+ count -= msg->meta.msg_len;
+ msg->callback(msg->buff, msg->meta.msg_len,
+ msg->meta.msg_type);
+ }
+ }
+
+ ret = -EAGAIN;
+ if (filp->f_flags & O_NONBLOCK)
+ break;
+
+ ret = -EINTR;
+ if (signal_pending(current))
+ break;
+
+ if (start != buf)
+ break;
+
+ locked = 0;
+ mutex_unlock(&ipa_ctx->msg_lock);
+ schedule();
+ }
+
+ finish_wait(&ipa_ctx->msg_waitq, &wait);
+ if (start != buf && ret != -EFAULT)
+ ret = buf - start;
+
+ if (locked)
+ mutex_unlock(&ipa_ctx->msg_lock);
+
+ return ret;
+}
+
+/**
+ * ipa_pull_msg() - pull the specified message from client
+ * @meta: [in] message meta-data
+ * @buf: [out] buffer to read into
+ * @count: [in] size of above buffer
+ *
+ * Populate the supplied buffer with the pull message which is fetched
+ * from client, the message must have previously been registered with
+ * the IPA driver
+ *
+ * Returns: how many bytes copied to buffer
+ *
+ * Note: Should not be called from atomic context
+ */
+int ipa_pull_msg(struct ipa_msg_meta *meta, char *buff, size_t count)
+{
+ struct ipa_pull_msg *entry;
+ int result = -EINVAL;
+
+ if (meta == NULL || buff == NULL || !count) {
+ IPAERR("invalid param name=%p buff=%p count=%zu\n",
+ meta, buff, count);
+ return result;
+ }
+
+ mutex_lock(&ipa_ctx->msg_lock);
+ list_for_each_entry(entry, &ipa_ctx->pull_msg_list, link) {
+ if (entry->meta.msg_len == meta->msg_len &&
+ entry->meta.msg_type == meta->msg_type) {
+ result = entry->callback(buff, count, meta->msg_type);
+ break;
+ }
+ }
+ mutex_unlock(&ipa_ctx->msg_lock);
+ return result;
+}
diff --git a/drivers/platform/msm/ipa/ipa_nat.c b/drivers/platform/msm/ipa/ipa_nat.c
index c13c53a..befa2cf 100644
--- a/drivers/platform/msm/ipa/ipa_nat.c
+++ b/drivers/platform/msm/ipa/ipa_nat.c
@@ -356,11 +356,11 @@
desc[cnt].len = sizeof(struct ipa_nat_dma);
desc[cnt].pyld = (void *)&cmd[cnt];
+
+ ret = ipa_send_cmd(1, &desc[cnt]);
+ if (ret == -EPERM)
+ IPAERR("Fail to send immediate command %d\n", cnt);
}
- IPADBG("posting dma command with entries %d\n", dma->entries);
- ret = ipa_send_cmd(dma->entries, desc);
- if (ret == -EPERM)
- IPAERR("Fail to send immediate command\n");
bail:
kfree(cmd);
diff --git a/drivers/platform/msm/ipa/ipa_ram_mmap.h b/drivers/platform/msm/ipa/ipa_ram_mmap.h
index 000718b..7e12b6a 100644
--- a/drivers/platform/msm/ipa/ipa_ram_mmap.h
+++ b/drivers/platform/msm/ipa/ipa_ram_mmap.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -21,7 +21,7 @@
#define IPA_RAM_NAT_OFST 0
#define IPA_RAM_NAT_SIZE 2048
#define IPA_RAM_HDR_OFST 2048
-#define IPA_RAM_HDR_SIZE 256
+#define IPA_RAM_HDR_SIZE 440
#define IPA_RAM_V4_FLT_OFST (IPA_RAM_HDR_OFST + IPA_RAM_HDR_SIZE)
#define IPA_RAM_V4_FLT_SIZE 1024
#define IPA_RAM_V4_RT_OFST (IPA_RAM_V4_FLT_OFST + IPA_RAM_V4_FLT_SIZE)
diff --git a/drivers/platform/msm/ipa/ipa_reg.h b/drivers/platform/msm/ipa/ipa_reg.h
index ecc069c..4a2acac 100644
--- a/drivers/platform/msm/ipa/ipa_reg.h
+++ b/drivers/platform/msm/ipa/ipa_reg.h
@@ -162,6 +162,15 @@
#define IPA_FILTER_FILTER_DIS_SHFT 0x0
#define IPA_SINGLE_NDP_MODE_OFST 0x00000064
#define IPA_QCNCM_OFST 0x00000060
+
+#define IPA_SPARE_REG_1_OFST 0x00002090
+
+#define IPA_ENDP_INIT_CTRL_n_OFST(n) (0x00000070 + 0x4 * (n))
+#define IPA_ENDP_INIT_CTRL_n_RMSK 0x1
+#define IPA_ENDP_INIT_CTRL_n_MAXn 19
+#define IPA_ENDP_INIT_CTRL_n_ENDP_SUSPEND_BMSK 0x1
+#define IPA_ENDP_INIT_CTRL_n_ENDP_SUSPEND_SHFT 0x0
+
#endif
diff --git a/drivers/platform/msm/ipa/ipa_rt.c b/drivers/platform/msm/ipa/ipa_rt.c
index 20f5c24..7d509c6 100644
--- a/drivers/platform/msm/ipa/ipa_rt.c
+++ b/drivers/platform/msm/ipa/ipa_rt.c
@@ -681,19 +681,20 @@
}
EXPORT_SYMBOL(ipa_add_rt_rule);
-static int __ipa_del_rt_rule(u32 rule_hdl)
+int __ipa_del_rt_rule(u32 rule_hdl)
{
struct ipa_rt_entry *entry = (struct ipa_rt_entry *)rule_hdl;
struct ipa_tree_node *node;
- if (entry == NULL || (entry->cookie != IPA_COOKIE)) {
- IPAERR("bad params\n");
- return -EINVAL;
- }
node = ipa_search(&ipa_ctx->rt_rule_hdl_tree, rule_hdl);
if (node == NULL) {
IPAERR("lookup failed\n");
- return -EPERM;
+ return -EINVAL;
+ }
+
+ if (entry == NULL || (entry->cookie != IPA_COOKIE)) {
+ IPAERR("bad params\n");
+ return -EINVAL;
}
if (entry->hdr)
@@ -770,6 +771,12 @@
int ipa_commit_rt(enum ipa_ip_type ip)
{
int ret;
+
+ if (ip >= IPA_IP_MAX) {
+ IPAERR("bad parm\n");
+ return -EINVAL;
+ }
+
/*
* issue a commit on the filtering module of same IP type since
* filtering rules point to routing tables
@@ -809,6 +816,11 @@
struct ipa_tree_node *node;
struct ipa_rt_tbl_set *rset;
+ if (ip >= IPA_IP_MAX) {
+ IPAERR("bad parm\n");
+ return -EINVAL;
+ }
+
/*
* issue a reset on the filtering module of same IP type since
* filtering rules point to routing tables
@@ -930,16 +942,21 @@
struct ipa_rt_tbl *entry = (struct ipa_rt_tbl *)rt_tbl_hdl;
struct ipa_tree_node *node;
enum ipa_ip_type ip = IPA_IP_MAX;
+ int result;
+
+ mutex_lock(&ipa_ctx->lock);
+ node = ipa_search(&ipa_ctx->rt_tbl_hdl_tree, rt_tbl_hdl);
+ if (node == NULL) {
+ IPAERR("lookup failed\n");
+ result = -EINVAL;
+ goto ret;
+ }
if (entry == NULL || (entry->cookie != IPA_COOKIE) ||
entry->ref_cnt == 0) {
IPAERR("bad parms\n");
- return -EINVAL;
- }
- node = ipa_search(&ipa_ctx->rt_tbl_hdl_tree, rt_tbl_hdl);
- if (node == NULL) {
- IPAERR("lookup failed\n");
- return -EPERM;
+ result = -EINVAL;
+ goto ret;
}
if (entry->set == &ipa_ctx->rt_tbl_set[IPA_IP_v4])
@@ -949,7 +966,6 @@
else
WARN_ON(1);
- mutex_lock(&ipa_ctx->lock);
entry->ref_cnt--;
if (entry->ref_cnt == 0 && entry->rule_cnt == 0) {
if (__ipa_del_rt_tbl(entry))
@@ -958,8 +974,12 @@
if (__ipa_commit_rt(ip))
IPAERR("fail to commit RT tbl\n");
}
+
+ result = 0;
+
+ret:
mutex_unlock(&ipa_ctx->lock);
- return 0;
+ return result;
}
EXPORT_SYMBOL(ipa_put_rt_tbl);
diff --git a/drivers/platform/msm/ipa/ipa_utils.c b/drivers/platform/msm/ipa/ipa_utils.c
index a81aece..264de0d 100644
--- a/drivers/platform/msm/ipa/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_utils.c
@@ -14,7 +14,6 @@
#include <linux/genalloc.h> /* gen_pool_alloc() */
#include <linux/io.h>
#include "ipa_i.h"
-
static const int ipa_ofst_meq32[] = { IPA_OFFSET_MEQ32_0,
IPA_OFFSET_MEQ32_1, -1 };
static const int ipa_ofst_meq128[] = { IPA_OFFSET_MEQ128_0,
@@ -123,6 +122,23 @@
}
/**
+ * ipa_get_client_mapping() - provide client mapping
+ * @mode: IPA operating mode
+ * @pipe_idx: IPA end-point number
+ *
+ * Return value: client mapping
+ */
+int ipa_get_client_mapping(enum ipa_operating_mode mode, int pipe_idx)
+{
+ int i;
+
+ for (i = 0; i < IPA_CLIENT_MAX; i++)
+ if (ep_mapping[mode][i] == pipe_idx)
+ break;
+ return i;
+}
+
+/**
* ipa_write_32() - convert 32 bit value to byte array
* @w: 32 bit integer
* @dest: byte array
@@ -751,6 +767,7 @@
int ipa_cfg_ep_mode(u32 clnt_hdl, const struct ipa_ep_cfg_mode *ipa_ep_cfg)
{
u32 val;
+ int ep;
if (clnt_hdl >= IPA_NUM_PIPES || ipa_ctx->ep[clnt_hdl].valid == 0 ||
ipa_ep_cfg == NULL) {
@@ -763,10 +780,16 @@
return -EINVAL;
}
+ ep = ipa_get_ep_mapping(ipa_ctx->mode, ipa_ep_cfg->dst);
+ if (ep == -1 && ipa_ep_cfg->mode == IPA_DMA) {
+ IPAERR("dst %d does not exist in mode %d\n", ipa_ep_cfg->dst,
+ ipa_ctx->mode);
+ return -EINVAL;
+ }
+
/* copy over EP cfg */
ipa_ctx->ep[clnt_hdl].cfg.mode = *ipa_ep_cfg;
- ipa_ctx->ep[clnt_hdl].dst_pipe_index = ipa_get_ep_mapping(ipa_ctx->mode,
- ipa_ep_cfg->dst);
+ ipa_ctx->ep[clnt_hdl].dst_pipe_index = ep;
val = IPA_SETFIELD(ipa_ctx->ep[clnt_hdl].cfg.mode.mode,
IPA_ENDP_INIT_MODE_n_MODE_SHFT,
@@ -944,206 +967,6 @@
mutex_unlock(&ipa_ctx->lock);
}
-/*
- * TODO: add swap if needed, for now assume LE is ok for device memory
- * even though IPA registers are assumed to be BE
- */
-/**
- * ipa_write_dev_8() - writes 8 bit value
- * @val: value
- * @ofst_ipa_sram: address to write to
- */
-void ipa_write_dev_8(u8 val, u16 ofst_ipa_sram)
-{
- iowrite8(val, (u32)ipa_ctx->mmio + 0x4000 + ofst_ipa_sram);
-}
-
-/**
- * ipa_write_dev_16() - writes 16 bit value
- * @val: value
- * @ofst_ipa_sram: address to write to
- *
- */
-void ipa_write_dev_16(u16 val, u16 ofst_ipa_sram)
-{
- iowrite16(val, (u32)ipa_ctx->mmio + 0x4000 + ofst_ipa_sram);
-}
-
-/**
- * ipa_write_dev_32() - writes 32 bit value
- * @val: value
- * @ofst_ipa_sram: address to write to
- */
-void ipa_write_dev_32(u32 val, u16 ofst_ipa_sram)
-{
- iowrite32(val, (u32)ipa_ctx->mmio + 0x4000 + ofst_ipa_sram);
-}
-
-/**
- * ipa_read_dev_8() - reads 8 bit value
- * @ofst_ipa_sram: address to read from
- *
- * Return value: value read
- */
-unsigned int ipa_read_dev_8(u16 ofst_ipa_sram)
-{
- return ioread8((u32)ipa_ctx->mmio + 0x4000 + ofst_ipa_sram);
-}
-
-/**
- * ipa_read_dev_16() - reads 16 bit value
- * @ofst_ipa_sram: address to read from
- *
- * Return value: value read
- */
-unsigned int ipa_read_dev_16(u16 ofst_ipa_sram)
-{
- return ioread16((u32)ipa_ctx->mmio + 0x4000 + ofst_ipa_sram);
-}
-
-/**
- * ipa_read_dev_32() - reads 32 bit value
- * @ofst_ipa_sram: address to read from
- *
- * Return value: value read
- */
-unsigned int ipa_read_dev_32(u16 ofst_ipa_sram)
-{
- return ioread32((u32)ipa_ctx->mmio + 0x4000 + ofst_ipa_sram);
-}
-
-/**
- * ipa_write_dev_8rep() - writes 8 bit value
- * @val: value
- * @ofst_ipa_sram: address to write to
- * @count: num of bytes to write
- */
-void ipa_write_dev_8rep(u16 ofst_ipa_sram, const void *buf, unsigned long count)
-{
- iowrite8_rep((void *)((u32)ipa_ctx->mmio + 0x4000 + ofst_ipa_sram), buf,
- count);
-}
-
-/**
- * ipa_write_dev_16rep() - writes 16 bit value
- * @val: value
- * @ofst_ipa_sram: address to write to
- * @count: num of bytes to write
- */
-void ipa_write_dev_16rep(u16 ofst_ipa_sram, const void *buf,
- unsigned long count)
-{
- iowrite16_rep((void *)((u32)ipa_ctx->mmio + 0x4000 + ofst_ipa_sram),
- buf, count);
-}
-
-/**
- * ipa_write_dev_32rep() - writes 32 bit value
- * @val: value
- * @ofst_ipa_sram: address to write to
- * @count: num of bytes to write
- */
-void ipa_write_dev_32rep(u16 ofst_ipa_sram, const void *buf,
- unsigned long count)
-{
- iowrite32_rep((void *)((u32)ipa_ctx->mmio + 0x4000 + ofst_ipa_sram),
- buf, count);
-}
-
-/**
- * ipa_read_dev_8rep() - reads 8 bit value
- * @ofst_ipa_sram: address to read from
- * @buf: buffer to read to
- * @count: number of bytes to read
- */
-void ipa_read_dev_8rep(u16 ofst_ipa_sram, void *buf, unsigned long count)
-{
- ioread8_rep((void *)((u32)ipa_ctx->mmio + 0x4000 + ofst_ipa_sram), buf,
- count);
-}
-
-/**
- * ipa_read_dev_16rep() - reads 16 bit value
- * @ofst_ipa_sram: address to read from
- * @buf: buffer to read to
- * @count: number of bytes to read
- */
-void ipa_read_dev_16rep(u16 ofst_ipa_sram, void *buf, unsigned long count)
-{
- ioread16_rep((void *)((u32)ipa_ctx->mmio + 0x4000 + ofst_ipa_sram), buf,
- count);
-}
-
-/**
- * ipa_read_dev_32rep() - reads 32 bit value
- * @ofst_ipa_sram: address to read from
- * @buf: buffer to read to
- * @count: number of bytes to read
- */
-void ipa_read_dev_32rep(u16 ofst_ipa_sram, void *buf, unsigned long count)
-{
- ioread32_rep((void *)((u32)ipa_ctx->mmio + 0x4000 + ofst_ipa_sram), buf,
- count);
-}
-
-/**
- * ipa_memset_dev() - memset IO
- * @ofst_ipa_sram: address to set
- * @value: value
- * @count: number of bytes to set
- */
-void ipa_memset_dev(u16 ofst_ipa_sram, u8 value, unsigned int count)
-{
- memset_io((void *)((u32)ipa_ctx->mmio + 0x4000 + ofst_ipa_sram), value,
- count);
-}
-
-/**
- * ipa_memcpy_from_dev() - copy memory from device
- * @dest: buffer to copy to
- * @ofst_ipa_sram: address
- * @count: number of bytes to copy
- */
-void ipa_memcpy_from_dev(void *dest, u16 ofst_ipa_sram, unsigned int count)
-{
- memcpy_fromio(dest, (void *)((u32)ipa_ctx->mmio + 0x4000 +
- ofst_ipa_sram), count);
-}
-
-/**
- * ipa_memcpy_to_dev() - copy memory to device
- * @ofst_ipa_sram: address
- * @source: buffer to copy from
- * @count: number of bytes to copy
- */
-void ipa_memcpy_to_dev(u16 ofst_ipa_sram, void *source, unsigned int count)
-{
- memcpy_toio((void *)((u32)ipa_ctx->mmio + 0x4000 + ofst_ipa_sram),
- source, count);
-}
-
-/**
- * ipa_defrag() - handle de-frag for bridging type of cases
- * @skb: skb
- *
- * Return value:
- * 0: success
- */
-int ipa_defrag(struct sk_buff *skb)
-{
- /*
- * Reassemble IP fragments. TODO: need to setup network_header to
- * point to start of IP header
- */
- if (ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)) {
- if (ip_defrag(skb, IP_DEFRAG_CONNTRACK_IN))
- return -EINPROGRESS;
- }
-
- /* skb is not fully assembled, send it back out */
- return 0;
-}
-
/**
* ipa_search() - search for handle in RB tree
* @root: tree root
diff --git a/drivers/platform/msm/ipa/rmnet_bridge.c b/drivers/platform/msm/ipa/rmnet_bridge.c
index 3c7f5ca..e5c7ec2 100644
--- a/drivers/platform/msm/ipa/rmnet_bridge.c
+++ b/drivers/platform/msm/ipa/rmnet_bridge.c
@@ -17,11 +17,12 @@
#include <mach/ipa.h>
#include <mach/sps.h>
#include "a2_service.h"
-#include "ipa_i.h"
static struct rmnet_bridge_cb_type {
u32 producer_handle;
u32 consumer_handle;
+ u32 ipa_producer_handle;
+ u32 ipa_consumer_handle;
bool is_connected;
} rmnet_bridge_cb;
@@ -57,8 +58,10 @@
rmnet_bridge_cb.is_connected = false;
- ret = ipa_bridge_teardown(IPA_DL);
- ret = ipa_bridge_teardown(IPA_UL);
+ ret = ipa_bridge_teardown(IPA_BRIDGE_DIR_DL, IPA_BRIDGE_TYPE_TETHERED,
+ rmnet_bridge_cb.ipa_consumer_handle);
+ ret = ipa_bridge_teardown(IPA_BRIDGE_DIR_UL, IPA_BRIDGE_TYPE_TETHERED,
+ rmnet_bridge_cb.ipa_producer_handle);
bail:
return ret;
}
@@ -78,6 +81,7 @@
u32 consumer_hdl,
int wwan_logical_channel_id)
{
+ struct ipa_sys_connect_params props;
int ret = 0;
if (true == rmnet_bridge_cb.is_connected) {
@@ -91,19 +95,35 @@
rmnet_bridge_cb.producer_handle = producer_hdl;
rmnet_bridge_cb.is_connected = true;
- ret = ipa_bridge_setup(IPA_DL);
+ memset(&props, 0, sizeof(props));
+ props.ipa_ep_cfg.mode.mode = IPA_DMA;
+ props.ipa_ep_cfg.mode.dst = IPA_CLIENT_USB_CONS;
+ props.client = IPA_CLIENT_A2_TETHERED_PROD;
+ props.desc_fifo_sz = 0x800;
+ /* setup notification callback if needed */
+
+ ret = ipa_bridge_setup(IPA_BRIDGE_DIR_DL, IPA_BRIDGE_TYPE_TETHERED,
+ &props, &rmnet_bridge_cb.ipa_consumer_handle);
if (ret) {
pr_err("%s: IPA DL bridge setup failure\n", __func__);
goto bail_dl;
}
- ret = ipa_bridge_setup(IPA_UL);
+
+ memset(&props, 0, sizeof(props));
+ props.client = IPA_CLIENT_A2_TETHERED_CONS;
+ props.desc_fifo_sz = 0x800;
+ /* setup notification callback if needed */
+
+ ret = ipa_bridge_setup(IPA_BRIDGE_DIR_UL, IPA_BRIDGE_TYPE_TETHERED,
+ &props, &rmnet_bridge_cb.ipa_producer_handle);
if (ret) {
pr_err("%s: IPA UL bridge setup failure\n", __func__);
goto bail_ul;
}
return 0;
bail_ul:
- ipa_bridge_teardown(IPA_DL);
+ ipa_bridge_teardown(IPA_BRIDGE_DIR_DL, IPA_BRIDGE_TYPE_TETHERED,
+ rmnet_bridge_cb.ipa_consumer_handle);
bail_dl:
rmnet_bridge_cb.is_connected = false;
bail:
diff --git a/drivers/platform/msm/qpnp-vibrator.c b/drivers/platform/msm/qpnp-vibrator.c
new file mode 100644
index 0000000..ca3832d
--- /dev/null
+++ b/drivers/platform/msm/qpnp-vibrator.c
@@ -0,0 +1,343 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/hrtimer.h>
+#include <linux/of_device.h>
+#include <linux/spmi.h>
+
+#include <linux/qpnp/vibrator.h>
+#include "../../staging/android/timed_output.h"
+
+#define QPNP_VIB_VTG_CTL(base) (base + 0x41)
+#define QPNP_VIB_EN_CTL(base) (base + 0x46)
+
+#define QPNP_VIB_MAX_LEVEL 31
+#define QPNP_VIB_MIN_LEVEL 12
+
+#define QPNP_VIB_DEFAULT_TIMEOUT 15000
+#define QPNP_VIB_DEFAULT_VTG_LVL 3100
+
+#define QPNP_VIB_EN BIT(7)
+#define QPNP_VIB_VTG_SET_MASK 0x1F
+#define QPNP_VIB_LOGIC_SHIFT 4
+
+struct qpnp_vib {
+ struct spmi_device *spmi;
+ struct hrtimer vib_timer;
+ struct timed_output_dev timed_dev;
+ struct work_struct work;
+
+ u8 reg_vtg_ctl;
+ u8 reg_en_ctl;
+ u16 base;
+ int state;
+ int vtg_level;
+ int timeout;
+ struct mutex lock;
+};
+
+static struct qpnp_vib *vib_dev;
+
+static int qpnp_vib_read_u8(struct qpnp_vib *vib, u8 *data, u16 reg)
+{
+ int rc;
+
+ rc = spmi_ext_register_readl(vib->spmi->ctrl, vib->spmi->sid,
+ reg, data, 1);
+ if (rc < 0)
+ dev_err(&vib->spmi->dev,
+ "Error reading address: %X - ret %X\n", reg, rc);
+
+ return rc;
+}
+
+static int qpnp_vib_write_u8(struct qpnp_vib *vib, u8 *data, u16 reg)
+{
+ int rc;
+
+ rc = spmi_ext_register_writel(vib->spmi->ctrl, vib->spmi->sid,
+ reg, data, 1);
+ if (rc < 0)
+ dev_err(&vib->spmi->dev,
+ "Error writing address: %X - ret %X\n", reg, rc);
+
+ return rc;
+}
+
+int qpnp_vibrator_config(struct qpnp_vib_config *vib_cfg)
+{
+ u8 reg = 0;
+ int rc = -EINVAL, level;
+
+ if (vib_dev == NULL) {
+ pr_err("%s: vib_dev is NULL\n", __func__);
+ return -ENODEV;
+ }
+
+ level = vib_cfg->drive_mV / 100;
+ if (level) {
+ if ((level < QPNP_VIB_MIN_LEVEL) ||
+ (level > QPNP_VIB_MAX_LEVEL)) {
+ dev_err(&vib_dev->spmi->dev, "Invalid voltage level\n");
+ return -EINVAL;
+ }
+ } else {
+ dev_err(&vib_dev->spmi->dev, "Voltage level not specified\n");
+ return -EINVAL;
+ }
+
+ /* Configure the VTG CTL regiser */
+ reg = vib_dev->reg_vtg_ctl;
+ reg &= ~QPNP_VIB_VTG_SET_MASK;
+ reg |= (level & QPNP_VIB_VTG_SET_MASK);
+ rc = qpnp_vib_write_u8(vib_dev, ®, QPNP_VIB_VTG_CTL(vib_dev->base));
+ if (rc)
+ return rc;
+ vib_dev->reg_vtg_ctl = reg;
+
+ /* Configure the VIB ENABLE regiser */
+ reg = vib_dev->reg_en_ctl;
+ reg |= (!!vib_cfg->active_low) << QPNP_VIB_LOGIC_SHIFT;
+ if (vib_cfg->enable_mode == QPNP_VIB_MANUAL)
+ reg |= QPNP_VIB_EN;
+ else
+ reg |= BIT(vib_cfg->enable_mode - 1);
+ rc = qpnp_vib_write_u8(vib_dev, ®, QPNP_VIB_EN_CTL(vib_dev->base));
+ if (rc < 0)
+ return rc;
+ vib_dev->reg_en_ctl = reg;
+
+ return rc;
+}
+EXPORT_SYMBOL(qpnp_vibrator_config);
+
+static int qpnp_vib_set(struct qpnp_vib *vib, int on)
+{
+ int rc;
+ u8 val;
+
+ if (on) {
+ val = vib->reg_vtg_ctl;
+ val &= ~QPNP_VIB_VTG_SET_MASK;
+ val |= (vib->vtg_level & QPNP_VIB_VTG_SET_MASK);
+ rc = qpnp_vib_write_u8(vib, &val, QPNP_VIB_VTG_CTL(vib->base));
+ if (rc < 0)
+ return rc;
+ vib->reg_vtg_ctl = val;
+ val = vib->reg_en_ctl;
+ val |= QPNP_VIB_EN;
+ rc = qpnp_vib_write_u8(vib, &val, QPNP_VIB_EN_CTL(vib->base));
+ if (rc < 0)
+ return rc;
+ vib->reg_en_ctl = val;
+ } else {
+ val = vib->reg_en_ctl;
+ val &= ~QPNP_VIB_EN;
+ rc = qpnp_vib_write_u8(vib, &val, QPNP_VIB_EN_CTL(vib->base));
+ if (rc < 0)
+ return rc;
+ vib->reg_en_ctl = val;
+ }
+
+ return rc;
+}
+
+static void qpnp_vib_enable(struct timed_output_dev *dev, int value)
+{
+ struct qpnp_vib *vib = container_of(dev, struct qpnp_vib,
+ timed_dev);
+
+ mutex_lock(&vib->lock);
+ hrtimer_cancel(&vib->vib_timer);
+
+ if (value == 0)
+ vib->state = 0;
+ else {
+ value = (value > vib->timeout ?
+ vib->timeout : value);
+ vib->state = 1;
+ hrtimer_start(&vib->vib_timer,
+ ktime_set(value / 1000, (value % 1000) * 1000000),
+ HRTIMER_MODE_REL);
+ }
+ mutex_unlock(&vib->lock);
+ schedule_work(&vib->work);
+}
+
+static void qpnp_vib_update(struct work_struct *work)
+{
+ struct qpnp_vib *vib = container_of(work, struct qpnp_vib,
+ work);
+ qpnp_vib_set(vib, vib->state);
+}
+
+static int qpnp_vib_get_time(struct timed_output_dev *dev)
+{
+ struct qpnp_vib *vib = container_of(dev, struct qpnp_vib,
+ timed_dev);
+
+ if (hrtimer_active(&vib->vib_timer)) {
+ ktime_t r = hrtimer_get_remaining(&vib->vib_timer);
+ return (int)ktime_to_us(r);
+ } else
+ return 0;
+}
+
+static enum hrtimer_restart qpnp_vib_timer_func(struct hrtimer *timer)
+{
+ struct qpnp_vib *vib = container_of(timer, struct qpnp_vib,
+ vib_timer);
+
+ vib->state = 0;
+ schedule_work(&vib->work);
+
+ return HRTIMER_NORESTART;
+}
+
+#ifdef CONFIG_PM
+static int qpnp_vibrator_suspend(struct device *dev)
+{
+ struct qpnp_vib *vib = dev_get_drvdata(dev);
+
+ hrtimer_cancel(&vib->vib_timer);
+ cancel_work_sync(&vib->work);
+ /* turn-off vibrator */
+ qpnp_vib_set(vib, 0);
+
+ return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(qpnp_vibrator_pm_ops, qpnp_vibrator_suspend, NULL);
+
+static int __devinit qpnp_vibrator_probe(struct spmi_device *spmi)
+{
+ struct qpnp_vib *vib;
+ struct resource *vib_resource;
+ int rc;
+ u8 val;
+ u32 temp_val;
+
+ vib = devm_kzalloc(&spmi->dev, sizeof(*vib), GFP_KERNEL);
+ if (!vib)
+ return -ENOMEM;
+
+ vib->spmi = spmi;
+
+ vib->timeout = QPNP_VIB_DEFAULT_TIMEOUT;
+ rc = of_property_read_u32(spmi->dev.of_node,
+ "qcom,vib-timeout-ms", &temp_val);
+ if (!rc) {
+ vib->timeout = temp_val;
+ } else if (rc != EINVAL) {
+ dev_err(&spmi->dev, "Unable to read vib timeout\n");
+ return rc;
+ }
+
+ vib->vtg_level = QPNP_VIB_DEFAULT_VTG_LVL;
+ rc = of_property_read_u32(spmi->dev.of_node,
+ "qcom,vib-vtg-level-mV", &temp_val);
+ if (!rc) {
+ vib->vtg_level = temp_val;
+ } else if (rc != -EINVAL) {
+ dev_err(&spmi->dev, "Unable to read vtg level\n");
+ return rc;
+ }
+
+ vib->vtg_level /= 100;
+
+ vib_resource = spmi_get_resource(spmi, 0, IORESOURCE_MEM, 0);
+ if (!vib_resource) {
+ dev_err(&spmi->dev, "Unable to get vibrator base address\n");
+ return -EINVAL;
+ }
+ vib->base = vib_resource->start;
+
+ /* save the control registers values */
+ rc = qpnp_vib_read_u8(vib, &val, QPNP_VIB_VTG_CTL(vib->base));
+ if (rc < 0)
+ return rc;
+ vib->reg_vtg_ctl = val;
+
+ rc = qpnp_vib_read_u8(vib, &val, QPNP_VIB_EN_CTL(vib->base));
+ if (rc < 0)
+ return rc;
+ vib->reg_en_ctl = val;
+
+ mutex_init(&vib->lock);
+ INIT_WORK(&vib->work, qpnp_vib_update);
+
+ hrtimer_init(&vib->vib_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ vib->vib_timer.function = qpnp_vib_timer_func;
+
+ vib->timed_dev.name = "vibrator";
+ vib->timed_dev.get_time = qpnp_vib_get_time;
+ vib->timed_dev.enable = qpnp_vib_enable;
+
+ dev_set_drvdata(&spmi->dev, vib);
+
+ rc = timed_output_dev_register(&vib->timed_dev);
+ if (rc < 0)
+ return rc;
+
+ vib_dev = vib;
+
+ return rc;
+}
+
+static int __devexit qpnp_vibrator_remove(struct spmi_device *spmi)
+{
+ struct qpnp_vib *vib = dev_get_drvdata(&spmi->dev);
+
+ cancel_work_sync(&vib->work);
+ hrtimer_cancel(&vib->vib_timer);
+ timed_output_dev_unregister(&vib->timed_dev);
+ mutex_destroy(&vib->lock);
+
+ return 0;
+}
+
+static struct of_device_id spmi_match_table[] = {
+ { .compatible = "qcom,qpnp-vibrator",
+ },
+ {}
+};
+
+static struct spmi_driver qpnp_vibrator_driver = {
+ .driver = {
+ .name = "qcom,qpnp-vibrator",
+ .of_match_table = spmi_match_table,
+ .pm = &qpnp_vibrator_pm_ops,
+ },
+ .probe = qpnp_vibrator_probe,
+ .remove = __devexit_p(qpnp_vibrator_remove),
+};
+
+static int __init qpnp_vibrator_init(void)
+{
+ return spmi_driver_register(&qpnp_vibrator_driver);
+}
+module_init(qpnp_vibrator_init);
+
+static void __exit qpnp_vibrator_exit(void)
+{
+ return spmi_driver_unregister(&qpnp_vibrator_driver);
+}
+module_exit(qpnp_vibrator_exit);
+
+MODULE_DESCRIPTION("qpnp vibrator driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index 82d58ef..13e23e8 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -136,6 +136,7 @@
int amux_2_trim_delta;
uint16_t prev_last_good_ocv_raw;
int rconn_mohm;
+ int rbatt_capacitive_mohm;
struct mutex last_ocv_uv_mutex;
int last_ocv_uv;
int last_ocv_temp_decidegc;
@@ -847,8 +848,8 @@
{
int ibat_ua, vbat_uv, ocv_est_uv;
int rc;
-
- int rbatt_mohm = chip->default_rbatt_mohm + chip->rconn_mohm;
+ int rbatt_mohm = chip->default_rbatt_mohm + chip->rconn_mohm
+ + chip->rbatt_capacitive_mohm;
rc = pm8921_bms_get_simultaneous_battery_voltage_and_current(
&ibat_ua,
@@ -917,7 +918,10 @@
rc = pm8921_bms_get_simultaneous_battery_voltage_and_current(
&ibat_ua,
&vbat_uv);
-
+ /*
+ * don't include rbatt and rbatt_capacitve since we expect this to
+ * be used with a fake battery which does not have internal resistnaces
+ */
ocv_est_uv = vbat_uv + (ibat_ua * the_chip->rconn_mohm) / 1000;
pr_debug("forcing ocv to be %d due to bms reset mode\n", ocv_est_uv);
the_chip->last_ocv_uv = ocv_est_uv;
@@ -1072,6 +1076,10 @@
pr_debug("adding rconn_mohm = %d rbatt = %d\n",
the_chip->rconn_mohm, rbatt);
+ rbatt += the_chip->rbatt_capacitive_mohm;
+ pr_debug("adding rbatt_capacitive_mohm = %d rbatt = %d\n",
+ the_chip->rbatt_capacitive_mohm, rbatt);
+
if (is_between(20, 10, soc_rbatt))
rbatt = rbatt
+ ((20 - soc_rbatt) * chip->delta_rbatt_mohm) / 10;
@@ -1583,6 +1591,8 @@
}
EXPORT_SYMBOL(pm8921_bms_get_simultaneous_battery_voltage_and_current);
+#define SIGN(x) ((x) < 0 ? -1 : 1)
+
static void find_ocv_for_soc(struct pm8921_bms_chip *chip,
int batt_temp,
int chargecycles,
@@ -1597,7 +1607,6 @@
int pc, new_pc;
int batt_temp_degc = batt_temp / 10;
int ocv;
- int count = 0;
rc = (s64)shutdown_soc * (fcc_uah - uuc_uah);
rc = div_s64(rc, 100) + cc_uah + uuc_uah;
@@ -1611,17 +1620,55 @@
new_pc = interpolate_pc(chip->pc_temp_ocv_lut, batt_temp_degc, ocv);
pr_debug("test revlookup pc = %d for ocv = %d\n", new_pc, ocv);
- /* try 10 times to get a close enough pc */
- while (abs(new_pc - pc) > 1 && count++ < 10) {
+ if (abs(new_pc - pc) > 0) {
+ /* Maximum spins to make in while-loop when searching in
+ * full resolution.
+ */
+ const unsigned int max_spin_count =
+ chip->max_voltage_uv / 1000 - chip->v_cutoff + 1;
+ unsigned int count = 0;
int delta_mv = 5;
+ int diff = abs(new_pc - pc);
+ char sign = SIGN(new_pc - pc);
+ char old_sign;
+ int old_diff;
+ int old_ocv;
- if (new_pc > pc)
- delta_mv = -1 * delta_mv;
+ do {
+ count++;
+ old_ocv = ocv;
+ old_diff = diff;
+ old_sign = sign;
- ocv = ocv + delta_mv;
- new_pc = interpolate_pc(chip->pc_temp_ocv_lut,
- batt_temp_degc, ocv);
- pr_debug("test revlookup pc = %d for ocv = %d\n", new_pc, ocv);
+ if (new_pc > pc)
+ ocv -= delta_mv;
+ else
+ ocv += delta_mv;
+
+ new_pc = interpolate_pc(chip->pc_temp_ocv_lut,
+ batt_temp_degc, ocv);
+ pr_debug("test revlookup pc = %d for ocv = %d\n",
+ new_pc, ocv);
+ diff = abs(new_pc - pc);
+ sign = SIGN(new_pc - pc);
+
+ if (sign != old_sign) {
+ if (delta_mv == 5) {
+ /*
+ * we crossed our desired PC probably
+ * becuase we were overcorrecting
+ */
+ delta_mv = 1;
+ } else {
+ /* we crossed our desired PC even with
+ * 1mV steps, choose the best of two */
+ if (diff > old_diff)
+ ocv = old_ocv;
+
+ break;
+ }
+ }
+ } while (count <= max_spin_count && diff > 0);
}
*ocv_uv = ocv * 1000;
@@ -2869,6 +2916,8 @@
chip->default_rbatt_mohm
= palladium_1500_data.default_rbatt_mohm;
chip->delta_rbatt_mohm = palladium_1500_data.delta_rbatt_mohm;
+ chip->rbatt_capacitive_mohm
+ = palladium_1500_data.rbatt_capacitive_mohm;
return 0;
desay:
chip->fcc = desay_5200_data.fcc;
@@ -2878,6 +2927,8 @@
chip->rbatt_sf_lut = desay_5200_data.rbatt_sf_lut;
chip->default_rbatt_mohm = desay_5200_data.default_rbatt_mohm;
chip->delta_rbatt_mohm = desay_5200_data.delta_rbatt_mohm;
+ chip->rbatt_capacitive_mohm
+ = desay_5200_data.rbatt_capacitive_mohm;
return 0;
}
@@ -3008,9 +3059,9 @@
int ret = 0;
struct pm8921_soc_params raw;
- mutex_lock(&the_chip->bms_output_lock);
+ mutex_lock(&the_chip->last_ocv_uv_mutex);
read_soc_params_raw(the_chip, &raw, 300);
- mutex_unlock(&the_chip->bms_output_lock);
+ mutex_lock(&the_chip->last_ocv_uv_mutex);
*val = 0;
diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index b3fd5bc..f87a443 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -295,6 +295,7 @@
bool btc_panic_if_cant_stop_chg;
int stop_chg_upon_expiry;
bool disable_aicl;
+ int usb_type;
};
/* user space parameter to limit usb current */
@@ -1561,7 +1562,7 @@
return 0;
}
- type = the_chip->usb_psy.type;
+ type = the_chip->usb_type;
if (type == POWER_SUPPLY_TYPE_USB_DCP ||
type == POWER_SUPPLY_TYPE_USB_ACA ||
type == POWER_SUPPLY_TYPE_USB_CDP)
@@ -1694,7 +1695,7 @@
case POWER_SUPPLY_PROP_ONLINE:
val->intval = 0;
- if (the_chip->usb_psy.type == POWER_SUPPLY_TYPE_USB)
+ if (the_chip->usb_type == POWER_SUPPLY_TYPE_USB)
val->intval = is_usb_chg_plugged_in(the_chip);
break;
@@ -2360,7 +2361,7 @@
if (type < POWER_SUPPLY_TYPE_USB && type > POWER_SUPPLY_TYPE_BATTERY)
return -EINVAL;
- the_chip->usb_psy.type = type;
+ the_chip->usb_type = type;
power_supply_changed(&the_chip->usb_psy);
power_supply_changed(&the_chip->dc_psy);
return 0;
@@ -4902,6 +4903,7 @@
pm8921_chg_btc_override_init(chip);
chip->stop_chg_upon_expiry = pdata->stop_chg_upon_expiry;
+ chip->usb_type = POWER_SUPPLY_TYPE_UNKNOWN;
chip->usb_psy.name = "usb";
chip->usb_psy.type = POWER_SUPPLY_TYPE_USB;
@@ -4948,9 +4950,6 @@
platform_set_drvdata(pdev, chip);
the_chip = chip;
- /* set initial state of the USB charger type to UNKNOWN */
- power_supply_set_supply_type(&chip->usb_psy, POWER_SUPPLY_TYPE_UNKNOWN);
-
wake_lock_init(&chip->eoc_wake_lock, WAKE_LOCK_SUSPEND, "pm8921_eoc");
INIT_DELAYED_WORK(&chip->eoc_work, eoc_worker);
INIT_DELAYED_WORK(&chip->vin_collapse_check_work,
diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c
index 6135e71..7f60128 100644
--- a/drivers/spi/spi_qsd.c
+++ b/drivers/spi/spi_qsd.c
@@ -2375,7 +2375,7 @@
of_property_read_u32(node, "spi-max-frequency",
&pdata->max_clock_speed);
- of_property_read_u32(node, "infinite_mode",
+ of_property_read_u32(node, "qcom,infinite-mode",
&pdata->infinite_mode);
pdata->ver_reg_exists = of_property_read_bool(node
@@ -2485,13 +2485,12 @@
goto err_probe_exit;
}
- rc = of_property_read_u32(pdev->dev.of_node,
- "cell-index", &pdev->id);
- if (rc)
+ rc = of_alias_get_id(pdev->dev.of_node, "spi");
+ if (rc < 0)
dev_warn(&pdev->dev,
"using default bus_num %d\n", pdev->id);
else
- master->bus_num = pdev->id;
+ master->bus_num = pdev->id = rc;
for (i = 0; i < ARRAY_SIZE(spi_rsrcs); ++i) {
dd->spi_gpios[i] = of_get_gpio_flags(pdev->dev.of_node,
diff --git a/drivers/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c
index 34ec396..71554ed 100644
--- a/drivers/staging/android/lowmemorykiller.c
+++ b/drivers/staging/android/lowmemorykiller.c
@@ -207,6 +207,10 @@
if (tsk->flags & PF_KTHREAD)
continue;
+ /* if task no longer has any memory ignore it */
+ if (test_task_flag(tsk, TIF_MM_RELEASED))
+ continue;
+
if (time_before_eq(jiffies, lowmem_deathpending_timeout)) {
if (test_task_flag(tsk, TIF_MEMDIE)) {
rcu_read_unlock();
@@ -251,12 +255,14 @@
send_sig(SIGKILL, selected, 0);
set_tsk_thread_flag(selected, TIF_MEMDIE);
rem -= selected_tasksize;
+ rcu_read_unlock();
/* give the system time to free up the memory */
msleep_interruptible(20);
- }
+ } else
+ rcu_read_unlock();
+
lowmem_print(4, "lowmem_shrink %lu, %x, return %d\n",
nr_to_scan, sc->gfp_mask, rem);
- rcu_read_unlock();
mutex_unlock(&scan_mutex);
return rem;
}
diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c
index a27322e..c982587 100644
--- a/drivers/tty/serial/msm_serial_hs.c
+++ b/drivers/tty/serial/msm_serial_hs.c
@@ -2861,7 +2861,7 @@
if (unlikely(msm_uport->wakeup.irq < 0)) {
ret = -ENXIO;
- goto unmap_memory;
+ goto deregister_bus_client;
}
if (is_blsp_uart(msm_uport)) {
@@ -2878,7 +2878,7 @@
IORESOURCE_DMA, "uartdm_channels");
if (unlikely(!resource)) {
ret = -ENXIO;
- goto unmap_memory;
+ goto deregister_bus_client;
}
msm_uport->dma_tx_channel = resource->start;
@@ -2888,7 +2888,7 @@
IORESOURCE_DMA, "uartdm_crci");
if (unlikely(!resource)) {
ret = -ENXIO;
- goto unmap_memory;
+ goto deregister_bus_client;
}
msm_uport->dma_tx_crci = resource->start;
@@ -2905,7 +2905,7 @@
msm_uport->clk = clk_get(&pdev->dev, "core_clk");
if (IS_ERR(msm_uport->clk)) {
ret = PTR_ERR(msm_uport->clk);
- goto unmap_memory;
+ goto deregister_bus_client;
}
msm_uport->pclk = clk_get(&pdev->dev, "iface_clk");
@@ -2919,7 +2919,7 @@
ret = clk_set_rate(msm_uport->clk, uport->uartclk);
if (ret) {
printk(KERN_WARNING "Error setting clock rate on UART\n");
- goto unmap_memory;
+ goto put_clk;
}
msm_uport->hsuart_wq = alloc_workqueue("k_hsuart",
@@ -2928,7 +2928,7 @@
pr_err("%s(): Unable to create workqueue hsuart_wq\n",
__func__);
ret = -ENOMEM;
- goto unmap_memory;
+ goto put_clk;
}
INIT_WORK(&msm_uport->clock_off_w, hsuart_clock_off_work);
@@ -2946,7 +2946,7 @@
ret = msm_hs_sps_init(msm_uport);
if (unlikely(ret)) {
pr_err("SPS Initialization failed ! err=%d", ret);
- goto workqueue_destroy;
+ goto destroy_mutex;
}
}
@@ -2989,7 +2989,6 @@
uport->line = pdata->userid;
ret = uart_add_one_port(&msm_hs_driver, uport);
if (!ret) {
-
msm_hs_bus_voting(msm_uport, BUS_RESET);
clk_disable_unprepare(msm_uport->clk);
if (msm_uport->pclk)
@@ -3003,8 +3002,21 @@
clk_disable_unprepare(msm_uport->clk);
if (msm_uport->pclk)
clk_disable_unprepare(msm_uport->pclk);
-workqueue_destroy:
+
+destroy_mutex:
+ mutex_destroy(&msm_uport->clk_mutex);
destroy_workqueue(msm_uport->hsuart_wq);
+
+put_clk:
+ if (msm_uport->pclk)
+ clk_put(msm_uport->pclk);
+
+ if (msm_uport->clk)
+ clk_put(msm_uport->clk);
+
+deregister_bus_client:
+ if (is_blsp_uart(msm_uport))
+ msm_bus_scale_unregister_client(msm_uport->bus_perf_client);
unmap_memory:
iounmap(uport->membase);
if (is_blsp_uart(msm_uport))
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index 6df0c96..116b5b0 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -53,13 +53,16 @@
#include "f_rmnet_sdio.c"
#include "f_rmnet_smd_sdio.c"
#include "f_rmnet.c"
+#ifdef CONFIG_SND_PCM
#include "f_audio_source.c"
+#endif
#include "f_mass_storage.c"
#include "u_serial.c"
#include "u_sdio.c"
#include "u_smd.c"
#include "u_bam.c"
#include "u_rmnet_ctrl_smd.c"
+#include "u_rmnet_ctrl_qti.c"
#include "u_ctrl_hsic.c"
#include "u_data_hsic.c"
#include "u_ctrl_hsuart.c"
@@ -1590,6 +1593,7 @@
.ctrlrequest = accessory_function_ctrlrequest,
};
+#ifdef CONFIG_SND_PCM
static int audio_source_function_init(struct android_usb_function *f,
struct usb_composite_dev *cdev)
{
@@ -1651,6 +1655,7 @@
.unbind_config = audio_source_function_unbind_config,
.attributes = audio_source_function_attributes,
};
+#endif
static int android_uasp_connect_cb(bool connect)
{
@@ -1721,7 +1726,9 @@
&ecm_function,
&mass_storage_function,
&accessory_function,
+#ifdef CONFIG_SND_PCM
&audio_source_function,
+#endif
&uasp_function,
NULL
};
diff --git a/drivers/usb/gadget/f_mbim.c b/drivers/usb/gadget/f_mbim.c
index 935a540..d69e850 100644
--- a/drivers/usb/gadget/f_mbim.c
+++ b/drivers/usb/gadget/f_mbim.c
@@ -224,6 +224,16 @@
.bmNetworkCapabilities = 0x20,
};
+static struct usb_cdc_ext_mbb_desc ext_mbb_desc = {
+ .bLength = sizeof ext_mbb_desc,
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubType = USB_CDC_EXT_MBB_TYPE,
+
+ .bcdMbbExtendedVersion = cpu_to_le16(0x0100),
+ .bMaxOutstandingCmdMsges = 64,
+ .wMTU = 1500,
+};
+
/* the default data interface has no endpoints ... */
static struct usb_interface_descriptor mbim_data_nop_intf = {
.bLength = sizeof mbim_data_nop_intf,
@@ -286,6 +296,7 @@
(struct usb_descriptor_header *) &mbim_control_intf,
(struct usb_descriptor_header *) &mbim_header_desc,
(struct usb_descriptor_header *) &mbb_desc,
+ (struct usb_descriptor_header *) &ext_mbb_desc,
(struct usb_descriptor_header *) &fs_mbim_notify_desc,
/* data interface, altsettings 0 and 1 */
(struct usb_descriptor_header *) &mbim_data_nop_intf,
@@ -330,6 +341,7 @@
(struct usb_descriptor_header *) &mbim_control_intf,
(struct usb_descriptor_header *) &mbim_header_desc,
(struct usb_descriptor_header *) &mbb_desc,
+ (struct usb_descriptor_header *) &ext_mbb_desc,
(struct usb_descriptor_header *) &hs_mbim_notify_desc,
/* data interface, altsettings 0 and 1 */
(struct usb_descriptor_header *) &mbim_data_nop_intf,
diff --git a/drivers/usb/gadget/f_rmnet.c b/drivers/usb/gadget/f_rmnet.c
index e6613e8..0d8fa0f 100644
--- a/drivers/usb/gadget/f_rmnet.c
+++ b/drivers/usb/gadget/f_rmnet.c
@@ -55,6 +55,7 @@
#define NR_RMNET_PORTS 3
static unsigned int nr_rmnet_ports;
static unsigned int no_ctrl_smd_ports;
+static unsigned int no_ctrl_qti_ports;
static unsigned int no_ctrl_hsic_ports;
static unsigned int no_ctrl_hsuart_ports;
static unsigned int no_data_bam_ports;
@@ -402,6 +403,14 @@
return ret;
}
break;
+ case USB_GADGET_XPORT_QTI:
+ ret = gqti_ctrl_connect(&dev->port);
+ if (ret) {
+ pr_err("%s: gqti_ctrl_connect failed: err:%d\n",
+ __func__, ret);
+ return ret;
+ }
+ break;
case USB_GADGET_XPORT_HSIC:
ret = ghsic_ctrl_connect(&dev->port, port_num);
if (ret) {
@@ -436,7 +445,10 @@
if (ret) {
pr_err("%s: gbam_connect failed: err:%d\n",
__func__, ret);
- gsmd_ctrl_disconnect(&dev->port, port_num);
+ if (cxport == USB_GADGET_XPORT_QTI)
+ gqti_ctrl_disconnect(&dev->port);
+ else
+ gsmd_ctrl_disconnect(&dev->port, port_num);
return ret;
}
break;
@@ -484,6 +496,9 @@
case USB_GADGET_XPORT_SMD:
gsmd_ctrl_disconnect(&dev->port, port_num);
break;
+ case USB_GADGET_XPORT_QTI:
+ gqti_ctrl_disconnect(&dev->port);
+ break;
case USB_GADGET_XPORT_HSIC:
ghsic_ctrl_disconnect(&dev->port, port_num);
break;
@@ -1170,6 +1185,7 @@
nr_rmnet_ports = 0;
no_ctrl_smd_ports = 0;
+ no_ctrl_qti_ports = 0;
no_data_bam_ports = 0;
no_data_bam2bam_ports = 0;
no_ctrl_hsic_ports = 0;
@@ -1215,6 +1231,10 @@
rmnet_port->ctrl_xport_num = no_ctrl_smd_ports;
no_ctrl_smd_ports++;
break;
+ case USB_GADGET_XPORT_QTI:
+ rmnet_port->ctrl_xport_num = no_ctrl_qti_ports;
+ no_ctrl_qti_ports++;
+ break;
case USB_GADGET_XPORT_HSIC:
rmnet_port->ctrl_xport_num = no_ctrl_hsic_ports;
no_ctrl_hsic_ports++;
@@ -1268,6 +1288,7 @@
nr_rmnet_ports = 0;
no_ctrl_smd_ports = 0;
+ no_ctrl_qti_ports = 0;
no_data_bam_ports = 0;
no_ctrl_hsic_ports = 0;
no_data_hsic_ports = 0;
diff --git a/drivers/usb/gadget/u_bam.c b/drivers/usb/gadget/u_bam.c
index fe39700..a2997e9 100644
--- a/drivers/usb/gadget/u_bam.c
+++ b/drivers/usb/gadget/u_bam.c
@@ -582,6 +582,11 @@
spin_unlock_irqrestore(&port->port_lock_ul, flags);
spin_lock_irqsave(&port->port_lock_dl, flags);
+ if (!port->port_usb) {
+ gbam_free_requests(ep, &d->rx_idle);
+ spin_unlock_irqrestore(&port->port_lock_dl, flags);
+ return;
+ }
ep = port->port_usb->in;
ret = gbam_alloc_requests(ep, &d->tx_idle, bam_mux_tx_q_size,
gbam_epin_complete, GFP_ATOMIC);
diff --git a/drivers/usb/gadget/u_rmnet.h b/drivers/usb/gadget/u_rmnet.h
index 81ba223..cea9369 100644
--- a/drivers/usb/gadget/u_rmnet.h
+++ b/drivers/usb/gadget/u_rmnet.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -55,5 +55,7 @@
int gsmd_ctrl_connect(struct grmnet *gr, int port_num);
void gsmd_ctrl_disconnect(struct grmnet *gr, u8 port_num);
int gsmd_ctrl_setup(unsigned int count);
+int gqti_ctrl_connect(struct grmnet *gr);
+void gqti_ctrl_disconnect(struct grmnet *gr);
#endif /* __U_RMNET_H*/
diff --git a/drivers/usb/gadget/u_rmnet_ctrl_qti.c b/drivers/usb/gadget/u_rmnet_ctrl_qti.c
new file mode 100644
index 0000000..e92978f
--- /dev/null
+++ b/drivers/usb/gadget/u_rmnet_ctrl_qti.c
@@ -0,0 +1,519 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/wait.h>
+#include <linux/poll.h>
+#include <linux/usb/rmnet_ctrl_qti.h>
+
+#include "u_rmnet.h"
+
+struct rmnet_ctrl_qti_port {
+ struct grmnet *port_usb;
+
+ bool is_open;
+
+ atomic_t connected;
+ atomic_t line_state;
+
+ atomic_t open_excl;
+ atomic_t read_excl;
+ atomic_t write_excl;
+ atomic_t ioctl_excl;
+
+ wait_queue_head_t read_wq;
+
+ struct list_head cpkt_req_q;
+
+ spinlock_t lock;
+};
+static struct rmnet_ctrl_qti_port *ctrl_port;
+
+static inline int rmnet_ctrl_lock(atomic_t *excl)
+{
+ if (atomic_inc_return(excl) == 1) {
+ return 0;
+ } else {
+ atomic_dec(excl);
+ return -EBUSY;
+ }
+}
+
+static inline void rmnet_ctrl_unlock(atomic_t *excl)
+{
+ atomic_dec(excl);
+}
+
+static void rmnet_ctrl_queue_notify(struct rmnet_ctrl_qti_port *port)
+{
+ unsigned long flags;
+ struct rmnet_ctrl_pkt *cpkt = NULL;
+
+ pr_debug("%s: Queue empty packet for QTI", __func__);
+
+ spin_lock_irqsave(&port->lock, flags);
+ if (!port->is_open) {
+ pr_err("%s: rmnet ctrl file handler %p is not open",
+ __func__, port);
+ spin_unlock_irqrestore(&port->lock, flags);
+ return;
+ }
+
+ cpkt = alloc_rmnet_ctrl_pkt(0, GFP_ATOMIC);
+ if (!cpkt) {
+ pr_err("%s: Unable to allocate reset function pkt\n", __func__);
+ spin_unlock_irqrestore(&port->lock, flags);
+ return;
+ }
+
+ list_add_tail(&cpkt->list, &port->cpkt_req_q);
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ pr_debug("%s: Wake up read queue", __func__);
+ wake_up(&port->read_wq);
+}
+
+static int grmnet_ctrl_qti_send_cpkt_tomodem(u8 portno,
+ void *buf, size_t len)
+{
+ unsigned long flags;
+ struct rmnet_ctrl_qti_port *port = ctrl_port;
+ struct rmnet_ctrl_pkt *cpkt;
+
+ if (len > MAX_QTI_PKT_SIZE) {
+ pr_err("given pkt size too big:%d > max_pkt_size:%d\n",
+ len, MAX_QTI_PKT_SIZE);
+ return -EINVAL;
+ }
+
+ cpkt = alloc_rmnet_ctrl_pkt(len, GFP_ATOMIC);
+ if (IS_ERR(cpkt)) {
+ pr_err("%s: Unable to allocate ctrl pkt\n", __func__);
+ return -ENOMEM;
+ }
+
+ memcpy(cpkt->buf, buf, len);
+ cpkt->len = len;
+
+ pr_debug("%s: Add to cpkt_req_q packet with len = %d\n", __func__, len);
+ spin_lock_irqsave(&port->lock, flags);
+
+ /* drop cpkt if port is not open */
+ if (!port->is_open) {
+ pr_err("rmnet file handler %p is not open", port);
+ spin_unlock_irqrestore(&port->lock, flags);
+ free_rmnet_ctrl_pkt(cpkt);
+ return 0;
+ }
+
+ list_add_tail(&cpkt->list, &port->cpkt_req_q);
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ /* wakeup read thread */
+ pr_debug("%s: Wake up read queue", __func__);
+ wake_up(&port->read_wq);
+
+ return 0;
+}
+
+static void
+gqti_ctrl_notify_modem(void *gptr, u8 portno, int val)
+{
+ struct rmnet_ctrl_qti_port *port = ctrl_port;
+
+ atomic_set(&port->line_state, val);
+
+ /* send 0 len pkt to qti to notify state change */
+ rmnet_ctrl_queue_notify(port);
+}
+
+int gqti_ctrl_connect(struct grmnet *gr)
+{
+ struct rmnet_ctrl_qti_port *port;
+ unsigned long flags;
+
+ pr_debug("%s: grmnet:%p\n", __func__, gr);
+
+ if (!gr) {
+ pr_err("%s: grmnet port is null\n", __func__);
+ return -ENODEV;
+ }
+
+ port = ctrl_port;
+
+ spin_lock_irqsave(&port->lock, flags);
+ port->port_usb = gr;
+ gr->send_encap_cmd = grmnet_ctrl_qti_send_cpkt_tomodem;
+ gr->notify_modem = gqti_ctrl_notify_modem;
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ atomic_set(&port->connected, 1);
+ wake_up(&port->read_wq);
+
+ if (port && port->port_usb && port->port_usb->connect)
+ port->port_usb->connect(port->port_usb);
+
+ return 0;
+}
+
+void gqti_ctrl_disconnect(struct grmnet *gr)
+{
+ struct rmnet_ctrl_qti_port *port = ctrl_port;
+ unsigned long flags;
+ struct rmnet_ctrl_pkt *cpkt;
+
+ pr_debug("%s: grmnet:%p\n", __func__, gr);
+
+ if (!gr) {
+ pr_err("%s: grmnet port is null\n", __func__);
+ return;
+ }
+
+ if (port && port->port_usb && port->port_usb->disconnect)
+ port->port_usb->disconnect(port->port_usb);
+
+ atomic_set(&port->connected, 0);
+ atomic_set(&port->line_state, 0);
+ spin_lock_irqsave(&port->lock, flags);
+ port->port_usb = 0;
+ gr->send_encap_cmd = 0;
+ gr->notify_modem = 0;
+
+ while (!list_empty(&port->cpkt_req_q)) {
+ cpkt = list_first_entry(&port->cpkt_req_q,
+ struct rmnet_ctrl_pkt, list);
+
+ list_del(&cpkt->list);
+ free_rmnet_ctrl_pkt(cpkt);
+ }
+
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ /* send 0 len pkt to qti to notify state change */
+ rmnet_ctrl_queue_notify(port);
+}
+
+static int rmnet_ctrl_open(struct inode *ip, struct file *fp)
+{
+ unsigned long flags;
+
+ pr_debug("Open rmnet_ctrl_qti device file\n");
+
+ if (rmnet_ctrl_lock(&ctrl_port->open_excl)) {
+ pr_debug("Already opened\n");
+ return -EBUSY;
+ }
+
+ fp->private_data = ctrl_port;
+
+ spin_lock_irqsave(&ctrl_port->lock, flags);
+ ctrl_port->is_open = true;
+ spin_unlock_irqrestore(&ctrl_port->lock, flags);
+
+ return 0;
+}
+
+static int rmnet_ctrl_release(struct inode *ip, struct file *fp)
+{
+ unsigned long flags;
+ struct rmnet_ctrl_qti_port *port = fp->private_data;
+
+ pr_debug("Close rmnet control file");
+
+ spin_lock_irqsave(&port->lock, flags);
+ port->is_open = false;
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ rmnet_ctrl_unlock(&port->open_excl);
+
+ return 0;
+}
+
+static ssize_t
+rmnet_ctrl_read(struct file *fp, char __user *buf, size_t count, loff_t *pos)
+{
+ struct rmnet_ctrl_qti_port *port = fp->private_data;
+ struct rmnet_ctrl_pkt *cpkt = NULL;
+ unsigned long flags;
+ int ret = 0;
+
+ pr_debug("%s: Enter(%d)\n", __func__, count);
+
+ if (count > MAX_QTI_PKT_SIZE) {
+ pr_err("Buffer size is too big %d, should be at most %d\n",
+ count, MAX_QTI_PKT_SIZE);
+ return -EINVAL;
+ }
+
+ if (rmnet_ctrl_lock(&port->read_excl)) {
+ pr_err("Previous reading is not finished yet\n");
+ return -EBUSY;
+ }
+
+ /* block until online */
+ while (!(atomic_read(&port->connected))) {
+ pr_debug("Not connected. Wait.\n");
+ ret = wait_event_interruptible(port->read_wq,
+ atomic_read(&port->connected));
+ if (ret < 0) {
+ rmnet_ctrl_unlock(&port->read_excl);
+ if (ret == -ERESTARTSYS)
+ return -ERESTARTSYS;
+ else
+ return -EINTR;
+ }
+ }
+
+ /* block until a new packet is available */
+ do {
+ spin_lock_irqsave(&port->lock, flags);
+ if (!list_empty(&port->cpkt_req_q))
+ break;
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ pr_debug("%s: Requests list is empty. Wait.\n", __func__);
+ ret = wait_event_interruptible(port->read_wq,
+ !list_empty(&port->cpkt_req_q));
+ if (ret < 0) {
+ pr_debug("Waiting failed\n");
+ rmnet_ctrl_unlock(&port->read_excl);
+ return -ERESTARTSYS;
+ }
+ } while (1);
+
+ cpkt = list_first_entry(&port->cpkt_req_q, struct rmnet_ctrl_pkt,
+ list);
+ list_del(&cpkt->list);
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ if (cpkt->len > count) {
+ pr_err("cpkt size too big:%d > buf size:%d\n",
+ cpkt->len, count);
+ rmnet_ctrl_unlock(&port->read_excl);
+ free_rmnet_ctrl_pkt(cpkt);
+ return -ENOMEM;
+ }
+
+ pr_debug("%s: cpkt size:%d\n", __func__, cpkt->len);
+
+
+ rmnet_ctrl_unlock(&port->read_excl);
+
+ ret = copy_to_user(buf, cpkt->buf, cpkt->len);
+ if (ret) {
+ pr_err("copy_to_user failed: err %d\n", ret);
+ ret = -EFAULT;
+ } else {
+ pr_debug("%s: copied %d bytes to user\n", __func__, cpkt->len);
+ ret = cpkt->len;
+ }
+
+ free_rmnet_ctrl_pkt(cpkt);
+
+ return ret;
+}
+
+static ssize_t
+rmnet_ctrl_write(struct file *fp, const char __user *buf, size_t count,
+ loff_t *pos)
+{
+ struct rmnet_ctrl_qti_port *port = fp->private_data;
+ void *kbuf;
+ unsigned long flags;
+ int ret = 0;
+
+ pr_debug("%s: Enter(%d)", __func__, count);
+
+ if (!count) {
+ pr_debug("zero length ctrl pkt\n");
+ return -EINVAL;
+ }
+
+ if (count > MAX_QTI_PKT_SIZE) {
+ pr_debug("given pkt size too big:%d > max_pkt_size:%d\n",
+ count, MAX_QTI_PKT_SIZE);
+ return -EINVAL;
+ }
+
+ if (rmnet_ctrl_lock(&port->write_excl)) {
+ pr_err("Previous writing not finished yet\n");
+ return -EBUSY;
+ }
+
+ if (!atomic_read(&port->connected)) {
+ pr_debug("USB cable not connected\n");
+ rmnet_ctrl_unlock(&port->write_excl);
+ return -EPIPE;
+ }
+
+ kbuf = kmalloc(count, GFP_KERNEL);
+ if (!kbuf) {
+ pr_err("failed to allocate ctrl pkt\n");
+ rmnet_ctrl_unlock(&port->write_excl);
+ return -ENOMEM;
+ }
+ ret = copy_from_user(kbuf, buf, count);
+ if (ret) {
+ pr_err("copy_from_user failed err:%d\n", ret);
+ kfree(kbuf);
+ rmnet_ctrl_unlock(&port->write_excl);
+ return -EFAULT;
+ }
+
+ spin_lock_irqsave(&port->lock, flags);
+ if (port->port_usb && port->port_usb->send_cpkt_response) {
+ ret = port->port_usb->send_cpkt_response(port->port_usb,
+ kbuf, count);
+ if (ret) {
+ pr_err("failed to send ctrl packet. error=%d\n", ret);
+ spin_unlock_irqrestore(&port->lock, flags);
+ kfree(kbuf);
+ rmnet_ctrl_unlock(&port->write_excl);
+ return ret;
+ }
+ } else {
+ pr_err("send_cpkt_response callback is NULL\n");
+ spin_unlock_irqrestore(&port->lock, flags);
+ kfree(kbuf);
+ rmnet_ctrl_unlock(&port->write_excl);
+ return -EINVAL;
+ }
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ kfree(kbuf);
+ rmnet_ctrl_unlock(&port->write_excl);
+
+ pr_debug("%s: Exit(%d)", __func__, count);
+
+ return count;
+
+}
+
+static long rmnet_ctrl_ioctl(struct file *fp, unsigned cmd, unsigned long arg)
+{
+ struct rmnet_ctrl_qti_port *port = fp->private_data;
+ int val, ret = 0;
+
+ pr_debug("%s: Received command %d", __func__, cmd);
+
+ if (rmnet_ctrl_lock(&port->ioctl_excl))
+ return -EBUSY;
+
+ switch (cmd) {
+ case FRMNET_CTRL_GET_LINE_STATE:
+ val = atomic_read(&port->line_state);
+ ret = copy_to_user((void __user *)arg, &val, sizeof(val));
+ if (ret) {
+ pr_err("copying to user space failed");
+ ret = -EFAULT;
+ }
+ pr_debug("%s: Sent line_state: %d", __func__,
+ atomic_read(&port->line_state));
+ break;
+ default:
+ pr_err("wrong parameter");
+ ret = -EINVAL;
+ }
+
+ rmnet_ctrl_unlock(&port->ioctl_excl);
+
+ return ret;
+}
+
+static unsigned int rmnet_ctrl_poll(struct file *file, poll_table *wait)
+{
+ struct rmnet_ctrl_qti_port *port = file->private_data;
+ unsigned long flags;
+ unsigned int mask = 0;
+
+ if (!port) {
+ pr_err("%s on a NULL device\n", __func__);
+ return POLLERR;
+ }
+
+ poll_wait(file, &port->read_wq, wait);
+
+ spin_lock_irqsave(&port->lock, flags);
+ if (!list_empty(&port->cpkt_req_q)) {
+ mask |= POLLIN | POLLRDNORM;
+ pr_debug("%s sets POLLIN for rmnet_ctrl_qti_port\n", __func__);
+ }
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ return mask;
+}
+
+/* file operations for rmnet device /dev/rmnet_ctrl */
+static const struct file_operations rmnet_ctrl_fops = {
+ .owner = THIS_MODULE,
+ .open = rmnet_ctrl_open,
+ .release = rmnet_ctrl_release,
+ .read = rmnet_ctrl_read,
+ .write = rmnet_ctrl_write,
+ .unlocked_ioctl = rmnet_ctrl_ioctl,
+ .poll = rmnet_ctrl_poll,
+};
+
+static struct miscdevice rmnet_device = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "rmnet_ctrl",
+ .fops = &rmnet_ctrl_fops,
+};
+
+static int __init gqti_ctrl_init(void)
+{
+ int ret;
+ struct rmnet_ctrl_qti_port *port = NULL;
+
+ port = kzalloc(sizeof(struct rmnet_ctrl_qti_port), GFP_KERNEL);
+ if (!port) {
+ pr_err("Failed to allocate rmnet control device\n");
+ return -ENOMEM;
+ }
+
+ INIT_LIST_HEAD(&port->cpkt_req_q);
+ spin_lock_init(&port->lock);
+
+ atomic_set(&port->open_excl, 0);
+ atomic_set(&port->read_excl, 0);
+ atomic_set(&port->write_excl, 0);
+ atomic_set(&port->ioctl_excl, 0);
+ atomic_set(&port->connected, 0);
+ atomic_set(&port->line_state, 0);
+
+ init_waitqueue_head(&port->read_wq);
+
+ ctrl_port = port;
+
+ ret = misc_register(&rmnet_device);
+ if (ret) {
+ pr_err("rmnet control driver failed to register");
+ goto fail_init;
+ }
+
+ return ret;
+
+fail_init:
+ kfree(port);
+ ctrl_port = NULL;
+ return ret;
+}
+module_init(gqti_ctrl_init);
+
+static void __exit gqti_ctrl_cleanup(void)
+{
+ misc_deregister(&rmnet_device);
+
+ kfree(ctrl_port);
+ ctrl_port = NULL;
+}
+module_exit(gqti_ctrl_cleanup);
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index 24f3cb1..a09b1ab 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -842,7 +842,7 @@
u32 __iomem *status_reg = &ehci->regs->port_status[
(wIndex & 0xff) - 1];
u32 __iomem *hostpc_reg = NULL;
- u32 temp, temp1, status, cmd = 0;
+ u32 temp, temp1, status;
unsigned long flags;
int retval = 0;
unsigned selector;
@@ -1221,31 +1221,13 @@
ehci->reset_done [wIndex] = jiffies
+ msecs_to_jiffies (50);
}
-
- if (ehci->reset_sof_bug && (temp & PORT_RESET)) {
- cmd = ehci_readl(ehci, &ehci->regs->command);
- cmd &= ~CMD_RUN;
- ehci_writel(ehci, cmd, &ehci->regs->command);
- if (handshake(ehci, &ehci->regs->status,
- STS_HALT, STS_HALT, 16 * 125))
- ehci_info(ehci,
- "controller halt failed\n");
- }
- ehci_writel(ehci, temp, status_reg);
- if (ehci->reset_sof_bug && (temp & PORT_RESET)
- && hcd->driver->enable_ulpi_control) {
- hcd->driver->enable_ulpi_control(hcd,
- PORT_RESET);
+ if (ehci->reset_sof_bug && (temp & PORT_RESET) &&
+ hcd->driver->reset_sof_bug_handler) {
spin_unlock_irqrestore(&ehci->lock, flags);
- usleep_range(50000, 55000);
- if (handshake(ehci, status_reg,
- PORT_RESET, 0, 10 * 1000))
- ehci_info(ehci,
- "failed to clear reset\n");
+ hcd->driver->reset_sof_bug_handler(hcd, temp);
spin_lock_irqsave(&ehci->lock, flags);
- hcd->driver->disable_ulpi_control(hcd);
- cmd |= CMD_RUN;
- ehci_writel(ehci, cmd, &ehci->regs->command);
+ } else {
+ ehci_writel(ehci, temp, status_reg);
}
break;
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index 3ec158b..8e32aa9 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -101,6 +101,8 @@
struct completion rt_completion;
int resume_status;
int resume_again;
+ int bus_reset;
+ int reset_again;
struct pm_qos_request pm_qos_req_dma;
};
@@ -430,7 +432,7 @@
}
-static int ulpi_read(struct msm_hsic_hcd *mehci, u32 reg)
+static int __maybe_unused ulpi_read(struct msm_hsic_hcd *mehci, u32 reg)
{
struct usb_hcd *hcd = hsic_to_hcd(mehci);
int cnt = 0;
@@ -501,37 +503,6 @@
return 0;
}
-#define HSIC_DBG1 0X38
-#define ULPI_MANUAL_ENABLE BIT(4)
-#define ULPI_LINESTATE_DATA BIT(5)
-#define ULPI_LINESTATE_STROBE BIT(6)
-static void ehci_msm_enable_ulpi_control(struct usb_hcd *hcd, u32 linestate)
-{
- struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
- int val;
-
- switch (linestate) {
- case PORT_RESET:
- val = ulpi_read(mehci, HSIC_DBG1);
- val |= ULPI_MANUAL_ENABLE;
- val &= ~(ULPI_LINESTATE_DATA | ULPI_LINESTATE_STROBE);
- ulpi_write(mehci, val, HSIC_DBG1);
- break;
- default:
- pr_info("%s: Unknown linestate:%0x\n", __func__, linestate);
- }
-}
-
-static void ehci_msm_disable_ulpi_control(struct usb_hcd *hcd)
-{
- struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
- int val;
-
- val = ulpi_read(mehci, HSIC_DBG1);
- val &= ~ULPI_MANUAL_ENABLE;
- ulpi_write(mehci, val, HSIC_DBG1);
-}
-
static int msm_hsic_config_gpios(struct msm_hsic_hcd *mehci, int gpio_en)
{
int rc = 0;
@@ -834,7 +805,7 @@
wake_unlock(&mehci->wlock);
- dev_info(mehci->dev, "HSIC-USB in low power mode\n");
+ dev_dbg(mehci->dev, "HSIC-USB in low power mode\n");
return 0;
}
@@ -936,7 +907,7 @@
}
enable_irq(hcd->irq);
- dev_info(mehci->dev, "HSIC-USB exited from low power mode\n");
+ dev_dbg(mehci->dev, "HSIC-USB exited from low power mode\n");
return 0;
}
@@ -955,6 +926,26 @@
__func__, ret);
}
+static int msm_hsic_reset_done(struct usb_hcd *hcd)
+{
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+ u32 __iomem *status_reg = &ehci->regs->port_status[0];
+ int ret;
+
+ ehci_writel(ehci, ehci_readl(ehci, status_reg) & ~(PORT_RWC_BITS |
+ PORT_RESET), status_reg);
+
+ ret = handshake(ehci, status_reg, PORT_RESET, 0, 1 * 1000);
+
+ if (ret)
+ pr_err("reset handshake failed in %s\n", __func__);
+ else
+ ehci_writel(ehci, ehci_readl(ehci, &ehci->regs->command) |
+ CMD_RUN, &ehci->regs->command);
+
+ return ret;
+}
+
#define STS_GPTIMER0_INTERRUPT BIT(24)
static irqreturn_t msm_hsic_irq(struct usb_hcd *hcd)
{
@@ -982,16 +973,28 @@
if (status & STS_GPTIMER0_INTERRUPT) {
int timeleft;
- dbg_log_event(NULL, "FPR: gpt0_isr", 0);
+ dbg_log_event(NULL, "FPR: gpt0_isr", mehci->bus_reset);
timeleft = GPT_CNT(ehci_readl(ehci,
&mehci->timer->gptimer1_ctrl));
if (timeleft) {
- ehci_writel(ehci, ehci_readl(ehci,
- &ehci->regs->command) | CMD_RUN,
- &ehci->regs->command);
- } else
- mehci->resume_again = 1;
+ if (mehci->bus_reset) {
+ ret = msm_hsic_reset_done(hcd);
+ if (ret) {
+ mehci->reset_again = 1;
+ dbg_log_event(NULL, "RESET: fail", 0);
+ }
+ } else {
+ ehci_writel(ehci, ehci_readl(ehci,
+ &ehci->regs->command) | CMD_RUN,
+ &ehci->regs->command);
+ }
+ } else {
+ if (mehci->bus_reset)
+ mehci->reset_again = 1;
+ else
+ mehci->resume_again = 1;
+ }
dbg_log_event(NULL, "FPR: timeleft", timeleft);
@@ -1047,6 +1050,83 @@
#ifdef CONFIG_PM
+#define RESET_RETRY_LIMIT 3
+#define RESET_SIGNAL_TIME_SOF_USEC (50 * 1000)
+#define RESET_SIGNAL_TIME_USEC (20 * 1000)
+static void ehci_hsic_reset_sof_bug_handler(struct usb_hcd *hcd, u32 val)
+{
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+ struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
+ struct msm_hsic_host_platform_data *pdata = mehci->dev->platform_data;
+ u32 __iomem *status_reg = &ehci->regs->port_status[0];
+ unsigned long flags;
+ int retries = 0, ret, cnt = RESET_SIGNAL_TIME_USEC;
+
+ if (pdata && pdata->swfi_latency)
+ pm_qos_update_request(&mehci->pm_qos_req_dma,
+ pdata->swfi_latency + 1);
+
+ mehci->bus_reset = 1;
+retry:
+ retries++;
+ dbg_log_event(NULL, "RESET: start", retries);
+ pr_debug("reset begin %d\n", retries);
+ mehci->reset_again = 0;
+ spin_lock_irqsave(&ehci->lock, flags);
+ ehci_writel(ehci, val, status_reg);
+ ehci_writel(ehci, GPT_LD(RESET_SIGNAL_TIME_USEC - 1),
+ &mehci->timer->gptimer0_ld);
+ ehci_writel(ehci, GPT_RESET | GPT_RUN,
+ &mehci->timer->gptimer0_ctrl);
+ ehci_writel(ehci, INTR_MASK | STS_GPTIMER0_INTERRUPT,
+ &ehci->regs->intr_enable);
+
+ ehci_writel(ehci, GPT_LD(RESET_SIGNAL_TIME_SOF_USEC - 1),
+ &mehci->timer->gptimer1_ld);
+ ehci_writel(ehci, GPT_RESET | GPT_RUN,
+ &mehci->timer->gptimer1_ctrl);
+
+ spin_unlock_irqrestore(&ehci->lock, flags);
+ wait_for_completion(&mehci->gpt0_completion);
+
+ if (!mehci->reset_again)
+ goto done;
+
+ if (handshake(ehci, status_reg, PORT_RESET, 0, 10 * 1000)) {
+ pr_err("reset handshake fatal error\n");
+ dbg_log_event(NULL, "RESET: fatal", retries);
+ goto fail;
+ }
+
+ if (retries < RESET_RETRY_LIMIT)
+ goto retry;
+
+ /* complete reset in tight loop */
+ pr_info("RESET in tight loop\n");
+ dbg_log_event(NULL, "RESET: tight", 0);
+
+ spin_lock_irqsave(&ehci->lock, flags);
+ ehci_writel(ehci, val, status_reg);
+ while (cnt--)
+ udelay(1);
+ ret = msm_hsic_reset_done(hcd);
+ spin_unlock_irqrestore(&ehci->lock, flags);
+ if (ret) {
+ pr_err("RESET in tight loop failed\n");
+ dbg_log_event(NULL, "RESET: tight failed", 0);
+ goto fail;
+ }
+
+done:
+ dbg_log_event(NULL, "RESET: done", retries);
+ pr_debug("reset completed\n");
+fail:
+ mehci->bus_reset = 0;
+ if (pdata && pdata->swfi_latency)
+ pm_qos_update_request(&mehci->pm_qos_req_dma,
+ PM_QOS_DEFAULT_VALUE);
+}
+
static int ehci_hsic_bus_suspend(struct usb_hcd *hcd)
{
struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
@@ -1321,10 +1401,8 @@
.log_urb = dbg_log_event,
.dump_regs = dump_hsic_regs,
- .enable_ulpi_control = ehci_msm_enable_ulpi_control,
- .disable_ulpi_control = ehci_msm_disable_ulpi_control,
-
.set_autosuspend_delay = ehci_msm_set_autosuspend_delay,
+ .reset_sof_bug_handler = ehci_hsic_reset_sof_bug_handler,
};
static int msm_hsic_init_clocks(struct msm_hsic_hcd *mehci, u32 init)
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index 4d5bbf84..c69071d 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -1008,9 +1008,11 @@
}
if (device_may_wakeup(phy->dev)) {
- enable_irq_wake(motg->irq);
if (motg->async_irq)
enable_irq_wake(motg->async_irq);
+ else
+ enable_irq_wake(motg->irq);
+
if (motg->pdata->pmic_id_irq)
enable_irq_wake(motg->pdata->pmic_id_irq);
if (pdata->otg_control == OTG_PHY_CONTROL &&
@@ -1117,9 +1119,11 @@
skip_phy_resume:
if (device_may_wakeup(phy->dev)) {
- disable_irq_wake(motg->irq);
if (motg->async_irq)
disable_irq_wake(motg->async_irq);
+ else
+ disable_irq_wake(motg->irq);
+
if (motg->pdata->pmic_id_irq)
disable_irq_wake(motg->pdata->pmic_id_irq);
if (pdata->otg_control == OTG_PHY_CONTROL &&
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index 0922f44..fbae011 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -780,6 +780,7 @@
case MDP_ARGB_8888:
case MDP_RGBA_8888:
case MDP_BGRA_8888:
+ case MDP_BGRX_8888:
case MDP_RGBX_8888:
case MDP_RGB_565:
case MDP_BGR_565:
@@ -967,6 +968,7 @@
case MDP_ARGB_8888:
case MDP_RGBA_8888:
case MDP_BGRA_8888:
+ case MDP_BGRX_8888:
case MDP_RGBX_8888:
return OVERLAY_TYPE_RGB;
case MDP_YCRYCB_H2V1:
@@ -1137,6 +1139,23 @@
pipe->element0 = C1_B_Cb; /* B */
pipe->bpp = 4; /* 4 bpp */
break;
+ case MDP_BGRX_8888:
+ pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR;
+ pipe->fetch_plane = OVERLAY_PLANE_INTERLEAVED;
+ pipe->a_bit = 3; /* alpha, 4 bits */
+ pipe->r_bit = 3; /* R, 8 bits */
+ pipe->b_bit = 3; /* B, 8 bits */
+ pipe->g_bit = 3; /* G, 8 bits */
+ pipe->alpha_enable = 0;
+ pipe->unpack_tight = 1;
+ pipe->unpack_align_msb = 0;
+ pipe->unpack_count = 3;
+ pipe->element3 = C3_ALPHA; /* alpha */
+ pipe->element2 = C2_R_Cr; /* R */
+ pipe->element1 = C0_G_Y; /* G */
+ pipe->element0 = C1_B_Cb; /* B */
+ pipe->bpp = 4; /* 4 bpp */
+ break;
case MDP_YCRYCB_H2V1:
pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR;
pipe->fetch_plane = OVERLAY_PLANE_INTERLEAVED;
@@ -1324,6 +1343,7 @@
case MDP_XRGB_8888:
case MDP_ARGB_8888:
case MDP_BGRA_8888:
+ case MDP_BGRX_8888:
b_start = 0;
g_start = 8;
r_start = 16;
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index e1e82fd..b6733d1 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -417,9 +417,6 @@
mfd->op_enable);
if (ret)
pr_warn("can't turn on display!\n");
-
- if (mfd->vsync_pending)
- mdss_mdp_overlay_vsync_ctrl(mfd, mfd->vsync_pending);
}
mfd->is_power_setting = false;
complete_all(&mfd->power_set_comp);
@@ -735,11 +732,9 @@
return -ENOMEM;
}
phys = memory_pool_node_paddr(virt);
- if (is_mdss_iommu_attached()) {
- dom = mdss_get_iommu_domain(MDSS_IOMMU_DOMAIN_UNSECURE);
- msm_iommu_map_contig_buffer(phys, dom, 0, size, SZ_4K,
- 0, &(mfd->iova));
- }
+ dom = mdss_get_iommu_domain(MDSS_IOMMU_DOMAIN_UNSECURE);
+ msm_iommu_map_contig_buffer(phys, dom, 0, size, SZ_4K,
+ 0, &(mfd->iova));
pr_info("allocating %u bytes at %p (%lx phys) for fb %d\n",
size, virt, phys, mfd->index);
} else {
@@ -1043,23 +1038,31 @@
void mdss_fb_wait_for_fence(struct msm_fb_data_type *mfd)
{
- int i, ret;
+ int i, ret = 0;
/* buf sync */
for (i = 0; i < mfd->acq_fen_cnt; i++) {
ret = sync_fence_wait(mfd->acq_fen[i], WAIT_FENCE_TIMEOUT);
- sync_fence_put(mfd->acq_fen[i]);
if (ret < 0) {
pr_err("%s: sync_fence_wait failed! ret = %x\n",
__func__, ret);
break;
}
+ sync_fence_put(mfd->acq_fen[i]);
+ }
+
+ if (ret < 0) {
+ while (i < mfd->acq_fen_cnt) {
+ sync_fence_put(mfd->acq_fen[i]);
+ i++;
+ }
}
mfd->acq_fen_cnt = 0;
}
static void mdss_fb_signal_timeline_locked(struct msm_fb_data_type *mfd)
{
- if (mfd->timeline) {
+ if (mfd->timeline && !list_empty((const struct list_head *)
+ (&(mfd->timeline->obj.active_list_head)))) {
sw_sync_timeline_inc(mfd->timeline, 1);
mfd->timeline_value++;
}
@@ -1445,32 +1448,32 @@
switch (mdp_pp.op) {
case mdp_op_pa_cfg:
- ret = mdss_mdp_pa_config(&mdp_pp.data.pa_cfg_data,
+ ret = mdss_mdp_pa_config(mfd->ctl, &mdp_pp.data.pa_cfg_data,
©back);
break;
case mdp_op_pcc_cfg:
- ret = mdss_mdp_pcc_config(&mdp_pp.data.pcc_cfg_data,
+ ret = mdss_mdp_pcc_config(mfd->ctl, &mdp_pp.data.pcc_cfg_data,
©back);
break;
case mdp_op_lut_cfg:
switch (mdp_pp.data.lut_cfg_data.lut_type) {
case mdp_lut_igc:
- ret = mdss_mdp_igc_lut_config(
+ ret = mdss_mdp_igc_lut_config(mfd->ctl,
(struct mdp_igc_lut_data *)
&mdp_pp.data.lut_cfg_data.data,
©back);
break;
case mdp_lut_pgc:
- ret = mdss_mdp_argc_config(
+ ret = mdss_mdp_argc_config(mfd->ctl,
&mdp_pp.data.lut_cfg_data.data.pgc_lut_data,
©back);
break;
case mdp_lut_hist:
- ret = mdss_mdp_hist_lut_config(
+ ret = mdss_mdp_hist_lut_config(mfd->ctl,
(struct mdp_hist_lut_data *)
&mdp_pp.data.lut_cfg_data.data, ©back);
break;
@@ -1481,12 +1484,12 @@
}
break;
case mdp_op_dither_cfg:
- ret = mdss_mdp_dither_config(&mdp_pp.data.dither_cfg_data,
- ©back);
+ ret = mdss_mdp_dither_config(mfd->ctl,
+ &mdp_pp.data.dither_cfg_data, ©back);
break;
case mdp_op_gamut_cfg:
- ret = mdss_mdp_gamut_config(&mdp_pp.data.gamut_cfg_data,
- ©back);
+ ret = mdss_mdp_gamut_config(mfd->ctl,
+ &mdp_pp.data.gamut_cfg_data, ©back);
break;
case mdp_bl_scale_cfg:
ret = mdss_bl_scale_config(mfd, (struct mdp_bl_scale_data *)
@@ -1672,7 +1675,7 @@
if (ret)
return ret;
- ret = mdss_mdp_hist_collect(info, &hist, &hist_data_addr);
+ ret = mdss_mdp_hist_collect(mfd->ctl, &hist, &hist_data_addr);
if ((ret == 0) && hist_data_addr) {
ret = copy_to_user(hist.c0, (u32 *)hist_data_addr,
sizeof(u32) * hist.bin_cnt);
@@ -1690,7 +1693,7 @@
if (ret)
return ret;
- ret = mdss_mdp_histogram_start(&hist_req);
+ ret = mdss_mdp_histogram_start(mfd->ctl, &hist_req);
break;
case MSMFB_HISTOGRAM_STOP:
@@ -1698,7 +1701,7 @@
if (ret)
return ret;
- ret = mdss_mdp_histogram_stop(block);
+ ret = mdss_mdp_histogram_stop(mfd->ctl, block);
break;
case MSMFB_GET_PAGE_PROTECTION:
diff --git a/drivers/video/msm/mdss/mdss_hdmi_edid.c b/drivers/video/msm/mdss/mdss_hdmi_edid.c
index 1aae22e..08be337 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_edid.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_edid.c
@@ -240,6 +240,8 @@
if (edid_ctrl->sink_data.num_of_elements) {
u32 *video_mode = edid_ctrl->sink_data.disp_mode_list;
for (i = 0; i < edid_ctrl->sink_data.num_of_elements; ++i) {
+ if (!hdmi_get_supported_mode(*video_mode))
+ continue;
if (ret > 0)
ret += snprintf(buf+ret, PAGE_SIZE-ret, ",%d",
*video_mode++ + 1);
diff --git a/drivers/video/msm/mdss/mdss_hdmi_mhl.h b/drivers/video/msm/mdss/mdss_hdmi_mhl.h
new file mode 100644
index 0000000..8fef63e
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_hdmi_mhl.h
@@ -0,0 +1,27 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __MDSS_HDMI_MHL_H__
+#define __MDSS_HDMI_MHL_H__
+
+#include <linux/platform_device.h>
+
+struct msm_hdmi_mhl_ops {
+ u8 (*tmds_enabled)(struct platform_device *pdev);
+ int (*set_mhl_max_pclk)(struct platform_device *pdev, u32 max_val);
+};
+
+int msm_hdmi_register_mhl(struct platform_device *pdev,
+ struct msm_hdmi_mhl_ops *ops);
+
+#endif /* __MDSS_HDMI_MHL_H__ */
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.c b/drivers/video/msm/mdss/mdss_hdmi_tx.c
index b6dec99..5404000 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.c
@@ -30,6 +30,7 @@
#include "mdss_hdmi_hdcp.h"
#include "mdss.h"
#include "mdss_panel.h"
+#include "mdss_hdmi_mhl.h"
#define DRV_NAME "hdmi-tx"
#define COMPATIBLE_NAME "qcom,hdmi-tx"
@@ -629,6 +630,30 @@
hdmi_set_supported_mode(HDMI_VFRMT_4096x2160p24_16_9);
} /* hdmi_tx_setup_video_mode_lut */
+/* Table tuned to indicate video formats supported by the MHL Tx */
+/* Valid pclk rates (Mhz): 25.2, 27, 27.03, 74.25 */
+static void hdmi_tx_setup_mhl_video_mode_lut(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+ u32 i;
+ struct hdmi_disp_mode_timing_type *temp_timing;
+
+ if (!hdmi_ctrl->mhl_max_pclk) {
+ DEV_WARN("%s: mhl max pclk not set!\n", __func__);
+ return;
+ }
+ DEV_DBG("%s: max mode set to [%u]\n",
+ __func__, hdmi_ctrl->mhl_max_pclk);
+ for (i = 0; i < HDMI_VFRMT_MAX; i++) {
+ temp_timing =
+ (struct hdmi_disp_mode_timing_type *)hdmi_get_supported_mode(i);
+ if (!temp_timing)
+ continue;
+ /* formats that exceed max mhl line clk bw */
+ if (temp_timing->pixel_freq > hdmi_ctrl->mhl_max_pclk)
+ hdmi_del_supported_mode(i);
+ }
+} /* hdmi_tx_setup_mhl_video_mode_lut */
+
static int hdmi_tx_read_sink_info(struct hdmi_tx_ctrl *hdmi_ctrl)
{
int status;
@@ -1758,12 +1783,65 @@
hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID], blk);
} /* hdmi_tx_get_audio_edid_blk */
+static u8 hdmi_tx_tmds_enabled(struct platform_device *pdev)
+{
+ struct hdmi_tx_ctrl *hdmi_ctrl = platform_get_drvdata(pdev);
+
+ if (!hdmi_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return -ENODEV;
+ }
+
+ /* status of tmds */
+ return (hdmi_ctrl->timing_gen_on == true);
+}
+
+static int hdmi_tx_set_mhl_max_pclk(struct platform_device *pdev, u32 max_val)
+{
+ struct hdmi_tx_ctrl *hdmi_ctrl = NULL;
+
+ hdmi_ctrl = platform_get_drvdata(pdev);
+
+ if (!hdmi_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return -ENODEV;
+ }
+ if (max_val) {
+ hdmi_ctrl->mhl_max_pclk = max_val;
+ hdmi_tx_setup_mhl_video_mode_lut(hdmi_ctrl);
+ } else {
+ DEV_ERR("%s: invalid max pclk val\n", __func__);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+int msm_hdmi_register_mhl(struct platform_device *pdev,
+ struct msm_hdmi_mhl_ops *ops)
+{
+ struct hdmi_tx_ctrl *hdmi_ctrl = platform_get_drvdata(pdev);
+
+ if (!hdmi_ctrl) {
+ DEV_ERR("%s: invalid pdev\n", __func__);
+ return -ENODEV;
+ }
+
+ if (!ops) {
+ DEV_ERR("%s: invalid ops\n", __func__);
+ return -EINVAL;
+ }
+
+ ops->tmds_enabled = hdmi_tx_tmds_enabled;
+ ops->set_mhl_max_pclk = hdmi_tx_set_mhl_max_pclk;
+ return 0;
+}
+
int msm_hdmi_register_audio_codec(struct platform_device *pdev,
struct msm_hdmi_audio_codec_ops *ops)
{
struct hdmi_tx_ctrl *hdmi_ctrl = platform_get_drvdata(pdev);
- if (!hdmi_ctrl) {
+ if (!hdmi_ctrl || !ops) {
DEV_ERR("%s: invalid input\n", __func__);
return -ENODEV;
}
@@ -2436,6 +2514,7 @@
DEV_ERR("%s: hdcp auth failed. rc=%d\n",
__func__, rc);
}
+ hdmi_ctrl->timing_gen_on = true;
break;
case MDSS_EVENT_SUSPEND:
@@ -2463,6 +2542,7 @@
break;
case MDSS_EVENT_TIMEGEN_OFF:
+ hdmi_ctrl->timing_gen_on = false;
break;
case MDSS_EVENT_CLOSE:
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.h b/drivers/video/msm/mdss/mdss_hdmi_tx.h
index ba5ee5b..06ae427 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.h
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.h
@@ -58,6 +58,8 @@
u32 hpd_off_pending;
u32 hpd_feature_on;
u32 hpd_initialized;
+ u8 timing_gen_on;
+ u32 mhl_max_pclk;
struct completion hpd_done;
struct work_struct hpd_int_work;
diff --git a/drivers/video/msm/mdss/mdss_hdmi_util.c b/drivers/video/msm/mdss/mdss_hdmi_util.c
index 13e2c9b..07c2336 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_util.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_util.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -34,6 +34,16 @@
}
} /* hdmi_init_supported_video_timings */
+void hdmi_del_supported_mode(u32 mode)
+{
+ struct hdmi_disp_mode_timing_type *ret = NULL;
+ DEV_DBG("%s: removing %s\n", __func__,
+ hdmi_get_video_fmt_2string(mode));
+ ret = &hdmi_supported_video_mode_lut[mode];
+ if (ret != NULL && ret->supported)
+ ret->supported = false;
+}
+
const struct hdmi_disp_mode_timing_type *hdmi_get_supported_mode(u32 mode)
{
const struct hdmi_disp_mode_timing_type *ret = NULL;
diff --git a/drivers/video/msm/mdss/mdss_hdmi_util.h b/drivers/video/msm/mdss/mdss_hdmi_util.h
index d621616..914aac1 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_util.h
+++ b/drivers/video/msm/mdss/mdss_hdmi_util.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -430,6 +430,7 @@
int hdmi_get_video_id_code(struct hdmi_disp_mode_timing_type *timing_in);
const struct hdmi_disp_mode_timing_type *hdmi_get_supported_mode(u32 mode);
void hdmi_set_supported_mode(u32 mode);
+void hdmi_del_supported_mode(u32 mode);
const char *hdmi_get_video_fmt_2string(u32 format);
ssize_t hdmi_get_video_3d_fmt_2string(u32 format, char *buf);
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index 455f725..29bc79a 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -1,4 +1,5 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/*
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -32,8 +33,6 @@
#define MAX_MIXER_HEIGHT 2400
#define MAX_IMG_WIDTH 0x3FFF
#define MAX_IMG_HEIGHT 0x3FFF
-#define MIN_DST_W 10
-#define MIN_DST_H 10
#define MAX_DST_W MAX_MIXER_WIDTH
#define MAX_DST_H MAX_MIXER_HEIGHT
#define MAX_PLANES 4
@@ -131,6 +130,7 @@
u32 bus_ab_quota;
u32 bus_ib_quota;
u32 clk_rate;
+ u32 perf_changed;
struct mdss_data_type *mdata;
struct msm_fb_data_type *mfd;
@@ -144,6 +144,7 @@
int (*stop_fnc) (struct mdss_mdp_ctl *ctl);
int (*prepare_fnc) (struct mdss_mdp_ctl *ctl, void *arg);
int (*display_fnc) (struct mdss_mdp_ctl *ctl, void *arg);
+ int (*wait_fnc) (struct mdss_mdp_ctl *ctl, void *arg);
int (*set_vsync_handler) (struct mdss_mdp_ctl *, mdp_vsync_handler_t);
void *priv_data;
@@ -334,6 +335,7 @@
int mdss_mdp_mixer_pipe_update(struct mdss_mdp_pipe *pipe, int params_changed);
int mdss_mdp_mixer_pipe_unstage(struct mdss_mdp_pipe *pipe);
int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg);
+int mdss_mdp_display_wait4comp(struct mdss_mdp_ctl *ctl);
int mdss_mdp_csc_setup(u32 block, u32 blk_idx, u32 tbl_idx, u32 csc_type);
int mdss_mdp_csc_setup_data(u32 block, u32 blk_idx, u32 tbl_idx,
@@ -341,25 +343,43 @@
int mdss_mdp_pp_init(struct device *dev);
void mdss_mdp_pp_term(struct device *dev);
+
int mdss_mdp_pp_resume(u32 mixer_num);
int mdss_mdp_pp_setup(struct mdss_mdp_ctl *ctl);
+int mdss_mdp_pp_setup_locked(struct mdss_mdp_ctl *ctl);
int mdss_mdp_pipe_pp_setup(struct mdss_mdp_pipe *pipe, u32 *op);
int mdss_mdp_pipe_sspp_setup(struct mdss_mdp_pipe *pipe, u32 *op);
void mdss_mdp_pipe_sspp_term(struct mdss_mdp_pipe *pipe);
-int mdss_mdp_pa_config(struct mdp_pa_cfg_data *config, u32 *copyback);
-int mdss_mdp_pcc_config(struct mdp_pcc_cfg_data *cfg_ptr, u32 *copyback);
-int mdss_mdp_igc_lut_config(struct mdp_igc_lut_data *config, u32 *copyback);
-int mdss_mdp_argc_config(struct mdp_pgc_lut_data *config, u32 *copyback);
-int mdss_mdp_hist_lut_config(struct mdp_hist_lut_data *config, u32 *copyback);
-int mdss_mdp_dither_config(struct mdp_dither_cfg_data *config, u32 *copyback);
-int mdss_mdp_gamut_config(struct mdp_gamut_cfg_data *config, u32 *copyback);
+int mdss_mdp_pa_config(struct mdss_mdp_ctl *ctl,
+ struct mdp_pa_cfg_data *config,
+ u32 *copyback);
+int mdss_mdp_pcc_config(struct mdss_mdp_ctl *ctl,
+ struct mdp_pcc_cfg_data *cfg_ptr,
+ u32 *copyback);
+int mdss_mdp_igc_lut_config(struct mdss_mdp_ctl *ctl,
+ struct mdp_igc_lut_data *config,
+ u32 *copyback);
+int mdss_mdp_argc_config(struct mdss_mdp_ctl *ctl,
+ struct mdp_pgc_lut_data *config,
+ u32 *copyback);
+int mdss_mdp_hist_lut_config(struct mdss_mdp_ctl *ctl,
+ struct mdp_hist_lut_data *config,
+ u32 *copyback);
+int mdss_mdp_dither_config(struct mdss_mdp_ctl *ctl,
+ struct mdp_dither_cfg_data *config,
+ u32 *copyback);
+int mdss_mdp_gamut_config(struct mdss_mdp_ctl *ctl,
+ struct mdp_gamut_cfg_data *config,
+ u32 *copyback);
-int mdss_mdp_histogram_start(struct mdp_histogram_start_req *req);
-int mdss_mdp_histogram_stop(u32 block);
-int mdss_mdp_hist_collect(struct fb_info *info,
- struct mdp_histogram_data *hist, u32 *hist_data_addr);
+int mdss_mdp_histogram_start(struct mdss_mdp_ctl *ctl,
+ struct mdp_histogram_start_req *req);
+int mdss_mdp_histogram_stop(struct mdss_mdp_ctl *ctl, u32 block);
+int mdss_mdp_hist_collect(struct mdss_mdp_ctl *ctl,
+ struct mdp_histogram_data *hist,
+ u32 *hist_data_addr);
void mdss_mdp_hist_intr_done(u32 isr);
struct mdss_mdp_pipe *mdss_mdp_pipe_alloc(struct mdss_mdp_mixer *mixer,
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index 0f52125..4b7263d 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -177,7 +177,7 @@
*clk_rate, *bus_ab_quota, *bus_ib_quota);
}
-static int mdss_mdp_ctl_perf_update(struct mdss_mdp_ctl *ctl, u32 *flags)
+static int mdss_mdp_ctl_perf_update(struct mdss_mdp_ctl *ctl)
{
int ret = MDSS_MDP_PERF_UPDATE_SKIP;
u32 clk_rate, ab_quota, ib_quota;
@@ -204,15 +204,13 @@
if ((total_ib_quota == 0) && (ctl->intf_type == MDSS_INTF_DSI))
total_ib_quota = SZ_16M >> MDSS_MDP_BUS_FACTOR_SHIFT;
- *flags = 0;
-
if (max_clk_rate != ctl->clk_rate) {
if (max_clk_rate > ctl->clk_rate)
ret = MDSS_MDP_PERF_UPDATE_EARLY;
else
ret = MDSS_MDP_PERF_UPDATE_LATE;
ctl->clk_rate = max_clk_rate;
- *flags |= MDSS_MDP_PERF_UPDATE_CLK;
+ ctl->perf_changed |= MDSS_MDP_PERF_UPDATE_CLK;
}
if ((total_ab_quota != ctl->bus_ab_quota) ||
@@ -225,7 +223,7 @@
}
ctl->bus_ab_quota = total_ab_quota;
ctl->bus_ib_quota = total_ib_quota;
- *flags |= MDSS_MDP_PERF_UPDATE_BUS;
+ ctl->perf_changed |= MDSS_MDP_PERF_UPDATE_BUS;
}
return ret;
@@ -280,7 +278,7 @@
}
static struct mdss_mdp_mixer *mdss_mdp_mixer_alloc(
- struct mdss_mdp_ctl *ctl, u32 type)
+ struct mdss_mdp_ctl *ctl, u32 type, int mux)
{
struct mdss_mdp_mixer *mixer = NULL;
u32 nmixers_intf;
@@ -297,7 +295,6 @@
nmixers_wb = ctl->mdata->nmixers_wb;
switch (type) {
-
case MDSS_MDP_MIXER_TYPE_INTF:
mixer_pool = ctl->mdata->mixer_intf;
nmixers = nmixers_intf;
@@ -314,6 +311,15 @@
break;
}
+ /* early mdp revision only supports mux of dual pipe on mixers 0 and 1,
+ * need to ensure that these pipes are readily available by using
+ * mixer 2 if available and mux is not required */
+ if (!mux && (ctl->mdata->mdp_rev == MDSS_MDP_HW_REV_100) &&
+ (type == MDSS_MDP_MIXER_TYPE_INTF) &&
+ (nmixers >= MDSS_MDP_INTF_LAYERMIXER2) &&
+ (mixer_pool[MDSS_MDP_INTF_LAYERMIXER2].ref_cnt == 0))
+ mixer_pool += MDSS_MDP_INTF_LAYERMIXER2;
+
for (i = 0; i < nmixers; i++) {
mixer = mixer_pool + i;
if (mixer->ref_cnt == 0) {
@@ -358,7 +364,7 @@
if (!ctl)
return NULL;
- mixer = mdss_mdp_mixer_alloc(ctl, MDSS_MDP_MIXER_TYPE_WRITEBACK);
+ mixer = mdss_mdp_mixer_alloc(ctl, MDSS_MDP_MIXER_TYPE_WRITEBACK, false);
if (!mixer)
goto error;
@@ -463,7 +469,8 @@
if (!ctl->mixer_left) {
ctl->mixer_left =
- mdss_mdp_mixer_alloc(ctl, MDSS_MDP_MIXER_TYPE_INTF);
+ mdss_mdp_mixer_alloc(ctl, MDSS_MDP_MIXER_TYPE_INTF,
+ (width > MAX_MIXER_WIDTH));
if (!ctl->mixer_left) {
pr_err("unable to allocate layer mixer\n");
return -ENOMEM;
@@ -484,7 +491,7 @@
if (width < ctl->width) {
if (ctl->mixer_right == NULL) {
ctl->mixer_right = mdss_mdp_mixer_alloc(ctl,
- MDSS_MDP_MIXER_TYPE_INTF);
+ MDSS_MDP_MIXER_TYPE_INTF, true);
if (!ctl->mixer_right) {
pr_err("unable to allocate right mixer\n");
if (ctl->mixer_left)
@@ -580,7 +587,7 @@
ctl->dst_format = MDSS_MDP_PANEL_FORMAT_RGB888;
break;
}
- mdss_mdp_dither_config(&dither, NULL);
+ mdss_mdp_dither_config(ctl, &dither, NULL);
}
return ctl;
@@ -619,14 +626,15 @@
sctl->width = pdata->panel_info.xres;
sctl->height = pdata->panel_info.yres;
- ctl->mixer_left = mdss_mdp_mixer_alloc(ctl, MDSS_MDP_MIXER_TYPE_INTF);
+ ctl->mixer_left = mdss_mdp_mixer_alloc(ctl, MDSS_MDP_MIXER_TYPE_INTF,
+ false);
if (!ctl->mixer_left) {
pr_err("unable to allocate layer mixer\n");
mdss_mdp_ctl_destroy(sctl);
return -ENOMEM;
}
- mixer = mdss_mdp_mixer_alloc(sctl, MDSS_MDP_MIXER_TYPE_INTF);
+ mixer = mdss_mdp_mixer_alloc(sctl, MDSS_MDP_MIXER_TYPE_INTF, false);
if (!mixer) {
pr_err("unable to allocate layer mixer\n");
mdss_mdp_ctl_destroy(sctl);
@@ -1149,13 +1157,38 @@
return 0;
}
+int mdss_mdp_display_wait4comp(struct mdss_mdp_ctl *ctl)
+{
+ int ret;
+
+ ret = mutex_lock_interruptible(&ctl->lock);
+ if (ret)
+ return ret;
+
+ if (!ctl->power_on) {
+ mutex_unlock(&ctl->lock);
+ return 0;
+ }
+
+ if (ctl->wait_fnc)
+ ret = ctl->wait_fnc(ctl, NULL);
+
+ if (ctl->perf_changed) {
+ mdss_mdp_ctl_perf_commit(ctl->mdata, ctl->perf_changed);
+ ctl->perf_changed = 0;
+ }
+
+ mutex_unlock(&ctl->lock);
+
+ return ret;
+}
+
int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg)
{
struct mdss_mdp_ctl *sctl = NULL;
int mixer1_changed, mixer2_changed;
int ret = 0;
int perf_update = MDSS_MDP_PERF_UPDATE_SKIP;
- u32 update_flags = 0;
if (!ctl) {
pr_err("display function not set\n");
@@ -1180,7 +1213,7 @@
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
if (mixer1_changed || mixer2_changed) {
- perf_update = mdss_mdp_ctl_perf_update(ctl, &update_flags);
+ perf_update = mdss_mdp_ctl_perf_update(ctl);
if (ctl->prepare_fnc)
ret = ctl->prepare_fnc(ctl, arg);
@@ -1189,8 +1222,10 @@
goto done;
}
- if (perf_update == MDSS_MDP_PERF_UPDATE_EARLY)
- mdss_mdp_ctl_perf_commit(ctl->mdata, update_flags);
+ if (perf_update == MDSS_MDP_PERF_UPDATE_EARLY) {
+ mdss_mdp_ctl_perf_commit(ctl->mdata, ctl->perf_changed);
+ ctl->perf_changed = 0;
+ }
if (mixer1_changed)
mdss_mdp_mixer_update(ctl->mixer_left);
@@ -1208,10 +1243,10 @@
}
/* postprocessing setup, including dspp */
- mdss_mdp_pp_setup(ctl);
+ mdss_mdp_pp_setup_locked(ctl);
mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_FLUSH, ctl->flush_bits);
if (sctl) {
- mdss_mdp_pp_setup(sctl);
+ mdss_mdp_pp_setup_locked(sctl);
mdss_mdp_ctl_write(sctl, MDSS_MDP_REG_CTL_FLUSH,
sctl->flush_bits);
}
@@ -1225,9 +1260,6 @@
ctl->play_cnt++;
- if (perf_update == MDSS_MDP_PERF_UPDATE_LATE)
- mdss_mdp_ctl_perf_commit(ctl->mdata, update_flags);
-
done:
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_video.c b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
index 0d4037c..e2c3b23 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_video.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
@@ -46,6 +46,7 @@
u8 timegen_en;
struct completion vsync_comp;
+ int wait_pending;
atomic_t vsync_ref;
spinlock_t vsync_lock;
@@ -271,13 +272,38 @@
pr_debug("intr ctl=%d\n", ctl->num);
- complete(&ctx->vsync_comp);
+ complete_all(&ctx->vsync_comp);
spin_lock(&ctx->vsync_lock);
if (ctx->vsync_handler)
ctx->vsync_handler(ctl, vsync_time);
spin_unlock(&ctx->vsync_lock);
}
+static int mdss_mdp_video_wait4comp(struct mdss_mdp_ctl *ctl, void *arg)
+{
+ struct mdss_mdp_video_ctx *ctx;
+ int rc;
+
+ ctx = (struct mdss_mdp_video_ctx *) ctl->priv_data;
+ if (!ctx) {
+ pr_err("invalid ctx\n");
+ return -ENODEV;
+ }
+
+ WARN(!ctx->wait_pending, "waiting without commit! ctl=%d", ctl->num);
+
+ rc = wait_for_completion_interruptible_timeout(&ctx->vsync_comp,
+ VSYNC_TIMEOUT);
+ WARN(rc <= 0, "vsync timed out (%d) ctl=%d\n", rc, ctl->num);
+
+ if (ctx->wait_pending) {
+ ctx->wait_pending = 0;
+ video_vsync_irq_disable(ctl);
+ }
+
+ return rc;
+}
+
static int mdss_mdp_video_display(struct mdss_mdp_ctl *ctl, void *arg)
{
struct mdss_mdp_video_ctx *ctx;
@@ -290,8 +316,14 @@
pr_err("invalid ctx\n");
return -ENODEV;
}
- INIT_COMPLETION(ctx->vsync_comp);
- video_vsync_irq_enable(ctl);
+
+ if (!ctx->wait_pending) {
+ ctx->wait_pending++;
+ INIT_COMPLETION(ctx->vsync_comp);
+ video_vsync_irq_enable(ctl);
+ } else {
+ WARN(1, "commit without wait! ctl=%d", ctl->num);
+ }
if (!ctx->timegen_en) {
rc = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_UNBLANK, NULL);
@@ -302,20 +334,17 @@
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
mdp_video_write(ctx, MDSS_MDP_REG_INTF_TIMING_ENGINE_EN, 1);
wmb();
- }
- rc = wait_for_completion_interruptible_timeout(&ctx->vsync_comp,
- VSYNC_TIMEOUT);
- WARN(rc <= 0, "vsync timed out (%d) ctl=%d\n", rc, ctl->num);
+ rc = wait_for_completion_interruptible_timeout(&ctx->vsync_comp,
+ VSYNC_TIMEOUT);
+ WARN(rc <= 0, "timeout (%d) enabling timegen on ctl=%d\n",
+ rc, ctl->num);
- if (!ctx->timegen_en) {
ctx->timegen_en = true;
rc = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_TIMEGEN_ON, NULL);
WARN(rc, "intf %d timegen on error (%d)\n", ctl->intf_num, rc);
}
- video_vsync_irq_disable(ctl);
-
return 0;
}
@@ -385,6 +414,7 @@
ctl->stop_fnc = mdss_mdp_video_stop;
ctl->display_fnc = mdss_mdp_video_display;
+ ctl->wait_fnc = mdss_mdp_video_wait4comp;
ctl->set_vsync_handler = mdss_mdp_video_set_vsync_handler;
return 0;
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index a8764cb..63ad005 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -57,10 +57,19 @@
struct mdss_mdp_format_params *fmt)
{
u32 xres, yres;
+ u32 min_src_size, min_dst_size;
xres = mfd->fbi->var.xres;
yres = mfd->fbi->var.yres;
+ if (mfd->mdata->mdp_rev >= MDSS_MDP_HW_REV_102) {
+ min_src_size = fmt->is_yuv ? 2 : 1;
+ min_dst_size = 1;
+ } else {
+ min_src_size = fmt->is_yuv ? 10 : 5;
+ min_dst_size = 2;
+ }
+
if (req->z_order >= MDSS_MDP_MAX_STAGE) {
pr_err("zorder %d out of range\n", req->z_order);
return -ERANGE;
@@ -68,7 +77,7 @@
if (req->src.width > MAX_IMG_WIDTH ||
req->src.height > MAX_IMG_HEIGHT ||
- req->src_rect.w == 0 || req->src_rect.h == 0 ||
+ req->src_rect.w < min_src_size || req->src_rect.h < min_src_size ||
CHECK_BOUNDS(req->src_rect.x, req->src_rect.w, req->src.width) ||
CHECK_BOUNDS(req->src_rect.y, req->src_rect.h, req->src.height)) {
pr_err("invalid source image img wh=%dx%d rect=%d,%d,%d,%d\n",
@@ -78,7 +87,7 @@
return -EOVERFLOW;
}
- if (req->dst_rect.w < MIN_DST_W || req->dst_rect.h < MIN_DST_H ||
+ if (req->dst_rect.w < min_dst_size || req->dst_rect.h < min_dst_size ||
req->dst_rect.w > MAX_DST_W || req->dst_rect.h > MAX_DST_H) {
pr_err("invalid destination resolution (%dx%d)",
req->dst_rect.w, req->dst_rect.h);
@@ -151,10 +160,6 @@
pr_err("invalid odd src resolution or coordinates\n");
return -EINVAL;
}
- if ((req->dst_rect.w & 0x1) || (req->dst_rect.h & 0x1)) {
- pr_err("invalid odd dst resolution\n");
- return -EINVAL;
- }
}
return 0;
@@ -265,14 +270,16 @@
pipe->params_changed = true;
}
- if (req->id == MSMFB_NEW_REQUEST) {
- mixer = mdss_mdp_mixer_get(mfd->ctl, mixer_mux);
- if (!mixer) {
- pr_err("unable to get mixer\n");
- return -ENODEV;
- }
+ mixer = mdss_mdp_mixer_get(mfd->ctl, mixer_mux);
+ if (!mixer) {
+ pr_err("unable to get mixer\n");
+ return -ENODEV;
+ }
- if (fmt->is_yuv || (req->flags & MDP_OV_PIPE_SHARE))
+ if (req->id == MSMFB_NEW_REQUEST) {
+ if (req->flags & MDP_OV_PIPE_FORCE_DMA)
+ pipe_type = MDSS_MDP_PIPE_TYPE_DMA;
+ else if (fmt->is_yuv || (req->flags & MDP_OV_PIPE_SHARE))
pipe_type = MDSS_MDP_PIPE_TYPE_VIG;
else
pipe_type = MDSS_MDP_PIPE_TYPE_RGB;
@@ -308,6 +315,21 @@
pr_err("invalid pipe ndx=%x\n", req->id);
return pipe ? PTR_ERR(pipe) : -ENODEV;
}
+
+ if (pipe->mixer != mixer) {
+ if (!mixer->ctl || (mixer->ctl->mfd != mfd)) {
+ pr_err("Can't switch mixer %d->%d pnum %d!\n",
+ pipe->mixer->num, mixer->num,
+ pipe->num);
+ mdss_mdp_pipe_unmap(pipe);
+ return -EINVAL;
+ }
+ pr_debug("switching pipe mixer %d->%d pnum %d\n",
+ pipe->mixer->num, mixer->num,
+ pipe->num);
+ mdss_mdp_mixer_pipe_unstage(pipe);
+ pipe->mixer = mixer;
+ }
}
pipe->flags = req->flags;
@@ -415,25 +437,28 @@
int num_planes,
u32 flags)
{
- int i;
+ int i, rc = 0;
+
+ if ((num_planes <= 0) || (num_planes > MAX_PLANES))
+ return -EINVAL;
memset(data, 0, sizeof(*data));
for (i = 0; i < num_planes; i++) {
data->p[i].flags = flags;
- mdss_mdp_get_img(&planes[i], &data->p[i]);
- if (data->p[0].len == 0)
+ rc = mdss_mdp_get_img(&planes[i], &data->p[i]);
+ if (rc) {
+ pr_err("failed to map buf p=%d flags=%x\n", i, flags);
+ while (i > 0) {
+ i--;
+ mdss_mdp_put_img(&data->p[i]);
+ }
break;
+ }
}
- if (i != num_planes) {
- for (; i >= 0; i--)
- mdss_mdp_put_img(&data->p[i]);
- return -ENOMEM;
- }
+ data->num_planes = i;
- data->num_planes = num_planes;
-
- return 0;
+ return rc;
}
static inline int mdss_mdp_overlay_free_buf(struct mdss_mdp_data *data)
@@ -491,17 +516,20 @@
}
}
}
- mutex_unlock(&mfd->lock);
if (mfd->kickoff_fnc)
ret = mfd->kickoff_fnc(ctl);
else
ret = mdss_mdp_display_commit(ctl, NULL);
+ mutex_unlock(&mfd->lock);
+
if (IS_ERR_VALUE(ret)) {
mutex_unlock(&mfd->ov_lock);
return ret;
}
+ ret = mdss_mdp_display_wait4comp(ctl);
+
complete(&mfd->update.comp);
mutex_lock(&mfd->no_update.lock);
if (mfd->no_update.timer.function)
@@ -645,26 +673,24 @@
ret = mdss_mdp_overlay_get_buf(mfd, &src_data, &req->data, 1, flgs);
if (ret) {
pr_err("src_data pmem error\n");
- goto rotate_done;
+ return ret;
}
ret = mdss_mdp_overlay_get_buf(mfd, &dst_data, &req->dst_data, 1, flgs);
if (ret) {
pr_err("dst_data pmem error\n");
- goto rotate_done;
+ goto dst_buf_fail;
}
ret = mdss_mdp_rotator_queue(rot, &src_data, &dst_data);
- if (ret) {
+ if (ret)
pr_err("rotator queue error session id=%x\n", req->id);
- goto rotate_done;
- }
-rotate_done:
mdss_mdp_overlay_free_buf(&dst_data);
+dst_buf_fail:
mdss_mdp_overlay_free_buf(&src_data);
- return 0;
+ return ret;
}
static int mdss_mdp_overlay_queue(struct msm_fb_data_type *mfd,
@@ -725,12 +751,6 @@
ret = mdss_mdp_overlay_free_fb_pipe(mfd);
} else {
ret = mdss_mdp_overlay_queue(mfd, req);
-
- if ((ret == 0) && (mfd->panel.type == WRITEBACK_PANEL)) {
- mutex_unlock(&mfd->ov_lock);
- ret = mdss_mdp_overlay_kickoff(mfd->ctl);
- return ret;
- }
}
mutex_unlock(&mfd->ov_lock);
@@ -1302,11 +1322,20 @@
mfd->ctl = ctl;
}
- pm_runtime_get_sync(&mfd->pdev->dev);
+ rc = pm_runtime_get_sync(&mfd->pdev->dev);
+ if (rc) {
+ pr_err("unable to resume with pm_runtime_get_sync (%d)\n", rc);
+ return rc;
+ }
rc = mdss_mdp_ctl_start(mfd->ctl);
if (rc == 0) {
atomic_inc(&ov_active_panels);
+
+ if (mfd->vsync_pending) {
+ mfd->vsync_pending = 0;
+ mdss_mdp_overlay_vsync_ctrl(mfd, mfd->vsync_pending);
+ }
} else {
mdss_mdp_ctl_destroy(mfd->ctl);
mfd->ctl = NULL;
@@ -1345,7 +1374,9 @@
if (atomic_dec_return(&ov_active_panels) == 0)
mdss_mdp_rotator_release_all();
- pm_runtime_put(&mfd->pdev->dev);
+ rc = pm_runtime_put(&mfd->pdev->dev);
+ if (rc)
+ pr_err("unable to suspend w/pm_runtime_put (%d)\n", rc);
}
return rc;
diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c
index 851d608..59d760b 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pp.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -610,15 +610,21 @@
struct pp_sts_type *pp_sts;
u32 data, col_state;
unsigned long flag;
- int i;
+ int i, ret = 0;
+
+ if (!mixer || !ctl)
+ return -EINVAL;
dspp_num = mixer->num;
/* no corresponding dspp */
if ((mixer->type != MDSS_MDP_MIXER_TYPE_INTF) ||
(dspp_num >= MDSS_MDP_MAX_DSPP))
- return 0;
+ return -EINVAL;
base = MDSS_MDP_REG_DSPP_OFFSET(dspp_num);
hist_info = &mdss_pp_res->dspp_hist[dspp_num];
+
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+
if (hist_info->col_en) {
/* HIST_EN & AUTO_CLEAR */
opmode |= (1 << 16) | (1 << 17);
@@ -634,7 +640,6 @@
MDSS_MDP_REG_DSPP_HIST_CTL_BASE, 1);
hist_info->col_state = HIST_START;
}
- hist_info->is_kick_ready = true;
spin_unlock_irqrestore(&mdss_hist_lock, flag);
mutex_unlock(&mdss_mdp_hist_mutex);
}
@@ -646,7 +651,7 @@
/* nothing to update */
if ((!flags) && (!(hist_info->col_en)))
- return 0;
+ goto dspp_exit;
pp_sts = &mdss_pp_res->pp_dspp_sts[dspp_num];
@@ -734,12 +739,36 @@
opmode |= (1 << 22);
MDSS_MDP_REG_WRITE(base + MDSS_MDP_REG_DSPP_OP_MODE, opmode);
- ctl->flush_bits |= BIT(13 + dspp_num); /* DSPP */
- return 0;
+ mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_FLUSH, BIT(13 + dspp_num));
+ wmb();
+dspp_exit:
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+ return ret;
}
int mdss_mdp_pp_setup(struct mdss_mdp_ctl *ctl)
{
+ int ret = 0;
+
+ if ((!ctl->mfd) || (!mdss_pp_res))
+ return -EINVAL;
+
+ /* TODO: have some sort of reader/writer lock to prevent unclocked
+ * access while display power is toggled */
+ if (!ctl->mfd->panel_power_on) {
+ ret = -EPERM;
+ goto error;
+ }
+ mutex_lock(&ctl->mfd->lock);
+ ret = mdss_mdp_pp_setup_locked(ctl);
+ mutex_unlock(&ctl->mfd->lock);
+error:
+ return ret;
+}
+
+/* call only when holding and mfd->lock */
+int mdss_mdp_pp_setup_locked(struct mdss_mdp_ctl *ctl)
+{
u32 disp_num;
if ((!ctl->mfd) || (!mdss_pp_res))
return -EINVAL;
@@ -887,11 +916,15 @@
return 0;
}
-int mdss_mdp_pa_config(struct mdp_pa_cfg_data *config, u32 *copyback)
+int mdss_mdp_pa_config(struct mdss_mdp_ctl *ctl, struct mdp_pa_cfg_data *config,
+ u32 *copyback)
{
int ret = 0;
u32 pa_offset, disp_num, dspp_num = 0;
+ if (!ctl)
+ return -EINVAL;
+
if ((config->block < MDP_LOGICAL_BLOCK_DISP_0) ||
(config->block >= MDP_BLOCK_MAX))
return -EINVAL;
@@ -925,6 +958,8 @@
pa_config_exit:
mutex_unlock(&mdss_pp_mutex);
+ if (!ret)
+ mdss_mdp_pp_setup(ctl);
return ret;
}
@@ -1054,11 +1089,16 @@
MDSS_MDP_REG_WRITE(offset + 8, cfg_ptr->b.rgb_1);
}
-int mdss_mdp_pcc_config(struct mdp_pcc_cfg_data *config, u32 *copyback)
+int mdss_mdp_pcc_config(struct mdss_mdp_ctl *ctl,
+ struct mdp_pcc_cfg_data *config,
+ u32 *copyback)
{
int ret = 0;
u32 base, disp_num, dspp_num = 0;
+ if (!ctl)
+ return -EINVAL;
+
if ((config->block < MDP_LOGICAL_BLOCK_DISP_0) ||
(config->block >= MDP_BLOCK_MAX))
return -EINVAL;
@@ -1088,8 +1128,9 @@
pcc_config_exit:
mutex_unlock(&mdss_pp_mutex);
+ if (!ret)
+ mdss_mdp_pp_setup(ctl);
return ret;
-
}
static void pp_read_igc_lut(struct mdp_igc_lut_data *cfg,
@@ -1146,12 +1187,17 @@
MDSS_MDP_REG_WRITE(offset, (cfg->c2_data[i] & 0xFFF) | data);
}
-int mdss_mdp_igc_lut_config(struct mdp_igc_lut_data *config, u32 *copyback)
+int mdss_mdp_igc_lut_config(struct mdss_mdp_ctl *ctl,
+ struct mdp_igc_lut_data *config,
+ u32 *copyback)
{
int ret = 0;
u32 tbl_idx, igc_offset, disp_num, dspp_num = 0;
struct mdp_igc_lut_data local_cfg;
+ if (!ctl)
+ return -EINVAL;
+
if ((config->block < MDP_LOGICAL_BLOCK_DISP_0) ||
(config->block >= MDP_BLOCK_MAX))
return -EINVAL;
@@ -1213,6 +1259,8 @@
igc_config_exit:
mutex_unlock(&mdss_pp_mutex);
+ if (!ret)
+ mdss_mdp_pp_setup(ctl);
return ret;
}
static void pp_update_gc_one_lut(u32 offset,
@@ -1310,7 +1358,9 @@
MDSS_MDP_REG_WRITE(offset + 4, 1);
}
-int mdss_mdp_argc_config(struct mdp_pgc_lut_data *config, u32 *copyback)
+int mdss_mdp_argc_config(struct mdss_mdp_ctl *ctl,
+ struct mdp_pgc_lut_data *config,
+ u32 *copyback)
{
int ret = 0;
u32 argc_offset = 0, disp_num, dspp_num = 0;
@@ -1318,6 +1368,9 @@
struct mdp_pgc_lut_data *pgc_ptr;
u32 tbl_size;
+ if (!ctl)
+ return -EINVAL;
+
if ((PP_BLOCK(config->block) < MDP_LOGICAL_BLOCK_DISP_0) ||
(PP_BLOCK(config->block) >= MDP_BLOCK_MAX))
return -EINVAL;
@@ -1407,13 +1460,20 @@
}
argc_config_exit:
mutex_unlock(&mdss_pp_mutex);
+ if (!ret)
+ mdss_mdp_pp_setup(ctl);
return ret;
}
-int mdss_mdp_hist_lut_config(struct mdp_hist_lut_data *config, u32 *copyback)
+int mdss_mdp_hist_lut_config(struct mdss_mdp_ctl *ctl,
+ struct mdp_hist_lut_data *config,
+ u32 *copyback)
{
int i, ret = 0;
u32 hist_offset, disp_num, dspp_num = 0;
+ if (!ctl)
+ return -EINVAL;
+
if ((config->block < MDP_LOGICAL_BLOCK_DISP_0) ||
(config->block >= MDP_BLOCK_MAX))
return -EINVAL;
@@ -1456,12 +1516,19 @@
}
enhist_config_exit:
mutex_unlock(&mdss_pp_mutex);
+ if (!ret)
+ mdss_mdp_pp_setup(ctl);
return ret;
}
-int mdss_mdp_dither_config(struct mdp_dither_cfg_data *config, u32 *copyback)
+int mdss_mdp_dither_config(struct mdss_mdp_ctl *ctl,
+ struct mdp_dither_cfg_data *config,
+ u32 *copyback)
{
u32 disp_num;
+ if (!ctl)
+ return -EINVAL;
+
if ((config->block < MDP_LOGICAL_BLOCK_DISP_0) ||
(config->block >= MDP_BLOCK_MAX))
return -EINVAL;
@@ -1473,16 +1540,22 @@
mdss_pp_res->dither_disp_cfg[disp_num] = *config;
mdss_pp_res->pp_disp_flags[disp_num] |= PP_FLAGS_DIRTY_DITHER;
mutex_unlock(&mdss_pp_mutex);
+ mdss_mdp_pp_setup(ctl);
return 0;
}
-int mdss_mdp_gamut_config(struct mdp_gamut_cfg_data *config, u32 *copyback)
+int mdss_mdp_gamut_config(struct mdss_mdp_ctl *ctl,
+ struct mdp_gamut_cfg_data *config,
+ u32 *copyback)
{
int i, j, size_total = 0, ret = 0;
u32 offset, disp_num, dspp_num = 0;
uint16_t *tbl_off;
struct mdp_gamut_cfg_data local_cfg;
+ if (!ctl)
+ return -EINVAL;
+
if ((config->block < MDP_LOGICAL_BLOCK_DISP_0) ||
(config->block >= MDP_BLOCK_MAX))
return -EINVAL;
@@ -1560,6 +1633,8 @@
}
gamut_config_exit:
mutex_unlock(&mdss_pp_mutex);
+ if (!ret)
+ mdss_mdp_pp_setup(ctl);
return ret;
}
static void pp_hist_read(u32 v_base, struct pp_hist_col_info *hist_info)
@@ -1576,7 +1651,8 @@
hist_info->hist_cnt_read++;
}
-int mdss_mdp_histogram_start(struct mdp_histogram_start_req *req)
+int mdss_mdp_histogram_start(struct mdss_mdp_ctl *ctl,
+ struct mdp_histogram_start_req *req)
{
u32 ctl_base, done_shift_bit;
struct pp_hist_col_info *hist_info;
@@ -1585,6 +1661,9 @@
u32 mixer_cnt, mixer_id[MDSS_MDP_INTF_MAX_LAYERMIXER];
unsigned long flag;
+ if (!ctl)
+ return -EINVAL;
+
if ((req->block < MDP_LOGICAL_BLOCK_DISP_0) ||
(req->block >= MDP_BLOCK_MAX))
return -EINVAL;
@@ -1642,10 +1721,24 @@
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
hist_start_exit:
mutex_unlock(&mdss_mdp_hist_mutex);
+ if (!ret) {
+ mdss_mdp_pp_setup(ctl);
+ /* wait for a frame to let histrogram enable itself */
+ usleep(41666);
+ for (i = 0; i < mixer_cnt; i++) {
+ dspp_num = mixer_id[i];
+ hist_info = &mdss_pp_res->dspp_hist[dspp_num];
+ mutex_lock(&mdss_mdp_hist_mutex);
+ spin_lock_irqsave(&mdss_hist_lock, flag);
+ hist_info->is_kick_ready = true;
+ spin_unlock_irqrestore(&mdss_hist_lock, flag);
+ mutex_unlock(&mdss_mdp_hist_mutex);
+ }
+ }
return ret;
}
-int mdss_mdp_histogram_stop(u32 block)
+int mdss_mdp_histogram_stop(struct mdss_mdp_ctl *ctl, u32 block)
{
int i, ret = 0;
u32 dspp_num, disp_num, ctl_base, done_bit;
@@ -1653,6 +1746,9 @@
u32 mixer_cnt, mixer_id[MDSS_MDP_INTF_MAX_LAYERMIXER];
unsigned long flag;
+ if (!ctl)
+ return -EINVAL;
+
if ((block < MDP_LOGICAL_BLOCK_DISP_0) ||
(block >= MDP_BLOCK_MAX))
return -EINVAL;
@@ -1699,11 +1795,14 @@
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
hist_stop_exit:
mutex_unlock(&mdss_mdp_hist_mutex);
+ if (!ret)
+ mdss_mdp_pp_setup(ctl);
return ret;
}
-int mdss_mdp_hist_collect(struct fb_info *info,
- struct mdp_histogram_data *hist, u32 *hist_data_addr)
+int mdss_mdp_hist_collect(struct mdss_mdp_ctl *ctl,
+ struct mdp_histogram_data *hist,
+ u32 *hist_data_addr)
{
int i, j, wait_ret, ret = 0;
u32 timeout, v_base;
@@ -1712,6 +1811,9 @@
u32 mixer_cnt, mixer_id[MDSS_MDP_INTF_MAX_LAYERMIXER];
unsigned long flag;
+ if (!ctl)
+ return -EINVAL;
+
if ((hist->block < MDP_LOGICAL_BLOCK_DISP_0) ||
(hist->block >= MDP_BLOCK_MAX))
return -EINVAL;
@@ -1750,6 +1852,8 @@
spin_unlock_irqrestore(&mdss_hist_lock, flag);
timeout = HIST_WAIT_TIMEOUT(hist_info->frame_cnt);
mutex_unlock(&mdss_mdp_hist_mutex);
+ /* flush updates before wait*/
+ mdss_mdp_pp_setup(ctl);
wait_ret = wait_for_completion_killable_timeout(
&(hist_info->comp), timeout);
@@ -1779,8 +1883,8 @@
}
if (hist_info->col_state != HIST_READY) {
ret = -ENODATA;
- pr_debug("%s: collection state is not ready: %d",
- __func__, hist_info->col_state);
+ pr_debug("%s: state is not ready: %d",
+ __func__, hist_info->col_state);
goto hist_collect_exit;
}
} else {
diff --git a/drivers/video/msm/mdss/mhl_msc.c b/drivers/video/msm/mdss/mhl_msc.c
index 3d3fff9..add65ac 100644
--- a/drivers/video/msm/mdss/mhl_msc.c
+++ b/drivers/video/msm/mdss/mhl_msc.c
@@ -16,6 +16,7 @@
#include <linux/vmalloc.h>
#include <linux/input.h>
#include "mhl_msc.h"
+#include "mdss_hdmi_mhl.h"
static struct mhl_tx_ctrl *mhl_ctrl;
static DEFINE_MUTEX(msc_send_workqueue_mutex);
@@ -39,6 +40,18 @@
"Reserved ",
};
+static bool mhl_check_tmds_enabled(struct mhl_tx_ctrl *mhl_ctrl)
+{
+ if (mhl_ctrl && mhl_ctrl->hdmi_mhl_ops) {
+ struct msm_hdmi_mhl_ops *ops = mhl_ctrl->hdmi_mhl_ops;
+ struct platform_device *pdev = mhl_ctrl->pdata->hdmi_pdev;
+ return (ops->tmds_enabled(pdev) == true);
+ } else {
+ pr_err("%s: invalid input\n", __func__);
+ return false;
+ }
+}
+
static void mhl_print_devcap(u8 offset, u8 devcap)
{
switch (offset) {
@@ -398,10 +411,12 @@
static int mhl_rap_recv(struct mhl_tx_ctrl *mhl_ctrl, u8 action_code)
{
u8 error_code;
+ bool tmds_en;
switch (action_code) {
case MHL_RAP_POLL:
- if (mhl_ctrl->tmds_enabled())
+ tmds_en = mhl_check_tmds_enabled(mhl_ctrl);
+ if (tmds_en)
error_code = MHL_RAPK_NO_ERROR;
else
error_code = MHL_RAPK_UNSUPPORTED_ACTION_CODE;
@@ -513,6 +528,8 @@
int mhl_msc_recv_write_stat(struct mhl_tx_ctrl *mhl_ctrl,
u8 offset, u8 value)
{
+ bool tmds_en;
+
if (offset >= 2)
return -EFAULT;
@@ -543,10 +560,11 @@
* changed and PATH ENABLED
* bit set
*/
+ tmds_en = mhl_check_tmds_enabled(mhl_ctrl);
if ((value ^ mhl_ctrl->path_en_state)
& MHL_STATUS_PATH_ENABLED) {
if (value & MHL_STATUS_PATH_ENABLED) {
- if (mhl_ctrl->tmds_enabled() &&
+ if (tmds_en &&
(mhl_ctrl->devcap[offset] &
MHL_FEATURE_RAP_SUPPORT)) {
mhl_msc_send_msc_msg(
diff --git a/drivers/video/msm/mdss/mhl_sii8334.c b/drivers/video/msm/mdss/mhl_sii8334.c
index 4d6af15..30dd471 100644
--- a/drivers/video/msm/mdss/mhl_sii8334.c
+++ b/drivers/video/msm/mdss/mhl_sii8334.c
@@ -30,6 +30,7 @@
#include "mdss_panel.h"
#include "mdss_io_util.h"
#include "mhl_msc.h"
+#include "mdss_hdmi_mhl.h"
#define MHL_DRIVER_NAME "sii8334"
#define COMPATIBLE_NAME "qcom,mhl-sii8334"
@@ -193,8 +194,6 @@
static void mhl_init_reg_settings(struct mhl_tx_ctrl *mhl_ctrl,
bool mhl_disc_en);
-static uint8_t store_tmds_state;
-
int mhl_i2c_reg_read(struct i2c_client *client,
uint8_t slave_addr_index, uint8_t reg_offset)
{
@@ -239,6 +238,8 @@
int i, rc = 0;
struct device_node *of_node = NULL;
struct dss_gpio *temp_gpio = NULL;
+ struct platform_device *hdmi_pdev = NULL;
+ struct device_node *hdmi_tx_node = NULL;
int dt_gpio;
i = 0;
@@ -316,6 +317,23 @@
temp_gpio->gpio);
pdata->gpios[MHL_TX_INTR_GPIO] = temp_gpio;
+ /* parse phandle for hdmi tx */
+ hdmi_tx_node = of_parse_phandle(of_node, "qcom,hdmi-tx-map", 0);
+ if (!hdmi_tx_node) {
+ pr_err("%s: can't find hdmi phandle\n", __func__);
+ goto error;
+ }
+
+ hdmi_pdev = of_find_device_by_node(hdmi_tx_node);
+ if (!hdmi_pdev) {
+ pr_err("%s: can't find the device by node\n", __func__);
+ goto error;
+ }
+ pr_debug("%s: hdmi_pdev [0X%x] to pdata->pdev\n",
+ __func__, (unsigned int)hdmi_pdev);
+
+ pdata->hdmi_pdev = hdmi_pdev;
+
return 0;
error:
pr_err("%s: ret due to err\n", __func__);
@@ -719,10 +737,6 @@
}
}
-uint8_t check_tmds_enabled(void)
-{
- return store_tmds_state;
-}
void mhl_tmds_ctrl(struct mhl_tx_ctrl *mhl_ctrl, uint8_t on)
{
@@ -730,16 +744,8 @@
if (on) {
MHL_SII_REG_NAME_MOD(REG_TMDS_CCTRL, BIT4, BIT4);
mhl_drive_hpd(mhl_ctrl, HPD_UP);
- /*
- * store the state to be used
- * before responding to RAP msgs
- * this needs to be obtained from
- * hdmi driver
- */
- store_tmds_state = 1;
} else {
MHL_SII_REG_NAME_MOD(REG_TMDS_CCTRL, BIT4, 0x00);
- store_tmds_state = 0;
}
}
@@ -1007,7 +1013,10 @@
*/
cbus_stat = MHL_SII_CBUS_RD(0x0D);
if (BIT6 & cbus_stat)
- mhl_tmds_ctrl(mhl_ctrl, TMDS_ENABLE);
+ mhl_drive_hpd(mhl_ctrl, HPD_UP);
+ else
+ mhl_drive_hpd(mhl_ctrl, HPD_DOWN);
+
}
}
@@ -1636,6 +1645,7 @@
struct mhl_tx_platform_data *pdata = NULL;
struct mhl_tx_ctrl *mhl_ctrl;
struct usb_ext_notification *mhl_info = NULL;
+ struct msm_hdmi_mhl_ops *hdmi_mhl_ops = NULL;
mhl_ctrl = devm_kzalloc(&client->dev, sizeof(*mhl_ctrl), GFP_KERNEL);
if (!mhl_ctrl) {
@@ -1784,25 +1794,63 @@
goto failed_probe;
}
+ hdmi_mhl_ops = devm_kzalloc(&client->dev,
+ sizeof(struct msm_hdmi_mhl_ops),
+ GFP_KERNEL);
+ if (!hdmi_mhl_ops) {
+ pr_err("%s: alloc hdmi mhl ops failed\n", __func__);
+ rc = -ENOMEM;
+ goto failed_probe_pwr;
+ }
+
pr_debug("%s: i2c client addr is [%x]\n", __func__, client->addr);
+ if (mhl_ctrl->pdata->hdmi_pdev) {
+ rc = msm_hdmi_register_mhl(mhl_ctrl->pdata->hdmi_pdev,
+ hdmi_mhl_ops);
+ if (rc) {
+ pr_err("%s: register with hdmi failed\n", __func__);
+ rc = -EPROBE_DEFER;
+ goto failed_probe_pwr;
+ }
+ }
+
+ if (!hdmi_mhl_ops || !hdmi_mhl_ops->tmds_enabled ||
+ !hdmi_mhl_ops->set_mhl_max_pclk) {
+ pr_err("%s: func ptr is NULL\n", __func__);
+ rc = -EINVAL;
+ goto failed_probe_pwr;
+ }
+ mhl_ctrl->hdmi_mhl_ops = hdmi_mhl_ops;
+
+ rc = hdmi_mhl_ops->set_mhl_max_pclk(
+ mhl_ctrl->pdata->hdmi_pdev, MAX_MHL_PCLK);
+ if (rc) {
+ pr_err("%s: can't set max mhl pclk\n", __func__);
+ goto failed_probe_pwr;
+ }
mhl_info = devm_kzalloc(&client->dev, sizeof(*mhl_info), GFP_KERNEL);
if (!mhl_info) {
pr_err("%s: alloc mhl info failed\n", __func__);
- goto failed_probe;
+ rc = -ENOMEM;
+ goto failed_probe_pwr;
}
mhl_info->ctxt = mhl_ctrl;
mhl_info->notify = mhl_sii_device_discovery;
if (msm_register_usb_ext_notification(mhl_info)) {
pr_err("%s: register for usb notifcn failed\n", __func__);
- goto failed_probe;
+ rc = -EPROBE_DEFER;
+ goto failed_probe_pwr;
}
mhl_ctrl->mhl_info = mhl_info;
mhl_register_msc(mhl_ctrl);
- mhl_ctrl->tmds_enabled = check_tmds_enabled;
return 0;
+
+failed_probe_pwr:
+ power_supply_unregister(&mhl_ctrl->mhl_psy);
failed_probe:
+ free_irq(mhl_ctrl->i2c_handle->irq, mhl_ctrl);
mhl_gpio_config(mhl_ctrl, 0);
mhl_vreg_config(mhl_ctrl, 0);
/* do not deep-free */
@@ -1814,6 +1862,9 @@
failed_no_mem:
if (mhl_ctrl)
devm_kfree(&client->dev, mhl_ctrl);
+ mhl_info = NULL;
+ pdata = NULL;
+ mhl_ctrl = NULL;
pr_err("%s: PROBE FAILED, rc=%d\n", __func__, rc);
return rc;
}
diff --git a/drivers/video/msm/mdss/msm_mdss_io_8974.c b/drivers/video/msm/mdss/msm_mdss_io_8974.c
index 83e89c5..3b6fc38 100644
--- a/drivers/video/msm/mdss/msm_mdss_io_8974.c
+++ b/drivers/video/msm/mdss/msm_mdss_io_8974.c
@@ -296,7 +296,6 @@
pd = ((ctrl_pdata->panel_data).panel_info.mipi).dsi_phy_db;
/* Strength ctrl 0 */
- MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0484, 0x07);
MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0484, pd->strength[0]);
/* phy regulator ctrl settings. Both the DSI controller
@@ -306,8 +305,11 @@
else
off = 0x0580 - 0x600;
- /* Regulator ctrl - CAL_PWD_CFG */
+ /* Regulator ctrl 0 */
+ MIPI_OUTP((ctrl_pdata->ctrl_base) + off + (4 * 0), 0x0);
+ /* Regulator ctrl - CAL_PWR_CFG */
MIPI_OUTP((ctrl_pdata->ctrl_base) + off + (4 * 6), pd->regulator[6]);
+
/* Regulator ctrl - TEST */
MIPI_OUTP((ctrl_pdata->ctrl_base) + off + (4 * 5), pd->regulator[5]);
/* Regulator ctrl 3 */
@@ -321,6 +323,12 @@
/* Regulator ctrl 4 */
MIPI_OUTP((ctrl_pdata->ctrl_base) + off + (4 * 4), pd->regulator[4]);
+ /* LDO ctrl 0 */
+ if ((ctrl_pdata->panel_data).panel_info.pdest == DISPLAY_1)
+ MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x4dc, 0x00);
+ else
+ MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x4dc, 0x00);
+
off = 0x0440; /* phy timing ctrl 0 - 11 */
for (i = 0; i < 12; i++) {
MIPI_OUTP((ctrl_pdata->ctrl_base) + off, pd->timing[i]);
@@ -352,7 +360,7 @@
}
/* MMSS_DSI_0_PHY_DSIPHY_CTRL_0 */
- MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0470, 0x7f);
+ MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0470, 0x5f);
wmb();
/* DSI_0_PHY_DSIPHY_GLBL_TEST_CTRL */
diff --git a/include/drm/kgsl_drm.h b/include/drm/kgsl_drm.h
index 7ffae9d..41f7c29 100644
--- a/include/drm/kgsl_drm.h
+++ b/include/drm/kgsl_drm.h
@@ -20,6 +20,7 @@
#define DRM_KGSL_GEM_UNLOCK_ON_TS 0x0D
#define DRM_KGSL_GEM_CREATE_FD 0x0E
#define DRM_KGSL_GEM_GET_ION_FD 0x0F
+#define DRM_KGSL_GEM_CREATE_FROM_ION 0x10
#define DRM_IOCTL_KGSL_GEM_CREATE \
DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_CREATE, struct drm_kgsl_gem_create)
@@ -80,6 +81,10 @@
DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_GET_ION_FD, \
struct drm_kgsl_gem_get_ion_fd)
+#define DRM_IOCTL_KGSL_GEM_CREATE_FROM_ION \
+DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_CREATE_FROM_ION, \
+struct drm_kgsl_gem_create_from_ion)
+
/* Maximum number of sub buffers per GEM object */
#define DRM_KGSL_GEM_MAX_BUFFERS 2
@@ -199,4 +204,9 @@
uint32_t handle;
};
+struct drm_kgsl_gem_create_from_ion {
+ uint32_t ion_fd;
+ uint32_t handle;
+};
+
#endif
diff --git a/include/linux/mfd/pm8xxx/batterydata-lib.h b/include/linux/mfd/pm8xxx/batterydata-lib.h
index 5ff1cfb..f27ceca 100644
--- a/include/linux/mfd/pm8xxx/batterydata-lib.h
+++ b/include/linux/mfd/pm8xxx/batterydata-lib.h
@@ -89,6 +89,8 @@
* readings from bms are not available.
* @delta_rbatt_mohm: the resistance to be added towards lower soc to
* compensate for battery capacitance.
+ * @rbatt_capacitve_mohm: the resistance to be added to compensate for
+ * battery capacitance
*/
struct bms_battery_data {
@@ -100,6 +102,7 @@
struct sf_lut *rbatt_sf_lut;
int default_rbatt_mohm;
int delta_rbatt_mohm;
+ int rbatt_capacitive_mohm;
};
#if defined(CONFIG_PM8921_BMS) || \
diff --git a/include/linux/mfd/wcd9xxx/core.h b/include/linux/mfd/wcd9xxx/core.h
index 3ebf091..aed549e 100644
--- a/include/linux/mfd/wcd9xxx/core.h
+++ b/include/linux/mfd/wcd9xxx/core.h
@@ -29,6 +29,8 @@
(((ver == TABLA_VERSION_1_0) || (ver == TABLA_VERSION_1_1)) ? 1 : 0)
#define TABLA_IS_2_0(ver) ((ver == TABLA_VERSION_2_0) ? 1 : 0)
+#define WCD9XXX_SUPPLY_BUCK_NAME "cdc-vdd-buck"
+
#define SITAR_VERSION_1P0 0
#define SITAR_VERSION_1P1 1
#define SITAR_IS_1P0(ver) \
diff --git a/include/linux/mfd/wcd9xxx/wcd9xxx_registers.h b/include/linux/mfd/wcd9xxx/wcd9xxx_registers.h
index 9c44e8b..412341a 100644
--- a/include/linux/mfd/wcd9xxx/wcd9xxx_registers.h
+++ b/include/linux/mfd/wcd9xxx/wcd9xxx_registers.h
@@ -196,4 +196,85 @@
#define WCD9XXX_A_MAD_ANA_CTRL (0x150)
#define WCD9XXX_A_MAD_ANA_CTRL__POR (0xF1)
+
+#define WCD9XXX_A_CDC_CLK_OTHR_CTL (0x30C)
+#define WCD9XXX_A_CDC_CLK_OTHR_CTL__POR (0x00)
+
+/* Class H related common registers */
+#define WCD9XXX_A_BUCK_MODE_1 (0x181)
+#define WCD9XXX_A_BUCK_MODE_1__POR (0x21)
+#define WCD9XXX_A_BUCK_MODE_2 (0x182)
+#define WCD9XXX_A_BUCK_MODE_2__POR (0xFF)
+#define WCD9XXX_A_BUCK_MODE_3 (0x183)
+#define WCD9XXX_A_BUCK_MODE_3__POR (0xCC)
+#define WCD9XXX_A_BUCK_MODE_4 (0x184)
+#define WCD9XXX_A_BUCK_MODE_4__POR (0x3A)
+#define WCD9XXX_A_BUCK_MODE_5 (0x185)
+#define WCD9XXX_A_BUCK_MODE_5__POR (0x00)
+#define WCD9XXX_A_BUCK_CTRL_VCL_1 (0x186)
+#define WCD9XXX_A_BUCK_CTRL_VCL_1__POR (0x48)
+#define WCD9XXX_A_BUCK_CTRL_VCL_2 (0x187)
+#define WCD9XXX_A_BUCK_CTRL_VCL_2__POR (0xA3)
+#define WCD9XXX_A_BUCK_CTRL_VCL_3 (0x188)
+#define WCD9XXX_A_BUCK_CTRL_VCL_3__POR (0x82)
+#define WCD9XXX_A_BUCK_CTRL_CCL_1 (0x189)
+#define WCD9XXX_A_BUCK_CTRL_CCL_1__POR (0xAB)
+#define WCD9XXX_A_BUCK_CTRL_CCL_2 (0x18A)
+#define WCD9XXX_A_BUCK_CTRL_CCL_2__POR (0xDC)
+#define WCD9XXX_A_BUCK_CTRL_CCL_3 (0x18B)
+#define WCD9XXX_A_BUCK_CTRL_CCL_3__POR (0x6A)
+#define WCD9XXX_A_BUCK_CTRL_CCL_4 (0x18C)
+#define WCD9XXX_A_BUCK_CTRL_CCL_4__POR (0x58)
+#define WCD9XXX_A_BUCK_CTRL_PWM_DRVR_1 (0x18D)
+#define WCD9XXX_A_BUCK_CTRL_PWM_DRVR_1__POR (0x50)
+#define WCD9XXX_A_BUCK_CTRL_PWM_DRVR_2 (0x18E)
+#define WCD9XXX_A_BUCK_CTRL_PWM_DRVR_2__POR (0x64)
+#define WCD9XXX_A_BUCK_CTRL_PWM_DRVR_3 (0x18F)
+#define WCD9XXX_A_BUCK_CTRL_PWM_DRVR_3__POR (0x77)
+#define WCD9XXX_A_BUCK_TMUX_A_D (0x190)
+#define WCD9XXX_A_BUCK_TMUX_A_D__POR (0x00)
+#define WCD9XXX_A_NCP_EN (0x192)
+#define WCD9XXX_A_NCP_EN__POR (0xFE)
+#define WCD9XXX_A_NCP_STATIC (0x194)
+#define WCD9XXX_A_NCP_STATIC__POR (0x28)
+#define WCD9XXX_A_NCP_BUCKREF (0x191)
+#define WCD9XXX_A_NCP_BUCKREF__POR (0x00)
+#define WCD9XXX_A_CDC_CLSH_B1_CTL (0x320)
+#define WCD9XXX_A_CDC_CLSH_B1_CTL__POR (0xE4)
+#define WCD9XXX_A_CDC_CLSH_B2_CTL (0x321)
+#define WCD9XXX_A_CDC_CLSH_B2_CTL__POR (0x00)
+#define WCD9XXX_A_CDC_CLSH_B3_CTL (0x322)
+#define WCD9XXX_A_CDC_CLSH_B3_CTL__POR (0x00)
+#define WCD9XXX_A_CDC_CLSH_BUCK_NCP_VARS (0x323)
+#define WCD9XXX_A_CDC_CLSH_BUCK_NCP_VARS__POR (0x00)
+#define WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD (0x324)
+#define WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD__POR (0x12)
+#define WCD9XXX_A_CDC_CLSH_IDLE_EAR_THSD (0x325)
+#define WCD9XXX_A_CDC_CLSH_IDLE_EAR_THSD__POR (0x0C)
+#define WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD (0x326)
+#define WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD__POR (0x18)
+#define WCD9XXX_A_CDC_CLSH_FCLKONLY_EAR_THSD (0x327)
+#define WCD9XXX_A_CDC_CLSH_FCLKONLY_EAR_THSD__POR (0x23)
+#define WCD9XXX_A_CDC_CLSH_K_ADDR (0x328)
+#define WCD9XXX_A_CDC_CLSH_K_ADDR__POR (0x00)
+#define WCD9XXX_A_CDC_CLSH_K_DATA (0x329)
+#define WCD9XXX_A_CDC_CLSH_K_DATA__POR (0xA4)
+#define WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L (0x32A)
+#define WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L__POR (0xD7)
+#define WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U (0x32B)
+#define WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U__POR (0x05)
+#define WCD9XXX_A_CDC_CLSH_I_PA_FACT_EAR_L (0x32C)
+#define WCD9XXX_A_CDC_CLSH_I_PA_FACT_EAR_L__POR (0x60)
+#define WCD9XXX_A_CDC_CLSH_I_PA_FACT_EAR_U (0x32D)
+#define WCD9XXX_A_CDC_CLSH_I_PA_FACT_EAR_U__POR (0x09)
+#define WCD9XXX_A_CDC_CLSH_V_PA_HD_EAR (0x32E)
+#define WCD9XXX_A_CDC_CLSH_V_PA_HD_EAR__POR (0x00)
+#define WCD9XXX_A_CDC_CLSH_V_PA_HD_HPH (0x32F)
+#define WCD9XXX_A_CDC_CLSH_V_PA_HD_HPH__POR (0x00)
+#define WCD9XXX_A_CDC_CLSH_V_PA_MIN_EAR (0x330)
+#define WCD9XXX_A_CDC_CLSH_V_PA_MIN_EAR__POR (0x00)
+#define WCD9XXX_A_CDC_CLSH_V_PA_MIN_HPH (0x331)
+#define WCD9XXX_A_CDC_CLSH_V_PA_MIN_HPH__POR (0x00)
+
+
#endif
diff --git a/include/linux/mhl_8334.h b/include/linux/mhl_8334.h
index 75e6546..d6f8356 100644
--- a/include/linux/mhl_8334.h
+++ b/include/linux/mhl_8334.h
@@ -50,6 +50,8 @@
u8 data[MHL_SCRATCHPAD_SIZE];
};
+/* MHL 8334 supports a max HD pixel clk of 75 MHz */
+#define MAX_MHL_PCLK 75000
/* USB driver interface */
@@ -124,6 +126,7 @@
struct dss_gpio *gpios[MHL_TX_MAX_GPIO];
struct dss_vreg *vregs[MHL_TX_MAX_VREG];
int irq;
+ struct platform_device *hdmi_pdev;
};
struct mhl_tx_ctrl {
@@ -144,7 +147,7 @@
uint8_t devcap[16];
uint8_t devcap_state;
uint8_t path_en_state;
- uint8_t (*tmds_enabled)(void);
+ void *hdmi_mhl_ops;
struct work_struct mhl_msc_send_work;
struct list_head list_cmd;
struct input_dev *input;
diff --git a/include/linux/msm_audio_acdb.h b/include/linux/msm_audio_acdb.h
index 471f10a..f0c4915 100644
--- a/include/linux/msm_audio_acdb.h
+++ b/include/linux/msm_audio_acdb.h
@@ -49,6 +49,10 @@
(AUDIO_MAX_COMMON_IOCTL_NUM+21), unsigned)
#define AUDIO_SET_LSM_CAL _IOW(AUDIO_IOCTL_MAGIC, \
(AUDIO_MAX_COMMON_IOCTL_NUM+22), unsigned)
+#define AUDIO_SET_ADM_CUSTOM_TOPOLOGY _IOW(AUDIO_IOCTL_MAGIC, \
+ (AUDIO_MAX_COMMON_IOCTL_NUM+23), unsigned)
+#define AUDIO_SET_ASM_CUSTOM_TOPOLOGY _IOW(AUDIO_IOCTL_MAGIC, \
+ (AUDIO_MAX_COMMON_IOCTL_NUM+24), unsigned)
#define AUDIO_MAX_ACDB_IOCTL (AUDIO_MAX_COMMON_IOCTL_NUM+30)
diff --git a/include/linux/msm_ion.h b/include/linux/msm_ion.h
index 409bcc8..c53cb35 100644
--- a/include/linux/msm_ion.h
+++ b/include/linux/msm_ion.h
@@ -281,6 +281,20 @@
{
return -ENODEV;
}
+
+static inline int msm_ion_secure_buffer(struct ion_client *client,
+ struct ion_handle *handle,
+ enum cp_mem_usage usage,
+ int flags)
+{
+ return -ENODEV;
+}
+
+static inline int msm_ion_unsecure_buffer(struct ion_client *client,
+ struct ion_handle *handle)
+{
+ return -ENODEV;
+}
#endif /* CONFIG_ION */
#endif /* __KERNEL */
diff --git a/include/linux/msm_ipa.h b/include/linux/msm_ipa.h
index 613cd9f..1b869b1 100644
--- a/include/linux/msm_ipa.h
+++ b/include/linux/msm_ipa.h
@@ -47,7 +47,7 @@
#define IPA_IOCTL_V4_INIT_NAT 23
#define IPA_IOCTL_NAT_DMA 24
#define IPA_IOCTL_V4_DEL_NAT 26
-#define IPA_IOCTL_GET_ASYNC_MSG 27
+#define IPA_IOCTL_PULL_MSG 27
#define IPA_IOCTL_GET_NAT_OFFSET 28
#define IPA_IOCTL_MAX 29
@@ -62,6 +62,11 @@
#define IPA_RESOURCE_NAME_MAX 20
/**
+ * size of the mac address
+ */
+#define IPA_MAC_ADDR_SIZE 6
+
+/**
* the attributes of the rule (routing or filtering)
*/
#define IPA_FLT_TOS (1ul << 0)
@@ -142,6 +147,26 @@
};
/**
+ * enum ipa_wlan_event - Events for wlan client
+ *
+ * wlan client connect: New wlan client connected
+ * wlan client disconnect: wlan client disconnected
+ * wlan client power save: wlan client moved to power save
+ * wlan client normal: wlan client moved out of power save
+ * sw routing enable: ipa routing is disabled
+ * sw routing disable: ipa routing is enabled
+ */
+enum ipa_wlan_event {
+ WLAN_CLIENT_CONNECT,
+ WLAN_CLIENT_DISCONNECT,
+ WLAN_CLIENT_POWER_SAVE_MODE,
+ WLAN_CLIENT_NORMAL_MODE,
+ SW_ROUTING_ENABLE,
+ SW_ROUTING_DISABLE,
+};
+
+
+/**
* struct ipa_rule_attrib - attributes of a routing/filtering
* rule, all in LE
* @attrib_mask: what attributes are valid
@@ -501,10 +526,12 @@
/**
* struct ipa_ioc_query_intf_tx_props - interface tx propertie
* @name: name of interface
+ * @num_tx_props: number of TX properties
* @tx[0]: output parameter, the tx properties go here back to back
*/
struct ipa_ioc_query_intf_tx_props {
char name[IPA_RESOURCE_NAME_MAX];
+ uint32_t num_tx_props;
struct ipa_ioc_tx_intf_prop tx[0];
};
@@ -523,10 +550,12 @@
/**
* struct ipa_ioc_query_intf_rx_props - interface rx propertie
* @name: name of interface
+ * @num_rx_props: number of RX properties
* @rx: output parameter, the rx properties go here back to back
*/
struct ipa_ioc_query_intf_rx_props {
char name[IPA_RESOURCE_NAME_MAX];
+ uint32_t num_rx_props;
struct ipa_ioc_rx_intf_prop rx[0];
};
@@ -609,24 +638,45 @@
/**
* struct ipa_msg_meta - Format of the message meta-data.
* @msg_type: the type of the message
- * @msg_len: the length of the message in bytes
* @rsvd: reserved bits for future use.
+ * @msg_len: the length of the message in bytes
*
+ * For push model:
* Client in user-space should issue a read on the device (/dev/ipa) with a
- * buffer of atleast this size in an continuous loop, call will block when there
- * is no pending async message.
+ * sufficiently large buffer in a continuous loop, call will block when there is
+ * no message to read. Upon return, client can read the ipa_msg_meta from start
+ * of buffer to find out type and length of message
+ * size of buffer supplied >= (size of largest message + size of metadata)
*
- * After reading a message's meta-data using above scheme, client should issue a
- * GET_MSG IOCTL to actually read the message itself into the buffer of
- * "msg_len" immediately following the ipa_msg_meta itself in the IOCTL payload
+ * For pull model:
+ * Client in user-space can also issue a pull msg IOCTL to device (/dev/ipa)
+ * with a payload containing space for the ipa_msg_meta and the message specific
+ * payload length.
+ * size of buffer supplied == (len of specific message + size of metadata)
*/
struct ipa_msg_meta {
uint8_t msg_type;
- uint16_t msg_len;
uint8_t rsvd;
+ uint16_t msg_len;
};
/**
+ * struct ipa_wlan_msg - To hold information about wlan client
+ * @name: name of the wlan interface
+ * @mac_addr: mac address of wlan client
+ *
+ * wlan drivers need to pass name of wlan iface and mac address of
+ * wlan client along with ipa_wlan_event, whenever a wlan client is
+ * connected/disconnected/moved to power save/come out of power save
+ */
+struct ipa_wlan_msg {
+ char name[IPA_RESOURCE_NAME_MAX];
+ uint8_t mac_addr[IPA_MAC_ADDR_SIZE];
+};
+
+
+
+/**
* actual IOCTLs supported by IPA driver
*/
#define IPA_IOC_ADD_HDR _IOWR(IPA_IOC_MAGIC, \
@@ -707,8 +757,8 @@
#define IPA_IOC_SET_FLT _IOW(IPA_IOC_MAGIC, \
IPA_IOCTL_SET_FLT, \
uint32_t)
-#define IPA_IOC_GET_ASYNC_MSG _IOWR(IPA_IOC_MAGIC, \
- IPA_IOCTL_GET_ASYNC_MSG, \
+#define IPA_IOC_PULL_MSG _IOWR(IPA_IOC_MAGIC, \
+ IPA_IOCTL_PULL_MSG, \
struct ipa_msg_meta *)
#endif /* _MSM_IPA_H_ */
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index 3ec966b..bc35d14 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -114,6 +114,7 @@
MDP_BGR_565, /* BGR 565 planer */
MDP_BGR_888, /* BGR 888 */
MDP_Y_CBCR_H2V2_VENUS,
+ MDP_BGRX_8888, /* BGRX 8888 */
MDP_IMGTYPE_LIMIT,
MDP_RGB_BORDERFILL, /* border fill pipe */
MDP_FB_FORMAT = MDP_IMGTYPE2_START, /* framebuffer format */
@@ -166,6 +167,7 @@
#define MDP_BACKEND_COMPOSITION 0x00040000
#define MDP_BORDERFILL_SUPPORTED 0x00010000
#define MDP_SECURE_OVERLAY_SESSION 0x00008000
+#define MDP_OV_PIPE_FORCE_DMA 0x00004000
#define MDP_MEMORY_ID_TYPE_FB 0x00001000
#define MDP_TRANSP_NOP 0xffffffff
diff --git a/include/linux/qpnp/vibrator.h b/include/linux/qpnp/vibrator.h
new file mode 100644
index 0000000..aa823be
--- /dev/null
+++ b/include/linux/qpnp/vibrator.h
@@ -0,0 +1,39 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __QPNP_VIBRATOR_H__
+#define __QPNP_VIBRATOR_H__
+
+enum qpnp_vib_en_mode {
+ QPNP_VIB_MANUAL,
+ QPNP_VIB_DTEST1,
+ QPNP_VIB_DTEST2,
+ QPNP_VIB_DTEST3,
+};
+
+struct qpnp_vib_config {
+ u16 drive_mV;
+ u8 active_low;
+ enum qpnp_vib_en_mode enable_mode;
+};
+#if defined(CONFIG_QPNP_VIBRATOR)
+
+int qpnp_vibrator_config(struct qpnp_vib_config *vib_config);
+#else
+
+static inline int qpnp_vibrator_config(struct qpnp_vib_config *vib_config)
+{
+ return -ENODEV;
+}
+#endif
+
+#endif /* __QPNP_VIBRATOR_H__ */
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 0a1428e..67889bf 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -2304,7 +2304,7 @@
}
/* mmput gets rid of the mappings and all user-space */
-extern void mmput(struct mm_struct *);
+extern int mmput(struct mm_struct *);
/* Grab a reference to a task's mm, if it is not already going away */
extern struct mm_struct *get_task_mm(struct task_struct *task);
/*
diff --git a/include/linux/usb/cdc.h b/include/linux/usb/cdc.h
index 2b39f69..478734f 100644
--- a/include/linux/usb/cdc.h
+++ b/include/linux/usb/cdc.h
@@ -54,6 +54,7 @@
#define USB_CDC_OBEX_TYPE 0x15
#define USB_CDC_NCM_TYPE 0x1a
#define USB_CDC_MBB_TYPE 0x1b /* mbb_desc */
+#define USB_CDC_EXT_MBB_TYPE 0x1c
/* "Header Functional Descriptor" from CDC spec 5.2.3.1 */
struct usb_cdc_header_desc {
@@ -203,6 +204,17 @@
__u8 bmNetworkCapabilities;
} __packed;
+/* "Extended MBIM Functional Descriptor" */
+struct usb_cdc_ext_mbb_desc {
+ __u8 bLength;
+ __u8 bDescriptorType;
+ __u8 bDescriptorSubType;
+
+ __le16 bcdMbbExtendedVersion;
+ __u8 bMaxOutstandingCmdMsges;
+ __le16 wMTU;
+} __packed;
+
/*-------------------------------------------------------------------------*/
/*
diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
index 268aa48..4fb20f6 100644
--- a/include/linux/usb/hcd.h
+++ b/include/linux/usb/hcd.h
@@ -349,9 +349,8 @@
/* to log submission/completion events*/
void (*log_urb)(struct urb *urb, char *event, unsigned extra);
void (*dump_regs)(struct usb_hcd *);
- void (*enable_ulpi_control)(struct usb_hcd *hcd, u32 linestate);
- void (*disable_ulpi_control)(struct usb_hcd *hcd);
void (*set_autosuspend_delay)(struct usb_device *);
+ void (*reset_sof_bug_handler)(struct usb_hcd *hcd, u32 val);
};
extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb);
diff --git a/include/linux/usb/rmnet_ctrl_qti.h b/include/linux/usb/rmnet_ctrl_qti.h
new file mode 100644
index 0000000..5038396
--- /dev/null
+++ b/include/linux/usb/rmnet_ctrl_qti.h
@@ -0,0 +1,12 @@
+#ifndef __LINUX_USB_U_RMNET_CTRL_QTI_H
+#define __LINUX_USB_U_RMNET_CTRL_QTI_H
+
+#include <linux/ioctl.h>
+
+#define MAX_QTI_PKT_SIZE 2048
+
+#define FRMNET_CTRL_IOCTL_MAGIC 'r'
+#define FRMNET_CTRL_GET_LINE_STATE _IOR(FRMNET_CTRL_IOCTL_MAGIC, 2, int)
+
+
+#endif /* __LINUX_USB_U_RMNET_CTRL_QTI_H */
diff --git a/include/media/msmb_generic_buf_mgr.h b/include/media/msmb_generic_buf_mgr.h
index 13844a3..17cb947 100644
--- a/include/media/msmb_generic_buf_mgr.h
+++ b/include/media/msmb_generic_buf_mgr.h
@@ -5,6 +5,7 @@
uint32_t session_id;
uint32_t stream_id;
uint32_t frame_id;
+ struct timeval timestamp;
uint32_t index;
};
diff --git a/include/media/msmb_isp.h b/include/media/msmb_isp.h
index c9d3f15..34b3139 100644
--- a/include/media/msmb_isp.h
+++ b/include/media/msmb_isp.h
@@ -45,7 +45,9 @@
PIX_VIEWFINDER,
CAMIF_RAW,
IDEAL_RAW,
- RDI,
+ RDI_INTF_0,
+ RDI_INTF_1,
+ RDI_INTF_2,
VFE_AXI_SRC_MAX
};
@@ -94,12 +96,17 @@
enum ISP_START_PIXEL_PATTERN pixel_pattern;
};
+struct msm_vfe_rdi_cfg {
+ uint8_t cid;
+ uint8_t frame_based;
+};
+
struct msm_vfe_input_cfg {
union {
struct msm_vfe_pix_cfg pix_cfg;
+ struct msm_vfe_rdi_cfg rdi_cfg;
} d;
enum msm_vfe_input_src input_src;
-
};
struct msm_vfe_axi_plane_cfg {
@@ -281,14 +288,15 @@
ISP_WM_BUS_OVERFLOW = 4,
ISP_STATS_OVERFLOW = 5,
ISP_CAMIF_ERROR = 6,
- ISP_STATS_NOTIFY = 7,
- ISP_SOF = 8,
- ISP_EOF = 9,
- ISP_BUF_DIVERT = 10,
- ISP_EVENT_MAX = 11
+ ISP_SOF = 7,
+ ISP_EOF = 8,
+ ISP_EVENT_MAX = 9
};
-#define ISP_EVENT_BASE (V4L2_EVENT_PRIVATE_START + 1)
+#define ISP_EVENT_OFFSET 8
+#define ISP_EVENT_BASE (V4L2_EVENT_PRIVATE_START)
+#define ISP_BUF_EVENT_BASE (ISP_EVENT_BASE + (1 << ISP_EVENT_OFFSET))
+#define ISP_STATS_EVENT_BASE (ISP_EVENT_BASE + (2 << ISP_EVENT_OFFSET))
#define ISP_EVENT_REG_UPDATE (ISP_EVENT_BASE + ISP_REG_UPDATE)
#define ISP_EVENT_START_ACK (ISP_EVENT_BASE + ISP_START_ACK)
#define ISP_EVENT_STOP_ACK (ISP_EVENT_BASE + ISP_STOP_ACK)
@@ -296,11 +304,10 @@
#define ISP_EVENT_WM_BUS_OVERFLOW (ISP_EVENT_BASE + ISP_WM_BUS_OVERFLOW)
#define ISP_EVENT_STATS_OVERFLOW (ISP_EVENT_BASE + ISP_STATS_OVERFLOW)
#define ISP_EVENT_CAMIF_ERROR (ISP_EVENT_BASE + ISP_CAMIF_ERROR)
-#define ISP_EVENT_STATS_NOTIFY (ISP_EVENT_BASE + ISP_STATS_NOTIFY)
#define ISP_EVENT_SOF (ISP_EVENT_BASE + ISP_SOF)
#define ISP_EVENT_EOF (ISP_EVENT_BASE + ISP_EOF)
-#define ISP_EVENT_BUF_DIVERT (ISP_EVENT_BASE + ISP_BUF_DIVERT)
-
+#define ISP_EVENT_BUF_DIVERT (ISP_BUF_EVENT_BASE)
+#define ISP_EVENT_STATS_NOTIFY (ISP_STATS_EVENT_BASE)
/* The msm_v4l2_event_data structure should match the
* v4l2_event.u.data field.
@@ -324,6 +331,9 @@
};
struct msm_isp_event_data {
+ /*Wall clock except for buffer divert events
+ *which use monotonic clock
+ */
struct timeval timestamp;
/* if pix is a src frame_id is from camif */
uint32_t frame_id;
@@ -340,6 +350,19 @@
} u; /* union can have max 52 bytes */
};
+#define V4L2_PIX_FMT_QBGGR8 v4l2_fourcc('Q', 'B', 'G', '8')
+#define V4L2_PIX_FMT_QGBRG8 v4l2_fourcc('Q', 'G', 'B', '8')
+#define V4L2_PIX_FMT_QGRBG8 v4l2_fourcc('Q', 'G', 'R', '8')
+#define V4L2_PIX_FMT_QRGGB8 v4l2_fourcc('Q', 'R', 'G', '8')
+#define V4L2_PIX_FMT_QBGGR10 v4l2_fourcc('Q', 'B', 'G', '0')
+#define V4L2_PIX_FMT_QGBRG10 v4l2_fourcc('Q', 'G', 'B', '0')
+#define V4L2_PIX_FMT_QGRBG10 v4l2_fourcc('Q', 'G', 'R', '0')
+#define V4L2_PIX_FMT_QRGGB10 v4l2_fourcc('Q', 'R', 'G', '0')
+#define V4L2_PIX_FMT_QBGGR12 v4l2_fourcc('Q', 'B', 'G', '2')
+#define V4L2_PIX_FMT_QGBRG12 v4l2_fourcc('Q', 'G', 'B', '2')
+#define V4L2_PIX_FMT_QGRBG12 v4l2_fourcc('Q', 'G', 'R', '2')
+#define V4L2_PIX_FMT_QRGGB12 v4l2_fourcc('Q', 'R', 'G', '2')
+
#define VIDIOC_MSM_VFE_REG_CFG \
_IOWR('V', BASE_VIDIOC_PRIVATE, struct msm_vfe_cfg_cmd2)
diff --git a/include/media/msmb_pproc.h b/include/media/msmb_pproc.h
index 939c4e3..b003f99 100644
--- a/include/media/msmb_pproc.h
+++ b/include/media/msmb_pproc.h
@@ -102,6 +102,9 @@
#define VIDIOC_MSM_CPP_GET_INST_INFO \
_IOWR('V', BASE_VIDIOC_PRIVATE + 2, struct msm_camera_v4l2_ioctl_t)
+#define VIDIOC_MSM_CPP_LOAD_FIRMWARE \
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 3, struct msm_camera_v4l2_ioctl_t)
+
#define V4L2_EVENT_CPP_FRAME_DONE (V4L2_EVENT_PRIVATE_START + 0)
struct msm_camera_v4l2_ioctl_t {
diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h
index badbd8e..e909195 100644
--- a/include/net/bluetooth/bluetooth.h
+++ b/include/net/bluetooth/bluetooth.h
@@ -1,6 +1,6 @@
/*
BlueZ - Bluetooth protocol stack for Linux
- Copyright (c) 2000-2001, 2010-2012 The Linux Foundation. All rights reserved.
+ Copyright (c) 2000-2001, 2010-2013 The Linux Foundation. All rights reserved.
Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
@@ -63,6 +63,7 @@
#define BT_SECURITY_LOW 1
#define BT_SECURITY_MEDIUM 2
#define BT_SECURITY_HIGH 3
+#define BT_SECURITY_VERY_HIGH 4
#define BT_DEFER_SETUP 7
#define BT_FLUSHABLE 8
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
index 4555b08..93f0aa90 100644
--- a/include/sound/apr_audio-v2.h
+++ b/include/sound/apr_audio-v2.h
@@ -82,6 +82,14 @@
*/
#define ADM_CMD_DEVICE_OPEN_V5 0x00010326
+#define ADM_BIT_SHIFT_DEVICE_PERF_MODE_FLAG 13
+
+/* Definition for a legacy device session. */
+#define ADM_LEGACY_DEVICE_SESSION 0
+
+/* Definition for a low latency stream session. */
+#define ADM_LOW_LATENCY_DEVICE_SESSION 1
+
/* Indicates that endpoint_id_2 is to be ignored.*/
#define ADM_CMD_COPP_OPEN_END_POINT_ID_2_IGNORE 0xFFFF
@@ -3794,8 +3802,15 @@
/* adsp_asm_session_command.h*/
#define ASM_STREAM_CMD_OPEN_WRITE_V2 0x00010D8F
+#define ASM_STREAM_CMD_OPEN_WRITE_V3 0x00010DB3
-struct asm_stream_cmd_open_write_v2 {
+#define ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_WRITE 28
+
+#define ASM_LEGACY_STREAM_SESSION 0
+
+#define ASM_LOW_LATENCY_STREAM_SESSION 1
+
+struct asm_stream_cmd_open_write_v3 {
struct apr_hdr hdr;
uint32_t mode_flags;
/* Mode flags that configure the stream to notify the client
@@ -3878,6 +3893,9 @@
} __packed;
#define ASM_STREAM_CMD_OPEN_READ_V2 0x00010D8C
+
+#define ASM_STREAM_CMD_OPEN_READ_V3 0x00010DB4
+
/* Definition of the timestamp type flag bitmask */
#define ASM_BIT_MASKIMESTAMPYPE_FLAG (0x00000020UL)
@@ -3890,8 +3908,10 @@
/* Absolute timestamp is identified by this value.*/
#define ASM_ABSOLUTEIMESTAMP 1
+/* Bit shift for the stream_perf_mode subfield. */
+#define ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_READ 29
-struct asm_stream_cmd_open_read_v2 {
+struct asm_stream_cmd_open_read_v3 {
struct apr_hdr hdr;
u32 mode_flags;
/* Mode flags that indicate whether meta information per encoded
@@ -6215,6 +6235,22 @@
#define VOICE_CMD_GET_PARAM 0x0001133E
#define VOICE_EVT_GET_PARAM_ACK 0x00011008
+/* Set Q6 topologies */
+#define ASM_CMD_ADD_TOPOLOGIES 0x00010DBE
+#define ADM_CMD_ADD_TOPOLOGIES 0x00010335
+
+/* structure used for both ioctls */
+struct cmd_set_topologies {
+ struct apr_hdr hdr;
+ u32 payload_addr_lsw;
+ /* LSW of parameter data payload address.*/
+ u32 payload_addr_msw;
+ /* MSW of parameter data payload address.*/
+ u32 mem_map_handle;
+ /* Memory map handle returned by mem map command */
+ u32 payload_size;
+ /* Size in bytes of the variable payload in shared memory */
+} __packed;
/* SRS TRUMEDIA start */
/* topology */
diff --git a/include/sound/q6adm-v2.h b/include/sound/q6adm-v2.h
index 6e5e649..77a805c 100644
--- a/include/sound/q6adm-v2.h
+++ b/include/sound/q6adm-v2.h
@@ -29,10 +29,11 @@
int srs_trumedia_open(int port_id, int srs_tech_id, void *srs_params);
-int adm_open(int port, int path, int rate, int mode, int topology);
+int adm_open(int port, int path, int rate, int mode, int topology,
+ bool perf_mode, uint16_t bits_per_sample);
int adm_multi_ch_copp_open(int port, int path, int rate, int mode,
- int topology);
+ int topology, bool perf_mode, uint16_t bits_per_sample);
int adm_memory_map_regions(int port_id, uint32_t *buf_add, uint32_t mempool_id,
uint32_t *bufsz, uint32_t bufcnt);
diff --git a/include/sound/q6asm-v2.h b/include/sound/q6asm-v2.h
index 984571b..dc30cd6 100644
--- a/include/sound/q6asm-v2.h
+++ b/include/sound/q6asm-v2.h
@@ -139,7 +139,7 @@
app_cb cb;
atomic_t cmd_state;
/* Relative or absolute TS */
- uint32_t time_flag;
+ atomic_t time_flag;
atomic_t nowait_cmd_cnt;
void *priv;
uint32_t io_mode;
@@ -150,6 +150,8 @@
/* idx:1 out port, 0: in port*/
struct audio_port_data port[2];
wait_queue_head_t cmd_wait;
+ wait_queue_head_t time_wait;
+ bool perf_mode;
};
void q6asm_audio_client_free(struct audio_client *ac);
@@ -177,6 +179,9 @@
int q6asm_open_write(struct audio_client *ac, uint32_t format
/*, uint16_t bits_per_sample*/);
+int q6asm_open_write_v2(struct audio_client *ac, uint32_t format,
+ uint16_t bits_per_sample);
+
int q6asm_open_read_write(struct audio_client *ac,
uint32_t rd_format,
uint32_t wr_format);
@@ -261,10 +266,20 @@
int q6asm_media_format_block_pcm(struct audio_client *ac,
uint32_t rate, uint32_t channels);
+int q6asm_media_format_block_pcm_format_support(struct audio_client *ac,
+ uint32_t rate, uint32_t channels,
+ uint16_t bits_per_sample);
+
int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac,
uint32_t rate, uint32_t channels,
bool use_default_chmap, char *channel_map);
+int q6asm_media_format_block_multi_ch_pcm_v2(
+ struct audio_client *ac,
+ uint32_t rate, uint32_t channels,
+ bool use_default_chmap, char *channel_map,
+ uint16_t bits_per_sample);
+
int q6asm_media_format_block_aac(struct audio_client *ac,
struct asm_aac_cfg *cfg);
diff --git a/kernel/exit.c b/kernel/exit.c
index d8bd3b42..6096e80 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -639,6 +639,7 @@
{
struct mm_struct *mm = tsk->mm;
struct core_state *core_state;
+ int mm_released;
mm_release(tsk, mm);
if (!mm)
@@ -683,7 +684,10 @@
enter_lazy_tlb(mm, current);
task_unlock(tsk);
mm_update_next_owner(mm);
- mmput(mm);
+
+ mm_released = mmput(mm);
+ if (mm_released)
+ set_tsk_thread_flag(tsk, TIF_MM_RELEASED);
}
/*
diff --git a/kernel/fork.c b/kernel/fork.c
index c0bf8c7..0de735c 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -581,8 +581,9 @@
/*
* Decrement the use count and release all resources for an mm.
*/
-void mmput(struct mm_struct *mm)
+int mmput(struct mm_struct *mm)
{
+ int mm_freed = 0;
might_sleep();
if (atomic_dec_and_test(&mm->mm_users)) {
@@ -600,7 +601,9 @@
if (mm->binfmt)
module_put(mm->binfmt->module);
mmdrop(mm);
+ mm_freed = 1;
}
+ return mm_freed;
}
EXPORT_SYMBOL_GPL(mmput);
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 7ecbc70..9962c88 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1474,6 +1474,8 @@
hdev->sniff_max_interval = 800;
hdev->sniff_min_interval = 80;
+ set_bit(HCI_SETUP, &hdev->flags);
+
tasklet_init(&hdev->cmd_task, hci_cmd_task, (unsigned long) hdev);
tasklet_init(&hdev->rx_task, hci_rx_task, (unsigned long) hdev);
tasklet_init(&hdev->tx_task, hci_tx_task, (unsigned long) hdev);
@@ -1542,7 +1544,6 @@
}
set_bit(HCI_AUTO_OFF, &hdev->flags);
- set_bit(HCI_SETUP, &hdev->flags);
queue_work(hdev->workqueue, &hdev->power_on);
hci_notify(hdev, HCI_DEV_REG);
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 15d3585..198773c 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -1,6 +1,6 @@
/*
BlueZ - Bluetooth protocol stack for Linux
- Copyright (c) 2000-2001, 2010-2012 The Linux Foundation. All rights reserved.
+ Copyright (c) 2000-2001, 2010-2013 The Linux Foundation. All rights reserved.
Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
@@ -2046,7 +2046,7 @@
sizeof(cp), &cp);
goto unlock;
} else if (!(lmp_ssp_capable(conn)) && conn->auth_initiator &&
- (conn->pending_sec_level == BT_SECURITY_HIGH)) {
+ (conn->pending_sec_level == BT_SECURITY_VERY_HIGH)) {
conn->pending_sec_level = BT_SECURITY_MEDIUM;
}
@@ -2669,6 +2669,12 @@
BT_DBG("Conn pending sec level is %d, ssp is %d, key len is %d",
conn->pending_sec_level, conn->ssp_mode, key->pin_len);
}
+ if (conn && (conn->ssp_mode == 0) &&
+ (conn->pending_sec_level == BT_SECURITY_VERY_HIGH) &&
+ (key->pin_len != 16)) {
+ BT_DBG("Security is high ignoring this key");
+ goto not_found;
+ }
if (key->key_type == 0x04 && conn && conn->auth_type != 0xff &&
(conn->auth_type & 0x01)) {
@@ -2853,14 +2859,14 @@
conn->ssp_mode = (ev->features[0] & 0x01);
/*In case if remote device ssp supported/2.0 device
- reduce the security level to MEDIUM if it is HIGH*/
+ reduce the security level to MEDIUM if it is VERY HIGH*/
if (!conn->ssp_mode && conn->auth_initiator &&
- (conn->pending_sec_level == BT_SECURITY_HIGH))
+ (conn->pending_sec_level == BT_SECURITY_VERY_HIGH))
conn->pending_sec_level = BT_SECURITY_MEDIUM;
if (conn->ssp_mode && conn->auth_initiator &&
conn->io_capability != 0x03) {
- conn->pending_sec_level = BT_SECURITY_HIGH;
+ conn->pending_sec_level = BT_SECURITY_VERY_HIGH;
conn->auth_type = HCI_AT_DEDICATED_BONDING_MITM;
}
}
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 6eab6d0..fd9088a 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -1,6 +1,6 @@
/*
BlueZ - Bluetooth protocol stack for Linux
- Copyright (c) 2000-2001, 2010-2012 The Linux Foundation. All rights reserved.
+ Copyright (c) 2000-2001, 2010-2013 The Linux Foundation. All rights reserved.
Copyright (C) 2009-2010 Gustavo F. Padovan <gustavo@padovan.org>
Copyright (C) 2010 Google Inc.
@@ -610,6 +610,7 @@
{
if (sk->sk_type == SOCK_RAW) {
switch (l2cap_pi(sk)->sec_level) {
+ case BT_SECURITY_VERY_HIGH:
case BT_SECURITY_HIGH:
return HCI_AT_DEDICATED_BONDING_MITM;
case BT_SECURITY_MEDIUM:
@@ -621,12 +622,14 @@
if (l2cap_pi(sk)->sec_level == BT_SECURITY_LOW)
l2cap_pi(sk)->sec_level = BT_SECURITY_SDP;
- if (l2cap_pi(sk)->sec_level == BT_SECURITY_HIGH)
+ if (l2cap_pi(sk)->sec_level == BT_SECURITY_HIGH ||
+ l2cap_pi(sk)->sec_level == BT_SECURITY_VERY_HIGH)
return HCI_AT_NO_BONDING_MITM;
else
return HCI_AT_NO_BONDING;
} else {
switch (l2cap_pi(sk)->sec_level) {
+ case BT_SECURITY_VERY_HIGH:
case BT_SECURITY_HIGH:
return HCI_AT_GENERAL_BONDING_MITM;
case BT_SECURITY_MEDIUM:
@@ -7533,7 +7536,8 @@
if (l2cap_pi(sk)->sec_level == BT_SECURITY_MEDIUM) {
l2cap_sock_clear_timer(sk);
l2cap_sock_set_timer(sk, HZ * 5);
- } else if (l2cap_pi(sk)->sec_level == BT_SECURITY_HIGH)
+ } else if (l2cap_pi(sk)->sec_level == BT_SECURITY_HIGH ||
+ l2cap_pi(sk)->sec_level == BT_SECURITY_VERY_HIGH)
__l2cap_sock_close(sk, ECONNREFUSED);
} else {
if (l2cap_pi(sk)->sec_level == BT_SECURITY_MEDIUM)
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index a1f2955..8658b94 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -383,23 +383,30 @@
err = cmd_status(sk, index, MGMT_OP_SET_POWERED, EBUSY);
goto failed;
}
+ /* Avoid queing power_on/off when the set up is going on via
+ * hci_register_dev
+ */
+ if (!test_bit(HCI_SETUP, &hdev->flags)) {
+ cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, index, data,
+ len);
+ if (!cmd) {
+ err = -ENOMEM;
+ goto failed;
+ }
- cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, index, data, len);
- if (!cmd) {
- err = -ENOMEM;
+ hci_dev_unlock_bh(hdev);
+
+ if (cp->val)
+ queue_work(hdev->workqueue, &hdev->power_on);
+ else
+ queue_work(hdev->workqueue, &hdev->power_off);
+
+ err = 0;
+ hci_dev_put(hdev);
+ } else {
+ err = cmd_status(sk, index, MGMT_OP_SET_POWERED, ENODEV);
goto failed;
}
-
- hci_dev_unlock_bh(hdev);
-
- if (cp->val)
- queue_work(hdev->workqueue, &hdev->power_on);
- else
- queue_work(hdev->workqueue, &hdev->power_off);
-
- err = 0;
- hci_dev_put(hdev);
-
return err;
failed:
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
index dc4bf2f..d1914ea 100644
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -262,6 +262,7 @@
__u8 auth_type;
switch (d->sec_level) {
+ case BT_SECURITY_VERY_HIGH:
case BT_SECURITY_HIGH:
auth_type = HCI_AT_GENERAL_BONDING_MITM;
break;
@@ -2163,7 +2164,8 @@
set_bit(RFCOMM_SEC_PENDING, &d->flags);
rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT);
continue;
- } else if (d->sec_level == BT_SECURITY_HIGH) {
+ } else if (d->sec_level == BT_SECURITY_HIGH ||
+ d->sec_level == BT_SECURITY_VERY_HIGH) {
__rfcomm_dlc_close(d, ECONNREFUSED);
continue;
}
diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
index 66cc1f0..216068f 100644
--- a/net/bluetooth/rfcomm/sock.c
+++ b/net/bluetooth/rfcomm/sock.c
@@ -707,12 +707,13 @@
break;
}
- if (sec.level > BT_SECURITY_HIGH) {
+ if (sec.level > BT_SECURITY_VERY_HIGH) {
err = -EINVAL;
break;
}
rfcomm_pi(sk)->sec_level = sec.level;
+ BT_DBG("set to %d", sec.level);
break;
case BT_DEFER_SETUP:
@@ -763,6 +764,7 @@
opt = RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT;
break;
case BT_SECURITY_HIGH:
+ case BT_SECURITY_VERY_HIGH:
opt = RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT |
RFCOMM_LM_SECURE;
break;
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index 517779f..4a83020 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -213,6 +213,7 @@
static __u8 seclevel_to_authreq(__u8 level)
{
switch (level) {
+ case BT_SECURITY_VERY_HIGH:
case BT_SECURITY_HIGH:
return SMP_AUTH_MITM | SMP_AUTH_BONDING;
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 0f14dc3..a09dab3 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -51,7 +51,7 @@
snd-soc-wcd9304-objs := wcd9304.o wcd9304-tables.o
snd-soc-wcd9310-objs := wcd9310.o wcd9310-tables.o
snd-soc-cs8427-objs := cs8427.o
-snd-soc-wcd9320-objs := wcd9xxx-resmgr.o wcd9320.o wcd9320-tables.o wcd9xxx-mbhc.o
+snd-soc-wcd9320-objs := wcd9xxx-resmgr.o wcd9320.o wcd9320-tables.o wcd9xxx-mbhc.o wcd9xxx-common.o
snd-soc-wcd9306-objs := wcd9306.o wcd9306-tables.o
snd-soc-msm8x10-wcd-objs := msm8x10-wcd.o msm8x10-wcd-tables.o
snd-soc-wl1273-objs := wl1273.o
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index 28be822..f48dbf1 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -36,6 +36,7 @@
#include <linux/gpio.h>
#include "wcd9320.h"
#include "wcd9xxx-resmgr.h"
+#include "wcd9xxx-common.h"
static atomic_t kp_taiko_priv;
static int spkr_drv_wrnd_param_set(const char *val,
@@ -69,6 +70,12 @@
#define TAIKO_SLIM_IRQ_PORT_CLOSED (1 << 2)
#define TAIKO_MCLK_CLK_12P288MHZ 12288000
#define TAIKO_MCLK_CLK_9P6HZ 9600000
+
+#define TAIKO_FORMATS_S16_S24_LE (SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FORMAT_S24_LE)
+
+#define TAIKO_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
+
enum {
AIF1_PB = 0,
AIF1_CAP,
@@ -233,6 +240,10 @@
struct wcd9xxx_resmgr resmgr;
/* mbhc module */
struct wcd9xxx_mbhc mbhc;
+
+ /* class h specific data */
+ struct wcd9xxx_clsh_cdc_data clsh_d;
+
};
static const u32 comp_shift[] = {
@@ -354,73 +365,6 @@
return 0;
}
-static int taiko_codec_enable_class_h_clk(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
-{
- struct snd_soc_codec *codec = w->codec;
-
- pr_debug("%s %s %d\n", __func__, w->name, event);
-
- switch (event) {
- case SND_SOC_DAPM_PRE_PMU:
- snd_soc_update_bits(codec, TAIKO_A_CDC_CLSH_B1_CTL, 0x01, 0x01);
- break;
- case SND_SOC_DAPM_PRE_PMD:
- snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_1, 0x80, 0x00);
- snd_soc_update_bits(codec, TAIKO_A_CDC_CLSH_B1_CTL, 0x01, 0x00);
- break;
- }
- return 0;
-}
-
-static int taiko_codec_enable_class_h(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
-{
- struct snd_soc_codec *codec = w->codec;
-
- pr_debug("%s %s %d\n", __func__, w->name, event);
-
- switch (event) {
- case SND_SOC_DAPM_POST_PMU:
- snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_5, 0x02, 0x02);
- snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_4, 0xFF, 0xFF);
- snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_1, 0x04, 0x04);
- snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_1, 0x04, 0x00);
- snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_3, 0x04, 0x00);
- snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_3, 0x08, 0x00);
- snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_1, 0x80, 0x80);
- usleep_range(1000, 1000);
- break;
- }
- return 0;
-}
-
-static int taiko_codec_enable_charge_pump(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
-{
- struct snd_soc_codec *codec = w->codec;
-
- pr_debug("%s %s %d\n", __func__, w->name, event);
-
- switch (event) {
- case SND_SOC_DAPM_PRE_PMU:
- snd_soc_update_bits(codec, w->reg, 0x01, 0x01);
- snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
- break;
-
- case SND_SOC_DAPM_POST_PMU:
- usleep_range(1000, 1000);
- break;
-
- case SND_SOC_DAPM_PRE_PMD:
- snd_soc_update_bits(codec, w->reg, 0x01, 0x00);
- snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
- break;
- }
- return 0;
-}
-
-
static int taiko_get_anc_slot(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -905,6 +849,17 @@
static const struct soc_enum cf_rxmix7_enum =
SOC_ENUM_SINGLE(TAIKO_A_CDC_RX7_B4_CTL, 1, 3, cf_text);
+static const char * const class_h_dsm_text[] = {
+ "ZERO", "DSM_HPHL_RX1", "DSM_SPKR_RX7"
+};
+
+static const struct soc_enum class_h_dsm_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_CLSH_CTL, 4, 3, class_h_dsm_text);
+
+static const struct snd_kcontrol_new class_h_dsm_mux =
+ SOC_DAPM_ENUM("CLASS_H_DSM MUX Mux", class_h_dsm_enum);
+
+
static const struct snd_kcontrol_new taiko_snd_controls[] = {
SOC_ENUM_EXT("EAR PA Gain", taiko_ear_pa_gain_enum[0],
@@ -1842,11 +1797,12 @@
if (enable) {
taiko->adc_count++;
- snd_soc_update_bits(codec, TAIKO_A_CDC_CLK_OTHR_CTL, 0x2, 0x2);
+ snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLK_OTHR_CTL,
+ 0x2, 0x2);
} else {
taiko->adc_count--;
if (!taiko->adc_count)
- snd_soc_update_bits(codec, TAIKO_A_CDC_CLK_OTHR_CTL,
+ snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLK_OTHR_CTL,
0x2, 0x0);
}
}
@@ -1934,6 +1890,7 @@
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = w->codec;
+ struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
u16 lineout_gain_reg;
pr_debug("%s %d %s\n", __func__, event, w->name);
@@ -1962,11 +1919,19 @@
snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x40);
break;
case SND_SOC_DAPM_POST_PMU:
- pr_debug("%s: sleeping 16 ms after %s PA turn on\n",
+ wcd9xxx_clsh_fsm(codec, &taiko->clsh_d,
+ WCD9XXX_CLSH_STATE_LO,
+ WCD9XXX_CLSH_REQ_ENABLE,
+ WCD9XXX_CLSH_EVENT_POST_PA);
+ pr_debug("%s: sleeping 3 ms after %s PA turn on\n",
__func__, w->name);
- usleep_range(16000, 16000);
+ usleep_range(3000, 3000);
break;
case SND_SOC_DAPM_POST_PMD:
+ wcd9xxx_clsh_fsm(codec, &taiko->clsh_d,
+ WCD9XXX_CLSH_STATE_LO,
+ WCD9XXX_CLSH_REQ_DISABLE,
+ WCD9XXX_CLSH_EVENT_POST_PA);
snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x00);
break;
}
@@ -2169,45 +2134,44 @@
{
struct snd_soc_codec *codec = w->codec;
struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
- u16 micb_int_reg;
+ u16 micb_int_reg = 0, micb_ctl_reg = 0;
u8 cfilt_sel_val = 0;
char *internal1_text = "Internal1";
char *internal2_text = "Internal2";
char *internal3_text = "Internal3";
enum wcd9xxx_notify_event e_post_off, e_pre_on, e_post_on;
- pr_debug("%s %d\n", __func__, event);
- switch (w->reg) {
- case TAIKO_A_MICB_1_CTL:
+ pr_debug("%s: w->name %s event %d\n", __func__, w->name, event);
+ if (strnstr(w->name, "MIC BIAS1", sizeof("MIC BIAS1"))) {
+ micb_ctl_reg = TAIKO_A_MICB_1_CTL;
micb_int_reg = TAIKO_A_MICB_1_INT_RBIAS;
cfilt_sel_val = taiko->resmgr.pdata->micbias.bias1_cfilt_sel;
e_pre_on = WCD9XXX_EVENT_PRE_MICBIAS_1_ON;
e_post_on = WCD9XXX_EVENT_POST_MICBIAS_1_ON;
e_post_off = WCD9XXX_EVENT_POST_MICBIAS_1_OFF;
- break;
- case TAIKO_A_MICB_2_CTL:
+ } else if (strnstr(w->name, "MIC BIAS2", sizeof("MIC BIAS2"))) {
+ micb_ctl_reg = TAIKO_A_MICB_2_CTL;
micb_int_reg = TAIKO_A_MICB_2_INT_RBIAS;
cfilt_sel_val = taiko->resmgr.pdata->micbias.bias2_cfilt_sel;
e_pre_on = WCD9XXX_EVENT_PRE_MICBIAS_2_ON;
e_post_on = WCD9XXX_EVENT_POST_MICBIAS_2_ON;
e_post_off = WCD9XXX_EVENT_POST_MICBIAS_2_OFF;
- break;
- case TAIKO_A_MICB_3_CTL:
+ } else if (strnstr(w->name, "MIC BIAS3", sizeof("MIC BIAS3"))) {
+ micb_ctl_reg = TAIKO_A_MICB_2_CTL;
micb_int_reg = TAIKO_A_MICB_3_INT_RBIAS;
cfilt_sel_val = taiko->resmgr.pdata->micbias.bias3_cfilt_sel;
e_pre_on = WCD9XXX_EVENT_PRE_MICBIAS_3_ON;
e_post_on = WCD9XXX_EVENT_POST_MICBIAS_3_ON;
e_post_off = WCD9XXX_EVENT_POST_MICBIAS_3_OFF;
- break;
- case TAIKO_A_MICB_4_CTL:
+ } else if (strnstr(w->name, "MIC BIAS4", sizeof("MIC BIAS4"))) {
+ micb_ctl_reg = TAIKO_A_MICB_2_CTL;
micb_int_reg = taiko->resmgr.reg_addr->micb_4_int_rbias;
cfilt_sel_val = taiko->resmgr.pdata->micbias.bias4_cfilt_sel;
e_pre_on = WCD9XXX_EVENT_PRE_MICBIAS_4_ON;
e_post_on = WCD9XXX_EVENT_POST_MICBIAS_4_ON;
e_post_off = WCD9XXX_EVENT_POST_MICBIAS_4_OFF;
- break;
- default:
- pr_err("%s: Error, invalid micbias register\n", __func__);
+ } else {
+ pr_err("%s: Error, invalid micbias %s\n", __func__, w->name);
return -EINVAL;
}
@@ -2226,6 +2190,16 @@
else if (strnstr(w->name, internal3_text, 30))
snd_soc_update_bits(codec, micb_int_reg, 0x3, 0x3);
+ if (micb_ctl_reg == TAIKO_A_MICB_2_CTL) {
+ WCD9XXX_BCL_LOCK(&taiko->resmgr);
+ wcd9xxx_resmgr_add_cond_update_bits(&taiko->resmgr,
+ WCD9XXX_COND_HPH_MIC,
+ micb_ctl_reg, w->shift,
+ false);
+ WCD9XXX_BCL_UNLOCK(&taiko->resmgr);
+ } else
+ snd_soc_update_bits(codec, micb_ctl_reg, 1 << w->shift,
+ 1 << w->shift);
break;
case SND_SOC_DAPM_POST_PMU:
usleep_range(20000, 20000);
@@ -2233,6 +2207,16 @@
wcd9xxx_resmgr_notifier_call(&taiko->resmgr, e_post_on);
break;
case SND_SOC_DAPM_POST_PMD:
+ if (micb_ctl_reg == TAIKO_A_MICB_2_CTL) {
+ WCD9XXX_BCL_LOCK(&taiko->resmgr);
+ wcd9xxx_resmgr_rm_cond_update_bits(&taiko->resmgr,
+ WCD9XXX_COND_HPH_MIC,
+ micb_ctl_reg, 7, false);
+ WCD9XXX_BCL_UNLOCK(&taiko->resmgr);
+ } else
+ snd_soc_update_bits(codec, micb_ctl_reg, 1 << w->shift,
+ 0);
+
/* Let MBHC module know so micbias switch to be off */
wcd9xxx_resmgr_notifier_call(&taiko->resmgr, e_post_off);
@@ -2496,18 +2480,52 @@
}
return 0;
}
-static int taiko_hphr_dac_event(struct snd_soc_dapm_widget *w,
+
+static int taiko_hphl_dac_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = w->codec;
+ struct taiko_priv *taiko_p = snd_soc_codec_get_drvdata(codec);
pr_debug("%s %s %d\n", __func__, w->name, event);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
- snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
+ snd_soc_update_bits(codec, TAIKO_A_CDC_CLK_RDAC_CLK_EN_CTL,
+ 0x02, 0x02);
+ wcd9xxx_clsh_fsm(codec, &taiko_p->clsh_d,
+ WCD9XXX_CLSH_STATE_HPHL,
+ WCD9XXX_CLSH_REQ_ENABLE,
+ WCD9XXX_CLSH_EVENT_PRE_DAC);
break;
case SND_SOC_DAPM_POST_PMD:
+ snd_soc_update_bits(codec, TAIKO_A_CDC_CLK_RDAC_CLK_EN_CTL,
+ 0x02, 0x00);
+ }
+ return 0;
+}
+
+static int taiko_hphr_dac_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ struct taiko_priv *taiko_p = snd_soc_codec_get_drvdata(codec);
+
+ pr_debug("%s %s %d\n", __func__, w->name, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ snd_soc_update_bits(codec, TAIKO_A_CDC_CLK_RDAC_CLK_EN_CTL,
+ 0x04, 0x04);
+ snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
+ wcd9xxx_clsh_fsm(codec, &taiko_p->clsh_d,
+ WCD9XXX_CLSH_STATE_HPHR,
+ WCD9XXX_CLSH_REQ_ENABLE,
+ WCD9XXX_CLSH_EVENT_PRE_DAC);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_update_bits(codec, TAIKO_A_CDC_CLK_RDAC_CLK_EN_CTL,
+ 0x04, 0x00);
snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
break;
}
@@ -2520,14 +2538,17 @@
struct snd_soc_codec *codec = w->codec;
struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
enum wcd9xxx_notify_event e_pre_on, e_post_off;
+ u8 req_clsh_state;
pr_debug("%s: %s event = %d\n", __func__, w->name, event);
if (w->shift == 5) {
e_pre_on = WCD9XXX_EVENT_PRE_HPHR_PA_ON;
e_post_off = WCD9XXX_EVENT_POST_HPHR_PA_OFF;
+ req_clsh_state = WCD9XXX_CLSH_STATE_HPHL;
} else if (w->shift == 4) {
e_pre_on = WCD9XXX_EVENT_PRE_HPHL_PA_ON;
e_post_off = WCD9XXX_EVENT_POST_HPHL_PA_OFF;
+ req_clsh_state = WCD9XXX_CLSH_STATE_HPHR;
} else {
pr_err("%s: Invalid w->shift %d\n", __func__, w->shift);
return -EINVAL;
@@ -2540,29 +2561,27 @@
break;
case SND_SOC_DAPM_POST_PMU:
- usleep_range(10000, 10000);
+ wcd9xxx_clsh_fsm(codec, &taiko->clsh_d,
+ req_clsh_state,
+ WCD9XXX_CLSH_REQ_ENABLE,
+ WCD9XXX_CLSH_EVENT_POST_PA);
- snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_5, 0x02, 0x00);
- snd_soc_update_bits(codec, TAIKO_A_NCP_STATIC, 0x20, 0x00);
- snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_3, 0x04, 0x04);
- snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_3, 0x08, 0x00);
- usleep_range(10, 10);
+ usleep_range(5000, 5000);
break;
case SND_SOC_DAPM_POST_PMD:
/* Let MBHC module know PA turned off */
wcd9xxx_resmgr_notifier_call(&taiko->resmgr, e_post_off);
- /*
- * schedule work is required because at the time HPH PA DAPM
- * event callback is called by DAPM framework, CODEC dapm mutex
- * would have been locked while snd_soc_jack_report also
- * attempts to acquire same lock.
- */
+ wcd9xxx_clsh_fsm(codec, &taiko->clsh_d,
+ req_clsh_state,
+ WCD9XXX_CLSH_REQ_DISABLE,
+ WCD9XXX_CLSH_EVENT_POST_PA);
+
pr_debug("%s: sleep 10 ms after %s PA disable.\n", __func__,
w->name);
- usleep_range(10000, 10000);
+ usleep_range(5000, 5000);
break;
}
return 0;
@@ -2579,11 +2598,16 @@
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = w->codec;
+ struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
pr_debug("%s %s %d\n", __func__, w->name, event);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
+ wcd9xxx_clsh_fsm(codec, &taiko->clsh_d,
+ WCD9XXX_CLSH_STATE_LO,
+ WCD9XXX_CLSH_REQ_ENABLE,
+ WCD9XXX_CLSH_EVENT_PRE_DAC);
snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
break;
@@ -2738,15 +2762,11 @@
{"SLIM TX10 MUX", "DEC9", "DEC9 MUX"},
{"SLIM TX10 MUX", "DEC10", "DEC10 MUX"},
- /* Change Pump */
- {"CP", NULL, "CLASS_H_CLK"},
-
/* Earpiece (RX MIX1) */
{"EAR", NULL, "EAR PA"},
{"EAR PA", NULL, "EAR_PA_MIXER"},
{"EAR_PA_MIXER", NULL, "DAC1"},
- {"DAC1", NULL, "CLASS_H_EAR"},
- {"CLASS_H_EAR", NULL, "CP"},
+ {"DAC1", NULL, "RX_BIAS"},
{"ANC1 FB MUX", "EAR_HPH_L", "RX1 MIX2"},
{"ANC1 FB MUX", "EAR_LINE_1", "RX2 MIX2"},
@@ -2758,15 +2778,11 @@
{"HPHL", NULL, "HPHL_PA_MIXER"},
{"HPHL_PA_MIXER", NULL, "HPHL DAC"},
+ {"HPHL DAC", NULL, "RX_BIAS"},
{"HPHR", NULL, "HPHR_PA_MIXER"},
{"HPHR_PA_MIXER", NULL, "HPHR DAC"},
-
- {"HPHL DAC", NULL, "CLASS_H_HPH_L"},
- {"CLASS_H_HPH_L", NULL, "CP"},
-
- {"HPHR DAC", NULL, "CLASS_H_HPH_R"},
- {"CLASS_H_HPH_R", NULL, "CP"},
+ {"HPHR DAC", NULL, "RX_BIAS"},
{"ANC", NULL, "ANC1 MUX"},
{"ANC", NULL, "ANC2 MUX"},
@@ -2781,8 +2797,8 @@
{"ANC", NULL, "CDC_CONN"},
- {"DAC1", "Switch", "RX1 CHAIN"},
- {"HPHL DAC", "Switch", "RX1 CHAIN"},
+ {"DAC1", "Switch", "CLASS_H_DSM MUX"},
+ {"HPHL DAC", "Switch", "CLASS_H_DSM MUX"},
{"HPHR DAC", NULL, "RX2 CHAIN"},
{"LINEOUT1", NULL, "LINEOUT1 PA"},
@@ -2791,30 +2807,20 @@
{"LINEOUT4", NULL, "LINEOUT4 PA"},
{"SPK_OUT", NULL, "SPK PA"},
- {"LINEOUT1 PA", NULL, "CP"},
{"LINEOUT1 PA", NULL, "LINEOUT1_PA_MIXER"},
{"LINEOUT1_PA_MIXER", NULL, "LINEOUT1 DAC"},
- {"LINEOUT2 PA", NULL, "CP"},
{"LINEOUT2 PA", NULL, "LINEOUT2_PA_MIXER"},
{"LINEOUT2_PA_MIXER", NULL, "LINEOUT2 DAC"},
- {"LINEOUT3 PA", NULL, "CP"},
{"LINEOUT3 PA", NULL, "LINEOUT3_PA_MIXER"},
{"LINEOUT3_PA_MIXER", NULL, "LINEOUT3 DAC"},
- {"LINEOUT4 PA", NULL, "CP"},
{"LINEOUT4 PA", NULL, "LINEOUT4_PA_MIXER"},
{"LINEOUT4_PA_MIXER", NULL, "LINEOUT4 DAC"},
- {"CP", NULL, "CLASS_H_LINEOUTS_PA"},
- {"CLASS_H_LINEOUTS_PA", NULL, "CLASS_H_CLK"},
-
-
-
{"LINEOUT1 DAC", NULL, "RX3 MIX1"},
-
{"RDAC5 MUX", "DEM3_INV", "RX3 MIX1"},
{"RDAC5 MUX", "DEM4", "RX4 MIX1"},
@@ -2831,12 +2837,13 @@
{"SPK DAC", NULL, "RX7 MIX2"},
{"SPK DAC", NULL, "VDD_SPKDRV"},
+ {"CLASS_H_DSM MUX", "DSM_HPHL_RX1", "RX1 CHAIN"},
+
{"RX1 CHAIN", NULL, "RX1 MIX2"},
{"RX2 CHAIN", NULL, "RX2 MIX2"},
{"RX1 CHAIN", NULL, "ANC"},
{"RX2 CHAIN", NULL, "ANC"},
- {"CLASS_H_CLK", NULL, "RX_BIAS"},
{"LINEOUT1 DAC", NULL, "RX_BIAS"},
{"LINEOUT2 DAC", NULL, "RX_BIAS"},
{"LINEOUT3 DAC", NULL, "RX_BIAS"},
@@ -3194,7 +3201,6 @@
return 0;
}
-#define TAIKO_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
static int taiko_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int value)
{
@@ -3671,6 +3677,29 @@
snd_soc_update_bits(codec, TAIKO_A_CDC_CLK_RX_I2S_CTL,
0x03, (rx_fs_rate >> 0x05));
} else {
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ snd_soc_update_bits(codec,
+ TAIKO_A_CDC_CONN_RX_SB_B1_CTL,
+ 0xFF, 0xAA);
+ snd_soc_update_bits(codec,
+ TAIKO_A_CDC_CONN_RX_SB_B2_CTL,
+ 0xFF, 0x2A);
+ taiko->dai[dai->id].bit_width = 16;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ snd_soc_update_bits(codec,
+ TAIKO_A_CDC_CONN_RX_SB_B1_CTL,
+ 0xFF, 0x00);
+ snd_soc_update_bits(codec,
+ TAIKO_A_CDC_CONN_RX_SB_B2_CTL,
+ 0xFF, 0x00);
+ taiko->dai[dai->id].bit_width = 24;
+ break;
+ default:
+ dev_err(codec->dev, "Invalid format\n");
+ break;
+ }
taiko->dai[dai->id].rate = params_rate(params);
}
break;
@@ -3700,7 +3729,7 @@
.playback = {
.stream_name = "AIF1 Playback",
.rates = WCD9320_RATES,
- .formats = TAIKO_FORMATS,
+ .formats = TAIKO_FORMATS_S16_S24_LE,
.rate_max = 192000,
.rate_min = 8000,
.channels_min = 1,
@@ -3728,7 +3757,7 @@
.playback = {
.stream_name = "AIF2 Playback",
.rates = WCD9320_RATES,
- .formats = TAIKO_FORMATS,
+ .formats = TAIKO_FORMATS_S16_S24_LE,
.rate_min = 8000,
.rate_max = 192000,
.channels_min = 1,
@@ -3770,7 +3799,7 @@
.playback = {
.stream_name = "AIF3 Playback",
.rates = WCD9320_RATES,
- .formats = TAIKO_FORMATS,
+ .formats = TAIKO_FORMATS_S16_S24_LE,
.rate_min = 8000,
.rate_max = 192000,
.channels_min = 1,
@@ -3967,24 +3996,81 @@
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = w->codec;
+ struct taiko_priv *taiko_p = snd_soc_codec_get_drvdata(codec);
pr_debug("%s %s %d\n", __func__, w->name, event);
switch (event) {
- break;
case SND_SOC_DAPM_POST_PMU:
-
- snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_5, 0x02, 0x00);
- snd_soc_update_bits(codec, TAIKO_A_NCP_STATIC, 0x20, 0x00);
- snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_3, 0x04, 0x04);
- snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_3, 0x08, 0x00);
+ wcd9xxx_clsh_fsm(codec, &taiko_p->clsh_d,
+ WCD9XXX_CLSH_STATE_EAR,
+ WCD9XXX_CLSH_REQ_ENABLE,
+ WCD9XXX_CLSH_EVENT_POST_PA);
usleep_range(5000, 5000);
break;
+ case SND_SOC_DAPM_POST_PMD:
+ wcd9xxx_clsh_fsm(codec, &taiko_p->clsh_d,
+ WCD9XXX_CLSH_STATE_EAR,
+ WCD9XXX_CLSH_REQ_DISABLE,
+ WCD9XXX_CLSH_EVENT_POST_PA);
+ usleep_range(5000, 5000);
+ }
+ return 0;
+}
+
+static int taiko_codec_ear_dac_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ struct taiko_priv *taiko_p = snd_soc_codec_get_drvdata(codec);
+
+ pr_debug("%s %s %d\n", __func__, w->name, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ wcd9xxx_clsh_fsm(codec, &taiko_p->clsh_d,
+ WCD9XXX_CLSH_STATE_EAR,
+ WCD9XXX_CLSH_REQ_ENABLE,
+ WCD9XXX_CLSH_EVENT_PRE_DAC);
+ break;
+ }
+
+ return 0;
+}
+
+static int taiko_codec_dsm_mux_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ u8 reg_val, zoh_mux_val = 0x00;
+
+ pr_debug("%s: event = %d\n", __func__, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ reg_val = snd_soc_read(codec, TAIKO_A_CDC_CONN_CLSH_CTL);
+
+ if ((reg_val & 0x30) == 0x10)
+ zoh_mux_val = 0x04;
+ else if ((reg_val & 0x30) == 0x20)
+ zoh_mux_val = 0x08;
+
+ if (zoh_mux_val != 0x00)
+ snd_soc_update_bits(codec,
+ TAIKO_A_CDC_CONN_CLSH_CTL,
+ 0x0C, zoh_mux_val);
+ break;
+
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_update_bits(codec, TAIKO_A_CDC_CONN_CLSH_CTL,
+ 0x0C, 0x00);
+ break;
}
return 0;
}
+
/* Todo: Have seperate dapm widgets for I2S and Slimbus.
* Might Need to have callbacks registered only for slimbus
*/
@@ -3993,10 +4079,12 @@
SND_SOC_DAPM_OUTPUT("EAR"),
SND_SOC_DAPM_PGA_E("EAR PA", TAIKO_A_RX_EAR_EN, 4, 0, NULL, 0,
- taiko_codec_enable_ear_pa, SND_SOC_DAPM_POST_PMU),
+ taiko_codec_enable_ear_pa, SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_MIXER("DAC1", TAIKO_A_RX_EAR_EN, 6, 0, dac1_switch,
- ARRAY_SIZE(dac1_switch)),
+ SND_SOC_DAPM_MIXER_E("DAC1", TAIKO_A_RX_EAR_EN, 6, 0, dac1_switch,
+ ARRAY_SIZE(dac1_switch), taiko_codec_ear_dac_event,
+ SND_SOC_DAPM_PRE_PMU),
SND_SOC_DAPM_AIF_IN_E("AIF1 PB", "AIF1 Playback", 0, SND_SOC_NOPM,
AIF1_PB, 0, taiko_codec_enable_slimrx,
@@ -4036,8 +4124,9 @@
SND_SOC_DAPM_PGA_E("HPHL", TAIKO_A_RX_HPH_CNP_EN, 5, 0, NULL, 0,
taiko_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_MIXER("HPHL DAC", TAIKO_A_RX_HPH_L_DAC_CTL, 7, 0,
- hphl_switch, ARRAY_SIZE(hphl_switch)),
+ SND_SOC_DAPM_MIXER_E("HPHL DAC", TAIKO_A_RX_HPH_L_DAC_CTL, 7, 0,
+ hphl_switch, ARRAY_SIZE(hphl_switch), taiko_hphl_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_PGA_E("HPHR", TAIKO_A_RX_HPH_CNP_EN, 4, 0, NULL, 0,
taiko_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
@@ -4173,36 +4262,20 @@
SND_SOC_DAPM_MUX("RDAC7 MUX", SND_SOC_NOPM, 0, 0,
&rx_dac7_mux),
- SND_SOC_DAPM_SUPPLY("CLASS_H_CLK", TAIKO_A_CDC_CLK_OTHR_CTL, 0, 0,
- taiko_codec_enable_class_h_clk, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_PRE_PMD),
-
- SND_SOC_DAPM_SUPPLY("CLASS_H_EAR", TAIKO_A_CDC_CLSH_B1_CTL, 4, 0,
- taiko_codec_enable_class_h, SND_SOC_DAPM_POST_PMU),
-
- SND_SOC_DAPM_SUPPLY("CLASS_H_HPH_L", TAIKO_A_CDC_CLSH_B1_CTL, 3, 0,
- taiko_codec_enable_class_h, SND_SOC_DAPM_POST_PMU),
-
- SND_SOC_DAPM_SUPPLY("CLASS_H_HPH_R", TAIKO_A_CDC_CLSH_B1_CTL, 2, 0,
- taiko_codec_enable_class_h, SND_SOC_DAPM_POST_PMU),
-
- SND_SOC_DAPM_SUPPLY("CLASS_H_LINEOUTS_PA", SND_SOC_NOPM, 0, 0,
- taiko_codec_enable_class_h, SND_SOC_DAPM_POST_PMU),
-
- SND_SOC_DAPM_SUPPLY("CP", TAIKO_A_NCP_EN, 0, 0,
- taiko_codec_enable_charge_pump, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_MUX_E("CLASS_H_DSM MUX", SND_SOC_NOPM, 0, 0,
+ &class_h_dsm_mux, taiko_codec_dsm_mux_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_SUPPLY("RX_BIAS", SND_SOC_NOPM, 0, 0,
taiko_codec_enable_rx_bias, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_SUPPLY("CDC_I2S_RX_CONN", TAIKO_A_CDC_CLK_OTHR_CTL, 5, 0,
+ SND_SOC_DAPM_SUPPLY("CDC_I2S_RX_CONN", WCD9XXX_A_CDC_CLK_OTHR_CTL, 5, 0,
NULL, 0),
/* TX */
- SND_SOC_DAPM_SUPPLY("CDC_CONN", TAIKO_A_CDC_CLK_OTHR_CTL, 2, 0, NULL,
+ SND_SOC_DAPM_SUPPLY("CDC_CONN", WCD9XXX_A_CDC_CLK_OTHR_CTL, 2, 0, NULL,
0),
SND_SOC_DAPM_SUPPLY("LDO_H", TAIKO_A_LDO_H_MODE_1, 7, 0,
@@ -4220,15 +4293,18 @@
SND_SOC_DAPM_INPUT("AMIC1"),
- SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 External", TAIKO_A_MICB_1_CTL, 7, 0,
- taiko_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal1", TAIKO_A_MICB_1_CTL, 7, 0,
- taiko_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal2", TAIKO_A_MICB_1_CTL, 7, 0,
- taiko_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 External", SND_SOC_NOPM, 7, 0,
+ taiko_codec_enable_micbias,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal1", SND_SOC_NOPM, 7, 0,
+ taiko_codec_enable_micbias,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal2", SND_SOC_NOPM, 7, 0,
+ taiko_codec_enable_micbias,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_ADC_E("ADC1", NULL, TAIKO_A_TX_1_2_EN, 7, 0,
taiko_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
@@ -4311,31 +4387,38 @@
SND_SOC_DAPM_MUX("ANC1 FB MUX", SND_SOC_NOPM, 0, 0, &anc1_fb_mux),
SND_SOC_DAPM_INPUT("AMIC2"),
- SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 External", TAIKO_A_MICB_2_CTL, 7, 0,
- taiko_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal1", TAIKO_A_MICB_2_CTL, 7, 0,
- taiko_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal2", TAIKO_A_MICB_2_CTL, 7, 0,
- taiko_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal3", TAIKO_A_MICB_2_CTL, 7, 0,
- taiko_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 External", TAIKO_A_MICB_3_CTL, 7, 0,
- taiko_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal1", TAIKO_A_MICB_3_CTL, 7, 0,
- taiko_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal2", TAIKO_A_MICB_3_CTL, 7, 0,
- taiko_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_MICBIAS_E("MIC BIAS4 External", TAIKO_A_MICB_4_CTL, 7,
- 0, taiko_codec_enable_micbias,
- SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
- SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 External", SND_SOC_NOPM, 7, 0,
+ taiko_codec_enable_micbias,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal1", SND_SOC_NOPM, 7, 0,
+ taiko_codec_enable_micbias,
+ SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal2", SND_SOC_NOPM, 7, 0,
+ taiko_codec_enable_micbias,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal3", SND_SOC_NOPM, 7, 0,
+ taiko_codec_enable_micbias,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 External", SND_SOC_NOPM, 7, 0,
+ taiko_codec_enable_micbias,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal1", SND_SOC_NOPM, 7, 0,
+ taiko_codec_enable_micbias,
+ SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal2", SND_SOC_NOPM, 7, 0,
+ taiko_codec_enable_micbias,
+ SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS4 External", SND_SOC_NOPM, 7,
+ 0, taiko_codec_enable_micbias,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_ADC_E("ADC2", NULL, TAIKO_A_TX_1_2_EN, 3, 0,
taiko_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
@@ -4511,84 +4594,6 @@
return IRQ_HANDLED;
}
-static const struct taiko_reg_mask_val taiko_1_0_class_h_ear[] = {
-
- /* CLASS-H EAR IDLE_THRESHOLD Table */
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_IDLE_EAR_THSD, 0x26),
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_FCLKONLY_EAR_THSD, 0x2C),
-
- /* CLASS-H EAR I_PA_FACT Table. */
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_I_PA_FACT_EAR_L, 0xA9),
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_I_PA_FACT_EAR_U, 0x07),
-
- /* CLASS-H EAR Voltage Headroom , Voltage Min. */
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_V_PA_HD_EAR, 0x0D),
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_V_PA_MIN_EAR, 0x3A),
-
- /* CLASS-H EAR K values --chnages from load. */
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_ADDR, 0x08),
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x1B),
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x00),
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x2D),
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x00),
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x36),
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x00),
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x37),
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x00),
- /** end of Ear PA load 32 */
-};
-
-static const struct taiko_reg_mask_val taiko_1_0_class_h_hph[] = {
-
- /* CLASS-H HPH IDLE_THRESHOLD Table */
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_IDLE_HPH_THSD, 0x13),
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0x19),
-
- /* CLASS-H HPH I_PA_FACT Table */
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_I_PA_FACT_HPH_L, 0x9A),
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_I_PA_FACT_HPH_U, 0x06),
-
- /* CLASS-H HPH Voltage Headroom , Voltage Min */
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_V_PA_HD_HPH, 0x0D),
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_V_PA_MIN_HPH, 0x1D),
-
- /* CLASS-H HPH K values --chnages from load .*/
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_ADDR, 0x00),
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0xAE),
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x01),
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x1C),
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x00),
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x25),
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x00),
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x27),
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x00),
-};
-
-static int taiko_config_ear_class_h(struct snd_soc_codec *codec, u32 ear_load)
-{
- u32 i;
-
- if (ear_load != 32)
- return -EINVAL;
-
- for (i = 0; i < ARRAY_SIZE(taiko_1_0_class_h_ear); i++)
- snd_soc_write(codec, taiko_1_0_class_h_ear[i].reg,
- taiko_1_0_class_h_ear[i].val);
- return 0;
-}
-
-static int taiko_config_hph_class_h(struct snd_soc_codec *codec, u32 hph_load)
-{
- u32 i;
- if (hph_load != 16)
- return -EINVAL;
-
- for (i = 0; i < ARRAY_SIZE(taiko_1_0_class_h_hph); i++)
- snd_soc_write(codec, taiko_1_0_class_h_hph[i].reg,
- taiko_1_0_class_h_hph[i].val);
- return 0;
-}
-
static int taiko_handle_pdata(struct taiko_priv *taiko)
{
struct snd_soc_codec *codec = taiko->codec;
@@ -4727,14 +4732,11 @@
0x00 : 0x16);
snd_soc_update_bits(codec, TAIKO_A_MICB_4_CTL, 0x1E, value);
- taiko_config_ear_class_h(codec, 32);
- taiko_config_hph_class_h(codec, 16);
-
done:
return rc;
}
-static const struct taiko_reg_mask_val taiko_reg_defaults[] = {
+static const struct wcd9xxx_reg_mask_val taiko_reg_defaults[] = {
/* set MCLk to 9.6 */
TAIKO_REG_VAL(TAIKO_A_CHIP_CTL, 0x02),
@@ -4743,24 +4745,6 @@
/* EAR PA deafults */
TAIKO_REG_VAL(TAIKO_A_RX_EAR_CMBUFF, 0x05),
- /* BUCK and NCP defaults for EAR and HS */
- TAIKO_REG_VAL(TAIKO_A_BUCK_CTRL_CCL_1, 0x5B),
-
- /* CLASS-H defaults for EAR and HS */
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_BUCK_NCP_VARS, 0x00),
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_BUCK_NCP_VARS, 0x04),
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_B2_CTL, 0x01),
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_B2_CTL, 0x05),
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_B2_CTL, 0x35),
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_B3_CTL, 0x30),
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_B3_CTL, 0x3B),
-
- /*
- * For CLASS-H, Enable ANC delay buffer,
- * set HPHL and EAR PA ref gain to 0 DB.
- */
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_B1_CTL, 0x26),
-
/* RX deafults */
TAIKO_REG_VAL(TAIKO_A_CDC_RX1_B5_CTL, 0x78),
TAIKO_REG_VAL(TAIKO_A_CDC_RX2_B5_CTL, 0x78),
@@ -4782,25 +4766,31 @@
TAIKO_REG_VAL(TAIKO_A_CDC_RX7_B6_CTL, 0x80),
};
-static const struct taiko_reg_mask_val taiko_1_0_reg_defaults[] = {
+static const struct wcd9xxx_reg_mask_val taiko_1_0_reg_defaults[] = {
/*
* The following only need to be written for Taiko 1.0 parts.
* Taiko 2.0 will have appropriate defaults for these registers.
*/
/* BUCK default */
- TAIKO_REG_VAL(TAIKO_A_BUCK_CTRL_CCL_4, 0x50),
+ TAIKO_REG_VAL(WCD9XXX_A_BUCK_CTRL_CCL_4, 0x50),
+
+ /* Required defaults for class H operation */
+ TAIKO_REG_VAL(TAIKO_A_RX_HPH_CHOP_CTL, 0xF4),
+ TAIKO_REG_VAL(TAIKO_A_BIAS_CURR_CTL_2, 0x08),
+ TAIKO_REG_VAL(WCD9XXX_A_BUCK_CTRL_CCL_1, 0x5B),
+ TAIKO_REG_VAL(WCD9XXX_A_BUCK_CTRL_CCL_3, 0x60),
/* Choose max non-overlap time for NCP */
TAIKO_REG_VAL(TAIKO_A_NCP_CLK, 0xFC),
/* Use 25mV/50mV for deltap/m to reduce ripple */
- TAIKO_REG_VAL(TAIKO_A_BUCK_CTRL_VCL_1, 0x08),
+ TAIKO_REG_VAL(WCD9XXX_A_BUCK_CTRL_VCL_1, 0x08),
/*
* Set DISABLE_MODE_SEL<1:0> to 0b10 (disable PWM in auto mode).
* Note that the other bits of this register will be changed during
* Rx PA bring up.
*/
- TAIKO_REG_VAL(TAIKO_A_BUCK_MODE_3, 0xCE),
+ TAIKO_REG_VAL(WCD9XXX_A_BUCK_MODE_3, 0xCE),
/* Reduce HPH DAC bias to 70% */
TAIKO_REG_VAL(TAIKO_A_RX_HPH_BIAS_PA, 0x7A),
/*Reduce EAR DAC bias to 70% */
@@ -4829,7 +4819,7 @@
* Don't update TAIKO_A_CHIP_CTL, TAIKO_A_BUCK_CTRL_CCL_1 and
* TAIKO_A_RX_EAR_CMBUFF as those are updated in taiko_reg_defaults
*/
-static const struct taiko_reg_mask_val taiko_2_0_reg_defaults[] = {
+static const struct wcd9xxx_reg_mask_val taiko_2_0_reg_defaults[] = {
TAIKO_REG_VAL(TAIKO_A_CDC_TX_1_GAIN, 0x2),
TAIKO_REG_VAL(TAIKO_A_CDC_TX_2_GAIN, 0x2),
TAIKO_REG_VAL(TAIKO_A_CDC_TX_1_2_ADC_IB, 0x44),
@@ -4839,9 +4829,9 @@
TAIKO_REG_VAL(TAIKO_A_CDC_TX_5_GAIN, 0x2),
TAIKO_REG_VAL(TAIKO_A_CDC_TX_6_GAIN, 0x2),
TAIKO_REG_VAL(TAIKO_A_CDC_TX_5_6_ADC_IB, 0x44),
- TAIKO_REG_VAL(TAIKO_A_BUCK_MODE_3, 0xCE),
- TAIKO_REG_VAL(TAIKO_A_BUCK_CTRL_VCL_1, 0x8),
- TAIKO_REG_VAL(TAIKO_A_BUCK_CTRL_CCL_4, 0x51),
+ TAIKO_REG_VAL(WCD9XXX_A_BUCK_MODE_3, 0xCE),
+ TAIKO_REG_VAL(WCD9XXX_A_BUCK_CTRL_VCL_1, 0x8),
+ TAIKO_REG_VAL(WCD9XXX_A_BUCK_CTRL_CCL_4, 0x51),
TAIKO_REG_VAL(TAIKO_A_NCP_DTEST, 0x10),
TAIKO_REG_VAL(TAIKO_A_RX_HPH_CHOP_CTL, 0xA4),
TAIKO_REG_VAL(TAIKO_A_RX_HPH_BIAS_PA, 0x7A),
@@ -4902,7 +4892,7 @@
}
}
-static const struct taiko_reg_mask_val taiko_codec_reg_init_val[] = {
+static const struct wcd9xxx_reg_mask_val taiko_codec_reg_init_val[] = {
/* Initialize current threshold to 350MA
* number of wait and run cycles to 4096
*/
@@ -4920,9 +4910,6 @@
{TAIKO_A_RX_LINE_4_GAIN, 0x20, 0x20},
{TAIKO_A_SPKR_DRV_GAIN, 0x04, 0x04},
- /* CLASS H config */
- {TAIKO_A_CDC_CONN_CLSH_CTL, 0x3C, 0x14},
-
/* Use 16 bit sample size for TX1 to TX6 */
{TAIKO_A_CDC_CONN_TX_SB_B1_CTL, 0x30, 0x20},
{TAIKO_A_CDC_CONN_TX_SB_B2_CTL, 0x30, 0x20},
@@ -4937,10 +4924,6 @@
{TAIKO_A_CDC_CONN_TX_SB_B9_CTL, 0x60, 0x40},
{TAIKO_A_CDC_CONN_TX_SB_B10_CTL, 0x60, 0x40},
- /* Use 16 bit sample size for RX */
- {TAIKO_A_CDC_CONN_RX_SB_B1_CTL, 0xFF, 0xAA},
- {TAIKO_A_CDC_CONN_RX_SB_B2_CTL, 0xFF, 0x2A},
-
/*enable HPF filter for TX paths */
{TAIKO_A_CDC_TX1_MUX_CTL, 0x8, 0x0},
{TAIKO_A_CDC_TX2_MUX_CTL, 0x8, 0x0},
@@ -5072,6 +5055,24 @@
return 0;
}
+static int taiko_codec_get_buck_mv(struct snd_soc_codec *codec)
+{
+ int buck_volt = WCD9XXX_CDC_BUCK_UNSUPPORTED;
+ struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
+ struct wcd9xxx_pdata *pdata = taiko->resmgr.pdata;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(pdata->regulator); i++) {
+ if (!strncmp(pdata->regulator[i].name,
+ WCD9XXX_SUPPLY_BUCK_NAME,
+ sizeof(WCD9XXX_SUPPLY_BUCK_NAME))) {
+ buck_volt = pdata->regulator[i].min_uV;
+ break;
+ }
+ }
+ return buck_volt;
+}
+
static int taiko_codec_probe(struct snd_soc_codec *codec)
{
struct wcd9xxx *control;
@@ -5103,8 +5104,10 @@
tx_hpf_corner_freq_callback);
}
+
snd_soc_codec_set_drvdata(codec, taiko);
+
/* codec resmgr module init */
wcd9xxx = codec->control_data;
pdata = dev_get_platdata(codec->dev->parent);
@@ -5115,6 +5118,9 @@
return ret;
}
+ taiko->clsh_d.buck_mv = taiko_codec_get_buck_mv(codec);
+ wcd9xxx_clsh_init(&taiko->clsh_d);
+
/* init and start mbhc */
ret = wcd9xxx_mbhc_init(&taiko->mbhc, &taiko->resmgr, codec);
if (ret) {
diff --git a/sound/soc/codecs/wcd9320.h b/sound/soc/codecs/wcd9320.h
index aea31db..89a0b9f 100644
--- a/sound/soc/codecs/wcd9320.h
+++ b/sound/soc/codecs/wcd9320.h
@@ -41,12 +41,6 @@
TAIKO_PID_MIC_20_UA,
};
-struct taiko_reg_mask_val {
- u16 reg;
- u8 mask;
- u8 val;
-};
-
enum taiko_mbhc_analog_pwr_cfg {
TAIKO_ANALOG_PWR_COLLAPSED = 0,
TAIKO_ANALOG_PWR_ON,
diff --git a/sound/soc/codecs/wcd9xxx-common.c b/sound/soc/codecs/wcd9xxx-common.c
new file mode 100644
index 0000000..dbf2e39
--- /dev/null
+++ b/sound/soc/codecs/wcd9xxx-common.c
@@ -0,0 +1,591 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <sound/soc.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
+#include "wcd9xxx-common.h"
+
+#define CLSH_COMPUTE_EAR 0x01
+#define CLSH_COMPUTE_HPH_L 0x02
+#define CLSH_COMPUTE_HPH_R 0x03
+
+#define BUCK_VREF_2V 0xFF
+#define BUCK_VREF_1P8V 0xE6
+
+#define NCP_FCLK_LEVEL_8 0x08
+#define NCP_FCLK_LEVEL_5 0x05
+
+#define BUCK_SETTLE_TIME_US 50
+#define NCP_SETTLE_TIME_US 50
+
+static inline void wcd9xxx_enable_clsh_block(
+ struct snd_soc_codec *codec,
+ bool on)
+{
+ snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLSH_B1_CTL,
+ 0x01, on ? 0x01 : 0x00);
+}
+
+static inline void wcd9xxx_enable_anc_delay(
+ struct snd_soc_codec *codec,
+ bool on)
+{
+ snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLSH_B1_CTL,
+ 0x02, on ? 0x02 : 0x00);
+}
+
+static inline void wcd9xxx_enable_ncp(
+ struct snd_soc_codec *codec,
+ bool on)
+{
+ snd_soc_update_bits(codec, WCD9XXX_A_NCP_EN,
+ 0x01, on ? 0x01 : 0x00);
+}
+
+static inline void wcd9xxx_enable_buck(
+ struct snd_soc_codec *codec,
+ bool on)
+{
+ snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_1,
+ 0x80, on ? 0x80 : 0x00);
+}
+
+static int cdc_lo_count;
+
+static void (*clsh_state_fp[NUM_CLSH_STATES])
+ (struct snd_soc_codec *,
+ struct wcd9xxx_clsh_cdc_data *,
+ u8 req_state, bool req_type);
+
+static const char *state_to_str(u8 state)
+{
+ if (state == WCD9XXX_CLSH_STATE_IDLE)
+ return "STATE_IDLE";
+ else if (state == WCD9XXX_CLSH_STATE_EAR)
+ return "STATE_EAR";
+ else if (state == WCD9XXX_CLSH_STATE_HPHL)
+ return "STATE_HPH_L";
+ else if (state == WCD9XXX_CLSH_STATE_HPHR)
+ return "STATE_HPH_R";
+ else if (state == (WCD9XXX_CLSH_STATE_HPHL
+ | WCD9XXX_CLSH_STATE_HPHR))
+ return "STATE_HPH_L_R";
+ else if (state == WCD9XXX_CLSH_STATE_LO)
+ return "STATE_LO";
+
+ return "UNKNOWN_STATE";
+}
+
+static void wcd9xxx_cfg_clsh_buck(
+ struct snd_soc_codec *codec)
+{
+ int i;
+ const struct wcd9xxx_reg_mask_val reg_set[] = {
+ {WCD9XXX_A_BUCK_CTRL_CCL_4, 0x0B, 0x00},
+ {WCD9XXX_A_BUCK_CTRL_CCL_1, 0xF0, 0x50},
+ {WCD9XXX_A_BUCK_CTRL_CCL_3, 0x03, 0x00},
+ {WCD9XXX_A_BUCK_CTRL_CCL_3, 0x0B, 0x00},
+ };
+
+ for (i = 0; i < ARRAY_SIZE(reg_set); i++)
+ snd_soc_update_bits(codec, reg_set[i].reg, reg_set[i].mask,
+ reg_set[i].val);
+
+ dev_dbg(codec->dev, "%s: Programmed buck parameters", __func__);
+}
+
+static void wcd9xxx_cfg_clsh_param_common(
+ struct snd_soc_codec *codec)
+{
+ int i;
+ const struct wcd9xxx_reg_mask_val reg_set[] = {
+ {WCD9XXX_A_CDC_CLSH_BUCK_NCP_VARS, 0x3 << 0, 0},
+ {WCD9XXX_A_CDC_CLSH_BUCK_NCP_VARS, 0x3 << 2, 1 << 2},
+ {WCD9XXX_A_CDC_CLSH_BUCK_NCP_VARS, (0x1 << 4), 0},
+ {WCD9XXX_A_CDC_CLSH_B2_CTL, (0x3 << 0), 0x01},
+ {WCD9XXX_A_CDC_CLSH_B2_CTL, (0x3 << 2), (0x01 << 2)},
+ {WCD9XXX_A_CDC_CLSH_B2_CTL, (0xf << 4), (0x03 << 4)},
+ {WCD9XXX_A_CDC_CLSH_B3_CTL, (0xf << 4), (0x03 << 4)},
+ {WCD9XXX_A_CDC_CLSH_B3_CTL, (0xf << 0), (0x0B)},
+ {WCD9XXX_A_CDC_CLSH_B1_CTL, (0x1 << 5), (0x01 << 5)},
+ {WCD9XXX_A_CDC_CLSH_B1_CTL, (0x1 << 1), (0x01 << 1)},
+ };
+
+ for (i = 0; i < ARRAY_SIZE(reg_set); i++)
+ snd_soc_update_bits(codec, reg_set[i].reg, reg_set[i].mask,
+ reg_set[i].val);
+
+ dev_dbg(codec->dev, "%s: Programmed class H controller common parameters",
+ __func__);
+}
+
+static void wcd9xxx_chargepump_request(
+ struct snd_soc_codec *codec, bool on)
+{
+ static int cp_count;
+
+ if (on && (++cp_count == 1)) {
+ snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLK_OTHR_CTL,
+ 0x01, 0x01);
+ dev_info(codec->dev, "%s: Charge Pump enabled, count = %d\n",
+ __func__, cp_count);
+ }
+
+ else if (!on) {
+ if (--cp_count < 0) {
+ dev_dbg(codec->dev, "%s: Unbalanced disable for charge pump\n",
+ __func__);
+ if (snd_soc_read(codec, WCD9XXX_A_CDC_CLK_OTHR_CTL)
+ & 0x01) {
+ dev_info(codec->dev, "%s: Actual chargepump is ON\n",
+ __func__);
+ }
+ cp_count = 0;
+ WARN_ON(1);
+ }
+
+ if (cp_count == 0) {
+ snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLK_OTHR_CTL,
+ 0x01, 0x00);
+ dev_dbg(codec->dev, "%s: Charge pump disabled, count = %d\n",
+ __func__, cp_count);
+ }
+ }
+}
+
+static inline void wcd9xxx_clsh_computation_request(
+ struct snd_soc_codec *codec, int compute_pa, bool on)
+{
+ u8 reg_val, reg_mask;
+
+ switch (compute_pa) {
+ case CLSH_COMPUTE_EAR:
+ reg_mask = 0x10;
+ reg_val = (on ? 0x10 : 0x00);
+ break;
+ case CLSH_COMPUTE_HPH_L:
+ reg_mask = 0x08;
+ reg_val = (on ? 0x08 : 0x00);
+ break;
+ case CLSH_COMPUTE_HPH_R:
+ reg_mask = 0x04;
+ reg_val = (on ? 0x04 : 0x00);
+ break;
+ default:
+ dev_dbg(codec->dev, "%s: class h computation PA request incorrect\n",
+ __func__);
+ return;
+ }
+
+ snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLSH_B1_CTL,
+ reg_mask, reg_val);
+
+}
+
+static void wcd9xxx_enable_buck_mode(struct snd_soc_codec *codec,
+ u8 buck_vref)
+{
+ int i;
+ const struct wcd9xxx_reg_mask_val reg_set[] = {
+ {WCD9XXX_A_BUCK_MODE_5, 0x02, 0x03},
+ {WCD9XXX_A_BUCK_MODE_4, 0xFF, buck_vref},
+ {WCD9XXX_A_BUCK_MODE_1, 0x04, 0x04},
+ {WCD9XXX_A_BUCK_MODE_1, 0x08, 0x00},
+ {WCD9XXX_A_BUCK_MODE_3, 0x04, 0x00},
+ {WCD9XXX_A_BUCK_MODE_3, 0x08, 0x00},
+ {WCD9XXX_A_BUCK_MODE_1, 0x80, 0x80},
+ };
+
+ for (i = 0; i < ARRAY_SIZE(reg_set); i++)
+ snd_soc_update_bits(codec, reg_set[i].reg,
+ reg_set[i].mask, reg_set[i].val);
+
+ dev_dbg(codec->dev, "%s: Done\n", __func__);
+ usleep_range(BUCK_SETTLE_TIME_US, BUCK_SETTLE_TIME_US);
+}
+
+static void wcd9xxx_clsh_enable_post_pa(struct snd_soc_codec *codec)
+{
+ int i;
+ const struct wcd9xxx_reg_mask_val reg_set[] = {
+ {WCD9XXX_A_BUCK_MODE_5, 0x02, 0x00},
+ {WCD9XXX_A_NCP_STATIC, 0x20, 0x00},
+ {WCD9XXX_A_BUCK_MODE_3, 0x04, 0x04},
+ {WCD9XXX_A_BUCK_MODE_3, 0x08, 0x08},
+ };
+
+ for (i = 0; i < ARRAY_SIZE(reg_set); i++)
+ snd_soc_update_bits(codec, reg_set[i].reg,
+ reg_set[i].mask, reg_set[i].val);
+
+ dev_dbg(codec->dev, "%s: completed clsh mode settings after PA enable\n",
+ __func__);
+
+}
+
+static void wcd9xxx_set_fclk_enable_ncp(struct snd_soc_codec *codec,
+ u8 fclk_level)
+{
+ int i;
+ const struct wcd9xxx_reg_mask_val reg_set[] = {
+ {WCD9XXX_A_NCP_STATIC, 0x20, 0x20},
+ {WCD9XXX_A_NCP_EN, 0x01, 0x01},
+ };
+ snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC,
+ 0x010, 0x00);
+ snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC,
+ 0x0F, fclk_level);
+ for (i = 0; i < ARRAY_SIZE(reg_set); i++)
+ snd_soc_update_bits(codec, reg_set[i].reg,
+ reg_set[i].mask, reg_set[i].val);
+
+ usleep_range(NCP_SETTLE_TIME_US, NCP_SETTLE_TIME_US);
+
+ dev_dbg(codec->dev, "%s: set ncp done\n", __func__);
+}
+
+static void wcd9xxx_cfg_clsh_param_ear(struct snd_soc_codec *codec)
+{
+ int i;
+ const struct wcd9xxx_reg_mask_val reg_set[] = {
+ {WCD9XXX_A_CDC_CLSH_B1_CTL, (0x1 << 7), 0},
+ {WCD9XXX_A_CDC_CLSH_V_PA_HD_EAR, (0x3f << 0), 0x0D},
+ {WCD9XXX_A_CDC_CLSH_V_PA_MIN_EAR, (0x3f << 0), 0x3A},
+
+ /* Under assumption that EAR load is 10.7ohm */
+ {WCD9XXX_A_CDC_CLSH_IDLE_EAR_THSD, (0x3f << 0), 0x26},
+ {WCD9XXX_A_CDC_CLSH_FCLKONLY_EAR_THSD, (0x3f << 0), 0x2C},
+ {WCD9XXX_A_CDC_CLSH_I_PA_FACT_EAR_L, 0xff, 0xA9},
+ {WCD9XXX_A_CDC_CLSH_I_PA_FACT_EAR_U, 0xff, 0x07},
+ {WCD9XXX_A_CDC_CLSH_K_ADDR, (0x1 << 7), 0},
+ {WCD9XXX_A_CDC_CLSH_K_ADDR, (0xf << 0), 0x08},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1b},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x2d},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x36},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x37},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+ };
+
+ for (i = 0; i < ARRAY_SIZE(reg_set); i++)
+ snd_soc_update_bits(codec, reg_set[i].reg,
+ reg_set[i].mask, reg_set[i].val);
+
+ dev_dbg(codec->dev, "%s: Programmed Class H controller EAR specific params\n",
+ __func__);
+}
+
+static void wcd9xxx_cfg_clsh_param_hph(struct snd_soc_codec *codec)
+{
+ int i;
+ const struct wcd9xxx_reg_mask_val reg_set[] = {
+ {WCD9XXX_A_CDC_CLSH_B1_CTL, (0x1 << 6), 0},
+ {WCD9XXX_A_CDC_CLSH_V_PA_HD_HPH, 0x3f, 0x0D},
+ {WCD9XXX_A_CDC_CLSH_V_PA_MIN_HPH, 0x3f, 0x1D},
+
+ /* Under assumption that HPH load is 16ohm per channel */
+ {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0x3f, 0x13},
+ {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0x1f, 0x19},
+ {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x97},
+ {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x05},
+ {WCD9XXX_A_CDC_CLSH_K_ADDR, (0x1 << 7), 0},
+ {WCD9XXX_A_CDC_CLSH_K_ADDR, 0x0f, 0},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xAE},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1C},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x24},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x25},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+ };
+
+ for (i = 0; i < ARRAY_SIZE(reg_set); i++)
+ snd_soc_update_bits(codec, reg_set[i].reg, reg_set[i].mask,
+ reg_set[i].val);
+ dev_dbg(codec->dev, "%s: Programmed Class H controller HPH specific params\n",
+ __func__);
+}
+
+static void wcd9xxx_clsh_turnoff_postpa
+ (struct snd_soc_codec *codec)
+{
+
+ int i;
+
+ const struct wcd9xxx_reg_mask_val reg_set[] = {
+ {WCD9XXX_A_NCP_EN, 0x01, 0x00},
+ {WCD9XXX_A_BUCK_MODE_1, 0x80, 0x00},
+ {WCD9XXX_A_CDC_CLSH_B1_CTL, 0x10, 0x00},
+ };
+
+ wcd9xxx_chargepump_request(codec, false);
+
+ for (i = 0; i < ARRAY_SIZE(reg_set); i++)
+ snd_soc_update_bits(codec, reg_set[i].reg,
+ reg_set[i].mask, reg_set[i].val);
+
+ wcd9xxx_enable_clsh_block(codec, false);
+
+ dev_dbg(codec->dev, "%s: Done\n", __func__);
+}
+
+static void wcd9xxx_clsh_state_idle(struct snd_soc_codec *codec,
+ struct wcd9xxx_clsh_cdc_data *clsh_d,
+ u8 req_state, bool is_enable)
+{
+ if (is_enable) {
+ dev_dbg(codec->dev, "%s: wrong transition, cannot enable IDLE state\n",
+ __func__);
+ } else {
+ if (req_state == WCD9XXX_CLSH_STATE_EAR) {
+ wcd9xxx_clsh_turnoff_postpa(codec);
+ } else if (req_state == WCD9XXX_CLSH_STATE_HPHL) {
+ wcd9xxx_clsh_computation_request(codec,
+ CLSH_COMPUTE_HPH_L, false);
+ wcd9xxx_clsh_turnoff_postpa(codec);
+ } else if (req_state == WCD9XXX_CLSH_STATE_HPHR) {
+ wcd9xxx_clsh_computation_request(codec,
+ CLSH_COMPUTE_HPH_R, false);
+ wcd9xxx_clsh_turnoff_postpa(codec);
+ } else if (req_state == WCD9XXX_CLSH_STATE_LO) {
+ wcd9xxx_enable_ncp(codec, false);
+ wcd9xxx_enable_buck(codec, false);
+ }
+ }
+}
+
+static void wcd9xxx_clsh_state_ear(struct snd_soc_codec *codec,
+ struct wcd9xxx_clsh_cdc_data *clsh_d,
+ u8 req_state, bool is_enable)
+{
+ if (is_enable) {
+ wcd9xxx_cfg_clsh_buck(codec);
+ wcd9xxx_cfg_clsh_param_common(codec);
+ wcd9xxx_cfg_clsh_param_ear(codec);
+ wcd9xxx_enable_clsh_block(codec, true);
+ wcd9xxx_chargepump_request(codec, true);
+ wcd9xxx_enable_anc_delay(codec, true);
+ wcd9xxx_clsh_computation_request(codec,
+ CLSH_COMPUTE_EAR, true);
+ wcd9xxx_enable_buck_mode(codec, BUCK_VREF_2V);
+ wcd9xxx_set_fclk_enable_ncp(codec, NCP_FCLK_LEVEL_8);
+
+ dev_dbg(codec->dev, "%s: Enabled ear mode class h\n", __func__);
+ } else {
+ dev_dbg(codec->dev, "%s: stub fallback to ear\n", __func__);
+ }
+}
+
+static void wcd9xxx_clsh_state_hph_l(struct snd_soc_codec *codec,
+ struct wcd9xxx_clsh_cdc_data *clsh_d,
+ u8 req_state, bool is_enable)
+{
+ if (is_enable) {
+ wcd9xxx_cfg_clsh_buck(codec);
+ wcd9xxx_cfg_clsh_param_common(codec);
+ wcd9xxx_cfg_clsh_param_hph(codec);
+ wcd9xxx_enable_clsh_block(codec, true);
+ wcd9xxx_chargepump_request(codec, true);
+ wcd9xxx_enable_anc_delay(codec, true);
+ wcd9xxx_clsh_computation_request(codec,
+ CLSH_COMPUTE_HPH_L, true);
+ wcd9xxx_enable_buck_mode(codec, BUCK_VREF_2V);
+ wcd9xxx_set_fclk_enable_ncp(codec, NCP_FCLK_LEVEL_8);
+
+ dev_dbg(codec->dev, "%s: Done\n", __func__);
+ } else {
+ if (req_state == WCD9XXX_CLSH_STATE_HPHR) {
+ wcd9xxx_clsh_computation_request(codec,
+ CLSH_COMPUTE_HPH_R, false);
+ } else {
+ dev_dbg(codec->dev, "%s: stub fallback to hph_l\n",
+ __func__);
+ }
+ }
+}
+
+static void wcd9xxx_clsh_state_hph_r(struct snd_soc_codec *codec,
+ struct wcd9xxx_clsh_cdc_data *clsh_d,
+ u8 req_state, bool is_enable)
+{
+ if (is_enable) {
+
+ wcd9xxx_cfg_clsh_buck(codec);
+ wcd9xxx_cfg_clsh_param_common(codec);
+ wcd9xxx_cfg_clsh_param_hph(codec);
+ wcd9xxx_enable_clsh_block(codec, true);
+ wcd9xxx_chargepump_request(codec, true);
+ wcd9xxx_enable_anc_delay(codec, true);
+ wcd9xxx_clsh_computation_request(codec,
+ CLSH_COMPUTE_HPH_R, true);
+ wcd9xxx_enable_buck_mode(codec, BUCK_VREF_2V);
+ wcd9xxx_set_fclk_enable_ncp(codec, NCP_FCLK_LEVEL_8);
+
+ dev_dbg(codec->dev, "%s: Done\n", __func__);
+ } else {
+ if (req_state == WCD9XXX_CLSH_STATE_HPHL) {
+ wcd9xxx_clsh_computation_request(codec,
+ CLSH_COMPUTE_HPH_L, false);
+ } else {
+ dev_dbg(codec->dev, "%s: stub fallback to hph_r\n",
+ __func__);
+ }
+ }
+}
+
+static void wcd9xxx_clsh_state_hph_st(struct snd_soc_codec *codec,
+ struct wcd9xxx_clsh_cdc_data *clsh_d,
+ u8 req_state, bool is_enable)
+{
+ if (is_enable) {
+ wcd9xxx_clsh_computation_request(codec,
+ CLSH_COMPUTE_HPH_L, true);
+ wcd9xxx_clsh_computation_request(codec,
+ CLSH_COMPUTE_HPH_R, true);
+ } else {
+ dev_dbg(codec->dev, "%s: stub fallback to hph_st\n", __func__);
+ }
+}
+
+static void wcd9xxx_clsh_state_lo(struct snd_soc_codec *codec,
+ struct wcd9xxx_clsh_cdc_data *clsh_d,
+ u8 req_state, bool is_enable)
+{
+ if (is_enable) {
+ if (++cdc_lo_count > 1)
+ return;
+
+ wcd9xxx_enable_buck_mode(codec, BUCK_VREF_1P8V);
+ wcd9xxx_set_fclk_enable_ncp(codec, NCP_FCLK_LEVEL_5);
+
+ if (clsh_d->buck_mv == WCD9XXX_CDC_BUCK_MV_1P8) {
+ wcd9xxx_enable_buck(codec, false);
+ snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC,
+ 0x20, 0x01);
+ wcd9xxx_enable_ncp(codec, true);
+ msleep(NCP_SETTLE_TIME_US);
+
+ } else {
+ snd_soc_update_bits(codec, WCD9XXX_A_NCP_EN,
+ 0x40, 0x00);
+ wcd9xxx_enable_ncp(codec, true);
+ msleep(NCP_SETTLE_TIME_US);
+ snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_5,
+ 0x01, 0x01);
+ snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_5,
+ 0xFB, (0x02 << 2));
+ }
+ snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_1,
+ 0x04, 0x00);
+ } else {
+ dev_dbg(codec->dev, "%s: stub fallback to lineout\n", __func__);
+ }
+}
+
+static void wcd9xxx_clsh_state_err(struct snd_soc_codec *codec,
+ struct wcd9xxx_clsh_cdc_data *clsh_d,
+ u8 req_state, bool is_enable)
+{
+ dev_dbg(codec->dev, "%s Wrong request for class H state machine requested to %s %s"
+ , __func__, is_enable ? "enable" : "disable",
+ state_to_str(req_state));
+ WARN_ON(1);
+}
+
+void wcd9xxx_clsh_fsm(struct snd_soc_codec *codec,
+ struct wcd9xxx_clsh_cdc_data *cdc_clsh_d,
+ u8 req_state, bool req_type, u8 clsh_event)
+{
+ u8 old_state, new_state;
+
+ switch (clsh_event) {
+
+ case WCD9XXX_CLSH_EVENT_PRE_DAC:
+
+ /* PRE_DAC event should be used only for Enable */
+ BUG_ON(req_type != WCD9XXX_CLSH_REQ_ENABLE);
+
+ old_state = cdc_clsh_d->state;
+ new_state = old_state | req_state;
+
+ (*clsh_state_fp[new_state]) (codec, cdc_clsh_d,
+ req_state, req_type);
+ cdc_clsh_d->state = new_state;
+ dev_info(codec->dev, "%s: ClassH state transition from %s to %s\n",
+ __func__, state_to_str(old_state),
+ state_to_str(cdc_clsh_d->state));
+
+ break;
+
+ case WCD9XXX_CLSH_EVENT_POST_PA:
+
+ if (req_type == WCD9XXX_CLSH_REQ_DISABLE) {
+ if (req_state == WCD9XXX_CLSH_STATE_LO
+ && --cdc_lo_count > 0)
+ break;
+
+ old_state = cdc_clsh_d->state;
+ new_state = old_state & (~req_state);
+
+ if (new_state < NUM_CLSH_STATES) {
+ (*clsh_state_fp[new_state]) (codec, cdc_clsh_d,
+ req_state, req_type);
+ cdc_clsh_d->state = new_state;
+ dev_info(codec->dev, "%s: ClassH state transition from %s to %s\n",
+ __func__, state_to_str(old_state),
+ state_to_str(cdc_clsh_d->state));
+
+ } else {
+ dev_dbg(codec->dev, "%s: wrong new state = %x\n",
+ __func__, new_state);
+ }
+
+
+ } else if (req_state != WCD9XXX_CLSH_STATE_LO) {
+ wcd9xxx_clsh_enable_post_pa(codec);
+ }
+
+ break;
+ }
+
+}
+EXPORT_SYMBOL_GPL(wcd9xxx_clsh_fsm);
+
+void wcd9xxx_clsh_init(struct wcd9xxx_clsh_cdc_data *clsh)
+{
+ int i;
+ clsh->state = WCD9XXX_CLSH_STATE_IDLE;
+
+ for (i = 0; i < NUM_CLSH_STATES; i++)
+ clsh_state_fp[i] = wcd9xxx_clsh_state_err;
+
+ clsh_state_fp[WCD9XXX_CLSH_STATE_IDLE] = wcd9xxx_clsh_state_idle;
+ clsh_state_fp[WCD9XXX_CLSH_STATE_EAR] = wcd9xxx_clsh_state_ear;
+ clsh_state_fp[WCD9XXX_CLSH_STATE_HPHL] =
+ wcd9xxx_clsh_state_hph_l;
+ clsh_state_fp[WCD9XXX_CLSH_STATE_HPHR] =
+ wcd9xxx_clsh_state_hph_r;
+ clsh_state_fp[WCD9XXX_CLSH_STATE_HPH_ST] =
+ wcd9xxx_clsh_state_hph_st;
+ clsh_state_fp[WCD9XXX_CLSH_STATE_LO] = wcd9xxx_clsh_state_lo;
+
+}
+EXPORT_SYMBOL_GPL(wcd9xxx_clsh_init);
+
+MODULE_DESCRIPTION("WCD9XXX Common");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/wcd9xxx-common.h b/sound/soc/codecs/wcd9xxx-common.h
new file mode 100644
index 0000000..743ab0c
--- /dev/null
+++ b/sound/soc/codecs/wcd9xxx-common.h
@@ -0,0 +1,68 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef WCD9XXX_CODEC_COMMON
+
+#define WCD9XXX_CODEC_COMMON
+
+#define WCD9XXX_CLSH_REQ_ENABLE true
+#define WCD9XXX_CLSH_REQ_DISABLE false
+
+#define WCD9XXX_CLSH_EVENT_PRE_DAC 0x01
+#define WCD9XXX_CLSH_EVENT_POST_PA 0x02
+
+/* Basic states for Class H state machine.
+ * represented as a bit mask within a u8 data type
+ * bit 0: EAR mode
+ * bit 1: HPH Left mode
+ * bit 2: HPH Right mode
+ * bit 3: Lineout mode
+ * bit 4: Ultrasound mode
+ */
+#define WCD9XXX_CLSH_STATE_IDLE 0x00
+#define WCD9XXX_CLSH_STATE_EAR (0x01 << 0)
+#define WCD9XXX_CLSH_STATE_HPHL (0x01 << 1)
+#define WCD9XXX_CLSH_STATE_HPHR (0x01 << 2)
+#define WCD9XXX_CLSH_STATE_LO (0x01 << 3)
+#define NUM_CLSH_STATES ((0x01 << 4) - 1)
+
+/* Derived State: Bits 1 and 2 should be set for Headphone stereo */
+#define WCD9XXX_CLSH_STATE_HPH_ST (WCD9XXX_CLSH_STATE_HPHL | \
+ WCD9XXX_CLSH_STATE_HPHR)
+
+
+struct wcd9xxx_reg_mask_val {
+ u16 reg;
+ u8 mask;
+ u8 val;
+};
+
+/* Class H data that the codec driver will maintain */
+struct wcd9xxx_clsh_cdc_data {
+ u8 state;
+ int buck_mv;
+};
+
+
+enum wcd9xxx_buck_volt {
+ WCD9XXX_CDC_BUCK_UNSUPPORTED = 0,
+ WCD9XXX_CDC_BUCK_MV_1P8 = 1800000,
+ WCD9XXX_CDC_BUCK_MV_2P15 = 2150000,
+};
+
+extern void wcd9xxx_clsh_fsm(struct snd_soc_codec *codec,
+ struct wcd9xxx_clsh_cdc_data *cdc_clsh_d,
+ u8 req_state, bool req_type, u8 clsh_event);
+
+extern void wcd9xxx_clsh_init(struct wcd9xxx_clsh_cdc_data *clsh);
+
+#endif
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.c b/sound/soc/codecs/wcd9xxx-mbhc.c
index a358be1..b3549cc 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.c
+++ b/sound/soc/codecs/wcd9xxx-mbhc.c
@@ -374,8 +374,14 @@
}
}
-static void wcd9xxx_jack_report(struct snd_soc_jack *jack, int status, int mask)
+static void wcd9xxx_jack_report(struct wcd9xxx_mbhc *mbhc,
+ struct snd_soc_jack *jack, int status, int mask)
{
+ if (jack == &mbhc->headset_jack)
+ wcd9xxx_resmgr_cond_update_cond(mbhc->resmgr,
+ WCD9XXX_COND_HPH_MIC,
+ status & SND_JACK_MICROPHONE);
+
snd_soc_jack_report_no_dapm(jack, status, mask);
}
@@ -388,7 +394,7 @@
codec = mbhc->codec;
if (mbhc->hph_status & jack_status) {
mbhc->hph_status &= ~jack_status;
- wcd9xxx_jack_report(&mbhc->headset_jack,
+ wcd9xxx_jack_report(mbhc, &mbhc->headset_jack,
mbhc->hph_status, WCD9XXX_JACK_MASK);
snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_OCP_CTL, 0x10,
0x00);
@@ -618,14 +624,14 @@
else if (mbhc->buttons_pressed) {
pr_debug("%s: release of button press%d\n",
__func__, jack_type);
- wcd9xxx_jack_report(&mbhc->button_jack, 0,
+ wcd9xxx_jack_report(mbhc, &mbhc->button_jack, 0,
mbhc->buttons_pressed);
mbhc->buttons_pressed &=
~WCD9XXX_JACK_BUTTON_MASK;
}
pr_debug("%s: Reporting removal %d(%x)\n", __func__,
jack_type, mbhc->hph_status);
- wcd9xxx_jack_report(&mbhc->headset_jack, mbhc->hph_status,
+ wcd9xxx_jack_report(mbhc, &mbhc->headset_jack, mbhc->hph_status,
WCD9XXX_JACK_MASK);
wcd9xxx_set_and_turnoff_hph_padac(mbhc);
hphrocp_off_report(mbhc, SND_JACK_OC_HPHR);
@@ -638,7 +644,7 @@
if (mbhc->hph_status && mbhc->hph_status != jack_type) {
pr_debug("%s: Reporting removal (%x)\n",
__func__, mbhc->hph_status);
- wcd9xxx_jack_report(&mbhc->headset_jack,
+ wcd9xxx_jack_report(mbhc, &mbhc->headset_jack,
0, WCD9XXX_JACK_MASK);
mbhc->hph_status = 0;
}
@@ -658,7 +664,7 @@
}
pr_debug("%s: Reporting insertion %d(%x)\n", __func__,
jack_type, mbhc->hph_status);
- wcd9xxx_jack_report(&mbhc->headset_jack,
+ wcd9xxx_jack_report(mbhc, &mbhc->headset_jack,
mbhc->hph_status, WCD9XXX_JACK_MASK);
wcd9xxx_clr_and_turnon_hph_padac(mbhc);
}
@@ -1606,6 +1612,14 @@
pr_debug("%s: enter, removal interrupt\n", __func__);
WCD9XXX_BCL_LOCK(mbhc->resmgr);
+ /*
+ * While we don't know whether MIC is there or not, let the resmgr know
+ * so micbias can be disabled temporarily
+ */
+ if (mbhc->current_plug == PLUG_TYPE_HEADSET)
+ wcd9xxx_resmgr_cond_update_cond(mbhc->resmgr,
+ WCD9XXX_COND_HPH_MIC, false);
+
vddio = (mbhc->mbhc_data.micb_mv != VDDIO_MICBIAS_MV &&
mbhc->mbhc_micbias_switched);
if (vddio)
@@ -1624,6 +1638,10 @@
*/
if (vddio && (mbhc->current_plug == PLUG_TYPE_HEADSET))
__wcd9xxx_switch_micbias(mbhc, 1, true, true);
+
+ if (mbhc->current_plug == PLUG_TYPE_HEADSET)
+ wcd9xxx_resmgr_cond_update_cond(mbhc->resmgr,
+ WCD9XXX_COND_HPH_MIC, true);
WCD9XXX_BCL_UNLOCK(mbhc->resmgr);
return IRQ_HANDLED;
@@ -1679,7 +1697,7 @@
pr_debug("%s: STA: %d, DCE: %d\n", __func__, sta_mv, dce_mv);
pr_debug("%s: Reporting long button press event\n", __func__);
- wcd9xxx_jack_report(&mbhc->button_jack, mbhc->buttons_pressed,
+ wcd9xxx_jack_report(mbhc, &mbhc->button_jack, mbhc->buttons_pressed,
mbhc->buttons_pressed);
pr_debug("%s: leave\n", __func__);
@@ -2357,7 +2375,7 @@
if (ret == 0) {
pr_debug("%s: Reporting long button release event\n",
__func__);
- wcd9xxx_jack_report(&mbhc->button_jack, 0,
+ wcd9xxx_jack_report(mbhc, &mbhc->button_jack, 0,
mbhc->buttons_pressed);
} else {
if (wcd9xxx_is_fake_press(mbhc)) {
@@ -2370,12 +2388,14 @@
} else {
pr_debug("%s: Reporting btn press\n",
__func__);
- wcd9xxx_jack_report(&mbhc->button_jack,
+ wcd9xxx_jack_report(mbhc,
+ &mbhc->button_jack,
mbhc->buttons_pressed,
mbhc->buttons_pressed);
pr_debug("%s: Reporting btn release\n",
__func__);
- wcd9xxx_jack_report(&mbhc->button_jack,
+ wcd9xxx_jack_report(mbhc,
+ &mbhc->button_jack,
0, mbhc->buttons_pressed);
}
}
@@ -2414,7 +2434,7 @@
WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
mbhc->hphlocp_cnt = 0;
mbhc->hph_status |= SND_JACK_OC_HPHL;
- wcd9xxx_jack_report(&mbhc->headset_jack,
+ wcd9xxx_jack_report(mbhc, &mbhc->headset_jack,
mbhc->hph_status,
WCD9XXX_JACK_MASK);
}
@@ -2443,7 +2463,7 @@
WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
mbhc->hphrocp_cnt = 0;
mbhc->hph_status |= SND_JACK_OC_HPHR;
- wcd9xxx_jack_report(&mbhc->headset_jack,
+ wcd9xxx_jack_report(mbhc, &mbhc->headset_jack,
mbhc->hph_status, WCD9XXX_JACK_MASK);
}
diff --git a/sound/soc/codecs/wcd9xxx-resmgr.c b/sound/soc/codecs/wcd9xxx-resmgr.c
index 17edd4a..2011346 100644
--- a/sound/soc/codecs/wcd9xxx-resmgr.c
+++ b/sound/soc/codecs/wcd9xxx-resmgr.c
@@ -94,6 +94,14 @@
"WCD9XXX_EVENT_LAST",
};
+struct wcd9xxx_resmgr_cond_entry {
+ unsigned short reg;
+ int shift;
+ bool invert;
+ enum wcd9xxx_resmgr_cond cond;
+ struct list_head list;
+};
+
static enum wcd9xxx_clock_type wcd9xxx_save_clock(struct wcd9xxx_resmgr
*resmgr);
static void wcd9xxx_restore_clock(struct wcd9xxx_resmgr *resmgr,
@@ -640,6 +648,93 @@
return rc;
}
+void wcd9xxx_resmgr_cond_trigger_cond(struct wcd9xxx_resmgr *resmgr,
+ enum wcd9xxx_resmgr_cond cond)
+{
+ struct list_head *l;
+ struct wcd9xxx_resmgr_cond_entry *e;
+ bool set;
+
+ pr_debug("%s: enter\n", __func__);
+ WCD9XXX_BCL_ASSERT_LOCKED(resmgr);
+ set = !!test_bit(cond, &resmgr->cond_flags);
+ list_for_each(l, &resmgr->update_bit_cond_h) {
+ e = list_entry(l, struct wcd9xxx_resmgr_cond_entry, list);
+ if (e->cond == cond)
+ snd_soc_update_bits(resmgr->codec, e->reg,
+ 1 << e->shift,
+ (set ? !e->invert : e->invert)
+ << e->shift);
+ }
+ pr_debug("%s: leave\n", __func__);
+}
+
+void wcd9xxx_resmgr_cond_update_cond(struct wcd9xxx_resmgr *resmgr,
+ enum wcd9xxx_resmgr_cond cond, bool set)
+{
+ WCD9XXX_BCL_ASSERT_LOCKED(resmgr);
+ if ((set && !test_and_set_bit(cond, &resmgr->cond_flags)) ||
+ (!set && test_and_clear_bit(cond, &resmgr->cond_flags))) {
+ pr_debug("%s: Resource %d condition changed to %s\n", __func__,
+ cond, set ? "set" : "clear");
+ wcd9xxx_resmgr_cond_trigger_cond(resmgr, cond);
+ }
+}
+
+int wcd9xxx_resmgr_add_cond_update_bits(struct wcd9xxx_resmgr *resmgr,
+ enum wcd9xxx_resmgr_cond cond,
+ unsigned short reg, int shift,
+ bool invert)
+{
+ struct wcd9xxx_resmgr_cond_entry *entry;
+
+ WCD9XXX_BCL_ASSERT_LOCKED(resmgr);
+ entry = kmalloc(sizeof(*entry), GFP_KERNEL);
+ if (!entry)
+ return -ENOMEM;
+
+ entry->cond = cond;
+ entry->reg = reg;
+ entry->shift = shift;
+ entry->invert = invert;
+ list_add_tail(&entry->list, &resmgr->update_bit_cond_h);
+
+ wcd9xxx_resmgr_cond_trigger_cond(resmgr, cond);
+
+ return 0;
+}
+
+/*
+ * wcd9xxx_resmgr_rm_cond_update_bits :
+ * Clear bit and remove from the conditional bit update list
+ */
+int wcd9xxx_resmgr_rm_cond_update_bits(struct wcd9xxx_resmgr *resmgr,
+ enum wcd9xxx_resmgr_cond cond,
+ unsigned short reg, int shift,
+ bool invert)
+{
+ struct list_head *l, *next;
+ struct wcd9xxx_resmgr_cond_entry *e = NULL;
+
+ pr_debug("%s: enter\n", __func__);
+ WCD9XXX_BCL_ASSERT_LOCKED(resmgr);
+ list_for_each_safe(l, next, &resmgr->update_bit_cond_h) {
+ e = list_entry(l, struct wcd9xxx_resmgr_cond_entry, list);
+ if (e->reg == reg && e->shift == shift && e->invert == invert) {
+ snd_soc_update_bits(resmgr->codec, e->reg,
+ 1 << e->shift,
+ e->invert << e->shift);
+ list_del(&e->list);
+ kfree(e);
+ return 0;
+ }
+ }
+ pr_err("%s: Cannot find update bit entry reg 0x%x, shift %d\n",
+ __func__, e ? e->reg : 0, e ? e->shift : 0);
+
+ return -EINVAL;
+}
+
int wcd9xxx_resmgr_register_notifier(struct wcd9xxx_resmgr *resmgr,
struct notifier_block *nblock)
{
@@ -669,6 +764,8 @@
resmgr->pdata = pdata;
resmgr->reg_addr = reg_addr;
+ INIT_LIST_HEAD(&resmgr->update_bit_cond_h);
+
BLOCKING_INIT_NOTIFIER_HEAD(&resmgr->notifier);
mutex_init(&resmgr->codec_resource_lock);
diff --git a/sound/soc/codecs/wcd9xxx-resmgr.h b/sound/soc/codecs/wcd9xxx-resmgr.h
index 6c30eeb..53c48f6 100644
--- a/sound/soc/codecs/wcd9xxx-resmgr.h
+++ b/sound/soc/codecs/wcd9xxx-resmgr.h
@@ -125,6 +125,9 @@
/* Notifier needs mbhc pointer with resmgr */
struct wcd9xxx_mbhc *mbhc;
+ unsigned long cond_flags;
+ struct list_head update_bit_cond_h;
+
/*
* Currently, only used for mbhc purpose, to protect
* concurrent execution of mbhc threaded irq handlers and
@@ -189,4 +192,18 @@
void wcd9xxx_resmgr_notifier_call(struct wcd9xxx_resmgr *resmgr,
const enum wcd9xxx_notify_event e);
+enum wcd9xxx_resmgr_cond {
+ WCD9XXX_COND_HPH_MIC = 1,
+};
+int wcd9xxx_resmgr_rm_cond_update_bits(struct wcd9xxx_resmgr *resmgr,
+ enum wcd9xxx_resmgr_cond cond,
+ unsigned short reg, int shift,
+ bool invert);
+int wcd9xxx_resmgr_add_cond_update_bits(struct wcd9xxx_resmgr *resmgr,
+ enum wcd9xxx_resmgr_cond cond,
+ unsigned short reg, int shift,
+ bool invert);
+void wcd9xxx_resmgr_cond_update_cond(struct wcd9xxx_resmgr *resmgr,
+ enum wcd9xxx_resmgr_cond cond, bool set);
+
#endif /* __WCD9XXX_COMMON_H__ */
diff --git a/sound/soc/msm/mdm9625.c b/sound/soc/msm/mdm9625.c
index 8eac69e..eb7366c 100644
--- a/sound/soc/msm/mdm9625.c
+++ b/sound/soc/msm/mdm9625.c
@@ -27,6 +27,7 @@
#include <mach/socinfo.h>
#include <qdsp6v2/msm-pcm-routing-v2.h>
#include "../codecs/wcd9320.h"
+#include <linux/io.h>
/* Spk control */
#define MDM9625_SPK_ON 1
@@ -38,9 +39,16 @@
#define MDM_MCLK_CLK_12P288MHZ 12288000
#define MDM_MCLK_CLK_9P6HZ 9600000
#define MDM_IBIT_CLK_DIV_1P56MHZ 7
-#define MDM_MI2S_PRIM_INTF 0
-#define MDM_MI2S_SEC_INTF 1
+#define MDM_MI2S_AUXPCM_PRIM_INTF 0
+#define MDM_MI2S_AUXPCM_SEC_INTF 1
+#define LPAIF_OFFSET 0xFE000000
+#define LPAIF_PRI_MODE_MUXSEL (LPAIF_OFFSET + 0x2B000)
+#define LPAIF_SEC_MODE_MUXSEL (LPAIF_OFFSET + 0x2C000)
+
+#define I2S_SEL 0
+#define I2S_PCM_SEL 1
+#define I2S_PCM_SEL_OFFSET 1
/* Machine driver Name*/
#define MDM9625_MACHINE_DRV_NAME "mdm9625-asoc-taiko"
@@ -77,6 +85,8 @@
#define GPIO_NAME_INDEX 0
#define DT_PARSE_INDEX 1
+static int mdm9625_auxpcm_rate = 8000;
+void *lpaif_pri_muxsel_virt_addr;
static char *mdm_i2s_gpio_name[][2] = {
{"PRIM_MI2S_WS", "prim-i2s-gpio-ws"},
@@ -93,6 +103,7 @@
static int mdm9625_mi2s_rx_ch = 1;
static int mdm9625_mi2s_tx_ch = 1;
static int msm_spk_control;
+static atomic_t aux_ref_count;
static atomic_t mi2s_ref_count;
static int mdm9625_enable_codec_ext_clk(struct snd_soc_codec *codec,
@@ -117,7 +128,8 @@
#define WCD9XXX_MBHC_DEF_BUTTONS 8
#define WCD9XXX_MBHC_DEF_RLOADS 5
-static int mdm9625_set_mi2s_gpio(struct snd_pcm_substream *substream, u32 intf)
+static int mdm9625_set_gpio(struct snd_pcm_substream *substream,
+ u32 intf)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_card *card = rtd->card;
@@ -134,8 +146,9 @@
goto err;
}
- if (intf == MDM_MI2S_PRIM_INTF)
+ if (intf == MDM_MI2S_AUXPCM_PRIM_INTF) {
i2s_ctrl = pdata->pri_ctrl;
+ }
else {
pr_err("%s: Wrong I2S Interface\n", __func__);
rtn = -EINVAL;
@@ -186,8 +199,9 @@
rtn = -EINVAL;
goto err;
}
- if (intf == MDM_MI2S_PRIM_INTF)
+ if (intf == MDM_MI2S_AUXPCM_PRIM_INTF) {
i2s_ctrl = pdata->pri_ctrl;
+ }
else {
pr_debug("%s: Wrong Interface\n", __func__);
rtn = -EINVAL;
@@ -264,7 +278,7 @@
struct snd_soc_pcm_runtime *rtd = substream->private_data;
int ret;
if (atomic_dec_return(&mi2s_ref_count) == 0) {
- mdm9625_mi2s_free_gpios(substream, MDM_MI2S_PRIM_INTF);
+ mdm9625_mi2s_free_gpios(substream, MDM_MI2S_AUXPCM_PRIM_INTF);
ret = mdm9625_mi2s_clk_ctl(rtd, false);
if (ret < 0)
pr_err("%s:clock disable failed\n", __func__);
@@ -279,7 +293,17 @@
int ret = 0;
if (atomic_inc_return(&mi2s_ref_count) == 1) {
- mdm9625_set_mi2s_gpio(substream, MDM_MI2S_PRIM_INTF);
+ if (lpaif_pri_muxsel_virt_addr != NULL)
+ iowrite32(I2S_SEL << I2S_PCM_SEL_OFFSET,
+ lpaif_pri_muxsel_virt_addr);
+ else
+ pr_err("%s lpaif_pri_muxsel_virt_addr is NULL\n",
+ __func__);
+ ret = mdm9625_set_gpio(substream, MDM_MI2S_AUXPCM_PRIM_INTF);
+ if (ret < 0) {
+ pr_err("%s, GPIO setup failed\n", __func__);
+ return ret;
+ }
ret = mdm9625_mi2s_clk_ctl(rtd, true);
if (ret < 0) {
pr_err("set format for codec dai failed\n");
@@ -470,6 +494,83 @@
return 0;
}
+static int mdm9625_auxpcm_startup(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ int ret = 0;
+
+ if (atomic_inc_return(&aux_ref_count) == 1) {
+ if (lpaif_pri_muxsel_virt_addr != NULL)
+ iowrite32(I2S_PCM_SEL << I2S_PCM_SEL_OFFSET,
+ lpaif_pri_muxsel_virt_addr);
+ else
+ pr_err("%s lpaif_pri_muxsel_virt_addr is NULL\n",
+ __func__);
+ ret = mdm9625_set_gpio(substream, MDM_MI2S_AUXPCM_PRIM_INTF);
+ if (ret < 0) {
+ pr_err("%s, GPIO setup failed\n", __func__);
+ return ret;
+ }
+ ret = mdm9625_mi2s_clk_ctl(rtd, true);
+ if (ret < 0) {
+ pr_err("set format for codec dai failed\n");
+ return ret;
+ }
+ }
+ return ret;
+}
+
+static void mdm9625_auxpcm_snd_shutdown(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ int ret;
+
+ if (atomic_dec_return(&aux_ref_count) == 0) {
+ mdm9625_mi2s_free_gpios(substream, MDM_MI2S_AUXPCM_PRIM_INTF);
+ ret = mdm9625_mi2s_clk_ctl(rtd, false);
+ if (ret < 0)
+ pr_err("%s:clock disable failed\n", __func__);
+ }
+}
+
+static int mdm9625_auxpcm_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = mdm9625_auxpcm_rate;
+ return 0;
+}
+
+static int mdm9625_auxpcm_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ switch (ucontrol->value.integer.value[0]) {
+ case 0:
+ mdm9625_auxpcm_rate = 8000;
+ break;
+ case 1:
+ mdm9625_auxpcm_rate = 16000;
+ break;
+ default:
+ mdm9625_auxpcm_rate = 8000;
+ break;
+ }
+ return 0;
+}
+
+static int mdm9625_auxpcm_be_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate =
+ hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+
+ struct snd_interval *channels =
+ hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ rate->min = rate->max = mdm9625_auxpcm_rate;
+ channels->min = channels->max = 1;
+
+ return 0;
+}
static const struct snd_soc_dapm_widget mdm9625_dapm_widgets[] = {
@@ -494,23 +595,28 @@
static const char *const spk_function[] = {"Off", "On"};
static const char *const mi2s_rx_ch_text[] = {"One", "Two"};
static const char *const mi2s_tx_ch_text[] = {"One", "Two"};
+static const char *const auxpcm_rate_text[] = {"rate_8000", "rate_16000"};
static const struct soc_enum mdm9625_enum[] = {
SOC_ENUM_SINGLE_EXT(2, spk_function),
SOC_ENUM_SINGLE_EXT(2, mi2s_rx_ch_text),
SOC_ENUM_SINGLE_EXT(2, mi2s_tx_ch_text),
+ SOC_ENUM_SINGLE_EXT(2, auxpcm_rate_text),
};
static const struct snd_kcontrol_new mdm_snd_controls[] = {
- SOC_ENUM_EXT("Speaker Function", mdm9625_enum[0],
+ SOC_ENUM_EXT("Speaker Function", mdm9625_enum[0],
mdm9625_mi2s_get_spk,
mdm9625_mi2s_set_spk),
- SOC_ENUM_EXT("MI2S_RX Channels", mdm9625_enum[1],
+ SOC_ENUM_EXT("MI2S_RX Channels", mdm9625_enum[1],
mdm9625_mi2s_rx_ch_get,
mdm9625_mi2s_rx_ch_put),
- SOC_ENUM_EXT("MI2S_TX Channels", mdm9625_enum[2],
+ SOC_ENUM_EXT("MI2S_TX Channels", mdm9625_enum[2],
mdm9625_mi2s_tx_ch_get,
mdm9625_mi2s_tx_ch_put),
+ SOC_ENUM_EXT("AUX PCM SampleRate", mdm9625_enum[3],
+ mdm9625_auxpcm_rate_get,
+ mdm9625_auxpcm_rate_put),
};
static int mdm9625_mi2s_audrx_init(struct snd_soc_pcm_runtime *rtd)
@@ -631,6 +737,11 @@
.shutdown = mdm9625_mi2s_snd_shutdown,
};
+static struct snd_soc_ops mdm9625_auxpcm_be_ops = {
+ .startup = mdm9625_auxpcm_startup,
+ .shutdown = mdm9625_auxpcm_snd_shutdown,
+};
+
/* Digital audio interface connects codec <---> CPU */
static struct snd_soc_dai_link mdm9625_dai[] = {
/* FrontEnd DAI Links */
@@ -799,6 +910,32 @@
.no_pcm = 1,
.be_id = MSM_BACKEND_DAI_AFE_PCM_TX,
},
+ {
+ .name = LPASS_BE_AUXPCM_RX,
+ .stream_name = "AUX PCM Playback",
+ .cpu_dai_name = "msm-dai-q6.4106",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_AUXPCM_RX,
+ .be_hw_params_fixup = mdm9625_auxpcm_be_params_fixup,
+ .ops = &mdm9625_auxpcm_be_ops,
+ .ignore_pmdown_time = 1,
+ /* this dainlink has playback support */
+ },
+ {
+ .name = LPASS_BE_AUXPCM_TX,
+ .stream_name = "AUX PCM Capture",
+ .cpu_dai_name = "msm-dai-q6.4107",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_AUXPCM_TX,
+ .be_hw_params_fixup = mdm9625_auxpcm_be_params_fixup,
+ .ops = &mdm9625_auxpcm_be_ops,
+ },
};
static struct snd_soc_card snd_soc_card_mdm9625 = {
@@ -807,7 +944,7 @@
.num_links = ARRAY_SIZE(mdm9625_dai),
};
-static int mdm9625_dtparse_mi2s(struct platform_device *pdev,
+static int mdm9625_dtparse(struct platform_device *pdev,
struct mdm9625_machine_data **pdata)
{
int ret = 0, i = 0;
@@ -920,10 +1057,10 @@
ret = -ENOMEM;
goto err;
}
- ret = mdm9625_dtparse_mi2s(pdev, &pdata);
+ ret = mdm9625_dtparse(pdev, &pdata);
if (ret) {
dev_err(&pdev->dev,
- "%s: mi2s Pin data parse failed",
+ "%s: mi2s-aux Pin data parse failed",
__func__);
goto err;
}
@@ -960,6 +1097,14 @@
ret);
goto err;
}
+
+ lpaif_pri_muxsel_virt_addr = ioremap(LPAIF_PRI_MODE_MUXSEL, 4);
+ if (lpaif_pri_muxsel_virt_addr == NULL) {
+ pr_err("%s Pri muxsel virt addr is null\n", __func__);
+ ret = -EINVAL;
+ goto err;
+ }
+
return 0;
err:
devm_kfree(&pdev->dev, pdata);
diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c
index 3f0c1d7..96709be 100644
--- a/sound/soc/msm/msm-dai-fe.c
+++ b/sound/soc/msm/msm-dai-fe.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -24,7 +24,8 @@
/* Conventional and unconventional sample rate supported */
static unsigned int supported_sample_rates[] = {
- 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
+ 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000,
+ 96000
};
static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
@@ -52,13 +53,14 @@
.playback = {
.stream_name = "Multimedia1 Playback",
.aif_name = "MM_DL1",
- .rates = (SNDRV_PCM_RATE_8000_48000|
+ .rates = (SNDRV_PCM_RATE_8000_96000|
SNDRV_PCM_RATE_KNOT),
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 96000,
},
.capture = {
.stream_name = "Multimedia1 Capture",
@@ -78,13 +80,14 @@
.playback = {
.stream_name = "Multimedia2 Playback",
.aif_name = "MM_DL2",
- .rates = (SNDRV_PCM_RATE_8000_48000|
+ .rates = (SNDRV_PCM_RATE_8000_96000|
SNDRV_PCM_RATE_KNOT),
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 96000,
},
.capture = {
.stream_name = "Multimedia2 Capture",
@@ -154,13 +157,14 @@
.playback = {
.stream_name = "MultiMedia3 Playback",
.aif_name = "MM_DL3",
- .rates = (SNDRV_PCM_RATE_8000_48000 |
+ .rates = (SNDRV_PCM_RATE_8000_96000 |
SNDRV_PCM_RATE_KNOT),
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
.channels_min = 1,
.channels_max = 6,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 96000,
},
.ops = &msm_fe_Multimedia_dai_ops,
.name = "MultiMedia3",
@@ -169,13 +173,14 @@
.playback = {
.stream_name = "MultiMedia4 Playback",
.aif_name = "MM_DL4",
- .rates = (SNDRV_PCM_RATE_8000_48000 |
+ .rates = (SNDRV_PCM_RATE_8000_96000 |
SNDRV_PCM_RATE_KNOT),
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 96000,
},
.capture = {
.stream_name = "MultiMedia4 Capture",
@@ -195,13 +200,14 @@
.playback = {
.stream_name = "MultiMedia5 Playback",
.aif_name = "MM_DL5",
- .rates = (SNDRV_PCM_RATE_8000_48000 |
+ .rates = (SNDRV_PCM_RATE_8000_96000 |
SNDRV_PCM_RATE_KNOT),
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 96000,
},
.capture = {
.stream_name = "MultiMedia5 Capture",
@@ -221,13 +227,14 @@
.playback = {
.stream_name = "MultiMedia6 Playback",
.aif_name = "MM_DL6",
- .rates = (SNDRV_PCM_RATE_8000_48000 |
+ .rates = (SNDRV_PCM_RATE_8000_96000 |
SNDRV_PCM_RATE_KNOT),
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 96000,
},
.ops = &msm_fe_Multimedia_dai_ops,
.name = "MultiMedia6",
@@ -236,13 +243,14 @@
.playback = {
.stream_name = "MultiMedia7 Playback",
.aif_name = "MM_DL7",
- .rates = (SNDRV_PCM_RATE_8000_48000 |
+ .rates = (SNDRV_PCM_RATE_8000_96000 |
SNDRV_PCM_RATE_KNOT),
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 96000,
},
.ops = &msm_fe_Multimedia_dai_ops,
.name = "MultiMedia7",
@@ -251,13 +259,14 @@
.playback = {
.stream_name = "MultiMedia8 Playback",
.aif_name = "MM_DL8",
- .rates = (SNDRV_PCM_RATE_8000_48000 |
+ .rates = (SNDRV_PCM_RATE_8000_96000 |
SNDRV_PCM_RATE_KNOT),
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 96000,
},
.ops = &msm_fe_Multimedia_dai_ops,
.name = "MultiMedia8",
@@ -267,8 +276,9 @@
.playback = {
.stream_name = "SLIMBUS0 Hostless Playback",
.aif_name = "SLIM0_DL_HL",
- .rates = SNDRV_PCM_RATE_8000_48000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
@@ -277,7 +287,7 @@
.capture = {
.stream_name = "SLIMBUS0 Hostless Capture",
.aif_name = "SLIM0_UL_HL",
- .rates = SNDRV_PCM_RATE_8000_48000,
+ .rates = SNDRV_PCM_RATE_8000_96000,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.channels_min = 1,
.channels_max = 8,
@@ -291,12 +301,13 @@
.playback = {
.stream_name = "SLIMBUS1 Hostless Playback",
.aif_name = "SLIM1_DL_HL",
- .rates = SNDRV_PCM_RATE_8000_48000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
.channels_min = 1,
.channels_max = 2,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 96000,
},
.capture = {
.stream_name = "SLIMBUS1 Hostless Capture",
@@ -316,7 +327,8 @@
.stream_name = "SLIMBUS3 Hostless Playback",
.aif_name = "SLIM3_DL_HL",
.rates = SNDRV_PCM_RATE_8000_48000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
.channels_min = 1,
.channels_max = 2,
.rate_min = 8000,
@@ -339,8 +351,9 @@
.playback = {
.stream_name = "SLIMBUS4 Hostless Playback",
.aif_name = "SLIM4_DL_HL",
- .rates = SNDRV_PCM_RATE_8000_48000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
.channels_min = 1,
.channels_max = 2,
.rate_min = 8000,
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index 7c5e599..91e5e67 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -26,6 +26,7 @@
#include <sound/jack.h>
#include <asm/mach-types.h>
#include <mach/socinfo.h>
+#include <sound/pcm_params.h>
#include <qdsp6v2/msm-pcm-routing-v2.h>
#include "../codecs/wcd9320.h"
#include <linux/io.h>
@@ -41,6 +42,11 @@
#define BTSCO_RATE_8KHZ 8000
#define BTSCO_RATE_16KHZ 16000
+static int slim0_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE;
+
+#define SAMPLING_RATE_48KHZ 48000
+#define SAMPLING_RATE_96KHZ 96000
+
static int msm8974_auxpcm_rate = 8000;
#define LO_1_SPK_AMP 0x1
#define LO_3_SPK_AMP 0x2
@@ -68,6 +74,29 @@
#define NUM_OF_AUXPCM_GPIOS 4
+static inline int param_is_mask(int p)
+{
+ return ((p >= SNDRV_PCM_HW_PARAM_FIRST_MASK) &&
+ (p <= SNDRV_PCM_HW_PARAM_LAST_MASK));
+}
+
+static inline struct snd_mask *param_to_mask(struct snd_pcm_hw_params *p, int n)
+{
+ return &(p->masks[n - SNDRV_PCM_HW_PARAM_FIRST_MASK]);
+}
+
+static void param_set_mask(struct snd_pcm_hw_params *p, int n, unsigned bit)
+{
+ if (bit >= SNDRV_MASK_MAX)
+ return;
+ if (param_is_mask(n)) {
+ struct snd_mask *m = param_to_mask(p, n);
+ m->bits[0] = 0;
+ m->bits[1] = 0;
+ m->bits[bit >> 5] |= (1 << (bit & 31));
+ }
+}
+
static const char *const auxpcm_rate_text[] = {"rate_8000", "rate_16000"};
static const struct soc_enum msm8974_auxpcm_enum[] = {
SOC_ENUM_SINGLE_EXT(2, auxpcm_rate_text),
@@ -150,6 +179,7 @@
static int msm_btsco_rate = BTSCO_RATE_8KHZ;
static int msm_btsco_ch = 1;
static int msm_hdmi_rx_ch = 2;
+static int slim0_rx_sample_rate = SAMPLING_RATE_48KHZ;
static struct mutex cdc_mclk_mutex;
static struct q_clkdiv *codec_clk;
@@ -543,6 +573,8 @@
static const char *const slim0_tx_ch_text[] = {"One", "Two", "Three", "Four"};
static char const *hdmi_rx_ch_text[] = {"Two", "Three", "Four", "Five",
"Six", "Seven", "Eight"};
+static char const *rx_bit_format_text[] = {"S16_LE", "S24_LE"};
+static char const *slim0_rx_sample_rate_text[] = {"KHZ_48", "KHZ_96"};
static const struct soc_enum msm_enum[] = {
SOC_ENUM_SINGLE_EXT(2, spk_function),
@@ -555,6 +587,87 @@
SOC_ENUM_SINGLE_EXT(2, btsco_rate_text),
};
+static int slim0_rx_sample_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int sample_rate_val = 0;
+
+ switch (slim0_rx_sample_rate) {
+ case SAMPLING_RATE_96KHZ:
+ sample_rate_val = 1;
+ break;
+
+ case SAMPLING_RATE_48KHZ:
+ default:
+ sample_rate_val = 0;
+ break;
+ }
+
+ ucontrol->value.integer.value[0] = sample_rate_val;
+ pr_debug("%s: slim0_rx_sample_rate = %d\n", __func__,
+ slim0_rx_sample_rate);
+
+ return 0;
+}
+
+static int slim0_rx_sample_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: ucontrol value = %ld\n", __func__,
+ ucontrol->value.integer.value[0]);
+
+ switch (ucontrol->value.integer.value[0]) {
+ case 1:
+ slim0_rx_sample_rate = SAMPLING_RATE_96KHZ;
+ break;
+ case 0:
+ default:
+ slim0_rx_sample_rate = SAMPLING_RATE_48KHZ;
+ }
+
+ pr_debug("%s: slim0_rx_sample_rate = %d\n", __func__,
+ slim0_rx_sample_rate);
+
+ return 0;
+}
+
+static int slim0_rx_bit_format_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+
+ switch (slim0_rx_bit_format) {
+ case SNDRV_PCM_FORMAT_S24_LE:
+ ucontrol->value.integer.value[0] = 1;
+ break;
+
+ case SNDRV_PCM_FORMAT_S16_LE:
+ default:
+ ucontrol->value.integer.value[0] = 0;
+ break;
+ }
+
+ pr_debug("%s: slim0_rx_bit_format = %d, ucontrol value = %ld\n",
+ __func__, slim0_rx_bit_format,
+ ucontrol->value.integer.value[0]);
+
+ return 0;
+}
+
+static int slim0_rx_bit_format_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ switch (ucontrol->value.integer.value[0]) {
+ case 1:
+ slim0_rx_bit_format = SNDRV_PCM_FORMAT_S24_LE;
+ break;
+ case 0:
+ default:
+ slim0_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE;
+ break;
+ }
+ return 0;
+}
+
static int msm_slim_0_rx_ch_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -861,9 +974,15 @@
hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
pr_debug("%s()\n", __func__);
- rate->min = rate->max = 48000;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ slim0_rx_bit_format);
+ rate->min = rate->max = slim0_rx_sample_rate;
channels->min = channels->max = msm_slim_0_rx_ch;
+ pr_debug("%s: format = %d, rate = %d, channels = %d\n",
+ __func__, params_format(params), params_rate(params),
+ msm_slim_0_rx_ch);
+
return 0;
}
@@ -900,6 +1019,8 @@
SOC_ENUM_SINGLE_EXT(2, slim0_rx_ch_text),
SOC_ENUM_SINGLE_EXT(4, slim0_tx_ch_text),
SOC_ENUM_SINGLE_EXT(7, hdmi_rx_ch_text),
+ SOC_ENUM_SINGLE_EXT(2, rx_bit_format_text),
+ SOC_ENUM_SINGLE_EXT(2, slim0_rx_sample_rate_text),
};
static const struct snd_kcontrol_new msm_snd_controls[] = {
@@ -913,6 +1034,10 @@
msm8974_auxpcm_rate_get, msm8974_auxpcm_rate_put),
SOC_ENUM_EXT("HDMI_RX Channels", msm_snd_enum[3],
msm_hdmi_rx_ch_get, msm_hdmi_rx_ch_put),
+ SOC_ENUM_EXT("SLIM_0_RX Format", msm_snd_enum[4],
+ slim0_rx_bit_format_get, slim0_rx_bit_format_put),
+ SOC_ENUM_EXT("SLIM_0_RX SampleRate", msm_snd_enum[5],
+ slim0_rx_sample_rate_get, slim0_rx_sample_rate_put),
};
static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
@@ -1213,7 +1338,7 @@
.name = "MSM8974 Media1",
.stream_name = "MultiMedia1",
.cpu_dai_name = "MultiMedia1",
- .platform_name = "msm-pcm-dsp",
+ .platform_name = "msm-pcm-dsp.0",
.dynamic = 1,
.trigger = {SND_SOC_DPCM_TRIGGER_POST,
SND_SOC_DPCM_TRIGGER_POST},
@@ -1228,7 +1353,7 @@
.name = "MSM8974 Media2",
.stream_name = "MultiMedia2",
.cpu_dai_name = "MultiMedia2",
- .platform_name = "msm-pcm-dsp",
+ .platform_name = "msm-pcm-dsp.0",
.dynamic = 1,
.codec_dai_name = "snd-soc-dummy-dai",
.codec_name = "snd-soc-dummy",
@@ -1423,6 +1548,21 @@
.codec_name = "snd-soc-dummy",
.be_id = MSM_FRONTEND_DAI_VOLTE,
},
+ {
+ .name = "MSM8974 LowLatency",
+ .stream_name = "MultiMedia5",
+ .cpu_dai_name = "MultiMedia5",
+ .platform_name = "msm-pcm-dsp.1",
+ .dynamic = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA5,
+ },
/* Backend BT/FM DAI Links */
{
.name = LPASS_BE_INT_BT_SCO_RX,
diff --git a/sound/soc/msm/qdsp6v2/audio_acdb.c b/sound/soc/msm/qdsp6v2/audio_acdb.c
index 58fdc1b..b71132e 100644
--- a/sound/soc/msm/qdsp6v2/audio_acdb.c
+++ b/sound/soc/msm/qdsp6v2/audio_acdb.c
@@ -66,6 +66,12 @@
/* VocProc dev cfg cal*/
struct acdb_atomic_cal_block vocproc_dev_cal;
+ /* Custom topology */
+ struct acdb_atomic_cal_block adm_custom_topology;
+ struct acdb_atomic_cal_block asm_custom_topology;
+ atomic_t valid_adm_custom_top;
+ atomic_t valid_asm_custom_top;
+
/* AFE cal */
struct acdb_atomic_cal_block afe_cal[MAX_AUDPROC_TYPES];
@@ -134,6 +140,106 @@
atomic_set(&acdb_data.asm_topology, topology);
}
+void reset_custom_topology_flags(void)
+{
+ atomic_set(&acdb_data.valid_adm_custom_top, 1);
+ atomic_set(&acdb_data.valid_asm_custom_top, 1);
+}
+
+void get_adm_custom_topology(struct acdb_cal_block *cal_block)
+{
+ pr_debug("%s\n", __func__);
+
+ if (cal_block == NULL) {
+ pr_err("ACDB=> NULL pointer sent to %s\n", __func__);
+ goto done;
+ }
+
+ if (atomic_read(&acdb_data.valid_adm_custom_top) == 0) {
+ cal_block->cal_size = 0;
+ goto done;
+ }
+ atomic_set(&acdb_data.valid_adm_custom_top, 0);
+
+ cal_block->cal_size =
+ atomic_read(&acdb_data.adm_custom_topology.cal_size);
+ cal_block->cal_paddr =
+ atomic_read(&acdb_data.adm_custom_topology.cal_paddr);
+ cal_block->cal_kvaddr =
+ atomic_read(&acdb_data.adm_custom_topology.cal_kvaddr);
+done:
+ return;
+}
+
+void store_adm_custom_topology(struct cal_block *cal_block)
+{
+ pr_debug("%s,\n", __func__);
+
+ if (cal_block->cal_offset > atomic64_read(&acdb_data.mem_len)) {
+ pr_err("%s: offset %d is > mem_len %ld\n",
+ __func__, cal_block->cal_offset,
+ (long)atomic64_read(&acdb_data.mem_len));
+ goto done;
+ }
+
+ atomic_set(&acdb_data.adm_custom_topology.cal_size,
+ cal_block->cal_size);
+ atomic_set(&acdb_data.adm_custom_topology.cal_paddr,
+ cal_block->cal_offset + atomic64_read(&acdb_data.paddr));
+ atomic_set(&acdb_data.adm_custom_topology.cal_kvaddr,
+ cal_block->cal_offset +
+ atomic64_read(&acdb_data.kvaddr));
+done:
+ return;
+}
+
+void get_asm_custom_topology(struct acdb_cal_block *cal_block)
+{
+ pr_debug("%s\n", __func__);
+
+ if (cal_block == NULL) {
+ pr_err("ACDB=> NULL pointer sent to %s\n", __func__);
+ goto done;
+ }
+
+ if (atomic_read(&acdb_data.valid_asm_custom_top) == 0) {
+ cal_block->cal_size = 0;
+ goto done;
+ }
+ atomic_set(&acdb_data.valid_asm_custom_top, 0);
+
+ cal_block->cal_size =
+ atomic_read(&acdb_data.asm_custom_topology.cal_size);
+ cal_block->cal_paddr =
+ atomic_read(&acdb_data.asm_custom_topology.cal_paddr);
+ cal_block->cal_kvaddr =
+ atomic_read(&acdb_data.asm_custom_topology.cal_kvaddr);
+done:
+ return;
+}
+
+void store_asm_custom_topology(struct cal_block *cal_block)
+{
+ pr_debug("%s,\n", __func__);
+
+ if (cal_block->cal_offset > atomic64_read(&acdb_data.mem_len)) {
+ pr_err("%s: offset %d is > mem_len %ld\n",
+ __func__, cal_block->cal_offset,
+ (long)atomic64_read(&acdb_data.mem_len));
+ goto done;
+ }
+
+ atomic_set(&acdb_data.asm_custom_topology.cal_size,
+ cal_block->cal_size);
+ atomic_set(&acdb_data.asm_custom_topology.cal_paddr,
+ cal_block->cal_offset + atomic64_read(&acdb_data.paddr));
+ atomic_set(&acdb_data.asm_custom_topology.cal_kvaddr,
+ cal_block->cal_offset +
+ atomic64_read(&acdb_data.kvaddr));
+done:
+ return;
+}
+
void get_voice_cal_allocation(struct acdb_cal_block *cal_block)
{
cal_block->cal_size = ACDB_TOTAL_VOICE_ALLOCATION;
@@ -672,6 +778,8 @@
__func__);
}
+ atomic_set(&acdb_data.valid_adm_custom_top, 1);
+ atomic_set(&acdb_data.valid_asm_custom_top, 1);
atomic_inc(&usage_count);
return result;
}
@@ -925,6 +1033,12 @@
case AUDIO_SET_LSM_CAL:
store_lsm_cal((struct cal_block *)data);
goto done;
+ case AUDIO_SET_ADM_CUSTOM_TOPOLOGY:
+ store_adm_custom_topology((struct cal_block *)data);
+ goto done;
+ case AUDIO_SET_ASM_CUSTOM_TOPOLOGY:
+ store_asm_custom_topology((struct cal_block *)data);
+ goto done;
default:
pr_err("ACDB=> ACDB ioctl not found!\n");
}
@@ -998,6 +1112,8 @@
memset(&acdb_data, 0, sizeof(acdb_data));
mutex_init(&acdb_data.acdb_mutex);
atomic_set(&usage_count, 0);
+ atomic_set(&acdb_data.valid_adm_custom_top, 1);
+ atomic_set(&acdb_data.valid_asm_custom_top, 1);
return misc_register(&acdb_misc);
}
diff --git a/sound/soc/msm/qdsp6v2/audio_acdb.h b/sound/soc/msm/qdsp6v2/audio_acdb.h
index 8528e3c..0b6110d 100644
--- a/sound/soc/msm/qdsp6v2/audio_acdb.h
+++ b/sound/soc/msm/qdsp6v2/audio_acdb.h
@@ -46,6 +46,9 @@
uint32_t get_adm_rx_topology(void);
uint32_t get_adm_tx_topology(void);
uint32_t get_asm_topology(void);
+void reset_custom_topology_flags(void);
+void get_adm_custom_topology(struct acdb_cal_block *cal_block);
+void get_asm_custom_topology(struct acdb_cal_block *cal_block);
void get_voice_cal_allocation(struct acdb_cal_block *cal_block);
void get_lsm_cal(struct acdb_cal_block *cal_block);
void get_anc_cal(struct acdb_cal_block *cal_block);
diff --git a/sound/soc/msm/qdsp6v2/audio_ocmem.c b/sound/soc/msm/qdsp6v2/audio_ocmem.c
index 145f095..1969fe8 100644
--- a/sound/soc/msm/qdsp6v2/audio_ocmem.c
+++ b/sound/soc/msm/qdsp6v2/audio_ocmem.c
@@ -30,6 +30,15 @@
#define AUDIO_OCMEM_BUF_SIZE (512 * SZ_1K)
+#define _BIT_MASK_\
+ ((1 << OCMEM_STATE_EXIT) |\
+ (1 << OCMEM_STATE_GROW) |\
+ (1 << OCMEM_STATE_SHRINK))
+
+#define set_bit_pos(x, y) (atomic_set(&x, (atomic_read(&x) | (1 << y))))
+#define clear_bit_pos(x, y) (atomic_set(&x, (atomic_read(&x) & (~(1 << y)))))
+#define test_bit_pos(x, y) ((atomic_read(&x)) & (1 << y))
+
static int enable_ocmem_audio_voice = 1;
module_param(enable_ocmem_audio_voice, int,
S_IRUGO | S_IWUSR | S_IWGRP);
@@ -48,6 +57,8 @@
OCMEM_STATE_MAP_FAIL,
OCMEM_STATE_UNMAP_FAIL,
OCMEM_STATE_EXIT,
+ OCMEM_STATE_SSR,
+ OCMEM_STATE_DISABLE,
};
static void audio_ocmem_process_workdata(struct work_struct *work);
@@ -74,6 +85,7 @@
atomic_t audio_cond;
atomic_t audio_exit;
spinlock_t audio_lock;
+ struct mutex protect_lock;
struct workqueue_struct *audio_ocmem_workqueue;
struct workqueue_struct *voice_ocmem_workqueue;
bool ocmem_en;
@@ -81,7 +93,6 @@
static struct audio_ocmem_prv audio_ocmem_lcl;
-
static int audio_ocmem_client_cb(struct notifier_block *this,
unsigned long event1, void *data)
{
@@ -97,7 +108,9 @@
switch (event1) {
case OCMEM_MAP_DONE:
pr_debug("%s: map done\n", __func__);
- atomic_set(&audio_ocmem_lcl.audio_state, OCMEM_STATE_MAP_COMPL);
+ clear_bit_pos(audio_ocmem_lcl.audio_state,
+ OCMEM_STATE_MAP_TRANSITION);
+ set_bit_pos(audio_ocmem_lcl.audio_state, OCMEM_STATE_MAP_COMPL);
break;
case OCMEM_MAP_FAIL:
pr_debug("%s: map fail\n", __func__);
@@ -105,7 +118,9 @@
break;
case OCMEM_UNMAP_DONE:
pr_debug("%s: unmap done\n", __func__);
- atomic_set(&audio_ocmem_lcl.audio_state,
+ clear_bit_pos(audio_ocmem_lcl.audio_state,
+ OCMEM_STATE_UNMAP_TRANSITION);
+ set_bit_pos(audio_ocmem_lcl.audio_state,
OCMEM_STATE_UNMAP_COMPL);
break;
case OCMEM_UNMAP_FAIL:
@@ -115,13 +130,13 @@
break;
case OCMEM_ALLOC_GROW:
rbuf = data;
- if (rbuf->len == AUDIO_OCMEM_BUF_SIZE) {
+ if ((rbuf->len == AUDIO_OCMEM_BUF_SIZE)) {
audio_ocmem_lcl.buf = data;
pr_debug("%s: Alloc grow request received buf->addr: 0x%08lx\n",
__func__,
(audio_ocmem_lcl.buf)->addr);
- atomic_set(&audio_ocmem_lcl.audio_state,
- OCMEM_STATE_GROW);
+ set_bit_pos(audio_ocmem_lcl.audio_state,
+ OCMEM_STATE_GROW);
} else {
pr_debug("%s: Alloc grow request with size: %ld",
__func__,
@@ -132,19 +147,33 @@
break;
case OCMEM_ALLOC_SHRINK:
pr_debug("%s: Alloc shrink request received\n", __func__);
- atomic_set(&audio_ocmem_lcl.audio_state, OCMEM_STATE_SHRINK);
+ set_bit_pos(audio_ocmem_lcl.audio_state, OCMEM_STATE_SHRINK);
break;
default:
pr_err("%s: Invalid event[%ld]\n", __func__, event1);
break;
}
spin_unlock_irqrestore(&audio_ocmem_lcl.audio_lock, flags);
- if (!vwait && (atomic_read(&audio_ocmem_lcl.audio_cond))) {
atomic_set(&audio_ocmem_lcl.audio_cond, 0);
wake_up(&audio_ocmem_lcl.audio_wait);
- }
return rc;
}
+int get_state_to_process(atomic_t *state)
+{
+
+ if (test_bit_pos((*state), OCMEM_STATE_SHRINK)) {
+ pr_debug("%s: returning shrink state\n", __func__);
+ return OCMEM_STATE_SHRINK;
+ } else if (test_bit_pos((*state), OCMEM_STATE_GROW)) {
+ pr_debug("%s: returning grow state\n", __func__);
+ return OCMEM_STATE_GROW;
+ } else if (test_bit_pos((*state), OCMEM_STATE_EXIT)) {
+ pr_debug("%s: returning exit state\n", __func__);
+ return OCMEM_STATE_EXIT;
+ } else
+ return -EINVAL;
+
+}
/**
* audio_ocmem_enable() - Exercise OCMEM for audio
@@ -159,36 +188,12 @@
{
int ret;
int i, j;
+ int state_bit;
struct ocmem_buf *buf = NULL;
struct avcs_cmd_rsp_get_low_power_segments_info_t *lp_segptr;
pr_debug("%s\n", __func__);
- /* Non-blocking ocmem allocate (asynchronous) */
- buf = ocmem_allocate_nb(cid, AUDIO_OCMEM_BUF_SIZE);
- if (IS_ERR_OR_NULL(buf)) {
- pr_err("%s: failed: %d\n", __func__, cid);
- return -ENOMEM;
- }
- atomic_set(&audio_ocmem_lcl.audio_state, OCMEM_STATE_ALLOC);
-
- 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__);
- ret = -EINVAL;
- goto fail_cmd;
- }
- }
- pr_debug("%s: buf->len: %ld\n", __func__, (audio_ocmem_lcl.buf)->len);
+ atomic_set(&audio_ocmem_lcl.audio_state, OCMEM_STATE_DEFAULT);
if (audio_ocmem_lcl.lp_memseg_ptr == NULL) {
/* Retrieve low power segments */
ret = core_get_low_power_segments(
@@ -213,6 +218,42 @@
(uint32_t)audio_ocmem_lcl.mlist.chunks[j].ddr_paddr,
(uint32_t)audio_ocmem_lcl.mlist.chunks[j].size);
}
+ /* Non-blocking ocmem allocate (asynchronous) */
+ buf = ocmem_allocate_nb(cid, AUDIO_OCMEM_BUF_SIZE);
+ if (IS_ERR_OR_NULL(buf)) {
+ pr_err("%s: failed: %d\n", __func__, cid);
+ return -ENOMEM;
+ }
+
+ set_bit_pos(audio_ocmem_lcl.audio_state, OCMEM_STATE_ALLOC);
+
+ 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__);
+ mutex_unlock(&audio_ocmem_lcl.protect_lock);
+ 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)) {
+ ret = ocmem_free(OCMEM_LP_AUDIO, audio_ocmem_lcl.buf);
+ if (ret) {
+ pr_err("%s: ocmem_free failed, state[%d]\n",
+ __func__,
+ atomic_read(&audio_ocmem_lcl.audio_state));
+ }
+ pr_info("%s: audio playback ended while waiting for ocmem\n",
+ __func__);
+ ret = 0;
+ goto fail_cmd;
+ }
+ clear_bit_pos(audio_ocmem_lcl.audio_state, OCMEM_STATE_GROW);
+ mutex_trylock(&audio_ocmem_lcl.protect_lock);
+ }
+ pr_debug("%s: buf->len: %ld\n", __func__, (audio_ocmem_lcl.buf)->len);
/* vote for ocmem bus bandwidth */
ret = msm_bus_scale_client_update_request(
@@ -221,7 +262,7 @@
if (ret)
pr_err("%s: failed to vote for bus bandwidth\n", __func__);
- atomic_set(&audio_ocmem_lcl.audio_state, OCMEM_STATE_MAP_TRANSITION);
+ set_bit_pos(audio_ocmem_lcl.audio_state, OCMEM_STATE_MAP_TRANSITION);
pr_debug("%s: buf->addr: 0x%08lx, len: %ld, audio_state[0x%x]\n",
__func__,
@@ -236,16 +277,25 @@
atomic_set(&audio_ocmem_lcl.audio_state, OCMEM_STATE_MAP_FAIL);
}
+ wait_event_interruptible(audio_ocmem_lcl.audio_wait,
+ test_bit_pos(audio_ocmem_lcl.audio_state,
+ OCMEM_STATE_MAP_COMPL) != 0);
+ atomic_set(&audio_ocmem_lcl.audio_cond, 1);
+
+ mutex_unlock(&audio_ocmem_lcl.protect_lock);
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)) {
+
+ while ((test_bit_pos(audio_ocmem_lcl.audio_state,
+ OCMEM_STATE_DISABLE)) == 0) {
wait_event_interruptible(audio_ocmem_lcl.audio_wait,
- atomic_read(&audio_ocmem_lcl.audio_cond) == 0);
+ (atomic_read(&audio_ocmem_lcl.audio_state) &
+ _BIT_MASK_) != 0);
- switch (atomic_read(&audio_ocmem_lcl.audio_state)) {
+ state_bit = get_state_to_process(&audio_ocmem_lcl.audio_state);
+ switch (state_bit) {
case OCMEM_STATE_MAP_COMPL:
pr_debug("%s: audio_cond[0x%x], audio_state[0x%x]\n",
__func__, atomic_read(&audio_ocmem_lcl.audio_cond),
@@ -258,6 +308,10 @@
pr_debug("%s: ocmem shrink request process\n",
__func__);
atomic_set(&audio_ocmem_lcl.audio_cond, 1);
+ clear_bit_pos(audio_ocmem_lcl.audio_state,
+ OCMEM_STATE_MAP_COMPL);
+ set_bit_pos(audio_ocmem_lcl.audio_state,
+ OCMEM_STATE_UNMAP_TRANSITION);
ret = ocmem_unmap(cid, audio_ocmem_lcl.buf,
&audio_ocmem_lcl.mlist);
if (ret) {
@@ -267,12 +321,9 @@
goto fail_cmd;
}
- atomic_set(&audio_ocmem_lcl.audio_state,
- OCMEM_STATE_UNMAP_TRANSITION);
wait_event_interruptible(audio_ocmem_lcl.audio_wait,
- atomic_read(&audio_ocmem_lcl.audio_cond) == 0);
- atomic_set(&audio_ocmem_lcl.audio_state,
- OCMEM_STATE_UNMAP_COMPL);
+ test_bit_pos(audio_ocmem_lcl.audio_state,
+ OCMEM_STATE_UNMAP_COMPL) != 0);
ret = ocmem_shrink(cid, audio_ocmem_lcl.buf, 0);
if (ret) {
pr_err("%s: ocmem_shrink failed, state[%d]\n",
@@ -281,11 +332,18 @@
goto fail_cmd;
}
atomic_set(&audio_ocmem_lcl.audio_cond, 1);
+ clear_bit_pos(audio_ocmem_lcl.audio_state,
+ OCMEM_STATE_SHRINK);
+ pr_debug("%s:shrink process complete\n", __func__);
break;
case OCMEM_STATE_GROW:
pr_debug("%s: ocmem grow request process\n",
__func__);
atomic_set(&audio_ocmem_lcl.audio_cond, 1);
+ clear_bit_pos(audio_ocmem_lcl.audio_state,
+ OCMEM_STATE_UNMAP_COMPL);
+ set_bit_pos(audio_ocmem_lcl.audio_state,
+ OCMEM_STATE_MAP_TRANSITION);
ret = ocmem_map(cid, audio_ocmem_lcl.buf,
&audio_ocmem_lcl.mlist);
if (ret) {
@@ -294,14 +352,102 @@
atomic_read(&audio_ocmem_lcl.audio_state));
goto fail_cmd;
}
- atomic_set(&audio_ocmem_lcl.audio_state,
- OCMEM_STATE_MAP_TRANSITION);
wait_event_interruptible(audio_ocmem_lcl.audio_wait,
- atomic_read(&audio_ocmem_lcl.audio_cond) == 0);
- atomic_set(&audio_ocmem_lcl.audio_state,
- OCMEM_STATE_MAP_COMPL);
+ test_bit_pos(audio_ocmem_lcl.audio_state,
+ OCMEM_STATE_MAP_COMPL) != 0);
+
+ clear_bit_pos(audio_ocmem_lcl.audio_state,
+ OCMEM_STATE_GROW);
atomic_set(&audio_ocmem_lcl.audio_cond, 1);
break;
+ case OCMEM_STATE_EXIT:
+ if (test_bit_pos(audio_ocmem_lcl.audio_state,
+ OCMEM_STATE_MAP_COMPL)) {
+ clear_bit_pos(audio_ocmem_lcl.audio_state,
+ OCMEM_STATE_MAP_COMPL);
+ set_bit_pos(audio_ocmem_lcl.audio_state,
+ OCMEM_STATE_UNMAP_TRANSITION);
+ ret = ocmem_unmap(cid, audio_ocmem_lcl.buf,
+ &audio_ocmem_lcl.mlist);
+ if (ret) {
+ pr_err("%s: ocmem_unmap failed, state[0x%x]\n",
+ __func__,
+ atomic_read(&audio_ocmem_lcl.audio_state));
+ goto fail_cmd;
+ }
+ wait_event_interruptible(
+ audio_ocmem_lcl.audio_wait,
+ test_bit_pos(audio_ocmem_lcl.audio_state,
+ OCMEM_STATE_UNMAP_COMPL) != 0);
+ }
+
+ if (test_bit_pos(audio_ocmem_lcl.audio_state,
+ OCMEM_STATE_SHRINK)) {
+ pr_debug("%s: SHRINK while exiting\n",
+ __func__);
+ ret = ocmem_shrink(cid, audio_ocmem_lcl.buf,
+ 0);
+ if (ret) {
+ pr_err("%s: ocmem_shrink failed, state[0x%x]\n",
+ __func__,
+ atomic_read(&audio_ocmem_lcl.audio_state));
+ goto fail_cmd;
+ }
+ clear_bit_pos(audio_ocmem_lcl.audio_state,
+ OCMEM_STATE_SHRINK);
+
+ }
+
+ pr_debug("%s: calling ocmem free\n", __func__);
+ ret = ocmem_free(OCMEM_LP_AUDIO, audio_ocmem_lcl.buf);
+ if (ret == -EAGAIN) {
+ pr_debug("%s: received EAGAIN\n", __func__);
+ if (test_bit_pos(audio_ocmem_lcl.audio_state,
+ OCMEM_STATE_SHRINK)) {
+ ret = ocmem_shrink(cid,
+ audio_ocmem_lcl.buf,
+ 0);
+ if (ret) {
+ pr_err("%s: ocmem_shrink failed, state[0x%x]\n",
+ __func__,
+ atomic_read(&audio_ocmem_lcl.audio_state));
+ goto fail_cmd;
+ }
+ pr_debug("calling free after EAGAIN");
+ ret = ocmem_free(OCMEM_LP_AUDIO,
+ audio_ocmem_lcl.buf);
+ if (ret) {
+ pr_err("%s: ocmem_free failed\n",
+ __func__);
+ goto fail_cmd;
+ }
+ } else {
+ pr_debug("%s: shrink callback already processed\n",
+ __func__);
+ goto fail_cmd;
+ }
+ } else if (ret) {
+ pr_err("%s: ocmem_free failed, state[0x%x], ret:%d\n",
+ __func__,
+ atomic_read(&audio_ocmem_lcl.audio_state),
+ ret);
+ goto fail_cmd;
+ }
+ pr_debug("%s: ocmem_free success\n", __func__);
+ msm_bus_scale_client_update_request(
+ audio_ocmem_lcl.audio_ocmem_bus_client,
+ 0);
+ set_bit_pos(audio_ocmem_lcl.audio_state,
+ OCMEM_STATE_DISABLE);
+ break;
+
+
+ case -EINVAL:
+ pr_info("%s: audio_cond[%d] audio_state[0x%x]\n",
+ __func__,
+ atomic_read(&audio_ocmem_lcl.audio_cond),
+ atomic_read(&audio_ocmem_lcl.audio_state));
+ break;
}
}
ret = 0;
@@ -320,64 +466,17 @@
*/
int audio_ocmem_disable(int cid)
{
- int ret;
- int cur_state;
-
- pr_debug("%s: disable\n", __func__);
- cur_state = atomic_read(&audio_ocmem_lcl.audio_state);
- if (atomic_cmpxchg(&audio_ocmem_lcl.audio_cond, 1, 0)) {
- atomic_set(&audio_ocmem_lcl.audio_state, OCMEM_STATE_EXIT);
- wake_up(&audio_ocmem_lcl.audio_wait);
- }
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));
- switch (cur_state) {
- case OCMEM_STATE_MAP_COMPL:
- atomic_set(&audio_ocmem_lcl.audio_cond, 1);
- ret = ocmem_unmap(cid, audio_ocmem_lcl.buf,
- &audio_ocmem_lcl.mlist);
- if (ret) {
- pr_err("%s: ocmem_unmap failed, state[%d]\n",
- __func__,
- atomic_read(&audio_ocmem_lcl.audio_state));
- goto fail_cmd;
- }
+ set_bit_pos(audio_ocmem_lcl.audio_state,
+ OCMEM_STATE_EXIT);
+ wake_up(&audio_ocmem_lcl.audio_wait);
- atomic_set(&audio_ocmem_lcl.audio_state, OCMEM_STATE_EXIT);
-
- wait_event_interruptible(audio_ocmem_lcl.audio_wait,
- atomic_read(&audio_ocmem_lcl.audio_cond) == 0);
- case OCMEM_STATE_UNMAP_COMPL:
- case OCMEM_STATE_MAP_FAIL:
- case OCMEM_STATE_MAP_TRANSITION:
- case OCMEM_STATE_ALLOC:
- ret = ocmem_free(OCMEM_LP_AUDIO, audio_ocmem_lcl.buf);
- if (ret) {
- pr_err("%s: ocmem_free failed, state[%d]\n",
- __func__,
- atomic_read(&audio_ocmem_lcl.audio_state));
- goto fail_cmd;
- }
- pr_debug("%s: state=%d", __func__,
- atomic_read(&audio_ocmem_lcl.audio_state));
- atomic_set(&audio_ocmem_lcl.audio_state, OCMEM_STATE_EXIT);
- pr_debug("%s: ocmem_free success\n", __func__);
- break;
-
- default:
- pr_debug("%s:error: state=%d", __func__,
- atomic_read(&audio_ocmem_lcl.audio_state));
- break;
-
- }
- msm_bus_scale_client_update_request(
- audio_ocmem_lcl.audio_ocmem_bus_client,
- 0);
+ mutex_unlock(&audio_ocmem_lcl.protect_lock);
+ pr_debug("%s: exit\n", __func__);
return 0;
-fail_cmd:
- return ret;
}
static void voice_ocmem_process_workdata(struct work_struct *work)
@@ -497,6 +596,10 @@
container_of(work, struct audio_ocmem_workdata, work);
en = audio_ocm_work->en;
+ mutex_lock(&audio_ocmem_lcl.protect_lock);
+ /* if previous work waiting for ocmem - signal it to exit */
+ atomic_set(&audio_ocmem_lcl.audio_exit, 1);
+ pr_debug("%s: acquired mutex for %d\n", __func__, en);
switch (audio_ocm_work->id) {
case AUDIO:
cid = OCMEM_LP_AUDIO;
@@ -548,9 +651,6 @@
workdata->id = id;
workdata->en = enable;
- /* if previous work waiting for ocmem - signal it to exit */
- atomic_set(&audio_ocmem_lcl.audio_exit, 1);
-
INIT_WORK(&workdata->work, audio_ocmem_process_workdata);
queue_work(audio_ocmem_lcl.audio_ocmem_workqueue,
&workdata->work);
@@ -611,6 +711,7 @@
atomic_set(&audio_ocmem_lcl.audio_state, OCMEM_STATE_DEFAULT);
atomic_set(&audio_ocmem_lcl.audio_exit, 0);
spin_lock_init(&audio_ocmem_lcl.audio_lock);
+ mutex_init(&audio_ocmem_lcl.protect_lock);
audio_ocmem_lcl.ocmem_en = true;
/* populate platform data */
diff --git a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
index 6df2fb93..b3107a4 100644
--- a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
@@ -81,7 +81,7 @@
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
.rates = SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_KNOT,
.rate_min = 8000,
.rate_max = 48000,
@@ -121,6 +121,7 @@
int i = 0;
int time_stamp_flag = 0;
int buffer_length = 0;
+ int stop_playback = 0;
pr_debug("%s opcode =%08x\n", __func__, opcode);
switch (opcode) {
@@ -141,6 +142,23 @@
break;
} else
atomic_set(&prtd->pending_buffer, 0);
+
+ /*
+ * check for underrun
+ */
+ snd_pcm_stream_lock_irq(substream);
+ if (snd_pcm_playback_empty(substream)) {
+ atomic_set(&prtd->pending_buffer, 1);
+ runtime->render_flag |= SNDRV_RENDER_STOPPED;
+ stop_playback = 1;
+ }
+ snd_pcm_stream_unlock_irq(substream);
+
+ if (stop_playback) {
+ pr_err("%s empty buffer, stop writes\n", __func__);
+ break;
+ }
+
buf = prtd->audio_client->port[IN].buf;
pr_debug("%s:writing %d bytes of buffer[%d] to dsp 2\n",
__func__, prtd->pcm_count, prtd->out_head);
@@ -519,6 +537,7 @@
}
prtd = &compr->prtd;
prtd->substream = substream;
+ runtime->render_flag = SNDRV_DMA_MODE;
prtd->audio_client = q6asm_audio_client_alloc(
(app_cb)compr_event_handler, compr);
if (!prtd->audio_client) {
@@ -527,6 +546,7 @@
return -ENOMEM;
}
+ prtd->audio_client->perf_mode = false;
pr_info("%s: session ID %d\n", __func__, prtd->audio_client->session);
prtd->session_id = prtd->audio_client->session;
@@ -673,6 +693,7 @@
pr_debug("%s\n", __func__);
prtd->mmap_flag = 1;
+ runtime->render_flag = SNDRV_NON_DMA_MODE;
if (runtime->dma_addr && runtime->dma_bytes) {
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
result = remap_pfn_range(vma, vma->vm_start,
@@ -696,6 +717,8 @@
struct snd_dma_buffer *dma_buf = &substream->dma_buffer;
struct audio_buffer *buf;
int dir, ret;
+ uint16_t bits_per_sample = 16;
+
struct asm_softpause_params softpause = {
.enable = SOFT_PAUSE_ENABLE,
.period = SOFT_PAUSE_PERIOD,
@@ -713,9 +736,13 @@
dir = IN;
else
dir = OUT;
+
+ if (runtime->format == SNDRV_PCM_FORMAT_S24_LE)
+ bits_per_sample = 24;
+
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- ret = q6asm_open_write(prtd->audio_client,
- compr->codec);
+ ret = q6asm_open_write_v2(prtd->audio_client,
+ compr->codec, bits_per_sample);
if (ret < 0) {
pr_err("%s: Session out open failed\n",
__func__);
@@ -723,6 +750,7 @@
}
msm_pcm_routing_reg_phy_stream(
soc_prtd->dai_link->be_id,
+ prtd->audio_client->perf_mode,
prtd->session_id,
substream->stream);
@@ -754,6 +782,7 @@
pr_debug("msm_pcm_routing_reg_phy_stream\n");
msm_pcm_routing_reg_phy_stream(
soc_prtd->dai_link->be_id,
+ prtd->audio_client->perf_mode,
prtd->session_id, substream->stream);
break;
default:
@@ -791,6 +820,9 @@
}
runtime->hw.buffer_bytes_max =
runtime->hw.period_bytes_min * runtime->hw.periods_max;
+ pr_debug("allocate %d buffers each of size %d\n",
+ runtime->hw.period_bytes_min,
+ runtime->hw.periods_max);
ret = q6asm_audio_client_buf_alloc_contiguous(dir,
prtd->audio_client,
runtime->hw.period_bytes_min,
@@ -948,6 +980,70 @@
return snd_pcm_lib_ioctl(substream, cmd, arg);
}
+static int msm_compr_restart(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct compr_audio *compr = runtime->private_data;
+ struct msm_audio *prtd = &compr->prtd;
+ struct audio_aio_write_param param;
+ struct audio_buffer *buf = NULL;
+ struct output_meta_data_st output_meta_data;
+ int time_stamp_flag = 0;
+ int buffer_length = 0;
+
+ pr_debug("%s, trigger restart\n", __func__);
+
+ if (runtime->render_flag & SNDRV_RENDER_STOPPED) {
+ buf = prtd->audio_client->port[IN].buf;
+ pr_debug("%s:writing %d bytes of buffer[%d] to dsp 2\n",
+ __func__, prtd->pcm_count, prtd->out_head);
+ pr_debug("%s:writing buffer[%d] from 0x%08x\n",
+ __func__, prtd->out_head,
+ ((unsigned int)buf[0].phys
+ + (prtd->out_head * prtd->pcm_count)));
+
+ if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE)
+ time_stamp_flag = SET_TIMESTAMP;
+ else
+ time_stamp_flag = NO_TIMESTAMP;
+ memcpy(&output_meta_data, (char *)(buf->data +
+ prtd->out_head * prtd->pcm_count),
+ COMPRE_OUTPUT_METADATA_SIZE);
+
+ buffer_length = output_meta_data.frame_size;
+ pr_debug("meta_data_length: %d, frame_length: %d\n",
+ output_meta_data.meta_data_length,
+ output_meta_data.frame_size);
+ pr_debug("timestamp_msw: %d, timestamp_lsw: %d\n",
+ output_meta_data.timestamp_msw,
+ output_meta_data.timestamp_lsw);
+
+ param.paddr = (unsigned long)buf[0].phys
+ + (prtd->out_head * prtd->pcm_count)
+ + output_meta_data.meta_data_length;
+ param.len = buffer_length;
+ param.msw_ts = output_meta_data.timestamp_msw;
+ param.lsw_ts = output_meta_data.timestamp_lsw;
+ param.flags = time_stamp_flag;
+ param.uid = (unsigned long)buf[0].phys
+ + (prtd->out_head * prtd->pcm_count
+ + output_meta_data.meta_data_length);
+ if (q6asm_async_write(prtd->audio_client,
+ ¶m) < 0)
+ pr_err("%s:q6asm_async_write failed\n",
+ __func__);
+ else
+ prtd->out_head =
+ (prtd->out_head + 1) & (runtime->periods - 1);
+
+ runtime->render_flag &= ~SNDRV_RENDER_STOPPED;
+ atomic_set(&prtd->pending_buffer, 0);
+ return 0;
+ }
+ return 0;
+}
+
+
static struct snd_pcm_ops msm_compr_ops = {
.open = msm_compr_open,
.hw_params = msm_compr_hw_params,
@@ -957,6 +1053,7 @@
.trigger = msm_compr_trigger,
.pointer = msm_compr_pointer,
.mmap = msm_compr_mmap,
+ .restart = msm_compr_restart,
};
static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
index 4efdb24..a6dce77 100644
--- a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
@@ -482,6 +482,18 @@
return -EINVAL;
break;
}
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ dai_data->port_config.i2s.bit_width = 16;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ dai_data->port_config.i2s.bit_width = 24;
+ break;
+ default:
+ return -EINVAL;
+ }
+
dai_data->rate = params_rate(params);
dai_data->port_config.i2s.sample_rate = dai_data->rate;
dai_data->port_config.i2s.i2s_cfg_minor_version =
@@ -490,8 +502,6 @@
dev_dbg(dai->dev, " channel %d sample rate %d entered\n",
dai_data->channels, dai_data->rate);
- /* Q6 only supports 16 as now */
- dai_data->port_config.i2s.bit_width = 16;
dai_data->port_config.i2s.channel_mode = 1;
return 0;
}
@@ -548,10 +558,19 @@
dai_data->channels = params_channels(params);
dai_data->rate = params_rate(params);
- /* Q6 only supports 16 as now */
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ dai_data->port_config.slim_sch.bit_width = 16;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ dai_data->port_config.slim_sch.bit_width = 24;
+ break;
+ default:
+ return -EINVAL;
+ }
+
dai_data->port_config.slim_sch.sb_cfg_minor_version =
AFE_API_VERSION_SLIMBUS_CONFIG;
- dai_data->port_config.slim_sch.bit_width = 16;
dai_data->port_config.slim_sch.data_format = 0;
dai_data->port_config.slim_sch.num_channels = dai_data->channels;
dai_data->port_config.slim_sch.sample_rate = dai_data->rate;
@@ -889,7 +908,7 @@
.playback = {
.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
SNDRV_PCM_RATE_16000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
.channels_min = 1,
.channels_max = 2,
.rate_min = 8000,
@@ -918,12 +937,12 @@
static struct snd_soc_dai_driver msm_dai_q6_slimbus_1_rx_dai = {
.playback = {
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_48000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
.channels_min = 1,
.channels_max = 2,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 96000,
},
.ops = &msm_dai_q6_ops,
.probe = msm_dai_q6_dai_probe,
@@ -1247,7 +1266,7 @@
.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_96000 |
SNDRV_PCM_RATE_192000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
diff --git a/sound/soc/msm/qdsp6v2/msm-multi-ch-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-multi-ch-pcm-q6-v2.c
index 827aaa3..d0d573c 100644
--- a/sound/soc/msm/qdsp6v2/msm-multi-ch-pcm-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-multi-ch-pcm-q6-v2.c
@@ -76,10 +76,11 @@
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
- .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .rates = SNDRV_PCM_RATE_8000_96000,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 96000,
.channels_min = 1,
.channels_max = 6,
.buffer_bytes_max = PLAYBACK_NUM_PERIODS * PLAYBACK_PERIOD_SIZE,
@@ -92,7 +93,8 @@
/* Conventional and unconventional sample rate supported */
static unsigned int supported_sample_rates[] = {
- 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
+ 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000,
+ 96000
};
static uint32_t in_frame_info[CAPTURE_NUM_PERIODS][2];
@@ -172,8 +174,7 @@
break;
}
if (prtd->mmap_flag) {
- pr_debug("%s:writing %d bytes"
- " of buffer to dsp\n",
+ pr_debug("%s:writing %d bytes of buffer to dsp\n",
__func__,
prtd->pcm_count);
q6asm_write_nolock(prtd->audio_client,
@@ -181,8 +182,7 @@
0, 0, NO_TIMESTAMP);
} else {
while (atomic_read(&prtd->out_needed)) {
- pr_debug("%s:writing %d bytes"
- " of buffer to dsp\n",
+ pr_debug("%s:writing %d bytes of buffer to dsp\n",
__func__,
prtd->pcm_count);
q6asm_write_nolock(prtd->audio_client,
@@ -210,6 +210,7 @@
struct snd_pcm_runtime *runtime = substream->runtime;
struct msm_audio *prtd = runtime->private_data;
int ret;
+ uint16_t bits_per_sample = 16;
pr_debug("%s\n", __func__);
prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
@@ -221,8 +222,19 @@
if (prtd->enabled)
return 0;
- ret = q6asm_media_format_block_pcm(prtd->audio_client,
- runtime->rate, runtime->channels);
+ switch (runtime->format) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ bits_per_sample = 16;
+ break;
+
+ case SNDRV_PCM_FORMAT_S24_LE:
+ bits_per_sample = 24;
+ break;
+ }
+
+ ret = q6asm_media_format_block_pcm_format_support(
+ prtd->audio_client, runtime->rate,
+ runtime->channels, bits_per_sample);
if (ret < 0)
pr_info("%s: CMD Format block failed\n", __func__);
@@ -336,6 +348,7 @@
kfree(prtd);
return -ENOMEM;
}
+ prtd->audio_client->perf_mode = false;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
runtime->hw = msm_pcm_hardware_playback;
ret = q6asm_open_write(prtd->audio_client,
@@ -363,6 +376,7 @@
prtd->session_id = prtd->audio_client->session;
msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
+ prtd->audio_client->perf_mode,
prtd->session_id, substream->stream);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
@@ -412,8 +426,8 @@
rc = q6asm_set_volume(multi_ch_pcm_audio.prtd->audio_client,
volume);
if (rc < 0) {
- pr_err("%s: Send Volume command failed"
- " rc=%d\n", __func__, rc);
+ pr_err("%s: Send Volume command failed rc=%d\n",
+ __func__, rc);
}
}
multi_ch_pcm_audio.volume = volume;
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c
index 7fb72cd..91bb09b 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c
@@ -42,7 +42,8 @@
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_INTERLEAVED),
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
.rates = (SNDRV_PCM_RATE_8000 |
SNDRV_PCM_RATE_16000 |
SNDRV_PCM_RATE_48000),
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c
index 4d88246..2fca464 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c
@@ -52,7 +52,8 @@
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
.rates = SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_KNOT,
.rate_min = 8000,
.rate_max = 48000,
@@ -196,6 +197,7 @@
struct snd_pcm_runtime *runtime = substream->runtime;
struct msm_audio *prtd = runtime->private_data;
int ret;
+ uint16_t bits_per_sample = 16;
pr_debug("%s\n", __func__);
prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
@@ -208,8 +210,19 @@
if (prtd->enabled)
return 0;
- ret = q6asm_media_format_block_pcm(prtd->audio_client, runtime->rate,
- runtime->channels);
+ switch (runtime->format) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ bits_per_sample = 16;
+ break;
+
+ case SNDRV_PCM_FORMAT_S24_LE:
+ bits_per_sample = 24;
+ break;
+ }
+
+ ret = q6asm_media_format_block_pcm_format_support(
+ prtd->audio_client, runtime->rate,
+ runtime->channels, bits_per_sample);
if (ret < 0)
pr_debug("%s: CMD Format block failed\n", __func__);
@@ -293,6 +306,7 @@
kfree(prtd);
return -ENOMEM;
}
+ prtd->audio_client->perf_mode = false;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
ret = q6asm_open_write(prtd->audio_client, FORMAT_LINEAR_PCM);
if (ret < 0) {
@@ -315,6 +329,7 @@
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->audio_client->perf_mode,
prtd->session_id, substream->stream);
ret = snd_pcm_hw_constraint_list(runtime, 0,
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
index 34b38a6..e05e58d 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
@@ -29,6 +29,7 @@
#include <linux/dma-mapping.h>
#include <linux/android_pmem.h>
#include <linux/of_device.h>
+#include <sound/pcm_params.h>
#include "msm-pcm-q6-v2.h"
#include "msm-pcm-routing-v2.h"
@@ -48,7 +49,7 @@
#define PLAYBACK_NUM_PERIODS 8
#define PLAYBACK_MAX_PERIOD_SIZE 12288
-#define PLAYBACK_MIN_PERIOD_SIZE 2048
+#define PLAYBACK_MIN_PERIOD_SIZE 1024
#define CAPTURE_NUM_PERIODS 16
#define CAPTURE_MAX_PERIOD_SIZE 4096
#define CAPTURE_MIN_PERIOD_SIZE 512
@@ -79,10 +80,11 @@
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
- .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ .rates = SNDRV_PCM_RATE_8000_96000,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 96000,
.channels_min = 1,
.channels_max = 8,
.buffer_bytes_max = PLAYBACK_NUM_PERIODS * PLAYBACK_MAX_PERIOD_SIZE,
@@ -95,7 +97,8 @@
/* Conventional and unconventional sample rate supported */
static unsigned int supported_sample_rates[] = {
- 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
+ 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000,
+ 96000
};
static uint32_t in_frame_info[CAPTURE_NUM_PERIODS][2];
@@ -209,6 +212,7 @@
struct snd_pcm_runtime *runtime = substream->runtime;
struct msm_audio *prtd = runtime->private_data;
int ret;
+ uint16_t bits_per_sample = 16;
pr_debug("%s\n", __func__);
prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
@@ -220,11 +224,19 @@
if (prtd->enabled)
return 0;
- ret = q6asm_media_format_block_multi_ch_pcm(prtd->audio_client,
- runtime->rate,
- runtime->channels,
- !prtd->set_channel_map,
- prtd->channel_map);
+ switch (runtime->format) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ bits_per_sample = 16;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ bits_per_sample = 24;
+ break;
+ }
+
+ ret = q6asm_media_format_block_multi_ch_pcm_v2(
+ prtd->audio_client, runtime->rate,
+ runtime->channels, !prtd->set_channel_map,
+ prtd->channel_map, bits_per_sample);
if (ret < 0)
pr_info("%s: CMD Format block failed\n", __func__);
@@ -309,11 +321,9 @@
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;
- pr_debug("%s\n", __func__);
prtd = kzalloc(sizeof(struct msm_audio), GFP_KERNEL);
if (prtd == NULL) {
pr_err("Failed to allocate memory for msm_audio\n");
@@ -327,24 +337,10 @@
kfree(prtd);
return -ENOMEM;
}
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+
+ 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;
- }
- 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);
- prtd->cmd_ack = 1;
-
- }
/* Capture path */
else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
runtime->hw = msm_pcm_hardware_capture;
@@ -655,11 +651,49 @@
struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
struct audio_buffer *buf;
int dir, ret;
+ struct msm_plat_data *pdata;
+ uint16_t bits_per_sample = 16;
+
+ pdata = (struct msm_plat_data *)
+ dev_get_drvdata(soc_prtd->platform->dev);
+ if (!pdata) {
+ pr_err("%s: platform data not populated\n", __func__);
+ return -EINVAL;
+ }
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
dir = IN;
- else {
+ else
dir = OUT;
+
+ prtd->audio_client->perf_mode = pdata->perf_mode;
+ pr_debug("%s: perf: %x\n", __func__, pdata->perf_mode);
+ /* Playback Path */
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ if (params_format(params) == SNDRV_PCM_FORMAT_S24_LE)
+ bits_per_sample = 24;
+
+ ret = q6asm_open_write_v2(prtd->audio_client,
+ FORMAT_LINEAR_PCM, bits_per_sample);
+ if (ret < 0) {
+ pr_err("%s: q6asm_open_write_v2 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->audio_client->perf_mode,
+ prtd->session_id, substream->stream);
+ prtd->cmd_ack = 1;
+ }
+
+ /* Capture Path */
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+
pr_debug("%s Opening %d-ch PCM read stream\n",
__func__, params_channels(params));
ret = q6asm_open_read(prtd->audio_client, FORMAT_LINEAR_PCM);
@@ -669,14 +703,15 @@
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->audio_client->perf_mode,
+ prtd->session_id, substream->stream);
}
- 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);
-
-
ret = q6asm_audio_client_buf_alloc_contiguous(dir,
prtd->audio_client,
(params_buffer_bytes(params) / params_periods(params)),
@@ -769,16 +804,46 @@
static __devinit int msm_pcm_probe(struct platform_device *pdev)
{
- if (pdev->dev.of_node)
- dev_set_name(&pdev->dev, "%s", "msm-pcm-dsp");
+ int rc;
+ int id;
+ struct msm_plat_data *pdata;
- pr_info("%s: dev name %s\n", __func__, dev_name(&pdev->dev));
+ rc = of_property_read_u32(pdev->dev.of_node,
+ "qcom,msm-pcm-dsp-id", &id);
+ if (rc) {
+ dev_err(&pdev->dev, "%s: qcom,msm-pcm-dsp-id missing in DT node\n",
+ __func__);
+ return rc;
+ }
+
+ pdata = kzalloc(sizeof(struct msm_plat_data), GFP_KERNEL);
+ if (!pdata) {
+ dev_err(&pdev->dev, "Failed to allocate memory for platform data\n");
+ return -ENOMEM;
+ }
+
+ if (of_property_read_bool(pdev->dev.of_node,
+ "qcom,msm-pcm-low-latency"))
+ pdata->perf_mode = 1;
+ else
+ pdata->perf_mode = 0;
+
+ dev_set_drvdata(&pdev->dev, pdata);
+
+ dev_set_name(&pdev->dev, "%s.%d", "msm-pcm-dsp", id);
+
+ dev_dbg(&pdev->dev, "%s: dev name %s\n",
+ __func__, dev_name(&pdev->dev));
return snd_soc_register_platform(&pdev->dev,
&msm_soc_platform);
}
static int msm_pcm_remove(struct platform_device *pdev)
{
+ struct msm_plat_data *pdata;
+
+ pdata = dev_get_drvdata(&pdev->dev);
+ kfree(pdata);
snd_soc_unregister_platform(&pdev->dev);
return 0;
}
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h
index 01ed41f..4b3cfe7 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h
@@ -95,4 +95,8 @@
uint32_t reserved[12];
};
+struct msm_plat_data {
+ int perf_mode;
+};
+
#endif /*_MSM_PCM_H*/
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index 8a5abc9..c48132e 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -29,6 +29,8 @@
#include <sound/q6asm-v2.h>
#include <sound/q6afe-v2.h>
#include <sound/tlv.h>
+#include <sound/asound.h>
+#include <sound/pcm_params.h>
#include "msm-pcm-routing-v2.h"
#include "q6voice.h"
@@ -40,6 +42,8 @@
unsigned long port_sessions; /* track Tx BE ports -> Rx BE */
unsigned int sample_rate;
unsigned int channel;
+ unsigned int format;
+ bool perf_mode;
};
#define INVALID_SESSION -1
@@ -71,6 +75,9 @@
static const DECLARE_TLV_DB_LINEAR(compressed_rx_vol_gain, 0,
INT_RX_VOL_MAX_STEPS);
+static int msm_route_multimedia5_vol_control;
+static const DECLARE_TLV_DB_LINEAR(multimedia5_rx_vol_gain, 0,
+ INT_RX_VOL_MAX_STEPS);
/* Equal to Frontend after last of the MULTIMEDIA SESSIONS */
@@ -208,6 +215,8 @@
{INVALID_SESSION, INVALID_SESSION},
/* MULTIMEDIA4 */
{INVALID_SESSION, INVALID_SESSION},
+ /* MULTIMEDIA5 */
+ {INVALID_SESSION, INVALID_SESSION},
};
static uint8_t is_be_dai_extproc(int be_dai)
@@ -283,11 +292,13 @@
mutex_unlock(&routing_lock);
}
-void msm_pcm_routing_reg_phy_stream(int fedai_id, int dspst_id, int stream_type)
+void msm_pcm_routing_reg_phy_stream(int fedai_id, bool perf_mode,
+ int dspst_id, int stream_type)
{
int i, session_type, path_type, port_type;
struct route_payload payload;
u32 channels;
+ uint16_t bits_per_sample = 16;
if (fedai_id > MSM_FRONTEND_DAI_MM_MAX_ID) {
/* bad ID assigned in machine driver */
@@ -313,6 +324,8 @@
if (eq_data[fedai_id].enable)
msm_send_eq_values(fedai_id);
for (i = 0; i < MSM_BACKEND_DAI_MAX; i++) {
+ if (test_bit(fedai_id, &msm_bedais[i].fe_sessions))
+ msm_bedais[i].perf_mode = perf_mode;
if (!is_be_dai_extproc(i) &&
(afe_get_port_type(msm_bedais[i].port_id) == port_type) &&
(msm_bedais[i].active) &&
@@ -320,19 +333,27 @@
channels = msm_bedais[i].channel;
+ if (msm_bedais[i].format == SNDRV_PCM_FORMAT_S16_LE)
+ bits_per_sample = 16;
+ else if (msm_bedais[i].format ==
+ SNDRV_PCM_FORMAT_S24_LE)
+ bits_per_sample = 24;
+
if ((stream_type == SNDRV_PCM_STREAM_PLAYBACK) &&
- (channels > 2))
+ (channels > 0))
adm_multi_ch_copp_open(msm_bedais[i].port_id,
path_type,
msm_bedais[i].sample_rate,
msm_bedais[i].channel,
- DEFAULT_COPP_TOPOLOGY);
+ DEFAULT_COPP_TOPOLOGY, msm_bedais[i].perf_mode,
+ bits_per_sample);
else
adm_open(msm_bedais[i].port_id,
path_type,
msm_bedais[i].sample_rate,
msm_bedais[i].channel,
- DEFAULT_COPP_TOPOLOGY);
+ DEFAULT_COPP_TOPOLOGY, false,
+ bits_per_sample);
payload.copp_ids[payload.num_copps++] =
msm_bedais[i].port_id;
@@ -401,6 +422,7 @@
{
int session_type, path_type;
u32 channels;
+ uint16_t bits_per_sample = 16;
pr_debug("%s: reg %x val %x set %x\n", __func__, reg, val, set);
@@ -430,18 +452,23 @@
INVALID_SESSION) {
channels = msm_bedais[reg].channel;
+ if (msm_bedais[reg].format == SNDRV_PCM_FORMAT_S24_LE)
+ bits_per_sample = 24;
- if ((session_type == SESSION_TYPE_RX) && (channels > 2))
+ if ((session_type == SESSION_TYPE_RX) &&
+ (channels > 0)) {
adm_multi_ch_copp_open(msm_bedais[reg].port_id,
path_type,
msm_bedais[reg].sample_rate,
channels,
- DEFAULT_COPP_TOPOLOGY);
- else
+ DEFAULT_COPP_TOPOLOGY,
+ msm_bedais[reg].perf_mode,
+ bits_per_sample);
+ } else
adm_open(msm_bedais[reg].port_id,
path_type,
msm_bedais[reg].sample_rate, channels,
- DEFAULT_COPP_TOPOLOGY);
+ DEFAULT_COPP_TOPOLOGY, false, bits_per_sample);
msm_pcm_routing_build_matrix(val,
fe_dai_map[val][session_type], path_type);
@@ -787,6 +814,25 @@
return 0;
}
+static int msm_routing_get_multimedia5_vol_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+
+ ucontrol->value.integer.value[0] = msm_route_multimedia5_vol_control;
+ return 0;
+}
+
+static int msm_routing_set_multimedia5_vol_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+
+ if (!multi_ch_pcm_set_volume(ucontrol->value.integer.value[0]))
+ msm_route_multimedia5_vol_control =
+ ucontrol->value.integer.value[0];
+
+ return 0;
+}
+
static int msm_routing_set_multimedia2_vol_mixer(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -1082,6 +1128,9 @@
SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_PRI_I2S_RX,
MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_PRI_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new sec_i2s_rx_mixer_controls[] = {
@@ -1097,6 +1146,9 @@
SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_SEC_I2S_RX,
MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_SEC_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new slimbus_rx_mixer_controls[] = {
@@ -1112,6 +1164,9 @@
SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_SLIMBUS_0_RX,
MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new mi2s_rx_mixer_controls[] = {
@@ -1127,6 +1182,9 @@
SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_MI2S_RX,
MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new quaternary_mi2s_rx_mixer_controls[] = {
@@ -1187,6 +1245,9 @@
SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_HDMI_RX,
MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_HDMI_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
/* incall music delivery mixer */
static const struct snd_kcontrol_new incall_music_delivery_mixer_controls[] = {
@@ -1220,6 +1281,9 @@
SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_INT_BT_SCO_RX,
MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new int_fm_rx_mixer_controls[] = {
@@ -1235,6 +1299,9 @@
SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_INT_FM_RX,
MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_INT_FM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new afe_pcm_rx_mixer_controls[] = {
@@ -1250,6 +1317,9 @@
SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_AFE_PCM_RX,
MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_AFE_PCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new auxpcm_rx_mixer_controls[] = {
@@ -1265,6 +1335,9 @@
SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_AUXPCM_RX,
MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new mmul1_mixer_controls[] = {
@@ -1318,6 +1391,27 @@
msm_routing_put_audio_mixer),
};
+static const struct snd_kcontrol_new mmul5_mixer_controls[] = {
+ SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_AFE_PCM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_INT_BT_SCO_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("AUX_PCM_TX", MSM_BACKEND_DAI_AUXPCM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
static const struct snd_kcontrol_new pri_rx_voice_mixer_controls[] = {
SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_PRI_I2S_RX,
MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
@@ -1658,6 +1752,12 @@
msm_routing_set_multimedia2_vol_mixer, multimedia2_rx_vol_gain),
};
+static const struct snd_kcontrol_new multimedia5_vol_mixer_controls[] = {
+ SOC_SINGLE_EXT_TLV("HIFI3 RX Volume", SND_SOC_NOPM, 0,
+ INT_RX_VOL_GAIN, 0, msm_routing_get_multimedia5_vol_mixer,
+ msm_routing_set_multimedia5_vol_mixer, multimedia5_rx_vol_gain),
+};
+
static const struct snd_kcontrol_new compressed_vol_mixer_controls[] = {
SOC_SINGLE_EXT_TLV("COMPRESSED RX Volume", SND_SOC_NOPM, 0,
INT_RX_VOL_GAIN, 0, msm_routing_get_compressed_vol_mixer,
@@ -1913,9 +2013,11 @@
SND_SOC_DAPM_AIF_IN("MM_DL2", "MultiMedia2 Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("MM_DL3", "MultiMedia3 Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("MM_DL4", "MultiMedia4 Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("MM_DL5", "MultiMedia5 Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("VOIP_DL", "VoIP Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MM_UL1", "MultiMedia1 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MM_UL2", "MultiMedia2 Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("MM_UL5", "MultiMedia5 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("CS-VOICE_DL1", "CS-VOICE Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("CS-VOICE_UL1", "CS-VOICE Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("VoLTE_DL", "VoLTE Playback", 0, 0, 0, 0),
@@ -2048,6 +2150,8 @@
mmul1_mixer_controls, ARRAY_SIZE(mmul1_mixer_controls)),
SND_SOC_DAPM_MIXER("MultiMedia2 Mixer", SND_SOC_NOPM, 0, 0,
mmul2_mixer_controls, ARRAY_SIZE(mmul2_mixer_controls)),
+ SND_SOC_DAPM_MIXER("MultiMedia5 Mixer", SND_SOC_NOPM, 0, 0,
+ mmul5_mixer_controls, ARRAY_SIZE(mmul5_mixer_controls)),
SND_SOC_DAPM_MIXER("AUX_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
auxpcm_rx_mixer_controls, ARRAY_SIZE(auxpcm_rx_mixer_controls)),
/* incall */
@@ -2152,24 +2256,28 @@
{"PRI_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
{"PRI_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
{"PRI_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"PRI_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
{"PRI_I2S_RX", NULL, "PRI_RX Audio Mixer"},
{"SEC_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
{"SEC_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
{"SEC_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
{"SEC_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"SEC_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
{"SEC_I2S_RX", NULL, "SEC_RX Audio Mixer"},
{"SLIMBUS_0_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
{"SLIMBUS_0_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
{"SLIMBUS_0_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
{"SLIMBUS_0_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"SLIMBUS_0_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
{"SLIMBUS_0_RX", NULL, "SLIMBUS_0_RX Audio Mixer"},
{"HDMI Mixer", "MultiMedia1", "MM_DL1"},
{"HDMI Mixer", "MultiMedia2", "MM_DL2"},
{"HDMI Mixer", "MultiMedia3", "MM_DL3"},
{"HDMI Mixer", "MultiMedia4", "MM_DL4"},
+ {"HDMI Mixer", "MultiMedia5", "MM_DL5"},
{"HDMI", NULL, "HDMI Mixer"},
/* incall */
@@ -2183,10 +2291,12 @@
{"MultiMedia1 Mixer", "VOC_REC_UL", "INCALL_RECORD_TX"},
{"MultiMedia1 Mixer", "VOC_REC_DL", "INCALL_RECORD_RX"},
{"MultiMedia1 Mixer", "SLIM_4_TX", "SLIMBUS_4_TX"},
+ {"MultiMedia5 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
{"MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
{"MI2S_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
{"MI2S_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
{"MI2S_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"MI2S_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
{"MI2S_RX", NULL, "MI2S_RX Audio Mixer"},
{"QUAT_MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -2214,6 +2324,7 @@
{"MultiMedia1 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
{"MultiMedia1 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
{"MultiMedia1 Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
+ {"MultiMedia5 Mixer", "AUX_PCM_TX", "AUX_PCM_TX"},
{"MultiMedia2 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
{"MultiMedia1 Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"},
@@ -2221,32 +2332,40 @@
{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
{"INT_BT_SCO_RX", NULL, "INTERNAL_BT_SCO_RX Audio Mixer"},
{"INTERNAL_FM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
{"INTERNAL_FM_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
{"INTERNAL_FM_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
{"INTERNAL_FM_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"INTERNAL_FM_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
{"INT_FM_RX", NULL, "INTERNAL_FM_RX Audio Mixer"},
{"AFE_PCM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
{"AFE_PCM_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
{"AFE_PCM_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
{"AFE_PCM_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"AFE_PCM_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
{"PCM_RX", NULL, "AFE_PCM_RX Audio Mixer"},
{"MultiMedia1 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+ {"MultiMedia5 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
{"MultiMedia1 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+ {"MultiMedia5 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
{"MultiMedia1 Mixer", "AFE_PCM_TX", "PCM_TX"},
+ {"MultiMedia5 Mixer", "AFE_PCM_TX", "PCM_TX"},
{"MM_UL1", NULL, "MultiMedia1 Mixer"},
{"MultiMedia2 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
{"MM_UL2", NULL, "MultiMedia2 Mixer"},
+ {"MM_UL5", NULL, "MultiMedia5 Mixer"},
{"AUX_PCM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
{"AUX_PCM_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
{"AUX_PCM_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
{"AUX_PCM_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"AUX_PCM_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
{"AUX_PCM_RX", NULL, "AUX_PCM_RX Audio Mixer"},
{"MI2S_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
@@ -2452,6 +2571,7 @@
mutex_lock(&routing_lock);
msm_bedais[be_id].sample_rate = params_rate(params);
msm_bedais[be_id].channel = params_channels(params);
+ msm_bedais[be_id].format = params_format(params);
mutex_unlock(&routing_lock);
return 0;
}
@@ -2483,6 +2603,7 @@
bedai->active = 0;
bedai->sample_rate = 0;
bedai->channel = 0;
+ bedai->perf_mode = false;
mutex_unlock(&routing_lock);
return 0;
@@ -2495,6 +2616,8 @@
int i, path_type, session_type;
struct msm_pcm_routing_bdai_data *bedai;
u32 channels;
+ bool playback, capture;
+ uint16_t bits_per_sample = 16;
if (be_id >= MSM_BACKEND_DAI_MAX) {
pr_err("%s: unexpected be_id %d\n", __func__, be_id);
@@ -2522,24 +2645,31 @@
* is started.
*/
bedai->active = 1;
+ playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+ capture = substream->stream == SNDRV_PCM_STREAM_CAPTURE;
+
for_each_set_bit(i, &bedai->fe_sessions, MSM_FRONTEND_DAI_MM_SIZE) {
if (fe_dai_map[i][session_type] != INVALID_SESSION) {
channels = bedai->channel;
- if ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK ||
- substream->stream == SNDRV_PCM_STREAM_CAPTURE)
- && (channels > 2))
+ if (bedai->format == SNDRV_PCM_FORMAT_S24_LE)
+ bits_per_sample = 24;
+
+ if ((playback) && (channels > 0)) {
adm_multi_ch_copp_open(bedai->port_id,
- path_type,
- bedai->sample_rate,
- channels,
- DEFAULT_COPP_TOPOLOGY);
- else
+ path_type,
+ bedai->sample_rate,
+ channels,
+ DEFAULT_COPP_TOPOLOGY, bedai->perf_mode,
+ bits_per_sample);
+ } else if (capture) {
adm_open(bedai->port_id,
path_type,
bedai->sample_rate,
channels,
- DEFAULT_COPP_TOPOLOGY);
+ DEFAULT_COPP_TOPOLOGY, false,
+ bits_per_sample);
+ }
msm_pcm_routing_build_matrix(i,
fe_dai_map[i][session_type], path_type);
@@ -2610,6 +2740,10 @@
ARRAY_SIZE(multimedia2_vol_mixer_controls));
snd_soc_add_platform_controls(platform,
+ multimedia5_vol_mixer_controls,
+ ARRAY_SIZE(multimedia5_vol_mixer_controls));
+
+ snd_soc_add_platform_controls(platform,
compressed_vol_mixer_controls,
ARRAY_SIZE(compressed_vol_mixer_controls));
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
index cf24f9a..7ecdff3 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
@@ -63,6 +63,7 @@
MSM_FRONTEND_DAI_MULTIMEDIA2,
MSM_FRONTEND_DAI_MULTIMEDIA3,
MSM_FRONTEND_DAI_MULTIMEDIA4,
+ MSM_FRONTEND_DAI_MULTIMEDIA5,
MSM_FRONTEND_DAI_CS_VOICE,
MSM_FRONTEND_DAI_VOIP,
MSM_FRONTEND_DAI_AFE_RX,
@@ -73,8 +74,8 @@
MSM_FRONTEND_DAI_MAX,
};
-#define MSM_FRONTEND_DAI_MM_SIZE (MSM_FRONTEND_DAI_MULTIMEDIA4 + 1)
-#define MSM_FRONTEND_DAI_MM_MAX_ID MSM_FRONTEND_DAI_MULTIMEDIA4
+#define MSM_FRONTEND_DAI_MM_SIZE (MSM_FRONTEND_DAI_MULTIMEDIA5 + 1)
+#define MSM_FRONTEND_DAI_MM_MAX_ID MSM_FRONTEND_DAI_MULTIMEDIA5
enum {
MSM_BACKEND_DAI_PRI_I2S_RX = 0,
@@ -121,7 +122,7 @@
* dspst_id: DSP audio stream ID
* stream_type: playback or capture
*/
-void msm_pcm_routing_reg_phy_stream(int fedai_id, int dspst_id,
+void msm_pcm_routing_reg_phy_stream(int fedai_id, bool perf_mode, int dspst_id,
int stream_type);
void msm_pcm_routing_reg_psthr_stream(int fedai_id, int dspst_id,
int stream_type);
diff --git a/sound/soc/msm/qdsp6v2/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c
index bc11304..913dded 100644
--- a/sound/soc/msm/qdsp6v2/q6adm.c
+++ b/sound/soc/msm/qdsp6v2/q6adm.c
@@ -46,8 +46,11 @@
/* 0 - (MAX_AUDPROC_TYPES -1): audproc handles */
/* (MAX_AUDPROC_TYPES -1) - (2 * MAX_AUDPROC_TYPES -1): audvol handles */
- atomic_t mem_map_cal_handles[(2 * MAX_AUDPROC_TYPES)];
+/* + 1 for custom ADM topology */
+ atomic_t mem_map_cal_handles[(2 * MAX_AUDPROC_TYPES) + 1];
atomic_t mem_map_cal_index;
+
+ int set_custom_topology;
};
static struct adm_ctl this_adm;
@@ -309,6 +312,8 @@
atomic_set(&this_adm.copp_stat[i], 0);
}
this_adm.apr = NULL;
+ reset_custom_topology_flags();
+ this_adm.set_custom_topology = 1;
}
pr_debug("Resetting calibration blocks");
for (i = 0; i < MAX_AUDPROC_TYPES; i++) {
@@ -350,6 +355,7 @@
case ADM_CMD_DEVICE_CLOSE_V5:
case ADM_CMD_SHARED_MEM_UNMAP_REGIONS:
case ADM_CMD_MATRIX_MAP_ROUTINGS_V5:
+ case ADM_CMD_ADD_TOPOLOGIES:
pr_debug("%s: Basic callback received, wake up.\n",
__func__);
atomic_set(&this_adm.copp_stat[index], 1);
@@ -435,6 +441,87 @@
return 0;
}
+void send_adm_custom_topology(int port_id)
+{
+ struct acdb_cal_block cal_block;
+ struct cmd_set_topologies adm_top;
+ int index;
+ int result;
+ int size = 4096;
+
+ get_adm_custom_topology(&cal_block);
+ if (cal_block.cal_size == 0) {
+ pr_debug("%s: no cal to send addr= 0x%x\n",
+ __func__, cal_block.cal_paddr);
+ goto done;
+ }
+
+ index = afe_get_port_index(port_id);
+ if (index < 0 || index >= AFE_MAX_PORTS) {
+ pr_err("%s: invalid port idx %d portid %#x\n",
+ __func__, index, port_id);
+ goto done;
+ }
+
+ if (this_adm.set_custom_topology) {
+ /* specific index 4 for adm topology memory */
+ atomic_set(&this_adm.mem_map_cal_index, 4);
+
+ /* Only call this once */
+ this_adm.set_custom_topology = 0;
+
+ result = adm_memory_map_regions(port_id, &cal_block.cal_paddr,
+ 0, &size, 1);
+ if (result < 0) {
+ pr_err("%s: mmap did not work! addr = 0x%x, size = %d\n",
+ __func__, cal_block.cal_paddr,
+ cal_block.cal_size);
+ goto done;
+ }
+ }
+
+
+ adm_top.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(20), APR_PKT_VER);
+ adm_top.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(adm_top));
+ adm_top.hdr.src_svc = APR_SVC_ADM;
+ adm_top.hdr.src_domain = APR_DOMAIN_APPS;
+ adm_top.hdr.src_port = port_id;
+ adm_top.hdr.dest_svc = APR_SVC_ADM;
+ adm_top.hdr.dest_domain = APR_DOMAIN_ADSP;
+ adm_top.hdr.dest_port = atomic_read(&this_adm.copp_id[index]);
+ adm_top.hdr.token = port_id;
+ adm_top.hdr.opcode = ADM_CMD_ADD_TOPOLOGIES;
+ adm_top.payload_addr_lsw = cal_block.cal_paddr;
+ adm_top.payload_addr_msw = 0;
+ adm_top.mem_map_handle = atomic_read(&this_adm.mem_map_cal_handles[4]);
+ adm_top.payload_size = cal_block.cal_size;
+
+ atomic_set(&this_adm.copp_stat[index], 0);
+ pr_debug("%s: Sending ADM_CMD_ADD_TOPOLOGIES payload = 0x%x, size = %d\n",
+ __func__, adm_top.payload_addr_lsw,
+ adm_top.payload_size);
+ result = apr_send_pkt(this_adm.apr, (uint32_t *)&adm_top);
+ if (result < 0) {
+ pr_err("%s: Set topologies failed port = 0x%x payload = 0x%x\n",
+ __func__, port_id, cal_block.cal_paddr);
+ goto done;
+ }
+ /* Wait for the callback */
+ result = wait_event_timeout(this_adm.wait[index],
+ atomic_read(&this_adm.copp_stat[index]),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!result) {
+ pr_err("%s: Set topologies timed out port = 0x%x, payload = 0x%x\n",
+ __func__, port_id, cal_block.cal_paddr);
+ goto done;
+ }
+
+done:
+ return;
+}
+
static int send_adm_cal_block(int port_id, struct acdb_cal_block *aud_cal)
{
s32 result = 0;
@@ -653,7 +740,8 @@
return ret;
}
-int adm_open(int port_id, int path, int rate, int channel_mode, int topology)
+int adm_open(int port_id, int path, int rate, int channel_mode, int topology,
+ bool perf_mode, uint16_t bits_per_sample)
{
struct adm_cmd_device_open_v5 open;
int ret = 0;
@@ -684,6 +772,7 @@
rtac_set_adm_handle(this_adm.apr);
}
+ send_adm_custom_topology(port_id);
/* Create a COPP if port id are not enabled */
if (atomic_read(&this_adm.copp_cnt[index]) == 0) {
@@ -699,10 +788,16 @@
open.hdr.dest_port = tmp_port;
open.hdr.token = port_id;
open.hdr.opcode = ADM_CMD_DEVICE_OPEN_V5;
+ open.flags = 0x00;
+ if (perf_mode) {
+ open.flags |= ADM_LOW_LATENCY_DEVICE_SESSION <<
+ ADM_BIT_SHIFT_DEVICE_PERF_MODE_FLAG;
+ } else {
+ open.flags |= ADM_LEGACY_DEVICE_SESSION <<
+ ADM_BIT_SHIFT_DEVICE_PERF_MODE_FLAG;
+ }
open.mode_of_operation = path;
- /* Reserved for future use, need to set this to 0 */
- open.flags = 0x00;
open.endpoint_id_1 = tmp_port;
open.endpoint_id_2 = 0xFFFF;
@@ -722,7 +817,7 @@
open.topology_id = topology;
open.dev_num_channel = channel_mode & 0x00FF;
- open.bit_width = 16;
+ open.bit_width = bits_per_sample;
open.sample_rate = rate;
memset(open.dev_channel_mapping, 0, 8);
@@ -791,8 +886,8 @@
atomic_read(&this_adm.copp_stat[index]),
msecs_to_jiffies(TIMEOUT_MS));
if (!ret) {
- pr_err("%s ADM open failed for port %#x"
- "for [%d]\n", __func__, tmp_port, port_id);
+ pr_err("%s ADM open failed for port %#x for [%d]\n",
+ __func__, tmp_port, port_id);
ret = -EINVAL;
goto fail_cmd;
}
@@ -805,13 +900,13 @@
return ret;
}
-
int adm_multi_ch_copp_open(int port_id, int path, int rate, int channel_mode,
- int topology)
+ int topology, bool perf_mode, uint16_t bits_per_sample)
{
int ret = 0;
- ret = adm_open(port_id, path, rate, channel_mode, topology);
+ ret = adm_open(port_id, path, rate, channel_mode,
+ topology, perf_mode, bits_per_sample);
return ret;
}
@@ -821,7 +916,7 @@
{
struct adm_cmd_matrix_map_routings_v5 *route;
struct adm_session_map_node_v5 *node;
- uint32_t *copps_list;
+ uint16_t *copps_list;
int cmd_size = 0;
int ret = 0, i = 0;
void *payload = NULL;
@@ -880,7 +975,7 @@
node->session_id = session_id;
node->num_copps = num_copps;
payload = (u8 *)node + sizeof(struct adm_session_map_node_v5);
- copps_list = (uint32_t *)payload;
+ copps_list = (uint16_t *)payload;
for (i = 0; i < num_copps; i++) {
int tmp;
port_id[i] = q6audio_convert_virtual_to_portid(port_id[i]);
@@ -1154,6 +1249,7 @@
{
int i = 0;
this_adm.apr = NULL;
+ this_adm.set_custom_topology = 1;
for (i = 0; i < AFE_MAX_PORTS; i++) {
atomic_set(&this_adm.copp_id[i], RESET_COPP_ID);
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index 3d8d5eb..87990a9 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -106,6 +106,9 @@
static int out_cold_index;
static char *out_buffer;
static char *in_buffer;
+static int set_custom_topology;
+static int topology_map_handle;
+
static int audio_output_latency_dbgfs_open(struct inode *inode,
struct file *file)
{
@@ -338,6 +341,91 @@
session[ac->session] = 0;
mutex_unlock(&session_lock);
ac->session = 0;
+ ac->perf_mode = 0;
+ return;
+}
+
+void send_asm_custom_topology(struct audio_client *ac)
+{
+ struct acdb_cal_block cal_block;
+ struct cmd_set_topologies asm_top;
+ struct audio_buffer *buf;
+ struct asm_buffer_node *buf_node = NULL;
+ struct list_head *ptr, *next;
+ int result;
+ int size = 4096;
+
+ get_asm_custom_topology(&cal_block);
+ if (cal_block.cal_size == 0) {
+ pr_debug("%s: no cal to send addr= 0x%x\n",
+ __func__, cal_block.cal_paddr);
+ goto done;
+ }
+
+ if (set_custom_topology) {
+ /* Only call this once */
+ set_custom_topology = 0;
+
+ /* Use first asm buf to map memory */
+ buf = kzalloc(sizeof(struct audio_buffer), GFP_KERNEL);
+ if (!buf) {
+ pr_debug("%s: could not allocate temp memory\n",
+ __func__);
+ goto done;
+ }
+ buf[0].phys = cal_block.cal_paddr;
+ ac->port[0].buf = buf;
+
+ result = q6asm_memory_map_regions(ac, 0, size, 1, 1);
+ if (result < 0) {
+ pr_err("%s: mmap did not work! addr = 0x%x, size = %d\n",
+ __func__, cal_block.cal_paddr,
+ cal_block.cal_size);
+ goto done;
+ }
+
+ list_for_each_safe(ptr, next, &ac->port[IN].mem_map_handle) {
+ buf_node = list_entry(ptr, struct asm_buffer_node,
+ list);
+ if (buf_node->buf_addr_lsw == cal_block.cal_paddr) {
+ topology_map_handle = buf_node->mmap_hdl;
+ break;
+ }
+ }
+
+ kfree(buf);
+ }
+
+ q6asm_add_hdr(ac, &asm_top.hdr, APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(asm_top)), TRUE);
+
+ asm_top.hdr.opcode = ASM_CMD_ADD_TOPOLOGIES;
+ asm_top.payload_addr_lsw = cal_block.cal_paddr;
+ asm_top.payload_addr_msw = 0;
+ asm_top.mem_map_handle = topology_map_handle;
+ asm_top.payload_size = cal_block.cal_size;
+
+ pr_debug("%s: Sending ASM_CMD_ADD_TOPOLOGIES payload = 0x%x, size = %d, map handle = 0x%x\n",
+ __func__, asm_top.payload_addr_lsw,
+ asm_top.payload_size, asm_top.mem_map_handle);
+
+ result = apr_send_pkt(ac->apr, (uint32_t *) &asm_top);
+ if (result < 0) {
+ pr_err("%s: Set topologies failed payload = 0x%x\n",
+ __func__, cal_block.cal_paddr);
+ goto done;
+ }
+
+ result = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+ if (result < 0) {
+ pr_err("%s: Set topologies failed payload = 0x%x\n",
+ __func__, cal_block.cal_paddr);
+ goto done;
+ }
+
+
+done:
return;
}
@@ -535,6 +623,7 @@
ac->cb = cb;
ac->priv = priv;
ac->io_mode = SYNC_IO_MODE;
+ ac->perf_mode = false;
ac->apr = apr_register("ADSP", "ASM", \
(apr_fn)q6asm_callback,\
((ac->session) << 8 | 0x0001),\
@@ -552,6 +641,8 @@
goto fail;
init_waitqueue_head(&ac->cmd_wait);
+ init_waitqueue_head(&ac->time_wait);
+ atomic_set(&ac->time_flag, 1);
INIT_LIST_HEAD(&ac->port[0].mem_map_handle);
INIT_LIST_HEAD(&ac->port[1].mem_map_handle);
pr_debug("%s: mem_map_handle list init'ed\n", __func__);
@@ -563,6 +654,8 @@
atomic_set(&ac->cmd_state, 0);
atomic_set(&ac->nowait_cmd_cnt, 0);
+ send_asm_custom_topology(ac);
+
pr_debug("%s: session[%d]\n", __func__, ac->session);
return ac;
@@ -822,6 +915,8 @@
apr_reset(this_mmap.apr);
atomic_set(&this_mmap.ref_cnt, 0);
this_mmap.apr = NULL;
+ reset_custom_topology_flags();
+ set_custom_topology = 1;
return 0;
}
sid = (data->token >> 8) & 0x0F;
@@ -956,6 +1051,8 @@
(uint32_t *)data->payload, ac->priv);
apr_reset(ac->apr);
ac->apr = NULL;
+ reset_custom_topology_flags();
+ set_custom_topology = 1;
return 0;
}
@@ -992,11 +1089,12 @@
__func__, token, ac->session);
return -EINVAL;
}
- case ASM_STREAM_CMD_OPEN_READ_V2:
- case ASM_STREAM_CMD_OPEN_WRITE_V2:
+ case ASM_STREAM_CMD_OPEN_READ_V3:
+ case ASM_STREAM_CMD_OPEN_WRITE_V3:
case ASM_STREAM_CMD_OPEN_READWRITE_V2:
case ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2:
case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
+ case ASM_CMD_ADD_TOPOLOGIES:
pr_debug("%s:Payload = [0x%x]stat[0x%x]\n",
__func__, payload[0], payload[1]);
if (atomic_read(&ac->cmd_state) && wakeup_flag) {
@@ -1128,10 +1226,8 @@
payload[0], payload[1], payload[2]);
ac->time_stamp = (uint64_t)(((uint64_t)payload[2] << 32) |
payload[1]);
- if (atomic_read(&ac->cmd_state)) {
- atomic_set(&ac->cmd_state, 0);
- wake_up(&ac->cmd_wait);
- }
+ if (atomic_cmpxchg(&ac->time_flag, 1, 0))
+ wake_up(&ac->time_wait);
break;
case ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY:
case ASM_DATA_EVENT_ENC_SR_CM_CHANGE_NOTIFY:
@@ -1339,7 +1435,7 @@
uint32_t format)
{
int rc = 0x00;
- struct asm_stream_cmd_open_read_v2 open;
+ struct asm_stream_cmd_open_read_v3 open;
uint16_t bits_per_sample = 16;
@@ -1353,7 +1449,7 @@
pr_debug("%s:session[%d]", __func__, ac->session);
q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
- open.hdr.opcode = ASM_STREAM_CMD_OPEN_READ_V2;
+ open.hdr.opcode = ASM_STREAM_CMD_OPEN_READ_V3;
/* Stream prio : High, provide meta info with encoded frames */
open.src_endpointype = ASM_END_POINT_DEVICE_MATRIX;
@@ -1361,30 +1457,39 @@
if (open.preprocopo_id == 0)
open.preprocopo_id = ASM_STREAM_POSTPROC_TOPO_ID_DEFAULT;
open.bits_per_sample = bits_per_sample;
+ open.mode_flags = 0x0;
+
+ if (ac->perf_mode) {
+ open.mode_flags |= ASM_LOW_LATENCY_STREAM_SESSION <<
+ ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_READ;
+ } else {
+ open.mode_flags |= ASM_LEGACY_STREAM_SESSION <<
+ ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_READ;
+ }
switch (format) {
case FORMAT_LINEAR_PCM:
- open.mode_flags = 0x00;
+ open.mode_flags |= 0x00;
open.enc_cfg_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2;
break;
case FORMAT_MPEG4_AAC:
- open.mode_flags = BUFFER_META_ENABLE;
+ open.mode_flags |= BUFFER_META_ENABLE;
open.enc_cfg_id = ASM_MEDIA_FMT_AAC_V2;
break;
case FORMAT_V13K:
- open.mode_flags = BUFFER_META_ENABLE;
+ open.mode_flags |= BUFFER_META_ENABLE;
open.enc_cfg_id = ASM_MEDIA_FMT_V13K_FS;
break;
case FORMAT_EVRC:
- open.mode_flags = BUFFER_META_ENABLE;
+ open.mode_flags |= BUFFER_META_ENABLE;
open.enc_cfg_id = ASM_MEDIA_FMT_EVRC_FS;
break;
case FORMAT_AMRNB:
- open.mode_flags = BUFFER_META_ENABLE ;
+ open.mode_flags |= BUFFER_META_ENABLE ;
open.enc_cfg_id = ASM_MEDIA_FMT_AMRNB_FS;
break;
case FORMAT_AMRWB:
- open.mode_flags = BUFFER_META_ENABLE ;
+ open.mode_flags |= BUFFER_META_ENABLE ;
open.enc_cfg_id = ASM_MEDIA_FMT_AMRWB_FS;
break;
default:
@@ -1408,10 +1513,12 @@
fail_cmd:
return -EINVAL;
}
-int q6asm_open_write(struct audio_client *ac, uint32_t format)
+
+static int __q6asm_open_write(struct audio_client *ac, uint32_t format,
+ uint16_t bits_per_sample)
{
int rc = 0x00;
- struct asm_stream_cmd_open_write_v2 open;
+ struct asm_stream_cmd_open_write_v3 open;
if ((ac == NULL) || (ac->apr == NULL)) {
pr_err("%s: APR handle NULL\n", __func__);
@@ -1422,11 +1529,18 @@
q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
- open.hdr.opcode = ASM_STREAM_CMD_OPEN_WRITE_V2;
+ open.hdr.opcode = ASM_STREAM_CMD_OPEN_WRITE_V3;
open.mode_flags = 0x00;
+ if (ac->perf_mode)
+ open.mode_flags |= (ASM_LOW_LATENCY_STREAM_SESSION <<
+ ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_WRITE);
+ else
+ open.mode_flags |= (ASM_LEGACY_STREAM_SESSION <<
+ ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_WRITE);
+
/* source endpoint : matrix */
open.sink_endpointype = ASM_END_POINT_DEVICE_MATRIX;
- open.bits_per_sample = 16;
+ open.bits_per_sample = bits_per_sample;
open.postprocopo_id = get_asm_topology();
if (open.postprocopo_id == 0)
@@ -1473,6 +1587,17 @@
return -EINVAL;
}
+int q6asm_open_write(struct audio_client *ac, uint32_t format)
+{
+ return __q6asm_open_write(ac, format, 16);
+}
+
+int q6asm_open_write_v2(struct audio_client *ac, uint32_t format,
+ uint16_t bits_per_sample)
+{
+ return __q6asm_open_write(ac, format, bits_per_sample);
+}
+
int q6asm_open_read_write(struct audio_client *ac,
uint32_t rd_format,
uint32_t wr_format)
@@ -2130,8 +2255,9 @@
return q6asm_media_format_block_multi_aac(ac, cfg);
}
-int q6asm_media_format_block_pcm(struct audio_client *ac,
- uint32_t rate, uint32_t channels)
+static int __q6asm_media_format_block_pcm(struct audio_client *ac,
+ uint32_t rate, uint32_t channels,
+ uint16_t bits_per_sample)
{
struct asm_multi_channel_pcm_fmt_blk_v2 fmt;
u8 *channel_mapping;
@@ -2146,7 +2272,7 @@
fmt.fmt_blk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
sizeof(fmt.fmt_blk);
fmt.num_channels = channels;
- fmt.bits_per_sample = 16;
+ fmt.bits_per_sample = bits_per_sample;
fmt.sample_rate = rate;
fmt.is_signed = 1;
@@ -2173,9 +2299,25 @@
return -EINVAL;
}
-int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac,
+int q6asm_media_format_block_pcm(struct audio_client *ac,
+ uint32_t rate, uint32_t channels)
+{
+ return __q6asm_media_format_block_pcm(ac, rate,
+ channels, 16);
+}
+
+int q6asm_media_format_block_pcm_format_support(struct audio_client *ac,
uint32_t rate, uint32_t channels,
- bool use_default_chmap, char *channel_map)
+ uint16_t bits_per_sample)
+{
+ return __q6asm_media_format_block_pcm(ac, rate,
+ channels, bits_per_sample);
+}
+
+static int __q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac,
+ uint32_t rate, uint32_t channels,
+ bool use_default_chmap, char *channel_map,
+ uint16_t bits_per_sample)
{
struct asm_multi_channel_pcm_fmt_blk_v2 fmt;
u8 *channel_mapping;
@@ -2223,6 +2365,26 @@
fail_cmd:
return -EINVAL;
}
+
+int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac,
+ uint32_t rate, uint32_t channels,
+ bool use_default_chmap, char *channel_map)
+{
+ return __q6asm_media_format_block_multi_ch_pcm(ac, rate,
+ channels, use_default_chmap, channel_map, 16);
+}
+
+int q6asm_media_format_block_multi_ch_pcm_v2(
+ struct audio_client *ac,
+ uint32_t rate, uint32_t channels,
+ bool use_default_chmap, char *channel_map,
+ uint16_t bits_per_sample)
+{
+ return __q6asm_media_format_block_multi_ch_pcm(ac, rate,
+ channels, use_default_chmap, channel_map,
+ bits_per_sample);
+}
+
int q6asm_media_format_block_multi_aac(struct audio_client *ac,
struct asm_aac_cfg *cfg)
{
@@ -3342,7 +3504,7 @@
}
q6asm_add_hdr(ac, &hdr, sizeof(hdr), TRUE);
hdr.opcode = ASM_SESSION_CMD_GET_SESSIONTIME_V3;
- atomic_set(&ac->cmd_state, 1);
+ atomic_set(&ac->time_flag, 1);
pr_debug("%s: session[%d]opcode[0x%x]\n", __func__,
ac->session,
@@ -3352,8 +3514,8 @@
pr_err("Commmand 0x%x failed\n", hdr.opcode);
goto fail_cmd;
}
- rc = wait_event_timeout(ac->cmd_wait,
- (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+ rc = wait_event_timeout(ac->time_wait,
+ (atomic_read(&ac->time_flag) == 0), 5*HZ);
if (!rc) {
pr_err("%s: timeout in getting session time from DSP\n",
__func__);
@@ -3564,6 +3726,7 @@
{
pr_debug("%s\n", __func__);
memset(session, 0, sizeof(session));
+ set_custom_topology = 1;
config_debug_fs_init();
diff --git a/sound/usb/card.c b/sound/usb/card.c
index deeb5c7..f453dbd 100644
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
@@ -265,7 +265,7 @@
break;
}
}
-
+ switch_set_state(usbaudiosdev, 1);
return 0;
}
@@ -421,7 +421,6 @@
}
snd_usb_audio_create_proc(chip);
- switch_set_state(usbaudiosdev, 1);
*rchip = chip;
return 0;