Merge "ARM: dts: msm: Add pm-qos-latency to GPU dtsi"
diff --git a/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt b/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt
index 1b881f0..aa24dc6 100644
--- a/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt
+++ b/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt
@@ -203,21 +203,6 @@
- qcom,cpr-uplift-speed-bin: The speed bin value corresponding to one type of processor which needs to apply the
pvs voltage uplift workaround.
This is required if cpr-fuse-uplift-disable-sel is present.
-- qcom,cpr-quot-adjust-table: Array of triples in which each triple indicates the speed bin of the CPU, the virtual
- corner to use and the quotient adjustment.
- The 3 elements in one triple are:
- [0]: => the speed bin of the CPU.
- [1]: => the virtual voltage corner to use.
- [2]: => the quotient adjustment for the corresponding virtual corner.
- If the speed bin in a triple is equal to the speed bin of the CPU, the adjustment would
- be subtracted from the quotient value of the voltage corner when the CPU is running at
- that virtual corner. Each virtual corner value must be in the range 1 to the number of
- elements in qcom,cpr-corner-map.
-- qcom,cpr-corner-map: Array of elements of fuse corner value for each virtual corner.
- The location or 1-based index of an element in the list corresponds to
- the virtual corner value. For example, the first element in the list is the fuse corner
- value that virtual corner 1 maps to.
- This is required if qcom,cpr-quot-adjust-table is present.
- qcom,cpr-quotient-adjustment: Array of three elements of CPR quotient adjustments for each corner.
The 3 quotient adjustments with index[0..2] are:
[0] => amount to add to the SVS quotient
@@ -230,6 +215,42 @@
Not Present: No such regulator.
- vdd-apc-optional-sec-supply: Present: Regulator of second highest priority to supply VDD APC power.
Not Present: No such regulator.
+- qcom,cpr-speed-bin-max-corners: Array of quintuples in which each quintuple maps a CPU speed bin and PVS version to
+ the maximum virtual voltage corner corresponding to the SVS, NORMAL and TURBO corners.
+ The 5 elements in one quintuple are:
+ [0]: => the speed bin of the CPU.
+ [1]: => the PVS version of the CPU.
+ [2]: => the max virtual voltage corner value corresponding to SVS corner for this speed bin.
+ [3]: => the max virtual voltage corner value corresponding to NORMAL corner for this speed bin.
+ [4]: => the max virtual voltage corner value corresponding to TURBO corner for this speed bin.
+ No CPR target quotient scaling is applied on chips which have a speed bin + PVS version
+ pair that does not appear in one of the quintuples in this property. If the property is
+ specified, then quotient scaling is enabled for the TURBO corner. If this property is
+ not specified, then no quotient scaling can take place.
+- qcom,cpr-corner-map: Array of elements of fuse corner value for each virtual corner.
+ The location or 1-based index of an element in the list corresponds to
+ the virtual corner value. For example, the first element in the list is the fuse corner
+ value that virtual corner 1 maps to.
+ This property is required if qcom,cpr-speed-bin-max-corners is present.
+- qcom,cpr-corner-frequency-map: Array of tuples in which a tuple describes a corner to application processor frequency
+ mapping.
+ The 2 elements in one tuple are:
+ [0]: => a virtual voltage corner.
+ [1]: => the application processor frequency in Hz corresponding to the virtual corner.
+ This property is required if qcom,cpr-speed-bin-max-corners is present.
+- qcom,pvs-version-fuse-sel: Array of 4 elements to indicate where to read the pvs version of the processor,
+ and the fuse reading method.
+ The 4 elements with index[0..3] are:
+ [0]: => the fuse row number of the selector;
+ [1]: => LSB bit position of the bits;
+ [2]: => the number of bits;
+ [3]: => fuse reading method, 0 for direct reading or 1 for SCM reading.
+ This property is required if qcom,cpr-speed-bin-max-corners is present.
+- qcom,cpr-quot-adjust-scaling-factor-max: The maximum allowed CPR target quotient scaling factor to use when
+ calculating the quotient adjustment for a given virtual voltage corner. It
+ corresponds to 'scaling' in this equation:
+ quot_adjust = (freq_turbo - freq_corner) * scaling / 1000.
+ This property is required if qcom,cpr-speed-bin-max-corners is present.
Example:
apc_vreg_corner: regulator@f9018000 {
@@ -319,9 +340,25 @@
qcom,cpr-uplift-speed-bin = <1>;
qcom,speed-bin-fuse-sel = <22 0 3 0>;
qcom,cpr-corner-map = <1 1 2 2 3 3 3 3 3 3 3 3>;
- qcom,cpr-quot-adjust-table = <1 1 0>, <1 2 0>, <1 3 0>,
- <1 4 0>, <1 5 450>, <1 6 375>,
- <1 7 300>, <1 8 225>, <1 9 187>,
- <1 10 150>, <1 11 75>, <1 12 0>;
+ qcom,cpr-corner-frequency-map =
+ <1 300000000>,
+ <2 384000000>,
+ <3 600000000>,
+ <4 787200000>,
+ <5 998400000>,
+ <6 1094400000>,
+ <7 1190400000>,
+ <8 1305600000>,
+ <9 1344000000>,
+ <10 1401600000>,
+ <11 1497600000>,
+ <12 1593600000>;
+ qcom,pvs-version-fuse-sel = <22 4 2 0>;
+ qcom,cpr-speed-bin-max-corners =
+ <0 1 2 4 7>,
+ <1 1 2 4 12>,
+ <2 1 2 4 10>,
+ <5 1 2 4 14>;
+ qcom,cpr-quot-adjust-scaling-factor-max = <650>;
};
diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-ctrl.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-ctrl.txt
index cda437a..e8b02cf 100644
--- a/Documentation/devicetree/bindings/fb/mdss-dsi-ctrl.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-dsi-ctrl.txt
@@ -6,7 +6,8 @@
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 set for the device.
+- reg: Offset and length of the register regions(s) for the device.
+- reg-names: A list of strings that map in order to the list of regs.
- 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.
@@ -52,7 +53,9 @@
compatible = "qcom,mdss-dsi-ctrl";
label = "MDSS DSI CTRL->0";
cell-index = <0>;
- reg = <0xfd922800 0x600>;
+ reg = <0xfd922800 0x600>,
+ <0xfd828000 0x108>;
+ reg-names = "dsi_phys", "mmss_misc_phys";
vdd-supply = <&pm8226_l15>;
vddio-supply = <&pm8226_l8>;
vdda-supply = <&pm8226_l4>;
diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
index ae6f8ef..02d6df9 100644
--- a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
@@ -254,6 +254,9 @@
mode. This master delay (t_init_delay as per DSI spec) should be sum
of DSI internal delay to reach fuctional after power up and minimum
delay required by panel to reach functional.
+- qcom,mdss-dsi-rx-eot-ignore: Boolean used to enable ignoring end of transmission packets.
+- qcom,mdss-dsi-tx-eot-append: Boolean used to enable appending end of transmission packets.
+- qcom,ulps-enabled: Boolean to enable support for Ultra Low Power State (ULPS) mode.
Note, if a given optional qcom,* binding is not present, then the driver will configure
the default values specified.
@@ -348,5 +351,8 @@
qcom,mdss-dsi-reset-sequence = <1 2>, <0 10>, <1 10>;
qcom,mdss-dsi-lp11-init;
qcom,mdss-dsi-init-delay-us = <100>;
+ mdss-dsi-rx-eot-ignore;
+ mdss-dsi-tx-eot-append;
+ qcom,ulps-enabled;
};
};
diff --git a/Documentation/devicetree/bindings/mtd/msm_qpic_nand.txt b/Documentation/devicetree/bindings/mtd/msm_qpic_nand.txt
index 8cef7f0..447c8c1 100644
--- a/Documentation/devicetree/bindings/mtd/msm_qpic_nand.txt
+++ b/Documentation/devicetree/bindings/mtd/msm_qpic_nand.txt
@@ -13,11 +13,12 @@
Each partition is represented as a sub-node of the qcom,mtd-partitions device.
Each node's name represents the name of the corresponding partition.
-Required properties:
-- reg : The partition offset and size
-- label : The label / name for this partition.
+This is now completely optional as the partition information is avaialble from
+bootloader.
Optional properties:
+- reg : The partition offset and size
+- label : The label / name for this partition.
- read-only: This parameter, if present, indicates that this partition
should only be mounted read-only.
diff --git a/Documentation/devicetree/bindings/nfc/nfc-nci.txt b/Documentation/devicetree/bindings/nfc/nfc-nci.txt
index 2c06599..7af847c 100644
--- a/Documentation/devicetree/bindings/nfc/nfc-nci.txt
+++ b/Documentation/devicetree/bindings/nfc/nfc-nci.txt
@@ -12,13 +12,12 @@
- qcom,clk-src-gpio: msm gpio clock,used ony if clock source is msm gpio
- qcom,clk-req-gpio: clk-req input gpio for MSM based clocks.
not used for pmic implementation
-- vlogic-supply: LDO for power supply
- interrupt-parent: Should be phandle for the interrupt controller
that services interrupts for this device.
- interrupts: Nfc read interrupt,gpio-clk-req interrupt
- qcom,clk-gpio: pmic or msm gpio on which bbclk2 signal is coming.
-LDO example:
+Example:
i2c@f9925000 { /* BLSP-1 QUP-3 */
nfc-nci@e {
@@ -31,7 +30,6 @@
interrupt-parent = <&msmgpio>;
interrupts = <77 0>;
qcom,clk-gpio = <&msmgpio 75 0x00>;
- vlogic-supply = <&pm8110_l14>;
};
};
diff --git a/Documentation/devicetree/bindings/power/qpnp-charger.txt b/Documentation/devicetree/bindings/power/qpnp-charger.txt
index 50381a2..87ecc64 100644
--- a/Documentation/devicetree/bindings/power/qpnp-charger.txt
+++ b/Documentation/devicetree/bindings/power/qpnp-charger.txt
@@ -106,6 +106,10 @@
- qcom,vbatdet-maxerr-mv This property in mV is a hystersis value for the charge
resume voltage property qcom,vbatdet-delta-mv. If this
property is not defined it defaults to 50 mV.
+- qcom,parallel-ovp-mode When this option is enabled, it allows charging through both
+ DC and USB OVP FETs. Please note that this should only
+ be enabled in board designs with PM8941 which have DC_IN
+ and USB_IN connected via a short.
Sub node required structure:
- A qcom,chg node must be a child of an SPMI node that has specified
diff --git a/Documentation/devicetree/bindings/regulator/krait-regulator.txt b/Documentation/devicetree/bindings/regulator/krait-regulator.txt
index 7c661fe..004c4df 100644
--- a/Documentation/devicetree/bindings/regulator/krait-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/krait-regulator.txt
@@ -22,7 +22,12 @@
the phase scaling factor eFuse address.
- qcom,pfm-threshold The power coeff threshold in abstract power units below which
pmic will be made to operate in PFM mode.
-
+- qcom,phase-scaling-factor-bits-pos indicates bit position of scaling factor data within the efuse
+ register.
+- qcom,valid-scaling-factor-versions This is an array holding four boolean values and indicates whether
+ the version read from efuses is valid.
+ The version is a two bit field and the value read from hardware is
+ used as an index in this array to check for validity.
Optional properties:
- qcom,use-phase-switching indicates whether the driver should add/shed phases on the PMIC
ganged regulator as cpus are hotplugged.
@@ -70,6 +75,9 @@
qcom,use-phase-switching;
qcom,use-phase-scaling-factor;
qcom,pfm-threshold = <376975>;
+ qcom,phase-scaling-factor-bits-pos = <18>;
+ qcom,valid-scaling-factor-versions = <0 1 1 0>;
+
#address-cells = <1>;
#size-cells = <1>;
ranges;
diff --git a/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt b/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
index 24f21b4..6562607 100644
--- a/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
+++ b/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
@@ -131,15 +131,24 @@
Required properties :
- compatible : should be "qcom,hsic-smsc-hub"
-- smsc,model-id : should be either <3503> or <4604> depending on hub model
-- smsc,<gpio-name>-gpio : handle to the GPIO node, see "gpios property"
- in Documentation/devicetree/bindings/gpio/gpio.txt.
- Required "gpio-name" is "reset" and optionally - "refclk", "int".
-- <supply-name>-supply: handle to the regulator device tree node
- Required "supply-name" is "hub_init" and optionally - "hub_vbus".
+- smsc,model-id : should be <3502>/<3503>/<4604> depending on hub model. It
+ will be 0 for standalone HSIC controller configuration.
+- smsc,reset-gpio: this output gpio is used to assert/de-assert the hub reset
- Sub node for "MSM HSIC EHCI controller".
Sub node has the required properties mentioned above.
+Optional properties :
+- smsc,int-gpio: this input gpio indicate HUB suspend status and signal remote
+ wakeup interrupt
+- smsc,refclk-gpio: this gpio is used to supply the reference clock
+- smsc,xo-clk-gio: this output gpio is used to control the external XO clock
+ which is supplied to the hub as a reference clock
+- hub-vbus-supply: this regulator is used to supply the power to
+ downstream ports
+- hub-int-supply: this regulator is used to bias the interrupt gpio
+- ext-hub-vddio-supply: this regulator is used to supply the power to one of
+ the hub's VDD.
+
Example SMSC HSIC HUB :
hsic_hub {
compatible = "qcom,hsic-smsc-hub";
@@ -148,8 +157,8 @@
smsc,reset-gpio = <&pm8941_gpios 8 0x00>;
smsc,refclk-gpio = <&pm8941_gpios 16 0x00>;
smsc,int-gpio = <&msmgpio 50 0x00>;
- hub_int-supply = <&pm8941_l10>;
- hub_vbus-supply = <&pm8941_mvs1>;
+ hub-int-supply = <&pm8941_l10>;
+ hub-vbus-supply = <&pm8941_mvs1>;
hsic@f9a00000 {
compatible = "qcom,hsic-host";
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index fd826d9..b94b587 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -8,6 +8,7 @@
apm Applied Micro Circuits Corporation (APM)
arm ARM Ltd.
atmel Atmel Corporation
+avago Avago Technologies
bosch Bosch Sensortec GmbH
capella Capella Microsystems, Inc.
cavium Cavium, Inc.
diff --git a/arch/arm/boot/dts/apq8074-dragonboard.dtsi b/arch/arm/boot/dts/apq8074-dragonboard.dtsi
index c7e24d9..8c76a6d 100644
--- a/arch/arm/boot/dts/apq8074-dragonboard.dtsi
+++ b/arch/arm/boot/dts/apq8074-dragonboard.dtsi
@@ -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
@@ -74,7 +74,7 @@
/* Dragonboard has an always-on VBUS supply for HSIC hub,
* providing a dummy regulator for the hub driver
*/
- hub_vbus-supply = <&vph_pwr_vreg>;
+ hub-vbus-supply = <&vph_pwr_vreg>;
hsic_host: hsic@f9a00000 {
compatible = "qcom,hsic-host";
diff --git a/arch/arm/boot/dts/msm8226-1080p-mtp.dtsi b/arch/arm/boot/dts/msm8226-1080p-mtp.dtsi
index a99df65..3734273 100644
--- a/arch/arm/boot/dts/msm8226-1080p-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8226-1080p-mtp.dtsi
@@ -120,6 +120,7 @@
qcom,cdc-mclk-gpios = <&pm8226_gpios 1 0>;
qcom,cdc-vdd-spkr-gpios = <&pm8226_gpios 2 0>;
+ qcom,cdc-us-euro-gpios = <&msmgpio 69 0>;
};
sound-9302 {
@@ -137,6 +138,7 @@
qcom,cdc-mclk-gpios = <&pm8226_gpios 1 0>;
qcom,cdc-vdd-spkr-gpios = <&pm8226_gpios 2 0>;
+ qcom,cdc-us-euro-gpios = <&msmgpio 69 0>;
};
};
diff --git a/arch/arm/boot/dts/msm8226-720p-mtp.dtsi b/arch/arm/boot/dts/msm8226-720p-mtp.dtsi
index 7f4f8fc..b4d9139 100644
--- a/arch/arm/boot/dts/msm8226-720p-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8226-720p-mtp.dtsi
@@ -110,6 +110,7 @@
qcom,cdc-mclk-gpios = <&pm8226_gpios 1 0>;
qcom,cdc-vdd-spkr-gpios = <&pm8226_gpios 2 0>;
+ qcom,cdc-us-euro-gpios = <&msmgpio 69 0>;
};
sound-9302 {
@@ -127,6 +128,7 @@
qcom,cdc-mclk-gpios = <&pm8226_gpios 1 0>;
qcom,cdc-vdd-spkr-gpios = <&pm8226_gpios 2 0>;
+ qcom,cdc-us-euro-gpios = <&msmgpio 69 0>;
};
};
diff --git a/arch/arm/boot/dts/msm8226-gpu.dtsi b/arch/arm/boot/dts/msm8226-gpu.dtsi
index c52073d..d1c3264 100644
--- a/arch/arm/boot/dts/msm8226-gpu.dtsi
+++ b/arch/arm/boot/dts/msm8226-gpu.dtsi
@@ -34,9 +34,9 @@
qcom,msm-bus,num-paths = <2>;
qcom,msm-bus,vectors-KBps =
<26 512 0 0>, <89 604 0 0>,
- <26 512 0 1600000>, <89 604 0 3200000>,
- <26 512 0 3200000>, <89 604 0 5120000>,
- <26 512 0 4256000>, <89 604 0 6400000>;
+ <26 512 800000 1600000>, <89 604 0 3200000>,
+ <26 512 1600000 3200000>, <89 604 0 5120000>,
+ <26 512 2128000 4256000>, <89 604 0 6400000>;
/* GDSC oxili regulators */
diff --git a/arch/arm/boot/dts/msm8226-mdss.dtsi b/arch/arm/boot/dts/msm8226-mdss.dtsi
index 375c5df..2176d39 100644
--- a/arch/arm/boot/dts/msm8226-mdss.dtsi
+++ b/arch/arm/boot/dts/msm8226-mdss.dtsi
@@ -95,7 +95,9 @@
compatible = "qcom,mdss-dsi-ctrl";
label = "MDSS DSI CTRL->0";
cell-index = <0>;
- reg = <0xfd922800 0x600>;
+ reg = <0xfd922800 0x600>,
+ <0xfd828000 0x108>;
+ reg-names = "dsi_phys", "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-v2-1080p-cdp.dts b/arch/arm/boot/dts/msm8226-v2-1080p-cdp.dts
index 77cc08c..d48f8b6 100644
--- a/arch/arm/boot/dts/msm8226-v2-1080p-cdp.dts
+++ b/arch/arm/boot/dts/msm8226-v2-1080p-cdp.dts
@@ -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
@@ -21,6 +21,6 @@
qcom,board-id = <1 2>;
};
-&hsic_host {
+&smsc_hub {
status = "ok";
};
diff --git a/arch/arm/boot/dts/msm8226-v2-720p-cdp.dts b/arch/arm/boot/dts/msm8226-v2-720p-cdp.dts
index 966ae2b..f73bac0 100644
--- a/arch/arm/boot/dts/msm8226-v2-720p-cdp.dts
+++ b/arch/arm/boot/dts/msm8226-v2-720p-cdp.dts
@@ -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
@@ -21,6 +21,6 @@
qcom,board-id = <1 0>;
};
-&hsic_host {
+&smsc_hub {
status = "ok";
};
diff --git a/arch/arm/boot/dts/msm8226-v2.dtsi b/arch/arm/boot/dts/msm8226-v2.dtsi
index 6215740..14fe237 100644
--- a/arch/arm/boot/dts/msm8226-v2.dtsi
+++ b/arch/arm/boot/dts/msm8226-v2.dtsi
@@ -37,14 +37,28 @@
qcom,cpr-up-threshold = <0>;
qcom,cpr-down-threshold = <5>;
qcom,cpr-corner-map = <1 1 2 2 3 3 3 3 3 3 3 3 3 3>;
- qcom,cpr-quot-adjust-table =
- <1 5 450>,
- <1 6 375>,
- <1 7 300>,
- <1 8 225>,
- <1 9 187>,
- <1 10 150>,
- <1 11 75>;
+ qcom,pvs-version-fuse-sel = <22 4 2 0>;
+ qcom,cpr-corner-frequency-map =
+ <1 300000000>,
+ <2 384000000>,
+ <3 600000000>,
+ <4 787200000>,
+ <5 998400000>,
+ <6 1094400000>,
+ <7 1190400000>,
+ <8 1305600000>,
+ <9 1344000000>,
+ <10 1401600000>,
+ <11 1497600000>,
+ <12 1593600000>,
+ <13 1689600000>,
+ <14 1785600000>;
+ qcom,cpr-speed-bin-max-corners =
+ <0 2 2 4 7>,
+ <1 2 2 4 12>,
+ <2 2 2 4 10>,
+ <5 2 2 4 14>;
+ qcom,cpr-quot-adjust-scaling-factor-max = <650>;
};
&msm_gpu {
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index 9113259..cf8e3b3 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -302,35 +302,43 @@
qcom,streaming-func = "rndis";
};
- hsic_host: hsic@f9a00000 {
+ smsc_hub: hsic_hub {
status = "disabled";
- compatible = "qcom,hsic-host";
- reg = <0xf9a00000 0x400>;
- #address-cells = <0>;
- interrupt-parent = <&hsic_host>;
- interrupts = <0 1 2>;
- #interrupt-cells = <1>;
- interrupt-map-mask = <0xffffffff>;
- interrupt-map = <0 &intc 0 136 0
- 1 &intc 0 148 0
- 2 &msmgpio 115 0x8>;
- interrupt-names = "core_irq", "async_irq", "wakeup";
- hsic_vdd_dig-supply = <&pm8226_s1_corner>;
- HSIC_GDSC-supply = <&gdsc_usb_hsic>;
- hsic,strobe-gpio = <&msmgpio 115 0x00>;
- hsic,data-gpio = <&msmgpio 116 0x00>;
- hsic,ignore-cal-pad-config;
- hsic,strobe-pad-offset = <0x2050>;
- hsic,data-pad-offset = <0x2054>;
- qcom,phy-susp-sof-workaround;
- hsic,vdd-voltage-level = <1 5 7>;
+ compatible = "qcom,hsic-smsc-hub";
+ smsc,model-id = <0>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
- qcom,msm-bus,name = "hsic";
- qcom,msm-bus,num-cases = <2>;
- qcom,msm-bus,num-paths = <1>;
- qcom,msm-bus,vectors-KBps =
+ hsic_host: hsic@f9a00000 {
+ compatible = "qcom,hsic-host";
+ reg = <0xf9a00000 0x400>;
+ #address-cells = <0>;
+ interrupt-parent = <&hsic_host>;
+ interrupts = <0 1 2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0xffffffff>;
+ interrupt-map = <0 &intc 0 136 0
+ 1 &intc 0 148 0
+ 2 &msmgpio 115 0x8>;
+ interrupt-names = "core_irq", "async_irq", "wakeup";
+ hsic_vdd_dig-supply = <&pm8226_s1_corner>;
+ HSIC_GDSC-supply = <&gdsc_usb_hsic>;
+ hsic,strobe-gpio = <&msmgpio 115 0x00>;
+ hsic,data-gpio = <&msmgpio 116 0x00>;
+ hsic,ignore-cal-pad-config;
+ hsic,strobe-pad-offset = <0x2050>;
+ hsic,data-pad-offset = <0x2054>;
+ qcom,phy-susp-sof-workaround;
+ hsic,vdd-voltage-level = <1 5 7>;
+
+ qcom,msm-bus,name = "hsic";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
<85 512 0 0>,
<85 512 40000 160000>;
+ };
};
wcd9xxx_intc: wcd9xxx-irq {
@@ -1256,8 +1264,8 @@
qcom,msm-bus,num-cases = <2>;
qcom,msm-bus,num-paths = <1>;
qcom,msm-bus,vectors-KBps =
- <1 618 0 0>,
- <1 618 0 800>;
+ <54 618 0 0>,
+ <54 618 0 800>;
};
qcom,tz-log@fe805720 {
diff --git a/arch/arm/boot/dts/msm8610-v1.dtsi b/arch/arm/boot/dts/msm8610-v1.dtsi
index 9d8c411..8965e93 100644
--- a/arch/arm/boot/dts/msm8610-v1.dtsi
+++ b/arch/arm/boot/dts/msm8610-v1.dtsi
@@ -20,6 +20,7 @@
/include/ "msm8610-v1-pm.dtsi"
/ {
- qcom,msm-id = <147 0>, <165 0>, <161 0>, <162 0>,
- <163 0>, <164 0>, <166 0>;
+ qcom,msm-id = <147 1000>, <165 1000>, <161 1000>, <162 1000>,
+ <163 1000>, <164 1000>, <166 1000>, <225 1000>,
+ <226 1000>;
};
diff --git a/arch/arm/boot/dts/msm8610-v2.dtsi b/arch/arm/boot/dts/msm8610-v2.dtsi
index a1f466a..221598d 100644
--- a/arch/arm/boot/dts/msm8610-v2.dtsi
+++ b/arch/arm/boot/dts/msm8610-v2.dtsi
@@ -21,5 +21,6 @@
/ {
qcom,msm-id = <147 0x10001>, <165 0x10001>, <161 0x10001>, <162 0x10001>,
- <163 0x10001>, <164 0x10001>, <166 0x10001>;
+ <163 0x10001>, <164 0x10001>, <166 0x10001>,
+ <225 0x10001>, <226 0x10001>;
};
diff --git a/arch/arm/boot/dts/msm8926-v1-1080p-cdp.dts b/arch/arm/boot/dts/msm8926-v1-1080p-cdp.dts
index 1b6f971..1829a8e 100644
--- a/arch/arm/boot/dts/msm8926-v1-1080p-cdp.dts
+++ b/arch/arm/boot/dts/msm8926-v1-1080p-cdp.dts
@@ -33,6 +33,6 @@
};
-&hsic_host {
+&smsc_hub {
status = "ok";
};
diff --git a/arch/arm/boot/dts/msm8926-v1-720p-cdp.dts b/arch/arm/boot/dts/msm8926-v1-720p-cdp.dts
index 37da01c..2217f15 100644
--- a/arch/arm/boot/dts/msm8926-v1-720p-cdp.dts
+++ b/arch/arm/boot/dts/msm8926-v1-720p-cdp.dts
@@ -33,6 +33,6 @@
};
-&hsic_host {
+&smsc_hub {
status = "ok";
};
diff --git a/arch/arm/boot/dts/msm8926-v2-1080p-cdp.dts b/arch/arm/boot/dts/msm8926-v2-1080p-cdp.dts
index a4ebbe1..7ab37cd 100644
--- a/arch/arm/boot/dts/msm8926-v2-1080p-cdp.dts
+++ b/arch/arm/boot/dts/msm8926-v2-1080p-cdp.dts
@@ -33,6 +33,6 @@
};
-&hsic_host {
+&smsc_hub {
status = "ok";
};
diff --git a/arch/arm/boot/dts/msm8926-v2-1080p-ext-buck-cdp.dts b/arch/arm/boot/dts/msm8926-v2-1080p-ext-buck-cdp.dts
index 64e872b..d38b53f 100644
--- a/arch/arm/boot/dts/msm8926-v2-1080p-ext-buck-cdp.dts
+++ b/arch/arm/boot/dts/msm8926-v2-1080p-ext-buck-cdp.dts
@@ -33,6 +33,6 @@
};
-&hsic_host {
+&smsc_hub {
status = "ok";
};
diff --git a/arch/arm/boot/dts/msm8926-v2-1080p-ext-buck-mtp.dts b/arch/arm/boot/dts/msm8926-v2-1080p-ext-buck-mtp.dts
index f9a3cd8..0a33976 100644
--- a/arch/arm/boot/dts/msm8926-v2-1080p-ext-buck-mtp.dts
+++ b/arch/arm/boot/dts/msm8926-v2-1080p-ext-buck-mtp.dts
@@ -21,3 +21,12 @@
compatible = "qcom,msm8926-mtp", "qcom,msm8926", "qcom,mtp";
qcom,board-id = <8 3>;
};
+
+&smsc_hub {
+ status = "ok";
+ smsc,model-id = <3502>;
+ smsc,reset-gpio = <&msmgpio 114 0x00>;
+ smsc,int-gpio = <&msmgpio 9 0x00>;
+ smsc,xo-clk-gpio = <&msmgpio 8 0x00>;
+ hub-int-supply = <&pm8226_l6>;
+};
diff --git a/arch/arm/boot/dts/msm8926-v2-1080p-mtp.dts b/arch/arm/boot/dts/msm8926-v2-1080p-mtp.dts
index 1f0bab1..2466f8b 100644
--- a/arch/arm/boot/dts/msm8926-v2-1080p-mtp.dts
+++ b/arch/arm/boot/dts/msm8926-v2-1080p-mtp.dts
@@ -21,3 +21,12 @@
compatible = "qcom,msm8926-mtp", "qcom,msm8926", "qcom,mtp";
qcom,board-id = <8 2>;
};
+
+&smsc_hub {
+ status = "ok";
+ smsc,model-id = <3502>;
+ smsc,reset-gpio = <&msmgpio 114 0x00>;
+ smsc,int-gpio = <&msmgpio 9 0x00>;
+ smsc,xo-clk-gpio = <&msmgpio 8 0x00>;
+ hub-int-supply = <&pm8226_l6>;
+};
diff --git a/arch/arm/boot/dts/msm8926-v2-720p-cdp.dts b/arch/arm/boot/dts/msm8926-v2-720p-cdp.dts
index 1e6e197..5c5ad89 100644
--- a/arch/arm/boot/dts/msm8926-v2-720p-cdp.dts
+++ b/arch/arm/boot/dts/msm8926-v2-720p-cdp.dts
@@ -33,6 +33,6 @@
};
-&hsic_host {
+&smsc_hub {
status = "ok";
};
diff --git a/arch/arm/boot/dts/msm8926-v2-720p-mtp.dts b/arch/arm/boot/dts/msm8926-v2-720p-mtp.dts
index 59ad506..2c577cd 100644
--- a/arch/arm/boot/dts/msm8926-v2-720p-mtp.dts
+++ b/arch/arm/boot/dts/msm8926-v2-720p-mtp.dts
@@ -21,3 +21,12 @@
compatible = "qcom,msm8926-mtp", "qcom,msm8926", "qcom,mtp";
qcom,board-id = <8 0>;
};
+
+&smsc_hub {
+ status = "ok";
+ smsc,model-id = <3502>;
+ smsc,reset-gpio = <&msmgpio 114 0x00>;
+ smsc,int-gpio = <&msmgpio 9 0x00>;
+ smsc,xo-clk-gpio = <&msmgpio 8 0x00>;
+ hub-int-supply = <&pm8226_l6>;
+};
diff --git a/arch/arm/boot/dts/msm8926-v2-ext-buck.dtsi b/arch/arm/boot/dts/msm8926-v2-ext-buck.dtsi
index 0785def..8a95116 100644
--- a/arch/arm/boot/dts/msm8926-v2-ext-buck.dtsi
+++ b/arch/arm/boot/dts/msm8926-v2-ext-buck.dtsi
@@ -81,7 +81,7 @@
qcom,ext-buck-control {
compatible = "qcom,ext-buck-control";
qcom,gpio-num = <50>;
- qcom,settling-time-us = <2580>;
+ qcom,settling-time-us = <9600>;
};
};
diff --git a/arch/arm/boot/dts/msm8926.dtsi b/arch/arm/boot/dts/msm8926.dtsi
index 8a0e5c4..e866286 100644
--- a/arch/arm/boot/dts/msm8926.dtsi
+++ b/arch/arm/boot/dts/msm8926.dtsi
@@ -138,15 +138,29 @@
regulator-min-microvolt = <1>;
regulator-max-microvolt = <14>;
qcom,cpr-corner-map = <1 1 2 2 3 3 3 3 3 3 3 3 3 3>;
- qcom,cpr-quot-adjust-table =
- <1 5 450>,
- <1 6 375>,
- <1 7 300>,
- <1 8 225>,
- <1 9 187>,
- <1 10 150>,
- <1 11 75>;
qcom,cpr-quotient-adjustment = <0 72 72>;
+ qcom,pvs-version-fuse-sel = <22 4 2 0>;
+ qcom,cpr-corner-frequency-map =
+ <1 300000000>,
+ <2 384000000>,
+ <3 600000000>,
+ <4 787200000>,
+ <5 998400000>,
+ <6 1094400000>,
+ <7 1190400000>,
+ <8 1305600000>,
+ <9 1344000000>,
+ <10 1401600000>,
+ <11 1497600000>,
+ <12 1593600000>,
+ <13 1689600000>,
+ <14 1785600000>;
+ qcom,cpr-speed-bin-max-corners =
+ <0 1 2 4 7>,
+ <1 1 2 4 12>,
+ <2 1 2 4 10>,
+ <5 1 2 4 14>;
+ qcom,cpr-quot-adjust-scaling-factor-max = <650>;
};
&tsens {
diff --git a/arch/arm/boot/dts/msm8974-mdss.dtsi b/arch/arm/boot/dts/msm8974-mdss.dtsi
index 7f63234..0e72446 100644
--- a/arch/arm/boot/dts/msm8974-mdss.dtsi
+++ b/arch/arm/boot/dts/msm8974-mdss.dtsi
@@ -113,7 +113,9 @@
compatible = "qcom,mdss-dsi-ctrl";
label = "MDSS DSI CTRL->0";
cell-index = <0>;
- reg = <0xfd922800 0x600>;
+ reg = <0xfd922800 0x600>,
+ <0xfdf30000 0x108>;
+ reg-names = "dsi_phys", "mmss_misc_phys";
vdd-supply = <&pm8941_l22>;
vddio-supply = <&pm8941_l12>;
vdda-supply = <&pm8941_l2>;
@@ -169,7 +171,9 @@
compatible = "qcom,mdss-dsi-ctrl";
label = "MDSS DSI CTRL->1";
cell-index = <1>;
- reg = <0xfd922e00 0x600>;
+ reg = <0xfd922e00 0x600>,
+ <0xfdf30000 0x108>;
+ reg-names = "dsi_phys", "mmss_misc_phys";
vdd-supply = <&pm8941_l22>;
vddio-supply = <&pm8941_l12>;
vdda-supply = <&pm8941_l2>;
diff --git a/arch/arm/boot/dts/msm8974-regulator.dtsi b/arch/arm/boot/dts/msm8974-regulator.dtsi
index 5cf98d6..45b716a 100644
--- a/arch/arm/boot/dts/msm8974-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8974-regulator.dtsi
@@ -465,6 +465,8 @@
ranges;
qcom,pfm-threshold = <76>;
qcom,use-phase-scaling-factor;
+ qcom,phase-scaling-factor-bits-pos = <16>;
+ qcom,valid-scaling-factor-versions = <0 1 0 0>;
krait0_vreg: regulator@f9088000 {
compatible = "qcom,krait-regulator";
diff --git a/arch/arm/boot/dts/msm8974pro-pm.dtsi b/arch/arm/boot/dts/msm8974pro-pm.dtsi
index 34ae372..aca8f20 100644
--- a/arch/arm/boot/dts/msm8974pro-pm.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-pm.dtsi
@@ -376,4 +376,12 @@
reg = <0xfc000000 0x1a0000>;
qcom,start-offset = <0x190010>;
};
+
+ qcom,rpm-master-stats@fc428150 {
+ compatible = "qcom,rpm-master-stats";
+ reg = <0xfc428150 0x3200>;
+ qcom,masters = "APSS", "MPSS", "LPSS", "PRONTO";
+ qcom,master-stats-version = <2>;
+ qcom,master-offset = <2560>;
+ };
};
diff --git a/arch/arm/boot/dts/msm8974pro-pm8941.dtsi b/arch/arm/boot/dts/msm8974pro-pm8941.dtsi
index decd444..9c2be1a 100644
--- a/arch/arm/boot/dts/msm8974pro-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-pm8941.dtsi
@@ -34,6 +34,8 @@
&krait_pdn {
qcom,use-phase-switching;
+ qcom,valid-scaling-factor-versions = <0 1 1 0>;
+
};
&krait0_vreg {
diff --git a/arch/arm/boot/dts/msm8974pro-pma8084-regulator.dtsi b/arch/arm/boot/dts/msm8974pro-pma8084-regulator.dtsi
index 78e2167..49bf4ea 100644
--- a/arch/arm/boot/dts/msm8974pro-pma8084-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-pma8084-regulator.dtsi
@@ -481,6 +481,8 @@
ranges;
qcom,pfm-threshold = <76>;
qcom,use-phase-scaling-factor;
+ qcom,phase-scaling-factor-bits-pos = <16>;
+ qcom,valid-scaling-factor-versions = <0 1 1 0>;
krait0_vreg: regulator@f9088000 {
compatible = "qcom,krait-regulator";
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index f1c285d..e72e5ff 100755
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -276,6 +276,7 @@
CONFIG_MD=y
CONFIG_BLK_DEV_DM=y
CONFIG_DM_CRYPT=y
+CONFIG_DM_REQ_CRYPT=y
CONFIG_NETDEVICES=y
CONFIG_DUMMY=y
CONFIG_TUN=y
@@ -540,8 +541,9 @@
CONFIG_CRYPTO_MD4=y
CONFIG_CRYPTO_ARC4=y
CONFIG_CRYPTO_TWOFISH=y
+CONFIG_CRYPTO_XTS=y
CONFIG_NFC_QNCI=y
-CONFIG_CRYPTO_DEV_QCRYPTO=m
+CONFIG_CRYPTO_DEV_QCRYPTO=y
CONFIG_CRYPTO_DEV_QCE=y
CONFIG_CRYPTO_DEV_QCEDEV=y
CONFIG_SND_SOC_MSM_HDMI_CODEC_RX=y
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index 7814288..1a09188 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/arch/arm/kernel/perf_event.c
@@ -893,6 +893,8 @@
hcpu, 1);
break;
case CPU_STARTING:
+ if (cpu_pmu && cpu_pmu->reset)
+ cpu_pmu->reset(NULL);
if (cpu_pmu && cpu_pmu->restore_pm_registers)
smp_call_function_single(cpu,
cpu_pmu->restore_pm_registers,
@@ -927,9 +929,8 @@
enable_irq_callback(&irq);
}
- if (cpu_pmu && cpu_pmu->reset) {
+ if (cpu_pmu) {
__get_cpu_var(from_idle) = 1;
- cpu_pmu->reset(NULL);
pmu = &cpu_pmu->pmu;
pmu->pmu_enable(pmu);
return NOTIFY_OK;
diff --git a/arch/arm/mach-msm/board-8226-gpiomux.c b/arch/arm/mach-msm/board-8226-gpiomux.c
index 5882ebc..fe7de31 100644
--- a/arch/arm/mach-msm/board-8226-gpiomux.c
+++ b/arch/arm/mach-msm/board-8226-gpiomux.c
@@ -11,6 +11,7 @@
*
*/
+#include <linux/gpio.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <mach/board.h>
@@ -18,6 +19,12 @@
#include <mach/gpiomux.h>
#include <mach/socinfo.h>
+#define WLAN_CLK 44
+#define WLAN_SET 43
+#define WLAN_DATA0 42
+#define WLAN_DATA1 41
+#define WLAN_DATA2 40
+
#ifdef CONFIG_USB_EHCI_MSM_HSIC
static struct gpiomux_setting hsic_sus_cfg = {
.func = GPIOMUX_FUNC_GPIO,
@@ -140,6 +147,18 @@
.pull = GPIOMUX_PULL_DOWN,
};
+static struct gpiomux_setting wcnss_5gpio_suspend_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting wcnss_5gpio_active_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_6MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
static struct gpiomux_setting gpio_i2c_config = {
.func = GPIOMUX_FUNC_3,
.drv = GPIOMUX_DRV_2MA,
@@ -542,6 +561,44 @@
},
};
+static struct msm_gpiomux_config wcnss_5gpio_interface[] = {
+ {
+ .gpio = 40,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wcnss_5gpio_active_cfg,
+ [GPIOMUX_SUSPENDED] = &wcnss_5gpio_suspend_cfg,
+ },
+ },
+ {
+ .gpio = 41,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wcnss_5gpio_active_cfg,
+ [GPIOMUX_SUSPENDED] = &wcnss_5gpio_suspend_cfg,
+ },
+ },
+ {
+ .gpio = 42,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wcnss_5gpio_active_cfg,
+ [GPIOMUX_SUSPENDED] = &wcnss_5gpio_suspend_cfg,
+ },
+ },
+ {
+ .gpio = 43,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wcnss_5gpio_active_cfg,
+ [GPIOMUX_SUSPENDED] = &wcnss_5gpio_suspend_cfg,
+ },
+ },
+ {
+ .gpio = 44,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wcnss_5gpio_active_cfg,
+ [GPIOMUX_SUSPENDED] = &wcnss_5gpio_suspend_cfg,
+ },
+ },
+};
+
static struct gpiomux_setting gpio_suspend_config[] = {
{
.func = GPIOMUX_FUNC_GPIO, /* IN-NP */
@@ -884,3 +941,109 @@
msm_gpiomux_install(msm_hsic_configs, ARRAY_SIZE(msm_hsic_configs));
#endif
}
+
+static void wcnss_switch_to_gpio(void)
+{
+ /* Switch MUX to GPIO */
+ msm_gpiomux_install(wcnss_5gpio_interface,
+ ARRAY_SIZE(wcnss_5gpio_interface));
+
+ /* Ensure GPIO config */
+ gpio_direction_input(WLAN_DATA2);
+ gpio_direction_input(WLAN_DATA1);
+ gpio_direction_input(WLAN_DATA0);
+ gpio_direction_output(WLAN_SET, 0);
+ gpio_direction_output(WLAN_CLK, 0);
+}
+
+static void wcnss_switch_to_5wire(void)
+{
+ msm_gpiomux_install(wcnss_5wire_interface,
+ ARRAY_SIZE(wcnss_5wire_interface));
+}
+
+u32 wcnss_rf_read_reg(u32 rf_reg_addr)
+{
+ int count = 0;
+ u32 rf_cmd_and_addr = 0;
+ u32 rf_data_received = 0;
+ u32 rf_bit = 0;
+
+ wcnss_switch_to_gpio();
+
+ /* Reset the signal if it is already being used. */
+ gpio_set_value(WLAN_SET, 0);
+ gpio_set_value(WLAN_CLK, 0);
+
+ /* We start with cmd_set high WLAN_SET = 1. */
+ gpio_set_value(WLAN_SET, 1);
+
+ gpio_direction_output(WLAN_DATA0, 1);
+ gpio_direction_output(WLAN_DATA1, 1);
+ gpio_direction_output(WLAN_DATA2, 1);
+
+ gpio_set_value(WLAN_DATA0, 0);
+ gpio_set_value(WLAN_DATA1, 0);
+ gpio_set_value(WLAN_DATA2, 0);
+
+ /* Prepare command and RF register address that need to sent out.
+ * Make sure that we send only 14 bits from LSB.
+ */
+ rf_cmd_and_addr = (((WLAN_RF_READ_REG_CMD) |
+ (rf_reg_addr << WLAN_RF_REG_ADDR_START_OFFSET)) &
+ WLAN_RF_READ_CMD_MASK);
+
+ for (count = 0; count < 5; count++) {
+ gpio_set_value(WLAN_CLK, 0);
+
+ rf_bit = (rf_cmd_and_addr & 0x1);
+ gpio_set_value(WLAN_DATA0, rf_bit ? 1 : 0);
+ rf_cmd_and_addr = (rf_cmd_and_addr >> 1);
+
+ rf_bit = (rf_cmd_and_addr & 0x1);
+ gpio_set_value(WLAN_DATA1, rf_bit ? 1 : 0);
+ rf_cmd_and_addr = (rf_cmd_and_addr >> 1);
+
+ rf_bit = (rf_cmd_and_addr & 0x1);
+ gpio_set_value(WLAN_DATA2, rf_bit ? 1 : 0);
+ rf_cmd_and_addr = (rf_cmd_and_addr >> 1);
+
+ /* Send the data out WLAN_CLK = 1 */
+ gpio_set_value(WLAN_CLK, 1);
+ }
+
+ /* Pull down the clock signal */
+ gpio_set_value(WLAN_CLK, 0);
+
+ /* Configure data pins to input IO pins */
+ gpio_direction_input(WLAN_DATA0);
+ gpio_direction_input(WLAN_DATA1);
+ gpio_direction_input(WLAN_DATA2);
+
+ for (count = 0; count < 2; count++) {
+ gpio_set_value(WLAN_CLK, 1);
+ gpio_set_value(WLAN_CLK, 0);
+ }
+
+ rf_bit = 0;
+ for (count = 0; count < 6; count++) {
+ gpio_set_value(WLAN_CLK, 1);
+ gpio_set_value(WLAN_CLK, 0);
+
+ rf_bit = gpio_get_value(WLAN_DATA0);
+ rf_data_received |= (rf_bit << (count * 3 + 0));
+
+ if (count != 5) {
+ rf_bit = gpio_get_value(WLAN_DATA1);
+ rf_data_received |= (rf_bit << (count * 3 + 1));
+
+ rf_bit = gpio_get_value(WLAN_DATA2);
+ rf_data_received |= (rf_bit << (count * 3 + 2));
+ }
+ }
+
+ gpio_set_value(WLAN_SET, 0);
+ wcnss_switch_to_5wire();
+
+ return rf_data_received;
+}
diff --git a/arch/arm/mach-msm/board-8226.c b/arch/arm/mach-msm/board-8226.c
index 3539ad3..1c1fbe3 100644
--- a/arch/arm/mach-msm/board-8226.c
+++ b/arch/arm/mach-msm/board-8226.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
@@ -75,6 +75,11 @@
return MEMTYPE_EBI1;
}
+static struct of_dev_auxdata msm_hsic_host_adata[] = {
+ OF_DEV_AUXDATA("qcom,hsic-host", 0xF9A00000, "msm_hsic_host", NULL),
+ {}
+};
+
static struct of_dev_auxdata msm8226_auxdata_lookup[] __initdata = {
OF_DEV_AUXDATA("qcom,msm-sdcc", 0xF9824000, \
"msm_sdcc.1", NULL),
@@ -89,6 +94,8 @@
OF_DEV_AUXDATA("qcom,sdhci-msm", 0xF9864900, \
"msm_sdcc.3", NULL),
OF_DEV_AUXDATA("qcom,hsic-host", 0xF9A00000, "msm_hsic_host", NULL),
+ OF_DEV_AUXDATA("qcom,hsic-smsc-hub", 0, "msm_smsc_hub",
+ msm_hsic_host_adata),
{}
};
diff --git a/arch/arm/mach-msm/board-8610-gpiomux.c b/arch/arm/mach-msm/board-8610-gpiomux.c
index 2e12fc2..4234f2a 100644
--- a/arch/arm/mach-msm/board-8610-gpiomux.c
+++ b/arch/arm/mach-msm/board-8610-gpiomux.c
@@ -11,6 +11,7 @@
*
*/
+#include <linux/gpio.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <mach/board.h>
@@ -18,6 +19,12 @@
#include <mach/gpiomux.h>
#include <mach/socinfo.h>
+#define WLAN_CLK 27
+#define WLAN_SET 26
+#define WLAN_DATA0 25
+#define WLAN_DATA1 24
+#define WLAN_DATA2 23
+
static struct gpiomux_setting gpio_spi_config = {
.func = GPIOMUX_FUNC_1,
.drv = GPIOMUX_DRV_6MA,
@@ -112,6 +119,18 @@
.pull = GPIOMUX_PULL_DOWN,
};
+static struct gpiomux_setting wcnss_5gpio_suspend_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting wcnss_5gpio_active_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_6MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
static struct gpiomux_setting lcd_en_act_cfg = {
.func = GPIOMUX_FUNC_GPIO,
.drv = GPIOMUX_DRV_8MA,
@@ -405,6 +424,44 @@
},
};
+static struct msm_gpiomux_config wcnss_5gpio_interface[] = {
+ {
+ .gpio = 23,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wcnss_5gpio_active_cfg,
+ [GPIOMUX_SUSPENDED] = &wcnss_5gpio_suspend_cfg,
+ },
+ },
+ {
+ .gpio = 24,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wcnss_5gpio_active_cfg,
+ [GPIOMUX_SUSPENDED] = &wcnss_5gpio_suspend_cfg,
+ },
+ },
+ {
+ .gpio = 25,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wcnss_5gpio_active_cfg,
+ [GPIOMUX_SUSPENDED] = &wcnss_5gpio_suspend_cfg,
+ },
+ },
+ {
+ .gpio = 26,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wcnss_5gpio_active_cfg,
+ [GPIOMUX_SUSPENDED] = &wcnss_5gpio_suspend_cfg,
+ },
+ },
+ {
+ .gpio = 27,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wcnss_5gpio_active_cfg,
+ [GPIOMUX_SUSPENDED] = &wcnss_5gpio_suspend_cfg,
+ },
+ },
+};
+
static struct gpiomux_setting gpio_suspend_config[] = {
{
.func = GPIOMUX_FUNC_GPIO, /* IN-NP */
@@ -714,3 +771,109 @@
msm_gpiomux_install(msm_cdc_dmic_configs,
ARRAY_SIZE(msm_cdc_dmic_configs));
}
+
+static void wcnss_switch_to_gpio(void)
+{
+ /* Switch MUX to GPIO */
+ msm_gpiomux_install(wcnss_5gpio_interface,
+ ARRAY_SIZE(wcnss_5gpio_interface));
+
+ /* Ensure GPIO config */
+ gpio_direction_input(WLAN_DATA2);
+ gpio_direction_input(WLAN_DATA1);
+ gpio_direction_input(WLAN_DATA0);
+ gpio_direction_output(WLAN_SET, 0);
+ gpio_direction_output(WLAN_CLK, 0);
+}
+
+static void wcnss_switch_to_5wire(void)
+{
+ msm_gpiomux_install(wcnss_5wire_interface,
+ ARRAY_SIZE(wcnss_5wire_interface));
+}
+
+u32 wcnss_rf_read_reg(u32 rf_reg_addr)
+{
+ int count = 0;
+ u32 rf_cmd_and_addr = 0;
+ u32 rf_data_received = 0;
+ u32 rf_bit = 0;
+
+ wcnss_switch_to_gpio();
+
+ /* Reset the signal if it is already being used. */
+ gpio_set_value(WLAN_SET, 0);
+ gpio_set_value(WLAN_CLK, 0);
+
+ /* We start with cmd_set high WLAN_SET = 1. */
+ gpio_set_value(WLAN_SET, 1);
+
+ gpio_direction_output(WLAN_DATA0, 1);
+ gpio_direction_output(WLAN_DATA1, 1);
+ gpio_direction_output(WLAN_DATA2, 1);
+
+ gpio_set_value(WLAN_DATA0, 0);
+ gpio_set_value(WLAN_DATA1, 0);
+ gpio_set_value(WLAN_DATA2, 0);
+
+ /* Prepare command and RF register address that need to sent out.
+ * Make sure that we send only 14 bits from LSB.
+ */
+ rf_cmd_and_addr = (((WLAN_RF_READ_REG_CMD) |
+ (rf_reg_addr << WLAN_RF_REG_ADDR_START_OFFSET)) &
+ WLAN_RF_READ_CMD_MASK);
+
+ for (count = 0; count < 5; count++) {
+ gpio_set_value(WLAN_CLK, 0);
+
+ rf_bit = (rf_cmd_and_addr & 0x1);
+ gpio_set_value(WLAN_DATA0, rf_bit ? 1 : 0);
+ rf_cmd_and_addr = (rf_cmd_and_addr >> 1);
+
+ rf_bit = (rf_cmd_and_addr & 0x1);
+ gpio_set_value(WLAN_DATA1, rf_bit ? 1 : 0);
+ rf_cmd_and_addr = (rf_cmd_and_addr >> 1);
+
+ rf_bit = (rf_cmd_and_addr & 0x1);
+ gpio_set_value(WLAN_DATA2, rf_bit ? 1 : 0);
+ rf_cmd_and_addr = (rf_cmd_and_addr >> 1);
+
+ /* Send the data out WLAN_CLK = 1 */
+ gpio_set_value(WLAN_CLK, 1);
+ }
+
+ /* Pull down the clock signal */
+ gpio_set_value(WLAN_CLK, 0);
+
+ /* Configure data pins to input IO pins */
+ gpio_direction_input(WLAN_DATA0);
+ gpio_direction_input(WLAN_DATA1);
+ gpio_direction_input(WLAN_DATA2);
+
+ for (count = 0; count < 2; count++) {
+ gpio_set_value(WLAN_CLK, 1);
+ gpio_set_value(WLAN_CLK, 0);
+ }
+
+ rf_bit = 0;
+ for (count = 0; count < 6; count++) {
+ gpio_set_value(WLAN_CLK, 1);
+ gpio_set_value(WLAN_CLK, 0);
+
+ rf_bit = gpio_get_value(WLAN_DATA0);
+ rf_data_received |= (rf_bit << (count * 3 + 0));
+
+ if (count != 5) {
+ rf_bit = gpio_get_value(WLAN_DATA1);
+ rf_data_received |= (rf_bit << (count * 3 + 1));
+
+ rf_bit = gpio_get_value(WLAN_DATA2);
+ rf_data_received |= (rf_bit << (count * 3 + 2));
+ }
+ }
+
+ gpio_set_value(WLAN_SET, 0);
+ wcnss_switch_to_5wire();
+
+ return rf_data_received;
+}
diff --git a/arch/arm/mach-msm/board-8974-gpiomux.c b/arch/arm/mach-msm/board-8974-gpiomux.c
index cec1a8f..5d4d379 100755
--- a/arch/arm/mach-msm/board-8974-gpiomux.c
+++ b/arch/arm/mach-msm/board-8974-gpiomux.c
@@ -11,6 +11,7 @@
*
*/
+#include <linux/gpio.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <mach/board.h>
@@ -20,6 +21,12 @@
#define KS8851_IRQ_GPIO 94
+#define WLAN_CLK 40
+#define WLAN_SET 39
+#define WLAN_DATA0 38
+#define WLAN_DATA1 37
+#define WLAN_DATA2 36
+
static struct gpiomux_setting ap2mdm_cfg = {
.func = GPIOMUX_FUNC_GPIO,
.drv = GPIOMUX_DRV_2MA,
@@ -208,6 +215,18 @@
.pull = GPIOMUX_PULL_DOWN,
};
+static struct gpiomux_setting wcnss_5gpio_suspend_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting wcnss_5gpio_active_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_6MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
static struct gpiomux_setting ath_gpio_active_cfg = {
.func = GPIOMUX_FUNC_GPIO,
.drv = GPIOMUX_DRV_2MA,
@@ -1158,6 +1177,43 @@
},
};
+static struct msm_gpiomux_config wcnss_5gpio_interface[] = {
+ {
+ .gpio = 36,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wcnss_5gpio_active_cfg,
+ [GPIOMUX_SUSPENDED] = &wcnss_5gpio_suspend_cfg,
+ },
+ },
+ {
+ .gpio = 37,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wcnss_5gpio_active_cfg,
+ [GPIOMUX_SUSPENDED] = &wcnss_5gpio_suspend_cfg,
+ },
+ },
+ {
+ .gpio = 38,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wcnss_5gpio_active_cfg,
+ [GPIOMUX_SUSPENDED] = &wcnss_5gpio_suspend_cfg,
+ },
+ },
+ {
+ .gpio = 39,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wcnss_5gpio_active_cfg,
+ [GPIOMUX_SUSPENDED] = &wcnss_5gpio_suspend_cfg,
+ },
+ },
+ {
+ .gpio = 40,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wcnss_5gpio_active_cfg,
+ [GPIOMUX_SUSPENDED] = &wcnss_5gpio_suspend_cfg,
+ },
+ },
+};
static struct msm_gpiomux_config ath_gpio_configs[] = {
{
@@ -1467,3 +1523,109 @@
msm_gpiomux_install(apq8074_dragonboard_ts_config,
ARRAY_SIZE(apq8074_dragonboard_ts_config));
}
+
+static void wcnss_switch_to_gpio(void)
+{
+ /* Switch MUX to GPIO */
+ msm_gpiomux_install(wcnss_5gpio_interface,
+ ARRAY_SIZE(wcnss_5gpio_interface));
+
+ /* Ensure GPIO config */
+ gpio_direction_input(WLAN_DATA2);
+ gpio_direction_input(WLAN_DATA1);
+ gpio_direction_input(WLAN_DATA0);
+ gpio_direction_output(WLAN_SET, 0);
+ gpio_direction_output(WLAN_CLK, 0);
+}
+
+static void wcnss_switch_to_5wire(void)
+{
+ msm_gpiomux_install(wcnss_5wire_interface,
+ ARRAY_SIZE(wcnss_5wire_interface));
+}
+
+u32 wcnss_rf_read_reg(u32 rf_reg_addr)
+{
+ int count = 0;
+ u32 rf_cmd_and_addr = 0;
+ u32 rf_data_received = 0;
+ u32 rf_bit = 0;
+
+ wcnss_switch_to_gpio();
+
+ /* Reset the signal if it is already being used. */
+ gpio_set_value(WLAN_SET, 0);
+ gpio_set_value(WLAN_CLK, 0);
+
+ /* We start with cmd_set high WLAN_SET = 1. */
+ gpio_set_value(WLAN_SET, 1);
+
+ gpio_direction_output(WLAN_DATA0, 1);
+ gpio_direction_output(WLAN_DATA1, 1);
+ gpio_direction_output(WLAN_DATA2, 1);
+
+ gpio_set_value(WLAN_DATA0, 0);
+ gpio_set_value(WLAN_DATA1, 0);
+ gpio_set_value(WLAN_DATA2, 0);
+
+ /* Prepare command and RF register address that need to sent out.
+ * Make sure that we send only 14 bits from LSB.
+ */
+ rf_cmd_and_addr = (((WLAN_RF_READ_REG_CMD) |
+ (rf_reg_addr << WLAN_RF_REG_ADDR_START_OFFSET)) &
+ WLAN_RF_READ_CMD_MASK);
+
+ for (count = 0; count < 5; count++) {
+ gpio_set_value(WLAN_CLK, 0);
+
+ rf_bit = (rf_cmd_and_addr & 0x1);
+ gpio_set_value(WLAN_DATA0, rf_bit ? 1 : 0);
+ rf_cmd_and_addr = (rf_cmd_and_addr >> 1);
+
+ rf_bit = (rf_cmd_and_addr & 0x1);
+ gpio_set_value(WLAN_DATA1, rf_bit ? 1 : 0);
+ rf_cmd_and_addr = (rf_cmd_and_addr >> 1);
+
+ rf_bit = (rf_cmd_and_addr & 0x1);
+ gpio_set_value(WLAN_DATA2, rf_bit ? 1 : 0);
+ rf_cmd_and_addr = (rf_cmd_and_addr >> 1);
+
+ /* Send the data out WLAN_CLK = 1 */
+ gpio_set_value(WLAN_CLK, 1);
+ }
+
+ /* Pull down the clock signal */
+ gpio_set_value(WLAN_CLK, 0);
+
+ /* Configure data pins to input IO pins */
+ gpio_direction_input(WLAN_DATA0);
+ gpio_direction_input(WLAN_DATA1);
+ gpio_direction_input(WLAN_DATA2);
+
+ for (count = 0; count < 2; count++) {
+ gpio_set_value(WLAN_CLK, 1);
+ gpio_set_value(WLAN_CLK, 0);
+ }
+
+ rf_bit = 0;
+ for (count = 0; count < 6; count++) {
+ gpio_set_value(WLAN_CLK, 1);
+ gpio_set_value(WLAN_CLK, 0);
+
+ rf_bit = gpio_get_value(WLAN_DATA0);
+ rf_data_received |= (rf_bit << (count * 3 + 0));
+
+ if (count != 5) {
+ rf_bit = gpio_get_value(WLAN_DATA1);
+ rf_data_received |= (rf_bit << (count * 3 + 1));
+
+ rf_bit = gpio_get_value(WLAN_DATA2);
+ rf_data_received |= (rf_bit << (count * 3 + 2));
+ }
+ }
+
+ gpio_set_value(WLAN_SET, 0);
+ wcnss_switch_to_5wire();
+
+ return rf_data_received;
+}
diff --git a/arch/arm/mach-msm/clock-8226.c b/arch/arm/mach-msm/clock-8226.c
index 798a33d..d1f8666 100644
--- a/arch/arm/mach-msm/clock-8226.c
+++ b/arch/arm/mach-msm/clock-8226.c
@@ -2583,17 +2583,6 @@
},
};
-static struct branch_clk mmss_mmssnoc_bto_ahb_clk = {
- .cbcr_reg = MMSS_MMSSNOC_BTO_AHB_CBCR,
- .has_sibling = 1,
- .base = &virt_bases[MMSS_BASE],
- .c = {
- .dbg_name = "mmss_mmssnoc_bto_ahb_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(mmss_mmssnoc_bto_ahb_clk.c),
- },
-};
-
static struct branch_clk mmss_mmssnoc_axi_clk = {
.cbcr_reg = MMSS_MMSSNOC_AXI_CBCR,
.has_sibling = 1,
@@ -2695,7 +2684,6 @@
#ifdef CONFIG_DEBUG_FS
static struct measure_mux_entry measure_mux_MMSS[] = {
- { &mmss_mmssnoc_bto_ahb_clk.c, MMSS_BASE, 0x0002 },
{ &mmss_misc_ahb_clk.c, MMSS_BASE, 0x0003 },
{ &mmss_mmssnoc_axi_clk.c, MMSS_BASE, 0x0004 },
{ &mmss_s0_axi_clk.c, MMSS_BASE, 0x0005 },
@@ -3395,6 +3383,8 @@
CLK_LOOKUP("iface_clk", mdss_ahb_clk.c, "fd922800.qcom,mdss_dsi"),
CLK_LOOKUP("bus_clk", mdss_axi_clk.c, "fd922800.qcom,mdss_dsi"),
CLK_LOOKUP("mdp_core_clk", mdss_mdp_clk.c, "fd922800.qcom,mdss_dsi"),
+ CLK_LOOKUP("core_mmss_clk", mmss_misc_ahb_clk.c,
+ "fd922800.qcom,mdss_dsi"),
CLK_LOOKUP("core_clk", mdss_mdp_clk.c, "fd900000.qcom,mdss_mdp"),
CLK_LOOKUP("lut_clk", mdss_mdp_lut_clk.c, "fd900000.qcom,mdss_mdp"),
@@ -3581,7 +3571,6 @@
CLK_LOOKUP("cam_gp1_clk", camss_gp1_clk.c, ""),
CLK_LOOKUP("iface_clk", camss_micro_ahb_clk.c, ""),
- CLK_LOOKUP("", mmss_mmssnoc_bto_ahb_clk.c, ""),
CLK_LOOKUP("", mmss_mmssnoc_axi_clk.c, ""),
CLK_LOOKUP("", mmss_s0_axi_clk.c, ""),
diff --git a/arch/arm/mach-msm/clock-8610.c b/arch/arm/mach-msm/clock-8610.c
index 8bd3bb5..e9c749a 100644
--- a/arch/arm/mach-msm/clock-8610.c
+++ b/arch/arm/mach-msm/clock-8610.c
@@ -2347,17 +2347,6 @@
},
};
-static struct branch_clk mmss_mmssnoc_bto_ahb_clk = {
- .cbcr_reg = MMSS_MMSSNOC_BTO_AHB_CBCR,
- .has_sibling = 1,
- .base = &virt_bases[MMSS_BASE],
- .c = {
- .dbg_name = "mmss_mmssnoc_bto_ahb_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(mmss_mmssnoc_bto_ahb_clk.c),
- },
-};
-
static struct branch_clk oxili_ahb_clk = {
.cbcr_reg = OXILI_AHB_CBCR,
.bcr_reg = OXILI_AHB_BCR,
@@ -2991,7 +2980,6 @@
CLK_LOOKUP("core_clk", mdp_vsync_clk.c, ""),
CLK_LOOKUP("core_clk", mmss_misc_ahb_clk.c, ""),
CLK_LOOKUP("core_clk", mmss_s0_axi_clk.c, ""),
- CLK_LOOKUP("core_clk", mmss_mmssnoc_bto_ahb_clk.c, ""),
CLK_LOOKUP("core_clk", mmss_mmssnoc_axi_clk.c, ""),
CLK_LOOKUP("core_clk", vfe_clk.c, ""),
CLK_LOOKUP("core_clk", vfe_ahb_clk.c, ""),
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index acfbfc7..b42878d 100755
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -4237,17 +4237,6 @@
},
};
-static struct branch_clk mmss_mmssnoc_bto_ahb_clk = {
- .cbcr_reg = MMSS_MMSSNOC_BTO_AHB_CBCR,
- .has_sibling = 1,
- .base = &virt_bases[MMSS_BASE],
- .c = {
- .dbg_name = "mmss_mmssnoc_bto_ahb_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(mmss_mmssnoc_bto_ahb_clk.c),
- },
-};
-
static struct branch_clk mmss_mmssnoc_axi_clk = {
.cbcr_reg = MMSS_MMSSNOC_AXI_CBCR,
.has_sibling = 1,
@@ -5087,6 +5076,10 @@
CLK_LOOKUP("pixel_clk", mdss_pclk1_clk.c, "fd922e00.qcom,mdss_dsi"),
CLK_LOOKUP("mdp_core_clk", mdss_mdp_clk.c, "fd922800.qcom,mdss_dsi"),
CLK_LOOKUP("mdp_core_clk", mdss_mdp_clk.c, "fd922e00.qcom,mdss_dsi"),
+ CLK_LOOKUP("core_mmss_clk", mmss_misc_ahb_clk.c,
+ "fd922800.qcom,mdss_dsi"),
+ CLK_LOOKUP("core_mmss_clk", mmss_misc_ahb_clk.c,
+ "fd922e00.qcom,mdss_dsi"),
CLK_LOOKUP("iface_clk", mdss_ahb_clk.c, "fd922100.qcom,hdmi_tx"),
CLK_LOOKUP("alt_iface_clk", mdss_hdmi_ahb_clk.c,
"fd922100.qcom,hdmi_tx"),
diff --git a/arch/arm/mach-msm/cpr-regulator.c b/arch/arm/mach-msm/cpr-regulator.c
index b940cb4..d952f82 100644
--- a/arch/arm/mach-msm/cpr-regulator.c
+++ b/arch/arm/mach-msm/cpr-regulator.c
@@ -169,6 +169,8 @@
/* Process voltage variables */
u32 pvs_bin;
u32 speed_bin;
+ u32 pvs_version;
+
/* APC voltage regulator */
struct regulator *vdd_apc;
@@ -1291,14 +1293,48 @@
return rc;
}
-static int cpr_get_of_corner_mappings(struct cpr_regulator *cpr_vreg,
+static void cpr_parse_pvs_version_fuse(struct cpr_regulator *cpr_vreg,
+ struct device_node *of_node)
+{
+ int rc;
+ u64 fuse_bits;
+ u32 fuse_sel[4];
+
+ rc = of_property_read_u32_array(of_node,
+ "qcom,pvs-version-fuse-sel", fuse_sel, 4);
+ if (!rc) {
+ fuse_bits = cpr_read_efuse_row(cpr_vreg,
+ fuse_sel[0], fuse_sel[3]);
+ cpr_vreg->pvs_version = (fuse_bits >> fuse_sel[1]) &
+ ((1 << fuse_sel[2]) - 1);
+ pr_info("[row: %d]: 0x%llx, pvs_version = %d\n",
+ fuse_sel[0], fuse_bits, cpr_vreg->pvs_version);
+ } else {
+ cpr_vreg->pvs_version = UINT_MAX;
+ }
+}
+
+/*
+ * cpr_get_corner_quot_adjustment() -- get the quot_adjust for each corner.
+ *
+ * Get the corner to fuse corner (SVS/NORMAL/TURBO) mappings and corner to
+ * APC clock frequency mappings from device tree.
+ * Calculate the quotient adjustment scaling factor for those corners mapping
+ * to the TURBO fuse corner.
+ * Calculate the quotient adjustment for each corner which map to the TURBO
+ * fuse corner.
+ */
+static int cpr_get_corner_quot_adjustment(struct cpr_regulator *cpr_vreg,
struct device *dev)
{
int rc = 0;
- int i, size, stripe_size;
+ int i, size;
struct property *prop;
- u32 *tmp;
bool corners_mapped;
+ u32 *tmp, *freq_mappings = NULL;
+ u32 scaling, max_factor;
+ u32 corner, turbo_corner = 0, normal_corner = 0, svs_corner = 0;
+ u32 freq_turbo, freq_normal, freq_corner;
prop = of_find_property(dev->of_node, "qcom,cpr-corner-map", NULL);
@@ -1313,81 +1349,182 @@
cpr_vreg->corner_map = devm_kzalloc(dev, sizeof(int) * (size + 1),
GFP_KERNEL);
if (!cpr_vreg->corner_map) {
- pr_err("Can't allocate cpr_vreg->corner_map memory\n");
+ pr_err("Can't allocate memory for cpr_vreg->corner_map\n");
return -ENOMEM;
}
cpr_vreg->num_corners = size;
+ cpr_vreg->quot_adjust = devm_kzalloc(dev,
+ sizeof(u32) * (cpr_vreg->num_corners + 1),
+ GFP_KERNEL);
+ if (!cpr_vreg->quot_adjust) {
+ pr_err("Can't allocate memory for cpr_vreg->quot_adjust\n");
+ return -ENOMEM;
+ }
+
if (!corners_mapped) {
for (i = CPR_FUSE_CORNER_SVS; i < CPR_FUSE_CORNER_MAX; i++)
cpr_vreg->corner_map[i] = i;
+ return 0;
} else {
rc = of_property_read_u32_array(dev->of_node,
"qcom,cpr-corner-map", &cpr_vreg->corner_map[1], size);
if (rc) {
- pr_err("qcom,cpr-corner-map missing, rc = %d", rc);
+ pr_err("qcom,cpr-corner-map missing, rc = %d\n", rc);
return rc;
}
}
- cpr_vreg->quot_adjust = devm_kzalloc(dev,
- sizeof(int) * (cpr_vreg->num_corners + 1),
- GFP_KERNEL);
- if (!cpr_vreg->quot_adjust) {
- pr_err("Can't allocate cpr_vreg->quot_adjust memory\n");
+ prop = of_find_property(dev->of_node,
+ "qcom,cpr-speed-bin-max-corners", NULL);
+ if (!prop) {
+ cpr_debug("qcom,cpr-speed-bin-max-corner missing\n");
+ return 0;
+ }
+
+ size = prop->length / sizeof(u32);
+ tmp = kzalloc(size * sizeof(u32), GFP_KERNEL);
+ if (!tmp) {
+ pr_err("memory alloc failed\n");
return -ENOMEM;
}
-
- prop = of_find_property(dev->of_node, "qcom,cpr-quot-adjust-table",
- NULL);
-
- if (prop) {
- if (!corners_mapped) {
- pr_err("qcom,cpr-corner-map missing\n");
- return -EINVAL;
- }
-
- size = prop->length / sizeof(u32);
- tmp = kzalloc(sizeof(u32) * size, GFP_KERNEL);
- if (!tmp)
- return -ENOMEM;
-
- rc = of_property_read_u32_array(dev->of_node,
- "qcom,cpr-quot-adjust-table", tmp, size);
- if (rc) {
- pr_err("qcom,cpr-quot-adjust-table missing, rc = %d",
- rc);
- kfree(tmp);
- return rc;
- }
-
- stripe_size = sizeof(struct quot_adjust_info) / sizeof(int);
-
- if ((size % stripe_size) != 0) {
- pr_err("qcom,cpr-quot-adjust-table data is not correct");
- kfree(tmp);
- return -EINVAL;
- }
-
- for (i = 0; i < size; i += stripe_size) {
- if (tmp[i] == cpr_vreg->speed_bin) {
- if (tmp[i + 1] >= 1 &&
- tmp[i + 1] <=
- cpr_vreg->num_corners) {
- cpr_vreg->quot_adjust[tmp[i + 1]] =
- tmp[i + 2];
- } else {
- pr_err("qcom,cpr-quot-adjust-table data is not correct");
- kfree(tmp);
- return -EINVAL;
- }
- }
- }
-
+ rc = of_property_read_u32_array(dev->of_node,
+ "qcom,cpr-speed-bin-max-corners", tmp, size);
+ if (rc < 0) {
kfree(tmp);
+ pr_err("get cpr-speed-bin-max-corners failed, rc = %d\n", rc);
+ return rc;
}
+ cpr_parse_pvs_version_fuse(cpr_vreg, dev->of_node);
+
+ /*
+ * According to speed_bin && pvs_version, get the maximum
+ * corner corresponding to SVS/NORMAL/TURBO fuse corner.
+ */
+ for (i = 0; i < size; i += 5) {
+ if (tmp[i] == cpr_vreg->speed_bin &&
+ tmp[i + 1] == cpr_vreg->pvs_version) {
+ svs_corner = tmp[i + 2];
+ normal_corner = tmp[i + 3];
+ turbo_corner = tmp[i + 4];
+ break;
+ }
+ }
+ kfree(tmp);
+ /*
+ * Return success if the virtual corner values read from
+ * qcom,cpr-speed-bin-max-corners property are incorrect,
+ * which make sure the driver could continue run without
+ * error.
+ */
+ if (turbo_corner <= normal_corner ||
+ turbo_corner > cpr_vreg->num_corners) {
+ cpr_debug("turbo:%d should be larger than normal:%d\n",
+ turbo_corner, normal_corner);
+ return 0;
+ }
+
+ prop = of_find_property(dev->of_node,
+ "qcom,cpr-corner-frequency-map", NULL);
+ if (!prop) {
+ cpr_debug("qcom,cpr-corner-frequency-map missing\n");
+ return 0;
+ }
+
+ size = prop->length / sizeof(u32);
+ tmp = kzalloc(sizeof(u32) * size, GFP_KERNEL);
+ if (!tmp) {
+ pr_err("memory alloc failed\n");
+ return -ENOMEM;
+ }
+ rc = of_property_read_u32_array(dev->of_node,
+ "qcom,cpr-corner-frequency-map", tmp, size);
+ if (rc < 0) {
+ pr_err("get cpr-corner-frequency-map failed, rc = %d\n", rc);
+ kfree(tmp);
+ return rc;
+ }
+ freq_mappings = kzalloc(sizeof(u32) * (cpr_vreg->num_corners + 1),
+ GFP_KERNEL);
+ if (!freq_mappings) {
+ pr_err("memory alloc for freq_mappings failed!\n");
+ kfree(tmp);
+ return -ENOMEM;
+ }
+ for (i = 0; i < size; i += 2) {
+ corner = tmp[i];
+ if ((corner < 1) || (corner > cpr_vreg->num_corners)) {
+ pr_err("corner should be in 1~%d range: %d\n",
+ cpr_vreg->num_corners, corner);
+ continue;
+ }
+ freq_mappings[corner] = tmp[i + 1];
+ cpr_debug("Frequency at virtual corner %d is %d Hz.\n",
+ corner, freq_mappings[corner]);
+ }
+ kfree(tmp);
+
+ rc = of_property_read_u32(dev->of_node,
+ "qcom,cpr-quot-adjust-scaling-factor-max",
+ &max_factor);
+ if (rc < 0) {
+ cpr_debug("get cpr-quot-adjust-scaling-factor-max failed\n");
+ kfree(freq_mappings);
+ return 0;
+ }
+
+ /*
+ * Get the quot adjust scaling factor, according to:
+ * scaling =
+ * min(1000 * (QUOT(fused @turbo) - QUOT(fused @normal)) /
+ * (freq_turbo - freq_normal), max_factor)
+ *
+ * @QUOT(fused @turbo): quotient read from fuse for TURBO fuse corner;
+ * @QUOT(fused @normal): quotient read from fuse for NORMAL fuse corner;
+ * @freq_turbo: MHz, max frequency running at TURBO fuse corner;
+ * @freq_normal: MHz, max frequency running at NORMAL fuse corner.
+ */
+
+ freq_turbo = freq_mappings[turbo_corner];
+ freq_normal = freq_mappings[normal_corner];
+ if (freq_normal == 0 || freq_turbo <= freq_normal) {
+ pr_err("freq_turbo: %d should larger than freq_normal: %d\n",
+ freq_turbo, freq_normal);
+ kfree(freq_mappings);
+ return -EINVAL;
+ }
+ freq_turbo /= 1000000; /* MHz */
+ freq_normal /= 1000000;
+ scaling = 1000 *
+ (cpr_vreg->cpr_fuse_target_quot[CPR_FUSE_CORNER_TURBO] -
+ cpr_vreg->cpr_fuse_target_quot[CPR_FUSE_CORNER_NORMAL]) /
+ (freq_turbo - freq_normal);
+ scaling = min(scaling, max_factor);
+ pr_info("quotient adjustment scaling factor: %d.%03d\n",
+ scaling / 1000, scaling % 1000);
+
+ /*
+ * Walk through the corners mapped to the TURBO fuse corner and
+ * calculate the quotient adjustment for each one using the following
+ * formula:
+ * quot_adjust = (freq_turbo - freq_corner) * scaling / 1000
+ *
+ * @freq_turbo: MHz, max frequency running at TURBO fuse corner;
+ * @freq_corner: MHz, frequency running at a corner.
+ */
+ for (i = turbo_corner; i > normal_corner; i--) {
+ freq_corner = freq_mappings[i] / 1000000; /* MHz */
+ if (freq_corner > 0) {
+ cpr_vreg->quot_adjust[i] =
+ scaling * (freq_turbo - freq_corner) / 1000;
+ }
+ pr_info("adjusted quotient[%d] = %d\n", i,
+ (cpr_vreg->cpr_fuse_target_quot[cpr_vreg->corner_map[i]]
+ - cpr_vreg->quot_adjust[i]));
+ }
+ kfree(freq_mappings);
return 0;
}
@@ -1531,7 +1668,7 @@
}
}
- rc = cpr_get_of_corner_mappings(cpr_vreg, &pdev->dev);
+ rc = cpr_get_corner_quot_adjustment(cpr_vreg, &pdev->dev);
if (rc)
return rc;
@@ -1724,12 +1861,12 @@
cpr_vreg->efuse_addr = res->start;
len = res->end - res->start + 1;
- pr_info("efuse_addr = 0x%x (len=0x%x)\n", res->start, len);
+ pr_info("efuse_addr = %pa (len=0x%x)\n", &res->start, len);
cpr_vreg->efuse_base = ioremap(cpr_vreg->efuse_addr, len);
if (!cpr_vreg->efuse_base) {
- pr_err("Unable to map efuse_addr 0x%08x\n",
- cpr_vreg->efuse_addr);
+ pr_err("Unable to map efuse_addr %pa\n",
+ &cpr_vreg->efuse_addr);
return -EINVAL;
}
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index 89e3b51..c7f8b74 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -27,6 +27,12 @@
#include <linux/msm_ssbi.h>
#include <mach/msm_bus.h>
+#define WLAN_RF_REG_ADDR_START_OFFSET 0x3
+#define WLAN_RF_REG_DATA_START_OFFSET 0xf
+#define WLAN_RF_READ_REG_CMD 0x3
+#define WLAN_RF_WRITE_REG_CMD 0x2
+#define WLAN_RF_READ_CMD_MASK 0x3fff
+
struct msm_camera_io_ext {
uint32_t mdcphy;
uint32_t mdcsz;
@@ -677,4 +683,5 @@
extern phys_addr_t msm_shared_ram_phys; /* defined in arch/arm/mach-msm/io.c */
+u32 wcnss_rf_read_reg(u32 rf_reg_addr);
#endif
diff --git a/arch/arm/mach-msm/krait-regulator.c b/arch/arm/mach-msm/krait-regulator.c
index f4456c0..a291b90 100644
--- a/arch/arm/mach-msm/krait-regulator.c
+++ b/arch/arm/mach-msm/krait-regulator.c
@@ -1443,11 +1443,17 @@
{
struct resource *res;
void __iomem *efuse;
- u32 efuse_data, efuse_version;
- bool scaling_factor_valid, use_efuse;
+ u32 efuse_data, efuse_version, efuse_version_data;
+ bool sf_valid, use_efuse;
+ int sf_pos, sf_mask;
+ struct device_node *node = pdev->dev.of_node;
+ struct device *dev = &pdev->dev;
+ int valid_sfs[4] = {0, 0, 0, 0};
+ int sf_versions_len;
+ int rc;
- use_efuse = of_property_read_bool(pdev->dev.of_node,
- "qcom,use-phase-scaling-factor");
+ use_efuse = of_property_read_bool(node,
+ "qcom,use-phase-scaling-factor");
/*
* Allow usage of the eFuse phase scaling factor if it is enabled in
* either device tree or by module parameter.
@@ -1462,6 +1468,7 @@
return -EINVAL;
}
+ /* Read efuse registers */
efuse = ioremap(res->start, 8);
if (!efuse) {
pr_err("could not map phase scaling eFuse address\n");
@@ -1469,25 +1476,47 @@
}
efuse_data = readl_relaxed(efuse);
- efuse_version = readl_relaxed(efuse + 4);
-
+ efuse_version_data = readl_relaxed(efuse + 4);
iounmap(efuse);
- scaling_factor_valid
- = ((efuse_version & PHASE_SCALING_EFUSE_VERSION_MASK) >>
- PHASE_SCALING_EFUSE_VERSION_POS)
- == PHASE_SCALING_EFUSE_VERSION_SET;
+ rc = of_property_read_u32(pdev->dev.of_node,
+ "qcom,phase-scaling-factor-bits-pos",
+ &sf_pos);
+ if (rc < 0) {
+ dev_err(dev, "qcom,phase-scaling-factor-bits-pos missing rc=%d\n",
+ rc);
+ return -EINVAL;
+ }
- if (scaling_factor_valid)
+ sf_mask = KRAIT_MASK(sf_pos + 2, sf_pos);
+
+ efuse_version
+ = ((efuse_version_data & PHASE_SCALING_EFUSE_VERSION_MASK) >>
+ PHASE_SCALING_EFUSE_VERSION_POS);
+
+ if (of_find_property(node, "qcom,valid-scaling-factor-versions",
+ &sf_versions_len)
+ && (sf_versions_len == 4 * sizeof(u32))) {
+ rc = of_property_read_u32_array(node,
+ "qcom,valid-scaling-factor-versions",
+ valid_sfs, 4);
+ sf_valid = (valid_sfs[efuse_version] == 1);
+ } else {
+ dev_err(dev, "qcom,valid-scaling-factor-versions missing or its size is incorrect rc=%d\n",
+ rc);
+ return -EINVAL;
+ }
+
+ if (sf_valid)
pvreg->efuse_phase_scaling_factor
- = ((efuse_data & PHASE_SCALING_EFUSE_VALUE_MASK)
- >> PHASE_SCALING_EFUSE_VALUE_POS) + 1;
+ = ((efuse_data & sf_mask)
+ >> sf_pos) + 1;
else
pvreg->efuse_phase_scaling_factor = PHASE_SCALING_REF;
pr_info("eFuse phase scaling factor = %d/%d%s\n",
pvreg->efuse_phase_scaling_factor, PHASE_SCALING_REF,
- scaling_factor_valid ? "" : " (eFuse not blown)");
+ sf_valid ? "" : " (eFuse not blown)");
pr_info("initial phase scaling factor = %d/%d%s\n",
use_efuse_phase_scaling_factor
? pvreg->efuse_phase_scaling_factor : PHASE_SCALING_REF,
diff --git a/arch/arm/mach-msm/mpm-of.c b/arch/arm/mach-msm/mpm-of.c
index 5b351b4..1fbd077 100644
--- a/arch/arm/mach-msm/mpm-of.c
+++ b/arch/arm/mach-msm/mpm-of.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
@@ -32,6 +32,7 @@
#include <linux/power_supply.h>
#include <linux/regulator/consumer.h>
#include <linux/workqueue.h>
+#include <linux/mutex.h>
#include <asm/hardware/gic.h>
#include <asm/arch_timer.h>
#include <mach/gpio.h>
@@ -567,6 +568,9 @@
}
static void msm_mpm_sys_low_power_modes(bool allow)
{
+ static DEFINE_MUTEX(enable_xo_mutex);
+
+ mutex_lock(&enable_xo_mutex);
if (allow) {
if (xo_enabled) {
clk_disable_unprepare(xo_clk);
@@ -582,6 +586,7 @@
xo_enabled = true;
}
}
+ mutex_unlock(&enable_xo_mutex);
}
void msm_mpm_suspend_prepare(void)
diff --git a/arch/arm/mach-msm/perf_debug.c b/arch/arm/mach-msm/perf_debug.c
index 05d3cef..3a87c78 100644
--- a/arch/arm/mach-msm/perf_debug.c
+++ b/arch/arm/mach-msm/perf_debug.c
@@ -46,6 +46,8 @@
"21 Perf: preserve registers across hotplug\n"
"22 msm: perf: fix formatting of trace entry\n"
"23 msm: perf: Fix cpu id logic in tracectr notifier\n"
+ "24 msm: perf: tracectr: Initialize cnts after hotplug\n"
+ "25 Perf: Reset pmu after hotplug\n"
;
static ssize_t desc_read(struct file *fp, char __user *buf,
diff --git a/arch/arm/mach-msm/perf_trace_counters.c b/arch/arm/mach-msm/perf_trace_counters.c
index 0a679b1..8eb1244 100644
--- a/arch/arm/mach-msm/perf_trace_counters.c
+++ b/arch/arm/mach-msm/perf_trace_counters.c
@@ -21,21 +21,17 @@
DEFINE_PER_CPU(u32[NUM_L1_CTRS], previous_l1_cnts);
DEFINE_PER_CPU(u32[NUM_L2_PERCPU], previous_l2_cnts);
DEFINE_PER_CPU(u32, old_pid);
+DEFINE_PER_CPU(u32, hotplug_flag);
/* Reset per_cpu variables that store counter values uppn CPU hotplug */
static int tracectr_cpu_hotplug_notifier(struct notifier_block *self,
unsigned long action, void *hcpu)
{
int ret = NOTIFY_OK;
int cpu = (int)hcpu;
- int i;
- if ((action & (~CPU_TASKS_FROZEN)) == CPU_UP_PREPARE) {
- per_cpu(previous_ccnt, cpu) = 0;
- for (i = 0; i < NUM_L1_CTRS; i++)
- per_cpu(previous_l1_cnts[i], cpu) = 0;
- for (i = 0; i < NUM_L2_PERCPU; i++)
- per_cpu(previous_l2_cnts[i], cpu) = 0;
- }
+ if ((action & (~CPU_TASKS_FROZEN)) == CPU_STARTING)
+ per_cpu(hotplug_flag, cpu) = 1;
+
return ret;
}
@@ -43,6 +39,35 @@
.notifier_call = tracectr_cpu_hotplug_notifier,
};
+static void setup_prev_cnts(u32 cpu)
+{
+ int i;
+ u32 cnten_val;
+
+ /* Read PMCNTENSET */
+ asm volatile("mrc p15, 0, %0, c9, c12, 1" : "=r"(cnten_val));
+ /* Disable all the counters that were enabled */
+ asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r"(cnten_val));
+ if (cnten_val & CC) {
+ /* Read value */
+ asm volatile("mrc p15, 0, %0, c9, c13, 0"
+ : "=r"(per_cpu(previous_ccnt, cpu)));
+ }
+
+ for (i = 0; i < NUM_L1_CTRS; i++) {
+ if (cnten_val & (1 << i)) {
+ /* Select */
+ asm volatile("mcr p15, 0, %0, c9, c12, 5"
+ : : "r"(i));
+ /* Read value */
+ asm volatile("mrc p15, 0, %0, c9, c13, 2"
+ : "=r"(per_cpu(previous_l1_cnts[i], cpu)));
+ }
+ }
+ /* Enable all the counters that were disabled */
+ asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r"(cnten_val));
+}
+
static int tracectr_notifier(struct notifier_block *self, unsigned long cmd,
void *v)
{
@@ -54,9 +79,14 @@
return -EFAULT;
current_pid = thread->task->pid;
- if (per_cpu(old_pid, cpu) != -1)
- trace_sched_switch_with_ctrs(per_cpu(old_pid, cpu),
- current_pid);
+ if (per_cpu(old_pid, cpu) != -1) {
+ if (per_cpu(hotplug_flag, cpu) == 1) {
+ per_cpu(hotplug_flag, cpu) = 0;
+ setup_prev_cnts(cpu);
+ } else
+ trace_sched_switch_with_ctrs(per_cpu(old_pid, cpu),
+ current_pid);
+ }
per_cpu(old_pid, cpu) = current_pid;
return NOTIFY_OK;
}
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index e7cec58..ab03712 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -393,6 +393,8 @@
[164] = MSM_CPU_8610,
[165] = MSM_CPU_8610,
[166] = MSM_CPU_8610,
+ [225] = MSM_CPU_8610,
+ [226] = MSM_CPU_8610,
/* 8064AB IDs */
[153] = MSM_CPU_8064AB,
@@ -676,6 +678,8 @@
char *buf)
{
uint32_t hw_subtype;
+ WARN_ONCE(1, "Deprecated, use platform_subtype_id instead\n");
+
if (!socinfo) {
pr_err("%s: No socinfo found!\n", __func__);
return 0;
@@ -705,6 +709,18 @@
}
static ssize_t
+socinfo_show_platform_subtype_id(struct sys_device *dev,
+ struct sysdev_attribute *attr,
+ char *buf)
+{
+ uint32_t hw_subtype;
+
+ hw_subtype = socinfo_get_platform_subtype();
+ return snprintf(buf, PAGE_SIZE, "%u\n",
+ hw_subtype);
+}
+
+static ssize_t
socinfo_show_pmic_model(struct sys_device *dev,
struct sysdev_attribute *attr,
char *buf)
@@ -827,6 +843,17 @@
}
static ssize_t
+msm_get_platform_subtype_id(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ uint32_t hw_subtype;
+ hw_subtype = socinfo_get_platform_subtype();
+ return snprintf(buf, PAGE_SIZE, "%u\n",
+ hw_subtype);
+}
+
+static ssize_t
msm_get_pmic_model(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -972,6 +999,8 @@
static struct sysdev_attribute socinfo_v6_files[] = {
_SYSDEV_ATTR(platform_subtype, 0444,
socinfo_show_platform_subtype, NULL),
+ _SYSDEV_ATTR(platform_subtype_id, 0444,
+ socinfo_show_platform_subtype_id, NULL),
};
static struct sysdev_attribute socinfo_v7_files[] = {
@@ -1057,6 +1086,13 @@
__ATTR(platform_subtype, S_IRUGO,
msm_get_platform_subtype, NULL);
+/* Platform Subtype String is being deprecated. Use Platform
+ * Subtype ID instead.
+ */
+static struct device_attribute msm_soc_attr_platform_subtype_id =
+ __ATTR(platform_subtype_id, S_IRUGO,
+ msm_get_platform_subtype_id, NULL);
+
static struct device_attribute msm_soc_attr_pmic_model =
__ATTR(pmic_model, S_IRUGO,
msm_get_pmic_model, NULL);
@@ -1150,6 +1186,8 @@
case 6:
device_create_file(msm_soc_device,
&msm_soc_attr_platform_subtype);
+ device_create_file(msm_soc_device,
+ &msm_soc_attr_platform_subtype_id);
case 5:
device_create_file(msm_soc_device,
&msm_soc_attr_accessory_chip);
diff --git a/block/blk-core.c b/block/blk-core.c
index 00eab3b..7afd6cf 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -1221,8 +1221,9 @@
elv_completed_request(q, req);
- /* this is a bio leak */
- WARN_ON(req->bio != NULL);
+ /* this is a bio leak if the bio is not tagged with BIO_DONTFREE */
+ WARN_ON(req->bio && !bio_flagged(req->bio, BIO_DONTFREE));
+
/*
* Request may not have originated from ll_rw_blk. if not,
@@ -2274,6 +2275,15 @@
blk_account_io_completion(req, nr_bytes);
total_bytes = bio_nbytes = 0;
+
+ /*
+ * Check for this if flagged, Req based dm needs to perform
+ * post processing, hence dont end bios or request.DM
+ * layer takes care.
+ */
+ if (bio_flagged(req->bio, BIO_DONTFREE))
+ return false;
+
while ((bio = req->bio) != NULL) {
int nbytes;
diff --git a/drivers/base/dma-contiguous.c b/drivers/base/dma-contiguous.c
index 885721f..606383a 100644
--- a/drivers/base/dma-contiguous.c
+++ b/drivers/base/dma-contiguous.c
@@ -547,9 +547,9 @@
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);
- free_contig_range(pfn, count);
mutex_unlock(&cma_mutex);
return true;
diff --git a/drivers/cpufreq/cpu-boost.c b/drivers/cpufreq/cpu-boost.c
index f20510d..b4aec53 100644
--- a/drivers/cpufreq/cpu-boost.c
+++ b/drivers/cpufreq/cpu-boost.c
@@ -335,8 +335,6 @@
int cpu, ret;
struct cpu_sync *s;
- cpufreq_register_notifier(&boost_adjust_nb, CPUFREQ_POLICY_NOTIFIER);
-
cpu_boost_wq = alloc_workqueue("cpuboost_wq", WQ_HIGHPRI, 0);
if (!cpu_boost_wq)
return -EFAULT;
@@ -354,10 +352,11 @@
"boost_sync/%d", cpu);
set_cpus_allowed(s->thread, *cpumask_of(cpu));
}
+ cpufreq_register_notifier(&boost_adjust_nb, CPUFREQ_POLICY_NOTIFIER);
atomic_notifier_chain_register(&migration_notifier_head,
&boost_migration_nb);
-
ret = input_register_handler(&cpuboost_input_handler);
+
return 0;
}
late_initcall(cpu_boost_init);
diff --git a/drivers/crypto/msm/qcrypto.c b/drivers/crypto/msm/qcrypto.c
index 3aebaf0..48dc6ec 100644
--- a/drivers/crypto/msm/qcrypto.c
+++ b/drivers/crypto/msm/qcrypto.c
@@ -39,6 +39,7 @@
#include <crypto/authenc.h>
#include <crypto/scatterwalk.h>
#include <crypto/internal/hash.h>
+#include <crypto/internal/aead.h>
#include <mach/scm.h>
#include <linux/platform_data/qcom_crypto_device.h>
@@ -66,6 +67,8 @@
u32 aead_sha1_3des_dec;
u32 aead_ccm_aes_enc;
u32 aead_ccm_aes_dec;
+ u32 aead_rfc4309_ccm_aes_enc;
+ u32 aead_rfc4309_ccm_aes_dec;
u32 aead_op_success;
u32 aead_op_fail;
u32 aead_bad_msg;
@@ -231,6 +234,8 @@
/* max of AES_BLOCK_SIZE, DES3_EDE_BLOCK_SIZE */
#define QCRYPTO_MAX_IV_LENGTH 16
+#define QCRYPTO_CCM4309_NONCE_LEN 3
+
struct qcrypto_cipher_ctx {
u8 auth_key[QCRYPTO_MAX_KEY_SIZE];
u8 iv[QCRYPTO_MAX_IV_LENGTH];
@@ -244,10 +249,12 @@
struct crypto_priv *cp;
unsigned int flags;
struct crypto_engine *pengine; /* fixed engine assigned */
+ u8 ccm4309_nonce[QCRYPTO_CCM4309_NONCE_LEN];
};
struct qcrypto_cipher_req_ctx {
u8 *iv;
+ u8 rfc4309_iv[QCRYPTO_MAX_IV_LENGTH];
unsigned int ivsize;
int aead;
struct scatterlist asg; /* Formatted associated data sg */
@@ -736,7 +743,12 @@
len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" AEAD CCM-AES decryption : %d\n",
pstat->aead_ccm_aes_dec);
-
+ len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ " AEAD RFC4309-CCM-AES encryption : %d\n",
+ pstat->aead_rfc4309_ccm_aes_enc);
+ len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ " AEAD RFC4309-CCM-AES decryption : %d\n",
+ pstat->aead_rfc4309_ccm_aes_dec);
len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" AEAD operation success : %d\n",
pstat->aead_op_success);
@@ -1272,6 +1284,12 @@
uint32_t bytes = 0;
uint32_t num_sg = 0;
+ if (alen == 0) {
+ qreq->assoc = NULL;
+ qreq->assoclen = 0;
+ return 0;
+ }
+
qreq->assoc = kzalloc((alen + 0x64), GFP_ATOMIC);
if (!qreq->assoc) {
pr_err("qcrypto Memory allocation of adata FAIL, error %ld\n",
@@ -1455,7 +1473,10 @@
qreq.authkey = cipher_ctx->auth_key;
qreq.authklen = cipher_ctx->auth_key_len;
qreq.authsize = crypto_aead_authsize(aead);
- qreq.ivsize = crypto_aead_ivsize(aead);
+ if (qreq.mode == QCE_MODE_CCM)
+ qreq.ivsize = AES_BLOCK_SIZE;
+ else
+ qreq.ivsize = crypto_aead_ivsize(aead);
qreq.flags = cipher_ctx->flags;
if (qreq.mode == QCE_MODE_CCM) {
@@ -1502,8 +1523,9 @@
kzfree(qreq.assoc);
return -ENOMEM;
}
-
- memcpy((char *)rctx->data, qreq.assoc, qreq.assoclen);
+ if (qreq.assoclen)
+ memcpy((char *)rctx->data, qreq.assoc,
+ qreq.assoclen);
num_sg = qcrypto_count_sg(req->src, req->cryptlen);
bytes = qcrypto_sg_copy_to_buffer(req->src, num_sg,
@@ -1845,6 +1867,29 @@
return _qcrypto_queue_req(cp, ctx->pengine, &req->base);
}
+static int _qcrypto_aead_rfc4309_enc_aes_ccm(struct aead_request *req)
+{
+ struct qcrypto_cipher_req_ctx *rctx;
+ struct qcrypto_cipher_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
+ struct crypto_priv *cp = ctx->cp;
+ struct crypto_stat *pstat;
+
+ pstat = &_qcrypto_stat;
+
+ rctx = aead_request_ctx(req);
+ rctx->aead = 1;
+ rctx->alg = CIPHER_ALG_AES;
+ rctx->dir = QCE_ENCRYPT;
+ rctx->mode = QCE_MODE_CCM;
+ memset(rctx->rfc4309_iv, 0, sizeof(rctx->rfc4309_iv));
+ rctx->rfc4309_iv[0] = 3; /* L -1 */
+ memcpy(&rctx->rfc4309_iv[1], ctx->ccm4309_nonce, 3);
+ memcpy(&rctx->rfc4309_iv[4], req->iv, 8);
+ rctx->iv = rctx->rfc4309_iv;
+ pstat->aead_rfc4309_ccm_aes_enc++;
+ return _qcrypto_queue_req(cp, ctx->pengine, &req->base);
+}
+
static int _qcrypto_enc_des_ecb(struct ablkcipher_request *req)
{
struct qcrypto_cipher_req_ctx *rctx;
@@ -2136,6 +2181,27 @@
return _qcrypto_queue_req(cp, ctx->pengine, &req->base);
}
+static int _qcrypto_aead_rfc4309_dec_aes_ccm(struct aead_request *req)
+{
+ struct qcrypto_cipher_req_ctx *rctx;
+ struct qcrypto_cipher_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
+ struct crypto_priv *cp = ctx->cp;
+ struct crypto_stat *pstat;
+
+ pstat = &_qcrypto_stat;
+ rctx = aead_request_ctx(req);
+ rctx->aead = 1;
+ rctx->alg = CIPHER_ALG_AES;
+ rctx->dir = QCE_DECRYPT;
+ rctx->mode = QCE_MODE_CCM;
+ memset(rctx->rfc4309_iv, 0, sizeof(rctx->rfc4309_iv));
+ rctx->rfc4309_iv[0] = 3; /* L -1 */
+ memcpy(&rctx->rfc4309_iv[1], ctx->ccm4309_nonce, 3);
+ memcpy(&rctx->rfc4309_iv[4], req->iv, 8);
+ rctx->iv = rctx->rfc4309_iv;
+ pstat->aead_rfc4309_ccm_aes_dec++;
+ return _qcrypto_queue_req(cp, ctx->pengine, &req->base);
+}
static int _qcrypto_aead_setauthsize(struct crypto_aead *authenc,
unsigned int authsize)
{
@@ -2166,6 +2232,24 @@
return 0;
}
+static int _qcrypto_aead_rfc4309_ccm_setauthsize(struct crypto_aead *authenc,
+ unsigned int authsize)
+{
+ struct qcrypto_cipher_ctx *ctx = crypto_aead_ctx(authenc);
+
+ switch (authsize) {
+ case 8:
+ case 12:
+ case 16:
+ break;
+ default:
+ return -EINVAL;
+ }
+ ctx->authsize = authsize;
+ return 0;
+}
+
+
static int _qcrypto_aead_setkey(struct crypto_aead *tfm, const u8 *key,
unsigned int keylen)
{
@@ -2231,6 +2315,21 @@
return 0;
}
+static int _qcrypto_aead_rfc4309_ccm_setkey(struct crypto_aead *aead,
+ const u8 *key, unsigned int key_len)
+{
+ struct crypto_tfm *tfm = crypto_aead_tfm(aead);
+ struct qcrypto_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
+ int ret;
+
+ if (key_len < QCRYPTO_CCM4309_NONCE_LEN)
+ return -EINVAL;
+ key_len -= QCRYPTO_CCM4309_NONCE_LEN;
+ memcpy(ctx->ccm4309_nonce, key + key_len, QCRYPTO_CCM4309_NONCE_LEN);
+ ret = _qcrypto_aead_ccm_setkey(aead, key, key_len);
+ return ret;
+};
+
static int _qcrypto_aead_encrypt_aes_cbc(struct aead_request *req)
{
struct qcrypto_cipher_req_ctx *rctx;
@@ -3762,7 +3861,7 @@
.cra_u = {
.aead = {
.ivsize = AES_BLOCK_SIZE,
- .maxauthsize = SHA1_DIGEST_SIZE,
+ .maxauthsize = AES_BLOCK_SIZE,
.setkey = _qcrypto_aead_ccm_setkey,
.setauthsize = _qcrypto_aead_ccm_setauthsize,
.encrypt = _qcrypto_aead_encrypt_aes_ccm,
@@ -3772,6 +3871,31 @@
}
};
+static struct crypto_alg _qcrypto_aead_rfc4309_ccm_algo = {
+ .cra_name = "rfc4309(ccm(aes))",
+ .cra_driver_name = "qcrypto-rfc4309-aes-ccm",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC,
+ .cra_blocksize = 1,
+ .cra_ctxsize = sizeof(struct qcrypto_cipher_ctx),
+ .cra_alignmask = 0,
+ .cra_type = &crypto_nivaead_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = _qcrypto_cra_aead_init,
+ .cra_exit = _qcrypto_cra_aead_exit,
+ .cra_u = {
+ .aead = {
+ .ivsize = 8,
+ .maxauthsize = 16,
+ .setkey = _qcrypto_aead_rfc4309_ccm_setkey,
+ .setauthsize = _qcrypto_aead_rfc4309_ccm_setauthsize,
+ .encrypt = _qcrypto_aead_rfc4309_enc_aes_ccm,
+ .decrypt = _qcrypto_aead_rfc4309_dec_aes_ccm,
+ .geniv = "seqiv",
+ }
+ }
+};
+
static int _qcrypto_probe(struct platform_device *pdev)
{
@@ -4078,6 +4202,36 @@
dev_info(&pdev->dev, "%s\n",
q_alg->cipher_alg.cra_driver_name);
}
+
+ q_alg = _qcrypto_cipher_alg_alloc(cp,
+ &_qcrypto_aead_rfc4309_ccm_algo);
+ if (IS_ERR(q_alg)) {
+ rc = PTR_ERR(q_alg);
+ goto err;
+ }
+
+ if (cp->ce_support.use_sw_aes_ccm_algo) {
+ rc = _qcrypto_prefix_alg_cra_name(
+ q_alg->cipher_alg.cra_name,
+ strlen(q_alg->cipher_alg.cra_name));
+ if (rc) {
+ dev_err(&pdev->dev,
+ "The algorithm name %s is too long.\n",
+ q_alg->cipher_alg.cra_name);
+ kfree(q_alg);
+ goto err;
+ }
+ }
+ rc = crypto_register_alg(&q_alg->cipher_alg);
+ if (rc) {
+ dev_err(&pdev->dev, "%s alg registration failed\n",
+ q_alg->cipher_alg.cra_driver_name);
+ kfree(q_alg);
+ } else {
+ list_add_tail(&q_alg->entry, &cp->alg_list);
+ dev_info(&pdev->dev, "%s\n",
+ q_alg->cipher_alg.cra_driver_name);
+ }
}
mutex_unlock(&cp->engine_lock);
diff --git a/drivers/gpio/qpnp-pin.c b/drivers/gpio/qpnp-pin.c
index 8d934df..6176df9 100644
--- a/drivers/gpio/qpnp-pin.c
+++ b/drivers/gpio/qpnp-pin.c
@@ -182,6 +182,7 @@
struct device_node *int_ctrl;
struct list_head chip_list;
struct dentry *dfs_dir;
+ bool chip_registered;
};
static LIST_HEAD(qpnp_pin_chips);
@@ -912,7 +913,7 @@
static int qpnp_pin_free_chip(struct qpnp_pin_chip *q_chip)
{
struct spmi_device *spmi = q_chip->spmi;
- int rc, i;
+ int i, rc = 0;
if (q_chip->chip_gpios)
for (i = 0; i < spmi->num_dev_node; i++)
@@ -921,10 +922,12 @@
mutex_lock(&qpnp_pin_chips_lock);
list_del(&q_chip->chip_list);
mutex_unlock(&qpnp_pin_chips_lock);
- rc = gpiochip_remove(&q_chip->gpio_chip);
- if (rc)
- dev_err(&q_chip->spmi->dev, "%s: unable to remove gpio\n",
- __func__);
+ if (q_chip->chip_registered) {
+ rc = gpiochip_remove(&q_chip->gpio_chip);
+ if (rc)
+ dev_err(&q_chip->spmi->dev, "%s: unable to remove gpio\n",
+ __func__);
+ }
kfree(q_chip->chip_gpios);
kfree(q_chip->pmic_pins);
kfree(q_chip);
@@ -1342,6 +1345,7 @@
goto err_probe;
}
+ q_chip->chip_registered = true;
/* now configure gpio config defaults if they exist */
for (i = 0; i < spmi->num_dev_node; i++) {
q_spec = qpnp_chip_gpio_get_spec(q_chip, i);
diff --git a/drivers/gpu/ion/ion_heap.c b/drivers/gpu/ion/ion_heap.c
index 6261d89..aa2551a 100644
--- a/drivers/gpu/ion/ion_heap.c
+++ b/drivers/gpu/ion/ion_heap.c
@@ -141,9 +141,11 @@
if (!ptr)
return -ENOMEM;
- memset(ptr, 0, npages_to_vmap * PAGE_SIZE);
/*
- * invalidate the cache to pick up the zeroing
+ * We have to invalidate the cache here because there
+ * might be dirty lines to these physical pages (which
+ * we don't care about) that could get written out at
+ * any moment.
*/
for (k = 0; k < npages_to_vmap; k++) {
void *p = kmap_atomic(pages[i + k]);
@@ -154,6 +156,7 @@
outer_inv_range(phys, phys + PAGE_SIZE);
kunmap_atomic(p);
}
+ memset(ptr, 0, npages_to_vmap * PAGE_SIZE);
vunmap(ptr);
}
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index a796790..7a92fe6 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -1625,17 +1625,19 @@
goto err;
}
- ret = of_property_read_u32_array(child, "reg", reg_val, 2);
- if (ret) {
- KGSL_CORE_ERR("Unable to read KGSL IOMMU 'reg'\n");
+ if (!strcmp("gfx3d_user", ctxs[ctx_index].iommu_ctx_name)) {
+ ctxs[ctx_index].ctx_id = 0;
+ } else if (!strcmp("gfx3d_priv",
+ ctxs[ctx_index].iommu_ctx_name)) {
+ ctxs[ctx_index].ctx_id = 1;
+ } else if (!strcmp("gfx3d_spare",
+ ctxs[ctx_index].iommu_ctx_name)) {
+ ctxs[ctx_index].ctx_id = 2;
+ } else {
+ KGSL_CORE_ERR("dt: IOMMU context %s is invalid\n",
+ ctxs[ctx_index].iommu_ctx_name);
goto err;
}
- if (msm_soc_version_supports_iommu_v0())
- ctxs[ctx_index].ctx_id = (reg_val[0] -
- data->physstart) >> KGSL_IOMMU_CTX_SHIFT;
- else
- ctxs[ctx_index].ctx_id = ((reg_val[0] -
- data->physstart) >> KGSL_IOMMU_CTX_SHIFT) - 8;
ctx_index++;
}
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 0f1e01d..e2ea262 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -191,8 +191,6 @@
unsigned int fast_hang_detect;
unsigned int ft_policy;
unsigned int long_ib_detect;
- unsigned int long_ib;
- unsigned int long_ib_ts;
unsigned int ft_pf_policy;
unsigned int gpulist_index;
struct ocmem_buf *ocmem_hdl;
diff --git a/drivers/gpu/msm/adreno_dispatch.c b/drivers/gpu/msm/adreno_dispatch.c
index 95e4017..48d0210 100644
--- a/drivers/gpu/msm/adreno_dispatch.c
+++ b/drivers/gpu/msm/adreno_dispatch.c
@@ -951,9 +951,6 @@
adreno_readreg(adreno_dev, ADRENO_REG_CP_ME_CNTL, ®);
reg |= (1 << 27) | (1 << 28);
adreno_writereg(adreno_dev, ADRENO_REG_CP_ME_CNTL, reg);
-
- /* Skip the PM dump for a timeout because it confuses people */
- set_bit(KGSL_FT_SKIP_PMDUMP, &cmdbatch->fault_policy);
}
adreno_readreg(adreno_dev, ADRENO_REG_CP_IB1_BASE, &base);
diff --git a/drivers/gpu/msm/adreno_drawctxt.h b/drivers/gpu/msm/adreno_drawctxt.h
index 7656cd5..258cf94 100644
--- a/drivers/gpu/msm/adreno_drawctxt.h
+++ b/drivers/gpu/msm/adreno_drawctxt.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2007-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2002,2007-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
@@ -133,7 +133,6 @@
*/
struct adreno_context {
struct kgsl_context base;
- unsigned int ib_gpu_time_used;
unsigned int timestamp;
unsigned int internal_timestamp;
int state;
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index 7d009ce..98fd731 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -28,7 +28,6 @@
#define KGSL_TIMEOUT_NONE 0
#define KGSL_TIMEOUT_DEFAULT 0xFFFFFFFF
#define KGSL_TIMEOUT_PART 50 /* 50 msec */
-#define KGSL_TIMEOUT_LONG_IB_DETECTION 2000 /* 2 sec*/
#define FIRST_TIMEOUT (HZ / 2)
@@ -723,4 +722,23 @@
return ret;
}
+/**
+ * kgsl_sysfs_store() - parse a string from a sysfs store function
+ * @buf: Incoming string to parse
+ * @ptr: Pointer to an unsigned int to store the value
+ */
+static inline int kgsl_sysfs_store(const char *buf, unsigned int *ptr)
+{
+ unsigned int val;
+ int rc;
+
+ rc = kstrtou32(buf, 0, &val);
+ if (rc)
+ return rc;
+
+ if (ptr)
+ *ptr = val;
+
+ return 0;
+}
#endif /* __KGSL_DEVICE_H */
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 7ecc546..656d7e2 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -220,19 +220,18 @@
{
struct kgsl_device *device = kgsl_device_from_dev(dev);
struct kgsl_pwrctrl *pwr;
- int ret, level;
+ int ret;
+ unsigned int level = 0;
if (device == NULL)
return 0;
pwr = &device->pwrctrl;
- ret = sscanf(buf, "%d", &level);
- if (ret != 1)
- return count;
+ ret = kgsl_sysfs_store(buf, &level);
- if (level < 0)
- return count;
+ if (ret)
+ return ret;
mutex_lock(&device->mutex);
@@ -274,20 +273,17 @@
{
struct kgsl_device *device = kgsl_device_from_dev(dev);
struct kgsl_pwrctrl *pwr;
- int ret, level, max_level;
+ int ret, max_level;
+ unsigned int level = 0;
if (device == NULL)
return 0;
pwr = &device->pwrctrl;
- ret = sscanf(buf, "%d", &level);
- if (ret != 1)
- return count;
-
- /* If the use specifies a negative number, then don't change anything */
- if (level < 0)
- return count;
+ ret = kgsl_sysfs_store(buf, &level);
+ if (ret)
+ return ret;
mutex_lock(&device->mutex);
@@ -329,20 +325,17 @@
const char *buf, size_t count)
{ struct kgsl_device *device = kgsl_device_from_dev(dev);
struct kgsl_pwrctrl *pwr;
- int ret, level, min_level;
+ int ret, min_level;
+ unsigned int level = 0;
if (device == NULL)
return 0;
pwr = &device->pwrctrl;
- ret = sscanf(buf, "%d", &level);
- if (ret != 1)
- return count;
-
- /* Don't do anything on obviously incorrect values */
- if (level < 0)
- return count;
+ ret = kgsl_sysfs_store(buf, &level);
+ if (ret)
+ return ret;
mutex_lock(&device->mutex);
if (level > pwr->num_pwrlevels - 2)
@@ -413,7 +406,7 @@
{
struct kgsl_device *device = kgsl_device_from_dev(dev);
struct kgsl_pwrctrl *pwr;
- unsigned long val;
+ unsigned int val = 0;
int ret, level;
if (device == NULL)
@@ -421,9 +414,9 @@
pwr = &device->pwrctrl;
- ret = sscanf(buf, "%ld", &val);
- if (ret != 1)
- return count;
+ ret = kgsl_sysfs_store(buf, &val);
+ if (ret)
+ return ret;
mutex_lock(&device->mutex);
level = _get_nearest_pwrlevel(pwr, val);
@@ -465,7 +458,7 @@
{
struct kgsl_device *device = kgsl_device_from_dev(dev);
struct kgsl_pwrctrl *pwr;
- unsigned long val;
+ unsigned int val = 0;
int ret, level;
if (device == NULL)
@@ -473,9 +466,9 @@
pwr = &device->pwrctrl;
- ret = sscanf(buf, "%ld", &val);
- if (ret != 1)
- return count;
+ ret = kgsl_sysfs_store(buf, &val);
+ if (ret)
+ return ret;
mutex_lock(&device->mutex);
level = _get_nearest_pwrlevel(pwr, val);
@@ -502,22 +495,19 @@
struct device_attribute *attr,
const char *buf, size_t count)
{
- char temp[20];
- unsigned long val;
+ unsigned int val = 0;
struct kgsl_device *device = kgsl_device_from_dev(dev);
struct kgsl_pwrctrl *pwr;
const long div = 1000/HZ;
- int rc;
+ int ret;
if (device == NULL)
return 0;
pwr = &device->pwrctrl;
- snprintf(temp, sizeof(temp), "%.*s",
- (int)min(count, sizeof(temp) - 1), buf);
- rc = strict_strtoul(temp, 0, &val);
- if (rc)
- return rc;
+ ret = kgsl_sysfs_store(buf, &val);
+ if (ret)
+ return ret;
mutex_lock(&device->mutex);
@@ -547,19 +537,16 @@
struct device_attribute *attr,
const char *buf, size_t count)
{
- char temp[20];
- unsigned long val;
+ unsigned int val = 0;
struct kgsl_device *device = kgsl_device_from_dev(dev);
- int rc;
+ int ret;
if (device == NULL)
return 0;
- snprintf(temp, sizeof(temp), "%.*s",
- (int)min(count, sizeof(temp) - 1), buf);
- rc = kstrtoul(temp, 0, &val);
- if (rc)
- return rc;
+ ret = kgsl_sysfs_store(buf, &val);
+ if (ret)
+ return ret;
mutex_lock(&device->mutex);
device->pwrctrl.pm_qos_latency = val;
@@ -694,19 +681,16 @@
const char *buf, size_t count,
int flag)
{
- char temp[20];
- unsigned long val;
+ unsigned int val = 0;
struct kgsl_device *device = kgsl_device_from_dev(dev);
- int rc;
+ int ret;
if (device == NULL)
return 0;
- snprintf(temp, sizeof(temp), "%.*s",
- (int)min(count, sizeof(temp) - 1), buf);
- rc = kstrtoul(temp, 0, &val);
- if (rc)
- return rc;
+ ret = kgsl_sysfs_store(buf, &val);
+ if (ret)
+ return ret;
mutex_lock(&device->mutex);
__force_on(device, flag, val);
@@ -772,19 +756,16 @@
struct device_attribute *attr,
const char *buf, size_t count)
{
- char temp[20];
- unsigned long val;
+ unsigned int val = 0;
struct kgsl_device *device = kgsl_device_from_dev(dev);
- int rc;
+ int ret;
if (device == NULL)
return 0;
- snprintf(temp, sizeof(temp), "%.*s",
- (int)min(count, sizeof(temp) - 1), buf);
- rc = kstrtoul(temp, 0, &val);
- if (rc)
- return rc;
+ ret = kgsl_sysfs_store(buf, &val);
+ if (ret)
+ return ret;
mutex_lock(&device->mutex);
device->pwrctrl.bus_control = val ? true : false;
diff --git a/drivers/gud/mobicore_driver/platforms/msm8960_surf_std/platform.h b/drivers/gud/mobicore_driver/platforms/msm8960_surf_std/platform.h
index 7854fc5..9d128ae 100644
--- a/drivers/gud/mobicore_driver/platforms/msm8960_surf_std/platform.h
+++ b/drivers/gud/mobicore_driver/platforms/msm8960_surf_std/platform.h
@@ -45,8 +45,7 @@
#define MC_VM_UNMAP
#endif
-
-#if defined(CONFIG_ARCH_MSM8974) || defined(CONFIG_ARCH_MSM8226)
+#if defined (CONFIG_ARCH_MSM8974) || defined (CONFIG_ARCH_MSM8226)
/* Perform clock enable/disable */
#define MC_CRYPTO_CLOCK_MANAGEMENT
#endif
diff --git a/drivers/leds/leds-qpnp.c b/drivers/leds/leds-qpnp.c
index 9208599..d87520f 100644
--- a/drivers/leds/leds-qpnp.c
+++ b/drivers/leds/leds-qpnp.c
@@ -619,7 +619,7 @@
for (i = 0; i < num_wled_strings; i++) {
rc = qpnp_led_masked_write(led,
WLED_FULL_SCALE_REG(led->base, i),
- WLED_MAX_CURR_MASK, led->max_current);
+ WLED_MAX_CURR_MASK, (u8)led->max_current);
if (rc) {
dev_err(&led->spmi_dev->dev,
"Write max current failure (%d)\n",
@@ -689,7 +689,8 @@
static int qpnp_mpp_set(struct qpnp_led_data *led)
{
- int rc, val;
+ int rc;
+ u8 val;
int duty_us;
if (led->cdev.brightness) {
@@ -1604,7 +1605,7 @@
rc = qpnp_led_masked_write(led,
WLED_FULL_SCALE_REG(led->base, i), WLED_MAX_CURR_MASK,
- led->max_current);
+ (u8)led->max_current);
if (rc) {
dev_err(&led->spmi_dev->dev,
"WLED max current reg write failed(%d)\n", rc);
@@ -2445,8 +2446,8 @@
static int __devinit qpnp_mpp_init(struct qpnp_led_data *led)
{
- int rc, val;
-
+ int rc;
+ u8 val;
if (led->max_current < LED_MPP_CURRENT_MIN ||
led->max_current > LED_MPP_CURRENT_MAX) {
diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig
index 10f122a..67df573 100644
--- a/drivers/md/Kconfig
+++ b/drivers/md/Kconfig
@@ -237,6 +237,23 @@
If unsure, say N.
+config DM_REQ_CRYPT
+ tristate "Crypt target support"
+ depends on BLK_DEV_DM
+ select XTS
+ select CRYPTO_XTS
+ ---help---
+ This request based device-mapper target allows you to create a device that
+ transparently encrypts the data on it. You'll need to activate
+ the ciphers you're going to use in the cryptoapi configuration.
+ The DM REQ CRYPT operates on requests (bigger payloads) to utilize
+ crypto hardware better.
+
+ To compile this code as a module, choose M here: the module will
+ be called dm-req-crypt.
+
+ If unsure, say N.
+
config DM_SNAPSHOT
tristate "Snapshot target"
depends on BLK_DEV_DM
diff --git a/drivers/md/Makefile b/drivers/md/Makefile
index 8b2e0df..7b16079 100644
--- a/drivers/md/Makefile
+++ b/drivers/md/Makefile
@@ -43,7 +43,7 @@
obj-$(CONFIG_DM_RAID) += dm-raid.o
obj-$(CONFIG_DM_THIN_PROVISIONING) += dm-thin-pool.o
obj-$(CONFIG_DM_VERITY) += dm-verity.o
-
+obj-$(CONFIG_DM_REQ_CRYPT) += dm-req-crypt.o
ifeq ($(CONFIG_DM_UEVENT),y)
dm-mod-objs += dm-uevent.o
endif
diff --git a/drivers/md/dm-req-crypt.c b/drivers/md/dm-req-crypt.c
new file mode 100644
index 0000000..ab21404
--- /dev/null
+++ b/drivers/md/dm-req-crypt.c
@@ -0,0 +1,752 @@
+/* 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/completion.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/bio.h>
+#include <linux/blkdev.h>
+#include <linux/mempool.h>
+#include <linux/slab.h>
+#include <linux/crypto.h>
+#include <linux/workqueue.h>
+#include <linux/backing-dev.h>
+#include <linux/atomic.h>
+#include <linux/scatterlist.h>
+#include <crypto/scatterwalk.h>
+#include <asm/page.h>
+#include <asm/unaligned.h>
+#include <crypto/hash.h>
+#include <crypto/md5.h>
+#include <crypto/algapi.h>
+#include <mach/qcrypto.h>
+
+#include <linux/device-mapper.h>
+
+
+#define DM_MSG_PREFIX "req-crypt"
+
+#define MAX_SG_LIST 1024
+#define REQ_DM_512_KB (512*1024)
+#define MAX_ENCRYPTION_BUFFERS 1
+#define MIN_IOS 16
+#define MIN_POOL_PAGES 32
+#define KEY_SIZE_XTS 64
+#define AES_XTS_IV_LEN 16
+
+#define DM_REQ_CRYPT_ERROR -1
+
+struct req_crypt_result {
+ struct completion completion;
+ int err;
+};
+
+struct dm_dev *dev;
+static struct kmem_cache *_req_crypt_io_pool;
+sector_t start_sector_orig;
+struct workqueue_struct *req_crypt_queue;
+mempool_t *req_io_pool;
+mempool_t *req_page_pool;
+struct crypto_ablkcipher *tfm;
+
+struct req_dm_crypt_io {
+ struct work_struct work;
+ struct request *cloned_request;
+ int error;
+ atomic_t pending;
+ struct timespec start_time;
+};
+
+static void req_crypt_cipher_complete
+ (struct crypto_async_request *req, int err);
+
+
+static void req_crypt_inc_pending(struct req_dm_crypt_io *io)
+{
+ atomic_inc(&io->pending);
+}
+
+static void req_crypt_dec_pending_encrypt(struct req_dm_crypt_io *io)
+{
+ int error = 0;
+ struct request *clone = NULL;
+
+ if (io) {
+ error = io->error;
+ if (io->cloned_request) {
+ clone = io->cloned_request;
+ } else {
+ DMERR("%s io->cloned_request is NULL\n",
+ __func__);
+ /*
+ * If Clone is NULL we cannot do anything,
+ * this should never happen
+ */
+ BUG();
+ }
+ } else {
+ DMERR("%s io is NULL\n", __func__);
+ /*
+ * If Clone is NULL we cannot do anything,
+ * this should never happen
+ */
+ BUG();
+ }
+
+ atomic_dec(&io->pending);
+
+ if (error < 0)
+ dm_kill_unmapped_request(clone, error);
+ else
+ dm_dispatch_request(clone);
+}
+
+static void req_crypt_dec_pending_decrypt(struct req_dm_crypt_io *io)
+{
+ int error = 0;
+ struct request *clone = NULL;
+
+ if (io) {
+ error = io->error;
+ if (io->cloned_request) {
+ clone = io->cloned_request;
+ } else {
+ DMERR("%s io->cloned_request is NULL\n",
+ __func__);
+ /*
+ * If Clone is NULL we cannot do anything,
+ * this should never happen
+ */
+ BUG();
+ }
+ } else {
+ DMERR("%s io is NULL\n",
+ __func__);
+ /*
+ * If Clone is NULL we cannot do anything,
+ * this should never happen
+ */
+ BUG();
+ }
+
+ /* Should never get here if io or Clone is NULL */
+ dm_end_request(clone, error);
+ atomic_dec(&io->pending);
+ mempool_free(io, req_io_pool);
+}
+
+/*
+ * The callback that will be called by the worker queue to perform Decryption
+ * for reads and use the dm function to complete the bios and requests.
+ */
+static void req_cryptd_crypt_read_convert(struct req_dm_crypt_io *io)
+{
+ struct request *clone = NULL;
+ int error = 0;
+ int total_sg_len = 0, rc = 0, total_bytes_in_req = 0;
+ struct ablkcipher_request *req = NULL;
+ struct req_crypt_result result;
+ struct scatterlist *req_sg_read = NULL;
+ int err = 0;
+ struct req_iterator iter2;
+ struct bio_vec *bvec = NULL;
+ u8 IV[AES_XTS_IV_LEN];
+
+ if (io) {
+ error = io->error;
+ if (io->cloned_request) {
+ clone = io->cloned_request;
+ } else {
+ DMERR("%s io->cloned_request is NULL\n",
+ __func__);
+ error = DM_REQ_CRYPT_ERROR;
+ goto submit_request;
+ }
+ } else {
+ DMERR("%s io is NULL\n",
+ __func__);
+ error = DM_REQ_CRYPT_ERROR;
+ goto submit_request;
+ }
+
+ req_crypt_inc_pending(io);
+
+ if (error != 0) {
+ err = error;
+ goto submit_request;
+ }
+
+ req = ablkcipher_request_alloc(tfm, GFP_KERNEL);
+ if (!req) {
+ DMERR("%s ablkcipher request allocation failed\n", __func__);
+ err = DM_REQ_CRYPT_ERROR;
+ goto ablkcipher_req_alloc_failure;
+ }
+
+ ablkcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
+ req_crypt_cipher_complete, &result);
+ init_completion(&result.completion);
+ qcrypto_cipher_set_flag(req,
+ QCRYPTO_CTX_USE_PIPE_KEY | QCRYPTO_CTX_XTS_DU_SIZE_512B);
+ crypto_ablkcipher_clear_flags(tfm, ~0);
+ crypto_ablkcipher_setkey(tfm, NULL, KEY_SIZE_XTS);
+
+ req_sg_read = kzalloc(sizeof(struct scatterlist) *
+ MAX_SG_LIST, GFP_KERNEL);
+ if (!req_sg_read) {
+ DMERR("%s req_sg_read allocation failed\n",
+ __func__);
+ err = DM_REQ_CRYPT_ERROR;
+ goto ablkcipher_req_alloc_failure;
+ }
+
+ total_sg_len = blk_rq_map_sg(clone->q, clone, req_sg_read);
+ if ((total_sg_len <= 0) || (total_sg_len > MAX_SG_LIST)) {
+ DMERR("%s Request Error%d", __func__, total_sg_len);
+ err = DM_REQ_CRYPT_ERROR;
+ goto ablkcipher_req_alloc_failure;
+ }
+
+
+ /* total bytes to copy */
+ bvec = NULL;
+ rq_for_each_segment(bvec, clone, iter2) {
+ total_bytes_in_req = total_bytes_in_req + bvec->bv_len;
+ }
+
+ memset(IV, 0, AES_XTS_IV_LEN);
+ memcpy(IV, &clone->__sector, sizeof(sector_t));
+
+ ablkcipher_request_set_crypt(req, req_sg_read, req_sg_read,
+ total_bytes_in_req, (void *) IV);
+
+ rc = crypto_ablkcipher_decrypt(req);
+
+ switch (rc) {
+ case 0:
+ break;
+
+ case -EBUSY:
+ /*
+ * Lets make this synchronous request by waiting on
+ * in progress as well
+ */
+ case -EINPROGRESS:
+ wait_for_completion_io(&result.completion);
+ if (result.err) {
+ DMERR("%s error = %d encrypting the request\n",
+ __func__, result.err);
+ err = DM_REQ_CRYPT_ERROR;
+ }
+ break;
+
+ default:
+ err = DM_REQ_CRYPT_ERROR;
+ break;
+ }
+
+ablkcipher_req_alloc_failure:
+
+ if (req)
+ ablkcipher_request_free(req);
+
+ kfree(req_sg_read);
+
+submit_request:
+ io->error = err;
+ req_crypt_dec_pending_decrypt(io);
+}
+
+/*
+ * The callback that will be called by the worker queue to perform Encryption
+ * for writes and submit the request using the elevelator.
+ */
+static void req_cryptd_crypt_write_convert(struct req_dm_crypt_io *io)
+{
+ struct request *clone = NULL;
+ struct bio *bio_src = NULL;
+ unsigned int total_sg_len_req_in = 0, total_sg_len_req_out = 0,
+ total_bytes_in_req = 0, error = DM_MAPIO_REMAPPED, rc = 0;
+ struct req_iterator iter;
+ struct ablkcipher_request *req = NULL;
+ struct req_crypt_result result;
+ struct bio_vec *bvec = NULL;
+ struct scatterlist *req_sg_in = NULL;
+ struct scatterlist *req_sg_out = NULL;
+ int copy_bio_sector_to_req = 0;
+ gfp_t gfp_mask = GFP_NOIO | __GFP_HIGHMEM;
+ struct page *page = NULL;
+ u8 IV[AES_XTS_IV_LEN];
+ int remaining_size = 0;
+
+ if (io) {
+ if (io->cloned_request) {
+ clone = io->cloned_request;
+ } else {
+ DMERR("%s io->cloned_request is NULL\n",
+ __func__);
+ error = DM_REQ_CRYPT_ERROR;
+ goto submit_request;
+ }
+ } else {
+ DMERR("%s io is NULL\n",
+ __func__);
+ error = DM_REQ_CRYPT_ERROR;
+ goto submit_request;
+ }
+
+ req_crypt_inc_pending(io);
+
+ req = ablkcipher_request_alloc(tfm, GFP_KERNEL);
+ if (!req) {
+ DMERR("%s ablkcipher request allocation failed\n",
+ __func__);
+ error = DM_REQ_CRYPT_ERROR;
+ goto ablkcipher_req_alloc_failure;
+ }
+
+ ablkcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
+ req_crypt_cipher_complete, &result);
+
+ init_completion(&result.completion);
+ qcrypto_cipher_set_flag(req,
+ QCRYPTO_CTX_USE_PIPE_KEY | QCRYPTO_CTX_XTS_DU_SIZE_512B);
+ crypto_ablkcipher_clear_flags(tfm, ~0);
+ crypto_ablkcipher_setkey(tfm, NULL, KEY_SIZE_XTS);
+
+ req_sg_in = kzalloc(sizeof(struct scatterlist) * MAX_SG_LIST,
+ GFP_KERNEL);
+ if (!req_sg_in) {
+ DMERR("%s req_sg_in allocation failed\n",
+ __func__);
+ error = DM_REQ_CRYPT_ERROR;
+ goto ablkcipher_req_alloc_failure;
+ }
+
+ req_sg_out = kzalloc(sizeof(struct scatterlist) * MAX_SG_LIST,
+ GFP_KERNEL);
+ if (!req_sg_out) {
+ DMERR("%s req_sg_out allocation failed\n",
+ __func__);
+ error = DM_REQ_CRYPT_ERROR;
+ goto ablkcipher_req_alloc_failure;
+ }
+
+ total_sg_len_req_in = blk_rq_map_sg(clone->q, clone, req_sg_in);
+ if ((total_sg_len_req_in <= 0) ||
+ (total_sg_len_req_in > MAX_SG_LIST)) {
+ DMERR("%s Request Error%d", __func__, total_sg_len_req_in);
+ error = DM_REQ_CRYPT_ERROR;
+ goto ablkcipher_req_alloc_failure;
+ }
+
+
+ rq_for_each_segment(bvec, clone, iter) {
+try_again:
+ if (bvec->bv_len > remaining_size) {
+ page = NULL;
+ page = mempool_alloc(req_page_pool, gfp_mask);
+ if (!page) {
+ DMERR("%s Crypt page alloc failed", __func__);
+ congestion_wait(BLK_RW_ASYNC, HZ/100);
+ goto try_again;
+ }
+ bvec->bv_page = page;
+ bvec->bv_offset = 0;
+ total_bytes_in_req = total_bytes_in_req + bvec->bv_len;
+ remaining_size = PAGE_SIZE - bvec->bv_len;
+ if (remaining_size < 0)
+ BUG();
+ } else {
+ bvec->bv_page = page;
+ bvec->bv_offset = PAGE_SIZE - remaining_size;
+ remaining_size = remaining_size - bvec->bv_len;
+ total_bytes_in_req = total_bytes_in_req + bvec->bv_len;
+ }
+ }
+
+ total_sg_len_req_out = blk_rq_map_sg(clone->q, clone, req_sg_out);
+ if ((total_sg_len_req_out <= 0) ||
+ (total_sg_len_req_out > MAX_SG_LIST)) {
+ DMERR("%s Request Error %d", __func__, total_sg_len_req_out);
+ error = DM_REQ_CRYPT_ERROR;
+ goto ablkcipher_req_alloc_failure;
+ }
+
+ memset(IV, 0, AES_XTS_IV_LEN);
+ memcpy(IV, &clone->__sector, sizeof(sector_t));
+
+ ablkcipher_request_set_crypt(req, req_sg_in, req_sg_out,
+ total_bytes_in_req, (void *) IV);
+
+ rc = crypto_ablkcipher_encrypt(req);
+
+ switch (rc) {
+ case 0:
+ break;
+
+ case -EBUSY:
+ /*
+ * Lets make this synchronous request by waiting on
+ * in progress as well
+ */
+ case -EINPROGRESS:
+ wait_for_completion_interruptible(&result.completion);
+ if (result.err) {
+ DMERR("%s error = %d encrypting the request\n",
+ __func__, result.err);
+ error = DM_REQ_CRYPT_ERROR;
+ goto ablkcipher_req_alloc_failure;
+ }
+ break;
+
+ default:
+ error = DM_REQ_CRYPT_ERROR;
+ goto ablkcipher_req_alloc_failure;
+ }
+
+ __rq_for_each_bio(bio_src, clone) {
+ if (copy_bio_sector_to_req == 0) {
+ clone->buffer = bio_data(bio_src);
+ copy_bio_sector_to_req++;
+ }
+ blk_queue_bounce(clone->q, &bio_src);
+ }
+
+
+ablkcipher_req_alloc_failure:
+ if (req)
+ ablkcipher_request_free(req);
+
+
+ kfree(req_sg_in);
+
+ kfree(req_sg_out);
+
+submit_request:
+ io->error = error;
+ req_crypt_dec_pending_encrypt(io);
+}
+
+/* Queue callback function that will get triggered */
+static void req_cryptd_crypt(struct work_struct *work)
+{
+ struct req_dm_crypt_io *io =
+ container_of(work, struct req_dm_crypt_io, work);
+
+ if (rq_data_dir(io->cloned_request) == WRITE)
+ req_cryptd_crypt_write_convert(io);
+ else if (rq_data_dir(io->cloned_request) == READ)
+ req_cryptd_crypt_read_convert(io);
+ else
+ DMERR("%s received non-write request for Clone %u\n",
+ __func__, (unsigned int)io->cloned_request);
+}
+
+static void req_cryptd_queue_crypt(struct req_dm_crypt_io *io)
+{
+ INIT_WORK(&io->work, req_cryptd_crypt);
+ queue_work(req_crypt_queue, &io->work);
+}
+
+/*
+ * Cipher complete callback, this is triggered by the Linux crypto api once
+ * the operation is done. This signals the waiting thread that the crypto
+ * operation is complete.
+ */
+static void req_crypt_cipher_complete(struct crypto_async_request *req, int err)
+{
+ struct req_crypt_result *res = req->data;
+
+ if (err == -EINPROGRESS)
+ return;
+
+ res->err = err;
+ complete(&res->completion);
+}
+
+/*
+ * If bio->bi_dev is a partition, remap the location
+ */
+static inline void req_crypt_blk_partition_remap(struct bio *bio)
+{
+ struct block_device *bdev = bio->bi_bdev;
+
+ if (bio_sectors(bio) && bdev != bdev->bd_contains) {
+ struct hd_struct *p = bdev->bd_part;
+
+ bio->bi_sector += p->start_sect;
+ bio->bi_bdev = bdev->bd_contains;
+ }
+}
+
+/*
+ * The endio function is called from ksoftirqd context (atomic).
+ * For write operations the new pages created form the mempool
+ * is freed and returned. * For read operations, decryption is
+ * required, since this is called in a atomic * context, the
+ * request is sent to a worker queue to complete decryptiona and
+ * free the request once done.
+ */
+static int req_crypt_endio(struct dm_target *ti, struct request *clone,
+ int error, union map_info *map_context)
+{
+ int err = 0;
+ struct req_iterator iter1;
+ struct bio_vec *bvec = NULL;
+ struct req_dm_crypt_io *req_io = map_context->ptr;
+
+ /* If it is a write request, do nothing just return. */
+ bvec = NULL;
+ if (rq_data_dir(clone) == WRITE) {
+ rq_for_each_segment(bvec, clone, iter1) {
+ if (bvec->bv_offset == 0) {
+ mempool_free(bvec->bv_page, req_page_pool);
+ bvec->bv_page = NULL;
+ } else
+ bvec->bv_page = NULL;
+ }
+ mempool_free(req_io, req_io_pool);
+ goto submit_request;
+ } else if (rq_data_dir(clone) == READ) {
+ req_io->error = error;
+ req_cryptd_queue_crypt(req_io);
+ err = DM_ENDIO_INCOMPLETE;
+ goto submit_request;
+ }
+
+submit_request:
+ return err;
+}
+
+/*
+ * This function is called with interrupts disabled
+ * The function remaps the clone for the underlying device.
+ * If it is a write request, it calls into the worker queue to
+ * encrypt the data
+ * and submit the request directly using the elevator
+ * For a read request no pre-processing is required the request
+ * is returned to dm once mapping is done
+ */
+
+static int req_crypt_map(struct dm_target *ti, struct request *clone,
+ union map_info *map_context)
+{
+ struct req_dm_crypt_io *req_io = NULL;
+ int error = DM_MAPIO_REMAPPED, copy_bio_sector_to_req = 0;
+ struct bio *bio_src = NULL;
+
+ req_io = mempool_alloc(req_io_pool, GFP_NOWAIT);
+ if (!req_io) {
+ DMERR("%s req_io allocation failed\n", __func__);
+ error = DM_REQ_CRYPT_ERROR;
+ goto submit_request;
+ }
+
+ /* Save the clone in the req_io, the callback to the worker
+ * queue will get the req_io
+ */
+ req_io->cloned_request = clone;
+ map_context->ptr = req_io;
+ atomic_set(&req_io->pending, 0);
+
+ /* Get the queue of the underlying original device */
+ clone->q = bdev_get_queue(dev->bdev);
+ clone->rq_disk = dev->bdev->bd_disk;
+
+ __rq_for_each_bio(bio_src, clone) {
+ bio_src->bi_bdev = dev->bdev;
+ /* Currently the way req-dm works is that once the underlying
+ * device driver completes the request by calling into the
+ * block layer. The block layer completes the bios (clones) and
+ * then the cloned request. This is undesirable for req-dm-crypt
+ * hence added a flag BIO_DONTFREE, this flag will ensure that
+ * blk layer does not complete the cloned bios before completing
+ * the request. When the crypt endio is called, post-processsing
+ * is done and then the dm layer will complete the bios (clones)
+ * and free them.
+ */
+ bio_src->bi_flags |= 1 << BIO_DONTFREE;
+
+ /*
+ * If this device has partitions, remap block n
+ * of partition p to block n+start(p) of the disk.
+ */
+ req_crypt_blk_partition_remap(bio_src);
+ if (copy_bio_sector_to_req == 0) {
+ clone->__sector = bio_src->bi_sector;
+ clone->buffer = bio_data(bio_src);
+ copy_bio_sector_to_req++;
+ }
+ blk_queue_bounce(clone->q, &bio_src);
+ }
+
+ if (rq_data_dir(clone) == READ) {
+ error = DM_MAPIO_REMAPPED;
+ goto submit_request;
+ } else if (rq_data_dir(clone) == WRITE) {
+ req_cryptd_queue_crypt(req_io);
+ error = DM_MAPIO_SUBMITTED;
+ goto submit_request;
+ } else {
+ error = DM_REQ_CRYPT_ERROR;
+ DMERR("%s Unknown request\n", __func__);
+ }
+
+submit_request:
+ return error;
+
+}
+
+static int req_crypt_status(struct dm_target *ti, status_type_t type,
+ char *result, unsigned maxlen)
+{
+ return 0;
+}
+
+static void req_crypt_dtr(struct dm_target *ti)
+{
+ if (req_crypt_queue)
+ destroy_workqueue(req_crypt_queue);
+ if (req_io_pool)
+ mempool_destroy(req_io_pool);
+ if (req_page_pool)
+ mempool_destroy(req_page_pool);
+ if (tfm)
+ crypto_free_ablkcipher(tfm);
+}
+
+
+/*
+ * Construct an encryption mapping:
+ * <cipher> <key> <iv_offset> <dev_path> <start>
+ */
+static int req_crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
+{
+ unsigned long long tmpll;
+ char dummy;
+
+ if (dm_get_device(ti, argv[3], dm_table_get_mode(ti->table), &dev)) {
+ DMERR(" %s Device Lookup failed\n", __func__);
+ return DM_REQ_CRYPT_ERROR;
+ }
+
+ if (sscanf(argv[4], "%llu%c", &tmpll, &dummy) != 1) {
+ DMERR("%s Invalid device sector\n", __func__);
+ return DM_REQ_CRYPT_ERROR;
+ }
+ start_sector_orig = tmpll;
+
+ req_crypt_queue = alloc_workqueue("req_cryptd",
+ WQ_HIGHPRI |
+ WQ_CPU_INTENSIVE|
+ WQ_MEM_RECLAIM,
+ 1);
+ if (!req_crypt_queue) {
+ DMERR("%s req_crypt_queue not allocated\n", __func__);
+ return DM_REQ_CRYPT_ERROR;
+ }
+
+ /* Allocate the crypto alloc blk cipher and keep the handle */
+ tfm = crypto_alloc_ablkcipher("qcom-xts(aes)", 0, 0);
+ if (IS_ERR(tfm)) {
+ DMERR("%s ablkcipher tfm allocation failed : error = %lu\n",
+ __func__, PTR_ERR(tfm));
+ return DM_REQ_CRYPT_ERROR;
+ }
+
+ req_io_pool = mempool_create_slab_pool(MIN_IOS, _req_crypt_io_pool);
+ if (!req_io_pool) {
+ DMERR("%s req_io_pool not allocated\n", __func__);
+ return DM_REQ_CRYPT_ERROR;
+ }
+
+ req_page_pool = mempool_create_page_pool(MIN_POOL_PAGES, 0);
+ if (!req_page_pool) {
+ DMERR("%s req_page_pool not allocated\n", __func__);
+ return DM_REQ_CRYPT_ERROR;
+ }
+
+ return 0;
+}
+
+static void req_crypt_postsuspend(struct dm_target *ti)
+{
+}
+
+static int req_crypt_preresume(struct dm_target *ti)
+{
+ return 0;
+}
+
+static void req_crypt_resume(struct dm_target *ti)
+{
+}
+
+/* Message interface
+ * key set <key>
+ * key wipe
+ */
+static int req_crypt_message(struct dm_target *ti, unsigned argc, char **argv)
+{
+ return 0;
+}
+
+static int req_crypt_iterate_devices(struct dm_target *ti,
+ iterate_devices_callout_fn fn, void *data)
+{
+ return fn(ti, dev, start_sector_orig, ti->len, data);
+}
+
+static struct target_type req_crypt_target = {
+ .name = "req-crypt",
+ .version = {1, 0, 0},
+ .module = THIS_MODULE,
+ .ctr = req_crypt_ctr,
+ .dtr = req_crypt_dtr,
+ .map_rq = req_crypt_map,
+ .rq_end_io = req_crypt_endio,
+ .status = req_crypt_status,
+ .postsuspend = req_crypt_postsuspend,
+ .preresume = req_crypt_preresume,
+ .resume = req_crypt_resume,
+ .message = req_crypt_message,
+ .iterate_devices = req_crypt_iterate_devices,
+};
+
+static int __init req_dm_crypt_init(void)
+{
+ int r;
+
+ _req_crypt_io_pool = KMEM_CACHE(req_dm_crypt_io, 0);
+ if (!_req_crypt_io_pool)
+ return -ENOMEM;
+
+ r = dm_register_target(&req_crypt_target);
+ if (r < 0)
+ DMERR("register failed %d", r);
+
+ return r;
+}
+
+static void __exit req_dm_crypt_exit(void)
+{
+ kmem_cache_destroy(_req_crypt_io_pool);
+ dm_unregister_target(&req_crypt_target);
+}
+
+module_init(req_dm_crypt_init);
+module_exit(req_dm_crypt_exit);
+
+MODULE_DESCRIPTION(DM_NAME " target for request based transparent encryption / decryption");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index e24143c..5d240d1 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -775,7 +775,7 @@
* Complete the clone and the original request.
* Must be called without queue lock.
*/
-static void dm_end_request(struct request *clone, int error)
+void dm_end_request(struct request *clone, int error)
{
int rw = rq_data_dir(clone);
struct dm_rq_target_io *tio = clone->end_io_data;
diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
index 4f39838..7d97c26 100644
--- a/drivers/media/media-device.c
+++ b/drivers/media/media-device.c
@@ -139,7 +139,9 @@
unsigned int p;
for (p = 0; p < entity->num_pads; p++) {
- struct media_pad_desc pad = {0};
+ struct media_pad_desc pad;
+
+ memset(&pad, 0, sizeof(pad));
media_device_kpad_to_upad(&entity->pads[p], &pad);
if (copy_to_user(&links.pads[p], &pad, sizeof(pad)))
return -EFAULT;
@@ -157,6 +159,7 @@
if (entity->links[l].source->entity != entity)
continue;
+ memset(&link, 0, sizeof(link));
media_device_kpad_to_upad(entity->links[l].source,
&link.source);
media_device_kpad_to_upad(entity->links[l].sink,
diff --git a/drivers/media/platform/msm/camera_v2/camera/camera.c b/drivers/media/platform/msm/camera_v2/camera/camera.c
index 3f7ba6b..43cdcbb 100644
--- a/drivers/media/platform/msm/camera_v2/camera/camera.c
+++ b/drivers/media/platform/msm/camera_v2/camera/camera.c
@@ -673,12 +673,22 @@
return rc;
}
+#ifdef CONFIG_COMPAT
+long camera_v4l2_compat_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ return -ENOIOCTLCMD;
+}
+#endif
static struct v4l2_file_operations camera_v4l2_fops = {
.owner = THIS_MODULE,
.open = camera_v4l2_open,
.poll = camera_v4l2_poll,
.release = camera_v4l2_close,
.ioctl = video_ioctl2,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl32 = camera_v4l2_compat_ioctl,
+#endif
};
int camera_init_v4l2(struct device *dev, unsigned int *session)
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
index d33d34b..334a293 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
@@ -459,6 +459,7 @@
uint8_t vt_enable;
void __iomem *p_avtimer_msw;
void __iomem *p_avtimer_lsw;
+ uint8_t ignore_error;
};
#endif
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
index 044f6f1..eb05015 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
@@ -176,15 +176,15 @@
uint32_t irq_status0, uint32_t irq_status1,
struct msm_isp_timestamp *ts)
{
+ uint32_t cnt;
if (!(irq_status0 & 0x1F))
return;
if (irq_status0 & BIT(0)) {
ISP_DBG("%s: SOF IRQ\n", __func__);
- if (vfe_dev->axi_data.src_info[VFE_PIX_0].raw_stream_count > 0
- && vfe_dev->axi_data.src_info[VFE_PIX_0].
- pix_stream_count == 0) {
- msm_isp_sof_notify(vfe_dev, VFE_PIX_0, ts);
+ cnt = vfe_dev->axi_data.src_info[VFE_PIX_0].raw_stream_count;
+ if (cnt > 0) {
+ msm_isp_sof_notify(vfe_dev, VFE_RAW_0, ts);
if (vfe_dev->axi_data.stream_update)
msm_isp_axi_stream_update(vfe_dev);
msm_isp_update_framedrop_reg(vfe_dev);
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 d53d7f6..e443e9a 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.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
@@ -370,15 +370,16 @@
uint32_t irq_status0, uint32_t irq_status1,
struct msm_isp_timestamp *ts)
{
+ int cnt;
+
if (!(irq_status0 & 0xF))
return;
if (irq_status0 & (1 << 0)) {
ISP_DBG("%s: SOF IRQ\n", __func__);
- if (vfe_dev->axi_data.src_info[VFE_PIX_0].raw_stream_count > 0
- && vfe_dev->axi_data.src_info[VFE_PIX_0].
- pix_stream_count == 0) {
- msm_isp_sof_notify(vfe_dev, VFE_PIX_0, ts);
+ cnt = vfe_dev->axi_data.src_info[VFE_PIX_0].raw_stream_count;
+ if (cnt > 0) {
+ msm_isp_sof_notify(vfe_dev, VFE_RAW_0, ts);
if (vfe_dev->axi_data.stream_update)
msm_isp_axi_stream_update(vfe_dev);
msm_isp_update_framedrop_reg(vfe_dev);
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 0264d6d..5902a99 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
@@ -81,6 +81,10 @@
return rc;
switch (stream_cfg_cmd->output_format) {
+ case V4L2_PIX_FMT_YUYV:
+ case V4L2_PIX_FMT_YVYU:
+ case V4L2_PIX_FMT_UYVY:
+ case V4L2_PIX_FMT_VYUY:
case V4L2_PIX_FMT_SBGGR8:
case V4L2_PIX_FMT_SGBRG8:
case V4L2_PIX_FMT_SGRBG8:
@@ -167,6 +171,10 @@
uint32_t size = 0;
struct msm_vfe_axi_plane_cfg *plane_cfg = stream_info->plane_cfg;
switch (stream_info->output_format) {
+ case V4L2_PIX_FMT_YUYV:
+ case V4L2_PIX_FMT_YVYU:
+ case V4L2_PIX_FMT_UYVY:
+ case V4L2_PIX_FMT_VYUY:
case V4L2_PIX_FMT_SBGGR8:
case V4L2_PIX_FMT_SGBRG8:
case V4L2_PIX_FMT_SGRBG8:
@@ -444,7 +452,7 @@
sof_event.frame_id = vfe_dev->axi_data.src_info[frame_src].frame_id;
sof_event.timestamp = ts->event_time;
sof_event.mono_timestamp = ts->buf_time;
- msm_isp_send_event(vfe_dev, ISP_EVENT_SOF, &sof_event);
+ msm_isp_send_event(vfe_dev, ISP_EVENT_SOF + frame_src, &sof_event);
}
void msm_isp_calculate_framedrop(
@@ -1308,11 +1316,13 @@
msm_isp_update_rdi_output_count(vfe_dev, stream_cfg_cmd);
cur_stream_cnt = msm_isp_get_curr_stream_cnt(vfe_dev);
if (cur_stream_cnt == 0) {
+ vfe_dev->ignore_error = 1;
if (camif_update == DISABLE_CAMIF_IMMEDIATELY) {
vfe_dev->hw_info->vfe_ops.axi_ops.halt(vfe_dev);
}
vfe_dev->hw_info->vfe_ops.core_ops.reset_hw(vfe_dev, ISP_RST_SOFT);
vfe_dev->hw_info->vfe_ops.core_ops.init_hw_reg(vfe_dev);
+ vfe_dev->ignore_error = 0;
}
for (i = 0; i < stream_cfg_cmd->num_streams; i++) {
@@ -1389,7 +1399,10 @@
return -EINVAL;
}
if (stream_info->state == ACTIVE &&
- stream_info->stream_type == BURST_STREAM) {
+ stream_info->stream_type == BURST_STREAM &&
+ (1 != update_cmd->num_streams ||
+ UPDATE_STREAM_FRAMEDROP_PATTERN !=
+ update_cmd->update_type)) {
pr_err("%s: Cannot update active burst stream\n",
__func__);
return -EINVAL;
@@ -1416,7 +1429,10 @@
msm_isp_get_framedrop_period(
update_info->skip_pattern);
stream_info->runtime_init_frame_drop = 0;
- stream_info->framedrop_pattern = 0x1;
+ if (update_info->skip_pattern == SKIP_ALL)
+ stream_info->framedrop_pattern = 0x0;
+ else
+ stream_info->framedrop_pattern = 0x1;
stream_info->framedrop_period = framedrop_period - 1;
vfe_dev->hw_info->vfe_ops.axi_ops.
cfg_framedrop(vfe_dev, stream_info);
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 057e87f..ffe0b9c 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
@@ -806,6 +806,12 @@
case V4L2_PIX_FMT_NV61:
val = CAL_WORD(pixel_per_line, 1, 8);
break;
+ case V4L2_PIX_FMT_YUYV:
+ case V4L2_PIX_FMT_YVYU:
+ case V4L2_PIX_FMT_UYVY:
+ case V4L2_PIX_FMT_VYUY:
+ val = CAL_WORD(pixel_per_line, 2, 8);
+ break;
/*TD: Add more image format*/
default:
msm_isp_print_fourcc_error(__func__, output_format);
@@ -995,7 +1001,8 @@
error_mask1 &= irq_status1;
irq_status0 &= ~error_mask0;
irq_status1 &= ~error_mask1;
- if ((error_mask0 != 0) || (error_mask1 != 0))
+ if (!vfe_dev->ignore_error &&
+ ((error_mask0 != 0) || (error_mask1 != 0)))
msm_isp_update_error_info(vfe_dev, error_mask0, error_mask1);
if ((irq_status0 == 0) && (irq_status1 == 0) &&
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c b/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c
index 981c210..8662657 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c
@@ -457,9 +457,8 @@
break;
}
for (i = 0; i < csid_params.lut_params.num_cid; i++) {
- vc_cfg = kzalloc(csid_params.lut_params.num_cid *
- sizeof(struct msm_camera_csid_vc_cfg),
- GFP_KERNEL);
+ vc_cfg = kzalloc(sizeof(struct msm_camera_csid_vc_cfg),
+ GFP_KERNEL);
if (!vc_cfg) {
pr_err("%s: %d failed\n", __func__, __LINE__);
for (i--; i >= 0; i--)
@@ -469,8 +468,7 @@
}
if (copy_from_user(vc_cfg,
(void *)csid_params.lut_params.vc_cfg[i],
- (csid_params.lut_params.num_cid *
- sizeof(struct msm_camera_csid_vc_cfg)))) {
+ sizeof(struct msm_camera_csid_vc_cfg))) {
pr_err("%s: %d failed\n", __func__, __LINE__);
kfree(vc_cfg);
for (i--; i >= 0; i--)
diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c
index fe0a42d..f0721c3 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -814,6 +814,10 @@
int msm_vidc_encoder_cmd(void *instance, struct v4l2_encoder_cmd *enc)
{
struct msm_vidc_inst *inst = instance;
+ if (!inst || !inst->core || !enc) {
+ dprintk(VIDC_ERR, "%s invalid params\n", __func__);
+ return -EINVAL;
+ }
if (inst->session_type == MSM_VIDC_ENCODER)
return msm_venc_cmd(instance, enc);
return -EINVAL;
@@ -822,6 +826,10 @@
int msm_vidc_decoder_cmd(void *instance, struct v4l2_decoder_cmd *dec)
{
struct msm_vidc_inst *inst = instance;
+ if (!inst || !inst->core || !dec) {
+ dprintk(VIDC_ERR, "%s invalid params\n", __func__);
+ return -EINVAL;
+ }
if (inst->session_type == MSM_VIDC_DECODER)
return msm_vdec_cmd(instance, dec);
return -EINVAL;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 81f18e1..70114de 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -3320,10 +3320,24 @@
rc = msm_vidc_load_supported(inst);
if (!rc && inst->capability.capability_set) {
- rc = call_hfi_op(hdev, capability_check,
- inst->fmts[OUTPUT_PORT]->fourcc,
- inst->prop.width[CAPTURE_PORT], &capability->width.max,
- &capability->height.max);
+ if (inst->prop.width[CAPTURE_PORT] < capability->width.min ||
+ inst->prop.height[CAPTURE_PORT] <
+ capability->height.min) {
+ dprintk(VIDC_ERR,
+ "Unsupported WxH = (%u)x(%u), min supported is - (%u)x(%u)\n",
+ inst->prop.width[CAPTURE_PORT],
+ inst->prop.height[CAPTURE_PORT],
+ capability->width.min,
+ capability->height.min);
+ rc = -ENOTSUPP;
+ }
+ if (!rc) {
+ rc = call_hfi_op(hdev, capability_check,
+ inst->fmts[OUTPUT_PORT]->fourcc,
+ inst->prop.width[CAPTURE_PORT],
+ &capability->width.max,
+ &capability->height.max);
+ }
if (!rc && (inst->prop.height[CAPTURE_PORT]
* inst->prop.width[CAPTURE_PORT] >
@@ -3341,7 +3355,6 @@
inst->state = MSM_VIDC_CORE_INVALID;
mutex_unlock(&inst->sync_lock);
msm_vidc_queue_v4l2_event(inst, V4L2_EVENT_MSM_VIDC_SYS_ERROR);
- wake_up(&inst->kernel_event_queue);
}
return rc;
}
diff --git a/drivers/media/platform/msm/vidc/q6_hfi.c b/drivers/media/platform/msm/vidc/q6_hfi.c
index e70635d..5404af6 100644
--- a/drivers/media/platform/msm/vidc/q6_hfi.c
+++ b/drivers/media/platform/msm/vidc/q6_hfi.c
@@ -554,6 +554,10 @@
new_session = (struct hal_session *)
kzalloc(sizeof(struct hal_session), GFP_KERNEL);
+ if (!new_session) {
+ dprintk(VIDC_ERR, "new session fail: Out of memory\n");
+ return NULL;
+ }
new_session->session_id = (u32) session_id;
if (session_type == 1)
new_session->is_decoder = 0;
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index 1839d07..efafa23 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -164,13 +164,14 @@
uint32_t qsee_perf_client;
struct qseecom_clk qsee;
struct qseecom_clk ce_drv;
- struct cdev cdev;
bool support_bus_scaling;
uint32_t cumulative_mode;
enum qseecom_bandwidth_request_mode current_mode;
struct timer_list bw_scale_down_timer;
struct work_struct bw_inactive_req_ws;
+ struct cdev cdev;
+ bool timer_running;
};
struct qseecom_client_handle {
@@ -490,6 +491,7 @@
__qseecom_set_msm_bus_request(INACTIVE);
pr_debug("current_mode = %d, cumulative_mode = %d\n",
qseecom.current_mode, qseecom.cumulative_mode);
+ qseecom.timer_running = false;
mutex_unlock(&qsee_bw_mutex);
mutex_unlock(&app_access_lock);
return;
@@ -501,6 +503,25 @@
return;
}
+static void __qseecom_decrease_clk_ref_count(enum qseecom_ce_hw_instance ce)
+{
+ struct qseecom_clk *qclk;
+ 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;
+ }
+ qclk->clk_access_cnt--;
+ mutex_unlock(&clk_access_lock);
+ return;
+}
+
+
static int qseecom_scale_bus_bandwidth_timer(uint32_t mode, uint32_t duration)
{
int32_t ret = 0;
@@ -515,13 +536,12 @@
} else {
request_mode = mode;
}
+
__qseecom_set_msm_bus_request(request_mode);
-
- del_timer_sync(&(qseecom.bw_scale_down_timer));
- qseecom.bw_scale_down_timer.expires = jiffies +
- msecs_to_jiffies(duration);
- add_timer(&(qseecom.bw_scale_down_timer));
-
+ if (qseecom.timer_running) {
+ __qseecom_decrease_clk_ref_count(CLK_QSEE);
+ del_timer_sync(&(qseecom.bw_scale_down_timer));
+ }
mutex_unlock(&qsee_bw_mutex);
return ret;
}
@@ -582,6 +602,14 @@
{
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);
+ }
return;
}
@@ -1061,16 +1089,13 @@
return -EINVAL;
}
- if (((uint32_t)req_ptr->cmd_req_buf <
- data_ptr->client.user_virt_sb_base)
- || ((uint32_t)req_ptr->cmd_req_buf >=
- (data_ptr->client.user_virt_sb_base +
- data_ptr->client.sb_length))) {
- pr_err("cmd buffer address not within shared bufffer\n");
+ /* Clients need to ensure req_buf is at base offset of shared buffer */
+ if ((uint32_t)req_ptr->cmd_req_buf !=
+ data_ptr->client.user_virt_sb_base) {
+ pr_err("cmd buf not pointing to base offset of shared buffer\n");
return -EINVAL;
}
-
if (((uint32_t)req_ptr->resp_buf < data_ptr->client.user_virt_sb_base)
|| ((uint32_t)req_ptr->resp_buf >=
(data_ptr->client.user_virt_sb_base +
@@ -1089,8 +1114,6 @@
(uint32_t)req_ptr->resp_buf));
send_svc_ireq_ptr->rsp_len = req_ptr->resp_len;
- pr_debug("CMD ID (%x), KEY_TYPE (%d)\n", send_svc_ireq_ptr->qsee_cmd_id,
- ((struct qseecom_rpmb_provision_key *)req_ptr->cmd_req_buf)->key_type);
return ret;
}
@@ -1115,6 +1138,21 @@
return -EINVAL;
}
+ if (data->client.sb_virt == NULL) {
+ pr_err("sb_virt null\n");
+ return -EINVAL;
+ }
+
+ if (data->client.user_virt_sb_base == 0) {
+ pr_err("user_virt_sb_base is null\n");
+ return -EINVAL;
+ }
+
+ if (data->client.sb_length == 0) {
+ pr_err("sb_length is 0\n");
+ return -EINVAL;
+ }
+
data->type = QSEECOM_SECURE_SERVICE;
switch (req.cmd_id) {
@@ -1164,7 +1202,16 @@
if (!qseecom.support_bus_scaling) {
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);
}
+
goto exit;
}
@@ -1188,6 +1235,18 @@
ret = -EINVAL;
break;
}
+ if (!qseecom.support_bus_scaling) {
+ 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);
+ }
+
exit:
return ret;
}
@@ -2024,6 +2083,14 @@
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);
+ }
atomic_dec(&data->ioctl_count);
mutex_unlock(&app_access_lock);
@@ -3148,6 +3215,15 @@
QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
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(
+ 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);
@@ -3171,7 +3247,15 @@
QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
atomic_inc(&data->ioctl_count);
ret = qseecom_send_modfd_cmd(data, argp);
- atomic_dec(&data->ioctl_count);
+ 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);
+ } atomic_dec(&data->ioctl_count);
wake_up_all(&data->abort_wq);
mutex_unlock(&app_access_lock);
if (ret)
@@ -3820,6 +3904,7 @@
/* register client for bus scaling */
if (pdev->dev.of_node) {
+ qseecom.pdev->of_node = pdev->dev.of_node;
qseecom.support_bus_scaling =
of_property_read_bool((&pdev->dev)->of_node,
"qcom,support-bus-scaling");
@@ -3924,6 +4009,7 @@
qseecom.bw_scale_down_timer.function =
qseecom_scale_bus_bandwidth_timer_callback;
}
+ qseecom.timer_running = false;
qseecom.qsee_perf_client = msm_bus_scale_register_client(
qseecom_platform_support);
diff --git a/drivers/misc/smsc_hub.c b/drivers/misc/smsc_hub.c
index 6f98dc7..e89451a 100644
--- a/drivers/misc/smsc_hub.c
+++ b/drivers/misc/smsc_hub.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
@@ -36,6 +36,7 @@
struct clk *ref_clk;
struct regulator *hsic_hub_reg;
struct regulator *int_pad_reg, *hub_vbus_reg;
+ bool enabled;
};
static struct hsic_hub *smsc_hub;
static struct platform_driver smsc_hub_driver;
@@ -191,6 +192,14 @@
{
int ret;
+ /*
+ * xo_clk_gpio controls an external xo clock which feeds
+ * the hub reference clock. When this gpio is present,
+ * assume that no other clocks are required.
+ */
+ if (hub->pdata->xo_clk_gpio)
+ return 0;
+
if (!init) {
if (!IS_ERR(hub->ref_clk))
clk_disable_unprepare(hub->ref_clk);
@@ -257,6 +266,15 @@
dev_err(hub->dev, "gpio request failed (CLK GPIO)\n");
}
+ if (pdata->xo_clk_gpio) {
+ ret = devm_gpio_request(hub->dev, pdata->xo_clk_gpio,
+ "HSIC_HUB_XO_CLK");
+ if (ret < 0) {
+ dev_err(hub->dev, "gpio request failed(XO CLK GPIO)\n");
+ return ret;
+ }
+ }
+
if (pdata->int_gpio) {
ret = devm_gpio_request(hub->dev, pdata->int_gpio,
"HSIC_HUB_INT");
@@ -266,7 +284,7 @@
}
/* Enable LDO if required for external pull-up */
- smsc_hub->int_pad_reg = devm_regulator_get(hub->dev, "hub_int");
+ smsc_hub->int_pad_reg = devm_regulator_get(hub->dev, "hub-int");
if (IS_ERR(smsc_hub->int_pad_reg)) {
dev_dbg(hub->dev, "unable to get ext hub_int reg\n");
} else {
@@ -298,6 +316,9 @@
{
int ret;
+ if (!of_get_property(hub->dev->of_node, "ext-hub-vddio-supply", NULL))
+ return 0;
+
if (!init) {
if (!IS_ERR(smsc_hub->hsic_hub_reg)) {
regulator_disable(smsc_hub->hsic_hub_reg);
@@ -308,7 +329,7 @@
return 0;
}
- smsc_hub->hsic_hub_reg = devm_regulator_get(hub->dev, "EXT_HUB_VDDIO");
+ smsc_hub->hsic_hub_reg = devm_regulator_get(hub->dev, "ext-hub-vddio");
if (IS_ERR(smsc_hub->hsic_hub_reg)) {
dev_dbg(hub->dev, "unable to get ext hub vddcx\n");
} else {
@@ -345,6 +366,124 @@
return ret;
}
+
+static int smsc_hub_enable(struct hsic_hub *hub)
+{
+ struct smsc_hub_platform_data *pdata = hub->pdata;
+ struct of_dev_auxdata *hsic_host_auxdata = dev_get_platdata(hub->dev);
+ struct device_node *node = hub->dev->of_node;
+ int ret;
+
+ ret = gpio_direction_output(pdata->xo_clk_gpio, 1);
+ if (ret < 0) {
+ dev_err(hub->dev, "fail to enable xo clk\n");
+ return ret;
+ }
+
+ ret = gpio_direction_output(pdata->hub_reset, 0);
+ if (ret < 0) {
+ dev_err(hub->dev, "fail to assert reset\n");
+ goto disable_xo;
+ }
+ udelay(5);
+ ret = gpio_direction_output(pdata->hub_reset, 1);
+ if (ret < 0) {
+ dev_err(hub->dev, "fail to de-assert reset\n");
+ goto disable_xo;
+ }
+
+ ret = of_platform_populate(node, NULL, hsic_host_auxdata,
+ hub->dev);
+ if (ret < 0) {
+ dev_err(smsc_hub->dev, "fail to add child with %d\n",
+ ret);
+ goto reset;
+ }
+
+ pm_runtime_allow(hub->dev);
+
+ return 0;
+
+reset:
+ gpio_direction_output(pdata->hub_reset, 0);
+disable_xo:
+ gpio_direction_output(pdata->xo_clk_gpio, 0);
+
+ return ret;
+}
+
+static int sms_hub_remove_child(struct device *dev, void *data)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+
+ /*
+ * Runtime PM is disabled before the driver's remove method
+ * is called. So resume the device before unregistering
+ * the device. Don't worry about the PM usage counter as
+ * the device will be freed.
+ */
+ pm_runtime_get_sync(dev);
+ of_device_unregister(pdev);
+
+ return 0;
+}
+
+static int smsc_hub_disable(struct hsic_hub *hub)
+{
+ struct smsc_hub_platform_data *pdata = hub->pdata;
+
+ pm_runtime_forbid(hub->dev);
+ device_for_each_child(hub->dev, NULL, sms_hub_remove_child);
+ gpio_direction_output(pdata->hub_reset, 0);
+ gpio_direction_output(pdata->xo_clk_gpio, 0);
+
+ return 0;
+}
+
+static ssize_t smsc_hub_enable_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%s\n", smsc_hub->enabled ?
+ "enabled" : "disabled");
+}
+
+static ssize_t smsc_hub_enable_store(struct device *dev,
+ struct device_attribute *attr, const char
+ *buf, size_t size)
+{
+
+ bool enable;
+ int val;
+ int ret = size;
+
+ if (sscanf(buf, "%d", &val) == 1) {
+ enable = !!val;
+ } else {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (smsc_hub->enabled == enable)
+ goto out;
+
+ if (enable)
+ ret = smsc_hub_enable(smsc_hub);
+ else
+ ret = smsc_hub_disable(smsc_hub);
+
+ pr_debug("smsc hub %s status %d\n", enable ?
+ "Enable" : "Disable", ret);
+ if (!ret) {
+ ret = size;
+ smsc_hub->enabled = enable;
+ }
+out:
+ return ret;
+}
+
+static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, smsc_hub_enable_show,
+ smsc_hub_enable_store);
+
struct smsc_hub_platform_data *msm_hub_dt_to_pdata(
struct platform_device *pdev)
{
@@ -365,6 +504,8 @@
return ERR_PTR(rc);
} else {
pdata->model_id = temp_val;
+ if (pdata->model_id == 0)
+ return pdata;
}
pdata->hub_reset = of_get_named_gpio(node, "smsc,reset-gpio", 0);
@@ -379,6 +520,10 @@
if (pdata->int_gpio < 0)
pdata->int_gpio = 0;
+ pdata->xo_clk_gpio = of_get_named_gpio(node, "smsc,xo-clk-gpio", 0);
+ if (pdata->xo_clk_gpio < 0)
+ pdata->xo_clk_gpio = 0;
+
return pdata;
}
@@ -406,6 +551,12 @@
return -ENODEV;
}
+ if (pdata->model_id == 0) {
+ dev_dbg(&pdev->dev, "standalone HSIC config enabled\n");
+ return of_platform_populate(node, NULL,
+ hsic_host_auxdata, &pdev->dev);
+ }
+
if (!pdata->hub_reset)
return -EINVAL;
@@ -416,11 +567,14 @@
smsc_hub->dev = &pdev->dev;
smsc_hub->pdata = pdata;
- smsc_hub->hub_vbus_reg = devm_regulator_get(&pdev->dev, "hub_vbus");
- ret = PTR_ERR(smsc_hub->hub_vbus_reg);
- if (ret == -EPROBE_DEFER) {
- dev_dbg(&pdev->dev, "failed to get hub_vbus\n");
- return ret;
+ if (of_get_property(pdev->dev.of_node, "hub-vbus-supply", NULL)) {
+ smsc_hub->hub_vbus_reg = devm_regulator_get(&pdev->dev,
+ "hub-vbus");
+ ret = PTR_ERR(smsc_hub->hub_vbus_reg);
+ if (ret == -EPROBE_DEFER) {
+ dev_dbg(&pdev->dev, "failed to get hub_vbus\n");
+ return ret;
+ }
}
ret = msm_hsic_hub_init_vdd(smsc_hub, 1);
@@ -439,6 +593,16 @@
goto uninit_clock;
}
+ if (pdata->model_id == SMSC3502_ID) {
+ ret = device_create_file(&pdev->dev, &dev_attr_enable);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "fail to create sysfs file\n");
+ goto uninit_gpio;
+ }
+ pm_runtime_forbid(&pdev->dev);
+ goto done;
+ }
+
gpio_direction_output(pdata->hub_reset, 0);
/*
* Hub reset should be asserted for minimum 2microsec
@@ -447,7 +611,7 @@
udelay(5);
gpio_direction_output(pdata->hub_reset, 1);
- if (!IS_ERR(smsc_hub->hub_vbus_reg)) {
+ if (!IS_ERR_OR_NULL(smsc_hub->hub_vbus_reg)) {
ret = regulator_enable(smsc_hub->hub_vbus_reg);
if (ret) {
dev_err(&pdev->dev, "unable to enable hub_vbus\n");
@@ -501,10 +665,13 @@
goto uninit_gpio;
}
+ smsc_hub->enabled = true;
+
if (!smsc_hub->client)
dev_err(&pdev->dev,
"failed to connect to smsc_hub through I2C\n");
+done:
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
@@ -524,7 +691,12 @@
{
const struct smsc_hub_platform_data *pdata;
+ if (!smsc_hub)
+ return 0;
+
pdata = smsc_hub->pdata;
+ if (pdata->model_id == SMSC3502_ID)
+ device_remove_file(&pdev->dev, &dev_attr_enable);
if (smsc_hub->client) {
i2c_unregister_device(smsc_hub->client);
smsc_hub->client = NULL;
@@ -532,7 +704,7 @@
}
pm_runtime_disable(&pdev->dev);
- if (!IS_ERR(smsc_hub->hub_vbus_reg))
+ if (!IS_ERR_OR_NULL(smsc_hub->hub_vbus_reg))
regulator_disable(smsc_hub->hub_vbus_reg);
msm_hsic_hub_init_gpio(smsc_hub, 0);
msm_hsic_hub_init_clock(smsc_hub, 0);
@@ -553,13 +725,19 @@
{
int ret = 0;
+ if (!smsc_hub || !smsc_hub->enabled)
+ return 0;
+
if (smsc_hub->xo_handle) {
ret = msm_xo_mode_vote(smsc_hub->xo_handle, MSM_XO_MODE_OFF);
if (ret) {
pr_err("%s: failed to devote for TCXO\n"
"D1 buffer%d\n", __func__, ret);
}
+ } else if (smsc_hub->pdata->xo_clk_gpio) {
+ gpio_direction_output(smsc_hub->pdata->xo_clk_gpio, 0);
}
+
return ret;
}
@@ -567,13 +745,19 @@
{
int ret = 0;
+ if (!smsc_hub || !smsc_hub->enabled)
+ return 0;
+
if (smsc_hub->xo_handle) {
ret = msm_xo_mode_vote(smsc_hub->xo_handle, MSM_XO_MODE_ON);
if (ret) {
pr_err("%s: failed to vote for TCXO\n"
"D1 buffer%d\n", __func__, ret);
}
+ } else if (smsc_hub->pdata->xo_clk_gpio) {
+ gpio_direction_output(smsc_hub->pdata->xo_clk_gpio, 1);
}
+
return ret;
}
#endif
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 885d0d2..63952e7 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -340,6 +340,8 @@
card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE];
mmc_select_card_type(card);
+ card->ext_csd.raw_drive_strength = ext_csd[EXT_CSD_DRIVE_STRENGTH];
+
card->ext_csd.raw_s_a_timeout = ext_csd[EXT_CSD_S_A_TIMEOUT];
card->ext_csd.raw_erase_timeout_mult =
ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT];
diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c
index 0fde9fc..40d3d9f 100644
--- a/drivers/mtd/ubi/build.c
+++ b/drivers/mtd/ubi/build.c
@@ -1224,7 +1224,11 @@
mtd = open_mtd_device(p->name);
if (IS_ERR(mtd)) {
err = PTR_ERR(mtd);
- goto out_detach;
+ ubi_err("cannot open mtd %s, error %d", p->name, err);
+ /* See comment below re-ubi_is_module(). */
+ if (ubi_is_module())
+ goto out_detach;
+ continue;
}
mutex_lock(&ubi_devices_mutex);
diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c
index 7c1a9bf..444e4ff 100644
--- a/drivers/mtd/ubi/wl.c
+++ b/drivers/mtd/ubi/wl.c
@@ -712,6 +712,9 @@
if (!(e2->ec - e1->ec >= UBI_WL_THRESHOLD)) {
dbg_wl("no WL needed: min used EC %d, max free EC %d",
e1->ec, e2->ec);
+
+ /* Give the unused PEB back */
+ wl_tree_add(e2, &ubi->free);
goto out_cancel;
}
paranoid_check_in_wl_tree(ubi, e1, &ubi->used);
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index 38c70a3..66875f7 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -36,6 +36,7 @@
#include <linux/mfd/pm8xxx/misc.h>
#include <linux/qpnp/qpnp-adc.h>
+#include <mach/board.h>
#include <mach/msm_smd.h>
#include <mach/msm_iomap.h>
#include <mach/subsystem_restart.h>
@@ -748,6 +749,22 @@
EXPORT_SYMBOL(wcnss_pronto_log_debug_regs);
#ifdef CONFIG_WCNSS_REGISTER_DUMP_ON_BITE
+static void wcnss_log_iris_regs(void)
+{
+ int i;
+ u32 reg_val;
+ u32 regs_array[] = {
+ 0x04, 0x05, 0x11, 0x1e, 0x40, 0x48,
+ 0x49, 0x4b, 0x00, 0x01, 0x4d};
+
+ pr_info("IRIS Registers [address] : value\n");
+
+ for (i = 0; i < ARRAY_SIZE(regs_array); i++) {
+ reg_val = wcnss_rf_read_reg(regs_array[i]);
+ pr_info("[0x%08x] : 0x%08x\n", regs_array[i], reg_val);
+ }
+}
+
void wcnss_log_debug_regs_on_bite(void)
{
struct platform_device *pdev = wcnss_get_platform_device();
@@ -768,10 +785,12 @@
clk_rate = clk_get_rate(measure);
pr_debug("wcnss: clock frequency is: %luHz\n", clk_rate);
- if (clk_rate)
+ if (clk_rate) {
wcnss_pronto_log_debug_regs();
- else
+ } else {
pr_err("clock frequency is zero, cannot access PMU or other registers\n");
+ wcnss_log_iris_regs();
+ }
}
}
#endif
diff --git a/drivers/nfc/nfc-nci.c b/drivers/nfc/nfc-nci.c
index c6192ed..a44c06c 100644
--- a/drivers/nfc/nfc-nci.c
+++ b/drivers/nfc/nfc-nci.c
@@ -1397,18 +1397,6 @@
gpio_set_value(platform_data->dis_gpio, 1);
goto err_nfcc_not_present;
}
- regulators.regulator = regulator_get(&client->dev, regulators.name);
- if (IS_ERR(regulators.regulator)) {
- r = PTR_ERR(regulators.regulator);
- pr_err("regulator get of %s failed (%d)\n", regulators.name, r);
- } else {
- /* Enable the regulator */
- r = regulator_enable(regulators.regulator);
- if (r) {
- pr_err("vreg %s enable failed (%d)\n",
- regulators.name, r);
- }
- }
logging_level = 0;
/* request irq. The irq is set whenever the chip has data available
diff --git a/drivers/nfc/nfc-nci.h b/drivers/nfc/nfc-nci.h
index 9bfb77d..297c152 100644
--- a/drivers/nfc/nfc-nci.h
+++ b/drivers/nfc/nfc-nci.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
@@ -223,9 +223,3 @@
unsigned int reg;
};
#endif
-/* enable LDO */
-struct vregs_info {
- const char * const name;
- struct regulator *regulator;
-};
-struct vregs_info regulators = {"vlogic", NULL};
diff --git a/drivers/power/qpnp-bms.c b/drivers/power/qpnp-bms.c
index bfe1f43..a0d9a24 100644
--- a/drivers/power/qpnp-bms.c
+++ b/drivers/power/qpnp-bms.c
@@ -606,12 +606,14 @@
temp_current = div_s64((vsense_uv * 1000000LL),
(int)chip->r_sense_uohm);
+ *result_ua = temp_current;
rc = qpnp_iadc_comp_result(chip->iadc_dev, &temp_current);
if (rc)
pr_debug("error compensation failed: %d\n", rc);
+ pr_debug("%d uA err compensated ibat=%llduA\n",
+ *result_ua, temp_current);
*result_ua = temp_current;
- pr_debug("err compensated ibat=%duA\n", *result_ua);
return 0;
}
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index 7689265..0870202 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -114,6 +114,9 @@
#define USB_OCP_CLR 0x53
#define BAT_IF_TEMP_STATUS 0x09
#define BOOST_ILIM 0x78
+#define USB_SPARE 0xDF
+#define DC_COMP_OVR1 0xE9
+#define CHGR_COMP_OVR1 0xEE
#define REG_OFFSET_PERP_SUBTYPE 0x05
@@ -319,6 +322,7 @@
bool aicl_settled;
bool use_external_rsense;
bool fastchg_on;
+ bool parallel_ovp_mode;
unsigned int bpd_detection;
unsigned int max_bat_chg_current;
unsigned int warm_bat_chg_ma;
@@ -385,6 +389,8 @@
bool power_stage_workaround_enable;
};
+static void
+qpnp_chg_set_appropriate_battery_current(struct qpnp_chg_chip *chip);
static struct of_device_id qpnp_charger_match_table[] = {
{ .compatible = QPNP_CHARGER_DEV_NAME, },
@@ -1011,10 +1017,68 @@
return iusbmax_ma;
}
+#define ILIMIT_OVR_0 0x02
+static int
+override_dcin_ilimit(struct qpnp_chg_chip *chip, bool override)
+{
+ int rc;
+
+ pr_debug("override %d\n", override);
+ rc = qpnp_chg_masked_write(chip,
+ chip->dc_chgpth_base + SEC_ACCESS,
+ 0xA5,
+ 0xA5, 1);
+ rc |= qpnp_chg_masked_write(chip,
+ chip->dc_chgpth_base + DC_COMP_OVR1,
+ 0xFF,
+ override ? ILIMIT_OVR_0 : 0, 1);
+ if (rc) {
+ pr_err("Failed to override dc ilimit rc = %d\n", rc);
+ return rc;
+ }
+
+ return rc;
+}
+
+#define DUAL_PATH_EN BIT(7)
+static int
+switch_parallel_ovp_mode(struct qpnp_chg_chip *chip, bool enable)
+{
+ int rc = 0;
+
+ if (!chip->usb_chgpth_base || !chip->dc_chgpth_base)
+ return rc;
+
+ pr_debug("enable %d\n", enable);
+ rc = override_dcin_ilimit(chip, 1);
+ udelay(10);
+
+ /* enable/disable dual path mode */
+ rc = qpnp_chg_masked_write(chip,
+ chip->usb_chgpth_base + SEC_ACCESS,
+ 0xA5,
+ 0xA5, 1);
+ rc |= qpnp_chg_masked_write(chip,
+ chip->usb_chgpth_base + USB_SPARE,
+ 0xFF,
+ enable ? DUAL_PATH_EN : 0, 1);
+ if (rc) {
+ pr_err("Failed to turn on usb ovp rc = %d\n", rc);
+ return rc;
+ }
+
+ rc = override_dcin_ilimit(chip, 0);
+ return rc;
+}
+
#define USB_SUSPEND_BIT BIT(0)
static int
qpnp_chg_usb_suspend_enable(struct qpnp_chg_chip *chip, int enable)
{
+ /* Turn off DC OVP FET when going into USB suspend */
+ if (chip->parallel_ovp_mode && enable)
+ switch_parallel_ovp_mode(chip, 0);
+
return qpnp_chg_masked_write(chip,
chip->usb_chgpth_base + CHGR_USB_USB_SUSP,
USB_SUSPEND_BIT,
@@ -1796,6 +1860,29 @@
return (chgr_sts & FAST_CHG_ON_IRQ) ? 1 : 0;
}
+#define VBATDET_BYPASS 0x01
+static int
+bypass_vbatdet_comp(struct qpnp_chg_chip *chip, bool bypass)
+{
+ int rc;
+
+ pr_debug("bypass %d\n", bypass);
+ rc = qpnp_chg_masked_write(chip,
+ chip->chgr_base + SEC_ACCESS,
+ 0xA5,
+ 0xA5, 1);
+ rc |= qpnp_chg_masked_write(chip,
+ chip->chgr_base + CHGR_COMP_OVR1,
+ 0xFF,
+ bypass ? VBATDET_BYPASS : 0, 1);
+ if (rc) {
+ pr_err("Failed to bypass vbatdet comp rc = %d\n", rc);
+ return rc;
+ }
+
+ return rc;
+}
+
static irqreturn_t
qpnp_chg_chgr_chg_fastchg_irq_handler(int irq, void *_chip)
{
@@ -1823,6 +1910,11 @@
if (fastchg_on) {
chip->chg_done = false;
+ bypass_vbatdet_comp(chip, 1);
+ if (chip->bat_is_warm || chip->bat_is_cool) {
+ qpnp_chg_set_appropriate_vddmax(chip);
+ qpnp_chg_set_appropriate_battery_current(chip);
+ }
if (chip->resuming_charging) {
chip->resuming_charging = false;
@@ -1834,6 +1926,13 @@
msecs_to_jiffies(EOC_CHECK_PERIOD_MS));
pm_stay_awake(chip->dev);
}
+ if (chip->parallel_ovp_mode)
+ switch_parallel_ovp_mode(chip, 1);
+ } else {
+ if (chip->parallel_ovp_mode)
+ switch_parallel_ovp_mode(chip, 0);
+ if (!chip->bat_is_warm && !chip->bat_is_cool)
+ bypass_vbatdet_comp(chip, 0);
}
}
@@ -1950,6 +2049,9 @@
if (qpnp_chg_is_otg_en_set(chip))
return 0;
+ if (chip->parallel_ovp_mode)
+ switch_parallel_ovp_mode(chip, 0);
+
if (chip->type == SMBBP) {
rc = qpnp_chg_masked_write(chip,
chip->boost_base + BOOST_ILIM,
@@ -2359,7 +2461,7 @@
pr_debug("Unable to read batt temperature rc=%d\n", rc);
return 0;
}
- pr_debug("get_bat_temp %d %lld\n",
+ pr_debug("get_bat_temp %d, %lld\n",
results.adc_code, results.physical);
return (int)results.physical;
@@ -2701,6 +2803,25 @@
return 0;
}
+static void
+qpnp_chg_set_appropriate_battery_current(struct qpnp_chg_chip *chip)
+{
+ unsigned int chg_current = chip->max_bat_chg_current;
+
+ if (chip->bat_is_cool)
+ chg_current = min(chg_current, chip->cool_bat_chg_ma);
+
+ if (chip->bat_is_warm)
+ chg_current = min(chg_current, chip->warm_bat_chg_ma);
+
+ if (chip->therm_lvl_sel != 0 && chip->thermal_mitigation)
+ chg_current = min(chg_current,
+ chip->thermal_mitigation[chip->therm_lvl_sel]);
+
+ pr_debug("setting %d mA\n", chg_current);
+ qpnp_chg_ibatmax_set(chip, chg_current);
+}
+
static int
qpnp_chg_vddsafe_set(struct qpnp_chg_chip *chip, int voltage)
{
@@ -2909,25 +3030,6 @@
}
static void
-qpnp_chg_set_appropriate_battery_current(struct qpnp_chg_chip *chip)
-{
- unsigned int chg_current = chip->max_bat_chg_current;
-
- if (chip->bat_is_cool)
- chg_current = min(chg_current, chip->cool_bat_chg_ma);
-
- if (chip->bat_is_warm)
- chg_current = min(chg_current, chip->warm_bat_chg_ma);
-
- if (chip->therm_lvl_sel != 0 && chip->thermal_mitigation)
- chg_current = min(chg_current,
- chip->thermal_mitigation[chip->therm_lvl_sel]);
-
- pr_debug("setting %d mA\n", chg_current);
- qpnp_chg_ibatmax_set(chip, chg_current);
-}
-
-static void
qpnp_batt_system_temp_level_set(struct qpnp_chg_chip *chip, int lvl_sel)
{
if (lvl_sel >= 0 && lvl_sel < chip->thermal_levels) {
@@ -3456,7 +3558,7 @@
state == ADC_TM_WARM_STATE ? "warm" : "cool");
if (state == ADC_TM_WARM_STATE) {
- if (temp > chip->warm_bat_decidegc) {
+ if (temp >= chip->warm_bat_decidegc) {
/* Normal to warm */
bat_warm = true;
bat_cool = false;
@@ -3464,7 +3566,7 @@
chip->warm_bat_decidegc - HYSTERISIS_DECIDEGC;
chip->adc_param.state_request =
ADC_TM_COOL_THR_ENABLE;
- } else if (temp >
+ } else if (temp >=
chip->cool_bat_decidegc + HYSTERISIS_DECIDEGC){
/* Cool to normal */
bat_warm = false;
@@ -3476,7 +3578,7 @@
ADC_TM_HIGH_LOW_THR_ENABLE;
}
} else {
- if (temp < chip->cool_bat_decidegc) {
+ if (temp <= chip->cool_bat_decidegc) {
/* Normal to cool */
bat_warm = false;
bat_cool = true;
@@ -3484,7 +3586,7 @@
chip->cool_bat_decidegc + HYSTERISIS_DECIDEGC;
chip->adc_param.state_request =
ADC_TM_WARM_THR_ENABLE;
- } else if (temp <
+ } else if (temp <=
chip->warm_bat_decidegc - HYSTERISIS_DECIDEGC){
/* Warm to normal */
bat_warm = false;
@@ -3501,9 +3603,6 @@
chip->bat_is_cool = bat_cool;
chip->bat_is_warm = bat_warm;
- if (bat_cool || bat_warm)
- chip->resuming_charging = false;
-
/**
* set appropriate voltages and currents.
*
@@ -3511,9 +3610,25 @@
* driver will not resume with SoC. Only vbatdet is used to
* determine resume of charging.
*/
- qpnp_chg_set_appropriate_vddmax(chip);
- qpnp_chg_set_appropriate_battery_current(chip);
- qpnp_chg_set_appropriate_vbatdet(chip);
+ if (bat_cool || bat_warm) {
+ chip->resuming_charging = false;
+ qpnp_chg_set_appropriate_vbatdet(chip);
+
+ /* To avoid ARB, only vbatdet is configured in
+ * warm/cold zones. Once vbat < vbatdet the
+ * appropriate vddmax/ibatmax adjustments will
+ * be made in the fast charge interrupt. */
+ bypass_vbatdet_comp(chip, 1);
+ qpnp_chg_charge_en(chip, !chip->charging_disabled);
+ qpnp_chg_charge_en(chip, chip->charging_disabled);
+ qpnp_chg_charge_en(chip, !chip->charging_disabled);
+ } else {
+ bypass_vbatdet_comp(chip, 0);
+ /* restore normal parameters */
+ qpnp_chg_set_appropriate_vbatdet(chip);
+ qpnp_chg_set_appropriate_vddmax(chip);
+ qpnp_chg_set_appropriate_battery_current(chip);
+ }
}
pr_debug("warm %d, cool %d, low = %d deciDegC, high = %d deciDegC\n",
@@ -4643,6 +4758,9 @@
chip->ibat_calibration_enabled =
of_property_read_bool(chip->spmi->dev.of_node,
"qcom,ibat-calibration-enabled");
+ chip->parallel_ovp_mode =
+ of_property_read_bool(chip->spmi->dev.of_node,
+ "qcom,parallel-ovp-mode");
of_get_property(chip->spmi->dev.of_node, "qcom,thermal-mitigation",
&(chip->thermal_levels));
diff --git a/drivers/slimbus/slim-msm-ngd.c b/drivers/slimbus/slim-msm-ngd.c
index 0b8c931..f858822 100644
--- a/drivers/slimbus/slim-msm-ngd.c
+++ b/drivers/slimbus/slim-msm-ngd.c
@@ -92,25 +92,25 @@
u32 stat = readl_relaxed(ngd + NGD_INT_STAT);
u32 pstat;
- if (stat & NGD_INT_TX_MSG_SENT) {
+ if ((stat & NGD_INT_MSG_BUF_CONTE) ||
+ (stat & NGD_INT_MSG_TX_INVAL) || (stat & NGD_INT_DEV_ERR) ||
+ (stat & NGD_INT_TX_NACKED_2)) {
+ writel_relaxed(stat, ngd + NGD_INT_CLR);
+ dev->err = -EIO;
+
+ dev_err(dev->dev, "NGD interrupt error:0x%x, err:%d", stat,
+ dev->err);
+ /* Guarantee that error interrupts are cleared */
+ mb();
+ if (dev->wr_comp)
+ complete(dev->wr_comp);
+
+ } else if (stat & NGD_INT_TX_MSG_SENT) {
writel_relaxed(NGD_INT_TX_MSG_SENT, ngd + NGD_INT_CLR);
/* Make sure interrupt is cleared */
mb();
if (dev->wr_comp)
complete(dev->wr_comp);
- } else if ((stat & NGD_INT_MSG_BUF_CONTE) ||
- (stat & NGD_INT_MSG_TX_INVAL) || (stat & NGD_INT_DEV_ERR) ||
- (stat & NGD_INT_TX_NACKED_2)) {
- dev_err(dev->dev, "NGD interrupt error:0x%x", stat);
- writel_relaxed(stat, ngd + NGD_INT_CLR);
- /* Guarantee that error interrupts are cleared */
- mb();
- if (((stat & NGD_INT_TX_NACKED_2) ||
- (stat & NGD_INT_MSG_TX_INVAL))) {
- dev->err = -EIO;
- if (dev->wr_comp)
- complete(dev->wr_comp);
- }
}
if (stat & NGD_INT_RX_MSG_RCVD) {
u32 rx_buf[10];
diff --git a/drivers/slimbus/slimbus.c b/drivers/slimbus/slimbus.c
index fc7c550..caf7a87 100644
--- a/drivers/slimbus/slimbus.c
+++ b/drivers/slimbus/slimbus.c
@@ -689,9 +689,12 @@
mutex_lock(&ctrl->m_ctrl);
txn = ctrl->txnt[tid];
- if (txn == NULL) {
- dev_err(&ctrl->dev, "Got response to invalid TID:%d, len:%d",
+ if (txn == NULL || txn->rbuf == NULL) {
+ if (txn == NULL)
+ dev_err(&ctrl->dev, "Got response to invalid TID:%d, len:%d",
tid, len);
+ else
+ dev_err(&ctrl->dev, "Invalid client buffer passed\n");
mutex_unlock(&ctrl->m_ctrl);
return;
}
diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c
index 517ec05..4058bec 100644
--- a/drivers/tty/serial/msm_serial_hs.c
+++ b/drivers/tty/serial/msm_serial_hs.c
@@ -3,7 +3,7 @@
* MSM 7k High speed uart driver
*
* Copyright (c) 2008 Google Inc.
- * Copyright (c) 2007-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2007-2014, The Linux Foundation. All rights reserved.
* Modified: Nick Pelly <npelly@google.com>
*
* All source code in this file is licensed under the following license
@@ -94,7 +94,6 @@
#define MSM_HS_DBG(x...) do { \
if (hs_serial_debug_mask >= DBG_LEV) { \
- pr_debug(x); \
if (ipc_msm_hs_log_ctxt) \
ipc_log_string(ipc_msm_hs_log_ctxt, x); \
} \
@@ -102,7 +101,6 @@
#define MSM_HS_INFO(x...) do { \
if (hs_serial_debug_mask >= INFO_LEV) {\
- pr_info(x); \
if (ipc_msm_hs_log_ctxt) \
ipc_log_string(ipc_msm_hs_log_ctxt, x); \
} \
@@ -141,7 +139,7 @@
FLUSH_NONE,
FLUSH_DATA_READY,
FLUSH_DATA_INVALID, /* values after this indicate invalid data */
- FLUSH_IGNORE = FLUSH_DATA_INVALID,
+ FLUSH_IGNORE,
FLUSH_STOP,
FLUSH_SHUTDOWN,
};
@@ -205,6 +203,8 @@
struct delayed_work flip_insert_work;
struct tasklet_struct tlet;
struct msm_hs_sps_ep_conn_data prod;
+ bool rx_cmd_queued;
+ bool rx_cmd_exec;
};
enum buffer_states {
NONE_PENDING = 0x0,
@@ -271,6 +271,8 @@
int rx_count_callback;
bool rx_bam_inprogress;
unsigned int *reg_ptr;
+ wait_queue_head_t bam_disconnect_wait;
+
};
unsigned int regmap_nonblsp[UART_DM_LAST] = {
@@ -344,7 +346,6 @@
#define BLSP_UART_CLK_FMAX 63160000
static struct dentry *debug_base;
-static struct msm_hs_port q_uart_port[UARTDM_NR];
static struct platform_driver msm_serial_hs_platform_driver;
static struct uart_driver msm_hs_driver;
static struct uart_ops msm_hs_ops;
@@ -352,6 +353,7 @@
static void msm_serial_hs_rx_tlet(unsigned long tlet_ptr);
static void flip_insert_work(struct work_struct *work);
static void msm_hs_bus_voting(struct msm_hs_port *msm_uport, unsigned int vote);
+static struct msm_hs_port *msm_hs_get_hs_port(int port_index);
#define UARTDM_TO_MSM(uart_port) \
container_of((uart_port), struct msm_hs_port, uport)
@@ -424,6 +426,7 @@
}
}
msm_uport->clk_state = MSM_HS_CLK_ON;
+ MSM_HS_DBG("%s: Clock ON successful\n", __func__);
}
@@ -432,71 +435,98 @@
static void msm_hs_clock_unvote(struct msm_hs_port *msm_uport)
{
- int rc = atomic_dec_return(&msm_uport->clk_count);
+ int rc = atomic_read(&msm_uport->clk_count);
- if (rc < 0) {
- msm_hs_bus_voting(msm_uport, BUS_RESET);
+ if (rc <= 0) {
WARN(rc, "msm_uport->clk_count < 0!");
dev_err(msm_uport->uport.dev,
- "%s: Clocks count invalid [%d]\n", __func__,
- atomic_read(&msm_uport->clk_count));
+ "%s: Clocks count invalid [%d]\n", __func__, rc);
return;
}
+ rc = atomic_dec_return(&msm_uport->clk_count);
if (0 == rc) {
- msm_hs_bus_voting(msm_uport, BUS_RESET);
/* Turn off the core clk and iface clk*/
clk_disable_unprepare(msm_uport->clk);
if (msm_uport->pclk)
clk_disable_unprepare(msm_uport->pclk);
+ /* Unvote the PNOC clock */
+ msm_hs_bus_voting(msm_uport, BUS_RESET);
msm_uport->clk_state = MSM_HS_CLK_OFF;
+ MSM_HS_DBG("%s: Clock OFF successful\n", __func__);
}
}
+/* Check if the uport line number matches with user id stored in pdata.
+ * User id information is stored during initialization. This function
+ * ensues that the same device is selected */
+
+static struct msm_hs_port *get_matching_hs_port(struct platform_device *pdev)
+{
+ struct msm_serial_hs_platform_data *pdata = pdev->dev.platform_data;
+ struct msm_hs_port *msm_uport = msm_hs_get_hs_port(pdev->id);
+
+ if ((!msm_uport) || (msm_uport->uport.line != pdev->id
+ && msm_uport->uport.line != pdata->userid)) {
+ MSM_HS_ERR("uport line number mismatch!");
+ WARN_ON(1);
+ return NULL;
+ }
+
+ return msm_uport;
+}
+
static ssize_t show_clock(struct device *dev, struct device_attribute *attr,
char *buf)
{
int state = 1;
+ ssize_t ret = 0;
enum msm_hs_clk_states_e clk_state;
unsigned long flags;
-
struct platform_device *pdev = container_of(dev, struct
platform_device, dev);
- struct msm_hs_port *msm_uport = &q_uart_port[pdev->id];
+ struct msm_hs_port *msm_uport = get_matching_hs_port(pdev);
- spin_lock_irqsave(&msm_uport->uport.lock, flags);
- clk_state = msm_uport->clk_state;
- spin_unlock_irqrestore(&msm_uport->uport.lock, flags);
+ /* This check should not fail */
+ if (msm_uport) {
+ spin_lock_irqsave(&msm_uport->uport.lock, flags);
+ clk_state = msm_uport->clk_state;
+ spin_unlock_irqrestore(&msm_uport->uport.lock, flags);
- if (clk_state <= MSM_HS_CLK_OFF)
- state = 0;
+ if (clk_state <= MSM_HS_CLK_OFF)
+ state = 0;
+ ret = snprintf(buf, PAGE_SIZE, "%d\n", state);
+ }
- return snprintf(buf, PAGE_SIZE, "%d\n", state);
+ return ret;
}
static ssize_t set_clock(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
int state;
+ ssize_t ret = 0;
struct platform_device *pdev = container_of(dev, struct
platform_device, dev);
- struct msm_hs_port *msm_uport = &q_uart_port[pdev->id];
+ struct msm_hs_port *msm_uport = get_matching_hs_port(pdev);
- state = buf[0] - '0';
- switch (state) {
- case 0: {
- msm_hs_request_clock_off(&msm_uport->uport);
- break;
+ /* This check should not fail */
+ if (msm_uport) {
+ state = buf[0] - '0';
+ switch (state) {
+ case 0:
+ msm_hs_request_clock_off(&msm_uport->uport);
+ ret = count;
+ break;
+ case 1:
+ msm_hs_request_clock_on(&msm_uport->uport);
+ ret = count;
+ break;
+ default:
+ ret = -EINVAL;
+ }
}
- case 1: {
- msm_hs_request_clock_on(&msm_uport->uport);
- break;
- }
- default: {
- return -EINVAL;
- }
- }
- return count;
+ return ret;
}
static DEVICE_ATTR(clock, S_IWUSR | S_IRUGO, show_clock, set_clock);
@@ -583,22 +613,33 @@
*/
static void dump_uart_hs_registers(struct msm_hs_port *msm_uport)
{
- msm_hs_clock_vote(msm_uport);
- MSM_HS_DBG("============= UART Registers ================\n");
- MSM_HS_DBG("UART_DM_MR1:%x\n", msm_hs_read(&(msm_uport->uport),
- UART_DM_MR1));
- MSM_HS_DBG("UART_DM_MR2:%x\n", msm_hs_read(&(msm_uport->uport),
- UART_DM_MR2));
- MSM_HS_DBG("UART_DM_IPR:%x\n", msm_hs_read(&(msm_uport->uport),
- UART_DM_IPR));
- MSM_HS_DBG("UART_DM_RFWR:%x\n", msm_hs_read(&(msm_uport->uport),
- UART_DM_RFWR));
- MSM_HS_DBG("UART_DM_SR:%x\n", msm_hs_read(&(msm_uport->uport),
- UART_DM_SR));
- MSM_HS_DBG("UART_DM_IMR: %x\n", msm_hs_read(&(msm_uport->uport),
- UART_DM_IMR));
- MSM_HS_DBG("=============================================\n");
- msm_hs_clock_unvote(msm_uport);
+ struct uart_port *uport = &(msm_uport->uport);
+ if (msm_uport->clk_state != MSM_HS_CLK_ON) {
+ MSM_HS_WARN("%s: Failed.Clocks are OFF\n", __func__);
+ return;
+ }
+
+ MSM_HS_DBG(
+ "MR1:%x MR2:%x TFWR:%x RFWR:%x DMEN:%x IMR:%x MISR:%x NCF_TX:%x\n",
+ msm_hs_read(uport, UART_DM_MR1),
+ msm_hs_read(uport, UART_DM_MR2),
+ msm_hs_read(uport, UART_DM_TFWR),
+ msm_hs_read(uport, UART_DM_RFWR),
+ msm_hs_read(uport, UART_DM_DMEN),
+ msm_hs_read(uport, UART_DM_IMR),
+ msm_hs_read(uport, UART_DM_MISR),
+ msm_hs_read(uport, UART_DM_NCF_TX));
+ MSM_HS_INFO("SR:%x ISR:%x DMRX:%x RX_SNAP:%x TXFS:%x RXFS:%x\n",
+ msm_hs_read(uport, UART_DM_SR),
+ msm_hs_read(uport, UART_DM_ISR),
+ msm_hs_read(uport, UART_DM_DMRX),
+ msm_hs_read(uport, UART_DM_RX_TOTAL_SNAP),
+ msm_hs_read(uport, UART_DM_TXFS),
+ msm_hs_read(uport, UART_DM_RXFS));
+ MSM_HS_DBG("clk_req_state:0x%x rx.flush:%u\n",
+ msm_uport->clk_req_off_state,
+ msm_uport->rx.flush);
+ MSM_HS_DBG("clk_state:%d", msm_uport->clk_state);
}
static void msm_hs_release_port(struct uart_port *port)
@@ -742,9 +783,11 @@
return -EINVAL;
}
- msm_uport = &q_uart_port[pdev->id];
- dev = msm_uport->uport.dev;
+ msm_uport = get_matching_hs_port(pdev);
+ if (!msm_uport)
+ return -EINVAL;
+ dev = msm_uport->uport.dev;
sysfs_remove_file(&pdev->dev.kobj, &dev_attr_clock.attr);
debugfs_remove(msm_uport->loopback_dir);
@@ -1096,6 +1139,10 @@
struct msm_hs_rx *rx = &msm_uport->rx;
struct sps_pipe *sps_pipe_handle = rx->prod.pipe_handle;
+ if (msm_uport->clk_state != MSM_HS_CLK_ON) {
+ MSM_HS_WARN("%s: Failed.Clocks are OFF\n", __func__);
+ return;
+ }
mutex_lock(&msm_uport->clk_mutex);
msm_hs_write(uport, UART_DM_IMR, 0);
@@ -1109,6 +1156,8 @@
data = msm_hs_read(uport, UART_DM_MR1);
data &= ~UARTDM_MR1_RX_RDY_CTL_BMSK;
msm_hs_write(uport, UART_DM_MR1, data);
+ /* set RFR_N to high */
+ msm_hs_write(uport, UART_DM_CR, RFR_HIGH);
/*
* Disable Rx channel of UARTDM
@@ -1195,10 +1244,12 @@
msm_hs_write(uport, UART_DM_CR, RESET_RX);
msm_hs_write(uport, UART_DM_CR, RESET_TX);
+ /* Issue TX BAM Start IFC command */
+ msm_hs_write(uport, UART_DM_CR, START_TX_BAM_IFC);
if (msm_uport->rx.flush == FLUSH_NONE) {
wake_lock(&msm_uport->rx.wake_lock);
- msm_uport->rx.flush = FLUSH_IGNORE;
+ msm_uport->rx.flush = FLUSH_DATA_INVALID;
/*
* Before using dmov APIs make sure that
* previous writel are completed. Hence
@@ -1215,6 +1266,7 @@
MSM_HS_ERR("%s(): sps_disconnect failed\n",
__func__);
msm_hs_spsconnect_rx(uport);
+ msm_uport->rx.flush = FLUSH_IGNORE;
msm_serial_hs_rx_tlet((unsigned long) &rx->tlet);
} else {
msm_uport->rx_discard_flush_issued = true;
@@ -1237,12 +1289,12 @@
* UART Core would trigger RFR if it is not having any space with
* RX FIFO.
*/
+ /* Pulling RFR line high */
+ msm_hs_write(uport, UART_DM_CR, RFR_LOW);
data = msm_hs_read(uport, UART_DM_MR1);
data &= ~(UARTDM_MR1_CTS_CTL_BMSK | UARTDM_MR1_RX_RDY_CTL_BMSK);
- if (c_cflag & CRTSCTS) {
data |= UARTDM_MR1_CTS_CTL_BMSK;
data |= UARTDM_MR1_RX_RDY_CTL_BMSK;
- }
msm_hs_write(uport, UART_DM_MR1, data);
msm_hs_write(uport, UART_DM_IMR, msm_uport->imr_reg);
@@ -1265,6 +1317,7 @@
msm_hs_clock_vote(msm_uport);
data = msm_hs_read(uport, UART_DM_SR);
msm_hs_clock_unvote(msm_uport);
+ MSM_HS_DBG("%s(): SR Reg Read 0x%x", __func__, data);
if (data & UARTDM_SR_TXEMT_BMSK)
ret = TIOCSER_TEMT;
@@ -1300,6 +1353,9 @@
wake_lock_timeout(&msm_uport->rx.wake_lock, HZ / 2);
msm_uport->rx.flush = FLUSH_SHUTDOWN;
+ MSM_HS_DBG("%s: Calling Completion\n", __func__);
+ wake_up(&msm_uport->bam_disconnect_wait);
+ MSM_HS_DBG("%s: Done Completion\n", __func__);
wake_up(&msm_uport->rx.wait);
}
@@ -1316,16 +1372,19 @@
struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
unsigned int data;
- /* disable dlink */
- data = msm_hs_read(uport, UART_DM_DMEN);
- if (is_blsp_uart(msm_uport))
- data &= ~UARTDM_RX_BAM_ENABLE_BMSK;
- else
- data &= ~UARTDM_RX_DM_EN_BMSK;
- msm_hs_write(uport, UART_DM_DMEN, data);
+ MSM_HS_DBG("In %s():\n", __func__);
+ if (msm_uport->clk_state != MSM_HS_CLK_OFF) {
+ /* disable dlink */
+ data = msm_hs_read(uport, UART_DM_DMEN);
+ if (is_blsp_uart(msm_uport))
+ data &= ~UARTDM_RX_BAM_ENABLE_BMSK;
+ else
+ data &= ~UARTDM_RX_DM_EN_BMSK;
+ msm_hs_write(uport, UART_DM_DMEN, data);
- /* calling DMOV or CLOCK API. Hence mb() */
- mb();
+ /* calling DMOV or CLOCK API. Hence mb() */
+ mb();
+ }
/* Disable the receiver */
if (msm_uport->rx.flush == FLUSH_NONE) {
wake_lock(&msm_uport->rx.wake_lock);
@@ -1352,7 +1411,7 @@
int aligned_tx_count;
dma_addr_t src_addr;
dma_addr_t aligned_src_addr;
- u32 flags = SPS_IOVEC_FLAG_EOT;
+ u32 flags = SPS_IOVEC_FLAG_EOT | SPS_IOVEC_FLAG_INT;
struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
struct msm_hs_tx *tx = &msm_uport->tx;
struct circ_buf *tx_buf = &msm_uport->uport.state->xmit;
@@ -1360,6 +1419,12 @@
if (uart_circ_empty(tx_buf) || uport->state->port.tty->stopped) {
msm_hs_stop_tx_locked(uport);
+ if (msm_uport->clk_state == MSM_HS_CLK_REQUEST_OFF) {
+ MSM_HS_DBG("%s(): Clock off requested calling WQ",
+ __func__);
+ queue_work(msm_uport->hsuart_wq,
+ &msm_uport->clock_off_w);
+ }
return;
}
@@ -1385,10 +1450,9 @@
dma_sync_single_for_device(uport->dev, aligned_src_addr,
aligned_tx_count, DMA_TO_DEVICE);
- if (is_blsp_uart(msm_uport)) {
- /* Issue TX BAM Start IFC command */
- msm_hs_write(uport, UART_DM_CR, START_TX_BAM_IFC);
- } else {
+ if (is_blsp_uart(msm_uport))
+ tx->tx_count = tx_count;
+ else {
tx->command_ptr->num_rows =
(((tx_count + 15) >> 4) << 16) |
((tx_count + 15) >> 4);
@@ -1399,18 +1463,16 @@
*tx->command_ptr_ptr = CMD_PTR_LP |
DMOV_CMD_ADDR(tx->mapped_cmd_ptr);
+ /* Save tx_count to use in Callback */
+ tx->tx_count = tx_count;
+ msm_hs_write(uport, UART_DM_NCF_TX, tx_count);
+ msm_uport->imr_reg &= ~UARTDM_ISR_TX_READY_BMSK;
+ msm_hs_write(uport, UART_DM_IMR, msm_uport->imr_reg);
+ /* Calling next DMOV API. Hence mb() here. */
+ mb();
+
}
- /* Save tx_count to use in Callback */
- tx->tx_count = tx_count;
- msm_hs_write(uport, UART_DM_NCF_TX, tx_count);
-
- /* Disable the tx_ready interrupt */
- msm_uport->imr_reg &= ~UARTDM_ISR_TX_READY_BMSK;
- msm_hs_write(uport, UART_DM_IMR, msm_uport->imr_reg);
- /* Calling next DMOV API. Hence mb() here. */
- mb();
-
msm_uport->tx.flush = FLUSH_NONE;
if (is_blsp_uart(msm_uport)) {
@@ -1439,6 +1501,16 @@
unsigned int buffer_pending = msm_uport->rx.buffer_pending;
unsigned int data;
+ if (msm_uport->clk_state != MSM_HS_CLK_ON) {
+ MSM_HS_WARN("%s: Failed.Clocks are OFF\n", __func__);
+ return;
+ }
+ if (rx->rx_cmd_exec) {
+ MSM_HS_DBG("%s: Rx Cmd got executed, wait for rx_tlet\n",
+ __func__);
+ rx->flush = FLUSH_IGNORE;
+ return;
+ }
msm_uport->rx.buffer_pending = 0;
if (buffer_pending && hs_serial_debug_mask)
MSM_HS_ERR("Error: rx started in buffer state = %x",
@@ -1447,8 +1519,6 @@
msm_hs_write(uport, UART_DM_CR, RESET_STALE_INT);
msm_hs_write(uport, UART_DM_DMRX, UARTDM_RX_BUF_SIZE);
msm_hs_write(uport, UART_DM_CR, STALE_EVENT_ENABLE);
- msm_uport->imr_reg |= UARTDM_ISR_RXLEV_BMSK;
-
/*
* Enable UARTDM Rx Interface as previously it has been
* disable in set_termios before configuring baud rate.
@@ -1488,10 +1558,8 @@
sps_transfer_one(sps_pipe_handle, rx->rbuffer,
UARTDM_RX_BUF_SIZE, msm_uport, flags);
msm_uport->rx_bam_inprogress = false;
+ msm_uport->rx.rx_cmd_queued = true;
wake_up(&msm_uport->rx.wait);
- } else {
- msm_dmov_enqueue_cmd(msm_uport->dma_rx_channel,
- &msm_uport->rx.xfer);
}
MSM_HS_DBG("%s:Enqueue Rx Cmd\n", __func__);
dump_uart_hs_registers(msm_uport);
@@ -1551,7 +1619,7 @@
static void msm_serial_hs_rx_tlet(unsigned long tlet_ptr)
{
int retval;
- int rx_count;
+ int rx_count = 0;
unsigned long status;
unsigned long flags;
unsigned int error_f = 0;
@@ -1571,6 +1639,9 @@
notify = &msm_uport->notify;
rx = &msm_uport->rx;
+ msm_uport->rx.rx_cmd_queued = false;
+ msm_uport->rx.rx_cmd_exec = false;
+
status = msm_hs_read(uport, UART_DM_SR);
spin_lock_irqsave(&uport->lock, flags);
@@ -1619,29 +1690,30 @@
}
}
- if (error_f)
- msm_hs_write(uport, UART_DM_CR, RESET_ERROR_STATUS);
-
- if (msm_uport->clk_req_off_state == CLK_REQ_OFF_FLUSH_ISSUED)
- msm_uport->clk_req_off_state = CLK_REQ_OFF_RXSTALE_FLUSHED;
+ if (error_f) {
+ if (msm_uport->clk_state == MSM_HS_CLK_ON)
+ msm_hs_write(uport, UART_DM_CR, RESET_ERROR_STATUS);
+ else
+ MSM_HS_WARN("%s: Failed.Clocks are OFF\n", __func__);
+ }
flush = msm_uport->rx.flush;
if (flush == FLUSH_IGNORE)
- if (!msm_uport->rx.buffer_pending)
+ if (!msm_uport->rx.buffer_pending) {
+ MSM_HS_DBG("%s: calling start_rx_locked\n", __func__);
msm_hs_start_rx_locked(uport);
-
- if (flush == FLUSH_STOP) {
- msm_uport->rx.flush = FLUSH_SHUTDOWN;
- wake_up(&msm_uport->rx.wait);
- }
+ }
if (flush >= FLUSH_DATA_INVALID)
goto out;
if (is_blsp_uart(msm_uport)) {
rx_count = msm_uport->rx_count_callback;
} else {
- rx_count = msm_hs_read(uport, UART_DM_RX_TOTAL_SNAP);
- /* order the read of rx.buffer */
- rmb();
+ if (msm_uport->clk_state == MSM_HS_CLK_ON) {
+ rx_count = msm_hs_read(uport, UART_DM_RX_TOTAL_SNAP);
+ /* order the read of rx.buffer */
+ rmb();
+ } else
+ MSM_HS_WARN("%s: Failed.Clocks are OFF\n", __func__);
}
MSM_HS_DBG("%s():[UART_RX]<%d>\n", __func__, rx_count);
@@ -1656,24 +1728,21 @@
retval << 5 | (rx_count - retval) << 16;
}
}
-
- MSM_HS_DBG("%s() read rx buffer complete", __func__);
- /* order the read of rx.buffer and the start of next rx xfer */
- wmb();
-
- if (!msm_uport->rx.buffer_pending) {
+ if (!msm_uport->rx.buffer_pending && !msm_uport->rx.rx_cmd_queued) {
if (is_blsp_uart(msm_uport)) {
msm_uport->rx.flush = FLUSH_NONE;
msm_uport->rx_bam_inprogress = true;
sps_pipe_handle = rx->prod.pipe_handle;
+ MSM_HS_DBG("Queing bam descriptor\n");
/* Queue transfer request to SPS */
sps_transfer_one(sps_pipe_handle, rx->rbuffer,
UARTDM_RX_BUF_SIZE, msm_uport, sps_flags);
msm_uport->rx_bam_inprogress = false;
+ msm_uport->rx.rx_cmd_queued = true;
wake_up(&msm_uport->rx.wait);
- } else {
+
+ } else
msm_hs_start_rx_locked(uport);
- }
}
out:
if (msm_uport->rx.buffer_pending) {
@@ -1695,8 +1764,12 @@
{
struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
+ if (msm_uport->clk_state != MSM_HS_CLK_ON) {
+ MSM_HS_WARN("%s: Failed.Clocks are OFF\n", __func__);
+ }
if (msm_uport->tx.tx_ready_int_en == 0) {
- msm_uport->tx.tx_ready_int_en = 1;
+ if (!is_blsp_uart(msm_uport))
+ msm_uport->tx.tx_ready_int_en = 1;
if (msm_uport->tx.dma_in_flight == 0)
msm_hs_submit_tx_locked(uport);
}
@@ -1718,11 +1791,12 @@
((struct sps_event_notify *)notify)->user;
msm_uport->notify = *notify;
- MSM_HS_DBG("%s: sps ev_id=%d, addr=0x%x, size=0x%x, flags=0x%x\n",
- __func__, notify->event_id,
- notify->data.transfer.iovec.addr,
- notify->data.transfer.iovec.size,
- notify->data.transfer.iovec.flags);
+ MSM_HS_DBG("%s: ev_id=%d, addr=0x%x, size=0x%x, flags=0x%x, line=%d\n",
+ __func__, notify->event_id,
+ notify->data.transfer.iovec.addr,
+ notify->data.transfer.iovec.size,
+ notify->data.transfer.iovec.flags,
+ msm_uport->uport.line);
tasklet_schedule(&msm_uport->tx.tlet);
}
@@ -1756,6 +1830,35 @@
unsigned long flags;
struct msm_hs_port *msm_uport = container_of((struct tasklet_struct *)
tlet_ptr, struct msm_hs_port, tx.tlet);
+ struct uart_port *uport = &msm_uport->uport;
+ struct circ_buf *tx_buf = &uport->state->xmit;
+ struct msm_hs_tx *tx = &msm_uport->tx;
+
+ /*
+ * Do the work buffer related work in BAM
+ * mode that is equivalent to legacy mode
+ */
+
+ if (!msm_uport->tty_flush_receive)
+ tx_buf->tail = (tx_buf->tail +
+ tx->tx_count) & ~UART_XMIT_SIZE;
+ else
+ msm_uport->tty_flush_receive = false;
+
+ tx->dma_in_flight = 0;
+
+ uport->icount.tx += tx->tx_count;
+
+ /*
+ * Calling to send next chunk of data
+ * If the circ buffer is empty, we stop
+ * If the clock off was requested, the clock
+ * off sequence is kicked off
+ */
+ msm_hs_submit_tx_locked(uport);
+
+ 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) {
@@ -1765,10 +1868,14 @@
return;
}
- msm_uport->imr_reg |= UARTDM_ISR_TX_READY_BMSK;
- msm_hs_write(&(msm_uport->uport), UART_DM_IMR, msm_uport->imr_reg);
- /* Calling clk API. Hence mb() requires. */
- mb();
+ /* TX_READY_BMSK only if non BAM mode */
+ if (!is_blsp_uart(msm_uport)) {
+ msm_uport->imr_reg |= UARTDM_ISR_TX_READY_BMSK;
+ msm_hs_write(&(msm_uport->uport), UART_DM_IMR,
+ msm_uport->imr_reg);
+ /* Calling clk API. Hence mb() requires. */
+ mb();
+ }
spin_unlock_irqrestore(&(msm_uport->uport.lock), flags);
MSM_HS_DBG("In %s()\n", __func__);
@@ -1804,6 +1911,7 @@
if (msm_uport->rx.flush == FLUSH_NONE) {
spin_lock_irqsave(&uport->lock, flags);
msm_uport->rx_count_callback = notify->data.transfer.iovec.size;
+ msm_uport->rx.rx_cmd_exec = true;
spin_unlock_irqrestore(&uport->lock, flags);
tasklet_schedule(&msm_uport->rx.tlet);
}
@@ -1873,7 +1981,12 @@
{
unsigned int set_rts;
unsigned int data;
+ struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
+ if (msm_uport->clk_state != MSM_HS_CLK_ON) {
+ MSM_HS_WARN("%s:Failed.Clocks are OFF\n", __func__);
+ return;
+ }
/* RTS is active low */
set_rts = TIOCM_RTS & mctrl ? 0 : 1;
@@ -1911,6 +2024,11 @@
{
struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
+ if (msm_uport->clk_state != MSM_HS_CLK_ON) {
+ MSM_HS_WARN("%s:Failed.Clocks are OFF\n", __func__);
+ return;
+ }
+
/* Enable DELTA_CTS Interrupt */
msm_uport->imr_reg |= UARTDM_ISR_DELTA_CTS_BMSK;
msm_hs_write(uport, UART_DM_IMR, msm_uport->imr_reg);
@@ -1935,6 +2053,12 @@
static void msm_hs_break_ctl(struct uart_port *uport, int ctl)
{
unsigned long flags;
+ struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
+
+ if (msm_uport->clk_state != MSM_HS_CLK_ON) {
+ MSM_HS_WARN("%s: Failed.Clocks are OFF\n", __func__);
+ return;
+ }
spin_lock_irqsave(&uport->lock, flags);
msm_hs_write(uport, UART_DM_CR, ctl ? START_BREAK : STOP_BREAK);
@@ -1967,6 +2091,12 @@
/* Handle CTS changes (Called from interrupt handler) */
static void msm_hs_handle_delta_cts_locked(struct uart_port *uport)
{
+ struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
+
+ if (msm_uport->clk_state != MSM_HS_CLK_ON) {
+ MSM_HS_WARN("%s: Failed.Clocks are OFF\n", __func__);
+ return;
+ }
/* clear interrupt */
msm_hs_write(uport, UART_DM_CR, RESET_CTS);
/* Calling CLOCK API. Hence mb() requires here. */
@@ -1986,60 +2116,47 @@
{
unsigned long sr_status;
unsigned long flags;
- int ret;
+ unsigned int data;
struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
struct circ_buf *tx_buf = &uport->state->xmit;
mutex_lock(&msm_uport->clk_mutex);
spin_lock_irqsave(&uport->lock, flags);
+ MSM_HS_DBG("In %s:\n", __func__);
/* Cancel if tx tty buffer is not empty, dma is in flight,
- * or tx fifo is not empty */
+ * or tx fifo is not empty
+ */
if (msm_uport->clk_state != MSM_HS_CLK_REQUEST_OFF ||
!uart_circ_empty(tx_buf) || msm_uport->tx.dma_in_flight ||
msm_uport->imr_reg & UARTDM_ISR_TXLEV_BMSK) {
spin_unlock_irqrestore(&uport->lock, flags);
mutex_unlock(&msm_uport->clk_mutex);
+ if (msm_uport->clk_state == MSM_HS_CLK_REQUEST_OFF) {
+ msm_uport->clk_state = MSM_HS_CLK_ON;
+ /* Pulling RFR line high */
+ msm_hs_write(uport, UART_DM_CR, RFR_LOW);
+ /* Enable auto RFR */
+ data = msm_hs_read(uport, UART_DM_MR1);
+ data |= UARTDM_MR1_RX_RDY_CTL_BMSK;
+ msm_hs_write(uport, UART_DM_MR1, data);
+ mb();
+ }
+ MSM_HS_DBG("%s(): clkstate %d", __func__, msm_uport->clk_state);
return -1;
}
- /* Make sure the uart is finished with the last byte */
- sr_status = msm_hs_read(uport, UARTDM_SR);
+ /* Make sure the uart is finished with the last byte,
+ * use BFamily Register
+ */
+ sr_status = msm_hs_read(uport, UART_DM_SR);
if (!(sr_status & UARTDM_SR_TXEMT_BMSK)) {
spin_unlock_irqrestore(&uport->lock, flags);
mutex_unlock(&msm_uport->clk_mutex);
+ MSM_HS_DBG("%s(): SR TXEMT fail %lx", __func__, sr_status);
return 0; /* retry */
}
- /* Make sure forced RXSTALE flush complete */
- switch (msm_uport->clk_req_off_state) {
- case CLK_REQ_OFF_START:
- msm_uport->clk_req_off_state = CLK_REQ_OFF_RXSTALE_ISSUED;
-
- if (!is_blsp_uart(msm_uport)) {
- msm_hs_write(uport, UART_DM_CR, FORCE_STALE_EVENT);
- /*
- * Before returning make sure that device writel
- * completed. Hence mb() requires here.
- */
- mb();
- }
- spin_unlock_irqrestore(&uport->lock, flags);
- mutex_unlock(&msm_uport->clk_mutex);
- return 0; /* RXSTALE flush not complete - retry */
- case CLK_REQ_OFF_RXSTALE_ISSUED:
- case CLK_REQ_OFF_FLUSH_ISSUED:
- spin_unlock_irqrestore(&uport->lock, flags);
- if (is_blsp_uart(msm_uport)) {
- msm_uport->clk_req_off_state =
- CLK_REQ_OFF_RXSTALE_FLUSHED;
- }
- mutex_unlock(&msm_uport->clk_mutex);
- return 0; /* RXSTALE flush not complete - retry */
- case CLK_REQ_OFF_RXSTALE_FLUSHED:
- break; /* continue */
- }
-
if (msm_uport->rx.flush != FLUSH_SHUTDOWN) {
if (msm_uport->rx.flush == FLUSH_NONE) {
msm_hs_stop_rx_locked(uport);
@@ -2047,24 +2164,23 @@
msm_uport->rx_discard_flush_issued = true;
}
+ MSM_HS_DBG("%s: rx.flush %d clk_state %d\n", __func__,
+ msm_uport->rx.flush, msm_uport->clk_state);
spin_unlock_irqrestore(&uport->lock, flags);
- if (msm_uport->rx_discard_flush_issued) {
- MSM_HS_DBG("%s(): wainting for flush completion.\n",
- __func__);
- ret = wait_event_timeout(msm_uport->rx.wait,
- msm_uport->rx_discard_flush_issued == false,
- RX_FLUSH_COMPLETE_TIMEOUT);
- if (!ret)
- MSM_HS_ERR("%s(): Flush complete pending.\n",
- __func__);
- }
-
mutex_unlock(&msm_uport->clk_mutex);
return 0; /* come back later to really clock off */
}
spin_unlock_irqrestore(&uport->lock, flags);
+ /* Pulling RFR line high */
+ msm_hs_write(uport, UART_DM_CR, RFR_LOW);
+ /* Enable auto RFR */
+ data = msm_hs_read(uport, UART_DM_MR1);
+ data |= UARTDM_MR1_RX_RDY_CTL_BMSK;
+ msm_hs_write(uport, UART_DM_MR1, data);
+ mb();
+
/* we really want to clock off */
msm_hs_clock_unvote(msm_uport);
@@ -2077,8 +2193,6 @@
spin_unlock_irqrestore(&uport->lock, flags);
- /* Reset PNOC Bus Scaling */
- msm_hs_bus_voting(msm_uport, BUS_RESET);
mutex_unlock(&msm_uport->clk_mutex);
return 1;
@@ -2142,11 +2256,6 @@
mb();
MSM_HS_DBG("%s:Stal Interrupt\n", __func__);
- if (msm_uport->clk_req_off_state ==
- CLK_REQ_OFF_RXSTALE_ISSUED)
- msm_uport->clk_req_off_state =
- CLK_REQ_OFF_FLUSH_ISSUED;
-
if (!is_blsp_uart(msm_uport) && (rx->flush == FLUSH_NONE)) {
rx->flush = FLUSH_DATA_READY;
msm_dmov_flush(msm_uport->dma_rx_channel, 1);
@@ -2170,7 +2279,8 @@
/* Complete DMA TX transactions and submit new transactions */
/* Do not update tx_buf.tail if uart_flush_buffer already
- called in serial core */
+ * called in serial core
+ */
if (!msm_uport->tty_flush_receive)
tx_buf->tail = (tx_buf->tail +
tx->tx_count) & ~UART_XMIT_SIZE;
@@ -2207,37 +2317,57 @@
return IRQ_HANDLED;
}
-/*
- * Find UART device port using its port index value.
+/* The following two functions provide interfaces to get the underlying
+ * port structure (struct uart_port or struct msm_hs_port) given
+ * the port index. msm_hs_get_uart port is called by clients.
+ * The function msm_hs_get_hs_port is for internal use
*/
+
struct uart_port *msm_hs_get_uart_port(int port_index)
{
- int i;
+ struct uart_state *state = msm_hs_driver.state + port_index;
- for (i = 0; i < UARTDM_NR; i++) {
- if (q_uart_port[i].uport.line == port_index)
- return &q_uart_port[i].uport;
- }
+ /* The uart_driver structure stores the states in an array.
+ * Thus the corresponding offset from the drv->state returns
+ * the state for the uart_port that is requested
+ */
+ if (port_index == state->uart_port->line)
+ return state->uart_port;
return NULL;
}
EXPORT_SYMBOL(msm_hs_get_uart_port);
+static struct msm_hs_port *msm_hs_get_hs_port(int port_index)
+{
+ struct uart_port *uport = msm_hs_get_uart_port(port_index);
+ if (uport)
+ return UARTDM_TO_MSM(uport);
+ return NULL;
+}
+
/* request to turn off uart clock once pending TX is flushed */
void msm_hs_request_clock_off(struct uart_port *uport) {
unsigned long flags;
struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
+ int data;
spin_lock_irqsave(&uport->lock, flags);
if (msm_uport->clk_state == MSM_HS_CLK_ON) {
msm_uport->clk_state = MSM_HS_CLK_REQUEST_OFF;
- msm_uport->clk_req_off_state = CLK_REQ_OFF_START;
- msm_uport->imr_reg |= UARTDM_ISR_TXLEV_BMSK;
- msm_hs_write(uport, UART_DM_IMR, msm_uport->imr_reg);
- /*
- * Complete device write before retuning back.
- * Hence mb() requires here.
- */
+ data = msm_hs_read(uport, UART_DM_MR1);
+ /*disable auto ready-for-receiving */
+ data &= ~UARTDM_MR1_RX_RDY_CTL_BMSK;
+ msm_hs_write(uport, UART_DM_MR1, data);
+ mb();
+ /* set RFR_N to high */
+ msm_hs_write(uport, UART_DM_CR, RFR_HIGH);
+
+ data = msm_hs_read(uport, UART_DM_SR);
+ MSM_HS_DBG("%s(): TXEMT, queuing clock off work\n",
+ __func__);
+ queue_work(msm_uport->hsuart_wq, &msm_uport->clock_off_w);
+
mb();
}
spin_unlock_irqrestore(&uport->lock, flags);
@@ -2254,6 +2384,15 @@
mutex_lock(&msm_uport->clk_mutex);
spin_lock_irqsave(&uport->lock, flags);
+ if (msm_uport->clk_state == MSM_HS_CLK_REQUEST_OFF) {
+ /* Pulling RFR line high */
+ msm_hs_write(uport, UART_DM_CR, RFR_LOW);
+ /* Enable auto RFR */
+ data = msm_hs_read(uport, UART_DM_MR1);
+ data |= UARTDM_MR1_RX_RDY_CTL_BMSK;
+ msm_hs_write(uport, UART_DM_MR1, data);
+ mb();
+ }
switch (msm_uport->clk_state) {
case MSM_HS_CLK_OFF:
wake_lock(&msm_uport->dma_wake_lock);
@@ -2263,7 +2402,7 @@
ret = msm_hs_clock_vote(msm_uport);
if (ret) {
- dev_err(uport->dev, "Clock ON Failure"
+ MSM_HS_INFO("Clock ON Failure"
"For UART CLK Stalling HSUART\n");
break;
}
@@ -2271,6 +2410,22 @@
spin_lock_irqsave(&uport->lock, flags);
/* else fall-through */
case MSM_HS_CLK_REQUEST_OFF:
+ hrtimer_cancel(&msm_uport->clk_off_timer);
+ if (msm_uport->rx.flush == FLUSH_STOP) {
+ spin_unlock_irqrestore(&uport->lock, flags);
+ MSM_HS_DBG("%s:Calling wait forxcompletion\n",
+ __func__);
+ ret = wait_event_timeout(msm_uport->bam_disconnect_wait,
+ msm_uport->rx.flush == FLUSH_SHUTDOWN, 300);
+ if (!ret)
+ MSM_HS_ERR("BAM Disconnect not happened\n");
+ spin_lock_irqsave(&uport->lock, flags);
+ MSM_HS_DBG("%s:DONE wait for completion\n", __func__);
+ }
+ MSM_HS_DBG("%s:clock state %d\n\n", __func__,
+ msm_uport->clk_state);
+ if (msm_uport->clk_state == MSM_HS_CLK_REQUEST_OFF)
+ msm_uport->clk_state = MSM_HS_CLK_ON;
if (msm_uport->rx.flush == FLUSH_STOP ||
msm_uport->rx.flush == FLUSH_SHUTDOWN) {
msm_hs_write(uport, UART_DM_CR, RESET_RX);
@@ -2283,7 +2438,8 @@
/* Complete above device write. Hence mb() here. */
mb();
}
- hrtimer_try_to_cancel(&msm_uport->clk_off_timer);
+
+ MSM_HS_DBG("%s: rx.flush %d\n", __func__, msm_uport->rx.flush);
if (msm_uport->rx.flush == FLUSH_SHUTDOWN) {
if (is_blsp_uart(msm_uport)) {
spin_unlock_irqrestore(&uport->lock, flags);
@@ -2294,7 +2450,7 @@
}
if (msm_uport->rx.flush == FLUSH_STOP)
msm_uport->rx.flush = FLUSH_IGNORE;
- msm_uport->clk_state = MSM_HS_CLK_ON;
+
break;
case MSM_HS_CLK_ON:
break;
@@ -2318,7 +2474,8 @@
spin_lock_irqsave(&uport->lock, flags);
if (msm_uport->clk_state == MSM_HS_CLK_OFF) {
/* ignore the first irq - it is a pending irq that occured
- * before enable_irq() */
+ * before enable_irq()
+ */
if (msm_uport->wakeup.ignore)
msm_uport->wakeup.ignore = 0;
else
@@ -2327,7 +2484,8 @@
if (wakeup) {
/* the uart was clocked off during an rx, wake up and
- * optionally inject char into tty rx */
+ * optionally inject char into tty rx
+ */
spin_unlock_irqrestore(&uport->lock, flags);
msm_hs_request_clock_on(uport);
spin_lock_irqsave(&uport->lock, flags);
@@ -2507,6 +2665,7 @@
}
}
+ msm_hs_write(uport, UARTDM_BCR_ADDR, 0x003F);
/* Set auto RFR Level */
data = msm_hs_read(uport, UART_DM_MR1);
data &= ~UARTDM_MR1_AUTO_RFR_LEVEL1_BMSK;
@@ -2548,6 +2707,7 @@
/* Initialize the tx */
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__);
@@ -2572,7 +2732,7 @@
msm_uport->imr_reg |= UARTDM_ISR_CURRENT_CTS_BMSK;
/* TXLEV on empty TX fifo */
- msm_hs_write(uport, UART_DM_TFWR, 0);
+ msm_hs_write(uport, UART_DM_TFWR, 4);
/*
* Complete all device write related configuration before
* queuing RX request. Hence mb() requires here.
@@ -2606,17 +2766,12 @@
}
disable_irq(msm_uport->wakeup.irq);
}
-
- msm_hs_clock_vote(msm_uport);
-
spin_lock_irqsave(&uport->lock, flags);
msm_hs_start_rx_locked(uport);
spin_unlock_irqrestore(&uport->lock, flags);
- msm_hs_clock_unvote(msm_uport);
-
pm_runtime_enable(uport->dev);
return 0;
@@ -2652,6 +2807,7 @@
init_waitqueue_head(&rx->wait);
init_waitqueue_head(&tx->wait);
+ init_waitqueue_head(&msm_uport->bam_disconnect_wait);
wake_lock_init(&rx->wake_lock, WAKE_LOCK_SUSPEND, "msm_serial_hs_rx");
wake_lock_init(&msm_uport->dma_wake_lock, WAKE_LOCK_SUSPEND,
"msm_serial_hs_dma");
@@ -2932,7 +3088,6 @@
sps_config->mode = SPS_MODE_SRC;
sps_config->src_pipe_index = msm_uport->bam_rx_ep_pipe_index;
sps_config->dest_pipe_index = 0;
- sps_config->options = SPS_O_DESC_DONE;
} else {
/* For UART consumer transfer, source is system memory
where as destination is UART peripheral */
@@ -2941,9 +3096,9 @@
sps_config->mode = SPS_MODE_DEST;
sps_config->src_pipe_index = 0;
sps_config->dest_pipe_index = msm_uport->bam_tx_ep_pipe_index;
- sps_config->options = SPS_O_EOT;
}
+ sps_config->options = SPS_O_EOT | SPS_O_DESC_DONE | SPS_O_AUTO_ENABLE;
sps_config->event_thresh = 0x10;
/* Allocate maximum descriptor fifo size */
@@ -2963,12 +3118,11 @@
if (is_producer) {
sps_event->callback = msm_hs_sps_rx_callback;
- sps_event->options = SPS_O_DESC_DONE;
} else {
sps_event->callback = msm_hs_sps_tx_callback;
- sps_event->options = SPS_O_EOT;
}
+ sps_event->options = SPS_O_DESC_DONE | SPS_O_EOT;
sps_event->user = (void *)msm_uport;
/* Now save the sps pipe handle */
@@ -3113,7 +3267,9 @@
return -EINVAL;
}
- msm_uport = &q_uart_port[pdev->id];
+ msm_uport = devm_kzalloc(&pdev->dev, sizeof(struct msm_hs_port),
+ GFP_KERNEL);
+ msm_uport->uport.type = PORT_UNKNOWN;
uport = &msm_uport->uport;
uport->dev = &pdev->dev;
@@ -3386,17 +3542,12 @@
static int __init msm_serial_hs_init(void)
{
int ret;
- int i;
ipc_msm_hs_log_ctxt = ipc_log_context_create(IPC_MSM_HS_LOG_PAGES,
"msm_serial_hs");
if (!ipc_msm_hs_log_ctxt)
MSM_HS_WARN("%s: error creating logging context", __func__);
- /* Init all UARTS as non-configured */
- for (i = 0; i < UARTDM_NR; i++)
- q_uart_port[i].uport.type = PORT_UNKNOWN;
-
ret = uart_register_driver(&msm_hs_driver);
if (unlikely(ret)) {
MSM_HS_WARN("%s failed to load\n", __func__);
@@ -3487,12 +3638,12 @@
*/
mb();
+ msm_hs_clock_unvote(msm_uport);
if (msm_uport->clk_state != MSM_HS_CLK_OFF) {
/* to balance clk_state */
msm_hs_clock_unvote(msm_uport);
wake_unlock(&msm_uport->dma_wake_lock);
}
- msm_hs_clock_unvote(msm_uport);
msm_uport->clk_state = MSM_HS_CLK_PORT_OFF;
dma_unmap_single(uport->dev, msm_uport->tx.dma_base,
@@ -3536,8 +3687,13 @@
{
struct platform_device *pdev = container_of(dev, struct
platform_device, dev);
- struct msm_hs_port *msm_uport = &q_uart_port[pdev->id];
- msm_hs_request_clock_on(&msm_uport->uport);
+ struct msm_hs_port *msm_uport = get_matching_hs_port(pdev);
+
+ /* This check should not fail
+ * During probe, we set uport->line to either pdev->id or userid */
+ if (msm_uport)
+ msm_hs_request_clock_on(&msm_uport->uport);
+
return 0;
}
@@ -3545,8 +3701,12 @@
{
struct platform_device *pdev = container_of(dev, struct
platform_device, dev);
- struct msm_hs_port *msm_uport = &q_uart_port[pdev->id];
- msm_hs_request_clock_off(&msm_uport->uport);
+ struct msm_hs_port *msm_uport = get_matching_hs_port(pdev);
+
+ /* This check should not fail
+ * During probe, we set uport->line to either pdev->id or userid */
+ if (msm_uport)
+ msm_hs_request_clock_off(&msm_uport->uport);
return 0;
}
diff --git a/drivers/usb/class/ccid_bridge.c b/drivers/usb/class/ccid_bridge.c
index a3e100a..05483fd 100644
--- a/drivers/usb/class/ccid_bridge.c
+++ b/drivers/usb/class/ccid_bridge.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
@@ -34,7 +34,7 @@
#define CCID_BRIDGE_MSG_SZ 512
#define CCID_BRIDGE_OPEN_TIMEOUT 500 /* msec */
#define CCID_CONTROL_TIMEOUT 500 /* msec */
-#define CCID_BRIDGE_MSG_TIMEOUT 500 /* msec */
+#define CCID_BRIDGE_MSG_TIMEOUT 1000 /* msec */
struct ccid_bridge {
struct usb_device *udev;
@@ -698,6 +698,7 @@
}
usb_set_intfdata(intf, ccid);
+ usb_enable_autosuspend(ccid->udev);
mutex_lock(&ccid->open_mutex);
ccid->intf = intf;
@@ -752,6 +753,7 @@
}
ccid->intf = NULL;
+ usb_put_dev(ccid->udev);
mutex_unlock(&ccid->event_mutex);
mutex_unlock(&ccid->read_mutex);
diff --git a/drivers/usb/gadget/f_diag.c b/drivers/usb/gadget/f_diag.c
index e218130..16f961e 100644
--- a/drivers/usb/gadget/f_diag.c
+++ b/drivers/usb/gadget/f_diag.c
@@ -26,6 +26,7 @@
#include <linux/usb/gadget.h>
#include <linux/workqueue.h>
#include <linux/debugfs.h>
+#include <linux/kmemleak.h>
static DEFINE_SPINLOCK(ch_lock);
static LIST_HEAD(usb_diag_ch_list);
@@ -381,6 +382,7 @@
req = usb_ep_alloc_request(ctxt->in, GFP_ATOMIC);
if (!req)
goto fail;
+ kmemleak_not_leak(req);
req->complete = diag_write_complete;
list_add_tail(&req->list, &ctxt->write_pool);
}
@@ -389,6 +391,7 @@
req = usb_ep_alloc_request(ctxt->out, GFP_ATOMIC);
if (!req)
goto fail;
+ kmemleak_not_leak(req);
req->complete = diag_read_complete;
list_add_tail(&req->list, &ctxt->read_pool);
}
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index ad09139..0a82e58 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -1013,9 +1013,6 @@
}
xhci = hcd_to_xhci(hcd);
- if (xhci->xhc_state & XHCI_STATE_HALTED)
- return -ENODEV;
-
if (check_virt_dev) {
if (!udev->slot_id || !xhci->devs[udev->slot_id]) {
printk(KERN_DEBUG "xHCI %s called with unaddressed "
@@ -1031,6 +1028,9 @@
}
}
+ if (xhci->xhc_state & XHCI_STATE_HALTED)
+ return -ENODEV;
+
return 1;
}
diff --git a/drivers/video/msm/mdss/dsi_host_v2.c b/drivers/video/msm/mdss/dsi_host_v2.c
index ca7f199..884f7f2 100644
--- a/drivers/video/msm/mdss/dsi_host_v2.c
+++ b/drivers/video/msm/mdss/dsi_host_v2.c
@@ -1216,6 +1216,13 @@
mutex_unlock(&ctrl_pdata->mutex);
return ret;
}
+ pinfo->panel_power_on = 1;
+ ret = mdss_dsi_panel_reset(pdata, 1);
+ if (ret) {
+ pr_err("%s: Panel reset failed\n", __func__);
+ mutex_unlock(&ctrl_pdata->mutex);
+ return ret;
+ }
msm_dsi_ahb_ctrl(1);
msm_dsi_prepare_clocks();
diff --git a/drivers/video/msm/mdss/dsi_v2.c b/drivers/video/msm/mdss/dsi_v2.c
index ccde545..bc76fd0 100644
--- a/drivers/video/msm/mdss/dsi_v2.c
+++ b/drivers/video/msm/mdss/dsi_v2.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
@@ -66,6 +66,7 @@
if (enable) {
dsi_ctrl_gpio_request(ctrl_pdata);
mdss_dsi_panel_reset(pdata, 1);
+ pdata->panel_info.panel_power_on = 1;
rc = ctrl_pdata->on(pdata);
if (rc)
pr_err("dsi_panel_handler panel on failed %d\n", rc);
@@ -73,6 +74,7 @@
if (dsi_intf.op_mode_config)
dsi_intf.op_mode_config(DSI_CMD_MODE, pdata);
rc = ctrl_pdata->off(pdata);
+ pdata->panel_info.panel_power_on = 0;
mdss_dsi_panel_reset(pdata, 0);
dsi_ctrl_gpio_free(ctrl_pdata);
}
@@ -202,75 +204,23 @@
{
int rc = 0;
- if (gpio_is_valid(ctrl_pdata->disp_en_gpio)) {
- rc = gpio_request(ctrl_pdata->disp_en_gpio, "disp_enable");
- if (rc)
- goto gpio_request_err4;
-
- ctrl_pdata->disp_en_gpio_requested = 1;
- }
-
- if (gpio_is_valid(ctrl_pdata->rst_gpio)) {
- rc = gpio_request(ctrl_pdata->rst_gpio, "disp_rst_n");
- if (rc)
- goto gpio_request_err3;
-
- ctrl_pdata->rst_gpio_requested = 1;
- }
-
if (gpio_is_valid(ctrl_pdata->disp_te_gpio)) {
rc = gpio_request(ctrl_pdata->disp_te_gpio, "disp_te");
if (rc)
- goto gpio_request_err2;
-
- ctrl_pdata->disp_te_gpio_requested = 1;
+ ctrl_pdata->disp_te_gpio_requested = 0;
+ else
+ ctrl_pdata->disp_te_gpio_requested = 1;
}
- if (gpio_is_valid(ctrl_pdata->mode_gpio)) {
- rc = gpio_request(ctrl_pdata->mode_gpio, "panel_mode");
- if (rc)
- goto gpio_request_err1;
-
- ctrl_pdata->mode_gpio_requested = 1;
- }
-
- return rc;
-
-gpio_request_err1:
- if (gpio_is_valid(ctrl_pdata->disp_te_gpio))
- gpio_free(ctrl_pdata->disp_te_gpio);
-gpio_request_err2:
- if (gpio_is_valid(ctrl_pdata->rst_gpio))
- gpio_free(ctrl_pdata->rst_gpio);
-gpio_request_err3:
- if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
- gpio_free(ctrl_pdata->disp_en_gpio);
-gpio_request_err4:
- ctrl_pdata->disp_en_gpio_requested = 0;
- ctrl_pdata->rst_gpio_requested = 0;
- ctrl_pdata->disp_te_gpio_requested = 0;
- ctrl_pdata->mode_gpio_requested = 0;
return rc;
}
void dsi_ctrl_gpio_free(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
{
- if (ctrl_pdata->disp_en_gpio_requested) {
- gpio_free(ctrl_pdata->disp_en_gpio);
- ctrl_pdata->disp_en_gpio_requested = 0;
- }
- if (ctrl_pdata->rst_gpio_requested) {
- gpio_free(ctrl_pdata->rst_gpio);
- ctrl_pdata->rst_gpio_requested = 0;
- }
if (ctrl_pdata->disp_te_gpio_requested) {
gpio_free(ctrl_pdata->disp_te_gpio);
ctrl_pdata->disp_te_gpio_requested = 0;
}
- if (ctrl_pdata->mode_gpio_requested) {
- gpio_free(ctrl_pdata->mode_gpio);
- ctrl_pdata->mode_gpio_requested = 0;
- }
}
static int dsi_parse_vreg(struct device *dev, struct dss_module_power *mp)
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.c b/drivers/video/msm/mdss/mdp3_ctrl.c
index eff1e81..b324130 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.c
+++ b/drivers/video/msm/mdss/mdp3_ctrl.c
@@ -792,16 +792,16 @@
if (panel && panel->set_backlight)
panel->set_backlight(panel, 0);
+ rc = panel->event_handler(panel, MDSS_EVENT_PANEL_OFF, NULL);
+ if (rc)
+ pr_err("fail to turn off panel\n");
+
rc = mdp3_dma->stop(mdp3_dma, mdp3_session->intf);
if (rc) {
pr_err("fail to stop the MDP3 dma\n");
goto reset_error;
}
- rc = panel->event_handler(panel, MDSS_EVENT_PANEL_OFF, NULL);
- if (rc)
- pr_err("fail to turn off panel\n");
-
rc = mdp3_put_mdp_dsi_clk();
if (rc) {
pr_err("fail to release mdp clocks\n");
@@ -1608,6 +1608,43 @@
return rc;
}
+static int mdp3_overlay_prepare(struct msm_fb_data_type *mfd,
+ struct mdp_overlay_list __user *user_ovlist)
+{
+ struct mdp_overlay_list ovlist;
+ struct mdp3_session_data *mdp3_session = mfd->mdp.private1;
+ struct mdp_overlay *req;
+ int rc;
+
+ if (!mdp3_session)
+ return -ENODEV;
+
+ req = &mdp3_session->req_overlay;
+
+ if (copy_from_user(&ovlist, user_ovlist, sizeof(ovlist)))
+ return -EFAULT;
+
+ if (ovlist.num_overlays != 1) {
+ pr_err("OV_PREPARE failed: only 1 overlay allowed\n");
+ return -EINVAL;
+ }
+
+ if (copy_from_user(req, ovlist.overlay_list[0], sizeof(*req)))
+ return -EFAULT;
+
+ rc = mdp3_overlay_set(mfd, req);
+ if (!IS_ERR_VALUE(rc)) {
+ if (copy_to_user(ovlist.overlay_list[0], req, sizeof(*req)))
+ return -EFAULT;
+ }
+
+ if (put_user(IS_ERR_VALUE(rc) ? 0 : 1,
+ &user_ovlist->processed_overlays))
+ return -EFAULT;
+
+ return rc;
+}
+
static int mdp3_ctrl_ioctl_handler(struct msm_fb_data_type *mfd,
u32 cmd, void __user *argp)
{
@@ -1707,6 +1744,9 @@
if (rc)
pr_err("OVERLAY_PLAY failed (%d)\n", rc);
break;
+ case MSMFB_OVERLAY_PREPARE:
+ rc = mdp3_overlay_prepare(mfd, argp);
+ break;
default:
break;
}
diff --git a/drivers/video/msm/mdss/mdp3_ppp.c b/drivers/video/msm/mdss/mdp3_ppp.c
index 8cc29da8..7e590b3a 100644
--- a/drivers/video/msm/mdss/mdp3_ppp.c
+++ b/drivers/video/msm/mdss/mdp3_ppp.c
@@ -272,11 +272,11 @@
int ret = 1;
/*
- * wait 40 ms for ppp operation to complete before declaring
+ * wait 200 ms for ppp operation to complete before declaring
* the MDP hung
*/
ret = wait_for_completion_timeout(
- &ppp_stat->ppp_comp, msecs_to_jiffies(40));
+ &ppp_stat->ppp_comp, msecs_to_jiffies(200));
if (!ret)
pr_err("%s: Timed out waiting for the MDP.\n",
__func__);
diff --git a/drivers/video/msm/mdss/mdss.h b/drivers/video/msm/mdss/mdss.h
index ada1281..7e6faa8 100644
--- a/drivers/video/msm/mdss/mdss.h
+++ b/drivers/video/msm/mdss/mdss.h
@@ -192,6 +192,7 @@
int handoff_pending;
struct mdss_prefill_data prefill_data;
+ bool ulps;
};
extern struct mdss_data_type *mdss_res;
diff --git a/drivers/video/msm/mdss/mdss_dsi.c b/drivers/video/msm/mdss/mdss_dsi.c
index 2efb973..7b4b065 100644
--- a/drivers/video/msm/mdss/mdss_dsi.c
+++ b/drivers/video/msm/mdss/mdss_dsi.c
@@ -27,8 +27,6 @@
#include "mdss_dsi.h"
#include "mdss_debug.h"
-static unsigned char *mdss_dsi_base;
-
static int mdss_dsi_regulator_init(struct platform_device *pdev)
{
struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
@@ -74,13 +72,25 @@
goto error;
}
- if (pdata->panel_info.panel_power_on == 0)
- mdss_dsi_panel_reset(pdata, 1);
-
+ if (!pdata->panel_info.mipi.lp11_init) {
+ ret = mdss_dsi_panel_reset(pdata, 1);
+ if (ret) {
+ pr_err("%s: Panel reset failed. rc=%d\n",
+ __func__, ret);
+ if (msm_dss_enable_vreg(
+ ctrl_pdata->power_data.vreg_config,
+ ctrl_pdata->power_data.num_vreg, 0))
+ pr_err("Disable vregs failed\n");
+ goto error;
+ }
+ }
} else {
-
- mdss_dsi_panel_reset(pdata, 0);
-
+ ret = mdss_dsi_panel_reset(pdata, 0);
+ if (ret) {
+ pr_err("%s: Panel reset failed. rc=%d\n",
+ __func__, ret);
+ goto error;
+ }
ret = msm_dss_enable_vreg(
ctrl_pdata->power_data.vreg_config,
ctrl_pdata->power_data.num_vreg, 0);
@@ -298,7 +308,7 @@
if (!pdata->panel_info.panel_power_on) {
pr_warn("%s:%d Panel already off.\n", __func__, __LINE__);
- return -EPERM;
+ return 0;
}
pdata->panel_info.panel_power_on = 0;
@@ -337,63 +347,22 @@
return ret;
}
-int mdss_dsi_on(struct mdss_panel_data *pdata)
+static void __mdss_dsi_ctrl_setup(struct mdss_panel_data *pdata)
{
- int ret = 0;
- u32 clk_rate;
+ struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
struct mdss_panel_info *pinfo;
struct mipi_panel_info *mipi;
+ u32 clk_rate;
u32 hbp, hfp, vbp, vfp, hspw, vspw, width, height;
u32 ystride, bpp, data, dst_bpp;
u32 dummy_xres, dummy_yres;
- struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
u32 hsync_period, vsync_period;
- if (pdata == NULL) {
- pr_err("%s: Invalid input data\n", __func__);
- return -EINVAL;
- }
-
- if (pdata->panel_info.panel_power_on) {
- pr_warn("%s:%d Panel already on.\n", __func__, __LINE__);
- return 0;
- }
-
ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
panel_data);
- pr_debug("%s+: ctrl=%p ndx=%d\n",
- __func__, ctrl_pdata, ctrl_pdata->ndx);
-
pinfo = &pdata->panel_info;
- ret = msm_dss_enable_vreg(ctrl_pdata->power_data.vreg_config,
- ctrl_pdata->power_data.num_vreg, 1);
- if (ret) {
- pr_err("%s:Failed to enable vregs. rc=%d\n", __func__, ret);
- return ret;
- }
-
- pdata->panel_info.panel_power_on = 1;
-
- if (!pdata->panel_info.mipi.lp11_init)
- mdss_dsi_panel_reset(pdata, 1);
-
- ret = mdss_dsi_bus_clk_start(ctrl_pdata);
- if (ret) {
- pr_err("%s: failed to enable bus clocks. rc=%d\n", __func__,
- ret);
- mdss_dsi_panel_power_on(pdata, 0);
- pdata->panel_info.panel_power_on = 0;
- return ret;
- }
-
- 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, 1);
-
clk_rate = pdata->panel_info.clk_rate;
clk_rate = min(clk_rate, pdata->panel_info.clk_max);
@@ -423,7 +392,7 @@
vsync_period = vspw + vbp + height + dummy_yres + vfp;
hsync_period = hspw + hbp + width + dummy_xres + hfp;
- mipi = &pdata->panel_info.mipi;
+ mipi = &pdata->panel_info.mipi;
if (pdata->panel_info.type == MIPI_VIDEO_PANEL) {
MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x24,
((hspw + hbp + width + dummy_xres) << 16 |
@@ -461,19 +430,195 @@
MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x64, data);
MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x5C, data);
}
+}
+static inline bool __mdss_dsi_ulps_feature_enabled(
+ struct mdss_panel_data *pdata)
+{
+ return pdata->panel_info.ulps_feature_enabled;
+}
+
+static int mdss_dsi_ulps_config_sub(struct mdss_dsi_ctrl_pdata *ctrl_pdata,
+ int enable)
+{
+ int ret = 0;
+ struct mdss_panel_data *pdata = NULL;
+ u32 lane_status = 0;
+
+ if (!ctrl_pdata) {
+ pr_err("%s: invalid input\n", __func__);
+ return -EINVAL;
+ }
+
+ pdata = &ctrl_pdata->panel_data;
+
+ if (!__mdss_dsi_ulps_feature_enabled(pdata)) {
+ pr_debug("%s: ULPS feature not supported. enable=%d\n",
+ __func__, enable);
+ return -ENOTSUPP;
+ }
+
+ if (enable && !ctrl_pdata->ulps) {
+ /* No need to configure ULPS mode when entering suspend state */
+ if (!pdata->panel_info.panel_power_on) {
+ pr_err("%s: panel off. returning\n", __func__);
+ goto error;
+ }
+
+ if (__mdss_dsi_clk_enabled(ctrl_pdata)) {
+ 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);
+ /*
+ * ULPS Entry Request.
+ * Wait for a short duration to ensure that the lanes
+ * enter ULP state.
+ */
+ MIPI_OUTP(ctrl_pdata->ctrl_base + 0x0AC, 0x01F);
+ usleep(100);
+
+ /* Enable MMSS DSI Clamps */
+ MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x14, 0x3FF);
+ MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x14, 0x83FF);
+
+ wmb();
+
+ MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x108, 0x1);
+ /* 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);
+ ctrl_pdata->ulps = true;
+ } else if (ctrl_pdata->ulps) {
+ mdss_dsi_phy_init(pdata);
+
+ __mdss_dsi_ctrl_setup(pdata);
+ mdss_dsi_sw_reset(pdata);
+ mdss_dsi_host_init(pdata);
+ mdss_dsi_op_mode_config(pdata->panel_info.mipi.mode,
+ pdata);
+
+ /* Disable MMSS DSI Clamps */
+ MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x14, 0x0);
+
+ /*
+ * ULPS Exit Request
+ * Hardware requirement is to wait for at least 1ms
+ */
+ MIPI_OUTP(ctrl_pdata->ctrl_base + 0x0AC, 0x1F00);
+ usleep(1000);
+ MIPI_OUTP(ctrl_pdata->ctrl_base + 0x0AC, 0x0);
+
+ /*
+ * Wait for a short duration before enabling
+ * data transmission
+ */
+ usleep(100);
+
+ lane_status = MIPI_INP(ctrl_pdata->ctrl_base + 0xA8),
+ ctrl_pdata->ulps = false;
+ }
+
+ pr_debug("%s: DSI lane status = 0x%08x. Ulps %s\n", __func__,
+ lane_status, enable ? "enabled" : "disabled");
+
+error:
+ return ret;
+}
+
+static int mdss_dsi_ulps_config(struct mdss_dsi_ctrl_pdata *ctrl,
+ int enable)
+{
+ int rc;
+ struct mdss_dsi_ctrl_pdata *sctrl = NULL;
+
+ if (ctrl->flags & DSI_FLAG_CLOCK_MASTER)
+ sctrl = mdss_dsi_ctrl_slave(ctrl);
+
+ 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 (rc)
+ return rc;
+ }
+
+ pr_debug("%s: configuring ulps (%s) for master ctrl\n",
+ __func__, (enable ? "on" : "off"));
+ return mdss_dsi_ulps_config_sub(ctrl, enable);
+}
+
+int mdss_dsi_on(struct mdss_panel_data *pdata)
+{
+ int ret = 0;
+ struct mdss_panel_info *pinfo;
+ struct mipi_panel_info *mipi;
+ struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+
+ if (pdata == NULL) {
+ pr_err("%s: Invalid input data\n", __func__);
+ return -EINVAL;
+ }
+
+ if (pdata->panel_info.panel_power_on) {
+ pr_warn("%s:%d Panel already on.\n", __func__, __LINE__);
+ return 0;
+ }
+
+ ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
+ panel_data);
+
+ pr_debug("%s+: ctrl=%p ndx=%d\n",
+ __func__, ctrl_pdata, ctrl_pdata->ndx);
+
+ pinfo = &pdata->panel_info;
+ mipi = &pdata->panel_info.mipi;
+
+ ret = mdss_dsi_panel_power_on(pdata, 1);
+ if (ret) {
+ pr_err("%s:Panel power on failed. rc=%d\n", __func__, ret);
+ return ret;
+ }
+
+ ret = mdss_dsi_bus_clk_start(ctrl_pdata);
+ if (ret) {
+ pr_err("%s: failed to enable bus clocks. rc=%d\n", __func__,
+ ret);
+ ret = mdss_dsi_panel_power_on(pdata, 0);
+ if (ret) {
+ pr_err("%s: Panel reset failed. rc=%d\n",
+ __func__, ret);
+ return ret;
+ }
+ pdata->panel_info.panel_power_on = 0;
+ return ret;
+ }
+ pdata->panel_info.panel_power_on = 1;
+
+ 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, 1);
+
+ __mdss_dsi_ctrl_setup(pdata);
mdss_dsi_sw_reset(pdata);
- mdss_dsi_host_init(mipi, pdata);
+ mdss_dsi_host_init(pdata);
/*
* Issue hardware reset line after enabling the DSI clocks and data
* data lanes for LP11 init
*/
- if (pdata->panel_info.mipi.lp11_init)
+ if (mipi->lp11_init)
mdss_dsi_panel_reset(pdata, 1);
- if (pdata->panel_info.mipi.init_delay)
- usleep(pdata->panel_info.mipi.init_delay);
+ if (mipi->init_delay)
+ usleep(mipi->init_delay);
if (mipi->force_clk_lane_hs) {
u32 tmp;
@@ -547,6 +692,17 @@
panel_data);
mipi = &pdata->panel_info.mipi;
+ if (__mdss_dsi_ulps_feature_enabled(pdata) &&
+ (ctrl_pdata->ulps)) {
+ /* Disable ULPS mode before blanking the panel */
+ ret = mdss_dsi_ulps_config(ctrl_pdata, 0);
+ if (ret) {
+ pr_err("%s: failed to exit ULPS mode. rc=%d\n",
+ __func__, ret);
+ return ret;
+ }
+ }
+
mdss_dsi_op_mode_config(DSI_CMD_MODE, pdata);
if (pdata->panel_info.type == MIPI_CMD_PANEL) {
@@ -593,7 +749,7 @@
"Incorrect Ctrl state=0x%x\n", ctrl_pdata->ctrl_state);
mdss_dsi_sw_reset(pdata);
- mdss_dsi_host_init(mipi, pdata);
+ mdss_dsi_host_init(pdata);
mdss_dsi_op_mode_config(mipi->mode, pdata);
if (ctrl_pdata->on_cmds.link_state == DSI_LP_MODE) {
@@ -800,6 +956,9 @@
case MDSS_EVENT_ENABLE_PARTIAL_UPDATE:
rc = mdss_dsi_ctl_partial_update(pdata);
break;
+ case MDSS_EVENT_DSI_ULPS_CTRL:
+ rc = mdss_dsi_ulps_config(ctrl_pdata, (int)arg);
+ break;
default:
pr_debug("%s: unhandled event=%d\n", __func__, event);
break;
@@ -906,7 +1065,6 @@
struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
struct device_node *dsi_pan_node = NULL;
char panel_cfg[MDSS_MAX_PANEL_LEN];
- struct resource *mdss_dsi_mres;
const char *ctrl_name;
bool cmd_cfg_cont_splash = true;
@@ -956,30 +1114,13 @@
else
pdev->id = 2;
- mdss_dsi_mres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!mdss_dsi_mres) {
- pr_err("%s:%d unable to get the MDSS resources",
- __func__, __LINE__);
- rc = -ENOMEM;
- goto error_no_mem;
- }
-
- mdss_dsi_base = ioremap(mdss_dsi_mres->start,
- resource_size(mdss_dsi_mres));
- if (!mdss_dsi_base) {
- pr_err("%s:%d unable to remap dsi resources",
- __func__, __LINE__);
- rc = -ENOMEM;
- goto error_no_mem;
- }
-
rc = of_platform_populate(pdev->dev.of_node,
NULL, NULL, &pdev->dev);
if (rc) {
dev_err(&pdev->dev,
"%s: failed to add child nodes, rc=%d\n",
__func__, rc);
- goto error_ioremap;
+ goto error_no_mem;
}
/* Parse the regulator information */
@@ -1026,8 +1167,6 @@
of_node_put(dsi_pan_node);
error_vreg:
mdss_dsi_put_dt_vreg_data(&pdev->dev, &ctrl_pdata->power_data);
-error_ioremap:
- iounmap(mdss_dsi_base);
error_no_mem:
devm_kfree(&pdev->dev, ctrl_pdata);
@@ -1050,7 +1189,7 @@
pr_err("%s: failed to de-init vregs\n", __func__);
mdss_dsi_put_dt_vreg_data(&pdev->dev, &ctrl_pdata->power_data);
mfd = platform_get_drvdata(pdev);
- iounmap(mdss_dsi_base);
+ msm_dss_iounmap(&ctrl_pdata->mmss_misc_io);
return 0;
}
@@ -1109,6 +1248,13 @@
pr_info("%s: dsi base=%x size=%x\n",
__func__, (int)ctrl->ctrl_base, ctrl->reg_size);
+ 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;
+ }
+
return 0;
}
@@ -1246,18 +1392,9 @@
ctrl_pdata->disp_en_gpio = of_get_named_gpio(ctrl_pdev->dev.of_node,
"qcom,platform-enable-gpio", 0);
- if (!gpio_is_valid(ctrl_pdata->disp_en_gpio)) {
+ if (!gpio_is_valid(ctrl_pdata->disp_en_gpio))
pr_err("%s:%d, Disp_en gpio not specified\n",
__func__, __LINE__);
- } else {
- rc = gpio_request(ctrl_pdata->disp_en_gpio, "disp_enable");
- if (rc) {
- pr_err("request reset gpio failed, rc=%d\n",
- rc);
- gpio_free(ctrl_pdata->disp_en_gpio);
- return -ENODEV;
- }
- }
if (pinfo->type == MIPI_CMD_PANEL) {
ctrl_pdata->disp_te_gpio = of_get_named_gpio(ctrl_pdev->dev.of_node,
@@ -1274,7 +1411,6 @@
if (rc) {
pr_err("request TE gpio failed, rc=%d\n",
rc);
- gpio_free(ctrl_pdata->disp_te_gpio);
return -ENODEV;
}
rc = gpio_tlmm_config(GPIO_CFG(
@@ -1304,44 +1440,18 @@
ctrl_pdata->rst_gpio = of_get_named_gpio(ctrl_pdev->dev.of_node,
"qcom,platform-reset-gpio", 0);
- if (!gpio_is_valid(ctrl_pdata->rst_gpio)) {
+ if (!gpio_is_valid(ctrl_pdata->rst_gpio))
pr_err("%s:%d, reset gpio not specified\n",
__func__, __LINE__);
- } else {
- rc = gpio_request(ctrl_pdata->rst_gpio, "disp_rst_n");
- if (rc) {
- pr_err("request reset gpio failed, rc=%d\n",
- rc);
- gpio_free(ctrl_pdata->rst_gpio);
- if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
- gpio_free(ctrl_pdata->disp_en_gpio);
- return -ENODEV;
- }
- }
if (pinfo->mode_gpio_state != MODE_GPIO_NOT_VALID) {
ctrl_pdata->mode_gpio = of_get_named_gpio(
ctrl_pdev->dev.of_node,
"qcom,platform-mode-gpio", 0);
- if (!gpio_is_valid(ctrl_pdata->mode_gpio)) {
+ if (!gpio_is_valid(ctrl_pdata->mode_gpio))
pr_info("%s:%d, mode gpio not specified\n",
__func__, __LINE__);
- } else {
- rc = gpio_request(ctrl_pdata->mode_gpio, "panel_mode");
- if (rc) {
- pr_err("request panel mode gpio failed,rc=%d\n",
- rc);
- gpio_free(ctrl_pdata->mode_gpio);
- if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
- gpio_free(ctrl_pdata->disp_en_gpio);
- if (gpio_is_valid(ctrl_pdata->rst_gpio))
- gpio_free(ctrl_pdata->rst_gpio);
- if (gpio_is_valid(ctrl_pdata->disp_te_gpio))
- gpio_free(ctrl_pdata->disp_te_gpio);
- return -ENODEV;
- }
- }
}
if (mdss_dsi_clk_init(ctrl_pdev, ctrl_pdata)) {
@@ -1392,10 +1502,6 @@
rc = mdss_register_panel(ctrl_pdev, &(ctrl_pdata->panel_data));
if (rc) {
pr_err("%s: unable to register MIPI DSI panel\n", __func__);
- if (ctrl_pdata->rst_gpio)
- gpio_free(ctrl_pdata->rst_gpio);
- if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
- gpio_free(ctrl_pdata->disp_en_gpio);
return rc;
}
@@ -1450,7 +1556,6 @@
static void __exit mdss_dsi_driver_cleanup(void)
{
- iounmap(mdss_dsi_base);
platform_driver_unregister(&mdss_dsi_ctrl_driver);
}
module_exit(mdss_dsi_driver_cleanup);
diff --git a/drivers/video/msm/mdss/mdss_dsi.h b/drivers/video/msm/mdss/mdss_dsi.h
index 2c9c37d..57b0e75 100644
--- a/drivers/video/msm/mdss/mdss_dsi.h
+++ b/drivers/video/msm/mdss/mdss_dsi.h
@@ -238,6 +238,7 @@
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 mmss_misc_io;
int reg_size;
u32 clk_cnt;
int clk_cnt_sub;
@@ -245,6 +246,7 @@
struct clk *mdp_core_clk;
struct clk *ahb_clk;
struct clk *axi_clk;
+ struct clk *mmss_misc_ahb_clk;
struct clk *byte_clk;
struct clk *esc_clk;
struct clk *pixel_clk;
@@ -256,10 +258,7 @@
int disp_en_gpio;
int disp_te_gpio;
int mode_gpio;
- int rst_gpio_requested;
- int disp_en_gpio_requested;
int disp_te_gpio_requested;
- int mode_gpio_requested;
int bklt_ctrl; /* backlight ctrl */
int pwm_period;
int pwm_pmic_gpio;
@@ -290,6 +289,8 @@
struct mutex mutex;
struct mutex cmd_mutex;
+ bool ulps;
+
struct dsi_buf tx_buf;
struct dsi_buf rx_buf;
};
@@ -303,8 +304,7 @@
int mdss_dsi_cmds_rx(struct mdss_dsi_ctrl_pdata *ctrl,
struct dsi_cmd_desc *cmds, int rlen);
-void mdss_dsi_host_init(struct mipi_panel_info *pinfo,
- struct mdss_panel_data *pdata);
+void mdss_dsi_host_init(struct mdss_panel_data *pdata);
void mdss_dsi_op_mode_config(int mode,
struct mdss_panel_data *pdata);
void mdss_dsi_cmd_mode_ctrl(int enable);
@@ -337,7 +337,7 @@
void mdss_dsi_clk_deinit(struct mdss_dsi_ctrl_pdata *ctrl_pdata);
int mdss_dsi_enable_bus_clocks(struct mdss_dsi_ctrl_pdata *ctrl_pdata);
void mdss_dsi_disable_bus_clocks(struct mdss_dsi_ctrl_pdata *ctrl_pdata);
-void mdss_dsi_panel_reset(struct mdss_panel_data *pdata, int enable);
+int mdss_dsi_panel_reset(struct mdss_panel_data *pdata, int enable);
void mdss_dsi_phy_disable(struct mdss_dsi_ctrl_pdata *ctrl);
void mdss_dsi_phy_init(struct mdss_panel_data *pdata);
void mdss_dsi_phy_sw_reset(unsigned char *ctrl_base);
@@ -351,6 +351,7 @@
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);
int mdss_dsi_panel_init(struct device_node *node,
struct mdss_dsi_ctrl_pdata *ctrl_pdata,
diff --git a/drivers/video/msm/mdss/mdss_dsi_host.c b/drivers/video/msm/mdss/mdss_dsi_host.c
index b4478ac..c2fbc1a 100644
--- a/drivers/video/msm/mdss/mdss_dsi_host.c
+++ b/drivers/video/msm/mdss/mdss_dsi_host.c
@@ -250,12 +250,12 @@
MIPI_OUTP((ctrl->ctrl_base) + 0x015c, 0x0);
}
-void mdss_dsi_host_init(struct mipi_panel_info *pinfo,
- struct mdss_panel_data *pdata)
+void mdss_dsi_host_init(struct mdss_panel_data *pdata)
{
u32 dsi_ctrl, intr_ctrl;
u32 data;
struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+ struct mipi_panel_info *pinfo = NULL;
if (pdata == NULL) {
pr_err("%s: Invalid input data\n", __func__);
@@ -265,6 +265,8 @@
ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
panel_data);
+ pinfo = &pdata->panel_info.mipi;
+
pinfo->rgb_swap = DSI_RGB_SWAP_RGB;
ctrl_pdata->panel_mode = pinfo->mode;
@@ -1477,7 +1479,9 @@
u32 isr0;
isr0 = MIPI_INP(left_ctrl_pdata->ctrl_base
+ 0x0110);/* DSI_INTR_CTRL */
- MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x0110, isr0);
+ if (isr0 & DSI_INTR_CMD_DMA_DONE)
+ MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x0110,
+ DSI_INTR_CMD_DMA_DONE);
}
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 76e6d1b..5415a7e 100644
--- a/drivers/video/msm/mdss/mdss_dsi_panel.c
+++ b/drivers/video/msm/mdss/mdss_dsi_panel.c
@@ -153,15 +153,53 @@
mdss_dsi_cmdlist_put(ctrl, &cmdreq);
}
-void mdss_dsi_panel_reset(struct mdss_panel_data *pdata, int enable)
+static int mdss_dsi_request_gpios(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
+{
+ int rc = 0;
+
+ if (gpio_is_valid(ctrl_pdata->disp_en_gpio)) {
+ rc = gpio_request(ctrl_pdata->disp_en_gpio,
+ "disp_enable");
+ if (rc) {
+ pr_err("request disp_en gpio failed, rc=%d\n",
+ rc);
+ goto disp_en_gpio_err;
+ }
+ }
+ rc = gpio_request(ctrl_pdata->rst_gpio, "disp_rst_n");
+ if (rc) {
+ pr_err("request reset gpio failed, rc=%d\n",
+ rc);
+ goto rst_gpio_err;
+ }
+ if (gpio_is_valid(ctrl_pdata->mode_gpio)) {
+ rc = gpio_request(ctrl_pdata->mode_gpio, "panel_mode");
+ if (rc) {
+ pr_err("request panel mode gpio failed,rc=%d\n",
+ rc);
+ goto mode_gpio_err;
+ }
+ }
+ return rc;
+
+mode_gpio_err:
+ gpio_free(ctrl_pdata->rst_gpio);
+rst_gpio_err:
+ if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
+ gpio_free(ctrl_pdata->disp_en_gpio);
+disp_en_gpio_err:
+ return rc;
+}
+
+int mdss_dsi_panel_reset(struct mdss_panel_data *pdata, int enable)
{
struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
struct mdss_panel_info *pinfo = NULL;
- int i;
+ int i, rc = 0;
if (pdata == NULL) {
pr_err("%s: Invalid input data\n", __func__);
- return;
+ return -EINVAL;
}
ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
@@ -175,21 +213,28 @@
if (!gpio_is_valid(ctrl_pdata->rst_gpio)) {
pr_debug("%s:%d, reset line not configured\n",
__func__, __LINE__);
- return;
+ return rc;
}
pr_debug("%s: enable = %d\n", __func__, enable);
pinfo = &(ctrl_pdata->panel_data.panel_info);
if (enable) {
- if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
- gpio_set_value((ctrl_pdata->disp_en_gpio), 1);
+ rc = mdss_dsi_request_gpios(ctrl_pdata);
+ if (rc) {
+ pr_err("gpio request failed\n");
+ return rc;
+ }
+ if (!pinfo->panel_power_on) {
+ if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
+ gpio_set_value((ctrl_pdata->disp_en_gpio), 1);
- for (i = 0; i < pdata->panel_info.rst_seq_len; ++i) {
- gpio_set_value((ctrl_pdata->rst_gpio),
- pdata->panel_info.rst_seq[i]);
- if (pdata->panel_info.rst_seq[++i])
- usleep(pdata->panel_info.rst_seq[i] * 1000);
+ for (i = 0; i < pdata->panel_info.rst_seq_len; ++i) {
+ gpio_set_value((ctrl_pdata->rst_gpio),
+ pdata->panel_info.rst_seq[i]);
+ if (pdata->panel_info.rst_seq[++i])
+ usleep(pinfo->rst_seq[i] * 1000);
+ }
}
if (gpio_is_valid(ctrl_pdata->mode_gpio)) {
@@ -205,10 +250,16 @@
pr_debug("%s: Reset panel done\n", __func__);
}
} else {
- gpio_set_value((ctrl_pdata->rst_gpio), 0);
- if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
+ if (gpio_is_valid(ctrl_pdata->disp_en_gpio)) {
gpio_set_value((ctrl_pdata->disp_en_gpio), 0);
+ gpio_free(ctrl_pdata->disp_en_gpio);
+ }
+ gpio_set_value((ctrl_pdata->rst_gpio), 0);
+ gpio_free(ctrl_pdata->rst_gpio);
+ if (gpio_is_valid(ctrl_pdata->mode_gpio))
+ gpio_free(ctrl_pdata->mode_gpio);
}
+ return rc;
}
static char caset[] = {0x2a, 0x00, 0x00, 0x03, 0x00}; /* DTYPE_DCS_LWRITE */
@@ -266,6 +317,17 @@
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)
{
@@ -297,6 +359,16 @@
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__);
+ return;
+ }
+ mdss_dsi_panel_bklt_dcs(rctrl_pdata, bl_level);
+ }
break;
default:
pr_err("%s: Unknown bl_ctrl configuration\n",
@@ -632,6 +704,35 @@
return 0;
}
+static int mdss_dsi_parse_panel_features(struct device_node *np,
+ struct mdss_dsi_ctrl_pdata *ctrl)
+{
+ struct mdss_panel_info *pinfo;
+
+ if (!np || !ctrl) {
+ pr_err("%s: Invalid arguments\n", __func__);
+ return -ENODEV;
+ }
+
+ pinfo = &ctrl->panel_data.panel_info;
+
+ pinfo->cont_splash_enabled = of_property_read_bool(np,
+ "qcom,cont-splash-enabled");
+
+ pinfo->partial_update_enabled = of_property_read_bool(np,
+ "qcom,partial-update-enabled");
+ pr_info("%s:%d Partial update %s\n", __func__, __LINE__,
+ (pinfo->partial_update_enabled ? "enabled" : "disabled"));
+ if (pinfo->partial_update_enabled)
+ ctrl->partial_update_fnc = mdss_dsi_panel_partial_update;
+
+ pinfo->ulps_feature_enabled = of_property_read_bool(np,
+ "qcom,ulps-enabled");
+ pr_info("%s: ulps feature %s", __func__,
+ (pinfo->ulps_feature_enabled ? "enabled" : "disabled"));
+
+ return 0;
+}
static int mdss_panel_parse_dt(struct device_node *np,
struct mdss_dsi_ctrl_pdata *ctrl_pdata)
@@ -856,6 +957,11 @@
rc = of_property_read_u32(np, "qcom,mdss-dsi-t-clk-post", &tmp);
pinfo->mipi.t_clk_post = (!rc ? tmp : 0x03);
+ pinfo->mipi.rx_eot_ignore = of_property_read_bool(np,
+ "qcom,mdss-dsi-rx-eot-ignore");
+ pinfo->mipi.tx_eot_append = of_property_read_bool(np,
+ "qcom,mdss-dsi-tx-eot-append");
+
rc = of_property_read_u32(np, "qcom,mdss-dsi-stream", &tmp);
pinfo->mipi.stream = (!rc ? tmp : 0);
@@ -906,6 +1012,12 @@
mdss_dsi_parse_dcs_cmds(np, &ctrl_pdata->off_cmds,
"qcom,mdss-dsi-off-command", "qcom,mdss-dsi-off-command-state");
+ rc = mdss_dsi_parse_panel_features(np, ctrl_pdata);
+ if (rc) {
+ pr_err("%s: failed to parse panel features\n", __func__);
+ goto error;
+ }
+
return 0;
error:
@@ -918,14 +1030,15 @@
{
int rc = 0;
static const char *panel_name;
- bool cont_splash_enabled;
- bool partial_update_enabled;
+ struct mdss_panel_info *pinfo;
- if (!node) {
- pr_err("%s: no panel node\n", __func__);
+ if (!node || !ctrl_pdata) {
+ pr_err("%s: Invalid arguments\n", __func__);
return -ENODEV;
}
+ pinfo = &ctrl_pdata->panel_data.panel_info;
+
pr_debug("%s:%d\n", __func__, __LINE__);
panel_name = of_get_property(node, "qcom,mdss-dsi-panel-name", NULL);
if (!panel_name)
@@ -940,33 +1053,10 @@
return rc;
}
- if (cmd_cfg_cont_splash)
- cont_splash_enabled = of_property_read_bool(node,
- "qcom,cont-splash-enabled");
- else
- cont_splash_enabled = false;
- if (!cont_splash_enabled) {
- pr_info("%s:%d Continuous splash flag not found.\n",
- __func__, __LINE__);
- ctrl_pdata->panel_data.panel_info.cont_splash_enabled = 0;
- } else {
- pr_info("%s:%d Continuous splash flag enabled.\n",
- __func__, __LINE__);
-
- ctrl_pdata->panel_data.panel_info.cont_splash_enabled = 1;
- }
-
- partial_update_enabled = of_property_read_bool(node,
- "qcom,partial-update-enabled");
- if (partial_update_enabled) {
- pr_info("%s:%d Partial update enabled.\n", __func__, __LINE__);
- ctrl_pdata->panel_data.panel_info.partial_update_enabled = 1;
- ctrl_pdata->partial_update_fnc = mdss_dsi_panel_partial_update;
- } else {
- pr_info("%s:%d Partial update disabled.\n", __func__, __LINE__);
- ctrl_pdata->panel_data.panel_info.partial_update_enabled = 0;
- ctrl_pdata->partial_update_fnc = NULL;
- }
+ if (!cmd_cfg_cont_splash)
+ pinfo->cont_splash_enabled = false;
+ pr_info("%s: Continuous splash %s", __func__,
+ pinfo->cont_splash_enabled ? "enabled" : "disabled");
ctrl_pdata->on = mdss_dsi_panel_on;
ctrl_pdata->off = mdss_dsi_panel_off;
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index 1df2903..252a86e 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -1214,9 +1214,11 @@
struct mdss_fb_proc_info *pinfo = NULL;
int result;
int pid = current->tgid;
+ struct task_struct *task = current->group_leader;
if (mfd->shutdown_pending) {
- pr_err("Shutdown pending. Aborting operation\n");
+ pr_err("Shutdown pending. Aborting operation. Request from pid:%d name=%s\n",
+ pid, task->comm);
return -EPERM;
}
@@ -2213,7 +2215,8 @@
mdss_fb_power_setting_idle(mfd);
if ((cmd != MSMFB_VSYNC_CTRL) && (cmd != MSMFB_OVERLAY_VSYNC_CTRL) &&
(cmd != MSMFB_ASYNC_BLIT) && (cmd != MSMFB_BLIT) &&
- (cmd != MSMFB_NOTIFY_UPDATE)) {
+ (cmd != MSMFB_NOTIFY_UPDATE) &&
+ (cmd != MSMFB_OVERLAY_PREPARE)) {
ret = mdss_fb_pan_idle(mfd);
if (ret) {
pr_debug("Shutdown pending. Aborting operation %x\n",
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.c b/drivers/video/msm/mdss/mdss_hdmi_tx.c
index 79afdca..cd2f8e4 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.c
@@ -3872,6 +3872,7 @@
static const struct of_device_id hdmi_tx_dt_match[] = {
{.compatible = COMPATIBLE_NAME,},
+ { /* Sentinel */ },
};
MODULE_DEVICE_TABLE(of, hdmi_tx_dt_match);
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index e1786a6..cfa594c 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -2405,8 +2405,10 @@
pr_debug("Enable MDP FS\n");
if (!mdata->fs_ena) {
regulator_enable(mdata->fs);
- mdss_mdp_cx_ctrl(mdata, true);
- mdss_mdp_batfet_ctrl(mdata, true);
+ if (!mdata->ulps) {
+ mdss_mdp_cx_ctrl(mdata, true);
+ mdss_mdp_batfet_ctrl(mdata, true);
+ }
}
mdata->fs_ena = true;
} else {
@@ -2414,13 +2416,41 @@
mdss_iommu_dettach(mdata);
if (mdata->fs_ena) {
regulator_disable(mdata->fs);
- mdss_mdp_cx_ctrl(mdata, false);
- mdss_mdp_batfet_ctrl(mdata, false);
+ if (!mdata->ulps) {
+ mdss_mdp_cx_ctrl(mdata, false);
+ mdss_mdp_batfet_ctrl(mdata, false);
+ }
}
mdata->fs_ena = false;
}
}
+/**
+ * mdss_mdp_footswitch_ctrl_ulps() - MDSS GDSC control with ULPS feature
+ * @on: 1 to turn on footswitch, 0 to turn off footswitch
+ * @dev: framebuffer device node
+ *
+ * MDSS GDSC can be voted off during idle-screen usecase for MIPI DSI command
+ * mode displays with Ultra-Low Power State (ULPS) feature enabled. Upon
+ * subsequent frame update, MDSS GDSC needs to turned back on and hw state
+ * needs to be restored.
+ */
+void mdss_mdp_footswitch_ctrl_ulps(int on, struct device *dev)
+{
+ struct mdss_data_type *mdata = mdss_mdp_get_mdata();
+
+ pr_debug("called on=%d\n", on);
+ if (on) {
+ pm_runtime_get_sync(dev);
+ mdss_iommu_attach(mdata);
+ mdss_hw_init(mdata);
+ mdata->ulps = false;
+ } else {
+ mdata->ulps = true;
+ pm_runtime_put_sync(dev);
+ }
+}
+
static inline int mdss_mdp_suspend_sub(struct mdss_data_type *mdata)
{
mdata->suspend_fs_ena = mdata->fs_ena;
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index 3afb27e..9a469a4 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -681,6 +681,8 @@
int mdss_mdp_wb_set_secure(struct msm_fb_data_type *mfd, int enable);
int mdss_mdp_wb_get_secure(struct msm_fb_data_type *mfd, uint8_t *enable);
+void mdss_mdp_ctl_restore(struct mdss_mdp_ctl *ctl);
+void mdss_mdp_footswitch_ctrl_ulps(int on, struct device *dev);
int mdss_mdp_pipe_program_pixel_extn(struct mdss_mdp_pipe *pipe);
#define mfd_to_mdp5_data(mfd) (mfd->mdp.private1)
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index b445afa..fa64448 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -1588,6 +1588,25 @@
return rc;
}
+/*
+ * mdss_mdp_ctl_restore() - restore mdp ctl path
+ * @ctl: mdp controller.
+ *
+ * This function is called whenever MDP comes out of a power collapse as
+ * a result of a screen update when DSI ULPS mode is enabled. It restores
+ * the MDP controller's software state to the hardware registers.
+ */
+void mdss_mdp_ctl_restore(struct mdss_mdp_ctl *ctl)
+{
+ u32 temp;
+
+ temp = readl_relaxed(ctl->mdata->mdp_base +
+ MDSS_MDP_REG_DISP_INTF_SEL);
+ temp |= (ctl->intf_type << ((ctl->intf_num - MDSS_MDP_INTF0) * 8));
+ writel_relaxed(temp, ctl->mdata->mdp_base +
+ MDSS_MDP_REG_DISP_INTF_SEL);
+}
+
static int mdss_mdp_ctl_start_sub(struct mdss_mdp_ctl *ctl, bool handoff)
{
struct mdss_mdp_mixer *mixer;
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
index 79bdee2..8c7dc29 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
@@ -27,6 +27,7 @@
#define KOFF_TIMEOUT msecs_to_jiffies(84)
#define STOP_TIMEOUT msecs_to_jiffies(16 * (VSYNC_EXPIRE_TICK + 2))
+#define ULPS_ENTER_TIME msecs_to_jiffies(100)
struct mdss_mdp_cmd_ctx {
struct mdss_mdp_ctl *ctl;
@@ -43,6 +44,7 @@
struct mutex clk_mtx;
spinlock_t clk_lock;
struct work_struct clk_work;
+ struct delayed_work ulps_work;
struct work_struct pp_done_work;
atomic_t pp_done_cnt;
@@ -53,6 +55,7 @@
u16 start_threshold;
u32 vclk_line; /* vsync clock per line */
struct mdss_panel_recovery recovery;
+ bool ulps;
};
struct mdss_mdp_cmd_ctx mdss_mdp_cmd_ctx_list[MAX_SESSIONS];
@@ -200,8 +203,19 @@
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);
+
+ if (ctx->ulps) {
+ if (mdss_mdp_cmd_tearcheck_setup(ctx->ctl, 1))
+ pr_warn("tearcheck setup failed\n");
+ mdss_mdp_ctl_intf_event(ctx->ctl,
+ MDSS_EVENT_DSI_ULPS_CTRL, (void *)0);
+ ctx->ulps = false;
+ }
+
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
mdss_mdp_hist_intr_setup(&mdata->hist_intr, MDSS_IRQ_RESUME);
}
@@ -231,6 +245,8 @@
mdss_mdp_ctl_intf_event
(ctx->ctl, MDSS_EVENT_PANEL_CLK_CTRL, (void *)0);
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+ if (ctx->panel_on)
+ schedule_delayed_work(&ctx->ulps_work, ULPS_ENTER_TIME);
}
mutex_unlock(&ctx->clk_mtx);
}
@@ -365,6 +381,38 @@
mdss_mdp_cmd_clk_off(ctx);
}
+static void __mdss_mdp_cmd_ulps_work(struct work_struct *work)
+{
+ struct delayed_work *dw = to_delayed_work(work);
+ struct mdss_mdp_cmd_ctx *ctx =
+ container_of(dw, struct mdss_mdp_cmd_ctx, ulps_work);
+
+ if (!ctx) {
+ pr_err("%s: invalid ctx\n", __func__);
+ return;
+ }
+
+ mutex_lock(&ctx->clk_mtx);
+ if (ctx->clk_enabled) {
+ mutex_unlock(&ctx->clk_mtx);
+ pr_warn("Cannot enter ulps mode if DSI clocks are on\n");
+ return;
+ }
+ mutex_unlock(&ctx->clk_mtx);
+
+ if (!ctx->panel_on) {
+ pr_err("Panel is off. skipping ULPS configuration\n");
+ return;
+ }
+
+ if (!mdss_mdp_ctl_intf_event(ctx->ctl, MDSS_EVENT_DSI_ULPS_CTRL,
+ (void *)1)) {
+ ctx->ulps = true;
+ ctx->ctl->play_cnt = 0;
+ mdss_mdp_footswitch_ctrl_ulps(0, &ctx->ctl->mfd->pdev->dev);
+ }
+}
+
static int mdss_mdp_cmd_add_vsync_handler(struct mdss_mdp_ctl *ctl,
struct mdss_mdp_vsync_handler *handle)
{
@@ -583,11 +631,14 @@
if (cancel_work_sync(&ctx->clk_work))
pr_debug("no pending clk work\n");
+ if (cancel_delayed_work_sync(&ctx->ulps_work))
+ pr_debug("deleted pending ulps work\n");
+
+ ctx->panel_on = 0;
mdss_mdp_cmd_clk_off(ctx);
flush_work(&ctx->pp_done_work);
- ctx->panel_on = 0;
mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_RD_PTR, ctx->pp_num,
NULL, NULL);
@@ -653,6 +704,7 @@
spin_lock_init(&ctx->clk_lock);
mutex_init(&ctx->clk_mtx);
INIT_WORK(&ctx->clk_work, clk_ctrl_work);
+ INIT_DELAYED_WORK(&ctx->ulps_work, __mdss_mdp_cmd_ulps_work);
INIT_WORK(&ctx->pp_done_work, pingpong_done_work);
atomic_set(&ctx->pp_done_cnt, 0);
INIT_LIST_HEAD(&ctx->vsync_handlers);
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index 5d6ecdc..ca35aaf 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -159,6 +159,9 @@
} else if (req->flags & MDP_BWC_EN) {
pr_err("Decimation can't be enabled with BWC\n");
return -EINVAL;
+ } else if (fmt->tile) {
+ pr_err("Decimation can't be enabled with MacroTile format\n");
+ return -EINVAL;
}
}
@@ -276,7 +279,7 @@
* mdp clock requirement
*/
if (mdata->has_decimation && (pipe->vert_deci < MAX_DECIMATION)
- && !pipe->bwc_mode)
+ && !pipe->bwc_mode && !pipe->src_fmt->tile)
pipe->vert_deci++;
else
return -EPERM;
@@ -844,6 +847,11 @@
struct mdss_mdp_ctl *ctl = mdp5_data->ctl;
if (ctl->power_on) {
+ if (mdp5_data->mdata->ulps) {
+ mdss_mdp_footswitch_ctrl_ulps(1, &mfd->pdev->dev);
+ mdss_mdp_ctl_restore(ctl);
+ }
+
if (!mdp5_data->mdata->batfet)
mdss_mdp_batfet_ctrl(mdp5_data->mdata, true);
if (!mfd->panel_info->cont_splash_enabled)
@@ -1039,11 +1047,13 @@
pipe->mixer = mdss_mdp_mixer_get(tmp,
MDSS_MDP_MIXER_MUX_DEFAULT);
}
+
+ /* ensure pipes are always reconfigured after power off/on */
+ if (ctl->play_cnt == 0)
+ pipe->params_changed++;
+
if (pipe->back_buf.num_planes) {
buf = &pipe->back_buf;
- } else if (ctl->play_cnt == 0 && pipe->front_buf.num_planes) {
- pipe->params_changed++;
- buf = &pipe->front_buf;
} else if (!pipe->params_changed) {
continue;
} else if (pipe->front_buf.num_planes) {
diff --git a/drivers/video/msm/mdss/mdss_panel.h b/drivers/video/msm/mdss/mdss_panel.h
index 274c523..135a00a 100644
--- a/drivers/video/msm/mdss/mdss_panel.h
+++ b/drivers/video/msm/mdss/mdss_panel.h
@@ -127,6 +127,11 @@
- 1 clock enable
* @MDSS_EVENT_ENABLE_PARTIAL_UPDATE: Event to update ROI of the panel.
* @MDSS_EVENT_DSI_CMDLIST_KOFF: acquire dsi_mdp_busy lock before kickoff.
+ * @MDSS_EVENT_DSI_ULPS_CTRL: Event to configure Ultra Lower Power Saving
+ * mode for the DSI data and clock lanes. The
+ * event arguments can have one of these values:
+ * - 0: Disable ULPS mode
+ * - 1: Enable ULPS mode
*/
enum mdss_intf_events {
MDSS_EVENT_RESET = 1,
@@ -145,6 +150,7 @@
MDSS_EVENT_PANEL_CLK_CTRL,
MDSS_EVENT_DSI_CMDLIST_KOFF,
MDSS_EVENT_ENABLE_PARTIAL_UPDATE,
+ MDSS_EVENT_DSI_ULPS_CTRL,
};
struct lcd_panel_info {
@@ -300,6 +306,7 @@
int pwm_period;
u32 mode_gpio_state;
bool dynamic_fps;
+ bool ulps_feature_enabled;
char dfps_update;
int new_fps;
diff --git a/drivers/video/msm/mdss/mhl_sii8334.c b/drivers/video/msm/mdss/mhl_sii8334.c
index 0f84b2d..c5d5366 100644
--- a/drivers/video/msm/mdss/mhl_sii8334.c
+++ b/drivers/video/msm/mdss/mhl_sii8334.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
@@ -194,6 +194,7 @@
static void mhl_init_reg_settings(struct mhl_tx_ctrl *mhl_ctrl,
bool mhl_disc_en);
static int mhl_gpio_config(struct mhl_tx_ctrl *mhl_ctrl, int on);
+static int mhl_vreg_config(struct mhl_tx_ctrl *mhl_ctrl, uint8_t on);
int mhl_i2c_reg_read(struct i2c_client *client,
uint8_t slave_addr_index, uint8_t reg_offset)
@@ -385,15 +386,69 @@
return 0;
}
+static int mhl_sii_config(struct mhl_tx_ctrl *mhl_ctrl, bool on)
+{
+ int rc = 0;
+ struct i2c_client *client = NULL;
+
+ if (!mhl_ctrl) {
+ pr_err("%s: ctrl is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ client = mhl_ctrl->i2c_handle;
+
+ if (on) {
+ rc = mhl_vreg_config(mhl_ctrl, 1);
+ if (rc) {
+ pr_err("%s: vreg init failed [%d]\n",
+ __func__, rc);
+ return -ENODEV;
+ }
+
+ rc = mhl_gpio_config(mhl_ctrl, 1);
+ if (rc) {
+ pr_err("%s: gpio init failed [%d]\n",
+ __func__, rc);
+ return -ENODEV;
+ }
+
+ rc = request_threaded_irq(mhl_ctrl->i2c_handle->irq, NULL,
+ &mhl_tx_isr, IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ client->dev.driver->name, mhl_ctrl);
+ if (rc) {
+ pr_err("%s: request_threaded_irq failed, status: %d\n",
+ __func__, rc);
+ return -ENODEV;
+ } else {
+ mhl_ctrl->irq_req_done = true;
+ }
+ } else {
+ free_irq(mhl_ctrl->i2c_handle->irq, mhl_ctrl);
+ mhl_gpio_config(mhl_ctrl, 0);
+ mhl_vreg_config(mhl_ctrl, 0);
+ mhl_ctrl->irq_req_done = false;
+ }
+
+ return rc;
+}
+
+static void mhl_sii_disc_intr_work(struct work_struct *work)
+{
+ struct mhl_tx_ctrl *mhl_ctrl = NULL;
+
+ mhl_ctrl = container_of(work, struct mhl_tx_ctrl, mhl_intr_work);
+
+ mhl_sii_config(mhl_ctrl, false);
+}
+
/* USB_HANDSHAKING FUNCTIONS */
static int mhl_sii_device_discovery(void *data, int id,
void (*usb_notify_cb)(void *, int), void *ctx)
{
int rc;
struct mhl_tx_ctrl *mhl_ctrl = data;
- struct i2c_client *client = mhl_ctrl->i2c_handle;
unsigned long flags;
- int discovery_retry = 5;
if (id) {
/* When MHL cable is disconnected we get a sii8334
@@ -413,18 +468,14 @@
mhl_ctrl->notify_usb_online = usb_notify_cb;
mhl_ctrl->notify_ctx = ctx;
}
-again:
+
+ flush_work(&mhl_ctrl->mhl_intr_work);
+
if (!mhl_ctrl->irq_req_done) {
- rc = request_threaded_irq(mhl_ctrl->i2c_handle->irq, NULL,
- &mhl_tx_isr, IRQF_TRIGGER_LOW | IRQF_ONESHOT,
- client->dev.driver->name, mhl_ctrl);
+ rc = mhl_sii_config(mhl_ctrl, true);
if (rc) {
- pr_debug("request_threaded_irq failed, status: %d\n",
- rc);
- return -EINVAL;
- } else {
- pr_debug("request_threaded_irq succeeded\n");
- mhl_ctrl->irq_req_done = true;
+ pr_err("%s: Failed to config vreg/gpio\n", __func__);
+ return rc;
}
/* wait for i2c interrupt line to be activated */
@@ -448,23 +499,9 @@
if (mhl_sii_wait_for_rgnd(mhl_ctrl)) {
pr_err("%s: discovery timeout\n", __func__);
- free_irq(mhl_ctrl->i2c_handle->irq, mhl_ctrl);
- mhl_gpio_config(mhl_ctrl, 0);
- mhl_ctrl->irq_req_done = false;
+ mhl_sii_config(mhl_ctrl, false);
- msleep(100);
-
- mhl_gpio_config(mhl_ctrl, 1);
- if (discovery_retry--) {
- pr_debug("%s: retrying discovery\n", __func__);
- goto again;
- } else {
- pr_err("%s: discovery failed, ret to USB\n",
- __func__);
- if (mhl_ctrl->notify_usb_online)
- mhl_ctrl->notify_usb_online(
- mhl_ctrl->notify_ctx, 0);
- }
+ return -EAGAIN;
}
} else {
if (mhl_ctrl->cur_state == POWER_STATE_D3) {
@@ -1059,13 +1096,8 @@
mhl_msm_connection(mhl_ctrl);
} else if (status & BIT3) {
pr_debug("%s: uUSB-a type dev detct\n", __func__);
-
- /* Short RGND */
- MHL_SII_REG_NAME_MOD(REG_DISC_STAT2, BIT0 | BIT1, 0x00);
- mhl_msm_disconnection(mhl_ctrl);
power_supply_changed(&mhl_ctrl->mhl_psy);
- if (mhl_ctrl->notify_usb_online)
- mhl_ctrl->notify_usb_online(mhl_ctrl->notify_ctx, 0);
+ mhl_drive_hpd(mhl_ctrl, HPD_DOWN);
return 0;
}
@@ -1081,6 +1113,9 @@
power_supply_changed(&mhl_ctrl->mhl_psy);
if (mhl_ctrl->notify_usb_online)
mhl_ctrl->notify_usb_online(mhl_ctrl->notify_ctx, 0);
+
+ queue_work(mhl_ctrl->mhl_workq, &mhl_ctrl->mhl_intr_work);
+
return 0;
}
@@ -1495,6 +1530,27 @@
int rc = -EINVAL;
pr_debug("%s\n", __func__);
+
+ if (!enable) {
+ regulator_disable(reg_8941_vdda);
+ regulator_put(reg_8941_vdda);
+ reg_8941_vdda = NULL;
+
+ regulator_disable(reg_8941_smps3a);
+ regulator_put(reg_8941_smps3a);
+ reg_8941_smps3a = NULL;
+
+ regulator_disable(reg_8941_l02);
+ regulator_put(reg_8941_l02);
+ reg_8941_l02 = NULL;
+
+ regulator_disable(reg_8941_l24);
+ regulator_put(reg_8941_l24);
+ reg_8941_l24 = NULL;
+
+ return 0;
+ }
+
if (!reg_8941_l24) {
reg_8941_l24 = regulator_get(&client->dev,
"avcc_18");
@@ -1736,26 +1792,6 @@
}
/*
- * Regulator init
- */
- rc = mhl_vreg_config(mhl_ctrl, 1);
- if (rc) {
- pr_err("%s: vreg init failed [%d]\n",
- __func__, rc);
- goto failed_probe;
- }
-
- /*
- * GPIO init
- */
- rc = mhl_gpio_config(mhl_ctrl, 1);
- if (rc) {
- pr_err("%s: gpio init failed [%d]\n",
- __func__, rc);
- goto failed_probe;
- }
-
- /*
* Other initializations
* such tx specific
*/
@@ -1767,6 +1803,9 @@
spin_lock_init(&mhl_ctrl->lock);
mhl_ctrl->msc_send_workqueue = create_singlethread_workqueue
("mhl_msc_cmd_queue");
+ mhl_ctrl->mhl_workq = create_singlethread_workqueue("mhl_workq");
+
+ INIT_WORK(&mhl_ctrl->mhl_intr_work, mhl_sii_disc_intr_work);
mhl_ctrl->input = input_allocate_device();
if (mhl_ctrl->input) {
@@ -1894,9 +1933,7 @@
failed_probe_pwr:
power_supply_unregister(&mhl_ctrl->mhl_psy);
failed_probe:
- free_irq(mhl_ctrl->i2c_handle->irq, mhl_ctrl);
- mhl_gpio_config(mhl_ctrl, 0);
- mhl_vreg_config(mhl_ctrl, 0);
+ mhl_sii_config(mhl_ctrl, false);
/* do not deep-free */
if (mhl_info)
devm_kfree(&client->dev, mhl_info);
@@ -1923,9 +1960,10 @@
return -EINVAL;
}
- free_irq(mhl_ctrl->i2c_handle->irq, mhl_ctrl);
- mhl_gpio_config(mhl_ctrl, 0);
- mhl_vreg_config(mhl_ctrl, 0);
+ mhl_sii_config(mhl_ctrl, false);
+
+ destroy_workqueue(mhl_ctrl->mhl_workq);
+
if (mhl_ctrl->mhl_info)
devm_kfree(&client->dev, mhl_ctrl->mhl_info);
if (mhl_ctrl->pdata)
@@ -1949,17 +1987,19 @@
pr_debug("%s\n", __func__);
- if (!mhl_ctrl)
+ if (!mhl_ctrl) {
+ pr_err("%s: invalid ctrl data\n", __func__);
return 0;
-
- free_irq(mhl_ctrl->i2c_handle->irq, mhl_ctrl);
- mhl_ctrl->irq_req_done = false;
+ }
if (mhl_ctrl->mhl_mode) {
mhl_ctrl->mhl_mode = 0;
+
power_supply_changed(&mhl_ctrl->mhl_psy);
if (mhl_ctrl->notify_usb_online)
mhl_ctrl->notify_usb_online(mhl_ctrl->notify_ctx, 0);
+
+ mhl_sii_config(mhl_ctrl, false);
}
return 0;
diff --git a/drivers/video/msm/mdss/msm_mdss_io_8974.c b/drivers/video/msm/mdss/msm_mdss_io_8974.c
index 6ebcdf6..a0663e3 100644
--- a/drivers/video/msm/mdss/msm_mdss_io_8974.c
+++ b/drivers/video/msm/mdss/msm_mdss_io_8974.c
@@ -64,6 +64,16 @@
goto mdss_dsi_clk_err;
}
+ if (ctrl_pdata->panel_data.panel_info.type == MIPI_CMD_PANEL) {
+ ctrl_pdata->mmss_misc_ahb_clk = clk_get(dev, "core_mmss_clk");
+ if (IS_ERR(ctrl_pdata->mmss_misc_ahb_clk)) {
+ rc = PTR_ERR(ctrl_pdata->mmss_misc_ahb_clk);
+ pr_err("%s: Unable to get mmss misc ahb clk. rc=%d\n",
+ __func__, rc);
+ goto mdss_dsi_clk_err;
+ }
+ }
+
ctrl_pdata->byte_clk = clk_get(dev, "byte_clk");
if (IS_ERR(ctrl_pdata->byte_clk)) {
rc = PTR_ERR(ctrl_pdata->byte_clk);
@@ -105,6 +115,8 @@
clk_put(ctrl_pdata->esc_clk);
if (ctrl_pdata->pixel_clk)
clk_put(ctrl_pdata->pixel_clk);
+ if (ctrl_pdata->mmss_misc_ahb_clk)
+ clk_put(ctrl_pdata->mmss_misc_ahb_clk);
if (ctrl_pdata->axi_clk)
clk_put(ctrl_pdata->axi_clk);
if (ctrl_pdata->ahb_clk)
@@ -275,12 +287,26 @@
goto error;
}
+ if (ctrl_pdata->mmss_misc_ahb_clk) {
+ rc = clk_prepare_enable(ctrl_pdata->mmss_misc_ahb_clk);
+ if (rc) {
+ pr_err("%s: failed to enable mmss misc ahb clk.rc=%d\n",
+ __func__, rc);
+ clk_disable_unprepare(ctrl_pdata->axi_clk);
+ clk_disable_unprepare(ctrl_pdata->ahb_clk);
+ clk_disable_unprepare(ctrl_pdata->mdp_core_clk);
+ goto error;
+ }
+ }
+
error:
return rc;
}
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);
clk_disable_unprepare(ctrl_pdata->axi_clk);
clk_disable_unprepare(ctrl_pdata->ahb_clk);
clk_disable_unprepare(ctrl_pdata->mdp_core_clk);
@@ -507,6 +533,16 @@
static DEFINE_MUTEX(dsi_clk_lock); /* per system */
+bool __mdss_dsi_clk_enabled(struct mdss_dsi_ctrl_pdata *ctrl)
+{
+ bool enabled;
+ mutex_lock(&dsi_clk_lock);
+ enabled = ctrl->clk_cnt ? true : false;
+ mutex_unlock(&dsi_clk_lock);
+
+ return enabled;
+}
+
void mdss_dsi_clk_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, int enable)
{
int changed = 0;
diff --git a/fs/fat/fat.h b/fs/fat/fat.h
index 341f753..8db494d 100644
--- a/fs/fat/fat.h
+++ b/fs/fat/fat.h
@@ -329,10 +329,14 @@
/* fat/misc.c */
extern __printf(3, 4) __cold
void __fat_fs_error(struct super_block *sb, int report, const char *fmt, ...);
-#define fat_fs_error(sb, fmt, args...) \
- __fat_fs_error(sb, 1, fmt , ## args)
#define fat_fs_error_ratelimit(sb, fmt, args...) \
__fat_fs_error(sb, __ratelimit(&MSDOS_SB(sb)->ratelimit), fmt , ## args)
+/*
+ * If removable devices with a fat fs are removed without a unmount, further
+ * accesses to the device by applications causes a large number of error prints
+ * & in some cases leads to watchdog bark.
+ */
+#define fat_fs_error(sb, fmt, args...) fat_fs_error_ratelimit(sb, fmt, ## args)
__printf(3, 4) __cold
void fat_msg(struct super_block *sb, const char *level, const char *fmt, ...);
extern int fat_clusters_flush(struct super_block *sb);
diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h
index ac750ea..3f62354 100644
--- a/include/linux/blk_types.h
+++ b/include/linux/blk_types.h
@@ -95,6 +95,12 @@
#define BIO_FS_INTEGRITY 9 /* fs owns integrity data, not block layer */
#define BIO_QUIET 10 /* Make BIO Quiet */
#define BIO_MAPPED_INTEGRITY 11/* integrity metadata has been remapped */
+/*
+ * Added for Req based dm which need to perform post processing. This flag
+ * ensures blk_update_request does not free the bios or request, this is done
+ * at the dm level
+ */
+#define BIO_DONTFREE 12
#define bio_flagged(bio, flag) ((bio)->bi_flags & (1 << (flag)))
/*
diff --git a/include/linux/device-mapper.h b/include/linux/device-mapper.h
index 98f34b8..546871b 100644
--- a/include/linux/device-mapper.h
+++ b/include/linux/device-mapper.h
@@ -510,5 +510,6 @@
void dm_requeue_unmapped_request(struct request *rq);
void dm_kill_unmapped_request(struct request *rq, int error);
int dm_underlying_device_busy(struct request_queue *q);
+void dm_end_request(struct request *clone, int error);
#endif /* _LINUX_DEVICE_MAPPER_H */
diff --git a/include/linux/mhl_8334.h b/include/linux/mhl_8334.h
index 71dec42..42ee81e 100644
--- a/include/linux/mhl_8334.h
+++ b/include/linux/mhl_8334.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
@@ -155,6 +155,8 @@
struct list_head list_cmd;
struct input_dev *input;
struct workqueue_struct *msc_send_workqueue;
+ struct workqueue_struct *mhl_workq;
+ struct work_struct mhl_intr_work;
u16 *rcp_key_code_tbl;
size_t rcp_key_code_tbl_len;
struct scrpd_struct scrpd;
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 272fe77..8b604e3 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -94,6 +94,7 @@
u8 raw_erased_mem_count; /* 181 */
u8 raw_ext_csd_structure; /* 194 */
u8 raw_card_type; /* 196 */
+ u8 raw_drive_strength; /* 197 */
u8 out_of_int_time; /* 198 */
u8 raw_s_a_timeout; /* 217 */
u8 raw_hc_erase_gap_size; /* 221 */
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index 764beec..b626915 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -303,6 +303,7 @@
#define EXT_CSD_REV 192 /* RO */
#define EXT_CSD_STRUCTURE 194 /* RO */
#define EXT_CSD_CARD_TYPE 196 /* RO */
+#define EXT_CSD_DRIVE_STRENGTH 197 /* RO */
#define EXT_CSD_OUT_OF_INTERRUPT_TIME 198 /* RO */
#define EXT_CSD_PART_SWITCH_TIME 199 /* RO */
#define EXT_CSD_PWR_CL_52_195 200 /* RO */
diff --git a/include/linux/smsc_hub.h b/include/linux/smsc_hub.h
index 9c0afc0..c87f21b 100644
--- a/include/linux/smsc_hub.h
+++ b/include/linux/smsc_hub.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 software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -14,6 +14,7 @@
#ifndef __LINUX_SMSC3503_H__
#define __LINUX_SMSC3503_H__
+#define SMSC3502_ID 3502
#define SMSC3503_ID 3503
#define SMSC4604_ID 4604
#define SMSC3503_I2C_ADDR 0x08
@@ -52,6 +53,7 @@
int hub_reset;
int refclk_gpio;
int int_gpio;
+ int xo_clk_gpio;
};
#endif
diff --git a/include/media/msmb_isp.h b/include/media/msmb_isp.h
index 3ba0abe..3828221 100644
--- a/include/media/msmb_isp.h
+++ b/include/media/msmb_isp.h
@@ -1,3 +1,14 @@
+/* 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
#ifndef __MSMB_ISP__
#define __MSMB_ISP__
@@ -302,15 +313,16 @@
ISP_WM_BUS_OVERFLOW = 4,
ISP_STATS_OVERFLOW = 5,
ISP_CAMIF_ERROR = 6,
- ISP_SOF = 7,
- ISP_EOF = 8,
- ISP_EVENT_MAX = 9
+ ISP_BUF_DONE = 9,
+ ISP_EVENT_MAX = 10
};
#define ISP_EVENT_OFFSET 8
#define ISP_EVENT_BASE (V4L2_EVENT_PRIVATE_START)
#define ISP_BUF_EVENT_BASE (ISP_EVENT_BASE + (1 << ISP_EVENT_OFFSET))
#define ISP_STATS_EVENT_BASE (ISP_EVENT_BASE + (2 << ISP_EVENT_OFFSET))
+#define ISP_SOF_EVENT_BASE (ISP_EVENT_BASE + (3 << ISP_EVENT_OFFSET))
+#define ISP_EOF_EVENT_BASE (ISP_EVENT_BASE + (4 << ISP_EVENT_OFFSET))
#define ISP_EVENT_REG_UPDATE (ISP_EVENT_BASE + ISP_REG_UPDATE)
#define ISP_EVENT_START_ACK (ISP_EVENT_BASE + ISP_START_ACK)
#define ISP_EVENT_STOP_ACK (ISP_EVENT_BASE + ISP_STOP_ACK)
@@ -318,8 +330,9 @@
#define ISP_EVENT_WM_BUS_OVERFLOW (ISP_EVENT_BASE + ISP_WM_BUS_OVERFLOW)
#define ISP_EVENT_STATS_OVERFLOW (ISP_EVENT_BASE + ISP_STATS_OVERFLOW)
#define ISP_EVENT_CAMIF_ERROR (ISP_EVENT_BASE + ISP_CAMIF_ERROR)
-#define ISP_EVENT_SOF (ISP_EVENT_BASE + ISP_SOF)
-#define ISP_EVENT_EOF (ISP_EVENT_BASE + ISP_EOF)
+#define ISP_EVENT_SOF (ISP_SOF_EVENT_BASE)
+#define ISP_EVENT_EOF (ISP_EOF_EVENT_BASE)
+#define ISP_EVENT_BUF_DONE (ISP_EVENT_BASE + ISP_BUF_DONE)
#define ISP_EVENT_BUF_DIVERT (ISP_BUF_EVENT_BASE)
#define ISP_EVENT_STATS_NOTIFY (ISP_STATS_EVENT_BASE)
#define ISP_EVENT_COMP_STATS_NOTIFY (ISP_EVENT_STATS_NOTIFY + MSM_ISP_STATS_MAX)
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 9f0d486..ecaef21 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -3224,8 +3224,8 @@
static inline struct sk_buff *
cfg80211_vendor_cmd_alloc_reply_skb(struct wiphy *wiphy, int approxlen)
{
- return __cfg80211_alloc_reply_skb(wiphy, NL80211_CMD_TESTMODE,
- NL80211_ATTR_TESTDATA, approxlen);
+ return __cfg80211_alloc_reply_skb(wiphy, NL80211_CMD_VENDOR,
+ NL80211_ATTR_VENDOR_DATA, approxlen);
}
/**
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
index 2c969cd..69944a6 100644
--- a/include/sound/apr_audio-v2.h
+++ b/include/sound/apr_audio-v2.h
@@ -6874,6 +6874,7 @@
#define Q6AFE_LPASS_IBIT_CLK_1_P024_MHZ 0xFA000
#define Q6AFE_LPASS_IBIT_CLK_768_KHZ 0xBB800
#define Q6AFE_LPASS_IBIT_CLK_512_KHZ 0x7D000
+#define Q6AFE_LPASS_IBIT_CLK_256_KHZ 0x3E800
#define Q6AFE_LPASS_IBIT_CLK_DISABLE 0x0
/* Supported LPASS CLK sources */
diff --git a/kernel/power/process.c b/kernel/power/process.c
index 31b6f25..e10e171 100644
--- a/kernel/power/process.c
+++ b/kernel/power/process.c
@@ -35,6 +35,7 @@
u64 elapsed_csecs64;
unsigned int elapsed_csecs;
bool wakeup = false;
+ int sleep_usecs = USEC_PER_MSEC;
do_gettimeofday(&start);
@@ -81,9 +82,12 @@
/*
* We need to retry, but first give the freezing tasks some
- * time to enter the regrigerator.
+ * time to enter the refrigerator. Start with an initial
+ * 1 ms sleep followed by exponential backoff until 8 ms.
*/
- msleep(10);
+ usleep_range(sleep_usecs / 2, sleep_usecs);
+ if (sleep_usecs < 8 * USEC_PER_MSEC)
+ sleep_usecs *= 2;
}
do_gettimeofday(&end);
diff --git a/lib/genalloc.c b/lib/genalloc.c
index 604ee09..0218f4b 100644
--- a/lib/genalloc.c
+++ b/lib/genalloc.c
@@ -247,7 +247,7 @@
end_bit = (chunk->end_addr - chunk->start_addr) >> order;
nbytes = sizeof(struct gen_pool_chunk) +
- (end_bit + BITS_PER_BYTE - 1) / BITS_PER_BYTE;
+ BITS_TO_LONGS(end_bit) * sizeof(long);
bit = find_next_bit(chunk->bits, end_bit, 0);
BUG_ON(bit < end_bit);
diff --git a/net/wireless/db.txt b/net/wireless/db.txt
index c27f165..f6c74c9 100644
--- a/net/wireless/db.txt
+++ b/net/wireless/db.txt
@@ -18,7 +18,7 @@
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 80), (3, 17)
(5250 - 5330 @ 80), (3, 24), DFS
- (5490 - 5710 @ 80), (3, 24), DFS
+ (5490 - 5730 @ 80), (3, 24), DFS
(5735 - 5835 @ 80), (3, 30)
country AL:
@@ -42,7 +42,7 @@
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 80), (3, 17)
(5250 - 5330 @ 80), (3, 24), DFS
- (5490 - 5710 @ 80), (3, 24), DFS
+ (5490 - 5730 @ 80), (3, 24), DFS
(5735 - 5835 @ 80), (3, 30)
country AS:
@@ -64,7 +64,7 @@
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 80), (3, 17)
(5250 - 5330 @ 80), (3, 24), DFS
- (5490 - 5710 @ 80), (3, 24), DFS
+ (5490 - 5730 @ 80), (3, 24), DFS
(5735 - 5835 @ 80), (3, 30)
country AW:
@@ -139,7 +139,7 @@
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 80), (3, 17)
(5250 - 5330 @ 80), (3, 24), DFS
- (5490 - 5710 @ 80), (3, 24), DFS
+ (5490 - 5730 @ 80), (3, 24), DFS
(5735 - 5835 @ 80), (3, 30)
country BS:
@@ -163,7 +163,7 @@
(2402 - 2472 @ 40), (N/A, 27)
(5170 - 5250 @ 80), (3, 17)
(5250 - 5330 @ 80), (3, 24), DFS
- (5490 - 5710 @ 80), (3, 24), DFS
+ (5490 - 5730 @ 80), (3, 24), DFS
(5735 - 5835 @ 80), (3, 30)
country CH: DFS-ETSI
@@ -196,14 +196,14 @@
(2402 - 2472 @ 40), (N/A, 27)
(5170 - 5250 @ 80), (3, 17)
(5250 - 5330 @ 80), (3, 24), DFS
- (5490 - 5710 @ 80), (3, 24), DFS
+ (5490 - 5730 @ 80), (3, 24), DFS
(5735 - 5835 @ 80), (3, 30)
country CR:
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 20), (3, 17)
(5250 - 5330 @ 20), (3, 24), DFS
- (5490 - 5710 @ 20), (3, 24), DFS
+ (5490 - 5730 @ 20), (3, 24), DFS
(5735 - 5835 @ 20), (3, 30)
country CY: DFS-ETSI
@@ -271,7 +271,7 @@
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 20), (3, 17)
(5250 - 5330 @ 20), (3, 24), DFS
- (5490 - 5710 @ 20), (3, 24), DFS
+ (5490 - 5730 @ 20), (3, 24), DFS
(5735 - 5835 @ 20), (3, 30)
country EE: DFS-ETSI
@@ -342,7 +342,7 @@
(2402 - 2472 @ 40), (3, 30)
(5170 - 5250 @ 80), (6, 17)
(5250 - 5330 @ 80), (6, 24), DFS
- (5490 - 5710 @ 80), (6, 24), DFS
+ (5490 - 5730 @ 80), (6, 24), DFS
(5735 - 5835 @ 80), (6, 30)
country GP:
@@ -375,21 +375,21 @@
(2402 - 2472 @ 40), (3, 30)
(5170 - 5250 @ 20), (6, 17)
(5250 - 5330 @ 20), (6, 24), DFS
- (5490 - 5710 @ 20), (6, 24), DFS
+ (5490 - 5730 @ 20), (6, 24), DFS
(5735 - 5835 @ 20), (6, 30)
country HN:
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 80), (6, 17)
(5250 - 5330 @ 80), (6, 24), DFS
- (5490 - 5710 @ 80), (6, 24), DFS
+ (5490 - 5730 @ 80), (6, 24), DFS
(5735 - 5835 @ 80), (6, 30)
country HK:
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 80), (6, 17)
(5250 - 5330 @ 80), (6, 24), DFS
- (5490 - 5710 @ 80), (6, 24), DFS
+ (5490 - 5730 @ 80), (6, 24), DFS
(5735 - 5835 @ 80), (6, 30)
country HR: DFS-ETSI
@@ -462,7 +462,7 @@
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 80), (6, 17)
(5250 - 5330 @ 80), (6, 24), DFS
- (5490 - 5710 @ 80), (6, 24), DFS
+ (5490 - 5730 @ 80), (6, 24), DFS
(5735 - 5835 @ 80), (6, 30)
country JP:
@@ -495,7 +495,7 @@
(2402 - 2472 @ 40), (N/A, 27)
(5170 - 5250 @ 80), (3, 17)
(5250 - 5330 @ 80), (3, 24), DFS
- (5490 - 5710 @ 80), (3, 24), DFS
+ (5490 - 5730 @ 80), (3, 24), DFS
(5735 - 5835 @ 80), (3, 30)
country KP:
@@ -537,7 +537,7 @@
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 20), (3, 17)
(5250 - 5330 @ 20), (3, 20), DFS
- (5490 - 5710 @ 20), (3, 20), DFS
+ (5490 - 5730 @ 20), (3, 20), DFS
(5735 - 5835 @ 20), (3, 30)
country LT: DFS-ETSI
@@ -634,7 +634,7 @@
(2402 - 2472 @ 40), (3, 27)
(5170 - 5250 @ 80), (3, 17)
(5250 - 5330 @ 80), (3, 24), DFS
- (5490 - 5710 @ 80), (3, 24), DFS
+ (5490 - 5730 @ 80), (3, 24), DFS
(5735 - 5835 @ 80), (3, 30)
country MW:
@@ -681,7 +681,7 @@
(2402 - 2482 @ 40), (N/A, 30)
(5170 - 5250 @ 80), (6, 17)
(5250 - 5330 @ 80), (6, 24), DFS
- (5490 - 5710 @ 80), (6, 24), DFS
+ (5490 - 5730 @ 80), (6, 24), DFS
(5735 - 5835 @ 80), (6, 30)
country OM:
@@ -700,7 +700,7 @@
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 80), (6, 20)
(5250 - 5330 @ 80), (6, 20), DFS
- (5490 - 5710 @ 80), (6, 27), DFS
+ (5490 - 5730 @ 80), (6, 27), DFS
(5735 - 5835 @ 80), (6, 30)
country PF:
@@ -720,7 +720,7 @@
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 80), (6, 17)
(5250 - 5330 @ 80), (6, 24), DFS
- (5490 - 5710 @ 80), (6, 24), DFS
+ (5490 - 5730 @ 80), (6, 24), DFS
(5735 - 5835 @ 80), (6, 30)
country PK:
@@ -747,7 +747,7 @@
(2402 - 2472 @ 40), (3, 30)
(5170 - 5250 @ 80), (6, 17)
(5250 - 5330 @ 80), (6, 24), DFS
- (5490 - 5710 @ 80), (6, 24), DFS
+ (5490 - 5730 @ 80), (6, 24), DFS
(5735 - 5835 @ 80), (6, 30)
country PY:
@@ -819,7 +819,7 @@
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 80), (6, 17)
(5250 - 5330 @ 80), (6, 24), DFS
- (5490 - 5710 @ 80), (6, 24), DFS
+ (5490 - 5730 @ 80), (6, 24), DFS
(5735 - 5835 @ 80), (6, 30)
country SI: DFS-ETSI
@@ -856,21 +856,21 @@
country TW:
(2402 - 2472 @ 40), (3, 27)
(5270 - 5330 @ 40), (6, 17), DFS
- (5490 - 5710 @ 80), (6, 30), DFS
+ (5490 - 5730 @ 80), (6, 30), DFS
(5735 - 5815 @ 80), (6, 30)
country TH:
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 80), (3, 17)
(5250 - 5330 @ 80), (3, 24), DFS
- (5490 - 5710 @ 80), (3, 24), DFS
+ (5490 - 5730 @ 80), (3, 24), DFS
(5735 - 5835 @ 80), (3, 30)
country TT:
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 40), (3, 17)
(5250 - 5330 @ 40), (3, 20), DFS
- (5490 - 5710 @ 40), (3, 20), DFS
+ (5490 - 5730 @ 40), (3, 20), DFS
(5735 - 5835 @ 40), (3, 30)
country TN:
@@ -914,8 +914,8 @@
(5170 - 5250 @ 80), (3, 17)
(5250 - 5330 @ 80), (3, 24), DFS
(5490 - 5600 @ 80), (3, 24), DFS
- (5650 - 5710 @ 40), (3, 24), DFS
- (5710 - 5835 @ 80), (3, 30)
+ (5650 - 5730 @ 40), (3, 24), DFS
+ (5735 - 5835 @ 80), (3, 30)
# 60g band
# reference: http://cfr.regstoday.com/47cfr15.aspx#47_CFR_15p255
# channels 1,2,3, EIRP=40dBm(43dBm peak)
@@ -935,14 +935,14 @@
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 40), (3, 17)
(5250 - 5330 @ 40), (3, 20), DFS
- (5490 - 5710 @ 40), (3, 20), DFS
+ (5490 - 5730 @ 40), (3, 20), DFS
(5735 - 5835 @ 40), (3, 30)
country UZ:
(2402 - 2472 @ 40), (3, 27)
(5170 - 5250 @ 40), (3, 17)
(5250 - 5330 @ 40), (3, 20), DFS
- (5490 - 5710 @ 40), (3, 20), DFS
+ (5490 - 5730 @ 40), (3, 20), DFS
(5735 - 5835 @ 40), (3, 30)
country VE:
@@ -956,7 +956,7 @@
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 80), (3, 17)
(5250 - 5330 @ 80), (3, 24), DFS
- (5490 - 5710 @ 80), (3, 24), DFS
+ (5490 - 5730 @ 80), (3, 24), DFS
(5735 - 5835 @ 80), (3, 30)
country VI:
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index e90ef68..b73cfe5 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -5431,6 +5431,8 @@
return err;
}
+#endif
+
struct sk_buff *__cfg80211_alloc_event_skb(struct wiphy *wiphy,
enum nl80211_commands cmd,
enum nl80211_attrs attr,
@@ -5478,7 +5480,7 @@
nl80211_testmode_mcgrp.id, gfp);
}
EXPORT_SYMBOL(__cfg80211_send_event_skb);
-#endif
+
static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
{
diff --git a/sound/soc/codecs/wcd9306.c b/sound/soc/codecs/wcd9306.c
index dd50020..d84ba90 100644
--- a/sound/soc/codecs/wcd9306.c
+++ b/sound/soc/codecs/wcd9306.c
@@ -1110,14 +1110,14 @@
SOC_ENUM_EXT("EAR PA Gain", tapan_ear_pa_gain_enum[0],
tapan_pa_gain_get, tapan_pa_gain_put),
- SOC_SINGLE_TLV("HPHL Volume", TAPAN_A_RX_HPH_L_GAIN, 0, 14, 1,
+ SOC_SINGLE_TLV("HPHL Volume", TAPAN_A_RX_HPH_L_GAIN, 0, 20, 1,
line_gain),
- SOC_SINGLE_TLV("HPHR Volume", TAPAN_A_RX_HPH_R_GAIN, 0, 14, 1,
+ SOC_SINGLE_TLV("HPHR Volume", TAPAN_A_RX_HPH_R_GAIN, 0, 20, 1,
line_gain),
- SOC_SINGLE_TLV("LINEOUT1 Volume", TAPAN_A_RX_LINE_1_GAIN, 0, 14, 1,
+ SOC_SINGLE_TLV("LINEOUT1 Volume", TAPAN_A_RX_LINE_1_GAIN, 0, 20, 1,
line_gain),
- SOC_SINGLE_TLV("LINEOUT2 Volume", TAPAN_A_RX_LINE_2_GAIN, 0, 14, 1,
+ SOC_SINGLE_TLV("LINEOUT2 Volume", TAPAN_A_RX_LINE_2_GAIN, 0, 20, 1,
line_gain),
SOC_SINGLE_TLV("SPK DRV Volume", TAPAN_A_SPKR_DRV_GAIN, 3, 8, 1,
diff --git a/sound/soc/msm/msm8x10.c b/sound/soc/msm/msm8x10.c
index 7b3a028..fe44a23 100644
--- a/sound/soc/msm/msm8x10.c
+++ b/sound/soc/msm/msm8x10.c
@@ -624,8 +624,8 @@
btn_low[5] = 190;
btn_high[5] = 228;
btn_low[6] = 229;
- btn_high[6] = 269;
- btn_low[7] = 270;
+ btn_high[6] = 264;
+ btn_low[7] = 265;
btn_high[7] = 500;
n_ready = wcd9xxx_mbhc_cal_btn_det_mp(btn_cfg, MBHC_BTN_DET_N_READY);
n_ready[0] = 80;
diff --git a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
index 41ef3e3..143508f 100644
--- a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
@@ -472,11 +472,12 @@
COMPR_PLAYBACK_MIN_NUM_FRAGMENTS;
prtd->compr_cap.max_fragments =
COMPR_PLAYBACK_MAX_NUM_FRAGMENTS;
- prtd->compr_cap.num_codecs = 4;
+ prtd->compr_cap.num_codecs = 5;
prtd->compr_cap.codecs[0] = SND_AUDIOCODEC_MP3;
prtd->compr_cap.codecs[1] = SND_AUDIOCODEC_AAC;
prtd->compr_cap.codecs[2] = SND_AUDIOCODEC_AC3;
prtd->compr_cap.codecs[3] = SND_AUDIOCODEC_EAC3;
+ prtd->compr_cap.codecs[4] = SND_AUDIOCODEC_PCM;
}
static int msm_compr_send_media_format_block(struct snd_compr_stream *cstream,
@@ -486,8 +487,22 @@
struct msm_compr_audio *prtd = runtime->private_data;
struct asm_aac_cfg aac_cfg;
int ret = 0;
+ uint16_t bit_width = 16;
switch (prtd->codec) {
+ case FORMAT_LINEAR_PCM:
+ pr_debug("SND_AUDIOCODEC_PCM\n");
+ if (prtd->codec_param.codec.format == SNDRV_PCM_FORMAT_S24_LE)
+ bit_width = 24;
+ ret = q6asm_media_format_block_pcm_format_support(
+ prtd->audio_client,
+ prtd->sample_rate,
+ prtd->num_channels,
+ bit_width);
+ if (ret < 0)
+ pr_err("%s: CMD Format block failed\n", __func__);
+
+ break;
case FORMAT_MP3:
/* no media format block needed */
break;
@@ -744,6 +759,7 @@
if ((stream_index < MAX_NUMBER_OF_STREAMS && stream_index >= 0) &&
(prtd->gapless_state.stream_opened[stream_index])) {
+ prtd->gapless_state.stream_opened[stream_index] = 0;
spin_unlock_irqrestore(&prtd->lock, flags);
pr_debug(" close stream %d", NEXT_STREAM_ID(stream_id));
q6asm_stream_cmd(ac, CMD_CLOSE, NEXT_STREAM_ID(stream_id));
@@ -753,6 +769,7 @@
stream_index = STREAM_ARRAY_INDEX(stream_id);
if ((stream_index < MAX_NUMBER_OF_STREAMS && stream_index >= 0) &&
(prtd->gapless_state.stream_opened[stream_index])) {
+ prtd->gapless_state.stream_opened[stream_index] = 0;
spin_unlock_irqrestore(&prtd->lock, flags);
pr_debug("close stream %d", stream_id);
q6asm_stream_cmd(ac, CMD_CLOSE, stream_id);
@@ -826,6 +843,12 @@
pr_debug("%s: sample_rate %d\n", __func__, prtd->sample_rate);
switch (params->codec.id) {
+ case SND_AUDIOCODEC_PCM: {
+ pr_debug("SND_AUDIOCODEC_PCM\n");
+ prtd->codec = FORMAT_LINEAR_PCM;
+ break;
+ }
+
case SND_AUDIOCODEC_MP3: {
pr_debug("SND_AUDIOCODEC_MP3\n");
prtd->codec = FORMAT_MP3;
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index 32e6b2b..4aa1bce 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -430,7 +430,7 @@
path_type,
msm_bedais[i].sample_rate,
msm_bedais[i].channel,
- topology, false,
+ topology, perf_mode,
bits_per_sample);
payload.copp_ids[payload.num_copps++] =
@@ -1476,7 +1476,7 @@
msm_route_ext_ec_ref = AFE_PORT_INVALID;
break;
}
- if (voc_set_ext_ec_ref(msm_route_ext_ec_ref, state)) {
+ if (!voc_set_ext_ec_ref(msm_route_ext_ec_ref, state)) {
mutex_unlock(&routing_lock);
snd_soc_dapm_mux_update_power(widget, kcontrol, 1, mux, e);
} else {
@@ -2611,6 +2611,11 @@
0, 1, 0, msm_routing_get_fm_pcmrx_switch_mixer,
msm_routing_put_fm_pcmrx_switch_mixer);
+static const struct snd_kcontrol_new pri_mi2s_rx_switch_mixer_controls =
+ SOC_SINGLE_EXT("Switch", SND_SOC_NOPM,
+ 0, 1, 0, msm_routing_get_switch_mixer,
+ msm_routing_put_switch_mixer);
+
static const struct soc_enum lsm_mux_enum =
SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(mad_audio_mux_text), mad_audio_mux_text);
@@ -3192,6 +3197,9 @@
SND_SOC_DAPM_AIF_OUT("PRI_MI2S_UL_HL",
"Primary MI2S_TX Hostless Capture",
0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("PRI_MI2S_DL_HL",
+ "Primary MI2S_RX Hostless Playback",
+ 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MI2S_DL_HL", "MI2S_RX_HOSTLESS Playback",
0, 0, 0, 0),
@@ -3298,6 +3306,8 @@
&fm_switch_mixer_controls),
SND_SOC_DAPM_SWITCH("PCM_RX_DL_HL", SND_SOC_NOPM, 0, 0,
&pcm_rx_switch_mixer_controls),
+ SND_SOC_DAPM_SWITCH("PRI_MI2S_RX_DL_HL", SND_SOC_NOPM, 0, 0,
+ &pri_mi2s_rx_switch_mixer_controls),
/* Mux Definitions */
SND_SOC_DAPM_MUX("LSM1 MUX", SND_SOC_NOPM, 0, 0, &lsm1_mux),
@@ -3914,6 +3924,8 @@
{"MI2S_UL_HL", NULL, "MI2S_TX"},
{"PCM_RX_DL_HL", "Switch", "SLIM0_DL_HL"},
{"PCM_RX", NULL, "PCM_RX_DL_HL"},
+ {"PRI_MI2S_RX_DL_HL", "Switch", "PRI_MI2S_DL_HL"},
+ {"PRI_MI2S_RX", NULL, "PRI_MI2S_RX_DL_HL"},
{"MI2S_UL_HL", NULL, "TERT_MI2S_TX"},
{"SEC_I2S_RX", NULL, "SEC_I2S_DL_HL"},
{"PRI_MI2S_UL_HL", NULL, "PRI_MI2S_TX"},