Merge "Enable NEED_NETDEV for vendor command support."
diff --git a/Documentation/devicetree/bindings/arm/msm/msm_bus.txt b/Documentation/devicetree/bindings/arm/msm/msm_bus.txt
index 9f74225..e6e54bf 100644
--- a/Documentation/devicetree/bindings/arm/msm/msm_bus.txt
+++ b/Documentation/devicetree/bindings/arm/msm/msm_bus.txt
@@ -100,8 +100,8 @@
(Can be Fixed/Limiter/Bypass/Regulator)
qcom,bimc,bw: Bandwidth limit for a BIMC master using dual modes.
This bandwidth is used to calculate Grant count and
- other parameters used in Limiter and Regular mode
- for static BKE configuration. It is defined in KBps.
+ other parameters used in Limiter and Regular mode.
+ for static BKE configuration. It is defined in KBytes/s.
qcom,bimc,gp: Grant Period for configuring a master in limiter
mode. This is an integer value in nano-seconds.
qcom,bimc,thmp: Medium threshold percentage for BIMC masters.
@@ -111,11 +111,12 @@
1 and 100.
qcom,thresh: Beyond this threshold frequency, the mode usage is
switched from mode specified by property qcom,mode
- to the one specified by qcom,mode-thresh. In case the
- requested IB value falls below this threshold, the mode
- is switched back to qcom,mode. Frequency is specified in
- KBps.
-
+ to the one specified by qcom,mode-thresh. These thresholds
+ can be setup in increasing order of thresholds, so the
+ requested IB is evaluated at each threshold level before
+ making the decision to switch QoS modes and applying the
+ corresponding qcom,bimc,bw limitig bw as needed.
+ This is specified in KBytes/s.
diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-ctrl.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-ctrl.txt
index e8b02cf..b88c3ce 100644
--- a/Documentation/devicetree/bindings/fb/mdss-dsi-ctrl.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-dsi-ctrl.txt
@@ -6,8 +6,12 @@
Required properties:
- compatible: Must be "qcom,mdss-dsi-ctrl"
- cell-index: Specifies the controller used among the two controllers.
-- reg: Offset and length of the register regions(s) for the device.
+- reg: Base address and length of the different register
+ regions(s) required for DSI device functionality.
- reg-names: A list of strings that map in order to the list of regs.
+ "dsi_ctrl" - MDSS DSI controller register region
+ "dsi_phy" - MDSS DSI PHY register region
+ "mmss_misc_phys" - Register region for MMSS DSI clamps
- vdd-supply: Phandle for vdd regulator device node.
- vddio-supply: Phandle for vdd-io regulator device node.
- vdda-supply: Phandle for vreg regulator device node.
@@ -53,9 +57,10 @@
compatible = "qcom,mdss-dsi-ctrl";
label = "MDSS DSI CTRL->0";
cell-index = <0>;
- reg = <0xfd922800 0x600>,
+ reg = <0xfd922800 0x1f8>,
+ <0xfd922b00 0x2b0>,
<0xfd828000 0x108>;
- reg-names = "dsi_phys", "mmss_misc_phys";
+ reg-names = "dsi_ctrl", "dsi_phy", "mmss_misc_phys";
vdd-supply = <&pm8226_l15>;
vddio-supply = <&pm8226_l8>;
vdda-supply = <&pm8226_l4>;
diff --git a/Documentation/devicetree/bindings/fb/mdss-mdp.txt b/Documentation/devicetree/bindings/fb/mdss-mdp.txt
index c2b963f..cfcc48b 100644
--- a/Documentation/devicetree/bindings/fb/mdss-mdp.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-mdp.txt
@@ -27,6 +27,14 @@
to the respective VIG pipes. Number of xin ids
defined should match the number of offsets
defined in property: qcom,mdss-pipe-vig-off
+- qcom,mdss-pipe-vig-clk-ctrl-off: Array of offsets describing clk control
+ offsets for dynamic clock gating. 1st value
+ in the array represents offset of the control
+ register. 2nd value represents bit offset within
+ control register and 3rd value represents bit
+ offset within status register. Number of tuples
+ defined should match the number of offsets
+ defined in property: qcom,mdss-pipe-vig-off
- qcom,mdss-pipe-rgb-off: Array of offsets for MDP source surface pipes of
type RGB, the offsets are calculated from
register "mdp_phys" defined in reg property.
@@ -42,6 +50,14 @@
to the respective RGB pipes. Number of xin ids
defined should match the number of offsets
defined in property: qcom,mdss-pipe-rgb-off
+- qcom,mdss-pipe-rgb-clk-ctrl-off: Array of offsets describing clk control
+ offsets for dynamic clock gating. 1st value
+ in the array represents offset of the control
+ register. 2nd value represents bit offset within
+ control register and 3rd value represents bit
+ offset within status register. Number of tuples
+ defined should match the number of offsets
+ defined in property: qcom,mdss-pipe-rgb-off
- qcom,mdss-pipe-dma-off: Array of offsets for MDP source surface pipes of
type DMA, the offsets are calculated from
register "mdp_phys" defined in reg property.
@@ -57,6 +73,14 @@
to the respective DMA pipes. Number of xin ids
defined should match the number of offsets
defined in property: qcom,mdss-pipe-dma-off
+- qcom,mdss-pipe-dma-clk-ctrl-off: Array of offsets describing clk control
+ offsets for dynamic clock gating. 1st value
+ in the array represents offset of the control
+ register. 2nd value represents bit offset within
+ control register and 3rd value represents bit
+ offset within status register. Number of tuples
+ defined should match the number of offsets
+ defined in property: qcom,mdss-pipe-dma-off
- qcom,mdss-smp-data: Array of shared memory pool data. There should
be only two values in this property. The first
value corresponds to the number of smp blocks
@@ -364,6 +388,19 @@
qcom,mdss-has-decimation;
qcom,mdss-has-wfd-blk;
+ qcom,mdss-pipe-vig-clk-ctrl-offsets = <0x3AC 0 0>,
+ <0x3B4 0 0>,
+ <0x3BC 0 0>,
+ <0x3C4 0 0>;
+
+ qcom,mdss-pipe-rgb-clk-ctrl-offsets = <0x3AC 4 8>,
+ <0x3B4 4 8>,
+ <0x3BC 4 8>,
+ <0x3C4 4 8>;
+
+ qcom,mdss-pipe-dma-clk-ctrl-offsets = <0x3AC 8 12>,
+ <0x3B4 8 12>;
+
qcom,mdss-ctl-off = <0x00000600 0x00000700 0x00000800
0x00000900 0x0000A00>;
qcom,mdss-mixer-intf-off = <0x00003200 0x00003600
diff --git a/Documentation/devicetree/bindings/hwmon/qpnp-adc-current.txt b/Documentation/devicetree/bindings/hwmon/qpnp-adc-current.txt
index d0cad52..9acf54a 100644
--- a/Documentation/devicetree/bindings/hwmon/qpnp-adc-current.txt
+++ b/Documentation/devicetree/bindings/hwmon/qpnp-adc-current.txt
@@ -33,6 +33,9 @@
apply the default RSENSE if conditions are met.
1 : Select this type to read the IADC, SMBB trim register and
manufacturer type and apply the default RSENSE if conditions are met.
+- qcom,pmic-revid : Phandle pointing to the revision peripheral node. Use it to query the
+ PMIC type and revision for applying the appropriate temperature
+ compensation parameters.
Channel node
NOTE: Atleast one Channel node is required.
diff --git a/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt b/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt
index dd0c440..83403ba 100644
--- a/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt
+++ b/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt
@@ -22,6 +22,9 @@
Optional properties:
- qcom,vadc-poll-eoc: Use polling instead of interrupts for End of Conversion completion.
+- qcom,pmic-revid : Phandle pointing to the revision peripheral node. Use it to query the
+ PMIC type and revision for applying the appropriate temperature
+ compensation parameters.
Client required property:
- qcom,<consumer name>-vadc : The phandle to the corresponding vadc device.
diff --git a/Documentation/devicetree/bindings/memory.txt b/Documentation/devicetree/bindings/memory.txt
index e98ee05..32f6a24 100644
--- a/Documentation/devicetree/bindings/memory.txt
+++ b/Documentation/devicetree/bindings/memory.txt
@@ -36,6 +36,7 @@
reg = <(baseaddr) (size)>;
(linux,contiguous-region);
(linux,default-contiguous-region);
+ (linux,memory-limit);
label = (unique_name);
};
@@ -48,6 +49,11 @@
linux,default-contiguous-region: property indicating that the region
is the default region for all contiguous memory
allocations, Linux specific (optional)
+linux,memory-limit: property specifying an upper bound on the physical address
+ of the region if the region is placed dynamically. If no limit
+ is specificed, the region may be placed anywhere in the physical
+ address space. 0 may be used to specify lowmem (i.e. the region
+ will be placed in the direct mapped lowmem region)
label: an internal name used for automatically associating the
cma region with a given device. The label is optional;
if the label is not given the client is responsible for
diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
index d502f78..8c41926 100644
--- a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
+++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
@@ -55,6 +55,9 @@
no default value that the driver assumes if this property
is not specified. So if this property is not specified,
then SDHC driver will not vote for PM QOS.
+ - qcom,dat1-mpm-int: specifies MPM interrupt number (e.g. sdhc_2 node below)
+ corresponding to DAT1 line of SDHC (used only if slot has dedicated
+ DAT1 MSM pin (not GPIO))
In the following, <supply> can be vdd (flash core voltage) or vdd-io (I/O voltage).
- qcom,<supply>-always-on - specifies whether supply should be kept "on" always.
@@ -165,4 +168,5 @@
<81 512 106496 212992>, /* 208 MB/s */
<81 512 2147483647 4294967295>; /* Max. bandwidth */
qcom,bus-bw-vectors-bps = <0 13631488 27262976 54525952 109051904 218103808 4294967295>;
+ qcom,dat1-mpm-int = <44>;
};
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
index e672a14..401a2ec 100644
--- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -140,6 +140,7 @@
FM Rx and TX port ID values from 12292 to 12293
incall record Rx and TX port ID values from 32771 to 32772
inCall Music Delivery port ID is 32773
+ incall Music 2 Delivery port ID is 32770
* msm-auxpcm
@@ -376,6 +377,11 @@
compatible = "qcom,msm-dai-q6-dev";
qcom,msm-dai-q6-dev-id = <32773>;
};
+
+ qcom,msm-dai-q6-incall-music-2-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <32770>;
+ };
};
qcom,msm-pri-auxpcm {
diff --git a/Documentation/devicetree/bindings/usb/msm-hsusb.txt b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
index 7d3d435..fcafe11 100644
--- a/Documentation/devicetree/bindings/usb/msm-hsusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
@@ -159,6 +159,7 @@
and no peripheral connected over dock during low power mode, fourth value represents
minimum value to vote when USB is operational, fifth item represents maximum value
to vote for USB is operational.
+- qcom,usb2-enable-uicc: If present, usb2 port will be used for uicc card connection.
Example MSM HSUSB EHCI controller device node :
ehci: qcom,ehci-host@f9a55000 {
@@ -172,6 +173,7 @@
qcom,usb2-enable-hsphy2;
qcom,usb2-power-budget = <500>;
qcom,vdd-voltage-level = <1 2 3 5 7>;
+ qcom,usb2-enable-uicc;
};
ANDROID USB:
diff --git a/Documentation/vm/ksm.txt b/Documentation/vm/ksm.txt
index b392e49..8e54981 100644
--- a/Documentation/vm/ksm.txt
+++ b/Documentation/vm/ksm.txt
@@ -72,6 +72,13 @@
pages_unshared - how many pages unique but repeatedly checked for merging
pages_volatile - how many pages changing too fast to be placed in a tree
full_scans - how many times all mergeable areas have been scanned
+deferred_timer - whether to use deferred timers or not
+ e.g. "echo 1 > /sys/kernel/mm/ksm/deferred_timer"
+ Default: 0 (means, we are not using deferred timers. Users
+ might want to set deferred_timer option if they donot want
+ ksm thread to wakeup CPU to carryout ksm activities thus
+ gaining on battery while compromising slightly on memory
+ that could have been saved.)
A high ratio of pages_sharing to pages_shared indicates good sharing, but
a high ratio of pages_unshared to pages_sharing indicates wasted effort.
diff --git a/arch/arm/boot/dts/apq8084-camera-sensor-cdp.dtsi b/arch/arm/boot/dts/apq8084-camera-sensor-cdp.dtsi
index 5577d16..173ea63 100644
--- a/arch/arm/boot/dts/apq8084-camera-sensor-cdp.dtsi
+++ b/arch/arm/boot/dts/apq8084-camera-sensor-cdp.dtsi
@@ -104,6 +104,7 @@
qcom,csiphy-sd-index = <0>;
qcom,csid-sd-index = <0>;
qcom,actuator-src = <&actuator0>;
+ qcom,mount-angle = <90>;
cam_vdig-supply = <&pma8084_l27>;
cam_vio-supply = <&pma8084_lvs4>;
cam_vana-supply = <&pma8084_l17>;
@@ -125,6 +126,8 @@
qcom,gpio-req-tbl-label = "CAMIF_MCLK",
"CAM_RESET1",
"CAM_STANDBY";
+ qcom,sensor-position = <0>;
+ qcom,sensor-mode = <1>;
qcom,cci-master = <0>;
status = "ok";
};
@@ -153,6 +156,8 @@
qcom,gpio-req-tbl-flags = <1 0>;
qcom,gpio-req-tbl-label = "CAMIF_MCLK2",
"CAM_XSHUTDOWN";
+ qcom,sensor-position = <1>;
+ qcom,sensor-mode = <1>;
qcom,cci-master = <0>;
status = "ok";
};
diff --git a/arch/arm/boot/dts/apq8084-camera-sensor-mtp.dtsi b/arch/arm/boot/dts/apq8084-camera-sensor-mtp.dtsi
index 02d8b59..bfbbf54 100644
--- a/arch/arm/boot/dts/apq8084-camera-sensor-mtp.dtsi
+++ b/arch/arm/boot/dts/apq8084-camera-sensor-mtp.dtsi
@@ -126,6 +126,8 @@
qcom,gpio-req-tbl-label = "CAMIF_MCLK",
"CAM_RESET1",
"CAM_STANDBY";
+ qcom,sensor-position = <0>;
+ qcom,sensor-mode = <1>;
qcom,cci-master = <0>;
status = "ok";
};
@@ -153,6 +155,8 @@
qcom,gpio-req-tbl-flags = <1 0>;
qcom,gpio-req-tbl-label = "CAMIF_MCLK2",
"CAM_XSHUTDOWN";
+ qcom,sensor-position = <1>;
+ qcom,sensor-mode = <1>;
qcom,cci-master = <0>;
status = "ok";
};
diff --git a/arch/arm/boot/dts/apq8084-mdss.dtsi b/arch/arm/boot/dts/apq8084-mdss.dtsi
index 329ab32..665eedc 100644
--- a/arch/arm/boot/dts/apq8084-mdss.dtsi
+++ b/arch/arm/boot/dts/apq8084-mdss.dtsi
@@ -54,6 +54,17 @@
qcom,mdss-pipe-rgb-xin-id = <1 5 9 13>;
qcom,mdss-pipe-dma-xin-id = <2 10>;
+ qcom,mdss-pipe-vig-clk-ctrl-offsets = <0x3AC 0 0>,
+ <0x3B4 0 0>,
+ <0x3BC 0 0>,
+ <0x3C4 0 0>;
+ qcom,mdss-pipe-rgb-clk-ctrl-offsets = <0x3AC 4 8>,
+ <0x3B4 4 8>,
+ <0x3BC 4 8>,
+ <0x3C4 4 8>;
+ qcom,mdss-pipe-dma-clk-ctrl-offsets = <0x3AC 8 12>,
+ <0x3B4 8 12>;
+
qcom,mdss-smp-data = <44 8192>;
qcom,mdss-ctl-off = <0x00000600 0x00000700 0x00000800
diff --git a/arch/arm/boot/dts/dsi-panel-nt35590-720p-video.dtsi b/arch/arm/boot/dts/dsi-panel-nt35590-720p-video.dtsi
index 8d28996..9a18a31 100644
--- a/arch/arm/boot/dts/dsi-panel-nt35590-720p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-nt35590-720p-video.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -30,7 +30,7 @@
qcom,mdss-dsi-h-back-porch = <164>;
qcom,mdss-dsi-h-pulse-width = <8>;
qcom,mdss-dsi-h-sync-skew = <0>;
- qcom,mdss-dsi-v-back-porch = <1>;
+ qcom,mdss-dsi-v-back-porch = <11>;
qcom,mdss-dsi-v-front-porch = <6>;
qcom,mdss-dsi-v-pulse-width = <1>;
qcom,mdss-dsi-h-left-border = <0>;
@@ -504,7 +504,9 @@
29 01 00 00 00 00 02 6A 60
29 01 00 00 00 00 02 FF 00
29 01 00 00 78 00 02 29 00
- 29 01 00 00 78 00 02 53 2C];
+ 29 01 00 00 78 00 02 53 2C
+ 29 01 00 00 00 00 02 FF 00
+ 29 01 00 00 00 00 06 3B 03 06 03 02 02];
qcom,mdss-dsi-off-command = [05 01 00 00 32 00 02 28 00
05 01 00 00 78 00 02 10 00];
qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
diff --git a/arch/arm/boot/dts/msm-pm8110.dtsi b/arch/arm/boot/dts/msm-pm8110.dtsi
index 9adbf81..7a60861 100644
--- a/arch/arm/boot/dts/msm-pm8110.dtsi
+++ b/arch/arm/boot/dts/msm-pm8110.dtsi
@@ -22,7 +22,7 @@
#address-cells = <1>;
#size-cells = <1>;
- qcom,revid@100 {
+ pm8110_revid: qcom,revid@100 {
compatible = "qcom,qpnp-revid";
reg = <0x100 0x100>;
};
@@ -219,6 +219,7 @@
qcom,adc-bit-resolution = <15>;
qcom,adc-vdd-reference = <1800>;
qcom,vadc-poll-eoc;
+ qcom,pmic-revid = <&pm8110_revid>;
chan@8 {
label = "die_temp";
@@ -268,6 +269,7 @@
qcom,iadc-vadc = <&pm8110_vadc>;
qcom,iadc-poll-eoc;
qcom,use-default-rds-trim = <1>;
+ qcom,pmic-revid = <&pm8110_revid>;
chan@0 {
label = "internal_rsense";
diff --git a/arch/arm/boot/dts/msm-pm8226.dtsi b/arch/arm/boot/dts/msm-pm8226.dtsi
index 41897da..08d3d05 100644
--- a/arch/arm/boot/dts/msm-pm8226.dtsi
+++ b/arch/arm/boot/dts/msm-pm8226.dtsi
@@ -364,6 +364,7 @@
qcom,adc-bit-resolution = <15>;
qcom,adc-vdd-reference = <1800>;
qcom,vadc-poll-eoc;
+ qcom,pmic-revid = <&pm8226_revid>;
chan@8 {
label = "die_temp";
@@ -424,6 +425,7 @@
qcom,iadc-vadc = <&pm8226_vadc>;
qcom,iadc-poll-eoc;
qcom,use-default-rds-trim = <0>;
+ qcom,pmic-revid = <&pm8226_revid>;
chan@0 {
label = "internal_rsense";
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index 94a4e83..a0e02f7 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -27,7 +27,7 @@
reg = <0x900 0x100>;
};
- qcom,revid@100 {
+ pm8941_revid: qcom,revid@100 {
compatible = "qcom,qpnp-revid";
reg = <0x100 0x100>;
};
@@ -577,6 +577,7 @@
qcom,adc-bit-resolution = <15>;
qcom,adc-vdd-reference = <1800>;
qcom,vadc-poll-eoc;
+ qcom,pmic-revid = <&pm8941_revid>;
chan@0 {
label = "usb_in";
@@ -824,6 +825,7 @@
qcom,iadc-vadc = <&pm8941_vadc>;
qcom,iadc-poll-eoc;
qcom,use-default-rds-trim = <0>;
+ qcom,pmic-revid = <&pm8941_revid>;
chan@0 {
label = "internal_rsense";
diff --git a/arch/arm/boot/dts/msm8226-720p-cdp.dtsi b/arch/arm/boot/dts/msm8226-720p-cdp.dtsi
index 00e90f3..66f9b18 100644
--- a/arch/arm/boot/dts/msm8226-720p-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8226-720p-cdp.dtsi
@@ -35,6 +35,20 @@
};
};
+ i2c@f9925000 { /* BLSP1 QUP3 */
+ nfc-nci@0e {
+ compatible = "qcom,nfc-nci";
+ reg = <0x0e>;
+ qcom,irq-gpio = <&msmgpio 21 0x00>;
+ qcom,dis-gpio = <&msmgpio 20 0x00>;
+ qcom,clk-src = "BBCLK2";
+ interrupt-parent = <&msmgpio>;
+ interrupts = <21 0>;
+ qcom,clk-gpio = <&pm8226_gpios 3 0>;
+ };
+ };
+
+
gpio_keys {
compatible = "gpio-keys";
input-name = "gpio-keys";
@@ -372,6 +386,11 @@
};
gpio@c200 { /* GPIO 3 */
+ qcom,mode = <0>; /* QPNP_PIN_MODE_DIG_IN */
+ qcom,pull = <5>; /* QPNP_PIN_PULL_NO */
+ qcom,vin-sel = <2>; /* QPNP_PIN_VIN2 */
+ qcom,src-sel = <2>; /* QPNP_PIN_SEL_FUNC_1 */
+ qcom,master-en = <1>;
};
gpio@c300 { /* GPIO 4 */
diff --git a/arch/arm/boot/dts/msm8226-bus.dtsi b/arch/arm/boot/dts/msm8226-bus.dtsi
index 74b4a30..a2f91cf 100644
--- a/arch/arm/boot/dts/msm8226-bus.dtsi
+++ b/arch/arm/boot/dts/msm8226-bus.dtsi
@@ -998,7 +998,7 @@
qcom,fabclk-dual = "mem_clk";
qcom,fabclk-active = "mem_a_clk";
qcom,ntieredslaves = <0>;
- qcom,qos-freq = <4800>;
+ qcom,qos-freq = <19200>;
qcom,hw-sel = "BIMC";
qcom,rpm-en;
@@ -1008,12 +1008,18 @@
qcom,masterp = <0>;
qcom,tier = <2>;
qcom,hw-sel = "BIMC";
- qcom,mode = "Fixed";
+ qcom,mode = "Limiter";
qcom,qport = <0>;
qcom,ws = <10000>;
qcom,mas-hw-id = <0>;
qcom,prio-rd = <0>;
qcom,prio-wr = <0>;
+ qcom,mode-thresh = "Fixed";
+ qcom,thresh = <1800000>;
+ qcom,dual-conf;
+ qcom,bimc,bw = <450000>;
+ qcom,bimc,gp = <5000>;
+ qcom,bimc,thmp = <50>;
};
mas-mss-proc {
diff --git a/arch/arm/boot/dts/msm8226-camera-sensor-cdp.dtsi b/arch/arm/boot/dts/msm8226-camera-sensor-cdp.dtsi
index 4170255..05a3f07 100644
--- a/arch/arm/boot/dts/msm8226-camera-sensor-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8226-camera-sensor-cdp.dtsi
@@ -198,6 +198,7 @@
reg = <0x0>;
qcom,csiphy-sd-index = <0>;
qcom,csid-sd-index = <0>;
+ qcom,mount-angle = <90>;
qcom,actuator-src = <&actuator0>;
qcom,led-flash-src = <&led_flash0>;
cam_vdig-supply = <&pm8226_l5>;
@@ -220,6 +221,8 @@
qcom,gpio-req-tbl-label = "CAMIF_MCLK",
"CAM_RESET1",
"CAM_STANDBY";
+ qcom,sensor-position = <0>;
+ qcom,sensor-mode = <0>;
qcom,cci-master = <0>;
status = "ok";
};
@@ -230,6 +233,7 @@
reg = <0x1>;
qcom,csiphy-sd-index = <1>;
qcom,csid-sd-index = <1>;
+ qcom,mount-angle = <0>;
cam_vdig-supply = <&pm8226_l5>;
cam_vana-supply = <&pm8226_l19>;
cam_vio-supply = <&pm8226_lvs1>;
@@ -248,6 +252,8 @@
qcom,gpio-req-tbl-label = "CAMIF_MCLK",
"CAM_RESET",
"CAM_STANDBY";
+ qcom,sensor-position = <1>;
+ qcom,sensor-mode = <1>;
qcom,cci-master = <0>;
status = "ok";
};
diff --git a/arch/arm/boot/dts/msm8226-camera-sensor-mtp.dtsi b/arch/arm/boot/dts/msm8226-camera-sensor-mtp.dtsi
index 97e7dff..a6af2c2 100644
--- a/arch/arm/boot/dts/msm8226-camera-sensor-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8226-camera-sensor-mtp.dtsi
@@ -112,7 +112,7 @@
reg = <0x0>;
qcom,csiphy-sd-index = <0>;
qcom,csid-sd-index = <0>;
- qcom,mount-angle = <0>;
+ qcom,mount-angle = <270>;
qcom,actuator-src = <&actuator0>;
qcom,led-flash-src = <&led_flash0>;
cam_vdig-supply = <&pm8226_l5>;
@@ -136,6 +136,8 @@
qcom,gpio-req-tbl-label = "CAMIF_MCLK",
"CAM_RESET1",
"CAM_STANDBY";
+ qcom,sensor-position = <0>;
+ qcom,sensor-mode = <0>;
qcom,cci-master = <0>;
status = "ok";
};
@@ -166,6 +168,8 @@
qcom,gpio-req-tbl-label = "CAMIF_MCLK",
"CAM_RESET",
"CAM_STANDBY";
+ qcom,sensor-position = <1>;
+ qcom,sensor-mode = <0>;
qcom,cci-master = <0>;
status = "ok";
};
diff --git a/arch/arm/boot/dts/msm8226-camera-sensor-qrd.dtsi b/arch/arm/boot/dts/msm8226-camera-sensor-qrd.dtsi
index a553918..dab92ff 100644
--- a/arch/arm/boot/dts/msm8226-camera-sensor-qrd.dtsi
+++ b/arch/arm/boot/dts/msm8226-camera-sensor-qrd.dtsi
@@ -448,7 +448,7 @@
reg = <0x0>;
qcom,csiphy-sd-index = <0>;
qcom,csid-sd-index = <0>;
- qcom,mount-angle = <270>;
+ qcom,mount-angle = <90>;
qcom,actuator-src = <&actuator0>;
qcom,eeprom-src = <&eeprom0>;
qcom,led-flash-src = <&led_flash0>;
@@ -479,6 +479,8 @@
"CAM_STANDBY",
"CAM_VDIG",
"CAM_AF_PWDM";
+ qcom,sensor-position = <0>;
+ qcom,sensor-mode = <0>;
qcom,cci-master = <0>;
status = "ok";
};
@@ -516,6 +518,8 @@
qcom,gpio-set-tbl-num = <1 1>;
qcom,gpio-set-tbl-flags = <0 2>;
qcom,gpio-set-tbl-delay = <1000 4000>;
+ qcom,sensor-position = <1>;
+ qcom,sensor-mode = <0>;
qcom,cci-master = <0>;
status = "ok";
};
diff --git a/arch/arm/boot/dts/msm8226-mdss.dtsi b/arch/arm/boot/dts/msm8226-mdss.dtsi
index 2176d39..5edc43b 100644
--- a/arch/arm/boot/dts/msm8226-mdss.dtsi
+++ b/arch/arm/boot/dts/msm8226-mdss.dtsi
@@ -19,7 +19,7 @@
interrupts = <0 72 0>;
vdd-supply = <&gdsc_mdss>;
- qcom,max-bandwidth-low-kbps = <1660000>;
+ qcom,max-bandwidth-low-kbps = <1100000>;
qcom,max-bandwidth-high-kbps = <1660000>;
/* Bus Scale Settings */
@@ -32,8 +32,8 @@
<22 512 0 6400000>;
/* Fudge factors */
- qcom,mdss-ab-factor = <2 1>; /* 2 times */
- qcom,mdss-ib-factor = <6 5>; /* 1.2 times */
+ qcom,mdss-ab-factor = <1 1>; /* 1 times */
+ qcom,mdss-ib-factor = <2 1>; /* 2 times */
qcom,mdss-clk-factor = <5 4>; /* 1.25 times */
qcom,max-clk-rate = <200000000>;
@@ -48,6 +48,10 @@
qcom,mdss-pipe-rgb-xin-id = <1>;
qcom,mdss-pipe-dma-xin-id = <2>;
+ qcom,mdss-pipe-vig-clk-ctrl-offsets = <0x3AC 0 0>;
+ qcom,mdss-pipe-rgb-clk-ctrl-offsets = <0x3AC 4 8>;
+ qcom,mdss-pipe-dma-clk-ctrl-offsets = <0x3AC 8 12>;
+
qcom,mdss-smp-data = <7 4096>;
qcom,mdss-ctl-off = <0x00000600 0x00000700>;
@@ -95,9 +99,10 @@
compatible = "qcom,mdss-dsi-ctrl";
label = "MDSS DSI CTRL->0";
cell-index = <0>;
- reg = <0xfd922800 0x600>,
+ reg = <0xfd922800 0x1f8>,
+ <0xfd922b00 0x2b0>,
<0xfd828000 0x108>;
- reg-names = "dsi_phys", "mmss_misc_phys";
+ reg-names = "dsi_ctrl", "dsi_phy", "mmss_misc_phys";
qcom,mdss-fb-map = <&mdss_fb0>;
qcom,mdss-mdp = <&mdss_mdp>;
vdd-supply = <&pm8226_l15>;
diff --git a/arch/arm/boot/dts/msm8226-regulator.dtsi b/arch/arm/boot/dts/msm8226-regulator.dtsi
index 5e890d3..78e1a63 100644
--- a/arch/arm/boot/dts/msm8226-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8226-regulator.dtsi
@@ -78,7 +78,7 @@
vdd-apc-supply = <&pm8226_s2>;
vdd-mx-supply = <&pm8226_l3_ao>;
- qcom,vdd-mx-vmax = <1350000>;
+ qcom,vdd-mx-vmax = <1337500>;
qcom,vdd-mx-vmin-method = <1>;
qcom,cpr-ref-clk = <19200>;
@@ -109,7 +109,7 @@
qcom,cpr-fuse-uplift-sel = <22 53 1 0 0>;
qcom,cpr-uplift-voltage = <50000>;
qcom,cpr-uplift-quotient = <0 0 120>;
- qcom,cpr-uplift-max-volt = <1350000>;
+ qcom,cpr-uplift-max-volt = <1330000>;
qcom,cpr-uplift-speed-bin = <1>;
qcom,speed-bin-fuse-sel = <22 0 3 0>;
};
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index 4117d9d..5576b2b 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -775,6 +775,7 @@
qcom,bus-width = <8>;
+ qcom,cpu-dma-latency-us = <701>;
qcom,msm-bus,name = "sdcc1";
qcom,msm-bus,num-cases = <8>;
qcom,msm-bus,num-paths = <1>;
@@ -802,6 +803,7 @@
qcom,bus-width = <8>;
+ qcom,cpu-dma-latency-us = <701>;
qcom,msm-bus,name = "sdhc1";
qcom,msm-bus,num-cases = <8>;
qcom,msm-bus,num-paths = <1>;
@@ -832,6 +834,7 @@
qcom,bus-width = <4>;
+ qcom,cpu-dma-latency-us = <701>;
qcom,msm-bus,name = "sdcc2";
qcom,msm-bus,num-cases = <8>;
qcom,msm-bus,num-paths = <1>;
@@ -859,6 +862,7 @@
qcom,bus-width = <4>;
+ qcom,cpu-dma-latency-us = <701>;
qcom,msm-bus,name = "sdhc2";
qcom,msm-bus,num-cases = <8>;
qcom,msm-bus,num-paths = <1>;
@@ -885,6 +889,7 @@
reg-names = "core_mem", "dml_mem", "bam_mem";
qcom,bus-width = <4>;
+ qcom,cpu-dma-latency-us = <701>;
gpios = <&msmgpio 44 0>, /* CLK */
<&msmgpio 43 0>, /* CMD */
<&msmgpio 42 0>, /* DATA0 */
@@ -928,6 +933,7 @@
reg-names = "hc_mem", "core_mem";
qcom,bus-width = <4>;
+ qcom,cpu-dma-latency-us = <701>;
gpios = <&msmgpio 44 0>, /* CLK */
<&msmgpio 43 0>, /* CMD */
<&msmgpio 42 0>, /* DATA0 */
diff --git a/arch/arm/boot/dts/msm8610-camera-sensor-cdp-mtp.dtsi b/arch/arm/boot/dts/msm8610-camera-sensor-cdp-mtp.dtsi
index 7f4197f..07b5da3 100644
--- a/arch/arm/boot/dts/msm8610-camera-sensor-cdp-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8610-camera-sensor-cdp-mtp.dtsi
@@ -291,6 +291,9 @@
qcom,gpio-req-tbl-label = "CAMIF_MCLK",
"CAM_RESET1",
"CAM_STANDBY";
+ qcom,sensor-position = <0>;
+ qcom,sensor-mode = <0>;
+ qcom,cci-master = <0>;
status = "ok";
};
@@ -320,6 +323,9 @@
qcom,gpio-req-tbl-label = "CAMIF_MCLK",
"CAM_RESET",
"CAM_STANDBY";
+ qcom,sensor-position = <1>;
+ qcom,sensor-mode = <0>;
+ qcom,cci-master = <0>;
status = "ok";
};
diff --git a/arch/arm/boot/dts/msm8610.dtsi b/arch/arm/boot/dts/msm8610.dtsi
index 43cd7c6..53d2d4f 100644
--- a/arch/arm/boot/dts/msm8610.dtsi
+++ b/arch/arm/boot/dts/msm8610.dtsi
@@ -305,6 +305,7 @@
qcom,bus-width = <8>;
qcom,nonremovable;
qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
+ qcom,cpu-dma-latency-us = <701>;
status = "disabled";
};
@@ -338,6 +339,7 @@
qcom,xpc;
qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
qcom,current-limit = <800>;
+ qcom,cpu-dma-latency-us = <701>;
status = "disabled";
};
@@ -351,6 +353,7 @@
interrupt-names = "hc_irq", "pwr_irq";
qcom,bus-width = <8>;
+ qcom,cpu-dma-latency-us = <701>;
status = "disabled";
};
@@ -363,6 +366,7 @@
interrupt-names = "hc_irq", "pwr_irq";
qcom,bus-width = <4>;
+ qcom,cpu-dma-latency-us = <701>;
status = "disabled";
};
diff --git a/arch/arm/boot/dts/msm8612-qrd-camera-sensor.dtsi b/arch/arm/boot/dts/msm8612-qrd-camera-sensor.dtsi
index 4d50b36..551e007 100644
--- a/arch/arm/boot/dts/msm8612-qrd-camera-sensor.dtsi
+++ b/arch/arm/boot/dts/msm8612-qrd-camera-sensor.dtsi
@@ -121,6 +121,8 @@
qcom,gpio-req-tbl-label = "CAMIF_MCLK",
"CAM_RESET1",
"CAM_STANDBY";
+ qcom,sensor-position = <0>;
+ qcom,sensor-mode = <0>;
qcom,cci-master = <0>;
status = "ok";
};
@@ -149,6 +151,8 @@
qcom,gpio-req-tbl-label = "CAMIF_MCLK",
"CAM_RESET",
"CAM_STANDBY";
+ qcom,sensor-position = <1>;
+ qcom,sensor-mode = <0>;
qcom,cci-master = <0>;
status = "ok";
};
diff --git a/arch/arm/boot/dts/msm8926-camera-sensor-qrd.dtsi b/arch/arm/boot/dts/msm8926-camera-sensor-qrd.dtsi
index 8e053a9..6af862f 100644
--- a/arch/arm/boot/dts/msm8926-camera-sensor-qrd.dtsi
+++ b/arch/arm/boot/dts/msm8926-camera-sensor-qrd.dtsi
@@ -263,6 +263,8 @@
"CAM_RESET1",
"CAM_STANDBY",
"CAM_AF_PWDM";
+ qcom,sensor-position = <0>;
+ qcom,sensor-mode = <0>;
qcom,cci-master = <0>;
status = "ok";
};
@@ -296,6 +298,8 @@
"CAM_RESET",
"CAM_STANDBY",
"CAM_VDIG";
+ qcom,sensor-position = <1>;
+ qcom,sensor-mode = <0>;
qcom,cci-master = <0>;
status = "ok";
};
diff --git a/arch/arm/boot/dts/msm8926.dtsi b/arch/arm/boot/dts/msm8926.dtsi
index e866286..394f4a9 100644
--- a/arch/arm/boot/dts/msm8926.dtsi
+++ b/arch/arm/boot/dts/msm8926.dtsi
@@ -22,6 +22,11 @@
/ {
model = "Qualcomm MSM 8926";
compatible = "qcom,msm8926";
+
+};
+
+&qsecom_mem {
+ linux,memory-limit = <0x0>;
};
&soc {
diff --git a/arch/arm/boot/dts/msm8974-bus.dtsi b/arch/arm/boot/dts/msm8974-bus.dtsi
index b33b2b5..ba8b27e 100644
--- a/arch/arm/boot/dts/msm8974-bus.dtsi
+++ b/arch/arm/boot/dts/msm8974-bus.dtsi
@@ -1175,9 +1175,9 @@
qcom,prio-rd = <0>;
qcom,prio-wr = <0>;
qcom,mode-thresh = "Fixed";
- qcom,thresh = <2000000>;
+ qcom,thresh = <2000000 2456000>;
qcom,dual-conf;
- qcom,bimc,bw = <300000>;
+ qcom,bimc,bw = <300000 450000>;
qcom,bimc,gp = <5000>;
qcom,bimc,thmp = <50>;
};
@@ -1195,9 +1195,9 @@
qcom,prio-rd = <0>;
qcom,prio-wr = <0>;
qcom,mode-thresh = "Fixed";
- qcom,thresh = <2000000>;
+ qcom,thresh = <2000000 2456000>;
qcom,dual-conf;
- qcom,bimc,bw = <300000>;
+ qcom,bimc,bw = <300000 450000>;
qcom,bimc,gp = <5000>;
qcom,bimc,thmp = <50>;
};
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-cdp.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-cdp.dtsi
index bdc3bef..157c136 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-cdp.dtsi
@@ -186,6 +186,7 @@
qcom,csid-sd-index = <0>;
qcom,actuator-src = <&actuator0>;
qcom,vdd-cx-supply = <&pm8841_s2>;
+ qcom,mount-angle = <90>;
qcom,vdd-cx-name = "qcom,vdd-cx";
cam_vdig-supply = <&pm8941_l3>;
cam_vana-supply = <&pm8941_l17>;
@@ -208,6 +209,8 @@
qcom,gpio-req-tbl-label = "CAMIF_MCLK",
"CAM_RESET1",
"CAM_STANDBY";
+ qcom,sensor-position = <0>;
+ qcom,sensor-mode = <0>;
qcom,cci-master = <0>;
status = "ok";
};
@@ -219,6 +222,7 @@
qcom,csiphy-sd-index = <1>;
qcom,csid-sd-index = <0>;
qcom,vdd-cx-supply = <&pm8841_s2>;
+ qcom,mount-angle = <90>;
qcom,vdd-cx-name = "qcom,vdd-cx";
cam_vdig-supply = <&pm8941_l3>;
cam_vana-supply = <&pm8941_l17>;
@@ -240,6 +244,8 @@
qcom,gpio-req-tbl-label = "CAMIF_MCLK",
"CAM_RESET1",
"CAM_STANDBY";
+ qcom,sensor-position = <1>;
+ qcom,sensor-mode = <0>;
qcom,cci-master = <0>;
status = "ok";
};
@@ -250,6 +256,7 @@
reg = <0x2>;
qcom,csiphy-sd-index = <2>;
qcom,csid-sd-index = <2>;
+ qcom,mount-angle = <90>;
qcom,vdd-cx-supply = <&pm8841_s2>;
qcom,vdd-cx-name = "qcom,vdd-cx";
cam_vdig-supply = <&pm8941_l3>;
@@ -268,6 +275,8 @@
qcom,gpio-req-tbl-flags = <1 0>;
qcom,gpio-req-tbl-label = "CAMIF_MCLK",
"CAM_RESET1";
+ qcom,sensor-position = <1>;
+ qcom,sensor-mode = <0>;
qcom,cci-master = <0>;
status = "ok";
};
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-dragonboard.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-dragonboard.dtsi
index 43b0d75..7ca986d 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-dragonboard.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-dragonboard.dtsi
@@ -247,6 +247,8 @@
qcom,gpio-req-tbl-label = "CAMIF_MCLK",
"CAM_RESET1",
"CAM_STANDBY";
+ qcom,sensor-position = <1>;
+ qcom,sensor-mode = <0>;
qcom,cci-master = <0>;
status = "ok";
};
@@ -257,6 +259,7 @@
reg = <0x2>;
qcom,csiphy-sd-index = <2>;
qcom,csid-sd-index = <2>;
+ qcom,mount-angle = <180>;
qcom,vdd-cx-supply = <&pm8841_s2>;
qcom,vdd-cx-name = "qcom,vdd-cx";
cam_vdig-supply = <&pm8941_l3>;
@@ -278,6 +281,8 @@
qcom,gpio-req-tbl-flags = <1 0 0>;
qcom,gpio-req-tbl-label = "CAMIF_MCLK",
"CAM_RESET1";
+ qcom,sensor-position = <1>;
+ qcom,sensor-mode = <0>;
qcom,cci-master = <0>;
status = "ok";
};
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-fluid.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-fluid.dtsi
index 529d3ba..ecf5098 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-fluid.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-fluid.dtsi
@@ -221,6 +221,8 @@
qcom,gpio-req-tbl-label = "CAMIF_MCLK",
"CAM_RESET1",
"CAM_STANDBY";
+ qcom,sensor-position = <0>;
+ qcom,sensor-mode = <0>;
qcom,cci-master = <0>;
status = "ok";
};
@@ -251,6 +253,8 @@
qcom,gpio-req-tbl-flags = <1 0>;
qcom,gpio-req-tbl-label = "CAMIF_MCLK",
"CAM_RESET1";
+ qcom,sensor-position = <1>;
+ qcom,sensor-mode = <0>;
qcom,cci-master = <1>;
status = "ok";
};
@@ -261,6 +265,7 @@
reg = <0x2>;
qcom,csiphy-sd-index = <2>;
qcom,csid-sd-index = <2>;
+ qcom,mount-angle = <90>;
qcom,vdd-cx-supply = <&pm8841_s2>;
qcom,vdd-cx-name = "qcom,vdd-cx";
cam_vdig-supply = <&pm8941_l3>;
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi
index 854e8f7..1b70557 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi
@@ -209,6 +209,8 @@
qcom,gpio-req-tbl-label = "CAMIF_MCLK",
"CAM_RESET1",
"CAM_STANDBY";
+ qcom,sensor-position = <0>;
+ qcom,sensor-mode = <0>;
qcom,cci-master = <0>;
status = "ok";
};
@@ -238,6 +240,8 @@
qcom,gpio-req-tbl-flags = <1 0>;
qcom,gpio-req-tbl-label = "CAMIF_MCLK",
"CAM_RESET1";
+ qcom,sensor-position = <1>;
+ qcom,sensor-mode = <0>;
qcom,cci-master = <0>;
status = "ok";
};
@@ -248,6 +252,7 @@
reg = <0x2>;
qcom,csiphy-sd-index = <2>;
qcom,csid-sd-index = <2>;
+ qcom,mount-angle = <180>;
qcom,vdd-cx-supply = <&pm8841_s2>;
qcom,vdd-cx-name = "qcom,vdd-cx";
cam_vdig-supply = <&pm8941_l3>;
@@ -270,6 +275,8 @@
qcom,gpio-req-tbl-label = "CAMIF_MCLK",
"CAM_RESET1",
"CAM_STANDBY";
+ qcom,sensor-position = <1>;
+ qcom,sensor-mode = <0>;
qcom,cci-master = <0>;
status = "ok";
};
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-mtp.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-mtp.dtsi
index 59e1a7c..f3dff1a 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-mtp.dtsi
@@ -222,6 +222,8 @@
qcom,gpio-req-tbl-label = "CAMIF_MCLK",
"CAM_RESET1",
"CAM_STANDBY";
+ qcom,sensor-position = <0>;
+ qcom,sensor-mode = <0>;
qcom,cci-master = <0>;
status = "ok";
};
@@ -251,6 +253,8 @@
qcom,gpio-req-tbl-flags = <1 0>;
qcom,gpio-req-tbl-label = "CAMIF_MCLK",
"CAM_RESET1";
+ qcom,sensor-position = <1>;
+ qcom,sensor-mode = <0>;
qcom,cci-master = <0>;
status = "ok";
};
@@ -278,6 +282,8 @@
qcom,gpio-req-tbl-flags = <1 0>;
qcom,gpio-req-tbl-label = "CAMIF_MCLK",
"CAM_RESET1";
+ qcom,sensor-position = <1>;
+ qcom,sensor-mode = <0>;
qcom,cci-master = <1>;
status = "ok";
};
diff --git a/arch/arm/boot/dts/msm8974-mdss.dtsi b/arch/arm/boot/dts/msm8974-mdss.dtsi
index 0e72446..d83a235 100644
--- a/arch/arm/boot/dts/msm8974-mdss.dtsi
+++ b/arch/arm/boot/dts/msm8974-mdss.dtsi
@@ -50,6 +50,15 @@
qcom,mdss-pipe-rgb-xin-id = <1 5 9>;
qcom,mdss-pipe-dma-xin-id = <2 10>;
+ qcom,mdss-pipe-vig-clk-ctrl-offsets = <0x3AC 0 0>,
+ <0x3B4 0 0>,
+ <0x3BC 0 0>;
+ qcom,mdss-pipe-rgb-clk-ctrl-offsets = <0x3AC 4 8>,
+ <0x3B4 4 8>,
+ <0x3BC 4 8>;
+ qcom,mdss-pipe-dma-clk-ctrl-offsets = <0x3AC 8 12>,
+ <0x3B4 8 12>;
+
qcom,mdss-smp-data = <22 4096>;
qcom,mdss-ctl-off = <0x00000600 0x00000700 0x00000800
@@ -113,9 +122,10 @@
compatible = "qcom,mdss-dsi-ctrl";
label = "MDSS DSI CTRL->0";
cell-index = <0>;
- reg = <0xfd922800 0x600>,
+ reg = <0xfd922800 0x1f8>,
+ <0xfd922b00 0x2b0>,
<0xfdf30000 0x108>;
- reg-names = "dsi_phys", "mmss_misc_phys";
+ reg-names = "dsi_ctrl", "dsi_phy", "mmss_misc_phys";
vdd-supply = <&pm8941_l22>;
vddio-supply = <&pm8941_l12>;
vdda-supply = <&pm8941_l2>;
@@ -171,9 +181,10 @@
compatible = "qcom,mdss-dsi-ctrl";
label = "MDSS DSI CTRL->1";
cell-index = <1>;
- reg = <0xfd922e00 0x600>,
+ reg = <0xfd922e00 0x1f8>,
+ <0xfd923100 0x2b0>,
<0xfdf30000 0x108>;
- reg-names = "dsi_phys", "mmss_misc_phys";
+ reg-names = "dsi_ctrl", "dsi_phy", "mmss_misc_phys";
vdd-supply = <&pm8941_l22>;
vddio-supply = <&pm8941_l12>;
vdda-supply = <&pm8941_l2>;
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index da5474d..b3c7eb4 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -509,6 +509,7 @@
<78 512 800000 1600000>, /* 200 MB/s */
<78 512 2048000 4096000>; /* Max. bandwidth */
qcom,bus-bw-vectors-bps = <0 400000 20000000 25000000 50000000 100000000 200000000 4294967295>;
+ qcom,dat1-mpm-int = <42>;
status = "disable";
};
@@ -535,6 +536,7 @@
<81 512 800000 1600000>, /* 200 MB/s */
<81 512 2048000 4096000>; /* Max. bandwidth */
qcom,bus-bw-vectors-bps = <0 400000 20000000 25000000 50000000 100000000 200000000 4294967295>;
+ qcom,dat1-mpm-int = <44>;
status = "disable";
};
@@ -542,8 +544,17 @@
compatible = "qcom,sdhci-msm";
reg = <0xf9864900 0x11c>, <0xf9864000 0x800>;
reg-names = "hc_mem", "core_mem";
- interrupts = <0 127 0>, <0 224 0>;
- interrupt-names = "hc_irq", "pwr_irq";
+
+ #address-cells = <0>;
+ interrupt-parent = <&sdhc_3>;
+ interrupts = <0 1 2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0xffffffff>;
+ interrupt-map = <0 &intc 0 127 0
+ 1 &intc 0 224 0
+ 2 &msmgpio 37 0x8>;
+ interrupt-names = "hc_irq", "pwr_irq", "sdiowakeup_irq";
+
gpios = <&msmgpio 40 0>, /* CLK */
<&msmgpio 39 0>, /* CMD */
<&msmgpio 38 0>, /* DATA0 */
@@ -575,8 +586,17 @@
compatible = "qcom,sdhci-msm";
reg = <0xf98e4900 0x11c>, <0xf98e4000 0x800>;
reg-names = "hc_mem", "core_mem";
- interrupts = <0 129 0>, <0 227 0>;
- interrupt-names = "hc_irq", "pwr_irq";
+
+ #address-cells = <0>;
+ interrupt-parent = <&sdhc_4>;
+ interrupts = <0 1 2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0xffffffff>;
+ interrupt-map = <0 &intc 0 129 0
+ 1 &intc 0 227 0
+ 2 &msmgpio 95 0x8>;
+ interrupt-names = "hc_irq", "pwr_irq", "sdiowakeup_irq";
+
gpios = <&msmgpio 93 0>, /* CLK */
<&msmgpio 91 0>, /* CMD */
<&msmgpio 96 0>, /* DATA0 */
@@ -1823,6 +1843,11 @@
compatible = "qcom,msm-dai-q6-dev";
qcom,msm-dai-q6-dev-id = <32773>;
};
+
+ qcom,msm-dai-q6-incall-music-2-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <32770>;
+ };
};
qcom,msm-pri-auxpcm {
diff --git a/arch/arm/boot/dts/msm8974pro.dtsi b/arch/arm/boot/dts/msm8974pro.dtsi
index 813ecaa..ae0547f 100644
--- a/arch/arm/boot/dts/msm8974pro.dtsi
+++ b/arch/arm/boot/dts/msm8974pro.dtsi
@@ -1657,6 +1657,7 @@
};
&mdss_mdp {
+ qcom,max-bandwidth-low-kbps = <2750000>;
qcom,vbif-settings = <0x0004 0x00000001>;
qcom,mdss-wb-off = <0x00011100 0x00011500
diff --git a/arch/arm/boot/dts/msmsamarium-camera-sensor-cdp-interposer.dtsi b/arch/arm/boot/dts/msmsamarium-camera-sensor-cdp-interposer.dtsi
index 81640f8..0c25060 100644
--- a/arch/arm/boot/dts/msmsamarium-camera-sensor-cdp-interposer.dtsi
+++ b/arch/arm/boot/dts/msmsamarium-camera-sensor-cdp-interposer.dtsi
@@ -135,6 +135,8 @@
qcom,gpio-req-tbl-label = "CAMIF_MCLK",
"CAM_RESET1",
"CAM_STANDBY";
+ qcom,sensor-position = <0>;
+ qcom,sensor-mode = <0>;
qcom,cci-master = <0>;
status = "ok";
};
@@ -165,6 +167,8 @@
qcom,gpio-req-tbl-flags = <1 0>;
qcom,gpio-req-tbl-label = "CAMIF_MCLK2",
"CAM_XSHUTDOWN";
+ qcom,sensor-position = <1>;
+ qcom,sensor-mode = <0>;
qcom,cci-master = <0>;
status = "ok";
};
diff --git a/arch/arm/boot/dts/msmsamarium-camera-sensor-cdp.dtsi b/arch/arm/boot/dts/msmsamarium-camera-sensor-cdp.dtsi
index 27f4a99..637356b 100644
--- a/arch/arm/boot/dts/msmsamarium-camera-sensor-cdp.dtsi
+++ b/arch/arm/boot/dts/msmsamarium-camera-sensor-cdp.dtsi
@@ -136,6 +136,8 @@
qcom,gpio-req-tbl-label = "CAMIF_MCLK",
"CAM_RESET1",
"CAM_STANDBY";
+ qcom,sensor-position = <0>;
+ qcom,sensor-mode = <0>;
qcom,cci-master = <0>;
status = "ok";
};
@@ -165,6 +167,8 @@
qcom,gpio-req-tbl-flags = <1 0>;
qcom,gpio-req-tbl-label = "CAMIF_MCLK2",
"CAM_XSHUTDOWN";
+ qcom,sensor-position = <1>;
+ qcom,sensor-mode = <0>;
qcom,cci-master = <0>;
status = "ok";
};
diff --git a/arch/arm/configs/apq8084_defconfig b/arch/arm/configs/apq8084_defconfig
index 823e4f8..2f5e776 100644
--- a/arch/arm/configs/apq8084_defconfig
+++ b/arch/arm/configs/apq8084_defconfig
@@ -365,6 +365,7 @@
CONFIG_QPNP_CLKDIV=y
CONFIG_MSM_IOMMU_V1=y
CONFIG_IOMMU_PGTABLES_L2=y
+CONFIG_MSM_IOMMU_VBIF_CHECK=y
CONFIG_IOMMU_NON_SECURE=y
CONFIG_EXT2_FS=y
CONFIG_EXT2_FS_XATTR=y
diff --git a/arch/arm/configs/msm8226-perf_defconfig b/arch/arm/configs/msm8226-perf_defconfig
index 3dd9c55..ef7a5db 100644
--- a/arch/arm/configs/msm8226-perf_defconfig
+++ b/arch/arm/configs/msm8226-perf_defconfig
@@ -272,8 +272,8 @@
CONFIG_INPUT_MISC=y
CONFIG_INPUT_UINPUT=y
CONFIG_INPUT_GPIO=m
-CONFIG_SERIAL_MSM_HSL=y
-CONFIG_SERIAL_MSM_HSL_CONSOLE=y
+#CONFIG_SERIAL_MSM_HSL is not set
+#CONFIG_SERIAL_MSM_HSL_CONSOLE is not set
CONFIG_DIAG_CHAR=y
CONFIG_HW_RANDOM=y
CONFIG_HW_RANDOM_MSM=y
@@ -396,6 +396,7 @@
CONFIG_MMC_PARANOID_SD_INIT=y
CONFIG_MMC_BLOCK_MINORS=32
CONFIG_MMC_TEST=m
+CONFIG_MMC_BLOCK_DEFERRED_RESUME=y
CONFIG_MMC_BLOCK_TEST=m
CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_PLTFM=y
@@ -427,6 +428,7 @@
CONFIG_QPNP_VIBRATOR=y
CONFIG_QPNP_REVID=y
CONFIG_MSM_IOMMU_V1=y
+CONFIG_MSM_IOMMU_VBIF_CHECK=y
CONFIG_EXT2_FS=y
CONFIG_EXT2_FS_XATTR=y
CONFIG_EXT3_FS=y
diff --git a/arch/arm/configs/msm8226_defconfig b/arch/arm/configs/msm8226_defconfig
index 38171e6..d7719eb 100644
--- a/arch/arm/configs/msm8226_defconfig
+++ b/arch/arm/configs/msm8226_defconfig
@@ -333,6 +333,7 @@
CONFIG_MSMB_JPEG=y
CONFIG_MSM_VIDC_V4L2=y
CONFIG_MSM_WFD=y
+CONFIG_MSM_COMMON_LOG=y
# CONFIG_MEDIA_TUNER_SIMPLE is not set
# CONFIG_MEDIA_TUNER_TDA8290 is not set
# CONFIG_MEDIA_TUNER_TDA827X is not set
@@ -420,6 +421,7 @@
CONFIG_MMC_PARANOID_SD_INIT=y
CONFIG_MMC_BLOCK_MINORS=32
CONFIG_MMC_TEST=m
+CONFIG_MMC_BLOCK_DEFERRED_RESUME=y
CONFIG_MMC_BLOCK_TEST=m
CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_PLTFM=y
@@ -451,6 +453,7 @@
CONFIG_QPNP_VIBRATOR=y
CONFIG_QPNP_REVID=y
CONFIG_MSM_IOMMU_V1=y
+CONFIG_MSM_IOMMU_VBIF_CHECK=y
CONFIG_CORESIGHT=y
CONFIG_CORESIGHT_FUSE=y
CONFIG_CORESIGHT_TMC=y
diff --git a/arch/arm/configs/msm8610-perf_defconfig b/arch/arm/configs/msm8610-perf_defconfig
index ede654d..9c583e3 100644
--- a/arch/arm/configs/msm8610-perf_defconfig
+++ b/arch/arm/configs/msm8610-perf_defconfig
@@ -251,8 +251,8 @@
CONFIG_INPUT_UINPUT=y
CONFIG_INPUT_GPIO=m
# CONFIG_INPUT_MOUSEDEV is not set
-CONFIG_SERIAL_MSM_HSL=y
-CONFIG_SERIAL_MSM_HSL_CONSOLE=y
+#CONFIG_SERIAL_MSM_HSL is not set
+#CONFIG_SERIAL_MSM_HSL_CONSOLE is not set
CONFIG_DIAG_CHAR=y
CONFIG_HW_RANDOM=y
CONFIG_HW_RANDOM_MSM=y
@@ -361,6 +361,7 @@
CONFIG_MMC_PARANOID_SD_INIT=y
CONFIG_MMC_BLOCK_MINORS=32
CONFIG_MMC_TEST=m
+CONFIG_MMC_BLOCK_DEFERRED_RESUME=y
CONFIG_MMC_BLOCK_TEST=y
CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_PLTFM=y
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index 4f60013..6e86676 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -315,6 +315,7 @@
CONFIG_MSMB_JPEG=y
CONFIG_MSM_VIDC_V4L2=y
CONFIG_MSM_WFD=y
+CONFIG_MSM_COMMON_LOG=y
# CONFIG_MEDIA_TUNER_SIMPLE is not set
# CONFIG_MEDIA_TUNER_TDA8290 is not set
# CONFIG_MEDIA_TUNER_TDA827X is not set
@@ -383,6 +384,7 @@
CONFIG_MMC_PARANOID_SD_INIT=y
CONFIG_MMC_BLOCK_MINORS=32
CONFIG_MMC_TEST=m
+CONFIG_MMC_BLOCK_DEFERRED_RESUME=y
CONFIG_MMC_BLOCK_TEST=y
CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_PLTFM=y
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index 915b1c3..a749766 100755
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -298,8 +298,8 @@
CONFIG_INPUT_HBTP_INPUT=y
CONFIG_INPUT_UINPUT=y
CONFIG_SERIAL_MSM_HS=y
-CONFIG_SERIAL_MSM_HSL=y
-CONFIG_SERIAL_MSM_HSL_CONSOLE=y
+#CONFIG_SERIAL_MSM_HSL is not set
+#CONFIG_SERIAL_MSM_HSL_CONSOLE is not set
CONFIG_DIAG_CHAR=y
CONFIG_HW_RANDOM=y
CONFIG_HW_RANDOM_MSM=y
@@ -343,10 +343,6 @@
CONFIG_VIDEO_V4L2_SUBDEV_API=y
CONFIG_DVB_CORE=m
# CONFIG_MSM_CAMERA is not set
-CONFIG_MT9M114=y
-CONFIG_OV2720=y
-CONFIG_IMX135=y
-CONFIG_IMX132=y
CONFIG_MSM_CAMERA_SENSOR=y
CONFIG_MSM_EEPROM=y
CONFIG_MSM_CPP=y
@@ -355,7 +351,6 @@
CONFIG_MSM_CSIPHY=y
CONFIG_MSM_CSID=y
CONFIG_MSM_ISPIF=y
-CONFIG_S5K3L1YX=y
CONFIG_MSMB_CAMERA=y
CONFIG_MSMB_JPEG=y
CONFIG_MSM_VIDC_V4L2=y
@@ -463,6 +458,7 @@
CONFIG_QPNP_COINCELL=y
CONFIG_MSM_IOMMU_V1=y
CONFIG_IOMMU_PGTABLES_L2=y
+CONFIG_MSM_IOMMU_VBIF_CHECK=y
CONFIG_MOBICORE_SUPPORT=m
CONFIG_MOBICORE_API=m
CONFIG_BIF=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index e72e5ff..b002e45 100755
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -124,6 +124,7 @@
CONFIG_PACKET=y
CONFIG_UNIX=y
CONFIG_XFRM_USER=y
+CONFIG_NET_KEY=y
CONFIG_INET=y
CONFIG_IP_ADVANCED_ROUTER=y
CONFIG_IP_MULTIPLE_TABLES=y
@@ -132,6 +133,7 @@
CONFIG_IP_PNP_DHCP=y
CONFIG_INET_AH=y
CONFIG_INET_ESP=y
+CONFIG_INET_IPCOMP=y
# CONFIG_INET_XFRM_MODE_BEET is not set
# CONFIG_INET_LRO is not set
CONFIG_IPV6=y
@@ -222,6 +224,9 @@
CONFIG_IP6_NF_RAW=y
CONFIG_BRIDGE_NF_EBTABLES=y
CONFIG_BRIDGE_EBT_BROUTE=y
+CONFIG_L2TP=y
+CONFIG_L2TP_DEBUGFS=y
+CONFIG_L2TP_V3=y
CONFIG_BRIDGE=y
CONFIG_NET_SCHED=y
CONFIG_NET_SCH_HTB=y
@@ -283,6 +288,18 @@
CONFIG_KS8851=m
# CONFIG_MSM_RMNET is not set
CONFIG_MSM_RMNET_BAM=y
+CONFIG_PPP=y
+CONFIG_PPP_BSDCOMP=y
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_MPPE=y
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPPOE=y
+CONFIG_PPPOL2TP=y
+CONFIG_PPPOLAC=y
+CONFIG_PPPOPNS=y
+CONFIG_PPP_ASYNC=y
+CONFIG_PPP_SYNC_TTY=y
CONFIG_SLIP=y
CONFIG_SLIP_COMPRESSED=y
CONFIG_SLIP_MODE_SLIP6=y
@@ -350,10 +367,6 @@
CONFIG_VIDEO_V4L2_SUBDEV_API=y
CONFIG_DVB_CORE=m
# CONFIG_MSM_CAMERA is not set
-CONFIG_MT9M114=y
-CONFIG_OV2720=y
-CONFIG_IMX135=y
-CONFIG_IMX132=y
CONFIG_MSM_CAMERA_SENSOR=y
CONFIG_MSM_EEPROM=y
CONFIG_MSM_CPP=y
@@ -362,7 +375,6 @@
CONFIG_MSM_CSIPHY=y
CONFIG_MSM_CSID=y
CONFIG_MSM_ISPIF=y
-CONFIG_S5K3L1YX=y
CONFIG_MSMB_CAMERA=y
CONFIG_MSMB_JPEG=y
CONFIG_MSM_VIDC_V4L2=y
@@ -471,6 +483,7 @@
CONFIG_MSM_IOMMU_V1=y
CONFIG_MSM_IOMMU_PMON=y
CONFIG_IOMMU_PGTABLES_L2=y
+CONFIG_MSM_IOMMU_VBIF_CHECK=y
CONFIG_MOBICORE_SUPPORT=m
CONFIG_MOBICORE_API=m
CONFIG_CORESIGHT=y
diff --git a/arch/arm/kernel/arch_timer.c b/arch/arm/kernel/arch_timer.c
index 8c0a923..5a1ed75 100644
--- a/arch/arm/kernel/arch_timer.c
+++ b/arch/arm/kernel/arch_timer.c
@@ -493,8 +493,8 @@
clockevents_config_and_register(clk, arch_timer_rate,
0xf, 0x7fffffff);
- err = request_irq(arch_timer_spi, arch_timer_handler_mem, 0,
- "arch_timer", clk);
+ err = request_irq(arch_timer_spi, arch_timer_handler_mem,
+ IRQF_TIMER, "arch_timer", clk);
return err;
}
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 5bca467..4a6e6db 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -696,6 +696,7 @@
void smp_send_reschedule(int cpu)
{
+ BUG_ON(cpu_is_offline(cpu));
smp_cross_call(cpumask_of(cpu), IPI_RESCHEDULE);
}
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index b8444c1..6b551cd 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -3005,6 +3005,13 @@
help
Select if BLSP based UART Core v.14 or higher is present.
+config MSM_COMMON_LOG
+ bool "Use to export symbols for parsing memory dump"
+ help
+ Use this to export symbols to a memory dump table. This table
+ can be used by post analysis tools to extract information from
+ memory when device crashes.
+
config MSM_BOOT_STATS
bool "Use MSM boot stats reporting"
help
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 1c07e7d..5f7f0d9 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -100,6 +100,7 @@
obj-$(CONFIG_MACH_TROUT) += board-trout-rfkill.o
obj-$(CONFIG_MSM_BAM_DMUX) += bam_dmux.o
obj-$(CONFIG_MSM_SMD_LOGGING) += smem_log.o
+obj-$(CONFIG_MSM_COMMON_LOG) += common_log.o
obj-$(CONFIG_MSM_IPC_LOGGING) += ipc_logging.o
ifdef CONFIG_DEBUG_FS
obj-$(CONFIG_MSM_IPC_LOGGING) += ipc_logging_debug.o
diff --git a/arch/arm/mach-msm/board-8226-gpiomux.c b/arch/arm/mach-msm/board-8226-gpiomux.c
index fe7de31..08566bb 100644
--- a/arch/arm/mach-msm/board-8226-gpiomux.c
+++ b/arch/arm/mach-msm/board-8226-gpiomux.c
@@ -57,6 +57,42 @@
};
#endif
+static struct gpiomux_setting smsc_hub_act_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting smsc_hub_susp_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct msm_gpiomux_config smsc_hub_configs[] = {
+ {
+ .gpio = 114, /* reset_n */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &smsc_hub_act_cfg,
+ [GPIOMUX_SUSPENDED] = &smsc_hub_susp_cfg,
+ },
+ },
+ {
+ .gpio = 8, /* clk_en */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &smsc_hub_act_cfg,
+ [GPIOMUX_SUSPENDED] = &smsc_hub_susp_cfg,
+ },
+ },
+ {
+ .gpio = 9, /* int_n */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &smsc_hub_act_cfg,
+ [GPIOMUX_SUSPENDED] = &smsc_hub_susp_cfg,
+ },
+ },
+};
+
#define KS8851_IRQ_GPIO 115
#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
@@ -940,6 +976,9 @@
}
msm_gpiomux_install(msm_hsic_configs, ARRAY_SIZE(msm_hsic_configs));
#endif
+ if (machine_is_msm8926() && of_board_is_mtp())
+ msm_gpiomux_install(smsc_hub_configs,
+ ARRAY_SIZE(smsc_hub_configs));
}
static void wcnss_switch_to_gpio(void)
diff --git a/arch/arm/mach-msm/clock-8226.c b/arch/arm/mach-msm/clock-8226.c
index d1f8666..7a7c008 100644
--- a/arch/arm/mach-msm/clock-8226.c
+++ b/arch/arm/mach-msm/clock-8226.c
@@ -3146,8 +3146,11 @@
CLK_LOOKUP("bus_clk", gcc_mss_q6_bimc_axi_clk.c, "fc880000.qcom,mss"),
CLK_LOOKUP("iface_clk", gcc_mss_cfg_ahb_clk.c, "fc880000.qcom,mss"),
CLK_LOOKUP("mem_clk", gcc_boot_rom_ahb_clk.c, "fc880000.qcom,mss"),
+
/* NFC */
- CLK_LOOKUP("ref_clk", cxo_d1_a_pin.c, "2-000e"),
+ CLK_LOOKUP("ref_clk", cxo_d1_a_pin.c, ""),
+ CLK_LOOKUP("ref_clk", cxo_d1_pin.c, "2-000e"),
+
/* PIL-PRONTO */
CLK_LOOKUP("xo", cxo_pil_pronto_clk.c, "fb21b000.qcom,pronto"),
@@ -3407,13 +3410,13 @@
/* MM sensor clocks */
CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6f.qcom,camera"),
- CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "90.qcom,camera"),
+ CLK_LOOKUP("cam_src_clk", mclk1_clk_src.c, "90.qcom,camera"),
CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6d.qcom,camera"),
CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6a.qcom,camera"),
CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6c.qcom,camera"),
CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "20.qcom,camera"),
CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "6f.qcom,camera"),
- CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "90.qcom,camera"),
+ CLK_LOOKUP("cam_clk", camss_mclk1_clk.c, "90.qcom,camera"),
CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "6d.qcom,camera"),
CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "6a.qcom,camera"),
CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "6c.qcom,camera"),
diff --git a/arch/arm/mach-msm/clock-mdss-8974.c b/arch/arm/mach-msm/clock-mdss-8974.c
index 1fc7f1d..b63008f 100644
--- a/arch/arm/mach-msm/clock-mdss-8974.c
+++ b/arch/arm/mach-msm/clock-mdss-8974.c
@@ -1877,7 +1877,7 @@
if (vco_rate == 810000000) {
DSS_REG_W(mdss_edp_base, 0x0c, 0x18);
/* UNIPHY_PLL_LKDET_CFG2 */
- DSS_REG_W(mdss_edp_base, 0x64, 0x05);
+ DSS_REG_W(mdss_edp_base, 0x64, 0x0d);
/* UNIPHY_PLL_REFCLK_CFG */
DSS_REG_W(mdss_edp_base, 0x00, 0x00);
/* UNIPHY_PLL_SDM_CFG0 */
@@ -1899,7 +1899,7 @@
/* UNIPHY_PLL_SSC_CFG3 */
DSS_REG_W(mdss_edp_base, 0x58, 0x00);
/* UNIPHY_PLL_CAL_CFG0 */
- DSS_REG_W(mdss_edp_base, 0x6c, 0x0a);
+ DSS_REG_W(mdss_edp_base, 0x6c, 0x12);
/* UNIPHY_PLL_CAL_CFG2 */
DSS_REG_W(mdss_edp_base, 0x74, 0x01);
/* UNIPHY_PLL_CAL_CFG6 */
@@ -1924,7 +1924,7 @@
DSS_REG_W(mdss_edp_base, 0x28, 0x00);
} else if (vco_rate == 1350000000) {
/* UNIPHY_PLL_LKDET_CFG2 */
- DSS_REG_W(mdss_edp_base, 0x64, 0x05);
+ DSS_REG_W(mdss_edp_base, 0x64, 0x0d);
/* UNIPHY_PLL_REFCLK_CFG */
DSS_REG_W(mdss_edp_base, 0x00, 0x01);
/* UNIPHY_PLL_SDM_CFG0 */
@@ -1946,7 +1946,7 @@
/* UNIPHY_PLL_SSC_CFG3 */
DSS_REG_W(mdss_edp_base, 0x58, 0x00);
/* UNIPHY_PLL_CAL_CFG0 */
- DSS_REG_W(mdss_edp_base, 0x6c, 0x0a);
+ DSS_REG_W(mdss_edp_base, 0x6c, 0x12);
/* UNIPHY_PLL_CAL_CFG2 */
DSS_REG_W(mdss_edp_base, 0x74, 0x01);
/* UNIPHY_PLL_CAL_CFG6 */
diff --git a/arch/arm/mach-msm/common_log.c b/arch/arm/mach-msm/common_log.c
new file mode 100644
index 0000000..9491d9a
--- /dev/null
+++ b/arch/arm/mach-msm/common_log.c
@@ -0,0 +1,44 @@
+/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/kallsyms.h>
+#include <mach/msm_memory_dump.h>
+
+static void __init common_log_register(void)
+{
+ struct msm_client_dump dump;
+ char **log_bufp;
+ uint32_t *log_buf_lenp;
+
+ log_bufp = (char **)kallsyms_lookup_name("log_buf");
+ log_buf_lenp = (uint32_t *)kallsyms_lookup_name("log_buf_len");
+ if (!log_bufp || !log_buf_lenp) {
+ pr_err("common_log_register: Symbol log_buf not found!\n");
+ return;
+ }
+ dump.id = MSM_LOG_BUF;
+ dump.start_addr = virt_to_phys(*log_bufp);
+ dump.end_addr = virt_to_phys(*log_bufp + *log_buf_lenp);
+ if (msm_dump_table_register(&dump))
+ pr_err("common_log_register: Could not register log_bug.\n");
+}
+
+static int __init msm_common_log_init(void)
+{
+ common_log_register();
+ return 0;
+}
+late_initcall(msm_common_log_init);
diff --git a/arch/arm/mach-msm/cpr-regulator.c b/arch/arm/mach-msm/cpr-regulator.c
index d952f82..d15da59f 100644
--- a/arch/arm/mach-msm/cpr-regulator.c
+++ b/arch/arm/mach-msm/cpr-regulator.c
@@ -96,6 +96,8 @@
/* RBCPR Result status Register */
#define REG_RBCPR_RESULT_0 0xA0
+#define RBCPR_RESULT0_BUSY_SHIFT 19
+#define RBCPR_RESULT0_BUSY_MASK BIT(RBCPR_RESULT0_BUSY_SHIFT)
#define RBCPR_RESULT0_ERROR_STEPS_SHIFT 2
#define RBCPR_RESULT0_ERROR_STEPS_BITS 4
#define RBCPR_RESULT0_ERROR_STEPS_MASK ((1<<RBCPR_RESULT0_ERROR_STEPS_BITS)-1)
@@ -388,6 +390,22 @@
cpr_ctl_modify(cpr_vreg, RBCPR_CTL_LOOP_EN, 0);
}
+static bool cpr_ctl_is_enabled(struct cpr_regulator *cpr_vreg)
+{
+ u32 reg_val;
+
+ reg_val = cpr_read(cpr_vreg, REG_RBCPR_CTL);
+ return reg_val & RBCPR_CTL_LOOP_EN;
+}
+
+static bool cpr_ctl_is_busy(struct cpr_regulator *cpr_vreg)
+{
+ u32 reg_val;
+
+ reg_val = cpr_read(cpr_vreg, REG_RBCPR_RESULT_0);
+ return reg_val & RBCPR_RESULT0_BUSY_MASK;
+}
+
static void cpr_corner_save(struct cpr_regulator *cpr_vreg, int corner)
{
cpr_vreg->save_ctl[corner] = cpr_read(cpr_vreg, REG_RBCPR_CTL);
@@ -732,7 +750,13 @@
cpr_debug_irq("IRQ_STATUS = 0x%02X\n", reg_val);
- if (!cpr_is_allowed(cpr_vreg)) {
+ if (!cpr_ctl_is_enabled(cpr_vreg)) {
+ cpr_debug_irq("CPR is disabled\n");
+ goto _exit;
+ } else if (cpr_ctl_is_busy(cpr_vreg)) {
+ cpr_debug_irq("CPR measurement is not ready\n");
+ goto _exit;
+ } else if (!cpr_is_allowed(cpr_vreg)) {
reg_val = cpr_read(cpr_vreg, REG_RBCPR_CTL);
pr_err("Interrupt broken? RBCPR_CTL = 0x%02X\n", reg_val);
goto _exit;
@@ -897,7 +921,6 @@
mutex_lock(&cpr_vreg->cpr_mutex);
cpr_ctl_disable(cpr_vreg);
- disable_irq(cpr_vreg->cpr_irq);
cpr_irq_clr(cpr_vreg);
@@ -917,7 +940,6 @@
cpr_vreg->is_cpr_suspended = false;
cpr_irq_clr(cpr_vreg);
- enable_irq(cpr_vreg->cpr_irq);
cpr_ctl_enable(cpr_vreg, cpr_vreg->corner);
mutex_unlock(&cpr_vreg->cpr_mutex);
diff --git a/arch/arm/mach-msm/include/mach/iommu.h b/arch/arm/mach-msm/include/mach/iommu.h
index c4db727..0f69a7b 100644
--- a/arch/arm/mach-msm/include/mach/iommu.h
+++ b/arch/arm/mach-msm/include/mach/iommu.h
@@ -86,6 +86,7 @@
* struct msm_iommu_drvdata - A single IOMMU hardware instance
* @base: IOMMU config port base address (VA)
* @glb_base: IOMMU config port base address for global register space (VA)
+ * @phys_base: IOMMU physical base address.
* @ncb The number of contexts on this IOMMU
* @irq: Interrupt number
* @clk: The bus clock for this IOMMU hardware instance
@@ -108,6 +109,7 @@
*/
struct msm_iommu_drvdata {
void __iomem *base;
+ phys_addr_t phys_base;
void __iomem *glb_base;
int ncb;
int ttbr_split;
diff --git a/arch/arm/mach-msm/include/mach/iommu_hw-v1.h b/arch/arm/mach-msm/include/mach/iommu_hw-v1.h
index 04cd441..4509092 100644
--- a/arch/arm/mach-msm/include/mach/iommu_hw-v1.h
+++ b/arch/arm/mach-msm/include/mach/iommu_hw-v1.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -16,17 +16,19 @@
#define CTX_SHIFT 12
#define CTX_OFFSET 0x8000
-#define GET_GLOBAL_REG(reg, base) (readl_relaxed((base) + (reg)))
-#define GET_CTX_REG(reg, base, ctx) \
- (readl_relaxed((base) + CTX_OFFSET + (reg) + ((ctx) << CTX_SHIFT)))
-#define GET_CTX_REG_L(reg, base, ctx) \
- (readll_relaxed((base) + CTX_OFFSET + (reg) + ((ctx) << CTX_SHIFT)))
+#define CTX_REG(reg, base, ctx) \
+ ((base) + CTX_OFFSET + (reg) + ((ctx) << CTX_SHIFT))
+#define GLB_REG(reg, base) \
+ ((base) + (reg))
+
+#define GET_GLOBAL_REG(reg, base) (readl_relaxed(GLB_REG(reg, base)))
+#define GET_CTX_REG(reg, base, ctx) (readl_relaxed(CTX_REG(reg, base, ctx)))
+#define GET_CTX_REG_L(reg, base, ctx) (readll_relaxed(CTX_REG(reg, base, ctx)))
#define SET_GLOBAL_REG(reg, base, val) writel_relaxed((val), ((base) + (reg)))
#define SET_CTX_REG(reg, base, ctx, val) \
- writel_relaxed((val), \
- ((base) + CTX_OFFSET + (reg) + ((ctx) << CTX_SHIFT)))
+ writel_relaxed((val), (CTX_REG(reg, base, ctx)))
/* Wrappers for numbered registers */
#define SET_GLOBAL_REG_N(b, n, r, v) SET_GLOBAL_REG((b), ((r) + (n << 2)), (v))
@@ -150,6 +152,11 @@
SET_GLOBAL_FIELD(b, MICRO_MMU_CTRL, HALT_REQ, v)
#define GET_MICRO_MMU_CTRL_IDLE(b) \
GET_GLOBAL_FIELD(b, MICRO_MMU_CTRL, IDLE)
+#define SET_MICRO_MMU_CTRL_RESERVED(b, v) \
+ SET_GLOBAL_FIELD(b, MICRO_MMU_CTRL, RESERVED, v)
+
+#define MMU_CTRL_IDLE (MICRO_MMU_CTRL_IDLE_MASK << MICRO_MMU_CTRL_IDLE_SHIFT)
+
#define SET_PREDICTIONDIS0(b, v) SET_GLOBAL_REG(PREDICTIONDIS0, (b), (v))
#define SET_PREDICTIONDIS1(b, v) SET_GLOBAL_REG(PREDICTIONDIS1, (b), (v))
#define SET_S1L1BFBLP0(b, v) SET_GLOBAL_REG(S1L1BFBLP0, (b), (v))
diff --git a/arch/arm/mach-msm/include/mach/msm_memory_dump.h b/arch/arm/mach-msm/include/mach/msm_memory_dump.h
index 89df485..13f54bf 100644
--- a/arch/arm/mach-msm/include/mach/msm_memory_dump.h
+++ b/arch/arm/mach-msm/include/mach/msm_memory_dump.h
@@ -27,6 +27,7 @@
MSM_ETM3_REG,
MSM_TMC0_REG, /* TMC_ETR */
MSM_TMC1_REG, /* TMC_ETF */
+ MSM_LOG_BUF,
MAX_NUM_CLIENTS,
};
diff --git a/arch/arm/mach-msm/krait-regulator.c b/arch/arm/mach-msm/krait-regulator.c
index a291b90..b0a1a7c 100644
--- a/arch/arm/mach-msm/krait-regulator.c
+++ b/arch/arm/mach-msm/krait-regulator.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2014, 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
@@ -708,8 +708,10 @@
static int switch_to_using_ldo(struct krait_power_vreg *kvreg)
{
- if (kvreg->mode == LDO_MODE
- && get_krait_ldo_uv(kvreg) == kvreg->uV - kvreg->ldo_delta_uV)
+ int uV = kvreg->uV - kvreg->ldo_delta_uV;
+ int ldo_uV = DIV_ROUND_UP(uV, KRAIT_LDO_STEP) * KRAIT_LDO_STEP;
+
+ if (kvreg->mode == LDO_MODE && get_krait_ldo_uv(kvreg) == ldo_uV)
return 0;
return smp_call_function_single(kvreg->cpu_num,
diff --git a/arch/arm/mach-msm/lpm_levels.c b/arch/arm/mach-msm/lpm_levels.c
index defcd43..bd28131 100644
--- a/arch/arm/mach-msm/lpm_levels.c
+++ b/arch/arm/mach-msm/lpm_levels.c
@@ -546,11 +546,11 @@
if (!dev->cpu && msm_rpm_waiting_for_ack())
break;
- if ((next_wakeup_us >> 10) > pwr->latency_us) {
+ if ((next_wakeup_us >> 10) > pwr->time_overhead_us) {
power = pwr->ss_power;
} else {
power = pwr->ss_power;
- power -= (pwr->latency_us * pwr->ss_power)
+ power -= (pwr->time_overhead_us * pwr->ss_power)
/ next_wakeup_us;
power += pwr->energy_overhead / next_wakeup_us;
}
diff --git a/arch/arm/mach-msm/mpm-of.c b/arch/arm/mach-msm/mpm-of.c
index 1fbd077..f1bf64f 100644
--- a/arch/arm/mach-msm/mpm-of.c
+++ b/arch/arm/mach-msm/mpm-of.c
@@ -531,6 +531,7 @@
void msm_mpm_exit_sleep(bool from_idle)
{
unsigned long pending;
+ uint32_t *enabled_intr;
int i;
int k;
@@ -539,12 +540,16 @@
return;
}
+ enabled_intr = from_idle ? msm_mpm_enabled_irq :
+ msm_mpm_wake_irq;
+
for (i = 0; i < MSM_MPM_REG_WIDTH; i++) {
pending = msm_mpm_read(MSM_MPM_REG_STATUS, i);
+ pending &= enabled_intr[i];
if (MSM_MPM_DEBUG_PENDING_IRQ & msm_mpm_debug_mask)
- pr_info("%s: pending.%d: 0x%08lx", __func__,
- i, pending);
+ pr_info("%s: enabled_intr pending.%d: 0x%08x 0x%08lx\n",
+ __func__, i, enabled_intr[i], pending);
k = find_first_bit(&pending, 32);
while (k < 32) {
@@ -678,7 +683,8 @@
return -ENXIO;
}
ret = devm_request_irq(&pdev->dev, dev->mpm_ipc_irq, msm_mpm_irq,
- IRQF_TRIGGER_RISING, pdev->name, msm_mpm_irq);
+ IRQF_TRIGGER_RISING | IRQF_NO_SUSPEND, pdev->name,
+ msm_mpm_irq);
if (ret) {
pr_info("%s(): request_irq failed errno: %d\n", __func__, ret);
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c b/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c
index 5747f79..8cb3cf3 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c
@@ -1828,6 +1828,53 @@
set_qos_mode(baddr, mas_index, 0, 0, 0);
}
+static void bimc_set_static_qos_bw(struct msm_bus_bimc_info *binfo,
+ int mport, struct msm_bus_bimc_qos_bw *qbw)
+{
+ int32_t bw_mbps, thh = 0, thm, thl, gc;
+ int32_t gp;
+ u64 temp;
+
+ if (binfo->qos_freq == 0) {
+ MSM_BUS_DBG("Zero QoS Frequency\n");
+ return;
+ }
+
+ if (!(qbw->bw && qbw->ws)) {
+ MSM_BUS_DBG("No QoS Bandwidth or Window size\n");
+ return;
+ }
+
+ /* Convert bandwidth to MBPS */
+ temp = qbw->bw;
+ bimc_div(&temp, 1000000);
+ bw_mbps = temp;
+
+ /* Grant period in clock cycles
+ * Grant period from bandwidth structure
+ * is in nano seconds, QoS freq is in KHz.
+ * Divide by 1000 to get clock cycles */
+ gp = (binfo->qos_freq * qbw->gp) / (1000 * NSEC_PER_USEC);
+
+ /* Grant count = BW in MBps * Grant period
+ * in micro seconds */
+ gc = bw_mbps * (qbw->gp / NSEC_PER_USEC);
+
+ /* Medium threshold = -((Medium Threshold percentage *
+ * Grant count) / 100) */
+ thm = -((qbw->thmp * gc) / 100);
+ qbw->thm = thm;
+
+ /* Low threshold = -(Grant count) */
+ thl = -gc;
+ qbw->thl = thl;
+
+ MSM_BUS_DBG("%s: BKE parameters: gp %d, gc %d, thm %d thl %d thh %d",
+ __func__, gp, gc, thm, thl, thh);
+
+ set_qos_bw_regs(binfo->base, mport, thh, thm, thl, gp, gc);
+}
+
static void msm_bus_bimc_config_master(
struct msm_bus_fabric_registration *fab_pdata,
struct msm_bus_inode_info *info,
@@ -1835,6 +1882,7 @@
{
int mode, i, ports;
struct msm_bus_bimc_info *binfo;
+ uint64_t bw = 0;
binfo = (struct msm_bus_bimc_info *)fab_pdata->hw_data;
ports = info->node_info->num_mports;
@@ -1843,11 +1891,17 @@
* Here check the details of dual configuration.
* Take actions based on different modes.
* Check for threshold if limiter mode, etc.
- */
- if (req_clk > info->node_info->th)
- mode = info->node_info->mode_thresh;
- else
+ */
+
+ if (req_clk <= info->node_info->th[0]) {
mode = info->node_info->mode;
+ bw = info->node_info->bimc_bw[0];
+ } else if ((info->node_info->num_thresh > 1) &&
+ (req_clk <= info->node_info->th[1])) {
+ mode = info->node_info->mode;
+ bw = info->node_info->bimc_bw[1];
+ } else
+ mode = info->node_info->mode_thresh;
switch (mode) {
case BIMC_QOS_MODE_BYPASS:
@@ -1858,9 +1912,24 @@
break;
case BIMC_QOS_MODE_REGULATOR:
case BIMC_QOS_MODE_LIMITER:
- for (i = 0; i < ports; i++)
+ for (i = 0; i < ports; i++) {
+ /* If not in fixed mode, update bandwidth */
+ if ((info->node_info->cur_lim_bw != bw)
+ && (mode != BIMC_QOS_MODE_FIXED)) {
+ struct msm_bus_bimc_qos_bw qbw;
+ qbw.ws = info->node_info->ws;
+ qbw.bw = bw;
+ qbw.gp = info->node_info->bimc_gp;
+ qbw.thmp = info->node_info->bimc_thmp;
+ bimc_set_static_qos_bw(binfo,
+ info->node_info->qport[i], &qbw);
+ info->node_info->cur_lim_bw = bw;
+ MSM_BUS_DBG("%s: Qos is %d reqclk %llu bw %llu",
+ __func__, mode, req_clk, bw);
+ }
bke_switch(binfo->base, info->node_info->qport[i],
BKE_ON, mode);
+ }
break;
default:
break;
@@ -1964,52 +2033,6 @@
return 0;
}
-static void bimc_set_static_qos_bw(struct msm_bus_bimc_info *binfo,
- int mport, struct msm_bus_bimc_qos_bw *qbw)
-{
- int32_t bw_mbps, thh = 0, thm, thl, gc;
- int32_t gp;
- u64 temp;
-
- if (binfo->qos_freq == 0) {
- MSM_BUS_DBG("Zero QoS Frequency\n");
- return;
- }
-
- if (!(qbw->bw && qbw->ws)) {
- MSM_BUS_DBG("No QoS Bandwidth or Window size\n");
- return;
- }
-
- /* Convert bandwidth to MBPS */
- temp = qbw->bw;
- bimc_div(&temp, 1000000);
- bw_mbps = temp;
-
- /* Grant period in clock cycles
- * Grant period from bandwidth structure
- * is in nano seconds, QoS freq is in KHz.
- * Divide by 1000 to get clock cycles */
- gp = (binfo->qos_freq * qbw->gp) / (1000 * NSEC_PER_USEC);
-
- /* Grant count = BW in MBps * Grant period
- * in micro seconds */
- gc = bw_mbps * (qbw->gp / NSEC_PER_USEC);
-
- /* Medium threshold = -((Medium Threshold percentage *
- * Grant count) / 100) */
- thm = -((qbw->thmp * gc) / 100);
- qbw->thm = thm;
-
- /* Low threshold = -(Grant count) */
- thl = -gc;
- qbw->thl = thl;
-
- MSM_BUS_DBG("%s: BKE parameters: gp %d, gc %d, thm %d thl %d thh %d",
- __func__, gp, gc, thm, thl, thh);
-
- set_qos_bw_regs(binfo->base, mport, thh, thm, thl, gp, gc);
-}
static void bimc_init_mas_reg(struct msm_bus_bimc_info *binfo,
struct msm_bus_inode_info *info,
@@ -2048,7 +2071,7 @@
if (mode != BIMC_QOS_MODE_FIXED) {
struct msm_bus_bimc_qos_bw qbw;
qbw.ws = info->node_info->ws;
- qbw.bw = info->node_info->bimc_bw;
+ qbw.bw = info->node_info->bimc_bw[0];
qbw.gp = info->node_info->bimc_gp;
qbw.thmp = info->node_info->bimc_thmp;
bimc_set_static_qos_bw(binfo,
@@ -2081,9 +2104,11 @@
* If the master supports dual configuration,
* configure registers for both modes
*/
- if (info->node_info->dual_conf)
+ if (info->node_info->dual_conf) {
bimc_init_mas_reg(binfo, info, qmode,
info->node_info->mode_thresh);
+ info->node_info->cur_lim_bw = 0;
+ }
bimc_init_mas_reg(binfo, info, qmode, info->node_info->mode);
return 0;
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 7e4a513..557bcca 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_core.h
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_core.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2014 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -82,10 +82,12 @@
unsigned int prio_wr;
unsigned int prio1;
unsigned int prio0;
- u64 th;
+ unsigned int num_thresh;
+ u64 *th;
+ u64 cur_lim_bw;
unsigned int mode_thresh;
bool dual_conf;
- u64 bimc_bw;
+ u64 *bimc_bw;
u32 bimc_gp;
u32 bimc_thmp;
const char *name;
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_of.c b/arch/arm/mach-msm/msm_bus/msm_bus_of.c
index 52195c7..f857920 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_of.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_of.c
@@ -271,6 +271,54 @@
return NULL;
}
+static u64 *get_th_params(struct platform_device *pdev,
+ const struct device_node *node, const char *prop,
+ int *nports)
+{
+ int size = 0, ret;
+ u64 *ret_arr = NULL;
+ int *arr = NULL;
+ int i;
+
+ if (of_get_property(node, prop, &size)) {
+ *nports = size / sizeof(int);
+ } else {
+ pr_debug("Property %s not available\n", prop);
+ *nports = 0;
+ return NULL;
+ }
+
+ ret_arr = devm_kzalloc(&pdev->dev, (*nports * sizeof(u64)),
+ GFP_KERNEL);
+ arr = kzalloc(size, GFP_KERNEL);
+ if ((size > 0) && (ZERO_OR_NULL_PTR(arr)
+ || ZERO_OR_NULL_PTR(ret_arr))) {
+ pr_err("Error: Failed to alloc mem for %s\n", prop);
+ return NULL;
+ }
+
+ ret = of_property_read_u32_array(node, prop, (u32 *)arr, *nports);
+ if (ret) {
+ pr_err("Error in reading property: %s\n", prop);
+ goto err;
+ }
+
+ for (i = 0; i < *nports; i++)
+ ret_arr[i] = (uint64_t)KBTOB(arr[i]);
+
+ MSM_BUS_DBG("%s: num entries %d prop %s", __func__, *nports, prop);
+
+ for (i = 0; i < *nports; i++)
+ MSM_BUS_DBG("Th %d val %llu", i, ret_arr[i]);
+
+ kfree(arr);
+ return ret_arr;
+err:
+ devm_kfree(&pdev->dev, arr);
+ devm_kfree(&pdev->dev, ret_arr);
+ return NULL;
+}
+
static struct msm_bus_node_info *get_nodes(struct device_node *of_node,
struct platform_device *pdev,
struct msm_bus_fabric_registration *pdata)
@@ -278,7 +326,7 @@
struct msm_bus_node_info *info;
struct device_node *child_node = NULL;
int i = 0, ret;
- u32 temp;
+ int num_bw = 0;
for_each_child_of_node(of_node, child_node) {
i++;
@@ -353,36 +401,29 @@
of_property_read_u32(child_node, "qcom,buswidth",
&info[i].buswidth);
of_property_read_u32(child_node, "qcom,ws", &info[i].ws);
- ret = of_property_read_u32(child_node, "qcom,thresh",
- &temp);
- if (!ret)
- info[i].th = (uint64_t)KBTOB(temp);
- ret = of_property_read_u32(child_node, "qcom,bimc,bw",
- &temp);
- if (!ret)
- info[i].bimc_bw = (uint64_t)KBTOB(temp);
+ info[i].dual_conf =
+ of_property_read_bool(child_node, "qcom,dual-conf");
+
+
+ info[i].th = get_th_params(pdev, child_node, "qcom,thresh",
+ &info[i].num_thresh);
+
+ info[i].bimc_bw = get_th_params(pdev, child_node,
+ "qcom,bimc,bw", &num_bw);
+
+ if (num_bw != info[i].num_thresh) {
+ pr_err("%s:num_bw %d must equal num_thresh %d",
+ __func__, num_bw, info[i].num_thresh);
+ pr_err("%s:Err setting up dual conf for %s",
+ __func__, info[i].name);
+ goto err;
+ }
of_property_read_u32(child_node, "qcom,bimc,gp",
&info[i].bimc_gp);
of_property_read_u32(child_node, "qcom,bimc,thmp",
&info[i].bimc_thmp);
- ret = of_property_read_string(child_node, "qcom,mode",
- &sel_str);
- if (ret)
- info[i].mode = 0;
- else {
- ret = get_num(mode_sel_name, sel_str);
- if (ret < 0) {
- pr_err("Unknown mode :%s\n", sel_str);
- goto err;
- }
-
- info[i].mode = ret;
- }
-
- info[i].dual_conf =
- of_property_read_bool(child_node, "qcom,dual-conf");
ret = of_property_read_string(child_node, "qcom,mode-thresh",
&sel_str);
@@ -397,7 +438,21 @@
info[i].mode_thresh = ret;
MSM_BUS_DBG("AXI: THreshold mode set: %d\n",
- info[i].mode_thresh);
+ info[i].mode_thresh);
+ }
+
+ ret = of_property_read_string(child_node, "qcom,mode",
+ &sel_str);
+ if (ret)
+ info[i].mode = 0;
+ else {
+ ret = get_num(mode_sel_name, sel_str);
+ if (ret < 0) {
+ pr_err("Unknown mode :%s\n", sel_str);
+ goto err;
+ }
+
+ info[i].mode = ret;
}
ret = of_property_read_string(child_node, "qcom,perm-mode",
diff --git a/drivers/base/dma-contiguous.c b/drivers/base/dma-contiguous.c
index 606383a..0395681 100644
--- a/drivers/base/dma-contiguous.c
+++ b/drivers/base/dma-contiguous.c
@@ -47,6 +47,7 @@
unsigned long base_pfn;
unsigned long count;
unsigned long *bitmap;
+ struct mutex lock;
};
static DEFINE_MUTEX(cma_mutex);
@@ -191,6 +192,7 @@
ret = cma_activate_area(base_pfn, count);
if (ret)
goto error;
+ mutex_init(&cma->lock);
pr_debug("%s: returned %p\n", __func__, (void *)cma);
return cma;
@@ -212,6 +214,7 @@
unsigned long len;
__be32 *prop;
char *name;
+ phys_addr_t limit = MEMBLOCK_ALLOC_ANYWHERE;
if (!of_get_flat_dt_prop(node, "linux,contiguous-region", NULL))
return 0;
@@ -225,9 +228,13 @@
name = of_get_flat_dt_prop(node, "label", NULL);
- pr_info("Found %s, memory base %lx, size %ld MiB\n", uname,
- (unsigned long)base, (unsigned long)size / SZ_1M);
- dma_contiguous_reserve_area(size, &base, MEMBLOCK_ALLOC_ANYWHERE, name);
+ prop = of_get_flat_dt_prop(node, "linux,memory-limit", NULL);
+ if (prop)
+ limit = be32_to_cpu(prop[0]);
+
+ pr_info("Found %s, memory base %lx, size %ld MiB, limit %pa\n", uname,
+ (unsigned long)base, (unsigned long)size / SZ_1M, &limit);
+ dma_contiguous_reserve_area(size, &base, limit, name);
return 0;
}
@@ -454,6 +461,13 @@
return cma->base_pfn << PAGE_SHIFT;
}
+static void clear_cma_bitmap(struct cma *cma, unsigned long pfn, int count)
+{
+ mutex_lock(&cma->lock);
+ bitmap_clear(cma->bitmap, pfn - cma->base_pfn, count);
+ mutex_unlock(&cma->lock);
+}
+
/**
* dma_alloc_from_contiguous() - allocate pages from contiguous area
* @dev: Pointer to device for which the allocation is performed.
@@ -488,23 +502,35 @@
mask = (1 << align) - 1;
- mutex_lock(&cma_mutex);
for (;;) {
+ mutex_lock(&cma->lock);
pageno = bitmap_find_next_zero_area(cma->bitmap, cma->count,
start, count, mask);
- if (pageno >= cma->count)
+ if (pageno >= cma->count) {
+ mutex_unlock(&cma_mutex);
break;
+ }
+ bitmap_set(cma->bitmap, pageno, count);
+ /*
+ * It's safe to drop the lock here. We've marked this region for
+ * our exclusive use. If the migration fails we will take the
+ * lock again and unmark it.
+ */
+ mutex_unlock(&cma->lock);
pfn = cma->base_pfn + pageno;
+ mutex_lock(&cma_mutex);
ret = alloc_contig_range(pfn, pfn + count, MIGRATE_CMA);
+ mutex_unlock(&cma_mutex);
if (ret == 0) {
- bitmap_set(cma->bitmap, pageno, count);
page = pfn_to_page(pfn);
break;
} else if (ret != -EBUSY) {
+ clear_cma_bitmap(cma, pfn, count);
break;
}
+ clear_cma_bitmap(cma, pfn, count);
tries++;
trace_dma_alloc_contiguous_retry(tries);
@@ -514,7 +540,6 @@
start = pageno + mask + 1;
}
- mutex_unlock(&cma_mutex);
pr_debug("%s(): returned %p\n", __func__, page);
return page;
}
@@ -548,9 +573,7 @@
VM_BUG_ON(pfn + count > cma->base_pfn + cma->count);
free_contig_range(pfn, count);
- mutex_lock(&cma_mutex);
- bitmap_clear(cma->bitmap, pfn - cma->base_pfn, count);
- mutex_unlock(&cma_mutex);
+ clear_cma_bitmap(cma, pfn, count);
return true;
}
diff --git a/drivers/gpio/gpio-msm-common.c b/drivers/gpio/gpio-msm-common.c
index 3d18809..4a69cd5 100644
--- a/drivers/gpio/gpio-msm-common.c
+++ b/drivers/gpio/gpio-msm-common.c
@@ -112,16 +112,11 @@
* @wake_irqs: a bitmap for tracking which interrupt lines are enabled
* as wakeup sources. When the device is suspended, interrupts which are
* not wakeup sources are disabled.
- *
- * @dual_edge_irqs: a bitmap used to track which irqs are configured
- * as dual-edge, as this is not supported by the hardware and requires
- * some special handling in the driver.
*/
struct msm_gpio_dev {
struct gpio_chip gpio_chip;
unsigned long *enabled_irqs;
unsigned long *wake_irqs;
- unsigned long *dual_edge_irqs;
struct irq_domain *domain;
};
@@ -219,64 +214,11 @@
},
};
-static void switch_mpm_config(struct irq_data *d, unsigned val)
-{
- /* switch the configuration in the mpm as well */
- if (!msm_gpio_irq_extn.irq_set_type)
- return;
-
- if (val)
- msm_gpio_irq_extn.irq_set_type(d, IRQF_TRIGGER_FALLING);
- else
- msm_gpio_irq_extn.irq_set_type(d, IRQF_TRIGGER_RISING);
-}
-
-/* For dual-edge interrupts in software, since the hardware has no
- * such support:
- *
- * At appropriate moments, this function may be called to flip the polarity
- * settings of both-edge irq lines to try and catch the next edge.
- *
- * The attempt is considered successful if:
- * - the status bit goes high, indicating that an edge was caught, or
- * - the input value of the gpio doesn't change during the attempt.
- * If the value changes twice during the process, that would cause the first
- * test to fail but would force the second, as two opposite
- * transitions would cause a detection no matter the polarity setting.
- *
- * The do-loop tries to sledge-hammer closed the timing hole between
- * the initial value-read and the polarity-write - if the line value changes
- * during that window, an interrupt is lost, the new polarity setting is
- * incorrect, and the first success test will fail, causing a retry.
- *
- * Algorithm comes from Google's msmgpio driver, see mach-msm/gpio.c.
- */
-static void msm_gpio_update_dual_edge_pos(struct irq_data *d, unsigned gpio)
-{
- int loop_limit = 100;
- unsigned val, val2, intstat;
-
- do {
- val = __msm_gpio_get_inout(gpio);
- __msm_gpio_set_polarity(gpio, val);
- val2 = __msm_gpio_get_inout(gpio);
- intstat = __msm_gpio_get_intr_status(gpio);
- if (intstat || val == val2) {
- switch_mpm_config(d, val);
- return;
- }
- } while (loop_limit-- > 0);
- pr_err("%s: dual-edge irq failed to stabilize, %#08x != %#08x\n",
- __func__, val, val2);
-}
-
static void msm_gpio_irq_ack(struct irq_data *d)
{
int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq);
__msm_gpio_set_intr_status(gpio);
- if (test_bit(gpio, msm_gpio.dual_edge_irqs))
- msm_gpio_update_dual_edge_pos(d, gpio);
mb();
}
@@ -327,29 +269,18 @@
spin_lock_irqsave(&tlmm_lock, irq_flags);
- if (flow_type & IRQ_TYPE_EDGE_BOTH) {
+ if (flow_type & IRQ_TYPE_EDGE_BOTH)
__irq_set_handler_locked(d->irq, handle_edge_irq);
- if ((flow_type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH)
- __set_bit(gpio, msm_gpio.dual_edge_irqs);
- else
- __clear_bit(gpio, msm_gpio.dual_edge_irqs);
- } else {
+ else
__irq_set_handler_locked(d->irq, handle_level_irq);
- __clear_bit(gpio, msm_gpio.dual_edge_irqs);
- }
__msm_gpio_set_intr_cfg_type(gpio, flow_type);
- if ((flow_type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH)
- msm_gpio_update_dual_edge_pos(d, gpio);
-
mb();
spin_unlock_irqrestore(&tlmm_lock, irq_flags);
- if ((flow_type & IRQ_TYPE_EDGE_BOTH) != IRQ_TYPE_EDGE_BOTH) {
- if (msm_gpio_irq_extn.irq_set_type)
- msm_gpio_irq_extn.irq_set_type(d, flow_type);
- }
+ if (msm_gpio_irq_extn.irq_set_type)
+ msm_gpio_irq_extn.irq_set_type(d, flow_type);
return 0;
}
@@ -609,17 +540,9 @@
, __func__);
return -ENOMEM;
}
- msm_gpio.dual_edge_irqs = devm_kzalloc(&pdev->dev, sizeof(unsigned long)
- * BITS_TO_LONGS(ngpio), GFP_KERNEL);
- if (!msm_gpio.dual_edge_irqs) {
- dev_err(&pdev->dev, "%s failed to allocated dual_edge_irqs bitmap\n"
- , __func__);
- return -ENOMEM;
- }
bitmap_zero(msm_gpio.enabled_irqs, ngpio);
bitmap_zero(msm_gpio.wake_irqs, ngpio);
- bitmap_zero(msm_gpio.dual_edge_irqs, ngpio);
ret = gpiochip_add(&msm_gpio.gpio_chip);
if (ret < 0)
return ret;
diff --git a/drivers/gpu/ion/ion_cma_secure_heap.c b/drivers/gpu/ion/ion_cma_secure_heap.c
index 0aef596..da68d05 100644
--- a/drivers/gpu/ion/ion_cma_secure_heap.c
+++ b/drivers/gpu/ion/ion_cma_secure_heap.c
@@ -444,6 +444,7 @@
ret = ion_secure_cma_alloc_from_pool(sheap, &info->phys, len);
if (ret) {
+retry:
ret = ion_secure_cma_add_to_pool(sheap, len);
if (ret) {
mutex_unlock(&sheap->alloc_lock);
@@ -453,10 +454,9 @@
ret = ion_secure_cma_alloc_from_pool(sheap, &info->phys, len);
if (ret) {
/*
- * We just added memory to the pool, we shouldn't be
- * failing to get memory
+ * Lost the race with the shrinker, try again
*/
- BUG();
+ goto retry;
}
}
mutex_unlock(&sheap->alloc_lock);
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 7a92fe6..695095f 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -1960,6 +1960,10 @@
for (i = 6; i < FT_DETECT_REGS_COUNT; i++)
ft_detect_regs[i] = 0;
+ /* turn on hang interrupt for a330v2 by default */
+ if (adreno_is_a330v2(adreno_dev))
+ set_bit(ADRENO_DEVICE_HANG_INTR, &adreno_dev->priv);
+
ret = adreno_perfcounter_init(device);
if (ret)
goto done;
@@ -2423,9 +2427,12 @@
if (tmp != adreno_dev->fast_hang_detect) {
if (adreno_dev->fast_hang_detect) {
- if (adreno_dev->gpudev->fault_detect_start)
+ if (adreno_dev->gpudev->fault_detect_start &&
+ !kgsl_active_count_get(&adreno_dev->dev)) {
adreno_dev->gpudev->fault_detect_start(
adreno_dev);
+ kgsl_active_count_put(&adreno_dev->dev);
+ }
} else {
if (adreno_dev->gpudev->fault_detect_stop)
adreno_dev->gpudev->fault_detect_stop(
@@ -2534,6 +2541,88 @@
return snprintf(buf, PAGE_SIZE, "%d\n", _wake_timeout);
}
+/**
+ * _ft_hang_intr_status_store - Routine to enable/disable h/w hang interrupt
+ * @dev: device ptr
+ * @attr: Device attribute
+ * @buf: value to write
+ * @count: size of the value to write
+ */
+static ssize_t _ft_hang_intr_status_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned int new_setting, old_setting;
+ struct kgsl_device *device = kgsl_device_from_dev(dev);
+ struct adreno_device *adreno_dev;
+ int ret;
+ if (device == NULL)
+ return 0;
+ adreno_dev = ADRENO_DEVICE(device);
+
+ mutex_lock(&device->mutex);
+ ret = _ft_sysfs_store(buf, count, &new_setting);
+ if (ret != count)
+ goto done;
+ if (new_setting)
+ new_setting = 1;
+ old_setting =
+ (test_bit(ADRENO_DEVICE_HANG_INTR, &adreno_dev->priv) ? 1 : 0);
+ if (new_setting != old_setting) {
+ if (new_setting)
+ set_bit(ADRENO_DEVICE_HANG_INTR, &adreno_dev->priv);
+ else
+ clear_bit(ADRENO_DEVICE_HANG_INTR, &adreno_dev->priv);
+ /* Set the new setting based on device state */
+ switch (device->state) {
+ case KGSL_STATE_NAP:
+ case KGSL_STATE_SLEEP:
+ kgsl_pwrctrl_wake(device, 0);
+ case KGSL_STATE_ACTIVE:
+ adreno_dev->gpudev->irq_control(adreno_dev, 1);
+ /*
+ * For following states setting will be picked up on device
+ * start. Still need them in switch statement to differentiate
+ * from default
+ */
+ case KGSL_STATE_SLUMBER:
+ case KGSL_STATE_SUSPEND:
+ break;
+ default:
+ ret = -EACCES;
+ /* reset back to old setting on error */
+ if (new_setting)
+ clear_bit(ADRENO_DEVICE_HANG_INTR,
+ &adreno_dev->priv);
+ else
+ set_bit(ADRENO_DEVICE_HANG_INTR,
+ &adreno_dev->priv);
+ goto done;
+ }
+ }
+done:
+ mutex_unlock(&device->mutex);
+ return ret;
+}
+
+/**
+ * _ft_hang_intr_status_show() - Routine to read hardware hang interrupt
+ * enablement
+ * @dev: device ptr
+ * @attr: Device attribute
+ * @buf: value read
+ */
+static ssize_t _ft_hang_intr_status_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct adreno_device *adreno_dev = _get_adreno_dev(dev);
+ if (adreno_dev == NULL)
+ return 0;
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ test_bit(ADRENO_DEVICE_HANG_INTR, &adreno_dev->priv) ? 1 : 0);
+}
+
#define FT_DEVICE_ATTR(name) \
DEVICE_ATTR(name, 0644, _ ## name ## _show, _ ## name ## _store);
@@ -2541,6 +2630,7 @@
FT_DEVICE_ATTR(ft_pagefault_policy);
FT_DEVICE_ATTR(ft_fast_hang_detect);
FT_DEVICE_ATTR(ft_long_ib_detect);
+FT_DEVICE_ATTR(ft_hang_intr_status);
static DEVICE_INT_ATTR(wake_nice, 0644, _wake_nice);
static FT_DEVICE_ATTR(wake_timeout);
@@ -2552,6 +2642,7 @@
&dev_attr_ft_long_ib_detect,
&dev_attr_wake_nice.attr,
&dev_attr_wake_timeout,
+ &dev_attr_ft_hang_intr_status,
NULL,
};
@@ -2786,7 +2877,7 @@
* Return true if the RBBM status register for the GPU type indicates that the
* hardware is idle
*/
-static bool adreno_hw_isidle(struct kgsl_device *device)
+bool adreno_hw_isidle(struct kgsl_device *device)
{
unsigned int reg_rbbm_status;
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
@@ -2899,6 +2990,12 @@
rptr = adreno_get_rptr(&adreno_dev->ringbuffer);
+ /*
+ * wptr is updated when we add commands to ringbuffer, add a barrier
+ * to make sure updated wptr is compared to rptr
+ */
+ smp_mb();
+
if (rptr == adreno_dev->ringbuffer.wptr)
return adreno_hw_isidle(device);
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index e2ea262..976a355 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -217,6 +217,7 @@
ADRENO_DEVICE_PWRON_FIXUP = 1,
ADRENO_DEVICE_INITIALIZED = 2,
ADRENO_DEVICE_STARTED = 3,
+ ADRENO_DEVICE_HANG_INTR = 4,
};
#define PERFCOUNTER_FLAG_NONE 0x0
@@ -341,6 +342,7 @@
ADRENO_REG_TC_CNTL_STATUS,
ADRENO_REG_TP0_CHICKEN,
ADRENO_REG_RBBM_RBBM_CTL,
+ ADRENO_REG_UCHE_INVALIDATE0,
ADRENO_REG_REGISTER_MAX,
};
@@ -413,7 +415,9 @@
#define KGSL_FT_SKIPFRAME 3
#define KGSL_FT_DISABLE 4
#define KGSL_FT_TEMP_DISABLE 5
-#define KGSL_FT_DEFAULT_POLICY (BIT(KGSL_FT_REPLAY) + BIT(KGSL_FT_SKIPIB))
+#define KGSL_FT_THROTTLE 6
+#define KGSL_FT_DEFAULT_POLICY (BIT(KGSL_FT_REPLAY) + BIT(KGSL_FT_SKIPIB) \
+ + BIT(KGSL_FT_THROTTLE))
/* This internal bit is used to skip the PM dump on replayed command batches */
#define KGSL_FT_SKIP_PMDUMP 31
@@ -431,7 +435,8 @@
{ BIT(KGSL_FT_SKIPIB), "skipib" }, \
{ BIT(KGSL_FT_SKIPFRAME), "skipframe" }, \
{ BIT(KGSL_FT_DISABLE), "disable" }, \
- { BIT(KGSL_FT_TEMP_DISABLE), "temp" }
+ { BIT(KGSL_FT_TEMP_DISABLE), "temp" }, \
+ { BIT(KGSL_FT_THROTTLE), "throttle"}
extern struct adreno_gpudev adreno_a2xx_gpudev;
extern struct adreno_gpudev adreno_a3xx_gpudev;
@@ -461,6 +466,7 @@
void adreno_coresight_remove(struct platform_device *pdev);
int adreno_coresight_init(struct platform_device *pdev);
+bool adreno_hw_isidle(struct kgsl_device *device);
int adreno_idle(struct kgsl_device *device);
bool adreno_isidle(struct kgsl_device *device);
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index eed11c3..2faa278 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -3039,6 +3039,25 @@
return 0;
}
+static void a3xx_fatal_err_callback(struct adreno_device *adreno_dev, int bit)
+{
+ struct kgsl_device *device = &adreno_dev->dev;
+ const char *err = "";
+
+ switch (bit) {
+ case A3XX_INT_MISC_HANG_DETECT:
+ err = "MISC: GPU hang detected\n";
+ break;
+ default:
+ return;
+ }
+ KGSL_DRV_CRIT(device, "%s\n", err);
+ kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
+
+ /* Trigger a fault in the dispatcher - this will effect a restart */
+ adreno_dispatcher_irq_fault(device);
+}
+
static void a3xx_err_callback(struct adreno_device *adreno_dev, int bit)
{
struct kgsl_device *device = &adreno_dev->dev;
@@ -3063,7 +3082,7 @@
/* Clear the error */
kgsl_regwrite(device, A3XX_RBBM_AHB_CMD, (1 << 3));
- goto done;
+ return;
}
case A3XX_INT_RBBM_REG_TIMEOUT:
err = "RBBM: AHB register timeout";
@@ -3100,14 +3119,10 @@
"CP | Protected mode error| %s | addr=%x\n",
reg & (1 << 24) ? "WRITE" : "READ",
(reg & 0x1FFFF) >> 2);
- goto done;
}
case A3XX_INT_CP_AHB_ERROR_HALT:
err = "ringbuffer AHB error interrupt";
break;
- case A3XX_INT_MISC_HANG_DETECT:
- err = "MISC: GPU hang detected";
- break;
case A3XX_INT_UCHE_OOB_ACCESS:
err = "UCHE: Out of bounds access";
break;
@@ -3115,11 +3130,6 @@
return;
}
KGSL_DRV_CRIT(device, "%s\n", err);
- kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
-
-done:
- /* Trigger a fault in the dispatcher - this will effect a restart */
- adreno_dispatcher_irq_fault(device);
}
static void a3xx_cp_callback(struct adreno_device *adreno_dev, int irq)
@@ -3561,7 +3571,7 @@
A3XX_IRQ_CALLBACK(a3xx_err_callback), /* 21 - CP_AHB_ERROR_FAULT */
A3XX_IRQ_CALLBACK(NULL), /* 22 - Unused */
A3XX_IRQ_CALLBACK(NULL), /* 23 - Unused */
- A3XX_IRQ_CALLBACK(NULL), /* 24 - MISC_HANG_DETECT */
+ A3XX_IRQ_CALLBACK(a3xx_fatal_err_callback),/* 24 - MISC_HANG_DETECT */
A3XX_IRQ_CALLBACK(a3xx_err_callback), /* 25 - UCHE_OOB_ACCESS */
/* 26 to 31 - Unused */
};
@@ -3602,7 +3612,9 @@
struct kgsl_device *device = &adreno_dev->dev;
if (state)
- kgsl_regwrite(device, A3XX_RBBM_INT_0_MASK, A3XX_INT_MASK);
+ kgsl_regwrite(device, A3XX_RBBM_INT_0_MASK, A3XX_INT_MASK |
+ (test_bit(ADRENO_DEVICE_HANG_INTR, &adreno_dev->priv) ?
+ (1 << A3XX_INT_MISC_HANG_DETECT) : 0));
else
kgsl_regwrite(device, A3XX_RBBM_INT_0_MASK, 0);
}
@@ -4193,9 +4205,12 @@
/* Turn on hang detection - this spews a lot of useful information
* into the RBBM registers on a hang */
-
- kgsl_regwrite(device, A3XX_RBBM_INTERFACE_HANG_INT_CTL,
- (1 << 16) | 0xFFF);
+ if (adreno_is_a330v2(adreno_dev))
+ kgsl_regwrite(device, A3XX_RBBM_INTERFACE_HANG_INT_CTL,
+ (1 << 31) | 0xFFFF);
+ else
+ kgsl_regwrite(device, A3XX_RBBM_INTERFACE_HANG_INT_CTL,
+ (1 << 16) | 0xFFF);
/* Enable 64-byte cacheline size. HW Default is 32-byte (0x000000E0). */
kgsl_regwrite(device, A3XX_UCHE_CACHE_MODE_CONTROL_REG, 0x00000001);
@@ -4577,6 +4592,8 @@
ADRENO_REG_DEFINE(ADRENO_REG_TC_CNTL_STATUS, REG_TC_CNTL_STATUS),
ADRENO_REG_DEFINE(ADRENO_REG_TP0_CHICKEN, REG_TP0_CHICKEN),
ADRENO_REG_DEFINE(ADRENO_REG_RBBM_RBBM_CTL, A3XX_RBBM_RBBM_CTL),
+ ADRENO_REG_DEFINE(ADRENO_REG_UCHE_INVALIDATE0,
+ A3XX_UCHE_CACHE_INVALIDATE0_REG),
};
struct adreno_reg_offsets a3xx_reg_offsets = {
diff --git a/drivers/gpu/msm/adreno_dispatch.c b/drivers/gpu/msm/adreno_dispatch.c
index 48d0210..7aae397 100644
--- a/drivers/gpu/msm/adreno_dispatch.c
+++ b/drivers/gpu/msm/adreno_dispatch.c
@@ -33,6 +33,15 @@
/* Number of command batches sent at a time from a single context */
static unsigned int _context_cmdbatch_burst = 5;
+/*
+ * GFT throttle parameters. If GFT recovered more than
+ * X times in Y ms invalidate the context and do not attempt recovery.
+ * X -> _fault_throttle_burst
+ * Y -> _fault_throttle_time
+ */
+static unsigned int _fault_throttle_time = 3000;
+static unsigned int _fault_throttle_burst = 3;
+
/* Number of command batches inflight in the ringbuffer at any time */
static unsigned int _dispatcher_inflight = 15;
@@ -78,15 +87,24 @@
static inline bool _isidle(struct kgsl_device *device)
{
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
- unsigned int ts;
+ unsigned int ts, i;
+
+ if (!kgsl_pwrctrl_isenabled(device))
+ goto ret;
ts = kgsl_readtimestamp(device, NULL, KGSL_TIMESTAMP_RETIRED);
- if (adreno_isidle(device) == true &&
- (ts >= adreno_dev->ringbuffer.global_ts))
- return true;
+ /* If GPU HW status is idle return true */
+ if (adreno_hw_isidle(device) ||
+ (ts == adreno_dev->ringbuffer.global_ts))
+ goto ret;
return false;
+
+ret:
+ for (i = 0; i < FT_DETECT_REGS_COUNT; i++)
+ fault_detect_regs[i] = 0;
+ return true;
}
/**
@@ -929,6 +947,12 @@
if (dispatcher->inflight == 0) {
KGSL_DRV_WARN(device,
"dispatcher_do_fault with 0 inflight commands\n");
+ /*
+ * For certain faults like h/w fault the interrupts are
+ * turned off, re-enable here
+ */
+ if (kgsl_pwrctrl_isenabled(device))
+ kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_ON);
return 0;
}
@@ -1015,6 +1039,35 @@
cmdbatch = replay[0];
/*
+ * If GFT recovered more than X times in Y ms invalidate the context
+ * and do not attempt recovery.
+ * Example: X==3 and Y==3000 ms, GPU hung at 500ms, 1700ms, 25000ms and
+ * 3000ms for the same context, we will not try FT and invalidate the
+ * context @3000ms because context triggered GFT more than 3 times in
+ * last 3 seconds. If a context caused recoverable GPU hangs
+ * where 1st and 4th gpu hang are more than 3 seconds apart we
+ * won't disable GFT and invalidate the context.
+ */
+ if (test_bit(KGSL_FT_THROTTLE, &cmdbatch->fault_policy)) {
+ if (time_after(jiffies, (cmdbatch->context->fault_time
+ + msecs_to_jiffies(_fault_throttle_time)))) {
+ cmdbatch->context->fault_time = jiffies;
+ cmdbatch->context->fault_count = 1;
+ } else {
+ cmdbatch->context->fault_count++;
+ if (cmdbatch->context->fault_count >
+ _fault_throttle_burst) {
+ set_bit(KGSL_FT_DISABLE,
+ &cmdbatch->fault_policy);
+ pr_fault(device, cmdbatch,
+ "gpu fault threshold exceeded %d faults in %d msecs\n",
+ _fault_throttle_burst,
+ _fault_throttle_time);
+ }
+ }
+ }
+
+ /*
* If FT is disabled for this cmdbatch invalidate immediately
*/
@@ -1628,6 +1681,10 @@
static DISPATCHER_UINT_ATTR(context_queue_wait, 0644, 0, _context_queue_wait);
static DISPATCHER_UINT_ATTR(fault_detect_interval, 0644, 0,
_fault_timer_interval);
+static DISPATCHER_UINT_ATTR(fault_throttle_time, 0644, 0,
+ _fault_throttle_time);
+static DISPATCHER_UINT_ATTR(fault_throttle_burst, 0644, 0,
+ _fault_throttle_burst);
static struct attribute *dispatcher_attrs[] = {
&dispatcher_attr_inflight.attr,
@@ -1636,6 +1693,8 @@
&dispatcher_attr_cmdbatch_timeout.attr,
&dispatcher_attr_context_queue_wait.attr,
&dispatcher_attr_fault_detect_interval.attr,
+ &dispatcher_attr_fault_throttle_time.attr,
+ &dispatcher_attr_fault_throttle_burst.attr,
NULL,
};
diff --git a/drivers/gpu/msm/adreno_drawctxt.c b/drivers/gpu/msm/adreno_drawctxt.c
index 4db045a..136456a 100644
--- a/drivers/gpu/msm/adreno_drawctxt.c
+++ b/drivers/gpu/msm/adreno_drawctxt.c
@@ -607,7 +607,7 @@
struct adreno_context *context)
{
struct kgsl_device *device;
- unsigned int cmds[5];
+ unsigned int cmds[8];
if (adreno_dev == NULL || context == NULL)
return -EINVAL;
@@ -621,8 +621,14 @@
cmds[3] = device->memstore.gpuaddr +
KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL, current_context);
cmds[4] = context->base.id;
+ /* Flush the UCHE for new context */
+ cmds[5] = cp_type0_packet(
+ adreno_getreg(adreno_dev, ADRENO_REG_UCHE_INVALIDATE0), 2);
+ cmds[6] = 0;
+ if (adreno_is_a3xx(adreno_dev))
+ cmds[7] = 0x90000000;
return adreno_ringbuffer_issuecmds(device, context,
- KGSL_CMD_FLAGS_NONE, cmds, 5);
+ KGSL_CMD_FLAGS_NONE, cmds, 8);
}
diff --git a/drivers/gpu/msm/kgsl_debugfs.c b/drivers/gpu/msm/kgsl_debugfs.c
index 318b10d..2d833e4 100644
--- a/drivers/gpu/msm/kgsl_debugfs.c
+++ b/drivers/gpu/msm/kgsl_debugfs.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2008-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2002,2008-2014, 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
@@ -260,8 +260,10 @@
kgsl_get_memory_usage(usage, sizeof(usage), m->flags);
- seq_printf(s, "%08x %08lx %8d %5d %5s %10s %16s %5d\n",
- m->gpuaddr, m->useraddr, m->size, entry->id, flags,
+ seq_printf(s, "%pK %pK %8zd %5d %5s %10s %16s %5d\n",
+ (unsigned long *) m->gpuaddr,
+ (unsigned long *) m->useraddr,
+ m->size, entry->id, flags,
memtype_str(entry->memtype), usage, m->sglen);
}
@@ -347,7 +349,7 @@
* So if debugfs is disabled in kernel, return as
* success.
*/
- dentry = debugfs_create_file("mem", 0400, private->debug_root, private,
+ dentry = debugfs_create_file("mem", 0444, private->debug_root, private,
&process_mem_fops);
if (IS_ERR(dentry)) {
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index 98fd731..fc4b77e 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -349,6 +349,8 @@
* is set.
* @flags: flags from userspace controlling the behavior of this context
* @pwr_constraint: power constraint from userspace for this context
+ * @fault_count: number of times gpu hanged in last _context_throttle_time ms
+ * @fault_time: time of the first gpu hang in last _context_throttle_time ms
*/
struct kgsl_context {
struct kref refcount;
@@ -367,6 +369,8 @@
unsigned int pagefault_ts;
unsigned int flags;
struct kgsl_pwr_constraint pwr_constraint;
+ unsigned int fault_count;
+ unsigned long fault_time;
};
/**
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index e87c670..69b953f 100755
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -641,16 +641,18 @@
phys_addr_t pt_base)
{
struct kgsl_iommu_pt *iommu_pt = pt ? pt->priv : NULL;
- phys_addr_t domain_ptbase = iommu_pt ?
- iommu_get_pt_base_addr(iommu_pt->domain) : 0;
+ phys_addr_t domain_ptbase;
- /* Only compare the valid address bits of the pt_base */
- domain_ptbase &= KGSL_IOMMU_CTX_TTBR0_ADDR_MASK;
+ if (iommu_pt == NULL)
+ return 0;
+
+ domain_ptbase = iommu_get_pt_base_addr(iommu_pt->domain)
+ & KGSL_IOMMU_CTX_TTBR0_ADDR_MASK;
pt_base &= KGSL_IOMMU_CTX_TTBR0_ADDR_MASK;
- return domain_ptbase && pt_base &&
- (domain_ptbase == pt_base);
+ return (domain_ptbase == pt_base);
+
}
/*
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 656d7e2..fb9bdb1 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -78,7 +78,7 @@
};
static void kgsl_pwrctrl_clk(struct kgsl_device *device, int state,
- int requested_state);
+ int requested_state);
static void kgsl_pwrctrl_axi(struct kgsl_device *device, int state);
static void kgsl_pwrctrl_pwrrail(struct kgsl_device *device, int state);
@@ -883,7 +883,7 @@
}
}
-static void kgsl_pwrctrl_clk(struct kgsl_device *device, int state,
+void kgsl_pwrctrl_clk(struct kgsl_device *device, int state,
int requested_state)
{
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
diff --git a/drivers/hwmon/qpnp-adc-common.c b/drivers/hwmon/qpnp-adc-common.c
index 7bc8773..37a11d2 100644
--- a/drivers/hwmon/qpnp-adc-common.c
+++ b/drivers/hwmon/qpnp-adc-common.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2014, 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
@@ -986,6 +986,92 @@
}
EXPORT_SYMBOL(qpnp_vadc_check_result);
+int qpnp_adc_get_revid_version(struct device *dev)
+{
+ struct pmic_revid_data *revid_data;
+ struct device_node *revid_dev_node;
+
+ revid_dev_node = of_parse_phandle(dev->of_node,
+ "qcom,pmic-revid", 0);
+ if (!revid_dev_node) {
+ pr_debug("Missing qcom,pmic-revid property\n");
+ return -EINVAL;
+ }
+
+ revid_data = get_revid_data(revid_dev_node);
+ if (IS_ERR(revid_data)) {
+ pr_debug("revid error rc = %ld\n", PTR_ERR(revid_data));
+ return -EINVAL;
+ }
+
+ if ((revid_data->rev1 == PM8941_V3P1_REV1) &&
+ (revid_data->rev2 == PM8941_V3P1_REV2) &&
+ (revid_data->rev3 == PM8941_V3P1_REV3) &&
+ (revid_data->rev4 == PM8941_V3P1_REV4) &&
+ (revid_data->pmic_type == PM8941_V3P1_TYPE) &&
+ (revid_data->pmic_subtype == PM8941_V3P1_SUBTYPE))
+ return QPNP_REV_ID_8941_3_1;
+ else if ((revid_data->rev1 == PM8941_V3P0_REV1) &&
+ (revid_data->rev2 == PM8941_V3P0_REV2) &&
+ (revid_data->rev3 == PM8941_V3P0_REV3) &&
+ (revid_data->rev4 == PM8941_V3P0_REV4) &&
+ (revid_data->pmic_type == PM8941_V3P0_TYPE) &&
+ (revid_data->pmic_subtype == PM8941_V3P0_SUBTYPE))
+ return QPNP_REV_ID_8941_3_0;
+ else if ((revid_data->rev1 == PM8941_V2P0_REV1) &&
+ (revid_data->rev2 == PM8941_V2P0_REV2) &&
+ (revid_data->rev3 == PM8941_V2P0_REV3) &&
+ (revid_data->rev4 == PM8941_V2P0_REV4) &&
+ (revid_data->pmic_type == PM8941_V2P0_TYPE) &&
+ (revid_data->pmic_subtype == PM8941_V2P0_SUBTYPE))
+ return QPNP_REV_ID_8941_2_0;
+ else if ((revid_data->rev1 == PM8226_V2P2_REV1) &&
+ (revid_data->rev2 == PM8226_V2P2_REV2) &&
+ (revid_data->rev3 == PM8226_V2P2_REV3) &&
+ (revid_data->rev4 == PM8226_V2P2_REV4) &&
+ (revid_data->pmic_type == PM8226_V2P2_TYPE) &&
+ (revid_data->pmic_subtype == PM8226_V2P2_SUBTYPE))
+ return QPNP_REV_ID_8026_2_2;
+ else if ((revid_data->rev1 == PM8226_V2P1_REV1) &&
+ (revid_data->rev2 == PM8226_V2P1_REV2) &&
+ (revid_data->rev3 == PM8226_V2P1_REV3) &&
+ (revid_data->rev4 == PM8226_V2P1_REV4) &&
+ (revid_data->pmic_type == PM8226_V2P1_TYPE) &&
+ (revid_data->pmic_subtype == PM8226_V2P1_SUBTYPE))
+ return QPNP_REV_ID_8026_2_1;
+ else if ((revid_data->rev1 == PM8226_V2P0_REV1) &&
+ (revid_data->rev2 == PM8226_V2P0_REV2) &&
+ (revid_data->rev3 == PM8226_V2P0_REV3) &&
+ (revid_data->rev4 == PM8226_V2P0_REV4) &&
+ (revid_data->pmic_type == PM8226_V2P0_TYPE) &&
+ (revid_data->pmic_subtype == PM8226_V2P0_SUBTYPE))
+ return QPNP_REV_ID_8026_2_0;
+ else if ((revid_data->rev1 == PM8226_V1P0_REV1) &&
+ (revid_data->rev2 == PM8226_V1P0_REV2) &&
+ (revid_data->rev3 == PM8226_V1P0_REV3) &&
+ (revid_data->rev4 == PM8226_V1P0_REV4) &&
+ (revid_data->pmic_type == PM8226_V1P0_TYPE) &&
+ (revid_data->pmic_subtype == PM8226_V1P0_SUBTYPE))
+ return QPNP_REV_ID_8026_1_0;
+ else if ((revid_data->rev1 == PM8110_V1P0_REV1) &&
+ (revid_data->rev2 == PM8110_V1P0_REV2) &&
+ (revid_data->rev3 == PM8110_V1P0_REV3) &&
+ (revid_data->rev4 == PM8110_V1P0_REV4) &&
+ (revid_data->pmic_type == PM8110_V1P0_TYPE) &&
+ (revid_data->pmic_subtype == PM8110_V1P0_SUBTYPE))
+ return QPNP_REV_ID_8110_1_0;
+ else if ((revid_data->rev1 == PM8110_V2P0_REV1) &&
+ (revid_data->rev2 == PM8110_V2P0_REV2) &&
+ (revid_data->rev3 == PM8110_V2P0_REV3) &&
+ (revid_data->rev4 == PM8110_V2P0_REV4) &&
+ (revid_data->pmic_type == PM8110_V2P0_TYPE) &&
+ (revid_data->pmic_subtype == PM8110_V2P0_SUBTYPE))
+ return QPNP_REV_ID_8110_2_0;
+ else
+ return -EINVAL;
+}
+EXPORT_SYMBOL(qpnp_adc_get_revid_version);
+
int32_t qpnp_adc_get_devicetree_data(struct spmi_device *spmi,
struct qpnp_adc_drv *adc_qpnp)
{
diff --git a/drivers/hwmon/qpnp-adc-current.c b/drivers/hwmon/qpnp-adc-current.c
index 44da261..ec6d8ec 100644
--- a/drivers/hwmon/qpnp-adc-current.c
+++ b/drivers/hwmon/qpnp-adc-current.c
@@ -340,48 +340,8 @@
return 0;
}
-#define QPNP_IADC_PM8941_3_1_REV2 3
-#define QPNP_IADC_PM8941_3_1_REV3 2
-#define QPNP_IADC_PM8026_1_REV2 1
-#define QPNP_IADC_PM8026_1_REV3 2
-#define QPNP_IADC_PM8026_2_REV2 4
-#define QPNP_IADC_PM8026_2_REV3 2
-#define QPNP_IADC_PM8110_1_REV2 2
-#define QPNP_IADC_PM8110_1_REV3 2
-
-#define QPNP_IADC_REV_ID_8941_3_1 1
-#define QPNP_IADC_REV_ID_8026_1_0 2
-#define QPNP_IADC_REV_ID_8026_2_0 3
-#define QPNP_IADC_REV_ID_8110_1_0 4
-
-static void qpnp_temp_comp_version_check(struct qpnp_iadc_chip *iadc,
- int32_t *version)
-{
- if ((iadc->iadc_comp.revision_dig_major ==
- QPNP_IADC_PM8941_3_1_REV2) &&
- (iadc->iadc_comp.revision_ana_minor ==
- QPNP_IADC_PM8941_3_1_REV3))
- *version = QPNP_IADC_REV_ID_8941_3_1;
- else if ((iadc->iadc_comp.revision_dig_major ==
- QPNP_IADC_PM8026_1_REV2) &&
- (iadc->iadc_comp.revision_ana_minor ==
- QPNP_IADC_PM8026_1_REV3))
- *version = QPNP_IADC_REV_ID_8026_1_0;
- else if ((iadc->iadc_comp.revision_dig_major ==
- QPNP_IADC_PM8026_2_REV2) &&
- (iadc->iadc_comp.revision_ana_minor ==
- QPNP_IADC_PM8026_2_REV3))
- *version = QPNP_IADC_REV_ID_8026_2_0;
- else if ((iadc->iadc_comp.revision_dig_major ==
- QPNP_IADC_PM8110_1_REV2) &&
- (iadc->iadc_comp.revision_ana_minor ==
- QPNP_IADC_PM8110_1_REV3))
- *version = QPNP_IADC_REV_ID_8110_1_0;
- else
- *version = -EINVAL;
-
- return;
-}
+#define QPNP_IADC_PM8026_2_REV2 4
+#define QPNP_IADC_PM8026_2_REV3 2
#define QPNP_COEFF_1 969000
#define QPNP_COEFF_2 32
@@ -408,15 +368,19 @@
#define QPNP_COEFF_22 5000000
#define QPNP_COEFF_23 3722500
#define QPNP_COEFF_24 84
+#define QPNP_COEFF_25 33
+#define QPNP_COEFF_26 22
+#define QPNP_COEFF_27 53
+#define QPNP_COEFF_28 48
static int32_t qpnp_iadc_comp(int64_t *result, struct qpnp_iadc_chip *iadc,
int64_t die_temp)
{
int64_t temp_var = 0, sys_gain_coeff = 0, old;
int32_t coeff_a = 0, coeff_b = 0;
- int32_t version;
+ int version = 0;
- qpnp_temp_comp_version_check(iadc, &version);
+ version = qpnp_adc_get_revid_version(iadc->dev);
if (version == -EINVAL)
return 0;
@@ -431,7 +395,7 @@
iadc->iadc_comp.sys_gain;
switch (version) {
- case QPNP_IADC_REV_ID_8941_3_1:
+ case QPNP_REV_ID_8941_3_1:
switch (iadc->iadc_comp.id) {
case COMP_ID_GF:
if (!iadc->iadc_comp.ext_rsense) {
@@ -470,7 +434,60 @@
break;
}
break;
- case QPNP_IADC_REV_ID_8026_1_0:
+ case QPNP_REV_ID_8026_2_1:
+ case QPNP_REV_ID_8026_2_2:
+ /* pm8026 rev 2.1 and 2.2 */
+ switch (iadc->iadc_comp.id) {
+ case COMP_ID_GF:
+ if (!iadc->iadc_comp.ext_rsense) {
+ /* internal rsense */
+ if (*result < 0) {
+ /* charge */
+ coeff_a = 0;
+ coeff_b = 0;
+ } else {
+ coeff_a = QPNP_COEFF_25;
+ coeff_b = 0;
+ }
+ } else {
+ if (*result < 0) {
+ /* charge */
+ coeff_a = 0;
+ coeff_b = 0;
+ } else {
+ /* discharge */
+ coeff_a = 0;
+ coeff_b = 0;
+ }
+ }
+ break;
+ case COMP_ID_TSMC:
+ default:
+ if (!iadc->iadc_comp.ext_rsense) {
+ /* internal rsense */
+ if (*result < 0) {
+ /* charge */
+ coeff_a = 0;
+ coeff_b = 0;
+ } else {
+ coeff_a = QPNP_COEFF_26;
+ coeff_b = 0;
+ }
+ } else {
+ if (*result < 0) {
+ /* charge */
+ coeff_a = 0;
+ coeff_b = 0;
+ } else {
+ /* discharge */
+ coeff_a = 0;
+ coeff_b = 0;
+ }
+ }
+ break;
+ }
+ break;
+ case QPNP_REV_ID_8026_1_0:
/* pm8026 rev 1.0 */
switch (iadc->iadc_comp.id) {
case COMP_ID_GF:
@@ -522,7 +539,7 @@
break;
}
break;
- case QPNP_IADC_REV_ID_8110_1_0:
+ case QPNP_REV_ID_8110_1_0:
/* pm8110 rev 1.0 */
switch (iadc->iadc_comp.id) {
case COMP_ID_GF:
@@ -554,8 +571,41 @@
break;
}
break;
+ case QPNP_REV_ID_8110_2_0:
+ die_temp -= 25000;
+ /* pm8110 rev 2.0 */
+ switch (iadc->iadc_comp.id) {
+ case COMP_ID_GF:
+ if (!iadc->iadc_comp.ext_rsense) {
+ /* internal rsense */
+ if (*result < 0) {
+ /* charge */
+ coeff_a = 0;
+ coeff_b = 0;
+ } else {
+ coeff_a = QPNP_COEFF_27;
+ coeff_b = 0;
+ }
+ }
+ break;
+ case COMP_ID_SMIC:
+ default:
+ if (!iadc->iadc_comp.ext_rsense) {
+ /* internal rsense */
+ if (*result < 0) {
+ /* charge */
+ coeff_a = 0;
+ coeff_b = 0;
+ } else {
+ coeff_a = QPNP_COEFF_28;
+ coeff_b = 0;
+ }
+ }
+ break;
+ }
+ break;
default:
- case QPNP_IADC_REV_ID_8026_2_0:
+ case QPNP_REV_ID_8026_2_0:
/* pm8026 rev 1.0 */
coeff_a = 0;
coeff_b = 0;
@@ -578,7 +628,8 @@
temp_var = div64_s64(temp_var * sys_gain_coeff, 1000000);
*result = div64_s64(*result * 1000, temp_var);
}
- pr_debug("%lld compensated into %lld\n", old, *result);
+ pr_debug("%lld compensated into %lld, a: %d, b: %d, sys_gain: %lld\n",
+ old, *result, coeff_a, coeff_b, sys_gain_coeff);
return 0;
}
@@ -844,9 +895,10 @@
bool batfet_closed)
{
uint8_t rslt_lsb, rslt_msb;
- int32_t rc = 0;
+ int32_t rc = 0, version = 0;
uint16_t raw_data;
uint32_t mode_sel = 0;
+ bool iadc_offset_ch_batfet_check;
if (qpnp_iadc_is_valid(iadc) < 0)
return -EPROBE_DEFER;
@@ -868,13 +920,22 @@
iadc->adc->calib.gain_raw = raw_data;
/*
- * there is a features in the BMS where if the batfet is opened
- * the BMS reads from INTERNAL_RSENSE (channel 0) actually go to
+ * there is a features on PM8941 in the BMS where if the batfet is
+ * opened the BMS reads from INTERNAL_RSENSE (channel 0) actually go to
* OFFSET_CALIBRATION_CSP_CSN (channel 5). Hence if batfet is opened
* we have to calibrate based on OFFSET_CALIBRATION_CSP_CSN even for
* internal rsense.
*/
- if (!batfet_closed || iadc->external_rsense) {
+ version = qpnp_adc_get_revid_version(iadc->dev);
+ if ((version == QPNP_REV_ID_8941_3_1) ||
+ (version == QPNP_REV_ID_8941_3_0) ||
+ (version == QPNP_REV_ID_8941_2_0))
+ iadc_offset_ch_batfet_check = true;
+ else
+ iadc_offset_ch_batfet_check = false;
+
+ if ((iadc_offset_ch_batfet_check && !batfet_closed) ||
+ (iadc->external_rsense)) {
/* external offset calculation */
rc = qpnp_iadc_configure(iadc, OFFSET_CALIBRATION_CSP_CSN,
&raw_data, mode_sel);
@@ -1141,10 +1202,12 @@
result->result_uv = -result->result_uv;
result_current = -result_current;
}
+ result_current *= -1;
rc = qpnp_iadc_comp_result(iadc, &result_current);
if (rc < 0)
pr_err("Error during compensating the IADC\n");
rc = 0;
+ result_current *= -1;
result->result_ua = (int32_t) result_current;
fail:
diff --git a/drivers/hwmon/qpnp-adc-voltage.c b/drivers/hwmon/qpnp-adc-voltage.c
index d462fb3..346a72d 100644
--- a/drivers/hwmon/qpnp-adc-voltage.c
+++ b/drivers/hwmon/qpnp-adc-voltage.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2014, 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
@@ -512,63 +512,52 @@
#define QPNP_VBAT_COEFF_13 102640000
#define QPNP_VBAT_COEFF_14 22220000
#define QPNP_VBAT_COEFF_15 83060000
-
-#define QPNP_VADC_REV_ID_8941_3_1 1
-#define QPNP_VADC_REV_ID_8026_1_0 2
-#define QPNP_VADC_REV_ID_8026_2_0 3
-
-static void qpnp_temp_comp_version_check(struct qpnp_vadc_chip *vadc,
- int32_t *version)
-{
- if (vadc->revision_dig_major == 3 &&
- vadc->revision_ana_minor == 2)
- *version = QPNP_VADC_REV_ID_8941_3_1;
- else if (vadc->revision_dig_major == 1 &&
- vadc->revision_ana_minor == 2)
- *version = QPNP_VADC_REV_ID_8026_1_0;
- else if (vadc->revision_dig_major == 2 &&
- vadc->revision_ana_minor == 2)
- *version = QPNP_VADC_REV_ID_8026_2_0;
- else
- *version = -EINVAL;
-
- return;
-}
+#define QPNP_VBAT_COEFF_16 2810
+#define QPNP_VBAT_COEFF_17 5260
+#define QPNP_VBAT_COEFF_18 8027
+#define QPNP_VBAT_COEFF_19 2347
+#define QPNP_VBAT_COEFF_20 6043
+#define QPNP_VBAT_COEFF_21 1914
+#define QPNP_VBAT_OFFSET_SMIC 9446
+#define QPNP_VBAT_OFFSET_GF 9441
+#define QPNP_OCV_OFFSET_SMIC 4596
+#define QPNP_OCV_OFFSET_GF 5896
+#define QPNP_VBAT_COEFF_22 6800
+#define QPNP_VBAT_COEFF_23 3500
+#define QPNP_VBAT_COEFF_24 4360
+#define QPNP_VBAT_COEFF_25 8060
static int32_t qpnp_ocv_comp(int64_t *result,
struct qpnp_vadc_chip *vadc, int64_t die_temp)
{
int64_t temp_var = 0;
int64_t old = *result;
- int32_t version;
+ int version;
- qpnp_temp_comp_version_check(vadc, &version);
+ version = qpnp_adc_get_revid_version(vadc->dev);
if (version == -EINVAL)
return 0;
- if (die_temp < 25000)
- return 0;
-
- if (die_temp > 60000)
- die_temp = 60000;
+ if (version == QPNP_REV_ID_8026_2_2) {
+ if (die_temp > 25000)
+ return 0;
+ }
switch (version) {
- case QPNP_VADC_REV_ID_8941_3_1:
+ case QPNP_REV_ID_8941_3_1:
switch (vadc->id) {
case COMP_ID_TSMC:
- temp_var = (((die_temp *
- (-QPNP_VBAT_COEFF_4))
- + QPNP_VBAT_COEFF_5));
+ temp_var = ((die_temp - 25000) *
+ (-QPNP_VBAT_COEFF_4));
break;
default:
case COMP_ID_GF:
- temp_var = (((die_temp *
- (-QPNP_VBAT_COEFF_1))
- + QPNP_VBAT_COEFF_2));
+ temp_var = ((die_temp - 25000) *
+ (-QPNP_VBAT_COEFF_1));
break;
}
break;
- case QPNP_VADC_REV_ID_8026_1_0:
+ case QPNP_REV_ID_8026_1_0:
switch (vadc->id) {
case COMP_ID_TSMC:
temp_var = (((die_temp *
@@ -583,19 +572,55 @@
break;
}
break;
- case QPNP_VADC_REV_ID_8026_2_0:
+ case QPNP_REV_ID_8026_2_0:
+ case QPNP_REV_ID_8026_2_1:
switch (vadc->id) {
case COMP_ID_TSMC:
- temp_var = ((die_temp - 2500) *
+ temp_var = ((die_temp - 25000) *
(-QPNP_VBAT_COEFF_10));
break;
default:
case COMP_ID_GF:
- temp_var = ((die_temp - 2500) *
+ temp_var = ((die_temp - 25000) *
(-QPNP_VBAT_COEFF_8));
break;
}
break;
+ case QPNP_REV_ID_8026_2_2:
+ switch (vadc->id) {
+ case COMP_ID_TSMC:
+ *result -= QPNP_VBAT_COEFF_22;
+ temp_var = (die_temp - 25000) *
+ QPNP_VBAT_COEFF_24;
+ break;
+ default:
+ case COMP_ID_GF:
+ *result -= QPNP_VBAT_COEFF_22;
+ temp_var = (die_temp - 25000) *
+ QPNP_VBAT_COEFF_25;
+ break;
+ }
+ case QPNP_REV_ID_8110_2_0:
+ switch (vadc->id) {
+ case COMP_ID_SMIC:
+ *result -= QPNP_OCV_OFFSET_SMIC;
+ if (die_temp < 25000)
+ temp_var = QPNP_VBAT_COEFF_18;
+ else
+ temp_var = QPNP_VBAT_COEFF_19;
+ temp_var = (die_temp - 25000) * temp_var;
+ break;
+ default:
+ case COMP_ID_GF:
+ *result -= QPNP_OCV_OFFSET_GF;
+ if (die_temp < 25000)
+ temp_var = QPNP_VBAT_COEFF_20;
+ else
+ temp_var = QPNP_VBAT_COEFF_21;
+ temp_var = (die_temp - 25000) * temp_var;
+ break;
+ }
+ break;
default:
temp_var = 0;
break;
@@ -618,35 +643,36 @@
{
int64_t temp_var = 0;
int64_t old = *result;
- int32_t version;
+ int version;
- qpnp_temp_comp_version_check(vadc, &version);
+ version = qpnp_adc_get_revid_version(vadc->dev);
if (version == -EINVAL)
return 0;
- if (die_temp < 25000)
- return 0;
-
- /* min(die_temp_c, 60_degC) */
- if (die_temp > 60000)
- die_temp = 60000;
+ if (version != QPNP_REV_ID_8941_3_1) {
+ /* min(die_temp_c, 60_degC) */
+ if (die_temp > 60000)
+ die_temp = 60000;
+ }
switch (version) {
- case QPNP_VADC_REV_ID_8941_3_1:
+ case QPNP_REV_ID_8941_3_1:
switch (vadc->id) {
case COMP_ID_TSMC:
- temp_var = (die_temp *
+ temp_var = ((die_temp - 25000) *
(-QPNP_VBAT_COEFF_1));
break;
default:
case COMP_ID_GF:
- temp_var = (((die_temp *
- (-QPNP_VBAT_COEFF_6))
- + QPNP_VBAT_COEFF_7));
+ /* min(die_temp_c, 60_degC) */
+ if (die_temp > 60000)
+ die_temp = 60000;
+ temp_var = ((die_temp - 25000) *
+ (-QPNP_VBAT_COEFF_1));
break;
}
break;
- case QPNP_VADC_REV_ID_8026_1_0:
+ case QPNP_REV_ID_8026_1_0:
switch (vadc->id) {
case COMP_ID_TSMC:
temp_var = (((die_temp *
@@ -661,19 +687,47 @@
break;
}
break;
- case QPNP_VADC_REV_ID_8026_2_0:
+ case QPNP_REV_ID_8026_2_0:
+ case QPNP_REV_ID_8026_2_1:
switch (vadc->id) {
case COMP_ID_TSMC:
- temp_var = ((die_temp - 2500) *
+ temp_var = ((die_temp - 25000) *
(-QPNP_VBAT_COEFF_11));
break;
default:
case COMP_ID_GF:
- temp_var = ((die_temp - 2500) *
+ temp_var = ((die_temp - 25000) *
(-QPNP_VBAT_COEFF_9));
break;
}
break;
+ case QPNP_REV_ID_8026_2_2:
+ switch (vadc->id) {
+ case COMP_ID_TSMC:
+ *result -= QPNP_VBAT_COEFF_23;
+ temp_var = 0;
+ break;
+ default:
+ case COMP_ID_GF:
+ *result -= QPNP_VBAT_COEFF_23;
+ temp_var = 0;
+ break;
+ }
+ case QPNP_REV_ID_8110_2_0:
+ switch (vadc->id) {
+ case COMP_ID_SMIC:
+ *result -= QPNP_VBAT_OFFSET_SMIC;
+ temp_var = ((die_temp - 25000) *
+ (QPNP_VBAT_COEFF_17));
+ break;
+ default:
+ case COMP_ID_GF:
+ *result -= QPNP_VBAT_OFFSET_GF;
+ temp_var = ((die_temp - 25000) *
+ (QPNP_VBAT_COEFF_16));
+ break;
+ }
+ break;
default:
temp_var = 0;
break;
@@ -692,7 +746,7 @@
}
int32_t qpnp_vbat_sns_comp_result(struct qpnp_vadc_chip *vadc,
- int64_t *result)
+ int64_t *result, bool is_pon_ocv)
{
struct qpnp_vadc_result die_temp_result;
int rc = 0;
@@ -708,7 +762,12 @@
return rc;
}
- rc = qpnp_ocv_comp(result, vadc, die_temp_result.physical);
+ if (is_pon_ocv)
+ rc = qpnp_ocv_comp(result, vadc, die_temp_result.physical);
+ else
+ rc = qpnp_vbat_sns_comp(result, vadc,
+ die_temp_result.physical);
+
if (rc < 0)
pr_err("Error with vbat compensation\n");
diff --git a/drivers/input/misc/mma8x5x.c b/drivers/input/misc/mma8x5x.c
index a605720..d576752 100644
--- a/drivers/input/misc/mma8x5x.c
+++ b/drivers/input/misc/mma8x5x.c
@@ -503,9 +503,12 @@
{
struct mma8x5x_data *pdata = container_of((struct delayed_work *)work,
struct mma8x5x_data, dwork);
- mma8x5x_report_data(pdata);
- schedule_delayed_work(&pdata->dwork,
- msecs_to_jiffies(pdata->poll_delay));
+
+ if ((pdata->active & MMA_STATE_MASK) == MMA_ACTIVED) {
+ mma8x5x_report_data(pdata);
+ schedule_delayed_work(&pdata->dwork,
+ msecs_to_jiffies(pdata->poll_delay));
+ }
}
static irqreturn_t mma8x5x_interrupt(int vec, void *data)
@@ -570,9 +573,9 @@
dev_err(&client->dev, "change device state failed!");
goto err_failed;
}
-
- schedule_delayed_work(&pdata->dwork,
- msecs_to_jiffies(pdata->poll_delay));
+ if (!pdata->use_int)
+ schedule_delayed_work(&pdata->dwork,
+ msecs_to_jiffies(pdata->poll_delay));
pdata->active = MMA_ACTIVED;
dev_dbg(&client->dev, "%s:mma enable setting active.\n",
@@ -580,8 +583,6 @@
}
} else if (enable == 0) {
if (pdata->active == MMA_ACTIVED) {
- cancel_delayed_work_sync(&pdata->dwork);
-
val = i2c_smbus_read_byte_data(client,
MMA8X5X_CTRL_REG1);
if (val < 0) {
@@ -596,7 +597,10 @@
dev_err(&client->dev, "change device state failed!");
goto err_failed;
}
-
+ /*
+ * Set standby state,
+ * polling work queue will stop after next call.
+ */
pdata->active = MMA_STANDBY;
dev_dbg(&client->dev, "%s:mma enable setting inactive.\n",
__func__);
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index cd6989c..be7c3c6 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -1983,6 +1983,7 @@
const char *buf, size_t count)
{
struct mxt_data *data = dev_get_drvdata(dev);
+ struct device *adapter = data->client->adapter->dev.parent;
unsigned long value;
int err = 0;
@@ -2000,7 +2001,7 @@
if (atomic_read(&data->st_enabled) == 0)
break;
- pm_runtime_put(data->client->adapter->dev.parent);
+ pm_runtime_put(adapter);
atomic_set(&data->st_enabled, 0);
mxt_secure_touch_notify(data);
mxt_interrupt(data->client->irq, data);
@@ -2012,7 +2013,7 @@
break;
}
- if (pm_runtime_get(data->client->adapter->dev.parent) < 0) {
+ if (pm_runtime_get_sync(adapter) < 0) {
dev_err(&data->client->dev, "pm_runtime_get failed\n");
err = -EIO;
break;
diff --git a/drivers/input/touchscreen/ft5x06_ts.c b/drivers/input/touchscreen/ft5x06_ts.c
index 4b8a3d4..1da84fa 100644
--- a/drivers/input/touchscreen/ft5x06_ts.c
+++ b/drivers/input/touchscreen/ft5x06_ts.c
@@ -3,7 +3,7 @@
* FocalTech ft5x06 TouchScreen driver.
*
* Copyright (c) 2010 Focal tech Ltd.
- * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2014, 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
@@ -69,7 +69,6 @@
#define FT_REG_THGROUP 0x80
#define FT_REG_ECC 0xCC
#define FT_REG_RESET_FW 0x07
-#define FT_REG_FW_MAJ_VER 0xB1
#define FT_REG_FW_MIN_VER 0xB2
#define FT_REG_FW_SUB_MIN_VER 0xB3
@@ -289,7 +288,7 @@
u8 reg_addr;
int err;
- reg_addr = FT_REG_FW_MAJ_VER;
+ reg_addr = FT_REG_FW_VER;
err = ft5x06_i2c_read(client, ®_addr, 1, &data->fw_ver[0], 1);
if (err < 0)
dev_err(&client->dev, "fw major version read failed");
@@ -877,6 +876,11 @@
u8 fw_file_maj, fw_file_min, fw_file_sub_min;
bool fw_upgrade = false;
+ if (data->suspended) {
+ dev_info(dev, "Device is in suspend state: Exit FW upgrade\n");
+ return -EBUSY;
+ }
+
rc = request_firmware(&fw, data->fw_name, dev);
if (rc < 0) {
dev_err(dev, "Request firmware failed - %s (%d)\n",
@@ -899,17 +903,10 @@
dev_info(dev, "New firmware: %d.%d.%d", fw_file_maj,
fw_file_min, fw_file_sub_min);
- if (force) {
+ if (force)
fw_upgrade = true;
- } else if (data->fw_ver[0] == fw_file_maj) {
- if (data->fw_ver[1] < fw_file_min)
- fw_upgrade = true;
- else if (data->fw_ver[2] < fw_file_sub_min)
- fw_upgrade = true;
- else
- dev_info(dev, "No need to upgrade\n");
- } else
- dev_info(dev, "Firmware versions do not match\n");
+ else if (data->fw_ver[0] < fw_file_maj)
+ fw_upgrade = true;
if (!fw_upgrade) {
dev_info(dev, "Exiting fw upgrade...\n");
diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index 8e70129..cb1dbd4 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -87,6 +87,16 @@
section mappings and TLB misses should be quite infrequent.
Most people can probably say Y here.
+config MSM_IOMMU_VBIF_CHECK
+ bool "Enable support for VBIF check when IOMMU gets stuck"
+ depends on MSM_IOMMU
+ help
+ Enables an extra check in the IOMMU driver that logs debugging
+ information when TLB sync or iommu halt issue occurs. This helps
+ in debugging such issues.
+
+ If unsure, say N here.
+
config IOMMU_NON_SECURE
bool "Turns on programming of secure SMMU by kernel"
depends on MSM_IOMMU
diff --git a/drivers/iommu/msm_iommu-v1.c b/drivers/iommu/msm_iommu-v1.c
index 84f81bf..50581f8 100644
--- a/drivers/iommu/msm_iommu-v1.c
+++ b/drivers/iommu/msm_iommu-v1.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -16,6 +16,7 @@
#include <linux/platform_device.h>
#include <linux/errno.h>
#include <linux/io.h>
+#include <linux/iopoll.h>
#include <linux/interrupt.h>
#include <linux/list.h>
#include <linux/mutex.h>
@@ -143,13 +144,141 @@
.iommu_lock_release = _iommu_lock_release,
};
-void iommu_halt(const struct msm_iommu_drvdata *iommu_drvdata)
+#ifdef CONFIG_MSM_IOMMU_VBIF_CHECK
+
+#define VBIF_XIN_HALT_CTRL0 0x200
+#define VBIF_XIN_HALT_CTRL1 0x204
+#define VBIF_AXI_HALT_CTRL0 0x208
+#define VBIF_AXI_HALT_CTRL1 0x20C
+
+static void __halt_vbif_xin(void __iomem *vbif_base)
+{
+ pr_err("Halting VBIF_XIN\n");
+ writel_relaxed(0xFFFFFFFF, vbif_base + VBIF_XIN_HALT_CTRL0);
+}
+
+static void __dump_vbif_state(void __iomem *base, void __iomem *vbif_base)
+{
+ unsigned int reg_val;
+
+ reg_val = readl_relaxed(base + MICRO_MMU_CTRL);
+ pr_err("Value of SMMU_IMPLDEF_MICRO_MMU_CTRL = 0x%x\n", reg_val);
+
+ reg_val = readl_relaxed(vbif_base + VBIF_XIN_HALT_CTRL0);
+ pr_err("Value of VBIF_XIN_HALT_CTRL0 = 0x%x\n", reg_val);
+ reg_val = readl_relaxed(vbif_base + VBIF_XIN_HALT_CTRL1);
+ pr_err("Value of VBIF_XIN_HALT_CTRL1 = 0x%x\n", reg_val);
+ reg_val = readl_relaxed(vbif_base + VBIF_AXI_HALT_CTRL0);
+ pr_err("Value of VBIF_AXI_HALT_CTRL0 = 0x%x\n", reg_val);
+ reg_val = readl_relaxed(vbif_base + VBIF_AXI_HALT_CTRL1);
+ pr_err("Value of VBIF_AXI_HALT_CTRL1 = 0x%x\n", reg_val);
+}
+
+static int __check_vbif_state(struct msm_iommu_drvdata const *drvdata)
+{
+ phys_addr_t addr = (phys_addr_t) (drvdata->phys_base
+ - (phys_addr_t) 0x4000);
+ void __iomem *base = ioremap(addr, 0x1000);
+ int ret = 0;
+
+ if (base) {
+ __dump_vbif_state(drvdata->base, base);
+ __halt_vbif_xin(drvdata->base);
+ __dump_vbif_state(drvdata->base, base);
+ iounmap(base);
+ } else {
+ pr_err("%s: Unable to ioremap\n", __func__);
+ ret = -ENOMEM;
+ }
+ return ret;
+}
+
+static void check_halt_state(struct msm_iommu_drvdata const *drvdata)
+{
+ int res;
+ unsigned int val;
+ void __iomem *base = drvdata->base;
+ char const *name = drvdata->name;
+
+ pr_err("Timed out waiting for IOMMU halt to complete for %s\n", name);
+ res = __check_vbif_state(drvdata);
+ if (res)
+ BUG();
+
+ pr_err("Checking if IOMMU halt completed for %s\n", name);
+
+ res = readl_tight_poll_timeout(
+ GLB_REG(MICRO_MMU_CTRL, base), val,
+ (val & MMU_CTRL_IDLE) == MMU_CTRL_IDLE, 5000000);
+
+ if (res) {
+ pr_err("Timed out (again) waiting for IOMMU halt to complete for %s\n",
+ name);
+ } else {
+ pr_err("IOMMU halt completed. VBIF FIFO most likely not getting drained by master\n");
+ }
+ BUG();
+}
+
+static void check_tlb_sync_state(struct msm_iommu_drvdata const *drvdata,
+ int ctx)
+{
+ int res;
+ unsigned int val;
+ void __iomem *base = drvdata->base;
+ char const *name = drvdata->name;
+
+ pr_err("Timed out waiting for TLB SYNC to complete for %s\n", name);
+ res = __check_vbif_state(drvdata);
+ if (res)
+ BUG();
+
+ pr_err("Checking if TLB sync completed for %s\n", name);
+
+ res = readl_tight_poll_timeout(CTX_REG(CB_TLBSTATUS, base, ctx), val,
+ (val & CB_TLBSTATUS_SACTIVE) == 0, 5000000);
+ if (res) {
+ pr_err("Timed out (again) waiting for TLB SYNC to complete for %s\n",
+ name);
+ } else {
+ pr_err("TLB Sync completed. VBIF FIFO most likely not getting drained by master\n");
+ }
+ BUG();
+}
+
+#else
+
+/*
+ * For targets without VBIF or for targets with the VBIF check disabled
+ * we directly just crash to capture the issue
+ */
+static void check_halt_state(struct msm_iommu_drvdata const *drvdata)
+{
+ BUG();
+}
+
+static void check_tlb_sync_state(struct msm_iommu_drvdata const *drvdata,
+ int ctx)
+{
+ BUG();
+}
+
+#endif
+
+void iommu_halt(struct msm_iommu_drvdata const *iommu_drvdata)
{
if (iommu_drvdata->halt_enabled) {
- SET_MICRO_MMU_CTRL_HALT_REQ(iommu_drvdata->base, 1);
+ unsigned int val;
+ void __iomem *base = iommu_drvdata->base;
+ int res;
- while (GET_MICRO_MMU_CTRL_IDLE(iommu_drvdata->base) == 0)
- cpu_relax();
+ SET_MICRO_MMU_CTRL_HALT_REQ(base, 1);
+ res = readl_tight_poll_timeout(
+ GLB_REG(MICRO_MMU_CTRL, base), val,
+ (val & MMU_CTRL_IDLE) == MMU_CTRL_IDLE, 5000000);
+
+ if (res)
+ check_halt_state(iommu_drvdata);
/* Ensure device is idle before continuing */
mb();
}
@@ -173,15 +302,19 @@
}
}
-static void __sync_tlb(void __iomem *base, int ctx)
+static void __sync_tlb(struct msm_iommu_drvdata *iommu_drvdata, int ctx)
{
+ unsigned int val;
+ unsigned int res;
+ void __iomem *base = iommu_drvdata->base;
+
SET_TLBSYNC(base, ctx, 0);
-
- /* No barrier needed due to register proximity */
- while (GET_CB_TLBSTATUS_SACTIVE(base, ctx))
- cpu_relax();
-
/* No barrier needed due to read dependency */
+
+ res = readl_tight_poll_timeout(CTX_REG(CB_TLBSTATUS, base, ctx), val,
+ (val & CB_TLBSTATUS_SACTIVE) == 0, 5000000);
+ if (res)
+ check_tlb_sync_state(iommu_drvdata, ctx);
}
static int __flush_iotlb_va(struct iommu_domain *domain, unsigned int va)
@@ -205,7 +338,7 @@
SET_TLBIVA(iommu_drvdata->base, ctx_drvdata->num,
ctx_drvdata->asid | (va & CB_TLBIVA_VA));
mb();
- __sync_tlb(iommu_drvdata->base, ctx_drvdata->num);
+ __sync_tlb(iommu_drvdata, ctx_drvdata->num);
__disable_clocks(iommu_drvdata);
}
fail:
@@ -232,7 +365,7 @@
SET_TLBIASID(iommu_drvdata->base, ctx_drvdata->num,
ctx_drvdata->asid);
mb();
- __sync_tlb(iommu_drvdata->base, ctx_drvdata->num);
+ __sync_tlb(iommu_drvdata, ctx_drvdata->num);
__disable_clocks(iommu_drvdata);
}
@@ -343,15 +476,14 @@
mb();
}
-static void __release_smg(void __iomem *base, int ctx)
+static void __release_smg(void __iomem *base)
{
int i, smt_size;
smt_size = GET_IDR0_NUMSMRG(base);
- /* Invalidate any SMGs associated with this context */
+ /* Invalidate all SMGs */
for (i = 0; i < smt_size; i++)
- if (GET_SMR_VALID(base, i) &&
- GET_S2CR_CBNDX(base, i) == ctx)
+ if (GET_SMR_VALID(base, i))
SET_SMR_VALID(base, i, 0);
}
@@ -394,17 +526,52 @@
}
}
+
+static int program_m2v_table(struct device *dev, void __iomem *base)
+{
+ struct msm_iommu_ctx_drvdata *ctx_drvdata = dev_get_drvdata(dev);
+ u32 *sids = ctx_drvdata->sids;
+ unsigned int ctx = ctx_drvdata->num;
+ int num = 0, i, smt_size;
+ int len = ctx_drvdata->nsid;
+
+ smt_size = GET_IDR0_NUMSMRG(base);
+ /* Program the M2V tables for this context */
+ for (i = 0; i < len / sizeof(*sids); i++) {
+ for (; num < smt_size; num++)
+ if (GET_SMR_VALID(base, num) == 0)
+ break;
+ BUG_ON(num >= smt_size);
+
+ SET_SMR_VALID(base, num, 1);
+ SET_SMR_MASK(base, num, 0);
+ SET_SMR_ID(base, num, sids[i]);
+
+ SET_S2CR_N(base, num, 0);
+ SET_S2CR_CBNDX(base, num, ctx);
+ SET_S2CR_MEMATTR(base, num, 0x0A);
+ /* Set security bit override to be Non-secure */
+ SET_S2CR_NSCFG(base, num, 3);
+ }
+
+ return 0;
+}
+
+static void program_all_m2v_tables(struct msm_iommu_drvdata *iommu_drvdata)
+{
+ device_for_each_child(iommu_drvdata->dev, iommu_drvdata->base,
+ program_m2v_table);
+}
+
static void __program_context(struct msm_iommu_drvdata *iommu_drvdata,
struct msm_iommu_ctx_drvdata *ctx_drvdata,
- struct msm_iommu_priv *priv, bool is_secure)
+ struct msm_iommu_priv *priv, bool is_secure,
+ bool program_m2v)
{
unsigned int prrr, nmrr;
- unsigned int pn;
- int num = 0, i, smt_size;
+ phys_addr_t pn;
void __iomem *base = iommu_drvdata->base;
unsigned int ctx = ctx_drvdata->num;
- u32 *sids = ctx_drvdata->sids;
- int len = ctx_drvdata->nsid;
phys_addr_t pgtable = __pa(priv->pt.fl_table);
__reset_context(base, ctx);
@@ -445,24 +612,9 @@
}
if (!is_secure) {
- smt_size = GET_IDR0_NUMSMRG(base);
- /* Program the M2V tables for this context */
- for (i = 0; i < len / sizeof(*sids); i++) {
- for (; num < smt_size; num++)
- if (GET_SMR_VALID(base, num) == 0)
- break;
- BUG_ON(num >= smt_size);
+ if (program_m2v)
+ program_all_m2v_tables(iommu_drvdata);
- SET_SMR_VALID(base, num, 1);
- SET_SMR_MASK(base, num, 0);
- SET_SMR_ID(base, num, sids[i]);
-
- SET_S2CR_N(base, num, 0);
- SET_S2CR_CBNDX(base, num, ctx);
- SET_S2CR_MEMATTR(base, num, 0x0A);
- /* Set security bit override to be Non-secure */
- SET_S2CR_NSCFG(base, num, 3);
- }
SET_CBAR_N(base, ctx, 0);
/* Stage 1 Context with Stage 2 bypass */
@@ -534,49 +686,55 @@
struct msm_iommu_drvdata *iommu_drvdata;
struct msm_iommu_ctx_drvdata *ctx_drvdata;
struct msm_iommu_ctx_drvdata *tmp_drvdata;
- int ret;
+ int ret = 0;
int is_secure;
+ bool set_m2v = false;
mutex_lock(&msm_iommu_lock);
priv = domain->priv;
if (!priv || !dev) {
ret = -EINVAL;
- goto fail;
+ goto unlock;
}
iommu_drvdata = dev_get_drvdata(dev->parent);
ctx_drvdata = dev_get_drvdata(dev);
if (!iommu_drvdata || !ctx_drvdata) {
ret = -EINVAL;
- goto fail;
+ goto unlock;
}
+ ++ctx_drvdata->attach_count;
+
+ if (ctx_drvdata->attach_count > 1)
+ goto already_attached;
+
if (!list_empty(&ctx_drvdata->attached_elm)) {
ret = -EBUSY;
- goto fail;
+ goto unlock;
}
list_for_each_entry(tmp_drvdata, &priv->list_attached, attached_elm)
if (tmp_drvdata == ctx_drvdata) {
ret = -EBUSY;
- goto fail;
+ goto unlock;
}
is_secure = iommu_drvdata->sec_id != -1;
ret = __enable_regulators(iommu_drvdata);
if (ret)
- goto fail;
+ goto unlock;
ret = apply_bus_vote(iommu_drvdata, 1);
if (ret)
- goto fail;
+ goto unlock;
ret = __enable_clocks(iommu_drvdata);
if (ret) {
__disable_regulators(iommu_drvdata);
- goto fail;
+ goto unlock;
}
/* We can only do this once */
@@ -591,16 +749,17 @@
if (ret) {
__disable_regulators(iommu_drvdata);
__disable_clocks(iommu_drvdata);
- goto fail;
+ goto unlock;
}
}
program_iommu_bfb_settings(iommu_drvdata->base,
iommu_drvdata->bfb_settings);
+ set_m2v = true;
}
iommu_halt(iommu_drvdata);
- __program_context(iommu_drvdata, ctx_drvdata, priv, is_secure);
+ __program_context(iommu_drvdata, ctx_drvdata, priv, is_secure, set_m2v);
iommu_resume(iommu_drvdata);
@@ -610,11 +769,12 @@
ctx_drvdata->attached_domain = domain;
++iommu_drvdata->ctx_attach_count;
+already_attached:
mutex_unlock(&msm_iommu_lock);
msm_iommu_attached(dev->parent);
return ret;
-fail:
+unlock:
mutex_unlock(&msm_iommu_lock);
return ret;
}
@@ -633,16 +793,22 @@
mutex_lock(&msm_iommu_lock);
priv = domain->priv;
if (!priv || !dev)
- goto fail;
+ goto unlock;
iommu_drvdata = dev_get_drvdata(dev->parent);
ctx_drvdata = dev_get_drvdata(dev);
if (!iommu_drvdata || !ctx_drvdata || !ctx_drvdata->attached_domain)
- goto fail;
+ goto unlock;
+
+ --ctx_drvdata->attach_count;
+ BUG_ON(ctx_drvdata->attach_count < 0);
+
+ if (ctx_drvdata->attach_count > 0)
+ goto unlock;
ret = __enable_clocks(iommu_drvdata);
if (ret)
- goto fail;
+ goto unlock;
is_secure = iommu_drvdata->sec_id != -1;
@@ -652,13 +818,15 @@
iommu_drvdata->asid[ctx_drvdata->asid - 1]--;
ctx_drvdata->asid = -1;
- iommu_halt(iommu_drvdata);
-
__reset_context(iommu_drvdata->base, ctx_drvdata->num);
- if (!is_secure)
- __release_smg(iommu_drvdata->base, ctx_drvdata->num);
- iommu_resume(iommu_drvdata);
+ /*
+ * Only reset the M2V tables on the very last detach */
+ if (!is_secure && iommu_drvdata->ctx_attach_count == 1) {
+ iommu_halt(iommu_drvdata);
+ __release_smg(iommu_drvdata->base);
+ iommu_resume(iommu_drvdata);
+ }
__disable_clocks(iommu_drvdata);
@@ -670,7 +838,7 @@
ctx_drvdata->attached_domain = NULL;
BUG_ON(iommu_drvdata->ctx_attach_count == 0);
--iommu_drvdata->ctx_attach_count;
-fail:
+unlock:
mutex_unlock(&msm_iommu_lock);
}
diff --git a/drivers/iommu/msm_iommu_dev-v1.c b/drivers/iommu/msm_iommu_dev-v1.c
index a9d164e..ff6b58c 100644
--- a/drivers/iommu/msm_iommu_dev-v1.c
+++ b/drivers/iommu/msm_iommu_dev-v1.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2014, 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
@@ -299,6 +299,7 @@
if (!drvdata->base)
return -ENOMEM;
+ drvdata->phys_base = r->start;
drvdata->glb_base = drvdata->base;
if (of_get_property(pdev->dev.of_node, "vdd-supply", NULL)) {
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
index e443e9a..c3fb176 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
@@ -13,7 +13,7 @@
#include <linux/module.h>
#include <mach/iommu.h>
#include <linux/ratelimit.h>
-
+#include <asm/div64.h>
#include "msm_isp40.h"
#include "msm_isp_util.h"
#include "msm_isp_axi_util.h"
@@ -36,8 +36,8 @@
#define VFE40_8x26_VERSION 0x20000013
#define VFE40_8x26V2_VERSION 0x20010014
-#define VFE40_BURST_LEN 3
-#define VFE40_STATS_BURST_LEN 2
+#define VFE40_BURST_LEN 1
+#define VFE40_STATS_BURST_LEN 1
#define VFE40_UB_SIZE 1536
#define VFE40_EQUAL_SLICE_UB 228
#define VFE40_WM_BASE(idx) (0x6C + 0x24 * idx)
@@ -1078,7 +1078,6 @@
uint8_t num_used_wms = 0;
uint32_t prop_size = 0;
uint32_t wm_ub_size;
- uint32_t delta;
for (i = 0; i < axi_data->hw_info->num_wm; i++) {
if (axi_data->free_wm[i] > 0) {
@@ -1090,9 +1089,11 @@
axi_data->hw_info->min_wm_ub * num_used_wms;
for (i = 0; i < axi_data->hw_info->num_wm; i++) {
if (axi_data->free_wm[i]) {
- delta =
- (axi_data->wm_image_size[i] *
- prop_size)/total_image_size;
+ uint64_t delta = 0;
+ uint64_t temp = (uint64_t)axi_data->wm_image_size[i] *
+ (uint64_t)prop_size;
+ do_div(temp, total_image_size);
+ delta = temp;
wm_ub_size = axi_data->hw_info->min_wm_ub + delta;
msm_camera_io_w(ub_offset << 16 | (wm_ub_size - 1),
vfe_dev->vfe_base + VFE40_WM_BASE(i) + 0x10);
@@ -1119,7 +1120,7 @@
static void msm_vfe40_cfg_axi_ub(struct vfe_device *vfe_dev)
{
struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
- axi_data->wm_ub_cfg_policy = MSM_WM_UB_EQUAL_SLICING;
+ axi_data->wm_ub_cfg_policy = MSM_WM_UB_CFG_DEFAULT;
if (axi_data->wm_ub_cfg_policy == MSM_WM_UB_EQUAL_SLICING)
msm_vfe40_cfg_axi_ub_equal_slicing(vfe_dev);
else
@@ -1408,8 +1409,8 @@
}
static struct msm_vfe_axi_hardware_info msm_vfe40_axi_hw_info = {
- .num_wm = 5,
- .num_comp_mask = 2,
+ .num_wm = 7,
+ .num_comp_mask = 3,
.num_rdi = 3,
.num_rdi_master = 3,
.min_wm_ub = 64,
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
index 206620c..a60fa09 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
@@ -1294,7 +1294,15 @@
rc = msm_isp_axi_wait_for_cfg_done(vfe_dev, camif_update);
if (rc < 0) {
pr_err("%s: wait for config done failed\n", __func__);
- return rc;
+ for (i = 0; i < stream_cfg_cmd->num_streams; i++) {
+ stream_info = &axi_data->stream_info[
+ HANDLE_TO_IDX(
+ stream_cfg_cmd->stream_handle[i])];
+ stream_info->state = STOP_PENDING;
+ msm_isp_axi_stream_enable_cfg(
+ vfe_dev, stream_info);
+ stream_info->state = INACTIVE;
+ }
}
}
msm_isp_update_stream_bandwidth(vfe_dev);
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
index ffe0b9c..cb46e9c 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
@@ -13,6 +13,7 @@
#include <linux/io.h>
#include <media/v4l2-subdev.h>
#include <linux/ratelimit.h>
+#include <asm/div64.h>
#include "msm.h"
#include "msm_isp_util.h"
@@ -24,11 +25,10 @@
static DEFINE_MUTEX(bandwidth_mgr_mutex);
static struct msm_isp_bandwidth_mgr isp_bandwidth_mgr;
-#define MSM_ISP_MIN_AB 300000000
-#define MSM_ISP_MIN_IB 450000000
+#define MSM_ISP_MIN_AB 450000000
+#define MSM_ISP_MIN_IB 900000000
#define VFE40_8974V2_VERSION 0x1001001A
-
static struct msm_bus_vectors msm_isp_init_vectors[] = {
{
.src = MSM_BUS_MASTER_VFE,
@@ -217,7 +217,8 @@
{
uint32_t avtimer_msw_1st = 0, avtimer_lsw = 0;
uint32_t avtimer_msw_2nd = 0;
- uint8_t iter = 0;
+ uint64_t av_timer_tick = 0;
+
if (!vfe_dev->p_avtimer_msw || !vfe_dev->p_avtimer_lsw) {
pr_err("%s: ioremap failed\n", __func__);
return;
@@ -226,15 +227,10 @@
avtimer_msw_1st = msm_camera_io_r(vfe_dev->p_avtimer_msw);
avtimer_lsw = msm_camera_io_r(vfe_dev->p_avtimer_lsw);
avtimer_msw_2nd = msm_camera_io_r(vfe_dev->p_avtimer_msw);
- } while ((avtimer_msw_1st != avtimer_msw_2nd)
- && (iter++ < AVTIMER_ITERATION_CTR));
- /*Just return if the MSW TimeStamps don't converge after
- a few iterations Application needs to handle the zero TS values*/
- if (iter >= AVTIMER_ITERATION_CTR) {
- pr_err("%s: AVTimer MSW TS did not converge !!!\n", __func__);
- return;
- }
- time_stamp->vt_time.tv_sec = avtimer_msw_1st;
+ } while (avtimer_msw_1st != avtimer_msw_2nd);
+ av_timer_tick = ((uint64_t)avtimer_msw_1st << 32) | avtimer_lsw;
+ avtimer_lsw = do_div(av_timer_tick, USEC_PER_SEC);
+ time_stamp->vt_time.tv_sec = (uint32_t)(av_timer_tick);
time_stamp->vt_time.tv_usec = avtimer_lsw;
}
diff --git a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c
index 87ad994..279a7dd 100755
--- a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c
@@ -169,6 +169,7 @@
if (rc < 0) {
pr_err("%s Default sensor position %d\n", __func__, __LINE__);
sensordata->sensor_info->position = 0;
+ rc = 0;
}
rc = of_property_read_u32(of_node, "qcom,sensor-mode",
@@ -178,6 +179,7 @@
if (rc < 0) {
pr_err("%s Default sensor mode %d\n", __func__, __LINE__);
sensordata->sensor_info->modes_supported = 0;
+ rc = 0;
}
rc = msm_sensor_get_dt_csi_data(of_node, &sensordata->csi_lane_params);
@@ -573,6 +575,10 @@
s_ctrl->sensordata->sensor_info->is_mount_angle_valid;
cdata->cfg.sensor_info.sensor_mount_angle =
s_ctrl->sensordata->sensor_info->sensor_mount_angle;
+ cdata->cfg.sensor_info.position =
+ s_ctrl->sensordata->sensor_info->position;
+ cdata->cfg.sensor_info.modes_supported =
+ s_ctrl->sensordata->sensor_info->modes_supported;
CDBG("%s:%d sensor name %s\n", __func__, __LINE__,
cdata->cfg.sensor_info.sensor_name);
CDBG("%s:%d session id %d\n", __func__, __LINE__,
diff --git a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c
index f5be347..772ed0e 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c
@@ -27,6 +27,8 @@
#define CDBG(fmt, args...) pr_debug(fmt, ##args)
#endif
+#define SENSOR_MAX_MOUNTANGLE (360)
+
/* Static declaration */
static struct msm_sensor_ctrl_t *g_sctrl[MAX_CAMERAS];
@@ -260,6 +262,58 @@
return rc;
}
+static int32_t msm_sensor_fill_slave_info_init_params(
+ struct msm_camera_sensor_slave_info *slave_info,
+ struct msm_sensor_info_t *sensor_info)
+{
+ struct msm_sensor_init_params *sensor_init_params;
+ if (!slave_info || !sensor_info)
+ return -EINVAL;
+
+ if (!slave_info->is_init_params_valid)
+ return 0;
+
+ sensor_init_params = &slave_info->sensor_init_params;
+ if (INVALID_CAMERA_B != sensor_init_params->position)
+ sensor_info->position =
+ sensor_init_params->position;
+
+ if (SENSOR_MAX_MOUNTANGLE > sensor_init_params->sensor_mount_angle) {
+ sensor_info->sensor_mount_angle =
+ sensor_init_params->sensor_mount_angle;
+ sensor_info->is_mount_angle_valid = 1;
+ }
+
+ if (CAMERA_MODE_INVALID != sensor_init_params->modes_supported)
+ sensor_info->modes_supported =
+ sensor_init_params->modes_supported;
+
+ return 0;
+}
+
+
+static int32_t msm_sensor_validate_slave_info(
+ struct msm_sensor_info_t *sensor_info)
+{
+ if (INVALID_CAMERA_B == sensor_info->position) {
+ sensor_info->position = BACK_CAMERA_B;
+ pr_err("%s Set dafault sensor position%d\n",
+ __func__, __LINE__);
+ }
+ if (CAMERA_MODE_INVALID == sensor_info->modes_supported) {
+ sensor_info->modes_supported = CAMERA_MODE_2D_B;
+ pr_err("%s Set dafault sensor modes_supported%d\n",
+ __func__, __LINE__);
+ }
+ if (SENSOR_MAX_MOUNTANGLE < sensor_info->sensor_mount_angle) {
+ sensor_info->sensor_mount_angle = 0;
+ pr_err("%s Set dafault sensor mount angle%d\n",
+ __func__, __LINE__);
+ sensor_info->is_mount_angle_valid = 1;
+ }
+ return 0;
+}
+
/* static function definition */
int32_t msm_sensor_driver_probe(void *setting)
{
@@ -274,6 +328,7 @@
struct msm_camera_power_ctrl_t *power_info = NULL;
int c, end;
struct msm_sensor_power_setting power_down_setting_t;
+ unsigned long mount_pos = 0;
/* Validate input parameters */
if (!setting) {
@@ -304,6 +359,13 @@
CDBG("size %d", slave_info->power_setting_array.size);
CDBG("size down %d", slave_info->power_setting_array.size_down);
+ if (slave_info->is_init_params_valid) {
+ CDBG("position %d",
+ slave_info->sensor_init_params.position);
+ CDBG("mount %d",
+ slave_info->sensor_init_params.sensor_mount_angle);
+ }
+
/* Validate camera id */
if (slave_info->camera_id >= MAX_CAMERAS) {
pr_err("failed: invalid camera id %d max %d",
@@ -537,6 +599,25 @@
/* Power down */
s_ctrl->func_tbl->sensor_power_down(s_ctrl);
+ rc = msm_sensor_fill_slave_info_init_params(
+ slave_info,
+ s_ctrl->sensordata->sensor_info);
+ if (rc < 0) {
+ pr_err("%s Fill slave info failed", slave_info->sensor_name);
+ goto FREE_CAMERA_INFO;
+ }
+ rc = msm_sensor_validate_slave_info(s_ctrl->sensordata->sensor_info);
+ if (rc < 0) {
+ pr_err("%s Validate slave info failed",
+ slave_info->sensor_name);
+ goto FREE_CAMERA_INFO;
+ }
+ /* Update sensor mount angle and position in media entity flag */
+ mount_pos = s_ctrl->sensordata->sensor_info->position << 16;
+ mount_pos = mount_pos | ((s_ctrl->sensordata->sensor_info->
+ sensor_mount_angle / 90) << 8);
+ s_ctrl->msm_sd.sd.entity.flags = mount_pos | MEDIA_ENT_FL_DEFAULT;
+
/*Save sensor info*/
s_ctrl->sensordata->cam_slave_info = slave_info;
@@ -707,6 +788,23 @@
sensordata->sensor_info->is_mount_angle_valid = 1;
}
+ rc = of_property_read_u32(of_node, "qcom,sensor-position",
+ &sensordata->sensor_info->position);
+ if (rc < 0) {
+ pr_err("%s:%d Invalid sensor position\n", __func__, __LINE__);
+ sensordata->sensor_info->position = INVALID_CAMERA_B;
+ rc = 0;
+ }
+
+ rc = of_property_read_u32(of_node, "qcom,sensor-mode",
+ &sensordata->sensor_info->modes_supported);
+ if (rc < 0) {
+ pr_err("%s:%d Invalid sensor mode supported\n",
+ __func__, __LINE__);
+ sensordata->sensor_info->modes_supported = CAMERA_MODE_INVALID;
+ rc = 0;
+ }
+
/* Get vdd-cx regulator */
/*Optional property, don't return error if absent */
of_property_read_string(of_node, "qcom,vdd-cx-name",
diff --git a/drivers/media/platform/msm/vidc/hfi_packetization.c b/drivers/media/platform/msm/vidc/hfi_packetization.c
index 4b7a3be..cdc649f 100644
--- a/drivers/media/platform/msm/vidc/hfi_packetization.c
+++ b/drivers/media/platform/msm/vidc/hfi_packetization.c
@@ -1479,10 +1479,18 @@
pr_err("MARK LTR\n");
break;
}
- case HAL_PARAM_VENC_HIER_P_NUM_FRAMES:
+ case HAL_PARAM_VENC_HIER_P_MAX_ENH_LAYERS:
{
pkt->rg_property_data[0] =
- HFI_PROPERTY_PARAM_VENC_HIER_P_NUM_ENH_LAYER;
+ HFI_PROPERTY_PARAM_VENC_HIER_P_MAX_NUM_ENH_LAYER;
+ pkt->rg_property_data[1] = *(u32 *)pdata;
+ pkt->size += sizeof(u32) * 2;
+ break;
+ }
+ case HAL_CONFIG_VENC_HIER_P_NUM_FRAMES:
+ {
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_CONFIG_VENC_HIER_P_ENH_LAYER;
pkt->rg_property_data[1] = *(u32 *)pdata;
pkt->size += sizeof(u32) * 2;
break;
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index 18432dd..030aa29 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -1001,11 +1001,53 @@
return rc;
}
+static int msm_venc_enable_hier_p(struct msm_vidc_inst *inst)
+{
+ int num_enh_layers = 0;
+ u32 property_id = 0;
+ struct hfi_device *hdev = NULL;
+ int rc = 0;
+
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+ return -EINVAL;
+ }
+
+ if (inst->fmts[CAPTURE_PORT]->fourcc != V4L2_PIX_FMT_VP8)
+ return 0;
+
+ num_enh_layers = inst->capability.hier_p.max - 1;
+ if (!num_enh_layers)
+ return 0;
+
+ hdev = inst->core->device;
+ property_id = HAL_PARAM_VENC_HIER_P_MAX_ENH_LAYERS;
+
+ rc = call_hfi_op(hdev, session_set_property,
+ (void *)inst->session, property_id,
+ (void *)&num_enh_layers);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "%s: failed with error = %d\n", __func__, rc);
+ }
+ return rc;
+}
+
static inline int start_streaming(struct msm_vidc_inst *inst)
{
int rc = 0;
struct vb2_buf_entry *temp;
struct list_head *ptr, *next;
+
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+ return -EINVAL;
+ }
+
+ rc = msm_venc_enable_hier_p(inst);
+ if (rc)
+ return rc;
+
if (inst->capability.pixelprocess_capabilities &
HAL_VIDEO_ENCODER_SCALING_CAPABILITY)
rc = msm_comm_check_scaling_supported(inst);
@@ -2102,7 +2144,7 @@
pdata = &markltr;
break;
case V4L2_CID_MPEG_VIDC_VIDEO_HIER_P_NUM_LAYERS:
- property_id = HAL_PARAM_VENC_HIER_P_NUM_FRAMES;
+ property_id = HAL_CONFIG_VENC_HIER_P_NUM_FRAMES;
hier_p_layers = ctrl->val;
if (hier_p_layers > (inst->capability.hier_p.max - 1)) {
dprintk(VIDC_ERR,
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 70114de..3430311 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -1196,6 +1196,8 @@
vb->v4l2_buf.flags |= V4L2_QCOM_BUF_DATA_CORRUPT;
if (fill_buf_done->flags1 & HAL_BUFFERFLAG_DROP_FRAME)
vb->v4l2_buf.flags |= V4L2_QCOM_BUF_DROP_FRAME;
+ if (fill_buf_done->flags1 & HAL_BUFFERFLAG_MBAFF)
+ vb->v4l2_buf.flags |= V4L2_MSM_BUF_FLAG_MBAFF;
switch (fill_buf_done->picture_type) {
case HAL_PICTURE_IDR:
vb->v4l2_buf.flags |= V4L2_QCOM_BUF_FLAG_IDRFRAME;
@@ -1772,10 +1774,16 @@
dprintk(VIDC_ERR, "%s invalid parameters", __func__);
return -EINVAL;
}
- if (inst->state == MSM_VIDC_CORE_INVALID ||
- inst->core->state == VIDC_CORE_INVALID) {
+
+ if (inst->core->state == VIDC_CORE_INVALID) {
dprintk(VIDC_ERR,
- "Core is in bad state can't do load res");
+ "Core is in bad state can't do load res\n");
+ return -EINVAL;
+ }
+
+ if (inst->state == MSM_VIDC_CORE_INVALID) {
+ dprintk(VIDC_ERR,
+ "Instance is in invalid state can't do load res\n");
return -EINVAL;
}
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
index c764758..d7350b6 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
@@ -44,6 +44,7 @@
#define HAL_BUFFERFLAG_READONLY 0x00000200
#define HAL_BUFFERFLAG_ENDOFSUBFRAME 0x00000400
#define HAL_BUFFERFLAG_EOSEQ 0x00200000
+#define HAL_BUFFERFLAG_MBAFF 0x08000000
#define HAL_BUFFERFLAG_DROP_FRAME 0x20000000
@@ -185,7 +186,8 @@
HAL_CONFIG_VENC_MARKLTRFRAME,
HAL_CONFIG_VENC_USELTRFRAME,
HAL_CONFIG_VENC_LTRPERIOD,
- HAL_PARAM_VENC_HIER_P_NUM_FRAMES,
+ HAL_CONFIG_VENC_HIER_P_NUM_FRAMES,
+ HAL_PARAM_VENC_HIER_P_MAX_ENH_LAYERS,
};
enum hal_domain {
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
index 5117266..7f4dd04 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
@@ -305,8 +305,6 @@
(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x018)
#define HFI_PROPERTY_PARAM_VENC_MULTIREF_P \
(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x019)
-#define HFI_PROPERTY_PARAM_VENC_HIER_P_NUM_ENH_LAYER \
- (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x01A)
#define HFI_PROPERTY_PARAM_VENC_H264_NAL_SVC_EXT \
(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x01B)
#define HFI_PROPERTY_PARAM_VENC_LTRMODE \
@@ -319,6 +317,8 @@
(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x01F)
#define HFI_PROPERTY_PARAM_VENC_MAX_NUM_B_FRAMES \
(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x020)
+#define HFI_PROPERTY_PARAM_VENC_HIER_P_MAX_NUM_ENH_LAYER \
+ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x026)
#define HFI_PROPERTY_CONFIG_VENC_COMMON_START \
(HFI_DOMAIN_BASE_VENC + HFI_ARCH_COMMON_OFFSET + 0x6000)
#define HFI_PROPERTY_CONFIG_VENC_TARGET_BITRATE \
@@ -342,6 +342,8 @@
(HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x009)
#define HFI_PROPERTY_CONFIG_VENC_USELTRFRAME \
(HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x00A)
+#define HFI_PROPERTY_CONFIG_VENC_HIER_P_ENH_LAYER \
+ (HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x00B)
#define HFI_PROPERTY_CONFIG_VENC_LTRPERIOD \
(HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x00C)
#define HFI_PROPERTY_CONFIG_VPE_COMMON_START \
diff --git a/drivers/media/platform/msm/wfd/vsg-subdev.c b/drivers/media/platform/msm/wfd/vsg-subdev.c
index 433468e..960e45c 100644
--- a/drivers/media/platform/msm/wfd/vsg-subdev.c
+++ b/drivers/media/platform/msm/wfd/vsg-subdev.c
@@ -337,6 +337,7 @@
static int vsg_start(struct v4l2_subdev *sd)
{
struct vsg_context *context = NULL;
+ int rc = 0;
if (!sd) {
WFD_MSG_ERR("ERROR, invalid arguments into %s\n", __func__);
@@ -345,18 +346,24 @@
context = (struct vsg_context *)sd->dev_priv;
+ mutex_lock(&context->mutex);
if (context->state == VSG_STATE_STARTED) {
WFD_MSG_ERR("VSG not stopped, start not allowed\n");
- return -EINPROGRESS;
+ rc = -EINPROGRESS;
+ goto err_bad_state;
} else if (context->state == VSG_STATE_ERROR) {
WFD_MSG_ERR("VSG in error state, not allowed to restart\n");
- return -ENOTRECOVERABLE;
+ rc = -ENOTRECOVERABLE;
+ goto err_bad_state;
}
context->state = VSG_STATE_STARTED;
hrtimer_start(&context->threshold_timer, ns_to_ktime(context->
max_frame_interval), HRTIMER_MODE_REL);
- return 0;
+
+err_bad_state:
+ mutex_unlock(&context->mutex);
+ return rc;
}
static int vsg_stop(struct v4l2_subdev *sd)
diff --git a/drivers/media/radio/radio-iris.c b/drivers/media/radio/radio-iris.c
index 9f18508..02441ec 100644
--- a/drivers/media/radio/radio-iris.c
+++ b/drivers/media/radio/radio-iris.c
@@ -1892,13 +1892,6 @@
return;
}
- if (radio->mode == FM_RECV_TURNING_ON) {
- radio->mode = FM_RECV;
- iris_q_event(radio, IRIS_EVT_RADIO_READY);
- } else if (radio->mode == FM_TRANS_TURNING_ON) {
- radio->mode = FM_TRANS;
- iris_q_event(radio, IRIS_EVT_RADIO_READY);
- }
radio_hci_req_complete(hdev, rsp->status);
}
@@ -3777,7 +3770,19 @@
radio->mode = FM_OFF;
goto END;
} else {
- initialise_recv(radio);
+ retval = initialise_recv(radio);
+ if (retval < 0) {
+ FMDERR("Error while initialising"\
+ "radio %d\n", retval);
+ hci_cmd(HCI_FM_DISABLE_RECV_CMD,
+ radio->fm_hdev);
+ radio->mode = FM_OFF;
+ goto END;
+ }
+ }
+ if (radio->mode == FM_RECV_TURNING_ON) {
+ radio->mode = FM_RECV;
+ iris_q_event(radio, IRIS_EVT_RADIO_READY);
}
break;
case FM_TRANS:
@@ -3794,7 +3799,19 @@
radio->mode = FM_OFF;
goto END;
} else {
- initialise_trans(radio);
+ retval = initialise_trans(radio);
+ if (retval < 0) {
+ FMDERR("Error while initialising"\
+ "radio %d\n", retval);
+ hci_cmd(HCI_FM_DISABLE_TRANS_CMD,
+ radio->fm_hdev);
+ radio->mode = FM_OFF;
+ goto END;
+ }
+ }
+ if (radio->mode == FM_TRANS_TURNING_ON) {
+ radio->mode = FM_TRANS;
+ iris_q_event(radio, IRIS_EVT_RADIO_READY);
}
break;
case FM_OFF:
diff --git a/drivers/media/video/videobuf2-core.c b/drivers/media/video/videobuf2-core.c
index 668cc73..e5311ce 100644
--- a/drivers/media/video/videobuf2-core.c
+++ b/drivers/media/video/videobuf2-core.c
@@ -1104,9 +1104,13 @@
* consistent after getting driver's lock back.
*/
if (q->memory == V4L2_MEMORY_USERPTR) {
- mmap_sem = ¤t->active_mm->mmap_sem;
+ bool mm_exists = !!current->mm;
+
+ mmap_sem = mm_exists ? ¤t->mm->mmap_sem : NULL;
call_qop(q, wait_prepare, q);
- down_read(mmap_sem);
+ /* kthreads have no userspace, hence no pages to lock */
+ if (mmap_sem)
+ down_read(mmap_sem);
call_qop(q, wait_finish, q);
}
diff --git a/drivers/misc/qfp_fuse.c b/drivers/misc/qfp_fuse.c
index 3a088dc..f271f96 100644
--- a/drivers/misc/qfp_fuse.c
+++ b/drivers/misc/qfp_fuse.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011, 2014 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -28,7 +28,7 @@
/*
* Time QFPROM requires to reliably burn a fuse.
*/
-#define QFPROM_BLOW_TIMEOUT_US 10
+#define QFPROM_BLOW_TIMEOUT_US 20
#define QFPROM_BLOW_TIMER_OFFSET 0x2038
/*
* Denotes number of cycles required to blow the fuse.
@@ -42,6 +42,10 @@
#define QFP_FUSE_READY 0x01
#define QFP_FUSE_OFF 0x00
+#define QFP_FUSE_BUF_SIZE 64
+#define UINT32_MAX (0xFFFFFFFFU)
+
+
struct qfp_priv_t {
uint32_t base;
uint32_t end;
@@ -53,6 +57,23 @@
/* We need only one instance of this for the driver */
static struct qfp_priv_t *qfp_priv;
+static inline bool is_usr_req_valid(const struct qfp_fuse_req *req)
+{
+ uint32_t size = qfp_priv->end - qfp_priv->base;
+ uint32_t req_size;
+
+ if (req->size >= (UINT32_MAX / sizeof(uint32_t)))
+ return false;
+ req_size = req->size * sizeof(uint32_t);
+ if ((req_size == 0) || (req_size > size))
+ return false;
+ if (req->offset >= size)
+ return false;
+ if ((req->offset + req_size) > size)
+ return false;
+
+ return true;
+}
static int qfp_fuse_open(struct inode *inode, struct file *filp)
{
@@ -177,7 +198,9 @@
{
int err = 0;
struct qfp_fuse_req req;
- u32 *buf = NULL;
+ u32 fuse_buf[QFP_FUSE_BUF_SIZE];
+ u32 *buf = fuse_buf;
+ u32 *ptr = NULL;
int i;
/* Verify user arguments. */
@@ -199,25 +222,21 @@
}
/* Check for limits */
- if (!req.size) {
- pr_err("Request size zero.\n");
- err = -EFAULT;
+ if (is_usr_req_valid(&req) == false) {
+ pr_err("Invalid request\n");
+ err = -EINVAL;
break;
}
- if (qfp_priv->base + req.offset + (req.size - 1) * 4 >
- qfp_priv->end) {
- pr_err("Req size exceeds QFPROM addr space\n");
- err = -EFAULT;
- break;
- }
-
- /* Allocate memory for buffer */
- buf = kzalloc(req.size * 4, GFP_KERNEL);
- if (buf == NULL) {
- pr_alert("No memory for data\n");
- err = -ENOMEM;
- break;
+ if (req.size > QFP_FUSE_BUF_SIZE) {
+ /* Allocate memory for buffer */
+ ptr = kzalloc(req.size * 4, GFP_KERNEL);
+ if (ptr == NULL) {
+ pr_alert("No memory for data\n");
+ err = -ENOMEM;
+ break;
+ }
+ buf = ptr;
}
if (mutex_lock_interruptible(&qfp_priv->lock)) {
@@ -251,24 +270,21 @@
break;
}
/* Check for limits */
- if (!req.size) {
- pr_err("Request size zero.\n");
- err = -EFAULT;
- break;
- }
- if (qfp_priv->base + req.offset + (req.size - 1) * 4 >
- qfp_priv->end) {
- pr_err("Req size exceeds QFPROM space\n");
- err = -EFAULT;
+ if (is_usr_req_valid(&req) == false) {
+ pr_err("Invalid request\n");
+ err = -EINVAL;
break;
}
- /* Allocate memory for buffer */
- buf = kzalloc(4 * (req.size), GFP_KERNEL);
- if (buf == NULL) {
- pr_alert("No memory for data\n");
- err = -ENOMEM;
- break;
+ if (req.size > QFP_FUSE_BUF_SIZE) {
+ /* Allocate memory for buffer */
+ ptr = kzalloc(req.size * 4, GFP_KERNEL);
+ if (ptr == NULL) {
+ pr_alert("No memory for data\n");
+ err = -ENOMEM;
+ break;
+ }
+ buf = ptr;
}
/* Copy user data to local buffer */
@@ -296,7 +312,7 @@
pr_err("Invalid ioctl command.\n");
return -ENOTTY;
}
- kfree(buf);
+ kfree(ptr);
return err;
}
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index efafa23..7ad51e6 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -287,7 +287,7 @@
/* Get the handle of the shared fd */
svc->ihandle = ion_import_dma_buf(qseecom.ion_clnt,
listener->ifd_data_fd);
- if (svc->ihandle == NULL) {
+ if (IS_ERR_OR_NULL(svc->ihandle)) {
pr_err("Ion client could not retrieve the handle\n");
return -ENOMEM;
}
@@ -503,26 +503,31 @@
return;
}
-static void __qseecom_decrease_clk_ref_count(enum qseecom_ce_hw_instance ce)
+static int __qseecom_decrease_clk_ref_count(enum qseecom_ce_hw_instance ce)
{
struct qseecom_clk *qclk;
+ int ret = 0;
mutex_lock(&clk_access_lock);
if (ce == CLK_QSEE)
qclk = &qseecom.qsee;
else
qclk = &qseecom.ce_drv;
- if (qclk->clk_access_cnt == 0) {
- mutex_unlock(&clk_access_lock);
- return;
+ if (qclk->clk_access_cnt > 2) {
+ pr_err("Invalid clock ref count %d\n", qclk->clk_access_cnt);
+ ret = -EINVAL;
+ goto err_dec_ref_cnt;
}
- qclk->clk_access_cnt--;
+ if (qclk->clk_access_cnt == 2)
+ qclk->clk_access_cnt--;
+
+err_dec_ref_cnt:
mutex_unlock(&clk_access_lock);
- return;
+ return ret;
}
-static int qseecom_scale_bus_bandwidth_timer(uint32_t mode, uint32_t duration)
+static int qseecom_scale_bus_bandwidth_timer(uint32_t mode)
{
int32_t ret = 0;
int32_t request_mode = INACTIVE;
@@ -537,11 +542,23 @@
request_mode = mode;
}
- __qseecom_set_msm_bus_request(request_mode);
- if (qseecom.timer_running) {
- __qseecom_decrease_clk_ref_count(CLK_QSEE);
- del_timer_sync(&(qseecom.bw_scale_down_timer));
+ ret = __qseecom_set_msm_bus_request(request_mode);
+ if (ret) {
+ pr_err("set msm bus request failed (%d),request_mode (%d)\n",
+ ret, request_mode);
+ goto err_scale_timer;
}
+
+ if (qseecom.timer_running) {
+ ret = __qseecom_decrease_clk_ref_count(CLK_QSEE);
+ if (ret) {
+ pr_err("Failed to decrease clk ref count.\n");
+ goto err_scale_timer;
+ }
+ del_timer_sync(&(qseecom.bw_scale_down_timer));
+ qseecom.timer_running = false;
+ }
+err_scale_timer:
mutex_unlock(&qsee_bw_mutex);
return ret;
}
@@ -598,18 +615,23 @@
return ret;
}
+static void __qseecom_add_bw_scale_down_timer(uint32_t duration)
+{
+ mutex_lock(&qsee_bw_mutex);
+ qseecom.bw_scale_down_timer.expires = jiffies +
+ msecs_to_jiffies(duration);
+ add_timer(&(qseecom.bw_scale_down_timer));
+ qseecom.timer_running = true;
+ mutex_unlock(&qsee_bw_mutex);
+}
+
static void __qseecom_disable_clk_scale_down(struct qseecom_dev_handle *data)
{
if (!qseecom.support_bus_scaling)
qsee_disable_clock_vote(data, CLK_SFPB);
- else {
- mutex_lock(&qsee_bw_mutex);
- qseecom.bw_scale_down_timer.expires = jiffies +
- msecs_to_jiffies(QSEECOM_LOAD_APP_CRYPTO_TIMEOUT);
- add_timer(&(qseecom.bw_scale_down_timer));
- qseecom.timer_running = true;
- mutex_unlock(&qsee_bw_mutex);
- }
+ else
+ __qseecom_add_bw_scale_down_timer(
+ QSEECOM_LOAD_APP_CRYPTO_TIMEOUT);
return;
}
@@ -617,8 +639,9 @@
{
int ret = 0;
if (qseecom.support_bus_scaling) {
- qseecom_scale_bus_bandwidth_timer(
- MEDIUM, QSEECOM_LOAD_APP_CRYPTO_TIMEOUT);
+ ret = qseecom_scale_bus_bandwidth_timer(MEDIUM);
+ if (ret)
+ pr_err("Failed to set bw MEDIUM.\n");
} else {
ret = qsee_vote_for_clock(data, CLK_SFPB);
if (ret)
@@ -1168,10 +1191,9 @@
}
if (qseecom.support_bus_scaling) {
- qseecom_scale_bus_bandwidth_timer(HIGH,
- QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
+ ret = qseecom_scale_bus_bandwidth_timer(HIGH);
if (ret) {
- pr_err("Fail to set bw HIGH%d\n", ret);
+ pr_err("Fail to set bw HIGH\n");
return ret;
}
} else {
@@ -1203,15 +1225,9 @@
qsee_disable_clock_vote(data, CLK_DFAB);
qsee_disable_clock_vote(data, CLK_SFPB);
} else {
- mutex_lock(&qsee_bw_mutex);
- qseecom.bw_scale_down_timer.expires = jiffies +
- msecs_to_jiffies(
+ __qseecom_add_bw_scale_down_timer(
QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
- add_timer(&(qseecom.bw_scale_down_timer));
- qseecom.timer_running = true;
- mutex_unlock(&qsee_bw_mutex);
}
-
goto exit;
}
@@ -1239,12 +1255,8 @@
qsee_disable_clock_vote(data, CLK_DFAB);
qsee_disable_clock_vote(data, CLK_SFPB);
} else {
- mutex_lock(&qsee_bw_mutex);
- qseecom.bw_scale_down_timer.expires = jiffies +
- msecs_to_jiffies(QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
- add_timer(&(qseecom.bw_scale_down_timer));
- qseecom.timer_running = true;
- mutex_unlock(&qsee_bw_mutex);
+ __qseecom_add_bw_scale_down_timer(
+ QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
}
exit:
@@ -1560,7 +1572,7 @@
if (wait_event_freezable(this_lstnr->rcv_req_wq,
__qseecom_listener_has_rcvd_req(data,
this_lstnr))) {
- pr_warning("Interrupted: exiting Listener Service = %d\n",
+ pr_debug("Interrupted: exiting Listener Service = %d\n",
(uint32_t)data->listener.id);
/* woken up for different reason */
return -ERESTARTSYS;
@@ -2079,18 +2091,19 @@
mutex_lock(&app_access_lock);
atomic_inc(&data->ioctl_count);
- if (qseecom.support_bus_scaling)
- qseecom_scale_bus_bandwidth_timer(INACTIVE,
- QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
- ret = __qseecom_send_cmd(data, &req);
if (qseecom.support_bus_scaling) {
- mutex_lock(&qsee_bw_mutex);
- qseecom.bw_scale_down_timer.expires = jiffies +
- msecs_to_jiffies(QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
- add_timer(&(qseecom.bw_scale_down_timer));
- qseecom.timer_running = true;
- mutex_unlock(&qsee_bw_mutex);
+ ret = qseecom_scale_bus_bandwidth_timer(INACTIVE);
+ if (ret) {
+ pr_err("Failed to set bw.\n");
+ atomic_dec(&data->ioctl_count);
+ mutex_unlock(&app_access_lock);
+ return ret;
+ }
}
+ ret = __qseecom_send_cmd(data, &req);
+ if (qseecom.support_bus_scaling)
+ __qseecom_add_bw_scale_down_timer(
+ QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
atomic_dec(&data->ioctl_count);
mutex_unlock(&app_access_lock);
@@ -3210,20 +3223,20 @@
}
/* Only one client allowed here at a time */
mutex_lock(&app_access_lock);
- if (qseecom.support_bus_scaling)
- qseecom_scale_bus_bandwidth_timer(INACTIVE,
- QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
+ if (qseecom.support_bus_scaling) {
+ ret = qseecom_scale_bus_bandwidth_timer(INACTIVE);
+ if (ret) {
+ pr_err("Failed to set bw.\n");
+ ret = -EINVAL;
+ mutex_unlock(&app_access_lock);
+ break;
+ }
+ }
atomic_inc(&data->ioctl_count);
ret = qseecom_send_cmd(data, argp);
- if (qseecom.support_bus_scaling) {
- mutex_lock(&qsee_bw_mutex);
- qseecom.bw_scale_down_timer.expires = jiffies +
- msecs_to_jiffies(
+ if (qseecom.support_bus_scaling)
+ __qseecom_add_bw_scale_down_timer(
QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
- add_timer(&(qseecom.bw_scale_down_timer));
- qseecom.timer_running = true;
- mutex_unlock(&qsee_bw_mutex);
- }
atomic_dec(&data->ioctl_count);
wake_up_all(&data->abort_wq);
mutex_unlock(&app_access_lock);
@@ -3242,20 +3255,21 @@
}
/* Only one client allowed here at a time */
mutex_lock(&app_access_lock);
- if (qseecom.support_bus_scaling)
- qseecom_scale_bus_bandwidth_timer(INACTIVE,
- QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
+ if (qseecom.support_bus_scaling) {
+ ret = qseecom_scale_bus_bandwidth_timer(INACTIVE);
+ if (ret) {
+ pr_err("Failed to set bw.\n");
+ mutex_unlock(&app_access_lock);
+ ret = -EINVAL;
+ break;
+ }
+ }
atomic_inc(&data->ioctl_count);
ret = qseecom_send_modfd_cmd(data, argp);
- if (qseecom.support_bus_scaling) {
- mutex_lock(&qsee_bw_mutex);
- qseecom.bw_scale_down_timer.expires = jiffies +
- msecs_to_jiffies(
+ if (qseecom.support_bus_scaling)
+ __qseecom_add_bw_scale_down_timer(
QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
- add_timer(&(qseecom.bw_scale_down_timer));
- qseecom.timer_running = true;
- mutex_unlock(&qsee_bw_mutex);
- } atomic_dec(&data->ioctl_count);
+ atomic_dec(&data->ioctl_count);
wake_up_all(&data->abort_wq);
mutex_unlock(&app_access_lock);
if (ret)
@@ -3274,7 +3288,7 @@
ret = qseecom_receive_req(data);
atomic_dec(&data->ioctl_count);
wake_up_all(&data->abort_wq);
- if (ret)
+ if (ret && (ret != -ERESTARTSYS))
pr_err("failed qseecom_receive_req: %d\n", ret);
break;
}
@@ -4107,7 +4121,8 @@
qclk = &qseecom.qsee;
if (qseecom.cumulative_mode != INACTIVE) {
- ret = __qseecom_set_msm_bus_request(INACTIVE);
+ ret = msm_bus_scale_client_update_request(
+ qseecom.qsee_perf_client, INACTIVE);
if (ret)
pr_err("Fail to scale down bus\n");
}
@@ -4119,6 +4134,10 @@
clk_disable_unprepare(qclk->ce_core_clk);
if (qclk->ce_bus_clk != NULL)
clk_disable_unprepare(qclk->ce_bus_clk);
+ if (qseecom.timer_running) {
+ del_timer_sync(&(qseecom.bw_scale_down_timer));
+ qseecom.timer_running = false;
+ }
}
mutex_unlock(&clk_access_lock);
return 0;
@@ -4137,9 +4156,11 @@
mode = qseecom.cumulative_mode;
if (qseecom.cumulative_mode != INACTIVE) {
- ret = __qseecom_set_msm_bus_request(mode);
+ ret = msm_bus_scale_client_update_request(
+ qseecom.qsee_perf_client, qseecom.cumulative_mode);
if (ret)
- pr_err("Fail to scale down bus\n");
+ pr_err("Fail to scale up bus to %d\n",
+ qseecom.cumulative_mode);
}
mutex_lock(&clk_access_lock);
@@ -4165,6 +4186,11 @@
qclk->clk_access_cnt = 0;
goto ce_bus_clk_err;
}
+ qseecom.bw_scale_down_timer.expires = jiffies +
+ msecs_to_jiffies(QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
+ add_timer(&(qseecom.bw_scale_down_timer));
+ qseecom.timer_running = true;
+
}
mutex_unlock(&clk_access_lock);
return 0;
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index b36faff..a6fcec5 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -421,10 +421,17 @@
else if (!mmc_card_sdio(card) && mmc_use_core_runtime_pm(card->host))
pm_runtime_enable(&card->dev);
+ if (mmc_card_sdio(card)) {
+ ret = device_init_wakeup(&card->dev, true);
+ if (ret)
+ pr_err("%s: %s: failed to init wakeup: %d\n",
+ mmc_hostname(card->host), __func__, ret);
+ }
ret = device_add(&card->dev);
if (ret)
return ret;
+ device_enable_async_suspend(&card->dev);
if (mmc_use_core_runtime_pm(card->host) && !mmc_card_sdio(card)) {
card->rpm_attrib.show = show_rpm_delay;
card->rpm_attrib.store = store_rpm_delay;
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index c7fa876..c4b9724 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -77,16 +77,40 @@
{
struct mmc_host *host = cls_dev_to_mmc_host(dev);
int ret = 0;
+ unsigned long flags;
if (!mmc_use_core_pm(host))
return 0;
+ spin_lock_irqsave(&host->clk_lock, flags);
+ /*
+ * let the driver know that suspend is in progress and must
+ * be aborted on receiving a sdio card interrupt
+ */
+ host->dev_status = DEV_SUSPENDING;
+ spin_unlock_irqrestore(&host->clk_lock, flags);
if (!pm_runtime_suspended(dev)) {
ret = mmc_suspend_host(host);
if (ret < 0)
pr_err("%s: %s: failed: ret: %d\n", mmc_hostname(host),
__func__, ret);
}
+ /*
+ * If SDIO function driver doesn't want to power off the card,
+ * atleast turn off clocks to allow deep sleep.
+ */
+ if (!ret && host->card && mmc_card_sdio(host->card) &&
+ host->ios.clock) {
+ spin_lock_irqsave(&host->clk_lock, flags);
+ host->clk_old = host->ios.clock;
+ host->ios.clock = 0;
+ host->clk_gated = true;
+ spin_unlock_irqrestore(&host->clk_lock, flags);
+ mmc_set_ios(host);
+ }
+ spin_lock_irqsave(&host->clk_lock, flags);
+ host->dev_status = DEV_SUSPENDED;
+ spin_unlock_irqrestore(&host->clk_lock, flags);
return ret;
}
@@ -104,6 +128,7 @@
pr_err("%s: %s: failed: ret: %d\n", mmc_hostname(host),
__func__, ret);
}
+ host->dev_status = DEV_RESUMED;
return ret;
}
@@ -697,6 +722,7 @@
if (err)
return err;
+ device_enable_async_suspend(&host->class_dev);
led_trigger_register_simple(dev_name(&host->class_dev), &host->led);
#ifdef CONFIG_DEBUG_FS
diff --git a/drivers/mmc/core/quirks.c b/drivers/mmc/core/quirks.c
index 4407d91..d517205 100644
--- a/drivers/mmc/core/quirks.c
+++ b/drivers/mmc/core/quirks.c
@@ -50,6 +50,14 @@
#define SDIO_DEVICE_ID_MSM_QCA_AR6003_2 0x301
#endif
+#ifndef SDIO_DEVICE_ID_MSM_QCA_AR6004_1
+#define SDIO_DEVICE_ID_MSM_QCA_AR6004_1 0x400
+#endif
+
+#ifndef SDIO_DEVICE_ID_MSM_QCA_AR6004_2
+#define SDIO_DEVICE_ID_MSM_QCA_AR6004_2 0x401
+#endif
+
/*
* This hook just adds a quirk for all sdio devices
*/
@@ -78,6 +86,12 @@
SDIO_FIXUP(SDIO_VENDOR_ID_MSM_QCA, SDIO_DEVICE_ID_MSM_QCA_AR6003_2,
remove_quirk, MMC_QUIRK_BROKEN_CLK_GATING),
+ SDIO_FIXUP(SDIO_VENDOR_ID_MSM_QCA, SDIO_DEVICE_ID_MSM_QCA_AR6004_1,
+ remove_quirk, MMC_QUIRK_BROKEN_CLK_GATING),
+
+ SDIO_FIXUP(SDIO_VENDOR_ID_MSM_QCA, SDIO_DEVICE_ID_MSM_QCA_AR6004_2,
+ remove_quirk, MMC_QUIRK_BROKEN_CLK_GATING),
+
SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271,
add_quirk, MMC_QUIRK_NONSTD_FUNC_IF),
diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c
index 3d8ceb4..2b48f77 100644
--- a/drivers/mmc/core/sdio_irq.c
+++ b/drivers/mmc/core/sdio_irq.c
@@ -85,6 +85,7 @@
struct sched_param param = { .sched_priority = 1 };
unsigned long period, idle_period;
int ret;
+ bool ws;
sched_setscheduler(current, SCHED_FIFO, ¶m);
@@ -118,6 +119,17 @@
ret = __mmc_claim_host(host, &host->sdio_irq_thread_abort);
if (ret)
break;
+ ws = false;
+ /*
+ * prevent suspend if it has started when scheduled;
+ * 100 msec (approx. value) should be enough for the system to
+ * resume and attend to the card's request
+ */
+ if ((host->dev_status == DEV_SUSPENDING) ||
+ (host->dev_status == DEV_SUSPENDED)) {
+ pm_wakeup_event(&host->card->dev, 100);
+ ws = true;
+ }
ret = process_sdio_pending_irqs(host);
host->sdio_irq_pending = false;
mmc_release_host(host);
@@ -154,6 +166,12 @@
host->ops->enable_sdio_irq(host, 1);
mmc_host_clk_release(host);
}
+ /*
+ * function drivers would have processed the event from card
+ * unless suspended, hence release wake source
+ */
+ if (ws && (host->dev_status == DEV_RESUMED))
+ pm_relax(&host->card->dev);
if (!kthread_should_stop())
schedule_timeout(period);
set_current_state(TASK_RUNNING);
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 739a237..9b41807 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -31,6 +31,7 @@
#include <linux/delay.h>
#include <linux/scatterlist.h>
#include <linux/slab.h>
+#include <linux/irq.h>
#include <linux/mmc/mmc.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
@@ -38,10 +39,18 @@
#include <linux/dma-mapping.h>
#include <mach/gpio.h>
#include <mach/msm_bus.h>
+#include <mach/mpm.h>
#include <linux/iopoll.h>
#include "sdhci-pltfm.h"
+enum sdc_mpm_pin_state {
+ SDC_DAT1_DISABLE,
+ SDC_DAT1_ENABLE,
+ SDC_DAT1_ENWAKE,
+ SDC_DAT1_DISWAKE,
+};
+
#define SDHCI_VER_100 0x2B
#define CORE_HC_MODE 0x78
#define HC_MODE_EN 0x1
@@ -156,6 +165,9 @@
#define INVALID_TUNING_PHASE -1
+#define sdhci_is_valid_mpm_wakeup_int(_h) ((_h)->pdata->mpm_sdiowakeup_int >= 0)
+#define sdhci_is_valid_gpio_wakeup_int(_h) ((_h)->pdata->sdiowakeup_irq >= 0)
+
static const u32 tuning_block_64[] = {
0x00FF0FFF, 0xCCC3CCFF, 0xFFCC3CC3, 0xEFFEFFFE,
0xDDFFDFFF, 0xFBFFFBFF, 0xFF7FFFBF, 0xEFBDF777,
@@ -283,6 +295,8 @@
struct sdhci_msm_bus_voting_data *voting_data;
u32 *sup_clk_table;
unsigned char sup_clk_cnt;
+ int mpm_sdiowakeup_int;
+ int sdiowakeup_irq;
};
struct sdhci_msm_bus_vote {
@@ -318,6 +332,7 @@
bool calibration_done;
u8 saved_tuning_phase;
atomic_t controller_clock;
+ bool is_sdiowakeup_enabled;
};
enum vdd_io_level {
@@ -1338,7 +1353,7 @@
struct device_node *np = dev->of_node;
u32 bus_width = 0;
u32 cpu_dma_latency;
- int len, i;
+ int len, i, mpm_int;
int clk_table_len;
u32 *clk_table = NULL;
enum of_gpio_flags flags = OF_GPIO_ACTIVE_LOW;
@@ -1433,6 +1448,12 @@
if (of_get_property(np, "qcom,nonremovable", NULL))
pdata->nonremovable = true;
+ if (!of_property_read_u32(np, "qcom,dat1-mpm-int",
+ &mpm_int))
+ pdata->mpm_sdiowakeup_int = mpm_int;
+ else
+ pdata->mpm_sdiowakeup_int = -1;
+
return pdata;
out:
return NULL;
@@ -1933,6 +1954,39 @@
return ret;
}
+/*
+ * Acquire spin-lock host->lock before calling this function
+ */
+static void sdhci_msm_cfg_sdiowakeup_gpio_irq(struct sdhci_host *host,
+ bool enable)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_msm_host *msm_host = pltfm_host->priv;
+
+ if (enable && !msm_host->is_sdiowakeup_enabled)
+ enable_irq(msm_host->pdata->sdiowakeup_irq);
+ else if (!enable && msm_host->is_sdiowakeup_enabled)
+ disable_irq_nosync(msm_host->pdata->sdiowakeup_irq);
+ else
+ dev_warn(&msm_host->pdev->dev, "%s: wakeup to config: %d curr: %d\n",
+ __func__, enable, msm_host->is_sdiowakeup_enabled);
+ msm_host->is_sdiowakeup_enabled = enable;
+}
+
+static irqreturn_t sdhci_msm_sdiowakeup_irq(int irq, void *data)
+{
+ struct sdhci_host *host = (struct sdhci_host *)data;
+ unsigned long flags;
+
+ pr_debug("%s: irq (%d) received\n", __func__, irq);
+
+ spin_lock_irqsave(&host->lock, flags);
+ sdhci_msm_cfg_sdiowakeup_gpio_irq(host, false);
+ spin_unlock_irqrestore(&host->lock, flags);
+
+ return IRQ_HANDLED;
+}
+
static irqreturn_t sdhci_msm_pwr_irq(int irq, void *data)
{
struct sdhci_host *host = (struct sdhci_host *)data;
@@ -2609,6 +2663,38 @@
.enable_controller_clock = sdhci_msm_enable_controller_clock,
};
+static int sdhci_msm_cfg_mpm_pin_wakeup(struct sdhci_host *host, unsigned mode)
+{
+ int ret = 0;
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_msm_host *msm_host = pltfm_host->priv;
+ unsigned int pin = msm_host->pdata->mpm_sdiowakeup_int;
+
+ if (!pin)
+ return 0;
+
+ switch (mode) {
+ case SDC_DAT1_DISABLE:
+ ret = msm_mpm_enable_pin(pin, 0);
+ break;
+ case SDC_DAT1_ENABLE:
+ ret = msm_mpm_set_pin_type(pin, IRQ_TYPE_LEVEL_LOW);
+ if (!ret)
+ ret = msm_mpm_enable_pin(pin, 1);
+ break;
+ case SDC_DAT1_ENWAKE:
+ ret = msm_mpm_set_pin_wake(pin, 1);
+ break;
+ case SDC_DAT1_DISWAKE:
+ ret = msm_mpm_set_pin_wake(pin, 0);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
static int __devinit sdhci_msm_probe(struct platform_device *pdev)
{
struct sdhci_host *host;
@@ -2619,6 +2705,7 @@
u32 vdd_max_current;
u16 host_version;
u32 pwr, irq_status, irq_ctl;
+ unsigned long flags;
pr_debug("%s: Enter %s\n", dev_name(&pdev->dev), __func__);
msm_host = devm_kzalloc(&pdev->dev, sizeof(struct sdhci_msm_host),
@@ -2837,6 +2924,8 @@
host->quirks2 |= SDHCI_QUIRK2_RDWR_TX_ACTIVE_EOT;
}
+ host->quirks2 |= SDHCI_QUIRK2_IGN_DATA_END_BIT_ERROR;
+
/* Setup PWRCTL irq */
msm_host->pwr_irq = platform_get_irq_byname(pdev, "pwr_irq");
if (msm_host->pwr_irq < 0) {
@@ -2891,7 +2980,7 @@
msm_host->mmc->caps2 |= MMC_CAP2_STOP_REQUEST;
msm_host->mmc->caps2 |= MMC_CAP2_ASYNC_SDIO_IRQ_4BIT_MODE;
msm_host->mmc->caps2 |= MMC_CAP2_CORE_PM;
- msm_host->mmc->pm_caps |= MMC_PM_KEEP_POWER;
+ msm_host->mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
if (msm_host->pdata->nonremovable)
msm_host->mmc->caps |= MMC_CAP_NONREMOVABLE;
@@ -2917,6 +3006,27 @@
dev_err(&pdev->dev, "%s: Failed to set dma mask\n", __func__);
}
+ msm_host->pdata->sdiowakeup_irq = platform_get_irq_byname(pdev,
+ "sdiowakeup_irq");
+ if (msm_host->pdata->sdiowakeup_irq >= 0) {
+ msm_host->is_sdiowakeup_enabled = true;
+ ret = request_irq(msm_host->pdata->sdiowakeup_irq,
+ sdhci_msm_sdiowakeup_irq,
+ IRQF_SHARED | IRQF_TRIGGER_LOW,
+ "sdhci-msm sdiowakeup", host);
+ if (ret) {
+ dev_err(&pdev->dev, "%s: request sdiowakeup IRQ %d: failed: %d\n",
+ __func__, msm_host->pdata->sdiowakeup_irq, ret);
+ msm_host->pdata->sdiowakeup_irq = -1;
+ msm_host->is_sdiowakeup_enabled = false;
+ goto free_cd_gpio;
+ } else {
+ spin_lock_irqsave(&host->lock, flags);
+ sdhci_msm_cfg_sdiowakeup_gpio_irq(host, false);
+ spin_unlock_irqrestore(&host->lock, flags);
+ }
+ }
+
ret = sdhci_add_host(host);
if (ret) {
dev_err(&pdev->dev, "Add host failed (%d)\n", ret);
@@ -2950,6 +3060,17 @@
else if (mmc_use_core_runtime_pm(host->mmc))
pm_runtime_enable(&pdev->dev);
+ if (msm_host->pdata->mpm_sdiowakeup_int != -1) {
+ ret = sdhci_msm_cfg_mpm_pin_wakeup(host, SDC_DAT1_ENABLE);
+ if (ret) {
+ pr_err("%s: enabling wakeup: failed: ret: %d\n",
+ mmc_hostname(host->mmc), ret);
+ ret = 0;
+ msm_host->pdata->mpm_sdiowakeup_int = -1;
+ }
+ }
+
+ device_enable_async_suspend(&pdev->dev);
/* Successful initialization */
goto out;
@@ -2961,6 +3082,8 @@
free_cd_gpio:
if (gpio_is_valid(msm_host->pdata->status_gpio))
mmc_cd_gpio_free(msm_host->mmc);
+ if (sdhci_is_valid_gpio_wakeup_int(msm_host))
+ free_irq(msm_host->pdata->sdiowakeup_irq, host);
vreg_deinit:
sdhci_msm_vreg_init(&pdev->dev, msm_host->pdata, false);
bus_unregister:
@@ -3006,6 +3129,12 @@
pm_runtime_disable(&pdev->dev);
sdhci_pltfm_free(pdev);
+ if (sdhci_is_valid_mpm_wakeup_int(msm_host))
+ sdhci_msm_cfg_mpm_pin_wakeup(host, SDC_DAT1_DISABLE);
+
+ if (sdhci_is_valid_gpio_wakeup_int(msm_host))
+ free_irq(msm_host->pdata->sdiowakeup_irq, host);
+
if (gpio_is_valid(msm_host->pdata->status_gpio))
mmc_cd_gpio_free(msm_host->mmc);
@@ -3021,13 +3150,75 @@
return 0;
}
+static int sdhci_msm_cfg_sdio_wakeup(struct sdhci_host *host, bool enable)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_msm_host *msm_host = pltfm_host->priv;
+ unsigned long flags;
+ int ret = 0;
+
+ if (!(host->mmc->card && mmc_card_sdio(host->mmc->card) &&
+ (sdhci_is_valid_mpm_wakeup_int(msm_host) ||
+ sdhci_is_valid_gpio_wakeup_int(msm_host)) &&
+ mmc_card_wake_sdio_irq(host->mmc))) {
+ return 1;
+ }
+
+ spin_lock_irqsave(&host->lock, flags);
+ if (enable) {
+ /* configure DAT1 gpio if applicable */
+ if (sdhci_is_valid_gpio_wakeup_int(msm_host)) {
+ ret = enable_irq_wake(msm_host->pdata->sdiowakeup_irq);
+ if (!ret)
+ sdhci_msm_cfg_sdiowakeup_gpio_irq(host, true);
+ goto out;
+ } else {
+ ret = sdhci_msm_cfg_mpm_pin_wakeup(host,
+ SDC_DAT1_ENWAKE);
+ if (ret)
+ goto out;
+ ret = enable_irq_wake(host->irq);
+ if (ret)
+ sdhci_msm_cfg_mpm_pin_wakeup(host,
+ SDC_DAT1_DISWAKE);
+ }
+ } else {
+ if (sdhci_is_valid_gpio_wakeup_int(msm_host)) {
+ ret = disable_irq_wake(msm_host->pdata->sdiowakeup_irq);
+ sdhci_msm_cfg_sdiowakeup_gpio_irq(host, false);
+ } else {
+ ret = sdhci_msm_cfg_mpm_pin_wakeup(host,
+ SDC_DAT1_DISWAKE);
+ if (ret)
+ goto out;
+ ret = disable_irq_wake(host->irq);
+ }
+ }
+out:
+ if (ret)
+ pr_err("%s: %s: %sable wakeup: failed: %d gpio: %d mpm: %d\n",
+ mmc_hostname(host->mmc), __func__, enable ? "en" : "dis",
+ ret, msm_host->pdata->sdiowakeup_irq,
+ msm_host->pdata->mpm_sdiowakeup_int);
+ spin_unlock_irqrestore(&host->lock, flags);
+ return ret;
+}
+
static int sdhci_msm_runtime_suspend(struct device *dev)
{
struct sdhci_host *host = dev_get_drvdata(dev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_msm_host *msm_host = pltfm_host->priv;
+ int ret;
+
+ ret = sdhci_msm_cfg_sdio_wakeup(host, true);
+ /* pwr_irq is not monitored by mpm on suspend, hence disable it */
+ if (!ret)
+ goto skip_disable_host_irq;
disable_irq(host->irq);
+
+skip_disable_host_irq:
disable_irq(msm_host->pwr_irq);
/*
@@ -3048,10 +3239,17 @@
struct sdhci_host *host = dev_get_drvdata(dev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_msm_host *msm_host = pltfm_host->priv;
+ int ret;
- enable_irq(msm_host->pwr_irq);
+ ret = sdhci_msm_cfg_sdio_wakeup(host, false);
+ if (!ret)
+ goto skip_enable_host_irq;
+
enable_irq(host->irq);
+skip_enable_host_irq:
+ enable_irq(msm_host->pwr_irq);
+
return 0;
}
@@ -3103,6 +3301,26 @@
out:
return ret;
}
+
+static int sdhci_msm_suspend_noirq(struct device *dev)
+{
+ struct sdhci_host *host = dev_get_drvdata(dev);
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_msm_host *msm_host = pltfm_host->priv;
+ int ret = 0;
+
+ /*
+ * ksdioirqd may get scheduled after sdhc suspend, hence retry
+ * suspend in case the clocks are ON
+ */
+ if (atomic_read(&msm_host->clks_on)) {
+ pr_warn("%s: %s: clock ON after suspend, aborting suspend\n",
+ mmc_hostname(host->mmc), __func__);
+ ret = -EAGAIN;
+ }
+
+ return ret;
+}
#endif
#ifdef CONFIG_PM
@@ -3110,6 +3328,7 @@
SET_SYSTEM_SLEEP_PM_OPS(sdhci_msm_suspend, sdhci_msm_resume)
SET_RUNTIME_PM_OPS(sdhci_msm_runtime_suspend, sdhci_msm_runtime_resume,
NULL)
+ .suspend_noirq = sdhci_msm_suspend_noirq,
};
#define SDHCI_MSM_PMOPS (&sdhci_msm_pmops)
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 822548e..32ff175 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -32,6 +32,7 @@
#include "sdhci.h"
#define DRIVER_NAME "sdhci"
+#define SDHCI_SUSPEND_TIMEOUT 300 /* 300 ms */
#define DBG(f, x...) \
pr_debug(DRIVER_NAME " [%s()]: " f, __func__,## x)
@@ -68,6 +69,12 @@
}
#endif
+static inline int sdhci_get_async_int_status(struct sdhci_host *host)
+{
+ return (sdhci_readw(host, SDHCI_HOST_CONTROL2) &
+ SDHCI_CTRL_ASYNC_INT_ENABLE) >> 14;
+}
+
static void sdhci_dump_state(struct sdhci_host *host)
{
struct mmc_host *mmc = host->mmc;
@@ -1579,6 +1586,33 @@
spin_unlock_irqrestore(&host->lock, flags);
}
+static void sdhci_cfg_async_intr(struct sdhci_host *host, bool enable)
+{
+ if (!host->async_int_supp)
+ return;
+
+ if (enable)
+ sdhci_writew(host,
+ sdhci_readw(host, SDHCI_HOST_CONTROL2) |
+ SDHCI_CTRL_ASYNC_INT_ENABLE,
+ SDHCI_HOST_CONTROL2);
+ else
+ sdhci_writew(host, sdhci_readw(host, SDHCI_HOST_CONTROL2) &
+ ~SDHCI_CTRL_ASYNC_INT_ENABLE,
+ SDHCI_HOST_CONTROL2);
+}
+
+static void sdhci_cfg_irq(struct sdhci_host *host, bool enable)
+{
+ if (enable && !host->irq_enabled) {
+ enable_irq(host->irq);
+ host->irq_enabled = true;
+ } else if (!enable && host->irq_enabled) {
+ disable_irq_nosync(host->irq);
+ host->irq_enabled = false;
+ }
+}
+
static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
{
unsigned long flags;
@@ -1594,9 +1628,26 @@
return;
}
- if (ios->clock)
+ spin_lock_irqsave(&host->lock, flags);
+ /* lock is being released intermittently below, hence disable irq */
+ sdhci_cfg_irq(host, false);
+ spin_unlock_irqrestore(&host->lock, flags);
+ if (ios->clock) {
sdhci_set_clock(host, ios->clock);
-
+ if (host->async_int_supp && sdhci_get_async_int_status(host)) {
+ if (host->disable_sdio_irq_deferred) {
+ pr_debug("%s: %s: disable sdio irq\n",
+ mmc_hostname(host->mmc), __func__);
+ host->mmc->ops->enable_sdio_irq(host->mmc, 0);
+ host->disable_sdio_irq_deferred = false;
+ }
+ spin_lock_irqsave(&host->lock, flags);
+ sdhci_cfg_async_intr(host, false);
+ spin_unlock_irqrestore(&host->lock, flags);
+ pr_debug("%s: %s: unconfig async intr\n",
+ mmc_hostname(host->mmc), __func__);
+ }
+ }
/*
* The controller clocks may be off during power-up and we may end up
* enabling card clock before giving power to the card. Hence, during
@@ -1622,6 +1673,7 @@
}
spin_lock_irqsave(&host->lock, flags);
if (!host->clock) {
+ sdhci_cfg_irq(host, true);
spin_unlock_irqrestore(&host->lock, flags);
mutex_unlock(&host->ios_mutex);
return;
@@ -1781,9 +1833,18 @@
if (host->vmmc && vdd_bit != -1)
mmc_regulator_set_ocr(host->mmc, host->vmmc, vdd_bit);
}
- if (!ios->clock)
+ if (!ios->clock) {
+ if (host->async_int_supp && host->mmc->card &&
+ mmc_card_sdio(host->mmc->card)) {
+ sdhci_cfg_async_intr(host, true);
+ pr_debug("%s: %s: config async intr\n",
+ mmc_hostname(host->mmc), __func__);
+ }
sdhci_set_clock(host, ios->clock);
-
+ }
+ spin_lock_irqsave(&host->lock, flags);
+ sdhci_cfg_irq(host, true);
+ spin_unlock_irqrestore(&host->lock, flags);
mmiowb();
mutex_unlock(&host->ios_mutex);
}
@@ -1863,6 +1924,14 @@
if (host->flags & SDHCI_DEVICE_DEAD)
goto out;
+ if (!enable && !host->clock) {
+ pr_debug("%s: %s: defered disabling card intr\n",
+ host->mmc ? mmc_hostname(host->mmc) : "null",
+ __func__);
+ host->disable_sdio_irq_deferred = true;
+ return;
+ }
+
if (enable)
host->flags |= SDHCI_SDIO_IRQ_ENABLED;
else
@@ -2742,6 +2811,23 @@
return IRQ_HANDLED;
}
+ if (!host->clock && host->mmc->card &&
+ mmc_card_sdio(host->mmc->card)) {
+ /* SDIO async. interrupt is level-sensitive */
+ sdhci_cfg_irq(host, false);
+ pr_debug("%s: got async-irq: clocks: %d gated: %d host-irq[en:1/dis:0]: %d\n",
+ mmc_hostname(host->mmc), host->clock,
+ host->mmc->clk_gated, host->irq_enabled);
+ spin_unlock(&host->lock);
+ /* prevent suspend till the ksdioirqd runs or resume happens */
+ if ((host->mmc->dev_status == DEV_SUSPENDING) ||
+ (host->mmc->dev_status == DEV_SUSPENDED))
+ pm_wakeup_event(&host->mmc->card->dev,
+ SDHCI_SUSPEND_TIMEOUT);
+ else
+ mmc_signal_sdio_irq(host->mmc);
+ return IRQ_HANDLED;
+ }
intmask = sdhci_readl(host, SDHCI_INT_STATUS);
if (!intmask || intmask == 0xffffffff) {
@@ -2837,9 +2923,13 @@
/*
* We have to delay this as it calls back into the driver.
*/
- if (cardint)
+ if (cardint) {
+ /* clks are on, but suspend may be in progress */
+ if (host->mmc->dev_status == DEV_SUSPENDING)
+ pm_wakeup_event(&host->mmc->card->dev,
+ SDHCI_SUSPEND_TIMEOUT);
mmc_signal_sdio_irq(host->mmc);
-
+ }
return result;
}
@@ -3489,6 +3579,7 @@
if (ret)
goto untasklet;
+ host->irq_enabled = true;
host->vmmc = regulator_get(mmc_dev(mmc), "vmmc");
if (IS_ERR(host->vmmc)) {
pr_info("%s: no vmmc regulator found\n", mmc_hostname(mmc));
@@ -3532,8 +3623,12 @@
mmc_hostname(mmc), ret);
}
+ if (caps[0] & SDHCI_ASYNC_INTR)
+ host->async_int_supp = true;
mmc_add_host(mmc);
+ if (host->quirks2 & SDHCI_QUIRK2_IGN_DATA_END_BIT_ERROR)
+ sdhci_clear_set_irqs(host, SDHCI_INT_DATA_END_BIT, 0);
pr_info("%s: SDHCI controller on %s [%s] using %s\n",
mmc_hostname(mmc), host->hw_name, dev_name(mmc_dev(mmc)),
(host->flags & SDHCI_USE_ADMA) ? "ADMA" :
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index db4806d..8c2320b 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -175,6 +175,7 @@
#define SDHCI_CTRL_DRV_TYPE_D 0x0030
#define SDHCI_CTRL_EXEC_TUNING 0x0040
#define SDHCI_CTRL_TUNED_CLK 0x0080
+#define SDHCI_CTRL_ASYNC_INT_ENABLE 0x4000
#define SDHCI_CTRL_PRESET_VAL_ENABLE 0x8000
#define SDHCI_CAPABILITIES 0x40
@@ -195,6 +196,7 @@
#define SDHCI_CAN_VDD_300 0x02000000
#define SDHCI_CAN_VDD_180 0x04000000
#define SDHCI_CAN_64BIT 0x10000000
+#define SDHCI_ASYNC_INTR 0x20000000
#define SDHCI_SUPPORT_SDR50 0x00000001
#define SDHCI_SUPPORT_SDR104 0x00000002
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index a3e88b4..d3d8d0e 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -147,6 +147,7 @@
#define PRONTO_PLL_STATUS_OFFSET 0x1c
#define MSM_PRONTO_MCU_BASE 0xfb080c00
+#define MCU_APB2PHY_STATUS_OFFSET 0xec
#define MCU_CBR_CCAHB_ERR_OFFSET 0x380
#define MCU_CBR_CAHB_ERR_OFFSET 0x384
#define MCU_CBR_CCAHB_TIMEOUT_OFFSET 0x388
@@ -741,6 +742,10 @@
reg = readl_relaxed(penv->wlan_tx_phy_aborts);
pr_err("WLAN_TX_PHY_ABORTS %08x\n", reg);
+ reg_addr = penv->pronto_mcu_base + MCU_APB2PHY_STATUS_OFFSET;
+ reg = readl_relaxed(reg_addr);
+ pr_err("MCU_APB2PHY_STATUS %08x\n", reg);
+
reg_addr = penv->pronto_mcu_base + MCU_CBR_CCAHB_ERR_OFFSET;
reg = readl_relaxed(reg_addr);
pr_err("MCU_CBR_CCAHB_ERR %08x\n", reg);
diff --git a/drivers/nfc/nfc-nci.c b/drivers/nfc/nfc-nci.c
index a44c06c..8cd4bd1 100644
--- a/drivers/nfc/nfc-nci.c
+++ b/drivers/nfc/nfc-nci.c
@@ -13,6 +13,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
+#include <linux/reboot.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/irq.h>
@@ -47,7 +48,7 @@
MODULE_DEVICE_TABLE(of, msm_match_table);
#define MAX_BUFFER_SIZE (780)
-#define PACKET_MAX_LENGTH (258)
+#define PACKET_MAX_LENGTH (258)
/* Read data */
#define PACKET_HEADER_SIZE_NCI (4)
#define PACKET_TYPE_NCI (16)
@@ -58,7 +59,7 @@
#define NTF_TIMEOUT (10000)
#define CORE_RESET_RSP_GID (0x60)
#define CORE_RESET_OID (0x00)
-#define CORE_RST_NTF_LENGTH (0x02)
+#define CORE_RST_NTF_LENGTH (0x02)
static void clk_req_update(struct work_struct *work);
@@ -115,6 +116,9 @@
static int ftm_werr_code;
+unsigned int disable_ctrl;
+bool region2_sent;
+
static void qca199x_init_stat(struct qca199x_dev *qca199x_dev)
{
qca199x_dev->count_irq = 0;
@@ -491,6 +495,12 @@
}
mutex_unlock(&qca199x_dev->read_mutex);
+ /* If we detect a Region2 command prior to power-down */
+ if ((tmp[0] == 0x2F) && (tmp[1] == 0x01) && (tmp[2] == 0x02) &&
+ (tmp[3] == 0x08) && (tmp[4] == 0x00)) {
+ region2_sent = true;
+ }
+
return ret;
}
@@ -606,7 +616,7 @@
if (r < 0)
goto err_req;
/*
- Also, set flag for initial NCI write following resetas
+ Also, set flag for initial NCI write following reset as
may wish to do some house keeping. Ensure no pending
messages in NFCC buffers which may be wrongly
construed as response to initial message
@@ -718,7 +728,7 @@
int r = 0;
unsigned short slave_addr = 0xE;
unsigned short curr_addr;
-
+ unsigned char raw_nci_wake[] = {0x10, 0x0F};
unsigned char raw_chip_version_addr = 0x00;
unsigned char raw_chip_rev_id_addr = 0x9C;
unsigned char raw_chip_version = 0xFF;
@@ -728,9 +738,22 @@
platform_data = qca199x_dev->client->dev.platform_data;
+ /*
+ * Always wake up chip when reading 0x9C, otherwise this
+ * register is not updated
+ */
+ curr_addr = qca199x_dev->client->addr;
+ qca199x_dev->client->addr = slave_addr;
+ r = nfc_i2c_write(qca199x_dev->client, &raw_nci_wake[0],
+ sizeof(raw_nci_wake));
+ r = sizeof(raw_nci_wake);
+ if (r != sizeof(raw_nci_wake))
+ goto invalid_wake_up;
+ qca199x_dev->state = NFCC_STATE_NORMAL_WAKE;
+
+ /* sleep to ensure the NFCC has time to wake up */
+ usleep(100);
if (arg == 0) {
- curr_addr = qca199x_dev->client->addr;
- qca199x_dev->client->addr = slave_addr;
r = nfc_i2c_write(qca199x_dev->client,
&raw_chip_version_addr, 1);
if (r < 0)
@@ -739,21 +762,19 @@
r = i2c_master_recv(qca199x_dev->client, &raw_chip_version, 1);
/* Restore original NFCC slave I2C address */
qca199x_dev->client->addr = curr_addr;
- }
- if (arg == 1) {
- curr_addr = qca199x_dev->client->addr;
- qca199x_dev->client->addr = slave_addr;
+ } else if (arg == 1) {
r = nfc_i2c_write(qca199x_dev->client,
&raw_chip_rev_id_addr, 1);
if (r < 0)
goto invalid_wr;
- usleep(10);
+ usleep(20);
r = i2c_master_recv(qca199x_dev->client, &raw_chip_version, 1);
/* Restore original NFCC slave I2C address */
qca199x_dev->client->addr = curr_addr;
}
-
return raw_chip_version;
+invalid_wake_up:
+ raw_chip_version = 0xFE;
invalid_wr:
raw_chip_version = 0xFF;
dev_err(&qca199x_dev->client->dev,
@@ -929,121 +950,117 @@
if (r < 0)
goto err_init;
- if (0x10 != (0x10 & buf)) {
- RAW(s73, 0x02);
+ RAW(s73, 0x02);
- r = nfc_i2c_write(client, &raw_s73[0], sizeof(raw_s73));
- if (r < 0)
- goto err_init;
-
- usleep(1000);
- RAW(1p8_CONTROL_011, XTAL_CLOCK | 0x01);
-
- r = nfc_i2c_write(client, &raw_1p8_CONTROL_011[0],
- sizeof(raw_1p8_CONTROL_011));
- if (r < 0)
- goto err_init;
-
- usleep(1000);
- RAW(1P8_CONTROL_010, (0x8));
- r = nfc_i2c_write(client, &raw_1P8_CONTROL_010[0],
- sizeof(raw_1P8_CONTROL_010));
- if (r < 0)
- goto err_init;
-
- usleep(10000); /* 10ms wait */
- RAW(1P8_CONTROL_010, (0xC));
- r = nfc_i2c_write(client, &raw_1P8_CONTROL_010[0],
- sizeof(raw_1P8_CONTROL_010));
- if (r < 0)
- goto err_init;
-
- usleep(100); /* 100uS wait */
- RAW(1P8_X0_0B0, (FREQ_SEL_19));
- r = nfc_i2c_write(client, &raw_1P8_X0_0B0[0],
- sizeof(raw_1P8_X0_0B0));
- if (r < 0)
- goto err_init;
-
- usleep(1000);
-
- /* PWR_EN = 1 */
- RAW(1P8_CONTROL_010, (0xd));
- r = nfc_i2c_write(client, &raw_1P8_CONTROL_010[0],
- sizeof(raw_1P8_CONTROL_010));
- if (r < 0)
- goto err_init;
-
-
- usleep(20000); /* 20ms wait */
- /* LS_EN = 1 */
- RAW(1P8_CONTROL_010, 0xF);
- r = nfc_i2c_write(client, &raw_1P8_CONTROL_010[0],
- sizeof(raw_1P8_CONTROL_010));
- if (r < 0)
- goto err_init;
-
- usleep(20000); /* 20ms wait */
-
- /* Enable the PMIC clock */
- RAW(1P8_PAD_CFG_CLK_REQ, (0x1));
- r = nfc_i2c_write(client, &raw_1P8_PAD_CFG_CLK_REQ[0],
- sizeof(raw_1P8_PAD_CFG_CLK_REQ));
- if (r < 0)
- goto err_init;
-
- usleep(1000);
-
- RAW(1P8_PAD_CFG_PWR_REQ, (0x1));
- r = nfc_i2c_write(client, &raw_1P8_PAD_CFG_PWR_REQ[0],
- sizeof(raw_1P8_PAD_CFG_PWR_REQ));
- if (r < 0)
- goto err_init;
-
- usleep(1000);
-
- RAW(slave2, 0x10);
- r = nfc_i2c_write(client, &raw_slave2[0], sizeof(raw_slave2));
- if (r < 0)
- goto err_init;
-
- usleep(1000);
-
- RAW(slave1, NCI_I2C_SLAVE);
- r = nfc_i2c_write(client, &raw_slave1[0], sizeof(raw_slave1));
- if (r < 0)
- goto err_init;
-
- usleep(1000);
-
- /* QCA199x NFCC CPU should now boot... */
- r = i2c_master_recv(client, &raw_slave1_rd, 1);
- /* Talk on NCI slave address NCI_I2C_SLAVE 0x2C*/
- client->addr = NCI_I2C_SLAVE;
-
- /*
- Start with small delay and then we will poll until we
- get a core reset notification - This is time for chip
- & NFCC controller to come-up.
- */
- usleep(1000); /* 1 ms */
-
- do {
- ret = i2c_master_recv(client, rsp, 5);
- /* Found core reset notification */
- if (((rsp[0] == CORE_RESET_RSP_GID) &&
- (rsp[1] == CORE_RESET_OID) &&
- (rsp[2] == CORE_RST_NTF_LENGTH))
- || time_taken == NTF_TIMEOUT) {
- core_reset_completed = true;
- }
- usleep(10); /* 10us sleep before retry */
- time_taken++;
- } while (!core_reset_completed);
- r = 0;
- } else {
+ r = nfc_i2c_write(client, &raw_s73[0], sizeof(raw_s73));
+ if (r < 0)
goto err_init;
- }
+
+ usleep(1000);
+ RAW(1p8_CONTROL_011, XTAL_CLOCK | 0x01);
+
+ r = nfc_i2c_write(client, &raw_1p8_CONTROL_011[0],
+ sizeof(raw_1p8_CONTROL_011));
+ if (r < 0)
+ goto err_init;
+
+ usleep(1000);
+ RAW(1P8_CONTROL_010, (0x8));
+ r = nfc_i2c_write(client, &raw_1P8_CONTROL_010[0],
+ sizeof(raw_1P8_CONTROL_010));
+ if (r < 0)
+ goto err_init;
+
+ usleep(10000); /* 10ms wait */
+ RAW(1P8_CONTROL_010, (0xC));
+ r = nfc_i2c_write(client, &raw_1P8_CONTROL_010[0],
+ sizeof(raw_1P8_CONTROL_010));
+ if (r < 0)
+ goto err_init;
+
+ usleep(100); /* 100uS wait */
+ RAW(1P8_X0_0B0, (FREQ_SEL_19));
+ r = nfc_i2c_write(client, &raw_1P8_X0_0B0[0],
+ sizeof(raw_1P8_X0_0B0));
+ if (r < 0)
+ goto err_init;
+
+ usleep(1000);
+
+ /* PWR_EN = 1 */
+ RAW(1P8_CONTROL_010, (0xd));
+ r = nfc_i2c_write(client, &raw_1P8_CONTROL_010[0],
+ sizeof(raw_1P8_CONTROL_010));
+ if (r < 0)
+ goto err_init;
+
+
+ usleep(20000); /* 20ms wait */
+ /* LS_EN = 1 */
+ RAW(1P8_CONTROL_010, 0xF);
+ r = nfc_i2c_write(client, &raw_1P8_CONTROL_010[0],
+ sizeof(raw_1P8_CONTROL_010));
+ if (r < 0)
+ goto err_init;
+
+ usleep(20000); /* 20ms wait */
+
+ /* Enable the PMIC clock */
+ RAW(1P8_PAD_CFG_CLK_REQ, (0x1));
+ r = nfc_i2c_write(client, &raw_1P8_PAD_CFG_CLK_REQ[0],
+ sizeof(raw_1P8_PAD_CFG_CLK_REQ));
+ if (r < 0)
+ goto err_init;
+
+ usleep(1000);
+
+ RAW(1P8_PAD_CFG_PWR_REQ, (0x1));
+ r = nfc_i2c_write(client, &raw_1P8_PAD_CFG_PWR_REQ[0],
+ sizeof(raw_1P8_PAD_CFG_PWR_REQ));
+ if (r < 0)
+ goto err_init;
+
+ usleep(1000);
+
+ RAW(slave2, 0x10);
+ r = nfc_i2c_write(client, &raw_slave2[0], sizeof(raw_slave2));
+ if (r < 0)
+ goto err_init;
+
+ usleep(1000);
+
+ RAW(slave1, NCI_I2C_SLAVE);
+ r = nfc_i2c_write(client, &raw_slave1[0], sizeof(raw_slave1));
+ if (r < 0)
+ goto err_init;
+
+ usleep(1000);
+
+ /* QCA199x NFCC CPU should now boot... */
+ r = i2c_master_recv(client, &raw_slave1_rd, 1);
+ /* Talk on NCI slave address NCI_I2C_SLAVE 0x2C*/
+ client->addr = NCI_I2C_SLAVE;
+
+ /*
+ Start with small delay and then we will poll until we
+ get a core reset notification - This is time for chip
+ & NFCC controller to come-up.
+ */
+ usleep(1000); /* 1 ms */
+
+ do {
+ ret = i2c_master_recv(client, rsp, 5);
+ /* Found core reset notification */
+ if (((rsp[0] == CORE_RESET_RSP_GID) &&
+ (rsp[1] == CORE_RESET_OID) &&
+ (rsp[2] == CORE_RST_NTF_LENGTH))
+ || time_taken == NTF_TIMEOUT) {
+ core_reset_completed = true;
+ }
+ usleep(10); /* 10us sleep before retry */
+ time_taken++;
+ } while (!core_reset_completed);
+ r = 0;
return r;
err_init:
r = 1;
@@ -1143,6 +1160,7 @@
pdata->dis_gpio = of_get_named_gpio(np, "qcom,dis-gpio", 0);
if ((!gpio_is_valid(pdata->dis_gpio)))
return -EINVAL;
+ disable_ctrl = pdata->dis_gpio;
pdata->irq_gpio = of_get_named_gpio(np, "qcom,irq-gpio", 0);
if ((!gpio_is_valid(pdata->irq_gpio)))
@@ -1246,8 +1264,12 @@
goto err_free_dev;
}
- /* Put device in ULPM */
- gpio_set_value(platform_data->dis_gpio, 0);
+ /* Guarantee that the NFCC starts in a clean state. */
+ gpio_set_value(platform_data->dis_gpio, 1);/* HPD */
+ usleep(200);
+ gpio_set_value(platform_data->dis_gpio, 0);/* ULPM */
+ usleep(200);
+
r = nfcc_hw_check(client, platform_data->reg);
if (r) {
/* We don't think there is hardware but just in case HPD */
@@ -1439,6 +1461,10 @@
}
i2c_set_clientdata(client, qca199x_dev);
gpio_set_value(platform_data->dis_gpio, 1);
+
+ /* To keep track if region2 command has been sent to controller */
+ region2_sent = false;
+
dev_dbg(&client->dev,
"nfc-nci probe: %s, probing qca1990 exited successfully\n",
__func__);
@@ -1513,17 +1539,52 @@
},
};
+
+static int nfcc_reboot(struct notifier_block *notifier, unsigned long val,
+ void *v)
+{
+ /*
+ * Set DISABLE=1 *ONLY* if the NFC service has been disabled.
+ * This will put NFCC into HPD(Hard Power Down) state for power
+ * saving when powering down(Low Batt. or Power off handset)
+ * If user requires NFC and CE mode when powered down(PD) the
+ * middleware puts NFCC into region2 prior to PD. In this case
+ * we DO NOT HPD chip as this will trash Region2 and CE support
+ * when handset is PD.
+ */
+ if (region2_sent == false) {
+ /* HPD the NFCC */
+ gpio_set_value(disable_ctrl, 1);
+ }
+ return NOTIFY_OK;
+}
+
+
+static struct notifier_block nfcc_notifier = {
+ .notifier_call = nfcc_reboot,
+ .next = NULL,
+ .priority = 0
+};
+
/*
* module load/unload record keeping
*/
static int __init qca199x_dev_init(void)
{
+ int ret;
+
+ ret = register_reboot_notifier(&nfcc_notifier);
+ if (ret) {
+ pr_err("cannot register reboot notifier (err=%d)\n", ret);
+ return ret;
+ }
return i2c_add_driver(&qca199x);
}
module_init(qca199x_dev_init);
static void __exit qca199x_dev_exit(void)
{
+ unregister_reboot_notifier(&nfcc_notifier);
i2c_del_driver(&qca199x);
}
module_exit(qca199x_dev_exit);
diff --git a/drivers/platform/msm/ipa/ipa.c b/drivers/platform/msm/ipa/ipa.c
index 20603f5..c93ec5f 100644
--- a/drivers/platform/msm/ipa/ipa.c
+++ b/drivers/platform/msm/ipa/ipa.c
@@ -544,6 +544,13 @@
retval = -EFAULT;
break;
}
+
+ if (((struct ipa_ioc_query_intf_tx_props *)header)->num_tx_props
+ > IPA_NUM_PROPS_MAX) {
+ retval = -EFAULT;
+ break;
+ }
+
pyld_sz = sz + ((struct ipa_ioc_query_intf_tx_props *)
header)->num_tx_props *
sizeof(struct ipa_ioc_tx_intf_prop);
@@ -572,6 +579,13 @@
retval = -EFAULT;
break;
}
+
+ if (((struct ipa_ioc_query_intf_rx_props *)header)->num_rx_props
+ > IPA_NUM_PROPS_MAX) {
+ retval = -EFAULT;
+ break;
+ }
+
pyld_sz = sz + ((struct ipa_ioc_query_intf_rx_props *)
header)->num_rx_props *
sizeof(struct ipa_ioc_rx_intf_prop);
diff --git a/drivers/platform/msm/ipa/ipa_intf.c b/drivers/platform/msm/ipa/ipa_intf.c
index 5ee1929..ea5c97f 100644
--- a/drivers/platform/msm/ipa/ipa_intf.c
+++ b/drivers/platform/msm/ipa/ipa_intf.c
@@ -60,6 +60,18 @@
return -EINVAL;
}
+ if (tx && tx->num_props > IPA_NUM_PROPS_MAX) {
+ IPAERR("invalid tx num_props=%d max=%d\n", tx->num_props,
+ IPA_NUM_PROPS_MAX);
+ return -EINVAL;
+ }
+
+ if (rx && rx->num_props > IPA_NUM_PROPS_MAX) {
+ IPAERR("invalid rx num_props=%d max=%d\n", rx->num_props,
+ IPA_NUM_PROPS_MAX);
+ return -EINVAL;
+ }
+
len = sizeof(struct ipa_intf);
intf = kzalloc(len, GFP_KERNEL);
if (intf == NULL) {
diff --git a/drivers/platform/msm/qpnp-power-on.c b/drivers/platform/msm/qpnp-power-on.c
index 0ef2639..462bd3b 100644
--- a/drivers/platform/msm/qpnp-power-on.c
+++ b/drivers/platform/msm/qpnp-power-on.c
@@ -24,6 +24,13 @@
#include <linux/log2.h>
#include <linux/qpnp/power-on.h>
+#define PMIC_VER_8941 0x01
+#define PMIC_VERSION_REG 0x0105
+#define PMIC_VERSION_REV4_REG 0x0103
+
+#define PMIC8941_V1_REV4 0x01
+#define PMIC8941_V2_REV4 0x02
+
/* Common PNP defines */
#define QPNP_PON_REVISION2(base) (base + 0x01)
@@ -36,6 +43,7 @@
#define QPNP_PON_REASON1(base) (base + 0x8)
#define QPNP_PON_WARM_RESET_REASON1(base) (base + 0xA)
#define QPNP_PON_WARM_RESET_REASON2(base) (base + 0xB)
+#define QPNP_POFF_REASON1(base) (base + 0xC)
#define QPNP_PON_KPDPWR_S1_TIMER(base) (base + 0x40)
#define QPNP_PON_KPDPWR_S2_TIMER(base) (base + 0x41)
#define QPNP_PON_KPDPWR_S2_CNTL(base) (base + 0x42)
@@ -93,7 +101,8 @@
#define QPNP_PON_S3_DBC_DELAY_MASK 0x07
#define QPNP_PON_RESET_TYPE_MAX 0xF
#define PON_S1_COUNT_MAX 0xF
-#define PON_REASON_MAX 8
+#define QPNP_PON_MIN_DBC_US (USEC_PER_SEC / 64)
+#define QPNP_PON_MAX_DBC_US (USEC_PER_SEC * 2)
#define QPNP_KEY_STATUS_DELAY msecs_to_jiffies(250)
#define QPNP_PON_REV_B 0x01
@@ -147,6 +156,26 @@
[7] = "Triggered from KPD (power key press)",
};
+static const char * const qpnp_poff_reason[] = {
+ [0] = "Triggered from SOFT (Software)",
+ [1] = "Triggered from PS_HOLD (PS_HOLD/MSM controlled shutdown)",
+ [2] = "Triggered from PMIC_WD (PMIC watchdog)",
+ [3] = "Triggered from GP1 (Keypad_Reset1)",
+ [4] = "Triggered from GP2 (Keypad_Reset2)",
+ [5] = "Triggered from KPDPWR_AND_RESIN"
+ "(Simultaneous power key and reset line)",
+ [6] = "Triggered from RESIN_N (Reset line/Volume Down Key)",
+ [7] = "Triggered from KPDPWR_N (Long Power Key hold)",
+ [8] = "N/A",
+ [9] = "N/A",
+ [10] = "N/A",
+ [11] = "Triggered from CHARGER (Charger ENUM_TIMER, BOOT_DONE)",
+ [12] = "Triggered from TFT (Thermal Fault Tolerance)",
+ [13] = "Triggered from UVLO (Under Voltage Lock Out)",
+ [14] = "Triggered from OTST3 (Overtemp)",
+ [15] = "Triggered from STAGE3 (Stage 3 reset)",
+};
+
static int
qpnp_pon_masked_write(struct qpnp_pon *pon, u16 addr, u8 mask, u8 val)
{
@@ -754,6 +783,8 @@
struct device_node *pp = NULL;
struct qpnp_pon_config *cfg;
u8 pon_ver;
+ u8 pmic_type;
+ u8 revid_rev4;
/* Check if it is rev B */
rc = spmi_ext_register_readl(pon->spmi->ctrl, pon->spmi->sid,
@@ -836,6 +867,38 @@
cfg->use_bark = of_property_read_bool(pp,
"qcom,use-bark");
+
+ rc = spmi_ext_register_readl(pon->spmi->ctrl,
+ pon->spmi->sid, PMIC_VERSION_REG,
+ &pmic_type, 1);
+
+ if (rc) {
+ dev_err(&pon->spmi->dev,
+ "Unable to read PMIC type\n");
+ return rc;
+ }
+
+ if (pmic_type == PMIC_VER_8941) {
+
+ rc = spmi_ext_register_readl(pon->spmi->ctrl,
+ pon->spmi->sid, PMIC_VERSION_REV4_REG,
+ &revid_rev4, 1);
+
+ if (rc) {
+ dev_err(&pon->spmi->dev,
+ "Unable to read PMIC revision ID\n");
+ return rc;
+ }
+
+ /*PM8941 V3 does not have harware bug. Hence
+ bark is not required from PMIC versions 3.0*/
+ if (!(revid_rev4 == PMIC8941_V1_REV4 ||
+ revid_rev4 == PMIC8941_V2_REV4)) {
+ cfg->support_reset = false;
+ cfg->use_bark = false;
+ }
+ }
+
if (cfg->use_bark) {
cfg->bark_irq = spmi_get_irq_byname(pon->spmi,
NULL, "resin-bark");
@@ -1035,9 +1098,10 @@
struct device_node *itr = NULL;
u32 delay = 0, s3_debounce = 0;
int rc, sys_reset, index;
- u8 pon_sts = 0;
+ u8 pon_sts = 0, buf[2];
const char *s3_src;
u8 s3_src_reg;
+ u16 poff_sts = 0;
pon = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_pon),
GFP_KERNEL);
@@ -1085,14 +1149,38 @@
dev_err(&pon->spmi->dev, "Unable to read PON_RESASON1 reg\n");
return rc;
}
- index = ffs(pon_sts);
- if ((index > PON_REASON_MAX) || (index < 0))
- index = 0;
+ index = ffs(pon_sts) - 1;
cold_boot = !qpnp_pon_is_warm_reset();
- pr_info("PMIC@SID%d Power-on reason: %s and '%s' boot\n",
- pon->spmi->sid, index ? qpnp_pon_reason[index - 1] :
- "Unknown", cold_boot ? "cold" : "warm");
+ if (index >= ARRAY_SIZE(qpnp_pon_reason) || index < 0)
+ dev_info(&pon->spmi->dev,
+ "PMIC@SID%d Power-on reason: Unknown and '%s' boot\n",
+ pon->spmi->sid, cold_boot ? "cold" : "warm");
+ else
+ dev_info(&pon->spmi->dev,
+ "PMIC@SID%d Power-on reason: %s and '%s' boot\n",
+ pon->spmi->sid, qpnp_pon_reason[index],
+ cold_boot ? "cold" : "warm");
+
+ /* POFF reason */
+ rc = spmi_ext_register_readl(pon->spmi->ctrl, pon->spmi->sid,
+ QPNP_POFF_REASON1(pon->base),
+ buf, 2);
+ if (rc) {
+ dev_err(&pon->spmi->dev, "Unable to read POFF_RESASON regs\n");
+ return rc;
+ }
+ poff_sts = buf[0] | (buf[1] << 8);
+ index = ffs(poff_sts) - 1;
+ if (index >= ARRAY_SIZE(qpnp_poff_reason) || index < 0)
+ dev_info(&pon->spmi->dev,
+ "PMIC@SID%d: Unknown power-off reason\n",
+ pon->spmi->sid);
+ else
+ dev_info(&pon->spmi->dev,
+ "PMIC@SID%d: Power-off reason: %s\n",
+ pon->spmi->sid,
+ qpnp_poff_reason[index]);
rc = of_property_read_u32(pon->spmi->dev.of_node,
"qcom,pon-dbc-delay", &delay);
diff --git a/drivers/power/qpnp-bms.c b/drivers/power/qpnp-bms.c
index 82c61c9..ed0279e 100644
--- a/drivers/power/qpnp-bms.c
+++ b/drivers/power/qpnp-bms.c
@@ -491,7 +491,7 @@
}
static inline int convert_vbatt_raw_to_uv(struct qpnp_bms_chip *chip,
- uint16_t reading)
+ uint16_t reading, bool is_pon_ocv)
{
int64_t uv;
int rc;
@@ -500,7 +500,7 @@
pr_debug("%u raw converted into %lld uv\n", reading, uv);
uv = adjust_vbatt_reading(chip, uv);
pr_debug("adjusted into %lld uv\n", uv);
- rc = qpnp_vbat_sns_comp_result(chip->vadc_dev, &uv);
+ rc = qpnp_vbat_sns_comp_result(chip->vadc_dev, &uv, is_pon_ocv);
if (rc)
pr_debug("could not compensate vbatt\n");
pr_debug("compensated into %lld uv\n", uv);
@@ -699,7 +699,7 @@
static void convert_and_store_ocv(struct qpnp_bms_chip *chip,
struct raw_soc_params *raw,
- int batt_temp)
+ int batt_temp, bool is_pon_ocv)
{
int rc;
@@ -711,7 +711,7 @@
pr_err("Vadc reference voltage read failed, rc = %d\n", rc);
chip->prev_last_good_ocv_raw = raw->last_good_ocv_raw;
raw->last_good_ocv_uv = convert_vbatt_raw_to_uv(chip,
- raw->last_good_ocv_raw);
+ raw->last_good_ocv_raw, is_pon_ocv);
chip->last_ocv_uv = raw->last_good_ocv_uv;
chip->last_ocv_temp = batt_temp;
chip->software_cc_uah = 0;
@@ -1042,7 +1042,7 @@
mutex_unlock(&chip->bms_output_lock);
if (chip->prev_last_good_ocv_raw == OCV_RAW_UNINITIALIZED) {
- convert_and_store_ocv(chip, raw, batt_temp);
+ convert_and_store_ocv(chip, raw, batt_temp, true);
pr_debug("PON_OCV_UV = %d, cc = %llx\n",
chip->last_ocv_uv, raw->cc);
warm_reset = qpnp_pon_is_warm_reset();
@@ -1078,7 +1078,7 @@
pr_debug("EOC Battery full ocv_reading = 0x%x\n",
chip->ocv_reading_at_100);
} else if (chip->prev_last_good_ocv_raw != raw->last_good_ocv_raw) {
- convert_and_store_ocv(chip, raw, batt_temp);
+ convert_and_store_ocv(chip, raw, batt_temp, false);
/* forget the old cc value upon ocv */
chip->last_cc_uah = INT_MIN;
} else {
@@ -2205,6 +2205,11 @@
pr_err("adc vbat failed err = %d\n", rc);
return soc;
}
+
+ /* only clamp when discharging */
+ if (is_battery_charging(chip))
+ return soc;
+
if (soc <= 0 && vbat_uv > chip->v_cutoff_uv) {
pr_debug("clamping soc to 1, vbat (%d) > cutoff (%d)\n",
vbat_uv, chip->v_cutoff_uv);
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index 0870202..6301724 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -650,24 +650,23 @@
return (batfet_closed_rt_sts & BAT_FET_ON_IRQ) ? 1 : 0;
}
-#define USB_VALID_BIT BIT(7)
static int
qpnp_chg_is_usb_chg_plugged_in(struct qpnp_chg_chip *chip)
{
- u8 usbin_valid_rt_sts;
+ u8 usb_chgpth_rt_sts;
int rc;
- rc = qpnp_chg_read(chip, &usbin_valid_rt_sts,
- chip->usb_chgpth_base + CHGR_STATUS , 1);
+ rc = qpnp_chg_read(chip, &usb_chgpth_rt_sts,
+ INT_RT_STS(chip->usb_chgpth_base), 1);
if (rc) {
pr_err("spmi read failed: addr=%03X, rc=%d\n",
- chip->usb_chgpth_base + CHGR_STATUS, rc);
+ INT_RT_STS(chip->usb_chgpth_base), rc);
return rc;
}
- pr_debug("chgr usb sts 0x%x\n", usbin_valid_rt_sts);
+ pr_debug("chgr usb sts 0x%x\n", usb_chgpth_rt_sts);
- return (usbin_valid_rt_sts & USB_VALID_BIT) ? 1 : 0;
+ return (usb_chgpth_rt_sts & USBIN_VALID_IRQ) ? 1 : 0;
}
static bool
@@ -686,10 +685,10 @@
return !!(buck_sts & IBAT_LOOP_IRQ);
}
-#define USB_VALID_MASK 0xC0
-#define USB_COARSE_DET 0x10
-#define USB_VALID_UVP_VALUE 0x00
-#define USB_VALID_OVP_VALUE 0x40
+#define USB_VALID_MASK 0xC0
+#define USB_VALID_IN_MASK BIT(7)
+#define USB_COARSE_DET 0x10
+#define USB_VALID_OVP_VALUE 0x40
static int
qpnp_chg_check_usb_coarse_det(struct qpnp_chg_chip *chip)
{
@@ -708,7 +707,8 @@
static int
qpnp_chg_check_usbin_health(struct qpnp_chg_chip *chip)
{
- u8 usbin_chg_rt_sts, usbin_health = 0;
+ u8 usbin_chg_rt_sts, usb_chgpth_rt_sts;
+ u8 usbin_health = 0;
int rc;
rc = qpnp_chg_read(chip, &usbin_chg_rt_sts,
@@ -720,13 +720,23 @@
return rc;
}
- pr_debug("chgr usb sts 0x%x\n", usbin_chg_rt_sts);
+ rc = qpnp_chg_read(chip, &usb_chgpth_rt_sts,
+ INT_RT_STS(chip->usb_chgpth_base) , 1);
+
+ if (rc) {
+ pr_err("spmi read failed: addr=%03X, rc=%d\n",
+ INT_RT_STS(chip->usb_chgpth_base), rc);
+ return rc;
+ }
+
+ pr_debug("chgr usb sts 0x%x, chgpth rt sts 0x%x\n",
+ usbin_chg_rt_sts, usb_chgpth_rt_sts);
if ((usbin_chg_rt_sts & USB_COARSE_DET) == USB_COARSE_DET) {
if ((usbin_chg_rt_sts & USB_VALID_MASK)
== USB_VALID_OVP_VALUE) {
usbin_health = USBIN_OVP;
pr_err("Over voltage charger inserted\n");
- } else if ((usbin_chg_rt_sts & USB_VALID_BIT) != 0) {
+ } else if ((usb_chgpth_rt_sts & USBIN_VALID_IRQ) != 0) {
usbin_health = USBIN_OK;
pr_debug("Valid charger inserted\n");
}
@@ -1067,7 +1077,8 @@
return rc;
}
- rc = override_dcin_ilimit(chip, 0);
+ if (enable)
+ rc = override_dcin_ilimit(chip, 0);
return rc;
}
@@ -5120,6 +5131,14 @@
qpnp_chg_force_run_on_batt(chip, chip->charging_disabled);
qpnp_chg_set_appropriate_vddmax(chip);
+ if (chip->parallel_ovp_mode) {
+ rc = override_dcin_ilimit(chip, 1);
+ if (rc) {
+ pr_err("Override DCIN LLIMIT %d\n", rc);
+ goto unregister_dc_psy;
+ }
+ }
+
rc = qpnp_chg_request_irqs(chip);
if (rc) {
pr_err("failed to request interrupts %d\n", rc);
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 450c4fb..047bbc4 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -1989,8 +1989,8 @@
int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV)
{
struct regulator_dev *rdev = regulator->rdev;
- int prev_min_uV, prev_max_uV;
int ret = 0;
+ int old_min_uV, old_max_uV;
mutex_lock(&rdev->mutex);
@@ -2013,24 +2013,28 @@
if (ret < 0)
goto out;
- prev_min_uV = regulator->min_uV;
- prev_max_uV = regulator->max_uV;
-
+ /* restore original values in case of error */
+ old_min_uV = regulator->min_uV;
+ old_max_uV = regulator->max_uV;
regulator->min_uV = min_uV;
regulator->max_uV = max_uV;
ret = regulator_check_consumers(rdev, &min_uV, &max_uV);
- if (ret < 0) {
- regulator->min_uV = prev_min_uV;
- regulator->max_uV = prev_max_uV;
- goto out;
- }
+ if (ret < 0)
+ goto out2;
ret = _regulator_do_set_voltage(rdev, min_uV, max_uV);
+ if (ret < 0)
+ goto out2;
out:
mutex_unlock(&rdev->mutex);
return ret;
+out2:
+ regulator->min_uV = old_min_uV;
+ regulator->max_uV = old_max_uV;
+ mutex_unlock(&rdev->mutex);
+ return ret;
}
EXPORT_SYMBOL_GPL(regulator_set_voltage);
diff --git a/drivers/rtc/alarm-dev.c b/drivers/rtc/alarm-dev.c
index 4682e9c..1e13ce1 100644
--- a/drivers/rtc/alarm-dev.c
+++ b/drivers/rtc/alarm-dev.c
@@ -99,7 +99,9 @@
}
alarm_enabled &= ~alarm_type_mask;
if (alarm_type == ANDROID_ALARM_RTC_POWEROFF_WAKEUP)
- set_power_on_alarm(0);
+ if (!copy_from_user(&new_alarm_time,
+ (void __user *)arg, sizeof(new_alarm_time)))
+ set_power_on_alarm(new_alarm_time.tv_sec, 0);
spin_unlock_irqrestore(&alarm_slock, flags);
break;
@@ -130,7 +132,7 @@
if ((alarm_type == ANDROID_ALARM_RTC_POWEROFF_WAKEUP) &&
(ANDROID_ALARM_BASE_CMD(cmd) ==
ANDROID_ALARM_SET(0)))
- set_power_on_alarm(new_alarm_time.tv_sec);
+ set_power_on_alarm(new_alarm_time.tv_sec, 1);
spin_unlock_irqrestore(&alarm_slock, flags);
if (ANDROID_ALARM_BASE_CMD(cmd) != ANDROID_ALARM_SET_AND_WAIT(0)
&& cmd != ANDROID_ALARM_SET_AND_WAIT_OLD)
diff --git a/drivers/rtc/alarm.c b/drivers/rtc/alarm.c
index 06749b9..2cf1158 100644
--- a/drivers/rtc/alarm.c
+++ b/drivers/rtc/alarm.c
@@ -71,9 +71,21 @@
static bool suspended;
static long power_on_alarm;
-void set_power_on_alarm(long secs)
+static void alarm_shutdown(struct platform_device *dev);
+void set_power_on_alarm(long secs, bool enable)
{
- power_on_alarm = secs;
+ if (enable) {
+ power_on_alarm = secs;
+ } else {
+ if (power_on_alarm && power_on_alarm != secs) {
+ pr_alarm(FLOW, "power-off alarm mismatch: \
+ previous=%ld, now=%ld\n",
+ power_on_alarm, secs);
+ }
+ else
+ power_on_alarm = 0;
+ }
+ alarm_shutdown(NULL);
}
diff --git a/drivers/rtc/qpnp-rtc.c b/drivers/rtc/qpnp-rtc.c
index d64b577..e0d5c1e 100644
--- a/drivers/rtc/qpnp-rtc.c
+++ b/drivers/rtc/qpnp-rtc.c
@@ -386,6 +386,7 @@
unsigned long irq_flags;
struct qpnp_rtc *rtc_dd = dev_get_drvdata(dev);
u8 ctrl_reg;
+ u8 value[4] = {0};
spin_lock_irqsave(&rtc_dd->alarm_ctrl_lock, irq_flags);
ctrl_reg = rtc_dd->alarm_ctrl_reg1;
@@ -401,6 +402,15 @@
rtc_dd->alarm_ctrl_reg1 = ctrl_reg;
+ /* Clear Alarm register */
+ if (!enabled) {
+ rc = qpnp_write_wrapper(rtc_dd, value,
+ rtc_dd->alarm_base + REG_OFFSET_ALARM_RW,
+ NUM_8_BIT_RTC_REGS);
+ if (rc)
+ dev_err(dev, "Clear ALARM value reg failed\n");
+ }
+
rtc_rw_fail:
spin_unlock_irqrestore(&rtc_dd->alarm_ctrl_lock, irq_flags);
return rc;
@@ -553,8 +563,15 @@
goto fail_rtc_enable;
}
+ rc = qpnp_read_wrapper(rtc_dd, &rtc_dd->alarm_ctrl_reg1,
+ rtc_dd->alarm_base + REG_OFFSET_ALARM_CTRL1, 1);
+ if (rc) {
+ dev_err(&spmi->dev,
+ "Read from Alarm control reg failed\n");
+ goto fail_rtc_enable;
+ }
/* Enable abort enable feature */
- rtc_dd->alarm_ctrl_reg1 = BIT_RTC_ABORT_ENABLE;
+ rtc_dd->alarm_ctrl_reg1 |= BIT_RTC_ABORT_ENABLE;
rc = qpnp_write_wrapper(rtc_dd, &rtc_dd->alarm_ctrl_reg1,
rtc_dd->alarm_base + REG_OFFSET_ALARM_CTRL1, 1);
if (rc) {
diff --git a/drivers/slimbus/slim-msm-ngd.c b/drivers/slimbus/slim-msm-ngd.c
index 496b31d..aa61ab9 100644
--- a/drivers/slimbus/slim-msm-ngd.c
+++ b/drivers/slimbus/slim-msm-ngd.c
@@ -1074,11 +1074,7 @@
while (!kthread_should_stop()) {
set_current_state(TASK_INTERRUPTIBLE);
- ret = wait_for_completion_interruptible(notify);
- if (ret) {
- dev_err(dev->dev, "rx thread wait err:%d", ret);
- continue;
- }
+ wait_for_completion(notify);
/* 1 irq notification per message */
if (dev->use_rx_msgqs != MSM_MSGQ_ENABLED) {
msm_slim_rx_dequeue(dev, (u8 *)buffer);
@@ -1116,12 +1112,7 @@
int ret, i = 0;
while (!kthread_should_stop()) {
set_current_state(TASK_INTERRUPTIBLE);
- ret = wait_for_completion_timeout(&dev->qmi.slave_notify,
- HZ);
- if (!ret) {
- dev_err(dev->dev, "slave thread wait err:%d", ret);
- continue;
- }
+ wait_for_completion(&dev->qmi.slave_notify);
/* Probe devices for first notification */
if (!i) {
dev->err = 0;
diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c
index 39e81fa..d3e4612 100644
--- a/drivers/spi/spi_qsd.c
+++ b/drivers/spi/spi_qsd.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2008-2014, 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
@@ -1980,14 +1980,17 @@
if (dd->use_rlock)
remote_mutex_lock(&dd->r_lock);
- if (!msm_spi_is_valid_state(dd)) {
+ spin_lock_irqsave(&dd->queue_lock, flags);
+ dd->transfer_pending = 1;
+ spin_unlock_irqrestore(&dd->queue_lock, flags);
+
+ if (dd->suspended || !msm_spi_is_valid_state(dd)) {
dev_err(dd->dev, "%s: SPI operational state not valid\n",
__func__);
status_error = 1;
}
-
spin_lock_irqsave(&dd->queue_lock, flags);
- dd->transfer_pending = 1;
+
while (!list_empty(&dd->queue)) {
dd->cur_msg = list_entry(dd->queue.next,
struct spi_message, queue);
diff --git a/drivers/spmi/qpnp-int.c b/drivers/spmi/qpnp-int.c
index 3e14333..9fc7299 100644
--- a/drivers/spmi/qpnp-int.c
+++ b/drivers/spmi/qpnp-int.c
@@ -184,6 +184,22 @@
return 0;
}
+static void qpnpint_irq_ack(struct irq_data *d)
+{
+ struct q_irq_data *irq_d = irq_data_get_irq_chip_data(d);
+ int rc;
+
+ pr_debug("hwirq %lu irq: %d\n", d->hwirq, d->irq);
+
+ rc = qpnpint_spmi_write(irq_d, QPNPINT_REG_LATCHED_CLR,
+ &irq_d->mask_shift, 1);
+ if (rc) {
+ pr_err_ratelimited("spmi write failure on irq %d, rc=%d\n",
+ d->irq, rc);
+ return;
+ }
+}
+
static void qpnpint_irq_mask(struct irq_data *d)
{
struct q_irq_data *irq_d = irq_data_get_irq_chip_data(d);
@@ -223,44 +239,10 @@
static void qpnpint_irq_mask_ack(struct irq_data *d)
{
- struct q_irq_data *irq_d = irq_data_get_irq_chip_data(d);
- struct q_chip_data *chip_d = irq_d->chip_d;
- struct q_perip_data *per_d = irq_d->per_d;
- int rc;
- uint8_t prev_int_en = per_d->int_en;
-
pr_debug("hwirq %lu irq: %d\n", d->hwirq, d->irq);
- if (!chip_d->cb) {
- pr_warn_ratelimited("No arbiter on bus=%u slave=%u offset=%u\n",
- chip_d->bus_nr, irq_d->spmi_slave,
- irq_d->spmi_offset);
- return;
- }
-
- per_d->int_en &= ~irq_d->mask_shift;
-
- if (prev_int_en && !(per_d->int_en)) {
- /*
- * no interrupt on this peripheral is enabled
- * ask the arbiter to ignore this peripheral
- */
- qpnpint_arbiter_op(d, irq_d, chip_d->cb->mask);
- }
-
- rc = qpnpint_spmi_write(irq_d, QPNPINT_REG_EN_CLR,
- &irq_d->mask_shift, 1);
- if (rc) {
- pr_err("spmi failure on irq %d\n", d->irq);
- return;
- }
-
- rc = qpnpint_spmi_write(irq_d, QPNPINT_REG_LATCHED_CLR,
- &irq_d->mask_shift, 1);
- if (rc) {
- pr_err("spmi failure on irq %d\n", d->irq);
- return;
- }
+ qpnpint_irq_mask(d);
+ qpnpint_irq_ack(d);
}
static void qpnpint_irq_unmask(struct irq_data *d)
@@ -269,6 +251,7 @@
struct q_chip_data *chip_d = irq_d->chip_d;
struct q_perip_data *per_d = irq_d->per_d;
int rc;
+ uint8_t buf[2];
uint8_t prev_int_en = per_d->int_en;
pr_debug("hwirq %lu irq: %d\n", d->hwirq, d->irq);
@@ -289,12 +272,29 @@
*/
qpnpint_arbiter_op(d, irq_d, chip_d->cb->unmask);
}
- rc = qpnpint_spmi_write(irq_d, QPNPINT_REG_EN_SET,
- &irq_d->mask_shift, 1);
+
+ /* Check the current state of the interrupt enable bit. */
+ rc = qpnpint_spmi_read(irq_d, QPNPINT_REG_EN_SET, buf, 1);
if (rc) {
- pr_err("spmi failure on irq %d\n", d->irq);
+ pr_err("SPMI read failure for IRQ %d, rc=%d\n", d->irq, rc);
return;
}
+
+ if (!(buf[0] & irq_d->mask_shift)) {
+ /*
+ * Since the interrupt is currently disabled, write to both the
+ * LATCHED_CLR and EN_SET registers so that a spurious interrupt
+ * cannot be triggered when the interrupt is enabled.
+ */
+ buf[0] = irq_d->mask_shift;
+ buf[1] = irq_d->mask_shift;
+ rc = qpnpint_spmi_write(irq_d, QPNPINT_REG_LATCHED_CLR, buf, 2);
+ if (rc) {
+ pr_err("SPMI write failure for IRQ %d, rc=%d\n", d->irq,
+ rc);
+ return;
+ }
+ }
}
static int qpnpint_irq_set_type(struct irq_data *d, unsigned int flow_type)
@@ -336,6 +336,11 @@
return rc;
}
+ if (flow_type & IRQ_TYPE_EDGE_BOTH)
+ __irq_set_handler_locked(d->irq, handle_edge_irq);
+ else
+ __irq_set_handler_locked(d->irq, handle_level_irq);
+
return 0;
}
@@ -363,6 +368,7 @@
static struct irq_chip qpnpint_chip = {
.name = "qpnp-int",
+ .irq_ack = qpnpint_irq_ack,
.irq_mask = qpnpint_irq_mask,
.irq_mask_ack = qpnpint_irq_mask_ack,
.irq_unmask = qpnpint_irq_unmask,
diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
index 21863e8..8cd70ac 100644
--- a/drivers/thermal/thermal_sys.c
+++ b/drivers/thermal/thermal_sys.c
@@ -92,13 +92,43 @@
}
EXPORT_SYMBOL(sensor_get_id);
+static void init_sensor_trip(struct sensor_info *sensor)
+{
+ int ret = 0, i = 0;
+ enum thermal_trip_type type;
+
+ for (i = 0; ((sensor->max_idx == -1) ||
+ (sensor->min_idx == -1)) &&
+ (sensor->tz->ops->get_trip_type) &&
+ (i < sensor->tz->trips); i++) {
+
+ sensor->tz->ops->get_trip_type(sensor->tz, i, &type);
+ if (type == THERMAL_TRIP_CONFIGURABLE_HI)
+ sensor->max_idx = i;
+ if (type == THERMAL_TRIP_CONFIGURABLE_LOW)
+ sensor->min_idx = i;
+ type = 0;
+ }
+
+ ret = sensor->tz->ops->get_trip_temp(sensor->tz,
+ sensor->min_idx, &sensor->threshold_min);
+ if (ret)
+ pr_err("Unable to get MIN trip temp. sensor:%d err:%d\n",
+ sensor->sensor_id, ret);
+
+ ret = sensor->tz->ops->get_trip_temp(sensor->tz,
+ sensor->max_idx, &sensor->threshold_max);
+ if (ret)
+ pr_err("Unable to get MAX trip temp. sensor:%d err:%d\n",
+ sensor->sensor_id, ret);
+}
+
static int __update_sensor_thresholds(struct sensor_info *sensor)
{
long max_of_low_thresh = LONG_MIN;
long min_of_high_thresh = LONG_MAX;
struct sensor_threshold *pos, *var;
- enum thermal_trip_type type;
- int i, ret = 0;
+ int ret = 0;
if (!sensor->tz->ops->set_trip_temp ||
!sensor->tz->ops->activate_trip_type ||
@@ -108,19 +138,8 @@
goto update_done;
}
- for (i = 0; ((sensor->max_idx == -1) || (sensor->min_idx == -1)) &&
- (sensor->tz->ops->get_trip_type) && (i < sensor->tz->trips);
- i++) {
- sensor->tz->ops->get_trip_type(sensor->tz, i, &type);
- if (type == THERMAL_TRIP_CONFIGURABLE_HI)
- sensor->max_idx = i;
- if (type == THERMAL_TRIP_CONFIGURABLE_LOW)
- sensor->min_idx = i;
- sensor->tz->ops->get_trip_temp(sensor->tz,
- THERMAL_TRIP_CONFIGURABLE_LOW, &sensor->threshold_min);
- sensor->tz->ops->get_trip_temp(sensor->tz,
- THERMAL_TRIP_CONFIGURABLE_HI, &sensor->threshold_max);
- }
+ if ((sensor->max_idx == -1) || (sensor->min_idx == -1))
+ init_sensor_trip(sensor);
list_for_each_entry_safe(pos, var, &sensor->threshold_list, list) {
if (!pos->active)
@@ -368,7 +387,7 @@
sensor->sensor_id = tz->id;
sensor->tz = tz;
- sensor->threshold_min = 0;
+ sensor->threshold_min = LONG_MIN;
sensor->threshold_max = LONG_MAX;
sensor->max_idx = -1;
sensor->min_idx = -1;
diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c
index 4058bec..a701ec8 100644
--- a/drivers/tty/serial/msm_serial_hs.c
+++ b/drivers/tty/serial/msm_serial_hs.c
@@ -251,7 +251,6 @@
struct workqueue_struct *hsuart_wq; /* hsuart workqueue */
struct mutex clk_mutex; /* mutex to guard against clock off/clock on */
struct work_struct disconnect_rx_endpoint; /* disconnect rx_endpoint */
- bool tty_flush_receive;
enum uart_core_type uart_type;
u32 bam_handle;
resource_size_t bam_mem;
@@ -319,6 +318,7 @@
[UART_DM_TXFS] = 0x4c,
[UART_DM_RXFS] = 0x50,
[UART_DM_RX_TRANS_CTRL] = 0xcc,
+ [UART_DM_BCR] = 0xc8,
};
static struct of_device_id msm_hs_match_table[] = {
@@ -1838,12 +1838,13 @@
* Do the work buffer related work in BAM
* mode that is equivalent to legacy mode
*/
+ spin_lock_irqsave(&(msm_uport->uport.lock), flags);
- if (!msm_uport->tty_flush_receive)
+ if (!uart_circ_empty(tx_buf))
tx_buf->tail = (tx_buf->tail +
tx->tx_count) & ~UART_XMIT_SIZE;
else
- msm_uport->tty_flush_receive = false;
+ MSM_HS_DBG("%s:circ buffer is empty\n", __func__);
tx->dma_in_flight = 0;
@@ -1860,7 +1861,6 @@
if (uart_circ_chars_pending(tx_buf) < WAKEUP_CHARS)
uart_write_wakeup(uport);
- spin_lock_irqsave(&(msm_uport->uport.lock), flags);
if (msm_uport->tx.flush == FLUSH_STOP) {
msm_uport->tx.flush = FLUSH_SHUTDOWN;
wake_up(&msm_uport->tx.wait);
@@ -2036,14 +2036,6 @@
}
-static void msm_hs_flush_buffer(struct uart_port *uport)
-{
- struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
-
- if (msm_uport->tx.dma_in_flight)
- msm_uport->tty_flush_receive = true;
-}
-
/*
* Standard API, Break Signal
*
@@ -2281,11 +2273,9 @@
/* Do not update tx_buf.tail if uart_flush_buffer already
* called in serial core
*/
- if (!msm_uport->tty_flush_receive)
+ if (!uart_circ_empty(tx_buf))
tx_buf->tail = (tx_buf->tail +
tx->tx_count) & ~UART_XMIT_SIZE;
- else
- msm_uport->tty_flush_receive = false;
tx->dma_in_flight = 0;
@@ -2665,7 +2655,11 @@
}
}
- msm_hs_write(uport, UARTDM_BCR_ADDR, 0x003F);
+ data = (UARTDM_BCR_TX_BREAK_DISABLE | UARTDM_BCR_STALE_IRQ_EMPTY |
+ UARTDM_BCR_RX_DMRX_LOW_EN | UARTDM_BCR_RX_STAL_IRQ_DMRX_EQL |
+ UARTDM_BCR_RX_DMRX_1BYTE_RES_EN);
+ msm_hs_write(uport, UART_DM_BCR, data);
+
/* Set auto RFR Level */
data = msm_hs_read(uport, UART_DM_MR1);
data &= ~UARTDM_MR1_AUTO_RFR_LEVEL1_BMSK;
@@ -2708,8 +2702,6 @@
tx->tx_ready_int_en = 0;
tx->dma_in_flight = 0;
rx->rx_cmd_exec = false;
- msm_uport->tty_flush_receive = false;
- MSM_HS_DBG("%s: Setting tty_flush_receive to false\n", __func__);
if (!is_blsp_uart(msm_uport)) {
tx->xfer.complete_func = msm_hs_dmov_tx_callback;
@@ -3751,7 +3743,7 @@
.config_port = msm_hs_config_port,
.release_port = msm_hs_release_port,
.request_port = msm_hs_request_port,
- .flush_buffer = msm_hs_flush_buffer,
+ .flush_buffer = NULL,
.ioctl = msm_hs_ioctl,
};
diff --git a/drivers/tty/serial/msm_serial_hs_hwreg.h b/drivers/tty/serial/msm_serial_hs_hwreg.h
index d912b9f..064bbda 100644
--- a/drivers/tty/serial/msm_serial_hs_hwreg.h
+++ b/drivers/tty/serial/msm_serial_hs_hwreg.h
@@ -81,6 +81,7 @@
UART_DM_TXFS,
UART_DM_RXFS,
UART_DM_RX_TRANS_CTRL,
+ UART_DM_BCR,
UART_DM_LAST,
};
@@ -94,7 +95,11 @@
* UARTDM Core v1.4 STALE_IRQ_EMPTY bit defination
* Stale interrupt will fire if bit is set when RX-FIFO is empty
*/
+#define UARTDM_BCR_TX_BREAK_DISABLE 0x1
#define UARTDM_BCR_STALE_IRQ_EMPTY 0x2
+#define UARTDM_BCR_RX_DMRX_LOW_EN 0x4
+#define UARTDM_BCR_RX_STAL_IRQ_DMRX_EQL 0x10
+#define UARTDM_BCR_RX_DMRX_1BYTE_RES_EN 0x20
/* TRANSFER_CONTROL Register for UARTDM Core v1.4 */
#define UARTDM_RX_TRANS_CTRL_ADDR 0xcc
diff --git a/drivers/usb/gadget/ci13xxx_msm.c b/drivers/usb/gadget/ci13xxx_msm.c
index f1e4220..be30b5f 100644
--- a/drivers/usb/gadget/ci13xxx_msm.c
+++ b/drivers/usb/gadget/ci13xxx_msm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2014, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -62,11 +62,27 @@
struct ci13xxx *udc = _udc;
struct usb_phy *phy = udc->transceiver;
- if (phy && (phy->flags & ENABLE_DP_MANUAL_PULLUP))
+ if (phy && (phy->flags & ENABLE_DP_MANUAL_PULLUP)) {
+ u32 temp;
+
usb_phy_io_write(phy,
ULPI_MISC_A_VBUSVLDEXT |
ULPI_MISC_A_VBUSVLDEXTSEL,
ULPI_CLR(ULPI_MISC_A));
+
+ /* Notify LINK of VBUS LOW */
+ temp = readl_relaxed(USB_USBCMD);
+ temp &= ~USBCMD_SESS_VLD_CTRL;
+ writel_relaxed(temp, USB_USBCMD);
+
+ /*
+ * Add memory barrier as it is must to complete
+ * above USB PHY and Link register writes before
+ * moving ahead with USB peripheral mode enumeration,
+ * otherwise USB peripheral mode may not work.
+ */
+ mb();
+ }
}
/* Link power management will reduce power consumption by
@@ -345,6 +361,11 @@
return 0;
}
+void ci13xxx_msm_shutdown(struct platform_device *pdev)
+{
+ ci13xxx_pullup(&_udc->gadget, 0);
+}
+
void msm_hw_bam_disable(bool bam_disable)
{
u32 val;
@@ -364,6 +385,7 @@
.name = "msm_hsusb",
},
.remove = ci13xxx_msm_remove,
+ .shutdown = ci13xxx_msm_shutdown,
};
MODULE_ALIAS("platform:msm_hsusb");
diff --git a/drivers/usb/gadget/f_audio_source.c b/drivers/usb/gadget/f_audio_source.c
index 37f229b..33b645e 100644
--- a/drivers/usb/gadget/f_audio_source.c
+++ b/drivers/usb/gadget/f_audio_source.c
@@ -327,15 +327,22 @@
s64 msecs;
s64 frames;
ktime_t now;
+ unsigned long flags;
+ spin_lock_irqsave(&audio->lock, flags);
/* audio->substream will be null if we have been closed */
- if (!audio->substream)
+ if (!audio->substream) {
+ spin_unlock_irqrestore(&audio->lock, flags);
return;
+ }
/* audio->buffer_pos will be null if we have been stopped */
- if (!audio->buffer_pos)
+ if (!audio->buffer_pos) {
+ spin_unlock_irqrestore(&audio->lock, flags);
return;
+ }
runtime = audio->substream->runtime;
+ spin_unlock_irqrestore(&audio->lock, flags);
/* compute number of frames to send */
now = ktime_get();
@@ -359,8 +366,21 @@
while (frames > 0) {
req = audio_req_get(audio);
- if (!req)
+ spin_lock_irqsave(&audio->lock, flags);
+ /* audio->substream will be null if we have been closed */
+ if (!audio->substream) {
+ spin_unlock_irqrestore(&audio->lock, flags);
+ return;
+ }
+ /* audio->buffer_pos will be null if we have been stopped */
+ if (!audio->buffer_pos) {
+ spin_unlock_irqrestore(&audio->lock, flags);
+ return;
+ }
+ if (!req) {
+ spin_unlock_irqrestore(&audio->lock, flags);
break;
+ }
length = frames_to_bytes(runtime, frames);
if (length > IN_EP_MAX_PACKET_SIZE)
@@ -386,6 +406,7 @@
}
req->length = length;
+ spin_unlock_irqrestore(&audio->lock, flags);
ret = usb_ep_queue(audio->in_ep, req, GFP_ATOMIC);
if (ret < 0) {
pr_err("usb_ep_queue failed ret: %d\n", ret);
diff --git a/drivers/usb/host/ehci-msm2.c b/drivers/usb/host/ehci-msm2.c
index 7ae0a54..ebb226c 100644
--- a/drivers/usb/host/ehci-msm2.c
+++ b/drivers/usb/host/ehci-msm2.c
@@ -46,6 +46,10 @@
#define PDEV_NAME_LEN 20
+static bool uicc_card_present;
+module_param(uicc_card_present, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(uicc_card_present, "UICC card inserted");
+
struct msm_hcd {
struct ehci_hcd ehci;
spinlock_t wakeup_lock;
@@ -295,6 +299,11 @@
static void msm_ehci_vbus_power(struct msm_hcd *mhcd, bool on)
{
int ret;
+ const struct msm_usb_host_platform_data *pdata;
+
+ pdata = mhcd->dev->platform_data;
+ if (pdata && pdata->is_uicc)
+ return;
if (!mhcd->vbus) {
pr_err("vbus is NULL.");
@@ -352,6 +361,10 @@
pdata = mhcd->dev->platform_data;
+ /* For uicc card connection, external vbus is not required */
+ if (pdata && pdata->is_uicc)
+ return 0;
+
if (!init) {
if (pdata && pdata->dock_connect_irq)
free_irq(pdata->dock_connect_irq, mhcd);
@@ -680,6 +693,8 @@
unsigned long timeout;
int ret;
u32 portsc;
+ const struct msm_usb_host_platform_data *pdata;
+ u32 func_ctrl;
if (atomic_read(&mhcd->in_lpm)) {
dev_dbg(mhcd->dev, "%s called in lpm\n", __func__);
@@ -696,6 +711,14 @@
return -EBUSY;
}
+ pdata = mhcd->dev->platform_data;
+ if (pdata && pdata->is_uicc) {
+ /* put the controller in non-driving mode */
+ func_ctrl = msm_ulpi_read(mhcd, ULPI_FUNC_CTRL);
+ func_ctrl &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
+ func_ctrl |= ULPI_FUNC_CTRL_OPMODE_NONDRIVING;
+ msm_ulpi_write(mhcd, func_ctrl, ULPI_FUNC_CTRL);
+ }
/* If port is enabled wait 5ms for PHCD to come up. Reset PHY
* and link if it fails to do so.
* If port is not enabled set the PHCD bit and poll for it to
@@ -800,6 +823,8 @@
unsigned temp;
int ret;
unsigned long flags;
+ u32 func_ctrl;
+ const struct msm_usb_host_platform_data *pdata;
if (!atomic_read(&mhcd->in_lpm)) {
dev_dbg(mhcd->dev, "%s called in !in_lpm\n", __func__);
@@ -869,6 +894,14 @@
}
skip_phy_resume:
+ pdata = mhcd->dev->platform_data;
+ if (pdata && pdata->is_uicc) {
+ /* put the controller in normal mode */
+ func_ctrl = msm_ulpi_read(mhcd, ULPI_FUNC_CTRL);
+ func_ctrl &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
+ func_ctrl |= ULPI_FUNC_CTRL_OPMODE_NORMAL;
+ msm_ulpi_write(mhcd, func_ctrl, ULPI_FUNC_CTRL);
+ }
usb_hcd_resume_root_hub(hcd);
atomic_set(&mhcd->in_lpm, 0);
@@ -1323,6 +1356,8 @@
pdata->resume_gpio = of_get_named_gpio(node, "qcom,resume-gpio", 0);
if (pdata->resume_gpio < 0)
pdata->resume_gpio = 0;
+ pdata->is_uicc = of_property_read_bool(node,
+ "qcom,usb2-enable-uicc");
return pdata;
}
@@ -1339,6 +1374,14 @@
dev_dbg(&pdev->dev, "ehci_msm2 probe\n");
+ /*
+ * Fail probe in case of uicc till userspace activates driver through
+ * sysfs entry.
+ */
+ if (!uicc_card_present && pdev->dev.of_node && of_property_read_bool(
+ pdev->dev.of_node, "qcom,usb2-enable-uicc"))
+ return -ENODEV;
+
if (pdev->dev.of_node) {
dev_dbg(&pdev->dev, "device tree enabled\n");
pdev->dev.platform_data = ehci_msm2_dt_to_pdata(pdev);
@@ -1612,6 +1655,10 @@
if (mhcd->resume_gpio)
gpio_free(mhcd->resume_gpio);
+ /* If the device was removed no need to call pm_runtime_disable */
+ if (pdev->dev.power.power_state.event != PM_EVENT_INVALID)
+ pm_runtime_disable(&pdev->dev);
+
device_init_wakeup(&pdev->dev, 0);
pm_runtime_set_suspended(&pdev->dev);
diff --git a/drivers/usb/host/ice40-hcd.c b/drivers/usb/host/ice40-hcd.c
index 4d62a3e..7b0a789 100644
--- a/drivers/usb/host/ice40-hcd.c
+++ b/drivers/usb/host/ice40-hcd.c
@@ -1225,7 +1225,7 @@
{
struct ice40_hcd *ihcd = hcd_to_ihcd(hcd);
u8 ctrl0;
- int ret;
+ int ret, i;
pm_stay_awake(&ihcd->spi->dev);
trace_ice40_bus_resume(0); /* start */
@@ -1234,7 +1234,18 @@
* Re-program the previous settings. For now we need to
* update the device address only.
*/
- ice40_spi_load_fw(ihcd);
+
+ for (i = 0; i < 3; i++) {
+ ret = ice40_spi_load_fw(ihcd);
+ if (!ret)
+ break;
+ }
+
+ if (ret) {
+ pr_err("Load firmware failed with ret: %d\n", ret);
+ return ret;
+ }
+
ice40_spi_reg_write(ihcd, ihcd->devnum, FADDR_REG);
ihcd->wblen0 = ~0;
@@ -1492,7 +1503,7 @@
static int ice40_spi_load_fw(struct ice40_hcd *ihcd)
{
int ret, i;
- struct gpiomux_setting old_setting;
+ struct gpiomux_setting active_old_setting, suspend_old_setting;
ret = gpio_direction_output(ihcd->reset_gpio, 0);
if (ret < 0) {
@@ -1514,21 +1525,38 @@
* We temporarily override the chip select config to
* drive it low. The SPI bus needs to be locked down during
* this period to avoid other slave data going to our
- * bridge chip.
- *
+ * bridge chip. Disable the SPI runtime suspend for exclusive
+ * chip select access.
*/
+ pm_runtime_get_sync(ihcd->spi->master->dev.parent);
+
spi_bus_lock(ihcd->spi->master);
ret = msm_gpiomux_write(ihcd->slave_select_gpio, GPIOMUX_SUSPENDED,
- &slave_select_setting, &old_setting);
+ &slave_select_setting, &suspend_old_setting);
if (ret < 0) {
- pr_err("fail to select the slave %d\n", ret);
+ pr_err("fail to override suspend setting and select slave %d\n",
+ ret);
+ spi_bus_unlock(ihcd->spi->master);
+ pm_runtime_put_noidle(ihcd->spi->master->dev.parent);
+ goto out;
+ }
+
+ ret = msm_gpiomux_write(ihcd->slave_select_gpio, GPIOMUX_ACTIVE,
+ &slave_select_setting, &active_old_setting);
+ if (ret < 0) {
+ pr_err("fail to override active setting and select slave %d\n",
+ ret);
+ spi_bus_unlock(ihcd->spi->master);
+ pm_runtime_put_noidle(ihcd->spi->master->dev.parent);
goto out;
}
ret = ice40_spi_power_up(ihcd);
if (ret < 0) {
pr_err("fail to power up the chip\n");
+ spi_bus_unlock(ihcd->spi->master);
+ pm_runtime_put_noidle(ihcd->spi->master->dev.parent);
goto out;
}
@@ -1540,12 +1568,25 @@
usleep_range(1200, 1250);
ret = msm_gpiomux_write(ihcd->slave_select_gpio, GPIOMUX_SUSPENDED,
- &old_setting, NULL);
+ &suspend_old_setting, NULL);
if (ret < 0) {
- pr_err("fail to de-select the slave %d\n", ret);
+ pr_err("fail to rewrite suspend setting %d\n", ret);
+ spi_bus_unlock(ihcd->spi->master);
+ pm_runtime_put_noidle(ihcd->spi->master->dev.parent);
goto power_off;
}
+ ret = msm_gpiomux_write(ihcd->slave_select_gpio, GPIOMUX_ACTIVE,
+ &active_old_setting, NULL);
+ if (ret < 0) {
+ pr_err("fail to rewrite active setting %d\n", ret);
+ spi_bus_unlock(ihcd->spi->master);
+ pm_runtime_put_noidle(ihcd->spi->master->dev.parent);
+ goto power_off;
+ }
+
+ pm_runtime_put_noidle(ihcd->spi->master->dev.parent);
+
ret = spi_sync_locked(ihcd->spi, ihcd->fmsg);
spi_bus_unlock(ihcd->spi->master);
@@ -1884,6 +1925,13 @@
ihcd->port_flags |= (USB_PORT_STAT_C_CONNECTION << 16);
ihcd->pcd_pending = true;
usb_hcd_poll_rh_status(ihcd->hcd);
+ } else if (!strcmp(buf, "config_test")) {
+ ice40_spi_power_off(ihcd);
+ ret = ice40_spi_load_fw(ihcd);
+ if (ret) {
+ pr_err("config load failed\n");
+ goto out;
+ }
} else {
ret = -EINVAL;
goto out;
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index 15a9ab0..350fd41 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -1381,6 +1381,16 @@
return -ENXIO;
}
+static void msm_otg_set_online_status(struct msm_otg *motg)
+{
+ if (!psy)
+ dev_dbg(motg->phy.dev, "no usb power supply registered\n");
+
+ /* Set power supply online status to false */
+ if (power_supply_set_online(psy, false))
+ dev_dbg(motg->phy.dev, "error setting power supply property\n");
+}
+
static void msm_otg_notify_charger(struct msm_otg *motg, unsigned mA)
{
struct usb_gadget *g = motg->phy.otg->gadget;
@@ -1400,6 +1410,13 @@
"Failed notifying %d charger type to PMIC\n",
motg->chg_type);
+ /*
+ * This condition will be true when usb cable is disconnected
+ * during bootup before charger detection mechanism starts.
+ */
+ if (motg->online && motg->cur_power == 0 && mA == 0)
+ msm_otg_set_online_status(motg);
+
if (motg->cur_power == mA)
return;
@@ -2683,6 +2700,7 @@
/* Turn off VDP_SRC */
ulpi_write(otg->phy, 0x2, 0x86);
}
+ msm_chg_block_off(motg);
msm_otg_reset(otg->phy);
/*
* There is a small window where ID interrupt
diff --git a/drivers/video/msm/mdss/dsi_host_v2.c b/drivers/video/msm/mdss/dsi_host_v2.c
index 884f7f2..e62cc59 100644
--- a/drivers/video/msm/mdss/dsi_host_v2.c
+++ b/drivers/video/msm/mdss/dsi_host_v2.c
@@ -203,6 +203,13 @@
struct mdss_dsi_ctrl_pdata *ctrl =
(struct mdss_dsi_ctrl_pdata *)ptr;
+ spin_lock(&ctrl->mdp_lock);
+
+ if (ctrl->dsi_irq_mask == 0) {
+ spin_unlock(&ctrl->mdp_lock);
+ return IRQ_HANDLED;
+ }
+
isr = MIPI_INP(dsi_host_private->dsi_base + DSI_INT_CTRL);
MIPI_OUTP(dsi_host_private->dsi_base + DSI_INT_CTRL, isr);
@@ -213,22 +220,20 @@
msm_dsi_error(dsi_host_private->dsi_base);
}
- spin_lock(&ctrl->mdp_lock);
-
if (isr & DSI_INTR_VIDEO_DONE)
complete(&ctrl->video_comp);
if (isr & DSI_INTR_CMD_DMA_DONE)
complete(&ctrl->dma_comp);
- spin_unlock(&ctrl->mdp_lock);
-
if (isr & DSI_INTR_BTA_DONE)
complete(&ctrl->bta_comp);
if (isr & DSI_INTR_CMD_MDP_DONE)
complete(&ctrl->mdp_comp);
+ spin_unlock(&ctrl->mdp_lock);
+
return IRQ_HANDLED;
}
@@ -236,6 +241,13 @@
struct mdss_dsi_ctrl_pdata *ctrl)
{
int ret;
+ u32 isr;
+
+ msm_dsi_ahb_ctrl(1);
+ isr = MIPI_INP(dsi_host_private->dsi_base + DSI_INT_CTRL);
+ isr &= ~DSI_INTR_ALL_MASK;
+ MIPI_OUTP(dsi_host_private->dsi_base + DSI_INT_CTRL, isr);
+ msm_dsi_ahb_ctrl(0);
ret = devm_request_irq(dev, irq_no, msm_dsi_isr_handler,
IRQF_DISABLED, "DSI", ctrl);
@@ -1510,14 +1522,6 @@
__func__, __LINE__);
rc = -ENODEV;
goto error_irq_resource;
- } else {
- rc = msm_dsi_irq_init(&pdev->dev, mdss_dsi_mres->start,
- ctrl_pdata);
- if (rc) {
- dev_err(&pdev->dev, "%s: failed to init irq, rc=%d\n",
- __func__, rc);
- goto error_irq_resource;
- }
}
rc = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
@@ -1580,6 +1584,14 @@
msm_dsi_ctrl_init(ctrl_pdata);
+ rc = msm_dsi_irq_init(&pdev->dev, mdss_dsi_mres->start,
+ ctrl_pdata);
+ if (rc) {
+ dev_err(&pdev->dev, "%s: failed to init irq, rc=%d\n",
+ __func__, rc);
+ goto error_device_register;
+ }
+
rc = dsi_panel_device_register_v2(pdev, ctrl_pdata);
if (rc) {
pr_err("%s: dsi panel dev reg failed\n", __func__);
diff --git a/drivers/video/msm/mdss/dsi_host_v2.h b/drivers/video/msm/mdss/dsi_host_v2.h
index b297452..0f3ea8d 100644
--- a/drivers/video/msm/mdss/dsi_host_v2.h
+++ b/drivers/video/msm/mdss/dsi_host_v2.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -25,6 +25,7 @@
#define DSI_INTR_CMD_MDP_DONE BIT(8)
#define DSI_INTR_CMD_DMA_DONE_MASK BIT(1)
#define DSI_INTR_CMD_DMA_DONE BIT(0)
+#define DSI_INTR_ALL_MASK 0x2220202
#define DSI_BTA_TERM BIT(1)
diff --git a/drivers/video/msm/mdss/dsi_status_v2.c b/drivers/video/msm/mdss/dsi_status_v2.c
index d62ddf3..565401d 100644
--- a/drivers/video/msm/mdss/dsi_status_v2.c
+++ b/drivers/video/msm/mdss/dsi_status_v2.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -82,7 +82,19 @@
mdp3_session = pdsi_status->mfd->mdp.private1;
mutex_lock(&mdp3_session->lock);
- ret = ctrl_pdata->check_status(ctrl_pdata);
+ if (!mdp3_session->status) {
+ pr_info("display off already\n");
+ mutex_unlock(&mdp3_session->lock);
+ return;
+ }
+
+ if (mdp3_session->wait_for_dma_done)
+ ret = mdp3_session->wait_for_dma_done(mdp3_session);
+
+ if (!ret)
+ ret = ctrl_pdata->check_status(ctrl_pdata);
+ else
+ pr_err("wait_for_dma_done error\n");
mutex_unlock(&mdp3_session->lock);
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.c b/drivers/video/msm/mdss/mdp3_ctrl.c
index 1111aeb..6ebe06a 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.c
+++ b/drivers/video/msm/mdss/mdp3_ctrl.c
@@ -157,6 +157,7 @@
{
struct mdp3_session_data *session = (struct mdp3_session_data *)arg;
schedule_work(&session->dma_done_work);
+ complete(&session->dma_completion);
}
void vsync_count_down(void *arg)
@@ -705,6 +706,7 @@
mdp3_session->vsync_enabled = 0;
atomic_set(&mdp3_session->vsync_countdown, 0);
mdp3_session->clk_on = 0;
+ mdp3_session->in_splash_screen = 0;
off_error:
mdp3_session->status = 0;
mdp3_bufq_deinit(&mdp3_session->bufq_out);
@@ -757,6 +759,7 @@
mdp3_dma->vsync_enable(mdp3_dma, &vsync_client);
mdp3_session->first_commit = true;
+ mdp3_session->in_splash_screen = 0;
reset_error:
mutex_unlock(&mdp3_session->lock);
@@ -845,6 +848,7 @@
mdp3_dma->vsync_enable(mdp3_dma, &vsync_client);
mdp3_session->first_commit = true;
+ mdp3_session->in_splash_screen = 0;
reset_error:
mutex_unlock(&mdp3_session->lock);
@@ -897,9 +901,7 @@
dma->source_config.stride = stride;
dma->output_config.pack_pattern =
mdp3_ctrl_get_pack_pattern(req->src.format);
- mdp3_clk_enable(1, 0);
- mdp3_session->dma->dma_config_source(dma);
- mdp3_clk_enable(0, 0);
+ dma->update_src_cfg = true;
}
mdp3_session->overlay.id = 1;
req->id = 1;
@@ -923,14 +925,6 @@
mutex_lock(&mdp3_session->lock);
if (mdp3_session->overlay.id == ndx && ndx == 1) {
- struct mdp3_dma *dma = mdp3_session->dma;
- dma->source_config.format = format;
- dma->source_config.stride = fix->line_length;
- dma->output_config.pack_pattern =
- mdp3_ctrl_get_pack_pattern(mfd->fb_imgType);
- mdp3_clk_enable(1, 0);
- mdp3_session->dma->dma_config_source(dma);
- mdp3_clk_enable(0, 0);
mdp3_session->overlay.id = MSMFB_NEW_REQUEST;
mdp3_bufq_deinit(&mdp3_session->bufq_in);
} else {
@@ -1009,7 +1003,7 @@
}
panel = mdp3_session->panel;
- if (!mdp3_iommu_is_attached(MDP3_CLIENT_DMA_P)) {
+ if (mdp3_session->in_splash_screen) {
pr_debug("continuous splash screen, IOMMU not attached\n");
rc = mdp3_ctrl_reset(mfd);
if (rc) {
@@ -1046,7 +1040,8 @@
MDP_NOTIFY_FRAME_DONE);
}
}
-
+ mdp3_session->dma_active = 1;
+ init_completion(&mdp3_session->dma_completion);
mdp3_ctrl_notify(mdp3_session, MDP_NOTIFY_FRAME_FLUSHED);
mdp3_bufq_push(&mdp3_session->bufq_out, data);
}
@@ -1094,7 +1089,7 @@
if (!mdp3_session || !mdp3_session->dma)
return;
- if (!mdp3_iommu_is_attached(MDP3_CLIENT_DMA_P)) {
+ if (mdp3_session->in_splash_screen) {
pr_debug("continuous splash screen, IOMMU not attached\n");
rc = mdp3_ctrl_reset(mfd);
if (rc) {
@@ -1140,6 +1135,8 @@
MDP_NOTIFY_FRAME_DONE);
}
}
+ mdp3_session->dma_active = 1;
+ init_completion(&mdp3_session->dma_completion);
mdp3_ctrl_notify(mdp3_session, MDP_NOTIFY_FRAME_FLUSHED);
} else {
pr_debug("mdp3_ctrl_pan_display no memory, stop interface");
@@ -1761,6 +1758,23 @@
return rc;
}
+int mdp3_wait_for_dma_done(struct mdp3_session_data *session)
+{
+ int rc = 0;
+
+ if (session->dma_active) {
+ rc = wait_for_completion_timeout(&session->dma_completion,
+ KOFF_TIMEOUT);
+ if (rc > 0) {
+ session->dma_active = 0;
+ rc = 0;
+ } else if (rc == 0) {
+ rc = -ETIME;
+ }
+ }
+ return rc;
+}
+
int mdp3_ctrl_init(struct msm_fb_data_type *mfd)
{
struct device *dev = mfd->fbi->dev;
@@ -1835,6 +1849,9 @@
mdp3_session->vsync_timer.data = (u32)mdp3_session;
mdp3_session->vsync_period = 1000 / mfd->panel_info->mipi.frame_rate;
mfd->mdp.private1 = mdp3_session;
+ init_completion(&mdp3_session->dma_completion);
+ if (intf_type != MDP3_DMA_OUTPUT_SEL_DSI_VIDEO)
+ mdp3_session->wait_for_dma_done = mdp3_wait_for_dma_done;
rc = sysfs_create_group(&dev->kobj, &vsync_fs_attr_group);
if (rc) {
@@ -1859,6 +1876,7 @@
if (mdp3_get_cont_spash_en()) {
mdp3_session->clk_on = 1;
+ mdp3_session->in_splash_screen = 1;
mdp3_ctrl_notifier_register(mdp3_session,
&mdp3_session->mfd->mdp_sync_pt_data.notifier);
}
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.h b/drivers/video/msm/mdss/mdp3_ctrl.h
index cfad1d3..20649fc 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.h
+++ b/drivers/video/msm/mdss/mdp3_ctrl.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, 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
@@ -61,6 +61,11 @@
int vsync_enabled;
atomic_t vsync_countdown; /* Used to count down */
+ bool in_splash_screen;
+
+ bool dma_active;
+ struct completion dma_completion;
+ int (*wait_for_dma_done)(struct mdp3_session_data *session);
};
int mdp3_ctrl_init(struct msm_fb_data_type *mfd);
diff --git a/drivers/video/msm/mdss/mdp3_dma.c b/drivers/video/msm/mdss/mdp3_dma.c
index 993a36f..8a13de2 100644
--- a/drivers/video/msm/mdss/mdp3_dma.c
+++ b/drivers/video/msm/mdss/mdp3_dma.c
@@ -605,6 +605,13 @@
}
}
}
+ if (dma->update_src_cfg) {
+ if (dma->output_config.out_sel ==
+ MDP3_DMA_OUTPUT_SEL_DSI_VIDEO && intf->active)
+ pr_err("configuring dma source while dma is active\n");
+ dma->dma_config_source(dma);
+ dma->update_src_cfg = false;
+ }
spin_lock_irqsave(&dma->dma_lock, flag);
MDP3_REG_WRITE(MDP3_REG_DMA_P_IBUF_ADDR, (u32)buf);
dma->source_config.buf = buf;
@@ -961,6 +968,7 @@
dma->vsync_client.handler = NULL;
dma->vsync_client.arg = NULL;
dma->histo_state = MDP3_DMA_HISTO_STATE_IDLE;
+ dma->update_src_cfg = false;
memset(&dma->cursor, 0, sizeof(dma->cursor));
memset(&dma->ccs_config, 0, sizeof(dma->ccs_config));
diff --git a/drivers/video/msm/mdss/mdp3_dma.h b/drivers/video/msm/mdss/mdp3_dma.h
index 207168f..80ebb9b 100644
--- a/drivers/video/msm/mdss/mdp3_dma.h
+++ b/drivers/video/msm/mdss/mdp3_dma.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, 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
@@ -259,6 +259,7 @@
int histo_state;
struct mdp3_dma_histogram_data histo_data;
unsigned int vsync_status;
+ bool update_src_cfg;
int (*dma_config)(struct mdp3_dma *dma,
struct mdp3_dma_source *source_config,
diff --git a/drivers/video/msm/mdss/mdss_dsi.c b/drivers/video/msm/mdss/mdss_dsi.c
index 7b4b065..6de0df6 100644
--- a/drivers/video/msm/mdss/mdss_dsi.c
+++ b/drivers/video/msm/mdss/mdss_dsi.c
@@ -321,7 +321,7 @@
ctrl_pdata, ctrl_pdata->ndx);
if (pdata->panel_info.type == MIPI_CMD_PANEL)
- mdss_dsi_clk_ctrl(ctrl_pdata, 1);
+ mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 1);
/* disable DSI controller */
mdss_dsi_controller_cfg(0, pdata);
@@ -329,7 +329,7 @@
/* disable DSI phy */
mdss_dsi_phy_disable(ctrl_pdata);
- mdss_dsi_clk_ctrl(ctrl_pdata, 0);
+ mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 0);
ret = mdss_dsi_panel_power_on(pdata, 0);
if (ret) {
@@ -465,14 +465,20 @@
goto error;
}
- if (__mdss_dsi_clk_enabled(ctrl_pdata)) {
+ if (__mdss_dsi_clk_enabled(ctrl_pdata, DSI_LINK_CLKS)) {
pr_err("%s: cannot enter ulps mode if dsi clocks are on\n",
__func__);
ret = -EPERM;
goto error;
}
- mdss_dsi_clk_ctrl(ctrl_pdata, 1);
+ ret = mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 1);
+ if (ret) {
+ pr_err("%s: Failed to enable clocks. rc=%d\n",
+ __func__, ret);
+ goto error;
+ }
+
/*
* ULPS Entry Request.
* Wait for a short duration to ensure that the lanes
@@ -480,6 +486,14 @@
*/
MIPI_OUTP(ctrl_pdata->ctrl_base + 0x0AC, 0x01F);
usleep(100);
+ lane_status = MIPI_INP(ctrl_pdata->ctrl_base + 0xA8);
+ if (lane_status & 0x1F00) {
+ pr_err("%s: ULPS entry req failed. Lane status=0x%08x\n",
+ __func__, lane_status);
+ ret = -EINVAL;
+ mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 0);
+ goto error;
+ }
/* Enable MMSS DSI Clamps */
MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x14, 0x3FF);
@@ -491,10 +505,17 @@
/* disable DSI controller */
mdss_dsi_controller_cfg(0, pdata);
- lane_status = MIPI_INP(ctrl_pdata->ctrl_base + 0xA8),
- mdss_dsi_clk_ctrl(ctrl_pdata, 0);
+ mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 0);
ctrl_pdata->ulps = true;
} else if (ctrl_pdata->ulps) {
+ ret = mdss_dsi_clk_ctrl(ctrl_pdata, DSI_BUS_CLKS, 1);
+ if (ret) {
+ pr_err("%s: Failed to enable bus clocks. rc=%d\n",
+ __func__, ret);
+ goto error;
+ }
+
+ MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x108, 0x0);
mdss_dsi_phy_init(pdata);
__mdss_dsi_ctrl_setup(pdata);
@@ -503,9 +524,28 @@
mdss_dsi_op_mode_config(pdata->panel_info.mipi.mode,
pdata);
+ /*
+ * ULPS Entry Request. This is needed because, after power
+ * collapse and reset, the DSI controller resets back to
+ * idle state and not ULPS.
+ * Wait for a short duration to ensure that the lanes
+ * enter ULP state.
+ */
+ MIPI_OUTP(ctrl_pdata->ctrl_base + 0x0AC, 0x01F);
+ usleep(100);
+
/* Disable MMSS DSI Clamps */
+ MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x14, 0x3FF);
MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x14, 0x0);
+ ret = mdss_dsi_clk_ctrl(ctrl_pdata, DSI_LINK_CLKS, 1);
+ if (ret) {
+ pr_err("%s: Failed to enable link clocks. rc=%d\n",
+ __func__, ret);
+ mdss_dsi_clk_ctrl(ctrl_pdata, DSI_BUS_CLKS, 0);
+ goto error;
+ }
+
/*
* ULPS Exit Request
* Hardware requirement is to wait for at least 1ms
@@ -520,7 +560,9 @@
*/
usleep(100);
- lane_status = MIPI_INP(ctrl_pdata->ctrl_base + 0xA8),
+ lane_status = MIPI_INP(ctrl_pdata->ctrl_base + 0xA8);
+ mdss_dsi_clk_ctrl(ctrl_pdata, DSI_LINK_CLKS, 0);
+ mdss_dsi_clk_ctrl(ctrl_pdata, DSI_BUS_CLKS, 0);
ctrl_pdata->ulps = false;
}
@@ -535,21 +577,31 @@
int enable)
{
int rc;
- struct mdss_dsi_ctrl_pdata *sctrl = NULL;
+ struct mdss_dsi_ctrl_pdata *mctrl = NULL;
- if (ctrl->flags & DSI_FLAG_CLOCK_MASTER)
- sctrl = mdss_dsi_ctrl_slave(ctrl);
+ if (&ctrl->mmss_misc_io == NULL) {
+ pr_err("%s: mmss_misc_io is NULL. ULPS not valid\n", __func__);
+ return -EINVAL;
+ }
- if (sctrl) {
- pr_debug("%s: configuring ulps (%s) for slave ctrl\n",
- __func__, (enable ? "on" : "off"));
- rc = mdss_dsi_ulps_config_sub(sctrl, enable);
+ if (mdss_dsi_is_slave_ctrl(ctrl)) {
+ mctrl = mdss_dsi_get_master_ctrl();
+ if (!mctrl) {
+ pr_err("%s: Unable to get master control\n", __func__);
+ return -EINVAL;
+ }
+ }
+
+ if (mctrl) {
+ pr_debug("%s: configuring ulps (%s) for master ctrl%d\n",
+ __func__, (enable ? "on" : "off"), ctrl->ndx);
+ rc = mdss_dsi_ulps_config_sub(mctrl, enable);
if (rc)
return rc;
}
- pr_debug("%s: configuring ulps (%s) for master ctrl\n",
- __func__, (enable ? "on" : "off"));
+ pr_debug("%s: configuring ulps (%s) for ctrl%d\n",
+ __func__, (enable ? "on" : "off"), ctrl->ndx);
return mdss_dsi_ulps_config_sub(ctrl, enable);
}
@@ -585,7 +637,7 @@
return ret;
}
- ret = mdss_dsi_bus_clk_start(ctrl_pdata);
+ mdss_dsi_clk_ctrl(ctrl_pdata, DSI_BUS_CLKS, 1);
if (ret) {
pr_err("%s: failed to enable bus clocks. rc=%d\n", __func__,
ret);
@@ -602,9 +654,9 @@
mdss_dsi_phy_sw_reset((ctrl_pdata->ctrl_base));
mdss_dsi_phy_init(pdata);
- mdss_dsi_bus_clk_stop(ctrl_pdata);
+ mdss_dsi_clk_ctrl(ctrl_pdata, DSI_BUS_CLKS, 0);
- mdss_dsi_clk_ctrl(ctrl_pdata, 1);
+ mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 1);
__mdss_dsi_ctrl_setup(pdata);
mdss_dsi_sw_reset(pdata);
@@ -630,7 +682,7 @@
}
if (pdata->panel_info.type == MIPI_CMD_PANEL)
- mdss_dsi_clk_ctrl(ctrl_pdata, 0);
+ mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 0);
pr_debug("%s-:\n", __func__);
return 0;
@@ -834,8 +886,8 @@
MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0004,
dsi_ctrl);
mdss_dsi_controller_cfg(true, pdata);
- mdss_dsi_clk_ctrl(ctrl_pdata, 0);
- mdss_dsi_clk_ctrl(ctrl_pdata, 1);
+ mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 0);
+ mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 1);
dsi_ctrl |= 0x2;
MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0004,
dsi_ctrl);
@@ -1190,6 +1242,8 @@
mdss_dsi_put_dt_vreg_data(&pdev->dev, &ctrl_pdata->power_data);
mfd = platform_get_drvdata(pdev);
msm_dss_iounmap(&ctrl_pdata->mmss_misc_io);
+ msm_dss_iounmap(&ctrl_pdata->phy_io);
+ msm_dss_iounmap(&ctrl_pdata->ctrl_io);
return 0;
}
@@ -1200,7 +1254,6 @@
{
int rc = 0;
u32 index;
- struct resource *mdss_dsi_mres;
rc = of_property_read_u32(pdev->dev.of_node, "cell-index", &index);
if (rc) {
@@ -1228,31 +1281,32 @@
return -EPERM;
}
- mdss_dsi_mres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!mdss_dsi_mres) {
- pr_err("%s:%d unable to get the DSI ctrl resources",
+ rc = msm_dss_ioremap_byname(pdev, &ctrl->ctrl_io, "dsi_ctrl");
+ if (rc) {
+ pr_err("%s:%d unable to remap dsi ctrl resources",
__func__, __LINE__);
- return -ENOMEM;
+ return rc;
}
- ctrl->ctrl_base = ioremap(mdss_dsi_mres->start,
- resource_size(mdss_dsi_mres));
- if (!(ctrl->ctrl_base)) {
- pr_err("%s:%d unable to remap dsi resources",
+ ctrl->ctrl_base = ctrl->ctrl_io.base;
+ ctrl->reg_size = ctrl->ctrl_io.len;
+
+ rc = msm_dss_ioremap_byname(pdev, &ctrl->phy_io, "dsi_phy");
+ if (rc) {
+ pr_err("%s:%d unable to remap dsi phy resources",
__func__, __LINE__);
- return -ENOMEM;
+ return rc;
}
- ctrl->reg_size = resource_size(mdss_dsi_mres);
-
- pr_info("%s: dsi base=%x size=%x\n",
- __func__, (int)ctrl->ctrl_base, ctrl->reg_size);
+ pr_info("%s: ctrl_base=%p ctrl_size=%x phy_base=%p phy_size=%x\n",
+ __func__, ctrl->ctrl_base, ctrl->reg_size, ctrl->phy_io.base,
+ ctrl->phy_io.len);
rc = msm_dss_ioremap_byname(pdev, &ctrl->mmss_misc_io,
"mmss_misc_phys");
if (rc) {
- pr_err("%s:%d mmss_misc IO remap failed\n", __func__, __LINE__);
- return rc;
+ pr_debug("%s:%d mmss_misc IO remap failed\n",
+ __func__, __LINE__);
}
return 0;
@@ -1492,7 +1546,7 @@
return rc;
}
- mdss_dsi_clk_ctrl(ctrl_pdata, 1);
+ mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 1);
ctrl_pdata->ctrl_state |=
(CTRL_STATE_PANEL_INIT | CTRL_STATE_MDP_ACTIVE);
} else {
diff --git a/drivers/video/msm/mdss/mdss_dsi.h b/drivers/video/msm/mdss/mdss_dsi.h
index 57b0e75..b0b884f 100644
--- a/drivers/video/msm/mdss/mdss_dsi.h
+++ b/drivers/video/msm/mdss/mdss_dsi.h
@@ -151,8 +151,8 @@
#define DSI_CMD_TERM BIT(0)
extern struct device dsi_dev;
-extern int mdss_dsi_clk_on;
extern u32 dsi_irq;
+extern struct mdss_dsi_ctrl_pdata *ctrl_list[];
struct dsiphy_pll_divider_config {
u32 clk_rate;
@@ -223,12 +223,18 @@
DSI_CTRL_MAX,
};
+/* DSI controller #0 is always treated as a master in broadcast mode */
+#define DSI_CTRL_MASTER DSI_CTRL_0
+#define DSI_CTRL_SLAVE DSI_CTRL_1
+
+#define DSI_BUS_CLKS BIT(0)
+#define DSI_LINK_CLKS BIT(1)
+#define DSI_ALL_CLKS ((DSI_BUS_CLKS) | (DSI_LINK_CLKS))
+
#define DSI_EV_PLL_UNLOCKED 0x0001
#define DSI_EV_MDP_FIFO_UNDERFLOW 0x0002
#define DSI_EV_MDP_BUSY_RELEASE 0x80000000
-#define DSI_FLAG_CLOCK_MASTER 0x80000000
-
struct mdss_dsi_ctrl_pdata {
int ndx; /* panel_num */
int (*on) (struct mdss_panel_data *pdata);
@@ -238,10 +244,12 @@
int (*cmdlist_commit)(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp);
struct mdss_panel_data panel_data;
unsigned char *ctrl_base;
+ struct dss_io_data ctrl_io;
struct dss_io_data mmss_misc_io;
+ struct dss_io_data phy_io;
int reg_size;
- u32 clk_cnt;
- int clk_cnt_sub;
+ u32 bus_clk_cnt;
+ u32 link_clk_cnt;
u32 flags;
struct clk *mdp_core_clk;
struct clk *ahb_clk;
@@ -253,7 +261,6 @@
u8 ctrl_state;
int panel_mode;
int irq_cnt;
- int mdss_dsi_clk_on;
int rst_gpio;
int disp_en_gpio;
int disp_te_gpio;
@@ -312,20 +319,14 @@
void mdss_dsi_cmd_mdp_start(struct mdss_dsi_ctrl_pdata *ctrl);
void mdss_dsi_cmd_bta_sw_trigger(struct mdss_panel_data *pdata);
void mdss_dsi_ack_err_status(struct mdss_dsi_ctrl_pdata *ctrl);
-void mdss_dsi_clk_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, int enable);
-int mdss_dsi_link_clk_start(struct mdss_dsi_ctrl_pdata *ctrl);
-void mdss_dsi_link_clk_stop(struct mdss_dsi_ctrl_pdata *ctrl);
-int mdss_dsi_bus_clk_start(struct mdss_dsi_ctrl_pdata *ctrl);
-void mdss_dsi_bus_clk_stop(struct mdss_dsi_ctrl_pdata *ctrl);
+int mdss_dsi_clk_ctrl(struct mdss_dsi_ctrl_pdata *ctrl,
+ u8 clk_type, int enable);
void mdss_dsi_clk_req(struct mdss_dsi_ctrl_pdata *ctrl,
int enable);
void mdss_dsi_controller_cfg(int enable,
struct mdss_panel_data *pdata);
void mdss_dsi_sw_reset(struct mdss_panel_data *pdata);
-struct mdss_dsi_ctrl_pdata *mdss_dsi_ctrl_slave(
- struct mdss_dsi_ctrl_pdata *ctrl);
-
irqreturn_t mdss_dsi_isr(int irq, void *ptr);
void mdss_dsi_irq_handler_config(struct mdss_dsi_ctrl_pdata *ctrl_pdata);
@@ -351,9 +352,52 @@
int mdss_dsi_cmdlist_commit(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp);
void mdss_dsi_cmdlist_kickoff(int intf);
int mdss_dsi_bta_status_check(struct mdss_dsi_ctrl_pdata *ctrl);
-bool __mdss_dsi_clk_enabled(struct mdss_dsi_ctrl_pdata *ctrl);
+bool __mdss_dsi_clk_enabled(struct mdss_dsi_ctrl_pdata *ctrl, u8 clk_type);
int mdss_dsi_panel_init(struct device_node *node,
struct mdss_dsi_ctrl_pdata *ctrl_pdata,
bool cmd_cfg_cont_splash);
+
+static inline bool mdss_dsi_broadcast_mode_enabled(void)
+{
+ return ctrl_list[DSI_CTRL_MASTER]->shared_pdata.broadcast_enable &&
+ ctrl_list[DSI_CTRL_SLAVE] &&
+ ctrl_list[DSI_CTRL_SLAVE]->shared_pdata.broadcast_enable;
+}
+
+static inline struct mdss_dsi_ctrl_pdata *mdss_dsi_get_master_ctrl(void)
+{
+ if (mdss_dsi_broadcast_mode_enabled())
+ return ctrl_list[DSI_CTRL_MASTER];
+ else
+ return NULL;
+}
+
+static inline struct mdss_dsi_ctrl_pdata *mdss_dsi_get_slave_ctrl(void)
+{
+ if (mdss_dsi_broadcast_mode_enabled())
+ return ctrl_list[DSI_CTRL_SLAVE];
+ else
+ return NULL;
+}
+
+static inline bool mdss_dsi_is_master_ctrl(struct mdss_dsi_ctrl_pdata *ctrl)
+{
+ return mdss_dsi_broadcast_mode_enabled() &&
+ (ctrl->ndx == DSI_CTRL_MASTER);
+}
+
+static inline bool mdss_dsi_is_slave_ctrl(struct mdss_dsi_ctrl_pdata *ctrl)
+{
+ return mdss_dsi_broadcast_mode_enabled() &&
+ (ctrl->ndx == DSI_CTRL_SLAVE);
+}
+
+static inline struct mdss_dsi_ctrl_pdata *mdss_dsi_get_ctrl_by_index(int ndx)
+{
+ if (ndx >= DSI_CTRL_MAX)
+ return NULL;
+
+ return ctrl_list[ndx];
+}
#endif /* MDSS_DSI_H */
diff --git a/drivers/video/msm/mdss/mdss_dsi_host.c b/drivers/video/msm/mdss/mdss_dsi_host.c
index c2fbc1a..a570914 100644
--- a/drivers/video/msm/mdss/mdss_dsi_host.c
+++ b/drivers/video/msm/mdss/mdss_dsi_host.c
@@ -29,10 +29,7 @@
#define VSYNC_PERIOD 17
-static struct mdss_dsi_ctrl_pdata *left_ctrl_pdata;
-
-static struct mdss_dsi_ctrl_pdata *ctrl_list[DSI_CTRL_MAX];
-
+struct mdss_dsi_ctrl_pdata *ctrl_list[DSI_CTRL_MAX];
struct mdss_hw mdss_dsi0_hw = {
.hw_ndx = MDSS_HW_DSI0,
@@ -72,14 +69,6 @@
void mdss_dsi_ctrl_init(struct mdss_dsi_ctrl_pdata *ctrl)
{
- if (ctrl->shared_pdata.broadcast_enable)
- if (ctrl->panel_data.panel_info.pdest
- == DISPLAY_1) {
- pr_debug("%s: Broadcast mode enabled.\n",
- __func__);
- left_ctrl_pdata = ctrl;
- }
-
if (ctrl->panel_data.panel_info.pdest == DISPLAY_1) {
mdss_dsi0_hw.ptr = (void *)(ctrl);
ctrl->dsi_hw = &mdss_dsi0_hw;
@@ -90,11 +79,9 @@
ctrl->ndx = DSI_CTRL_1;
}
- ctrl_list[ctrl->ndx] = ctrl; /* keep it */
+ ctrl->panel_mode = ctrl->panel_data.panel_info.mipi.mode;
- if (ctrl->shared_pdata.broadcast_enable)
- if (ctrl->ndx == DSI_CTRL_1)
- ctrl->flags |= DSI_FLAG_CLOCK_MASTER;
+ ctrl_list[ctrl->ndx] = ctrl; /* keep it */
if (mdss_register_irq(ctrl->dsi_hw))
pr_err("%s: mdss_register_irq failed.\n", __func__);
@@ -121,22 +108,6 @@
}
}
-struct mdss_dsi_ctrl_pdata *mdss_dsi_ctrl_slave(
- struct mdss_dsi_ctrl_pdata *ctrl)
-{
- int ndx;
- struct mdss_dsi_ctrl_pdata *sctrl = NULL;
-
- /* only two controllers */
- ndx = ctrl->ndx;
- ndx += 1;
- ndx %= DSI_CTRL_MAX;
- sctrl = ctrl_list[ndx];
-
- return sctrl;
-
-}
-
void mdss_dsi_clk_req(struct mdss_dsi_ctrl_pdata *ctrl, int enable)
{
if (enable == 0) {
@@ -146,22 +117,26 @@
mutex_unlock(&ctrl->cmd_mutex);
}
- mdss_dsi_clk_ctrl(ctrl, enable);
+ mdss_dsi_clk_ctrl(ctrl, DSI_ALL_CLKS, enable);
}
void mdss_dsi_pll_relock(struct mdss_dsi_ctrl_pdata *ctrl)
{
int i, cnt;
- cnt = ctrl->clk_cnt;
+ /*
+ * todo: this code does not work very well with dual
+ * dsi use cases. Need to fix this eventually.
+ */
+ cnt = ctrl->link_clk_cnt;
/* disable dsi clk */
for (i = 0; i < cnt; i++)
- mdss_dsi_clk_ctrl(ctrl, 0);
+ mdss_dsi_clk_ctrl(ctrl, DSI_LINK_CLKS, 0);
/* enable dsi clk */
for (i = 0; i < cnt; i++)
- mdss_dsi_clk_ctrl(ctrl, 1);
+ mdss_dsi_clk_ctrl(ctrl, DSI_LINK_CLKS, 1);
}
void mdss_dsi_enable_irq(struct mdss_dsi_ctrl_pdata *ctrl, u32 term)
@@ -269,8 +244,6 @@
pinfo->rgb_swap = DSI_RGB_SWAP_RGB;
- ctrl_pdata->panel_mode = pinfo->mode;
-
if (pinfo->mode == DSI_VIDEO_MODE) {
data = 0;
if (pinfo->pulse_mode_hsa_he)
@@ -341,7 +314,7 @@
/* from frame buffer, low power mode */
/* DSI_COMMAND_MODE_DMA_CTRL */
- if (ctrl_pdata->shared_pdata.broadcast_enable)
+ if (mdss_dsi_broadcast_mode_enabled())
MIPI_OUTP(ctrl_pdata->ctrl_base + 0x3C, 0x94000000);
else
MIPI_OUTP(ctrl_pdata->ctrl_base + 0x3C, 0x14000000);
@@ -544,6 +517,7 @@
{
u32 dsi_ctrl, intr_ctrl;
struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+ struct mdss_dsi_ctrl_pdata *mctrl = NULL;
if (pdata == NULL) {
pr_err("%s: Invalid input data\n", __func__);
@@ -553,12 +527,15 @@
ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
panel_data);
- if (ctrl_pdata->shared_pdata.broadcast_enable)
- if (pdata->panel_info.pdest == DISPLAY_1) {
- pr_debug("%s: Broadcast mode. 1st ctrl\n",
- __func__);
- return;
- }
+ /*
+ * In broadcast mode, the configuration for master controller
+ * would be done when the slave controller is configured
+ */
+ if (mdss_dsi_is_master_ctrl(ctrl_pdata)) {
+ pr_debug("%s: Broadcast mode enabled. skipping config for ctrl%d\n",
+ __func__, ctrl_pdata->ndx);
+ return;
+ }
dsi_ctrl = MIPI_INP((ctrl_pdata->ctrl_base) + 0x0004);
/*If Video enabled, Keep Video and Cmd mode ON */
@@ -579,17 +556,22 @@
DSI_INTR_CMD_MDP_DONE_MASK | DSI_INTR_BTA_DONE_MASK;
}
- if (ctrl_pdata->shared_pdata.broadcast_enable)
- if ((pdata->panel_info.pdest == DISPLAY_2)
- && (left_ctrl_pdata != NULL)) {
- MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x0110,
- intr_ctrl); /* DSI_INTL_CTRL */
- MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x0004,
- dsi_ctrl);
+ /* Ensure that for slave controller, master is also configured */
+ if (mdss_dsi_is_slave_ctrl(ctrl_pdata)) {
+ mctrl = mdss_dsi_get_master_ctrl();
+ if (mctrl) {
+ pr_debug("%s: configuring ctrl%d\n", __func__,
+ mctrl->ndx);
+ MIPI_OUTP(mctrl->ctrl_base + 0x0110, intr_ctrl);
+ MIPI_OUTP(mctrl->ctrl_base + 0x0004, dsi_ctrl);
+ } else {
+ pr_warn("%s: Unable to get master control\n",
+ __func__);
}
+ }
- MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0110,
- intr_ctrl); /* DSI_INTL_CTRL */
+ pr_debug("%s: configuring ctrl%d\n", __func__, ctrl_pdata->ndx);
+ MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0110, intr_ctrl);
MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0004, dsi_ctrl);
wmb();
}
@@ -640,7 +622,7 @@
pr_debug("%s: Checking BTA status\n", __func__);
- mdss_dsi_clk_ctrl(ctrl_pdata, 1);
+ mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 1);
spin_lock_irqsave(&ctrl_pdata->mdp_lock, flag);
INIT_COMPLETION(ctrl_pdata->bta_comp);
mdss_dsi_enable_irq(ctrl_pdata, DSI_BTA_TERM);
@@ -655,7 +637,7 @@
pr_err("%s: DSI BTA error: %i\n", __func__, ret);
}
- mdss_dsi_clk_ctrl(ctrl_pdata, 0);
+ mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 0);
pr_debug("%s: BTA done with ret: %d\n", __func__, ret);
return ret;
@@ -744,6 +726,40 @@
return tot;
}
+/**
+ * __mdss_dsi_cmd_mode_config() - Enable/disable command mode engine
+ * @ctrl: pointer to the dsi controller structure
+ * @enable: true to enable command mode, false to disable command mode
+ *
+ * This function can be used to temporarily enable the command mode
+ * engine (even for video mode panels) so as to transfer any dma commands to
+ * the panel. It can also be used to disable the command mode engine
+ * when no longer needed.
+ *
+ * Return: true, if there was a mode switch to command mode for video mode
+ * panels.
+ */
+static inline bool __mdss_dsi_cmd_mode_config(
+ struct mdss_dsi_ctrl_pdata *ctrl, bool enable)
+{
+ bool mode_changed = false;
+ u32 dsi_ctrl;
+
+ dsi_ctrl = MIPI_INP((ctrl->ctrl_base) + 0x0004);
+ /* if currently in video mode, enable command mode */
+ if (enable) {
+ if ((dsi_ctrl) & BIT(1)) {
+ MIPI_OUTP((ctrl->ctrl_base) + 0x0004,
+ dsi_ctrl | BIT(2));
+ mode_changed = true;
+ }
+ } else {
+ MIPI_OUTP((ctrl->ctrl_base) + 0x0004, dsi_ctrl & ~BIT(2));
+ }
+
+ return mode_changed;
+}
+
/*
* mdss_dsi_cmds_tx:
* thread context only
@@ -751,61 +767,49 @@
int mdss_dsi_cmds_tx(struct mdss_dsi_ctrl_pdata *ctrl,
struct dsi_cmd_desc *cmds, int cnt)
{
- u32 dsi_ctrl, data;
- int video_mode, ret = 0;
- u32 left_dsi_ctrl = 0;
- bool left_ctrl_restore = false;
+ int ret = 0;
+ bool ctrl_restore = false, mctrl_restore = false;
+ struct mdss_dsi_ctrl_pdata *mctrl = NULL;
- if (ctrl->shared_pdata.broadcast_enable) {
- if (ctrl->ndx == DSI_CTRL_0) {
- pr_debug("%s: Broadcast mode. 1st ctrl\n",
- __func__);
- return 0;
- }
+ /*
+ * In broadcast mode, the configuration for master controller
+ * would be done when the slave controller is configured
+ */
+ if (mdss_dsi_is_master_ctrl(ctrl)) {
+ pr_debug("%s: Broadcast mode enabled. skipping config for ctrl%d\n",
+ __func__, ctrl->ndx);
+ return 0;
}
- if (ctrl->shared_pdata.broadcast_enable) {
- if ((ctrl->ndx == DSI_CTRL_1)
- && (left_ctrl_pdata != NULL)) {
- left_dsi_ctrl = MIPI_INP(left_ctrl_pdata->ctrl_base
- + 0x0004);
- video_mode =
- left_dsi_ctrl & 0x02; /* VIDEO_MODE_EN */
- if (video_mode) {
- data = left_dsi_ctrl | 0x04; /* CMD_MODE_EN */
- MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x0004,
- data);
- left_ctrl_restore = true;
- }
- }
+ /*
+ * Turn on cmd mode in order to transmit the commands.
+ * For video mode, do not send cmds more than one pixel line,
+ * since it only transmit it during BLLP.
+ * Ensure that for slave controller, master is also configured
+ */
+ if (mdss_dsi_is_slave_ctrl(ctrl)) {
+ mctrl = mdss_dsi_get_master_ctrl();
+ if (!mctrl)
+ pr_warn("%s: Unable to get master control\n",
+ __func__);
+ else
+ mctrl_restore = __mdss_dsi_cmd_mode_config(mctrl, 1);
}
- /* turn on cmd mode
- * for video mode, do not send cmds more than
- * one pixel line, since it only transmit it
- * during BLLP.
- */
- dsi_ctrl = MIPI_INP((ctrl->ctrl_base) + 0x0004);
- video_mode = dsi_ctrl & 0x02; /* VIDEO_MODE_EN */
- if (video_mode) {
- data = dsi_ctrl | 0x04; /* CMD_MODE_EN */
- MIPI_OUTP((ctrl->ctrl_base) + 0x0004, data);
- }
+ ctrl_restore = __mdss_dsi_cmd_mode_config(ctrl, 1);
ret = mdss_dsi_cmds2buf_tx(ctrl, cmds, cnt);
if (IS_ERR_VALUE(ret)) {
- pr_err("%s: failed to call\n",
- __func__);
+ pr_err("%s: failed to call\n", __func__);
cnt = -EINVAL;
}
- if (left_ctrl_restore)
- MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x0004,
- left_dsi_ctrl); /*restore */
+ if (mctrl_restore)
+ __mdss_dsi_cmd_mode_config(mctrl, 0);
- if (video_mode)
- MIPI_OUTP((ctrl->ctrl_base) + 0x0004,
- dsi_ctrl); /* restore */
+ if (ctrl_restore)
+ __mdss_dsi_cmd_mode_config(ctrl, 0);
+
return cnt;
}
@@ -838,45 +842,35 @@
int short_response, diff, pkt_size, ret = 0;
struct dsi_buf *tp, *rp;
char cmd;
- u32 dsi_ctrl, data;
- int video_mode;
- u32 left_dsi_ctrl = 0;
- bool left_ctrl_restore = false;
+ bool ctrl_restore = false, mctrl_restore = false;
+ struct mdss_dsi_ctrl_pdata *mctrl = NULL;
- if (ctrl->shared_pdata.broadcast_enable) {
- if (ctrl->ndx == DSI_CTRL_0) {
- pr_debug("%s: Broadcast mode. 1st ctrl\n",
- __func__);
- return 0;
- }
+ /*
+ * In broadcast mode, the configuration for master controller
+ * would be done when the slave controller is configured
+ */
+ if (mdss_dsi_is_master_ctrl(ctrl)) {
+ pr_debug("%s: Broadcast mode enabled. skipping config for ctrl%d\n",
+ __func__, ctrl->ndx);
+ return 0;
}
- if (ctrl->shared_pdata.broadcast_enable) {
- if ((ctrl->ndx == DSI_CTRL_1)
- && (left_ctrl_pdata != NULL)) {
- left_dsi_ctrl = MIPI_INP(left_ctrl_pdata->ctrl_base
- + 0x0004);
- video_mode = left_dsi_ctrl & 0x02; /* VIDEO_MODE_EN */
- if (video_mode) {
- data = left_dsi_ctrl | 0x04; /* CMD_MODE_EN */
- MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x0004,
- data);
- left_ctrl_restore = true;
- }
- }
+ /*
+ * Turn on cmd mode in order to transmit the commands.
+ * For video mode, do not send cmds more than one pixel line,
+ * since it only transmit it during BLLP.
+ * Ensure that for slave controller, master is also configured
+ */
+ if (mdss_dsi_is_slave_ctrl(ctrl)) {
+ mctrl = mdss_dsi_get_master_ctrl();
+ if (!mctrl)
+ pr_warn("%s: Unable to get master control\n",
+ __func__);
+ else
+ mctrl_restore = __mdss_dsi_cmd_mode_config(mctrl, 1);
}
- /* turn on cmd mode
- * for video mode, do not send cmds more than
- * one pixel line, since it only transmit it
- * during BLLP.
- */
- dsi_ctrl = MIPI_INP((ctrl->ctrl_base) + 0x0004);
- video_mode = dsi_ctrl & 0x02; /* VIDEO_MODE_EN */
- if (video_mode) {
- data = dsi_ctrl | 0x04; /* CMD_MODE_EN */
- MIPI_OUTP((ctrl->ctrl_base) + 0x0004, data);
- }
+ ctrl_restore = __mdss_dsi_cmd_mode_config(ctrl, 1);
if (rlen == 0) {
short_response = 1;
@@ -1003,12 +997,11 @@
rp->len = 0;
}
end:
- if (left_ctrl_restore)
- MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x0004,
- left_dsi_ctrl); /*restore */
- if (video_mode)
- MIPI_OUTP((ctrl->ctrl_base) + 0x0004,
- dsi_ctrl); /* restore */
+ if (mctrl_restore)
+ __mdss_dsi_cmd_mode_config(mctrl, 0);
+
+ if (ctrl_restore)
+ __mdss_dsi_cmd_mode_config(ctrl, 0);
return rp->len;
}
@@ -1022,6 +1015,7 @@
int domain = MDSS_IOMMU_DOMAIN_UNSECURE;
char *bp;
unsigned long size, addr;
+ struct mdss_dsi_ctrl_pdata *mctrl = NULL;
bp = tp->data;
@@ -1043,24 +1037,27 @@
INIT_COMPLETION(ctrl->dma_comp);
- if (ctrl->shared_pdata.broadcast_enable)
- if ((ctrl->ndx == DSI_CTRL_1)
- && (left_ctrl_pdata != NULL)) {
- MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x048, addr);
- MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x04c, len);
+ /* Ensure that for slave controller, master is also configured */
+ if (mdss_dsi_is_slave_ctrl(ctrl)) {
+ mctrl = mdss_dsi_get_master_ctrl();
+ if (mctrl) {
+ MIPI_OUTP(mctrl->ctrl_base + 0x048, addr);
+ MIPI_OUTP(mctrl->ctrl_base + 0x04c, len);
+ } else {
+ pr_warn("%s: Unable to get master control\n",
+ __func__);
}
+ }
MIPI_OUTP((ctrl->ctrl_base) + 0x048, addr);
MIPI_OUTP((ctrl->ctrl_base) + 0x04c, len);
wmb();
- if (ctrl->shared_pdata.broadcast_enable)
- if ((ctrl->ndx == DSI_CTRL_1)
- && (left_ctrl_pdata != NULL)) {
- MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x090, 0x01);
- }
+ /* Trigger on master controller as well */
+ if (mctrl)
+ MIPI_OUTP(mctrl->ctrl_base + 0x090, 0x01);
- MIPI_OUTP((ctrl->ctrl_base) + 0x090, 0x01); /* trigger */
+ MIPI_OUTP((ctrl->ctrl_base) + 0x090, 0x01);
wmb();
ret = wait_for_completion_timeout(&ctrl->dma_comp,
@@ -1210,13 +1207,11 @@
len = mdss_dsi_cmds_rx(ctrl, req->cmds, req->rlen);
memcpy(req->rbuf, rp->data, rp->len);
/*
- * For dual DSI cases, early return of controller - 0
+ * For dual DSI cases, early return of master ctrl
* is valid. Hence, for those cases the return value
* is zero even though we don't send any commands.
- *
*/
- if ((ctrl->shared_pdata.broadcast_enable &&
- ctrl->ndx == DSI_CTRL_0) || (len != 0))
+ if (mdss_dsi_is_master_ctrl(ctrl) || (len != 0))
ret = 0;
} else {
pr_err("%s: No rx buffer provided\n", __func__);
@@ -1253,14 +1248,14 @@
mdss_bus_bandwidth_ctrl(1);
pr_debug("%s: from_mdp=%d pid=%d\n", __func__, from_mdp, current->pid);
- mdss_dsi_clk_ctrl(ctrl, 1);
+ mdss_dsi_clk_ctrl(ctrl, DSI_ALL_CLKS, 1);
if (req->flags & CMD_REQ_RX)
ret = mdss_dsi_cmdlist_rx(ctrl, req);
else
ret = mdss_dsi_cmdlist_tx(ctrl, req);
- mdss_dsi_clk_ctrl(ctrl, 0);
+ mdss_dsi_clk_ctrl(ctrl, DSI_ALL_CLKS, 0);
mdss_bus_bandwidth_ctrl(0);
need_lock:
@@ -1465,6 +1460,7 @@
u32 isr;
struct mdss_dsi_ctrl_pdata *ctrl =
(struct mdss_dsi_ctrl_pdata *)ptr;
+ struct mdss_dsi_ctrl_pdata *mctrl = NULL;
if (!ctrl->ctrl_base)
pr_err("%s:%d DSI base adr no Initialized",
@@ -1473,16 +1469,19 @@
isr = MIPI_INP(ctrl->ctrl_base + 0x0110);/* DSI_INTR_CTRL */
MIPI_OUTP(ctrl->ctrl_base + 0x0110, isr);
- if (ctrl->shared_pdata.broadcast_enable)
- if ((ctrl->panel_data.panel_info.pdest == DISPLAY_2)
- && (left_ctrl_pdata != NULL)) {
+ if (mdss_dsi_is_slave_ctrl(ctrl)) {
+ mctrl = mdss_dsi_get_master_ctrl();
+ if (mctrl) {
u32 isr0;
- isr0 = MIPI_INP(left_ctrl_pdata->ctrl_base
- + 0x0110);/* DSI_INTR_CTRL */
+ isr0 = MIPI_INP(mctrl->ctrl_base + 0x0110);
if (isr0 & DSI_INTR_CMD_DMA_DONE)
- MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x0110,
+ MIPI_OUTP(mctrl->ctrl_base + 0x0110,
DSI_INTR_CMD_DMA_DONE);
+ } else {
+ pr_warn("%s: Unable to get master control\n",
+ __func__);
}
+ }
pr_debug("%s: ndx=%d isr=%x\n", __func__, ctrl->ndx, isr);
diff --git a/drivers/video/msm/mdss/mdss_dsi_panel.c b/drivers/video/msm/mdss/mdss_dsi_panel.c
index 5415a7e..f450dec 100644
--- a/drivers/video/msm/mdss/mdss_dsi_panel.c
+++ b/drivers/video/msm/mdss/mdss_dsi_panel.c
@@ -317,17 +317,6 @@
return rc;
}
-static struct mdss_dsi_ctrl_pdata *get_rctrl_data(struct mdss_panel_data *pdata)
-{
- if (!pdata || !pdata->next) {
- pr_err("%s: Invalid panel data\n", __func__);
- return NULL;
- }
-
- return container_of(pdata->next, struct mdss_dsi_ctrl_pdata,
- panel_data);
-}
-
static void mdss_dsi_panel_bl_ctrl(struct mdss_panel_data *pdata,
u32 bl_level)
{
@@ -359,15 +348,15 @@
break;
case BL_DCS_CMD:
mdss_dsi_panel_bklt_dcs(ctrl_pdata, bl_level);
- if (ctrl_pdata->shared_pdata.broadcast_enable &&
- ctrl_pdata->ndx == DSI_CTRL_0) {
- struct mdss_dsi_ctrl_pdata *rctrl_pdata = NULL;
- rctrl_pdata = get_rctrl_data(pdata);
- if (!rctrl_pdata) {
- pr_err("%s: Right ctrl data NULL\n", __func__);
+ if (mdss_dsi_is_master_ctrl(ctrl_pdata)) {
+ struct mdss_dsi_ctrl_pdata *sctrl =
+ mdss_dsi_get_slave_ctrl();
+ if (!sctrl) {
+ pr_err("%s: Invalid slave ctrl data\n",
+ __func__);
return;
}
- mdss_dsi_panel_bklt_dcs(rctrl_pdata, bl_level);
+ mdss_dsi_panel_bklt_dcs(sctrl, bl_level);
}
break;
default:
diff --git a/drivers/video/msm/mdss/mdss_dsi_status.c b/drivers/video/msm/mdss/mdss_dsi_status.c
index f0c4f4c..1dca08e 100644
--- a/drivers/video/msm/mdss/mdss_dsi_status.c
+++ b/drivers/video/msm/mdss/mdss_dsi_status.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, 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
@@ -65,6 +65,11 @@
return;
}
+ if (!pdsi_status->mfd) {
+ pr_err("%s: FB data not available\n", __func__);
+ return;
+ }
+
pdata = dev_get_platdata(&pdsi_status->mfd->pdev->dev);
if (!pdata) {
pr_err("%s: Panel data not available\n", __func__);
@@ -86,6 +91,15 @@
mutex_lock(ctl->shared_lock);
mutex_lock(&mdp5_data->ov_lock);
+ if (pdsi_status->mfd->shutdown_pending) {
+ mutex_unlock(&mdp5_data->ov_lock);
+ if (ctl->shared_lock)
+ mutex_unlock(ctl->shared_lock);
+ pr_err("%s: DSI turning off, avoiding BTA status check\n",
+ __func__);
+ return;
+ }
+
/*
* For the command mode panels, we return pan display
* IOCTL on vsync interrupt. So, after vsync interrupt comes
@@ -142,10 +156,13 @@
struct fb_event *evdata = data;
struct dsi_status_data *pdata = container_of(self,
struct dsi_status_data, fb_notifier);
- pdata->mfd = evdata->info->par;
if (event == FB_EVENT_BLANK && evdata) {
int *blank = evdata->data;
+ struct dsi_status_data *pdata = container_of(self,
+ struct dsi_status_data, fb_notifier);
+ pdata->mfd = evdata->info->par;
+
switch (*blank) {
case FB_BLANK_UNBLANK:
schedule_delayed_work(&pdata->check_status,
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index 252a86e..198e242 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -127,7 +127,7 @@
ret = 1;
} else if (notify == NOTIFY_UPDATE_START) {
INIT_COMPLETION(mfd->update.comp);
- ret = wait_for_completion_timeout(
+ ret = wait_for_completion_interruptible_timeout(
&mfd->update.comp, 4 * HZ);
to_user = (unsigned int)mfd->update.value;
if (mfd->update.type == NOTIFY_TYPE_SUSPEND) {
@@ -136,13 +136,13 @@
}
} else if (notify == NOTIFY_UPDATE_STOP) {
INIT_COMPLETION(mfd->no_update.comp);
- ret = wait_for_completion_timeout(
+ ret = wait_for_completion_interruptible_timeout(
&mfd->no_update.comp, 4 * HZ);
to_user = (unsigned int)mfd->no_update.value;
} else {
if (mfd->panel_power_on) {
INIT_COMPLETION(mfd->power_off_comp);
- ret = wait_for_completion_timeout(
+ ret = wait_for_completion_interruptible_timeout(
&mfd->power_off_comp, 1 * HZ);
}
}
@@ -828,6 +828,8 @@
}
break;
}
+ /* Notify listeners */
+ sysfs_notify(&mfd->fbi->dev->kobj, NULL, "show_blank_event");
return ret;
}
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.c b/drivers/video/msm/mdss/mdss_hdmi_tx.c
index cdf9d73..2b409f5 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2014, 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
@@ -1127,6 +1127,17 @@
DEV_DBG("%s: Got HPD interrupt\n", __func__);
if (hdmi_ctrl->hpd_state) {
+ /*
+ * If a down stream device or bridge chip is attached to hdmi
+ * Tx core output, it is likely that it might be powering the
+ * hpd module ON/OFF on cable connect/disconnect as it would
+ * have its own mechanism of detecting cable. Flush power off
+ * work is needed in case there is any race condidtion between
+ * power off and on during fast cable plug in/out.
+ */
+ if (hdmi_ctrl->ds_registered)
+ flush_work(&hdmi_ctrl->power_off_work);
+
if (hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_DDC_PM, true)) {
DEV_ERR("%s: Failed to enable ddc power\n", __func__);
return;
@@ -2351,6 +2362,8 @@
ops->set_mhl_max_pclk = hdmi_tx_set_mhl_max_pclk;
ops->set_upstream_hpd = hdmi_tx_set_mhl_hpd;
+ hdmi_ctrl->ds_registered = true;
+
return 0;
}
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.h b/drivers/video/msm/mdss/mdss_hdmi_tx.h
index 8233ba8..54d80dc 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.h
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.h
@@ -83,6 +83,7 @@
struct work_struct cable_notify_work;
bool hdcp_feature_on;
+ bool ds_registered;
u32 present_hdcp;
u8 spd_vendor_name[9];
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index cfa594c..8a215bc 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -296,6 +296,7 @@
pr_debug("Disable HW=%d irq ena=%d mask=%x\n", hw->hw_ndx,
mdss_res->irq_ena, mdss_res->irq_mask);
+ spin_lock(&mdss_lock);
if (!(mdss_res->irq_mask & ndx_bit)) {
pr_warn("MDSS HW ndx=%d is NOT set, mask=%x, hist mask=%x\n",
hw->hw_ndx, mdss_res->mdp_irq_mask,
@@ -307,6 +308,7 @@
disable_irq_nosync(mdss_res->irq);
}
}
+ spin_unlock(&mdss_lock);
}
EXPORT_SYMBOL(mdss_disable_irq_nosync);
@@ -505,7 +507,16 @@
spin_unlock_irqrestore(&mdp_lock, irq_flags);
}
-/* called from interrupt context */
+/**
+ * mdss_mdp_irq_disable_nosync() - disable mdp irq
+ * @intr_type: mdp interface type
+ * @intf_num: mdp interface num
+ *
+ * This fucntion is called from interrupt context
+ * mdp_lock is already held at up stream (mdss_irq_handler)
+ * therefore spin_lock(&mdp_lock) is not allowed here
+ *
+*/
void mdss_mdp_irq_disable_nosync(u32 intr_type, u32 intf_num)
{
u32 irq;
@@ -1001,8 +1012,9 @@
writel_relaxed(1, offset + 16);
}
- mdata->nmax_concurrent_ad_hw = (mdata->mdp_rev <= MDSS_MDP_HW_REV_102) ?
- 1 : 2;
+ mdata->nmax_concurrent_ad_hw =
+ (mdata->mdp_rev < MDSS_MDP_HW_REV_103) ? 1 : 2;
+
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
pr_debug("MDP hw init done\n");
@@ -1578,6 +1590,61 @@
return 0;
}
+static int mdss_mdp_parse_dt_pipe_clk_ctrl(struct platform_device *pdev,
+ char *prop_name, struct mdss_mdp_pipe *pipe_list, u32 npipes)
+{
+ int rc = 0;
+ size_t len;
+ const u32 *arr;
+
+ arr = of_get_property(pdev->dev.of_node, prop_name, &len);
+ if (arr) {
+ int i, j;
+
+ len /= sizeof(u32);
+ for (i = 0, j = 0; i < len; j++) {
+ struct mdss_mdp_pipe *pipe = NULL;
+
+ if (j >= npipes) {
+ pr_err("invalid clk ctrl enries for prop: %s\n",
+ prop_name);
+ return -EINVAL;
+ }
+
+ pipe = &pipe_list[j];
+
+ pipe->clk_ctrl.reg_off = be32_to_cpu(arr[i++]);
+ pipe->clk_ctrl.bit_off = be32_to_cpu(arr[i++]);
+
+ /* status register is next in line to ctrl register */
+ pipe->clk_status.reg_off = pipe->clk_ctrl.reg_off + 4;
+ pipe->clk_status.bit_off = be32_to_cpu(arr[i++]);
+
+ pr_debug("%s[%d]: ctrl: reg_off: 0x%x bit_off: %d\n",
+ prop_name, j, pipe->clk_ctrl.reg_off,
+ pipe->clk_ctrl.bit_off);
+ pr_debug("%s[%d]: status: reg_off: 0x%x bit_off: %d\n",
+ prop_name, j, pipe->clk_status.reg_off,
+ pipe->clk_status.bit_off);
+ }
+ if (j != npipes) {
+ pr_err("%s: %d entries found. required %d\n",
+ prop_name, j, npipes);
+ for (i = 0; i < npipes; i++) {
+ memset(&pipe_list[i].clk_ctrl, 0,
+ sizeof(pipe_list[i].clk_ctrl));
+ memset(&pipe_list[i].clk_status, 0,
+ sizeof(pipe_list[i].clk_status));
+ }
+ rc = -EINVAL;
+ }
+ } else {
+ pr_err("error mandatory property '%s' not found\n", prop_name);
+ rc = -EINVAL;
+ }
+
+ return rc;
+}
static int mdss_mdp_parse_dt_pipe(struct platform_device *pdev)
{
@@ -1761,6 +1828,25 @@
setup_cnt += mdata->nrgb_pipes - DEFAULT_TOTAL_RGB_PIPES;
}
+ rc = mdss_mdp_parse_dt_pipe_clk_ctrl(pdev,
+ "qcom,mdss-pipe-vig-clk-ctrl-offsets", mdata->vig_pipes,
+ mdata->nvig_pipes);
+ if (rc)
+ goto parse_fail;
+
+ rc = mdss_mdp_parse_dt_pipe_clk_ctrl(pdev,
+ "qcom,mdss-pipe-rgb-clk-ctrl-offsets", mdata->rgb_pipes,
+ mdata->nrgb_pipes);
+ if (rc)
+ goto parse_fail;
+
+ rc = mdss_mdp_parse_dt_pipe_clk_ctrl(pdev,
+ "qcom,mdss-pipe-dma-clk-ctrl-offsets", mdata->dma_pipes,
+ mdata->ndma_pipes);
+ if (rc)
+ goto parse_fail;
+
+
goto parse_done;
parse_fail:
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index 9a469a4..adee7b50 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -349,6 +349,11 @@
DECLARE_BITMAP(fixed, MAX_DRV_SUP_MMB_BLKS);
};
+struct mdss_mdp_shared_reg_ctrl {
+ u32 reg_off;
+ u32 bit_off;
+};
+
struct mdss_mdp_pipe {
u32 num;
u32 type;
@@ -356,6 +361,9 @@
char __iomem *base;
u32 ftch_id;
u32 xin_id;
+ struct mdss_mdp_shared_reg_ctrl clk_ctrl;
+ struct mdss_mdp_shared_reg_ctrl clk_status;
+
atomic_t ref_cnt;
u32 play_cnt;
int pid;
@@ -452,6 +460,16 @@
};
#define is_vig_pipe(_pipe_id_) ((_pipe_id_) <= MDSS_MDP_SSPP_VIG2)
+
+static inline struct mdss_mdp_ctl *mdss_mdp_get_split_ctl(
+ struct mdss_mdp_ctl *ctl)
+{
+ if (ctl && ctl->mixer_right && (ctl->mixer_right->ctl != ctl))
+ return ctl->mixer_right->ctl;
+
+ return NULL;
+}
+
static inline void mdss_mdp_ctl_write(struct mdss_mdp_ctl *ctl,
u32 reg, u32 val)
{
@@ -533,7 +551,8 @@
struct mdss_mdp_pipe **left_plist, int left_cnt,
struct mdss_mdp_pipe **right_plist, int right_cnt);
int mdss_mdp_perf_calc_pipe(struct mdss_mdp_pipe *pipe,
- struct mdss_mdp_perf_params *perf, struct mdss_mdp_img_rect *roi);
+ struct mdss_mdp_perf_params *perf, struct mdss_mdp_img_rect *roi,
+ bool apply_fudge);
int mdss_mdp_ctl_notify(struct mdss_mdp_ctl *ctl, int event);
void mdss_mdp_ctl_notifier_register(struct mdss_mdp_ctl *ctl,
struct notifier_block *notifier);
@@ -629,10 +648,10 @@
int mdss_mdp_ctl_addr_setup(struct mdss_data_type *mdata, u32 *ctl_offsets,
u32 *wb_offsets, u32 len);
+int mdss_mdp_pipe_fetch_halt(struct mdss_mdp_pipe *pipe);
int mdss_mdp_pipe_destroy(struct mdss_mdp_pipe *pipe);
int mdss_mdp_pipe_queue_data(struct mdss_mdp_pipe *pipe,
struct mdss_mdp_data *src_data);
-int mdss_mdp_pipe_fetch_halt(struct mdss_mdp_pipe *pipe);
int mdss_mdp_data_check(struct mdss_mdp_data *data,
struct mdss_mdp_plane_sizes *ps);
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index fa64448..2c1beab 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -303,6 +303,7 @@
* @pipe: Source pipe struct containing updated pipe params
* @perf: Structure containing values that should be updated for
* performance tuning
+ * @apply_fudge: Boolean to determine if mdp clock fudge is applicable
*
* Function calculates the minimum required performance calculations in order
* to avoid MDP underflow. The calculations are based on the way MDP
@@ -310,7 +311,8 @@
* (MDP clock requirement) based on frame size and scaling requirements.
*/
int mdss_mdp_perf_calc_pipe(struct mdss_mdp_pipe *pipe,
- struct mdss_mdp_perf_params *perf, struct mdss_mdp_img_rect *roi)
+ struct mdss_mdp_perf_params *perf, struct mdss_mdp_img_rect *roi,
+ bool apply_fudge)
{
struct mdss_mdp_mixer *mixer;
int fps = DEFAULT_FRAME_RATE;
@@ -384,7 +386,10 @@
perf->bw_overlap = (quota / dst.h) * v_total;
}
- perf->mdp_clk_rate = mdss_mdp_clk_fudge_factor(mixer, rate);
+ if (apply_fudge)
+ perf->mdp_clk_rate = mdss_mdp_clk_fudge_factor(mixer, rate);
+ else
+ perf->mdp_clk_rate = rate;
prefill_params.smp_bytes = mdss_mdp_smp_get_size(pipe);
prefill_params.xres = xres;
@@ -440,6 +445,8 @@
u64 bw_overlap[MDSS_MDP_MAX_STAGE] = { 0 };
u32 v_region[MDSS_MDP_MAX_STAGE * 2] = { 0 };
u32 prefill_bytes = 0;
+ struct mdss_data_type *mdata = mdss_mdp_get_mdata();
+ bool apply_fudge = true;
BUG_ON(num_pipes > MDSS_MDP_MAX_STAGE);
@@ -469,13 +476,36 @@
memset(bw_overlap, 0, sizeof(u64) * MDSS_MDP_MAX_STAGE);
memset(v_region, 0, sizeof(u32) * MDSS_MDP_MAX_STAGE * 2);
+ /*
+ * Apply this logic only for 8x26 to reduce clock rate
+ * for single video playback use case
+ */
+ if (IS_MDSS_MAJOR_MINOR_SAME(mdata->mdp_rev, MDSS_MDP_HW_REV_101)
+ && mixer->type == MDSS_MDP_MIXER_TYPE_INTF) {
+ u32 npipes = 0;
+ for (i = 0; i < MDSS_MDP_MAX_STAGE; i++) {
+ pipe = mixer->stage_pipe[i];
+ if (pipe) {
+ if (npipes) {
+ apply_fudge = true;
+ break;
+ }
+ npipes++;
+ apply_fudge = !(pipe->src_fmt->is_yuv)
+ || !(pipe->flags
+ & MDP_SOURCE_ROTATED_90);
+ }
+ }
+ }
+
for (i = 0; i < num_pipes; i++) {
struct mdss_mdp_perf_params tmp;
pipe = pipe_list[i];
if (pipe == NULL)
continue;
- if (mdss_mdp_perf_calc_pipe(pipe, &tmp, &mixer->roi))
+ if (mdss_mdp_perf_calc_pipe(pipe, &tmp, &mixer->roi,
+ apply_fudge))
continue;
prefill_bytes += tmp.prefill_bytes;
bw_overlap[i] = tmp.bw_overlap;
@@ -622,9 +652,6 @@
}
perf->bw_ctl = max(perf->bw_prefill, perf->bw_overlap);
-
- if (ctl->is_video_mode)
- perf->bw_ctl = IB_FUDGE_FACTOR(perf->bw_ctl);
}
int mdss_mdp_perf_bw_check(struct mdss_mdp_ctl *ctl,
@@ -667,6 +694,9 @@
left_plist, (left_plist ? MDSS_MDP_MAX_STAGE : 0),
right_plist, (right_plist ? MDSS_MDP_MAX_STAGE : 0));
+ if (ctl->is_video_mode)
+ perf->bw_ctl = IB_FUDGE_FACTOR(perf->bw_ctl);
+
pr_debug("ctl=%d clk_rate=%u\n", ctl->num, perf->mdp_clk_rate);
pr_debug("bw_overlap=%llu bw_prefill=%llu prefill_byptes=%d\n",
perf->bw_overlap, perf->bw_prefill, perf->prefill_bytes);
@@ -1133,15 +1163,6 @@
return 0;
}
-static inline struct mdss_mdp_ctl *mdss_mdp_get_split_ctl(
- struct mdss_mdp_ctl *ctl)
-{
- if (ctl && ctl->mixer_right && (ctl->mixer_right->ctl != ctl))
- return ctl->mixer_right->ctl;
-
- return NULL;
-}
-
int mdss_mdp_ctl_splash_finish(struct mdss_mdp_ctl *ctl, bool handoff)
{
struct mdss_mdp_ctl *sctl = mdss_mdp_get_split_ctl(ctl);
diff --git a/drivers/video/msm/mdss/mdss_mdp_hwio.h b/drivers/video/msm/mdss/mdss_mdp_hwio.h
index bff56d2..4b9ea20 100644
--- a/drivers/video/msm/mdss/mdss_mdp_hwio.h
+++ b/drivers/video/msm/mdss/mdss_mdp_hwio.h
@@ -21,10 +21,6 @@
#define ENHIST_LUT_ENTRIES 256
#define HIST_V_SIZE 256
-#define MDSS_MDP_HW_REV_100 0x10000000
-#define MDSS_MDP_HW_REV_102 0x10020000
-#define MDSS_MDP_HW_REV_103 0x10030000
-
#define MDSS_MDP_FETCH_CONFIG_RESET_VALUE 0x00000087
#define MDSS_REG_HW_VERSION 0x0
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
index 78ecf16..96da27e 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
@@ -200,13 +200,17 @@
{
unsigned long flags;
struct mdss_data_type *mdata = mdss_mdp_get_mdata();
+
+ if (!ctx->panel_on)
+ return;
+
mutex_lock(&ctx->clk_mtx);
if (!ctx->clk_enabled) {
ctx->clk_enabled = 1;
if (cancel_delayed_work_sync(&ctx->ulps_work))
pr_debug("deleted pending ulps work\n");
- mdss_mdp_ctl_intf_event
- (ctx->ctl, MDSS_EVENT_PANEL_CLK_CTRL, (void *)1);
+
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
if (ctx->ulps) {
if (mdss_mdp_cmd_tearcheck_setup(ctx->ctl, 1))
@@ -216,7 +220,9 @@
ctx->ulps = false;
}
- mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+ mdss_mdp_ctl_intf_event
+ (ctx->ctl, MDSS_EVENT_PANEL_CLK_CTRL, (void *)1);
+
mdss_mdp_hist_intr_setup(&mdata->hist_intr, MDSS_IRQ_RESUME);
}
spin_lock_irqsave(&ctx->clk_lock, flags);
@@ -277,6 +283,10 @@
if (!ctx->vsync_enabled) {
if (ctx->rdptr_enabled)
ctx->rdptr_enabled--;
+
+ /* keep clk on during kickoff */
+ if (ctx->rdptr_enabled == 0 && ctx->koff_cnt)
+ ctx->rdptr_enabled++;
}
if (ctx->rdptr_enabled == 0) {
@@ -561,22 +571,22 @@
WARN(rc, "intf %d panel on error (%d)\n", ctl->intf_num, rc);
}
- mdss_mdp_cmd_set_partial_roi(ctl);
+ spin_lock_irqsave(&ctx->clk_lock, flags);
+ ctx->koff_cnt++;
+ spin_unlock_irqrestore(&ctx->clk_lock, flags);
mdss_mdp_cmd_clk_on(ctx);
+ mdss_mdp_cmd_set_partial_roi(ctl);
+
/*
* tx dcs command if had any
*/
mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_DSI_CMDLIST_KOFF,
(void *)&ctx->recovery);
-
INIT_COMPLETION(ctx->pp_comp);
mdss_mdp_irq_enable(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num);
mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_START, 1);
- spin_lock_irqsave(&ctx->clk_lock, flags);
- ctx->koff_cnt++;
- spin_unlock_irqrestore(&ctx->clk_lock, flags);
mb();
return 0;
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_video.c b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
index 55a4a4d..f8bdc04 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_video.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
@@ -298,6 +298,7 @@
{
struct mdss_mdp_video_ctx *ctx;
struct mdss_mdp_vsync_handler *tmp, *handle;
+ struct mdss_mdp_ctl *sctl;
int rc;
u32 frame_rate = 0;
@@ -335,6 +336,10 @@
mdss_mdp_irq_disable(MDSS_MDP_IRQ_INTF_UNDER_RUN,
ctl->intf_num);
+ sctl = mdss_mdp_get_split_ctl(ctl);
+ if (sctl)
+ mdss_mdp_irq_disable(MDSS_MDP_IRQ_INTF_UNDER_RUN,
+ sctl->intf_num);
}
list_for_each_entry_safe(handle, tmp, &ctx->vsync_handlers, list)
@@ -641,6 +646,7 @@
static int mdss_mdp_video_display(struct mdss_mdp_ctl *ctl, void *arg)
{
struct mdss_mdp_video_ctx *ctx;
+ struct mdss_mdp_ctl *sctl;
int rc;
pr_debug("kickoff ctl=%d\n", ctl->num);
@@ -674,6 +680,11 @@
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
mdss_mdp_irq_enable(MDSS_MDP_IRQ_INTF_UNDER_RUN, ctl->intf_num);
+ sctl = mdss_mdp_get_split_ctl(ctl);
+ if (sctl)
+ mdss_mdp_irq_enable(MDSS_MDP_IRQ_INTF_UNDER_RUN,
+ sctl->intf_num);
+
mdp_video_write(ctx, MDSS_MDP_REG_INTF_TIMING_ENGINE_EN, 1);
wmb();
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index 7420f95..7628380 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -268,7 +268,7 @@
int rc;
for (;;) {
- rc = mdss_mdp_perf_calc_pipe(pipe, &perf, NULL);
+ rc = mdss_mdp_perf_calc_pipe(pipe, &perf, NULL, true);
if (!rc && (perf.mdp_clk_rate <= mdata->max_mdp_clk_rate))
break;
@@ -321,10 +321,6 @@
rc, src, pipe->dst.h);
return rc;
}
- pipe->scale.init_phase_x[0] = (pipe->scale.phase_step_x[0] -
- (1 << PHASE_STEP_SHIFT)) / 2;
- pipe->scale.init_phase_y[0] = (pipe->scale.phase_step_y[0] -
- (1 << PHASE_STEP_SHIFT)) / 2;
return rc;
}
@@ -770,17 +766,16 @@
LIST_HEAD(destroy_pipes);
mutex_lock(&mfd->lock);
- __mdss_mdp_overlay_free_list_purge(mfd);
-
list_for_each_entry_safe(pipe, tmp, &mdp5_data->pipes_cleanup,
cleanup_list) {
list_move(&pipe->cleanup_list, &destroy_pipes);
+
+ /* make sure pipe fetch has been halted before freeing buffer */
mdss_mdp_pipe_fetch_halt(pipe);
- mdss_mdp_overlay_free_buf(&pipe->back_buf);
- __mdss_mdp_overlay_free_list_add(mfd, &pipe->front_buf);
- pipe->mfd = NULL;
}
+ __mdss_mdp_overlay_free_list_purge(mfd);
+
list_for_each_entry(pipe, &mdp5_data->pipes_used, used_list) {
if (pipe->back_buf.num_planes) {
/* make back buffer active */
@@ -788,9 +783,20 @@
swap(pipe->back_buf, pipe->front_buf);
}
}
- mutex_unlock(&mfd->lock);
- list_for_each_entry_safe(pipe, tmp, &destroy_pipes, cleanup_list)
+
+ list_for_each_entry_safe(pipe, tmp, &destroy_pipes, cleanup_list) {
+ /*
+ * in case of secure UI, the buffer needs to be released as
+ * soon as session is closed.
+ */
+ if (pipe->flags & MDP_SECURE_DISPLAY_OVERLAY_SESSION)
+ mdss_mdp_overlay_free_buf(&pipe->front_buf);
+ else
+ __mdss_mdp_overlay_free_list_add(mfd, &pipe->front_buf);
+ mdss_mdp_overlay_free_buf(&pipe->back_buf);
mdss_mdp_pipe_destroy(pipe);
+ }
+ mutex_unlock(&mfd->lock);
}
static void __mdss_mdp_handoff_cleanup_pipes(struct msm_fb_data_type *mfd,
@@ -974,6 +980,11 @@
int ret = 0;
int sd_in_pipe = 0;
+ if (!ctl) {
+ pr_warn("kickoff on fb=%d without a ctl attched\n", mfd->index);
+ return ret;
+ }
+
if (ctl->shared_lock)
mutex_lock(ctl->shared_lock);
@@ -1774,7 +1785,7 @@
vsync_ticks = ktime_to_ns(mdp5_data->vsync_time);
pr_debug("fb%d vsync=%llu", mfd->index, vsync_ticks);
- ret = scnprintf(buf, PAGE_SIZE, "VSYNC=%llu", vsync_ticks);
+ ret = scnprintf(buf, PAGE_SIZE, "VSYNC=%llu\n", vsync_ticks);
return ret;
}
@@ -2693,6 +2704,56 @@
return 0;
}
+static int __mdss_mdp_ctl_handoff(struct mdss_mdp_ctl *ctl,
+ struct mdss_data_type *mdata)
+{
+ int rc = 0;
+ int i, j;
+ u32 mixercfg;
+ struct mdss_mdp_pipe *pipe = NULL;
+
+ if (!ctl || !mdata)
+ return -EINVAL;
+
+ for (i = 0; i < mdata->nmixers_intf; i++) {
+ mixercfg = mdss_mdp_ctl_read(ctl, MDSS_MDP_REG_CTL_LAYER(i));
+ pr_debug("for lm%d mixercfg = 0x%09x\n", i, mixercfg);
+
+ j = MDSS_MDP_SSPP_VIG0;
+ for (; j < MDSS_MDP_MAX_SSPP && mixercfg; j++) {
+ u32 cfg = j * 3;
+ if ((j == MDSS_MDP_SSPP_VIG3) ||
+ (j == MDSS_MDP_SSPP_RGB3)) {
+ /* Add 2 to account for Cursor & Border bits */
+ cfg += 2;
+ }
+ if (mixercfg & (0x7 << cfg)) {
+ pr_debug("Pipe %d staged\n", j);
+ pipe = mdss_mdp_pipe_search(mdata, BIT(j));
+ if (!pipe) {
+ pr_warn("Invalid pipe %d staged\n", j);
+ continue;
+ }
+
+ rc = mdss_mdp_pipe_handoff(pipe);
+ if (rc) {
+ pr_err("Failed to handoff pipe%d\n",
+ pipe->num);
+ goto exit;
+ }
+
+ rc = mdss_mdp_mixer_handoff(ctl, i, pipe);
+ if (rc) {
+ pr_err("failed to handoff mix%d\n", i);
+ goto exit;
+ }
+ }
+ }
+ }
+exit:
+ return rc;
+}
+
/**
* mdss_mdp_overlay_handoff() - Read MDP registers to handoff an active ctl path
* @mfd: Msm frame buffer structure associated with the fb device.
@@ -2708,10 +2769,8 @@
int rc = 0;
struct mdss_data_type *mdata = mfd_to_mdata(mfd);
struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
- int i, j;
- u32 reg;
- struct mdss_mdp_pipe *pipe = NULL;
struct mdss_mdp_ctl *ctl = NULL;
+ struct mdss_mdp_ctl *sctl = NULL;
if (!mdp5_data->ctl) {
ctl = __mdss_mdp_overlay_ctl_init(mfd);
@@ -2735,38 +2794,23 @@
ctl->clk_rate = mdss_mdp_get_clk_rate(MDSS_CLK_MDP_SRC);
pr_debug("Set the ctl clock rate to %d Hz\n", ctl->clk_rate);
- for (i = 0; i < mdata->nmixers_intf; i++) {
- reg = mdss_mdp_ctl_read(ctl, MDSS_MDP_REG_CTL_LAYER(i));
- pr_debug("for lm%d reg = 0x%09x\n", i, reg);
- for (j = MDSS_MDP_SSPP_VIG0; j < MDSS_MDP_MAX_SSPP; j++) {
- u32 cfg = j * 3;
- if ((j == MDSS_MDP_SSPP_VIG3) ||
- (j == MDSS_MDP_SSPP_RGB3)) {
- /* Add 2 to account for Cursor & Border bits */
- cfg += 2;
- }
- if (reg & (0x7 << cfg)) {
- pr_debug("Pipe %d staged\n", j);
- pipe = mdss_mdp_pipe_search(mdata, BIT(j));
- if (!pipe) {
- pr_warn("Invalid pipe %d staged\n", j);
- continue;
- }
+ rc = __mdss_mdp_ctl_handoff(ctl, mdata);
+ if (rc) {
+ pr_err("primary ctl handoff failed. rc=%d\n", rc);
+ goto error;
+ }
- rc = mdss_mdp_pipe_handoff(pipe);
- if (rc) {
- pr_err("Failed to handoff pipe num %d\n"
- , pipe->num);
- goto error;
- }
-
- rc = mdss_mdp_mixer_handoff(ctl, i, pipe);
- if (rc) {
- pr_err("failed to handoff mixer num %d\n"
- , i);
- goto error;
- }
- }
+ if (mfd->split_display) {
+ sctl = mdss_mdp_get_split_ctl(ctl);
+ if (!sctl) {
+ pr_err("cannot get secondary ctl. fail the handoff\n");
+ rc = -EPERM;
+ goto error;
+ }
+ rc = __mdss_mdp_ctl_handoff(sctl, mdata);
+ if (rc) {
+ pr_err("secondary ctl handoff failed. rc=%d\n", rc);
+ goto error;
}
}
diff --git a/drivers/video/msm/mdss/mdss_mdp_pipe.c b/drivers/video/msm/mdss/mdss_mdp_pipe.c
index b6f9b17..50bee17 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pipe.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pipe.c
@@ -28,6 +28,12 @@
#define PIPE_HALT_TIMEOUT_US 0x4000
+/* following offsets are relative to ctrl register bit offset */
+#define CLK_FORCE_ON_OFFSET 0x0
+#define CLK_FORCE_OFF_OFFSET 0x1
+/* following offsets are relative to status register bit offset */
+#define CLK_STATUS_OFFSET 0x0
+
static DEFINE_MUTEX(mdss_mdp_sspp_lock);
static DEFINE_MUTEX(mdss_mdp_smp_lock);
@@ -210,7 +216,7 @@
struct mdss_mdp_plane_sizes ps;
int i;
int rc = 0, rot_mode = 0, wb_mixer = 0;
- u32 nlines, format;
+ u32 nlines, format, seg_w;
u16 width;
width = pipe->src.w >> pipe->horz_deci;
@@ -222,19 +228,17 @@
return rc;
/*
* Override fetch strides with SMP buffer size for both the
- * planes
+ * planes. BWC line buffer needs to be divided into 16
+ * segments and every segment is aligned to format
+ * specific RAU size
*/
+ seg_w = DIV_ROUND_UP(pipe->src.w, 16);
if (pipe->src_fmt->fetch_planes == MDSS_MDP_PLANE_INTERLEAVED) {
- /*
- * BWC line buffer needs to be divided into 16
- * segments and every segment is aligned to format
- * specific RAU size
- */
- ps.ystride[0] = ALIGN(pipe->src.w / 16 , 32) * 16 *
- ps.rau_h[0] * pipe->src_fmt->bpp;
+ ps.ystride[0] = ALIGN(seg_w, 32) * 16 * ps.rau_h[0] *
+ pipe->src_fmt->bpp;
ps.ystride[1] = 0;
} else {
- u32 bwc_width = ALIGN(pipe->src.w / 16, 64) * 16;
+ u32 bwc_width = ALIGN(seg_w, 64) * 16;
ps.ystride[0] = bwc_width * ps.rau_h[0];
ps.ystride[1] = bwc_width * ps.rau_h[1];
/*
@@ -545,7 +549,7 @@
}
if (pipe && mdss_mdp_pipe_fetch_halt(pipe)) {
- pr_err("%d failed because vbif client is in bad state\n",
+ pr_err("%d failed because pipe is in bad state\n",
pipe->num);
atomic_dec(&pipe->ref_cnt);
return NULL;
@@ -677,6 +681,7 @@
if (pipe->play_cnt) {
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+ mdss_mdp_pipe_fetch_halt(pipe);
mdss_mdp_pipe_sspp_term(pipe);
mdss_mdp_smp_free(pipe);
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
@@ -692,6 +697,53 @@
return 0;
}
+static int mdss_mdp_is_pipe_idle(struct mdss_mdp_pipe *pipe,
+ bool ignore_force_on)
+{
+ u32 reg_val;
+ u32 vbif_idle_mask, forced_on_mask, clk_status_idle_mask;
+ bool is_idle = false, is_forced_on;
+ struct mdss_data_type *mdata = mdss_mdp_get_mdata();
+
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+
+ forced_on_mask = BIT(pipe->clk_ctrl.bit_off + CLK_FORCE_ON_OFFSET);
+ reg_val = readl_relaxed(mdata->mdp_base + pipe->clk_ctrl.reg_off);
+ is_forced_on = (reg_val & forced_on_mask) ? true : false;
+
+ pr_debug("pipe#:%d clk_ctrl: 0x%x forced_on_mask: 0x%x\n", pipe->num,
+ reg_val, forced_on_mask);
+ /* if forced on then no need to check status */
+ if (!is_forced_on) {
+ clk_status_idle_mask =
+ BIT(pipe->clk_status.bit_off + CLK_STATUS_OFFSET);
+ reg_val = readl_relaxed(mdata->mdp_base +
+ pipe->clk_status.reg_off);
+
+ if (reg_val & clk_status_idle_mask)
+ is_idle = false;
+
+ pr_debug("pipe#:%d clk_status:0x%x clk_status_idle_mask:0x%x\n",
+ pipe->num, reg_val, clk_status_idle_mask);
+ }
+
+ if (!ignore_force_on && (is_forced_on || !is_idle))
+ goto exit;
+
+ vbif_idle_mask = BIT(pipe->xin_id + 16);
+ reg_val = readl_relaxed(mdata->vbif_base + MMSS_VBIF_XIN_HALT_CTRL1);
+
+ if (reg_val & vbif_idle_mask)
+ is_idle = true;
+
+ pr_debug("pipe#:%d XIN_HALT_CTRL1: 0x%x\n", pipe->num, reg_val);
+
+exit:
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+
+ return is_idle;
+}
+
/**
* mdss_mdp_pipe_fetch_halt() - Halt VBIF client corresponding to specified pipe
* @pipe: pointer to the pipe data structure which needs to be halted.
@@ -711,18 +763,15 @@
u32 reg_val, idle_mask, status;
struct mdss_data_type *mdata = mdss_mdp_get_mdata();
- mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
-
- idle_mask = BIT(pipe->xin_id + 16);
- reg_val = readl_relaxed(mdata->vbif_base + MMSS_VBIF_XIN_HALT_CTRL1);
-
- is_idle = (reg_val & idle_mask) ? true : false;
+ is_idle = mdss_mdp_is_pipe_idle(pipe, true);
if (!is_idle) {
- pr_debug("%pS: pipe%d is not idle. xin_id=%d halt_ctrl1=0x%x\n",
- __builtin_return_address(0), pipe->num, pipe->xin_id,
- reg_val);
+ pr_err("%pS: pipe%d is not idle. xin_id=%d\n",
+ __builtin_return_address(0), pipe->num, pipe->xin_id);
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
mutex_lock(&mdata->reg_lock);
+ idle_mask = BIT(pipe->xin_id + 16);
+
reg_val = readl_relaxed(mdata->vbif_base +
MMSS_VBIF_XIN_HALT_CTRL0);
writel_relaxed(reg_val | BIT(pipe->xin_id),
@@ -743,9 +792,10 @@
MMSS_VBIF_XIN_HALT_CTRL0);
writel_relaxed(reg_val & ~BIT(pipe->xin_id),
mdata->vbif_base + MMSS_VBIF_XIN_HALT_CTRL0);
+
mutex_unlock(&mdata->reg_lock);
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
}
- mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
return rc;
}
@@ -1065,7 +1115,7 @@
static int mdss_mdp_pipe_solidfill_setup(struct mdss_mdp_pipe *pipe)
{
int ret;
- u32 secure, format;
+ u32 secure, format, unpack;
pr_debug("solid fill setup on pnum=%d\n", pipe->num);
@@ -1078,9 +1128,13 @@
format = MDSS_MDP_FMT_SOLID_FILL;
secure = (pipe->flags & MDP_SECURE_OVERLAY_SESSION ? 0xF : 0x0);
+ /* support ARGB color format only */
+ unpack = (C3_ALPHA << 24) | (C2_R_Cr << 16) |
+ (C1_B_Cb << 8) | (C0_G_Y << 0);
mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_FORMAT, format);
mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_CONSTANT_COLOR,
pipe->bg_color);
+ mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_UNPACK_PATTERN, unpack);
mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_ADDR_SW_STATUS, secure);
return 0;
diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c
index 54ec6f8..37b71c7 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pp.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2014, 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
@@ -1306,19 +1306,19 @@
goto error;
}
+ mutex_lock(&hist_info->hist_mutex);
+ spin_lock_irqsave(&hist_info->hist_lock, flag);
if (hist_info->col_en) {
*op |= op_flags;
- mutex_lock(&hist_info->hist_mutex);
- spin_lock_irqsave(&hist_info->hist_lock, flag);
col_state = hist_info->col_state;
if (col_state == HIST_IDLE) {
/* Kick off collection */
writel_relaxed(1, base + kick_base);
hist_info->col_state = HIST_START;
}
- spin_unlock_irqrestore(&hist_info->hist_lock, flag);
- mutex_unlock(&hist_info->hist_mutex);
}
+ spin_unlock_irqrestore(&hist_info->hist_lock, flag);
+ mutex_unlock(&hist_info->hist_mutex);
ret = 0;
error:
return ret;
@@ -1750,6 +1750,8 @@
&mdss_pp_res->dspp_hist[i].hist_mutex);
spin_lock_init(
&mdss_pp_res->dspp_hist[i].hist_lock);
+ init_completion(
+ &mdss_pp_res->dspp_hist[i].comp);
}
}
}
@@ -1758,6 +1760,7 @@
for (i = 0; i < mdata->nvig_pipes; i++) {
mutex_init(&vig[i].pp_res.hist.hist_mutex);
spin_lock_init(&vig[i].pp_res.hist.hist_lock);
+ init_completion(&vig[i].pp_res.hist.comp);
}
if (!mdata->pp_bus_hdl) {
pp_bus_pdata = &mdp_pp_bus_scale_table;
@@ -2887,22 +2890,23 @@
mutex_lock(&hist_info->hist_mutex);
/* check if it is idle */
+ spin_lock_irqsave(&hist_info->hist_lock, flag);
if (hist_info->col_en) {
+ spin_unlock_irqrestore(&hist_info->hist_lock, flag);
pr_info("%s Hist collection has already been enabled %d",
__func__, (u32) ctl_base);
ret = -EINVAL;
goto exit;
}
- hist_info->frame_cnt = req->frame_cnt;
- init_completion(&hist_info->comp);
- hist_info->hist_cnt_read = 0;
- hist_info->hist_cnt_sent = 0;
- hist_info->hist_cnt_time = 0;
- spin_lock_irqsave(&hist_info->hist_lock, flag);
hist_info->read_request = 0;
hist_info->col_state = HIST_RESET;
hist_info->col_en = true;
spin_unlock_irqrestore(&hist_info->hist_lock, flag);
+ hist_info->frame_cnt = req->frame_cnt;
+ INIT_COMPLETION(hist_info->comp);
+ hist_info->hist_cnt_read = 0;
+ hist_info->hist_cnt_sent = 0;
+ hist_info->hist_cnt_time = 0;
mdss_mdp_hist_intr_req(&mdata->hist_intr, 3 << shift_bit, true);
writel_relaxed(req->frame_cnt, ctl_base + 8);
/* Kick out reset start */
@@ -3013,17 +3017,18 @@
struct mdss_data_type *mdata = mdss_mdp_get_mdata();
mutex_lock(&hist_info->hist_mutex);
+ spin_lock_irqsave(&hist_info->hist_lock, flag);
if (hist_info->col_en == false) {
+ spin_unlock_irqrestore(&hist_info->hist_lock, flag);
pr_debug("Histogram already disabled (%d)", (u32) ctl_base);
ret = -EINVAL;
goto exit;
}
- complete_all(&hist_info->comp);
- spin_lock_irqsave(&hist_info->hist_lock, flag);
hist_info->col_en = false;
hist_info->col_state = HIST_UNKNOWN;
spin_unlock_irqrestore(&hist_info->hist_lock, flag);
mdss_mdp_hist_intr_req(&mdata->hist_intr, done_bit, false);
+ complete_all(&hist_info->comp);
writel_relaxed(BIT(1), ctl_base);/* cancel */
ret = 0;
exit:
@@ -3264,12 +3269,13 @@
struct mdss_mdp_pipe *pipe;
mutex_lock(&hist_info->hist_mutex);
+ spin_lock_irqsave(&hist_info->hist_lock, flag);
if ((hist_info->col_en == 0) ||
(hist_info->col_state == HIST_UNKNOWN)) {
+ spin_unlock_irqrestore(&hist_info->hist_lock, flag);
ret = -EINVAL;
goto hist_collect_exit;
}
- spin_lock_irqsave(&hist_info->hist_lock, flag);
/* wait for hist done if cache has no data */
if (hist_info->col_state != HIST_READY) {
spin_unlock_irqrestore(&hist_info->hist_lock, flag);
@@ -3285,9 +3291,9 @@
&(hist_info->comp), timeout);
mutex_lock(&hist_info->hist_mutex);
+ spin_lock_irqsave(&hist_info->hist_lock, flag);
if (wait_ret == 0) {
ret = -ETIMEDOUT;
- spin_lock_irqsave(&hist_info->hist_lock, flag);
pr_debug("bin collection timedout, state %d",
hist_info->col_state);
/*
@@ -3302,37 +3308,33 @@
*/
hist_info->hist_cnt_time++;
hist_info->col_state = HIST_READY;
- spin_unlock_irqrestore(&hist_info->hist_lock, flag);
} else if (wait_ret < 0) {
+ spin_unlock_irqrestore(&hist_info->hist_lock, flag);
ret = -EINTR;
pr_debug("%s: bin collection interrupted",
__func__);
goto hist_collect_exit;
}
- if (hist_info->col_state != HIST_READY) {
+ if (hist_info->col_state != HIST_READY &&
+ hist_info->col_state != HIST_UNKNOWN) {
ret = -ENODATA;
- spin_lock_irqsave(&hist_info->hist_lock, flag);
hist_info->col_state = HIST_READY;
- spin_unlock_irqrestore(&hist_info->hist_lock, flag);
pr_debug("%s: state is not ready: %d",
__func__, hist_info->col_state);
}
- } else {
- spin_unlock_irqrestore(&hist_info->hist_lock, flag);
}
- spin_lock_irqsave(&hist_info->hist_lock, flag);
if (hist_info->col_state == HIST_READY) {
+ hist_info->col_state = HIST_IDLE;
spin_unlock_irqrestore(&hist_info->hist_lock, flag);
v_base = ctl_base + 0x1C;
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
sum = pp_hist_read(v_base, hist_info);
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
- spin_lock_irqsave(&hist_info->hist_lock, flag);
if (expect_sum && sum != expect_sum)
ret = -ENODATA;
- hist_info->col_state = HIST_IDLE;
+ } else {
+ spin_unlock_irqrestore(&hist_info->hist_lock, flag);
}
- spin_unlock_irqrestore(&hist_info->hist_lock, flag);
hist_collect_exit:
mutex_unlock(&hist_info->hist_mutex);
return ret;
diff --git a/drivers/video/msm/mdss/msm_mdss_io_8974.c b/drivers/video/msm/mdss/msm_mdss_io_8974.c
index a0663e3..834ef66 100644
--- a/drivers/video/msm/mdss/msm_mdss_io_8974.c
+++ b/drivers/video/msm/mdss/msm_mdss_io_8974.c
@@ -259,7 +259,7 @@
return 0;
}
-int mdss_dsi_bus_clk_start(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
+static int mdss_dsi_bus_clk_start(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
{
int rc = 0;
@@ -303,7 +303,7 @@
return rc;
}
-void mdss_dsi_bus_clk_stop(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
+static void mdss_dsi_bus_clk_stop(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
{
if (ctrl_pdata->mmss_misc_ahb_clk)
clk_disable_unprepare(ctrl_pdata->mmss_misc_ahb_clk);
@@ -408,11 +408,6 @@
pr_debug("%s: ndx=%d\n", __func__, ctrl_pdata->ndx);
- if (ctrl_pdata->mdss_dsi_clk_on) {
- pr_info("%s: mdss_dsi_clks already ON\n", __func__);
- return 0;
- }
-
rc = clk_enable(ctrl_pdata->esc_clk);
if (rc) {
pr_err("%s: Failed to enable dsi esc clk\n", __func__);
@@ -431,8 +426,6 @@
goto pixel_clk_err;
}
- ctrl_pdata->mdss_dsi_clk_on = 1;
-
return rc;
pixel_clk_err:
@@ -452,19 +445,12 @@
pr_debug("%s: ndx=%d\n", __func__, ctrl_pdata->ndx);
- if (ctrl_pdata->mdss_dsi_clk_on == 0) {
- pr_info("%s: mdss_dsi_clks already OFF\n", __func__);
- return;
- }
-
clk_disable(ctrl_pdata->esc_clk);
clk_disable(ctrl_pdata->pixel_clk);
clk_disable(ctrl_pdata->byte_clk);
-
- ctrl_pdata->mdss_dsi_clk_on = 0;
}
-int mdss_dsi_link_clk_start(struct mdss_dsi_ctrl_pdata *ctrl)
+static int mdss_dsi_link_clk_start(struct mdss_dsi_ctrl_pdata *ctrl)
{
int rc = 0;
@@ -494,90 +480,191 @@
return rc;
}
-void mdss_dsi_link_clk_stop(struct mdss_dsi_ctrl_pdata *ctrl)
+static void mdss_dsi_link_clk_stop(struct mdss_dsi_ctrl_pdata *ctrl)
{
mdss_dsi_link_clk_disable(ctrl);
mdss_dsi_link_clk_unprepare(ctrl);
}
-static void mdss_dsi_clk_ctrl_sub(struct mdss_dsi_ctrl_pdata *ctrl, int enable)
+static int __mdss_dsi_update_clk_cnt(u32 *clk_cnt, int enable)
{
int changed = 0;
if (enable) {
- if (ctrl->clk_cnt_sub == 0)
+ if (*clk_cnt == 0)
changed++;
- ctrl->clk_cnt_sub++;
+ (*clk_cnt)++;
} else {
- if (ctrl->clk_cnt_sub) {
- ctrl->clk_cnt_sub--;
- if (ctrl->clk_cnt_sub == 0)
+ if (*clk_cnt != 0) {
+ (*clk_cnt)--;
+ if (*clk_cnt == 0)
changed++;
} else {
- pr_debug("%s: Can not be turned off\n", __func__);
+ pr_debug("%s: clk cnt already zero\n", __func__);
}
}
- pr_debug("%s: ndx=%d clk_cnt_sub=%d changed=%d enable=%d\n",
- __func__, ctrl->ndx, ctrl->clk_cnt_sub, changed, enable);
- if (changed) {
- if (enable) {
- if (mdss_dsi_bus_clk_start(ctrl) == 0)
- mdss_dsi_link_clk_start(ctrl);
- } else {
- mdss_dsi_link_clk_stop(ctrl);
- mdss_dsi_bus_clk_stop(ctrl);
+ return changed;
+}
+
+static int mdss_dsi_clk_ctrl_sub(struct mdss_dsi_ctrl_pdata *ctrl,
+ u8 clk_type, int enable)
+{
+ int rc = 0;
+
+ pr_debug("%s: ndx=%d clk_type=%08x enable=%d\n", __func__,
+ ctrl->ndx, clk_type, enable);
+
+ if (enable) {
+ if (clk_type & DSI_BUS_CLKS) {
+ rc = mdss_dsi_bus_clk_start(ctrl);
+ if (rc) {
+ pr_err("Failed to start bus clocks. rc=%d\n",
+ rc);
+ goto error;
+ }
}
+ if (clk_type & DSI_LINK_CLKS) {
+ rc = mdss_dsi_link_clk_start(ctrl);
+ if (rc) {
+ pr_err("Failed to start link clocks. rc=%d\n",
+ rc);
+ if (clk_type & DSI_BUS_CLKS)
+ mdss_dsi_bus_clk_stop(ctrl);
+ goto error;
+ }
+ }
+ } else {
+ if (clk_type & DSI_LINK_CLKS)
+ mdss_dsi_link_clk_stop(ctrl);
+ if (clk_type & DSI_BUS_CLKS)
+ mdss_dsi_bus_clk_stop(ctrl);
}
+
+error:
+ return rc;
}
static DEFINE_MUTEX(dsi_clk_lock); /* per system */
-bool __mdss_dsi_clk_enabled(struct mdss_dsi_ctrl_pdata *ctrl)
+bool __mdss_dsi_clk_enabled(struct mdss_dsi_ctrl_pdata *ctrl, u8 clk_type)
{
- bool enabled;
+ bool bus_enabled = true;
+ bool link_enabled = true;
+
mutex_lock(&dsi_clk_lock);
- enabled = ctrl->clk_cnt ? true : false;
+ if (clk_type & DSI_BUS_CLKS)
+ bus_enabled = ctrl->bus_clk_cnt ? true : false;
+ if (clk_type & DSI_LINK_CLKS)
+ link_enabled = ctrl->link_clk_cnt ? true : false;
mutex_unlock(&dsi_clk_lock);
- return enabled;
+ return bus_enabled && link_enabled;
}
-void mdss_dsi_clk_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, int enable)
+int mdss_dsi_clk_ctrl(struct mdss_dsi_ctrl_pdata *ctrl,
+ u8 clk_type, int enable)
{
- int changed = 0;
- struct mdss_dsi_ctrl_pdata *sctrl = NULL;
+ int rc = 0;
+ int changed = 0, m_changed = 0;
+ struct mdss_dsi_ctrl_pdata *mctrl = NULL;
+
+ if (!ctrl) {
+ pr_err("%s: Invalid arg\n", __func__);
+ return -EINVAL;
+ }
+
+ /*
+ * In broadcast mode, we need to enable clocks for the
+ * master controller as well when enabling clocks for the
+ * slave controller
+ */
+ if (mdss_dsi_is_slave_ctrl(ctrl)) {
+ mctrl = mdss_dsi_get_master_ctrl();
+ if (!mctrl)
+ pr_warn("%s: Unable to get master control\n", __func__);
+ }
+
+ pr_debug("%s++: ndx=%d clk_type=%d bus_clk_cnt=%d link_clk_cnt=%d",
+ __func__, ctrl->ndx, clk_type, ctrl->bus_clk_cnt,
+ ctrl->link_clk_cnt);
+ pr_debug("%s++: mctrl=%s m_bus_clk_cnt=%d m_link_clk_cnt=%d\n, enable=%d\n",
+ __func__, mctrl ? "yes" : "no", mctrl ? mctrl->bus_clk_cnt : -1,
+ mctrl ? mctrl->link_clk_cnt : -1, enable);
mutex_lock(&dsi_clk_lock);
- if (enable) {
- if (ctrl->clk_cnt == 0)
- changed++;
- ctrl->clk_cnt++;
- } else {
- if (ctrl->clk_cnt) {
- ctrl->clk_cnt--;
- if (ctrl->clk_cnt == 0)
- changed++;
- } else {
- pr_debug("%s: Can not be turned off\n", __func__);
- }
+ if (clk_type & DSI_BUS_CLKS) {
+ changed = __mdss_dsi_update_clk_cnt(&ctrl->bus_clk_cnt,
+ enable);
+ if (changed && mctrl)
+ m_changed = __mdss_dsi_update_clk_cnt(
+ &mctrl->bus_clk_cnt, enable);
}
- pr_debug("%s: ndx=%d clk_cnt=%d changed=%d enable=%d\n",
- __func__, ctrl->ndx, ctrl->clk_cnt, changed, enable);
- if (ctrl->flags & DSI_FLAG_CLOCK_MASTER)
- sctrl = mdss_dsi_ctrl_slave(ctrl);
+ if (clk_type & DSI_LINK_CLKS) {
+ changed += __mdss_dsi_update_clk_cnt(&ctrl->link_clk_cnt,
+ enable);
+ if (changed && mctrl)
+ m_changed += __mdss_dsi_update_clk_cnt(
+ &mctrl->link_clk_cnt, enable);
+ }
if (changed) {
- if (enable && sctrl)
- mdss_dsi_clk_ctrl_sub(sctrl, enable);
+ if (enable && m_changed) {
+ rc = mdss_dsi_clk_ctrl_sub(mctrl, clk_type, enable);
+ if (rc) {
+ pr_err("Failed to start mctrl clocks. rc=%d\n",
+ rc);
+ goto error_mctrl_start;
+ }
+ }
- mdss_dsi_clk_ctrl_sub(ctrl, enable);
+ rc = mdss_dsi_clk_ctrl_sub(ctrl, clk_type, enable);
+ if (rc) {
+ pr_err("Failed to %s ctrl clocks. rc=%d\n",
+ (enable ? "start" : "stop"), rc);
+ goto error_ctrl;
+ }
- if (!enable && sctrl)
- mdss_dsi_clk_ctrl_sub(sctrl, enable);
+ if (!enable && m_changed) {
+ rc = mdss_dsi_clk_ctrl_sub(mctrl, clk_type, enable);
+ if (rc) {
+ pr_err("Failed to stop mctrl clocks. rc=%d\n",
+ rc);
+ goto error_mctrl_stop;
+ }
+ }
}
+ goto no_error;
+
+error_mctrl_stop:
+ mdss_dsi_clk_ctrl_sub(ctrl, clk_type, enable ? 0 : 1);
+error_ctrl:
+ mdss_dsi_clk_ctrl_sub(mctrl, clk_type, 0);
+error_mctrl_start:
+ if (clk_type & DSI_BUS_CLKS) {
+ if (mctrl)
+ __mdss_dsi_update_clk_cnt(&mctrl->bus_clk_cnt,
+ enable ? 0 : 1);
+ __mdss_dsi_update_clk_cnt(&ctrl->bus_clk_cnt, enable ? 0 : 1);
+ }
+ if (clk_type & DSI_LINK_CLKS) {
+ if (mctrl)
+ __mdss_dsi_update_clk_cnt(&mctrl->link_clk_cnt,
+ enable ? 0 : 1);
+ __mdss_dsi_update_clk_cnt(&ctrl->link_clk_cnt, enable ? 0 : 1);
+ }
+
+no_error:
mutex_unlock(&dsi_clk_lock);
+ pr_debug("%s++: ndx=%d clk_type=%d bus_clk_cnt=%d link_clk_cnt=%d changed=%d",
+ __func__, ctrl->ndx, clk_type, ctrl->bus_clk_cnt,
+ ctrl->link_clk_cnt, changed);
+ pr_debug("%s++: mctrl=%s m_bus_clk_cnt=%d m_link_clk_cnt=%d\n, m_changed=%d, enable=%d\n",
+ __func__, mctrl ? "yes" : "no", mctrl ? mctrl->bus_clk_cnt : -1,
+ mctrl ? mctrl->link_clk_cnt : -1, m_changed, enable);
+
+ return rc;
}
void mdss_dsi_phy_sw_reset(unsigned char *ctrl_base)
@@ -594,29 +681,39 @@
void mdss_dsi_phy_disable(struct mdss_dsi_ctrl_pdata *ctrl)
{
- static struct mdss_dsi_ctrl_pdata *left_ctrl;
+ struct mdss_dsi_ctrl_pdata *ctrl0 = NULL;
if (ctrl == NULL) {
pr_err("%s: Invalid input data\n", __func__);
return;
}
- if (left_ctrl &&
- (ctrl->panel_data.panel_info.pdest == DISPLAY_1))
+ /*
+ * In dual-dsi configuration, the phy should be disabled for the
+ * first controller only when the second controller is disabled.
+ * This is true regardless of whether broadcast mode is enabled
+ * or not.
+ */
+ if ((ctrl->ndx == DSI_CTRL_0) &&
+ mdss_dsi_get_ctrl_by_index(DSI_CTRL_1)) {
+ pr_debug("%s: Dual dsi detected. skipping config for ctrl%d\n",
+ __func__, ctrl->ndx);
return;
-
- if (left_ctrl &&
- (ctrl->panel_data.panel_info.pdest
- ==
- DISPLAY_2)) {
- MIPI_OUTP(left_ctrl->ctrl_base + 0x0470,
- 0x000);
- MIPI_OUTP(left_ctrl->ctrl_base + 0x0598,
- 0x000);
}
- MIPI_OUTP(ctrl->ctrl_base + 0x0470, 0x000);
- MIPI_OUTP(ctrl->ctrl_base + 0x0598, 0x000);
+ if (ctrl->ndx == DSI_CTRL_1) {
+ ctrl0 = mdss_dsi_get_ctrl_by_index(DSI_CTRL_0);
+ if (ctrl0) {
+ MIPI_OUTP(ctrl0->phy_io.base + 0x0170, 0x000);
+ MIPI_OUTP(ctrl0->phy_io.base + 0x0298, 0x000);
+ } else {
+ pr_warn("%s: Unable to get control%d\n",
+ __func__, DSI_CTRL_0);
+ }
+ }
+
+ MIPI_OUTP(ctrl->phy_io.base + 0x0170, 0x000);
+ MIPI_OUTP(ctrl->phy_io.base + 0x0298, 0x000);
/*
* Wait for the registers writes to complete in order to
@@ -629,7 +726,7 @@
{
struct mdss_dsi_phy_ctrl *pd;
int i, off, ln, offset;
- struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+ struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL, *temp_ctrl = NULL;
ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
panel_data);
@@ -637,67 +734,75 @@
pr_err("%s: Invalid input data\n", __func__);
return;
}
+ temp_ctrl = ctrl_pdata;
pd = &(((ctrl_pdata->panel_data).panel_info.mipi).dsi_phy_db);
/* Strength ctrl 0 */
- MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0484, pd->strength[0]);
+ MIPI_OUTP((ctrl_pdata->phy_io.base) + 0x0184, pd->strength[0]);
- /* phy regulator ctrl settings. Both the DSI controller
- have one regulator */
- if ((ctrl_pdata->panel_data).panel_info.pdest == DISPLAY_1)
- off = 0x0580;
- else
- off = 0x0580 - 0x600;
+ /*
+ * Phy regulator ctrl settings.
+ * In dual dsi configuration, the second controller also uses
+ * the regulators of the first controller, irrespective of whether
+ * broadcast mode is enabled or not.
+ */
+ if (ctrl_pdata->ndx == DSI_CTRL_1) {
+ temp_ctrl = mdss_dsi_get_ctrl_by_index(DSI_CTRL_0);
+ if (!temp_ctrl) {
+ pr_err("%s: Unable to get master ctrl\n", __func__);
+ return;
+ }
+ }
/* Regulator ctrl 0 */
- MIPI_OUTP((ctrl_pdata->ctrl_base) + off + (4 * 0), 0x0);
+ MIPI_OUTP((temp_ctrl->phy_io.base) + 0x280, 0x0);
/* Regulator ctrl - CAL_PWR_CFG */
- MIPI_OUTP((ctrl_pdata->ctrl_base) + off + (4 * 6), pd->regulator[6]);
+ MIPI_OUTP((temp_ctrl->phy_io.base) + 0x298, pd->regulator[6]);
/* Regulator ctrl - TEST */
- MIPI_OUTP((ctrl_pdata->ctrl_base) + off + (4 * 5), pd->regulator[5]);
+ MIPI_OUTP((temp_ctrl->phy_io.base) + 0x294, pd->regulator[5]);
/* Regulator ctrl 3 */
- MIPI_OUTP((ctrl_pdata->ctrl_base) + off + (4 * 3), pd->regulator[3]);
+ MIPI_OUTP((temp_ctrl->phy_io.base) + 0x28c, pd->regulator[3]);
/* Regulator ctrl 2 */
- MIPI_OUTP((ctrl_pdata->ctrl_base) + off + (4 * 2), pd->regulator[2]);
+ MIPI_OUTP((temp_ctrl->phy_io.base) + 0x288, pd->regulator[2]);
/* Regulator ctrl 1 */
- MIPI_OUTP((ctrl_pdata->ctrl_base) + off + (4 * 1), pd->regulator[1]);
+ MIPI_OUTP((temp_ctrl->phy_io.base) + 0x284, pd->regulator[1]);
/* Regulator ctrl 0 */
- MIPI_OUTP((ctrl_pdata->ctrl_base) + off + (4 * 0), pd->regulator[0]);
+ MIPI_OUTP((temp_ctrl->phy_io.base) + 0x280, pd->regulator[0]);
/* Regulator ctrl 4 */
- MIPI_OUTP((ctrl_pdata->ctrl_base) + off + (4 * 4), pd->regulator[4]);
+ MIPI_OUTP((temp_ctrl->phy_io.base) + 0x290, pd->regulator[4]);
/* LDO ctrl 0 */
if ((ctrl_pdata->panel_data).panel_info.pdest == DISPLAY_1)
- MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x4dc, 0x00);
+ MIPI_OUTP((ctrl_pdata->phy_io.base) + 0x1dc, 0x00);
else
- MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x4dc, 0x00);
+ MIPI_OUTP((ctrl_pdata->phy_io.base) + 0x1dc, 0x00);
- off = 0x0440; /* phy timing ctrl 0 - 11 */
+ off = 0x0140; /* phy timing ctrl 0 - 11 */
for (i = 0; i < 12; i++) {
- MIPI_OUTP((ctrl_pdata->ctrl_base) + off, pd->timing[i]);
+ MIPI_OUTP((ctrl_pdata->phy_io.base) + off, pd->timing[i]);
wmb();
off += 4;
}
/* MMSS_DSI_0_PHY_DSIPHY_CTRL_1 */
- MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0474, 0x00);
+ MIPI_OUTP((ctrl_pdata->phy_io.base) + 0x0174, 0x00);
/* MMSS_DSI_0_PHY_DSIPHY_CTRL_0 */
- MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0470, 0x5f);
+ MIPI_OUTP((ctrl_pdata->phy_io.base) + 0x0170, 0x5f);
wmb();
/* Strength ctrl 1 */
- MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0488, pd->strength[1]);
+ MIPI_OUTP((ctrl_pdata->phy_io.base) + 0x0188, pd->strength[1]);
wmb();
/* 4 lanes + clk lane configuration */
/* lane config n * (0 - 4) & DataPath setup */
for (ln = 0; ln < 5; ln++) {
- off = 0x0300 + (ln * 0x40);
+ off = (ln * 0x40);
for (i = 0; i < 9; i++) {
offset = i + (ln * 9);
- MIPI_OUTP((ctrl_pdata->ctrl_base) + off,
+ MIPI_OUTP((ctrl_pdata->phy_io.base) + off,
pd->lanecfg[offset]);
wmb();
off += 4;
@@ -705,19 +810,19 @@
}
/* MMSS_DSI_0_PHY_DSIPHY_CTRL_0 */
- MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0470, 0x5f);
+ MIPI_OUTP((ctrl_pdata->phy_io.base) + 0x0170, 0x5f);
wmb();
/* DSI_0_PHY_DSIPHY_GLBL_TEST_CTRL */
if ((ctrl_pdata->panel_data).panel_info.pdest == DISPLAY_1)
- MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x04d4, 0x01);
+ MIPI_OUTP((ctrl_pdata->phy_io.base) + 0x01d4, 0x01);
else
- MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x04d4, 0x00);
+ MIPI_OUTP((ctrl_pdata->phy_io.base) + 0x01d4, 0x00);
wmb();
- off = 0x04b4; /* phy BIST ctrl 0 - 5 */
+ off = 0x01b4; /* phy BIST ctrl 0 - 5 */
for (i = 0; i < 6; i++) {
- MIPI_OUTP((ctrl_pdata->ctrl_base) + off, pd->bistctrl[i]);
+ MIPI_OUTP((ctrl_pdata->phy_io.base) + off, pd->bistctrl[i]);
wmb();
off += 4;
}
diff --git a/include/linux/android_alarm.h b/include/linux/android_alarm.h
index b017caa..65227ad 100644
--- a/include/linux/android_alarm.h
+++ b/include/linux/android_alarm.h
@@ -71,7 +71,7 @@
void alarm_start_range(struct alarm *alarm, ktime_t start, ktime_t end);
int alarm_try_to_cancel(struct alarm *alarm);
int alarm_cancel(struct alarm *alarm);
-void set_power_on_alarm(long secs);
+void set_power_on_alarm(long secs, bool enable);
ktime_t alarm_get_elapsed_realtime(void);
/* set rtc while preserving elapsed realtime */
diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
index 70b3eef..3ab25c3 100644
--- a/include/linux/devfreq.h
+++ b/include/linux/devfreq.h
@@ -51,10 +51,10 @@
* bound (greatest lower bound)
*/
#define DEVFREQ_FLAG_LEAST_UPPER_BOUND 0x1
-#define DEVFREQ_FLAG_WAKEUP_MAXFREQ 0x2
-#define DEVFREQ_FLAG_FAST_HINT 0x2
-#define DEVFREQ_FLAG_SLOW_HINT 0x4
+#define DEVFREQ_FLAG_FAST_HINT 0x2
+#define DEVFREQ_FLAG_SLOW_HINT 0x4
+#define DEVFREQ_FLAG_WAKEUP_MAXFREQ 0x8
/**
* struct devfreq_governor_data - mapping to per device governor data
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index bff056d..e53c350 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -197,6 +197,12 @@
void *handler_priv;
};
+enum dev_state {
+ DEV_SUSPENDING = 1,
+ DEV_SUSPENDED,
+ DEV_RESUMED,
+};
+
struct mmc_host {
struct device *parent;
struct device class_dev;
@@ -421,6 +427,7 @@
struct delayed_work work;
enum mmc_load state;
} clk_scaling;
+ enum dev_state dev_status;
unsigned long private[0] ____cacheline_aligned;
};
diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h
index 08ca341..65a3fe1 100644
--- a/include/linux/mmc/sdhci.h
+++ b/include/linux/mmc/sdhci.h
@@ -160,6 +160,11 @@
*/
#define SDHCI_QUIRK2_DIVIDE_TOUT_BY_4 (1 << 9)
+/*
+ * Some SDHC controllers are unable to handle data-end bit error in
+ * 1-bit mode of SDIO.
+ */
+#define SDHCI_QUIRK2_IGN_DATA_END_BIT_ERROR (1<<9)
int irq; /* Device IRQ */
void __iomem *ioaddr; /* Mapped address */
@@ -252,6 +257,9 @@
struct mutex ios_mutex;
enum sdhci_power_policy power_policy;
+ bool irq_enabled; /* host irq status flag */
+ bool async_int_supp; /* async support to rxv int, when clks are off */
+ bool disable_sdio_irq_deferred; /* status of disabling sdio irq */
u32 auto_cmd_err_sts;
unsigned long private[0] ____cacheline_aligned;
};
diff --git a/include/linux/msm_ipa.h b/include/linux/msm_ipa.h
index b2229d3..9368d8f 100644
--- a/include/linux/msm_ipa.h
+++ b/include/linux/msm_ipa.h
@@ -64,6 +64,11 @@
#define IPA_RESOURCE_NAME_MAX 20
/**
+ * max number of interface properties
+ */
+#define IPA_NUM_PROPS_MAX 20
+
+/**
* size of the mac address
*/
#define IPA_MAC_ADDR_SIZE 6
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index e332368..3ec92e6 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -85,6 +85,30 @@
#define MDP_IMGTYPE2_START 0x10000
#define MSMFB_DRIVER_VERSION 0xF9E8D701
+/* HW Revisions for different MDSS targets */
+#define MDSS_GET_MAJOR(rev) ((rev) >> 28)
+#define MDSS_GET_MINOR(rev) (((rev) >> 16) & 0xFFF)
+#define MDSS_GET_STEP(rev) ((rev) & 0xFFFF)
+#define MDSS_GET_MAJOR_MINOR(rev) ((rev) >> 16)
+
+#define IS_MDSS_MAJOR_MINOR_SAME(rev1, rev2) \
+ (MDSS_GET_MAJOR_MINOR((rev1)) == MDSS_GET_MAJOR_MINOR((rev2)))
+
+#define MDSS_MDP_REV(major, minor, step) \
+ ((((major) & 0x000F) << 28) | \
+ (((minor) & 0x0FFF) << 16) | \
+ ((step) & 0xFFFF))
+
+#define MDSS_MDP_HW_REV_100 MDSS_MDP_REV(1, 0, 0) /* 8974 v1.0 */
+#define MDSS_MDP_HW_REV_101 MDSS_MDP_REV(1, 1, 0) /* 8x26 v1.0 */
+#define MDSS_MDP_HW_REV_101_1 MDSS_MDP_REV(1, 1, 1) /* 8x26 v2.0, 8926 v1.0 */
+#define MDSS_MDP_HW_REV_101_2 MDSS_MDP_REV(1, 1, 2) /* 8926 v2.0 */
+#define MDSS_MDP_HW_REV_102 MDSS_MDP_REV(1, 2, 0) /* 8974 v2.0 */
+#define MDSS_MDP_HW_REV_102_1 MDSS_MDP_REV(1, 2, 1) /* 8974 v3.0 (Pro) */
+#define MDSS_MDP_HW_REV_103 MDSS_MDP_REV(1, 3, 0) /* 8084 v1.0 */
+#define MDSS_MDP_HW_REV_103_1 MDSS_MDP_REV(1, 3, 1) /* 8084 v1.1 */
+#define MDSS_MDP_HW_REV_200 MDSS_MDP_REV(2, 0, 0) /* 8092 v1.0 */
+
enum {
NOTIFY_UPDATE_START,
NOTIFY_UPDATE_STOP,
diff --git a/include/linux/qpnp-revid.h b/include/linux/qpnp-revid.h
index 3cf9f1c..3d271f0 100644
--- a/include/linux/qpnp-revid.h
+++ b/include/linux/qpnp-revid.h
@@ -13,6 +13,13 @@
#ifndef __QPNP_REVID
#define __QPNP_REVID
+#define PM8226_V2P2_REV1 0x00
+#define PM8226_V2P2_REV2 0x00
+#define PM8226_V2P2_REV3 0x02
+#define PM8226_V2P2_REV4 0x02
+#define PM8226_V2P2_TYPE 0x51
+#define PM8226_V2P2_SUBTYPE 0x04
+
#define PM8226_V2P1_REV1 0x00
#define PM8226_V2P1_REV2 0x00
#define PM8226_V2P1_REV3 0x01
diff --git a/include/linux/qpnp/qpnp-adc.h b/include/linux/qpnp/qpnp-adc.h
index 13eb461..7ba4148 100644
--- a/include/linux/qpnp/qpnp-adc.h
+++ b/include/linux/qpnp/qpnp-adc.h
@@ -20,6 +20,7 @@
#include <linux/kernel.h>
#include <linux/list.h>
+#include <linux/qpnp-revid.h>
/**
* enum qpnp_vadc_channels - QPNP AMUX arbiter channels
*/
@@ -1002,15 +1003,27 @@
* @chan_prop - Represent the channel properties of the ADC.
*/
struct qpnp_adc_amux_properties {
- uint32_t amux_channel;
- uint32_t decimation;
- uint32_t mode_sel;
- uint32_t hw_settle_time;
- uint32_t fast_avg_setup;
- enum qpnp_vadc_trigger trigger_channel;
+ uint32_t amux_channel;
+ uint32_t decimation;
+ uint32_t mode_sel;
+ uint32_t hw_settle_time;
+ uint32_t fast_avg_setup;
+ enum qpnp_vadc_trigger trigger_channel;
struct qpnp_vadc_chan_properties chan_prop[0];
};
+/* SW index's for PMIC type and version used by QPNP VADC and IADC */
+#define QPNP_REV_ID_8941_3_1 1
+#define QPNP_REV_ID_8026_1_0 2
+#define QPNP_REV_ID_8026_2_0 3
+#define QPNP_REV_ID_8110_1_0 4
+#define QPNP_REV_ID_8026_2_1 5
+#define QPNP_REV_ID_8110_2_0 6
+#define QPNP_REV_ID_8026_2_2 7
+#define QPNP_REV_ID_8941_3_0 8
+#define QPNP_REV_ID_8941_2_0 9
+
+
/* Public API */
#if defined(CONFIG_SENSORS_QPNP_ADC_VOLTAGE) \
|| defined(CONFIG_SENSORS_QPNP_ADC_VOLTAGE_MODULE)
@@ -1366,9 +1379,16 @@
* qpnp_vadc_sns_comp_result() - Compensate vbatt readings based on temperature
* @dev: Structure device for qpnp vadc
* @result: Voltage in uV that needs compensation.
+ * @is_pon_ocv: Whether the reading is from a power on OCV or not
*/
int32_t qpnp_vbat_sns_comp_result(struct qpnp_vadc_chip *dev,
- int64_t *result);
+ int64_t *result, bool is_pon_ocv);
+/**
+ * qpnp_adc_get_revid_version() - Obtain the PMIC number and revision.
+ * @dev: Structure device node.
+ * returns internal mapped PMIC number and revision id.
+ */
+int qpnp_adc_get_revid_version(struct device *dev);
#else
static inline int32_t qpnp_vadc_read(struct qpnp_vadc_chip *dev,
uint32_t channel,
@@ -1482,6 +1502,8 @@
static inline int32_t qpnp_vbat_sns_comp_result(struct qpnp_vadc_chip *dev,
int64_t *result)
{ return -ENXIO; }
+static inline int qpnp_adc_get_revid_version(struct device *dev)
+{ return -ENXIO; }
#endif
/* Public API */
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index d16448a..195800f 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -523,6 +523,7 @@
bool use_sec_phy;
bool no_selective_suspend;
int resume_gpio;
+ bool is_uicc;
};
/**
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 81d5b9c..f446f51 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -708,6 +708,7 @@
#define V4L2_QCOM_BUF_INPUT_UNSUPPORTED 0x200000
#define V4L2_QCOM_BUF_FLAG_EOS 0x2000
#define V4L2_QCOM_BUF_FLAG_READONLY 0x400000
+#define V4L2_MSM_BUF_FLAG_MBAFF 0x800000
/*
* O V E R L A Y P R E V I E W
diff --git a/include/media/msm_cam_sensor.h b/include/media/msm_cam_sensor.h
index a88a71d..8199643 100644
--- a/include/media/msm_cam_sensor.h
+++ b/include/media/msm_cam_sensor.h
@@ -246,16 +246,6 @@
MASTER_MAX,
};
-struct msm_camera_sensor_slave_info {
- char sensor_name[32];
- char eeprom_name[32];
- char actuator_name[32];
- enum msm_sensor_camera_id_t camera_id;
- uint16_t slave_addr;
- enum msm_camera_i2c_reg_addr_type addr_type;
- struct msm_sensor_id_info_t sensor_id_info;
- struct msm_sensor_power_setting_array power_setting_array;
-};
struct msm_camera_i2c_reg_array {
uint16_t reg_addr;
@@ -343,6 +333,7 @@
enum camb_position_t {
BACK_CAMERA_B,
FRONT_CAMERA_B,
+ INVALID_CAMERA_B,
};
struct msm_sensor_info_t {
@@ -366,7 +357,8 @@
enum camerab_mode_t {
CAMERA_MODE_2D_B = (1<<0),
- CAMERA_MODE_3D_B = (1<<1)
+ CAMERA_MODE_3D_B = (1<<1),
+ CAMERA_MODE_INVALID = (1<<2),
};
struct msm_sensor_init_params {
@@ -378,6 +370,19 @@
uint32_t sensor_mount_angle;
};
+struct msm_camera_sensor_slave_info {
+ char sensor_name[32];
+ char eeprom_name[32];
+ char actuator_name[32];
+ enum msm_sensor_camera_id_t camera_id;
+ uint16_t slave_addr;
+ enum msm_camera_i2c_reg_addr_type addr_type;
+ struct msm_sensor_id_info_t sensor_id_info;
+ struct msm_sensor_power_setting_array power_setting_array;
+ uint8_t is_init_params_valid;
+ struct msm_sensor_init_params sensor_init_params;
+};
+
struct sensorb_cfg_data {
int cfgtype;
union {
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 50660b3..dce56a6 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -131,6 +131,8 @@
* most likely due to retrans in 3WHS.
*/
+#define TCP_DELACK_SEG 1 /*Number of full MSS to receive before Acking RFC2581*/
+
#define TCP_RESOURCE_PROBE_INTERVAL ((unsigned)(HZ/2U)) /* Maximal interval between probes
* for local resources.
*/
@@ -253,6 +255,10 @@
extern int sysctl_tcp_thin_linear_timeouts;
extern int sysctl_tcp_thin_dupack;
+/* sysctl variables for controlling various tcp parameters */
+extern int sysctl_tcp_delack_seg;
+extern int sysctl_tcp_use_userconfig;
+
extern atomic_long_t tcp_memory_allocated;
extern struct percpu_counter tcp_sockets_allocated;
extern int tcp_memory_pressure;
@@ -346,6 +352,10 @@
struct pipe_inode_info *pipe, size_t len,
unsigned int flags);
+extern int tcp_use_userconfig_sysctl_handler(struct ctl_table *, int,
+ void __user *, size_t *, loff_t *);
+extern int tcp_proc_delayed_ack_control(struct ctl_table *, int,
+ void __user *, size_t *, loff_t *);
static inline void tcp_dec_quickack_mode(struct sock *sk,
const unsigned int pkts)
{
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 700d2ae..f320017 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -384,7 +384,7 @@
void tracing_off(void)
{
if (global_trace.buffer)
- ring_buffer_record_on(global_trace.buffer);
+ ring_buffer_record_off(global_trace.buffer);
/*
* This flag is only looked at when buffers haven't been
* allocated yet. We don't really care about the race
diff --git a/mm/ksm.c b/mm/ksm.c
index 47c8853..fa73fc6 100644
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -189,6 +189,9 @@
/* Milliseconds ksmd should sleep between batches */
static unsigned int ksm_thread_sleep_millisecs = 20;
+/* Boolean to indicate whether to use deferred timer or not */
+static bool use_deferred_timer;
+
#define KSM_RUN_STOP 0
#define KSM_RUN_MERGE 1
#define KSM_RUN_UNMERGE 2
@@ -1427,6 +1430,41 @@
}
}
+static void process_timeout(unsigned long __data)
+{
+ wake_up_process((struct task_struct *)__data);
+}
+
+static signed long __sched deferred_schedule_timeout(signed long timeout)
+{
+ struct timer_list timer;
+ unsigned long expire;
+
+ __set_current_state(TASK_INTERRUPTIBLE);
+ if (timeout < 0) {
+ pr_err("schedule_timeout: wrong timeout value %lx\n",
+ timeout);
+ __set_current_state(TASK_RUNNING);
+ goto out;
+ }
+
+ expire = timeout + jiffies;
+
+ setup_deferrable_timer_on_stack(&timer, process_timeout,
+ (unsigned long)current);
+ mod_timer(&timer, expire);
+ schedule();
+ del_singleshot_timer_sync(&timer);
+
+ /* Remove the timer from the object tracker */
+ destroy_timer_on_stack(&timer);
+
+ timeout = expire - jiffies;
+
+out:
+ return timeout < 0 ? 0 : timeout;
+}
+
static int ksmd_should_run(void)
{
return (ksm_run & KSM_RUN_MERGE) && !list_empty(&ksm_mm_head.mm_list);
@@ -1446,7 +1484,11 @@
try_to_freeze();
if (ksmd_should_run()) {
- schedule_timeout_interruptible(
+ if (use_deferred_timer)
+ deferred_schedule_timeout(
+ msecs_to_jiffies(ksm_thread_sleep_millisecs));
+ else
+ schedule_timeout_interruptible(
msecs_to_jiffies(ksm_thread_sleep_millisecs));
} else {
wait_event_freezable(ksm_thread_wait,
@@ -1926,6 +1968,26 @@
}
KSM_ATTR(run);
+static ssize_t deferred_timer_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ return snprintf(buf, 8, "%d\n", use_deferred_timer);
+}
+
+static ssize_t deferred_timer_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long enable;
+ int err;
+
+ err = kstrtoul(buf, 10, &enable);
+ use_deferred_timer = enable;
+
+ return count;
+}
+KSM_ATTR(deferred_timer);
+
static ssize_t pages_shared_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
@@ -1980,6 +2042,7 @@
&pages_unshared_attr.attr,
&pages_volatile_attr.attr,
&full_scans_attr.attr,
+ &deferred_timer_attr.attr,
NULL,
};
diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c
index 7f38d35..a8d7ed0 100644
--- a/net/ipv4/ping.c
+++ b/net/ipv4/ping.c
@@ -896,13 +896,13 @@
sin6->sin6_port = 0;
sin6->sin6_addr = ip6->saddr;
+ sin6->sin6_flowinfo = 0;
if (np->sndflow)
sin6->sin6_flowinfo =
*(__be32 *)ip6 & IPV6_FLOWINFO_MASK;
- if (__ipv6_addr_needs_scope_id(
- ipv6_addr_type(&sin6->sin6_addr)))
- sin6->sin6_scope_id = IP6CB(skb)->iif;
+ sin6->sin6_scope_id = ipv6_iface_scope_id(&sin6->sin6_addr,
+ IP6CB(skb)->iif);
if (inet6_sk(sk)->rxopt.all)
pingv6_ops.datagram_recv_ctl(sk, msg, skb);
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index 7a7724d..6bd622f 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -36,6 +36,10 @@
static int ip_ttl_max = 255;
static int ip_ping_group_range_min[] = { 0, 0 };
static int ip_ping_group_range_max[] = { GID_T_MAX, GID_T_MAX };
+static int tcp_delack_seg_min = TCP_DELACK_MIN;
+static int tcp_delack_seg_max = 60;
+static int tcp_use_userconfig_min;
+static int tcp_use_userconfig_max = 1;
/* Update system visible IP port range */
static void set_local_port_range(int range[2])
@@ -699,6 +703,25 @@
.proc_handler = proc_dointvec_minmax,
.extra1 = &zero
},
+ {
+ .procname = "tcp_delack_seg",
+ .data = &sysctl_tcp_delack_seg,
+ .maxlen = sizeof(sysctl_tcp_delack_seg),
+ .mode = 0644,
+ .proc_handler = tcp_proc_delayed_ack_control,
+ .extra1 = &tcp_delack_seg_min,
+ .extra2 = &tcp_delack_seg_max,
+ },
+ {
+ .procname = "tcp_use_userconfig",
+ .data = &sysctl_tcp_use_userconfig,
+ .maxlen = sizeof(sysctl_tcp_use_userconfig),
+ .mode = 0644,
+ .proc_handler = tcp_use_userconfig_sysctl_handler,
+ .extra1 = &tcp_use_userconfig_min,
+ .extra2 = &tcp_use_userconfig_max,
+ },
+
{ }
};
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 74a286c..706899e 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -294,6 +294,12 @@
EXPORT_SYMBOL(sysctl_tcp_rmem);
EXPORT_SYMBOL(sysctl_tcp_wmem);
+int sysctl_tcp_delack_seg __read_mostly = TCP_DELACK_SEG;
+EXPORT_SYMBOL(sysctl_tcp_delack_seg);
+
+int sysctl_tcp_use_userconfig __read_mostly;
+EXPORT_SYMBOL(sysctl_tcp_use_userconfig);
+
atomic_long_t tcp_memory_allocated; /* Current allocated memory. */
EXPORT_SYMBOL(tcp_memory_allocated);
@@ -1213,8 +1219,11 @@
/* Delayed ACKs frequently hit locked sockets during bulk
* receive. */
if (icsk->icsk_ack.blocked ||
- /* Once-per-two-segments ACK was not sent by tcp_input.c */
- tp->rcv_nxt - tp->rcv_wup > icsk->icsk_ack.rcv_mss ||
+ /* Once-per-sysctl_tcp_delack_seg segments
+ * ACK was not sent by tcp_input.c
+ */
+ tp->rcv_nxt - tp->rcv_wup > (icsk->icsk_ack.rcv_mss) *
+ sysctl_tcp_delack_seg ||
/*
* If this read emptied read buffer, we send ACK, if
* connection is not bidirectional, user drained
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 257b617..7c3612b 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -5047,7 +5047,8 @@
struct tcp_sock *tp = tcp_sk(sk);
/* More than one full frame received... */
- if (((tp->rcv_nxt - tp->rcv_wup) > inet_csk(sk)->icsk_ack.rcv_mss &&
+ if (((tp->rcv_nxt - tp->rcv_wup) > (inet_csk(sk)->icsk_ack.rcv_mss) *
+ sysctl_tcp_delack_seg &&
/* ... and right edge of window advances far enough.
* (tcp_recvmsg() will send ACK otherwise). Or...
*/
diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c
index 34d4a02..d1b4792 100644
--- a/net/ipv4/tcp_timer.c
+++ b/net/ipv4/tcp_timer.c
@@ -34,7 +34,39 @@
static void tcp_write_timer(unsigned long);
static void tcp_delack_timer(unsigned long);
-static void tcp_keepalive_timer (unsigned long data);
+static void tcp_keepalive_timer(unsigned long data);
+
+/*Function to reset tcp_ack related sysctl on resetting master control */
+void set_tcp_default(void)
+{
+ sysctl_tcp_delack_seg = TCP_DELACK_SEG;
+}
+
+/*sysctl handler for tcp_ack realted master control */
+int tcp_proc_delayed_ack_control(ctl_table *table, int write,
+ void __user *buffer, size_t *length, loff_t *ppos)
+{
+ int ret = proc_dointvec_minmax(table, write, buffer, length, ppos);
+
+ /* The ret value will be 0 if the input validation is successful
+ * and the values are written to sysctl table. If not, the stack
+ * will continue to work with currently configured values
+ */
+ return ret;
+}
+
+/*sysctl handler for tcp_ack realted master control */
+int tcp_use_userconfig_sysctl_handler(ctl_table *table, int write,
+ void __user *buffer, size_t *length, loff_t *ppos)
+{
+ int ret = proc_dointvec_minmax(table, write, buffer, length, ppos);
+
+ if (write && ret == 0) {
+ if (!sysctl_tcp_use_userconfig)
+ set_tcp_default();
+ }
+ return ret;
+}
void tcp_init_xmit_timers(struct sock *sk)
{
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index b28b7eb..c868a74 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -3816,6 +3816,11 @@
struct lsm_network_audit net = {0,};
u32 tsid = task_sid(task);
+ if (unlikely(!sksec)) {
+ pr_warn("SELinux: sksec is NULL, socket is already freed\n");
+ return -EINVAL;
+ }
+
if (sksec->sid == SECINITSID_KERNEL)
return 0;
diff --git a/sound/soc/codecs/msm8x10-wcd.c b/sound/soc/codecs/msm8x10-wcd.c
index c73b2c8..2286e34 100644
--- a/sound/soc/codecs/msm8x10-wcd.c
+++ b/sound/soc/codecs/msm8x10-wcd.c
@@ -2361,6 +2361,10 @@
struct snd_kcontrol *kcontrol, int event)
{
switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ snd_soc_update_bits(w->codec, MSM8X10_WCD_A_CDC_ANA_CLK_CTL,
+ 0x4, 0x4);
+ break;
case SND_SOC_DAPM_POST_PMU:
dev_dbg(w->codec->dev,
"%s: Sleeping 20ms after enabling EAR PA\n",
@@ -2371,6 +2375,8 @@
dev_dbg(w->codec->dev,
"%s: Sleeping 20ms after disabling EAR PA\n",
__func__);
+ snd_soc_update_bits(w->codec, MSM8X10_WCD_A_CDC_ANA_CLK_CTL,
+ 0x4, 0x0);
msleep(20);
break;
}
@@ -2382,7 +2388,7 @@
SND_SOC_DAPM_OUTPUT("EAR"),
SND_SOC_DAPM_PGA_E("EAR PA", MSM8X10_WCD_A_RX_EAR_EN, 4, 0, NULL, 0,
- msm8x10_wcd_codec_enable_ear_pa,
+ msm8x10_wcd_codec_enable_ear_pa, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_MIXER("DAC1", MSM8X10_WCD_A_RX_EAR_EN, 6, 0, dac1_switch,
@@ -2471,7 +2477,7 @@
SND_SOC_DAPM_SUPPLY("HPHL CLK", MSM8X10_WCD_A_CDC_ANA_CLK_CTL,
1, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("EAR CLK", MSM8X10_WCD_A_CDC_ANA_CLK_CTL,
- 2, 0, NULL, 0),
+ 6, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("LINEOUT CLK", MSM8X10_WCD_A_CDC_ANA_CLK_CTL,
3, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("SPK CLK", MSM8X10_WCD_A_CDC_ANA_CLK_CTL,
diff --git a/sound/soc/codecs/wcd9306.c b/sound/soc/codecs/wcd9306.c
index 95f2041..b201f0b 100644
--- a/sound/soc/codecs/wcd9306.c
+++ b/sound/soc/codecs/wcd9306.c
@@ -4238,6 +4238,23 @@
return 0;
}
+static int tapan_codec_iir_mux_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ pr_debug("%s: event = %d\n", __func__, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ snd_soc_write(codec, w->reg, snd_soc_read(codec, w->reg));
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_write(codec, w->reg, snd_soc_read(codec, w->reg));
+ break;
+ }
+ return 0;
+}
+
static int tapan_codec_dsm_mux_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
@@ -4725,7 +4742,10 @@
SND_SOC_DAPM_POST_PMD),
/* Sidetone */
- SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
+ SND_SOC_DAPM_MUX_E("IIR1 INP1 MUX", TAPAN_A_CDC_IIR1_GAIN_B1_CTL, 0, 0,
+ &iir1_inp1_mux, tapan_codec_iir_mux_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
SND_SOC_DAPM_PGA("IIR1", TAPAN_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
/* AUX PGA */
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index b72590f..9ef2ea4 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -4260,6 +4260,10 @@
if (reg == TAIKO_A_RX_HPH_L_STATUS || reg == TAIKO_A_RX_HPH_R_STATUS)
return 1;
+ /* HPH PA Enable */
+ if (reg == TAIKO_A_RX_HPH_CNP_EN)
+ return 1;
+
if (reg == TAIKO_A_MBHC_INSERT_DET_STATUS)
return 1;
@@ -6797,18 +6801,21 @@
snd_soc_card_change_online_state(codec->card, 1);
mutex_lock(&codec->mutex);
- if (codec->reg_def_copy) {
- pr_debug("%s: Update ASOC cache", __func__);
- kfree(codec->reg_cache);
- codec->reg_cache = kmemdup(codec->reg_def_copy,
- codec->reg_size, GFP_KERNEL);
- }
+
+ taiko_update_reg_defaults(codec);
+ if (wcd9xxx->mclk_rate == TAIKO_MCLK_CLK_12P288MHZ)
+ snd_soc_update_bits(codec, TAIKO_A_CHIP_CTL, 0x06, 0x0);
+ else if (wcd9xxx->mclk_rate == TAIKO_MCLK_CLK_9P6MHZ)
+ snd_soc_update_bits(codec, TAIKO_A_CHIP_CTL, 0x06, 0x2);
+ taiko_codec_init_reg(codec);
if (spkr_drv_wrnd == 1)
snd_soc_update_bits(codec, TAIKO_A_SPKR_DRV_EN, 0x80, 0x80);
- taiko_update_reg_defaults(codec);
- taiko_codec_init_reg(codec);
+ codec->cache_sync = true;
+ snd_soc_cache_sync(codec);
+ codec->cache_sync = false;
+
ret = taiko_handle_pdata(taiko);
if (IS_ERR_VALUE(ret))
pr_err("%s: bad pdata\n", __func__);
@@ -7208,6 +7215,11 @@
{
struct platform_device *pdev = to_platform_device(dev);
struct taiko_priv *taiko = platform_get_drvdata(pdev);
+
+ if (!taiko) {
+ dev_err(dev, "%s: taiko private data is NULL\n", __func__);
+ return -EINVAL;
+ }
dev_dbg(dev, "%s: system resume\n", __func__);
/* Notify */
wcd9xxx_resmgr_notifier_call(&taiko->resmgr, WCD9XXX_EVENT_POST_RESUME);
diff --git a/sound/soc/codecs/wcd9xxx-common.c b/sound/soc/codecs/wcd9xxx-common.c
index b104a6b..eb3a0ba 100644
--- a/sound/soc/codecs/wcd9xxx-common.c
+++ b/sound/soc/codecs/wcd9xxx-common.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, 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
@@ -651,6 +651,29 @@
}
EXPORT_SYMBOL(wcd9xxx_restore_registers);
+static void wcd9xxx_dynamic_bypass_buck_ctrl(struct snd_soc_codec *cdc,
+ bool enable)
+{
+ int i;
+ const struct wcd9xxx_reg_mask_val reg_set[] = {
+ {WCD9XXX_A_BUCK_MODE_3, (0x1 << 3), (enable << 3)},
+ {WCD9XXX_A_BUCK_MODE_5, (0x1 << 1), (enable << 1)},
+ {WCD9XXX_A_BUCK_MODE_5, 0x1, enable}
+ };
+ if (!enable) {
+ snd_soc_update_bits(cdc, WCD9XXX_A_BUCK_MODE_1,
+ (0x1 << 3), 0x00);
+ snd_soc_update_bits(cdc, WCD9XXX_A_BUCK_MODE_4,
+ 0xFF, BUCK_VREF_2V);
+ }
+ for (i = 0; i < ARRAY_SIZE(reg_set); i++)
+ snd_soc_update_bits(cdc, reg_set[i].reg, reg_set[i].mask,
+ reg_set[i].val);
+
+ /* 50us sleep is reqd. as per the class H HW design sequence */
+ usleep_range(BUCK_SETTLE_TIME_US, BUCK_SETTLE_TIME_US+10);
+}
+
static void wcd9xxx_set_buck_mode(struct snd_soc_codec *codec, u8 buck_vref)
{
int i;
@@ -807,6 +830,239 @@
__func__);
}
+static void wcd9xxx_ncp_bypass_enable(struct snd_soc_codec *cdc, bool enable)
+{
+ snd_soc_update_bits(cdc, WCD9XXX_A_NCP_STATIC, 0x10, (enable << 4));
+ /* 50us sleep is reqd. as per the class H HW design sequence */
+ usleep_range(BUCK_SETTLE_TIME_US, BUCK_SETTLE_TIME_US+10);
+}
+
+static void wcd9xxx_clsh_set_Iest(struct snd_soc_codec *codec,
+ u8 value)
+{
+ snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_5,
+ 0x01, (0x01 & 0x03));
+ snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_5,
+ 0xFC, (value << 2));
+}
+
+static void wcd9xxx_clsh_state_hph_ear(struct snd_soc_codec *codec,
+ struct wcd9xxx_clsh_cdc_data *clsh_d,
+ u8 req_state, bool is_enable)
+{
+ int compute_pa = 0;
+
+ dev_dbg(codec->dev, "%s: enter %s\n", __func__,
+ is_enable ? "enable" : "disable");
+
+ if (is_enable) {
+ /*
+ * The below check condition is required to make sure
+ * functions inside if condition will execute only once.
+ */
+ if ((clsh_d->state == WCD9XXX_CLSH_STATE_EAR) ||
+ (req_state == WCD9XXX_CLSH_STATE_EAR)) {
+ wcd9xxx_dynamic_bypass_buck_ctrl(codec, false);
+ wcd9xxx_ncp_bypass_enable(codec, true);
+ }
+ switch (req_state) {
+ case WCD9XXX_CLSH_STATE_HPHL:
+ compute_pa = CLSH_COMPUTE_HPH_L;
+ break;
+ case WCD9XXX_CLSH_STATE_HPHR:
+ compute_pa = CLSH_COMPUTE_HPH_R;
+ break;
+ case WCD9XXX_CLSH_STATE_EAR:
+ compute_pa = CLSH_COMPUTE_EAR;
+ break;
+ default:
+ dev_dbg(codec->dev,
+ "%s:Invalid state:0x%x,enable:0x%x\n",
+ __func__, req_state, is_enable);
+ break;
+ }
+ wcd9xxx_clsh_comp_req(codec, clsh_d, compute_pa, true);
+
+ dev_dbg(codec->dev, "%s: Enabled hph+ear mode clsh\n",
+ __func__);
+ } else {
+ switch (req_state) {
+ case WCD9XXX_CLSH_STATE_HPHL:
+ compute_pa = CLSH_COMPUTE_HPH_L;
+ break;
+ case WCD9XXX_CLSH_STATE_HPHR:
+ compute_pa = CLSH_COMPUTE_HPH_R;
+ break;
+ case WCD9XXX_CLSH_STATE_EAR:
+ compute_pa = CLSH_COMPUTE_EAR;
+ break;
+ default:
+ dev_dbg(codec->dev,
+ "%s:Invalid state:0x%x,enable:0x%x\n",
+ __func__, req_state, is_enable);
+ break;
+ }
+ wcd9xxx_clsh_comp_req(codec, clsh_d, compute_pa, false);
+
+ if (((clsh_d->state & (~req_state)) ==
+ WCD9XXX_CLSH_STATE_EAR) ||
+ (req_state == WCD9XXX_CLSH_STATE_EAR)) {
+ wcd9xxx_ncp_bypass_enable(codec, false);
+ wcd9xxx_dynamic_bypass_buck_ctrl(codec, true);
+ }
+ }
+}
+
+static void wcd9xxx_clsh_state_hph_lo(struct snd_soc_codec *codec,
+ struct wcd9xxx_clsh_cdc_data *clsh_d,
+ u8 req_state, bool is_enable)
+{
+
+ dev_dbg(codec->dev, "%s: enter %s\n", __func__,
+ is_enable ? "enable" : "disable");
+ if (is_enable) {
+ if ((clsh_d->state == WCD9XXX_CLSH_STATE_LO) ||
+ (req_state == WCD9XXX_CLSH_STATE_LO)) {
+ wcd9xxx_dynamic_bypass_buck_ctrl(codec, false);
+ wcd9xxx_enable_buck(codec, clsh_d, true);
+ wcd9xxx_set_fclk_get_ncp(codec, clsh_d,
+ NCP_FCLK_LEVEL_8);
+ if (req_state & WCD9XXX_CLSH_STATE_HPH_ST) {
+ wcd9xxx_ncp_bypass_enable(codec, true);
+ wcd9xxx_enable_clsh_block(codec, clsh_d, true);
+ wcd9xxx_chargepump_request(codec, true);
+ wcd9xxx_enable_anc_delay(codec, true);
+ }
+ }
+ if (req_state == WCD9XXX_CLSH_STATE_HPHL)
+ wcd9xxx_clsh_comp_req(codec, clsh_d,
+ CLSH_COMPUTE_HPH_L, true);
+ if (req_state == WCD9XXX_CLSH_STATE_HPHR)
+ wcd9xxx_clsh_comp_req(codec, clsh_d,
+ CLSH_COMPUTE_HPH_R, true);
+ } else {
+ switch (req_state) {
+ case WCD9XXX_CLSH_STATE_LO:
+ snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC,
+ 0x20, 0x00);
+ wcd9xxx_dynamic_bypass_buck_ctrl(codec, true);
+ break;
+ case WCD9XXX_CLSH_STATE_HPHL:
+ wcd9xxx_clsh_comp_req(codec, clsh_d,
+ CLSH_COMPUTE_HPH_L, false);
+ break;
+ case WCD9XXX_CLSH_STATE_HPHR:
+ wcd9xxx_clsh_comp_req(codec, clsh_d,
+ CLSH_COMPUTE_HPH_R, false);
+ break;
+ default:
+ dev_dbg(codec->dev,
+ "%s:Invalid state:0x%x,enable:0x%x\n",
+ __func__, req_state, is_enable);
+ break;
+ }
+ if ((req_state == WCD9XXX_CLSH_STATE_LO) ||
+ ((clsh_d->state & (~req_state)) == WCD9XXX_CLSH_STATE_LO)) {
+ wcd9xxx_set_fclk_put_ncp(codec, clsh_d,
+ NCP_FCLK_LEVEL_8);
+ wcd9xxx_ncp_bypass_enable(codec, false);
+
+ if (req_state & WCD9XXX_CLSH_STATE_HPH_ST) {
+ usleep_range(BUCK_SETTLE_TIME_US,
+ BUCK_SETTLE_TIME_US + 10);
+ if (clsh_d->buck_mv ==
+ WCD9XXX_CDC_BUCK_MV_1P8) {
+ wcd9xxx_enable_buck(codec, clsh_d,
+ false);
+ wcd9xxx_ncp_bypass_enable(codec, true);
+ } else {
+ /*
+ *NCP settle time recommended by codec
+ *specification
+ */
+ usleep_range(NCP_SETTLE_TIME_US,
+ NCP_SETTLE_TIME_US + 10);
+ wcd9xxx_clsh_set_Iest(codec, 0x02);
+ }
+ snd_soc_update_bits(codec,
+ WCD9XXX_A_BUCK_MODE_1,
+ 0x04, 0x00);
+ snd_soc_update_bits(codec,
+ WCD9XXX_A_BUCK_MODE_4,
+ 0xFF, BUCK_VREF_1P8V);
+ }
+ }
+ }
+}
+
+static void wcd9xxx_clsh_state_ear_lo(struct snd_soc_codec *codec,
+ struct wcd9xxx_clsh_cdc_data *clsh_d,
+ u8 req_state, bool is_enable)
+{
+
+ dev_dbg(codec->dev, "%s: enter %s\n", __func__,
+ is_enable ? "enable" : "disable");
+ if (is_enable) {
+ wcd9xxx_dynamic_bypass_buck_ctrl(codec, false);
+ wcd9xxx_enable_buck(codec, clsh_d, true);
+ if (req_state & WCD9XXX_CLSH_STATE_EAR) {
+ wcd9xxx_set_fclk_get_ncp(codec, clsh_d,
+ NCP_FCLK_LEVEL_8);
+ wcd9xxx_ncp_bypass_enable(codec, true);
+ wcd9xxx_enable_clsh_block(codec, clsh_d, true);
+ wcd9xxx_chargepump_request(codec, true);
+ wcd9xxx_enable_anc_delay(codec, true);
+ wcd9xxx_clsh_comp_req(codec, clsh_d,
+ CLSH_COMPUTE_EAR, true);
+ }
+ } else {
+ wcd9xxx_set_fclk_put_ncp(codec, clsh_d, NCP_FCLK_LEVEL_8);
+ wcd9xxx_ncp_bypass_enable(codec, false);
+ if (req_state & WCD9XXX_CLSH_STATE_LO) {
+ snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC,
+ 0x20, 0x00);
+ wcd9xxx_dynamic_bypass_buck_ctrl(codec, true);
+ } else if (req_state & WCD9XXX_CLSH_STATE_EAR) {
+ wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_EAR,
+ false);
+ /*sleep 5ms*/
+ if (clsh_d->buck_mv == WCD9XXX_CDC_BUCK_MV_1P8) {
+ wcd9xxx_enable_buck(codec, clsh_d, false);
+ wcd9xxx_ncp_bypass_enable(codec, true);
+ } else {
+ /* NCP settle time recommended by codec spec */
+ usleep_range(NCP_SETTLE_TIME_US,
+ NCP_SETTLE_TIME_US + 10);
+ wcd9xxx_clsh_set_Iest(codec, 0x02);
+ }
+ snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_1,
+ 0x04, 0x00);
+ snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_4,
+ 0xFF, BUCK_VREF_1P8V);
+ }
+ }
+}
+
+static void wcd9xxx_clsh_state_hph_ear_lo(struct snd_soc_codec *codec,
+ struct wcd9xxx_clsh_cdc_data *clsh_d,
+ u8 req_state, bool is_enable)
+{
+ dev_dbg(codec->dev, "%s: enter %s\n", __func__,
+ is_enable ? "enable" : "disable");
+
+ if (req_state & WCD9XXX_CLSH_STATE_HPHL)
+ wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_L,
+ is_enable);
+
+ if (req_state & WCD9XXX_CLSH_STATE_HPHR)
+ wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_R,
+ is_enable);
+
+ if (req_state & WCD9XXX_CLSH_STATE_EAR)
+ wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_EAR,
+ is_enable);
+}
+
static void wcd9xxx_clsh_state_ear(struct snd_soc_codec *codec,
struct wcd9xxx_clsh_cdc_data *clsh_d,
u8 req_state, bool is_enable)
@@ -895,10 +1151,20 @@
pr_debug("%s: enter %s\n", __func__, is_enable ? "enable" : "disable");
if (is_enable) {
- wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_L, true);
- wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_R, true);
+ if (req_state == WCD9XXX_CLSH_STATE_HPHL)
+ wcd9xxx_clsh_comp_req(codec, clsh_d,
+ CLSH_COMPUTE_HPH_L, true);
+ if (req_state == WCD9XXX_CLSH_STATE_HPHR)
+ wcd9xxx_clsh_comp_req(codec, clsh_d,
+ CLSH_COMPUTE_HPH_R, true);
} else {
dev_dbg(codec->dev, "%s: stub fallback to hph_st\n", __func__);
+ if (req_state == WCD9XXX_CLSH_STATE_HPHL)
+ wcd9xxx_clsh_comp_req(codec, clsh_d,
+ CLSH_COMPUTE_HPH_L, false);
+ if (req_state == WCD9XXX_CLSH_STATE_HPHR)
+ wcd9xxx_clsh_comp_req(codec, clsh_d,
+ CLSH_COMPUTE_HPH_R, false);
}
}
@@ -952,6 +1218,47 @@
WARN_ON(1);
}
+/*
+ * Function: wcd9xxx_clsh_is_state_valid
+ * Params: state
+ * Description:
+ * Provides information on valid states of Class H configuration
+ */
+static int wcd9xxx_clsh_is_state_valid(u8 state)
+{
+ switch (state) {
+ case WCD9XXX_CLSH_STATE_IDLE:
+ case WCD9XXX_CLSH_STATE_EAR:
+ case WCD9XXX_CLSH_STATE_HPHL:
+ case WCD9XXX_CLSH_STATE_HPHR:
+ case WCD9XXX_CLSH_STATE_HPH_ST:
+ case WCD9XXX_CLSH_STATE_LO:
+ case WCD9XXX_CLSH_STATE_HPHL_EAR:
+ case WCD9XXX_CLSH_STATE_HPHR_EAR:
+ case WCD9XXX_CLSH_STATE_HPH_ST_EAR:
+ case WCD9XXX_CLSH_STATE_HPHL_LO:
+ case WCD9XXX_CLSH_STATE_HPHR_LO:
+ case WCD9XXX_CLSH_STATE_HPH_ST_LO:
+ case WCD9XXX_CLSH_STATE_EAR_LO:
+ case WCD9XXX_CLSH_STATE_HPHL_EAR_LO:
+ case WCD9XXX_CLSH_STATE_HPHR_EAR_LO:
+ case WCD9XXX_CLSH_STATE_HPH_ST_EAR_LO:
+ return 1;
+ default:
+ break;
+ }
+ return 0;
+}
+
+/*
+ * Function: wcd9xxx_clsh_fsm
+ * Params: codec, cdc_clsh_d, req_state, req_type, clsh_event
+ * Description:
+ * This function handles PRE DAC and POST DAC conditions of different devices
+ * and updates class H configuration of different combination of devices
+ * based on validity of their states. cdc_clsh_d will contain current
+ * class h state information
+ */
void wcd9xxx_clsh_fsm(struct snd_soc_codec *codec,
struct wcd9xxx_clsh_cdc_data *cdc_clsh_d,
u8 req_state, bool req_type, u8 clsh_event)
@@ -967,10 +1274,25 @@
old_state = cdc_clsh_d->state;
new_state = old_state | req_state;
- (*clsh_state_fp[req_state]) (codec, cdc_clsh_d, req_state,
+ if (!wcd9xxx_clsh_is_state_valid(new_state)) {
+ dev_dbg(codec->dev,
+ "%s: classH not a valid new state: %s\n",
+ __func__,
+ state_to_str(new_state, msg0, sizeof(msg0)));
+ return;
+ }
+ if (new_state == old_state) {
+ dev_dbg(codec->dev,
+ "%s: classH already in requested state: %s\n",
+ __func__,
+ state_to_str(new_state, msg0, sizeof(msg0)));
+ return;
+ }
+ (*clsh_state_fp[new_state]) (codec, cdc_clsh_d, req_state,
req_type);
cdc_clsh_d->state = new_state;
- dev_dbg(codec->dev, "%s: ClassH state transition from %s to %s\n",
+ dev_dbg(codec->dev,
+ "%s: ClassH state transition from %s to %s\n",
__func__, state_to_str(old_state, msg0, sizeof(msg0)),
state_to_str(cdc_clsh_d->state, msg1, sizeof(msg1)));
@@ -981,7 +1303,23 @@
new_state = old_state & (~req_state);
if (new_state < NUM_CLSH_STATES) {
- (*clsh_state_fp[req_state]) (codec, cdc_clsh_d,
+ if (!wcd9xxx_clsh_is_state_valid(old_state)) {
+ dev_dbg(codec->dev,
+ "%s:Invalid old state:%s\n",
+ __func__,
+ state_to_str(old_state, msg0,
+ sizeof(msg0)));
+ return;
+ }
+ if (new_state == old_state) {
+ dev_dbg(codec->dev,
+ "%s: clsH already in old state: %s\n",
+ __func__,
+ state_to_str(new_state, msg0,
+ sizeof(msg0)));
+ return;
+ }
+ (*clsh_state_fp[old_state]) (codec, cdc_clsh_d,
req_state,
req_type);
cdc_clsh_d->state = new_state;
@@ -992,7 +1330,7 @@
sizeof(msg1)));
} else {
- dev_dbg(codec->dev, "%s: wrong new state = %x\n",
+ dev_dbg(codec->dev, "%s:wrong new state=0x%x\n",
__func__, new_state);
}
} else if (!(cdc_clsh_d->state & WCD9XXX_CLSH_STATE_LO)) {
@@ -1023,6 +1361,23 @@
clsh_state_fp[WCD9XXX_CLSH_STATE_HPH_ST] =
wcd9xxx_clsh_state_hph_st;
clsh_state_fp[WCD9XXX_CLSH_STATE_LO] = wcd9xxx_clsh_state_lo;
+ clsh_state_fp[WCD9XXX_CLSH_STATE_HPHL_EAR] =
+ wcd9xxx_clsh_state_hph_ear;
+ clsh_state_fp[WCD9XXX_CLSH_STATE_HPHR_EAR] =
+ wcd9xxx_clsh_state_hph_ear;
+ clsh_state_fp[WCD9XXX_CLSH_STATE_HPH_ST_EAR] =
+ wcd9xxx_clsh_state_hph_ear;
+ clsh_state_fp[WCD9XXX_CLSH_STATE_HPHL_LO] = wcd9xxx_clsh_state_hph_lo;
+ clsh_state_fp[WCD9XXX_CLSH_STATE_HPHR_LO] = wcd9xxx_clsh_state_hph_lo;
+ clsh_state_fp[WCD9XXX_CLSH_STATE_HPH_ST_LO] =
+ wcd9xxx_clsh_state_hph_lo;
+ clsh_state_fp[WCD9XXX_CLSH_STATE_EAR_LO] = wcd9xxx_clsh_state_ear_lo;
+ clsh_state_fp[WCD9XXX_CLSH_STATE_HPHL_EAR_LO] =
+ wcd9xxx_clsh_state_hph_ear_lo;
+ clsh_state_fp[WCD9XXX_CLSH_STATE_HPHR_EAR_LO] =
+ wcd9xxx_clsh_state_hph_ear_lo;
+ clsh_state_fp[WCD9XXX_CLSH_STATE_HPH_ST_EAR_LO] =
+ wcd9xxx_clsh_state_hph_ear_lo;
}
EXPORT_SYMBOL_GPL(wcd9xxx_clsh_init);
diff --git a/sound/soc/codecs/wcd9xxx-common.h b/sound/soc/codecs/wcd9xxx-common.h
index 324f6e9..13f91ed 100644
--- a/sound/soc/codecs/wcd9xxx-common.h
+++ b/sound/soc/codecs/wcd9xxx-common.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -35,7 +35,7 @@
#define WCD9XXX_CLSH_STATE_HPHL (0x01 << 1)
#define WCD9XXX_CLSH_STATE_HPHR (0x01 << 2)
#define WCD9XXX_CLSH_STATE_LO (0x01 << 3)
-#define NUM_CLSH_STATES ((0x01 << 4) - 1)
+#define NUM_CLSH_STATES (0x01 << 4)
#define WCD9XXX_DMIC_SAMPLE_RATE_DIV_2 0x0
#define WCD9XXX_DMIC_SAMPLE_RATE_DIV_3 0x1
@@ -56,6 +56,34 @@
#define WCD9XXX_CLSH_STATE_HPH_ST (WCD9XXX_CLSH_STATE_HPHL | \
WCD9XXX_CLSH_STATE_HPHR)
+#define WCD9XXX_CLSH_STATE_HPHL_EAR (WCD9XXX_CLSH_STATE_HPHL | \
+ WCD9XXX_CLSH_STATE_EAR)
+#define WCD9XXX_CLSH_STATE_HPHR_EAR (WCD9XXX_CLSH_STATE_HPHR | \
+ WCD9XXX_CLSH_STATE_EAR)
+
+#define WCD9XXX_CLSH_STATE_HPH_ST_EAR (WCD9XXX_CLSH_STATE_HPH_ST | \
+ WCD9XXX_CLSH_STATE_EAR)
+
+#define WCD9XXX_CLSH_STATE_HPHL_LO (WCD9XXX_CLSH_STATE_HPHL | \
+ WCD9XXX_CLSH_STATE_LO)
+#define WCD9XXX_CLSH_STATE_HPHR_LO (WCD9XXX_CLSH_STATE_HPHR | \
+ WCD9XXX_CLSH_STATE_LO)
+
+#define WCD9XXX_CLSH_STATE_HPH_ST_LO (WCD9XXX_CLSH_STATE_HPH_ST | \
+ WCD9XXX_CLSH_STATE_LO)
+
+#define WCD9XXX_CLSH_STATE_EAR_LO (WCD9XXX_CLSH_STATE_EAR | \
+ WCD9XXX_CLSH_STATE_LO)
+
+#define WCD9XXX_CLSH_STATE_HPHL_EAR_LO (WCD9XXX_CLSH_STATE_HPHL | \
+ WCD9XXX_CLSH_STATE_EAR | \
+ WCD9XXX_CLSH_STATE_LO)
+#define WCD9XXX_CLSH_STATE_HPHR_EAR_LO (WCD9XXX_CLSH_STATE_HPHR | \
+ WCD9XXX_CLSH_STATE_EAR | \
+ WCD9XXX_CLSH_STATE_LO)
+#define WCD9XXX_CLSH_STATE_HPH_ST_EAR_LO (WCD9XXX_CLSH_STATE_HPH_ST | \
+ WCD9XXX_CLSH_STATE_EAR | \
+ WCD9XXX_CLSH_STATE_LO)
struct wcd9xxx_reg_mask_val {
u16 reg;
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index ca5e217..9c01a08 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -2397,6 +2397,21 @@
.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
.ops = &msm8974_slimbus_2_be_ops,
},
+ {
+ .name = "MSM8974 Media9",
+ .stream_name = "MultiMedia9",
+ .cpu_dai_name = "MultiMedia9",
+ .platform_name = "msm-pcm-dsp.0",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA9,
+ },
/* Backend BT/FM DAI Links */
{
.name = LPASS_BE_INT_BT_SCO_RX,
@@ -2688,6 +2703,19 @@
.be_hw_params_fixup = msm_be_hw_params_fixup,
.ignore_suspend = 1,
},
+ /* Incall Music 2 BACK END DAI Link */
+ {
+ .name = LPASS_BE_VOICE2_PLAYBACK_TX,
+ .stream_name = "Voice2 Farend Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.32770",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_VOICE2_PLAYBACK_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ }
};
static struct snd_soc_dai_link msm8974_hdmi_dai_link[] = {
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index 8e69a2b..157d63a 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -725,9 +725,9 @@
if (voc_get_route_flag(session_id, RX_PATH) &&
voc_get_route_flag(session_id, TX_PATH))
- voc_enable_cvp(session_id);
+ voc_enable_device(session_id);
} else {
- voc_disable_cvp(session_id);
+ voc_disable_device(session_id);
}
} else {
voc_set_route_flag(session_id, TX_PATH, set);
@@ -736,9 +736,9 @@
msm_bedais[reg].port_id, DEV_TX);
if (voc_get_route_flag(session_id, RX_PATH) &&
voc_get_route_flag(session_id, TX_PATH))
- voc_enable_cvp(session_id);
+ voc_enable_device(session_id);
} else {
- voc_disable_cvp(session_id);
+ voc_disable_device(session_id);
}
}
}
@@ -3865,6 +3865,8 @@
{"VOC_EXT_EC MUX", "TERT_MI2S_TX" , "TERT_MI2S_TX"},
{"VOC_EXT_EC MUX", "QUAT_MI2S_TX" , "QUAT_MI2S_TX"},
{"CS-VOICE_UL1", NULL, "VOC_EXT_EC MUX"},
+ {"VOIP_UL", NULL, "VOC_EXT_EC MUX"},
+ {"VoLTE_UL", NULL, "VOC_EXT_EC MUX"},
{"Voice_Tx Mixer", "PRI_TX_Voice", "PRI_I2S_TX"},
{"Voice_Tx Mixer", "PRI_MI2S_TX_Voice", "PRI_MI2S_TX"},
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c
index fac5845..c54d03c 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c
@@ -405,12 +405,37 @@
pr_debug("%s: mute=%d session_id=%#x ramp_duration=%d\n", __func__,
mute, session_id, ramp_duration);
- voc_set_tx_mute(session_id, TX_PATH, mute, ramp_duration);
+ ret = voc_set_tx_mute(session_id, TX_PATH, mute, ramp_duration);
done:
return ret;
}
+static int msm_voice_tx_device_mute_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ret = 0;
+ int mute = ucontrol->value.integer.value[0];
+ uint32_t session_id = ucontrol->value.integer.value[1];
+ int ramp_duration = ucontrol->value.integer.value[2];
+
+ if ((mute < 0) || (mute > 1) || (ramp_duration < 0) ||
+ (ramp_duration > MAX_RAMP_DURATION)) {
+ pr_err(" %s Invalid arguments", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ pr_debug("%s: mute=%d session_id=%#x ramp_duration=%d\n", __func__,
+ mute, session_id, ramp_duration);
+
+ ret = voc_set_device_mute(session_id, VSS_IVOLUME_DIRECTION_TX,
+ mute, ramp_duration);
+
+done:
+ return ret;
+}
static int msm_voice_rx_device_mute_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
@@ -420,8 +445,8 @@
uint32_t session_id = ucontrol->value.integer.value[1];
int ramp_duration = ucontrol->value.integer.value[2];
- if ((mute < 0) || (mute > 1) || (ramp_duration < 0)
- || (ramp_duration > MAX_RAMP_DURATION)) {
+ if ((mute < 0) || (mute > 1) || (ramp_duration < 0) ||
+ (ramp_duration > MAX_RAMP_DURATION)) {
pr_err(" %s Invalid arguments", __func__);
ret = -EINVAL;
@@ -429,9 +454,10 @@
}
pr_debug("%s: mute=%d session_id=%#x ramp_duration=%d\n", __func__,
- mute, session_id, ramp_duration);
+ mute, session_id, ramp_duration);
- voc_set_rx_device_mute(session_id, mute, ramp_duration);
+ voc_set_device_mute(session_id, VSS_IVOLUME_DIRECTION_RX,
+ mute, ramp_duration);
done:
return ret;
@@ -485,6 +511,8 @@
static struct snd_kcontrol_new msm_voice_controls[] = {
SOC_SINGLE_MULTI_EXT("Voice Rx Device Mute", SND_SOC_NOPM, 0, VSID_MAX,
0, 3, NULL, msm_voice_rx_device_mute_put),
+ SOC_SINGLE_MULTI_EXT("Voice Tx Device Mute", SND_SOC_NOPM, 0, VSID_MAX,
+ 0, 3, NULL, msm_voice_tx_device_mute_put),
SOC_SINGLE_MULTI_EXT("Voice Tx Mute", SND_SOC_NOPM, 0, VSID_MAX,
0, 3, NULL, msm_voice_mute_put),
SOC_SINGLE_MULTI_EXT("Voice Rx Gain", SND_SOC_NOPM, 0, VSID_MAX, 0, 3,
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index badc3c3..0d19657 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -393,60 +393,52 @@
struct list_head *ptr, *next;
int result;
int size = 4096;
+
+ if (!set_custom_topology)
+ return;
+
get_asm_custom_topology(&cal_block);
if (cal_block.cal_size == 0) {
- pr_debug("%s: no cal to send addr= 0x%x\n",
- __func__, cal_block.cal_paddr);
- goto done;
+ pr_debug("%s: no cal to send addr= 0x%pa\n",
+ __func__, &cal_block.cal_paddr);
+ return;
}
- if (set_custom_topology) {
- if (common_client.mmap_apr == NULL) {
- common_client.mmap_apr = q6asm_mmap_apr_reg();
- common_client.apr = common_client.mmap_apr;
- if (common_client.mmap_apr == NULL) {
- pr_err("%s: q6asm_mmap_apr_reg failed\n",
- __func__);
- result = -EPERM;
- goto done;
- }
- }
- /* Only call this once */
- set_custom_topology = 0;
+ common_client.mmap_apr = q6asm_mmap_apr_reg();
+ common_client.apr = common_client.mmap_apr;
+ if (common_client.mmap_apr == NULL) {
+ pr_err("%s: q6asm_mmap_apr_reg failed\n",
+ __func__);
+ result = -EPERM;
+ goto mmap_fail;
+ }
+ /* Only call this once */
+ set_custom_topology = 0;
- /* Use first asm buf to map memory */
- if (common_client.port[IN].buf == NULL) {
- pr_err("%s: common buf is NULL\n",
- __func__);
- goto done;
- }
- common_client.port[IN].buf->phys = cal_block.cal_paddr;
+ /* Use first asm buf to map memory */
+ if (common_client.port[IN].buf == NULL) {
+ pr_err("%s: common buf is NULL\n",
+ __func__);
+ goto err_map;
+ }
+ common_client.port[IN].buf->phys = cal_block.cal_paddr;
- result = q6asm_memory_map_regions(&common_client,
- IN, size, 1, 1);
- if (result < 0) {
- pr_err("%s: mmap did not work! addr = 0x%x, size = %d\n",
- __func__, cal_block.cal_paddr,
- cal_block.cal_size);
- goto done;
- }
+ result = q6asm_memory_map_regions(&common_client,
+ IN, size, 1, 1);
+ if (result < 0) {
+ pr_err("%s: mmap did not work! addr = 0x%pa, size = %zd\n",
+ __func__, &cal_block.cal_paddr,
+ cal_block.cal_size);
+ goto err_map;
+ }
- list_for_each_safe(ptr, next,
- &common_client.port[IN].mem_map_handle) {
- buf_node = list_entry(ptr, struct asm_buffer_node,
- list);
- if (buf_node->buf_addr_lsw == cal_block.cal_paddr) {
- topology_map_handle = buf_node->mmap_hdl;
- break;
- }
- }
-
- result = q6asm_mmap_apr_dereg();
- if (result < 0) {
- pr_err("%s: q6asm_mmap_apr_dereg failed, err %d\n",
- __func__, result);
- } else {
- common_client.mmap_apr = NULL;
+ list_for_each_safe(ptr, next,
+ &common_client.port[IN].mem_map_handle) {
+ buf_node = list_entry(ptr, struct asm_buffer_node,
+ list);
+ if (buf_node->buf_addr_lsw == cal_block.cal_paddr) {
+ topology_map_handle = buf_node->mmap_hdl;
+ break;
}
}
@@ -468,7 +460,7 @@
if (result < 0) {
pr_err("%s: Set topologies failed payload = 0x%x\n",
__func__, cal_block.cal_paddr);
- goto done;
+ goto err_unmap;
}
result = wait_event_timeout(ac->cmd_wait,
@@ -476,10 +468,15 @@
if (!result) {
pr_err("%s: Set topologies failed after timedout payload = 0x%x\n",
__func__, cal_block.cal_paddr);
- goto done;
+ goto err_unmap;
}
-
-done:
+ return;
+err_unmap:
+ q6asm_memory_unmap_regions(ac, IN);
+err_map:
+ q6asm_mmap_apr_dereg();
+ set_custom_topology = 1;
+mmap_fail:
return;
}
@@ -768,6 +765,7 @@
apr_deregister(ac->apr);
ac->apr = NULL;
ac->mmap_apr = NULL;
+ rtac_set_asm_handle(ac->session, ac->apr);
q6asm_session_free(ac);
q6asm_mmap_apr_dereg();
@@ -857,7 +855,7 @@
if (ac->apr == NULL) {
pr_err("%s Registration with APR failed\n", __func__);
mutex_unlock(&session_lock);
- goto fail;
+ goto fail_apr1;
}
ac->apr2 = apr_register("ADSP", "ASM", \
(apr_fn)q6asm_callback,\
@@ -867,16 +865,17 @@
if (ac->apr2 == NULL) {
pr_err("%s Registration with APR-2 failed\n", __func__);
mutex_unlock(&session_lock);
- goto fail;
+ goto fail_apr2;
}
+
rtac_set_asm_handle(n, ac->apr);
pr_debug("%s Registering the common port with APR\n", __func__);
ac->mmap_apr = q6asm_mmap_apr_reg();
if (ac->mmap_apr == NULL) {
mutex_unlock(&session_lock);
- goto fail;
- }
+ goto fail_mmap;
+ }
init_waitqueue_head(&ac->cmd_wait);
init_waitqueue_head(&ac->time_wait);
@@ -899,9 +898,12 @@
mutex_unlock(&session_lock);
return ac;
-fail:
- q6asm_audio_client_free(ac);
- return NULL;
+fail_mmap:
+ apr_deregister(ac->apr2);
+fail_apr2:
+ apr_deregister(ac->apr);
+fail_apr1:
+ q6asm_session_free(ac);
fail_session:
kfree(ac);
return NULL;
@@ -1115,12 +1117,20 @@
payload = data->payload;
if (data->opcode == RESET_EVENTS) {
+ struct audio_client *ac_mmap = (struct audio_client *)priv;
+ if (ac_mmap == NULL) {
+ pr_err("%s ac or priv NULL\n", __func__);
+ return -EINVAL;
+ }
pr_debug("%s: Reset event is received: %d %d apr[%p]\n",
__func__,
data->reset_event,
data->reset_proc,
this_mmap.apr);
+ atomic_set(&this_mmap.ref_cnt, 0);
apr_reset(this_mmap.apr);
+ this_mmap.apr = NULL;
+ ac_mmap->mmap_apr = NULL;
for (; i <= OUT; i++) {
list_for_each_safe(ptr, next,
&common_client.port[i].mem_map_handle) {
@@ -1135,7 +1145,6 @@
}
pr_debug("%s:Clearing custom topology\n", __func__);
}
- this_mmap.apr = NULL;
reset_custom_topology_flags();
set_custom_topology = 1;
topology_map_handle = 0;
@@ -3748,6 +3757,11 @@
mutex_lock(&port->lock);
dsp_buf = port->dsp_buf;
+ if (port->buf == NULL) {
+ pr_err("%s buf is NULL\n", __func__);
+ mutex_unlock(&port->lock);
+ return -EINVAL;
+ }
ab = &port->buf[dsp_buf];
pr_debug("%s:session[%d]dsp-buf[%d][%p]cpu_buf[%d][%p]\n",
diff --git a/sound/soc/msm/qdsp6v2/q6voice.c b/sound/soc/msm/qdsp6v2/q6voice.c
index ac8b018..1ca9b1a 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.c
+++ b/sound/soc/msm/qdsp6v2/q6voice.c
@@ -94,6 +94,8 @@
static int voice_alloc_oob_mem_table(void);
static int voice_alloc_and_map_cal_mem(struct voice_data *v);
static int voice_alloc_and_map_oob_mem(struct voice_data *v);
+static int voc_disable_cvp(uint32_t session_id);
+static int voc_enable_cvp(uint32_t session_id);
static struct voice_data *voice_get_session_by_idx(int idx);
@@ -1081,39 +1083,37 @@
}
mvm_handle = voice_get_mvm_handle(v);
- if (v->tty_mode) {
- /* send tty mode cmd to mvm */
- mvm_tty_mode_cmd.hdr.hdr_field = APR_HDR_FIELD(
- APR_MSG_TYPE_SEQ_CMD,
- APR_HDR_LEN(APR_HDR_SIZE),
- APR_PKT_VER);
- mvm_tty_mode_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
- sizeof(mvm_tty_mode_cmd) -
- APR_HDR_SIZE);
- pr_debug("%s: pkt size = %d\n",
- __func__, mvm_tty_mode_cmd.hdr.pkt_size);
- mvm_tty_mode_cmd.hdr.src_port =
- voice_get_idx_for_session(v->session_id);
- mvm_tty_mode_cmd.hdr.dest_port = mvm_handle;
- mvm_tty_mode_cmd.hdr.token = 0;
- mvm_tty_mode_cmd.hdr.opcode = VSS_ISTREAM_CMD_SET_TTY_MODE;
- mvm_tty_mode_cmd.tty_mode.mode = v->tty_mode;
- pr_debug("tty mode =%d\n", mvm_tty_mode_cmd.tty_mode.mode);
+ /* send tty mode cmd to mvm */
+ mvm_tty_mode_cmd.hdr.hdr_field = APR_HDR_FIELD(
+ APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ mvm_tty_mode_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(mvm_tty_mode_cmd) -
+ APR_HDR_SIZE);
+ pr_debug("%s: pkt size = %d\n",
+ __func__, mvm_tty_mode_cmd.hdr.pkt_size);
+ mvm_tty_mode_cmd.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
+ mvm_tty_mode_cmd.hdr.dest_port = mvm_handle;
+ mvm_tty_mode_cmd.hdr.token = 0;
+ mvm_tty_mode_cmd.hdr.opcode = VSS_ISTREAM_CMD_SET_TTY_MODE;
+ mvm_tty_mode_cmd.tty_mode.mode = v->tty_mode;
+ pr_debug("tty mode =%d\n", mvm_tty_mode_cmd.tty_mode.mode);
- v->mvm_state = CMD_STATUS_FAIL;
- ret = apr_send_pkt(apr_mvm, (uint32_t *) &mvm_tty_mode_cmd);
- if (ret < 0) {
- pr_err("%s: Error %d sending SET_TTY_MODE\n",
- __func__, ret);
- goto fail;
- }
- ret = wait_event_timeout(v->mvm_wait,
- (v->mvm_state == CMD_STATUS_SUCCESS),
- msecs_to_jiffies(TIMEOUT_MS));
- if (!ret) {
- pr_err("%s: wait_event timeout\n", __func__);
- goto fail;
- }
+ v->mvm_state = CMD_STATUS_FAIL;
+ ret = apr_send_pkt(apr_mvm, (uint32_t *) &mvm_tty_mode_cmd);
+ if (ret < 0) {
+ pr_err("%s: Error %d sending SET_TTY_MODE\n",
+ __func__, ret);
+ goto fail;
+ }
+ ret = wait_event_timeout(v->mvm_wait,
+ (v->mvm_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ goto fail;
}
return 0;
fail:
@@ -3166,8 +3166,7 @@
voice_send_netid_timing_cmd(v);
}
- /* enable slowtalk if st_enable is set */
- if (v->st_enable)
+ if (v->st_enable && !v->tty_mode)
voice_send_set_pp_enable_cmd(v,
MODULE_ID_VOICE_MODULE_ST,
v->st_enable);
@@ -4379,7 +4378,7 @@
return ret;
}
-int voc_disable_cvp(uint32_t session_id)
+static int voc_disable_cvp(uint32_t session_id)
{
struct voice_data *v = voice_get_session(session_id);
int ret = 0;
@@ -4414,7 +4413,7 @@
return ret;
}
-int voc_enable_cvp(uint32_t session_id)
+static int voc_enable_cvp(uint32_t session_id)
{
struct voice_data *v = voice_get_session(session_id);
int ret = 0;
@@ -4486,10 +4485,8 @@
goto fail;
}
- /* Send tty mode if tty device is used */
voice_send_tty_mode_cmd(v);
- /* enable slowtalk */
- if (v->st_enable)
+ if (v->st_enable && !v->tty_mode)
voice_send_set_pp_enable_cmd(v,
MODULE_ID_VOICE_MODULE_ST,
v->st_enable);
@@ -4570,8 +4567,8 @@
return ret;
}
-int voc_set_rx_device_mute(uint32_t session_id, uint32_t mute,
- uint32_t ramp_duration)
+int voc_set_device_mute(uint32_t session_id, uint32_t dir, uint32_t mute,
+ uint32_t ramp_duration)
{
struct voice_data *v = NULL;
int ret = 0;
@@ -4581,16 +4578,23 @@
while (voice_itr_get_next_session(&itr, &v)) {
if (v != NULL) {
mutex_lock(&v->lock);
- v->dev_rx.dev_mute = mute;
- v->dev_rx.dev_mute_ramp_duration_ms =
+ if (dir == VSS_IVOLUME_DIRECTION_TX) {
+ v->dev_tx.dev_mute = mute;
+ v->dev_tx.dev_mute_ramp_duration_ms =
ramp_duration;
+ } else {
+ v->dev_rx.dev_mute = mute;
+ v->dev_rx.dev_mute_ramp_duration_ms =
+ ramp_duration;
+ }
+
if (((v->voc_state == VOC_RUN) ||
(v->voc_state == VOC_STANDBY)) &&
(v->lch_mode == 0))
ret = voice_send_device_mute_cmd(v,
- VSS_IVOLUME_DIRECTION_RX,
- v->dev_rx.dev_mute,
- ramp_duration);
+ dir,
+ mute,
+ ramp_duration);
mutex_unlock(&v->lock);
} else {
pr_err("%s: invalid session_id 0x%x\n", __func__,
@@ -4682,8 +4686,8 @@
v->st_enable = enable;
if (v->voc_state == VOC_RUN) {
- if (module_id ==
- MODULE_ID_VOICE_MODULE_ST)
+ if ((module_id == MODULE_ID_VOICE_MODULE_ST) &&
+ (!v->tty_mode))
ret = voice_send_set_pp_enable_cmd(v,
MODULE_ID_VOICE_MODULE_ST,
enable);
@@ -4906,6 +4910,110 @@
return ret;
}
+int voc_disable_device(uint32_t session_id)
+{
+ struct voice_data *v = voice_get_session(session_id);
+ int ret = 0;
+
+ pr_debug("%s: voc state=%d\n", __func__, v->voc_state);
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ mutex_lock(&v->lock);
+ if (v->voc_state == VOC_RUN) {
+ ret = voice_pause_voice_call(v);
+ if (ret < 0) {
+ pr_err("%s: Pause Voice Call failed for session 0x%x, err %d!\n",
+ __func__, v->session_id, ret);
+ goto done;
+ }
+ rtac_remove_voice(voice_get_cvs_handle(v));
+ voice_send_cvp_deregister_vol_cal_cmd(v);
+ voice_send_cvp_deregister_cal_cmd(v);
+ voice_send_cvp_deregister_dev_cfg_cmd(v);
+
+ v->voc_state = VOC_CHANGE;
+ } else {
+ pr_debug("%s: called in voc state=%d, No_OP\n",
+ __func__, v->voc_state);
+ }
+
+ if (common.ec_ref_ext)
+ voc_set_ext_ec_ref(AFE_PORT_INVALID, false);
+done:
+ mutex_unlock(&v->lock);
+
+ return ret;
+}
+
+int voc_enable_device(uint32_t session_id)
+{
+ struct voice_data *v = voice_get_session(session_id);
+ int ret = 0;
+
+ pr_debug("%s: voc state=%d\n", __func__, v->voc_state);
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ mutex_lock(&v->lock);
+ if (v->voc_state == VOC_CHANGE) {
+ ret = voice_send_tty_mode_cmd(v);
+ if (ret < 0) {
+ pr_err("%s: Sending TTY mode failed, ret=%d\n",
+ __func__, ret);
+ /* Not a critical error, allow voice call to continue */
+ }
+
+ if (v->tty_mode) {
+ /* disable slowtalk */
+ voice_send_set_pp_enable_cmd(v,
+ MODULE_ID_VOICE_MODULE_ST,
+ 0);
+ } else {
+ /* restore slowtalk */
+ voice_send_set_pp_enable_cmd(v,
+ MODULE_ID_VOICE_MODULE_ST,
+ v->st_enable);
+ }
+
+ ret = voice_send_set_device_cmd(v);
+ if (ret < 0) {
+ pr_err("%s: Set device failed, ret=%d\n",
+ __func__, ret);
+ goto done;
+ }
+
+ voice_send_cvp_register_dev_cfg_cmd(v);
+ voice_send_cvp_register_cal_cmd(v);
+ voice_send_cvp_register_vol_cal_cmd(v);
+
+ rtac_add_voice(voice_get_cvs_handle(v),
+ voice_get_cvp_handle(v),
+ v->dev_rx.port_id, v->dev_tx.port_id,
+ v->session_id);
+
+ ret = voice_send_start_voice_cmd(v);
+ if (ret < 0) {
+ pr_err("%s: Fail in sending START_VOICE, ret=%d\n",
+ __func__, ret);
+ goto done;
+ }
+ v->voc_state = VOC_RUN;
+ } else {
+ pr_debug("%s: called in voc state=%d, No_OP\n",
+ __func__, v->voc_state);
+ }
+
+done:
+ mutex_unlock(&v->lock);
+
+ return ret;
+}
+
int voc_set_lch(uint32_t session_id, enum voice_lch_mode lch_mode)
{
struct voice_data *v = voice_get_session(session_id);
diff --git a/sound/soc/msm/qdsp6v2/q6voice.h b/sound/soc/msm/qdsp6v2/q6voice.h
index 59c86cd..c6f3482 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.h
+++ b/sound/soc/msm/qdsp6v2/q6voice.h
@@ -1444,11 +1444,9 @@
uint32_t ramp_duration);
int voc_set_tx_mute(uint32_t session_id, uint32_t dir, uint32_t mute,
uint32_t ramp_duration);
-int voc_set_rx_device_mute(uint32_t session_id, uint32_t mute,
- uint32_t ramp_duration);
+int voc_set_device_mute(uint32_t session_id, uint32_t dir, uint32_t mute,
+ uint32_t ramp_duration);
int voc_get_rx_device_mute(uint32_t session_id);
-int voc_disable_cvp(uint32_t session_id);
-int voc_enable_cvp(uint32_t session_id);
int voc_set_route_flag(uint32_t session_id, uint8_t path_dir, uint8_t set);
uint8_t voc_get_route_flag(uint32_t session_id, uint8_t path_dir);
int voc_enable_dtmf_rx_detection(uint32_t session_id, uint32_t enable);
@@ -1470,5 +1468,7 @@
int voice_get_idx_for_session(u32 session_id);
int voc_set_ext_ec_ref(uint16_t port_id, bool state);
int voc_update_amr_vocoder_rate(uint32_t session_id);
+int voc_disable_device(uint32_t session_id);
+int voc_enable_device(uint32_t session_id);
#endif