Merge "mmc: card: activate packing control only for eMMC4.5 cards"
diff --git a/Documentation/devicetree/bindings/hwmon/qpnp-adc-current.txt b/Documentation/devicetree/bindings/hwmon/qpnp-adc-current.txt
index 33d5cc1..e458ea0 100644
--- a/Documentation/devicetree/bindings/hwmon/qpnp-adc-current.txt
+++ b/Documentation/devicetree/bindings/hwmon/qpnp-adc-current.txt
@@ -11,6 +11,7 @@
- compatible : should be "qcom,qpnp-iadc" for Current ADC driver.
- reg : offset and length of the PMIC Aribter register map.
- interrupts : The USR bank peripheral IADC interrupt.
+- interrupt-names : Should contain "eoc-int-en-set".
- qcom,adc-bit-resolution : Bit resolution of the ADC.
- qcom,adc-vdd-reference : Voltage reference used by the ADC.
- qcom,rsense : Internal rsense resistor used for current measurements.
@@ -84,6 +85,7 @@
compatible = "qcom,qpnp-iadc";
reg = <0x3200 0x100>;
interrupts = <0 0x36 0>;
+ interrupt-names = "eoc-int-en-set";
qcom,adc-bit-resolution = <16>;
qcom,adc-vdd-reference = <1800>;
qcom,rsense = <1500>;
diff --git a/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt b/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt
index d7d3ec2..e23605c 100644
--- a/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt
+++ b/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt
@@ -11,6 +11,7 @@
- compatible : should be "qcom,qpnp-vadc" for Voltage ADC driver.
- reg : offset and length of the PMIC Aribter register map.
- interrupts : The USR bank peripheral VADC interrupt.
+- interrupt-names : Should contain "eoc-int-en-set".
- qcom,adc-bit-resolution : Bit resolution of the ADC.
- qcom,adc-vdd-reference : Voltage reference used by the ADC.
@@ -82,6 +83,7 @@
compatible = "qcom,qpnp-vadc";
reg = <0x3100 0x100>;
interrupts = <0x0 0x31 0x0>;
+ interrupt-names = "eoc-int-en-set";
qcom,adc-bit-resolution = <15>;
qcom,adc-vdd-reference = <1800>;
diff --git a/Documentation/devicetree/bindings/media/video/msm-camera-flash.txt b/Documentation/devicetree/bindings/media/video/msm-camera-flash.txt
new file mode 100644
index 0000000..72b32be
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/video/msm-camera-flash.txt
@@ -0,0 +1,23 @@
+* Qualcomm MSM CAMERA FLASH
+
+Required properties:
+- cell-index : Should contain flash source index to diffentiate
+ between different flash devices. These indexes represent flash devices
+ for multiple sensors.
+ - 0, 1, 2, 3
+- compatible :
+ - "qcom,camera-led-flash"
+- qcom,flash-type : Should contain type flash device
+ - 1 for LED flash
+ - 2 for strobe flash
+- qcom,flash-source : Should contain array of phandles to flash source nodes.
+ - pm8941_flash0 pm8941_flash1
+
+Example:
+
+qcom,camera-led-flash {
+ cell-index = <0>;
+ compatible = "qcom,camera-led-flash";
+ qcom,flash-type = <1>;
+ qcom,flash-source = <&pm8941_flash0 &pm8941_flash1>;
+};
diff --git a/Documentation/devicetree/bindings/media/video/msm-cci.txt b/Documentation/devicetree/bindings/media/video/msm-cci.txt
index 6b03fab..e256265 100644
--- a/Documentation/devicetree/bindings/media/video/msm-cci.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-cci.txt
@@ -62,9 +62,9 @@
- 1 -> yuv format
Optional properties:
-- qcom,flash-type : should contain flash type if flash is supported for this
- sensor
- - 0 if flash is not supported, 1 if flash is supported
+- qcom,flash-src-index : should contain phandle to flash source node if flash
+ is supported for this sensor
+ - led_flash0, led_flash1
- qcom,mount-angle : should contain the physical mount angle of the sensor on
the target
- 0, 90, 180, 360
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
index 213da90..c47d442 100644
--- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -72,6 +72,11 @@
- compatible : "msm-dai-q6"
+Optional properties:
+
+ - qcom,ext-spk-amp-supply : External speaker amplifier power supply.
+ - qcom,ext-spk-amp-gpio : External speaker amplifier enable signal.
+
[Second Level Nodes]
Required properties:
diff --git a/Documentation/dvb/qcom-mpq.txt b/Documentation/dvb/qcom-mpq.txt
index 28f5d39..1196da0 100644
--- a/Documentation/dvb/qcom-mpq.txt
+++ b/Documentation/dvb/qcom-mpq.txt
@@ -123,17 +123,15 @@
Background Processing
---------------------
-When demux receives notifications from underlying HW drivers about new
-data, it schedules work to a single-threaded workqueue to process the
-notification.
+Demux allocates a kernel thread for each live-input to process
+the TS packets notified from the HW for specific input. There
+are two such inputs (TSIF0 and TSIF1), both can be processed in
+parallel by two seperate threads.
The processing is the action of demuxing of the new data; it may sleep
as it locks against the demux data-structure that may be accessed by
user-space in the meanwhile.
-A single threaded workqueue exists for each live input (TSIF0 or TSIF1)
-to process the inputs in parallel.
-
Dependencies
------------
The demux driver depends on the following kernel drivers and subsystems:
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index 89d4df8..6538db5 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -487,6 +487,7 @@
compatible = "qcom,qpnp-vadc";
reg = <0x3100 0x100>;
interrupts = <0x0 0x31 0x0>;
+ interrupt-names = "eoc-int-en-set";
qcom,adc-bit-resolution = <15>;
qcom,adc-vdd-reference = <1800>;
@@ -698,12 +699,24 @@
qcom,hw-settle-time = <0>;
qcom,fast-avg-setup = <0>;
};
+
+ chan@185 {
+ label = "usb_id";
+ qcom,channel-num = <185>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
};
iadc@3600 {
compatible = "qcom,qpnp-iadc";
reg = <0x3600 0x100>;
interrupts = <0x0 0x36 0x0>;
+ interrupt-names = "eoc-int-en-set";
qcom,adc-bit-resolution = <16>;
qcom,adc-vdd-reference = <1800>;
qcom,rsense = <1500>;
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index b900c3f..ebd0ea3 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -83,6 +83,74 @@
qcom,ipi-ping = <1>;
};
+ qcom,smem@fa00000 {
+ compatible = "qcom,smem";
+ reg = <0xfa00000 0x200000>,
+ <0xfa006000 0x1000>,
+ <0xfc428000 0x4000>;
+ reg-names = "smem", "irq-reg-base", "aux-mem1";
+
+ qcom,smd-modem {
+ compatible = "qcom,smd";
+ qcom,smd-edge = <0>;
+ qcom,smd-irq-offset = <0x8>;
+ qcom,smd-irq-bitmask = <0x1000>;
+ qcom,pil-string = "modem";
+ interrupts = <0 25 1>;
+ }
+
+ qcom,smsm-modem {
+ compatible = "qcom,smsm";
+ qcom,smsm-edge = <0>;
+ qcom,smsm-irq-offset = <0x8>;
+ qcom,smsm-irq-bitmask = <0x2000>;
+ interrupts = <0 26 1>;
+ }
+
+ qcom,smd-adsp {
+ compatible = "qcom,smd";
+ qcom,smd-edge = <1>;
+ qcom,smd-irq-offset = <0x8>;
+ qcom,smd-irq-bitmask = <0x100>;
+ qcom,pil-string = "adsp";
+ interrupts = <0 156 1>;
+ }
+
+ qcom,smsm-adsp {
+ compatible = "qcom,smsm";
+ qcom,smsm-edge = <1>;
+ qcom,smsm-irq-offset = <0x8>;
+ qcom,smsm-irq-bitmask = <0x200>;
+ interrupts = <0 157 1>;
+ }
+
+ qcom,smd-wcnss {
+ compatible = "qcom,smd";
+ qcom,smd-edge = <6>;
+ qcom,smd-irq-offset = <0x8>;
+ qcom,smd-irq-bitmask = <0x20000>;
+ qcom,pil-string = "wcnss";
+ interrupts = <0 142 1>;
+ }
+
+ qcom,smsm-wcnss {
+ compatible = "qcom,smsm";
+ qcom,smsm-edge = <6>;
+ qcom,smsm-irq-offset = <0x8>;
+ qcom,smsm-irq-bitmask = <0x80000>;
+ interrupts = <0 144 1>;
+ }
+
+ qcom,smd-rpm {
+ compatible = "qcom,smd";
+ qcom,smd-edge = <15>;
+ qcom,smd-irq-offset = <0x8>;
+ qcom,smd-irq-bitmask = <0x1>;
+ interrupts = <0 168 1>;
+ qcom,irq-no-suspend;
+ }
+ };
+
};
&gdsc_venus {
diff --git a/arch/arm/boot/dts/msm8910.dtsi b/arch/arm/boot/dts/msm8910.dtsi
index 9514e5a..9b5c9b1 100644
--- a/arch/arm/boot/dts/msm8910.dtsi
+++ b/arch/arm/boot/dts/msm8910.dtsi
@@ -193,6 +193,14 @@
interrupts = <0 168 1>;
qcom,irq-no-suspend;
};
+
+ qcom,wdt@f9017000 {
+ compatible = "qcom,msm-watchdog";
+ reg = <0xf9017000 0x1000>;
+ interrupts = <0 3 0>, <0 4 0>;
+ qcom,bark-time = <11000>;
+ qcom,pet-time = <10000>;
+ qcom,ipi-ping = <1>;
};
};
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi
index 25f79f8..c9b999f 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi
@@ -19,7 +19,7 @@
reg = <0x6e 0x0>;
qcom,csi-if = <1>;
qcom,csid-core = <0>;
- qcom,flash-type = <0>;
+ qcom,flash-src-index = <&led_flash0>;
qcom,mount-angle = <0>;
qcom,sensor-name = "s5k3l1yx";
cam_vdig-supply = <&pm8941_l3>;
@@ -61,7 +61,6 @@
reg = <0x6c 0x0>;
qcom,csi-if = <1>;
qcom,csid-core = <0>;
- qcom,flash-type = <0>;
qcom,mount-angle = <180>;
qcom,sensor-name = "ov2720";
cam_vdig-supply = <&pm8941_l3>;
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor.dtsi
index d804355..68da844 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor.dtsi
@@ -18,7 +18,7 @@
reg = <0x6e 0x0>;
qcom,csi-if = <1>;
qcom,csid-core = <0>;
- qcom,flash-type = <0>;
+ qcom,flash-src-index = <&led_flash0>;
qcom,mount-angle = <90>;
qcom,sensor-name = "s5k3l1yx";
cam_vdig-supply = <&pm8941_l3>;
@@ -60,7 +60,6 @@
reg = <0x6c 0x0>;
qcom,csi-if = <1>;
qcom,csid-core = <0>;
- qcom,flash-type = <0>;
qcom,mount-angle = <180>;
qcom,sensor-name = "ov2720";
cam_vdig-supply = <&pm8941_l3>;
diff --git a/arch/arm/boot/dts/msm8974-camera.dtsi b/arch/arm/boot/dts/msm8974-camera.dtsi
index 4b96811..48dd4dc 100644
--- a/arch/arm/boot/dts/msm8974-camera.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera.dtsi
@@ -165,6 +165,13 @@
vdd-supply = <&gdsc_vfe>;
};
+ led_flash0: qcom,camera-led-flash {
+ cell-index = <0>;
+ compatible = "qcom,camera-led-flash";
+ qcom,flash-type = <1>;
+ qcom,flash-source = <&pm8941_flash0 &pm8941_flash1>;
+ };
+
cci: qcom,cci@fda0C000 {
cell-index = <0>;
compatible = "qcom,cci";
@@ -189,7 +196,6 @@
reg = <0x90 0x0>;
qcom,csi-if = <1>;
qcom,csid-core = <0>;
- qcom,flash-type = <0>;
qcom,mount-angle = <0>;
qcom,sensor-name = "mt9m114";
cam_vdig-supply = <&pm8941_l3>;
diff --git a/arch/arm/boot/dts/msm8974-cdp.dtsi b/arch/arm/boot/dts/msm8974-cdp.dtsi
index 7557fd1..468c283 100644
--- a/arch/arm/boot/dts/msm8974-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8974-cdp.dtsi
@@ -11,8 +11,8 @@
*/
/include/ "dsi-panel-toshiba-720p-video.dtsi"
-/include/ "msm8974-camera-sensor.dtsi"
/include/ "msm8974-leds.dtsi"
+/include/ "msm8974-camera-sensor.dtsi"
/ {
serial@f991e000 {
diff --git a/arch/arm/boot/dts/msm8974-leds.dtsi b/arch/arm/boot/dts/msm8974-leds.dtsi
index 89bb687..8ba3470 100644
--- a/arch/arm/boot/dts/msm8974-leds.dtsi
+++ b/arch/arm/boot/dts/msm8974-leds.dtsi
@@ -45,13 +45,13 @@
status = "disabled";
};
- qcom,leds@d2000 {
+ qcom,leds@d200 {
status = "disabled";
};
qcom,leds@d300 {
status = "okay";
- qcom,flash_0 {
+ pm8941_flash0: qcom,flash_0 {
qcom,max-current = <1000>;
qcom,default-state = "off";
qcom,headroom = <0>;
@@ -67,7 +67,7 @@
qcom,current = <625>;
};
- qcom,flash_1 {
+ pm8941_flash1: qcom,flash_1 {
qcom,max-current = <1000>;
qcom,default-state = "off";
qcom,headroom = <0>;
diff --git a/arch/arm/boot/dts/msm8974-liquid.dtsi b/arch/arm/boot/dts/msm8974-liquid.dtsi
index 0f65dc8..ec723a7 100644
--- a/arch/arm/boot/dts/msm8974-liquid.dtsi
+++ b/arch/arm/boot/dts/msm8974-liquid.dtsi
@@ -10,8 +10,8 @@
* GNU General Public License for more details.
*/
-/include/ "msm8974-camera-sensor-liquid.dtsi"
/include/ "msm8974-leds.dtsi"
+/include/ "msm8974-camera-sensor-liquid.dtsi"
/ {
serial@f991e000 {
diff --git a/arch/arm/boot/dts/msm8974-rumi.dtsi b/arch/arm/boot/dts/msm8974-rumi.dtsi
index 33656cd..4919391 100644
--- a/arch/arm/boot/dts/msm8974-rumi.dtsi
+++ b/arch/arm/boot/dts/msm8974-rumi.dtsi
@@ -10,6 +10,7 @@
* GNU General Public License for more details.
*/
+/include/ "msm8974-leds.dtsi"
/include/ "msm8974-camera-sensor.dtsi"
/ {
@@ -106,4 +107,36 @@
qcom,mss@fc880000 {
status = "disable";
};
+
+ qcom,kgsl-3d0@fdb00000 {
+ status = "disabled";
+ };
+};
+
+&gdsc_venus {
+ status = "disabled";
+};
+
+&gdsc_mdss {
+ status = "disabled";
+};
+
+&gdsc_jpeg {
+ status = "disabled";
+};
+
+&gdsc_vfe {
+ status = "disabled";
+};
+
+&gdsc_oxili_gx {
+ status = "disabled";
+};
+
+&gdsc_oxili_cx {
+ status = "disabled";
+};
+
+&gdsc_usb_hsic {
+ status = "disabled";
};
diff --git a/arch/arm/boot/dts/msm8974-sim.dtsi b/arch/arm/boot/dts/msm8974-sim.dtsi
index 8e8b3c3..fb638f7 100644
--- a/arch/arm/boot/dts/msm8974-sim.dtsi
+++ b/arch/arm/boot/dts/msm8974-sim.dtsi
@@ -11,6 +11,7 @@
*/
/include/ "dsi-panel-sim-video.dtsi"
+/include/ "msm8974-leds.dtsi"
/include/ "msm8974-camera-sensor.dtsi"
/ {
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 19b8828..0fd5c97 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -849,6 +849,16 @@
};
};
+ qcom,msm-dai-mi2s {
+ compatible = "qcom,msm-dai-mi2s";
+ qcom,msm-dai-q6-mi2s-quat {
+ compatible = "qcom,msm-dai-q6-mi2s";
+ qcom,msm-dai-q6-mi2s-dev-id = <3>;
+ qcom,msm-mi2s-rx-lines = <1>;
+ qcom,msm-mi2s-tx-lines = <2>;
+ };
+ };
+
qcom,msm-pcm-hostless {
compatible = "qcom,msm-pcm-hostless";
};
diff --git a/arch/arm/configs/msm8910_defconfig b/arch/arm/configs/msm8910_defconfig
index 2dd4b30..de78559 100644
--- a/arch/arm/configs/msm8910_defconfig
+++ b/arch/arm/configs/msm8910_defconfig
@@ -99,6 +99,9 @@
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_DEBUG_GPIO=y
CONFIG_GPIO_SYSFS=y
# CONFIG_HWMON is not set
@@ -125,6 +128,8 @@
CONFIG_MMC_BLOCK_MINORS=32
CONFIG_MMC_TEST=m
CONFIG_MMC_MSM=y
+CONFIG_SPS=y
+CONFIG_SPS_SUPPORT_NDP_BAM=y
CONFIG_STAGING=y
CONFIG_ANDROID=y
CONFIG_ANDROID_BINDER_IPC=y
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index f468fe0..8f82962 100644
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -47,6 +47,7 @@
CONFIG_MSM_BAM_DMUX=y
CONFIG_MSM_IPC_ROUTER=y
CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
+CONFIG_MSM_IPC_ROUTER_SECURITY=y
CONFIG_MSM_QMI_INTERFACE=y
# CONFIG_MSM_HW3D is not set
CONFIG_MSM_SUBSYSTEM_RESTART=y
@@ -355,6 +356,8 @@
CONFIG_MMC_BLOCK_MINORS=32
# CONFIG_MMC_BLOCK_BOUNCE is not set
CONFIG_MMC_TEST=m
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PLTFM=y
CONFIG_MMC_MSM=y
CONFIG_MMC_MSM_SPS_SUPPORT=y
CONFIG_LEDS_QPNP=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index 973eef9..ade2e66 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -46,6 +46,7 @@
CONFIG_MSM_BAM_DMUX=y
CONFIG_MSM_IPC_ROUTER=y
CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
+CONFIG_MSM_IPC_ROUTER_SECURITY=y
CONFIG_MSM_QMI_INTERFACE=y
# CONFIG_MSM_HW3D is not set
CONFIG_MSM_SUBSYSTEM_RESTART=y
@@ -357,6 +358,8 @@
CONFIG_MMC_BLOCK_MINORS=32
# CONFIG_MMC_BLOCK_BOUNCE is not set
CONFIG_MMC_TEST=m
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PLTFM=y
CONFIG_MMC_MSM=y
CONFIG_MMC_MSM_SPS_SUPPORT=y
CONFIG_LEDS_QPNP=y
diff --git a/arch/arm/configs/msm9625_defconfig b/arch/arm/configs/msm9625_defconfig
index 1a8bbfc..80f16d4 100644
--- a/arch/arm/configs/msm9625_defconfig
+++ b/arch/arm/configs/msm9625_defconfig
@@ -21,6 +21,7 @@
CONFIG_BLK_DEV_INITRD=y
CONFIG_RD_BZIP2=y
CONFIG_RD_LZMA=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
CONFIG_PANIC_TIMEOUT=5
CONFIG_KALLSYMS_ALL=y
CONFIG_EMBEDDED=y
@@ -110,7 +111,7 @@
# CONFIG_NET_VENDOR_SEEQ is not set
# CONFIG_NET_VENDOR_SMSC is not set
# CONFIG_NET_VENDOR_STMICRO is not set
-# CONFIG_WLAN is not set
+CONFIG_ATH6K_LEGACY_EXT=y
# CONFIG_INPUT_MOUSEDEV is not set
CONFIG_INPUT_EVDEV=y
# CONFIG_INPUT_KEYBOARD is not set
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index 2464140..3a52ddc 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/arch/arm/kernel/perf_event.c
@@ -439,12 +439,12 @@
if (plat && plat->request_pmu_irq)
armpmu->request_pmu_irq = plat->request_pmu_irq;
- else
+ else if (!armpmu->request_pmu_irq)
armpmu->request_pmu_irq = armpmu_generic_request_irq;
if (plat && plat->free_pmu_irq)
armpmu->free_pmu_irq = plat->free_pmu_irq;
- else
+ else if (!armpmu->request_pmu_irq)
armpmu->free_pmu_irq = armpmu_generic_free_irq;
irqs = min(pmu_device->num_resources, num_possible_cpus());
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index f3a6fee..90aed03 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -178,6 +178,7 @@
select ARM_HAS_SG_CHAIN
select MSM_KRAIT_WFE_FIXUP
select MSM_ULTRASOUND_A
+ select MSM_IOMMU_GPU_SYNC
select GENERIC_TIME_VSYSCALL
select USE_USER_ACCESSIBLE_TIMERS
select ARM_USE_USER_ACCESSIBLE_TIMERS
@@ -214,6 +215,7 @@
select HOLES_IN_ZONE if SPARSEMEM
select ARM_HAS_SG_CHAIN
select MSM_KRAIT_WFE_FIXUP
+ select MSM_IOMMU_GPU_SYNC
select GENERIC_TIME_VSYSCALL
select USE_USER_ACCESSIBLE_TIMERS
select ARM_USE_USER_ACCESSIBLE_TIMERS
@@ -246,6 +248,7 @@
select ARM_HAS_SG_CHAIN
select MSM_KRAIT_WFE_FIXUP
select MSM_ULTRASOUND_A
+ select MSM_IOMMU_GPU_SYNC
select GENERIC_TIME_VSYSCALL
select USE_USER_ACCESSIBLE_TIMERS
select ARM_USE_USER_ACCESSIBLE_TIMERS
@@ -1535,6 +1538,16 @@
help
SMD Transport Layer for IPC Router
+config MSM_IPC_ROUTER_SECURITY
+ depends on MSM_IPC_ROUTER
+ bool "MSM IPC Router Security support"
+ help
+ This feature of IPC Router will enforce security rules
+ configured by a security script from the user-space. IPC Router
+ once configured with the security rules will ensure that the
+ sender of the message to a service belongs to the relevant
+ Linux group as configured by the security script.
+
config MSM_QMI_INTERFACE
depends on MSM_IPC_ROUTER
depends on QMI_ENCDEC
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 2c7424e..548f40e 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -138,6 +138,7 @@
obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter_device.o
obj-$(CONFIG_MSM_IPC_ROUTER) += ipc_router.o
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_DEBUG_FS) += smd_rpc_sym.o
obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter_servers.o
diff --git a/arch/arm/mach-msm/acpuclock-8064.c b/arch/arm/mach-msm/acpuclock-8064.c
index 5c1d3e1..8174370 100644
--- a/arch/arm/mach-msm/acpuclock-8064.c
+++ b/arch/arm/mach-msm/acpuclock-8064.c
@@ -241,20 +241,127 @@
static struct acpu_level tbl_PVS0_1700MHz[] __initdata = {
{ 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 950000 },
- { 1, { 486000, HFPLL, 2, 0x24 }, L2(6), 975000 },
- { 1, { 594000, HFPLL, 1, 0x16 }, L2(6), 1000000 },
- { 1, { 702000, HFPLL, 1, 0x1A }, L2(6), 1025000 },
- { 1, { 810000, HFPLL, 1, 0x1E }, L2(6), 1075000 },
- { 1, { 918000, HFPLL, 1, 0x22 }, L2(6), 1100000 },
- { 1, { 1026000, HFPLL, 1, 0x26 }, L2(6), 1125000 },
- { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1175000 },
- { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 1200000 },
- { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1225000 },
- { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 1237500 },
- { 1, { 1512000, HFPLL, 1, 0x38 }, L2(15), 1250000 },
- { 1, { 1566000, HFPLL, 1, 0x3A }, L2(15), 1250000 },
- { 1, { 1620000, HFPLL, 1, 0x3C }, L2(15), 1250000 },
- { 1, { 1674000, HFPLL, 1, 0x3E }, L2(15), 1250000 },
+ { 1, { 486000, HFPLL, 2, 0x24 }, L2(6), 950000 },
+ { 1, { 594000, HFPLL, 1, 0x16 }, L2(6), 950000 },
+ { 1, { 702000, HFPLL, 1, 0x1A }, L2(6), 962500 },
+ { 1, { 810000, HFPLL, 1, 0x1E }, L2(6), 1000000 },
+ { 1, { 918000, HFPLL, 1, 0x22 }, L2(6), 1025000 },
+ { 1, { 1026000, HFPLL, 1, 0x26 }, L2(6), 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, { 1566000, HFPLL, 1, 0x3A }, L2(15), 1175000 },
+ { 1, { 1674000, HFPLL, 1, 0x3E }, L2(15), 1225000 },
+ { 1, { 1728000, HFPLL, 1, 0x40 }, L2(15), 1250000 },
+ { 0, { 0 } }
+};
+
+static struct acpu_level tbl_PVS1_1700MHz[] __initdata = {
+ { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 950000 },
+ { 1, { 486000, HFPLL, 2, 0x24 }, L2(6), 950000 },
+ { 1, { 594000, HFPLL, 1, 0x16 }, L2(6), 950000 },
+ { 1, { 702000, HFPLL, 1, 0x1A }, L2(6), 962500 },
+ { 1, { 810000, HFPLL, 1, 0x1E }, L2(6), 975000 },
+ { 1, { 918000, HFPLL, 1, 0x22 }, L2(6), 1000000 },
+ { 1, { 1026000, HFPLL, 1, 0x26 }, L2(6), 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, { 1566000, HFPLL, 1, 0x3A }, L2(15), 1150000 },
+ { 1, { 1674000, HFPLL, 1, 0x3E }, L2(15), 1187500 },
+ { 1, { 1728000, HFPLL, 1, 0x40 }, L2(15), 1200000 },
+ { 0, { 0 } }
+};
+
+static struct acpu_level tbl_PVS2_1700MHz[] __initdata = {
+ { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 925000 },
+ { 1, { 486000, HFPLL, 2, 0x24 }, L2(6), 925000 },
+ { 1, { 594000, HFPLL, 1, 0x16 }, L2(6), 925000 },
+ { 1, { 702000, HFPLL, 1, 0x1A }, L2(6), 925000 },
+ { 1, { 810000, HFPLL, 1, 0x1E }, L2(6), 937500 },
+ { 1, { 918000, HFPLL, 1, 0x22 }, L2(6), 950000 },
+ { 1, { 1026000, HFPLL, 1, 0x26 }, L2(6), 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, { 1566000, HFPLL, 1, 0x3A }, L2(15), 1100000 },
+ { 1, { 1674000, HFPLL, 1, 0x3E }, L2(15), 1137500 },
+ { 1, { 1728000, HFPLL, 1, 0x40 }, L2(15), 1162500 },
+ { 0, { 0 } }
+};
+
+static struct acpu_level tbl_PVS3_1700MHz[] __initdata = {
+ { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 900000 },
+ { 1, { 486000, HFPLL, 2, 0x24 }, L2(6), 900000 },
+ { 1, { 594000, HFPLL, 1, 0x16 }, L2(6), 900000 },
+ { 1, { 702000, HFPLL, 1, 0x1A }, L2(6), 900000 },
+ { 1, { 810000, HFPLL, 1, 0x1E }, L2(6), 900000 },
+ { 1, { 918000, HFPLL, 1, 0x22 }, L2(6), 925000 },
+ { 1, { 1026000, HFPLL, 1, 0x26 }, L2(6), 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, { 1566000, HFPLL, 1, 0x3A }, L2(15), 1062500 },
+ { 1, { 1674000, HFPLL, 1, 0x3E }, L2(15), 1100000 },
+ { 1, { 1728000, HFPLL, 1, 0x40 }, L2(15), 1125000 },
+ { 0, { 0 } }
+};
+
+static struct acpu_level tbl_PVS4_1700MHz[] __initdata = {
+ { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 875000 },
+ { 1, { 486000, HFPLL, 2, 0x24 }, L2(6), 875000 },
+ { 1, { 594000, HFPLL, 1, 0x16 }, L2(6), 875000 },
+ { 1, { 702000, HFPLL, 1, 0x1A }, L2(6), 875000 },
+ { 1, { 810000, HFPLL, 1, 0x1E }, L2(6), 887500 },
+ { 1, { 918000, HFPLL, 1, 0x22 }, L2(6), 900000 },
+ { 1, { 1026000, HFPLL, 1, 0x26 }, L2(6), 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, { 1566000, HFPLL, 1, 0x3A }, L2(15), 1037500 },
+ { 1, { 1674000, HFPLL, 1, 0x3E }, L2(15), 1075000 },
+ { 1, { 1728000, HFPLL, 1, 0x40 }, L2(15), 1100000 },
+ { 0, { 0 } }
+};
+
+static struct acpu_level tbl_PVS5_1700MHz[] __initdata = {
+ { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 875000 },
+ { 1, { 486000, HFPLL, 2, 0x24 }, L2(6), 875000 },
+ { 1, { 594000, HFPLL, 1, 0x16 }, L2(6), 875000 },
+ { 1, { 702000, HFPLL, 1, 0x1A }, L2(6), 875000 },
+ { 1, { 810000, HFPLL, 1, 0x1E }, L2(6), 887500 },
+ { 1, { 918000, HFPLL, 1, 0x22 }, L2(6), 900000 },
+ { 1, { 1026000, HFPLL, 1, 0x26 }, L2(6), 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, { 1566000, HFPLL, 1, 0x3A }, L2(15), 1012500 },
+ { 1, { 1674000, HFPLL, 1, 0x3E }, L2(15), 1050000 },
+ { 1, { 1728000, HFPLL, 1, 0x40 }, L2(15), 1075000 },
+ { 0, { 0 } }
+};
+
+static struct acpu_level tbl_PVS6_1700MHz[] __initdata = {
+ { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 875000 },
+ { 1, { 486000, HFPLL, 2, 0x24 }, L2(6), 875000 },
+ { 1, { 594000, HFPLL, 1, 0x16 }, L2(6), 875000 },
+ { 1, { 702000, HFPLL, 1, 0x1A }, L2(6), 875000 },
+ { 1, { 810000, HFPLL, 1, 0x1E }, L2(6), 887500 },
+ { 1, { 918000, HFPLL, 1, 0x22 }, L2(6), 900000 },
+ { 1, { 1026000, HFPLL, 1, 0x26 }, L2(6), 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, { 1566000, HFPLL, 1, 0x3A }, L2(15), 1000000 },
+ { 1, { 1674000, HFPLL, 1, 0x3E }, L2(15), 1025000 },
+ { 1, { 1728000, HFPLL, 1, 0x40 }, L2(15), 1050000 },
{ 0, { 0 } }
};
@@ -398,12 +505,12 @@
[0][PVS_FASTER] = {tbl_faster, sizeof(tbl_faster), 25000 },
[1][0] = { tbl_PVS0_1700MHz, sizeof(tbl_PVS0_1700MHz), 0 },
- [1][1] = { tbl_PVS0_1700MHz, sizeof(tbl_PVS0_1700MHz), 0 },
- [1][2] = { tbl_PVS0_1700MHz, sizeof(tbl_PVS0_1700MHz), 0 },
- [1][3] = { tbl_PVS0_1700MHz, sizeof(tbl_PVS0_1700MHz), 0 },
- [1][4] = { tbl_PVS0_1700MHz, sizeof(tbl_PVS0_1700MHz), 0 },
- [1][5] = { tbl_PVS0_1700MHz, sizeof(tbl_PVS0_1700MHz), 0 },
- [1][6] = { tbl_PVS0_1700MHz, sizeof(tbl_PVS0_1700MHz), 0 },
+ [1][1] = { tbl_PVS1_1700MHz, sizeof(tbl_PVS1_1700MHz), 0 },
+ [1][2] = { tbl_PVS2_1700MHz, sizeof(tbl_PVS2_1700MHz), 0 },
+ [1][3] = { tbl_PVS3_1700MHz, sizeof(tbl_PVS3_1700MHz), 0 },
+ [1][4] = { tbl_PVS4_1700MHz, sizeof(tbl_PVS4_1700MHz), 0 },
+ [1][5] = { tbl_PVS5_1700MHz, sizeof(tbl_PVS5_1700MHz), 0 },
+ [1][6] = { tbl_PVS6_1700MHz, sizeof(tbl_PVS6_1700MHz), 0 },
[2][0] = { tbl_PVS0_2000MHz, sizeof(tbl_PVS0_2000MHz), 0 },
[2][1] = { tbl_PVS1_2000MHz, sizeof(tbl_PVS1_2000MHz), 0 },
diff --git a/arch/arm/mach-msm/acpuclock-8930.c b/arch/arm/mach-msm/acpuclock-8930.c
index e46599a..948ecdd 100644
--- a/arch/arm/mach-msm/acpuclock-8930.c
+++ b/arch/arm/mach-msm/acpuclock-8930.c
@@ -155,19 +155,19 @@
static struct acpu_level acpu_freq_tbl_slow[] __initdata = {
{ 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 950000 },
- { 1, { 432000, HFPLL, 2, 0x20 }, L2(5), 975000 },
+ { 0, { 432000, HFPLL, 2, 0x20 }, L2(5), 975000 },
{ 1, { 486000, HFPLL, 2, 0x24 }, L2(5), 975000 },
- { 1, { 540000, HFPLL, 2, 0x28 }, L2(5), 1000000 },
+ { 0, { 540000, HFPLL, 2, 0x28 }, L2(5), 1000000 },
{ 1, { 594000, HFPLL, 1, 0x16 }, L2(5), 1000000 },
- { 1, { 648000, HFPLL, 1, 0x18 }, L2(5), 1025000 },
+ { 0, { 648000, HFPLL, 1, 0x18 }, L2(5), 1025000 },
{ 1, { 702000, HFPLL, 1, 0x1A }, L2(5), 1025000 },
- { 1, { 756000, HFPLL, 1, 0x1C }, L2(10), 1075000 },
+ { 0, { 756000, HFPLL, 1, 0x1C }, L2(10), 1075000 },
{ 1, { 810000, HFPLL, 1, 0x1E }, L2(10), 1075000 },
- { 1, { 864000, HFPLL, 1, 0x20 }, L2(10), 1100000 },
+ { 0, { 864000, HFPLL, 1, 0x20 }, L2(10), 1100000 },
{ 1, { 918000, HFPLL, 1, 0x22 }, L2(10), 1100000 },
- { 1, { 972000, HFPLL, 1, 0x24 }, L2(10), 1125000 },
+ { 0, { 972000, HFPLL, 1, 0x24 }, L2(10), 1125000 },
{ 1, { 1026000, HFPLL, 1, 0x26 }, L2(10), 1125000 },
- { 1, { 1080000, HFPLL, 1, 0x28 }, L2(15), 1175000 },
+ { 0, { 1080000, HFPLL, 1, 0x28 }, L2(15), 1175000 },
{ 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1175000 },
{ 1, { 1188000, HFPLL, 1, 0x2C }, L2(15), 1200000 },
{ 0, { 0 } }
@@ -175,19 +175,19 @@
static struct acpu_level acpu_freq_tbl_nom[] __initdata = {
{ 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 925000 },
- { 1, { 432000, HFPLL, 2, 0x20 }, L2(5), 950000 },
+ { 0, { 432000, HFPLL, 2, 0x20 }, L2(5), 950000 },
{ 1, { 486000, HFPLL, 2, 0x24 }, L2(5), 950000 },
- { 1, { 540000, HFPLL, 2, 0x28 }, L2(5), 975000 },
+ { 0, { 540000, HFPLL, 2, 0x28 }, L2(5), 975000 },
{ 1, { 594000, HFPLL, 1, 0x16 }, L2(5), 975000 },
- { 1, { 648000, HFPLL, 1, 0x18 }, L2(5), 1000000 },
+ { 0, { 648000, HFPLL, 1, 0x18 }, L2(5), 1000000 },
{ 1, { 702000, HFPLL, 1, 0x1A }, L2(5), 1000000 },
- { 1, { 756000, HFPLL, 1, 0x1C }, L2(10), 1050000 },
+ { 0, { 756000, HFPLL, 1, 0x1C }, L2(10), 1050000 },
{ 1, { 810000, HFPLL, 1, 0x1E }, L2(10), 1050000 },
- { 1, { 864000, HFPLL, 1, 0x20 }, L2(10), 1075000 },
+ { 0, { 864000, HFPLL, 1, 0x20 }, L2(10), 1075000 },
{ 1, { 918000, HFPLL, 1, 0x22 }, L2(10), 1075000 },
- { 1, { 972000, HFPLL, 1, 0x24 }, L2(10), 1100000 },
+ { 0, { 972000, HFPLL, 1, 0x24 }, L2(10), 1100000 },
{ 1, { 1026000, HFPLL, 1, 0x26 }, L2(10), 1100000 },
- { 1, { 1080000, HFPLL, 1, 0x28 }, L2(15), 1150000 },
+ { 0, { 1080000, HFPLL, 1, 0x28 }, L2(15), 1150000 },
{ 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1150000 },
{ 1, { 1188000, HFPLL, 1, 0x2C }, L2(15), 1175000 },
{ 0, { 0 } }
@@ -195,19 +195,19 @@
static struct acpu_level acpu_freq_tbl_fast[] __initdata = {
{ 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 900000 },
- { 1, { 432000, HFPLL, 2, 0x20 }, L2(5), 900000 },
+ { 0, { 432000, HFPLL, 2, 0x20 }, L2(5), 900000 },
{ 1, { 486000, HFPLL, 2, 0x24 }, L2(5), 900000 },
- { 1, { 540000, HFPLL, 2, 0x28 }, L2(5), 925000 },
+ { 0, { 540000, HFPLL, 2, 0x28 }, L2(5), 925000 },
{ 1, { 594000, HFPLL, 1, 0x16 }, L2(5), 925000 },
- { 1, { 648000, HFPLL, 1, 0x18 }, L2(5), 950000 },
+ { 0, { 648000, HFPLL, 1, 0x18 }, L2(5), 950000 },
{ 1, { 702000, HFPLL, 1, 0x1A }, L2(5), 950000 },
- { 1, { 756000, HFPLL, 1, 0x1C }, L2(10), 1000000 },
+ { 0, { 756000, HFPLL, 1, 0x1C }, L2(10), 1000000 },
{ 1, { 810000, HFPLL, 1, 0x1E }, L2(10), 1000000 },
- { 1, { 864000, HFPLL, 1, 0x20 }, L2(10), 1025000 },
+ { 0, { 864000, HFPLL, 1, 0x20 }, L2(10), 1025000 },
{ 1, { 918000, HFPLL, 1, 0x22 }, L2(10), 1025000 },
- { 1, { 972000, HFPLL, 1, 0x24 }, L2(10), 1050000 },
+ { 0, { 972000, HFPLL, 1, 0x24 }, L2(10), 1050000 },
{ 1, { 1026000, HFPLL, 1, 0x26 }, L2(10), 1050000 },
- { 1, { 1080000, HFPLL, 1, 0x28 }, L2(15), 1100000 },
+ { 0, { 1080000, HFPLL, 1, 0x28 }, L2(15), 1100000 },
{ 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1100000 },
{ 1, { 1188000, HFPLL, 1, 0x2C }, L2(15), 1125000 },
{ 0, { 0 } }
diff --git a/arch/arm/mach-msm/acpuclock-8930aa.c b/arch/arm/mach-msm/acpuclock-8930aa.c
index 9d2b6fc..8d48b54 100644
--- a/arch/arm/mach-msm/acpuclock-8930aa.c
+++ b/arch/arm/mach-msm/acpuclock-8930aa.c
@@ -119,23 +119,23 @@
static struct acpu_level acpu_freq_tbl_slow[] __initdata = {
{ 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 950000 },
- { 1, { 432000, HFPLL, 2, 0x20 }, L2(5), 975000 },
+ { 0, { 432000, HFPLL, 2, 0x20 }, L2(5), 975000 },
{ 1, { 486000, HFPLL, 2, 0x24 }, L2(5), 975000 },
- { 1, { 540000, HFPLL, 2, 0x28 }, L2(5), 1000000 },
+ { 0, { 540000, HFPLL, 2, 0x28 }, L2(5), 1000000 },
{ 1, { 594000, HFPLL, 1, 0x16 }, L2(5), 1000000 },
- { 1, { 648000, HFPLL, 1, 0x18 }, L2(5), 1025000 },
+ { 0, { 648000, HFPLL, 1, 0x18 }, L2(5), 1025000 },
{ 1, { 702000, HFPLL, 1, 0x1A }, L2(5), 1025000 },
- { 1, { 756000, HFPLL, 1, 0x1C }, L2(10), 1075000 },
+ { 0, { 756000, HFPLL, 1, 0x1C }, L2(10), 1075000 },
{ 1, { 810000, HFPLL, 1, 0x1E }, L2(10), 1075000 },
- { 1, { 864000, HFPLL, 1, 0x20 }, L2(10), 1100000 },
+ { 0, { 864000, HFPLL, 1, 0x20 }, L2(10), 1100000 },
{ 1, { 918000, HFPLL, 1, 0x22 }, L2(10), 1100000 },
- { 1, { 972000, HFPLL, 1, 0x24 }, L2(10), 1125000 },
+ { 0, { 972000, HFPLL, 1, 0x24 }, L2(10), 1125000 },
{ 1, { 1026000, HFPLL, 1, 0x26 }, L2(10), 1125000 },
- { 1, { 1080000, HFPLL, 1, 0x28 }, L2(15), 1175000 },
+ { 0, { 1080000, HFPLL, 1, 0x28 }, L2(15), 1175000 },
{ 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1175000 },
- { 1, { 1188000, HFPLL, 1, 0x2C }, L2(15), 1200000 },
+ { 0, { 1188000, HFPLL, 1, 0x2C }, L2(15), 1200000 },
{ 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 1200000 },
- { 1, { 1296000, HFPLL, 1, 0x30 }, L2(15), 1225000 },
+ { 0, { 1296000, HFPLL, 1, 0x30 }, L2(15), 1225000 },
{ 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1225000 },
{ 1, { 1404000, HFPLL, 1, 0x34 }, L2(15), 1237500 },
{ 0, { 0 } }
@@ -143,23 +143,23 @@
static struct acpu_level acpu_freq_tbl_nom[] __initdata = {
{ 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 925000 },
- { 1, { 432000, HFPLL, 2, 0x20 }, L2(5), 950000 },
+ { 0, { 432000, HFPLL, 2, 0x20 }, L2(5), 950000 },
{ 1, { 486000, HFPLL, 2, 0x24 }, L2(5), 950000 },
- { 1, { 540000, HFPLL, 2, 0x28 }, L2(5), 975000 },
+ { 0, { 540000, HFPLL, 2, 0x28 }, L2(5), 975000 },
{ 1, { 594000, HFPLL, 1, 0x16 }, L2(5), 975000 },
- { 1, { 648000, HFPLL, 1, 0x18 }, L2(5), 1000000 },
+ { 0, { 648000, HFPLL, 1, 0x18 }, L2(5), 1000000 },
{ 1, { 702000, HFPLL, 1, 0x1A }, L2(5), 1000000 },
- { 1, { 756000, HFPLL, 1, 0x1C }, L2(10), 1050000 },
+ { 0, { 756000, HFPLL, 1, 0x1C }, L2(10), 1050000 },
{ 1, { 810000, HFPLL, 1, 0x1E }, L2(10), 1050000 },
- { 1, { 864000, HFPLL, 1, 0x20 }, L2(10), 1075000 },
+ { 0, { 864000, HFPLL, 1, 0x20 }, L2(10), 1075000 },
{ 1, { 918000, HFPLL, 1, 0x22 }, L2(10), 1075000 },
- { 1, { 972000, HFPLL, 1, 0x24 }, L2(10), 1100000 },
+ { 0, { 972000, HFPLL, 1, 0x24 }, L2(10), 1100000 },
{ 1, { 1026000, HFPLL, 1, 0x26 }, L2(10), 1100000 },
- { 1, { 1080000, HFPLL, 1, 0x28 }, L2(15), 1150000 },
+ { 0, { 1080000, HFPLL, 1, 0x28 }, L2(15), 1150000 },
{ 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1150000 },
- { 1, { 1188000, HFPLL, 1, 0x2C }, L2(15), 1175000 },
+ { 0, { 1188000, HFPLL, 1, 0x2C }, L2(15), 1175000 },
{ 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 1175000 },
- { 1, { 1296000, HFPLL, 1, 0x30 }, L2(15), 1200000 },
+ { 0, { 1296000, HFPLL, 1, 0x30 }, L2(15), 1200000 },
{ 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1200000 },
{ 1, { 1404000, HFPLL, 1, 0x34 }, L2(15), 1212500 },
{ 0, { 0 } }
@@ -167,23 +167,23 @@
static struct acpu_level acpu_freq_tbl_fast[] __initdata = {
{ 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 900000 },
- { 1, { 432000, HFPLL, 2, 0x20 }, L2(5), 900000 },
+ { 0, { 432000, HFPLL, 2, 0x20 }, L2(5), 900000 },
{ 1, { 486000, HFPLL, 2, 0x24 }, L2(5), 900000 },
- { 1, { 540000, HFPLL, 2, 0x28 }, L2(5), 925000 },
+ { 0, { 540000, HFPLL, 2, 0x28 }, L2(5), 925000 },
{ 1, { 594000, HFPLL, 1, 0x16 }, L2(5), 925000 },
- { 1, { 648000, HFPLL, 1, 0x18 }, L2(5), 950000 },
+ { 0, { 648000, HFPLL, 1, 0x18 }, L2(5), 950000 },
{ 1, { 702000, HFPLL, 1, 0x1A }, L2(5), 950000 },
- { 1, { 756000, HFPLL, 1, 0x1C }, L2(10), 1000000 },
+ { 0, { 756000, HFPLL, 1, 0x1C }, L2(10), 1000000 },
{ 1, { 810000, HFPLL, 1, 0x1E }, L2(10), 1000000 },
- { 1, { 864000, HFPLL, 1, 0x20 }, L2(10), 1025000 },
+ { 0, { 864000, HFPLL, 1, 0x20 }, L2(10), 1025000 },
{ 1, { 918000, HFPLL, 1, 0x22 }, L2(10), 1025000 },
- { 1, { 972000, HFPLL, 1, 0x24 }, L2(10), 1050000 },
+ { 0, { 972000, HFPLL, 1, 0x24 }, L2(10), 1050000 },
{ 1, { 1026000, HFPLL, 1, 0x26 }, L2(10), 1050000 },
- { 1, { 1080000, HFPLL, 1, 0x28 }, L2(15), 1100000 },
+ { 0, { 1080000, HFPLL, 1, 0x28 }, L2(15), 1100000 },
{ 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1100000 },
- { 1, { 1188000, HFPLL, 1, 0x2C }, L2(15), 1125000 },
+ { 0, { 1188000, HFPLL, 1, 0x2C }, L2(15), 1125000 },
{ 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 1125000 },
- { 1, { 1296000, HFPLL, 1, 0x30 }, L2(15), 1150000 },
+ { 0, { 1296000, HFPLL, 1, 0x30 }, L2(15), 1150000 },
{ 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1150000 },
{ 1, { 1404000, HFPLL, 1, 0x34 }, L2(15), 1162500 },
{ 0, { 0 } }
diff --git a/arch/arm/mach-msm/acpuclock-8930ab.c b/arch/arm/mach-msm/acpuclock-8930ab.c
index 764ae41..96029b4 100644
--- a/arch/arm/mach-msm/acpuclock-8930ab.c
+++ b/arch/arm/mach-msm/acpuclock-8930ab.c
@@ -153,29 +153,29 @@
static struct acpu_level acpu_freq_tbl_slow[] __initdata = {
{ 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 950000 },
- { 1, { 432000, HFPLL, 2, 0x20 }, L2(5), 975000 },
+ { 0, { 432000, HFPLL, 2, 0x20 }, L2(5), 975000 },
{ 1, { 486000, HFPLL, 2, 0x24 }, L2(5), 975000 },
- { 1, { 540000, HFPLL, 2, 0x28 }, L2(5), 1000000 },
+ { 0, { 540000, HFPLL, 2, 0x28 }, L2(5), 1000000 },
{ 1, { 594000, HFPLL, 1, 0x16 }, L2(5), 1000000 },
- { 1, { 648000, HFPLL, 1, 0x18 }, L2(5), 1025000 },
+ { 0, { 648000, HFPLL, 1, 0x18 }, L2(5), 1025000 },
{ 1, { 702000, HFPLL, 1, 0x1A }, L2(5), 1025000 },
- { 1, { 756000, HFPLL, 1, 0x1C }, L2(10), 1075000 },
+ { 0, { 756000, HFPLL, 1, 0x1C }, L2(10), 1075000 },
{ 1, { 810000, HFPLL, 1, 0x1E }, L2(10), 1075000 },
- { 1, { 864000, HFPLL, 1, 0x20 }, L2(10), 1100000 },
+ { 0, { 864000, HFPLL, 1, 0x20 }, L2(10), 1100000 },
{ 1, { 918000, HFPLL, 1, 0x22 }, L2(10), 1100000 },
- { 1, { 972000, HFPLL, 1, 0x24 }, L2(10), 1125000 },
+ { 0, { 972000, HFPLL, 1, 0x24 }, L2(10), 1125000 },
{ 1, { 1026000, HFPLL, 1, 0x26 }, L2(10), 1125000 },
- { 1, { 1080000, HFPLL, 1, 0x28 }, L2(15), 1175000 },
+ { 0, { 1080000, HFPLL, 1, 0x28 }, L2(15), 1175000 },
{ 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1175000 },
- { 1, { 1188000, HFPLL, 1, 0x2C }, L2(15), 1200000 },
+ { 0, { 1188000, HFPLL, 1, 0x2C }, L2(15), 1200000 },
{ 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 1200000 },
- { 1, { 1296000, HFPLL, 1, 0x30 }, L2(15), 1225000 },
+ { 0, { 1296000, HFPLL, 1, 0x30 }, L2(15), 1225000 },
{ 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1225000 },
- { 1, { 1404000, HFPLL, 1, 0x34 }, L2(15), 1237500 },
+ { 0, { 1404000, HFPLL, 1, 0x34 }, L2(15), 1237500 },
{ 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 1237500 },
- { 1, { 1512000, HFPLL, 1, 0x38 }, L2(15), 1250000 },
+ { 0, { 1512000, HFPLL, 1, 0x38 }, L2(15), 1250000 },
{ 1, { 1566000, HFPLL, 1, 0x3A }, L2(15), 1250000 },
- { 1, { 1620000, HFPLL, 1, 0x3C }, L2(15), 1262500 },
+ { 0, { 1620000, HFPLL, 1, 0x3C }, L2(15), 1262500 },
{ 1, { 1674000, HFPLL, 1, 0x3E }, L2(15), 1262500 },
{ 1, { 1728000, HFPLL, 1, 0x40 }, L2(15), 1287500 },
{ 0, { 0 } }
@@ -183,29 +183,29 @@
static struct acpu_level acpu_freq_tbl_nom[] __initdata = {
{ 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 950000 },
- { 1, { 432000, HFPLL, 2, 0x20 }, L2(5), 975000 },
+ { 0, { 432000, HFPLL, 2, 0x20 }, L2(5), 975000 },
{ 1, { 486000, HFPLL, 2, 0x24 }, L2(5), 975000 },
- { 1, { 540000, HFPLL, 2, 0x28 }, L2(5), 1000000 },
+ { 0, { 540000, HFPLL, 2, 0x28 }, L2(5), 1000000 },
{ 1, { 594000, HFPLL, 1, 0x16 }, L2(5), 1000000 },
- { 1, { 648000, HFPLL, 1, 0x18 }, L2(5), 1025000 },
+ { 0, { 648000, HFPLL, 1, 0x18 }, L2(5), 1025000 },
{ 1, { 702000, HFPLL, 1, 0x1A }, L2(5), 1025000 },
- { 1, { 756000, HFPLL, 1, 0x1C }, L2(10), 1075000 },
+ { 0, { 756000, HFPLL, 1, 0x1C }, L2(10), 1075000 },
{ 1, { 810000, HFPLL, 1, 0x1E }, L2(10), 1075000 },
- { 1, { 864000, HFPLL, 1, 0x20 }, L2(10), 1100000 },
+ { 0, { 864000, HFPLL, 1, 0x20 }, L2(10), 1100000 },
{ 1, { 918000, HFPLL, 1, 0x22 }, L2(10), 1100000 },
- { 1, { 972000, HFPLL, 1, 0x24 }, L2(10), 1125000 },
+ { 0, { 972000, HFPLL, 1, 0x24 }, L2(10), 1125000 },
{ 1, { 1026000, HFPLL, 1, 0x26 }, L2(10), 1125000 },
- { 1, { 1080000, HFPLL, 1, 0x28 }, L2(15), 1175000 },
+ { 0, { 1080000, HFPLL, 1, 0x28 }, L2(15), 1175000 },
{ 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1175000 },
- { 1, { 1188000, HFPLL, 1, 0x2C }, L2(15), 1200000 },
+ { 0, { 1188000, HFPLL, 1, 0x2C }, L2(15), 1200000 },
{ 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 1200000 },
- { 1, { 1296000, HFPLL, 1, 0x30 }, L2(15), 1225000 },
+ { 0, { 1296000, HFPLL, 1, 0x30 }, L2(15), 1225000 },
{ 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1225000 },
- { 1, { 1404000, HFPLL, 1, 0x34 }, L2(15), 1237500 },
+ { 0, { 1404000, HFPLL, 1, 0x34 }, L2(15), 1237500 },
{ 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 1237500 },
- { 1, { 1512000, HFPLL, 1, 0x38 }, L2(15), 1250000 },
+ { 0, { 1512000, HFPLL, 1, 0x38 }, L2(15), 1250000 },
{ 1, { 1566000, HFPLL, 1, 0x3A }, L2(15), 1250000 },
- { 1, { 1620000, HFPLL, 1, 0x3C }, L2(15), 1262500 },
+ { 0, { 1620000, HFPLL, 1, 0x3C }, L2(15), 1262500 },
{ 1, { 1674000, HFPLL, 1, 0x3E }, L2(15), 1262500 },
{ 1, { 1728000, HFPLL, 1, 0x40 }, L2(15), 1287500 },
{ 0, { 0 } }
@@ -213,29 +213,29 @@
static struct acpu_level acpu_freq_tbl_fast[] __initdata = {
{ 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 950000 },
- { 1, { 432000, HFPLL, 2, 0x20 }, L2(5), 975000 },
+ { 0, { 432000, HFPLL, 2, 0x20 }, L2(5), 975000 },
{ 1, { 486000, HFPLL, 2, 0x24 }, L2(5), 975000 },
- { 1, { 540000, HFPLL, 2, 0x28 }, L2(5), 1000000 },
+ { 0, { 540000, HFPLL, 2, 0x28 }, L2(5), 1000000 },
{ 1, { 594000, HFPLL, 1, 0x16 }, L2(5), 1000000 },
- { 1, { 648000, HFPLL, 1, 0x18 }, L2(5), 1025000 },
+ { 0, { 648000, HFPLL, 1, 0x18 }, L2(5), 1025000 },
{ 1, { 702000, HFPLL, 1, 0x1A }, L2(5), 1025000 },
- { 1, { 756000, HFPLL, 1, 0x1C }, L2(10), 1075000 },
+ { 0, { 756000, HFPLL, 1, 0x1C }, L2(10), 1075000 },
{ 1, { 810000, HFPLL, 1, 0x1E }, L2(10), 1075000 },
- { 1, { 864000, HFPLL, 1, 0x20 }, L2(10), 1100000 },
+ { 0, { 864000, HFPLL, 1, 0x20 }, L2(10), 1100000 },
{ 1, { 918000, HFPLL, 1, 0x22 }, L2(10), 1100000 },
- { 1, { 972000, HFPLL, 1, 0x24 }, L2(10), 1125000 },
+ { 0, { 972000, HFPLL, 1, 0x24 }, L2(10), 1125000 },
{ 1, { 1026000, HFPLL, 1, 0x26 }, L2(10), 1125000 },
- { 1, { 1080000, HFPLL, 1, 0x28 }, L2(15), 1175000 },
+ { 0, { 1080000, HFPLL, 1, 0x28 }, L2(15), 1175000 },
{ 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1175000 },
- { 1, { 1188000, HFPLL, 1, 0x2C }, L2(15), 1200000 },
+ { 0, { 1188000, HFPLL, 1, 0x2C }, L2(15), 1200000 },
{ 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 1200000 },
- { 1, { 1296000, HFPLL, 1, 0x30 }, L2(15), 1225000 },
+ { 0, { 1296000, HFPLL, 1, 0x30 }, L2(15), 1225000 },
{ 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1225000 },
- { 1, { 1404000, HFPLL, 1, 0x34 }, L2(15), 1237500 },
+ { 0, { 1404000, HFPLL, 1, 0x34 }, L2(15), 1237500 },
{ 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 1237500 },
- { 1, { 1512000, HFPLL, 1, 0x38 }, L2(15), 1250000 },
+ { 0, { 1512000, HFPLL, 1, 0x38 }, L2(15), 1250000 },
{ 1, { 1566000, HFPLL, 1, 0x3A }, L2(15), 1250000 },
- { 1, { 1620000, HFPLL, 1, 0x3C }, L2(15), 1262500 },
+ { 0, { 1620000, HFPLL, 1, 0x3C }, L2(15), 1262500 },
{ 1, { 1674000, HFPLL, 1, 0x3E }, L2(15), 1262500 },
{ 1, { 1728000, HFPLL, 1, 0x40 }, L2(15), 1287500 },
{ 0, { 0 } }
diff --git a/arch/arm/mach-msm/board-8064-pmic.c b/arch/arm/mach-msm/board-8064-pmic.c
index fe2d2d2..f6dd2ea 100644
--- a/arch/arm/mach-msm/board-8064-pmic.c
+++ b/arch/arm/mach-msm/board-8064-pmic.c
@@ -405,7 +405,7 @@
.resume_charge_percent = 99,
.term_current = CHG_TERM_MA,
.cool_temp = 10,
- .warm_temp = 40,
+ .warm_temp = 45,
.temp_check_period = 1,
.max_bat_chg_current = 1100,
.cool_bat_chg_current = 350,
@@ -433,6 +433,8 @@
.shutdown_soc_valid_limit = 20,
.adjust_soc_low_threshold = 25,
.chg_term_ua = CHG_TERM_MA * 1000,
+ .normal_voltage_calc_ms = 20000,
+ .low_voltage_calc_ms = 1000,
};
static struct pm8921_platform_data
diff --git a/arch/arm/mach-msm/board-8910.c b/arch/arm/mach-msm/board-8910.c
index 42fe1ea..b4a95ee 100644
--- a/arch/arm/mach-msm/board-8910.c
+++ b/arch/arm/mach-msm/board-8910.c
@@ -69,6 +69,7 @@
CLK_DUMMY("iface_clk", NULL, "msm_sdcc.2", OFF),
CLK_DUMMY("core_clk", NULL, "msm_sdcc.2", OFF),
CLK_DUMMY("bus_clk", NULL, "msm_sdcc.2", OFF),
+ CLK_DUMMY("dfab_clk", DFAB_CLK, "msm_sps", OFF),
};
static struct clock_init_data msm_dummy_clock_init_data __initdata = {
diff --git a/arch/arm/mach-msm/board-8930-pmic.c b/arch/arm/mach-msm/board-8930-pmic.c
index 618f83b..a5fded4 100644
--- a/arch/arm/mach-msm/board-8930-pmic.c
+++ b/arch/arm/mach-msm/board-8930-pmic.c
@@ -325,7 +325,7 @@
.resume_charge_percent = 99,
.term_current = CHG_TERM_MA,
.cool_temp = 10,
- .warm_temp = 40,
+ .warm_temp = 45,
.temp_check_period = 1,
.max_bat_chg_current = 1100,
.cool_bat_chg_current = 350,
@@ -472,6 +472,8 @@
.adjust_soc_low_threshold = 25,
.chg_term_ua = CHG_TERM_MA * 1000,
.rconn_mohm = 18,
+ .normal_voltage_calc_ms = 20000,
+ .low_voltage_calc_ms = 1000,
};
static struct pm8038_platform_data pm8038_platform_data __devinitdata = {
diff --git a/arch/arm/mach-msm/board-8960-pmic.c b/arch/arm/mach-msm/board-8960-pmic.c
index 2071a55..f0ba1c9 100644
--- a/arch/arm/mach-msm/board-8960-pmic.c
+++ b/arch/arm/mach-msm/board-8960-pmic.c
@@ -406,7 +406,7 @@
.resume_charge_percent = 99,
.term_current = CHG_TERM_MA,
.cool_temp = 10,
- .warm_temp = 40,
+ .warm_temp = 45,
.temp_check_period = 1,
.max_bat_chg_current = 1100,
.cool_bat_chg_current = 350,
@@ -431,6 +431,8 @@
.shutdown_soc_valid_limit = 20,
.adjust_soc_low_threshold = 25,
.chg_term_ua = CHG_TERM_MA * 1000,
+ .normal_voltage_calc_ms = 20000,
+ .low_voltage_calc_ms = 1000,
};
#define PM8921_LC_LED_MAX_CURRENT 4 /* I = 4mA */
@@ -613,6 +615,6 @@
pm8921_bms_pdata.rconn_mohm = 20;
if (!machine_is_msm8960_fluid() && !machine_is_msm8960_liquid()
- && !machine_is_msm8960_fluid())
+ && !machine_is_msm8960_mtp())
pm8921_chg_pdata.battery_less_hardware = 1;
}
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index c9ebb24..b9b3a1f 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -1676,7 +1676,7 @@
.reg_base_addr = MSM_SAW0_BASE,
.reg_init_values[MSM_SPM_REG_SAW2_CFG] = 0x1F,
#if defined(CONFIG_MSM_AVS_HW)
- .reg_init_values[MSM_SPM_REG_SAW2_AVS_CTL] = 0x50589464,
+ .reg_init_values[MSM_SPM_REG_SAW2_AVS_CTL] = 0x58589464,
.reg_init_values[MSM_SPM_REG_SAW2_AVS_HYSTERESIS] = 0x00020000,
#endif
.reg_init_values[MSM_SPM_REG_SAW2_SPM_CTL] = 0x01,
@@ -1691,7 +1691,7 @@
.reg_base_addr = MSM_SAW1_BASE,
.reg_init_values[MSM_SPM_REG_SAW2_CFG] = 0x1F,
#if defined(CONFIG_MSM_AVS_HW)
- .reg_init_values[MSM_SPM_REG_SAW2_AVS_CTL] = 0x50589464,
+ .reg_init_values[MSM_SPM_REG_SAW2_AVS_CTL] = 0x58589464,
.reg_init_values[MSM_SPM_REG_SAW2_AVS_HYSTERESIS] = 0x00020000,
#endif
.reg_init_values[MSM_SPM_REG_SAW2_SPM_CTL] = 0x01,
diff --git a/arch/arm/mach-msm/board-8974-gpiomux.c b/arch/arm/mach-msm/board-8974-gpiomux.c
index 89ad4ef..ad74182 100644
--- a/arch/arm/mach-msm/board-8974-gpiomux.c
+++ b/arch/arm/mach-msm/board-8974-gpiomux.c
@@ -16,6 +16,7 @@
#include <mach/board.h>
#include <mach/gpio.h>
#include <mach/gpiomux.h>
+#include <mach/socinfo.h>
#define KS8851_IRQ_GPIO 94
@@ -249,6 +250,21 @@
},
};
+static struct msm_gpiomux_config msm_rumi_blsp_configs[] __initdata = {
+ {
+ .gpio = 45, /* BLSP2 UART8 TX */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_uart_config,
+ },
+ },
+ {
+ .gpio = 46, /* BLSP2 UART8 RX */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_uart_config,
+ },
+ },
+};
+
static struct msm_gpiomux_config msm_blsp_configs[] __initdata = {
#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
{
@@ -624,4 +640,8 @@
msm_gpiomux_install(msm_hdmi_configs, ARRAY_SIZE(msm_hdmi_configs));
msm_gpiomux_install(msm_mhl_configs, ARRAY_SIZE(msm_mhl_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 c47b688..ca8f68a 100644
--- a/arch/arm/mach-msm/board-8974.c
+++ b/arch/arm/mach-msm/board-8974.c
@@ -304,8 +304,6 @@
"usb_bam", NULL),
OF_DEV_AUXDATA("qcom,spi-qup-v2", 0xF9924000, \
"spi_qsd.1", NULL),
- OF_DEV_AUXDATA("qcom,spmi-pmic-arb", 0xFC4C0000, \
- "spmi-pmic-arb.0", NULL),
OF_DEV_AUXDATA("qcom,msm-sdcc", 0xF9824000, \
"msm_sdcc.1", NULL),
OF_DEV_AUXDATA("qcom,msm-sdcc", 0xF98A4000, \
diff --git a/arch/arm/mach-msm/board-9615.c b/arch/arm/mach-msm/board-9615.c
index 39060ad..1022616 100644
--- a/arch/arm/mach-msm/board-9615.c
+++ b/arch/arm/mach-msm/board-9615.c
@@ -621,7 +621,7 @@
#define USB_BAM_PHY_BASE 0x12502000
#define HSIC_BAM_PHY_BASE 0x12542000
#define A2_BAM_PHY_BASE 0x124C2000
-static struct usb_bam_pipe_connect msm_usb_bam_connections[MAX_BAMS][4][2] = {
+static struct usb_bam_pipe_connect msm_usb_bam_connections[MAX_BAMS][8][2] = {
[HSUSB_BAM][0][USB_TO_PEER_PERIPHERAL] = {
.src_phy_addr = USB_BAM_PHY_BASE,
.src_pipe_index = 11,
diff --git a/arch/arm/mach-msm/board-msm7627a-io.c b/arch/arm/mach-msm/board-msm7627a-io.c
index 2983dc0..8c52456 100644
--- a/arch/arm/mach-msm/board-msm7627a-io.c
+++ b/arch/arm/mach-msm/board-msm7627a-io.c
@@ -727,6 +727,15 @@
[KP_INDEX_SKU3(1, 1)] = KEY_CAMERA,
};
+static unsigned int kp_row_gpios_skud[] = {31, 32};
+static unsigned int kp_col_gpios_skud[] = {37};
+
+static const unsigned short keymap_skud[] = {
+ [KP_INDEX_SKU3(0, 0)] = KEY_VOLUMEUP,
+ [KP_INDEX_SKU3(0, 1)] = KEY_VOLUMEDOWN,
+};
+
+
static struct gpio_event_matrix_info kp_matrix_info_sku3 = {
.info.func = gpio_event_matrix_func,
.keymap = keymap_sku3,
@@ -887,13 +896,23 @@
#endif
/* keypad */
+
+ if (machine_is_qrd_skud_prime()) {
+ kp_matrix_info_sku3.keymap = keymap_skud;
+ kp_matrix_info_sku3.output_gpios = kp_row_gpios_skud;
+ kp_matrix_info_sku3.input_gpios = kp_col_gpios_skud;
+ kp_matrix_info_sku3.noutputs = ARRAY_SIZE(kp_row_gpios_skud);
+ kp_matrix_info_sku3.ninputs = ARRAY_SIZE(kp_col_gpios_skud);
+ }
+
if (machine_is_msm8625_evt())
kp_matrix_info_8625.keymap = keymap_8625_evt;
if (machine_is_msm7627a_evb() || machine_is_msm8625_evb() ||
machine_is_msm8625_evt())
platform_device_register(&kp_pdev_8625);
- else if (machine_is_msm7627a_qrd3() || machine_is_msm8625_qrd7())
+ else if (machine_is_msm7627a_qrd3() || machine_is_msm8625_qrd7()
+ || machine_is_qrd_skud_prime())
platform_device_register(&kp_pdev_sku3);
/* leds */
diff --git a/arch/arm/mach-msm/board-qrd7627a.c b/arch/arm/mach-msm/board-qrd7627a.c
index 023ce86..a25290f 100644
--- a/arch/arm/mach-msm/board-qrd7627a.c
+++ b/arch/arm/mach-msm/board-qrd7627a.c
@@ -46,6 +46,7 @@
#include <mach/usbdiag.h>
#include <mach/msm_memtypes.h>
#include <mach/msm_serial_hs.h>
+#include <mach/msm_serial_pdata.h>
#include <mach/pmic.h>
#include <mach/socinfo.h>
#include <mach/vreg.h>
@@ -82,6 +83,10 @@
.id = -1,
};
+static struct msm_serial_platform_data msm_8625_uart1_pdata = {
+ .userid = 10,
+};
+
static struct msm_gpio qup_i2c_gpios_io[] = {
{ GPIO_CFG(60, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA),
"qup_scl" },
@@ -994,6 +999,7 @@
if (machine_is_msm8625_evb() || machine_is_msm8625_qrd7()
|| machine_is_msm8625_evt()
|| machine_is_qrd_skud_prime()) {
+ msm8625_device_uart1.dev.platform_data = &msm_8625_uart1_pdata;
platform_add_devices(msm8625_evb_devices,
ARRAY_SIZE(msm8625_evb_devices));
platform_add_devices(qrd3_devices,
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index a4d7e61..c394982 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -6319,12 +6319,12 @@
*/
/*
* Initialize MM AHB registers: Enable the FPB clock and disable HW
- * gating on 8627, 8960 and 8930ab for all clocks. Also set VFE_AHB's
+ * gating on 8627 and 8930ab for all clocks. Also set VFE_AHB's
* FORCE_CORE_ON bit to prevent its memory from being collapsed when
* the clock is halted. The sleep and wake-up delays are set to safe
* values.
*/
- if (cpu_is_msm8627() || cpu_is_msm8960ab() || cpu_is_msm8930ab()) {
+ if (cpu_is_msm8627() || cpu_is_msm8930ab()) {
rmwreg(0x00000003, AHB_EN_REG, 0x6C000103);
writel_relaxed(0x000007F9, AHB_EN2_REG);
} else {
@@ -6342,7 +6342,7 @@
/* Initialize MM AXI registers: Enable HW gating for all clocks that
* support it. Also set FORCE_CORE_ON bits, and any sleep and wake-up
* delays to safe values. */
- if (cpu_is_msm8960ab() || (cpu_is_msm8960() &&
+ if ((cpu_is_msm8960() &&
SOCINFO_VERSION_MAJOR(socinfo_get_version()) < 3) ||
cpu_is_msm8627() || cpu_is_msm8930ab()) {
rmwreg(0x000007F9, MAXI_EN_REG, 0x0803FFFF);
@@ -6365,8 +6365,6 @@
if (cpu_is_msm8627() || cpu_is_msm8930ab())
rmwreg(0x000003C7, SAXI_EN_REG, 0x00003FFF);
- else if (cpu_is_msm8960ab())
- rmwreg(0x000001C6, SAXI_EN_REG, 0x00001DF6);
else
rmwreg(0x00003C38, SAXI_EN_REG, 0x00003FFF);
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index c0a553f..216de11 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -522,6 +522,14 @@
#define dsipll0_pixel_mm_source_val 1
#define hdmipll_mm_source_val 3
+#define F_GCC_GND \
+ { \
+ .freq_hz = 0, \
+ .m_val = 0, \
+ .n_val = 0, \
+ .div_src_val = BVAL(4, 0, 1) | BVAL(10, 8, gnd_source_val), \
+ }
+
#define F(f, s, div, m, n) \
{ \
.freq_hz = (f), \
@@ -914,6 +922,7 @@
};
static struct clk_freq_tbl ftbl_gcc_blsp1_2_uart1_6_apps_clk[] = {
+ F_GCC_GND,
F( 3686400, gpll0, 1, 96, 15625),
F( 7372800, gpll0, 1, 192, 15625),
F(14745600, gpll0, 1, 384, 15625),
@@ -5120,6 +5129,7 @@
CLK_LOOKUP("core_clk", gcc_usb30_master_clk.c, "msm_dwc3"),
CLK_LOOKUP("utmi_clk", gcc_usb30_mock_utmi_clk.c, "msm_dwc3"),
CLK_LOOKUP("iface_clk", gcc_sys_noc_usb3_axi_clk.c, "msm_dwc3"),
+ CLK_LOOKUP("iface_clk", gcc_sys_noc_usb3_axi_clk.c, "msm_usb3"),
CLK_LOOKUP("sleep_clk", gcc_usb30_sleep_clk.c, "msm_dwc3"),
CLK_LOOKUP("sleep_a_clk", gcc_usb2a_phy_sleep_clk.c, "msm_dwc3"),
CLK_LOOKUP("sleep_b_clk", gcc_usb2b_phy_sleep_clk.c, "msm_dwc3"),
@@ -5345,10 +5355,14 @@
CLK_LOOKUP("osr_clk", audio_core_lpaif_ter_osr_clk.c, ""),
CLK_LOOKUP("ebit_clk", audio_core_lpaif_ter_ebit_clk.c, ""),
CLK_LOOKUP("ibit_clk", audio_core_lpaif_ter_ibit_clk.c, ""),
- CLK_LOOKUP("core_clk", audio_core_lpaif_quad_clk_src.c, ""),
- CLK_LOOKUP("osr_clk", audio_core_lpaif_quad_osr_clk.c, ""),
- CLK_LOOKUP("ebit_clk", audio_core_lpaif_quad_ebit_clk.c, ""),
- CLK_LOOKUP("ibit_clk", audio_core_lpaif_quad_ibit_clk.c, ""),
+ CLK_LOOKUP("core_clk", audio_core_lpaif_quad_clk_src.c,
+ "msm-dai-q6-mi2s.3"),
+ CLK_LOOKUP("osr_clk", audio_core_lpaif_quad_osr_clk.c,
+ "msm-dai-q6-mi2s.3"),
+ CLK_LOOKUP("ebit_clk", audio_core_lpaif_quad_ebit_clk.c,
+ "msm-dai-q6-mi2s.3"),
+ CLK_LOOKUP("ibit_clk", audio_core_lpaif_quad_ibit_clk.c,
+ "msm-dai-q6-mi2s.3"),
CLK_LOOKUP("pcm_clk", audio_core_lpaif_pcm0_clk_src.c,
"msm-dai-q6.4106"),
CLK_LOOKUP("ebit_clk", audio_core_lpaif_pcm0_ebit_clk.c, ""),
diff --git a/arch/arm/mach-msm/clock-9625.c b/arch/arm/mach-msm/clock-9625.c
index b284168..d3a4bba 100644
--- a/arch/arm/mach-msm/clock-9625.c
+++ b/arch/arm/mach-msm/clock-9625.c
@@ -246,6 +246,14 @@
#define lpapll0_lpass_source_val 1
#define gpll0_lpass_source_val 5
+#define F_GCC_GND \
+ { \
+ .freq_hz = 0, \
+ .m_val = 0, \
+ .n_val = 0, \
+ .div_src_val = BVAL(4, 0, 1) | BVAL(10, 8, gnd_source_val), \
+ }
+
#define F(f, s, div, m, n) \
{ \
.freq_hz = (f), \
@@ -611,6 +619,7 @@
};
static struct clk_freq_tbl ftbl_gcc_blsp1_uart1_6_apps_clk[] = {
+ F_GCC_GND,
F( 3686400, gpll0, 1, 96, 15625),
F( 7372800, gpll0, 1, 192, 15625),
F(14745600, gpll0, 1, 384, 15625),
diff --git a/arch/arm/mach-msm/devices-8930.c b/arch/arm/mach-msm/devices-8930.c
index 0faf500..aad512e 100644
--- a/arch/arm/mach-msm/devices-8930.c
+++ b/arch/arm/mach-msm/devices-8930.c
@@ -143,12 +143,12 @@
MSM_RPM_MAP(8930, PM8038_CLK2_0, PM8038_CLK2, 2),
MSM_RPM_MAP(8930, PM8038_LVS1, PM8038_LVS1, 1),
MSM_RPM_MAP(8930, PM8038_LVS2, PM8038_LVS2, 1),
- MSM_RPM_MAP(8930, NCP_0, NCP, 2),
- MSM_RPM_MAP(8930, CXO_BUFFERS, CXO_BUFFERS, 1),
- MSM_RPM_MAP(8930, USB_OTG_SWITCH, USB_OTG_SWITCH, 1),
- MSM_RPM_MAP(8930, HDMI_SWITCH, HDMI_SWITCH, 1),
- MSM_RPM_MAP(8930, QDSS_CLK, QDSS_CLK, 1),
- MSM_RPM_MAP(8930, VOLTAGE_CORNER, VOLTAGE_CORNER, 1),
+ MSM_RPM_MAP_PMIC(8930, 8038, NCP_0, NCP, 2),
+ MSM_RPM_MAP_PMIC(8930, 8038, CXO_BUFFERS, CXO_BUFFERS, 1),
+ MSM_RPM_MAP_PMIC(8930, 8038, USB_OTG_SWITCH, USB_OTG_SWITCH, 1),
+ MSM_RPM_MAP_PMIC(8930, 8038, HDMI_SWITCH, HDMI_SWITCH, 1),
+ MSM_RPM_MAP_PMIC(8930, 8038, QDSS_CLK, QDSS_CLK, 1),
+ MSM_RPM_MAP_PMIC(8930, 8038, VOLTAGE_CORNER, VOLTAGE_CORNER, 1),
},
.target_status = {
MSM_RPM_STATUS_ID_MAP(8930, VERSION_MAJOR),
@@ -369,12 +369,12 @@
MSM_RPM_MAP(8930, PM8917_LVS5, PM8917_LVS5, 1),
MSM_RPM_MAP(8930, PM8917_LVS6, PM8917_LVS6, 1),
MSM_RPM_MAP(8930, PM8917_LVS7, PM8917_LVS7, 1),
- MSM_RPM_MAP(8930, NCP_0, NCP, 2),
- MSM_RPM_MAP(8930, CXO_BUFFERS, CXO_BUFFERS, 1),
- MSM_RPM_MAP(8930, USB_OTG_SWITCH, USB_OTG_SWITCH, 1),
- MSM_RPM_MAP(8930, HDMI_SWITCH, HDMI_SWITCH, 1),
- MSM_RPM_MAP(8930, QDSS_CLK, QDSS_CLK, 1),
- MSM_RPM_MAP(8930, VOLTAGE_CORNER, VOLTAGE_CORNER, 1),
+ MSM_RPM_MAP_PMIC(8930, 8917, NCP_0, NCP, 2),
+ MSM_RPM_MAP_PMIC(8930, 8917, CXO_BUFFERS, CXO_BUFFERS, 1),
+ MSM_RPM_MAP_PMIC(8930, 8917, USB_OTG_SWITCH, USB_OTG_SWITCH, 1),
+ MSM_RPM_MAP_PMIC(8930, 8917, HDMI_SWITCH, HDMI_SWITCH, 1),
+ MSM_RPM_MAP_PMIC(8930, 8917, QDSS_CLK, QDSS_CLK, 1),
+ MSM_RPM_MAP_PMIC(8930, 8917, VOLTAGE_CORNER, VOLTAGE_CORNER, 1),
},
.target_status = {
MSM_RPM_STATUS_ID_MAP(8930, VERSION_MAJOR),
diff --git a/arch/arm/mach-msm/devices-msm7x27a.c b/arch/arm/mach-msm/devices-msm7x27a.c
index b4ef76d2..8fc5020 100644
--- a/arch/arm/mach-msm/devices-msm7x27a.c
+++ b/arch/arm/mach-msm/devices-msm7x27a.c
@@ -501,6 +501,18 @@
.exit_sleep3 = msm_gic_irq_exit_sleep3,
};
+void msm_clk_dump_debug_info(void)
+{
+ pr_info("%s: GLBL_CLK_ENA: 0x%08X\n", __func__,
+ readl_relaxed(MSM_CLK_CTL_BASE + 0x0));
+ pr_info("%s: GLBL_CLK_STATE: 0x%08X\n", __func__,
+ readl_relaxed(MSM_CLK_CTL_BASE + 0x4));
+ pr_info("%s: GRP_NS_REG: 0x%08X\n", __func__,
+ readl_relaxed(MSM_CLK_CTL_BASE + 0x84));
+ pr_info("%s: CLK_HALT_STATEB: 0x%08X\n", __func__,
+ readl_relaxed(MSM_CLK_CTL_BASE + 0x10C));
+}
+
void __init msm_pm_register_irqs(void)
{
if (cpu_is_msm8625())
@@ -2135,6 +2147,7 @@
static int msm7627a_panic_handler(struct notifier_block *this,
unsigned long event, void *ptr)
{
+ msm_clk_dump_debug_info();
flush_cache_all();
outer_flush_all();
return NOTIFY_DONE;
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index cbe2040..8b5c70f 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -599,6 +599,13 @@
void msm_map_msm8910_io(void);
void msm8910_init_irq(void);
+/* Dump debug info (states, rate, etc) of clocks */
+#if defined(CONFIG_ARCH_MSM7X27)
+void msm_clk_dump_debug_info(void);
+#else
+static inline void msm_clk_dump_debug_info(void) {}
+#endif
+
struct mmc_platform_data;
int msm_add_sdcc(unsigned int controller,
struct mmc_platform_data *plat);
diff --git a/arch/arm/mach-msm/include/mach/iommu.h b/arch/arm/mach-msm/include/mach/iommu.h
index 57b4bd3..ea3fb64 100644
--- a/arch/arm/mach-msm/include/mach/iommu.h
+++ b/arch/arm/mach-msm/include/mach/iommu.h
@@ -147,6 +147,59 @@
irqreturn_t msm_iommu_fault_handler(int irq, void *dev_id);
irqreturn_t msm_iommu_fault_handler_v2(int irq, void *dev_id);
+enum {
+ PROC_APPS,
+ PROC_GPU,
+ PROC_MAX
+};
+
+/* Expose structure to allow kgsl iommu driver to use the same structure to
+ * communicate to GPU the addresses of the flag and turn variables.
+ */
+struct remote_iommu_petersons_spinlock {
+ uint32_t flag[PROC_MAX];
+ uint32_t turn;
+};
+
+#ifdef CONFIG_MSM_IOMMU
+void *msm_iommu_lock_initialize(void);
+void msm_iommu_mutex_lock(void);
+void msm_iommu_mutex_unlock(void);
+#else
+static inline void *msm_iommu_lock_initialize(void)
+{
+ return NULL;
+}
+static inline void msm_iommu_mutex_lock(void) { }
+static inline void msm_iommu_mutex_unlock(void) { }
+#endif
+
+#ifdef CONFIG_MSM_IOMMU_GPU_SYNC
+void msm_iommu_remote_p0_spin_lock(void);
+void msm_iommu_remote_p0_spin_unlock(void);
+
+#define msm_iommu_remote_lock_init() _msm_iommu_remote_spin_lock_init()
+#define msm_iommu_remote_spin_lock() msm_iommu_remote_p0_spin_lock()
+#define msm_iommu_remote_spin_unlock() msm_iommu_remote_p0_spin_unlock()
+#else
+#define msm_iommu_remote_lock_init()
+#define msm_iommu_remote_spin_lock()
+#define msm_iommu_remote_spin_unlock()
+#endif
+
+/* Allows kgsl iommu driver to acquire lock */
+#define msm_iommu_lock() \
+ do { \
+ msm_iommu_mutex_lock(); \
+ msm_iommu_remote_spin_lock(); \
+ } while (0)
+
+#define msm_iommu_unlock() \
+ do { \
+ msm_iommu_remote_spin_unlock(); \
+ msm_iommu_mutex_unlock(); \
+ } while (0)
+
#ifdef CONFIG_MSM_IOMMU
/*
* Look up an IOMMU context device by its context name. NULL if none found.
diff --git a/arch/arm/mach-msm/include/mach/irqs-8092.h b/arch/arm/mach-msm/include/mach/irqs-8092.h
index ae9634e..dfe21c2 100644
--- a/arch/arm/mach-msm/include/mach/irqs-8092.h
+++ b/arch/arm/mach-msm/include/mach/irqs-8092.h
@@ -34,12 +34,5 @@
#define TLMM_MSM_SUMMARY_IRQ (GIC_SPI_START + 208)
#define SPS_BAM_DMA_IRQ (GIC_SPI_START + 105)
-#define NR_MSM_IRQS 1020 /* Should be 256 - but higher due to bug in sim */
-#define NR_GPIO_IRQS 146
-#define NR_QPNP_IRQS 32768 /* SPARSE_IRQ is required to support this */
-#define NR_BOARD_IRQS NR_QPNP_IRQS
-#define NR_TLMM_MSM_DIR_CONN_IRQ 8
-#define NR_MSM_GPIOS NR_GPIO_IRQS
-
#endif
diff --git a/arch/arm/mach-msm/include/mach/irqs-8226.h b/arch/arm/mach-msm/include/mach/irqs-8226.h
index 72602b1..abc62d2 100644
--- a/arch/arm/mach-msm/include/mach/irqs-8226.h
+++ b/arch/arm/mach-msm/include/mach/irqs-8226.h
@@ -31,11 +31,4 @@
#define SC_SICL2PERFMONIRPTREQ APCC_QGICL2PERFMONIRPTREQ
#define TLMM_MSM_SUMMARY_IRQ (GIC_SPI_START + 208)
-#define NR_MSM_IRQS 256
-#define NR_GPIO_IRQS 117
-#define NR_QPNP_IRQS 32768 /* SPARSE_IRQ is required to support this */
-#define NR_BOARD_IRQS NR_QPNP_IRQS
-#define NR_TLMM_MSM_DIR_CONN_IRQ 8
-#define NR_MSM_GPIOS NR_GPIO_IRQS
-
#endif
diff --git a/arch/arm/mach-msm/include/mach/irqs-8910.h b/arch/arm/mach-msm/include/mach/irqs-8910.h
index e883214..635c044 100644
--- a/arch/arm/mach-msm/include/mach/irqs-8910.h
+++ b/arch/arm/mach-msm/include/mach/irqs-8910.h
@@ -30,11 +30,4 @@
#define SC_SICL2PERFMONIRPTREQ APCC_QGICL2PERFMONIRPTREQ
#define TLMM_MSM_SUMMARY_IRQ (GIC_SPI_START + 208)
-#define NR_MSM_IRQS 256
-#define NR_GPIO_IRQS 102
-#define NR_QPNP_IRQS 32768 /* SPARSE_IRQ is required to support this */
-#define NR_BOARD_IRQS NR_QPNP_IRQS
-#define NR_TLMM_MSM_DIR_CONN_IRQ 8
-#define NR_MSM_GPIOS NR_GPIO_IRQS
-
#endif
diff --git a/arch/arm/mach-msm/include/mach/irqs-8974.h b/arch/arm/mach-msm/include/mach/irqs-8974.h
index 8152eca..150b2ee 100644
--- a/arch/arm/mach-msm/include/mach/irqs-8974.h
+++ b/arch/arm/mach-msm/include/mach/irqs-8974.h
@@ -32,12 +32,5 @@
#define TLMM_MSM_SUMMARY_IRQ (GIC_SPI_START + 208)
#define SPS_BAM_DMA_IRQ (GIC_SPI_START + 105)
-#define NR_MSM_IRQS 1020 /* Should be 256 - but higher due to bug in sim */
-#define NR_GPIO_IRQS 146
-#define NR_QPNP_IRQS 32768 /* SPARSE_IRQ is required to support this */
-#define NR_BOARD_IRQS NR_QPNP_IRQS
-#define NR_TLMM_MSM_DIR_CONN_IRQ 8
-#define NR_MSM_GPIOS NR_GPIO_IRQS
-
#endif
diff --git a/arch/arm/mach-msm/include/mach/irqs.h b/arch/arm/mach-msm/include/mach/irqs.h
index 7aff770..7837c79 100644
--- a/arch/arm/mach-msm/include/mach/irqs.h
+++ b/arch/arm/mach-msm/include/mach/irqs.h
@@ -19,9 +19,40 @@
#define MSM_IRQ_BIT(irq) (1 << ((irq) & 31))
-#include "irqs-8625.h"
+#if defined(CONFIG_ARCH_MSM8974) || defined(CONFIG_ARCH_MPQ8092)
-#if defined(CONFIG_ARCH_MSM8960) || defined(CONFIG_ARCH_APQ8064) || \
+#ifdef CONFIG_ARCH_MSM8974
+#include "irqs-8974.h"
+#endif
+
+#ifdef CONFIG_ARCH_MPQ8092
+#include "irqs-8092.h"
+#endif
+
+#define NR_MSM_IRQS 1020 /* Should be 256 - but higher due to bug in sim */
+#define NR_GPIO_IRQS 146
+#define NR_QPNP_IRQS 32768
+#define NR_BOARD_IRQS NR_QPNP_IRQS
+#define NR_TLMM_MSM_DIR_CONN_IRQ 8
+#define NR_MSM_GPIOS NR_GPIO_IRQS
+
+#elif defined(CONFIG_ARCH_MSM8910) || defined(CONFIG_ARCH_MSM8226)
+#ifdef CONFIG_ARCH_MSM8910
+#include "irqs-8910.h"
+#endif
+
+#ifdef CONFIG_ARCH_MSM8226
+#include "irqs-8226.h"
+#endif
+
+#define NR_MSM_IRQS 256
+#define NR_GPIO_IRQS 117
+#define NR_QPNP_IRQS 32768
+#define NR_BOARD_IRQS NR_QPNP_IRQS
+#define NR_TLMM_MSM_DIR_CONN_IRQ 8
+#define NR_MSM_GPIOS NR_GPIO_IRQS
+
+#elif defined(CONFIG_ARCH_MSM8960) || defined(CONFIG_ARCH_APQ8064) || \
defined(CONFIG_ARCH_MSM8930)
#ifdef CONFIG_ARCH_MSM8960
@@ -58,18 +89,10 @@
#else
-#if defined(CONFIG_ARCH_MSM8974)
-#include "irqs-8974.h"
-#elif defined(CONFIG_ARCH_MSM8910)
-#include "irqs-8910.h"
-#elif defined(CONFIG_ARCH_MPQ8092)
-#include "irqs-8092.h"
-#elif defined(CONFIG_ARCH_MSM9615)
+#if defined(CONFIG_ARCH_MSM9615)
#include "irqs-9615.h"
#elif defined(CONFIG_ARCH_MSM9625)
#include "irqs-9625.h"
-#elif defined(CONFIG_ARCH_MSM8226)
-#include "irqs-8226.h"
#elif defined(CONFIG_ARCH_MSM7X30)
#include "irqs-7x30.h"
#elif defined(CONFIG_ARCH_QSD8X50)
@@ -78,7 +101,8 @@
#elif defined(CONFIG_ARCH_MSM8X60)
#include "irqs-8x60.h"
#elif defined(CONFIG_ARCH_MSM7X01A) || defined(CONFIG_ARCH_MSM7X25) \
- || defined(CONFIG_ARCH_MSM7X27)
+ || defined(CONFIG_ARCH_MSM7X27) || defined(CONFIG_ARCH_MSM8625)
+#include "irqs-8625.h"
#include "irqs-7xxx.h"
#define NR_GPIO_IRQS 133
diff --git a/arch/arm/mach-msm/include/mach/msm_bus_board.h b/arch/arm/mach-msm/include/mach/msm_bus_board.h
index 84a7dc0..ab0e72f 100644
--- a/arch/arm/mach-msm/include/mach/msm_bus_board.h
+++ b/arch/arm/mach-msm/include/mach/msm_bus_board.h
@@ -29,6 +29,7 @@
unsigned int len;
int ahb;
const char *fabclk[NUM_CTX];
+ const char *iface_clk;
unsigned int offset;
unsigned int haltid;
unsigned int rpm_enabled;
diff --git a/arch/arm/mach-msm/include/mach/msm_ipc_router.h b/arch/arm/mach-msm/include/mach/msm_ipc_router.h
index 45a7e19..c68c783 100644
--- a/arch/arm/mach-msm/include/mach/msm_ipc_router.h
+++ b/arch/arm/mach-msm/include/mach/msm_ipc_router.h
@@ -55,6 +55,7 @@
void *endpoint;
void (*notify)(unsigned event, void *priv);
+ int (*check_send_permissions)(void *data);
uint32_t num_tx;
uint32_t num_rx;
diff --git a/arch/arm/mach-msm/include/mach/msm_serial_pdata.h b/arch/arm/mach-msm/include/mach/msm_serial_pdata.h
index 4153cb2..40bdc9d 100644
--- a/arch/arm/mach-msm/include/mach/msm_serial_pdata.h
+++ b/arch/arm/mach-msm/include/mach/msm_serial_pdata.h
@@ -10,8 +10,8 @@
* GNU General Public License for more details.
*/
-#ifndef __ASM_ARCH_MSM_SERIAL_HS_H
-#define __ASM_ARCH_MSM_SERIAL_HS_H
+#ifndef __ASM_ARCH_MSM_SERIAL_H
+#define __ASM_ARCH_MSM_SERIAL_H
#include <linux/serial_core.h>
@@ -22,6 +22,7 @@
/* bool: inject char into rx tty on wakeup */
unsigned char inject_rx_on_wakeup;
char rx_to_inject;
+ int userid;
};
#endif
diff --git a/arch/arm/mach-msm/include/mach/rpm-8930.h b/arch/arm/mach-msm/include/mach/rpm-8930.h
index 4ac9192..bc1b918 100644
--- a/arch/arm/mach-msm/include/mach/rpm-8930.h
+++ b/arch/arm/mach-msm/include/mach/rpm-8930.h
@@ -219,182 +219,190 @@
MSM_RPM_8930_ID_MM_FABRIC_ARB_0 + 10,
/* PMIC 8038 */
- MSM_RPM_8930_ID_PM8038_S1_0 = 90,
- MSM_RPM_8930_ID_PM8038_S1_1 = 91,
- MSM_RPM_8930_ID_PM8038_S2_0 = 92,
- MSM_RPM_8930_ID_PM8038_S2_1 = 93,
- MSM_RPM_8930_ID_PM8038_S3_0 = 94,
- MSM_RPM_8930_ID_PM8038_S3_1 = 95,
- MSM_RPM_8930_ID_PM8038_S4_0 = 96,
- MSM_RPM_8930_ID_PM8038_S4_1 = 97,
- MSM_RPM_8930_ID_PM8038_S5_0 = 98,
- MSM_RPM_8930_ID_PM8038_S5_1 = 99,
- MSM_RPM_8930_ID_PM8038_S6_0 = 100,
- MSM_RPM_8930_ID_PM8038_S6_1 = 101,
- MSM_RPM_8930_ID_PM8038_L1_0 = 102,
- MSM_RPM_8930_ID_PM8038_L1_1 = 103,
- MSM_RPM_8930_ID_PM8038_L2_0 = 104,
- MSM_RPM_8930_ID_PM8038_L2_1 = 105,
- MSM_RPM_8930_ID_PM8038_L3_0 = 106,
- MSM_RPM_8930_ID_PM8038_L3_1 = 107,
- MSM_RPM_8930_ID_PM8038_L4_0 = 108,
- MSM_RPM_8930_ID_PM8038_L4_1 = 109,
- MSM_RPM_8930_ID_PM8038_L5_0 = 110,
- MSM_RPM_8930_ID_PM8038_L5_1 = 111,
- MSM_RPM_8930_ID_PM8038_L6_0 = 112,
- MSM_RPM_8930_ID_PM8038_L6_1 = 113,
- MSM_RPM_8930_ID_PM8038_L7_0 = 114,
- MSM_RPM_8930_ID_PM8038_L7_1 = 115,
- MSM_RPM_8930_ID_PM8038_L8_0 = 116,
- MSM_RPM_8930_ID_PM8038_L8_1 = 117,
- MSM_RPM_8930_ID_PM8038_L9_0 = 118,
- MSM_RPM_8930_ID_PM8038_L9_1 = 119,
- MSM_RPM_8930_ID_PM8038_L10_0 = 120,
- MSM_RPM_8930_ID_PM8038_L10_1 = 121,
- MSM_RPM_8930_ID_PM8038_L11_0 = 122,
- MSM_RPM_8930_ID_PM8038_L11_1 = 123,
- MSM_RPM_8930_ID_PM8038_L12_0 = 124,
- MSM_RPM_8930_ID_PM8038_L12_1 = 125,
- MSM_RPM_8930_ID_PM8038_L13_0 = 126,
- MSM_RPM_8930_ID_PM8038_L13_1 = 127,
- MSM_RPM_8930_ID_PM8038_L14_0 = 128,
- MSM_RPM_8930_ID_PM8038_L14_1 = 129,
- MSM_RPM_8930_ID_PM8038_L15_0 = 130,
- MSM_RPM_8930_ID_PM8038_L15_1 = 131,
- MSM_RPM_8930_ID_PM8038_L16_0 = 132,
- MSM_RPM_8930_ID_PM8038_L16_1 = 133,
- MSM_RPM_8930_ID_PM8038_L17_0 = 134,
- MSM_RPM_8930_ID_PM8038_L17_1 = 135,
- MSM_RPM_8930_ID_PM8038_L18_0 = 136,
- MSM_RPM_8930_ID_PM8038_L18_1 = 137,
- MSM_RPM_8930_ID_PM8038_L19_0 = 138,
- MSM_RPM_8930_ID_PM8038_L19_1 = 139,
- MSM_RPM_8930_ID_PM8038_L20_0 = 140,
- MSM_RPM_8930_ID_PM8038_L20_1 = 141,
- MSM_RPM_8930_ID_PM8038_L21_0 = 142,
- MSM_RPM_8930_ID_PM8038_L21_1 = 143,
- MSM_RPM_8930_ID_PM8038_L22_0 = 144,
- MSM_RPM_8930_ID_PM8038_L22_1 = 145,
- MSM_RPM_8930_ID_PM8038_L23_0 = 146,
- MSM_RPM_8930_ID_PM8038_L23_1 = 147,
- MSM_RPM_8930_ID_PM8038_L24_0 = 148,
- MSM_RPM_8930_ID_PM8038_L24_1 = 149,
- MSM_RPM_8930_ID_PM8038_L25_0 = 150,
- MSM_RPM_8930_ID_PM8038_L25_1 = 151,
- MSM_RPM_8930_ID_PM8038_L26_0 = 152,
- MSM_RPM_8930_ID_PM8038_L26_1 = 153,
- MSM_RPM_8930_ID_PM8038_L27_0 = 154,
- MSM_RPM_8930_ID_PM8038_L27_1 = 155,
- MSM_RPM_8930_ID_PM8038_CLK1_0 = 156,
- MSM_RPM_8930_ID_PM8038_CLK1_1 = 157,
- MSM_RPM_8930_ID_PM8038_CLK2_0 = 158,
- MSM_RPM_8930_ID_PM8038_CLK2_1 = 159,
- MSM_RPM_8930_ID_PM8038_LVS1 = 160,
- MSM_RPM_8930_ID_PM8038_LVS2 = 161,
+ MSM_RPM_8930_ID_PM8038_S1_0 = 90,
+ MSM_RPM_8930_ID_PM8038_S1_1 = 91,
+ MSM_RPM_8930_ID_PM8038_S2_0 = 92,
+ MSM_RPM_8930_ID_PM8038_S2_1 = 93,
+ MSM_RPM_8930_ID_PM8038_S3_0 = 94,
+ MSM_RPM_8930_ID_PM8038_S3_1 = 95,
+ MSM_RPM_8930_ID_PM8038_S4_0 = 96,
+ MSM_RPM_8930_ID_PM8038_S4_1 = 97,
+ MSM_RPM_8930_ID_PM8038_S5_0 = 98,
+ MSM_RPM_8930_ID_PM8038_S5_1 = 99,
+ MSM_RPM_8930_ID_PM8038_S6_0 = 100,
+ MSM_RPM_8930_ID_PM8038_S6_1 = 101,
+ MSM_RPM_8930_ID_PM8038_L1_0 = 102,
+ MSM_RPM_8930_ID_PM8038_L1_1 = 103,
+ MSM_RPM_8930_ID_PM8038_L2_0 = 104,
+ MSM_RPM_8930_ID_PM8038_L2_1 = 105,
+ MSM_RPM_8930_ID_PM8038_L3_0 = 106,
+ MSM_RPM_8930_ID_PM8038_L3_1 = 107,
+ MSM_RPM_8930_ID_PM8038_L4_0 = 108,
+ MSM_RPM_8930_ID_PM8038_L4_1 = 109,
+ MSM_RPM_8930_ID_PM8038_L5_0 = 110,
+ MSM_RPM_8930_ID_PM8038_L5_1 = 111,
+ MSM_RPM_8930_ID_PM8038_L6_0 = 112,
+ MSM_RPM_8930_ID_PM8038_L6_1 = 113,
+ MSM_RPM_8930_ID_PM8038_L7_0 = 114,
+ MSM_RPM_8930_ID_PM8038_L7_1 = 115,
+ MSM_RPM_8930_ID_PM8038_L8_0 = 116,
+ MSM_RPM_8930_ID_PM8038_L8_1 = 117,
+ MSM_RPM_8930_ID_PM8038_L9_0 = 118,
+ MSM_RPM_8930_ID_PM8038_L9_1 = 119,
+ MSM_RPM_8930_ID_PM8038_L10_0 = 120,
+ MSM_RPM_8930_ID_PM8038_L10_1 = 121,
+ MSM_RPM_8930_ID_PM8038_L11_0 = 122,
+ MSM_RPM_8930_ID_PM8038_L11_1 = 123,
+ MSM_RPM_8930_ID_PM8038_L12_0 = 124,
+ MSM_RPM_8930_ID_PM8038_L12_1 = 125,
+ MSM_RPM_8930_ID_PM8038_L13_0 = 126,
+ MSM_RPM_8930_ID_PM8038_L13_1 = 127,
+ MSM_RPM_8930_ID_PM8038_L14_0 = 128,
+ MSM_RPM_8930_ID_PM8038_L14_1 = 129,
+ MSM_RPM_8930_ID_PM8038_L15_0 = 130,
+ MSM_RPM_8930_ID_PM8038_L15_1 = 131,
+ MSM_RPM_8930_ID_PM8038_L16_0 = 132,
+ MSM_RPM_8930_ID_PM8038_L16_1 = 133,
+ MSM_RPM_8930_ID_PM8038_L17_0 = 134,
+ MSM_RPM_8930_ID_PM8038_L17_1 = 135,
+ MSM_RPM_8930_ID_PM8038_L18_0 = 136,
+ MSM_RPM_8930_ID_PM8038_L18_1 = 137,
+ MSM_RPM_8930_ID_PM8038_L19_0 = 138,
+ MSM_RPM_8930_ID_PM8038_L19_1 = 139,
+ MSM_RPM_8930_ID_PM8038_L20_0 = 140,
+ MSM_RPM_8930_ID_PM8038_L20_1 = 141,
+ MSM_RPM_8930_ID_PM8038_L21_0 = 142,
+ MSM_RPM_8930_ID_PM8038_L21_1 = 143,
+ MSM_RPM_8930_ID_PM8038_L22_0 = 144,
+ MSM_RPM_8930_ID_PM8038_L22_1 = 145,
+ MSM_RPM_8930_ID_PM8038_L23_0 = 146,
+ MSM_RPM_8930_ID_PM8038_L23_1 = 147,
+ MSM_RPM_8930_ID_PM8038_L24_0 = 148,
+ MSM_RPM_8930_ID_PM8038_L24_1 = 149,
+ MSM_RPM_8930_ID_PM8038_L25_0 = 150,
+ MSM_RPM_8930_ID_PM8038_L25_1 = 151,
+ MSM_RPM_8930_ID_PM8038_L26_0 = 152,
+ MSM_RPM_8930_ID_PM8038_L26_1 = 153,
+ MSM_RPM_8930_ID_PM8038_L27_0 = 154,
+ MSM_RPM_8930_ID_PM8038_L27_1 = 155,
+ MSM_RPM_8930_ID_PM8038_CLK1_0 = 156,
+ MSM_RPM_8930_ID_PM8038_CLK1_1 = 157,
+ MSM_RPM_8930_ID_PM8038_CLK2_0 = 158,
+ MSM_RPM_8930_ID_PM8038_CLK2_1 = 159,
+ MSM_RPM_8930_ID_PM8038_LVS1 = 160,
+ MSM_RPM_8930_ID_PM8038_LVS2 = 161,
+ MSM_RPM_8930_ID_PM8038_NCP_0 = 162,
+ MSM_RPM_8930_ID_PM8038_NCP_1 = 163,
+ MSM_RPM_8930_ID_PM8038_CXO_BUFFERS = 164,
+ MSM_RPM_8930_ID_PM8038_USB_OTG_SWITCH = 165,
+ MSM_RPM_8930_ID_PM8038_HDMI_SWITCH = 166,
+ MSM_RPM_8930_ID_PM8038_QDSS_CLK = 167,
+ MSM_RPM_8930_ID_PM8038_VOLTAGE_CORNER = 168,
+ MSM_RPM_8930_ID_PM8038_LAST = MSM_RPM_8930_ID_PM8038_VOLTAGE_CORNER,
/* PMIC 8917 */
- MSM_RPM_8930_ID_PM8917_S1_0 = 90,
- MSM_RPM_8930_ID_PM8917_S1_1 = 91,
- MSM_RPM_8930_ID_PM8917_S2_0 = 92,
- MSM_RPM_8930_ID_PM8917_S2_1 = 93,
- MSM_RPM_8930_ID_PM8917_S3_0 = 94,
- MSM_RPM_8930_ID_PM8917_S3_1 = 95,
- MSM_RPM_8930_ID_PM8917_S4_0 = 96,
- MSM_RPM_8930_ID_PM8917_S4_1 = 97,
- MSM_RPM_8930_ID_PM8917_S5_0 = 98,
- MSM_RPM_8930_ID_PM8917_S5_1 = 99,
- MSM_RPM_8930_ID_PM8917_S6_0 = 100,
- MSM_RPM_8930_ID_PM8917_S6_1 = 101,
- MSM_RPM_8930_ID_PM8917_S7_0 = 102,
- MSM_RPM_8930_ID_PM8917_S7_1 = 103,
- MSM_RPM_8930_ID_PM8917_S8_0 = 104,
- MSM_RPM_8930_ID_PM8917_S8_1 = 105,
- MSM_RPM_8930_ID_PM8917_L1_0 = 106,
- MSM_RPM_8930_ID_PM8917_L1_1 = 107,
- MSM_RPM_8930_ID_PM8917_L2_0 = 108,
- MSM_RPM_8930_ID_PM8917_L2_1 = 109,
- MSM_RPM_8930_ID_PM8917_L3_0 = 110,
- MSM_RPM_8930_ID_PM8917_L3_1 = 111,
- MSM_RPM_8930_ID_PM8917_L4_0 = 112,
- MSM_RPM_8930_ID_PM8917_L4_1 = 113,
- MSM_RPM_8930_ID_PM8917_L5_0 = 114,
- MSM_RPM_8930_ID_PM8917_L5_1 = 115,
- MSM_RPM_8930_ID_PM8917_L6_0 = 116,
- MSM_RPM_8930_ID_PM8917_L6_1 = 117,
- MSM_RPM_8930_ID_PM8917_L7_0 = 118,
- MSM_RPM_8930_ID_PM8917_L7_1 = 119,
- MSM_RPM_8930_ID_PM8917_L8_0 = 120,
- MSM_RPM_8930_ID_PM8917_L8_1 = 121,
- MSM_RPM_8930_ID_PM8917_L9_0 = 122,
- MSM_RPM_8930_ID_PM8917_L9_1 = 123,
- MSM_RPM_8930_ID_PM8917_L10_0 = 124,
- MSM_RPM_8930_ID_PM8917_L10_1 = 125,
- MSM_RPM_8930_ID_PM8917_L11_0 = 126,
- MSM_RPM_8930_ID_PM8917_L11_1 = 127,
- MSM_RPM_8930_ID_PM8917_L12_0 = 128,
- MSM_RPM_8930_ID_PM8917_L12_1 = 129,
- MSM_RPM_8930_ID_PM8917_L14_0 = 130,
- MSM_RPM_8930_ID_PM8917_L14_1 = 131,
- MSM_RPM_8930_ID_PM8917_L15_0 = 132,
- MSM_RPM_8930_ID_PM8917_L15_1 = 133,
- MSM_RPM_8930_ID_PM8917_L16_0 = 134,
- MSM_RPM_8930_ID_PM8917_L16_1 = 135,
- MSM_RPM_8930_ID_PM8917_L17_0 = 136,
- MSM_RPM_8930_ID_PM8917_L17_1 = 137,
- MSM_RPM_8930_ID_PM8917_L18_0 = 138,
- MSM_RPM_8930_ID_PM8917_L18_1 = 139,
- MSM_RPM_8930_ID_PM8917_L21_0 = 140,
- MSM_RPM_8930_ID_PM8917_L21_1 = 141,
- MSM_RPM_8930_ID_PM8917_L22_0 = 142,
- MSM_RPM_8930_ID_PM8917_L22_1 = 143,
- MSM_RPM_8930_ID_PM8917_L23_0 = 144,
- MSM_RPM_8930_ID_PM8917_L23_1 = 145,
- MSM_RPM_8930_ID_PM8917_L24_0 = 146,
- MSM_RPM_8930_ID_PM8917_L24_1 = 147,
- MSM_RPM_8930_ID_PM8917_L25_0 = 148,
- MSM_RPM_8930_ID_PM8917_L25_1 = 149,
- MSM_RPM_8930_ID_PM8917_L26_0 = 150,
- MSM_RPM_8930_ID_PM8917_L26_1 = 151,
- MSM_RPM_8930_ID_PM8917_L27_0 = 152,
- MSM_RPM_8930_ID_PM8917_L27_1 = 153,
- MSM_RPM_8930_ID_PM8917_L28_0 = 154,
- MSM_RPM_8930_ID_PM8917_L28_1 = 155,
- MSM_RPM_8930_ID_PM8917_L29_0 = 156,
- MSM_RPM_8930_ID_PM8917_L29_1 = 157,
- MSM_RPM_8930_ID_PM8917_L30_0 = 158,
- MSM_RPM_8930_ID_PM8917_L30_1 = 159,
- MSM_RPM_8930_ID_PM8917_L31_0 = 160,
- MSM_RPM_8930_ID_PM8917_L31_1 = 161,
- MSM_RPM_8930_ID_PM8917_L32_0 = 162,
- MSM_RPM_8930_ID_PM8917_L32_1 = 163,
- MSM_RPM_8930_ID_PM8917_L33_0 = 164,
- MSM_RPM_8930_ID_PM8917_L33_1 = 165,
- MSM_RPM_8930_ID_PM8917_L34_0 = 166,
- MSM_RPM_8930_ID_PM8917_L34_1 = 167,
- MSM_RPM_8930_ID_PM8917_L35_0 = 168,
- MSM_RPM_8930_ID_PM8917_L35_1 = 169,
- MSM_RPM_8930_ID_PM8917_L36_0 = 170,
- MSM_RPM_8930_ID_PM8917_L36_1 = 171,
- MSM_RPM_8930_ID_PM8917_CLK1_0 = 172,
- MSM_RPM_8930_ID_PM8917_CLK1_1 = 173,
- MSM_RPM_8930_ID_PM8917_CLK2_0 = 174,
- MSM_RPM_8930_ID_PM8917_CLK2_1 = 175,
- MSM_RPM_8930_ID_PM8917_LVS1 = 176,
- MSM_RPM_8930_ID_PM8917_LVS3 = 177,
- MSM_RPM_8930_ID_PM8917_LVS4 = 178,
- MSM_RPM_8930_ID_PM8917_LVS5 = 179,
- MSM_RPM_8930_ID_PM8917_LVS6 = 180,
- MSM_RPM_8930_ID_PM8917_LVS7 = 181,
+ MSM_RPM_8930_ID_PM8917_S1_0 = 90,
+ MSM_RPM_8930_ID_PM8917_S1_1 = 91,
+ MSM_RPM_8930_ID_PM8917_S2_0 = 92,
+ MSM_RPM_8930_ID_PM8917_S2_1 = 93,
+ MSM_RPM_8930_ID_PM8917_S3_0 = 94,
+ MSM_RPM_8930_ID_PM8917_S3_1 = 95,
+ MSM_RPM_8930_ID_PM8917_S4_0 = 96,
+ MSM_RPM_8930_ID_PM8917_S4_1 = 97,
+ MSM_RPM_8930_ID_PM8917_S5_0 = 98,
+ MSM_RPM_8930_ID_PM8917_S5_1 = 99,
+ MSM_RPM_8930_ID_PM8917_S6_0 = 100,
+ MSM_RPM_8930_ID_PM8917_S6_1 = 101,
+ MSM_RPM_8930_ID_PM8917_S7_0 = 102,
+ MSM_RPM_8930_ID_PM8917_S7_1 = 103,
+ MSM_RPM_8930_ID_PM8917_S8_0 = 104,
+ MSM_RPM_8930_ID_PM8917_S8_1 = 105,
+ MSM_RPM_8930_ID_PM8917_L1_0 = 106,
+ MSM_RPM_8930_ID_PM8917_L1_1 = 107,
+ MSM_RPM_8930_ID_PM8917_L2_0 = 108,
+ MSM_RPM_8930_ID_PM8917_L2_1 = 109,
+ MSM_RPM_8930_ID_PM8917_L3_0 = 110,
+ MSM_RPM_8930_ID_PM8917_L3_1 = 111,
+ MSM_RPM_8930_ID_PM8917_L4_0 = 112,
+ MSM_RPM_8930_ID_PM8917_L4_1 = 113,
+ MSM_RPM_8930_ID_PM8917_L5_0 = 114,
+ MSM_RPM_8930_ID_PM8917_L5_1 = 115,
+ MSM_RPM_8930_ID_PM8917_L6_0 = 116,
+ MSM_RPM_8930_ID_PM8917_L6_1 = 117,
+ MSM_RPM_8930_ID_PM8917_L7_0 = 118,
+ MSM_RPM_8930_ID_PM8917_L7_1 = 119,
+ MSM_RPM_8930_ID_PM8917_L8_0 = 120,
+ MSM_RPM_8930_ID_PM8917_L8_1 = 121,
+ MSM_RPM_8930_ID_PM8917_L9_0 = 122,
+ MSM_RPM_8930_ID_PM8917_L9_1 = 123,
+ MSM_RPM_8930_ID_PM8917_L10_0 = 124,
+ MSM_RPM_8930_ID_PM8917_L10_1 = 125,
+ MSM_RPM_8930_ID_PM8917_L11_0 = 126,
+ MSM_RPM_8930_ID_PM8917_L11_1 = 127,
+ MSM_RPM_8930_ID_PM8917_L12_0 = 128,
+ MSM_RPM_8930_ID_PM8917_L12_1 = 129,
+ MSM_RPM_8930_ID_PM8917_L14_0 = 130,
+ MSM_RPM_8930_ID_PM8917_L14_1 = 131,
+ MSM_RPM_8930_ID_PM8917_L15_0 = 132,
+ MSM_RPM_8930_ID_PM8917_L15_1 = 133,
+ MSM_RPM_8930_ID_PM8917_L16_0 = 134,
+ MSM_RPM_8930_ID_PM8917_L16_1 = 135,
+ MSM_RPM_8930_ID_PM8917_L17_0 = 136,
+ MSM_RPM_8930_ID_PM8917_L17_1 = 137,
+ MSM_RPM_8930_ID_PM8917_L18_0 = 138,
+ MSM_RPM_8930_ID_PM8917_L18_1 = 139,
+ MSM_RPM_8930_ID_PM8917_L21_0 = 140,
+ MSM_RPM_8930_ID_PM8917_L21_1 = 141,
+ MSM_RPM_8930_ID_PM8917_L22_0 = 142,
+ MSM_RPM_8930_ID_PM8917_L22_1 = 143,
+ MSM_RPM_8930_ID_PM8917_L23_0 = 144,
+ MSM_RPM_8930_ID_PM8917_L23_1 = 145,
+ MSM_RPM_8930_ID_PM8917_L24_0 = 146,
+ MSM_RPM_8930_ID_PM8917_L24_1 = 147,
+ MSM_RPM_8930_ID_PM8917_L25_0 = 148,
+ MSM_RPM_8930_ID_PM8917_L25_1 = 149,
+ MSM_RPM_8930_ID_PM8917_L26_0 = 150,
+ MSM_RPM_8930_ID_PM8917_L26_1 = 151,
+ MSM_RPM_8930_ID_PM8917_L27_0 = 152,
+ MSM_RPM_8930_ID_PM8917_L27_1 = 153,
+ MSM_RPM_8930_ID_PM8917_L28_0 = 154,
+ MSM_RPM_8930_ID_PM8917_L28_1 = 155,
+ MSM_RPM_8930_ID_PM8917_L29_0 = 156,
+ MSM_RPM_8930_ID_PM8917_L29_1 = 157,
+ MSM_RPM_8930_ID_PM8917_L30_0 = 158,
+ MSM_RPM_8930_ID_PM8917_L30_1 = 159,
+ MSM_RPM_8930_ID_PM8917_L31_0 = 160,
+ MSM_RPM_8930_ID_PM8917_L31_1 = 161,
+ MSM_RPM_8930_ID_PM8917_L32_0 = 162,
+ MSM_RPM_8930_ID_PM8917_L32_1 = 163,
+ MSM_RPM_8930_ID_PM8917_L33_0 = 164,
+ MSM_RPM_8930_ID_PM8917_L33_1 = 165,
+ MSM_RPM_8930_ID_PM8917_L34_0 = 166,
+ MSM_RPM_8930_ID_PM8917_L34_1 = 167,
+ MSM_RPM_8930_ID_PM8917_L35_0 = 168,
+ MSM_RPM_8930_ID_PM8917_L35_1 = 169,
+ MSM_RPM_8930_ID_PM8917_L36_0 = 170,
+ MSM_RPM_8930_ID_PM8917_L36_1 = 171,
+ MSM_RPM_8930_ID_PM8917_CLK1_0 = 172,
+ MSM_RPM_8930_ID_PM8917_CLK1_1 = 173,
+ MSM_RPM_8930_ID_PM8917_CLK2_0 = 174,
+ MSM_RPM_8930_ID_PM8917_CLK2_1 = 175,
+ MSM_RPM_8930_ID_PM8917_LVS1 = 176,
+ MSM_RPM_8930_ID_PM8917_LVS3 = 177,
+ MSM_RPM_8930_ID_PM8917_LVS4 = 178,
+ MSM_RPM_8930_ID_PM8917_LVS5 = 179,
+ MSM_RPM_8930_ID_PM8917_LVS6 = 180,
+ MSM_RPM_8930_ID_PM8917_LVS7 = 181,
+ MSM_RPM_8930_ID_PM8917_NCP_0 = 182,
+ MSM_RPM_8930_ID_PM8917_NCP_1 = 183,
+ MSM_RPM_8930_ID_PM8917_CXO_BUFFERS = 184,
+ MSM_RPM_8930_ID_PM8917_USB_OTG_SWITCH = 185,
+ MSM_RPM_8930_ID_PM8917_HDMI_SWITCH = 186,
+ MSM_RPM_8930_ID_PM8917_QDSS_CLK = 187,
+ MSM_RPM_8930_ID_PM8917_VOLTAGE_CORNER = 188,
- MSM_RPM_8930_ID_NCP_0 = 182,
- MSM_RPM_8930_ID_NCP_1 = 183,
- MSM_RPM_8930_ID_CXO_BUFFERS = 184,
- MSM_RPM_8930_ID_USB_OTG_SWITCH = 185,
- MSM_RPM_8930_ID_HDMI_SWITCH = 186,
- MSM_RPM_8930_ID_QDSS_CLK = 187,
- MSM_RPM_8930_ID_VOLTAGE_CORNER = 188,
-
- MSM_RPM_8930_ID_LAST = MSM_RPM_8930_ID_VOLTAGE_CORNER,
+ MSM_RPM_8930_ID_LAST = MSM_RPM_8930_ID_PM8917_VOLTAGE_CORNER,
+ MSM_RPM_8930_ID_PM8917_LAST = MSM_RPM_8930_ID_LAST,
};
/* RPM status ID enum */
diff --git a/arch/arm/mach-msm/include/mach/rpm.h b/arch/arm/mach-msm/include/mach/rpm.h
index 4ee1997..200a8cf 100644
--- a/arch/arm/mach-msm/include/mach/rpm.h
+++ b/arch/arm/mach-msm/include/mach/rpm.h
@@ -1086,6 +1086,14 @@
.count = c, \
}
+#define MSM_RPM_MAP_PMIC(_target, _pmic, _id, _select, _count) \
+ [MSM_RPM_ID_##_id] = \
+ {\
+ .id = MSM_RPM_##_target##_ID_PM##_pmic##_##_id, \
+ .sel = MSM_RPM_##_target##_SEL_##_select, \
+ .count = _count, \
+ }
+
#define MSM_RPM_STATUS_ID_VALID BIT(31)
#define MSM_RPM_STATUS_ID_MAP(t, i) \
diff --git a/arch/arm/mach-msm/include/mach/sps.h b/arch/arm/mach-msm/include/mach/sps.h
index 5333c2e..a000c3e 100644
--- a/arch/arm/mach-msm/include/mach/sps.h
+++ b/arch/arm/mach-msm/include/mach/sps.h
@@ -160,6 +160,8 @@
SPS_O_AUTO_ENABLE = 0x20000000,
/* DISABLE endpoint synchronization for config/enable/disable */
SPS_O_NO_EP_SYNC = 0x40000000,
+ /* Allow partial polling duing IRQ mode */
+ SPS_O_HYBRID = 0x80000000,
};
/**
diff --git a/arch/arm/mach-msm/include/mach/usbdiag.h b/arch/arm/mach-msm/include/mach/usbdiag.h
index 4d0f63a..d9320c3 100644
--- a/arch/arm/mach-msm/include/mach/usbdiag.h
+++ b/arch/arm/mach-msm/include/mach/usbdiag.h
@@ -21,6 +21,8 @@
#ifndef _DRIVERS_USB_DIAG_H_
#define _DRIVERS_USB_DIAG_H_
+#include <linux/err.h>
+
#define DIAG_LEGACY "diag"
#define DIAG_MDM "diag_mdm"
#define DIAG_QSC "diag_qsc"
@@ -46,6 +48,7 @@
void *priv_usb;
};
+#ifdef CONFIG_USB_G_ANDROID
struct usb_diag_ch *usb_diag_open(const char *name, void *priv,
void (*notify)(void *, unsigned, struct diag_request *));
void usb_diag_close(struct usb_diag_ch *ch);
@@ -53,7 +56,32 @@
void usb_diag_free_req(struct usb_diag_ch *ch);
int usb_diag_read(struct usb_diag_ch *ch, struct diag_request *d_req);
int usb_diag_write(struct usb_diag_ch *ch, struct diag_request *d_req);
-
-int diag_read_from_cb(unsigned char * , int);
-
+#else
+static inline struct usb_diag_ch *usb_diag_open(const char *name, void *priv,
+ void (*notify)(void *, unsigned, struct diag_request *))
+{
+ return ERR_PTR(-ENODEV);
+}
+static inline void usb_diag_close(struct usb_diag_ch *ch)
+{
+}
+static inline
+int usb_diag_alloc_req(struct usb_diag_ch *ch, int n_write, int n_read)
+{
+ return -ENODEV;
+}
+static inline void usb_diag_free_req(struct usb_diag_ch *ch)
+{
+}
+static inline
+int usb_diag_read(struct usb_diag_ch *ch, struct diag_request *d_req)
+{
+ return -ENODEV;
+}
+static inline
+int usb_diag_write(struct usb_diag_ch *ch, struct diag_request *d_req)
+{
+ return -ENODEV;
+}
+#endif /* CONFIG_USB_G_ANDROID */
#endif /* _DRIVERS_USB_DIAG_H_ */
diff --git a/arch/arm/mach-msm/ipc_router.c b/arch/arm/mach-msm/ipc_router.c
index 8f1d197..fde43b0 100644
--- a/arch/arm/mach-msm/ipc_router.c
+++ b/arch/arm/mach-msm/ipc_router.c
@@ -37,6 +37,7 @@
#include "ipc_router.h"
#include "modem_notifier.h"
+#include "msm_ipc_router_security.h"
enum {
SMEM_LOG = 1U << 0,
@@ -114,6 +115,7 @@
struct msm_ipc_port_name name;
char pdev_name[32];
int next_pdev_id;
+ int synced_sec_rule;
struct list_head server_port_list;
};
@@ -133,6 +135,7 @@
wait_queue_head_t quota_wait;
uint32_t tx_quota_cnt;
struct mutex quota_lock;
+ void *sec_rule;
};
struct msm_ipc_router_xprt_info {
@@ -651,6 +654,7 @@
rport_ptr->port_id = port_id;
rport_ptr->node_id = node_id;
rport_ptr->restart_state = RESTART_NORMAL;
+ rport_ptr->sec_rule = NULL;
rport_ptr->tx_quota_cnt = 0;
init_waitqueue_head(&rport_ptr->quota_wait);
mutex_init(&rport_ptr->quota_lock);
@@ -770,6 +774,7 @@
}
server->name.service = service;
server->name.instance = instance;
+ server->synced_sec_rule = 0;
INIT_LIST_HEAD(&server->server_port_list);
list_add_tail(&server->list, &server_list[key]);
scnprintf(server->pdev_name, sizeof(server->pdev_name),
@@ -1312,6 +1317,95 @@
msm_ipc_cleanup_routing_table(xprt_info);
}
+/**
+ * sync_sec_rule() - Synchrnoize the security rule into the server structure
+ * @server: Server structure where the rule has to be synchronized.
+ * @rule: Security tule to be synchronized.
+ *
+ * This function is used to update the server structure with the security
+ * rule configured for the <service:instance> corresponding to that server.
+ */
+static void sync_sec_rule(struct msm_ipc_server *server, void *rule)
+{
+ struct msm_ipc_server_port *server_port;
+ struct msm_ipc_router_remote_port *rport_ptr = NULL;
+
+ list_for_each_entry(server_port, &server->server_port_list, list) {
+ rport_ptr = msm_ipc_router_lookup_remote_port(
+ server_port->server_addr.node_id,
+ server_port->server_addr.port_id);
+ if (!rport_ptr)
+ continue;
+ rport_ptr->sec_rule = rule;
+ }
+ server->synced_sec_rule = 1;
+}
+
+/**
+ * msm_ipc_sync_sec_rule() - Sync the security rule to the service
+ * @service: Service for which the rule has to be synchronized.
+ * @instance: Instance for which the rule has to be synchronized.
+ * @rule: Security rule to be synchronized.
+ *
+ * This function is used to syncrhonize the security rule with the server
+ * hash table, if the user-space script configures the rule after the service
+ * has come up. This function is used to synchronize the security rule to a
+ * specific service and optionally a specific instance.
+ */
+void msm_ipc_sync_sec_rule(uint32_t service, uint32_t instance, void *rule)
+{
+ int key = (service & (SRV_HASH_SIZE - 1));
+ struct msm_ipc_server *server;
+
+ mutex_lock(&server_list_lock);
+ list_for_each_entry(server, &server_list[key], list) {
+ if (server->name.service != service)
+ continue;
+
+ if (server->name.instance != instance &&
+ instance != ALL_INSTANCE)
+ continue;
+
+ /*
+ * If the rule applies to all instances and if the specific
+ * instance of a service has a rule synchronized already,
+ * do not apply the rule for that specific instance.
+ */
+ if (instance == ALL_INSTANCE && server->synced_sec_rule)
+ continue;
+
+ sync_sec_rule(server, rule);
+ }
+ mutex_unlock(&server_list_lock);
+}
+
+/**
+ * msm_ipc_sync_default_sec_rule() - Default security rule to all services
+ * @rule: Security rule to be synchronized.
+ *
+ * This function is used to syncrhonize the security rule with the server
+ * hash table, if the user-space script configures the rule after the service
+ * has come up. This function is used to synchronize the security rule that
+ * applies to all services, if the concerned service do not have any rule
+ * defined.
+ */
+void msm_ipc_sync_default_sec_rule(void *rule)
+{
+ int key;
+ struct msm_ipc_server *server;
+
+ mutex_lock(&server_list_lock);
+ for (key = 0; key < SRV_HASH_SIZE; key++) {
+ list_for_each_entry(server, &server_list[key], list) {
+ if (server->synced_sec_rule)
+ continue;
+
+ sync_sec_rule(server, rule);
+ }
+ }
+ mutex_unlock(&server_list_lock);
+}
+
static int process_hello_msg(struct msm_ipc_router_xprt_info *xprt_info,
struct rr_header *hdr)
{
@@ -1491,6 +1585,9 @@
if (!rport_ptr)
pr_err("%s: Remote port create "
"failed\n", __func__);
+ rport_ptr->sec_rule =
+ msm_ipc_get_security_rule(
+ msg->srv.service, msg->srv.instance);
}
wake_up(&newserver_wait);
}
@@ -1989,6 +2086,15 @@
return -ENOMEM;
}
+ if (src->check_send_permissions) {
+ ret = src->check_send_permissions(rport_ptr->sec_rule);
+ if (ret <= 0) {
+ pr_err("%s: permission failure for %s\n",
+ __func__, current->comm);
+ return -EPERM;
+ }
+ }
+
pkt = create_pkt(data);
if (!pkt) {
pr_err("%s: Pkt creation failed\n", __func__);
@@ -2781,6 +2887,10 @@
if (ret < 0)
pr_err("%s: Init sockets failed\n", __func__);
+ ret = msm_ipc_router_security_init();
+ if (ret < 0)
+ pr_err("%s: Security Init failed\n", __func__);
+
complete_all(&msm_ipc_local_router_up);
return ret;
}
diff --git a/arch/arm/mach-msm/ipc_router.h b/arch/arm/mach-msm/ipc_router.h
index 39038f2..39bde30 100644
--- a/arch/arm/mach-msm/ipc_router.h
+++ b/arch/arm/mach-msm/ipc_router.h
@@ -52,6 +52,9 @@
#define ALIGN_SIZE(x) ((4 - ((x) & 3)) & 3)
+#define ALL_SERVICE 0xFFFFFFFF
+#define ALL_INSTANCE 0xFFFFFFFF
+
union rr_control_msg {
uint32_t cmd;
struct {
@@ -139,6 +142,10 @@
int msm_ipc_router_init_sockets(void);
void msm_ipc_router_exit_sockets(void);
+void msm_ipc_sync_sec_rule(uint32_t service, uint32_t instance, void *rule);
+
+void msm_ipc_sync_default_sec_rule(void *rule);
+
#if defined CONFIG_MSM_IPC_ROUTER_SMD_XPRT
extern void *msm_ipc_load_default_node(void);
diff --git a/arch/arm/mach-msm/ipc_socket.c b/arch/arm/mach-msm/ipc_socket.c
index 3a6abbd..5d21fa5 100644
--- a/arch/arm/mach-msm/ipc_socket.c
+++ b/arch/arm/mach-msm/ipc_socket.c
@@ -21,10 +21,6 @@
#include <linux/gfp.h>
#include <linux/msm_ipc.h>
-#ifdef CONFIG_ANDROID_PARANOID_NETWORK
-#include <linux/android_aid.h>
-#endif
-
#include <asm/string.h>
#include <asm/atomic.h>
@@ -33,6 +29,7 @@
#include <mach/msm_ipc_router.h>
#include "ipc_router.h"
+#include "msm_ipc_router_security.h"
#define msm_ipc_sk(sk) ((struct msm_ipc_sock *)(sk))
#define msm_ipc_sk_port(sk) ((struct msm_ipc_port *)(msm_ipc_sk(sk)->port))
@@ -41,21 +38,6 @@
static struct proto msm_ipc_proto;
static const struct proto_ops msm_ipc_proto_ops;
-#ifdef CONFIG_ANDROID_PARANOID_NETWORK
-static inline int check_permissions(void)
-{
- int rc = 0;
- if (!current_euid() || in_egroup_p(AID_NET_RAW))
- rc = 1;
- return rc;
-}
-# else
-static inline int check_permissions(void)
-{
- return 1;
-}
-#endif
-
static struct sk_buff_head *msm_ipc_router_build_msg(unsigned int num_sect,
struct iovec const *msg_sect,
size_t total_len)
@@ -193,7 +175,8 @@
void *pil;
if (!check_permissions()) {
- pr_err("%s: Do not have permissions\n", __func__);
+ pr_err("%s: %s Do not have permissions\n",
+ __func__, current->comm);
return -EPERM;
}
@@ -223,6 +206,7 @@
return -ENOMEM;
}
+ port_ptr->check_send_permissions = msm_ipc_check_send_permissions;
sock->ops = &msm_ipc_proto_ops;
sock_init_data(sock, sk);
sk->sk_rcvtimeo = DEFAULT_RCV_TIMEO;
@@ -445,6 +429,10 @@
ret = msm_ipc_router_bind_control_port(port_ptr);
break;
+ case IPC_ROUTER_IOCTL_CONFIG_SEC_RULES:
+ ret = msm_ipc_config_sec_rules((void *)arg);
+ break;
+
default:
ret = -EINVAL;
}
diff --git a/arch/arm/mach-msm/mdm_common.c b/arch/arm/mach-msm/mdm_common.c
index b81832e..aef4ac9 100644
--- a/arch/arm/mach-msm/mdm_common.c
+++ b/arch/arm/mach-msm/mdm_common.c
@@ -300,6 +300,7 @@
if (ret)
pr_err("%s: Graceful shutdown of the external modem failed, ret = %d\n",
__func__, ret);
+ put_user(ret, (unsigned long __user *) arg);
break;
default:
pr_err("%s: invalid ioctl cmd = %d\n", __func__, _IOC_NR(cmd));
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 5c20a4e..dbfa5ec 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
@@ -642,6 +642,8 @@
.qport = qports_crypto_c0,
.mas_hw_id = MAS_CRYPTO_CORE0,
.hw_sel = MSM_BUS_NOC,
+ .prio_rd = 1,
+ .prio_wr = 1,
},
{
.id = MSM_BUS_MASTER_CRYPTO_CORE1,
@@ -653,6 +655,8 @@
.qport = qports_crypto_c1,
.mas_hw_id = MAS_CRYPTO_CORE1,
.hw_sel = MSM_BUS_NOC,
+ .prio_rd = 1,
+ .prio_wr = 1,
},
{
.id = MSM_BUS_MASTER_LPASS_PROC,
@@ -722,6 +726,7 @@
.prio_rd = 2,
.prio_wr = 2,
.hw_sel = MSM_BUS_NOC,
+ .iface_clk_node = "msm_usb3",
},
{
.id = MSM_BUS_SLAVE_AMPSS,
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_core.h b/arch/arm/mach-msm/msm_bus/msm_bus_core.h
index 12d6862..2c6efb8 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_core.h
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_core.h
@@ -71,6 +71,7 @@
int hw_sel;
const char *slaveclk[NUM_CTX];
const char *memclk[NUM_CTX];
+ const char *iface_clk_node;
unsigned int buswidth;
unsigned int ws;
unsigned int mode;
@@ -117,6 +118,7 @@
int commit_index;
struct nodeclk nodeclk[NUM_CTX];
struct nodeclk memclk[NUM_CTX];
+ struct nodeclk iface_clk;
void *hw_data;
};
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 7169440..b6870c6 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
@@ -175,6 +175,15 @@
}
}
+ if (info->node_info->iface_clk_node) {
+ info->iface_clk.clk = clk_get_sys(info->node_info->
+ iface_clk_node, "iface_clk");
+ if (IS_ERR(info->iface_clk.clk)) {
+ MSM_BUS_ERR("ERR: Couldn't get clk %s\n",
+ info->node_info->iface_clk_node);
+ }
+ }
+
ret = info->node_info->gateway ?
msm_bus_fabric_add_fab(fabric, info) :
msm_bus_fabric_add_node(fabric, info);
@@ -187,6 +196,12 @@
if (fabric->fabdev.hw_algo.node_init == NULL)
continue;
+ if (info->iface_clk.clk) {
+ MSM_BUS_DBG("Enabled iface clock for node init: %d\n",
+ info->node_info->priv_id);
+ clk_prepare_enable(info->iface_clk.clk);
+ }
+
for (j = 0; j < NUM_CTX; j++)
clk_prepare_enable(fabric->info.nodeclk[j].clk);
@@ -198,6 +213,14 @@
for (j = 0; j < NUM_CTX; j++)
clk_disable_unprepare(fabric->info.nodeclk[j].clk);
+
+ if (info->iface_clk.clk) {
+ MSM_BUS_DBG("Disable iface_clk after node init: %d\n",
+ info->node_info->priv_id);
+ clk_disable_unprepare(info->iface_clk.clk);
+ }
+
+
}
MSM_BUS_DBG("Fabric: %d nmasters: %d nslaves: %d\n"
@@ -355,14 +378,35 @@
return;
}
+ /* Enable clocks before accessing QoS registers */
for (i = 0; i < NUM_CTX; i++)
clk_prepare_enable(fabric->info.nodeclk[i].clk);
+ if (info->iface_clk.clk)
+ clk_prepare_enable(info->iface_clk.clk);
+
+ if (hop->iface_clk.clk)
+ clk_prepare_enable(hop->iface_clk.clk);
+
fabdev->hw_algo.update_bw(hop, info, fabric->pdata, sel_cdata,
master_tiers, add_bw);
+
+ /* Disable clocks after accessing QoS registers */
for (i = 0; i < NUM_CTX; i++)
clk_disable_unprepare(fabric->info.nodeclk[i].clk);
+ if (info->iface_clk.clk) {
+ MSM_BUS_DBG("Commented: Will disable clock for info: %d\n",
+ info->node_info->priv_id);
+ clk_disable_unprepare(info->iface_clk.clk);
+ }
+
+ if (hop->iface_clk.clk) {
+ MSM_BUS_DBG("Commented Will disable clock for hop: %d\n",
+ hop->node_info->priv_id);
+ clk_disable_unprepare(hop->iface_clk.clk);
+ }
+
fabric->arb_dirty = true;
}
diff --git a/arch/arm/mach-msm/msm_dcvs.c b/arch/arm/mach-msm/msm_dcvs.c
index 41afd24..3b9656e 100644
--- a/arch/arm/mach-msm/msm_dcvs.c
+++ b/arch/arm/mach-msm/msm_dcvs.c
@@ -65,6 +65,7 @@
struct kobj_attribute thermal_poll_ms;
struct kobj_attribute freq_tbl;
+ struct kobj_attribute offset_tbl;
struct attribute_group attrib_group;
};
@@ -295,9 +296,14 @@
continue;
if (gpu->pending_freq != STOP_FREQ_CHANGE &&
- gpu->set_floor_frequency)
+ gpu->set_floor_frequency) {
gpu->set_floor_frequency(gpu->type_core_num,
gpu_floor_freq);
+ /* TZ will know about a freq change (if any)
+ * at next idle exit. */
+ gpu->actual_freq =
+ gpu->get_frequency(gpu->type_core_num);
+ }
}
mutex_unlock(&gpu_floor_mutex);
@@ -715,6 +721,77 @@
DCVS_PARAM_STORE(thermal_poll_ms)
+static ssize_t msm_dcvs_attr_offset_tbl_show(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ char *buf)
+{
+ struct msm_dcvs_freq_entry *freq_tbl;
+ char *buf_idx = buf;
+ int i, len;
+ struct dcvs_core *core = CORE_FROM_ATTRIBS(attr, offset_tbl);
+
+ freq_tbl = core->info->freq_tbl;
+ *buf_idx = '\0';
+
+ /* limit the number of frequencies we will print into
+ * the PAGE_SIZE sysfs show buffer. */
+ if (core->info->power_param.num_freq > 64)
+ return 0;
+
+ for (i = 0; i < core->info->power_param.num_freq; i++) {
+ len = snprintf(buf_idx, 30, "%7d %7d %7d\n",
+ freq_tbl[i].freq,
+ freq_tbl[i].active_energy_offset,
+ freq_tbl[i].leakage_energy_offset);
+ /* buf_idx always points at terminating null */
+ buf_idx += len;
+ }
+ return buf_idx - buf;
+}
+
+static ssize_t msm_dcvs_attr_offset_tbl_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ struct msm_dcvs_freq_entry *freq_tbl;
+ uint32_t freq, active_energy_offset, leakage_energy_offset;
+ int i, ret;
+ struct dcvs_core *core = CORE_FROM_ATTRIBS(attr, offset_tbl);
+
+ freq_tbl = core->info->freq_tbl;
+
+ ret = sscanf(buf, "%u %u %u",
+ &freq, &active_energy_offset, &leakage_energy_offset);
+ if (ret != 3) {
+ __err("Invalid input %s for offset_tbl\n", buf);
+ return count;
+ }
+
+ for (i = 0; i < core->info->power_param.num_freq; i++)
+ if (freq_tbl[i].freq == freq) {
+ freq_tbl[i].active_energy_offset =
+ active_energy_offset;
+ freq_tbl[i].leakage_energy_offset =
+ leakage_energy_offset;
+ break;
+ }
+
+ if (i >= core->info->power_param.num_freq) {
+ __err("Invalid frequency for offset_tbl: %d\n", freq);
+ return count;
+ }
+
+ ret = msm_dcvs_scm_set_power_params(core->dcvs_core_id,
+ &core->info->power_param,
+ &core->info->freq_tbl[0],
+ &core->coeffs);
+ if (ret)
+ __err("Error %d in updating active/leakage energy\n", ret);
+
+ return count;
+}
+
static ssize_t msm_dcvs_attr_freq_tbl_show(struct kobject *kobj,
struct kobj_attribute *attr,
char *buf)
@@ -791,7 +868,7 @@
{
int ret = 0;
struct kobject *core_kobj = NULL;
- const int attr_count = 25;
+ const int attr_count = 26;
BUG_ON(!cores_kobj);
@@ -830,8 +907,9 @@
DCVS_RW_ATTRIB(22, thermal_poll_ms);
DCVS_RW_ATTRIB(23, freq_tbl);
+ DCVS_RW_ATTRIB(24, offset_tbl);
- core->attrib.attrib_group.attrs[24] = NULL;
+ core->attrib.attrib_group.attrs[25] = NULL;
core_kobj = kobject_create_and_add(core->core_name, cores_kobj);
if (!core_kobj) {
@@ -919,27 +997,6 @@
num_cpu_freqs++;
}
-static void update_cpu_dcvs_params(struct msm_dcvs_core_info *info)
-{
- int i;
-
- BUG_ON(num_cpu_freqs == 0);
-
- info->freq_tbl = cpu_freq_tbl;
- info->power_param.num_freq = num_cpu_freqs;
-
- if (!dcvs_pdata || dcvs_pdata->num_sync_rules == 0)
- return;
-
- /* the first sync rule shows what the turbo frequencies are -
- * these frequencies need energy offsets set */
- for (i = 0; i < DCVS_MAX_NUM_FREQS && cpu_freq_tbl[i].freq != 0; i++)
- if (cpu_freq_tbl[i].freq > dcvs_pdata->sync_rules[0].cpu_khz) {
- cpu_freq_tbl[i].active_energy_offset = 100;
- cpu_freq_tbl[i].leakage_energy_offset = 100;
- }
-}
-
int msm_dcvs_register_core(
enum msm_dcvs_core_type type,
int type_core_num,
@@ -975,8 +1032,11 @@
core->set_floor_frequency = set_floor_frequency;
core->info = info;
- if (type == MSM_DCVS_CORE_TYPE_CPU)
- update_cpu_dcvs_params(info);
+ if (type == MSM_DCVS_CORE_TYPE_CPU) {
+ BUG_ON(num_cpu_freqs == 0);
+ info->freq_tbl = cpu_freq_tbl;
+ info->power_param.num_freq = num_cpu_freqs;
+ }
memcpy(&core->algo_param, &info->algo_param,
sizeof(struct msm_dcvs_algo_param));
diff --git a/arch/arm/mach-msm/msm_ipc_router_security.c b/arch/arm/mach-msm/msm_ipc_router_security.c
new file mode 100644
index 0000000..27cf524
--- /dev/null
+++ b/arch/arm/mach-msm/msm_ipc_router_security.c
@@ -0,0 +1,271 @@
+/* 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/types.h>
+#include <linux/net.h>
+#include <linux/socket.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/poll.h>
+#include <linux/fcntl.h>
+#include <linux/gfp.h>
+#include <linux/uaccess.h>
+#include <linux/kernel.h>
+#include <linux/msm_ipc.h>
+
+#include <asm/uaccess.h>
+
+#include <net/sock.h>
+#include "ipc_router.h"
+#include "msm_ipc_router_security.h"
+
+#define SEC_RULES_HASH_SZ 32
+struct security_rule {
+ struct list_head list;
+ uint32_t service_id;
+ uint32_t instance_id;
+ unsigned reserved;
+ int num_group_info;
+ int *group_id;
+};
+
+static DEFINE_MUTEX(security_rules_lock);
+static struct list_head security_rules[SEC_RULES_HASH_SZ];
+
+/**
+ * check_permisions() - Check whether the process has permissions to
+ * create an interface handle with IPC Router
+ *
+ * @return: true if the process has permissions, else false.
+ */
+int check_permissions(void)
+{
+ int rc = 0;
+ if (!current_euid() || in_egroup_p(AID_NET_RAW))
+ rc = 1;
+ return rc;
+}
+EXPORT_SYMBOL(check_permissions);
+
+/**
+ * msm_ipc_config_sec_rules() - Add a security rule to the database
+ * @arg: Pointer to the buffer containing the rule.
+ *
+ * @return: 0 if successfully added, < 0 for error.
+ *
+ * A security rule is defined using <Service_ID: Group_ID> tuple. The rule
+ * implies that a user-space process in order to send a QMI message to
+ * service Service_ID should belong to the Linux group Group_ID.
+ */
+int msm_ipc_config_sec_rules(void *arg)
+{
+ struct config_sec_rules_args sec_rules_arg;
+ struct security_rule *rule, *temp_rule;
+ int key;
+ int ret;
+
+ if (current_euid())
+ return -EPERM;
+
+ ret = copy_from_user(&sec_rules_arg, (void *)arg,
+ sizeof(sec_rules_arg));
+ if (ret)
+ return -EFAULT;
+
+ if (sec_rules_arg.num_group_info <= 0)
+ return -EINVAL;
+
+ rule = kzalloc(sizeof(struct security_rule), GFP_KERNEL);
+ if (!rule) {
+ pr_err("%s: security_rule alloc failed\n", __func__);
+ return -ENOMEM;
+ }
+
+ rule->group_id = kzalloc((sec_rules_arg.num_group_info * sizeof(int)),
+ GFP_KERNEL);
+ if (!rule->group_id) {
+ pr_err("%s: group_id alloc failed\n", __func__);
+ kfree(rule);
+ return -ENOMEM;
+ }
+
+ rule->service_id = sec_rules_arg.service_id;
+ rule->instance_id = sec_rules_arg.instance_id;
+ rule->reserved = sec_rules_arg.reserved;
+ rule->num_group_info = sec_rules_arg.num_group_info;
+ ret = copy_from_user(rule->group_id,
+ ((void *)(arg + sizeof(sec_rules_arg))),
+ (rule->num_group_info * sizeof(uint32_t)));
+ if (ret) {
+ kfree(rule->group_id);
+ kfree(rule);
+ return -EFAULT;
+ }
+
+ key = rule->service_id & (SEC_RULES_HASH_SZ - 1);
+ mutex_lock(&security_rules_lock);
+ if (rule->service_id == ALL_SERVICE) {
+ temp_rule = list_first_entry(&security_rules[key],
+ struct security_rule, list);
+ list_del(&temp_rule->list);
+ kfree(temp_rule->group_id);
+ kfree(temp_rule);
+ }
+ list_add_tail(&rule->list, &security_rules[key]);
+ mutex_unlock(&security_rules_lock);
+
+ if (rule->service_id == ALL_SERVICE)
+ msm_ipc_sync_default_sec_rule((void *)rule);
+ else
+ msm_ipc_sync_sec_rule(rule->service_id, rule->instance_id,
+ (void *)rule);
+
+ return 0;
+}
+EXPORT_SYMBOL(msm_ipc_config_sec_rules);
+
+/**
+ * msm_ipc_add_default_rule() - Add default security rule
+ *
+ * @return: 0 on success, < 0 on error/
+ *
+ * This function is used to ensure the basic security, if there is no
+ * security rule defined for a service. It can be overwritten by the
+ * default security rule from user-space script.
+ */
+static int msm_ipc_add_default_rule(void)
+{
+ struct security_rule *rule;
+ int key;
+
+ rule = kzalloc(sizeof(struct security_rule), GFP_KERNEL);
+ if (!rule) {
+ pr_err("%s: security_rule alloc failed\n", __func__);
+ return -ENOMEM;
+ }
+
+ rule->group_id = kzalloc(sizeof(int), GFP_KERNEL);
+ if (!rule->group_id) {
+ pr_err("%s: group_id alloc failed\n", __func__);
+ kfree(rule);
+ return -ENOMEM;
+ }
+
+ rule->service_id = ALL_SERVICE;
+ rule->instance_id = ALL_INSTANCE;
+ rule->num_group_info = 1;
+ *(rule->group_id) = AID_NET_RAW;
+ mutex_lock(&security_rules_lock);
+ key = (ALL_SERVICE & (SEC_RULES_HASH_SZ - 1));
+ list_add_tail(&rule->list, &security_rules[key]);
+ mutex_unlock(&security_rules_lock);
+ return 0;
+}
+
+/**
+ * msm_ipc_get_security_rule() - Get the security rule corresponding to a
+ * service
+ * @service_id: Service ID for which the rule has to be got.
+ * @instance_id: Instance ID for which the rule has to be got.
+ *
+ * @return: Returns the rule info on success, NULL on error.
+ *
+ * This function is used when the service comes up and gets registered with
+ * the IPC Router.
+ */
+void *msm_ipc_get_security_rule(uint32_t service_id, uint32_t instance_id)
+{
+ int key;
+ struct security_rule *rule;
+
+ key = (service_id & (SEC_RULES_HASH_SZ - 1));
+ mutex_lock(&security_rules_lock);
+ /* Return the rule for a specific <service:instance>, if found. */
+ list_for_each_entry(rule, &security_rules[key], list) {
+ if ((rule->service_id == service_id) &&
+ (rule->instance_id == instance_id)) {
+ mutex_unlock(&security_rules_lock);
+ return (void *)rule;
+ }
+ }
+
+ /* Return the rule for a specific service, if found. */
+ list_for_each_entry(rule, &security_rules[key], list) {
+ if ((rule->service_id == service_id) &&
+ (rule->instance_id == ALL_INSTANCE)) {
+ mutex_unlock(&security_rules_lock);
+ return (void *)rule;
+ }
+ }
+
+ /* Return the default rule, if no rule defined for a service. */
+ key = (ALL_SERVICE & (SEC_RULES_HASH_SZ - 1));
+ list_for_each_entry(rule, &security_rules[key], list) {
+ if ((rule->service_id == ALL_SERVICE) &&
+ (rule->instance_id == ALL_INSTANCE)) {
+ mutex_unlock(&security_rules_lock);
+ return (void *)rule;
+ }
+ }
+ return NULL;
+}
+EXPORT_SYMBOL(msm_ipc_get_security_rule);
+
+/**
+ * msm_ipc_check_send_permissions() - Check if the sendng process has
+ * permissions specified as per the rule
+ * @data: Security rule to be checked.
+ *
+ * @return: true if the process has permissions, else false.
+ *
+ * This function is used to check if the current executing process has
+ * permissions to send message to the remote entity. The security rule
+ * corresponding to the remote entity is specified by "data" parameter
+ */
+int msm_ipc_check_send_permissions(void *data)
+{
+ int i;
+ struct security_rule *rule = (struct security_rule *)data;
+
+ /* Source/Sender is Root user */
+ if (!current_euid())
+ return 1;
+
+ /* Destination has no rules defined, possibly a client. */
+ if (!rule)
+ return 1;
+
+ for (i = 0; i < rule->num_group_info; i++) {
+ if (in_egroup_p(rule->group_id[i]))
+ return 1;
+ }
+ return 0;
+}
+EXPORT_SYMBOL(msm_ipc_check_send_permissions);
+
+/**
+ * msm_ipc_router_security_init() - Initialize the security rule database
+ *
+ * @return: 0 if successful, < 0 for error.
+ */
+int msm_ipc_router_security_init(void)
+{
+ int i;
+
+ for (i = 0; i < SEC_RULES_HASH_SZ; i++)
+ INIT_LIST_HEAD(&security_rules[i]);
+
+ msm_ipc_add_default_rule();
+ return 0;
+}
+EXPORT_SYMBOL(msm_ipc_router_security_init);
diff --git a/arch/arm/mach-msm/msm_ipc_router_security.h b/arch/arm/mach-msm/msm_ipc_router_security.h
new file mode 100644
index 0000000..8701343
--- /dev/null
+++ b/arch/arm/mach-msm/msm_ipc_router_security.h
@@ -0,0 +1,104 @@
+/* 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 _MSM_IPC_ROUTER_SECURITY_H
+#define _MSM_IPC_ROUTER_SECURITY_H
+
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/errno.h>
+
+#ifdef CONFIG_MSM_IPC_ROUTER_SECURITY
+#include <linux/android_aid.h>
+
+/**
+ * check_permisions() - Check whether the process has permissions to
+ * create an interface handle with IPC Router
+ *
+ * @return: true if the process has permissions, else false.
+ */
+int check_permissions(void);
+
+/**
+ * msm_ipc_config_sec_rules() - Add a security rule to the database
+ * @arg: Pointer to the buffer containing the rule.
+ *
+ * @return: 0 if successfully added, < 0 for error.
+ *
+ * A security rule is defined using <Service_ID: Group_ID> tuple. The rule
+ * implies that a user-space process in order to send a QMI message to
+ * service Service_ID should belong to the Linux group Group_ID.
+ */
+int msm_ipc_config_sec_rules(void *arg);
+
+/**
+ * msm_ipc_get_security_rule() - Get the security rule corresponding to a
+ * service
+ * @service_id: Service ID for which the rule has to be got.
+ * @instance_id: Instance ID for which the rule has to be got.
+ *
+ * @return: Returns the rule info on success, NULL on error.
+ *
+ * This function is used when the service comes up and gets registered with
+ * the IPC Router.
+ */
+void *msm_ipc_get_security_rule(uint32_t service_id, uint32_t instance_id);
+
+/**
+ * msm_ipc_check_send_permissions() - Check if the sendng process has
+ * permissions specified as per the rule
+ * @data: Security rule to be checked.
+ *
+ * @return: true if the process has permissions, else false.
+ *
+ * This function is used to check if the current executing process has
+ * permissions to send message to the remote entity. The security rule
+ * corresponding to the remote entity is specified by "data" parameter
+ */
+int msm_ipc_check_send_permissions(void *data);
+
+/**
+ * msm_ipc_router_security_init() - Initialize the security rule database
+ *
+ * @return: 0 if successful, < 0 for error.
+ */
+int msm_ipc_router_security_init(void);
+
+#else
+
+static inline int check_permissions(void)
+{
+ return 1;
+}
+
+static inline int msm_ipc_config_sec_rules(void *arg)
+{
+ return -ENODEV;
+}
+
+static inline void *msm_ipc_get_security_rule(uint32_t service_id,
+ uint32_t instance_id)
+{
+ return NULL;
+}
+
+static inline int msm_ipc_check_send_permissions(void *data)
+{
+ return 1;
+}
+
+static inline int msm_ipc_router_security_init(void)
+{
+ return 0;
+}
+#endif
+#endif
diff --git a/arch/arm/mach-msm/peripheral-loader.c b/arch/arm/mach-msm/peripheral-loader.c
index 65e05a9..e3a3563 100644
--- a/arch/arm/mach-msm/peripheral-loader.c
+++ b/arch/arm/mach-msm/peripheral-loader.c
@@ -382,6 +382,7 @@
if (priv->region)
ion_free(ion, priv->region);
+ priv->region = NULL;
list_for_each_entry_safe(p, tmp, &priv->segs, list) {
list_del(&p->list);
kfree(p);
diff --git a/arch/arm/mach-msm/pil-riva.c b/arch/arm/mach-msm/pil-riva.c
index 7993090..74fae98 100644
--- a/arch/arm/mach-msm/pil-riva.c
+++ b/arch/arm/mach-msm/pil-riva.c
@@ -542,7 +542,7 @@
}
ret = devm_request_irq(&pdev->dev, drv->irq, riva_wdog_bite_irq_hdlr,
- IRQF_TRIGGER_HIGH, "riva_wdog", drv);
+ IRQF_TRIGGER_RISING, "riva_wdog", drv);
if (ret < 0)
goto err;
diff --git a/arch/arm/mach-msm/platsmp.c b/arch/arm/mach-msm/platsmp.c
index 0933d20..b1d2464 100644
--- a/arch/arm/mach-msm/platsmp.c
+++ b/arch/arm/mach-msm/platsmp.c
@@ -175,6 +175,9 @@
{
BUG_ON(cpu >= get_core_count());
+ if (machine_is_msm8974_rumi())
+ return 0;
+
if (cpu_is_msm8x60())
return scorpion_release_secondary();
diff --git a/arch/arm/mach-msm/qdsp6v2/Makefile b/arch/arm/mach-msm/qdsp6v2/Makefile
index 66d6bda..08a6de6 100644
--- a/arch/arm/mach-msm/qdsp6v2/Makefile
+++ b/arch/arm/mach-msm/qdsp6v2/Makefile
@@ -20,10 +20,10 @@
obj-$(CONFIG_MSM_QDSP6_CODECS) += aac_in.o qcelp_in.o evrc_in.o amrnb_in.o audio_utils.o
obj-$(CONFIG_MSM_QDSP6_CODECS) += audio_wma.o audio_wmapro.o audio_aac.o audio_multi_aac.o audio_utils_aio.o
obj-$(CONFIG_MSM_QDSP6_CODECS) += rtac.o q6audio_v1.o q6audio_v1_aio.o
-obj-$(CONFIG_MSM_QDSP6_CODECS) += audio_mp3.o audio_amrnb.o audio_amrwb.o audio_evrc.o audio_qcelp.o amrwb_in.o
+obj-$(CONFIG_MSM_QDSP6_CODECS) += audio_mp3.o audio_amrnb.o audio_amrwb.o audio_amrwbplus.o audio_evrc.o audio_qcelp.o amrwb_in.o
obj-$(CONFIG_MSM_QDSP6V2_CODECS) += aac_in.o qcelp_in.o evrc_in.o amrnb_in.o audio_utils.o
obj-$(CONFIG_MSM_QDSP6V2_CODECS) += audio_wma.o audio_wmapro.o audio_aac.o audio_multi_aac.o audio_utils_aio.o
obj-$(CONFIG_MSM_QDSP6V2_CODECS) += rtac_v2.o q6audio_v2.o q6audio_v2_aio.o
-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_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/
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_amrwbplus.c b/arch/arm/mach-msm/qdsp6v2/audio_amrwbplus.c
new file mode 100644
index 0000000..2889c14
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/audio_amrwbplus.c
@@ -0,0 +1,234 @@
+/* amr-wbplus audio output device
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/msm_audio_amrwbplus.h>
+#include "audio_utils_aio.h"
+
+#ifdef CONFIG_DEBUG_FS
+static const struct file_operations audio_amrwbplus_debug_fops = {
+ .read = audio_aio_debug_read,
+ .open = audio_aio_debug_open,
+};
+static void config_debug_fs(struct q6audio_aio *audio)
+{
+ if (audio != NULL) {
+ char name[sizeof("msm_amrwbplus_") + 5];
+ snprintf(name, sizeof(name), "msm_amrwbplus_%04x",
+ audio->ac->session);
+ audio->dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
+ NULL, (void *)audio,
+ &audio_amrwbplus_debug_fops);
+ if (IS_ERR(audio->dentry))
+ pr_debug("debugfs_create_file failed\n");
+ }
+}
+#else
+static void config_debug_fs(struct q6audio_aio *)
+{
+}
+#endif
+
+static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct asm_amrwbplus_cfg q6_amrwbplus_cfg;
+ struct msm_audio_amrwbplus_config_v2 *amrwbplus_drv_config;
+ struct q6audio_aio *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_START: {
+ pr_err("%s[%p]: AUDIO_START session_id[%d]\n", __func__,
+ audio, audio->ac->session);
+ if (audio->feedback == NON_TUNNEL_MODE) {
+ /* Configure PCM output block */
+ rc = q6asm_enc_cfg_blk_pcm(audio->ac,
+ audio->pcm_cfg.sample_rate,
+ audio->pcm_cfg.channel_count);
+ if (rc < 0) {
+ pr_err("pcm output block config failed\n");
+ break;
+ }
+ }
+ amrwbplus_drv_config =
+ (struct msm_audio_amrwbplus_config_v2 *)audio->codec_cfg;
+
+ q6_amrwbplus_cfg.size_bytes =
+ amrwbplus_drv_config->size_bytes;
+ q6_amrwbplus_cfg.version =
+ amrwbplus_drv_config->version;
+ q6_amrwbplus_cfg.num_channels =
+ amrwbplus_drv_config->num_channels;
+ q6_amrwbplus_cfg.amr_band_mode =
+ amrwbplus_drv_config->amr_band_mode;
+ q6_amrwbplus_cfg.amr_dtx_mode =
+ amrwbplus_drv_config->amr_dtx_mode;
+ q6_amrwbplus_cfg.amr_frame_fmt =
+ amrwbplus_drv_config->amr_frame_fmt;
+ q6_amrwbplus_cfg.amr_lsf_idx =
+ amrwbplus_drv_config->amr_lsf_idx;
+
+ rc = q6asm_media_format_block_amrwbplus(audio->ac,
+ &q6_amrwbplus_cfg);
+ if (rc < 0) {
+ pr_err("q6asm_media_format_block_amrwb+ failed...\n");
+ break;
+ }
+ rc = audio_aio_enable(audio);
+ audio->eos_rsp = 0;
+ audio->eos_flag = 0;
+ if (!rc) {
+ audio->enabled = 1;
+ } else {
+ audio->enabled = 0;
+ pr_err("Audio Start procedure failed rc=%d\n", rc);
+ break;
+ }
+ pr_debug("%s:AUDIO_START sessionid[%d]enable[%d]\n", __func__,
+ audio->ac->session,
+ audio->enabled);
+ if (audio->stopped == 1)
+ audio->stopped = 0;
+ break;
+ }
+ case AUDIO_GET_AMRWBPLUS_CONFIG_V2: {
+ if ((audio) && (arg) && (audio->codec_cfg)) {
+ if (copy_to_user((void *)arg, audio->codec_cfg,
+ sizeof(struct msm_audio_amrwbplus_config_v2))) {
+ rc = -EFAULT;
+ pr_err("wb+ config get copy_to_user failed");
+ break;
+ }
+ } else {
+ pr_err("wb+ config v2 invalid parameters..");
+ rc = -EFAULT;
+ break;
+ }
+ break;
+ }
+ case AUDIO_SET_AMRWBPLUS_CONFIG_V2: {
+ if ((audio) && (arg) && (audio->codec_cfg)) {
+ if (copy_from_user(audio->codec_cfg, (void *)arg,
+ sizeof(struct msm_audio_amrwbplus_config_v2))) {
+ rc = -EFAULT;
+ pr_err("wb+ config set copy_to_user_failed");
+ break;
+ }
+ } else {
+ pr_err("wb+ config invalid parameters..");
+ rc = -EFAULT;
+ break;
+ }
+ break;
+ }
+ default:
+ pr_debug("%s[%p]: Calling utils ioctl\n", __func__, audio);
+ rc = audio->codec_ioctl(file, cmd, arg);
+ }
+ return rc;
+}
+
+static int audio_open(struct inode *inode, struct file *file)
+{
+ struct q6audio_aio *audio = NULL;
+ int rc = 0;
+
+ audio = kzalloc(sizeof(struct q6audio_aio), GFP_KERNEL);
+
+ if (audio == NULL) {
+ pr_err("kzalloc failed for amrwb+ decode driver\n");
+ return -ENOMEM;
+ }
+ audio->codec_cfg =
+ kzalloc(sizeof(struct msm_audio_amrwbplus_config_v2), GFP_KERNEL);
+ if (audio->codec_cfg == NULL) {
+ pr_err("%s:failed kzalloc for amrwb+ config structure",
+ __func__);
+ kfree(audio);
+ return -ENOMEM;
+ }
+ audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN;
+
+ audio->ac =
+ q6asm_audio_client_alloc((app_cb) q6_audio_cb, (void *)audio);
+
+ if (!audio->ac) {
+ pr_err("Could not allocate memory for audio client\n");
+ kfree(audio->codec_cfg);
+ kfree(audio);
+ return -ENOMEM;
+ }
+
+ /* open in T/NT mode */
+ if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
+ rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM,
+ FORMAT_AMR_WB_PLUS);
+ if (rc < 0) {
+ pr_err("amrwbplus NT mode Open failed rc=%d\n", rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ audio->feedback = NON_TUNNEL_MODE;
+ audio->buf_cfg.frames_per_buf = 0x01;
+ audio->buf_cfg.meta_info_enable = 0x01;
+ } else if ((file->f_mode & FMODE_WRITE) &&
+ !(file->f_mode & FMODE_READ)) {
+ rc = q6asm_open_write(audio->ac, FORMAT_AMR_WB_PLUS);
+ if (rc < 0) {
+ pr_err("wb+ T mode Open failed rc=%d\n", rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ audio->feedback = TUNNEL_MODE;
+ audio->buf_cfg.meta_info_enable = 0x00;
+ } else {
+ pr_err("audio_amrwbplus Not supported mode\n");
+ rc = -EACCES;
+ goto fail;
+ }
+ rc = audio_aio_open(audio, file);
+
+ config_debug_fs(audio);
+ pr_debug("%s: AMRWBPLUS dec success mode[%d]session[%d]\n", __func__,
+ audio->feedback,
+ audio->ac->session);
+ return 0;
+fail:
+ q6asm_audio_client_free(audio->ac);
+ kfree(audio->codec_cfg);
+ kfree(audio);
+ return rc;
+}
+
+static const struct file_operations audio_amrwbplus_fops = {
+ .owner = THIS_MODULE,
+ .open = audio_open,
+ .release = audio_aio_release,
+ .unlocked_ioctl = audio_ioctl,
+ .fsync = audio_aio_fsync,
+};
+
+struct miscdevice audio_amrwbplus_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "msm_amrwbplus",
+ .fops = &audio_amrwbplus_fops,
+};
+
+static int __init audio_amrwbplus_init(void)
+{
+ return misc_register(&audio_amrwbplus_misc);
+}
+
+device_initcall(audio_amrwbplus_init);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
index fb0ace7..a4a6b906 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
@@ -1142,6 +1142,11 @@
mutex_unlock(&audio->lock);
break;
}
+ if (audio->drv_status & ADRV_STATUS_FSYNC) {
+ pr_debug("%s[%p] Waking up the audio_aio_fsync\n",
+ __func__, audio);
+ wake_up(&audio->write_wait);
+ }
mutex_unlock(&audio->lock);
break;
}
@@ -1178,6 +1183,11 @@
mutex_lock(&audio->lock);
audio->rflush = 1;
audio->wflush = 1;
+ if (audio->drv_status & ADRV_STATUS_FSYNC) {
+ pr_debug("%s[%p] Waking up the audio_aio_fsync\n",
+ __func__, audio);
+ wake_up(&audio->write_wait);
+ }
/* Flush DSP */
rc = audio_aio_flush(audio);
/* Flush input / Output buffer in software*/
diff --git a/arch/arm/mach-msm/qdsp6v2/ultrasound/usfcdev.c b/arch/arm/mach-msm/qdsp6v2/ultrasound/usfcdev.c
index f566e82..94192cf 100644
--- a/arch/arm/mach-msm/qdsp6v2/ultrasound/usfcdev.c
+++ b/arch/arm/mach-msm/qdsp6v2/ultrasound/usfcdev.c
@@ -16,15 +16,38 @@
#include <linux/miscdevice.h>
#include <linux/module.h>
#include <linux/init.h>
+#include <linux/input/mt.h>
+#include <linux/syscalls.h>
#include "usfcdev.h"
+#define UNDEF_ID 0xffffffff
+#define SLOT_CMD_ID 0
+#define MAX_RETRIES 10
+
+
+
+enum usdev_event_status {
+ USFCDEV_EVENT_ENABLED,
+ USFCDEV_EVENT_DISABLING,
+ USFCDEV_EVENT_DISABLED,
+};
+
struct usfcdev_event {
bool (*match_cb)(uint16_t, struct input_dev *dev);
bool registered_event;
- bool filter;
+ bool interleaved;
+ enum usdev_event_status event_status;
};
static struct usfcdev_event s_usfcdev_events[MAX_EVENT_TYPE_NUM];
+struct usfcdev_input_command {
+ unsigned int type;
+ unsigned int code;
+ unsigned int value;
+};
+
+static long s_usf_pid;
+
static bool usfcdev_filter(struct input_handle *handle,
unsigned int type, unsigned int code, int value);
static bool usfcdev_match(struct input_handler *handler,
@@ -83,6 +106,22 @@
},
};
+static struct usfcdev_input_command initial_clear_cmds[] = {
+ {EV_ABS, ABS_PRESSURE, 0},
+ {EV_KEY, BTN_TOUCH, 0},
+};
+
+static struct usfcdev_input_command slot_clear_cmds[] = {
+ {EV_ABS, ABS_MT_SLOT, 0},
+ {EV_ABS, ABS_MT_TRACKING_ID, UNDEF_ID},
+};
+
+static struct usfcdev_input_command no_filter_cmds[] = {
+ {EV_ABS, ABS_MT_SLOT, 0},
+ {EV_ABS, ABS_MT_TRACKING_ID, UNDEF_ID},
+ {EV_SYN, SYN_REPORT, 0},
+};
+
static bool usfcdev_match(struct input_handler *handler, struct input_dev *dev)
{
bool rc = false;
@@ -91,7 +130,7 @@
pr_debug("%s: name=[%s]; ind=%d\n", __func__, dev->name, ind);
if (s_usfcdev_events[ind].registered_event &&
- s_usfcdev_events[ind].match_cb) {
+ s_usfcdev_events[ind].match_cb) {
rc = (*s_usfcdev_events[ind].match_cb)((uint16_t)ind, dev);
pr_debug("%s: [%s]; rc=%d\n", __func__, dev->name, rc);
}
@@ -139,16 +178,39 @@
static bool usfcdev_filter(struct input_handle *handle,
unsigned int type, unsigned int code, int value)
{
+ uint16_t i = 0;
uint16_t ind = (uint16_t)handle->handler->minor;
+ bool rc = (s_usfcdev_events[ind].event_status != USFCDEV_EVENT_ENABLED);
- pr_debug("%s: event_type=%d; filter=%d; abs_xy=%ld; abs_y_mt[]=%ld\n",
- __func__,
- ind,
- s_usfcdev_events[ind].filter,
- usfc_tsc_ids[0].absbit[0],
- usfc_tsc_ids[1].absbit[1]);
+ if (s_usf_pid == sys_getpid()) {
+ /* Pass events from usfcdev driver */
+ rc = false;
+ pr_debug("%s: event_type=%d; type=%d; code=%d; val=%d",
+ __func__,
+ ind,
+ type,
+ code,
+ value);
+ } else if (s_usfcdev_events[ind].event_status ==
+ USFCDEV_EVENT_DISABLING) {
+ uint32_t u_value = value;
+ s_usfcdev_events[ind].interleaved = true;
+ /* Pass events for freeing slots from TSC driver */
+ for (i = 0; i < ARRAY_SIZE(no_filter_cmds); ++i) {
+ if ((no_filter_cmds[i].type == type) &&
+ (no_filter_cmds[i].code == code) &&
+ (no_filter_cmds[i].value <= u_value)) {
+ rc = false;
+ pr_debug("%s: no_filter_cmds[%d]; %d",
+ __func__,
+ i,
+ no_filter_cmds[i].value);
+ break;
+ }
+ }
+ }
- return s_usfcdev_events[ind].filter;
+ return rc;
}
bool usfcdev_register(
@@ -175,7 +237,7 @@
s_usfcdev_events[event_type_ind].registered_event = true;
s_usfcdev_events[event_type_ind].match_cb = match_cb;
- s_usfcdev_events[event_type_ind].filter = false;
+ s_usfcdev_events[event_type_ind].event_status = USFCDEV_EVENT_ENABLED;
ret = input_register_handler(&s_usfc_handlers[event_type_ind]);
if (!ret) {
rc = true;
@@ -209,7 +271,64 @@
event_type_ind);
s_usfcdev_events[event_type_ind].registered_event = false;
s_usfcdev_events[event_type_ind].match_cb = NULL;
- s_usfcdev_events[event_type_ind].filter = false;
+ s_usfcdev_events[event_type_ind].event_status =
+ USFCDEV_EVENT_ENABLED;
+
+ }
+}
+
+static inline void usfcdev_send_cmd(
+ struct input_dev *dev,
+ struct usfcdev_input_command cmd)
+{
+ input_event(dev, cmd.type, cmd.code, cmd.value);
+}
+
+static void usfcdev_clean_dev(uint16_t event_type_ind)
+{
+ struct input_dev *dev = NULL;
+ int i;
+ int j;
+ int retries = 0;
+
+ if (event_type_ind >= MAX_EVENT_TYPE_NUM) {
+ pr_err("%s: wrong input: event_type_ind=%d\n",
+ __func__,
+ event_type_ind);
+ return;
+ }
+
+ dev = s_usfc_handles[event_type_ind].dev;
+
+ for (i = 0; i < ARRAY_SIZE(initial_clear_cmds); i++)
+ usfcdev_send_cmd(dev, initial_clear_cmds[i]);
+ input_sync(dev);
+
+ /* Send commands to free all slots */
+ for (i = 0; i < dev->mtsize; i++) {
+ s_usfcdev_events[event_type_ind].interleaved = false;
+ if (input_mt_get_value(&(dev->mt[i]), ABS_MT_TRACKING_ID) < 0) {
+ pr_debug("%s: skipping slot %d",
+ __func__, i);
+ continue;
+ }
+ slot_clear_cmds[SLOT_CMD_ID].value = i;
+ for (j = 0; j < ARRAY_SIZE(slot_clear_cmds); j++)
+ usfcdev_send_cmd(dev, slot_clear_cmds[j]);
+
+ if (s_usfcdev_events[event_type_ind].interleaved) {
+ pr_debug("%s: interleaved(%d): slot(%d)",
+ __func__, i, dev->slot);
+ if (retries++ < MAX_RETRIES) {
+ --i;
+ continue;
+ }
+ pr_warning("%s: index(%d) reached max retires",
+ __func__, i);
+ }
+
+ retries = 0;
+ input_sync(dev);
}
}
@@ -225,12 +344,22 @@
}
if (s_usfcdev_events[event_type_ind].registered_event) {
- s_usfcdev_events[event_type_ind].filter = filter;
+
pr_debug("%s: event_type[%d]; filter=%d\n",
__func__,
event_type_ind,
filter
);
+ if (filter) {
+ s_usfcdev_events[event_type_ind].event_status =
+ USFCDEV_EVENT_DISABLING;
+ s_usf_pid = sys_getpid();
+ usfcdev_clean_dev(event_type_ind);
+ s_usfcdev_events[event_type_ind].event_status =
+ USFCDEV_EVENT_DISABLED;
+ } else
+ s_usfcdev_events[event_type_ind].event_status =
+ USFCDEV_EVENT_ENABLED;
} else {
pr_err("%s: event_type[%d] isn't registered\n",
__func__,
diff --git a/arch/arm/mach-msm/rpm-smd.c b/arch/arm/mach-msm/rpm-smd.c
index a59b338..1db3d34 100644
--- a/arch/arm/mach-msm/rpm-smd.c
+++ b/arch/arm/mach-msm/rpm-smd.c
@@ -973,7 +973,7 @@
static bool msm_rpm_set_standalone(void)
{
- if (machine_is_msm9625()) {
+ if (machine_is_msm9625() || machine_is_msm8974_rumi()) {
pr_warn("%s(): Running in standalone mode, requests "
"will not be sent to RPM\n", __func__);
standalone = true;
diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c
index 3af066d..212ad77 100644
--- a/arch/arm/mach-msm/timer.c
+++ b/arch/arm/mach-msm/timer.c
@@ -1012,6 +1012,19 @@
};
#endif /* CONFIG_LOCAL_TIMERS */
+#ifdef CONFIG_ARCH_MSM8625
+static void fixup_msm8625_timer(void)
+{
+ struct msm_clock *dgt = &msm_clocks[MSM_CLOCK_DGT];
+ struct msm_clock *gpt = &msm_clocks[MSM_CLOCK_GPT];
+ dgt->irq = MSM8625_INT_DEBUG_TIMER_EXP;
+ gpt->irq = MSM8625_INT_GP_TIMER_EXP;
+ global_timer_offset = MSM_TMR0_BASE - MSM_TMR_BASE;
+}
+#else
+static inline void fixup_msm8625_timer(void) { };
+#endif
+
static void __init msm_timer_init(void)
{
int i;
@@ -1032,11 +1045,8 @@
gpt->flags |= MSM_CLOCK_FLAGS_UNSTABLE_COUNT
| MSM_CLOCK_FLAGS_ODD_MATCH_WRITE
| MSM_CLOCK_FLAGS_DELAYED_WRITE_POST;
- if (cpu_is_msm8625()) {
- dgt->irq = MSM8625_INT_DEBUG_TIMER_EXP;
- gpt->irq = MSM8625_INT_GP_TIMER_EXP;
- global_timer_offset = MSM_TMR0_BASE - MSM_TMR_BASE;
- }
+ if (cpu_is_msm8625())
+ fixup_msm8625_timer();
} else if (cpu_is_qsd8x50()) {
dgt->freq = 4800000;
gpt->regbase = MSM_TMR_BASE;
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 8994d6d..93b8ef1 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -1059,7 +1059,7 @@
dpm_wait_for_children(dev, async);
if (async_error)
- return 0;
+ goto Complete;
/*
* If a device configured to wake up the system from sleep states
@@ -1072,7 +1072,7 @@
if (pm_wakeup_pending()) {
async_error = -EBUSY;
- return 0;
+ goto Complete;
}
data.dev = dev;
@@ -1141,6 +1141,7 @@
del_timer_sync(&timer);
destroy_timer_on_stack(&timer);
+ Complete:
complete_all(&dev->power.completion);
if (error)
diff --git a/drivers/bluetooth/hci_ath.c b/drivers/bluetooth/hci_ath.c
index 50b3362..b5531d6 100644
--- a/drivers/bluetooth/hci_ath.c
+++ b/drivers/bluetooth/hci_ath.c
@@ -43,6 +43,9 @@
#include <net/bluetooth/hci_core.h>
#include "hci_uart.h"
+#ifdef CONFIG_SERIAL_MSM_HS
+#include <mach/msm_serial_hs.h>
+#endif
unsigned int enableuartsleep = 1;
module_param(enableuartsleep, uint, 0644);
@@ -52,8 +55,8 @@
/** Global state flags */
static unsigned long flags;
-/** Tasklet to respond to change in hostwake line */
-static struct tasklet_struct hostwake_task;
+/** Workqueue to respond to change in hostwake line */
+static void wakeup_host_work(struct work_struct *work);
/** Transmission timer */
static void bluesleep_tx_timer_expire(unsigned long data);
@@ -89,11 +92,23 @@
struct sk_buff_head txq;
struct work_struct ctxtsw;
+ struct work_struct ws_sleep;
};
-static void hostwake_interrupt(unsigned long data)
+static void hsuart_serial_clock_on(struct tty_struct *tty)
{
- BT_INFO(" wakeup host\n");
+ struct uart_state *state = tty->driver_data;
+ struct uart_port *port = state->uart_port;
+ BT_DBG("");
+ msm_hs_request_clock_on(port);
+}
+
+static void hsuart_serial_clock_off(struct tty_struct *tty)
+{
+ struct uart_state *state = tty->driver_data;
+ struct uart_port *port = state->uart_port;
+ BT_DBG("");
+ msm_hs_request_clock_off(port);
}
static void modify_timer_task(void)
@@ -109,6 +124,7 @@
{
int status = 0;
if (test_bit(BT_TXEXPIRED, &flags)) {
+ hsuart_serial_clock_on(tty);
BT_INFO("wakeup device\n");
gpio_set_value(bsi->ext_wake, 0);
msleep(20);
@@ -118,6 +134,19 @@
return status;
}
+static void wakeup_host_work(struct work_struct *work)
+{
+ struct ath_struct *ath =
+ container_of(work, struct ath_struct, ws_sleep);
+
+ BT_INFO("wake up host");
+ if (test_bit(BT_SLEEPENABLE, &flags)) {
+ if (test_bit(BT_TXEXPIRED, &flags))
+ hsuart_serial_clock_on(ath->hu->tty);
+ }
+ modify_timer_task();
+}
+
static void ath_hci_uart_work(struct work_struct *work)
{
int status;
@@ -141,11 +170,14 @@
static irqreturn_t bluesleep_hostwake_isr(int irq, void *dev_id)
{
/* schedule a tasklet to handle the change in the host wake line */
- tasklet_schedule(&hostwake_task);
+ struct ath_struct *ath = (struct ath_struct *)dev_id;
+
+ schedule_work(&ath->ws_sleep);
+
return IRQ_HANDLED;
}
-static int ath_bluesleep_gpio_config(int on)
+static int ath_bluesleep_gpio_config(struct ath_struct *ath, int on)
{
int ret = 0;
@@ -193,19 +225,16 @@
/* Initialize timer */
init_timer(&tx_timer);
tx_timer.function = bluesleep_tx_timer_expire;
- tx_timer.data = 0;
-
- /* initialize host wake tasklet */
- tasklet_init(&hostwake_task, hostwake_interrupt, 0);
+ tx_timer.data = (u_long)ath->hu;
if (bsi->irq_polarity == POLARITY_LOW) {
ret = request_irq(bsi->host_wake_irq, bluesleep_hostwake_isr,
IRQF_DISABLED | IRQF_TRIGGER_FALLING,
- "bluetooth hostwake", NULL);
+ "bluetooth hostwake", (void *)ath);
} else {
ret = request_irq(bsi->host_wake_irq, bluesleep_hostwake_isr,
IRQF_DISABLED | IRQF_TRIGGER_RISING,
- "bluetooth hostwake", NULL);
+ "bluetooth hostwake", (void *)ath);
}
if (ret < 0) {
BT_ERR("Couldn't acquire BT_HOST_WAKE IRQ");
@@ -221,7 +250,7 @@
return 0;
free_host_wake_irq:
- free_irq(bsi->host_wake_irq, NULL);
+ free_irq(bsi->host_wake_irq, (void *)ath);
delete_timer:
del_timer(&tx_timer);
gpio_ext_wake:
@@ -242,11 +271,6 @@
if (!bsi)
return -EIO;
- if (ath_bluesleep_gpio_config(1) < 0) {
- BT_ERR("HCIATH3K GPIO Config failed");
- return -EIO;
- }
-
ath = kzalloc(sizeof(*ath), GFP_ATOMIC);
if (!ath)
return -ENOMEM;
@@ -256,13 +280,20 @@
hu->priv = ath;
ath->hu = hu;
+ if (ath_bluesleep_gpio_config(ath, 1) < 0) {
+ BT_ERR("HCIATH3K GPIO Config failed");
+ hu->priv = NULL;
+ kfree(ath);
+ return -EIO;
+ }
+
ath->cur_sleep = enableuartsleep;
if (ath->cur_sleep == 1) {
set_bit(BT_SLEEPENABLE, &flags);
modify_timer_task();
}
INIT_WORK(&ath->ctxtsw, ath_hci_uart_work);
-
+ INIT_WORK(&ath->ws_sleep, wakeup_host_work);
return 0;
}
@@ -289,11 +320,13 @@
cancel_work_sync(&ath->ctxtsw);
- hu->priv = NULL;
- kfree(ath);
+ cancel_work_sync(&ath->ws_sleep);
if (bsi)
- ath_bluesleep_gpio_config(0);
+ ath_bluesleep_gpio_config(ath, 0);
+
+ hu->priv = NULL;
+ kfree(ath);
return 0;
}
@@ -383,11 +416,14 @@
static void bluesleep_tx_timer_expire(unsigned long data)
{
+ struct hci_uart *hu = (struct hci_uart *) data;
+
if (!test_bit(BT_SLEEPENABLE, &flags))
return;
BT_INFO("Tx timer expired\n");
set_bit(BT_TXEXPIRED, &flags);
+ hsuart_serial_clock_off(hu->tty);
}
static struct hci_uart_proto athp = {
diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c
index e78a2aa..24fc99a 100644
--- a/drivers/char/diag/diag_dci.c
+++ b/drivers/char/diag/diag_dci.c
@@ -38,6 +38,8 @@
struct mutex dci_log_mask_mutex;
struct mutex dci_event_mask_mutex;
+smd_channel_t *ch_dci_temp;
+
#define DCI_CHK_CAPACITY(entry, new_data_len) \
((entry->data_len + new_data_len > entry->total_capacity) ? 1 : 0) \
@@ -306,28 +308,100 @@
diag_smd_dci_send_req(MODEM_PROC);
}
-static void diag_smd_dci_notify(void *ctxt, unsigned event)
+void diag_update_smd_dci_work_fn(struct work_struct *work)
{
- queue_work(driver->diag_dci_wq, &(driver->diag_read_smd_dci_work));
+ int i, j;
+ char dirty_bits[16];
+ uint8_t *client_log_mask_ptr;
+ uint8_t *log_mask_ptr;
+ int ret;
+
+ /* Update the peripheral(s) with the dci log and event masks */
+
+ /* If the cntl channel is not up, we can't update logs and events */
+ if (!driver->ch_cntl)
+ return;
+
+ memset(dirty_bits, 0, 16 * sizeof(uint8_t));
+
+ /*
+ * From each log entry used by each client, determine
+ * which log entries in the cumulative logs that need
+ * to be updated on the peripheral.
+ */
+ for (i = 0; i < MAX_DCI_CLIENTS; i++) {
+ if (driver->dci_client_tbl[i].client) {
+ client_log_mask_ptr =
+ driver->dci_client_tbl[i].dci_log_mask;
+ for (j = 0; j < 16; j++) {
+ if (*(client_log_mask_ptr+1))
+ dirty_bits[j] = 1;
+ client_log_mask_ptr += 514;
+ }
+ }
+ }
+
+ mutex_lock(&dci_log_mask_mutex);
+ /* Update the appropriate dirty bits in the cumulative mask */
+ log_mask_ptr = dci_cumulative_log_mask;
+ for (i = 0; i < 16; i++) {
+ if (dirty_bits[i])
+ *(log_mask_ptr+1) = dirty_bits[i];
+
+ log_mask_ptr += 514;
+ }
+ mutex_unlock(&dci_log_mask_mutex);
+
+ ret = diag_send_dci_log_mask(driver->ch_cntl);
+
+ ret = diag_send_dci_event_mask(driver->ch_cntl);
}
-void diag_dci_notify_client(int peripheral_mask)
+void diag_dci_notify_client(int peripheral_mask, int data)
{
int i, stat;
+ struct siginfo info;
+ memset(&info, 0, sizeof(struct siginfo));
+ info.si_code = SI_QUEUE;
+ info.si_int = (peripheral_mask | data);
/* Notify the DCI process that the peripheral DCI Channel is up */
for (i = 0; i < MAX_DCI_CLIENTS; i++) {
if (driver->dci_client_tbl[i].list & peripheral_mask) {
- pr_info("diag: sending signal now\n");
- stat = send_sig(driver->dci_client_tbl[i].signal_type,
- driver->dci_client_tbl[i].client, 0);
+ info.si_signo = driver->dci_client_tbl[i].signal_type;
+ stat = send_sig_info(
+ driver->dci_client_tbl[i].signal_type,
+ &info, driver->dci_client_tbl[i].client);
if (stat)
- pr_err("diag: Err send sig stat: %d\n", stat);
+ pr_err("diag: Err sending dci signal to client, signal data: 0x%x, stat: %d\n",
+ info.si_int, stat);
break;
}
} /* end of loop for all DCI clients */
}
+static void diag_smd_dci_notify(void *ctxt, unsigned event)
+{
+ if (event == SMD_EVENT_CLOSE) {
+ driver->ch_dci = 0;
+ /* Notify the clients of the close */
+ diag_dci_notify_client(DIAG_CON_MPSS, DIAG_STATUS_CLOSED);
+ return;
+ } else if (event == SMD_EVENT_OPEN) {
+
+ if (ch_dci_temp)
+ driver->ch_dci = ch_dci_temp;
+
+ queue_work(driver->diag_dci_wq,
+ &(driver->diag_update_smd_dci_work));
+
+ /* Notify the clients of the open */
+ diag_dci_notify_client(DIAG_CON_MPSS, DIAG_STATUS_OPEN);
+ }
+
+ queue_work(driver->diag_dci_wq, &(driver->diag_read_smd_dci_work));
+}
+
static int diag_dci_probe(struct platform_device *pdev)
{
int err = 0;
@@ -339,12 +413,11 @@
pr_err("diag: cannot open DCI port, Id = %d, err ="
" %d\n", pdev->id, err);
else
- diag_dci_notify_client(DIAG_CON_MPSS);
+ ch_dci_temp = driver->ch_dci;
}
return err;
}
-
int diag_send_dci_pkt(struct diag_master_table entry, unsigned char *buf,
int len, int index)
{
@@ -414,6 +487,11 @@
uint8_t *event_mask_ptr;
int offset = 0;
+ if (!driver->ch_dci) {
+ pr_err("diag: ch_dci not valid for dci updates\n");
+ return DIAG_DCI_SEND_DATA_FAIL;
+ }
+
/* This is Pkt request/response transaction */
if (*(int *)temp > 0) {
/* enter this UID into kernel table and return index */
@@ -535,7 +613,7 @@
ret = DIAG_DCI_NO_ERROR;
}
/* send updated mask to peripherals */
- diag_send_dci_log_mask(driver->ch_cntl);
+ ret = diag_send_dci_log_mask(driver->ch_cntl);
} else if (*(int *)temp == DCI_EVENT_TYPE) {
/* find client id and table */
for (i = 0; i < MAX_DCI_CLIENTS; i++) {
@@ -581,7 +659,7 @@
ret = DIAG_DCI_NO_ERROR;
}
/* send updated mask to peripherals */
- diag_send_dci_event_mask(driver->ch_cntl);
+ ret = diag_send_dci_event_mask(driver->ch_cntl);
} else {
pr_alert("diag: Incorrect DCI transaction\n");
}
@@ -614,11 +692,12 @@
mutex_unlock(&dci_event_mask_mutex);
}
-void diag_send_dci_event_mask(smd_channel_t *ch)
+int diag_send_dci_event_mask(smd_channel_t *ch)
{
void *buf = driver->buf_event_mask_update;
int header_size = sizeof(struct diag_ctrl_event_mask);
int wr_size = -ENOMEM, retry_count = 0, timer;
+ int ret = DIAG_DCI_NO_ERROR;
mutex_lock(&driver->diag_cntl_mutex);
/* send event mask update */
@@ -642,12 +721,18 @@
break;
}
}
- if (wr_size != header_size + DCI_EVENT_MASK_SIZE)
+ if (wr_size != header_size + DCI_EVENT_MASK_SIZE) {
pr_err("diag: error writing dci event mask %d, tried %d\n",
wr_size, header_size + DCI_EVENT_MASK_SIZE);
- } else
+ ret = DIAG_DCI_SEND_DATA_FAIL;
+ }
+ } else {
pr_err("diag: ch not valid for dci event mask update\n");
+ ret = DIAG_DCI_SEND_DATA_FAIL;
+ }
mutex_unlock(&driver->diag_cntl_mutex);
+
+ return ret;
}
void update_dci_cumulative_log_mask(int offset, int byte_index,
@@ -686,12 +771,18 @@
mutex_unlock(&dci_log_mask_mutex);
}
-void diag_send_dci_log_mask(smd_channel_t *ch)
+int diag_send_dci_log_mask(smd_channel_t *ch)
{
void *buf = driver->buf_log_mask_update;
int header_size = sizeof(struct diag_ctrl_log_mask);
uint8_t *log_mask_ptr = dci_cumulative_log_mask;
int i, wr_size = -ENOMEM, retry_count = 0, timer;
+ int ret = DIAG_DCI_NO_ERROR;
+
+ if (!ch) {
+ pr_err("diag: ch not valid for dci log mask update\n");
+ return DIAG_DCI_SEND_DATA_FAIL;
+ }
mutex_lock(&driver->diag_cntl_mutex);
for (i = 0; i < 16; i++) {
@@ -715,10 +806,12 @@
} else
break;
}
- if (wr_size != header_size + 512)
+ if (wr_size != header_size + 512) {
pr_err("diag: dci log mask update failed %d, tried %d",
wr_size, header_size + 512);
- else {
+ ret = DIAG_DCI_SEND_DATA_FAIL;
+
+ } else {
*(log_mask_ptr+1) = 0; /* clear dirty byte */
pr_debug("diag: updated dci log equip ID %d\n",
*log_mask_ptr);
@@ -727,6 +820,8 @@
log_mask_ptr += 514;
}
mutex_unlock(&driver->diag_cntl_mutex);
+
+ return ret;
}
void create_dci_log_mask_tbl(unsigned char *tbl_buf)
@@ -778,6 +873,8 @@
{
int success = 0;
+ ch_dci_temp = NULL;
+
driver->dci_tag = 0;
driver->dci_client_id = 0;
driver->num_dci_client = 0;
diff --git a/drivers/char/diag/diag_dci.h b/drivers/char/diag/diag_dci.h
index 435c750..3f62e5e 100644
--- a/drivers/char/diag/diag_dci.h
+++ b/drivers/char/diag/diag_dci.h
@@ -79,6 +79,7 @@
int diag_dci_init(void);
void diag_dci_exit(void);
void diag_read_smd_dci_work_fn(struct work_struct *);
+void diag_update_smd_dci_work_fn(struct work_struct *);
int diag_process_dci_transaction(unsigned char *buf, int len);
int diag_send_dci_pkt(struct diag_master_table entry, unsigned char *buf,
int len, int index);
@@ -87,11 +88,11 @@
void create_dci_log_mask_tbl(unsigned char *tbl_buf);
void update_dci_cumulative_log_mask(int offset, int byte_index,
uint8_t byte_mask);
-void diag_send_dci_log_mask(smd_channel_t *ch);
+int diag_send_dci_log_mask(smd_channel_t *ch);
void extract_dci_log(unsigned char *buf);
/* DCI event streaming functions */
void update_dci_cumulative_event_mask(int offset, uint8_t byte_mask);
-void diag_send_dci_event_mask(smd_channel_t *ch);
+int diag_send_dci_event_mask(smd_channel_t *ch);
void extract_dci_events(unsigned char *buf);
void create_dci_event_mask_tbl(unsigned char *tbl_buf);
#endif
diff --git a/drivers/char/diag/diag_debugfs.c b/drivers/char/diag/diag_debugfs.c
index 7863f74..c404229 100644
--- a/drivers/char/diag/diag_debugfs.c
+++ b/drivers/char/diag/diag_debugfs.c
@@ -113,7 +113,8 @@
"diag_modem_mask_update_work: %d\n"
"diag_lpass_mask_update_work: %d\n"
"diag_wcnss_mask_update_work: %d\n"
- "diag_read_smd_dci_work: %d\n",
+ "diag_read_smd_dci_work: %d\n"
+ "diag_update_smd_dci_work: %d\n",
work_pending(&(driver->diag_drain_work)),
work_pending(&(driver->diag_read_smd_work)),
work_pending(&(driver->diag_read_smd_cntl_work)),
@@ -124,7 +125,8 @@
work_pending(&(driver->diag_modem_mask_update_work)),
work_pending(&(driver->diag_lpass_mask_update_work)),
work_pending(&(driver->diag_wcnss_mask_update_work)),
- work_pending(&(driver->diag_read_smd_dci_work)));
+ work_pending(&(driver->diag_read_smd_dci_work)),
+ work_pending(&(driver->diag_update_smd_dci_work)));
#ifdef CONFIG_DIAG_OVER_USB
ret += scnprintf(buf+ret, DEBUG_BUF_SIZE,
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index d1ec5f2..ec3bb81 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -67,6 +67,15 @@
#define DIAG_CON_LPASS (0x0004) /* Bit mask for LPASS */
#define DIAG_CON_WCNSS (0x0008) /* Bit mask for WCNSS */
+/*
+ * The status bit masks when received in a signal handler are to be
+ * used in conjunction with the peripheral list bit mask to determine the
+ * status for a peripheral. For instance, 0x00010002 would denote an open
+ * status on the MPSS
+ */
+#define DIAG_STATUS_OPEN (0x00010000) /* DCI channel open status mask */
+#define DIAG_STATUS_CLOSED (0x00020000) /* DCI channel closed status mask */
+
/* Maximum number of pkt reg supported at initialization*/
extern unsigned int diag_max_reg;
extern unsigned int diag_threshold_reg;
@@ -235,6 +244,7 @@
struct work_struct diag_lpass_mask_update_work;
struct work_struct diag_wcnss_mask_update_work;
struct work_struct diag_read_smd_dci_work;
+ struct work_struct diag_update_smd_dci_work;
struct work_struct diag_clean_modem_reg_work;
struct work_struct diag_clean_lpass_reg_work;
struct work_struct diag_clean_wcnss_reg_work;
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 645d916..34ff345 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -1613,7 +1613,9 @@
INIT_WORK(&(driver->diag_read_smd_wcnss_cntl_work),
diag_read_smd_wcnss_cntl_work_fn);
INIT_WORK(&(driver->diag_read_smd_dci_work),
- diag_read_smd_dci_work_fn);
+ diag_read_smd_dci_work_fn);
+ INIT_WORK(&(driver->diag_update_smd_dci_work),
+ diag_update_smd_dci_work_fn);
INIT_WORK(&(driver->diag_clean_modem_reg_work),
diag_clean_modem_reg_fn);
INIT_WORK(&(driver->diag_clean_lpass_reg_work),
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index fa66e96..060e89a 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -393,13 +393,6 @@
*cmds++ = cp_type3_packet(CP_INVALIDATE_STATE, 1);
*cmds++ = 0x7fff;
sizedwords += 2;
- /*
- * add an interrupt at the end of commands so that the smmu
- * disable clock off function will get called
- */
- *cmds++ = cp_type3_packet(CP_INTERRUPT, 1);
- *cmds++ = CP_INT_CNTL__RB_INT_MASK;
- sizedwords += 2;
/* This returns the per context timestamp but we need to
* use the global timestamp for iommu clock disablement */
adreno_ringbuffer_issuecmds(device, adreno_ctx,
@@ -2097,6 +2090,67 @@
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,
struct kgsl_context *context, unsigned int timestamp)
{
@@ -2606,6 +2660,7 @@
.drawctxt_destroy = adreno_drawctxt_destroy,
.setproperty = adreno_setproperty,
.postmortem_dump = adreno_dump,
+ .next_event = adreno_next_event,
};
static struct platform_driver adreno_platform_driver = {
diff --git a/drivers/gpu/msm/adreno_postmortem.c b/drivers/gpu/msm/adreno_postmortem.c
index e069fa5..6e0d6ad 100644
--- a/drivers/gpu/msm/adreno_postmortem.c
+++ b/drivers/gpu/msm/adreno_postmortem.c
@@ -12,6 +12,7 @@
*/
#include <linux/vmalloc.h>
+#include <mach/board.h>
#include "kgsl.h"
#include "kgsl_sharedmem.h"
@@ -737,6 +738,8 @@
mb();
+ msm_clk_dump_debug_info();
+
if (adreno_is_a2xx(adreno_dev))
adreno_dump_a2xx(device);
else if (adreno_is_a3xx(adreno_dev))
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index ed9d00f..0b445d6 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -323,9 +323,19 @@
}
EXPORT_SYMBOL(kgsl_mem_entry_destroy);
-static
-void kgsl_mem_entry_attach_process(struct kgsl_mem_entry *entry,
- struct kgsl_process_private *process)
+/**
+ * kgsl_mem_entry_track_gpuaddr - Insert a mem_entry in the address tree
+ * @process: the process that owns the memory
+ * @entry: the memory entry
+ *
+ * Insert a kgsl_mem_entry in to the rb_tree for searching by GPU address.
+ * Not all mem_entries will have gpu addresses when first created, so this
+ * function may be called after creation when the GPU address is finally
+ * assigned.
+ */
+static void
+kgsl_mem_entry_track_gpuaddr(struct kgsl_process_private *process,
+ struct kgsl_mem_entry *entry)
{
struct rb_node **node;
struct rb_node *parent = NULL;
@@ -350,8 +360,48 @@
rb_insert_color(&entry->node, &process->mem_rb);
spin_unlock(&process->mem_lock);
+}
+/**
+ * kgsl_mem_entry_attach_process - Attach a mem_entry to its owner process
+ * @entry: the memory entry
+ * @process: the owner process
+ *
+ * Attach a newly created mem_entry to its owner process so that
+ * it can be found later. The mem_entry will be added to mem_idr and have
+ * its 'id' field assigned. If the GPU address has been set, the entry
+ * will also be added to the mem_rb tree.
+ *
+ * @returns - 0 on success or error code on failure.
+ */
+static int
+kgsl_mem_entry_attach_process(struct kgsl_mem_entry *entry,
+ struct kgsl_process_private *process)
+{
+ int ret;
+
+ while (1) {
+ if (idr_pre_get(&process->mem_idr, GFP_KERNEL) == 0) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ spin_lock(&process->mem_lock);
+ ret = idr_get_new_above(&process->mem_idr, entry, 1,
+ &entry->id);
+ spin_unlock(&process->mem_lock);
+
+ if (ret == 0)
+ break;
+ else if (ret != -EAGAIN)
+ goto err;
+ }
entry->priv = process;
+
+ if (entry->memdesc.gpuaddr != 0)
+ kgsl_mem_entry_track_gpuaddr(process, entry);
+err:
+ return ret;
}
/* Detach a memory entry from a process and unmap it from the MMU */
@@ -361,6 +411,17 @@
if (entry == NULL)
return;
+ spin_lock(&entry->priv->mem_lock);
+
+ if (entry->id != 0)
+ idr_remove(&entry->priv->mem_idr, entry->id);
+ entry->id = 0;
+
+ if (entry->memdesc.gpuaddr != 0)
+ rb_erase(&entry->node, &entry->priv->mem_rb);
+
+ spin_unlock(&entry->priv->mem_lock);
+
entry->priv->stats[entry->memtype].cur -= entry->memdesc.size;
entry->priv = NULL;
@@ -504,6 +565,22 @@
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);
@@ -761,6 +838,8 @@
private->pid = task_tgid_nr(current);
private->mem_rb = RB_ROOT;
+ idr_init(&private->mem_idr);
+
if (kgsl_mmu_enabled())
{
unsigned long pt_name;
@@ -789,7 +868,7 @@
struct kgsl_process_private *private)
{
struct kgsl_mem_entry *entry = NULL;
- struct rb_node *node;
+ int next = 0;
if (!private)
return;
@@ -804,14 +883,22 @@
list_del(&private->list);
- for (node = rb_first(&private->mem_rb); node; ) {
- entry = rb_entry(node, struct kgsl_mem_entry, node);
- node = rb_next(&entry->node);
-
- rb_erase(&entry->node, &private->mem_rb);
+ while (1) {
+ rcu_read_lock();
+ entry = idr_get_next(&private->mem_idr, &next);
+ rcu_read_unlock();
+ if (entry == NULL)
+ break;
kgsl_mem_entry_detach_process(entry);
+ /*
+ * Always start back at the beginning, to
+ * ensure all entries are removed,
+ * like list_for_each_entry_safe.
+ */
+ next = 0;
}
kgsl_mmu_putpagetable(private->pagetable);
+ idr_destroy(&private->mem_idr);
kfree(private);
unlock:
mutex_unlock(&kgsl_driver.process_mutex);
@@ -990,6 +1077,25 @@
return kgsl_sharedmem_find_region(private, gpuaddr, 1);
}
+/**
+ * kgsl_sharedmem_find_id - find a memory entry by id
+ * @process: the owning process
+ * @id: id to find
+ *
+ * @returns - the mem_entry or NULL
+ */
+static inline struct kgsl_mem_entry *
+kgsl_sharedmem_find_id(struct kgsl_process_private *process, unsigned int id)
+{
+ struct kgsl_mem_entry *entry;
+
+ rcu_read_lock();
+ entry = idr_find(&process->mem_idr, id);
+ rcu_read_unlock();
+
+ return entry;
+}
+
/*call all ioctl sub functions with driver locked*/
static long kgsl_ioctl_device_getproperty(struct kgsl_device_private *dev_priv,
unsigned int cmd, void *data)
@@ -1277,9 +1383,6 @@
void *priv, u32 id, u32 timestamp)
{
struct kgsl_mem_entry *entry = priv;
- spin_lock(&entry->priv->mem_lock);
- rb_erase(&entry->node, &entry->priv->mem_rb);
- spin_unlock(&entry->priv->mem_lock);
trace_kgsl_mem_timestamp_free(device, entry, id, timestamp, 0);
kgsl_mem_entry_detach_process(entry);
}
@@ -1391,34 +1494,52 @@
static long kgsl_ioctl_sharedmem_free(struct kgsl_device_private *dev_priv,
unsigned int cmd, void *data)
{
- int result = 0;
struct kgsl_sharedmem_free *param = data;
struct kgsl_process_private *private = dev_priv->process_priv;
struct kgsl_mem_entry *entry = NULL;
spin_lock(&private->mem_lock);
entry = kgsl_sharedmem_find(private, param->gpuaddr);
- if (entry)
- rb_erase(&entry->node, &private->mem_rb);
-
spin_unlock(&private->mem_lock);
- if (entry) {
- trace_kgsl_mem_free(entry);
-
- kgsl_memfree_hist_set_event(
- entry->priv->pid,
- entry->memdesc.gpuaddr,
- entry->memdesc.size,
- entry->memdesc.flags);
-
- kgsl_mem_entry_detach_process(entry);
- } else {
- KGSL_CORE_ERR("invalid gpuaddr %08x\n", param->gpuaddr);
- result = -EINVAL;
+ if (!entry) {
+ KGSL_MEM_INFO(dev_priv->device, "invalid gpuaddr %08x\n",
+ param->gpuaddr);
+ return -EINVAL;
}
+ trace_kgsl_mem_free(entry);
- return result;
+ kgsl_memfree_hist_set_event(entry->priv->pid,
+ entry->memdesc.gpuaddr,
+ entry->memdesc.size,
+ entry->memdesc.flags);
+
+ kgsl_mem_entry_detach_process(entry);
+ return 0;
+}
+
+static long kgsl_ioctl_gpumem_free_id(struct kgsl_device_private *dev_priv,
+ unsigned int cmd, void *data)
+{
+ struct kgsl_gpumem_free_id *param = data;
+ struct kgsl_process_private *private = dev_priv->process_priv;
+ struct kgsl_mem_entry *entry = NULL;
+
+ entry = kgsl_sharedmem_find_id(private, param->id);
+
+ if (!entry) {
+ KGSL_MEM_INFO(dev_priv->device, "invalid id %d\n", param->id);
+ return -EINVAL;
+ }
+ trace_kgsl_mem_free(entry);
+
+ kgsl_memfree_hist_set_event(entry->priv->pid,
+ entry->memdesc.gpuaddr,
+ entry->memdesc.size,
+ entry->memdesc.flags);
+
+ kgsl_mem_entry_detach_process(entry);
+ return 0;
}
static struct vm_area_struct *kgsl_get_vma_from_start_addr(unsigned int addr)
@@ -1782,6 +1903,16 @@
else
memtype = param->memtype;
+ /*
+ * Mask off unknown flags from userspace. This way the caller can
+ * check if a flag is supported by looking at the returned flags.
+ * Note: CACHEMODE is ignored for this call. Caching should be
+ * determined by type of allocation being mapped.
+ */
+ param->flags &= KGSL_MEMFLAGS_GPUREADONLY
+ | KGSL_MEMTYPE_MASK
+ | KGSL_MEMALIGN_MASK;
+
entry->memdesc.flags = param->flags;
switch (memtype) {
@@ -1856,18 +1987,25 @@
/* Adjust the returned value for a non 4k aligned offset */
param->gpuaddr = entry->memdesc.gpuaddr + (param->offset & ~PAGE_MASK);
+ /* echo back flags */
+ param->flags = entry->memdesc.flags;
+
+ result = kgsl_mem_entry_attach_process(entry, private);
+ if (result)
+ goto error_unmap;
KGSL_STATS_ADD(param->len, kgsl_driver.stats.mapped,
kgsl_driver.stats.mapped_max);
kgsl_process_add_stats(private, entry->memtype, param->len);
- kgsl_mem_entry_attach_process(entry, private);
trace_kgsl_mem_map(entry, param->fd);
kgsl_check_idle(dev_priv->device);
return result;
+error_unmap:
+ kgsl_mmu_unmap(private->pagetable, &entry->memdesc);
error_put_file_ptr:
switch (entry->memtype) {
case KGSL_MEM_ENTRY_PMEM:
@@ -1887,33 +2025,133 @@
return result;
}
-/*This function flushes a graphics memory allocation from CPU cache
- *when caching is enabled with MMU*/
+static int _kgsl_gpumem_sync_cache(struct kgsl_mem_entry *entry, int op)
+{
+ int ret = 0;
+ int cacheop;
+ int mode;
+
+ /*
+ * Flush is defined as (clean | invalidate). If both bits are set, then
+ * do a flush, otherwise check for the individual bits and clean or inv
+ * as requested
+ */
+
+ if ((op & KGSL_GPUMEM_CACHE_FLUSH) == KGSL_GPUMEM_CACHE_FLUSH)
+ cacheop = KGSL_CACHE_OP_FLUSH;
+ else if (op & KGSL_GPUMEM_CACHE_CLEAN)
+ cacheop = KGSL_CACHE_OP_CLEAN;
+ else if (op & KGSL_GPUMEM_CACHE_INV)
+ cacheop = KGSL_CACHE_OP_INV;
+ else {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ mode = kgsl_memdesc_get_cachemode(&entry->memdesc);
+ if (mode != KGSL_CACHEMODE_UNCACHED
+ && mode != KGSL_CACHEMODE_WRITECOMBINE)
+ kgsl_cache_range_op(&entry->memdesc, cacheop);
+
+done:
+ return ret;
+}
+
+/* New cache sync function - supports both directions (clean and invalidate) */
+
+static long
+kgsl_ioctl_gpumem_sync_cache(struct kgsl_device_private *dev_priv,
+ unsigned int cmd, void *data)
+{
+ struct kgsl_gpumem_sync_cache *param = data;
+ struct kgsl_process_private *private = dev_priv->process_priv;
+ struct kgsl_mem_entry *entry = NULL;
+
+ if (param->id != 0) {
+ entry = kgsl_sharedmem_find_id(private, param->id);
+ if (entry == NULL) {
+ KGSL_MEM_INFO(dev_priv->device, "can't find id %d\n",
+ param->id);
+ return -EINVAL;
+ }
+ } else if (param->gpuaddr != 0) {
+ spin_lock(&private->mem_lock);
+ entry = kgsl_sharedmem_find(private, param->gpuaddr);
+ spin_unlock(&private->mem_lock);
+ if (entry == NULL) {
+ KGSL_MEM_INFO(dev_priv->device,
+ "can't find gpuaddr %x\n",
+ param->gpuaddr);
+ return -EINVAL;
+ }
+ } else {
+ return -EINVAL;
+ }
+
+ return _kgsl_gpumem_sync_cache(entry, param->op);
+}
+
+/* Legacy cache function, does a flush (clean + inv) */
+
static long
kgsl_ioctl_sharedmem_flush_cache(struct kgsl_device_private *dev_priv,
unsigned int cmd, void *data)
{
- int result = 0;
- struct kgsl_mem_entry *entry;
struct kgsl_sharedmem_free *param = data;
struct kgsl_process_private *private = dev_priv->process_priv;
+ struct kgsl_mem_entry *entry = NULL;
spin_lock(&private->mem_lock);
entry = kgsl_sharedmem_find(private, param->gpuaddr);
- if (!entry) {
- KGSL_CORE_ERR("invalid gpuaddr %08x\n", param->gpuaddr);
- result = -EINVAL;
- goto done;
- }
- if (!entry->memdesc.hostptr) {
- KGSL_CORE_ERR("invalid hostptr with gpuaddr %08x\n",
- param->gpuaddr);
- goto done;
+ spin_unlock(&private->mem_lock);
+ if (entry == NULL) {
+ KGSL_MEM_INFO(dev_priv->device,
+ "can't find gpuaddr %x\n",
+ param->gpuaddr);
+ return -EINVAL;
}
- kgsl_cache_range_op(&entry->memdesc, KGSL_CACHE_OP_CLEAN);
-done:
- spin_unlock(&private->mem_lock);
+ return _kgsl_gpumem_sync_cache(entry, KGSL_GPUMEM_CACHE_FLUSH);
+}
+
+/*
+ * The common parts of kgsl_ioctl_gpumem_alloc and kgsl_ioctl_gpumem_alloc_id.
+ */
+int
+_gpumem_alloc(struct kgsl_device_private *dev_priv,
+ struct kgsl_mem_entry **ret_entry,
+ unsigned int size, unsigned int flags)
+{
+ int result;
+ struct kgsl_process_private *private = dev_priv->process_priv;
+ struct kgsl_mem_entry *entry;
+
+ /*
+ * Mask off unknown flags from userspace. This way the caller can
+ * check if a flag is supported by looking at the returned flags.
+ */
+ flags &= KGSL_MEMFLAGS_GPUREADONLY
+ | KGSL_CACHEMODE_MASK
+ | KGSL_MEMTYPE_MASK
+ | KGSL_MEMALIGN_MASK;
+
+ entry = kgsl_mem_entry_create();
+ if (entry == NULL)
+ return -ENOMEM;
+
+ result = kgsl_allocate_user(&entry->memdesc, private->pagetable, size,
+ flags);
+ if (result != 0)
+ goto err;
+
+ entry->memtype = KGSL_MEM_ENTRY_KERNEL;
+
+ kgsl_check_idle(dev_priv->device);
+ *ret_entry = entry;
+ return result;
+err:
+ kfree(entry);
+ *ret_entry = NULL;
return result;
}
@@ -1923,29 +2161,111 @@
{
struct kgsl_process_private *private = dev_priv->process_priv;
struct kgsl_gpumem_alloc *param = data;
- struct kgsl_mem_entry *entry;
+ struct kgsl_mem_entry *entry = NULL;
int result;
- entry = kgsl_mem_entry_create();
- if (entry == NULL)
- return -ENOMEM;
+ result = _gpumem_alloc(dev_priv, &entry, param->size, param->flags);
+ if (result)
+ return result;
- result = kgsl_allocate_user(&entry->memdesc, private->pagetable,
- param->size, param->flags);
+ result = kgsl_mmu_map(private->pagetable, &entry->memdesc,
+ kgsl_memdesc_protflags(&entry->memdesc));
+ if (result)
+ goto err;
- if (result == 0) {
- entry->memtype = KGSL_MEM_ENTRY_KERNEL;
- kgsl_mem_entry_attach_process(entry, private);
- param->gpuaddr = entry->memdesc.gpuaddr;
+ result = kgsl_mem_entry_attach_process(entry, private);
+ if (result != 0)
+ goto err;
- kgsl_process_add_stats(private, entry->memtype, param->size);
- trace_kgsl_mem_alloc(entry);
- } else
- kfree(entry);
+ kgsl_process_add_stats(private, entry->memtype, param->size);
+ trace_kgsl_mem_alloc(entry);
- kgsl_check_idle(dev_priv->device);
+ param->gpuaddr = entry->memdesc.gpuaddr;
+ param->size = entry->memdesc.size;
+ param->flags = entry->memdesc.flags;
+ return result;
+err:
+ kgsl_sharedmem_free(&entry->memdesc);
+ kfree(entry);
return result;
}
+
+static long
+kgsl_ioctl_gpumem_alloc_id(struct kgsl_device_private *dev_priv,
+ unsigned int cmd, void *data)
+{
+ struct kgsl_process_private *private = dev_priv->process_priv;
+ struct kgsl_gpumem_alloc_id *param = data;
+ struct kgsl_mem_entry *entry = NULL;
+ int result;
+
+ result = _gpumem_alloc(dev_priv, &entry, param->size, param->flags);
+ if (result != 0)
+ goto err;
+
+ result = kgsl_mmu_map(private->pagetable, &entry->memdesc,
+ kgsl_memdesc_protflags(&entry->memdesc));
+ if (result)
+ goto err;
+
+ result = kgsl_mem_entry_attach_process(entry, private);
+ if (result != 0)
+ goto err;
+
+ kgsl_process_add_stats(private, entry->memtype, param->size);
+ trace_kgsl_mem_alloc(entry);
+
+ param->id = entry->id;
+ param->flags = entry->memdesc.flags;
+ param->size = entry->memdesc.size;
+ param->mmapsize = entry->memdesc.size;
+ param->gpuaddr = entry->memdesc.gpuaddr;
+ return result;
+err:
+ if (entry)
+ kgsl_sharedmem_free(&entry->memdesc);
+ kfree(entry);
+ return result;
+}
+
+static long
+kgsl_ioctl_gpumem_get_info(struct kgsl_device_private *dev_priv,
+ unsigned int cmd, void *data)
+{
+ struct kgsl_process_private *private = dev_priv->process_priv;
+ struct kgsl_gpumem_get_info *param = data;
+ struct kgsl_mem_entry *entry = NULL;
+ int result = 0;
+
+ if (param->id != 0) {
+ entry = kgsl_sharedmem_find_id(private, param->id);
+ if (entry == NULL) {
+ KGSL_MEM_INFO(dev_priv->device, "can't find id %d\n",
+ param->id);
+ return -EINVAL;
+ }
+ } else if (param->gpuaddr != 0) {
+ spin_lock(&private->mem_lock);
+ entry = kgsl_sharedmem_find(private, param->gpuaddr);
+ spin_unlock(&private->mem_lock);
+ if (entry == NULL) {
+ KGSL_MEM_INFO(dev_priv->device,
+ "can't find gpuaddr %lx\n",
+ param->gpuaddr);
+ return -EINVAL;
+ }
+ } else {
+ return -EINVAL;
+ }
+ param->gpuaddr = entry->memdesc.gpuaddr;
+ param->id = entry->id;
+ param->flags = entry->memdesc.flags;
+ param->size = entry->memdesc.size;
+ param->mmapsize = entry->memdesc.size;
+ param->useraddr = entry->memdesc.useraddr;
+ return result;
+}
+
static long kgsl_ioctl_cff_syncmem(struct kgsl_device_private *dev_priv,
unsigned int cmd, void *data)
{
@@ -2145,6 +2465,14 @@
kgsl_ioctl_timestamp_event, 1),
KGSL_IOCTL_FUNC(IOCTL_KGSL_SETPROPERTY,
kgsl_ioctl_device_setproperty, 1),
+ KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUMEM_ALLOC_ID,
+ kgsl_ioctl_gpumem_alloc_id, 0),
+ KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUMEM_FREE_ID,
+ kgsl_ioctl_gpumem_free_id, 0),
+ KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUMEM_GET_INFO,
+ kgsl_ioctl_gpumem_get_info, 0),
+ KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUMEM_SYNC_CACHE,
+ kgsl_ioctl_gpumem_sync_cache, 0),
};
static long kgsl_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
@@ -2314,7 +2642,7 @@
static int kgsl_mmap(struct file *file, struct vm_area_struct *vma)
{
- unsigned int ret;
+ unsigned int ret, cache;
unsigned long vma_offset = vma->vm_pgoff << PAGE_SHIFT;
struct kgsl_device_private *dev_priv = file->private_data;
struct kgsl_process_private *private = dev_priv->process_priv;
@@ -2327,16 +2655,17 @@
return kgsl_mmap_memstore(device, vma);
/* Find a chunk of GPU memory */
+ entry = kgsl_sharedmem_find_id(private, vma->vm_pgoff);
- spin_lock(&private->mem_lock);
- entry = kgsl_sharedmem_find(private, vma_offset);
+ if (entry == NULL) {
+ spin_lock(&private->mem_lock);
+ entry = kgsl_sharedmem_find(private, vma_offset);
+ spin_unlock(&private->mem_lock);
+ }
if (entry)
kgsl_mem_entry_get(entry);
-
- spin_unlock(&private->mem_lock);
-
- if (entry == NULL)
+ else
return -EINVAL;
if (!entry->memdesc.ops ||
@@ -2359,7 +2688,27 @@
vma->vm_flags |= entry->memdesc.ops->vmflags(&entry->memdesc);
vma->vm_private_data = entry;
- vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+
+ /* Determine user-side caching policy */
+
+ cache = kgsl_memdesc_get_cachemode(&entry->memdesc);
+
+ switch (cache) {
+ case KGSL_CACHEMODE_UNCACHED:
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+ break;
+ case KGSL_CACHEMODE_WRITETHROUGH:
+ vma->vm_page_prot = pgprot_writethroughcache(vma->vm_page_prot);
+ break;
+ case KGSL_CACHEMODE_WRITEBACK:
+ vma->vm_page_prot = pgprot_writebackcache(vma->vm_page_prot);
+ break;
+ case KGSL_CACHEMODE_WRITECOMBINE:
+ default:
+ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+ break;
+ }
+
vma->vm_ops = &kgsl_gpumem_vm_ops;
vma->vm_file = file;
diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h
index d22cb6d..cd1f763 100644
--- a/drivers/gpu/msm/kgsl.h
+++ b/drivers/gpu/msm/kgsl.h
@@ -185,6 +185,7 @@
int flags;
void *priv_data;
struct rb_node node;
+ unsigned int id;
unsigned int context_id;
/* back pointer to private structure under whose context this
* allocation is made */
diff --git a/drivers/gpu/msm/kgsl_debugfs.c b/drivers/gpu/msm/kgsl_debugfs.c
index 07a5ff4..d4834e5 100644
--- a/drivers/gpu/msm/kgsl_debugfs.c
+++ b/drivers/gpu/msm/kgsl_debugfs.c
@@ -221,17 +221,28 @@
return '-';
}
+static char get_cacheflag(const struct kgsl_memdesc *m)
+{
+ static const char table[] = {
+ [KGSL_CACHEMODE_WRITECOMBINE] = '-',
+ [KGSL_CACHEMODE_UNCACHED] = 'u',
+ [KGSL_CACHEMODE_WRITEBACK] = 'b',
+ [KGSL_CACHEMODE_WRITETHROUGH] = 't',
+ };
+ return table[kgsl_memdesc_get_cachemode(m)];
+}
+
static int process_mem_print(struct seq_file *s, void *unused)
{
struct kgsl_mem_entry *entry;
struct rb_node *node;
struct kgsl_process_private *private = s->private;
- char flags[4];
+ char flags[5];
char usage[16];
spin_lock(&private->mem_lock);
- seq_printf(s, "%8s %8s %5s %10s %16s %5s\n",
- "gpuaddr", "size", "flags", "type", "usage", "sglen");
+ seq_printf(s, "%8s %8s %5s %5s %10s %16s %5s\n",
+ "gpuaddr", "size", "id", "flags", "type", "usage", "sglen");
for (node = rb_first(&private->mem_rb); node; node = rb_next(node)) {
struct kgsl_memdesc *m;
@@ -241,12 +252,13 @@
flags[0] = kgsl_memdesc_is_global(m) ? 'g' : '-';
flags[1] = m->flags & KGSL_MEMFLAGS_GPUREADONLY ? 'r' : '-';
flags[2] = get_alignflag(m);
- flags[3] = '\0';
+ flags[3] = get_cacheflag(m);
+ flags[4] = '\0';
kgsl_get_memory_usage(usage, sizeof(usage), m->flags);
- seq_printf(s, "%08x %8d %5s %10s %16s %5d\n",
- m->gpuaddr, m->size, flags,
+ seq_printf(s, "%08x %8d %5d %5s %10s %16s %5d\n",
+ m->gpuaddr, m->size, entry->id, flags,
memtype_str(entry->memtype), usage, m->sglen);
}
spin_unlock(&private->mem_lock);
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index ec9a123..ce3820c 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -58,6 +58,7 @@
struct kgsl_device_private;
struct kgsl_context;
struct kgsl_power_stats;
+struct kgsl_event;
struct kgsl_functable {
/* Mandatory functions - these functions must be implemented
@@ -112,6 +113,8 @@
enum kgsl_property_type type, void *value,
unsigned int sizebytes);
int (*postmortem_dump) (struct kgsl_device *device, int manual);
+ void (*next_event)(struct kgsl_device *device,
+ struct kgsl_event *event);
};
/* MH register values */
@@ -265,6 +268,7 @@
pid_t pid;
spinlock_t mem_lock;
struct rb_root mem_rb;
+ struct idr mem_idr;
struct kgsl_pagetable *pagetable;
struct list_head list;
struct kobject kobj;
diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c
index 6fe119d..bf39587 100644
--- a/drivers/gpu/msm/kgsl_mmu.c
+++ b/drivers/gpu/msm/kgsl_mmu.c
@@ -25,6 +25,7 @@
#include "kgsl_mmu.h"
#include "kgsl_device.h"
#include "kgsl_sharedmem.h"
+#include "adreno.h"
#define KGSL_MMU_ALIGN_SHIFT 13
#define KGSL_MMU_ALIGN_MASK (~((1 << KGSL_MMU_ALIGN_SHIFT) - 1))
@@ -536,6 +537,12 @@
uint32_t flags)
{
struct kgsl_device *device = mmu->device;
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+
+ if (!(flags & (KGSL_MMUFLAGS_TLBFLUSH | KGSL_MMUFLAGS_PTUPDATE))
+ && !adreno_is_a2xx(adreno_dev))
+ return;
+
if (KGSL_MMU_TYPE_NONE == kgsl_mmu_type)
return;
else if (device->ftbl->setstate)
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 7a7a8dc..27f198b 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -86,63 +86,296 @@
clkstats->start = ktime_get();
}
+/*
+ * Given a requested power level do bounds checking on the constraints and
+ * return the nearest possible level
+ */
+
+static inline int _adjust_pwrlevel(struct kgsl_pwrctrl *pwr, int level)
+{
+ unsigned int max_pwrlevel = max_t(int, pwr->thermal_pwrlevel,
+ pwr->max_pwrlevel);
+
+ unsigned int min_pwrlevel = max_t(int, pwr->thermal_pwrlevel,
+ pwr->min_pwrlevel);
+
+ if (level < max_pwrlevel)
+ return max_pwrlevel;
+ if (level > min_pwrlevel)
+ return min_pwrlevel;
+
+ return level;
+}
+
void kgsl_pwrctrl_pwrlevel_change(struct kgsl_device *device,
unsigned int new_level)
{
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
- if (new_level < (pwr->num_pwrlevels - 1) &&
- new_level >= pwr->thermal_pwrlevel &&
- new_level != pwr->active_pwrlevel) {
- struct kgsl_pwrlevel *pwrlevel = &pwr->pwrlevels[new_level];
- int diff = new_level - pwr->active_pwrlevel;
- int d = (diff > 0) ? 1 : -1;
- int level = pwr->active_pwrlevel;
- /* Update the clock stats */
- update_clk_statistics(device, true);
- /* Finally set active level */
- pwr->active_pwrlevel = new_level;
- if ((test_bit(KGSL_PWRFLAGS_CLK_ON, &pwr->power_flags)) ||
- (device->state == KGSL_STATE_NAP)) {
- /*
- * On some platforms, instability is caused on
- * changing clock freq when the core is busy.
- * Idle the gpu core before changing the clock freq.
- */
- if (pwr->idle_needed == true)
- device->ftbl->idle(device);
+ struct kgsl_pwrlevel *pwrlevel;
+ int delta;
- /* Don't shift by more than one level at a time to
- * avoid glitches.
- */
- while (level != new_level) {
- level += d;
- clk_set_rate(pwr->grp_clks[0],
- pwr->pwrlevels[level].gpu_freq);
- }
+ /* Adjust the power level to the current constraints */
+ new_level = _adjust_pwrlevel(pwr, new_level);
+
+ if (new_level == pwr->active_pwrlevel)
+ return;
+
+ delta = new_level < pwr->active_pwrlevel ? -1 : 1;
+
+ update_clk_statistics(device, true);
+
+ if (test_bit(KGSL_PWRFLAGS_CLK_ON, &pwr->power_flags) ||
+ (device->state == KGSL_STATE_NAP)) {
+
+ /*
+ * On some platforms, instability is caused on
+ * changing clock freq when the core is busy.
+ * Idle the gpu core before changing the clock freq.
+ */
+
+ if (pwr->idle_needed == true)
+ device->ftbl->idle(device);
+
+ /*
+ * Don't shift by more than one level at a time to
+ * avoid glitches.
+ */
+
+ while (pwr->active_pwrlevel != new_level) {
+ pwr->active_pwrlevel += delta;
+
+ clk_set_rate(pwr->grp_clks[0],
+ pwr->pwrlevels[pwr->active_pwrlevel].gpu_freq);
}
- if (test_bit(KGSL_PWRFLAGS_AXI_ON, &pwr->power_flags)) {
- if (pwr->pcl)
- msm_bus_scale_client_update_request(pwr->pcl,
- pwrlevel->bus_freq);
- else if (pwr->ebi1_clk)
- clk_set_rate(pwr->ebi1_clk, pwrlevel->bus_freq);
- }
- trace_kgsl_pwrlevel(device, pwr->active_pwrlevel,
- pwrlevel->gpu_freq);
}
+
+ pwrlevel = &pwr->pwrlevels[pwr->active_pwrlevel];
+
+ if (test_bit(KGSL_PWRFLAGS_AXI_ON, &pwr->power_flags)) {
+
+ if (pwr->pcl)
+ msm_bus_scale_client_update_request(pwr->pcl,
+ pwrlevel->bus_freq);
+ else if (pwr->ebi1_clk)
+ clk_set_rate(pwr->ebi1_clk, pwrlevel->bus_freq);
+ }
+
+ trace_kgsl_pwrlevel(device, pwr->active_pwrlevel, pwrlevel->gpu_freq);
}
+
EXPORT_SYMBOL(kgsl_pwrctrl_pwrlevel_change);
-static int __gpuclk_store(int max, struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{ int ret, i, delta = 5000000;
- unsigned long val;
+static int kgsl_pwrctrl_thermal_pwrlevel_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
struct kgsl_device *device = kgsl_device_from_dev(dev);
struct kgsl_pwrctrl *pwr;
+ int ret, level;
if (device == NULL)
return 0;
+
+ pwr = &device->pwrctrl;
+
+ ret = sscanf(buf, "%d", &level);
+ if (ret != 1)
+ return count;
+
+ if (level < 0)
+ return count;
+
+ mutex_lock(&device->mutex);
+
+ if (level > pwr->num_pwrlevels - 2)
+ level = pwr->num_pwrlevels - 2;
+
+ pwr->thermal_pwrlevel = level;
+
+ /*
+ * If there is no power policy set the clock to the requested thermal
+ * level - if thermal now happens to be higher than max, then that will
+ * be limited by the pwrlevel change function. Otherwise if there is
+ * a policy only change the active clock if it is higher then the new
+ * thermal level
+ */
+
+ if (device->pwrscale.policy == NULL ||
+ pwr->thermal_pwrlevel > pwr->active_pwrlevel)
+ kgsl_pwrctrl_pwrlevel_change(device, pwr->thermal_pwrlevel);
+
+ mutex_unlock(&device->mutex);
+
+ return count;
+}
+
+static int kgsl_pwrctrl_thermal_pwrlevel_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+
+ struct kgsl_device *device = kgsl_device_from_dev(dev);
+ struct kgsl_pwrctrl *pwr;
+ if (device == NULL)
+ return 0;
+ pwr = &device->pwrctrl;
+ return snprintf(buf, PAGE_SIZE, "%d\n", pwr->thermal_pwrlevel);
+}
+
+static int kgsl_pwrctrl_max_pwrlevel_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct kgsl_device *device = kgsl_device_from_dev(dev);
+ struct kgsl_pwrctrl *pwr;
+ int ret, level, max_level;
+
+ if (device == NULL)
+ return 0;
+
+ pwr = &device->pwrctrl;
+
+ ret = sscanf(buf, "%d", &level);
+ if (ret != 1)
+ return count;
+
+ /* If the use specifies a negative number, then don't change anything */
+ if (level < 0)
+ return count;
+
+ mutex_lock(&device->mutex);
+
+ /* You can't set a maximum power level lower than the minimum */
+ if (level > pwr->min_pwrlevel)
+ level = pwr->min_pwrlevel;
+
+ pwr->max_pwrlevel = level;
+
+
+ max_level = max_t(int, pwr->thermal_pwrlevel, pwr->max_pwrlevel);
+
+ /*
+ * If there is no policy then move to max by default. Otherwise only
+ * move max if the current level happens to be higher then the new max
+ */
+
+ if (device->pwrscale.policy == NULL ||
+ (max_level > pwr->active_pwrlevel))
+ kgsl_pwrctrl_pwrlevel_change(device, max_level);
+
+ mutex_unlock(&device->mutex);
+
+ return count;
+}
+
+static int kgsl_pwrctrl_max_pwrlevel_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+
+ struct kgsl_device *device = kgsl_device_from_dev(dev);
+ struct kgsl_pwrctrl *pwr;
+ if (device == NULL)
+ return 0;
+ pwr = &device->pwrctrl;
+ return snprintf(buf, PAGE_SIZE, "%d\n", pwr->max_pwrlevel);
+}
+
+static int kgsl_pwrctrl_min_pwrlevel_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{ struct kgsl_device *device = kgsl_device_from_dev(dev);
+ struct kgsl_pwrctrl *pwr;
+ int ret, level, min_level;
+
+ if (device == NULL)
+ return 0;
+
+ pwr = &device->pwrctrl;
+
+ ret = sscanf(buf, "%d", &level);
+ if (ret != 1)
+ return count;
+
+ /* Don't do anything on obviously incorrect values */
+ if (level < 0)
+ return count;
+
+ mutex_lock(&device->mutex);
+ if (level > pwr->num_pwrlevels - 2)
+ level = pwr->num_pwrlevels - 2;
+
+ /* You can't set a minimum power level lower than the maximum */
+ if (level < pwr->max_pwrlevel)
+ level = pwr->max_pwrlevel;
+
+ pwr->min_pwrlevel = level;
+
+ min_level = max_t(int, pwr->thermal_pwrlevel, pwr->min_pwrlevel);
+
+ /* Only move the power level higher if minimum is higher then the
+ * current level
+ */
+
+ if (min_level < pwr->active_pwrlevel)
+ kgsl_pwrctrl_pwrlevel_change(device, min_level);
+
+ mutex_unlock(&device->mutex);
+
+ return count;
+}
+
+static int kgsl_pwrctrl_min_pwrlevel_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct kgsl_device *device = kgsl_device_from_dev(dev);
+ struct kgsl_pwrctrl *pwr;
+ if (device == NULL)
+ return 0;
+ pwr = &device->pwrctrl;
+ return snprintf(buf, PAGE_SIZE, "%d\n", pwr->min_pwrlevel);
+}
+
+static int kgsl_pwrctrl_num_pwrlevels_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+
+ struct kgsl_device *device = kgsl_device_from_dev(dev);
+ struct kgsl_pwrctrl *pwr;
+ if (device == NULL)
+ return 0;
+ pwr = &device->pwrctrl;
+ return snprintf(buf, PAGE_SIZE, "%d\n", pwr->num_pwrlevels - 1);
+}
+
+/* Given a GPU clock value, return the nearest powerlevel */
+
+static int _get_nearest_pwrlevel(struct kgsl_pwrctrl *pwr, unsigned int clock)
+{
+ int i;
+
+ for (i = 0; i < pwr->num_pwrlevels - 1; i++) {
+ if (abs(pwr->pwrlevels[i].gpu_freq - clock) < 5000000)
+ return i;
+ }
+
+ return -ERANGE;
+}
+
+static int kgsl_pwrctrl_max_gpuclk_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct kgsl_device *device = kgsl_device_from_dev(dev);
+ struct kgsl_pwrctrl *pwr;
+ unsigned long val;
+ int ret, level;
+
+ if (device == NULL)
+ return 0;
+
pwr = &device->pwrctrl;
ret = sscanf(buf, "%ld", &val);
@@ -150,44 +383,30 @@
return count;
mutex_lock(&device->mutex);
- for (i = 0; i < pwr->num_pwrlevels - 1; i++) {
- if (abs(pwr->pwrlevels[i].gpu_freq - val) < delta) {
- if (max)
- pwr->thermal_pwrlevel = i;
- break;
- }
- }
-
- if (i == (pwr->num_pwrlevels - 1))
+ level = _get_nearest_pwrlevel(pwr, val);
+ if (level < 0)
goto done;
+ pwr->thermal_pwrlevel = level;
+
/*
- * If the current or requested clock speed is greater than the
- * thermal limit, bump down immediately.
+ * if the thermal limit is lower than the current setting,
+ * move the speed down immediately
*/
- if (pwr->pwrlevels[pwr->active_pwrlevel].gpu_freq >
- pwr->pwrlevels[pwr->thermal_pwrlevel].gpu_freq)
+ if (pwr->thermal_pwrlevel > pwr->active_pwrlevel)
kgsl_pwrctrl_pwrlevel_change(device, pwr->thermal_pwrlevel);
- else if (!max || (NULL == device->pwrscale.policy))
- kgsl_pwrctrl_pwrlevel_change(device, i);
done:
mutex_unlock(&device->mutex);
return count;
}
-static int kgsl_pwrctrl_max_gpuclk_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- return __gpuclk_store(1, dev, attr, buf, count);
-}
-
static int kgsl_pwrctrl_max_gpuclk_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
+
struct kgsl_device *device = kgsl_device_from_dev(dev);
struct kgsl_pwrctrl *pwr;
if (device == NULL)
@@ -201,7 +420,27 @@
struct device_attribute *attr,
const char *buf, size_t count)
{
- return __gpuclk_store(0, dev, attr, buf, count);
+ struct kgsl_device *device = kgsl_device_from_dev(dev);
+ struct kgsl_pwrctrl *pwr;
+ unsigned long val;
+ int ret, level;
+
+ if (device == NULL)
+ return 0;
+
+ pwr = &device->pwrctrl;
+
+ ret = sscanf(buf, "%ld", &val);
+ if (ret != 1)
+ return count;
+
+ mutex_lock(&device->mutex);
+ level = _get_nearest_pwrlevel(pwr, val);
+ if (level >= 0)
+ kgsl_pwrctrl_pwrlevel_change(device, level);
+
+ mutex_unlock(&device->mutex);
+ return count;
}
static int kgsl_pwrctrl_gpuclk_show(struct device *dev,
@@ -382,6 +621,18 @@
DEVICE_ATTR(gpu_available_frequencies, 0444,
kgsl_pwrctrl_gpu_available_frequencies_show,
NULL);
+DEVICE_ATTR(max_pwrlevel, 0644,
+ kgsl_pwrctrl_max_pwrlevel_show,
+ kgsl_pwrctrl_max_pwrlevel_store);
+DEVICE_ATTR(min_pwrlevel, 0644,
+ kgsl_pwrctrl_min_pwrlevel_show,
+ kgsl_pwrctrl_min_pwrlevel_store);
+DEVICE_ATTR(thermal_pwrlevel, 0644,
+ kgsl_pwrctrl_thermal_pwrlevel_show,
+ kgsl_pwrctrl_thermal_pwrlevel_store);
+DEVICE_ATTR(num_pwrlevels, 0444,
+ kgsl_pwrctrl_num_pwrlevels_show,
+ NULL);
static const struct device_attribute *pwrctrl_attr_list[] = {
&dev_attr_gpuclk,
@@ -391,6 +642,10 @@
&dev_attr_gpubusy,
&dev_attr_gputop,
&dev_attr_gpu_available_frequencies,
+ &dev_attr_max_pwrlevel,
+ &dev_attr_min_pwrlevel,
+ &dev_attr_thermal_pwrlevel,
+ &dev_attr_num_pwrlevels,
NULL
};
@@ -623,6 +878,13 @@
goto done;
}
pwr->num_pwrlevels = pdata->num_levels;
+
+ /* Initialize the user and thermal clock constraints */
+
+ pwr->max_pwrlevel = 0;
+ pwr->min_pwrlevel = pdata->num_levels - 2;
+ pwr->thermal_pwrlevel = 0;
+
pwr->active_pwrlevel = pdata->init_level;
pwr->default_pwrlevel = pdata->init_level;
for (i = 0; i < pdata->num_levels; i++) {
@@ -885,6 +1147,9 @@
kgsl_pwrstate_to_str(device->state));
break;
}
+
+ kgsl_mmu_disable_clk_on_ts(&device->mmu, 0, false);
+
return 0;
}
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.h b/drivers/gpu/msm/kgsl_pwrctrl.h
index c02a9fc..e51ec54 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.h
+++ b/drivers/gpu/msm/kgsl_pwrctrl.h
@@ -38,6 +38,30 @@
unsigned int elapsed_old;
};
+/**
+ * struct kgsl_pwrctrl - Power control settings for a KGSL device
+ * @interrupt_num - The interrupt number for the device
+ * @ebi1_clk - Pointer to the EBI clock structure
+ * @grp_clks - Array of clocks structures that we control
+ * @power_flags - Control flags for power
+ * @pwrlevels - List of supported power levels
+ * @active_pwrlevel - The currently active power level
+ * @thermal_pwrlevel - maximum powerlevel constraint from thermal
+ * @max_pwrlevel - maximum allowable powerlevel per the user
+ * @min_pwrlevel - minimum allowable powerlevel per the user
+ * @num_pwrlevels - number of available power levels
+ * @interval_timeout - timeout in jiffies to be idle before a power event
+ * @strtstp_sleepwake - true if the device supports low latency GPU start/stop
+ * @gpu_reg - pointer to the regulator structure for gpu_reg
+ * @gpu_cx - pointer to the regulator structure for gpu_cx
+ * @pcl - bus scale identifier
+ * @nap_allowed - true if the device supports naps
+ * @idle_needed - true if the device needs a idle before clock change
+ * @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
+ */
+
struct kgsl_pwrctrl {
int interrupt_num;
struct clk *ebi1_clk;
@@ -47,6 +71,8 @@
unsigned int active_pwrlevel;
int thermal_pwrlevel;
unsigned int default_pwrlevel;
+ unsigned int max_pwrlevel;
+ unsigned int min_pwrlevel;
unsigned int num_pwrlevels;
unsigned int interval_timeout;
bool strtstp_sleepwake;
diff --git a/drivers/gpu/msm/kgsl_pwrscale.c b/drivers/gpu/msm/kgsl_pwrscale.c
index f6277b3..aad1a8d 100644
--- a/drivers/gpu/msm/kgsl_pwrscale.c
+++ b/drivers/gpu/msm/kgsl_pwrscale.c
@@ -299,8 +299,14 @@
{
if (device->pwrscale.policy != NULL) {
device->pwrscale.policy->close(device, &device->pwrscale);
+
+ /*
+ * Try to set max pwrlevel which will be limited to thermal by
+ * kgsl_pwrctrl_pwrlevel_change if thermal is indeed lower
+ */
+
kgsl_pwrctrl_pwrlevel_change(device,
- device->pwrctrl.thermal_pwrlevel);
+ device->pwrctrl.max_pwrlevel);
}
device->pwrscale.policy = NULL;
}
diff --git a/drivers/gpu/msm/kgsl_pwrscale_trustzone.c b/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
index 7c2514b..e01932b 100644
--- a/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
+++ b/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
@@ -93,7 +93,7 @@
priv->governor = TZ_GOVERNOR_PERFORMANCE;
if (priv->governor == TZ_GOVERNOR_PERFORMANCE)
- kgsl_pwrctrl_pwrlevel_change(device, pwr->thermal_pwrlevel);
+ kgsl_pwrctrl_pwrlevel_change(device, pwr->max_pwrlevel);
mutex_unlock(&device->mutex);
return count;
diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c
index be51c11..11ca0b0 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.c
+++ b/drivers/gpu/msm/kgsl_sharedmem.c
@@ -511,7 +511,14 @@
void kgsl_cache_range_op(struct kgsl_memdesc *memdesc, int op)
{
- void *addr = memdesc->hostptr;
+ /*
+ * If the buffer is mapped in the kernel operate on that address
+ * otherwise use the user address
+ */
+
+ void *addr = (memdesc->hostptr) ?
+ memdesc->hostptr : (void *) memdesc->useraddr;
+
int size = memdesc->size;
if (addr != NULL) {
@@ -534,7 +541,7 @@
static int
_kgsl_sharedmem_page_alloc(struct kgsl_memdesc *memdesc,
struct kgsl_pagetable *pagetable,
- size_t size, unsigned int protflags)
+ size_t size)
{
int pcount = 0, order, ret = 0;
int j, len, page_size, sglen_alloc, sglen = 0;
@@ -698,11 +705,6 @@
outer_cache_range_op_sg(memdesc->sg, memdesc->sglen,
KGSL_CACHE_OP_FLUSH);
- ret = kgsl_mmu_map(pagetable, memdesc, protflags);
-
- if (ret)
- goto done;
-
KGSL_STATS_ADD(size, kgsl_driver.stats.page_alloc,
kgsl_driver.stats.page_alloc_max);
@@ -729,8 +731,7 @@
size = ALIGN(size, PAGE_SIZE * 2);
- ret = _kgsl_sharedmem_page_alloc(memdesc, pagetable, size,
- GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
+ ret = _kgsl_sharedmem_page_alloc(memdesc, pagetable, size);
if (!ret)
ret = kgsl_page_alloc_map_kernel(memdesc);
if (ret)
@@ -744,17 +745,7 @@
struct kgsl_pagetable *pagetable,
size_t size)
{
- unsigned int protflags;
-
- if (size == 0)
- return -EINVAL;
-
- protflags = GSL_PT_PAGE_RV;
- if (!(memdesc->flags & KGSL_MEMFLAGS_GPUREADONLY))
- protflags |= GSL_PT_PAGE_WV;
-
- return _kgsl_sharedmem_page_alloc(memdesc, pagetable, size,
- protflags);
+ return _kgsl_sharedmem_page_alloc(memdesc, pagetable, PAGE_ALIGN(size));
}
EXPORT_SYMBOL(kgsl_sharedmem_page_alloc_user);
@@ -832,12 +823,6 @@
if (result)
goto err;
- result = kgsl_mmu_map(pagetable, memdesc,
- GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
-
- if (result)
- goto err;
-
KGSL_STATS_ADD(size, kgsl_driver.stats.coherent,
kgsl_driver.stats.coherent_max);
diff --git a/drivers/gpu/msm/kgsl_sharedmem.h b/drivers/gpu/msm/kgsl_sharedmem.h
index 53e88be..f07f049 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.h
+++ b/drivers/gpu/msm/kgsl_sharedmem.h
@@ -83,6 +83,18 @@
}
/*
+ * kgsl_memdesc_get_cachemode - Get cache mode of a memdesc
+ * @memdesc: the memdesc
+ *
+ * Returns a KGSL_CACHEMODE* value.
+ */
+static inline int
+kgsl_memdesc_get_cachemode(const struct kgsl_memdesc *memdesc)
+{
+ return (memdesc->flags & KGSL_CACHEMODE_MASK) >> KGSL_CACHEMODE_SHIFT;
+}
+
+/*
* kgsl_memdesc_set_align - Set alignment flags of a memdesc
* @memdesc - the memdesc
* @align - alignment requested, as a power of 2 exponent.
@@ -168,14 +180,38 @@
return (memdesc->priv & KGSL_MEMDESC_GLOBAL) != 0;
}
+/*
+ * kgsl_memdesc_protflags - get mmu protection flags
+ * @memdesc - the memdesc
+ * Returns a mask of GSL_PT_PAGE* values based on the
+ * memdesc flags.
+ */
+static inline unsigned int
+kgsl_memdesc_protflags(const struct kgsl_memdesc *memdesc)
+{
+ unsigned int protflags = GSL_PT_PAGE_RV;
+ if (!(memdesc->flags & KGSL_MEMFLAGS_GPUREADONLY))
+ protflags |= GSL_PT_PAGE_WV;
+ return protflags;
+}
+
static inline int
kgsl_allocate(struct kgsl_memdesc *memdesc,
struct kgsl_pagetable *pagetable, size_t size)
{
+ int ret;
+ memdesc->priv |= (KGSL_MEMTYPE_KERNEL << KGSL_MEMTYPE_SHIFT);
if (kgsl_mmu_get_mmutype() == KGSL_MMU_TYPE_NONE)
return kgsl_sharedmem_ebimem(memdesc, pagetable, size);
- memdesc->flags |= (KGSL_MEMTYPE_KERNEL << KGSL_MEMTYPE_SHIFT);
- return kgsl_sharedmem_page_alloc(memdesc, pagetable, size);
+
+ ret = kgsl_sharedmem_page_alloc(memdesc, pagetable, size);
+ if (ret)
+ return ret;
+ ret = kgsl_mmu_map(pagetable, memdesc,
+ kgsl_memdesc_protflags(memdesc));
+ if (ret)
+ kgsl_sharedmem_free(memdesc);
+ return ret;
}
static inline int
@@ -185,6 +221,9 @@
{
int ret;
+ if (size == 0)
+ return -EINVAL;
+
memdesc->flags = flags;
if (kgsl_mmu_get_mmutype() == KGSL_MMU_TYPE_NONE)
diff --git a/drivers/gpu/msm/kgsl_trace.h b/drivers/gpu/msm/kgsl_trace.h
index 0b247e5..7cc55f6 100644
--- a/drivers/gpu/msm/kgsl_trace.h
+++ b/drivers/gpu/msm/kgsl_trace.h
@@ -317,6 +317,8 @@
__field(unsigned int, size)
__field(unsigned int, tgid)
__array(char, usage, 16)
+ __field(unsigned int, id)
+ __field(unsigned int, flags)
),
TP_fast_assign(
@@ -325,12 +327,14 @@
__entry->tgid = mem_entry->priv->pid;
kgsl_get_memory_usage(__entry->usage, sizeof(__entry->usage),
mem_entry->memdesc.flags);
+ __entry->id = mem_entry->id;
+ __entry->flags = mem_entry->memdesc.flags;
),
TP_printk(
- "gpuaddr=0x%08x size=%d tgid=%d usage=%s",
+ "gpuaddr=0x%08x size=%d tgid=%d usage=%s id=%d flags=0x%08x",
__entry->gpuaddr, __entry->size, __entry->tgid,
- __entry->usage
+ __entry->usage, __entry->id, __entry->flags
)
);
@@ -347,6 +351,7 @@
__field(int, type)
__field(unsigned int, tgid)
__array(char, usage, 16)
+ __field(unsigned int, id)
),
TP_fast_assign(
@@ -357,13 +362,14 @@
__entry->tgid = mem_entry->priv->pid;
kgsl_get_memory_usage(__entry->usage, sizeof(__entry->usage),
mem_entry->memdesc.flags);
+ __entry->id = mem_entry->id;
),
TP_printk(
- "gpuaddr=0x%08x size=%d type=%d fd=%d tgid=%d usage %s",
+ "gpuaddr=0x%08x size=%d type=%d fd=%d tgid=%d usage=%s id=%d",
__entry->gpuaddr, __entry->size,
__entry->type, __entry->fd, __entry->tgid,
- __entry->usage
+ __entry->usage, __entry->id
)
);
@@ -380,6 +386,7 @@
__field(int, fd)
__field(unsigned int, tgid)
__array(char, usage, 16)
+ __field(unsigned int, id)
),
TP_fast_assign(
@@ -389,12 +396,13 @@
__entry->tgid = mem_entry->priv->pid;
kgsl_get_memory_usage(__entry->usage, sizeof(__entry->usage),
mem_entry->memdesc.flags);
+ __entry->id = mem_entry->id;
),
TP_printk(
- "gpuaddr=0x%08x size=%d type=%d tgid=%d usage=%s",
+ "gpuaddr=0x%08x size=%d type=%d tgid=%d usage=%s id=%d",
__entry->gpuaddr, __entry->size, __entry->type,
- __entry->tgid, __entry->usage
+ __entry->tgid, __entry->usage, __entry->id
)
);
@@ -411,6 +419,7 @@
__field(unsigned int, size)
__field(int, type)
__array(char, usage, 16)
+ __field(unsigned int, id)
__field(unsigned int, drawctxt_id)
__field(unsigned int, curr_ts)
__field(unsigned int, free_ts)
@@ -422,6 +431,7 @@
__entry->size = mem_entry->memdesc.size;
kgsl_get_memory_usage(__entry->usage, sizeof(__entry->usage),
mem_entry->memdesc.flags);
+ __entry->id = mem_entry->id;
__entry->drawctxt_id = id;
__entry->type = mem_entry->memtype;
__entry->curr_ts = curr_ts;
@@ -429,13 +439,14 @@
),
TP_printk(
- "d_name=%s gpuaddr=0x%08x size=%d type=%d usage=%s ctx=%u"
+ "d_name=%s gpuaddr=0x%08x size=%d type=%d usage=%s id=%d ctx=%u"
" curr_ts=0x%x free_ts=0x%x",
__get_str(device_name),
__entry->gpuaddr,
__entry->size,
__entry->type,
__entry->usage,
+ __entry->id,
__entry->drawctxt_id,
__entry->curr_ts,
__entry->free_ts
diff --git a/drivers/hwmon/qpnp-adc-common.c b/drivers/hwmon/qpnp-adc-common.c
index e319813..5fb041d 100644
--- a/drivers/hwmon/qpnp-adc-common.c
+++ b/drivers/hwmon/qpnp-adc-common.c
@@ -616,6 +616,63 @@
}
EXPORT_SYMBOL_GPL(qpnp_adc_scale_therm_pu2);
+int32_t qpnp_adc_tm_scale_voltage_therm_pu2(uint32_t reg, int64_t *result)
+{
+ int64_t adc_voltage = 0;
+ struct qpnp_vadc_linear_graph param1;
+ int negative_offset;
+
+ qpnp_get_vadc_gain_and_offset(¶m1, CALIB_RATIOMETRIC);
+
+ adc_voltage = (reg - param1.adc_gnd) * param1.adc_vref;
+ if (adc_voltage < 0) {
+ negative_offset = 1;
+ adc_voltage = -adc_voltage;
+ }
+
+ do_div(adc_voltage, param1.dy);
+
+ qpnp_adc_map_temp_voltage(adcmap_100k_104ef_104fb,
+ ARRAY_SIZE(adcmap_100k_104ef_104fb),
+ adc_voltage, result);
+ if (negative_offset)
+ adc_voltage = -adc_voltage;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(qpnp_adc_tm_scale_voltage_therm_pu2);
+
+int32_t qpnp_adc_tm_scale_therm_voltage_pu2(struct qpnp_adc_tm_config *param)
+{
+ struct qpnp_vadc_linear_graph param1;
+ int rc;
+
+ qpnp_get_vadc_gain_and_offset(¶m1, CALIB_RATIOMETRIC);
+
+ rc = qpnp_adc_map_voltage_temp(adcmap_100k_104ef_104fb,
+ ARRAY_SIZE(adcmap_100k_104ef_104fb),
+ param->low_thr_temp, ¶m->low_thr_voltage);
+ if (rc)
+ return rc;
+
+ param->low_thr_voltage *= param1.dy;
+ do_div(param->low_thr_voltage, param1.adc_vref);
+ param->low_thr_voltage += param1.adc_gnd;
+
+ rc = qpnp_adc_map_voltage_temp(adcmap_100k_104ef_104fb,
+ ARRAY_SIZE(adcmap_100k_104ef_104fb),
+ param->high_thr_temp, ¶m->high_thr_voltage);
+ if (rc)
+ return rc;
+
+ param->high_thr_voltage *= param1.dy;
+ do_div(param->high_thr_voltage, param1.adc_vref);
+ param->high_thr_voltage += param1.adc_gnd;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(qpnp_adc_tm_scale_therm_voltage_pu2);
+
int32_t qpnp_adc_scale_batt_id(int32_t adc_code,
const struct qpnp_adc_properties *adc_properties,
const struct qpnp_vadc_chan_properties *chan_properties,
@@ -689,6 +746,65 @@
}
EXPORT_SYMBOL_GPL(qpnp_adc_scale_default);
+int32_t qpnp_adc_usb_scaler(struct qpnp_adc_tm_usbid_param *param,
+ uint32_t *low_threshold, uint32_t *high_threshold)
+{
+ struct qpnp_vadc_linear_graph usb_param;
+
+ qpnp_get_vadc_gain_and_offset(&usb_param, CALIB_ABSOLUTE);
+
+ *low_threshold = param->low_thr * usb_param.dy;
+ do_div(*low_threshold, usb_param.adc_vref);
+ *low_threshold += usb_param.adc_gnd;
+
+ *high_threshold = param->high_thr * usb_param.dy;
+ do_div(*high_threshold, usb_param.adc_vref);
+ *high_threshold += usb_param.adc_gnd;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(qpnp_adc_usb_scaler);
+
+int32_t qpnp_adc_btm_scaler(struct qpnp_adc_tm_btm_param *param,
+ uint32_t *low_threshold, uint32_t *high_threshold)
+{
+ struct qpnp_vadc_linear_graph btm_param;
+ int64_t *low_output = 0, *high_output = 0;
+ int rc = 0;
+
+ qpnp_get_vadc_gain_and_offset(&btm_param, CALIB_RATIOMETRIC);
+
+ rc = qpnp_adc_map_temp_voltage(
+ adcmap_btm_threshold,
+ ARRAY_SIZE(adcmap_btm_threshold),
+ (param->low_temp),
+ low_output);
+ if (rc)
+ return rc;
+
+ *low_output *= btm_param.dy;
+ do_div(*low_output, btm_param.adc_vref);
+ *low_output += btm_param.adc_gnd;
+
+ rc = qpnp_adc_map_temp_voltage(
+ adcmap_btm_threshold,
+ ARRAY_SIZE(adcmap_btm_threshold),
+ (param->high_temp),
+ high_output);
+ if (rc)
+ return rc;
+
+ *high_output *= btm_param.dy;
+ do_div(*high_output, btm_param.adc_vref);
+ *high_output += btm_param.adc_gnd;
+
+ low_threshold = (uint32_t *) low_output;
+ high_threshold = (uint32_t *) high_output;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(qpnp_adc_btm_scaler);
+
int32_t qpnp_vadc_check_result(int32_t *data)
{
if (*data < QPNP_VADC_MIN_ADC_CODE)
@@ -731,7 +847,7 @@
return -ENOMEM;
}
adc_channel_list = devm_kzalloc(&spmi->dev,
- sizeof(struct qpnp_vadc_amux) * count_adc_channel_list,
+ ((sizeof(struct qpnp_vadc_amux)) * count_adc_channel_list),
GFP_KERNEL);
if (!adc_channel_list) {
dev_err(&spmi->dev, "Unable to allocate memory\n");
@@ -844,8 +960,9 @@
adc_qpnp->offset = res->start;
/* Register the ADC peripheral interrupt */
- adc_qpnp->adc_irq = spmi_get_irq(spmi, 0, 0);
- if (adc_qpnp->adc_irq < 0) {
+ adc_qpnp->adc_irq_eoc = spmi_get_irq_byname(spmi, NULL,
+ "eoc-int-en-set");
+ if (adc_qpnp->adc_irq_eoc < 0) {
pr_err("Invalid irq\n");
return -ENXIO;
}
diff --git a/drivers/hwmon/qpnp-adc-current.c b/drivers/hwmon/qpnp-adc-current.c
index 0e82cf7..b5ee104 100644
--- a/drivers/hwmon/qpnp-adc-current.c
+++ b/drivers/hwmon/qpnp-adc-current.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* 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
@@ -695,14 +695,14 @@
return -EINVAL;
}
- rc = devm_request_irq(&spmi->dev, iadc->adc->adc_irq,
+ rc = devm_request_irq(&spmi->dev, iadc->adc->adc_irq_eoc,
qpnp_iadc_isr,
IRQF_TRIGGER_RISING, "qpnp_iadc_interrupt", iadc);
if (rc) {
dev_err(&spmi->dev, "failed to request adc irq\n");
return rc;
} else
- enable_irq_wake(iadc->adc->adc_irq);
+ enable_irq_wake(iadc->adc->adc_irq_eoc);
iadc->iadc_init_calib = false;
dev_set_drvdata(&spmi->dev, iadc);
diff --git a/drivers/hwmon/qpnp-adc-voltage.c b/drivers/hwmon/qpnp-adc-voltage.c
index c59aa5b..b71c998 100644
--- a/drivers/hwmon/qpnp-adc-voltage.c
+++ b/drivers/hwmon/qpnp-adc-voltage.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* 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
@@ -509,6 +509,39 @@
return rc;
}
+int32_t qpnp_get_vadc_gain_and_offset(struct qpnp_vadc_linear_graph *param,
+ enum qpnp_adc_calib_type calib_type)
+{
+
+ struct qpnp_vadc_drv *vadc = qpnp_vadc;
+
+ switch (calib_type) {
+ case CALIB_RATIOMETRIC:
+ param->dy =
+ vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].dy;
+ param->dx =
+ vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].dx;
+ param->adc_vref = vadc->adc->adc_prop->adc_vdd_reference;
+ param->adc_gnd =
+ vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].adc_gnd;
+ break;
+ case CALIB_ABSOLUTE:
+ param->dy =
+ vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].dy;
+ param->dx =
+ vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].dx;
+ param->adc_vref = vadc->adc->adc_prop->adc_vdd_reference;
+ param->adc_gnd =
+ vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].adc_gnd;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(qpnp_get_vadc_gain_and_offset);
+
int32_t qpnp_vadc_is_ready(void)
{
struct qpnp_vadc_drv *vadc = qpnp_vadc;
@@ -743,7 +776,7 @@
return rc;
}
- rc = devm_request_irq(&spmi->dev, vadc->adc->adc_irq,
+ rc = devm_request_irq(&spmi->dev, vadc->adc->adc_irq_eoc,
qpnp_vadc_isr, IRQF_TRIGGER_RISING,
"qpnp_vadc_interrupt", vadc);
if (rc) {
@@ -751,7 +784,7 @@
"failed to request adc irq with error %d\n", rc);
return rc;
} else {
- enable_irq_wake(vadc->adc->adc_irq);
+ enable_irq_wake(vadc->adc->adc_irq_eoc);
}
qpnp_vadc = vadc;
diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index ec3429b..332138c 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -25,6 +25,17 @@
If unsure, say N here.
+# MSM IOMMU CPU-GPU sync programming support
+config MSM_IOMMU_GPU_SYNC
+ bool "MSM IOMMU CPU-GPU Sync Support"
+ depends on (ARCH_MSM8X60 || ARCH_MSM8960 || ARCH_APQ8064 || ARCH_MSM8930) && MSM_IOMMU && MSM_REMOTE_SPINLOCK_SFPB
+ help
+ Say Y here if you want to synchronize access to IOMMU configuration
+ port between CPU and GPU. CPU will grab a remote spinlock before
+ accessing IOMMU configuration registers and GPU will do the same.
+
+ 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/msm_iommu.c b/drivers/iommu/msm_iommu.c
index f8c9809..4c72df7 100644
--- a/drivers/iommu/msm_iommu.c
+++ b/drivers/iommu/msm_iommu.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
@@ -29,6 +29,7 @@
#include <mach/iommu_hw-8xxx.h>
#include <mach/iommu.h>
+#include <mach/msm_smsm.h>
#define MRC(reg, processor, op1, crn, crm, op2) \
__asm__ __volatile__ ( \
@@ -66,6 +67,69 @@
DEFINE_MUTEX(msm_iommu_lock);
+/**
+ * Remote spinlock implementation based on Peterson's algorithm to be used
+ * to synchronize IOMMU config port access between CPU and GPU.
+ * This implements Process 0 of the spin lock algorithm. GPU implements
+ * Process 1. Flag and turn is stored in shared memory to allow GPU to
+ * access these.
+ */
+struct msm_iommu_remote_lock {
+ int initialized;
+ struct remote_iommu_petersons_spinlock *lock;
+};
+
+static struct msm_iommu_remote_lock msm_iommu_remote_lock;
+
+#ifdef CONFIG_MSM_IOMMU_GPU_SYNC
+static void _msm_iommu_remote_spin_lock_init(void)
+{
+ msm_iommu_remote_lock.lock = smem_alloc(SMEM_SPINLOCK_ARRAY, 32);
+ memset(msm_iommu_remote_lock.lock, 0,
+ sizeof(*msm_iommu_remote_lock.lock));
+}
+
+void msm_iommu_remote_p0_spin_lock(void)
+{
+ msm_iommu_remote_lock.lock->flag[PROC_APPS] = 1;
+ msm_iommu_remote_lock.lock->turn = 1;
+
+ smp_mb();
+
+ while (msm_iommu_remote_lock.lock->flag[PROC_GPU] == 1 &&
+ msm_iommu_remote_lock.lock->turn == 1)
+ cpu_relax();
+}
+
+void msm_iommu_remote_p0_spin_unlock(void)
+{
+ smp_mb();
+
+ msm_iommu_remote_lock.lock->flag[PROC_APPS] = 0;
+}
+#endif
+
+inline void msm_iommu_mutex_lock(void)
+{
+ mutex_lock(&msm_iommu_lock);
+}
+
+inline void msm_iommu_mutex_unlock(void)
+{
+ mutex_unlock(&msm_iommu_lock);
+}
+
+void *msm_iommu_lock_initialize(void)
+{
+ mutex_lock(&msm_iommu_lock);
+ if (!msm_iommu_remote_lock.initialized) {
+ msm_iommu_remote_lock_init();
+ msm_iommu_remote_lock.initialized = 1;
+ }
+ mutex_unlock(&msm_iommu_lock);
+ return msm_iommu_remote_lock.lock;
+}
+
struct msm_priv {
unsigned long *pgtable;
int redirect;
@@ -116,12 +180,17 @@
if (ret)
goto fail;
+ msm_iommu_remote_spin_lock();
+
asid = GET_CONTEXTIDR_ASID(iommu_drvdata->base,
ctx_drvdata->num);
SET_TLBIVA(iommu_drvdata->base, ctx_drvdata->num,
asid | (va & TLBIVA_VA));
mb();
+
+ msm_iommu_remote_spin_unlock();
+
__disable_clocks(iommu_drvdata);
}
fail:
@@ -148,11 +217,16 @@
if (ret)
goto fail;
+ msm_iommu_remote_spin_lock();
+
asid = GET_CONTEXTIDR_ASID(iommu_drvdata->base,
ctx_drvdata->num);
SET_TLBIASID(iommu_drvdata->base, ctx_drvdata->num, asid);
mb();
+
+ msm_iommu_remote_spin_unlock();
+
__disable_clocks(iommu_drvdata);
}
fail:
@@ -189,6 +263,9 @@
{
unsigned int prrr, nmrr;
int i, j, found;
+
+ msm_iommu_remote_spin_lock();
+
__reset_context(base, ctx);
/* Set up HTW mode */
@@ -278,6 +355,8 @@
/* Enable the MMU */
SET_M(base, ctx, 1);
mb();
+
+ msm_iommu_remote_spin_unlock();
}
static int msm_iommu_domain_init(struct iommu_domain *domain, int flags)
@@ -417,10 +496,15 @@
if (ret)
goto fail;
+ msm_iommu_remote_spin_lock();
+
SET_TLBIASID(iommu_drvdata->base, ctx_dev->num,
GET_CONTEXTIDR_ASID(iommu_drvdata->base, ctx_dev->num));
__reset_context(iommu_drvdata->base, ctx_dev->num);
+
+ msm_iommu_remote_spin_unlock();
+
__disable_clocks(iommu_drvdata);
list_del_init(&ctx_drvdata->attached_elm);
ctx_drvdata->attached_domain = NULL;
@@ -1083,6 +1167,8 @@
if (ret)
goto fail;
+ msm_iommu_remote_spin_lock();
+
SET_V2PPR(base, ctx, va & V2Pxx_VA);
mb();
@@ -1097,6 +1183,8 @@
if (GET_FAULT(base, ctx))
ret = 0;
+ msm_iommu_remote_spin_unlock();
+
__disable_clocks(iommu_drvdata);
fail:
mutex_unlock(&msm_iommu_lock);
@@ -1157,6 +1245,8 @@
if (ret)
goto fail;
+ msm_iommu_remote_spin_lock();
+
fsr = GET_FSR(base, num);
if (fsr) {
@@ -1188,6 +1278,8 @@
} else
ret = IRQ_NONE;
+ msm_iommu_remote_spin_unlock();
+
__disable_clocks(drvdata);
fail:
mutex_unlock(&msm_iommu_lock);
@@ -1258,6 +1350,8 @@
if (!msm_soc_version_supports_iommu_v1())
return -ENODEV;
+ msm_iommu_lock_initialize();
+
setup_iommu_tex_classes();
bus_set_iommu(&platform_bus_type, &msm_iommu_ops);
return 0;
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
index 6d66d45..978cb38d 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -42,8 +42,6 @@
*/
// #define DVB_DEMUX_SECTION_LOSS_LOG
-#define TIMESTAMP_LEN 4
-
static int dvb_demux_tscheck;
module_param(dvb_demux_tscheck, int, 0644);
MODULE_PARM_DESC(dvb_demux_tscheck,
@@ -608,7 +606,7 @@
((f)->feed.ts.is_filtering) && \
(((f)->ts_type & (TS_PACKET | TS_DEMUX)) == TS_PACKET))
-static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf,
+void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf,
const u8 timestamp[TIMESTAMP_LEN])
{
struct dvb_demux_feed *feed;
@@ -688,6 +686,7 @@
dvb_dmx_swfilter_output_packet(feed, buf, timestamp);
}
}
+EXPORT_SYMBOL(dvb_dmx_swfilter_packet);
void dvb_dmx_swfilter_section_packets(struct dvb_demux *demux, const u8 *buf,
size_t count)
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.h b/drivers/media/dvb/dvb-core/dvb_demux.h
index 4e6dfaf..f89367b 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.h
+++ b/drivers/media/dvb/dvb-core/dvb_demux.h
@@ -47,6 +47,8 @@
#define MAX_PID 0x1fff
+#define TIMESTAMP_LEN 4
+
#define SPEED_PKTS_INTERVAL 50000
struct dvb_demux_filter {
@@ -189,6 +191,8 @@
struct dvb_demux *demux, const u8 *buf,
size_t count,
enum dmx_tsp_format_t tsp_format);
+void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf,
+ const u8 timestamp[TIMESTAMP_LEN]);
#endif /* _DVB_DEMUX_H_ */
diff --git a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.c b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.c
index 51d66cd..e2ef6a0 100644
--- a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.c
+++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.c
@@ -473,16 +473,23 @@
* when dvb-demux is terminated.
*/
mpq_demux->hw_notification_count = 0;
- mpq_demux->hw_notification_rate = 0;
+ mpq_demux->hw_notification_interval = 0;
mpq_demux->hw_notification_size = 0;
mpq_demux->decoder_tsp_drop_count = 0;
+ mpq_demux->hw_notification_min_size = 0xFFFFFFFF;
if (mpq_demux->demux.dmx.debugfs_demux_dir != NULL) {
debugfs_create_u32(
- "hw_notification_rate",
+ "hw_notification_interval",
S_IRUGO|S_IWUGO,
mpq_demux->demux.dmx.debugfs_demux_dir,
- &mpq_demux->hw_notification_rate);
+ &mpq_demux->hw_notification_interval);
+
+ debugfs_create_u32(
+ "hw_notification_min_interval",
+ S_IRUGO|S_IWUGO,
+ mpq_demux->demux.dmx.debugfs_demux_dir,
+ &mpq_demux->hw_notification_min_interval);
debugfs_create_u32(
"hw_notification_count",
@@ -497,6 +504,12 @@
&mpq_demux->hw_notification_size);
debugfs_create_u32(
+ "hw_notification_min_size",
+ S_IRUGO|S_IWUGO,
+ mpq_demux->demux.dmx.debugfs_demux_dir,
+ &mpq_demux->hw_notification_min_size);
+
+ debugfs_create_u32(
"decoder_tsp_drop_count",
S_IRUGO|S_IWUGO,
mpq_demux->demux.dmx.debugfs_demux_dir,
@@ -520,10 +533,17 @@
curr_time,
mpq_demux->last_notification_time);
- delta_time_ms = (u64)timespec_to_ns(&delta_time);
- delta_time_ms = div64_u64(delta_time_ms, 1000000); /* ns->ms */
+ delta_time_ms = ((u64)delta_time.tv_sec * MSEC_PER_SEC) +
+ delta_time.tv_nsec / NSEC_PER_MSEC;
- mpq_demux->hw_notification_rate = delta_time_ms;
+ mpq_demux->hw_notification_interval = delta_time_ms;
+
+ if ((mpq_demux->hw_notification_count == 1) ||
+ (mpq_demux->hw_notification_interval &&
+ mpq_demux->hw_notification_interval <
+ mpq_demux->hw_notification_min_interval))
+ mpq_demux->hw_notification_min_interval =
+ mpq_demux->hw_notification_interval;
}
mpq_demux->hw_notification_count++;
diff --git a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.h b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.h
index 3500eda..69305b6 100644
--- a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.h
+++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.h
@@ -30,7 +30,7 @@
/**
* TSIF alias name length
*/
-#define TSIF_NAME_LENGTH 10
+#define TSIF_NAME_LENGTH 20
#define MPQ_MAX_FOUND_PATTERNS 5
@@ -44,9 +44,14 @@
* initialized or not.
* @ion_client: ION demux client used to allocate memory from ION.
* @feed_lock: Lock used to protect against private feed data
- * @hw_notification_rate: Notification rate in msec, exposed in debugfs.
+ * @hw_notification_interval: Notification interval in msec,
+ * exposed in debugfs.
+ * @hw_notification_min_interval: Minimum notification internal in msec,
+ * exposed in debugfs.
* @hw_notification_count: Notification count, exposed in debugfs.
* @hw_notification_size: Notification size in bytes, exposed in debugfs.
+ * @hw_notification_min_size: Minimum notification size in bytes,
+ * exposed in debugfs.
* @decoder_tsp_drop_count: Counter of number of dropped TS packets
* due to decoder buffer fullness, exposed in debugfs.
* @last_notification_time: Time of last HW notification.
@@ -61,9 +66,11 @@
spinlock_t feed_lock;
/* debug-fs */
- u32 hw_notification_rate;
+ u32 hw_notification_interval;
+ u32 hw_notification_min_interval;
u32 hw_notification_count;
u32 hw_notification_size;
+ u32 hw_notification_min_size;
u32 decoder_tsp_drop_count;
struct timespec last_notification_time;
};
diff --git a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tsif.c b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tsif.c
index 2e783f6..bbf9d0a 100644
--- a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tsif.c
+++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tsif.c
@@ -13,7 +13,7 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/tsif_api.h>
-#include <linux/workqueue.h>
+#include <linux/kthread.h>
#include <linux/moduleparam.h>
#include "mpq_dvb_debug.h"
#include "mpq_dmx_plugin_common.h"
@@ -38,17 +38,8 @@
static int tsif_mode = DMX_TSIF_DRIVER_MODE_DEF;
static int clock_inv;
module_param(threshold, int, S_IRUGO);
-module_param(tsif_mode, int, S_IRUGO);
-module_param(clock_inv, int, S_IRUGO);
-
-/*
- * Work scheduled each time TSIF notifies dmx
- * of new TS packet
- */
-struct tsif_work {
- struct work_struct work;
- int tsif_id;
-};
+module_param(tsif_mode, int, S_IRUGO | S_IWUSR);
+module_param(clock_inv, int, S_IRUGO | S_IWUSR);
/*
@@ -78,11 +69,12 @@
{
/* Information for each TSIF input processing */
struct {
- /* work used to submit to workqueue for processing */
- struct tsif_work work;
+ /* thread processing TS packets from TSIF */
+ struct task_struct *thread;
+ wait_queue_head_t wait_queue;
- /* workqueue that processes TS packets from specific TSIF */
- struct workqueue_struct *workqueue;
+ /* Counter for data notifications from TSIF */
+ atomic_t data_cnt;
/* TSIF alias */
char name[TSIF_NAME_LENGTH];
@@ -103,94 +95,72 @@
/**
- * Worker function that processes the TS packets notified by the TSIF driver.
+ * Demux thread function handling data from specific TSIF.
*
- * @worker: the executed work
+ * @arg: TSIF number
*/
-static void mpq_dmx_tsif_work(struct work_struct *worker)
+static int mpq_dmx_tsif_thread(void *arg)
{
- struct tsif_work *tsif_work =
- container_of(worker, struct tsif_work, work);
struct mpq_demux *mpq_demux;
struct tsif_driver_info *tsif_driver;
size_t packets = 0;
- int tsif = tsif_work->tsif_id;
+ int tsif = (int)arg;
+ int ret;
- mpq_demux = mpq_dmx_tsif_info.tsif[tsif].mpq_demux;
- tsif_driver = &(mpq_dmx_tsif_info.tsif[tsif].tsif_driver);
+ do {
+ ret = wait_event_interruptible(
+ mpq_dmx_tsif_info.tsif[tsif].wait_queue,
+ (atomic_read(
+ &mpq_dmx_tsif_info.tsif[tsif].data_cnt) != 0) ||
+ kthread_should_stop());
- MPQ_DVB_DBG_PRINT(
- "%s executed, tsif = %d\n",
- __func__,
- tsif);
+ if ((ret < 0) || kthread_should_stop()) {
+ MPQ_DVB_DBG_PRINT("%s: exit\n", __func__);
+ break;
+ }
- if (mutex_lock_interruptible(&mpq_dmx_tsif_info.tsif[tsif].mutex))
- return;
+ if (mutex_lock_interruptible(
+ &mpq_dmx_tsif_info.tsif[tsif].mutex))
+ return -ERESTARTSYS;
- /* Check if driver handler is still valid */
- if (tsif_driver->tsif_handler == NULL) {
- mutex_unlock(&mpq_dmx_tsif_info.tsif[tsif].mutex);
- MPQ_DVB_ERR_PRINT("%s: tsif_driver->tsif_handler is NULL!\n",
+ tsif_driver = &(mpq_dmx_tsif_info.tsif[tsif].tsif_driver);
+ mpq_demux = mpq_dmx_tsif_info.tsif[tsif].mpq_demux;
+
+ /* Check if driver handler is still valid */
+ if (tsif_driver->tsif_handler == NULL) {
+ mutex_unlock(&mpq_dmx_tsif_info.tsif[tsif].mutex);
+ MPQ_DVB_DBG_PRINT(
+ "%s: tsif was detached\n",
__func__);
- return;
- }
+ continue;
+ }
- tsif_get_state(tsif_driver->tsif_handler, &(tsif_driver->ri),
- &(tsif_driver->wi), &(tsif_driver->state));
+ tsif_get_state(
+ tsif_driver->tsif_handler, &(tsif_driver->ri),
+ &(tsif_driver->wi), &(tsif_driver->state));
- if ((tsif_driver->wi == tsif_driver->ri) ||
- (tsif_driver->state == tsif_state_stopped) ||
- (tsif_driver->state == tsif_state_error)) {
+ if ((tsif_driver->wi == tsif_driver->ri) ||
+ (tsif_driver->state == tsif_state_stopped) ||
+ (tsif_driver->state == tsif_state_error)) {
- mpq_demux->hw_notification_size = 0;
+ mpq_demux->hw_notification_size = 0;
- mutex_unlock(&mpq_dmx_tsif_info.tsif[tsif].mutex);
+ mutex_unlock(&mpq_dmx_tsif_info.tsif[tsif].mutex);
- MPQ_DVB_ERR_PRINT(
- "%s: invalid TSIF state (%d), wi = (%d), ri = (%d)\n",
- __func__,
- tsif_driver->state, tsif_driver->wi, tsif_driver->ri);
- return;
- }
+ MPQ_DVB_DBG_PRINT(
+ "%s: TSIF invalid state %d, %d, %d\n",
+ __func__,
+ tsif_driver->state,
+ tsif_driver->wi,
+ tsif_driver->ri);
+ continue;
+ }
- if (tsif_driver->wi > tsif_driver->ri) {
- packets = (tsif_driver->wi - tsif_driver->ri);
- mpq_demux->hw_notification_size = packets;
+ atomic_dec(&mpq_dmx_tsif_info.tsif[tsif].data_cnt);
- dvb_dmx_swfilter_format(
- &mpq_demux->demux,
- (tsif_driver->data_buffer +
- (tsif_driver->ri * TSIF_PKT_SIZE)),
- (packets * TSIF_PKT_SIZE),
- DMX_TSP_FORMAT_192_TAIL);
-
- tsif_driver->ri =
- (tsif_driver->ri + packets) % tsif_driver->buffer_size;
-
- tsif_reclaim_packets(tsif_driver->tsif_handler,
- tsif_driver->ri);
- } else {
- /*
- * wi < ri, means wraparound on cyclic buffer.
- * Handle in two stages.
- */
- packets = (tsif_driver->buffer_size - tsif_driver->ri);
- mpq_demux->hw_notification_size = packets;
-
- dvb_dmx_swfilter_format(
- &mpq_demux->demux,
- (tsif_driver->data_buffer +
- (tsif_driver->ri * TSIF_PKT_SIZE)),
- (packets * TSIF_PKT_SIZE),
- DMX_TSP_FORMAT_192_TAIL);
-
- /* tsif_driver->ri should be 0 after this */
- tsif_driver->ri =
- (tsif_driver->ri + packets) % tsif_driver->buffer_size;
-
- packets = tsif_driver->wi;
- if (packets > 0) {
- mpq_demux->hw_notification_size += packets;
+ if (tsif_driver->wi > tsif_driver->ri) {
+ packets = (tsif_driver->wi - tsif_driver->ri);
+ mpq_demux->hw_notification_size = packets;
dvb_dmx_swfilter_format(
&mpq_demux->demux,
@@ -202,13 +172,55 @@
tsif_driver->ri =
(tsif_driver->ri + packets) %
tsif_driver->buffer_size;
+
+ tsif_reclaim_packets(
+ tsif_driver->tsif_handler,
+ tsif_driver->ri);
+ } else {
+ /*
+ * wi < ri, means wraparound on cyclic buffer.
+ * Handle in two stages.
+ */
+ packets = (tsif_driver->buffer_size - tsif_driver->ri);
+ mpq_demux->hw_notification_size = packets;
+
+ dvb_dmx_swfilter_format(
+ &mpq_demux->demux,
+ (tsif_driver->data_buffer +
+ (tsif_driver->ri * TSIF_PKT_SIZE)),
+ (packets * TSIF_PKT_SIZE),
+ DMX_TSP_FORMAT_192_TAIL);
+
+ /* tsif_driver->ri should be 0 after this */
+ tsif_driver->ri =
+ (tsif_driver->ri + packets) %
+ tsif_driver->buffer_size;
+
+ packets = tsif_driver->wi;
+ if (packets > 0) {
+ mpq_demux->hw_notification_size += packets;
+
+ dvb_dmx_swfilter_format(
+ &mpq_demux->demux,
+ (tsif_driver->data_buffer +
+ (tsif_driver->ri * TSIF_PKT_SIZE)),
+ (packets * TSIF_PKT_SIZE),
+ DMX_TSP_FORMAT_192_TAIL);
+
+ tsif_driver->ri =
+ (tsif_driver->ri + packets) %
+ tsif_driver->buffer_size;
+ }
+
+ tsif_reclaim_packets(
+ tsif_driver->tsif_handler,
+ tsif_driver->ri);
}
- tsif_reclaim_packets(tsif_driver->tsif_handler,
- tsif_driver->ri);
- }
+ mutex_unlock(&mpq_dmx_tsif_info.tsif[tsif].mutex);
+ } while (1);
- mutex_unlock(&mpq_dmx_tsif_info.tsif[tsif].mutex);
+ return 0;
}
@@ -220,7 +232,6 @@
static void mpq_tsif_callback(void *user)
{
int tsif = (int)user;
- struct work_struct *work;
struct mpq_demux *mpq_demux;
MPQ_DVB_DBG_PRINT("%s executed, tsif = %d\n", __func__, tsif);
@@ -229,11 +240,8 @@
mpq_demux = mpq_dmx_tsif_info.tsif[tsif].mpq_demux;
mpq_dmx_update_hw_statistics(mpq_demux);
- work = &mpq_dmx_tsif_info.tsif[tsif].work.work;
-
- /* Scheudle a new work to demux workqueue */
- if (!work_pending(work))
- queue_work(mpq_dmx_tsif_info.tsif[tsif].workqueue, work);
+ atomic_inc(&mpq_dmx_tsif_info.tsif[tsif].data_cnt);
+ wake_up(&mpq_dmx_tsif_info.tsif[tsif].wait_queue);
}
@@ -376,20 +384,10 @@
tsif_driver = &(mpq_dmx_tsif_info.tsif[tsif].tsif_driver);
tsif_stop(tsif_driver->tsif_handler);
tsif_detach(tsif_driver->tsif_handler);
- /*
- * temporarily release mutex and flush the work queue
- * before setting tsif_handler to NULL
- */
- mutex_unlock(&mpq_dmx_tsif_info.tsif[tsif].mutex);
- flush_workqueue(mpq_dmx_tsif_info.tsif[tsif].workqueue);
- /* re-acquire mutex */
- if (mutex_lock_interruptible(
- &mpq_dmx_tsif_info.tsif[tsif].mutex))
- return -ERESTARTSYS;
-
tsif_driver->tsif_handler = NULL;
tsif_driver->data_buffer = NULL;
tsif_driver->buffer_size = 0;
+ atomic_set(&mpq_dmx_tsif_info.tsif[tsif].data_cnt, 0);
mpq_dmx_tsif_info.tsif[tsif].mpq_demux = NULL;
}
@@ -708,31 +706,28 @@
}
for (i = 0; i < TSIF_COUNT; i++) {
- mpq_dmx_tsif_info.tsif[i].work.tsif_id = i;
-
- INIT_WORK(&mpq_dmx_tsif_info.tsif[i].work.work,
- mpq_dmx_tsif_work);
-
snprintf(mpq_dmx_tsif_info.tsif[i].name,
TSIF_NAME_LENGTH,
- "tsif_%d",
+ "dmx_tsif%d",
i);
- mpq_dmx_tsif_info.tsif[i].workqueue =
- create_singlethread_workqueue(
+ atomic_set(&mpq_dmx_tsif_info.tsif[i].data_cnt, 0);
+ init_waitqueue_head(&mpq_dmx_tsif_info.tsif[i].wait_queue);
+ mpq_dmx_tsif_info.tsif[i].thread =
+ kthread_run(
+ mpq_dmx_tsif_thread, (void *)i,
mpq_dmx_tsif_info.tsif[i].name);
- if (mpq_dmx_tsif_info.tsif[i].workqueue == NULL) {
+ if (IS_ERR(mpq_dmx_tsif_info.tsif[i].thread)) {
int j;
for (j = 0; j < i; j++) {
- destroy_workqueue(
- mpq_dmx_tsif_info.tsif[j].workqueue);
+ kthread_stop(mpq_dmx_tsif_info.tsif[j].thread);
mutex_destroy(&mpq_dmx_tsif_info.tsif[j].mutex);
}
MPQ_DVB_ERR_PRINT(
- "%s: create_singlethread_workqueue failed\n",
+ "%s: kthread_run failed\n",
__func__);
return -ENOMEM;
@@ -753,7 +748,7 @@
ret);
for (i = 0; i < TSIF_COUNT; i++) {
- destroy_workqueue(mpq_dmx_tsif_info.tsif[i].workqueue);
+ kthread_stop(mpq_dmx_tsif_info.tsif[i].thread);
mutex_destroy(&mpq_dmx_tsif_info.tsif[i].mutex);
}
}
@@ -781,16 +776,13 @@
if (tsif_driver->tsif_handler)
tsif_stop(tsif_driver->tsif_handler);
}
+
/* Detach from TSIF driver to avoid further notifications. */
if (tsif_driver->tsif_handler)
tsif_detach(tsif_driver->tsif_handler);
- /* release mutex to allow work queue to finish scheduled work */
mutex_unlock(&mpq_dmx_tsif_info.tsif[i].mutex);
- /* flush the work queue and destroy it */
- flush_workqueue(mpq_dmx_tsif_info.tsif[i].workqueue);
- destroy_workqueue(mpq_dmx_tsif_info.tsif[i].workqueue);
-
+ kthread_stop(mpq_dmx_tsif_info.tsif[i].thread);
mutex_destroy(&mpq_dmx_tsif_info.tsif[i].mutex);
}
diff --git a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v1.c b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v1.c
index 360d96a..ac03e43 100644
--- a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v1.c
+++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v1.c
@@ -12,12 +12,11 @@
#include <linux/init.h>
#include <linux/module.h>
-#include <linux/workqueue.h>
+#include <linux/kthread.h>
#include <mach/msm_tspp.h>
#include "mpq_dvb_debug.h"
#include "mpq_dmx_plugin_common.h"
-
#define TSIF_COUNT 2
#define TSPP_MAX_PID_FILTER_NUM 16
@@ -28,6 +27,7 @@
/* For each TSIF we allocate two pipes, one for PES and one for sections */
#define TSPP_PES_CHANNEL 0
#define TSPP_SECTION_CHANNEL 1
+#define TSPP_CHANNEL_COUNT 2
/* the channel_id set to TSPP driver based on TSIF number and channel type */
#define TSPP_CHANNEL_ID(tsif, ch) ((tsif << 1) + ch)
@@ -35,45 +35,36 @@
#define TSPP_GET_TSIF_NUM(ch_id) (ch_id >> 1)
/* mask that set to care for all bits in pid filter */
-#define TSPP_PID_MASK 0x1FFF
+#define TSPP_PID_MASK 0x1FFF
/* dvb-demux defines pid 0x2000 as full capture pid */
-#define TSPP_PASS_THROUGH_PID 0x2000
+#define TSPP_PASS_THROUGH_PID 0x2000
-/* TODO - NEED TO SET THESE PROPERLY
- * once TSPP driver is ready, reduce TSPP_BUFFER_SIZE
- * to single packet and set TSPP_BUFFER_COUNT accordingly
- */
+#define TSPP_RAW_TTS_SIZE 192
+#define TSPP_RAW_SIZE 188
-#define TSPP_RAW_TTS_SIZE 192
+#define MAX_BAM_DESCRIPTOR_SIZE (32*1024 - 1)
-#define MAX_BAM_DESCRIPTOR_SIZE (32*1024 - 1)
+#define TSPP_BUFFER_SIZE (500 * 1024) /* 500KB */
-/* Size of single descriptor for PES/rec pipe.
+#define TSPP_PES_BUFFER_SIZE (TSPP_RAW_TTS_SIZE)
+
+#define TSPP_SECTION_BUFFER_SIZE (TSPP_RAW_TTS_SIZE)
+
+#define TSPP_BUFFER_COUNT(buffer_size) \
+ ((buffer_size) / TSPP_RAW_TTS_SIZE)
+
+/* When TSPP notifies demux that new packets are received.
* Using max descriptor size (170 packets).
* Assuming 20MBit/sec stream, with 170 packets
* per descriptor there would be about 82 descriptors,
* Meanning about 82 notifications per second.
*/
-#define TSPP_PES_BUFFER_SIZE \
- ((MAX_BAM_DESCRIPTOR_SIZE / TSPP_RAW_TTS_SIZE) * TSPP_RAW_TTS_SIZE)
-
-/* Size of single descriptor for section pipe.
- * Assuming 8MBit/sec section rate, with 65 packets
- * per descriptor there would be about 85 descriptors,
- * Meanning about 85 notifications per second.
- */
-#define TSPP_SECTION_BUFFER_SIZE \
- (65 * TSPP_RAW_TTS_SIZE)
-
-/* Number of descriptors, total size: TSPP_BUFFER_SIZE*TSPP_BUFFER_COUNT */
-#define TSPP_BUFFER_COUNT (32)
-
-/* When TSPP notifies demux that new packets are received */
-#define TSPP_NOTIFICATION_SIZE 1
+#define TSPP_NOTIFICATION_SIZE(desc_size) \
+ (MAX_BAM_DESCRIPTOR_SIZE / (desc_size))
/* Channel timeout in msec */
-#define TSPP_CHANNEL_TIMEOUT 16
+#define TSPP_CHANNEL_TIMEOUT 100
enum mem_buffer_allocation_mode {
MPQ_DMX_TSPP_INTERNAL_ALLOC = 0,
@@ -84,18 +75,17 @@
static int clock_inv;
static int tsif_mode = 2;
static int allocation_mode = MPQ_DMX_TSPP_INTERNAL_ALLOC;
-module_param(tsif_mode, int, S_IRUGO);
-module_param(clock_inv, int, S_IRUGO);
-module_param(allocation_mode, int, S_IRUGO);
+static int tspp_out_buffer_size = TSPP_BUFFER_SIZE;
+static int tspp_notification_size = TSPP_NOTIFICATION_SIZE(TSPP_RAW_TTS_SIZE);
+static int tspp_channel_timeout = TSPP_CHANNEL_TIMEOUT;
-/*
- * Work scheduled each time TSPP notifies dmx
- * of new TS packet in some channel
- */
-struct tspp_work {
- struct work_struct work;
- int channel_id;
-};
+module_param(tsif_mode, int, S_IRUGO | S_IWUSR);
+module_param(clock_inv, int, S_IRUGO | S_IWUSR);
+module_param(allocation_mode, int, S_IRUGO);
+module_param(tspp_out_buffer_size, int, S_IRUGO);
+module_param(tspp_notification_size, int, S_IRUGO | S_IWUSR);
+module_param(tspp_channel_timeout, int, S_IRUGO | S_IWUSR);
+
/* The following structure hold singelton information
* required for dmx implementation on top of TSPP.
@@ -111,8 +101,8 @@
*/
int pes_channel_ref;
- /* work used to submit to workqueue to process pes channel */
- struct tspp_work pes_work;
+ /* Counter for data notifications on PES pipe */
+ atomic_t pes_data_cnt;
/* ION handle used for TSPP data buffer allocation */
struct ion_handle *pes_mem_heap_handle;
@@ -130,8 +120,8 @@
*/
int section_channel_ref;
- /* work used to submit to workqueue to process pes channel */
- struct tspp_work section_work;
+ /* Counter for data notifications on section pipe */
+ atomic_t section_data_cnt;
/* ION handle used for TSPP data buffer allocation */
struct ion_handle *section_mem_heap_handle;
@@ -142,6 +132,8 @@
/* buffer allocation index */
int section_index;
+ u32 buffer_count;
+
/*
* Holds PIDs of allocated TSPP filters along with
* how many feeds are opened on same PID.
@@ -151,8 +143,9 @@
int ref_count;
} filters[TSPP_MAX_PID_FILTER_NUM];
- /* workqueue that processes TS packets from specific TSIF */
- struct workqueue_struct *workqueue;
+ /* thread processing TS packets from TSPP */
+ struct task_struct *thread;
+ wait_queue_head_t wait_queue;
/* TSIF alias */
char name[TSIF_NAME_LENGTH];
@@ -175,7 +168,8 @@
int i = TSPP_GET_TSIF_NUM(channel_id);
if (TSPP_IS_PES_CHANNEL(channel_id)) {
- if (mpq_dmx_tspp_info.tsif[i].pes_index == TSPP_BUFFER_COUNT)
+ if (mpq_dmx_tspp_info.tsif[i].pes_index ==
+ mpq_dmx_tspp_info.tsif[i].buffer_count)
return NULL;
virt_addr =
(mpq_dmx_tspp_info.tsif[i].pes_mem_heap_virt_base +
@@ -186,7 +180,7 @@
mpq_dmx_tspp_info.tsif[i].pes_index++;
} else {
if (mpq_dmx_tspp_info.tsif[i].section_index ==
- TSPP_BUFFER_COUNT)
+ mpq_dmx_tspp_info.tsif[i].buffer_count)
return NULL;
virt_addr =
(mpq_dmx_tspp_info.tsif[i].section_mem_heap_virt_base +
@@ -274,55 +268,105 @@
}
/**
- * Worker function that processes the TS packets notified by TSPP.
+ * Demux thread function handling data from specific TSIF.
*
- * @worker: the executed work
+ * @arg: TSIF number
*/
-static void mpq_dmx_tspp_work(struct work_struct *worker)
+static int mpq_dmx_tspp_thread(void *arg)
{
- struct tspp_work *tspp_work =
- container_of(worker, struct tspp_work, work);
+ int tsif = (int)arg;
struct mpq_demux *mpq_demux;
- int channel_id = tspp_work->channel_id;
- int tsif = TSPP_GET_TSIF_NUM(channel_id);
const struct tspp_data_descriptor *tspp_data_desc;
+ atomic_t *data_cnt;
+ u32 notif_size;
int ref_count;
+ int ret;
+ int i;
+ int j;
- mpq_demux = mpq_dmx_tspp_info.tsif[tsif].mpq_demux;
+ do {
+ ret = wait_event_interruptible(
+ mpq_dmx_tspp_info.tsif[tsif].wait_queue,
+ (atomic_read(
+ &mpq_dmx_tspp_info.tsif[tsif].pes_data_cnt)) ||
+ (atomic_read(
+ &mpq_dmx_tspp_info.tsif[tsif].section_data_cnt)) ||
+ kthread_should_stop());
- /* Lock against the TSPP filters data-structure */
- if (mutex_lock_interruptible(&mpq_dmx_tspp_info.tsif[tsif].mutex))
- return;
+ if ((ret < 0) || kthread_should_stop()) {
+ MPQ_DVB_ERR_PRINT("%s: exit\n", __func__);
+ break;
+ }
- /* Make sure channel is still active */
- if (TSPP_IS_PES_CHANNEL(channel_id))
- ref_count = mpq_dmx_tspp_info.tsif[tsif].pes_channel_ref;
- else
- ref_count = mpq_dmx_tspp_info.tsif[tsif].section_channel_ref;
+ /* Lock against the TSPP filters data-structure */
+ if (mutex_lock_interruptible(
+ &mpq_dmx_tspp_info.tsif[tsif].mutex))
+ return -ERESTARTSYS;
- if (ref_count == 0) {
+ for (i = 0; i < TSPP_CHANNEL_COUNT; i++) {
+ int channel_id = TSPP_CHANNEL_ID(tsif, i);
+
+ if (TSPP_IS_PES_CHANNEL(channel_id)) {
+ ref_count =
+ mpq_dmx_tspp_info.tsif[tsif].pes_channel_ref;
+ data_cnt =
+ &mpq_dmx_tspp_info.tsif[tsif].pes_data_cnt;
+ } else {
+ ref_count =
+ mpq_dmx_tspp_info.tsif[tsif].
+ section_channel_ref;
+ data_cnt =
+ &mpq_dmx_tspp_info.tsif[tsif].section_data_cnt;
+ }
+
+ /* Make sure channel is still active */
+ if (ref_count == 0)
+ continue;
+
+ atomic_dec(data_cnt);
+
+ mpq_demux = mpq_dmx_tspp_info.tsif[tsif].mpq_demux;
+ mpq_demux->hw_notification_size = 0;
+
+ /*
+ * Go through all filled descriptors
+ * and perform demuxing on them
+ */
+ while ((tspp_data_desc =
+ tspp_get_buffer(0, channel_id)) != NULL) {
+ notif_size =
+ tspp_data_desc->size /
+ TSPP_RAW_TTS_SIZE;
+
+ mpq_demux->hw_notification_size +=
+ notif_size;
+
+ for (j = 0; j < notif_size; j++)
+ dvb_dmx_swfilter_packet(
+ &mpq_demux->demux,
+ ((u8 *)tspp_data_desc->virt_base) +
+ j * TSPP_RAW_TTS_SIZE,
+ ((u8 *)tspp_data_desc->virt_base) +
+ j * TSPP_RAW_TTS_SIZE + TSPP_RAW_SIZE);
+ /*
+ * Notify TSPP that the buffer
+ * is no longer needed
+ */
+ tspp_release_buffer(0,
+ channel_id, tspp_data_desc->id);
+ }
+
+ if (mpq_demux->hw_notification_size &&
+ (mpq_demux->hw_notification_size <
+ mpq_demux->hw_notification_min_size))
+ mpq_demux->hw_notification_min_size =
+ mpq_demux->hw_notification_size;
+ }
+
mutex_unlock(&mpq_dmx_tspp_info.tsif[tsif].mutex);
- return;
- }
+ } while (1);
- mpq_demux->hw_notification_size = 0;
-
- /* Go through all filled descriptors and perform demuxing on them */
- while ((tspp_data_desc = tspp_get_buffer(0, channel_id)) != NULL) {
- mpq_demux->hw_notification_size +=
- (tspp_data_desc->size / TSPP_RAW_TTS_SIZE);
-
- dvb_dmx_swfilter_format(
- &mpq_demux->demux,
- tspp_data_desc->virt_base,
- tspp_data_desc->size,
- DMX_TSP_FORMAT_192_TAIL);
-
- /* Notify TSPP that the buffer is no longer needed */
- tspp_release_buffer(0, channel_id, tspp_data_desc->id);
- }
-
- mutex_unlock(&mpq_dmx_tspp_info.tsif[tsif].mutex);
+ return 0;
}
/**
@@ -334,7 +378,6 @@
static void mpq_tspp_callback(int channel_id, void *user)
{
int tsif = (int)user;
- struct work_struct *work;
struct mpq_demux *mpq_demux;
/* Save statistics on TSPP notifications */
@@ -342,13 +385,11 @@
mpq_dmx_update_hw_statistics(mpq_demux);
if (TSPP_IS_PES_CHANNEL(channel_id))
- work = &mpq_dmx_tspp_info.tsif[tsif].pes_work.work;
+ atomic_inc(&mpq_dmx_tspp_info.tsif[tsif].pes_data_cnt);
else
- work = &mpq_dmx_tspp_info.tsif[tsif].section_work.work;
+ atomic_inc(&mpq_dmx_tspp_info.tsif[tsif].section_data_cnt);
- /* Scheudle a new work to demux workqueue */
- if (!work_pending(work))
- queue_work(mpq_dmx_tspp_info.tsif[tsif].workqueue, work);
+ wake_up(&mpq_dmx_tspp_info.tsif[tsif].wait_queue);
}
/**
@@ -438,7 +479,6 @@
/* check if required TSPP pipe is already allocated or not */
if (*channel_ref_count == 0) {
ret = tspp_open_channel(0, channel_id);
-
if (ret < 0) {
MPQ_DVB_ERR_PRINT(
"%s: tspp_open_channel(%d) failed (%d)\n",
@@ -467,7 +507,7 @@
channel_id,
mpq_tspp_callback,
(void *)tsif,
- TSPP_CHANNEL_TIMEOUT);
+ tspp_channel_timeout);
/* register allocater and provide allocation function
* that allocates from continous memory so that we can have
@@ -479,23 +519,15 @@
* allocate TSPP data buffers
*/
if (allocation_mode == MPQ_DMX_TSPP_CONTIGUOUS_PHYS_ALLOC) {
- ret = tspp_allocate_buffers(0,
- channel_id,
- TSPP_BUFFER_COUNT,
- buffer_size,
- TSPP_NOTIFICATION_SIZE,
- tspp_mem_allocator,
- tspp_mem_free,
- NULL);
+ ret = tspp_allocate_buffers(0, channel_id,
+ mpq_dmx_tspp_info.tsif[tsif].buffer_count,
+ buffer_size, tspp_notification_size,
+ tspp_mem_allocator, tspp_mem_free, NULL);
} else {
- ret = tspp_allocate_buffers(0,
- channel_id,
- TSPP_BUFFER_COUNT,
- buffer_size,
- TSPP_NOTIFICATION_SIZE,
- NULL,
- NULL,
- NULL);
+ ret = tspp_allocate_buffers(0, channel_id,
+ mpq_dmx_tspp_info.tsif[tsif].buffer_count,
+ buffer_size, tspp_notification_size,
+ NULL, NULL, NULL);
}
if (ret < 0) {
MPQ_DVB_ERR_PRINT(
@@ -586,6 +618,7 @@
int tsif;
int ret;
int channel_id;
+ atomic_t *data_cnt;
int *channel_ref_count;
struct tspp_filter tspp_filter;
struct mpq_demux *mpq_demux = feed->demux->priv;
@@ -613,10 +646,12 @@
channel_id = TSPP_CHANNEL_ID(tsif, TSPP_PES_CHANNEL);
channel_ref_count =
&mpq_dmx_tspp_info.tsif[tsif].pes_channel_ref;
+ data_cnt = &mpq_dmx_tspp_info.tsif[tsif].pes_data_cnt;
} else {
channel_id = TSPP_CHANNEL_ID(tsif, TSPP_SECTION_CHANNEL);
channel_ref_count =
&mpq_dmx_tspp_info.tsif[tsif].section_channel_ref;
+ data_cnt = &mpq_dmx_tspp_info.tsif[tsif].section_data_cnt;
}
/* check if required TSPP pipe is already allocated or not */
@@ -677,6 +712,7 @@
tspp_unregister_notification(0, channel_id);
tspp_close_channel(0, channel_id);
tspp_close_stream(0, channel_id);
+ atomic_set(data_cnt, 0);
}
mutex_unlock(&mpq_dmx_tspp_info.tsif[tsif].mutex);
@@ -735,7 +771,7 @@
ret = mpq_dmx_init_video_feed(feed);
if (ret < 0) {
- MPQ_DVB_DBG_PRINT(
+ MPQ_DVB_ERR_PRINT(
"%s: mpq_dmx_init_video_feed failed(%d)\n",
__func__,
ret);
@@ -917,11 +953,11 @@
for (i = 0; i < TSIF_COUNT; i++) {
mpq_dmx_tspp_info.tsif[i].pes_mem_heap_handle =
ion_alloc(mpq_dmx_tspp_info.ion_client,
- (TSPP_BUFFER_COUNT *
- TSPP_PES_BUFFER_SIZE),
- TSPP_RAW_TTS_SIZE,
- ION_HEAP(ION_CP_MM_HEAP_ID),
- 0); /* non-cached */
+ (mpq_dmx_tspp_info.tsif[i].buffer_count *
+ TSPP_PES_BUFFER_SIZE),
+ TSPP_RAW_TTS_SIZE,
+ ION_HEAP(ION_CP_MM_HEAP_ID),
+ 0); /* non-cached */
if (IS_ERR_OR_NULL(mpq_dmx_tspp_info.tsif[i].
pes_mem_heap_handle)) {
MPQ_DVB_ERR_PRINT("%s: ion_alloc() failed\n",
@@ -956,11 +992,11 @@
mpq_dmx_tspp_info.tsif[i].section_mem_heap_handle =
ion_alloc(mpq_dmx_tspp_info.ion_client,
- (TSPP_BUFFER_COUNT *
- TSPP_SECTION_BUFFER_SIZE),
- TSPP_RAW_TTS_SIZE,
- ION_HEAP(ION_CP_MM_HEAP_ID),
- 0); /* non-cached */
+ (mpq_dmx_tspp_info.tsif[i].buffer_count *
+ TSPP_SECTION_BUFFER_SIZE),
+ TSPP_RAW_TTS_SIZE,
+ ION_HEAP(ION_CP_MM_HEAP_ID),
+ 0); /* non-cached */
if (IS_ERR_OR_NULL(mpq_dmx_tspp_info.tsif[i].
section_mem_heap_handle)) {
MPQ_DVB_ERR_PRINT("%s: ion_alloc() failed\n",
@@ -1074,29 +1110,22 @@
MPQ_DVB_DBG_PRINT("%s executed\n", __func__);
for (i = 0; i < TSIF_COUNT; i++) {
+ mpq_dmx_tspp_info.tsif[i].buffer_count =
+ TSPP_BUFFER_COUNT(tspp_out_buffer_size);
+
mpq_dmx_tspp_info.tsif[i].pes_channel_ref = 0;
mpq_dmx_tspp_info.tsif[i].pes_index = 0;
mpq_dmx_tspp_info.tsif[i].pes_mem_heap_handle = NULL;
mpq_dmx_tspp_info.tsif[i].pes_mem_heap_virt_base = NULL;
mpq_dmx_tspp_info.tsif[i].pes_mem_heap_phys_base = 0;
-
- mpq_dmx_tspp_info.tsif[i].pes_work.channel_id =
- TSPP_CHANNEL_ID(i, TSPP_PES_CHANNEL);
-
- INIT_WORK(&mpq_dmx_tspp_info.tsif[i].pes_work.work,
- mpq_dmx_tspp_work);
+ atomic_set(&mpq_dmx_tspp_info.tsif[i].pes_data_cnt, 0);
mpq_dmx_tspp_info.tsif[i].section_channel_ref = 0;
mpq_dmx_tspp_info.tsif[i].section_index = 0;
mpq_dmx_tspp_info.tsif[i].section_mem_heap_handle = NULL;
mpq_dmx_tspp_info.tsif[i].section_mem_heap_virt_base = NULL;
mpq_dmx_tspp_info.tsif[i].section_mem_heap_phys_base = 0;
-
- mpq_dmx_tspp_info.tsif[i].section_work.channel_id =
- TSPP_CHANNEL_ID(i, TSPP_SECTION_CHANNEL);
-
- INIT_WORK(&mpq_dmx_tspp_info.tsif[i].section_work.work,
- mpq_dmx_tspp_work);
+ atomic_set(&mpq_dmx_tspp_info.tsif[i].section_data_cnt, 0);
for (j = 0; j < TSPP_MAX_PID_FILTER_NUM; j++) {
mpq_dmx_tspp_info.tsif[i].filters[j].pid = -1;
@@ -1105,22 +1134,23 @@
snprintf(mpq_dmx_tspp_info.tsif[i].name,
TSIF_NAME_LENGTH,
- "tsif_%d",
+ "dmx_tsif%d",
i);
- mpq_dmx_tspp_info.tsif[i].workqueue =
- create_singlethread_workqueue(
+ init_waitqueue_head(&mpq_dmx_tspp_info.tsif[i].wait_queue);
+ mpq_dmx_tspp_info.tsif[i].thread =
+ kthread_run(
+ mpq_dmx_tspp_thread, (void *)i,
mpq_dmx_tspp_info.tsif[i].name);
- if (mpq_dmx_tspp_info.tsif[i].workqueue == NULL) {
+ if (IS_ERR(mpq_dmx_tspp_info.tsif[i].thread)) {
for (j = 0; j < i; j++) {
- destroy_workqueue(
- mpq_dmx_tspp_info.tsif[j].workqueue);
-
+ kthread_stop(mpq_dmx_tspp_info.tsif[j].thread);
mutex_destroy(&mpq_dmx_tspp_info.tsif[j].mutex);
}
+
MPQ_DVB_ERR_PRINT(
- "%s: create_singlethread_workqueue failed\n",
+ "%s: kthread_run failed\n",
__func__);
return -ENOMEM;
@@ -1138,7 +1168,7 @@
ret);
for (i = 0; i < TSIF_COUNT; i++) {
- destroy_workqueue(mpq_dmx_tspp_info.tsif[i].workqueue);
+ kthread_stop(mpq_dmx_tspp_info.tsif[i].thread);
mutex_destroy(&mpq_dmx_tspp_info.tsif[i].mutex);
}
}
@@ -1179,8 +1209,7 @@
mpq_dmx_tsif_ion_cleanup(i);
mutex_unlock(&mpq_dmx_tspp_info.tsif[i].mutex);
- flush_workqueue(mpq_dmx_tspp_info.tsif[i].workqueue);
- destroy_workqueue(mpq_dmx_tspp_info.tsif[i].workqueue);
+ kthread_stop(mpq_dmx_tspp_info.tsif[i].thread);
mutex_destroy(&mpq_dmx_tspp_info.tsif[i].mutex);
}
diff --git a/drivers/media/video/msm/jpeg_10/msm_jpeg_hw_reg.h b/drivers/media/video/msm/jpeg_10/msm_jpeg_hw_reg.h
index ff99aa3..31286dd 100644
--- a/drivers/media/video/msm/jpeg_10/msm_jpeg_hw_reg.h
+++ b/drivers/media/video/msm/jpeg_10/msm_jpeg_hw_reg.h
@@ -126,5 +126,11 @@
#define JPEG_VBIF_OUT_WR_LIM_CONF0 0xD4
#define JPEG_VBIF_DDR_OUT_MAX_BURST 0xD8
#define JPEG_VBIF_OCMEM_OUT_MAX_BURST 0xDC
+#define JPEG_VBIF_ARB_CTL 0xF0
+#define JPEG_VBIF_OUT_AXI_AOOO_EN 0x178
+#define JPEG_VBIF_OUT_AXI_AOOO 0x17c
+#define JPEG_VBIF_ROUND_ROBIN_QOS_ARB 0x124
+#define JPEG_VBIF_OUT_AXI_AMEMTYPE_CONF0 0x160
+#define JPEG_VBIF_OUT_AXI_AMEMTYPE_CONF1 0x164
#endif /* MSM_JPEG_HW_REG_H */
diff --git a/drivers/media/video/msm/jpeg_10/msm_jpeg_platform.c b/drivers/media/video/msm/jpeg_10/msm_jpeg_platform.c
index 06135ec..38a0ffb 100644
--- a/drivers/media/video/msm/jpeg_10/msm_jpeg_platform.c
+++ b/drivers/media/video/msm/jpeg_10/msm_jpeg_platform.c
@@ -108,12 +108,26 @@
jpeg_vbif_base + JPEG_VBIF_IN_WR_LIM_CONF2);
writel_relaxed(0x00001010,
jpeg_vbif_base + JPEG_VBIF_OUT_RD_LIM_CONF0);
- writel_relaxed(0x00001010,
+ writel_relaxed(0x00000110,
jpeg_vbif_base + JPEG_VBIF_OUT_WR_LIM_CONF0);
writel_relaxed(0x00000707,
jpeg_vbif_base + JPEG_VBIF_DDR_OUT_MAX_BURST);
- writel_relaxed(0x00000707,
+ writel_relaxed(0x7,
jpeg_vbif_base + JPEG_VBIF_OCMEM_OUT_MAX_BURST);
+ writel_relaxed(0x00000030,
+ jpeg_vbif_base + JPEG_VBIF_ARB_CTL);
+ writel_relaxed(0x00000FFF,
+ jpeg_vbif_base + JPEG_VBIF_OUT_AXI_AOOO_EN);
+ writel_relaxed(0x0FFF0FFF,
+ jpeg_vbif_base + JPEG_VBIF_OUT_AXI_AOOO);
+ /*FE and WE QOS configuration need to be set when
+ QOS RR arbitration is enabled*/
+ writel_relaxed(0x00000001,
+ jpeg_vbif_base + JPEG_VBIF_ROUND_ROBIN_QOS_ARB);
+ writel_relaxed(0x22222222,
+ jpeg_vbif_base + JPEG_VBIF_OUT_AXI_AMEMTYPE_CONF0);
+ writel_relaxed(0x2222,
+ jpeg_vbif_base + JPEG_VBIF_OUT_AXI_AMEMTYPE_CONF1);
}
diff --git a/drivers/media/video/msm/sensors/msm_sensor.c b/drivers/media/video/msm/sensors/msm_sensor.c
index 63cf38e..907523c 100644
--- a/drivers/media/video/msm/sensors/msm_sensor.c
+++ b/drivers/media/video/msm/sensors/msm_sensor.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
@@ -603,6 +603,8 @@
{
int32_t rc = 0;
uint32_t val = 0;
+ struct msm_camera_sensor_flash_data *flash_data = NULL;
+ struct device_node *flash_src_node = NULL;
sensordata->flash_data = kzalloc(sizeof(
struct msm_camera_sensor_flash_data), GFP_KERNEL);
@@ -611,16 +613,42 @@
return -ENOMEM;
}
- rc = of_property_read_u32(of_node, "qcom,flash-type", &val);
+ if (!of_get_property(of_node, "qcom,flash-src-index", &val)) {
+ CDBG("%s flash not available\n", __func__);
+ return rc;
+ }
+ flash_data = sensordata->flash_data;
+
+ flash_src_node = of_parse_phandle(of_node, "qcom,flash-src-index", 0);
+ if (!flash_src_node) {
+ pr_err("%s:%d flash_src_node NULL\n", __func__,
+ __LINE__);
+ goto ERROR1;
+ }
+
+ rc = of_property_read_u32(flash_src_node, "qcom,flash-type", &val);
CDBG("%s qcom,flash-type %d, rc %d\n", __func__, val, rc);
if (rc < 0) {
pr_err("%s failed %d\n", __func__, __LINE__);
- goto ERROR;
+ goto ERROR2;
}
- sensordata->flash_data->flash_type = val;
+ flash_data->flash_type = val;
+
+ rc = of_property_read_u32(flash_src_node, "cell-index", &val);
+ CDBG("%s qcom,flash-src-index %d, rc %d\n", __func__, val, rc);
+ if (rc < 0) {
+ pr_err("%s failed %d\n", __func__, __LINE__);
+ goto ERROR2;
+ }
+ flash_data->flash_src_index = val;
+
+ of_node_put(flash_src_node);
+
return rc;
-ERROR:
- kfree(sensordata->flash_data);
+ERROR2:
+ of_node_put(flash_src_node);
+ERROR1:
+ flash_data->flash_type = MSM_CAMERA_FLASH_NONE;
return rc;
}
diff --git a/drivers/media/video/msm/server/msm_cam_server.c b/drivers/media/video/msm/server/msm_cam_server.c
index b2a7f71..f61b74f 100644
--- a/drivers/media/video/msm/server/msm_cam_server.c
+++ b/drivers/media/video/msm/server/msm_cam_server.c
@@ -473,16 +473,15 @@
kfree(ctrlcmd);
free_qcmd(rcmd);
D("%s: rc %d\n", __func__, rc);
- /* rc is the time elapsed. */
- if (rc >= 0) {
- /* TODO: Refactor msm_ctrl_cmd::status field */
- if (out->status == 0)
- rc = -1;
- else if (out->status == 1 || out->status == 4)
- rc = 0;
- else
- rc = -EINVAL;
- }
+ /* rc is the time elapsed.
+ * This means that the communication with the daemon itself was
+ * successful(irrespective of the handling of the ctrlcmd).
+ * So, just reset the rc to 0 to indicate success.
+ * Its upto the caller to parse the ctrlcmd to check the status. We
+ * dont need to parse it here. */
+ if (rc >= 0)
+ rc = 0;
+
return rc;
ctrlcmd_alloc_fail:
@@ -846,9 +845,9 @@
rc = -EINVAL;
goto end;
}
-
+ tmp_cmd.status = cmd_ptr->status = ctrlcmd.status;
if (copy_to_user((void __user *)ioctl_ptr->ioctl_ptr,
- (void *)&tmp_cmd, cmd_len)) {
+ (void *)cmd_ptr, cmd_len)) {
pr_err("%s: copy_to_user failed in cpy, size=%d\n",
__func__, cmd_len);
rc = -EINVAL;
diff --git a/drivers/media/video/msm/vfe/msm_vfe40.c b/drivers/media/video/msm/vfe/msm_vfe40.c
index 287c77c..81a6dd2 100644
--- a/drivers/media/video/msm/vfe/msm_vfe40.c
+++ b/drivers/media/video/msm/vfe/msm_vfe40.c
@@ -5170,39 +5170,44 @@
static void msm_vfe40_init_vbif_parms(void __iomem *vfe_vbif_base)
{
- msm_camera_io_w_mb(0x1,
+ msm_camera_io_w(0x1,
vfe_vbif_base + VFE40_VBIF_CLKON);
- msm_camera_io_w_mb(0x1,
- vfe_vbif_base + VFE40_VBIF_ROUND_ROBIN_QOS_ARB);
- msm_camera_io_w_mb(0xFFFF,
- vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO_EN);
- msm_camera_io_w_mb(0xFFFFFFFF,
- vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO);
-
- msm_camera_io_w_mb(0x10101010,
+ msm_camera_io_w(0x01010101,
vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF0);
- msm_camera_io_w_mb(0x10101010,
+ msm_camera_io_w(0x01010101,
vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF1);
- msm_camera_io_w_mb(0x10101010,
+ msm_camera_io_w(0x10010110,
vfe_vbif_base + VFE40_VBIF_IN_RD_LIM_CONF2);
- msm_camera_io_w_mb(0x10101010,
+ msm_camera_io_w(0x10101010,
vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF0);
- msm_camera_io_w_mb(0x10101010,
+ msm_camera_io_w(0x10101010,
vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF1);
- msm_camera_io_w_mb(0x10101010,
+ msm_camera_io_w(0x10101010,
vfe_vbif_base + VFE40_VBIF_IN_WR_LIM_CONF2);
- msm_camera_io_w_mb(0x00001010,
+ msm_camera_io_w(0x00001010,
vfe_vbif_base + VFE40_VBIF_OUT_RD_LIM_CONF0);
- msm_camera_io_w_mb(0x00001010,
+ msm_camera_io_w(0x00001010,
vfe_vbif_base + VFE40_VBIF_OUT_WR_LIM_CONF0);
- msm_camera_io_w_mb(0x00000707,
+ msm_camera_io_w(0x00000707,
vfe_vbif_base + VFE40_VBIF_DDR_OUT_MAX_BURST);
- msm_camera_io_w_mb(0x00000030,
+ msm_camera_io_w(0x00000707,
+ vfe_vbif_base + VFE40_VBIF_OCMEM_OUT_MAX_BURST);
+ msm_camera_io_w(0x00000030,
vfe_vbif_base + VFE40_VBIF_ARB_CTL);
- msm_camera_io_w_mb(0x04210842,
+ msm_camera_io_w(0x04210842,
vfe_vbif_base + VFE40_VBIF_DDR_ARB_CONF0);
- msm_camera_io_w_mb(0x04210842,
+ msm_camera_io_w(0x04210842,
vfe_vbif_base + VFE40_VBIF_DDR_ARB_CONF1);
+ msm_camera_io_w(0x00000001,
+ vfe_vbif_base + VFE40_VBIF_ROUND_ROBIN_QOS_ARB);
+ msm_camera_io_w(0x22222222,
+ vfe_vbif_base + VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF0);
+ msm_camera_io_w(0x00002222,
+ vfe_vbif_base + VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF1);
+ msm_camera_io_w(0x00000FFF,
+ vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO_EN);
+ msm_camera_io_w(0x0FFF0FFF,
+ vfe_vbif_base + VFE40_VBIF_OUT_AXI_AOOO);
}
int msm_axi_subdev_init(struct v4l2_subdev *sd)
diff --git a/drivers/media/video/msm/vfe/msm_vfe40.h b/drivers/media/video/msm/vfe/msm_vfe40.h
index 4acc7e4..a94c428 100644
--- a/drivers/media/video/msm/vfe/msm_vfe40.h
+++ b/drivers/media/video/msm/vfe/msm_vfe40.h
@@ -901,22 +901,25 @@
#define VFE40_OUTPUT_MODE_TERTIARY1 BIT(10)
#define VFE40_OUTPUT_MODE_TERTIARY2 BIT(11)
-#define VFE40_VBIF_CLKON 0x4
-#define VFE40_VBIF_IN_RD_LIM_CONF0 0xB0
-#define VFE40_VBIF_IN_RD_LIM_CONF1 0xB4
-#define VFE40_VBIF_IN_RD_LIM_CONF2 0xB8
-#define VFE40_VBIF_IN_WR_LIM_CONF0 0xC0
-#define VFE40_VBIF_IN_WR_LIM_CONF1 0xC4
-#define VFE40_VBIF_IN_WR_LIM_CONF2 0xC8
-#define VFE40_VBIF_OUT_RD_LIM_CONF0 0xD0
-#define VFE40_VBIF_OUT_WR_LIM_CONF0 0xD4
-#define VFE40_VBIF_DDR_OUT_MAX_BURST 0xD8
-#define VFE40_VBIF_ARB_CTL 0xF0
-#define VFE40_VBIF_DDR_ARB_CONF0 0xF4
-#define VFE40_VBIF_DDR_ARB_CONF1 0xF8
-#define VFE40_VBIF_ROUND_ROBIN_QOS_ARB 0x124
-#define VFE40_VBIF_OUT_AXI_AOOO_EN 0x178
-#define VFE40_VBIF_OUT_AXI_AOOO 0x17C
+#define VFE40_VBIF_CLKON 0x4
+#define VFE40_VBIF_IN_RD_LIM_CONF0 0xB0
+#define VFE40_VBIF_IN_RD_LIM_CONF1 0xB4
+#define VFE40_VBIF_IN_RD_LIM_CONF2 0xB8
+#define VFE40_VBIF_IN_WR_LIM_CONF0 0xC0
+#define VFE40_VBIF_IN_WR_LIM_CONF1 0xC4
+#define VFE40_VBIF_IN_WR_LIM_CONF2 0xC8
+#define VFE40_VBIF_OUT_RD_LIM_CONF0 0xD0
+#define VFE40_VBIF_OUT_WR_LIM_CONF0 0xD4
+#define VFE40_VBIF_DDR_OUT_MAX_BURST 0xD8
+#define VFE40_VBIF_OCMEM_OUT_MAX_BURST 0xDC
+#define VFE40_VBIF_ARB_CTL 0xF0
+#define VFE40_VBIF_DDR_ARB_CONF0 0xF4
+#define VFE40_VBIF_DDR_ARB_CONF1 0xF8
+#define VFE40_VBIF_ROUND_ROBIN_QOS_ARB 0x124
+#define VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF0 0x160
+#define VFE40_VBIF_OUT_AXI_AMEMTYPE_CONF1 0x164
+#define VFE40_VBIF_OUT_AXI_AOOO_EN 0x178
+#define VFE40_VBIF_OUT_AXI_AOOO 0x17C
struct vfe_stats_control {
uint32_t droppedStatsFrameCount;
diff --git a/drivers/media/video/msm_vidc/msm_smem.c b/drivers/media/video/msm_vidc/msm_smem.c
index 83f33a1..e1b73ef 100644
--- a/drivers/media/video/msm_vidc/msm_smem.c
+++ b/drivers/media/video/msm_vidc/msm_smem.c
@@ -32,8 +32,6 @@
clnt, hndl, iova, buffer_size);
return -EINVAL;
}
- if (align < 4096)
- align = 4096;
dprintk(VIDC_DBG, "domain: %d, partition: %d\n",
domain_num, partition_num);
if (flags & SMEM_SECURE) {
@@ -74,6 +72,7 @@
unsigned long iova = 0;
unsigned long buffer_size = 0;
int rc = 0;
+ int align = SZ_4K;
hndl = ion_import_dma_buf(client->clnt, fd);
if (IS_ERR_OR_NULL(hndl)) {
dprintk(VIDC_ERR, "Failed to get handle: %p, %d, %d, %p\n",
@@ -85,8 +84,12 @@
mem->domain = domain;
mem->partition_num = partition;
mem->flags = flags;
+
+ if (flags & SMEM_SECURE)
+ align = ALIGN(align, SZ_1M);
+
rc = get_device_address(client->clnt, hndl, mem->domain,
- mem->partition_num, 4096, &iova, &buffer_size, flags);
+ mem->partition_num, align, &iova, &buffer_size, flags);
if (rc) {
dprintk(VIDC_ERR, "Failed to get device address: %d\n", rc);
goto fail_device_address;
@@ -121,15 +124,16 @@
else
ionflags = ION_SET_UNCACHED(ionflags);
+ align = ALIGN(align, SZ_4K);
+ size = ALIGN(size, SZ_4K);
+
if (flags & SMEM_SECURE) {
ionflags |= ION_SECURE;
- size = (size + 0xfffff) & (~0xfffff);
+ size = ALIGN(size, SZ_1M);
+ align = ALIGN(align, SZ_1M);
}
heap_mask = ION_HEAP(ION_CP_MM_HEAP_ID);
- if (align < 4096)
- align = 4096;
- size = (size + 4095) & (~4095);
dprintk(VIDC_DBG, "domain: %d, partition: %d\n",
domain, partition);
hndl = ion_alloc(client->clnt, size, align, heap_mask, ionflags);
diff --git a/drivers/media/video/msm_vidc/msm_v4l2_vidc.c b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
index 4f2373e..38e8de1 100644
--- a/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
+++ b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
@@ -591,7 +591,7 @@
}
v4l2_inst->vidc_inst = msm_vidc_open(core->id, vid_dev->type);
- if (rc) {
+ if (!v4l2_inst->vidc_inst) {
dprintk(VIDC_ERR,
"Failed to create video instance, core: %d, type = %d\n",
core->id, vid_dev->type);
diff --git a/drivers/media/video/msm_vidc/msm_vdec.c b/drivers/media/video/msm_vidc/msm_vdec.c
index a95a296..e0a341a 100644
--- a/drivers/media/video/msm_vidc/msm_vdec.c
+++ b/drivers/media/video/msm_vidc/msm_vdec.c
@@ -462,7 +462,7 @@
b->m.planes[extra_idx].m.userptr;
else
buffer_info.extradata_addr = 0;
-
+ buffer_info.response_required = false;
rc = vidc_hal_session_release_buffers(
(void *)inst->session, &buffer_info);
if (rc)
@@ -631,10 +631,7 @@
}
inst->prop.fps = (u8) (USEC_PER_SEC / us_per_frame);
if (inst->prop.fps) {
- if (msm_comm_scale_clocks(inst->core, inst->session_type)) {
- dprintk(VIDC_WARN,
- "Failed to scale clocks\n");
- }
+ msm_comm_scale_clocks_and_bus(inst);
}
exit:
return rc;
@@ -881,11 +878,7 @@
"Failed to set persist buffers: %d\n", rc);
goto fail_start;
}
- if (msm_comm_scale_clocks(inst->core, inst->session_type)) {
- dprintk(VIDC_WARN,
- "Failed to scale clocks. Performance might be impacted\n");
- }
-
+ msm_comm_scale_clocks_and_bus(inst);
rc = msm_comm_try_state(inst, MSM_VIDC_START_DONE);
if (rc) {
dprintk(VIDC_ERR,
@@ -976,10 +969,7 @@
rc = -EINVAL;
break;
}
- if (msm_comm_scale_clocks(inst->core, inst->session_type)) {
- dprintk(VIDC_WARN,
- "Failed to scale clocks. Power might be impacted\n");
- }
+ msm_comm_scale_clocks_and_bus(inst);
if (rc)
dprintk(VIDC_ERR,
diff --git a/drivers/media/video/msm_vidc/msm_venc.c b/drivers/media/video/msm_vidc/msm_venc.c
index d01841d..f436cf3 100644
--- a/drivers/media/video/msm_vidc/msm_venc.c
+++ b/drivers/media/video/msm_vidc/msm_venc.c
@@ -639,10 +639,7 @@
dprintk(VIDC_ERR, "Failed to set persist buffers: %d\n", rc);
goto fail_start;
}
- if (msm_comm_scale_clocks(inst->core, inst->session_type)) {
- dprintk(VIDC_WARN,
- "Failed to scale clocks. Performance might be impacted\n");
- }
+ msm_comm_scale_clocks_and_bus(inst);
rc = msm_comm_try_state(inst, MSM_VIDC_START_DONE);
if (rc) {
@@ -718,10 +715,7 @@
rc = -EINVAL;
break;
}
- if (msm_comm_scale_clocks(inst->core, inst->session_type)) {
- dprintk(VIDC_WARN,
- "Failed to scale clocks. Power might be impacted\n");
- }
+ msm_comm_scale_clocks_and_bus(inst);
if (rc)
dprintk(VIDC_ERR,
@@ -1371,10 +1365,7 @@
dprintk(VIDC_WARN,
"Failed to set frame rate %d\n", rc);
}
- if (msm_comm_scale_clocks(inst->core, inst->session_type)) {
- dprintk(VIDC_WARN,
- "Failed to scale clocks\n");
- }
+ msm_comm_scale_clocks_and_bus(inst);
}
exit:
return rc;
@@ -1578,6 +1569,7 @@
b->m.planes[i].m.userptr;
buffer_info.extradata_size = 0;
buffer_info.extradata_addr = 0;
+ buffer_info.response_required = false;
rc = vidc_hal_session_release_buffers(
(void *)inst->session, &buffer_info);
if (rc)
diff --git a/drivers/media/video/msm_vidc/msm_vidc_common.c b/drivers/media/video/msm_vidc/msm_vidc_common.c
index cda0ea8..46a88c2 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_common.c
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.c
@@ -64,7 +64,6 @@
};
static const u32 bus_table[] = {
- 0,
36000,
110400,
244800,
@@ -77,12 +76,11 @@
{
int num_rows = sizeof(bus_table)/(sizeof(u32));
int i;
- if (!load)
- return 0;
for (i = 0; i < num_rows; i++) {
if (load <= bus_table[i])
break;
}
+ i++;
dprintk(VIDC_DBG, "Required bus = %d\n", i);
return i;
}
@@ -122,37 +120,60 @@
break;
ret = table[i].freq;
}
- dprintk(VIDC_INFO, "Required clock rate = %lu\n", ret);
+ dprintk(VIDC_DBG, "Required clock rate = %lu\n", ret);
return ret;
}
-int msm_comm_scale_bus(struct msm_vidc_core *core, enum session_type type)
+static int msm_comm_scale_bus(struct msm_vidc_core *core,
+ enum session_type type, enum mem_type mtype)
{
int load;
int rc = 0;
+ u32 handle = 0;
if (!core || type >= MSM_VIDC_MAX_DEVICES) {
dprintk(VIDC_ERR, "Invalid args: %p, %d\n", core, type);
return -EINVAL;
}
load = msm_comm_get_load(core, type);
- rc = msm_bus_scale_client_update_request(
- core->resources.bus_info.ddr_handle[type],
- get_bus_vector(load));
- if (rc) {
- dprintk(VIDC_ERR, "Failed to scale bus: %d\n", rc);
- goto fail_scale_bus;
+ if (mtype & DDR_MEM)
+ handle = core->resources.bus_info.ddr_handle[type];
+ if (mtype & OCMEM_MEM)
+ handle = core->resources.bus_info.ocmem_handle[type];
+ if (handle) {
+ rc = msm_bus_scale_client_update_request(
+ handle, get_bus_vector(load));
+ if (rc)
+ dprintk(VIDC_ERR, "Failed to scale bus: %d\n", rc);
+ } else {
+ dprintk(VIDC_ERR, "Failed to scale bus, mtype: %d\n",
+ mtype);
+ rc = -EINVAL;
}
- rc = msm_bus_scale_client_update_request(
- core->resources.bus_info.ocmem_handle[type],
- get_bus_vector(load));
- if (rc) {
- dprintk(VIDC_ERR, "Failed to scale bus: %d\n", rc);
- goto fail_scale_bus;
- }
-fail_scale_bus:
return rc;
}
+static void msm_comm_unvote_buses(struct msm_vidc_core *core,
+ enum mem_type mtype)
+{
+ int i;
+ for (i = 0; i < MSM_VIDC_MAX_DEVICES; i++) {
+ if ((mtype & DDR_MEM) &&
+ msm_bus_scale_client_update_request(
+ core->resources.bus_info.ddr_handle[i],
+ 0)) {
+ dprintk(VIDC_WARN,
+ "Failed to unvote for DDR accesses\n");
+ }
+ if ((mtype & OCMEM_MEM) &&
+ msm_bus_scale_client_update_request(
+ core->resources.bus_info.ocmem_handle[i],
+ 0)) {
+ dprintk(VIDC_WARN,
+ "Failed to unvote for OCMEM accesses\n");
+ }
+ }
+}
+
static int protect_cp_mem(struct msm_vidc_core *core)
{
struct tzbsp_memprot memprot;
@@ -333,6 +354,48 @@
}
}
+static void handle_session_release_buf_done(enum command_response cmd,
+ void *data)
+{
+ struct msm_vidc_cb_cmd_done *response = data;
+ struct msm_vidc_inst *inst;
+ struct internal_buf *buf;
+ struct list_head *ptr, *next;
+ struct hal_buffer_info *buffer;
+ u32 address, buf_found = false;
+
+ if (!response || !response->data) {
+ dprintk(VIDC_ERR, "Invalid release_buf_done response\n");
+ return;
+ }
+
+ inst = (struct msm_vidc_inst *)response->session_id;
+ buffer = (struct hal_buffer_info *) response->data;
+ address = (u32) buffer->buffer_addr;
+
+ list_for_each_safe(ptr, next, &inst->internalbufs) {
+ buf = list_entry(ptr, struct internal_buf, list);
+ if (address == buf->handle->device_addr) {
+ dprintk(VIDC_DBG, "releasing scratch: 0x%x",
+ (u32) buf->handle->device_addr);
+ buf_found = true;
+ }
+ }
+
+ list_for_each_safe(ptr, next, &inst->persistbufs) {
+ buf = list_entry(ptr, struct internal_buf, list);
+ if (address == (u32) buf->handle->device_addr) {
+ dprintk(VIDC_DBG, "releasing persist: 0x%x",
+ (u32) buf->handle->device_addr);
+ buf_found = true;
+ }
+ }
+
+ if (!buf_found)
+ dprintk(VIDC_ERR, "invalid buffer received from firmware");
+ complete(&inst->completions[SESSION_MSG_INDEX(cmd)]);
+}
+
static void handle_sys_release_res_done(
enum command_response cmd, void *data)
{
@@ -589,33 +652,28 @@
struct v4l2_event dqevent;
unsigned long flags;
if (response) {
- inst = (struct msm_vidc_inst *)response->session_id;
- dprintk(VIDC_WARN,
- "Sys error received for session %p\n", inst);
- if (inst) {
- core = inst->core;
- if (core) {
- spin_lock_irqsave(&core->lock, flags);
- core->state = VIDC_CORE_INVALID;
- spin_unlock_irqrestore(&core->lock, flags);
- dqevent.type = V4L2_EVENT_MSM_VIDC_SYS_ERROR;
- dqevent.id = 0;
- list_for_each_entry(inst, &core->instances,
+ core = get_vidc_core(response->device_id);
+ dprintk(VIDC_WARN, "SYS_ERROR received for core %p\n", core);
+ if (core) {
+ spin_lock_irqsave(&core->lock, flags);
+ core->state = VIDC_CORE_INVALID;
+ spin_unlock_irqrestore(&core->lock, flags);
+ dqevent.type = V4L2_EVENT_MSM_VIDC_SYS_ERROR;
+ dqevent.id = 0;
+ list_for_each_entry(inst, &core->instances,
list) {
- if (inst) {
- v4l2_event_queue_fh(
- &inst->event_handler,
- &dqevent);
- spin_lock_irqsave(&inst->lock,
- flags);
- inst->state =
- MSM_VIDC_CORE_INVALID;
- spin_unlock_irqrestore(
- &inst->lock, flags);
- }
- }
- wake_up(&inst->kernel_event_queue);
+ v4l2_event_queue_fh(&inst->event_handler,
+ &dqevent);
+
+ spin_lock_irqsave(&inst->lock, flags);
+ inst->state = MSM_VIDC_CORE_INVALID;
+ spin_unlock_irqrestore(&inst->lock, flags);
+
+ wake_up(&inst->kernel_event_queue);
}
+ } else {
+ dprintk(VIDC_ERR,
+ "Got SYS_ERR but unable to identify core");
}
} else {
dprintk(VIDC_ERR,
@@ -876,13 +934,16 @@
case SESSION_ERROR:
handle_session_error(cmd, data);
break;
+ case SESSION_RELEASE_BUFFER_DONE:
+ handle_session_release_buf_done(cmd, data);
+ break;
default:
dprintk(VIDC_ERR, "response unhandled\n");
break;
}
}
-int msm_comm_scale_clocks(struct msm_vidc_core *core, enum session_type type)
+static int msm_comm_scale_clocks(struct msm_vidc_core *core)
{
int num_mbs_per_sec;
int rc = 0;
@@ -896,14 +957,8 @@
rc = clk_set_rate(core->resources.clock[VCODEC_CLK].clk,
get_clock_rate(&core->resources.clock[VCODEC_CLK],
num_mbs_per_sec));
- if (rc) {
- dprintk(VIDC_ERR, "Failed to set clock rate: %d\n", rc);
- goto fail_clk_set_rate;
- }
- rc = msm_comm_scale_bus(core, type);
if (rc)
- dprintk(VIDC_ERR, "Failed to scale bus bandwidth\n");
-fail_clk_set_rate:
+ dprintk(VIDC_ERR, "Failed to set clock rate: %d\n", rc);
return rc;
}
@@ -949,6 +1004,28 @@
}
}
+void msm_comm_scale_clocks_and_bus(struct msm_vidc_inst *inst)
+{
+ struct msm_vidc_core *core = inst->core;
+ if (!inst) {
+ dprintk(VIDC_WARN, "Invalid params\n");
+ return;
+ }
+ if (msm_comm_scale_clocks(core)) {
+ dprintk(VIDC_WARN,
+ "Failed to scale clocks. Performance might be impacted\n");
+ }
+ if (msm_comm_scale_bus(core, inst->session_type, DDR_MEM)) {
+ dprintk(VIDC_WARN,
+ "Failed to scale DDR bus. Performance might be impacted\n");
+ }
+ if (core->resources.ocmem.buf) {
+ if (msm_comm_scale_bus(core, inst->session_type, OCMEM_MEM))
+ dprintk(VIDC_WARN,
+ "Failed to scale OCMEM bus. Performance might be impacted\n");
+ }
+}
+
static int msm_comm_load_fw(struct msm_vidc_core *core)
{
int rc = 0;
@@ -956,25 +1033,28 @@
dprintk(VIDC_ERR, "Invalid paramter: %p\n", core);
return -EINVAL;
}
-
if (!core->resources.fw.cookie)
core->resources.fw.cookie = subsystem_get("venus");
if (IS_ERR_OR_NULL(core->resources.fw.cookie)) {
dprintk(VIDC_ERR, "Failed to download firmware\n");
rc = -ENOMEM;
- goto fail_subsystem_get;
+ goto fail_load_fw;
}
+ /*Clocks can be enabled only after pil_get since
+ * gdsc is turned-on in pil_get*/
rc = msm_comm_enable_clks(core);
if (rc) {
dprintk(VIDC_ERR, "Failed to enable clocks: %d\n", rc);
goto fail_enable_clks;
}
+
rc = protect_cp_mem(core);
if (rc) {
dprintk(VIDC_ERR, "Failed to protect memory\n");
goto fail_iommu_attach;
}
+
rc = msm_comm_iommu_attach(core);
if (rc) {
dprintk(VIDC_ERR, "Failed to attach iommu");
@@ -986,7 +1066,7 @@
fail_enable_clks:
subsystem_put(core->resources.fw.cookie);
core->resources.fw.cookie = NULL;
-fail_subsystem_get:
+fail_load_fw:
return rc;
}
@@ -1189,16 +1269,24 @@
core->id, core->state);
goto core_already_inited;
}
- rc = msm_comm_scale_clocks(core, inst->session_type);
+
+ rc = msm_comm_scale_bus(core, inst->session_type, DDR_MEM);
if (rc) {
- dprintk(VIDC_ERR, "Failed to set clock rate: %d\n", rc);
- goto fail_load_fw;
+ dprintk(VIDC_ERR, "Failed to scale DDR bus: %d\n", rc);
+ goto fail_scale_bus;
}
+
rc = msm_comm_load_fw(core);
if (rc) {
dprintk(VIDC_ERR, "Failed to load video firmware\n");
goto fail_load_fw;
}
+ rc = msm_comm_scale_clocks(core);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to scale clocks: %d\n", rc);
+ goto fail_core_init;
+ }
+
init_completion(&core->completions[SYS_MSG_INDEX(SYS_INIT_DONE)]);
rc = vidc_hal_core_init(core->device,
core->resources.io_map[NS_MAP].domain);
@@ -1216,6 +1304,8 @@
fail_core_init:
msm_comm_unload_fw(core);
fail_load_fw:
+ msm_comm_unvote_buses(core, DDR_MEM);
+fail_scale_bus:
mutex_unlock(&core->sync_lock);
return rc;
}
@@ -1231,10 +1321,7 @@
core->id, core->state);
goto core_already_uninited;
}
- if (msm_comm_scale_clocks(core, inst->session_type)) {
- dprintk(VIDC_WARN, "Failed to scale clocks while closing\n");
- dprintk(VIDC_INFO, "Power might be impacted\n");
- }
+ msm_comm_scale_clocks_and_bus(inst);
if (list_empty(&core->instances)) {
msm_comm_unset_ocmem(core);
msm_comm_free_ocmem(core);
@@ -1249,6 +1336,7 @@
core->state = VIDC_CORE_UNINIT;
spin_unlock_irqrestore(&core->lock, flags);
msm_comm_unload_fw(core);
+ msm_comm_unvote_buses(core, DDR_MEM|OCMEM_MEM);
}
core_already_uninited:
change_inst_state(inst, MSM_VIDC_CORE_UNINIT);
@@ -1367,11 +1455,18 @@
goto exit;
}
ocmem_sz = get_ocmem_requirement(inst->prop.height, inst->prop.width);
- rc = msm_comm_alloc_ocmem(inst->core, ocmem_sz);
- if (rc)
- dprintk(VIDC_WARN,
+ rc = msm_comm_scale_bus(inst->core, inst->session_type, OCMEM_MEM);
+ if (!rc) {
+ rc = msm_comm_alloc_ocmem(inst->core, ocmem_sz);
+ if (rc) {
+ dprintk(VIDC_WARN,
"Failed to allocate OCMEM. Performance will be impacted\n");
-
+ msm_comm_unvote_buses(inst->core, OCMEM_MEM);
+ }
+ } else {
+ dprintk(VIDC_WARN,
+ "Failed to vote for OCMEM BW. Performance will be impacted\n");
+ }
rc = vidc_hal_session_load_res((void *) inst->session);
if (rc) {
dprintk(VIDC_ERR,
@@ -1790,6 +1885,10 @@
buffer_info.align_device_addr = handle->device_addr;
if (inst->state != MSM_VIDC_CORE_INVALID &&
core->state != VIDC_CORE_INVALID) {
+ buffer_info.response_required = true;
+ init_completion(
+ &inst->completions[SESSION_MSG_INDEX
+ (SESSION_RELEASE_BUFFER_DONE)]);
rc = vidc_hal_session_release_buffers(
(void *) inst->session,
&buffer_info);
@@ -1798,6 +1897,10 @@
"Rel scrtch buf fail:0x%x, %d",
buffer_info.align_device_addr,
buffer_info.buffer_size);
+ spin_unlock_irqrestore(&inst->lock, flags);
+ rc = wait_for_sess_signal_receipt(inst,
+ SESSION_RELEASE_BUFFER_DONE);
+ spin_lock_irqsave(&inst->lock, flags);
}
list_del(&buf->list);
spin_unlock_irqrestore(&inst->lock, flags);
@@ -1842,6 +1945,10 @@
buffer_info.align_device_addr = handle->device_addr;
if (inst->state != MSM_VIDC_CORE_INVALID &&
core->state != VIDC_CORE_INVALID) {
+ buffer_info.response_required = true;
+ init_completion(
+ &inst->completions[SESSION_MSG_INDEX
+ (SESSION_RELEASE_BUFFER_DONE)]);
rc = vidc_hal_session_release_buffers(
(void *) inst->session,
&buffer_info);
@@ -1850,6 +1957,10 @@
"Rel prst buf fail:0x%x, %d",
buffer_info.align_device_addr,
buffer_info.buffer_size);
+ spin_unlock_irqrestore(&inst->lock, flags);
+ rc = wait_for_sess_signal_receipt(inst,
+ SESSION_RELEASE_BUFFER_DONE);
+ spin_lock_irqsave(&inst->lock, flags);
}
list_del(&buf->list);
spin_unlock_irqrestore(&inst->lock, flags);
@@ -1932,6 +2043,8 @@
buffer_info.buffer_type = HAL_BUFFER_INTERNAL_SCRATCH;
buffer_info.num_buffers = 1;
buffer_info.align_device_addr = handle->device_addr;
+ dprintk(VIDC_DBG, "Scratch buffer address: %x",
+ buffer_info.align_device_addr);
rc = vidc_hal_session_set_buffers(
(void *) inst->session, &buffer_info);
if (rc) {
@@ -2003,6 +2116,8 @@
buffer_info.buffer_type = HAL_BUFFER_INTERNAL_PERSIST;
buffer_info.num_buffers = 1;
buffer_info.align_device_addr = handle->device_addr;
+ dprintk(VIDC_DBG, "Persist buffer address: %x",
+ buffer_info.align_device_addr);
rc = vidc_hal_session_set_buffers(
(void *) inst->session, &buffer_info);
if (rc) {
diff --git a/drivers/media/video/msm_vidc/msm_vidc_common.h b/drivers/media/video/msm_vidc/msm_vidc_common.h
index 28bec97..916a3ca 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_common.h
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.h
@@ -32,7 +32,7 @@
int msm_comm_set_scratch_buffers(struct msm_vidc_inst *inst);
int msm_comm_set_persist_buffers(struct msm_vidc_inst *inst);
int msm_comm_qbuf(struct vb2_buffer *vb);
-int msm_comm_scale_clocks(struct msm_vidc_core *core, enum session_type type);
+void msm_comm_scale_clocks_and_bus(struct msm_vidc_inst *inst);
int msm_comm_flush(struct msm_vidc_inst *inst, u32 flags);
int msm_comm_release_scratch_buffers(struct msm_vidc_inst *inst);
int msm_comm_release_persist_buffers(struct msm_vidc_inst *inst);
diff --git a/drivers/media/video/msm_vidc/msm_vidc_internal.h b/drivers/media/video/msm_vidc/msm_vidc_internal.h
index e9295a6..b274d13 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_internal.h
+++ b/drivers/media/video/msm_vidc/msm_vidc_internal.h
@@ -134,6 +134,11 @@
u32 freq;
};
+enum mem_type {
+ DDR_MEM = 0x1,
+ OCMEM_MEM = 0x2,
+};
+
struct core_clock {
char name[MAX_NAME_LENGTH];
struct clk *clk;
diff --git a/drivers/media/video/msm_vidc/vidc_hal.c b/drivers/media/video/msm_vidc/vidc_hal.c
index e449821..207bfe4 100644
--- a/drivers/media/video/msm_vidc/vidc_hal.c
+++ b/drivers/media/video/msm_vidc/vidc_hal.c
@@ -1954,6 +1954,7 @@
pkt->size = sizeof(struct hfi_cmd_session_set_buffers_packet) +
((buffer_info->num_buffers - 1) * sizeof(u32));
}
+ pkt->response_req = buffer_info->response_required;
buffer = get_hfi_buffer(buffer_info->buffer_type);
if (buffer)
pkt->buffer_type = buffer;
diff --git a/drivers/media/video/msm_vidc/vidc_hal_api.h b/drivers/media/video/msm_vidc/vidc_hal_api.h
index 9d20a31..3b83424 100644
--- a/drivers/media/video/msm_vidc/vidc_hal_api.h
+++ b/drivers/media/video/msm_vidc/vidc_hal_api.h
@@ -777,6 +777,12 @@
u32 align_device_addr;
u32 extradata_size;
u32 extradata_addr;
+ u32 response_required;
+};
+
+struct hal_buffer_info {
+ u32 buffer_addr;
+ u32 extra_data_addr;
};
struct vidc_frame_plane_config {
diff --git a/drivers/media/video/msm_vidc/vidc_hal_interrupt_handler.c b/drivers/media/video/msm_vidc/vidc_hal_interrupt_handler.c
index 200f5d3..abce25f 100644
--- a/drivers/media/video/msm_vidc/vidc_hal_interrupt_handler.c
+++ b/drivers/media/video/msm_vidc/vidc_hal_interrupt_handler.c
@@ -154,11 +154,14 @@
cmd_done.device_id = device->device_id;
device->callback(SYS_ERROR, &cmd_done);
}
-static void hal_process_session_error(struct hal_device *device)
+static void hal_process_session_error(struct hal_device *device,
+ 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.session_id = ((struct hal_session *) pkt->session_id)->
+ session_id;
device->callback(SESSION_ERROR, &cmd_done);
}
static void hal_process_event_notify(struct hal_device *device,
@@ -179,7 +182,7 @@
break;
case HFI_EVENT_SESSION_ERROR:
dprintk(VIDC_INFO, "HFI_EVENT_SESSION_ERROR");
- hal_process_session_error(device);
+ hal_process_session_error(device, pkt);
break;
case HFI_EVENT_SESSION_SEQUENCE_CHANGED:
dprintk(VIDC_INFO, "HFI_EVENT_SESSION_SEQUENCE_CHANGED");
@@ -729,6 +732,31 @@
device->callback(SESSION_RELEASE_RESOURCE_DONE, &cmd_done);
}
+static void hal_process_session_rel_buf_done(struct hal_device *device,
+ struct hfi_msg_session_release_buffers_done_packet *pkt)
+{
+ struct msm_vidc_cb_cmd_done cmd_done;
+ if (!pkt || pkt->size !=
+ sizeof(struct
+ hfi_msg_session_release_buffers_done_packet)) {
+ dprintk(VIDC_ERR, "bad packet/packet size: %d", pkt->size);
+ return;
+ }
+ memset(&cmd_done, 0, sizeof(struct msm_vidc_cb_cmd_done));
+ cmd_done.device_id = device->device_id;
+ cmd_done.size = sizeof(struct msm_vidc_cb_cmd_done);
+ cmd_done.session_id =
+ ((struct hal_session *) pkt->session_id)->session_id;
+ cmd_done.status = vidc_map_hal_err_status((u32)pkt->error_type);
+ if (pkt->rg_buffer_info) {
+ cmd_done.data = (void *) &pkt->rg_buffer_info;
+ cmd_done.size = sizeof(struct hfi_buffer_info);
+ } else {
+ dprintk(VIDC_ERR, "invalid payload in rel_buff_done\n");
+ }
+ device->callback(SESSION_RELEASE_BUFFER_DONE, &cmd_done);
+}
+
static void hal_process_session_end_done(struct hal_device *device,
struct hfi_msg_sys_session_end_done_packet *pkt)
{
@@ -867,6 +895,11 @@
hfi_msg_session_get_sequence_header_done_packet
*) msg_hdr);
break;
+ case HFI_MSG_SESSION_RELEASE_BUFFERS_DONE:
+ hal_process_session_rel_buf_done(device, (struct
+ hfi_msg_session_release_buffers_done_packet
+ *) msg_hdr);
+ break;
default:
dprintk(VIDC_ERR, "UNKNOWN_MSG_TYPE : %d", msg_hdr->packet);
break;
diff --git a/drivers/media/video/msm_wfd/enc-mfc-subdev.c b/drivers/media/video/msm_wfd/enc-mfc-subdev.c
index 45532a9..21fc719 100644
--- a/drivers/media/video/msm_wfd/enc-mfc-subdev.c
+++ b/drivers/media/video/msm_wfd/enc-mfc-subdev.c
@@ -40,6 +40,7 @@
int secure;
struct mem_region unqueued_op_bufs;
bool streaming;
+ enum venc_framerate_modes framerate_mode;
};
struct venc {
@@ -301,6 +302,8 @@
inst->cbdata = vmops->cbdata;
inst->secure = vmops->secure;
inst->streaming = false;
+ inst->framerate_mode = VENC_MODE_VFR;
+
if (vmops->secure) {
WFD_MSG_ERR("OPENING SECURE SESSION\n");
flags |= VCD_CP_SESSION;
@@ -1123,6 +1126,14 @@
return rc;
}
+static long venc_set_framerate_mode(struct v4l2_subdev *sd,
+ void *arg)
+{
+ struct venc_inst *inst = sd->dev_priv;
+ inst->framerate_mode = *(enum venc_framerate_modes *)arg;
+ return 0;
+}
+
static long venc_set_qp_value(struct video_client_ctx *client_ctx,
__s32 frametype, __s32 qp)
{
@@ -1400,6 +1411,51 @@
return rc;
}
+static long venc_set_vui_timing_info(struct video_client_ctx *client_ctx,
+ struct venc_inst *inst, __s32 flag)
+{
+ struct vcd_property_hdr vcd_property_hdr;
+ struct vcd_property_vui_timing_info_enable vui_timing_info_enable;
+
+ if (!client_ctx)
+ return -EINVAL;
+ if (inst->framerate_mode == VENC_MODE_VFR) {
+ WFD_MSG_ERR("VUI timing info not suported in VFR mode ");
+ return -EINVAL;
+ }
+ vcd_property_hdr.prop_id = VCD_I_ENABLE_VUI_TIMING_INFO;
+ vcd_property_hdr.sz =
+ sizeof(struct vcd_property_vui_timing_info_enable);
+ vui_timing_info_enable.vui_timing_info = flag;
+ return vcd_set_property(client_ctx->vcd_handle,
+ &vcd_property_hdr, &vui_timing_info_enable);
+}
+
+static long venc_get_vui_timing_info(struct video_client_ctx *client_ctx,
+ __s32 *flag)
+{
+ struct vcd_property_hdr vcd_property_hdr;
+ struct vcd_property_vui_timing_info_enable vui_timing_info_enable;
+ int rc = 0;
+
+ if (!client_ctx || !flag)
+ return -EINVAL;
+
+ vcd_property_hdr.prop_id = VCD_I_ENABLE_VUI_TIMING_INFO;
+ vcd_property_hdr.sz =
+ sizeof(struct vcd_property_vui_timing_info_enable);
+ rc = vcd_get_property(client_ctx->vcd_handle,
+ &vcd_property_hdr, &vui_timing_info_enable);
+
+ if (rc < 0) {
+ WFD_MSG_ERR("Failed getting property for VUI timing info");
+ return rc;
+ }
+
+ *flag = vui_timing_info_enable.vui_timing_info;
+ return rc;
+}
+
static long venc_set_header_mode(struct video_client_ctx *client_ctx,
__s32 mode)
{
@@ -2285,6 +2341,9 @@
case V4L2_CID_MPEG_VIDC_VIDEO_H264_AU_DELIMITER:
rc = venc_set_avc_delimiter(client_ctx, ctrl->value);
break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO:
+ rc = venc_set_vui_timing_info(client_ctx, inst, ctrl->value);
+ break;
case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE:
rc = venc_set_entropy_mode(client_ctx, ctrl->value);
break;
@@ -2359,6 +2418,9 @@
case V4L2_CID_MPEG_VIDC_VIDEO_H264_AU_DELIMITER:
rc = venc_get_avc_delimiter(client_ctx, &ctrl->value);
break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO:
+ rc = venc_get_vui_timing_info(client_ctx, &ctrl->value);
+ break;
default:
WFD_MSG_ERR("Get property not suported: %d\n", ctrl->id);
rc = -ENOTSUPP;
@@ -2503,6 +2565,9 @@
case ENC_MUNMAP:
rc = venc_munmap(sd, arg);
break;
+ case SET_FRAMERATE_MODE:
+ rc = venc_set_framerate_mode(sd, arg);
+ break;
default:
rc = -1;
break;
diff --git a/drivers/media/video/msm_wfd/enc-subdev.h b/drivers/media/video/msm_wfd/enc-subdev.h
index c6c854e..25373e4 100644
--- a/drivers/media/video/msm_wfd/enc-subdev.h
+++ b/drivers/media/video/msm_wfd/enc-subdev.h
@@ -20,6 +20,11 @@
#include <media/videobuf2-core.h>
#define VENC_MAGIC_IOCTL 'V'
+enum venc_framerate_modes {
+ VENC_MODE_CFR,
+ VENC_MODE_VFR,
+};
+
struct mem_region {
struct list_head list;
u8 *kvaddr;
@@ -101,6 +106,7 @@
#define ENCODE_FLUSH _IO('V', 24)
#define ENC_MMAP _IOWR('V', 25, struct mem_region_map *)
#define ENC_MUNMAP _IOWR('V', 26, struct mem_region_map *)
+#define SET_FRAMERATE_MODE _IO('V', 27)
extern int venc_init(struct v4l2_subdev *sd, u32 val);
extern int venc_load_fw(struct v4l2_subdev *sd);
diff --git a/drivers/media/video/msm_wfd/wfd-ioctl.c b/drivers/media/video/msm_wfd/wfd-ioctl.c
index 5f67a96..99dc0d0 100644
--- a/drivers/media/video/msm_wfd/wfd-ioctl.c
+++ b/drivers/media/video/msm_wfd/wfd-ioctl.c
@@ -240,6 +240,7 @@
int rc;
unsigned long flags;
struct mdp_buf_info mdp_buf = {0};
+ struct mem_region_map mmap_context = {0};
spin_lock_irqsave(&inst->inst_lock, flags);
if (inst->input_bufs_allocated) {
spin_unlock_irqrestore(&inst->inst_lock, flags);
@@ -249,7 +250,6 @@
spin_unlock_irqrestore(&inst->inst_lock, flags);
for (i = 0; i < VENC_INPUT_BUFFERS; ++i) {
- struct mem_region_map mmap_context = {0};
mpair = kzalloc(sizeof(*mpair), GFP_KERNEL);
enc_mregion = kzalloc(sizeof(*enc_mregion), GFP_KERNEL);
mdp_mregion = kzalloc(sizeof(*enc_mregion), GFP_KERNEL);
@@ -278,6 +278,10 @@
rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl,
SET_INPUT_BUFFER, (void *)enc_mregion);
+ if (rc) {
+ WFD_MSG_ERR("Setting enc input buffer failed\n");
+ goto set_input_fail;
+ }
/* map the buffer from encoder to mdp */
mdp_mregion->kvaddr = enc_mregion->kvaddr;
@@ -301,7 +305,7 @@
mdp_mregion->kvaddr = NULL;
mdp_mregion->paddr = NULL;
mdp_mregion->ion_handle = NULL;
- goto alloc_fail;
+ goto mdp_mmap_fail;
}
mdp_buf.inst = inst->mdp_inst;
@@ -314,34 +318,58 @@
((int)mdp_mregion->paddr + mdp_mregion->size),
mdp_mregion->kvaddr);
- INIT_LIST_HEAD(&mpair->list);
- mpair->enc = enc_mregion;
- mpair->mdp = mdp_mregion;
- list_add_tail(&mpair->list, &inst->input_mem_list);
-
rc = v4l2_subdev_call(&wfd_dev->mdp_sdev, core, ioctl,
MDP_Q_BUFFER, (void *)&mdp_buf);
if (rc) {
WFD_MSG_ERR("Unable to queue the"
" buffer to mdp\n");
- break;
+ goto mdp_q_fail;
} else {
wfd_stats_update(&inst->stats,
WFD_STAT_EVENT_MDP_QUEUE);
}
+
+ INIT_LIST_HEAD(&mpair->list);
+ mpair->enc = enc_mregion;
+ mpair->mdp = mdp_mregion;
+ list_add_tail(&mpair->list, &inst->input_mem_list);
+
}
+
rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl,
ALLOC_RECON_BUFFERS, NULL);
if (rc) {
WFD_MSG_ERR("Failed to allocate recon buffers\n");
- goto alloc_fail;
+ goto recon_alloc_fail;
}
return rc;
+ /*
+ * Clean up only the buffer that we failed in setting up.
+ * Caller will clean up the rest by calling free_input_buffers()
+ */
+mdp_q_fail:
+ memset(&mmap_context, 0, sizeof(mmap_context));
+ mmap_context.mregion = mdp_mregion;
+ mmap_context.ion_client = wfd_dev->ion_client;
+ mmap_context.cookie = inst->mdp_inst;
+ v4l2_subdev_call(&wfd_dev->mdp_sdev, core, ioctl,
+ MDP_MUNMAP, (void *)&mmap_context);
+mdp_mmap_fail:
+ v4l2_subdev_call(&wfd_dev->enc_sdev,
+ core, ioctl, FREE_INPUT_BUFFER,
+ (void *)enc_mregion);
+set_input_fail:
+ memset(&mmap_context, 0, sizeof(mmap_context));
+ mmap_context.ion_client = wfd_dev->ion_client;
+ mmap_context.mregion = enc_mregion;
+ v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl,
+ ENC_MUNMAP, &mmap_context);
alloc_fail:
kfree(mpair);
kfree(enc_mregion);
kfree(mdp_mregion);
+recon_alloc_fail:
return rc;
}
void wfd_free_input_buffers(struct wfd_device *wfd_dev,
@@ -1047,7 +1075,8 @@
struct v4l2_qcom_frameskip frameskip;
int64_t frame_interval, max_frame_interval;
void *extendedmode = NULL;
- enum vsg_modes mode = VSG_MODE_VFR;
+ enum vsg_modes vsg_mode = VSG_MODE_VFR;
+ enum venc_framerate_modes venc_mode = VENC_MODE_VFR;
if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
@@ -1069,6 +1098,7 @@
rc = -EINVAL;
goto set_parm_fail;
}
+ venc_mode = VENC_MODE_CFR;
frame_interval =
a->parm.capture.timeperframe.numerator * NSEC_PER_SEC /
a->parm.capture.timeperframe.denominator;
@@ -1097,7 +1127,7 @@
goto set_parm_fail;
max_frame_interval = (int64_t)frameskip.maxframeinterval;
- mode = VSG_MODE_VFR;
+ vsg_mode = VSG_MODE_VFR;
rc = v4l2_subdev_call(&wfd_dev->vsg_sdev, core,
ioctl, VSG_SET_MAX_FRAME_INTERVAL,
@@ -1107,19 +1137,23 @@
goto set_parm_fail;
rc = v4l2_subdev_call(&wfd_dev->vsg_sdev, core,
- ioctl, VSG_SET_MODE, &mode);
+ ioctl, VSG_SET_MODE, &vsg_mode);
if (rc)
goto set_parm_fail;
} else {
- mode = VSG_MODE_CFR;
+ vsg_mode = VSG_MODE_CFR;
rc = v4l2_subdev_call(&wfd_dev->vsg_sdev, core,
- ioctl, VSG_SET_MODE, &mode);
+ ioctl, VSG_SET_MODE, &vsg_mode);
if (rc)
goto set_parm_fail;
}
+ rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core,
+ ioctl, SET_FRAMERATE_MODE,
+ &venc_mode);
+
set_parm_fail:
return rc;
}
diff --git a/drivers/misc/tspp.c b/drivers/misc/tspp.c
index f310524..eebaab9 100644
--- a/drivers/misc/tspp.c
+++ b/drivers/misc/tspp.c
@@ -35,6 +35,8 @@
#include <mach/sps.h> /* BAM stuff */
#include <mach/gpio.h>
#include <linux/wakelock.h> /* Locking functions */
+#include <linux/timer.h> /* Timer services */
+#include <linux/jiffies.h> /* Jiffies counter */
#include <mach/dma.h>
#include <mach/msm_tspp.h>
#include <linux/debugfs.h>
@@ -49,11 +51,24 @@
#define TSPP_NUM_PRIORITIES 16
#define TSPP_NUM_KEYS 8
#define INVALID_CHANNEL 0xFFFFFFFF
-#define TSPP_SPS_DESCRIPTOR_COUNT 128
+
+/*
+ * BAM descriptor FIFO size (in number of descriptors).
+ * Max number of descriptors allowed by SPS which is 8K-1.
+ * Restrict it to half of this to save DMA memory.
+ */
+#define TSPP_SPS_DESCRIPTOR_COUNT (4 * 1024 - 1)
#define TSPP_PACKET_LENGTH 188
#define TSPP_MIN_BUFFER_SIZE (TSPP_PACKET_LENGTH)
-#define TSPP_MAX_BUFFER_SIZE (32 * 1024)
-#define TSPP_NUM_BUFFERS 64
+
+/* Max descriptor buffer size allowed by SPS */
+#define TSPP_MAX_BUFFER_SIZE (32 * 1024 - 1)
+
+/*
+ * Max allowed TSPP buffers/descriptors.
+ * If SPS desc FIFO holds X descriptors, we can queue up to X-1 descriptors.
+ */
+#define TSPP_NUM_BUFFERS (TSPP_SPS_DESCRIPTOR_COUNT - 1)
#define TSPP_TSIF_DEFAULT_TIME_LIMIT 60
#define SPS_DESCRIPTOR_SIZE 8
#define MIN_ACCEPTABLE_BUFFER_COUNT 2
@@ -307,6 +322,8 @@
#define CONTEXT_UNSPEC_LENGTH BIT(11)
#define CONTEXT_GET_CONT_COUNT(_a) ((_a >> 12) & 0xF)
+#define MSEC_TO_JIFFIES(msec) ((msec) * HZ / 1000)
+
struct tspp_pipe_performance_regs {
u32 tsp_total;
u32 ps_duplicate_tsp;
@@ -379,7 +396,8 @@
enum tspp_mode mode;
tspp_notifier *notifier; /* used only with kernel api */
void *notify_data; /* data to be passed with the notifier */
- u32 notify_timer; /* notification for partially filled buffers */
+ u32 expiration_period_ms; /* notification on partially filled buffers */
+ struct timer_list expiration_timer;
tspp_memfree *memfree; /* user defined memory free function */
void *user_info; /* user cookie passed to memory alloc/free function */
};
@@ -539,6 +557,14 @@
tasklet_schedule(&pdev->tlet);
}
+static void tspp_expiration_timer(unsigned long data)
+{
+ struct tspp_device *pdev = (struct tspp_device *)data;
+
+ if (pdev)
+ tasklet_schedule(&pdev->tlet);
+}
+
/*** tasklet ***/
static void tspp_sps_complete_tlet(unsigned long data)
{
@@ -553,9 +579,14 @@
for (i = 0; i < TSPP_NUM_CHANNELS; i++) {
complete = 0;
channel = &device->channels[i];
+
if (!channel->used || !channel->waiting)
continue;
+ /* stop the expiration timer */
+ if (channel->expiration_period_ms)
+ del_timer(&channel->expiration_timer);
+
/* get completions */
while (channel->waiting->state == TSPP_BUF_STATE_WAITING) {
if (sps_get_iovec(channel->pipe, &iovec) != 0) {
@@ -593,6 +624,13 @@
channel->notifier(channel->id,
channel->notify_data);
}
+
+ /* restart expiration timer */
+ if (channel->expiration_period_ms)
+ mod_timer(&channel->expiration_timer,
+ jiffies +
+ MSEC_TO_JIFFIES(
+ channel->expiration_period_ms));
}
spin_unlock_irqrestore(&device->spinlock, flags);
@@ -897,7 +935,7 @@
/* generate interrupt according to requested frequency */
if (buffer->desc.id % channel->int_freq == channel->int_freq-1)
- flags = SPS_IOVEC_FLAG_INT | SPS_IOVEC_FLAG_EOB;
+ flags = SPS_IOVEC_FLAG_INT;
/* start the transfer */
rc = sps_transfer_one(channel->pipe,
@@ -1034,7 +1072,7 @@
channel->mode = TSPP_MODE_DISABLED;
channel->notifier = NULL;
channel->notify_data = NULL;
- channel->notify_timer = 0;
+ channel->expiration_period_ms = 0;
channel->memfree = NULL;
channel->user_info = NULL;
init_waitqueue_head(&channel->in_queue);
@@ -1394,10 +1432,11 @@
SPS_O_AUTO_ENABLE | /* connection is auto-enabled */
SPS_O_STREAMING | /* streaming mode */
SPS_O_DESC_DONE | /* interrupt on end of descriptor */
- SPS_O_ACK_TRANSFERS; /* must use sps_get_iovec() */
+ SPS_O_ACK_TRANSFERS | /* must use sps_get_iovec() */
+ SPS_O_HYBRID; /* Read actual descriptors in sps_get_iovec() */
config->src_pipe_index = channel->id;
config->desc.size =
- (TSPP_SPS_DESCRIPTOR_COUNT + 1) * SPS_DESCRIPTOR_SIZE;
+ TSPP_SPS_DESCRIPTOR_COUNT * SPS_DESCRIPTOR_SIZE;
config->desc.base = dma_alloc_coherent(NULL,
config->desc.size,
&config->desc.phys_base,
@@ -1428,6 +1467,11 @@
goto err_event;
}
+ init_timer(&channel->expiration_timer);
+ channel->expiration_timer.function = tspp_expiration_timer;
+ channel->expiration_timer.data = (unsigned long)pdev;
+ channel->expiration_timer.expires = 0xffffffffL;
+
rc = pm_runtime_get(&pdev->pdev->dev);
if (rc < 0) {
dev_err(&pdev->pdev->dev,
@@ -1482,9 +1526,12 @@
if (!channel->used)
return 0;
+ if (channel->expiration_period_ms)
+ del_timer(&channel->expiration_timer);
+
channel->notifier = NULL;
channel->notify_data = NULL;
- channel->notify_timer = 0;
+ channel->expiration_period_ms = 0;
config = &channel->config;
pdev = channel->pdev;
@@ -1833,7 +1880,8 @@
channel = &pdev->channels[channel_id];
channel->notifier = pNotify;
channel->notify_data = userdata;
- channel->notify_timer = timer_ms;
+ channel->expiration_period_ms = timer_ms;
+
return 0;
}
EXPORT_SYMBOL(tspp_register_notification);
@@ -2113,6 +2161,13 @@
channel->read = channel->data;
channel->locked = channel->data;
+ /* Now that buffers are scheduled to HW, kick data expiration timer */
+ if (channel->expiration_period_ms)
+ mod_timer(&channel->expiration_timer,
+ jiffies +
+ MSEC_TO_JIFFIES(
+ channel->expiration_period_ms));
+
return 0;
}
EXPORT_SYMBOL(tspp_allocate_buffers);
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 9fbce4b..ae68060 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -298,13 +298,33 @@
{
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)
- md->queue.num_wr_reqs_to_start_packing = value;
+ if (value >= 0) {
+ md->queue.num_wr_reqs_to_start_packing =
+ min_t(int, value, (int)card->ext_csd.max_packed_writes);
+
+ pr_debug("%s: trigger to pack: new value = %d",
+ mmc_hostname(card->host),
+ md->queue.num_wr_reqs_to_start_packing);
+ } else {
+ pr_err("%s: value %d is not valid. old value remains = %d",
+ mmc_hostname(card->host), value,
+ md->queue.num_wr_reqs_to_start_packing);
+ ret = -EINVAL;
+ }
+
+exit:
mmc_blk_put(md);
- return count;
+ return ret;
}
static ssize_t
@@ -317,13 +337,13 @@
int ret;
if (!card)
- return -EINVAL;
-
- min_sectors_to_check_bkops_status =
- card->bkops_info.min_sectors_to_queue_delayed_work;
-
- ret = snprintf(buf, PAGE_SIZE, "%d\n",
- min_sectors_to_check_bkops_status);
+ ret = -EINVAL;
+ else {
+ min_sectors_to_check_bkops_status =
+ card->bkops_info.min_sectors_to_queue_delayed_work;
+ ret = snprintf(buf, PAGE_SIZE, "%d\n",
+ min_sectors_to_check_bkops_status);
+ }
mmc_blk_put(md);
return ret;
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index 8897f18a..8eb787d 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -210,7 +210,9 @@
mq->mqrq_cur = mqrq_cur;
mq->mqrq_prev = mqrq_prev;
mq->queue->queuedata = mq;
- mq->num_wr_reqs_to_start_packing = DEFAULT_NUM_REQS_TO_START_PACK;
+ mq->num_wr_reqs_to_start_packing =
+ min_t(int, (int)card->ext_csd.max_packed_writes,
+ DEFAULT_NUM_REQS_TO_START_PACK);
blk_queue_prep_rq(mq->queue, mmc_prep_request);
queue_flag_set_unlocked(QUEUE_FLAG_NONROT, mq->queue);
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 48516b6..f91ba89 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -29,6 +29,7 @@
#include <linux/wakelock.h>
#include <linux/pm.h>
#include <linux/slab.h>
+#include <linux/jiffies.h>
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
@@ -44,6 +45,8 @@
#include "sd_ops.h"
#include "sdio_ops.h"
+static void mmc_clk_scaling(struct mmc_host *host, bool from_wq);
+
/*
* Background operations can take a long time, depending on the housekeeping
* operations the card has to perform.
@@ -171,6 +174,10 @@
#ifdef CONFIG_MMC_PERF_PROFILING
ktime_t diff;
#endif
+ if (host->card && host->clk_scaling.enable)
+ host->clk_scaling.busy_time_us +=
+ ktime_to_us(ktime_sub(ktime_get(),
+ host->clk_scaling.start_busy));
if (err && cmd->retries && mmc_host_is_spi(host)) {
if (cmd->resp[0] & R1_SPI_ILLEGAL_COMMAND)
@@ -300,6 +307,19 @@
}
mmc_host_clk_hold(host);
led_trigger_event(host->led, LED_FULL);
+
+ if (host->card && host->clk_scaling.enable) {
+ /*
+ * Check if we need to scale the clocks. Clocks
+ * will be scaled up immediately if necessary
+ * conditions are satisfied. Scaling down the
+ * frequency will be done after current thread
+ * releases host.
+ */
+ mmc_clk_scaling(host, false);
+ host->clk_scaling.start_busy = ktime_get();
+ }
+
host->ops->request(host, mrq);
}
@@ -2286,6 +2306,289 @@
}
EXPORT_SYMBOL(mmc_hw_reset_check);
+/**
+ * mmc_reset_clk_scale_stats() - reset clock scaling statistics
+ * @host: pointer to mmc host structure
+ */
+void mmc_reset_clk_scale_stats(struct mmc_host *host)
+{
+ host->clk_scaling.busy_time_us = 0;
+ host->clk_scaling.window_time = jiffies;
+}
+EXPORT_SYMBOL_GPL(mmc_reset_clk_scale_stats);
+
+/**
+ * mmc_get_max_frequency() - get max. frequency supported
+ * @host: pointer to mmc host structure
+ *
+ * Returns max. frequency supported by card/host. If the
+ * timing mode is SDR50/SDR104/HS200/DDR50 return appropriate
+ * max. frequency in these modes else, use the current frequency.
+ * Also, allow host drivers to overwrite the frequency in case
+ * they support "get_max_frequency" host ops.
+ */
+unsigned long mmc_get_max_frequency(struct mmc_host *host)
+{
+ unsigned long freq;
+
+ if (host->ops && host->ops->get_max_frequency) {
+ freq = host->ops->get_max_frequency(host);
+ goto out;
+ }
+
+ switch (host->ios.timing) {
+ case MMC_TIMING_UHS_SDR50:
+ freq = UHS_SDR50_MAX_DTR;
+ break;
+ case MMC_TIMING_UHS_SDR104:
+ freq = UHS_SDR104_MAX_DTR;
+ break;
+ case MMC_TIMING_MMC_HS200:
+ freq = MMC_HS200_MAX_DTR;
+ break;
+ case MMC_TIMING_UHS_DDR50:
+ freq = UHS_DDR50_MAX_DTR;
+ break;
+ default:
+ mmc_host_clk_hold(host);
+ freq = host->ios.clock;
+ mmc_host_clk_release(host);
+ break;
+ }
+
+out:
+ return freq;
+}
+EXPORT_SYMBOL_GPL(mmc_get_max_frequency);
+
+/**
+ * mmc_get_min_frequency() - get min. frequency supported
+ * @host: pointer to mmc host structure
+ *
+ * Returns min. frequency supported by card/host which doesn't impair
+ * performance for most usecases. If the timing mode is SDR50/SDR104/HS200
+ * return 50MHz value. If timing mode is DDR50 return 25MHz so that
+ * throughput would be equivalent to SDR50/SDR104 in 50MHz. Also, allow
+ * host drivers to overwrite the frequency in case they support
+ * "get_min_frequency" host ops.
+ */
+static unsigned long mmc_get_min_frequency(struct mmc_host *host)
+{
+ unsigned long freq;
+
+ if (host->ops && host->ops->get_min_frequency) {
+ freq = host->ops->get_min_frequency(host);
+ goto out;
+ }
+
+ switch (host->ios.timing) {
+ case MMC_TIMING_UHS_SDR50:
+ case MMC_TIMING_UHS_SDR104:
+ freq = UHS_SDR25_MAX_DTR;
+ break;
+ case MMC_TIMING_MMC_HS200:
+ freq = MMC_HIGH_52_MAX_DTR;
+ break;
+ case MMC_TIMING_UHS_DDR50:
+ freq = UHS_DDR50_MAX_DTR / 2;
+ break;
+ default:
+ mmc_host_clk_hold(host);
+ freq = host->ios.clock;
+ mmc_host_clk_release(host);
+ break;
+ }
+
+out:
+ return freq;
+}
+
+/*
+ * Scale down clocks to minimum frequency supported.
+ * The delayed work re-arms itself in case it cannot
+ * claim the host.
+ */
+static void mmc_clk_scale_work(struct work_struct *work)
+{
+ struct mmc_host *host = container_of(work, struct mmc_host,
+ clk_scaling.work.work);
+
+ if (!host->card || !host->bus_ops ||
+ !host->bus_ops->change_bus_speed ||
+ !host->clk_scaling.enable || !host->ios.clock)
+ goto out;
+
+ if (!mmc_try_claim_host(host)) {
+ /* retry after a timer tick */
+ queue_delayed_work(system_nrt_wq, &host->clk_scaling.work, 1);
+ goto out;
+ }
+
+ mmc_clk_scaling(host, true);
+ mmc_release_host(host);
+out:
+ return;
+}
+
+
+/**
+ * mmc_clk_scaling() - clock scaling decision algorithm
+ * @host: pointer to mmc host structure
+ * @from_wq: variable that specifies the context in which
+ * mmc_clk_scaling() is called.
+ *
+ * Calculate load percentage based on host busy time
+ * and total sampling interval and decide clock scaling
+ * based on scale up/down thresholds.
+ * If load is greater than up threshold increase the
+ * frequency to maximum as supported by host. Else,
+ * if load is less than down threshold, scale down the
+ * frequency to minimum supported by the host. Otherwise,
+ * retain current frequency and do nothing.
+ */
+static void mmc_clk_scaling(struct mmc_host *host, bool from_wq)
+{
+ int err = 0;
+ struct mmc_card *card = host->card;
+ unsigned long total_time_ms = 0;
+ unsigned long busy_time_ms = 0;
+ unsigned long freq;
+ unsigned int up_threshold = host->clk_scaling.up_threshold;
+ unsigned int down_threshold = host->clk_scaling.down_threshold;
+ bool queue_scale_down_work = false;
+
+ if (!card || !host->bus_ops || !host->bus_ops->change_bus_speed) {
+ pr_err("%s: %s: invalid entry\n", mmc_hostname(host), __func__);
+ goto out;
+ }
+
+ /* Check if the clocks are already gated. */
+ if (!host->ios.clock)
+ goto out;
+
+ if (time_is_after_jiffies(host->clk_scaling.window_time +
+ msecs_to_jiffies(host->clk_scaling.polling_delay_ms)))
+ goto out;
+
+ /* handle time wrap */
+ total_time_ms = jiffies_to_msecs((long)jiffies -
+ (long)host->clk_scaling.window_time);
+
+ /* Check if we re-enter during clock switching */
+ if (unlikely(host->clk_scaling.in_progress))
+ goto out;
+
+ host->clk_scaling.in_progress = true;
+
+ busy_time_ms = host->clk_scaling.busy_time_us / USEC_PER_MSEC;
+
+ freq = host->clk_scaling.curr_freq;
+
+ /*
+ * Note that the max. and min. frequency should be based
+ * on the timing modes that the card and host handshake
+ * during initialization.
+ */
+ if ((busy_time_ms * 100 > total_time_ms * up_threshold)) {
+ freq = mmc_get_max_frequency(host);
+ } else if ((busy_time_ms * 100 < total_time_ms * down_threshold)) {
+ if (!from_wq)
+ queue_scale_down_work = true;
+ freq = mmc_get_min_frequency(host);
+ }
+
+ if (freq != host->clk_scaling.curr_freq) {
+ if (!queue_scale_down_work) {
+ if (!from_wq)
+ cancel_delayed_work_sync(
+ &host->clk_scaling.work);
+ err = host->bus_ops->change_bus_speed(host, &freq);
+ if (!err)
+ host->clk_scaling.curr_freq = freq;
+ else
+ pr_err("%s: %s: failed (%d) at freq=%lu\n",
+ mmc_hostname(host), __func__, err,
+ freq);
+ } else {
+ /*
+ * We hold claim host while queueing the scale down
+ * work, so delay atleast one timer tick to release
+ * host and re-claim while scaling down the clocks.
+ */
+ queue_delayed_work(system_nrt_wq,
+ &host->clk_scaling.work, 1);
+ host->clk_scaling.in_progress = false;
+ goto out;
+ }
+ }
+
+ mmc_reset_clk_scale_stats(host);
+ host->clk_scaling.in_progress = false;
+out:
+ return;
+}
+
+/**
+ * mmc_disable_clk_scaling() - Disable clock scaling
+ * @host: pointer to mmc host structure
+ *
+ * Disables clock scaling temporarily by setting enable
+ * property to false. To disable completely, one also
+ * need to set 'initialized' variable to false.
+ */
+void mmc_disable_clk_scaling(struct mmc_host *host)
+{
+ cancel_delayed_work_sync(&host->clk_scaling.work);
+ host->clk_scaling.enable = false;
+}
+EXPORT_SYMBOL_GPL(mmc_disable_clk_scaling);
+
+/**
+ * mmc_can_scale_clk() - Check if clock scaling is initialized
+ * @host: pointer to mmc host structure
+ */
+bool mmc_can_scale_clk(struct mmc_host *host)
+{
+ return host->clk_scaling.initialized;
+}
+EXPORT_SYMBOL_GPL(mmc_can_scale_clk);
+
+/**
+ * mmc_init_clk_scaling() - Initialize clock scaling
+ * @host: pointer to mmc host structure
+ *
+ * Initialize clock scaling for supported hosts.
+ * It is assumed that the caller ensure clock is
+ * running at maximum possible frequency before
+ * calling this function.
+ */
+void mmc_init_clk_scaling(struct mmc_host *host)
+{
+ if (!host->card || !(host->caps2 & MMC_CAP2_CLK_SCALE))
+ return;
+
+ INIT_DELAYED_WORK(&host->clk_scaling.work, mmc_clk_scale_work);
+ host->clk_scaling.curr_freq = mmc_get_max_frequency(host);
+ mmc_reset_clk_scale_stats(host);
+ host->clk_scaling.enable = true;
+ host->clk_scaling.initialized = true;
+ pr_debug("%s: clk scaling enabled\n", mmc_hostname(host));
+}
+EXPORT_SYMBOL_GPL(mmc_init_clk_scaling);
+
+/**
+ * mmc_exit_clk_scaling() - Disable clock scaling
+ * @host: pointer to mmc host structure
+ *
+ * Disable clock scaling permanently.
+ */
+void mmc_exit_clk_scaling(struct mmc_host *host)
+{
+ cancel_delayed_work_sync(&host->clk_scaling.work);
+ memset(&host->clk_scaling, 0, sizeof(host->clk_scaling));
+}
+EXPORT_SYMBOL_GPL(mmc_exit_clk_scaling);
+
static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)
{
host->f_init = freq;
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
index de87e82..c85f5aa 100644
--- a/drivers/mmc/core/core.h
+++ b/drivers/mmc/core/core.h
@@ -81,5 +81,11 @@
void mmc_add_card_debugfs(struct mmc_card *card);
void mmc_remove_card_debugfs(struct mmc_card *card);
+extern void mmc_disable_clk_scaling(struct mmc_host *host);
+extern bool mmc_can_scale_clk(struct mmc_host *host);
+extern void mmc_init_clk_scaling(struct mmc_host *host);
+extern void mmc_exit_clk_scaling(struct mmc_host *host);
+extern void mmc_reset_clk_scale_stats(struct mmc_host *host);
+extern unsigned long mmc_get_max_frequency(struct mmc_host *host);
#endif
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index 850872d..d30f10f 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -163,6 +163,9 @@
if (host->clk_gated) {
spin_unlock_irqrestore(&host->clk_lock, flags);
mmc_ungate_clock(host);
+
+ /* Reset clock scaling stats as host is out of idle */
+ mmc_reset_clk_scale_stats(host);
spin_lock_irqsave(&host->clk_lock, flags);
pr_debug("%s: ungated MCI clock\n", mmc_hostname(host));
}
@@ -446,6 +449,10 @@
#endif
mmc_host_clk_sysfs_init(host);
+ host->clk_scaling.up_threshold = 35;
+ host->clk_scaling.down_threshold = 5;
+ host->clk_scaling.polling_delay_ms = 100;
+
err = sysfs_create_group(&host->parent->kobj, &dev_attr_grp);
if (err)
pr_err("%s: failed to create sysfs group with err %d\n",
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index a98ed3d..d3dc133 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1460,6 +1460,7 @@
mmc_claim_host(host);
host->card = NULL;
+ mmc_exit_clk_scaling(host);
mmc_release_host(host);
}
@@ -1510,6 +1511,12 @@
BUG_ON(!host);
BUG_ON(!host->card);
+ /*
+ * Disable clock scaling before suspend and enable it after resume so
+ * as to avoid clock scaling decisions kicking in during this window.
+ */
+ mmc_disable_clk_scaling(host);
+
mmc_claim_host(host);
if (mmc_can_poweroff_notify(host->card))
err = mmc_poweroff_notify(host->card, EXT_CSD_POWER_OFF_SHORT);
@@ -1540,6 +1547,13 @@
err = mmc_init_card(host, host->ocr, host->card);
mmc_release_host(host);
+ /*
+ * We have done full initialization of the card,
+ * reset the clk scale stats and current frequency.
+ */
+ if (mmc_can_scale_clk(host))
+ mmc_init_clk_scaling(host);
+
return err;
}
@@ -1547,11 +1561,17 @@
{
int ret;
+ /* Disable clk scaling to avoid switching frequencies intermittently */
+ mmc_disable_clk_scaling(host);
+
host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
mmc_claim_host(host);
ret = mmc_init_card(host, host->ocr, host->card);
mmc_release_host(host);
+ if (mmc_can_scale_clk(host))
+ mmc_init_clk_scaling(host);
+
return ret;
}
@@ -1686,6 +1706,10 @@
if (err)
goto remove_card;
+ /* Initialize clock scaling only for high frequency modes */
+ if (mmc_card_hs200(host->card) || mmc_card_ddr_mode(host->card))
+ mmc_init_clk_scaling(host);
+
return 0;
remove_card:
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 8661929..318d590 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -1121,6 +1121,7 @@
mmc_claim_host(host);
host->card = NULL;
+ mmc_exit_clk_scaling(host);
mmc_release_host(host);
}
@@ -1187,6 +1188,12 @@
BUG_ON(!host);
BUG_ON(!host->card);
+ /*
+ * Disable clock scaling before suspend and enable it after resume so
+ * as to avoid clock scaling decisions kicking in during this window.
+ */
+ mmc_disable_clk_scaling(host);
+
mmc_claim_host(host);
if (!mmc_host_is_spi(host))
mmc_deselect_cards(host);
@@ -1235,6 +1242,13 @@
#endif
mmc_release_host(host);
+ /*
+ * We have done full initialization of the card,
+ * reset the clk scale stats and current frequency.
+ */
+ if (mmc_can_scale_clk(host))
+ mmc_init_clk_scaling(host);
+
return err;
}
@@ -1242,11 +1256,17 @@
{
int ret;
+ /* Disable clk scaling to avoid switching frequencies intermittently */
+ mmc_disable_clk_scaling(host);
+
host->card->state &= ~MMC_STATE_HIGHSPEED;
mmc_claim_host(host);
ret = mmc_sd_init_card(host, host->ocr, host->card);
mmc_release_host(host);
+ if (mmc_can_scale_clk(host))
+ mmc_init_clk_scaling(host);
+
return ret;
}
@@ -1385,6 +1405,10 @@
if (err)
goto remove_card;
+ /* Initialize clock scaling only for high frequency modes */
+ if (mmc_card_uhs(host->card))
+ mmc_init_clk_scaling(host);
+
return 0;
remove_card:
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index 81a4ba0..4e76f61 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -162,10 +162,7 @@
if (ret)
goto out;
- if (card->host->caps &
- (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
- MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 |
- MMC_CAP_UHS_DDR50)) {
+ if (mmc_host_uhs(card->host)) {
if (data & SDIO_UHS_DDR50)
card->sw_caps.sd3_bus_mode
|= SD_MODE_UHS_DDR50;
@@ -480,8 +477,7 @@
* If the host doesn't support any of the UHS-I modes, fallback on
* default speed.
*/
- if (!(card->host->caps & (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
- MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_DDR50)))
+ if (!mmc_host_uhs(card->host))
return 0;
bus_speed = SDIO_SPEED_SDR12;
@@ -491,23 +487,27 @@
bus_speed = SDIO_SPEED_SDR104;
timing = MMC_TIMING_UHS_SDR104;
card->sw_caps.uhs_max_dtr = UHS_SDR104_MAX_DTR;
+ card->sd_bus_speed = UHS_SDR104_BUS_SPEED;
} else if ((card->host->caps & MMC_CAP_UHS_DDR50) &&
(card->sw_caps.sd3_bus_mode & SD_MODE_UHS_DDR50)) {
bus_speed = SDIO_SPEED_DDR50;
timing = MMC_TIMING_UHS_DDR50;
card->sw_caps.uhs_max_dtr = UHS_DDR50_MAX_DTR;
+ card->sd_bus_speed = UHS_DDR50_BUS_SPEED;
} else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
MMC_CAP_UHS_SDR50)) && (card->sw_caps.sd3_bus_mode &
SD_MODE_UHS_SDR50)) {
bus_speed = SDIO_SPEED_SDR50;
timing = MMC_TIMING_UHS_SDR50;
card->sw_caps.uhs_max_dtr = UHS_SDR50_MAX_DTR;
+ card->sd_bus_speed = UHS_SDR50_BUS_SPEED;
} else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25)) &&
(card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR25)) {
bus_speed = SDIO_SPEED_SDR25;
timing = MMC_TIMING_UHS_SDR25;
card->sw_caps.uhs_max_dtr = UHS_SDR25_MAX_DTR;
+ card->sd_bus_speed = UHS_SDR25_BUS_SPEED;
} else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25 |
MMC_CAP_UHS_SDR12)) && (card->sw_caps.sd3_bus_mode &
@@ -515,6 +515,7 @@
bus_speed = SDIO_SPEED_SDR12;
timing = MMC_TIMING_UHS_SDR12;
card->sw_caps.uhs_max_dtr = UHS_SDR12_MAX_DTR;
+ card->sd_bus_speed = UHS_SDR12_BUS_SPEED;
}
err = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_SPEED, 0, &speed);
@@ -653,11 +654,7 @@
* systems that claim 1.8v signalling in fact do not support
* it.
*/
- if ((ocr & R4_18V_PRESENT) &&
- (host->caps &
- (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
- MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 |
- MMC_CAP_UHS_DDR50))) {
+ if ((ocr & R4_18V_PRESENT) && mmc_host_uhs(host)) {
err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180,
true);
if (err) {
@@ -964,10 +961,12 @@
mmc_claim_host(host);
/* No need to reinitialize powered-resumed nonremovable cards */
- if (mmc_card_is_removable(host) || !mmc_card_keep_power(host))
+ if (mmc_card_is_removable(host) || !mmc_card_keep_power(host)) {
+ sdio_reset(host);
+ mmc_go_idle(host);
err = mmc_sdio_init_card(host, host->ocr, host->card,
mmc_card_keep_power(host));
- else if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) {
+ } else if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) {
/* We may have switched to 1-bit mode during suspend */
err = sdio_enable_4bit_bus(host->card);
if (err > 0) {
@@ -1054,6 +1053,10 @@
goto out;
}
+ if (mmc_host_uhs(host))
+ /* to query card if 1.8V signalling is supported */
+ host->ocr |= R4_18V_PRESENT;
+
ret = mmc_sdio_init_card(host, host->ocr, host->card,
mmc_card_keep_power(host));
if (!ret && host->sdio_irqs)
@@ -1119,6 +1122,10 @@
/*
* Detect and init the card.
*/
+ if (mmc_host_uhs(host))
+ /* to query card if 1.8V signalling is supported */
+ host->ocr |= R4_18V_PRESENT;
+
err = mmc_sdio_init_card(host, host->ocr, NULL, 0);
if (err) {
if (err == -EAGAIN) {
@@ -1236,79 +1243,6 @@
int sdio_reset_comm(struct mmc_card *card)
{
- struct mmc_host *host = card->host;
- u32 ocr;
- int err;
-
- printk("%s():\n", __func__);
- mmc_claim_host(host);
-
- mmc_go_idle(host);
-
- mmc_set_clock(host, host->f_min);
-
- err = mmc_send_io_op_cond(host, 0, &ocr);
- if (err)
- goto err;
-
- host->ocr = mmc_select_voltage(host, ocr);
- if (!host->ocr) {
- err = -EINVAL;
- goto err;
- }
-
- err = mmc_send_io_op_cond(host, host->ocr, &ocr);
- if (err)
- goto err;
-
- if (mmc_host_is_spi(host)) {
- err = mmc_spi_set_crc(host, use_spi_crc);
- if (err)
- goto err;
- }
-
- if (!mmc_host_is_spi(host)) {
- err = mmc_send_relative_addr(host, &card->rca);
- if (err)
- goto err;
- mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL);
- }
- if (!mmc_host_is_spi(host)) {
- err = mmc_select_card(card);
- if (err)
- goto err;
- }
-
- /*
- * Switch to high-speed (if supported).
- */
- err = sdio_enable_hs(card);
- if (err > 0)
- mmc_sd_go_highspeed(card);
- else if (err)
- goto err;
-
- /*
- * Change to the card's maximum speed.
- */
- mmc_set_clock(host, mmc_sdio_get_max_clock(card));
-
- err = sdio_enable_4bit_bus(card);
- if (err > 0) {
- if (host->caps & MMC_CAP_8_BIT_DATA)
- mmc_set_bus_width(host, MMC_BUS_WIDTH_8);
- else if (host->caps & MMC_CAP_4_BIT_DATA)
- mmc_set_bus_width(host, MMC_BUS_WIDTH_4);
- }
- else if (err)
- goto err;
-
- mmc_release_host(host);
- return 0;
-err:
- printk("%s: Error resetting SDIO communications (%d)\n",
- mmc_hostname(host), err);
- mmc_release_host(host);
- return err;
+ return mmc_power_restore_host(card->host);
}
EXPORT_SYMBOL(sdio_reset_comm);
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index 4f7d4c3..c8b47b9 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -162,6 +162,7 @@
static int msmsdcc_runtime_resume(struct device *dev);
static int msmsdcc_dt_get_array(struct device *dev, const char *prop_name,
u32 **out_array, int *len, int size);
+static int msmsdcc_execute_tuning(struct mmc_host *mmc, u32 opcode);
static inline unsigned short msmsdcc_get_nr_sg(struct msmsdcc_host *host)
{
@@ -1201,8 +1202,9 @@
*c |= MCI_CSPM_DATCMD;
/* Check if AUTO CMD19/CMD21 is required or not? */
- if (host->tuning_needed &&
- (host->en_auto_cmd19 || host->en_auto_cmd21)) {
+ if (host->tuning_needed && (cmd->mrq->data &&
+ (cmd->mrq->data->flags & MMC_DATA_READ)) &&
+ (host->en_auto_cmd19 || host->en_auto_cmd21)) {
/*
* For open ended block read operation (without CMD23),
* AUTO_CMD19/AUTO_CMD21 bit should be set while sending
@@ -1216,7 +1218,8 @@
MMC_READ_MULTIPLE_BLOCK) ||
(!host->curr.mrq->sbc &&
(cmd->opcode == MMC_READ_SINGLE_BLOCK ||
- cmd->opcode == MMC_READ_MULTIPLE_BLOCK))) {
+ cmd->opcode == MMC_READ_MULTIPLE_BLOCK ||
+ cmd->opcode == SD_IO_RW_EXTENDED))) {
msmsdcc_enable_cdr_cm_sdc4_dll(host);
if (host->en_auto_cmd19 &&
host->mmc->ios.timing == MMC_TIMING_UHS_SDR104)
@@ -1416,6 +1419,10 @@
else
data->error = -ETIMEDOUT;
}
+ /* In case of DATA CRC/timeout error, execute tuning again */
+ if (host->tuning_needed && !host->tuning_in_progress)
+ host->tuning_done = false;
+
} else if (status & MCI_RXOVERRUN) {
pr_err("%s: RX overrun\n", mmc_hostname(host->mmc));
data->error = -EIO;
@@ -1768,6 +1775,8 @@
msmsdcc_dump_sdcc_state(host);
/* Execute full tuning in case of CRC errors */
host->saved_tuning_phase = INVALID_TUNING_PHASE;
+ if (host->tuning_needed)
+ host->tuning_done = false;
cmd->error = -EILSEQ;
}
@@ -1864,9 +1873,10 @@
*/
wake_lock(&host->sdio_wlock);
} else {
- if (mmc->card && !mmc_card_sdio(mmc->card)) {
- WARN(1, "%s: SDCC core interrupt received for non-SDIO cards when SDCC clocks are off\n",
- mmc_hostname(mmc));
+ if (!mmc->card || (mmc->card &&
+ !mmc_card_sdio(mmc->card))) {
+ pr_warning("%s: SDCC core interrupt received for non-SDIO cards when SDCC clocks are off\n",
+ mmc_hostname(mmc));
ret = 1;
break;
}
@@ -1898,9 +1908,10 @@
#endif
if (status & MCI_SDIOINTROPE) {
- if (mmc->card && !mmc_card_sdio(mmc->card)) {
- WARN(1, "%s: SDIO interrupt received for non-SDIO card\n",
- mmc_hostname(mmc));
+ if (!mmc->card || (mmc->card &&
+ !mmc_card_sdio(mmc->card))) {
+ pr_warning("%s: SDIO interrupt (SDIOINTROPE) received for non-SDIO card\n",
+ mmc_hostname(mmc));
ret = 1;
break;
}
@@ -2147,6 +2158,22 @@
}
}
+ /*
+ * Check if DLL retuning is required? If yes, perform it here before
+ * starting new request.
+ */
+ if (host->tuning_needed && !host->tuning_in_progress &&
+ !host->tuning_done) {
+ pr_debug("%s: %s: execute_tuning for timing mode = %d\n",
+ mmc_hostname(mmc), __func__, host->mmc->ios.timing);
+ if (host->mmc->ios.timing == MMC_TIMING_UHS_SDR104)
+ msmsdcc_execute_tuning(mmc,
+ MMC_SEND_TUNING_BLOCK);
+ else if (host->mmc->ios.timing == MMC_TIMING_MMC_HS200)
+ msmsdcc_execute_tuning(mmc,
+ MMC_SEND_TUNING_BLOCK_HS200);
+ }
+
spin_lock_irqsave(&host->lock, flags);
if (host->eject) {
@@ -3343,10 +3370,24 @@
/* Card clock frequency must be > 100MHz to enable tuning */
clk |= (4 << 14);
host->tuning_needed = 1;
- } else if (ios->timing == MMC_TIMING_UHS_DDR50) {
- clk |= (3 << 14);
} else {
- clk |= (2 << 14); /* feedback clock */
+ if (ios->timing == MMC_TIMING_UHS_DDR50)
+ clk |= (3 << 14);
+ else
+ clk |= (2 << 14); /* feedback clock */
+
+ host->tuning_done = false;
+ if (atomic_read(&host->clks_on)) {
+ /* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
+ writel_relaxed((readl_relaxed(host->base +
+ MCI_DLL_CONFIG) | MCI_DLL_RST),
+ host->base + MCI_DLL_CONFIG);
+
+ /* Write 1 to DLL_PDN bit of MCI_DLL_CONFIG register */
+ writel_relaxed((readl_relaxed(host->base +
+ MCI_DLL_CONFIG) | MCI_DLL_PDN),
+ host->base + MCI_DLL_CONFIG);
+ }
}
/* Select free running MCLK as input clock of cm_dll_sdc4 */
@@ -4181,6 +4222,8 @@
out:
spin_lock_irqsave(&host->lock, flags);
host->tuning_in_progress = 0;
+ if (!rc)
+ host->tuning_done = true;
spin_unlock_irqrestore(&host->lock, flags);
exit:
pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
diff --git a/drivers/mmc/host/msm_sdcc.h b/drivers/mmc/host/msm_sdcc.h
index bb1b211..500b5fb 100644
--- a/drivers/mmc/host/msm_sdcc.h
+++ b/drivers/mmc/host/msm_sdcc.h
@@ -401,6 +401,7 @@
bool io_pad_pwr_switch;
bool tuning_in_progress;
bool tuning_needed;
+ bool tuning_done;
bool en_auto_cmd19;
bool en_auto_cmd21;
bool sdio_gpio_lpm;
diff --git a/drivers/platform/msm/Kconfig b/drivers/platform/msm/Kconfig
index 75cc086..872a9b5 100644
--- a/drivers/platform/msm/Kconfig
+++ b/drivers/platform/msm/Kconfig
@@ -12,11 +12,7 @@
config SPS
bool "SPS support"
- depends on (HAS_IOMEM && (ARCH_MSM8960 || ARCH_MSM8X60 \
- || ARCH_APQ8064 || ARCH_MSM9615 \
- || ARCH_MSM9625 || ARCH_MSM8974))
select GENERIC_ALLOCATOR
- default n
help
The SPS (Smart Peripheral Switch) is a DMA engine.
It can move data in the following modes:
diff --git a/drivers/platform/msm/sps/sps_bam.c b/drivers/platform/msm/sps/sps_bam.c
index f671ece..a3bbb73 100644
--- a/drivers/platform/msm/sps/sps_bam.c
+++ b/drivers/platform/msm/sps/sps_bam.c
@@ -1005,6 +1005,8 @@
no_queue = ((options & SPS_O_NO_Q));
ack_xfers = ((options & SPS_O_ACK_TRANSFERS));
+ pipe->hybrid = options & SPS_O_HYBRID;
+
/* Create interrupt source mask */
mask = 0;
for (n = 0; n < ARRAY_SIZE(opt_event_table); n++) {
@@ -1773,7 +1775,7 @@
}
/* If pipe is polled and queue is enabled, perform polling operation */
- if (pipe->polled && !pipe->sys.no_queue)
+ if ((pipe->polled || pipe->hybrid) && !pipe->sys.no_queue)
pipe_handler_eot(dev, pipe);
/* Is there a completed descriptor? */
diff --git a/drivers/platform/msm/sps/sps_bam.h b/drivers/platform/msm/sps/sps_bam.h
index 6004b75..84d2b97 100644
--- a/drivers/platform/msm/sps/sps_bam.h
+++ b/drivers/platform/msm/sps/sps_bam.h
@@ -170,6 +170,7 @@
u32 pipe_index_mask;
u32 irq_mask;
int polled;
+ int hybrid;
u32 irq_gen_addr;
enum sps_mode mode;
u32 num_descs; /* Size (number of elements) of descriptor FIFO */
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index 703aca9..2eddb9d 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -55,6 +55,9 @@
#define TEMP_IAVG_STORAGE 0x105
#define TEMP_IAVG_STORAGE_USE_MASK 0x0F
+#define PON_CNTRL_6 0x018
+#define WD_BIT BIT(7)
+
enum pmic_bms_interrupts {
PM8921_BMS_SBI_WRITE_OK,
PM8921_BMS_CC_THR,
@@ -151,6 +154,9 @@
struct power_supply *batt_psy;
bool low_voltage_wake_lock_held;
struct wake_lock low_voltage_wake_lock;
+ int soc_calc_period;
+ int normal_voltage_calc_ms;
+ int low_voltage_calc_ms;
};
/*
@@ -627,17 +633,17 @@
return 0;
}
-#define MBG_TRANSIENT_ERROR_RAW 51
-static void adjust_pon_ocv_raw(struct pm8921_bms_chip *chip,
- struct pm8921_soc_params *raw)
+#define MBG_TRANSIENT_ERROR_UV 15000
+static void adjust_pon_ocv(struct pm8921_bms_chip *chip, int *uv)
{
- /* in 8921 parts the PON ocv is taken when the MBG is not settled.
+ /*
+ * In 8921 parts the PON ocv is taken when the MBG is not settled.
* decrease the pon ocv by 15mV raw value to account for it
* Since a 1/3rd of vbatt is supplied to the adc the raw value
* needs to be adjusted by 5mV worth bits
*/
- if (raw->last_good_ocv_raw >= MBG_TRANSIENT_ERROR_RAW)
- raw->last_good_ocv_raw -= MBG_TRANSIENT_ERROR_RAW;
+ if (*uv >= MBG_TRANSIENT_ERROR_UV)
+ *uv -= MBG_TRANSIENT_ERROR_UV;
}
#define SEL_ALT_OREG_BIT BIT(2)
@@ -660,10 +666,71 @@
return compensated_ocv;
}
+#define RESET_CC_BIT BIT(3)
+static int reset_cc(struct pm8921_bms_chip *chip)
+{
+ int rc;
+
+ rc = pm_bms_masked_write(chip, BMS_TEST1, RESET_CC_BIT, RESET_CC_BIT);
+ if (rc < 0) {
+ pr_err("err setting cc reset rc = %d\n", rc);
+ return rc;
+ }
+
+ /* sleep 100uS for the coulomb counter to reset */
+ udelay(100);
+
+ rc = pm_bms_masked_write(chip, BMS_TEST1, RESET_CC_BIT, 0);
+ if (rc < 0)
+ pr_err("err clearing cc reset rc = %d\n", rc);
+ return rc;
+}
+
+static int estimate_ocv(struct pm8921_bms_chip *chip)
+{
+ int ibat_ua, vbat_uv, ocv_est_uv;
+ int rc;
+
+ int rbatt_mohm = chip->default_rbatt_mohm + chip->rconn_mohm;
+
+ rc = pm8921_bms_get_simultaneous_battery_voltage_and_current(
+ &ibat_ua,
+ &vbat_uv);
+ if (rc) {
+ pr_err("simultaneous failed rc = %d\n", rc);
+ return rc;
+ }
+
+ ocv_est_uv = vbat_uv + (ibat_ua * rbatt_mohm) / 1000;
+ pr_debug("estimated pon ocv = %d\n", ocv_est_uv);
+ return ocv_est_uv;
+}
+
+static bool is_warm_restart(struct pm8921_bms_chip *chip)
+{
+ u8 reg;
+ int rc;
+
+ rc = pm8xxx_readb(chip->dev->parent, PON_CNTRL_6, ®);
+ if (rc) {
+ pr_err("err reading pon 6 rc = %d\n", rc);
+ return false;
+ }
+ return reg & WD_BIT;
+}
+/*
+ * This reflects what should the CC readings should be for
+ * a 5mAh discharge. This value is dependent on
+ * CC_RESOLUTION_N, CC_RESOLUTION_D, CC_READING_TICKS
+ * and rsense
+ */
+#define CC_RAW_5MAH 0x00110000
+#define MIN_OCV_UV 2000000
static int read_soc_params_raw(struct pm8921_bms_chip *chip,
struct pm8921_soc_params *raw)
{
int usb_chg;
+ int est_ocv_uv;
mutex_lock(&chip->bms_output_lock);
pm_bms_lock_output_data(chip);
@@ -679,12 +746,40 @@
if (chip->prev_last_good_ocv_raw == 0) {
chip->prev_last_good_ocv_raw = raw->last_good_ocv_raw;
- adjust_pon_ocv_raw(chip, raw);
+
convert_vbatt_raw_to_uv(chip, usb_chg,
raw->last_good_ocv_raw, &raw->last_good_ocv_uv);
+ adjust_pon_ocv(chip, &raw->last_good_ocv_uv);
raw->last_good_ocv_uv = ocv_ir_compensation(chip,
raw->last_good_ocv_uv);
chip->last_ocv_uv = raw->last_good_ocv_uv;
+
+ if (is_warm_restart(chip)
+ || raw->cc > CC_RAW_5MAH
+ || (raw->last_good_ocv_uv < MIN_OCV_UV
+ && raw->cc > 0)) {
+ /*
+ * The CC value is higher than 5mAh.
+ * The phone started without going through a pon
+ * sequence
+ * OR
+ * The ocv was very small and there was no
+ * charging in the bootloader
+ * - reset the CC and take an ocv again
+ */
+ pr_debug("cc_raw = 0x%x may be > 5mAh(0x%x)\n",
+ raw->cc, CC_RAW_5MAH);
+ pr_debug("ocv_uv = %d ocv_raw = 0x%x may be < 2V\n",
+ chip->last_ocv_uv,
+ raw->last_good_ocv_raw);
+ est_ocv_uv = estimate_ocv(chip);
+ if (est_ocv_uv > 0) {
+ raw->last_good_ocv_uv = est_ocv_uv;
+ chip->last_ocv_uv = est_ocv_uv;
+ reset_cc(chip);
+ raw->cc = 0;
+ }
+ }
pr_debug("PON_OCV_UV = %d\n", chip->last_ocv_uv);
} else if (chip->prev_last_good_ocv_raw != raw->last_good_ocv_raw) {
chip->prev_last_good_ocv_raw = raw->last_good_ocv_raw;
@@ -1370,6 +1465,7 @@
pr_debug("voltage = %d low holding wakelock\n", vbat_uv);
wake_lock(&chip->low_voltage_wake_lock);
chip->low_voltage_wake_lock_held = 1;
+ chip->soc_calc_period = chip->low_voltage_calc_ms;
}
if (vbat_uv > (chip->v_cutoff + 20) * 1000
@@ -1377,6 +1473,7 @@
pr_debug("voltage = %d releasing wakelock\n", vbat_uv);
chip->low_voltage_wake_lock_held = 0;
wake_unlock(&chip->low_voltage_wake_lock);
+ chip->soc_calc_period = chip->normal_voltage_calc_ms;
}
}
@@ -1811,7 +1908,6 @@
return calculated_soc;
}
-#define CALCULATE_SOC_MS 20000
static void calculate_soc_work(struct work_struct *work)
{
struct pm8921_bms_chip *chip = container_of(work,
@@ -1841,7 +1937,7 @@
schedule_delayed_work(&chip->calculate_soc_delayed_work,
round_jiffies_relative(msecs_to_jiffies
- (CALCULATE_SOC_MS)));
+ (chip->soc_calc_period)));
}
static int report_state_of_charge(struct pm8921_bms_chip *chip)
@@ -2686,7 +2782,9 @@
int ret = 0;
struct pm8921_soc_params raw;
+ mutex_lock(&the_chip->bms_output_lock);
read_soc_params_raw(the_chip, &raw);
+ mutex_unlock(&the_chip->bms_output_lock);
*val = 0;
@@ -2907,6 +3005,12 @@
chip->end_percent = -EINVAL;
chip->shutdown_soc_valid_limit = pdata->shutdown_soc_valid_limit;
chip->adjust_soc_low_threshold = pdata->adjust_soc_low_threshold;
+
+ chip->normal_voltage_calc_ms = pdata->normal_voltage_calc_ms;
+ chip->low_voltage_calc_ms = pdata->low_voltage_calc_ms;
+
+ chip->soc_calc_period = pdata->normal_voltage_calc_ms;
+
if (chip->adjust_soc_low_threshold >= 45)
chip->adjust_soc_low_threshold = 45;
diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index 3995cf7..e39e9d7 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -260,11 +260,9 @@
struct dentry *dent;
struct bms_notify bms_notify;
int *usb_trim_table;
- bool keep_btm_on_suspend;
bool ext_charging;
bool ext_charge_done;
bool iusb_fine_res;
- bool dc_unplug_check;
bool disable_hw_clock_switching;
DECLARE_BITMAP(enabled_irqs, PM_CHG_MAX_INTS);
struct work_struct battery_id_valid_work;
@@ -307,8 +305,6 @@
static struct pm8921_chg_chip *the_chip;
-static struct pm8xxx_adc_arb_btm_param btm_config;
-
static int pm_chg_masked_write(struct pm8921_chg_chip *chip, u16 addr,
u8 mask, u8 val)
{
@@ -1431,15 +1427,6 @@
case POWER_SUPPLY_PROP_PRESENT:
case POWER_SUPPLY_PROP_ONLINE:
val->intval = 0;
- if (charging_disabled)
- return 0;
-
- /*
- * if drawing any current from usb is disabled behave
- * as if no usb cable is connected
- */
- if (pm_is_chg_charge_dis(the_chip))
- return 0;
/* USB charging */
if (usb_target_ma < USB_WALL_THRESHOLD_MA)
@@ -1905,22 +1892,6 @@
}
EXPORT_SYMBOL_GPL(pm8921_charger_vbus_draw);
-int pm8921_charger_enable(bool enable)
-{
- int rc;
-
- if (!the_chip) {
- pr_err("called before init\n");
- return -EINVAL;
- }
- enable = !!enable;
- rc = pm_chg_auto_enable(the_chip, enable);
- if (rc)
- pr_err("Failed rc=%d\n", rc);
- return rc;
-}
-EXPORT_SYMBOL(pm8921_charger_enable);
-
int pm8921_is_usb_chg_plugged_in(void)
{
if (!the_chip) {
@@ -2312,7 +2283,10 @@
pr_warn("%s. battery temperature not ok.\n", __func__);
return;
}
- pm8921_disable_source_current(true); /* Force BATFET=ON */
+
+ /* Force BATFET=ON */
+ pm8921_disable_source_current(true);
+
vbat_ov = pm_chg_get_rt_status(chip, VBAT_OV_IRQ);
if (vbat_ov) {
pr_warn("%s. battery over voltage.\n", __func__);
@@ -2322,16 +2296,17 @@
schedule_delayed_work(&chip->unplug_check_work,
round_jiffies_relative(msecs_to_jiffies
(UNPLUG_CHECK_WAIT_PERIOD_MS)));
- pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
power_supply_set_online(chip->ext_psy, dc_present);
power_supply_set_charge_type(chip->ext_psy,
POWER_SUPPLY_CHARGE_TYPE_FAST);
- power_supply_changed(&chip->dc_psy);
chip->ext_charging = true;
chip->ext_charge_done = false;
bms_notify_check(chip);
- /* Start BMS */
+ /*
+ * since we wont get a fastchg irq from external charger
+ * use eoc worker to detect end of charging
+ */
schedule_delayed_work(&chip->eoc_work, delay);
wake_lock(&chip->eoc_wake_lock);
/* Update battery charging LEDs and user space battery info */
@@ -2568,15 +2543,25 @@
struct pm8921_chg_chip *chip = container_of(dwork,
struct pm8921_chg_chip, vin_collapse_check_work);
- /* AICL only for wall-chargers */
- if (is_usb_chg_plugged_in(chip) &&
- usb_target_ma > USB_WALL_THRESHOLD_MA) {
+ /*
+ * AICL only for wall-chargers. If the charger appears to be plugged
+ * back in now, the corresponding unplug must have been because of we
+ * were trying to draw more current than the charger can support. In
+ * such a case reset usb current to 500mA and decrease the target.
+ * The AICL algorithm will step up the current from 500mA to target
+ */
+ if (is_usb_chg_plugged_in(chip)
+ && usb_target_ma > USB_WALL_THRESHOLD_MA) {
/* decrease usb_target_ma */
decrease_usb_ma_value(&usb_target_ma);
/* reset here, increase in unplug_check_worker */
__pm8921_charger_vbus_draw(USB_WALL_THRESHOLD_MA);
pr_debug("usb_now=%d, usb_target = %d\n",
USB_WALL_THRESHOLD_MA, usb_target_ma);
+ if (!delayed_work_pending(&chip->unplug_check_work))
+ schedule_delayed_work(&chip->unplug_check_work,
+ round_jiffies_relative(msecs_to_jiffies
+ (UNPLUG_CHECK_WAIT_PERIOD_MS)));
} else {
handle_usb_insertion_removal(chip);
}
@@ -2801,12 +2786,6 @@
}
} else if (active_path & DC_ACTIVE_BIT) {
pr_debug("DC charger active\n");
- /*
- * Some board designs are not prone to reverse boost on DC
- * charging path
- */
- if (!chip->dc_unplug_check)
- return;
} else {
/* No charger active */
if (!(is_usb_chg_plugged_in(chip)
@@ -3079,20 +3058,33 @@
struct pm8921_chg_chip *chip = data;
int dc_present;
+ pm_chg_failed_clear(chip, 1);
dc_present = pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
- if (chip->ext_psy)
- power_supply_set_online(chip->ext_psy, dc_present);
- chip->dc_present = dc_present;
- if (dc_present)
- handle_start_ext_chg(chip);
- else
- handle_stop_ext_chg(chip);
- if (!chip->ext_psy) {
+ if (chip->dc_present ^ dc_present)
+ pm8921_bms_calibrate_hkadc();
+
+ if (dc_present)
+ pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
+ else
+ pm8921_chg_disable_irq(chip, CHG_GONE_IRQ);
+
+ chip->dc_present = dc_present;
+
+ if (chip->ext_psy) {
+ if (dc_present)
+ handle_start_ext_chg(chip);
+ else
+ handle_stop_ext_chg(chip);
+ } else {
+ if (dc_present)
+ schedule_delayed_work(&chip->unplug_check_work,
+ round_jiffies_relative(msecs_to_jiffies
+ (UNPLUG_CHECK_WAIT_PERIOD_MS)));
power_supply_changed(&chip->dc_psy);
- power_supply_changed(&chip->batt_psy);
}
+ power_supply_changed(&chip->batt_psy);
return IRQ_HANDLED;
}
@@ -3243,6 +3235,79 @@
- the_chip->resume_voltage_delta);
}
+static void set_appropriate_battery_current(struct pm8921_chg_chip *chip)
+{
+ unsigned int chg_current = chip->max_bat_chg_current;
+
+ if (chip->is_bat_cool)
+ chg_current = min(chg_current, chip->cool_bat_chg_current);
+
+ if (chip->is_bat_warm)
+ chg_current = min(chg_current, chip->warm_bat_chg_current);
+
+ if (thermal_mitigation != 0 && chip->thermal_mitigation)
+ chg_current = min(chg_current,
+ chip->thermal_mitigation[thermal_mitigation]);
+
+ pm_chg_ibatmax_set(the_chip, chg_current);
+}
+
+#define TEMP_HYSTERISIS_DECIDEGC 20
+static void battery_cool(bool enter)
+{
+ pr_debug("enter = %d\n", enter);
+ if (enter == the_chip->is_bat_cool)
+ return;
+ the_chip->is_bat_cool = enter;
+ if (enter)
+ pm_chg_vddmax_set(the_chip, the_chip->cool_bat_voltage);
+ else
+ pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
+ set_appropriate_battery_current(the_chip);
+ set_appropriate_vbatdet(the_chip);
+}
+
+static void battery_warm(bool enter)
+{
+ pr_debug("enter = %d\n", enter);
+ if (enter == the_chip->is_bat_warm)
+ return;
+ the_chip->is_bat_warm = enter;
+ if (enter)
+ pm_chg_vddmax_set(the_chip, the_chip->warm_bat_voltage);
+ else
+ pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
+
+ set_appropriate_battery_current(the_chip);
+ set_appropriate_vbatdet(the_chip);
+}
+
+static void check_temp_thresholds(struct pm8921_chg_chip *chip)
+{
+ int temp = 0;
+
+ temp = get_prop_batt_temp(chip);
+ pr_debug("temp = %d, warm_thr_temp = %d, cool_thr_temp = %d\n",
+ temp, chip->warm_temp_dc,
+ chip->cool_temp_dc);
+
+ if (chip->warm_temp_dc != INT_MIN) {
+ if (chip->is_bat_warm
+ && temp < chip->warm_temp_dc - TEMP_HYSTERISIS_DECIDEGC)
+ battery_warm(false);
+ else if (!chip->is_bat_warm && temp >= chip->warm_temp_dc)
+ battery_warm(true);
+ }
+
+ if (chip->cool_temp_dc != INT_MIN) {
+ if (chip->is_bat_cool
+ && temp > chip->cool_temp_dc + TEMP_HYSTERISIS_DECIDEGC)
+ battery_cool(false);
+ else if (!chip->is_bat_cool && temp <= chip->cool_temp_dc)
+ battery_cool(true);
+ }
+}
+
enum {
CHG_IN_PROGRESS,
CHG_NOT_IN_PROGRESS,
@@ -3418,6 +3483,7 @@
/* declare end of charging by invoking chgdone interrupt */
chgdone_irq_handler(chip->pmic_chg_irq[CHGDONE_IRQ], chip);
} else {
+ check_temp_thresholds(chip);
adjust_vdd_max_for_fastchg(chip, vbat_batt_terminal_uv);
pr_debug("EOC count = %d\n", count);
schedule_delayed_work(&chip->eoc_work,
@@ -3432,100 +3498,6 @@
set_appropriate_vbatdet(chip);
}
-static void btm_configure_work(struct work_struct *work)
-{
- int rc;
-
- rc = pm8xxx_adc_btm_configure(&btm_config);
- if (rc)
- pr_err("failed to configure btm rc=%d", rc);
-}
-
-DECLARE_WORK(btm_config_work, btm_configure_work);
-
-static void set_appropriate_battery_current(struct pm8921_chg_chip *chip)
-{
- unsigned int chg_current = chip->max_bat_chg_current;
-
- if (chip->is_bat_cool)
- chg_current = min(chg_current, chip->cool_bat_chg_current);
-
- if (chip->is_bat_warm)
- chg_current = min(chg_current, chip->warm_bat_chg_current);
-
- if (thermal_mitigation != 0 && chip->thermal_mitigation)
- chg_current = min(chg_current,
- chip->thermal_mitigation[thermal_mitigation]);
-
- pm_chg_ibatmax_set(the_chip, chg_current);
-}
-
-#define TEMP_HYSTERISIS_DEGC 2
-static void battery_cool(bool enter)
-{
- pr_debug("enter = %d\n", enter);
- if (enter == the_chip->is_bat_cool)
- return;
- the_chip->is_bat_cool = enter;
- if (enter) {
- btm_config.low_thr_temp =
- the_chip->cool_temp_dc + TEMP_HYSTERISIS_DEGC;
- pm_chg_vddmax_set(the_chip, the_chip->cool_bat_voltage);
- } else {
- btm_config.low_thr_temp = the_chip->cool_temp_dc;
- pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
- }
- set_appropriate_battery_current(the_chip);
- set_appropriate_vbatdet(the_chip);
- schedule_work(&btm_config_work);
-}
-
-static void battery_warm(bool enter)
-{
- pr_debug("enter = %d\n", enter);
- if (enter == the_chip->is_bat_warm)
- return;
- the_chip->is_bat_warm = enter;
- if (enter) {
- btm_config.high_thr_temp =
- the_chip->warm_temp_dc - TEMP_HYSTERISIS_DEGC;
- pm_chg_vddmax_set(the_chip, the_chip->warm_bat_voltage);
- } else {
- btm_config.high_thr_temp = the_chip->warm_temp_dc;
- pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
- }
- set_appropriate_battery_current(the_chip);
- set_appropriate_vbatdet(the_chip);
- schedule_work(&btm_config_work);
-}
-
-static int configure_btm(struct pm8921_chg_chip *chip)
-{
- int rc;
-
- if (chip->warm_temp_dc != INT_MIN)
- btm_config.btm_warm_fn = battery_warm;
- else
- btm_config.btm_warm_fn = NULL;
-
- if (chip->cool_temp_dc != INT_MIN)
- btm_config.btm_cool_fn = battery_cool;
- else
- btm_config.btm_cool_fn = NULL;
-
- btm_config.low_thr_temp = chip->cool_temp_dc;
- btm_config.high_thr_temp = chip->warm_temp_dc;
- btm_config.interval = chip->temp_check_period;
- rc = pm8xxx_adc_btm_configure(&btm_config);
- if (rc)
- pr_err("failed to configure btm rc = %d\n", rc);
- rc = pm8xxx_adc_btm_start();
- if (rc)
- pr_err("failed to start btm rc = %d\n", rc);
-
- return rc;
-}
-
/**
* set_disable_status_param -
*
@@ -4435,19 +4407,8 @@
static int pm8921_charger_resume(struct device *dev)
{
- int rc;
struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
- if (!(chip->cool_temp_dc == INT_MIN && chip->warm_temp_dc == INT_MIN)
- && !(chip->keep_btm_on_suspend)) {
- rc = pm8xxx_adc_btm_configure(&btm_config);
- if (rc)
- pr_err("couldn't reconfigure btm rc=%d\n", rc);
-
- rc = pm8xxx_adc_btm_start();
- if (rc)
- pr_err("couldn't restart btm rc=%d\n", rc);
- }
if (pm8921_chg_is_enabled(chip, LOOP_CHANGE_IRQ)) {
disable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]);
pm8921_chg_disable_irq(chip, LOOP_CHANGE_IRQ);
@@ -4460,13 +4421,6 @@
int rc;
struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
- if (!(chip->cool_temp_dc == INT_MIN && chip->warm_temp_dc == INT_MIN)
- && !(chip->keep_btm_on_suspend)) {
- rc = pm8xxx_adc_btm_end();
- if (rc)
- pr_err("Failed to disable BTM on suspend rc=%d\n", rc);
- }
-
if (is_usb_chg_plugged_in(chip)) {
pm8921_chg_enable_irq(chip, LOOP_CHANGE_IRQ);
enable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]);
@@ -4524,13 +4478,11 @@
chip->warm_temp_dc = INT_MIN;
chip->temp_check_period = pdata->temp_check_period;
- chip->dc_unplug_check = pdata->dc_unplug_check;
chip->max_bat_chg_current = pdata->max_bat_chg_current;
chip->cool_bat_chg_current = pdata->cool_bat_chg_current;
chip->warm_bat_chg_current = pdata->warm_bat_chg_current;
chip->cool_bat_voltage = pdata->cool_bat_voltage;
chip->warm_bat_voltage = pdata->warm_bat_voltage;
- chip->keep_btm_on_suspend = pdata->keep_btm_on_suspend;
chip->trkl_voltage = pdata->trkl_voltage;
chip->weak_voltage = pdata->weak_voltage;
chip->trkl_current = pdata->trkl_current;
@@ -4624,17 +4576,6 @@
enable_irq_wake(chip->pmic_chg_irq[BAT_TEMP_OK_IRQ]);
enable_irq_wake(chip->pmic_chg_irq[VBATDET_LOW_IRQ]);
enable_irq_wake(chip->pmic_chg_irq[FASTCHG_IRQ]);
- /*
- * if both the cool_temp_dc and warm_temp_dc are invalid device doesnt
- * care for jeita compliance
- */
- if (!(chip->cool_temp_dc == INT_MIN && chip->warm_temp_dc == INT_MIN)) {
- rc = configure_btm(chip);
- if (rc) {
- pr_err("couldn't register with btm rc=%d\n", rc);
- goto free_irq;
- }
- }
rc = pm8921_charger_configure_batt_alarm(chip);
if (rc) {
diff --git a/drivers/power/qpnp-bms.c b/drivers/power/qpnp-bms.c
index 1955ff4..6623d81 100644
--- a/drivers/power/qpnp-bms.c
+++ b/drivers/power/qpnp-bms.c
@@ -176,7 +176,8 @@
int soc_at_cv;
int prev_chg_soc;
int calculated_soc;
- int last_vbat_read_uv;
+ int prev_voltage_based_soc;
+ bool use_voltage_soc;
};
static struct of_device_id qpnp_bms_match_table[] = {
@@ -196,37 +197,6 @@
POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
};
-static bool use_voltage_soc;
-
-/* module params */
-static int bms_param_set_bool(const char *val, const struct kernel_param *kp)
-{
- int rc;
- struct power_supply *bms_psy;
-
- rc = param_set_bool(val, kp);
- if (rc) {
- pr_err("failed to set %s, rc = %d\n", kp->name, rc);
- return rc;
- }
-
- bms_psy = power_supply_get_by_name("bms");
-
- if (bms_psy)
- power_supply_changed(bms_psy);
- else
- pr_debug("%s changed but bms has not been initialized yet\n",
- kp->name);
-
- return 0;
-}
-
-static struct kernel_param_ops bms_param_ops = {
- .set = bms_param_set_bool,
- .get = param_get_bool,
-};
-
-module_param_cb(use_voltage_soc, &bms_param_ops, &use_voltage_soc, 0644);
static int qpnp_read_wrapper(struct qpnp_bms_chip *chip, u8 *val,
u16 base, int count)
@@ -370,6 +340,10 @@
s64 result_uv;
pr_debug("adjusting_uv = %lld\n", uv);
+ if (gain == 0) {
+ pr_debug("gain is %d, not adjusting\n", gain);
+ return uv;
+ }
pr_debug("adjusting by factor: %lld/%hu = %lld%%\n",
QPNP_ADC_GAIN_NV, gain,
div_s64(QPNP_ADC_GAIN_NV * 100LL, (s64)gain));
@@ -1381,12 +1355,12 @@
}
chip->calculated_soc = new_calculated_soc;
- pr_debug("Set calculated SOC = %d\n", chip->calculated_soc);
+ pr_debug("CC based calculated SOC = %d\n", chip->calculated_soc);
chip->first_time_calc_soc = 0;
return chip->calculated_soc;
}
-static void read_vbat(struct qpnp_bms_chip *chip)
+static int read_vbat(struct qpnp_bms_chip *chip)
{
int rc;
struct qpnp_vadc_result result;
@@ -1395,9 +1369,35 @@
if (rc) {
pr_err("error reading vadc VBAT_SNS = %d, rc = %d\n",
VBAT_SNS, rc);
- return;
+ return rc;
}
- chip->last_vbat_read_uv = (int)result.physical;
+ pr_debug("read %duv from vadc\n", (int)result.physical);
+ return (int)result.physical;
+}
+
+static int calculate_soc_from_voltage(struct qpnp_bms_chip *chip)
+{
+ int voltage_range_uv, voltage_remaining_uv, voltage_based_soc;
+ int vbat_uv;
+
+ vbat_uv = read_vbat(chip);
+
+ voltage_range_uv = chip->max_voltage_uv - chip->v_cutoff_uv;
+ voltage_remaining_uv = vbat_uv - chip->v_cutoff_uv;
+ voltage_based_soc = voltage_remaining_uv * 100 / voltage_range_uv;
+
+ voltage_based_soc = clamp(voltage_based_soc, 0, 100);
+
+ if (chip->prev_voltage_based_soc != voltage_based_soc
+ && chip->bms_psy.name != NULL) {
+ power_supply_changed(&chip->bms_psy);
+ pr_debug("power supply changed\n");
+ }
+ chip->prev_voltage_based_soc = voltage_based_soc;
+
+ pr_debug("vbat used = %duv\n", vbat_uv);
+ pr_debug("Calculated voltage based soc = %d\n", voltage_based_soc);
+ return voltage_based_soc;
}
static void calculate_soc_work(struct work_struct *work)
@@ -1409,22 +1409,25 @@
struct qpnp_vadc_result result;
struct raw_soc_params raw;
- read_vbat(chip);
-
- rc = qpnp_vadc_read(LR_MUX1_BATT_THERM, &result);
- if (rc) {
- pr_err("error reading vadc LR_MUX1_BATT_THERM = %d, rc = %d\n",
- LR_MUX1_BATT_THERM, rc);
- return;
- }
- pr_debug("batt_temp phy = %lld meas = 0x%llx\n", result.physical,
+ if (chip->use_voltage_soc) {
+ soc = calculate_soc_from_voltage(chip);
+ } else {
+ rc = qpnp_vadc_read(LR_MUX1_BATT_THERM, &result);
+ if (rc) {
+ pr_err("error reading vadc LR_MUX1_BATT_THERM = %d, rc = %d\n",
+ LR_MUX1_BATT_THERM, rc);
+ return;
+ }
+ pr_debug("batt_temp phy = %lld meas = 0x%llx\n",
+ result.physical,
result.measurement);
- batt_temp = (int)result.physical;
+ batt_temp = (int)result.physical;
- mutex_lock(&chip->last_ocv_uv_mutex);
- read_soc_params_raw(chip, &raw);
- soc = calculate_state_of_charge(chip, &raw, batt_temp);
- mutex_unlock(&chip->last_ocv_uv_mutex);
+ mutex_lock(&chip->last_ocv_uv_mutex);
+ read_soc_params_raw(chip, &raw);
+ soc = calculate_state_of_charge(chip, &raw, batt_temp);
+ mutex_unlock(&chip->last_ocv_uv_mutex);
+ }
if (soc < chip->low_soc_calc_threshold)
schedule_delayed_work(&chip->calculate_soc_delayed_work,
@@ -1514,7 +1517,14 @@
static int bms_fake_battery = -EINVAL;
module_param(bms_fake_battery, int, 0644);
-static int report_state_of_charge(struct qpnp_bms_chip *chip)
+static int report_voltage_based_soc(struct qpnp_bms_chip *chip)
+{
+ pr_debug("Reported voltage based soc = %d\n",
+ chip->prev_voltage_based_soc);
+ return chip->prev_voltage_based_soc;
+}
+
+static int report_cc_based_soc(struct qpnp_bms_chip *chip)
{
int soc;
int delta_time_us;
@@ -1523,11 +1533,6 @@
int batt_temp;
int rc;
- if (bms_fake_battery != -EINVAL) {
- pr_debug("Returning Fake SOC = %d%%\n", bms_fake_battery);
- return bms_fake_battery;
- }
-
soc = chip->calculated_soc;
rc = qpnp_vadc_read(LR_MUX1_BATT_THERM, &result);
@@ -1598,27 +1603,21 @@
return chip->last_soc;
}
-static int calculate_soc_from_voltage(struct qpnp_bms_chip *chip)
+static int report_state_of_charge(struct qpnp_bms_chip *chip)
{
- int voltage_range_uv, voltage_remaining_uv, voltage_based_soc;
-
- if (chip->last_vbat_read_uv < 0)
- read_vbat(chip);
-
- voltage_range_uv = chip->max_voltage_uv - chip->v_cutoff_uv;
- voltage_remaining_uv = chip->last_vbat_read_uv - chip->v_cutoff_uv;
- voltage_based_soc = voltage_remaining_uv * 100 / voltage_range_uv;
-
- return clamp(voltage_based_soc, 0, 100);
+ if (bms_fake_battery != -EINVAL) {
+ pr_debug("Returning Fake SOC = %d%%\n", bms_fake_battery);
+ return bms_fake_battery;
+ } else if (chip->use_voltage_soc)
+ return report_voltage_based_soc(chip);
+ else
+ return report_cc_based_soc(chip);
}
/* Returns capacity as a SoC percentage between 0 and 100 */
static int get_prop_bms_capacity(struct qpnp_bms_chip *chip)
{
- if (use_voltage_soc)
- return calculate_soc_from_voltage(chip);
- else
- return report_state_of_charge(chip);
+ return report_state_of_charge(chip);
}
/* Returns instantaneous current in uA */
@@ -1873,7 +1872,7 @@
chip->ignore_shutdown_soc = of_property_read_bool(
chip->spmi->dev.of_node,
"qcom,bms-ignore-shutdown-soc");
- use_voltage_soc = of_property_read_bool(chip->spmi->dev.of_node,
+ chip->use_voltage_soc = of_property_read_bool(chip->spmi->dev.of_node,
"qcom,bms-use-voltage-soc");
if (chip->adjust_soc_low_threshold >= 45)
@@ -1889,7 +1888,7 @@
chip->adjust_soc_high_threshold, chip->chg_term_ua,
chip->batt_type);
pr_debug("ignore_shutdown_soc:%d, use_voltage_soc:%d\n",
- chip->ignore_shutdown_soc, use_voltage_soc);
+ chip->ignore_shutdown_soc, chip->use_voltage_soc);
return 0;
}
@@ -1902,7 +1901,6 @@
chip->soc_at_cv = -EINVAL;
chip->calculated_soc = -EINVAL;
chip->last_soc = -EINVAL;
- chip->last_vbat_read_uv = -EINVAL;
chip->last_soc_est = -EINVAL;
chip->first_time_calc_soc = 1;
chip->first_time_calc_uuc = 1;
@@ -1950,6 +1948,18 @@
goto error_read;
}
+ rc = qpnp_vadc_is_ready();
+ if (rc) {
+ pr_info("vadc not ready: %d, deferring probe\n", rc);
+ goto error_read;
+ }
+
+ rc = qpnp_iadc_is_ready();
+ if (rc) {
+ pr_info("iadc not ready: %d, deferring probe\n", rc);
+ goto error_read;
+ }
+
rc = set_battery_data(chip);
if (rc) {
pr_err("Bad battery data %d\n", rc);
@@ -1996,7 +2006,7 @@
vbatt = 0;
get_battery_voltage(&vbatt);
- pr_info("OK battery_capacity_at_boot=%d vbatt = %d\n",
+ pr_debug("OK battery_capacity_at_boot=%d vbatt = %d\n",
get_prop_bms_capacity(chip),
vbatt);
pr_info("probe success\n");
diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c
index 0497a32..7b6b890 100644
--- a/drivers/spi/spi_qsd.c
+++ b/drivers/spi/spi_qsd.c
@@ -2658,7 +2658,8 @@
err_probe_reg_master:
err_probe_irq:
err_probe_state:
- dd->dma_teardown(dd);
+ if (dd->dma_teardown)
+ dd->dma_teardown(dd);
err_probe_dma:
err_probe_gsbi:
if (pclk_enabled)
@@ -2741,7 +2742,8 @@
spi_debugfs_exit(dd);
sysfs_remove_group(&pdev->dev.kobj, &dev_attr_grp);
- dd->dma_teardown(dd);
+ if (dd->dma_teardown)
+ dd->dma_teardown(dd);
clk_put(dd->clk);
clk_put(dd->pclk);
destroy_workqueue(dd->workqueue);
diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c
index e6f5bf5..5e7ab9f 100644
--- a/drivers/tty/serial/msm_serial.c
+++ b/drivers/tty/serial/msm_serial.c
@@ -848,8 +848,7 @@
},
};
-#define UART_NR ARRAY_SIZE(msm_uart_ports)
-
+#define UART_NR 256
static inline struct uart_port * get_port_from_line(unsigned int line)
{
return &msm_uart_ports[line].uart;
@@ -1002,9 +1001,7 @@
struct resource *resource;
struct uart_port *port;
int irq;
-#ifdef CONFIG_SERIAL_MSM_RX_WAKEUP
struct msm_serial_platform_data *pdata = pdev->dev.platform_data;
-#endif
if (unlikely(pdev->id < 0 || pdev->id >= UART_NR))
return -ENXIO;
@@ -1057,6 +1054,8 @@
#endif
pm_runtime_enable(port->dev);
+ if (pdata != NULL && pdata->userid && pdata->userid <= UART_NR)
+ port->line = pdata->userid;
return uart_add_one_port(&msm_uart_driver, port);
}
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 494ec49..55ff980 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -1357,8 +1357,14 @@
{
struct usb_device *udev = to_usb_device(dev);
- if (udev->bus->skip_resume && udev->state == USB_STATE_SUSPENDED)
- return 0;
+ if (udev->bus->skip_resume) {
+ if (udev->state == USB_STATE_SUSPENDED) {
+ return 0;
+ } else {
+ dev_err(dev, "abort suspend\n");
+ return -EBUSY;
+ }
+ }
unbind_no_pm_drivers_interfaces(udev);
diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c
index d4a30f1..be4eff7 100644
--- a/drivers/usb/dwc3/debugfs.c
+++ b/drivers/usb/dwc3/debugfs.c
@@ -56,7 +56,7 @@
#define dump_register(nm) \
{ \
.name = __stringify(nm), \
- .offset = DWC3_ ##nm, \
+ .offset = DWC3_ ##nm - DWC3_GLOBALS_REGS_START, \
}
static const struct debugfs_reg32 dwc3_regs[] = {
diff --git a/drivers/usb/gadget/f_diag.c b/drivers/usb/gadget/f_diag.c
index 8f68234..aca2af3 100644
--- a/drivers/usb/gadget/f_diag.c
+++ b/drivers/usb/gadget/f_diag.c
@@ -18,6 +18,7 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
+#include <linux/ratelimit.h>
#include <mach/usbdiag.h>
@@ -427,6 +428,7 @@
struct diag_context *ctxt = ch->priv_usb;
unsigned long flags;
struct usb_request *req;
+ static DEFINE_RATELIMIT_STATE(rl, 10*HZ, 1);
if (!ctxt)
return -ENODEV;
@@ -456,7 +458,9 @@
spin_lock_irqsave(&ctxt->lock, flags);
list_add_tail(&req->list, &ctxt->read_pool);
spin_unlock_irqrestore(&ctxt->lock, flags);
- ERROR(ctxt->cdev, "%s: cannot queue"
+ /* 1 error message for every 10 sec */
+ if (__ratelimit(&rl))
+ ERROR(ctxt->cdev, "%s: cannot queue"
" read request\n", __func__);
return -EIO;
}
@@ -483,6 +487,7 @@
struct diag_context *ctxt = ch->priv_usb;
unsigned long flags;
struct usb_request *req = NULL;
+ static DEFINE_RATELIMIT_STATE(rl, 10*HZ, 1);
if (!ctxt)
return -ENODEV;
@@ -512,7 +517,9 @@
spin_lock_irqsave(&ctxt->lock, flags);
list_add_tail(&req->list, &ctxt->write_pool);
spin_unlock_irqrestore(&ctxt->lock, flags);
- ERROR(ctxt->cdev, "%s: cannot queue"
+ /* 1 error message for every 10 sec */
+ if (__ratelimit(&rl))
+ ERROR(ctxt->cdev, "%s: cannot queue"
" read request\n", __func__);
return -EIO;
}
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index 8c22f8e..7d12598 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -1886,7 +1886,8 @@
* when remote wakeup is received or interface driver
* start I/O.
*/
- if (!atomic_read(&mehci->pm_usage_cnt))
+ if (!atomic_read(&mehci->pm_usage_cnt) &&
+ pm_runtime_suspended(dev))
return 0;
ret = msm_hsic_resume(mehci);
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index c6fe765..b9e95ab 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -485,6 +485,9 @@
ret = msm_otg_phy_clk_reset(motg);
if (ret)
return ret;
+ /* 10 usec delay is required according to spec */
+ if (IS_ERR(motg->phy_reset_clk))
+ usleep_range(10, 12);
ret = msm_otg_link_clk_reset(motg, 0);
if (ret)
return ret;
@@ -771,10 +774,12 @@
if (aca_enabled())
return 0;
- if (atomic_read(&motg->in_lpm) == suspend &&
- !atomic_read(&motg->suspend_work_pending))
- return 0;
-
+ /*
+ * UDC and HCD call usb_phy_set_suspend() to enter/exit LPM
+ * during bus suspend/resume. Update the relevant state
+ * machine inputs and trigger LPM entry/exit. Checking
+ * in_lpm flag would avoid unnecessary work scheduling.
+ */
if (suspend) {
switch (phy->state) {
case OTG_STATE_A_WAIT_BCON:
@@ -784,16 +789,18 @@
case OTG_STATE_A_HOST:
pr_debug("host bus suspend\n");
clear_bit(A_BUS_REQ, &motg->inputs);
- queue_work(system_nrt_wq, &motg->sm_work);
+ if (!atomic_read(&motg->in_lpm))
+ queue_work(system_nrt_wq, &motg->sm_work);
break;
case OTG_STATE_B_PERIPHERAL:
pr_debug("peripheral bus suspend\n");
if (!(motg->caps & ALLOW_LPM_ON_DEV_SUSPEND))
break;
set_bit(A_BUS_SUSPEND, &motg->inputs);
- atomic_set(&motg->suspend_work_pending, 1);
- queue_delayed_work(system_nrt_wq, &motg->suspend_work,
- USB_SUSPEND_DELAY_TIME);
+ if (!atomic_read(&motg->in_lpm))
+ queue_delayed_work(system_nrt_wq,
+ &motg->suspend_work,
+ USB_SUSPEND_DELAY_TIME);
break;
default:
@@ -801,20 +808,29 @@
}
} else {
switch (phy->state) {
+ case OTG_STATE_A_WAIT_BCON:
+ /* Remote wakeup or resume */
+ set_bit(A_BUS_REQ, &motg->inputs);
+ /* ensure hardware is not in low power mode */
+ if (atomic_read(&motg->in_lpm))
+ pm_runtime_resume(phy->dev);
+ break;
case OTG_STATE_A_SUSPEND:
/* Remote wakeup or resume */
set_bit(A_BUS_REQ, &motg->inputs);
phy->state = OTG_STATE_A_HOST;
/* ensure hardware is not in low power mode */
- pm_runtime_resume(phy->dev);
+ if (atomic_read(&motg->in_lpm))
+ pm_runtime_resume(phy->dev);
break;
case OTG_STATE_B_PERIPHERAL:
pr_debug("peripheral bus resume\n");
if (!(motg->caps & ALLOW_LPM_ON_DEV_SUSPEND))
break;
clear_bit(A_BUS_SUSPEND, &motg->inputs);
- queue_work(system_nrt_wq, &motg->sm_work);
+ if (atomic_read(&motg->in_lpm))
+ queue_work(system_nrt_wq, &motg->sm_work);
break;
default:
break;
@@ -2945,8 +2961,10 @@
{
struct msm_otg *motg =
container_of(w, struct msm_otg, suspend_work.work);
- atomic_set(&motg->suspend_work_pending, 0);
- msm_otg_sm_work(&motg->sm_work);
+
+ /* This work is only for device bus suspend */
+ if (test_bit(A_BUS_SUSPEND, &motg->inputs))
+ msm_otg_sm_work(&motg->sm_work);
}
static irqreturn_t msm_otg_irq(int irq, void *data)
diff --git a/drivers/video/msm/mdp4.h b/drivers/video/msm/mdp4.h
index 6edc9f2..67ef8bf 100644
--- a/drivers/video/msm/mdp4.h
+++ b/drivers/video/msm/mdp4.h
@@ -28,6 +28,8 @@
extern char *mmss_cc_base; /* mutimedia sub system clock control */
extern spinlock_t dsi_clk_lock;
extern u32 mdp_max_clk;
+extern u32 dbg_force_ov0_blt;
+extern u32 dbg_force_ov1_blt;
#define MDP4_OVERLAYPROC0_BASE 0x10000
#define MDP4_OVERLAYPROC1_BASE 0x18000
@@ -94,11 +96,6 @@
#define MDP4_PANEL_WRITEBACK BIT(6)
enum {
- OVERLAY_MODE_NONE,
- OVERLAY_MODE_BLT
-};
-
-enum {
OVERLAY_REFRESH_ON_DEMAND,
OVERLAY_REFRESH_VSYNC,
OVERLAY_REFRESH_VSYNC_HALF,
@@ -449,7 +446,6 @@
void mdp4_intr_clear_set(ulong clear, ulong set);
void mdp4_dma_p_cfg(void);
unsigned is_mdp4_hw_reset(void);
-void mdp4_overlay_cfg_init(void);
void mdp4_hw_init(void);
void mdp4_isr_read(int);
void mdp4_clear_lcdc(void);
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index 59565c1..f4332dd 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -53,7 +53,6 @@
uint32 flush[MDP4_MIXER_MAX];
struct iommu_free_list iommu_free[MDP4_MIXER_MAX];
uint32 cs_controller;
- uint32 hw_version;
uint32 panel_3d;
uint32 panel_mode;
uint32 mixer0_played;
@@ -253,7 +252,7 @@
pipe->pipe_ndx, plane);
if (ion_map_iommu(display_iclient, *srcp_ihdl,
DISPLAY_READ_DOMAIN, GEN_POOL, SZ_4K, 0, start,
- len, 0, ION_IOMMU_UNMAP_DELAYED)) {
+ len, 0, 0)) {
ion_free(display_iclient, *srcp_ihdl);
pr_err("ion_map_iommu() failed\n");
return -EINVAL;
@@ -354,23 +353,9 @@
return ctrl->panel_mode;
}
-void mdp4_overlay_cfg_init(void)
-{
- if (ctrl->hw_version == 0) {
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
- ctrl->hw_version = inpdw(MDP_BASE + 0x0); /* MDP_HW_VERSION */
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
- }
-
- if (ctrl->hw_version >= 0x0402030b) {
- /* MDP_LAYERMIXER_IN_CFG_UPDATE_METHOD */
- outpdw(MDP_BASE + 0x100fc, 0x01);
- }
-}
-
int mdp4_overlay_borderfill_supported(void)
{
- return (ctrl->hw_version >= 0x0402030b);
+ return (mdp_rev >= MDP_REV_42);
}
void mdp4_overlay_dmae_cfg(struct msm_fb_data_type *mfd, int atv)
@@ -2895,8 +2880,9 @@
perf_req->mdp_bw);
perf_cur->mdp_bw = perf_req->mdp_bw;
}
- if (mfd->panel_info.pdest == DISPLAY_1 &&
- perf_req->use_ov0_blt && !perf_cur->use_ov0_blt) {
+ if ((mfd->panel_info.pdest == DISPLAY_1 &&
+ perf_req->use_ov0_blt && !perf_cur->use_ov0_blt) ||
+ dbg_force_ov0_blt) {
if (mfd->panel_info.type == LCDC_PANEL ||
mfd->panel_info.type == LVDS_PANEL)
mdp4_lcdc_overlay_blt_start(mfd);
@@ -2906,17 +2892,18 @@
mdp4_dsi_cmd_blt_start(mfd);
else if (ctrl->panel_mode & MDP4_PANEL_MDDI)
mdp4_mddi_blt_start(mfd);
- pr_info("%s mixer0 start blt [%d] from %d to %d.\n",
+ pr_debug("%s mixer0 start blt [%d] from %d to %d.\n",
__func__,
flag,
perf_cur->use_ov0_blt,
perf_req->use_ov0_blt);
perf_cur->use_ov0_blt = perf_req->use_ov0_blt;
}
- if (mfd->panel_info.pdest == DISPLAY_2 &&
- perf_req->use_ov1_blt && !perf_cur->use_ov1_blt) {
+ if ((mfd->panel_info.pdest == DISPLAY_2 &&
+ perf_req->use_ov1_blt && !perf_cur->use_ov1_blt) ||
+ dbg_force_ov1_blt) {
mdp4_dtv_overlay_blt_start(mfd);
- pr_info("%s mixer1 start blt [%d] from %d to %d.\n",
+ pr_debug("%s mixer1 start blt [%d] from %d to %d.\n",
__func__,
flag,
perf_cur->use_ov1_blt,
@@ -2945,8 +2932,9 @@
perf_req->mdp_bw);
perf_cur->mdp_bw = perf_req->mdp_bw;
}
- if (mfd->panel_info.pdest == DISPLAY_1 &&
- !perf_req->use_ov0_blt && perf_cur->use_ov0_blt) {
+ if ((mfd->panel_info.pdest == DISPLAY_1 &&
+ !perf_req->use_ov0_blt && perf_cur->use_ov0_blt) ||
+ dbg_force_ov0_blt) {
if (mfd->panel_info.type == LCDC_PANEL ||
mfd->panel_info.type == LVDS_PANEL)
mdp4_lcdc_overlay_blt_stop(mfd);
@@ -2956,17 +2944,18 @@
mdp4_dsi_cmd_blt_stop(mfd);
else if (ctrl->panel_mode & MDP4_PANEL_MDDI)
mdp4_mddi_blt_stop(mfd);
- pr_info("%s mixer0 stop blt [%d] from %d to %d.\n",
+ pr_debug("%s mixer0 stop blt [%d] from %d to %d.\n",
__func__,
flag,
perf_cur->use_ov0_blt,
perf_req->use_ov0_blt);
perf_cur->use_ov0_blt = perf_req->use_ov0_blt;
}
- if (mfd->panel_info.pdest == DISPLAY_2 &&
- !perf_req->use_ov1_blt && perf_cur->use_ov1_blt) {
+ if ((mfd->panel_info.pdest == DISPLAY_2 &&
+ !perf_req->use_ov1_blt && perf_cur->use_ov1_blt) ||
+ dbg_force_ov1_blt) {
mdp4_dtv_overlay_blt_stop(mfd);
- pr_info("%s mixer1 stop blt [%d] from %d to %d.\n",
+ pr_debug("%s mixer1 stop blt [%d] from %d to %d.\n",
__func__,
flag,
perf_cur->use_ov1_blt,
diff --git a/drivers/video/msm/mdp4_overlay_dsi_video.c b/drivers/video/msm/mdp4_overlay_dsi_video.c
index 239d9f5..450f1de 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_video.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_video.c
@@ -56,7 +56,8 @@
int wait_vsync_cnt;
int blt_change;
int blt_free;
- int blt_ctrl;
+ u32 blt_ctrl;
+ u32 blt_mode;
int sysfs_created;
struct mutex update_lock;
struct completion ov_comp;
@@ -197,18 +198,6 @@
}
spin_unlock_irqrestore(&vctrl->spin_lock, flags);
- if (vctrl->blt_change) {
- pipe = vctrl->base_pipe;
- spin_lock_irqsave(&vctrl->spin_lock, flags);
- INIT_COMPLETION(vctrl->dmap_comp);
- INIT_COMPLETION(vctrl->ov_comp);
- vsync_irq_enable(INTR_DMA_P_DONE, MDP_DMAP_TERM);
- spin_unlock_irqrestore(&vctrl->spin_lock, flags);
- mdp4_dsi_video_wait4dmap(0);
- if (pipe->ov_blt_addr)
- mdp4_dsi_video_wait4ov(0);
- }
-
pipe = vp->plist;
for (i = 0; i < OVERLAY_PIPE_MAX; i++, pipe++) {
@@ -498,7 +487,6 @@
vctrl = &vsync_ctrl_db[cndx];
mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
- pinfo = &mfd->panel_info;
if (!mfd)
return -ENODEV;
@@ -508,7 +496,9 @@
vctrl->mfd = mfd;
vctrl->dev = mfd->fbi->dev;
+ pinfo = &mfd->panel_info;
vctrl->blt_ctrl = pinfo->lcd.blt_ctrl;
+ vctrl->blt_mode = pinfo->lcd.blt_mode;
/* mdp clock on */
mdp_clk_ctrl(1);
@@ -551,6 +541,7 @@
mfd->cont_splash_done = 1;
mdp4_dsi_video_wait4dmap_done(0);
MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE, 0);
+ dsi_video_enabled = 0;
mipi_dsi_controller_cfg(0);
/* Clks are enabled in probe.
Disabling clocks now */
@@ -940,20 +931,8 @@
if (vctrl->blt_change) {
mdp4_overlayproc_cfg(pipe);
mdp4_overlay_dmap_xy(pipe);
- if (pipe->ov_blt_addr) {
- mdp4_dsi_video_blt_ov_update(pipe);
- pipe->ov_cnt++;
- /* Prefill one frame */
- vsync_irq_enable(INTR_OVERLAY0_DONE,
- MDP_OVERLAY0_TERM);
- /* kickoff overlay0 engine */
- mdp4_stat.kickoff_ov0++;
- vctrl->ov_koff++; /* make up for prefill */
- outpdw(MDP_BASE + 0x0004, 0);
- }
vctrl->blt_change = 0;
}
-
complete_all(&vctrl->dmap_comp);
mdp4_overlay_dma_commit(cndx);
spin_unlock(&vctrl->spin_lock);
@@ -997,19 +976,43 @@
struct vsycn_ctrl *vctrl;
struct mdp4_overlay_pipe *pipe;
long long vtime;
+ u32 mode, ctrl;
vctrl = &vsync_ctrl_db[cndx];
pipe = vctrl->base_pipe;
- mdp4_allocate_writeback_buf(mfd, MDP4_MIXER0);
+ mode = (dbg_force_ov0_blt & 0x0f) ?
+ (dbg_force_ov0_blt & 0x0f) : vctrl->blt_mode;
+ ctrl = (dbg_force_ov0_blt >> 4) ?
+ (dbg_force_ov0_blt >> 4) : vctrl->blt_ctrl;
- if (mfd->ov0_wb_buf->write_addr == 0) {
- pr_info("%s: no blt_base assigned\n", __func__);
+ pr_debug("%s: mode=%d, enable=%d ov_blt_addr=%x\n",
+ __func__, mode, enable, (int)pipe->ov_blt_addr);
+
+ if ((mode == MDP4_OVERLAY_MODE_BLT_ALWAYS_OFF) &&
+ !pipe->ov_blt_addr)
return;
+ else if ((mode == MDP4_OVERLAY_MODE_BLT_ALWAYS_ON) &&
+ pipe->ov_blt_addr)
+ return;
+ else if (enable && pipe->ov_blt_addr)
+ return;
+ else if (!enable && !pipe->ov_blt_addr)
+ return;
+
+ if (pipe->ov_blt_addr == 0) {
+ mdp4_allocate_writeback_buf(mfd, MDP4_MIXER0);
+ if (mfd->ov0_wb_buf->write_addr == 0) {
+ pr_warning("%s: no blt_base assigned\n", __func__);
+ return;
+ }
}
+ pr_debug("%s: mode=%d, enable=%d ov_blt_addr=%x\n",
+ __func__, mode, enable, (int)pipe->ov_blt_addr);
+
spin_lock_irqsave(&vctrl->spin_lock, flag);
- if (enable && pipe->ov_blt_addr == 0) {
+ if (pipe->ov_blt_addr == 0) {
pipe->ov_blt_addr = mfd->ov0_wb_buf->write_addr;
pipe->dma_blt_addr = mfd->ov0_wb_buf->read_addr;
pipe->ov_cnt = 0;
@@ -1018,36 +1021,38 @@
vctrl->ov_done = 0;
vctrl->blt_free = 0;
mdp4_stat.blt_dsi_video++;
- vctrl->blt_change++;
- } else if (enable == 0 && pipe->ov_blt_addr) {
+ } else {
pipe->ov_blt_addr = 0;
pipe->dma_blt_addr = 0;
vctrl->blt_free = 4; /* 4 commits to free wb buf */
- vctrl->blt_change++;
- }
-
- pr_info("%s: changed=%d enable=%d ov_blt_addr=%x\n", __func__,
- vctrl->blt_change, enable, (int)pipe->ov_blt_addr);
-
- if (!vctrl->blt_change) {
- spin_unlock_irqrestore(&vctrl->spin_lock, flag);
- return;
}
spin_unlock_irqrestore(&vctrl->spin_lock, flag);
- if (vctrl->blt_ctrl == BLT_SWITCH_TG_OFF) {
- int tg_enabled;
-
- vctrl->blt_change = 0;
- tg_enabled = inpdw(MDP_BASE + DSI_VIDEO_BASE) & 0x01;
- if (tg_enabled) {
+ if (ctrl == MDP4_OVERLAY_BLT_SWITCH_TG_ON) {
+ spin_lock_irqsave(&vctrl->spin_lock, flag);
+ if (!dsi_video_enabled) {
+ pr_debug("%s: blt switched not in ISR dsi_video_enabled=%d\n",
+ __func__, dsi_video_enabled);
+ mdp4_overlayproc_cfg(pipe);
+ mdp4_overlay_dmap_xy(pipe);
+ } else {
+ pr_debug("%s: blt switched in ISR dsi_video_enabled=%d\n",
+ __func__, dsi_video_enabled);
+ vctrl->blt_change++;
+ }
+ spin_unlock_irqrestore(&vctrl->spin_lock, flag);
+ if (dsi_video_enabled)
+ mdp4_dsi_video_wait4dmap_done(0);
+ } else if (ctrl == MDP4_OVERLAY_BLT_SWITCH_TG_OFF) {
+ pr_debug("%s: blt switched by turning TG off\n", __func__);
+ if (dsi_video_enabled) {
mdp4_dsi_video_wait4vsync(0, &vtime);
MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE, 0);
mdp4_dsi_video_wait4dmap_done(0);
}
mdp4_overlayproc_cfg(pipe);
mdp4_overlay_dmap_xy(pipe);
- if (tg_enabled) {
+ if (dsi_video_enabled) {
/*
* need wait for more than 1 ms to
* make sure dsi lanes' fifo is empty and
@@ -1058,7 +1063,15 @@
mipi_dsi_sw_reset();
MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE, 1);
}
- }
+ } else if (ctrl == MDP4_OVERLAY_BLT_SWITCH_POLL) {
+ pr_debug("%s: blt switched by polling mdp status\n", __func__);
+ if (dsi_video_enabled)
+ while (inpdw(MDP_BASE + 0x0018) & 0x05)
+ cpu_relax();
+ mdp4_overlayproc_cfg(pipe);
+ mdp4_overlay_dmap_xy(pipe);
+ } else
+ pr_err("%s: ctrl=%d is not supported\n", __func__, ctrl);
}
void mdp4_dsi_video_overlay_blt(struct msm_fb_data_type *mfd,
@@ -1125,4 +1138,3 @@
mdp4_overlay_mdp_perf_upd(mfd, 0);
mutex_unlock(&mfd->dma->ov_mutex);
}
-
diff --git a/drivers/video/msm/mdp4_overlay_dtv.c b/drivers/video/msm/mdp4_overlay_dtv.c
index 1de5d6e..7de2e2a 100644
--- a/drivers/video/msm/mdp4_overlay_dtv.c
+++ b/drivers/video/msm/mdp4_overlay_dtv.c
@@ -66,6 +66,9 @@
int dmae_wait_cnt;
int wait_vsync_cnt;
int blt_change;
+ int blt_ctrl;
+ int blt_mode;
+ int blt_free;
int sysfs_created;
struct mutex update_lock;
struct completion ov_comp;
@@ -159,6 +162,7 @@
}
static void mdp4_dtv_blt_ov_update(struct mdp4_overlay_pipe *pipe);
+static void mdp4_dtv_wait4ov(int cndx);
static void mdp4_dtv_wait4dmae(int cndx);
int mdp4_dtv_pipe_commit(int cndx, int wait)
@@ -191,6 +195,13 @@
vctrl->update_ndx++;
vctrl->update_ndx &= 0x01;
vp->update_cnt = 0; /* reset */
+
+ if (vctrl->blt_free) {
+ vctrl->blt_free--;
+ if (vctrl->blt_free == 0)
+ mdp4_free_writeback_buf(vctrl->mfd, mixer);
+ }
+
mutex_unlock(&vctrl->update_lock);
pipe = vp->plist;
@@ -220,6 +231,7 @@
if (pipe->ov_blt_addr) {
mdp4_dtv_blt_ov_update(pipe);
pipe->blt_ov_done++;
+ INIT_COMPLETION(vctrl->ov_comp);
vsync_irq_enable(INTR_OVERLAY1_DONE, MDP_OVERLAY1_TERM);
mb();
pipe->blt_ov_koff++;
@@ -234,9 +246,12 @@
spin_unlock_irqrestore(&vctrl->spin_lock, flags);
mdp4_stat.overlay_commit[pipe->mixer_num]++;
- if (wait)
- mdp4_dtv_wait4dmae(cndx);
-
+ if (wait) {
+ if (pipe->ov_blt_addr)
+ mdp4_dtv_wait4ov(cndx);
+ else
+ mdp4_dtv_wait4dmae(cndx);
+ }
return cnt;
}
@@ -296,6 +311,23 @@
*vtime = ktime_to_ns(vctrl->vsync_time);
}
+static void mdp4_dtv_wait4ov(int cndx)
+{
+ struct vsycn_ctrl *vctrl;
+
+ if (cndx >= MAX_CONTROLLER) {
+ pr_err("%s: out or range: cndx=%d\n", __func__, cndx);
+ return;
+ }
+
+ vctrl = &vsync_ctrl_db[cndx];
+
+ if (atomic_read(&vctrl->suspend) > 0)
+ return;
+
+ wait_for_completion(&vctrl->ov_comp);
+}
+
static void mdp4_dtv_wait4dmae(int cndx)
{
struct vsycn_ctrl *vctrl;
@@ -367,6 +399,28 @@
return ret;
}
+static void mdp4_dtv_wait4dmae_done(int cndx)
+{
+ unsigned long flags;
+ struct vsycn_ctrl *vctrl;
+
+ if (cndx >= MAX_CONTROLLER) {
+ pr_err("%s: out or range: cndx=%d\n", __func__, cndx);
+ return;
+ }
+
+ vctrl = &vsync_ctrl_db[cndx];
+
+ if (atomic_read(&vctrl->suspend) > 0)
+ return;
+
+ spin_lock_irqsave(&vctrl->spin_lock, flags);
+ INIT_COMPLETION(vctrl->dmae_comp);
+ vsync_irq_enable(INTR_DMA_E_DONE, MDP_DMA_E_TERM);
+ spin_unlock_irqrestore(&vctrl->spin_lock, flags);
+ mdp4_dtv_wait4dmae(cndx);
+}
+
void mdp4_dtv_vsync_init(int cndx)
{
struct vsycn_ctrl *vctrl;
@@ -554,6 +608,7 @@
/* enable DTV block */
MDP_OUTP(MDP_BASE + DTV_BASE, 1);
+ dtv_enabled = 1;
return 0;
}
@@ -568,6 +623,7 @@
return -EINVAL;
MDP_OUTP(MDP_BASE + DTV_BASE, 0);
+ dtv_enabled = 0;
return 0;
}
@@ -578,6 +634,7 @@
int ret = 0;
int cndx = 0;
struct vsycn_ctrl *vctrl;
+ struct msm_panel_info *pinfo;
vctrl = &vsync_ctrl_db[cndx];
@@ -589,7 +646,12 @@
if (mfd->key != MFD_KEY)
return -EINVAL;
+ vctrl->mfd = mfd;
vctrl->dev = mfd->fbi->dev;
+ pinfo = &mfd->panel_info;
+
+ vctrl->blt_ctrl = pinfo->lcd.blt_ctrl;
+ vctrl->blt_mode = pinfo->lcd.blt_mode;
mdp_footswitch_ctrl(TRUE);
/* Mdp clock enable */
@@ -673,7 +735,7 @@
if (vctrl->vsync_irq_enabled) {
vctrl->vsync_irq_enabled = 0;
- vsync_irq_disable(INTR_PRIMARY_VSYNC, MDP_PRIM_VSYNC_TERM);
+ vsync_irq_disable(INTR_EXTERNAL_VSYNC, MDP_EXTER_VSYNC_TERM);
}
undx = vctrl->update_ndx;
@@ -748,11 +810,6 @@
MDP_OUTP(MDP_BASE + 0xb0008, addr);
}
-void mdp4_overlay_dtv_set_perf(struct msm_fb_data_type *mfd)
-{
-
-}
-
static void mdp4_overlay_dtv_alloc_pipe(struct msm_fb_data_type *mfd,
int32 ptype, struct vsycn_ctrl *vctrl)
{
@@ -940,18 +997,8 @@
spin_lock(&vctrl->spin_lock);
if (vctrl->blt_change) {
- if (pipe->ov_blt_addr) {
- mdp4_overlayproc_cfg(pipe);
- mdp4_overlay_dmae_xy(pipe);
- mdp4_dtv_blt_ov_update(pipe);
- pipe->blt_ov_done++;
-
- /* Prefill one frame */
- vsync_irq_enable(INTR_OVERLAY1_DONE, MDP_OVERLAY1_TERM);
- /* kickoff overlay1 engine */
- mdp4_stat.kickoff_ov1++;
- outpdw(MDP_BASE + 0x0008, 0);
- }
+ mdp4_overlayproc_cfg(pipe);
+ mdp4_overlay_dmae_xy(pipe);
vctrl->blt_change = 0;
}
@@ -986,6 +1033,7 @@
}
mdp4_dtv_blt_dmae_update(pipe);
+ complete_all(&vctrl->ov_comp);
pipe->blt_dmap_done++;
vsync_irq_disable(INTR_OVERLAY1_DONE, MDP_OVERLAY1_TERM);
spin_unlock(&vctrl->spin_lock);
@@ -1039,63 +1087,100 @@
static void mdp4_dtv_do_blt(struct msm_fb_data_type *mfd, int enable)
{
unsigned long flag;
- int data;
int cndx = 0;
struct vsycn_ctrl *vctrl;
struct mdp4_overlay_pipe *pipe;
+ u32 mode, ctrl;
vctrl = &vsync_ctrl_db[cndx];
pipe = vctrl->base_pipe;
- mdp4_allocate_writeback_buf(mfd, MDP4_MIXER1);
+ mode = (dbg_force_ov1_blt & 0x0f) ?
+ (dbg_force_ov1_blt & 0x0f) : vctrl->blt_mode;
+ ctrl = (dbg_force_ov1_blt >> 4) ?
+ (dbg_force_ov1_blt >> 4) : vctrl->blt_ctrl;
- if (!mfd->ov1_wb_buf->write_addr) {
- pr_info("%s: ctrl=%d blt_base NOT assigned\n", __func__, cndx);
+ pr_debug("%s: mode=%d, ctrl = %d, enable=%d ov_blt_addr=%x\n",
+ __func__, mode, ctrl, enable, (int)pipe->ov_blt_addr);
+
+ if ((mode == MDP4_OVERLAY_MODE_BLT_ALWAYS_OFF) &&
+ !pipe->ov_blt_addr)
return;
+ else if ((mode == MDP4_OVERLAY_MODE_BLT_ALWAYS_ON) &&
+ pipe->ov_blt_addr)
+ return;
+ else if (enable && pipe->ov_blt_addr)
+ return;
+ else if (!enable && !pipe->ov_blt_addr)
+ return;
+
+ if (pipe->ov_blt_addr == 0) {
+ mdp4_allocate_writeback_buf(vctrl->mfd, MDP4_MIXER1);
+ if (!vctrl->mfd->ov1_wb_buf->write_addr) {
+ pr_warning("%s: ctrl=%d blt_base NOT assigned\n",
+ __func__, cndx);
+ return;
+ }
}
+ pr_debug("%s: mode=%d, ctrl=%d, enable=%d ov_blt_addr=%x\n",
+ __func__, mode, ctrl, enable, (int)pipe->ov_blt_addr);
+
spin_lock_irqsave(&vctrl->spin_lock, flag);
if (enable && pipe->ov_blt_addr == 0) {
- pipe->ov_blt_addr = mfd->ov1_wb_buf->write_addr;
- pipe->dma_blt_addr = mfd->ov1_wb_buf->read_addr;
+ pipe->ov_blt_addr = vctrl->mfd->ov1_wb_buf->write_addr;
+ pipe->dma_blt_addr = vctrl->mfd->ov1_wb_buf->read_addr;
pipe->blt_cnt = 0;
pipe->ov_cnt = 0;
pipe->blt_dmap_done = 0;
pipe->blt_ov_koff = 0;
pipe->blt_ov_done = 0;
mdp4_stat.blt_dtv++;
- vctrl->blt_change++;
+ vctrl->blt_free = 0;
} else if (enable == 0 && pipe->ov_blt_addr) {
pipe->ov_blt_addr = 0;
pipe->dma_blt_addr = 0;
- vctrl->blt_change++;
+ vctrl->blt_free = 4;
}
-
- pr_info("%s: enable=%d change=%d blt_addr=%x\n", __func__,
- enable, vctrl->blt_change, (int)pipe->ov_blt_addr);
-
- if (!vctrl->blt_change) {
- spin_unlock_irqrestore(&vctrl->spin_lock, flag);
- return;
- }
-
- atomic_set(&vctrl->suspend, 1);
spin_unlock_irqrestore(&vctrl->spin_lock, flag);
- data = inpdw(MDP_BASE + DTV_BASE);
- data &= 0x01;
- if (data) /* timing generator enabled */
- mdp4_dtv_wait4dmae(0);
+ if (ctrl == MDP4_OVERLAY_BLT_SWITCH_TG_ON) {
+ spin_lock_irqsave(&vctrl->spin_lock, flag);
+ if (!dtv_enabled) {
+ pr_debug("%s: blt switched not in isr dtv_enabled=%d\n",
+ __func__, dtv_enabled);
+ mdp4_overlayproc_cfg(pipe);
+ mdp4_overlay_dmae_xy(pipe);
+ } else {
+ pr_debug("%s: blt switched in ISR dtv_enabled=%d\n",
+ __func__, dtv_enabled);
+ vctrl->blt_change++;
- if (pipe->ov_blt_addr == 0) {
- MDP_OUTP(MDP_BASE + DTV_BASE, 0); /* stop dtv */
- msleep(20);
+ }
+ spin_unlock_irqrestore(&vctrl->spin_lock, flag);
+ if (dtv_enabled)
+ mdp4_dtv_wait4dmae_done(0);
+ } else if (ctrl == MDP4_OVERLAY_BLT_SWITCH_TG_OFF) {
+ pr_debug("%s: dtv blt switched by turning TG off\n",
+ __func__);
+ if (dtv_enabled) {
+ mdp4_dtv_wait4dmae_done(0);
+ MDP_OUTP(MDP_BASE + DTV_BASE, 0);
+ msleep(20);
+ }
mdp4_overlayproc_cfg(pipe);
mdp4_overlay_dmae_xy(pipe);
- MDP_OUTP(MDP_BASE + DTV_BASE, 1); /* start dtv */
- }
-
- atomic_set(&vctrl->suspend, 0);
+ if (dtv_enabled)
+ MDP_OUTP(MDP_BASE + DTV_BASE, 1);
+ } else if (ctrl == MDP4_OVERLAY_BLT_SWITCH_POLL) {
+ pr_debug("%s: dtv blt change by polling status\n",
+ __func__);
+ while (inpdw(MDP_BASE + 0x0018) & 0x12)
+ cpu_relax();
+ mdp4_overlayproc_cfg(pipe);
+ mdp4_overlay_dmae_xy(pipe);
+ } else
+ pr_err("%s: ctrl=%d is not supported\n", __func__, ctrl);
}
void mdp4_dtv_overlay_blt_start(struct msm_fb_data_type *mfd)
diff --git a/drivers/video/msm/mdp4_util.c b/drivers/video/msm/mdp4_util.c
index ee9ca3c..b6c2634 100644
--- a/drivers/video/msm/mdp4_util.c
+++ b/drivers/video/msm/mdp4_util.c
@@ -454,8 +454,6 @@
clk_rate = mdp_get_core_clk();
mdp4_fetch_cfg(clk_rate);
- mdp4_overlay_cfg_init();
-
/* Mark hardware as initialized. Only revisions > v2.1 have a register
* for tracking core reset status. */
if (mdp_hw_revision > MDP4_REVISION_V2_1)
diff --git a/drivers/video/msm/mdp_debugfs.c b/drivers/video/msm/mdp_debugfs.c
index 54f5ef5..767375d 100644
--- a/drivers/video/msm/mdp_debugfs.c
+++ b/drivers/video/msm/mdp_debugfs.c
@@ -1029,6 +1029,135 @@
.write = dbg_reg_write,
};
+u32 dbg_force_ov0_blt;
+u32 dbg_force_ov1_blt;
+
+static ssize_t dbg_force_ov0_blt_read(
+ struct file *file,
+ char __user *buff,
+ size_t count,
+ loff_t *ppos) {
+ int len;
+
+ if (*ppos)
+ return 0;
+
+ len = snprintf(debug_buf, sizeof(debug_buf),
+ "%d\n", dbg_force_ov0_blt);
+
+ if (len < 0)
+ return 0;
+
+ if (copy_to_user(buff, debug_buf, len))
+ return -EFAULT;
+
+ *ppos += len;
+
+ return len;
+}
+
+static ssize_t dbg_force_ov0_blt_write(
+ struct file *file,
+ const char __user *buff,
+ size_t count,
+ loff_t *ppos)
+{
+ u32 cnt;
+
+ if (count >= sizeof(debug_buf))
+ return -EFAULT;
+
+ if (copy_from_user(debug_buf, buff, count))
+ return -EFAULT;
+
+ debug_buf[count] = 0; /* end of string */
+
+ cnt = sscanf(debug_buf, "%x", &dbg_force_ov0_blt);
+
+ pr_info("%s: dbg_force_ov0_blt = %x\n",
+ __func__, dbg_force_ov0_blt);
+
+ if ((dbg_force_ov0_blt & 0x0f) > 2)
+ pr_err("%s: invalid dbg_force_ov0_blt = %d\n",
+ __func__, dbg_force_ov0_blt);
+
+ if ((dbg_force_ov0_blt >> 4) > 2)
+ pr_err("%s: invalid dbg_force_ov0_blt = %d\n",
+ __func__, dbg_force_ov0_blt);
+
+ return count;
+}
+
+static const struct file_operations dbg_force_ov0_blt_fops = {
+ .open = dbg_open,
+ .release = dbg_release,
+ .read = dbg_force_ov0_blt_read,
+ .write = dbg_force_ov0_blt_write,
+};
+
+static ssize_t dbg_force_ov1_blt_read(
+ struct file *file,
+ char __user *buff,
+ size_t count,
+ loff_t *ppos) {
+ int len;
+
+ if (*ppos)
+ return 0;
+
+ len = snprintf(debug_buf, sizeof(debug_buf),
+ "%x\n", dbg_force_ov1_blt);
+
+ if (len < 0)
+ return 0;
+
+ if (copy_to_user(buff, debug_buf, len))
+ return -EFAULT;
+
+ *ppos += len;
+
+ return len;
+}
+
+static ssize_t dbg_force_ov1_blt_write(
+ struct file *file,
+ const char __user *buff,
+ size_t count,
+ loff_t *ppos)
+{
+ u32 cnt;
+
+ if (count >= sizeof(debug_buf))
+ return -EFAULT;
+
+ if (copy_from_user(debug_buf, buff, count))
+ return -EFAULT;
+
+ debug_buf[count] = 0; /* end of string */
+
+ cnt = sscanf(debug_buf, "%x", &dbg_force_ov1_blt);
+
+ pr_info("%s: dbg_force_ov1_blt = %x\n",
+ __func__, dbg_force_ov1_blt);
+
+ if ((dbg_force_ov1_blt & 0x0f) > 2)
+ pr_err("%s: invalid dbg_force_ov1_blt = %x\n",
+ __func__, dbg_force_ov1_blt);
+
+ if ((dbg_force_ov1_blt >> 4) > 2)
+ pr_err("%s: invalid dbg_force_ov1_blt = %d\n",
+ __func__, dbg_force_ov1_blt);
+
+ return count;
+}
+
+static const struct file_operations dbg_force_ov1_blt_fops = {
+ .open = dbg_open,
+ .release = dbg_release,
+ .read = dbg_force_ov1_blt_read,
+ .write = dbg_force_ov1_blt_write,
+};
+
#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
static uint32 hdmi_offset;
static uint32 hdmi_count;
@@ -1249,6 +1378,22 @@
}
#endif
+ if (debugfs_create_file("force_ov0_blt", 0644, dent, 0,
+ &dbg_force_ov0_blt_fops)
+ == NULL) {
+ pr_err("%s(%d): debugfs_create_file: debug fail\n",
+ __FILE__, __LINE__);
+ return -EFAULT;
+ }
+
+ if (debugfs_create_file("force_ov1_blt", 0644, dent, 0,
+ &dbg_force_ov1_blt_fops)
+ == NULL) {
+ pr_err("%s(%d): debugfs_create_file: debug fail\n",
+ __FILE__, __LINE__);
+ return -EFAULT;
+ }
+
dent = debugfs_create_dir("mddi", NULL);
if (IS_ERR(dent)) {
diff --git a/drivers/video/msm/mdss/mdss_fb.h b/drivers/video/msm/mdss/mdss_fb.h
index b760388..5e57de6 100644
--- a/drivers/video/msm/mdss/mdss_fb.h
+++ b/drivers/video/msm/mdss/mdss_fb.h
@@ -64,6 +64,9 @@
u32 fb_imgType;
u32 dst_format;
int vsync_pending;
+ ktime_t vsync_time;
+ struct completion vsync_comp;
+ spinlock_t vsync_lock;
int hw_refresh;
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_video.c b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
index 9508846..052d78c 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_video.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* 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
@@ -13,8 +13,6 @@
#define pr_fmt(fmt) "%s: " fmt, __func__
-#include <linux/workqueue.h>
-
#include "mdss_fb.h"
#include "mdss_mdp.h"
@@ -39,7 +37,6 @@
#define MAX_SESSIONS 3
struct mdss_mdp_video_ctx {
- u32 ctl_num;
u32 pp_num;
u8 ref_cnt;
@@ -47,11 +44,9 @@
struct completion pp_comp;
struct completion vsync_comp;
- struct mutex vsync_lock;
- struct work_struct vsync_work;
+ atomic_t vsync_ref;
+ spinlock_t vsync_lock;
mdp_vsync_handler_t vsync_handler;
- void *vsync_ptr;
- ktime_t vsync_time;
};
struct mdss_mdp_video_ctx mdss_mdp_video_ctx_list[MAX_SESSIONS];
@@ -157,43 +152,43 @@
return 0;
}
-static void send_vsync_work(struct work_struct *work)
-{
- struct mdss_mdp_video_ctx *ctx;
- ctx = container_of(work, typeof(*ctx), vsync_work);
- mutex_lock(&ctx->vsync_lock);
- if (ctx->vsync_handler)
- ctx->vsync_handler(ctx->vsync_ptr, ctx->vsync_time);
- mutex_unlock(&ctx->vsync_lock);
+static inline void video_vsync_irq_enable(struct mdss_mdp_ctl *ctl)
+{
+ struct mdss_mdp_video_ctx *ctx = ctl->priv_data;
+
+ if (atomic_inc_return(&ctx->vsync_ref) == 1)
+ mdss_mdp_irq_enable(MDSS_MDP_IRQ_INTF_VSYNC, ctl->intf_num);
+}
+
+static inline void video_vsync_irq_disable(struct mdss_mdp_ctl *ctl)
+{
+ struct mdss_mdp_video_ctx *ctx = ctl->priv_data;
+
+ if (atomic_dec_return(&ctx->vsync_ref) == 0)
+ mdss_mdp_irq_disable(MDSS_MDP_IRQ_INTF_VSYNC, ctl->intf_num);
}
static int mdss_mdp_video_set_vsync_handler(struct mdss_mdp_ctl *ctl,
mdp_vsync_handler_t vsync_handler)
{
struct mdss_mdp_video_ctx *ctx;
+ unsigned long flags;
ctx = (struct mdss_mdp_video_ctx *) ctl->priv_data;
if (!ctx) {
pr_err("invalid ctx for ctl=%d\n", ctl->num);
return -ENODEV;
}
- if (mutex_lock_interruptible(&ctx->vsync_lock))
- return -EINTR;
- if (vsync_handler && !ctx->timegen_en) {
- ctx->vsync_time = ktime_get();
- schedule_work(&ctx->vsync_work);
- }
-
+ spin_lock_irqsave(&ctx->vsync_lock, flags);
if (!ctx->vsync_handler && vsync_handler)
- mdss_mdp_irq_enable(MDSS_MDP_IRQ_INTF_VSYNC, ctl->intf_num);
+ video_vsync_irq_enable(ctl);
else if (ctx->vsync_handler && !vsync_handler)
- mdss_mdp_irq_disable(MDSS_MDP_IRQ_INTF_VSYNC, ctl->intf_num);
+ video_vsync_irq_disable(ctl);
ctx->vsync_handler = vsync_handler;
- ctx->vsync_ptr = ctl;
- mutex_unlock(&ctx->vsync_lock);
+ spin_unlock_irqrestore(&ctx->vsync_lock, flags);
return 0;
}
@@ -229,8 +224,7 @@
WARN(rc, "intf %d timegen off error (%d)\n", ctl->intf_num, rc);
}
- if (ctx->vsync_handler)
- mdss_mdp_video_set_vsync_handler(ctl, NULL);
+ mdss_mdp_video_set_vsync_handler(ctl, NULL);
mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_INTF_VSYNC, ctl->intf_num,
NULL, NULL);
@@ -244,9 +238,9 @@
static void mdss_mdp_video_pp_intr_done(void *arg)
{
- struct mdss_mdp_video_ctx *ctx;
+ struct mdss_mdp_ctl *ctl = arg;
+ struct mdss_mdp_video_ctx *ctx = ctl->priv_data;
- ctx = (struct mdss_mdp_video_ctx *) arg;
if (!ctx) {
pr_err("invalid ctx\n");
return;
@@ -259,20 +253,24 @@
static void mdss_mdp_video_vsync_intr_done(void *arg)
{
- struct mdss_mdp_video_ctx *ctx;
+ struct mdss_mdp_ctl *ctl = arg;
+ struct mdss_mdp_video_ctx *ctx = ctl->priv_data;
+ ktime_t vsync_time;
- ctx = (struct mdss_mdp_video_ctx *) arg;
if (!ctx) {
pr_err("invalid ctx\n");
return;
}
- ctx->vsync_time = ktime_get();
- pr_debug("intr ctl=%d\n", ctx->ctl_num);
+ vsync_time = ktime_get();
+
+ pr_debug("intr ctl=%d\n", ctl->num);
complete(&ctx->vsync_comp);
+ spin_lock(&ctx->vsync_lock);
if (ctx->vsync_handler)
- schedule_work(&ctx->vsync_work);
+ ctx->vsync_handler(ctl, vsync_time);
+ spin_unlock(&ctx->vsync_lock);
}
static int mdss_mdp_video_prepare(struct mdss_mdp_ctl *ctl, void *arg)
@@ -309,11 +307,7 @@
return -ENODEV;
}
INIT_COMPLETION(ctx->vsync_comp);
-
- if (mutex_lock_interruptible(&ctx->vsync_lock))
- return -EINTR;
- if (!ctx->vsync_handler)
- mdss_mdp_irq_enable(MDSS_MDP_IRQ_INTF_VSYNC, ctl->intf_num);
+ video_vsync_irq_enable(ctl);
if (!ctx->timegen_en) {
int off = MDSS_MDP_REG_INTF_OFFSET(ctl->intf_num);
@@ -335,9 +329,8 @@
rc = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_TIMEGEN_ON, NULL);
WARN(rc, "intf %d timegen on error (%d)\n", ctl->intf_num, rc);
}
- if (!ctx->vsync_handler)
- mdss_mdp_irq_disable(MDSS_MDP_IRQ_INTF_VSYNC, ctl->intf_num);
- mutex_unlock(&ctx->vsync_lock);
+
+ video_vsync_irq_disable(ctl);
return 0;
}
@@ -376,17 +369,16 @@
return -ENOMEM;
}
ctl->priv_data = ctx;
- ctx->ctl_num = ctl->num;
ctx->pp_num = mixer->num;
init_completion(&ctx->pp_comp);
init_completion(&ctx->vsync_comp);
+ spin_lock_init(&ctx->vsync_lock);
+ atomic_set(&ctx->vsync_ref, 0);
- INIT_WORK(&ctx->vsync_work, send_vsync_work);
- mutex_init(&ctx->vsync_lock);
mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_INTF_VSYNC, ctl->intf_num,
- mdss_mdp_video_vsync_intr_done, ctx);
+ mdss_mdp_video_vsync_intr_done, ctl);
mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num,
- mdss_mdp_video_pp_intr_done, ctx);
+ mdss_mdp_video_pp_intr_done, ctl);
itp.width = pinfo->xres + pinfo->lcdc.xres_pad;
itp.height = pinfo->yres + pinfo->lcdc.yres_pad;
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index f537c39..9c62ea2 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -26,6 +26,7 @@
#include "mdss_mdp.h"
#include "mdss_mdp_rotator.h"
+#define VSYNC_PERIOD 16
#define CHECK_BOUNDS(offset, size, max_size) \
(((size) > (max_size)) || ((offset) > ((max_size) - (size))))
@@ -837,30 +838,27 @@
mdss_mdp_overlay_kickoff(mfd->ctl);
}
+/* function is called in irq context should have minimum processing */
static void mdss_mdp_overlay_handle_vsync(struct mdss_mdp_ctl *ctl, ktime_t t)
{
- struct device *dev;
- char buf[64];
- char *envp[2];
-
- if (!ctl || !ctl->mfd || !ctl->mfd->fbi) {
+ struct msm_fb_data_type *mfd = ctl->mfd;
+ if (!mfd) {
pr_warn("Invalid handle for vsync\n");
return;
}
- dev = ctl->mfd->fbi->dev;
+ pr_debug("vsync on fb%d play_cnt=%d\n", mfd->index, ctl->play_cnt);
- snprintf(buf, sizeof(buf), "VSYNC=%llu", ktime_to_ns(t));
- envp[0] = buf;
- envp[1] = NULL;
- kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
-
- pr_debug("sent vsync on ctl=%d ts=%llu\n", ctl->num, ktime_to_ns(t));
+ spin_lock(&mfd->vsync_lock);
+ mfd->vsync_time = t;
+ complete(&mfd->vsync_comp);
+ spin_unlock(&mfd->vsync_lock);
}
int mdss_mdp_overlay_vsync_ctrl(struct msm_fb_data_type *mfd, int en)
{
struct mdss_mdp_ctl *ctl = mfd->ctl;
+ unsigned long flags;
int rc;
if (!ctl)
@@ -868,13 +866,23 @@
if (!ctl->set_vsync_handler)
return -ENOTSUPP;
- pr_debug("vsync en=%d\n", en);
-
if (!ctl->power_on) {
+ pr_debug("fb%d vsync pending first update en=%d\n",
+ mfd->index, en);
mfd->vsync_pending = en;
return 0;
}
+ pr_debug("fb%d vsync en=%d\n", mfd->index, en);
+
+ spin_lock_irqsave(&mfd->vsync_lock, flags);
+ INIT_COMPLETION(mfd->vsync_comp);
+ if (en && ctl->play_cnt == 0) {
+ mfd->vsync_time = ktime_get();
+ complete(&mfd->vsync_comp);
+ }
+ spin_unlock_irqrestore(&mfd->vsync_lock, flags);
+
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
if (en)
rc = ctl->set_vsync_handler(ctl, mdss_mdp_overlay_handle_vsync);
@@ -885,6 +893,47 @@
return rc;
}
+static ssize_t mdss_mdp_vsync_show_event(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct fb_info *fbi = dev_get_drvdata(dev);
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par;
+ unsigned long flags;
+ u64 vsync_ticks;
+ int ret;
+
+ if (!mfd->ctl || !mfd->ctl->power_on)
+ return 0;
+
+ ret = wait_for_completion_interruptible_timeout(&mfd->vsync_comp,
+ msecs_to_jiffies(VSYNC_PERIOD * 5));
+ if (ret <= 0) {
+ pr_warn("vsync wait on fb%d interrupted (%d)\n",
+ mfd->index, ret);
+ return -EBUSY;
+ }
+
+ spin_lock_irqsave(&mfd->vsync_lock, flags);
+ vsync_ticks = ktime_to_ns(mfd->vsync_time);
+ spin_unlock_irqrestore(&mfd->vsync_lock, flags);
+
+ pr_debug("fb%d vsync=%llu", mfd->index, vsync_ticks);
+ ret = snprintf(buf, PAGE_SIZE, "VSYNC=%llu", vsync_ticks);
+
+ return ret;
+}
+
+static DEVICE_ATTR(vsync_event, S_IRUGO, mdss_mdp_vsync_show_event, NULL);
+
+static struct attribute *vsync_fs_attrs[] = {
+ &dev_attr_vsync_event.attr,
+ NULL,
+};
+
+static struct attribute_group vsync_fs_attr_group = {
+ .attrs = vsync_fs_attrs,
+};
+
static int mdss_mdp_hw_cursor_update(struct msm_fb_data_type *mfd,
struct fb_cursor *cursor)
{
@@ -1154,6 +1203,9 @@
int mdss_mdp_overlay_init(struct msm_fb_data_type *mfd)
{
+ struct device *dev = mfd->fbi->dev;
+ int rc;
+
mfd->on_fnc = mdss_mdp_overlay_on;
mfd->off_fnc = mdss_mdp_overlay_off;
mfd->hw_refresh = true;
@@ -1168,7 +1220,18 @@
INIT_LIST_HEAD(&mfd->pipes_used);
INIT_LIST_HEAD(&mfd->pipes_cleanup);
+ init_completion(&mfd->vsync_comp);
+ spin_lock_init(&mfd->vsync_lock);
mutex_init(&mfd->ov_lock);
- return 0;
+ rc = sysfs_create_group(&dev->kobj, &vsync_fs_attr_group);
+ if (rc) {
+ pr_err("vsync sysfs group creation failed, ret=%d\n", rc);
+ return rc;
+ }
+
+ kobject_uevent(&dev->kobj, KOBJ_ADD);
+ pr_debug("vsync kobject_uevent(KOBJ_ADD)\n");
+
+ return rc;
}
diff --git a/drivers/video/msm/msm_fb_panel.h b/drivers/video/msm/msm_fb_panel.h
index bdd4f3bb..505928e 100644
--- a/drivers/video/msm/msm_fb_panel.h
+++ b/drivers/video/msm/msm_fb_panel.h
@@ -71,6 +71,7 @@
__u32 hw_vsync_mode;
__u32 vsync_notifier_period;
__u32 blt_ctrl;
+ __u32 blt_mode;
__u32 rev;
};
@@ -204,6 +205,18 @@
int (*clk_func) (int enable);
};
+enum {
+ MDP4_OVERLAY_BLT_SWITCH_TG_OFF,
+ MDP4_OVERLAY_BLT_SWITCH_TG_ON,
+ MDP4_OVERLAY_BLT_SWITCH_POLL
+};
+
+enum {
+ MDP4_OVERLAY_MODE_BLT_CTRL,
+ MDP4_OVERLAY_MODE_BLT_ALWAYS_ON,
+ MDP4_OVERLAY_MODE_BLT_ALWAYS_OFF
+};
+
/*===========================================================================
FUNCTIONS PROTOTYPES
============================================================================*/
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
index 2a850d8..7a1d521 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
@@ -293,6 +293,7 @@
struct vcd_property_slice_delivery_info slice_delivery_info;
struct ddl_batch_frame_data batch_frame;
u32 avc_delimiter_enable;
+ u32 vui_timinginfo_enable;
};
struct ddl_decoder_data {
struct ddl_codec_data_hdr hdr;
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c
index 2c41ab4..78f96c8 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c
@@ -1259,7 +1259,8 @@
output_vcd_frm->flags |=
VCD_FRAME_FLAG_DATACORRUPT;
}
- if (decoder->codec.codec != VCD_CODEC_H264)
+ if (decoder->codec.codec != VCD_CODEC_H264 ||
+ decoder->codec.codec != VCD_CODEC_MPEG2)
output_vcd_frm->flags &= ~VCD_FRAME_FLAG_DATACORRUPT;
output_vcd_frm->ip_frm_tag = dec_disp_info->tag_top;
vidc_sm_get_picture_times(&ddl->shared_mem
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 d6558c3..332497f 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
@@ -1061,6 +1061,20 @@
}
break;
}
+ case VCD_I_ENABLE_VUI_TIMING_INFO:
+ {
+ struct vcd_property_vui_timing_info_enable *vui_timing_enable =
+ (struct vcd_property_vui_timing_info_enable *)
+ property_value;
+ if (sizeof(struct vcd_property_vui_timing_info_enable) ==
+ property_hdr->sz &&
+ encoder->codec.codec == VCD_CODEC_H264) {
+ encoder->vui_timinginfo_enable =
+ vui_timing_enable->vui_timing_info;
+ vcd_status = VCD_S_SUCCESS;
+ }
+ break;
+ }
default:
DDL_MSG_ERROR("INVALID ID %d\n", (int)property_hdr->prop_id);
vcd_status = VCD_ERR_ILLEGAL_OP;
@@ -1553,6 +1567,15 @@
vcd_status = VCD_S_SUCCESS;
}
break;
+ case VCD_I_ENABLE_VUI_TIMING_INFO:
+ if (sizeof(struct vcd_property_vui_timing_info_enable) ==
+ property_hdr->sz) {
+ ((struct vcd_property_vui_timing_info_enable *)
+ property_value)->vui_timing_info =
+ encoder->vui_timinginfo_enable;
+ vcd_status = VCD_S_SUCCESS;
+ }
+ break;
default:
vcd_status = VCD_ERR_ILLEGAL_OP;
break;
@@ -1715,6 +1738,7 @@
encoder->slice_delivery_info.num_slices = 0;
encoder->slice_delivery_info.num_slices_enc = 0;
encoder->avc_delimiter_enable = 0;
+ encoder->vui_timinginfo_enable = 0;
}
static void ddl_set_default_enc_profile(struct ddl_encoder_data *encoder)
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
index 40dc2aa..7bdb3b9 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
@@ -83,6 +83,8 @@
#define VIDC_SM_ENC_EXT_CTRL_ADDR 0x0028
#define VIDC_SM_ENC_EXT_CTRL_VBV_BUFFER_SIZE_BMSK 0xffff0000
#define VIDC_SM_ENC_EXT_CTRL_VBV_BUFFER_SIZE_SHFT 16
+#define VIDC_SM_ENC_EXT_CTRL_TIMING_INFO_EN_BMSK 0x00004000
+#define VIDC_SM_ENC_EXT_CTRL_TIMING_INFO_EN_SHFT 14
#define VIDC_SM_ENC_EXT_CTRL_AU_DELIMITER_EN_BMSK 0x00000800
#define VIDC_SM_ENC_EXT_CTRL_AU_DELIMITER_EN_SHFT 11
#define VIDC_SM_ENC_EXT_CTRL_H263_CPCFC_ENABLE_BMSK 0x80
@@ -176,6 +178,13 @@
#define VIDC_SM_ENC_NUM_OF_SLICE_COMP_ADDR 0x01d0
#define VIDC_SM_ENC_NUM_OF_SLICE_COMP_VALUE_BMSK 0xffffffff
#define VIDC_SM_ENC_NUM_OF_SLICE_COMP_VALUE_SHFT 0
+#define VIDC_SM_ENC_NUM_UNITS_IN_TICK_ADDR 0x01dc
+#define VIDC_SM_ENC_NUM_UNITS_IN_TICK_VALUE_BMSK 0xffffffff
+#define VIDC_SM_ENC_NUM_UNITS_IN_TICK_VALUE_SHFT 0
+#define VIDC_SM_ENC_TIME_SCALE_ADDR 0x01e0
+#define VIDC_SM_ENC_TIME_SCALE_VALUE_BMSK 0xffffffff
+#define VIDC_SM_ENC_TIME_SCALE_VALUE_SHFT 0
+
#define VIDC_SM_ALLOCATED_LUMA_DPB_SIZE_ADDR 0x0064
#define VIDC_SM_ALLOCATED_CHROMA_DPB_SIZE_ADDR 0x0068
@@ -449,7 +458,8 @@
enum VIDC_SM_frame_skip frame_skip_mode,
u32 seq_hdr_in_band, u32 vbv_buffer_size, u32 cpcfc_enable,
u32 sps_pps_control, u32 closed_gop_enable,
- u32 au_delim_enable)
+ u32 au_delim_enable,
+ u32 vui_timing_info_enable)
{
u32 enc_ctrl;
enc_ctrl = VIDC_SETFIELD((hec_enable) ? 1 : 0,
@@ -475,7 +485,10 @@
VIDC_SM_ENC_EXT_CTRL_CLOSED_GOP_ENABLE_BMSK) |
VIDC_SETFIELD((au_delim_enable) ? 1 : 0,
VIDC_SM_ENC_EXT_CTRL_AU_DELIMITER_EN_SHFT,
- VIDC_SM_ENC_EXT_CTRL_AU_DELIMITER_EN_BMSK);
+ VIDC_SM_ENC_EXT_CTRL_AU_DELIMITER_EN_BMSK) |
+ VIDC_SETFIELD((vui_timing_info_enable) ? 1 : 0,
+ VIDC_SM_ENC_EXT_CTRL_TIMING_INFO_EN_SHFT,
+ VIDC_SM_ENC_EXT_CTRL_TIMING_INFO_EN_BMSK);
DDL_MEM_WRITE_32(shared_mem, VIDC_SM_ENC_EXT_CTRL_ADDR, enc_ctrl);
}
@@ -1139,3 +1152,15 @@
VIDC_SM_MP2_DATA_DUMP_BUFFER_SIZE_ADDR,
mp2datadumpsize);
}
+
+void vidc_sm_set_h264_encoder_timing_info(struct ddl_buf_addr *shared_mem,
+ u32 num_units_in_tick, u32 time_scale)
+{
+ DDL_MEM_WRITE_32(shared_mem,
+ VIDC_SM_ENC_NUM_UNITS_IN_TICK_ADDR,
+ num_units_in_tick);
+
+ DDL_MEM_WRITE_32(shared_mem,
+ VIDC_SM_ENC_TIME_SCALE_ADDR,
+ time_scale);
+}
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h
index c4d577b..2eef99d 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h
@@ -106,7 +106,7 @@
struct ddl_buf_addr *shared_mem, u32 hec_enable,
enum VIDC_SM_frame_skip frame_skip_mode, u32 seq_hdr_in_band,
u32 vbv_buffer_size, u32 cpcfc_enable, u32 sps_pps_control,
- u32 closed_gop_enable, u32 au_delim_enable);
+ u32 closed_gop_enable, u32 au_delim_enable, u32 vui_timing_info_enable);
void vidc_sm_set_encoder_param_change(struct ddl_buf_addr *shared_mem,
u32 bit_rate_chg, u32 frame_rate_chg, u32 i_period_chg);
void vidc_sm_set_encoder_vop_time(struct ddl_buf_addr *shared_mem,
@@ -198,6 +198,8 @@
void vidc_sm_set_mp2datadump_enable(struct ddl_buf_addr *shared_mem,
struct ddl_mp2_datadumpenabletype *ddl_mp2_datadump_enable);
void vidc_sm_set_mp2datadumpbuffer(struct ddl_buf_addr *shared_mem,
- u32 mp2datadumpaddr, u32 mp2datadumpsize);
+ u32 mp2datadumpaddr, u32 mp2datadumpsize);
+void vidc_sm_set_h264_encoder_timing_info(struct ddl_buf_addr *shared_mem,
+ u32 num_units_in_tick, u32 time_scale);
#endif
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.h
index bbde7ae..6817101 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.h
@@ -62,7 +62,8 @@
#define DDL_GET_ALIGNED_VITUAL(x) ((x).align_virtual_addr)
#define DDL_KILO_BYTE(x) ((x)*1024)
#define DDL_MEGA_BYTE(x) ((x)*1024*1024)
-#define DDL_FRAMERATE_SCALE(x) ((x) * 1000)
+#define DDL_FRAMERATE_SCALE_FACTOR (1000)
+#define DDL_FRAMERATE_SCALE(x) ((x) * DDL_FRAMERATE_SCALE_FACTOR)
#define DDL_MIN(x, y) ((x < y) ? x : y)
#define DDL_MAX(x, y) ((x > y) ? x : y)
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
index 5eed305..76972ca 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
@@ -370,6 +370,15 @@
(u32)(DDL_FRAMERATE_SCALE(encoder->\
frame_rate.fps_numerator) /
encoder->frame_rate.fps_denominator));
+ if (encoder->vui_timinginfo_enable &&
+ encoder->frame_rate.fps_denominator) {
+ vidc_sm_set_h264_encoder_timing_info(
+ &ddl->shared_mem[ddl->command_channel],
+ DDL_FRAMERATE_SCALE_FACTOR,
+ (u32)(DDL_FRAMERATE_SCALE(encoder->\
+ frame_rate.fps_numerator) / encoder->\
+ frame_rate.fps_denominator) << 1);
+ }
encoder->dynamic_prop_change &=
~(DDL_ENC_CHANGE_FRAMERATE);
}
@@ -596,7 +605,14 @@
[ddl->command_channel], hdr_ext_control,
r_cframe_skip, false, 0,
h263_cpfc_enable, encoder->sps_pps.sps_pps_for_idr_enable_flag,
- encoder->closed_gop, encoder->avc_delimiter_enable);
+ encoder->closed_gop, encoder->avc_delimiter_enable,
+ encoder->vui_timinginfo_enable);
+ if (encoder->vui_timinginfo_enable) {
+ vidc_sm_set_h264_encoder_timing_info(
+ &ddl->shared_mem[ddl->command_channel],
+ DDL_FRAMERATE_SCALE_FACTOR,
+ scaled_frame_rate << 1);
+ }
vidc_sm_set_encoder_init_rc_value(&ddl->shared_mem
[ddl->command_channel],
encoder->target_bit_rate.target_bitrate);
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index 98cce5b..29546b7 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -445,4 +445,5 @@
header-y += genlock.h
header-y += msm_audio_amrwb.h
header-y += coresight-stm.h
-header-y += ci-bridge-spi.h
\ No newline at end of file
+header-y += ci-bridge-spi.h
+header-y += msm_audio_amrwbplus.h
diff --git a/include/linux/mfd/pm8xxx/pm8921-bms.h b/include/linux/mfd/pm8xxx/pm8921-bms.h
index 82ec57d..6db6204 100644
--- a/include/linux/mfd/pm8xxx/pm8921-bms.h
+++ b/include/linux/mfd/pm8xxx/pm8921-bms.h
@@ -37,6 +37,10 @@
* is considered empty(mV)
* @enable_fcc_learning: if set the driver will learn full charge
* capacity of the battery upon end of charge
+ * @normal_voltage_calc_ms: The period of soc calculation in ms when battery
+ * voltage higher than cutoff voltage
+ * @low_voltage_calc_ms: The period of soc calculation in ms when battery
+ * voltage is near cutoff voltage
*/
struct pm8921_bms_platform_data {
struct pm8xxx_bms_core_data bms_cdata;
@@ -51,6 +55,8 @@
int ignore_shutdown_soc;
int adjust_soc_low_threshold;
int chg_term_ua;
+ int normal_voltage_calc_ms;
+ int low_voltage_calc_ms;
};
#if defined(CONFIG_PM8921_BMS) || defined(CONFIG_PM8921_BMS_MODULE)
diff --git a/include/linux/mfd/pm8xxx/pm8921-charger.h b/include/linux/mfd/pm8xxx/pm8921-charger.h
index 4ad55f4..12094e2 100644
--- a/include/linux/mfd/pm8xxx/pm8921-charger.h
+++ b/include/linux/mfd/pm8xxx/pm8921-charger.h
@@ -96,10 +96,6 @@
* @get_batt_capacity_percent:
* a board specific function to return battery
* capacity. If null - a default one will be used
- * @dc_unplug_check: enables the reverse boosting fix for the DC_IN line
- * however, this should only be enabled for devices which
- * control the DC OVP FETs otherwise this option should
- * remain disabled
* @has_dc_supply: report DC online if this bit is set in board file
* @trkl_voltage: the trkl voltage in (mV) below which hw controlled
* trkl charging happens with linear charger
@@ -152,7 +148,6 @@
int64_t batt_id_min;
int64_t batt_id_max;
bool keep_btm_on_suspend;
- bool dc_unplug_check;
bool has_dc_supply;
int trkl_voltage;
int weak_voltage;
@@ -178,15 +173,6 @@
void pm8921_charger_vbus_draw(unsigned int mA);
int pm8921_charger_register_vbus_sn(void (*callback)(int));
void pm8921_charger_unregister_vbus_sn(void (*callback)(int));
-/**
- * pm8921_charger_enable -
- *
- * @enable: 1 means enable charging, 0 means disable
- *
- * Enable/Disable battery charging current, the device will still draw current
- * from the charging source
- */
-int pm8921_charger_enable(bool enable);
/**
* pm8921_is_usb_chg_plugged_in - is usb plugged in
@@ -312,10 +298,6 @@
static inline void pm8921_charger_unregister_vbus_sn(void (*callback)(int))
{
}
-static inline int pm8921_charger_enable(bool enable)
-{
- return -ENXIO;
-}
static inline int pm8921_is_usb_chg_plugged_in(void)
{
return -ENXIO;
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index f435221..6c43ec7 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -138,6 +138,8 @@
void (*enable_preset_value)(struct mmc_host *host, bool enable);
int (*select_drive_strength)(unsigned int max_dtr, int host_drv, int card_drv);
void (*hw_reset)(struct mmc_host *host);
+ unsigned long (*get_max_frequency)(struct mmc_host *host);
+ unsigned long (*get_min_frequency)(struct mmc_host *host);
};
struct mmc_card;
@@ -250,6 +252,7 @@
#define MMC_CAP2_SANITIZE (1 << 13) /* Support Sanitize */
#define MMC_CAP2_INIT_BKOPS (1 << 15) /* Need to set BKOPS_EN */
+#define MMC_CAP2_CLK_SCALE (1 << 16) /* Allow dynamic clk scaling */
mmc_pm_flag_t pm_caps; /* supported pm features */
int clk_requests; /* internal reference counter */
@@ -353,6 +356,19 @@
#endif
struct mmc_ios saved_ios;
+ struct {
+ unsigned long busy_time_us;
+ unsigned long window_time;
+ unsigned long curr_freq;
+ unsigned long polling_delay_ms;
+ unsigned int up_threshold;
+ unsigned int down_threshold;
+ ktime_t start_busy;
+ bool enable;
+ bool initialized;
+ bool in_progress;
+ struct delayed_work work;
+ } clk_scaling;
unsigned long private[0] ____cacheline_aligned;
};
@@ -468,6 +484,14 @@
return !(host->caps2 & MMC_CAP2_BOOTPART_NOACC);
}
+static inline int mmc_host_uhs(struct mmc_host *host)
+{
+ return host->caps &
+ (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
+ MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 |
+ MMC_CAP_UHS_DDR50);
+}
+
#ifdef CONFIG_MMC_CLKGATE
void mmc_host_clk_hold(struct mmc_host *host);
void mmc_host_clk_release(struct mmc_host *host);
diff --git a/include/linux/msm_audio_amrwbplus.h b/include/linux/msm_audio_amrwbplus.h
new file mode 100644
index 0000000..aa17117
--- /dev/null
+++ b/include/linux/msm_audio_amrwbplus.h
@@ -0,0 +1,18 @@
+#ifndef __MSM_AUDIO_AMR_WB_PLUS_H
+#define __MSM_AUDIO_AMR_WB_PLUS_H
+
+#define AUDIO_GET_AMRWBPLUS_CONFIG_V2 _IOR(AUDIO_IOCTL_MAGIC, \
+ (AUDIO_MAX_COMMON_IOCTL_NUM+2), struct msm_audio_amrwbplus_config_v2)
+#define AUDIO_SET_AMRWBPLUS_CONFIG_V2 _IOW(AUDIO_IOCTL_MAGIC, \
+ (AUDIO_MAX_COMMON_IOCTL_NUM+3), struct msm_audio_amrwbplus_config_v2)
+
+struct msm_audio_amrwbplus_config_v2 {
+ unsigned int size_bytes;
+ unsigned int version;
+ unsigned int num_channels;
+ unsigned int amr_band_mode;
+ unsigned int amr_dtx_mode;
+ unsigned int amr_frame_fmt;
+ unsigned int amr_lsf_idx;
+};
+#endif /* __MSM_AUDIO_AMR_WB_PLUS_H */
diff --git a/include/linux/msm_ipc.h b/include/linux/msm_ipc.h
index 44fa8eb..7b6bf41 100644
--- a/include/linux/msm_ipc.h
+++ b/include/linux/msm_ipc.h
@@ -45,6 +45,14 @@
unsigned char reserved;
};
+struct config_sec_rules_args {
+ int num_group_info;
+ uint32_t service_id;
+ uint32_t instance_id;
+ unsigned reserved;
+ gid_t group_id[0];
+};
+
#define IPC_ROUTER_IOCTL_MAGIC (0xC3)
#define IPC_ROUTER_IOCTL_GET_VERSION \
@@ -62,6 +70,9 @@
#define IPC_ROUTER_IOCTL_BIND_CONTROL_PORT \
_IOR(IPC_ROUTER_IOCTL_MAGIC, 4, unsigned int)
+#define IPC_ROUTER_IOCTL_CONFIG_SEC_RULES \
+ _IOR(IPC_ROUTER_IOCTL_MAGIC, 5, struct config_sec_rules_args)
+
struct msm_ipc_server_info {
uint32_t node_id;
uint32_t port_id;
diff --git a/include/linux/msm_kgsl.h b/include/linux/msm_kgsl.h
index 6912087..ee136cac 100644
--- a/include/linux/msm_kgsl.h
+++ b/include/linux/msm_kgsl.h
@@ -1,6 +1,13 @@
#ifndef _MSM_KGSL_H
#define _MSM_KGSL_H
+/*
+ * The KGSL version has proven not to be very useful in userspace if features
+ * are cherry picked into other trees out of order so it is frozen as of 3.14.
+ * It is left here for backwards compatabilty and as a reminder that
+ * software releases are never linear. Also, I like pie.
+ */
+
#define KGSL_VERSION_MAJOR 3
#define KGSL_VERSION_MINOR 14
@@ -16,13 +23,24 @@
#define KGSL_CONTEXT_INVALID 0xffffffff
-/* Memory allocayion flags */
-#define KGSL_MEMFLAGS_GPUREADONLY 0x01000000
+/* --- Memory allocation flags --- */
+/* General allocation hints */
+#define KGSL_MEMFLAGS_GPUREADONLY 0x01000000
+
+/* Memory caching hints */
+#define KGSL_CACHEMODE_MASK 0x0C000000
+#define KGSL_CACHEMODE_SHIFT 26
+
+#define KGSL_CACHEMODE_WRITECOMBINE 0
+#define KGSL_CACHEMODE_UNCACHED 1
+#define KGSL_CACHEMODE_WRITETHROUGH 2
+#define KGSL_CACHEMODE_WRITEBACK 3
+
+/* Memory types for which allocations are made */
#define KGSL_MEMTYPE_MASK 0x0000FF00
#define KGSL_MEMTYPE_SHIFT 8
-/* Memory types for which allocations are made */
#define KGSL_MEMTYPE_OBJECTANY 0
#define KGSL_MEMTYPE_FRAMEBUFFER 1
#define KGSL_MEMTYPE_RENDERBUFFER 2
@@ -53,7 +71,8 @@
#define KGSL_MEMALIGN_MASK 0x00FF0000
#define KGSL_MEMALIGN_SHIFT 16
-/* generic flag values */
+/* --- generic KGSL flag values --- */
+
#define KGSL_FLAGS_NORMALMODE 0x00000000
#define KGSL_FLAGS_SAFEMODE 0x00000001
#define KGSL_FLAGS_INITIALIZED0 0x00000002
@@ -419,6 +438,14 @@
#define IOCTL_KGSL_SHAREDMEM_FROM_VMALLOC \
_IOWR(KGSL_IOC_TYPE, 0x23, struct kgsl_sharedmem_from_vmalloc)
+/*
+ * This is being deprecated in favor of IOCTL_KGSL_GPUMEM_CACHE_SYNC which
+ * supports both directions (flush and invalidate). This code will still
+ * work, but by definition it will do a flush of the cache which might not be
+ * what you want to have happen on a buffer following a GPU operation. It is
+ * safer to go with IOCTL_KGSL_GPUMEM_CACHE_SYNC
+ */
+
#define IOCTL_KGSL_SHAREDMEM_FLUSH_CACHE \
_IOW(KGSL_IOC_TYPE, 0x24, struct kgsl_sharedmem_free)
@@ -511,6 +538,113 @@
#define IOCTL_KGSL_TIMESTAMP_EVENT \
_IOWR(KGSL_IOC_TYPE, 0x33, struct kgsl_timestamp_event)
+/**
+ * struct kgsl_gpumem_alloc_id - argument to IOCTL_KGSL_GPUMEM_ALLOC_ID
+ * @id: returned id value for this allocation.
+ * @flags: mask of KGSL_MEM* values requested and actual flags on return.
+ * @size: requested size of the allocation and actual size on return.
+ * @mmapsize: returned size to pass to mmap() which may be larger than 'size'
+ * @gpuaddr: returned GPU address for the allocation
+ *
+ * Allocate memory for access by the GPU. The flags and size fields are echoed
+ * back by the kernel, so that the caller can know if the request was
+ * adjusted.
+ *
+ * Supported flags:
+ * KGSL_MEMFLAGS_GPUREADONLY: the GPU will be unable to write to the buffer
+ * KGSL_MEMTYPE*: usage hint for debugging aid
+ * KGSL_MEMALIGN*: alignment hint, may be ignored or adjusted by the kernel.
+ */
+struct kgsl_gpumem_alloc_id {
+ unsigned int id;
+ unsigned int flags;
+ unsigned int size;
+ unsigned int mmapsize;
+ unsigned long gpuaddr;
+/* private: reserved for future use*/
+ unsigned int __pad[2];
+};
+
+#define IOCTL_KGSL_GPUMEM_ALLOC_ID \
+ _IOWR(KGSL_IOC_TYPE, 0x34, struct kgsl_gpumem_alloc_id)
+
+/**
+ * struct kgsl_gpumem_free_id - argument to IOCTL_KGSL_GPUMEM_FREE_ID
+ * @id: GPU allocation id to free
+ *
+ * Free an allocation by id, in case a GPU address has not been assigned or
+ * is unknown. Freeing an allocation by id with this ioctl or by GPU address
+ * with IOCTL_KGSL_SHAREDMEM_FREE are equivalent.
+ */
+struct kgsl_gpumem_free_id {
+ unsigned int id;
+/* private: reserved for future use*/
+ unsigned int __pad;
+};
+
+#define IOCTL_KGSL_GPUMEM_FREE_ID \
+ _IOWR(KGSL_IOC_TYPE, 0x35, struct kgsl_gpumem_free_id)
+
+/**
+ * struct kgsl_gpumem_get_info - argument to IOCTL_KGSL_GPUMEM_GET_INFO
+ * @gpuaddr: GPU address to query. Also set on return.
+ * @id: GPU allocation id to query. Also set on return.
+ * @flags: returned mask of KGSL_MEM* values.
+ * @size: returned size of the allocation.
+ * @mmapsize: returned size to pass mmap(), which may be larger than 'size'
+ * @useraddr: returned address of the userspace mapping for this buffer
+ *
+ * This ioctl allows querying of all user visible attributes of an existing
+ * allocation, by either the GPU address or the id returned by a previous
+ * call to IOCTL_KGSL_GPUMEM_ALLOC_ID. Legacy allocation ioctls may not
+ * return all attributes so this ioctl can be used to look them up if needed.
+ *
+ */
+struct kgsl_gpumem_get_info {
+ unsigned long gpuaddr;
+ unsigned int id;
+ unsigned int flags;
+ unsigned int size;
+ unsigned int mmapsize;
+ unsigned long useraddr;
+/* private: reserved for future use*/
+ unsigned int __pad[4];
+};
+
+#define IOCTL_KGSL_GPUMEM_GET_INFO\
+ _IOWR(KGSL_IOC_TYPE, 0x36, struct kgsl_gpumem_get_info)
+
+/**
+ * struct kgsl_gpumem_sync_cache - argument to IOCTL_KGSL_GPUMEM_SYNC_CACHE
+ * @gpuaddr: GPU address of the buffer to sync.
+ * @id: id of the buffer to sync. Either gpuaddr or id is sufficient.
+ * @op: a mask of KGSL_GPUMEM_CACHE_* values
+ *
+ * Sync the L2 cache for memory headed to and from the GPU - this replaces
+ * KGSL_SHAREDMEM_FLUSH_CACHE since it can handle cache management for both
+ * directions
+ *
+ */
+struct kgsl_gpumem_sync_cache {
+ unsigned int gpuaddr;
+ unsigned int id;
+ unsigned int op;
+/* private: reserved for future use*/
+ unsigned int __pad[2]; /* For future binary compatibility */
+};
+
+#define KGSL_GPUMEM_CACHE_CLEAN (1 << 0)
+#define KGSL_GPUMEM_CACHE_TO_GPU KGSL_GPUMEM_CACHE_CLEAN
+
+#define KGSL_GPUMEM_CACHE_INV (1 << 1)
+#define KGSL_GPUMEM_CACHE_FROM_GPU KGSL_GPUMEM_CACHE_INV
+
+#define KGSL_GPUMEM_CACHE_FLUSH \
+ (KGSL_GPUMEM_CACHE_CLEAN | KGSL_GPUMEM_CACHE_INV)
+
+#define IOCTL_KGSL_GPUMEM_SYNC_CACHE \
+ _IOW(KGSL_IOC_TYPE, 0x37, struct kgsl_gpumem_sync_cache)
+
#ifdef __KERNEL__
#ifdef CONFIG_MSM_KGSL_DRM
int kgsl_gem_obj_addr(int drm_fd, int handle, unsigned long *start,
diff --git a/include/linux/qpnp/qpnp-adc.h b/include/linux/qpnp/qpnp-adc.h
index 077ccfc..fc34b22 100644
--- a/include/linux/qpnp/qpnp-adc.h
+++ b/include/linux/qpnp/qpnp-adc.h
@@ -402,8 +402,11 @@
};
/**
- * enum qpnp_adc_meas_timer - Selects the measurement interval time.
+ * enum qpnp_adc_meas_timer_1 - Selects the measurement interval time.
* If value = 0, use 0ms else use 2^(value + 4)/ 32768).
+ * The timer period is used by the USB_ID. Do not set a polling rate
+ * greater than 1 second on PMIC 2.0. The max polling rate on the PMIC 2.0
+ * appears to be limited to 1 second.
* %ADC_MEAS_INTERVAL_0MS : 0ms
* %ADC_MEAS_INTERVAL_1P0MS : 1ms
* %ADC_MEAS_INTERVAL_2P0MS : 2ms
@@ -421,24 +424,126 @@
* %ADC_MEAS_INTERVAL_8S : 8seconds
* %ADC_MEAS_INTERVAL_16S: 16seconds
*/
-enum qpnp_adc_meas_timer {
- ADC_MEAS_INTERVAL_0MS = 0,
- ADC_MEAS_INTERVAL_1P0MS,
- ADC_MEAS_INTERVAL_2P0MS,
- ADC_MEAS_INTERVAL_3P9MS,
- ADC_MEAS_INTERVAL_7P8MS,
- ADC_MEAS_INTERVAL_15P6MS,
- ADC_MEAS_INTERVAL_31P3MS,
- ADC_MEAS_INTERVAL_62P5MS,
- ADC_MEAS_INTERVAL_125MS,
- ADC_MEAS_INTERVAL_250MS,
- ADC_MEAS_INTERVAL_500MS,
- ADC_MEAS_INTERVAL_1S,
- ADC_MEAS_INTERVAL_2S,
- ADC_MEAS_INTERVAL_4S,
- ADC_MEAS_INTERVAL_8S,
- ADC_MEAS_INTERVAL_16S,
- ADC_MEAS_INTERVAL_NONE,
+enum qpnp_adc_meas_timer_1 {
+ ADC_MEAS1_INTERVAL_0MS = 0,
+ ADC_MEAS1_INTERVAL_1P0MS,
+ ADC_MEAS1_INTERVAL_2P0MS,
+ ADC_MEAS1_INTERVAL_3P9MS,
+ ADC_MEAS1_INTERVAL_7P8MS,
+ ADC_MEAS1_INTERVAL_15P6MS,
+ ADC_MEAS1_INTERVAL_31P3MS,
+ ADC_MEAS1_INTERVAL_62P5MS,
+ ADC_MEAS1_INTERVAL_125MS,
+ ADC_MEAS1_INTERVAL_250MS,
+ ADC_MEAS1_INTERVAL_500MS,
+ ADC_MEAS1_INTERVAL_1S,
+ ADC_MEAS1_INTERVAL_2S,
+ ADC_MEAS1_INTERVAL_4S,
+ ADC_MEAS1_INTERVAL_8S,
+ ADC_MEAS1_INTERVAL_16S,
+ ADC_MEAS1_INTERVAL_NONE,
+};
+
+/**
+ * enum qpnp_adc_meas_timer_2 - Selects the measurement interval time.
+ * If value = 0, use 0ms else use 2^(value + 4)/ 32768).
+ * The timer period is used by the batt_therm. Do not set a polling rate
+ * greater than 1 second on PMIC 2.0. The max polling rate on the PMIC 2.0
+ * appears to be limited to 1 second.
+ * %ADC_MEAS_INTERVAL_0MS : 0ms
+ * %ADC_MEAS_INTERVAL_100MS : 100ms
+ * %ADC_MEAS_INTERVAL_200MS : 200ms
+ * %ADC_MEAS_INTERVAL_300MS : 300ms
+ * %ADC_MEAS_INTERVAL_400MS : 400ms
+ * %ADC_MEAS_INTERVAL_500MS : 500ms
+ * %ADC_MEAS_INTERVAL_600MS : 600ms
+ * %ADC_MEAS_INTERVAL_700MS : 700ms
+ * %ADC_MEAS_INTERVAL_800MS : 800ms
+ * %ADC_MEAS_INTERVAL_900MS : 900ms
+ * %ADC_MEAS_INTERVAL_1S: 1seconds
+ * %ADC_MEAS_INTERVAL_1P1S: 1.1seconds
+ * %ADC_MEAS_INTERVAL_1P2S: 1.2seconds
+ * %ADC_MEAS_INTERVAL_1P3S: 1.3seconds
+ * %ADC_MEAS_INTERVAL_1P4S: 1.4seconds
+ * %ADC_MEAS_INTERVAL_1P5S: 1.5seconds
+ */
+enum qpnp_adc_meas_timer_2 {
+ ADC_MEAS2_INTERVAL_0MS = 0,
+ ADC_MEAS2_INTERVAL_100MS,
+ ADC_MEAS2_INTERVAL_200MS,
+ ADC_MEAS2_INTERVAL_300MS,
+ ADC_MEAS2_INTERVAL_400MS,
+ ADC_MEAS2_INTERVAL_500MS,
+ ADC_MEAS2_INTERVAL_600MS,
+ ADC_MEAS2_INTERVAL_700MS,
+ ADC_MEAS2_INTERVAL_800MS,
+ ADC_MEAS2_INTERVAL_900MS,
+ ADC_MEAS2_INTERVAL_1S,
+ ADC_MEAS2_INTERVAL_1P1S,
+ ADC_MEAS2_INTERVAL_1P2S,
+ ADC_MEAS2_INTERVAL_1P3S,
+ ADC_MEAS2_INTERVAL_1P4S,
+ ADC_MEAS2_INTERVAL_1P5S,
+ ADC_MEAS2_INTERVAL_NONE,
+};
+
+/**
+ * enum qpnp_adc_meas_timer_3 - Selects the measurement interval time.
+ * If value = 0, use 0ms else use 2^(value + 4)/ 32768).
+ * Do not set a polling rate greater than 1 second on PMIC 2.0.
+ * The max polling rate on the PMIC 2.0 appears to be limited to 1 second.
+ * %ADC_MEAS_INTERVAL_0MS : 0ms
+ * %ADC_MEAS_INTERVAL_1S : 1seconds
+ * %ADC_MEAS_INTERVAL_2S : 2seconds
+ * %ADC_MEAS_INTERVAL_3S : 3seconds
+ * %ADC_MEAS_INTERVAL_4S : 4seconds
+ * %ADC_MEAS_INTERVAL_5S : 5seconds
+ * %ADC_MEAS_INTERVAL_6S: 6seconds
+ * %ADC_MEAS_INTERVAL_7S : 7seconds
+ * %ADC_MEAS_INTERVAL_8S : 8seconds
+ * %ADC_MEAS_INTERVAL_9S : 9seconds
+ * %ADC_MEAS_INTERVAL_10S : 10seconds
+ * %ADC_MEAS_INTERVAL_11S : 11seconds
+ * %ADC_MEAS_INTERVAL_12S : 12seconds
+ * %ADC_MEAS_INTERVAL_13S : 13seconds
+ * %ADC_MEAS_INTERVAL_14S : 14seconds
+ * %ADC_MEAS_INTERVAL_15S : 15seconds
+ */
+enum qpnp_adc_meas_timer_3 {
+ ADC_MEAS3_INTERVAL_0S = 0,
+ ADC_MEAS3_INTERVAL_1S,
+ ADC_MEAS3_INTERVAL_2S,
+ ADC_MEAS3_INTERVAL_3S,
+ ADC_MEAS3_INTERVAL_4S,
+ ADC_MEAS3_INTERVAL_5S,
+ ADC_MEAS3_INTERVAL_6S,
+ ADC_MEAS3_INTERVAL_7S,
+ ADC_MEAS3_INTERVAL_8S,
+ ADC_MEAS3_INTERVAL_9S,
+ ADC_MEAS3_INTERVAL_10S,
+ ADC_MEAS3_INTERVAL_11S,
+ ADC_MEAS3_INTERVAL_12S,
+ ADC_MEAS3_INTERVAL_13S,
+ ADC_MEAS3_INTERVAL_14S,
+ ADC_MEAS3_INTERVAL_15S,
+ ADC_MEAS3_INTERVAL_NONE,
+};
+
+/**
+ * enum qpnp_adc_meas_timer_select - Selects the timer for which
+ * the appropriate polling frequency is set.
+ * %ADC_MEAS_TIMER_SELECT1 - Select this timer if the client is USB_ID.
+ * %ADC_MEAS_TIMER_SELECT2 - Select this timer if the client is batt_therm.
+ * %ADC_MEAS_TIMER_SELECT3 - The timer is added only for completion. It is
+ * not used by kernel space clients and user space clients cannot set
+ * the polling frequency. The driver will set a appropriate polling
+ * frequency to measure the user space clients from qpnp_adc_meas_timer_3.
+ */
+enum qpnp_adc_meas_timer_select {
+ ADC_MEAS_TIMER_SELECT1 = 0,
+ ADC_MEAS_TIMER_SELECT2,
+ ADC_MEAS_TIMER_SELECT3,
+ ADC_MEAS_TIMER_NUM,
};
/**
@@ -455,6 +560,134 @@
};
/**
+ * Channel selection registers for each of the 5 configurable measurements
+ * Channels allotment is fixed for the given channels below.
+ * The USB_ID and BATT_THERM channels are used only by the kernel space
+ * USB and Battery drivers.
+ * The other 3 channels are configurable for use by userspace clients.
+ * USB_ID uses QPNP_ADC_TM_M0_ADC_CH_SEL_CTL
+ * BATT_TEMP uses QPNP_ADC_TM_M1_ADC_CH_SEL_CTL
+ * PA_THERM1 uses QPNP_ADC_TM_M2_ADC_CH_SEL_CTL
+ * PA_THERM2 uses QPNP_ADC_TM_M3_ADC_CH_SEL_CTL
+ * EMMC_THERM uses QPNP_ADC_TM_M4_ADC_CH_SEL_CTL
+ */
+enum qpnp_adc_tm_channel_select {
+ QPNP_ADC_TM_M0_ADC_CH_SEL_CTL = 0x48,
+ QPNP_ADC_TM_M1_ADC_CH_SEL_CTL = 0x68,
+ QPNP_ADC_TM_M2_ADC_CH_SEL_CTL = 0x70,
+ QPNP_ADC_TM_M3_ADC_CH_SEL_CTL = 0x78,
+ QPNP_ADC_TM_M4_ADC_CH_SEL_CTL = 0x80,
+ QPNP_ADC_TM_CH_SELECT_NONE
+};
+
+/**
+ * struct qpnp_adc_tm_config - Represent ADC Thermal Monitor configuration.
+ * @channel: ADC channel for which thermal monitoring is requested.
+ * @adc_code: The pre-calibrated digital output of a given ADC releative to the
+ * ADC reference.
+ * @high_thr_temp: Temperature at which high threshold notification is required.
+ * @low_thr_temp: Temperature at which low threshold notification is required.
+ * @low_thr_voltage : Low threshold voltage ADC code used for reverse
+ * calibration.
+ * @high_thr_voltage: High threshold voltage ADC code used for reverse
+ * calibration.
+ */
+struct qpnp_adc_tm_config {
+ int channel;
+ int adc_code;
+ int high_thr_temp;
+ int low_thr_temp;
+ int64_t high_thr_voltage;
+ int64_t low_thr_voltage;
+};
+
+/**
+ * enum qpnp_adc_tm_trip_type - Type for setting high/low temperature/voltage.
+ * %ADC_TM_TRIP_HIGH_WARM: Setting high temperature. Note that high temperature
+ * corresponds to low voltage. Driver handles this case
+ * appropriately to set high/low thresholds for voltage.
+ * threshold.
+ * %ADC_TM_TRIP_LOW_COOL: Setting low temperature.
+ */
+enum qpnp_adc_tm_trip_type {
+ ADC_TM_TRIP_HIGH_WARM = 0,
+ ADC_TM_TRIP_LOW_COOL,
+ ADC_TM_TRIP_NUM,
+};
+
+/**
+ * enum qpnp_tm_state - This lets the client know whether the threshold
+ * that was crossed was high/low.
+ * %ADC_TM_HIGH_STATE: Client is notified of crossing the requested high
+ * threshold.
+ * %ADC_TM_LOW_STATE: Client is notified of crossing the requested low
+ * threshold.
+ */
+enum qpnp_tm_state {
+ ADC_TM_HIGH_STATE = 0,
+ ADC_TM_LOW_STATE,
+ ADC_TM_STATE_NUM,
+};
+
+/**
+ * enum qpnp_state_request - Request to enable/disable the corresponding
+ * high/low voltage/temperature thresholds.
+ * %ADC_TM_HIGH_THR_ENABLE: Enable high voltage/temperature threshold.
+ * %ADC_TM_LOW_THR_ENABLE: Enable low voltage/temperature threshold.
+ * %ADC_TM_HIGH_LOW_THR_ENABLE: Enable high and low voltage/temperature
+ * threshold.
+ * %ADC_TM_HIGH_THR_DISABLE: Disable high voltage/temperature threshold.
+ * %ADC_TM_LOW_THR_DISABLE: Disable low voltage/temperature threshold.
+ * %ADC_TM_HIGH_THR_DISABLE: Disable high and low voltage/temperature
+ * threshold.
+ */
+enum qpnp_state_request {
+ ADC_TM_HIGH_THR_ENABLE = 0,
+ ADC_TM_LOW_THR_ENABLE,
+ ADC_TM_HIGH_LOW_THR_ENABLE,
+ ADC_TM_HIGH_THR_DISABLE,
+ ADC_TM_LOW_THR_DISABLE,
+ ADC_TM_HIGH_LOW_THR_DISABLE,
+ ADC_TM_THR_NUM,
+};
+
+/**
+ * struct qpnp_adc_tm_usbid_param - Represent USB_ID threshold
+ * monitoring configuration.
+ * @high_thr: High voltage threshold for which notification is requested.
+ * @low_thr: Low voltage threshold for which notification is requested.
+ * @state_request: Enable/disable the corresponding high and low voltage
+ * thresholds.
+ * @timer_interval: Select polling rate from qpnp_adc_meas_timer_1 type.
+ * @threshold_notification: Notification callback once threshold are crossed.
+ */
+struct qpnp_adc_tm_usbid_param {
+ int32_t high_thr;
+ int32_t low_thr;
+ enum qpnp_state_request state_request;
+ enum qpnp_adc_meas_timer_1 timer_interval;
+ void (*threshold_notification) (enum qpnp_tm_state state);
+};
+
+/**
+ * struct qpnp_adc_tm_btm_param - Represent Battery temperature threshold
+ * monitoring configuration.
+ * @high_temp: High temperature threshold for which notification is requested.
+ * @low_temp: Low temperature threshold for which notification is requested.
+ * @state_request: Enable/disable the corresponding high and low temperature
+ * thresholds.
+ * @timer_interval: Select polling rate from qpnp_adc_meas_timer_2 type.
+ * @threshold_notification: Notification callback once threshold are crossed.
+ */
+struct qpnp_adc_tm_btm_param {
+ int32_t high_temp;
+ int32_t low_temp;
+ enum qpnp_state_request state_request;
+ enum qpnp_adc_meas_timer_2 timer_interval;
+ void (*threshold_notification) (enum qpnp_tm_state state);
+};
+
+/**
* struct qpnp_vadc_linear_graph - Represent ADC characteristics.
* @dy: Numerator slope to calculate the gain.
* @dx: Denominator slope to calculate the gain.
@@ -541,7 +774,7 @@
};
/**
- * struct qpnp_adc_amux - AMUX properties for individual channel
+ * struct qpnp_vadc_amux - AMUX properties for individual channel
* @name: Channel string name.
* @channel_num: Channel in integer used from qpnp_adc_channels.
* @chan_path_prescaling: Channel scaling performed on the input signal.
@@ -624,7 +857,7 @@
* @adc_prop - ADC properties specific to the ADC peripheral.
* @amux_prop - AMUX properties representing the ADC peripheral.
* @adc_channels - ADC channel properties for the ADC peripheral.
- * @adc_irq - IRQ number that is mapped to the ADC peripheral.
+ * @adc_irq_eoc - End of Conversion IRQ.
* @adc_lock - ADC lock for access to the peripheral.
* @adc_rslt_completion - ADC result notification after interrupt
* is received.
@@ -637,7 +870,7 @@
struct qpnp_adc_properties *adc_prop;
struct qpnp_adc_amux_properties *amux_prop;
struct qpnp_vadc_amux *adc_channels;
- int adc_irq;
+ int adc_irq_eoc;
struct mutex adc_lock;
struct completion adc_rslt_completion;
struct qpnp_iadc_calib calib;
@@ -828,6 +1061,70 @@
* has not occured.
*/
int32_t qpnp_vadc_is_ready(void);
+/**
+ * qpnp_adc_tm_scaler() - Performs reverse calibration.
+ * @config: Thermal monitoring configuration.
+ * @adc_prop: adc properties of the qpnp adc such as bit resolution and
+ * reference voltage.
+ * @chan_prop: Individual channel properties to compensate the i/p scaling,
+ * slope and offset.
+ */
+static inline int32_t qpnp_adc_tm_scaler(struct qpnp_adc_tm_config *tm_config,
+ const struct qpnp_adc_properties *adc_prop,
+ const struct qpnp_vadc_chan_properties *chan_prop)
+{ return -ENXIO; }
+/**
+ * qpnp_get_vadc_gain_and_offset() - Obtains the VADC gain and offset
+ * for absolute and ratiometric calibration.
+ * @param: The result in which the ADC offset and gain values are stored.
+ * @type: The calibration type whether client needs the absolute or
+ * ratiometric gain and offset values.
+ */
+int32_t qpnp_get_vadc_gain_and_offset(struct qpnp_vadc_linear_graph *param,
+ enum qpnp_adc_calib_type calib_type);
+/**
+ * qpnp_adc_btm_scaler() - Performs reverse calibration on the low/high
+ * temperature threshold values passed by the client.
+ * The function maps the temperature to voltage and applies
+ * ratiometric calibration on the voltage values.
+ * @param: The input parameters that contain the low/high temperature
+ * values.
+ * @low_threshold: The low threshold value that needs to be updated with
+ * the above calibrated voltage value.
+ * @high_threshold: The low threshold value that needs to be updated with
+ * the above calibrated voltage value.
+ */
+int32_t qpnp_adc_btm_scaler(struct qpnp_adc_tm_btm_param *param,
+ uint32_t *low_threshold, uint32_t *high_threshold);
+/**
+ * qpnp_adc_tm_scale_therm_voltage_pu2() - Performs reverse calibration
+ * and convert given temperature to voltage on supported
+ * thermistor channels using 100k pull-up.
+ * @param: The input temperature values.
+ */
+int32_t qpnp_adc_tm_scale_therm_voltage_pu2(struct qpnp_adc_tm_config *param);
+/**
+ * qpnp_adc_tm_scale_therm_voltage_pu2() - Performs reverse calibration
+ * and converts the given ADC code to temperature for
+ * thermistor channels using 100k pull-up.
+ * @reg: The input ADC code.
+ * @result: The physical measurement temperature on the thermistor.
+ */
+int32_t qpnp_adc_tm_scale_voltage_therm_pu2(uint32_t reg, int64_t *result);
+/**
+ * qpnp_adc_usb_scaler() - Performs reverse calibration on the low/high
+ * voltage threshold values passed by the client.
+ * The function applies ratiometric calibration on the
+ * voltage values.
+ * @param: The input parameters that contain the low/high voltage
+ * threshold values.
+ * @low_threshold: The low threshold value that needs to be updated with
+ * the above calibrated voltage value.
+ * @high_threshold: The low threshold value that needs to be updated with
+ * the above calibrated voltage value.
+ */
+int32_t qpnp_adc_usb_scaler(struct qpnp_adc_tm_usbid_param *param,
+ uint32_t *low_threshold, uint32_t *high_threshold);
#else
static inline int32_t qpnp_vadc_read(uint32_t channel,
struct qpnp_vadc_result *result)
@@ -874,6 +1171,29 @@
{ return -ENXIO; }
static inline int32_t qpnp_vadc_is_ready(void)
{ return -ENXIO; }
+static inline int32_t qpnp_adc_scale_default(int32_t adc_code,
+ const struct qpnp_adc_properties *adc_prop,
+ const struct qpnp_adc_chan_properties *chan_prop,
+ struct qpnp_adc_chan_result *chan_rslt)
+{ return -ENXIO; }
+static inline int32_t qpnp_get_vadc_gain_and_offset(
+ struct qpnp_vadc_linear_graph *param,
+ enum qpnp_adc_calib_type calib_type)
+{ return -ENXIO; }
+static inline int32_t qpnp_adc_usb_scaler(
+ struct qpnp_adc_tm_usbid_param *param,
+ uint32_t *low_threshold, uint32_t *high_threshold)
+{ return -ENXIO; }
+static inline int32_t qpnp_adc_btm_scaler(
+ struct qpnp_adc_tm_btm_param *param,
+ uint32_t *low_threshold, uint32_t *high_threshold)
+{ return -ENXIO; }
+static inline int32_t qpnp_adc_tm_scale_therm_voltage_pu2(
+ struct qpnp_adc_tm_config *param)
+{ return -ENXIO; }
+static inline int32_t qpnp_adc_tm_scale_voltage_therm_pu2(
+ uint32_t reg, int64_t *result)
+{ return -ENXIO; }
#endif
/* Public API */
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index d6fbc64..5b7820d 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -333,7 +333,6 @@
bool sm_work_pending;
atomic_t pm_suspended;
atomic_t in_lpm;
- atomic_t suspend_work_pending;
int async_int;
unsigned cur_power;
struct delayed_work chg_work;
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index b1f534d..e5e0bb4 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -1833,6 +1833,12 @@
V4L2_MPEG_VIDC_INDEX_EXTRADATA_DIGITAL_ZOOM,
V4L2_MPEG_VIDC_INDEX_EXTRADATA_ASPECT_RATIO,
};
+#define V4L2_CID_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 23)
+enum v4l2_mpeg_vidc_video_h264_vui_timing_info {
+ V4L2_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO_DISABLED = 0,
+ V4L2_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO_ENABLED = 1
+};
/* Camera class control IDs */
#define V4L2_CID_CAMERA_CLASS_BASE (V4L2_CTRL_CLASS_CAMERA | 0x900)
diff --git a/include/media/msm/vcd_property.h b/include/media/msm/vcd_property.h
index 180b38d..545dcd2 100644
--- a/include/media/msm/vcd_property.h
+++ b/include/media/msm/vcd_property.h
@@ -56,6 +56,8 @@
#define VCD_I_VOP_TIMING_CONSTANT_DELTA (VCD_START_BASE + 0x28)
#define VCD_I_SET_TURBO_CLK (VCD_START_BASE + 0x29)
#define VCD_I_ENABLE_DELIMITER_FLAG (VCD_START_BASE + 0x2A)
+#define VCD_I_ENABLE_VUI_TIMING_INFO (VCD_START_BASE + 0x2B)
+
#define VCD_START_REQ (VCD_START_BASE + 0x1000)
#define VCD_I_REQ_IFRAME (VCD_START_REQ + 0x1)
@@ -378,4 +380,8 @@
u32 avc_delimiter_enable_flag;
};
+struct vcd_property_vui_timing_info_enable {
+ u32 vui_timing_info;
+};
+
#endif
diff --git a/include/media/vcap_fmt.h b/include/media/vcap_fmt.h
index 84d9b42..369cf45 100644
--- a/include/media/vcap_fmt.h
+++ b/include/media/vcap_fmt.h
@@ -38,8 +38,8 @@
};
enum hal_vcap_polar {
- HAL_VCAP_POLAR_NEG = 0,
- HAL_VCAP_POLAR_POS,
+ HAL_VCAP_POLAR_POS = 0,
+ HAL_VCAP_POLAR_NEG,
};
enum hal_vcap_color {
diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index 14ccf3e..3bf514f 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -247,6 +247,11 @@
bdaddr_t bdaddr;
} __packed;
+#define MGMT_OP_CANCEL_RESOLVE_NAME 0x0024
+struct mgmt_cp_cancel_resolve_name {
+ bdaddr_t bdaddr;
+} __packed;
+
#define MGMT_OP_LE_READ_WHITE_LIST_SIZE 0xE000
#define MGMT_OP_LE_CLEAR_WHITE_LIST 0xE001
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
index 4376ece..3dd0ccd 100644
--- a/include/sound/apr_audio-v2.h
+++ b/include/sound/apr_audio-v2.h
@@ -712,8 +712,8 @@
#define AFE_PORT_ID_PRIMARY_MI2S_TX 0x1001
#define AFE_PORT_ID_SECONDARY_MI2S_RX 0x1002
#define AFE_PORT_ID_SECONDARY_MI2S_TX 0x1003
-#define AFE_PORT_IDERTIARY_MI2S_RX 0x1004
-#define AFE_PORT_IDERTIARY_MI2S_TX 0x1005
+#define AFE_PORT_ID_TERTIARY_MI2S_RX 0x1004
+#define AFE_PORT_ID_TERTIARY_MI2S_TX 0x1005
#define AFE_PORT_ID_QUATERNARY_MI2S_RX 0x1006
#define AFE_PORT_ID_QUATERNARY_MI2S_TX 0x1007
#define AUDIO_PORT_ID_I2S_RX 0x1008
diff --git a/include/sound/msm-dai-q6-v2.h b/include/sound/msm-dai-q6-v2.h
index 6c60318..4ecd435 100644
--- a/include/sound/msm-dai-q6-v2.h
+++ b/include/sound/msm-dai-q6-v2.h
@@ -20,10 +20,11 @@
#define MSM_MI2S_SD3 (1 << 3)
#define MSM_MI2S_CAP_RX 0
#define MSM_MI2S_CAP_TX 1
+
#define MSM_PRIM_MI2S 0
#define MSM_SEC_MI2S 1
#define MSM_TERT_MI2S 2
-#define MSM_QUAD_MI2S 3
+#define MSM_QUAT_MI2S 3
struct msm_dai_auxpcm_pdata {
const char *clk;
diff --git a/include/sound/q6adm-v2.h b/include/sound/q6adm-v2.h
index cb2f3d7..9c43d09 100644
--- a/include/sound/q6adm-v2.h
+++ b/include/sound/q6adm-v2.h
@@ -16,13 +16,13 @@
#define ADM_PATH_PLAYBACK 0x1
#define ADM_PATH_LIVE_REC 0x2
#define ADM_PATH_NONLIVE_REC 0x3
+#include <sound/q6afe-v2.h>
#include <sound/q6audio-v2.h>
-#define Q6_AFE_MAX_PORTS 32
/* multiple copp per stream. */
struct route_payload {
- unsigned int copp_ids[Q6_AFE_MAX_PORTS];
+ unsigned int copp_ids[AFE_MAX_PORTS];
unsigned short num_copps;
unsigned int session_id;
};
diff --git a/include/sound/q6afe-v2.h b/include/sound/q6afe-v2.h
index 1324f8a..444b432 100644
--- a/include/sound/q6afe-v2.h
+++ b/include/sound/q6afe-v2.h
@@ -71,6 +71,8 @@
IDX_INT_FM_TX = 29,
IDX_RT_PROXY_PORT_001_RX = 30,
IDX_RT_PROXY_PORT_001_TX = 31,
+ IDX_AFE_PORT_ID_QUATERNARY_MI2S_RX = 32,
+ IDX_AFE_PORT_ID_QUATERNARY_MI2S_TX = 33,
AFE_MAX_PORTS
};
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 28eb7ea..493801a 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -1956,6 +1956,38 @@
return err;
}
+static int cancel_resolve_name(struct sock *sk, u16 index, unsigned char *data,
+ u16 len)
+{
+ struct mgmt_cp_cancel_resolve_name *mgmt_cp = (void *) data;
+ struct hci_cp_remote_name_req_cancel hci_cp;
+ struct hci_dev *hdev;
+ int err;
+
+ BT_DBG("");
+
+ if (len != sizeof(*mgmt_cp))
+ return cmd_status(sk, index, MGMT_OP_CANCEL_RESOLVE_NAME,
+ EINVAL);
+
+ hdev = hci_dev_get(index);
+ if (!hdev)
+ return cmd_status(sk, index, MGMT_OP_CANCEL_RESOLVE_NAME,
+ ENODEV);
+
+ hci_dev_lock_bh(hdev);
+
+ memset(&hci_cp, 0, sizeof(hci_cp));
+ bacpy(&hci_cp.bdaddr, &mgmt_cp->bdaddr);
+ err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(hci_cp),
+ &hci_cp);
+
+ hci_dev_unlock_bh(hdev);
+ hci_dev_put(hdev);
+
+ return err;
+}
+
static int set_connection_params(struct sock *sk, u16 index,
unsigned char *data, u16 len)
{
@@ -2189,10 +2221,11 @@
struct mgmt_mode cp = {0};
int err = -1;
- BT_DBG("");
-
hdev = hci_dev_get(index);
+ if (hdev)
+ BT_DBG("disco_state: %d", hdev->disco_state);
+
if (!hdev || !lmp_le_capable(hdev)) {
mgmt_pending_foreach(MGMT_OP_STOP_DISCOVERY, index,
@@ -2200,6 +2233,8 @@
mgmt_event(MGMT_EV_DISCOVERING, index, &cp, sizeof(cp), NULL);
+ hdev->disco_state = SCAN_IDLE;
+
if (hdev)
goto done;
else
@@ -2315,6 +2350,7 @@
if (!hdev)
return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENODEV);
+ BT_DBG("disco_state: %d", hdev->disco_state);
hci_dev_lock_bh(hdev);
if (hdev->disco_state && timer_pending(&hdev->disco_timer)) {
@@ -2395,6 +2431,8 @@
if (!hdev)
return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, ENODEV);
+ BT_DBG("disco_state: %d", hdev->disco_state);
+
hci_dev_lock_bh(hdev);
state = hdev->disco_state;
@@ -2659,6 +2697,9 @@
case MGMT_OP_RESOLVE_NAME:
err = resolve_name(sk, index, buf + sizeof(*hdr), len);
break;
+ case MGMT_OP_CANCEL_RESOLVE_NAME:
+ err = cancel_resolve_name(sk, index, buf + sizeof(*hdr), len);
+ break;
case MGMT_OP_SET_CONNECTION_PARAMS:
err = set_connection_params(sk, index, buf + sizeof(*hdr), len);
break;
diff --git a/net/rfkill/core.c b/net/rfkill/core.c
index 04afd89..b7a3656 100644
--- a/net/rfkill/core.c
+++ b/net/rfkill/core.c
@@ -256,6 +256,7 @@
static void rfkill_set_block(struct rfkill *rfkill, bool blocked)
{
unsigned long flags;
+ bool prev, curr;
int err;
if (unlikely(rfkill->dev.power.power_state.event & PM_EVENT_SLEEP))
@@ -270,6 +271,8 @@
rfkill->ops->query(rfkill, rfkill->data);
spin_lock_irqsave(&rfkill->lock, flags);
+ prev = rfkill->state & RFKILL_BLOCK_SW;
+
if (rfkill->state & RFKILL_BLOCK_SW)
rfkill->state |= RFKILL_BLOCK_SW_PREV;
else
@@ -299,10 +302,15 @@
}
rfkill->state &= ~RFKILL_BLOCK_SW_SETCALL;
rfkill->state &= ~RFKILL_BLOCK_SW_PREV;
+ curr = rfkill->state & RFKILL_BLOCK_SW;
+
spin_unlock_irqrestore(&rfkill->lock, flags);
rfkill_led_trigger_event(rfkill);
- rfkill_event(rfkill);
+
+ if (prev != curr)
+ rfkill_event(rfkill);
+
}
#ifdef CONFIG_RFKILL_INPUT
diff --git a/sound/soc/msm/mdm9615.c b/sound/soc/msm/mdm9615.c
index 76cd625..7190ae9 100644
--- a/sound/soc/msm/mdm9615.c
+++ b/sound/soc/msm/mdm9615.c
@@ -1024,6 +1024,9 @@
}
codec_clk = clk_get(cpu_dai->dev, "osr_clk");
err = tabla_hs_detect(codec, &mbhc_cfg);
+ msm_gpiomux_install(
+ msm9615_audio_prim_i2s_codec_configs,
+ ARRAY_SIZE(msm9615_audio_prim_i2s_codec_configs));
return err;
}
@@ -1617,6 +1620,7 @@
codec_clk = clk_get(cpu_dai->dev, "osr_clk");
if (hs_detect_use_gpio) {
+ pr_debug("%s: GPIO Headset detection enabled\n", __func__);
mbhc_cfg.gpio = PM8018_GPIO_PM_TO_SYS(JACK_DETECT_GPIO);
mbhc_cfg.gpio_irq = JACK_DETECT_INT;
}
@@ -2428,6 +2432,8 @@
sif_virt_addr = ioremap(LPASS_SIF_MUX_ADDR, 4);
secpcm_portslc_virt_addr = ioremap(SEC_PCM_PORT_SLC_ADDR, 4);
+ hs_detect_use_gpio = true;
+
return ret;
}
module_init(mdm9615_audio_init);
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index 58205e9..37a4234 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -18,6 +18,7 @@
#include <linux/slab.h>
#include <linux/mfd/pm8xxx/pm8921.h>
#include <linux/qpnp/clkdiv.h>
+#include <linux/regulator/consumer.h>
#include <sound/core.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
@@ -30,9 +31,6 @@
#define DRV_NAME "msm8974-asoc-taiko"
-#define PM8921_GPIO_BASE NR_GPIO_IRQS
-#define PM8921_GPIO_PM_TO_SYS(pm_gpio) (pm_gpio - 1 + PM8921_GPIO_BASE)
-
#define MSM8974_SPK_ON 1
#define MSM8974_SPK_OFF 0
@@ -42,10 +40,10 @@
#define BTSCO_RATE_8KHZ 8000
#define BTSCO_RATE_16KHZ 16000
-#define BOTTOM_SPK_AMP_POS 0x1
-#define BOTTOM_SPK_AMP_NEG 0x2
-#define TOP_SPK_AMP_POS 0x4
-#define TOP_SPK_AMP_NEG 0x8
+#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
@@ -56,6 +54,9 @@
#define WCD9XXX_MBHC_DEF_RLOADS 5
#define TAIKO_EXT_CLK_RATE 9600000
+/* It takes about 13ms for Class-D PAs to ramp-up */
+#define EXT_CLASS_D_EN_DELAY 13000
+
void *def_taiko_mbhc_cal(void);
static int msm_snd_enable_codec_ext_clk(struct snd_soc_codec *codec, int enable,
bool dapm);
@@ -89,11 +90,11 @@
SLIM_4_TX_1 = 150, /* In-call musid delivery TX */
};
-static u32 top_spk_pamp_gpio = PM8921_GPIO_PM_TO_SYS(18);
-static u32 bottom_spk_pamp_gpio = PM8921_GPIO_PM_TO_SYS(19);
-static int msm_spk_control;
-static int msm_ext_bottom_spk_pamp;
-static int msm_ext_top_spk_pamp;
+static struct platform_device *spdev;
+static struct regulator *ext_spk_amp_regulator;
+static int ext_spk_amp_gpio = -1;
+static int msm8974_spk_control = 1;
+static int msm8974_ext_spk_pamp;
static int msm_slim_0_rx_ch = 1;
static int msm_slim_0_tx_ch = 1;
@@ -105,103 +106,70 @@
static int clk_users;
static atomic_t auxpcm_rsc_ref;
-static void msm_enable_ext_spk_amp_gpio(u32 spk_amp_gpio)
+static int msm8974_liquid_ext_spk_power_amp_init(void)
{
int ret = 0;
- struct pm_gpio param = {
- .direction = PM_GPIO_DIR_OUT,
- .output_buffer = PM_GPIO_OUT_BUF_CMOS,
- .output_value = 1,
- .pull = PM_GPIO_PULL_NO,
- .vin_sel = PM_GPIO_VIN_S4,
- .out_strength = PM_GPIO_STRENGTH_MED,
- .
- function = PM_GPIO_FUNC_NORMAL,
- };
-
- if (spk_amp_gpio == bottom_spk_pamp_gpio) {
-
- ret = gpio_request(bottom_spk_pamp_gpio, "BOTTOM_SPK_AMP");
+ ext_spk_amp_gpio = of_get_named_gpio(spdev->dev.of_node,
+ "qcom,ext-spk-amp-gpio", 0);
+ if (ext_spk_amp_gpio >= 0) {
+ ret = gpio_request(ext_spk_amp_gpio, "ext_spk_amp_gpio");
if (ret) {
- pr_err("%s: Error requesting BOTTOM SPK AMP GPIO %u\n",
- __func__, bottom_spk_pamp_gpio);
- return;
+ pr_err("%s: gpio_request failed for ext_spk_amp_gpio.\n",
+ __func__);
+ return -EINVAL;
}
- ret = pm8xxx_gpio_config(bottom_spk_pamp_gpio, ¶m);
- if (ret)
- pr_err("%s: Failed to configure Bottom Spk Ampl gpio %u\n",
- __func__, bottom_spk_pamp_gpio);
- else {
- pr_debug("%s: enable Bottom spkr amp gpio\n", __func__);
- gpio_direction_output(bottom_spk_pamp_gpio, 1);
- }
+ gpio_direction_output(ext_spk_amp_gpio, 0);
- } else if (spk_amp_gpio == top_spk_pamp_gpio) {
+ if (ext_spk_amp_regulator == NULL) {
+ ext_spk_amp_regulator = regulator_get(&spdev->dev,
+ "qcom,ext-spk-amp");
- ret = gpio_request(top_spk_pamp_gpio, "TOP_SPK_AMP");
- if (ret) {
- pr_err("%s: Error requesting GPIO %d\n", __func__,
- top_spk_pamp_gpio);
- return;
+ if (IS_ERR(ext_spk_amp_regulator)) {
+ pr_err("%s: Cannot get regulator %s.\n",
+ __func__, "qcom,ext-spk-amp");
+
+ gpio_free(ext_spk_amp_gpio);
+ return PTR_ERR(ext_spk_amp_regulator);
+ }
}
- ret = pm8xxx_gpio_config(top_spk_pamp_gpio, ¶m);
- if (ret)
- pr_err("%s: Failed to configure Top Spk Ampl gpio %u\n",
- __func__, top_spk_pamp_gpio);
- else {
- pr_debug("%s: enable Top spkr amp gpio\n", __func__);
- gpio_direction_output(top_spk_pamp_gpio, 1);
- }
- } else {
- pr_err("%s: ERROR : Invalid External Speaker Ampl GPIO. gpio = %u\n",
- __func__, spk_amp_gpio);
- return;
}
+
+ return 0;
}
-static void msm_ext_spk_power_amp_on(u32 spk)
+static void msm8974_liquid_ext_spk_power_amp_enable(u32 on)
{
- if (spk & (BOTTOM_SPK_AMP_POS | BOTTOM_SPK_AMP_NEG)) {
+ if (on)
+ regulator_enable(ext_spk_amp_regulator);
+ else
+ regulator_disable(ext_spk_amp_regulator);
- if ((msm_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_POS) &&
- (msm_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_NEG)) {
+ gpio_direction_output(ext_spk_amp_gpio, on);
+ usleep_range(EXT_CLASS_D_EN_DELAY, EXT_CLASS_D_EN_DELAY);
+ pr_debug("%s: %s external speaker PAs.\n", __func__,
+ on ? "Enable" : "Disable");
+}
- pr_debug("%s() External Bottom Speaker Ampl already turned on. spk = 0x%08x\n",
+static void msm8974_ext_spk_power_amp_on(u32 spk)
+{
+ if (spk & (LO_1_SPK_AMP |
+ LO_3_SPK_AMP |
+ LO_2_SPK_AMP |
+ LO_4_SPK_AMP)) {
+
+ pr_debug("%s() External Left/Right Speakers already turned on. spk = 0x%08x\n",
__func__, spk);
- return;
- }
- msm_ext_bottom_spk_pamp |= spk;
+ msm8974_ext_spk_pamp |= spk;
- if ((msm_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_POS) &&
- (msm_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_NEG)) {
+ if ((msm8974_ext_spk_pamp & LO_1_SPK_AMP) &&
+ (msm8974_ext_spk_pamp & LO_3_SPK_AMP) &&
+ (msm8974_ext_spk_pamp & LO_2_SPK_AMP) &&
+ (msm8974_ext_spk_pamp & LO_4_SPK_AMP)) {
- msm_enable_ext_spk_amp_gpio(bottom_spk_pamp_gpio);
- pr_debug("%s: slepping 4 ms after turning on external Bottom Speaker Ampl\n",
- __func__);
- usleep_range(4000, 4000);
- }
-
- } else if (spk & (TOP_SPK_AMP_POS | TOP_SPK_AMP_NEG)) {
-
- if ((msm_ext_top_spk_pamp & TOP_SPK_AMP_POS) &&
- (msm_ext_top_spk_pamp & TOP_SPK_AMP_NEG)) {
-
- pr_debug("%s() External Top Speaker Ampl already turned on. spk = 0x%08x\n",
- __func__, spk);
- return;
- }
-
- msm_ext_top_spk_pamp |= spk;
-
- if ((msm_ext_top_spk_pamp & TOP_SPK_AMP_POS) &&
- (msm_ext_top_spk_pamp & TOP_SPK_AMP_NEG)) {
-
- msm_enable_ext_spk_amp_gpio(top_spk_pamp_gpio);
- pr_debug("%s: sleeping 4 ms after turning on external Top Speaker Ampl\n",
- __func__);
- usleep_range(4000, 4000);
+ if (ext_spk_amp_gpio >= 0)
+ msm8974_liquid_ext_spk_power_amp_enable(1);
}
} else {
@@ -211,35 +179,22 @@
}
}
-static void msm_ext_spk_power_amp_off(u32 spk)
+static void msm8974_ext_spk_power_amp_off(u32 spk)
{
- if (spk & (BOTTOM_SPK_AMP_POS | BOTTOM_SPK_AMP_NEG)) {
+ if (spk & (LO_1_SPK_AMP |
+ LO_3_SPK_AMP |
+ LO_2_SPK_AMP |
+ LO_4_SPK_AMP)) {
- if (!msm_ext_bottom_spk_pamp)
- return;
+ pr_debug("%s Left and right speakers case spk = 0x%08x",
+ __func__, spk);
- gpio_direction_output(bottom_spk_pamp_gpio, 0);
- gpio_free(bottom_spk_pamp_gpio);
- msm_ext_bottom_spk_pamp = 0;
+ if (!msm8974_ext_spk_pamp) {
+ if (ext_spk_amp_gpio >= 0)
+ msm8974_liquid_ext_spk_power_amp_enable(0);
+ msm8974_ext_spk_pamp = 0;
+ }
- pr_debug("%s: sleeping 4 ms after turning off external Bottom Speaker Ampl\n",
- __func__);
-
- usleep_range(4000, 4000);
-
- } else if (spk & (TOP_SPK_AMP_POS | TOP_SPK_AMP_NEG)) {
-
- if (!msm_ext_top_spk_pamp)
- return;
-
- gpio_direction_output(top_spk_pamp_gpio, 0);
- gpio_free(top_spk_pamp_gpio);
- msm_ext_top_spk_pamp = 0;
-
- pr_debug("%s: sleeping 4 ms after turning off external Top Spkaker Ampl\n",
- __func__);
-
- usleep_range(4000, 4000);
} else {
pr_err("%s: ERROR : Invalid Ext Spk Ampl. spk = 0x%08x\n",
@@ -248,87 +203,89 @@
}
}
-static void msm_ext_control(struct snd_soc_codec *codec)
+static void msm8974_ext_control(struct snd_soc_codec *codec)
{
struct snd_soc_dapm_context *dapm = &codec->dapm;
mutex_lock(&dapm->codec->mutex);
- pr_debug("%s: msm_spk_control = %d", __func__, msm_spk_control);
- if (msm_spk_control == MSM8974_SPK_ON) {
- snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Pos");
- snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Neg");
- snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Pos");
- snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Neg");
+ pr_debug("%s: msm8974_spk_control = %d", __func__, msm8974_spk_control);
+ if (msm8974_spk_control == MSM8974_SPK_ON) {
+ snd_soc_dapm_enable_pin(dapm, "Lineout_1 amp");
+ snd_soc_dapm_enable_pin(dapm, "Lineout_3 amp");
+ snd_soc_dapm_enable_pin(dapm, "Lineout_2 amp");
+ snd_soc_dapm_enable_pin(dapm, "Lineout_4 amp");
} else {
- snd_soc_dapm_disable_pin(dapm, "Ext Spk Bottom Pos");
- snd_soc_dapm_disable_pin(dapm, "Ext Spk Bottom Neg");
- snd_soc_dapm_disable_pin(dapm, "Ext Spk Top Pos");
- snd_soc_dapm_disable_pin(dapm, "Ext Spk Top Neg");
+ snd_soc_dapm_disable_pin(dapm, "Lineout_1 amp");
+ snd_soc_dapm_disable_pin(dapm, "Lineout_3 amp");
+ snd_soc_dapm_disable_pin(dapm, "Lineout_2 amp");
+ snd_soc_dapm_disable_pin(dapm, "Lineout_4 amp");
}
snd_soc_dapm_sync(dapm);
mutex_unlock(&dapm->codec->mutex);
}
-static int msm_get_spk(struct snd_kcontrol *kcontrol,
+static int msm8974_get_spk(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- pr_debug("%s: msm_spk_control = %d", __func__, msm_spk_control);
- ucontrol->value.integer.value[0] = msm_spk_control;
+ pr_debug("%s: msm8974_spk_control = %d", __func__, msm8974_spk_control);
+ ucontrol->value.integer.value[0] = msm8974_spk_control;
return 0;
}
-static int msm_set_spk(struct snd_kcontrol *kcontrol,
+static int msm8974_set_spk(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
pr_debug("%s()\n", __func__);
- if (msm_spk_control == ucontrol->value.integer.value[0])
+ if (msm8974_spk_control == ucontrol->value.integer.value[0])
return 0;
- msm_spk_control = ucontrol->value.integer.value[0];
- msm_ext_control(codec);
+ msm8974_spk_control = ucontrol->value.integer.value[0];
+ msm8974_ext_control(codec);
return 1;
}
-static int msm_spkramp_event(struct snd_soc_dapm_widget *w,
+
+static int msm_ext_spkramp_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *k, int event)
{
- pr_debug("%s() %x\n", __func__, SND_SOC_DAPM_EVENT_ON(event));
+ pr_debug("%s()\n", __func__);
if (SND_SOC_DAPM_EVENT_ON(event)) {
- if (!strncmp(w->name, "Ext Spk Bottom Pos", 18))
- msm_ext_spk_power_amp_on(BOTTOM_SPK_AMP_POS);
- else if (!strncmp(w->name, "Ext Spk Bottom Neg", 18))
- msm_ext_spk_power_amp_on(BOTTOM_SPK_AMP_NEG);
- else if (!strncmp(w->name, "Ext Spk Top Pos", 15))
- msm_ext_spk_power_amp_on(TOP_SPK_AMP_POS);
- else if (!strncmp(w->name, "Ext Spk Top Neg", 15))
- msm_ext_spk_power_amp_on(TOP_SPK_AMP_NEG);
+ if (!strncmp(w->name, "Lineout_1 amp", 14))
+ msm8974_ext_spk_power_amp_on(LO_1_SPK_AMP);
+ else if (!strncmp(w->name, "Lineout_3 amp", 14))
+ msm8974_ext_spk_power_amp_on(LO_3_SPK_AMP);
+ else if (!strncmp(w->name, "Lineout_2 amp", 14))
+ msm8974_ext_spk_power_amp_on(LO_2_SPK_AMP);
+ else if (!strncmp(w->name, "Lineout_4 amp", 14))
+ msm8974_ext_spk_power_amp_on(LO_4_SPK_AMP);
else {
pr_err("%s() Invalid Speaker Widget = %s\n",
__func__, w->name);
return -EINVAL;
}
-
} else {
- if (!strncmp(w->name, "Ext Spk Bottom Pos", 18))
- msm_ext_spk_power_amp_off(BOTTOM_SPK_AMP_POS);
- else if (!strncmp(w->name, "Ext Spk Bottom Neg", 18))
- msm_ext_spk_power_amp_off(BOTTOM_SPK_AMP_NEG);
- else if (!strncmp(w->name, "Ext Spk Top Pos", 15))
- msm_ext_spk_power_amp_off(TOP_SPK_AMP_POS);
- else if (!strncmp(w->name, "Ext Spk Top Neg", 15))
- msm_ext_spk_power_amp_off(TOP_SPK_AMP_NEG);
+ if (!strncmp(w->name, "Lineout_1 amp", 14))
+ msm8974_ext_spk_power_amp_off(LO_1_SPK_AMP);
+ else if (!strncmp(w->name, "Lineout_3 amp", 14))
+ msm8974_ext_spk_power_amp_off(LO_3_SPK_AMP);
+ else if (!strncmp(w->name, "Lineout_2 amp", 14))
+ msm8974_ext_spk_power_amp_off(LO_2_SPK_AMP);
+ else if (!strncmp(w->name, "Lineout_4 amp", 14))
+ msm8974_ext_spk_power_amp_off(LO_4_SPK_AMP);
else {
pr_err("%s() Invalid Speaker Widget = %s\n",
__func__, w->name);
return -EINVAL;
}
}
+
return 0;
+
}
static int msm_snd_enable_codec_ext_clk(struct snd_soc_codec *codec, int enable,
@@ -397,11 +354,11 @@
SND_SOC_DAPM_SUPPLY("MCLK", SND_SOC_NOPM, 0, 0,
msm8974_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_SPK("Ext Spk Bottom Pos", msm_spkramp_event),
- SND_SOC_DAPM_SPK("Ext Spk Bottom Neg", msm_spkramp_event),
+ SND_SOC_DAPM_SPK("Lineout_1 amp", msm_ext_spkramp_event),
+ SND_SOC_DAPM_SPK("Lineout_3 amp", msm_ext_spkramp_event),
- SND_SOC_DAPM_SPK("Ext Spk Top Pos", msm_spkramp_event),
- SND_SOC_DAPM_SPK("Ext Spk Top Neg", msm_spkramp_event),
+ SND_SOC_DAPM_SPK("Lineout_2 amp", msm_ext_spkramp_event),
+ SND_SOC_DAPM_SPK("Lineout_4 amp", msm_ext_spkramp_event),
SND_SOC_DAPM_MIC("Handset Mic", NULL),
SND_SOC_DAPM_MIC("Headset Mic", NULL),
@@ -693,8 +650,8 @@
};
static const struct snd_kcontrol_new msm_snd_controls[] = {
- SOC_ENUM_EXT("Speaker Function", msm_snd_enum[0], msm_get_spk,
- msm_set_spk),
+ SOC_ENUM_EXT("Speaker Function", msm_snd_enum[0], msm8974_get_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),
SOC_ENUM_EXT("SLIM_0_TX Channels", msm_snd_enum[2],
@@ -723,11 +680,6 @@
pr_info("%s(), dev_name%s\n", __func__, dev_name(cpu_dai->dev));
- if (machine_is_msm8960_liquid()) {
- top_spk_pamp_gpio = (PM8921_GPIO_PM_TO_SYS(19));
- bottom_spk_pamp_gpio = (PM8921_GPIO_PM_TO_SYS(18));
- }
-
rtd->pmdown_time = 0;
err = snd_soc_add_codec_controls(codec, msm_snd_controls,
@@ -735,13 +687,21 @@
if (err < 0)
return err;
+ err = msm8974_liquid_ext_spk_power_amp_init();
+ if (err) {
+ pr_err("%s: LiQUID 8974 CLASS_D PAs init failed (%d)\n",
+ __func__, err);
+ return err;
+ }
+
snd_soc_dapm_new_controls(dapm, msm8974_dapm_widgets,
ARRAY_SIZE(msm8974_dapm_widgets));
- snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Pos");
- snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Neg");
- snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Pos");
- snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Neg");
+ snd_soc_dapm_enable_pin(dapm, "Lineout_1 amp");
+ snd_soc_dapm_enable_pin(dapm, "Lineout_3 amp");
+ snd_soc_dapm_enable_pin(dapm, "Lineout_2 amp");
+ snd_soc_dapm_enable_pin(dapm, "Lineout_4 amp");
+
snd_soc_dapm_sync(dapm);
@@ -1458,9 +1418,13 @@
ret);
goto err;
}
+
mutex_init(&cdc_mclk_mutex);
atomic_set(&auxpcm_rsc_ref, 0);
+ spdev = pdev;
+ ext_spk_amp_regulator = NULL;
+
return 0;
err:
devm_kfree(&pdev->dev, pdata);
@@ -1472,7 +1436,13 @@
struct snd_soc_card *card = platform_get_drvdata(pdev);
struct msm8974_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+ if (ext_spk_amp_regulator)
+ regulator_put(ext_spk_amp_regulator);
+
gpio_free(pdata->mclk_gpio);
+ if (ext_spk_amp_gpio >= 0)
+ gpio_free(ext_spk_amp_gpio);
+
snd_soc_unregister_card(card);
return 0;
diff --git a/sound/soc/msm/qdsp6/q6adm.c b/sound/soc/msm/qdsp6/q6adm.c
index 00394aa..119e017 100644
--- a/sound/soc/msm/qdsp6/q6adm.c
+++ b/sound/soc/msm/qdsp6/q6adm.c
@@ -853,24 +853,15 @@
} else if (channel_mode == 4) {
open.dev_channel_mapping[0] = PCM_CHANNEL_FL;
open.dev_channel_mapping[1] = PCM_CHANNEL_FR;
- open.dev_channel_mapping[2] = PCM_CHANNEL_RB;
- open.dev_channel_mapping[3] = PCM_CHANNEL_LB;
+ open.dev_channel_mapping[2] = PCM_CHANNEL_LS;
+ open.dev_channel_mapping[3] = PCM_CHANNEL_RS;
} else if (channel_mode == 6) {
- open.dev_channel_mapping[0] = PCM_CHANNEL_FL;
- open.dev_channel_mapping[1] = PCM_CHANNEL_FR;
- open.dev_channel_mapping[2] = PCM_CHANNEL_LFE;
- open.dev_channel_mapping[3] = PCM_CHANNEL_FC;
- open.dev_channel_mapping[4] = PCM_CHANNEL_LB;
- open.dev_channel_mapping[5] = PCM_CHANNEL_RB;
- } else if (channel_mode == 8) {
- open.dev_channel_mapping[0] = PCM_CHANNEL_FL;
- open.dev_channel_mapping[1] = PCM_CHANNEL_FR;
- open.dev_channel_mapping[2] = PCM_CHANNEL_LFE;
- open.dev_channel_mapping[3] = PCM_CHANNEL_FC;
- open.dev_channel_mapping[4] = PCM_CHANNEL_LB;
- open.dev_channel_mapping[5] = PCM_CHANNEL_RB;
- open.dev_channel_mapping[6] = PCM_CHANNEL_FLC;
- open.dev_channel_mapping[7] = PCM_CHANNEL_FRC;
+ open.dev_channel_mapping[0] = PCM_CHANNEL_FC;
+ open.dev_channel_mapping[1] = PCM_CHANNEL_FL;
+ open.dev_channel_mapping[2] = PCM_CHANNEL_FR;
+ open.dev_channel_mapping[3] = PCM_CHANNEL_LS;
+ open.dev_channel_mapping[4] = PCM_CHANNEL_RS;
+ open.dev_channel_mapping[5] = PCM_CHANNEL_LFE;
} else {
pr_err("%s invalid num_chan %d\n", __func__,
channel_mode);
diff --git a/sound/soc/msm/qdsp6/q6asm.c b/sound/soc/msm/qdsp6/q6asm.c
index cde5b02..52e481a 100644
--- a/sound/soc/msm/qdsp6/q6asm.c
+++ b/sound/soc/msm/qdsp6/q6asm.c
@@ -1152,7 +1152,9 @@
enc_cfg.enc_blk.cfg_size = sizeof(struct asm_dts_enc_cfg);
enc_cfg.enc_blk.cfg.dts.sample_rate = sample_rate;
enc_cfg.enc_blk.cfg.dts.num_channels = channels;
- if (channels == 2) {
+ if (channels == 1) {
+ enc_cfg.enc_blk.cfg.dts.channel_mapping[0] = PCM_CHANNEL_FC;
+ } else if (channels == 2) {
enc_cfg.enc_blk.cfg.dts.channel_mapping[0] = PCM_CHANNEL_FL;
enc_cfg.enc_blk.cfg.dts.channel_mapping[1] = PCM_CHANNEL_FR;
enc_cfg.enc_blk.cfg.dts.channel_mapping[2] = 0;
@@ -1167,12 +1169,12 @@
enc_cfg.enc_blk.cfg.dts.channel_mapping[4] = 0;
enc_cfg.enc_blk.cfg.dts.channel_mapping[5] = 0;
} else if (channels == 6) {
- enc_cfg.enc_blk.cfg.dts.channel_mapping[0] = PCM_CHANNEL_FL;
- enc_cfg.enc_blk.cfg.dts.channel_mapping[1] = PCM_CHANNEL_FR;
- enc_cfg.enc_blk.cfg.dts.channel_mapping[2] = PCM_CHANNEL_LFE;
+ enc_cfg.enc_blk.cfg.dts.channel_mapping[0] = PCM_CHANNEL_FC;
+ enc_cfg.enc_blk.cfg.dts.channel_mapping[1] = PCM_CHANNEL_FL;
+ enc_cfg.enc_blk.cfg.dts.channel_mapping[2] = PCM_CHANNEL_FR;
enc_cfg.enc_blk.cfg.dts.channel_mapping[3] = PCM_CHANNEL_LS;
enc_cfg.enc_blk.cfg.dts.channel_mapping[4] = PCM_CHANNEL_RS;
- enc_cfg.enc_blk.cfg.dts.channel_mapping[5] = PCM_CHANNEL_FC;
+ enc_cfg.enc_blk.cfg.dts.channel_mapping[5] = PCM_CHANNEL_LFE;
}
rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
if (rc < 0) {
@@ -1765,6 +1767,9 @@
case FORMAT_AMRWB:
open.write_format = AMRWB_FS;
break;
+ case FORMAT_AMR_WB_PLUS:
+ open.write_format = AMR_WB_PLUS;
+ break;
case FORMAT_V13K:
open.write_format = V13K_FS;
break;
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
index 621d24b..a307bcc 100644
--- a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
@@ -1310,6 +1310,16 @@
switch (mi2s_id) {
case MSM_PRIM_MI2S:
*port_id = MI2S_RX;
+ break;
+ case MSM_SEC_MI2S:
+ *port_id = AFE_PORT_ID_SECONDARY_MI2S_RX;
+ break;
+ case MSM_TERT_MI2S:
+ *port_id = AFE_PORT_ID_TERTIARY_MI2S_RX;
+ break;
+ case MSM_QUAT_MI2S:
+ *port_id = AFE_PORT_ID_QUATERNARY_MI2S_RX;
+ break;
break;
default:
ret = -1;
@@ -1320,7 +1330,16 @@
switch (mi2s_id) {
case MSM_PRIM_MI2S:
*port_id = MI2S_TX;
- break;
+ break;
+ case MSM_SEC_MI2S:
+ *port_id = AFE_PORT_ID_SECONDARY_MI2S_TX;
+ break;
+ case MSM_TERT_MI2S:
+ *port_id = AFE_PORT_ID_TERTIARY_MI2S_TX;
+ break;
+ case MSM_QUAT_MI2S:
+ *port_id = AFE_PORT_ID_QUATERNARY_MI2S_TX;
+ break;
default:
ret = -1;
break;
@@ -1330,7 +1349,7 @@
ret = -1;
break;
}
- pr_debug("%s: port_id = %x\n", __func__, *port_id);
+ pr_debug("%s: port_id = %#x\n", __func__, *port_id);
return ret;
}
@@ -1346,15 +1365,17 @@
u16 port_id = 0;
int rc = 0;
- dev_dbg(dai->dev, "%s: device name %s dai id %x,port id = %x\n",
- __func__, dai->name, dai->id, port_id);
-
if (msm_mi2s_get_port_id(dai->id, substream->stream,
&port_id) != 0) {
- dev_err(dai->dev, "%s: Invalid Port ID\n", __func__);
+ dev_err(dai->dev, "%s: Invalid Port ID %#x\n",
+ __func__, port_id);
return -EINVAL;
}
+ dev_dbg(dai->dev, "%s: dai id %d, afe port id = %x\n"
+ "dai_data->channels = %u sample_rate = %u\n", __func__,
+ dai->id, port_id, dai_data->channels, dai_data->rate);
+
if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
/* PORT START should be set if prepare called
* in active state.
@@ -1382,6 +1403,8 @@
(substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
&mi2s_dai_data->rx_dai : &mi2s_dai_data->tx_dai);
struct msm_dai_q6_dai_data *dai_data = &mi2s_dai_config->mi2s_dai_data;
+ struct afe_param_id_i2s_cfg *i2s = &dai_data->port_config.i2s;
+
dai_data->channels = params_channels(params);
switch (dai_data->channels) {
@@ -1451,13 +1474,19 @@
mi2s_dai_data->bitwidth_constraint.list = &dai_data->bitwidth;
}
- pr_debug("%s: dai_data->channels = %d, line = %d\n"
- ",mono_stereo =%x sample rate = %x\n", __func__,
- dai_data->channels, dai_data->port_config.i2s.channel_mode,
- dai_data->port_config.i2s.mono_stereo, dai_data->rate);
+ dev_dbg(dai->dev, "%s: dai id %d dai_data->channels = %d\n"
+ "sample_rate = %u i2s_cfg_minor_version = %#x\n"
+ "bit_width = %hu channel_mode = %#x mono_stereo = %#x\n"
+ "ws_src = %#x sample_rate = %u data_format = %#x\n"
+ "reserved = %u\n", __func__, dai->id, dai_data->channels,
+ dai_data->rate, i2s->i2s_cfg_minor_version, i2s->bit_width,
+ i2s->channel_mode, i2s->mono_stereo, i2s->ws_src,
+ i2s->sample_rate, i2s->data_format, i2s->reserved);
+
return 0;
+
error_invalid_data:
- pr_debug("%s: dai_data->channels = %d, line = %d\n", __func__,
+ pr_debug("%s: dai_data->channels = %d channel_mode = %d\n", __func__,
dai_data->channels, dai_data->port_config.i2s.channel_mode);
return -EINVAL;
}
@@ -1507,11 +1536,12 @@
if (msm_mi2s_get_port_id(dai->id, substream->stream,
&port_id) != 0) {
- dev_err(dai->dev, "%s: Invalid Port ID\n", __func__);
+ dev_err(dai->dev, "%s: Invalid Port ID %#x\n",
+ __func__, port_id);
}
- dev_dbg(dai->dev, "%s: device name %s port id = %x\n",
- __func__, dai->name, port_id);
+ dev_dbg(dai->dev, "%s: closing afe port id = %x\n",
+ __func__, port_id);
if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
rc = afe_close(port_id);
@@ -1714,20 +1744,21 @@
if (rc) {
dev_err(&pdev->dev,
"%s: missing %x in dt node\n", __func__, mi2s_intf);
- return rc;
+ return rc;
}
- if (mi2s_intf > MSM_QUAD_MI2S) {
- dev_err(&pdev->dev, "%s: Invalid MI2S ID from Device Tree\n",
- __func__);
- return -EINVAL;
+ dev_dbg(&pdev->dev, "dev name %s dev id %x\n", dev_name(&pdev->dev),
+ mi2s_intf);
+
+ if (mi2s_intf < MSM_PRIM_MI2S || mi2s_intf > MSM_QUAT_MI2S) {
+ dev_err(&pdev->dev,
+ "%s: Invalid MI2S ID %u from Device Tree\n",
+ __func__, mi2s_intf);
+ return -ENXIO;
}
- if (mi2s_intf == MSM_PRIM_MI2S) {
- dev_set_name(&pdev->dev, "%s.%d", "msm-dai-q6-mi2s",
- MSM_PRIM_MI2S);
- pdev->id = MSM_PRIM_MI2S;
- }
+ dev_set_name(&pdev->dev, "%s.%d", "msm-dai-q6-mi2s", mi2s_intf);
+ pdev->id = mi2s_intf;
mi2s_pdata = kzalloc(sizeof(struct msm_mi2s_pdata), GFP_KERNEL);
if (!mi2s_pdata) {
@@ -1736,9 +1767,6 @@
goto rtn;
}
- dev_dbg(&pdev->dev, "dev name %s dev id %x\n", dev_name(&pdev->dev),
- pdev->id);
-
rc = of_property_read_u32(pdev->dev.of_node, "qcom,msm-mi2s-rx-lines",
&rx_line);
if (rc) {
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index 2e0c229..17c18dd 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -142,6 +142,8 @@
{ SLIMBUS_EXTPROC_RX, 0, 0, 0, 0, 0},
{ SLIMBUS_EXTPROC_RX, 0, 0, 0, 0, 0},
{ SLIMBUS_EXTPROC_RX, 0, 0, 0, 0, 0},
+ { AFE_PORT_ID_QUATERNARY_MI2S_RX, 0, 0, 0, 0, 0},
+ { AFE_PORT_ID_QUATERNARY_MI2S_TX, 0, 0, 0, 0, 0},
};
@@ -943,6 +945,21 @@
msm_routing_put_audio_mixer),
};
+static const struct snd_kcontrol_new quaternary_mi2s_rx_mixer_controls[] = {
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX ,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
static const struct snd_kcontrol_new hdmi_mixer_controls[] = {
SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_HDMI_RX,
MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
@@ -1043,6 +1060,9 @@
SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_MI2S_TX,
MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
@@ -1623,8 +1643,13 @@
SND_SOC_DAPM_AIF_OUT("SLIMBUS_0_RX", "Slimbus Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("HDMI", "HDMI Playback", 0, 0, 0 , 0),
SND_SOC_DAPM_AIF_OUT("MI2S_RX", "MI2S Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("QUAT_MI2S_RX", "Quaternary MI2S Playback",
+ 0, 0, 0, 0),
+
SND_SOC_DAPM_AIF_IN("PRI_I2S_TX", "Primary I2S Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("MI2S_TX", "MI2S Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("QUAT_MI2S_TX", "Quaternary MI2S Capture",
+ 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("SLIMBUS_0_TX", "Slimbus Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("INT_BT_SCO_RX", "Internal BT-SCO Playback",
0, 0, 0 , 0),
@@ -1684,6 +1709,9 @@
hdmi_mixer_controls, ARRAY_SIZE(hdmi_mixer_controls)),
SND_SOC_DAPM_MIXER("MI2S_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
mi2s_rx_mixer_controls, ARRAY_SIZE(mi2s_rx_mixer_controls)),
+ SND_SOC_DAPM_MIXER("QUAT_MI2S_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
+ quaternary_mi2s_rx_mixer_controls,
+ ARRAY_SIZE(quaternary_mi2s_rx_mixer_controls)),
SND_SOC_DAPM_MIXER("MultiMedia1 Mixer", SND_SOC_NOPM, 0, 0,
mmul1_mixer_controls, ARRAY_SIZE(mmul1_mixer_controls)),
SND_SOC_DAPM_MIXER("MultiMedia2 Mixer", SND_SOC_NOPM, 0, 0,
@@ -1827,9 +1855,16 @@
{"MI2S_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
{"MI2S_RX", NULL, "MI2S_RX Audio Mixer"},
+ {"QUAT_MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"QUAT_MI2S_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"QUAT_MI2S_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
+ {"QUAT_MI2S_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"QUAT_MI2S_RX", NULL, "QUAT_MI2S_RX Audio Mixer"},
+
{"MultiMedia1 Mixer", "PRI_TX", "PRI_I2S_TX"},
{"MultiMedia1 Mixer", "MI2S_TX", "MI2S_TX"},
{"MultiMedia2 Mixer", "MI2S_TX", "MI2S_TX"},
+ {"MultiMedia1 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
{"MultiMedia1 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
{"MultiMedia1 Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
{"MultiMedia2 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
@@ -2006,8 +2041,11 @@
{"BE_OUT", NULL, "SLIMBUS_4_RX"},
{"BE_OUT", NULL, "HDMI"},
{"BE_OUT", NULL, "MI2S_RX"},
+ {"BE_OUT", NULL, "QUAT_MI2S_RX"},
+
{"PRI_I2S_TX", NULL, "BE_IN"},
{"MI2S_TX", NULL, "BE_IN"},
+ {"QUAT_MI2S_TX", NULL, "BE_IN"},
{"SLIMBUS_0_TX", NULL, "BE_IN" },
{"SLIMBUS_1_TX", NULL, "BE_IN" },
{"SLIMBUS_3_TX", NULL, "BE_IN" },
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
index 261c359..be646ed 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
@@ -33,6 +33,8 @@
#define LPASS_BE_MI2S_RX "MI2S_RX"
#define LPASS_BE_MI2S_TX "MI2S_TX"
+#define LPASS_BE_QUAT_MI2S_RX "QUAT_MI2S_RX"
+#define LPASS_BE_QUAT_MI2S_TX "QUAT_MI2S_TX"
#define LPASS_BE_STUB_RX "STUB_RX"
#define LPASS_BE_STUB_TX "STUB_TX"
#define LPASS_BE_SLIMBUS_1_RX "SLIMBUS_1_RX"
@@ -95,6 +97,8 @@
MSM_BACKEND_DAI_EXTPROC_RX,
MSM_BACKEND_DAI_EXTPROC_TX,
MSM_BACKEND_DAI_EXTPROC_EC_TX,
+ MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+ MSM_BACKEND_DAI_QUATERNARY_MI2S_TX,
MSM_BACKEND_DAI_MAX,
};
diff --git a/sound/soc/msm/qdsp6v2/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c
index cc69123..7267a82 100644
--- a/sound/soc/msm/qdsp6v2/q6adm.c
+++ b/sound/soc/msm/qdsp6v2/q6adm.c
@@ -34,11 +34,11 @@
struct adm_ctl {
void *apr;
- atomic_t copp_id[Q6_AFE_MAX_PORTS];
- atomic_t copp_cnt[Q6_AFE_MAX_PORTS];
- atomic_t copp_stat[Q6_AFE_MAX_PORTS];
- u32 mem_map_handle[Q6_AFE_MAX_PORTS];
- wait_queue_head_t wait[Q6_AFE_MAX_PORTS];
+ atomic_t copp_id[AFE_MAX_PORTS];
+ atomic_t copp_cnt[AFE_MAX_PORTS];
+ atomic_t copp_stat[AFE_MAX_PORTS];
+ u32 mem_map_handle[AFE_MAX_PORTS];
+ wait_queue_head_t wait[AFE_MAX_PORTS];
};
static struct acdb_cal_block mem_addr_audproc[MAX_AUDPROC_TYPES];
@@ -81,7 +81,7 @@
this_adm.apr);
if (this_adm.apr) {
apr_reset(this_adm.apr);
- for (i = 0; i < Q6_AFE_MAX_PORTS; i++) {
+ for (i = 0; i < AFE_MAX_PORTS; i++) {
atomic_set(&this_adm.copp_id[i],
RESET_COPP_ID);
atomic_set(&this_adm.copp_cnt[i], 0);
@@ -107,7 +107,7 @@
adm_callback_debug_print(data);
if (data->payload_size) {
index = q6audio_get_port_index(data->token);
- if (index < 0 || index >= Q6_AFE_MAX_PORTS) {
+ if (index < 0 || index >= AFE_MAX_PORTS) {
pr_err("%s: invalid port idx %d token %d\n",
__func__, index, data->token);
return 0;
@@ -219,15 +219,15 @@
struct adm_cmd_set_pp_params_v5 adm_params;
int index = afe_get_port_index(port_id);
if (index < 0 || index >= AFE_MAX_PORTS) {
- pr_err("%s: invalid port idx %d portid %d\n",
+ pr_err("%s: invalid port idx %d portid %#x\n",
__func__, index, port_id);
return 0;
}
- pr_debug("%s: Port id %d, index %d\n", __func__, port_id, index);
+ pr_debug("%s: Port id %#x, index %d\n", __func__, port_id, index);
if (!aud_cal || aud_cal->cal_size == 0) {
- pr_debug("%s: No ADM cal to send for port_id = %d!\n",
+ pr_debug("%s: No ADM cal to send for port_id = %#x!\n",
__func__, port_id);
result = -EINVAL;
goto done;
@@ -257,7 +257,7 @@
adm_params.payload_size);
result = apr_send_pkt(this_adm.apr, (uint32_t *)&adm_params);
if (result < 0) {
- pr_err("%s: Set params failed port = %d payload = 0x%x\n",
+ pr_err("%s: Set params failed port = %#x payload = 0x%x\n",
__func__, port_id, aud_cal->cal_paddr);
result = -EINVAL;
goto done;
@@ -267,7 +267,7 @@
atomic_read(&this_adm.copp_stat[index]),
msecs_to_jiffies(TIMEOUT_MS));
if (!result) {
- pr_err("%s: Set params timed out port = %d, payload = 0x%x\n",
+ pr_err("%s: Set params timed out port = %#x, payload = 0x%x\n",
__func__, port_id, aud_cal->cal_paddr);
result = -EINVAL;
goto done;
@@ -317,10 +317,10 @@
}
if (!send_adm_cal_block(port_id, &aud_cal))
- pr_debug("%s: Audproc cal sent for port id: %d, path %d\n",
+ pr_debug("%s: Audproc cal sent for port id: %#x, path %d\n",
__func__, port_id, acdb_path);
else
- pr_debug("%s: Audproc cal not sent for port id: %d, path %d\n",
+ pr_debug("%s: Audproc cal not sent for port id: %#x, path %d\n",
__func__, port_id, acdb_path);
pr_debug("%s: Sending audvol cal\n", __func__);
@@ -351,10 +351,10 @@
}
if (!send_adm_cal_block(port_id, &aud_cal))
- pr_debug("%s: Audvol cal sent for port id: %d, path %d\n",
+ pr_debug("%s: Audvol cal sent for port id: %#x, path %d\n",
__func__, port_id, acdb_path);
else
- pr_debug("%s: Audvol cal not sent for port id: %d, path %d\n",
+ pr_debug("%s: Audvol cal not sent for port id: %#x, path %d\n",
__func__, port_id, acdb_path);
}
@@ -384,7 +384,7 @@
rtac_set_adm_handle(this_adm.apr);
}
index = afe_get_port_index(port_id);
- pr_debug("%s: Port ID %d, index %d\n", __func__, port_id, index);
+ pr_debug("%s: Port ID %#x, index %d\n", __func__, port_id, index);
cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
@@ -405,7 +405,7 @@
atomic_set(&this_adm.copp_stat[index], 0);
ret = apr_send_pkt(this_adm.apr, (uint32_t *)&cmd);
if (ret < 0) {
- pr_err("%s:ADM enable for port %d failed\n",
+ pr_err("%s:ADM enable for port %#x failed\n",
__func__, port_id);
ret = -EINVAL;
goto fail_cmd;
@@ -415,7 +415,7 @@
atomic_read(&this_adm.copp_stat[index]),
msecs_to_jiffies(TIMEOUT_MS));
if (!ret) {
- pr_err("%s ADM connect AFE failed for port %d\n", __func__,
+ pr_err("%s ADM connect AFE failed for port %#x\n", __func__,
port_id);
ret = -EINVAL;
goto fail_cmd;
@@ -435,18 +435,18 @@
int index;
int tmp_port = q6audio_get_port_id(port_id);
- pr_debug("%s: port %d path:%d rate:%d mode:%d\n", __func__,
+ pr_debug("%s: port %#x path:%d rate:%d mode:%d\n", __func__,
port_id, path, rate, channel_mode);
port_id = q6audio_convert_virtual_to_portid(port_id);
if (q6audio_validate_port(port_id) < 0) {
- pr_err("%s port idi[%d] is invalid\n", __func__, port_id);
+ pr_err("%s port idi[%#x] is invalid\n", __func__, port_id);
return -ENODEV;
}
index = q6audio_get_port_index(port_id);
- pr_debug("%s: Port ID %d, index %d\n", __func__, port_id, index);
+ pr_debug("%s: Port ID %#x, index %d\n", __func__, port_id, index);
if (this_adm.apr == NULL) {
this_adm.apr = apr_register("ADSP", "ADM", adm_callback,
@@ -543,15 +543,15 @@
return -EINVAL;
}
- pr_debug("%s: port_id=%d rate=%d"
- "topology_id=0x%X\n", __func__, open.endpoint_id_1, \
- open.sample_rate, open.topology_id);
+ pr_debug("%s: port_id=%#x rate=%d topology_id=0x%X\n",
+ __func__, open.endpoint_id_1, open.sample_rate,
+ open.topology_id);
atomic_set(&this_adm.copp_stat[index], 0);
ret = apr_send_pkt(this_adm.apr, (uint32_t *)&open);
if (ret < 0) {
- pr_err("%s:ADM enable for port %d for[%d] failed\n",
+ pr_err("%s:ADM enable for port %#x for[%d] failed\n",
__func__, tmp_port, port_id);
ret = -EINVAL;
goto fail_cmd;
@@ -561,7 +561,7 @@
atomic_read(&this_adm.copp_stat[index]),
msecs_to_jiffies(TIMEOUT_MS));
if (!ret) {
- pr_err("%s ADM open failed for port %d"
+ pr_err("%s ADM open failed for port %#x"
"for [%d]\n", __func__, tmp_port, port_id);
ret = -EINVAL;
goto fail_cmd;
@@ -599,7 +599,7 @@
/* Assumes port_ids have already been validated during adm_open */
int index = q6audio_get_port_index(copp_id);
- if (index < 0 || index >= Q6_AFE_MAX_PORTS) {
+ if (index < 0 || index >= AFE_MAX_PORTS) {
pr_err("%s: invalid port idx %d token %d\n",
__func__, index, copp_id);
return 0;
@@ -615,7 +615,7 @@
}
route = (struct adm_cmd_matrix_map_routings_v5 *)matrix_map;
- pr_debug("%s: session 0x%x path:%d num_copps:%d port_id[0] :%d coppid[%d]\n",
+ pr_debug("%s: session 0x%x path:%d num_copps:%d port_id[0]:%#x coppid[%d]\n",
__func__, session_id, path, num_copps, port_id[0], copp_id);
route->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
@@ -658,10 +658,10 @@
tmp = q6audio_get_port_index(port_id[i]);
- if (tmp >= 0 && tmp < Q6_AFE_MAX_PORTS)
+ if (tmp >= 0 && tmp < AFE_MAX_PORTS)
copps_list[i] =
atomic_read(&this_adm.copp_id[tmp]);
- pr_debug("%s: port_id[%d]: %d, index: %d act coppid[0x%x]\n",
+ pr_debug("%s: port_id[%#x]: %d, index: %d act coppid[0x%x]\n",
__func__, i, port_id[i], tmp,
atomic_read(&this_adm.copp_id[tmp]));
}
@@ -669,7 +669,7 @@
ret = apr_send_pkt(this_adm.apr, (uint32_t *)matrix_map);
if (ret < 0) {
- pr_err("%s: ADM routing for port %d failed\n",
+ pr_err("%s: ADM routing for port %#x failed\n",
__func__, port_id[0]);
ret = -EINVAL;
goto fail_cmd;
@@ -678,7 +678,7 @@
atomic_read(&this_adm.copp_stat[index]),
msecs_to_jiffies(TIMEOUT_MS));
if (!ret) {
- pr_err("%s: ADM cmd Route failed for port %d\n",
+ pr_err("%s: ADM cmd Route failed for port %#x\n",
__func__, port_id[0]);
ret = -EINVAL;
goto fail_cmd;
@@ -724,7 +724,7 @@
port_id = q6audio_convert_virtual_to_portid(port_id);
if (q6audio_validate_port(port_id) < 0) {
- pr_err("%s port id[%d] is invalid\n", __func__, port_id);
+ pr_err("%s port id[%#x] is invalid\n", __func__, port_id);
return -ENODEV;
}
@@ -864,10 +864,10 @@
if (q6audio_validate_port(port_id) < 0)
return -EINVAL;
- pr_debug("%s port_id=%d index %d\n", __func__, port_id, index);
+ pr_debug("%s port_id=%#x index %d\n", __func__, port_id, index);
if (!(atomic_read(&this_adm.copp_cnt[index]))) {
- pr_err("%s: copp count for port[%d]is 0\n", __func__, port_id);
+ pr_err("%s: copp count for port[%#x]is 0\n", __func__, port_id);
goto fail_cmd;
}
@@ -890,7 +890,7 @@
atomic_set(&this_adm.copp_stat[index], 0);
- pr_debug("%s:coppid %d portid=%d index=%d coppcnt=%d\n",
+ pr_debug("%s:coppid %d portid=%#x index=%d coppcnt=%d\n",
__func__,
atomic_read(&this_adm.copp_id[index]),
port_id, index,
@@ -907,7 +907,7 @@
atomic_read(&this_adm.copp_stat[index]),
msecs_to_jiffies(TIMEOUT_MS));
if (!ret) {
- pr_err("%s: ADM cmd Route failed for port %d\n",
+ pr_err("%s: ADM cmd Route failed for port %#x\n",
__func__, port_id);
ret = -EINVAL;
goto fail_cmd;
@@ -925,7 +925,7 @@
int i = 0;
this_adm.apr = NULL;
- for (i = 0; i < Q6_AFE_MAX_PORTS; i++) {
+ for (i = 0; i < AFE_MAX_PORTS; i++) {
atomic_set(&this_adm.copp_id[i], RESET_COPP_ID);
atomic_set(&this_adm.copp_cnt[i], 0);
atomic_set(&this_adm.copp_stat[i], 0);
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
index 8d8ff5d..de9841a 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -165,6 +165,7 @@
case INT_FM_RX:
case VOICE_PLAYBACK_TX:
case RT_PROXY_PORT_001_RX:
+ case AFE_PORT_ID_QUATERNARY_MI2S_RX:
ret = MSM_AFE_PORT_TYPE_RX;
break;
@@ -183,12 +184,13 @@
case VOICE_RECORD_RX:
case INT_BT_SCO_TX:
case RT_PROXY_PORT_001_TX:
+ case AFE_PORT_ID_QUATERNARY_MI2S_TX:
ret = MSM_AFE_PORT_TYPE_TX;
break;
default:
WARN_ON(1);
- pr_err("%s: invalid port id %d\n", __func__, port_id);
+ pr_err("%s: invalid port id %#x\n", __func__, port_id);
ret = -EINVAL;
}
@@ -283,10 +285,10 @@
(port_id == RT_PROXY_DAI_001_TX))
port_id = VIRTUAL_ID_TO_PORTID(port_id);
- pr_debug("%s: port id: %d\n", __func__, port_id);
+ pr_debug("%s: port id: %#x\n", __func__, port_id);
index = q6audio_get_port_index(port_id);
if (q6audio_validate_port(port_id) < 0) {
- pr_err("%s: port id: %d\n", __func__, port_id);
+ pr_err("%s: port id: %#x\n", __func__, port_id);
return -EINVAL;
}
@@ -295,7 +297,7 @@
return ret;
if (q6audio_validate_port(port_id) < 0) {
- pr_err("%s: Failed : Invalid Port id = %d\n", __func__,
+ pr_err("%s: Failed : Invalid Port id = %#x\n", __func__,
port_id);
ret = -EINVAL;
goto fail_cmd;
@@ -321,6 +323,12 @@
case SECONDARY_I2S_TX:
case MI2S_RX:
case MI2S_TX:
+ case AFE_PORT_ID_SECONDARY_MI2S_RX:
+ case AFE_PORT_ID_SECONDARY_MI2S_TX:
+ case AFE_PORT_ID_TERTIARY_MI2S_RX:
+ case AFE_PORT_ID_TERTIARY_MI2S_TX:
+ case AFE_PORT_ID_QUATERNARY_MI2S_RX:
+ case AFE_PORT_ID_QUATERNARY_MI2S_TX:
cfg_type = AFE_PARAM_ID_I2S_CONFIG;
break;
case HDMI_RX:
@@ -370,7 +378,7 @@
atomic_set(&this_afe.status, 0);
ret = apr_send_pkt(this_afe.apr, (uint32_t *) &config);
if (ret < 0) {
- pr_err("%s: AFE enable for port %d failed\n", __func__,
+ pr_err("%s: AFE enable for port %#x failed\n", __func__,
port_id);
ret = -EINVAL;
goto fail_cmd;
@@ -407,7 +415,7 @@
ret = apr_send_pkt(this_afe.apr, (uint32_t *) &start);
if (IS_ERR_VALUE(ret)) {
- pr_err("%s: AFE enable for port %d failed\n", __func__,
+ pr_err("%s: AFE enable for port %#x failed\n", __func__,
port_id);
ret = -EINVAL;
goto fail_cmd;
@@ -468,7 +476,10 @@
case RT_PROXY_PORT_001_TX: return IDX_RT_PROXY_PORT_001_TX;
case SLIMBUS_4_RX: return IDX_SLIMBUS_4_RX;
case SLIMBUS_4_TX: return IDX_SLIMBUS_4_TX;
-
+ case AFE_PORT_ID_QUATERNARY_MI2S_RX:
+ return IDX_AFE_PORT_ID_QUATERNARY_MI2S_RX;
+ case AFE_PORT_ID_QUATERNARY_MI2S_TX:
+ return IDX_AFE_PORT_ID_QUATERNARY_MI2S_TX;
default: return -EINVAL;
}
}
diff --git a/sound/soc/msm/qdsp6v2/q6audio-v2.c b/sound/soc/msm/qdsp6v2/q6audio-v2.c
index 8c524fa..033cb8e 100644
--- a/sound/soc/msm/qdsp6v2/q6audio-v2.c
+++ b/sound/soc/msm/qdsp6v2/q6audio-v2.c
@@ -48,7 +48,10 @@
case INT_FM_TX: return IDX_INT_FM_TX;
case RT_PROXY_PORT_001_RX: return IDX_RT_PROXY_PORT_001_RX;
case RT_PROXY_PORT_001_TX: return IDX_RT_PROXY_PORT_001_TX;
-
+ case AFE_PORT_ID_QUATERNARY_MI2S_RX:
+ return IDX_AFE_PORT_ID_QUATERNARY_MI2S_RX;
+ case AFE_PORT_ID_QUATERNARY_MI2S_TX:
+ return IDX_AFE_PORT_ID_QUATERNARY_MI2S_TX;
default: return -EINVAL;
}
}
@@ -82,6 +85,10 @@
case INT_FM_TX: return AFE_PORT_ID_INTERNAL_FM_TX;
case RT_PROXY_PORT_001_RX: return AFE_PORT_ID_RT_PROXY_PORT_001_RX;
case RT_PROXY_PORT_001_TX: return AFE_PORT_ID_RT_PROXY_PORT_001_TX;
+ case AFE_PORT_ID_QUATERNARY_MI2S_RX:
+ return AFE_PORT_ID_QUATERNARY_MI2S_RX;
+ case AFE_PORT_ID_QUATERNARY_MI2S_TX:
+ return AFE_PORT_ID_QUATERNARY_MI2S_TX;
default: return -EINVAL;
}
@@ -138,6 +145,8 @@
case INT_FM_TX:
case RT_PROXY_PORT_001_RX:
case RT_PROXY_PORT_001_TX:
+ case AFE_PORT_ID_QUATERNARY_MI2S_RX:
+ case AFE_PORT_ID_QUATERNARY_MI2S_TX:
{
ret = 0;
break;