Merge "block: row: Add some debug information on ROW queues"
diff --git a/Documentation/devicetree/bindings/arm/msm/jtag-mm.txt b/Documentation/devicetree/bindings/arm/msm/jtag-mm.txt
new file mode 100644
index 0000000..21dead3
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/jtag-mm.txt
@@ -0,0 +1,21 @@
+* JTAG-MM
+
+The jtag-mm entry specifies the memory mapped addresses for the debug and ETM
+registers. The jtag-mm driver uses these to save and restore the registers
+using memory mapped access during power collapse so as to retain their state
+accross power collapse. This is necessary in case cp14 access to the registers
+is not permitted.
+
+Required Properties:
+compatible: component name used for driver matching, should be "qcom,jtag-mm"
+reg: physical base address and length of the register set
+reg-names: should be "etm-base" for etm register set and "debug-base" for debug
+ register set.
+
+Example:
+jtag_mm: jtagmm@fc332000 {
+ compatible = "qcom,jtag-mm";
+ reg = <0xfc332000 0x1000>,
+ <0xfc333000 0x1000>;
+ reg-names = "etm-base","debug-base";
+ };
diff --git a/Documentation/devicetree/bindings/arm/msm/msm_bus.txt b/Documentation/devicetree/bindings/arm/msm/msm_bus.txt
index fb72525..5f534a2 100644
--- a/Documentation/devicetree/bindings/arm/msm/msm_bus.txt
+++ b/Documentation/devicetree/bindings/arm/msm/msm_bus.txt
@@ -1,6 +1,11 @@
MSM Bus Scaling Driver
-The msm bus scaling driver provides the ability to configure
+The bus scaling driver builds the topology of chipsets by adding
+bus devices (fabrics/NoCs) to the kernel tree. The device-tree
+data for bus devices contains the register addresses for QoS
+related registers on each NoC/Fabric.
+
+The bus scaling driver also provides the ability to configure
bus performance parameters across the entire chip-set.
Various clients use MSM scaling APIs to request bandwidth
between multiple master-slave pairs. The bus driver then finds
diff --git a/Documentation/devicetree/bindings/arm/msm/rpm-regulator-smd.txt b/Documentation/devicetree/bindings/arm/msm/rpm-regulator-smd.txt
index 93b5144..d930799 100644
--- a/Documentation/devicetree/bindings/arm/msm/rpm-regulator-smd.txt
+++ b/Documentation/devicetree/bindings/arm/msm/rpm-regulator-smd.txt
@@ -113,8 +113,14 @@
14 = 1.37
15 = 1.28
16 = 1.20
-- qcom,init-head-room: Voltage head room in uV required for the
- regulator
+- qcom,init-head-room: Voltage head room in mV required for the
+ regulator. This head room value should be used
+ in situations where the device connected to the
+ output of the regulator has low noise tolerance.
+ Note that the RPM independently enforces a
+ safety head room value for subregulated LDOs
+ which is sufficient to account for LDO drop-out
+ voltage.
- qcom,init-quiet-mode: Specify that quiet mode is needed for an SMPS
regulator in order to have lower output noise.
Supported values are:
diff --git a/Documentation/devicetree/bindings/iommu/msm_iommu.txt b/Documentation/devicetree/bindings/iommu/msm_iommu.txt
index f093f51..2a631ed 100644
--- a/Documentation/devicetree/bindings/iommu/msm_iommu.txt
+++ b/Documentation/devicetree/bindings/iommu/msm_iommu.txt
@@ -3,12 +3,19 @@
Required properties:
- compatible : one of:
- "qcom,msm-smmu-v2"
-- reg : offset and length of the register set for the device.
+- reg : offset and length of the register set for the device. Optional
+ offset and length for clock register for additional clock that
+ needs to be turned on for access to this IOMMU.
+- reg-names: "iommu_base", "clk_base" (optional)
+- label: name of this IOMMU instance.
Optional properties:
- qcom,iommu-secure-id : Secure identifier for the IOMMU block
- qcom,secure-context : boolean indicating that a context is secure and
programmed by the secure environment.
+- qcom,alt-vdd-supply : Alternative regulator needed to access IOMMU
+ configuration registers.
+- interrupts : should contain the performance monitor overflow interrupt number.
- List of sub nodes, one for each of the translation context banks supported.
Each sub node has the following required properties:
@@ -39,23 +46,25 @@
Example:
- qcom,iommu@fda64000 {
- compatible = "qcom,msm-smmu-v2";
- reg = <0xfda64000 0x10000>;
+ qcom,iommu@fda64000 {
+ compatible = "qcom,msm-smmu-v2";
+ reg = <0xfda64000 0x10000>;
+ reg-names = "iommu_base";
vdd-supply = <&gdsc_iommu>;
qcom,iommu-bfb-regs = <0x204c 0x2050>;
qcom,iommu-bfb-data = <0xffff 0xffce>;
+ label = "iommu_0";
- qcom,iommu-ctx@fda6c000 {
- reg = <0xfda6c000 0x1000>;
- interrupts = <0 70 0>;
- qcom,iommu-ctx-sids = <0 2>;
+ qcom,iommu-ctx@fda6c000 {
+ reg = <0xfda6c000 0x1000>;
+ interrupts = <0 70 0>;
+ qcom,iommu-ctx-sids = <0 2>;
label = "ctx_0";
- };
- qcom,iommu-ctx@fda6d000 {
- reg = <0xfda6d000 0x1000>;
- interrupts = <0 71 0>;
- qcom,iommu-ctx-sids = <1>;
+ };
+ qcom,iommu-ctx@fda6d000 {
+ reg = <0xfda6d000 0x1000>;
+ interrupts = <0 71 0>;
+ qcom,iommu-ctx-sids = <1>;
label = "ctx_1";
- };
- };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/media/video/msm-vidc.txt b/Documentation/devicetree/bindings/media/video/msm-vidc.txt
index 79a3ab5..2f2ea22 100644
--- a/Documentation/devicetree/bindings/media/video/msm-vidc.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-vidc.txt
@@ -13,6 +13,9 @@
or non-secure.
- load-freq-tbl : load (in macroblocks/sec) and corresponding vcodec clock
required for optimal performance in descending order.
+- hfi : supported Host-Firmware Interface, one of:
+ - "venus"
+ - "q6"
Example:
@@ -29,4 +32,5 @@
<243000 133330000>,
<108000 100000000>,
<36000 50000000>;
+ hfi = "venus";
};
diff --git a/Documentation/devicetree/bindings/regulator/fixed-regulator.txt b/Documentation/devicetree/bindings/regulator/fixed-regulator.txt
index 9cf57fd..7637adc 100644
--- a/Documentation/devicetree/bindings/regulator/fixed-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/fixed-regulator.txt
@@ -8,6 +8,7 @@
- startup-delay-us: startup time in microseconds
- enable-active-high: Polarity of GPIO is Active high
If this property is missing, the default assumed is Active low.
+- parent-supply: phandle to the parent supply/regulator node if one exists.
Any property defined as part of the core regulator
binding, defined in regulator.txt, can also be used.
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
index 032c814..3d022a3 100644
--- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -97,25 +97,42 @@
- compatible : "qcom,msm-auxpcm-resource"
- - qcom,msm-cpudai-auxpcm-clk: clock for auxpcm
+ - qcom,msm-cpudai-auxpcm-clk: clock for auxpcm. The first value is
+ for 8khz mode, the second is for
+ 16khz
- - qcom,msm-cpudai-auxpcm-mode: mode information
+ - qcom,msm-cpudai-auxpcm-mode: mode information. The first value is
+ for 8khz mode, the second is for
+ 16khz
0 - for PCM
- - qcom,msm-cpudai-auxpcm-sync: sync information
+ - qcom,msm-cpudai-auxpcm-sync: sync information. The first value is
+ for 8khz mode, the second is for
+ 16khz
- - qcom,msm-cpudai-auxpcm-frame: No.of bytes per frame
+ - qcom,msm-cpudai-auxpcm-frame: No.of bytes per frame. The first
+ value is for 8khz mode, the second
+ is for 16khz
5 - 256BPF
+ 4 - 128BPF
- - qcom,msm-cpudai-auxpcm-quant: Type of quantization
+ - qcom,msm-cpudai-auxpcm-quant: Type of quantization. The first
+ value is for 8khz mode, the second
+ is for 16khz
2 - Linear quantization
- qcom,msm-cpudai-auxpcm-slot: Slot number for multichannel scenario
+ The first value is for 8khz mode the
+ second is for 16khz
Value is 1
- - qcom,msm-cpudai-auxpcm-data: Data field - 0
+ - qcom,msm-cpudai-auxpcm-data: Data field - 0. The first value is
+ for 8khz mode, the second is for
+ 16khz
- - qcom,msm-cpudai-auxpcm-pcm-clk-rate: Clock rate for pcm - 2048000
+ - qcom,msm-cpudai-auxpcm-pcm-clk-rate: Clock rate for pcm - 2048000. The
+ first value is for 8khz mode, the
+ second is for auxpcm
[Second Level Nodes]
@@ -302,13 +319,13 @@
qcom,msm-auxpcm {
compatible = "qcom,msm-auxpcm-resource";
qcom,msm-cpudai-auxpcm-clk = "pcm_clk";
- qcom,msm-cpudai-auxpcm-mode = <0>;
- qcom,msm-cpudai-auxpcm-sync = <1>;
- qcom,msm-cpudai-auxpcm-frame = <5>;
- qcom,msm-cpudai-auxpcm-quant = <2>;
- qcom,msm-cpudai-auxpcm-slot = <1>;
- qcom,msm-cpudai-auxpcm-data = <0>;
- qcom,msm-cpudai-auxpcm-pcm-clk-rate = <2048000>;
+ 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>;
@@ -357,6 +374,10 @@
- taiko-mclk-clk : phandle to PMIC8941 clkdiv1 node.
- qcom,taiko-mclk-clk-freq : Taiko mclk Freq in Hz. currently only 9600000Hz
is supported.
+- prim-auxpcm-gpio-clk : GPIO on which AUXPCM clk signal is coming.
+- prim-auxpcm-gpio-sync : GPIO on which AUXPCM SYNC signal is coming.
+- prim-auxpcm-gpio-din : GPIO on which AUXPCM DIN signal is coming.
+- prim-auxpcm-gpio-dout : GPIO on which AUXPCM DOUT signal is coming.
Optional properties:
- qcom,hdmi-audio-rx: specifies if HDMI audio support is enabled or not.
@@ -401,6 +422,11 @@
qcom,taiko-mclk-clk-freq = <9600000>;
qcom,hdmi-audio-rx;
+
+ prim-auxpcm-gpio-clk = <&msmgpio 65 0>;
+ prim-auxpcm-gpio-sync = <&msmgpio 66 0>;
+ prim-auxpcm-gpio-din = <&msmgpio 67 0>;
+ prim-auxpcm-gpio-dout = <&msmgpio 68 0>;
};
* msm-dai-mi2s
diff --git a/Documentation/devicetree/bindings/tty/serial/msm_serial_hs.txt b/Documentation/devicetree/bindings/tty/serial/msm_serial_hs.txt
new file mode 100644
index 0000000..3534823
--- /dev/null
+++ b/Documentation/devicetree/bindings/tty/serial/msm_serial_hs.txt
@@ -0,0 +1,70 @@
+* Qualcomm MSM HSUART
+
+Required properties:
+- compatible :
+ - "qcom,msm-hsuart-v14" to be used for UARTDM Core v1.4
+- reg : offset and length of the register set for both the device,
+ uart core and bam core
+- reg-names : names of the uart core and bam core.
+- interrupts : should contain the uart interrupt.
+- interrupt-names : names of interrupts to be used.
+- bam-tx-ep-pipe-index : BAM TX Endpoint Pipe Index for HSUART
+- bam-rx-ep-pipe-index : BAM RX Endpoint Pipe Index for HSUART
+
+BLSP has a static pipe allocation and assumes a pair-pipe for each uart core.
+Pipes [2*i : 2*i+1] are allocated for UART cores where i = [0 : 5].
+Hence, Minimum and Maximum permitted value of endpoint pipe index to be used
+with uart core is 0 and 11 respectively.
+
+There is one HSUART block used in MSM devices,
+"qcom,msm-hsuart-v14". The msm-serial-hs driver is
+able to handle this, and matches against the "qcom,msm-hsuart-v14"
+as the compatibility.
+
+The registers for the "qcom,msm-hsuart-v14" device need to specify both
+register blocks - uart core and bam core.
+
+Example:
+
+ uart7@f995d000 {
+ compatible = "qcom,msm-hsuart-v14";
+ reg = <0xf995d000 0x1000>,
+ <0xf9944000 0x5000>;
+ reg-names = "core_mem", "bam_mem";
+ interrupts = <0 113 0>, <0 239 0>;
+ interrupt-names = "core_irq", "bam_irq";
+ };
+
+Optional properties:
+- qcom,<gpio-name>-gpio : handle to the GPIO node, see "gpios property" in
+Documentation/devicetree/bindings/gpio/gpio.txt.
+"gpio-name" can be "tx", "rx", "cts" and "rfr" based on number of UART GPIOs
+need to configured.
+Gpio's are optional if it is required to be not configured by UART driver or
+case where there is nothing connected and we want to use internal loopback mode
+for uart.
+- qcom, wakeup_irq : UART RX GPIO IRQ line to be configured as wakeup source.
+- qcom,inject_rx_on_wakeup : inject_rx_on_wakeup enables feature where on
+receiving interrupt with UART RX GPIO IRQ line (i.e. above wakeup_irq property),
+HSUART driver injects provided character with property rx_to_inject.
+- qcom, rx_to_inject : The character to be inserted on wakeup.
+
+
+Example:
+
+ uart7: uart@f995d000 {
+ compatible = "qcom,msm-hsuart-v14"
+ reg = <0x19c40000 0x1000">,
+ <0xf9944000 0x5000>;
+ reg-names = "core_mem", "bam_mem";
+ interrupts = <0 113 0>, <0 239 0>;
+ interrupt-names = "core_irq", "bam_irq";
+
+ qcom,tx-gpio = <&msmgpio 41 0x00>;
+ qcom,rx-gpio = <&msmgpio 42 0x00>;
+ qcom,cts-gpio = <&msmgpio 43 0x00>;
+ qcom,rfr-gpio = <&msmgpio 44 0x00>;
+
+ qcom,bam-tx-ep-pipe-index = <0>;
+ qcom,bam-rx-ep-pipe-index = <1>;
+ };
diff --git a/Documentation/devicetree/bindings/usb/msm-ssusb.txt b/Documentation/devicetree/bindings/usb/msm-ssusb.txt
index 5d10940..7add91f 100644
--- a/Documentation/devicetree/bindings/usb/msm-ssusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-ssusb.txt
@@ -41,7 +41,12 @@
- qcom,charging-disabled: If present then battery charging using USB
is disabled.
- qcom,dwc-hsphy-init: This property if present represents phy init
- value to be used for overriding HSPHY parameters.
+ value to be used for overriding HSPHY parameters into QSCRATCH register.
+ This 32 bit value represents parameters as follows:
+ bits 0-5 PARAMETER_OVERRIDE_A
+ bits 6-12 PARAMETER_OVERRIDE_B
+ bits 13-19 PARAMETER_OVERRIDE_C
+ bits 20-25 PARAMETER_OVERRIDE_D
Example MSM USB3.0 controller device node :
usb@f9200000 {
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 23181d9..5a9cecf 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -782,6 +782,7 @@
select HAVE_CLK_PREPARE
select NEED_MACH_MEMORY_H
select NEED_MACH_IO_H
+ select SOC_BUS
help
Support for Qualcomm MSM/QSD based systems. This runs on the
apps processor of the MSM/QSD and depends on a shared memory
diff --git a/arch/arm/boot/dts/msm-iommu.dtsi b/arch/arm/boot/dts/msm-iommu.dtsi
index 8343c7a..024c11f 100755
--- a/arch/arm/boot/dts/msm-iommu.dtsi
+++ b/arch/arm/boot/dts/msm-iommu.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
@@ -17,7 +17,10 @@
#size-cells = <1>;
ranges;
reg = <0xfda64000 0x10000>;
+ reg-names = "iommu_base";
vdd-supply = <&gdsc_jpeg>;
+ qcom,needs-alt-core-clk;
+ label = "jpeg_iommu";
status = "disabled";
qcom,iommu-bfb-regs = <0x204c
@@ -80,8 +83,10 @@
#size-cells = <1>;
ranges;
reg = <0xfd928000 0x10000>;
+ reg-names = "iommu_base";
vdd-supply = <&gdsc_mdss>;
qcom,iommu-secure-id = <1>;
+ label = "mdp_iommu";
status = "disabled";
qcom,iommu-bfb-regs = <0x204c
@@ -143,10 +148,13 @@
#address-cells = <1>;
#size-cells = <1>;
ranges;
- reg = <0xfdc84000 0x10000>;
+ reg = <0xfdc84000 0x10000
+ 0xfdce0004 0x4>;
+ reg-names = "iommu_base", "clk_base";
vdd-supply = <&gdsc_venus>;
qcom,iommu-secure-id = <0>;
qcom,needs-alt-core-clk;
+ label = "venus_iommu";
status = "disabled";
qcom,iommu-bfb-regs = <0x204c
@@ -229,8 +237,11 @@
#size-cells = <1>;
ranges;
reg = <0xfdb10000 0x10000>;
+ reg-names = "iommu_base";
vdd-supply = <&gdsc_oxili_cx>;
+ qcom,alt-vdd-supply = <&gdsc_oxili_gx>;
qcom,needs-alt-core-clk;
+ label = "kgsl_iommu";
status = "disabled";
qcom,iommu-bfb-regs = <0x204c
@@ -280,7 +291,10 @@
#size-cells = <1>;
ranges;
reg = <0xfda44000 0x10000>;
+ reg-names = "iommu_base";
vdd-supply = <&gdsc_vfe>;
+ qcom,needs-alt-core-clk;
+ label = "vfe_iommu";
status = "disabled";
qcom,iommu-bfb-regs = <0x204c
diff --git a/arch/arm/boot/dts/msm8226-iommu.dtsi b/arch/arm/boot/dts/msm8226-iommu.dtsi
new file mode 100644
index 0000000..66a7848
--- /dev/null
+++ b/arch/arm/boot/dts/msm8226-iommu.dtsi
@@ -0,0 +1,37 @@
+/* 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/ "msm-iommu.dtsi"
+
+&jpeg_iommu {
+ status = "ok";
+};
+
+&mdp_iommu {
+ status = "ok";
+ /* HACK: set to -1 during pre-si due to lack of TZ */
+ qcom,iommu-secure-id = <0xFFFFFFFF>;
+};
+
+&venus_iommu {
+ status = "ok";
+ /* HACK: set to -1 during pre-si due to lack of TZ */
+ qcom,iommu-secure-id = <0xFFFFFFFF>;
+};
+
+&kgsl_iommu {
+ status = "ok";
+};
+
+&vfe_iommu {
+ status = "ok";
+};
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index 36bcdd7..854a708 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.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
@@ -13,6 +13,7 @@
/include/ "skeleton.dtsi"
/include/ "msm8226-ion.dtsi"
/include/ "msm-gdsc.dtsi"
+/include/ "msm8226-iommu.dtsi"
/ {
model = "Qualcomm MSM 8226";
@@ -546,6 +547,17 @@
<0x1d80002b>; /* WLED */
};
+ i2c@f9926000 { /* BLSP-1 QUP-4 */
+ cell-index = <0>;
+ compatible = "qcom,i2c-qup";
+ reg = <0xf9926000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg-names = "qup_phys_addr";
+ interrupts = <0 98 0>;
+ interrupt-names = "qup_err_intr";
+ qcom,i2c-bus-freq = <100000>;
+ };
};
&gdsc_venus {
diff --git a/arch/arm/boot/dts/msm8974-cdp.dtsi b/arch/arm/boot/dts/msm8974-cdp.dtsi
index 5e65ca4..3b3402d 100644
--- a/arch/arm/boot/dts/msm8974-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8974-cdp.dtsi
@@ -180,6 +180,15 @@
qcom,model = "msm8974-taiko-cdp-snd-card";
qcom,hdmi-audio-rx;
};
+
+ usb2_otg_sw: regulator-tpd4s214 {
+ compatible = "regulator-fixed";
+ regulator-name = "usb2_otg_sw";
+ gpio = <&pm8941_gpios 18 0>;
+ parent-supply = <&pm8941_boost>;
+ startup-delay-us = <17000>;
+ enable-active-high;
+ };
};
&spmi_bus {
@@ -374,6 +383,14 @@
};
gpio@d100 { /* GPIO 18 */
+ /* usb2_otg_sw regulator enable */
+ qcom,mode = <1>; /* Digital output */
+ qcom,output-type = <0>; /* CMOS logic */
+ qcom,invert = <0>; /* Output low initially */
+ qcom,vin-sel = <2>; /* PM8941 S3 = 1.8 V */
+ qcom,src-sel = <0>; /* Constant */
+ qcom,out-strength = <2>; /* Medium drive strength */
+ qcom,master-en = <1>; /* Enable GPIO */
};
gpio@d200 { /* GPIO 19 */
diff --git a/arch/arm/boot/dts/msm8974-liquid.dtsi b/arch/arm/boot/dts/msm8974-liquid.dtsi
index 98ed0bf..7368788 100644
--- a/arch/arm/boot/dts/msm8974-liquid.dtsi
+++ b/arch/arm/boot/dts/msm8974-liquid.dtsi
@@ -563,6 +563,12 @@
};
};
+&slim_msm {
+ taiko_codec {
+ qcom,cdc-micbias2-ext-cap;
+ };
+};
+
&spi_epm {
epm-adc@0 {
compatible = "cy,epm-adc-cy8c5568lti-114";
diff --git a/arch/arm/boot/dts/msm8974-pm.dtsi b/arch/arm/boot/dts/msm8974-pm.dtsi
index b8a977b..1302ccb 100644
--- a/arch/arm/boot/dts/msm8974-pm.dtsi
+++ b/arch/arm/boot/dts/msm8974-pm.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. 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
@@ -183,11 +183,11 @@
reg = <0x0>;
qcom,mode = <0>; /* MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT */
qcom,xo = <1>; /* ON */
- qcom,l2 = <3>; /* ACTIVE */
- qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
- qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
- qcom,vdd-dig-upper-bound = <5>; /* MAX */
- qcom,vdd-dig-lower-bound = <3>; /* ACTIVE */
+ qcom,l2 = <2>; /* Retention */
+ qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
+ qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
+ qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
+ qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
qcom,latency-us = <1>;
qcom,ss-power = <784>;
qcom,energy-overhead = <190000>;
@@ -198,27 +198,26 @@
reg = <0x1>;
qcom,mode = <4>; /* MSM_PM_SLEEP_MODE_RETENTION*/
qcom,xo = <1>; /* ON */
- qcom,l2 = <3>; /* ACTIVE */
- qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
- qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
- qcom,vdd-dig-upper-bound = <5>; /* MAX */
- qcom,vdd-dig-lower-bound = <3>; /* ACTIVE */
+ qcom,l2 = <2>; /* Retention */
+ qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
+ qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
+ qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
+ qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
qcom,latency-us = <75>;
qcom,ss-power = <735>;
qcom,energy-overhead = <77341>;
qcom,time-overhead = <105>;
};
-
qcom,lpm-level@2 {
reg = <0x2>;
qcom,mode = <2>; /* MSM_PM_SLEEP_MODE_STANDALONE_POWER_COLLAPSE */
qcom,xo = <1>; /* ON */
- qcom,l2 = <3>; /* ACTIVE */
- qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
- qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
- qcom,vdd-dig-upper-bound = <5>; /* MAX */
- qcom,vdd-dig-lower-bound = <3>; /* ACTIVE */
+ qcom,l2 = <2>; /* Retention */
+ qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
+ qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
+ qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
+ qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
qcom,latency-us = <95>;
qcom,ss-power = <725>;
qcom,energy-overhead = <99500>;
@@ -230,10 +229,10 @@
qcom,mode = <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
qcom,xo = <1>; /* ON */
qcom,l2 = <1>; /* GDHS */
- qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
- qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
- qcom,vdd-dig-upper-bound = <5>; /* MAX */
- qcom,vdd-dig-lower-bound = <3>; /* ACTIVE */
+ qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
+ qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
+ qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
+ qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
qcom,latency-us = <2000>;
qcom,ss-power = <138>;
qcom,energy-overhead = <1208400>;
@@ -244,11 +243,11 @@
reg = <0x4>;
qcom,mode = <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
qcom,xo = <1>; /* ON */
- qcom,l2 = <0>; /* OFF */
- qcom,vdd-mem-upper-bound = <1050000>; /* ACTIVE */
- qcom,vdd-mem-lower-bound = <750000>; /* RETENTION HIGH */
- qcom,vdd-dig-upper-bound = <3>; /* ACTIVE */
- qcom,vdd-dig-lower-bound = <2>; /* RETENTION HIGH */
+ qcom,l2 = <1>; /* GDHS */
+ qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
+ qcom,vdd-mem-lower-bound = <950000>; /* SVS SOC */
+ qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
+ qcom,vdd-dig-lower-bound = <3>; /* SVS SOC */
qcom,latency-us = <3000>;
qcom,ss-power = <110>;
qcom,energy-overhead = <1250300>;
@@ -260,10 +259,10 @@
qcom,mode = <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
qcom,xo = <0>; /* OFF */
qcom,l2 = <1>; /* GDHS */
- qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
- qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
- qcom,vdd-dig-upper-bound = <5>; /* MAX */
- qcom,vdd-dig-lower-bound = <3>; /* ACTIVE */
+ qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
+ qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
+ qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
+ qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
qcom,latency-us = <3000>;
qcom,ss-power = <68>;
qcom,energy-overhead = <1350200>;
@@ -272,17 +271,17 @@
qcom,lpm-level@6 {
reg = <0x6>;
- qcom,mode = <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
+ qcom,mode= <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
qcom,xo = <0>; /* OFF */
- qcom,l2 = <0>; /* OFF */
- qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
- qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
- qcom,vdd-dig-upper-bound = <5>; /* MAX */
- qcom,vdd-dig-lower-bound = <3>; /* ACTIVE */
- qcom,latency-us = <10300>;
- qcom,ss-power = <63>;
- qcom,energy-overhead = <2128000>;
- qcom,time-overhead = <18200>;
+ qcom,l2 = <1>; /* GDHS */
+ qcom,vdd-mem-upper-bound = <950000>; /* NORMAL */
+ qcom,vdd-mem-lower-bound = <950000>; /* SVS SOC */
+ qcom,vdd-dig-upper-bound = <4>; /* NORMAL */
+ qcom,vdd-dig-lower-bound = <3>; /* SVS SOC */
+ qcom,latency-us = <18000>;
+ qcom,ss-power = <10>;
+ qcom,energy-overhead = <3202600>;
+ qcom,time-overhead = <27000>;
};
qcom,lpm-level@7 {
@@ -290,25 +289,10 @@
qcom,mode= <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
qcom,xo = <0>; /* OFF */
qcom,l2 = <0>; /* OFF */
- qcom,vdd-mem-upper-bound = <1050000>; /* ACTIVE */
- qcom,vdd-mem-lower-bound = <750000>; /* RETENTION HIGH */
- qcom,vdd-dig-upper-bound = <3>; /* ACTIVE */
- qcom,vdd-dig-lower-bound = <2>; /* RETIONTION HIGH */
- qcom,latency-us = <18000>;
- qcom,ss-power = <10>;
- qcom,energy-overhead = <3202600>;
- qcom,time-overhead = <27000>;
- };
-
- qcom,lpm-level@8 {
- reg = <0x8>;
- qcom,mode= <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
- qcom,xo = <0>; /* OFF */
- qcom,l2 = <0>; /* OFF */
- qcom,vdd-mem-upper-bound = <750000>; /* RETENTION HIGH */
- qcom,vdd-mem-lower-bound = <750000>; /* RETENTION LOW */
- qcom,vdd-dig-upper-bound = <2>; /* RETENTION HIGH */
- qcom,vdd-dig-lower-bound = <0>; /* RETENTION LOW */
+ qcom,vdd-mem-upper-bound = <950000>; /* SVS SOC */
+ qcom,vdd-mem-lower-bound = <675000>; /* RETENTION */
+ qcom,vdd-dig-upper-bound = <3>; /* SVS SOC */
+ qcom,vdd-dig-lower-bound = <1>; /* RETENTION */
qcom,latency-us = <20000>;
qcom,ss-power = <2>;
qcom,energy-overhead = <4252000>;
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 9be99af..8838953 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -70,6 +70,7 @@
<783360 410000000>,
<489600 266670000>,
<244800 133330000>;
+ hfi = "venus";
};
qcom,wfd {
@@ -430,6 +431,10 @@
qcom,cdc-mclk-gpios = <&pm8941_gpios 15 0>;
taiko-mclk-clk = <&pm8941_clkdiv1>;
qcom,taiko-mclk-clk-freq = <9600000>;
+ prim-auxpcm-gpio-clk = <&msmgpio 65 0>;
+ prim-auxpcm-gpio-sync = <&msmgpio 66 0>;
+ prim-auxpcm-gpio-din = <&msmgpio 67 0>;
+ prim-auxpcm-gpio-dout = <&msmgpio 68 0>;
};
spmi_bus: qcom,spmi@fc4c0000 {
@@ -655,6 +660,7 @@
vbus_dwc3-supply = <&pm8941_mvs1>;
qcom,dwc-usb3-msm-dbm-eps = <4>;
qcom,vdd-voltage-level = <1 5 7>;
+ qcom,dwc-hsphy-init = <0x00D195A4>;
qcom,msm-bus,name = "usb3";
qcom,msm-bus,num-cases = <2>;
@@ -821,13 +827,13 @@
qcom,msm-auxpcm {
compatible = "qcom,msm-auxpcm-resource";
qcom,msm-cpudai-auxpcm-clk = "pcm_clk";
- qcom,msm-cpudai-auxpcm-mode = <0>;
- qcom,msm-cpudai-auxpcm-sync = <1>;
- qcom,msm-cpudai-auxpcm-frame = <5>;
- qcom,msm-cpudai-auxpcm-quant = <2>;
- qcom,msm-cpudai-auxpcm-slot = <1>;
- qcom,msm-cpudai-auxpcm-data = <0>;
- qcom,msm-cpudai-auxpcm-pcm-clk-rate = <2048000>;
+ 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>;
diff --git a/arch/arm/boot/dts/msm9625-coresight.dtsi b/arch/arm/boot/dts/msm9625-coresight.dtsi
index f01fe63..9a49c32 100644
--- a/arch/arm/boot/dts/msm9625-coresight.dtsi
+++ b/arch/arm/boot/dts/msm9625-coresight.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
@@ -107,11 +107,23 @@
coresight-child-ports = <7>;
};
+ etm: etm@fc332000 {
+ compatible = "arm,coresight-etm";
+ reg = <0xfc332000 0x1000>;
+
+ coresight-id = <8>;
+ coresight-name = "coresight-etm";
+ coresight-nr-inports = <0>;
+ coresight-outports = <0>;
+ coresight-child-list = <&funnel_in0>;
+ coresight-child-ports = <4>;
+ };
+
csr: csr@fc302000 {
compatible = "qcom,coresight-csr";
reg = <0xfc302000 0x1000>;
- coresight-id = <8>;
+ coresight-id = <9>;
coresight-name = "coresight-csr";
coresight-nr-inports = <0>;
};
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index 2fbff6d..d374b59 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. 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
@@ -602,6 +602,12 @@
qcom,bam-pipe-pair = <2>;
};
+ jtag_mm: jtagmm@fc332000 {
+ compatible = "qcom,jtag-mm";
+ reg = <0xfc332000 0x1000>,
+ <0xfc330000 0x1000>;
+ reg-names = "etm-base","debug-base";
+ };
};
/include/ "msm-pm8019-rpm-regulator.dtsi"
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
new file mode 100644
index 0000000..3db20a2
--- /dev/null
+++ b/arch/arm/configs/msm8610_defconfig
@@ -0,0 +1,179 @@
+# CONFIG_ARM_PATCH_PHYS_VIRT is not set
+CONFIG_EXPERIMENTAL=y
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SYSVIPC=y
+CONFIG_RCU_FAST_NO_HZ=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_DEBUG=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_RESOURCE_COUNTERS=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+CONFIG_RELAY=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_RD_BZIP2=y
+CONFIG_RD_LZMA=y
+CONFIG_PANIC_TIMEOUT=5
+CONFIG_KALLSYMS_ALL=y
+CONFIG_ASHMEM=y
+CONFIG_EMBEDDED=y
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=m
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_EFI_PARTITION=y
+CONFIG_ARCH_MSM=y
+CONFIG_ARCH_MSM8910=y
+CONFIG_ARCH_MSM8610=y
+CONFIG_ARCH_MSM8226=y
+CONFIG_SND_SOC_MSM8226=y
+# CONFIG_MSM_STACKED_MEMORY is not set
+CONFIG_CPU_HAS_L2_PMU=y
+# CONFIG_MSM_FIQ_SUPPORT is not set
+# CONFIG_MSM_PROC_COMM is not set
+CONFIG_MSM_SMD=y
+CONFIG_MSM_SMD_PKG4=y
+# CONFIG_MSM_HW3D is not set
+CONFIG_MSM_DIRECT_SCLK_ACCESS=y
+CONFIG_MSM_WATCHDOG_V2=y
+CONFIG_MSM_ADSP_LOADER=m
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_SMP=y
+CONFIG_SCHED_MC=y
+CONFIG_ARM_ARCH_TIMER=y
+CONFIG_HOTPLUG_CPU=y
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+CONFIG_HIGHMEM=y
+CONFIG_VMALLOC_RESERVE=0x19000000
+CONFIG_USE_OF=y
+CONFIG_VFP=y
+CONFIG_NEON=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_SUSPEND is not set
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=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_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+CONFIG_IPV6=y
+CONFIG_IPV6_PRIVACY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+CONFIG_IPV6_MIP6=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+CONFIG_NETFILTER=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_CRYPT=y
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_EVBUG=m
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_INPUT_GPIO=m
+CONFIG_SERIAL_MSM_HSL=y
+CONFIG_SERIAL_MSM_HSL_CONSOLE=y
+CONFIG_DIAG_CHAR=y
+CONFIG_HW_RANDOM=y
+CONFIG_SPMI=y
+CONFIG_SPMI_MSM_PMIC_ARB=y
+CONFIG_MSM_QPNP_INT=y
+CONFIG_SLIMBUS=y
+CONFIG_SLIMBUS_MSM_NGD=y
+CONFIG_DEBUG_GPIO=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_I2C=y
+CONFIG_WCD9306_CODEC=y
+# CONFIG_HWMON is not set
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_STUB=y
+CONFIG_ION=y
+CONFIG_ION_MSM=y
+CONFIG_FB=y
+CONFIG_FB_VIRTUAL=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_SOC=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_DEBUG_FILES=y
+CONFIG_USB_GADGET_DEBUG_FS=y
+CONFIG_USB_CI13XXX_MSM=y
+CONFIG_USB_G_ANDROID=y
+CONFIG_MMC=y
+CONFIG_MMC_PERF_PROFILING=y
+CONFIG_MMC_UNSAFE_RESUME=y
+CONFIG_MMC_CLKGATE=y
+CONFIG_MMC_EMBEDDED_SDIO=y
+CONFIG_MMC_PARANOID_SD_INIT=y
+CONFIG_MMC_BLOCK_MINORS=32
+CONFIG_MMC_TEST=m
+CONFIG_MMC_MSM=y
+CONFIG_STAGING=y
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_ANDROID_LOGGER=y
+CONFIG_ANDROID_RAM_CONSOLE=y
+CONFIG_ANDROID_TIMED_GPIO=y
+CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_MSM_IOMMU=y
+CONFIG_SPS=y
+CONFIG_SPS_SUPPORT_NDP_BAM=y
+CONFIG_MMC_MSM_SPS_SUPPORT=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT4_FS=y
+CONFIG_FUSE_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_FS=y
+CONFIG_SCHEDSTATS=y
+CONFIG_TIMER_STATS=y
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_DEBUG_USER=y
+CONFIG_KEYS=y
+CONFIG_CRYPTO_MD4=y
+CONFIG_CRYPTO_SHA256=y
+CONFIG_CRYPTO_AES=y
+CONFIG_CRYPTO_ARC4=y
+CONFIG_CRYPTO_TWOFISH=y
+# CONFIG_CRYPTO_HW is not set
+CONFIG_CRC_CCITT=y
+CONFIG_LIBCRC32C=y
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index f464a55..4e9f707 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -253,7 +253,6 @@
CONFIG_PMIC8XXX_VIBRATOR=y
CONFIG_QSEECOM=y
CONFIG_USB_HSIC_SMSC_HUB=y
-CONFIG_SCSI=y
CONFIG_SCSI_TGT=y
CONFIG_BLK_DEV_SD=y
CONFIG_CHR_DEV_SG=y
@@ -262,6 +261,8 @@
CONFIG_SCSI_CONSTANTS=y
CONFIG_SCSI_LOGGING=y
CONFIG_SCSI_SCAN_ASYNC=y
+CONFIG_ATA=y
+CONFIG_SATA_AHCI_MSM=y
CONFIG_MD=y
CONFIG_BLK_DEV_DM=y
CONFIG_DM_CRYPT=y
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index e54459d..5d37dd0 100644
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -258,7 +258,6 @@
CONFIG_PMIC8XXX_VIBRATOR=y
CONFIG_QSEECOM=y
CONFIG_USB_HSIC_SMSC_HUB=y
-CONFIG_SCSI=y
CONFIG_SCSI_TGT=y
CONFIG_BLK_DEV_SD=y
CONFIG_CHR_DEV_SG=y
@@ -267,6 +266,8 @@
CONFIG_SCSI_CONSTANTS=y
CONFIG_SCSI_LOGGING=y
CONFIG_SCSI_SCAN_ASYNC=y
+CONFIG_ATA=y
+CONFIG_SATA_AHCI_MSM=y
CONFIG_MD=y
CONFIG_BLK_DEV_DM=y
CONFIG_DM_CRYPT=y
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index 136cb5a..71b6990 100644
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -45,6 +45,7 @@
CONFIG_MSM_SMD=y
CONFIG_MSM_SMD_PKG4=y
CONFIG_MSM_BAM_DMUX=y
+CONFIG_MSM_IPC_LOGGING=y
CONFIG_MSM_IPC_ROUTER=y
CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
CONFIG_MSM_IPC_ROUTER_SECURITY=y
@@ -329,6 +330,7 @@
CONFIG_FB_MSM_MDSS=y
CONFIG_FB_MSM_MDSS_WRITEBACK=y
CONFIG_FB_MSM_MDSS_HDMI_PANEL=y
+CONFIG_FB_MSM_MDSS_HDMI_MHL_SII8334=y
CONFIG_BACKLIGHT_LCD_SUPPORT=y
# CONFIG_LCD_CLASS_DEVICE is not set
CONFIG_BACKLIGHT_CLASS_DEVICE=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index eb3c315..6770fe4 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -44,6 +44,7 @@
CONFIG_MSM_SMD=y
CONFIG_MSM_SMD_PKG4=y
CONFIG_MSM_BAM_DMUX=y
+CONFIG_MSM_IPC_LOGGING=y
CONFIG_MSM_IPC_ROUTER=y
CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
CONFIG_MSM_IPC_ROUTER_SECURITY=y
@@ -73,6 +74,8 @@
CONFIG_MSM_L1_RECOV_ERR_PANIC=y
CONFIG_MSM_L1_ERR_LOG=y
CONFIG_MSM_L2_ERP_PRINT_ACCESS_ERRORS=y
+CONFIG_MSM_L2_ERP_PORT_PANIC=y
+CONFIG_MSM_L2_ERP_1BIT_PANIC=y
CONFIG_MSM_L2_ERP_2BIT_PANIC=y
CONFIG_MSM_CACHE_DUMP=y
CONFIG_MSM_CACHE_DUMP_ON_PANIC=y
@@ -330,6 +333,7 @@
CONFIG_FB_MSM_MDSS=y
CONFIG_FB_MSM_MDSS_WRITEBACK=y
CONFIG_FB_MSM_MDSS_HDMI_PANEL=y
+CONFIG_FB_MSM_MDSS_HDMI_MHL_SII8334=y
CONFIG_BACKLIGHT_LCD_SUPPORT=y
# CONFIG_LCD_CLASS_DEVICE is not set
CONFIG_BACKLIGHT_CLASS_DEVICE=y
diff --git a/arch/arm/configs/msm9625_defconfig b/arch/arm/configs/msm9625_defconfig
index decd8f2..a2d21d9 100644
--- a/arch/arm/configs/msm9625_defconfig
+++ b/arch/arm/configs/msm9625_defconfig
@@ -40,6 +40,7 @@
CONFIG_MSM_SMD=y
CONFIG_MSM_SMD_PKG4=y
CONFIG_MSM_BAM_DMUX=y
+CONFIG_MSM_IPC_LOGGING=y
CONFIG_MSM_IPC_ROUTER=y
CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
CONFIG_MSM_RPM_REGULATOR_SMD=y
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 5b0ac52..3f22221 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -184,6 +184,7 @@
select ARM_USE_USER_ACCESSIBLE_TIMERS
select MSM_USE_USER_ACCESSIBLE_TIMERS
select MSM_CPU_PWRCTL
+ select MSM_LPM_TEST
config ARCH_MSM8930
bool "MSM8930"
@@ -287,6 +288,7 @@
select QMI_ENCDEC
select DONT_MAP_HOLE_AFTER_MEMBANK0
select SENSORS_ADSP
+ select MSM_ULTRASOUND_B
config ARCH_MPQ8092
bool "MPQ8092"
@@ -374,6 +376,7 @@
select MSM_QDSP6V2_CODECS
select MSM_AUDIO_QDSP6V2 if SND_SOC
select CPU_HAS_L2_PMU
+ select MSM_JTAG_MM if MSM_QDSS
config ARCH_MSM8910
bool "MSM8910"
@@ -522,6 +525,17 @@
enables the MPM driver that supports initialization from a device
tree
+config MSM_LPM_TEST
+ bool "Low Power Mode test framework"
+ depends on MSM_RPM
+ depends on MSM_PM8X60
+ help
+ LPM_TEST is a test framework that assists in exercising the low
+ power mode algorithm on MSM targets. This test framework tracks
+ notifications sent during entry/exit of the low power modes and
+ processes them to measure various stats including latency
+ measurement.
+
config MSM_XO
bool
@@ -1568,6 +1582,16 @@
to perform QMI message marshaling and transport them over IPC
Router.
+config MSM_TEST_QMI_CLIENT
+ depends on MSM_QMI_INTERFACE
+ bool "MSM TEST QMI CLIENT"
+ help
+ The sample QMI client provides a test code for QMI usage. The
+ test_service client driver uses QMI interface library to send
+ and receive QMI messages over IPC Router. The test code sends
+ a synchronous QMI request to the test_service and handles the
+ QMI responses.
+
config MSM_ONCRPCROUTER_DEBUG
depends on MSM_ONCRPCROUTER
default y
@@ -2250,6 +2274,19 @@
For production builds, you should probably say 'N' here to avoid
potential power, performance and memory penalty.
+config MSM_JTAG_MM
+ bool "ETM trace and debug support across power collapse using memory mapped access"
+ help
+ Enables support for kernel debugging (specifically breakpoints) and
+ processor tracing using ETM across power collapse both for JTag and
+ OS hosted software running on the target. Enabling this will ensure
+ debug and ETM registers are saved and restored across power collapse.
+ Needed on targets on which cp14 access to debug and ETM registers is
+ not permitted and so memory mapped access is necessary.
+
+ For production builds, you should probably say 'N' here to avoid
+ potential power, performance and memory penalty.
+
config MSM_ETM
tristate "Enable MSM ETM and ETB"
depends on ARCH_MSM8X60
@@ -2390,6 +2427,16 @@
HW and services, calculating input events
upon the ultrasound data.
+config MSM_ULTRASOUND_B
+ bool "QDSP6V2 HW Ultrasound support"
+ help
+ Enable HW Ultrasound support in QDSP6V2.
+ QDSP6V2 can support HW encoder & decoder and
+ ultrasound processing. It will enable
+ ultrasound data paths between
+ HW and services, calculating input events
+ upon the ultrasound data.
+
config MSM_RPC_VIBRATOR
bool "RPC based MSM Vibrator Support"
depends on MSM_ONCRPCROUTER
@@ -2742,4 +2789,9 @@
stand alone power collapse operation. Selecting this option
ensures that they are always off.
+config MSM_UARTDM_Core_v14
+ bool "Use MSM BLSP based HSUART Core v1.4"
+ depends on SERIAL_MSM_HS
+ help
+ Select if BLSP based UART Core v.14 or higher is present.
endif
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 594bb5f..b69f397 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -60,6 +60,7 @@
obj-$(CONFIG_CPU_V6) += idle-v6.o
obj-$(CONFIG_CPU_V7) += idle-v7.o
obj-$(CONFIG_MSM_JTAG) += jtag.o
+obj-$(CONFIG_MSM_JTAG_MM) += jtag-mm.o
msm-etm-objs := etm.o
obj-$(CONFIG_MSM_ETM) += msm-etm.o
@@ -138,6 +139,7 @@
obj-$(CONFIG_MSM_IPC_ROUTER)+= ipc_socket.o
obj-$(CONFIG_MSM_IPC_ROUTER_SECURITY)+= msm_ipc_router_security.o
obj-$(CONFIG_MSM_QMI_INTERFACE) += msm_qmi_interface.o
+obj-$(CONFIG_MSM_TEST_QMI_CLIENT) += kernel_test_service_v01.o test_qmi_client.o
obj-$(CONFIG_DEBUG_FS) += smd_rpc_sym.o
obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter_servers.o
obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter_clients.o
@@ -208,14 +210,7 @@
endif
obj-$(CONFIG_MSM_SYSMON_COMM) += sysmon.o
-ifdef CONFIG_CPU_IDLE
- obj-$(CONFIG_ARCH_APQ8064) += cpuidle.o
- obj-$(CONFIG_ARCH_MSM8960) += cpuidle.o
- obj-$(CONFIG_ARCH_MSM8X60) += cpuidle.o
- obj-$(CONFIG_ARCH_MSM9615) += cpuidle.o
- obj-$(CONFIG_ARCH_MSM9625) += cpuidle.o
- obj-$(CONFIG_ARCH_MSM8974) += cpuidle.o
-endif
+obj-$(CONFIG_CPU_IDLE) += cpuidle.o
ifdef CONFIG_MSM_CAMERA_V4L2
obj-$(CONFIG_ARCH_MSM8X60) += board-msm8x60-camera.o
@@ -321,17 +316,9 @@
obj-$(CONFIG_HTC_HEADSET) += htc_headset.o
obj-$(CONFIG_MSM_RMT_STORAGE_CLIENT) += rmt_storage_client.o
obj-$(CONFIG_MSM_SDIO_SMEM) += sdio_smem.o
-obj-$(CONFIG_MSM_RPM) += rpm.o
-ifdef CONFIG_MSM_RPM
- obj-$(CONFIG_ARCH_APQ8064) += rpm_resources.o
- obj-$(CONFIG_ARCH_MSM8960) += rpm_resources.o
- obj-$(CONFIG_ARCH_MSM8X60) += rpm_resources.o
- obj-$(CONFIG_ARCH_MSM9615) += rpm_resources.o
-endif
-ifdef CONFIG_MSM_RPM_SMD
- obj-$(CONFIG_ARCH_MSM8974) += lpm_levels.o lpm_resources.o
- obj-$(CONFIG_ARCH_MSM9625) += lpm_levels.o lpm_resources.o
-endif
+obj-$(CONFIG_MSM_RPM) += rpm.o rpm_resources.o
+obj-$(CONFIG_MSM_LPM_TEST) += test-lpm.o
+obj-$(CONFIG_MSM_RPM_SMD) += rpm-smd.o lpm_levels.o lpm_resources.o
obj-$(CONFIG_MSM_MPM_OF) += mpm-of.o
obj-$(CONFIG_MSM_MPM) += mpm.o
obj-$(CONFIG_MSM_RPM_STATS_LOG) += rpm_stats.o rpm_master_stat.o
diff --git a/arch/arm/mach-msm/acpuclock-8064.c b/arch/arm/mach-msm/acpuclock-8064.c
index e8c7680..359a156 100644
--- a/arch/arm/mach-msm/acpuclock-8064.c
+++ b/arch/arm/mach-msm/acpuclock-8064.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011-2012, Code Aurora Forum. 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
@@ -239,6 +239,118 @@
{ 0, { 0 } }
};
+static struct acpu_level tbl_PVS0_1512MHz[] __initdata = {
+ { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 950000 },
+ { 1, { 486000, HFPLL, 2, 0x24 }, L2(5), 950000 },
+ { 1, { 594000, HFPLL, 1, 0x16 }, L2(5), 950000 },
+ { 1, { 702000, HFPLL, 1, 0x1A }, L2(5), 962500 },
+ { 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 1000000 },
+ { 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 1025000 },
+ { 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 1037500 },
+ { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1075000 },
+ { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 1087500 },
+ { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1125000 },
+ { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 1150000 },
+ { 1, { 1512000, HFPLL, 1, 0x38 }, L2(15), 1162500 },
+ { 0, { 0 } }
+};
+
+static struct acpu_level tbl_PVS1_1512MHz[] __initdata = {
+ { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 950000 },
+ { 1, { 486000, HFPLL, 2, 0x24 }, L2(5), 950000 },
+ { 1, { 594000, HFPLL, 1, 0x16 }, L2(5), 950000 },
+ { 1, { 702000, HFPLL, 1, 0x1A }, L2(5), 962500 },
+ { 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 975000 },
+ { 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 1000000 },
+ { 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 1012500 },
+ { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1037500 },
+ { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 1050000 },
+ { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1087500 },
+ { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 1112500 },
+ { 1, { 1512000, HFPLL, 1, 0x38 }, L2(15), 1125000 },
+ { 0, { 0 } }
+};
+
+static struct acpu_level tbl_PVS2_1512MHz[] __initdata = {
+ { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 925000 },
+ { 1, { 486000, HFPLL, 2, 0x24 }, L2(5), 925000 },
+ { 1, { 594000, HFPLL, 1, 0x16 }, L2(5), 925000 },
+ { 1, { 702000, HFPLL, 1, 0x1A }, L2(5), 925000 },
+ { 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 937500 },
+ { 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 950000 },
+ { 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 975000 },
+ { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1000000 },
+ { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 1012500 },
+ { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1037500 },
+ { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 1075000 },
+ { 1, { 1512000, HFPLL, 1, 0x38 }, L2(15), 1087500 },
+ { 0, { 0 } }
+};
+
+static struct acpu_level tbl_PVS3_1512MHz[] __initdata = {
+ { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 900000 },
+ { 1, { 486000, HFPLL, 2, 0x24 }, L2(5), 900000 },
+ { 1, { 594000, HFPLL, 1, 0x16 }, L2(5), 900000 },
+ { 1, { 702000, HFPLL, 1, 0x1A }, L2(5), 900000 },
+ { 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 900000 },
+ { 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 925000 },
+ { 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 950000 },
+ { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 975000 },
+ { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 987500 },
+ { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1000000 },
+ { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 1037500 },
+ { 1, { 1512000, HFPLL, 1, 0x38 }, L2(15), 1050000 },
+ { 0, { 0 } }
+};
+
+static struct acpu_level tbl_PVS4_1512MHz[] __initdata = {
+ { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 875000 },
+ { 1, { 486000, HFPLL, 2, 0x24 }, L2(5), 875000 },
+ { 1, { 594000, HFPLL, 1, 0x16 }, L2(5), 875000 },
+ { 1, { 702000, HFPLL, 1, 0x1A }, L2(5), 875000 },
+ { 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 887500 },
+ { 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 900000 },
+ { 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 925000 },
+ { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 950000 },
+ { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 962500 },
+ { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 975000 },
+ { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 1000000 },
+ { 1, { 1512000, HFPLL, 1, 0x38 }, L2(15), 1012500 },
+ { 0, { 0 } }
+};
+
+static struct acpu_level tbl_PVS5_1512MHz[] __initdata = {
+ { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 875000 },
+ { 1, { 486000, HFPLL, 2, 0x24 }, L2(5), 875000 },
+ { 1, { 594000, HFPLL, 1, 0x16 }, L2(5), 875000 },
+ { 1, { 702000, HFPLL, 1, 0x1A }, L2(5), 875000 },
+ { 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 887500 },
+ { 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 900000 },
+ { 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 925000 },
+ { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 937500 },
+ { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 950000 },
+ { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 962500 },
+ { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 987500 },
+ { 1, { 1512000, HFPLL, 1, 0x38 }, L2(15), 1000000 },
+ { 0, { 0 } }
+};
+
+static struct acpu_level tbl_PVS6_1512MHz[] __initdata = {
+ { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 875000 },
+ { 1, { 486000, HFPLL, 2, 0x24 }, L2(5), 875000 },
+ { 1, { 594000, HFPLL, 1, 0x16 }, L2(5), 875000 },
+ { 1, { 702000, HFPLL, 1, 0x1A }, L2(5), 875000 },
+ { 1, { 810000, HFPLL, 1, 0x1E }, L2(5), 887500 },
+ { 1, { 918000, HFPLL, 1, 0x22 }, L2(5), 900000 },
+ { 1, { 1026000, HFPLL, 1, 0x26 }, L2(5), 925000 },
+ { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 937500 },
+ { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 950000 },
+ { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 962500 },
+ { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 975000 },
+ { 1, { 1512000, HFPLL, 1, 0x38 }, L2(15), 987500 },
+ { 0, { 0 } }
+};
+
static struct acpu_level tbl_PVS0_1700MHz[] __initdata = {
{ 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 950000 },
{ 1, { 486000, HFPLL, 2, 0x24 }, L2(5), 950000 },
@@ -519,6 +631,14 @@
[2][4] = { tbl_PVS4_2000MHz, sizeof(tbl_PVS4_2000MHz), 25000 },
[2][5] = { tbl_PVS5_2000MHz, sizeof(tbl_PVS5_2000MHz), 25000 },
[2][6] = { tbl_PVS6_2000MHz, sizeof(tbl_PVS6_2000MHz), 25000 },
+
+ [14][0] = { tbl_PVS0_1512MHz, sizeof(tbl_PVS0_1512MHz), 0 },
+ [14][1] = { tbl_PVS1_1512MHz, sizeof(tbl_PVS1_1512MHz), 25000 },
+ [14][2] = { tbl_PVS2_1512MHz, sizeof(tbl_PVS2_1512MHz), 25000 },
+ [14][3] = { tbl_PVS3_1512MHz, sizeof(tbl_PVS3_1512MHz), 25000 },
+ [14][4] = { tbl_PVS4_1512MHz, sizeof(tbl_PVS4_1512MHz), 25000 },
+ [14][5] = { tbl_PVS5_1512MHz, sizeof(tbl_PVS5_1512MHz), 25000 },
+ [14][6] = { tbl_PVS6_1512MHz, sizeof(tbl_PVS6_1512MHz), 25000 },
};
static struct acpuclk_krait_params acpuclk_8064_params __initdata = {
diff --git a/arch/arm/mach-msm/board-8064-gpiomux.c b/arch/arm/mach-msm/board-8064-gpiomux.c
index 9e34f47..67760ee 100644
--- a/arch/arm/mach-msm/board-8064-gpiomux.c
+++ b/arch/arm/mach-msm/board-8064-gpiomux.c
@@ -917,38 +917,38 @@
static struct gpiomux_setting ap2mdm_cfg = {
.func = GPIOMUX_FUNC_GPIO,
- .drv = GPIOMUX_DRV_8MA,
+ .drv = GPIOMUX_DRV_4MA,
.pull = GPIOMUX_PULL_DOWN,
};
static struct gpiomux_setting mdm2ap_status_cfg = {
.func = GPIOMUX_FUNC_GPIO,
- .drv = GPIOMUX_DRV_8MA,
+ .drv = GPIOMUX_DRV_2MA,
.pull = GPIOMUX_PULL_DOWN,
};
static struct gpiomux_setting mdm2ap_errfatal_cfg = {
.func = GPIOMUX_FUNC_GPIO,
- .drv = GPIOMUX_DRV_16MA,
+ .drv = GPIOMUX_DRV_2MA,
.pull = GPIOMUX_PULL_DOWN,
};
static struct gpiomux_setting mdm2ap_pblrdy = {
.func = GPIOMUX_FUNC_GPIO,
- .drv = GPIOMUX_DRV_16MA,
+ .drv = GPIOMUX_DRV_2MA,
.pull = GPIOMUX_PULL_DOWN,
};
static struct gpiomux_setting ap2mdm_soft_reset_cfg = {
.func = GPIOMUX_FUNC_GPIO,
- .drv = GPIOMUX_DRV_8MA,
+ .drv = GPIOMUX_DRV_4MA,
.pull = GPIOMUX_PULL_DOWN,
};
static struct gpiomux_setting ap2mdm_wakeup = {
.func = GPIOMUX_FUNC_GPIO,
- .drv = GPIOMUX_DRV_8MA,
+ .drv = GPIOMUX_DRV_4MA,
.pull = GPIOMUX_PULL_DOWN,
};
diff --git a/arch/arm/mach-msm/board-8064-regulator.c b/arch/arm/mach-msm/board-8064-regulator.c
index a6f0e32..16b53fb 100644
--- a/arch/arm/mach-msm/board-8064-regulator.c
+++ b/arch/arm/mach-msm/board-8064-regulator.c
@@ -1,5 +1,5 @@
/*
- * 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
@@ -190,6 +190,7 @@
REGULATOR_SUPPLY("vddp", "0-0048"),
REGULATOR_SUPPLY("hdmi_lvl_tsl", "hdmi_msm.0"),
REGULATOR_SUPPLY("vdd-io", "spi0.2"),
+ REGULATOR_SUPPLY("sata_pmp_pwr", "msm_sata.0"),
};
VREG_CONSUMERS(S5) = {
REGULATOR_SUPPLY("8921_s5", NULL),
@@ -260,12 +261,15 @@
REGULATOR_SUPPLY("dsi1_vccs_3p3v", "mipi_dsi.1"),
REGULATOR_SUPPLY("hdmi_mux_vdd", "hdmi_msm.0"),
REGULATOR_SUPPLY("pcie_ext_3p3v", "msm_pcie"),
- REGULATOR_SUPPLY("sata_ext_3p3v", "ahci.0"),
};
VREG_CONSUMERS(EXT_TS_SW) = {
REGULATOR_SUPPLY("ext_ts_sw", NULL),
REGULATOR_SUPPLY("vdd_ana", "3-005b"),
};
+VREG_CONSUMERS(EXT_SATA_PWR) = {
+ REGULATOR_SUPPLY("ext_sata_pwr", NULL),
+ REGULATOR_SUPPLY("sata_ext_3p3v", "msm_sata.0"),
+};
VREG_CONSUMERS(AVC_1P2V) = {
REGULATOR_SUPPLY("avc_1p2v", NULL),
};
@@ -436,7 +440,8 @@
.pin_ctrl = _pin_ctrl, \
}
-#define GPIO_VREG(_id, _reg_name, _gpio_label, _gpio, _supply_regulator) \
+#define GPIO_VREG(_id, _reg_name, _gpio_label, _gpio, _supply_regulator, \
+ _active_low) \
[GPIO_VREG_ID_##_id] = { \
.init_data = { \
.constraints = { \
@@ -450,6 +455,7 @@
.regulator_name = _reg_name, \
.gpio_label = _gpio_label, \
.gpio = _gpio, \
+ .active_low = _active_low, \
}
#define SAW_VREG_INIT(_id, _name, _min_uV, _max_uV) \
@@ -565,25 +571,30 @@
/* GPIO regulator constraints */
struct gpio_regulator_platform_data
apq8064_gpio_regulator_pdata[] __devinitdata = {
- /* ID vreg_name gpio_label gpio supply */
- GPIO_VREG(EXT_5V, "ext_5v", "ext_5v_en", PM8921_MPP_PM_TO_SYS(7), NULL),
+ /* ID vreg_name gpio_label gpio supply active_low */
+ GPIO_VREG(EXT_5V, "ext_5v", "ext_5v_en",
+ PM8921_MPP_PM_TO_SYS(7), NULL, 0),
GPIO_VREG(EXT_3P3V, "ext_3p3v", "ext_3p3v_en",
- APQ8064_EXT_3P3V_REG_EN_GPIO, NULL),
+ APQ8064_EXT_3P3V_REG_EN_GPIO, NULL, 0),
GPIO_VREG(EXT_TS_SW, "ext_ts_sw", "ext_ts_sw_en",
- PM8921_GPIO_PM_TO_SYS(23), "ext_3p3v"),
+ PM8921_GPIO_PM_TO_SYS(23), "ext_3p3v", 0),
GPIO_VREG(EXT_MPP8, "ext_mpp8", "ext_mpp8_en",
- PM8921_MPP_PM_TO_SYS(8), NULL),
+ PM8921_MPP_PM_TO_SYS(8), NULL, 0),
+ GPIO_VREG(EXT_SATA_PWR, "ext_sata_pwr", "ext_sata_pwr_en",
+ PM8921_MPP_PM_TO_SYS(4), "ext_3p3v", 1),
};
struct gpio_regulator_platform_data
mpq8064_gpio_regulator_pdata[] __devinitdata = {
- GPIO_VREG(AVC_1P2V, "avc_1p2v", "avc_1p2v_en", SX150X_GPIO(4, 2), NULL),
- GPIO_VREG(AVC_1P8V, "avc_1p8v", "avc_1p8v_en", SX150X_GPIO(4, 4), NULL),
+ GPIO_VREG(AVC_1P2V, "avc_1p2v", "avc_1p2v_en",
+ SX150X_GPIO(4, 2), NULL, 0),
+ GPIO_VREG(AVC_1P8V, "avc_1p8v", "avc_1p8v_en",
+ SX150X_GPIO(4, 4), NULL, 0),
GPIO_VREG(AVC_2P2V, "avc_2p2v", "avc_2p2v_en",
- SX150X_GPIO(4, 14), NULL),
- GPIO_VREG(AVC_5V, "avc_5v", "avc_5v_en", SX150X_GPIO(4, 3), NULL),
+ SX150X_GPIO(4, 14), NULL, 0),
+ GPIO_VREG(AVC_5V, "avc_5v", "avc_5v_en", SX150X_GPIO(4, 3), NULL, 0),
GPIO_VREG(AVC_3P3V, "avc_3p3v", "avc_3p3v_en",
- SX150X_GPIO(4, 15), "avc_5v"),
+ SX150X_GPIO(4, 15), "avc_5v", 0),
};
/* SAW regulator constraints */
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index 90315b5..3fe0838 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.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
@@ -10,6 +10,7 @@
* GNU General Public License for more details.
*
*/
+#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/bitops.h>
#include <linux/platform_device.h>
@@ -2072,7 +2073,8 @@
{
msm_shared_ram_phys = MSM_SHARED_RAM_PHYS;
msm_map_apq8064_io();
- if (socinfo_init() < 0)
+
+ if (IS_ERR_OR_NULL(socinfo_init()))
pr_err("socinfo_init() failed!\n");
}
@@ -2528,6 +2530,16 @@
},
};
+static struct platform_device
+apq8064_device_ext_3p3v_mpp4_vreg __devinitdata = {
+ .name = GPIO_REGULATOR_DEV_NAME,
+ .id = PM8921_MPP_PM_TO_SYS(4),
+ .dev = {
+ .platform_data =
+ &apq8064_gpio_regulator_pdata[GPIO_VREG_ID_EXT_SATA_PWR],
+ },
+};
+
static struct platform_device apq8064_device_rpm_regulator __devinitdata = {
.name = "rpm-regulator",
.id = 0,
@@ -3568,7 +3580,7 @@
platform_device_register(&msm_gpio_device);
msm_tsens_early_init(&apq_tsens_pdata);
msm_thermal_init(&msm_thermal_pdata);
- if (socinfo_init() < 0)
+ if (IS_ERR_OR_NULL(socinfo_init()))
pr_err("socinfo_init() failed!\n");
BUG_ON(msm_rpm_init(&apq8064_rpm_data));
BUG_ON(msm_rpmrs_levels_init(&msm_rpmrs_data));
@@ -3759,6 +3771,23 @@
if (machine_is_mpq8064_cdp() || machine_is_mpq8064_hrd() ||
machine_is_mpq8064_dtv())
platform_device_register(&msm_dev_avtimer_device);
+
+ if (machine_is_apq8064_cdp() || machine_is_mpq8064_hrd()) {
+ int ret;
+ struct pm8xxx_mpp_config_data sata_pwr_cfg = {
+ .type = PM8XXX_MPP_TYPE_D_OUTPUT,
+ .level = PM8921_MPP_DIG_LEVEL_VPH,
+ .control = PM8XXX_MPP_DOUT_CTRL_HIGH,
+ };
+
+ /* Apply MPP-4 init only when it is used to control SATA PWR */
+ ret = pm8xxx_mpp_config(PM8921_MPP_PM_TO_SYS(4), &sata_pwr_cfg);
+ if (ret)
+ pr_err("%s: pm8921 MPP %d init config failed(%d)\n",
+ __func__, PM8921_MPP_PM_TO_SYS(4), ret);
+ platform_device_register(&apq8064_device_ext_3p3v_mpp4_vreg);
+ platform_device_register(&apq8064_device_sata);
+ }
}
MACHINE_START(APQ8064_CDP, "QCT APQ8064 CDP")
diff --git a/arch/arm/mach-msm/board-8064.h b/arch/arm/mach-msm/board-8064.h
index 2bc0981..4cdf939 100644
--- a/arch/arm/mach-msm/board-8064.h
+++ b/arch/arm/mach-msm/board-8064.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
@@ -16,7 +16,6 @@
#include <linux/regulator/msm-gpio-regulator.h>
#include <linux/mfd/pm8xxx/pm8921.h>
#include <linux/mfd/pm8xxx/pm8821.h>
-#include <linux/ahci_platform.h>
#include <mach/msm_memtypes.h>
#include <mach/irqs.h>
#include <mach/rpm-regulator.h>
@@ -50,6 +49,7 @@
#define GPIO_VREG_ID_EXT_3P3V 1
#define GPIO_VREG_ID_EXT_TS_SW 2
#define GPIO_VREG_ID_EXT_MPP8 3
+#define GPIO_VREG_ID_EXT_SATA_PWR 4
#define GPIO_VREG_ID_AVC_1P2V 0
#define GPIO_VREG_ID_AVC_1P8V 1
@@ -81,7 +81,6 @@
struct mmc_platform_data *plat);
void apq8064_init_mmc(void);
-int __init apq8064_add_ahci(struct ahci_platform_data *platd);
void apq8064_init_gpiomux(void);
void apq8064_init_pmic(void);
diff --git a/arch/arm/mach-msm/board-8092.c b/arch/arm/mach-msm/board-8092.c
index cbd257f..c7d01bf 100644
--- a/arch/arm/mach-msm/board-8092.c
+++ b/arch/arm/mach-msm/board-8092.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. 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
@@ -10,6 +10,7 @@
* GNU General Public License for more details.
*/
+#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/of.h>
@@ -78,9 +79,6 @@
static void __init mpq8092_map_io(void)
{
msm_map_mpq8092_io();
- if (socinfo_init() < 0)
- pr_err("%s: socinfo_init() failed\n", __func__);
-
}
static struct of_dev_auxdata mpq8092_auxdata_lookup[] __initdata = {
@@ -98,6 +96,11 @@
static void __init mpq8092_init(void)
{
struct of_dev_auxdata *adata = mpq8092_auxdata_lookup;
+ struct device *parent;
+
+ parent = socinfo_init();
+ if (IS_ERR_OR_NULL(parent))
+ pr_err("%s: socinfo_init() failed\n", __func__);
mpq8092_init_gpiomux();
msm_clock_init(&mpq8092_clock_init_data);
diff --git a/arch/arm/mach-msm/board-8226-gpiomux.c b/arch/arm/mach-msm/board-8226-gpiomux.c
index 7a53b24..e58cee7 100644
--- a/arch/arm/mach-msm/board-8226-gpiomux.c
+++ b/arch/arm/mach-msm/board-8226-gpiomux.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
@@ -25,11 +25,6 @@
.drv = GPIOMUX_DRV_2MA,
.func = GPIOMUX_FUNC_GPIO,
};
-static struct gpiomux_setting gpio_spi_config = {
- .func = GPIOMUX_FUNC_1,
- .drv = GPIOMUX_DRV_8MA,
- .pull = GPIOMUX_PULL_NONE,
-};
static struct msm_gpiomux_config msm_eth_configs[] = {
{
@@ -39,6 +34,19 @@
}
},
};
+#endif
+
+static struct gpiomux_setting gpio_spi_config = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting gpio_i2c_config = {
+ .func = GPIOMUX_FUNC_3,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
static struct msm_gpiomux_config msm_blsp_configs[] __initdata = {
{
@@ -65,8 +73,19 @@
[GPIOMUX_SUSPENDED] = &gpio_spi_config,
},
},
+ {
+ .gpio = 14, /* BLSP-1 QUP-4 I2C_SDA */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_i2c_config,
+ },
+ },
+ {
+ .gpio = 15, /* BLSP-1 QUP-4 I2C_SCL */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_i2c_config,
+ },
+ },
};
-#endif
void __init msm8226_init_gpiomux(void)
{
@@ -77,8 +96,10 @@
pr_err("%s failed %d\n", __func__, rc);
return;
}
+
#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
msm_gpiomux_install(msm_eth_configs, ARRAY_SIZE(msm_eth_configs));
- msm_gpiomux_install(msm_blsp_configs, ARRAY_SIZE(msm_blsp_configs));
#endif
+
+ msm_gpiomux_install(msm_blsp_configs, ARRAY_SIZE(msm_blsp_configs));
}
diff --git a/arch/arm/mach-msm/board-8226.c b/arch/arm/mach-msm/board-8226.c
index 2f2eb2c..0f8bfd4 100644
--- a/arch/arm/mach-msm/board-8226.c
+++ b/arch/arm/mach-msm/board-8226.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
@@ -10,6 +10,7 @@
* GNU General Public License for more details.
*/
+#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/platform_device.h>
@@ -61,6 +62,8 @@
return MEMTYPE_EBI1;
}
static struct clk_lookup msm_clocks_dummy[] = {
+ CLK_DUMMY("core_clk", NULL, "f9926000.i2c", OFF),
+ CLK_DUMMY("iface_clk", NULL, "f9926000.i2c", OFF),
CLK_DUMMY("core_clk", BLSP1_UART_CLK, "f991f000.serial", OFF),
CLK_DUMMY("iface_clk", BLSP1_UART_CLK, "f991f000.serial", OFF),
CLK_DUMMY("iface_clk", HSUSB_IFACE_CLK, "f9a55000.usb", OFF),
@@ -75,6 +78,18 @@
CLK_DUMMY("bus_clk", NULL, "msm_sdcc.2", OFF),
CLK_DUMMY("core_clk", NULL, "f9928000.spi", OFF),
CLK_DUMMY("iface_clk", NULL, "f9928000.spi", OFF),
+ CLK_DUMMY("iface_clk", NULL, "fda64000.qcom,iommu", OFF),
+ CLK_DUMMY("core_clk", NULL, "fda64000.qcom,iommu", OFF),
+ CLK_DUMMY("iface_clk", NULL, "fda44000.qcom,iommu", OFF),
+ CLK_DUMMY("core_clk", NULL, "fda44000.qcom,iommu", OFF),
+ CLK_DUMMY("iface_clk", NULL, "fd928000.qcom,iommu", OFF),
+ CLK_DUMMY("core_clk", NULL, "fd928000.qcom,iommu", OFF),
+ CLK_DUMMY("core_clk", NULL, "fdb10000.qcom,iommu", OFF),
+ CLK_DUMMY("iface_clk", NULL, "fdb10000.qcom,iommu", OFF),
+ CLK_DUMMY("alt_core_clk", NULL, "fdb10000.qcom,iommu", OFF),
+ CLK_DUMMY("iface_clk", NULL, "fdc84000.qcom,iommu", OFF),
+ CLK_DUMMY("alt_core_clk", NULL, "fdc84000.qcom,iommu", OFF),
+ CLK_DUMMY("core_clk", NULL, "fdc84000.qcom,iommu", OFF),
};
static struct clock_init_data msm_dummy_clock_init_data __initdata = {
@@ -109,14 +124,15 @@
void __init msm8226_init(void)
{
struct of_dev_auxdata *adata = msm8226_auxdata_lookup;
+ struct device *parent;
+
+ parent = socinfo_init();
+ if (IS_ERR_OR_NULL(parent))
+ pr_err("%s: socinfo_init() failed\n", __func__);
msm8226_init_gpiomux();
msm_clock_init(&msm_dummy_clock_init_data);
-
- if (socinfo_init() < 0)
- pr_err("%s: socinfo_init() failed\n", __func__);
-
of_platform_populate(NULL, of_default_bus_match_table, adata, NULL);
}
diff --git a/arch/arm/mach-msm/board-8910.c b/arch/arm/mach-msm/board-8910.c
index 2ff4567..f779c1f 100644
--- a/arch/arm/mach-msm/board-8910.c
+++ b/arch/arm/mach-msm/board-8910.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
@@ -10,6 +10,7 @@
* GNU General Public License for more details.
*/
+#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/platform_device.h>
@@ -86,6 +87,11 @@
void __init msm8910_init(void)
{
struct of_dev_auxdata *adata = msm8910_auxdata_lookup;
+ struct device *parent;
+
+ parent = socinfo_init();
+ if (IS_ERR_OR_NULL(parent))
+ pr_err("%s: socinfo_init() failed\n", __func__);
msm8910_init_gpiomux();
@@ -93,10 +99,6 @@
msm_clock_init(&msm8910_rumi_clock_init_data);
else
msm_clock_init(&msm8910_clock_init_data);
-
- if (socinfo_init() < 0)
- pr_err("%s: socinfo_init() failed\n", __func__);
-
of_platform_populate(NULL, of_default_bus_match_table, adata, NULL);
}
diff --git a/arch/arm/mach-msm/board-8930-pmic.c b/arch/arm/mach-msm/board-8930-pmic.c
index a5fded4..c0402ef 100644
--- a/arch/arm/mach-msm/board-8930-pmic.c
+++ b/arch/arm/mach-msm/board-8930-pmic.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. 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
@@ -182,6 +182,8 @@
static struct pm8xxx_mpp_init pm8917_mpps[] __initdata = {
PM8917_MPP_INIT(PM8XXX_AMUX_MPP_3, A_INPUT,
PM8XXX_MPP_AIN_AMUX_CH8, DIN_TO_INT),
+ /* Configure MPP01 for USB ID detection */
+ PM8917_MPP_INIT(1, D_INPUT, PM8921_MPP_DIG_LEVEL_S4, DIN_TO_INT),
};
void __init msm8930_pm8038_gpio_mpp_init(void)
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index 3785fb2..194c77f 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.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
@@ -10,6 +10,7 @@
* GNU General Public License for more details.
*
*/
+#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/io.h>
@@ -1464,8 +1465,9 @@
msm_shared_ram_phys = MSM_SHARED_RAM_PHYS;
msm_map_msm8930_io();
- if (socinfo_init() < 0)
+ if (IS_ERR_OR_NULL(socinfo_init()))
pr_err("socinfo_init() failed!\n");
+
}
static void __init msm8930_init_irq(void)
@@ -1505,6 +1507,16 @@
#ifdef CONFIG_USB_MSM_OTG_72K
static struct msm_otg_platform_data msm_otg_pdata;
#else
+static int enable_usb_host_mode;
+static int __init usb_host_mode_with_pm8917(char *param)
+{
+ int ret;
+
+ ret = kstrtoint(param, 10, &enable_usb_host_mode);
+ return ret;
+}
+early_param("usb_host_mode_pm8917", usb_host_mode_with_pm8917);
+
#ifdef CONFIG_MSM_BUS_SCALING
/* Bandwidth requests (zero) if no vote placed */
static struct msm_bus_vectors usb_init_vectors[] = {
@@ -1558,7 +1570,6 @@
.mode = USB_OTG,
.otg_control = OTG_PMIC_CONTROL,
.phy_type = SNPS_28NM_INTEGRATED_PHY,
- .pmic_id_irq = PM8038_USB_ID_IN_IRQ(PM8038_IRQ_BASE),
.power_budget = 750,
#ifdef CONFIG_MSM_BUS_SCALING
.bus_scale_table = &usb_bus_scale_pdata,
@@ -2491,6 +2502,7 @@
&msm_pcm_hostless,
&msm_multi_ch_pcm,
&msm_lowlatency_pcm,
+ &msm_fm_loopback,
};
static void __init msm8930_i2c_init(void)
@@ -2870,6 +2882,27 @@
msm_clock_init(&msm8930_pm8917_clock_init_data);
else
msm_clock_init(&msm8930_clock_init_data);
+
+ if (socinfo_get_pmic_model() == PMIC_MODEL_PM8917) {
+ /*
+ * By default, set USB mode as USB Peripheral only due to
+ * hardware rework requirement for USB Host Mode.
+ * Provide pmic_id_irq number only if host mode is enable
+ * by user assuming that hardware rework is available.
+ */
+ if (enable_usb_host_mode) {
+ /* MPP01 IRQ number */
+ msm_otg_pdata.pmic_id_irq =
+ PM8921_MPP_IRQ(PM8917_IRQ_BASE, 1);
+ } else {
+ pr_err("Enabling USB Peripheral Only mode.\n");
+ msm_otg_pdata.mode = USB_PERIPHERAL;
+ }
+ } else {
+ msm_otg_pdata.pmic_id_irq =
+ PM8038_USB_ID_IN_IRQ(PM8038_IRQ_BASE);
+ }
+
msm_otg_pdata.phy_init_seq = hsusb_phy_init_seq;
if (msm8930_mhl_display_enabled()) {
mhl_platform_data.mhl_enabled = true;
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index f64bf18..f4e7880 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.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
@@ -10,6 +10,7 @@
* GNU General Public License for more details.
*
*/
+#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/io.h>
@@ -1486,9 +1487,9 @@
{
msm_shared_ram_phys = MSM_SHARED_RAM_PHYS;
msm_map_msm8960_io();
-
- if (socinfo_init() < 0)
+ if (IS_ERR_OR_NULL(socinfo_init()))
pr_err("socinfo_init() failed!\n");
+
}
static void __init msm8960_init_irq(void)
diff --git a/arch/arm/mach-msm/board-8974-gpiomux.c b/arch/arm/mach-msm/board-8974-gpiomux.c
index 6672f49..b1e107d 100644
--- a/arch/arm/mach-msm/board-8974-gpiomux.c
+++ b/arch/arm/mach-msm/board-8974-gpiomux.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012-2013, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -640,6 +640,51 @@
},
},
};
+
+static struct gpiomux_setting pri_auxpcm_act_cfg = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+
+static struct gpiomux_setting pri_auxpcm_sus_cfg = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct msm_gpiomux_config msm8974_pri_auxpcm_configs[] __initdata = {
+ {
+ .gpio = 65,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &pri_auxpcm_sus_cfg,
+ [GPIOMUX_ACTIVE] = &pri_auxpcm_act_cfg,
+ },
+ },
+ {
+ .gpio = 66,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &pri_auxpcm_sus_cfg,
+ [GPIOMUX_ACTIVE] = &pri_auxpcm_act_cfg,
+ },
+ },
+ {
+ .gpio = 67,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &pri_auxpcm_sus_cfg,
+ [GPIOMUX_ACTIVE] = &pri_auxpcm_act_cfg,
+ },
+ },
+ {
+ .gpio = 68,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &pri_auxpcm_sus_cfg,
+ [GPIOMUX_ACTIVE] = &pri_auxpcm_act_cfg,
+ },
+ },
+};
+
static struct msm_gpiomux_config wcnss_5wire_interface[] = {
{
.gpio = 36,
@@ -902,6 +947,9 @@
msm_gpiomux_install(msm_hdmi_configs, ARRAY_SIZE(msm_hdmi_configs));
msm_gpiomux_install(msm_mhl_configs, ARRAY_SIZE(msm_mhl_configs));
+ msm_gpiomux_install(msm8974_pri_auxpcm_configs,
+ ARRAY_SIZE(msm8974_pri_auxpcm_configs));
+
if (machine_is_msm8974_rumi())
msm_gpiomux_install(msm_rumi_blsp_configs,
ARRAY_SIZE(msm_rumi_blsp_configs));
diff --git a/arch/arm/mach-msm/board-8974.c b/arch/arm/mach-msm/board-8974.c
index 2f6d3d0..b90d75b 100644
--- a/arch/arm/mach-msm/board-8974.c
+++ b/arch/arm/mach-msm/board-8974.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. 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
@@ -10,6 +10,7 @@
* GNU General Public License for more details.
*/
+#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/io.h>
@@ -358,18 +359,20 @@
static void __init msm8974_map_io(void)
{
msm_map_8974_io();
- if (socinfo_init() < 0)
- pr_err("%s: socinfo_init() failed\n", __func__);
}
void __init msm8974_init(void)
{
struct of_dev_auxdata *adata = msm8974_auxdata_lookup;
+ struct device *parent;
+
+ parent = socinfo_init();
+ if (IS_ERR_OR_NULL(parent))
+ pr_err("%s: socinfo_init() failed\n", __func__);
msm_8974_init_gpiomux();
regulator_has_full_constraints();
of_platform_populate(NULL, of_default_bus_match_table, adata, NULL);
-
msm8974_add_drivers();
}
diff --git a/arch/arm/mach-msm/board-9625-gpiomux.c b/arch/arm/mach-msm/board-9625-gpiomux.c
index 2f75470..b39dc27 100644
--- a/arch/arm/mach-msm/board-9625-gpiomux.c
+++ b/arch/arm/mach-msm/board-9625-gpiomux.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012-2013, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -142,34 +142,6 @@
},
},
{
- .gpio = 16, /* Sec mi2s ws */
- .settings = {
- [GPIOMUX_SUSPENDED] = &mi2s_suspend_cfg,
- [GPIOMUX_ACTIVE] = &mi2s_active_cfg,
- },
- },
- {
- .gpio = 17, /* Sec mi2s din */
- .settings = {
- [GPIOMUX_SUSPENDED] = &mi2s_suspend_cfg,
- [GPIOMUX_ACTIVE] = &mi2s_active_cfg,
- },
- },
- {
- .gpio = 18, /* Sec mi2s dout */
- .settings = {
- [GPIOMUX_SUSPENDED] = &mi2s_suspend_cfg,
- [GPIOMUX_ACTIVE] = &mi2s_active_cfg,
- },
- },
- {
- .gpio = 19, /* Sec mi2s clk */
- .settings = {
- [GPIOMUX_SUSPENDED] = &mi2s_suspend_cfg,
- [GPIOMUX_ACTIVE] = &mi2s_active_cfg,
- },
- },
- {
.gpio = 71, /* mi2s mclk */
.settings = {
[GPIOMUX_SUSPENDED] = &mi2s_suspend_cfg,
diff --git a/arch/arm/mach-msm/board-9625.c b/arch/arm/mach-msm/board-9625.c
index f6a354f..07c37dd 100644
--- a/arch/arm/mach-msm/board-9625.c
+++ b/arch/arm/mach-msm/board-9625.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. 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
@@ -10,6 +10,7 @@
* GNU General Public License for more details.
*/
+#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/io.h>
@@ -236,7 +237,10 @@
void __init msm9625_init(void)
{
- if (socinfo_init() < 0)
+ struct device *parent;
+
+ parent = socinfo_init();
+ if (IS_ERR_OR_NULL(parent))
pr_err("%s: socinfo_init() failed\n", __func__);
msm9625_init_gpiomux();
diff --git a/arch/arm/mach-msm/board-fsm9xxx.c b/arch/arm/mach-msm/board-fsm9xxx.c
index 274b338..16740b2 100644
--- a/arch/arm/mach-msm/board-fsm9xxx.c
+++ b/arch/arm/mach-msm/board-fsm9xxx.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
@@ -1002,10 +1002,8 @@
{
msm_shared_ram_phys = 0x00100000;
msm_map_fsm9xxx_io();
- if (socinfo_init() < 0)
- pr_err("%s: socinfo_init() failed!\n",
- __func__);
-
+ if (IS_ERR_OR_NULL(socinfo_init()))
+ pr_err("socinfo_init() failed!\n");
}
MACHINE_START(FSM9XXX_SURF, "QCT FSM9XXX")
diff --git a/arch/arm/mach-msm/board-msm7627a-bt.c b/arch/arm/mach-msm/board-msm7627a-bt.c
index 1c2d8a2..3e90a15 100644
--- a/arch/arm/mach-msm/board-msm7627a-bt.c
+++ b/arch/arm/mach-msm/board-msm7627a-bt.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. 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
@@ -485,7 +485,7 @@
const struct bahama_config_register *p;
- u8 version;
+ int version;
const struct bahama_config_register v10_bt_on[] = {
{ 0xE9, 0x00, 0xFF },
@@ -567,7 +567,7 @@
u8 offset = 0; /* index into bahama configs */
on = on ? 1 : 0;
version = marimba_read_bahama_ver(&config);
- if ((int)version < 0 || version == BAHAMA_VER_UNSUPPORTED) {
+ if (version < 0 || version == BAHAMA_VER_UNSUPPORTED) {
dev_err(&msm_bt_power_device.dev, "%s : Bahama "
"version read Error, version = %d\n",
__func__, version);
@@ -602,10 +602,10 @@
__func__, (p+i)->reg,
value, (p+i)->mask);
value = 0;
- rc = marimba_read_bit_mask(&config,
+ /* Ignoring the read failure as it is only for check */
+ if (marimba_read_bit_mask(&config,
(p+i)->reg, &value,
- sizeof((p+i)->value), (p+i)->mask);
- if (rc < 0)
+ sizeof((p+i)->value), (p+i)->mask) < 0)
dev_err(&msm_bt_power_device.dev,
"%s marimba_read_bit_mask- error",
__func__);
@@ -678,7 +678,6 @@
dev_err(&msm_bt_power_device.dev,
"%s: could not %sable regulator %s: %d\n",
__func__, "dis", bt_vregs[i].name, rc);
- goto reg_disable;
}
}
@@ -687,8 +686,8 @@
if (on)
regulator_disable(bt_vregs[i].reg);
reg_disable:
- while (i) {
- if (on) {
+ if (on) {
+ while (i) {
i--;
regulator_disable(bt_vregs[i].reg);
regulator_put(bt_vregs[i].reg);
@@ -835,7 +834,10 @@
int pin, rc = 0;
const char *id = "BTPW";
int cid = 0;
+ int bt_state = 0;
+ struct marimba config = { .mod_id = SLAVE_ID_BAHAMA};
+ pr_debug("%s: on = %d\n", __func__, on);
cid = adie_get_detected_connectivity_type();
if (cid != BAHAMA_ID) {
pr_err("%s: unexpected adie connectivity type: %d\n",
@@ -854,7 +856,7 @@
if (rc < 0) {
pr_err("%s: bluetooth_switch_regulators rc = %d",
__func__, rc);
- goto exit;
+ goto fail_gpio;
}
/*setup BT GPIO lines*/
for (pin = 0; pin < ARRAY_SIZE(bt_config_power_on);
@@ -874,7 +876,7 @@
PMAPP_CLOCK_VOTE_ON);
if (rc < 0) {
pr_err("Failed to vote for TCXO_D1 ON\n");
- goto fail_clock;
+ goto fail_gpio_cfg;
}
msleep(20);
@@ -882,7 +884,7 @@
rc = bahama_bt(1);
if (rc < 0) {
pr_err("%s: bahama_bt rc = %d", __func__, rc);
- goto fail_i2c;
+ goto fail_clock;
}
msleep(20);
@@ -891,7 +893,7 @@
if (rc < 0) {
pr_err("%s: msm_bahama_setup_pcm_i2s , rc =%d\n",
__func__, rc);
- goto fail_power;
+ goto fail_i2c;
}
rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_D1,
PMAPP_CLOCK_VOTE_PIN_CTRL);
@@ -900,26 +902,28 @@
__func__, rc);
} else {
- rc = bahama_bt(0);
- if (rc < 0)
- pr_err("%s: bahama_bt rc = %d", __func__, rc);
+ bt_state = marimba_get_bt_status(&config);
+ if (!bt_state) {
+ pr_err("%s: BT is already turned OFF.\n", __func__);
+ return 0;
+ }
rc = msm_bahama_setup_pcm_i2s(BT_PCM_OFF);
if (rc < 0) {
pr_err("%s: msm_bahama_setup_pcm_i2s, rc =%d\n",
__func__, rc);
}
- rc = bt_set_gpio(on);
- if (rc) {
- pr_err("%s: bt_set_gpio = %d\n",
- __func__, rc);
- }
fail_i2c:
+ rc = bahama_bt(0);
+ if (rc < 0)
+ pr_err("%s: bahama_bt rc = %d", __func__, rc);
+
+fail_clock:
rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_D1,
PMAPP_CLOCK_VOTE_OFF);
if (rc < 0)
pr_err("%s: Failed to vote Off D1\n", __func__);
-fail_clock:
+fail_gpio_cfg:
for (pin = 0; pin < ARRAY_SIZE(bt_config_power_off);
pin++) {
rc = gpio_tlmm_config(bt_config_power_off[pin],
@@ -936,6 +940,12 @@
if (rc < 0) {
pr_err("%s: switch_regulators : rc = %d",\
__func__, rc);
+ }
+fail_gpio:
+ rc = bt_set_gpio(0);
+ if (rc) {
+ pr_err("%s: bt_set_gpio = %d\n",
+ __func__, rc);
goto exit;
}
}
diff --git a/arch/arm/mach-msm/board-msm7x30.c b/arch/arm/mach-msm/board-msm7x30.c
index 9822aa9..752c99a 100644
--- a/arch/arm/mach-msm/board-msm7x30.c
+++ b/arch/arm/mach-msm/board-msm7x30.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2012, Code Aurora Forum. 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
@@ -11,6 +11,7 @@
*
*/
+#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/irq.h>
#include <linux/gpio.h>
@@ -7348,9 +7349,8 @@
{
msm_shared_ram_phys = 0x00100000;
msm_map_msm7x30_io();
- if (socinfo_init() < 0)
- printk(KERN_ERR "%s: socinfo_init() failed!\n",
- __func__);
+ if (IS_ERR_OR_NULL(socinfo_init()))
+ pr_err("socinfo_init() failed!\n");
}
static void __init msm7x30_init_early(void)
diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c
index d4205bd..e678dfb 100644
--- a/arch/arm/mach-msm/board-msm8x60.c
+++ b/arch/arm/mach-msm/board-msm8x60.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
@@ -11,6 +11,7 @@
*
*/
+#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
@@ -7540,9 +7541,9 @@
{
msm_shared_ram_phys = MSM_SHARED_RAM_PHYS;
msm_map_msm8x60_io();
-
- if (socinfo_init() < 0)
+ if (IS_ERR_OR_NULL(socinfo_init()))
pr_err("socinfo_init() failed!\n");
+
}
/*
diff --git a/arch/arm/mach-msm/board-qsd8x50.c b/arch/arm/mach-msm/board-qsd8x50.c
index 146c8a8..57c548e 100644
--- a/arch/arm/mach-msm/board-qsd8x50.c
+++ b/arch/arm/mach-msm/board-qsd8x50.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2008-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
@@ -2521,9 +2521,8 @@
msm_shared_ram_phys = MSM_SHARED_RAM_PHYS;
msm_map_qsd8x50_io();
qsd8x50_allocate_memory_regions();
- if (socinfo_init() < 0)
- printk(KERN_ERR "%s: socinfo_init() failed!\n",
- __func__);
+ if (IS_ERR_OR_NULL(socinfo_init()))
+ pr_err("socinfo_init() failed!\n");
}
MACHINE_START(QSD8X50_SURF, "QCT QSD8X50 SURF")
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index 7038b06..928b5aa 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2012, Code Aurora Forum. 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
@@ -114,6 +114,7 @@
#define SATA_RXOOB_CLK_CTL_REG REG(0x2C0C)
#define SATA_PMALIVE_CLK_CTL_REG REG(0x2C10)
#define SATA_PHY_REF_CLK_CTL_REG REG(0x2C14)
+#define SATA_RESET REG(0x2C1C)
#define SATA_ACLK_CTL_REG REG(0x2C20)
#define SATA_PHY_CFG_CLK_CTL_REG REG(0x2C40)
#define USB_FSn_HCLK_CTL_REG(n) REG(0x2960+(0x20*((n)-1)))
@@ -2085,6 +2086,8 @@
.en_mask = BIT(4),
.halt_reg = CLK_HALT_MSS_SMPSS_MISC_STATE_REG,
.halt_bit = 27,
+ .reset_reg = SATA_RESET,
+ .reset_mask = BIT(0),
},
.c = {
.dbg_name = "sata_p_clk",
@@ -5311,14 +5314,14 @@
CLK_LOOKUP("src_clk", usb_fs1_src_clk.c, ""),
CLK_LOOKUP("alt_core_clk", usb_fs1_xcvr_clk.c, ""),
CLK_LOOKUP("sys_clk", usb_fs1_sys_clk.c, ""),
- CLK_LOOKUP("ref_clk", sata_phy_ref_clk.c, ""),
- CLK_LOOKUP("cfg_clk", sata_phy_cfg_clk.c, ""),
- CLK_LOOKUP("src_clk", sata_src_clk.c, ""),
- CLK_LOOKUP("core_rxoob_clk", sata_rxoob_clk.c, ""),
- CLK_LOOKUP("core_pmalive_clk", sata_pmalive_clk.c, ""),
- CLK_LOOKUP("bus_clk", sata_a_clk.c, ""),
- CLK_LOOKUP("iface_clk", sata_p_clk.c, ""),
- CLK_LOOKUP("slave_iface_clk", sfab_sata_s_p_clk.c, ""),
+ CLK_LOOKUP("ref_clk", sata_phy_ref_clk.c, "msm_sata.0"),
+ CLK_LOOKUP("cfg_clk", sata_phy_cfg_clk.c, "msm_sata.0"),
+ CLK_LOOKUP("src_clk", sata_src_clk.c, "msm_sata.0"),
+ CLK_LOOKUP("core_rxoob_clk", sata_rxoob_clk.c, "msm_sata.0"),
+ CLK_LOOKUP("core_pmalive_clk", sata_pmalive_clk.c, "msm_sata.0"),
+ CLK_LOOKUP("bus_clk", sata_a_clk.c, "msm_sata.0"),
+ CLK_LOOKUP("iface_clk", sata_p_clk.c, "msm_sata.0"),
+ CLK_LOOKUP("slave_iface_clk", sfab_sata_s_p_clk.c, "msm_sata.0"),
CLK_LOOKUP("iface_clk", ce3_p_clk.c, "qce.0"),
CLK_LOOKUP("iface_clk", ce3_p_clk.c, "qcrypto.0"),
CLK_LOOKUP("core_clk", ce3_core_clk.c, "qce.0"),
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index 43a03a0..389ac62 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -662,9 +662,9 @@
#define D0_ID 1
#define D1_ID 2
-#define A0_ID 3
-#define A1_ID 4
-#define A2_ID 5
+#define A0_ID 4
+#define A1_ID 5
+#define A2_ID 6
#define DIFF_CLK_ID 7
#define DIV_CLK1_ID 11
#define DIV_CLK2_ID 12
@@ -934,6 +934,7 @@
F(56000000, gpll0, 1, 7, 75),
F(58982400, gpll0, 1, 1536, 15625),
F(60000000, gpll0, 10, 0, 0),
+ F(63160000, gpll0, 9.5, 0, 0),
F_END
};
@@ -2550,6 +2551,7 @@
F_MM(133330000, mmpll0, 6, 0, 0),
F_MM(160000000, mmpll0, 5, 0, 0),
F_MM(200000000, mmpll0, 4, 0, 0),
+ F_MM(240000000, gpll0, 2.5, 0, 0),
F_MM(266670000, mmpll0, 3, 0, 0),
F_MM(320000000, mmpll0, 2.5, 0, 0),
F_END
@@ -5139,6 +5141,7 @@
/* Multimedia clocks */
CLK_LOOKUP("bus_clk_src", axi_clk_src.c, ""),
CLK_LOOKUP("bus_clk", mmss_mmssnoc_axi_clk.c, ""),
+ CLK_LOOKUP("bus_clk", mmssnoc_ahb_clk.c, ""),
CLK_LOOKUP("core_clk", mdss_edpaux_clk.c, "fd923400.qcom,mdss_edp"),
CLK_LOOKUP("pixel_clk", mdss_edppixel_clk.c, "fd923400.qcom,mdss_edp"),
CLK_LOOKUP("link_clk", mdss_edplink_clk.c, "fd923400.qcom,mdss_edp"),
@@ -5373,6 +5376,14 @@
"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"),
diff --git a/arch/arm/mach-msm/clock-9625.c b/arch/arm/mach-msm/clock-9625.c
index 151f192..c4cbdfd 100644
--- a/arch/arm/mach-msm/clock-9625.c
+++ b/arch/arm/mach-msm/clock-9625.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
@@ -2097,10 +2097,10 @@
CLK_LOOKUP("iface_clk", gcc_usb_hs_ahb_clk.c, "f9a55000.usb"),
CLK_LOOKUP("core_clk", gcc_usb_hs_system_clk.c, "f9a55000.usb"),
- CLK_LOOKUP("iface_clk", gcc_usb_hsic_ahb_clk.c, "f9a15000.hsic"),
- CLK_LOOKUP("phy_clk", gcc_usb_hsic_clk.c, "f9a15000.hsic"),
- CLK_LOOKUP("cal_clk", gcc_usb_hsic_io_cal_clk.c, "f9a15000.hsic"),
- CLK_LOOKUP("core_clk", gcc_usb_hsic_system_clk.c, "f9a15000.hsic"),
+ CLK_LOOKUP("iface_clk", gcc_usb_hsic_ahb_clk.c, "msm_hsic_host"),
+ CLK_LOOKUP("phy_clk", gcc_usb_hsic_clk.c, "msm_hsic_host"),
+ CLK_LOOKUP("cal_clk", gcc_usb_hsic_io_cal_clk.c, "msm_hsic_host"),
+ CLK_LOOKUP("core_clk", gcc_usb_hsic_system_clk.c, "msm_hsic_host"),
CLK_LOOKUP("alt_core_clk", gcc_usb_hsic_xcvr_fs_clk.c, ""),
CLK_LOOKUP("core_clk", gcc_ce1_clk.c, "fd400000.qcom,qcedev"),
@@ -2175,6 +2175,7 @@
CLK_LOOKUP("core_clk", qdss_clk.c, "fc31a000.funnel"),
CLK_LOOKUP("core_clk", qdss_clk.c, "fc321000.stm"),
CLK_LOOKUP("core_clk", qdss_clk.c, "fc332000.etm"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc332000.jtagmm"),
CLK_LOOKUP("core_a_clk", qdss_clk.c, "fc322000.tmc"),
CLK_LOOKUP("core_a_clk", qdss_clk.c, "fc318000.tpiu"),
@@ -2185,6 +2186,7 @@
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"),
};
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index dcd90d0..67485dc 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.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
@@ -20,7 +20,6 @@
#include <linux/dma-mapping.h>
#include <linux/coresight.h>
#include <linux/avtimer.h>
-#include <linux/ahci_platform.h>
#include <mach/irqs-8064.h>
#include <mach/board.h>
#include <mach/msm_iomap.h>
@@ -1779,9 +1778,11 @@
}
#define MSM_SATA_AHCI_BASE 0x29000000
-#define MSM_SATA_AHCI_REGS_SZ 0x17C
+#define MSM_SATA_AHCI_REGS_SZ 0x180
+#define MSM_SATA_PHY_BASE 0x1B400000
+#define MSM_SATA_PHY_REGS_SZ 0x200
-static struct resource resources_ahci[] = {
+static struct resource resources_sata[] = {
{
.name = "ahci_mem",
.flags = IORESOURCE_MEM,
@@ -1794,31 +1795,25 @@
.start = SATA_CONTROLLER_IRQ,
.end = SATA_CONTROLLER_IRQ,
},
-};
-
-static u64 ahci_dma_mask = DMA_BIT_MASK(32);
-static struct platform_device apq8064_device_ahci = {
- .name = "ahci",
- .id = 0,
- .num_resources = ARRAY_SIZE(resources_ahci),
- .resource = resources_ahci,
- .dev = {
- .dma_mask = &ahci_dma_mask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
+ {
+ .name = "phy_mem",
+ .flags = IORESOURCE_MEM,
+ .start = MSM_SATA_PHY_BASE,
+ .end = MSM_SATA_PHY_BASE + MSM_SATA_PHY_REGS_SZ - 1,
},
};
-int __init apq8064_add_ahci(struct ahci_platform_data *platd)
-{
- struct platform_device *pdev;
-
- if (!platd)
- return -EINVAL;
-
- pdev = &apq8064_device_ahci;
- pdev->dev.platform_data = platd;
- return platform_device_register(pdev);
-}
+static u64 sata_dma_mask = DMA_BIT_MASK(32);
+struct platform_device apq8064_device_sata = {
+ .name = "msm_sata",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(resources_sata),
+ .resource = resources_sata,
+ .dev = {
+ .dma_mask = &sata_dma_mask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+};
static struct resource resources_sps[] = {
{
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index 446f3f2..8762aa1 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.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
@@ -2459,6 +2459,11 @@
.id = -1,
};
+struct platform_device msm_fm_loopback = {
+ .name = "msm-pcm-loopback",
+ .id = -1,
+};
+
static struct fs_driver_data gfx2d0_fs_data = {
.clks = (struct fs_clk_data[]){
{ .name = "core_clk" },
diff --git a/arch/arm/mach-msm/devices-9615.c b/arch/arm/mach-msm/devices-9615.c
index cec57fd..15994565 100644
--- a/arch/arm/mach-msm/devices-9615.c
+++ b/arch/arm/mach-msm/devices-9615.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
@@ -11,6 +11,7 @@
*
*/
+#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/irq.h>
@@ -1545,7 +1546,7 @@
msm_shared_ram_phys = MSM_SHARED_RAM_PHYS;
msm_map_msm9615_io();
l2x0_cache_init();
- if (socinfo_init() < 0)
+ if (IS_ERR_OR_NULL(socinfo_init()))
pr_err("socinfo_init() failed!\n");
}
diff --git a/arch/arm/mach-msm/devices-msm7x27a.c b/arch/arm/mach-msm/devices-msm7x27a.c
index 3c60fa6..c8b160c 100644
--- a/arch/arm/mach-msm/devices-msm7x27a.c
+++ b/arch/arm/mach-msm/devices-msm7x27a.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. 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
@@ -2147,8 +2147,8 @@
void __init msm_common_io_init(void)
{
msm_map_common_io();
- if (socinfo_init() < 0)
- pr_err("%s: socinfo_init() failed!\n", __func__);
+ if (IS_ERR_OR_NULL(socinfo_init()))
+ pr_err("socinfo_init() failed!\n");
msm7x27x_cache_init();
}
@@ -2163,8 +2163,8 @@
{
msm_map_msm8625_io();
- if (socinfo_init() < 0)
- pr_err("%s: socinfo_init() failed!\n", __func__);
+ if (IS_ERR_OR_NULL(socinfo_init()))
+ pr_err("socinfo_init() failed!\n");
msm7x27x_cache_init();
}
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index 2339706..3471a30 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
@@ -95,6 +95,7 @@
extern struct platform_device apq8064_device_ssbi_pmic1;
extern struct platform_device apq8064_device_ssbi_pmic2;
extern struct platform_device apq8064_device_cache_erp;
+extern struct platform_device apq8064_device_sata;
extern struct platform_device msm9615_device_uart_gsbi4;
extern struct platform_device msm9615_device_qup_i2c_gsbi5;
@@ -252,6 +253,7 @@
extern struct platform_device msm_i2s_cpudai4;
extern struct platform_device msm_i2s_cpudai5;
extern struct platform_device msm_cpudai_stub;
+extern struct platform_device msm_fm_loopback;
extern struct platform_device msm_pil_q6v3;
extern struct platform_device msm_pil_modem;
diff --git a/arch/arm/mach-msm/idle-v7.S b/arch/arm/mach-msm/idle-v7.S
index 9a22996..6840f1c 100644
--- a/arch/arm/mach-msm/idle-v7.S
+++ b/arch/arm/mach-msm/idle-v7.S
@@ -2,7 +2,7 @@
* Idle processing for ARMv7-based Qualcomm SoCs.
*
* Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2007-2009, 2011-2012 Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2007-2009, 2011-2013 The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -97,7 +97,7 @@
mrc p15, 0, ip, c13, c0, 1 /* context ID */
stmia r0!, {r1-r9, ip}
-#ifdef CONFIG_MSM_JTAG
+#if defined(CONFIG_MSM_JTAG) || defined(CONFIG_MSM_JTAG_MM)
bl msm_jtag_save_state
#endif
@@ -185,7 +185,7 @@
blxne r1
dmb
-#ifdef CONFIG_MSM_JTAG
+#if defined(CONFIG_MSM_JTAG) || defined(CONFIG_MSM_JTAG_MM)
bl msm_jtag_restore_state
#endif
ldr r0, =msm_saved_state /* address of msm_saved_state ptr */
@@ -286,7 +286,7 @@
stmfd sp!, {lr}
blxne r1
dmb
-#ifdef CONFIG_MSM_JTAG
+#if defined(CONFIG_MSM_JTAG) || defined(CONFIG_MSM_JTAG_MM)
bl msm_jtag_restore_state
#endif
ldmfd sp!, {lr}
diff --git a/arch/arm/mach-msm/include/mach/iommu.h b/arch/arm/mach-msm/include/mach/iommu.h
index 8b39e34..9e2c24e 100644
--- a/arch/arm/mach-msm/include/mach/iommu.h
+++ b/arch/arm/mach-msm/include/mach/iommu.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
@@ -94,6 +94,7 @@
* @bfb_settings: Optional BFB performance tuning parameters
* @dev: Struct device this hardware instance is tied to
* @list: List head to link all iommus together
+ * @clk_reg_virt: Optional clock register virtual address.
*
* A msm_iommu_drvdata holds the global driver data about a single piece
* of an IOMMU hardware instance.
@@ -108,10 +109,12 @@
struct clk *aclk;
const char *name;
struct regulator *gdsc;
+ struct regulator *alt_gdsc;
struct msm_iommu_bfb_settings *bfb_settings;
int sec_id;
struct device *dev;
struct list_head list;
+ void __iomem *clk_reg_virt;
};
void msm_iommu_add_drv(struct msm_iommu_drvdata *drv);
diff --git a/arch/arm/mach-msm/include/mach/iommu_perfmon.h b/arch/arm/mach-msm/include/mach/iommu_perfmon.h
new file mode 100644
index 0000000..b44523f
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/iommu_perfmon.h
@@ -0,0 +1,177 @@
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/list.h>
+
+#ifndef MSM_IOMMU_PERFMON_H
+#define MSM_IOMMU_PERFMON_H
+
+
+/**
+ * struct iommu_access_ops - Callbacks for accessing IOMMU
+ * @iommu_power_on: Turn on clocks/power to unit
+ * @iommu_power_off: Turn off clocks/power to unit
+ * @iommu_lock_acquire: Acquire any locks needed
+ * @iommu_lock_release: Release locks needed
+ */
+struct iommu_access_ops {
+ int (*iommu_power_on)(void *);
+ int (*iommu_power_off)(void *);
+ void (*iommu_lock_acquire)(void);
+ void (*iommu_lock_release)(void);
+};
+
+/**
+ * struct iommu_pmon_counter - container for a performance counter.
+ * @counter_no: counter number within the group
+ * @absolute_counter_no: counter number within IOMMU PMU
+ * @value: cached counter value
+ * @overflow_count: no of times counter has overflowed
+ * @enabled: indicates whether counter is enabled or not
+ * @current_event_class: current selected event class, -1 if none
+ * @counter_dir: debugfs directory for this counter
+ * @cnt_group: group this counter belongs to
+ */
+struct iommu_pmon_counter {
+ unsigned int counter_no;
+ unsigned int absolute_counter_no;
+ unsigned long value;
+ unsigned long overflow_count;
+ unsigned int enabled;
+ int current_event_class;
+ struct dentry *counter_dir;
+ struct iommu_pmon_cnt_group *cnt_group;
+};
+
+/**
+ * struct iommu_pmon_cnt_group - container for a perf mon counter group.
+ * @grp_no: group number
+ * @num_counters: number of counters in this group
+ * @counters: list of counter in this group
+ * @group_dir: debugfs directory for this group
+ * @pmon: pointer to the iommu_pmon object this group belongs to
+ */
+struct iommu_pmon_cnt_group {
+ unsigned int grp_no;
+ unsigned int num_counters;
+ struct iommu_pmon_counter *counters;
+ struct dentry *group_dir;
+ struct iommu_pmon *pmon;
+};
+
+/**
+ * struct iommu_info - container for a perf mon iommu info.
+ * @iommu_name: name of the iommu from device tree
+ * @base: virtual base address for this iommu
+ * @evt_irq: irq number for event overflow interrupt
+ * @iommu_dev: pointer to iommu device
+ * @ops: iommu access operations pointer.
+ */
+struct iommu_info {
+ const char *iommu_name;
+ void *base;
+ int evt_irq;
+ struct device *iommu_dev;
+ struct iommu_access_ops *ops;
+};
+
+/**
+ * struct iommu_pmon - main container for a perf mon data.
+ * @iommu_dir: debugfs directory for this iommu
+ * @iommu: iommu_info instance
+ * @iommu_list: iommu_list head
+ * @cnt_grp: list of counter groups
+ * @num_groups: number of counter groups
+ * @event_cls_supp_value: event classes supported for this PMU
+ * @enabled: Indicates whether perf. mon is enabled or not
+ * @iommu_attached Indicates whether iommu is attached or not.
+ * @lock: mutex used to synchronize access to shared data
+ */
+struct iommu_pmon {
+ struct dentry *iommu_dir;
+ struct iommu_info iommu;
+ struct list_head iommu_list;
+ struct iommu_pmon_cnt_group *cnt_grp;
+ unsigned int num_groups;
+ unsigned int event_cls_supp_value;
+ unsigned int enabled;
+ unsigned int iommu_attach_count;
+ struct mutex lock;
+};
+
+extern struct iommu_access_ops iommu_access_ops;
+
+#ifdef CONFIG_MSM_IOMMU_PMON
+/**
+ * Allocate memory for performance monitor structure. Must
+ * be called befre iommu_pm_iommu_register
+ */
+struct iommu_info *msm_iommu_pm_alloc(struct device *iommu_dev);
+
+/**
+ * Free memory previously allocated with iommu_pm_alloc
+ */
+void msm_iommu_pm_free(struct device *iommu_dev);
+
+/**
+ * Register iommu with the performance monitor module.
+ */
+int msm_iommu_pm_iommu_register(struct iommu_info *info);
+
+/**
+ * Unregister iommu with the performance monitor module.
+ */
+void msm_iommu_pm_iommu_unregister(struct device *dev);
+
+/**
+ * Called by iommu driver when attaching is complete
+ * Must NOT be called with IOMMU mutexes held.
+ * @param iommu_dev IOMMU device that is attached
+ */
+void msm_iommu_attached(struct device *dev);
+
+/**
+ * Called by iommu driver before detaching.
+ * Must NOT be called with IOMMU mutexes held.
+ * @param iommu_dev IOMMU device that is going to be detached
+ */
+void msm_iommu_detached(struct device *dev);
+#else
+static inline struct iommu_info *msm_iommu_pm_alloc(struct device *iommu_dev)
+{
+ return NULL;
+}
+
+static inline void msm_iommu_pm_free(struct device *iommu_dev)
+{
+ return;
+}
+
+static inline int msm_iommu_pm_iommu_register(struct iommu_info *info)
+{
+ return -EIO;
+}
+
+static inline void msm_iommu_pm_iommu_unregister(struct device *dev)
+{
+}
+
+static inline void msm_iommu_attached(struct device *dev)
+{
+}
+
+static inline void msm_iommu_detached(struct device *dev)
+{
+}
+#endif
+#endif
diff --git a/arch/arm/mach-msm/include/mach/jtag.h b/arch/arm/mach-msm/include/mach/jtag.h
index 3850eff..2131be6 100644
--- a/arch/arm/mach-msm/include/mach/jtag.h
+++ b/arch/arm/mach-msm/include/mach/jtag.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. 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
@@ -13,7 +13,7 @@
#ifndef __MACH_JTAG_H
#define __MACH_JTAG_H
-#ifdef CONFIG_MSM_JTAG
+#if defined(CONFIG_MSM_JTAG) || defined(CONFIG_MSM_JTAG_MM)
extern void msm_jtag_save_state(void);
extern void msm_jtag_restore_state(void);
#else
diff --git a/arch/arm/mach-msm/include/mach/msm_ipc_logging.h b/arch/arm/mach-msm/include/mach/msm_ipc_logging.h
index 0a203a5..ec9fdb0 100644
--- a/arch/arm/mach-msm/include/mach/msm_ipc_logging.h
+++ b/arch/arm/mach-msm/include/mach/msm_ipc_logging.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. 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
@@ -185,47 +185,49 @@
struct decode_context *));
#else
-void *ipc_log_context_create(int max_num_pages, const char *modname)
+static inline void *ipc_log_context_create(int max_num_pages,
+ const char *modname)
{ return NULL; }
-void msg_encode_start(struct encode_context *ectxt, uint32_t type) { }
+static inline void msg_encode_start(struct encode_context *ectxt,
+ uint32_t type) { }
-int tsv_timestamp_write(struct encode_context *ectxt)
+static inline int tsv_timestamp_write(struct encode_context *ectxt)
{ return -EINVAL; }
-int tsv_pointer_write(struct encode_context *ectxt, void *pointer)
+static inline int tsv_pointer_write(struct encode_context *ectxt, void *pointer)
{ return -EINVAL; }
-int tsv_int32_write(struct encode_context *ectxt, int32_t n)
+static inline int tsv_int32_write(struct encode_context *ectxt, int32_t n)
{ return -EINVAL; }
-int tsv_byte_array_write(struct encode_context *ectxt,
+static inline int tsv_byte_array_write(struct encode_context *ectxt,
void *data, int data_size)
{ return -EINVAL; }
-void msg_encode_end(struct encode_context *ectxt) { }
+static inline void msg_encode_end(struct encode_context *ectxt) { }
-void ipc_log_write(void *ctxt, struct encode_context *ectxt) { }
+static inline void ipc_log_write(void *ctxt, struct encode_context *ectxt) { }
-int ipc_log_string(void *ilctxt, const char *fmt, ...)
+static inline int ipc_log_string(void *ilctxt, const char *fmt, ...)
{ return -EINVAL; }
#define IPC_SPRINTF_DECODE(dctxt, args...) do { } while (0)
-void tsv_timestamp_read(struct encode_context *ectxt,
+static inline void tsv_timestamp_read(struct encode_context *ectxt,
struct decode_context *dctxt, const char *format) { }
-void tsv_pointer_read(struct encode_context *ectxt,
+static inline void tsv_pointer_read(struct encode_context *ectxt,
struct decode_context *dctxt, const char *format) { }
-int32_t tsv_int32_read(struct encode_context *ectxt,
+static inline int32_t tsv_int32_read(struct encode_context *ectxt,
struct decode_context *dctxt, const char *format)
{ return 0; }
-void tsv_byte_array_read(struct encode_context *ectxt,
+static inline void tsv_byte_array_read(struct encode_context *ectxt,
struct decode_context *dctxt, const char *format) { }
-int add_deserialization_func(void *ctxt, int type,
+static inline int add_deserialization_func(void *ctxt, int type,
void (*dfunc)(struct encode_context *,
struct decode_context *))
{ return 0; }
diff --git a/arch/arm/mach-msm/include/mach/msm_serial_hs.h b/arch/arm/mach-msm/include/mach/msm_serial_hs.h
index d2905d4..cc50955 100644
--- a/arch/arm/mach-msm/include/mach/msm_serial_hs.h
+++ b/arch/arm/mach-msm/include/mach/msm_serial_hs.h
@@ -17,15 +17,34 @@
#include<linux/serial_core.h>
-/* Optional platform device data for msm_serial_hs driver.
- * Used to configure low power wakeup */
+/**
+ * struct msm_serial_hs_platform_data - platform device data
+ * for msm hsuart device
+ * @wakeup_irq : IRQ line to be configured as Wakeup source.
+ * @inject_rx_on_wakeup : Set 1 if specific character to be inserted on wakeup
+ * @rx_to_inject : Character to be inserted on wakeup
+ * @gpio_config : Configure gpios that are used for uart communication
+ * @userid : User-defined number to be used to enumerate device as tty<userid>
+ * @uart_tx_gpio: GPIO number for UART Tx Line.
+ * @uart_rx_gpio: GPIO number for UART Rx Line.
+ * @uart_cts_gpio: GPIO number for UART CTS Line.
+ * @uart_rfr_gpio: GPIO number for UART RFR Line.
+ * @bam_tx_ep_pipe_index : BAM TX Endpoint Pipe Index for HSUART
+ * @bam_tx_ep_pipe_index : BAM RX Endpoint Pipe Index for HSUART
+ */
struct msm_serial_hs_platform_data {
int wakeup_irq; /* wakeup irq */
- /* bool: inject char into rx tty on wakeup */
unsigned char inject_rx_on_wakeup;
char rx_to_inject;
int (*gpio_config)(int);
int userid;
+
+ unsigned uart_tx_gpio;
+ unsigned uart_rx_gpio;
+ unsigned uart_cts_gpio;
+ unsigned uart_rfr_gpio;
+ unsigned bam_tx_ep_pipe_index;
+ unsigned bam_rx_ep_pipe_index;
};
unsigned int msm_hs_tx_empty(struct uart_port *uport);
diff --git a/arch/arm/mach-msm/include/mach/qdsp5/audio_acdb_def.h b/arch/arm/mach-msm/include/mach/qdsp5/audio_acdb_def.h
index e1fc0cd..5fc87e0 100644
--- a/arch/arm/mach-msm/include/mach/qdsp5/audio_acdb_def.h
+++ b/arch/arm/mach-msm/include/mach/qdsp5/audio_acdb_def.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. 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
@@ -48,4 +48,5 @@
/* ID used for virtual devices */
#define PSEUDO_ACDB_ID 0xFFFF
+int is_acdb_enabled(void);
#endif /* _MACH_QDSP5_V2_AUDIO_ACDB_DEF_H */
diff --git a/arch/arm/mach-msm/include/mach/qdsp6v2/apr_us_b.h b/arch/arm/mach-msm/include/mach/qdsp6v2/apr_us_b.h
new file mode 100644
index 0000000..11de6ef
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp6v2/apr_us_b.h
@@ -0,0 +1,70 @@
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef __APR_US_B_H__
+#define __APR_US_B_H__
+
+#include "apr_us.h"
+
+/* ======================================================================= */
+/* Session Level commands */
+#define USM_CMD_SHARED_MEM_MAP_REGION 0x00012728
+struct usm_cmd_memory_map_region {
+ struct apr_hdr hdr;
+ u16 mempool_id;
+ u16 num_regions;
+ u32 flags;
+ u32 shm_addr_lsw;
+ u32 shm_addr_msw;
+ u32 mem_size_bytes;
+} __packed;
+
+#define USM_CMDRSP_SHARED_MEM_MAP_REGION 0x00012729
+struct usm_cmdrsp_memory_map_region {
+ u32 mem_map_handle;
+} __packed;
+
+#define USM_CMD_SHARED_MEM_UNMAP_REGION 0x0001272A
+struct usm_cmd_memory_unmap_region {
+ struct apr_hdr hdr;
+ u32 mem_map_handle;
+} __packed;
+
+#define USM_DATA_CMD_READ 0x00012724
+struct usm_stream_cmd_read {
+ struct apr_hdr hdr;
+ u32 buf_addr_lsw;
+ u32 buf_addr_msw;
+ u32 mem_map_handle;
+ u32 buf_size;
+ u32 seq_id;
+ u32 counter;
+} __packed;
+
+#define USM_DATA_EVENT_READ_DONE 0x00012725
+
+#define USM_DATA_CMD_WRITE 0x00012726
+struct usm_stream_cmd_write {
+ struct apr_hdr hdr;
+ u32 buf_addr_lsw;
+ u32 buf_addr_msw;
+ u32 mem_map_handle;
+ u32 buf_size;
+ u32 seq_id;
+ u32 res0;
+ u32 res1;
+ u32 res2;
+} __packed;
+
+#define USM_DATA_EVENT_WRITE_DONE 0x00012727
+
+#endif /* __APR_US_B_H__ */
diff --git a/arch/arm/mach-msm/include/mach/remote_spinlock.h b/arch/arm/mach-msm/include/mach/remote_spinlock.h
index 75b70f3..72e7337 100644
--- a/arch/arm/mach-msm/include/mach/remote_spinlock.h
+++ b/arch/arm/mach-msm/include/mach/remote_spinlock.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009, 2011 Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2009, 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
@@ -39,7 +39,7 @@
typedef raw_remote_spinlock_t *_remote_spinlock_t;
#define remote_spinlock_id_t const char *
-#define SMEM_SPINLOCK_PID_APPS 1
+#define SPINLOCK_PID_APPS 1
static inline void __raw_remote_ex_spin_lock(raw_remote_spinlock_t *lock)
{
@@ -52,7 +52,7 @@
" teqeq %0, #0\n"
" bne 1b"
: "=&r" (tmp)
- : "r" (&lock->lock), "r" (1)
+ : "r" (&lock->lock), "r" (SPINLOCK_PID_APPS)
: "cc");
smp_mb();
@@ -67,7 +67,7 @@
" teq %0, #0\n"
" strexeq %0, %2, [%1]\n"
: "=&r" (tmp)
- : "r" (&lock->lock), "r" (1)
+ : "r" (&lock->lock), "r" (SPINLOCK_PID_APPS)
: "cc");
if (tmp == 0) {
@@ -79,7 +79,14 @@
static inline void __raw_remote_ex_spin_unlock(raw_remote_spinlock_t *lock)
{
+ int lock_owner;
+
smp_mb();
+ lock_owner = readl_relaxed(&lock->lock);
+ if (lock_owner != SPINLOCK_PID_APPS) {
+ pr_err("%s: spinlock not owned by Apps (actual owner is %d)\n",
+ __func__, lock_owner);
+ }
__asm__ __volatile__(
" str %1, [%0]\n"
@@ -122,7 +129,14 @@
static inline void __raw_remote_swp_spin_unlock(raw_remote_spinlock_t *lock)
{
+ int lock_owner;
+
smp_mb();
+ lock_owner = readl_relaxed(&lock->lock);
+ if (lock_owner != SPINLOCK_PID_APPS) {
+ pr_err("%s: spinlock not owned by Apps (actual owner is %d)\n",
+ __func__, lock_owner);
+ }
__asm__ __volatile__(
" str %1, [%0]"
@@ -178,15 +192,20 @@
static inline int __raw_remote_dek_spin_release(raw_remote_spinlock_t *lock,
uint32_t pid)
{
- return -EINVAL;
+ return -EPERM;
+}
+
+static inline int __raw_remote_dek_spin_owner(raw_remote_spinlock_t *lock)
+{
+ return -EPERM;
}
static inline void __raw_remote_sfpb_spin_lock(raw_remote_spinlock_t *lock)
{
do {
- writel_relaxed(SMEM_SPINLOCK_PID_APPS, lock);
+ writel_relaxed(SPINLOCK_PID_APPS, lock);
smp_mb();
- } while (readl_relaxed(lock) != SMEM_SPINLOCK_PID_APPS);
+ } while (readl_relaxed(lock) != SPINLOCK_PID_APPS);
}
static inline int __raw_remote_sfpb_spin_trylock(raw_remote_spinlock_t *lock)
@@ -196,6 +215,14 @@
static inline void __raw_remote_sfpb_spin_unlock(raw_remote_spinlock_t *lock)
{
+ int lock_owner;
+
+ lock_owner = readl_relaxed(lock);
+ if (lock_owner != SPINLOCK_PID_APPS) {
+ pr_err("%s: spinlock not owned by Apps (actual owner is %d)\n",
+ __func__, lock_owner);
+ }
+
writel_relaxed(0, lock);
smp_mb();
}
@@ -206,8 +233,8 @@
* This is only to be used for situations where the processor owning
* the spinlock has crashed and the spinlock must be released.
*
- * @lock - lock structure
- * @pid - processor ID of processor to release
+ * @lock: lock structure
+ * @pid: processor ID of processor to release
*/
static inline int __raw_remote_gen_spin_release(raw_remote_spinlock_t *lock,
uint32_t pid)
@@ -222,6 +249,20 @@
return ret;
}
+/**
+ * Return owner of the spinlock.
+ *
+ * @lock: pointer to lock structure
+ * @returns: >= 0 owned PID; < 0 for error case
+ *
+ * Used for testing. PID's are assumed to be 31 bits or less.
+ */
+static inline int __raw_remote_gen_spin_owner(raw_remote_spinlock_t *lock)
+{
+ rmb();
+ return readl_relaxed(&lock->lock);
+}
+
#if defined(CONFIG_MSM_SMD) || defined(CONFIG_MSM_REMOTE_SPINLOCK_SFPB)
int _remote_spin_lock_init(remote_spinlock_id_t, _remote_spinlock_t *lock);
void _remote_spin_release_all(uint32_t pid);
@@ -242,6 +283,7 @@
#define _remote_spin_trylock(lock) __raw_remote_dek_spin_trylock(*lock)
#define _remote_spin_release(lock, pid) __raw_remote_dek_spin_release(*lock,\
pid)
+#define _remote_spin_owner(lock) __raw_remote_dek_spin_owner(*lock)
#elif defined(CONFIG_MSM_REMOTE_SPINLOCK_SWP)
/* Use SWP-based locks when LDREX/STREX are unavailable for shared memory. */
#define _remote_spin_lock(lock) __raw_remote_swp_spin_lock(*lock)
@@ -249,6 +291,7 @@
#define _remote_spin_trylock(lock) __raw_remote_swp_spin_trylock(*lock)
#define _remote_spin_release(lock, pid) __raw_remote_gen_spin_release(*lock,\
pid)
+#define _remote_spin_owner(lock) __raw_remote_gen_spin_owner(*lock)
#elif defined(CONFIG_MSM_REMOTE_SPINLOCK_SFPB)
/* Use SFPB Hardware Mutex Registers */
#define _remote_spin_lock(lock) __raw_remote_sfpb_spin_lock(*lock)
@@ -256,6 +299,7 @@
#define _remote_spin_trylock(lock) __raw_remote_sfpb_spin_trylock(*lock)
#define _remote_spin_release(lock, pid) __raw_remote_gen_spin_release(*lock,\
pid)
+#define _remote_spin_owner(lock) __raw_remote_gen_spin_owner(*lock)
#else
/* Use LDREX/STREX for shared memory locking, when available */
#define _remote_spin_lock(lock) __raw_remote_ex_spin_lock(*lock)
@@ -263,6 +307,7 @@
#define _remote_spin_trylock(lock) __raw_remote_ex_spin_trylock(*lock)
#define _remote_spin_release(lock, pid) __raw_remote_gen_spin_release(*lock, \
pid)
+#define _remote_spin_owner(lock) __raw_remote_gen_spin_owner(*lock)
#endif
/* Remote mutex definitions. */
diff --git a/arch/arm/mach-msm/include/mach/socinfo.h b/arch/arm/mach-msm/include/mach/socinfo.h
index c0624bb..345f09c 100644
--- a/arch/arm/mach-msm/include/mach/socinfo.h
+++ b/arch/arm/mach-msm/include/mach/socinfo.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2012, Code Aurora Forum. 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
@@ -147,7 +147,7 @@
uint32_t socinfo_get_platform_version(void);
enum pmic_model socinfo_get_pmic_model(void);
uint32_t socinfo_get_pmic_die_revision(void);
-int __init socinfo_init(void) __must_check;
+struct device * __init socinfo_init(void) __must_check;
const int read_msm_cpu_type(void);
const int get_core_count(void);
const int cpu_is_krait(void);
diff --git a/arch/arm/mach-msm/ipc_router.c b/arch/arm/mach-msm/ipc_router.c
index fde43b0..cdacd87 100644
--- a/arch/arm/mach-msm/ipc_router.c
+++ b/arch/arm/mach-msm/ipc_router.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. 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
@@ -2288,13 +2288,19 @@
RR("x REMOVE_SERVER Name=%d:%08x Id=%d:%08x\n",
msg.srv.service, msg.srv.instance,
msg.srv.node_id, msg.srv.port_id);
- } else if (port_ptr->type == CLIENT_PORT) {
- msg.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT;
- msg.cli.node_id = port_ptr->this_port.node_id;
- msg.cli.port_id = port_ptr->this_port.port_id;
- RR("x REMOVE_CLIENT id=%d:%08x\n",
- msg.cli.node_id, msg.cli.port_id);
+ broadcast_ctl_msg(&msg);
+ broadcast_ctl_msg_locally(&msg);
}
+
+ /*
+ * Server port could have been a client port earlier.
+ * Send REMOVE_CLIENT message in either case.
+ */
+ msg.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT;
+ msg.cli.node_id = port_ptr->this_port.node_id;
+ msg.cli.port_id = port_ptr->this_port.port_id;
+ RR("x REMOVE_CLIENT id=%d:%08x\n",
+ msg.cli.node_id, msg.cli.port_id);
broadcast_ctl_msg(&msg);
broadcast_ctl_msg_locally(&msg);
} else if (port_ptr->type == CONTROL_PORT) {
diff --git a/arch/arm/mach-msm/jtag-mm.c b/arch/arm/mach-msm/jtag-mm.c
new file mode 100644
index 0000000..af05995
--- /dev/null
+++ b/arch/arm/mach-msm/jtag-mm.c
@@ -0,0 +1,747 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/smp.h>
+#include <linux/export.h>
+#include <linux/printk.h>
+#include <linux/ratelimit.h>
+#include <linux/coresight.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/bitops.h>
+#include <mach/scm.h>
+#include <mach/jtag.h>
+
+/* Coresight management registers */
+#define CORESIGHT_ITCTRL (0xF00)
+#define CORESIGHT_CLAIMSET (0xFA0)
+#define CORESIGHT_CLAIMCLR (0xFA4)
+#define CORESIGHT_LAR (0xFB0)
+#define CORESIGHT_LSR (0xFB4)
+#define CORESIGHT_AUTHSTATUS (0xFB8)
+#define CORESIGHT_DEVID (0xFC8)
+#define CORESIGHT_DEVTYPE (0xFCC)
+
+#define CORESIGHT_UNLOCK (0xC5ACCE55)
+
+#define TIMEOUT_US (100)
+
+#define BM(lsb, msb) ((BIT(msb) - BIT(lsb)) + BIT(msb))
+#define BMVAL(val, lsb, msb) ((val & BM(lsb, msb)) >> lsb)
+#define BVAL(val, n) ((val & BIT(n)) >> n)
+
+/* Trace registers */
+#define ETMCR (0x000)
+#define ETMCCR (0x004)
+#define ETMTRIGGER (0x008)
+#define ETMASICCTLR (0x00C)
+#define ETMSR (0x010)
+#define ETMSCR (0x014)
+#define ETMTSSCR (0x018)
+#define ETMTECR2 (0x01C)
+#define ETMTEEVR (0x020)
+#define ETMTECR1 (0x024)
+#define ETMFFLR (0x02C)
+#define ETMVDEVR (0x030)
+#define ETMVDCR1 (0x034)
+#define ETMVDCR3 (0x03C)
+#define ETMACVRn(n) (0x040 + (n * 4))
+#define ETMACTRn(n) (0x080 + (n * 4))
+#define ETMDCVRn(n) (0x0C0 + (n * 8))
+#define ETMDCMRn(n) (0x100 + (n * 8))
+#define ETMCNTRLDVRn(n) (0x140 + (n * 4))
+#define ETMCNTENRn(n) (0x150 + (n * 4))
+#define ETMCNTRLDEVRn(n) (0x160 + (n * 4))
+#define ETMCNTVRn(n) (0x170 + (n * 4))
+#define ETMSQ12EVR (0x180)
+#define ETMSQ21EVR (0x184)
+#define ETMSQ23EVR (0x188)
+#define ETMSQ31EVR (0x18C)
+#define ETMSQ32EVR (0x190)
+#define ETMSQ13EVR (0x194)
+#define ETMSQR (0x19C)
+#define ETMEXTOUTEVRn(n) (0x1A0 + (n * 4))
+#define ETMCIDCVRn(n) (0x1B0 + (n * 4))
+#define ETMCIDCMR (0x1BC)
+#define ETMIMPSPEC0 (0x1C0)
+#define ETMIMPSPEC1 (0x1C4)
+#define ETMIMPSPEC2 (0x1C8)
+#define ETMIMPSPEC3 (0x1CC)
+#define ETMIMPSPEC4 (0x1D0)
+#define ETMIMPSPEC5 (0x1D4)
+#define ETMIMPSPEC6 (0x1D8)
+#define ETMIMPSPEC7 (0x1DC)
+#define ETMSYNCFR (0x1E0)
+#define ETMIDR (0x1E4)
+#define ETMCCER (0x1E8)
+#define ETMEXTINSELR (0x1EC)
+#define ETMTESSEICR (0x1F0)
+#define ETMEIBCR (0x1F4)
+#define ETMTSEVR (0x1F8)
+#define ETMAUXCR (0x1FC)
+#define ETMTRACEIDR (0x200)
+#define ETMIDR2 (0x208)
+#define ETMVMIDCVR (0x240)
+#define ETMCLAIMSET (0xFA0)
+#define ETMCLAIMCLR (0xFA4)
+/* ETM Management registers */
+#define ETMOSLAR (0x300)
+#define ETMOSLSR (0x304)
+#define ETMOSSRR (0x308)
+#define ETMPDCR (0x310)
+#define ETMPDSR (0x314)
+
+#define ETM_MAX_ADDR_CMP (16)
+#define ETM_MAX_CNTR (4)
+#define ETM_MAX_CTXID_CMP (3)
+
+/* DBG Registers */
+#define DBGDIDR (0x0)
+#define DBGWFAR (0x18)
+#define DBGVCR (0x1C)
+#define DBGDTRRXext (0x80)
+#define DBGDSCRext (0x88)
+#define DBGDTRTXext (0x8C)
+#define DBGDRCR (0x90)
+#define DBGBVRn(n) (0x100 + (n * 4))
+#define DBGBCRn(n) (0x140 + (n * 4))
+#define DBGWVRn(n) (0x180 + (n * 4))
+#define DBGWCRn(n) (0x1C0 + (n * 4))
+#define DBGPRCR (0x310)
+#define DBGITMISCOUT (0xEF8)
+#define DBGITMISCIN (0xEFC)
+#define DBGCLAIMSET (0xFA0)
+#define DBGCLAIMCLR (0xFA4)
+
+#define DBGDSCR_MASK (0x6C30FC3C)
+
+#define MAX_DBG_STATE_SIZE (90)
+#define MAX_ETM_STATE_SIZE (78)
+
+#define TZ_DBG_ETM_FEAT_ID (0x8)
+#define TZ_DBG_ETM_VER (0x400000)
+
+#define ARCH_V3_5 (0x25)
+#define ARM_DEBUG_ARCH_V7B (0x3)
+
+#define etm_write(etm, val, off) \
+ __raw_writel(val, etm->base + off)
+#define etm_read(etm, off) \
+ __raw_readl(etm->base + off)
+
+#define dbg_write(dbg, val, off) \
+ __raw_writel(val, dbg->base + off)
+#define dbg_read(dbg, off) \
+ __raw_readl(dbg->base + off)
+
+#define ETM_LOCK(base) \
+do { \
+ /* recommended by spec to ensure ETM writes are committed prior
+ * to resuming execution
+ */ \
+ mb(); \
+ etm_write(base, 0x0, CORESIGHT_LAR); \
+} while (0)
+
+#define ETM_UNLOCK(base) \
+do { \
+ etm_write(base, CORESIGHT_UNLOCK, CORESIGHT_LAR); \
+ /* ensure unlock and any pending writes are committed prior to
+ * programming ETM registers
+ */ \
+ mb(); \
+} while (0)
+
+#define DBG_LOCK(base) \
+do { \
+ /* recommended by spec to ensure ETM writes are committed prior
+ * to resuming execution
+ */ \
+ mb(); \
+ dbg_write(base, 0x0, CORESIGHT_LAR); \
+} while (0)
+
+#define DBG_UNLOCK(base) \
+do { \
+ dbg_write(base, CORESIGHT_UNLOCK, CORESIGHT_LAR); \
+ /* ensure unlock and any pending writes are committed prior to
+ * programming ETM registers
+ */ \
+ mb(); \
+} while (0)
+
+uint32_t msm_jtag_save_cntr[NR_CPUS];
+uint32_t msm_jtag_restore_cntr[NR_CPUS];
+
+struct dbg_cpu_ctx {
+ void __iomem *base;
+ uint32_t *state;
+};
+
+struct dbg_ctx {
+ uint8_t arch;
+ uint8_t nr_wp;
+ uint8_t nr_bp;
+ uint8_t nr_ctx_cmp;
+ struct dbg_cpu_ctx *cpu_ctx[NR_CPUS];
+ bool save_restore_enabled[NR_CPUS];
+};
+static struct dbg_ctx dbg;
+
+struct etm_cpu_ctx {
+ void __iomem *base;
+ struct device *dev;
+ uint32_t *state;
+};
+
+struct etm_ctx {
+ uint8_t arch;
+ uint8_t nr_addr_cmp;
+ uint8_t nr_data_cmp;
+ uint8_t nr_cntr;
+ uint8_t nr_ext_inp;
+ uint8_t nr_ext_out;
+ uint8_t nr_ctxid_cmp;
+ struct etm_cpu_ctx *cpu_ctx[NR_CPUS];
+ bool save_restore_enabled[NR_CPUS];
+};
+
+static struct etm_ctx etm;
+
+static struct clk *clock[NR_CPUS];
+
+static void etm_set_pwrdwn(struct etm_cpu_ctx *etmdata)
+{
+ uint32_t etmcr;
+
+ /* ensure all writes are complete before setting pwrdwn */
+ mb();
+ etmcr = etm_read(etmdata, ETMCR);
+ etmcr |= BIT(0);
+ etm_write(etmdata, etmcr, ETMCR);
+}
+
+static void etm_clr_pwrdwn(struct etm_cpu_ctx *etmdata)
+{
+ uint32_t etmcr;
+
+ etmcr = etm_read(etmdata, ETMCR);
+ etmcr &= ~BIT(0);
+ etm_write(etmdata, etmcr, ETMCR);
+ /* ensure pwrup completes before subsequent register accesses */
+ mb();
+}
+
+static void etm_set_prog(struct etm_cpu_ctx *etmdata)
+{
+ uint32_t etmcr;
+ int count;
+
+ etmcr = etm_read(etmdata, ETMCR);
+ etmcr |= BIT(10);
+ etm_write(etmdata, etmcr, ETMCR);
+ for (count = TIMEOUT_US; BVAL(etm_read(etmdata, ETMSR), 1) != 1
+ && count > 0; count--)
+ udelay(1);
+ WARN(count == 0, "timeout while setting prog bit, ETMSR: %#x\n",
+ etm_read(etmdata, ETMSR));
+}
+
+static inline void etm_save_state(struct etm_cpu_ctx *etmdata)
+{
+ int i, j;
+
+ i = 0;
+ ETM_UNLOCK(etmdata);
+
+ switch (etm.arch) {
+ case ETM_ARCH_V3_5:
+ etmdata->state[i++] = etm_read(etmdata, ETMTRIGGER);
+ etmdata->state[i++] = etm_read(etmdata, ETMASICCTLR);
+ etmdata->state[i++] = etm_read(etmdata, ETMSR);
+ etmdata->state[i++] = etm_read(etmdata, ETMTSSCR);
+ etmdata->state[i++] = etm_read(etmdata, ETMTECR2);
+ etmdata->state[i++] = etm_read(etmdata, ETMTEEVR);
+ etmdata->state[i++] = etm_read(etmdata, ETMTECR1);
+ etmdata->state[i++] = etm_read(etmdata, ETMFFLR);
+ etmdata->state[i++] = etm_read(etmdata, ETMVDEVR);
+ etmdata->state[i++] = etm_read(etmdata, ETMVDCR1);
+ etmdata->state[i++] = etm_read(etmdata, ETMVDCR3);
+ for (j = 0; j < etm.nr_addr_cmp; j++) {
+ etmdata->state[i++] = etm_read(etmdata,
+ ETMACVRn(j));
+ etmdata->state[i++] = etm_read(etmdata,
+ ETMACTRn(j));
+ }
+ for (j = 0; j < etm.nr_data_cmp; j++) {
+ etmdata->state[i++] = etm_read(etmdata,
+ ETMDCVRn(j));
+ etmdata->state[i++] = etm_read(etmdata,
+ ETMDCMRn(j));
+ }
+ for (j = 0; j < etm.nr_cntr; j++) {
+ etmdata->state[i++] = etm_read(etmdata,
+ ETMCNTRLDVRn(j));
+ etmdata->state[i++] = etm_read(etmdata,
+ ETMCNTENRn(j));
+ etmdata->state[i++] = etm_read(etmdata,
+ ETMCNTRLDEVRn(j));
+ etmdata->state[i++] = etm_read(etmdata,
+ ETMCNTVRn(j));
+ }
+ etmdata->state[i++] = etm_read(etmdata, ETMSQ12EVR);
+ etmdata->state[i++] = etm_read(etmdata, ETMSQ21EVR);
+ etmdata->state[i++] = etm_read(etmdata, ETMSQ23EVR);
+ etmdata->state[i++] = etm_read(etmdata, ETMSQ31EVR);
+ etmdata->state[i++] = etm_read(etmdata, ETMSQ32EVR);
+ etmdata->state[i++] = etm_read(etmdata, ETMSQ13EVR);
+ etmdata->state[i++] = etm_read(etmdata, ETMSQR);
+ for (j = 0; j < etm.nr_ext_out; j++)
+ etmdata->state[i++] = etm_read(etmdata,
+ ETMEXTOUTEVRn(j));
+ for (j = 0; j < etm.nr_ctxid_cmp; j++)
+ etmdata->state[i++] = etm_read(etmdata,
+ ETMCIDCVRn(j));
+ etmdata->state[i++] = etm_read(etmdata, ETMCIDCMR);
+ etmdata->state[i++] = etm_read(etmdata, ETMSYNCFR);
+ etmdata->state[i++] = etm_read(etmdata, ETMEXTINSELR);
+ etmdata->state[i++] = etm_read(etmdata, ETMTSEVR);
+ etmdata->state[i++] = etm_read(etmdata, ETMAUXCR);
+ etmdata->state[i++] = etm_read(etmdata, ETMTRACEIDR);
+ etmdata->state[i++] = etm_read(etmdata, ETMVMIDCVR);
+ etmdata->state[i++] = etm_read(etmdata, ETMCLAIMCLR);
+ etmdata->state[i++] = etm_read(etmdata, ETMCR);
+ break;
+ default:
+ pr_err_ratelimited("unsupported etm arch %d in %s\n", etm.arch,
+ __func__);
+ }
+
+ ETM_LOCK(etmdata);
+}
+
+static inline void etm_restore_state(struct etm_cpu_ctx *etmdata)
+{
+ int i, j;
+
+ i = 0;
+ ETM_UNLOCK(etmdata);
+
+ switch (etm.arch) {
+ case ETM_ARCH_V3_5:
+ etm_clr_pwrdwn(etmdata);
+ etm_write(etmdata, etmdata->state[i++], ETMTRIGGER);
+ etm_write(etmdata, etmdata->state[i++], ETMASICCTLR);
+ etm_write(etmdata, etmdata->state[i++], ETMSR);
+ etm_write(etmdata, etmdata->state[i++], ETMTSSCR);
+ etm_write(etmdata, etmdata->state[i++], ETMTECR2);
+ etm_write(etmdata, etmdata->state[i++], ETMTEEVR);
+ etm_write(etmdata, etmdata->state[i++], ETMTECR1);
+ etm_write(etmdata, etmdata->state[i++], ETMFFLR);
+ etm_write(etmdata, etmdata->state[i++], ETMVDEVR);
+ etm_write(etmdata, etmdata->state[i++], ETMVDCR1);
+ etm_write(etmdata, etmdata->state[i++], ETMVDCR3);
+ for (j = 0; j < etm.nr_addr_cmp; j++) {
+ etm_write(etmdata, etmdata->state[i++],
+ ETMACVRn(j));
+ etm_write(etmdata, etmdata->state[i++],
+ ETMACTRn(j));
+ }
+ for (j = 0; j < etm.nr_data_cmp; j++) {
+ etm_write(etmdata, etmdata->state[i++],
+ ETMDCVRn(j));
+ etm_write(etmdata, etmdata->state[i++],
+ ETMDCMRn(j));
+ }
+ for (j = 0; j < etm.nr_cntr; j++) {
+ etm_write(etmdata, etmdata->state[i++],
+ ETMCNTRLDVRn(j));
+ etm_write(etmdata, etmdata->state[i++],
+ ETMCNTENRn(j));
+ etm_write(etmdata, etmdata->state[i++],
+ ETMCNTRLDEVRn(j));
+ etm_write(etmdata, etmdata->state[i++],
+ ETMCNTVRn(j));
+ }
+ etm_write(etmdata, etmdata->state[i++], ETMSQ12EVR);
+ etm_write(etmdata, etmdata->state[i++], ETMSQ21EVR);
+ etm_write(etmdata, etmdata->state[i++], ETMSQ23EVR);
+ etm_write(etmdata, etmdata->state[i++], ETMSQ31EVR);
+ etm_write(etmdata, etmdata->state[i++], ETMSQ32EVR);
+ etm_write(etmdata, etmdata->state[i++], ETMSQ13EVR);
+ etm_write(etmdata, etmdata->state[i++], ETMSQR);
+ for (j = 0; j < etm.nr_ext_out; j++)
+ etm_write(etmdata, etmdata->state[i++],
+ ETMEXTOUTEVRn(j));
+ for (j = 0; j < etm.nr_ctxid_cmp; j++)
+ etm_write(etmdata, etmdata->state[i++],
+ ETMCIDCVRn(j));
+ etm_write(etmdata, etmdata->state[i++], ETMCIDCMR);
+ etm_write(etmdata, etmdata->state[i++], ETMSYNCFR);
+ etm_write(etmdata, etmdata->state[i++], ETMEXTINSELR);
+ etm_write(etmdata, etmdata->state[i++], ETMTSEVR);
+ etm_write(etmdata, etmdata->state[i++], ETMAUXCR);
+ etm_write(etmdata, etmdata->state[i++], ETMTRACEIDR);
+ etm_write(etmdata, etmdata->state[i++], ETMVMIDCVR);
+ etm_write(etmdata, etmdata->state[i++], ETMCLAIMSET);
+ /*
+ * Set ETMCR at last as we dont know the saved status of pwrdwn
+ * bit
+ */
+ etm_write(etmdata, etmdata->state[i++], ETMCR);
+ break;
+ default:
+ pr_err_ratelimited("unsupported etm arch %d in %s\n", etm.arch,
+ __func__);
+ }
+
+ ETM_LOCK(etmdata);
+}
+
+static inline void dbg_save_state(struct dbg_cpu_ctx *dbgdata)
+{
+ int i, j;
+
+ i = 0;
+ DBG_UNLOCK(dbgdata);
+
+ dbgdata->state[i++] = dbg_read(dbgdata, DBGWFAR);
+ dbgdata->state[i++] = dbg_read(dbgdata, DBGVCR);
+ for (j = 0; j < dbg.nr_bp; j++) {
+ dbgdata->state[i++] = dbg_read(dbgdata, DBGBVRn(j));
+ dbgdata->state[i++] = dbg_read(dbgdata, DBGBCRn(j));
+ }
+ for (j = 0; j < dbg.nr_wp; j++) {
+ dbgdata->state[i++] = dbg_read(dbgdata, DBGWVRn(j));
+ dbgdata->state[i++] = dbg_read(dbgdata, DBGWCRn(j));
+ }
+ dbgdata->state[i++] = dbg_read(dbgdata, DBGPRCR);
+ dbgdata->state[i++] = dbg_read(dbgdata, DBGCLAIMSET);
+ dbgdata->state[i++] = dbg_read(dbgdata, DBGCLAIMCLR);
+ dbgdata->state[i++] = dbg_read(dbgdata, DBGDTRTXext);
+ dbgdata->state[i++] = dbg_read(dbgdata, DBGDTRRXext);
+ dbgdata->state[i++] = dbg_read(dbgdata, DBGDSCRext);
+
+ DBG_LOCK(dbgdata);
+}
+
+static inline void dbg_restore_state(struct dbg_cpu_ctx *dbgdata)
+{
+ int i, j;
+
+ i = 0;
+ DBG_UNLOCK(dbgdata);
+
+ dbg_write(dbgdata, dbgdata->state[i++], DBGWFAR);
+ dbg_write(dbgdata, dbgdata->state[i++], DBGVCR);
+ for (j = 0; j < dbg.nr_bp; j++) {
+ dbg_write(dbgdata, dbgdata->state[i++], DBGBVRn(j));
+ dbg_write(dbgdata, dbgdata->state[i++], DBGBCRn(j));
+ }
+ for (j = 0; j < dbg.nr_wp; j++) {
+ dbg_write(dbgdata, dbgdata->state[i++], DBGWVRn(j));
+ dbg_write(dbgdata, dbgdata->state[i++], DBGWCRn(j));
+ }
+ dbg_write(dbgdata, dbgdata->state[i++], DBGPRCR);
+ dbg_write(dbgdata, dbgdata->state[i++], DBGCLAIMSET);
+ dbg_write(dbgdata, dbgdata->state[i++], DBGCLAIMCLR);
+ dbg_write(dbgdata, dbgdata->state[i++], DBGDTRTXext);
+ dbg_write(dbgdata, dbgdata->state[i++], DBGDTRRXext);
+ dbg_write(dbgdata, dbgdata->state[i++] & DBGDSCR_MASK,
+ DBGDSCRext);
+
+ DBG_LOCK(dbgdata);
+}
+
+void msm_jtag_save_state(void)
+{
+ int cpu;
+
+ cpu = raw_smp_processor_id();
+
+ msm_jtag_save_cntr[cpu]++;
+ /* ensure counter is updated before moving forward */
+ mb();
+
+ if (dbg.save_restore_enabled[cpu])
+ dbg_save_state(dbg.cpu_ctx[cpu]);
+ if (etm.save_restore_enabled[cpu])
+ etm_save_state(etm.cpu_ctx[cpu]);
+}
+EXPORT_SYMBOL(msm_jtag_save_state);
+
+void msm_jtag_restore_state(void)
+{
+ int cpu;
+
+ cpu = raw_smp_processor_id();
+
+ /* Attempt restore only if save has been done. If power collapse
+ * is disabled, hotplug off of non-boot core will result in WFI
+ * and hence msm_jtag_save_state will not occur. Subsequently,
+ * during hotplug on of non-boot core when msm_jtag_restore_state
+ * is called via msm_platform_secondary_init, this check will help
+ * bail us out without restoring.
+ */
+ if (msm_jtag_save_cntr[cpu] == msm_jtag_restore_cntr[cpu])
+ return;
+ else if (msm_jtag_save_cntr[cpu] != msm_jtag_restore_cntr[cpu] + 1)
+ pr_err_ratelimited("jtag imbalance, save:%lu, restore:%lu\n",
+ (unsigned long)msm_jtag_save_cntr[cpu],
+ (unsigned long)msm_jtag_restore_cntr[cpu]);
+
+ msm_jtag_restore_cntr[cpu]++;
+ /* ensure counter is updated before moving forward */
+ mb();
+
+ if (dbg.save_restore_enabled[cpu])
+ dbg_restore_state(dbg.cpu_ctx[cpu]);
+ if (etm.save_restore_enabled[cpu])
+ etm_restore_state(etm.cpu_ctx[cpu]);
+}
+EXPORT_SYMBOL(msm_jtag_restore_state);
+
+static inline bool etm_arch_supported(uint8_t arch)
+{
+ switch (arch) {
+ case ETM_ARCH_V3_5:
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+static void __devinit etm_init_arch_data(void *info)
+{
+ uint32_t etmidr;
+ uint32_t etmccr;
+ struct etm_cpu_ctx *etmdata = info;
+
+ /*
+ * Clear power down bit since when this bit is set writes to
+ * certain registers might be ignored.
+ */
+ ETM_UNLOCK(etmdata);
+
+ etm_clr_pwrdwn(etmdata);
+ /* Set prog bit. It will be set from reset but this is included to
+ * ensure it is set
+ */
+ etm_set_prog(etmdata);
+
+ /* find all capabilities */
+ etmidr = etm_read(etmdata, ETMIDR);
+ etm.arch = BMVAL(etmidr, 4, 11);
+
+ etmccr = etm_read(etmdata, ETMCCR);
+ etm.nr_addr_cmp = BMVAL(etmccr, 0, 3) * 2;
+ etm.nr_data_cmp = BMVAL(etmccr, 4, 7);
+ etm.nr_cntr = BMVAL(etmccr, 13, 15);
+ etm.nr_ext_inp = BMVAL(etmccr, 17, 19);
+ etm.nr_ext_out = BMVAL(etmccr, 20, 22);
+ etm.nr_ctxid_cmp = BMVAL(etmccr, 24, 25);
+
+ etm_set_pwrdwn(etmdata);
+
+ ETM_LOCK(etmdata);
+}
+
+static int __devinit jtag_mm_etm_probe(struct platform_device *pdev,
+ uint32_t cpu)
+{
+ struct etm_cpu_ctx *etmdata;
+ struct resource *res;
+ struct device *dev = &pdev->dev;
+
+ /* Allocate memory per cpu */
+ etmdata = devm_kzalloc(dev, sizeof(struct etm_cpu_ctx), GFP_KERNEL);
+ if (!etmdata)
+ return -ENOMEM;
+
+ etm.cpu_ctx[cpu] = etmdata;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ etmdata->base = devm_ioremap(dev, res->start, resource_size(res));
+ if (!etmdata->base)
+ return -EINVAL;
+
+ /* Allocate etm state save space per core */
+ etmdata->state = devm_kzalloc(dev,
+ (MAX_ETM_STATE_SIZE * sizeof(uint32_t)), GFP_KERNEL);
+ if (!etmdata->state)
+ return -ENOMEM;
+
+ smp_call_function_single(0, etm_init_arch_data, etmdata, 1);
+
+ if (etm_arch_supported(etm.arch)) {
+ if (scm_get_feat_version(TZ_DBG_ETM_FEAT_ID) < TZ_DBG_ETM_VER)
+ etm.save_restore_enabled[cpu] = true;
+ else
+ pr_info("etm save-restore supported by TZ\n");
+ } else
+ pr_info("etm arch %u not supported\n", etm.arch);
+ return 0;
+}
+
+static inline bool dbg_arch_supported(uint8_t arch)
+{
+ switch (arch) {
+ case ARM_DEBUG_ARCH_V7B:
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+static void __devinit dbg_init_arch_data(void *info)
+{
+ uint32_t dbgdidr;
+ struct dbg_cpu_ctx *dbgdata = info;
+
+ /* This will run on core0 so use it to populate parameters */
+ dbgdidr = dbg_read(dbgdata, DBGDIDR);
+ dbg.arch = BMVAL(dbgdidr, 16, 19);
+ dbg.nr_ctx_cmp = BMVAL(dbgdidr, 20, 23) + 1;
+ dbg.nr_bp = BMVAL(dbgdidr, 24, 27) + 1;
+ dbg.nr_wp = BMVAL(dbgdidr, 28, 31) + 1;
+}
+
+
+
+static int __devinit jtag_mm_dbg_probe(struct platform_device *pdev,
+ uint32_t cpu)
+{
+ struct dbg_cpu_ctx *dbgdata;
+ struct resource *res;
+ struct device *dev = &pdev->dev;
+
+ /* Allocate memory per cpu */
+ dbgdata = devm_kzalloc(dev, sizeof(struct dbg_cpu_ctx), GFP_KERNEL);
+ if (!dbgdata)
+ return -ENOMEM;
+
+ dbg.cpu_ctx[cpu] = dbgdata;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+
+ dbgdata->base = devm_ioremap(dev, res->start, resource_size(res));
+ if (!dbgdata->base)
+ return -EINVAL;
+
+ /* Allocate etm state save space per core */
+ dbgdata->state = devm_kzalloc(dev,
+ (MAX_DBG_STATE_SIZE * sizeof(uint32_t)), GFP_KERNEL);
+ if (!dbgdata->state)
+ return -ENOMEM;
+
+ smp_call_function_single(0, dbg_init_arch_data, dbgdata, 1);
+
+ if (dbg_arch_supported(dbg.arch)) {
+ if (scm_get_feat_version(TZ_DBG_ETM_FEAT_ID) < TZ_DBG_ETM_VER)
+ dbg.save_restore_enabled[cpu] = true;
+ else
+ pr_info("dbg save-restore supported by TZ\n");
+ } else
+ pr_info("dbg arch %u not supported\n", dbg.arch);
+ return 0;
+}
+
+static int __devinit jtag_mm_probe(struct platform_device *pdev)
+{
+ int etm_ret, dbg_ret, ret;
+ static uint32_t cpu;
+ static uint32_t count;
+ struct device *dev = &pdev->dev;
+
+ cpu = count;
+ count++;
+
+ clock[cpu] = devm_clk_get(dev, "core_clk");
+ if (IS_ERR(clock[cpu])) {
+ ret = PTR_ERR(clock[cpu]);
+ return ret;
+ }
+
+ ret = clk_set_rate(clock[cpu], CORESIGHT_CLK_RATE_TRACE);
+ if (ret)
+ return ret;
+
+ ret = clk_prepare_enable(clock[cpu]);
+ if (ret)
+ return ret;
+
+ platform_set_drvdata(pdev, clock[cpu]);
+
+ etm_ret = jtag_mm_etm_probe(pdev, cpu);
+
+ dbg_ret = jtag_mm_dbg_probe(pdev, cpu);
+
+ /* The probe succeeds even when only one of the etm and dbg probes
+ * succeeds. This allows us to save-restore etm and dbg registers
+ * independently.
+ */
+ if (etm_ret && dbg_ret) {
+ clk_disable_unprepare(clock[cpu]);
+ ret = etm_ret;
+ } else
+ ret = 0;
+ return ret;
+}
+
+static int __devexit jtag_mm_remove(struct platform_device *pdev)
+{
+ struct clk *clock = platform_get_drvdata(pdev);
+
+ clk_disable_unprepare(clock);
+ return 0;
+}
+
+static struct of_device_id msm_qdss_mm_match[] = {
+ { .compatible = "qcom,jtag-mm"},
+ {}
+};
+
+static struct platform_driver jtag_mm_driver = {
+ .probe = jtag_mm_probe,
+ .remove = __devexit_p(jtag_mm_remove),
+ .driver = {
+ .name = "msm-jtag-mm",
+ .owner = THIS_MODULE,
+ .of_match_table = msm_qdss_mm_match,
+ },
+};
+
+static int __init jtag_mm_init(void)
+{
+ return platform_driver_register(&jtag_mm_driver);
+}
+module_init(jtag_mm_init);
+
+static void __exit jtag_mm_exit(void)
+{
+ platform_driver_unregister(&jtag_mm_driver);
+}
+module_exit(jtag_mm_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Coresight debug and ETM save-restore driver");
diff --git a/arch/arm/mach-msm/kernel_test_service_v01.c b/arch/arm/mach-msm/kernel_test_service_v01.c
new file mode 100644
index 0000000..498e046
--- /dev/null
+++ b/arch/arm/mach-msm/kernel_test_service_v01.c
@@ -0,0 +1,254 @@
+/* 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/qmi_encdec.h>
+
+#include <mach/msm_qmi_interface.h>
+
+#include "kernel_test_service_v01.h"
+
+#define PING_REQ1_TLV_TYPE 0x1
+#define PING_RESP1_TLV_TYPE 0x2
+#define PING_OPT1_TLV_TYPE 0x10
+#define PING_OPT2_TLV_TYPE 0x11
+
+#define DATA_REQ1_TLV_TYPE 0x1
+#define DATA_RESP1_TLV_TYPE 0x2
+#define DATA_OPT1_TLV_TYPE 0x10
+#define DATA_OPT2_TLV_TYPE 0x11
+
+static struct elem_info test_name_type_v01_ei[] = {
+ {
+ .data_type = QMI_DATA_LEN,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
+ .offset = offsetof(struct test_name_type_v01,
+ name_len),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = TEST_MAX_NAME_SIZE_V01,
+ .elem_size = sizeof(char),
+ .is_array = VAR_LEN_ARRAY,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
+ .offset = offsetof(struct test_name_type_v01,
+ name),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info test_ping_req_msg_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 4,
+ .elem_size = sizeof(char),
+ .is_array = STATIC_ARRAY,
+ .tlv_type = PING_REQ1_TLV_TYPE,
+ .offset = offsetof(struct test_ping_req_msg_v01,
+ ping),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = PING_OPT1_TLV_TYPE,
+ .offset = offsetof(struct test_ping_req_msg_v01,
+ client_name_valid),
+ },
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct test_name_type_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = PING_OPT1_TLV_TYPE,
+ .offset = offsetof(struct test_ping_req_msg_v01,
+ client_name),
+ .ei_array = test_name_type_v01_ei,
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info test_ping_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = PING_RESP1_TLV_TYPE,
+ .offset = offsetof(struct test_ping_resp_msg_v01,
+ resp),
+ .ei_array = get_qmi_response_type_v01_ei(),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = PING_OPT1_TLV_TYPE,
+ .offset = offsetof(struct test_ping_resp_msg_v01,
+ pong_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 4,
+ .elem_size = sizeof(char),
+ .is_array = STATIC_ARRAY,
+ .tlv_type = PING_OPT1_TLV_TYPE,
+ .offset = offsetof(struct test_ping_resp_msg_v01,
+ pong),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = PING_OPT2_TLV_TYPE,
+ .offset = offsetof(struct test_ping_resp_msg_v01,
+ service_name_valid),
+ },
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct test_name_type_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = PING_OPT2_TLV_TYPE,
+ .offset = offsetof(struct test_ping_resp_msg_v01,
+ service_name),
+ .ei_array = test_name_type_v01_ei,
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info test_data_req_msg_v01_ei[] = {
+ {
+ .data_type = QMI_DATA_LEN,
+ .elem_len = 1,
+ .elem_size = sizeof(uint32_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = DATA_REQ1_TLV_TYPE,
+ .offset = offsetof(struct test_data_req_msg_v01,
+ data_len),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = TEST_MED_DATA_SIZE_V01,
+ .elem_size = sizeof(uint8_t),
+ .is_array = VAR_LEN_ARRAY,
+ .tlv_type = DATA_REQ1_TLV_TYPE,
+ .offset = offsetof(struct test_data_req_msg_v01,
+ data),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = DATA_OPT1_TLV_TYPE,
+ .offset = offsetof(struct test_data_req_msg_v01,
+ client_name_valid),
+ },
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct test_name_type_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = DATA_OPT1_TLV_TYPE,
+ .offset = offsetof(struct test_data_req_msg_v01,
+ client_name),
+ .ei_array = test_name_type_v01_ei,
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info test_data_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = DATA_RESP1_TLV_TYPE,
+ .offset = offsetof(struct test_data_resp_msg_v01,
+ resp),
+ .ei_array = get_qmi_response_type_v01_ei(),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = DATA_OPT1_TLV_TYPE,
+ .offset = offsetof(struct test_data_resp_msg_v01,
+ data_valid),
+ },
+ {
+ .data_type = QMI_DATA_LEN,
+ .elem_len = 1,
+ .elem_size = sizeof(uint32_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = DATA_OPT1_TLV_TYPE,
+ .offset = offsetof(struct test_data_resp_msg_v01,
+ data_len),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = TEST_MED_DATA_SIZE_V01,
+ .elem_size = sizeof(uint8_t),
+ .is_array = VAR_LEN_ARRAY,
+ .tlv_type = DATA_OPT1_TLV_TYPE,
+ .offset = offsetof(struct test_data_resp_msg_v01,
+ data),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = DATA_OPT2_TLV_TYPE,
+ .offset = offsetof(struct test_data_resp_msg_v01,
+ service_name_valid),
+ },
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct test_name_type_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = DATA_OPT2_TLV_TYPE,
+ .offset = offsetof(struct test_data_resp_msg_v01,
+ service_name),
+ .ei_array = test_name_type_v01_ei,
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
+ },
+};
diff --git a/arch/arm/mach-msm/kernel_test_service_v01.h b/arch/arm/mach-msm/kernel_test_service_v01.h
new file mode 100644
index 0000000..79c1845
--- /dev/null
+++ b/arch/arm/mach-msm/kernel_test_service_v01.h
@@ -0,0 +1,73 @@
+/* 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_QMI_TEST_SERVICE_V01_H
+#define MSM_QMI_TEST_SERVICE_V01_H
+
+#include <mach/msm_qmi_interface.h>
+
+#define TEST_MED_DATA_SIZE_V01 8192
+#define TEST_MAX_NAME_SIZE_V01 255
+
+#define TEST_PING_REQ_MSG_ID_V01 0x20
+#define TEST_DATA_REQ_MSG_ID_V01 0x21
+
+#define TEST_PING_REQ_MAX_MSG_LEN_V01 266
+#define TEST_DATA_REQ_MAX_MSG_LEN_V01 8456
+
+struct test_name_type_v01 {
+ uint32_t name_len;
+ char name[TEST_MAX_NAME_SIZE_V01];
+};
+
+struct test_ping_req_msg_v01 {
+ char ping[4];
+
+ uint8_t client_name_valid;
+ struct test_name_type_v01 client_name;
+};
+
+struct test_ping_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+
+ uint8_t pong_valid;
+ char pong[4];
+
+ uint8_t service_name_valid;
+ struct test_name_type_v01 service_name;
+};
+
+struct test_data_req_msg_v01 {
+ uint32_t data_len;
+ uint8_t data[TEST_MED_DATA_SIZE_V01];
+
+ uint8_t client_name_valid;
+ struct test_name_type_v01 client_name;
+};
+
+struct test_data_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+
+ uint8_t data_valid;
+ uint32_t data_len;
+ uint8_t data[TEST_MED_DATA_SIZE_V01];
+
+ uint8_t service_name_valid;
+ struct test_name_type_v01 service_name;
+};
+
+extern struct elem_info test_ping_req_msg_v01_ei[];
+extern struct elem_info test_data_req_msg_v01_ei[];
+extern struct elem_info test_ping_resp_msg_v01_ei[];
+extern struct elem_info test_data_resp_msg_v01_ei[];
+
+#endif
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_board_8974.c b/arch/arm/mach-msm/msm_bus/msm_bus_board_8974.c
index dbfa5ec..7b67157 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_board_8974.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_board_8974.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. 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
@@ -539,7 +539,6 @@
static int qports_venus_p1[] = {5};
static int qports_vfe[] = {6};
static int qports_gemini_ocmem[] = {0};
-static int qports_mdp_ocmem[] = {1};
static int qports_venus_p0_ocmem[] = {2};
static int qports_venus_p1_ocmem[] = {3};
static int qports_vfe_ocmem[] = {4};
@@ -1154,7 +1153,6 @@
.num_tiers = ARRAY_SIZE(tier2),
.perm_mode = NOC_QOS_PERM_MODE_FIXED,
.mode = NOC_QOS_MODE_FIXED,
- .qport = qports_mdp_ocmem,
.mas_hw_id = MAS_MDP_OCMEM,
.hw_sel = MSM_BUS_NOC,
},
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c b/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
index b6870c6..2c4b434 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2013, 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
@@ -679,7 +679,7 @@
return ret;
}
-static int msm_bus_fabric_probe(struct platform_device *pdev)
+static int __devinit msm_bus_fabric_probe(struct platform_device *pdev)
{
int ctx, ret = 0;
struct msm_bus_fabric *fabric;
@@ -694,7 +694,6 @@
INIT_LIST_HEAD(&fabric->gateways);
INIT_RADIX_TREE(&fabric->fab_tree, GFP_ATOMIC);
fabric->num_nodes = 0;
- fabric->fabdev.id = pdev->id;
fabric->fabdev.visited = false;
fabric->info.node_info = kzalloc(sizeof(struct msm_bus_node_info),
@@ -704,18 +703,31 @@
kfree(fabric);
return -ENOMEM;
}
- fabric->info.node_info->priv_id = fabric->fabdev.id;
- fabric->info.node_info->id = fabric->fabdev.id;
+
fabric->info.num_pnodes = -1;
fabric->info.link_info.clk[DUAL_CTX] = 0;
fabric->info.link_info.bw[DUAL_CTX] = 0;
fabric->info.link_info.clk[ACTIVE_CTX] = 0;
fabric->info.link_info.bw[ACTIVE_CTX] = 0;
- fabric->fabdev.id = pdev->id;
- pdata = (struct msm_bus_fabric_registration *)pdev->dev.platform_data;
+ /* If possible, get pdata from device-tree */
+ if (pdev->dev.of_node) {
+ pdata = pdev->dev.platform_data;
+ if (IS_ERR(pdata) || ZERO_OR_NULL_PTR(pdata)) {
+ pr_err("Null platform data\n");
+ return PTR_ERR(pdata);
+ }
+ fabric->fabdev.id = pdata->id;
+ } else {
+ pdata = (struct msm_bus_fabric_registration *)pdev->
+ dev.platform_data;
+ fabric->fabdev.id = pdev->id;
+ }
+
fabric->fabdev.name = pdata->name;
fabric->fabdev.algo = &msm_bus_algo;
+ fabric->info.node_info->priv_id = fabric->fabdev.id;
+ fabric->info.node_info->id = fabric->fabdev.id;
ret = msm_bus_fabric_hw_init(pdata, &fabric->fabdev.hw_algo);
if (ret) {
MSM_BUS_ERR("Error initializing hardware for fabric: %d\n",
@@ -811,12 +823,18 @@
return ret;
}
+static struct of_device_id fabric_match[] = {
+ {.compatible = "msm_bus_fabric"},
+ {}
+};
+
static struct platform_driver msm_bus_fabric_driver = {
.probe = msm_bus_fabric_probe,
.remove = msm_bus_fabric_remove,
.driver = {
.name = "msm_bus_fabric",
.owner = THIS_MODULE,
+ .of_match_table = fabric_match,
},
};
@@ -825,4 +843,4 @@
MSM_BUS_ERR("msm_bus_fabric_init_driver\n");
return platform_driver_register(&msm_bus_fabric_driver);
}
-postcore_initcall(msm_bus_fabric_init_driver);
+subsys_initcall(msm_bus_fabric_init_driver);
diff --git a/arch/arm/mach-msm/ocmem_core.c b/arch/arm/mach-msm/ocmem_core.c
index 3d9639f..9782b90 100644
--- a/arch/arm/mach-msm/ocmem_core.c
+++ b/arch/arm/mach-msm/ocmem_core.c
@@ -488,7 +488,7 @@
if (mpu_start < 0)
/* Avoid underflow */
mpu_start = 0;
- mpu_end = ((offset+len) >> GFX_MPU_SHIFT) - 1;
+ mpu_end = ((offset+len) >> GFX_MPU_SHIFT);
BUG_ON(mpu_end < 0);
pr_debug("ocmem: mpu: start %x end %x\n", mpu_start, mpu_end);
diff --git a/arch/arm/mach-msm/pil-pronto.c b/arch/arm/mach-msm/pil-pronto.c
index cfcf5dc..9c89f2d 100644
--- a/arch/arm/mach-msm/pil-pronto.c
+++ b/arch/arm/mach-msm/pil-pronto.c
@@ -235,6 +235,12 @@
return pas_init_image(PAS_WCNSS, metadata, size);
}
+static int pil_pronto_mem_setup_trusted(struct pil_desc *pil, phys_addr_t addr,
+ size_t size)
+{
+ return pas_mem_setup(PAS_WCNSS, addr, size);
+}
+
static int pil_pronto_reset_trusted(struct pil_desc *pil)
{
return pas_auth_and_reset(PAS_WCNSS);
@@ -247,6 +253,7 @@
static struct pil_reset_ops pil_pronto_ops_trusted = {
.init_image = pil_pronto_init_image_trusted,
+ .mem_setup = pil_pronto_mem_setup_trusted,
.auth_and_reset = pil_pronto_reset_trusted,
.shutdown = pil_pronto_shutdown_trusted,
.proxy_vote = pil_pronto_make_proxy_vote,
diff --git a/arch/arm/mach-msm/pil-q6v5-lpass.c b/arch/arm/mach-msm/pil-q6v5-lpass.c
index 5e03aa8..5c498ec 100644
--- a/arch/arm/mach-msm/pil-q6v5-lpass.c
+++ b/arch/arm/mach-msm/pil-q6v5-lpass.c
@@ -153,6 +153,12 @@
return pas_init_image(PAS_Q6, metadata, size);
}
+static int pil_lpass_mem_setup_trusted(struct pil_desc *pil, phys_addr_t addr,
+ size_t size)
+{
+ return pas_mem_setup(PAS_Q6, addr, size);
+}
+
static int pil_lpass_reset_trusted(struct pil_desc *pil)
{
return pas_auth_and_reset(PAS_Q6);
@@ -165,6 +171,7 @@
static struct pil_reset_ops pil_lpass_ops_trusted = {
.init_image = pil_lpass_init_image_trusted,
+ .mem_setup = pil_lpass_mem_setup_trusted,
.proxy_vote = pil_q6v5_make_proxy_votes,
.proxy_unvote = pil_q6v5_remove_proxy_votes,
.auth_and_reset = pil_lpass_reset_trusted,
diff --git a/arch/arm/mach-msm/pil-venus.c b/arch/arm/mach-msm/pil-venus.c
index eb222e3..1fcd3ba 100644
--- a/arch/arm/mach-msm/pil-venus.c
+++ b/arch/arm/mach-msm/pil-venus.c
@@ -401,6 +401,12 @@
return pas_init_image(PAS_VIDC, metadata, size);
}
+static int pil_venus_mem_setup_trusted(struct pil_desc *pil, phys_addr_t addr,
+ size_t size)
+{
+ return pas_mem_setup(PAS_VIDC, addr, size);
+}
+
static int pil_venus_reset_trusted(struct pil_desc *pil)
{
int rc;
@@ -442,6 +448,7 @@
static struct pil_reset_ops pil_venus_ops_trusted = {
.init_image = pil_venus_init_image_trusted,
+ .mem_setup = pil_venus_mem_setup_trusted,
.auth_and_reset = pil_venus_reset_trusted,
.shutdown = pil_venus_shutdown_trusted,
.proxy_vote = pil_venus_make_proxy_vote,
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index b42ad94..e35d843 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -779,7 +779,7 @@
{
int i;
unsigned int power_usage = -1;
- int ret = 0;
+ int ret = MSM_PM_SLEEP_MODE_NOT_SELECTED;
uint32_t modified_time_us = 0;
struct msm_pm_time_params time_param;
@@ -948,9 +948,14 @@
break;
}
+ case MSM_PM_SLEEP_MODE_NOT_SELECTED:
+ goto cpuidle_enter_bail;
+ break;
+
default:
__WARN();
goto cpuidle_enter_bail;
+ break;
}
time = ktime_to_ns(ktime_get()) - time;
diff --git a/arch/arm/mach-msm/pm.h b/arch/arm/mach-msm/pm.h
index bd61feb..86d8f98 100644
--- a/arch/arm/mach-msm/pm.h
+++ b/arch/arm/mach-msm/pm.h
@@ -52,7 +52,8 @@
MSM_PM_SLEEP_MODE_RETENTION = MSM_PM_SLEEP_MODE_APPS_SLEEP,
MSM_PM_SLEEP_MODE_POWER_COLLAPSE_SUSPEND = 5,
MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN = 6,
- MSM_PM_SLEEP_MODE_NR
+ MSM_PM_SLEEP_MODE_NR = 7,
+ MSM_PM_SLEEP_MODE_NOT_SELECTED,
};
#define MSM_PM_MODE(cpu, mode_nr) ((cpu) * MSM_PM_SLEEP_MODE_NR + (mode_nr))
diff --git a/arch/arm/mach-msm/pmu.c b/arch/arm/mach-msm/pmu.c
index cb191fc..21f65f8 100644
--- a/arch/arm/mach-msm/pmu.c
+++ b/arch/arm/mach-msm/pmu.c
@@ -181,7 +181,7 @@
* and point to the appropriate 'struct resource'.
*/
#ifdef CONFIG_ARCH_MSM8625
- if (cpu_is_msm8625()) {
+ if (cpu_is_msm8625() || cpu_is_msm8625q()) {
pmu_devices[0] = &msm8625_cpu_pmu_device;
pmu_devices[1] = &msm8625_l2_pmu_device;
msm8625_cpu_pmu_device.dev.platform_data = &multicore_data;
diff --git a/arch/arm/mach-msm/qdsp5/audio_acdb.c b/arch/arm/mach-msm/qdsp5/audio_acdb.c
index d7a4607..681b41c 100644
--- a/arch/arm/mach-msm/qdsp5/audio_acdb.c
+++ b/arch/arm/mach-msm/qdsp5/audio_acdb.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. 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
@@ -1301,6 +1301,15 @@
}
EXPORT_SYMBOL(acdb_get_calibration_data);
+int is_acdb_enabled()
+{
+ if (acdb_data.handle != NULL)
+ return 1;
+ else
+ return 0;
+}
+EXPORT_SYMBOL(is_acdb_enabled);
+
static u8 check_device_info_already_present(
struct dev_evt_msg device_info,
struct acdb_cache_node *acdb_cache_free_node)
@@ -1522,7 +1531,7 @@
result = -EINVAL;
goto done;
} else
- MM_DBG("AUDPP is calibrated with IIR parameters");
+ MM_DBG("AUDPP is calibrated with IIR parameters\n");
}
result = acdb_fill_audpp_mbadrc();
if (!IS_ERR_VALUE(result)) {
@@ -2270,13 +2279,9 @@
if (ret == 1) {
MM_DBG("got device ready call back for another "\
"audplay task sessions on same COPP\n");
- /*stream_id is used to keep track of number of active*/
- /*sessions active on this device*/
- acdb_cache_free_node->stream_id++;
mutex_unlock(&acdb_data.acdb_mutex);
goto done;
}
- acdb_cache_free_node->stream_id++;
}
update_acdb_data_struct(acdb_cache_free_node);
acdb_data.device_cb_compl = 1;
@@ -2317,6 +2322,9 @@
}
goto done;
}
+ /*stream_id is used to keep track of number of active*/
+ /*sessions active on this device*/
+ acdb_cache_rx.stream_id++;
acdb_data.acdb_state |= AUDPP_READY;
acdb_data.audpp_cb_compl = 1;
diff --git a/arch/arm/mach-msm/qdsp5/audio_out.c b/arch/arm/mach-msm/qdsp5/audio_out.c
index 6f3bf91..fee7404 100644
--- a/arch/arm/mach-msm/qdsp5/audio_out.c
+++ b/arch/arm/mach-msm/qdsp5/audio_out.c
@@ -4,7 +4,7 @@
*
* Copyright (C) 2008 Google, Inc.
* Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2012 Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2012-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
@@ -39,6 +39,7 @@
#include "audmgr.h"
+#include <mach/qdsp5/audio_acdb_def.h>
#include <mach/qdsp5/qdsp5audppcmdi.h>
#include <mach/qdsp5/qdsp5audppmsg.h>
#include <mach/qdsp5/qdsp5audpp.h>
@@ -298,19 +299,20 @@
if (!audio_copp->status)
return;
- audpp_dsp_set_mbadrc(COMMON_OBJ_ID, audio_copp->mbadrc_enable,
+ if (!is_acdb_enabled()) {
+ audpp_dsp_set_mbadrc(COMMON_OBJ_ID, audio_copp->mbadrc_enable,
&audio_copp->mbadrc);
- audpp_dsp_set_eq(COMMON_OBJ_ID, audio_copp->eq_enable,
+ audpp_dsp_set_eq(COMMON_OBJ_ID, audio_copp->eq_enable,
&audio_copp->eq);
-
- audpp_dsp_set_rx_iir(COMMON_OBJ_ID, audio_copp->rx_iir_enable,
+ audpp_dsp_set_rx_iir(COMMON_OBJ_ID, audio_copp->rx_iir_enable,
&audio_copp->iir);
- audpp_dsp_set_vol_pan(COMMON_OBJ_ID, &audio_copp->vol_pan);
+ audpp_dsp_set_vol_pan(COMMON_OBJ_ID, &audio_copp->vol_pan);
- audpp_dsp_set_qconcert_plus(COMMON_OBJ_ID,
+ audpp_dsp_set_qconcert_plus(COMMON_OBJ_ID,
audio_copp->qconcert_plus_enable,
&audio_copp->qconcert_plus);
+ }
audio_enable_srs_trumedia(audio_copp, true);
}
EXPORT_SYMBOL(audio_commit_pending_pp_params);
diff --git a/arch/arm/mach-msm/qdsp5/audio_pcm_in.c b/arch/arm/mach-msm/qdsp5/audio_pcm_in.c
index 7b2090d..c5787fd 100644
--- a/arch/arm/mach-msm/qdsp5/audio_pcm_in.c
+++ b/arch/arm/mach-msm/qdsp5/audio_pcm_in.c
@@ -2,7 +2,7 @@
*
* pcm audio input device
*
- * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
*
* This code is based in part on arch/arm/mach-msm/qdsp5v2/audio_pcm_in.c,
* Copyright (C) 2008 Google, Inc.
@@ -42,6 +42,7 @@
#include "audmgr.h"
+#include <mach/qdsp5/audio_acdb_def.h>
#include <mach/qdsp5/qdsp5audpreproc.h>
#include <mach/qdsp5/qdsp5audpreproccmdi.h>
#include <mach/qdsp5/qdsp5audpreprocmsg.h>
@@ -346,6 +347,8 @@
case AUDREC_MSG_CMD_AREC_PARAM_CFG_DONE_MSG: {
MM_INFO("PARAM CFG DONE\n");
audio->running = 1;
+ if (is_acdb_enabled())
+ break;
audio_dsp_set_tx_agc(audio);
audio_dsp_set_ns(audio);
audio_dsp_set_iir(audio);
@@ -914,6 +917,12 @@
mutex_lock(&audio->lock);
switch (cmd) {
case AUDIO_ENABLE_AUDPRE:
+
+ if (is_acdb_enabled()) {
+ MM_INFO("Audpp is supported via acdb\n");
+ rc = -EFAULT;
+ break;
+ }
if (copy_from_user(&enable_mask, (void *) arg,
sizeof(enable_mask))) {
rc = -EFAULT;
diff --git a/arch/arm/mach-msm/qdsp5/audmgr.c b/arch/arm/mach-msm/qdsp5/audmgr.c
index f2a84aa..fb51240 100644
--- a/arch/arm/mach-msm/qdsp5/audmgr.c
+++ b/arch/arm/mach-msm/qdsp5/audmgr.c
@@ -158,8 +158,10 @@
return;
if (am->state != STATE_ENABLED)
am->state = STATE_ENABLED;
- if (!amg->cad)
+ if (!amg->cad) {
+ wake_up(&am->wait);
break;
+ }
if (am->evt.session_info == SESSION_PLAYBACK &&
am->evt.dev_type.rx_device != amg->rx_device) {
diff --git a/arch/arm/mach-msm/qdsp6v2/Makefile b/arch/arm/mach-msm/qdsp6v2/Makefile
index 08a6de6..323532c 100644
--- a/arch/arm/mach-msm/qdsp6v2/Makefile
+++ b/arch/arm/mach-msm/qdsp6v2/Makefile
@@ -27,3 +27,4 @@
obj-$(CONFIG_MSM_QDSP6V2_CODECS) += audio_mp3.o audio_amrnb.o audio_amrwb.o audio_evrc.o audio_qcelp.o amrwb_in.o
obj-$(CONFIG_MSM_ADSP_LOADER) += adsp-loader.o
obj-$(CONFIG_MSM_ULTRASOUND_A) += ultrasound/version_a/
+obj-$(CONFIG_MSM_ULTRASOUND_B) += ultrasound/version_b/
diff --git a/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.h b/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.h
index c68ad68..bf47366 100644
--- a/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.h
+++ b/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. 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
@@ -62,7 +62,7 @@
struct mutex lock;
spinlock_t dsp_lock;
/* extended parameters, related to q6 variants */
- void *ext;
+ void *ext;
};
struct us_client {
diff --git a/arch/arm/mach-msm/qdsp6v2/ultrasound/version_b/Makefile b/arch/arm/mach-msm/qdsp6v2/ultrasound/version_b/Makefile
new file mode 100644
index 0000000..23de73f
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/ultrasound/version_b/Makefile
@@ -0,0 +1,2 @@
+obj-y += q6usm_b.o ../usf.o ../usfcdev.o
+ccflags-y := -I$(src)/.. -I$(src)/../..
diff --git a/arch/arm/mach-msm/qdsp6v2/ultrasound/version_b/q6usm_b.c b/arch/arm/mach-msm/qdsp6v2/ultrasound/version_b/q6usm_b.c
new file mode 100644
index 0000000..11b1405
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/ultrasound/version_b/q6usm_b.c
@@ -0,0 +1,1208 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/mutex.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/msm_audio.h>
+#include <sound/apr_audio.h>
+#include <mach/qdsp6v2/apr_us_b.h>
+#include "q6usm.h"
+
+#define ADSP_MEMORY_MAP_SHMEM8_4K_POOL 3
+
+#define MEM_4K_OFFSET 4095
+#define MEM_4K_MASK 0xfffff000
+
+#define SESSION_MAX 0x02 /* aDSP:USM limit */
+
+#define READDONE_IDX_STATUS 0
+
+#define WRITEDONE_IDX_STATUS 0
+
+/* Standard timeout in the asynchronous ops */
+#define Q6USM_TIMEOUT_JIFFIES (1*HZ) /* 1 sec */
+
+static DEFINE_MUTEX(session_lock);
+
+static struct us_client *session[SESSION_MAX];
+static int32_t q6usm_mmapcallback(struct apr_client_data *data, void *priv);
+static int32_t q6usm_callback(struct apr_client_data *data, void *priv);
+static void q6usm_add_hdr(struct us_client *usc, struct apr_hdr *hdr,
+ uint32_t pkt_size, bool cmd_flg);
+
+struct usm_mmap {
+ atomic_t ref_cnt;
+ atomic_t cmd_state;
+ wait_queue_head_t cmd_wait;
+ void *apr;
+ int mem_handle;
+};
+
+static struct usm_mmap this_mmap;
+
+static void q6usm_add_mmaphdr(struct us_client *usc, struct apr_hdr *hdr,
+ uint32_t pkt_size, bool cmd_flg, u32 token)
+{
+ hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, \
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ hdr->src_port = 0;
+ hdr->dest_port = 0;
+ if (cmd_flg) {
+ hdr->token = token;
+ atomic_set(&this_mmap.cmd_state, 1);
+ }
+ hdr->pkt_size = pkt_size;
+ return;
+}
+
+static int q6usm_memory_map(struct us_client *usc, uint32_t buf_add, int dir,
+ uint32_t bufsz, uint32_t bufcnt)
+{
+ struct usm_cmd_memory_map_region mem_region_map;
+ int rc = 0;
+
+ if ((usc == NULL) || (usc->apr == NULL) || (this_mmap.apr == NULL)) {
+ pr_err("%s: APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ q6usm_add_mmaphdr(usc, &mem_region_map.hdr,
+ sizeof(struct usm_cmd_memory_map_region), true,
+ ((usc->session << 8) | dir));
+
+ mem_region_map.hdr.opcode = USM_CMD_SHARED_MEM_MAP_REGION;
+ mem_region_map.mempool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL;
+
+ mem_region_map.num_regions = 1;
+ mem_region_map.flags = 0;
+
+ mem_region_map.shm_addr_lsw = buf_add;
+ mem_region_map.shm_addr_msw = 0;
+ mem_region_map.mem_size_bytes = bufsz * bufcnt;
+
+ rc = apr_send_pkt(this_mmap.apr, (uint32_t *) &mem_region_map);
+ if (rc < 0) {
+ pr_err("%s: mem_map op[0x%x]rc[%d]\n",
+ __func__, mem_region_map.hdr.opcode, rc);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+
+ rc = wait_event_timeout(this_mmap.cmd_wait,
+ (atomic_read(&this_mmap.cmd_state) == 0),
+ Q6USM_TIMEOUT_JIFFIES);
+ if (!rc) {
+ rc = -ETIME;
+ pr_err("%s: timeout. waited for memory_map\n", __func__);
+ } else {
+ struct us_port_data *port = &usc->port[dir];
+
+ *((uint32_t *)(port->ext)) = this_mmap.mem_handle;
+ rc = 0;
+ }
+fail_cmd:
+ return rc;
+}
+
+int q6usm_memory_unmap(struct us_client *usc, uint32_t buf_add, int dir)
+{
+ struct usm_cmd_memory_unmap_region mem_unmap;
+ struct us_port_data *port = &usc->port[dir];
+ int rc = 0;
+
+ if ((usc == NULL) || (usc->apr == NULL) || (this_mmap.apr == NULL)) {
+ pr_err("%s: APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ port = &usc->port[dir];
+ q6usm_add_mmaphdr(usc, &mem_unmap.hdr,
+ sizeof(struct usm_cmd_memory_unmap_region), true,
+ ((usc->session << 8) | dir));
+ mem_unmap.hdr.opcode = USM_CMD_SHARED_MEM_UNMAP_REGION;
+ mem_unmap.mem_map_handle = *((uint32_t *)(port->ext));
+
+ rc = apr_send_pkt(this_mmap.apr, (uint32_t *) &mem_unmap);
+ if (rc < 0) {
+ pr_err("%s: mem_unmap op[0x%x] rc[%d]\n",
+ __func__, mem_unmap.hdr.opcode, rc);
+ goto fail_cmd;
+ }
+
+ rc = wait_event_timeout(this_mmap.cmd_wait,
+ (atomic_read(&this_mmap.cmd_state) == 0),
+ Q6USM_TIMEOUT_JIFFIES);
+ if (!rc) {
+ rc = -ETIME;
+ pr_err("%s: timeout. waited for memory_unmap\n", __func__);
+ } else
+ rc = 0;
+fail_cmd:
+ return rc;
+}
+
+static int q6usm_session_alloc(struct us_client *usc)
+{
+ int ind = 0;
+
+ mutex_lock(&session_lock);
+ for (ind = 0; ind < SESSION_MAX; ++ind) {
+ if (!session[ind]) {
+ session[ind] = usc;
+ mutex_unlock(&session_lock);
+ ++ind; /* session id: 0 reserved */
+ pr_debug("%s: session[%d] was allocated\n",
+ __func__, ind);
+ return ind;
+ }
+ }
+ mutex_unlock(&session_lock);
+ return -ENOMEM;
+}
+
+static void q6usm_session_free(struct us_client *usc)
+{
+ /* Session index was incremented during allocation */
+ uint16_t ind = (uint16_t)usc->session - 1;
+
+ pr_debug("%s: to free session[%d]\n", __func__, ind);
+ if (ind < SESSION_MAX) {
+ mutex_lock(&session_lock);
+ session[ind] = 0;
+ mutex_unlock(&session_lock);
+ }
+}
+
+int q6usm_us_client_buf_free(unsigned int dir,
+ struct us_client *usc)
+{
+ struct us_port_data *port;
+ int rc = 0;
+ uint32_t size = 0;
+
+ if ((usc == NULL) ||
+ ((dir != IN) && (dir != OUT)))
+ return -EINVAL;
+
+ mutex_lock(&usc->cmd_lock);
+ port = &usc->port[dir];
+ if (port == NULL) {
+ mutex_unlock(&usc->cmd_lock);
+ return -EINVAL;
+ }
+
+ if (port->data == NULL) {
+ mutex_unlock(&usc->cmd_lock);
+ return 0;
+ }
+
+ rc = q6usm_memory_unmap(usc, port->phys, dir);
+ pr_debug("%s: data[%p]phys[%p][%p]\n", __func__,
+ (void *)port->data, (void *)port->phys, (void *)&port->phys);
+ /* 4K boundary is required by the API with QDSP6 */
+ size = (port->buf_size * port->buf_cnt + MEM_4K_OFFSET) & MEM_4K_MASK;
+ dma_free_coherent(NULL, size, port->data, port->phys);
+ port->data = NULL;
+ port->phys = 0;
+ port->buf_size = 0;
+ port->buf_cnt = 0;
+
+ mutex_unlock(&usc->cmd_lock);
+ return rc;
+}
+
+void q6usm_us_client_free(struct us_client *usc)
+{
+ int loopcnt = 0;
+ struct us_port_data *port;
+ uint32_t *p_mem_handle = NULL;
+
+ if ((usc == NULL) ||
+ !(usc->session))
+ return;
+
+ for (loopcnt = 0; loopcnt <= OUT; ++loopcnt) {
+ port = &usc->port[loopcnt];
+ if (port->data == NULL)
+ continue;
+ pr_debug("%s: loopcnt = %d\n", __func__, loopcnt);
+ q6usm_us_client_buf_free(loopcnt, usc);
+ }
+ q6usm_session_free(usc);
+ apr_deregister(usc->apr);
+
+ pr_debug("%s: APR De-Register\n", __func__);
+
+ if (atomic_read(&this_mmap.ref_cnt) <= 0) {
+ pr_err("%s: APR Common Port Already Closed\n", __func__);
+ goto done;
+ }
+
+ atomic_dec(&this_mmap.ref_cnt);
+ if (atomic_read(&this_mmap.ref_cnt) == 0) {
+ apr_deregister(this_mmap.apr);
+ pr_debug("%s: APR De-Register common port\n", __func__);
+ }
+
+done:
+ p_mem_handle = (uint32_t *)usc->port[IN].ext;
+ kfree(p_mem_handle);
+ kfree(usc);
+ pr_debug("%s:\n", __func__);
+ return;
+}
+
+struct us_client *q6usm_us_client_alloc(
+ void (*cb)(uint32_t, uint32_t, uint32_t *, void *),
+ void *priv)
+{
+ struct us_client *usc;
+ uint32_t *p_mem_handle = NULL;
+ int n;
+ int lcnt = 0;
+
+ usc = kzalloc(sizeof(struct us_client), GFP_KERNEL);
+ if (usc == NULL) {
+ pr_err("%s: us_client allocation failed\n", __func__);
+ return NULL;
+ }
+ p_mem_handle = kzalloc(sizeof(uint32_t) * 2, GFP_KERNEL);
+ if (p_mem_handle == NULL) {
+ pr_err("%s: p_mem_handle allocation failed\n", __func__);
+ kfree(usc);
+ return NULL;
+ }
+
+ n = q6usm_session_alloc(usc);
+ if (n <= 0)
+ goto fail_session;
+ usc->session = n;
+ usc->cb = cb;
+ usc->priv = priv;
+ usc->apr = apr_register("ADSP", "USM", \
+ (apr_fn)q6usm_callback,\
+ ((usc->session) << 8 | 0x0001),\
+ usc);
+
+ if (usc->apr == NULL) {
+ pr_err("%s: Registration with APR failed\n", __func__);
+ goto fail;
+ }
+ pr_debug("%s: Registering the common port with APR\n", __func__);
+ if (atomic_read(&this_mmap.ref_cnt) == 0) {
+ this_mmap.apr = apr_register("ADSP", "USM",
+ (apr_fn)q6usm_mmapcallback,
+ 0x0FFFFFFFF, &this_mmap);
+ if (this_mmap.apr == NULL) {
+ pr_err("%s: USM port registration failed\n",
+ __func__);
+ goto fail;
+ }
+ }
+
+ atomic_inc(&this_mmap.ref_cnt);
+ init_waitqueue_head(&usc->cmd_wait);
+ mutex_init(&usc->cmd_lock);
+ for (lcnt = 0; lcnt <= OUT; ++lcnt) {
+ mutex_init(&usc->port[lcnt].lock);
+ spin_lock_init(&usc->port[lcnt].dsp_lock);
+ usc->port[lcnt].ext = (void *)p_mem_handle++;
+ pr_err("%s: usc->port[%d].ext=%p;\n",
+ __func__, lcnt, usc->port[lcnt].ext);
+ }
+ atomic_set(&usc->cmd_state, 0);
+
+ return usc;
+fail:
+ q6usm_us_client_free(usc);
+ return NULL;
+fail_session:
+ kfree(p_mem_handle);
+ kfree(usc);
+ return NULL;
+}
+
+int q6usm_us_client_buf_alloc(unsigned int dir,
+ struct us_client *usc,
+ unsigned int bufsz,
+ unsigned int bufcnt)
+{
+ int rc = 0;
+ struct us_port_data *port = NULL;
+ unsigned int size = bufsz*bufcnt;
+
+ if ((usc == NULL) ||
+ ((dir != IN) && (dir != OUT)) || (size == 0) ||
+ (usc->session <= 0 || usc->session > SESSION_MAX)) {
+ pr_err("%s: wrong parameters: size=%d; bufcnt=%d\n",
+ __func__, size, bufcnt);
+ return -EINVAL;
+ }
+
+ mutex_lock(&usc->cmd_lock);
+
+ port = &usc->port[dir];
+
+ port->data = dma_alloc_coherent(NULL, size, &(port->phys), GFP_KERNEL);
+ if (port->data == NULL) {
+ pr_err("%s: US region allocation failed\n", __func__);
+ mutex_unlock(&usc->cmd_lock);
+ return -ENOMEM;
+ }
+
+ port->buf_cnt = bufcnt;
+ port->buf_size = bufsz;
+ pr_debug("%s: data[%p]; phys[%p]; [%p]\n", __func__,
+ (void *)port->data,
+ (void *)port->phys,
+ (void *)&port->phys);
+
+ size = (size + MEM_4K_OFFSET) & MEM_4K_MASK;
+ rc = q6usm_memory_map(usc, port->phys, dir, size, 1);
+ if (rc < 0) {
+ pr_err("%s: CMD Memory_map failed\n", __func__);
+ mutex_unlock(&usc->cmd_lock);
+ q6usm_us_client_buf_free(dir, usc);
+ } else {
+ mutex_unlock(&usc->cmd_lock);
+ rc = 0;
+ }
+
+ return rc;
+}
+
+static int32_t q6usm_mmapcallback(struct apr_client_data *data, void *priv)
+{
+ uint32_t token;
+ uint32_t *payload = data->payload;
+
+ pr_debug("%s: ptr0[0x%x]; ptr1[0x%x]; opcode[0x%x]\n",
+ __func__, payload[0], payload[1], data->opcode);
+ pr_debug("%s: token[0x%x]; payload_size[%d]; src[%d]; dest[%d];\n",
+ __func__, data->token, data->payload_size,
+ data->src_port, data->dest_port);
+
+ if (data->opcode == APR_BASIC_RSP_RESULT) {
+ /* status field check */
+ if (payload[1]) {
+ pr_err("%s: wrong response[%d] on cmd [%d]\n",
+ __func__, payload[1], payload[0]);
+ } else {
+ token = data->token;
+ switch (payload[0]) {
+ case USM_CMD_SHARED_MEM_UNMAP_REGION:
+ if (atomic_read(&this_mmap.cmd_state)) {
+ atomic_set(&this_mmap.cmd_state, 0);
+ wake_up(&this_mmap.cmd_wait);
+ }
+ case USM_CMD_SHARED_MEM_MAP_REGION:
+ /* For MEM_MAP, additional answer is waited, */
+ /* therfore, no wake-up here */
+ pr_debug("%s: cmd[0x%x]; result[0x%x]\n",
+ __func__, payload[0], payload[1]);
+ break;
+ default:
+ pr_debug("%s: wrong command[0x%x]\n",
+ __func__, payload[0]);
+ break;
+ }
+ }
+ } else {
+ if (data->opcode == USM_CMDRSP_SHARED_MEM_MAP_REGION) {
+ this_mmap.mem_handle = payload[0];
+ pr_debug("%s: memory map handle = 0x%x",
+ __func__, payload[0]);
+ if (atomic_read(&this_mmap.cmd_state)) {
+ atomic_set(&this_mmap.cmd_state, 0);
+ wake_up(&this_mmap.cmd_wait);
+ }
+ }
+ }
+ return 0;
+}
+
+
+static int32_t q6usm_callback(struct apr_client_data *data, void *priv)
+{
+ struct us_client *usc = (struct us_client *)priv;
+ unsigned long dsp_flags;
+ uint32_t *payload = data->payload;
+ uint32_t token = data->token;
+ uint32_t opcode = Q6USM_EVENT_UNDEF;
+
+ if (usc == NULL) {
+ pr_err("%s: client info is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ if (data->opcode == APR_BASIC_RSP_RESULT) {
+ /* status field check */
+ if (payload[1]) {
+ pr_err("%s: wrong response[%d] on cmd [%d]\n",
+ __func__, payload[1], payload[0]);
+ if (usc->cb)
+ usc->cb(data->opcode, token,
+ (uint32_t *)data->payload, usc->priv);
+ } else {
+ switch (payload[0]) {
+ case USM_SESSION_CMD_RUN:
+ case USM_STREAM_CMD_CLOSE:
+ if (token != usc->session) {
+ pr_err("%s: wrong token[%d]",
+ __func__, token);
+ break;
+ }
+ case USM_STREAM_CMD_OPEN_READ:
+ case USM_STREAM_CMD_OPEN_WRITE:
+ case USM_STREAM_CMD_SET_ENC_PARAM:
+ case USM_DATA_CMD_MEDIA_FORMAT_UPDATE:
+ case USM_SESSION_CMD_SIGNAL_DETECT_MODE:
+ if (atomic_read(&usc->cmd_state)) {
+ atomic_set(&usc->cmd_state, 0);
+ wake_up(&usc->cmd_wait);
+ }
+ if (usc->cb)
+ usc->cb(data->opcode, token,
+ (uint32_t *)data->payload,
+ usc->priv);
+ break;
+ default:
+ break;
+ }
+ }
+ return 0;
+ }
+
+ switch (data->opcode) {
+ case USM_DATA_EVENT_READ_DONE: {
+ struct us_port_data *port = &usc->port[OUT];
+
+ opcode = Q6USM_EVENT_READ_DONE;
+ spin_lock_irqsave(&port->dsp_lock, dsp_flags);
+ if (payload[READDONE_IDX_STATUS]) {
+ pr_err("%s: wrong READDONE[%d]; token[%d]\n",
+ __func__,
+ payload[READDONE_IDX_STATUS],
+ token);
+ token = USM_WRONG_TOKEN;
+ spin_unlock_irqrestore(&port->dsp_lock,
+ dsp_flags);
+ break;
+ }
+
+ if (port->expected_token != token) {
+ u32 cpu_buf = port->cpu_buf;
+ pr_err("%s: expected[%d] != token[%d]\n",
+ __func__, port->expected_token, token);
+ pr_debug("%s: dsp_buf=%d; cpu_buf=%d;\n",
+ __func__, port->dsp_buf, cpu_buf);
+
+ token = USM_WRONG_TOKEN;
+ /* To prevent data handle continiue */
+ port->expected_token = USM_WRONG_TOKEN;
+ spin_unlock_irqrestore(&port->dsp_lock,
+ dsp_flags);
+ break;
+ } /* port->expected_token != data->token */
+
+ port->expected_token = token + 1;
+ if (port->expected_token == port->buf_cnt)
+ port->expected_token = 0;
+
+ /* gap support */
+ if (port->expected_token != port->cpu_buf) {
+ port->dsp_buf = port->expected_token;
+ token = port->dsp_buf; /* for callback */
+ } else
+ port->dsp_buf = token;
+
+ spin_unlock_irqrestore(&port->dsp_lock, dsp_flags);
+ break;
+ } /* case USM_DATA_EVENT_READ_DONE */
+
+ case USM_DATA_EVENT_WRITE_DONE: {
+ struct us_port_data *port = &usc->port[IN];
+
+ opcode = Q6USM_EVENT_WRITE_DONE;
+ if (payload[WRITEDONE_IDX_STATUS]) {
+ pr_err("%s: wrong WRITEDONE_IDX_STATUS[%d]\n",
+ __func__,
+ payload[WRITEDONE_IDX_STATUS]);
+ break;
+ }
+
+ spin_lock_irqsave(&port->dsp_lock, dsp_flags);
+ port->dsp_buf = token + 1;
+ if (port->dsp_buf == port->buf_cnt)
+ port->dsp_buf = 0;
+ spin_unlock_irqrestore(&port->dsp_lock, dsp_flags);
+
+ break;
+ } /* case USM_DATA_EVENT_WRITE_DONE */
+
+ case USM_SESSION_EVENT_SIGNAL_DETECT_RESULT: {
+ pr_debug("%s: US detect result: result=%d",
+ __func__,
+ payload[0]);
+ opcode = Q6USM_EVENT_SIGNAL_DETECT_RESULT;
+
+ break;
+ } /* case USM_SESSION_EVENT_SIGNAL_DETECT_RESULT */
+
+ default:
+ return 0;
+
+ } /* switch */
+
+ if (usc->cb)
+ usc->cb(opcode, token,
+ data->payload, usc->priv);
+
+ return 0;
+}
+
+uint32_t q6usm_get_virtual_address(int dir,
+ struct us_client *usc,
+ struct vm_area_struct *vms)
+{
+ uint32_t ret = 0xffffffff;
+
+ if (vms && (usc != NULL) && ((dir == IN) || (dir == OUT))) {
+ struct us_port_data *port = &usc->port[dir];
+ int size = (port->buf_size * port->buf_cnt + MEM_4K_OFFSET)
+ & MEM_4K_MASK;
+
+ ret = dma_mmap_coherent(NULL, vms,
+ port->data, port->phys,
+ size);
+ }
+ return ret;
+}
+
+static void q6usm_add_hdr(struct us_client *usc, struct apr_hdr *hdr,
+ uint32_t pkt_size, bool cmd_flg)
+{
+ mutex_lock(&usc->cmd_lock);
+ hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, \
+ APR_HDR_LEN(sizeof(struct apr_hdr)),\
+ APR_PKT_VER);
+ hdr->src_svc = ((struct apr_svc *)usc->apr)->id;
+ hdr->src_domain = APR_DOMAIN_APPS;
+ hdr->dest_svc = APR_SVC_USM;
+ hdr->dest_domain = APR_DOMAIN_ADSP;
+ hdr->src_port = (usc->session << 8) | 0x0001;
+ hdr->dest_port = (usc->session << 8) | 0x0001;
+ if (cmd_flg) {
+ hdr->token = usc->session;
+ atomic_set(&usc->cmd_state, 1);
+ }
+ hdr->pkt_size = APR_PKT_SIZE(APR_HDR_SIZE, pkt_size);
+ mutex_unlock(&usc->cmd_lock);
+ return;
+}
+
+static uint32_t q6usm_ext2int_format(uint32_t ext_format)
+{
+ uint32_t int_format = INVALID_FORMAT;
+ switch (ext_format) {
+ case FORMAT_USPS_EPOS:
+ int_format = US_POINT_EPOS_FORMAT;
+ break;
+ case FORMAT_USRAW:
+ int_format = US_RAW_FORMAT;
+ break;
+ case FORMAT_USPROX:
+ int_format = US_PROX_FORMAT;
+ break;
+ default:
+ pr_err("%s: Invalid format[%d]\n", __func__, ext_format);
+ break;
+ }
+
+ return int_format;
+}
+
+int q6usm_open_read(struct us_client *usc,
+ uint32_t format)
+{
+ uint32_t int_format = INVALID_FORMAT;
+ int rc = 0x00;
+ struct usm_stream_cmd_open_read open;
+
+ pr_debug("%s: session[%d]", __func__, usc->session);
+
+ if ((usc == NULL) || (usc->apr == NULL)) {
+ pr_err("%s: client or its apr is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ q6usm_add_hdr(usc, &open.hdr, sizeof(open), true);
+ open.hdr.opcode = USM_STREAM_CMD_OPEN_READ;
+ open.src_endpoint = 0; /* AFE */
+ open.pre_proc_top = 0; /* No preprocessing required */
+
+ int_format = q6usm_ext2int_format(format);
+ if (int_format == INVALID_FORMAT)
+ return -EINVAL;
+
+ open.uMode = STREAM_PRIORITY_NORMAL;
+ open.format = int_format;
+
+ rc = apr_send_pkt(usc->apr, (uint32_t *) &open);
+ if (rc < 0) {
+ pr_err("%s: open failed op[0x%x]rc[%d]\n",
+ __func__, open.hdr.opcode, rc);
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(usc->cmd_wait,
+ (atomic_read(&usc->cmd_state) == 0),
+ Q6USM_TIMEOUT_JIFFIES);
+ if (!rc) {
+ rc = -ETIME;
+ pr_err("%s: timeout, waited for OPEN_READ rc[%d]\n",
+ __func__, rc);
+ goto fail_cmd;
+ } else
+ rc = 0;
+fail_cmd:
+ return rc;
+}
+
+
+int q6usm_enc_cfg_blk(struct us_client *usc, struct us_encdec_cfg *us_cfg)
+{
+ uint32_t int_format = INVALID_FORMAT;
+ struct usm_stream_cmd_encdec_cfg_blk enc_cfg_obj;
+ struct usm_stream_cmd_encdec_cfg_blk *enc_cfg = &enc_cfg_obj;
+ int rc = 0;
+ uint32_t total_cfg_size =
+ sizeof(struct usm_stream_cmd_encdec_cfg_blk);
+ uint32_t round_params_size = 0;
+ uint8_t is_allocated = 0;
+
+
+ if ((usc == NULL) || (us_cfg == NULL)) {
+ pr_err("%s: wrong input", __func__);
+ return -EINVAL;
+ }
+
+ int_format = q6usm_ext2int_format(us_cfg->format_id);
+ if (int_format == INVALID_FORMAT) {
+ pr_err("%s: wrong input format[%d]",
+ __func__, us_cfg->format_id);
+ return -EINVAL;
+ }
+
+ /* Transparent configuration data is after enc_cfg */
+ /* Integer number of u32s is requred */
+ round_params_size = ((us_cfg->params_size + 3)/4) * 4;
+ if (round_params_size > USM_MAX_CFG_DATA_SIZE) {
+ /* Dynamic allocated encdec_cfg_blk is required */
+ /* static part use */
+ round_params_size -= USM_MAX_CFG_DATA_SIZE;
+ total_cfg_size += round_params_size;
+ enc_cfg = kzalloc(total_cfg_size, GFP_KERNEL);
+ if (enc_cfg == NULL) {
+ pr_err("%s: enc_cfg[%d] allocation failed\n",
+ __func__, total_cfg_size);
+ return -ENOMEM;
+ }
+ is_allocated = 1;
+ } else
+ round_params_size = 0;
+
+ q6usm_add_hdr(usc, &enc_cfg->hdr, total_cfg_size - APR_HDR_SIZE, true);
+
+ enc_cfg->hdr.opcode = USM_STREAM_CMD_SET_ENC_PARAM;
+ enc_cfg->param_id = USM_PARAM_ID_ENCDEC_ENC_CFG_BLK;
+ enc_cfg->param_size = sizeof(struct usm_encode_cfg_blk)+
+ round_params_size;
+ enc_cfg->enc_blk.frames_per_buf = 1;
+ enc_cfg->enc_blk.format_id = int_format;
+ enc_cfg->enc_blk.cfg_size = sizeof(struct usm_cfg_common)+
+ USM_MAX_CFG_DATA_SIZE +
+ round_params_size;
+ memcpy(&(enc_cfg->enc_blk.cfg_common), &(us_cfg->cfg_common),
+ sizeof(struct usm_cfg_common));
+
+ /* Transparent data copy */
+ memcpy(enc_cfg->enc_blk.transp_data, us_cfg->params,
+ us_cfg->params_size);
+ pr_debug("%s: cfg_size[%d], params_size[%d]\n",
+ __func__,
+ enc_cfg->enc_blk.cfg_size,
+ us_cfg->params_size);
+ pr_debug("%s: params[%d,%d,%d,%d, %d,%d,%d,%d]\n",
+ __func__,
+ enc_cfg->enc_blk.transp_data[0],
+ enc_cfg->enc_blk.transp_data[1],
+ enc_cfg->enc_blk.transp_data[2],
+ enc_cfg->enc_blk.transp_data[3],
+ enc_cfg->enc_blk.transp_data[4],
+ enc_cfg->enc_blk.transp_data[5],
+ enc_cfg->enc_blk.transp_data[6],
+ enc_cfg->enc_blk.transp_data[7]
+ );
+ pr_debug("%s: srate:%d, ch=%d, bps= %d; dmap:0x%x; dev_id=0x%x\n",
+ __func__, enc_cfg->enc_blk.cfg_common.sample_rate,
+ enc_cfg->enc_blk.cfg_common.ch_cfg,
+ enc_cfg->enc_blk.cfg_common.bits_per_sample,
+ enc_cfg->enc_blk.cfg_common.data_map,
+ enc_cfg->enc_blk.cfg_common.dev_id);
+
+ rc = apr_send_pkt(usc->apr, (uint32_t *) enc_cfg);
+ if (rc < 0) {
+ pr_err("%s:Comamnd open failed\n", __func__);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(usc->cmd_wait,
+ (atomic_read(&usc->cmd_state) == 0),
+ Q6USM_TIMEOUT_JIFFIES);
+ if (!rc) {
+ rc = -ETIME;
+ pr_err("%s: timeout opcode[0x%x]\n",
+ __func__, enc_cfg->hdr.opcode);
+ } else
+ rc = 0;
+
+fail_cmd:
+ if (is_allocated == 1)
+ kfree(enc_cfg);
+
+ return rc;
+}
+
+int q6usm_dec_cfg_blk(struct us_client *usc, struct us_encdec_cfg *us_cfg)
+{
+
+ uint32_t int_format = INVALID_FORMAT;
+ struct usm_stream_media_format_update dec_cfg_obj;
+ struct usm_stream_media_format_update *dec_cfg = &dec_cfg_obj;
+
+ int rc = 0;
+ uint32_t total_cfg_size = sizeof(struct usm_stream_media_format_update);
+ uint32_t round_params_size = 0;
+ uint8_t is_allocated = 0;
+
+
+ if ((usc == NULL) || (us_cfg == NULL)) {
+ pr_err("%s: wrong input", __func__);
+ return -EINVAL;
+ }
+
+ int_format = q6usm_ext2int_format(us_cfg->format_id);
+ if (int_format == INVALID_FORMAT) {
+ pr_err("%s: wrong input format[%d]",
+ __func__, us_cfg->format_id);
+ return -EINVAL;
+ }
+
+ /* Transparent configuration data is after enc_cfg */
+ /* Integer number of u32s is requred */
+ round_params_size = ((us_cfg->params_size + 3)/4) * 4;
+ if (round_params_size > USM_MAX_CFG_DATA_SIZE) {
+ /* Dynamic allocated encdec_cfg_blk is required */
+ /* static part use */
+ round_params_size -= USM_MAX_CFG_DATA_SIZE;
+ total_cfg_size += round_params_size;
+ dec_cfg = kzalloc(total_cfg_size, GFP_KERNEL);
+ if (dec_cfg == NULL) {
+ pr_err("%s:dec_cfg[%d] allocation failed\n",
+ __func__, total_cfg_size);
+ return -ENOMEM;
+ }
+ is_allocated = 1;
+ } else { /* static transp_data is enough */
+ round_params_size = 0;
+ }
+
+ q6usm_add_hdr(usc, &dec_cfg->hdr, total_cfg_size - APR_HDR_SIZE, true);
+
+ dec_cfg->hdr.opcode = USM_DATA_CMD_MEDIA_FORMAT_UPDATE;
+ dec_cfg->format_id = int_format;
+ dec_cfg->cfg_size = sizeof(struct usm_cfg_common) +
+ USM_MAX_CFG_DATA_SIZE +
+ round_params_size;
+ memcpy(&(dec_cfg->cfg_common), &(us_cfg->cfg_common),
+ sizeof(struct usm_cfg_common));
+ /* Transparent data copy */
+ memcpy(dec_cfg->transp_data, us_cfg->params, us_cfg->params_size);
+ pr_debug("%s: cfg_size[%d], params_size[%d]; parambytes[%d,%d,%d,%d]\n",
+ __func__,
+ dec_cfg->cfg_size,
+ us_cfg->params_size,
+ dec_cfg->transp_data[0],
+ dec_cfg->transp_data[1],
+ dec_cfg->transp_data[2],
+ dec_cfg->transp_data[3]
+ );
+
+ rc = apr_send_pkt(usc->apr, (uint32_t *) dec_cfg);
+ if (rc < 0) {
+ pr_err("%s:Comamnd open failed\n", __func__);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(usc->cmd_wait,
+ (atomic_read(&usc->cmd_state) == 0),
+ Q6USM_TIMEOUT_JIFFIES);
+ if (!rc) {
+ rc = -ETIME;
+ pr_err("%s: timeout opcode[0x%x]\n",
+ __func__, dec_cfg->hdr.opcode);
+ } else
+ rc = 0;
+
+fail_cmd:
+ if (is_allocated == 1)
+ kfree(dec_cfg);
+
+ return rc;
+}
+
+int q6usm_open_write(struct us_client *usc,
+ uint32_t format)
+{
+ int rc = 0;
+ uint32_t int_format = INVALID_FORMAT;
+ struct usm_stream_cmd_open_write open;
+
+ pr_debug("%s: session[%d]", __func__, usc->session);
+
+ if ((usc == NULL) || (usc->apr == NULL)) {
+ pr_err("%s: APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ q6usm_add_hdr(usc, &open.hdr, sizeof(open), true);
+ open.hdr.opcode = USM_STREAM_CMD_OPEN_WRITE;
+
+ int_format = q6usm_ext2int_format(format);
+ if (int_format == INVALID_FORMAT) {
+ pr_err("%s: wrong format[%d]", __func__, format);
+ return -EINVAL;
+ }
+
+ open.format = int_format;
+
+ rc = apr_send_pkt(usc->apr, (uint32_t *) &open);
+ if (rc < 0) {
+ pr_err("%s:open failed op[0x%x]rc[%d]\n", \
+ __func__, open.hdr.opcode, rc);
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(usc->cmd_wait,
+ (atomic_read(&usc->cmd_state) == 0),
+ Q6USM_TIMEOUT_JIFFIES);
+ if (!rc) {
+ rc = -ETIME;
+ pr_err("%s:timeout. waited for OPEN_WRITR rc[%d]\n",
+ __func__, rc);
+ goto fail_cmd;
+ } else
+ rc = 0;
+
+fail_cmd:
+ return rc;
+}
+
+int q6usm_run(struct us_client *usc, uint32_t flags,
+ uint32_t msw_ts, uint32_t lsw_ts)
+{
+ struct usm_stream_cmd_run run;
+ int rc = 0;
+
+ if ((usc == NULL) || (usc->apr == NULL)) {
+ pr_err("%s: APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+ q6usm_add_hdr(usc, &run.hdr, sizeof(run), true);
+
+ run.hdr.opcode = USM_SESSION_CMD_RUN;
+ run.flags = flags;
+ run.msw_ts = msw_ts;
+ run.lsw_ts = lsw_ts;
+
+ rc = apr_send_pkt(usc->apr, (uint32_t *) &run);
+ if (rc < 0) {
+ pr_err("%s: Commmand run failed[%d]\n", __func__, rc);
+ goto fail_cmd;
+ }
+
+ rc = wait_event_timeout(usc->cmd_wait,
+ (atomic_read(&usc->cmd_state) == 0),
+ Q6USM_TIMEOUT_JIFFIES);
+ if (!rc) {
+ rc = -ETIME;
+ pr_err("%s: timeout. waited for run success rc[%d]\n",
+ __func__, rc);
+ } else
+ rc = 0;
+
+fail_cmd:
+ return rc;
+}
+
+
+
+int q6usm_read(struct us_client *usc, uint32_t read_ind)
+{
+ struct usm_stream_cmd_read read;
+ struct us_port_data *port = NULL;
+ int rc = 0;
+ u32 read_counter = 0;
+ u32 loop_ind = 0;
+
+ if ((usc == NULL) || (usc->apr == NULL)) {
+ pr_err("%s: APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+ port = &usc->port[OUT];
+
+ if (read_ind > port->buf_cnt) {
+ pr_err("%s: wrong read_ind[%d]\n",
+ __func__, read_ind);
+ return -EINVAL;
+ }
+ if (read_ind == port->cpu_buf) {
+ pr_err("%s: no free region\n", __func__);
+ return 0;
+ }
+
+ if (read_ind > port->cpu_buf) { /* 1 range */
+ read_counter = read_ind - port->cpu_buf;
+ } else { /* 2 ranges */
+ read_counter = (port->buf_cnt - port->cpu_buf) + read_ind;
+ }
+
+ q6usm_add_hdr(usc, &read.hdr, (sizeof(read) - APR_HDR_SIZE), false);
+
+ read.hdr.opcode = USM_DATA_CMD_READ;
+ read.buf_size = port->buf_size;
+ read.buf_addr_msw = 0;
+ read.mem_map_handle = *((uint32_t *)(port->ext));
+
+ for (loop_ind = 0; loop_ind < read_counter; ++loop_ind) {
+ u32 temp_cpu_buf = port->cpu_buf;
+
+ read.buf_addr_lsw = (uint32_t)(port->phys) +
+ port->buf_size * (port->cpu_buf);
+ read.seq_id = port->cpu_buf;
+ read.hdr.token = port->cpu_buf;
+ read.counter = 1;
+
+ ++(port->cpu_buf);
+ if (port->cpu_buf == port->buf_cnt)
+ port->cpu_buf = 0;
+
+ rc = apr_send_pkt(usc->apr, (uint32_t *) &read);
+
+ if (rc < 0) {
+ port->cpu_buf = temp_cpu_buf;
+
+ pr_err("%s:read op[0x%x]rc[%d]\n",
+ __func__, read.hdr.opcode, rc);
+ break;
+ } else
+ rc = 0;
+ } /* bufs loop */
+
+ return rc;
+}
+
+int q6usm_write(struct us_client *usc, uint32_t write_ind)
+{
+ int rc = 0;
+ struct usm_stream_cmd_write cmd_write;
+ struct us_port_data *port = NULL;
+ u32 current_dsp_buf = 0;
+
+ if ((usc == NULL) || (usc->apr == NULL)) {
+ pr_err("%s: APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+ port = &usc->port[IN];
+
+ current_dsp_buf = port->dsp_buf;
+ /* free region, caused by new dsp_buf report from DSP, */
+ /* can be only extended */
+ if (port->cpu_buf >= current_dsp_buf) {
+ /* 2 -part free region, including empty buffer */
+ if ((write_ind <= port->cpu_buf) &&
+ (write_ind > current_dsp_buf)) {
+ pr_err("%s: wrong w_ind[%d]; d_buf=%d; c_buf=%d\n",
+ __func__, write_ind,
+ current_dsp_buf, port->cpu_buf);
+ return -EINVAL;
+ }
+ } else {
+ /* 1 -part free region */
+ if ((write_ind <= port->cpu_buf) ||
+ (write_ind > current_dsp_buf)) {
+ pr_err("%s: wrong w_ind[%d]; d_buf=%d; c_buf=%d\n",
+ __func__, write_ind,
+ current_dsp_buf, port->cpu_buf);
+ return -EINVAL;
+ }
+ }
+
+ q6usm_add_hdr(usc, &cmd_write.hdr,
+ (sizeof(cmd_write) - APR_HDR_SIZE), false);
+
+ cmd_write.hdr.opcode = USM_DATA_CMD_WRITE;
+ cmd_write.buf_size = port->buf_size;
+ cmd_write.buf_addr_msw = 0;
+ cmd_write.mem_map_handle = *((uint32_t *)(port->ext));
+ cmd_write.res0 = 0;
+ cmd_write.res1 = 0;
+ cmd_write.res2 = 0;
+
+ while (port->cpu_buf != write_ind) {
+ u32 temp_cpu_buf = port->cpu_buf;
+
+ cmd_write.buf_addr_lsw = (uint32_t)(port->phys) +
+ port->buf_size * (port->cpu_buf);
+ cmd_write.seq_id = port->cpu_buf;
+ cmd_write.hdr.token = port->cpu_buf;
+
+ ++(port->cpu_buf);
+ if (port->cpu_buf == port->buf_cnt)
+ port->cpu_buf = 0;
+
+ rc = apr_send_pkt(usc->apr, (uint32_t *) &cmd_write);
+
+ if (rc < 0) {
+ port->cpu_buf = temp_cpu_buf;
+ pr_err("%s:write op[0x%x];rc[%d];cpu_buf[%d]\n",
+ __func__, cmd_write.hdr.opcode,
+ rc, port->cpu_buf);
+ break;
+ }
+
+ rc = 0;
+ }
+
+ return rc;
+}
+
+bool q6usm_is_write_buf_full(struct us_client *usc, uint32_t *free_region)
+{
+ struct us_port_data *port = NULL;
+ u32 cpu_buf = 0;
+
+ if ((usc == NULL) || !free_region) {
+ pr_err("%s: input data wrong\n", __func__);
+ return false;
+ }
+ port = &usc->port[IN];
+ cpu_buf = port->cpu_buf + 1;
+ if (cpu_buf == port->buf_cnt)
+ cpu_buf = 0;
+
+ *free_region = port->dsp_buf;
+
+ return cpu_buf == *free_region;
+}
+
+int q6usm_cmd(struct us_client *usc, int cmd)
+{
+ struct apr_hdr hdr;
+ int rc = 0;
+ atomic_t *state;
+
+ if ((usc == NULL) || (usc->apr == NULL)) {
+ pr_err("%s: APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+ q6usm_add_hdr(usc, &hdr, (sizeof(hdr) - APR_HDR_SIZE), true);
+ switch (cmd) {
+ case CMD_CLOSE:
+ hdr.opcode = USM_STREAM_CMD_CLOSE;
+ state = &usc->cmd_state;
+ break;
+
+ default:
+ pr_err("%s:Invalid format[%d]\n", __func__, cmd);
+ goto fail_cmd;
+ }
+
+ rc = apr_send_pkt(usc->apr, (uint32_t *) &hdr);
+ if (rc < 0) {
+ pr_err("%s: Command 0x%x failed\n", __func__, hdr.opcode);
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(usc->cmd_wait, (atomic_read(state) == 0),
+ Q6USM_TIMEOUT_JIFFIES);
+ if (!rc) {
+ rc = -ETIME;
+ pr_err("%s:timeout. waited for response opcode[0x%x]\n",
+ __func__, hdr.opcode);
+ } else
+ rc = 0;
+fail_cmd:
+ return rc;
+}
+
+int q6usm_set_us_detection(struct us_client *usc,
+ struct usm_session_cmd_detect_info *detect_info,
+ uint16_t detect_info_size)
+{
+ int rc = 0;
+
+ if ((usc == NULL) ||
+ (detect_info_size == 0) ||
+ (detect_info == NULL)) {
+ pr_err("%s: wrong input: usc=0x%p, inf_size=%d; info=0x%p",
+ __func__,
+ usc,
+ detect_info_size,
+ detect_info);
+ return -EINVAL;
+ }
+
+ q6usm_add_hdr(usc, &detect_info->hdr,
+ detect_info_size - APR_HDR_SIZE, true);
+
+ detect_info->hdr.opcode = USM_SESSION_CMD_SIGNAL_DETECT_MODE;
+
+ rc = apr_send_pkt(usc->apr, (uint32_t *)detect_info);
+ if (rc < 0) {
+ pr_err("%s:Comamnd signal detect failed\n", __func__);
+ return -EINVAL;
+ }
+ rc = wait_event_timeout(usc->cmd_wait,
+ (atomic_read(&usc->cmd_state) == 0),
+ Q6USM_TIMEOUT_JIFFIES);
+ if (!rc) {
+ rc = -ETIME;
+ pr_err("%s: CMD_SIGNAL_DETECT_MODE: timeout=%d\n",
+ __func__, Q6USM_TIMEOUT_JIFFIES);
+ } else
+ rc = 0;
+
+ return rc;
+}
+
+static int __init q6usm_init(void)
+{
+ pr_debug("%s\n", __func__);
+ init_waitqueue_head(&this_mmap.cmd_wait);
+ memset(session, 0, sizeof(session));
+ return 0;
+}
+
+device_initcall(q6usm_init);
diff --git a/arch/arm/mach-msm/rpm_resources.c b/arch/arm/mach-msm/rpm_resources.c
index 43073d3..78c5ae0 100644
--- a/arch/arm/mach-msm/rpm_resources.c
+++ b/arch/arm/mach-msm/rpm_resources.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -21,6 +21,7 @@
#include <linux/spinlock.h>
#include <linux/cpu.h>
#include <linux/hrtimer.h>
+#include <linux/platform_device.h>
#include <mach/rpm.h>
#include <mach/msm_iomap.h>
#include <asm/mach-types.h>
@@ -71,6 +72,10 @@
static int vdd_mem_vlevels[MSM_RPMRS_VDD_MEM_LAST];
static int vdd_mask;
+static DEFINE_PER_CPU(uint32_t , msm_lpm_sleep_time);
+static DEFINE_PER_CPU(int , lpm_permitted_level);
+static DEFINE_PER_CPU(struct atomic_notifier_head, lpm_notify_head);
+
#define MSM_RPMRS_MAX_RS_REGISTER_COUNT 2
#define RPMRS_ATTR(_name) \
@@ -869,6 +874,13 @@
spin_unlock_irqrestore(&msm_rpmrs_lock, flags);
}
+static bool lpm_level_permitted(int cur_level_count)
+{
+ if (__get_cpu_var(lpm_permitted_level) == msm_rpmrs_level_count + 1)
+ return true;
+ return (__get_cpu_var(lpm_permitted_level) == cur_level_count);
+}
+
s32 msm_cpuidle_get_deep_idle_latency(void)
{
int i;
@@ -904,6 +916,7 @@
uint32_t pwr;
uint32_t next_wakeup_us = time_param->sleep_us;
bool modify_event_timer;
+ int best_level_iter = msm_rpmrs_level_count + 1;
if (sleep_mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE) {
irqs_detectable = msm_mpm_irqs_detectable(from_idle);
@@ -968,6 +981,7 @@
level->rs_limits.latency_us[cpu] = level->latency_us;
level->rs_limits.power[cpu] = pwr;
best_level = level;
+ best_level_iter = i;
if (power)
*power = pwr;
if (modify_event_timer && best_level->latency_us > 1)
@@ -978,6 +992,12 @@
time_param->modified_time_us = 0;
}
}
+ if (best_level && !lpm_level_permitted(best_level_iter))
+ best_level = NULL;
+ else
+ per_cpu(msm_lpm_sleep_time, cpu) =
+ time_param->modified_time_us ?
+ time_param->modified_time_us : time_param->sleep_us;
return best_level ? &best_level->rs_limits : NULL;
}
@@ -986,6 +1006,12 @@
bool from_idle, bool notify_rpm)
{
int rc = 0;
+ struct msm_lpm_sleep_data sleep_data;
+
+ sleep_data.limits = limits;
+ sleep_data.kernel_sleep = __get_cpu_var(msm_lpm_sleep_time);
+ atomic_notifier_call_chain(&__get_cpu_var(lpm_notify_head),
+ MSM_LPM_STATE_ENTER, &sleep_data);
if (notify_rpm) {
rc = msm_rpmrs_flush_buffer(sclk_count, limits, from_idle);
@@ -1009,6 +1035,9 @@
if (msm_rpmrs_use_mpm(limits))
msm_mpm_exit_sleep(from_idle);
+
+ atomic_notifier_call_chain(&__get_cpu_var(lpm_notify_head),
+ MSM_LPM_STATE_EXIT, NULL);
}
static int rpmrs_cpu_callback(struct notifier_block *nfb,
@@ -1033,6 +1062,16 @@
return NOTIFY_OK;
}
+static struct lpm_test_platform_data lpm_test_pdata;
+
+static struct platform_device msm_lpm_test_device = {
+ .name = "lpm_test",
+ .id = -1,
+ .dev = {
+ .platform_data = &lpm_test_pdata,
+ },
+};
+
static struct notifier_block __refdata rpmrs_cpu_notifier = {
.notifier_call = rpmrs_cpu_callback,
};
@@ -1041,6 +1080,7 @@
{
int i, k;
struct msm_rpmrs_level *levels = data->levels;
+ unsigned int m_cpu = 0;
msm_rpmrs_level_count = data->num_levels;
@@ -1052,6 +1092,16 @@
memcpy(msm_rpmrs_levels, levels,
msm_rpmrs_level_count * sizeof(struct msm_rpmrs_level));
+ lpm_test_pdata.use_qtimer = 0;
+ lpm_test_pdata.msm_lpm_test_levels = msm_rpmrs_levels,
+ lpm_test_pdata.msm_lpm_test_level_count = msm_rpmrs_level_count;
+
+ for_each_possible_cpu(m_cpu)
+ per_cpu(lpm_permitted_level, m_cpu) =
+ msm_rpmrs_level_count + 1;
+
+ platform_device_register(&msm_lpm_test_device);
+
memcpy(vdd_dig_vlevels, data->vdd_dig_levels,
(MSM_RPMRS_VDD_DIG_MAX + 1) * sizeof(vdd_dig_vlevels[0]));
@@ -1087,6 +1137,41 @@
return 0;
}
+uint32_t msm_pm_get_pxo(struct msm_rpmrs_limits *limits)
+{
+ return limits->pxo;
+}
+
+uint32_t msm_pm_get_l2_cache(struct msm_rpmrs_limits *limits)
+{
+ return limits->l2_cache;
+}
+
+uint32_t msm_pm_get_vdd_mem(struct msm_rpmrs_limits *limits)
+{
+ return limits->vdd_mem;
+}
+
+uint32_t msm_pm_get_vdd_dig(struct msm_rpmrs_limits *limits)
+{
+ return limits->vdd_dig;
+}
+
+int msm_lpm_register_notifier(int cpu, int level_iter,
+ struct notifier_block *nb, bool is_latency_measure)
+{
+ per_cpu(lpm_permitted_level, cpu) = level_iter;
+ return atomic_notifier_chain_register(&per_cpu(lpm_notify_head,
+ cpu), nb);
+}
+
+int msm_lpm_unregister_notifier(int cpu, struct notifier_block *nb)
+{
+ per_cpu(lpm_permitted_level, cpu) = msm_rpmrs_level_count + 1;
+ return atomic_notifier_chain_unregister(&per_cpu(lpm_notify_head, cpu),
+ nb);
+}
+
static int __init msm_rpmrs_init(void)
{
struct msm_rpm_iv_pair req;
diff --git a/arch/arm/mach-msm/rpm_resources.h b/arch/arm/mach-msm/rpm_resources.h
index 46d6d94..0a180fb 100644
--- a/arch/arm/mach-msm/rpm_resources.h
+++ b/arch/arm/mach-msm/rpm_resources.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -15,7 +15,9 @@
#define __ARCH_ARM_MACH_MSM_RPM_RESOURCES_H
#include <mach/rpm.h>
+#include <linux/notifier.h>
#include "pm.h"
+#include "test-lpm.h"
enum {
MSM_RPMRS_ID_PXO_CLK = 0,
@@ -102,6 +104,94 @@
unsigned int rpmrs_target_id[MSM_RPMRS_ID_LAST];
};
+enum {
+ MSM_LPM_STATE_ENTER = 0,
+ MSM_LPM_STATE_EXIT = 1,
+};
+
+/**
+ * struct msm_lpm_sleep_data - abstraction to get sleep data
+ * @limits: pointer to the msm_rpmrs_limits structure
+ * @kernel_sleep: kernel sleep time as decided by the power calculation
+ * algorithm
+ *
+ * This structure is an abstraction to get the limits and kernel sleep time
+ * during enter sleep.
+ */
+
+struct msm_lpm_sleep_data {
+ struct msm_rpmrs_limits *limits;
+ uint32_t kernel_sleep;
+};
+
+#define MSM_PM(field) MSM_RPMRS_##field
+
+/**
+ * msm_pm_get_pxo() - get the limits for pxo
+ * @limits: pointer to the msm_rpmrs_limits structure
+ *
+ * This function gets the limits to the resource pxo on
+ * 8960
+ */
+
+uint32_t msm_pm_get_pxo(struct msm_rpmrs_limits *limits);
+
+/**
+ * msm_pm_get_l2_cache() - get the limits for l2 cache
+ * @limits: pointer to the msm_rpmrs_limits structure
+ *
+ * This function gets the limits to the resource l2 cache
+ * on 8960
+ */
+
+uint32_t msm_pm_get_l2_cache(struct msm_rpmrs_limits *limits);
+
+/**
+ * msm_pm_get_vdd_mem() - get the limits for pxo
+ * @limits: pointer to the msm_rpmrs_limits structure
+ *
+ * This function gets the limits to the resource vdd mem
+ * on 8960
+ */
+
+uint32_t msm_pm_get_vdd_mem(struct msm_rpmrs_limits *limits);
+
+/**
+ * msm_pm_get_vdd_dig() - get the limits for vdd dig
+ * @limits: pointer to the msm_rpmrs_limits structure
+ *
+ * This function gets the limits to the resource vdd dig
+ * on 8960
+ */
+
+uint32_t msm_pm_get_vdd_dig(struct msm_rpmrs_limits *limits);
+
+/**
+ * msm_lpm_register_notifier() - register for notifications
+ * @cpu: cpu to debug
+ * @level_iter: low power level index to debug
+ * @nb: notifier block to callback on notifications
+ * @is_latency_measure: is it latency measure
+ *
+ * This function sets the permitted level to the index of the
+ * level under test and registers notifier for callback.
+ */
+
+int msm_lpm_register_notifier(int cpu, int level_iter,
+ struct notifier_block *nb, bool is_latency_measure);
+
+/**
+ * msm_lpm_unregister_notifier() - unregister from notifications
+ * @cpu: cpu to debug
+ * @nb: notifier block to callback on notifications
+ *
+ * This function sets the permitted level to a value one more than
+ * available levels count which indicates that all levels are
+ * permitted and it also unregisters notifier for callback.
+ */
+
+int msm_lpm_unregister_notifier(int cpu, struct notifier_block *nb);
+
#if defined(CONFIG_MSM_RPM)
int msm_rpmrs_set(int ctx, struct msm_rpm_iv_pair *req, int count);
diff --git a/arch/arm/mach-msm/sdio_al_dloader.c b/arch/arm/mach-msm/sdio_al_dloader.c
index f48c32b..b0cb88f 100644
--- a/arch/arm/mach-msm/sdio_al_dloader.c
+++ b/arch/arm/mach-msm/sdio_al_dloader.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-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
@@ -21,6 +21,7 @@
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/wakelock.h>
+#include <linux/workqueue.h>
#include <linux/mmc/card.h>
#include <linux/dma-mapping.h>
#include <mach/dma.h>
@@ -87,6 +88,8 @@
const char __user *buf, size_t count, loff_t *ppos);
#endif
+static void sdio_dld_tear_down(struct work_struct *work);
+DECLARE_WORK(cleanup, sdio_dld_tear_down);
/* STRUCTURES AND TYPES */
enum sdio_dld_op_mode {
@@ -224,6 +227,8 @@
static DEFINE_SPINLOCK(lock2);
static unsigned long lock_flags2;
+static atomic_t sdio_dld_in_use = ATOMIC_INIT(0);
+
/*
* sdio_op_mode sets the operation mode of the sdio_dloader -
* it may be in NORMAL_MODE, BOOT_TEST_MODE or AMSS_TEST_MODE
@@ -1108,6 +1113,10 @@
REAL_FUNC_TO_FUNC_IN_ARRAY(sdio_dld->sdioc_boot_func);
struct sdio_func *str_func = sdio_dld->card->sdio_func[func_in_array];
+ if (atomic_read(&sdio_dld_in_use) == 1)
+ return -EBUSY;
+
+ atomic_set(&sdio_dld_in_use, 1);
sdio_dld->tty_str = tty;
sdio_dld->tty_str->low_latency = 1;
sdio_dld->tty_str->icanon = 0;
@@ -1185,7 +1194,6 @@
*/
static void sdio_dld_close(struct tty_struct *tty, struct file *file)
{
- int status = 0;
struct sdioc_reg_chunk *reg = &sdio_dld->sdio_dloader_data.sdioc_reg;
/* informing the SDIOC that it can exit boot phase */
@@ -1200,20 +1208,6 @@
sdio_dld->dld_main_thread.exit_wait.wake_up_signal);
pr_debug(MODULE_NAME ": %s - CLOSING - WOKE UP...", __func__);
- del_timer_sync(&sdio_dld->timer);
- del_timer_sync(&sdio_dld->push_timer);
-
- sdio_dld_dealloc_local_buffers();
-
- tty_unregister_device(sdio_dld->tty_drv, 0);
-
- status = tty_unregister_driver(sdio_dld->tty_drv);
-
- if (status) {
- pr_err(MODULE_NAME ": %s - tty_unregister_driver() failed\n",
- __func__);
- }
-
#ifdef CONFIG_DEBUG_FS
gd.curr_i = curr_index;
gd.duration_ms = sdio_dld_info.time_msec;
@@ -1263,9 +1257,8 @@
if (sdio_dld->done_callback)
sdio_dld->done_callback();
- pr_info(MODULE_NAME ": %s - Freeing sdio_dld data structure, and "
- " returning...", __func__);
- kfree(sdio_dld);
+ schedule_work(&cleanup);
+ pr_info(MODULE_NAME ": %s - Bootloader done, returning...", __func__);
}
/**
@@ -2392,6 +2385,9 @@
struct sdio_func *str_func = NULL;
struct device *tty_dev;
+ if (atomic_read(&sdio_dld_in_use) == 1)
+ return -EBUSY;
+
if (num_of_devices == 0 || num_of_devices > MAX_NUM_DEVICES) {
pr_err(MODULE_NAME ": %s - invalid number of devices\n",
__func__);
@@ -2534,6 +2530,28 @@
return status;
}
+static void sdio_dld_tear_down(struct work_struct *work)
+{
+ int status = 0;
+
+ del_timer_sync(&sdio_dld->timer);
+ del_timer_sync(&sdio_dld->push_timer);
+
+ sdio_dld_dealloc_local_buffers();
+
+ tty_unregister_device(sdio_dld->tty_drv, 0);
+
+ status = tty_unregister_driver(sdio_dld->tty_drv);
+
+ if (status) {
+ pr_err(MODULE_NAME ": %s - tty_unregister_driver() failed\n",
+ __func__);
+ }
+
+ kfree(sdio_dld);
+ atomic_set(&sdio_dld_in_use, 0);
+}
+
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("SDIO Downloader");
MODULE_AUTHOR("Yaniv Gardi <ygardi@codeaurora.org>");
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index 2743547..1ab1f71 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2012, Code Aurora Forum. 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
@@ -15,9 +15,17 @@
*
*/
-#include <linux/types.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/sys_soc.h>
+#include <linux/slab.h>
+#include <linux/stat.h>
#include <linux/sysdev.h>
+#include <linux/types.h>
+
#include <asm/mach-types.h>
+
#include <mach/socinfo.h>
#include "smd_private.h"
@@ -399,6 +407,11 @@
: 0;
}
+static uint32_t socinfo_get_format(void)
+{
+ return socinfo ? socinfo->v1.format : 0;
+}
+
enum msm_cpu socinfo_get_msm_cpu(void)
{
return cur_cpu;
@@ -607,6 +620,100 @@
socinfo_get_pmic_die_revision());
}
+static ssize_t
+msm_get_vendor(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "Qualcomm\n");
+}
+
+static ssize_t
+msm_get_raw_id(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%u\n",
+ socinfo_get_raw_id());
+}
+
+static ssize_t
+msm_get_raw_version(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%u\n",
+ socinfo_get_raw_version());
+}
+
+static ssize_t
+msm_get_build_id(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%-.32s\n",
+ socinfo_get_build_id());
+}
+
+static ssize_t
+msm_get_hw_platform(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ uint32_t hw_type;
+ hw_type = socinfo_get_platform_type();
+
+ return snprintf(buf, PAGE_SIZE, "%-.32s\n",
+ hw_platform[hw_type]);
+}
+
+static ssize_t
+msm_get_platform_version(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%u\n",
+ socinfo_get_platform_version());
+}
+
+static ssize_t
+msm_get_accessory_chip(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%u\n",
+ socinfo_get_accessory_chip());
+}
+
+static ssize_t
+msm_get_platform_subtype(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ uint32_t hw_subtype;
+ hw_subtype = socinfo_get_platform_subtype();
+ return snprintf(buf, PAGE_SIZE, "%-.32s\n",
+ hw_platform_subtype[hw_subtype]);
+}
+
+static ssize_t
+msm_get_pmic_model(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%u\n",
+ socinfo_get_pmic_model());
+}
+
+static ssize_t
+msm_get_pmic_die_revision(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%u\n",
+ socinfo_get_pmic_die_revision());
+}
+
static struct sysdev_attribute socinfo_v1_files[] = {
_SYSDEV_ATTR(id, 0444, socinfo_show_id, NULL),
_SYSDEV_ATTR(version, 0444, socinfo_show_version, NULL),
@@ -644,6 +751,42 @@
socinfo_show_pmic_die_revision, NULL),
};
+static struct device_attribute msm_soc_attr_raw_version =
+ __ATTR(raw_version, S_IRUGO, msm_get_raw_version, NULL);
+
+static struct device_attribute msm_soc_attr_raw_id =
+ __ATTR(raw_id, S_IRUGO, msm_get_raw_id, NULL);
+
+static struct device_attribute msm_soc_attr_vendor =
+ __ATTR(vendor, S_IRUGO, msm_get_vendor, NULL);
+
+static struct device_attribute msm_soc_attr_build_id =
+ __ATTR(build_id, S_IRUGO, msm_get_build_id, NULL);
+
+static struct device_attribute msm_soc_attr_hw_platform =
+ __ATTR(hw_platform, S_IRUGO, msm_get_hw_platform, NULL);
+
+
+static struct device_attribute msm_soc_attr_platform_version =
+ __ATTR(platform_version, S_IRUGO,
+ msm_get_platform_version, NULL);
+
+static struct device_attribute msm_soc_attr_accessory_chip =
+ __ATTR(accessory_chip, S_IRUGO,
+ msm_get_accessory_chip, NULL);
+
+static struct device_attribute msm_soc_attr_platform_subtype =
+ __ATTR(platform_subtype, S_IRUGO,
+ msm_get_platform_subtype, NULL);
+
+static struct device_attribute msm_soc_attr_pmic_model =
+ __ATTR(pmic_model, S_IRUGO,
+ msm_get_pmic_model, NULL);
+
+static struct device_attribute msm_soc_attr_pmic_die_revision =
+ __ATTR(pmic_die_revision, S_IRUGO,
+ msm_get_pmic_die_revision, NULL);
+
static struct sysdev_class soc_sysdev_class = {
.name = "soc",
};
@@ -764,47 +907,63 @@
return (void *) &dummy_socinfo;
}
-int __init socinfo_init(void)
+static void __init populate_soc_sysfs_files(struct device *msm_soc_device)
{
- socinfo = smem_alloc(SMEM_HW_SW_BUILD_ID, sizeof(struct socinfo_v7));
+ uint32_t legacy_format = socinfo_get_format();
- if (!socinfo)
- socinfo = smem_alloc(SMEM_HW_SW_BUILD_ID,
- sizeof(struct socinfo_v6));
+ device_create_file(msm_soc_device, &msm_soc_attr_vendor);
- if (!socinfo)
- socinfo = smem_alloc(SMEM_HW_SW_BUILD_ID,
- sizeof(struct socinfo_v5));
-
- if (!socinfo)
- socinfo = smem_alloc(SMEM_HW_SW_BUILD_ID,
- sizeof(struct socinfo_v4));
-
- if (!socinfo)
- socinfo = smem_alloc(SMEM_HW_SW_BUILD_ID,
- sizeof(struct socinfo_v3));
-
- if (!socinfo)
- socinfo = smem_alloc(SMEM_HW_SW_BUILD_ID,
- sizeof(struct socinfo_v2));
-
- if (!socinfo)
- socinfo = smem_alloc(SMEM_HW_SW_BUILD_ID,
- sizeof(struct socinfo_v1));
-
- if (!socinfo) {
- pr_warn("%s: Can't find SMEM_HW_SW_BUILD_ID; falling back on "
- "dummy values.\n", __func__);
- socinfo = setup_dummy_socinfo();
+ switch (legacy_format) {
+ case 7:
+ device_create_file(msm_soc_device,
+ &msm_soc_attr_pmic_model);
+ device_create_file(msm_soc_device,
+ &msm_soc_attr_pmic_die_revision);
+ case 6:
+ device_create_file(msm_soc_device,
+ &msm_soc_attr_platform_subtype);
+ case 5:
+ device_create_file(msm_soc_device,
+ &msm_soc_attr_accessory_chip);
+ case 4:
+ device_create_file(msm_soc_device,
+ &msm_soc_attr_platform_version);
+ case 3:
+ device_create_file(msm_soc_device,
+ &msm_soc_attr_hw_platform);
+ case 2:
+ device_create_file(msm_soc_device,
+ &msm_soc_attr_raw_id);
+ device_create_file(msm_soc_device,
+ &msm_soc_attr_raw_version);
+ case 1:
+ device_create_file(msm_soc_device,
+ &msm_soc_attr_build_id);
+ break;
+ default:
+ pr_err("%s:Unknown socinfo format:%u\n", __func__,
+ legacy_format);
+ break;
}
- WARN(!socinfo_get_id(), "Unknown SOC ID!\n");
- WARN(socinfo_get_id() >= ARRAY_SIZE(cpu_of_id),
- "New IDs added! ID => CPU mapping might need an update.\n");
+ return;
+}
- if (socinfo->v1.id < ARRAY_SIZE(cpu_of_id))
- cur_cpu = cpu_of_id[socinfo->v1.id];
+static void __init soc_info_populate(struct soc_device_attribute *soc_dev_attr)
+{
+ uint32_t soc_version = socinfo_get_version();
+ soc_dev_attr->soc_id = kasprintf(GFP_KERNEL, "%d", socinfo_get_id());
+ soc_dev_attr->machine = "Snapdragon";
+ soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%u.%u",
+ SOCINFO_VERSION_MAJOR(soc_version),
+ SOCINFO_VERSION_MINOR(soc_version));
+ return;
+
+}
+
+static void socinfo_print(void)
+{
switch (socinfo->v1.format) {
case 1:
pr_info("%s: v%u, id=%u, ver=%u.%u\n",
@@ -880,8 +1039,69 @@
pr_err("%s: Unknown format found\n", __func__);
break;
}
+}
- return 0;
+struct device * __init socinfo_init(void)
+{
+ struct device *msm_soc_device;
+ struct soc_device *soc_dev;
+ struct soc_device_attribute *soc_dev_attr;
+
+ socinfo = smem_alloc(SMEM_HW_SW_BUILD_ID, sizeof(struct socinfo_v7));
+
+ if (!socinfo)
+ socinfo = smem_alloc(SMEM_HW_SW_BUILD_ID,
+ sizeof(struct socinfo_v6));
+
+ if (!socinfo)
+ socinfo = smem_alloc(SMEM_HW_SW_BUILD_ID,
+ sizeof(struct socinfo_v5));
+
+ if (!socinfo)
+ socinfo = smem_alloc(SMEM_HW_SW_BUILD_ID,
+ sizeof(struct socinfo_v4));
+
+ if (!socinfo)
+ socinfo = smem_alloc(SMEM_HW_SW_BUILD_ID,
+ sizeof(struct socinfo_v3));
+
+ if (!socinfo)
+ socinfo = smem_alloc(SMEM_HW_SW_BUILD_ID,
+ sizeof(struct socinfo_v2));
+
+ if (!socinfo)
+ socinfo = smem_alloc(SMEM_HW_SW_BUILD_ID,
+ sizeof(struct socinfo_v1));
+
+ if (!socinfo) {
+ pr_warn("%s: Can't find SMEM_HW_SW_BUILD_ID; falling back on dummy values.\n",
+ __func__);
+ socinfo = setup_dummy_socinfo();
+ }
+
+ WARN(!socinfo_get_id(), "Unknown SOC ID!\n");
+ WARN(socinfo_get_id() >= ARRAY_SIZE(cpu_of_id),
+ "New IDs added! ID => CPU mapping might need an update.\n");
+
+ if (socinfo->v1.id < ARRAY_SIZE(cpu_of_id))
+ cur_cpu = cpu_of_id[socinfo->v1.id];
+
+ socinfo_print();
+ soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
+ if (!soc_dev_attr)
+ return ERR_PTR(-ENOMEM);
+
+ soc_info_populate(soc_dev_attr);
+ soc_dev = soc_device_register(soc_dev_attr);
+ if (IS_ERR_OR_NULL(soc_dev)) {
+ kfree(soc_dev_attr);
+ return ERR_PTR(-EIO);
+ }
+
+ msm_soc_device = soc_device_to_device(soc_dev);
+ populate_soc_sysfs_files(msm_soc_device);
+
+ return msm_soc_device;
}
const int get_core_count(void)
@@ -921,6 +1141,7 @@
return MSM_CPU_8064;
case 0x511F06F1:
+ case 0x511F06F2:
case 0x512F06F0:
return MSM_CPU_8974;
@@ -972,6 +1193,7 @@
case 0x512F04D0:
case 0x511F06F0:
case 0x511F06F1:
+ case 0x511F06F2:
case 0x510F05D0:
return 1;
diff --git a/arch/arm/mach-msm/test-lpm.c b/arch/arm/mach-msm/test-lpm.c
new file mode 100644
index 0000000..dbc8100
--- /dev/null
+++ b/arch/arm/mach-msm/test-lpm.c
@@ -0,0 +1,696 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/pm.h>
+#include <linux/mutex.h>
+#include <linux/uaccess.h>
+#include <linux/debugfs.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/ctype.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <mach/socinfo.h>
+#if defined(CONFIG_MSM_RPM)
+#include "rpm_resources.h"
+#endif
+#include "timer.h"
+#include "test-lpm.h"
+
+#define LPM_STATS_RESET "reset"
+#define LPM_TEST_ALL_LEVELS "lpm"
+#define LPM_TEST_LATENCIES "latency"
+#define LPM_TEST_CLEAR "clear"
+#define BUF_SIZE 200
+#define STAT_BUF_EXTRA_SIZE 500
+#define WAIT_FOR_XO 1
+#define COMM_BUF_SIZE 15
+#define INPUT_COUNT_BUF 10
+#define LPM_DEFAULT_CPU 0
+
+#define SNPRINTF(buf, size, format, ...) \
+{ \
+ if (size > 0) { \
+ int ret; \
+ ret = snprintf(buf, size, format, ## __VA_ARGS__); \
+ if (ret > size) { \
+ buf += size; \
+ size = 0; \
+ } else { \
+ buf += ret; \
+ size -= ret; \
+ } \
+ } \
+} \
+
+static DEFINE_MUTEX(lpm_stats_mutex);
+
+struct lpm_level_stat {
+ char level_name[BUF_SIZE];
+ int64_t min_time;
+ int64_t max_time;
+ int64_t avg_time;
+ int64_t exit_early;
+ int64_t count;
+ unsigned long min_threshold;
+ uint32_t kernel_sleep_time;
+ bool entered;
+};
+
+static DEFINE_PER_CPU(struct lpm_level_stat *, lpm_levels);
+
+static struct dentry *lpm_stat;
+static struct dentry *lpm_ext_comm;
+static struct msm_rpmrs_level *lpm_supp_level;
+static int lpm_level_count;
+static int lpm_level_iter;
+static bool msm_lpm_use_qtimer;
+static unsigned long lpm_sleep_time;
+static bool lpm_latency_test;
+
+static unsigned int timer_interval = 5000;
+module_param_named(lpm_timer_interval_msec, timer_interval, uint,
+ S_IRUGO | S_IWUSR | S_IWGRP);
+
+static unsigned int latency_test_interval = 50;
+module_param_named(lpm_latency_timer_interval_usec, latency_test_interval, uint,
+ S_IRUGO | S_IWUSR | S_IWGRP);
+
+static unsigned int cpu_to_debug = LPM_DEFAULT_CPU;
+static int lpm_cpu_update(const char *val, const struct kernel_param *kp)
+{
+ int ret = 0;
+ unsigned int debug_val;
+
+ ret = kstrtouint(val, 10, &debug_val);
+ if ((ret < 0) || (debug_val >= num_possible_cpus()))
+ return -EINVAL;
+ cpu_to_debug = debug_val;
+ return ret;
+}
+
+static struct kernel_param_ops cpu_debug_events = {
+ .set = lpm_cpu_update,
+};
+
+module_param_cb(cpu_to_debug, &cpu_debug_events, &cpu_to_debug,
+ S_IRUGO | S_IWUSR | S_IWGRP);
+
+static void lpm_populate_name(struct lpm_level_stat *stat,
+ struct msm_rpmrs_level *supp)
+{
+ char nm[BUF_SIZE] = {0};
+ char default_buf[20];
+
+ switch (supp->sleep_mode) {
+ case MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT:
+ strlcat(nm, "WFI ", BUF_SIZE);
+ break;
+ case MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT:
+ strlcat(nm, "WFI voltage Rampdown ", BUF_SIZE);
+ break;
+ case MSM_PM_SLEEP_MODE_RETENTION:
+ strlcat(nm, "Retention ", BUF_SIZE);
+ break;
+ case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE:
+ strlcat(nm, "Standalone Power collapse ", BUF_SIZE);
+ break;
+ case MSM_PM_SLEEP_MODE_POWER_COLLAPSE:
+ strlcat(nm, "Idle Power collapse ", BUF_SIZE);
+ break;
+ case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_SUSPEND:
+ strlcat(nm, "Suspend Power collapse ", BUF_SIZE);
+ break;
+ default:
+ strlcat(nm, "Invalid Mode ", BUF_SIZE);
+ break;
+ }
+
+ switch (msm_pm_get_pxo(&(supp->rs_limits))) {
+ case MSM_PM(PXO_OFF):
+ strlcat(nm, "XO: OFF ", BUF_SIZE);
+ break;
+ case MSM_PM(PXO_ON):
+ strlcat(nm, "XO: ON ", BUF_SIZE);
+ break;
+ default:
+ snprintf(default_buf, sizeof(default_buf),
+ "XO : %d ", msm_pm_get_pxo(&(supp->rs_limits)));
+ strlcat(nm, default_buf , BUF_SIZE);
+ break;
+ }
+
+ switch (msm_pm_get_l2_cache(&(supp->rs_limits))) {
+ case MSM_PM(L2_CACHE_HSFS_OPEN):
+ strlcat(nm, "L2: HSFS ", BUF_SIZE);
+ break;
+ case MSM_PM(L2_CACHE_GDHS):
+ strlcat(nm, "L2: GDHS ", BUF_SIZE);
+ break;
+ case MSM_PM(L2_CACHE_RETENTION):
+ strlcat(nm, "L2: Retention ", BUF_SIZE);
+ break;
+ case MSM_PM(L2_CACHE_ACTIVE):
+ strlcat(nm, "L2: Active ", BUF_SIZE);
+ break;
+ default:
+ snprintf(default_buf, sizeof(default_buf),
+ "L2 : %d ", msm_pm_get_l2_cache(&(supp->rs_limits)));
+ strlcat(nm, default_buf , BUF_SIZE);
+ break;
+ }
+
+ snprintf(default_buf, sizeof(default_buf),
+ "Vdd_mem : %d ", msm_pm_get_vdd_mem(&(supp->rs_limits)));
+ strlcat(nm, default_buf , BUF_SIZE);
+
+ snprintf(default_buf, sizeof(default_buf),
+ "Vdd_dig : %d ", msm_pm_get_vdd_dig(&(supp->rs_limits)));
+ strlcat(nm, default_buf , BUF_SIZE);
+
+ strlcpy(stat->level_name, nm, strnlen(nm, BUF_SIZE));
+}
+
+static int64_t msm_lpm_get_time(void)
+{
+ if (msm_lpm_use_qtimer)
+ return ktime_to_ns(ktime_get());
+
+ return msm_timer_get_sclk_time(NULL);
+}
+
+static bool lpm_get_level(void *v, unsigned int *ct)
+{
+ bool ret = false;
+ int it;
+ struct msm_rpmrs_level *level_enter;
+
+ level_enter = container_of(((struct msm_lpm_sleep_data *)v)->limits,
+ struct msm_rpmrs_level, rs_limits);
+ if (level_enter) {
+ for (it = 0; it < lpm_level_count; it++)
+ if (!memcmp(level_enter , lpm_supp_level + it,
+ sizeof(struct msm_rpmrs_level))) {
+ *ct = it;
+ ret = true;
+ break;
+ }
+ }
+ return ret;
+}
+
+static int lpm_callback(struct notifier_block *self, unsigned long cmd,
+ void *sleep_data)
+{
+ static int64_t time;
+ unsigned int ct;
+ struct lpm_level_stat *stats;
+ stats = per_cpu(lpm_levels, cpu_to_debug);
+ /* Update the stats and get the start/stop time */
+ if (cmd == MSM_LPM_STATE_ENTER && !lpm_latency_test) {
+ time = msm_lpm_get_time();
+ stats[lpm_level_iter].entered = true;
+ } else if ((cmd == MSM_LPM_STATE_EXIT) && (time)
+ && (!lpm_latency_test)) {
+ int64_t time1;
+ time1 = msm_lpm_get_time();
+ time = time1 - time;
+
+ if ((time < stats[lpm_level_iter].min_time) ||
+ (!stats[lpm_level_iter].min_time))
+ stats[lpm_level_iter].min_time = time;
+
+ if (time > stats[lpm_level_iter].max_time)
+ stats[lpm_level_iter].max_time = time;
+
+ time1 = stats[lpm_level_iter].avg_time *
+ stats[lpm_level_iter].count + time;
+ do_div(time1, ++(stats[lpm_level_iter].count));
+
+ stats[lpm_level_iter].avg_time = time1;
+ do_div(time, NSEC_PER_USEC);
+ if (time < lpm_supp_level[lpm_level_iter].
+ time_overhead_us)
+ stats[lpm_level_iter].exit_early++;
+ time = 0;
+ } else if (cmd == MSM_LPM_STATE_ENTER && lpm_latency_test) {
+
+ struct msm_lpm_sleep_data *data = sleep_data;
+ if ((lpm_get_level(sleep_data, &ct)) &&
+ (stats[ct].min_threshold == 0) &&
+ data->kernel_sleep <= lpm_sleep_time) {
+
+ stats[ct].min_threshold = lpm_sleep_time;
+ stats[ct].kernel_sleep_time =
+ data->kernel_sleep;
+ }
+ }
+ return 0;
+}
+
+static struct notifier_block lpm_idle_nb = {
+ .notifier_call = lpm_callback,
+};
+
+static void lpm_test_initiate(int lpm_level_test)
+{
+ int test_ret;
+
+ /* This will communicate to 'stat' debugfs to skip latency printing*/
+ lpm_sleep_time = 0;
+ lpm_latency_test = false;
+ /* Unregister any infinitely registered level*/
+ msm_lpm_unregister_notifier(cpu_to_debug, &lpm_idle_nb);
+
+ /* Register/Unregister for Notification */
+ while (lpm_level_iter < lpm_level_count) {
+ test_ret = msm_lpm_register_notifier(cpu_to_debug,
+ lpm_level_iter, &lpm_idle_nb, false);
+ if (test_ret < 0) {
+ pr_err("%s: Registering notifier failed\n", __func__);
+ return;
+ }
+ if (!timer_interval)
+ break;
+ msleep(timer_interval);
+ msm_lpm_unregister_notifier(cpu_to_debug, &lpm_idle_nb);
+ if (lpm_level_test == lpm_level_count)
+ lpm_level_iter++;
+ else
+ break;
+ }
+}
+
+static void lpm_latency_test_initiate(unsigned long max_time)
+{
+ int test_ret;
+ lpm_latency_test = true;
+ lpm_sleep_time = latency_test_interval;
+
+ msm_lpm_unregister_notifier(cpu_to_debug, &lpm_idle_nb);
+ if (max_time > lpm_sleep_time) {
+
+ do {
+ test_ret = msm_lpm_register_notifier(cpu_to_debug,
+ lpm_level_count + 1,
+ &lpm_idle_nb, true);
+ if (test_ret) {
+ pr_err("%s: Registering notifier failed\n",
+ __func__);
+ return;
+ }
+ usleep(lpm_sleep_time);
+ /*Unregister to ensure that we dont update the latency
+ during the timer value transistion*/
+ msm_lpm_unregister_notifier(cpu_to_debug,
+ &lpm_idle_nb);
+ lpm_sleep_time += latency_test_interval;
+ } while (lpm_sleep_time < max_time);
+ } else
+ pr_err("%s: Invalid time interval specified\n", __func__);
+
+ lpm_latency_test = false;
+}
+
+static ssize_t lpm_test_comm_read(struct file *fp, char __user *user_buffer,
+ size_t buffer_length, loff_t *position)
+{
+ int i = 0;
+ int count = buffer_length;
+ int alloc_size = 100 * lpm_level_count;
+ char *temp_buf;
+ char *comm_buf;
+ ssize_t ret;
+
+ comm_buf = kzalloc(alloc_size, GFP_KERNEL);
+ if (!comm_buf) {
+ pr_err("%s:Memory alloc failed\n", __func__);
+ ret = 0;
+ goto com_read_failed;
+ }
+ temp_buf = comm_buf;
+
+ SNPRINTF(temp_buf, count, "Low power modes available:\n");
+
+ for (i = 0; i < lpm_level_count; i++)
+ SNPRINTF(temp_buf, count, "%d. %s\n", i,
+ per_cpu(lpm_levels, cpu_to_debug)[i].level_name);
+
+ SNPRINTF(temp_buf, count, "%d. MSM test all lpm\n", i++);
+ SNPRINTF(temp_buf, count, "%d. MSM determine latency\n", i);
+
+ ret = simple_read_from_buffer(user_buffer, buffer_length - count,
+ position, comm_buf, alloc_size);
+ kfree(comm_buf);
+
+com_read_failed:
+ return ret;
+}
+
+char *trimspaces(char *time_buf)
+{
+ int len;
+ char *tail;
+
+ len = strnlen(time_buf, INPUT_COUNT_BUF);
+ tail = time_buf + len;
+ while (isspace(*time_buf) && (time_buf != tail))
+ time_buf++;
+ if (time_buf == tail) {
+ time_buf = NULL;
+ goto exit_trim_spaces;
+ }
+ len = strnlen(time_buf, INPUT_COUNT_BUF);
+ tail = time_buf + len - 1;
+ while (isspace(*tail) && tail != time_buf) {
+ *tail = '\0';
+ tail--;
+ }
+exit_trim_spaces:
+ return time_buf;
+}
+
+static ssize_t lpm_test_comm_write(struct file *fp, const char __user
+ *user_buffer, size_t count, loff_t *position)
+{
+ ssize_t ret;
+ int str_ret;
+ int lpm_level_test;
+ char *new_ptr;
+ char *comm_buf;
+
+ comm_buf = kzalloc(COMM_BUF_SIZE, GFP_KERNEL);
+ if (!comm_buf) {
+ pr_err("\'%s\': kzalloc failed\n", __func__);
+ return -EINVAL;
+ }
+
+ memset(comm_buf, '\0', COMM_BUF_SIZE);
+
+ ret = simple_write_to_buffer(comm_buf, COMM_BUF_SIZE, position,
+ user_buffer, count);
+ new_ptr = trimspaces(comm_buf);
+ if (!new_ptr) {
+ pr_err("%s: Test case number input invalid\n", __func__);
+ goto write_com_failed;
+ }
+
+ if (!memcmp(comm_buf, LPM_TEST_ALL_LEVELS,
+ sizeof(LPM_TEST_ALL_LEVELS) - 1)) {
+ lpm_level_test = lpm_level_count;
+ lpm_level_iter = 0;
+ lpm_test_initiate(lpm_level_test);
+ goto write_com_success;
+ } else if (!memcmp(comm_buf, LPM_TEST_LATENCIES,
+ sizeof(LPM_TEST_LATENCIES) - 1)) {
+ lpm_level_test = lpm_level_count + 1;
+ lpm_latency_test_initiate(timer_interval * USEC_PER_MSEC);
+ goto write_com_success;
+ } else if (!memcmp(comm_buf, LPM_TEST_CLEAR,
+ sizeof(LPM_TEST_CLEAR) - 1)) {
+ msm_lpm_unregister_notifier(cpu_to_debug, &lpm_idle_nb);
+ goto write_com_success;
+ }
+
+ str_ret = kstrtoint(new_ptr, 10, &lpm_level_test);
+ if ((str_ret) || (lpm_level_test > (lpm_level_count + 1)) ||
+ (lpm_level_test < 0))
+ goto write_com_failed;
+
+ lpm_level_iter = lpm_level_test;
+ lpm_test_initiate(lpm_level_test);
+ goto write_com_success;
+
+write_com_failed:
+ ret = -EINVAL;
+write_com_success:
+ kfree(comm_buf);
+ return ret;
+}
+
+static ssize_t lpm_test_stat_read(struct file *fp, char __user *user_buffer,
+ size_t buffer_length, loff_t *position)
+{
+ int i = 0;
+ int j = 0;
+ int count = buffer_length;
+ char *stat_buf;
+ char *stat_buf_start;
+ size_t stat_buf_size;
+ ssize_t ret;
+ int64_t min_ns;
+ int64_t max_ns;
+ int64_t avg_ns;
+ uint32_t min_ms;
+ uint32_t max_ms;
+ uint32_t avg_ms;
+
+ stat_buf_size = ((sizeof(struct lpm_level_stat) * lpm_level_count) +
+ STAT_BUF_EXTRA_SIZE);
+ stat_buf = kzalloc(stat_buf_size, GFP_KERNEL);
+ if (!stat_buf) {
+ pr_err("\'%s\': kzalloc failed\n", __func__);
+ return -EINVAL;
+ }
+ stat_buf_start = stat_buf;
+ mutex_lock(&lpm_stats_mutex);
+ memset(stat_buf, '\0', stat_buf_size);
+ SNPRINTF(stat_buf, count, "\n\nStats for CPU: %d\nTotal Levels: %d\n",
+ cpu_to_debug, lpm_level_count);
+ if (!lpm_sleep_time) {
+ SNPRINTF(stat_buf, count, "Level(s) failed: ");
+ for (i = 0 ; i < lpm_level_count; i++) {
+ if (per_cpu(lpm_levels, cpu_to_debug)[i].entered)
+ continue;
+ else {
+ SNPRINTF(stat_buf, count,
+ "\n%d. %s", ++j, per_cpu(lpm_levels,
+ cpu_to_debug)[i].level_name);
+ }
+ }
+ SNPRINTF(stat_buf, count, "\n\nSTATS:");
+ for (i = 0; i < lpm_level_count; i++) {
+ min_ns = per_cpu(lpm_levels, cpu_to_debug)[i].min_time;
+ min_ms = do_div(min_ns, NSEC_PER_MSEC);
+ max_ns = per_cpu(lpm_levels, cpu_to_debug)[i].max_time;
+ max_ms = do_div(max_ns, NSEC_PER_MSEC);
+ avg_ns = per_cpu(lpm_levels, cpu_to_debug)[i].avg_time;
+ avg_ms = do_div(avg_ns, NSEC_PER_MSEC);
+ SNPRINTF(stat_buf, count, "\nLEVEL: %s\n"
+ "Entered : %lld\n"
+ "Early wakeup : %lld\n"
+ "Min Time (mSec): %lld.%06u\n"
+ "Max Time (mSec): %lld.%06u\n"
+ "Avg Time (mSec): %lld.%06u\n",
+ per_cpu(lpm_levels, cpu_to_debug)[i].level_name,
+ per_cpu(lpm_levels, cpu_to_debug)[i].count,
+ per_cpu(lpm_levels, cpu_to_debug)[i].exit_early,
+ min_ns, min_ms,
+ max_ns, max_ms,
+ avg_ns, avg_ms);
+ }
+ } else {
+ for (i = 0; i < lpm_level_count; i++) {
+ SNPRINTF(stat_buf, count, "\nLEVEL: %s\n"
+ "Min Timer value (uSec): %lu\n"
+ "Kernel sleep time (uSec): %u\n",
+ per_cpu(lpm_levels, cpu_to_debug)[i].level_name,
+ per_cpu(lpm_levels, cpu_to_debug)[i].
+ min_threshold,
+ per_cpu(lpm_levels,
+ cpu_to_debug)[i].kernel_sleep_time);
+ }
+ }
+
+ ret = simple_read_from_buffer(user_buffer, buffer_length - count,
+ position, stat_buf_start, stat_buf_size);
+
+ mutex_unlock(&lpm_stats_mutex);
+ kfree(stat_buf_start);
+ return ret;
+}
+
+static ssize_t lpm_test_stat_write(struct file *fp, const char __user
+ *user_buffer, size_t count, loff_t *position)
+{
+ char buf[sizeof(LPM_STATS_RESET)];
+ int ret;
+ int i;
+ struct lpm_level_stat *stats;
+
+ if (count > sizeof(LPM_STATS_RESET)) {
+ ret = -EINVAL;
+ goto write_debug_failed;
+ }
+
+ simple_write_to_buffer(buf, sizeof(LPM_STATS_RESET), position,
+ user_buffer, count);
+
+ if (memcmp(buf, LPM_STATS_RESET, sizeof(LPM_STATS_RESET) - 1)) {
+ ret = -EINVAL;
+ goto write_debug_failed;
+ }
+
+ mutex_lock(&lpm_stats_mutex);
+ stats = per_cpu(lpm_levels, cpu_to_debug);
+ for (i = 0 ; i < lpm_level_count; i++) {
+ stats[i].entered = 0;
+ stats[i].min_time = 0;
+ stats[i].max_time = 0;
+ stats[i].avg_time = 0;
+ stats[i].count = 0;
+ stats[i].exit_early = 0;
+ stats[i].min_threshold = 0;
+ stats[i].kernel_sleep_time = 0;
+ }
+ mutex_unlock(&lpm_stats_mutex);
+ return count;
+write_debug_failed:
+ return ret;
+}
+
+static void lpm_init_rpm_levels(int test_lpm_level_count,
+ struct msm_rpmrs_level *test_levels)
+{
+ int i = 0;
+ unsigned int m_cpu = 0;
+ struct lpm_level_stat *stat_levels = NULL;
+
+ if (test_lpm_level_count < 0)
+ return;
+
+ lpm_level_count = test_lpm_level_count;
+
+ lpm_supp_level = test_levels;
+ for_each_possible_cpu(m_cpu) {
+ stat_levels = kzalloc(sizeof(struct lpm_level_stat) *
+ lpm_level_count, GFP_KERNEL);
+ if (!stat_levels) {
+ for (i = m_cpu - 1; i >= 0; i--)
+ kfree(per_cpu(lpm_levels, i));
+ return;
+ }
+
+ for (i = 0; i < lpm_level_count; i++)
+ lpm_populate_name(&stat_levels[i], &lpm_supp_level[i]);
+
+ per_cpu(lpm_levels, m_cpu) = stat_levels;
+ }
+}
+
+static const struct file_operations fops_stat = {
+ .read = lpm_test_stat_read,
+ .write = lpm_test_stat_write,
+};
+
+static const struct file_operations fops_comm = {
+ .read = lpm_test_comm_read,
+ .write = lpm_test_comm_write,
+};
+
+static int __devinit lpm_test_init(int test_lpm_level_count,
+ struct msm_rpmrs_level *test_levels)
+{
+ int filevalue;
+ int lpm_comm;
+ int ret = -EINVAL;
+ struct dentry *parent_dir = NULL;
+
+ parent_dir = debugfs_create_dir("msm_lpm_debug", NULL);
+ if (!parent_dir) {
+ pr_err("%s: debugfs directory creation failed\n",
+ __func__);
+ goto init_err;
+ }
+
+ lpm_stat = debugfs_create_file("stat",
+ S_IRUGO | S_IWUSR | S_IWGRP, parent_dir,
+ &filevalue, &fops_stat);
+ if (!lpm_stat) {
+ pr_err("%s: lpm_stats debugfs creation failed\n",
+ __func__);
+ goto init_err;
+ }
+
+ lpm_ext_comm = debugfs_create_file("comm",
+ S_IRUGO | S_IWUSR | S_IWGRP, parent_dir, &lpm_comm,
+ &fops_comm);
+ if (!lpm_ext_comm) {
+ pr_err("%s: lpm_comm debugfs creation failed\n",
+ __func__);
+ debugfs_remove(lpm_stat);
+ goto init_err;
+ }
+
+ /*Query RPM resources and allocate the data sturctures*/
+ lpm_init_rpm_levels(test_lpm_level_count, test_levels);
+ ret = 0;
+
+init_err:
+ return ret;
+}
+
+static int __devexit lpm_test_exit(struct platform_device *pdev)
+{
+ unsigned int m_cpu = 0;
+
+ kfree(lpm_supp_level);
+ for_each_possible_cpu(m_cpu)
+ kfree(per_cpu(lpm_levels, m_cpu));
+ debugfs_remove(lpm_stat);
+ debugfs_remove(lpm_ext_comm);
+ return 0;
+}
+
+static int __devinit lpm_test_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct lpm_test_platform_data *pdata;
+ struct msm_rpmrs_level *test_levels;
+ int test_lpm_level_count;
+
+ pdata = pdev->dev.platform_data;
+
+ if (!pdata) {
+ dev_err(dev, "no platform data specified\n");
+ return -EINVAL;
+ }
+
+ test_levels = pdata->msm_lpm_test_levels;
+ test_lpm_level_count = pdata->msm_lpm_test_level_count;
+
+ if (pdata->use_qtimer)
+ msm_lpm_use_qtimer = true;
+
+ lpm_test_init(test_lpm_level_count, test_levels);
+
+ return 0;
+}
+
+static struct platform_driver lpm_test_driver = {
+ .probe = lpm_test_probe,
+ .remove = lpm_test_exit,
+ .driver = {
+ .name = "lpm_test",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init lpm_test_platform_driver_init(void)
+{
+ return platform_driver_register(&lpm_test_driver);
+}
+
+late_initcall(lpm_test_platform_driver_init);
diff --git a/arch/arm/mach-msm/test-lpm.h b/arch/arm/mach-msm/test-lpm.h
new file mode 100644
index 0000000..1486f88
--- /dev/null
+++ b/arch/arm/mach-msm/test-lpm.h
@@ -0,0 +1,22 @@
+/* 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 __ARCH_ARM_MACH_MSM_TEST_LPM_H
+#define __ARCH_ARM_MACH_MSM_TEST_LPM_H
+
+struct lpm_test_platform_data {
+ struct msm_rpmrs_level *msm_lpm_test_levels;
+ int msm_lpm_test_level_count;
+ bool use_qtimer;
+};
+#endif
diff --git a/arch/arm/mach-msm/test_qmi_client.c b/arch/arm/mach-msm/test_qmi_client.c
new file mode 100644
index 0000000..d070e37
--- /dev/null
+++ b/arch/arm/mach-msm/test_qmi_client.c
@@ -0,0 +1,344 @@
+/* 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/slab.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/debugfs.h>
+#include <linux/qmi_encdec.h>
+
+#include <asm/uaccess.h>
+
+#include <mach/msm_qmi_interface.h>
+
+#include "kernel_test_service_v01.h"
+
+#define TEST_SERVICE_SVC_ID 0x0000000f
+#define TEST_SERVICE_INS_ID 1
+
+static int test_rep_cnt = 10;
+module_param_named(rep_cnt, test_rep_cnt, int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+static int test_data_sz = 50;
+module_param_named(data_sz, test_data_sz, int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+static int test_clnt_debug_mask;
+module_param_named(debug_mask, test_clnt_debug_mask,
+ int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+#define D(x...) do { \
+ if (test_clnt_debug_mask) \
+ pr_debug(x); \
+} while (0)
+
+/* Variable to initiate the test through debugfs interface */
+static struct dentry *test_dent;
+
+/* Test client port for IPC Router */
+static struct qmi_handle *test_clnt;
+static int test_clnt_reset;
+
+/* Reader thread to receive responses & indications */
+static void test_clnt_recv_msg(struct work_struct *work);
+static DECLARE_DELAYED_WORK(work_recv_msg, test_clnt_recv_msg);
+static void test_clnt_svc_arrive(struct work_struct *work);
+static DECLARE_DELAYED_WORK(work_svc_arrive, test_clnt_svc_arrive);
+static void test_clnt_svc_exit(struct work_struct *work);
+static DECLARE_DELAYED_WORK(work_svc_exit, test_clnt_svc_exit);
+static struct workqueue_struct *test_clnt_workqueue;
+
+/* Variable to hold the test result */
+static int test_res;
+
+static int test_qmi_ping_pong_send_sync_msg(void)
+{
+ struct test_ping_req_msg_v01 req;
+ struct test_ping_resp_msg_v01 resp;
+ struct msg_desc req_desc, resp_desc;
+ int rc;
+
+ memcpy(req.ping, "ping", sizeof(req.ping));
+ req.client_name_valid = 0;
+
+ req_desc.max_msg_len = TEST_PING_REQ_MAX_MSG_LEN_V01;
+ req_desc.msg_id = TEST_PING_REQ_MSG_ID_V01;
+ req_desc.ei_array = test_ping_req_msg_v01_ei;
+
+ resp_desc.max_msg_len = TEST_PING_REQ_MAX_MSG_LEN_V01;
+ resp_desc.msg_id = TEST_PING_REQ_MSG_ID_V01;
+ resp_desc.ei_array = test_ping_resp_msg_v01_ei;
+
+ rc = qmi_send_req_wait(test_clnt, &req_desc, &req, sizeof(req),
+ &resp_desc, &resp, sizeof(resp), 0);
+ if (rc < 0) {
+ pr_err("%s: send req failed %d\n", __func__, rc);
+ return rc;
+ }
+
+ D("%s: Received %s response\n", __func__, resp.pong);
+ return rc;
+}
+
+static int test_qmi_data_send_sync_msg(unsigned int data_len)
+{
+ struct test_data_req_msg_v01 *req;
+ struct test_data_resp_msg_v01 *resp;
+ struct msg_desc req_desc, resp_desc;
+ int rc, i;
+
+ req = kzalloc(sizeof(struct test_data_req_msg_v01), GFP_KERNEL);
+ if (!req) {
+ pr_err("%s: Data req msg alloc failed\n", __func__);
+ return -ENOMEM;
+ }
+
+ resp = kzalloc(sizeof(struct test_data_resp_msg_v01), GFP_KERNEL);
+ if (!resp) {
+ pr_err("%s: Data resp msg alloc failed\n", __func__);
+ kfree(req);
+ return -ENOMEM;
+ }
+
+ req->data_len = data_len;
+ for (i = 0; i < data_len; i = i + sizeof(int))
+ memcpy(req->data + i, (uint8_t *)&i, sizeof(int));
+ req->client_name_valid = 0;
+
+ req_desc.max_msg_len = TEST_DATA_REQ_MAX_MSG_LEN_V01;
+ req_desc.msg_id = TEST_DATA_REQ_MSG_ID_V01;
+ req_desc.ei_array = test_data_req_msg_v01_ei;
+
+ resp_desc.max_msg_len = TEST_DATA_REQ_MAX_MSG_LEN_V01;
+ resp_desc.msg_id = TEST_DATA_REQ_MSG_ID_V01;
+ resp_desc.ei_array = test_data_resp_msg_v01_ei;
+
+ rc = qmi_send_req_wait(test_clnt, &req_desc, req, sizeof(*req),
+ &resp_desc, resp, sizeof(*resp), 0);
+ if (rc < 0) {
+ pr_err("%s: send req failed\n", __func__);
+ goto data_send_err;
+ }
+
+ D("%s: data_valid %d\n", __func__, resp->data_valid);
+ D("%s: data_len %d\n", __func__, resp->data_len);
+data_send_err:
+ kfree(resp);
+ kfree(req);
+ return rc;
+}
+
+static void test_clnt_recv_msg(struct work_struct *work)
+{
+ int rc;
+
+ rc = qmi_recv_msg(test_clnt);
+ if (rc < 0)
+ pr_err("%s: Error receiving message\n", __func__);
+}
+
+static void test_clnt_notify(struct qmi_handle *handle,
+ enum qmi_event_type event, void *notify_priv)
+{
+ switch (event) {
+ case QMI_RECV_MSG:
+ queue_delayed_work(test_clnt_workqueue,
+ &work_recv_msg, 0);
+ break;
+ default:
+ break;
+ }
+}
+
+static void test_clnt_svc_arrive(struct work_struct *work)
+{
+ int rc;
+
+ D("%s begins\n", __func__);
+
+ /* Create a Local client port for QMI communication */
+ test_clnt = qmi_handle_create(test_clnt_notify, NULL);
+ if (!test_clnt) {
+ pr_err("%s: QMI client handle alloc failed\n", __func__);
+ return;
+ }
+
+ D("%s: Lookup server name\n", __func__);
+ rc = qmi_connect_to_service(test_clnt, TEST_SERVICE_SVC_ID,
+ TEST_SERVICE_INS_ID);
+ if (rc < 0) {
+ pr_err("%s: Server not found\n", __func__);
+ qmi_handle_destroy(test_clnt);
+ test_clnt = NULL;
+ return;
+ }
+ test_clnt_reset = 0;
+ D("%s complete\n", __func__);
+}
+
+static void test_clnt_svc_exit(struct work_struct *work)
+{
+ D("%s begins\n", __func__);
+
+ qmi_handle_destroy(test_clnt);
+ test_clnt_reset = 1;
+ test_clnt = NULL;
+
+ D("%s complete\n", __func__);
+}
+
+static int test_clnt_svc_event_notify(struct notifier_block *this,
+ unsigned long code,
+ void *_cmd)
+{
+ D("%s: event %ld\n", __func__, code);
+ switch (code) {
+ case QMI_SERVER_ARRIVE:
+ queue_delayed_work(test_clnt_workqueue,
+ &work_svc_arrive, 0);
+ break;
+ case QMI_SERVER_EXIT:
+ queue_delayed_work(test_clnt_workqueue,
+ &work_svc_exit, 0);
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+static int test_qmi_open(struct inode *ip, struct file *fp)
+{
+ if (!test_clnt) {
+ pr_err("%s Test client is not initialized\n", __func__);
+ return -ENODEV;
+ }
+ return 0;
+}
+
+static ssize_t test_qmi_read(struct file *fp, char __user *buf,
+ size_t count, loff_t *pos)
+{
+ char _buf[16];
+ snprintf(_buf, sizeof(_buf), "%d\n", test_res);
+ test_res = 0;
+ return simple_read_from_buffer(buf, count, pos,
+ _buf, strnlen(_buf, 16));
+}
+
+static int test_qmi_release(struct inode *ip, struct file *fp)
+{
+ return 0;
+}
+
+static ssize_t test_qmi_write(struct file *fp, const char __user *buf,
+ size_t count, loff_t *pos)
+{
+ unsigned char cmd[64];
+ int len;
+ int i;
+
+ if (count < 1)
+ return 0;
+
+ len = min(count, (sizeof(cmd) - 1));
+
+ if (copy_from_user(cmd, buf, len))
+ return -EFAULT;
+
+ cmd[len] = 0;
+ if (cmd[len-1] == '\n') {
+ cmd[len-1] = 0;
+ len--;
+ }
+
+ if (!strncmp(cmd, "ping_pong", sizeof(cmd))) {
+ for (i = 0; i < test_rep_cnt; i++) {
+ test_res = test_qmi_ping_pong_send_sync_msg();
+ if (test_res == -ENETRESET || test_clnt_reset) {
+ do {
+ msleep(50);
+ } while (test_clnt_reset);
+ }
+ }
+ } else if (!strncmp(cmd, "data", sizeof(cmd))) {
+ for (i = 0; i < test_rep_cnt; i++) {
+ test_res = test_qmi_data_send_sync_msg(test_data_sz);
+ if (test_res == -ENETRESET || test_clnt_reset) {
+ do {
+ msleep(50);
+ } while (test_clnt_reset);
+ }
+ }
+ } else {
+ test_res = -EINVAL;
+ }
+ return count;
+}
+
+static struct notifier_block test_clnt_nb = {
+ .notifier_call = test_clnt_svc_event_notify,
+};
+
+static const struct file_operations debug_ops = {
+ .owner = THIS_MODULE,
+ .open = test_qmi_open,
+ .read = test_qmi_read,
+ .write = test_qmi_write,
+ .release = test_qmi_release,
+};
+
+static int __init test_qmi_init(void)
+{
+ int rc;
+
+ test_clnt_workqueue = create_singlethread_workqueue("test_clnt");
+ if (!test_clnt_workqueue)
+ return -EFAULT;
+
+ rc = qmi_svc_event_notifier_register(TEST_SERVICE_SVC_ID,
+ TEST_SERVICE_INS_ID, &test_clnt_nb);
+ if (rc < 0) {
+ pr_err("%s: notifier register failed\n", __func__);
+ destroy_workqueue(test_clnt_workqueue);
+ return rc;
+ }
+
+ test_dent = debugfs_create_file("test_qmi_client", 0444, 0,
+ NULL, &debug_ops);
+ if (IS_ERR(test_dent)) {
+ pr_err("%s: unable to create debugfs %ld\n",
+ __func__, IS_ERR(test_dent));
+ test_dent = NULL;
+ qmi_svc_event_notifier_unregister(TEST_SERVICE_SVC_ID,
+ TEST_SERVICE_INS_ID, &test_clnt_nb);
+ destroy_workqueue(test_clnt_workqueue);
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+static void __exit test_qmi_exit(void)
+{
+ qmi_svc_event_notifier_unregister(TEST_SERVICE_SVC_ID,
+ TEST_SERVICE_INS_ID, &test_clnt_nb);
+ destroy_workqueue(test_clnt_workqueue);
+ debugfs_remove(test_dent);
+}
+
+module_init(test_qmi_init);
+module_exit(test_qmi_exit);
+
+MODULE_DESCRIPTION("TEST QMI Client Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/block/blk-merge.c b/block/blk-merge.c
index 4fced1b..5d74cc3 100644
--- a/block/blk-merge.c
+++ b/block/blk-merge.c
@@ -42,6 +42,9 @@
goto new_segment;
if (!BIOVEC_SEG_BOUNDARY(q, bvprv, bv))
goto new_segment;
+ if ((bvprv->bv_page != bv->bv_page) &&
+ (bvprv->bv_page + 1) != bv->bv_page)
+ goto new_segment;
seg_size += bv->bv_len;
bvprv = bv;
@@ -141,6 +144,9 @@
goto new_segment;
if (!BIOVEC_SEG_BOUNDARY(q, bvprv, bvec))
goto new_segment;
+ if ((bvprv->bv_page != bvec->bv_page) &&
+ ((bvprv->bv_page + 1) != bvec->bv_page))
+ goto new_segment;
sg->length += nbytes;
} else {
diff --git a/block/test-iosched.c b/block/test-iosched.c
index d2716c84..3b3d485 100644
--- a/block/test-iosched.c
+++ b/block/test-iosched.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012-2013, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -44,7 +44,6 @@
static struct test_data *ptd;
-
/**
* test_iosched_get_req_queue() - returns the request queue
* served by the scheduler
@@ -76,17 +75,20 @@
}
EXPORT_SYMBOL(test_iosched_mark_test_completion);
-/* Check if all the queued test requests were completed */
-static void check_test_completion(void)
+/**
+ * check_test_completion() - Check if all the queued test
+ * requests were completed
+ */
+void check_test_completion(void)
{
struct test_request *test_rq;
if (!ptd)
- return;
+ goto exit;
list_for_each_entry(test_rq, &ptd->dispatched_queue, queuelist)
if (!test_rq->req_completed)
- return;
+ goto exit;
if (!list_empty(&ptd->test_queue)
|| !list_empty(&ptd->reinsert_queue)
@@ -96,7 +98,7 @@
__func__, ptd->test_count, ptd->reinsert_count);
test_pr_info("%s: dispatched_count=%d, urgent_count=%d",
__func__, ptd->dispatched_count, ptd->urgent_count);
- return;
+ goto exit;
}
ptd->test_info.test_duration = jiffies -
@@ -108,7 +110,11 @@
__func__, ptd->dispatched_count);
test_iosched_mark_test_completion();
+
+exit:
+ return;
}
+EXPORT_SYMBOL(check_test_completion);
/*
* A callback to be called per bio completion.
@@ -348,7 +354,7 @@
rq->end_io = end_test_req;
rq->__sector = start_sec;
rq->cmd_type |= REQ_TYPE_FS;
- rq->cmd_flags |= REQ_SORTED; /* do we need this?*/
+ rq->cmd_flags |= REQ_SORTED;
if (rq->bio) {
rq->bio->bi_sector = start_sec;
@@ -364,6 +370,8 @@
test_rq->req_completed = false;
test_rq->req_result = -EINVAL;
test_rq->rq = rq;
+ if (ptd->test_info.get_rq_disk_fn)
+ test_rq->rq->rq_disk = ptd->test_info.get_rq_disk_fn();
test_rq->is_err_expected = is_err_expcted;
rq->elv.priv[0] = (void *)test_rq;
@@ -682,6 +690,8 @@
/**
* test_iosched_start_test() - Prepares and runs the test.
+ * The members test_duration and test_byte_count of the input
+ * parameter t_info are modified by this function.
* @t_info: the current test testcase and callbacks
* functions
*
@@ -770,6 +780,7 @@
wait_event(ptd->wait_q, ptd->test_state == TEST_COMPLETED);
t_info->test_duration = ptd->test_info.test_duration;
+ t_info->test_byte_count = ptd->test_info.test_byte_count;
del_timer_sync(&ptd->timeout_timer);
ret = check_test_result(ptd);
@@ -1004,6 +1015,7 @@
print_req(rq);
elv_dispatch_sort(q, rq);
+ ptd->test_info.test_byte_count += test_rq->buf_size;
ret = 1;
goto err;
}
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index 6bdedd7..83ef121 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -83,6 +83,17 @@
If unsure, say N.
+config SATA_AHCI_MSM
+ tristate "Qualcomm MSM AHCI SATA support"
+ depends on ARCH_MSM
+ select SATA_AHCI_PLATFORM
+ help
+ This option enables support for AHCI SATA controller
+ integrated into Qualcomm MSM chipsets. For more
+ information please refer to http://www.qualcomm.com/chipsets.
+
+ If unsure, say N.
+
config SATA_FSL
tristate "Freescale 3.0Gbps SATA support"
depends on FSL_SOC
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
index 6ece5b7..bc40152 100644
--- a/drivers/ata/Makefile
+++ b/drivers/ata/Makefile
@@ -9,6 +9,7 @@
obj-$(CONFIG_SATA_INIC162X) += sata_inic162x.o
obj-$(CONFIG_SATA_SIL24) += sata_sil24.o
obj-$(CONFIG_SATA_DWC) += sata_dwc_460ex.o
+obj-$(CONFIG_SATA_AHCI_MSM) += ahci_msm.o
# SFF w/ custom DMA
obj-$(CONFIG_PDC_ADMA) += pdc_adma.o
diff --git a/drivers/ata/ahci_msm.c b/drivers/ata/ahci_msm.c
new file mode 100644
index 0000000..8536040
--- /dev/null
+++ b/drivers/ata/ahci_msm.c
@@ -0,0 +1,778 @@
+/*
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * SATA init module.
+ * To be used with SATA interface on MSM targets.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/iopoll.h>
+#include <linux/regulator/consumer.h>
+#include <linux/ahci_platform.h>
+#include <mach/clk.h>
+
+/* PHY registers */
+#define UNIPHY_PLL_REFCLK_CFG 0x000
+#define UNIPHY_PLL_POSTDIV1_CFG 0x004
+#define UNIPHY_PLL_CHGPUMP_CFG 0x008
+#define UNIPHY_PLL_VCOLPF_CFG 0x00C
+#define UNIPHY_PLL_VREG_CFG 0x010
+#define UNIPHY_PLL_PWRGEN_CFG 0x014
+#define UNIPHY_PLL_DMUX_CFG 0x018
+#define UNIPHY_PLL_AMUX_CFG 0x01C
+#define UNIPHY_PLL_GLB_CFG 0x020
+#define UNIPHY_PLL_POSTDIV2_CFG 0x024
+#define UNIPHY_PLL_POSTDIV3_CFG 0x028
+#define UNIPHY_PLL_LPFR_CFG 0x02C
+#define UNIPHY_PLL_LPFC1_CFG 0x030
+#define UNIPHY_PLL_LPFC2_CFG 0x034
+#define UNIPHY_PLL_SDM_CFG0 0x038
+#define UNIPHY_PLL_SDM_CFG1 0x03C
+#define UNIPHY_PLL_SDM_CFG2 0x040
+#define UNIPHY_PLL_SDM_CFG3 0x044
+#define UNIPHY_PLL_SDM_CFG4 0x048
+#define UNIPHY_PLL_SSC_CFG0 0x04C
+#define UNIPHY_PLL_SSC_CFG1 0x050
+#define UNIPHY_PLL_SSC_CFG2 0x054
+#define UNIPHY_PLL_SSC_CFG3 0x058
+#define UNIPHY_PLL_LKDET_CFG0 0x05C
+#define UNIPHY_PLL_LKDET_CFG1 0x060
+#define UNIPHY_PLL_LKDET_CFG2 0x064
+#define UNIPHY_PLL_TEST_CFG 0x068
+#define UNIPHY_PLL_CAL_CFG0 0x06C
+#define UNIPHY_PLL_CAL_CFG1 0x070
+#define UNIPHY_PLL_CAL_CFG2 0x074
+#define UNIPHY_PLL_CAL_CFG3 0x078
+#define UNIPHY_PLL_CAL_CFG4 0x07C
+#define UNIPHY_PLL_CAL_CFG5 0x080
+#define UNIPHY_PLL_CAL_CFG6 0x084
+#define UNIPHY_PLL_CAL_CFG7 0x088
+#define UNIPHY_PLL_CAL_CFG8 0x08C
+#define UNIPHY_PLL_CAL_CFG9 0x090
+#define UNIPHY_PLL_CAL_CFG10 0x094
+#define UNIPHY_PLL_CAL_CFG11 0x098
+#define UNIPHY_PLL_EFUSE_CFG 0x09C
+#define UNIPHY_PLL_DEBUG_BUS_SEL 0x0A0
+#define UNIPHY_PLL_CTRL_42 0x0A4
+#define UNIPHY_PLL_CTRL_43 0x0A8
+#define UNIPHY_PLL_CTRL_44 0x0AC
+#define UNIPHY_PLL_CTRL_45 0x0B0
+#define UNIPHY_PLL_CTRL_46 0x0B4
+#define UNIPHY_PLL_CTRL_47 0x0B8
+#define UNIPHY_PLL_CTRL_48 0x0BC
+#define UNIPHY_PLL_STATUS 0x0C0
+#define UNIPHY_PLL_DEBUG_BUS0 0x0C4
+#define UNIPHY_PLL_DEBUG_BUS1 0x0C8
+#define UNIPHY_PLL_DEBUG_BUS2 0x0CC
+#define UNIPHY_PLL_DEBUG_BUS3 0x0D0
+#define UNIPHY_PLL_CTRL_54 0x0D4
+
+#define SATA_PHY_SER_CTRL 0x100
+#define SATA_PHY_TX_DRIV_CTRL0 0x104
+#define SATA_PHY_TX_DRIV_CTRL1 0x108
+#define SATA_PHY_TX_DRIV_CTRL2 0x10C
+#define SATA_PHY_TX_DRIV_CTRL3 0x110
+#define SATA_PHY_TX_RESV0 0x114
+#define SATA_PHY_TX_RESV1 0x118
+#define SATA_PHY_TX_IMCAL0 0x11C
+#define SATA_PHY_TX_IMCAL1 0x120
+#define SATA_PHY_TX_IMCAL2 0x124
+#define SATA_PHY_RX_IMCAL0 0x128
+#define SATA_PHY_RX_IMCAL1 0x12C
+#define SATA_PHY_RX_IMCAL2 0x130
+#define SATA_PHY_RX_TERM 0x134
+#define SATA_PHY_RX_TERM_RESV 0x138
+#define SATA_PHY_EQUAL 0x13C
+#define SATA_PHY_EQUAL_RESV 0x140
+#define SATA_PHY_OOB_TERM 0x144
+#define SATA_PHY_CDR_CTRL0 0x148
+#define SATA_PHY_CDR_CTRL1 0x14C
+#define SATA_PHY_CDR_CTRL2 0x150
+#define SATA_PHY_CDR_CTRL3 0x154
+#define SATA_PHY_CDR_CTRL4 0x158
+#define SATA_PHY_FA_LOAD0 0x15C
+#define SATA_PHY_FA_LOAD1 0x160
+#define SATA_PHY_CDR_CTRL_RESV 0x164
+#define SATA_PHY_PI_CTRL0 0x168
+#define SATA_PHY_PI_CTRL1 0x16C
+#define SATA_PHY_DESER_RESV 0x170
+#define SATA_PHY_RX_RESV0 0x174
+#define SATA_PHY_AD_TPA_CTRL 0x178
+#define SATA_PHY_REFCLK_CTRL 0x17C
+#define SATA_PHY_POW_DWN_CTRL0 0x180
+#define SATA_PHY_POW_DWN_CTRL1 0x184
+#define SATA_PHY_TX_DATA_CTRL 0x188
+#define SATA_PHY_BIST_GEN0 0x18C
+#define SATA_PHY_BIST_GEN1 0x190
+#define SATA_PHY_BIST_GEN2 0x194
+#define SATA_PHY_BIST_GEN3 0x198
+#define SATA_PHY_LBK_CTRL 0x19C
+#define SATA_PHY_TEST_DEBUG_CTRL 0x1A0
+#define SATA_PHY_ALIGNP 0x1A4
+#define SATA_PHY_PRBS_CFG0 0x1A8
+#define SATA_PHY_PRBS_CFG1 0x1AC
+#define SATA_PHY_PRBS_CFG2 0x1B0
+#define SATA_PHY_PRBS_CFG3 0x1B4
+#define SATA_PHY_CHAN_COMP_CHK_CNT 0x1B8
+#define SATA_PHY_RESET_CTRL 0x1BC
+#define SATA_PHY_RX_CLR 0x1C0
+#define SATA_PHY_RX_EBUF_CTRL 0x1C4
+#define SATA_PHY_ID0 0x1C8
+#define SATA_PHY_ID1 0x1CC
+#define SATA_PHY_ID2 0x1D0
+#define SATA_PHY_ID3 0x1D4
+#define SATA_PHY_RX_CHK_ERR_CNT0 0x1D8
+#define SATA_PHY_RX_CHK_ERR_CNT1 0x1DC
+#define SATA_PHY_RX_CHK_STAT 0x1E0
+#define SATA_PHY_TX_IMCAL_STAT 0x1E4
+#define SATA_PHY_RX_IMCAL_STAT 0x1E8
+#define SATA_PHY_RX_EBUF_STAT 0x1EC
+#define SATA_PHY_DEBUG_BUS_STAT0 0x1F0
+#define SATA_PHY_DEBUG_BUS_STAT1 0x1F4
+#define SATA_PHY_DEBUG_BUS_STAT2 0x1F8
+#define SATA_PHY_DEBUG_BUS_STAT3 0x1FC
+
+#define AHCI_HOST_CAP 0x00
+#define AHCI_HOST_CAP_MASK 0x1F
+#define AHCI_HOST_CAP_PMP (1 << 17)
+
+struct msm_sata_hba {
+ struct platform_device *ahci_pdev;
+ struct clk *slave_iface_clk;
+ struct clk *bus_clk;
+ struct clk *iface_clk;
+ struct clk *src_clk;
+ struct clk *rxoob_clk;
+ struct clk *pmalive_clk;
+ struct clk *cfg_clk;
+ struct regulator *clk_pwr;
+ struct regulator *pmp_pwr;
+ void __iomem *phy_base;
+ void __iomem *ahci_base;
+};
+
+static inline void msm_sata_delay_us(unsigned int delay)
+{
+ /* sleep for max. 50us more to combine processor wakeups */
+ usleep_range(delay, delay + 50);
+}
+
+static int msm_sata_clk_get_prepare_enable_set_rate(struct device *dev,
+ const char *name, struct clk **out_clk, int rate)
+{
+ int ret = 0;
+ struct clk *clk;
+
+ clk = devm_clk_get(dev, name);
+ if (IS_ERR(clk)) {
+ ret = PTR_ERR(clk);
+ dev_err(dev, "failed to get clk: %s err = %d\n", name, ret);
+ goto out;
+ }
+
+ if (rate >= 0) {
+ ret = clk_set_rate(clk, rate);
+ if (ret) {
+ dev_err(dev, "failed to set rate: %d clk: %s err = %d\n",
+ rate, name, ret);
+ goto out;
+ }
+ }
+
+ ret = clk_prepare_enable(clk);
+ if (ret)
+ dev_err(dev, "failed to enable clk: %s err = %d\n", name, ret);
+out:
+ if (!ret)
+ *out_clk = clk;
+
+ return ret;
+}
+
+static int msm_sata_clk_get_prepare_enable(struct device *dev,
+ const char *name, struct clk **out_clk)
+{
+ return msm_sata_clk_get_prepare_enable_set_rate(dev, name, out_clk, -1);
+}
+
+static void msm_sata_clk_put_unprepare_disable(struct clk **clk)
+{
+ if (*clk) {
+ clk_disable_unprepare(*clk);
+ clk_put(*clk);
+ *clk = NULL;
+ }
+}
+
+static int msm_sata_hard_reset(struct device *dev)
+{
+ int ret;
+ struct msm_sata_hba *hba = dev_get_drvdata(dev);
+
+ ret = clk_reset(hba->iface_clk, CLK_RESET_ASSERT);
+ if (ret) {
+ dev_err(dev, "iface_clk assert failed %d\n", ret);
+ goto out;
+ }
+
+ ret = clk_reset(hba->iface_clk, CLK_RESET_DEASSERT);
+ if (ret) {
+ dev_err(dev, "iface_clk de-assert failed %d\n", ret);
+ goto out;
+ }
+out:
+ return ret;
+}
+
+static int msm_sata_clk_init(struct device *dev)
+{
+ int ret = 0;
+ struct msm_sata_hba *hba = dev_get_drvdata(dev);
+
+ /* Enable AHB clock for system fabric slave port connected to SATA */
+ ret = msm_sata_clk_get_prepare_enable(dev,
+ "slave_iface_clk", &hba->slave_iface_clk);
+ if (ret)
+ goto out;
+
+ /* Enable AHB clock for system fabric and SATA core interface */
+ ret = msm_sata_clk_get_prepare_enable(dev,
+ "iface_clk", &hba->iface_clk);
+ if (ret)
+ goto put_dis_slave_iface_clk;
+
+ /* Enable AXI clock for SATA AXI master and slave interfaces */
+ ret = msm_sata_clk_get_prepare_enable(dev,
+ "bus_clk", &hba->bus_clk);
+ if (ret)
+ goto put_dis_iface_clk;
+
+ /* Enable the source clock for pmalive, rxoob and phy ref clocks */
+ ret = msm_sata_clk_get_prepare_enable_set_rate(dev,
+ "src_clk", &hba->src_clk, 100000000);
+ if (ret)
+ goto put_dis_bus_clk;
+
+ /*
+ * Enable RX OOB detection clock. The clock rate is
+ * same as PHY reference clock (100MHz).
+ */
+ ret = msm_sata_clk_get_prepare_enable(dev,
+ "core_rxoob_clk", &hba->rxoob_clk);
+ if (ret)
+ goto put_dis_src_clk;
+
+ /*
+ * Enable power management always-on clock. The clock rate
+ * is same as PHY reference clock (100MHz).
+ */
+ ret = msm_sata_clk_get_prepare_enable(dev,
+ "core_pmalive_clk", &hba->pmalive_clk);
+ if (ret)
+ goto put_dis_rxoob_clk;
+
+ /* Enable PHY configuration AHB clock, fixed 64MHz clock */
+ ret = msm_sata_clk_get_prepare_enable(dev,
+ "cfg_clk", &hba->cfg_clk);
+ if (ret)
+ goto put_dis_pmalive_clk;
+
+ return ret;
+
+put_dis_pmalive_clk:
+ msm_sata_clk_put_unprepare_disable(&hba->pmalive_clk);
+put_dis_rxoob_clk:
+ msm_sata_clk_put_unprepare_disable(&hba->rxoob_clk);
+put_dis_src_clk:
+ msm_sata_clk_put_unprepare_disable(&hba->src_clk);
+put_dis_bus_clk:
+ msm_sata_clk_put_unprepare_disable(&hba->bus_clk);
+put_dis_iface_clk:
+ msm_sata_clk_put_unprepare_disable(&hba->iface_clk);
+put_dis_slave_iface_clk:
+ msm_sata_clk_put_unprepare_disable(&hba->slave_iface_clk);
+out:
+ return ret;
+}
+
+static void msm_sata_clk_deinit(struct device *dev)
+{
+ struct msm_sata_hba *hba = dev_get_drvdata(dev);
+
+ msm_sata_clk_put_unprepare_disable(&hba->cfg_clk);
+ msm_sata_clk_put_unprepare_disable(&hba->pmalive_clk);
+ msm_sata_clk_put_unprepare_disable(&hba->rxoob_clk);
+ msm_sata_clk_put_unprepare_disable(&hba->src_clk);
+ msm_sata_clk_put_unprepare_disable(&hba->bus_clk);
+ msm_sata_clk_put_unprepare_disable(&hba->iface_clk);
+ msm_sata_clk_put_unprepare_disable(&hba->slave_iface_clk);
+}
+
+static int msm_sata_vreg_get_enable_set_vdd(struct device *dev,
+ const char *name, struct regulator **out_vreg,
+ int min_uV, int max_uV, int hpm_uA)
+{
+ int ret = 0;
+ struct regulator *vreg;
+
+ vreg = devm_regulator_get(dev, name);
+ if (IS_ERR(vreg)) {
+ ret = PTR_ERR(vreg);
+ dev_err(dev, "Regulator: %s get failed, err=%d\n", name, ret);
+ goto out;
+ }
+
+ if (regulator_count_voltages(vreg) > 0) {
+ ret = regulator_set_voltage(vreg, min_uV, max_uV);
+ if (ret) {
+ dev_err(dev, "Regulator: %s set voltage failed, err=%d\n",
+ name, ret);
+ goto err;
+ }
+
+ ret = regulator_set_optimum_mode(vreg, hpm_uA);
+ if (ret < 0) {
+ dev_err(dev, "Regulator: %s set optimum mode(uA_load=%d) failed, err=%d\n",
+ name, hpm_uA, ret);
+ goto err;
+ } else {
+ /*
+ * regulator_set_optimum_mode() can return non zero
+ * value even for success case.
+ */
+ ret = 0;
+ }
+ }
+
+ ret = regulator_enable(vreg);
+ if (ret)
+ dev_err(dev, "Regulator: %s enable failed, err=%d\n",
+ name, ret);
+err:
+ if (!ret)
+ *out_vreg = vreg;
+ else
+ devm_regulator_put(vreg);
+out:
+ return ret;
+}
+
+static int msm_sata_vreg_put_disable(struct device *dev,
+ struct regulator *reg, const char *name, int max_uV)
+{
+ int ret;
+
+ if (!reg)
+ return 0;
+
+ ret = regulator_disable(reg);
+ if (ret) {
+ dev_err(dev, "Regulator: %s disable failed err=%d\n",
+ name, ret);
+ goto err;
+ }
+
+ if (regulator_count_voltages(reg) > 0) {
+ ret = regulator_set_voltage(reg, 0, max_uV);
+ if (ret < 0) {
+ dev_err(dev, "Regulator: %s set voltage to 0 failed, err=%d\n",
+ name, ret);
+ goto err;
+ }
+
+ ret = regulator_set_optimum_mode(reg, 0);
+ if (ret < 0) {
+ dev_err(dev, "Regulator: %s set optimum mode(uA_load = 0) failed, err=%d\n",
+ name, ret);
+ goto err;
+ } else {
+ /*
+ * regulator_set_optimum_mode() can return non zero
+ * value even for success case.
+ */
+ ret = 0;
+ }
+ }
+
+err:
+ devm_regulator_put(reg);
+ return ret;
+}
+
+static int msm_sata_vreg_init(struct device *dev)
+{
+ int ret = 0;
+ struct msm_sata_hba *hba = dev_get_drvdata(dev);
+
+ /*
+ * The SATA clock generator needs 3.3V supply and can consume
+ * max. 850mA during functional mode.
+ */
+ ret = msm_sata_vreg_get_enable_set_vdd(dev, "sata_ext_3p3v",
+ &hba->clk_pwr, 3300000, 3300000, 850000);
+ if (ret)
+ goto out;
+
+ /* Add 1ms regulator ramp-up delay */
+ msm_sata_delay_us(1000);
+
+ /* Read AHCI capability register to check if PMP is supported.*/
+ if (readl_relaxed(hba->ahci_base +
+ AHCI_HOST_CAP) & AHCI_HOST_CAP_PMP) {
+ /* Power up port-multiplier */
+ ret = msm_sata_vreg_get_enable_set_vdd(dev, "sata_pmp_pwr",
+ &hba->pmp_pwr, 1800000, 1800000, 200000);
+ if (ret) {
+ msm_sata_vreg_put_disable(dev, hba->clk_pwr,
+ "sata_ext_3p3v", 3300000);
+ goto out;
+ }
+
+ /* Add 1ms regulator ramp-up delay */
+ msm_sata_delay_us(1000);
+ }
+
+out:
+ return ret;
+}
+
+static void msm_sata_vreg_deinit(struct device *dev)
+{
+ struct msm_sata_hba *hba = dev_get_drvdata(dev);
+
+ msm_sata_vreg_put_disable(dev, hba->clk_pwr,
+ "sata_ext_3p3v", 3300000);
+
+ if (hba->pmp_pwr)
+ msm_sata_vreg_put_disable(dev, hba->pmp_pwr,
+ "sata_pmp_pwr", 1800000);
+}
+
+static void msm_sata_phy_deinit(struct device *dev)
+{
+ struct msm_sata_hba *hba = dev_get_drvdata(dev);
+
+ /* Power down PHY */
+ writel_relaxed(0xF8, hba->phy_base + SATA_PHY_POW_DWN_CTRL0);
+ writel_relaxed(0xFE, hba->phy_base + SATA_PHY_POW_DWN_CTRL1);
+
+ /* Power down PLL block */
+ writel_relaxed(0x00, hba->phy_base + UNIPHY_PLL_GLB_CFG);
+ mb();
+
+ devm_iounmap(dev, hba->phy_base);
+}
+
+static int msm_sata_phy_init(struct device *dev)
+{
+ int ret = 0;
+ u32 reg = 0;
+ struct platform_device *pdev = to_platform_device(dev);
+ struct msm_sata_hba *hba = dev_get_drvdata(dev);
+ struct resource *mem;
+
+ mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy_mem");
+ if (!mem) {
+ dev_err(dev, "no mmio space\n");
+ return -EINVAL;
+ }
+
+ hba->phy_base = devm_ioremap(dev, mem->start, resource_size(mem));
+ if (!hba->phy_base) {
+ dev_err(dev, "failed to allocate memory for SATA PHY\n");
+ return -ENOMEM;
+ }
+
+ /* SATA phy initialization */
+
+ writel_relaxed(0x01, hba->phy_base + SATA_PHY_SER_CTRL);
+
+ writel_relaxed(0xB1, hba->phy_base + SATA_PHY_POW_DWN_CTRL0);
+ mb();
+ msm_sata_delay_us(10);
+
+ writel_relaxed(0x01, hba->phy_base + SATA_PHY_POW_DWN_CTRL0);
+ writel_relaxed(0x3E, hba->phy_base + SATA_PHY_POW_DWN_CTRL1);
+ writel_relaxed(0x01, hba->phy_base + SATA_PHY_RX_IMCAL0);
+ writel_relaxed(0x01, hba->phy_base + SATA_PHY_TX_IMCAL0);
+ writel_relaxed(0x02, hba->phy_base + SATA_PHY_TX_IMCAL2);
+
+ /* Write UNIPHYPLL registers to configure PLL */
+ writel_relaxed(0x04, hba->phy_base + UNIPHY_PLL_REFCLK_CFG);
+ writel_relaxed(0x00, hba->phy_base + UNIPHY_PLL_PWRGEN_CFG);
+
+ writel_relaxed(0x0A, hba->phy_base + UNIPHY_PLL_CAL_CFG0);
+ writel_relaxed(0xF3, hba->phy_base + UNIPHY_PLL_CAL_CFG8);
+ writel_relaxed(0x01, hba->phy_base + UNIPHY_PLL_CAL_CFG9);
+ writel_relaxed(0xED, hba->phy_base + UNIPHY_PLL_CAL_CFG10);
+ writel_relaxed(0x02, hba->phy_base + UNIPHY_PLL_CAL_CFG11);
+
+ writel_relaxed(0x36, hba->phy_base + UNIPHY_PLL_SDM_CFG0);
+ writel_relaxed(0x0D, hba->phy_base + UNIPHY_PLL_SDM_CFG1);
+ writel_relaxed(0xA3, hba->phy_base + UNIPHY_PLL_SDM_CFG2);
+ writel_relaxed(0xF0, hba->phy_base + UNIPHY_PLL_SDM_CFG3);
+ writel_relaxed(0x00, hba->phy_base + UNIPHY_PLL_SDM_CFG4);
+
+ writel_relaxed(0x19, hba->phy_base + UNIPHY_PLL_SSC_CFG0);
+ writel_relaxed(0xE1, hba->phy_base + UNIPHY_PLL_SSC_CFG1);
+ writel_relaxed(0x00, hba->phy_base + UNIPHY_PLL_SSC_CFG2);
+ writel_relaxed(0x11, hba->phy_base + UNIPHY_PLL_SSC_CFG3);
+
+ writel_relaxed(0x04, hba->phy_base + UNIPHY_PLL_LKDET_CFG0);
+ writel_relaxed(0xFF, hba->phy_base + UNIPHY_PLL_LKDET_CFG1);
+
+ writel_relaxed(0x02, hba->phy_base + UNIPHY_PLL_GLB_CFG);
+ mb();
+ msm_sata_delay_us(40);
+
+ writel_relaxed(0x03, hba->phy_base + UNIPHY_PLL_GLB_CFG);
+ mb();
+ msm_sata_delay_us(400);
+
+ writel_relaxed(0x05, hba->phy_base + UNIPHY_PLL_LKDET_CFG2);
+ mb();
+
+ /* poll for ready status, timeout after 1 sec */
+ ret = readl_poll_timeout(hba->phy_base + UNIPHY_PLL_STATUS, reg,
+ (reg & 1 << 0), 100, 1000000);
+ if (ret) {
+ dev_err(dev, "poll timeout UNIPHY_PLL_STATUS\n");
+ goto out;
+ }
+
+ ret = readl_poll_timeout(hba->phy_base + SATA_PHY_TX_IMCAL_STAT, reg,
+ (reg & 1 << 0), 100, 1000000);
+ if (ret) {
+ dev_err(dev, "poll timeout SATA_PHY_TX_IMCAL_STAT\n");
+ goto out;
+ }
+
+ ret = readl_poll_timeout(hba->phy_base + SATA_PHY_RX_IMCAL_STAT, reg,
+ (reg & 1 << 0), 100, 1000000);
+ if (ret) {
+ dev_err(dev, "poll timeout SATA_PHY_RX_IMCAL_STAT\n");
+ goto out;
+ }
+
+ /* SATA phy calibrated succesfully, power up to functional mode */
+ writel_relaxed(0x3E, hba->phy_base + SATA_PHY_POW_DWN_CTRL1);
+ writel_relaxed(0x01, hba->phy_base + SATA_PHY_RX_IMCAL0);
+ writel_relaxed(0x01, hba->phy_base + SATA_PHY_TX_IMCAL0);
+
+ writel_relaxed(0x00, hba->phy_base + SATA_PHY_POW_DWN_CTRL1);
+ writel_relaxed(0x59, hba->phy_base + SATA_PHY_CDR_CTRL0);
+ writel_relaxed(0x04, hba->phy_base + SATA_PHY_CDR_CTRL1);
+ writel_relaxed(0x00, hba->phy_base + SATA_PHY_CDR_CTRL2);
+ writel_relaxed(0x00, hba->phy_base + SATA_PHY_PI_CTRL0);
+ writel_relaxed(0x00, hba->phy_base + SATA_PHY_CDR_CTRL3);
+ writel_relaxed(0x01, hba->phy_base + SATA_PHY_POW_DWN_CTRL0);
+
+ writel_relaxed(0x11, hba->phy_base + SATA_PHY_TX_DATA_CTRL);
+ writel_relaxed(0x43, hba->phy_base + SATA_PHY_ALIGNP);
+ writel_relaxed(0x04, hba->phy_base + SATA_PHY_OOB_TERM);
+
+ writel_relaxed(0x01, hba->phy_base + SATA_PHY_EQUAL);
+ writel_relaxed(0x09, hba->phy_base + SATA_PHY_TX_DRIV_CTRL0);
+ writel_relaxed(0x09, hba->phy_base + SATA_PHY_TX_DRIV_CTRL1);
+ mb();
+
+ dev_dbg(dev, "SATA PHY powered up in functional mode\n");
+
+out:
+ /* power down PHY in case of failure */
+ if (ret)
+ msm_sata_phy_deinit(dev);
+
+ return ret;
+}
+
+int msm_sata_init(struct device *ahci_dev, void __iomem *mmio)
+{
+ int ret;
+ struct device *dev = ahci_dev->parent;
+ struct msm_sata_hba *hba = dev_get_drvdata(dev);
+
+ /* Save ahci mmio to access vendor specific registers */
+ hba->ahci_base = mmio;
+
+ ret = msm_sata_clk_init(dev);
+ if (ret) {
+ dev_err(dev, "SATA clk init failed with err=%d\n", ret);
+ goto out;
+ }
+
+ ret = msm_sata_vreg_init(dev);
+ if (ret) {
+ dev_err(dev, "SATA vreg init failed with err=%d\n", ret);
+ msm_sata_clk_deinit(dev);
+ goto out;
+ }
+
+ ret = msm_sata_phy_init(dev);
+ if (ret) {
+ dev_err(dev, "SATA PHY init failed with err=%d\n", ret);
+ msm_sata_vreg_deinit(dev);
+ msm_sata_clk_deinit(dev);
+ goto out;
+ }
+
+out:
+ return ret;
+}
+
+void msm_sata_deinit(struct device *ahci_dev)
+{
+ struct device *dev = ahci_dev->parent;
+
+ msm_sata_phy_deinit(dev);
+ msm_sata_vreg_deinit(dev);
+ msm_sata_clk_deinit(dev);
+}
+
+static int msm_sata_suspend(struct device *ahci_dev)
+{
+ msm_sata_deinit(ahci_dev);
+
+ return 0;
+}
+
+static int msm_sata_resume(struct device *ahci_dev)
+{
+ int ret;
+ struct device *dev = ahci_dev->parent;
+
+ ret = msm_sata_clk_init(dev);
+ if (ret) {
+ dev_err(dev, "SATA clk init failed with err=%d\n", ret);
+ /*
+ * If clock initialization failed, that means ahci driver
+ * cannot access any register going further. Since there is
+ * no check within ahci driver to check for clock failures,
+ * panic here instead of making an unclocked register access.
+ */
+ BUG();
+ }
+
+ /* Issue asynchronous reset to reset PHY */
+ ret = msm_sata_hard_reset(dev);
+ if (ret)
+ goto out;
+
+ ret = msm_sata_vreg_init(dev);
+ if (ret) {
+ dev_err(dev, "SATA vreg init failed with err=%d\n", ret);
+ /* Do not turn off clks, AHCI driver might do register access */
+ goto out;
+ }
+
+ ret = msm_sata_phy_init(dev);
+ if (ret) {
+ dev_err(dev, "SATA PHY init failed with err=%d\n", ret);
+ /* Do not turn off clks, AHCI driver might do register access */
+ msm_sata_vreg_deinit(dev);
+ goto out;
+ }
+out:
+ return ret;
+}
+
+static struct ahci_platform_data msm_ahci_pdata = {
+ .init = msm_sata_init,
+ .exit = msm_sata_deinit,
+ .suspend = msm_sata_suspend,
+ .resume = msm_sata_resume,
+};
+
+static int __devinit msm_sata_probe(struct platform_device *pdev)
+{
+ struct platform_device *ahci;
+ struct msm_sata_hba *hba;
+ int ret = 0;
+
+ hba = devm_kzalloc(&pdev->dev, sizeof(struct msm_sata_hba), GFP_KERNEL);
+ if (!hba) {
+ dev_err(&pdev->dev, "no memory\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ platform_set_drvdata(pdev, hba);
+
+ ahci = platform_device_alloc("ahci", pdev->id);
+ if (!ahci) {
+ dev_err(&pdev->dev, "couldn't allocate ahci device\n");
+ ret = -ENOMEM;
+ goto err_free;
+ }
+
+ dma_set_coherent_mask(&ahci->dev, pdev->dev.coherent_dma_mask);
+
+ ahci->dev.parent = &pdev->dev;
+ ahci->dev.dma_mask = pdev->dev.dma_mask;
+ ahci->dev.dma_parms = pdev->dev.dma_parms;
+ hba->ahci_pdev = ahci;
+
+ ret = platform_device_add_resources(ahci, pdev->resource,
+ pdev->num_resources);
+ if (ret) {
+ dev_err(&pdev->dev, "couldn't add resources to ahci device\n");
+ goto err_put_device;
+ }
+
+ ahci->dev.platform_data = &msm_ahci_pdata;
+ ret = platform_device_add(ahci);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register ahci device\n");
+ goto err_put_device;
+ }
+
+ return 0;
+
+err_put_device:
+ platform_device_put(ahci);
+err_free:
+ devm_kfree(&pdev->dev, hba);
+err:
+ return ret;
+}
+
+static int __devexit msm_sata_remove(struct platform_device *pdev)
+{
+ struct msm_sata_hba *hba = platform_get_drvdata(pdev);
+
+ platform_device_unregister(hba->ahci_pdev);
+
+ return 0;
+}
+
+static struct platform_driver msm_sata_driver = {
+ .probe = msm_sata_probe,
+ .remove = __devexit_p(msm_sata_remove),
+ .driver = {
+ .name = "msm_sata",
+ },
+};
+
+module_platform_driver(msm_sata_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("AHCI platform MSM Glue Layer");
diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
index 82d19e0..0f82142 100644
--- a/drivers/ata/ahci_platform.c
+++ b/drivers/ata/ahci_platform.c
@@ -21,6 +21,7 @@
#include <linux/platform_device.h>
#include <linux/libata.h>
#include <linux/ahci_platform.h>
+#include <linux/pm_runtime.h>
#include "ahci.h"
enum ahci_type {
@@ -73,7 +74,7 @@
AHCI_SHT("ahci_platform"),
};
-static int __init ahci_probe(struct platform_device *pdev)
+static int __devinit ahci_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct ahci_platform_data *pdata = dev_get_platdata(dev);
@@ -192,6 +193,14 @@
if (rc)
goto err0;
+ rc = pm_runtime_set_active(dev);
+ if (rc) {
+ dev_warn(dev, "Unable to set runtime pm active err=%d\n", rc);
+ } else {
+ pm_runtime_enable(dev);
+ pm_runtime_forbid(dev);
+ }
+
return 0;
err0:
if (pdata && pdata->exit)
@@ -275,6 +284,8 @@
static struct dev_pm_ops ahci_pm_ops = {
.suspend = &ahci_suspend,
.resume = &ahci_resume,
+ .runtime_suspend = &ahci_suspend,
+ .runtime_resume = &ahci_resume,
};
#endif
@@ -287,6 +298,7 @@
MODULE_DEVICE_TABLE(of, ahci_of_match);
static struct platform_driver ahci_driver = {
+ .probe = ahci_probe,
.remove = __devexit_p(ahci_remove),
.driver = {
.name = "ahci",
@@ -301,7 +313,7 @@
static int __init ahci_init(void)
{
- return platform_driver_probe(&ahci_driver, ahci_probe);
+ return platform_driver_register(&ahci_driver);
}
module_init(ahci_init);
diff --git a/drivers/base/sync.c b/drivers/base/sync.c
index c0690c8..202c40d 100644
--- a/drivers/base/sync.c
+++ b/drivers/base/sync.c
@@ -28,8 +28,13 @@
#include <linux/anon_inodes.h>
+#define CREATE_TRACE_POINTS
+#include <trace/events/sync.h>
+
static void sync_fence_signal_pt(struct sync_pt *pt);
static int _sync_pt_has_signaled(struct sync_pt *pt);
+static void sync_fence_free(struct kref *kref);
+static void sync_dump(void);
static LIST_HEAD(sync_timeline_list_head);
static DEFINE_SPINLOCK(sync_timeline_list_lock);
@@ -50,6 +55,7 @@
if (obj == NULL)
return NULL;
+ kref_init(&obj->kref);
obj->ops = ops;
strlcpy(obj->name, name, sizeof(obj->name));
@@ -67,8 +73,10 @@
}
EXPORT_SYMBOL(sync_timeline_create);
-static void sync_timeline_free(struct sync_timeline *obj)
+static void sync_timeline_free(struct kref *kref)
{
+ struct sync_timeline *obj =
+ container_of(kref, struct sync_timeline, kref);
unsigned long flags;
if (obj->ops->release_obj)
@@ -83,17 +91,14 @@
void sync_timeline_destroy(struct sync_timeline *obj)
{
- unsigned long flags;
- bool needs_freeing;
-
- spin_lock_irqsave(&obj->child_list_lock, flags);
obj->destroyed = true;
- needs_freeing = list_empty(&obj->child_list_head);
- spin_unlock_irqrestore(&obj->child_list_lock, flags);
- if (needs_freeing)
- sync_timeline_free(obj);
- else
+ /*
+ * If this is not the last reference, signal any children
+ * that their parent is going away.
+ */
+
+ if (!kref_put(&obj->kref, sync_timeline_free))
sync_timeline_signal(obj);
}
EXPORT_SYMBOL(sync_timeline_destroy);
@@ -113,7 +118,6 @@
{
struct sync_timeline *obj = pt->parent;
unsigned long flags;
- bool needs_freeing;
spin_lock_irqsave(&obj->active_list_lock, flags);
if (!list_empty(&pt->active_list))
@@ -121,12 +125,10 @@
spin_unlock_irqrestore(&obj->active_list_lock, flags);
spin_lock_irqsave(&obj->child_list_lock, flags);
- list_del(&pt->child_list);
- needs_freeing = obj->destroyed && list_empty(&obj->child_list_head);
+ if (!list_empty(&pt->child_list)) {
+ list_del_init(&pt->child_list);
+ }
spin_unlock_irqrestore(&obj->child_list_lock, flags);
-
- if (needs_freeing)
- sync_timeline_free(obj);
}
void sync_timeline_signal(struct sync_timeline *obj)
@@ -135,24 +137,30 @@
LIST_HEAD(signaled_pts);
struct list_head *pos, *n;
+ trace_sync_timeline(obj);
+
spin_lock_irqsave(&obj->active_list_lock, flags);
list_for_each_safe(pos, n, &obj->active_list_head) {
struct sync_pt *pt =
container_of(pos, struct sync_pt, active_list);
- if (_sync_pt_has_signaled(pt))
- list_move(pos, &signaled_pts);
+ if (_sync_pt_has_signaled(pt)) {
+ list_del_init(pos);
+ list_add(&pt->signaled_list, &signaled_pts);
+ kref_get(&pt->fence->kref);
+ }
}
spin_unlock_irqrestore(&obj->active_list_lock, flags);
list_for_each_safe(pos, n, &signaled_pts) {
struct sync_pt *pt =
- container_of(pos, struct sync_pt, active_list);
+ container_of(pos, struct sync_pt, signaled_list);
list_del_init(pos);
sync_fence_signal_pt(pt);
+ kref_put(&pt->fence->kref, sync_fence_free);
}
}
EXPORT_SYMBOL(sync_timeline_signal);
@@ -169,6 +177,7 @@
return NULL;
INIT_LIST_HEAD(&pt->active_list);
+ kref_get(&parent->kref);
sync_timeline_add_pt(parent, pt);
return pt;
@@ -182,6 +191,8 @@
sync_timeline_remove_pt(pt);
+ kref_put(&pt->parent->kref, sync_timeline_free);
+
kfree(pt);
}
EXPORT_SYMBOL(sync_pt_free);
@@ -255,6 +266,7 @@
if (fence->file == NULL)
goto err;
+ kref_init(&fence->kref);
strlcpy(fence->name, name, sizeof(fence->name));
INIT_LIST_HEAD(&fence->pt_list_head);
@@ -290,6 +302,12 @@
list_add(&pt->pt_list, &fence->pt_list_head);
sync_pt_activate(pt);
+ /*
+ * signal the fence in case pt was activated before
+ * sync_pt_activate(pt) was called
+ */
+ sync_fence_signal_pt(pt);
+
return fence;
}
EXPORT_SYMBOL(sync_fence_create);
@@ -314,6 +332,65 @@
return 0;
}
+static int sync_fence_merge_pts(struct sync_fence *dst, struct sync_fence *src)
+{
+ struct list_head *src_pos, *dst_pos, *n;
+
+ list_for_each(src_pos, &src->pt_list_head) {
+ struct sync_pt *src_pt =
+ container_of(src_pos, struct sync_pt, pt_list);
+ bool collapsed = false;
+
+ list_for_each_safe(dst_pos, n, &dst->pt_list_head) {
+ struct sync_pt *dst_pt =
+ container_of(dst_pos, struct sync_pt, pt_list);
+ /* collapse two sync_pts on the same timeline
+ * to a single sync_pt that will signal at
+ * the later of the two
+ */
+ if (dst_pt->parent == src_pt->parent) {
+ if (dst_pt->parent->ops->compare(dst_pt, src_pt) == -1) {
+ struct sync_pt *new_pt =
+ sync_pt_dup(src_pt);
+ if (new_pt == NULL)
+ return -ENOMEM;
+
+ 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;
+ break;
+ }
+ }
+
+ if (!collapsed) {
+ struct sync_pt *new_pt = sync_pt_dup(src_pt);
+
+ if (new_pt == NULL)
+ return -ENOMEM;
+
+ new_pt->fence = dst;
+ list_add(&new_pt->pt_list, &dst->pt_list_head);
+ sync_pt_activate(new_pt);
+ }
+ }
+
+ return 0;
+}
+
+static void sync_fence_detach_pts(struct sync_fence *fence)
+{
+ struct list_head *pos, *n;
+
+ list_for_each_safe(pos, n, &fence->pt_list_head) {
+ struct sync_pt *pt = container_of(pos, struct sync_pt, pt_list);
+ sync_timeline_remove_pt(pt);
+ }
+}
+
static void sync_fence_free_pts(struct sync_fence *fence)
{
struct list_head *pos, *n;
@@ -388,11 +465,17 @@
if (err < 0)
goto err;
- err = sync_fence_copy_pts(fence, b);
+ err = sync_fence_merge_pts(fence, b);
if (err < 0)
goto err;
- fence->status = sync_fence_get_status(fence);
+ /*
+ * signal the fence in case one of it's pts were activated before
+ * they were activated
+ */
+ sync_fence_signal_pt(list_first_entry(&fence->pt_list_head,
+ struct sync_pt,
+ pt_list));
return fence;
err:
@@ -491,44 +574,87 @@
}
EXPORT_SYMBOL(sync_fence_cancel_async);
+static bool sync_fence_check(struct sync_fence *fence)
+{
+ /*
+ * Make sure that reads to fence->status are ordered with the
+ * wait queue event triggering
+ */
+ smp_rmb();
+ return fence->status != 0;
+}
+
int sync_fence_wait(struct sync_fence *fence, long timeout)
{
- int err;
+ int err = 0;
+ struct sync_pt *pt;
- if (timeout) {
+ trace_sync_wait(fence, 1);
+ list_for_each_entry(pt, &fence->pt_list_head, pt_list)
+ trace_sync_pt(pt);
+
+ if (timeout > 0) {
timeout = msecs_to_jiffies(timeout);
err = wait_event_interruptible_timeout(fence->wq,
- fence->status != 0,
+ sync_fence_check(fence),
timeout);
- } else {
- err = wait_event_interruptible(fence->wq, fence->status != 0);
+ } else if (timeout < 0) {
+ err = wait_event_interruptible(fence->wq,
+ sync_fence_check(fence));
}
+ trace_sync_wait(fence, 0);
if (err < 0)
return err;
- if (fence->status < 0)
+ if (fence->status < 0) {
+ pr_info("fence error %d on [%p]\n", fence->status, fence);
+ sync_dump();
return fence->status;
+ }
- if (fence->status == 0)
+ if (fence->status == 0) {
+ pr_info("fence timeout on [%p] after %dms\n", fence,
+ jiffies_to_msecs(timeout));
+ sync_dump();
return -ETIME;
+ }
return 0;
}
EXPORT_SYMBOL(sync_fence_wait);
+static void sync_fence_free(struct kref *kref)
+{
+ struct sync_fence *fence = container_of(kref, struct sync_fence, kref);
+
+ sync_fence_free_pts(fence);
+
+ kfree(fence);
+}
+
static int sync_fence_release(struct inode *inode, struct file *file)
{
struct sync_fence *fence = file->private_data;
unsigned long flags;
- sync_fence_free_pts(fence);
-
+ /*
+ * We need to remove all ways to access this fence before droping
+ * our ref.
+ *
+ * start with its membership in the global fence list
+ */
spin_lock_irqsave(&sync_fence_list_lock, flags);
list_del(&fence->sync_fence_list);
spin_unlock_irqrestore(&sync_fence_list_lock, flags);
- kfree(fence);
+ /*
+ * remove its pts from their parents so that sync_timeline_signal()
+ * can't reference the fence.
+ */
+ sync_fence_detach_pts(fence);
+
+ kref_put(&fence->kref, sync_fence_free);
return 0;
}
@@ -539,6 +665,12 @@
poll_wait(file, &fence->wq, wait);
+ /*
+ * Make sure that reads to fence->status are ordered with the
+ * wait queue event triggering
+ */
+ smp_rmb();
+
if (fence->status == 1)
return POLLIN;
else if (fence->status < 0)
@@ -549,7 +681,7 @@
static long sync_fence_ioctl_wait(struct sync_fence *fence, unsigned long arg)
{
- __u32 value;
+ __s32 value;
if (copy_from_user(&value, (void __user *)arg, sizeof(value)))
return -EFAULT;
@@ -564,8 +696,13 @@
struct sync_fence *fence2, *fence3;
struct sync_merge_data data;
- if (copy_from_user(&data, (void __user *)arg, sizeof(data)))
- return -EFAULT;
+ if (fd < 0)
+ return fd;
+
+ if (copy_from_user(&data, (void __user *)arg, sizeof(data))) {
+ err = -EFAULT;
+ goto err_put_fd;
+ }
fence2 = sync_fence_fdget(data.fd2);
if (fence2 == NULL) {
@@ -722,7 +859,17 @@
seq_printf(s, "@%ld.%06ld", tv.tv_sec, tv.tv_usec);
}
- if (pt->parent->ops->print_pt) {
+ if (pt->parent->ops->timeline_value_str &&
+ pt->parent->ops->pt_value_str) {
+ char value[64];
+ pt->parent->ops->pt_value_str(pt, value, sizeof(value));
+ seq_printf(s, ": %s", value);
+ if (fence) {
+ pt->parent->ops->timeline_value_str(pt->parent, value,
+ sizeof(value));
+ seq_printf(s, " / %s", value);
+ }
+ } else if (pt->parent->ops->print_pt) {
seq_printf(s, ": ");
pt->parent->ops->print_pt(s, pt);
}
@@ -737,7 +884,11 @@
seq_printf(s, "%s %s", obj->name, obj->ops->driver_name);
- if (obj->ops->print_obj) {
+ if (obj->ops->timeline_value_str) {
+ char value[64];
+ obj->ops->timeline_value_str(obj, value, sizeof(value));
+ seq_printf(s, ": %s", value);
+ } else if (obj->ops->print_obj) {
seq_printf(s, ": ");
obj->ops->print_obj(s, obj);
}
@@ -758,7 +909,8 @@
struct list_head *pos;
unsigned long flags;
- seq_printf(s, "%s: %s\n", fence->name, sync_status_str(fence->status));
+ seq_printf(s, "[%p] %s: %s\n", fence, fence->name,
+ sync_status_str(fence->status));
list_for_each(pos, &fence->pt_list_head) {
struct sync_pt *pt =
@@ -826,7 +978,34 @@
debugfs_create_file("sync", S_IRUGO, NULL, NULL, &sync_debugfs_fops);
return 0;
}
-
late_initcall(sync_debugfs_init);
+#define DUMP_CHUNK 256
+static char sync_dump_buf[64 * 1024];
+void sync_dump(void)
+{
+ struct seq_file s = {
+ .buf = sync_dump_buf,
+ .size = sizeof(sync_dump_buf) - 1,
+ };
+ int i;
+
+ sync_debugfs_show(&s, NULL);
+
+ for (i = 0; i < s.count; i += DUMP_CHUNK) {
+ if ((s.count - i) > DUMP_CHUNK) {
+ char c = s.buf[i + DUMP_CHUNK];
+ s.buf[i + DUMP_CHUNK] = 0;
+ pr_cont("%s", s.buf + i);
+ s.buf[i + DUMP_CHUNK] = c;
+ } else {
+ s.buf[s.count] = 0;
+ pr_cont("%s", s.buf + i);
+ }
+ }
+}
+#else
+static void sync_dump(void)
+{
+}
#endif
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index f6c26c3..564e085 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2008-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
@@ -250,6 +250,10 @@
pr_alert("diag: Invalid file pointer");
return -ENOMEM;
}
+
+ if (!driver)
+ return -ENOMEM;
+
/* clean up any DCI registrations, if this is a DCI client
* This will specially help in case of ungraceful exit of any DCI client
* This call will remove any pending registrations of such client
@@ -289,26 +293,23 @@
if (driver->table[i].process_id == current->tgid)
driver->table[i].process_id = 0;
- if (driver) {
- mutex_lock(&driver->diagchar_mutex);
- driver->ref_count--;
- /* On Client exit, try to destroy all 3 pools */
- diagmem_exit(driver, POOL_TYPE_COPY);
- diagmem_exit(driver, POOL_TYPE_HDLC);
- diagmem_exit(driver, POOL_TYPE_WRITE_STRUCT);
- for (i = 0; i < driver->num_clients; i++) {
- if (NULL != diagpriv_data && diagpriv_data->pid ==
- driver->client_map[i].pid) {
- driver->client_map[i].pid = 0;
- kfree(diagpriv_data);
- diagpriv_data = NULL;
- break;
- }
+ mutex_lock(&driver->diagchar_mutex);
+ driver->ref_count--;
+ /* On Client exit, try to destroy all 3 pools */
+ diagmem_exit(driver, POOL_TYPE_COPY);
+ diagmem_exit(driver, POOL_TYPE_HDLC);
+ diagmem_exit(driver, POOL_TYPE_WRITE_STRUCT);
+ for (i = 0; i < driver->num_clients; i++) {
+ if (NULL != diagpriv_data && diagpriv_data->pid ==
+ driver->client_map[i].pid) {
+ driver->client_map[i].pid = 0;
+ kfree(diagpriv_data);
+ diagpriv_data = NULL;
+ break;
}
- mutex_unlock(&driver->diagchar_mutex);
- return 0;
}
- return -ENOMEM;
+ mutex_unlock(&driver->diagchar_mutex);
+ return 0;
}
int diag_find_polling_reg(int i)
@@ -1067,10 +1068,9 @@
COPY_USER_SPACE_OR_EXIT(buf, data_type, 4);
/* check the current client and copy its data */
for (i = 0; i < MAX_DCI_CLIENTS; i++) {
- if (driver->dci_client_tbl[i].client != NULL) {
- entry = &(driver->dci_client_tbl[i]);
- if (entry && (current->tgid ==
- entry->client->tgid)) {
+ entry = &(driver->dci_client_tbl[i]);
+ if (entry && entry->client) {
+ if (current->tgid == entry->client->tgid) {
COPY_USER_SPACE_OR_EXIT(buf+4,
entry->data_len, 4);
COPY_USER_SPACE_OR_EXIT(buf+8,
@@ -1273,6 +1273,13 @@
ret = -ENOMEM;
goto fail_free_hdlc;
}
+ if (HDLC_OUT_BUF_SIZE < (2*payload_size) + 3) {
+ pr_err("diag: Dropping packet, HDLC encoded packet payload size crosses buffer limit. Current payload size %d\n",
+ ((2*payload_size) + 3));
+ driver->dropped_count++;
+ ret = -EBADMSG;
+ goto fail_free_hdlc;
+ }
if (HDLC_OUT_BUF_SIZE - driver->used <= (2*payload_size) + 3) {
err = diag_device_write(buf_hdlc, APPS_DATA, NULL);
if (err) {
@@ -1343,8 +1350,8 @@
driver->used = 0;
}
- mutex_unlock(&driver->diagchar_mutex);
diagmem_free(driver, buf_copy, POOL_TYPE_COPY);
+ mutex_unlock(&driver->diagchar_mutex);
if (!timer_in_progress) {
timer_in_progress = 1;
ret = mod_timer(&drain_timer, jiffies + msecs_to_jiffies(500));
diff --git a/drivers/coresight/coresight-etm.c b/drivers/coresight/coresight-etm.c
index 9f96b19..b569aed 100644
--- a/drivers/coresight/coresight-etm.c
+++ b/drivers/coresight/coresight-etm.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
@@ -91,75 +91,87 @@
*/
/* Trace registers (0x000-0x2FC) */
-#define ETMCR (0x000)
-#define ETMCCR (0x004)
-#define ETMTRIGGER (0x008)
-#define ETMSR (0x010)
-#define ETMSCR (0x014)
-#define ETMTSSCR (0x018)
-#define ETMTEEVR (0x020)
-#define ETMTECR1 (0x024)
-#define ETMFFLR (0x02C)
-#define ETMACVRn(n) (0x040 + (n * 4))
-#define ETMACTRn(n) (0x080 + (n * 4))
-#define ETMCNTRLDVRn(n) (0x140 + (n * 4))
-#define ETMCNTENRn(n) (0x150 + (n * 4))
-#define ETMCNTRLDEVRn(n) (0x160 + (n * 4))
-#define ETMCNTVRn(n) (0x170 + (n * 4))
-#define ETMSQ12EVR (0x180)
-#define ETMSQ21EVR (0x184)
-#define ETMSQ23EVR (0x188)
-#define ETMSQ31EVR (0x18C)
-#define ETMSQ32EVR (0x190)
-#define ETMSQ13EVR (0x194)
-#define ETMSQR (0x19C)
-#define ETMEXTOUTEVRn(n) (0x1A0 + (n * 4))
-#define ETMCIDCVRn(n) (0x1B0 + (n * 4))
-#define ETMCIDCMR (0x1BC)
-#define ETMIMPSPEC0 (0x1C0)
-#define ETMIMPSPEC1 (0x1C4)
-#define ETMIMPSPEC2 (0x1C8)
-#define ETMIMPSPEC3 (0x1CC)
-#define ETMIMPSPEC4 (0x1D0)
-#define ETMIMPSPEC5 (0x1D4)
-#define ETMIMPSPEC6 (0x1D8)
-#define ETMIMPSPEC7 (0x1DC)
-#define ETMSYNCFR (0x1E0)
-#define ETMIDR (0x1E4)
-#define ETMCCER (0x1E8)
-#define ETMEXTINSELR (0x1EC)
-#define ETMTESSEICR (0x1F0)
-#define ETMEIBCR (0x1F4)
-#define ETMTSEVR (0x1F8)
-#define ETMAUXCR (0x1FC)
-#define ETMTRACEIDR (0x200)
-#define ETMVMIDCVR (0x240)
+#define ETMCR (0x000)
+#define ETMCCR (0x004)
+#define ETMTRIGGER (0x008)
+#define ETMASSICCTLR (0x00C)
+#define ETMSR (0x010)
+#define ETMSCR (0x014)
+#define ETMTSSCR (0x018)
+#define ETMTECR2 (0x01C)
+#define ETMTEEVR (0x020)
+#define ETMTECR1 (0x024)
+#define ETMFFLR (0x02C)
+#define ETMVDEVR (0x030)
+#define ETMVDCR1 (0x034)
+#define ETMVDCR3 (0x03C)
+#define ETMACVRn(n) (0x040 + (n * 4))
+#define ETMACTRn(n) (0x080 + (n * 4))
+#define ETMDCVRn(n) (0x0C0 + (n * 8))
+#define ETMDCMRn(n) (0x100 + (n * 8))
+#define ETMCNTRLDVRn(n) (0x140 + (n * 4))
+#define ETMCNTENRn(n) (0x150 + (n * 4))
+#define ETMCNTRLDEVRn(n) (0x160 + (n * 4))
+#define ETMCNTVRn(n) (0x170 + (n * 4))
+#define ETMSQ12EVR (0x180)
+#define ETMSQ21EVR (0x184)
+#define ETMSQ23EVR (0x188)
+#define ETMSQ31EVR (0x18C)
+#define ETMSQ32EVR (0x190)
+#define ETMSQ13EVR (0x194)
+#define ETMSQR (0x19C)
+#define ETMEXTOUTEVRn(n) (0x1A0 + (n * 4))
+#define ETMCIDCVRn(n) (0x1B0 + (n * 4))
+#define ETMCIDCMR (0x1BC)
+#define ETMIMPSPEC0 (0x1C0)
+#define ETMIMPSPEC1 (0x1C4)
+#define ETMIMPSPEC2 (0x1C8)
+#define ETMIMPSPEC3 (0x1CC)
+#define ETMIMPSPEC4 (0x1D0)
+#define ETMIMPSPEC5 (0x1D4)
+#define ETMIMPSPEC6 (0x1D8)
+#define ETMIMPSPEC7 (0x1DC)
+#define ETMSYNCFR (0x1E0)
+#define ETMIDR (0x1E4)
+#define ETMCCER (0x1E8)
+#define ETMEXTINSELR (0x1EC)
+#define ETMTESSEICR (0x1F0)
+#define ETMEIBCR (0x1F4)
+#define ETMTSEVR (0x1F8)
+#define ETMAUXCR (0x1FC)
+#define ETMTRACEIDR (0x200)
+#define ETMIDR2 (0x208)
+#define ETMVMIDCVR (0x240)
/* Management registers (0x300-0x314) */
-#define ETMOSLAR (0x300)
-#define ETMOSLSR (0x304)
-#define ETMOSSRR (0x308)
-#define ETMPDCR (0x310)
-#define ETMPDSR (0x314)
+#define ETMOSLAR (0x300)
+#define ETMOSLSR (0x304)
+#define ETMOSSRR (0x308)
+#define ETMPDCR (0x310)
+#define ETMPDSR (0x314)
-#define ETM_MAX_ADDR_CMP (16)
-#define ETM_MAX_CNTR (4)
-#define ETM_MAX_CTXID_CMP (3)
+#define ETM_MAX_ADDR_CMP (16)
+#define ETM_MAX_CNTR (4)
+#define ETM_MAX_CTXID_CMP (3)
-#define ETM_MODE_EXCLUDE BIT(0)
-#define ETM_MODE_CYCACC BIT(1)
-#define ETM_MODE_STALL BIT(2)
-#define ETM_MODE_TIMESTAMP BIT(3)
-#define ETM_MODE_CTXID BIT(4)
-#define ETM_MODE_ALL (0x1F)
+#define ETM_MODE_EXCLUDE BIT(0)
+#define ETM_MODE_CYCACC BIT(1)
+#define ETM_MODE_STALL BIT(2)
+#define ETM_MODE_TIMESTAMP BIT(3)
+#define ETM_MODE_CTXID BIT(4)
+#define ETM_MODE_DATA_TRACE_VAL BIT(5)
+#define ETM_MODE_DATA_TRACE_ADDR BIT(6)
+#define ETM_MODE_ALL (0x7F)
-#define ETM_EVENT_MASK (0x1FFFF)
-#define ETM_SYNC_MASK (0xFFF)
-#define ETM_ALL_MASK (0xFFFFFFFF)
+#define ETM_DATACMP_ENABLE (0x2)
-#define ETM_SEQ_STATE_MAX_VAL (0x2)
+#define ETM_EVENT_MASK (0x1FFFF)
+#define ETM_SYNC_MASK (0xFFF)
+#define ETM_ALL_MASK (0xFFFFFFFF)
-#define ETM_REG_DUMP_VER_OFF (4)
-#define ETM_REG_DUMP_VER (1)
+#define ETM_SEQ_STATE_MAX_VAL (0x2)
+
+#define ETM_REG_DUMP_VER_OFF (4)
+#define ETM_REG_DUMP_VER (1)
enum etm_addr_type {
ETM_ADDR_TYPE_NONE,
@@ -203,6 +215,7 @@
uint8_t nr_ext_inp;
uint8_t nr_ext_out;
uint8_t nr_ctxid_cmp;
+ uint8_t nr_data_cmp;
uint8_t reset;
uint32_t mode;
uint32_t ctrl;
@@ -210,11 +223,18 @@
uint32_t startstop_ctrl;
uint32_t enable_event;
uint32_t enable_ctrl1;
+ uint32_t enable_ctrl2;
uint32_t fifofull_level;
uint8_t addr_idx;
uint32_t addr_val[ETM_MAX_ADDR_CMP];
uint32_t addr_acctype[ETM_MAX_ADDR_CMP];
uint32_t addr_type[ETM_MAX_ADDR_CMP];
+ bool data_trace_support;
+ uint32_t data_val[ETM_MAX_ADDR_CMP];
+ uint32_t data_mask[ETM_MAX_ADDR_CMP];
+ uint32_t viewdata_event;
+ uint32_t viewdata_ctrl1;
+ uint32_t viewdata_ctrl3;
uint8_t cntr_idx;
uint32_t cntr_rld_val[ETM_MAX_CNTR];
uint32_t cntr_event[ETM_MAX_CNTR];
@@ -247,8 +267,10 @@
*/
static void etm_os_unlock(void *info)
{
- etm_writel_cp14(0x0, ETMOSLAR);
- isb();
+ if (cpu_is_krait()) {
+ etm_writel_cp14(0x0, ETMOSLAR);
+ isb();
+ }
}
/*
@@ -382,6 +404,14 @@
ETM_LOCK(drvdata);
}
+static bool etm_version_gte(uint8_t arch, uint8_t base_arch)
+{
+ if (arch >= base_arch && ((arch & PFT_ARCH_MAJOR) != PFT_ARCH_MAJOR))
+ return true;
+ else
+ return false;
+}
+
static void __etm_enable(void *info)
{
int i;
@@ -409,13 +439,24 @@
etm_writel(drvdata, drvdata->ctrl | etmcr, ETMCR);
etm_writel(drvdata, drvdata->trigger_event, ETMTRIGGER);
etm_writel(drvdata, drvdata->startstop_ctrl, ETMTSSCR);
+ if (etm_version_gte(drvdata->arch, ETM_ARCH_V1_2))
+ etm_writel(drvdata, drvdata->enable_ctrl2, ETMTECR2);
etm_writel(drvdata, drvdata->enable_event, ETMTEEVR);
etm_writel(drvdata, drvdata->enable_ctrl1, ETMTECR1);
etm_writel(drvdata, drvdata->fifofull_level, ETMFFLR);
+ if (drvdata->data_trace_support == true) {
+ etm_writel(drvdata, drvdata->viewdata_event, ETMVDEVR);
+ etm_writel(drvdata, drvdata->viewdata_ctrl1, ETMVDCR1);
+ etm_writel(drvdata, drvdata->viewdata_ctrl3, ETMVDCR3);
+ }
for (i = 0; i < drvdata->nr_addr_cmp; i++) {
etm_writel(drvdata, drvdata->addr_val[i], ETMACVRn(i));
etm_writel(drvdata, drvdata->addr_acctype[i], ETMACTRn(i));
}
+ for (i = 0; i < drvdata->nr_data_cmp; i++) {
+ etm_writel(drvdata, drvdata->data_val[i], ETMDCVRn(i));
+ etm_writel(drvdata, drvdata->data_mask[i], ETMDCMRn(i));
+ }
for (i = 0; i < drvdata->nr_cntr; i++) {
etm_writel(drvdata, drvdata->cntr_rld_val[i], ETMCNTRLDVRn(i));
etm_writel(drvdata, drvdata->cntr_event[i], ETMCNTENRn(i));
@@ -594,21 +635,37 @@
if (val) {
drvdata->mode = ETM_MODE_EXCLUDE;
drvdata->ctrl = 0x0;
+ if (etm_version_gte(drvdata->arch, ETM_ARCH_V1_0))
+ drvdata->ctrl |= BIT(11);
if (cpu_is_krait_v1()) {
drvdata->mode |= ETM_MODE_CYCACC;
drvdata->ctrl |= BIT(12);
}
drvdata->trigger_event = 0x406F;
drvdata->startstop_ctrl = 0x0;
+ if (etm_version_gte(drvdata->arch, ETM_ARCH_V1_2))
+ drvdata->enable_ctrl2 = 0x0;
drvdata->enable_event = 0x6F;
drvdata->enable_ctrl1 = 0x1000000;
drvdata->fifofull_level = 0x28;
+ if (drvdata->data_trace_support == true) {
+ drvdata->mode |= (ETM_MODE_DATA_TRACE_VAL |
+ ETM_MODE_DATA_TRACE_ADDR);
+ drvdata->ctrl |= BIT(2) | BIT(3);
+ drvdata->viewdata_event = 0x6F;
+ drvdata->viewdata_ctrl1 = 0x0;
+ drvdata->viewdata_ctrl3 = 0x10000;
+ }
drvdata->addr_idx = 0x0;
for (i = 0; i < drvdata->nr_addr_cmp; i++) {
drvdata->addr_val[i] = 0x0;
drvdata->addr_acctype[i] = 0x0;
drvdata->addr_type[i] = ETM_ADDR_TYPE_NONE;
}
+ for (i = 0; i < drvdata->nr_data_cmp; i++) {
+ drvdata->data_val[i] = 0;
+ drvdata->data_mask[i] = ~(0);
+ }
drvdata->cntr_idx = 0x0;
for (i = 0; i < drvdata->nr_cntr; i++) {
drvdata->cntr_rld_val[i] = 0x0;
@@ -684,6 +741,17 @@
drvdata->ctrl |= (BIT(14) | BIT(15));
else
drvdata->ctrl &= ~(BIT(14) | BIT(15));
+ if (etm_version_gte(drvdata->arch, ETM_ARCH_V1_0)) {
+ if (drvdata->mode & ETM_MODE_DATA_TRACE_VAL)
+ drvdata->ctrl |= BIT(2);
+ else
+ drvdata->ctrl &= ~(BIT(2));
+
+ if (drvdata->mode & ETM_MODE_DATA_TRACE_ADDR)
+ drvdata->ctrl |= (BIT(3));
+ else
+ drvdata->ctrl &= ~(BIT(3));
+ }
spin_unlock(&drvdata->spinlock);
return size;
@@ -839,6 +907,8 @@
drvdata->addr_val[idx] = val;
drvdata->addr_type[idx] = ETM_ADDR_TYPE_SINGLE;
+ if (etm_version_gte(drvdata->arch, ETM_ARCH_V1_2))
+ drvdata->enable_ctrl2 |= (1 << idx);
spin_unlock(&drvdata->spinlock);
return size;
}
@@ -1039,6 +1109,138 @@
static DEVICE_ATTR(addr_acctype, S_IRUGO | S_IWUSR, etm_show_addr_acctype,
etm_store_addr_acctype);
+static ssize_t etm_show_data_val(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ unsigned long val;
+ uint8_t idx;
+
+ spin_lock(&drvdata->spinlock);
+ idx = drvdata->addr_idx;
+ if (idx % 2 != 0) {
+ spin_unlock(&drvdata->spinlock);
+ return -EPERM;
+ }
+ idx = idx >> 1;
+ if (idx >= drvdata->nr_data_cmp) {
+ spin_unlock(&drvdata->spinlock);
+ return -EPERM;
+ }
+
+ val = drvdata->data_val[idx];
+ spin_unlock(&drvdata->spinlock);
+ return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+
+static ssize_t etm_store_data_val(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ unsigned long val;
+ uint8_t idx, data_idx;
+
+ if (sscanf(buf, "%lx", &val) != 1)
+ return -EINVAL;
+
+ spin_lock(&drvdata->spinlock);
+ idx = drvdata->addr_idx;
+ /* Adjust index to use the correct data comparator */
+ data_idx = idx >> 1;
+ /* Only idx = 0, 2, 4, 6... are valid */
+ if (idx % 2 != 0) {
+ spin_unlock(&drvdata->spinlock);
+ return -EPERM;
+ }
+ if (data_idx >= drvdata->nr_data_cmp) {
+ spin_unlock(&drvdata->spinlock);
+ return -EPERM;
+ }
+ if (!BVAL(drvdata->addr_acctype[idx], ETM_DATACMP_ENABLE)) {
+ spin_unlock(&drvdata->spinlock);
+ return -EPERM;
+ }
+ if (drvdata->addr_type[idx] == ETM_ADDR_TYPE_RANGE) {
+ if (!BVAL(drvdata->addr_acctype[idx + 1], ETM_DATACMP_ENABLE)) {
+ spin_unlock(&drvdata->spinlock);
+ return -EPERM;
+ }
+ }
+
+ drvdata->data_val[data_idx] = val;
+ spin_unlock(&drvdata->spinlock);
+ return size;
+}
+static DEVICE_ATTR(data_val, S_IRUGO | S_IWUSR, etm_show_data_val,
+ etm_store_data_val);
+
+static ssize_t etm_show_data_mask(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ unsigned long mask;
+ uint8_t idx;
+
+ spin_lock(&drvdata->spinlock);
+ idx = drvdata->addr_idx;
+ if (idx % 2 != 0) {
+ spin_unlock(&drvdata->spinlock);
+ return -EPERM;
+ }
+ idx = idx >> 1;
+ if (idx >= drvdata->nr_data_cmp) {
+ spin_unlock(&drvdata->spinlock);
+ return -EPERM;
+ }
+
+ mask = drvdata->data_mask[idx];
+ spin_unlock(&drvdata->spinlock);
+ return scnprintf(buf, PAGE_SIZE, "%#lx\n", mask);
+}
+
+static ssize_t etm_store_data_mask(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ unsigned long mask;
+ uint8_t idx, data_idx;
+
+ if (sscanf(buf, "%lx", &mask) != 1)
+ return -EINVAL;
+
+ spin_lock(&drvdata->spinlock);
+ idx = drvdata->addr_idx;
+ /* Adjust index to use the correct data comparator */
+ data_idx = idx >> 1;
+ /* Only idx = 0, 2, 4, 6... are valid */
+ if (idx % 2 != 0) {
+ spin_unlock(&drvdata->spinlock);
+ return -EPERM;
+ }
+ if (data_idx >= drvdata->nr_data_cmp) {
+ spin_unlock(&drvdata->spinlock);
+ return -EPERM;
+ }
+ if (!BVAL(drvdata->addr_acctype[idx], ETM_DATACMP_ENABLE)) {
+ spin_unlock(&drvdata->spinlock);
+ return -EPERM;
+ }
+ if (drvdata->addr_type[idx] == ETM_ADDR_TYPE_RANGE) {
+ if (!BVAL(drvdata->addr_acctype[idx + 1], ETM_DATACMP_ENABLE)) {
+ spin_unlock(&drvdata->spinlock);
+ return -EPERM;
+ }
+ }
+
+ drvdata->data_mask[data_idx] = mask;
+ spin_unlock(&drvdata->spinlock);
+ return size;
+}
+static DEVICE_ATTR(data_mask, S_IRUGO | S_IWUSR, etm_show_data_mask,
+ etm_store_data_mask);
+
static ssize_t etm_show_cntr_idx(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -1604,6 +1806,8 @@
&dev_attr_addr_start.attr,
&dev_attr_addr_stop.attr,
&dev_attr_addr_acctype.attr,
+ &dev_attr_data_val.attr,
+ &dev_attr_data_mask.attr,
&dev_attr_cntr_idx.attr,
&dev_attr_cntr_rld_val.attr,
&dev_attr_cntr_event.attr,
@@ -1681,6 +1885,8 @@
switch (arch) {
case PFT_ARCH_V1_1:
break;
+ case ETM_ARCH_V3_5:
+ break;
default:
return false;
}
@@ -1691,6 +1897,7 @@
{
uint32_t etmidr;
uint32_t etmccr;
+ uint32_t etmcr;
struct etm_drvdata *drvdata = info;
ETM_UNLOCK(drvdata);
@@ -1721,6 +1928,19 @@
drvdata->nr_ext_inp = BMVAL(etmccr, 17, 19);
drvdata->nr_ext_out = BMVAL(etmccr, 20, 22);
drvdata->nr_ctxid_cmp = BMVAL(etmccr, 24, 25);
+ drvdata->nr_data_cmp = BMVAL(etmccr, 4, 7);
+
+ if (etm_version_gte(drvdata->arch, ETM_ARCH_V1_0)) {
+ etmcr = etm_readl(drvdata, ETMCR);
+ etmcr |= (BIT(2) | BIT(3));
+ etm_writel(drvdata, etmcr, ETMCR);
+ etmcr = etm_readl(drvdata, ETMCR);
+ if (BVAL(etmcr, 2) || BVAL(etmcr, 3))
+ drvdata->data_trace_support = true;
+ else
+ drvdata->data_trace_support = false;
+ } else
+ drvdata->data_trace_support = false;
etm_set_pwrdwn(drvdata);
ETM_LOCK(drvdata);
@@ -1734,6 +1954,8 @@
drvdata->nr_ext_inp = etmdrvdata[0]->nr_ext_inp;
drvdata->nr_ext_out = etmdrvdata[0]->nr_ext_out;
drvdata->nr_ctxid_cmp = etmdrvdata[0]->nr_ctxid_cmp;
+ drvdata->nr_data_cmp = etmdrvdata[0]->nr_data_cmp;
+ drvdata->data_trace_support = etmdrvdata[0]->data_trace_support;
}
static void __devinit etm_init_default_data(struct etm_drvdata *drvdata)
@@ -1749,6 +1971,10 @@
drvdata->addr_val[1] = (uint32_t) _etext;
drvdata->addr_type[0] = ETM_ADDR_TYPE_RANGE;
drvdata->addr_type[1] = ETM_ADDR_TYPE_RANGE;
+ if (etm_version_gte(drvdata->arch, ETM_ARCH_V1_0)) {
+ drvdata->addr_acctype[0] = 0x19;
+ drvdata->addr_acctype[1] = 0x19;
+ }
}
for (i = 0; i < drvdata->nr_cntr; i++) {
drvdata->cntr_event[i] = 0x406F;
@@ -1781,6 +2007,23 @@
drvdata->addr_type[i] = ETM_ADDR_TYPE_NONE;
}
}
+
+ if (etm_version_gte(drvdata->arch, ETM_ARCH_V1_0))
+ drvdata->ctrl |= BIT(11);
+ if (etm_version_gte(drvdata->arch, ETM_ARCH_V1_2))
+ drvdata->enable_ctrl2 = 0x0;
+ if (drvdata->data_trace_support == true) {
+ drvdata->mode |= (ETM_MODE_DATA_TRACE_VAL |
+ ETM_MODE_DATA_TRACE_ADDR);
+ drvdata->ctrl |= BIT(2) | BIT(3);
+ drvdata->viewdata_ctrl1 = 0x0;
+ drvdata->viewdata_ctrl3 = 0x10000;
+ drvdata->viewdata_event = 0x6F;
+ }
+ for (i = 0; i < drvdata->nr_data_cmp; i++) {
+ drvdata->data_val[i] = 0;
+ drvdata->data_mask[i] = ~(0);
+ }
}
static int __devinit etm_probe(struct platform_device *pdev)
diff --git a/drivers/coresight/coresight-tmc.c b/drivers/coresight/coresight-tmc.c
index 3bb9ec7..09cda5d 100644
--- a/drivers/coresight/coresight-tmc.c
+++ b/drivers/coresight/coresight-tmc.c
@@ -50,41 +50,45 @@
mb(); \
} while (0)
-#define TMC_RSZ (0x004)
-#define TMC_STS (0x00C)
-#define TMC_RRD (0x010)
-#define TMC_RRP (0x014)
-#define TMC_RWP (0x018)
-#define TMC_TRG (0x01C)
-#define TMC_CTL (0x020)
-#define TMC_RWD (0x024)
-#define TMC_MODE (0x028)
-#define TMC_LBUFLEVEL (0x02C)
-#define TMC_CBUFLEVEL (0x030)
-#define TMC_BUFWM (0x034)
-#define TMC_RRPHI (0x038)
-#define TMC_RWPHI (0x03C)
-#define TMC_AXICTL (0x110)
-#define TMC_DBALO (0x118)
-#define TMC_DBAHI (0x11C)
-#define TMC_FFSR (0x300)
-#define TMC_FFCR (0x304)
-#define TMC_PSCR (0x308)
-#define TMC_ITMISCOP0 (0xEE0)
-#define TMC_ITTRFLIN (0xEE8)
-#define TMC_ITATBDATA0 (0xEEC)
-#define TMC_ITATBCTR2 (0xEF0)
-#define TMC_ITATBCTR1 (0xEF4)
-#define TMC_ITATBCTR0 (0xEF8)
+#define TMC_RSZ (0x004)
+#define TMC_STS (0x00C)
+#define TMC_RRD (0x010)
+#define TMC_RRP (0x014)
+#define TMC_RWP (0x018)
+#define TMC_TRG (0x01C)
+#define TMC_CTL (0x020)
+#define TMC_RWD (0x024)
+#define TMC_MODE (0x028)
+#define TMC_LBUFLEVEL (0x02C)
+#define TMC_CBUFLEVEL (0x030)
+#define TMC_BUFWM (0x034)
+#define TMC_RRPHI (0x038)
+#define TMC_RWPHI (0x03C)
+#define TMC_AXICTL (0x110)
+#define TMC_DBALO (0x118)
+#define TMC_DBAHI (0x11C)
+#define TMC_FFSR (0x300)
+#define TMC_FFCR (0x304)
+#define TMC_PSCR (0x308)
+#define TMC_ITMISCOP0 (0xEE0)
+#define TMC_ITTRFLIN (0xEE8)
+#define TMC_ITATBDATA0 (0xEEC)
+#define TMC_ITATBCTR2 (0xEF0)
+#define TMC_ITATBCTR1 (0xEF4)
+#define TMC_ITATBCTR0 (0xEF8)
-#define BYTES_PER_WORD 4
-#define TMC_ETR_BAM_PIPE_INDEX 0
-#define TMC_ETR_BAM_NR_PIPES 2
+#define BYTES_PER_WORD 4
+#define TMC_ETR_BAM_PIPE_INDEX 0
+#define TMC_ETR_BAM_NR_PIPES 2
-#define TMC_ETFETB_DUMP_VER_OFF (4)
-#define TMC_ETFETB_DUMP_VER (1)
-#define TMC_REG_DUMP_VER_OFF (4)
-#define TMC_REG_DUMP_VER (1)
+#define TMC_ETFETB_DUMP_MAGIC_OFF (0)
+#define TMC_ETFETB_DUMP_MAGIC (0x5D1DB1BF)
+#define TMC_ETFETB_DUMP_VER_OFF (4)
+#define TMC_ETFETB_DUMP_VER (1)
+#define TMC_REG_DUMP_MAGIC_OFF (0)
+#define TMC_REG_DUMP_MAGIC (0x5D1DB1BF)
+#define TMC_REG_DUMP_VER_OFF (4)
+#define TMC_REG_DUMP_VER (1)
enum tmc_config_type {
TMC_CONFIG_TYPE_ETB,
@@ -134,6 +138,8 @@
struct mutex read_lock;
int read_count;
bool reading;
+ bool aborting;
+ char *reg_buf;
char *buf;
unsigned long paddr;
void __iomem *vaddr;
@@ -462,10 +468,64 @@
return tmc_enable(drvdata, TMC_MODE_HARDWARE_FIFO);
}
+static void __tmc_reg_dump(struct tmc_drvdata *drvdata)
+{
+ char *reg_hdr;
+ uint32_t *reg_buf;
+
+ if (!drvdata->reg_buf || !drvdata->aborting)
+ return;
+
+ reg_hdr = drvdata->reg_buf - PAGE_SIZE;
+ reg_buf = (uint32_t *)drvdata->reg_buf;
+
+ reg_buf[1] = tmc_readl(drvdata, TMC_RSZ);
+ reg_buf[3] = tmc_readl(drvdata, TMC_STS);
+ reg_buf[5] = tmc_readl(drvdata, TMC_RRP);
+ reg_buf[6] = tmc_readl(drvdata, TMC_RWP);
+ reg_buf[7] = tmc_readl(drvdata, TMC_TRG);
+ reg_buf[8] = tmc_readl(drvdata, TMC_CTL);
+ reg_buf[10] = tmc_readl(drvdata, TMC_MODE);
+ reg_buf[11] = tmc_readl(drvdata, TMC_LBUFLEVEL);
+ reg_buf[12] = tmc_readl(drvdata, TMC_CBUFLEVEL);
+ reg_buf[13] = tmc_readl(drvdata, TMC_BUFWM);
+ if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
+ reg_buf[14] = tmc_readl(drvdata, TMC_RRPHI);
+ reg_buf[15] = tmc_readl(drvdata, TMC_RWPHI);
+ reg_buf[68] = tmc_readl(drvdata, TMC_AXICTL);
+ reg_buf[70] = tmc_readl(drvdata, TMC_DBALO);
+ reg_buf[71] = tmc_readl(drvdata, TMC_DBAHI);
+ }
+ reg_buf[192] = tmc_readl(drvdata, TMC_FFSR);
+ reg_buf[193] = tmc_readl(drvdata, TMC_FFCR);
+ reg_buf[194] = tmc_readl(drvdata, TMC_PSCR);
+ reg_buf[1000] = tmc_readl(drvdata, CORESIGHT_CLAIMSET);
+ reg_buf[1001] = tmc_readl(drvdata, CORESIGHT_CLAIMCLR);
+ reg_buf[1005] = tmc_readl(drvdata, CORESIGHT_LSR);
+ reg_buf[1006] = tmc_readl(drvdata, CORESIGHT_AUTHSTATUS);
+ reg_buf[1010] = tmc_readl(drvdata, CORESIGHT_DEVID);
+ reg_buf[1011] = tmc_readl(drvdata, CORESIGHT_DEVTYPE);
+ reg_buf[1012] = tmc_readl(drvdata, CORESIGHT_PERIPHIDR4);
+ reg_buf[1013] = tmc_readl(drvdata, CORESIGHT_PERIPHIDR5);
+ reg_buf[1014] = tmc_readl(drvdata, CORESIGHT_PERIPHIDR6);
+ reg_buf[1015] = tmc_readl(drvdata, CORESIGHT_PERIPHIDR7);
+ reg_buf[1016] = tmc_readl(drvdata, CORESIGHT_PERIPHIDR0);
+ reg_buf[1017] = tmc_readl(drvdata, CORESIGHT_PERIPHIDR1);
+ reg_buf[1018] = tmc_readl(drvdata, CORESIGHT_PERIPHIDR2);
+ reg_buf[1019] = tmc_readl(drvdata, CORESIGHT_PERIPHIDR3);
+ reg_buf[1020] = tmc_readl(drvdata, CORESIGHT_COMPIDR0);
+ reg_buf[1021] = tmc_readl(drvdata, CORESIGHT_COMPIDR1);
+ reg_buf[1022] = tmc_readl(drvdata, CORESIGHT_COMPIDR2);
+ reg_buf[1023] = tmc_readl(drvdata, CORESIGHT_COMPIDR3);
+
+ *(uint32_t *)(reg_hdr + TMC_REG_DUMP_MAGIC_OFF) = TMC_REG_DUMP_MAGIC;
+}
+
static void __tmc_etb_dump(struct tmc_drvdata *drvdata)
{
enum tmc_mem_intf_width memwidth;
uint8_t memwords;
+ char *hdr;
char *bufp;
uint32_t read_data;
int i;
@@ -485,11 +545,18 @@
for (i = 0; i < memwords; i++) {
read_data = tmc_readl(drvdata, TMC_RRD);
if (read_data == 0xFFFFFFFF)
- return;
+ goto out;
memcpy(bufp, &read_data, BYTES_PER_WORD);
bufp += BYTES_PER_WORD;
}
}
+
+out:
+ if (drvdata->aborting) {
+ hdr = drvdata->buf - PAGE_SIZE;
+ *(uint32_t *)(hdr + TMC_ETFETB_DUMP_MAGIC_OFF) =
+ TMC_ETFETB_DUMP_MAGIC;
+ }
}
static void __tmc_etb_disable(struct tmc_drvdata *drvdata)
@@ -498,6 +565,7 @@
tmc_flush_and_stop(drvdata);
__tmc_etb_dump(drvdata);
+ __tmc_reg_dump(drvdata);
__tmc_disable(drvdata);
TMC_LOCK(drvdata);
@@ -522,6 +590,7 @@
tmc_flush_and_stop(drvdata);
__tmc_etr_dump(drvdata);
+ __tmc_reg_dump(drvdata);
__tmc_disable(drvdata);
TMC_LOCK(drvdata);
@@ -604,6 +673,8 @@
unsigned long flags;
enum tmc_mode mode;
+ drvdata->aborting = true;
+
spin_lock_irqsave(&drvdata->spinlock, flags);
if (drvdata->reading)
goto out0;
@@ -1077,8 +1148,10 @@
dump.start_addr = virt_to_phys(baddr);
dump.end_addr = dump.start_addr + PAGE_SIZE + drvdata->size;
ret = msm_dump_table_register(&dump);
- /* Don't free the buffer in case of error since it can still
- * be used to provide dump collection via the device node
+ /*
+ * Don't free the buffer in case of error since it can still
+ * be used to provide dump collection via the device node or
+ * as part of abort.
*/
if (ret)
dev_info(dev, "TMC ETF-ETB dump setup failed\n");
@@ -1087,15 +1160,19 @@
baddr = devm_kzalloc(dev, PAGE_SIZE + reg_size, GFP_KERNEL);
if (baddr) {
+ drvdata->reg_buf = baddr + PAGE_SIZE;
*(uint32_t *)(baddr + TMC_REG_DUMP_VER_OFF) = TMC_REG_DUMP_VER;
dump.id = MSM_TMC0_REG + count;
dump.start_addr = virt_to_phys(baddr);
dump.end_addr = dump.start_addr + PAGE_SIZE + reg_size;
ret = msm_dump_table_register(&dump);
- if (ret) {
- devm_kfree(dev, baddr);
+ /*
+ * Don't free the buffer in case of error since it can still
+ * be used to dump registers as part of abort to aid post crash
+ * parsing.
+ */
+ if (ret)
dev_info(dev, "TMC REG dump setup failed\n");
- }
} else {
dev_info(dev, "TMC REG dump space allocation failed\n");
}
diff --git a/drivers/crypto/msm/qce.c b/drivers/crypto/msm/qce.c
index 4a9729c..7f8460b 100644
--- a/drivers/crypto/msm/qce.c
+++ b/drivers/crypto/msm/qce.c
@@ -1,6 +1,6 @@
/* Qualcomm Crypto Engine driver.
*
- * 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
@@ -474,11 +474,37 @@
{
int i;
- for (i = 0; nbytes > 0; i++, sg = sg_next(sg))
+ for (i = 0; nbytes > 0; i++, sg = scatterwalk_sg_next(sg))
nbytes -= sg->length;
return i;
}
+static int qce_dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
+ enum dma_data_direction direction)
+{
+ int i;
+
+ for (i = 0; i < nents; ++i) {
+ dma_map_sg(dev, sg, 1, direction);
+ sg = scatterwalk_sg_next(sg);
+ }
+
+ return nents;
+}
+
+static int qce_dma_unmap_sg(struct device *dev, struct scatterlist *sg,
+ int nents, enum dma_data_direction direction)
+{
+ int i;
+
+ for (i = 0; i < nents; ++i) {
+ dma_unmap_sg(dev, sg, 1, direction);
+ sg = scatterwalk_sg_next(sg);
+ }
+
+ return nents;
+}
+
static int dma_map_pmem_sg(struct buf_info *pmem, unsigned entries,
struct scatterlist *sg)
{
@@ -917,15 +943,15 @@
ivsize = crypto_aead_ivsize(aead);
if (areq->src != areq->dst) {
- dma_unmap_sg(pce_dev->pdev, areq->dst, pce_dev->dst_nents,
+ qce_dma_unmap_sg(pce_dev->pdev, areq->dst, pce_dev->dst_nents,
DMA_FROM_DEVICE);
}
- dma_unmap_sg(pce_dev->pdev, areq->src, pce_dev->src_nents,
+ qce_dma_unmap_sg(pce_dev->pdev, areq->src, pce_dev->src_nents,
(areq->src == areq->dst) ? DMA_BIDIRECTIONAL :
DMA_TO_DEVICE);
dma_unmap_single(pce_dev->pdev, pce_dev->phy_iv_in,
ivsize, DMA_TO_DEVICE);
- dma_unmap_sg(pce_dev->pdev, areq->assoc, pce_dev->assoc_nents,
+ qce_dma_unmap_sg(pce_dev->pdev, areq->assoc, pce_dev->assoc_nents,
DMA_TO_DEVICE);
/* check ce error status */
@@ -975,7 +1001,7 @@
uint32_t status;
areq = (struct ahash_request *) pce_dev->areq;
- dma_unmap_sg(pce_dev->pdev, areq->src, pce_dev->src_nents,
+ qce_dma_unmap_sg(pce_dev->pdev, areq->src, pce_dev->src_nents,
DMA_TO_DEVICE);
/* check ce error status */
@@ -1014,10 +1040,10 @@
areq = (struct ablkcipher_request *) pce_dev->areq;
if (areq->src != areq->dst) {
- dma_unmap_sg(pce_dev->pdev, areq->dst,
+ qce_dma_unmap_sg(pce_dev->pdev, areq->dst,
pce_dev->dst_nents, DMA_FROM_DEVICE);
}
- dma_unmap_sg(pce_dev->pdev, areq->src, pce_dev->src_nents,
+ qce_dma_unmap_sg(pce_dev->pdev, areq->src, pce_dev->src_nents,
(areq->src == areq->dst) ? DMA_BIDIRECTIONAL :
DMA_TO_DEVICE);
@@ -1178,7 +1204,7 @@
}
}
if (nbytes > 0)
- sg = sg_next(sg);
+ sg = scatterwalk_sg_next(sg);
}
return 0;
}
@@ -1341,7 +1367,7 @@
}
}
if (nbytes > 0)
- sg = sg_next(sg);
+ sg = scatterwalk_sg_next(sg);
}
return 0;
}
@@ -2041,7 +2067,7 @@
pce_dev->dst_nents = 0;
pce_dev->assoc_nents = count_sg(areq->assoc, areq->assoclen);
- dma_map_sg(pce_dev->pdev, areq->assoc, pce_dev->assoc_nents,
+ qce_dma_map_sg(pce_dev->pdev, areq->assoc, pce_dev->assoc_nents,
DMA_TO_DEVICE);
if (_chain_sg_buffer_in(pce_dev, areq->assoc, areq->assoclen) < 0) {
rc = -ENOMEM;
@@ -2065,7 +2091,7 @@
/* cipher input */
pce_dev->src_nents = count_sg(areq->src, q_req->cryptlen);
- dma_map_sg(pce_dev->pdev, areq->src, pce_dev->src_nents,
+ qce_dma_map_sg(pce_dev->pdev, areq->src, pce_dev->src_nents,
(areq->src == areq->dst) ? DMA_BIDIRECTIONAL :
DMA_TO_DEVICE);
if (_chain_sg_buffer_in(pce_dev, areq->src, q_req->cryptlen) < 0) {
@@ -2076,7 +2102,7 @@
/* cipher output */
if (areq->src != areq->dst) {
pce_dev->dst_nents = count_sg(areq->dst, q_req->cryptlen);
- dma_map_sg(pce_dev->pdev, areq->dst, pce_dev->dst_nents,
+ qce_dma_map_sg(pce_dev->pdev, areq->dst, pce_dev->dst_nents,
DMA_FROM_DEVICE);
};
if (_chain_sg_buffer_out(pce_dev, areq->dst, q_req->cryptlen) < 0) {
@@ -2119,20 +2145,20 @@
return 0;
bad:
if (pce_dev->assoc_nents) {
- dma_unmap_sg(pce_dev->pdev, areq->assoc, pce_dev->assoc_nents,
- DMA_TO_DEVICE);
+ qce_dma_unmap_sg(pce_dev->pdev, areq->assoc,
+ pce_dev->assoc_nents, DMA_TO_DEVICE);
}
if (pce_dev->phy_iv_in) {
dma_unmap_single(pce_dev->pdev, pce_dev->phy_iv_in,
ivsize, DMA_TO_DEVICE);
}
if (pce_dev->src_nents) {
- dma_unmap_sg(pce_dev->pdev, areq->src, pce_dev->src_nents,
+ qce_dma_unmap_sg(pce_dev->pdev, areq->src, pce_dev->src_nents,
(areq->src == areq->dst) ? DMA_BIDIRECTIONAL :
DMA_TO_DEVICE);
}
if (pce_dev->dst_nents) {
- dma_unmap_sg(pce_dev->pdev, areq->dst, pce_dev->dst_nents,
+ qce_dma_unmap_sg(pce_dev->pdev, areq->dst, pce_dev->dst_nents,
DMA_FROM_DEVICE);
}
return rc;
@@ -2158,7 +2184,7 @@
pce_dev->src_nents = count_sg(areq->src, areq->nbytes);
if (c_req->use_pmem != 1)
- dma_map_sg(pce_dev->pdev, areq->src, pce_dev->src_nents,
+ qce_dma_map_sg(pce_dev->pdev, areq->src, pce_dev->src_nents,
(areq->src == areq->dst) ? DMA_BIDIRECTIONAL :
DMA_TO_DEVICE);
else
@@ -2174,8 +2200,8 @@
if (areq->src != areq->dst) {
pce_dev->dst_nents = count_sg(areq->dst, areq->nbytes);
if (c_req->use_pmem != 1)
- dma_map_sg(pce_dev->pdev, areq->dst, pce_dev->dst_nents,
- DMA_FROM_DEVICE);
+ qce_dma_map_sg(pce_dev->pdev, areq->dst,
+ pce_dev->dst_nents, DMA_FROM_DEVICE);
else
dma_map_pmem_sg(&c_req->pmem->dst[0],
pce_dev->dst_nents, areq->dst);
@@ -2233,11 +2259,11 @@
bad:
if (c_req->use_pmem != 1) {
if (pce_dev->dst_nents) {
- dma_unmap_sg(pce_dev->pdev, areq->dst,
+ qce_dma_unmap_sg(pce_dev->pdev, areq->dst,
pce_dev->dst_nents, DMA_FROM_DEVICE);
}
if (pce_dev->src_nents) {
- dma_unmap_sg(pce_dev->pdev, areq->src,
+ qce_dma_unmap_sg(pce_dev->pdev, areq->src,
pce_dev->src_nents,
(areq->src == areq->dst) ?
DMA_BIDIRECTIONAL :
@@ -2257,7 +2283,7 @@
_chain_buffer_in_init(pce_dev);
pce_dev->src_nents = count_sg(sreq->src, sreq->size);
- dma_map_sg(pce_dev->pdev, sreq->src, pce_dev->src_nents,
+ qce_dma_map_sg(pce_dev->pdev, sreq->src, pce_dev->src_nents,
DMA_TO_DEVICE);
if (_chain_sg_buffer_in(pce_dev, sreq->src, sreq->size) < 0) {
@@ -2293,7 +2319,7 @@
return 0;
bad:
if (pce_dev->src_nents) {
- dma_unmap_sg(pce_dev->pdev, sreq->src,
+ qce_dma_unmap_sg(pce_dev->pdev, sreq->src,
pce_dev->src_nents, DMA_TO_DEVICE);
}
diff --git a/drivers/crypto/msm/qce40.c b/drivers/crypto/msm/qce40.c
index de060cc..84d41da 100644
--- a/drivers/crypto/msm/qce40.c
+++ b/drivers/crypto/msm/qce40.c
@@ -1,6 +1,6 @@
/* Qualcomm Crypto Engine driver.
*
- * Copyright (c) 2011 - 2012, Code Aurora Forum. 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
@@ -107,11 +107,37 @@
{
int i;
- for (i = 0; nbytes > 0; i++, sg = sg_next(sg))
+ for (i = 0; nbytes > 0; i++, sg = scatterwalk_sg_next(sg))
nbytes -= sg->length;
return i;
}
+static int qce_dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
+ enum dma_data_direction direction)
+{
+ int i;
+
+ for (i = 0; i < nents; ++i) {
+ dma_map_sg(dev, sg, 1, direction);
+ sg = scatterwalk_sg_next(sg);
+ }
+
+ return nents;
+}
+
+static int qce_dma_unmap_sg(struct device *dev, struct scatterlist *sg,
+ int nents, enum dma_data_direction direction)
+{
+ int i;
+
+ for (i = 0; i < nents; ++i) {
+ dma_unmap_sg(dev, sg, 1, direction);
+ sg = scatterwalk_sg_next(sg);
+ }
+
+ return nents;
+}
+
static int dma_map_pmem_sg(struct buf_info *pmem, unsigned entries,
struct scatterlist *sg)
{
@@ -670,14 +696,14 @@
areq = (struct aead_request *) pce_dev->areq;
if (areq->src != areq->dst) {
- dma_unmap_sg(pce_dev->pdev, areq->dst, pce_dev->dst_nents,
+ qce_dma_unmap_sg(pce_dev->pdev, areq->dst, pce_dev->dst_nents,
DMA_FROM_DEVICE);
}
- dma_unmap_sg(pce_dev->pdev, areq->src, pce_dev->src_nents,
+ qce_dma_unmap_sg(pce_dev->pdev, areq->src, pce_dev->src_nents,
(areq->src == areq->dst) ? DMA_BIDIRECTIONAL :
DMA_TO_DEVICE);
- dma_unmap_sg(pce_dev->pdev, areq->assoc, pce_dev->assoc_nents,
+ qce_dma_unmap_sg(pce_dev->pdev, areq->assoc, pce_dev->assoc_nents,
DMA_TO_DEVICE);
/* check MAC */
@@ -700,7 +726,7 @@
struct ahash_request *areq;
areq = (struct ahash_request *) pce_dev->areq;
- dma_unmap_sg(pce_dev->pdev, areq->src, pce_dev->src_nents,
+ qce_dma_unmap_sg(pce_dev->pdev, areq->src, pce_dev->src_nents,
DMA_TO_DEVICE);
pce_dev->qce_cb(areq, pce_dev->ce_dm.buffer.auth_result,
@@ -716,10 +742,10 @@
areq = (struct ablkcipher_request *) pce_dev->areq;
if (areq->src != areq->dst) {
- dma_unmap_sg(pce_dev->pdev, areq->dst,
+ qce_dma_unmap_sg(pce_dev->pdev, areq->dst,
pce_dev->dst_nents, DMA_FROM_DEVICE);
}
- dma_unmap_sg(pce_dev->pdev, areq->src, pce_dev->src_nents,
+ qce_dma_unmap_sg(pce_dev->pdev, areq->src, pce_dev->src_nents,
(areq->src == areq->dst) ? DMA_BIDIRECTIONAL :
DMA_TO_DEVICE);
@@ -826,7 +852,7 @@
&pce_dev->ce_dm.ce_in_src_desc_index);
}
if (nbytes > 0)
- sg = sg_next(sg);
+ sg = scatterwalk_sg_next(sg);
}
return 0;
}
@@ -989,7 +1015,7 @@
}
if (nbytes > 0)
- sg = sg_next(sg);
+ sg = scatterwalk_sg_next(sg);
}
return 0;
}
@@ -2149,7 +2175,7 @@
/* associated data input */
pce_dev->assoc_nents = count_sg(areq->assoc, areq->assoclen);
- dma_map_sg(pce_dev->pdev, areq->assoc, pce_dev->assoc_nents,
+ qce_dma_map_sg(pce_dev->pdev, areq->assoc, pce_dev->assoc_nents,
DMA_TO_DEVICE);
if (_chain_sg_buffer_in(pce_dev, areq->assoc, areq->assoclen) < 0) {
rc = -ENOMEM;
@@ -2157,7 +2183,7 @@
}
/* cipher input */
pce_dev->src_nents = count_sg(areq->src, areq->cryptlen);
- dma_map_sg(pce_dev->pdev, areq->src, pce_dev->src_nents,
+ qce_dma_map_sg(pce_dev->pdev, areq->src, pce_dev->src_nents,
(areq->src == areq->dst) ? DMA_BIDIRECTIONAL :
DMA_TO_DEVICE);
if (_chain_sg_buffer_in(pce_dev, areq->src, areq->cryptlen) < 0) {
@@ -2182,7 +2208,7 @@
/* cipher + mac output for encryption */
if (areq->src != areq->dst) {
pce_dev->dst_nents = count_sg(areq->dst, out_len);
- dma_map_sg(pce_dev->pdev, areq->dst, pce_dev->dst_nents,
+ qce_dma_map_sg(pce_dev->pdev, areq->dst, pce_dev->dst_nents,
DMA_FROM_DEVICE);
};
if (_chain_sg_buffer_out(pce_dev, areq->dst, out_len) < 0) {
@@ -2222,17 +2248,17 @@
return 0;
bad:
if (pce_dev->assoc_nents) {
- dma_unmap_sg(pce_dev->pdev, areq->assoc, pce_dev->assoc_nents,
- DMA_TO_DEVICE);
+ qce_dma_unmap_sg(pce_dev->pdev, areq->assoc,
+ pce_dev->assoc_nents, DMA_TO_DEVICE);
}
if (pce_dev->src_nents) {
- dma_unmap_sg(pce_dev->pdev, areq->src, pce_dev->src_nents,
+ qce_dma_unmap_sg(pce_dev->pdev, areq->src, pce_dev->src_nents,
(areq->src == areq->dst) ? DMA_BIDIRECTIONAL :
DMA_TO_DEVICE);
}
if (pce_dev->dst_nents) {
- dma_unmap_sg(pce_dev->pdev, areq->dst, pce_dev->dst_nents,
+ qce_dma_unmap_sg(pce_dev->pdev, areq->dst, pce_dev->dst_nents,
DMA_FROM_DEVICE);
}
return rc;
@@ -2259,7 +2285,7 @@
pce_dev->src_nents = count_sg(areq->src, areq->nbytes);
if (c_req->use_pmem != 1)
- dma_map_sg(pce_dev->pdev, areq->src, pce_dev->src_nents,
+ qce_dma_map_sg(pce_dev->pdev, areq->src, pce_dev->src_nents,
(areq->src == areq->dst) ? DMA_BIDIRECTIONAL :
DMA_TO_DEVICE);
else
@@ -2275,8 +2301,8 @@
if (areq->src != areq->dst) {
pce_dev->dst_nents = count_sg(areq->dst, areq->nbytes);
if (c_req->use_pmem != 1)
- dma_map_sg(pce_dev->pdev, areq->dst, pce_dev->dst_nents,
- DMA_FROM_DEVICE);
+ qce_dma_map_sg(pce_dev->pdev, areq->dst,
+ pce_dev->dst_nents, DMA_FROM_DEVICE);
else
dma_map_pmem_sg(&c_req->pmem->dst[0],
pce_dev->dst_nents, areq->dst);
@@ -2333,11 +2359,11 @@
bad:
if (c_req->use_pmem != 1) {
if (pce_dev->dst_nents) {
- dma_unmap_sg(pce_dev->pdev, areq->dst,
+ qce_dma_unmap_sg(pce_dev->pdev, areq->dst,
pce_dev->dst_nents, DMA_FROM_DEVICE);
}
if (pce_dev->src_nents) {
- dma_unmap_sg(pce_dev->pdev, areq->src,
+ qce_dma_unmap_sg(pce_dev->pdev, areq->src,
pce_dev->src_nents,
(areq->src == areq->dst) ?
DMA_BIDIRECTIONAL :
@@ -2358,7 +2384,7 @@
_chain_buffer_in_init(pce_dev);
pce_dev->src_nents = count_sg(sreq->src, sreq->size);
- dma_map_sg(pce_dev->pdev, sreq->src, pce_dev->src_nents,
+ qce_dma_map_sg(pce_dev->pdev, sreq->src, pce_dev->src_nents,
DMA_TO_DEVICE);
if (_chain_sg_buffer_in(pce_dev, sreq->src, sreq->size) < 0) {
@@ -2392,7 +2418,7 @@
return 0;
bad:
if (pce_dev->src_nents) {
- dma_unmap_sg(pce_dev->pdev, sreq->src,
+ qce_dma_unmap_sg(pce_dev->pdev, sreq->src,
pce_dev->src_nents, DMA_TO_DEVICE);
}
diff --git a/drivers/crypto/msm/qcrypto.c b/drivers/crypto/msm/qcrypto.c
index 10f83f3..b64368d 100644
--- a/drivers/crypto/msm/qcrypto.c
+++ b/drivers/crypto/msm/qcrypto.c
@@ -1,6 +1,6 @@
/* Qualcomm Crypto driver
*
- * 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
@@ -1043,7 +1043,7 @@
}
adata += len;
qreq->assoclen = ALIGN((alen + len), 16);
- for (l = alen; l > 0; sg = sg_next(sg)) {
+ for (l = alen; l > 0; sg = scatterwalk_sg_next(sg)) {
memcpy(adata, sg_virt(sg), sg->length);
l -= sg->length;
adata += sg->length;
@@ -2118,7 +2118,7 @@
{
int i;
- for (i = 0; nbytes > 0; i++, sg = sg_next(sg))
+ for (i = 0; nbytes > 0; i++, sg = scatterwalk_sg_next(sg))
nbytes -= sg->length;
return i;
diff --git a/drivers/gpu/ion/ion_cp_heap.c b/drivers/gpu/ion/ion_cp_heap.c
index d96b755..8f5addd 100644
--- a/drivers/gpu/ion/ion_cp_heap.c
+++ b/drivers/gpu/ion/ion_cp_heap.c
@@ -2,7 +2,7 @@
* drivers/gpu/ion/ion_cp_heap.c
*
* Copyright (C) 2011 Google, Inc.
- * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -469,6 +469,7 @@
{
unsigned long offset;
unsigned long secure_allocation = flags & ION_SECURE;
+ unsigned long force_contig = flags & ION_FORCE_CONTIGUOUS;
struct ion_cp_heap *cp_heap =
container_of(heap, struct ion_cp_heap, heap);
@@ -481,7 +482,8 @@
return ION_CP_ALLOCATE_FAIL;
}
- if (!secure_allocation && cp_heap->disallow_non_secure_allocation) {
+ if (!force_contig && !secure_allocation &&
+ cp_heap->disallow_non_secure_allocation) {
mutex_unlock(&cp_heap->lock);
pr_debug("%s: non-secure allocation disallowed from this heap\n",
__func__);
diff --git a/drivers/gpu/msm/Makefile b/drivers/gpu/msm/Makefile
index aacd355..fec5363 100644
--- a/drivers/gpu/msm/Makefile
+++ b/drivers/gpu/msm/Makefile
@@ -9,7 +9,8 @@
kgsl_mmu.o \
kgsl_gpummu.o \
kgsl_iommu.o \
- kgsl_snapshot.o
+ kgsl_snapshot.o \
+ kgsl_events.o
msm_kgsl_core-$(CONFIG_DEBUG_FS) += kgsl_debugfs.o
msm_kgsl_core-$(CONFIG_MSM_KGSL_CFF_DUMP) += kgsl_cffdump.o
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 24be1b0..612e34a 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2007-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2002,2007-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
@@ -1282,14 +1282,22 @@
device->ftbl->irqctrl(device, 1);
status = adreno_ringbuffer_start(&adreno_dev->ringbuffer, init_ram);
- if (status == 0) {
- /* While recovery is on we do not want timer to
- * fire and attempt to change any device state */
- if (KGSL_STATE_DUMP_AND_RECOVER != device->state)
- mod_timer(&device->idle_timer, jiffies + FIRST_TIMEOUT);
- return 0;
- }
+ if (status)
+ goto error_irq_off;
+ /*
+ * While recovery is on we do not want timer to
+ * fire and attempt to change any device state
+ */
+
+ if (KGSL_STATE_DUMP_AND_RECOVER != device->state)
+ mod_timer(&device->idle_timer, jiffies + FIRST_TIMEOUT);
+
+ device->reset_counter++;
+
+ return 0;
+
+error_irq_off:
kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
error_mmu_off:
@@ -1342,7 +1350,7 @@
adreno_context->flags |= CTXT_FLAGS_GPU_HANG;
} else if (KGSL_CTX_STAT_GUILTY_CONTEXT_RESET_EXT !=
context->reset_status) {
- if (adreno_context->flags & (CTXT_FLAGS_GPU_HANG ||
+ if (adreno_context->flags & (CTXT_FLAGS_GPU_HANG |
CTXT_FLAGS_GPU_HANG_RECOVERED))
context->reset_status =
KGSL_CTX_STAT_GUILTY_CONTEXT_RESET_EXT;
@@ -1622,6 +1630,11 @@
KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
eoptimestamp),
rb->timestamp[KGSL_MEMSTORE_GLOBAL]);
+
+ /* switch to NULL ctxt */
+ if (adreno_dev->drawctxt_active != NULL)
+ adreno_drawctxt_switch(adreno_dev, NULL, 0);
+
done:
adreno_set_max_ts_for_bad_ctxs(device);
adreno_mark_context_status(device, ret);
@@ -2142,125 +2155,89 @@
return context_id;
}
-static void adreno_next_event(struct kgsl_device *device,
- struct kgsl_event *event)
-{
- int status;
- unsigned int ref_ts, enableflag;
- unsigned int context_id = _get_context_id(event->context);
- struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
-
- status = kgsl_check_timestamp(device, event->context, event->timestamp);
- if (!status) {
- kgsl_sharedmem_readl(&device->memstore, &enableflag,
- KGSL_MEMSTORE_OFFSET(context_id, ts_cmp_enable));
- /*
- * Barrier is needed here to make sure the read from memstore
- * has posted
- */
-
- mb();
-
- if (enableflag) {
- kgsl_sharedmem_readl(&device->memstore, &ref_ts,
- KGSL_MEMSTORE_OFFSET(context_id,
- ref_wait_ts));
-
- /* Make sure the memstore read has posted */
- mb();
- if (timestamp_cmp(ref_ts, event->timestamp) >= 0) {
- kgsl_sharedmem_writel(&device->memstore,
- KGSL_MEMSTORE_OFFSET(context_id,
- ref_wait_ts), event->timestamp);
- /* Make sure the memstore write is posted */
- wmb();
- }
- } else {
- unsigned int cmds[2];
- kgsl_sharedmem_writel(&device->memstore,
- KGSL_MEMSTORE_OFFSET(context_id,
- ref_wait_ts), event->timestamp);
- enableflag = 1;
- kgsl_sharedmem_writel(&device->memstore,
- KGSL_MEMSTORE_OFFSET(context_id,
- ts_cmp_enable), enableflag);
-
- /* Make sure the memstore write gets posted */
- wmb();
-
- /*
- * submit a dummy packet so that even if all
- * commands upto timestamp get executed we will still
- * get an interrupt
- */
- cmds[0] = cp_type3_packet(CP_NOP, 1);
- cmds[1] = 0;
-
- if (adreno_dev->drawctxt_active)
- adreno_ringbuffer_issuecmds_intr(device,
- event->context, &cmds[0], 2);
- }
- }
-}
-
-static int kgsl_check_interrupt_timestamp(struct kgsl_device *device,
+static unsigned int adreno_check_hw_ts(struct kgsl_device *device,
struct kgsl_context *context, unsigned int timestamp)
{
- int status;
+ int status = 0;
unsigned int ref_ts, enableflag;
- unsigned int context_id;
+ unsigned int context_id = _get_context_id(context);
- mutex_lock(&device->mutex);
- context_id = _get_context_id(context);
/*
* If the context ID is invalid, we are in a race with
* the context being destroyed by userspace so bail.
*/
if (context_id == KGSL_CONTEXT_INVALID) {
KGSL_DRV_WARN(device, "context was detached");
- status = -EINVAL;
- goto unlock;
+ return -EINVAL;
}
status = kgsl_check_timestamp(device, context, timestamp);
- if (!status) {
- kgsl_sharedmem_readl(&device->memstore, &enableflag,
- KGSL_MEMSTORE_OFFSET(context_id, ts_cmp_enable));
- mb();
+ if (status)
+ return status;
- if (enableflag) {
- kgsl_sharedmem_readl(&device->memstore, &ref_ts,
+ kgsl_sharedmem_readl(&device->memstore, &enableflag,
+ KGSL_MEMSTORE_OFFSET(context_id, ts_cmp_enable));
+ /*
+ * Barrier is needed here to make sure the read from memstore
+ * has posted
+ */
+
+ mb();
+
+ if (enableflag) {
+ kgsl_sharedmem_readl(&device->memstore, &ref_ts,
KGSL_MEMSTORE_OFFSET(context_id,
ref_wait_ts));
- mb();
- if (timestamp_cmp(ref_ts, timestamp) >= 0) {
- kgsl_sharedmem_writel(&device->memstore,
+
+ /* Make sure the memstore read has posted */
+ mb();
+ if (timestamp_cmp(ref_ts, timestamp) >= 0) {
+ kgsl_sharedmem_writel(&device->memstore,
+ KGSL_MEMSTORE_OFFSET(context_id,
+ ref_wait_ts), timestamp);
+ /* Make sure the memstore write is posted */
+ wmb();
+ }
+ } else {
+ kgsl_sharedmem_writel(&device->memstore,
KGSL_MEMSTORE_OFFSET(context_id,
ref_wait_ts), timestamp);
- wmb();
- }
- } else {
- unsigned int cmds[2];
- kgsl_sharedmem_writel(&device->memstore,
- KGSL_MEMSTORE_OFFSET(context_id,
- ref_wait_ts), timestamp);
- enableflag = 1;
- kgsl_sharedmem_writel(&device->memstore,
+ enableflag = 1;
+ kgsl_sharedmem_writel(&device->memstore,
KGSL_MEMSTORE_OFFSET(context_id,
ts_cmp_enable), enableflag);
- wmb();
- /* submit a dummy packet so that even if all
- * commands upto timestamp get executed we will still
- * get an interrupt */
- cmds[0] = cp_type3_packet(CP_NOP, 1);
- cmds[1] = 0;
- if (context)
- adreno_ringbuffer_issuecmds_intr(device,
- context, &cmds[0], 2);
+ /* Make sure the memstore write gets posted */
+ wmb();
+
+ /*
+ * submit a dummy packet so that even if all
+ * commands upto timestamp get executed we will still
+ * get an interrupt
+ */
+
+ if (context) {
+ adreno_ringbuffer_issuecmds(device, context->devctxt,
+ KGSL_CMD_FLAGS_NONE, NULL, 0);
}
}
-unlock:
+
+ return 0;
+}
+
+static void adreno_next_event(struct kgsl_device *device,
+ struct kgsl_event *event)
+{
+ adreno_check_hw_ts(device, event->context, event->timestamp);
+}
+
+static int adreno_check_interrupt_timestamp(struct kgsl_device *device,
+ struct kgsl_context *context, unsigned int timestamp)
+{
+ int status;
+
+ mutex_lock(&device->mutex);
+ status = adreno_check_hw_ts(device, context, timestamp);
mutex_unlock(&device->mutex);
return status;
@@ -2497,7 +2474,7 @@
/* Wait for a timestamp event */
status = kgsl_wait_event_interruptible_timeout(
device->wait_queue,
- kgsl_check_interrupt_timestamp(device, context,
+ adreno_check_interrupt_timestamp(device, context,
timestamp), msecs_to_jiffies(wait), io);
mutex_lock(&device->mutex);
diff --git a/drivers/gpu/msm/adreno_a3xx_snapshot.c b/drivers/gpu/msm/adreno_a3xx_snapshot.c
index de95951..713ef1a 100644
--- a/drivers/gpu/msm/adreno_a3xx_snapshot.c
+++ b/drivers/gpu/msm/adreno_a3xx_snapshot.c
@@ -24,6 +24,22 @@
#define SHADER_MEMORY_SIZE 0x4000
/**
+ * _rbbm_debug_bus_read - Helper function to read data from the RBBM
+ * debug bus.
+ * @device - GPU device to read/write registers
+ * @block_id - Debug bus block to read from
+ * @index - Index in the debug bus block to read
+ * @ret - Value of the register read
+ */
+static void _rbbm_debug_bus_read(struct kgsl_device *device,
+ unsigned int block_id, unsigned int index, unsigned int *val)
+{
+ unsigned int block = (block_id << 8) | 1 << 16;
+ adreno_regwrite(device, A3XX_RBBM_DEBUG_BUS_CTL, block | index);
+ adreno_regread(device, A3XX_RBBM_DEBUG_BUS_DATA_STATUS, val);
+}
+
+/**
* a3xx_snapshot_shader_memory - Helper function to dump the GPU shader
* memory to the snapshot buffer.
* @device - GPU device whose shader memory is to be dumped
@@ -260,7 +276,6 @@
struct kgsl_snapshot_debugbus *header = snapshot;
struct debugbus_block *block = priv;
- unsigned int val;
int i;
unsigned int *data = snapshot + sizeof(*header);
unsigned int dwords;
@@ -282,16 +297,11 @@
return 0;
}
- val = (block->block_id << 8) | (1 << 16);
-
header->id = block->block_id;
header->count = dwords;
- for (i = 0; i < dwords; i++) {
- adreno_regwrite(device, A3XX_RBBM_DEBUG_BUS_CTL, val | i);
- adreno_regread(device, A3XX_RBBM_DEBUG_BUS_DATA_STATUS,
- &data[i]);
- }
+ for (i = 0; i < dwords; i++)
+ _rbbm_debug_bus_read(device, block->block_id, i, &data[i]);
return size;
}
@@ -353,18 +363,58 @@
struct kgsl_snapshot_registers_list *list,
struct adreno_device *adreno_dev)
{
- /* HLSQ specific registers */
+ struct kgsl_device *device = &adreno_dev->dev;
+
/*
- * Don't dump any a3xx HLSQ registers just yet. Reading the HLSQ
- * registers can cause the device to hang if the HLSQ block is
- * busy. Add specific checks for each a3xx core as the requirements
- * are discovered. Disable by default for now.
+ * Trying to read HLSQ registers when the HLSQ block is busy
+ * will cause the device to hang. The RBBM_DEBUG_BUS has information
+ * that will tell us if the HLSQ block is busy or not. Read values
+ * from the debug bus to ensure the HLSQ block is not busy (this
+ * is hardware dependent). If the HLSQ block is busy do not
+ * dump the registers, otherwise dump the HLSQ registers.
*/
- if (!adreno_is_a3xx(adreno_dev)) {
- regs[list->count].regs = (unsigned int *) a3xx_hlsq_registers;
- regs[list->count].count = a3xx_hlsq_registers_count;
- list->count++;
+
+ if (adreno_is_a330(adreno_dev)) {
+ /*
+ * stall_ctxt_full status bit: RBBM_BLOCK_ID_HLSQ index 49 [27]
+ *
+ * if (!stall_context_full)
+ * then dump HLSQ registers
+ */
+ unsigned int stall_context_full = 0;
+
+ _rbbm_debug_bus_read(device, RBBM_BLOCK_ID_HLSQ, 49,
+ &stall_context_full);
+ stall_context_full &= 0x08000000;
+
+ if (stall_context_full)
+ return;
+ } else {
+ /*
+ * tpif status bits: RBBM_BLOCK_ID_HLSQ index 4 [4:0]
+ * spif status bits: RBBM_BLOCK_ID_HLSQ index 7 [5:0]
+ *
+ * if ((tpif == 0, 1, 28) && (spif == 0, 1, 10))
+ * then dump HLSQ registers
+ */
+ unsigned int next_pif = 0;
+
+ /* check tpif */
+ _rbbm_debug_bus_read(device, RBBM_BLOCK_ID_HLSQ, 4, &next_pif);
+ next_pif &= 0x1f;
+ if (next_pif != 0 && next_pif != 1 && next_pif != 28)
+ return;
+
+ /* check spif */
+ _rbbm_debug_bus_read(device, RBBM_BLOCK_ID_HLSQ, 7, &next_pif);
+ next_pif &= 0x3f;
+ if (next_pif != 0 && next_pif != 1 && next_pif != 10)
+ return;
}
+
+ regs[list->count].regs = (unsigned int *) a3xx_hlsq_registers;
+ regs[list->count].count = a3xx_hlsq_registers_count;
+ list->count++;
}
static void _snapshot_a330_regs(struct kgsl_snapshot_registers *regs,
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index 97b35b0..03828c6 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2007-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2002,2007-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
@@ -745,30 +745,6 @@
return timestamp;
}
-void
-adreno_ringbuffer_issuecmds_intr(struct kgsl_device *device,
- struct kgsl_context *k_ctxt,
- unsigned int *cmds,
- int sizedwords)
-{
- struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
- struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
- struct adreno_context *a_ctxt = NULL;
-
- if (!k_ctxt)
- return;
-
- a_ctxt = k_ctxt->devctxt;
-
- if (k_ctxt->id == KGSL_CONTEXT_INVALID ||
- a_ctxt == NULL ||
- device->state & KGSL_STATE_HUNG)
- return;
-
- adreno_ringbuffer_addcmds(rb, a_ctxt, KGSL_CMD_FLAGS_INTERNAL_ISSUE,
- cmds, sizedwords, 0);
-}
-
unsigned int
adreno_ringbuffer_issuecmds(struct kgsl_device *device,
struct adreno_context *drawctxt,
@@ -1071,10 +1047,6 @@
0,
&link[0], (cmds - link), *timestamp);
- KGSL_CMD_INFO(device, "<%d:0x%x> g %08x numibs %d\n",
- context->id, *timestamp, (unsigned int)ibdesc, numibs);
-
-
#ifdef CONFIG_MSM_KGSL_CFF_DUMP
/*
* insert wait for idle after every IB1
diff --git a/drivers/gpu/msm/adreno_ringbuffer.h b/drivers/gpu/msm/adreno_ringbuffer.h
index 50d9c25..e87b506 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.h
+++ b/drivers/gpu/msm/adreno_ringbuffer.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2007-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2002,2007-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -110,11 +110,6 @@
unsigned int *cmdaddr,
int sizedwords);
-void adreno_ringbuffer_issuecmds_intr(struct kgsl_device *device,
- struct kgsl_context *k_ctxt,
- unsigned int *cmdaddr,
- int sizedwords);
-
void adreno_ringbuffer_submit(struct adreno_ringbuffer *rb);
void kgsl_cp_intrcallback(struct kgsl_device *device);
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 9cde1d7..f234d67 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2008-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
@@ -53,147 +53,6 @@
static struct ion_client *kgsl_ion_client;
-/**
- * kgsl_add_event - Add a new timstamp event for the KGSL device
- * @device - KGSL device for the new event
- * @ts - the timestamp to trigger the event on
- * @cb - callback function to call when the timestamp expires
- * @priv - private data for the specific event type
- * @owner - driver instance that owns this event
- *
- * @returns - 0 on success or error code on failure
- */
-
-int kgsl_add_event(struct kgsl_device *device, u32 id, u32 ts,
- void (*cb)(struct kgsl_device *, void *, u32, u32), void *priv,
- void *owner)
-{
- struct kgsl_event *event;
- struct list_head *n;
- unsigned int cur_ts;
- struct kgsl_context *context = NULL;
-
- if (cb == NULL)
- return -EINVAL;
-
- if (id != KGSL_MEMSTORE_GLOBAL) {
- context = idr_find(&device->context_idr, id);
- if (context == NULL)
- return -EINVAL;
- }
- cur_ts = kgsl_readtimestamp(device, context, KGSL_TIMESTAMP_RETIRED);
-
- /* Check to see if the requested timestamp has already fired */
-
- if (timestamp_cmp(cur_ts, ts) >= 0) {
- cb(device, priv, id, cur_ts);
- return 0;
- }
-
- event = kzalloc(sizeof(*event), GFP_KERNEL);
- if (event == NULL)
- return -ENOMEM;
-
- event->context = context;
- event->timestamp = ts;
- event->priv = priv;
- event->func = cb;
- event->owner = owner;
-
- /*
- * Add the event in order to the list. Order is by context id
- * first and then by timestamp for that context.
- */
-
- for (n = device->events.next ; n != &device->events; n = n->next) {
- struct kgsl_event *e =
- list_entry(n, struct kgsl_event, list);
-
- if (e->context != context)
- continue;
-
- if (timestamp_cmp(e->timestamp, ts) > 0) {
- list_add(&event->list, n->prev);
- break;
- }
- }
-
- if (n == &device->events)
- list_add_tail(&event->list, &device->events);
-
- queue_work(device->work_queue, &device->ts_expired_ws);
- return 0;
-}
-EXPORT_SYMBOL(kgsl_add_event);
-
-/**
- * kgsl_cancel_events_ctxt - Cancel all events for a context
- * @device - KGSL device for the events to cancel
- * @ctxt - context whose events we want to cancel
- *
- */
-static void kgsl_cancel_events_ctxt(struct kgsl_device *device,
- struct kgsl_context *context)
-{
- struct kgsl_event *event, *event_tmp;
- unsigned int id, cur;
-
- cur = kgsl_readtimestamp(device, context, KGSL_TIMESTAMP_RETIRED);
- id = context->id;
-
- list_for_each_entry_safe(event, event_tmp, &device->events, list) {
- if (event->context != context)
- continue;
-
- /*
- * "cancel" the events by calling their callback.
- * Currently, events are used for lock and memory
- * management, so if the process is dying the right
- * thing to do is release or free.
- */
- if (event->func)
- event->func(device, event->priv, id, cur);
-
- list_del(&event->list);
- kfree(event);
- }
-}
-
-/**
- * kgsl_cancel_events - Cancel all events for a process
- * @device - KGSL device for the events to cancel
- * @owner - driver instance that owns the events to cancel
- *
- */
-void kgsl_cancel_events(struct kgsl_device *device,
- void *owner)
-{
- struct kgsl_event *event, *event_tmp;
- unsigned int id, cur;
-
- list_for_each_entry_safe(event, event_tmp, &device->events, list) {
- if (event->owner != owner)
- continue;
-
- cur = kgsl_readtimestamp(device, event->context,
- KGSL_TIMESTAMP_RETIRED);
-
- id = event->context ? event->context->id : KGSL_MEMSTORE_GLOBAL;
- /*
- * "cancel" the events by calling their callback.
- * Currently, events are used for lock and memory
- * management, so if the process is dying the right
- * thing to do is release or free.
- */
- if (event->func)
- event->func(device, event->priv, id, cur);
-
- list_del(&event->list);
- kfree(event);
- }
-}
-EXPORT_SYMBOL(kgsl_cancel_events);
-
int kgsl_memfree_hist_init(void)
{
void *base;
@@ -486,6 +345,20 @@
goto func_end;
}
+ /* Initialize the pending event list */
+ INIT_LIST_HEAD(&context->events);
+
+ /*
+ * Initialize the node that is used to maintain the master list of
+ * contexts with pending events in the device structure. Normally we
+ * wouldn't take the time to initalize a node but at event add time we
+ * call list_empty() on the node as a quick way of determining if the
+ * context is already in the master list so it needs to always be either
+ * active or in an unused but initialized state
+ */
+
+ INIT_LIST_HEAD(&context->events_list);
+
func_end:
if (ret) {
kfree(context);
@@ -540,52 +413,6 @@
kfree(context);
}
-void kgsl_timestamp_expired(struct work_struct *work)
-{
- struct kgsl_device *device = container_of(work, struct kgsl_device,
- ts_expired_ws);
- struct kgsl_event *event, *event_tmp;
- uint32_t ts_processed;
- unsigned int id;
-
- mutex_lock(&device->mutex);
-
- /* Process expired events */
- list_for_each_entry_safe(event, event_tmp, &device->events, list) {
- ts_processed = kgsl_readtimestamp(device, event->context,
- KGSL_TIMESTAMP_RETIRED);
- if (timestamp_cmp(ts_processed, event->timestamp) < 0)
- continue;
-
- id = event->context ? event->context->id : KGSL_MEMSTORE_GLOBAL;
-
- if (event->func)
- event->func(device, event->priv, id, ts_processed);
-
- list_del(&event->list);
- kfree(event);
- }
-
- /* Send the next pending event for each context to the device */
- if (device->ftbl->next_event) {
- unsigned int id = KGSL_MEMSTORE_GLOBAL;
-
- list_for_each_entry(event, &device->events, list) {
-
- if (!event->context)
- continue;
-
- if (event->context->id != id) {
- device->ftbl->next_event(device, event);
- id = event->context->id;
- }
- }
- }
-
- mutex_unlock(&device->mutex);
-}
-EXPORT_SYMBOL(kgsl_timestamp_expired);
-
static void kgsl_check_idle_locked(struct kgsl_device *device)
{
if (device->pwrctrl.nap_allowed == true &&
@@ -690,7 +517,7 @@
INIT_COMPLETION(device->hwaccess_gate);
device->ftbl->suspend_context(device);
device->ftbl->stop(device);
- pm_qos_update_request(&device->pm_qos_req_dma,
+ pm_qos_update_request(&device->pwrctrl.pm_qos_req_dma,
PM_QOS_DEFAULT_VALUE);
kgsl_pwrctrl_set_state(device, KGSL_STATE_SUSPEND);
break;
@@ -3136,7 +2963,8 @@
goto error_close_mmu;
}
- pm_qos_add_request(&device->pm_qos_req_dma, PM_QOS_CPU_DMA_LATENCY,
+ pm_qos_add_request(&device->pwrctrl.pm_qos_req_dma,
+ PM_QOS_CPU_DMA_LATENCY,
PM_QOS_DEFAULT_VALUE);
/* Initalize the snapshot engine */
@@ -3247,7 +3075,7 @@
kgsl_cffdump_close(device->id);
kgsl_pwrctrl_uninit_sysfs(device);
- pm_qos_remove_request(&device->pm_qos_req_dma);
+ pm_qos_remove_request(&device->pwrctrl.pm_qos_req_dma);
idr_destroy(&device->context_idr);
diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h
index 72e7776..3eb8831 100644
--- a/drivers/gpu/msm/kgsl.h
+++ b/drivers/gpu/msm/kgsl.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2008-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
@@ -89,6 +89,7 @@
struct kgsl_device;
+struct kgsl_context;
struct kgsl_driver {
struct cdev cdev;
@@ -217,6 +218,9 @@
void kgsl_cancel_events(struct kgsl_device *device,
void *owner);
+void kgsl_cancel_events_ctxt(struct kgsl_device *device,
+ struct kgsl_context *context);
+
extern const struct dev_pm_ops kgsl_pm_ops;
struct early_suspend;
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index ce3820c..557ce23 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2007-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2002,2007-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
@@ -212,17 +212,19 @@
int pwr_log;
struct kgsl_pwrscale pwrscale;
struct kobject pwrscale_kobj;
- struct pm_qos_request pm_qos_req_dma;
struct work_struct ts_expired_ws;
struct list_head events;
+ struct list_head events_pending_list;
s64 on_time;
/* Postmortem Control switches */
int pm_regs_enabled;
int pm_ib_enabled;
+
+ int reset_counter; /* Track how many GPU core resets have occured */
};
-void kgsl_timestamp_expired(struct work_struct *work);
+void kgsl_process_events(struct work_struct *work);
#define KGSL_DEVICE_COMMON_INIT(_dev) \
.hwaccess_gate = COMPLETION_INITIALIZER((_dev).hwaccess_gate),\
@@ -231,36 +233,42 @@
.idle_check_ws = __WORK_INITIALIZER((_dev).idle_check_ws,\
kgsl_idle_check),\
.ts_expired_ws = __WORK_INITIALIZER((_dev).ts_expired_ws,\
- kgsl_timestamp_expired),\
+ kgsl_process_events),\
.context_idr = IDR_INIT((_dev).context_idr),\
.events = LIST_HEAD_INIT((_dev).events),\
+ .events_pending_list = LIST_HEAD_INIT((_dev).events_pending_list), \
.wait_queue = __WAIT_QUEUE_HEAD_INITIALIZER((_dev).wait_queue),\
.mutex = __MUTEX_INITIALIZER((_dev).mutex),\
.state = KGSL_STATE_INIT,\
.ver_major = DRIVER_VERSION_MAJOR,\
.ver_minor = DRIVER_VERSION_MINOR
+
+/**
+ * struct kgsl_context - Master structure for a KGSL context object
+ * @refcount - kref object for reference counting the context
+ * @id - integer identifier for the context
+ * @dev_priv - pointer to the owning device instance
+ * @devctxt - pointer to the device specific context information
+ * @reset_status - status indication whether a gpu reset occured and whether
+ * this context was responsible for causing it
+ * @wait_on_invalid_ts - flag indicating if this context has tried to wait on a
+ * bad timestamp
+ * @timeline - sync timeline used to create fences that can be signaled when a
+ * sync_pt timestamp expires
+ * @events - list head of pending events for this context
+ * @events_list - list node for the list of all contexts that have pending events
+ */
struct kgsl_context {
struct kref refcount;
uint32_t id;
-
- /* Pointer to the owning device instance */
struct kgsl_device_private *dev_priv;
-
- /* Pointer to the device specific context information */
void *devctxt;
- /*
- * Status indicating whether a gpu reset occurred and whether this
- * context was responsible for causing it
- */
unsigned int reset_status;
- /* Flag indicating if we tried to wait for bad timestamp for this ctx */
bool wait_on_invalid_ts;
- /*
- * Timeline used to create fences that can be signaled when a
- * sync_pt timestamp expires.
- */
struct sync_timeline *timeline;
+ struct list_head events;
+ struct list_head events_list;
};
struct kgsl_process_private {
diff --git a/drivers/gpu/msm/kgsl_events.c b/drivers/gpu/msm/kgsl_events.c
new file mode 100644
index 0000000..2002537
--- /dev/null
+++ b/drivers/gpu/msm/kgsl_events.c
@@ -0,0 +1,251 @@
+/* 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <kgsl_device.h>
+
+static void _add_event_to_list(struct list_head *head, struct kgsl_event *event)
+{
+ struct list_head *n;
+
+ for (n = head->next; n != head; n = n->next) {
+ struct kgsl_event *e =
+ list_entry(n, struct kgsl_event, list);
+
+ if (timestamp_cmp(e->timestamp, event->timestamp) > 0) {
+ list_add(&event->list, n->prev);
+ break;
+ }
+ }
+
+ if (n == head)
+ list_add_tail(&event->list, head);
+}
+
+/**
+ * kgsl_add_event - Add a new timstamp event for the KGSL device
+ * @device - KGSL device for the new event
+ * @id - the context ID that the event should be added to
+ * @ts - the timestamp to trigger the event on
+ * @cb - callback function to call when the timestamp expires
+ * @priv - private data for the specific event type
+ * @owner - driver instance that owns this event
+ *
+ * @returns - 0 on success or error code on failure
+ */
+int kgsl_add_event(struct kgsl_device *device, u32 id, u32 ts,
+ void (*cb)(struct kgsl_device *, void *, u32, u32), void *priv,
+ void *owner)
+{
+ struct kgsl_event *event;
+ unsigned int cur_ts;
+ struct kgsl_context *context = NULL;
+
+ if (cb == NULL)
+ return -EINVAL;
+
+ if (id != KGSL_MEMSTORE_GLOBAL) {
+ context = idr_find(&device->context_idr, id);
+ if (context == NULL)
+ return -EINVAL;
+ }
+ cur_ts = kgsl_readtimestamp(device, context, KGSL_TIMESTAMP_RETIRED);
+
+ /* Check to see if the requested timestamp has already fired */
+
+ if (timestamp_cmp(cur_ts, ts) >= 0) {
+ cb(device, priv, id, cur_ts);
+ return 0;
+ }
+
+ event = kzalloc(sizeof(*event), GFP_KERNEL);
+ if (event == NULL)
+ return -ENOMEM;
+
+ event->context = context;
+ event->timestamp = ts;
+ event->priv = priv;
+ event->func = cb;
+ event->owner = owner;
+
+ /* Add the event to either the owning context or the global list */
+
+ if (context) {
+ _add_event_to_list(&context->events, event);
+
+ /*
+ * Add it to the master list of contexts with pending events if
+ * it isn't already there
+ */
+
+ if (list_empty(&context->events_list))
+ list_add_tail(&context->events_list,
+ &device->events_pending_list);
+
+ } else
+ _add_event_to_list(&device->events, event);
+
+ queue_work(device->work_queue, &device->ts_expired_ws);
+ return 0;
+}
+EXPORT_SYMBOL(kgsl_add_event);
+
+/**
+ * kgsl_cancel_events_ctxt - Cancel all events for a context
+ * @device - KGSL device for the events to cancel
+ * @context - context whose events we want to cancel
+ *
+ */
+void kgsl_cancel_events_ctxt(struct kgsl_device *device,
+ struct kgsl_context *context)
+{
+ struct kgsl_event *event, *event_tmp;
+ unsigned int id, cur;
+
+ cur = kgsl_readtimestamp(device, context, KGSL_TIMESTAMP_RETIRED);
+ id = context->id;
+
+ list_for_each_entry_safe(event, event_tmp, &context->events, list) {
+ /*
+ * "cancel" the events by calling their callback.
+ * Currently, events are used for lock and memory
+ * management, so if the process is dying the right
+ * thing to do is release or free.
+ */
+ if (event->func)
+ event->func(device, event->priv, id, cur);
+
+ list_del(&event->list);
+ kfree(event);
+ }
+
+ /* Remove ourselves from the master pending list */
+ list_del_init(&context->events_list);
+}
+
+/**
+ * kgsl_cancel_events - Cancel all generic events for a process
+ * @device - KGSL device for the events to cancel
+ * @owner - driver instance that owns the events to cancel
+ *
+ */
+void kgsl_cancel_events(struct kgsl_device *device,
+ void *owner)
+{
+ struct kgsl_event *event, *event_tmp;
+ unsigned int cur;
+
+ cur = kgsl_readtimestamp(device, NULL, KGSL_TIMESTAMP_RETIRED);
+
+ list_for_each_entry_safe(event, event_tmp, &device->events, list) {
+ if (event->owner != owner)
+ continue;
+
+ /*
+ * "cancel" the events by calling their callback.
+ * Currently, events are used for lock and memory
+ * management, so if the process is dying the right
+ * thing to do is release or free.
+ */
+ if (event->func)
+ event->func(device, event->priv, KGSL_MEMSTORE_GLOBAL,
+ cur);
+
+ list_del(&event->list);
+ kfree(event);
+ }
+}
+EXPORT_SYMBOL(kgsl_cancel_events);
+
+static void _process_event_list(struct kgsl_device *device,
+ struct list_head *head, unsigned int timestamp)
+{
+ struct kgsl_event *event, *tmp;
+ unsigned int id;
+
+ list_for_each_entry_safe(event, tmp, head, list) {
+ if (timestamp_cmp(timestamp, event->timestamp) < 0)
+ break;
+
+ id = event->context ? event->context->id : KGSL_MEMSTORE_GLOBAL;
+
+ if (event->func)
+ event->func(device, event->priv, id, timestamp);
+
+ list_del(&event->list);
+ kfree(event);
+ }
+}
+
+static inline void _mark_next_event(struct kgsl_device *device,
+ struct list_head *head)
+{
+ struct kgsl_event *event;
+
+ if (!list_empty(head)) {
+ event = list_first_entry(head, struct kgsl_event, list);
+ device->ftbl->next_event(device, event);
+ }
+}
+
+static int kgsl_process_context_events(struct kgsl_device *device,
+ struct kgsl_context *context)
+{
+ unsigned int timestamp = kgsl_readtimestamp(device, context,
+ KGSL_TIMESTAMP_RETIRED);
+
+ _process_event_list(device, &context->events, timestamp);
+
+ /* Mark the next pending event on the list to fire an interrupt */
+ _mark_next_event(device, &context->events);
+
+ /*
+ * Return 0 if the list is empty so the calling function can remove the
+ * context from the pending list
+ */
+
+ return list_empty(&context->events) ? 0 : 1;
+}
+
+void kgsl_process_events(struct work_struct *work)
+{
+ struct kgsl_device *device = container_of(work, struct kgsl_device,
+ ts_expired_ws);
+ struct kgsl_context *context, *tmp;
+ uint32_t timestamp;
+
+ mutex_lock(&device->mutex);
+
+ /* Process expired global events */
+ timestamp = kgsl_readtimestamp(device, NULL, KGSL_TIMESTAMP_RETIRED);
+ _process_event_list(device, &device->events, timestamp);
+ _mark_next_event(device, &device->events);
+
+ /* Now process all of the pending contexts */
+ list_for_each_entry_safe(context, tmp, &device->events_pending_list,
+ events_list) {
+
+ /*
+ * If kgsl_timestamp_expired_context returns 0 then it no longer
+ * has any pending events and can be removed from the list
+ */
+
+ if (kgsl_process_context_events(device, context) == 0)
+ list_del_init(&context->events_list);
+ }
+
+ mutex_unlock(&device->mutex);
+}
+EXPORT_SYMBOL(kgsl_process_events);
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 73c8df1..8311a2d 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.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
@@ -30,7 +30,6 @@
#define KGSL_PWRFLAGS_AXI_ON 2
#define KGSL_PWRFLAGS_IRQ_ON 3
-#define GPU_SWFI_LATENCY 3
#define UPDATE_BUSY_VAL 1000000
#define UPDATE_BUSY 50
@@ -555,6 +554,42 @@
device->pwrctrl.interval_timeout);
}
+static int kgsl_pwrctrl_pmqos_latency_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ char temp[20];
+ unsigned long val;
+ struct kgsl_device *device = kgsl_device_from_dev(dev);
+ int rc;
+
+ if (device == NULL)
+ return 0;
+
+ snprintf(temp, sizeof(temp), "%.*s",
+ (int)min(count, sizeof(temp) - 1), buf);
+ rc = kstrtoul(temp, 0, &val);
+ if (rc)
+ return rc;
+
+ mutex_lock(&device->mutex);
+ device->pwrctrl.pm_qos_latency = val;
+ mutex_unlock(&device->mutex);
+
+ return count;
+}
+
+static int kgsl_pwrctrl_pmqos_latency_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct kgsl_device *device = kgsl_device_from_dev(dev);
+ if (device == NULL)
+ return 0;
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ device->pwrctrl.pm_qos_latency);
+}
+
static int kgsl_pwrctrl_gpubusy_show(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -616,6 +651,14 @@
return num_chars;
}
+static int kgsl_pwrctrl_reset_count_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct kgsl_device *device = kgsl_device_from_dev(dev);
+ return snprintf(buf, PAGE_SIZE, "%d\n", device->reset_counter);
+}
+
DEVICE_ATTR(gpuclk, 0644, kgsl_pwrctrl_gpuclk_show, kgsl_pwrctrl_gpuclk_store);
DEVICE_ATTR(max_gpuclk, 0644, kgsl_pwrctrl_max_gpuclk_show,
kgsl_pwrctrl_max_gpuclk_store);
@@ -641,6 +684,12 @@
DEVICE_ATTR(num_pwrlevels, 0444,
kgsl_pwrctrl_num_pwrlevels_show,
NULL);
+DEVICE_ATTR(pmqos_latency, 0644,
+ kgsl_pwrctrl_pmqos_latency_show,
+ kgsl_pwrctrl_pmqos_latency_store);
+DEVICE_ATTR(reset_count, 0444,
+ kgsl_pwrctrl_reset_count_show,
+ NULL);
static const struct device_attribute *pwrctrl_attr_list[] = {
&dev_attr_gpuclk,
@@ -654,6 +703,8 @@
&dev_attr_min_pwrlevel,
&dev_attr_thermal_pwrlevel,
&dev_attr_num_pwrlevels,
+ &dev_attr_pmqos_latency,
+ &dev_attr_reset_count,
NULL
};
@@ -951,6 +1002,8 @@
}
}
+ /* Set the CPU latency to 501usec to allow low latency PC modes */
+ pwr->pm_qos_latency = 501;
pm_runtime_enable(device->parentdev);
register_early_suspend(&device->display_off);
@@ -1147,7 +1200,7 @@
_sleep_accounting(device);
kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_OFF, KGSL_STATE_SLEEP);
kgsl_pwrctrl_set_state(device, KGSL_STATE_SLEEP);
- pm_qos_update_request(&device->pm_qos_req_dma,
+ pm_qos_update_request(&device->pwrctrl.pm_qos_req_dma,
PM_QOS_DEFAULT_VALUE);
break;
case KGSL_STATE_SLEEP:
@@ -1181,7 +1234,7 @@
device->ftbl->stop(device);
_sleep_accounting(device);
kgsl_pwrctrl_set_state(device, KGSL_STATE_SLUMBER);
- pm_qos_update_request(&device->pm_qos_req_dma,
+ pm_qos_update_request(&device->pwrctrl.pm_qos_req_dma,
PM_QOS_DEFAULT_VALUE);
break;
case KGSL_STATE_SLUMBER:
@@ -1267,8 +1320,8 @@
/* Re-enable HW access */
mod_timer(&device->idle_timer,
jiffies + device->pwrctrl.interval_timeout);
- pm_qos_update_request(&device->pm_qos_req_dma,
- GPU_SWFI_LATENCY);
+ pm_qos_update_request(&device->pwrctrl.pm_qos_req_dma,
+ device->pwrctrl.pm_qos_latency);
case KGSL_STATE_ACTIVE:
kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
break;
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.h b/drivers/gpu/msm/kgsl_pwrctrl.h
index e51ec54..72ad4d1 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.h
+++ b/drivers/gpu/msm/kgsl_pwrctrl.h
@@ -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
@@ -60,6 +60,8 @@
* @irq_name - resource name for the IRQ
* @restore_slumber - Flag to indicate that we are in a suspend/restore sequence
* @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
*/
struct kgsl_pwrctrl {
@@ -85,6 +87,8 @@
s64 time;
unsigned int restore_slumber;
struct kgsl_clk_stats clk_stats;
+ struct pm_qos_request pm_qos_req_dma;
+ unsigned int pm_qos_latency;
};
void kgsl_pwrctrl_irq(struct kgsl_device *device, int state);
diff --git a/drivers/gpu/msm/z180.c b/drivers/gpu/msm/z180.c
index 258dcfa..8f03ccb 100644
--- a/drivers/gpu/msm/z180.c
+++ b/drivers/gpu/msm/z180.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2007-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2002,2007-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
@@ -576,6 +576,9 @@
mod_timer(&device->idle_timer, jiffies + FIRST_TIMEOUT);
kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_ON);
device->ftbl->irqctrl(device, 1);
+
+ device->reset_counter++;
+
return 0;
error_clk_off:
diff --git a/drivers/hwmon/pm8xxx-adc-scale.c b/drivers/hwmon/pm8xxx-adc-scale.c
index 4a1f58c..56c352a 100644
--- a/drivers/hwmon/pm8xxx-adc-scale.c
+++ b/drivers/hwmon/pm8xxx-adc-scale.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011-2012, Code Aurora Forum. 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
@@ -271,172 +271,174 @@
};
static const struct pm8xxx_adc_map_pt adcmap_ntcg_104ef_104fb[] = {
- {696483, -40960},
- {649148, -39936},
- {605368, -38912},
- {564809, -37888},
- {527215, -36864},
- {492322, -35840},
- {460007, -34816},
- {429982, -33792},
- {402099, -32768},
- {376192, -31744},
- {352075, -30720},
- {329714, -29696},
- {308876, -28672},
- {289480, -27648},
- {271417, -26624},
- {254574, -25600},
- {238903, -24576},
- {224276, -23552},
- {210631, -22528},
- {197896, -21504},
- {186007, -20480},
- {174899, -19456},
- {164521, -18432},
- {154818, -17408},
- {145744, -16384},
- {137265, -15360},
- {129307, -14336},
- {121866, -13312},
- {114896, -12288},
- {108365, -11264},
- {102252, -10240},
- {96499, -9216},
- {91111, -8192},
- {86055, -7168},
- {81308, -6144},
- {76857, -5120},
- {72660, -4096},
- {68722, -3072},
- {65020, -2048},
- {61538, -1024},
- {58261, 0},
- {55177, 1024},
- {52274, 2048},
- {49538, 3072},
- {46962, 4096},
- {44531, 5120},
- {42243, 6144},
- {40083, 7168},
- {38045, 8192},
- {36122, 9216},
- {34308, 10240},
- {32592, 11264},
- {30972, 12288},
- {29442, 13312},
- {27995, 14336},
- {26624, 15360},
- {25333, 16384},
- {24109, 17408},
- {22951, 18432},
- {21854, 19456},
- {20807, 20480},
- {19831, 21504},
- {18899, 22528},
- {18016, 23552},
- {17178, 24576},
- {16384, 25600},
- {15631, 26624},
- {14916, 27648},
- {14237, 28672},
- {13593, 29696},
- {12976, 30720},
- {12400, 31744},
- {11848, 32768},
- {11324, 33792},
- {10825, 34816},
- {10354, 35840},
- {9900, 36864},
- {9471, 37888},
- {9062, 38912},
- {8674, 39936},
- {8306, 40960},
- {7951, 41984},
- {7616, 43008},
- {7296, 44032},
- {6991, 45056},
- {6701, 46080},
- {6424, 47104},
- {6160, 48128},
- {5908, 49152},
- {5667, 50176},
- {5439, 51200},
- {5219, 52224},
- {5010, 53248},
- {4810, 54272},
- {4619, 55296},
- {4440, 56320},
- {4263, 57344},
- {4097, 58368},
- {3938, 59392},
- {3785, 60416},
- {3637, 61440},
- {3501, 62464},
- {3368, 63488},
- {3240, 64512},
- {3118, 65536},
- {2998, 66560},
- {2889, 67584},
- {2782, 68608},
- {2680, 69632},
- {2581, 70656},
- {2490, 71680},
- {2397, 72704},
- {2310, 73728},
- {2227, 74752},
- {2147, 75776},
- {2064, 76800},
- {1998, 77824},
- {1927, 78848},
- {1860, 79872},
- {1795, 80896},
- {1736, 81920},
- {1673, 82944},
- {1615, 83968},
- {1560, 84992},
- {1507, 86016},
- {1456, 87040},
- {1407, 88064},
- {1360, 89088},
- {1314, 90112},
- {1271, 91136},
- {1228, 92160},
- {1189, 93184},
- {1150, 94208},
- {1112, 95232},
- {1076, 96256},
- {1042, 97280},
- {1008, 98304},
- {976, 99328},
- {945, 100352},
- {915, 101376},
+ {374682, -40960},
+ {360553, -39936},
+ {346630, -38912},
+ {332940, -37888},
+ {319510, -36864},
+ {306363, -35840},
+ {293521, -34816},
+ {281001, -33792},
+ {268818, -32768},
+ {256987, -31744},
+ {245516, -30720},
+ {234413, -29696},
+ {223685, -28672},
+ {213333, -27648},
+ {203360, -26624},
+ {193763, -25600},
+ {184541, -24576},
+ {175691, -23552},
+ {167205, -22528},
+ {159079, -21504},
+ {151304, -20480},
+ {143872, -19456},
+ {136775, -18432},
+ {130001, -17408},
+ {123542, -16384},
+ {117387, -15360},
+ {111526, -14336},
+ {105946, -13312},
+ {100639, -12288},
+ {95592, -11264},
+ {90795, -10240},
+ {86238, -9216},
+ {81909, -8192},
+ {77800, -7168},
+ {73899, -6144},
+ {70197, -5120},
+ {66685, -4096},
+ {63354, -3072},
+ {60194, -2048},
+ {57198, -1024},
+ {54356, 0},
+ {51662, 1024},
+ {49108, 2048},
+ {46687, 3072},
+ {44391, 4096},
+ {42215, 5120},
+ {40151, 6144},
+ {38195, 7168},
+ {36340, 8192},
+ {34582, 9216},
+ {32914, 10240},
+ {31333, 11264},
+ {29833, 12288},
+ {28410, 13312},
+ {27061, 14336},
+ {25781, 15360},
+ {24566, 16384},
+ {23413, 17408},
+ {22319, 18432},
+ {21280, 19456},
+ {20294, 20480},
+ {19358, 21504},
+ {18469, 22528},
+ {17624, 23552},
+ {16822, 24576},
+ {16060, 25600},
+ {15335, 26624},
+ {14646, 27648},
+ {13992, 28672},
+ {13369, 29696},
+ {12777, 30720},
+ {12214, 31744},
+ {11678, 32768},
+ {11168, 33792},
+ {10682, 34816},
+ {10220, 35840},
+ {9780, 36864},
+ {9361, 37888},
+ {8962, 38912},
+ {8582, 39936},
+ {8219, 40960},
+ {7874, 41984},
+ {7545, 43008},
+ {7231, 44032},
+ {6931, 45056},
+ {6646, 46080},
+ {6373, 47104},
+ {6113, 48128},
+ {5865, 49152},
+ {5628, 50176},
+ {5402, 51200},
+ {5185, 52224},
+ {4979, 53248},
+ {4782, 54272},
+ {4593, 55296},
+ {4413, 56320},
+ {4241, 57344},
+ {4076, 58368},
+ {3919, 59392},
+ {3768, 60416},
+ {3624, 61440},
+ {3486, 62464},
+ {3354, 63488},
+ {3227, 64512},
+ {3106, 65536},
+ {2990, 66560},
+ {2879, 67584},
+ {2773, 68608},
+ {2671, 69632},
+ {2573, 70656},
+ {2479, 71680},
+ {2390, 72704},
+ {2303, 73728},
+ {2221, 74752},
+ {2142, 75776},
+ {2066, 76800},
+ {1993, 77824},
+ {1923, 78848},
+ {1855, 79872},
+ {1791, 80896},
+ {1729, 81920},
+ {1669, 82944},
+ {1612, 83968},
+ {1557, 84992},
+ {1504, 86016},
+ {1453, 87040},
+ {1404, 88064},
+ {1357, 89088},
+ {1312, 90112},
+ {1269, 91136},
+ {1227, 92160},
+ {1187, 93184},
+ {1148, 94208},
+ {1111, 95232},
+ {1075, 96256},
+ {1040, 97280},
+ {1007, 98304},
+ {975, 99328},
+ {944, 100352},
+ {914, 101376},
{886, 102400},
- {859, 103424},
- {832, 104448},
- {807, 105472},
- {782, 106496},
- {756, 107520},
- {735, 108544},
+ {858, 103424},
+ {831, 104448},
+ {806, 105472},
+ {781, 106496},
+ {757, 107520},
+ {734, 108544},
{712, 109568},
- {691, 110592},
+ {690, 110592},
{670, 111616},
{650, 112640},
- {631, 113664},
+ {630, 113664},
{612, 114688},
{594, 115712},
- {577, 116736},
- {560, 117760},
- {544, 118784},
- {528, 119808},
- {513, 120832},
+ {576, 116736},
+ {559, 117760},
+ {543, 118784},
+ {527, 119808},
+ {512, 120832},
{498, 121856},
{483, 122880},
{470, 123904},
- {457, 124928},
+ {456, 124928},
{444, 125952},
{431, 126976},
- {419, 128000}
+ {419, 128000},
+ {408, 129024},
+ {396, 130048}
};
static int32_t pm8xxx_adc_map_linear(const struct pm8xxx_adc_map_pt *pts,
@@ -716,6 +718,10 @@
struct pm8xxx_adc_chan_result *adc_chan_result)
{
int64_t xo_thm = 0;
+ uint32_t num1 = 0;
+ uint32_t num2 = 0;
+ uint32_t dnum = 0;
+ uint32_t rt_r25 = 0;
if (!chan_properties || !chan_properties->offset_gain_numerator ||
!chan_properties->offset_gain_denominator || !adc_properties
@@ -724,10 +730,21 @@
xo_thm = pm8xxx_adc_scale_ratiometric_calib(adc_code,
adc_properties, chan_properties);
- xo_thm <<= 4;
+ if (xo_thm < 0)
+ xo_thm = -xo_thm;
+
+ num1 = xo_thm << 14;
+ num2 = (adc_properties->adc_vdd_reference - xo_thm) >> 1;
+ dnum = (adc_properties->adc_vdd_reference - xo_thm);
+
+ if (dnum == 0)
+ rt_r25 = 0x7FFFFFFF ;
+ else
+ rt_r25 = (num1 + num2)/dnum ;
+
pm8xxx_adc_map_linear(adcmap_ntcg_104ef_104fb,
ARRAY_SIZE(adcmap_ntcg_104ef_104fb),
- xo_thm, &adc_chan_result->physical);
+ rt_r25, &adc_chan_result->physical);
return 0;
}
diff --git a/drivers/hwmon/pm8xxx-adc.c b/drivers/hwmon/pm8xxx-adc.c
index 181a97e..1a163a4 100644
--- a/drivers/hwmon/pm8xxx-adc.c
+++ b/drivers/hwmon/pm8xxx-adc.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011-2012, Code Aurora Forum. 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
@@ -1075,7 +1075,7 @@
return 0;
}
-DEFINE_SIMPLE_ATTRIBUTE(reg_fops, get_adc, NULL, "%llu\n");
+DEFINE_SIMPLE_ATTRIBUTE(reg_fops, get_adc, NULL, "%lld\n");
#ifdef CONFIG_DEBUG_FS
static void create_debugfs_entries(void)
diff --git a/drivers/input/touchscreen/cyttsp-i2c-qc.c b/drivers/input/touchscreen/cyttsp-i2c-qc.c
index 6eba5d1..6c4e6b7 100644
--- a/drivers/input/touchscreen/cyttsp-i2c-qc.c
+++ b/drivers/input/touchscreen/cyttsp-i2c-qc.c
@@ -2881,17 +2881,17 @@
cyttsp_debug("Wake Up\n");
- if (ts->is_suspended == false) {
- pr_err("%s: in wakeup state\n", __func__);
- return 0;
- }
-
if (device_may_wakeup(dev)) {
if (ts->client->irq)
disable_irq_wake(ts->client->irq);
return 0;
}
+ if (ts->is_suspended == false) {
+ pr_err("%s: in wakeup state\n", __func__);
+ return 0;
+ }
+
/* re-enable the interrupt prior to wake device */
if (ts->client->irq)
enable_irq(ts->client->irq);
@@ -2952,6 +2952,12 @@
cyttsp_debug("Enter Sleep\n");
+ if (device_may_wakeup(dev)) {
+ if (ts->client->irq)
+ enable_irq_wake(ts->client->irq);
+ return 0;
+ }
+
if (ts->is_suspended == true) {
pr_err("%s: in sleep state\n", __func__);
return 0;
@@ -2966,11 +2972,6 @@
}
mutex_unlock(&ts->mutex);
- if (device_may_wakeup(dev)) {
- if (ts->client->irq)
- enable_irq_wake(ts->client->irq);
- return 0;
- }
if (ts->client->irq == 0)
del_timer(&ts->timer);
diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index 86703e0..4f54a0c 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -16,7 +16,7 @@
# MSM IOMMU support
config MSM_IOMMU
bool "MSM IOMMU Support"
- depends on ARCH_MSM8X60 || ARCH_MSM8960 || ARCH_APQ8064 || ARCH_MSM8974 || ARCH_MPQ8092 || ARCH_MSM8910
+ depends on ARCH_MSM8X60 || ARCH_MSM8960 || ARCH_APQ8064 || ARCH_MSM8974 || ARCH_MPQ8092 || ARCH_MSM8910 || ARCH_MSM8226
select IOMMU_API
help
Support for the IOMMUs found on certain Qualcomm SOCs.
@@ -36,6 +36,16 @@
If unsure, say N here.
+config MSM_IOMMU_PMON
+ bool "MSM IOMMU Perfomance Monitoring Support"
+ depends on ARCH_MSM8974 && MSM_IOMMU
+ help
+ Support for monitoring IOMMUs performance on certain Qualcomm SOCs.
+ It captures TLB statistics per context bank of the IOMMU as an
+ indication of its performance metric.
+
+ If unsure, say N here.
+
config IOMMU_PGTABLES_L2
bool "Allow SMMU page tables in the L2 cache (Experimental)"
depends on MSM_IOMMU && MMU && SMP && CPU_DCACHE_DISABLE=n
diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile
index 11d50c1..5db4258 100644
--- a/drivers/iommu/Makefile
+++ b/drivers/iommu/Makefile
@@ -3,6 +3,7 @@
ifdef CONFIG_OF
obj-$(CONFIG_MSM_IOMMU) += msm_iommu-v2.o msm_iommu_dev-v2.o msm_iommu_pagetable.o msm_iommu_sec.o
endif
+obj-$(CONFIG_MSM_IOMMU_PMON) += msm_iommu_perfmon.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-v2.c b/drivers/iommu/msm_iommu-v2.c
index e3aa30c..79bd15c 100644
--- a/drivers/iommu/msm_iommu-v2.c
+++ b/drivers/iommu/msm_iommu-v2.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
@@ -30,7 +30,7 @@
#include <mach/iommu_hw-v2.h>
#include <mach/iommu.h>
-
+#include <mach/iommu_perfmon.h>
#include "msm_iommu_pagetable.h"
/* bitmap of the page sizes currently supported */
@@ -43,6 +43,29 @@
struct list_head list_attached;
};
+static int __enable_regulators(struct msm_iommu_drvdata *drvdata)
+{
+ int ret = regulator_enable(drvdata->gdsc);
+ if (ret)
+ goto fail;
+
+ if (drvdata->alt_gdsc)
+ ret = regulator_enable(drvdata->alt_gdsc);
+
+ if (ret)
+ regulator_disable(drvdata->gdsc);
+fail:
+ return ret;
+}
+
+static void __disable_regulators(struct msm_iommu_drvdata *drvdata)
+{
+ if (drvdata->alt_gdsc)
+ regulator_disable(drvdata->alt_gdsc);
+
+ regulator_disable(drvdata->gdsc);
+}
+
static int __enable_clocks(struct msm_iommu_drvdata *drvdata)
{
int ret;
@@ -62,6 +85,14 @@
clk_disable_unprepare(drvdata->pclk);
}
}
+
+ if (drvdata->clk_reg_virt) {
+ unsigned int value;
+
+ value = readl_relaxed(drvdata->clk_reg_virt);
+ value &= ~0x1;
+ writel_relaxed(value, drvdata->clk_reg_virt);
+ }
fail:
return ret;
}
@@ -74,6 +105,53 @@
clk_disable_unprepare(drvdata->pclk);
}
+static int _iommu_power_off(void *data)
+{
+ struct msm_iommu_drvdata *drvdata;
+
+ drvdata = (struct msm_iommu_drvdata *)data;
+ __disable_clocks(drvdata);
+ __disable_regulators(drvdata);
+ return 0;
+}
+
+static int _iommu_power_on(void *data)
+{
+ int ret;
+ struct msm_iommu_drvdata *drvdata;
+
+ drvdata = (struct msm_iommu_drvdata *)data;
+ ret = __enable_regulators(drvdata);
+ if (ret)
+ goto fail;
+
+ ret = __enable_clocks(drvdata);
+ if (ret) {
+ __disable_regulators(drvdata);
+ goto fail;
+ }
+ return 0;
+fail:
+ return -EIO;
+}
+
+static void _iommu_lock_acquire(void)
+{
+ mutex_lock(&msm_iommu_lock);
+}
+
+static void _iommu_lock_release(void)
+{
+ mutex_unlock(&msm_iommu_lock);
+}
+
+struct iommu_access_ops iommu_access_ops = {
+ .iommu_power_on = _iommu_power_on,
+ .iommu_power_off = _iommu_power_off,
+ .iommu_lock_acquire = _iommu_lock_acquire,
+ .iommu_lock_release = _iommu_lock_release,
+};
+
static void __sync_tlb(void __iomem *base, int ctx)
{
SET_TLBSYNC(base, ctx, 0);
@@ -160,7 +238,6 @@
SET_GFAR(base, 0);
SET_GFSRRESTORE(base, 0);
SET_TLBIALLNSNH(base, 0);
- SET_PMCR(base, 0);
SET_SCR1(base, 0);
SET_SSDR_N(base, 0, 0);
smt_size = GET_IDR0_NUMSMRG(base);
@@ -478,13 +555,13 @@
is_secure = iommu_drvdata->sec_id != -1;
- ret = regulator_enable(iommu_drvdata->gdsc);
+ ret = __enable_regulators(iommu_drvdata);
if (ret)
goto fail;
ret = __enable_clocks(iommu_drvdata);
if (ret) {
- regulator_disable(iommu_drvdata->gdsc);
+ __disable_regulators(iommu_drvdata);
goto fail;
}
@@ -496,7 +573,7 @@
ret = msm_iommu_sec_program_iommu(
iommu_drvdata->sec_id);
if (ret) {
- regulator_disable(iommu_drvdata->gdsc);
+ __disable_regulators(iommu_drvdata);
__disable_clocks(iommu_drvdata);
goto fail;
}
@@ -511,6 +588,10 @@
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;
fail:
mutex_unlock(&msm_iommu_lock);
return ret;
@@ -525,6 +606,8 @@
int ret;
int is_secure;
+ msm_iommu_detached(dev->parent);
+
mutex_lock(&msm_iommu_lock);
priv = domain->priv;
if (!priv || !dev)
@@ -550,7 +633,7 @@
__disable_clocks(iommu_drvdata);
- regulator_disable(iommu_drvdata->gdsc);
+ __disable_regulators(iommu_drvdata);
list_del_init(&ctx_drvdata->attached_elm);
ctx_drvdata->attached_domain = NULL;
diff --git a/drivers/iommu/msm_iommu_dev-v2.c b/drivers/iommu/msm_iommu_dev-v2.c
index 7961280..4571595 100644
--- a/drivers/iommu/msm_iommu_dev-v2.c
+++ b/drivers/iommu/msm_iommu_dev-v2.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
@@ -27,6 +27,7 @@
#include <mach/iommu_hw-v2.h>
#include <mach/iommu.h>
+#include <mach/iommu_perfmon.h>
static int msm_iommu_parse_bfb_settings(struct platform_device *pdev,
struct msm_iommu_drvdata *drvdata)
@@ -93,6 +94,7 @@
{
struct device_node *child;
int ret = 0;
+ struct resource *r;
drvdata->dev = &pdev->dev;
msm_iommu_add_drv(drvdata);
@@ -107,17 +109,50 @@
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)
+ goto fail;
+
drvdata->sec_id = -1;
of_property_read_u32(pdev->dev.of_node, "qcom,iommu-secure-id",
&drvdata->sec_id);
+
+ r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "clk_base");
+ if (r) {
+ drvdata->clk_reg_virt = devm_ioremap(&pdev->dev, r->start,
+ resource_size(r));
+ if (!drvdata->clk_reg_virt) {
+ pr_err("Failed to map 0x%x for iommu clk\n",
+ r->start);
+ ret = -ENOMEM;
+ goto fail;
+ }
+ }
+
return 0;
fail:
return ret;
}
+static int msm_iommu_pmon_parse_dt(struct platform_device *pdev,
+ struct iommu_info *pmon_info)
+{
+ int ret = 0;
+ int irq = platform_get_irq(pdev, 0);
+
+ if (irq > 0) {
+ pmon_info->evt_irq = platform_get_irq(pdev, 0);
+ } else {
+ pmon_info->evt_irq = -1;
+ ret = irq;
+ }
+ return ret;
+}
+
static int __devinit msm_iommu_probe(struct platform_device *pdev)
{
+ struct iommu_info *pmon_info;
struct msm_iommu_drvdata *drvdata;
struct resource *r;
int ret, needs_alt_core_clk;
@@ -126,7 +161,7 @@
if (!drvdata)
return -ENOMEM;
- r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "iommu_base");
if (!r)
return -EINVAL;
@@ -140,6 +175,10 @@
if (IS_ERR(drvdata->gdsc))
return -EINVAL;
+ drvdata->alt_gdsc = devm_regulator_get(&pdev->dev, "qcom,alt-vdd");
+ if (IS_ERR(drvdata->alt_gdsc))
+ drvdata->alt_gdsc = NULL;
+
drvdata->pclk = devm_clk_get(&pdev->dev, "iface_clk");
if (IS_ERR(drvdata->pclk))
return PTR_ERR(drvdata->pclk);
@@ -170,11 +209,32 @@
if (ret)
return ret;
- pr_info("device %s mapped at %p, with %d ctx banks\n",
+ dev_info(&pdev->dev, "device %s mapped at %p, with %d ctx banks\n",
drvdata->name, drvdata->base, drvdata->ncb);
platform_set_drvdata(pdev, 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->base = drvdata->base;
+ pmon_info->ops = &iommu_access_ops;
+ pmon_info->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_name);
+ }
+ }
+ }
return 0;
}
@@ -182,6 +242,9 @@
{
struct msm_iommu_drvdata *drv = NULL;
+ msm_iommu_pm_iommu_unregister(&pdev->dev);
+ msm_iommu_pm_free(&pdev->dev);
+
drv = platform_get_drvdata(pdev);
if (drv) {
msm_iommu_remove_drv(drv);
diff --git a/drivers/iommu/msm_iommu_perfmon.c b/drivers/iommu/msm_iommu_perfmon.c
new file mode 100644
index 0000000..15302b1
--- /dev/null
+++ b/drivers/iommu/msm_iommu_perfmon.c
@@ -0,0 +1,1104 @@
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/iommu.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/bitops.h>
+#include <linux/debugfs.h>
+#include <mach/iommu_hw-v2.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 {
+ unsigned int event_number;
+ const char *desc;
+};
+
+static struct event_class pmu_event_classes[] = {
+ { 0x00, "cycle_count" },
+ { 0x01, "cycle_count64" },
+ { 0x08, "tlb_refill" },
+ { 0x09, "tlb_refill_read" },
+ { 0x0A, "tlb_refill_write" },
+ { 0x10, "access" },
+ { 0x11, "access_read" },
+ { 0x12, "access_write" },
+};
+
+static struct event_class pmu_event_classes_impl_defined[] = {
+ { 0x80, "full_misses" },
+ { 0x81, "partial_miss_1lbfb_hit" },
+ { 0x82, "partial_miss_2lbfb_hit" },
+ { 0x83, "full_hit" },
+ { 0x90, "pred_req_full_miss" },
+ { 0x91, "pred_req_partial_miss_1lbfb_hit" },
+ { 0x92, "pred_req_partial_miss_2lbfb_hit" },
+ { 0xb0, "tot_num_miss_axi_htw_read_req" },
+ { 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,
+ unsigned int event_cls)
+{
+ unsigned long buf_size = (ARRAY_SIZE(pmu_event_classes) +
+ ARRAY_SIZE(pmu_event_classes_impl_defined)) *
+ MAX_EVEN_CLASS_NAME_LEN;
+ unsigned int pos = 0;
+
+ *buf = kzalloc(buf_size, GFP_KERNEL);
+ if (*buf) {
+ int i;
+ struct event_class *ptr;
+ size_t array_len = ARRAY_SIZE(pmu_event_classes);
+ ptr = pmu_event_classes;
+
+ for (i = 0; i < array_len; ++i) {
+ if ((1 << ptr[i].event_number) & event_cls) {
+ if (pos < buf_size) {
+ pos += snprintf(&(*buf)[pos],
+ buf_size-pos,
+ "[%u] %s\n",
+ ptr[i].event_number,
+ ptr[i].desc);
+ }
+
+ }
+ }
+
+ /*
+ * No way to read a register to check if impl. defined
+ * classes are supported or not so we just assume all of them
+ * are
+ */
+ array_len = ARRAY_SIZE(pmu_event_classes_impl_defined);
+ ptr = pmu_event_classes_impl_defined;
+
+ for (i = 0; i < array_len; ++i) {
+ if (buf_size > pos) {
+ pos += snprintf(&(*buf)[pos],
+ buf_size-pos,
+ "[%u] %s\n",
+ ptr[i].event_number,
+ ptr[i].desc);
+ }
+ }
+ }
+ return pos;
+}
+
+static const char *iommu_pm_find_event_class_name(int event_class)
+{
+ size_t array_len;
+ struct event_class *ptr;
+ int i;
+ const char *event_class_name = NO_EVENT_CLASS_NAME;
+ if (event_class < 0) {
+ goto out;
+ } else if (event_class < 0x80) {
+ array_len = ARRAY_SIZE(pmu_event_classes);
+ ptr = pmu_event_classes;
+ } else {
+ /* All implementation defined classes are above 0x7F */
+ array_len = ARRAY_SIZE(pmu_event_classes_impl_defined);
+ ptr = pmu_event_classes_impl_defined;
+ }
+
+ for (i = 0; i < array_len; ++i) {
+ if (ptr[i].event_number == event_class) {
+ event_class_name = ptr[i].desc;
+ break;
+ }
+ }
+
+out:
+ return event_class_name;
+}
+
+static int iommu_pm_find_event_class(const char *event_class_name)
+{
+ size_t array_len;
+ struct event_class *ptr;
+ int i;
+ int event_class = NO_EVENT_CLASS;
+
+ if (strcmp(event_class_name, NO_EVENT_CLASS_NAME) == 0)
+ goto out;
+
+ array_len = ARRAY_SIZE(pmu_event_classes);
+ ptr = pmu_event_classes;
+
+ for (i = 0; i < array_len; ++i) {
+ if (strcmp(ptr[i].desc, event_class_name) == 0) {
+ event_class = ptr[i].event_number;
+ goto out;
+ }
+ }
+
+ array_len = ARRAY_SIZE(pmu_event_classes_impl_defined);
+ ptr = pmu_event_classes_impl_defined;
+
+ for (i = 0; i < array_len; ++i) {
+ if (strcmp(ptr[i].desc, event_class_name) == 0) {
+ event_class = ptr[i].event_number;
+ goto out;
+ }
+ }
+
+out:
+ return event_class;
+}
+
+static inline void iommu_pm_add_to_iommu_list(struct iommu_pmon *iommu_pmon)
+{
+ list_add(&iommu_pmon->iommu_list, &iommu_list);
+}
+
+static inline void iommu_pm_del_from_iommu_list(struct iommu_pmon *iommu_pmon)
+{
+ list_del(&iommu_pmon->iommu_list);
+}
+
+static struct iommu_pmon *iommu_pm_get_pm_by_dev(struct device *dev)
+{
+ struct iommu_pmon *pmon;
+ struct iommu_info *info;
+ struct list_head *ent;
+ list_for_each(ent, &iommu_list) {
+ pmon = list_entry(ent, struct iommu_pmon, iommu_list);
+ info = &pmon->iommu;
+ if (dev == info->iommu_dev)
+ return pmon;
+ }
+ 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);
+}
+
+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)
+{
+ int event_class;
+ unsigned int count_no;
+ struct iommu_info *iommu = &pmon->iommu;
+
+ 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)) {
+ 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->ops->iommu_lock_release();
+ }
+ counter->overflow_count = 0;
+ counter->value = 0;
+ } else {
+ counter->overflow_count = 0;
+ counter->value = 0;
+ if (iommu_pm_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->ops->iommu_lock_release();
+ }
+ }
+}
+
+static void iommu_pm_reset_counts(struct iommu_pmon *pmon)
+{
+ unsigned int i;
+ unsigned int j;
+ 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) {
+ cnt_grp->counters[j].value = 0;
+ cnt_grp->counters[j].overflow_count = 0;
+ }
+ }
+}
+
+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;
+ unsigned int j;
+ 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)
+ iommu_pm_set_event_type(pmon, &cnt_grp->counters[j]);
+ }
+}
+
+static void iommu_pm_read_all_counters(struct iommu_pmon *pmon)
+{
+ unsigned int i;
+ unsigned int j;
+ 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);
+ }
+ }
+}
+
+static void iommu_pm_on(struct iommu_pmon *pmon)
+{
+ unsigned int i;
+ struct iommu_info *iommu = &pmon->iommu;
+ struct msm_iommu_drvdata *iommu_drvdata =
+ dev_get_drvdata(iommu->iommu_dev);
+
+ iommu->ops->iommu_power_on(iommu_drvdata);
+
+ iommu_pm_reset_counts(pmon);
+
+ pmon->enabled = 1;
+
+ iommu_pm_set_all_counters(pmon);
+
+ iommu->ops->iommu_lock_acquire();
+
+ /* enable all counter group */
+ for (i = 0; i < pmon->num_groups; ++i)
+ iommu_pm_grp_enable(iommu, i);
+
+ /* enable global counters */
+ iommu_pm_enable(iommu);
+ iommu->ops->iommu_lock_release();
+
+ pr_info("%s: TLB performance monitoring turned ON\n",
+ pmon->iommu.iommu_name);
+}
+
+static void iommu_pm_off(struct iommu_pmon *pmon)
+{
+ unsigned int i;
+ struct iommu_info *iommu = &pmon->iommu;
+ struct msm_iommu_drvdata *iommu_drvdata =
+ dev_get_drvdata(iommu->iommu_dev);
+
+ pmon->enabled = 0;
+
+ iommu->ops->iommu_lock_acquire();
+
+ /* disable global counters */
+ iommu_pm_disable(iommu);
+
+ /* Check if we overflowed just before turning off pmon */
+ iommu_pm_check_for_overflow(pmon);
+
+ /* disable all counter group */
+ for (i = 0; i < pmon->num_groups; ++i)
+ iommu_pm_grp_disable(iommu, i);
+
+ /* Update cached copy of counters before turning off power */
+ iommu_pm_read_all_counters(pmon);
+
+ iommu->ops->iommu_lock_release();
+ iommu->ops->iommu_power_off(iommu_drvdata);
+
+ pr_info("%s: TLB performance monitoring turned OFF\n",
+ pmon->iommu.iommu_name);
+}
+
+static unsigned int iommu_pm_get_num_groups(struct iommu_pmon *iommu_pmon)
+{
+ unsigned int pmcfgr;
+ unsigned int num_cntgrp;
+ struct iommu_info *iommu = &iommu_pmon->iommu;
+
+ pmcfgr = readl_relaxed(iommu->base + PMCFGR);
+
+ /* Due to a bug in IOMMU hardware the counter register is returning
+ * the wrong information. num_cntgrp should return "total number
+ * of counter groups - 1". However, it returns "total number
+ * of counter groups". Thus we do not add 1 to the total number of
+ * counter groups. If we find that the number of counter group is 0
+ * then we assume the bug has been fixed and add 1 to the count.
+ */
+ num_cntgrp = ((pmcfgr & PMCFGR_NCG) >> PMCFGR_NCG_SHIFT);
+ if (num_cntgrp == 0)
+ num_cntgrp++;
+
+ return num_cntgrp;
+
+}
+
+static unsigned int iommu_pm_get_num_counters(struct iommu_pmon *iommu_pmon,
+ unsigned int group_no)
+{
+ unsigned int num_counters;
+ unsigned int tmp;
+ struct iommu_info *iommu = &iommu_pmon->iommu;
+
+ tmp = readl_relaxed(iommu->base + PMCGCR_(group_no));
+ num_counters = ((tmp & PMCGCR_CGNC) >> PMCGCR_CGNC_SHIFT);
+
+ return num_counters;
+
+}
+
+static unsigned int iommu_pm_get_sup_ev_cls(struct iommu_info *iommu)
+{
+ return readl_relaxed(iommu->base + PMCEID0);
+}
+
+static int iommu_pm_debug_open(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+static ssize_t iommu_pm_count_value_read(struct file *fp,
+ char __user *user_buff,
+ size_t count, loff_t *pos)
+{
+ size_t rd_cnt;
+ unsigned long long full_count;
+
+ struct iommu_pmon_counter *counter = fp->private_data;
+ struct iommu_pmon *pmon = counter->cnt_group->pmon;
+ struct iommu_info *iommu = &pmon->iommu;
+ char buf[50];
+ size_t len;
+
+ mutex_lock(&pmon->lock);
+
+ if (iommu_pm_is_hw_access_OK(pmon)) {
+ iommu->ops->iommu_lock_acquire();
+ counter->value = iommu_pm_read_counter(counter);
+ iommu->ops->iommu_lock_release();
+ }
+ full_count = (unsigned long long) counter->value +
+ ((unsigned long long)counter->overflow_count *
+ 0x100000000ULL);
+
+ len = snprintf(buf, 50, "%llu\n", full_count);
+ rd_cnt = simple_read_from_buffer(user_buff, count, pos, buf, len);
+ mutex_unlock(&pmon->lock);
+
+ return rd_cnt;
+}
+
+static const struct file_operations cnt_value_file_ops = {
+ .open = iommu_pm_debug_open,
+ .read = iommu_pm_count_value_read,
+};
+
+static ssize_t iommu_pm_event_class_read(struct file *fp,
+ char __user *user_buff,
+ size_t count, loff_t *pos)
+{
+ size_t rd_cnt;
+ struct iommu_pmon_counter *counter = fp->private_data;
+ struct iommu_pmon *pmon = counter->cnt_group->pmon;
+ char buf[50];
+ const char *event_class_name;
+ size_t len;
+
+ mutex_lock(&pmon->lock);
+ event_class_name = iommu_pm_find_event_class_name(
+ counter->current_event_class);
+ len = snprintf(buf, 50, "%s\n", event_class_name);
+
+ rd_cnt = simple_read_from_buffer(user_buff, count, pos, buf, len);
+ mutex_unlock(&pmon->lock);
+ return rd_cnt;
+}
+
+static ssize_t iommu_pm_event_class_write(struct file *fp,
+ const char __user *user_buff,
+ size_t count, loff_t *pos)
+{
+ size_t wr_cnt;
+ char buf[50];
+ size_t buf_size = sizeof(buf);
+ struct iommu_pmon_counter *counter = fp->private_data;
+ struct iommu_pmon *pmon = counter->cnt_group->pmon;
+ int current_event_class;
+
+ if ((count + *pos) >= buf_size)
+ return -EINVAL;
+
+ mutex_lock(&pmon->lock);
+ current_event_class = counter->current_event_class;
+ wr_cnt = simple_write_to_buffer(buf, buf_size, pos, user_buff, count);
+ if (wr_cnt >= 1) {
+ int rv;
+ long value;
+ buf[wr_cnt-1] = '\0';
+ rv = kstrtol(buf, 50, &value);
+ if (!rv) {
+ counter->current_event_class =
+ iommu_pm_find_event_class(
+ iommu_pm_find_event_class_name(value));
+ } else {
+ counter->current_event_class =
+ iommu_pm_find_event_class(buf);
+ } }
+
+ if (current_event_class != counter->current_event_class)
+ iommu_pm_set_event_type(pmon, counter);
+
+ mutex_unlock(&pmon->lock);
+ return wr_cnt;
+}
+
+static const struct file_operations event_class_file_ops = {
+ .open = iommu_pm_debug_open,
+ .read = iommu_pm_event_class_read,
+ .write = iommu_pm_event_class_write,
+};
+
+static ssize_t iommu_reset_counters_write(struct file *fp,
+ const char __user *user_buff,
+ size_t count, loff_t *pos)
+{
+ size_t wr_cnt;
+ char buf[10];
+ size_t buf_size = sizeof(buf);
+ struct iommu_pmon *pmon = fp->private_data;
+ struct iommu_info *iommu = &pmon->iommu;
+
+ if ((count + *pos) >= buf_size)
+ return -EINVAL;
+
+ mutex_lock(&pmon->lock);
+ wr_cnt = simple_write_to_buffer(buf, buf_size, pos, user_buff, count);
+ if (wr_cnt >= 1) {
+ unsigned long cmd = 0;
+ int rv;
+ buf[wr_cnt-1] = '\0';
+ rv = kstrtoul(buf, 10, &cmd);
+ if (!rv && (cmd == 1)) {
+ if (iommu_pm_is_hw_access_OK(pmon)) {
+ iommu->ops->iommu_lock_acquire();
+ iommu_pm_reset_counters(&pmon->iommu);
+ iommu->ops->iommu_lock_release();
+ }
+ iommu_pm_reset_counts(pmon);
+ pr_info("TLB performance counters reset\n");
+ } else {
+ pr_err("Unknown performance monitor command: %lu\n",
+ cmd);
+ }
+ }
+ mutex_unlock(&pmon->lock);
+ return wr_cnt;
+}
+
+static const struct file_operations reset_file_ops = {
+ .open = iommu_pm_debug_open,
+ .write = iommu_reset_counters_write,
+};
+
+static ssize_t iommu_pm_enable_counters_read(struct file *fp,
+ char __user *user_buff,
+ size_t count, loff_t *pos)
+{
+ size_t rd_cnt;
+ char buf[5];
+ size_t len;
+ struct iommu_pmon *pmon = fp->private_data;
+
+ mutex_lock(&pmon->lock);
+ len = snprintf(buf, 5, "%u\n", pmon->enabled);
+ rd_cnt = simple_read_from_buffer(user_buff, count, pos, buf, len);
+ mutex_unlock(&pmon->lock);
+ return rd_cnt;
+}
+
+static ssize_t iommu_pm_enable_counters_write(struct file *fp,
+ const char __user *user_buff,
+ size_t count, loff_t *pos)
+{
+ size_t wr_cnt;
+ char buf[10];
+ size_t buf_size = sizeof(buf);
+ struct iommu_pmon *pmon = fp->private_data;
+
+ if ((count + *pos) >= buf_size)
+ return -EINVAL;
+
+ mutex_lock(&pmon->lock);
+ wr_cnt = simple_write_to_buffer(buf, buf_size, pos, user_buff, count);
+ if (wr_cnt >= 1) {
+ unsigned long cmd;
+ int rv;
+ buf[wr_cnt-1] = '\0';
+ rv = kstrtoul(buf, 10, &cmd);
+ if (!rv && (cmd < 2)) {
+ if (pmon->enabled == 1 && cmd == 0) {
+ if (pmon->iommu_attach_count > 0)
+ iommu_pm_off(pmon);
+ } else if (pmon->enabled == 0 && cmd == 1) {
+ /* We can only turn on perf. monitoring if
+ * iommu is attached. Delay turning on perf.
+ * monitoring until we are attached.
+ */
+ if (pmon->iommu_attach_count > 0)
+ iommu_pm_on(pmon);
+ else
+ pmon->enabled = 1;
+ }
+ } else {
+ pr_err("Unknown performance monitor command: %lu\n",
+ cmd);
+ }
+ }
+ mutex_unlock(&pmon->lock);
+ return wr_cnt;
+}
+
+static const struct file_operations event_enable_file_ops = {
+ .open = iommu_pm_debug_open,
+ .read = iommu_pm_enable_counters_read,
+ .write = iommu_pm_enable_counters_write,
+};
+
+static ssize_t iommu_pm_avail_event_cls_read(struct file *fp,
+ char __user *user_buff,
+ size_t count, loff_t *pos)
+{
+ size_t rd_cnt = 0;
+ struct iommu_pmon *pmon = fp->private_data;
+ char *buf;
+ size_t len;
+
+ mutex_lock(&pmon->lock);
+
+ len = iommu_pm_create_sup_cls_str(&buf, pmon->event_cls_supp_value);
+ if (buf) {
+ rd_cnt = simple_read_from_buffer(user_buff, count, pos,
+ buf, len);
+ kfree(buf);
+ }
+ mutex_unlock(&pmon->lock);
+ return rd_cnt;
+}
+
+static const struct file_operations available_event_cls_file_ops = {
+ .open = iommu_pm_debug_open,
+ .read = iommu_pm_avail_event_cls_read,
+};
+
+
+
+static int iommu_pm_create_grp_debugfs_counters_hierarchy(
+ struct iommu_pmon_cnt_group *cnt_grp,
+ unsigned int *abs_counter_no)
+{
+ int ret = 0;
+ int j;
+ char name[20];
+
+ for (j = 0; j < cnt_grp->num_counters; ++j) {
+ struct dentry *grp_dir = cnt_grp->group_dir;
+ struct dentry *counter_dir;
+ cnt_grp->counters[j].cnt_group = cnt_grp;
+ cnt_grp->counters[j].counter_no = j;
+ cnt_grp->counters[j].absolute_counter_no = *abs_counter_no;
+ (*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;
+
+ snprintf(name, 20, "counter%u", j);
+
+ counter_dir = debugfs_create_dir(name, grp_dir);
+
+ if (IS_ERR_OR_NULL(counter_dir)) {
+ pr_err("unable to create counter debugfs dir %s\n",
+ name);
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ cnt_grp->counters[j].counter_dir = counter_dir;
+
+ if (!debugfs_create_file("value", 0644, counter_dir,
+ &cnt_grp->counters[j],
+ &cnt_value_file_ops)) {
+ ret = -EIO;
+ goto out;
+ }
+
+ if (!debugfs_create_file("current_event_class", 0644,
+ counter_dir, &cnt_grp->counters[j],
+ &event_class_file_ops)) {
+ ret = -EIO;
+ goto out;
+ }
+ }
+out:
+ return ret;
+}
+
+static int iommu_pm_create_group_debugfs_hierarchy(struct iommu_info *iommu,
+ struct iommu_pmon *pmon_entry)
+{
+ int i;
+ int ret = 0;
+ char name[20];
+ unsigned int abs_counter_no = 0;
+
+ for (i = 0; i < pmon_entry->num_groups; ++i) {
+ pmon_entry->cnt_grp[i].pmon = pmon_entry;
+ pmon_entry->cnt_grp[i].grp_no = i;
+ pmon_entry->cnt_grp[i].num_counters =
+ iommu_pm_get_num_counters(pmon_entry, i);
+ pmon_entry->cnt_grp[i].counters =
+ kzalloc(sizeof(*pmon_entry->cnt_grp[i].counters)
+ * pmon_entry->cnt_grp[i].num_counters, GFP_KERNEL);
+
+ if (!pmon_entry->cnt_grp[i].counters) {
+ pr_err("Unable to allocate memory for counters\n");
+ ret = -ENOMEM;
+ goto out;
+ }
+ snprintf(name, 20, "group%u", i);
+ pmon_entry->cnt_grp[i].group_dir = debugfs_create_dir(name,
+ pmon_entry->iommu_dir);
+ if (IS_ERR_OR_NULL(pmon_entry->cnt_grp[i].group_dir)) {
+ pr_err("unable to create group debugfs dir %s\n", name);
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ret = iommu_pm_create_grp_debugfs_counters_hierarchy(
+ &pmon_entry->cnt_grp[i],
+ &abs_counter_no);
+ if (ret)
+ goto out;
+ }
+out:
+ return ret;
+}
+
+int msm_iommu_pm_iommu_register(struct iommu_info *iommu)
+{
+ struct iommu_pmon *pmon_entry;
+ int ret = 0;
+ struct msm_iommu_drvdata *iommu_drvdata;
+ int i;
+
+ if (!iommu->ops || !iommu->iommu_name || !iommu->base
+ || !iommu->iommu_dev) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (!msm_iommu_root_debugfs_dir) {
+ msm_iommu_root_debugfs_dir = debugfs_create_dir("iommu", NULL);
+ if (IS_ERR_OR_NULL(msm_iommu_root_debugfs_dir)) {
+ pr_err("Failed creating iommu debugfs dir \"iommu\"\n");
+ ret = -EIO;
+ goto out;
+ }
+ }
+ pmon_entry = (struct iommu_pmon *)container_of(iommu,
+ struct iommu_pmon, iommu);
+ iommu_drvdata = dev_get_drvdata(iommu->iommu_dev);
+
+ iommu->ops->iommu_power_on(iommu_drvdata);
+ iommu->ops->iommu_lock_acquire();
+
+ pmon_entry->num_groups = iommu_pm_get_num_groups(pmon_entry);
+ pmon_entry->cnt_grp = kzalloc(sizeof(*pmon_entry->cnt_grp)
+ * pmon_entry->num_groups, GFP_KERNEL);
+ if (!pmon_entry->cnt_grp) {
+ pr_err("Unable to allocate memory for counter groups\n");
+ ret = -ENOMEM;
+ goto file_err;
+ }
+ pmon_entry->event_cls_supp_value = iommu_pm_get_sup_ev_cls(iommu);
+
+ pmon_entry->iommu_dir = debugfs_create_dir(iommu->iommu_name,
+ msm_iommu_root_debugfs_dir);
+ if (IS_ERR_OR_NULL(pmon_entry->iommu_dir)) {
+ pr_err("unable to create iommu debugfs dir %s\n",
+ iommu->iommu_name);
+ ret = -ENOMEM;
+ goto free_mem;
+ }
+
+ if (!debugfs_create_file("reset_counters", 0644,
+ pmon_entry->iommu_dir, pmon_entry, &reset_file_ops)) {
+ ret = -EIO;
+ goto free_mem;
+ }
+
+ if (!debugfs_create_file("enable_counters", 0644,
+ pmon_entry->iommu_dir, pmon_entry, &event_enable_file_ops)) {
+ ret = -EIO;
+ goto free_mem;
+ }
+
+ if (!debugfs_create_file("available_event_classes", 0644,
+ pmon_entry->iommu_dir, pmon_entry,
+ &available_event_cls_file_ops)) {
+ ret = -EIO;
+ goto free_mem;
+ }
+
+ ret = iommu_pm_create_group_debugfs_hierarchy(iommu, pmon_entry);
+ if (ret)
+ goto free_mem;
+
+ iommu->ops->iommu_lock_release();
+ iommu->ops->iommu_power_off(iommu_drvdata);
+
+ if (iommu->evt_irq > 0) {
+ ret = request_threaded_irq(iommu->evt_irq, NULL,
+ iommu_pm_evt_ovfl_int_handler,
+ IRQF_ONESHOT | IRQF_SHARED,
+ "msm_iommu_nonsecure_irq", pmon_entry);
+ if (ret) {
+ pr_err("Request IRQ %d failed with ret=%d\n",
+ iommu->evt_irq,
+ ret);
+ goto free_mem;
+ }
+ } else {
+ pr_info("%s: Overflow interrupt not available\n", __func__);
+ }
+
+ dev_dbg(iommu->iommu_dev, "%s iommu registered\n",
+ iommu->iommu_name);
+
+ goto out;
+free_mem:
+ if (pmon_entry->cnt_grp) {
+ for (i = 0; i < pmon_entry->num_groups; ++i) {
+ kfree(pmon_entry->cnt_grp[i].counters);
+ pmon_entry->cnt_grp[i].counters = 0;
+ }
+ }
+ kfree(pmon_entry->cnt_grp);
+ pmon_entry->cnt_grp = 0;
+file_err:
+ debugfs_remove_recursive(msm_iommu_root_debugfs_dir);
+out:
+ return ret;
+}
+EXPORT_SYMBOL(msm_iommu_pm_iommu_register);
+
+void msm_iommu_pm_iommu_unregister(struct device *dev)
+{
+ int i;
+ struct iommu_pmon *pmon_entry = iommu_pm_get_pm_by_dev(dev);
+
+ if (!pmon_entry)
+ return;
+
+ free_irq(pmon_entry->iommu.evt_irq, pmon_entry->iommu.iommu_dev);
+
+ if (!pmon_entry)
+ goto remove_debugfs;
+
+ if (pmon_entry->cnt_grp) {
+ for (i = 0; i < pmon_entry->num_groups; ++i)
+ kfree(pmon_entry->cnt_grp[i].counters);
+ }
+
+ kfree(pmon_entry->cnt_grp);
+
+remove_debugfs:
+ debugfs_remove_recursive(msm_iommu_root_debugfs_dir);
+
+ return;
+}
+EXPORT_SYMBOL(msm_iommu_pm_iommu_unregister);
+
+struct iommu_info *msm_iommu_pm_alloc(struct device *dev)
+{
+ struct iommu_pmon *pmon_entry;
+ struct iommu_info *info;
+ pmon_entry = devm_kzalloc(dev, sizeof(*pmon_entry), GFP_KERNEL);
+ if (!pmon_entry)
+ return NULL;
+ info = &pmon_entry->iommu;
+ info->iommu_dev = dev;
+ mutex_init(&pmon_entry->lock);
+ iommu_pm_add_to_iommu_list(pmon_entry);
+ return &pmon_entry->iommu;
+}
+EXPORT_SYMBOL(msm_iommu_pm_alloc);
+
+void msm_iommu_pm_free(struct device *dev)
+{
+ struct iommu_pmon *pmon = iommu_pm_get_pm_by_dev(dev);
+ if (pmon)
+ iommu_pm_del_from_iommu_list(pmon);
+}
+EXPORT_SYMBOL(msm_iommu_pm_free);
+
+void msm_iommu_attached(struct device *dev)
+{
+ struct iommu_pmon *pmon = iommu_pm_get_pm_by_dev(dev);
+ if (pmon) {
+ mutex_lock(&pmon->lock);
+ ++pmon->iommu_attach_count;
+ if (pmon->iommu_attach_count == 1) {
+ /* If perf. mon was enabled before we attached we do
+ * the actual after we attach.
+ */
+ if (pmon->enabled)
+ iommu_pm_on(pmon);
+ }
+ mutex_unlock(&pmon->lock);
+ }
+}
+EXPORT_SYMBOL(msm_iommu_attached);
+
+void msm_iommu_detached(struct device *dev)
+{
+ struct iommu_pmon *pmon = iommu_pm_get_pm_by_dev(dev);
+ if (pmon) {
+ mutex_lock(&pmon->lock);
+ if (pmon->iommu_attach_count == 1) {
+ /* If perf. mon is still enabled we have to disable
+ * before we do the detach.
+ */
+ if (pmon->enabled)
+ iommu_pm_off(pmon);
+ }
+ BUG_ON(pmon->iommu_attach_count == 0);
+ --pmon->iommu_attach_count;
+ mutex_unlock(&pmon->lock);
+ }
+}
+EXPORT_SYMBOL(msm_iommu_detached);
+
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index 82b6aa0..f5a505c 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -1680,7 +1680,8 @@
* Decoder filters have no data in the data buffer and their
* events can be removed now from the queue.
*/
- if (dmxdevfilter->params.pes.output == DMX_OUT_DECODER)
+ if ((dmxdevfilter->type == DMXDEV_TYPE_PES) &&
+ (dmxdevfilter->params.pes.output == DMX_OUT_DECODER))
dmxdevfilter->events.read_index =
dvb_dmxdev_advance_event_idx(
dmxdevfilter->events.read_index);
diff --git a/drivers/media/video/msm/msm_mctl_buf.c b/drivers/media/video/msm/msm_mctl_buf.c
index 2919d23..f4bb5b3 100644
--- a/drivers/media/video/msm/msm_mctl_buf.c
+++ b/drivers/media/video/msm/msm_mctl_buf.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2013, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -122,6 +122,11 @@
}
for (i = 0; i < vb->num_planes; i++) {
mem = vb2_plane_cookie(vb, i);
+ if (mem == NULL) {
+ pr_err("%s Inst %p Buffer %d Plane %d cookie is null",
+ __func__, pcam_inst, buf_idx, i);
+ return -EINVAL;
+ }
if (buf_type == VIDEOBUF2_MULTIPLE_PLANES)
offset.data_offset =
pcam_inst->plane_info.plane[i].offset;
@@ -266,8 +271,14 @@
}
for (i = 0; i < vb->num_planes; i++) {
mem = vb2_plane_cookie(vb, i);
- videobuf2_pmem_contig_user_put(mem, pmctl->client,
- pmctl->domain_num);
+ if (mem) {
+ videobuf2_pmem_contig_user_put(mem, pmctl->client,
+ pmctl->domain_num);
+ } else {
+ pr_err("%s Inst %p buffer plane cookie is null",
+ __func__, pcam_inst);
+ return;
+ }
}
buf->state = MSM_BUFFER_STATE_UNUSED;
}
@@ -385,7 +396,13 @@
&pcam_inst->free_vq, list) {
buf_idx = buf->vidbuf.v4l2_buf.index;
mem = vb2_plane_cookie(&buf->vidbuf, 0);
- if (mem->buffer_type == VIDEOBUF2_MULTIPLE_PLANES)
+ if (mem == NULL) {
+ pr_err("%s Inst %p plane cookie is null",
+ __func__, pcam_inst);
+ spin_unlock_irqrestore(&pcam_inst->vq_irqlock, flags);
+ return NULL;
+ }
+ if (mem->buffer_type == VIDEOBUF2_MULTIPLE_PLANES)
offset = mem->offset.data_offset +
pcam_inst->buf_offset[buf_idx][0].data_offset;
else
@@ -690,7 +707,19 @@
return rc;
}
spin_lock_irqsave(&pcam_inst->vq_irqlock, flags);
+ if (pcam_inst->free_vq.next == NULL) {
+ pr_err("%s Inst %p Free queue head is null",
+ __func__, pcam_inst);
+ spin_unlock_irqrestore(&pcam_inst->vq_irqlock, flags);
+ return rc;
+ }
list_for_each_entry(buf, &pcam_inst->free_vq, list) {
+ if (buf == NULL) {
+ pr_err("%s Inst %p Invalid buffer ptr",
+ __func__, pcam_inst);
+ spin_unlock_irqrestore(&pcam_inst->vq_irqlock, flags);
+ return rc;
+ }
if (buf->state != MSM_BUFFER_STATE_QUEUED)
continue;
@@ -701,6 +730,13 @@
pcam_inst->plane_info.num_planes;
for (i = 0; i < free_buf->num_planes; i++) {
mem = vb2_plane_cookie(&buf->vidbuf, i);
+ if (mem == NULL) {
+ pr_err("%s Inst %p %d invalid cookie",
+ __func__, pcam_inst, buf_idx);
+ spin_unlock_irqrestore(
+ &pcam_inst->vq_irqlock, flags);
+ return rc;
+ }
if (mem->buffer_type ==
VIDEOBUF2_MULTIPLE_PLANES)
plane_offset =
@@ -721,6 +757,13 @@
}
} else {
mem = vb2_plane_cookie(&buf->vidbuf, 0);
+ if (mem == NULL) {
+ pr_err("%s Inst %p %d invalid cookie",
+ __func__, pcam_inst, buf_idx);
+ spin_unlock_irqrestore(
+ &pcam_inst->vq_irqlock, flags);
+ return rc;
+ }
free_buf->ch_paddr[0] = (uint32_t)
videobuf2_to_pmem_contig(&buf->vidbuf, 0) +
mem->offset.sp_off.y_off;
diff --git a/drivers/media/video/msm/msm_mctl_pp.c b/drivers/media/video/msm/msm_mctl_pp.c
index 7155d4c..7f0fd94 100644
--- a/drivers/media/video/msm/msm_mctl_pp.c
+++ b/drivers/media/video/msm/msm_mctl_pp.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2013, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -138,6 +138,12 @@
&pcam_inst->free_vq, list) {
buf_idx = buf->vidbuf.v4l2_buf.index;
mem = vb2_plane_cookie(&buf->vidbuf, 0);
+ if (mem == NULL) {
+ pr_err("%s Inst %p Buffer %d invalid plane cookie",
+ __func__, pcam_inst, buf_idx);
+ spin_unlock_irqrestore(&pcam_inst->vq_irqlock, flags);
+ return 0;
+ }
if (mem->buffer_type == VIDEOBUF2_MULTIPLE_PLANES)
offset = mem->offset.data_offset +
pcam_inst->buf_offset[buf_idx][0].data_offset;
@@ -272,6 +278,11 @@
* Also use this to check the number of planes in
* this buffer.*/
mem = vb2_plane_cookie(&vb->vidbuf, 0);
+ if (mem == NULL) {
+ pr_err("%s Inst %p Buffer %d, invalid plane cookie ", __func__,
+ pcam_inst, buf_idx);
+ return -EINVAL;
+ }
div.frame.path = mem->path;
div.frame.node_type = node;
if (mem->buffer_type == VIDEOBUF2_SINGLE_PLANE) {
@@ -296,6 +307,11 @@
* fill out the plane info. */
for (i = 0; i < div.frame.num_planes; i++) {
mem = vb2_plane_cookie(&vb->vidbuf, i);
+ if (mem == NULL) {
+ pr_err("%s Inst %p %d invalid plane cookie ",
+ __func__, pcam_inst, buf_idx);
+ return -EINVAL;
+ }
div.frame.mp[i].phy_addr =
videobuf2_to_pmem_contig(&vb->vidbuf, i);
if (!pcam_inst->buf_offset)
@@ -338,6 +354,11 @@
* Also use this to check the number of planes in
* this buffer.*/
mem = vb2_plane_cookie(&vb->vidbuf, 0);
+ if (mem == NULL) {
+ pr_err("%s Inst %p Buffer %d, invalid plane cookie ", __func__,
+ pcam_inst, buf_idx);
+ return -EINVAL;
+ }
pp_frame->image_type = (unsigned short)mem->path;
if (mem->buffer_type == VIDEOBUF2_SINGLE_PLANE) {
pp_frame->num_planes = 1;
diff --git a/drivers/media/video/msm_vidc/Makefile b/drivers/media/video/msm_vidc/Makefile
index c8e7076..da829cc 100644
--- a/drivers/media/video/msm_vidc/Makefile
+++ b/drivers/media/video/msm_vidc/Makefile
@@ -8,3 +8,4 @@
venus_hfi.o \
hfi_response_handler.o \
hfi_packetization.o \
+ vidc_hfi.o \
diff --git a/drivers/media/video/msm_vidc/hfi_packetization.c b/drivers/media/video/msm_vidc/hfi_packetization.c
index 509b013..4d3d07d 100644
--- a/drivers/media/video/msm_vidc/hfi_packetization.c
+++ b/drivers/media/video/msm_vidc/hfi_packetization.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
@@ -794,6 +794,7 @@
HFI_PROPERTY_CONFIG_VENC_TARGET_BITRATE;
hfi = (struct hfi_bitrate *) &pkt->rg_property_data[1];
hfi->bit_rate = ((struct hal_bitrate *)pdata)->bit_rate;
+ hfi->layer_id = ((struct hal_bitrate *)pdata)->layer_id;
pkt->size += sizeof(u32) * 2;
break;
}
@@ -943,11 +944,15 @@
case HAL_PARAM_VENC_SESSION_QP:
{
struct hfi_quantization *hfi;
+ struct hal_quantization *hal_quant =
+ (struct hal_quantization *) pdata;
pkt->rg_property_data[0] =
HFI_PROPERTY_PARAM_VENC_SESSION_QP;
hfi = (struct hfi_quantization *) &pkt->rg_property_data[1];
- memcpy(hfi, (struct hfi_quantization *) pdata,
- sizeof(struct hfi_quantization));
+ hfi->qp_i = hal_quant->qpi;
+ hfi->qp_p = hal_quant->qpp;
+ hfi->qp_b = hal_quant->qpb;
+ hfi->layer_id = hal_quant->layer_id;
pkt->size += sizeof(u32) + sizeof(struct hfi_quantization);
break;
}
diff --git a/drivers/media/video/msm_vidc/hfi_packetization.h b/drivers/media/video/msm_vidc/hfi_packetization.h
index 541654f..a3edc7c 100644
--- a/drivers/media/video/msm_vidc/hfi_packetization.h
+++ b/drivers/media/video/msm_vidc/hfi_packetization.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
@@ -15,8 +15,8 @@
#include <linux/types.h>
#include "vidc_hfi_helper.h"
+#include "vidc_hfi.h"
#include "vidc_hfi_api.h"
-#include "venus_hfi.h"
int create_pkt_cmd_sys_init(struct hfi_cmd_sys_init_packet *pkt,
u32 arch_type);
diff --git a/drivers/media/video/msm_vidc/hfi_response_handler.c b/drivers/media/video/msm_vidc/hfi_response_handler.c
index 50970cb..23829e5 100644
--- a/drivers/media/video/msm_vidc/hfi_response_handler.c
+++ b/drivers/media/video/msm_vidc/hfi_response_handler.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
@@ -14,9 +14,10 @@
#include <linux/slab.h>
#include <linux/list.h>
#include <linux/interrupt.h>
-#include "venus_hfi.h"
+#include "vidc_hfi_helper.h"
#include "vidc_hfi_io.h"
#include "msm_vidc_debug.h"
+#include "vidc_hfi.h"
static enum vidc_status hfi_map_err_status(int hfi_err)
{
@@ -75,8 +76,9 @@
return vidc_err;
}
-static void hfi_process_sess_evt_seq_changed(struct venus_hfi_device *device,
- struct hfi_msg_event_notify_packet *pkt)
+static void hfi_process_sess_evt_seq_changed(
+ msm_vidc_callback callback, u32 device_id,
+ struct hfi_msg_event_notify_packet *pkt)
{
struct msm_vidc_cb_cmd_done cmd_done;
struct msm_vidc_cb_event event_notify;
@@ -95,7 +97,7 @@
memset(&event_notify, 0, sizeof(struct
msm_vidc_cb_event));
- cmd_done.device_id = device->device_id;
+ cmd_done.device_id = device_id;
cmd_done.session_id = ((struct hal_session *) pkt->session_id)->
session_id;
cmd_done.status = VIDC_ERR_NONE;
@@ -136,39 +138,35 @@
} while (num_properties_changed > 0);
}
cmd_done.data = &event_notify;
- device->callback(VIDC_EVENT_CHANGE, &cmd_done);
+ callback(VIDC_EVENT_CHANGE, &cmd_done);
}
-static void hfi_process_sys_watchdog_timeout(struct venus_hfi_device *device)
-{
- struct msm_vidc_cb_cmd_done cmd_done;
- device->intr_status &= ~VIDC_WRAPPER_INTR_STATUS_A2HWD_BMSK;
- memset(&cmd_done, 0, sizeof(struct msm_vidc_cb_cmd_done));
- cmd_done.device_id = device->device_id;
- device->callback(SYS_WATCHDOG_TIMEOUT, &cmd_done);
-}
-static void hfi_process_sys_error(struct venus_hfi_device *device)
+
+static void hfi_process_sys_error(
+ msm_vidc_callback callback, u32 device_id)
{
struct msm_vidc_cb_cmd_done cmd_done;
memset(&cmd_done, 0, sizeof(struct msm_vidc_cb_cmd_done));
- cmd_done.device_id = device->device_id;
- device->callback(SYS_ERROR, &cmd_done);
+ cmd_done.device_id = device_id;
+ callback(SYS_ERROR, &cmd_done);
}
-static void hfi_process_session_error(struct venus_hfi_device *device,
+static void hfi_process_session_error(
+ msm_vidc_callback callback, u32 device_id,
struct hfi_msg_event_notify_packet *pkt)
{
struct msm_vidc_cb_cmd_done cmd_done;
memset(&cmd_done, 0, sizeof(struct msm_vidc_cb_cmd_done));
- cmd_done.device_id = device->device_id;
+ cmd_done.device_id = device_id;
cmd_done.session_id = ((struct hal_session *) pkt->session_id)->
session_id;
- device->callback(SESSION_ERROR, &cmd_done);
+ callback(SESSION_ERROR, &cmd_done);
}
-static void hfi_process_event_notify(struct venus_hfi_device *device,
- struct hfi_msg_event_notify_packet *pkt)
+static void hfi_process_event_notify(
+ msm_vidc_callback callback, u32 device_id,
+ struct hfi_msg_event_notify_packet *pkt)
{
dprintk(VIDC_DBG, "RECVD:EVENT_NOTIFY");
- if (!device || !pkt ||
+ if (!callback || !pkt ||
pkt->size < sizeof(struct hfi_msg_event_notify_packet)) {
dprintk(VIDC_ERR, "Invalid Params");
return;
@@ -178,15 +176,15 @@
case HFI_EVENT_SYS_ERROR:
dprintk(VIDC_ERR, "HFI_EVENT_SYS_ERROR: %d\n",
pkt->event_data1);
- hfi_process_sys_error(device);
+ hfi_process_sys_error(callback, device_id);
break;
case HFI_EVENT_SESSION_ERROR:
dprintk(VIDC_ERR, "HFI_EVENT_SESSION_ERROR");
- hfi_process_session_error(device, pkt);
+ hfi_process_session_error(callback, device_id, pkt);
break;
case HFI_EVENT_SESSION_SEQUENCE_CHANGED:
dprintk(VIDC_INFO, "HFI_EVENT_SESSION_SEQUENCE_CHANGED");
- hfi_process_sess_evt_seq_changed(device, pkt);
+ hfi_process_sess_evt_seq_changed(callback, device_id, pkt);
break;
case HFI_EVENT_SESSION_PROPERTY_CHANGED:
dprintk(VIDC_INFO, "HFI_EVENT_SESSION_PROPERTY_CHANGED");
@@ -196,7 +194,8 @@
break;
}
}
-static void hfi_process_sys_init_done(struct venus_hfi_device *device,
+static void hfi_process_sys_init_done(
+ msm_vidc_callback callback, u32 device_id,
struct hfi_msg_sys_init_done_packet *pkt)
{
struct msm_vidc_cb_cmd_done cmd_done;
@@ -273,16 +272,17 @@
}
}
err_no_prop:
- cmd_done.device_id = device->device_id;
+ cmd_done.device_id = device_id;
cmd_done.session_id = 0;
cmd_done.status = (u32) status;
cmd_done.size = sizeof(struct vidc_hal_sys_init_done);
cmd_done.data = (void *) &sys_init_done;
- device->callback(SYS_INIT_DONE, &cmd_done);
+ callback(SYS_INIT_DONE, &cmd_done);
}
-static void hfi_process_sys_rel_resource_done(struct venus_hfi_device *device,
- struct hfi_msg_sys_release_resource_done_packet *pkt)
+static void hfi_process_sys_rel_resource_done(
+ msm_vidc_callback callback, u32 device_id,
+ struct hfi_msg_sys_release_resource_done_packet *pkt)
{
struct msm_vidc_cb_cmd_done cmd_done;
enum vidc_status status = VIDC_ERR_NONE;
@@ -297,12 +297,12 @@
return;
}
status = hfi_map_err_status((u32)pkt->error_type);
- cmd_done.device_id = device->device_id;
+ cmd_done.device_id = device_id;
cmd_done.session_id = 0;
cmd_done.status = (u32) status;
cmd_done.size = 0;
cmd_done.data = NULL;
- device->callback(RELEASE_RESOURCE_DONE, &cmd_done);
+ callback(RELEASE_RESOURCE_DONE, &cmd_done);
}
enum vidc_status hfi_process_sess_init_done_prop_read(
@@ -408,8 +408,9 @@
}
}
-static void hfi_process_session_prop_info(struct venus_hfi_device *device,
- struct hfi_msg_session_property_info_packet *pkt)
+static void hfi_process_session_prop_info(
+ msm_vidc_callback callback, u32 device_id,
+ struct hfi_msg_session_property_info_packet *pkt)
{
struct msm_vidc_cb_cmd_done cmd_done;
struct buffer_requirements buff_req;
@@ -433,13 +434,13 @@
switch (pkt->rg_property_data[0]) {
case HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS:
hfi_process_sess_get_prop_buf_req(pkt, &buff_req);
- cmd_done.device_id = device->device_id;
+ cmd_done.device_id = device_id;
cmd_done.session_id =
((struct hal_session *) pkt->session_id)->session_id;
cmd_done.status = VIDC_ERR_NONE;
cmd_done.data = &buff_req;
cmd_done.size = sizeof(struct buffer_requirements);
- device->callback(SESSION_PROPERTY_INFO, &cmd_done);
+ callback(SESSION_PROPERTY_INFO, &cmd_done);
break;
default:
dprintk(VIDC_ERR, "hal_process_session_prop_info:"
@@ -449,8 +450,9 @@
}
}
-static void hfi_process_session_init_done(struct venus_hfi_device *device,
- struct hfi_msg_sys_session_init_done_packet *pkt)
+static void hfi_process_session_init_done(
+ msm_vidc_callback callback, u32 device_id,
+ struct hfi_msg_sys_session_init_done_packet *pkt)
{
struct msm_vidc_cb_cmd_done cmd_done;
struct vidc_hal_session_init_done session_init_done;
@@ -466,7 +468,7 @@
memset(&session_init_done, 0, sizeof(struct
vidc_hal_session_init_done));
- cmd_done.device_id = device->device_id;
+ cmd_done.device_id = device_id;
cmd_done.session_id =
((struct hal_session *) pkt->session_id)->session_id;
cmd_done.status = hfi_map_err_status((u32)pkt->error_type);
@@ -476,11 +478,12 @@
pkt, &cmd_done);
}
cmd_done.size = sizeof(struct vidc_hal_session_init_done);
- device->callback(SESSION_INIT_DONE, &cmd_done);
+ callback(SESSION_INIT_DONE, &cmd_done);
}
-static void hfi_process_session_load_res_done(struct venus_hfi_device *device,
- struct hfi_msg_session_load_resources_done_packet *pkt)
+static void hfi_process_session_load_res_done(
+ msm_vidc_callback callback, u32 device_id,
+ struct hfi_msg_session_load_resources_done_packet *pkt)
{
struct msm_vidc_cb_cmd_done cmd_done;
dprintk(VIDC_DBG, "RECEIVED:SESSION_LOAD_RESOURCES_DONE");
@@ -494,17 +497,18 @@
memset(&cmd_done, 0, sizeof(struct msm_vidc_cb_cmd_done));
- cmd_done.device_id = device->device_id;
+ cmd_done.device_id = device_id;
cmd_done.session_id =
((struct hal_session *) pkt->session_id)->session_id;
cmd_done.status = hfi_map_err_status((u32)pkt->error_type);
cmd_done.data = NULL;
cmd_done.size = 0;
- device->callback(SESSION_LOAD_RESOURCE_DONE, &cmd_done);
+ callback(SESSION_LOAD_RESOURCE_DONE, &cmd_done);
}
-static void hfi_process_session_flush_done(struct venus_hfi_device *device,
- struct hfi_msg_session_flush_done_packet *pkt)
+static void hfi_process_session_flush_done(
+ msm_vidc_callback callback, u32 device_id,
+ struct hfi_msg_session_flush_done_packet *pkt)
{
struct msm_vidc_cb_cmd_done cmd_done;
@@ -517,17 +521,18 @@
}
memset(&cmd_done, 0, sizeof(struct msm_vidc_cb_cmd_done));
- cmd_done.device_id = device->device_id;
+ cmd_done.device_id = device_id;
cmd_done.session_id =
((struct hal_session *) pkt->session_id)->session_id;
cmd_done.status = hfi_map_err_status((u32)pkt->error_type);
cmd_done.data = (void *) pkt->flush_type;
cmd_done.size = sizeof(u32);
- device->callback(SESSION_FLUSH_DONE, &cmd_done);
+ callback(SESSION_FLUSH_DONE, &cmd_done);
}
-static void hfi_process_session_etb_done(struct venus_hfi_device *device,
- struct hfi_msg_session_empty_buffer_done_packet *pkt)
+static void hfi_process_session_etb_done(
+ msm_vidc_callback callback, u32 device_id,
+ struct hfi_msg_session_empty_buffer_done_packet *pkt)
{
struct msm_vidc_cb_data_done data_done;
@@ -541,7 +546,7 @@
memset(&data_done, 0, sizeof(struct msm_vidc_cb_data_done));
- data_done.device_id = device->device_id;
+ data_done.device_id = device_id;
data_done.session_id =
((struct hal_session *) pkt->session_id)->session_id;
data_done.status = hfi_map_err_status((u32) pkt->error_type);
@@ -550,11 +555,12 @@
data_done.input_done.offset = pkt->offset;
data_done.input_done.filled_len = pkt->filled_len;
data_done.input_done.packet_buffer = pkt->packet_buffer;
- device->callback(SESSION_ETB_DONE, &data_done);
+ callback(SESSION_ETB_DONE, &data_done);
}
-static void hfi_process_session_ftb_done(struct venus_hfi_device *device,
- void *msg_hdr)
+static void hfi_process_session_ftb_done(
+ msm_vidc_callback callback, u32 device_id,
+ void *msg_hdr)
{
struct msm_vidc_cb_data_done data_done;
struct hfi_msg_session_fill_buffer_done_compressed_packet *pack =
@@ -590,7 +596,7 @@
/* Proceed with the FBD */
}
- data_done.device_id = device->device_id;
+ data_done.device_id = device_id;
data_done.session_id = (u32) session;
data_done.status = hfi_map_err_status((u32)
pkt->error_type);
@@ -624,7 +630,7 @@
return;
}
- data_done.device_id = device->device_id;
+ data_done.device_id = device_id;
data_done.session_id = (u32) session;
data_done.status = hfi_map_err_status((u32)
pkt->error_type);
@@ -657,11 +663,12 @@
else if (pkt->stream_id == 1)
data_done.output_done.buffer_type = HAL_BUFFER_OUTPUT2;
}
- device->callback(SESSION_FTB_DONE, &data_done);
+ callback(SESSION_FTB_DONE, &data_done);
}
-static void hfi_process_session_start_done(struct venus_hfi_device *device,
- struct hfi_msg_session_start_done_packet *pkt)
+static void hfi_process_session_start_done(
+ msm_vidc_callback callback, u32 device_id,
+ struct hfi_msg_session_start_done_packet *pkt)
{
struct msm_vidc_cb_cmd_done cmd_done;
@@ -675,17 +682,18 @@
}
memset(&cmd_done, 0, sizeof(struct msm_vidc_cb_cmd_done));
- cmd_done.device_id = device->device_id;
+ cmd_done.device_id = device_id;
cmd_done.session_id =
((struct hal_session *) pkt->session_id)->session_id;
cmd_done.status = hfi_map_err_status((u32)pkt->error_type);
cmd_done.data = NULL;
cmd_done.size = 0;
- device->callback(SESSION_START_DONE, &cmd_done);
+ callback(SESSION_START_DONE, &cmd_done);
}
-static void hfi_process_session_stop_done(struct venus_hfi_device *device,
- struct hfi_msg_session_stop_done_packet *pkt)
+static void hfi_process_session_stop_done(
+ msm_vidc_callback callback, u32 device_id,
+ struct hfi_msg_session_stop_done_packet *pkt)
{
struct msm_vidc_cb_cmd_done cmd_done;
@@ -699,17 +707,18 @@
}
memset(&cmd_done, 0, sizeof(struct msm_vidc_cb_cmd_done));
- cmd_done.device_id = device->device_id;
+ cmd_done.device_id = device_id;
cmd_done.session_id =
((struct hal_session *) pkt->session_id)->session_id;
cmd_done.status = hfi_map_err_status((u32)pkt->error_type);
cmd_done.data = NULL;
cmd_done.size = 0;
- device->callback(SESSION_STOP_DONE, &cmd_done);
+ callback(SESSION_STOP_DONE, &cmd_done);
}
-static void hfi_process_session_rel_res_done(struct venus_hfi_device *device,
- struct hfi_msg_session_release_resources_done_packet *pkt)
+static void hfi_process_session_rel_res_done(
+ msm_vidc_callback callback, u32 device_id,
+ struct hfi_msg_session_release_resources_done_packet *pkt)
{
struct msm_vidc_cb_cmd_done cmd_done;
@@ -723,17 +732,18 @@
}
memset(&cmd_done, 0, sizeof(struct msm_vidc_cb_cmd_done));
- cmd_done.device_id = device->device_id;
+ cmd_done.device_id = device_id;
cmd_done.session_id =
((struct hal_session *) pkt->session_id)->session_id;
cmd_done.status = hfi_map_err_status((u32)pkt->error_type);
cmd_done.data = NULL;
cmd_done.size = 0;
- device->callback(SESSION_RELEASE_RESOURCE_DONE, &cmd_done);
+ callback(SESSION_RELEASE_RESOURCE_DONE, &cmd_done);
}
-static void hfi_process_session_rel_buf_done(struct venus_hfi_device *device,
- struct hfi_msg_session_release_buffers_done_packet *pkt)
+static void hfi_process_session_rel_buf_done(
+ msm_vidc_callback callback, u32 device_id,
+ struct hfi_msg_session_release_buffers_done_packet *pkt)
{
struct msm_vidc_cb_cmd_done cmd_done;
if (!pkt || pkt->size !=
@@ -743,7 +753,7 @@
return;
}
memset(&cmd_done, 0, sizeof(struct msm_vidc_cb_cmd_done));
- cmd_done.device_id = device->device_id;
+ cmd_done.device_id = device_id;
cmd_done.size = sizeof(struct msm_vidc_cb_cmd_done);
cmd_done.session_id =
((struct hal_session *) pkt->session_id)->session_id;
@@ -754,11 +764,12 @@
} else {
dprintk(VIDC_ERR, "invalid payload in rel_buff_done\n");
}
- device->callback(SESSION_RELEASE_BUFFER_DONE, &cmd_done);
+ callback(SESSION_RELEASE_BUFFER_DONE, &cmd_done);
}
-static void hfi_process_session_end_done(struct venus_hfi_device *device,
- struct hfi_msg_sys_session_end_done_packet *pkt)
+static void hfi_process_session_end_done(
+ msm_vidc_callback callback, u32 device_id,
+ struct hfi_msg_sys_session_end_done_packet *pkt)
{
struct msm_vidc_cb_cmd_done cmd_done;
struct hal_session *sess_close;
@@ -779,17 +790,17 @@
kfree(sess_close);
memset(&cmd_done, 0, sizeof(struct msm_vidc_cb_cmd_done));
- cmd_done.device_id = device->device_id;
+ cmd_done.device_id = device_id;
cmd_done.session_id =
((struct hal_session *) pkt->session_id)->session_id;
cmd_done.status = hfi_map_err_status((u32)pkt->error_type);
cmd_done.data = NULL;
cmd_done.size = 0;
- device->callback(SESSION_END_DONE, &cmd_done);
+ callback(SESSION_END_DONE, &cmd_done);
}
static void hfi_process_session_get_seq_hdr_done(
- struct venus_hfi_device *device,
+ msm_vidc_callback callback, u32 device_id,
struct hfi_msg_session_get_sequence_header_done_packet *pkt)
{
struct msm_vidc_cb_data_done data_done;
@@ -800,7 +811,7 @@
return;
}
memset(&data_done, 0, sizeof(struct msm_vidc_cb_data_done));
- data_done.device_id = device->device_id;
+ data_done.device_id = device_id;
data_done.size = sizeof(struct msm_vidc_cb_data_done);
data_done.session_id =
((struct hal_session *) pkt->session_id)->session_id;
@@ -809,121 +820,99 @@
data_done.output_done.filled_len1 = pkt->header_len;
dprintk(VIDC_INFO, "seq_hdr: %p, Length: %d",
pkt->sequence_header, pkt->header_len);
- device->callback(SESSION_GET_SEQ_HDR_DONE, &data_done);
+ callback(SESSION_GET_SEQ_HDR_DONE, &data_done);
}
-static void hfi_process_msg_packet(struct venus_hfi_device *device,
- struct vidc_hal_msg_pkt_hdr *msg_hdr)
+void hfi_process_msg_packet(
+ msm_vidc_callback callback, u32 device_id,
+ struct vidc_hal_msg_pkt_hdr *msg_hdr)
{
- if (!device || !msg_hdr || msg_hdr->size <
- VIDC_IFACEQ_MIN_PKT_SIZE) {
+ if (!callback || !msg_hdr || msg_hdr->size <
+ HFI_MIN_PKT_SIZE) {
dprintk(VIDC_ERR, "hal_process_msg_packet:bad"
"packet/packet size: %d", msg_hdr->size);
return;
}
dprintk(VIDC_INFO, "Received: 0x%x in ", msg_hdr->packet);
- if ((device->intr_status & VIDC_WRAPPER_INTR_CLEAR_A2HWD_BMSK)) {
- dprintk(VIDC_ERR, "Received: Watchdog timeout %s", __func__);
- hfi_process_sys_watchdog_timeout(device);
- return;
- }
switch (msg_hdr->packet) {
case HFI_MSG_EVENT_NOTIFY:
- hfi_process_event_notify(device,
+ hfi_process_event_notify(callback, device_id,
(struct hfi_msg_event_notify_packet *) msg_hdr);
break;
case HFI_MSG_SYS_INIT_DONE:
- hfi_process_sys_init_done(device,
+ hfi_process_sys_init_done(callback, device_id,
(struct hfi_msg_sys_init_done_packet *)
msg_hdr);
break;
case HFI_MSG_SYS_SESSION_INIT_DONE:
- hfi_process_session_init_done(device,
+ hfi_process_session_init_done(callback, device_id,
(struct hfi_msg_sys_session_init_done_packet *)
msg_hdr);
break;
case HFI_MSG_SYS_SESSION_END_DONE:
- hfi_process_session_end_done(device,
+ hfi_process_session_end_done(callback, device_id,
(struct hfi_msg_sys_session_end_done_packet *)
msg_hdr);
break;
case HFI_MSG_SESSION_LOAD_RESOURCES_DONE:
- hfi_process_session_load_res_done(device,
+ hfi_process_session_load_res_done(callback, device_id,
(struct hfi_msg_session_load_resources_done_packet *)
msg_hdr);
break;
case HFI_MSG_SESSION_START_DONE:
- hfi_process_session_start_done(device,
+ hfi_process_session_start_done(callback, device_id,
(struct hfi_msg_session_start_done_packet *)
msg_hdr);
break;
case HFI_MSG_SESSION_STOP_DONE:
- hfi_process_session_stop_done(device,
+ hfi_process_session_stop_done(callback, device_id,
(struct hfi_msg_session_stop_done_packet *)
msg_hdr);
break;
case HFI_MSG_SESSION_EMPTY_BUFFER_DONE:
- hfi_process_session_etb_done(device,
+ hfi_process_session_etb_done(callback, device_id,
(struct hfi_msg_session_empty_buffer_done_packet *)
msg_hdr);
break;
case HFI_MSG_SESSION_FILL_BUFFER_DONE:
- hfi_process_session_ftb_done(device, msg_hdr);
+ hfi_process_session_ftb_done(callback, device_id, msg_hdr);
break;
case HFI_MSG_SESSION_FLUSH_DONE:
- hfi_process_session_flush_done(device,
+ hfi_process_session_flush_done(callback, device_id,
(struct hfi_msg_session_flush_done_packet *)
msg_hdr);
break;
case HFI_MSG_SESSION_PROPERTY_INFO:
- hfi_process_session_prop_info(device,
+ hfi_process_session_prop_info(callback, device_id,
(struct hfi_msg_session_property_info_packet *)
msg_hdr);
break;
case HFI_MSG_SESSION_RELEASE_RESOURCES_DONE:
- hfi_process_session_rel_res_done(device,
+ hfi_process_session_rel_res_done(callback, device_id,
(struct hfi_msg_session_release_resources_done_packet *)
msg_hdr);
break;
case HFI_MSG_SYS_RELEASE_RESOURCE:
- hfi_process_sys_rel_resource_done(device,
+ hfi_process_sys_rel_resource_done(callback, device_id,
(struct hfi_msg_sys_release_resource_done_packet *)
msg_hdr);
break;
case HFI_MSG_SESSION_GET_SEQUENCE_HEADER_DONE:
- hfi_process_session_get_seq_hdr_done(device, (struct
- hfi_msg_session_get_sequence_header_done_packet
- *) msg_hdr);
+ hfi_process_session_get_seq_hdr_done(
+ callback, device_id, (struct
+ hfi_msg_session_get_sequence_header_done_packet*)
+ msg_hdr);
break;
case HFI_MSG_SESSION_RELEASE_BUFFERS_DONE:
- hfi_process_session_rel_buf_done(device, (struct
- hfi_msg_session_release_buffers_done_packet
- *) msg_hdr);
+ hfi_process_session_rel_buf_done(
+ callback, device_id, (struct
+ hfi_msg_session_release_buffers_done_packet*)
+ msg_hdr);
break;
default:
dprintk(VIDC_ERR, "UNKNOWN_MSG_TYPE : %d", msg_hdr->packet);
break;
}
}
-
-void hfi_response_handler(struct venus_hfi_device *device)
-{
- u8 packet[VIDC_IFACEQ_MED_PKT_SIZE];
-
- dprintk(VIDC_INFO, "#####vidc_hal_response_handler#####\n");
- if (device) {
- while (!venus_hfi_iface_msgq_read(device, packet)) {
- hfi_process_msg_packet(device,
- (struct vidc_hal_msg_pkt_hdr *) packet);
- }
- while (!venus_hfi_iface_dbgq_read(device, packet)) {
- struct hfi_msg_sys_debug_packet *pkt =
- (struct hfi_msg_sys_debug_packet *) packet;
- dprintk(VIDC_FW, "FW-SAYS: %s", pkt->rg_msg_data);
- }
- } else {
- dprintk(VIDC_ERR, "SPURIOUS_INTERRUPT");
- }
-}
diff --git a/drivers/media/video/msm_vidc/msm_v4l2_vidc.c b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
index e51896c..4f39357 100644
--- a/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
+++ b/drivers/media/video/msm_vidc/msm_v4l2_vidc.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
@@ -29,7 +29,7 @@
#include "msm_vidc_debug.h"
#include "vidc_hfi_api.h"
#include "msm_smem.h"
-#include "venus_hfi.h"
+#include "vidc_hfi_api.h"
#define BASE_DEVICE_NUMBER 32
@@ -355,7 +355,8 @@
int i, rc = 0;
int smem_flags = 0;
int domain;
- struct venus_hfi_device *device;
+ struct hfi_device *hdev;
+
vidc_inst = get_vidc_inst(file, fh);
v4l2_inst = get_v4l2_inst(file, fh);
if (!v4l2_inst || !vidc_inst || !vidc_inst->core
@@ -364,7 +365,8 @@
goto exit;
}
- device = vidc_inst->core->device;
+ hdev = vidc_inst->core->device;
+
if (!v4l2_inst->mem_client) {
dprintk(VIDC_ERR, "Failed to get memory client\n");
rc = -ENOMEM;
@@ -404,9 +406,11 @@
&& (!EXTRADATA_IDX(b->length)
|| (i != EXTRADATA_IDX(b->length)))) {
smem_flags |= SMEM_SECURE;
- domain = venus_hfi_get_domain(device, CP_MAP);
+ domain = hdev->get_domain(hdev->hfi_device_data,
+ CP_MAP);
} else
- domain = venus_hfi_get_domain(device, NS_MAP);
+ domain = hdev->get_domain(hdev->hfi_device_data,
+ NS_MAP);
if (b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
smem_flags |= SMEM_INPUT;
@@ -667,6 +671,30 @@
{
}
+static int msm_vidc_get_hfi(struct platform_device *pdev,
+ struct msm_vidc_core *core)
+{
+ struct device_node *np = pdev->dev.of_node;
+ int rc = 0;
+ const char *hfi_name = NULL;
+
+ rc = of_property_read_string(np, "hfi", &hfi_name);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to read hfi from device tree\n");
+ goto err_hfi_read;
+ }
+
+ if (!strcmp(hfi_name, "venus"))
+ core->hfi_type = VIDC_HFI_VENUS;
+ else if (!strcmp(hfi_name, "q6"))
+ core->hfi_type = VIDC_HFI_Q6;
+
+ dprintk(VIDC_INFO, "hfi_type = %d\n", core->hfi_type);
+
+err_hfi_read:
+ return rc;
+}
+
static int msm_vidc_initialize_core(struct platform_device *pdev,
struct msm_vidc_core *core)
{
@@ -685,6 +713,11 @@
init_completion(&core->completions[i]);
}
+ rc = msm_vidc_get_hfi(pdev, core);
+ if (rc)
+ dprintk(VIDC_ERR,
+ "Failed to read Host-Firmware Interface rc: %d\n", rc);
+
return rc;
}
@@ -736,8 +769,8 @@
}
video_set_drvdata(&core->vdev[MSM_VIDC_ENCODER].vdev, core);
- core->device =
- venus_hfi_get_device(core->id, pdev, &handle_cmd_response);
+ core->device = vidc_hfi_initialize(core->hfi_type, core->id,
+ pdev, &handle_cmd_response);
if (!core->device) {
dprintk(VIDC_ERR, "Failed to create HFI device\n");
goto err_cores_exceeded;
@@ -774,9 +807,20 @@
static int __devexit msm_vidc_remove(struct platform_device *pdev)
{
int rc = 0;
- struct msm_vidc_core *core = pdev->dev.platform_data;
+ struct msm_vidc_core *core;
- venus_hfi_delete_device(core->device);
+ if (!pdev) {
+ dprintk(VIDC_ERR, "%s invalid input %p", __func__, pdev);
+ return -EINVAL;
+ }
+ core = pdev->dev.platform_data;
+
+ if (!core) {
+ dprintk(VIDC_ERR, "%s invalid core", __func__);
+ return -EINVAL;
+ }
+
+ vidc_hfi_deinitialize(core->hfi_type, core->device);
video_unregister_device(&core->vdev[MSM_VIDC_ENCODER].vdev);
video_unregister_device(&core->vdev[MSM_VIDC_DECODER].vdev);
v4l2_device_unregister(&core->v4l2_dev);
diff --git a/drivers/media/video/msm_vidc/msm_vdec.c b/drivers/media/video/msm_vidc/msm_vdec.c
index 525bad8..24407dd 100644
--- a/drivers/media/video/msm_vidc/msm_vdec.c
+++ b/drivers/media/video/msm_vidc/msm_vdec.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
@@ -377,6 +377,14 @@
struct vidc_buffer_addr_info buffer_info;
int extra_idx = 0;
int i;
+ struct hfi_device *hdev;
+
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s invalid parameters", __func__);
+ return -EINVAL;
+ }
+ hdev = inst->core->device;
+
switch (b->type) {
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
break;
@@ -415,7 +423,7 @@
buffer_info.extradata_addr = 0;
buffer_info.extradata_size = 0;
}
- rc = venus_hfi_session_set_buffers(
+ rc = hdev->session_set_buffers(
(void *)inst->session, &buffer_info);
if (rc)
dprintk(VIDC_ERR,
@@ -436,6 +444,15 @@
struct msm_vidc_core *core = inst->core;
int extra_idx = 0;
int i;
+ struct hfi_device *hdev;
+
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s invalid parameters", __func__);
+ return -EINVAL;
+ }
+
+ hdev = inst->core->device;
+
if (inst->state == MSM_VIDC_CORE_INVALID ||
core->state == VIDC_CORE_INVALID) {
dprintk(VIDC_ERR,
@@ -484,7 +501,7 @@
else
buffer_info.extradata_addr = 0;
buffer_info.response_required = false;
- rc = venus_hfi_session_release_buffers(
+ rc = hdev->session_release_buffers(
(void *)inst->session, &buffer_info);
if (rc)
dprintk(VIDC_ERR,
@@ -809,6 +826,7 @@
unsigned long flags;
struct hal_buffer_requirements *bufreq;
int extra_idx = 0;
+ struct hfi_device *hdev;
if (!q || !num_buffers || !num_planes
|| !sizes || !q->drv_priv) {
dprintk(VIDC_ERR, "Invalid input, q = %p, %p, %p\n",
@@ -816,6 +834,14 @@
return -EINVAL;
}
inst = q->drv_priv;
+
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s invalid parameters", __func__);
+ return -EINVAL;
+ }
+
+ hdev = inst->core->device;
+
switch (q->type) {
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
*num_planes = inst->fmts[OUTPUT_PORT]->num_planes;
@@ -851,7 +877,7 @@
new_buf_count.buffer_type = HAL_BUFFER_OUTPUT;
new_buf_count.buffer_count_actual = *num_buffers;
- rc = venus_hfi_session_set_property(inst->session,
+ rc = hdev->session_set_property(inst->session,
property_id, &new_buf_count);
}
@@ -1088,6 +1114,13 @@
enum hal_property property_id = 0;
u32 property_val = 0;
void *pdata;
+ struct hfi_device *hdev;
+
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s invalid parameters", __func__);
+ return -EINVAL;
+ }
+ hdev = inst->core->device;
switch (ctrl->id) {
case V4L2_CID_MPEG_VIDC_VIDEO_STREAM_FORMAT:
@@ -1166,7 +1199,7 @@
property_id,
msm_vdec_ctrls[control_idx].id,
control.value);
- rc = venus_hfi_session_set_property((void *)
+ rc = hdev->session_set_property((void *)
inst->session, property_id,
pdata);
}
diff --git a/drivers/media/video/msm_vidc/msm_venc.c b/drivers/media/video/msm_vidc/msm_venc.c
index 341e06f..0326c79 100644
--- a/drivers/media/video/msm_vidc/msm_venc.c
+++ b/drivers/media/video/msm_vidc/msm_venc.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
@@ -611,11 +611,19 @@
struct hal_buffer_count_actual new_buf_count;
enum hal_property property_id;
unsigned long flags;
+ struct hfi_device *hdev;
if (!q || !q->drv_priv) {
dprintk(VIDC_ERR, "Invalid input, q = %p\n", q);
return -EINVAL;
}
inst = q->drv_priv;
+
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s invalid parameters", __func__);
+ return -EINVAL;
+ }
+ hdev = inst->core->device;
+
switch (q->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
*num_planes = 1;
@@ -648,7 +656,7 @@
property_id = HAL_PARAM_BUFFER_COUNT_ACTUAL;
new_buf_count.buffer_type = HAL_BUFFER_INPUT;
new_buf_count.buffer_count_actual = *num_buffers;
- rc = venus_hfi_session_set_property(inst->session,
+ rc = hdev->session_set_property(inst->session,
property_id, &new_buf_count);
dprintk(VIDC_DBG, "size = %d, alignment = %d, count = %d\n",
inst->buff_req.buffer[0].buffer_size,
@@ -966,6 +974,13 @@
u32 property_id = 0, property_val = 0;
void *pdata;
struct v4l2_ctrl *temp_ctrl = NULL;
+ struct hfi_device *hdev;
+
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s invalid parameters", __func__);
+ return -EINVAL;
+ }
+ hdev = inst->core->device;
/* Small helper macro for quickly getting a control and err checking */
#define TRY_GET_CTRL(__ctrl_id) ({ \
@@ -1104,6 +1119,7 @@
property_id =
HAL_CONFIG_VENC_TARGET_BITRATE;
bitrate.bit_rate = ctrl->val;
+ bitrate.layer_id = 0;
pdata = &bitrate;
break;
case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE:
@@ -1218,6 +1234,7 @@
quantization.qpi = ctrl->val;
quantization.qpp = qpp->val;
quantization.qpb = qpb->val;
+ quantization.layer_id = 0;
pdata = &quantization;
break;
@@ -1233,6 +1250,7 @@
quantization.qpp = ctrl->val;
quantization.qpi = qpi->val;
quantization.qpb = qpb->val;
+ quantization.layer_id = 0;
pdata = &quantization;
break;
@@ -1248,6 +1266,7 @@
quantization.qpb = ctrl->val;
quantization.qpi = qpi->val;
quantization.qpp = qpp->val;
+ quantization.layer_id = 0;
pdata = &quantization;
break;
@@ -1405,7 +1424,7 @@
dprintk(VIDC_DBG, "Control: HAL property=%d,ctrl_value=%d\n",
property_id,
ctrl->val);
- rc = venus_hfi_session_set_property((void *)inst->session,
+ rc = hdev->session_set_property((void *)inst->session,
property_id, pdata);
}
@@ -1570,6 +1589,14 @@
void *pdata;
int rc = 0;
struct hal_frame_rate frame_rate;
+ struct hfi_device *hdev;
+
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s invalid parameters", __func__);
+ return -EINVAL;
+ }
+ hdev = inst->core->device;
+
property_id = HAL_CONFIG_FRAME_RATE;
if (a->parm.output.timeperframe.denominator) {
switch (a->type) {
@@ -1597,7 +1624,7 @@
frame_rate.frame_rate = inst->prop.fps * (0x1<<16);
frame_rate.buffer_type = HAL_BUFFER_OUTPUT;
pdata = &frame_rate;
- rc = venus_hfi_session_set_property((void *)inst->session,
+ rc = hdev->session_set_property((void *)inst->session,
property_id, pdata);
if (rc) {
dprintk(VIDC_WARN,
@@ -1614,11 +1641,19 @@
struct hal_frame_size frame_sz;
int rc = 0;
int i;
+ struct hfi_device *hdev;
if (!inst || !f) {
dprintk(VIDC_ERR,
"Invalid input, inst = %p, format = %p\n", inst, f);
return -EINVAL;
}
+
+ if (!inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s invalid parameters", __func__);
+ return -EINVAL;
+ }
+ hdev = inst->core->device;
+
if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
fmt = msm_comm_get_pixel_fmt_fourcc(venc_formats,
ARRAY_SIZE(venc_formats), f->fmt.pix_mp.pixelformat,
@@ -1638,7 +1673,7 @@
frame_sz.height = inst->prop.height;
dprintk(VIDC_DBG, "width = %d, height = %d\n",
frame_sz.width, frame_sz.height);
- rc = venus_hfi_session_set_property((void *)inst->session,
+ rc = hdev->session_set_property((void *)inst->session,
HAL_PARAM_FRAME_SIZE, &frame_sz);
if (rc) {
dprintk(VIDC_ERR,
@@ -1646,7 +1681,7 @@
goto exit;
}
frame_sz.buffer_type = HAL_BUFFER_OUTPUT;
- rc = venus_hfi_session_set_property((void *)inst->session,
+ rc = hdev->session_set_property((void *)inst->session,
HAL_PARAM_FRAME_SIZE, &frame_sz);
if (rc) {
dprintk(VIDC_ERR,
@@ -1752,6 +1787,14 @@
int rc = 0;
int i;
struct vidc_buffer_addr_info buffer_info;
+ struct hfi_device *hdev;
+
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s invalid parameters", __func__);
+ return -EINVAL;
+ }
+
+ hdev = inst->core->device;
switch (b->type) {
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
@@ -1769,7 +1812,7 @@
b->m.planes[i].m.userptr;
buffer_info.extradata_size = 0;
buffer_info.extradata_addr = 0;
- rc = venus_hfi_session_set_buffers(
+ rc = hdev->session_set_buffers(
(void *)inst->session, &buffer_info);
if (rc)
dprintk(VIDC_ERR,
@@ -1790,6 +1833,15 @@
int rc = 0;
int i;
struct vidc_buffer_addr_info buffer_info;
+ struct hfi_device *hdev;
+
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s invalid parameters", __func__);
+ return -EINVAL;
+ }
+
+ hdev = inst->core->device;
+
rc = msm_comm_try_state(inst, MSM_VIDC_RELEASE_RESOURCES_DONE);
if (rc) {
dprintk(VIDC_ERR,
@@ -1814,7 +1866,7 @@
buffer_info.extradata_size = 0;
buffer_info.extradata_addr = 0;
buffer_info.response_required = false;
- rc = venus_hfi_session_release_buffers(
+ rc = hdev->session_release_buffers(
(void *)inst->session, &buffer_info);
if (rc)
dprintk(VIDC_ERR,
diff --git a/drivers/media/video/msm_vidc/msm_vidc.c b/drivers/media/video/msm_vidc/msm_vidc.c
index b9f1508..73c9860 100644
--- a/drivers/media/video/msm_vidc/msm_vidc.c
+++ b/drivers/media/video/msm_vidc/msm_vidc.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
@@ -21,7 +21,7 @@
#include "msm_vidc_common.h"
#include "msm_smem.h"
#include <linux/delay.h>
-#include "venus_hfi.h"
+#include "vidc_hfi_api.h"
#define MAX_EVENTS 30
@@ -86,11 +86,14 @@
struct msm_vidc_iommu_info maps[MAX_MAP])
{
struct msm_vidc_inst *inst = instance;
+ struct hfi_device *hdev;
- if (!inst || !maps || !inst->core)
+ if (!inst || !maps || !inst->core || !inst->core->device)
return -EINVAL;
- return venus_hfi_iommu_get_map(inst->core->device, maps);
+ hdev = inst->core->device;
+
+ return hdev->iommu_get_map(hdev->hfi_device_data, maps);
}
int msm_vidc_querycap(void *instance, struct v4l2_capability *cap)
diff --git a/drivers/media/video/msm_vidc/msm_vidc_common.c b/drivers/media/video/msm_vidc/msm_vidc_common.c
index eac715f..955f4ca 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_common.c
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.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
@@ -20,7 +20,6 @@
#include "vidc_hfi_api.h"
#include "msm_smem.h"
#include "msm_vidc_debug.h"
-#include "venus_hfi.h"
#define HW_RESPONSE_TIMEOUT (5 * 60 * 1000)
@@ -77,14 +76,22 @@
{
int load;
int rc = 0;
+ struct hfi_device *hdev;
if (!core || type >= MSM_VIDC_MAX_DEVICES) {
dprintk(VIDC_ERR, "Invalid args: %p, %d\n", core, type);
return -EINVAL;
}
+
+ hdev = core->device;
+ if (!hdev) {
+ dprintk(VIDC_ERR, "Invalid device handle %p\n", hdev);
+ return -EINVAL;
+ }
+
load = msm_comm_get_load(core, type);
- rc = venus_hfi_scale_bus(core->device, load, type, mtype);
+ rc = hdev->scale_bus(hdev->hfi_device_data, load, type, mtype);
if (rc)
dprintk(VIDC_ERR, "Failed to scale bus: %d\n", rc);
@@ -95,14 +102,23 @@
enum mem_type mtype)
{
int i;
+ struct hfi_device *hdev;
+
+ if (!core || !core->device) {
+ dprintk(VIDC_ERR, "%s invalid parameters", __func__);
+ return;
+ }
+ hdev = core->device;
+
for (i = 0; i < MSM_VIDC_MAX_DEVICES; i++) {
if ((mtype & DDR_MEM) &&
- venus_hfi_scale_bus(core->device, 0, i, DDR_MEM)) {
+ hdev->scale_bus(hdev->hfi_device_data, 0, i, DDR_MEM)) {
dprintk(VIDC_WARN,
"Failed to unvote for DDR accesses\n");
}
if ((mtype & OCMEM_MEM) &&
- venus_hfi_scale_bus(core->device, 0, i, OCMEM_MEM)) {
+ hdev->scale_bus(hdev->hfi_device_data, 0, i,
+ OCMEM_MEM)) {
dprintk(VIDC_WARN,
"Failed to unvote for OCMEM accesses\n");
}
@@ -876,15 +892,23 @@
{
int num_mbs_per_sec;
int rc = 0;
+ struct hfi_device *hdev;
if (!core) {
- dprintk(VIDC_ERR, "Invalid args: %p\n", core);
+ dprintk(VIDC_ERR, "%s Invalid args: %p\n", __func__, core);
+ return -EINVAL;
+ }
+
+ hdev = core->device;
+ if (!hdev) {
+ dprintk(VIDC_ERR, "%s Invalid device handle: %p\n",
+ __func__, hdev);
return -EINVAL;
}
num_mbs_per_sec = msm_comm_get_load(core, MSM_VIDC_ENCODER);
num_mbs_per_sec += msm_comm_get_load(core, MSM_VIDC_DECODER);
dprintk(VIDC_INFO, "num_mbs_per_sec = %d\n", num_mbs_per_sec);
- rc = venus_hfi_scale_clocks(core->device, num_mbs_per_sec);
+ rc = hdev->scale_clocks(hdev->hfi_device_data, num_mbs_per_sec);
if (rc)
dprintk(VIDC_ERR, "Failed to set clock rate: %d\n", rc);
return rc;
@@ -892,12 +916,16 @@
void msm_comm_scale_clocks_and_bus(struct msm_vidc_inst *inst)
{
- struct msm_vidc_core *core = inst->core;
+ struct msm_vidc_core *core;
+ struct hfi_device *hdev;
- if (!inst) {
- dprintk(VIDC_WARN, "Invalid params\n");
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s Invalid params\n", __func__);
return;
}
+ core = inst->core;
+ hdev = core->device;
+
if (msm_comm_scale_clocks(core)) {
dprintk(VIDC_WARN,
"Failed to scale clocks. Performance might be impacted\n");
@@ -906,7 +934,7 @@
dprintk(VIDC_WARN,
"Failed to scale DDR bus. Performance might be impacted\n");
}
- if (venus_hfi_is_ocmem_present(core->device)) {
+ if (hdev->is_ocmem_present(hdev->hfi_device_data)) {
if (msm_comm_scale_bus(core, inst->session_type,
OCMEM_MEM))
dprintk(VIDC_WARN,
@@ -926,6 +954,14 @@
static int msm_comm_unset_ocmem(struct msm_vidc_core *core)
{
int rc = 0;
+ struct hfi_device *hdev;
+
+ if (!core || !core->device) {
+ dprintk(VIDC_ERR, "%s invalid parameters", __func__);
+ return -EINVAL;
+ }
+ hdev = core->device;
+
if (core->state == VIDC_CORE_INVALID) {
dprintk(VIDC_ERR,
"Core is in bad state. Cannot unset ocmem\n");
@@ -935,7 +971,7 @@
init_completion(
&core->completions[SYS_MSG_INDEX(RELEASE_RESOURCE_DONE)]);
- rc = venus_hfi_unset_ocmem(core->device);
+ rc = hdev->unset_ocmem(hdev->hfi_device_data);
if (rc) {
dprintk(VIDC_ERR, "Failed to set OCMEM on driver\n");
goto release_ocmem_failed;
@@ -951,39 +987,6 @@
return rc;
}
-int msm_vidc_ocmem_notify_handler(struct notifier_block *this,
- unsigned long event, void *data)
-{
- struct ocmem_buf *buff = data;
- struct msm_vidc_core *core;
- struct venus_hfi_device *device;
- struct venus_resources *resources;
- struct on_chip_mem *ocmem;
- int rc = NOTIFY_DONE;
- if (event == OCMEM_ALLOC_GROW) {
- ocmem = container_of(this, struct on_chip_mem, vidc_ocmem_nb);
- if (!ocmem) {
- dprintk(VIDC_ERR, "Wrong handler passed\n");
- rc = NOTIFY_BAD;
- goto bad_notfier;
- }
- resources = container_of(ocmem,
- struct venus_resources, ocmem);
- device = container_of(resources,
- struct venus_hfi_device, resources);
- core = container_of((void *)device,
- struct msm_vidc_core, device);
- if (venus_hfi_set_ocmem(core->device, buff)) {
- dprintk(VIDC_ERR, "Failed to set ocmem: %d\n", rc);
- goto ocmem_set_failed;
- }
- rc = NOTIFY_OK;
- }
-ocmem_set_failed:
-bad_notfier:
- return rc;
-}
-
static int msm_comm_init_core_done(struct msm_vidc_inst *inst)
{
struct msm_vidc_core *core = inst->core;
@@ -1022,11 +1025,11 @@
int rc = 0;
struct msm_vidc_core *core = inst->core;
unsigned long flags;
- struct venus_hfi_device *device;
+ struct hfi_device *hdev;
if (!core || !core->device)
return -EINVAL;
- device = core->device;
+ hdev = core->device;
mutex_lock(&core->sync_lock);
if (core->state >= VIDC_CORE_INIT) {
@@ -1041,7 +1044,7 @@
goto fail_scale_bus;
}
- rc = venus_hfi_load_fw(core->device);
+ rc = hdev->load_fw(hdev->hfi_device_data);
if (rc) {
dprintk(VIDC_ERR, "Failed to load video firmware\n");
goto fail_load_fw;
@@ -1053,7 +1056,7 @@
}
init_completion(&core->completions[SYS_MSG_INDEX(SYS_INIT_DONE)]);
- rc = venus_hfi_core_init(core->device);
+ rc = hdev->core_init(hdev->hfi_device_data);
if (rc) {
dprintk(VIDC_ERR, "Failed to init core, id = %d\n", core->id);
goto fail_core_init;
@@ -1066,7 +1069,7 @@
mutex_unlock(&core->sync_lock);
return rc;
fail_core_init:
- venus_hfi_unload_fw(core->device);
+ hdev->unload_fw(hdev->hfi_device_data);
fail_load_fw:
msm_comm_unvote_buses(core, DDR_MEM);
fail_scale_bus:
@@ -1077,8 +1080,18 @@
static int msm_vidc_deinit_core(struct msm_vidc_inst *inst)
{
int rc = 0;
- struct msm_vidc_core *core = inst->core;
+ struct msm_vidc_core *core;
+ struct hfi_device *hdev;
unsigned long flags;
+
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s invalid parameters", __func__);
+ return -EINVAL;
+ }
+
+ core = inst->core;
+ hdev = core->device;
+
mutex_lock(&core->sync_lock);
if (core->state == VIDC_CORE_UNINIT) {
dprintk(VIDC_INFO, "Video core: %d is already in state: %d\n",
@@ -1088,9 +1101,9 @@
msm_comm_scale_clocks_and_bus(inst);
if (list_empty(&core->instances)) {
msm_comm_unset_ocmem(core);
- venus_hfi_free_ocmem(core->device);
+ hdev->free_ocmem(hdev->hfi_device_data);
dprintk(VIDC_DBG, "Calling vidc_hal_core_release\n");
- rc = venus_hfi_core_release(core->device);
+ rc = hdev->core_release(hdev->hfi_device_data);
if (rc) {
dprintk(VIDC_ERR, "Failed to release core, id = %d\n",
core->id);
@@ -1099,7 +1112,7 @@
spin_lock_irqsave(&core->lock, flags);
core->state = VIDC_CORE_UNINIT;
spin_unlock_irqrestore(&core->lock, flags);
- venus_hfi_unload_fw(core->device);
+ hdev->unload_fw(hdev->hfi_device_data);
msm_comm_unvote_buses(core, DDR_MEM|OCMEM_MEM);
}
core_already_uninited:
@@ -1182,6 +1195,14 @@
{
int rc = 0;
int fourcc = 0;
+ struct hfi_device *hdev;
+
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s invalid parameters", __func__);
+ return -EINVAL;
+ }
+ hdev = inst->core->device;
+
if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_OPEN)) {
dprintk(VIDC_INFO, "inst: %p is already in state: %d\n",
inst, inst->state);
@@ -1197,7 +1218,7 @@
}
init_completion(
&inst->completions[SESSION_MSG_INDEX(SESSION_INIT_DONE)]);
- inst->session = venus_hfi_session_init(inst->core->device, (u32) inst,
+ inst->session = hdev->session_init(hdev->hfi_device_data, (u32) inst,
get_hal_domain(inst->session_type),
get_hal_codec_type(fourcc));
if (!inst->session) {
@@ -1218,6 +1239,14 @@
{
int rc = 0;
u32 ocmem_sz = 0;
+ struct hfi_device *hdev;
+
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s invalid parameters", __func__);
+ return -EINVAL;
+ }
+ hdev = inst->core->device;
+
if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_LOAD_RESOURCES)) {
dprintk(VIDC_INFO, "inst: %p is already in state: %d\n",
inst, inst->state);
@@ -1227,7 +1256,7 @@
rc = msm_comm_scale_bus(inst->core, inst->session_type, OCMEM_MEM);
if (!rc) {
mutex_lock(&inst->core->sync_lock);
- rc = venus_hfi_alloc_ocmem(inst->core->device, ocmem_sz);
+ rc = hdev->alloc_ocmem(hdev->hfi_device_data, ocmem_sz);
mutex_unlock(&inst->core->sync_lock);
if (rc) {
dprintk(VIDC_WARN,
@@ -1238,7 +1267,7 @@
dprintk(VIDC_WARN,
"Failed to vote for OCMEM BW. Performance will be impacted\n");
}
- rc = venus_hfi_session_load_res((void *) inst->session);
+ rc = hdev->session_load_res((void *) inst->session);
if (rc) {
dprintk(VIDC_ERR,
"Failed to send load resources\n");
@@ -1252,6 +1281,15 @@
static int msm_vidc_start(int flipped_state, struct msm_vidc_inst *inst)
{
int rc = 0;
+ struct hfi_device *hdev;
+
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s invalid parameters", __func__);
+ return -EINVAL;
+ }
+
+ hdev = inst->core->device;
+
if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_START)) {
dprintk(VIDC_INFO,
"inst: %p is already in state: %d\n",
@@ -1260,7 +1298,7 @@
}
init_completion(
&inst->completions[SESSION_MSG_INDEX(SESSION_START_DONE)]);
- rc = venus_hfi_session_start((void *) inst->session);
+ rc = hdev->session_start((void *) inst->session);
if (rc) {
dprintk(VIDC_ERR,
"Failed to send start\n");
@@ -1274,6 +1312,14 @@
static int msm_vidc_stop(int flipped_state, struct msm_vidc_inst *inst)
{
int rc = 0;
+ struct hfi_device *hdev;
+
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s invalid parameters", __func__);
+ return -EINVAL;
+ }
+ hdev = inst->core->device;
+
if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_STOP)) {
dprintk(VIDC_INFO,
"inst: %p is already in state: %d\n",
@@ -1283,7 +1329,7 @@
dprintk(VIDC_DBG, "Send Stop to hal\n");
init_completion(
&inst->completions[SESSION_MSG_INDEX(SESSION_STOP_DONE)]);
- rc = venus_hfi_session_stop((void *) inst->session);
+ rc = hdev->session_stop((void *) inst->session);
if (rc) {
dprintk(VIDC_ERR, "Failed to send stop\n");
goto exit;
@@ -1296,6 +1342,14 @@
static int msm_vidc_release_res(int flipped_state, struct msm_vidc_inst *inst)
{
int rc = 0;
+ struct hfi_device *hdev;
+
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s invalid parameters", __func__);
+ return -EINVAL;
+ }
+ hdev = inst->core->device;
+
if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_RELEASE_RESOURCES)) {
dprintk(VIDC_INFO,
"inst: %p is already in state: %d\n",
@@ -1306,7 +1360,7 @@
"Send release res to hal\n");
init_completion(
&inst->completions[SESSION_MSG_INDEX(SESSION_RELEASE_RESOURCE_DONE)]);
- rc = venus_hfi_session_release_res((void *) inst->session);
+ rc = hdev->session_release_res((void *) inst->session);
if (rc) {
dprintk(VIDC_ERR,
"Failed to send release resources\n");
@@ -1317,9 +1371,17 @@
return rc;
}
-static int msm_comm_session_close(int flipped_state, struct msm_vidc_inst *inst)
+static int msm_comm_session_close(int flipped_state,
+ struct msm_vidc_inst *inst)
{
int rc = 0;
+ struct hfi_device *hdev;
+
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s invalid params", __func__);
+ return -EINVAL;
+ }
+ hdev = inst->core->device;
if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_CLOSE)) {
dprintk(VIDC_INFO,
"inst: %p is already in state: %d\n",
@@ -1330,7 +1392,7 @@
"Send session close to hal\n");
init_completion(
&inst->completions[SESSION_MSG_INDEX(SESSION_END_DONE)]);
- rc = venus_hfi_session_end((void *) inst->session);
+ rc = hdev->session_end((void *) inst->session);
if (rc) {
dprintk(VIDC_ERR,
"Failed to send close\n");
@@ -1479,6 +1541,7 @@
struct vb2_buf_entry *entry;
struct vidc_frame_data frame_data;
struct msm_vidc_core *core;
+ struct hfi_device *hdev;
q = vb->vb2_queue;
inst = q->drv_priv;
if (!inst || !vb) {
@@ -1491,6 +1554,11 @@
"Invalid input: %p, %p, %p\n", inst, core, vb);
return -EINVAL;
}
+ hdev = core->device;
+ if (!hdev) {
+ dprintk(VIDC_ERR, "Invalid input: %p", hdev);
+ return -EINVAL;
+ }
if (inst->state == MSM_VIDC_CORE_INVALID ||
core->state == VIDC_CORE_INVALID) {
@@ -1534,7 +1602,7 @@
dprintk(VIDC_DBG,
"Sending etb to hal: Alloc: %d :filled: %d\n",
frame_data.alloc_len, frame_data.filled_len);
- rc = venus_hfi_session_etb((void *) inst->session,
+ rc = hdev->session_etb((void *) inst->session,
&frame_data);
if (!rc)
msm_vidc_debugfs_update(inst,
@@ -1564,7 +1632,7 @@
seq_hdr.seq_hdr = (u8 *) vb->v4l2_planes[0].
m.userptr;
seq_hdr.seq_hdr_len = vb->v4l2_planes[0].length;
- rc = venus_hfi_session_get_seq_hdr((void *)
+ rc = hdev->session_get_seq_hdr((void *)
inst->session, &seq_hdr);
if (!rc) {
inst->vb2_seq_hdr = vb;
@@ -1572,7 +1640,7 @@
inst->vb2_seq_hdr);
}
} else {
- rc = venus_hfi_session_ftb((void *)
+ rc = hdev->session_ftb((void *)
inst->session, &frame_data);
if (!rc)
msm_vidc_debugfs_update(inst,
@@ -1595,6 +1663,14 @@
int msm_comm_try_get_bufreqs(struct msm_vidc_inst *inst)
{
int rc = 0;
+ struct hfi_device *hdev;
+
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s invalid parameters", __func__);
+ return -EINVAL;
+ }
+ hdev = inst->core->device;
+
mutex_lock(&inst->sync_lock);
if (inst->state < MSM_VIDC_OPEN_DONE || inst->state >= MSM_VIDC_CLOSE) {
dprintk(VIDC_ERR,
@@ -1604,7 +1680,7 @@
}
init_completion(
&inst->completions[SESSION_MSG_INDEX(SESSION_PROPERTY_INFO)]);
- rc = venus_hfi_session_get_buf_req((void *) inst->session);
+ rc = hdev->session_get_buf_req((void *) inst->session);
if (rc) {
dprintk(VIDC_ERR, "Failed to get property\n");
goto exit;
@@ -1632,6 +1708,7 @@
int rc = 0;
unsigned long flags;
struct msm_vidc_core *core;
+ struct hfi_device *hdev;
if (!inst) {
dprintk(VIDC_ERR,
"Invalid instance pointer = %p\n", inst);
@@ -1643,6 +1720,11 @@
"Invalid core pointer = %p\n", core);
return -EINVAL;
}
+ hdev = core->device;
+ if (!hdev) {
+ dprintk(VIDC_ERR, "Invalid device pointer = %p\n", hdev);
+ return -EINVAL;
+ }
spin_lock_irqsave(&inst->lock, flags);
if (!list_empty(&inst->internalbufs)) {
list_for_each_safe(ptr, next, &inst->internalbufs) {
@@ -1659,7 +1741,7 @@
init_completion(
&inst->completions[SESSION_MSG_INDEX
(SESSION_RELEASE_BUFFER_DONE)]);
- rc = venus_hfi_session_release_buffers(
+ rc = hdev->session_release_buffers(
(void *) inst->session,
&buffer_info);
if (rc)
@@ -1692,6 +1774,7 @@
int rc = 0;
unsigned long flags;
struct msm_vidc_core *core;
+ struct hfi_device *hdev;
if (!inst) {
dprintk(VIDC_ERR,
"Invalid instance pointer = %p\n", inst);
@@ -1703,6 +1786,11 @@
"Invalid core pointer = %p\n", core);
return -EINVAL;
}
+ hdev = core->device;
+ if (!hdev) {
+ dprintk(VIDC_ERR, "Invalid device pointer = %p\n", hdev);
+ return -EINVAL;
+ }
spin_lock_irqsave(&inst->lock, flags);
if (!list_empty(&inst->persistbufs)) {
list_for_each_safe(ptr, next, &inst->persistbufs) {
@@ -1719,7 +1807,7 @@
init_completion(
&inst->completions[SESSION_MSG_INDEX
(SESSION_RELEASE_BUFFER_DONE)]);
- rc = venus_hfi_session_release_buffers(
+ rc = hdev->session_release_buffers(
(void *) inst->session,
&buffer_info);
if (rc)
@@ -1747,17 +1835,25 @@
enum hal_property ptype, void *pdata)
{
int rc = 0;
+ struct hfi_device *hdev;
if (!inst) {
dprintk(VIDC_ERR, "Invalid input: %p\n", inst);
return -EINVAL;
}
+
+ if (!inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s invalid parameters", __func__);
+ return -EINVAL;
+ }
+ hdev = inst->core->device;
+
mutex_lock(&inst->sync_lock);
if (inst->state < MSM_VIDC_OPEN_DONE || inst->state >= MSM_VIDC_CLOSE) {
dprintk(VIDC_ERR, "Not in proper state to set property\n");
rc = -EAGAIN;
goto exit;
}
- rc = venus_hfi_session_set_property((void *)inst->session,
+ rc = hdev->session_set_property((void *)inst->session,
ptype, pdata);
if (rc)
dprintk(VIDC_ERR, "Failed to set hal property for framesize\n");
@@ -1777,12 +1873,15 @@
unsigned long smem_flags = 0;
struct hal_buffer_requirements *scratch_buf;
int i;
- struct venus_hfi_device *device;
+ struct hfi_device *hdev;
- if (!inst || !inst->core || !inst->core->device)
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s invalid parameters", __func__);
return -EINVAL;
+ }
- device = inst->core->device;
+ hdev = inst->core->device;
+
scratch_buf =
&inst->buff_req.buffer[HAL_BUFFER_INTERNAL_SCRATCH];
dprintk(VIDC_DBG,
@@ -1792,10 +1891,10 @@
if (msm_comm_release_scratch_buffers(inst))
dprintk(VIDC_WARN, "Failed to release scratch buffers\n");
if (inst->mode == VIDC_SECURE) {
- domain = venus_hfi_get_domain(device, CP_MAP);
+ domain = hdev->get_domain(hdev->hfi_device_data, CP_MAP);
smem_flags |= SMEM_SECURE;
} else
- domain = venus_hfi_get_domain(device, NS_MAP);
+ domain = hdev->get_domain(hdev->hfi_device_data, NS_MAP);
if (scratch_buf->buffer_size) {
for (i = 0; i < scratch_buf->buffer_count_actual;
@@ -1822,7 +1921,7 @@
buffer_info.align_device_addr = handle->device_addr;
dprintk(VIDC_DBG, "Scratch buffer address: %x",
buffer_info.align_device_addr);
- rc = venus_hfi_session_set_buffers(
+ rc = hdev->session_set_buffers(
(void *) inst->session, &buffer_info);
if (rc) {
dprintk(VIDC_ERR,
@@ -1854,12 +1953,14 @@
int domain;
struct hal_buffer_requirements *persist_buf;
int i;
- struct venus_hfi_device *device;
+ struct hfi_device *hdev;
- if (!inst || !inst->core || !inst->core->device)
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s invalid parameters", __func__);
return -EINVAL;
+ }
- device = inst->core->device;
+ hdev = inst->core->device;
persist_buf =
&inst->buff_req.buffer[HAL_BUFFER_INTERNAL_PERSIST];
@@ -1874,10 +1975,10 @@
}
if (inst->mode == VIDC_SECURE) {
- domain = venus_hfi_get_domain(device, CP_MAP);
+ domain = hdev->get_domain(hdev->hfi_device_data, CP_MAP);
flags |= SMEM_SECURE;
} else
- domain = venus_hfi_get_domain(device, NS_MAP);
+ domain = hdev->get_domain(hdev->hfi_device_data, NS_MAP);
if (persist_buf->buffer_size) {
for (i = 0; i < persist_buf->buffer_count_actual; i++) {
@@ -1903,7 +2004,7 @@
buffer_info.align_device_addr = handle->device_addr;
dprintk(VIDC_DBG, "Persist buffer address: %x",
buffer_info.align_device_addr);
- rc = venus_hfi_session_set_buffers(
+ rc = hdev->session_set_buffers(
(void *) inst->session, &buffer_info);
if (rc) {
dprintk(VIDC_ERR,
@@ -1977,6 +2078,7 @@
struct vb2_buf_entry *temp;
struct mutex *lock;
struct msm_vidc_core *core;
+ struct hfi_device *hdev;
if (!inst) {
dprintk(VIDC_ERR,
"Invalid instance pointer = %p\n", inst);
@@ -1988,6 +2090,11 @@
"Invalid core pointer = %p\n", core);
return -EINVAL;
}
+ hdev = core->device;
+ if (!hdev) {
+ dprintk(VIDC_ERR, "Invalid device pointer = %p", hdev);
+ return -EINVAL;
+ }
ip_flush = flags & V4L2_QCOM_CMD_FLUSH_OUTPUT;
op_flush = flags & V4L2_QCOM_CMD_FLUSH_CAPTURE;
@@ -2014,7 +2121,7 @@
dprintk(VIDC_WARN,
"FLUSH BUG: Pending q not empty! It should be empty\n");
}
- rc = venus_hfi_session_flush(inst->session,
+ rc = hdev->session_flush(inst->session,
HAL_FLUSH_OUTPUT);
} else {
if (!list_empty(&inst->pendingq)) {
@@ -2035,7 +2142,7 @@
kfree(temp);
}
}
- rc = venus_hfi_session_flush(inst->session,
+ rc = hdev->session_flush(inst->session,
HAL_FLUSH_ALL);
}
mutex_unlock(&inst->sync_lock);
diff --git a/drivers/media/video/msm_vidc/msm_vidc_debug.c b/drivers/media/video/msm_vidc/msm_vidc_debug.c
index bdf146e..ff829d7 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_debug.c
+++ b/drivers/media/video/msm_vidc/msm_vidc_debug.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
@@ -12,7 +12,7 @@
*/
#include "msm_vidc_debug.h"
-#include "venus_hfi.h"
+#include "vidc_hfi_api.h"
#define MAX_DBG_BUF_SIZE 4096
int msm_vidc_debug = 0x3;
@@ -53,22 +53,26 @@
size_t count, loff_t *ppos)
{
struct msm_vidc_core *core = file->private_data;
- struct venus_hfi_device *device;
+ struct hfi_device *hdev;
int i = 0;
if (!core || !core->device) {
dprintk(VIDC_ERR, "Invalid params, core: %p\n", core);
return 0;
}
- device = core->device;
+ hdev = core->device;
INIT_DBG_BUF(dbg_buf);
write_str(&dbg_buf, "===============================\n");
write_str(&dbg_buf, "CORE %d: 0x%p\n", core->id, core);
write_str(&dbg_buf, "===============================\n");
write_str(&dbg_buf, "state: %d\n", core->state);
- write_str(&dbg_buf, "base addr: 0x%x\n", device->base_addr);
- write_str(&dbg_buf, "register_base: 0x%x\n", device->register_base);
- write_str(&dbg_buf, "register_size: %u\n", device->register_size);
- write_str(&dbg_buf, "irq: %u\n", device->irq);
+ write_str(&dbg_buf, "base addr: 0x%x\n",
+ hdev->get_fw_info(hdev->hfi_device_data, FW_BASE_ADDRESS));
+ write_str(&dbg_buf, "register_base: 0x%x\n",
+ hdev->get_fw_info(hdev->hfi_device_data, FW_REGISTER_BASE));
+ write_str(&dbg_buf, "register_size: %u\n",
+ hdev->get_fw_info(hdev->hfi_device_data, FW_REGISTER_SIZE));
+ write_str(&dbg_buf, "irq: %u\n",
+ hdev->get_fw_info(hdev->hfi_device_data, FW_IRQ));
for (i = SYS_MSG_START; i < SYS_MSG_END; i++) {
write_str(&dbg_buf, "completions[%d]: %s\n", i,
completion_done(&core->completions[SYS_MSG_INDEX(i)]) ?
diff --git a/drivers/media/video/msm_vidc/msm_vidc_internal.h b/drivers/media/video/msm_vidc/msm_vidc_internal.h
index 14cef1e..52c1de8 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_internal.h
+++ b/drivers/media/video/msm_vidc/msm_vidc_internal.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
@@ -32,6 +32,7 @@
#include <media/msm_media_info.h>
#include "vidc_hfi_api.h"
+#include "vidc_hfi_api.h"
#define MSM_VIDC_DRV_NAME "msm_vidc_driver"
#define MSM_VIDC_VERSION KERNEL_VERSION(0, 0, 1);
@@ -177,6 +178,7 @@
struct dentry *debugfs_root;
enum vidc_core_state state;
struct completion completions[SYS_MSG_END - SYS_MSG_START + 1];
+ enum msm_vidc_hfi_type hfi_type;
};
struct msm_vidc_inst {
@@ -235,6 +237,4 @@
};
void handle_cmd_response(enum command_response cmd, void *data);
-int msm_vidc_ocmem_notify_handler(struct notifier_block *this,
- unsigned long event, void *data);
#endif
diff --git a/drivers/media/video/msm_vidc/venus_hfi.c b/drivers/media/video/msm_vidc/venus_hfi.c
index 8f0902f..015ed11 100644
--- a/drivers/media/video/msm_vidc/venus_hfi.c
+++ b/drivers/media/video/msm_vidc/venus_hfi.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
@@ -37,8 +37,6 @@
#define SHARED_QSIZE 0x1000000
-struct hal_device_data hal_ctxt;
-
static struct msm_bus_vectors enc_ocmem_init_vectors[] = {
{
.src = MSM_BUS_MASTER_VIDEO_P0_OCMEM,
@@ -840,7 +838,7 @@
return result;
}
-int venus_hfi_iface_msgq_read(struct venus_hfi_device *device, void *pkt)
+static int venus_hfi_iface_msgq_read(struct venus_hfi_device *device, void *pkt)
{
u32 tx_req_is_set = 0;
int rc = 0;
@@ -875,7 +873,7 @@
return rc;
}
-int venus_hfi_iface_dbgq_read(struct venus_hfi_device *device, void *pkt)
+static int venus_hfi_iface_dbgq_read(struct venus_hfi_device *device, void *pkt)
{
u32 tx_req_is_set = 0;
int rc = 0;
@@ -1146,7 +1144,7 @@
return 0;
}
-int venus_hfi_core_init(void *device)
+static int venus_hfi_core_init(void *device)
{
struct hfi_cmd_sys_init_packet pkt;
int rc = 0;
@@ -1214,7 +1212,7 @@
return rc;
}
-int venus_hfi_core_release(void *device)
+static int venus_hfi_core_release(void *device)
{
struct venus_hfi_device *dev;
if (device) {
@@ -1288,7 +1286,7 @@
dprintk(VIDC_DBG, "Cleared WRAPPER/A2H interrupt");
}
-int venus_hfi_core_set_resource(void *device,
+static int venus_hfi_core_set_resource(void *device,
struct vidc_resource_hdr *resource_hdr, void *resource_value)
{
struct hfi_cmd_sys_set_resource_packet *pkt;
@@ -1318,7 +1316,7 @@
return rc;
}
-int venus_hfi_core_release_resource(void *device,
+static int venus_hfi_core_release_resource(void *device,
struct vidc_resource_hdr *resource_hdr)
{
struct hfi_cmd_sys_release_resource_packet pkt;
@@ -1345,7 +1343,7 @@
return rc;
}
-int venus_hfi_core_ping(void *device)
+static int venus_hfi_core_ping(void *device)
{
struct hfi_cmd_sys_ping_packet pkt;
int rc = 0;
@@ -1371,8 +1369,8 @@
return rc;
}
-int venus_hfi_session_set_property(void *sess,
- enum hal_property ptype, void *pdata)
+static int venus_hfi_session_set_property(void *sess,
+ enum hal_property ptype, void *pdata)
{
u8 packet[VIDC_IFACEQ_VAR_LARGE_PKT_SIZE];
struct hfi_cmd_session_set_property_packet *pkt =
@@ -1401,8 +1399,8 @@
return rc;
}
-int venus_hfi_session_get_property(void *sess,
- enum hal_property ptype, void *pdata)
+static int venus_hfi_session_get_property(void *sess,
+ enum hal_property ptype, void *pdata)
{
struct hal_session *session;
@@ -1524,8 +1522,8 @@
return 0;
}
-void *venus_hfi_session_init(void *device, u32 session_id,
- enum hal_domain session_type, enum hal_video_codec codec_type)
+static void *venus_hfi_session_init(void *device, u32 session_id,
+ enum hal_domain session_type, enum hal_video_codec codec_type)
{
struct hfi_cmd_sys_session_init_packet pkt;
struct hal_session *new_session;
@@ -1592,20 +1590,20 @@
return rc;
}
-int venus_hfi_session_end(void *session)
+static int venus_hfi_session_end(void *session)
{
return venus_hfi_send_session_cmd(session,
HFI_CMD_SYS_SESSION_END);
}
-int venus_hfi_session_abort(void *session)
+static int venus_hfi_session_abort(void *session)
{
return venus_hfi_send_session_cmd(session,
HFI_CMD_SYS_SESSION_ABORT);
}
-int venus_hfi_session_set_buffers(void *sess,
- struct vidc_buffer_addr_info *buffer_info)
+static int venus_hfi_session_set_buffers(void *sess,
+ struct vidc_buffer_addr_info *buffer_info)
{
struct hfi_cmd_session_set_buffers_packet *pkt;
u8 packet[VIDC_IFACEQ_VAR_LARGE_PKT_SIZE];
@@ -1638,8 +1636,8 @@
return rc;
}
-int venus_hfi_session_release_buffers(void *sess,
- struct vidc_buffer_addr_info *buffer_info)
+static int venus_hfi_session_release_buffers(void *sess,
+ struct vidc_buffer_addr_info *buffer_info)
{
struct hfi_cmd_session_release_buffer_packet *pkt;
u8 packet[VIDC_IFACEQ_VAR_LARGE_PKT_SIZE];
@@ -1672,43 +1670,44 @@
return rc;
}
-int venus_hfi_session_load_res(void *sess)
+static int venus_hfi_session_load_res(void *sess)
{
return venus_hfi_send_session_cmd(sess,
HFI_CMD_SESSION_LOAD_RESOURCES);
}
-int venus_hfi_session_release_res(void *sess)
+static int venus_hfi_session_release_res(void *sess)
{
return venus_hfi_send_session_cmd(sess,
HFI_CMD_SESSION_RELEASE_RESOURCES);
}
-int venus_hfi_session_start(void *sess)
+static int venus_hfi_session_start(void *sess)
{
return venus_hfi_send_session_cmd(sess,
HFI_CMD_SESSION_START);
}
-int venus_hfi_session_stop(void *sess)
+static int venus_hfi_session_stop(void *sess)
{
return venus_hfi_send_session_cmd(sess,
HFI_CMD_SESSION_STOP);
}
-int venus_hfi_session_suspend(void *sess)
+static int venus_hfi_session_suspend(void *sess)
{
return venus_hfi_send_session_cmd(sess,
HFI_CMD_SESSION_SUSPEND);
}
-int venus_hfi_session_resume(void *sess)
+static int venus_hfi_session_resume(void *sess)
{
return venus_hfi_send_session_cmd(sess,
HFI_CMD_SESSION_RESUME);
}
-int venus_hfi_session_etb(void *sess, struct vidc_frame_data *input_frame)
+static int venus_hfi_session_etb(void *sess,
+ struct vidc_frame_data *input_frame)
{
int rc = 0;
struct hal_session *session;
@@ -1752,8 +1751,8 @@
return rc;
}
-int venus_hfi_session_ftb(void *sess,
- struct vidc_frame_data *output_frame)
+static int venus_hfi_session_ftb(void *sess,
+ struct vidc_frame_data *output_frame)
{
struct hfi_cmd_session_fill_buffer_packet pkt;
int rc = 0;
@@ -1778,8 +1777,8 @@
return rc;
}
-int venus_hfi_session_parse_seq_hdr(void *sess,
- struct vidc_seq_hdr *seq_hdr)
+static int venus_hfi_session_parse_seq_hdr(void *sess,
+ struct vidc_seq_hdr *seq_hdr)
{
struct hfi_cmd_session_parse_sequence_header_packet *pkt;
int rc = 0;
@@ -1809,8 +1808,8 @@
return rc;
}
-int venus_hfi_session_get_seq_hdr(void *sess,
- struct vidc_seq_hdr *seq_hdr)
+static int venus_hfi_session_get_seq_hdr(void *sess,
+ struct vidc_seq_hdr *seq_hdr)
{
struct hfi_cmd_session_get_sequence_header_packet *pkt;
int rc = 0;
@@ -1837,7 +1836,7 @@
return rc;
}
-int venus_hfi_session_get_buf_req(void *sess)
+static int venus_hfi_session_get_buf_req(void *sess)
{
struct hfi_cmd_session_get_property_packet pkt;
int rc = 0;
@@ -1862,7 +1861,7 @@
return rc;
}
-int venus_hfi_session_flush(void *sess, enum hal_flush flush_mode)
+static int venus_hfi_session_flush(void *sess, enum hal_flush flush_mode)
{
struct hfi_cmd_session_flush_packet pkt;
int rc = 0;
@@ -1937,6 +1936,44 @@
return -EINVAL;
}
+static void venus_hfi_process_sys_watchdog_timeout(
+ struct venus_hfi_device *device)
+{
+ struct msm_vidc_cb_cmd_done cmd_done;
+ device->intr_status &= ~VIDC_WRAPPER_INTR_STATUS_A2HWD_BMSK;
+ memset(&cmd_done, 0, sizeof(struct msm_vidc_cb_cmd_done));
+ cmd_done.device_id = device->device_id;
+ device->callback(SYS_WATCHDOG_TIMEOUT, &cmd_done);
+}
+
+static void venus_hfi_response_handler(struct venus_hfi_device *device)
+{
+ u8 packet[VIDC_IFACEQ_MED_PKT_SIZE];
+
+ dprintk(VIDC_INFO, "#####venus_hfi_response_handler#####\n");
+ if (device) {
+ if ((device->intr_status &
+ VIDC_WRAPPER_INTR_CLEAR_A2HWD_BMSK)) {
+ dprintk(VIDC_ERR, "Received: Watchdog timeout %s",
+ __func__);
+ venus_hfi_process_sys_watchdog_timeout(device);
+ }
+
+ while (!venus_hfi_iface_msgq_read(device, packet)) {
+ hfi_process_msg_packet(device->callback,
+ device->device_id,
+ (struct vidc_hal_msg_pkt_hdr *) packet);
+ }
+ while (!venus_hfi_iface_dbgq_read(device, packet)) {
+ struct hfi_msg_sys_debug_packet *pkt =
+ (struct hfi_msg_sys_debug_packet *) packet;
+ dprintk(VIDC_FW, "FW-SAYS: %s", pkt->rg_msg_data);
+ }
+ } else {
+ dprintk(VIDC_ERR, "SPURIOUS_INTERRUPT");
+ }
+}
+
static void venus_hfi_core_work_handler(struct work_struct *work)
{
struct venus_hfi_device *device = list_first_entry(
@@ -1949,7 +1986,7 @@
return;
}
venus_hfi_core_clear_interrupt(device);
- hfi_response_handler(device);
+ venus_hfi_response_handler(device);
enable_irq(device->hal_data->irq);
}
static DECLARE_WORK(venus_hfi_work, venus_hfi_core_work_handler);
@@ -2157,9 +2194,10 @@
return ret;
}
-int venus_hfi_scale_clocks(struct venus_hfi_device *device, int load)
+static int venus_hfi_scale_clocks(void *dev, int load)
{
int rc = 0;
+ struct venus_hfi_device *device = dev;
if (!device) {
dprintk(VIDC_ERR, "Invalid args: %p\n", device);
return -EINVAL;
@@ -2374,11 +2412,18 @@
return i;
}
-int venus_hfi_scale_bus(struct venus_hfi_device *device, int load,
+static int venus_hfi_scale_bus(void *dev, int load,
enum session_type type, enum mem_type mtype)
{
int rc = 0;
u32 handle = 0;
+ struct venus_hfi_device *device = dev;
+
+ if (!device) {
+ dprintk(VIDC_ERR, "%s invalid device handle %p",
+ __func__, device);
+ return -EINVAL;
+ }
if (mtype & DDR_MEM)
handle = device->resources.bus_info.ddr_handle[type];
@@ -2399,24 +2444,10 @@
return rc;
}
-static void venus_hfi_ocmem_init(struct venus_hfi_device *device)
-{
- struct on_chip_mem *ocmem;
-
- ocmem = &device->resources.ocmem;
- ocmem->vidc_ocmem_nb.notifier_call = msm_vidc_ocmem_notify_handler;
- ocmem->handle =
- ocmem_notifier_register(OCMEM_VIDEO, &ocmem->vidc_ocmem_nb);
- if (!ocmem->handle) {
- dprintk(VIDC_WARN, "Failed to register OCMEM notifier.");
- dprintk(VIDC_INFO, " Performance will be impacted\n");
- }
-}
-
-int venus_hfi_set_ocmem(struct venus_hfi_device *device,
- struct ocmem_buf *ocmem)
+static int venus_hfi_set_ocmem(void *dev, struct ocmem_buf *ocmem)
{
struct vidc_resource_hdr rhdr;
+ struct venus_hfi_device *device = dev;
int rc = 0;
if (!device || !ocmem) {
dprintk(VIDC_ERR, "Invalid params, core:%p, ocmem: %p\n",
@@ -2437,12 +2468,14 @@
return rc;
}
-int venus_hfi_unset_ocmem(struct venus_hfi_device *device)
+static int venus_hfi_unset_ocmem(void *dev)
{
struct vidc_resource_hdr rhdr;
+ struct venus_hfi_device *device = dev;
int rc = 0;
if (!device || !device->resources.ocmem.buf) {
- dprintk(VIDC_ERR, "Invalid params, device:%p\n", device);
+ dprintk(VIDC_ERR, "%s Invalid params, device:%p\n",
+ __func__, device);
return -EINVAL;
}
rhdr.resource_id = VIDC_RESOURCE_OCMEM;
@@ -2454,15 +2487,59 @@
return rc;
}
-int venus_hfi_alloc_ocmem(struct venus_hfi_device *device,
- unsigned long size)
+static int venus_hfi_ocmem_notify_handler(struct notifier_block *this,
+ unsigned long event, void *data)
+{
+ struct ocmem_buf *buff = data;
+ struct venus_hfi_device *device;
+ struct venus_resources *resources;
+ struct on_chip_mem *ocmem;
+ int rc = NOTIFY_DONE;
+ if (event == OCMEM_ALLOC_GROW) {
+ ocmem = container_of(this, struct on_chip_mem, vidc_ocmem_nb);
+ if (!ocmem) {
+ dprintk(VIDC_ERR, "Wrong handler passed\n");
+ rc = NOTIFY_BAD;
+ goto err_ocmem_notify;
+ }
+ resources = container_of(ocmem,
+ struct venus_resources, ocmem);
+ device = container_of(resources,
+ struct venus_hfi_device, resources);
+ if (venus_hfi_set_ocmem(device, buff)) {
+ dprintk(VIDC_ERR, "Failed to set ocmem: %d\n", rc);
+ goto err_ocmem_notify;
+ }
+ rc = NOTIFY_OK;
+ }
+
+err_ocmem_notify:
+ return rc;
+}
+
+static void venus_hfi_ocmem_init(struct venus_hfi_device *device)
+{
+ struct on_chip_mem *ocmem;
+
+ ocmem = &device->resources.ocmem;
+ ocmem->vidc_ocmem_nb.notifier_call = venus_hfi_ocmem_notify_handler;
+ ocmem->handle =
+ ocmem_notifier_register(OCMEM_VIDEO, &ocmem->vidc_ocmem_nb);
+ if (!ocmem->handle) {
+ dprintk(VIDC_WARN, "Failed to register OCMEM notifier.");
+ dprintk(VIDC_INFO, " Performance will be impacted\n");
+ }
+}
+
+static int venus_hfi_alloc_ocmem(void *dev, unsigned long size)
{
int rc = 0;
struct ocmem_buf *ocmem_buffer;
+ struct venus_hfi_device *device = dev;
if (!device || !size) {
- dprintk(VIDC_ERR,
- "Invalid param, core: %p, size: %lu\n", device, size);
+ dprintk(VIDC_ERR, "%s Invalid param, core: %p, size: %lu\n",
+ __func__, device, size);
return -EINVAL;
}
ocmem_buffer = device->resources.ocmem.buf;
@@ -2490,21 +2567,35 @@
return rc;
}
-int venus_hfi_free_ocmem(struct venus_hfi_device *device)
+static int venus_hfi_free_ocmem(void *dev)
{
+ struct venus_hfi_device *device = dev;
int rc = 0;
+ if (!device) {
+ dprintk(VIDC_ERR, "%s invalid device handle %p",
+ __func__, device);
+ return -EINVAL;
+ }
+
if (device->resources.ocmem.buf) {
rc = ocmem_free(OCMEM_VIDEO, device->resources.ocmem.buf);
if (rc)
dprintk(VIDC_ERR, "Failed to free ocmem\n");
+ device->resources.ocmem.buf = NULL;
}
- device->resources.ocmem.buf = NULL;
return rc;
}
-int venus_hfi_is_ocmem_present(struct venus_hfi_device *device)
+static int venus_hfi_is_ocmem_present(void *dev)
{
+ struct venus_hfi_device *device = dev;
+ if (!device) {
+ dprintk(VIDC_ERR, "%s invalid device handle %p",
+ __func__, device);
+ return -EINVAL;
+ }
+
return device->resources.ocmem.buf ? 1 : 0;
}
@@ -2515,6 +2606,7 @@
&device->resources.ocmem.vidc_ocmem_nb);
}
+
static int venus_hfi_init_resources(struct venus_hfi_device *device,
struct platform_device *pdev)
{
@@ -2619,9 +2711,9 @@
}
}
-int venus_hfi_get_domain(struct venus_hfi_device *device,
- enum msm_vidc_io_maps iomap)
+static int venus_hfi_get_domain(void *dev, enum msm_vidc_io_maps iomap)
{
+ struct venus_hfi_device *device = dev;
if (!device || iomap < CP_MAP || iomap >= MAX_MAP) {
dprintk(VIDC_ERR, "%s: Invalid parameter: %p iomap: %d\n",
__func__, device, iomap);
@@ -2630,10 +2722,11 @@
return device->resources.io_map[iomap].domain;
}
-int venus_hfi_iommu_get_map(struct venus_hfi_device *device,
+static int venus_hfi_iommu_get_map(void *dev,
struct msm_vidc_iommu_info maps[MAX_MAP])
{
int i = 0;
+ struct venus_hfi_device *device = dev;
if (!device || !maps) {
dprintk(VIDC_ERR, "%s: Invalid param device: %p maps: %p\n",
@@ -2677,12 +2770,14 @@
return rc;
}
-int venus_hfi_load_fw(struct venus_hfi_device *device)
+static int venus_hfi_load_fw(void *dev)
{
int rc = 0;
+ struct venus_hfi_device *device = dev;
if (!device) {
- dprintk(VIDC_ERR, "Invalid paramter: %p\n", device);
+ dprintk(VIDC_ERR, "%s Invalid paramter: %p\n",
+ __func__, device);
return -EINVAL;
}
@@ -2723,10 +2818,12 @@
return rc;
}
-void venus_hfi_unload_fw(struct venus_hfi_device *device)
+static void venus_hfi_unload_fw(void *dev)
{
+ struct venus_hfi_device *device = dev;
if (!device) {
- dprintk(VIDC_ERR, "Invalid paramter: %p\n", device);
+ dprintk(VIDC_ERR, "%s Invalid paramter: %p\n",
+ __func__, device);
return;
}
if (device->resources.fw.cookie) {
@@ -2737,6 +2834,40 @@
}
}
+static int venus_hfi_get_fw_info(void *dev, enum fw_info info)
+{
+ int rc = 0;
+ struct venus_hfi_device *device = dev;
+
+ if (!device) {
+ dprintk(VIDC_ERR, "%s Invalid paramter: %p\n",
+ __func__, device);
+ return -EINVAL;
+ }
+
+ switch (info) {
+ case FW_BASE_ADDRESS:
+ rc = device->base_addr;
+ break;
+
+ case FW_REGISTER_BASE:
+ rc = device->register_base;
+ break;
+
+ case FW_REGISTER_SIZE:
+ rc = device->register_size;
+ break;
+
+ case FW_IRQ:
+ rc = device->irq;
+ break;
+
+ default:
+ dprintk(VIDC_ERR, "Invalid fw info requested");
+ }
+ return rc;
+}
+
static void *venus_hfi_add_device(u32 device_id, struct platform_device *pdev,
void (*callback) (enum command_response cmd, void *data))
{
@@ -2786,9 +2917,9 @@
return NULL;
}
-void *venus_hfi_get_device(u32 device_id,
- struct platform_device *pdev,
- void (*callback) (enum command_response cmd, void *data))
+static void *venus_hfi_get_device(u32 device_id,
+ struct platform_device *pdev,
+ hfi_cmd_response_callback callback)
{
struct venus_hfi_device *device;
int rc = 0;
@@ -2837,3 +2968,60 @@
}
}
+
+static void venus_init_hfi_callbacks(struct hfi_device *hdev)
+{
+ hdev->core_init = venus_hfi_core_init;
+ hdev->core_release = venus_hfi_core_release;
+ hdev->core_pc_prep = venus_hfi_core_pc_prep;
+ hdev->core_ping = venus_hfi_core_ping;
+ hdev->session_init = venus_hfi_session_init;
+ hdev->session_end = venus_hfi_session_end;
+ hdev->session_abort = venus_hfi_session_abort;
+ hdev->session_set_buffers = venus_hfi_session_set_buffers;
+ hdev->session_release_buffers = venus_hfi_session_release_buffers;
+ hdev->session_load_res = venus_hfi_session_load_res;
+ hdev->session_release_res = venus_hfi_session_release_res;
+ hdev->session_start = venus_hfi_session_start;
+ hdev->session_stop = venus_hfi_session_stop;
+ hdev->session_suspend = venus_hfi_session_suspend;
+ hdev->session_resume = venus_hfi_session_resume;
+ hdev->session_etb = venus_hfi_session_etb;
+ hdev->session_ftb = venus_hfi_session_ftb;
+ hdev->session_parse_seq_hdr = venus_hfi_session_parse_seq_hdr;
+ hdev->session_get_seq_hdr = venus_hfi_session_get_seq_hdr;
+ hdev->session_get_buf_req = venus_hfi_session_get_buf_req;
+ hdev->session_flush = venus_hfi_session_flush;
+ hdev->session_set_property = venus_hfi_session_set_property;
+ hdev->session_get_property = venus_hfi_session_get_property;
+ hdev->scale_clocks = venus_hfi_scale_clocks;
+ hdev->scale_bus = venus_hfi_scale_bus;
+ hdev->unset_ocmem = venus_hfi_unset_ocmem;
+ hdev->alloc_ocmem = venus_hfi_alloc_ocmem;
+ hdev->free_ocmem = venus_hfi_free_ocmem;
+ hdev->is_ocmem_present = venus_hfi_is_ocmem_present;
+ hdev->get_domain = venus_hfi_get_domain;
+ hdev->iommu_get_map = venus_hfi_iommu_get_map;
+ hdev->load_fw = venus_hfi_load_fw;
+ hdev->unload_fw = venus_hfi_unload_fw;
+ hdev->get_fw_info = venus_hfi_get_fw_info;
+}
+
+int venus_hfi_initialize(struct hfi_device *hdev, u32 device_id,
+ struct platform_device *pdev, hfi_cmd_response_callback callback)
+{
+ int rc = 0;
+
+ if (!hdev || !callback) {
+ dprintk(VIDC_ERR, "Invalid params: %p %p\n", pdev, callback);
+ rc = -EINVAL;
+ goto err_venus_hfi_init;
+ }
+ hdev->hfi_device_data = venus_hfi_get_device(device_id, pdev, callback);
+
+ venus_init_hfi_callbacks(hdev);
+
+err_venus_hfi_init:
+ return rc;
+}
+
diff --git a/drivers/media/video/msm_vidc/venus_hfi.h b/drivers/media/video/msm_vidc/venus_hfi.h
index 93b9ae3..f825c20 100644
--- a/drivers/media/video/msm_vidc/venus_hfi.h
+++ b/drivers/media/video/msm_vidc/venus_hfi.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
@@ -19,10 +19,12 @@
#include <linux/platform_device.h>
#include <linux/spinlock.h>
#include <mach/ocmem.h>
-#include <media/msm_vidc.h>
+
#include "vidc_hfi_api.h"
#include "msm_smem.h"
#include "vidc_hfi_helper.h"
+#include "vidc_hfi_api.h"
+#include "vidc_hfi.h"
#define HFI_MASK_QHDR_TX_TYPE 0xFF000000
#define HFI_MASK_QHDR_RX_TYPE 0x00FF0000
@@ -106,793 +108,6 @@
VIDC_HWREG_HVI_SOFTINTEN = 0xA,
};
-#define HFI_EVENT_SESSION_SEQUENCE_CHANGED (HFI_OX_BASE + 0x3)
-#define HFI_EVENT_SESSION_PROPERTY_CHANGED (HFI_OX_BASE + 0x4)
-
-#define HFI_EVENT_DATA_SEQUENCE_CHANGED_SUFFICIENT_BUFFER_RESOURCES \
- (HFI_OX_BASE + 0x1)
-#define HFI_EVENT_DATA_SEQUENCE_CHANGED_INSUFFICIENT_BUFFER_RESOURCES \
- (HFI_OX_BASE + 0x2)
-
-#define HFI_BUFFERFLAG_EOS 0x00000001
-#define HFI_BUFFERFLAG_STARTTIME 0x00000002
-#define HFI_BUFFERFLAG_DECODEONLY 0x00000004
-#define HFI_BUFFERFLAG_DATACORRUPT 0x00000008
-#define HFI_BUFFERFLAG_ENDOFFRAME 0x00000010
-#define HFI_BUFFERFLAG_SYNCFRAME 0x00000020
-#define HFI_BUFFERFLAG_EXTRADATA 0x00000040
-#define HFI_BUFFERFLAG_CODECCONFIG 0x00000080
-#define HFI_BUFFERFLAG_TIMESTAMPINVALID 0x00000100
-#define HFI_BUFFERFLAG_READONLY 0x00000200
-#define HFI_BUFFERFLAG_ENDOFSUBFRAME 0x00000400
-#define HFI_BUFFERFLAG_EOSEQ 0x00200000
-#define HFI_BUFFERFLAG_DISCONTINUITY 0x80000000
-#define HFI_BUFFERFLAG_TEI 0x40000000
-
-#define HFI_ERR_SESSION_EMPTY_BUFFER_DONE_OUTPUT_PENDING \
- (HFI_OX_BASE + 0x1001)
-#define HFI_ERR_SESSION_SAME_STATE_OPERATION \
- (HFI_OX_BASE + 0x1002)
-#define HFI_ERR_SESSION_SYNC_FRAME_NOT_DETECTED \
- (HFI_OX_BASE + 0x1003)
-#define HFI_ERR_SESSION_START_CODE_NOT_FOUND \
- (HFI_OX_BASE + 0x1004)
-
-#define HFI_BUFFER_INTERNAL_SCRATCH (HFI_OX_BASE + 0x1)
-#define HFI_BUFFER_EXTRADATA_INPUT (HFI_OX_BASE + 0x2)
-#define HFI_BUFFER_EXTRADATA_OUTPUT (HFI_OX_BASE + 0x3)
-#define HFI_BUFFER_EXTRADATA_OUTPUT2 (HFI_OX_BASE + 0x4)
-
-#define HFI_BUFFER_MODE_STATIC (HFI_OX_BASE + 0x1)
-#define HFI_BUFFER_MODE_RING (HFI_OX_BASE + 0x2)
-
-struct hfi_buffer_alloc_mode {
- u32 buffer_type;
- u32 buffer_mode;
-};
-
-#define HFI_FLUSH_INPUT (HFI_OX_BASE + 0x1)
-#define HFI_FLUSH_OUTPUT (HFI_OX_BASE + 0x2)
-#define HFI_FLUSH_OUTPUT2 (HFI_OX_BASE + 0x3)
-#define HFI_FLUSH_ALL (HFI_OX_BASE + 0x4)
-
-#define HFI_EXTRADATA_NONE 0x00000000
-#define HFI_EXTRADATA_MB_QUANTIZATION 0x00000001
-#define HFI_EXTRADATA_INTERLACE_VIDEO 0x00000002
-#define HFI_EXTRADATA_VC1_FRAMEDISP 0x00000003
-#define HFI_EXTRADATA_VC1_SEQDISP 0x00000004
-#define HFI_EXTRADATA_TIMESTAMP 0x00000005
-#define HFI_EXTRADATA_S3D_FRAME_PACKING 0x00000006
-#define HFI_EXTRADATA_FRAME_RATE 0x00000007
-#define HFI_EXTRADATA_PANSCAN_WINDOW 0x00000008
-#define HFI_EXTRADATA_RECOVERY_POINT_SEI 0x00000009
-#define HFI_EXTRADATA_CLOSED_CAPTION_UD 0x0000000A
-#define HFI_EXTRADATA_AFD_UD 0x0000000B
-#define HFI_EXTRADATA_MULTISLICE_INFO 0x7F100000
-#define HFI_EXTRADATA_NUM_CONCEALED_MB 0x7F100001
-#define HFI_EXTRADATA_INDEX 0x7F100002
-#define HFI_EXTRADATA_METADATA_FILLER 0x7FE00002
-
-#define HFI_INDEX_EXTRADATA_INPUT_CROP 0x0700000E
-#define HFI_INDEX_EXTRADATA_DIGITAL_ZOOM 0x07000010
-#define HFI_INDEX_EXTRADATA_ASPECT_RATIO 0x7F100003
-
-struct hfi_index_extradata_config {
- int enable;
- u32 index_extra_data_id;
-};
-
-struct hfi_extradata_header {
- u32 size;
- u32 version;
- u32 port_index;
- u32 type;
- u32 data_size;
- u8 rg_data[1];
-};
-
-#define HFI_INTERLACE_FRAME_PROGRESSIVE 0x01
-#define HFI_INTERLACE_INTERLEAVE_FRAME_TOPFIELDFIRST 0x02
-#define HFI_INTERLACE_INTERLEAVE_FRAME_BOTTOMFIELDFIRST 0x04
-#define HFI_INTERLACE_FRAME_TOPFIELDFIRST 0x08
-#define HFI_INTERLACE_FRAME_BOTTOMFIELDFIRST 0x10
-
-#define HFI_PROPERTY_SYS_OX_START \
- (HFI_DOMAIN_BASE_COMMON + HFI_ARCH_OX_OFFSET + 0x0000)
-#define HFI_PROPERTY_SYS_IDLE_INDICATOR \
- (HFI_PROPERTY_SYS_OX_START + 0x001)
-
-#define HFI_PROPERTY_PARAM_OX_START \
- (HFI_DOMAIN_BASE_COMMON + HFI_ARCH_OX_OFFSET + 0x1000)
-#define HFI_PROPERTY_PARAM_BUFFER_COUNT_ACTUAL \
- (HFI_PROPERTY_PARAM_OX_START + 0x001)
-#define HFI_PROPERTY_PARAM_UNCOMPRESSED_PLANE_ACTUAL_CONSTRAINTS_INFO \
- (HFI_PROPERTY_PARAM_OX_START + 0x002)
-#define HFI_PROPERTY_PARAM_INTERLACE_FORMAT_SUPPORTED \
- (HFI_PROPERTY_PARAM_OX_START + 0x003)
-#define HFI_PROPERTY_PARAM_CHROMA_SITE \
-(HFI_PROPERTY_PARAM_OX_START + 0x004)
-#define HFI_PROPERTY_PARAM_EXTRA_DATA_HEADER_CONFIG \
- (HFI_PROPERTY_PARAM_OX_START + 0x005)
-#define HFI_PROPERTY_PARAM_INDEX_EXTRADATA \
- (HFI_PROPERTY_PARAM_OX_START + 0x006)
-#define HFI_PROPERTY_PARAM_DIVX_FORMAT \
- (HFI_PROPERTY_PARAM_OX_START + 0x007)
-#define HFI_PROPERTY_PARAM_BUFFER_ALLOC_MODE \
- (HFI_PROPERTY_PARAM_OX_START + 0x008)
-#define HFI_PROPERTY_PARAM_S3D_FRAME_PACKING_EXTRADATA \
- (HFI_PROPERTY_PARAM_OX_START + 0x009)
-
-#define HFI_PROPERTY_CONFIG_OX_START \
- (HFI_DOMAIN_BASE_COMMON + HFI_ARCH_OX_OFFSET + 0x02000)
-#define HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS \
- (HFI_PROPERTY_CONFIG_OX_START + 0x001)
-#define HFI_PROPERTY_CONFIG_REALTIME \
- (HFI_PROPERTY_CONFIG_OX_START + 0x002)
-#define HFI_PROPERTY_CONFIG_PRIORITY \
- (HFI_PROPERTY_CONFIG_OX_START + 0x003)
-#define HFI_PROPERTY_CONFIG_BATCH_INFO \
- (HFI_PROPERTY_CONFIG_OX_START + 0x004)
-
-#define HFI_PROPERTY_PARAM_VDEC_OX_START \
- (HFI_DOMAIN_BASE_VDEC + HFI_ARCH_OX_OFFSET + 0x3000)
-#define HFI_PROPERTY_PARAM_VDEC_CONTINUE_DATA_TRANSFER \
- (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x001)
-#define HFI_PROPERTY_PARAM_VDEC_DISPLAY_PICTURE_BUFFER_COUNT\
- (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x002)
-#define HFI_PROPERTY_PARAM_VDEC_MULTI_VIEW_SELECT \
- (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x003)
-#define HFI_PROPERTY_PARAM_VDEC_PICTURE_TYPE_DECODE \
- (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x004)
-#define HFI_PROPERTY_PARAM_VDEC_OUTPUT_ORDER \
- (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x005)
-#define HFI_PROPERTY_PARAM_VDEC_MB_QUANTIZATION \
- (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x006)
-#define HFI_PROPERTY_PARAM_VDEC_NUM_CONCEALED_MB \
- (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x007)
-#define HFI_PROPERTY_PARAM_VDEC_H264_ENTROPY_SWITCHING \
- (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x008)
-#define HFI_PROPERTY_PARAM_VDEC_OUTPUT2_KEEP_ASPECT_RATIO\
- (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x009)
-#define HFI_PROPERTY_PARAM_VDEC_FRAME_RATE_EXTRADATA \
- (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x00A)
-#define HFI_PROPERTY_PARAM_VDEC_PANSCAN_WNDW_EXTRADATA \
- (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x00B)
-#define HFI_PROPERTY_PARAM_VDEC_RECOVERY_POINT_SEI_EXTRADATA \
- (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x00C)
-#define HFI_PROPERTY_PARAM_VDEC_THUMBNAIL_MODE \
- (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x00D)
-
-#define HFI_PROPERTY_PARAM_VDEC_FRAME_ASSEMBLY \
- (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x00E)
-#define HFI_PROPERTY_PARAM_VDEC_CLOSED_CAPTION_EXTRADATA \
- (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x00F)
-#define HFI_PROPERTY_PARAM_VDEC_AFD_EXTRADATA \
- (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x010)
-#define HFI_PROPERTY_PARAM_VDEC_VC1_FRAMEDISP_EXTRADATA \
- (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x011)
-#define HFI_PROPERTY_PARAM_VDEC_VC1_SEQDISP_EXTRADATA \
- (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x012)
-#define HFI_PROPERTY_PARAM_VDEC_TIMESTAMP_EXTRADATA \
- (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x013)
-#define HFI_PROPERTY_PARAM_VDEC_INTERLACE_VIDEO_EXTRADATA \
- (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x014)
-#define HFI_PROPERTY_PARAM_VDEC_AVC_SESSION_SELECT \
- (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x015)
-
-#define HFI_PROPERTY_CONFIG_VDEC_OX_START \
- (HFI_DOMAIN_BASE_VDEC + HFI_ARCH_OX_OFFSET + 0x0000)
-#define HFI_PROPERTY_CONFIG_VDEC_POST_LOOP_DEBLOCKER \
- (HFI_PROPERTY_CONFIG_VDEC_OX_START + 0x001)
-#define HFI_PROPERTY_CONFIG_VDEC_MB_ERROR_MAP_REPORTING \
- (HFI_PROPERTY_CONFIG_VDEC_OX_START + 0x002)
-#define HFI_PROPERTY_CONFIG_VDEC_MB_ERROR_MAP \
- (HFI_PROPERTY_CONFIG_VDEC_OX_START + 0x003)
-
-#define HFI_PROPERTY_PARAM_VENC_OX_START \
- (HFI_DOMAIN_BASE_VENC + HFI_ARCH_OX_OFFSET + 0x5000)
-#define HFI_PROPERTY_PARAM_VENC_MULTI_SLICE_INFO \
- (HFI_PROPERTY_PARAM_VENC_OX_START + 0x001)
-#define HFI_PROPERTY_PARAM_VENC_H264_IDR_S3D_FRAME_PACKING_NAL \
- (HFI_PROPERTY_PARAM_VENC_OX_START + 0x002)
-
-#define HFI_PROPERTY_CONFIG_VENC_OX_START \
- (HFI_DOMAIN_BASE_VENC + HFI_ARCH_OX_OFFSET + 0x6000)
-#define HFI_PROPERTY_CONFIG_VENC_FRAME_QP \
- (HFI_PROPERTY_CONFIG_VENC_OX_START + 0x001)
-
-#define HFI_PROPERTY_PARAM_VPE_OX_START \
- (HFI_DOMAIN_BASE_VPE + HFI_ARCH_OX_OFFSET + 0x7000)
-#define HFI_PROPERTY_CONFIG_VPE_OX_START \
- (HFI_DOMAIN_BASE_VPE + HFI_ARCH_OX_OFFSET + 0x8000)
-
-struct hfi_batch_info {
- u32 input_batch_count;
- u32 output_batch_count;
-};
-
-struct hfi_buffer_count_actual {
- u32 buffer_type;
- u32 buffer_count_actual;
-};
-
-struct hfi_buffer_requirements {
- u32 buffer_type;
- u32 buffer_size;
- u32 buffer_region_size;
- u32 buffer_hold_count;
- u32 buffer_count_min;
- u32 buffer_count_actual;
- u32 contiguous;
- u32 buffer_alignment;
-};
-
-#define HFI_CHROMA_SITE_0 (HFI_OX_BASE + 0x1)
-#define HFI_CHROMA_SITE_1 (HFI_OX_BASE + 0x2)
-#define HFI_CHROMA_SITE_2 (HFI_OX_BASE + 0x3)
-#define HFI_CHROMA_SITE_3 (HFI_OX_BASE + 0x4)
-#define HFI_CHROMA_SITE_4 (HFI_OX_BASE + 0x5)
-#define HFI_CHROMA_SITE_5 (HFI_OX_BASE + 0x6)
-
-struct hfi_data_payload {
- u32 size;
- u8 rg_data[1];
-};
-
-struct hfi_enable_picture {
- u32 picture_type;
-};
-
-struct hfi_display_picture_buffer_count {
- int enable;
- u32 count;
-};
-
-struct hfi_extra_data_header_config {
- u32 type;
- u32 buffer_type;
- u32 version;
- u32 port_index;
- u32 client_extra_data_id;
-};
-
-struct hfi_interlace_format_supported {
- u32 buffer_type;
- u32 format;
-};
-
-struct hfi_mb_error_map {
- u32 error_map_size;
- u8 rg_error_map[1];
-};
-
-struct hfi_metadata_pass_through {
- int enable;
- u32 size;
-};
-
-struct hfi_multi_view_select {
- u32 view_index;
-};
-
-#define HFI_PRIORITY_LOW 10
-#define HFI_PRIOIRTY_MEDIUM 20
-#define HFI_PRIORITY_HIGH 30
-
-#define HFI_OUTPUT_ORDER_DISPLAY (HFI_OX_BASE + 0x1)
-#define HFI_OUTPUT_ORDER_DECODE (HFI_OX_BASE + 0x2)
-
-#define HFI_RATE_CONTROL_OFF (HFI_OX_BASE + 0x1)
-#define HFI_RATE_CONTROL_VBR_VFR (HFI_OX_BASE + 0x2)
-#define HFI_RATE_CONTROL_VBR_CFR (HFI_OX_BASE + 0x3)
-#define HFI_RATE_CONTROL_CBR_VFR (HFI_OX_BASE + 0x4)
-#define HFI_RATE_CONTROL_CBR_CFR (HFI_OX_BASE + 0x5)
-
-struct hfi_uncompressed_plane_actual_constraints_info {
- u32 buffer_type;
- u32 num_planes;
- struct hfi_uncompressed_plane_constraints rg_plane_format[1];
-};
-
-#define HFI_CMD_SYS_OX_START \
-(HFI_DOMAIN_BASE_COMMON + HFI_ARCH_OX_OFFSET + HFI_CMD_START_OFFSET + 0x0000)
-#define HFI_CMD_SYS_SESSION_ABORT (HFI_CMD_SYS_OX_START + 0x001)
-#define HFI_CMD_SYS_PING (HFI_CMD_SYS_OX_START + 0x002)
-
-#define HFI_CMD_SESSION_OX_START \
-(HFI_DOMAIN_BASE_COMMON + HFI_ARCH_OX_OFFSET + HFI_CMD_START_OFFSET + 0x1000)
-#define HFI_CMD_SESSION_LOAD_RESOURCES (HFI_CMD_SESSION_OX_START + 0x001)
-#define HFI_CMD_SESSION_START (HFI_CMD_SESSION_OX_START + 0x002)
-#define HFI_CMD_SESSION_STOP (HFI_CMD_SESSION_OX_START + 0x003)
-#define HFI_CMD_SESSION_EMPTY_BUFFER (HFI_CMD_SESSION_OX_START + 0x004)
-#define HFI_CMD_SESSION_FILL_BUFFER (HFI_CMD_SESSION_OX_START + 0x005)
-#define HFI_CMD_SESSION_SUSPEND (HFI_CMD_SESSION_OX_START + 0x006)
-#define HFI_CMD_SESSION_RESUME (HFI_CMD_SESSION_OX_START + 0x007)
-#define HFI_CMD_SESSION_FLUSH (HFI_CMD_SESSION_OX_START + 0x008)
-#define HFI_CMD_SESSION_GET_PROPERTY (HFI_CMD_SESSION_OX_START + 0x009)
-#define HFI_CMD_SESSION_PARSE_SEQUENCE_HEADER \
- (HFI_CMD_SESSION_OX_START + 0x00A)
-#define HFI_CMD_SESSION_RELEASE_BUFFERS \
- (HFI_CMD_SESSION_OX_START + 0x00B)
-#define HFI_CMD_SESSION_RELEASE_RESOURCES \
- (HFI_CMD_SESSION_OX_START + 0x00C)
-
-#define HFI_MSG_SYS_OX_START \
-(HFI_DOMAIN_BASE_COMMON + HFI_ARCH_OX_OFFSET + HFI_MSG_START_OFFSET + 0x0000)
-#define HFI_MSG_SYS_IDLE (HFI_MSG_SYS_OX_START + 0x1)
-#define HFI_MSG_SYS_PING_ACK (HFI_MSG_SYS_OX_START + 0x2)
-#define HFI_MSG_SYS_PROPERTY_INFO (HFI_MSG_SYS_OX_START + 0x3)
-#define HFI_MSG_SYS_SESSION_ABORT_DONE (HFI_MSG_SYS_OX_START + 0x4)
-
-#define HFI_MSG_SESSION_OX_START \
-(HFI_DOMAIN_BASE_COMMON + HFI_ARCH_OX_OFFSET + HFI_MSG_START_OFFSET + 0x1000)
-#define HFI_MSG_SESSION_LOAD_RESOURCES_DONE (HFI_MSG_SESSION_OX_START + 0x1)
-#define HFI_MSG_SESSION_START_DONE (HFI_MSG_SESSION_OX_START + 0x2)
-#define HFI_MSG_SESSION_STOP_DONE (HFI_MSG_SESSION_OX_START + 0x3)
-#define HFI_MSG_SESSION_SUSPEND_DONE (HFI_MSG_SESSION_OX_START + 0x4)
-#define HFI_MSG_SESSION_RESUME_DONE (HFI_MSG_SESSION_OX_START + 0x5)
-#define HFI_MSG_SESSION_FLUSH_DONE (HFI_MSG_SESSION_OX_START + 0x6)
-#define HFI_MSG_SESSION_EMPTY_BUFFER_DONE (HFI_MSG_SESSION_OX_START + 0x7)
-#define HFI_MSG_SESSION_FILL_BUFFER_DONE (HFI_MSG_SESSION_OX_START + 0x8)
-#define HFI_MSG_SESSION_PROPERTY_INFO (HFI_MSG_SESSION_OX_START + 0x9)
-#define HFI_MSG_SESSION_RELEASE_RESOURCES_DONE \
- (HFI_MSG_SESSION_OX_START + 0xA)
-#define HFI_MSG_SESSION_PARSE_SEQUENCE_HEADER_DONE \
- (HFI_MSG_SESSION_OX_START + 0xB)
-#define HFI_MSG_SESSION_RELEASE_BUFFERS_DONE \
- (HFI_MSG_SESSION_OX_START + 0xC)
-
-struct hfi_cmd_sys_session_abort_packet {
- u32 size;
- u32 packet_type;
- u32 session_id;
-};
-
-struct hfi_cmd_sys_ping_packet {
- u32 size;
- u32 packet_type;
- u32 client_data;
-};
-
-struct hfi_cmd_session_load_resources_packet {
- u32 size;
- u32 packet_type;
- u32 session_id;
-};
-
-struct hfi_cmd_session_start_packet {
- u32 size;
- u32 packet_type;
- u32 session_id;
-};
-
-struct hfi_cmd_session_stop_packet {
- u32 size;
- u32 packet_type;
- u32 session_id;
-};
-
-struct hfi_cmd_session_empty_buffer_compressed_packet {
- u32 size;
- u32 packet_type;
- u32 session_id;
- u32 time_stamp_hi;
- u32 time_stamp_lo;
- u32 flags;
- u32 mark_target;
- u32 mark_data;
- u32 offset;
- u32 alloc_len;
- u32 filled_len;
- u32 input_tag;
- u8 *packet_buffer;
- u8 *extra_data_buffer;
- u32 rgData[0];
-};
-
-struct hfi_cmd_session_empty_buffer_uncompressed_plane0_packet {
- u32 size;
- u32 packet_type;
- u32 session_id;
- u32 view_id;
- u32 time_stamp_hi;
- u32 time_stamp_lo;
- u32 flags;
- u32 mark_target;
- u32 mark_data;
- u32 alloc_len;
- u32 filled_len;
- u32 offset;
- u32 input_tag;
- u8 *packet_buffer;
- u8 *extra_data_buffer;
- u32 rgData[0];
-};
-
-struct hfi_cmd_session_empty_buffer_uncompressed_plane1_packet {
- u32 flags;
- u32 alloc_len;
- u32 filled_len;
- u32 offset;
- u8 *packet_buffer2;
- u32 rgData[0];
-};
-
-struct hfi_cmd_session_empty_buffer_uncompressed_plane2_packet {
- u32 flags;
- u32 alloc_len;
- u32 filled_len;
- u32 offset;
- u8 *packet_buffer3;
- u32 rgData[0];
-};
-
-struct hfi_cmd_session_fill_buffer_packet {
- u32 size;
- u32 packet_type;
- u32 session_id;
- u32 stream_id;
- u32 offset;
- u32 alloc_len;
- u32 filled_len;
- u32 output_tag;
- u8 *packet_buffer;
- u8 *extra_data_buffer;
- u32 rgData[0];
-};
-
-struct hfi_cmd_session_flush_packet {
- u32 size;
- u32 packet_type;
- u32 session_id;
- u32 flush_type;
-};
-
-struct hfi_cmd_session_suspend_packet {
- u32 size;
- u32 packet_type;
- u32 session_id;
-};
-
-struct hfi_cmd_session_resume_packet {
- u32 size;
- u32 packet_type;
- u32 session_id;
-};
-
-struct hfi_cmd_session_get_property_packet {
- u32 size;
- u32 packet_type;
- u32 session_id;
- u32 num_properties;
- u32 rg_property_data[1];
-};
-
-struct hfi_cmd_session_release_buffer_packet {
- u32 size;
- u32 packet_type;
- u32 session_id;
- u32 buffer_type;
- u32 buffer_size;
- u32 extra_data_size;
- int response_req;
- u32 num_buffers;
- u32 rg_buffer_info[1];
-};
-
-struct hfi_cmd_session_release_resources_packet {
- u32 size;
- u32 packet_type;
- u32 session_id;
-};
-
-struct hfi_cmd_session_parse_sequence_header_packet {
- u32 size;
- u32 packet_type;
- u32 session_id;
- u32 header_len;
- u8 *packet_buffer;
-};
-
-struct hfi_msg_sys_session_abort_done_packet {
- u32 size;
- u32 packet_type;
- u32 session_id;
- u32 error_type;
-};
-
-struct hfi_msg_sys_idle_packet {
- u32 size;
- u32 packet_type;
-};
-
-struct hfi_msg_sys_ping_ack_packet {
- u32 size;
- u32 packet_type;
- u32 client_data;
-};
-
-struct hfi_msg_sys_property_info_packet {
- u32 size;
- u32 packet_type;
- u32 num_properties;
- u32 rg_property_data[1];
-};
-
-struct hfi_msg_session_load_resources_done_packet {
- u32 size;
- u32 packet_type;
- u32 session_id;
- u32 error_type;
-};
-
-struct hfi_msg_session_start_done_packet {
- u32 size;
- u32 packet_type;
- u32 session_id;
- u32 error_type;
-};
-
-struct hfi_msg_session_stop_done_packet {
- u32 size;
- u32 packet_type;
- u32 session_id;
- u32 error_type;
-};
-
-struct hfi_msg_session_suspend_done_packet {
- u32 size;
- u32 packet_type;
- u32 session_id;
- u32 error_type;
-};
-
-struct hfi_msg_session_resume_done_packet {
- u32 size;
- u32 packet_type;
- u32 session_id;
- u32 error_type;
-};
-
-struct hfi_msg_session_flush_done_packet {
- u32 size;
- u32 packet_type;
- u32 session_id;
- u32 error_type;
- u32 flush_type;
-};
-
-struct hfi_msg_session_empty_buffer_done_packet {
- u32 size;
- u32 packet_type;
- u32 session_id;
- u32 error_type;
- u32 offset;
- u32 filled_len;
- u32 input_tag;
- u8 *packet_buffer;
- u8 *extra_data_buffer;
- u32 rgData[0];
-};
-
-struct hfi_msg_session_fill_buffer_done_compressed_packet {
- u32 size;
- u32 packet_type;
- u32 session_id;
- u32 time_stamp_hi;
- u32 time_stamp_lo;
- u32 error_type;
- u32 flags;
- u32 mark_target;
- u32 mark_data;
- u32 stats;
- u32 offset;
- u32 alloc_len;
- u32 filled_len;
- u32 input_tag;
- u32 output_tag;
- u32 picture_type;
- u8 *packet_buffer;
- u8 *extra_data_buffer;
- u32 rgData[0];
-};
-
-struct hfi_msg_session_fbd_uncompressed_plane0_packet {
- u32 size;
- u32 packet_type;
- u32 session_id;
- u32 stream_id;
- u32 view_id;
- u32 error_type;
- u32 time_stamp_hi;
- u32 time_stamp_lo;
- u32 flags;
- u32 mark_target;
- u32 mark_data;
- u32 stats;
- u32 alloc_len;
- u32 filled_len;
- u32 offset;
- u32 frame_width;
- u32 frame_height;
- u32 start_x_coord;
- u32 start_y_coord;
- u32 input_tag;
- u32 input_tag2;
- u32 output_tag;
- u32 picture_type;
- u8 *packet_buffer;
- u8 *extra_data_buffer;
- u32 rgData[0];
-};
-
-struct hfi_msg_session_fill_buffer_done_uncompressed_plane1_packet {
- u32 flags;
- u32 alloc_len;
- u32 filled_len;
- u32 offset;
- u8 *packet_buffer2;
- u32 rgData[0];
-};
-
-struct hfi_msg_session_fill_buffer_done_uncompressed_plane2_packet {
- u32 flags;
- u32 alloc_len;
- u32 filled_len;
- u32 offset;
- u8 *packet_buffer3;
- u32 rgData[0];
-};
-
-struct hfi_msg_session_parse_sequence_header_done_packet {
- u32 size;
- u32 packet_type;
- u32 session_id;
- u32 error_type;
- u32 num_properties;
- u32 rg_property_data[1];
-};
-
-struct hfi_msg_session_property_info_packet {
- u32 size;
- u32 packet_type;
- u32 session_id;
- u32 num_properties;
- u32 rg_property_data[1];
-};
-
-struct hfi_msg_session_release_resources_done_packet {
- u32 size;
- u32 packet_type;
- u32 session_id;
- u32 error_type;
-};
-
-struct hfi_msg_session_release_buffers_done_packet {
- u32 size;
- u32 packet_type;
- u32 session_id;
- u32 error_type;
- u32 num_buffers;
- u32 rg_buffer_info[1];
-};
-
-struct hfi_extradata_mb_quantization_payload {
- u8 rg_mb_qp[1];
-};
-
-struct hfi_extradata_vc1_pswnd {
- u32 ps_wnd_h_offset;
- u32 ps_wnd_v_offset;
- u32 ps_wnd_width;
- u32 ps_wnd_height;
-};
-
-struct hfi_extradata_vc1_framedisp_payload {
- u32 res_pic;
- u32 ref;
- u32 range_map_present;
- u32 range_map_y;
- u32 range_map_uv;
- u32 num_pan_scan_wnds;
- struct hfi_extradata_vc1_pswnd rg_ps_wnd[1];
-};
-
-struct hfi_extradata_vc1_seqdisp_payload {
- u32 prog_seg_frm;
- u32 uv_sampling_fmt;
- u32 color_fmt_flag;
- u32 color_primaries;
- u32 transfer_char;
- u32 mat_coeff;
- u32 aspect_ratio;
- u32 aspect_horiz;
- u32 aspect_vert;
-};
-
-struct hfi_extradata_timestamp_payload {
- u32 time_stamp_low;
- u32 time_stamp_high;
-};
-
-
-struct hfi_extradata_s3d_frame_packing_payload {
- u32 fpa_id;
- int cancel_flag;
- u32 fpa_type;
- int quin_cunx_flag;
- u32 content_interprtation_type;
- int spatial_flipping_flag;
- int frame0_flipped_flag;
- int field_views_flag;
- int current_frame_isFrame0_flag;
- int frame0_self_contained_flag;
- int frame1_self_contained_flag;
- u32 frame0_graid_pos_x;
- u32 frame0_graid_pos_y;
- u32 frame1_graid_pos_x;
- u32 frame1_graid_pos_y;
- u32 fpa_reserved_byte;
- u32 fpa_repetition_period;
- int fpa_extension_flag;
-};
-
-struct hfi_extradata_interlace_video_payload {
- u32 format;
-};
-
-struct hfi_extradata_num_concealed_mb_payload {
- u32 num_mb_concealed;
-};
-
-struct hfi_extradata_sliceinfo {
- u32 offset_in_stream;
- u32 slice_length;
-};
-
-struct hfi_extradata_multislice_info_payload {
- u32 num_slices;
- struct hfi_extradata_sliceinfo rg_slice_info[1];
-};
-
-struct hfi_index_extradata_input_crop_payload {
- u32 size;
- u32 version;
- u32 port_index;
- u32 left;
- u32 top;
- u32 width;
- u32 height;
-};
-
-struct hfi_index_extradata_digital_zoom_payload {
- u32 size;
- u32 version;
- u32 port_index;
- int width;
- int height;
-};
-
-struct hfi_index_extradata_aspect_ratio_payload {
- u32 size;
- u32 version;
- u32 port_index;
- u32 aspect_width;
- u32 aspect_height;
-};
-struct hfi_extradata_panscan_wndw_payload {
- u32 num_window;
- struct hfi_extradata_vc1_pswnd wnd[1];
-};
-
-struct hfi_extradata_frame_type_payload {
- u32 frame_rate;
-};
-
-struct hfi_extradata_recovery_point_sei_payload {
- u32 flag;
-};
-
struct vidc_mem_addr {
u8 *align_device_addr;
u8 *align_virtual_addr;
@@ -921,11 +136,6 @@
VCODEC_MAX_CLKS
};
-enum mem_type {
- DDR_MEM = 0x1,
- OCMEM_MEM = 0x2,
-};
-
struct load_freq_table {
u32 load;
u32 freq;
@@ -968,7 +178,7 @@
u32 device_id;
spinlock_t read_lock;
spinlock_t write_lock;
- void (*callback) (u32 response, void *callback);
+ msm_vidc_callback callback;
struct vidc_mem_addr iface_q_table;
struct vidc_mem_addr qdss;
struct vidc_mem_addr sfr;
@@ -986,49 +196,7 @@
struct venus_resources resources;
};
-struct hal_session {
- struct list_head list;
- u32 session_id;
- u32 is_decoder;
- struct venus_hfi_device *device;
-};
-
-struct hal_device_data {
- struct list_head dev_head;
- int dev_count;
-};
-
-extern struct hal_device_data hal_ctxt;
-
-int venus_hfi_iface_msgq_read(struct venus_hfi_device *device, void *pkt);
-int venus_hfi_iface_dbgq_read(struct venus_hfi_device *device, void *pkt);
-
-/* Interrupt Processing:*/
-void hfi_response_handler(struct venus_hfi_device *device);
-
void venus_hfi_delete_device(void *device);
-
-int venus_hfi_scale_clocks(struct venus_hfi_device *device, int load);
-
-void *venus_hfi_get_device(u32 device_id,
- struct platform_device *pdev,
- void (*callback) (enum command_response cmd, void *data));
-
-int venus_hfi_scale_bus(struct venus_hfi_device *device, int load,
- enum session_type type, enum mem_type mtype);
-int venus_hfi_set_ocmem(struct venus_hfi_device *device,
- struct ocmem_buf *ocmem);
-int venus_hfi_unset_ocmem(struct venus_hfi_device *device);
-int venus_hfi_alloc_ocmem(struct venus_hfi_device *device,
- unsigned long size);
-int venus_hfi_free_ocmem(struct venus_hfi_device *device);
-int venus_hfi_is_ocmem_present(struct venus_hfi_device *device);
-
-int venus_hfi_get_domain(struct venus_hfi_device *device,
- enum msm_vidc_io_maps iomap);
-int venus_hfi_iommu_get_map(struct venus_hfi_device *device,
- struct msm_vidc_iommu_info maps[MAX_MAP]);
-int venus_hfi_load_fw(struct venus_hfi_device *device);
-void venus_hfi_unload_fw(struct venus_hfi_device *device);
-
+int venus_hfi_initialize(struct hfi_device *hdev, u32 device_id,
+ struct platform_device *pdev, hfi_cmd_response_callback callback);
#endif
diff --git a/drivers/media/video/msm_vidc/vidc_hfi.c b/drivers/media/video/msm_vidc/vidc_hfi.c
new file mode 100644
index 0000000..f09d3d5
--- /dev/null
+++ b/drivers/media/video/msm_vidc/vidc_hfi.c
@@ -0,0 +1,68 @@
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/slab.h>
+#include "msm_vidc_debug.h"
+#include "vidc_hfi_api.h"
+#include "venus_hfi.h"
+
+struct hal_device_data hal_ctxt;
+
+void *vidc_hfi_initialize(enum msm_vidc_hfi_type hfi_type, u32 device_id,
+ struct platform_device *pdev,
+ hfi_cmd_response_callback callback)
+{
+ struct hfi_device *hdev = NULL;
+ hdev = (struct hfi_device *)
+ kzalloc(sizeof(struct hfi_device), GFP_KERNEL);
+ if (!hdev) {
+ dprintk(VIDC_ERR, "%s: failed to allocate hdev\n", __func__);
+ return NULL;
+ }
+
+ switch (hfi_type) {
+ case VIDC_HFI_VENUS:
+ venus_hfi_initialize(hdev, device_id, pdev, callback);
+ break;
+
+ case VIDC_HFI_Q6:
+ default:
+ dprintk(VIDC_ERR, "Unsupported host-firmware interface\n");
+ goto err_hfi_init;
+ }
+ return hdev;
+
+err_hfi_init:
+ kfree(hdev);
+ return NULL;
+}
+
+void vidc_hfi_deinitialize(enum msm_vidc_hfi_type hfi_type,
+ struct hfi_device *hdev)
+{
+ if (!hdev) {
+ dprintk(VIDC_ERR, "%s invalid device %p", __func__, hdev);
+ return;
+ }
+
+ switch (hfi_type) {
+ case VIDC_HFI_VENUS:
+ venus_hfi_delete_device(hdev->hfi_device_data);
+ break;
+
+ case VIDC_HFI_Q6:
+ default:
+ dprintk(VIDC_ERR, "Unsupported host-firmware interface\n");
+ }
+ kfree(hdev);
+}
+
diff --git a/drivers/media/video/msm_vidc/vidc_hfi.h b/drivers/media/video/msm_vidc/vidc_hfi.h
new file mode 100644
index 0000000..6ff0921
--- /dev/null
+++ b/drivers/media/video/msm_vidc/vidc_hfi.h
@@ -0,0 +1,826 @@
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef __H_VIDC_HFI_H__
+#define __H_VIDC_HFI_H__
+
+#include "vidc_hfi_helper.h"
+#include "vidc_hfi_api.h"
+
+#define HFI_EVENT_SESSION_SEQUENCE_CHANGED (HFI_OX_BASE + 0x3)
+#define HFI_EVENT_SESSION_PROPERTY_CHANGED (HFI_OX_BASE + 0x4)
+
+#define HFI_EVENT_DATA_SEQUENCE_CHANGED_SUFFICIENT_BUFFER_RESOURCES \
+ (HFI_OX_BASE + 0x1)
+#define HFI_EVENT_DATA_SEQUENCE_CHANGED_INSUFFICIENT_BUFFER_RESOURCES \
+ (HFI_OX_BASE + 0x2)
+
+#define HFI_BUFFERFLAG_EOS 0x00000001
+#define HFI_BUFFERFLAG_STARTTIME 0x00000002
+#define HFI_BUFFERFLAG_DECODEONLY 0x00000004
+#define HFI_BUFFERFLAG_DATACORRUPT 0x00000008
+#define HFI_BUFFERFLAG_ENDOFFRAME 0x00000010
+#define HFI_BUFFERFLAG_SYNCFRAME 0x00000020
+#define HFI_BUFFERFLAG_EXTRADATA 0x00000040
+#define HFI_BUFFERFLAG_CODECCONFIG 0x00000080
+#define HFI_BUFFERFLAG_TIMESTAMPINVALID 0x00000100
+#define HFI_BUFFERFLAG_READONLY 0x00000200
+#define HFI_BUFFERFLAG_ENDOFSUBFRAME 0x00000400
+#define HFI_BUFFERFLAG_EOSEQ 0x00200000
+#define HFI_BUFFERFLAG_DISCONTINUITY 0x80000000
+#define HFI_BUFFERFLAG_TEI 0x40000000
+
+#define HFI_ERR_SESSION_EMPTY_BUFFER_DONE_OUTPUT_PENDING \
+ (HFI_OX_BASE + 0x1001)
+#define HFI_ERR_SESSION_SAME_STATE_OPERATION \
+ (HFI_OX_BASE + 0x1002)
+#define HFI_ERR_SESSION_SYNC_FRAME_NOT_DETECTED \
+ (HFI_OX_BASE + 0x1003)
+#define HFI_ERR_SESSION_START_CODE_NOT_FOUND \
+ (HFI_OX_BASE + 0x1004)
+
+#define HFI_BUFFER_INTERNAL_SCRATCH (HFI_OX_BASE + 0x1)
+#define HFI_BUFFER_EXTRADATA_INPUT (HFI_OX_BASE + 0x2)
+#define HFI_BUFFER_EXTRADATA_OUTPUT (HFI_OX_BASE + 0x3)
+#define HFI_BUFFER_EXTRADATA_OUTPUT2 (HFI_OX_BASE + 0x4)
+
+#define HFI_BUFFER_MODE_STATIC (HFI_OX_BASE + 0x1)
+#define HFI_BUFFER_MODE_RING (HFI_OX_BASE + 0x2)
+
+#define HFI_FLUSH_INPUT (HFI_OX_BASE + 0x1)
+#define HFI_FLUSH_OUTPUT (HFI_OX_BASE + 0x2)
+#define HFI_FLUSH_OUTPUT2 (HFI_OX_BASE + 0x3)
+#define HFI_FLUSH_ALL (HFI_OX_BASE + 0x4)
+
+#define HFI_EXTRADATA_NONE 0x00000000
+#define HFI_EXTRADATA_MB_QUANTIZATION 0x00000001
+#define HFI_EXTRADATA_INTERLACE_VIDEO 0x00000002
+#define HFI_EXTRADATA_VC1_FRAMEDISP 0x00000003
+#define HFI_EXTRADATA_VC1_SEQDISP 0x00000004
+#define HFI_EXTRADATA_TIMESTAMP 0x00000005
+#define HFI_EXTRADATA_S3D_FRAME_PACKING 0x00000006
+#define HFI_EXTRADATA_FRAME_RATE 0x00000007
+#define HFI_EXTRADATA_PANSCAN_WINDOW 0x00000008
+#define HFI_EXTRADATA_RECOVERY_POINT_SEI 0x00000009
+#define HFI_EXTRADATA_CLOSED_CAPTION_UD 0x0000000A
+#define HFI_EXTRADATA_AFD_UD 0x0000000B
+#define HFI_EXTRADATA_MULTISLICE_INFO 0x7F100000
+#define HFI_EXTRADATA_NUM_CONCEALED_MB 0x7F100001
+#define HFI_EXTRADATA_INDEX 0x7F100002
+#define HFI_EXTRADATA_METADATA_FILLER 0x7FE00002
+
+#define HFI_INDEX_EXTRADATA_INPUT_CROP 0x0700000E
+#define HFI_INDEX_EXTRADATA_DIGITAL_ZOOM 0x07000010
+#define HFI_INDEX_EXTRADATA_ASPECT_RATIO 0x7F100003
+
+struct hfi_buffer_alloc_mode {
+ u32 buffer_type;
+ u32 buffer_mode;
+};
+
+
+struct hfi_index_extradata_config {
+ int enable;
+ u32 index_extra_data_id;
+};
+
+struct hfi_extradata_header {
+ u32 size;
+ u32 version;
+ u32 port_index;
+ u32 type;
+ u32 data_size;
+ u8 rg_data[1];
+};
+
+#define HFI_INTERLACE_FRAME_PROGRESSIVE 0x01
+#define HFI_INTERLACE_INTERLEAVE_FRAME_TOPFIELDFIRST 0x02
+#define HFI_INTERLACE_INTERLEAVE_FRAME_BOTTOMFIELDFIRST 0x04
+#define HFI_INTERLACE_FRAME_TOPFIELDFIRST 0x08
+#define HFI_INTERLACE_FRAME_BOTTOMFIELDFIRST 0x10
+
+#define HFI_PROPERTY_SYS_OX_START \
+ (HFI_DOMAIN_BASE_COMMON + HFI_ARCH_OX_OFFSET + 0x0000)
+#define HFI_PROPERTY_SYS_IDLE_INDICATOR \
+ (HFI_PROPERTY_SYS_OX_START + 0x001)
+
+#define HFI_PROPERTY_PARAM_OX_START \
+ (HFI_DOMAIN_BASE_COMMON + HFI_ARCH_OX_OFFSET + 0x1000)
+#define HFI_PROPERTY_PARAM_BUFFER_COUNT_ACTUAL \
+ (HFI_PROPERTY_PARAM_OX_START + 0x001)
+#define HFI_PROPERTY_PARAM_UNCOMPRESSED_PLANE_ACTUAL_CONSTRAINTS_INFO \
+ (HFI_PROPERTY_PARAM_OX_START + 0x002)
+#define HFI_PROPERTY_PARAM_INTERLACE_FORMAT_SUPPORTED \
+ (HFI_PROPERTY_PARAM_OX_START + 0x003)
+#define HFI_PROPERTY_PARAM_CHROMA_SITE \
+(HFI_PROPERTY_PARAM_OX_START + 0x004)
+#define HFI_PROPERTY_PARAM_EXTRA_DATA_HEADER_CONFIG \
+ (HFI_PROPERTY_PARAM_OX_START + 0x005)
+#define HFI_PROPERTY_PARAM_INDEX_EXTRADATA \
+ (HFI_PROPERTY_PARAM_OX_START + 0x006)
+#define HFI_PROPERTY_PARAM_DIVX_FORMAT \
+ (HFI_PROPERTY_PARAM_OX_START + 0x007)
+#define HFI_PROPERTY_PARAM_BUFFER_ALLOC_MODE \
+ (HFI_PROPERTY_PARAM_OX_START + 0x008)
+#define HFI_PROPERTY_PARAM_S3D_FRAME_PACKING_EXTRADATA \
+ (HFI_PROPERTY_PARAM_OX_START + 0x009)
+
+#define HFI_PROPERTY_CONFIG_OX_START \
+ (HFI_DOMAIN_BASE_COMMON + HFI_ARCH_OX_OFFSET + 0x02000)
+#define HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS \
+ (HFI_PROPERTY_CONFIG_OX_START + 0x001)
+#define HFI_PROPERTY_CONFIG_REALTIME \
+ (HFI_PROPERTY_CONFIG_OX_START + 0x002)
+#define HFI_PROPERTY_CONFIG_PRIORITY \
+ (HFI_PROPERTY_CONFIG_OX_START + 0x003)
+#define HFI_PROPERTY_CONFIG_BATCH_INFO \
+ (HFI_PROPERTY_CONFIG_OX_START + 0x004)
+
+#define HFI_PROPERTY_PARAM_VDEC_OX_START \
+ (HFI_DOMAIN_BASE_VDEC + HFI_ARCH_OX_OFFSET + 0x3000)
+#define HFI_PROPERTY_PARAM_VDEC_CONTINUE_DATA_TRANSFER \
+ (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x001)
+#define HFI_PROPERTY_PARAM_VDEC_DISPLAY_PICTURE_BUFFER_COUNT\
+ (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x002)
+#define HFI_PROPERTY_PARAM_VDEC_MULTI_VIEW_SELECT \
+ (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x003)
+#define HFI_PROPERTY_PARAM_VDEC_PICTURE_TYPE_DECODE \
+ (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x004)
+#define HFI_PROPERTY_PARAM_VDEC_OUTPUT_ORDER \
+ (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x005)
+#define HFI_PROPERTY_PARAM_VDEC_MB_QUANTIZATION \
+ (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x006)
+#define HFI_PROPERTY_PARAM_VDEC_NUM_CONCEALED_MB \
+ (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x007)
+#define HFI_PROPERTY_PARAM_VDEC_H264_ENTROPY_SWITCHING \
+ (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x008)
+#define HFI_PROPERTY_PARAM_VDEC_OUTPUT2_KEEP_ASPECT_RATIO\
+ (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x009)
+#define HFI_PROPERTY_PARAM_VDEC_FRAME_RATE_EXTRADATA \
+ (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x00A)
+#define HFI_PROPERTY_PARAM_VDEC_PANSCAN_WNDW_EXTRADATA \
+ (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x00B)
+#define HFI_PROPERTY_PARAM_VDEC_RECOVERY_POINT_SEI_EXTRADATA \
+ (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x00C)
+#define HFI_PROPERTY_PARAM_VDEC_THUMBNAIL_MODE \
+ (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x00D)
+
+#define HFI_PROPERTY_PARAM_VDEC_FRAME_ASSEMBLY \
+ (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x00E)
+#define HFI_PROPERTY_PARAM_VDEC_CLOSED_CAPTION_EXTRADATA \
+ (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x00F)
+#define HFI_PROPERTY_PARAM_VDEC_AFD_EXTRADATA \
+ (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x010)
+#define HFI_PROPERTY_PARAM_VDEC_VC1_FRAMEDISP_EXTRADATA \
+ (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x011)
+#define HFI_PROPERTY_PARAM_VDEC_VC1_SEQDISP_EXTRADATA \
+ (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x012)
+#define HFI_PROPERTY_PARAM_VDEC_TIMESTAMP_EXTRADATA \
+ (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x013)
+#define HFI_PROPERTY_PARAM_VDEC_INTERLACE_VIDEO_EXTRADATA \
+ (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x014)
+#define HFI_PROPERTY_PARAM_VDEC_AVC_SESSION_SELECT \
+ (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x015)
+
+#define HFI_PROPERTY_CONFIG_VDEC_OX_START \
+ (HFI_DOMAIN_BASE_VDEC + HFI_ARCH_OX_OFFSET + 0x0000)
+#define HFI_PROPERTY_CONFIG_VDEC_POST_LOOP_DEBLOCKER \
+ (HFI_PROPERTY_CONFIG_VDEC_OX_START + 0x001)
+#define HFI_PROPERTY_CONFIG_VDEC_MB_ERROR_MAP_REPORTING \
+ (HFI_PROPERTY_CONFIG_VDEC_OX_START + 0x002)
+#define HFI_PROPERTY_CONFIG_VDEC_MB_ERROR_MAP \
+ (HFI_PROPERTY_CONFIG_VDEC_OX_START + 0x003)
+
+#define HFI_PROPERTY_PARAM_VENC_OX_START \
+ (HFI_DOMAIN_BASE_VENC + HFI_ARCH_OX_OFFSET + 0x5000)
+#define HFI_PROPERTY_PARAM_VENC_MULTI_SLICE_INFO \
+ (HFI_PROPERTY_PARAM_VENC_OX_START + 0x001)
+#define HFI_PROPERTY_PARAM_VENC_H264_IDR_S3D_FRAME_PACKING_NAL \
+ (HFI_PROPERTY_PARAM_VENC_OX_START + 0x002)
+
+#define HFI_PROPERTY_CONFIG_VENC_OX_START \
+ (HFI_DOMAIN_BASE_VENC + HFI_ARCH_OX_OFFSET + 0x6000)
+#define HFI_PROPERTY_CONFIG_VENC_FRAME_QP \
+ (HFI_PROPERTY_CONFIG_VENC_OX_START + 0x001)
+
+#define HFI_PROPERTY_PARAM_VPE_OX_START \
+ (HFI_DOMAIN_BASE_VPE + HFI_ARCH_OX_OFFSET + 0x7000)
+#define HFI_PROPERTY_CONFIG_VPE_OX_START \
+ (HFI_DOMAIN_BASE_VPE + HFI_ARCH_OX_OFFSET + 0x8000)
+
+struct hfi_batch_info {
+ u32 input_batch_count;
+ u32 output_batch_count;
+};
+
+struct hfi_buffer_count_actual {
+ u32 buffer_type;
+ u32 buffer_count_actual;
+};
+
+struct hfi_buffer_requirements {
+ u32 buffer_type;
+ u32 buffer_size;
+ u32 buffer_region_size;
+ u32 buffer_hold_count;
+ u32 buffer_count_min;
+ u32 buffer_count_actual;
+ u32 contiguous;
+ u32 buffer_alignment;
+};
+
+#define HFI_CHROMA_SITE_0 (HFI_OX_BASE + 0x1)
+#define HFI_CHROMA_SITE_1 (HFI_OX_BASE + 0x2)
+#define HFI_CHROMA_SITE_2 (HFI_OX_BASE + 0x3)
+#define HFI_CHROMA_SITE_3 (HFI_OX_BASE + 0x4)
+#define HFI_CHROMA_SITE_4 (HFI_OX_BASE + 0x5)
+#define HFI_CHROMA_SITE_5 (HFI_OX_BASE + 0x6)
+
+struct hfi_data_payload {
+ u32 size;
+ u8 rg_data[1];
+};
+
+struct hfi_enable_picture {
+ u32 picture_type;
+};
+
+struct hfi_display_picture_buffer_count {
+ int enable;
+ u32 count;
+};
+
+struct hfi_extra_data_header_config {
+ u32 type;
+ u32 buffer_type;
+ u32 version;
+ u32 port_index;
+ u32 client_extra_data_id;
+};
+
+struct hfi_interlace_format_supported {
+ u32 buffer_type;
+ u32 format;
+};
+
+struct hfi_mb_error_map {
+ u32 error_map_size;
+ u8 rg_error_map[1];
+};
+
+struct hfi_metadata_pass_through {
+ int enable;
+ u32 size;
+};
+
+struct hfi_multi_view_select {
+ u32 view_index;
+};
+
+#define HFI_PRIORITY_LOW 10
+#define HFI_PRIOIRTY_MEDIUM 20
+#define HFI_PRIORITY_HIGH 30
+
+#define HFI_OUTPUT_ORDER_DISPLAY (HFI_OX_BASE + 0x1)
+#define HFI_OUTPUT_ORDER_DECODE (HFI_OX_BASE + 0x2)
+
+#define HFI_RATE_CONTROL_OFF (HFI_OX_BASE + 0x1)
+#define HFI_RATE_CONTROL_VBR_VFR (HFI_OX_BASE + 0x2)
+#define HFI_RATE_CONTROL_VBR_CFR (HFI_OX_BASE + 0x3)
+#define HFI_RATE_CONTROL_CBR_VFR (HFI_OX_BASE + 0x4)
+#define HFI_RATE_CONTROL_CBR_CFR (HFI_OX_BASE + 0x5)
+
+struct hfi_uncompressed_plane_actual_constraints_info {
+ u32 buffer_type;
+ u32 num_planes;
+ struct hfi_uncompressed_plane_constraints rg_plane_format[1];
+};
+
+#define HFI_CMD_SYS_OX_START \
+(HFI_DOMAIN_BASE_COMMON + HFI_ARCH_OX_OFFSET + HFI_CMD_START_OFFSET + 0x0000)
+#define HFI_CMD_SYS_SESSION_ABORT (HFI_CMD_SYS_OX_START + 0x001)
+#define HFI_CMD_SYS_PING (HFI_CMD_SYS_OX_START + 0x002)
+
+#define HFI_CMD_SESSION_OX_START \
+(HFI_DOMAIN_BASE_COMMON + HFI_ARCH_OX_OFFSET + HFI_CMD_START_OFFSET + 0x1000)
+#define HFI_CMD_SESSION_LOAD_RESOURCES (HFI_CMD_SESSION_OX_START + 0x001)
+#define HFI_CMD_SESSION_START (HFI_CMD_SESSION_OX_START + 0x002)
+#define HFI_CMD_SESSION_STOP (HFI_CMD_SESSION_OX_START + 0x003)
+#define HFI_CMD_SESSION_EMPTY_BUFFER (HFI_CMD_SESSION_OX_START + 0x004)
+#define HFI_CMD_SESSION_FILL_BUFFER (HFI_CMD_SESSION_OX_START + 0x005)
+#define HFI_CMD_SESSION_SUSPEND (HFI_CMD_SESSION_OX_START + 0x006)
+#define HFI_CMD_SESSION_RESUME (HFI_CMD_SESSION_OX_START + 0x007)
+#define HFI_CMD_SESSION_FLUSH (HFI_CMD_SESSION_OX_START + 0x008)
+#define HFI_CMD_SESSION_GET_PROPERTY (HFI_CMD_SESSION_OX_START + 0x009)
+#define HFI_CMD_SESSION_PARSE_SEQUENCE_HEADER \
+ (HFI_CMD_SESSION_OX_START + 0x00A)
+#define HFI_CMD_SESSION_RELEASE_BUFFERS \
+ (HFI_CMD_SESSION_OX_START + 0x00B)
+#define HFI_CMD_SESSION_RELEASE_RESOURCES \
+ (HFI_CMD_SESSION_OX_START + 0x00C)
+
+#define HFI_MSG_SYS_OX_START \
+(HFI_DOMAIN_BASE_COMMON + HFI_ARCH_OX_OFFSET + HFI_MSG_START_OFFSET + 0x0000)
+#define HFI_MSG_SYS_IDLE (HFI_MSG_SYS_OX_START + 0x1)
+#define HFI_MSG_SYS_PING_ACK (HFI_MSG_SYS_OX_START + 0x2)
+#define HFI_MSG_SYS_PROPERTY_INFO (HFI_MSG_SYS_OX_START + 0x3)
+#define HFI_MSG_SYS_SESSION_ABORT_DONE (HFI_MSG_SYS_OX_START + 0x4)
+
+#define HFI_MSG_SESSION_OX_START \
+(HFI_DOMAIN_BASE_COMMON + HFI_ARCH_OX_OFFSET + HFI_MSG_START_OFFSET + 0x1000)
+#define HFI_MSG_SESSION_LOAD_RESOURCES_DONE (HFI_MSG_SESSION_OX_START + 0x1)
+#define HFI_MSG_SESSION_START_DONE (HFI_MSG_SESSION_OX_START + 0x2)
+#define HFI_MSG_SESSION_STOP_DONE (HFI_MSG_SESSION_OX_START + 0x3)
+#define HFI_MSG_SESSION_SUSPEND_DONE (HFI_MSG_SESSION_OX_START + 0x4)
+#define HFI_MSG_SESSION_RESUME_DONE (HFI_MSG_SESSION_OX_START + 0x5)
+#define HFI_MSG_SESSION_FLUSH_DONE (HFI_MSG_SESSION_OX_START + 0x6)
+#define HFI_MSG_SESSION_EMPTY_BUFFER_DONE (HFI_MSG_SESSION_OX_START + 0x7)
+#define HFI_MSG_SESSION_FILL_BUFFER_DONE (HFI_MSG_SESSION_OX_START + 0x8)
+#define HFI_MSG_SESSION_PROPERTY_INFO (HFI_MSG_SESSION_OX_START + 0x9)
+#define HFI_MSG_SESSION_RELEASE_RESOURCES_DONE \
+ (HFI_MSG_SESSION_OX_START + 0xA)
+#define HFI_MSG_SESSION_PARSE_SEQUENCE_HEADER_DONE \
+ (HFI_MSG_SESSION_OX_START + 0xB)
+#define HFI_MSG_SESSION_RELEASE_BUFFERS_DONE \
+ (HFI_MSG_SESSION_OX_START + 0xC)
+
+#define HFI_MIN_PKT_SIZE 8
+
+struct hfi_cmd_sys_session_abort_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+};
+
+struct hfi_cmd_sys_ping_packet {
+ u32 size;
+ u32 packet_type;
+ u32 client_data;
+};
+
+struct hfi_cmd_session_load_resources_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+};
+
+struct hfi_cmd_session_start_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+};
+
+struct hfi_cmd_session_stop_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+};
+
+struct hfi_cmd_session_empty_buffer_compressed_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+ u32 time_stamp_hi;
+ u32 time_stamp_lo;
+ u32 flags;
+ u32 mark_target;
+ u32 mark_data;
+ u32 offset;
+ u32 alloc_len;
+ u32 filled_len;
+ u32 input_tag;
+ u8 *packet_buffer;
+ u8 *extra_data_buffer;
+ u32 rgData[0];
+};
+
+struct hfi_cmd_session_empty_buffer_uncompressed_plane0_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+ u32 view_id;
+ u32 time_stamp_hi;
+ u32 time_stamp_lo;
+ u32 flags;
+ u32 mark_target;
+ u32 mark_data;
+ u32 alloc_len;
+ u32 filled_len;
+ u32 offset;
+ u32 input_tag;
+ u8 *packet_buffer;
+ u8 *extra_data_buffer;
+ u32 rgData[0];
+};
+
+struct hfi_cmd_session_empty_buffer_uncompressed_plane1_packet {
+ u32 flags;
+ u32 alloc_len;
+ u32 filled_len;
+ u32 offset;
+ u8 *packet_buffer2;
+ u32 rgData[0];
+};
+
+struct hfi_cmd_session_empty_buffer_uncompressed_plane2_packet {
+ u32 flags;
+ u32 alloc_len;
+ u32 filled_len;
+ u32 offset;
+ u8 *packet_buffer3;
+ u32 rgData[0];
+};
+
+struct hfi_cmd_session_fill_buffer_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+ u32 stream_id;
+ u32 offset;
+ u32 alloc_len;
+ u32 filled_len;
+ u32 output_tag;
+ u8 *packet_buffer;
+ u8 *extra_data_buffer;
+ u32 rgData[0];
+};
+
+struct hfi_cmd_session_flush_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+ u32 flush_type;
+};
+
+struct hfi_cmd_session_suspend_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+};
+
+struct hfi_cmd_session_resume_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+};
+
+struct hfi_cmd_session_get_property_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+ u32 num_properties;
+ u32 rg_property_data[1];
+};
+
+struct hfi_cmd_session_release_buffer_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+ u32 buffer_type;
+ u32 buffer_size;
+ u32 extra_data_size;
+ int response_req;
+ u32 num_buffers;
+ u32 rg_buffer_info[1];
+};
+
+struct hfi_cmd_session_release_resources_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+};
+
+struct hfi_cmd_session_parse_sequence_header_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+ u32 header_len;
+ u8 *packet_buffer;
+};
+
+struct hfi_msg_sys_session_abort_done_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+ u32 error_type;
+};
+
+struct hfi_msg_sys_idle_packet {
+ u32 size;
+ u32 packet_type;
+};
+
+struct hfi_msg_sys_ping_ack_packet {
+ u32 size;
+ u32 packet_type;
+ u32 client_data;
+};
+
+struct hfi_msg_sys_property_info_packet {
+ u32 size;
+ u32 packet_type;
+ u32 num_properties;
+ u32 rg_property_data[1];
+};
+
+struct hfi_msg_session_load_resources_done_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+ u32 error_type;
+};
+
+struct hfi_msg_session_start_done_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+ u32 error_type;
+};
+
+struct hfi_msg_session_stop_done_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+ u32 error_type;
+};
+
+struct hfi_msg_session_suspend_done_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+ u32 error_type;
+};
+
+struct hfi_msg_session_resume_done_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+ u32 error_type;
+};
+
+struct hfi_msg_session_flush_done_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+ u32 error_type;
+ u32 flush_type;
+};
+
+struct hfi_msg_session_empty_buffer_done_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+ u32 error_type;
+ u32 offset;
+ u32 filled_len;
+ u32 input_tag;
+ u8 *packet_buffer;
+ u8 *extra_data_buffer;
+ u32 rgData[0];
+};
+
+struct hfi_msg_session_fill_buffer_done_compressed_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+ u32 time_stamp_hi;
+ u32 time_stamp_lo;
+ u32 error_type;
+ u32 flags;
+ u32 mark_target;
+ u32 mark_data;
+ u32 stats;
+ u32 offset;
+ u32 alloc_len;
+ u32 filled_len;
+ u32 input_tag;
+ u32 output_tag;
+ u32 picture_type;
+ u8 *packet_buffer;
+ u8 *extra_data_buffer;
+ u32 rgData[0];
+};
+
+struct hfi_msg_session_fbd_uncompressed_plane0_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+ u32 stream_id;
+ u32 view_id;
+ u32 error_type;
+ u32 time_stamp_hi;
+ u32 time_stamp_lo;
+ u32 flags;
+ u32 mark_target;
+ u32 mark_data;
+ u32 stats;
+ u32 alloc_len;
+ u32 filled_len;
+ u32 offset;
+ u32 frame_width;
+ u32 frame_height;
+ u32 start_x_coord;
+ u32 start_y_coord;
+ u32 input_tag;
+ u32 input_tag2;
+ u32 output_tag;
+ u32 picture_type;
+ u8 *packet_buffer;
+ u8 *extra_data_buffer;
+ u32 rgData[0];
+};
+
+struct hfi_msg_session_fill_buffer_done_uncompressed_plane1_packet {
+ u32 flags;
+ u32 alloc_len;
+ u32 filled_len;
+ u32 offset;
+ u8 *packet_buffer2;
+ u32 rgData[0];
+};
+
+struct hfi_msg_session_fill_buffer_done_uncompressed_plane2_packet {
+ u32 flags;
+ u32 alloc_len;
+ u32 filled_len;
+ u32 offset;
+ u8 *packet_buffer3;
+ u32 rgData[0];
+};
+
+struct hfi_msg_session_parse_sequence_header_done_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+ u32 error_type;
+ u32 num_properties;
+ u32 rg_property_data[1];
+};
+
+struct hfi_msg_session_property_info_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+ u32 num_properties;
+ u32 rg_property_data[1];
+};
+
+struct hfi_msg_session_release_resources_done_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+ u32 error_type;
+};
+
+struct hfi_msg_session_release_buffers_done_packet {
+ u32 size;
+ u32 packet_type;
+ u32 session_id;
+ u32 error_type;
+ u32 num_buffers;
+ u32 rg_buffer_info[1];
+};
+
+struct hfi_extradata_mb_quantization_payload {
+ u8 rg_mb_qp[1];
+};
+
+struct hfi_extradata_vc1_pswnd {
+ u32 ps_wnd_h_offset;
+ u32 ps_wnd_v_offset;
+ u32 ps_wnd_width;
+ u32 ps_wnd_height;
+};
+
+struct hfi_extradata_vc1_framedisp_payload {
+ u32 res_pic;
+ u32 ref;
+ u32 range_map_present;
+ u32 range_map_y;
+ u32 range_map_uv;
+ u32 num_pan_scan_wnds;
+ struct hfi_extradata_vc1_pswnd rg_ps_wnd[1];
+};
+
+struct hfi_extradata_vc1_seqdisp_payload {
+ u32 prog_seg_frm;
+ u32 uv_sampling_fmt;
+ u32 color_fmt_flag;
+ u32 color_primaries;
+ u32 transfer_char;
+ u32 mat_coeff;
+ u32 aspect_ratio;
+ u32 aspect_horiz;
+ u32 aspect_vert;
+};
+
+struct hfi_extradata_timestamp_payload {
+ u32 time_stamp_low;
+ u32 time_stamp_high;
+};
+
+
+struct hfi_extradata_s3d_frame_packing_payload {
+ u32 fpa_id;
+ int cancel_flag;
+ u32 fpa_type;
+ int quin_cunx_flag;
+ u32 content_interprtation_type;
+ int spatial_flipping_flag;
+ int frame0_flipped_flag;
+ int field_views_flag;
+ int current_frame_isFrame0_flag;
+ int frame0_self_contained_flag;
+ int frame1_self_contained_flag;
+ u32 frame0_graid_pos_x;
+ u32 frame0_graid_pos_y;
+ u32 frame1_graid_pos_x;
+ u32 frame1_graid_pos_y;
+ u32 fpa_reserved_byte;
+ u32 fpa_repetition_period;
+ int fpa_extension_flag;
+};
+
+struct hfi_extradata_interlace_video_payload {
+ u32 format;
+};
+
+struct hfi_extradata_num_concealed_mb_payload {
+ u32 num_mb_concealed;
+};
+
+struct hfi_extradata_sliceinfo {
+ u32 offset_in_stream;
+ u32 slice_length;
+};
+
+struct hfi_extradata_multislice_info_payload {
+ u32 num_slices;
+ struct hfi_extradata_sliceinfo rg_slice_info[1];
+};
+
+struct hfi_index_extradata_input_crop_payload {
+ u32 size;
+ u32 version;
+ u32 port_index;
+ u32 left;
+ u32 top;
+ u32 width;
+ u32 height;
+};
+
+struct hfi_index_extradata_digital_zoom_payload {
+ u32 size;
+ u32 version;
+ u32 port_index;
+ int width;
+ int height;
+};
+
+struct hfi_index_extradata_aspect_ratio_payload {
+ u32 size;
+ u32 version;
+ u32 port_index;
+ u32 aspect_width;
+ u32 aspect_height;
+};
+struct hfi_extradata_panscan_wndw_payload {
+ u32 num_window;
+ struct hfi_extradata_vc1_pswnd wnd[1];
+};
+
+struct hfi_extradata_frame_type_payload {
+ u32 frame_rate;
+};
+
+struct hfi_extradata_recovery_point_sei_payload {
+ u32 flag;
+};
+
+struct hal_session {
+ struct list_head list;
+ u32 session_id;
+ u32 is_decoder;
+ void *device;
+};
+
+struct hal_device_data {
+ struct list_head dev_head;
+ int dev_count;
+};
+
+extern struct hal_device_data hal_ctxt;
+
+void hfi_process_msg_packet(msm_vidc_callback callback,
+ u32 device_id, struct vidc_hal_msg_pkt_hdr *msg_hdr);
+#endif
+
diff --git a/drivers/media/video/msm_vidc/vidc_hfi_api.h b/drivers/media/video/msm_vidc/vidc_hfi_api.h
index 79fee90..370785c 100644
--- a/drivers/media/video/msm_vidc/vidc_hfi_api.h
+++ b/drivers/media/video/msm_vidc/vidc_hfi_api.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
@@ -14,7 +14,9 @@
#ifndef __VIDC_HFI_API_H__
#define __VIDC_HFI_API_H__
+#include <linux/platform_device.h>
#include <linux/types.h>
+#include <media/msm_vidc.h>
#define CONTAINS(__a, __sz, __t) ({\
int __rc = __t >= __a && \
@@ -513,6 +515,7 @@
struct hal_bitrate {
u32 bit_rate;
+ u32 layer_id;
};
struct hal_profile_level {
@@ -587,6 +590,7 @@
u32 qpi;
u32 qpp;
u32 qpb;
+ u32 layer_id;
};
struct hal_intra_period {
@@ -979,44 +983,84 @@
struct hal_buffer_requirements buffer[HAL_BUFFER_MAX];
};
-/* VIDC_HAL CORE API's */
-int venus_hfi_core_init(void *device);
-int venus_hfi_core_release(void *device);
-int venus_hfi_core_pc_prep(void *device);
-int venus_hfi_core_set_resource(void *device,
- struct vidc_resource_hdr *resource_hdr, void *resource_value);
-int venus_hfi_core_release_resource(void *device,
- struct vidc_resource_hdr *resource_hdr);
-int venus_hfi_core_ping(void *device);
+enum msm_vidc_hfi_type {
+ VIDC_HFI_VENUS,
+ VIDC_HFI_Q6,
+};
-/* VIDC_HAL SESSION API's */
-void *venus_hfi_session_init(void *device, u32 session_id,
- enum hal_domain session_type, enum hal_video_codec codec_type);
-int venus_hfi_session_end(void *session);
-int venus_hfi_session_abort(void *session);
-int venus_hfi_session_set_buffers(void *sess,
- struct vidc_buffer_addr_info *buffer_info);
-int venus_hfi_session_release_buffers(void *sess,
- struct vidc_buffer_addr_info *buffer_info);
-int venus_hfi_session_load_res(void *sess);
-int venus_hfi_session_release_res(void *sess);
-int venus_hfi_session_start(void *sess);
-int venus_hfi_session_stop(void *sess);
-int venus_hfi_session_suspend(void *sess);
-int venus_hfi_session_resume(void *sess);
-int venus_hfi_session_etb(void *sess,
- struct vidc_frame_data *input_frame);
-int venus_hfi_session_ftb(void *sess,
- struct vidc_frame_data *output_frame);
-int venus_hfi_session_parse_seq_hdr(void *sess,
- struct vidc_seq_hdr *seq_hdr);
-int venus_hfi_session_get_seq_hdr(void *sess,
- struct vidc_seq_hdr *seq_hdr);
-int venus_hfi_session_get_buf_req(void *sess);
-int venus_hfi_session_flush(void *sess, enum hal_flush flush_mode);
-int venus_hfi_session_set_property(void *sess, enum hal_property ptype,
- void *pdata);
-int venus_hfi_session_get_property(void *sess, enum hal_property ptype,
- void *pdata);
+enum mem_type {
+ DDR_MEM = 0x1,
+ OCMEM_MEM = 0x2,
+};
+
+enum fw_info {
+ FW_BASE_ADDRESS,
+ FW_REGISTER_BASE,
+ FW_REGISTER_SIZE,
+ FW_IRQ,
+ FW_INFO_MAX,
+};
+
+struct hfi_device {
+ void *hfi_device_data;
+
+ /*Add function pointers for all the hfi functions below*/
+ int (*core_init)(void *device);
+ int (*core_release)(void *device);
+ int (*core_pc_prep)(void *device);
+ int (*core_ping)(void *device);
+ void *(*session_init)(void *device, u32 session_id,
+ enum hal_domain session_type, enum hal_video_codec codec_type);
+ int (*session_end)(void *session);
+ int (*session_abort)(void *session);
+ int (*session_set_buffers)(void *sess,
+ struct vidc_buffer_addr_info *buffer_info);
+ int (*session_release_buffers)(void *sess,
+ struct vidc_buffer_addr_info *buffer_info);
+ int (*session_load_res)(void *sess);
+ int (*session_release_res)(void *sess);
+ int (*session_start)(void *sess);
+ int (*session_stop)(void *sess);
+ int (*session_suspend)(void *sess);
+ int (*session_resume)(void *sess);
+ int (*session_etb)(void *sess,
+ struct vidc_frame_data *input_frame);
+ int (*session_ftb)(void *sess,
+ struct vidc_frame_data *output_frame);
+ int (*session_parse_seq_hdr)(void *sess,
+ struct vidc_seq_hdr *seq_hdr);
+ int (*session_get_seq_hdr)(void *sess,
+ struct vidc_seq_hdr *seq_hdr);
+ int (*session_get_buf_req)(void *sess);
+ int (*session_flush)(void *sess, enum hal_flush flush_mode);
+ int (*session_set_property)(void *sess, enum hal_property ptype,
+ void *pdata);
+ int (*session_get_property)(void *sess, enum hal_property ptype,
+ void *pdata);
+ int (*scale_clocks)(void *dev, int load);
+ int (*scale_bus)(void *dev, int load,
+ enum session_type type, enum mem_type mtype);
+ int (*unset_ocmem)(void *dev);
+ int (*alloc_ocmem)(void *dev, unsigned long size);
+ int (*free_ocmem)(void *dev);
+ int (*is_ocmem_present)(void *dev);
+ int (*get_domain)(void *dev, enum msm_vidc_io_maps iomap);
+ int (*iommu_get_map)(void *dev,
+ struct msm_vidc_iommu_info maps[MAX_MAP]);
+ int (*load_fw)(void *dev);
+ void (*unload_fw)(void *dev);
+ int (*get_fw_info)(void *dev, enum fw_info info);
+};
+
+typedef void (*hfi_cmd_response_callback) (enum command_response cmd,
+ void *data);
+typedef void (*msm_vidc_callback) (u32 response, void *callback);
+
+void *vidc_hfi_initialize(enum msm_vidc_hfi_type hfi_type, u32 device_id,
+ struct platform_device *pdev,
+ hfi_cmd_response_callback callback);
+void vidc_hfi_deinitialize(enum msm_vidc_hfi_type hfi_type,
+ struct hfi_device *hdev);
+
#endif /*__VIDC_HFI_API_H__ */
diff --git a/drivers/media/video/msm_wfd/mdp-4-subdev.c b/drivers/media/video/msm_wfd/mdp-4-subdev.c
index c68d5d4..d2ecd22 100644
--- a/drivers/media/video/msm_wfd/mdp-4-subdev.c
+++ b/drivers/media/video/msm_wfd/mdp-4-subdev.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. 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
@@ -11,6 +11,7 @@
*
*/
#include <linux/msm_mdp.h>
+#include <linux/switch.h>
#include <mach/iommu_domains.h>
#include <media/videobuf2-core.h>
#include "enc-subdev.h"
@@ -23,6 +24,7 @@
u32 width;
bool secure;
bool uses_iommu_split_domain;
+ struct switch_dev sdev;
};
int mdp_init(struct v4l2_subdev *sd, u32 val)
@@ -54,14 +56,13 @@
rc = -ENODEV;
goto mdp_open_fail;
}
-
- /*Tell HDMI daemon to open fb2*/
- rc = kobject_uevent(&fbi->dev->kobj, KOBJ_ADD);
+ inst->sdev.name = "wfd";
+ /* Register wfd node to switch driver */
+ rc = switch_dev_register(&inst->sdev);
if (rc) {
- WFD_MSG_ERR("Failed add to kobj");
+ WFD_MSG_ERR("WFD switch registration failed\n");
goto mdp_open_fail;
}
-
msm_fb_writeback_init(fbi);
inst->mdp = fbi;
inst->secure = mops->secure;
@@ -91,9 +92,8 @@
rc = -ENODEV;
goto exit;
}
- rc = kobject_uevent(&fbi->dev->kobj, KOBJ_ONLINE);
- if (rc)
- WFD_MSG_ERR("Failed to send ONLINE event\n");
+ switch_set_state(&inst->sdev, true);
+ WFD_MSG_DBG("wfd state switched to %d\n", inst->sdev.state);
}
exit:
return rc;
@@ -110,11 +110,8 @@
return rc;
}
fbi = (struct fb_info *)inst->mdp;
- rc = kobject_uevent(&fbi->dev->kobj, KOBJ_OFFLINE);
- if (rc) {
- WFD_MSG_ERR("Failed to send offline event\n");
- return -EIO;
- }
+ switch_set_state(&inst->sdev, false);
+ WFD_MSG_DBG("wfd state switched to %d\n", inst->sdev.state);
}
return 0;
}
@@ -126,6 +123,8 @@
fbi = (struct fb_info *)inst->mdp;
msm_fb_writeback_terminate(fbi);
kfree(inst);
+ /* Unregister wfd node from switch driver */
+ switch_dev_unregister(&inst->sdev);
}
return 0;
}
diff --git a/drivers/media/video/msm_wfd/mdp-5-subdev.c b/drivers/media/video/msm_wfd/mdp-5-subdev.c
index 4f29389..5b49498 100644
--- a/drivers/media/video/msm_wfd/mdp-5-subdev.c
+++ b/drivers/media/video/msm_wfd/mdp-5-subdev.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
@@ -11,18 +11,19 @@
*
*/
#include <linux/msm_mdp.h>
+#include <linux/switch.h>
#include <mach/iommu_domains.h>
#include <media/videobuf2-core.h>
#include "enc-subdev.h"
#include "mdp-subdev.h"
#include "wfd-util.h"
-
struct mdp_instance {
struct fb_info *mdp;
u32 height;
u32 width;
bool secure;
+ struct switch_dev sdev;
};
int mdp_init(struct v4l2_subdev *sd, u32 val)
@@ -54,12 +55,13 @@
rc = -ENODEV;
goto mdp_open_fail;
}
-
- /*Tell HDMI daemon to open fb2*/
- rc = kobject_uevent(&fbi->dev->kobj, KOBJ_ADD);
- if (rc)
- WFD_MSG_ERR("Failed add to kobj");
-
+ inst->sdev.name = "wfd";
+ /* Register wfd node to switch driver */
+ rc = switch_dev_register(&inst->sdev);
+ if (rc) {
+ WFD_MSG_ERR("WFD switch registration failed\n");
+ goto mdp_open_fail;
+ }
msm_fb_writeback_init(fbi);
inst->mdp = fbi;
inst->secure = mops->secure;
@@ -88,9 +90,8 @@
rc = -ENODEV;
goto exit;
}
- rc = kobject_uevent(&fbi->dev->kobj, KOBJ_ONLINE);
- if (rc)
- WFD_MSG_ERR("Failed to send ONLINE event\n");
+ switch_set_state(&inst->sdev, true);
+ WFD_MSG_DBG("wfd state switched to %d\n", inst->sdev.state);
}
exit:
return rc;
@@ -108,11 +109,8 @@
return rc;
}
fbi = (struct fb_info *)inst->mdp;
- rc = kobject_uevent(&fbi->dev->kobj, KOBJ_OFFLINE);
- if (rc) {
- WFD_MSG_ERR("Failed to send offline event\n");
- return -EIO;
- }
+ switch_set_state(&inst->sdev, false);
+ WFD_MSG_DBG("wfd state switched to %d\n", inst->sdev.state);
}
return 0;
}
@@ -124,6 +122,8 @@
fbi = (struct fb_info *)inst->mdp;
msm_fb_writeback_terminate(fbi);
kfree(inst);
+ /* Unregister wfd node from switch driver */
+ switch_dev_unregister(&inst->sdev);
}
return 0;
}
diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c
index bc129da..cc021c0 100644
--- a/drivers/mfd/wcd9xxx-core.c
+++ b/drivers/mfd/wcd9xxx-core.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. 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
@@ -334,7 +334,7 @@
{
int ret;
- if (wcd9xxx->reset_gpio) {
+ if (wcd9xxx->reset_gpio && wcd9xxx->slim_device_bootup) {
ret = gpio_request(wcd9xxx->reset_gpio, "CDC_RESET");
if (ret) {
pr_err("%s: Failed to request gpio %d\n", __func__,
@@ -342,7 +342,8 @@
wcd9xxx->reset_gpio = 0;
return ret;
}
-
+ }
+ if (wcd9xxx->reset_gpio) {
gpio_direction_output(wcd9xxx->reset_gpio, 0);
msleep(20);
gpio_direction_output(wcd9xxx->reset_gpio, 1);
@@ -1259,6 +1260,7 @@
wcd9xxx->reset_gpio = pdata->reset_gpio;
wcd9xxx->dev = &slim->dev;
wcd9xxx->mclk_rate = pdata->mclk_rate;
+ wcd9xxx->slim_device_bootup = true;
ret = wcd9xxx_enable_supplies(wcd9xxx, pdata);
if (ret)
@@ -1378,6 +1380,29 @@
return ret;
}
+static int wcd9xxx_device_up(struct wcd9xxx *wcd9xxx)
+{
+ int ret = 0;
+
+ if (wcd9xxx->slim_device_bootup) {
+ wcd9xxx->slim_device_bootup = false;
+ return 0;
+ }
+ ret = wcd9xxx_reset(wcd9xxx);
+ if (ret)
+ pr_err("%s: Resetting Codec failed\n", __func__);
+
+ wcd9xxx_bring_up(wcd9xxx);
+ wcd9xxx->post_reset(wcd9xxx);
+ return ret;
+}
+
+static int wcd9xxx_slim_device_up(struct slim_device *sldev)
+{
+ struct wcd9xxx *wcd9xxx = slim_get_devicedata(sldev);
+ return wcd9xxx_device_up(wcd9xxx);
+}
+
static int wcd9xxx_slim_resume(struct slim_device *sldev)
{
struct wcd9xxx *wcd9xxx = slim_get_devicedata(sldev);
@@ -1533,6 +1558,7 @@
.id_table = taiko_slimtest_id,
.resume = wcd9xxx_slim_resume,
.suspend = wcd9xxx_slim_suspend,
+ .device_up = wcd9xxx_slim_device_up,
};
static const struct slim_device_id tapan_slimtest_id[] = {
diff --git a/drivers/mfd/wcd9xxx-irq.c b/drivers/mfd/wcd9xxx-irq.c
index 23e0fcc..962558c 100644
--- a/drivers/mfd/wcd9xxx-irq.c
+++ b/drivers/mfd/wcd9xxx-irq.c
@@ -182,23 +182,37 @@
}
EXPORT_SYMBOL_GPL(wcd9xxx_unlock_sleep);
+void wcd9xxx_nested_irq_lock(struct wcd9xxx *wcd9xxx)
+{
+ mutex_lock(&wcd9xxx->nested_irq_lock);
+}
+
+void wcd9xxx_nested_irq_unlock(struct wcd9xxx *wcd9xxx)
+{
+ mutex_unlock(&wcd9xxx->nested_irq_lock);
+}
+
static void wcd9xxx_irq_dispatch(struct wcd9xxx *wcd9xxx, int irqbit)
{
if ((irqbit <= WCD9XXX_IRQ_MBHC_INSERTION) &&
(irqbit >= WCD9XXX_IRQ_MBHC_REMOVAL)) {
+ wcd9xxx_nested_irq_lock(wcd9xxx);
wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_INTR_CLEAR0 +
BIT_BYTE(irqbit),
BYTE_BIT_MASK(irqbit));
if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_INTR_MODE, 0x02);
handle_nested_irq(phyirq_to_virq(wcd9xxx, irqbit));
+ wcd9xxx_nested_irq_unlock(wcd9xxx);
} else {
+ wcd9xxx_nested_irq_lock(wcd9xxx);
handle_nested_irq(phyirq_to_virq(wcd9xxx, irqbit));
wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_INTR_CLEAR0 +
BIT_BYTE(irqbit),
BYTE_BIT_MASK(irqbit));
if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_INTR_MODE, 0x02);
+ wcd9xxx_nested_irq_unlock(wcd9xxx);
}
}
@@ -325,11 +339,13 @@
u8 irq_level[wcd9xxx_num_irq_regs(wcd9xxx)];
mutex_init(&wcd9xxx->irq_lock);
+ mutex_init(&wcd9xxx->nested_irq_lock);
wcd9xxx->irq = wcd9xxx_irq_get_upstream_irq(wcd9xxx);
if (!wcd9xxx->irq) {
pr_warn("%s: irq driver is not yet initialized\n", __func__);
mutex_destroy(&wcd9xxx->irq_lock);
+ mutex_destroy(&wcd9xxx->nested_irq_lock);
return -EPROBE_DEFER;
}
pr_debug("%s: probed irq %d\n", __func__, wcd9xxx->irq);
@@ -339,6 +355,8 @@
if (ret) {
pr_err("%s: Failed to setup downstream IRQ\n", __func__);
wcd9xxx_irq_put_upstream_irq(wcd9xxx);
+ mutex_destroy(&wcd9xxx->irq_lock);
+ mutex_destroy(&wcd9xxx->nested_irq_lock);
return ret;
}
@@ -388,6 +406,7 @@
pr_err("%s: Failed to init wcd9xxx irq\n", __func__);
wcd9xxx_irq_put_upstream_irq(wcd9xxx);
mutex_destroy(&wcd9xxx->irq_lock);
+ mutex_destroy(&wcd9xxx->nested_irq_lock);
}
return ret;
@@ -424,6 +443,7 @@
device_init_wakeup(wcd9xxx->dev, 0);
}
mutex_destroy(&wcd9xxx->irq_lock);
+ mutex_destroy(&wcd9xxx->nested_irq_lock);
}
#ifndef CONFIG_OF
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index c415952..3d3563a 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -2,7 +2,7 @@
/*Qualcomm Secure Execution Environment Communicator (QSEECOM) driver
*
- * Copyright (c) 2012, Code Aurora Forum. 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
@@ -1463,7 +1463,7 @@
struct qseecom_command_scm_resp resp;
u8 *img_data = NULL;
- if (__qseecom_get_fw_size("commonlib", &fw_size))
+ if (__qseecom_get_fw_size("cmnlib", &fw_size))
return -EIO;
img_data = kzalloc(fw_size, GFP_KERNEL);
@@ -1471,7 +1471,7 @@
pr_err("Mem allocation for lib image data failed\n");
return -ENOMEM;
}
- ret = __qseecom_get_fw_data("commonlib", img_data, &load_req);
+ ret = __qseecom_get_fw_data("cmnlib", img_data, &load_req);
if (ret) {
kzfree(img_data);
return -EIO;
@@ -2277,12 +2277,16 @@
ret = qsee_vote_for_clock(data, CLK_DFAB);
if (ret)
pr_err("Failed to vote for DFAB clock%d\n", ret);
+ ret = qsee_vote_for_clock(data, CLK_SFPB);
+ if (ret)
+ pr_err("Failed to vote for SFPB clock%d\n", ret);
atomic_dec(&data->ioctl_count);
break;
}
case QSEECOM_IOCTL_PERF_DISABLE_REQ:{
atomic_inc(&data->ioctl_count);
qsee_disable_clock_vote(data, CLK_DFAB);
+ qsee_disable_clock_vote(data, CLK_SFPB);
atomic_dec(&data->ioctl_count);
break;
}
diff --git a/drivers/misc/tspp.c b/drivers/misc/tspp.c
index d4ff38b..563a013 100644
--- a/drivers/misc/tspp.c
+++ b/drivers/misc/tspp.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. 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
@@ -25,6 +25,7 @@
#include <linux/slab.h> /* kfree, kzalloc */
#include <linux/ioport.h> /* XXX_ mem_region */
#include <linux/dma-mapping.h> /* dma_XXX */
+#include <linux/dmapool.h> /* DMA pools */
#include <linux/delay.h> /* msleep */
#include <linux/platform_device.h>
#include <linux/clk.h>
@@ -65,6 +66,14 @@
#define TSPP_MAX_BUFFER_SIZE (32 * 1024 - 1)
/*
+ * Returns whether to use DMA pool for TSPP output buffers.
+ * For buffers smaller than page size, using DMA pool
+ * provides better memory utilization as dma_alloc_coherent
+ * allocates minimum of page size.
+ */
+#define TSPP_USE_DMA_POOL(buff_size) ((buff_size) < PAGE_SIZE)
+
+/*
* Max allowed TSPP buffers/descriptors.
* If SPS desc FIFO holds X descriptors, we can queue up to X-1 descriptors.
*/
@@ -398,6 +407,7 @@
void *notify_data; /* data to be passed with the notifier */
u32 expiration_period_ms; /* notification on partially filled buffers */
struct timer_list expiration_timer;
+ struct dma_pool *dma_pool;
tspp_memfree *memfree; /* user defined memory free function */
void *user_info; /* user cookie passed to memory alloc/free function */
};
@@ -898,7 +908,7 @@
}
static int tspp_alloc_buffer(u32 channel_id, struct tspp_data_descriptor *desc,
- u32 size, tspp_allocator *alloc, void *user)
+ u32 size, struct dma_pool *dma_pool, tspp_allocator *alloc, void *user)
{
if (size < TSPP_MIN_BUFFER_SIZE ||
size > TSPP_MAX_BUFFER_SIZE) {
@@ -911,10 +921,15 @@
desc->virt_base = alloc(channel_id, size,
&desc->phys_base, user);
} else {
- desc->virt_base = dma_alloc_coherent(NULL, size,
- &desc->phys_base, GFP_KERNEL);
+ if (!dma_pool)
+ desc->virt_base = dma_alloc_coherent(NULL, size,
+ &desc->phys_base, GFP_KERNEL);
+ else
+ desc->virt_base = dma_pool_alloc(dma_pool, GFP_KERNEL,
+ &desc->phys_base);
+
if (desc->virt_base == 0) {
- pr_err("tspp dma alloc coherent failed %i", size);
+ pr_err("tspp: dma buffer allocation failed %i\n", size);
return -ENOMEM;
}
}
@@ -1225,10 +1240,15 @@
pbuf->desc.phys_base,
channel->user_info);
} else {
- dma_free_coherent(NULL,
- pbuf->desc.size,
- pbuf->desc.virt_base,
- pbuf->desc.phys_base);
+ if (!channel->dma_pool)
+ dma_free_coherent(NULL,
+ pbuf->desc.size,
+ pbuf->desc.virt_base,
+ pbuf->desc.phys_base);
+ else
+ dma_pool_free(channel->dma_pool,
+ pbuf->desc.virt_base,
+ pbuf->desc.phys_base);
}
pbuf->desc.phys_base = 0;
}
@@ -1568,6 +1588,10 @@
config->desc.phys_base);
tspp_destroy_buffers(channel_id, channel);
+ if (channel->dma_pool) {
+ dma_pool_destroy(channel->dma_pool);
+ channel->dma_pool = NULL;
+ }
channel->src = TSPP_SOURCE_NONE;
channel->mode = TSPP_MODE_DISABLED;
@@ -1704,7 +1728,7 @@
*/
if (channel->buffer_count == 0) {
channel->buffer_size =
- tspp_align_buffer_size_by_mode(channel->buffer_size,
+ tspp_align_buffer_size_by_mode(channel->buffer_size,
channel->mode);
rc = tspp_allocate_buffers(dev, channel->id,
channel->max_buffers,
@@ -2072,6 +2096,7 @@
}
channel = &pdev->channels[channel_id];
+
/* allow buffer allocation only if there was no previous buffer
* allocation for this channel.
*/
@@ -2101,6 +2126,22 @@
channel->memfree = memfree;
channel->user_info = user;
+ /*
+ * For small buffers, create a DMA pool so that memory
+ * is not wasted through dma_alloc_coherent.
+ */
+ if (TSPP_USE_DMA_POOL(channel->buffer_size)) {
+ channel->dma_pool = dma_pool_create("tspp",
+ NULL, channel->buffer_size, 0, 0);
+ if (!channel->dma_pool) {
+ pr_err("%s: Can't allocate memory pool\n", __func__);
+ return -ENOMEM;
+ }
+ } else {
+ channel->dma_pool = NULL;
+ }
+
+
for (channel->buffer_count = 0;
channel->buffer_count < channel->max_buffers;
channel->buffer_count++) {
@@ -2117,7 +2158,8 @@
desc->desc.id = channel->buffer_count;
/* allocate the buffer */
if (tspp_alloc_buffer(channel_id, &desc->desc,
- channel->buffer_size, alloc, user) != 0) {
+ channel->buffer_size, channel->dma_pool,
+ alloc, user) != 0) {
kfree(desc);
pr_warn("%s: Can't allocate buffer %i",
__func__, channel->buffer_count);
@@ -2154,6 +2196,11 @@
*/
tspp_destroy_buffers(channel_id, channel);
channel->buffer_count = 0;
+
+ if (channel->dma_pool) {
+ dma_pool_destroy(channel->dma_pool);
+ channel->dma_pool = NULL;
+ }
return -ENOMEM;
}
@@ -2292,8 +2339,10 @@
*/
if (buffer->read_index == buffer->filled) {
buffer->state = TSPP_BUF_STATE_WAITING;
+
if (tspp_queue_buffer(channel, buffer))
pr_err("tspp: can't submit transfer");
+
channel->locked = channel->read;
channel->read = channel->read->next;
}
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index e25e297..4708096 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -57,6 +57,7 @@
#define INAND_CMD38_ARG_SECERASE 0x80
#define INAND_CMD38_ARG_SECTRIM1 0x81
#define INAND_CMD38_ARG_SECTRIM2 0x88
+#define MMC_BLK_TIMEOUT_MS (30 * 1000) /* 30 sec timeout */
#define MMC_SANITIZE_REQ_TIMEOUT 240000 /* msec */
@@ -122,6 +123,7 @@
struct device_attribute power_ro_lock;
struct device_attribute num_wr_reqs_to_start_packing;
struct device_attribute bkops_check_threshold;
+ struct device_attribute no_pack_for_random;
int area_type;
};
@@ -390,6 +392,55 @@
return count;
}
+static ssize_t
+no_pack_for_random_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
+ int ret;
+
+ ret = snprintf(buf, PAGE_SIZE, "%d\n", md->queue.no_pack_for_random);
+
+ mmc_blk_put(md);
+ return ret;
+}
+
+static ssize_t
+no_pack_for_random_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int value;
+ struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
+ struct mmc_card *card = md->queue.card;
+ int ret = count;
+
+ if (!card) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ sscanf(buf, "%d", &value);
+
+ if (value < 0) {
+ pr_err("%s: value %d is not valid. old value remains = %d",
+ mmc_hostname(card->host), value,
+ md->queue.no_pack_for_random);
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ md->queue.no_pack_for_random = (value > 0) ? true : false;
+
+ pr_debug("%s: no_pack_for_random: new value = %d",
+ mmc_hostname(card->host),
+ md->queue.no_pack_for_random);
+
+exit:
+ mmc_blk_put(md);
+ return ret;
+}
+
static int mmc_blk_open(struct block_device *bdev, fmode_t mode)
{
struct mmc_blk_data *md = mmc_blk_get(bdev->bd_disk);
@@ -527,8 +578,6 @@
struct mmc_request mrq = {NULL};
struct scatterlist sg;
int err;
- int is_rpmb = false;
- u32 status = 0;
/*
* The caller must have CAP_SYS_RAWIO, and must be calling this on the
@@ -548,9 +597,6 @@
goto cmd_done;
}
- if (md->area_type & MMC_BLK_DATA_AREA_RPMB)
- is_rpmb = true;
-
card = md->queue.card;
if (IS_ERR(card)) {
err = PTR_ERR(card);
@@ -611,13 +657,6 @@
goto cmd_rel_host;
}
- if (is_rpmb) {
- err = mmc_set_blockcount(card, data.blocks,
- idata->ic.write_flag & (1 << 31));
- if (err)
- goto cmd_rel_host;
- }
-
mmc_wait_for_req(card->host, &mrq);
if (cmd.error) {
@@ -653,7 +692,171 @@
}
}
- if (is_rpmb) {
+cmd_rel_host:
+ mmc_release_host(card->host);
+
+cmd_done:
+ mmc_blk_put(md);
+ kfree(idata->buf);
+ kfree(idata);
+ return err;
+}
+
+struct mmc_blk_ioc_rpmb_data {
+ struct mmc_blk_ioc_data *data[MMC_IOC_MAX_RPMB_CMD];
+};
+
+static struct mmc_blk_ioc_rpmb_data *mmc_blk_ioctl_rpmb_copy_from_user(
+ struct mmc_ioc_rpmb __user *user)
+{
+ struct mmc_blk_ioc_rpmb_data *idata;
+ int err, i;
+
+ idata = kzalloc(sizeof(*idata), GFP_KERNEL);
+ if (!idata) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ for (i = 0; i < MMC_IOC_MAX_RPMB_CMD; i++) {
+ idata->data[i] = mmc_blk_ioctl_copy_from_user(&(user->cmds[i]));
+ if (IS_ERR(idata->data[i])) {
+ err = PTR_ERR(idata->data[i]);
+ goto copy_err;
+ }
+ }
+
+ return idata;
+
+copy_err:
+ while (--i >= 0) {
+ kfree(idata->data[i]->buf);
+ kfree(idata->data[i]);
+ }
+ kfree(idata);
+out:
+ return ERR_PTR(err);
+}
+
+static int mmc_blk_ioctl_rpmb_cmd(struct block_device *bdev,
+ struct mmc_ioc_rpmb __user *ic_ptr)
+{
+ struct mmc_blk_ioc_rpmb_data *idata;
+ struct mmc_blk_data *md;
+ struct mmc_card *card;
+ struct mmc_command cmd = {0};
+ struct mmc_data data = {0};
+ struct mmc_request mrq = {NULL};
+ struct scatterlist sg;
+ int err = 0, i = 0;
+ u32 status = 0;
+
+ /* The caller must have CAP_SYS_RAWIO */
+ if (!capable(CAP_SYS_RAWIO))
+ return -EPERM;
+
+ md = mmc_blk_get(bdev->bd_disk);
+ /* make sure this is a rpmb partition */
+ if ((!md) || (!(md->area_type & MMC_BLK_DATA_AREA_RPMB))) {
+ err = -EINVAL;
+ goto cmd_done;
+ }
+
+ idata = mmc_blk_ioctl_rpmb_copy_from_user(ic_ptr);
+ if (IS_ERR(idata)) {
+ err = PTR_ERR(idata);
+ goto cmd_done;
+ }
+
+ card = md->queue.card;
+ if (IS_ERR(card)) {
+ err = PTR_ERR(card);
+ goto idata_free;
+ }
+
+ mmc_claim_host(card->host);
+
+ err = mmc_blk_part_switch(card, md);
+ if (err)
+ goto cmd_rel_host;
+
+ for (i = 0; i < MMC_IOC_MAX_RPMB_CMD; i++) {
+ struct mmc_blk_ioc_data *curr_data;
+ struct mmc_ioc_cmd *curr_cmd;
+
+ curr_data = idata->data[i];
+ curr_cmd = &curr_data->ic;
+ if (!curr_cmd->opcode)
+ break;
+
+ cmd.opcode = curr_cmd->opcode;
+ cmd.arg = curr_cmd->arg;
+ cmd.flags = curr_cmd->flags;
+
+ if (curr_data->buf_bytes) {
+ data.sg = &sg;
+ data.sg_len = 1;
+ data.blksz = curr_cmd->blksz;
+ data.blocks = curr_cmd->blocks;
+
+ sg_init_one(data.sg, curr_data->buf,
+ curr_data->buf_bytes);
+
+ if (curr_cmd->write_flag)
+ data.flags = MMC_DATA_WRITE;
+ else
+ data.flags = MMC_DATA_READ;
+
+ /* data.flags must already be set before doing this. */
+ mmc_set_data_timeout(&data, card);
+
+ /*
+ * Allow overriding the timeout_ns for empirical tuning.
+ */
+ if (curr_cmd->data_timeout_ns)
+ data.timeout_ns = curr_cmd->data_timeout_ns;
+
+ mrq.data = &data;
+ }
+
+ mrq.cmd = &cmd;
+
+ err = mmc_set_blockcount(card, data.blocks,
+ curr_cmd->write_flag & (1 << 31));
+ if (err)
+ goto cmd_rel_host;
+
+ mmc_wait_for_req(card->host, &mrq);
+
+ if (cmd.error) {
+ dev_err(mmc_dev(card->host), "%s: cmd error %d\n",
+ __func__, cmd.error);
+ err = cmd.error;
+ goto cmd_rel_host;
+ }
+ if (data.error) {
+ dev_err(mmc_dev(card->host), "%s: data error %d\n",
+ __func__, data.error);
+ err = data.error;
+ goto cmd_rel_host;
+ }
+
+ if (copy_to_user(&(ic_ptr->cmds[i].response), cmd.resp,
+ sizeof(cmd.resp))) {
+ err = -EFAULT;
+ goto cmd_rel_host;
+ }
+
+ if (!curr_cmd->write_flag) {
+ if (copy_to_user((void __user *)(unsigned long)
+ curr_cmd->data_ptr,
+ curr_data->buf,
+ curr_data->buf_bytes)) {
+ err = -EFAULT;
+ goto cmd_rel_host;
+ }
+ }
+
/*
* Ensure RPMB command has completed by polling CMD13
* "Send Status".
@@ -668,10 +871,15 @@
cmd_rel_host:
mmc_release_host(card->host);
+idata_free:
+ for (i = 0; i < MMC_IOC_MAX_RPMB_CMD; i++) {
+ kfree(idata->data[i]->buf);
+ kfree(idata->data[i]);
+ }
+ kfree(idata);
+
cmd_done:
mmc_blk_put(md);
- kfree(idata->buf);
- kfree(idata);
return err;
}
@@ -681,6 +889,9 @@
int ret = -EINVAL;
if (cmd == MMC_IOC_CMD)
ret = mmc_blk_ioctl_cmd(bdev, (struct mmc_ioc_cmd __user *)arg);
+ if (cmd == MMC_IOC_RPMB_CMD)
+ ret = mmc_blk_ioctl_rpmb_cmd(bdev,
+ (struct mmc_ioc_rpmb __user *)arg);
return ret;
}
@@ -709,7 +920,8 @@
int ret;
struct mmc_blk_data *main_md = mmc_get_drvdata(card);
- if (main_md->part_curr == md->part_type)
+ if ((main_md->part_curr == md->part_type) &&
+ (card->part_curr == md->part_type))
return 0;
if (mmc_card_mmc(card)) {
@@ -725,6 +937,7 @@
return ret;
card->ext_csd.part_config = part_config;
+ card->part_curr = md->part_type;
}
main_md->part_curr = md->part_type;
@@ -1250,6 +1463,9 @@
*/
if (!mmc_host_is_spi(card->host) && rq_data_dir(req) != READ) {
u32 status;
+ unsigned long timeout;
+
+ timeout = jiffies + msecs_to_jiffies(MMC_BLK_TIMEOUT_MS);
do {
int err = get_card_status(card, &status, 5);
if (err) {
@@ -1257,6 +1473,17 @@
req->rq_disk->disk_name, err);
return MMC_BLK_CMD_ERR;
}
+
+ /* Timeout if the device never becomes ready for data
+ * and never leaves the program state.
+ */
+ if (time_after(jiffies, timeout)) {
+ pr_err("%s: Card stuck in programming state!"\
+ " %s %s\n", mmc_hostname(card->host),
+ req->rq_disk->disk_name, __func__);
+
+ return MMC_BLK_CMD_ERR;
+ }
/*
* Some cards mishandle the status bits,
* so make sure to check both the busy
@@ -1574,39 +1801,6 @@
}
EXPORT_SYMBOL(mmc_blk_init_packed_statistics);
-/**
- * mmc_blk_init_async_event_statistics() - Init async event
- * statistics data
- * @card: The mmc_card in which the async_event_stats
- * struct is a member
- *
- * Initiate counters for the new request feature, and mark the
- * statistics as enabled.
- */
-void mmc_blk_init_async_event_statistics(struct mmc_card *card)
-{
- if (!card)
- return;
-
- /* init async events tests stats */
- memset(&card->async_event_stats,
- sizeof(struct mmc_async_event_stats), 0);
- card->async_event_stats.null_fetched = 0;
- card->async_event_stats.wakeup_new = 0;
- card->async_event_stats.new_request_flag = 0;
- card->async_event_stats.q_no_waiting = 0;
- card->async_event_stats.enabled = true;
- card->async_event_stats.no_mmc_request_action = 0;
- card->async_event_stats.wakeup_mq_thread = 0;
- card->async_event_stats.fetch_due_to_new_req = 0;
- card->async_event_stats.returned_new_req = 0;
- card->async_event_stats.done_flag = 0;
- card->async_event_stats.cmd_retry = 0;
- card->async_event_stats.done_when_new_req_event_on = 0;
- card->async_event_stats.new_req_when_new_marked = 0;
-}
-EXPORT_SYMBOL(mmc_blk_init_async_event_statistics);
-
static u8 mmc_blk_prep_packed_list(struct mmc_queue *mq, struct request *req)
{
struct request_queue *q = mq->queue;
@@ -1619,12 +1813,7 @@
u8 put_back = 0;
u8 max_packed_rw = 0;
u8 reqs = 0;
- struct mmc_wr_pack_stats *stats;
-
- if (!card)
- goto no_packed;
-
- stats = &card->wr_pack_stats;
+ struct mmc_wr_pack_stats *stats = &card->wr_pack_stats;
mmc_blk_clear_packed(mq->mqrq_cur);
@@ -1719,6 +1908,15 @@
break;
}
+ if (mq->no_pack_for_random) {
+ if ((blk_rq_pos(cur) + blk_rq_sectors(cur)) !=
+ blk_rq_pos(next)) {
+ MMC_BLK_UPDATE_STOP_REASON(stats, RANDOM);
+ put_back = 1;
+ break;
+ }
+ }
+
if (rq_data_dir(next) == WRITE) {
mq->num_of_potential_packed_wr_reqs++;
if (card->ext_csd.bkops_en)
@@ -1951,7 +2149,6 @@
struct mmc_async_req *areq;
const u8 packed_num = 2;
u8 reqs = 0;
- struct mmc_async_event_stats *stats = &card->async_event_stats;
if (!rqc && !mq->mqrq_prev->req)
return 0;
@@ -1974,12 +2171,8 @@
areq = NULL;
areq = mmc_start_req(card->host, areq, (int *) &status);
if (!areq) {
- if (status == MMC_BLK_NEW_REQUEST && stats) {
- if (stats->enabled)
- stats->returned_new_req++;
-
+ if (status == MMC_BLK_NEW_REQUEST)
mq->flags |= MMC_QUEUE_NEW_REQUEST;
- }
return 0;
}
@@ -1990,8 +2183,6 @@
mmc_queue_bounce_post(mq_rq);
switch (status) {
- case MMC_BLK_NEW_REQUEST:
- BUG(); /* should never get here */
case MMC_BLK_SUCCESS:
case MMC_BLK_PARTIAL:
/*
@@ -2064,6 +2255,11 @@
break;
case MMC_BLK_NOMEDIUM:
goto cmd_abort;
+ default:
+ pr_err("%s:%s: Unhandled return value (%d)",
+ req->rq_disk->disk_name,
+ __func__, status);
+ goto cmd_abort;
}
if (ret) {
@@ -2119,6 +2315,8 @@
int ret;
struct mmc_blk_data *md = mq->data;
struct mmc_card *card = md->queue.card;
+ struct mmc_host *host = card->host;
+ unsigned long flags;
#ifdef CONFIG_MMC_BLOCK_DEFERRED_RESUME
if (mmc_bus_needs_resume(card->host)) {
@@ -2166,6 +2364,11 @@
mmc_blk_issue_rw_rq(mq, NULL);
ret = mmc_blk_issue_flush(mq, req);
} else {
+ if (!req && host->areq) {
+ spin_lock_irqsave(&host->context_info.lock, flags);
+ host->context_info.is_waiting_last_req = true;
+ spin_unlock_irqrestore(&host->context_info.lock, flags);
+ }
ret = mmc_blk_issue_rw_rq(mq, req);
}
@@ -2481,8 +2684,21 @@
if (ret)
goto bkops_check_threshold_fails;
+ md->no_pack_for_random.show = no_pack_for_random_show;
+ md->no_pack_for_random.store = no_pack_for_random_store;
+ sysfs_attr_init(&md->no_pack_for_random.attr);
+ md->no_pack_for_random.attr.name = "no_pack_for_random";
+ md->no_pack_for_random.attr.mode = S_IRUGO | S_IWUSR;
+ ret = device_create_file(disk_to_dev(md->disk),
+ &md->no_pack_for_random);
+ if (ret)
+ goto no_pack_for_random_fails;
+
return ret;
+no_pack_for_random_fails:
+ device_remove_file(disk_to_dev(md->disk),
+ &md->bkops_check_threshold);
bkops_check_threshold_fails:
device_remove_file(disk_to_dev(md->disk),
&md->num_wr_reqs_to_start_packing);
diff --git a/drivers/mmc/card/mmc_block_test.c b/drivers/mmc/card/mmc_block_test.c
index 4a21fd4..7a4d19e 100644
--- a/drivers/mmc/card/mmc_block_test.c
+++ b/drivers/mmc/card/mmc_block_test.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 @@
#define MODULE_NAME "mmc_block_test"
#define TEST_MAX_SECTOR_RANGE (600*1024*1024) /* 600 MB */
-#define TEST_MAX_BIOS_PER_REQ 120
+#define TEST_MAX_BIOS_PER_REQ 128
#define CMD23_PACKED_BIT (1 << 30)
#define LARGE_PRIME_1 1103515367
#define LARGE_PRIME_2 35757
@@ -37,28 +37,30 @@
#define SECTOR_SIZE 512
#define NUM_OF_SECTORS_PER_BIO ((BIO_U32_SIZE * 4) / SECTOR_SIZE)
#define BIO_TO_SECTOR(x) (x * NUM_OF_SECTORS_PER_BIO)
-/* the desired long test size to be written or read */
-#define LONG_TEST_MAX_NUM_BYTES (50*1024*1024) /* 50MB */
+/* the desired long test size to be read */
+#define LONG_READ_TEST_MAX_NUM_BYTES (50*1024*1024) /* 50MB */
+/* the minimum amount of requests that will be created */
+#define LONG_WRITE_TEST_MIN_NUM_REQS 200 /* 100MB */
/* request queue limitation is 128 requests, and we leave 10 spare requests */
#define TEST_MAX_REQUESTS 118
-#define LONG_TEST_MAX_NUM_REQS (LONG_TEST_MAX_NUM_BYTES / \
+#define LONG_READ_TEST_MAX_NUM_REQS (LONG_READ_TEST_MAX_NUM_BYTES / \
(TEST_MAX_BIOS_PER_REQ * sizeof(int) * BIO_U32_SIZE))
/* this doesn't allow the test requests num to be greater than the maximum */
-#define LONG_TEST_ACTUAL_NUM_REQS \
- ((TEST_MAX_REQUESTS < LONG_TEST_MAX_NUM_REQS) ? \
- TEST_MAX_REQUESTS : LONG_TEST_MAX_NUM_REQS)
+#define LONG_READ_TEST_ACTUAL_NUM_REQS \
+ ((TEST_MAX_REQUESTS < LONG_READ_TEST_MAX_NUM_REQS) ? \
+ TEST_MAX_REQUESTS : LONG_READ_TEST_MAX_NUM_REQS)
#define MB_MSEC_RATIO_APPROXIMATION ((1024 * 1024) / 1000)
/* actual number of bytes in test */
-#define LONG_TEST_ACTUAL_BYTE_NUM (LONG_TEST_ACTUAL_NUM_REQS * \
+#define LONG_READ_NUM_BYTES (LONG_READ_TEST_ACTUAL_NUM_REQS * \
(TEST_MAX_BIOS_PER_REQ * sizeof(int) * BIO_U32_SIZE))
/* actual number of MiB in test multiplied by 10, for single digit precision*/
-#define LONG_TEST_ACTUAL_MB_NUM_X_10 ((LONG_TEST_ACTUAL_BYTE_NUM * 10) / \
- (1024 * 1024))
+#define BYTE_TO_MB_x_10(x) ((x * 10) / (1024 * 1024))
/* extract integer value */
-#define LONG_TEST_SIZE_INTEGER (LONG_TEST_ACTUAL_MB_NUM_X_10 / 10)
+#define LONG_TEST_SIZE_INTEGER(x) (BYTE_TO_MB_x_10(x) / 10)
/* and calculate the MiB value fraction */
-#define LONG_TEST_SIZE_FRACTION (LONG_TEST_ACTUAL_MB_NUM_X_10 - \
- (LONG_TEST_SIZE_INTEGER * 10))
+#define LONG_TEST_SIZE_FRACTION(x) (BYTE_TO_MB_x_10(x) - \
+ (LONG_TEST_SIZE_INTEGER(x) * 10))
+#define LONG_WRITE_TEST_SLEEP_TIME_MS 5
#define test_pr_debug(fmt, args...) pr_debug("%s: "fmt"\n", MODULE_NAME, args)
#define test_pr_info(fmt, args...) pr_info("%s: "fmt"\n", MODULE_NAME, args)
@@ -222,8 +224,8 @@
enum bkops_test_stages bkops_stage;
/* A wait queue for BKOPs tests */
wait_queue_head_t bkops_wait_q;
-
- unsigned int completed_req_count;
+ /* A counter for the number of test requests completed */
+ unsigned int completed_req_count;
};
static struct mmc_block_test_data *mbtd;
@@ -285,50 +287,6 @@
spin_unlock(&card->wr_pack_stats.lock);
}
-/**
- * mmc_print_async_event_stats() - Print async event statistics
- * @card: The mmc_card in which the async_event_stats
- * struct is a member
- */
-void mmc_print_async_event_stats(struct mmc_card *card)
-{
- struct mmc_async_event_stats *s;
-
- if (!card)
- return;
-
- s = &card->async_event_stats;
- if (!s)
- return;
-
- pr_info("%s: new notification & req statistics:\n",
- mmc_hostname(card->host));
- pr_info("%s: done_flag:%d", mmc_hostname(card->host),
- s->done_flag);
- pr_info("%s: cmd_retry:%d", mmc_hostname(card->host),
- s->cmd_retry);
- pr_info("%s: NULL fetched:%d", mmc_hostname(card->host),
- s->null_fetched);
- pr_info("%s: wake up new:%d", mmc_hostname(card->host),
- s->wakeup_new);
- pr_info("%s: new_request_flag:%d", mmc_hostname(card->host),
- s->new_request_flag);
- pr_info("%s: no waiting:%d\n", mmc_hostname(card->host),
- s->q_no_waiting);
- pr_info("%s: no_mmc_request_action:%d", mmc_hostname(card->host),
- s->no_mmc_request_action);
- pr_info("%s: wakeup_mq_thread:%d", mmc_hostname(card->host),
- s->wakeup_mq_thread);
- pr_info("%s: fetch_due_to_new_req:%d", mmc_hostname(card->host),
- s->fetch_due_to_new_req);
- pr_info("%s: returned_new_req:%d", mmc_hostname(card->host),
- s->returned_new_req);
- pr_info("%s: done_when_new_req_event_on:%d", mmc_hostname(card->host),
- s->done_when_new_req_event_on);
- pr_info("%s: new_req_when_new_marked:%d", mmc_hostname(card->host),
- s->new_req_when_new_marked);
-}
-
/*
* A callback assigned to the packed_test_fn field.
* Called from block layer in mmc_blk_packed_hdr_wrq_prep.
@@ -1024,8 +982,6 @@
__func__, mbtd->random_test_seed);
}
- mmc_blk_init_packed_statistics(mq->card);
-
ret = prepare_request_add_write_reqs(td, num_requests, is_err_expected,
is_random);
if (ret)
@@ -1121,8 +1077,6 @@
__func__, mbtd->random_test_seed);
}
- mmc_blk_init_packed_statistics(mq->card);
-
if (td->test_info.testcase ==
TEST_PACK_MIX_NO_PACKED_PACKED_NO_PACKED) {
temp_num_req = num_requests;
@@ -1277,8 +1231,6 @@
max_packed_reqs = mq->card->ext_csd.max_packed_writes;
- mmc_blk_init_packed_statistics(mq->card);
-
for (i = 1; i <= num_requests; i++) {
if (i > (num_requests / 2))
is_err_expected = 1;
@@ -1388,13 +1340,12 @@
return num_requests;
}
-static int prepare_long_test_requests(struct test_data *td)
+static int prepare_long_read_test_requests(struct test_data *td)
{
int ret;
int start_sec;
int j;
- int test_direction;
if (td)
start_sec = td->start_sector;
@@ -1403,23 +1354,18 @@
return -EINVAL;
}
- if (td->test_info.testcase == TEST_LONG_SEQUENTIAL_WRITE)
- test_direction = WRITE;
- else
- test_direction = READ;
+ test_pr_info("%s: Adding %d read requests, first req_id=%d", __func__,
+ LONG_READ_TEST_ACTUAL_NUM_REQS, td->wr_rd_next_req_id);
- test_pr_info("%s: Adding %d write requests, first req_id=%d", __func__,
- LONG_TEST_ACTUAL_NUM_REQS, td->wr_rd_next_req_id);
+ for (j = 0; j < LONG_READ_TEST_ACTUAL_NUM_REQS; j++) {
- for (j = 0; j < LONG_TEST_ACTUAL_NUM_REQS; j++) {
-
- ret = test_iosched_add_wr_rd_test_req(0, test_direction,
+ ret = test_iosched_add_wr_rd_test_req(0, READ,
start_sec,
TEST_MAX_BIOS_PER_REQ,
TEST_NO_PATTERN, NULL);
if (ret) {
- test_pr_err("%s: failed to add a bio request",
- __func__);
+ test_pr_err("%s: failed to add a read request, err = %d"
+ , __func__, ret);
return ret;
}
@@ -1539,10 +1485,8 @@
test_packed_trigger, is_random);
break;
case TEST_LONG_SEQUENTIAL_WRITE:
- ret = prepare_long_test_requests(td);
- break;
case TEST_LONG_SEQUENTIAL_READ:
- ret = prepare_long_test_requests(td);
+ ret = prepare_long_read_test_requests(td);
break;
default:
test_pr_info("%s: Invalid test case...", __func__);
@@ -1552,6 +1496,44 @@
return ret;
}
+static int run_packed_test(struct test_data *td)
+{
+ struct mmc_queue *mq;
+ struct request_queue *req_q;
+
+ if (!td) {
+ pr_err("%s: NULL td", __func__);
+ return -EINVAL;
+ }
+
+ req_q = td->req_q;
+
+ if (!req_q) {
+ pr_err("%s: NULL request queue", __func__);
+ return -EINVAL;
+ }
+
+ mq = req_q->queuedata;
+ if (!mq) {
+ test_pr_err("%s: NULL mq", __func__);
+ return -EINVAL;
+ }
+ mmc_blk_init_packed_statistics(mq->card);
+
+ if (td->test_info.testcase != TEST_PACK_MIX_PACKED_NO_PACKED_PACKED) {
+ /*
+ * Verify that the packing is disabled before starting the
+ * test
+ */
+ mq->wr_packing_enabled = false;
+ mq->num_of_potential_packed_wr_reqs = 0;
+ }
+
+ __blk_run_queue(td->req_q);
+
+ return 0;
+}
+
/*
* An implementation for the post_test_fn in the test_info data structure.
* In our case we just reset the function pointers in the mmc_queue in order for
@@ -2097,9 +2079,6 @@
if (!mq || !mq->card)
goto exit;
- /* disable async_event test stats */
- mq->card->async_event_stats.enabled = false;
- mmc_print_async_event_stats(mq->card);
test_pr_info("Completed %d requests",
mbtd->completed_req_count);
@@ -2153,14 +2132,12 @@
struct mmc_queue *mq = (struct mmc_queue *)q->queuedata;
mmc_blk_init_packed_statistics(mq->card);
- mmc_blk_init_async_event_statistics(mq->card);
-
mbtd->completed_req_count = 0;
return 0;
}
-static int test_new_req_notification(struct test_data *ptd)
+static int run_new_req(struct test_data *ptd)
{
int ret = 0;
int i;
@@ -2230,18 +2207,6 @@
return ret;
}
-static int run_new_req(struct test_data *td)
-{
- int ret = 0;
- struct request_queue *q = td->req_q;
- struct mmc_queue *mq = (struct mmc_queue *)q->queuedata;
-
- mmc_blk_init_async_event_statistics(mq->card);
- ret = test_new_req_notification(td);
-
- return ret;
-}
-
static bool message_repeat;
static int test_open(struct inode *inode, struct file *file)
{
@@ -2282,6 +2247,7 @@
mbtd->test_info.data = mbtd;
mbtd->test_info.prepare_test_fn = prepare_test;
+ mbtd->test_info.run_test_fn = run_packed_test;
mbtd->test_info.check_test_result_fn = check_wr_packing_statistics;
mbtd->test_info.get_test_case_str_fn = get_test_case_str;
mbtd->test_info.post_test_fn = post_test;
@@ -2380,6 +2346,7 @@
mbtd->test_info.data = mbtd;
mbtd->test_info.prepare_test_fn = prepare_test;
+ mbtd->test_info.run_test_fn = run_packed_test;
mbtd->test_info.check_test_result_fn = check_wr_packing_statistics;
mbtd->test_info.get_test_case_str_fn = get_test_case_str;
mbtd->test_info.post_test_fn = post_test;
@@ -2479,6 +2446,7 @@
mbtd->test_info.data = mbtd;
mbtd->test_info.prepare_test_fn = prepare_test;
+ mbtd->test_info.run_test_fn = run_packed_test;
mbtd->test_info.check_test_result_fn = check_wr_packing_statistics;
mbtd->test_info.get_test_case_str_fn = get_test_case_str;
mbtd->test_info.post_test_fn = post_test;
@@ -2591,6 +2559,7 @@
mbtd->test_info.data = mbtd;
mbtd->test_info.prepare_test_fn = prepare_test;
+ mbtd->test_info.run_test_fn = run_packed_test;
mbtd->test_info.check_test_result_fn = check_wr_packing_statistics;
mbtd->test_info.get_test_case_str_fn = get_test_case_str;
@@ -2792,7 +2761,7 @@
int ret = 0;
int i = 0;
int number = -1;
- unsigned int mtime, integer, fraction;
+ unsigned long mtime, integer, fraction;
test_pr_info("%s: -- Long Sequential Read TEST --", __func__);
@@ -2820,21 +2789,22 @@
mtime = jiffies_to_msecs(mbtd->test_info.test_duration);
- test_pr_info("%s: time is %u msec, size is %u.%u MiB",
- __func__, mtime, LONG_TEST_SIZE_INTEGER,
- LONG_TEST_SIZE_FRACTION);
+ test_pr_info("%s: time is %lu msec, size is %u.%u MiB",
+ __func__, mtime,
+ LONG_TEST_SIZE_INTEGER(LONG_READ_NUM_BYTES),
+ LONG_TEST_SIZE_FRACTION(LONG_READ_NUM_BYTES));
/* we first multiply in order not to lose precision */
mtime *= MB_MSEC_RATIO_APPROXIMATION;
/* divide values to get a MiB/sec integer value with one
digit of precision. Multiply by 10 for one digit precision
*/
- fraction = integer = (LONG_TEST_ACTUAL_BYTE_NUM * 10) / mtime;
+ fraction = integer = (LONG_READ_NUM_BYTES * 10) / mtime;
integer /= 10;
/* and calculate the MiB value fraction */
fraction -= integer * 10;
- test_pr_info("%s: Throughput: %u.%u MiB/sec\n"
+ test_pr_info("%s: Throughput: %lu.%lu MiB/sec\n"
, __func__, integer, fraction);
/* Allow FS requests to be dispatched */
@@ -2873,6 +2843,72 @@
.read = long_sequential_read_test_read,
};
+static void long_seq_write_free_end_io_fn(struct request *rq, int err)
+{
+ struct test_request *test_rq =
+ (struct test_request *)rq->elv.priv[0];
+ struct test_data *ptd = test_get_test_data();
+
+ BUG_ON(!test_rq);
+
+ spin_lock_irq(&ptd->lock);
+ list_del_init(&test_rq->queuelist);
+ ptd->dispatched_count--;
+ __blk_put_request(ptd->req_q, test_rq->rq);
+ spin_unlock_irq(&ptd->lock);
+
+ kfree(test_rq->bios_buffer);
+ kfree(test_rq);
+ mbtd->completed_req_count++;
+
+ check_test_completion();
+}
+
+static int run_long_seq_write(struct test_data *td)
+{
+ int ret = 0;
+ int i;
+
+ td->test_count = 0;
+ mbtd->completed_req_count = 0;
+
+ test_pr_info("%s: Adding at least %d write requests, first req_id=%d",
+ __func__, LONG_WRITE_TEST_MIN_NUM_REQS,
+ td->wr_rd_next_req_id);
+
+ do {
+ for (i = 0; i < TEST_MAX_REQUESTS; i++) {
+ /*
+ * since our requests come from a pool containing 128
+ * requests, we don't want to exhaust this quantity,
+ * therefore we add up to TEST_MAX_REQUESTS (which
+ * includes a safety margin) and then call the mmc layer
+ * to fetch them
+ */
+ if (td->test_count > TEST_MAX_REQUESTS)
+ break;
+
+ ret = test_iosched_add_wr_rd_test_req(0, WRITE,
+ td->start_sector, TEST_MAX_BIOS_PER_REQ,
+ TEST_PATTERN_5A,
+ long_seq_write_free_end_io_fn);
+ if (ret) {
+ test_pr_err("%s: failed to create write request"
+ , __func__);
+ break;
+ }
+ }
+
+ __blk_run_queue(td->req_q);
+
+ } while (mbtd->completed_req_count < LONG_WRITE_TEST_MIN_NUM_REQS);
+
+ test_pr_info("%s: completed %d requests", __func__,
+ mbtd->completed_req_count);
+
+ return ret;
+}
+
static ssize_t long_sequential_write_test_write(struct file *file,
const char __user *buf,
size_t count,
@@ -2881,7 +2917,7 @@
int ret = 0;
int i = 0;
int number = -1;
- unsigned int mtime, integer, fraction;
+ unsigned long mtime, integer, fraction, byte_count;
test_pr_info("%s: -- Long Sequential Write TEST --", __func__);
@@ -2894,13 +2930,16 @@
mbtd->test_group = TEST_GENERAL_GROUP;
mbtd->test_info.data = mbtd;
- mbtd->test_info.prepare_test_fn = prepare_test;
mbtd->test_info.get_test_case_str_fn = get_test_case_str;
+ mbtd->test_info.run_test_fn = run_long_seq_write;
for (i = 0 ; i < number ; ++i) {
test_pr_info("%s: Cycle # %d / %d", __func__, i+1, number);
test_pr_info("%s: ====================", __func__);
+ integer = 0;
+ fraction = 0;
+ mbtd->test_info.test_byte_count = 0;
mbtd->test_info.testcase = TEST_LONG_SEQUENTIAL_WRITE;
mbtd->is_random = NON_RANDOM_TEST;
ret = test_iosched_start_test(&mbtd->test_info);
@@ -2908,22 +2947,23 @@
break;
mtime = jiffies_to_msecs(mbtd->test_info.test_duration);
+ byte_count = mbtd->test_info.test_byte_count;
- test_pr_info("%s: time is %u msec, size is %u.%u MiB",
- __func__, mtime, LONG_TEST_SIZE_INTEGER,
- LONG_TEST_SIZE_FRACTION);
+ test_pr_info("%s: time is %lu msec, size is %lu.%lu MiB",
+ __func__, mtime, LONG_TEST_SIZE_INTEGER(byte_count),
+ LONG_TEST_SIZE_FRACTION(byte_count));
/* we first multiply in order not to lose precision */
mtime *= MB_MSEC_RATIO_APPROXIMATION;
/* divide values to get a MiB/sec integer value with one
digit of precision
*/
- fraction = integer = (LONG_TEST_ACTUAL_BYTE_NUM * 10) / mtime;
+ fraction = integer = (byte_count * 10) / mtime;
integer /= 10;
/* and calculate the MiB value fraction */
fraction -= integer * 10;
- test_pr_info("%s: Throughput: %u.%u MiB/sec\n",
+ test_pr_info("%s: Throughput: %lu.%lu MiB/sec\n",
__func__, integer, fraction);
/* Allow FS requests to be dispatched */
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index ad40660..c4b2d16 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -59,33 +59,18 @@
struct request_queue *q = mq->queue;
struct request *req;
struct mmc_card *card = mq->card;
- struct mmc_async_event_stats *stats;
- struct mmc_queue_req *tmp;
-
- if (!card)
- return 0;
-
- stats = &mq->card->async_event_stats;
current->flags |= PF_MEMALLOC;
down(&mq->thread_sem);
do {
-
+ struct mmc_queue_req *tmp;
req = NULL; /* Must be set to NULL at each iteration */
spin_lock_irq(q->queue_lock);
set_current_state(TASK_INTERRUPTIBLE);
req = blk_fetch_request(q);
mq->mqrq_cur->req = req;
- if (!req && mq->mqrq_prev->req &&
- !(mq->mqrq_prev->req->cmd_flags & REQ_SANITIZE) &&
- !(mq->mqrq_prev->req->cmd_flags & REQ_FLUSH) &&
- !(mq->mqrq_prev->req->cmd_flags & REQ_DISCARD)) {
- card->host->context_info.is_waiting_last_req = true;
- if (stats && stats->enabled)
- stats->null_fetched++;
- }
spin_unlock_irq(q->queue_lock);
if (req || mq->mqrq_prev->req) {
@@ -93,8 +78,6 @@
mq->issue_fn(mq, req);
if (mq->flags & MMC_QUEUE_NEW_REQUEST) {
mq->flags &= ~MMC_QUEUE_NEW_REQUEST;
- if (stats && stats->enabled)
- stats->fetch_due_to_new_req++;
continue; /* fetch again */
}
@@ -132,7 +115,6 @@
static void mmc_request(struct request_queue *q)
{
struct mmc_queue *mq = q->queuedata;
- struct mmc_async_event_stats *stats;
struct request *req;
unsigned long flags;
struct mmc_context_info *cntx;
@@ -144,39 +126,22 @@
}
return;
}
- if (mq->card) {
- cntx = &mq->card->host->context_info;
- stats = &mq->card->async_event_stats;
- } else
- return;
cntx = &mq->card->host->context_info;
- stats = &mq->card->async_event_stats;
if (!mq->mqrq_cur->req && mq->mqrq_prev->req) {
/*
* New MMC request arrived when MMC thread may be
* blocked on the previous request to be complete
* with no current request fetched
*/
-
spin_lock_irqsave(&cntx->lock, flags);
if (cntx->is_waiting_last_req) {
- if (stats && stats->enabled)
- stats->wakeup_new++;
- if (cntx->is_new_req)
- if (stats->enabled)
- stats->new_req_when_new_marked++;
cntx->is_new_req = true;
wake_up_interruptible(&cntx->wait);
- } else if (stats->enabled)
- stats->q_no_waiting++;
+ }
spin_unlock_irqrestore(&cntx->lock, flags);
- } else if (!mq->mqrq_cur->req && !mq->mqrq_prev->req) {
+ } else if (!mq->mqrq_cur->req && !mq->mqrq_prev->req)
wake_up_process(mq->thread);
- if (stats->enabled)
- stats->wakeup_mq_thread++;
- } else if (stats->enabled)
- stats->no_mmc_request_action++;
}
static struct scatterlist *mmc_alloc_sg(int sg_len, int *err)
diff --git a/drivers/mmc/card/queue.h b/drivers/mmc/card/queue.h
index 0a72372..119b0c7 100644
--- a/drivers/mmc/card/queue.h
+++ b/drivers/mmc/card/queue.h
@@ -51,6 +51,7 @@
bool wr_packing_enabled;
int num_of_potential_packed_wr_reqs;
int num_wr_reqs_to_start_packing;
+ bool no_pack_for_random;
int (*err_check_fn) (struct mmc_card *, struct mmc_async_req *);
void (*packed_test_fn) (struct request_queue *, struct mmc_queue_req *);
};
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index b308441..c1de8e8 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -47,6 +47,9 @@
static void mmc_clk_scaling(struct mmc_host *host, bool from_wq);
+/* If the device is not responding */
+#define MMC_CORE_TIMEOUT_MS (10 * 60 * 1000) /* 10 minute timeout */
+
/*
* Background operations can take a long time, depending on the housekeeping
* operations the card has to perform.
@@ -560,6 +563,7 @@
mmc_start_bkops(card, false);
}
EXPORT_SYMBOL(mmc_start_idle_time_bkops);
+
/*
* mmc_wait_data_done() - done callback for data request
* @mrq: done data request
@@ -623,13 +627,13 @@
* Returns enum mmc_blk_status after checking errors.
*/
static int mmc_wait_for_data_req_done(struct mmc_host *host,
- struct mmc_request *mrq)
+ struct mmc_request *mrq,
+ struct mmc_async_req *next_req)
{
struct mmc_command *cmd;
struct mmc_context_info *context_info = &host->context_info;
int err;
unsigned long flags;
- struct mmc_async_event_stats *stats = &host->card->async_event_stats;
while (1) {
wait_io_event_interruptible(context_info->wait,
@@ -642,18 +646,13 @@
context_info->is_done_rcv = false;
context_info->is_new_req = false;
cmd = mrq->cmd;
- if (stats->enabled) {
- stats->done_flag++;
- if (context_info->is_new_req)
- stats->done_when_new_req_event_on++;
- }
if (!cmd->error || !cmd->retries ||
mmc_card_removed(host->card)) {
err = host->areq->err_check(host->card,
host->areq);
break; /* return err */
} else {
- pr_info("%s: req failed (CMD%u):%d, retrying\n",
+ pr_info("%s: req failed (CMD%u): %d, retrying...\n",
mmc_hostname(host),
cmd->opcode, cmd->error);
cmd->retries--;
@@ -663,10 +662,10 @@
}
} else if (context_info->is_new_req) {
context_info->is_new_req = false;
- if (stats->enabled)
- stats->new_request_flag++;
- err = MMC_BLK_NEW_REQUEST;
- break; /* return err */
+ if (!next_req) {
+ err = MMC_BLK_NEW_REQUEST;
+ break; /* return err */
+ }
}
} /* while */
return err;
@@ -779,13 +778,9 @@
mmc_pre_req(host, areq->mrq, !host->areq);
if (host->areq) {
- err = mmc_wait_for_data_req_done(host, host->areq->mrq);
+ err = mmc_wait_for_data_req_done(host, host->areq->mrq,
+ areq);
if (err == MMC_BLK_NEW_REQUEST) {
- if (areq) {
- pr_err("%s: new request while areq = %p",
- mmc_hostname(host), areq);
- BUG_ON(1);
- }
if (error)
*error = err;
/*
@@ -855,6 +850,7 @@
{
int err;
u32 status;
+ unsigned long prg_wait;
BUG_ON(!card);
@@ -870,30 +866,39 @@
goto out;
}
- /*
- * If the card status is in PRG-state, we can send the HPI command.
- */
- if (R1_CURRENT_STATE(status) == R1_STATE_PRG) {
- do {
- /*
- * We don't know when the HPI command will finish
- * processing, so we need to resend HPI until out
- * of prg-state, and keep checking the card status
- * with SEND_STATUS. If a timeout error occurs when
- * sending the HPI command, we are already out of
- * prg-state.
- */
- err = mmc_send_hpi_cmd(card, &status);
- if (err)
- pr_debug("%s: abort HPI (%d error)\n",
- mmc_hostname(card->host), err);
+ switch (R1_CURRENT_STATE(status)) {
+ case R1_STATE_IDLE:
+ case R1_STATE_READY:
+ case R1_STATE_STBY:
+ case R1_STATE_TRAN:
+ /*
+ * In idle and transfer states, HPI is not needed and the caller
+ * can issue the next intended command immediately
+ */
+ goto out;
+ case R1_STATE_PRG:
+ break;
+ default:
+ /* In all other states, it's illegal to issue HPI */
+ pr_debug("%s: HPI cannot be sent. Card state=%d\n",
+ mmc_hostname(card->host), R1_CURRENT_STATE(status));
+ err = -EINVAL;
+ goto out;
+ }
- err = mmc_send_status(card, &status);
- if (err)
- break;
- } while (R1_CURRENT_STATE(status) == R1_STATE_PRG);
- } else
- pr_debug("%s: Left prg-state\n", mmc_hostname(card->host));
+ err = mmc_send_hpi_cmd(card, &status);
+ if (err)
+ goto out;
+
+ prg_wait = jiffies + msecs_to_jiffies(card->ext_csd.out_of_int_time);
+ do {
+ err = mmc_send_status(card, &status);
+
+ if (!err && R1_CURRENT_STATE(status) == R1_STATE_TRAN)
+ break;
+ if (time_after(jiffies, prg_wait))
+ err = -ETIMEDOUT;
+ } while (!err);
out:
mmc_release_host(card->host);
@@ -1863,7 +1868,6 @@
#endif
host->detect_change = 1;
- wake_lock(&host->detect_wake_lock);
mmc_schedule_delayed_work(&host->detect, delay);
}
@@ -2022,6 +2026,7 @@
{
struct mmc_command cmd = {0};
unsigned int qty = 0;
+ unsigned long timeout;
int err;
/*
@@ -2099,6 +2104,7 @@
if (mmc_host_is_spi(card->host))
goto out;
+ timeout = jiffies + msecs_to_jiffies(MMC_CORE_TIMEOUT_MS);
do {
memset(&cmd, 0, sizeof(struct mmc_command));
cmd.opcode = MMC_SEND_STATUS;
@@ -2112,8 +2118,19 @@
err = -EIO;
goto out;
}
+
+ /* Timeout if the device never becomes ready for data and
+ * never leaves the program state.
+ */
+ if (time_after(jiffies, timeout)) {
+ pr_err("%s: Card stuck in programming state! %s\n",
+ mmc_hostname(card->host), __func__);
+ err = -EIO;
+ goto out;
+ }
+
} while (!(cmd.resp[0] & R1_READY_FOR_DATA) ||
- R1_CURRENT_STATE(cmd.resp[0]) == R1_STATE_PRG);
+ (R1_CURRENT_STATE(cmd.resp[0]) == R1_STATE_PRG));
out:
return err;
}
@@ -2889,12 +2906,9 @@
out:
if (extend_wakelock)
wake_lock_timeout(&host->detect_wake_lock, HZ / 2);
- else
- wake_unlock(&host->detect_wake_lock);
- if (host->caps & MMC_CAP_NEEDS_POLL) {
- wake_lock(&host->detect_wake_lock);
+
+ if (host->caps & MMC_CAP_NEEDS_POLL)
mmc_schedule_delayed_work(&host->detect, HZ);
- }
}
void mmc_start_host(struct mmc_host *host)
@@ -2912,8 +2926,8 @@
spin_unlock_irqrestore(&host->lock, flags);
#endif
- if (cancel_delayed_work_sync(&host->detect))
- wake_unlock(&host->detect_wake_lock);
+ cancel_delayed_work_sync(&host->detect);
+
mmc_flush_scheduled_work();
/* clear pm flags now and let card drivers set them as needed */
@@ -3111,8 +3125,7 @@
if (mmc_bus_needs_resume(host))
return 0;
- if (cancel_delayed_work(&host->detect))
- wake_unlock(&host->detect_wake_lock);
+ cancel_delayed_work(&host->detect);
mmc_flush_scheduled_work();
mmc_bus_get(host);
@@ -3259,10 +3272,22 @@
spin_unlock_irqrestore(&host->lock, flags);
break;
}
+ spin_unlock_irqrestore(&host->lock, flags);
+
+ /* Wait for pending detect work to be completed */
+ if (!(host->caps & MMC_CAP_NEEDS_POLL))
+ flush_work(&host->detect.work);
+
+ spin_lock_irqsave(&host->lock, flags);
host->rescan_disable = 1;
spin_unlock_irqrestore(&host->lock, flags);
- if (cancel_delayed_work_sync(&host->detect))
- wake_unlock(&host->detect_wake_lock);
+
+ /*
+ * In some cases, the detect work might be scheduled
+ * just before rescan_disable is set to true.
+ * Cancel such the scheduled works.
+ */
+ cancel_delayed_work_sync(&host->detect);
if (!host->bus_ops || host->bus_ops->suspend)
break;
@@ -3290,7 +3315,10 @@
host->rescan_disable = 0;
spin_unlock_irqrestore(&host->lock, flags);
mmc_detect_change(host, 0);
+ break;
+ default:
+ return -EINVAL;
}
return 0;
@@ -3313,6 +3341,14 @@
EXPORT_SYMBOL(mmc_set_embedded_sdio_data);
#endif
+/**
+ * mmc_init_context_info() - init synchronization context
+ * @host: mmc host
+ *
+ * Init struct context_info needed to implement asynchronous
+ * request mechanism, used by mmc core, host driver and mmc requests
+ * supplier.
+ */
void mmc_init_context_info(struct mmc_host *host)
{
spin_lock_init(&host->context_info.lock);
diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
index ae8a619..931ddb0 100644
--- a/drivers/mmc/core/debugfs.c
+++ b/drivers/mmc/core/debugfs.c
@@ -484,6 +484,13 @@
pack_stats->pack_stop_reason[LARGE_SEC_ALIGN]);
strlcat(ubuf, temp_buf, cnt);
}
+ if (pack_stats->pack_stop_reason[RANDOM]) {
+ snprintf(temp_buf, TEMP_BUF_SIZE,
+ "%s: %d times: random request\n",
+ mmc_hostname(card->host),
+ pack_stats->pack_stop_reason[RANDOM]);
+ strlcat(ubuf, temp_buf, cnt);
+ }
spin_unlock(&pack_stats->lock);
@@ -528,141 +535,6 @@
.write = mmc_wr_pack_stats_write,
};
-static int mmc_new_req_stats_open(struct inode *inode, struct file *filp)
-{
- struct mmc_card *card = inode->i_private;
-
- filp->private_data = card;
- card->async_event_stats.print_in_read = 1;
- return 0;
-}
-
-static ssize_t mmc_new_req_stats_read(struct file *filp, char __user *ubuf,
- size_t cnt, loff_t *ppos)
-{
- struct mmc_card *card = filp->private_data;
- struct mmc_async_event_stats *s;
- char *temp_buf;
-
- if (!card)
- return cnt;
-
- s = &card->async_event_stats;
-
- if (!card->async_event_stats.enabled) {
- pr_info("%s: New Request statistics are disabled\n",
- mmc_hostname(card->host));
- goto exit;
- }
-
- temp_buf = kmalloc(2 * TEMP_BUF_SIZE, GFP_KERNEL);
- if (!temp_buf)
- goto exit;
-
- memset(ubuf, 0, cnt);
- memset(temp_buf, 0, 2 * TEMP_BUF_SIZE);
-
- snprintf(temp_buf, TEMP_BUF_SIZE,
- "%s: new notification & req statistics:\n",
- mmc_hostname(card->host));
- strlcat(ubuf, temp_buf, cnt);
-
- snprintf(temp_buf, TEMP_BUF_SIZE,
- "%s: done_flag:%d\n", mmc_hostname(card->host), s->done_flag);
- strlcat(ubuf, temp_buf, cnt);
-
- snprintf(temp_buf, TEMP_BUF_SIZE,
- "%s: cmd_retry:%d\n", mmc_hostname(card->host), s->cmd_retry);
- strlcat(ubuf, temp_buf, cnt);
-
- snprintf(temp_buf, TEMP_BUF_SIZE,
- "%s: NULL fetched:%d\n", mmc_hostname(card->host),
- s->null_fetched);
- strlcat(ubuf, temp_buf, cnt);
-
- snprintf(temp_buf, TEMP_BUF_SIZE,
- "%s: wake up new:%d\n",
- mmc_hostname(card->host), s->wakeup_new);
- strlcat(ubuf, temp_buf, cnt);
-
- snprintf(temp_buf, TEMP_BUF_SIZE,
- "%s: new_request_flag:%d\n", mmc_hostname(card->host),
- s->new_request_flag);
- strlcat(ubuf, temp_buf, cnt);
-
- snprintf(temp_buf, TEMP_BUF_SIZE,
- "%s: no waiting:%d\n", mmc_hostname(card->host),
- s->q_no_waiting);
- strlcat(ubuf, temp_buf, cnt);
-
- snprintf(temp_buf, TEMP_BUF_SIZE,
- "%s: no_mmc_request_action:%d\n", mmc_hostname(card->host),
- s->no_mmc_request_action);
- strlcat(ubuf, temp_buf, cnt);
-
- snprintf(temp_buf, TEMP_BUF_SIZE,
- "%s: wakeup_mq_thread:%d\n", mmc_hostname(card->host),
- s->wakeup_mq_thread);
- strlcat(ubuf, temp_buf, cnt);
-
- snprintf(temp_buf, TEMP_BUF_SIZE,
- "%s: fetch_due_to_new_req:%d\n", mmc_hostname(card->host),
- s->fetch_due_to_new_req);
- strlcat(ubuf, temp_buf, cnt);
-
- snprintf(temp_buf, TEMP_BUF_SIZE,
- "%s: returned_new_req:%d\n", mmc_hostname(card->host),
- s->returned_new_req);
- strlcat(ubuf, temp_buf, cnt);
-
- snprintf(temp_buf, TEMP_BUF_SIZE,
- "%s: done_when_new_req_event_on:%d\n",
- mmc_hostname(card->host), s->done_when_new_req_event_on);
- strlcat(ubuf, temp_buf, cnt);
-
- kfree(temp_buf);
-
- pr_info("%s", ubuf);
-
-exit:
- if (card->async_event_stats.print_in_read == 1) {
- card->async_event_stats.print_in_read = 0;
- return strnlen(ubuf, cnt);
- }
-
- return 0;
-}
-
-static ssize_t mmc_new_req_stats_write(struct file *filp,
- const char __user *ubuf, size_t cnt,
- loff_t *ppos)
-{
- struct mmc_card *card = filp->private_data;
- int value;
-
- if (!card)
- return cnt;
-
- sscanf(ubuf, "%d", &value);
- if (value) {
- mmc_blk_init_async_event_statistics(card);
- pr_info("%s: %s: New request statistics are enabled",
- mmc_hostname(card->host), __func__);
- } else {
- card->async_event_stats.enabled = false;
- pr_info("%s: %s: New request statistics are disabled",
- mmc_hostname(card->host), __func__);
- }
-
- return cnt;
-}
-
-static const struct file_operations mmc_dbg_new_req_stats_fops = {
- .open = mmc_new_req_stats_open,
- .read = mmc_new_req_stats_read,
- .write = mmc_new_req_stats_write,
-};
-
static int mmc_bkops_stats_open(struct inode *inode, struct file *filp)
{
struct mmc_card *card = inode->i_private;
@@ -808,10 +680,6 @@
&mmc_dbg_wr_pack_stats_fops))
goto err;
- if (!debugfs_create_file("new_req_stats", S_IRUSR, root, card,
- &mmc_dbg_new_req_stats_fops))
- goto err;
-
if (mmc_card_mmc(card) && (card->ext_csd.rev >= 5) &&
card->ext_csd.bkops_en)
if (!debugfs_create_file("bkops_stats", S_IRUSR, root, card,
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index 751ba75..0cfddc4 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -33,6 +33,7 @@
static void mmc_host_classdev_release(struct device *dev)
{
struct mmc_host *host = cls_dev_to_mmc_host(dev);
+ kfree(host->wlock_name);
kfree(host);
}
@@ -337,8 +338,10 @@
spin_lock_init(&host->lock);
init_waitqueue_head(&host->wq);
+ host->wlock_name = kasprintf(GFP_KERNEL,
+ "%s_detect", mmc_hostname(host));
wake_lock_init(&host->detect_wake_lock, WAKE_LOCK_SUSPEND,
- kasprintf(GFP_KERNEL, "%s_detect", mmc_hostname(host)));
+ host->wlock_name);
INIT_DELAYED_WORK(&host->detect, mmc_rescan);
#ifdef CONFIG_PM
host->pm_notify.notifier_call = mmc_pm_notify;
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index ec30cad..a9f7819 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1086,6 +1086,8 @@
card->ext_csd.part_time);
if (err && err != -EBADMSG)
goto free_card;
+ card->part_curr = card->ext_csd.part_config &
+ EXT_CSD_PART_CONFIG_ACC_MASK;
}
/*
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index f8c9720..8087ea6 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -21,6 +21,8 @@
#include "core.h"
#include "mmc_ops.h"
+#define MMC_OPS_TIMEOUT_MS (10 * 60 * 1000) /* 10 minute timeout */
+
static int _mmc_select_card(struct mmc_host *host, struct mmc_card *card)
{
int err;
@@ -386,6 +388,7 @@
{
int err;
struct mmc_command cmd = {0};
+ unsigned long timeout;
u32 status;
BUG_ON(!card);
@@ -415,6 +418,7 @@
return 0;
/* Must check status to be sure of no errors */
+ timeout = jiffies + msecs_to_jiffies(MMC_OPS_TIMEOUT_MS);
do {
err = mmc_send_status(card, &status);
if (err)
@@ -423,6 +427,13 @@
break;
if (mmc_host_is_spi(card->host))
break;
+
+ /* Timeout if the device never leaves the program state. */
+ if (time_after(jiffies, timeout)) {
+ pr_err("%s: Card stuck in programming state! %s\n",
+ mmc_hostname(card->host), __func__);
+ return -ETIMEDOUT;
+ }
} while (R1_CURRENT_STATE(status) == R1_STATE_PRG);
if (mmc_host_is_spi(card->host)) {
@@ -594,7 +605,6 @@
cmd.opcode = opcode;
cmd.arg = card->rca << 16 | 1;
- cmd.cmd_timeout_ms = card->ext_csd.out_of_int_time;
err = mmc_wait_for_cmd(card->host, &cmd, 0);
if (err) {
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index f1ba8ad..1b2b33a 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2007 Google Inc,
* Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved.
- * 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
@@ -236,14 +236,6 @@
{
int rc;
- /* Reset and init DML */
- rc = msmsdcc_dml_init(host);
- if (rc) {
- pr_err("%s: msmsdcc_dml_init error=%d\n",
- mmc_hostname(host->mmc), rc);
- goto out;
- }
-
/* Reset all SDCC BAM pipes */
rc = msmsdcc_sps_reset_ep(host, &host->sps.prod);
if (rc) {
@@ -276,13 +268,21 @@
}
rc = msmsdcc_sps_restore_ep(host, &host->sps.cons);
- if (rc)
+ if (rc) {
pr_err("%s: msmsdcc_sps_restore_ep(cons) error=%d\n",
mmc_hostname(host->mmc), rc);
- else
- host->sps.reset_bam = false;
+ goto out;
+ }
+
+ /* Reset and init DML */
+ rc = msmsdcc_dml_init(host);
+ if (rc)
+ pr_err("%s: msmsdcc_dml_init error=%d\n",
+ mmc_hostname(host->mmc), rc);
out:
+ if (!rc)
+ host->sps.reset_bam = false;
return rc;
}
@@ -4969,9 +4969,6 @@
} else {
mmc->caps &= ~MMC_CAP_NEEDS_POLL;
}
-#ifdef CONFIG_HAS_EARLYSUSPEND
- host->polling_enabled = mmc->caps & MMC_CAP_NEEDS_POLL;
-#endif
spin_unlock_irqrestore(&host->lock, flags);
return count;
}
@@ -5091,33 +5088,6 @@
return count;
}
-#ifdef CONFIG_HAS_EARLYSUSPEND
-static void msmsdcc_early_suspend(struct early_suspend *h)
-{
- struct msmsdcc_host *host =
- container_of(h, struct msmsdcc_host, early_suspend);
- unsigned long flags;
-
- spin_lock_irqsave(&host->lock, flags);
- host->polling_enabled = host->mmc->caps & MMC_CAP_NEEDS_POLL;
- host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
- spin_unlock_irqrestore(&host->lock, flags);
-};
-static void msmsdcc_late_resume(struct early_suspend *h)
-{
- struct msmsdcc_host *host =
- container_of(h, struct msmsdcc_host, early_suspend);
- unsigned long flags;
-
- if (host->polling_enabled) {
- spin_lock_irqsave(&host->lock, flags);
- host->mmc->caps |= MMC_CAP_NEEDS_POLL;
- mmc_detect_change(host->mmc, 0);
- spin_unlock_irqrestore(&host->lock, flags);
- }
-};
-#endif
-
static void msmsdcc_print_regs(const char *name, void __iomem *base,
u32 phys_base, unsigned int no_of_regs)
{
@@ -6211,13 +6181,6 @@
mmc->clk_scaling.polling_delay_ms = 100;
mmc->caps2 |= MMC_CAP2_CLK_SCALE;
-#ifdef CONFIG_HAS_EARLYSUSPEND
- host->early_suspend.suspend = msmsdcc_early_suspend;
- host->early_suspend.resume = msmsdcc_late_resume;
- host->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
- register_early_suspend(&host->early_suspend);
-#endif
-
pr_info("%s: Qualcomm MSM SDCC-core at 0x%016llx irq %d,%d dma %d"
" dmacrcri %d\n", mmc_hostname(mmc),
(unsigned long long)core_memres->start,
@@ -6473,9 +6436,6 @@
iounmap(host->base);
mmc_free_host(mmc);
-#ifdef CONFIG_HAS_EARLYSUSPEND
- unregister_early_suspend(&host->early_suspend);
-#endif
pm_runtime_disable(&(pdev)->dev);
pm_runtime_set_suspended(&(pdev)->dev);
@@ -6764,9 +6724,21 @@
msmsdcc_disable_status_gpio(host);
}
- if (!pm_runtime_suspended(dev))
+ /*
+ * If system comes out of suspend, msmsdcc_pm_resume() sets the
+ * host->pending_resume flag if the SDCC wasn't runtime suspended.
+ * Now if the system again goes to suspend without any SDCC activity
+ * then host->pending_resume flag will remain set which may cause
+ * the SDCC resume to happen first and then suspend.
+ * To avoid this unnecessary resume/suspend, make sure that
+ * pending_resume flag is cleared before calling the
+ * msmsdcc_runtime_suspend().
+ */
+ if (!pm_runtime_suspended(dev) && !host->pending_resume)
rc = msmsdcc_runtime_suspend(dev);
out:
+ /* This flag must not be set if system is entering into suspend */
+ host->pending_resume = false;
msmsdcc_print_pm_stats(host, start, __func__, rc);
return rc;
}
diff --git a/drivers/mmc/host/msm_sdcc.h b/drivers/mmc/host/msm_sdcc.h
index 8ae5b86..877120c 100644
--- a/drivers/mmc/host/msm_sdcc.h
+++ b/drivers/mmc/host/msm_sdcc.h
@@ -2,7 +2,7 @@
* linux/drivers/mmc/host/msmsdcc.h - QCT MSM7K SDC Controller
*
* Copyright (C) 2008 Google, All Rights Reserved.
- * 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 as
@@ -25,7 +25,6 @@
#include <linux/scatterlist.h>
#include <linux/dma-mapping.h>
#include <linux/wakelock.h>
-#include <linux/earlysuspend.h>
#include <linux/pm_qos.h>
#include <mach/sps.h>
@@ -381,11 +380,6 @@
struct msmsdcc_sps_data sps;
struct msmsdcc_pio_data pio;
-#ifdef CONFIG_HAS_EARLYSUSPEND
- struct early_suspend early_suspend;
- int polling_enabled;
-#endif
-
struct tasklet_struct dma_tlet;
unsigned int prog_enable;
diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index a09e5ee..5485e27 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -4210,7 +4210,7 @@
return rc;
}
/* Check if die 3.0.1 is present */
- if (subrev == 0x1)
+ if (subrev & 0x1)
pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0xA4);
else
pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0xAC);
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index 510071a..32359e5 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -81,6 +81,7 @@
#define CHGR_MISC_BOOT_DONE 0x42
#define CHGR_BUCK_COMPARATOR_OVRIDE_3 0xED
#define MISC_REVISION2 0x01
+#define USB_OVP_CTL 0x42
#define SEC_ACCESS 0xD0
/* SMBB peripheral subtype values */
@@ -99,6 +100,7 @@
#define CHGR_BOOT_DONE BIT(7)
#define CHGR_CHG_EN BIT(7)
#define CHGR_ON_BAT_FORCE_BIT BIT(0)
+#define USB_VALID_DEB_20MS 0x03
/* Interrupt definitions */
/* smbb_chg_interrupts */
@@ -481,6 +483,10 @@
static int
qpnp_chg_force_run_on_batt(struct qpnp_chg_chip *chip, int disable)
{
+ /* Don't run on battery for batteryless hardware */
+ if (chip->use_default_batt_values)
+ return 0;
+
/* This bit forces the charger to run off of the battery rather
* than a connected charger */
return qpnp_chg_masked_write(chip, chip->chgr_base + CHGR_CHG_CTRL,
@@ -1189,6 +1195,11 @@
}
rc = qpnp_chg_masked_write(chip,
+ chip->usb_chgpth_base + USB_OVP_CTL,
+ USB_VALID_DEB_20MS,
+ USB_VALID_DEB_20MS, 1);
+
+ rc = qpnp_chg_masked_write(chip,
chip->usb_chgpth_base + CHGR_USB_ENUM_T_STOP,
ENUM_T_STOP_BIT,
ENUM_T_STOP_BIT, 1);
diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c
index 7e74eca..d0410a4 100644
--- a/drivers/regulator/fixed.c
+++ b/drivers/regulator/fixed.c
@@ -104,6 +104,9 @@
if (of_find_property(np, "enable-active-high", NULL))
config->enable_high = true;
+ if (of_find_property(np, "parent-supply", NULL))
+ init_data->supply_regulator = "parent";
+
return config;
}
diff --git a/drivers/slimbus/slim-msm-ctrl.c b/drivers/slimbus/slim-msm-ctrl.c
index 9c69f47..d4fb02b 100644
--- a/drivers/slimbus/slim-msm-ctrl.c
+++ b/drivers/slimbus/slim-msm-ctrl.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. 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
@@ -1409,7 +1409,7 @@
err_request_irq_failed:
kthread_stop(dev->rx_msgq_thread);
err_thread_create_failed:
- msm_slim_sps_exit(dev);
+ msm_slim_sps_exit(dev, true);
err_sps_init_failed:
if (dev->hclk) {
clk_disable_unprepare(dev->hclk);
@@ -1453,7 +1453,7 @@
clk_put(dev->rclk);
if (dev->hclk)
clk_put(dev->hclk);
- msm_slim_sps_exit(dev);
+ msm_slim_sps_exit(dev, true);
kthread_stop(dev->rx_msgq_thread);
iounmap(dev->bam.base);
iounmap(dev->base);
diff --git a/drivers/slimbus/slim-msm-ngd.c b/drivers/slimbus/slim-msm-ngd.c
index 78e8a6f..a37a7803 100644
--- a/drivers/slimbus/slim-msm-ngd.c
+++ b/drivers/slimbus/slim-msm-ngd.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
@@ -33,6 +33,7 @@
#define NGD_SLIM_NAME "ngd_msm_ctrl"
#define SLIM_LA_MGR 0xFF
#define SLIM_ROOT_FREQ 24576000
+#define LADDR_RETRY 5
#define NGD_BASE_V1(r) (((r) % 2) ? 0x800 : 0xA00)
#define NGD_BASE_V2(r) (((r) % 2) ? 0x1000 : 0x2000)
@@ -78,6 +79,12 @@
NGD_TX_BUSY = 0x0,
};
+enum ngd_status {
+ NGD_LADDR = 1 << 1,
+};
+
+static int ngd_slim_runtime_resume(struct device *device);
+
static irqreturn_t ngd_slim_interrupt(int irq, void *d)
{
struct msm_slim_ctrl *dev = (struct msm_slim_ctrl *)d;
@@ -144,23 +151,24 @@
return IRQ_HANDLED;
}
-static int ngd_clk_pause_wakeup(struct slim_controller *ctrl)
-{
- struct msm_slim_ctrl *dev = slim_get_ctrldata(ctrl);
- return msm_slim_qmi_power_request(dev, true);
-}
-
static int ngd_qmi_available(struct notifier_block *n, unsigned long code,
void *_cmd)
{
struct msm_slim_qmi *qmi = container_of(n, struct msm_slim_qmi, nb);
+ struct msm_slim_ctrl *dev =
+ container_of(qmi, struct msm_slim_ctrl, qmi);
pr_info("Slimbus QMI NGD CB received event:%ld", code);
switch (code) {
case QMI_SERVER_ARRIVE:
- complete(&qmi->qmi_comp);
+ schedule_work(&qmi->ssr_up);
break;
case QMI_SERVER_EXIT:
- /* SSR implementation */
+ dev->state = MSM_CTRL_DOWN;
+ /* make sure autosuspend is not called until ADSP comes up*/
+ pm_runtime_get_noresume(dev->dev);
+ /* Reset ctrl_up completion */
+ init_completion(&dev->ctrl_up);
+ schedule_work(&qmi->ssr_down);
break;
default:
break;
@@ -227,22 +235,43 @@
txn->mc <= SLIM_MSG_MC_RECONFIGURE_NOW)) {
return 0;
}
- msm_slim_get_ctrl(dev);
+ /* If txn is tried when controller is down, wait for ADSP to boot */
+ if (txn->mc != SLIM_USR_MC_REPORT_SATELLITE) {
+ if (dev->state == MSM_CTRL_DOWN) {
+ u8 mc = (u8)txn->mc;
+ int timeout;
+ dev_err(dev->dev, "ADSP slimbus not up yet");
+ /*
+ * Messages related to data channel management can't
+ * wait since they are holding reconfiguration lock.
+ * clk_pause in resume (which can change state back to
+ * MSM_CTRL_AWAKE), will need that lock
+ */
+ if ((txn->mt == SLIM_MSG_MT_CORE) &&
+ ((mc >= SLIM_MSG_MC_CONNECT_SOURCE &&
+ mc <= SLIM_MSG_MC_CHANGE_CONTENT) ||
+ (mc >= SLIM_MSG_MC_BEGIN_RECONFIGURATION &&
+ mc <= SLIM_MSG_MC_RECONFIGURE_NOW)))
+ return -EREMOTEIO;
+ if ((txn->mt == SLIM_MSG_MT_DEST_REFERRED_USER) &&
+ ((mc >= SLIM_USR_MC_DEFINE_CHAN &&
+ mc <= SLIM_USR_MC_DISCONNECT_PORT)))
+ return -EREMOTEIO;
+ timeout = wait_for_completion_timeout(&dev->ctrl_up,
+ HZ);
+ if (!timeout)
+ return -ETIMEDOUT;
+ }
+ msm_slim_get_ctrl(dev);
+ }
mutex_lock(&dev->tx_lock);
+
if (txn->mc != SLIM_USR_MC_REPORT_SATELLITE &&
- (dev->state == MSM_CTRL_ASLEEP ||
- dev->state == MSM_CTRL_SLEEPING)) {
- int timeout;
+ (dev->state != MSM_CTRL_AWAKE)) {
dev_err(dev->dev, "controller not ready");
mutex_unlock(&dev->tx_lock);
- /* Reconf is signalled when master responds */
- timeout = wait_for_completion_timeout(&dev->reconf, HZ);
- if (timeout) {
- mutex_lock(&dev->tx_lock);
- } else {
- msm_slim_put_ctrl(dev);
- return -EBUSY;
- }
+ msm_slim_put_ctrl(dev);
+ return -EREMOTEIO;
}
if (txn->mt == SLIM_MSG_MT_CORE &&
(txn->mc == SLIM_MSG_MC_CONNECT_SOURCE ||
@@ -370,24 +399,23 @@
mutex_unlock(&dev->tx_lock);
msm_slim_put_ctrl(dev);
timeout = wait_for_completion_timeout(txn->comp, HZ);
- if (!timeout) {
- pr_err("connect/disc :0x%x, tid:%d timed out", txn->mc,
- txn->tid);
+ if (!timeout)
ret = -ETIMEDOUT;
+ else
+ ret = txn->ec;
+ if (ret) {
+ pr_err("connect/disconnect:0x%x,tid:%d err:%d", txn->mc,
+ txn->tid, ret);
mutex_lock(&ctrl->m_ctrl);
ctrl->txnt[txn->tid] = NULL;
mutex_unlock(&ctrl->m_ctrl);
- } else {
- ret = txn->ec;
}
- if (ret)
- pr_err("connect/disconnect:0x%x,tid:%d err:%d", txn->mc,
- txn->tid, ret);
return ret ? ret : dev->err;
}
ngd_xfer_err:
mutex_unlock(&dev->tx_lock);
- msm_slim_put_ctrl(dev);
+ if (txn->mc != SLIM_USR_MC_REPORT_SATELLITE)
+ msm_slim_put_ctrl(dev);
return ret ? ret : dev->err;
}
@@ -398,20 +426,18 @@
if (!ret) {
int timeout;
timeout = wait_for_completion_timeout(txn->comp, HZ);
- if (!timeout) {
- pr_err("master req:0x%x, tid:%d timed out", txn->mc,
- txn->tid);
+ if (!timeout)
ret = -ETIMEDOUT;
- mutex_lock(&ctrl->m_ctrl);
- ctrl->txnt[txn->tid] = NULL;
- mutex_unlock(&ctrl->m_ctrl);
- } else {
+ else
ret = txn->ec;
- }
}
- if (ret)
+ if (ret) {
pr_err("master msg:0x%x,tid:%d ret:%d", txn->mc,
txn->tid, ret);
+ mutex_lock(&ctrl->m_ctrl);
+ ctrl->txnt[txn->tid] = NULL;
+ mutex_unlock(&ctrl->m_ctrl);
+ }
return ret;
}
@@ -582,26 +608,31 @@
txn.wbuf = wbuf;
txn.len = 4;
pr_info("SLIM SAT: Received master capability");
- dev->use_rx_msgqs = 1;
- msm_slim_sps_init(dev, dev->bam_mem,
- NGD_BASE(dev->ctrl.nr, dev->ver) + NGD_STATUS, true);
- if (dev->use_rx_msgqs)
- msgq_en |= NGD_CFG_RX_MSGQ_EN;
- writel_relaxed(msgq_en, dev->base +
- NGD_BASE(dev->ctrl.nr, dev->ver));
- /* make sure NGD MSG-Q config goes through */
- mb();
+ if (dev->state == MSM_CTRL_DOWN) {
+ dev->use_rx_msgqs = 1;
+ msm_slim_sps_init(dev, dev->bam_mem,
+ NGD_BASE(dev->ctrl.nr, dev->ver) + NGD_STATUS,
+ true);
+ if (dev->use_rx_msgqs)
+ msgq_en |= NGD_CFG_RX_MSGQ_EN;
+ writel_relaxed(msgq_en, dev->base +
+ NGD_BASE(dev->ctrl.nr, dev->ver));
+ /* make sure NGD MSG-Q config goes through */
+ mb();
+ }
ret = ngd_xfer_msg(&dev->ctrl, &txn);
if (!ret) {
+ enum msm_ctrl_state prev_state = dev->state;
dev->state = MSM_CTRL_AWAKE;
-
- pm_runtime_use_autosuspend(dev->dev);
- pm_runtime_set_autosuspend_delay(dev->dev,
- MSM_SLIM_AUTOSUSPEND);
- pm_runtime_set_active(dev->dev);
- pm_runtime_enable(dev->dev);
- complete(&dev->reconf);
+ if (prev_state >= MSM_CTRL_ASLEEP)
+ complete(&dev->reconf);
+ else
+ pr_err("SLIM: unexpected capability, state:%d",
+ prev_state);
+ /* ADSP SSR, send device_up notifications */
+ if (prev_state == MSM_CTRL_DOWN)
+ schedule_work(&dev->slave_notify);
}
}
if (mc == SLIM_MSG_MC_REPLY_INFORMATION ||
@@ -654,38 +685,116 @@
}
}
-static int ngd_slim_enable(struct msm_slim_ctrl *dev, bool enable)
+static int ngd_slim_power_up(struct msm_slim_ctrl *dev)
{
+ void __iomem *ngd;
+ int timeout, ret;
+ enum msm_ctrl_state cur_state = dev->state;
+ u32 laddr;
+ u32 msgq_en = 1;
u32 ngd_int = (NGD_INT_RECFG_DONE | NGD_INT_TX_NACKED_2 |
NGD_INT_MSG_BUF_CONTE | NGD_INT_MSG_TX_INVAL |
NGD_INT_IE_VE_CHG | NGD_INT_DEV_ERR |
NGD_INT_TX_MSG_SENT | NGD_INT_RX_MSG_RCVD);
- if (enable) {
- int ret = msm_slim_qmi_init(dev, false);
- if (ret)
- return ret;
- ret = msm_slim_qmi_power_request(dev, true);
- if (ret)
- return ret;
- writel_relaxed(ngd_int, dev->base + NGD_INT_EN +
- NGD_BASE(dev->ctrl.nr, dev->ver));
+
+ if (cur_state == MSM_CTRL_DOWN) {
+ int timeout = wait_for_completion_timeout(&dev->qmi.qmi_comp,
+ HZ);
+ if (!timeout)
+ pr_err("slimbus QMI init timed out");
+ }
+
+ ret = msm_slim_qmi_power_request(dev, true);
+ if (ret) {
+ pr_err("SLIM QMI power request failed:%d", ret);
+ return ret;
+ }
+ if (!dev->ver) {
+ dev->ver = readl_relaxed(dev->base);
+ /* Version info in 16 MSbits */
+ dev->ver >>= 16;
+ }
+ ngd = dev->base + NGD_BASE(dev->ctrl.nr, dev->ver);
+ laddr = readl_relaxed(ngd + NGD_STATUS);
+ if (laddr & NGD_LADDR) {
/*
- * Enable NGD. Configure NGD in register acc. mode until master
- * announcement is received
+ * ADSP power collapse case, where HW wasn't reset.
+ * Reconnect BAM pipes if disconnected
*/
- writel_relaxed(1, dev->base + NGD_BASE(dev->ctrl.nr, dev->ver));
- /* make sure NGD enabling goes through */
- mb();
- } else {
- writel_relaxed(0, dev->base + NGD_BASE(dev->ctrl.nr, dev->ver));
- writel_relaxed(0, dev->base + NGD_INT_EN +
+ return 0;
+ } else if (cur_state != MSM_CTRL_DOWN) {
+ pr_info("ADSP P.C. CTRL state:%d NGD not enumerated:0x%x",
+ dev->state, laddr);
+ if (dev->use_rx_msgqs)
+ msgq_en |= NGD_CFG_RX_MSGQ_EN;
+ }
+
+ /*
+ * ADSP power collapse case (OR SSR), where HW was reset
+ * BAM programming will happen when capability message is received
+ */
+ writel_relaxed(ngd_int, dev->base + NGD_INT_EN +
NGD_BASE(dev->ctrl.nr, dev->ver));
- /* make sure NGD disabling goes through */
- mb();
+ /*
+ * Enable NGD. Configure NGD in register acc. mode until master
+ * announcement is received
+ */
+ writel_relaxed(msgq_en, dev->base + NGD_BASE(dev->ctrl.nr, dev->ver));
+ /* make sure NGD enabling goes through */
+ mb();
+
+ timeout = wait_for_completion_timeout(&dev->reconf, HZ);
+ if (!timeout) {
+ pr_err("failed to received master capability");
+ return -ETIMEDOUT;
+ }
+ if (cur_state == MSM_CTRL_DOWN)
+ complete(&dev->ctrl_up);
+ return 0;
+}
+
+static int ngd_slim_enable(struct msm_slim_ctrl *dev, bool enable)
+{
+ int ret = 0;
+ if (enable) {
+ ret = msm_slim_qmi_init(dev, false);
+ /* controller state should be in sync with framework state */
+ if (!ret) {
+ ret = slim_ctrl_clk_pause(&dev->ctrl, false,
+ SLIM_CLK_UNSPECIFIED);
+ complete(&dev->qmi.qmi_comp);
+ /*
+ * Power-up won't be called if clock pause failed.
+ * This can happen if ADSP SSR happened when audio
+ * session is in progress. Framework will think that
+ * clock pause failed so no need to wakeup controller.
+ * Call power-up explicitly in that case, since slimbus
+ * HW needs to be powered-on to be in sync with
+ * framework state
+ */
+ if (ret)
+ ngd_slim_power_up(dev);
+ if (!pm_runtime_enabled(dev->dev) ||
+ !pm_runtime_suspended(dev->dev))
+ ngd_slim_runtime_resume(dev->dev);
+ else
+ pm_runtime_resume(dev->dev);
+ pm_runtime_mark_last_busy(dev->dev);
+ pm_runtime_put(dev->dev);
+ } else
+ dev_err(dev->dev, "qmi init fail, ret:%d, state:%d",
+ ret, dev->state);
+ } else {
msm_slim_qmi_exit(dev);
}
- return 0;
+ return ret;
+}
+
+static int ngd_clk_pause_wakeup(struct slim_controller *ctrl)
+{
+ struct msm_slim_ctrl *dev = slim_get_ctrldata(ctrl);
+ return ngd_slim_power_up(dev);
}
static int ngd_slim_rx_msgq_thread(void *data)
@@ -698,14 +807,6 @@
u32 buffer[10];
u8 msg_len = 0;
- wait_for_completion_interruptible(&dev->qmi.qmi_comp);
- ret = ngd_slim_enable(dev, true);
- /* Exit the thread if component can't be enabled */
- if (ret) {
- pr_err("Enabling NGD failed:%d", ret);
- return 0;
- }
-
while (!kthread_should_stop()) {
set_current_state(TASK_INTERRUPTIBLE);
ret = wait_for_completion_interruptible(notify);
@@ -741,6 +842,64 @@
return 0;
}
+static void ngd_laddr_lookup(struct work_struct *work)
+{
+ struct msm_slim_ctrl *dev =
+ container_of(work, struct msm_slim_ctrl, slave_notify);
+ struct slim_controller *ctrl = &dev->ctrl;
+ struct slim_device *sbdev;
+ int i;
+ mutex_lock(&ctrl->m_ctrl);
+ list_for_each_entry(sbdev, &ctrl->devs, dev_list) {
+ int ret = 0;
+ mutex_unlock(&ctrl->m_ctrl);
+ for (i = 0; i < LADDR_RETRY; i++) {
+ ret = slim_get_logical_addr(sbdev, sbdev->e_addr,
+ 6, &sbdev->laddr);
+ if (!ret)
+ break;
+ else /* time for ADSP to assign LA */
+ msleep(20);
+ }
+ mutex_lock(&ctrl->m_ctrl);
+ }
+ mutex_unlock(&ctrl->m_ctrl);
+}
+
+static void ngd_adsp_down(struct work_struct *work)
+{
+ struct msm_slim_qmi *qmi =
+ container_of(work, struct msm_slim_qmi, ssr_down);
+ struct msm_slim_ctrl *dev =
+ container_of(qmi, struct msm_slim_ctrl, qmi);
+ struct slim_controller *ctrl = &dev->ctrl;
+ struct slim_device *sbdev;
+ int i;
+
+ ngd_slim_enable(dev, false);
+ /* disconnect BAM pipes */
+ msm_slim_sps_exit(dev, false);
+ dev->use_rx_msgqs = 0;
+ mutex_lock(&ctrl->m_ctrl);
+ /* device up should be called again after SSR */
+ list_for_each_entry(sbdev, &ctrl->devs, dev_list)
+ sbdev->notified = false;
+ /* invalidate logical addresses */
+ for (i = 0; i < ctrl->num_dev; i++)
+ ctrl->addrt[i].valid = false;
+ mutex_unlock(&ctrl->m_ctrl);
+ pr_info("SLIM ADSP SSR (DOWN) done");
+}
+
+static void ngd_adsp_up(struct work_struct *work)
+{
+ struct msm_slim_qmi *qmi =
+ container_of(work, struct msm_slim_qmi, ssr_up);
+ struct msm_slim_ctrl *dev =
+ container_of(qmi, struct msm_slim_ctrl, qmi);
+ ngd_slim_enable(dev, true);
+}
+
static int __devinit ngd_slim_probe(struct platform_device *pdev)
{
struct msm_slim_ctrl *dev;
@@ -834,15 +993,13 @@
dev->bam_mem = bam_mem;
init_completion(&dev->reconf);
+ init_completion(&dev->ctrl_up);
mutex_init(&dev->tx_lock);
spin_lock_init(&dev->rx_lock);
dev->ee = 1;
dev->irq = irq->start;
dev->bam.irq = bam_irq->start;
- dev->ver = readl_relaxed(dev->base);
- /* Version info in 16 MSbits */
- dev->ver >>= 16;
init_completion(&dev->rx_msgq_notify);
/* Register with framework */
@@ -854,7 +1011,7 @@
dev->ctrl.dev.parent = &pdev->dev;
dev->ctrl.dev.of_node = pdev->dev.of_node;
- dev->state = MSM_CTRL_ASLEEP;
+ dev->state = MSM_CTRL_DOWN;
ret = request_irq(dev->irq, ngd_slim_interrupt,
IRQF_TRIGGER_HIGH, "ngd_slim_irq", dev);
@@ -865,7 +1022,16 @@
}
init_completion(&dev->qmi.qmi_comp);
+ pm_runtime_use_autosuspend(dev->dev);
+ pm_runtime_set_autosuspend_delay(dev->dev, MSM_SLIM_AUTOSUSPEND);
+ pm_runtime_set_suspended(dev->dev);
+ pm_runtime_enable(dev->dev);
+
+ INIT_WORK(&dev->slave_notify, ngd_laddr_lookup);
+ INIT_WORK(&dev->qmi.ssr_down, ngd_adsp_down);
+ INIT_WORK(&dev->qmi.ssr_up, ngd_adsp_up);
dev->qmi.nb.notifier_call = ngd_qmi_available;
+ pm_runtime_get_noresume(dev->dev);
ret = qmi_svc_event_notifier_register(SLIMBUS_QMI_SVC_ID,
SLIMBUS_QMI_INS_ID, &dev->qmi.nb);
if (ret) {
@@ -873,6 +1039,7 @@
goto qmi_register_failed;
}
+
/* Fire up the Rx message queue thread */
dev->rx_msgq_thread = kthread_run(ngd_slim_rx_msgq_thread, dev,
NGD_SLIM_NAME "_ngd_msgq_thread");
@@ -914,7 +1081,6 @@
qmi_svc_event_notifier_unregister(SLIMBUS_QMI_SVC_ID,
SLIMBUS_QMI_INS_ID, &dev->qmi.nb);
pm_runtime_disable(&pdev->dev);
- pm_runtime_set_suspended(&pdev->dev);
free_irq(dev->irq, dev);
slim_del_controller(&dev->ctrl);
kthread_stop(dev->rx_msgq_thread);
@@ -938,31 +1104,12 @@
* functions to be called from system suspend/resume. So they are not
* inside ifdef CONFIG_PM_RUNTIME
*/
-#ifdef CONFIG_PM_SLEEP
-static int ngd_slim_runtime_suspend(struct device *device)
-{
- struct platform_device *pdev = to_platform_device(device);
- struct msm_slim_ctrl *dev = platform_get_drvdata(pdev);
- int ret;
- dev_dbg(device, "pm_runtime: suspending...\n");
- dev->state = MSM_CTRL_SLEEPING;
- ret = slim_ctrl_clk_pause(&dev->ctrl, false, SLIM_CLK_UNSPECIFIED);
- if (ret) {
- dev_err(device, "clk pause not entered:%d", ret);
- dev->state = MSM_CTRL_AWAKE;
- } else {
- dev->state = MSM_CTRL_ASLEEP;
- }
- return ret;
-}
-
static int ngd_slim_runtime_resume(struct device *device)
{
struct platform_device *pdev = to_platform_device(device);
struct msm_slim_ctrl *dev = platform_get_drvdata(pdev);
int ret = 0;
- dev_dbg(device, "pm_runtime: resuming...\n");
- if (dev->state == MSM_CTRL_ASLEEP)
+ if (dev->state >= MSM_CTRL_ASLEEP)
ret = slim_ctrl_clk_pause(&dev->ctrl, true, 0);
if (ret) {
dev_err(device, "clk pause not exited:%d", ret);
@@ -973,6 +1120,24 @@
return ret;
}
+#ifdef CONFIG_PM_SLEEP
+static int ngd_slim_runtime_suspend(struct device *device)
+{
+ struct platform_device *pdev = to_platform_device(device);
+ struct msm_slim_ctrl *dev = platform_get_drvdata(pdev);
+ int ret = 0;
+ dev->state = MSM_CTRL_SLEEPING;
+ ret = slim_ctrl_clk_pause(&dev->ctrl, false, SLIM_CLK_UNSPECIFIED);
+ if (ret) {
+ if (ret != -EBUSY)
+ dev_err(device, "clk pause not entered:%d", ret);
+ dev->state = MSM_CTRL_AWAKE;
+ } else {
+ dev->state = MSM_CTRL_ASLEEP;
+ }
+ return ret;
+}
+
static int ngd_slim_suspend(struct device *dev)
{
int ret = -EBUSY;
diff --git a/drivers/slimbus/slim-msm.c b/drivers/slimbus/slim-msm.c
index c62ac27..72a8669 100644
--- a/drivers/slimbus/slim-msm.c
+++ b/drivers/slimbus/slim-msm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. 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
@@ -517,6 +517,8 @@
},
};
+ if (dev->bam.hdl)
+ goto init_rx_msgq;
bam_props.ee = dev->ee;
bam_props.virt_addr = dev->bam.base;
bam_props.phys_addr = bam_mem->start;
@@ -565,7 +567,7 @@
return ret;
}
-void msm_slim_sps_exit(struct msm_slim_ctrl *dev)
+void msm_slim_sps_exit(struct msm_slim_ctrl *dev, bool dereg)
{
if (dev->use_rx_msgqs) {
struct msm_slim_endp *endpoint = &dev->rx_msgq;
@@ -579,7 +581,10 @@
sps_disconnect(endpoint->sps);
msm_slim_sps_mem_free(dev, descr);
msm_slim_free_endpoint(endpoint);
+ }
+ if (dereg) {
sps_deregister_bam_device(dev->bam.hdl);
+ dev->bam.hdl = 0L;
}
}
@@ -589,6 +594,11 @@
#define SLIMBUS_QMI_POWER_REQ_V01 0x0021
#define SLIMBUS_QMI_POWER_RESP_V01 0x0021
+#define SLIMBUS_QMI_POWER_REQ_MAX_MSG_LEN 7
+#define SLIMBUS_QMI_POWER_RESP_MAX_MSG_LEN 7
+#define SLIMBUS_QMI_SELECT_INSTANCE_REQ_MAX_MSG_LEN 14
+#define SLIMBUS_QMI_SELECT_INSTANCE_RESP_MAX_MSG_LEN 7
+
enum slimbus_mode_enum_type_v01 {
/* To force a 32 bit signed enum. Do not change or use*/
SLIMBUS_MODE_ENUM_TYPE_MIN_ENUM_VAL_V01 = INT_MIN,
@@ -791,11 +801,11 @@
int rc;
req_desc.msg_id = SLIMBUS_QMI_SELECT_INSTANCE_REQ_V01;
- req_desc.max_msg_len = sizeof(*req);
+ req_desc.max_msg_len = SLIMBUS_QMI_SELECT_INSTANCE_REQ_MAX_MSG_LEN;
req_desc.ei_array = slimbus_select_inst_req_msg_v01_ei;
resp_desc.msg_id = SLIMBUS_QMI_SELECT_INSTANCE_RESP_V01;
- resp_desc.max_msg_len = sizeof(resp);
+ resp_desc.max_msg_len = SLIMBUS_QMI_SELECT_INSTANCE_RESP_MAX_MSG_LEN;
resp_desc.ei_array = slimbus_select_inst_resp_msg_v01_ei;
rc = qmi_send_req_wait(dev->qmi.handle, &req_desc, req, sizeof(*req),
@@ -823,11 +833,11 @@
int rc;
req_desc.msg_id = SLIMBUS_QMI_POWER_REQ_V01;
- req_desc.max_msg_len = sizeof(*req);
+ req_desc.max_msg_len = SLIMBUS_QMI_POWER_REQ_MAX_MSG_LEN;
req_desc.ei_array = slimbus_power_req_msg_v01_ei;
resp_desc.msg_id = SLIMBUS_QMI_POWER_RESP_V01;
- resp_desc.max_msg_len = sizeof(resp);
+ resp_desc.max_msg_len = SLIMBUS_QMI_POWER_RESP_MAX_MSG_LEN;
resp_desc.ei_array = slimbus_power_resp_msg_v01_ei;
rc = qmi_send_req_wait(dev->qmi.handle, &req_desc, req, sizeof(*req),
diff --git a/drivers/slimbus/slim-msm.h b/drivers/slimbus/slim-msm.h
index 3daf7ee..1c6db32 100644
--- a/drivers/slimbus/slim-msm.h
+++ b/drivers/slimbus/slim-msm.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. 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
@@ -152,6 +152,7 @@
MSM_CTRL_AWAKE,
MSM_CTRL_SLEEPING,
MSM_CTRL_ASLEEP,
+ MSM_CTRL_DOWN,
};
struct msm_slim_sps_bam {
@@ -176,6 +177,8 @@
struct kthread_worker kworker;
struct completion qmi_comp;
struct notifier_block nb;
+ struct work_struct ssr_down;
+ struct work_struct ssr_up;
};
struct msm_slim_ctrl {
@@ -212,8 +215,10 @@
bool reconf_busy;
bool chan_active;
enum msm_ctrl_state state;
+ struct completion ctrl_up;
int nsats;
u32 ver;
+ struct work_struct slave_notify;
struct msm_slim_qmi qmi;
};
@@ -266,7 +271,7 @@
int msm_slim_rx_msgq_get(struct msm_slim_ctrl *dev, u32 *data, int offset);
int msm_slim_sps_init(struct msm_slim_ctrl *dev, struct resource *bam_mem,
u32 pipe_reg, bool remote);
-void msm_slim_sps_exit(struct msm_slim_ctrl *dev);
+void msm_slim_sps_exit(struct msm_slim_ctrl *dev, bool dereg);
void msm_slim_qmi_exit(struct msm_slim_ctrl *dev);
int msm_slim_qmi_init(struct msm_slim_ctrl *dev, bool apps_is_master);
diff --git a/drivers/slimbus/slimbus.c b/drivers/slimbus/slimbus.c
index c320e46..e5b3158 100644
--- a/drivers/slimbus/slimbus.c
+++ b/drivers/slimbus/slimbus.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. 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
@@ -3047,6 +3047,7 @@
for (i = 0; i < ctrl->last_tid; i++) {
if (ctrl->txnt[i]) {
ret = -EBUSY;
+ pr_info("slim_clk_pause: txn-rsp for %d pending", i);
mutex_unlock(&ctrl->m_ctrl);
return -EBUSY;
}
@@ -3057,6 +3058,7 @@
mutex_lock(&ctrl->sched.m_reconf);
/* Data channels active */
if (ctrl->sched.usedslots) {
+ pr_info("slim_clk_pause: data channel active");
ret = -EBUSY;
goto clk_pause_ret;
}
diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c
index 4ffe0d8..8ff6cff 100644
--- a/drivers/tty/serial/msm_serial_hs.c
+++ b/drivers/tty/serial/msm_serial_hs.c
@@ -3,7 +3,7 @@
* MSM 7k High speed uart driver
*
* Copyright (c) 2008 Google Inc.
- * Copyright (c) 2007-2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2007-2013, The Linux Foundation. All rights reserved.
* Modified: Nick Pelly <npelly@google.com>
*
* All source code in this file is licensed under the following license
@@ -54,18 +54,34 @@
#include <linux/device.h>
#include <linux/wakelock.h>
#include <linux/debugfs.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
#include <asm/atomic.h>
#include <asm/irq.h>
#include <mach/hardware.h>
#include <mach/dma.h>
+#include <mach/sps.h>
#include <mach/msm_serial_hs.h>
#include "msm_serial_hs_hwreg.h"
+#define UART_SPS_CONS_PERIPHERAL 0
+#define UART_SPS_PROD_PERIPHERAL 1
static int hs_serial_debug_mask = 1;
module_param_named(debug_mask, hs_serial_debug_mask,
int, S_IRUGO | S_IWUSR | S_IWGRP);
+/*
+ * There are 3 different kind of UART Core available on MSM.
+ * High Speed UART (i.e. Legacy HSUART), GSBI based HSUART
+ * and BSLP based HSUART.
+ */
+enum uart_core_type {
+ LEGACY_HSUART,
+ GSBI_HSUART,
+ BLSP_HSUART,
+};
enum flush_reason {
FLUSH_NONE,
@@ -92,6 +108,17 @@
CLK_REQ_OFF_RXSTALE_FLUSHED,
};
+/* SPS data structures to support HSUART with BAM
+ * @sps_pipe - This struct defines BAM pipe descriptor
+ * @sps_connect - This struct defines a connection's end point
+ * @sps_register - This struct defines a event registration parameters
+ */
+struct msm_hs_sps_ep_conn_data {
+ struct sps_pipe *pipe_handle;
+ struct sps_connect config;
+ struct sps_register_event event;
+};
+
struct msm_hs_tx {
unsigned int tx_ready_int_en; /* ok to dma more tx */
unsigned int dma_in_flight; /* tx dma in progress */
@@ -105,6 +132,7 @@
int tx_count;
dma_addr_t dma_base;
struct tasklet_struct tlet;
+ struct msm_hs_sps_ep_conn_data cons;
};
struct msm_hs_rx {
@@ -122,6 +150,7 @@
struct wake_lock wake_lock;
struct delayed_work flip_insert_work;
struct tasklet_struct tlet;
+ struct msm_hs_sps_ep_conn_data prod;
};
enum buffer_states {
@@ -168,7 +197,20 @@
struct work_struct clock_off_w; /* work for actual clock off */
struct workqueue_struct *hsuart_wq; /* hsuart workqueue */
struct mutex clk_mutex; /* mutex to guard against clock off/clock on */
+ struct work_struct reset_bam_rx; /* work for reset bam rx endpoint */
+ struct work_struct disconnect_rx_endpoint; /* disconnect rx_endpoint */
bool tty_flush_receive;
+ enum uart_core_type uart_type;
+ u32 bam_handle;
+ resource_size_t bam_mem;
+ int bam_irq;
+ unsigned char __iomem *bam_base;
+ unsigned int bam_tx_ep_pipe_index;
+ unsigned int bam_rx_ep_pipe_index;
+ /* struct sps_event_notify is an argument passed when triggering a
+ * callback event object registered for an SPS connection end point.
+ */
+ struct sps_event_notify notify;
};
#define MSM_UARTDM_BURST_SIZE 16 /* DM burst size (in bytes) */
@@ -176,12 +218,17 @@
#define UARTDM_RX_BUF_SIZE 512
#define RETRY_TIMEOUT 5
#define UARTDM_NR 256
+#define BAM_PIPE_MIN 0
+#define BAM_PIPE_MAX 11
static struct dentry *debug_base;
static struct msm_hs_port q_uart_port[UARTDM_NR];
static struct platform_driver msm_serial_hs_platform_driver;
static struct uart_driver msm_hs_driver;
static struct uart_ops msm_hs_ops;
+static void msm_hs_start_rx_locked(struct uart_port *uport);
+static void msm_serial_hs_rx_tlet(unsigned long tlet_ptr);
+static void flip_insert_work(struct work_struct *work);
#define UARTDM_TO_MSM(uart_port) \
container_of((uart_port), struct msm_hs_port, uport)
@@ -244,7 +291,10 @@
/* assume gsbi uart if gsbi resource found in pdata */
return ((msm_uport->mapped_gsbi != NULL));
}
-
+static unsigned int is_blsp_uart(struct msm_hs_port *msm_uport)
+{
+ return (msm_uport->uart_type == BLSP_HSUART);
+}
static inline unsigned int msm_hs_read(struct uart_port *uport,
unsigned int offset)
{
@@ -320,13 +370,21 @@
if (val) {
spin_lock_irqsave(&uport->lock, flags);
ret = msm_hs_read(uport, UARTDM_MR2_ADDR);
- ret |= UARTDM_MR2_LOOP_MODE_BMSK;
+ if (is_blsp_uart(msm_uport))
+ ret |= (UARTDM_MR2_LOOP_MODE_BMSK |
+ UARTDM_MR2_RFR_CTS_LOOP_MODE_BMSK);
+ else
+ ret |= UARTDM_MR2_LOOP_MODE_BMSK;
msm_hs_write(uport, UARTDM_MR2_ADDR, ret);
spin_unlock_irqrestore(&uport->lock, flags);
} else {
spin_lock_irqsave(&uport->lock, flags);
ret = msm_hs_read(uport, UARTDM_MR2_ADDR);
- ret &= ~UARTDM_MR2_LOOP_MODE_BMSK;
+ if (is_blsp_uart(msm_uport))
+ ret &= ~(UARTDM_MR2_LOOP_MODE_BMSK |
+ UARTDM_MR2_RFR_CTS_LOOP_MODE_BMSK);
+ else
+ ret &= ~UARTDM_MR2_LOOP_MODE_BMSK;
msm_hs_write(uport, UARTDM_MR2_ADDR, ret);
spin_unlock_irqrestore(&uport->lock, flags);
}
@@ -470,6 +528,89 @@
return 0;
}
+
+/* Connect a UART peripheral's SPS endpoint(consumer endpoint)
+ *
+ * Also registers a SPS callback function for the consumer
+ * process with the SPS driver
+ *
+ * @uport - Pointer to uart uport structure
+ *
+ * @return - 0 if successful else negative value.
+ *
+ */
+
+static int msm_hs_spsconnect_tx(struct uart_port *uport)
+{
+ int ret;
+ struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
+ struct msm_hs_tx *tx = &msm_uport->tx;
+ struct sps_pipe *sps_pipe_handle = tx->cons.pipe_handle;
+ struct sps_connect *sps_config = &tx->cons.config;
+ struct sps_register_event *sps_event = &tx->cons.event;
+
+ /* Establish connection between peripheral and memory endpoint */
+ ret = sps_connect(sps_pipe_handle, sps_config);
+ if (ret) {
+ pr_err("msm_serial_hs: sps_connect() failed for tx!!\n"
+ "pipe_handle=0x%x ret=%d", (u32)sps_pipe_handle, ret);
+ return ret;
+ }
+ /* Register callback event for EOT (End of transfer) event. */
+ ret = sps_register_event(sps_pipe_handle, sps_event);
+ if (ret) {
+ pr_err("msm_serial_hs: sps_connect() failed for tx!!\n"
+ "pipe_handle=0x%x ret=%d", (u32)sps_pipe_handle, ret);
+ goto reg_event_err;
+ }
+ return 0;
+
+reg_event_err:
+ sps_disconnect(sps_pipe_handle);
+ return ret;
+}
+
+/* Connect a UART peripheral's SPS endpoint(producer endpoint)
+ *
+ * Also registers a SPS callback function for the producer
+ * process with the SPS driver
+ *
+ * @uport - Pointer to uart uport structure
+ *
+ * @return - 0 if successful else negative value.
+ *
+ */
+
+static int msm_hs_spsconnect_rx(struct uart_port *uport)
+{
+ int ret;
+ struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
+ struct msm_hs_rx *rx = &msm_uport->rx;
+ struct sps_pipe *sps_pipe_handle = rx->prod.pipe_handle;
+ struct sps_connect *sps_config = &rx->prod.config;
+ struct sps_register_event *sps_event = &rx->prod.event;
+
+ /* Establish connection between peripheral and memory endpoint */
+ ret = sps_connect(sps_pipe_handle, sps_config);
+ if (ret) {
+ pr_err("msm_serial_hs: sps_connect() failed for rx!!\n"
+ "pipe_handle=0x%x ret=%d", (u32)sps_pipe_handle, ret);
+ return ret;
+ }
+ /* Register callback event for EOT (End of transfer) event. */
+ ret = sps_register_event(sps_pipe_handle, sps_event);
+ if (ret) {
+ pr_err("msm_serial_hs: sps_connect() failed for rx!!\n"
+ "pipe_handle=0x%x ret=%d", (u32)sps_pipe_handle, ret);
+ goto reg_event_err;
+ }
+ return 0;
+
+reg_event_err:
+ sps_disconnect(sps_pipe_handle);
+ return ret;
+}
+
/*
* programs the UARTDM_CSR register with correct bit rates
*
@@ -479,9 +620,8 @@
* Goal is to have around 8 ms before indicate stale.
* roundup (((Bit Rate * .008) / 10) + 1
*/
-static unsigned long msm_hs_set_bps_locked(struct uart_port *uport,
- unsigned int bps,
- unsigned long flags)
+static void msm_hs_set_bps_locked(struct uart_port *uport,
+ unsigned int bps)
{
unsigned long rxstale;
unsigned long data;
@@ -581,15 +721,11 @@
uport->uartclk = 7372800;
}
- spin_unlock_irqrestore(&uport->lock, flags);
if (clk_set_rate(msm_uport->clk, uport->uartclk)) {
printk(KERN_WARNING "Error setting clock rate on UART\n");
WARN_ON(1);
- spin_lock_irqsave(&uport->lock, flags);
- return flags;
}
- spin_lock_irqsave(&uport->lock, flags);
data = rxstale & UARTDM_IPR_STALE_LSB_BMSK;
data |= UARTDM_IPR_STALE_TIMEOUT_MSB_BMSK & (rxstale << 2);
@@ -601,7 +737,6 @@
*/
msm_hs_write(uport, UARTDM_CR_ADDR, RESET_TX);
msm_hs_write(uport, UARTDM_CR_ADDR, RESET_RX);
- return flags;
}
@@ -654,6 +789,23 @@
msm_hs_write(uport, UARTDM_IPR_ADDR, data);
}
+
+/* Reset BAM RX Endpoint Pipe Index from workqueue context*/
+
+static void hsuart_reset_bam_rx_work(struct work_struct *w)
+{
+ struct msm_hs_port *msm_uport = container_of(w, struct msm_hs_port,
+ reset_bam_rx);
+ struct uart_port *uport = &msm_uport->uport;
+ struct msm_hs_rx *rx = &msm_uport->rx;
+ struct sps_pipe *sps_pipe_handle = rx->prod.pipe_handle;
+
+ sps_disconnect(sps_pipe_handle);
+ msm_hs_spsconnect_rx(uport);
+
+ msm_serial_hs_rx_tlet((unsigned long) &rx->tlet);
+}
+
/*
* termios : new ktermios
* oldtermios: old ktermios previous setting
@@ -666,12 +818,12 @@
{
unsigned int bps;
unsigned long data;
- unsigned long flags;
unsigned int c_cflag = termios->c_cflag;
struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
+ struct msm_hs_rx *rx = &msm_uport->rx;
+ struct sps_pipe *sps_pipe_handle = rx->prod.pipe_handle;
mutex_lock(&msm_uport->clk_mutex);
- spin_lock_irqsave(&uport->lock, flags);
/*
* Disable Rx channel of UARTDM
@@ -683,7 +835,13 @@
* suggested to do disable/reset or reset/disable at the same time.
*/
data = msm_hs_read(uport, UARTDM_DMEN_ADDR);
- data &= ~UARTDM_RX_DM_EN_BMSK;
+ if (is_blsp_uart(msm_uport)) {
+ /* Disable UARTDM RX BAM Interface */
+ data &= ~UARTDM_RX_BAM_ENABLE_BMSK;
+ } else {
+ data &= ~UARTDM_RX_DM_EN_BMSK;
+ }
+
msm_hs_write(uport, UARTDM_DMEN_ADDR, data);
/* 300 is the minimum baud support by the driver */
@@ -697,7 +855,7 @@
if (!uport->uartclk)
msm_hs_set_std_bps_locked(uport, bps);
else
- flags = msm_hs_set_bps_locked(uport, bps, flags);
+ msm_hs_set_bps_locked(uport, bps);
data = msm_hs_read(uport, UARTDM_MR2_ADDR);
data &= ~UARTDM_MR2_PARITY_MODE_BMSK;
@@ -754,7 +912,7 @@
uport->ignore_status_mask = termios->c_iflag & INPCK;
uport->ignore_status_mask |= termios->c_iflag & IGNPAR;
- uport->ignore_status_mask = termios->c_iflag & IGNBRK;
+ uport->ignore_status_mask |= termios->c_iflag & IGNBRK;
uport->read_status_mask = (termios->c_cflag & CREAD);
@@ -775,13 +933,18 @@
* dsb requires here.
*/
mb();
- /* do discard flush */
- msm_dmov_flush(msm_uport->dma_rx_channel, 0);
+ if (is_blsp_uart(msm_uport)) {
+ sps_disconnect(sps_pipe_handle);
+ msm_hs_spsconnect_rx(uport);
+ msm_serial_hs_rx_tlet((unsigned long) &rx->tlet);
+ } else {
+ /* do discard flush */
+ msm_dmov_flush(msm_uport->dma_rx_channel, 0);
+ }
}
msm_hs_write(uport, UARTDM_IMR_ADDR, msm_uport->imr_reg);
mb();
- spin_unlock_irqrestore(&uport->lock, flags);
mutex_unlock(&msm_uport->clk_mutex);
}
@@ -814,6 +977,20 @@
msm_uport->tx.tx_ready_int_en = 0;
}
+/* Disconnect BAM RX Endpoint Pipe Index from workqueue context*/
+static void hsuart_disconnect_rx_endpoint_work(struct work_struct *w)
+{
+ struct msm_hs_port *msm_uport = container_of(w, struct msm_hs_port,
+ disconnect_rx_endpoint);
+ struct msm_hs_rx *rx = &msm_uport->rx;
+ struct sps_pipe *sps_pipe_handle = rx->prod.pipe_handle;
+
+ sps_disconnect(sps_pipe_handle);
+ wake_lock_timeout(&msm_uport->rx.wake_lock, HZ / 2);
+ msm_uport->rx.flush = FLUSH_SHUTDOWN;
+ wake_up(&msm_uport->rx.wait);
+}
+
/*
* Standard API, Stop receiver as soon as possible.
*
@@ -829,7 +1006,10 @@
/* disable dlink */
data = msm_hs_read(uport, UARTDM_DMEN_ADDR);
- data &= ~UARTDM_RX_DM_EN_BMSK;
+ if (is_blsp_uart(msm_uport))
+ data &= ~UARTDM_RX_BAM_ENABLE_BMSK;
+ else
+ data &= ~UARTDM_RX_DM_EN_BMSK;
msm_hs_write(uport, UARTDM_DMEN_ADDR, data);
/* calling DMOV or CLOCK API. Hence mb() */
@@ -837,10 +1017,17 @@
/* Disable the receiver */
if (msm_uport->rx.flush == FLUSH_NONE) {
wake_lock(&msm_uport->rx.wake_lock);
- /* do discard flush */
- msm_dmov_flush(msm_uport->dma_rx_channel, 0);
+ if (is_blsp_uart(msm_uport)) {
+ msm_uport->rx.flush = FLUSH_STOP;
+ /* workqueue for BAM rx endpoint disconnect */
+ queue_work(msm_uport->hsuart_wq,
+ &msm_uport->disconnect_rx_endpoint);
+ } else {
+ /* do discard flush */
+ msm_dmov_flush(msm_uport->dma_rx_channel, 0);
+ }
}
- if (msm_uport->rx.flush != FLUSH_SHUTDOWN)
+ if (!is_blsp_uart(msm_uport) && msm_uport->rx.flush != FLUSH_SHUTDOWN)
msm_uport->rx.flush = FLUSH_STOP;
}
@@ -852,9 +1039,11 @@
int aligned_tx_count;
dma_addr_t src_addr;
dma_addr_t aligned_src_addr;
+ u32 flags = SPS_IOVEC_FLAG_EOT;
struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
struct msm_hs_tx *tx = &msm_uport->tx;
struct circ_buf *tx_buf = &msm_uport->uport.state->xmit;
+ struct sps_pipe *sps_pipe_handle;
if (uart_circ_empty(tx_buf) || uport->state->port.tty->stopped) {
msm_hs_stop_tx_locked(uport);
@@ -882,14 +1071,21 @@
dma_sync_single_for_device(uport->dev, aligned_src_addr,
aligned_tx_count, DMA_TO_DEVICE);
- tx->command_ptr->num_rows = (((tx_count + 15) >> 4) << 16) |
- ((tx_count + 15) >> 4);
- tx->command_ptr->src_row_addr = src_addr;
+ if (is_blsp_uart(msm_uport)) {
+ /* Issue TX BAM Start IFC command */
+ msm_hs_write(uport, UARTDM_CR_ADDR, START_TX_BAM_IFC);
+ } else {
+ tx->command_ptr->num_rows =
+ (((tx_count + 15) >> 4) << 16) |
+ ((tx_count + 15) >> 4);
+ tx->command_ptr->src_row_addr = src_addr;
- dma_sync_single_for_device(uport->dev, tx->mapped_cmd_ptr,
- sizeof(dmov_box), DMA_TO_DEVICE);
+ dma_sync_single_for_device(uport->dev, tx->mapped_cmd_ptr,
+ sizeof(dmov_box), DMA_TO_DEVICE);
- *tx->command_ptr_ptr = CMD_PTR_LP | DMOV_CMD_ADDR(tx->mapped_cmd_ptr);
+ *tx->command_ptr_ptr = CMD_PTR_LP |
+ DMOV_CMD_ADDR(tx->mapped_cmd_ptr);
+ }
/* Save tx_count to use in Callback */
tx->tx_count = tx_count;
@@ -901,16 +1097,28 @@
/* Calling next DMOV API. Hence mb() here. */
mb();
- dma_sync_single_for_device(uport->dev, tx->mapped_cmd_ptr_ptr,
- sizeof(u32), DMA_TO_DEVICE);
msm_uport->tx.flush = FLUSH_NONE;
- msm_dmov_enqueue_cmd(msm_uport->dma_tx_channel, &tx->xfer);
+
+ if (is_blsp_uart(msm_uport)) {
+ sps_pipe_handle = tx->cons.pipe_handle;
+ /* Queue transfer request to SPS */
+ sps_transfer_one(sps_pipe_handle, src_addr, tx_count,
+ msm_uport, flags);
+ } else {
+ dma_sync_single_for_device(uport->dev, tx->mapped_cmd_ptr_ptr,
+ sizeof(u32), DMA_TO_DEVICE);
+
+ msm_dmov_enqueue_cmd(msm_uport->dma_tx_channel, &tx->xfer);
+ }
}
/* Start to receive the next chunk of data */
static void msm_hs_start_rx_locked(struct uart_port *uport)
{
struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
+ struct msm_hs_rx *rx = &msm_uport->rx;
+ struct sps_pipe *sps_pipe_handle;
+ u32 flags = SPS_IOVEC_FLAG_EOT;
unsigned int buffer_pending = msm_uport->rx.buffer_pending;
unsigned int data;
@@ -919,6 +1127,10 @@
printk(KERN_ERR "Error: rx started in buffer state = %x",
buffer_pending);
+ if (is_blsp_uart(msm_uport)) {
+ /* Issue RX BAM Start IFC command */
+ msm_hs_write(uport, UARTDM_CR_ADDR, START_RX_BAM_IFC);
+ }
msm_hs_write(uport, UARTDM_CR_ADDR, RESET_STALE_INT);
msm_hs_write(uport, UARTDM_DMRX_ADDR, UARTDM_RX_BUF_SIZE);
msm_hs_write(uport, UARTDM_CR_ADDR, STALE_EVENT_ENABLE);
@@ -929,15 +1141,29 @@
* disable in set_termios before configuring baud rate.
*/
data = msm_hs_read(uport, UARTDM_DMEN_ADDR);
- data |= UARTDM_RX_DM_EN_BMSK;
+ if (is_blsp_uart(msm_uport)) {
+ /* Enable UARTDM Rx BAM Interface */
+ data |= UARTDM_RX_BAM_ENABLE_BMSK;
+ } else {
+ data |= UARTDM_RX_DM_EN_BMSK;
+ }
+
msm_hs_write(uport, UARTDM_DMEN_ADDR, data);
msm_hs_write(uport, UARTDM_IMR_ADDR, msm_uport->imr_reg);
/* Calling next DMOV API. Hence mb() here. */
mb();
msm_uport->rx.flush = FLUSH_NONE;
- msm_dmov_enqueue_cmd(msm_uport->dma_rx_channel, &msm_uport->rx.xfer);
+ if (is_blsp_uart(msm_uport)) {
+ sps_pipe_handle = rx->prod.pipe_handle;
+ /* Queue transfer request to SPS */
+ sps_transfer_one(sps_pipe_handle, rx->rbuffer,
+ UARTDM_RX_BUF_SIZE, msm_uport, flags);
+ } else {
+ msm_dmov_enqueue_cmd(msm_uport->dma_rx_channel,
+ &msm_uport->rx.xfer);
+ }
}
static void flip_insert_work(struct work_struct *work)
@@ -999,6 +1225,7 @@
{
int retval;
int rx_count;
+ static int remaining_rx_count, bytes_pending;
unsigned long status;
unsigned long flags;
unsigned int error_f = 0;
@@ -1075,6 +1302,20 @@
rx_count = msm_hs_read(uport, UARTDM_RX_TOTAL_SNAP_ADDR);
+ if (is_blsp_uart(msm_uport)) {
+ if (rx_count > UARTDM_RX_BUF_SIZE) {
+ if (bytes_pending) {
+ rx_count = remaining_rx_count;
+ bytes_pending = 0;
+ } else {
+ remaining_rx_count = rx_count -
+ UARTDM_RX_BUF_SIZE;
+ if (remaining_rx_count)
+ bytes_pending = 1;
+ rx_count = UARTDM_RX_BUF_SIZE;
+ }
+ }
+ }
/* order the read of rx.buffer */
rmb();
@@ -1124,6 +1365,31 @@
}
}
+/**
+ * Callback notification from SPS driver
+ *
+ * This callback function gets triggered called from
+ * SPS driver when requested SPS data transfer is
+ * completed.
+ *
+ */
+
+static void msm_hs_sps_tx_callback(struct sps_event_notify *notify)
+{
+ struct msm_hs_port *msm_uport =
+ (struct msm_hs_port *)
+ ((struct sps_event_notify *)notify)->user;
+
+ msm_uport->notify = *notify;
+ pr_debug("%s: sps ev_id=%d, addr=0x%x, size=0x%x, flags=0x%x\n",
+ __func__, notify->event_id,
+ notify->data.transfer.iovec.addr,
+ notify->data.transfer.iovec.size,
+ notify->data.transfer.iovec.flags);
+
+ tasklet_schedule(&msm_uport->tx.tlet);
+}
+
/*
* This routine is called when we are done with a DMA transfer
*
@@ -1170,6 +1436,33 @@
spin_unlock_irqrestore(&(msm_uport->uport.lock), flags);
}
+/**
+ * Callback notification from SPS driver
+ *
+ * This callback function gets triggered called from
+ * SPS driver when requested SPS data transfer is
+ * completed.
+ *
+ */
+
+static void msm_hs_sps_rx_callback(struct sps_event_notify *notify)
+{
+
+ struct msm_hs_port *msm_uport =
+ (struct msm_hs_port *)
+ ((struct sps_event_notify *)notify)->user;
+
+ msm_uport->notify = *notify;
+ pr_debug("%s: sps ev_id=%d, addr=0x%x, size=0x%x, flags=0x%x\n",
+ __func__, notify->event_id,
+ notify->data.transfer.iovec.addr,
+ notify->data.transfer.iovec.size,
+ notify->data.transfer.iovec.flags);
+
+ if (msm_uport->rx.flush == FLUSH_NONE)
+ tasklet_schedule(&msm_uport->rx.tlet);
+}
+
/*
* This routine is called when we are done with a DMA transfer or the
* a flush has been sent to the data mover driver.
@@ -1265,7 +1558,8 @@
{
struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
- msm_uport->tty_flush_receive = true;
+ if (msm_uport->tx.dma_in_flight)
+ msm_uport->tty_flush_receive = true;
}
/*
@@ -1356,6 +1650,14 @@
switch (msm_uport->clk_req_off_state) {
case CLK_REQ_OFF_START:
msm_uport->clk_req_off_state = CLK_REQ_OFF_RXSTALE_ISSUED;
+ if (is_blsp_uart(msm_uport)) {
+ /* Stale interrupt when RX-FIFO is empty
+ * will fire if STALE_IRQ_EMPTY bit is set
+ * for UART Core v1.4
+ */
+ msm_hs_write(uport, UARTDM_BCR_ADDR,
+ UARTDM_BCR_STALE_IRQ_EMPTY);
+ }
msm_hs_write(uport, UARTDM_CR_ADDR, FORCE_STALE_EVENT);
/*
* Before returning make sure that device writel completed.
@@ -1458,13 +1760,25 @@
*/
mb();
- if (msm_uport->clk_req_off_state == CLK_REQ_OFF_RXSTALE_ISSUED)
+ if (msm_uport->clk_req_off_state ==
+ CLK_REQ_OFF_RXSTALE_ISSUED) {
msm_uport->clk_req_off_state =
CLK_REQ_OFF_FLUSH_ISSUED;
+ if (is_blsp_uart(msm_uport)) {
+ /* Reset BCR Register for UARTDM Core v14*/
+ msm_hs_write(uport, UARTDM_BCR_ADDR, 0x0);
+ }
+ }
+
if (rx->flush == FLUSH_NONE) {
rx->flush = FLUSH_DATA_READY;
- msm_dmov_flush(msm_uport->dma_rx_channel, 1);
+ if (is_blsp_uart(msm_uport)) {
+ queue_work(msm_uport->hsuart_wq,
+ &msm_uport->reset_bam_rx);
+ } else {
+ msm_dmov_flush(msm_uport->dma_rx_channel, 1);
+ }
}
}
/* tx ready interrupt */
@@ -1581,7 +1895,10 @@
msm_uport->rx.flush == FLUSH_SHUTDOWN) {
msm_hs_write(uport, UARTDM_CR_ADDR, RESET_RX);
data = msm_hs_read(uport, UARTDM_DMEN_ADDR);
- data |= UARTDM_RX_DM_EN_BMSK;
+ if (is_blsp_uart(msm_uport))
+ data |= UARTDM_RX_BAM_ENABLE_BMSK;
+ else
+ data |= UARTDM_RX_DM_EN_BMSK;
msm_hs_write(uport, UARTDM_DMEN_ADDR, data);
/* Complete above device write. Hence mb() here. */
mb();
@@ -1661,6 +1978,9 @@
pdev->dev.platform_data;
struct circ_buf *tx_buf = &uport->state->xmit;
struct msm_hs_tx *tx = &msm_uport->tx;
+ struct msm_hs_rx *rx = &msm_uport->rx;
+ struct sps_pipe *sps_pipe_handle_tx = tx->cons.pipe_handle;
+ struct sps_pipe *sps_pipe_handle_rx = rx->prod.pipe_handle;
rfr_level = uport->fifosize;
if (rfr_level > 16)
@@ -1682,6 +2002,24 @@
if (unlikely(pdata->gpio_config(1)))
dev_err(uport->dev, "Cannot configure gpios\n");
+
+ /* SPS Connect for BAM endpoints */
+ if (is_blsp_uart(msm_uport)) {
+ /* SPS connect for TX */
+ ret = msm_hs_spsconnect_tx(uport);
+ if (ret) {
+ pr_err("msm_serial_hs: SPS connect failed for TX");
+ goto deinit_uart_clk;
+ }
+
+ /* SPS connect for RX */
+ ret = msm_hs_spsconnect_rx(uport);
+ if (ret) {
+ pr_err("msm_serial_hs: SPS connect failed for RX");
+ goto sps_disconnect_tx;
+ }
+ }
+
/* Set auto RFR Level */
data = msm_hs_read(uport, UARTDM_MR1_ADDR);
data &= ~UARTDM_MR1_AUTO_RFR_LEVEL1_BMSK;
@@ -1697,8 +2035,13 @@
msm_hs_write(uport, UARTDM_IPR_ADDR, data);
}
- /* Enable Data Mover Mode */
- data = UARTDM_TX_DM_EN_BMSK | UARTDM_RX_DM_EN_BMSK;
+ if (is_blsp_uart(msm_uport)) {
+ /* Enable BAM mode */
+ data = UARTDM_TX_BAM_ENABLE_BMSK | UARTDM_RX_BAM_ENABLE_BMSK;
+ } else {
+ /* Enable Data Mover Mode */
+ data = UARTDM_TX_DM_EN_BMSK | UARTDM_RX_DM_EN_BMSK;
+ }
msm_hs_write(uport, UARTDM_DMEN_ADDR, data);
/* Reset TX */
@@ -1719,18 +2062,20 @@
tx->tx_ready_int_en = 0;
tx->dma_in_flight = 0;
- tx->xfer.complete_func = msm_hs_dmov_tx_callback;
+ if (!is_blsp_uart(msm_uport)) {
+ tx->xfer.complete_func = msm_hs_dmov_tx_callback;
- tx->command_ptr->cmd = CMD_LC |
- CMD_DST_CRCI(msm_uport->dma_tx_crci) | CMD_MODE_BOX;
+ tx->command_ptr->cmd = CMD_LC |
+ CMD_DST_CRCI(msm_uport->dma_tx_crci) | CMD_MODE_BOX;
- tx->command_ptr->src_dst_len = (MSM_UARTDM_BURST_SIZE << 16)
+ tx->command_ptr->src_dst_len = (MSM_UARTDM_BURST_SIZE << 16)
| (MSM_UARTDM_BURST_SIZE);
- tx->command_ptr->row_offset = (MSM_UARTDM_BURST_SIZE << 16);
+ tx->command_ptr->row_offset = (MSM_UARTDM_BURST_SIZE << 16);
- tx->command_ptr->dst_row_addr =
- msm_uport->uport.mapbase + UARTDM_TF_ADDR;
+ tx->command_ptr->dst_row_addr =
+ msm_uport->uport.mapbase + UARTDM_TF_ADDR;
+ }
msm_uport->imr_reg |= UARTDM_ISR_RXSTALE_BMSK;
/* Enable reading the current CTS, no harm even if CTS is ignored */
@@ -1747,7 +2092,7 @@
ret = irq_set_irq_wake(msm_uport->wakeup.irq, 1);
if (unlikely(ret)) {
pr_err("%s():Err setting wakeup irq\n", __func__);
- goto deinit_uart_clk;
+ goto sps_disconnect_rx;
}
}
@@ -1787,6 +2132,12 @@
free_irq(uport->irq, msm_uport);
free_wake_irq:
irq_set_irq_wake(msm_uport->wakeup.irq, 0);
+sps_disconnect_rx:
+ if (is_blsp_uart(msm_uport))
+ sps_disconnect(sps_pipe_handle_rx);
+sps_disconnect_tx:
+ if (is_blsp_uart(msm_uport))
+ sps_disconnect(sps_pipe_handle_tx);
deinit_uart_clk:
clk_disable_unprepare(msm_uport->clk);
if (msm_uport->pclk)
@@ -1804,24 +2155,6 @@
struct msm_hs_tx *tx = &msm_uport->tx;
struct msm_hs_rx *rx = &msm_uport->rx;
- /* Allocate the command pointer. Needs to be 64 bit aligned */
- tx->command_ptr = kmalloc(sizeof(dmov_box), GFP_KERNEL | __GFP_DMA);
- if (!tx->command_ptr)
- return -ENOMEM;
-
- tx->command_ptr_ptr = kmalloc(sizeof(u32), GFP_KERNEL | __GFP_DMA);
- if (!tx->command_ptr_ptr) {
- ret = -ENOMEM;
- goto free_tx_command_ptr;
- }
-
- tx->mapped_cmd_ptr = dma_map_single(uport->dev, tx->command_ptr,
- sizeof(dmov_box), DMA_TO_DEVICE);
- tx->mapped_cmd_ptr_ptr = dma_map_single(uport->dev,
- tx->command_ptr_ptr,
- sizeof(u32), DMA_TO_DEVICE);
- tx->xfer.cmdptr = DMOV_CMD_ADDR(tx->mapped_cmd_ptr_ptr);
-
init_waitqueue_head(&rx->wait);
init_waitqueue_head(&tx->wait);
wake_lock_init(&rx->wake_lock, WAKE_LOCK_SUSPEND, "msm_serial_hs_rx");
@@ -1848,12 +2181,40 @@
goto free_pool;
}
+ /* Set up Uart Receive */
+ msm_hs_write(uport, UARTDM_RFWR_ADDR, 0);
+
+ INIT_DELAYED_WORK(&rx->flip_insert_work, flip_insert_work);
+
+ if (is_blsp_uart(msm_uport))
+ return ret;
+
+ /* Allocate the command pointer. Needs to be 64 bit aligned */
+ tx->command_ptr = kmalloc(sizeof(dmov_box), GFP_KERNEL | __GFP_DMA);
+ if (!tx->command_ptr) {
+ return -ENOMEM;
+ goto free_rx_buffer;
+ }
+
+ tx->command_ptr_ptr = kmalloc(sizeof(u32), GFP_KERNEL | __GFP_DMA);
+ if (!tx->command_ptr_ptr) {
+ ret = -ENOMEM;
+ goto free_tx_command_ptr;
+ }
+
+ tx->mapped_cmd_ptr = dma_map_single(uport->dev, tx->command_ptr,
+ sizeof(dmov_box), DMA_TO_DEVICE);
+ tx->mapped_cmd_ptr_ptr = dma_map_single(uport->dev,
+ tx->command_ptr_ptr,
+ sizeof(u32), DMA_TO_DEVICE);
+ tx->xfer.cmdptr = DMOV_CMD_ADDR(tx->mapped_cmd_ptr_ptr);
+
/* Allocate the command pointer. Needs to be 64 bit aligned */
rx->command_ptr = kmalloc(sizeof(dmov_box), GFP_KERNEL | __GFP_DMA);
if (!rx->command_ptr) {
pr_err("%s(): cannot allocate rx->command_ptr", __func__);
ret = -ENOMEM;
- goto free_rx_buffer;
+ goto free_tx_command_ptr_ptr;
}
rx->command_ptr_ptr = kmalloc(sizeof(u32), GFP_KERNEL | __GFP_DMA);
@@ -1868,9 +2229,6 @@
rx->command_ptr->dst_row_addr = rx->rbuffer;
- /* Set up Uart Receive */
- msm_hs_write(uport, UARTDM_RFWR_ADDR, 0);
-
rx->xfer.complete_func = msm_hs_dmov_rx_callback;
rx->command_ptr->cmd = CMD_LC |
@@ -1890,13 +2248,21 @@
sizeof(u32), DMA_TO_DEVICE);
rx->xfer.cmdptr = DMOV_CMD_ADDR(rx->cmdptr_dmaaddr);
- INIT_DELAYED_WORK(&rx->flip_insert_work, flip_insert_work);
-
return ret;
free_rx_command_ptr:
kfree(rx->command_ptr);
+free_tx_command_ptr_ptr:
+ kfree(msm_uport->tx.command_ptr_ptr);
+ dma_unmap_single(uport->dev, msm_uport->tx.mapped_cmd_ptr_ptr,
+ sizeof(u32), DMA_TO_DEVICE);
+ dma_unmap_single(uport->dev, msm_uport->tx.mapped_cmd_ptr,
+ sizeof(dmov_box), DMA_TO_DEVICE);
+
+free_tx_command_ptr:
+ kfree(msm_uport->tx.command_ptr);
+
free_rx_buffer:
dma_pool_free(msm_uport->rx.pool, msm_uport->rx.buffer,
msm_uport->rx.rbuffer);
@@ -1909,47 +2275,386 @@
wake_lock_destroy(&msm_uport->dma_wake_lock);
tasklet_kill(&msm_uport->tx.tlet);
tasklet_kill(&msm_uport->rx.tlet);
- dma_unmap_single(uport->dev, msm_uport->tx.mapped_cmd_ptr_ptr,
- sizeof(u32), DMA_TO_DEVICE);
- dma_unmap_single(uport->dev, msm_uport->tx.mapped_cmd_ptr,
- sizeof(dmov_box), DMA_TO_DEVICE);
- kfree(msm_uport->tx.command_ptr_ptr);
-
-free_tx_command_ptr:
- kfree(msm_uport->tx.command_ptr);
return ret;
}
+struct msm_serial_hs_platform_data
+ *msm_hs_dt_to_pdata(struct platform_device *pdev)
+{
+ struct device_node *node = pdev->dev.of_node;
+ struct msm_serial_hs_platform_data *pdata;
+ int rx_to_inject, ret;
+
+ pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata) {
+ pr_err("unable to allocate memory for platform data\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ /* UART TX GPIO */
+ pdata->uart_tx_gpio = of_get_named_gpio(node,
+ "qcom,tx-gpio", 0);
+ if (pdata->uart_tx_gpio < 0)
+ pr_debug("uart_tx_gpio is not available\n");
+
+ /* UART RX GPIO */
+ pdata->uart_rx_gpio = of_get_named_gpio(node,
+ "qcom,rx-gpio", 0);
+ if (pdata->uart_rx_gpio < 0)
+ pr_debug("uart_rx_gpio is not available\n");
+
+ /* UART CTS GPIO */
+ pdata->uart_cts_gpio = of_get_named_gpio(node,
+ "qcom,cts-gpio", 0);
+ if (pdata->uart_cts_gpio < 0)
+ pr_debug("uart_cts_gpio is not available\n");
+
+ /* UART RFR GPIO */
+ pdata->uart_rfr_gpio = of_get_named_gpio(node,
+ "qcom,rfr-gpio", 0);
+ if (pdata->uart_rfr_gpio < 0)
+ pr_debug("uart_rfr_gpio is not available\n");
+
+ pdata->inject_rx_on_wakeup = of_property_read_bool(node,
+ "qcom,inject-rx-on-wakeup");
+
+ if (pdata->inject_rx_on_wakeup) {
+ ret = of_property_read_u32(node, "qcom,rx-char-to-inject",
+ &rx_to_inject);
+ if (ret < 0) {
+ pr_err("Error: Rx_char_to_inject not specified.\n");
+ return ERR_PTR(ret);
+ }
+ pdata->rx_to_inject = (char)rx_to_inject;
+ }
+
+ ret = of_property_read_u32(node, "qcom,bam-tx-ep-pipe-index",
+ &pdata->bam_tx_ep_pipe_index);
+ if (ret < 0) {
+ pr_err("Error: Getting UART BAM TX EP Pipe Index.\n");
+ return ERR_PTR(ret);
+ }
+
+ if (!(pdata->bam_tx_ep_pipe_index >= BAM_PIPE_MIN &&
+ pdata->bam_tx_ep_pipe_index <= BAM_PIPE_MAX)) {
+ pr_err("Error: Invalid UART BAM TX EP Pipe Index.\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ ret = of_property_read_u32(node, "qcom,bam-rx-ep-pipe-index",
+ &pdata->bam_rx_ep_pipe_index);
+ if (ret < 0) {
+ pr_err("Error: Getting UART BAM RX EP Pipe Index.\n");
+ return ERR_PTR(ret);
+ }
+
+ if (!(pdata->bam_rx_ep_pipe_index >= BAM_PIPE_MIN &&
+ pdata->bam_rx_ep_pipe_index <= BAM_PIPE_MAX)) {
+ pr_err("Error: Invalid UART BAM RX EP Pipe Index.\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ pr_debug("tx_ep_pipe_index:%d rx_ep_pipe_index:%d\n"
+ "tx_gpio:%d rx_gpio:%d rfr_gpio:%d cts_gpio:%d",
+ pdata->bam_tx_ep_pipe_index, pdata->bam_rx_ep_pipe_index,
+ pdata->uart_tx_gpio, pdata->uart_rx_gpio, pdata->uart_cts_gpio,
+ pdata->uart_rfr_gpio);
+
+ return pdata;
+}
+
+
+/**
+ * Deallocate UART peripheral's SPS endpoint
+ * @msm_uport - Pointer to msm_hs_port structure
+ * @ep - Pointer to sps endpoint data structure
+ */
+
+static void msm_hs_exit_ep_conn(struct msm_hs_port *msm_uport,
+ struct msm_hs_sps_ep_conn_data *ep)
+{
+ struct sps_pipe *sps_pipe_handle = ep->pipe_handle;
+ struct sps_connect *sps_config = &ep->config;
+
+ dma_free_coherent(msm_uport->uport.dev,
+ sps_config->desc.size,
+ &sps_config->desc.phys_base,
+ GFP_KERNEL);
+ sps_free_endpoint(sps_pipe_handle);
+}
+
+
+/**
+ * Allocate UART peripheral's SPS endpoint
+ *
+ * This function allocates endpoint context
+ * by calling appropriate SPS driver APIs.
+ *
+ * @msm_uport - Pointer to msm_hs_port structure
+ * @ep - Pointer to sps endpoint data structure
+ * @is_produce - 1 means Producer endpoint
+ * - 0 means Consumer endpoint
+ *
+ * @return - 0 if successful else negative value
+ */
+
+static int msm_hs_sps_init_ep_conn(struct msm_hs_port *msm_uport,
+ struct msm_hs_sps_ep_conn_data *ep,
+ bool is_producer)
+{
+ int rc = 0;
+ struct sps_pipe *sps_pipe_handle;
+ struct sps_connect *sps_config = &ep->config;
+ struct sps_register_event *sps_event = &ep->event;
+
+ /* Allocate endpoint context */
+ sps_pipe_handle = sps_alloc_endpoint();
+ if (!sps_pipe_handle) {
+ pr_err("msm_serial_hs: sps_alloc_endpoint() failed!!\n"
+ "is_producer=%d", is_producer);
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ /* Get default connection configuration for an endpoint */
+ rc = sps_get_config(sps_pipe_handle, sps_config);
+ if (rc) {
+ pr_err("msm_serial_hs: sps_get_config() failed!!\n"
+ "pipe_handle=0x%x rc=%d", (u32)sps_pipe_handle, rc);
+ goto get_config_err;
+ }
+
+ /* Modify the default connection configuration */
+ if (is_producer) {
+ /* For UART producer transfer, source is UART peripheral
+ where as destination is system memory */
+ sps_config->source = msm_uport->bam_handle;
+ sps_config->destination = SPS_DEV_HANDLE_MEM;
+ sps_config->mode = SPS_MODE_SRC;
+ sps_config->src_pipe_index = msm_uport->bam_rx_ep_pipe_index;
+ sps_config->dest_pipe_index = 0;
+ sps_config->options = SPS_O_EOT;
+ } else {
+ /* For UART consumer transfer, source is system memory
+ where as destination is UART peripheral */
+ sps_config->source = SPS_DEV_HANDLE_MEM;
+ sps_config->destination = msm_uport->bam_handle;
+ sps_config->mode = SPS_MODE_DEST;
+ sps_config->src_pipe_index = 0;
+ sps_config->dest_pipe_index = msm_uport->bam_tx_ep_pipe_index;
+ sps_config->options = SPS_O_EOT;
+ }
+
+ sps_config->event_thresh = 0x10;
+
+ /* Allocate maximum descriptor fifo size */
+ sps_config->desc.size = 65532;
+ sps_config->desc.base = dma_alloc_coherent(msm_uport->uport.dev,
+ sps_config->desc.size,
+ &sps_config->desc.phys_base,
+ GFP_KERNEL);
+ if (!sps_config->desc.base) {
+ rc = -ENOMEM;
+ pr_err("msm_serial_hs: dma_alloc_coherent() failed!!\n");
+ goto get_config_err;
+ }
+ memset(sps_config->desc.base, 0x00, sps_config->desc.size);
+
+ sps_event->mode = SPS_TRIGGER_CALLBACK;
+ sps_event->options = SPS_O_EOT;
+ if (is_producer)
+ sps_event->callback = msm_hs_sps_rx_callback;
+ else
+ sps_event->callback = msm_hs_sps_tx_callback;
+
+ sps_event->user = (void *)msm_uport;
+
+ /* Now save the sps pipe handle */
+ ep->pipe_handle = sps_pipe_handle;
+ pr_debug("msm_serial_hs: success !! %s: pipe_handle=0x%x\n"
+ "desc_fifo.phys_base=0x%x\n",
+ is_producer ? "READ" : "WRITE",
+ (u32)sps_pipe_handle, sps_config->desc.phys_base);
+ return 0;
+
+get_config_err:
+ sps_free_endpoint(sps_pipe_handle);
+out:
+ return rc;
+}
+
+/**
+ * Initialize SPS HW connected with UART core
+ *
+ * This function register BAM HW resources with
+ * SPS driver and then initialize 2 SPS endpoints
+ *
+ * msm_uport - Pointer to msm_hs_port structure
+ *
+ * @return - 0 if successful else negative value
+ */
+
+static int msm_hs_sps_init(struct msm_hs_port *msm_uport)
+{
+ int rc = 0;
+ struct sps_bam_props bam = {0};
+ u32 bam_handle;
+
+ rc = sps_phy2h(msm_uport->bam_mem, &bam_handle);
+ if (rc || !bam_handle) {
+ bam.phys_addr = msm_uport->bam_mem;
+ bam.virt_addr = msm_uport->bam_base;
+ /*
+ * This event thresold value is only significant for BAM-to-BAM
+ * transfer. It's ignored for BAM-to-System mode transfer.
+ */
+ bam.event_threshold = 0x10; /* Pipe event threshold */
+ bam.summing_threshold = 1; /* BAM event threshold */
+
+ /* SPS driver wll handle the UART BAM IRQ */
+ bam.irq = (u32)msm_uport->bam_irq;
+ bam.manage = SPS_BAM_MGR_LOCAL;
+
+ pr_debug("msm_serial_hs: bam physical base=0x%x\n",
+ (u32)bam.phys_addr);
+ pr_debug("msm_serial_hs: bam virtual base=0x%x\n",
+ (u32)bam.virt_addr);
+
+ /* Register UART Peripheral BAM device to SPS driver */
+ rc = sps_register_bam_device(&bam, &bam_handle);
+ if (rc) {
+ pr_err("msm_serial_hs: BAM device register failed\n");
+ return rc;
+ }
+ pr_info("msm_serial_hs: BAM device registered. bam_handle=0x%x",
+ msm_uport->bam_handle);
+ }
+ msm_uport->bam_handle = bam_handle;
+
+ rc = msm_hs_sps_init_ep_conn(msm_uport, &msm_uport->rx.prod,
+ UART_SPS_PROD_PERIPHERAL);
+ if (rc) {
+ pr_err("%s: Failed to Init Producer BAM-pipe", __func__);
+ goto deregister_bam;
+ }
+
+ rc = msm_hs_sps_init_ep_conn(msm_uport, &msm_uport->tx.cons,
+ UART_SPS_CONS_PERIPHERAL);
+ if (rc) {
+ pr_err("%s: Failed to Init Consumer BAM-pipe", __func__);
+ goto deinit_ep_conn_prod;
+ }
+ return 0;
+
+deinit_ep_conn_prod:
+ msm_hs_exit_ep_conn(msm_uport, &msm_uport->rx.prod);
+deregister_bam:
+ sps_deregister_bam_device(msm_uport->bam_handle);
+ return rc;
+}
+
static int __devinit msm_hs_probe(struct platform_device *pdev)
{
int ret;
struct uart_port *uport;
struct msm_hs_port *msm_uport;
+ struct resource *core_resource;
+ struct resource *bam_resource;
struct resource *resource;
+ int core_irqres, bam_irqres;
struct msm_serial_hs_platform_data *pdata = pdev->dev.platform_data;
+ struct device_node *node = pdev->dev.of_node;
+
+ if (pdev->dev.of_node) {
+ dev_dbg(&pdev->dev, "device tree enabled\n");
+ pdata = msm_hs_dt_to_pdata(pdev);
+ if (IS_ERR(pdata))
+ return PTR_ERR(pdata);
+
+ of_property_read_u32(node, "cell-index",
+ &pdev->id);
+
+ pdev->dev.platform_data = pdata;
+ }
if (pdev->id < 0 || pdev->id >= UARTDM_NR) {
- printk(KERN_ERR "Invalid plaform device ID = %d\n", pdev->id);
+ pr_err("Invalid plaform device ID = %d\n", pdev->id);
return -EINVAL;
}
msm_uport = &q_uart_port[pdev->id];
uport = &msm_uport->uport;
-
uport->dev = &pdev->dev;
- resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (unlikely(!resource))
- return -ENXIO;
- uport->mapbase = resource->start; /* virtual address */
+ if (pdev->dev.of_node)
+ msm_uport->uart_type = BLSP_HSUART;
- uport->membase = ioremap(uport->mapbase, PAGE_SIZE);
- if (unlikely(!uport->membase))
- return -ENOMEM;
+ /* Get required resources for BAM HSUART */
+ if (is_blsp_uart(msm_uport)) {
+ core_resource = platform_get_resource_byname(pdev,
+ IORESOURCE_MEM, "core_mem");
+ bam_resource = platform_get_resource_byname(pdev,
+ IORESOURCE_MEM, "bam_mem");
+ core_irqres = platform_get_irq_byname(pdev, "core_irq");
+ bam_irqres = platform_get_irq_byname(pdev, "bam_irq");
- uport->irq = platform_get_irq(pdev, 0);
- if (unlikely((int)uport->irq < 0))
- return -ENXIO;
+ if (!core_resource) {
+ pr_err("Invalid core HSUART Resources.\n");
+ return -ENXIO;
+ }
+
+ if (!bam_resource) {
+ pr_err("Invalid BAM HSUART Resources.\n");
+ return -ENXIO;
+ }
+
+ if (!core_irqres) {
+ pr_err("Invalid core irqres Resources.\n");
+ return -ENXIO;
+ }
+ if (!bam_irqres) {
+ pr_err("Invalid bam irqres Resources.\n");
+ return -ENXIO;
+ }
+
+ uport->mapbase = core_resource->start;
+
+ uport->membase = ioremap(uport->mapbase,
+ resource_size(core_resource));
+ if (unlikely(!uport->membase)) {
+ pr_err("UART Resource ioremap Failed.\n");
+ return -ENOMEM;
+ }
+ msm_uport->bam_mem = bam_resource->start;
+ msm_uport->bam_base = ioremap(msm_uport->bam_mem,
+ resource_size(bam_resource));
+ if (unlikely(!msm_uport->bam_base)) {
+ pr_err("UART BAM Resource ioremap Failed.\n");
+ iounmap(uport->membase);
+ return -ENOMEM;
+ }
+
+ uport->irq = core_irqres;
+ msm_uport->bam_irq = bam_irqres;
+
+ } else {
+
+ resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (unlikely(!resource))
+ return -ENXIO;
+ uport->mapbase = resource->start;
+ uport->membase = ioremap(uport->mapbase,
+ resource_size(resource));
+ if (unlikely(!uport->membase))
+ return -ENOMEM;
+
+ uport->irq = platform_get_irq(pdev, 0);
+ if (unlikely((int)uport->irq < 0)) {
+ pr_err("UART IRQ Failed.\n");
+ iounmap(uport->membase);
+ return -ENXIO;
+ }
+ }
if (pdata == NULL)
msm_uport->wakeup.irq = -1;
@@ -1959,24 +2664,41 @@
msm_uport->wakeup.inject_rx = pdata->inject_rx_on_wakeup;
msm_uport->wakeup.rx_to_inject = pdata->rx_to_inject;
- if (unlikely(msm_uport->wakeup.irq < 0))
- return -ENXIO;
+ if (unlikely(msm_uport->wakeup.irq < 0)) {
+ ret = -ENXIO;
+ goto unmap_memory;
+ }
+ if (is_blsp_uart(msm_uport)) {
+ msm_uport->bam_tx_ep_pipe_index =
+ pdata->bam_tx_ep_pipe_index;
+ msm_uport->bam_rx_ep_pipe_index =
+ pdata->bam_rx_ep_pipe_index;
+ }
}
- resource = platform_get_resource_byname(pdev, IORESOURCE_DMA,
- "uartdm_channels");
- if (unlikely(!resource))
- return -ENXIO;
- msm_uport->dma_tx_channel = resource->start;
- msm_uport->dma_rx_channel = resource->end;
+ if (!is_blsp_uart(msm_uport)) {
- resource = platform_get_resource_byname(pdev, IORESOURCE_DMA,
- "uartdm_crci");
- if (unlikely(!resource))
- return -ENXIO;
- msm_uport->dma_tx_crci = resource->start;
- msm_uport->dma_rx_crci = resource->end;
+ resource = platform_get_resource_byname(pdev,
+ IORESOURCE_DMA, "uartdm_channels");
+ if (unlikely(!resource)) {
+ ret = -ENXIO;
+ goto unmap_memory;
+ }
+
+ msm_uport->dma_tx_channel = resource->start;
+ msm_uport->dma_rx_channel = resource->end;
+
+ resource = platform_get_resource_byname(pdev,
+ IORESOURCE_DMA, "uartdm_crci");
+ if (unlikely(!resource)) {
+ ret = -ENXIO;
+ goto unmap_memory;
+ }
+
+ msm_uport->dma_tx_crci = resource->start;
+ msm_uport->dma_rx_crci = resource->end;
+ }
uport->iotype = UPIO_MEM;
uport->fifosize = 64;
@@ -1986,8 +2708,10 @@
msm_uport->imr_reg = 0x0;
msm_uport->clk = clk_get(&pdev->dev, "core_clk");
- if (IS_ERR(msm_uport->clk))
- return PTR_ERR(msm_uport->clk);
+ if (IS_ERR(msm_uport->clk)) {
+ ret = PTR_ERR(msm_uport->clk);
+ goto unmap_memory;
+ }
msm_uport->pclk = clk_get(&pdev->dev, "iface_clk");
/*
@@ -2000,7 +2724,7 @@
ret = clk_set_rate(msm_uport->clk, uport->uartclk);
if (ret) {
printk(KERN_WARNING "Error setting clock rate on UART\n");
- return ret;
+ goto unmap_memory;
}
msm_uport->hsuart_wq = alloc_workqueue("k_hsuart",
@@ -2008,12 +2732,29 @@
if (!msm_uport->hsuart_wq) {
pr_err("%s(): Unable to create workqueue hsuart_wq\n",
__func__);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto unmap_memory;
}
INIT_WORK(&msm_uport->clock_off_w, hsuart_clock_off_work);
+
+ /* Init work for Reset Rx bam endpoints */
+ INIT_WORK(&msm_uport->reset_bam_rx, hsuart_reset_bam_rx_work);
+
+ /* Init work for sps_disconnect in stop_rx_locked */
+ INIT_WORK(&msm_uport->disconnect_rx_endpoint,
+ hsuart_disconnect_rx_endpoint_work);
mutex_init(&msm_uport->clk_mutex);
+ /* Initialize SPS HW connected with UART core */
+ if (is_blsp_uart(msm_uport)) {
+ ret = msm_hs_sps_init(msm_uport);
+ if (unlikely(ret)) {
+ pr_err("SPS Initialization failed ! err=%d", ret);
+ goto unmap_memory;
+ }
+ }
+
clk_prepare_enable(msm_uport->clk);
if (msm_uport->pclk)
clk_prepare_enable(msm_uport->pclk);
@@ -2023,7 +2764,7 @@
clk_disable_unprepare(msm_uport->clk);
if (msm_uport->pclk)
clk_disable_unprepare(msm_uport->pclk);
- return ret;
+ goto unmap_memory;
}
/* configure the CR Protection to Enable */
@@ -2048,14 +2789,23 @@
ret = sysfs_create_file(&pdev->dev.kobj, &dev_attr_clock.attr);
if (unlikely(ret))
- return ret;
+ goto unmap_memory;
msm_serial_debugfs_init(msm_uport, pdev->id);
uport->line = pdev->id;
if (pdata != NULL && pdata->userid && pdata->userid <= UARTDM_NR)
uport->line = pdata->userid;
- return uart_add_one_port(&msm_hs_driver, uport);
+ ret = uart_add_one_port(&msm_hs_driver, uport);
+ if (!ret)
+ return ret;
+
+unmap_memory:
+ iounmap(uport->membase);
+ if (is_blsp_uart(msm_uport))
+ iounmap(msm_uport->bam_base);
+
+ return ret;
}
static int __init msm_serial_hs_init(void)
@@ -2102,27 +2852,35 @@
struct platform_device *pdev = to_platform_device(uport->dev);
const struct msm_serial_hs_platform_data *pdata =
pdev->dev.platform_data;
+ struct msm_hs_tx *tx = &msm_uport->tx;
+ struct sps_pipe *sps_pipe_handle = tx->cons.pipe_handle;
if (msm_uport->tx.dma_in_flight) {
- spin_lock_irqsave(&uport->lock, flags);
- /* disable UART TX interface to DM */
- data = msm_hs_read(uport, UARTDM_DMEN_ADDR);
- data &= ~UARTDM_TX_DM_EN_BMSK;
- msm_hs_write(uport, UARTDM_DMEN_ADDR, data);
- /* turn OFF UART Transmitter */
- msm_hs_write(uport, UARTDM_CR_ADDR, UARTDM_CR_TX_DISABLE_BMSK);
- /* reset UART TX */
- msm_hs_write(uport, UARTDM_CR_ADDR, RESET_TX);
- /* reset UART TX Error */
- msm_hs_write(uport, UARTDM_CR_ADDR, RESET_TX_ERROR);
- msm_uport->tx.flush = FLUSH_STOP;
- spin_unlock_irqrestore(&uport->lock, flags);
- /* discard flush */
- msm_dmov_flush(msm_uport->dma_tx_channel, 0);
- ret = wait_event_timeout(msm_uport->tx.wait,
- msm_uport->tx.flush == FLUSH_SHUTDOWN, 100);
- if (!ret)
- pr_err("%s():HSUART TX Stalls.\n", __func__);
+ if (!is_blsp_uart(msm_uport)) {
+ spin_lock_irqsave(&uport->lock, flags);
+ /* disable UART TX interface to DM */
+ data = msm_hs_read(uport, UARTDM_DMEN_ADDR);
+ data &= ~UARTDM_TX_DM_EN_BMSK;
+ msm_hs_write(uport, UARTDM_DMEN_ADDR, data);
+ /* turn OFF UART Transmitter */
+ msm_hs_write(uport, UARTDM_CR_ADDR,
+ UARTDM_CR_TX_DISABLE_BMSK);
+ /* reset UART TX */
+ msm_hs_write(uport, UARTDM_CR_ADDR, RESET_TX);
+ /* reset UART TX Error */
+ msm_hs_write(uport, UARTDM_CR_ADDR, RESET_TX_ERROR);
+ msm_uport->tx.flush = FLUSH_STOP;
+ spin_unlock_irqrestore(&uport->lock, flags);
+ /* discard flush */
+ msm_dmov_flush(msm_uport->dma_tx_channel, 0);
+ ret = wait_event_timeout(msm_uport->tx.wait,
+ msm_uport->tx.flush == FLUSH_SHUTDOWN, 100);
+ if (!ret)
+ pr_err("%s():HSUART TX Stalls.\n", __func__);
+ } else {
+ /* BAM Disconnect for TX */
+ sps_disconnect(sps_pipe_handle);
+ }
}
tasklet_kill(&msm_uport->tx.tlet);
BUG_ON(msm_uport->rx.flush < FLUSH_STOP);
@@ -2211,12 +2969,18 @@
.runtime_idle = msm_hs_runtime_idle,
};
+static struct of_device_id msm_hs_match_table[] = {
+ { .compatible = "qcom,msm-hsuart-v14" },
+ {}
+};
+
static struct platform_driver msm_serial_hs_platform_driver = {
.probe = msm_hs_probe,
.remove = __devexit_p(msm_hs_remove),
.driver = {
.name = "msm_serial_hs",
.pm = &msm_hs_dev_pm_ops,
+ .of_match_table = msm_hs_match_table,
},
};
diff --git a/drivers/tty/serial/msm_serial_hs_hwreg.h b/drivers/tty/serial/msm_serial_hs_hwreg.h
index 8debc36..20d6781 100644
--- a/drivers/tty/serial/msm_serial_hs_hwreg.h
+++ b/drivers/tty/serial/msm_serial_hs_hwreg.h
@@ -1,6 +1,6 @@
/* drivers/serial/msm_serial_hs_hwreg.h
*
- * Copyright (c) 2007-2009, 2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2007-2009, 2012-2013,The Linux Foundation. All rights reserved.
*
* All source code in this file is licensed under the following license
* except where indicated.
@@ -59,8 +59,16 @@
#define UARTDM_MR1_ADDR 0x0
#define UARTDM_MR2_ADDR 0x4
+/* Backward Compatability Register for UARTDM Core v1.4 */
+#define UARTDM_BCR_ADDR 0xc8
+
+/*
+ * UARTDM Core v1.4 STALE_IRQ_EMPTY bit defination
+ * Stale interrupt will fire if bit is set when RX-FIFO is empty
+ */
+#define UARTDM_BCR_STALE_IRQ_EMPTY 0x2
+
/* write only register */
-#define UARTDM_CSR_ADDR 0x8
#define UARTDM_CSR_115200 0xFF
#define UARTDM_CSR_57600 0xEE
#define UARTDM_CSR_38400 0xDD
@@ -79,22 +87,11 @@
#define UARTDM_CSR_75 0x00
/* write only register */
-#define UARTDM_TF_ADDR 0x70
-#define UARTDM_TF2_ADDR 0x74
-#define UARTDM_TF3_ADDR 0x78
-#define UARTDM_TF4_ADDR 0x7C
-
-/* write only register */
-#define UARTDM_CR_ADDR 0x10
-/* write only register */
-#define UARTDM_IMR_ADDR 0x14
-
#define UARTDM_IPR_ADDR 0x18
#define UARTDM_TFWR_ADDR 0x1c
#define UARTDM_RFWR_ADDR 0x20
#define UARTDM_HCR_ADDR 0x24
#define UARTDM_DMRX_ADDR 0x34
-#define UARTDM_IRDA_ADDR 0x38
#define UARTDM_DMEN_ADDR 0x3c
/* UART_DM_NO_CHARS_FOR_TX */
@@ -105,21 +102,6 @@
#define UARTDM_SIM_CFG_ADDR 0x80
/* Read Only register */
-#define UARTDM_SR_ADDR 0x8
-
-/* Read Only register */
-#define UARTDM_RF_ADDR 0x70
-#define UARTDM_RF2_ADDR 0x74
-#define UARTDM_RF3_ADDR 0x78
-#define UARTDM_RF4_ADDR 0x7C
-
-/* Read Only register */
-#define UARTDM_MISR_ADDR 0x10
-
-/* Read Only register */
-#define UARTDM_ISR_ADDR 0x14
-#define UARTDM_RX_TOTAL_SNAP_ADDR 0x38
-
#define UARTDM_TXFS_ADDR 0x4C
#define UARTDM_RXFS_ADDR 0x50
@@ -155,11 +137,25 @@
#define RESET_TX_ERROR 0x800
#define RESET_TX_DONE 0x810
+/*
+ * UARTDM_CR BAM IFC comman bit value
+ * for UARTDM Core v1.4
+ */
+#define START_RX_BAM_IFC 0x850
+#define START_TX_BAM_IFC 0x860
+
#define UARTDM_MR1_AUTO_RFR_LEVEL1_BMSK 0xffffff00
#define UARTDM_MR1_AUTO_RFR_LEVEL0_BMSK 0x3f
#define UARTDM_MR1_CTS_CTL_BMSK 0x40
#define UARTDM_MR1_RX_RDY_CTL_BMSK 0x80
+/*
+ * UARTDM Core v1.4 MR2_RFR_CTS_LOOP bitmask
+ * Enables internal loopback between RFR_N of
+ * RX channel and CTS_N of TX channel.
+ */
+#define UARTDM_MR2_RFR_CTS_LOOP_MODE_BMSK 0x400
+
#define UARTDM_MR2_LOOP_MODE_BMSK 0x80
#define UARTDM_MR2_ERROR_MODE_BMSK 0x40
#define UARTDM_MR2_BITS_PER_CHAR_BMSK 0x30
@@ -204,4 +200,110 @@
#define UARTDM_TX_DM_EN_BMSK 0x1
#define UARTDM_RX_DM_EN_BMSK 0x2
+/*
+ * UARTDM Core v1.4 bitmask
+ * Bitmasks for enabling Rx and Tx BAM Interface
+ */
+#define UARTDM_TX_BAM_ENABLE_BMSK 0x4
+#define UARTDM_RX_BAM_ENABLE_BMSK 0x8
+
+/*
+ * Some of the BLSP Based UART Core(v14) existing register offsets
+ * are different compare to GSBI based UART Core(v13)
+ * Hence add the changed register offsets for UART Core v14
+ */
+#ifdef CONFIG_MSM_UARTDM_Core_v14
+
+/* write only register */
+#define UARTDM_CSR_ADDR 0x0a
+
+/* write only register */
+#define UARTDM_TF_ADDR 0x100
+#define UARTDM_TF2_ADDR 0x104
+#define UARTDM_TF3_ADDR 0x108
+#define UARTDM_TF4_ADDR 0x10c
+#define UARTDM_TF5_ADDR 0x110
+#define UARTDM_TF6_ADDR 0x114
+#define UARTDM_TF7_ADDR 0x118
+#define UARTDM_TF8_ADDR 0x11c
+#define UARTDM_TF9_ADDR 0x120
+#define UARTDM_TF10_ADDR 0x124
+#define UARTDM_TF11_ADDR 0x128
+#define UARTDM_TF12_ADDR 0x12c
+#define UARTDM_TF13_ADDR 0x130
+#define UARTDM_TF14_ADDR 0x134
+#define UARTDM_TF15_ADDR 0x138
+#define UARTDM_TF16_ADDR 0x13c
+
+/* write only register */
+#define UARTDM_CR_ADDR 0xa8
+/* write only register */
+#define UARTDM_IMR_ADDR 0xb0
+#define UARTDM_IRDA_ADDR 0xb8
+
+/* Read Only register */
+#define UARTDM_SR_ADDR 0xa4
+
+/* Read Only register */
+#define UARTDM_RF_ADDR 0x140
+#define UARTDM_RF2_ADDR 0x144
+#define UARTDM_RF3_ADDR 0x148
+#define UARTDM_RF4_ADDR 0x14c
+#define UARTDM_RF5_ADDR 0x150
+#define UARTDM_RF6_ADDR 0x154
+#define UARTDM_RF7_ADDR 0x158
+#define UARTDM_RF8_ADDR 0x15c
+#define UARTDM_RF9_ADDR 0x160
+#define UARTDM_RF10_ADDR 0x164
+#define UARTDM_RF11_ADDR 0x168
+#define UARTDM_RF12_ADDR 0x16c
+#define UARTDM_RF13_ADDR 0x170
+#define UARTDM_RF14_ADDR 0x174
+#define UARTDM_RF15_ADDR 0x178
+#define UARTDM_RF16_ADDR 0x17c
+
+/* Read Only register */
+#define UARTDM_MISR_ADDR 0xac
+
+/* Read Only register */
+#define UARTDM_ISR_ADDR 0xb4
+#define UARTDM_RX_TOTAL_SNAP_ADDR 0xbc
+
+#else
+
+/* Register offsets for UART Core v13 */
+
+/* write only register */
+#define UARTDM_CSR_ADDR 0x8
+
+/* write only register */
+#define UARTDM_TF_ADDR 0x70
+#define UARTDM_TF2_ADDR 0x74
+#define UARTDM_TF3_ADDR 0x78
+#define UARTDM_TF4_ADDR 0x7c
+
+/* write only register */
+#define UARTDM_CR_ADDR 0x10
+/* write only register */
+#define UARTDM_IMR_ADDR 0x14
+#define UARTDM_IRDA_ADDR 0x38
+
+/* Read Only register */
+#define UARTDM_SR_ADDR 0x8
+
+/* Read Only register */
+#define UARTDM_RF_ADDR 0x70
+#define UARTDM_RF2_ADDR 0x74
+#define UARTDM_RF3_ADDR 0x78
+#define UARTDM_RF4_ADDR 0x7c
+
+/* Read Only register */
+#define UARTDM_MISR_ADDR 0x10
+
+/* Read Only register */
+#define UARTDM_ISR_ADDR 0x14
+#define UARTDM_RX_TOTAL_SNAP_ADDR 0x38
+
+#endif
+
#endif /* MSM_SERIAL_HS_HWREG_H */
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index 9c7b1ec..9d231d6 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -2115,7 +2115,6 @@
*/
static int _gadget_stop_activity(struct usb_gadget *gadget)
{
- struct usb_ep *ep;
struct ci13xxx *udc = container_of(gadget, struct ci13xxx, gadget);
unsigned long flags;
@@ -2136,20 +2135,10 @@
gadget->host_request = 0;
gadget->otg_srp_reqd = 0;
- /* flush all endpoints */
- gadget_for_each_ep(ep, gadget) {
- usb_ep_fifo_flush(ep);
- }
+ udc->driver->disconnect(gadget);
usb_ep_fifo_flush(&udc->ep0out.ep);
usb_ep_fifo_flush(&udc->ep0in.ep);
- udc->driver->disconnect(gadget);
-
- /* make sure to disable all endpoints */
- gadget_for_each_ep(ep, gadget) {
- usb_ep_disable(ep);
- }
-
if (udc->status != NULL) {
usb_ep_free_request(&udc->ep0in.ep, udc->status);
udc->status = NULL;
diff --git a/drivers/usb/gadget/msm72k_udc.c b/drivers/usb/gadget/msm72k_udc.c
index b408bfd..887a10c 100644
--- a/drivers/usb/gadget/msm72k_udc.c
+++ b/drivers/usb/gadget/msm72k_udc.c
@@ -2,7 +2,7 @@
* Driver for HighSpeed USB Client Controller in MSM7K
*
* Copyright (C) 2008 Google, Inc.
- * Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
* Author: Mike Lockwood <lockwood@android.com>
* Brian Swetland <swetland@google.com>
*
@@ -1649,6 +1649,20 @@
usb_phy_set_power(ui->xceiv, 0);
if (ui->irq) {
+ /* Disable and acknowledge all
+ * USB interrupts before freeing
+ * irq, so that no USB spurious
+ * interrupt occurs during USB cable
+ * disconnect which may lead to
+ * IRQ nobody cared error.
+ */
+ writel_relaxed(0, USB_USBINTR);
+ writel_relaxed(readl_relaxed(USB_USBSTS)
+ , USB_USBSTS);
+ /* Ensure that above STOREs are
+ * completed before enabling
+ * interrupts */
+ wmb();
free_irq(ui->irq, ui);
ui->irq = 0;
}
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index 1141a24..8ab4a6a 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -1625,19 +1625,23 @@
{
struct device_node *node = pdev->dev.of_node;
struct msm_hsic_host_platform_data *pdata;
+ int res_gpio;
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata) {
dev_err(&pdev->dev, "unable to allocate platform data\n");
return NULL;
}
- pdata->strobe = of_get_named_gpio(node, "hsic,strobe-gpio", 0);
- if (pdata->strobe < 0)
- pdata->strobe = 0;
- pdata->data = of_get_named_gpio(node, "hsic,data-gpio", 0);
- if (pdata->data < 0)
- pdata->data = 0;
+ res_gpio = of_get_named_gpio(node, "hsic,strobe-gpio", 0);
+ if (res_gpio < 0)
+ res_gpio = 0;
+ pdata->strobe = res_gpio;
+
+ res_gpio = of_get_named_gpio(node, "hsic,data-gpio", 0);
+ if (res_gpio < 0)
+ res_gpio = 0;
+ pdata->data = res_gpio;
pdata->ignore_cal_pad_config = of_property_read_bool(node,
"hsic,ignore-cal-pad-config");
diff --git a/drivers/usb/misc/ks_bridge.c b/drivers/usb/misc/ks_bridge.c
index dab6e7f..e76a9a8 100644
--- a/drivers/usb/misc/ks_bridge.c
+++ b/drivers/usb/misc/ks_bridge.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2012-2013, 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
@@ -297,6 +297,9 @@
if (!test_bit(USB_DEV_CONNECTED, &ksb->flags))
return -ENODEV;
+ if (count > MAX_DATA_PKT_SIZE)
+ count = MAX_DATA_PKT_SIZE;
+
pkt = ksb_alloc_data_pkt(count, GFP_KERNEL, ksb);
if (IS_ERR(pkt)) {
pr_err("unable to allocate data packet");
diff --git a/drivers/video/msm/mdp4.h b/drivers/video/msm/mdp4.h
index 02cdd71..ed0a385 100644
--- a/drivers/video/msm/mdp4.h
+++ b/drivers/video/msm/mdp4.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2009-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
@@ -955,6 +955,7 @@
int mdp4_pcc_cfg(struct mdp_pcc_cfg_data *cfg_ptr);
int mdp4_argc_cfg(struct mdp_pgc_lut_data *pgc_ptr);
int mdp4_qseed_cfg(struct mdp_qseed_cfg_data *cfg);
+int mdp4_calib_config(struct mdp_calib_config_data *cfg);
int mdp4_qseed_access_cfg(struct mdp_qseed_cfg *cfg, uint32_t base);
u32 mdp4_allocate_writeback_buf(struct msm_fb_data_type *mfd, u32 mix_num);
void mdp4_init_writeback_buf(struct msm_fb_data_type *mfd, u32 mix_num);
diff --git a/drivers/video/msm/mdp4_overlay_dsi_cmd.c b/drivers/video/msm/mdp4_overlay_dsi_cmd.c
index 1d38fb0..5554d88 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_cmd.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_cmd.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. 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
@@ -870,6 +870,9 @@
pipe = vctrl->base_pipe;
}
+ /* TE enabled */
+ mdp4_mipi_vsync_enable(mfd, pipe, 0);
+
MDP_OUTP(MDP_BASE + 0x021c, 10); /* read pointer */
/*
diff --git a/drivers/video/msm/mdp4_util.c b/drivers/video/msm/mdp4_util.c
index 01ec10e..4858073 100644
--- a/drivers/video/msm/mdp4_util.c
+++ b/drivers/video/msm/mdp4_util.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2012, Code Aurora Forum. 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
@@ -3080,6 +3080,108 @@
error:
return ret;
}
+
+static int is_valid_calib_addr(void *addr)
+{
+ int ret = 0;
+ unsigned int ptr;
+
+ if (addr == NULL)
+ goto end;
+
+ ptr = (unsigned int) addr;
+
+ if (mdp_rev >= MDP_REV_30 && mdp_rev < MDP_REV_40) {
+ /* if request is outside the MDP reg-map or is not aligned 4 */
+ if (ptr > 0xF0600 || ptr % 0x4)
+ goto end;
+
+ if (ptr >= 0x90000 && ptr < 0x94000) {
+ if (ptr == 0x90000 || ptr == 0x90070)
+ ret = 1;
+ else if (ptr >= 0x93400 && ptr <= 0x93420)
+ ret = 1;
+ else if (ptr >= 0x93500 && ptr <= 0x93508)
+ ret = 1;
+ else if (ptr >= 0x93580 && ptr <= 0x93588)
+ ret = 1;
+ else if (ptr >= 0x93600 && ptr <= 0x93614)
+ ret = 1;
+ else if (ptr >= 0x93680 && ptr <= 0x93694)
+ ret = 1;
+ else if (ptr >= 0x93800 && ptr <= 0x93BFC)
+ ret = 1;
+ }
+ } else if (mdp_rev >= MDP_REV_40 && mdp_rev <= MDP_REV_44) {
+ /* if request is outside the MDP reg-map or is not aligned 4 */
+ if (ptr > 0xF0600 || ptr % 0x4)
+ goto end;
+
+ if (ptr < 0x90000) {
+ if (ptr == 0x4 || ptr == 0x28200 || ptr == 0x28204)
+ ret = 1;
+ } else if (ptr < 0x95000) {
+ if (ptr == 0x90000 || ptr == 0x90070)
+ ret = 1;
+ else if (ptr >= 0x93400 && ptr <= 0x93420)
+ ret = 1;
+ else if (ptr >= 0x93500 && ptr <= 0x93508)
+ ret = 1;
+ else if (ptr >= 0x93580 && ptr <= 0x93588)
+ ret = 1;
+ else if (ptr >= 0x93600 && ptr <= 0x93614)
+ ret = 1;
+ else if (ptr >= 0x93680 && ptr <= 0x93694)
+ ret = 1;
+ else if (ptr >= 0x94800 && ptr <= 0x94BFC)
+ ret = 1;
+ } else if (ptr < 0x9A000) {
+ if (ptr >= 0x98800 && ptr <= 0x9883C)
+ ret = 1;
+ else if (ptr >= 0x98880 && ptr <= 0x988AC)
+ ret = 1;
+ else if (ptr >= 0x98900 && ptr <= 0x9893C)
+ ret = 1;
+ else if (ptr >= 0x98980 && ptr <= 0x989BC)
+ ret = 1;
+ else if (ptr >= 0x98A00 && ptr <= 0x98A3C)
+ ret = 1;
+ else if (ptr >= 0x98A80 && ptr <= 0x98ABC)
+ ret = 1;
+ else if (ptr >= 0x99000 && ptr <= 0x993FC)
+ ret = 1;
+ else if (ptr >= 0x99800 && ptr <= 0x99BFC)
+ ret = 1;
+ } else if (ptr >= 0x9A000 && ptr <= 0x9a08c) {
+ ret = 1;
+ }
+ }
+end:
+ return ret;
+}
+
+int mdp4_calib_config(struct mdp_calib_config_data *cfg)
+{
+ int ret = -1;
+ void *ptr = (void *) cfg->addr;
+
+ if (is_valid_calib_addr(ptr))
+ ret = 0;
+ else
+ return ret;
+
+ ptr = (void *)(((unsigned int) ptr) + MDP_BASE);
+ mdp_clk_ctrl(1);
+ if (cfg->ops & MDP_PP_OPS_READ) {
+ cfg->data = inpdw(ptr);
+ ret = 1;
+ } else if (cfg->ops & MDP_PP_OPS_WRITE) {
+ outpdw(ptr, cfg->data);
+ }
+ mdp_clk_ctrl(0);
+ return ret;
+}
+
u32 mdp4_get_mixer_num(u32 panel_type)
{
u32 mixer_num;
diff --git a/drivers/video/msm/mdss/Kconfig b/drivers/video/msm/mdss/Kconfig
index 56eb90c..7682a49 100644
--- a/drivers/video/msm/mdss/Kconfig
+++ b/drivers/video/msm/mdss/Kconfig
@@ -12,7 +12,7 @@
The MDSS HDMI Panel provides support for transmitting TMDS signals of
MDSS frame buffer data to connected hdmi compliant TVs, monitors etc.
-config FB_MSM_MDSS_HDMI_MHL_8334
+config FB_MSM_MDSS_HDMI_MHL_SII8334
depends on FB_MSM_MDSS_HDMI_PANEL
bool 'MHL SII8334 support '
default n
diff --git a/drivers/video/msm/mdss/Makefile b/drivers/video/msm/mdss/Makefile
index 4deaa8c..17987d4 100644
--- a/drivers/video/msm/mdss/Makefile
+++ b/drivers/video/msm/mdss/Makefile
@@ -19,7 +19,7 @@
obj-$(CONFIG_FB_MSM_MDSS_HDMI_PANEL) += mdss_hdmi_tx.o
obj-$(CONFIG_FB_MSM_MDSS_HDMI_PANEL) += mdss_hdmi_util.o
obj-$(CONFIG_FB_MSM_MDSS_HDMI_PANEL) += mdss_hdmi_edid.o
-obj-$(CONFIG_FB_MSM_MDSS_HDMI_MHL_8334) += mhl_sii8334.o
+obj-$(CONFIG_FB_MSM_MDSS_HDMI_MHL_SII8334) += mhl_sii8334.o mhl_msc.o
obj-$(CONFIG_FB_MSM_MDSS_HDMI_PANEL) += mdss_hdmi_hdcp.o
obj-$(CONFIG_FB_MSM_MDSS_WRITEBACK) += mdss_wb.o
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index 50723e7..4404b9d 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -2,7 +2,7 @@
* Core MDSS framebuffer driver.
*
* Copyright (C) 2007 Google Incorporated
- * Copyright (c) 2008-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2008-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
@@ -889,20 +889,6 @@
var->hsync_len = panel_info->lcdc.h_pulse_width;
var->pixclock = panel_info->clk_rate / 1000;
- if (panel_info->type == MIPI_VIDEO_PANEL) {
- var->reserved[4] = panel_info->mipi.frame_rate;
- } else {
- var->reserved[4] = panel_info->clk_rate /
- ((panel_info->lcdc.h_back_porch +
- panel_info->lcdc.h_front_porch +
- panel_info->lcdc.h_pulse_width +
- panel_info->xres) *
- (panel_info->lcdc.v_back_porch +
- panel_info->lcdc.v_front_porch +
- panel_info->lcdc.v_pulse_width +
- panel_info->yres));
- }
-
/* id field for fb app */
id = (int *)&mfd->panel;
@@ -1589,6 +1575,23 @@
return ret;
}
+static int mdss_fb_get_metadata(struct msm_fb_data_type *mfd,
+ struct msmfb_metadata *metadata)
+{
+ int ret = 0;
+ switch (metadata->op) {
+ case metadata_op_frame_rate:
+ metadata->data.panel_frame_rate =
+ mdss_get_panel_framerate(mfd);
+ break;
+ default:
+ pr_warn("Unsupported request to MDP META IOCTL.\n");
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
static int mdss_fb_ioctl(struct fb_info *info, unsigned int cmd,
unsigned long arg)
{
@@ -1600,6 +1603,7 @@
struct mdp_page_protection fb_page_protection;
int ret = -ENOSYS;
struct mdp_buf_sync buf_sync;
+ struct msmfb_metadata metadata;
mdss_fb_power_setting_idle(mfd);
@@ -1683,6 +1687,15 @@
ret = mdss_fb_display_commit(info, argp);
break;
+ case MSMFB_METADATA_GET:
+ ret = copy_from_user(&metadata, argp, sizeof(metadata));
+ if (ret)
+ return ret;
+ ret = mdss_fb_get_metadata(mfd, &metadata);
+ if (!ret)
+ ret = copy_to_user(argp, &metadata, sizeof(metadata));
+ break;
+
default:
if (mfd->ioctl_handler)
ret = mfd->ioctl_handler(mfd, cmd, argp);
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index 9503489..ef6e5b4 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. 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
@@ -235,7 +235,6 @@
struct msm_fb_data_type *mfd;
struct mdss_mdp_mixer *mixer;
- struct mutex lock;
struct mdp_overlay req_data;
u32 params_changed;
@@ -326,10 +325,10 @@
struct mdss_mdp_pipe *mdss_mdp_pipe_alloc_pnum(u32 pnum);
-struct mdss_mdp_pipe *mdss_mdp_pipe_alloc_locked(u32 type);
-struct mdss_mdp_pipe *mdss_mdp_pipe_get_locked(u32 ndx);
-int mdss_mdp_pipe_lock(struct mdss_mdp_pipe *pipe);
-void mdss_mdp_pipe_unlock(struct mdss_mdp_pipe *pipe);
+struct mdss_mdp_pipe *mdss_mdp_pipe_alloc(u32 type);
+struct mdss_mdp_pipe *mdss_mdp_pipe_get(u32 ndx);
+int mdss_mdp_pipe_map(struct mdss_mdp_pipe *pipe);
+void mdss_mdp_pipe_unmap(struct mdss_mdp_pipe *pipe);
int mdss_mdp_pipe_destroy(struct mdss_mdp_pipe *pipe);
int mdss_mdp_pipe_queue_data(struct mdss_mdp_pipe *pipe,
@@ -342,6 +341,7 @@
struct mdss_mdp_format_params *mdss_mdp_get_format_params(u32 format);
int mdss_mdp_put_img(struct mdss_mdp_img_data *data);
int mdss_mdp_get_img(struct msmfb_data *img, struct mdss_mdp_img_data *data);
+u32 mdss_get_panel_framerate(struct msm_fb_data_type *mfd);
int mdss_mdp_wb_kickoff(struct mdss_mdp_ctl *ctl);
int mdss_mdp_wb_ioctl_handler(struct msm_fb_data_type *mfd, u32 cmd, void *arg);
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index f62dd24..2f4c2ed 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.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
@@ -784,6 +784,14 @@
stage);
}
+ if (mixercfg == MDSS_MDP_LM_BORDER_COLOR &&
+ pipe->src_fmt->alpha_enable &&
+ pipe->dst.w == mixer->width &&
+ pipe->dst.h == mixer->height) {
+ pr_debug("setting pipe=%d as BG_PIPE\n", pipe->num);
+ bgalpha = 1;
+ }
+
mixercfg |= stage << (3 * pipe->num);
MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_LM_OP_MODE, blend_op);
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index d278554..338cf87 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.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
@@ -39,14 +39,14 @@
{
struct mdss_mdp_pipe *pipe;
- pipe = mdss_mdp_pipe_get_locked(req->id);
- if (pipe == NULL) {
+ pipe = mdss_mdp_pipe_get(req->id);
+ if (IS_ERR_OR_NULL(pipe)) {
pr_err("invalid pipe ndx=%x\n", req->id);
- return -ENODEV;
+ return pipe ? PTR_ERR(pipe) : -ENODEV;
}
*req = pipe->req_data;
- mdss_mdp_pipe_unlock(pipe);
+ mdss_mdp_pipe_unmap(pipe);
return 0;
}
@@ -280,12 +280,12 @@
else
pipe_type = MDSS_MDP_PIPE_TYPE_RGB;
- pipe = mdss_mdp_pipe_alloc_locked(pipe_type);
+ pipe = mdss_mdp_pipe_alloc(pipe_type);
/* VIG pipes can also support RGB format */
if (!pipe && pipe_type == MDSS_MDP_PIPE_TYPE_RGB) {
pipe_type = MDSS_MDP_PIPE_TYPE_VIG;
- pipe = mdss_mdp_pipe_alloc_locked(pipe_type);
+ pipe = mdss_mdp_pipe_alloc(pipe_type);
}
if (pipe == NULL) {
@@ -293,16 +293,23 @@
return -ENOMEM;
}
+ ret = mdss_mdp_pipe_map(pipe);
+ if (ret) {
+ pr_err("unable to map pipe=%d\n", pipe->num);
+ return ret;
+ }
+
mutex_lock(&mfd->lock);
list_add(&pipe->used_list, &mfd->pipes_used);
mutex_unlock(&mfd->lock);
pipe->mixer = mixer;
pipe->mfd = mfd;
+ pipe->play_cnt = 0;
} else {
- pipe = mdss_mdp_pipe_get_locked(req->id);
- if (pipe == NULL) {
+ pipe = mdss_mdp_pipe_get(req->id);
+ if (IS_ERR_OR_NULL(pipe)) {
pr_err("invalid pipe ndx=%x\n", req->id);
- return -ENODEV;
+ return pipe ? PTR_ERR(pipe) : -ENODEV;
}
}
@@ -353,7 +360,7 @@
*ppipe = pipe;
- mdss_mdp_pipe_unlock(pipe);
+ mdss_mdp_pipe_unmap(pipe);
return ret;
}
@@ -498,8 +505,8 @@
pipe_ndx = BIT(i);
if (pipe_ndx & ndx) {
unset_ndx |= pipe_ndx;
- pipe = mdss_mdp_pipe_get_locked(pipe_ndx);
- if (!pipe) {
+ pipe = mdss_mdp_pipe_get(pipe_ndx);
+ if (IS_ERR_OR_NULL(pipe)) {
pr_warn("unknown pipe ndx=%x\n", pipe_ndx);
continue;
}
@@ -508,6 +515,7 @@
list_add(&pipe->cleanup_list, &mfd->pipes_cleanup);
mutex_unlock(&mfd->lock);
mdss_mdp_mixer_pipe_unstage(pipe);
+ mdss_mdp_pipe_unmap(pipe);
}
}
return 0;
@@ -638,10 +646,10 @@
int ret;
u32 flags;
- pipe = mdss_mdp_pipe_get_locked(req->id);
- if (pipe == NULL) {
+ pipe = mdss_mdp_pipe_get(req->id);
+ if (IS_ERR_OR_NULL(pipe)) {
pr_err("pipe ndx=%x doesn't exist\n", req->id);
- return -ENODEV;
+ return pipe ? PTR_ERR(pipe) : -ENODEV;
}
pr_debug("ov queue pnum=%d\n", pipe->num);
@@ -664,7 +672,7 @@
mdss_mdp_overlay_free_buf(src_data);
}
ctl = pipe->mixer->ctl;
- mdss_mdp_pipe_unlock(pipe);
+ mdss_mdp_pipe_unmap(pipe);
return ret;
}
@@ -844,9 +852,12 @@
return;
}
- mdss_mdp_pipe_lock(pipe);
+ if (mdss_mdp_pipe_map(pipe)) {
+ pr_err("unable to map base pipe\n");
+ return;
+ }
ret = mdss_mdp_pipe_queue_data(pipe, &data);
- mdss_mdp_pipe_unlock(pipe);
+ mdss_mdp_pipe_unmap(pipe);
if (ret) {
pr_err("unable to queue data\n");
return;
@@ -859,9 +870,12 @@
pr_err("unable to allocate right base pipe\n");
return;
}
- mdss_mdp_pipe_lock(pipe);
+ if (mdss_mdp_pipe_map(pipe)) {
+ pr_err("unable to map right base pipe\n");
+ return;
+ }
ret = mdss_mdp_pipe_queue_data(pipe, &data);
- mdss_mdp_pipe_unlock(pipe);
+ mdss_mdp_pipe_unmap(pipe);
if (ret) {
pr_err("unable to queue right data\n");
return;
@@ -901,10 +915,15 @@
if (!ctl->set_vsync_handler)
return -ENOTSUPP;
+ rc = mutex_lock_interruptible(&ctl->lock);
+ if (rc)
+ return rc;
+
if (!ctl->power_on) {
pr_debug("fb%d vsync pending first update en=%d\n",
mfd->index, en);
mfd->vsync_pending = en;
+ mutex_unlock(&ctl->lock);
return 0;
}
@@ -925,6 +944,8 @@
rc = ctl->set_vsync_handler(ctl, NULL);
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+ mutex_unlock(&ctl->lock);
+
return rc;
}
@@ -935,13 +956,20 @@
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par;
unsigned long flags;
u64 vsync_ticks;
+ unsigned long timeout;
int ret;
if (!mfd->ctl || !mfd->ctl->power_on)
return 0;
+ timeout = msecs_to_jiffies(VSYNC_PERIOD * 5);
+ if (mfd->ctl->play_cnt == 0) {
+ pr_debug("timegen enable still pending on fb%d\n", mfd->index);
+ timeout <<= 5;
+ }
+
ret = wait_for_completion_interruptible_timeout(&mfd->vsync_comp,
- msecs_to_jiffies(VSYNC_PERIOD * 5));
+ timeout);
if (ret <= 0) {
pr_warn("vsync wait on fb%d interrupted (%d)\n",
mfd->index, ret);
diff --git a/drivers/video/msm/mdss/mdss_mdp_pipe.c b/drivers/video/msm/mdss/mdss_mdp_pipe.c
index ade7cb4..89f3405 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pipe.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pipe.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. 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
@@ -27,6 +27,8 @@
static struct mdss_mdp_pipe mdss_mdp_pipe_list[MDSS_MDP_MAX_SSPP];
+static int mdss_mdp_pipe_free(struct mdss_mdp_pipe *pipe);
+
static u32 mdss_mdp_smp_mmb_reserve(unsigned long *smp, size_t n)
{
u32 i, mmb;
@@ -157,47 +159,43 @@
return 0;
}
-void mdss_mdp_pipe_unlock(struct mdss_mdp_pipe *pipe)
+void mdss_mdp_pipe_unmap(struct mdss_mdp_pipe *pipe)
{
- atomic_dec(&pipe->ref_cnt);
- mutex_unlock(&pipe->lock);
+ int tmp;
+
+ tmp = atomic_dec_return(&pipe->ref_cnt);
+
+ WARN(tmp < 0, "Invalid unmap with ref_cnt=%d", tmp);
+ if (tmp == 0)
+ mdss_mdp_pipe_free(pipe);
}
-int mdss_mdp_pipe_lock(struct mdss_mdp_pipe *pipe)
+int mdss_mdp_pipe_map(struct mdss_mdp_pipe *pipe)
{
- if (atomic_inc_not_zero(&pipe->ref_cnt)) {
- if (mutex_lock_interruptible(&pipe->lock)) {
- atomic_dec(&pipe->ref_cnt);
- return -EINTR;
- }
- return 0;
+ if (!atomic_inc_not_zero(&pipe->ref_cnt)) {
+ pr_err("attempting to map unallocated pipe (%d)", pipe->num);
+ return -EINVAL;
}
- return -EINVAL;
+ return 0;
}
static struct mdss_mdp_pipe *mdss_mdp_pipe_init(u32 pnum)
{
- struct mdss_mdp_pipe *pipe = NULL;
+ struct mdss_mdp_pipe *pipe;
- if (atomic_read(&mdss_mdp_pipe_list[pnum].ref_cnt) == 0) {
- pipe = &mdss_mdp_pipe_list[pnum];
- memset(pipe, 0, sizeof(*pipe));
+ pipe = &mdss_mdp_pipe_list[pnum];
- mutex_init(&pipe->lock);
- atomic_set(&pipe->ref_cnt, 1);
+ if (atomic_cmpxchg(&pipe->ref_cnt, 0, 1) == 0) {
+ pipe->num = pnum;
+ pipe->type = mdss_res->pipe_type_map[pnum];
+ pipe->ndx = BIT(pnum);
- if (mdss_mdp_pipe_lock(pipe) == 0) {
- pipe->num = pnum;
- pipe->type = mdss_res->pipe_type_map[pnum];
- pipe->ndx = BIT(pnum);
+ pr_debug("ndx=%x pnum=%d\n", pipe->ndx, pipe->num);
- pr_debug("ndx=%x pnum=%d\n", pipe->ndx, pipe->num);
- } else {
- atomic_set(&pipe->ref_cnt, 0);
- pipe = NULL;
- }
+ return pipe;
}
- return pipe;
+
+ return NULL;
}
struct mdss_mdp_pipe *mdss_mdp_pipe_alloc_pnum(u32 pnum)
@@ -210,7 +208,7 @@
return pipe;
}
-struct mdss_mdp_pipe *mdss_mdp_pipe_alloc_locked(u32 type)
+struct mdss_mdp_pipe *mdss_mdp_pipe_alloc(u32 type)
{
struct mdss_mdp_pipe *pipe = NULL;
int pnum;
@@ -228,57 +226,60 @@
return pipe;
}
-struct mdss_mdp_pipe *mdss_mdp_pipe_get_locked(u32 ndx)
+struct mdss_mdp_pipe *mdss_mdp_pipe_get(u32 ndx)
{
struct mdss_mdp_pipe *pipe = NULL;
int i;
if (!ndx)
- return NULL;
+ return ERR_PTR(-EINVAL);
mutex_lock(&mdss_mdp_sspp_lock);
for (i = 0; i < MDSS_MDP_MAX_SSPP; i++) {
pipe = &mdss_mdp_pipe_list[i];
- if (ndx == pipe->ndx)
+ if (ndx == pipe->ndx) {
+ if (mdss_mdp_pipe_map(pipe))
+ pipe = ERR_PTR(-EACCES);
break;
+ }
}
mutex_unlock(&mdss_mdp_sspp_lock);
if (i == MDSS_MDP_MAX_SSPP)
- return NULL;
-
- if (mdss_mdp_pipe_lock(pipe))
- return NULL;
-
- if (pipe->ndx != ndx) {
- mdss_mdp_pipe_unlock(pipe);
- pipe = NULL;
- }
+ return ERR_PTR(-ENODEV);
return pipe;
}
-
-static void mdss_mdp_pipe_free(struct mdss_mdp_pipe *pipe)
-{
- mdss_mdp_smp_free(pipe);
- pipe->ndx = 0;
- atomic_dec(&pipe->ref_cnt);
- mdss_mdp_pipe_unlock(pipe);
-}
-
-int mdss_mdp_pipe_destroy(struct mdss_mdp_pipe *pipe)
+static int mdss_mdp_pipe_free(struct mdss_mdp_pipe *pipe)
{
pr_debug("ndx=%x pnum=%d ref_cnt=%d\n", pipe->ndx, pipe->num,
atomic_read(&pipe->ref_cnt));
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
- mdss_mdp_pipe_free(pipe);
+ mdss_mdp_smp_free(pipe);
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
return 0;
}
+int mdss_mdp_pipe_destroy(struct mdss_mdp_pipe *pipe)
+{
+ int tmp;
+
+ tmp = atomic_dec_return(&pipe->ref_cnt);
+
+ if (tmp != 0) {
+ pr_err("unable to free pipe %d while still in use (%d)\n",
+ pipe->num, tmp);
+ return -EBUSY;
+ }
+ mdss_mdp_pipe_free(pipe);
+
+ return 0;
+
+}
+
static inline void mdss_mdp_pipe_write(struct mdss_mdp_pipe *pipe,
u32 reg, u32 val)
{
diff --git a/drivers/video/msm/mdss/mdss_mdp_rotator.c b/drivers/video/msm/mdss/mdss_mdp_rotator.c
index 1e58269..a151b38 100644
--- a/drivers/video/msm/mdss/mdss_mdp_rotator.c
+++ b/drivers/video/msm/mdss/mdss_mdp_rotator.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
@@ -89,7 +89,7 @@
pipe = mdss_mdp_pipe_alloc_pnum(pnum);
- if (pipe)
+ if (!IS_ERR_OR_NULL(pipe))
pipe->mixer = mixer;
done:
if (!pipe)
diff --git a/drivers/video/msm/mdss/mdss_mdp_util.c b/drivers/video/msm/mdss/mdss_mdp_util.c
index 9f2df85..75a926a 100644
--- a/drivers/video/msm/mdss/mdss_mdp_util.c
+++ b/drivers/video/msm/mdss/mdss_mdp_util.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
@@ -29,6 +29,8 @@
#include "mdss_mdp.h"
#include "mdss_mdp_formats.h"
+#define DEFAULT_FRAME_RATE 60
+
enum {
MDP_INTR_VSYNC_INTF_0,
MDP_INTR_VSYNC_INTF_1,
@@ -433,3 +435,26 @@
return ret;
}
+
+u32 mdss_get_panel_framerate(struct msm_fb_data_type *mfd)
+{
+ u32 frame_rate = DEFAULT_FRAME_RATE;
+ u32 pixel_total;
+ struct mdss_panel_info *panel_info = mfd->panel_info;
+
+ if (panel_info->type == MIPI_VIDEO_PANEL) {
+ frame_rate = panel_info->mipi.frame_rate;
+ } else {
+ pixel_total = (panel_info->lcdc.h_back_porch +
+ panel_info->lcdc.h_front_porch +
+ panel_info->lcdc.h_pulse_width +
+ panel_info->xres) *
+ (panel_info->lcdc.v_back_porch +
+ panel_info->lcdc.v_front_porch +
+ panel_info->lcdc.v_pulse_width +
+ panel_info->yres);
+ if (pixel_total)
+ frame_rate = panel_info->clk_rate / pixel_total;
+ }
+ return frame_rate;
+}
diff --git a/drivers/video/msm/mdss/mhl_msc.c b/drivers/video/msm/mdss/mhl_msc.c
new file mode 100644
index 0000000..94f6d2b
--- /dev/null
+++ b/drivers/video/msm/mdss/mhl_msc.c
@@ -0,0 +1,489 @@
+/* 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/types.h>
+#include <linux/mhl_8334.h>
+#include <linux/vmalloc.h>
+#include <linux/input.h>
+#include "mhl_msc.h"
+
+static struct mhl_tx_ctrl *mhl_ctrl;
+static DEFINE_MUTEX(msc_send_workqueue_mutex);
+
+const char *devcap_reg_name[] = {
+ "DEV_STATE ",
+ "MHL_VERSION ",
+ "DEV_CAT ",
+ "ADOPTER_ID_H ",
+ "ADOPTER_ID_L ",
+ "VID_LINK_MODE ",
+ "AUD_LINK_MODE ",
+ "VIDEO_TYPE ",
+ "LOG_DEV_MAP ",
+ "BANDWIDTH ",
+ "FEATURE_FLAG ",
+ "DEVICE_ID_H ",
+ "DEVICE_ID_L ",
+ "SCRATCHPAD_SIZE ",
+ "INT_STAT_SIZE ",
+ "Reserved ",
+};
+
+static void mhl_print_devcap(u8 offset, u8 devcap)
+{
+ switch (offset) {
+ case DEVCAP_OFFSET_DEV_CAT:
+ pr_debug("DCAP: %02X %s: %02X DEV_TYPE=%X POW=%s\n",
+ offset, devcap_reg_name[offset], devcap,
+ devcap & 0x0F, (devcap & 0x10) ? "y" : "n");
+ break;
+ case DEVCAP_OFFSET_FEATURE_FLAG:
+ pr_debug("DCAP: %02X %s: %02X RCP=%s RAP=%s SP=%s\n",
+ offset, devcap_reg_name[offset], devcap,
+ (devcap & 0x01) ? "y" : "n",
+ (devcap & 0x02) ? "y" : "n",
+ (devcap & 0x04) ? "y" : "n");
+ break;
+ default:
+ pr_debug("DCAP: %02X %s: %02X\n",
+ offset, devcap_reg_name[offset], devcap);
+ break;
+ }
+}
+
+void mhl_register_msc(struct mhl_tx_ctrl *ctrl)
+{
+ if (ctrl)
+ mhl_ctrl = ctrl;
+}
+
+void mhl_msc_send_work(struct work_struct *work)
+{
+ struct mhl_tx_ctrl *mhl_ctrl =
+ container_of(work, struct mhl_tx_ctrl, mhl_msc_send_work);
+ struct msc_cmd_envelope *cmd_env;
+ int ret;
+ /*
+ * Remove item from the queue
+ * and schedule it
+ */
+ mutex_lock(&msc_send_workqueue_mutex);
+ while (!list_empty(&mhl_ctrl->list_cmd)) {
+ cmd_env = list_first_entry(&mhl_ctrl->list_cmd,
+ struct msc_cmd_envelope,
+ msc_queue_envelope);
+ list_del(&cmd_env->msc_queue_envelope);
+ mutex_unlock(&msc_send_workqueue_mutex);
+
+ ret = mhl_send_msc_command(mhl_ctrl, &cmd_env->msc_cmd_msg);
+ if (ret == -EAGAIN) {
+ int retry = 2;
+ while (retry--) {
+ ret = mhl_send_msc_command(
+ mhl_ctrl,
+ &cmd_env->msc_cmd_msg);
+ if (ret != -EAGAIN)
+ break;
+ }
+ }
+ if (ret == -EAGAIN)
+ pr_err("%s: send_msc_command retry out!\n", __func__);
+
+ vfree(cmd_env);
+ mutex_lock(&msc_send_workqueue_mutex);
+ }
+ mutex_unlock(&msc_send_workqueue_mutex);
+}
+
+int mhl_queue_msc_command(struct mhl_tx_ctrl *mhl_ctrl,
+ struct msc_command_struct *req,
+ int priority_send)
+{
+ struct msc_cmd_envelope *cmd_env;
+
+ mutex_lock(&msc_send_workqueue_mutex);
+ cmd_env = vmalloc(sizeof(struct msc_cmd_envelope));
+ if (!cmd_env) {
+ pr_err("%s: out of memory!\n", __func__);
+ return -ENOMEM;
+ }
+
+ memcpy(&cmd_env->msc_cmd_msg, req,
+ sizeof(struct msc_command_struct));
+
+ if (priority_send)
+ list_add(&cmd_env->msc_queue_envelope,
+ &mhl_ctrl->list_cmd);
+ else
+ list_add_tail(&cmd_env->msc_queue_envelope,
+ &mhl_ctrl->list_cmd);
+ mutex_unlock(&msc_send_workqueue_mutex);
+ queue_work(mhl_ctrl->msc_send_workqueue, &mhl_ctrl->mhl_msc_send_work);
+
+ return 0;
+}
+
+static int mhl_update_devcap(struct mhl_tx_ctrl *mhl_ctrl,
+ int offset, u8 devcap)
+{
+ if (!mhl_ctrl)
+ return -EFAULT;
+ if (offset < 0 || offset > 15)
+ return -EFAULT;
+ mhl_ctrl->devcap[offset] = devcap;
+ mhl_print_devcap(offset, mhl_ctrl->devcap[offset]);
+
+ return 0;
+}
+
+
+int mhl_msc_command_done(struct mhl_tx_ctrl *mhl_ctrl,
+ struct msc_command_struct *req)
+{
+ switch (req->command) {
+ case MHL_WRITE_STAT:
+ if (req->offset == MHL_STATUS_REG_LINK_MODE) {
+ if (req->payload.data[0]
+ & MHL_STATUS_PATH_ENABLED)
+ /* Enable TMDS output */
+ mhl_tmds_ctrl(mhl_ctrl, TMDS_ENABLE);
+ else
+ /* Disable TMDS output */
+ mhl_tmds_ctrl(mhl_ctrl, TMDS_DISABLE);
+ }
+ break;
+ case MHL_READ_DEVCAP:
+ mhl_update_devcap(mhl_ctrl,
+ req->offset, req->retval);
+ mhl_ctrl->devcap_state |= BIT(req->offset);
+ switch (req->offset) {
+ case MHL_DEV_CATEGORY_OFFSET:
+ if (req->retval & MHL_DEV_CATEGORY_POW_BIT)
+ pr_debug("%s: devcap pow bit set\n",
+ __func__);
+ else
+ pr_debug("%s: devcap pow bit unset\n",
+ __func__);
+ break;
+ case DEVCAP_OFFSET_MHL_VERSION:
+ case DEVCAP_OFFSET_INT_STAT_SIZE:
+ break;
+ }
+
+ break;
+ }
+ return 0;
+}
+
+int mhl_msc_send_set_int(struct mhl_tx_ctrl *mhl_ctrl,
+ u8 offset, u8 mask)
+{
+ struct msc_command_struct req;
+ req.command = MHL_SET_INT;
+ req.offset = offset;
+ req.payload.data[0] = mask;
+ return mhl_queue_msc_command(mhl_ctrl, &req, MSC_NORMAL_SEND);
+}
+
+int mhl_msc_send_write_stat(struct mhl_tx_ctrl *mhl_ctrl,
+ u8 offset, u8 value)
+{
+ struct msc_command_struct req;
+ req.command = MHL_WRITE_STAT;
+ req.offset = offset;
+ req.payload.data[0] = value;
+ return mhl_queue_msc_command(mhl_ctrl, &req, MSC_NORMAL_SEND);
+}
+
+int mhl_msc_send_msc_msg(struct mhl_tx_ctrl *mhl_ctrl,
+ u8 sub_cmd, u8 cmd_data)
+{
+ struct msc_command_struct req;
+ req.command = MHL_MSC_MSG;
+ req.payload.data[0] = sub_cmd;
+ req.payload.data[1] = cmd_data;
+ return mhl_queue_msc_command(mhl_ctrl, &req, MSC_NORMAL_SEND);
+}
+
+/*
+ * Certain MSC msgs such as RCPK, RCPE and RAPK
+ * should be transmitted as a high priority
+ * because these msgs should be sent within
+ * 1000ms of a receipt of RCP/RAP. So such msgs can
+ * be added to the head of msc cmd queue.
+ */
+static int mhl_msc_send_prior_msc_msg(struct mhl_tx_ctrl *mhl_ctrl,
+ u8 sub_cmd, u8 cmd_data)
+{
+ struct msc_command_struct req;
+ req.command = MHL_MSC_MSG;
+ req.payload.data[0] = sub_cmd;
+ req.payload.data[1] = cmd_data;
+ return mhl_queue_msc_command(mhl_ctrl, &req, MSC_PRIORITY_SEND);
+}
+
+
+int mhl_msc_read_devcap(struct mhl_tx_ctrl *mhl_ctrl, u8 offset)
+{
+ struct msc_command_struct req;
+ if (offset < 0 || offset > 15)
+ return -EFAULT;
+ req.command = MHL_READ_DEVCAP;
+ req.offset = offset;
+ req.payload.data[0] = 0;
+ return mhl_queue_msc_command(mhl_ctrl, &req, MSC_NORMAL_SEND);
+}
+
+int mhl_msc_read_devcap_all(struct mhl_tx_ctrl *mhl_ctrl)
+{
+ int offset;
+ int ret;
+
+ for (offset = 0; offset < DEVCAP_SIZE; offset++) {
+ ret = mhl_msc_read_devcap(mhl_ctrl, offset);
+ if (ret == -EBUSY)
+ pr_err("%s: queue busy!\n", __func__);
+ }
+ return ret;
+}
+
+
+static void mhl_handle_input(struct mhl_tx_ctrl *mhl_ctrl,
+ u8 key_code, u16 input_key_code)
+{
+ int key_press = (key_code & 0x80) == 0;
+
+ pr_debug("%s: send key events[%x][%d]\n",
+ __func__, key_code, key_press);
+ input_report_key(mhl_ctrl->input, input_key_code, key_press);
+ input_sync(mhl_ctrl->input);
+}
+
+
+
+int mhl_rcp_recv(struct mhl_tx_ctrl *mhl_ctrl, u8 key_code)
+{
+ u8 index = key_code & 0x7f;
+ u16 input_key_code;
+
+ if (!mhl_ctrl->rcp_key_code_tbl) {
+ pr_err("%s: RCP Key Code Table not initialized\n", __func__);
+ return -EINVAL;
+ }
+
+ input_key_code = mhl_ctrl->rcp_key_code_tbl[index];
+
+ if ((index < mhl_ctrl->rcp_key_code_tbl_len) &&
+ (input_key_code > 0)) {
+ /* prior send rcpk */
+ mhl_msc_send_prior_msc_msg(
+ mhl_ctrl,
+ MHL_MSC_MSG_RCPK,
+ key_code);
+
+ if (mhl_ctrl->input)
+ mhl_handle_input(mhl_ctrl, key_code, input_key_code);
+ } else {
+ /* prior send rcpe */
+ mhl_msc_send_prior_msc_msg(
+ mhl_ctrl,
+ MHL_MSC_MSG_RCPE,
+ MHL_RCPE_INEFFECTIVE_KEY_CODE);
+
+ /* send rcpk after rcpe send */
+ mhl_msc_send_prior_msc_msg(
+ mhl_ctrl,
+ MHL_MSC_MSG_RCPK,
+ key_code);
+ }
+ return 0;
+}
+
+
+static int mhl_rap_action(struct mhl_tx_ctrl *mhl_ctrl, u8 action_code)
+{
+ switch (action_code) {
+ case MHL_RAP_CONTENT_ON:
+ mhl_tmds_ctrl(mhl_ctrl, TMDS_ENABLE);
+ break;
+ case MHL_RAP_CONTENT_OFF:
+ mhl_tmds_ctrl(mhl_ctrl, TMDS_DISABLE);
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+static int mhl_rap_recv(struct mhl_tx_ctrl *mhl_ctrl, u8 action_code)
+{
+ u8 error_code;
+
+ switch (action_code) {
+ case MHL_RAP_POLL:
+ if (mhl_ctrl->tmds_enabled())
+ error_code = MHL_RAPK_NO_ERROR;
+ else
+ error_code = MHL_RAPK_UNSUPPORTED_ACTION_CODE;
+ break;
+ case MHL_RAP_CONTENT_ON:
+ case MHL_RAP_CONTENT_OFF:
+ mhl_rap_action(mhl_ctrl, action_code);
+ error_code = MHL_RAPK_NO_ERROR;
+ break;
+ default:
+ error_code = MHL_RAPK_UNRECOGNIZED_ACTION_CODE;
+ break;
+ }
+ /* prior send rapk */
+ return mhl_msc_send_prior_msc_msg(
+ mhl_ctrl,
+ MHL_MSC_MSG_RAPK,
+ error_code);
+}
+
+
+int mhl_msc_recv_msc_msg(struct mhl_tx_ctrl *mhl_ctrl,
+ u8 sub_cmd, u8 cmd_data)
+{
+ int rc = 0;
+ switch (sub_cmd) {
+ case MHL_MSC_MSG_RCP:
+ pr_debug("MHL: receive RCP(0x%02x)\n", cmd_data);
+ rc = mhl_rcp_recv(mhl_ctrl, cmd_data);
+ break;
+ case MHL_MSC_MSG_RCPK:
+ pr_debug("MHL: receive RCPK(0x%02x)\n", cmd_data);
+ break;
+ case MHL_MSC_MSG_RCPE:
+ pr_debug("MHL: receive RCPE(0x%02x)\n", cmd_data);
+ break;
+ case MHL_MSC_MSG_RAP:
+ pr_debug("MHL: receive RAP(0x%02x)\n", cmd_data);
+ rc = mhl_rap_recv(mhl_ctrl, cmd_data);
+ break;
+ case MHL_MSC_MSG_RAPK:
+ pr_debug("MHL: receive RAPK(0x%02x)\n", cmd_data);
+ break;
+ default:
+ break;
+ }
+ return rc;
+}
+
+int mhl_msc_recv_set_int(struct mhl_tx_ctrl *mhl_ctrl,
+ u8 offset, u8 set_int)
+{
+ if (offset >= 2)
+ return -EFAULT;
+
+ switch (offset) {
+ case 0:
+ if (set_int & MHL_INT_DCAP_CHG) {
+ /* peer dcap has changed */
+ mhl_ctrl->devcap_state = 0;
+ mhl_msc_read_devcap_all(mhl_ctrl);
+ }
+ if (set_int & MHL_INT_DSCR_CHG)
+ pr_debug("%s: dscr chg\n", __func__);
+ if (set_int & MHL_INT_REQ_WRT) {
+ /* SET_INT: GRT_WRT */
+ mhl_msc_send_set_int(
+ mhl_ctrl,
+ MHL_RCHANGE_INT,
+ MHL_INT_GRT_WRT);
+ }
+ if (set_int & MHL_INT_GRT_WRT)
+ pr_debug("%s: recvd req to permit/grant write",
+ __func__);
+ break;
+ case 1:
+ if (set_int & MHL_INT_EDID_CHG) {
+ /* peer EDID has changed
+ * toggle HPD to read EDID
+ */
+ pr_debug("%s: EDID CHG\n", __func__);
+ mhl_drive_hpd(mhl_ctrl, HPD_DOWN);
+ msleep(110);
+ mhl_drive_hpd(mhl_ctrl, HPD_UP);
+ }
+ }
+ return 0;
+}
+
+int mhl_msc_recv_write_stat(struct mhl_tx_ctrl *mhl_ctrl,
+ u8 offset, u8 value)
+{
+ if (offset >= 2)
+ return -EFAULT;
+
+ switch (offset) {
+ case 0:
+ /*
+ * connected device bits
+ * changed and DEVCAP READY
+ */
+ if (((value ^ mhl_ctrl->devcap_state) &
+ MHL_STATUS_DCAP_RDY)) {
+ if (value & MHL_STATUS_DCAP_RDY) {
+ mhl_ctrl->devcap_state = 0;
+ mhl_msc_read_devcap_all(mhl_ctrl);
+ } else {
+ /*
+ * peer dcap turned not ready
+ * use old devap state
+ */
+ pr_debug("%s: DCAP RDY bit cleared\n",
+ __func__);
+ }
+ }
+ break;
+ case 1:
+ /*
+ * connected device bits
+ * changed and PATH ENABLED
+ * bit set
+ */
+ if ((value ^ mhl_ctrl->path_en_state)
+ & MHL_STATUS_PATH_ENABLED) {
+ if (value & MHL_STATUS_PATH_ENABLED) {
+ if (mhl_ctrl->tmds_enabled() &&
+ (mhl_ctrl->devcap[offset] &
+ MHL_FEATURE_RAP_SUPPORT)) {
+ mhl_msc_send_msc_msg(
+ mhl_ctrl,
+ MHL_MSC_MSG_RAP,
+ MHL_RAP_CONTENT_ON);
+ }
+ mhl_ctrl->path_en_state
+ |= (MHL_STATUS_PATH_ENABLED |
+ MHL_STATUS_CLK_MODE_NORMAL);
+ mhl_msc_send_write_stat(
+ mhl_ctrl,
+ MHL_STATUS_REG_LINK_MODE,
+ mhl_ctrl->path_en_state);
+ } else {
+ mhl_ctrl->path_en_state
+ &= ~(MHL_STATUS_PATH_ENABLED |
+ MHL_STATUS_CLK_MODE_NORMAL);
+ mhl_msc_send_write_stat(
+ mhl_ctrl,
+ MHL_STATUS_REG_LINK_MODE,
+ mhl_ctrl->path_en_state);
+ }
+ }
+ break;
+ }
+ mhl_ctrl->path_en_state = value;
+ return 0;
+}
diff --git a/drivers/video/msm/mdss/mhl_msc.h b/drivers/video/msm/mdss/mhl_msc.h
new file mode 100644
index 0000000..9a7b3d6
--- /dev/null
+++ b/drivers/video/msm/mdss/mhl_msc.h
@@ -0,0 +1,57 @@
+/* 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 __MHL_MSC_H__
+#define __MHL_MSC_H__
+#include <linux/mhl_8334.h>
+
+#define MAX_RCP_KEYS_SUPPORTED 256
+
+#define MSC_NORMAL_SEND 0
+#define MSC_PRIORITY_SEND 1
+
+#define TMDS_ENABLE 1
+#define TMDS_DISABLE 0
+
+/******************************************************************/
+/* the below APIs are implemented by the MSC functionality */
+int mhl_msc_command_done(struct mhl_tx_ctrl *mhl_ctrl,
+ struct msc_command_struct *req);
+
+int mhl_msc_send_set_int(struct mhl_tx_ctrl *mhl_ctrl,
+ u8 offset, u8 mask);
+
+int mhl_msc_send_write_stat(struct mhl_tx_ctrl *mhl_ctrl,
+ u8 offset, u8 value);
+int mhl_msc_send_msc_msg(struct mhl_tx_ctrl *mhl_ctrl,
+ u8 sub_cmd, u8 cmd_data);
+
+int mhl_msc_recv_set_int(struct mhl_tx_ctrl *mhl_ctrl, u8 offset, u8 set_int);
+
+int mhl_msc_recv_write_stat(struct mhl_tx_ctrl *mhl_ctrl,
+ u8 offset, u8 value);
+int mhl_msc_recv_msc_msg(struct mhl_tx_ctrl *mhl_ctrl,
+ u8 sub_cmd, u8 cmd_data);
+void mhl_msc_send_work(struct work_struct *work);
+
+/******************************************************************/
+/* Tx should implement these APIs */
+int mhl_send_msc_command(struct mhl_tx_ctrl *mhl_ctrl,
+ struct msc_command_struct *req);
+void mhl_drive_hpd(struct mhl_tx_ctrl *mhl_ctrl, uint8_t to_state);
+void mhl_tmds_ctrl(struct mhl_tx_ctrl *ctrl, uint8_t on);
+/******************************************************************/
+/* MHL driver registers ctrl with MSC */
+void mhl_register_msc(struct mhl_tx_ctrl *ctrl);
+
+#endif /* __MHL_MSC_H__ */
diff --git a/drivers/video/msm/mdss/mhl_sii8334.c b/drivers/video/msm/mdss/mhl_sii8334.c
index f3be983..7baeef5 100644
--- a/drivers/video/msm/mdss/mhl_sii8334.c
+++ b/drivers/video/msm/mdss/mhl_sii8334.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
@@ -18,6 +18,8 @@
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/types.h>
+#include <linux/vmalloc.h>
+#include <linux/input.h>
#include <linux/usb/msm_hsusb.h>
#include <linux/mhl_8334.h>
@@ -27,6 +29,7 @@
#include "mdss.h"
#include "mdss_panel.h"
#include "mdss_io_util.h"
+#include "mhl_msc.h"
#define MHL_DRIVER_NAME "sii8334"
#define COMPATIBLE_NAME "qcom,mhl-sii8334"
@@ -34,39 +37,142 @@
#define pr_debug_intr(...) pr_debug("\n")
-enum mhl_gpio_type {
- MHL_TX_RESET_GPIO,
- MHL_TX_INTR_GPIO,
- MHL_TX_PMIC_PWR_GPIO,
- MHL_TX_MAX_GPIO,
-};
+#define MSC_START_BIT_MSC_CMD (0x01 << 0)
+#define MSC_START_BIT_VS_CMD (0x01 << 1)
+#define MSC_START_BIT_READ_REG (0x01 << 2)
+#define MSC_START_BIT_WRITE_REG (0x01 << 3)
+#define MSC_START_BIT_WRITE_BURST (0x01 << 4)
-enum mhl_vreg_type {
- MHL_TX_3V_VREG,
- MHL_TX_MAX_VREG,
-};
-
-struct mhl_tx_platform_data {
- /* Data filled from device tree nodes */
- struct dss_gpio *gpios[MHL_TX_MAX_GPIO];
- struct dss_vreg *vregs[MHL_TX_MAX_VREG];
- int irq;
-};
-
-struct mhl_tx_ctrl {
- struct platform_device *pdev;
- struct mhl_tx_platform_data *pdata;
- struct i2c_client *i2c_handle;
- uint8_t cur_state;
- uint8_t chip_rev_id;
- int mhl_mode;
- struct completion rgnd_done;
- void (*notify_usb_online)(int online);
- struct usb_ext_notification *mhl_info;
- bool disc_enabled;
- struct power_supply mhl_psy;
- bool vbus_active;
- int current_val;
+/* supported RCP key code */
+u16 support_rcp_key_code_tbl[] = {
+ KEY_ENTER, /* 0x00 Select */
+ KEY_UP, /* 0x01 Up */
+ KEY_DOWN, /* 0x02 Down */
+ KEY_LEFT, /* 0x03 Left */
+ KEY_RIGHT, /* 0x04 Right */
+ KEY_UNKNOWN, /* 0x05 Right-up */
+ KEY_UNKNOWN, /* 0x06 Right-down */
+ KEY_UNKNOWN, /* 0x07 Left-up */
+ KEY_UNKNOWN, /* 0x08 Left-down */
+ KEY_MENU, /* 0x09 Root Menu */
+ KEY_OPTION, /* 0x0A Setup Menu */
+ KEY_UNKNOWN, /* 0x0B Contents Menu */
+ KEY_UNKNOWN, /* 0x0C Favorite Menu */
+ KEY_EXIT, /* 0x0D Exit */
+ KEY_RESERVED, /* 0x0E */
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED, /* 0x1F */
+ KEY_NUMERIC_0, /* 0x20 NUMERIC_0 */
+ KEY_NUMERIC_1, /* 0x21 NUMERIC_1 */
+ KEY_NUMERIC_2, /* 0x22 NUMERIC_2 */
+ KEY_NUMERIC_3, /* 0x23 NUMERIC_3 */
+ KEY_NUMERIC_4, /* 0x24 NUMERIC_4 */
+ KEY_NUMERIC_5, /* 0x25 NUMERIC_5 */
+ KEY_NUMERIC_6, /* 0x26 NUMERIC_6 */
+ KEY_NUMERIC_7, /* 0x27 NUMERIC_7 */
+ KEY_NUMERIC_8, /* 0x28 NUMERIC_8 */
+ KEY_NUMERIC_9, /* 0x29 NUMERIC_9 */
+ KEY_DOT, /* 0x2A Dot */
+ KEY_ENTER, /* 0x2B Enter */
+ KEY_ESC, /* 0x2C Clear */
+ KEY_RESERVED, /* 0x2D */
+ KEY_RESERVED, /* 0x2E */
+ KEY_RESERVED, /* 0x2F */
+ KEY_UNKNOWN, /* 0x30 Channel Up */
+ KEY_UNKNOWN, /* 0x31 Channel Down */
+ KEY_UNKNOWN, /* 0x32 Previous Channel */
+ KEY_UNKNOWN, /* 0x33 Sound Select */
+ KEY_UNKNOWN, /* 0x34 Input Select */
+ KEY_UNKNOWN, /* 0x35 Show Information */
+ KEY_UNKNOWN, /* 0x36 Help */
+ KEY_UNKNOWN, /* 0x37 Page Up */
+ KEY_UNKNOWN, /* 0x38 Page Down */
+ KEY_RESERVED, /* 0x39 */
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED, /* 0x3F */
+ KEY_RESERVED, /* 0x40 */
+ KEY_VOLUMEUP, /* 0x41 Volume Up */
+ KEY_VOLUMEDOWN, /* 0x42 Volume Down */
+ KEY_MUTE, /* 0x43 Mute */
+ KEY_PLAY, /* 0x44 Play */
+ KEY_STOP, /* 0x45 Stop */
+ KEY_PAUSE, /* 0x46 Pause */
+ KEY_UNKNOWN, /* 0x47 Record */
+ KEY_REWIND, /* 0x48 Rewind */
+ KEY_FASTFORWARD, /* 0x49 Fast Forward */
+ KEY_UNKNOWN, /* 0x4A Eject */
+ KEY_FORWARD, /* 0x4B Forward */
+ KEY_BACK, /* 0x4C Backward */
+ KEY_RESERVED, /* 0x4D */
+ KEY_RESERVED,
+ KEY_RESERVED, /* 0x4F */
+ KEY_UNKNOWN, /* 0x50 Angle */
+ KEY_UNKNOWN, /* 0x51 Subtitle */
+ KEY_RESERVED, /* 0x52 */
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED, /* 0x5F */
+ KEY_PLAYPAUSE, /* 0x60 Play Function */
+ KEY_PLAYPAUSE, /* 0x61 Pause_Play Function */
+ KEY_UNKNOWN, /* 0x62 Record Function */
+ KEY_PAUSE, /* 0x63 Pause Record Function */
+ KEY_STOP, /* 0x64 Stop Function */
+ KEY_MUTE, /* 0x65 Mute Function */
+ KEY_UNKNOWN, /* 0x66 Restore Volume Function */
+ KEY_UNKNOWN, /* 0x67 Tune Function */
+ KEY_UNKNOWN, /* 0x68 Select Media Function */
+ KEY_RESERVED, /* 0x69 */
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED, /* 0x70 */
+ KEY_BLUE, /* 0x71 F1 */
+ KEY_RED, /* 0x72 F2 */
+ KEY_GREEN, /* 0x73 F3 */
+ KEY_YELLOW, /* 0x74 F4 */
+ KEY_UNKNOWN, /* 0x75 F5 */
+ KEY_RESERVED, /* 0x76 */
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED, /* 0x7D */
+ KEY_VENDOR, /* Vendor Specific */
+ KEY_RESERVED, /* 0x7F */
};
@@ -84,13 +190,12 @@
static irqreturn_t mhl_tx_isr(int irq, void *dev_id);
static void switch_mode(struct mhl_tx_ctrl *mhl_ctrl,
enum mhl_st_type to_mode);
-static void mhl_drive_hpd(struct mhl_tx_ctrl *mhl_ctrl,
- uint8_t to_state);
-
static void mhl_init_reg_settings(struct mhl_tx_ctrl *mhl_ctrl,
- bool mhl_disc_en);
+ bool mhl_disc_en);
-static int mhl_i2c_reg_read(struct i2c_client *client,
+static uint8_t store_tmds_state;
+
+int mhl_i2c_reg_read(struct i2c_client *client,
uint8_t slave_addr_index, uint8_t reg_offset)
{
int rc = -1;
@@ -107,7 +212,7 @@
}
-static int mhl_i2c_reg_write(struct i2c_client *client,
+int mhl_i2c_reg_write(struct i2c_client *client,
uint8_t slave_addr_index, uint8_t reg_offset,
uint8_t value)
{
@@ -115,7 +220,7 @@
reg_offset, &value);
}
-static void mhl_i2c_reg_modify(struct i2c_client *client,
+void mhl_i2c_reg_modify(struct i2c_client *client,
uint8_t slave_addr_index, uint8_t reg_offset,
uint8_t mask, uint8_t val)
{
@@ -350,11 +455,11 @@
MHL_SII_REG_NAME_WR(REG_INTR5_MASK, 0x00);
/* Unmask CBUS1 Intrs */
- MHL_SII_CBUS_WR(0x0009,
+ MHL_SII_REG_NAME_WR(REG_CBUS_INTR_ENABLE,
BIT2 | BIT3 | BIT4 | BIT5 | BIT6);
/* Unmask CBUS2 Intrs */
- MHL_SII_CBUS_WR(0x001F, BIT2 | BIT3);
+ MHL_SII_REG_NAME_WR(REG_CBUS_MSC_INT2_ENABLE, BIT2 | BIT3);
for (i = 0; i < 4; i++) {
/*
@@ -369,7 +474,6 @@
*/
MHL_SII_CBUS_WR((0xF0 + i), 0xFF);
}
- return;
}
static void init_cbus_regs(struct i2c_client *client)
@@ -576,6 +680,7 @@
/* Force HPD to 0 when not in MHL mode. */
mhl_drive_hpd(mhl_ctrl, HPD_DOWN);
+ mhl_tmds_ctrl(mhl_ctrl, TMDS_DISABLE);
/*
* Change TMDS termination to high impedance
* on disconnection.
@@ -592,7 +697,31 @@
}
}
-static void mhl_drive_hpd(struct mhl_tx_ctrl *mhl_ctrl, uint8_t to_state)
+uint8_t check_tmds_enabled(void)
+{
+ return store_tmds_state;
+}
+
+void mhl_tmds_ctrl(struct mhl_tx_ctrl *mhl_ctrl, uint8_t on)
+{
+ struct i2c_client *client = mhl_ctrl->i2c_handle;
+ 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;
+ }
+}
+
+void mhl_drive_hpd(struct mhl_tx_ctrl *mhl_ctrl, uint8_t to_state)
{
struct i2c_client *client = mhl_ctrl->i2c_handle;
@@ -600,15 +729,6 @@
if (to_state == HPD_UP) {
/*
* Drive HPD to UP state
- *
- * The below two reg configs combined
- * enable TMDS output.
- */
-
- /* Enable TMDS on TMDS_CCTRL */
- MHL_SII_REG_NAME_MOD(REG_TMDS_CCTRL, BIT4, BIT4);
-
- /*
* Set HPD_OUT_OVR_EN = HPD State
* EDID read and Un-force HPD (from low)
* propogate to src let HPD float by clearing
@@ -616,15 +736,9 @@
*/
MHL_SII_REG_NAME_MOD(REG_INT_CTRL, BIT4, 0x00);
} else {
- /*
- * Drive HPD to DOWN state
- * Disable TMDS Output on REG_TMDS_CCTRL
- * Enable/Disable TMDS output (MHL TMDS output only)
- */
+ /* Drive HPD to DOWN state */
MHL_SII_REG_NAME_MOD(REG_INT_CTRL, BIT4, BIT4);
- MHL_SII_REG_NAME_MOD(REG_TMDS_CCTRL, BIT4, 0x00);
}
- return;
}
static void mhl_msm_connection(struct mhl_tx_ctrl *mhl_ctrl)
@@ -655,7 +769,19 @@
val = MHL_SII_PAGE3_RD(0x10);
MHL_SII_PAGE3_WR(0x10, val | BIT0);
- return;
+ /*
+ * indicate DCAP_RDY and DCAP_CHG
+ * to the peer only after
+ * msm conn has been established
+ */
+ mhl_msc_send_write_stat(mhl_ctrl,
+ MHL_STATUS_REG_CONNECTED_RDY,
+ MHL_STATUS_DCAP_RDY);
+
+ mhl_msc_send_set_int(mhl_ctrl,
+ MHL_RCHANGE_INT,
+ MHL_INT_DCAP_CHG);
+
}
static void mhl_msm_disconnection(struct mhl_tx_ctrl *mhl_ctrl)
@@ -668,7 +794,6 @@
MHL_SII_PAGE3_WR(0x30, 0xD0);
switch_mode(mhl_ctrl, POWER_STATE_D3);
- return;
}
static int mhl_msm_read_rgnd_int(struct mhl_tx_ctrl *mhl_ctrl)
@@ -676,8 +801,8 @@
uint8_t rgnd_imp;
struct i2c_client *client = mhl_ctrl->i2c_handle;
/* DISC STATUS REG 2 */
- rgnd_imp = (mhl_i2c_reg_read(client,
- TX_PAGE_3, 0x001C) & (BIT1 | BIT0));
+ rgnd_imp = (mhl_i2c_reg_read(client, TX_PAGE_3, 0x001C) &
+ (BIT1 | BIT0));
pr_debug("imp range read=%02X\n", (int)rgnd_imp);
if (0x02 == rgnd_imp) {
@@ -820,8 +945,6 @@
release_usb_switch_open(mhl_ctrl);
}
MHL_SII_REG_NAME_WR(REG_INTR4, status);
-
- return;
}
static void mhl_misc_isr(struct mhl_tx_ctrl *mhl_ctrl)
@@ -861,9 +984,225 @@
*/
cbus_stat = MHL_SII_CBUS_RD(0x0D);
if (BIT6 & cbus_stat)
- mhl_drive_hpd(mhl_ctrl, HPD_UP);
+ mhl_tmds_ctrl(mhl_ctrl, TMDS_ENABLE);
}
- return;
+}
+
+static void mhl_sii_cbus_process_errors(struct i2c_client *client,
+ u8 int_status)
+{
+ u8 abort_reason = 0;
+
+ if (int_status & BIT2) {
+ abort_reason = MHL_SII_REG_NAME_RD(REG_DDC_ABORT_REASON);
+ pr_debug("%s: CBUS DDC Abort Reason(0x%02x)\n",
+ __func__, abort_reason);
+ }
+ if (int_status & BIT5) {
+ abort_reason = MHL_SII_REG_NAME_RD(REG_PRI_XFR_ABORT_REASON);
+ pr_debug("%s: CBUS MSC Requestor Abort Reason(0x%02x)\n",
+ __func__, abort_reason);
+ MHL_SII_REG_NAME_WR(REG_PRI_XFR_ABORT_REASON, 0xFF);
+ }
+ if (int_status & BIT6) {
+ abort_reason = MHL_SII_REG_NAME_RD(
+ REG_CBUS_PRI_FWR_ABORT_REASON);
+ pr_debug("%s: CBUS MSC Responder Abort Reason(0x%02x)\n",
+ __func__, abort_reason);
+ MHL_SII_REG_NAME_WR(REG_CBUS_PRI_FWR_ABORT_REASON, 0xFF);
+ }
+}
+
+int mhl_send_msc_command(struct mhl_tx_ctrl *mhl_ctrl,
+ struct msc_command_struct *req)
+{
+ int timeout;
+ u8 start_bit = 0x00;
+ u8 *burst_data;
+ int i;
+ struct i2c_client *client = mhl_ctrl->i2c_handle;
+
+ if (mhl_ctrl->cur_state != POWER_STATE_D0_MHL) {
+ pr_debug("%s: power_state:%02x CBUS(0x0A):%02x\n",
+ __func__,
+ mhl_ctrl->cur_state,
+ MHL_SII_REG_NAME_RD(REG_CBUS_BUS_STATUS));
+ return -EFAULT;
+ }
+
+ if (!req)
+ return -EFAULT;
+
+ pr_debug("%s: command=0x%02x offset=0x%02x %02x %02x",
+ __func__,
+ req->command,
+ req->offset,
+ req->payload.data[0],
+ req->payload.data[1]);
+
+ /* REG_CBUS_PRI_ADDR_CMD = REQ CBUS CMD or OFFSET */
+ MHL_SII_REG_NAME_WR(REG_CBUS_PRI_ADDR_CMD, req->offset);
+ MHL_SII_REG_NAME_WR(REG_CBUS_PRI_WR_DATA_1ST,
+ req->payload.data[0]);
+
+ switch (req->command) {
+ case MHL_SET_INT:
+ case MHL_WRITE_STAT:
+ start_bit = MSC_START_BIT_WRITE_REG;
+ break;
+ case MHL_READ_DEVCAP:
+ start_bit = MSC_START_BIT_READ_REG;
+ break;
+ case MHL_GET_STATE:
+ case MHL_GET_VENDOR_ID:
+ case MHL_SET_HPD:
+ case MHL_CLR_HPD:
+ case MHL_GET_SC1_ERRORCODE:
+ case MHL_GET_DDC_ERRORCODE:
+ case MHL_GET_MSC_ERRORCODE:
+ case MHL_GET_SC3_ERRORCODE:
+ start_bit = MSC_START_BIT_MSC_CMD;
+ MHL_SII_REG_NAME_WR(REG_CBUS_PRI_ADDR_CMD, req->command);
+ break;
+ case MHL_MSC_MSG:
+ start_bit = MSC_START_BIT_VS_CMD;
+ MHL_SII_REG_NAME_WR(REG_CBUS_PRI_WR_DATA_2ND,
+ req->payload.data[1]);
+ MHL_SII_REG_NAME_WR(REG_CBUS_PRI_ADDR_CMD, req->command);
+ break;
+ case MHL_WRITE_BURST:
+ start_bit = MSC_START_BIT_WRITE_BURST;
+ MHL_SII_REG_NAME_WR(REG_MSC_WRITE_BURST_LEN, req->length - 1);
+ if (!(req->payload.burst_data)) {
+ pr_err("%s: burst data is null!\n", __func__);
+ goto cbus_send_fail;
+ }
+ burst_data = req->payload.burst_data;
+ for (i = 0; i < req->length; i++, burst_data++)
+ MHL_SII_CBUS_WR(0xC0 + i, *burst_data);
+ break;
+ default:
+ pr_err("%s: unknown command! (%02x)\n",
+ __func__, req->command);
+ goto cbus_send_fail;
+ }
+
+ INIT_COMPLETION(mhl_ctrl->msc_cmd_done);
+ MHL_SII_REG_NAME_WR(REG_CBUS_PRI_START, start_bit);
+ timeout = wait_for_completion_interruptible_timeout
+ (&mhl_ctrl->msc_cmd_done, msecs_to_jiffies(T_ABORT_NEXT));
+ if (!timeout) {
+ pr_err("%s: cbus_command_send timed out!\n", __func__);
+ goto cbus_send_fail;
+ }
+
+ switch (req->command) {
+ case MHL_READ_DEVCAP:
+ req->retval = MHL_SII_REG_NAME_RD(REG_CBUS_PRI_RD_DATA_1ST);
+ break;
+ case MHL_MSC_MSG:
+ /* check if MSC_MSG NACKed */
+ if (MHL_SII_REG_NAME_RD(REG_MSC_WRITE_BURST_LEN) & BIT6)
+ return -EAGAIN;
+ default:
+ req->retval = 0;
+ break;
+ }
+ mhl_msc_command_done(mhl_ctrl, req);
+ pr_debug("%s: msc cmd done\n", __func__);
+ return 0;
+
+cbus_send_fail:
+ return -EFAULT;
+}
+
+static void mhl_cbus_isr(struct mhl_tx_ctrl *mhl_ctrl)
+{
+ uint8_t regval;
+ int req_done = 0;
+ uint8_t sub_cmd = 0x0;
+ uint8_t cmd_data = 0x0;
+ int msc_msg_recved = 0;
+ int rc = -1;
+ struct i2c_client *client = mhl_ctrl->i2c_handle;
+
+ regval = MHL_SII_REG_NAME_RD(REG_CBUS_INTR_STATUS);
+ if (regval == 0xff)
+ return;
+
+ if (regval)
+ MHL_SII_REG_NAME_WR(REG_CBUS_INTR_STATUS, regval);
+
+ pr_debug("%s: CBUS_INT = %02x\n", __func__, regval);
+
+ /* MSC_MSG (RCP/RAP) */
+ if (regval & BIT3) {
+ sub_cmd = MHL_SII_REG_NAME_RD(REG_CBUS_PRI_VS_CMD);
+ cmd_data = MHL_SII_REG_NAME_RD(REG_CBUS_PRI_VS_DATA);
+ msc_msg_recved = 1;
+ }
+ /* MSC_MT_ABRT/MSC_MR_ABRT/DDC_ABORT */
+ if (regval & (BIT6 | BIT5 | BIT2))
+ mhl_sii_cbus_process_errors(client, regval);
+
+ /* MSC_REQ_DONE */
+ if (regval & BIT4)
+ req_done = 1;
+
+ /* look for interrupts on CBUS_MSC_INT2 */
+ regval = MHL_SII_REG_NAME_RD(REG_CBUS_MSC_INT2_STATUS);
+
+ /* clear all interrupts */
+ if (regval)
+ MHL_SII_REG_NAME_WR(REG_CBUS_MSC_INT2_STATUS, regval);
+
+ pr_debug("%s: CBUS_MSC_INT2 = %02x\n", __func__, regval);
+
+ /* received SET_INT */
+ if (regval & BIT2) {
+ uint8_t intr;
+ intr = MHL_SII_REG_NAME_RD(REG_CBUS_SET_INT_0);
+ MHL_SII_REG_NAME_WR(REG_CBUS_SET_INT_0, intr);
+ mhl_msc_recv_set_int(mhl_ctrl, 0, intr);
+
+ pr_debug("%s: MHL_INT_0 = %02x\n", __func__, intr);
+ intr = MHL_SII_REG_NAME_RD(REG_CBUS_SET_INT_1);
+ MHL_SII_REG_NAME_WR(REG_CBUS_SET_INT_1, intr);
+ mhl_msc_recv_set_int(mhl_ctrl, 1, intr);
+
+ pr_debug("%s: MHL_INT_1 = %02x\n", __func__, intr);
+ MHL_SII_REG_NAME_WR(REG_CBUS_SET_INT_2, 0xFF);
+ MHL_SII_REG_NAME_WR(REG_CBUS_SET_INT_3, 0xFF);
+ }
+
+ /* received WRITE_STAT */
+ if (regval & BIT3) {
+ uint8_t stat;
+ stat = MHL_SII_REG_NAME_RD(REG_CBUS_WRITE_STAT_0);
+ mhl_msc_recv_write_stat(mhl_ctrl, 0, stat);
+
+ pr_debug("%s: MHL_STATUS_0 = %02x\n", __func__, stat);
+ stat = MHL_SII_REG_NAME_RD(REG_CBUS_WRITE_STAT_1);
+ mhl_msc_recv_write_stat(mhl_ctrl, 1, stat);
+ pr_debug("%s: MHL_STATUS_1 = %02x\n", __func__, stat);
+
+ MHL_SII_REG_NAME_WR(REG_CBUS_WRITE_STAT_0, 0xFF);
+ MHL_SII_REG_NAME_WR(REG_CBUS_WRITE_STAT_1, 0xFF);
+ MHL_SII_REG_NAME_WR(REG_CBUS_WRITE_STAT_2, 0xFF);
+ MHL_SII_REG_NAME_WR(REG_CBUS_WRITE_STAT_3, 0xFF);
+ }
+
+ /* received MSC_MSG */
+ if (msc_msg_recved) {
+ /*mhl msc recv msc msg*/
+ rc = mhl_msc_recv_msc_msg(mhl_ctrl, sub_cmd, cmd_data);
+ if (rc)
+ pr_err("MHL: mhl msc recv msc msg failed(%d)!\n", rc);
+ }
+ /* complete last command */
+ if (req_done)
+ complete_all(&mhl_ctrl->msc_cmd_done);
+
}
static void clear_all_intrs(struct i2c_client *client)
@@ -1002,11 +1341,11 @@
mhl_misc_isr(mhl_ctrl);
/*
- * Check for any peer messages for DCAP_CHG etc
+ * Check for any peer messages for DCAP_CHG, MSC etc
* Dispatch to have the CBUS module working only
* once connected.
- mhl_cbus_isr(mhl_ctrl);
*/
+ mhl_cbus_isr(mhl_ctrl);
mhl_hpd_stat_isr(mhl_ctrl);
}
@@ -1296,6 +1635,59 @@
* such tx specific
*/
mhl_ctrl->disc_enabled = false;
+ INIT_WORK(&mhl_ctrl->mhl_msc_send_work, mhl_msc_send_work);
+ mhl_ctrl->cur_state = POWER_STATE_D0_MHL;
+ INIT_LIST_HEAD(&mhl_ctrl->list_cmd);
+ init_completion(&mhl_ctrl->msc_cmd_done);
+ mhl_ctrl->msc_send_workqueue = create_singlethread_workqueue
+ ("mhl_msc_cmd_queue");
+
+ mhl_ctrl->input = input_allocate_device();
+ if (mhl_ctrl->input) {
+ int i;
+ struct input_dev *input = mhl_ctrl->input;
+
+ mhl_ctrl->rcp_key_code_tbl = vmalloc(
+ ARRAY_SIZE(support_rcp_key_code_tbl));
+ if (!mhl_ctrl->rcp_key_code_tbl) {
+ pr_err("%s: no alloc mem for rcp keycode tbl\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ memcpy(mhl_ctrl->rcp_key_code_tbl,
+ &support_rcp_key_code_tbl[0],
+ ARRAY_SIZE(support_rcp_key_code_tbl));
+ mhl_ctrl->rcp_key_code_tbl_len = ARRAY_SIZE(
+ support_rcp_key_code_tbl);
+
+ input->phys = "cbus/input0";
+ input->id.bustype = BUS_VIRTUAL;
+ input->id.vendor = 0x1095;
+ input->id.product = 0x8334;
+ input->id.version = 0xA;
+
+ input->name = "mhl-rcp";
+
+ input->keycode = support_rcp_key_code_tbl;
+ input->keycodesize = sizeof(u16);
+ input->keycodemax = ARRAY_SIZE(support_rcp_key_code_tbl);
+
+ input->evbit[0] = EV_KEY;
+ for (i = 0; i < ARRAY_SIZE(support_rcp_key_code_tbl); i++) {
+ if (support_rcp_key_code_tbl[i] > 1)
+ input_set_capability(input, EV_KEY,
+ support_rcp_key_code_tbl[i]);
+ }
+
+ if (input_register_device(input) < 0) {
+ pr_warn("%s: failed to register input device\n",
+ __func__);
+ input_free_device(input);
+ mhl_ctrl->input = NULL;
+ }
+ }
+
rc = mhl_tx_chip_init(mhl_ctrl);
if (rc) {
pr_err("%s: tx chip init failed [%d]\n",
@@ -1315,7 +1707,7 @@
client->dev.driver->name, mhl_ctrl);
if (rc) {
pr_err("request_threaded_irq failed, status: %d\n",
- rc);
+ rc);
goto failed_probe;
} else {
pr_debug("request_threaded_irq succeeded\n");
@@ -1353,6 +1745,8 @@
goto failed_probe;
}
mhl_ctrl->mhl_info = mhl_info;
+ mhl_register_msc(mhl_ctrl);
+ mhl_ctrl->tmds_enabled = check_tmds_enabled;
return 0;
failed_probe:
mhl_gpio_config(mhl_ctrl, 0);
diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c
index e4e93eb..3841498 100644
--- a/drivers/video/msm/msm_fb.c
+++ b/drivers/video/msm/msm_fb.c
@@ -3,7 +3,7 @@
* Core MSM framebuffer driver.
*
* Copyright (C) 2007 Google Incorporated
- * Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-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
@@ -1262,8 +1262,6 @@
((PAGE_SIZE - remainder)/fix->line_length) * mfd->fb_page;
var->bits_per_pixel = bpp * 8; /* FrameBuffer color depth */
- var->reserved[4] = mdp_get_panel_framerate(mfd);
-
/*
* id field for fb app
*/
@@ -1732,7 +1730,7 @@
}
mdp_set_dma_pan_info(info, dirtyPtr,
- (var->activate == FB_ACTIVATE_VBL));
+ (var->activate & FB_ACTIVATE_VBL));
mdp_dma_pan_update(info);
up(&msm_fb_pan_sem);
@@ -3249,6 +3247,10 @@
ret = mdp4_qseed_cfg((struct mdp_qseed_cfg_data *)
&pp_ptr->data.qseed_cfg_data);
break;
+ case mdp_op_calib_cfg:
+ ret = mdp4_calib_config((struct mdp_calib_config_data *)
+ &pp_ptr->data.calib_cfg);
+ break;
#endif
case mdp_bl_scale_cfg:
ret = mdp_bl_scale_config(mfd, (struct mdp_bl_scale_data *)
@@ -3281,6 +3283,24 @@
}
return ret;
}
+
+static int msmfb_get_metadata(struct msm_fb_data_type *mfd,
+ struct msmfb_metadata *metadata_ptr)
+{
+ int ret = 0;
+ switch (metadata_ptr->op) {
+ case metadata_op_frame_rate:
+ metadata_ptr->data.panel_frame_rate =
+ mdp_get_panel_framerate(mfd);
+ break;
+ default:
+ pr_warn("Unsupported request to MDP META IOCTL.\n");
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
static int msm_fb_ioctl(struct fb_info *info, unsigned int cmd,
unsigned long arg)
{
@@ -3583,6 +3603,8 @@
return ret;
ret = msmfb_handle_pp_ioctl(mfd, &mdp_pp);
+ if (ret == 1)
+ ret = copy_to_user(argp, &mdp_pp, sizeof(mdp_pp));
break;
case MSMFB_METADATA_SET:
@@ -3592,6 +3614,16 @@
ret = msmfb_handle_metadata_ioctl(mfd, &mdp_metadata);
break;
+ case MSMFB_METADATA_GET:
+ ret = copy_from_user(&mdp_metadata, argp, sizeof(mdp_metadata));
+ if (ret)
+ return ret;
+ ret = msmfb_get_metadata(mfd, &mdp_metadata);
+ if (!ret)
+ ret = copy_to_user(argp, &mdp_metadata,
+ sizeof(mdp_metadata));
+ break;
+
default:
MSM_FB_INFO("MDP: unknown ioctl (cmd=%x) received!\n", cmd);
ret = -EINVAL;
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.c
index 91cf3ae..1b7bed6 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, Code Aurora Forum. 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
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
index 95f4bf0..5cf2f9c 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2013, 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
@@ -1115,14 +1115,21 @@
encoder->client_output_buf_req.sz/num_slices;
encoder->client_output_buf_req.sz =
DDL_ALIGN(output_buf_size, DDL_KILO_BYTE(4));
+ if (encoder->client_output_buf_req. \
+ actual_count < encoder-> \
+ client_output_buf_req.min_count) {
+ encoder->client_output_buf_req. \
+ actual_count = encoder-> \
+ client_output_buf_req.min_count;
+ }
encoder->output_buf_req =
encoder->client_output_buf_req;
- DDL_MSG_HIGH("%s num_mb = %u num_slices = %u "
- "output_buf_count = %u "
- "output_buf_size = %u aligned size = %u\n",
+ DDL_MSG_HIGH("%s num_mb = %u num_slices = %u" \
+ " min_count = %u act_count = %u" \
+ " aligned size = %u\n",
__func__, num_mb, num_slices,
encoder->client_output_buf_req.min_count,
- output_buf_size,
+ encoder->client_output_buf_req.actual_count,
encoder->client_output_buf_req.sz);
vcd_status = VCD_S_SUCCESS;
}
diff --git a/drivers/video/msm/vidc/common/enc/venc.c b/drivers/video/msm/vidc/common/enc/venc.c
index c05e568..c18bb92 100644
--- a/drivers/video/msm/vidc/common/enc/venc.c
+++ b/drivers/video/msm/vidc/common/enc/venc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, Code Aurora Forum. 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
@@ -35,6 +35,7 @@
#include "vcd_res_tracker_api.h"
#define VID_ENC_NAME "msm_vidc_enc"
+static char *node_name[2] = {"", "_sec"};
#if DEBUG
#define DBG(x...) printk(KERN_DEBUG x)
@@ -50,7 +51,6 @@
static struct class *vid_enc_class;
static long vid_enc_ioctl(struct file *file,
unsigned cmd, unsigned long arg);
-static int stop_cmd;
static s32 vid_enc_get_empty_client_index(void)
{
@@ -483,7 +483,7 @@
mutex_lock(&vid_enc_device_p->lock);
- if (!stop_cmd) {
+ if (!client_ctx->stop_called) {
vcd_status = vcd_stop(client_ctx->vcd_handle);
DBG("Waiting for VCD_STOP: Before Timeout\n");
if (!vcd_status) {
@@ -520,13 +520,13 @@
sizeof(struct video_client_ctx));
vid_enc_device_p->num_clients--;
- stop_cmd = 0;
+ client_ctx->stop_called = 0;
mutex_unlock(&vid_enc_device_p->lock);
return true;
}
-
-static int vid_enc_open(struct inode *inode, struct file *file)
+static int vid_enc_open_client(struct video_client_ctx **vid_clnt_ctx,
+ int flags)
{
s32 client_index;
struct video_client_ctx *client_ctx;
@@ -534,22 +534,25 @@
u8 client_count = 0;
INFO("\n msm_vidc_enc: Inside %s()", __func__);
-
- mutex_lock(&vid_enc_device_p->lock);
-
- stop_cmd = 0;
+ if (!vid_clnt_ctx) {
+ ERR("Invalid input\n");
+ rc = -EINVAL;
+ goto client_failure;
+ }
+ *vid_clnt_ctx = NULL;
client_count = vcd_get_num_of_clients();
if (client_count == VIDC_MAX_NUM_CLIENTS) {
- ERR("ERROR : vid_enc_open() max number of clients"
- "limit reached\n");
- mutex_unlock(&vid_enc_device_p->lock);
- return -ENODEV;
+ ERR("ERROR : vid_enc_open() max number of clients\n");
+ rc = -ENODEV;
+ goto client_failure;
}
DBG(" Virtual Address of ioremap is %p\n", vid_enc_device_p->virt_base);
if (!vid_enc_device_p->num_clients) {
- if (!vidc_load_firmware())
- return -ENODEV;
+ if (!vidc_load_firmware()) {
+ rc = -ENODEV;
+ goto client_failure;
+ }
}
client_index = vid_enc_get_empty_client_index();
@@ -557,7 +560,8 @@
if (client_index == -1) {
ERR("%s() : No free clients client_index == -1\n",
__func__);
- return -ENODEV;
+ rc = -ENODEV;
+ goto client_failure;
}
client_ctx =
@@ -573,27 +577,46 @@
client_ctx->user_ion_client = vcd_get_ion_client();
if (!client_ctx->user_ion_client) {
ERR("vcd_open ion get client failed");
- return -EFAULT;
+ rc = -EFAULT;
+ goto client_failure;
}
}
rc = vcd_open(vid_enc_device_p->device_handle, false,
- vid_enc_vcd_cb, client_ctx, 0);
+ vid_enc_vcd_cb, client_ctx, flags);
client_ctx->stop_msg = 0;
+ client_ctx->stop_called = 1;
if (!rc) {
wait_for_completion(&client_ctx->event);
if (client_ctx->event_status) {
ERR("callback for vcd_open returned error: %u",
client_ctx->event_status);
- mutex_unlock(&vid_enc_device_p->lock);
- return -EFAULT;
+ rc = -EFAULT;
+ goto client_failure;
}
} else {
ERR("vcd_open returned error: %u", rc);
- mutex_unlock(&vid_enc_device_p->lock);
- return rc;
+ goto client_failure;
}
- file->private_data = client_ctx;
+ *vid_clnt_ctx = client_ctx;
+client_failure:
+ return rc;
+}
+static int vid_enc_open(struct inode *inode, struct file *file)
+{
+ int rc = 0;
+ struct video_client_ctx *client_ctx = NULL;
+ INFO("msm_vidc_venc: Inside %s()", __func__);
+ mutex_lock(&vid_enc_device_p->lock);
+ rc = vid_enc_open_client(&client_ctx, 0);
+ if (rc)
+ pr_err("%s() open failed rc=%d\n", __func__, rc);
+ else if (!client_ctx) {
+ pr_err("%s() client_ctx is NULL\n", __func__);
+ rc = -ENOMEM;
+ }
+ if (!rc)
+ file->private_data = client_ctx;
mutex_unlock(&vid_enc_device_p->lock);
return rc;
}
@@ -610,12 +633,62 @@
INFO("\n msm_vidc_enc: Return from %s()", __func__);
return 0;
}
+static int vid_enc_open_secure(struct inode *inode, struct file *file)
+{
+ int rc = 0, vcd_status = 0;
+ struct video_client_ctx *client_ctx = NULL;
+ struct vcd_property_hdr vcd_property_hdr;
+ struct vcd_property_sps_pps_for_idr_enable idr_enable;
-static const struct file_operations vid_enc_fops = {
- .owner = THIS_MODULE,
- .open = vid_enc_open,
- .release = vid_enc_release,
- .unlocked_ioctl = vid_enc_ioctl,
+ INFO("msm_vidc_enc: Inside %s()", __func__);
+ mutex_lock(&vid_enc_device_p->lock);
+ rc = vid_enc_open_client(&client_ctx, VCD_CP_SESSION);
+ if (rc || !client_ctx) {
+ pr_err("%s() open failed rc=%d\n", __func__, rc);
+ if (!client_ctx)
+ rc = -ENOMEM;
+ goto error;
+ }
+ file->private_data = client_ctx;
+ vcd_property_hdr.prop_id = VCD_I_ENABLE_SPS_PPS_FOR_IDR;
+ vcd_property_hdr.sz =
+ sizeof(struct vcd_property_sps_pps_for_idr_enable);
+ idr_enable.sps_pps_for_idr_enable_flag = 1;
+ vcd_status = vcd_set_property(client_ctx->vcd_handle,
+ &vcd_property_hdr, &idr_enable);
+ if (vcd_status) {
+ ERR("Setting SPS with IDR failed\n");
+ rc = -EACCES;
+ goto close_client;
+ }
+
+ if (res_trk_open_secure_session()) {
+ rc = -EACCES;
+ goto close_client;
+ }
+ mutex_unlock(&vid_enc_device_p->lock);
+ return rc;
+
+close_client:
+ vid_enc_close_client(client_ctx);
+ ERR("Secure session operation failure\n");
+error:
+ mutex_unlock(&vid_enc_device_p->lock);
+ return rc;
+}
+static const struct file_operations vid_enc_fops[NUM_OF_DRIVER_NODES] = {
+ {
+ .owner = THIS_MODULE,
+ .open = vid_enc_open,
+ .release = vid_enc_release,
+ .unlocked_ioctl = vid_enc_ioctl,
+ },
+ {
+ .owner = THIS_MODULE,
+ .open = vid_enc_open_secure,
+ .release = vid_enc_release,
+ .unlocked_ioctl = vid_enc_ioctl,
+ },
};
void vid_enc_interrupt_deregister(void)
@@ -680,7 +753,7 @@
static int __init vid_enc_init(void)
{
- int rc = 0;
+ int rc = 0, i = 0, j = 0;
struct device *class_devp;
INFO("\n msm_vidc_enc: Inside %s()", __func__);
@@ -691,14 +764,13 @@
__func__);
return -ENOMEM;
}
-
- rc = alloc_chrdev_region(&vid_enc_dev_num, 0, 1, VID_ENC_NAME);
+ rc = alloc_chrdev_region(&vid_enc_dev_num, 0, NUM_OF_DRIVER_NODES,
+ VID_ENC_NAME);
if (rc < 0) {
ERR("%s: alloc_chrdev_region Failed rc = %d\n",
__func__, rc);
goto error_vid_enc_alloc_chrdev_region;
}
-
vid_enc_class = class_create(THIS_MODULE, VID_ENC_NAME);
if (IS_ERR(vid_enc_class)) {
rc = PTR_ERR(vid_enc_class);
@@ -706,32 +778,40 @@
__func__, rc);
goto error_vid_enc_class_create;
}
+ for (i = 0; i < NUM_OF_DRIVER_NODES; i++) {
+ class_devp = device_create(vid_enc_class, NULL,
+ (vid_enc_dev_num + i), NULL,
+ VID_ENC_NAME "%s", node_name[i]);
- class_devp = device_create(vid_enc_class, NULL,
- vid_enc_dev_num, NULL, VID_ENC_NAME);
+ if (IS_ERR(class_devp)) {
+ rc = PTR_ERR(class_devp);
+ ERR("%s: class device_create failed %d\n",
+ __func__, rc);
+ if (!i)
+ goto error_vid_enc_class_device_create;
+ else
+ goto error_vid_enc_cdev_add;
+ }
- if (IS_ERR(class_devp)) {
- rc = PTR_ERR(class_devp);
- ERR("%s: class device_create failed %d\n",
- __func__, rc);
- goto error_vid_enc_class_device_create;
- }
+ vid_enc_device_p->device[i] = class_devp;
- vid_enc_device_p->device = class_devp;
+ cdev_init(&vid_enc_device_p->cdev[i], &vid_enc_fops[i]);
+ vid_enc_device_p->cdev[i].owner = THIS_MODULE;
+ rc = cdev_add(&(vid_enc_device_p->cdev[i]),
+ (vid_enc_dev_num + i), 1);
- cdev_init(&vid_enc_device_p->cdev, &vid_enc_fops);
- vid_enc_device_p->cdev.owner = THIS_MODULE;
- rc = cdev_add(&(vid_enc_device_p->cdev), vid_enc_dev_num, 1);
-
- if (rc < 0) {
- ERR("%s: cdev_add failed %d\n",
- __func__, rc);
- goto error_vid_enc_cdev_add;
+ if (rc < 0) {
+ ERR("%s: cdev_add failed %d\n",
+ __func__, rc);
+ goto error_vid_enc_cdev_add;
+ }
}
vid_enc_vcd_init();
return 0;
error_vid_enc_cdev_add:
+ for (j = i-1; j >= 0; j--)
+ cdev_del(&(vid_enc_device_p->cdev[j]));
device_destroy(vid_enc_class, vid_enc_dev_num);
error_vid_enc_class_device_create:
class_destroy(vid_enc_class);
@@ -745,8 +825,10 @@
static void __exit vid_enc_exit(void)
{
+ int i = 0;
INFO("\n msm_vidc_enc: Inside %s()", __func__);
- cdev_del(&(vid_enc_device_p->cdev));
+ for (i = 0; i < NUM_OF_DRIVER_NODES; i++)
+ cdev_del(&(vid_enc_device_p->cdev[i]));
device_destroy(vid_enc_class, vid_enc_dev_num);
class_destroy(vid_enc_class);
unregister_chrdev_region(vid_enc_dev_num, 1);
@@ -944,7 +1026,8 @@
if (!result) {
ERR("setting VEN_IOCTL_CMD_START failed\n");
return -EIO;
- }
+ } else
+ client_ctx->stop_called = 0;
break;
}
case VEN_IOCTL_CMD_STOP:
@@ -955,7 +1038,7 @@
ERR("setting VEN_IOCTL_CMD_STOP failed\n");
return -EIO;
}
- stop_cmd = 1;
+ client_ctx->stop_called = 1;
break;
}
case VEN_IOCTL_CMD_PAUSE:
diff --git a/drivers/video/msm/vidc/common/enc/venc_internal.h b/drivers/video/msm/vidc/common/enc/venc_internal.h
index 17cefbb..b7b8c98 100644
--- a/drivers/video/msm/vidc/common/enc/venc_internal.h
+++ b/drivers/video/msm/vidc/common/enc/venc_internal.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, Code Aurora Forum. 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
@@ -18,6 +18,7 @@
#include <linux/cdev.h>
#include <media/msm/vidc_init.h>
+#define NUM_OF_DRIVER_NODES 2
#define VID_ENC_MAX_NUM_OF_BUFF 100
enum venc_buffer_dir{
@@ -32,8 +33,8 @@
struct vid_enc_dev {
- struct cdev cdev;
- struct device *device;
+ struct cdev cdev[NUM_OF_DRIVER_NODES];
+ struct device *device[NUM_OF_DRIVER_NODES];
resource_size_t phys_base;
void __iomem *virt_base;
unsigned int irq;
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_api.c b/drivers/video/msm/vidc/common/vcd/vcd_api.c
index 0dbbf57..3d7474f 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_api.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_api.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, Code Aurora Forum. 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
@@ -117,36 +117,20 @@
int is_secure;
struct client_security_info sec_info;
int client_count = 0;
- int secure_session_running = 0;
+ int secure_session_running = 0, non_secure_runnung = 0;
is_secure = (flags & VCD_CP_SESSION) ? 1 : 0;
client_count = vcd_get_clients_security_info(&sec_info);
secure_session_running = (sec_info.secure_enc > 0) ||
(sec_info.secure_dec > 0);
- if (!decoding && is_secure) {
- if ((sec_info.secure_dec == 1))
- VCD_MSG_LOW("SE-SD: SUCCESS\n");
- else {
- VCD_MSG_LOW("SE is permitted only with SD: FAILURE\n");
- return -EACCES;
- }
- } else if (!decoding && !is_secure) {
+ non_secure_runnung = sec_info.non_secure_dec + sec_info.non_secure_enc;
+ if (!is_secure) {
if (secure_session_running) {
- VCD_MSG_LOW("SD-NSE: FAILURE\n");
- VCD_MSG_LOW("SE-NSE: FAILURE\n");
- return -EACCES;
- }
- } else if (decoding && is_secure) {
- if (client_count > 0) {
- VCD_MSG_LOW("S/NS-SD: FAILURE\n");
- if (sec_info.secure_enc > 0 ||
- sec_info.non_secure_enc > 0) {
- return -EAGAIN;
- }
+ pr_err("non secure session failed secure running\n");
return -EACCES;
}
} else {
- if (sec_info.secure_dec > 0) {
- VCD_MSG_LOW("SD-NSD: FAILURE\n");
+ if (non_secure_runnung) {
+ pr_err("Secure session failed non secure running\n");
return -EACCES;
}
}
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_client_sm.c b/drivers/video/msm/vidc/common/vcd/vcd_client_sm.c
index 983923b..884050b 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_client_sm.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_client_sm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2013, 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
@@ -1750,7 +1750,7 @@
vcd_get_buffer_requirements_cmn,
NULL,
NULL,
- NULL,
+ vcd_free_buffer_cmn,
vcd_fill_output_buffer_cmn,
vcd_clnt_cb_in_flushing,
},
diff --git a/include/linux/coresight.h b/include/linux/coresight.h
index 0bdacffa..b167b44 100644
--- a/include/linux/coresight.h
+++ b/include/linux/coresight.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -30,7 +30,11 @@
#define CORESIGHT_COMPIDR2 (0xFF8)
#define CORESIGHT_COMPIDR3 (0xFFC)
+#define ETM_ARCH_V1_0 (0x00)
+#define ETM_ARCH_V1_2 (0x02)
#define ETM_ARCH_V3_3 (0x23)
+#define ETM_ARCH_V3_5 (0x25)
+#define PFT_ARCH_MAJOR (0x30)
#define PFT_ARCH_V1_1 (0x31)
enum coresight_clk_rate {
diff --git a/include/linux/diagchar.h b/include/linux/diagchar.h
index 43daaf2..4bd8885 100644
--- a/include/linux/diagchar.h
+++ b/include/linux/diagchar.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2008-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
@@ -112,7 +112,7 @@
/* This needs to be modified manually now, when we add
a new RANGE of SSIDs to the msg_mask_tbl */
#define MSG_MASK_TBL_CNT 24
-#define EVENT_LAST_ID 0x08C5
+#define EVENT_LAST_ID 0x099F
#define MSG_SSID_0 0
#define MSG_SSID_0_LAST 93
@@ -692,7 +692,7 @@
/* LOG CODES */
#define LOG_0 0x0
-#define LOG_1 0x1636
+#define LOG_1 0x1750
#define LOG_2 0x0
#define LOG_3 0x0
#define LOG_4 0x4910
diff --git a/include/linux/fb.h b/include/linux/fb.h
index f6a2923..d31cb68 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -279,7 +279,7 @@
__u32 vmode; /* see FB_VMODE_* */
__u32 rotate; /* angle we rotate counter clockwise */
__u32 colorspace; /* colorspace for FOURCC-based modes */
- __u32 reserved[5]; /* Reserved for future compatibility */
+ __u32 reserved[4]; /* Reserved for future compatibility */
};
struct fb_cmap {
diff --git a/include/linux/mfd/wcd9xxx/core.h b/include/linux/mfd/wcd9xxx/core.h
index 4b2ad66..458f060 100644
--- a/include/linux/mfd/wcd9xxx/core.h
+++ b/include/linux/mfd/wcd9xxx/core.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. 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
@@ -148,6 +148,7 @@
struct mutex io_lock;
struct mutex xfer_lock;
struct mutex irq_lock;
+ struct mutex nested_irq_lock;
u8 version;
int reset_gpio;
@@ -156,6 +157,10 @@
int bytes, void *dest, bool interface_reg);
int (*write_dev)(struct wcd9xxx *wcd9xxx, unsigned short reg,
int bytes, void *src, bool interface_reg);
+ int (*post_reset)(struct wcd9xxx *wcd9xxx);
+
+ void *ssr_priv;
+ bool slim_device_bootup;
u32 num_of_supplies;
struct regulator_bulk_data *supplies;
@@ -200,6 +205,8 @@
bool wcd9xxx_lock_sleep(struct wcd9xxx *wcd9xxx);
void wcd9xxx_unlock_sleep(struct wcd9xxx *wcd9xxx);
+void wcd9xxx_nested_irq_lock(struct wcd9xxx *wcd9xxx);
+void wcd9xxx_nested_irq_unlock(struct wcd9xxx *wcd9xxx);
enum wcd9xxx_pm_state wcd9xxx_pm_cmpxchg(struct wcd9xxx *wcd9xxx,
enum wcd9xxx_pm_state o,
enum wcd9xxx_pm_state n);
diff --git a/include/linux/mfd/wcd9xxx/wcd9310_registers.h b/include/linux/mfd/wcd9xxx/wcd9310_registers.h
index 67c2a6b..46336e2 100644
--- a/include/linux/mfd/wcd9xxx/wcd9310_registers.h
+++ b/include/linux/mfd/wcd9xxx/wcd9310_registers.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. 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
@@ -898,37 +898,37 @@
#define TABLA_A_CDC_DEBUG_B6_CTL (0x0000036D)
#define TABLA_A_CDC_DEBUG_B6_CTL__POR (0x00000000)
#define TABLA_A_CDC_COMP1_B1_CTL (0x00000370)
-#define TABLA_A_CDC_COMP1_B1_CTL__POR (0x00000000)
+#define TABLA_A_CDC_COMP1_B1_CTL__POR (0x00000030)
#define TABLA_A_CDC_COMP1_B2_CTL (0x00000371)
-#define TABLA_A_CDC_COMP1_B2_CTL__POR (0x00000000)
+#define TABLA_A_CDC_COMP1_B2_CTL__POR (0x000000B5)
#define TABLA_A_CDC_COMP1_B3_CTL (0x00000372)
-#define TABLA_A_CDC_COMP1_B3_CTL__POR (0x00000000)
+#define TABLA_A_CDC_COMP1_B3_CTL__POR (0x00000028)
#define TABLA_A_CDC_COMP1_B4_CTL (0x00000373)
-#define TABLA_A_CDC_COMP1_B4_CTL__POR (0x00000000)
+#define TABLA_A_CDC_COMP1_B4_CTL__POR (0x0000003C)
#define TABLA_A_CDC_COMP1_B5_CTL (0x00000374)
-#define TABLA_A_CDC_COMP1_B5_CTL__POR (0x00000000)
+#define TABLA_A_CDC_COMP1_B5_CTL__POR (0x0000001F)
#define TABLA_A_CDC_COMP1_B6_CTL (0x00000375)
#define TABLA_A_CDC_COMP1_B6_CTL__POR (0x00000000)
#define TABLA_A_CDC_COMP1_SHUT_DOWN_STATUS (0x00000376)
#define TABLA_A_CDC_COMP1_SHUT_DOWN_STATUS__POR (0x00000000)
#define TABLA_A_CDC_COMP1_FS_CFG (0x00000377)
-#define TABLA_A_CDC_COMP1_FS_CFG__POR (0x00000000)
+#define TABLA_A_CDC_COMP1_FS_CFG__POR (0x0000001B)
#define TABLA_A_CDC_COMP2_B1_CTL (0x00000378)
-#define TABLA_A_CDC_COMP2_B1_CTL__POR (0x00000000)
+#define TABLA_A_CDC_COMP2_B1_CTL__POR (0x00000030)
#define TABLA_A_CDC_COMP2_B2_CTL (0x00000379)
-#define TABLA_A_CDC_COMP2_B2_CTL__POR (0x00000000)
+#define TABLA_A_CDC_COMP2_B2_CTL__POR (0x000000B5)
#define TABLA_A_CDC_COMP2_B3_CTL (0x0000037A)
-#define TABLA_A_CDC_COMP2_B3_CTL__POR (0x00000000)
+#define TABLA_A_CDC_COMP2_B3_CTL__POR (0x00000028)
#define TABLA_A_CDC_COMP2_B4_CTL (0x0000037B)
-#define TABLA_A_CDC_COMP2_B4_CTL__POR (0x00000000)
+#define TABLA_A_CDC_COMP2_B4_CTL__POR (0x0000003C)
#define TABLA_A_CDC_COMP2_B5_CTL (0x0000037C)
-#define TABLA_A_CDC_COMP2_B5_CTL__POR (0x00000000)
+#define TABLA_A_CDC_COMP2_B5_CTL__POR (0x0000001F)
#define TABLA_A_CDC_COMP2_B6_CTL (0x0000037D)
#define TABLA_A_CDC_COMP2_B6_CTL__POR (0x00000000)
#define TABLA_A_CDC_COMP2_SHUT_DOWN_STATUS (0x0000037E)
#define TABLA_A_CDC_COMP2_SHUT_DOWN_STATUS__POR (0x00000000)
#define TABLA_A_CDC_COMP2_FS_CFG (0x0000037F)
-#define TABLA_A_CDC_COMP2_FS_CFG__POR (0x00000000)
+#define TABLA_A_CDC_COMP2_FS_CFG__POR (0x0000001B)
#define TABLA_A_CDC_CONN_RX1_B1_CTL (0x00000380)
#define TABLA_A_CDC_CONN_RX1_B1_CTL__POR (0x00000000)
#define TABLA_A_CDC_CONN_RX1_B2_CTL (0x00000381)
diff --git a/include/linux/mhl_8334.h b/include/linux/mhl_8334.h
index d3597dc..cb74b73 100644
--- a/include/linux/mhl_8334.h
+++ b/include/linux/mhl_8334.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. 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
@@ -18,6 +18,7 @@
#include <linux/platform_device.h>
#include <mach/board.h>
#include <linux/mhl_devcap.h>
+#include <linux/power_supply.h>
#include <linux/mhl_defs.h>
#define MHL_DEVICE_NAME "sii8334"
@@ -96,6 +97,65 @@
struct msc_command_struct* (*msc_command_get_work) (void);
};
+#ifdef CONFIG_FB_MSM_MDSS_HDMI_MHL_SII8334
+enum mhl_gpio_type {
+ MHL_TX_RESET_GPIO,
+ MHL_TX_INTR_GPIO,
+ MHL_TX_PMIC_PWR_GPIO,
+ MHL_TX_MAX_GPIO,
+};
+
+enum mhl_vreg_type {
+ MHL_TX_3V_VREG,
+ MHL_TX_MAX_VREG,
+};
+
+
+struct mhl_tx_platform_data {
+ /* Data filled from device tree nodes */
+ struct dss_gpio *gpios[MHL_TX_MAX_GPIO];
+ struct dss_vreg *vregs[MHL_TX_MAX_VREG];
+ int irq;
+};
+
+struct mhl_tx_ctrl {
+ struct platform_device *pdev;
+ struct mhl_tx_platform_data *pdata;
+ struct i2c_client *i2c_handle;
+ uint8_t cur_state;
+ uint8_t chip_rev_id;
+ int mhl_mode;
+ struct completion rgnd_done;
+ void (*notify_usb_online)(int online);
+ struct usb_ext_notification *mhl_info;
+ bool disc_enabled;
+ struct power_supply mhl_psy;
+ bool vbus_active;
+ int current_val;
+ struct completion msc_cmd_done;
+ uint8_t devcap[16];
+ uint8_t devcap_state;
+ uint8_t path_en_state;
+ uint8_t (*tmds_enabled)(void);
+ struct work_struct mhl_msc_send_work;
+ struct list_head list_cmd;
+ struct input_dev *input;
+ struct workqueue_struct *msc_send_workqueue;
+ u16 *rcp_key_code_tbl;
+ size_t rcp_key_code_tbl_len;
+};
+
+int mhl_i2c_reg_read(struct i2c_client *client,
+ uint8_t slave_addr_index, uint8_t reg_offset);
+int mhl_i2c_reg_write(struct i2c_client *client,
+ uint8_t slave_addr_index, uint8_t reg_offset,
+ uint8_t value);
+void mhl_i2c_reg_modify(struct i2c_client *client,
+ uint8_t slave_addr_index, uint8_t reg_offset,
+ uint8_t mask, uint8_t val);
+
+#endif /* CONFIG_FB_MSM_MDSS_HDMI_MHL_SII8334 */
+
enum {
TX_PAGE_TPI = 0x00,
TX_PAGE_L0 = 0x01,
@@ -204,6 +264,7 @@
#define REG_TMDS_CSTAT ((TX_PAGE_3 << 16) | 0x0040)
+#define REG_CBUS_INTR_STATUS ((TX_PAGE_CBUS << 16) | 0x0008)
#define REG_CBUS_INTR_ENABLE ((TX_PAGE_CBUS << 16) | 0x0009)
#define REG_DDC_ABORT_REASON ((TX_PAGE_CBUS << 16) | 0x000B)
diff --git a/include/linux/mhl_defs.h b/include/linux/mhl_defs.h
index 062bdf9..f23be79 100644
--- a/include/linux/mhl_defs.h
+++ b/include/linux/mhl_defs.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. 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
@@ -149,6 +149,7 @@
#define MHL_RCPE_NO_ERROR 0x00
#define MHL_RCPE_UNSUPPORTED_KEY_CODE 0x01
+#define MHL_RCPE_INEFFECTIVE_KEY_CODE 0x01
#define MHL_RCPE_BUSY 0x02
#define MHL_RAPK_NO_ERROR 0x00
@@ -156,6 +157,8 @@
#define MHL_RAPK_UNSUPPORTED_ACTION_CODE 0x02
#define MHL_RAPK_BUSY 0x03
+#define T_ABORT_NEXT (2050)
+
/* MHL spec related defines*/
enum {
/* Command or Data byte acknowledge */
@@ -196,6 +199,8 @@
MHL_GET_SC3_ERRORCODE = 0x6D,
};
+/* Polling. */
+#define MHL_RAP_POLL 0x00
/* Turn content streaming ON. */
#define MHL_RAP_CONTENT_ON 0x10
/* Turn content streaming OFF. */
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 4c8822d..b362d7a 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -198,6 +198,7 @@
REL_WRITE,
THRESHOLD,
LARGE_SEC_ALIGN,
+ RANDOM,
MAX_REASONS,
};
@@ -305,31 +306,6 @@
#define BKOPS_SIZE_PERCENTAGE_TO_QUEUE_DELAYED_WORK 1 /* 1% */
};
-/**
- * struct mmc_async_event_stats - async events stats data
- *
- * @enabled A boolean indicating if the stats are initiated
- * and enabled
- * The rest of the members in this struct are counters which are
- * incremented at strategic locations in the async events flows.
- */
-struct mmc_async_event_stats {
- bool enabled;
- u32 cmd_retry;
- u32 new_request_flag;
- u32 null_fetched;
- u32 wakeup_new;
- u32 q_no_waiting;
- u32 done_flag;
- u32 no_mmc_request_action;
- u32 wakeup_mq_thread;
- u32 fetch_due_to_new_req;
- u32 returned_new_req;
- u32 done_when_new_req_event_on;
- u32 new_req_when_new_marked;
- bool print_in_read;
-};
-
/*
* MMC device
*/
@@ -400,12 +376,11 @@
struct dentry *debugfs_root;
struct mmc_part part[MMC_NUM_PHY_PARTITION]; /* physical partitions */
unsigned int nr_parts;
+ unsigned int part_curr;
struct mmc_wr_pack_stats wr_pack_stats; /* packed commands stats*/
struct mmc_bkops_info bkops_info;
- /* async events flow stats */
- struct mmc_async_event_stats async_event_stats;
};
/*
@@ -636,5 +611,5 @@
extern struct mmc_wr_pack_stats *mmc_blk_get_packed_statistics(
struct mmc_card *card);
extern void mmc_blk_init_packed_statistics(struct mmc_card *card);
-extern void mmc_blk_init_async_event_statistics(struct mmc_card *card);
+
#endif /* LINUX_MMC_CARD_H */
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 6982c45..f9e0627 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -315,6 +315,7 @@
struct delayed_work detect;
struct wake_lock detect_wake_lock;
+ const char *wlock_name;
int detect_change; /* card detect flag */
struct mmc_hotplug hotplug;
diff --git a/include/linux/mmc/ioctl.h b/include/linux/mmc/ioctl.h
index 1f5e689..befbdc2 100644
--- a/include/linux/mmc/ioctl.h
+++ b/include/linux/mmc/ioctl.h
@@ -47,6 +47,60 @@
#define MMC_IOC_CMD _IOWR(MMC_BLOCK_MAJOR, 0, struct mmc_ioc_cmd)
+/**
+ * There are four request types that are applicable for rpmb accesses- two
+ * under read category and two under write. They are
+ *
+ * Reads
+ * -------
+ * 1. Read Write Counter
+ * 2. Authenticated data read
+ *
+ *
+ * Writes
+ * -------
+ * 1. Provision RPMB key (though it might be done in a secure environment)
+ * 2. Authenticated data write
+ *
+ * While its given that the rpmb data frames are going to have that
+ * information encoded in it and the frames should be generated by a secure
+ * piece of code, the request types can be classified as above.
+ *
+ * So here are the set of commands that should be executed atomically in the
+ * ioctl for rpmb read operation
+ * 1. Switch partition
+ * 2. Set block count
+ * 3. Write data frame - CMD25 to write the rpmb data frame
+ * 4. Set block count
+ * 5. Read the data - CMD18 to do the actual read
+ *
+ * Similarly for rpmb write operation, these are the commands that should be
+ * executed atomically in the ioctl for rpmb write operation
+ * 1. Switch partition
+ * 2. Set block count
+ * 3. Write data frame - CMD25 to write the rpmb data frame with data
+ * 4. Set block count
+ * 5. Read the data - CMD25 to write rpmb data frame indicating that rpmb
+ * result register is about to be read
+ * 6. Set block count
+ * 7. Read rpmb result - CMD18 to read the rpmb result register
+ *
+ * Each of the above commands should be sent individually via struct mmc_ioc_cmd
+ * and fields like is_acmd that are not needed for rpmb operations will be
+ * ignored.
+ */
+#define MMC_IOC_MAX_RPMB_CMD 3
+struct mmc_ioc_rpmb {
+ struct mmc_ioc_cmd cmds[MMC_IOC_MAX_RPMB_CMD];
+};
+
+/*
+ * This ioctl is meant for use with rpmb partitions. This is needed since the
+ * access procedure for this particular partition is different from regular
+ * or normal partitions.
+ */
+#define MMC_IOC_RPMB_CMD _IOWR(MMC_BLOCK_MAJOR, 0, struct mmc_ioc_rpmb)
+
/*
* Since this ioctl is only meant to enhance (and not replace) normal access
* to the mmc bus device, an upper data transfer limit of MMC_IOC_MAX_BYTES
diff --git a/include/linux/msm_ion.h b/include/linux/msm_ion.h
index d423b26..14492ea 100644
--- a/include/linux/msm_ion.h
+++ b/include/linux/msm_ion.h
@@ -1,6 +1,6 @@
/*
*
- * Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-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
@@ -75,6 +75,13 @@
#define ION_SECURE (1 << ION_HEAP_ID_RESERVED)
/**
+ * Flag for clients to force contiguous memort allocation
+ *
+ * Use of this flag is carefully monitored!
+ */
+#define ION_FORCE_CONTIGUOUS (1 << 30)
+
+/**
* Macro should be used with ion_heap_ids defined above.
*/
#define ION_HEAP(bit) (1 << (bit))
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index 7e67db0..fdb8fb6 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -1,7 +1,7 @@
/* include/linux/msm_mdp.h
*
* Copyright (C) 2007 Google Incorporated
- * Copyright (c) 2012 Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2012-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
@@ -75,6 +75,7 @@
#define MSMFB_BUFFER_SYNC _IOW(MSMFB_IOCTL_MAGIC, 164, struct mdp_buf_sync)
#define MSMFB_DISPLAY_COMMIT _IOW(MSMFB_IOCTL_MAGIC, 165, \
struct mdp_display_commit)
+#define MSMFB_METADATA_GET _IOW(MSMFB_IOCTL_MAGIC, 166, struct msmfb_metadata)
#define FB_TYPE_3D_PANEL 0x10101010
#define MDP_IMGTYPE2_START 0x10000
@@ -555,6 +556,7 @@
enum {
metadata_op_none,
metadata_op_base_blend,
+ metadata_op_frame_rate,
metadata_op_max
};
@@ -567,6 +569,7 @@
uint32_t flags;
union {
struct mdp_blend_cfg blend_cfg;
+ uint32_t panel_frame_rate;
} data;
};
diff --git a/include/linux/qmi_encdec.h b/include/linux/qmi_encdec.h
index 4c5f6d3..b1fd217 100644
--- a/include/linux/qmi_encdec.h
+++ b/include/linux/qmi_encdec.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
@@ -150,6 +150,15 @@
int qmi_kernel_decode(struct msg_desc *desc, void *out_c_struct,
void *in_buf, uint32_t in_buf_len);
+/**
+ * qmi_verify_max_msg_len() - Verify the maximum length of a QMI message
+ * @desc: Pointer to structure descriptor.
+ *
+ * @return: true if the maximum message length embedded in structure
+ * descriptor matches the calculated value, else false.
+ */
+bool qmi_verify_max_msg_len(struct msg_desc *desc);
+
#else
static inline int qmi_kernel_encode(struct msg_desc *desc,
void *out_buf, uint32_t out_buf_len,
@@ -164,6 +173,11 @@
{
return -EOPNOTSUPP;
}
+
+static inline bool qmi_verify_max_msg_len(struct msg_desc *desc)
+{
+ return false;
+}
#endif
#endif
diff --git a/include/linux/remote_spinlock.h b/include/linux/remote_spinlock.h
index 8d7c7e7..e39846f 100644
--- a/include/linux/remote_spinlock.h
+++ b/include/linux/remote_spinlock.h
@@ -1,4 +1,5 @@
-/* Copyright (c) 2008-2009, 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2008-2009, 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
@@ -89,6 +90,9 @@
#define remote_spin_release_all(pid) \
_remote_spin_release_all(pid)
+#define remote_spin_owner(lock) \
+ _remote_spin_owner(&((lock)->remote))
+
typedef struct {
struct mutex local;
_remote_mutex_t remote;
diff --git a/include/linux/sync.h b/include/linux/sync.h
index 4c00f04..31ba6ec 100644
--- a/include/linux/sync.h
+++ b/include/linux/sync.h
@@ -16,6 +16,7 @@
#include <linux/types.h>
#ifdef __KERNEL__
+#include <linux/kref.h>
#include <linux/ktime.h>
#include <linux/list.h>
#include <linux/spinlock.h>
@@ -40,14 +41,14 @@
* -1 if a will signabl before b
* @free_pt: called before sync_pt is freed
* @release_obj: called before sync_timeline is freed
- * @print_obj: print aditional debug information about sync_timeline.
- * should not print a newline
- * @print_pt: print aditional debug information about sync_pt.
- * should not print a newline
+ * @print_obj: deprecated
+ * @print_pt: deprecated
* @fill_driver_data: write implmentation specific driver data to data.
* should return an error if there is not enough room
* as specified by size. This information is returned
* to userspace by SYNC_IOC_FENCE_INFO.
+ * @timeline_value_str: fill str with the value of the sync_timeline's counter
+ * @pt_value_str: fill str with the value of the sync_pt
*/
struct sync_timeline_ops {
const char *driver_name;
@@ -67,19 +68,27 @@
/* optional */
void (*release_obj)(struct sync_timeline *sync_timeline);
- /* optional */
+ /* deprecated */
void (*print_obj)(struct seq_file *s,
struct sync_timeline *sync_timeline);
- /* optional */
+ /* deprecated */
void (*print_pt)(struct seq_file *s, struct sync_pt *sync_pt);
/* optional */
int (*fill_driver_data)(struct sync_pt *syncpt, void *data, int size);
+
+ /* optional */
+ void (*timeline_value_str)(struct sync_timeline *timeline, char *str,
+ int size);
+
+ /* optional */
+ void (*pt_value_str)(struct sync_pt *pt, char *str, int size);
};
/**
* struct sync_timeline - sync object
+ * @kref: reference count on fence.
* @ops: ops that define the implementaiton of the sync_timeline
* @name: name of the sync_timeline. Useful for debugging
* @destoryed: set when sync_timeline is destroyed
@@ -90,6 +99,7 @@
* @sync_timeline_list: membership in global sync_timeline_list
*/
struct sync_timeline {
+ struct kref kref;
const struct sync_timeline_ops *ops;
char name[32];
@@ -110,6 +120,7 @@
* @parent: sync_timeline to which this sync_pt belongs
* @child_list: membership in sync_timeline.child_list_head
* @active_list: membership in sync_timeline.active_list_head
+ * @signaled_list: membership in temorary signaled_list on stack
* @fence: sync_fence to which the sync_pt belongs
* @pt_list: membership in sync_fence.pt_list_head
* @status: 1: signaled, 0:active, <0: error
@@ -121,6 +132,7 @@
struct list_head child_list;
struct list_head active_list;
+ struct list_head signaled_list;
struct sync_fence *fence;
struct list_head pt_list;
@@ -134,6 +146,7 @@
/**
* struct sync_fence - sync fence
* @file: file representing this fence
+ * @kref: referenace count on fence.
* @name: name of sync_fence. Useful for debugging
* @pt_list_head: list of sync_pts in ths fence. immutable once fence
* is created
@@ -146,6 +159,7 @@
*/
struct sync_fence {
struct file *file;
+ struct kref kref;
char name[32];
/* this list is immutable once the fence is created */
@@ -323,8 +337,8 @@
* @fence: fence to wait on
* @tiemout: timeout in ms
*
- * Wait for @fence to be signaled or have an error. Waits indefintly
- * if @timeout = 0
+ * Wait for @fence to be signaled or have an error. Waits indefinitely
+ * if @timeout < 0
*/
int sync_fence_wait(struct sync_fence *fence, long timeout);
@@ -383,9 +397,9 @@
/**
* DOC: SYNC_IOC_WAIT - wait for a fence to signal
*
- * pass timeout in milliseconds.
+ * pass timeout in milliseconds. Waits indefinitely timeout < 0.
*/
-#define SYNC_IOC_WAIT _IOW(SYNC_IOC_MAGIC, 0, __u32)
+#define SYNC_IOC_WAIT _IOW(SYNC_IOC_MAGIC, 0, __s32)
/**
* DOC: SYNC_IOC_MERGE - merge two fences
diff --git a/include/linux/test-iosched.h b/include/linux/test-iosched.h
index b933069..ec28463 100644
--- a/include/linux/test-iosched.h
+++ b/include/linux/test-iosched.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012-2013, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -38,6 +38,7 @@
typedef char* (get_test_case_str_fn) (struct test_data *);
typedef void (blk_dev_test_init_fn) (void);
typedef void (blk_dev_test_exit_fn) (void);
+typedef struct gendisk* (get_rq_disk_fn) (void);
/**
* enum test_state - defines the state of the test
@@ -132,6 +133,8 @@
* @test_duration: A jiffies value saved for timing
* calculations
* @data: Test specific private data
+ * @test_byte_count: Total number of bytes dispatched in
+ * the test
*/
struct test_info {
int testcase;
@@ -142,7 +145,9 @@
post_test_fn *post_test_fn;
get_test_case_str_fn *get_test_case_str_fn;
unsigned long test_duration;
+ get_rq_disk_fn *get_rq_disk_fn;
void *data;
+ unsigned long test_byte_count;
};
/**
@@ -229,6 +234,7 @@
extern int test_iosched_start_test(struct test_info *t_info);
extern void test_iosched_mark_test_completion(void);
+extern void check_test_completion(void);
extern int test_iosched_add_unique_test_req(int is_err_expcted,
enum req_unique_type req_unique,
int start_sec, int nr_sects, rq_end_io_fn *end_req_io);
diff --git a/include/sound/apr_audio.h b/include/sound/apr_audio.h
index 5afbfad..c12cbbe 100644
--- a/include/sound/apr_audio.h
+++ b/include/sound/apr_audio.h
@@ -1,6 +1,6 @@
/*
*
- * 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
@@ -1453,6 +1453,23 @@
u32 read_format;
} __attribute__((packed));
+#define ASM_STREAM_CMD_OPEN_LOOPBACK 0x00010D6E
+struct asm_stream_cmd_open_loopback {
+ struct apr_hdr hdr;
+ u32 mode_flags;
+/* Mode flags.
+ * Bit 0-31: reserved; client should set these bits to 0
+ */
+ u16 src_endpointype;
+ /* Endpoint type. 0 = Tx Matrix */
+ u16 sink_endpointype;
+ /* Endpoint type. 0 = Rx Matrix */
+ u32 postprocopo_id;
+/* Postprocessor topology ID. Specifies the topology of
+ * postprocessing algorithms.
+ */
+} __packed;
+
#define ADM_CMD_CONNECT_AFE_PORT 0x00010320
#define ADM_CMD_DISCONNECT_AFE_PORT 0x00010321
@@ -1898,5 +1915,4 @@
int srs_ss3d_open(int port_id, int srs_tech_id, void *srs_params);
/* SRS Studio Sound 3D end */
-
#endif /*_APR_AUDIO_H_*/
diff --git a/include/sound/msm-dai-q6-v2.h b/include/sound/msm-dai-q6-v2.h
index 4ecd435..c04cbfc 100644
--- a/include/sound/msm-dai-q6-v2.h
+++ b/include/sound/msm-dai-q6-v2.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012-2013, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -26,8 +26,7 @@
#define MSM_TERT_MI2S 2
#define MSM_QUAT_MI2S 3
-struct msm_dai_auxpcm_pdata {
- const char *clk;
+struct msm_dai_auxpcm_config {
u16 mode;
u16 sync;
u16 frame;
@@ -40,6 +39,12 @@
int pcm_clk_rate;
};
+struct msm_dai_auxpcm_pdata {
+ const char *clk;
+ struct msm_dai_auxpcm_config mode_8k;
+ struct msm_dai_auxpcm_config mode_16k;
+};
+
struct msm_mi2s_pdata {
u16 rx_sd_lines;
u16 tx_sd_lines;
diff --git a/include/sound/q6asm.h b/include/sound/q6asm.h
index 6b4c17b..275cdbe 100644
--- a/include/sound/q6asm.h
+++ b/include/sound/q6asm.h
@@ -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
@@ -74,10 +74,12 @@
/* Enable Sample_Rate/Channel_Mode notification event from Decoder */
#define SR_CM_NOTIFY_ENABLE 0x0004
-#define ASYNC_IO_MODE 0x0002
-#define SYNC_IO_MODE 0x0001
-#define NO_TIMESTAMP 0xFF00
-#define SET_TIMESTAMP 0x0000
+#define TUN_WRITE_IO_MODE 0x0008 /* tunnel read write mode */
+#define TUN_READ_IO_MODE 0x0004 /* tunnel read write mode */
+#define ASYNC_IO_MODE 0x0002
+#define SYNC_IO_MODE 0x0001
+#define NO_TIMESTAMP 0xFF00
+#define SET_TIMESTAMP 0x0000
#define SOFT_PAUSE_ENABLE 1
#define SOFT_PAUSE_DISABLE 0
@@ -204,6 +206,8 @@
uint32_t rd_format,
uint32_t wr_format);
+int q6asm_open_loopack(struct audio_client *ac);
+
int q6asm_write(struct audio_client *ac, uint32_t len, uint32_t msw_ts,
uint32_t lsw_ts, uint32_t flags);
int q6asm_write_nolock(struct audio_client *ac, uint32_t len, uint32_t msw_ts,
diff --git a/include/trace/events/sync.h b/include/trace/events/sync.h
new file mode 100644
index 0000000..f31bc63
--- /dev/null
+++ b/include/trace/events/sync.h
@@ -0,0 +1,82 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM sync
+
+#if !defined(_TRACE_SYNC_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_SYNC_H
+
+#include <linux/sync.h>
+#include <linux/tracepoint.h>
+
+TRACE_EVENT(sync_timeline,
+ TP_PROTO(struct sync_timeline *timeline),
+
+ TP_ARGS(timeline),
+
+ TP_STRUCT__entry(
+ __string(name, timeline->name)
+ __array(char, value, 32)
+ ),
+
+ TP_fast_assign(
+ __assign_str(name, timeline->name);
+ if (timeline->ops->timeline_value_str) {
+ timeline->ops->timeline_value_str(timeline,
+ __entry->value,
+ sizeof(__entry->value));
+ } else {
+ __entry->value[0] = '\0';
+ }
+ ),
+
+ TP_printk("name=%s value=%s", __get_str(name), __entry->value)
+);
+
+TRACE_EVENT(sync_wait,
+ TP_PROTO(struct sync_fence *fence, int begin),
+
+ TP_ARGS(fence, begin),
+
+ TP_STRUCT__entry(
+ __string(name, fence->name)
+ __field(s32, status)
+ __field(u32, begin)
+ ),
+
+ TP_fast_assign(
+ __assign_str(name, fence->name);
+ __entry->status = fence->status;
+ __entry->begin = begin;
+ ),
+
+ TP_printk("%s name=%s state=%d", __entry->begin ? "begin" : "end",
+ __get_str(name), __entry->status)
+);
+
+TRACE_EVENT(sync_pt,
+ TP_PROTO(struct sync_pt *pt),
+
+ TP_ARGS(pt),
+
+ TP_STRUCT__entry(
+ __string(timeline, pt->parent->name)
+ __array(char, value, 32)
+ ),
+
+ TP_fast_assign(
+ __assign_str(timeline, pt->parent->name);
+ if (pt->parent->ops->pt_value_str) {
+ pt->parent->ops->pt_value_str(pt,
+ __entry->value,
+ sizeof(__entry->value));
+ } else {
+ __entry->value[0] = '\0';
+ }
+ ),
+
+ TP_printk("name=%s value=%s", __get_str(timeline), __entry->value)
+ );
+
+#endif /* if !defined(_TRACE_SYNC_H) || defined(TRACE_HEADER_MULTI_READ) */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
diff --git a/lib/qmi_encdec.c b/lib/qmi_encdec.c
index 40273d0..3f618cb 100644
--- a/lib/qmi_encdec.c
+++ b/lib/qmi_encdec.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
@@ -82,7 +82,7 @@
static int _qmi_kernel_encode(struct elem_info *ei_array,
void *out_buf, void *in_c_struct,
- int enc_level);
+ uint32_t out_buf_len, int enc_level);
static int _qmi_kernel_decode(struct elem_info *ei_array,
void *out_c_struct,
@@ -90,6 +90,71 @@
int dec_level);
/**
+ * qmi_calc_max_msg_len() - Calculate the maximum length of a QMI message
+ * @ei_array: Struct info array describing the structure.
+ * @level: Level to identify the depth of the nested structures.
+ *
+ * @return: expected maximum length of the QMI message or 0 on failure.
+ */
+static int qmi_calc_max_msg_len(struct elem_info *ei_array,
+ int level)
+{
+ int max_msg_len = 0;
+ struct elem_info *temp_ei;
+
+ if (!ei_array)
+ return max_msg_len;
+
+ for (temp_ei = ei_array; temp_ei->data_type != QMI_EOTI; temp_ei++) {
+ /* Flag to identify the optional element is not encoded */
+ if (temp_ei->data_type == QMI_OPT_FLAG)
+ continue;
+
+ if (temp_ei->data_type == QMI_DATA_LEN) {
+ max_msg_len += (temp_ei->elem_size == sizeof(uint8_t) ?
+ sizeof(uint8_t) : sizeof(uint16_t));
+ continue;
+ } else if (temp_ei->data_type == QMI_STRUCT) {
+ max_msg_len += qmi_calc_max_msg_len(temp_ei->ei_array,
+ (level + 1));
+ } else {
+ max_msg_len += (temp_ei->elem_len * temp_ei->elem_size);
+ }
+
+ /*
+ * Type & Length info. not prepended for elements in the
+ * nested structure.
+ */
+ if (level == 1)
+ max_msg_len += (TLV_TYPE_SIZE + TLV_LEN_SIZE);
+ }
+ return max_msg_len;
+}
+
+/**
+ * qmi_verify_max_msg_len() - Verify the maximum length of a QMI message
+ * @desc: Pointer to structure descriptor.
+ *
+ * @return: true if the maximum message length embedded in structure
+ * descriptor matches the calculated value, else false.
+ */
+bool qmi_verify_max_msg_len(struct msg_desc *desc)
+{
+ int calc_max_msg_len;
+
+ if (!desc)
+ return false;
+
+ calc_max_msg_len = qmi_calc_max_msg_len(desc->ei_array, 1);
+ if (calc_max_msg_len != desc->max_msg_len) {
+ pr_err("%s: Calc. len %d != Passed len %d\n",
+ __func__, calc_max_msg_len, desc->max_msg_len);
+ return false;
+ }
+ return true;
+}
+
+/**
* qmi_kernel_encode() - Encode to QMI message wire format
* @desc: Pointer to structure descriptor.
* @out_buf: Buffer to hold the encoded QMI message.
@@ -103,6 +168,7 @@
void *in_c_struct)
{
int enc_level = 1;
+ int ret, calc_max_msg_len;
if (!desc || !desc->ei_array)
return -EINVAL;
@@ -113,8 +179,14 @@
if (desc->max_msg_len < out_buf_len)
return -ETOOSMALL;
- return _qmi_kernel_encode(desc->ei_array, out_buf,
- in_c_struct, enc_level);
+ ret = _qmi_kernel_encode(desc->ei_array, out_buf,
+ in_c_struct, out_buf_len, enc_level);
+ if (ret == -ETOOSMALL) {
+ calc_max_msg_len = qmi_calc_max_msg_len(desc->ei_array, 1);
+ pr_err("%s: Calc. len %d != Out buf len %d\n",
+ __func__, calc_max_msg_len, out_buf_len);
+ }
+ return ret;
}
EXPORT_SYMBOL(qmi_kernel_encode);
@@ -152,6 +224,7 @@
* @buf_dst: Buffer to store the encoded information.
* @buf_src: Buffer containing the elements to be encoded.
* @elem_len: Number of elements, in the buf_src, to be encoded.
+ * @out_buf_len: Available space in the encode buffer.
* @enc_level: Depth of the nested structure from the main structure.
*
* @return: Mumber of bytes of encoded information, on success.
@@ -165,14 +238,16 @@
*/
static int qmi_encode_struct_elem(struct elem_info *ei_array,
void *buf_dst, void *buf_src,
- uint32_t elem_len, int enc_level)
+ uint32_t elem_len, uint32_t out_buf_len,
+ int enc_level)
{
int i, rc, encoded_bytes = 0;
struct elem_info *temp_ei = ei_array;
for (i = 0; i < elem_len; i++) {
- rc = _qmi_kernel_encode(temp_ei->ei_array,
- buf_dst, buf_src, enc_level);
+ rc = _qmi_kernel_encode(temp_ei->ei_array, buf_dst, buf_src,
+ (out_buf_len - encoded_bytes),
+ enc_level);
if (rc < 0) {
pr_err("%s: STRUCT Encode failure\n", __func__);
return rc;
@@ -214,6 +289,7 @@
* @ei_array: Struct info array describing the structure to be encoded.
* @out_buf: Buffer to hold the encoded QMI message.
* @in_c_struct: Pointer to the C structure to be encoded.
+ * @out_buf_len: Available space in the encode buffer.
* @enc_level: Encode level to indicate the depth of the nested structure,
* within the main structure, being encoded.
*
@@ -222,7 +298,7 @@
*/
static int _qmi_kernel_encode(struct elem_info *ei_array,
void *out_buf, void *in_c_struct,
- int enc_level)
+ uint32_t out_buf_len, int enc_level)
{
struct elem_info *temp_ei = ei_array;
uint8_t opt_flag_value = 0;
@@ -268,6 +344,13 @@
memcpy(&data_len_value, buf_src, temp_ei->elem_size);
data_len_sz = temp_ei->elem_size == sizeof(uint8_t) ?
sizeof(uint8_t) : sizeof(uint16_t);
+ /* Check to avoid out of range buffer access */
+ if ((data_len_sz + encoded_bytes + TLV_LEN_SIZE +
+ TLV_TYPE_SIZE) > out_buf_len) {
+ pr_err("%s: Too Small Buffer @DATA_LEN\n",
+ __func__);
+ return -ETOOSMALL;
+ }
rc = qmi_encode_basic_elem(buf_dst, &data_len_value,
1, data_len_sz);
if (data_len_value) {
@@ -285,6 +368,14 @@
case QMI_UNSIGNED_8_BYTE:
case QMI_SIGNED_2_BYTE_ENUM:
case QMI_SIGNED_4_BYTE_ENUM:
+ /* Check to avoid out of range buffer access */
+ if (((data_len_value * temp_ei->elem_size) +
+ encoded_bytes + TLV_LEN_SIZE + TLV_TYPE_SIZE) >
+ out_buf_len) {
+ pr_err("%s: Too Small Buffer @data_type:%d\n",
+ __func__, temp_ei->data_type);
+ return -ETOOSMALL;
+ }
rc = qmi_encode_basic_elem(buf_dst, buf_src,
data_len_value, temp_ei->elem_size);
QMI_ENCODE_LOG_ELEM(enc_level, data_len_value,
@@ -295,7 +386,8 @@
case QMI_STRUCT:
rc = qmi_encode_struct_elem(temp_ei, buf_dst, buf_src,
- data_len_value, (enc_level + 1));
+ data_len_value, (out_buf_len - encoded_bytes),
+ (enc_level + 1));
if (rc < 0)
return rc;
UPDATE_ENCODE_VARIABLES(temp_ei, buf_dst,
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 7dc95af..73ac1b0 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -913,14 +913,12 @@
* This array describes the order lists are fallen back to when
* the free lists for the desirable migrate type are depleted
*/
-static int fallbacks[MIGRATE_TYPES][4] = {
+static int fallbacks[MIGRATE_TYPES][3] = {
[MIGRATE_UNMOVABLE] = { MIGRATE_RECLAIMABLE, MIGRATE_MOVABLE, MIGRATE_RESERVE },
[MIGRATE_RECLAIMABLE] = { MIGRATE_UNMOVABLE, MIGRATE_MOVABLE, MIGRATE_RESERVE },
-#ifdef CONFIG_CMA
- [MIGRATE_MOVABLE] = { MIGRATE_CMA, MIGRATE_RECLAIMABLE, MIGRATE_UNMOVABLE, MIGRATE_RESERVE },
- [MIGRATE_CMA] = { MIGRATE_RESERVE }, /* Never used */
-#else
[MIGRATE_MOVABLE] = { MIGRATE_RECLAIMABLE, MIGRATE_UNMOVABLE, MIGRATE_RESERVE },
+#ifdef CONFIG_CMA
+ [MIGRATE_CMA] = { MIGRATE_RESERVE }, /* Never used */
#endif
[MIGRATE_RESERVE] = { MIGRATE_RESERVE }, /* Never used */
[MIGRATE_ISOLATE] = { MIGRATE_RESERVE }, /* Never used */
@@ -1043,17 +1041,10 @@
* pages to the preferred allocation list. If falling
* back for a reclaimable kernel allocation, be more
* aggressive about taking ownership of free pages
- *
- * On the other hand, never change migration
- * type of MIGRATE_CMA pageblocks nor move CMA
- * pages on different free lists. We don't
- * want unmovable pages to be allocated from
- * MIGRATE_CMA areas.
*/
- if (!is_migrate_cma(migratetype) &&
- (unlikely(current_order >= pageblock_order / 2) ||
- start_migratetype == MIGRATE_RECLAIMABLE ||
- page_group_by_mobility_disabled)) {
+ if (unlikely(current_order >= pageblock_order / 2) ||
+ start_migratetype == MIGRATE_RECLAIMABLE ||
+ page_group_by_mobility_disabled) {
int pages;
pages = move_freepages_block(zone, page,
start_migratetype);
@@ -1072,14 +1063,12 @@
rmv_page_order(page);
/* Take ownership for orders >= pageblock_order */
- if (current_order >= pageblock_order &&
- !is_migrate_cma(migratetype))
+ if (current_order >= pageblock_order)
change_pageblock_range(page, current_order,
start_migratetype);
expand(zone, page, order, current_order, area,
- is_migrate_cma(migratetype)
- ? migratetype : start_migratetype);
+ start_migratetype);
trace_mm_page_alloc_extfrag(page, order, current_order,
start_migratetype, migratetype);
@@ -1100,21 +1089,27 @@
{
struct page *page;
-retry_reserve:
- page = __rmqueue_smallest(zone, order, migratetype);
+#ifdef CONFIG_CMA
+ if (migratetype == MIGRATE_MOVABLE)
+ migratetype = MIGRATE_CMA;
+#endif
- if (unlikely(!page) && migratetype != MIGRATE_RESERVE) {
- page = __rmqueue_fallback(zone, order, migratetype);
+ for(;;) {
+ page = __rmqueue_smallest(zone, order, migratetype);
+ if (likely(page) || migratetype == MIGRATE_RESERVE)
+ break;
- /*
- * Use MIGRATE_RESERVE rather than fail an allocation. goto
- * is used because __rmqueue_smallest is an inline function
- * and we want just one call site
- */
- if (!page) {
- migratetype = MIGRATE_RESERVE;
- goto retry_reserve;
+ if (is_migrate_cma(migratetype)) {
+ migratetype = MIGRATE_MOVABLE;
+ continue;
}
+
+ page = __rmqueue_fallback(zone, order, migratetype);
+ if (page)
+ break;
+
+ /* Use MIGRATE_RESERVE rather than fail an allocation. */
+ migratetype = MIGRATE_RESERVE;
}
trace_mm_page_alloc_zone_locked(page, order, migratetype);
@@ -2791,6 +2786,31 @@
#define K(x) ((x) << (PAGE_SHIFT-10))
+static void show_migration_types(unsigned char type)
+{
+ static const char types[MIGRATE_TYPES] = {
+ [MIGRATE_UNMOVABLE] = 'U',
+ [MIGRATE_RECLAIMABLE] = 'E',
+ [MIGRATE_MOVABLE] = 'M',
+ [MIGRATE_RESERVE] = 'R',
+#ifdef CONFIG_CMA
+ [MIGRATE_CMA] = 'C',
+#endif
+ [MIGRATE_ISOLATE] = 'I',
+ };
+ char tmp[MIGRATE_TYPES + 1];
+ char *p = tmp;
+ int i;
+
+ for (i = 0; i < MIGRATE_TYPES; i++) {
+ if (type & (1 << i))
+ *p++ = types[i];
+ }
+
+ *p = '\0';
+ printk("(%s) ", tmp);
+}
+
/*
* Show free area list (used inside shift_scroll-lock stuff)
* We also calculate the percentage fragmentation. We do this by counting the
@@ -2919,6 +2939,7 @@
for_each_populated_zone(zone) {
unsigned long nr[MAX_ORDER], flags, order, total = 0;
+ unsigned char types[MAX_ORDER];
if (skip_free_areas_node(filter, zone_to_nid(zone)))
continue;
@@ -2927,12 +2948,24 @@
spin_lock_irqsave(&zone->lock, flags);
for (order = 0; order < MAX_ORDER; order++) {
- nr[order] = zone->free_area[order].nr_free;
+ struct free_area *area = &zone->free_area[order];
+ int type;
+
+ nr[order] = area->nr_free;
total += nr[order] << order;
+
+ types[order] = 0;
+ for (type = 0; type < MIGRATE_TYPES; type++) {
+ if (!list_empty(&area->free_list[type]))
+ types[order] |= 1 << type;
+ }
}
spin_unlock_irqrestore(&zone->lock, flags);
- for (order = 0; order < MAX_ORDER; order++)
+ for (order = 0; order < MAX_ORDER; order++) {
printk("%lu*%lukB ", nr[order], K(1UL) << order);
+ if (nr[order])
+ show_migration_types(types[order]);
+ }
printk("= %lukB\n", K(total));
}
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index e672cdb..d7521f8 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. 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
@@ -99,7 +99,8 @@
RX_MIX1_INP_SEL_RX7,
};
-#define TABLA_COMP_DIGITAL_GAIN_OFFSET 3
+#define TABLA_COMP_DIGITAL_GAIN_HP_OFFSET 3
+#define TABLA_COMP_DIGITAL_GAIN_LINEOUT_OFFSET 6
#define TABLA_MCLK_RATE_12288KHZ 12288000
#define TABLA_MCLK_RATE_9600KHZ 9600000
@@ -127,7 +128,9 @@
#define TABLA_MBHC_GND_MIC_SWAP_THRESHOLD 2
-#define TABLA_ACQUIRE_LOCK(x) do { mutex_lock(&x); } while (0)
+#define TABLA_ACQUIRE_LOCK(x) do { \
+ mutex_lock_nested(&x, SINGLE_DEPTH_NESTING); \
+} while (0)
#define TABLA_RELEASE_LOCK(x) do { mutex_unlock(&x); } while (0)
static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
@@ -188,6 +191,16 @@
COMPANDER_FS_MAX,
};
+enum {
+ COMP_SHUTDWN_TIMEOUT_PCM_1 = 0,
+ COMP_SHUTDWN_TIMEOUT_PCM_240,
+ COMP_SHUTDWN_TIMEOUT_PCM_480,
+ COMP_SHUTDWN_TIMEOUT_PCM_960,
+ COMP_SHUTDWN_TIMEOUT_PCM_1440,
+ COMP_SHUTDWN_TIMEOUT_PCM_2880,
+ COMP_SHUTDWN_TIMEOUT_PCM_5760,
+};
+
/* Flags to track of PA and DAC state.
* PA and DAC should be tracked separately as AUXPGA loopback requires
* only PA to be turned on without DAC being on. */
@@ -203,6 +216,7 @@
u32 peak_det_timeout;
u32 rms_meter_div_fact;
u32 rms_meter_resamp_fact;
+ u32 shutdown_timeout;
};
/* Data used by MBHC */
@@ -399,7 +413,7 @@
static const u32 comp_shift[] = {
0,
- 2,
+ 1,
};
static const int comp_rx_path[] = {
@@ -412,28 +426,43 @@
COMPANDER_MAX,
};
-static const struct comp_sample_dependent_params comp_samp_params[] = {
+static const struct comp_sample_dependent_params
+ comp_samp_params[COMPANDER_FS_MAX] = {
{
- .peak_det_timeout = 0x2,
- .rms_meter_div_fact = 0x8 << 4,
- .rms_meter_resamp_fact = 0x21,
- },
- {
- .peak_det_timeout = 0x3,
+ .peak_det_timeout = 0x6,
.rms_meter_div_fact = 0x9 << 4,
- .rms_meter_resamp_fact = 0x28,
+ .rms_meter_resamp_fact = 0x06,
+ .shutdown_timeout = COMP_SHUTDWN_TIMEOUT_PCM_240 << 3,
},
-
{
- .peak_det_timeout = 0x5,
+ .peak_det_timeout = 0x7,
+ .rms_meter_div_fact = 0xA << 4,
+ .rms_meter_resamp_fact = 0x0C,
+ .shutdown_timeout = COMP_SHUTDWN_TIMEOUT_PCM_480 << 3,
+ },
+ {
+ .peak_det_timeout = 0x8,
+ .rms_meter_div_fact = 0xB << 4,
+ .rms_meter_resamp_fact = 0x30,
+ .shutdown_timeout = COMP_SHUTDWN_TIMEOUT_PCM_960 << 3,
+ },
+ {
+ .peak_det_timeout = 0x9,
.rms_meter_div_fact = 0xB << 4,
.rms_meter_resamp_fact = 0x28,
+ .shutdown_timeout = COMP_SHUTDWN_TIMEOUT_PCM_1440 << 3,
},
-
{
- .peak_det_timeout = 0x5,
- .rms_meter_div_fact = 0xB << 4,
- .rms_meter_resamp_fact = 0x28,
+ .peak_det_timeout = 0xA,
+ .rms_meter_div_fact = 0xC << 4,
+ .rms_meter_resamp_fact = 0x50,
+ .shutdown_timeout = COMP_SHUTDWN_TIMEOUT_PCM_2880 << 3,
+ },
+ {
+ .peak_det_timeout = 0xB,
+ .rms_meter_div_fact = 0xC << 4,
+ .rms_meter_resamp_fact = 0x50,
+ .shutdown_timeout = COMP_SHUTDWN_TIMEOUT_PCM_5760 << 3,
},
};
@@ -484,6 +513,8 @@
snd_soc_update_bits(codec, TABLA_A_CDC_CLSG_CTL, 0x08, 0x00);
snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x01,
0x00);
+ snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_RESET_CTL, 0x10,
+ 0x00);
snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x08, 0x00);
break;
}
@@ -726,7 +757,7 @@
static int tabla_compander_gain_offset(
struct snd_soc_codec *codec, u32 enable,
- unsigned int reg, int mask, int event)
+ unsigned int reg, int mask, int event, u32 comp)
{
int pa_mode = snd_soc_read(codec, reg) & mask;
int gain_offset = 0;
@@ -736,10 +767,21 @@
* if PMD && pa_mode is comp -> offset is -3: PMU compander is on.
*/
- if (SND_SOC_DAPM_EVENT_ON(event) && (enable != 0))
- gain_offset = TABLA_COMP_DIGITAL_GAIN_OFFSET;
- if (SND_SOC_DAPM_EVENT_OFF(event) && (pa_mode == 0))
- gain_offset = -TABLA_COMP_DIGITAL_GAIN_OFFSET;
+ if (SND_SOC_DAPM_EVENT_ON(event) && (enable != 0)) {
+ if (comp == COMPANDER_1)
+ gain_offset = TABLA_COMP_DIGITAL_GAIN_HP_OFFSET;
+ if (comp == COMPANDER_2)
+ gain_offset = TABLA_COMP_DIGITAL_GAIN_LINEOUT_OFFSET;
+ }
+ if (SND_SOC_DAPM_EVENT_OFF(event) && (pa_mode == 0)) {
+ if (comp == COMPANDER_1)
+ gain_offset = -TABLA_COMP_DIGITAL_GAIN_HP_OFFSET;
+ if (comp == COMPANDER_2)
+ gain_offset = -TABLA_COMP_DIGITAL_GAIN_LINEOUT_OFFSET;
+
+ }
+ pr_debug("%s: compander #%d gain_offset %d\n",
+ __func__, comp + 1, gain_offset);
return gain_offset;
}
@@ -762,38 +804,38 @@
if (compander == COMPANDER_1) {
gain_offset = tabla_compander_gain_offset(codec, enable,
- TABLA_A_RX_HPH_L_GAIN, mask, event);
+ TABLA_A_RX_HPH_L_GAIN, mask, event, compander);
snd_soc_update_bits(codec, TABLA_A_RX_HPH_L_GAIN, mask, value);
gain = snd_soc_read(codec, TABLA_A_CDC_RX1_VOL_CTL_B2_CTL);
snd_soc_update_bits(codec, TABLA_A_CDC_RX1_VOL_CTL_B2_CTL,
0xFF, gain - gain_offset);
gain_offset = tabla_compander_gain_offset(codec, enable,
- TABLA_A_RX_HPH_R_GAIN, mask, event);
+ TABLA_A_RX_HPH_R_GAIN, mask, event, compander);
snd_soc_update_bits(codec, TABLA_A_RX_HPH_R_GAIN, mask, value);
gain = snd_soc_read(codec, TABLA_A_CDC_RX2_VOL_CTL_B2_CTL);
snd_soc_update_bits(codec, TABLA_A_CDC_RX2_VOL_CTL_B2_CTL,
0xFF, gain - gain_offset);
} else if (compander == COMPANDER_2) {
gain_offset = tabla_compander_gain_offset(codec, enable,
- TABLA_A_RX_LINE_1_GAIN, mask, event);
+ TABLA_A_RX_LINE_1_GAIN, mask, event, compander);
snd_soc_update_bits(codec, TABLA_A_RX_LINE_1_GAIN, mask, value);
gain = snd_soc_read(codec, TABLA_A_CDC_RX3_VOL_CTL_B2_CTL);
snd_soc_update_bits(codec, TABLA_A_CDC_RX3_VOL_CTL_B2_CTL,
0xFF, gain - gain_offset);
gain_offset = tabla_compander_gain_offset(codec, enable,
- TABLA_A_RX_LINE_3_GAIN, mask, event);
+ TABLA_A_RX_LINE_3_GAIN, mask, event, compander);
snd_soc_update_bits(codec, TABLA_A_RX_LINE_3_GAIN, mask, value);
gain = snd_soc_read(codec, TABLA_A_CDC_RX4_VOL_CTL_B2_CTL);
snd_soc_update_bits(codec, TABLA_A_CDC_RX4_VOL_CTL_B2_CTL,
0xFF, gain - gain_offset);
gain_offset = tabla_compander_gain_offset(codec, enable,
- TABLA_A_RX_LINE_2_GAIN, mask, event);
+ TABLA_A_RX_LINE_2_GAIN, mask, event, compander);
snd_soc_update_bits(codec, TABLA_A_RX_LINE_2_GAIN, mask, value);
gain = snd_soc_read(codec, TABLA_A_CDC_RX5_VOL_CTL_B2_CTL);
snd_soc_update_bits(codec, TABLA_A_CDC_RX5_VOL_CTL_B2_CTL,
0xFF, gain - gain_offset);
gain_offset = tabla_compander_gain_offset(codec, enable,
- TABLA_A_RX_LINE_4_GAIN, mask, event);
+ TABLA_A_RX_LINE_4_GAIN, mask, event, compander);
snd_soc_update_bits(codec, TABLA_A_RX_LINE_4_GAIN, mask, value);
gain = snd_soc_read(codec, TABLA_A_CDC_RX6_VOL_CTL_B2_CTL);
snd_soc_update_bits(codec, TABLA_A_CDC_RX6_VOL_CTL_B2_CTL,
@@ -823,10 +865,11 @@
int comp = ((struct soc_multi_mixer_control *)
kcontrol->private_value)->max;
int value = ucontrol->value.integer.value[0];
-
+ pr_debug("%s: compander #%d enable %d\n",
+ __func__, comp + 1, value);
if (value == tabla->comp_enabled[comp]) {
pr_debug("%s: compander #%d enable %d no change\n",
- __func__, comp, value);
+ __func__, comp + 1, value);
return 0;
}
tabla->comp_enabled[comp] = value;
@@ -841,34 +884,44 @@
struct snd_soc_codec *codec = w->codec;
struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
u32 rate = tabla->comp_fs[w->shift];
-
+ u32 status;
+ unsigned long timeout;
+ pr_debug("%s: compander #%d enable %d event %d\n",
+ __func__, w->shift + 1,
+ tabla->comp_enabled[w->shift], event);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
if (tabla->comp_enabled[w->shift] != 0) {
/* Enable both L/R compander clocks */
snd_soc_update_bits(codec,
TABLA_A_CDC_CLK_RX_B2_CTL,
- 0x03 << comp_shift[w->shift],
- 0x03 << comp_shift[w->shift]);
- /* Clar the HALT for the compander*/
+ 1 << comp_shift[w->shift],
+ 1 << comp_shift[w->shift]);
+ /* Clear the HALT for the compander*/
snd_soc_update_bits(codec,
TABLA_A_CDC_COMP1_B1_CTL +
w->shift * 8, 1 << 2, 0);
/* Toggle compander reset bits*/
snd_soc_update_bits(codec,
TABLA_A_CDC_CLK_OTHR_RESET_CTL,
- 0x03 << comp_shift[w->shift],
- 0x03 << comp_shift[w->shift]);
+ 1 << comp_shift[w->shift],
+ 1 << comp_shift[w->shift]);
snd_soc_update_bits(codec,
TABLA_A_CDC_CLK_OTHR_RESET_CTL,
- 0x03 << comp_shift[w->shift], 0);
+ 1 << comp_shift[w->shift], 0);
tabla_config_gain_compander(codec, w->shift, 1, event);
+ /* Compander enable -> 0x370/0x378*/
+ snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B1_CTL +
+ w->shift * 8, 0x03, 0x03);
/* Update the RMS meter resampling*/
snd_soc_update_bits(codec,
TABLA_A_CDC_COMP1_B3_CTL +
w->shift * 8, 0xFF, 0x01);
+ snd_soc_update_bits(codec,
+ TABLA_A_CDC_COMP1_B2_CTL +
+ w->shift * 8, 0xF0, 0x50);
/* Wait for 1ms*/
- usleep_range(1000, 1000);
+ usleep_range(5000, 5000);
}
break;
case SND_SOC_DAPM_POST_PMU:
@@ -885,26 +938,50 @@
snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B3_CTL +
w->shift * 8, 0xFF,
comp_samp_params[rate].rms_meter_resamp_fact);
- /* Compander enable -> 0x370/0x378*/
snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B1_CTL +
- w->shift * 8, 0x03, 0x03);
+ w->shift * 8, 0x38,
+ comp_samp_params[rate].shutdown_timeout);
}
break;
case SND_SOC_DAPM_PRE_PMD:
- /* Halt the compander*/
- snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B1_CTL +
- w->shift * 8, 1 << 2, 1 << 2);
+ if (tabla->comp_enabled[w->shift] != 0) {
+ status = snd_soc_read(codec,
+ TABLA_A_CDC_COMP1_SHUT_DOWN_STATUS +
+ w->shift * 8);
+ pr_debug("%s: compander #%d shutdown status %d in event %d\n",
+ __func__, w->shift + 1, status, event);
+ /* Halt the compander*/
+ snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B1_CTL +
+ w->shift * 8, 1 << 2, 1 << 2);
+ }
break;
case SND_SOC_DAPM_POST_PMD:
- /* Restore the gain */
- tabla_config_gain_compander(codec, w->shift,
- tabla->comp_enabled[w->shift], event);
- /* Disable the compander*/
- snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B1_CTL +
- w->shift * 8, 0x03, 0x00);
- /* Turn off the clock for compander in pair*/
- snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_B2_CTL,
- 0x03 << comp_shift[w->shift], 0);
+ if (tabla->comp_enabled[w->shift] != 0) {
+ /* Wait up to a second for shutdown complete */
+ timeout = jiffies + HZ;
+ do {
+ status = snd_soc_read(codec,
+ TABLA_A_CDC_COMP1_SHUT_DOWN_STATUS +
+ w->shift * 8);
+ if (status == 0x3)
+ break;
+ usleep_range(5000, 5000);
+ } while (!(time_after(jiffies, timeout)));
+ /* Restore the gain */
+ tabla_config_gain_compander(codec, w->shift,
+ tabla->comp_enabled[w->shift],
+ event);
+ /* Disable the compander*/
+ snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B1_CTL +
+ w->shift * 8, 0x03, 0x00);
+ /* Turn off the clock for compander in pair*/
+ snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_B2_CTL,
+ 0x03 << comp_shift[w->shift], 0);
+ /* Clear the HALT for the compander*/
+ snd_soc_update_bits(codec,
+ TABLA_A_CDC_COMP1_B1_CTL +
+ w->shift * 8, 1 << 2, 0);
+ }
break;
}
return 0;
@@ -2558,6 +2635,9 @@
return;
}
+ snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x01, 0x01);
+ msleep(250);
+ snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
pr_debug("%s: leave\n", __func__);
}
@@ -3982,6 +4062,10 @@
if (reg == TABLA_A_RX_HPH_L_STATUS || reg == TABLA_A_RX_HPH_R_STATUS)
return 1;
+ if (reg == TABLA_A_CDC_COMP1_SHUT_DOWN_STATUS ||
+ reg == TABLA_A_CDC_COMP2_SHUT_DOWN_STATUS)
+ return 1;
+
return 0;
}
@@ -7524,6 +7608,7 @@
{
bool insert;
struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+ struct wcd9xxx *core = dev_get_drvdata(codec->dev->parent);
bool is_removed = false;
pr_debug("%s: enter\n", __func__);
@@ -7533,6 +7618,7 @@
usleep_range(TABLA_GPIO_IRQ_DEBOUNCE_TIME_US,
TABLA_GPIO_IRQ_DEBOUNCE_TIME_US);
+ wcd9xxx_nested_irq_lock(core);
TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
/* cancel pending button press */
@@ -7604,6 +7690,7 @@
tabla->in_gpio_handler = false;
TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
+ wcd9xxx_nested_irq_unlock(core);
pr_debug("%s: leave\n", __func__);
}
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index 1546b9e..ad1546d 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. 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
@@ -4892,12 +4892,53 @@
}
EXPORT_SYMBOL_GPL(taiko_hs_detect);
+static int taiko_post_reset_cb(struct wcd9xxx *wcd9xxx)
+{
+ int ret = 0;
+ struct snd_soc_codec *codec;
+ struct taiko_priv *taiko;
+
+ codec = (struct snd_soc_codec *)(wcd9xxx->ssr_priv);
+ taiko = snd_soc_codec_get_drvdata(codec);
+ mutex_lock(&codec->mutex);
+ WCD9XXX_BCL_LOCK(&taiko->resmgr);
+ if (spkr_drv_wrnd == 1) {
+ wcd9xxx_resmgr_post_ssr(&taiko->resmgr);
+ snd_soc_update_bits(codec, TAIKO_A_SPKR_DRV_EN, 0x80, 0x80);
+ }
+ WCD9XXX_BCL_UNLOCK(&taiko->resmgr);
+
+ if (codec->reg_def_copy) {
+ pr_debug("%s: Update ASOC cache", __func__);
+ kfree(codec->reg_cache);
+ codec->reg_cache = kmemdup(codec->reg_def_copy,
+ codec->reg_size, GFP_KERNEL);
+ }
+
+ taiko_update_reg_defaults(codec);
+ taiko_codec_init_reg(codec);
+ ret = taiko_handle_pdata(taiko);
+ if (IS_ERR_VALUE(ret))
+ pr_err("%s: bad pdata\n", __func__);
+ mutex_unlock(&codec->mutex);
+ return ret;
+}
+
+
static struct wcd9xxx_reg_address taiko_reg_address = {
.micb_4_mbhc = TAIKO_A_MICB_4_MBHC,
.micb_4_int_rbias = TAIKO_A_MICB_4_INT_RBIAS,
.micb_4_ctl = TAIKO_A_MICB_4_CTL,
};
+static int wcd9xxx_ssr_register(struct wcd9xxx *control,
+ int (*post_reset_cb)(struct wcd9xxx *wcd9xxx), void *priv)
+{
+ control->post_reset = post_reset_cb;
+ control->ssr_priv = priv;
+ return 0;
+}
+
static int taiko_codec_probe(struct snd_soc_codec *codec)
{
struct wcd9xxx *control;
@@ -4912,6 +4953,8 @@
codec->control_data = dev_get_drvdata(codec->dev->parent);
control = codec->control_data;
+ wcd9xxx_ssr_register(control, taiko_post_reset_cb, (void *)codec);
+
dev_info(codec->dev, "%s()\n", __func__);
taiko = kzalloc(sizeof(struct taiko_priv), GFP_KERNEL);
diff --git a/sound/soc/codecs/wcd9xxx-resmgr.c b/sound/soc/codecs/wcd9xxx-resmgr.c
index 3952dd5..0ab650e 100644
--- a/sound/soc/codecs/wcd9xxx-resmgr.c
+++ b/sound/soc/codecs/wcd9xxx-resmgr.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
@@ -116,7 +116,8 @@
/* Notify bg mode change */
wcd9xxx_resmgr_notifier_call(resmgr, WCD9XXX_EVENT_PRE_BG_OFF);
/* Disable bg */
- snd_soc_write(resmgr->codec, WCD9XXX_A_BIAS_CENTRAL_BG_CTL, 0x00);
+ snd_soc_update_bits(resmgr->codec, WCD9XXX_A_BIAS_CENTRAL_BG_CTL,
+ 0x03, 0x00);
usleep_range(100, 100);
/* Notify bg mode change */
wcd9xxx_resmgr_notifier_call(resmgr, WCD9XXX_EVENT_POST_BG_OFF);
@@ -194,6 +195,24 @@
pr_debug("%s: leave\n", __func__);
}
+void wcd9xxx_resmgr_post_ssr(struct wcd9xxx_resmgr *resmgr)
+{
+ int old_bg_audio_users, old_bg_mbhc_users;
+
+ WCD9XXX_BCL_ASSERT_LOCKED(resmgr);
+
+ old_bg_audio_users = resmgr->bg_audio_users;
+ resmgr->bg_audio_users = 0;
+ old_bg_mbhc_users = resmgr->bg_mbhc_users;
+ resmgr->bg_mbhc_users = 0;
+
+ while (old_bg_audio_users && --old_bg_audio_users)
+ wcd9xxx_resmgr_get_bandgap(resmgr, WCD9XXX_BANDGAP_AUDIO_MODE);
+
+ while (old_bg_mbhc_users && --old_bg_mbhc_users)
+ wcd9xxx_resmgr_get_bandgap(resmgr, WCD9XXX_BANDGAP_MBHC_MODE);
+}
+
/*
* wcd9xxx_resmgr_get_bandgap : Vote for bandgap ref
* choice : WCD9XXX_BANDGAP_AUDIO_MODE, WCD9XXX_BANDGAP_MBHC_MODE
diff --git a/sound/soc/codecs/wcd9xxx-resmgr.h b/sound/soc/codecs/wcd9xxx-resmgr.h
index 2d04102..6c30eeb 100644
--- a/sound/soc/codecs/wcd9xxx-resmgr.h
+++ b/sound/soc/codecs/wcd9xxx-resmgr.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
@@ -158,6 +158,7 @@
enum wcd9xxx_cfilt_sel cfilt_sel);
void wcd9xxx_resmgr_bcl_lock(struct wcd9xxx_resmgr *resmgr);
+void wcd9xxx_resmgr_post_ssr(struct wcd9xxx_resmgr *resmgr);
#define WCD9XXX_BCL_LOCK(resmgr) \
{ \
pr_debug("%s: Acquiring BCL\n", __func__); \
diff --git a/sound/soc/msm/Makefile b/sound/soc/msm/Makefile
index 4c8d2e3..e5f0208 100644
--- a/sound/soc/msm/Makefile
+++ b/sound/soc/msm/Makefile
@@ -55,8 +55,7 @@
# for MSM 8960 sound card driver
obj-$(CONFIG_SND_SOC_MSM_QDSP6_INTF) += qdsp6/
-
-snd-soc-qdsp6-objs := msm-dai-q6.o msm-pcm-q6.o msm-multi-ch-pcm-q6.o msm-lowlatency-pcm-q6.o msm-pcm-routing.o msm-dai-fe.o msm-compr-q6.o msm-dai-stub.o
+snd-soc-qdsp6-objs := msm-dai-q6.o msm-pcm-q6.o msm-multi-ch-pcm-q6.o msm-lowlatency-pcm-q6.o msm-pcm-loopback.o msm-pcm-routing.o msm-dai-fe.o msm-compr-q6.o msm-dai-stub.o
obj-$(CONFIG_SND_SOC_MSM_QDSP6_HDMI_AUDIO) += msm-dai-q6-hdmi.o
obj-$(CONFIG_SND_SOC_VOICE) += msm-pcm-voice.o msm-pcm-voip.o msm-pcm-dtmf.o
snd-soc-qdsp6-objs += msm-pcm-lpa.o msm-pcm-afe.o
diff --git a/sound/soc/msm/mpq8064.c b/sound/soc/msm/mpq8064.c
index cef8659..784d516 100644
--- a/sound/soc/msm/mpq8064.c
+++ b/sound/soc/msm/mpq8064.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012-2013, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -1441,7 +1441,7 @@
.name = "MSM8960 Media3",
.stream_name = "MultiMedia3",
.cpu_dai_name = "MultiMedia3",
- .platform_name = "msm-pcm-dsp",
+ .platform_name = "msm-multi-ch-pcm-dsp",
.dynamic = 1,
.trigger = {SND_SOC_DPCM_TRIGGER_POST,
SND_SOC_DPCM_TRIGGER_POST},
diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c
index cf0d4cd..784b650 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, Code Aurora Forum. 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
@@ -229,6 +229,17 @@
.rate_min = 8000,
.rate_max = 48000,
},
+ .capture = {
+ .stream_name = "MultiMedia6 Capture",
+ .aif_name = "MM_UL6",
+ .rates = (SNDRV_PCM_RATE_8000_48000|
+ SNDRV_PCM_RATE_KNOT),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
.ops = &msm_fe_Multimedia_dai_ops,
.name = "MultiMedia6",
},
diff --git a/sound/soc/msm/msm-dai-q6.c b/sound/soc/msm/msm-dai-q6.c
index 8cc0eaa..7381677 100644
--- a/sound/soc/msm/msm-dai-q6.c
+++ b/sound/soc/msm/msm-dai-q6.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
@@ -743,15 +743,14 @@
{
int rc = 0;
+ struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
mutex_lock(&aux_pcm_mutex);
-
- if (aux_pcm_count == 0) {
- dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count is 0. Just"
- " return\n", __func__, dai->id);
+ dev_dbg(dai->dev, "%s dai->id = %d", __func__, dai->id);
+ if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
mutex_unlock(&aux_pcm_mutex);
return;
}
-
+ clear_bit(STATUS_PORT_STARTED, dai_data->status_mask);
aux_pcm_count--;
if (aux_pcm_count > 0) {
@@ -866,24 +865,13 @@
unsigned long pcm_clk_rate;
mutex_lock(&aux_pcm_mutex);
-
- if (aux_pcm_count == 2) {
- dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count is 2. Just"
- " return.\n", __func__, dai->id);
- mutex_unlock(&aux_pcm_mutex);
- return 0;
- } else if (aux_pcm_count > 2) {
- dev_err(dai->dev, "%s(): ERROR: dai->id %d"
- " aux_pcm_count = %d > 2\n",
- __func__, dai->id, aux_pcm_count);
- mutex_unlock(&aux_pcm_mutex);
- return 0;
- }
-
+ set_bit(STATUS_PORT_STARTED,
+ dai_data->status_mask);
+ dev_dbg(dai->dev, "%s dai->id = %d", __func__, dai->id);
aux_pcm_count++;
- if (aux_pcm_count == 2) {
- dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count = %d after "
- " increment\n", __func__, dai->id, aux_pcm_count);
+ if (aux_pcm_count >= 2) {
+ dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count = %d >= 2\n",
+ __func__, dai->id, aux_pcm_count);
mutex_unlock(&aux_pcm_mutex);
return 0;
}
diff --git a/sound/soc/msm/msm-pcm-loopback.c b/sound/soc/msm/msm-pcm-loopback.c
new file mode 100644
index 0000000..55f29a5
--- /dev/null
+++ b/sound/soc/msm/msm-pcm-loopback.c
@@ -0,0 +1,327 @@
+/* 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/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <sound/apr_audio.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/q6asm.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <asm/dma.h>
+#include <linux/dma-mapping.h>
+
+#include "msm-pcm-routing.h"
+
+struct msm_pcm {
+ struct snd_pcm_substream *playback_substream;
+ struct snd_pcm_substream *capture_substream;
+
+ int instance;
+
+ struct mutex lock;
+
+ uint32_t samp_rate;
+ uint32_t channel_mode;
+
+ int playback_start;
+ int capture_start;
+ int session_id;
+ struct audio_client *audio_client;
+};
+
+static void stop_pcm(struct msm_pcm *pcm);
+
+static struct msm_pcm pcm_info;
+
+static const struct snd_pcm_hardware dummy_pcm_hardware = {
+ .formats = 0xffffffff,
+ .channels_min = 1,
+ .channels_max = UINT_MAX,
+
+ /* Random values to keep userspace happy when checking constraints */
+ .info = SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER,
+ .buffer_bytes_max = 128*1024,
+ .period_bytes_min = PAGE_SIZE,
+ .period_bytes_max = PAGE_SIZE*2,
+ .periods_min = 2,
+ .periods_max = 128,
+};
+
+static void event_handler(uint32_t opcode,
+ uint32_t token, uint32_t *payload, void *priv)
+{
+ pr_debug("%s\n", __func__);
+ switch (opcode) {
+ case APR_BASIC_RSP_RESULT:
+ pr_debug("%s: opcode[0x%x]\n", __func__, opcode);
+ break;
+ default:
+ pr_err("Not Supported Event opcode[0x%x]\n", opcode);
+ break;
+ }
+}
+
+static int msm_pcm_open(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct msm_pcm *pcm = &pcm_info;
+ int ret = 0;
+
+ mutex_lock(&pcm->lock);
+
+ snd_soc_set_runtime_hwparams(substream, &dummy_pcm_hardware);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ pcm->playback_substream = substream;
+ else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ pcm->capture_substream = substream;
+
+ pcm->instance++;
+ pr_debug("%s: pcm out open: %d,%d\n", __func__,
+ pcm->instance, substream->stream);
+ if (pcm->instance == 2) {
+ struct snd_soc_pcm_runtime *soc_pcm_rx =
+ pcm->playback_substream->private_data;
+ struct snd_soc_pcm_runtime *soc_pcm_tx =
+ pcm->capture_substream->private_data;
+ if (pcm->audio_client != NULL)
+ stop_pcm(pcm);
+
+ pcm->audio_client = q6asm_audio_client_alloc(
+ (app_cb)event_handler, pcm);
+ if (!pcm->audio_client) {
+ pr_err("%s: Could not allocate memory\n", __func__);
+ mutex_unlock(&pcm->lock);
+ return -ENOMEM;
+ }
+ pcm->session_id = pcm->audio_client->session;
+ pcm->audio_client->perf_mode = false;
+ ret = q6asm_open_loopack(pcm->audio_client);
+ if (ret < 0) {
+ pr_err("%s: pcm out open failed\n", __func__);
+ q6asm_audio_client_free(pcm->audio_client);
+ mutex_unlock(&pcm->lock);
+ return -ENOMEM;
+ }
+ msm_pcm_routing_reg_phy_stream(soc_pcm_tx->dai_link->be_id,
+ pcm->audio_client->perf_mode,
+ pcm->session_id, pcm->capture_substream->stream);
+ msm_pcm_routing_reg_phy_stream(soc_pcm_rx->dai_link->be_id,
+ pcm->audio_client->perf_mode,
+ pcm->session_id, pcm->playback_substream->stream);
+ }
+ pr_debug("%s: Instance = %d, Stream ID = %s\n",
+ __func__ , pcm->instance, substream->pcm->id);
+ runtime->private_data = pcm;
+
+ mutex_unlock(&pcm->lock);
+
+ return 0;
+}
+
+int msm_set_lb_volume(unsigned volume)
+{
+ int rc = 0;
+ if (pcm_info.audio_client != NULL) {
+ pr_debug("%s: apply loopback vol:%d\n", __func__, volume);
+ rc = q6asm_set_volume(pcm_info.audio_client, volume);
+ if (rc < 0) {
+ pr_err("%s: Send Volume command failed" \
+ " rc=%d\n", __func__, rc);
+ }
+ }
+ return rc;
+}
+
+static void stop_pcm(struct msm_pcm *pcm)
+{
+ struct snd_soc_pcm_runtime *soc_pcm_rx =
+ pcm->playback_substream->private_data;
+ struct snd_soc_pcm_runtime *soc_pcm_tx =
+ pcm->capture_substream->private_data;
+
+ if (pcm->audio_client == NULL)
+ return;
+ q6asm_cmd(pcm->audio_client, CMD_CLOSE);
+
+ msm_pcm_routing_dereg_phy_stream(soc_pcm_rx->dai_link->be_id,
+ SNDRV_PCM_STREAM_PLAYBACK);
+ msm_pcm_routing_dereg_phy_stream(soc_pcm_tx->dai_link->be_id,
+ SNDRV_PCM_STREAM_CAPTURE);
+ q6asm_audio_client_free(pcm->audio_client);
+ pcm->audio_client = NULL;
+}
+
+static int msm_pcm_close(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct msm_pcm *pcm = runtime->private_data;
+ int ret = 0;
+
+ mutex_lock(&pcm->lock);
+
+ pr_debug("%s: end pcm call:%d\n", __func__, substream->stream);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ pcm->playback_start = 0;
+ else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ pcm->capture_start = 0;
+
+ pcm->instance--;
+ if (!pcm->playback_start || !pcm->capture_start) {
+ pr_debug("%s: end pcm call\n", __func__);
+ stop_pcm(pcm);
+ }
+
+ mutex_unlock(&pcm->lock);
+ return ret;
+}
+
+static int msm_pcm_prepare(struct snd_pcm_substream *substream)
+{
+ int ret = 0;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct msm_pcm *pcm = runtime->private_data;
+
+ mutex_lock(&pcm->lock);
+
+ pr_debug("%s: ASM loopback stream:%d\n", __func__, substream->stream);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ if (!pcm->playback_start)
+ pcm->playback_start = 1;
+ } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ if (!pcm->capture_start)
+ pcm->capture_start = 1;
+ }
+ mutex_unlock(&pcm->lock);
+
+ return ret;
+}
+
+static int msm_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct msm_pcm *pcm = runtime->private_data;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ pr_debug("%s: playback_start:%d,capture_start:%d\n", __func__,
+ pcm->playback_start, pcm->capture_start);
+ if (pcm->playback_start && pcm->capture_start)
+ q6asm_run_nowait(pcm->audio_client, 0, 0, 0);
+ break;
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ case SNDRV_PCM_TRIGGER_STOP:
+ pr_debug("%s:Pause/Stop - playback_start:%d,capture_start:%d\n",
+ __func__, pcm->playback_start, pcm->capture_start);
+ if (pcm->playback_start && pcm->capture_start)
+ q6asm_cmd_nowait(pcm->audio_client, CMD_PAUSE);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int msm_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+
+ pr_debug("%s: ASM loopback\n", __func__);
+
+ return snd_pcm_lib_alloc_vmalloc_buffer(substream,
+ params_buffer_bytes(params));
+}
+
+static int msm_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+ return snd_pcm_lib_free_vmalloc_buffer(substream);
+}
+
+static struct snd_pcm_ops msm_pcm_ops = {
+ .open = msm_pcm_open,
+ .hw_params = msm_pcm_hw_params,
+ .hw_free = msm_pcm_hw_free,
+ .close = msm_pcm_close,
+ .prepare = msm_pcm_prepare,
+ .trigger = msm_pcm_trigger,
+};
+
+
+static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_card *card = rtd->card->snd_card;
+ int ret = 0;
+
+ if (!card->dev->coherent_dma_mask)
+ card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+ return ret;
+}
+
+static struct snd_soc_platform_driver msm_soc_platform = {
+ .ops = &msm_pcm_ops,
+ .pcm_new = msm_asoc_pcm_new,
+};
+
+static __devinit int msm_pcm_probe(struct platform_device *pdev)
+{
+ pr_debug("%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)
+{
+ snd_soc_unregister_platform(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver msm_pcm_driver = {
+ .driver = {
+ .name = "msm-pcm-loopback",
+ .owner = THIS_MODULE,
+ },
+ .probe = msm_pcm_probe,
+ .remove = __devexit_p(msm_pcm_remove),
+};
+
+static int __init msm_soc_platform_init(void)
+{
+ memset(&pcm_info, 0, sizeof(struct msm_pcm));
+ mutex_init(&pcm_info.lock);
+
+ return platform_driver_register(&msm_pcm_driver);
+}
+module_init(msm_soc_platform_init);
+
+static void __exit msm_soc_platform_exit(void)
+{
+ mutex_destroy(&pcm_info.lock);
+ platform_driver_unregister(&msm_pcm_driver);
+}
+module_exit(msm_soc_platform_exit);
+
+MODULE_DESCRIPTION("ASM loopback module platform driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/msm-pcm-lpa.c b/sound/soc/msm/msm-pcm-lpa.c
index ff0fb3b..a5be2e0 100644
--- a/sound/soc/msm/msm-pcm-lpa.c
+++ b/sound/soc/msm/msm-pcm-lpa.c
@@ -331,7 +331,7 @@
atomic_set(&prtd->stop, 1);
runtime->private_data = prtd;
lpa_audio.prtd = prtd;
- lpa_set_volume(lpa_audio.volume);
+ lpa_set_volume(0);
ret = q6asm_set_softpause(lpa_audio.prtd->audio_client, &softpause);
if (ret < 0)
pr_err("%s: Send SoftPause Param failed ret=%d\n",
diff --git a/sound/soc/msm/msm-pcm-q6.c b/sound/soc/msm/msm-pcm-q6.c
index 74136dc..8e29b5c 100644
--- a/sound/soc/msm/msm-pcm-q6.c
+++ b/sound/soc/msm/msm-pcm-q6.c
@@ -97,6 +97,25 @@
.mask = 0,
};
+static void msm_pcm_route_event_handler(enum msm_pcm_routing_event event,
+ void *priv_data)
+{
+ struct msm_audio *prtd = priv_data;
+
+ BUG_ON(!prtd);
+
+ pr_debug("%s: event %x\n", __func__, event);
+
+ switch (event) {
+ case MSM_PCM_RT_EVT_BUF_RECFG:
+ q6asm_cmd(prtd->audio_client, CMD_PAUSE);
+ q6asm_cmd(prtd->audio_client, CMD_FLUSH);
+ q6asm_run(prtd->audio_client, 0, 0, 0);
+ default:
+ break;
+ }
+}
+
static void event_handler(uint32_t opcode,
uint32_t token, uint32_t *payload, void *priv)
{
@@ -143,18 +162,33 @@
pr_debug("cmd[%d]=0x%08x\n", i, *ptrmem);
in_frame_info[token][0] = payload[2];
in_frame_info[token][1] = payload[3];
- prtd->pcm_irq_pos += in_frame_info[token][0];
- pr_debug("pcm_irq_pos=%d\n", prtd->pcm_irq_pos);
- if (atomic_read(&prtd->start))
- snd_pcm_period_elapsed(substream);
- if (atomic_read(&prtd->in_count) <= prtd->periods)
- atomic_inc(&prtd->in_count);
- wake_up(&the_locks.read_wait);
- if (prtd->mmap_flag
- && q6asm_is_cpu_buf_avail_nolock(OUT,
+
+ /* assume data size = 0 during flushing */
+ if (in_frame_info[token][0]) {
+ prtd->pcm_irq_pos += in_frame_info[token][0];
+ pr_debug("pcm_irq_pos=%d\n", prtd->pcm_irq_pos);
+ if (atomic_read(&prtd->start))
+ snd_pcm_period_elapsed(substream);
+ if (atomic_read(&prtd->in_count) <= prtd->periods)
+ atomic_inc(&prtd->in_count);
+ wake_up(&the_locks.read_wait);
+ if (prtd->mmap_flag &&
+ q6asm_is_cpu_buf_avail_nolock(OUT,
prtd->audio_client,
&size, &idx))
- q6asm_read_nolock(prtd->audio_client);
+ q6asm_read_nolock(prtd->audio_client);
+ } else {
+ pr_debug("%s: reclaim flushed buf in_count %x\n",
+ __func__, atomic_read(&prtd->in_count));
+ atomic_inc(&prtd->in_count);
+ if (atomic_read(&prtd->in_count) == prtd->periods) {
+ pr_info("%s: reclaimed all bufs\n", __func__);
+ if (atomic_read(&prtd->start))
+ snd_pcm_period_elapsed(substream);
+ wake_up(&the_locks.read_wait);
+ }
+ }
+
break;
}
case APR_BASIC_RSP_RESULT: {
@@ -627,6 +661,7 @@
struct audio_buffer *buf;
int dir, ret;
int format = FORMAT_LINEAR_PCM;
+ struct msm_pcm_routing_evt event;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
dir = IN;
@@ -650,10 +685,13 @@
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);
- }
+ event.event_func = msm_pcm_route_event_handler;
+ event.priv_data = (void *) prtd;
+ msm_pcm_routing_reg_phy_stream_v2(soc_prtd->dai_link->be_id,
+ prtd->audio_client->perf_mode,
+ prtd->session_id,
+ substream->stream, event);
+ }
ret = q6asm_audio_client_buf_alloc_contiguous(dir,
prtd->audio_client,
diff --git a/sound/soc/msm/msm-pcm-routing.c b/sound/soc/msm/msm-pcm-routing.c
index 841d313..aaae373 100644
--- a/sound/soc/msm/msm-pcm-routing.c
+++ b/sound/soc/msm/msm-pcm-routing.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
@@ -41,6 +41,12 @@
bool perf_mode;
};
+struct msm_pcm_routing_fdai_data {
+ u16 be_srate; /* track prior backend sample rate for flushing purpose */
+ int strm_id; /* ASM stream ID */
+ struct msm_pcm_routing_evt event_info;
+};
+
#define INVALID_SESSION -1
#define SESSION_TYPE_RX 0
#define SESSION_TYPE_TX 1
@@ -71,6 +77,10 @@
static const DECLARE_TLV_DB_LINEAR(multimedia5_rx_vol_gain, 0,
INT_RX_VOL_MAX_STEPS);
+static int msm_route_multimedia3_vol_control;
+static const DECLARE_TLV_DB_LINEAR(multimedia3_rx_vol_gain, 0,
+ INT_RX_VOL_MAX_STEPS);
+
static int msm_route_compressed_vol_control;
static const DECLARE_TLV_DB_LINEAR(compressed_rx_vol_gain, 0,
INT_RX_VOL_MAX_STEPS);
@@ -78,6 +88,10 @@
static int msm_route_compressed2_vol_control;
static const DECLARE_TLV_DB_LINEAR(compressed2_rx_vol_gain, 0,
INT_RX_VOL_MAX_STEPS);
+
+static int msm_route_compressed3_vol_control;
+static const DECLARE_TLV_DB_LINEAR(compressed3_rx_vol_gain, 0,
+ INT_RX_VOL_MAX_STEPS);
static int msm_route_ec_ref_rx;
/* Equal to Frontend after last of the MULTIMEDIA SESSIONS */
@@ -234,25 +248,35 @@
/* Track ASM playback & capture sessions of DAI */
-static int fe_dai_map[MSM_FRONTEND_DAI_MM_SIZE][2] = {
+static struct msm_pcm_routing_fdai_data
+ fe_dai_map[MSM_FRONTEND_DAI_MM_SIZE][2] = {
/* MULTIMEDIA1 */
- {INVALID_SESSION, INVALID_SESSION},
+ {{0, INVALID_SESSION, {NULL, NULL} },
+ {0, INVALID_SESSION, {NULL, NULL} } },
/* MULTIMEDIA2 */
- {INVALID_SESSION, INVALID_SESSION},
+ {{0, INVALID_SESSION, {NULL, NULL} },
+ {0, INVALID_SESSION, {NULL, NULL} } },
/* MULTIMEDIA3 */
- {INVALID_SESSION, INVALID_SESSION},
+ {{0, INVALID_SESSION, {NULL, NULL} },
+ {0, INVALID_SESSION, {NULL, NULL} } },
/* MULTIMEDIA4 */
- {INVALID_SESSION, INVALID_SESSION},
+ {{0, INVALID_SESSION, {NULL, NULL} },
+ {0, INVALID_SESSION, {NULL, NULL} } },
/* MULTIMEDIA5 */
- {INVALID_SESSION, INVALID_SESSION},
+ {{0, INVALID_SESSION, {NULL, NULL} },
+ {0, INVALID_SESSION, {NULL, NULL} } },
/* MULTIMEDIA6 */
- {INVALID_SESSION, INVALID_SESSION},
+ {{0, INVALID_SESSION, {NULL, NULL} },
+ {0, INVALID_SESSION, {NULL, NULL} } },
/* MULTIMEDIA7*/
- {INVALID_SESSION, INVALID_SESSION},
+ {{0, INVALID_SESSION, {NULL, NULL} },
+ {0, INVALID_SESSION, {NULL, NULL} } },
/* MULTIMEDIA8 */
- {INVALID_SESSION, INVALID_SESSION},
+ {{0, INVALID_SESSION, {NULL, NULL} },
+ {0, INVALID_SESSION, {NULL, NULL} } },
/* PSEUDO */
- {INVALID_SESSION, INVALID_SESSION},
+ {{0, INVALID_SESSION, {NULL, NULL} },
+ {0, INVALID_SESSION, {NULL, NULL} } },
};
static uint8_t is_be_dai_extproc(int be_dai)
@@ -312,10 +336,12 @@
}
mutex_lock(&routing_lock);
+
if (enable)
- fe_dai_map[fedai_id][session_type] = dspst_id;
+ fe_dai_map[fedai_id][session_type].strm_id = dspst_id;
else
- fe_dai_map[fedai_id][session_type] = INVALID_SESSION;
+ fe_dai_map[fedai_id][session_type].strm_id = INVALID_SESSION;
+
for (i = 0; i < MSM_BACKEND_DAI_MAX; i++) {
if (!is_be_dai_extproc(i) &&
(afe_get_port_type(msm_bedais[i].port_id) == port_type) &&
@@ -414,7 +440,7 @@
mutex_lock(&routing_lock);
payload.num_copps = 0; /* only RX needs to use payload */
- fe_dai_map[fedai_id][session_type] = dspst_id;
+ fe_dai_map[fedai_id][session_type].strm_id = dspst_id;
/* re-enable EQ if active */
if (eq_data[fedai_id].enable)
msm_send_eq_values(fedai_id);
@@ -464,6 +490,19 @@
mutex_unlock(&routing_lock);
}
+void msm_pcm_routing_reg_phy_stream_v2(int fedai_id, bool perf_mode,
+ int dspst_id, int stream_type,
+ struct msm_pcm_routing_evt event_info)
+{
+ msm_pcm_routing_reg_phy_stream(fedai_id, perf_mode, dspst_id,
+ stream_type);
+
+ if (stream_type == SNDRV_PCM_STREAM_PLAYBACK)
+ fe_dai_map[fedai_id][SESSION_TYPE_RX].event_info = event_info;
+ else
+ fe_dai_map[fedai_id][SESSION_TYPE_TX].event_info = event_info;
+
+}
void msm_pcm_routing_dereg_pseudo_stream(int fedai_id, int dspst_id)
{
@@ -522,8 +561,8 @@
}
}
- fe_dai_map[fedai_id][session_type] = INVALID_SESSION;
-
+ fe_dai_map[fedai_id][session_type].strm_id = INVALID_SESSION;
+ fe_dai_map[fedai_id][session_type].be_srate = 0;
mutex_unlock(&routing_lock);
}
@@ -548,6 +587,7 @@
{
int session_type, path_type;
u32 channels;
+ struct msm_pcm_routing_fdai_data *fdai;
pr_debug("%s: reg %x val %x set %x\n", __func__, reg, val, set);
@@ -574,11 +614,24 @@
voc_start_playback(set);
set_bit(val, &msm_bedais[reg].fe_sessions);
- if (msm_bedais[reg].active && fe_dai_map[val][session_type] !=
+ fdai = &fe_dai_map[val][session_type];
+ if (msm_bedais[reg].active && fdai->strm_id !=
INVALID_SESSION) {
channels = msm_bedais[reg].channel;
+ if (session_type == SESSION_TYPE_TX && fdai->be_srate &&
+ (fdai->be_srate != msm_bedais[reg].sample_rate)) {
+ pr_debug("%s: flush strm %d due diff BE rates\n",
+ __func__, fdai->strm_id);
+
+ if (fdai->event_info.event_func)
+ fdai->event_info.event_func(
+ MSM_PCM_RT_EVT_BUF_RECFG,
+ fdai->event_info.priv_data);
+ fdai->be_srate = 0; /* might not need it */
+ }
+
if ((session_type == SESSION_TYPE_RX) &&
((channels == 1) || (channels == 2))
&& msm_bedais[reg].perf_mode) {
@@ -606,7 +659,7 @@
msm_pcm_routing_build_matrix(val,
- fe_dai_map[val][session_type], path_type);
+ fdai->strm_id, path_type);
srs_port_id = msm_bedais[reg].port_id;
srs_send_params(srs_port_id, 1, 0);
}
@@ -615,11 +668,13 @@
(msm_bedais[reg].port_id == VOICE_PLAYBACK_TX))
voc_start_playback(set);
clear_bit(val, &msm_bedais[reg].fe_sessions);
- if (msm_bedais[reg].active && fe_dai_map[val][session_type] !=
+ fdai = &fe_dai_map[val][session_type];
+ if (msm_bedais[reg].active && fdai->strm_id !=
INVALID_SESSION) {
+ fdai->be_srate = msm_bedais[reg].sample_rate;
adm_close(msm_bedais[reg].port_id);
msm_pcm_routing_build_matrix(val,
- fe_dai_map[val][session_type], path_type);
+ fdai->strm_id, path_type);
}
}
if ((msm_bedais[reg].port_id == VOICE_RECORD_RX)
@@ -982,6 +1037,23 @@
return 0;
}
+static int msm_routing_get_multimedia3_vol_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = msm_route_multimedia3_vol_control;
+ return 0;
+}
+
+static int msm_routing_set_multimedia3_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_multimedia3_vol_control =
+ ucontrol->value.integer.value[0];
+
+ return 0;
+}
+
static int msm_routing_get_compressed_vol_mixer(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -1016,6 +1088,22 @@
return 0;
}
+static int msm_routing_get_compressed3_vol_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = msm_route_compressed3_vol_control;
+ return 0;
+}
+
+static int msm_routing_set_compressed3_vol_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ if (!compressed_set_volume(ucontrol->value.integer.value[0]))
+ msm_route_compressed3_vol_control =
+ ucontrol->value.integer.value[0];
+ return 0;
+}
+
static int msm_routing_get_srs_trumedia_control(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -1171,12 +1259,12 @@
static void msm_send_eq_values(int eq_idx)
{
int result;
- struct audio_client *ac =
- q6asm_get_audio_client(fe_dai_map[eq_idx][SESSION_TYPE_RX]);
+ struct audio_client *ac = q6asm_get_audio_client(
+ fe_dai_map[eq_idx][SESSION_TYPE_RX].strm_id);
if (ac == NULL) {
pr_err("%s: Could not get audio client for session: %d\n",
- __func__, fe_dai_map[eq_idx][SESSION_TYPE_RX]);
+ __func__, fe_dai_map[eq_idx][SESSION_TYPE_RX].strm_id);
goto done;
}
@@ -1520,6 +1608,9 @@
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),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new int_fm_rx_mixer_controls[] = {
@@ -1556,6 +1647,9 @@
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),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_AFE_PCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new auxpcm_rx_mixer_controls[] = {
@@ -1574,6 +1668,9 @@
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),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new sec_auxpcm_rx_mixer_controls[] = {
@@ -1670,6 +1767,12 @@
msm_routing_put_audio_mixer),
};
+static const struct snd_kcontrol_new mmul6_mixer_controls[] = {
+ SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 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,
@@ -2124,6 +2227,12 @@
msm_routing_set_multimedia5_vol_mixer, multimedia5_rx_vol_gain),
};
+static const struct snd_kcontrol_new multimedia3_vol_mixer_controls[] = {
+ SOC_SINGLE_EXT_TLV("HIFI4 RX Volume", SND_SOC_NOPM, 0,
+ INT_RX_VOL_GAIN, 0, msm_routing_get_multimedia3_vol_mixer,
+ msm_routing_set_multimedia3_vol_mixer, multimedia3_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,
@@ -2136,6 +2245,12 @@
msm_routing_set_compressed2_vol_mixer, compressed2_rx_vol_gain),
};
+static const struct snd_kcontrol_new compressed3_vol_mixer_controls[] = {
+ SOC_SINGLE_EXT_TLV("COMPRESSED3 RX Volume", SND_SOC_NOPM, 0,
+ INT_RX_VOL_GAIN, 0, msm_routing_get_compressed3_vol_mixer,
+ msm_routing_set_compressed3_vol_mixer, compressed3_rx_vol_gain),
+};
+
static const struct snd_kcontrol_new lpa_SRS_trumedia_controls[] = {
{.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "SRS TruMedia",
@@ -2449,6 +2564,7 @@
SND_SOC_DAPM_AIF_OUT("MM_UL2", "MultiMedia2 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MM_UL4", "MultiMedia4 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MM_UL5", "MultiMedia5 Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("MM_UL6", "MultiMedia6 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),
@@ -2556,6 +2672,8 @@
mmul4_mixer_controls, ARRAY_SIZE(mmul4_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("MultiMedia6 Mixer", SND_SOC_NOPM, 0, 0,
+ mmul6_mixer_controls, ARRAY_SIZE(mmul6_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)),
SND_SOC_DAPM_MIXER("SEC_AUX_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
@@ -2730,6 +2848,7 @@
{"MI2S_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
{"MI2S_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
{"MI2S_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"MI2S_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
{"MI2S_RX", NULL, "MI2S_RX Audio Mixer"},
{"MultiMedia1 Mixer", "PRI_TX", "PRI_I2S_TX"},
@@ -2748,6 +2867,7 @@
{"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"},
+ {"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
{"INT_BT_SCO_RX", NULL, "INTERNAL_BT_SCO_RX Audio Mixer"},
{"INTERNAL_FM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -2762,12 +2882,14 @@
{"AFE_PCM_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
{"AFE_PCM_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
{"AFE_PCM_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"AFE_PCM_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
{"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"},
+ {"MultiMedia6 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
{"MultiMedia1 Mixer", "AFE_PCM_TX", "PCM_TX"},
{"MultiMedia5 Mixer", "AFE_PCM_TX", "PCM_TX"},
@@ -2776,12 +2898,14 @@
{"MM_UL2", NULL, "MultiMedia2 Mixer"},
{"MM_UL4", NULL, "MultiMedia4 Mixer"},
{"MM_UL5", NULL, "MultiMedia5 Mixer"},
+ {"MM_UL6", NULL, "MultiMedia6 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 Audio Mixer", "MultiMedia6", "MM_DL6"},
{"AUX_PCM_RX", NULL, "AUX_PCM_RX Audio Mixer"},
{"SEC_AUX_PCM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -3028,7 +3152,9 @@
mutex_lock(&routing_lock);
for_each_set_bit(i, &bedai->fe_sessions, MSM_FRONTEND_DAI_MM_SIZE) {
- if (fe_dai_map[i][session_type] != INVALID_SESSION) {
+ if (fe_dai_map[i][session_type].strm_id != INVALID_SESSION) {
+ fe_dai_map[i][session_type].be_srate =
+ bedai->sample_rate;
adm_close(bedai->port_id);
srs_port_id = -1;
}
@@ -3051,6 +3177,7 @@
struct msm_pcm_routing_bdai_data *bedai;
u32 channels;
bool playback, capture;
+ struct msm_pcm_routing_fdai_data *fdai;
if (be_id >= MSM_BACKEND_DAI_MAX) {
pr_err("%s: unexpected be_id %d\n", __func__, be_id);
@@ -3082,7 +3209,21 @@
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) {
+ fdai = &fe_dai_map[i][session_type];
+ if (fdai->strm_id != INVALID_SESSION) {
+ if (session_type == SESSION_TYPE_TX && fdai->be_srate &&
+ (fdai->be_srate != bedai->sample_rate)) {
+ pr_debug("%s: flush strm %d due diff BE rates\n",
+ __func__,
+ fdai->strm_id);
+
+ if (fdai->event_info.event_func)
+ fdai->event_info.event_func(
+ MSM_PCM_RT_EVT_BUF_RECFG,
+ fdai->event_info.priv_data);
+ fdai->be_srate = 0; /* might not need it */
+ }
+
channels = bedai->channel;
if (bedai->port_id == PSEUDOPORT_01) {
adm_multi_ch_copp_pseudo_open_v3(bedai->port_id,
@@ -3116,7 +3257,7 @@
DEFAULT_COPP_TOPOLOGY);
msm_pcm_routing_build_matrix(i,
- fe_dai_map[i][session_type], path_type);
+ fdai->strm_id, path_type);
srs_port_id = bedai->port_id;
srs_send_params(srs_port_id, 1, 0);
}
@@ -3188,13 +3329,22 @@
ARRAY_SIZE(multimedia5_vol_mixer_controls));
snd_soc_add_platform_controls(platform,
+ multimedia3_vol_mixer_controls,
+ ARRAY_SIZE(multimedia3_vol_mixer_controls));
+
+ snd_soc_add_platform_controls(platform,
compressed_vol_mixer_controls,
ARRAY_SIZE(compressed_vol_mixer_controls));
+
snd_soc_add_platform_controls(platform,
compressed2_vol_mixer_controls,
ARRAY_SIZE(compressed2_vol_mixer_controls));
snd_soc_add_platform_controls(platform,
+ compressed3_vol_mixer_controls,
+ ARRAY_SIZE(compressed3_vol_mixer_controls));
+
+ snd_soc_add_platform_controls(platform,
lpa_SRS_trumedia_controls,
ARRAY_SIZE(lpa_SRS_trumedia_controls));
diff --git a/sound/soc/msm/msm-pcm-routing.h b/sound/soc/msm/msm-pcm-routing.h
index 0c0d3b4..202e7ea 100644
--- a/sound/soc/msm/msm-pcm-routing.h
+++ b/sound/soc/msm/msm-pcm-routing.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
@@ -113,6 +113,10 @@
MSM_BACKEND_DAI_MAX,
};
+enum msm_pcm_routing_event {
+ MSM_PCM_RT_EVT_BUF_RECFG,
+ MSM_PCM_RT_EVT_MAX,
+};
/* dai_id: front-end ID,
* dspst_id: DSP audio stream ID
* stream_type: playback or capture
@@ -128,10 +132,21 @@
void msm_pcm_routing_dereg_pseudo_stream(int fedai_id, int dspst_id);
+struct msm_pcm_routing_evt {
+ void (*event_func)(enum msm_pcm_routing_event, void *);
+ void *priv_data;
+};
+
+void msm_pcm_routing_reg_phy_stream_v2(int fedai_id, bool perf_mode,
+ int dspst_id, int stream_type,
+ struct msm_pcm_routing_evt event_info);
+
void msm_pcm_routing_dereg_phy_stream(int fedai_id, int stream_type);
int lpa_set_volume(unsigned volume);
+int msm_set_lb_volume(unsigned volume);
+
int msm_routing_check_backend_enabled(int fedai_id);
int multi_ch_pcm_set_volume(unsigned volume);
diff --git a/sound/soc/msm/msm8930.c b/sound/soc/msm/msm8930.c
index d674b8b..196cb44 100644
--- a/sound/soc/msm/msm8930.c
+++ b/sound/soc/msm/msm8930.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. 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
@@ -1135,6 +1135,22 @@
.ignore_pmdown_time = 1,
.be_id = MSM_FRONTEND_DAI_MULTIMEDIA5,
},
+ {
+ .name = "MSM8960 FM",
+ .stream_name = "MultiMedia6",
+ .cpu_dai_name = "MultiMedia6",
+ .platform_name = "msm-pcm-loopback",
+ .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,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA6,
+ },
/* Backend DAI Links */
{
.name = LPASS_BE_SLIMBUS_0_RX,
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index 633066f..6712941 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -28,6 +28,7 @@
#include <mach/socinfo.h>
#include <qdsp6v2/msm-pcm-routing-v2.h>
#include "../codecs/wcd9320.h"
+#include <linux/io.h>
#define DRV_NAME "msm8974-asoc-taiko"
@@ -40,15 +41,21 @@
#define BTSCO_RATE_8KHZ 8000
#define BTSCO_RATE_16KHZ 16000
+static int msm8974_auxpcm_rate = 8000;
#define LO_1_SPK_AMP 0x1
#define LO_3_SPK_AMP 0x2
#define LO_2_SPK_AMP 0x4
#define LO_4_SPK_AMP 0x8
-#define GPIO_AUX_PCM_DOUT 43
-#define GPIO_AUX_PCM_DIN 44
-#define GPIO_AUX_PCM_SYNC 45
-#define GPIO_AUX_PCM_CLK 46
+#define LPAIF_OFFSET 0xFE000000
+#define LPAIF_PRI_MODE_MUXSEL (LPAIF_OFFSET + 0x2B000)
+#define LPAIF_SEC_MODE_MUXSEL (LPAIF_OFFSET + 0x2C000)
+#define LPAIF_TER_MODE_MUXSEL (LPAIF_OFFSET + 0x2D000)
+#define LPAIF_QUAD_MODE_MUXSEL (LPAIF_OFFSET + 0x2E000)
+
+#define I2S_PCM_SEL 1
+#define I2S_PCM_SEL_OFFSET 1
+
#define WCD9XXX_MBHC_DEF_BUTTONS 8
#define WCD9XXX_MBHC_DEF_RLOADS 5
@@ -57,6 +64,13 @@
/* It takes about 13ms for Class-D PAs to ramp-up */
#define EXT_CLASS_D_EN_DELAY 13000
+#define NUM_OF_AUXPCM_GPIOS 4
+
+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),
+};
+
void *def_taiko_mbhc_cal(void);
static int msm_snd_enable_codec_ext_clk(struct snd_soc_codec *codec, int enable,
bool dapm);
@@ -75,11 +89,34 @@
.swap_gnd_mic = NULL,
};
+struct msm_auxpcm_gpio {
+ unsigned gpio_no;
+ const char *gpio_name;
+};
+
+struct msm_auxpcm_ctrl {
+ struct msm_auxpcm_gpio *pin_data;
+ u32 cnt;
+};
+
struct msm8974_asoc_mach_data {
int mclk_gpio;
u32 mclk_freq;
+ struct msm_auxpcm_ctrl *pri_auxpcm_ctrl;
};
+#define GPIO_NAME_INDEX 0
+#define DT_PARSE_INDEX 1
+
+static char *msm_auxpcm_gpio_name[][2] = {
+ {"PRIM_AUXPCM_CLK", "prim-auxpcm-gpio-clk"},
+ {"PRIM_AUXPCM_SYNC", "prim-auxpcm-gpio-sync"},
+ {"PRIM_AUXPCM_DIN", "prim-auxpcm-gpio-din"},
+ {"PRIM_AUXPCM_DOUT", "prim-auxpcm-gpio-dout"},
+};
+
+void *lpaif_pri_muxsel_virt_addr;
+
/* Shared channel numbers for Slimbus ports that connect APQ to MDM. */
enum {
SLIM_1_RX_1 = 145, /* BT-SCO and USB TX */
@@ -471,6 +508,30 @@
return 0;
}
+static int msm8974_auxpcm_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = msm8974_auxpcm_rate;
+ return 0;
+}
+
+static int msm8974_auxpcm_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ switch (ucontrol->value.integer.value[0]) {
+ case 0:
+ msm8974_auxpcm_rate = 8000;
+ break;
+ case 1:
+ msm8974_auxpcm_rate = 16000;
+ break;
+ default:
+ msm8974_auxpcm_rate = 8000;
+ break;
+ }
+ return 0;
+}
+
static int msm_auxpcm_be_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
@@ -480,8 +541,7 @@
struct snd_interval *channels =
hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
- /* PCM only supports mono output with 8khz sample rate */
- rate->min = rate->max = 8000;
+ rate->min = rate->max = msm8974_auxpcm_rate;
channels->min = channels->max = 1;
return 0;
@@ -516,59 +576,86 @@
return 0;
}
-static int msm_aux_pcm_get_gpios(void)
+static int msm_aux_pcm_get_gpios(struct snd_pcm_substream *substream)
{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_card *card = rtd->card;
+ struct msm8974_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+ struct msm_auxpcm_ctrl *auxpcm_ctrl = NULL;
+ struct msm_auxpcm_gpio *pin_data = NULL;
int ret = 0;
+ int i;
+ int j;
- pr_debug("%s\n", __func__);
-
- ret = gpio_request(GPIO_AUX_PCM_DOUT, "AUX PCM DOUT");
- if (ret < 0) {
- pr_err("%s: Failed to request gpio(%d): AUX PCM DOUT",
- __func__, GPIO_AUX_PCM_DOUT);
- goto fail_dout;
+ if (pdata == NULL) {
+ pr_err("%s: pdata is NULL\n", __func__);
+ ret = -EINVAL;
+ goto err;
}
- ret = gpio_request(GPIO_AUX_PCM_DIN, "AUX PCM DIN");
- if (ret < 0) {
- pr_err("%s: Failed to request gpio(%d): AUX PCM DIN",
- __func__, GPIO_AUX_PCM_DIN);
- goto fail_din;
+ auxpcm_ctrl = pdata->pri_auxpcm_ctrl;
+
+ if (auxpcm_ctrl == NULL || auxpcm_ctrl->pin_data == NULL) {
+ pr_err("%s: Ctrl pointers are NULL\n", __func__);
+ ret = -EINVAL;
+ goto err;
+ }
+ pin_data = auxpcm_ctrl->pin_data;
+ for (i = 0; i < auxpcm_ctrl->cnt; i++, pin_data++) {
+ ret = gpio_request(pin_data->gpio_no,
+ pin_data->gpio_name);
+ pr_debug("%s: gpio = %d, gpio name = %s\n"
+ "ret = %d\n", __func__,
+ pin_data->gpio_no,
+ pin_data->gpio_name,
+ ret);
+ if (ret) {
+ pr_err("%s: Failed to request gpio %d\n",
+ __func__, pin_data->gpio_no);
+ /* Release all GPIOs on failure */
+ for (j = i; j >= 0; j--)
+ gpio_free(pin_data->gpio_no);
+ goto err;
+ }
}
- ret = gpio_request(GPIO_AUX_PCM_SYNC, "AUX PCM SYNC");
- if (ret < 0) {
- pr_err("%s: Failed to request gpio(%d): AUX PCM SYNC",
- __func__, GPIO_AUX_PCM_SYNC);
- goto fail_sync;
- }
- ret = gpio_request(GPIO_AUX_PCM_CLK, "AUX PCM CLK");
- if (ret < 0) {
- pr_err("%s: Failed to request gpio(%d): AUX PCM CLK",
- __func__, GPIO_AUX_PCM_CLK);
- goto fail_clk;
- }
-
- return 0;
-
-fail_clk:
- gpio_free(GPIO_AUX_PCM_SYNC);
-fail_sync:
- gpio_free(GPIO_AUX_PCM_DIN);
-fail_din:
- gpio_free(GPIO_AUX_PCM_DOUT);
-fail_dout:
-
+err:
return ret;
}
-static int msm_aux_pcm_free_gpios(void)
-{
- gpio_free(GPIO_AUX_PCM_DIN);
- gpio_free(GPIO_AUX_PCM_DOUT);
- gpio_free(GPIO_AUX_PCM_SYNC);
- gpio_free(GPIO_AUX_PCM_CLK);
- return 0;
+static int msm_aux_pcm_free_gpios(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_card *card = rtd->card;
+ struct msm8974_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+ struct msm_auxpcm_ctrl *auxpcm_ctrl = NULL;
+ struct msm_auxpcm_gpio *pin_data = NULL;
+ int ret = 0;
+ int i;
+
+ if (pdata == NULL) {
+ pr_err("%s: pdata is NULL\n", __func__);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ auxpcm_ctrl = pdata->pri_auxpcm_ctrl;
+
+ if (auxpcm_ctrl == NULL || auxpcm_ctrl->pin_data == NULL) {
+ pr_err("%s: Ctrl pointers are NULL\n", __func__);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ pin_data = auxpcm_ctrl->pin_data;
+ for (i = 0; i < auxpcm_ctrl->cnt; i++, pin_data++) {
+ gpio_free(pin_data->gpio_no);
+ pr_debug("%s: gpio = %d, gpio_name = %s\n",
+ __func__, pin_data->gpio_no,
+ pin_data->gpio_name);
+ }
+err:
+ return ret;
}
static int msm_auxpcm_startup(struct snd_pcm_substream *substream)
@@ -577,8 +664,16 @@
pr_debug("%s(): substream = %s, auxpcm_rsc_ref counter = %d\n",
__func__, substream->name, atomic_read(&auxpcm_rsc_ref));
- if (atomic_inc_return(&auxpcm_rsc_ref) == 1)
- ret = msm_aux_pcm_get_gpios();
+
+ if (atomic_inc_return(&auxpcm_rsc_ref) == 1) {
+ if (lpaif_pri_muxsel_virt_addr != NULL)
+ iowrite32(I2S_PCM_SEL << I2S_PCM_SEL_OFFSET,
+ lpaif_pri_muxsel_virt_addr);
+ else
+ pr_err("%s lpaif_pri_muxsel_virt_addr is NULL\n",
+ __func__);
+ ret = msm_aux_pcm_get_gpios(substream);
+ }
if (ret < 0) {
pr_err("%s: Aux PCM GPIO request failed\n", __func__);
return -EINVAL;
@@ -592,7 +687,7 @@
pr_debug("%s(): substream = %s, auxpcm_rsc_ref counter = %d\n",
__func__, substream->name, atomic_read(&auxpcm_rsc_ref));
if (atomic_dec_return(&auxpcm_rsc_ref) == 0)
- msm_aux_pcm_free_gpios();
+ msm_aux_pcm_free_gpios(substream);
}
static struct snd_soc_ops msm_auxpcm_be_ops = {
.startup = msm_auxpcm_startup,
@@ -651,11 +746,13 @@
static const struct snd_kcontrol_new msm_snd_controls[] = {
SOC_ENUM_EXT("Speaker Function", msm_snd_enum[0], msm8974_get_spk,
- msm8974_set_spk),
+ msm8974_set_spk),
SOC_ENUM_EXT("SLIM_0_RX Channels", msm_snd_enum[1],
- msm_slim_0_rx_ch_get, msm_slim_0_rx_ch_put),
+ msm_slim_0_rx_ch_get, msm_slim_0_rx_ch_put),
SOC_ENUM_EXT("SLIM_0_TX Channels", msm_snd_enum[2],
- msm_slim_0_tx_ch_get, msm_slim_0_tx_ch_put),
+ msm_slim_0_tx_ch_get, msm_slim_0_tx_ch_put),
+ SOC_ENUM_EXT("AUX PCM SampleRate", msm8974_auxpcm_enum[0],
+ msm8974_auxpcm_rate_get, msm8974_auxpcm_rate_put),
};
static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
@@ -775,21 +872,21 @@
btn_high = wcd9xxx_mbhc_cal_btn_det_mp(btn_cfg,
MBHC_BTN_DET_V_BTN_HIGH);
btn_low[0] = -50;
- btn_high[0] = 10;
- btn_low[1] = 11;
- btn_high[1] = 52;
- btn_low[2] = 53;
- btn_high[2] = 94;
- btn_low[3] = 95;
- btn_high[3] = 133;
- btn_low[4] = 134;
- btn_high[4] = 171;
- btn_low[5] = 172;
- btn_high[5] = 208;
- btn_low[6] = 209;
- btn_high[6] = 244;
- btn_low[7] = 245;
- btn_high[7] = 330;
+ btn_high[0] = 20;
+ btn_low[1] = 21;
+ btn_high[1] = 63;
+ btn_low[2] = 64;
+ btn_high[2] = 106;
+ btn_low[3] = 107;
+ btn_high[3] = 146;
+ btn_low[4] = 146;
+ btn_high[4] = 186;
+ btn_low[5] = 187;
+ btn_high[5] = 221;
+ btn_low[6] = 222;
+ btn_high[6] = 253;
+ btn_low[7] = 254;
+ btn_high[7] = 500;
n_ready = wcd9xxx_mbhc_cal_btn_det_mp(btn_cfg, MBHC_BTN_DET_N_READY);
n_ready[0] = 80;
n_ready[1] = 68;
@@ -867,6 +964,7 @@
{
pr_debug("%s(): substream = %s stream = %d\n", __func__,
substream->name, substream->stream);
+
}
static struct snd_soc_ops msm8974_be_ops = {
@@ -1363,6 +1461,69 @@
.name = "msm8974-taiko-snd-card",
};
+static int msm8974_dtparse_auxpcm(struct platform_device *pdev,
+ struct msm8974_asoc_mach_data **pdata)
+{
+ int ret = 0;
+ int i = 0;
+ struct msm_auxpcm_gpio *pin_data = NULL;
+ struct msm_auxpcm_ctrl *ctrl;
+ unsigned int gpio_no[NUM_OF_AUXPCM_GPIOS];
+ enum of_gpio_flags flags = OF_GPIO_ACTIVE_LOW;
+ int prim_cnt = 0;
+
+ pin_data = devm_kzalloc(&pdev->dev, (ARRAY_SIZE(gpio_no) *
+ sizeof(struct msm_auxpcm_gpio)),
+ GFP_KERNEL);
+ if (!pin_data) {
+ dev_err(&pdev->dev, "No memory for gpio\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(gpio_no); i++) {
+ gpio_no[i] = of_get_named_gpio_flags(pdev->dev.of_node,
+ msm_auxpcm_gpio_name[i][DT_PARSE_INDEX],
+ 0, &flags);
+
+ if (gpio_no[i] > 0) {
+ pin_data[i].gpio_name =
+ msm_auxpcm_gpio_name[prim_cnt][GPIO_NAME_INDEX];
+ pin_data[i].gpio_no = gpio_no[i];
+ dev_dbg(&pdev->dev, "%s:GPIO gpio[%s] =\n"
+ "0x%x\n", __func__,
+ pin_data[i].gpio_name,
+ pin_data[i].gpio_no);
+ prim_cnt++;
+ } else {
+ dev_err(&pdev->dev, "%s:Invalid AUXPCM GPIO[%s]= %x\n",
+ __func__,
+ msm_auxpcm_gpio_name[i][GPIO_NAME_INDEX],
+ gpio_no[i]);
+ ret = -ENODEV;
+ goto err;
+ }
+ }
+
+ ctrl = devm_kzalloc(&pdev->dev,
+ sizeof(struct msm_auxpcm_ctrl), GFP_KERNEL);
+ if (!ctrl) {
+ dev_err(&pdev->dev, "No memory for gpio\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ ctrl->pin_data = pin_data;
+ ctrl->cnt = prim_cnt;
+ (*pdata)->pri_auxpcm_ctrl = ctrl;
+ return ret;
+
+err:
+ if (pin_data)
+ devm_kfree(&pdev->dev, pin_data);
+ return ret;
+}
+
static int msm8974_prepare_codec_mclk(struct snd_soc_card *card)
{
struct msm8974_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
@@ -1413,6 +1574,13 @@
goto err;
}
+ ret = msm8974_dtparse_auxpcm(pdev, &pdata);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "%s: Auxpcm pin data parse failed\n", __func__);
+ goto err;
+ }
+
card->dev = &pdev->dev;
platform_set_drvdata(pdev, card);
snd_soc_card_set_drvdata(card, pdata);
@@ -1489,6 +1657,12 @@
spdev = pdev;
ext_spk_amp_regulator = NULL;
+ 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);
@@ -1506,7 +1680,7 @@
gpio_free(pdata->mclk_gpio);
if (ext_spk_amp_gpio >= 0)
gpio_free(ext_spk_amp_gpio);
-
+ iounmap(lpaif_pri_muxsel_virt_addr);
snd_soc_unregister_card(card);
return 0;
diff --git a/sound/soc/msm/qdsp6/q6asm.c b/sound/soc/msm/qdsp6/q6asm.c
index 52e481a..8ec2e94 100644
--- a/sound/soc/msm/qdsp6/q6asm.c
+++ b/sound/soc/msm/qdsp6/q6asm.c
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2010-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
@@ -220,7 +220,7 @@
int rc = 0;
pr_debug("%s: Session id %d\n", __func__, ac->session);
mutex_lock(&ac->cmd_lock);
- if (ac->io_mode == SYNC_IO_MODE) {
+ if (ac->io_mode & SYNC_IO_MODE) {
port = &ac->port[dir];
if (!port->buf) {
mutex_unlock(&ac->cmd_lock);
@@ -351,7 +351,7 @@
if (!ac || !ac->session)
return;
pr_debug("%s: Session id %d\n", __func__, ac->session);
- if (ac->io_mode == SYNC_IO_MODE) {
+ if (ac->io_mode & SYNC_IO_MODE) {
for (loopcnt = 0; loopcnt <= OUT; loopcnt++) {
port = &ac->port[loopcnt];
if (!port->buf)
@@ -386,14 +386,20 @@
pr_err("%s APR handle NULL\n", __func__);
return -EINVAL;
}
- if ((mode == ASYNC_IO_MODE) || (mode == SYNC_IO_MODE)) {
- ac->io_mode = mode;
- pr_debug("%s:Set Mode to %d\n", __func__, ac->io_mode);
- return 0;
+
+ if (mode == ASYNC_IO_MODE) {
+ ac->io_mode &= ~SYNC_IO_MODE;
+ ac->io_mode |= ASYNC_IO_MODE;
+ } else if (mode == SYNC_IO_MODE) {
+ ac->io_mode &= ~ASYNC_IO_MODE;
+ ac->io_mode |= SYNC_IO_MODE;
} else {
pr_err("%s:Not an valid IO Mode:%d\n", __func__, ac->io_mode);
return -EINVAL;
}
+
+ pr_debug("%s:Set Mode to %d\n", __func__, ac->io_mode);
+ return 0;
}
struct audio_client *q6asm_audio_client_alloc(app_cb cb, void *priv)
@@ -498,7 +504,7 @@
if (ac->session <= 0 || ac->session > 8)
goto fail;
- if (ac->io_mode == SYNC_IO_MODE) {
+ if (ac->io_mode & SYNC_IO_MODE) {
if (ac->port[dir].buf) {
pr_debug("%s: buffer already allocated\n", __func__);
return 0;
@@ -906,6 +912,7 @@
case ASM_STREAM_CMD_OPEN_WRITE:
case ASM_STREAM_CMD_OPEN_WRITE_V2_1:
case ASM_STREAM_CMD_OPEN_READWRITE:
+ case ASM_STREAM_CMD_OPEN_LOOPBACK:
case ASM_DATA_CMD_MEDIA_FORMAT_UPDATE:
case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
case ASM_STREAM_CMD_OPEN_WRITE_COMPRESSED:
@@ -942,7 +949,7 @@
pr_debug("%s: Rxed opcode[0x%x] status[0x%x] token[%d]",
__func__, payload[0], payload[1],
data->token);
- if (ac->io_mode == SYNC_IO_MODE) {
+ if (ac->io_mode & SYNC_IO_MODE) {
if (port->buf == NULL) {
pr_err("%s: Unexpected Write Done\n",
__func__);
@@ -1024,7 +1031,7 @@
if (in_enable_flag)
in_cont_index++;
#endif
- if (ac->io_mode == SYNC_IO_MODE) {
+ if (ac->io_mode & SYNC_IO_MODE) {
if (port->buf == NULL) {
pr_err("%s: Unexpected Write Done\n", __func__);
return -EINVAL;
@@ -1203,7 +1210,7 @@
if (!ac || ((dir != IN) && (dir != OUT)))
return NULL;
- if (ac->io_mode == SYNC_IO_MODE) {
+ if (ac->io_mode & SYNC_IO_MODE) {
port = &ac->port[dir];
mutex_lock(&port->lock);
@@ -1297,7 +1304,7 @@
if (!ac || (dir != OUT))
return ret;
- if (ac->io_mode == SYNC_IO_MODE) {
+ if (ac->io_mode & SYNC_IO_MODE) {
port = &ac->port[dir];
mutex_lock(&port->lock);
@@ -1430,6 +1437,9 @@
rc);
goto fail_cmd;
}
+
+ ac->io_mode |= TUN_READ_IO_MODE;
+
return 0;
fail_cmd:
return -EINVAL;
@@ -1716,6 +1726,9 @@
pr_err("%s: format = %x not supported\n", __func__, format);
goto fail_cmd;
}
+
+ ac->io_mode |= TUN_WRITE_IO_MODE;
+
return 0;
fail_cmd:
return -EINVAL;
@@ -1836,6 +1849,45 @@
return -EINVAL;
}
+int q6asm_open_loopack(struct audio_client *ac)
+{
+ int rc = 0x00;
+ struct asm_stream_cmd_open_loopback open;
+
+ if ((ac == NULL) || (ac->apr == NULL)) {
+ pr_err("APR handle NULL\n");
+ return -EINVAL;
+ }
+ pr_debug("%s: session[%d]", __func__, ac->session);
+
+ q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
+ open.hdr.opcode = ASM_STREAM_CMD_OPEN_LOOPBACK;
+
+ open.mode_flags = 0;
+ open.src_endpointype = 0;
+ open.sink_endpointype = 0;
+ /* source endpoint : matrix */
+ open.postprocopo_id = get_asm_topology();
+ if (open.postprocopo_id == 0)
+ open.postprocopo_id = DEFAULT_POPP_TOPOLOGY;
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
+ if (rc < 0) {
+ pr_err("open failed op[0x%x]rc[%d]\n", \
+ open.hdr.opcode, rc);
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+ if (!rc) {
+ pr_err("timeout. waited for OPEN_LOOPBACK rc[%d]\n", rc);
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return -EINVAL;
+}
+
int q6asm_run(struct audio_client *ac, uint32_t flags,
uint32_t msw_ts, uint32_t lsw_ts)
{
@@ -3440,7 +3492,7 @@
pr_err("APR handle NULL\n");
return -EINVAL;
}
- if (ac->io_mode == SYNC_IO_MODE) {
+ if (ac->io_mode & SYNC_IO_MODE) {
port = &ac->port[OUT];
q6asm_add_hdr(ac, &read.hdr, sizeof(read), FALSE);
@@ -3492,7 +3544,7 @@
pr_err("APR handle NULL\n");
return -EINVAL;
}
- if (ac->io_mode == SYNC_IO_MODE) {
+ if (ac->io_mode & SYNC_IO_MODE) {
port = &ac->port[OUT];
q6asm_add_hdr_async(ac, &read.hdr, sizeof(read), FALSE);
@@ -3516,7 +3568,7 @@
read.hdr.token = port->dsp_buf;
port->dsp_buf = (port->dsp_buf + 1) & (port->max_buf_cnt - 1);
- pr_debug("%s:buf add[0x%x] token[%d] uid[%d]\n", __func__,
+ pr_info("%s:buf add[0x%x] token[%d] uid[%d]\n", __func__,
read.buf_add,
read.hdr.token,
read.uid);
@@ -3677,7 +3729,7 @@
return -EINVAL;
}
pr_debug("%s: session[%d] len=%d", __func__, ac->session, len);
- if (ac->io_mode == SYNC_IO_MODE) {
+ if (ac->io_mode & SYNC_IO_MODE) {
port = &ac->port[IN];
q6asm_add_hdr(ac, &write.hdr, sizeof(write),
@@ -3759,7 +3811,7 @@
return -EINVAL;
}
pr_debug("%s: session[%d] len=%d", __func__, ac->session, len);
- if (ac->io_mode == SYNC_IO_MODE) {
+ if (ac->io_mode & SYNC_IO_MODE) {
port = &ac->port[IN];
q6asm_add_hdr_async(ac, &write.hdr, sizeof(write),
@@ -3961,9 +4013,11 @@
{
int cnt = 0;
int loopcnt = 0;
+ int used;
struct audio_port_data *port = NULL;
- if (ac->io_mode == SYNC_IO_MODE) {
+ if (ac->io_mode & SYNC_IO_MODE) {
+ used = (ac->io_mode & TUN_WRITE_IO_MODE ? 1 : 0);
mutex_lock(&ac->cmd_lock);
for (loopcnt = 0; loopcnt <= OUT; loopcnt++) {
port = &ac->port[loopcnt];
@@ -3973,7 +4027,7 @@
while (cnt >= 0) {
if (!port->buf)
continue;
- port->buf[cnt].used = 1;
+ port->buf[cnt].used = used;
cnt--;
}
}
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
index a7a80a6..ab92269 100644
--- a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012-2013, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -33,6 +33,12 @@
STATUS_MAX
};
+enum {
+ RATE_8KHZ,
+ RATE_16KHZ,
+ RATE_MAX_NUM_OF_AUX_PCM_RATES,
+};
+
struct msm_dai_q6_dai_data {
DECLARE_BITMAP(status_mask, STATUS_MAX);
u32 rate;
@@ -92,25 +98,49 @@
return -EINVAL;
}
dai_data->channels = params_channels(params);
-
- if (params_rate(params) != 8000) {
- dev_err(dai->dev, "AUX PCM supports only 8KHz sampling rate\n");
- return -EINVAL;
- }
dai_data->rate = params_rate(params);
- dai_data->port_config.pcm.pcm_cfg_minor_version =
+ switch (dai_data->rate) {
+ case 8000:
+ dai_data->port_config.pcm.pcm_cfg_minor_version =
AFE_API_VERSION_PCM_CONFIG;
- dai_data->port_config.pcm.aux_mode = auxpcm_pdata->mode;
- dai_data->port_config.pcm.sync_src = auxpcm_pdata->sync;
- dai_data->port_config.pcm.frame_setting = auxpcm_pdata->frame;
- dai_data->port_config.pcm.quantype = auxpcm_pdata->quant;
- dai_data->port_config.pcm.ctrl_data_out_enable = auxpcm_pdata->data;
- dai_data->port_config.pcm.sample_rate = dai_data->rate;
- dai_data->port_config.pcm.num_channels = dai_data->channels;
- dai_data->port_config.pcm.bit_width = 16;
- dai_data->port_config.pcm.slot_number_mapping[0] = auxpcm_pdata->slot;
-
+ dai_data->port_config.pcm.aux_mode = auxpcm_pdata->mode_8k.mode;
+ dai_data->port_config.pcm.sync_src = auxpcm_pdata->mode_8k.sync;
+ dai_data->port_config.pcm.frame_setting =
+ auxpcm_pdata->mode_8k.frame;
+ dai_data->port_config.pcm.quantype =
+ auxpcm_pdata->mode_8k.quant;
+ dai_data->port_config.pcm.ctrl_data_out_enable =
+ auxpcm_pdata->mode_8k.data;
+ dai_data->port_config.pcm.sample_rate = dai_data->rate;
+ dai_data->port_config.pcm.num_channels = dai_data->channels;
+ dai_data->port_config.pcm.bit_width = 16;
+ dai_data->port_config.pcm.slot_number_mapping[0] =
+ auxpcm_pdata->mode_8k.slot;
+ break;
+ case 16000:
+ dai_data->port_config.pcm.pcm_cfg_minor_version =
+ AFE_API_VERSION_PCM_CONFIG;
+ dai_data->port_config.pcm.aux_mode =
+ auxpcm_pdata->mode_16k.mode;
+ dai_data->port_config.pcm.sync_src =
+ auxpcm_pdata->mode_16k.sync;
+ dai_data->port_config.pcm.frame_setting =
+ auxpcm_pdata->mode_16k.frame;
+ dai_data->port_config.pcm.quantype =
+ auxpcm_pdata->mode_16k.quant;
+ dai_data->port_config.pcm.ctrl_data_out_enable =
+ auxpcm_pdata->mode_16k.data;
+ dai_data->port_config.pcm.sample_rate = dai_data->rate;
+ dai_data->port_config.pcm.num_channels = dai_data->channels;
+ dai_data->port_config.pcm.bit_width = 16;
+ dai_data->port_config.pcm.slot_number_mapping[0] =
+ auxpcm_pdata->mode_16k.slot;
+ break;
+ default:
+ dev_err(dai->dev, "AUX PCM supports only 8kHz and 16kHz sampling rate\n");
+ return -EINVAL;
+ }
return 0;
}
@@ -166,6 +196,7 @@
struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
struct msm_dai_auxpcm_pdata *auxpcm_pdata = NULL;
int rc = 0;
+ unsigned long pcm_clk_rate;
auxpcm_pdata = dai->dev->platform_data;
@@ -210,27 +241,43 @@
* assert/deasset and afe_open sequence is not followed.
*/
- rc = clk_set_rate(pcm_src_clk, auxpcm_pdata->pcm_clk_rate);
+ if (dai_data->rate == 8000) {
+ pcm_clk_rate = auxpcm_pdata->mode_8k.pcm_clk_rate;
+ } else if (dai_data->rate == 16000) {
+ pcm_clk_rate = (auxpcm_pdata->mode_16k.pcm_clk_rate);
+ } else {
+ dev_err(dai->dev, "%s: Invalid AUX PCM rate %d\n", __func__,
+ dai_data->rate);
+ mutex_unlock(&aux_pcm_mutex);
+ return -EINVAL;
+ }
+
+ rc = clk_set_rate(pcm_src_clk, pcm_clk_rate);
+
if (rc < 0) {
pr_err("%s: clk_set_rate failed\n", __func__);
+ mutex_unlock(&aux_pcm_mutex);
goto fail;
}
rc = clk_prepare_enable(pcm_branch_clk);
if (rc) {
pr_err("%s: clk enable failed\n", __func__);
+ mutex_unlock(&aux_pcm_mutex);
goto fail;
}
rc = clk_set_rate(pcm_oe_src_clk, 24576000>>1);
if (rc < 0) {
pr_err("%s: clk_set_rate on pcm oe failed\n", __func__);
+ mutex_unlock(&aux_pcm_mutex);
goto fail;
}
rc = clk_prepare_enable(pcm_oe_branch_clk);
if (rc) {
pr_err("%s: clk enable pcm_oe_branch_clk failed\n", __func__);
+ mutex_unlock(&aux_pcm_mutex);
goto fail;
}
@@ -1060,7 +1107,7 @@
{
int rc = 0;
struct msm_dai_auxpcm_pdata *auxpcm_pdata = NULL;
- u32 property_val;
+ uint32_t val_array[RATE_MAX_NUM_OF_AUX_PCM_RATES];
auxpcm_pdata = kzalloc(sizeof(struct msm_dai_auxpcm_pdata),
GFP_KERNEL);
@@ -1078,62 +1125,81 @@
__func__);
goto fail_free_plat;
}
- rc = of_property_read_u32(pdev->dev.of_node,
- "qcom,msm-cpudai-auxpcm-mode", &property_val);
+
+ rc = of_property_read_u32_array(pdev->dev.of_node,
+ "qcom,msm-cpudai-auxpcm-mode",
+ val_array, RATE_MAX_NUM_OF_AUX_PCM_RATES);
if (rc) {
dev_err(&pdev->dev, "%s: qcom,msm-cpudai-auxpcm-mode missing in DT node\n",
__func__);
goto fail_free_plat;
}
- auxpcm_pdata->mode = (u16)property_val;
- rc = of_property_read_u32(pdev->dev.of_node,
- "qcom,msm-cpudai-auxpcm-sync", &property_val);
+ auxpcm_pdata->mode_8k.mode = (u16)val_array[RATE_8KHZ];
+ auxpcm_pdata->mode_16k.mode = (u16)val_array[RATE_16KHZ];
+
+ rc = of_property_read_u32_array(pdev->dev.of_node,
+ "qcom,msm-cpudai-auxpcm-sync",
+ val_array, RATE_MAX_NUM_OF_AUX_PCM_RATES);
if (rc) {
dev_err(&pdev->dev, "%s: qcom,msm-cpudai-auxpcm-sync missing in DT node\n",
__func__);
goto fail_free_plat;
}
- auxpcm_pdata->sync = (u16)property_val;
- rc = of_property_read_u32(pdev->dev.of_node,
- "qcom,msm-cpudai-auxpcm-frame", &property_val);
+ auxpcm_pdata->mode_8k.sync = (u16)val_array[RATE_8KHZ];
+ auxpcm_pdata->mode_16k.sync = (u16)val_array[RATE_16KHZ];
+
+ rc = of_property_read_u32_array(pdev->dev.of_node,
+ "qcom,msm-cpudai-auxpcm-frame",
+ val_array, RATE_MAX_NUM_OF_AUX_PCM_RATES);
+
if (rc) {
dev_err(&pdev->dev, "%s: qcom,msm-cpudai-auxpcm-frame missing in DT node\n",
__func__);
goto fail_free_plat;
}
- auxpcm_pdata->frame = (u16)property_val;
- rc = of_property_read_u32(pdev->dev.of_node,
- "qcom,msm-cpudai-auxpcm-quant", &property_val);
+ auxpcm_pdata->mode_8k.frame = (u16)val_array[RATE_8KHZ];
+ auxpcm_pdata->mode_16k.frame = (u16)val_array[RATE_16KHZ];
+
+ rc = of_property_read_u32_array(pdev->dev.of_node,
+ "qcom,msm-cpudai-auxpcm-quant",
+ val_array, RATE_MAX_NUM_OF_AUX_PCM_RATES);
if (rc) {
dev_err(&pdev->dev, "%s: qcom,msm-cpudai-auxpcm-quant missing in DT node\n",
__func__);
goto fail_free_plat;
}
- auxpcm_pdata->quant = (u16)property_val;
- rc = of_property_read_u32(pdev->dev.of_node,
- "qcom,msm-cpudai-auxpcm-slot", &property_val);
+ auxpcm_pdata->mode_8k.quant = (u16)val_array[RATE_8KHZ];
+ auxpcm_pdata->mode_16k.quant = (u16)val_array[RATE_16KHZ];
+
+ rc = of_property_read_u32_array(pdev->dev.of_node,
+ "qcom,msm-cpudai-auxpcm-slot",
+ val_array, RATE_MAX_NUM_OF_AUX_PCM_RATES);
if (rc) {
dev_err(&pdev->dev, "%s: qcom,msm-cpudai-auxpcm-slot missing in DT node\n",
__func__);
goto fail_free_plat;
}
- auxpcm_pdata->slot = (u16)property_val;
- rc = of_property_read_u32(pdev->dev.of_node,
- "qcom,msm-cpudai-auxpcm-data", &property_val);
+ auxpcm_pdata->mode_8k.slot = (u16)val_array[RATE_8KHZ];
+ auxpcm_pdata->mode_16k.slot = (u16)val_array[RATE_16KHZ];
+
+ rc = of_property_read_u32_array(pdev->dev.of_node,
+ "qcom,msm-cpudai-auxpcm-data",
+ val_array, RATE_MAX_NUM_OF_AUX_PCM_RATES);
if (rc) {
dev_err(&pdev->dev, "%s: qcom,msm-cpudai-auxpcm-data missing in DT node\n",
__func__);
goto fail_free_plat;
}
- auxpcm_pdata->data = (u16)property_val;
- rc = of_property_read_u32(pdev->dev.of_node,
+ auxpcm_pdata->mode_8k.data = (u16)val_array[RATE_8KHZ];
+ auxpcm_pdata->mode_16k.data = (u16)val_array[RATE_16KHZ];
+
+ rc = of_property_read_u32_array(pdev->dev.of_node,
"qcom,msm-cpudai-auxpcm-pcm-clk-rate",
- &auxpcm_pdata->pcm_clk_rate);
- if (rc) {
- dev_err(&pdev->dev, "%s: qcom,msm-cpudai-auxpcm-pcm-clk-rate missing in DT node\n",
- __func__);
- goto fail_free_plat;
- }
+ val_array, RATE_MAX_NUM_OF_AUX_PCM_RATES);
+
+ auxpcm_pdata->mode_8k.pcm_clk_rate = (int)val_array[RATE_8KHZ];
+ auxpcm_pdata->mode_16k.pcm_clk_rate = (int)val_array[RATE_16KHZ];
+
platform_set_drvdata(pdev, auxpcm_pdata);
rc = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);