Merge "radio-iris: Configure repeat count for PS string"
diff --git a/Documentation/devicetree/bindings/pil/pil-pronto.txt b/Documentation/devicetree/bindings/pil/pil-pronto.txt
index 199862f..85ccc5d 100644
--- a/Documentation/devicetree/bindings/pil/pil-pronto.txt
+++ b/Documentation/devicetree/bindings/pil/pil-pronto.txt
@@ -14,6 +14,7 @@
- vdd_pronto_pll-supply: regulator to supply pronto pll.
- qcom,firmware-name: Base name of the firmware image. Ex. "wcnss"
- qcom,gpio-err-fatal: GPIO used by the wcnss to indicate error fatal to the Apps.
+- qcom,gpio-err-ready: GPIO used by the wcnss to indicate error ready to the Apps.
- qcom,gpio-proxy-unvote: GPIO used by the wcnss to trigger proxy unvoting in
the Apps
- qcom,gpio-force-stop: GPIO used by the Apps to force the wcnss to shutdown.
@@ -32,6 +33,7 @@
/* GPIO input from wcnss */
qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_4_in 0 0>;
+ qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_4_in 1 0>;
qcom,proxy-unvote = <&smp2pgpio_ssr_smp2p_4_in 2 0>;
/* GPIO output to wcnss */
diff --git a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
index 2d20794..c3d929c 100644
--- a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
+++ b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
@@ -17,6 +17,7 @@
- vdd_mx-supply: Reference to the regulator that supplies the memory rail.
- qcom,firmware-name: Base name of the firmware image. Ex. "mdsp"
- qcom,gpio-err-fatal: GPIO used by the modem to indicate error fatal to the apps.
+- qcom,gpio-err-ready: GPIO used by the modem to indicate error ready to the apps.
- qcom,gpio-proxy-unvote: GPIO used by the modem to trigger proxy unvoting in
the apps.
- qcom,gpio-force-stop: GPIO used by the apps to force the modem to shutdown.
@@ -49,6 +50,7 @@
/* GPIO inputs from mss */
qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_1_in 0 0>;
+ qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_1_in 1 0>;
qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_1_in 2 0>;
/* GPIO output to mss */
diff --git a/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt b/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt
index eb62ea1..f2cfe34 100644
--- a/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt
@@ -11,9 +11,10 @@
Optional properties:
- parent-supply: phandle to the parent supply/regulator node
- - qcom,retain-mems: For Oxili GDSCs only: Presence currently denotes a hardware
- requirement to assert the forced memory retention signals
- in the core's clock branch control register.
+ - qcom,clock-names: List of string names for core clocks
+ - qcom,retain-mems: Presence denotes a hardware requirement to leave the
+ forced memory retention signals in the core's clock
+ branch control register asserted.
Example:
gdsc_oxili_gx: qcom,gdsc@fd8c4024 {
@@ -21,4 +22,5 @@
regulator-name = "gdsc_oxili_gx";
parent-supply = <&pm8841_s4>;
reg = <0xfd8c4024 0x4>;
+ qcom,clock-names = "core_clk";
};
diff --git a/arch/arm/boot/dts/apq8084-sim.dts b/arch/arm/boot/dts/apq8084-sim.dts
index 93803dbe..ebcca1b 100644
--- a/arch/arm/boot/dts/apq8084-sim.dts
+++ b/arch/arm/boot/dts/apq8084-sim.dts
@@ -165,3 +165,7 @@
mpp@a700 { /* MPP 8 */
};
};
+
+&usb3 {
+ qcom,skip-charger-detection;
+};
diff --git a/arch/arm/boot/dts/apq8084.dtsi b/arch/arm/boot/dts/apq8084.dtsi
index bc6f030..95b1c8f 100644
--- a/arch/arm/boot/dts/apq8084.dtsi
+++ b/arch/arm/boot/dts/apq8084.dtsi
@@ -126,6 +126,37 @@
interrupt-controller;
#interrupt-cells = <3>;
};
+
+ usb3: qcom,ssusb@f9200000 {
+ compatible = "qcom,dwc-usb3-msm";
+ reg = <0xf9200000 0xfc000>,
+ <0xfd4ab000 0x4>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+ interrupts = <0 133 0>;
+ interrupt-names = "hs_phy_irq";
+ ssusb_vdd_dig-supply = <&pma8084_s1>;
+ SSUSB_1p8-supply = <&pma8084_l6>;
+ hsusb_vdd_dig-supply = <&pma8084_s1>;
+ HSUSB_1p8-supply = <&pma8084_l6>;
+ HSUSB_3p3-supply = <&pma8084_l24>;
+ qcom,dwc-usb3-msm-dbm-eps = <4>;
+ qcom,vdd-voltage-level = <0 900000 1050000>;
+
+ dwc3@f9200000 {
+ compatible = "synopsys,dwc3";
+ reg = <0xf9200000 0xfc000>;
+ interrupt-parent = <&intc>;
+ interrupts = <0 131 0>, <0 179 0>;
+ interrupt-names = "irq", "otg_irq";
+ tx-fifo-resize;
+ };
+ };
+
+ android_usb {
+ compatible = "qcom,android-usb";
+ };
};
/include/ "msm-pma8084.dtsi"
diff --git a/arch/arm/boot/dts/dsi-panel-nt35590-720p-cmd.dtsi b/arch/arm/boot/dts/dsi-panel-nt35590-720p-cmd.dtsi
new file mode 100644
index 0000000..7942567
--- /dev/null
+++ b/arch/arm/boot/dts/dsi-panel-nt35590-720p-cmd.dtsi
@@ -0,0 +1,530 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/ {
+ qcom,mdss_dsi_nt35590_720p_cmd {
+ compatible = "qcom,mdss-dsi-panel";
+ label = "nt35590 720p command mode dsi panel";
+ status = "disable";
+ qcom,dsi-ctrl-phandle = <&mdss_dsi0>;
+ qcom,rst-gpio = <&msmgpio 25 0>;
+ qcom,te-gpio = <&msmgpio 24 0>;
+ qcom,mdss-pan-res = <720 1280>;
+ qcom,mdss-pan-bpp = <24>;
+ qcom,mdss-pan-dest = "display_1";
+ qcom,mdss-pan-porch-values = <164 8 140 1 1 6>;
+ qcom,mdss-pan-underflow-clr = <0xff>;
+ qcom,mdss-pan-bl-ctrl = "bl_ctrl_wled";
+ qcom,mdss-pan-bl-levels = <1 4095>;
+ qcom,mdss-pan-dsi-mode = <1>;
+ qcom,mdss-vsync-enable = <1>;
+ qcom,mdss-hw-vsync-mode = <1>;
+ qcom,mdss-pan-dsi-h-pulse-mode = <1>;
+ qcom,mdss-pan-dsi-h-power-stop = <0 0 0>;
+ qcom,mdss-pan-dsi-bllp-power-stop = <1 1>;
+ qcom,mdss-pan-dsi-traffic-mode = <2>;
+ qcom,mdss-pan-dsi-dst-format = <8>;
+ qcom,mdss-pan-insert-dcs-cmd = <1>;
+ qcom,mdss-pan-wr-mem-continue = <0x3c>;
+ qcom,mdss-pan-wr-mem-start = <0x2c>;
+ qcom,mdss-pan-te-sel = <1>;
+ qcom,mdss-pan-dsi-vc = <0>;
+ qcom,mdss-pan-dsi-rgb-swap = <0>;
+ qcom,mdss-pan-dsi-data-lanes = <1 1 1 1>; /* 4 lanes */
+ qcom,mdss-pan-dsi-dlane-swap = <0>;
+ qcom,mdss-pan-dsi-t-clk = <0x2c 0x20>;
+ qcom,mdss-pan-dsi-stream = <0>;
+ qcom,mdss-pan-dsi-mdp-tr = <0x0>;
+ qcom,mdss-pan-dsi-dma-tr = <0x04>;
+ qcom,mdss-pan-dsi-frame-rate = <60>;
+ qcom,panel-phy-regulatorSettings = [07 09 03 00 /* Regualotor settings */
+ 20 00 01];
+ qcom,panel-phy-timingSettings = [7d 25 1d 00 37 33
+ 22 27 1e 03 04 00];
+ qcom,panel-phy-strengthCtrl = [ff 06];
+ qcom,panel-phy-bistCtrl = [00 00 b1 ff /* BIST Ctrl settings */
+ 00 00];
+ qcom,panel-phy-laneConfig = [00 00 00 00 00 00 00 01 97 /* lane0 config */
+ 00 00 00 00 05 00 00 01 97 /* lane1 config */
+ 00 00 00 00 0a 00 00 01 97 /* lane2 config */
+ 00 00 00 00 0f 00 00 01 97 /* lane3 config */
+ 00 c0 00 00 00 00 00 01 bb]; /* Clk ln config */
+ qcom,panel-on-cmds = [29 01 00 00 00 02 FF EE
+ 29 01 00 00 00 02 26 08
+ 29 01 00 00 00 02 26 00
+ 29 01 00 00 10 02 FF 00
+ 29 01 00 00 00 02 BA 03
+ 29 01 00 00 00 02 C2 08
+ 29 01 00 00 00 02 FF 01
+ 29 01 00 00 00 02 FB 01
+ 29 01 00 00 00 02 00 4A
+ 29 01 00 00 00 02 01 33
+ 29 01 00 00 00 02 02 53
+ 29 01 00 00 00 02 03 55
+ 29 01 00 00 00 02 04 55
+ 29 01 00 00 00 02 05 33
+ 29 01 00 00 00 02 06 22
+ 29 01 00 00 00 02 08 56
+ 29 01 00 00 00 02 09 8F
+ 29 01 00 00 00 02 36 73
+ 29 01 00 00 00 02 0B 9F
+ 29 01 00 00 00 02 0C 9F
+ 29 01 00 00 00 02 0D 2F
+ 29 01 00 00 00 02 0E 24
+ 29 01 00 00 00 02 11 83
+ 29 01 00 00 00 02 12 03
+ 29 01 00 00 00 02 71 2C
+ 29 01 00 00 00 02 6F 03
+ 29 01 00 00 00 02 0F 0A
+ 29 01 00 00 00 02 FF 05
+ 29 01 00 00 00 02 FB 01
+ 29 01 00 00 00 02 01 00
+ 29 01 00 00 00 02 02 8B
+ 29 01 00 00 00 02 03 82
+ 29 01 00 00 00 02 04 82
+ 29 01 00 00 00 02 05 30
+ 29 01 00 00 00 02 06 33
+ 29 01 00 00 00 02 07 01
+ 29 01 00 00 00 02 08 00
+ 29 01 00 00 00 02 09 46
+ 29 01 00 00 00 02 0A 46
+ 29 01 00 00 00 02 0D 0B
+ 29 01 00 00 00 02 0E 1D
+ 29 01 00 00 00 02 0F 08
+ 29 01 00 00 00 02 10 53
+ 29 01 00 00 00 02 11 00
+ 29 01 00 00 00 02 12 00
+ 29 01 00 00 00 02 14 01
+ 29 01 00 00 00 02 15 00
+ 29 01 00 00 00 02 16 05
+ 29 01 00 00 00 02 17 00
+ 29 01 00 00 00 02 19 7F
+ 29 01 00 00 00 02 1A FF
+ 29 01 00 00 00 02 1B 0F
+ 29 01 00 00 00 02 1C 00
+ 29 01 00 00 00 02 1D 00
+ 29 01 00 00 00 02 1E 00
+ 29 01 00 00 00 02 1F 07
+ 29 01 00 00 00 02 20 00
+ 29 01 00 00 00 02 21 06
+ 29 01 00 00 00 02 22 55
+ 29 01 00 00 00 02 23 4D
+ 29 01 00 00 00 02 2D 02
+ 29 01 00 00 00 02 28 01
+ 29 01 00 00 00 02 2F 02
+ 29 01 00 00 00 02 83 01
+ 29 01 00 00 00 02 9E 58
+ 29 01 00 00 00 02 9F 6A
+ 29 01 00 00 00 02 A0 01
+ 29 01 00 00 00 02 A2 10
+ 29 01 00 00 00 02 BB 0A
+ 29 01 00 00 00 02 BC 0A
+ 29 01 00 00 00 02 32 08
+ 29 01 00 00 00 02 33 B8
+ 29 01 00 00 00 02 36 01
+ 29 01 00 00 00 02 37 00
+ 29 01 00 00 00 02 43 00
+ 29 01 00 00 00 02 4B 21
+ 29 01 00 00 00 02 4C 03
+ 29 01 00 00 00 02 50 21
+ 29 01 00 00 00 02 51 03
+ 29 01 00 00 00 02 58 21
+ 29 01 00 00 00 02 59 03
+ 29 01 00 00 00 02 5D 21
+ 29 01 00 00 00 02 5E 03
+ 29 01 00 00 00 02 6C 00
+ 29 01 00 00 00 02 6D 00
+ 29 01 00 00 00 02 FB 01
+ 29 01 00 00 00 02 FF 01
+ 29 01 00 00 00 02 FB 01
+ 29 01 00 00 00 02 75 00
+ 29 01 00 00 00 02 76 7D
+ 29 01 00 00 00 02 77 00
+ 29 01 00 00 00 02 78 8A
+ 29 01 00 00 00 02 79 00
+ 29 01 00 00 00 02 7A 9C
+ 29 01 00 00 00 02 7B 00
+ 29 01 00 00 00 02 7C B1
+ 29 01 00 00 00 02 7D 00
+ 29 01 00 00 00 02 7E BF
+ 29 01 00 00 00 02 7F 00
+ 29 01 00 00 00 02 80 CF
+ 29 01 00 00 00 02 81 00
+ 29 01 00 00 00 02 82 DD
+ 29 01 00 00 00 02 83 00
+ 29 01 00 00 00 02 84 E8
+ 29 01 00 00 00 02 85 00
+ 29 01 00 00 00 02 86 F2
+ 29 01 00 00 00 02 87 01
+ 29 01 00 00 00 02 88 1F
+ 29 01 00 00 00 02 89 01
+ 29 01 00 00 00 02 8A 41
+ 29 01 00 00 00 02 8B 01
+ 29 01 00 00 00 02 8C 78
+ 29 01 00 00 00 02 8D 01
+ 29 01 00 00 00 02 8E A5
+ 29 01 00 00 00 02 8F 01
+ 29 01 00 00 00 02 90 EE
+ 29 01 00 00 00 02 91 02
+ 29 01 00 00 00 02 92 29
+ 29 01 00 00 00 02 93 02
+ 29 01 00 00 00 02 94 2A
+ 29 01 00 00 00 02 95 02
+ 29 01 00 00 00 02 96 5D
+ 29 01 00 00 00 02 97 02
+ 29 01 00 00 00 02 98 93
+ 29 01 00 00 00 02 99 02
+ 29 01 00 00 00 02 9A B8
+ 29 01 00 00 00 02 9B 02
+ 29 01 00 00 00 02 9C E7
+ 29 01 00 00 00 02 9D 03
+ 29 01 00 00 00 02 9E 07
+ 29 01 00 00 00 02 9F 03
+ 29 01 00 00 00 02 A0 37
+ 29 01 00 00 00 02 A2 03
+ 29 01 00 00 00 02 A3 46
+ 29 01 00 00 00 02 A4 03
+ 29 01 00 00 00 02 A5 56
+ 29 01 00 00 00 02 A6 03
+ 29 01 00 00 00 02 A7 66
+ 29 01 00 00 00 02 A9 03
+ 29 01 00 00 00 02 AA 7A
+ 29 01 00 00 00 02 AB 03
+ 29 01 00 00 00 02 AC 93
+ 29 01 00 00 00 02 AD 03
+ 29 01 00 00 00 02 AE A3
+ 29 01 00 00 00 02 AF 03
+ 29 01 00 00 00 02 B0 B4
+ 29 01 00 00 00 02 B1 03
+ 29 01 00 00 00 02 B2 CB
+ 29 01 00 00 00 02 B3 00
+ 29 01 00 00 00 02 B4 7D
+ 29 01 00 00 00 02 B5 00
+ 29 01 00 00 00 02 B6 8A
+ 29 01 00 00 00 02 B7 00
+ 29 01 00 00 00 02 B8 9C
+ 29 01 00 00 00 02 B9 00
+ 29 01 00 00 00 02 BA B1
+ 29 01 00 00 00 02 BB 00
+ 29 01 00 00 00 02 BC BF
+ 29 01 00 00 00 02 BD 00
+ 29 01 00 00 00 02 BE CF
+ 29 01 00 00 00 02 BF 00
+ 29 01 00 00 00 02 C0 DD
+ 29 01 00 00 00 02 C1 00
+ 29 01 00 00 00 02 C2 E8
+ 29 01 00 00 00 02 C3 00
+ 29 01 00 00 00 02 C4 F2
+ 29 01 00 00 00 02 C5 01
+ 29 01 00 00 00 02 C6 1F
+ 29 01 00 00 00 02 C7 01
+ 29 01 00 00 00 02 C8 41
+ 29 01 00 00 00 02 C9 01
+ 29 01 00 00 00 02 CA 78
+ 29 01 00 00 00 02 CB 01
+ 29 01 00 00 00 02 CC A5
+ 29 01 00 00 00 02 CD 01
+ 29 01 00 00 00 02 CE EE
+ 29 01 00 00 00 02 CF 02
+ 29 01 00 00 00 02 D0 29
+ 29 01 00 00 00 02 D1 02
+ 29 01 00 00 00 02 D2 2A
+ 29 01 00 00 00 02 D3 02
+ 29 01 00 00 00 02 D4 5D
+ 29 01 00 00 00 02 D5 02
+ 29 01 00 00 00 02 D6 93
+ 29 01 00 00 00 02 D7 02
+ 29 01 00 00 00 02 D8 B8
+ 29 01 00 00 00 02 D9 02
+ 29 01 00 00 00 02 DA E7
+ 29 01 00 00 00 02 DB 03
+ 29 01 00 00 00 02 DC 07
+ 29 01 00 00 00 02 DD 03
+ 29 01 00 00 00 02 DE 37
+ 29 01 00 00 00 02 DF 03
+ 29 01 00 00 00 02 E0 46
+ 29 01 00 00 00 02 E1 03
+ 29 01 00 00 00 02 E2 56
+ 29 01 00 00 00 02 E3 03
+ 29 01 00 00 00 02 E4 66
+ 29 01 00 00 00 02 E5 03
+ 29 01 00 00 00 02 E6 7A
+ 29 01 00 00 00 02 E7 03
+ 29 01 00 00 00 02 E8 93
+ 29 01 00 00 00 02 E9 03
+ 29 01 00 00 00 02 EA A3
+ 29 01 00 00 00 02 EB 03
+ 29 01 00 00 00 02 EC B4
+ 29 01 00 00 00 02 ED 03
+ 29 01 00 00 00 02 EE CB
+ 29 01 00 00 00 02 EF 00
+ 29 01 00 00 00 02 F0 ED
+ 29 01 00 00 00 02 F1 00
+ 29 01 00 00 00 02 F2 F3
+ 29 01 00 00 00 02 F3 00
+ 29 01 00 00 00 02 F4 FE
+ 29 01 00 00 00 02 F5 01
+ 29 01 00 00 00 02 F6 09
+ 29 01 00 00 00 02 F7 01
+ 29 01 00 00 00 02 F8 13
+ 29 01 00 00 00 02 F9 01
+ 29 01 00 00 00 02 FA 1D
+ 29 01 00 00 00 02 FF 02
+ 29 01 00 00 00 02 FB 01
+ 29 01 00 00 00 02 00 01
+ 29 01 00 00 00 02 01 26
+ 29 01 00 00 00 02 02 01
+ 29 01 00 00 00 02 03 2F
+ 29 01 00 00 00 02 04 01
+ 29 01 00 00 00 02 05 37
+ 29 01 00 00 00 02 06 01
+ 29 01 00 00 00 02 07 56
+ 29 01 00 00 00 02 08 01
+ 29 01 00 00 00 02 09 70
+ 29 01 00 00 00 02 0A 01
+ 29 01 00 00 00 02 0B 9D
+ 29 01 00 00 00 02 0C 01
+ 29 01 00 00 00 02 0D C2
+ 29 01 00 00 00 02 0E 01
+ 29 01 00 00 00 02 0F FF
+ 29 01 00 00 00 02 10 02
+ 29 01 00 00 00 02 11 31
+ 29 01 00 00 00 02 12 02
+ 29 01 00 00 00 02 13 32
+ 29 01 00 00 00 02 14 02
+ 29 01 00 00 00 02 15 60
+ 29 01 00 00 00 02 16 02
+ 29 01 00 00 00 02 17 94
+ 29 01 00 00 00 02 18 02
+ 29 01 00 00 00 02 19 B5
+ 29 01 00 00 00 02 1A 02
+ 29 01 00 00 00 02 1B E3
+ 29 01 00 00 00 02 1C 03
+ 29 01 00 00 00 02 1D 03
+ 29 01 00 00 00 02 1E 03
+ 29 01 00 00 00 02 1F 2D
+ 29 01 00 00 00 02 20 03
+ 29 01 00 00 00 02 21 3A
+ 29 01 00 00 00 02 22 03
+ 29 01 00 00 00 02 23 48
+ 29 01 00 00 00 02 24 03
+ 29 01 00 00 00 02 25 57
+ 29 01 00 00 00 02 26 03
+ 29 01 00 00 00 02 27 68
+ 29 01 00 00 00 02 28 03
+ 29 01 00 00 00 02 29 7B
+ 29 01 00 00 00 02 2A 03
+ 29 01 00 00 00 02 2B 90
+ 29 01 00 00 00 02 2D 03
+ 29 01 00 00 00 02 2F A0
+ 29 01 00 00 00 02 30 03
+ 29 01 00 00 00 02 31 CB
+ 29 01 00 00 00 02 32 00
+ 29 01 00 00 00 02 33 ED
+ 29 01 00 00 00 02 34 00
+ 29 01 00 00 00 02 35 F3
+ 29 01 00 00 00 02 36 00
+ 29 01 00 00 00 02 37 FE
+ 29 01 00 00 00 02 38 01
+ 29 01 00 00 00 02 39 09
+ 29 01 00 00 00 02 3A 01
+ 29 01 00 00 00 02 3B 13
+ 29 01 00 00 00 02 3D 01
+ 29 01 00 00 00 02 3F 1D
+ 29 01 00 00 00 02 40 01
+ 29 01 00 00 00 02 41 26
+ 29 01 00 00 00 02 42 01
+ 29 01 00 00 00 02 43 2F
+ 29 01 00 00 00 02 44 01
+ 29 01 00 00 00 02 45 37
+ 29 01 00 00 00 02 46 01
+ 29 01 00 00 00 02 47 56
+ 29 01 00 00 00 02 48 01
+ 29 01 00 00 00 02 49 70
+ 29 01 00 00 00 02 4A 01
+ 29 01 00 00 00 02 4B 9D
+ 29 01 00 00 00 02 4C 01
+ 29 01 00 00 00 02 4D C2
+ 29 01 00 00 00 02 4E 01
+ 29 01 00 00 00 02 4F FF
+ 29 01 00 00 00 02 50 02
+ 29 01 00 00 00 02 51 31
+ 29 01 00 00 00 02 52 02
+ 29 01 00 00 00 02 53 32
+ 29 01 00 00 00 02 54 02
+ 29 01 00 00 00 02 55 60
+ 29 01 00 00 00 02 56 02
+ 29 01 00 00 00 02 58 94
+ 29 01 00 00 00 02 59 02
+ 29 01 00 00 00 02 5A B5
+ 29 01 00 00 00 02 5B 02
+ 29 01 00 00 00 02 5C E3
+ 29 01 00 00 00 02 5D 03
+ 29 01 00 00 00 02 5E 03
+ 29 01 00 00 00 02 5F 03
+ 29 01 00 00 00 02 60 2D
+ 29 01 00 00 00 02 61 03
+ 29 01 00 00 00 02 62 3A
+ 29 01 00 00 00 02 63 03
+ 29 01 00 00 00 02 64 48
+ 29 01 00 00 00 02 65 03
+ 29 01 00 00 00 02 66 57
+ 29 01 00 00 00 02 67 03
+ 29 01 00 00 00 02 68 68
+ 29 01 00 00 00 02 69 03
+ 29 01 00 00 00 02 6A 7B
+ 29 01 00 00 00 02 6B 03
+ 29 01 00 00 00 02 6C 90
+ 29 01 00 00 00 02 6D 03
+ 29 01 00 00 00 02 6E A0
+ 29 01 00 00 00 02 6F 03
+ 29 01 00 00 00 02 70 CB
+ 29 01 00 00 00 02 71 00
+ 29 01 00 00 00 02 72 19
+ 29 01 00 00 00 02 73 00
+ 29 01 00 00 00 02 74 36
+ 29 01 00 00 00 02 75 00
+ 29 01 00 00 00 02 76 55
+ 29 01 00 00 00 02 77 00
+ 29 01 00 00 00 02 78 70
+ 29 01 00 00 00 02 79 00
+ 29 01 00 00 00 02 7A 83
+ 29 01 00 00 00 02 7B 00
+ 29 01 00 00 00 02 7C 99
+ 29 01 00 00 00 02 7D 00
+ 29 01 00 00 00 02 7E A8
+ 29 01 00 00 00 02 7F 00
+ 29 01 00 00 00 02 80 B7
+ 29 01 00 00 00 02 81 00
+ 29 01 00 00 00 02 82 C5
+ 29 01 00 00 00 02 83 00
+ 29 01 00 00 00 02 84 F7
+ 29 01 00 00 00 02 85 01
+ 29 01 00 00 00 02 86 1E
+ 29 01 00 00 00 02 87 01
+ 29 01 00 00 00 02 88 60
+ 29 01 00 00 00 02 89 01
+ 29 01 00 00 00 02 8A 95
+ 29 01 00 00 00 02 8B 01
+ 29 01 00 00 00 02 8C E1
+ 29 01 00 00 00 02 8D 02
+ 29 01 00 00 00 02 8E 20
+ 29 01 00 00 00 02 8F 02
+ 29 01 00 00 00 02 90 23
+ 29 01 00 00 00 02 91 02
+ 29 01 00 00 00 02 92 59
+ 29 01 00 00 00 02 93 02
+ 29 01 00 00 00 02 94 94
+ 29 01 00 00 00 02 95 02
+ 29 01 00 00 00 02 96 B4
+ 29 01 00 00 00 02 97 02
+ 29 01 00 00 00 02 98 E1
+ 29 01 00 00 00 02 99 03
+ 29 01 00 00 00 02 9A 01
+ 29 01 00 00 00 02 9B 03
+ 29 01 00 00 00 02 9C 28
+ 29 01 00 00 00 02 9D 03
+ 29 01 00 00 00 02 9E 30
+ 29 01 00 00 00 02 9F 03
+ 29 01 00 00 00 02 A0 37
+ 29 01 00 00 00 02 A2 03
+ 29 01 00 00 00 02 A3 3B
+ 29 01 00 00 00 02 A4 03
+ 29 01 00 00 00 02 A5 40
+ 29 01 00 00 00 02 A6 03
+ 29 01 00 00 00 02 A7 50
+ 29 01 00 00 00 02 A9 03
+ 29 01 00 00 00 02 AA 6D
+ 29 01 00 00 00 02 AB 03
+ 29 01 00 00 00 02 AC 80
+ 29 01 00 00 00 02 AD 03
+ 29 01 00 00 00 02 AE CB
+ 29 01 00 00 00 02 AF 00
+ 29 01 00 00 00 02 B0 19
+ 29 01 00 00 00 02 B1 00
+ 29 01 00 00 00 02 B2 36
+ 29 01 00 00 00 02 B3 00
+ 29 01 00 00 00 02 B4 55
+ 29 01 00 00 00 02 B5 00
+ 29 01 00 00 00 02 B6 70
+ 29 01 00 00 00 02 B7 00
+ 29 01 00 00 00 02 B8 83
+ 29 01 00 00 00 02 B9 00
+ 29 01 00 00 00 02 BA 99
+ 29 01 00 00 00 02 BB 00
+ 29 01 00 00 00 02 BC A8
+ 29 01 00 00 00 02 BD 00
+ 29 01 00 00 00 02 BE B7
+ 29 01 00 00 00 02 BF 00
+ 29 01 00 00 00 02 C0 C5
+ 29 01 00 00 00 02 C1 00
+ 29 01 00 00 00 02 C2 F7
+ 29 01 00 00 00 02 C3 01
+ 29 01 00 00 00 02 C4 1E
+ 29 01 00 00 00 02 C5 01
+ 29 01 00 00 00 02 C6 60
+ 29 01 00 00 00 02 C7 01
+ 29 01 00 00 00 02 C8 95
+ 29 01 00 00 00 02 C9 01
+ 29 01 00 00 00 02 CA E1
+ 29 01 00 00 00 02 CB 02
+ 29 01 00 00 00 02 CC 20
+ 29 01 00 00 00 02 CD 02
+ 29 01 00 00 00 02 CE 23
+ 29 01 00 00 00 02 CF 02
+ 29 01 00 00 00 02 D0 59
+ 29 01 00 00 00 02 D1 02
+ 29 01 00 00 00 02 D2 94
+ 29 01 00 00 00 02 D3 02
+ 29 01 00 00 00 02 D4 B4
+ 29 01 00 00 00 02 D5 02
+ 29 01 00 00 00 02 D6 E1
+ 29 01 00 00 00 02 D7 03
+ 29 01 00 00 00 02 D8 01
+ 29 01 00 00 00 02 D9 03
+ 29 01 00 00 00 02 DA 28
+ 29 01 00 00 00 02 DB 03
+ 29 01 00 00 00 02 DC 30
+ 29 01 00 00 00 02 DD 03
+ 29 01 00 00 00 02 DE 37
+ 29 01 00 00 00 02 DF 03
+ 29 01 00 00 00 02 E0 3B
+ 29 01 00 00 00 02 E1 03
+ 29 01 00 00 00 02 E2 40
+ 29 01 00 00 00 02 E3 03
+ 29 01 00 00 00 02 E4 50
+ 29 01 00 00 00 02 E5 03
+ 29 01 00 00 00 02 E6 6D
+ 29 01 00 00 00 02 E7 03
+ 29 01 00 00 00 02 E8 80
+ 29 01 00 00 00 02 E9 03
+ 29 01 00 00 00 02 EA CB
+ 29 01 00 00 00 02 FF 01
+ 29 01 00 00 00 02 FB 01
+ 29 01 00 00 00 02 FF 02
+ 29 01 00 00 00 02 FB 01
+ 29 01 00 00 00 02 FF 04
+ 29 01 00 00 00 02 FB 01
+ 29 01 00 00 00 02 FF 00
+ 29 01 00 00 64 02 11 00
+ 29 01 00 00 00 02 FF EE
+ 29 01 00 00 00 02 12 50
+ 29 01 00 00 00 02 13 02
+ 29 01 00 00 00 02 6A 60
+ 29 01 00 00 00 02 FF 00
+ 29 01 00 00 78 02 29 00];
+ qcom,on-cmds-dsi-state = "DSI_LP_MODE";
+ qcom,panel-off-cmds = [05 01 00 00 32 02 28 00
+ 05 01 00 00 78 02 10 00];
+ qcom,off-cmds-dsi-state = "DSI_HS_MODE";
+ };
+};
diff --git a/arch/arm/boot/dts/dsi-v2-panel-truly-wvga-video.dtsi b/arch/arm/boot/dts/dsi-v2-panel-truly-wvga-video.dtsi
new file mode 100644
index 0000000..a3718aa
--- /dev/null
+++ b/arch/arm/boot/dts/dsi-v2-panel-truly-wvga-video.dtsi
@@ -0,0 +1,120 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/ {
+ qcom,dsi_v2_truly_wvga_video {
+ compatible = "qcom,dsi-panel-v2";
+ label = "Truly WVGA video mode dsi panel";
+ qcom,dsi-ctrl-phandle = <&mdss_dsi0>;
+ qcom,rst-gpio = <&msmgpio 41 0>;
+ qcom,mode-selection-gpio = <&msmgpio 7 0>;
+ vdda-supply = <&pm8110_l19>;
+ vddio-supply=<&pm8110_l14>;
+ qcom,mdss-pan-res = <480 800>;
+ qcom,mdss-pan-bpp = <24>;
+ qcom,mdss-pan-dest = "display_1";
+ qcom,mdss-pan-porch-values = <40 8 160 10 2 12>;
+ qcom,mdss-pan-underflow-clr = <0xff>;
+ qcom,mdss-pan-bl-levels = <1 255>;
+ qcom,mdss-pan-bl-ctrl = "bl_ctrl_wled";
+ qcom,mdss-pan-dsi-mode = <0>;
+ qcom,mdss-pan-dsi-h-pulse-mode = <0>;
+ qcom,mdss-pan-dsi-h-power-stop = <0 0 0>;
+ qcom,mdss-pan-dsi-bllp-power-stop = <1 1>;
+ qcom,mdss-pan-dsi-traffic-mode = <1>;
+ qcom,mdss-pan-dsi-dst-format = <3>;
+ qcom,mdss-pan-dsi-vc = <0>;
+ qcom,mdss-pan-dsi-rgb-swap = <0>;
+ qcom,mdss-pan-dsi-data-lanes = <1 1 0 0>;
+ qcom,mdss-pan-dsi-dlane-swap = <0>;
+ qcom,mdss-pan-dsi-t-clk = <0x1b 0x04>;
+ qcom,mdss-pan-dsi-stream = <0>;
+ qcom,mdss-pan-dsi-mdp-tr = <0x0>;/*todo*/
+ qcom,mdss-pan-dsi-dma-tr = <0x04>;
+ qcom,mdss-pan-dsi-frame-rate = <60>;
+ qcom,panel-phy-regulatorSettings =[09 08 05 00 20 03];
+ qcom,panel-phy-timingSettings = [5D 12 0C 00 33 38
+ 10 16 1E 03 04 00];
+ qcom,panel-phy-strengthCtrl = [ff 06];
+ qcom,panel-phy-bistCtrl = [03 03 00 00 0f 00];
+ qcom,panel-phy-laneConfig =
+ [80 45 00 00 01 66 /*lane0**/
+ 80 45 00 00 01 66 /*lane1*/
+ 80 45 00 00 01 66 /*lane2*/
+ 80 45 00 00 01 66 /*lane3*/
+ 40 67 00 00 01 88]; /*Clk*/
+
+ qcom,on-cmds-dsi-state = "DSI_LP_MODE";
+ qcom,panel-on-cmds = [
+ 05 01 00 00 01 02
+ 01 00
+ 23 01 00 00 01 02
+ b0 04
+ 29 01 00 00 01 03
+ b3 02 00
+ 23 01 00 00 01 02
+ bd 00
+ 29 01 00 00 01 03
+ c0 18 66
+ 29 01 00 00 01 10
+ c1 23 31 99 21 20 00 30 28 0c 0c
+ 00 00 00 21 01
+ 29 01 00 00 01 07
+ c2 10 06 06 01 03 00
+ 29 01 00 00 01 19
+ c8 04 10 18 20 2e 46 3c 28 1f 18
+ 10 04 04 10 18 20 2e 46 3c 28 1f 18 10 04
+ 29 01 00 00 01 19
+ c9 04 10 18 20 2e 46 3c 28 1f 18
+ 10 04 04 10 18 20 2e 46 3c 28 1f 18 10 04
+ 29 01 00 00 01 19
+ ca 04 10 18 20 2e 46 3c 28 1f 18
+ 10 04 04 10 18 20 2e 46 3c 28 1f 18 10 04
+ 29 01 00 00 01 11
+ d0 29 03 ce a6 00 43 20 10 01 00
+ 01 01 00 03 01 00
+ 29 01 00 00 01 08
+ d1 18 0C 23 03 75 02 50
+ 23 01 00 00 01 02
+ d3 11
+ 29 01 00 00 01 03
+ d5 2a 2a
+ 29 01 00 00 01 03
+ de 01 41
+ 23 01 00 00 01 02
+ e6 51
+ 23 01 00 00 01 02
+ fa 03
+ 23 01 00 00 64 02
+ d6 28
+ 39 01 00 00 01 05
+ 2a 00 00 01 df
+ 39 01 00 00 01 05
+ 2b 00 00 03 1f
+ 15 01 00 00 01 02
+ 35 00
+ 39 01 00 00 01 03
+ 44 00 50
+ 15 01 00 00 01 02
+ 36 c1
+ 15 01 00 00 01 02
+ 3a 77
+ 05 01 00 00 96 02
+ 11 00
+ 05 01 00 00 64 02
+ 29 00
+ ];
+ qcom,panel-off-cmds = [05 01 00 00 32 02 28 00
+ 05 01 00 00 78 02 10 00];
+ qcom,off-cmds-dsi-state = "DSI_LP_MODE";
+ };
+};
diff --git a/arch/arm/boot/dts/msm-pm8110.dtsi b/arch/arm/boot/dts/msm-pm8110.dtsi
index 79760c1..391c564 100644
--- a/arch/arm/boot/dts/msm-pm8110.dtsi
+++ b/arch/arm/boot/dts/msm-pm8110.dtsi
@@ -260,6 +260,12 @@
};
};
+ qcom,leds@a100 {
+ compatible = "qcom,leds-qpnp";
+ reg = <0xa100 0x100>;
+ label = "mpp";
+ };
+
qcom,leds@a200 {
compatible = "qcom,leds-qpnp";
reg = <0xa200 0x100>;
@@ -492,5 +498,12 @@
reg = <0x5500 0x100>;
status = "disabled";
};
+
+ qcom,vibrator@c000 {
+ compatible = "qcom,qpnp-vibrator";
+ reg = <0xc000 0x100>;
+ label = "vibrator";
+ status = "disabled";
+ };
};
};
diff --git a/arch/arm/boot/dts/msm8226-ion.dtsi b/arch/arm/boot/dts/msm8226-ion.dtsi
index f433a49..9ada271 100644
--- a/arch/arm/boot/dts/msm8226-ion.dtsi
+++ b/arch/arm/boot/dts/msm8226-ion.dtsi
@@ -38,9 +38,7 @@
qcom,ion-heap@27 { /* QSECOM HEAP */
compatible = "qcom,msm-ion-reserve";
reg = <27>;
- qcom,heap-align = <0x1000>;
- qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
- qcom,memory-reservation-size = <0x780000>;
+ linux,contiguous-region = <&qsecom_mem>;
};
qcom,ion-heap@28 { /* AUDIO HEAP */
diff --git a/arch/arm/boot/dts/msm8226-pm.dtsi b/arch/arm/boot/dts/msm8226-pm.dtsi
index c62fb3e..b6fbd5b 100644
--- a/arch/arm/boot/dts/msm8226-pm.dtsi
+++ b/arch/arm/boot/dts/msm8226-pm.dtsi
@@ -114,7 +114,7 @@
qcom,type = <0x61706d73>; /* "smpa" */
qcom,id = <0x01>;
qcom,key = <0x6e726f63>; /* "corn" */
- qcom,init-value = <5>; /* Super Turbo */
+ qcom,init-value = <3>; /* SVS SOC */
};
qcom,lpm-resources@1 {
@@ -123,7 +123,7 @@
qcom,type = <0x616F646C>; /* "ldoa" */
qcom,id = <0x03>;
qcom,key = <0x6e726f63>; /* "corn" */
- qcom,init-value = <3>; /* Active */
+ qcom,init-value = <3>; /* SVS SOC */
};
qcom,lpm-resources@2 {
diff --git a/arch/arm/boot/dts/msm8226-regulator.dtsi b/arch/arm/boot/dts/msm8226-regulator.dtsi
index 70731d2..4551f03 100644
--- a/arch/arm/boot/dts/msm8226-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8226-regulator.dtsi
@@ -67,7 +67,7 @@
regulator-min-microvolt = <1>;
regulator-max-microvolt = <7>;
qcom,use-voltage-corner;
- qcom,consumer-supplies = "vdd_dig", "", "vdd_sr2_dig", "";
+ qcom,consumer-supplies = "vdd_dig", "";
};
pm8226_s1_corner_ao: regulator-s1-corner-ao {
compatible = "qcom,rpm-regulator-smd";
@@ -76,6 +76,7 @@
regulator-min-microvolt = <1>;
regulator-max-microvolt = <7>;
qcom,use-voltage-corner;
+ qcom,consumer-supplies = "vdd_sr2_dig", "";
};
};
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index c392428..cdb79d6 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -59,6 +59,19 @@
reg = <0 0x3800000>;
label = "secure_mem";
};
+
+ qsecom_mem: qsecom_region {
+ linux,contiguous-region;
+ reg = <0 0x780000>;
+ label = "qsecom_mem";
+ };
+
+ };
+
+ qcom,mpm2-sleep-counter@fc4a3000 {
+ compatible = "qcom,mpm2-sleep-counter";
+ reg = <0xfc4a3000 0x1000>;
+ clock-frequency = <32768>;
};
timer {
@@ -680,7 +693,7 @@
reg = <0xf9927000 0x1000>;
interrupt-names = "qup_err_intr";
interrupts = <0 99 0>;
- qcom,i2c-bus-freq = <100000>;
+ qcom,i2c-bus-freq = <384000>;
qcom,i2c-src-freq = <19200000>;
};
@@ -737,6 +750,7 @@
/* GPIO inputs from wcnss */
qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_4_in 0 0>;
+ qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_4_in 1 0>;
qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_4_in 2 0>;
/* GPIO output to wcnss */
@@ -789,6 +803,7 @@
/* GPIO inputs from mss */
qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_1_in 0 0>;
+ qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_1_in 1 0>;
qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_1_in 2 0>;
/* GPIO output to mss */
diff --git a/arch/arm/boot/dts/msm8610-cdp.dts b/arch/arm/boot/dts/msm8610-cdp.dts
index 84eebbf..d6d41cc 100644
--- a/arch/arm/boot/dts/msm8610-cdp.dts
+++ b/arch/arm/boot/dts/msm8610-cdp.dts
@@ -13,6 +13,7 @@
/dts-v1/;
/include/ "msm8610.dtsi"
+/include/ "dsi-v2-panel-truly-wvga-video.dtsi"
/ {
model = "Qualcomm MSM 8610 CDP";
@@ -23,10 +24,131 @@
serial@f991e000 {
status = "ok";
};
+
+ i2c@f9923000{
+ atmel_mxt_ts@4a {
+ compatible = "atmel,mxt-ts";
+ reg = <0x4a>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <1 0x2>;
+ vdd_ana-supply = <&pm8110_l19>;
+ vcc_i2c-supply = <&pm8110_l14>;
+ atmel,reset-gpio = <&msmgpio 0 0x00>;
+ atmel,irq-gpio = <&msmgpio 1 0x00>;
+ atmel,panel-coords = <0 0 508 880>;
+ atmel,display-coords = <0 0 480 800>;
+ atmel,i2c-pull-up;
+ atmel,no-force-update;
+ atmel,cfg_1 {
+ atmel,family-id = <0x81>;
+ atmel,variant-id = <0x15>;
+ atmel,version = <0x11>;
+ atmel,build = <0xaa>;
+ atmel,config = [
+ /* Object 6, Instance = 0 */
+ 00 00 00 00 00 00
+ /* Object 38, Instance = 0 */
+ 1D 01 00 0C 04 0D 00 00
+ /* Object 7, Instance = 0 */
+ 20 08 32
+ /* Object 8, Instance = 0 */
+ 19 00 14 14 FF 00 FF 00 00 00
+ /* Object 9, Instance = 0 */
+ 83 00 00 13 0B 00 20 32 01 03
+ 00 32 05 30 0A 05 0A 00 70 03
+ FC 01 00 36 2F 2C 00 00 40 00
+ 00 0A 00 00 02
+ /* Object 18, Instance = 0 */
+ 00 00
+ /* Object 19, Instance = 0 */
+ 00 00 00 00 00 00
+ /* Object 25, Instance = 0 */
+ 03 00 18 79 A8 61
+ /* Object 58, Instance = 0 */
+ 00 00 00 00 00 00 00 00 00 00
+ 00
+ /* Object 42, Instance = 0 */
+ 00 00 00 00 00 00 00 00
+ /* Object 46, Instance = 0 */
+ 04 03 08 10 00 00 00 00 00
+ /* Object 47, Instance = 0 */
+ 00 00 00 00 00 00 00 00 00 00
+ /* Object 48, Instance = 0 */
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00
+ /* Object 55, Instance = 0 */
+ 00 00 00 00
+ ];
+ };
+ };
+ };
+};
+
+&i2c_cdc {
+ msm8x10_wcd_codec@0d{
+ compatible = "qcom,msm8x10-wcd-i2c";
+ reg = <0x0d>;
+ cdc-vdda-cp-supply = <&pm8110_s4>;
+ qcom,cdc-vdda-cp-voltage = <2150000 2150000>;
+ qcom,cdc-vdda-cp-current = <650000>;
+
+ cdc-vdda-h-supply = <&pm8110_l6>;
+ qcom,cdc-vdda-h-voltage = <1800000 1800000>;
+ qcom,cdc-vdda-h-current = <250000>;
+
+ cdc-vdd-px-supply = <&pm8110_l6>;
+ qcom,cdc-vdd-px-voltage = <1800000 1800000>;
+ qcom,cdc-vdd-px-current = <10000>;
+
+ cdc-vdd-1p2v-supply = <&pm8110_l4>;
+ qcom,cdc-vdd-1p2v-voltage = <1200000 1200000>;
+ qcom,cdc-vdd-1p2v-current = <5000>;
+
+ cdc-vdd-mic-bias-supply = <&pm8110_l20>;
+ qcom,cdc-vdd-mic-bias-voltage = <3075000 3075000>;
+ qcom,cdc-vdd-mic-bias-current = <25000>;
+
+ qcom,cdc-micbias-cfilt-sel = <0x0>;
+ qcom,cdc-micbias-cfilt-mv = <1800000>;
+ qcom,cdc-mclk-clk-rate = <12288000>;
+ };
+
+ msm8x10_wcd_codec@77{
+ compatible = "qcom,msm8x10-wcd-i2c";
+ reg = <0x77>;
+ };
+
+ msm8x10_wcd_codec@66{
+ compatible = "qcom,msm8x10-wcd-i2c";
+ reg = <0x66>;
+ };
+
+ msm8x10_wcd_codec@55{
+ compatible = "qcom,msm8x10-wcd-i2c";
+ reg = <0x55>;
+ };
};
&spmi_bus {
qcom,pm8110@0 {
+ qcom,leds@a100 {
+ status = "okay";
+ qcom,led_mpp_2 {
+ label = "mpp";
+ linux,name = "button-backlight";
+ linux-default-trigger = "hr-trigger";
+ qcom,default-state = "off";
+ qcom,max-current = <40>;
+ qcom,id = <6>;
+ qcom,source-sel = <1>;
+ qcom,mode-ctrl = <0x60>;
+ };
+ };
+
qcom,leds@a200 {
status = "okay";
qcom,led_mpp_3 {
@@ -75,6 +197,16 @@
};
};
+&spmi_bus {
+ qcom,pm8110@1 {
+ qcom,vibrator@c000 {
+ status = "okay";
+ qcom,vib-timeout-ms = <15000>;
+ qcom,vib-vtg-level-mV = <3100>;
+ };
+ };
+};
+
&sdhc_1 {
vdd-supply = <&pm8110_l17>;
qcom,vdd-always-on;
@@ -152,3 +284,33 @@
status = "ok";
};
};
+
+&pm8110_gpios {
+ gpio@c000 { /* GPIO 1 */
+ };
+
+ gpio@c100 { /* GPIO 2 */
+ };
+
+ gpio@c200 { /* GPIO 3 */
+ };
+
+ gpio@c300 { /* GPIO 4 */
+ };
+};
+
+&pm8110_mpps {
+ mpp@a000 { /* MPP 1 */
+ };
+
+ mpp@a100 { /* MPP 2 */
+ status = "disabled";
+ };
+
+ mpp@a200 { /* MPP 3 */
+ status = "disabled";
+ };
+
+ mpp@a300 { /* MPP 4 */
+ };
+};
diff --git a/arch/arm/boot/dts/msm8610-ion.dtsi b/arch/arm/boot/dts/msm8610-ion.dtsi
index 41b58da..7d7d8fd 100644
--- a/arch/arm/boot/dts/msm8610-ion.dtsi
+++ b/arch/arm/boot/dts/msm8610-ion.dtsi
@@ -31,9 +31,7 @@
qcom,ion-heap@27 { /* QSECOM HEAP */
compatible = "qcom,msm-ion-reserve";
reg = <27>;
- qcom,heap-align = <0x1000>;
- qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
- qcom,memory-reservation-size = <0x100000>;
+ linux,contiguous-region = <&qsecom_mem>;
};
};
};
diff --git a/arch/arm/boot/dts/msm8610-mdss.dtsi b/arch/arm/boot/dts/msm8610-mdss.dtsi
new file mode 100644
index 0000000..42fa149
--- /dev/null
+++ b/arch/arm/boot/dts/msm8610-mdss.dtsi
@@ -0,0 +1,37 @@
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/ {
+ qcom,mdss_mdp@fd900000 {
+ compatible = "qcom,mdss_mdp3";
+ reg = <0xfd900000 0x100000>;
+ reg-names = "mdp_phys";
+ interrupts = <0 72 0>;
+
+ mdss_fb0: qcom,mdss_fb_primary {
+ cell-index = <0>;
+ compatible = "qcom,mdss-fb";
+ qcom,memory-reservation-type = "EBI1";
+ qcom,memory-reservation-size = <0x800000>;
+ };
+ };
+
+ mdss_dsi0: qcom,mdss_dsi@fdd00000 {
+ compatible = "qcom,msm-dsi-v2";
+ label = "MDSS DSI CTRL->0";
+ cell-index = <0>;
+ reg = <0xfdd00000 0x100000>;
+ interrupts = <0 30 0>;
+ vdda-supply = <&pm8110_l4>;
+ qcom,mdss-fb-map = <&mdss_fb0>;
+ };
+};
diff --git a/arch/arm/boot/dts/msm8610-mtp.dts b/arch/arm/boot/dts/msm8610-mtp.dts
index 90d4a0e..06a2321 100644
--- a/arch/arm/boot/dts/msm8610-mtp.dts
+++ b/arch/arm/boot/dts/msm8610-mtp.dts
@@ -13,6 +13,7 @@
/dts-v1/;
/include/ "msm8610.dtsi"
+/include/ "dsi-v2-panel-truly-wvga-video.dtsi"
/ {
model = "Qualcomm MSM 8610 MTP";
@@ -23,10 +24,131 @@
serial@f991e000 {
status = "ok";
};
+
+ i2c@f9923000{
+ atmel_mxt_ts@4a {
+ compatible = "atmel,mxt-ts";
+ reg = <0x4a>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <1 0x2>;
+ vdd_ana-supply = <&pm8110_l19>;
+ vcc_i2c-supply = <&pm8110_l14>;
+ atmel,reset-gpio = <&msmgpio 0 0x00>;
+ atmel,irq-gpio = <&msmgpio 1 0x00>;
+ atmel,panel-coords = <0 0 508 880>;
+ atmel,display-coords = <0 0 480 800>;
+ atmel,i2c-pull-up;
+ atmel,no-force-update;
+ atmel,cfg_1 {
+ atmel,family-id = <0x81>;
+ atmel,variant-id = <0x15>;
+ atmel,version = <0x11>;
+ atmel,build = <0xaa>;
+ atmel,config = [
+ /* Object 6, Instance = 0 */
+ 00 00 00 00 00 00
+ /* Object 38, Instance = 0 */
+ 1D 01 00 0C 04 0D 00 00
+ /* Object 7, Instance = 0 */
+ 20 08 32
+ /* Object 8, Instance = 0 */
+ 19 00 14 14 FF 00 FF 00 00 00
+ /* Object 9, Instance = 0 */
+ 83 00 00 13 0B 00 20 32 01 03
+ 00 32 05 30 0A 05 0A 00 70 03
+ FC 01 00 36 2F 2C 00 00 40 00
+ 00 0A 00 00 02
+ /* Object 18, Instance = 0 */
+ 00 00
+ /* Object 19, Instance = 0 */
+ 00 00 00 00 00 00
+ /* Object 25, Instance = 0 */
+ 03 00 18 79 A8 61
+ /* Object 58, Instance = 0 */
+ 00 00 00 00 00 00 00 00 00 00
+ 00
+ /* Object 42, Instance = 0 */
+ 00 00 00 00 00 00 00 00
+ /* Object 46, Instance = 0 */
+ 04 03 08 10 00 00 00 00 00
+ /* Object 47, Instance = 0 */
+ 00 00 00 00 00 00 00 00 00 00
+ /* Object 48, Instance = 0 */
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00
+ /* Object 55, Instance = 0 */
+ 00 00 00 00
+ ];
+ };
+ };
+ };
+};
+
+&i2c_cdc {
+ msm8x10_wcd_codec@0d{
+ compatible = "qcom,msm8x10-wcd-i2c";
+ reg = <0x0d>;
+ cdc-vdda-cp-supply = <&pm8110_s4>;
+ qcom,cdc-vdda-cp-voltage = <2150000 2150000>;
+ qcom,cdc-vdda-cp-current = <650000>;
+
+ cdc-vdda-h-supply = <&pm8110_l6>;
+ qcom,cdc-vdda-h-voltage = <1800000 1800000>;
+ qcom,cdc-vdda-h-current = <250000>;
+
+ cdc-vdd-px-supply = <&pm8110_l6>;
+ qcom,cdc-vdd-px-voltage = <1800000 1800000>;
+ qcom,cdc-vdd-px-current = <10000>;
+
+ cdc-vdd-1p2v-supply = <&pm8110_l4>;
+ qcom,cdc-vdd-1p2v-voltage = <1200000 1200000>;
+ qcom,cdc-vdd-1p2v-current = <5000>;
+
+ cdc-vdd-mic-bias-supply = <&pm8110_l20>;
+ qcom,cdc-vdd-mic-bias-voltage = <3075000 3075000>;
+ qcom,cdc-vdd-mic-bias-current = <25000>;
+
+ qcom,cdc-micbias-cfilt-sel = <0x0>;
+ qcom,cdc-micbias-cfilt-mv = <1800000>;
+ qcom,cdc-mclk-clk-rate = <12288000>;
+ };
+
+ msm8x10_wcd_codec@77{
+ compatible = "qcom,msm8x10-wcd-i2c";
+ reg = <0x77>;
+ };
+
+ msm8x10_wcd_codec@66{
+ compatible = "qcom,msm8x10-wcd-i2c";
+ reg = <0x66>;
+ };
+
+ msm8x10_wcd_codec@55{
+ compatible = "qcom,msm8x10-wcd-i2c";
+ reg = <0x55>;
+ };
};
&spmi_bus {
qcom,pm8110@0 {
+ qcom,leds@a100 {
+ status = "okay";
+ qcom,led_mpp_2 {
+ label = "mpp";
+ linux,name = "button-backlight";
+ linux-default-trigger = "hr-trigger";
+ qcom,default-state = "off";
+ qcom,max-current = <40>;
+ qcom,id = <6>;
+ qcom,source-sel = <1>;
+ qcom,mode-ctrl = <0x60>;
+ };
+ };
+
qcom,leds@a200 {
status = "okay";
qcom,led_mpp_3 {
@@ -75,6 +197,16 @@
};
};
+&spmi_bus {
+ qcom,pm8110@1 {
+ qcom,vibrator@c000 {
+ status = "okay";
+ qcom,vib-timeout-ms = <15000>;
+ qcom,vib-vtg-level-mV = <3100>;
+ };
+ };
+};
+
&sdhc_1 {
vdd-supply = <&pm8110_l17>;
qcom,vdd-always-on;
@@ -155,3 +287,33 @@
status = "ok";
};
};
+
+&pm8110_gpios {
+ gpio@c000 { /* GPIO 1 */
+ };
+
+ gpio@c100 { /* GPIO 2 */
+ };
+
+ gpio@c200 { /* GPIO 3 */
+ };
+
+ gpio@c300 { /* GPIO 4 */
+ };
+};
+
+&pm8110_mpps {
+ mpp@a000 { /* MPP 1 */
+ };
+
+ mpp@a100 { /* MPP 2 */
+ status = "disabled";
+ };
+
+ mpp@a200 { /* MPP 3 */
+ status = "disabled";
+ };
+
+ mpp@a300 { /* MPP 4 */
+ };
+};
diff --git a/arch/arm/boot/dts/msm8610-regulator.dtsi b/arch/arm/boot/dts/msm8610-regulator.dtsi
index 67eee5c..f5d01e0 100644
--- a/arch/arm/boot/dts/msm8610-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8610-regulator.dtsi
@@ -66,7 +66,7 @@
regulator-min-microvolt = <1>;
regulator-max-microvolt = <7>;
qcom,use-voltage-corner;
- qcom,consumer-supplies = "vdd_dig", "", "vdd_sr2_dig", "";
+ qcom,consumer-supplies = "vdd_dig", "";
};
pm8110_s1_corner_ao: regulator-s1-corner-ao {
@@ -76,6 +76,7 @@
regulator-min-microvolt = <1>;
regulator-max-microvolt = <7>;
qcom,use-voltage-corner;
+ qcom,consumer-supplies = "vdd_sr2_dig", "";
};
};
diff --git a/arch/arm/boot/dts/msm8610-sim.dts b/arch/arm/boot/dts/msm8610-sim.dts
index 1838b94..fc94cc9 100644
--- a/arch/arm/boot/dts/msm8610-sim.dts
+++ b/arch/arm/boot/dts/msm8610-sim.dts
@@ -23,3 +23,48 @@
status = "ok";
};
};
+
+&i2c_cdc {
+ msm8x10_wcd_codec@0d{
+ compatible = "qcom,msm8x10-wcd-i2c";
+ reg = <0x0d>;
+ cdc-vdda-cp-supply = <&pm8110_s4>;
+ qcom,cdc-vdda-cp-voltage = <2150000 2150000>;
+ qcom,cdc-vdda-cp-current = <650000>;
+
+ cdc-vdda-h-supply = <&pm8110_l6>;
+ qcom,cdc-vdda-h-voltage = <1800000 1800000>;
+ qcom,cdc-vdda-h-current = <250000>;
+
+ cdc-vdd-px-supply = <&pm8110_l6>;
+ qcom,cdc-vdd-px-voltage = <1800000 1800000>;
+ qcom,cdc-vdd-px-current = <10000>;
+
+ cdc-vdd-1p2v-supply = <&pm8110_l4>;
+ qcom,cdc-vdd-1p2v-voltage = <1200000 1200000>;
+ qcom,cdc-vdd-1p2v-current = <5000>;
+
+ cdc-vdd-mic-bias-supply = <&pm8110_l20>;
+ qcom,cdc-vdd-mic-bias-voltage = <3075000 3075000>;
+ qcom,cdc-vdd-mic-bias-current = <25000>;
+
+ qcom,cdc-micbias-cfilt-sel = <0x0>;
+ qcom,cdc-micbias-cfilt-mv = <1800000>;
+ qcom,cdc-mclk-clk-rate = <12288000>;
+ };
+
+ msm8x10_wcd_codec@77{
+ compatible = "qcom,msm8x10-wcd-i2c";
+ reg = <0x77>;
+ };
+
+ msm8x10_wcd_codec@66{
+ compatible = "qcom,msm8x10-wcd-i2c";
+ reg = <0x66>;
+ };
+
+ msm8x10_wcd_codec@55{
+ compatible = "qcom,msm8x10-wcd-i2c";
+ reg = <0x55>;
+ };
+};
diff --git a/arch/arm/boot/dts/msm8610.dtsi b/arch/arm/boot/dts/msm8610.dtsi
index 822c792..2cbd76e 100644
--- a/arch/arm/boot/dts/msm8610.dtsi
+++ b/arch/arm/boot/dts/msm8610.dtsi
@@ -19,6 +19,7 @@
/include/ "msm8610-pm.dtsi"
/include/ "msm8610-smp2p.dtsi"
/include/ "msm8610-bus.dtsi"
+/include/ "msm8610-mdss.dtsi"
/ {
model = "Qualcomm MSM 8610";
@@ -45,12 +46,27 @@
qcom,direct-connect-irqs = <8>;
};
+ memory {
+
+ qsecom_mem: qsecom_region {
+ linux,contiguous-region;
+ reg = <0 0x100000>;
+ label = "qsecom_mem";
+ };
+
+ };
+
aliases {
- spi0 = &spi_0;
sdhc1 = &sdhc_1; /* SDC1 eMMC slot */
sdhc2 = &sdhc_2; /* SDC2 SD card slot */
};
+ qcom,mpm2-sleep-counter@fc4a3000 {
+ compatible = "qcom,mpm2-sleep-counter";
+ reg = <0xfc4a3000 0x1000>;
+ clock-frequency = <32768>;
+ };
+
timer {
compatible = "arm,armv7-timer";
interrupts = <1 2 0 1 3 0>;
@@ -148,7 +164,7 @@
qcom,buffer-type-tz-usage-map = <0x1 0x1>,
<0x1fe 0x2>;
qcom,hfi = "q6";
- qcom,max-hw-load = <97200>; /* FWVGA @ 30 * 2 */
+ qcom,max-hw-load = <108000>; /* 720p @ 30 * 1 */
};
qcom,usbbam@f9a44000 {
@@ -417,18 +433,33 @@
qcom,pmic-arb-channel = <0>;
};
- i2c@f9925000 { /* BLSP-1 QUP-3 */
- cell-index = <0>;
+ i2c@f9923000 { /* BLSP-1 QUP-1 */
+ cell-index = <1>;
compatible = "qcom,i2c-qup";
#address-cells = <1>;
#size-cells = <0>;
reg-names = "qup_phys_addr";
- reg = <0xf9925000 0x1000>;
+ reg = <0xf9923000 0x1000>;
interrupt-names = "qup_err_intr";
- interrupts = <0 97 0>;
+ interrupts = <0 95 0>;
qcom,i2c-bus-freq = <100000>;
+ qcom,i2c-src-freq = <19200000>;
+ qcom,sda-gpio = <&msmgpio 2 0>;
+ qcom,scl-gpio = <&msmgpio 3 0>;
};
+ i2c_cdc: i2c@f9927000 { /* BLSP1 QUP5 */
+ cell-index = <5>;
+ compatible = "qcom,i2c-qup";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg-names = "qup_phys_addr";
+ reg = <0xf9927000 0x1000>;
+ interrupt-names = "qup_err_intr";
+ interrupts = <0 99 0>;
+ qcom,i2c-bus-freq = <100000>;
+ };
+
i2c@f9928000 { /* BLSP1 QUP6 */
cell-index = <6>;
compatible = "qcom,i2c-qup";
@@ -444,27 +475,16 @@
qcom,scl-gpio = <&msmgpio 17 0>;
};
- spi_0: spi@f9923000 { /* BLSP1 QUP1 */
- compatible = "qcom,spi-qup-v2";
+ i2c@f9925000 { /* BLSP-1 QUP-3 */
+ cell-index = <0>;
+ compatible = "qcom,i2c-qup";
#address-cells = <1>;
#size-cells = <0>;
- reg-names = "spi_physical", "spi_bam_physical";
- reg = <0xf9923000 0x1000>,
- <0xf9904000 0xF000>;
- interrupt-names = "spi_irq", "spi_bam_irq";
- interrupts = <0 95 0>, <0 238 0>;
- spi-max-frequency = <19200000>;
-
- gpios = <&msmgpio 3 0>, /* CLK */
- <&msmgpio 1 0>, /* MISO */
- <&msmgpio 0 0>; /* MOSI */
- cs-gpios = <&msmgpio 2 0>;
-
- qcom,infinite-mode = <0>;
- qcom,use-bam;
- qcom,ver-reg-exists;
- qcom,bam-consumer-pipe-index = <12>;
- qcom,bam-producer-pipe-index = <13>;
+ reg-names = "qup_phys_addr";
+ reg = <0xf9925000 0x1000>;
+ interrupt-names = "qup_err_intr";
+ interrupts = <0 97 0>;
+ qcom,i2c-bus-freq = <100000>;
};
qcom,pronto@fb21b000 {
@@ -480,6 +500,7 @@
/* GPIO inputs from wcnss */
qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_4_in 0 0>;
+ qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_4_in 1 0>;
qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_4_in 2 0>;
/* GPIO output to wcnss */
@@ -497,6 +518,13 @@
qcom,msm-pcm {
compatible = "qcom,msm-pcm-dsp";
+ qcom,msm-pcm-dsp-id = <0>;
+ };
+
+ qcom,msm-pcm-low-latency {
+ compatible = "qcom,msm-pcm-dsp";
+ qcom,msm-pcm-dsp-id = <1>;
+ qcom,msm-pcm-low-latency;
};
qcom,msm-pcm-routing {
@@ -536,15 +564,15 @@
qcom,msm-dai-q6-mi2s-prim {
compatible = "qcom,msm-dai-q6-mi2s";
qcom,msm-dai-q6-mi2s-dev-id = <0>;
- qcom,msm-mi2s-rx-lines = <1>;
- qcom,msm-mi2s-tx-lines = <0>;
+ qcom,msm-mi2s-rx-lines = <0>;
+ qcom,msm-mi2s-tx-lines = <3>;
};
qcom,msm-dai-q6-mi2s-sec {
compatible = "qcom,msm-dai-q6-mi2s";
qcom,msm-dai-q6-mi2s-dev-id = <1>;
- qcom,msm-mi2s-rx-lines = <0>;
- qcom,msm-mi2s-tx-lines = <3>;
+ qcom,msm-mi2s-rx-lines = <3>;
+ qcom,msm-mi2s-tx-lines = <0>;
};
};
@@ -589,6 +617,21 @@
compatible = "qcom,msm-dai-q6-dev";
qcom,msm-dai-q6-dev-id = <240>;
};
+
+ qcom,msm-dai-q6-incall-record-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <32771>;
+ };
+
+ qcom,msm-dai-q6-incall-record-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <32772>;
+ };
+
+ qcom,msm-dai-q6-incall-music-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <32773>;
+ };
};
qcom,msm-pcm-hostless {
@@ -637,6 +680,7 @@
/* GPIO inputs from mss */
qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_1_in 0 0>;
+ qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_1_in 1 0>;
qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_1_in 2 0>;
/* GPIO output to mss */
@@ -720,6 +764,12 @@
qcom,msm-rng-iface-clk;
};
+ qcom,msm-rtb {
+ compatible = "qcom,msm-rtb";
+ qcom,memory-reservation-type = "EBI1";
+ qcom,memory-reservation-size = <0x100000>; /* 1M EBI1 buffer */
+ };
+
jtag_mm0: jtagmm@fc34c000 {
compatible = "qcom,jtag-mm";
reg = <0xfc34c000 0x1000>,
@@ -808,7 +858,7 @@
label = "vchg_sns";
reg = <2>;
qcom,decimation = <0>;
- qcom,pre-div-channel-scaling = <3>;
+ qcom,pre-div-channel-scaling = <2>;
qcom,calibration-type = "absolute";
qcom,scale-function = <0>;
qcom,hw-settle-time = <0>;
diff --git a/arch/arm/boot/dts/msm8974-ion.dtsi b/arch/arm/boot/dts/msm8974-ion.dtsi
index 31afd9c..cfe39fc 100644
--- a/arch/arm/boot/dts/msm8974-ion.dtsi
+++ b/arch/arm/boot/dts/msm8974-ion.dtsi
@@ -45,9 +45,7 @@
qcom,ion-heap@27 { /* QSECOM HEAP */
compatible = "qcom,msm-ion-reserve";
reg = <27>;
- qcom,heap-align = <0x1000>;
- qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
- qcom,memory-reservation-size = <0x1100000>;
+ linux,contiguous-region = <&qsecom_mem>;
};
qcom,ion-heap@28 { /* AUDIO HEAP */
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index f787cf5..a0a7cbe 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -47,6 +47,13 @@
reg = <0 0x2000000>;
label = "adsp_mem";
};
+
+ qsecom_mem: qsecom_region {
+ linux,contiguous-region;
+ reg = <0 0x1100000>;
+ label = "qseecom_mem";
+ };
+
};
intc: interrupt-controller@F9000000 {
@@ -725,6 +732,22 @@
qcom,i2c-src-freq = <50000000>;
};
+ i2c_1: i2c@f9923000 {
+ cell-index = <1>;
+ compatible = "qcom,i2c-qup";
+ reg = <0xf9923000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg-names = "qup_phys_addr";
+ interrupts = <0 95 0>;
+ interrupt-names = "qup_err_intr";
+ qcom,i2c-bus-freq = <100000>;
+ qcom,i2c-src-freq = <19200000>;
+ qcom,scl-gpio = <&msmgpio 3 0>;
+ qcom,sda-gpio = <&msmgpio 2 0>;
+ status = "disabled";
+ };
+
i2c_2: i2c@f9924000 {
cell-index = <2>;
compatible = "qcom,i2c-qup";
@@ -1102,6 +1125,7 @@
/* GPIO inputs from mss */
qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_1_in 0 0>;
+ qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_1_in 1 0>;
qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_1_in 2 0>;
/* GPIO output to mss */
@@ -1121,6 +1145,7 @@
/* GPIO inputs from wcnss */
qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_4_in 0 0>;
+ qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_4_in 1 0>;
qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_4_in 2 0>;
/* GPIO output to wcnss */
@@ -1544,22 +1569,28 @@
};
&gdsc_venus {
+ qcom,clock-names = "core_clk";
status = "ok";
};
&gdsc_mdss {
+ qcom,clock-names = "core_clk", "lut_clk";
status = "ok";
};
&gdsc_jpeg {
+ qcom,clock-names = "core0_clk", "core1_clk", "core2_clk";
status = "ok";
};
&gdsc_vfe {
+ qcom,clock-names = "core0_clk", "core1_clk", "csi0_clk", "csi1_clk",
+ "cpp_clk";
status = "ok";
};
&gdsc_oxili_gx {
+ qcom,clock-names = "core_clk";
qcom,retain-mems;
status = "ok";
};
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index abfd7ec..3e2eab3 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -757,6 +757,7 @@
/* GPIO inputs from mss */
qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_1_in 0 0>;
+ qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_1_in 1 0>;
qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_1_in 2 0>;
/* GPIO output to mss */
diff --git a/arch/arm/configs/apq8084_defconfig b/arch/arm/configs/apq8084_defconfig
index 5ba76b6..a1fa53c 100644
--- a/arch/arm/configs/apq8084_defconfig
+++ b/arch/arm/configs/apq8084_defconfig
@@ -74,8 +74,6 @@
CONFIG_MSM_L2_ERP_PORT_PANIC=y
CONFIG_MSM_L2_ERP_1BIT_PANIC=y
CONFIG_MSM_L2_ERP_2BIT_PANIC=y
-CONFIG_MSM_CACHE_DUMP=y
-CONFIG_MSM_CACHE_DUMP_ON_PANIC=y
CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
CONFIG_ARM_LPAE=y
CONFIG_NO_HZ=y
diff --git a/arch/arm/configs/msm8610-perf_defconfig b/arch/arm/configs/msm8610-perf_defconfig
index 03ac944..5660dec 100644
--- a/arch/arm/configs/msm8610-perf_defconfig
+++ b/arch/arm/configs/msm8610-perf_defconfig
@@ -25,6 +25,7 @@
CONFIG_PANIC_TIMEOUT=5
CONFIG_KALLSYMS_ALL=y
CONFIG_EMBEDDED=y
+# CONFIG_SLUB_DEBUG is not set
CONFIG_PROFILING=y
CONFIG_OPROFILE=m
CONFIG_MODULES=y
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index 3322896..09b038c 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -59,7 +59,6 @@
CONFIG_MSM_WATCHDOG_V2=y
CONFIG_MSM_MEMORY_DUMP=y
CONFIG_MSM_DLOAD_MODE=y
-CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
CONFIG_MSM_ADSP_LOADER=m
CONFIG_MSM_OCMEM=y
CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y
@@ -69,6 +68,7 @@
CONFIG_SENSORS_ADSP=y
CONFIG_MSM_RTB=y
CONFIG_MSM_RTB_SEPARATE_CPUS=y
+CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_SMP=y
@@ -214,6 +214,7 @@
CONFIG_INPUT_EVBUG=m
CONFIG_KEYBOARD_GPIO=y
CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ATMEL_MXT=y
CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4=y
CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI4_DEV=y
CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE=y
@@ -278,7 +279,6 @@
CONFIG_ION_MSM=y
CONFIG_MSM_KGSL=y
CONFIG_FB=y
-CONFIG_FB_VIRTUAL=y
CONFIG_FB_MSM=y
# CONFIG_FB_MSM_BACKLIGHT is not set
CONFIG_FB_MSM_MDSS=y
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index a70e6c6..0eecffd 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -418,6 +418,7 @@
select MAY_HAVE_SPARSE_IRQ
select SPARSE_IRQ
select MULTI_IRQ_HANDLER
+ select ARM_TICKET_LOCKS
select GPIO_MSM_V3
select MSM_GPIOMUX
select MSM_NATIVE_RESTART
@@ -459,6 +460,7 @@
select MAY_HAVE_SPARSE_IRQ
select SPARSE_IRQ
select MULTI_IRQ_HANDLER
+ select ARM_TICKET_LOCKS
select GPIO_MSM_V3
select MSM_GPIOMUX
select MSM_NATIVE_RESTART
@@ -1113,14 +1115,14 @@
config KERNEL_PMEM_SMI_REGION
bool "Enable in-kernel PMEM region for SMI"
default y if ARCH_MSM8X60
- depends on ANDROID_PMEM && ((ARCH_QSD8X50 && !PMEM_GPU0) || (ARCH_MSM8X60 && !VCM))
+ depends on (ARCH_QSD8X50 && !PMEM_GPU0) || (ARCH_MSM8X60 && !VCM)
help
Enable the in-kernel PMEM allocator to use SMI memory.
config PMEM_GPU0
bool "Enable PMEM GPU0 region"
default y
- depends on ARCH_QSD8X50 && ANDROID_PMEM
+ depends on ARCH_QSD8X50
help
Enable the PMEM GPU0 device on SMI Memory.
@@ -1856,7 +1858,6 @@
config MSM_HW3D
tristate "MSM Hardware 3D Register Driver"
- depends on ANDROID_PMEM
help
Provides access to registers needed by the userspace OpenGL|ES
library.
@@ -1864,7 +1865,6 @@
config MSM_ADSP
depends on (ARCH_MSM7X01A || ARCH_MSM7X25 || ARCH_MSM7X27)
tristate "MSM ADSP driver"
- depends on ANDROID_PMEM
default y
help
Provides access to registers needed by the userspace aDSP library.
@@ -1890,7 +1890,7 @@
config MSM7KV2_AUDIO
bool "MSM7K v2 audio"
- depends on (ARCH_MSM7X30 && ANDROID_PMEM)
+ depends on ARCH_MSM7X30
default y
help
Enables QDSP5V2-based audio drivers for audio playbacks and
@@ -1906,14 +1906,14 @@
config MSM_QDSP6
tristate "QDSP6 support"
- depends on ARCH_QSD8X50 && ANDROID_PMEM
+ depends on ARCH_QSD8X50
default y
help
Enable support for qdsp6. This provides audio and video functionality.
config MSM8X60_AUDIO
tristate "MSM8X60 audio support"
- depends on ARCH_MSM8X60 && ANDROID_PMEM
+ depends on ARCH_MSM8X60
default y
help
Enable support for qdsp6v2. This provides audio functionality.
@@ -1972,7 +1972,7 @@
config QSD_AUDIO
bool "QSD audio"
- depends on ARCH_MSM_SCORPION && MSM_DALRPC && ANDROID_PMEM && !MSM_SMP
+ depends on ARCH_MSM_SCORPION && MSM_DALRPC && !MSM_SMP
default y
help
Provides PCM, MP3, and AAC audio playback.
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index d5f880a..8efc000 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -4,10 +4,9 @@
ifndef CONFIG_ARM_ARCH_TIMER
obj-y += timer.o
endif
-obj-y += clock.o clock-voter.o clock-dummy.o
+obj-y += clock.o clock-voter.o clock-dummy.o clock-generic.o
obj-y += modem_notifier.o
obj-$(CONFIG_USE_OF) += board-dt.o
-obj-$(CONFIG_CPU_FREQ_MSM) += cpufreq.o
obj-$(CONFIG_DEBUG_FS) += nohlt.o clock-debug.o
obj-$(CONFIG_KEXEC) += msm_kexec.o
@@ -429,3 +428,4 @@
obj-$(CONFIG_ARCH_MSM8974) += msm_mpmctr.o
obj-$(CONFIG_MSM_CPR_REGULATOR) += cpr-regulator.o
+obj-$(CONFIG_CPU_FREQ_MSM) += cpufreq.o
diff --git a/arch/arm/mach-msm/acpuclock-8226.c b/arch/arm/mach-msm/acpuclock-8226.c
index 153be21..a6f772d 100644
--- a/arch/arm/mach-msm/acpuclock-8226.c
+++ b/arch/arm/mach-msm/acpuclock-8226.c
@@ -65,7 +65,6 @@
* 3) Depending on Frodo version, may need minimum of LVL_NOM
*/
static struct clkctl_acpu_speed acpu_freq_tbl_8226[] = {
- { 0, 19200, CXO, 0, 0, CPR_CORNER_SVS, 0, 0 },
{ 1, 300000, PLL0, 4, 2, CPR_CORNER_SVS, 0, 4 },
{ 1, 384000, ACPUPLL, 5, 0, CPR_CORNER_SVS, 0, 4 },
{ 1, 600000, PLL0, 4, 0, CPR_CORNER_NORMAL, 0, 6 },
@@ -77,7 +76,6 @@
};
static struct clkctl_acpu_speed acpu_freq_tbl_8610[] = {
- { 0, 19200, CXO, 0, 0, CPR_CORNER_SVS, 0, 0 },
{ 1, 300000, PLL0, 4, 2, CPR_CORNER_SVS, 0, 3 },
{ 1, 384000, ACPUPLL, 5, 0, CPR_CORNER_SVS, 0, 3 },
{ 1, 600000, PLL0, 4, 0, CPR_CORNER_NORMAL, 0, 4 },
diff --git a/arch/arm/mach-msm/board-8064-gpiomux.c b/arch/arm/mach-msm/board-8064-gpiomux.c
index 0f88287..ede53bc 100644
--- a/arch/arm/mach-msm/board-8064-gpiomux.c
+++ b/arch/arm/mach-msm/board-8064-gpiomux.c
@@ -968,7 +968,6 @@
.pull = GPIOMUX_PULL_DOWN,
};
-
static struct gpiomux_setting ap2mdm_soft_reset_cfg = {
.func = GPIOMUX_FUNC_GPIO,
.drv = GPIOMUX_DRV_4MA,
diff --git a/arch/arm/mach-msm/board-8610-gpiomux.c b/arch/arm/mach-msm/board-8610-gpiomux.c
index eada62c..593e2b1 100644
--- a/arch/arm/mach-msm/board-8610-gpiomux.c
+++ b/arch/arm/mach-msm/board-8610-gpiomux.c
@@ -29,14 +29,26 @@
.pull = GPIOMUX_PULL_NONE,
};
-static struct gpiomux_setting gpio_spi_config = {
- .func = GPIOMUX_FUNC_1,
- .drv = GPIOMUX_DRV_6MA,
- .pull = GPIOMUX_PULL_NONE,
+static struct gpiomux_setting atmel_int_act_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_UP,
};
-static struct gpiomux_setting gpio_spi_cs_config = {
- .func = GPIOMUX_FUNC_1,
+static struct gpiomux_setting atmel_int_sus_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting atmel_reset_act_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_6MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting atmel_reset_sus_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
.drv = GPIOMUX_DRV_6MA,
.pull = GPIOMUX_PULL_DOWN,
};
@@ -97,6 +109,18 @@
static struct msm_gpiomux_config msm_blsp_configs[] __initdata = {
{
+ .gpio = 2, /* BLSP1 QUP1 I2C_SDA */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_i2c_config,
+ },
+ },
+ {
+ .gpio = 3, /* BLSP1 QUP1 I2C_SCL */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_i2c_config,
+ },
+ },
+ {
.gpio = 10, /* BLSP1 QUP3 I2C_SDA */
.settings = {
[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
@@ -120,28 +144,21 @@
[GPIOMUX_SUSPENDED] = &gpio_cam_i2c_config,
},
},
+};
+
+static struct msm_gpiomux_config msm_atmel_configs[] __initdata = {
{
- .gpio = 0, /* BLSP1 QUP1 SPI_DATA_MOSI */
+ .gpio = 0, /* TOUCH RESET */
.settings = {
- [GPIOMUX_SUSPENDED] = &gpio_spi_config,
+ [GPIOMUX_ACTIVE] = &atmel_reset_act_cfg,
+ [GPIOMUX_SUSPENDED] = &atmel_reset_sus_cfg,
},
},
{
- .gpio = 1, /* BLSP1 QUP1 SPI_DATA_MISO */
+ .gpio = 1, /* TOUCH INT */
.settings = {
- [GPIOMUX_SUSPENDED] = &gpio_spi_config,
- },
- },
- {
- .gpio = 3, /* BLSP1 QUP1 SPI_CLK */
- .settings = {
- [GPIOMUX_SUSPENDED] = &gpio_spi_config,
- },
- },
- {
- .gpio = 2, /* BLSP1 QUP1 SPI_CS1 */
- .settings = {
- [GPIOMUX_SUSPENDED] = &gpio_spi_cs_config,
+ [GPIOMUX_ACTIVE] = &atmel_int_act_cfg,
+ [GPIOMUX_SUSPENDED] = &atmel_int_sus_cfg,
},
},
};
@@ -208,6 +225,30 @@
},
};
+static struct gpiomux_setting sd_card_det_active_config = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_NONE,
+ .dir = GPIOMUX_IN,
+};
+
+static struct gpiomux_setting sd_card_det_suspend_config = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_UP,
+ .dir = GPIOMUX_IN,
+};
+
+static struct msm_gpiomux_config sd_card_det[] __initdata = {
+ {
+ .gpio = 42,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &sd_card_det_active_config,
+ [GPIOMUX_SUSPENDED] = &sd_card_det_suspend_config,
+ },
+ },
+};
+
void __init msm8610_init_gpiomux(void)
{
int rc;
@@ -219,9 +260,12 @@
}
msm_gpiomux_install(msm_blsp_configs, ARRAY_SIZE(msm_blsp_configs));
+ msm_gpiomux_install(msm_atmel_configs,
+ ARRAY_SIZE(msm_atmel_configs));
msm_gpiomux_install(wcnss_5wire_interface,
ARRAY_SIZE(wcnss_5wire_interface));
msm_gpiomux_install(msm_lcd_configs, ARRAY_SIZE(msm_lcd_configs));
msm_gpiomux_install(msm_keypad_configs,
ARRAY_SIZE(msm_keypad_configs));
+ msm_gpiomux_install(sd_card_det, ARRAY_SIZE(sd_card_det));
}
diff --git a/arch/arm/mach-msm/board-8930-regulator-pm8038.c b/arch/arm/mach-msm/board-8930-regulator-pm8038.c
index c34394e..8ed93ea 100644
--- a/arch/arm/mach-msm/board-8930-regulator-pm8038.c
+++ b/arch/arm/mach-msm/board-8930-regulator-pm8038.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -95,7 +95,7 @@
REGULATOR_SUPPLY("VDDIO_CDC", "sitar1p1-slim"),
REGULATOR_SUPPLY("CDC_VDDA_TX", "sitar1p1-slim"),
REGULATOR_SUPPLY("CDC_VDDA_RX", "sitar1p1-slim"),
- REGULATOR_SUPPLY("vddp", "0-0048"),
+ REGULATOR_SUPPLY("vcc_i2c", "0-0048"),
REGULATOR_SUPPLY("mhl_iovcc18", "0-0039"),
REGULATOR_SUPPLY("vdd-io", "spi0.0"),
REGULATOR_SUPPLY("vdd-phy", "spi0.0"),
@@ -209,7 +209,6 @@
REGULATOR_SUPPLY("8038_lvs2", NULL),
REGULATOR_SUPPLY("vcc_i2c", "3-004a"),
REGULATOR_SUPPLY("vcc_i2c", "3-0024"),
- REGULATOR_SUPPLY("vcc_i2c", "0-0048"),
REGULATOR_SUPPLY("vddio", "12-0018"),
REGULATOR_SUPPLY("vlogic", "12-0068"),
};
diff --git a/arch/arm/mach-msm/board-8930-regulator-pm8917.c b/arch/arm/mach-msm/board-8930-regulator-pm8917.c
index 8f853a4..cdc419f 100644
--- a/arch/arm/mach-msm/board-8930-regulator-pm8917.c
+++ b/arch/arm/mach-msm/board-8930-regulator-pm8917.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -194,7 +194,7 @@
REGULATOR_SUPPLY("VDDIO_CDC", "sitar1p1-slim"),
REGULATOR_SUPPLY("CDC_VDDA_TX", "sitar1p1-slim"),
REGULATOR_SUPPLY("CDC_VDDA_RX", "sitar1p1-slim"),
- REGULATOR_SUPPLY("vddp", "0-0048"),
+ REGULATOR_SUPPLY("vcc_i2c", "0-0048"),
REGULATOR_SUPPLY("mhl_iovcc18", "0-0039"),
REGULATOR_SUPPLY("CDC_VDD_CP", "sitar-slim"),
REGULATOR_SUPPLY("CDC_VDD_CP", "sitar1p1-slim"),
@@ -233,7 +233,6 @@
REGULATOR_SUPPLY("8917_lvs4", NULL),
REGULATOR_SUPPLY("vcc_i2c", "3-004a"),
REGULATOR_SUPPLY("vcc_i2c", "3-0024"),
- REGULATOR_SUPPLY("vcc_i2c", "0-0048"),
REGULATOR_SUPPLY("vddio", "12-0018"),
REGULATOR_SUPPLY("vlogic", "12-0068"),
};
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index 6ccaba6..ccea956 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -1718,12 +1718,6 @@
static struct isa1200_regulator isa1200_reg_data[] = {
{
- .name = "vddp",
- .min_uV = ISA_I2C_VTG_MIN_UV,
- .max_uV = ISA_I2C_VTG_MAX_UV,
- .load_uA = ISA_I2C_CURR_UA,
- },
- {
.name = "vcc_i2c",
.min_uV = ISA_I2C_VTG_MIN_UV,
.max_uV = ISA_I2C_VTG_MAX_UV,
@@ -2356,6 +2350,7 @@
&msm_pcm_hostless,
&msm_multi_ch_pcm,
&msm_lowlatency_pcm,
+ &msm_fm_loopback,
};
static void __init msm8930_i2c_init(void)
diff --git a/arch/arm/mach-msm/board-8974-gpiomux.c b/arch/arm/mach-msm/board-8974-gpiomux.c
index 705275c..f5b76da 100644
--- a/arch/arm/mach-msm/board-8974-gpiomux.c
+++ b/arch/arm/mach-msm/board-8974-gpiomux.c
@@ -20,6 +20,98 @@
#define KS8851_IRQ_GPIO 94
+static struct gpiomux_setting ap2mdm_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting mdm2ap_status_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_DOWN,
+ .dir = GPIOMUX_IN,
+};
+
+static struct gpiomux_setting mdm2ap_errfatal_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_DOWN,
+ .dir = GPIOMUX_IN,
+};
+
+static struct gpiomux_setting mdm2ap_pblrdy = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_NONE,
+ .dir = GPIOMUX_IN,
+};
+
+
+static struct gpiomux_setting ap2mdm_soft_reset_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting ap2mdm_wakeup = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct msm_gpiomux_config mdm_configs[] __initdata = {
+ /* AP2MDM_STATUS */
+ {
+ .gpio = 105,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &ap2mdm_cfg,
+ }
+ },
+ /* MDM2AP_STATUS */
+ {
+ .gpio = 46,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &mdm2ap_status_cfg,
+ }
+ },
+ /* MDM2AP_ERRFATAL */
+ {
+ .gpio = 82,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &mdm2ap_errfatal_cfg,
+ }
+ },
+ /* AP2MDM_ERRFATAL */
+ {
+ .gpio = 106,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &ap2mdm_cfg,
+ }
+ },
+ /* AP2MDM_SOFT_RESET, aka AP2MDM_PON_RESET_N */
+ {
+ .gpio = 24,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &ap2mdm_soft_reset_cfg,
+ }
+ },
+ /* AP2MDM_WAKEUP */
+ {
+ .gpio = 104,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &ap2mdm_wakeup,
+ }
+ },
+ /* MDM2AP_PBL_READY*/
+ {
+ .gpio = 80,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &mdm2ap_pblrdy,
+ }
+ },
+};
+
static struct gpiomux_setting gpio_uart_config = {
.func = GPIOMUX_FUNC_2,
.drv = GPIOMUX_DRV_16MA,
@@ -1140,4 +1232,8 @@
if (of_board_is_rumi())
msm_gpiomux_install(msm_rumi_blsp_configs,
ARRAY_SIZE(msm_rumi_blsp_configs));
+
+ if (socinfo_get_platform_subtype() == PLATFORM_SUBTYPE_MDM)
+ msm_gpiomux_install(mdm_configs,
+ ARRAY_SIZE(mdm_configs));
}
diff --git a/arch/arm/mach-msm/clock-8226.c b/arch/arm/mach-msm/clock-8226.c
index 1090d89..486842f 100644
--- a/arch/arm/mach-msm/clock-8226.c
+++ b/arch/arm/mach-msm/clock-8226.c
@@ -169,7 +169,7 @@
VDD_DIG_NUM
};
-static const int *vdd_corner[] = {
+static int *vdd_corner[] = {
[VDD_DIG_NONE] = VDD_UV(RPM_REGULATOR_CORNER_NONE),
[VDD_DIG_LOW] = VDD_UV(RPM_REGULATOR_CORNER_SVS_SOC),
[VDD_DIG_NOMINAL] = VDD_UV(RPM_REGULATOR_CORNER_NORMAL),
@@ -2753,7 +2753,7 @@
VDD_SR2_PLL_NUM
};
-static const int *vdd_sr2_levels[] = {
+static int *vdd_sr2_levels[] = {
[VDD_SR2_PLL_OFF] = VDD_UV(0, RPM_REGULATOR_CORNER_NONE),
[VDD_SR2_PLL_SVS] = VDD_UV(1800000, RPM_REGULATOR_CORNER_SVS_SOC),
[VDD_SR2_PLL_NOM] = VDD_UV(1800000, RPM_REGULATOR_CORNER_NORMAL),
diff --git a/arch/arm/mach-msm/clock-8610.c b/arch/arm/mach-msm/clock-8610.c
index c13e595..2683d19 100644
--- a/arch/arm/mach-msm/clock-8610.c
+++ b/arch/arm/mach-msm/clock-8610.c
@@ -30,6 +30,7 @@
#include "clock-rpm.h"
#include "clock-voter.h"
#include "clock.h"
+#include "clock-dsi-8610.h"
enum {
GCC_BASE,
@@ -433,7 +434,7 @@
VDD_DIG_NUM
};
-static const int *vdd_corner[] = {
+static int *vdd_corner[] = {
[VDD_DIG_NONE] = VDD_UV(RPM_REGULATOR_CORNER_NONE),
[VDD_DIG_LOW] = VDD_UV(RPM_REGULATOR_CORNER_SVS_SOC),
[VDD_DIG_NOMINAL] = VDD_UV(RPM_REGULATOR_CORNER_NORMAL),
@@ -532,7 +533,7 @@
VDD_SR2_PLL_NUM
};
-static const int *vdd_sr2_levels[] = {
+static int *vdd_sr2_levels[] = {
[VDD_SR2_PLL_OFF] = VDD_UV(0, RPM_REGULATOR_CORNER_NONE),
[VDD_SR2_PLL_SVS] = VDD_UV(1800000, RPM_REGULATOR_CORNER_SVS_SOC),
[VDD_SR2_PLL_NOM] = VDD_UV(1800000, RPM_REGULATOR_CORNER_NORMAL),
@@ -1561,21 +1562,85 @@
static DEFINE_CLK_VOTER(mdp_axi_clk_src, &axi_clk_src.c, 200000000);
static DEFINE_CLK_VOTER(mmssnoc_axi_clk_src, &axi_clk_src.c, 200000000);
-static struct clk_freq_tbl ftbl_dsi_pclk_clk[] = {
- F_MDSS( 50000000, dsipll, 10, 0, 0),
- F_MDSS(103330000, dsipll, 9, 0, 0),
- F_END,
+static struct clk_ops dsi_byte_clk_src_ops;
+static struct clk_ops dsi_pixel_clk_src_ops;
+static struct clk_ops dsi_dsi_clk_src_ops;
+
+static struct dsi_pll_vco_clk dsi_vco = {
+ .vco_clk_min = 600000000,
+ .vco_clk_max = 1200000000,
+ .pref_div_ratio = 26,
+ .c = {
+ .parent = &gcc_xo_clk_src.c,
+ .dbg_name = "dsi_vco",
+ .ops = &clk_ops_dsi_vco,
+ CLK_INIT(dsi_vco.c),
+ },
};
+static struct clk dsi_pll_byte = {
+ .parent = &dsi_vco.c,
+ .dbg_name = "dsi_pll_byte",
+ .ops = &clk_ops_dsi_byteclk,
+ CLK_INIT(dsi_pll_byte),
+};
+
+static struct clk dsi_pll_pixel = {
+ .parent = &dsi_vco.c,
+ .dbg_name = "dsi_pll_pixel",
+ .ops = &clk_ops_dsi_dsiclk,
+ CLK_INIT(dsi_pll_pixel),
+};
+
+static struct clk_freq_tbl pixel_freq_tbl[] = {
+ {
+ .src_clk = &dsi_pll_pixel,
+ .div_src_val = BVAL(10, 8, dsipll_mm_source_val),
+ },
+ F_END
+};
+
+#define CFG_RCGR_DIV_MASK BM(4, 0)
+
+static int set_rate_pixel_byte_clk(struct clk *clk, unsigned long rate)
+{
+ struct rcg_clk *rcg = to_rcg_clk(clk);
+ struct clk *pll = clk->parent;
+ unsigned long source_rate, div;
+ struct clk_freq_tbl *cur_freq = rcg->current_freq;
+ int rc;
+
+ if (rate == 0)
+ return clk_set_rate(pll, 0);
+
+ source_rate = clk_round_rate(pll, rate);
+ if (!source_rate || ((2 * source_rate) % rate))
+ return -EINVAL;
+
+ div = ((2 * source_rate)/rate) - 1;
+ if (div > CFG_RCGR_DIV_MASK)
+ return -EINVAL;
+
+ rc = clk_set_rate(pll, source_rate);
+ if (rc)
+ return rc;
+
+ cur_freq->div_src_val &= ~CFG_RCGR_DIV_MASK;
+ cur_freq->div_src_val |= BVAL(4, 0, div);
+ rcg->set_rate(rcg, cur_freq);
+
+ return 0;
+}
+
static struct rcg_clk dsi_pclk_clk_src = {
.cmd_rcgr_reg = DSI_PCLK_CMD_RCGR,
.set_rate = set_rate_mnd,
- .freq_tbl = ftbl_dsi_pclk_clk,
- .current_freq = &rcg_dummy_freq,
+ .current_freq = pixel_freq_tbl,
.base = &virt_bases[MMSS_BASE],
.c = {
+ .parent = &dsi_pll_pixel,
.dbg_name = "dsi_pclk_clk_src",
- .ops = &clk_ops_rcg_mnd,
+ .ops = &dsi_pixel_clk_src_ops,
VDD_DIG_FMAX_MAP2(LOW, 50000000, NOMINAL, 103330000),
CLK_INIT(dsi_pclk_clk_src.c),
},
@@ -1687,41 +1752,60 @@
},
};
-static struct clk_freq_tbl ftbl_dsi_clk[] = {
- F_MDSS(155000000, dsipll, 6, 0, 0),
- F_MDSS(310000000, dsipll, 3, 0, 0),
- F_END,
+/*
+ * The DSI clock will always use a divider of 1. However, we still
+ * need to set the right voltage and source.
+ */
+static int set_rate_dsi_clk(struct clk *clk, unsigned long rate)
+{
+ struct rcg_clk *rcg = to_rcg_clk(clk);
+ struct clk_freq_tbl *cur_freq = rcg->current_freq;
+
+ rcg->set_rate(rcg, cur_freq);
+
+ return 0;
+}
+
+static struct clk_freq_tbl dsi_freq_tbl[] = {
+ {
+ .src_clk = &dsi_pll_pixel,
+ .div_src_val = BVAL(4, 0, 0) |
+ BVAL(10, 8, dsipll_mm_source_val),
+ },
+ F_END
};
static struct rcg_clk dsi_clk_src = {
.cmd_rcgr_reg = DSI_CMD_RCGR,
.set_rate = set_rate_mnd,
- .freq_tbl = ftbl_dsi_clk,
- .current_freq = &rcg_dummy_freq,
+ .current_freq = dsi_freq_tbl,
.base = &virt_bases[MMSS_BASE],
.c = {
+ .parent = &dsi_pll_pixel,
.dbg_name = "dsi_clk_src",
- .ops = &clk_ops_rcg_mnd,
+ .ops = &dsi_dsi_clk_src_ops,
VDD_DIG_FMAX_MAP2(LOW, 155000000, NOMINAL, 310000000),
CLK_INIT(dsi_clk_src.c),
},
};
-static struct clk_freq_tbl ftbl_dsi_byte_clk[] = {
- F_MDSS( 62500000, dsipll, 12, 0, 0),
- F_MDSS(125000000, dsipll, 6, 0, 0),
- F_END,
+static struct clk_freq_tbl byte_freq_tbl[] = {
+ {
+ .src_clk = &dsi_pll_byte,
+ .div_src_val = BVAL(10, 8, dsipll_mm_source_val),
+ },
+ F_END
};
static struct rcg_clk dsi_byte_clk_src = {
.cmd_rcgr_reg = DSI_BYTE_CMD_RCGR,
.set_rate = set_rate_hid,
- .freq_tbl = ftbl_dsi_byte_clk,
- .current_freq = &rcg_dummy_freq,
+ .current_freq = byte_freq_tbl,
.base = &virt_bases[MMSS_BASE],
.c = {
+ .parent = &dsi_pll_byte,
.dbg_name = "dsi_byte_clk_src",
- .ops = &clk_ops_rcg,
+ .ops = &dsi_byte_clk_src_ops,
VDD_DIG_FMAX_MAP2(LOW, 62500000, NOMINAL, 125000000),
CLK_INIT(dsi_byte_clk_src.c),
},
@@ -1933,7 +2017,7 @@
},
};
-static struct mux_clk csi0phy_mux_clk = {
+static struct cam_mux_clk csi0phy_cam_mux_clk = {
.enable_reg = MMSS_CAMSS_MISC,
.enable_mask = BIT(11),
.select_reg = MMSS_CAMSS_MISC,
@@ -1945,13 +2029,13 @@
},
.base = &virt_bases[MMSS_BASE],
.c = {
- .dbg_name = "csi0phy_mux_clk",
- .ops = &clk_ops_mux,
- CLK_INIT(csi0phy_mux_clk.c),
+ .dbg_name = "csi0phy_cam_mux_clk",
+ .ops = &clk_ops_cam_mux,
+ CLK_INIT(csi0phy_cam_mux_clk.c),
},
};
-static struct mux_clk csi1phy_mux_clk = {
+static struct cam_mux_clk csi1phy_cam_mux_clk = {
.enable_reg = MMSS_CAMSS_MISC,
.enable_mask = BIT(10),
.select_reg = MMSS_CAMSS_MISC,
@@ -1963,13 +2047,13 @@
},
.base = &virt_bases[MMSS_BASE],
.c = {
- .dbg_name = "csi1phy_mux_clk",
- .ops = &clk_ops_mux,
- CLK_INIT(csi1phy_mux_clk.c),
+ .dbg_name = "csi1phy_cam_mux_clk",
+ .ops = &clk_ops_cam_mux,
+ CLK_INIT(csi1phy_cam_mux_clk.c),
},
};
-static struct mux_clk csi0pix_mux_clk = {
+static struct cam_mux_clk csi0pix_cam_mux_clk = {
.enable_reg = MMSS_CAMSS_MISC,
.enable_mask = BIT(7),
.select_reg = MMSS_CAMSS_MISC,
@@ -1981,14 +2065,14 @@
},
.base = &virt_bases[MMSS_BASE],
.c = {
- .dbg_name = "csi0pix_mux_clk",
- .ops = &clk_ops_mux,
- CLK_INIT(csi0pix_mux_clk.c),
+ .dbg_name = "csi0pix_cam_mux_clk",
+ .ops = &clk_ops_cam_mux,
+ CLK_INIT(csi0pix_cam_mux_clk.c),
},
};
-static struct mux_clk rdi2_mux_clk = {
+static struct cam_mux_clk rdi2_cam_mux_clk = {
.enable_reg = MMSS_CAMSS_MISC,
.enable_mask = BIT(6),
.select_reg = MMSS_CAMSS_MISC,
@@ -2000,13 +2084,13 @@
},
.base = &virt_bases[MMSS_BASE],
.c = {
- .dbg_name = "rdi2_mux_clk",
- .ops = &clk_ops_mux,
- CLK_INIT(rdi2_mux_clk.c),
+ .dbg_name = "rdi2_cam_mux_clk",
+ .ops = &clk_ops_cam_mux,
+ CLK_INIT(rdi2_cam_mux_clk.c),
},
};
-static struct mux_clk rdi1_mux_clk = {
+static struct cam_mux_clk rdi1_cam_mux_clk = {
.enable_reg = MMSS_CAMSS_MISC,
.enable_mask = BIT(5),
.select_reg = MMSS_CAMSS_MISC,
@@ -2018,13 +2102,13 @@
},
.base = &virt_bases[MMSS_BASE],
.c = {
- .dbg_name = "rdi1_mux_clk",
- .ops = &clk_ops_mux,
- CLK_INIT(rdi1_mux_clk.c),
+ .dbg_name = "rdi1_cam_mux_clk",
+ .ops = &clk_ops_cam_mux,
+ CLK_INIT(rdi1_cam_mux_clk.c),
},
};
-static struct mux_clk rdi0_mux_clk = {
+static struct cam_mux_clk rdi0_cam_mux_clk = {
.enable_reg = MMSS_CAMSS_MISC,
.enable_mask = BIT(4),
.select_reg = MMSS_CAMSS_MISC,
@@ -2036,9 +2120,9 @@
},
.base = &virt_bases[MMSS_BASE],
.c = {
- .dbg_name = "rdi0_mux_clk",
- .ops = &clk_ops_mux,
- CLK_INIT(rdi0_mux_clk.c),
+ .dbg_name = "rdi0_cam_mux_clk",
+ .ops = &clk_ops_cam_mux,
+ CLK_INIT(rdi0_cam_mux_clk.c),
},
};
@@ -2114,7 +2198,6 @@
static struct branch_clk dsi_pclk_clk = {
.cbcr_reg = DSI_PCLK_CBCR,
- .has_sibling = 1,
.base = &virt_bases[MMSS_BASE],
.c = {
.parent = &dsi_pclk_clk_src.c,
@@ -2789,17 +2872,18 @@
CLK_LOOKUP("core_clk_src", sdcc1_apps_clk_src.c, ""),
CLK_LOOKUP("core_clk_src", sdcc2_apps_clk_src.c, ""),
CLK_LOOKUP("core_clk_src", usb_hs_system_clk_src.c, ""),
+ CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f9923000.i2c"),
CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f9925000.i2c"),
- CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f9923000.spi"),
- CLK_LOOKUP("core_clk", gcc_blsp1_qup1_i2c_apps_clk.c, ""),
- CLK_LOOKUP("core_clk", gcc_blsp1_qup1_spi_apps_clk.c, "f9923000.spi"),
+ CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f9927000.i2c"),
+ CLK_LOOKUP("core_clk", gcc_blsp1_qup1_i2c_apps_clk.c, "f9923000.i2c"),
+ CLK_LOOKUP("core_clk", gcc_blsp1_qup1_spi_apps_clk.c, ""),
CLK_LOOKUP("core_clk", gcc_blsp1_qup2_i2c_apps_clk.c, ""),
CLK_LOOKUP("core_clk", gcc_blsp1_qup2_spi_apps_clk.c, ""),
CLK_LOOKUP("core_clk", gcc_blsp1_qup3_i2c_apps_clk.c, "f9925000.i2c"),
CLK_LOOKUP("core_clk", gcc_blsp1_qup3_spi_apps_clk.c, ""),
CLK_LOOKUP("core_clk", gcc_blsp1_qup4_i2c_apps_clk.c, ""),
CLK_LOOKUP("core_clk", gcc_blsp1_qup4_spi_apps_clk.c, ""),
- CLK_LOOKUP("core_clk", gcc_blsp1_qup5_i2c_apps_clk.c, ""),
+ CLK_LOOKUP("core_clk", gcc_blsp1_qup5_i2c_apps_clk.c, "f9927000.i2c"),
CLK_LOOKUP("core_clk", gcc_blsp1_qup5_spi_apps_clk.c, ""),
CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f9928000.i2c"),
CLK_LOOKUP("core_clk", gcc_blsp1_qup6_i2c_apps_clk.c, "f9928000.i2c"),
@@ -2884,12 +2968,12 @@
CLK_LOOKUP("core_clk", vfe_ahb_clk.c, ""),
CLK_LOOKUP("core_clk", vfe_axi_clk.c, ""),
- CLK_LOOKUP("core_clk", csi0pix_mux_clk.c, ""),
- CLK_LOOKUP("core_clk", csi0phy_mux_clk.c, ""),
- CLK_LOOKUP("core_clk", csi1phy_mux_clk.c, ""),
- CLK_LOOKUP("core_clk", rdi2_mux_clk.c, ""),
- CLK_LOOKUP("core_clk", rdi1_mux_clk.c, ""),
- CLK_LOOKUP("core_clk", rdi0_mux_clk.c, ""),
+ CLK_LOOKUP("core_clk", csi0pix_cam_mux_clk.c, ""),
+ CLK_LOOKUP("core_clk", csi0phy_cam_mux_clk.c, ""),
+ CLK_LOOKUP("core_clk", csi1phy_cam_mux_clk.c, ""),
+ CLK_LOOKUP("core_clk", rdi2_cam_mux_clk.c, ""),
+ CLK_LOOKUP("core_clk", rdi1_cam_mux_clk.c, ""),
+ CLK_LOOKUP("core_clk", rdi0_cam_mux_clk.c, ""),
CLK_LOOKUP("core_clk", oxili_gfx3d_clk.c, "fdc00000.qcom,kgsl-3d0"),
CLK_LOOKUP("iface_clk", oxili_ahb_clk.c, "fdc00000.qcom,kgsl-3d0"),
@@ -3075,6 +3159,26 @@
clk_set_rate(&mclk1_clk_src.c, mclk1_clk_src.freq_tbl[0].freq_hz);
}
+static void dsi_init(void)
+{
+ dsi_byte_clk_src_ops = clk_ops_rcg;
+ dsi_byte_clk_src_ops.set_rate = set_rate_pixel_byte_clk;
+ dsi_byte_clk_src_ops.handoff = byte_rcg_handoff;
+ dsi_byte_clk_src_ops.get_parent = NULL;
+
+ dsi_dsi_clk_src_ops = clk_ops_rcg_mnd;
+ dsi_dsi_clk_src_ops.set_rate = set_rate_dsi_clk;
+ dsi_dsi_clk_src_ops.handoff = pixel_rcg_handoff;
+ dsi_dsi_clk_src_ops.get_parent = NULL;
+
+ dsi_pixel_clk_src_ops = clk_ops_rcg_mnd;
+ dsi_pixel_clk_src_ops.set_rate = set_rate_pixel_byte_clk;
+ dsi_pixel_clk_src_ops.handoff = pixel_rcg_handoff;
+ dsi_pixel_clk_src_ops.get_parent = NULL;
+
+ dsi_clk_ctrl_init(&dsi_ahb_clk.c);
+}
+
#define GCC_CC_PHYS 0xFC400000
#define GCC_CC_SIZE SZ_16K
@@ -3134,6 +3238,8 @@
reg_init();
+ dsi_init();
+
/* Maintain the max nominal frequency on the MMSSNOC AHB bus. */
clk_set_rate(&mmssnoc_ahb_a_clk.c, 40000000);
clk_prepare_enable(&mmssnoc_ahb_a_clk.c);
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index be6d965..9ee4476 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -6406,79 +6406,14 @@
.main_output_mask = BIT(23),
};
-static void __init reg_init(void)
+
+static void __init init_mm_cc(void)
{
- void __iomem *imem_reg;
-
- /* Deassert MM SW_RESET_ALL signal. */
- writel_relaxed(0, SW_RESET_ALL_REG);
-
/*
- * Some bits are only used on 8960 or 8064 or 8930 and are marked as
- * reserved bits on the other SoCs. Writing to these reserved bits
- * should have no effect.
- */
- /*
- * Initialize MM AHB registers: Enable the FPB clock and disable HW
- * gating on 8627 and 8930ab for all clocks. Also set VFE_AHB's
- * FORCE_CORE_ON bit to prevent its memory from being collapsed when
- * the clock is halted. The sleep and wake-up delays are set to safe
- * values.
- */
- if (cpu_is_msm8627() || cpu_is_msm8930ab()) {
- rmwreg(0x00000003, AHB_EN_REG, 0x6C000103);
- writel_relaxed(0x000007F9, AHB_EN2_REG);
- } else {
- rmwreg(0x40000000, AHB_EN_REG, 0x6C000103);
- writel_relaxed(0x3C7097F9, AHB_EN2_REG);
- }
-
- if (soc_class_is_apq8064())
- rmwreg(0x00000000, AHB_EN3_REG, 0x00000001);
-
- /* Deassert all locally-owned MM AHB resets. */
- rmwreg(0, SW_RESET_AHB_REG, 0xFFF7DFFF);
- rmwreg(0, SW_RESET_AHB2_REG, 0x0000000F);
-
- /* Initialize MM AXI registers: Enable HW gating for all clocks that
- * support it. Also set FORCE_CORE_ON bits, and any sleep and wake-up
- * delays to safe values. */
- if ((cpu_is_msm8960() &&
- SOCINFO_VERSION_MAJOR(socinfo_get_version()) < 3) ||
- cpu_is_msm8627() || cpu_is_msm8930ab()) {
- rmwreg(0x000007F9, MAXI_EN_REG, 0x0803FFFF);
- rmwreg(0x3027FCFF, MAXI_EN2_REG, 0x3A3FFFFF);
- } else {
- rmwreg(0x0003AFF9, MAXI_EN_REG, 0x0803FFFF);
- rmwreg(0x3A27FCFF, MAXI_EN2_REG, 0x3A3FFFFF);
- }
-
- rmwreg(0x0027FCFF, MAXI_EN3_REG, 0x003FFFFF);
- rmwreg(0x0027FCFF, MAXI_EN4_REG, 0x017FFFFF);
-
- if (soc_class_is_apq8064())
- rmwreg(0x019FECFF, MAXI_EN5_REG, 0x01FFEFFF);
- if (cpu_is_msm8930() || cpu_is_msm8930aa() || cpu_is_msm8627() ||
- cpu_is_msm8930ab())
- rmwreg(0x000004FF, MAXI_EN5_REG, 0x00000FFF);
- if (cpu_is_msm8960ab())
- rmwreg(0x009FE000, MAXI_EN5_REG, 0x01FFE000);
-
- if (cpu_is_msm8627() || cpu_is_msm8930ab())
- rmwreg(0x000003C7, SAXI_EN_REG, 0x00003FFF);
- else
- rmwreg(0x00003C38, SAXI_EN_REG, 0x00003FFF);
-
- /* Enable IMEM's clk_on signal */
- imem_reg = ioremap(0x04b00040, 4);
- if (imem_reg) {
- writel_relaxed(0x3, imem_reg);
- iounmap(imem_reg);
- }
-
- /* Initialize MM CC registers: Set MM FORCE_CORE_ON bits so that core
+ * Initialize MM CC registers: Set MM FORCE_CORE_ON bits so that core
* memories retain state even when not clocked. Also, set sleep and
- * wake-up delays to safe values. */
+ * wake-up delays to safe values.
+ */
rmwreg(0x00000000, CSI0_CC_REG, 0x00000410);
rmwreg(0x00000000, CSI1_CC_REG, 0x00000410);
rmwreg(0x80FF0000, DSI1_BYTE_CC_REG, 0xE0FF0010);
@@ -6493,28 +6428,72 @@
rmwreg(0x80FF0000, VFE_CC_REG, 0xE0FF4010);
rmwreg(0x800000FF, VFE_CC2_REG, 0xE00000FF);
rmwreg(0x80FF0000, VPE_CC_REG, 0xE0FF0010);
- if (cpu_is_msm8960ab() || cpu_is_msm8960() || soc_class_is_apq8064()) {
- rmwreg(0x80FF0000, DSI2_BYTE_CC_REG, 0xE0FF0010);
- rmwreg(0x80FF0000, DSI2_PIXEL_CC_REG, 0xE0FF0010);
- rmwreg(0x80FF0000, JPEGD_CC_REG, 0xE0FF0010);
- }
- if (cpu_is_msm8960ab())
- rmwreg(0x00000001, DSI2_PIXEL_CC2_REG, 0x00000001);
+}
- if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_msm8930aa() ||
- cpu_is_msm8627() || cpu_is_msm8930ab())
- rmwreg(0x80FF0000, TV_CC_REG, 0xE1FFC010);
- if (cpu_is_msm8960ab())
- rmwreg(0x00000000, TV_CC_REG, 0x00004010);
+static void __init enable_imem_clk(unsigned long phys)
+{
+ void __iomem *imem_reg;
- if (cpu_is_msm8960()) {
- rmwreg(0x80FF0000, GFX2D0_CC_REG, 0xE0FF0010);
- rmwreg(0x80FF0000, GFX2D1_CC_REG, 0xE0FF0010);
+ /* Enable IMEM's clk_on signal */
+ imem_reg = ioremap(phys, SZ_4);
+ if (imem_reg) {
+ writel_relaxed(0x3, imem_reg);
+ iounmap(imem_reg);
}
- if (soc_class_is_apq8064()) {
- rmwreg(0x00000000, TV_CC_REG, 0x00004010);
- rmwreg(0x80FF0000, VCAP_CC_REG, 0xE0FF1010);
+}
+
+static void __init reg_init_8930(void)
+{
+ /* MM-AHB default values */
+ u32 en_reg = 0x40000000, en2_reg = 0x3C7097F9;
+ /* MM-AXI default values */
+ u32 aen_reg = 0x0003AFF9, aen2_reg = 0x3A27FCFF,
+ saen_reg = 0x00003C38;
+
+
+ /* Deassert MM SW_RESET_ALL signal. */
+ writel_relaxed(0, SW_RESET_ALL_REG);
+
+ /*
+ * Initialize MM AHB registers: Enable the FPB clock and disable HW
+ * gating on 8627 and 8930ab for all clocks. Also set VFE_AHB's
+ * FORCE_CORE_ON bit to prevent its memory from being collapsed when
+ * the clock is halted. The sleep and wake-up delays are set to safe
+ * values.
+ */
+ if (cpu_is_msm8627() || cpu_is_msm8930ab()) {
+ en_reg = 0x00000003;
+ en2_reg = 0x000007F9;
}
+ rmwreg(en_reg, AHB_EN_REG, 0x6C000103);
+ writel_relaxed(en2_reg, AHB_EN2_REG);
+
+ /* Deassert all locally-owned MM AHB resets. */
+ rmwreg(0, SW_RESET_AHB_REG, 0xFFF7DFFF);
+ rmwreg(0, SW_RESET_AHB2_REG, 0x0000000F);
+
+ /*
+ * Initialize MM AXI registers: Enable HW gating for all clocks that
+ * support it. Also set FORCE_CORE_ON bits, and any sleep and wake-up
+ * delays to safe values.
+ */
+ if (cpu_is_msm8627() || cpu_is_msm8930ab()) {
+ aen_reg = 0x000007F9;
+ aen2_reg = 0x3027FCFF;
+ }
+ rmwreg(aen_reg, MAXI_EN_REG, 0x0803FFFF);
+ rmwreg(aen2_reg, MAXI_EN2_REG, 0x3A3FFFFF);
+ rmwreg(0x0027FCFF, MAXI_EN3_REG, 0x003FFFFF);
+ rmwreg(0x0027FCFF, MAXI_EN4_REG, 0x017FFFFF);
+ rmwreg(0x000004FF, MAXI_EN5_REG, 0x00000FFF);
+ if (cpu_is_msm8627() || cpu_is_msm8930ab())
+ saen_reg = 0x000003C7;
+ rmwreg(saen_reg, SAXI_EN_REG, 0x00003FFF);
+
+ enable_imem_clk(0x04b00040);
+
+ init_mm_cc();
+ rmwreg(0x80FF0000, TV_CC_REG, 0xE1FFC010);
/*
* Initialize USB_HS_HCLK_FS registers: Set FORCE_C_ON bits so that
@@ -6522,10 +6501,6 @@
* and wake-up value to max.
*/
rmwreg(0x0000004F, USB_HS1_HCLK_FS_REG, 0x0000007F);
- if (soc_class_is_apq8064()) {
- rmwreg(0x0000004F, USB_HS3_HCLK_FS_REG, 0x0000007F);
- rmwreg(0x0000004F, USB_HS4_HCLK_FS_REG, 0x0000007F);
- }
/* De-assert MM AXI resets to all hardware blocks. */
writel_relaxed(0, SW_RESET_AXI_REG);
@@ -6538,88 +6513,231 @@
writel_relaxed(BIT(11), TSSC_CLK_CTL_REG);
writel_relaxed(BIT(15), PDM_CLK_NS_REG);
- /* Source SLIMBus xo src from slimbus reference clock */
- if (cpu_is_msm8960ab() || cpu_is_msm8960())
- writel_relaxed(0x3, SLIMBUS_XO_SRC_CLK_CTL_REG);
-
- /* Source the dsi_byte_clks from the DSI PHY PLLs */
+ /* Source the dsi1_byte_clks/dsi1_esc_clk from the DSI PHY PLLs */
rmwreg(0x1, DSI1_BYTE_NS_REG, 0x7);
- if (cpu_is_msm8960ab() || cpu_is_msm8960() || soc_class_is_apq8064())
- rmwreg(0x2, DSI2_BYTE_NS_REG, 0x7);
-
- /* Source the dsi1_esc_clk from the DSI1 PHY PLLs */
rmwreg(0x1, DSI1_ESC_NS_REG, 0x7);
/*
+ * Change PLL15 configuration based on the SoC we're running on.
+ *
+ * Default pll15 l, m, n values for 8930/8930aa/8627()
+ */
+ pll15_config.l = 0x21 | BVAL(31, 7, 0x600);
+ pll15_config.m = 0x1;
+ pll15_config.n = 0x3;
+
+ if (cpu_is_msm8930ab()) {
+ pll15_config.l = 0x25 | BVAL(31, 7, 0x600);
+ pll15_config.m = 0x25;
+ pll15_config.n = 0x3E7;
+ }
+ configure_sr_pll(&pll15_config, &pll15_regs, 0);
+
+ /* Disable AUX and BIST outputs */
+ writel_relaxed(0, MM_PLL3_TEST_CTL_REG);
+}
+
+static void __init reg_init_8064(void)
+{
+ u32 is_pll_enabled;
+
+ /* Deassert MM SW_RESET_ALL signal. */
+ writel_relaxed(0, SW_RESET_ALL_REG);
+
+ /*
+ * Initialize MM AHB registers:
+ * Also set VFE_AHB's FORCE_CORE_ON bit to prevent its memory
+ * from being collapsed when the clock is halted. The sleep and
+ * wake-up delays are set to safe values.
+ */
+ rmwreg(0x40000000, AHB_EN_REG, 0x6C000103);
+ writel_relaxed(0x3C7097F9, AHB_EN2_REG);
+ rmwreg(0x00000000, AHB_EN3_REG, 0x00000001);
+
+ /* Deassert all locally-owned MM AHB resets. */
+ rmwreg(0, SW_RESET_AHB_REG, 0xFFF7DFFF);
+ rmwreg(0, SW_RESET_AHB2_REG, 0x0000000F);
+
+ /*
+ * Initialize MM AXI registers: Enable HW gating for all clocks that
+ * support it. Also set FORCE_CORE_ON bits, and any sleep and wake-up
+ * delays to safe values.
+ */
+ rmwreg(0x0003AFF9, MAXI_EN_REG, 0x0803FFFF);
+ rmwreg(0x3A27FCFF, MAXI_EN2_REG, 0x3A3FFFFF);
+ rmwreg(0x0027FCFF, MAXI_EN3_REG, 0x003FFFFF);
+ rmwreg(0x0027FCFF, MAXI_EN4_REG, 0x017FFFFF);
+ rmwreg(0x019FECFF, MAXI_EN5_REG, 0x01FFEFFF);
+ rmwreg(0x00003C38, SAXI_EN_REG, 0x00003FFF);
+
+ enable_imem_clk(0x04b00040);
+
+ init_mm_cc();
+ rmwreg(0x80FF0000, DSI2_BYTE_CC_REG, 0xE0FF0010);
+ rmwreg(0x80FF0000, DSI2_PIXEL_CC_REG, 0xE0FF0010);
+ rmwreg(0x80FF0000, JPEGD_CC_REG, 0xE0FF0010);
+ rmwreg(0x00000000, TV_CC_REG, 0x00004010);
+ rmwreg(0x80FF0000, VCAP_CC_REG, 0xE0FF1010);
+
+ /*
+ * Initialize USB_HS_HCLK_FS registers: Set FORCE_C_ON bits so that
+ * core remain active during halt state of the clk. Also, set sleep
+ * and wake-up value to max.
+ */
+ rmwreg(0x0000004F, USB_HS1_HCLK_FS_REG, 0x0000007F);
+ rmwreg(0x0000004F, USB_HS3_HCLK_FS_REG, 0x0000007F);
+ rmwreg(0x0000004F, USB_HS4_HCLK_FS_REG, 0x0000007F);
+
+ /* De-assert MM AXI resets to all hardware blocks. */
+ writel_relaxed(0, SW_RESET_AXI_REG);
+
+ /* Deassert all MM core resets. */
+ writel_relaxed(0, SW_RESET_CORE_REG);
+ writel_relaxed(0, SW_RESET_CORE2_REG);
+
+ /* Enable TSSC and PDM PXO sources. */
+ writel_relaxed(BIT(11), TSSC_CLK_CTL_REG);
+ writel_relaxed(BIT(15), PDM_CLK_NS_REG);
+
+ /* Source the dsi1_byte_clks/dsi1_esc_clk from the DSI PHY PLLs */
+ rmwreg(0x1, DSI1_BYTE_NS_REG, 0x7);
+ rmwreg(0x1, DSI1_ESC_NS_REG, 0x7);
+
+ /* Source the dsi2_byte_clks from the DSI PHY PLLs */
+ rmwreg(0x2, DSI2_BYTE_NS_REG, 0x7);
+
+ /*
* Source the sata_phy_ref_clk from PXO and set predivider of
* sata_pmalive_clk to 1.
*/
- if (soc_class_is_apq8064()) {
- rmwreg(0, SATA_PHY_REF_CLK_CTL_REG, 0x1);
- rmwreg(0, SATA_PMALIVE_CLK_CTL_REG, 0x3);
- }
+ rmwreg(0, SATA_PHY_REF_CLK_CTL_REG, 0x1);
+ rmwreg(0, SATA_PMALIVE_CLK_CTL_REG, 0x3);
/*
* TODO: Programming below PLLs and prng_clk is temporary and
* needs to be removed after bootloaders program them.
*/
- if (soc_class_is_apq8064()) {
- u32 is_pll_enabled;
- /* Program pxo_src_clk to source from PXO */
- rmwreg(0x1, PXO_SRC_CLK_CTL_REG, 0x7);
+ /* Program pxo_src_clk to source from PXO */
+ rmwreg(0x1, PXO_SRC_CLK_CTL_REG, 0x7);
- /* Check if PLL14 is active */
- is_pll_enabled = readl_relaxed(BB_PLL14_STATUS_REG) & BIT(16);
- if (!is_pll_enabled)
- /* Ref clk = 27MHz and program pll14 to 480MHz */
- configure_sr_pll(&pll14_config, &pll14_regs, 1);
+ /* Check if PLL14 is active */
+ is_pll_enabled = readl_relaxed(BB_PLL14_STATUS_REG) & BIT(16);
+ if (!is_pll_enabled)
+ /* Ref clk = 27MHz and program pll14 to 480MHz */
+ configure_sr_pll(&pll14_config, &pll14_regs, 1);
- /* Check if PLL4 is active */
- is_pll_enabled = readl_relaxed(LCC_PLL0_STATUS_REG) & BIT(16);
- if (!is_pll_enabled)
- /* Ref clk = 27MHz and program pll4 to 393.2160MHz */
- configure_sr_pll(&pll4_config_393, &pll4_regs, 1);
+ /* Check if PLL4 is active */
+ is_pll_enabled = readl_relaxed(LCC_PLL0_STATUS_REG) & BIT(16);
+ if (!is_pll_enabled)
+ /* Ref clk = 27MHz and program pll4 to 393.2160MHz */
+ configure_sr_pll(&pll4_config_393, &pll4_regs, 1);
- /* Enable PLL4 source on the LPASS Primary PLL Mux */
- writel_relaxed(0x1, LCC_PRI_PLL_CLK_CTL_REG);
+ /* Enable PLL4 source on the LPASS Primary PLL Mux */
+ writel_relaxed(0x1, LCC_PRI_PLL_CLK_CTL_REG);
- /* Program prng_clk to 64MHz if it isn't configured */
- if (!readl_relaxed(PRNG_CLK_NS_REG))
- writel_relaxed(0x2B, PRNG_CLK_NS_REG);
- }
+ /* Program prng_clk to 64MHz if it isn't configured */
+ if (!readl_relaxed(PRNG_CLK_NS_REG))
+ writel_relaxed(0x2B, PRNG_CLK_NS_REG);
- if (cpu_is_apq8064() || cpu_is_apq8064aa()) {
- /* Program PLL15 to 975MHz with ref clk = 27MHz */
- configure_sr_pll(&pll15_config, &pll15_regs, 0);
- } else if (cpu_is_apq8064ab()) {
+ if (cpu_is_apq8064ab()) {
/* Program PLL15 to 900MHZ */
pll15_config.l = 0x21 | BVAL(31, 7, 0x620);
pll15_config.m = 0x1;
pll15_config.n = 0x3;
- configure_sr_pll(&pll15_config, &pll15_regs, 0);
- } else if (cpu_is_msm8960ab()) {
- pll3_clk.c.rate = 880000000;
- configure_sr_pll(&pll3_config, &pll3_regs, 0);
+ }
+ /*
+ * Default Program PLL15 to 975MHz with ref clk = 27MHz
+ * In case of apq8064ab PLL15 is set to 900MHZ
+ */
+ configure_sr_pll(&pll15_config, &pll15_regs, 0);
+}
+
+static void __init reg_init_8960(void)
+{
+ u32 aen_reg = 0x0003AFF9, aen2_reg = 0x3A27FCFF;
+
+ /* Deassert MM SW_RESET_ALL signal. */
+ writel_relaxed(0, SW_RESET_ALL_REG);
+
+ /*
+ * Initialize MM AHB registers:
+ * Also set VFE_AHB's FORCE_CORE_ON bit to prevent its memory
+ * from being collapsed when the clock is halted. The sleep and
+ * wake-up delays are set to safe values.
+ */
+ rmwreg(0x40000000, AHB_EN_REG, 0x6C000103);
+ writel_relaxed(0x3C7097F9, AHB_EN2_REG);
+
+ /* Deassert all locally-owned MM AHB resets. */
+ rmwreg(0, SW_RESET_AHB_REG, 0xFFF7DFFF);
+ rmwreg(0, SW_RESET_AHB2_REG, 0x0000000F);
+
+ /*
+ * Initialize MM AXI registers: Enable HW gating for all clocks that
+ * support it. Also set FORCE_CORE_ON bits, and any sleep and wake-up
+ * delays to safe values.
+ */
+ if (cpu_is_msm8960() &&
+ SOCINFO_VERSION_MAJOR(socinfo_get_version()) < 3) {
+ aen_reg = 0x000007F9;
+ aen2_reg = 0x3027FCFF;
+ }
+ rmwreg(aen_reg, MAXI_EN_REG, 0x0803FFFF);
+ rmwreg(aen2_reg, MAXI_EN2_REG, 0x3A3FFFFF);
+ rmwreg(0x0027FCFF, MAXI_EN3_REG, 0x003FFFFF);
+ rmwreg(0x0027FCFF, MAXI_EN4_REG, 0x017FFFFF);
+ if (cpu_is_msm8960ab())
+ rmwreg(0x009FE000, MAXI_EN5_REG, 0x01FFE000);
+ rmwreg(0x00003C38, SAXI_EN_REG, 0x00003FFF);
+
+ enable_imem_clk(0x04b00040);
+
+ init_mm_cc();
+ rmwreg(0x80FF0000, DSI2_BYTE_CC_REG, 0xE0FF0010);
+ rmwreg(0x80FF0000, DSI2_PIXEL_CC_REG, 0xE0FF0010);
+ rmwreg(0x80FF0000, JPEGD_CC_REG, 0xE0FF0010);
+ if (cpu_is_msm8960ab()) {
+ rmwreg(0x00000001, DSI2_PIXEL_CC2_REG, 0x00000001);
+ rmwreg(0x00000000, TV_CC_REG, 0x00004010);
+ }
+ if (cpu_is_msm8960()) {
+ rmwreg(0x80FF0000, TV_CC_REG, 0xE1FFC010);
+ rmwreg(0x80FF0000, GFX2D0_CC_REG, 0xE0FF0010);
+ rmwreg(0x80FF0000, GFX2D1_CC_REG, 0xE0FF0010);
}
/*
- * Change PLL15 configuration based on the SoC we're running on.
+ * Initialize USB_HS_HCLK_FS registers: Set FORCE_C_ON bits so that
+ * core remain active during halt state of the clk. Also, set sleep
+ * and wake-up value to max.
*/
- if (cpu_is_msm8930() || cpu_is_msm8930aa() || cpu_is_msm8627()) {
- pll15_config.l = 0x21 | BVAL(31, 7, 0x600);
- pll15_config.m = 0x1;
- pll15_config.n = 0x3;
- configure_sr_pll(&pll15_config, &pll15_regs, 0);
- /* Disable AUX and BIST outputs */
- writel_relaxed(0, MM_PLL3_TEST_CTL_REG);
- } else if (cpu_is_msm8930ab()) {
- pll15_config.l = 0x25 | BVAL(31, 7, 0x600);
- pll15_config.m = 0x25;
- pll15_config.n = 0x3E7;
- configure_sr_pll(&pll15_config, &pll15_regs, 0);
- /* Disable AUX and BIST outputs */
- writel_relaxed(0, MM_PLL3_TEST_CTL_REG);
+ rmwreg(0x0000004F, USB_HS1_HCLK_FS_REG, 0x0000007F);
+
+ /* De-assert MM AXI resets to all hardware blocks. */
+ writel_relaxed(0, SW_RESET_AXI_REG);
+
+ /* Deassert all MM core resets. */
+ writel_relaxed(0, SW_RESET_CORE_REG);
+ writel_relaxed(0, SW_RESET_CORE2_REG);
+
+ /* Enable TSSC and PDM PXO sources. */
+ writel_relaxed(BIT(11), TSSC_CLK_CTL_REG);
+ writel_relaxed(BIT(15), PDM_CLK_NS_REG);
+
+ /* Source the dsi1_byte_clks/dsi1_esc_clk from the DSI PHY PLLs */
+ rmwreg(0x1, DSI1_BYTE_NS_REG, 0x7);
+ rmwreg(0x1, DSI1_ESC_NS_REG, 0x7);
+
+ /* Source SLIMBus xo src from slimbus reference clock */
+ writel_relaxed(0x3, SLIMBUS_XO_SRC_CLK_CTL_REG);
+
+ /* Source the dsi2_byte_clks from the DSI PHY PLLs */
+ rmwreg(0x2, DSI2_BYTE_NS_REG, 0x7);
+
+ if (cpu_is_msm8960ab()) {
+ pll3_clk.c.rate = 880000000;
+ configure_sr_pll(&pll3_config, &pll3_regs, 0);
}
}
@@ -6645,13 +6763,15 @@
}
struct clock_init_data msm8960_clock_init_data __initdata;
+
static void __init msm8960_clock_pre_init(void)
{
- /* Initialize clock registers. */
- reg_init();
+ struct clk_lookup *clk_lkup;
+ size_t clk_size;
+ struct clk_freq_tbl *tbl;
- if (soc_class_is_apq8064())
- vdd_sr2_hdmi_pll.set_vdd = set_vdd_sr2_hdmi_pll_8064;
+ /* Initialize clock registers. */
+ reg_init_8960();
/* Detect PLL4 programmed for alternate 491.52MHz clock plan. */
if (readl_relaxed(LCC_PLL0_L_VAL_REG) == 0x12) {
@@ -6665,73 +6785,120 @@
pcm_clk.freq_tbl = clk_tbl_pcm_492;
}
- if (cpu_is_msm8960() || cpu_is_msm8960ab())
- memcpy(msm_clocks_8960, msm_clocks_8960_common,
- sizeof(msm_clocks_8960_common));
- if (cpu_is_msm8960ab()) {
- gfx3d_clk.freq_tbl = clk_tbl_gfx3d_8960ab;
- mdp_clk.c.fmax = fmax_mdp_8960ab;
-
- gfx3d_clk.c.fmax = select_gfx_fmax_plan(fmax_gfx3d_8960ab,
- ARRAY_SIZE(fmax_gfx3d_8960ab));
-
- memcpy(msm_clocks_8960 + ARRAY_SIZE(msm_clocks_8960_common),
- msm_clocks_8960ab_only, sizeof(msm_clocks_8960ab_only));
- msm8960_clock_init_data.size -=
- ARRAY_SIZE(msm_clocks_8960_only);
-
- gmem_axi_clk.c.depends = &gfx3d_axi_clk.c;
- } else if (cpu_is_msm8960()) {
- gfx3d_clk.freq_tbl = clk_tbl_gfx3d_8960;
- memcpy(msm_clocks_8960 + ARRAY_SIZE(msm_clocks_8960_common),
- msm_clocks_8960_only, sizeof(msm_clocks_8960_only));
+ if (cpu_is_msm8960()) {
+ tbl = clk_tbl_gfx3d_8960;
+ clk_lkup = msm_clocks_8960_only;
+ clk_size = sizeof(msm_clocks_8960_only);
msm8960_clock_init_data.size -=
ARRAY_SIZE(msm_clocks_8960ab_only);
}
- /*
- * Change the freq tables for and voltage requirements for
- * clocks which differ between chips.
- */
- if (cpu_is_apq8064() || cpu_is_apq8064aa())
- gfx3d_clk.c.fmax = fmax_gfx3d_8064;
+
+ if (cpu_is_msm8960ab()) {
+ mdp_clk.c.fmax = fmax_mdp_8960ab;
+ gmem_axi_clk.c.depends = &gfx3d_axi_clk.c;
+ tbl = clk_tbl_gfx3d_8960ab;
+ gfx3d_clk.c.fmax = select_gfx_fmax_plan(fmax_gfx3d_8960ab,
+ ARRAY_SIZE(fmax_gfx3d_8960ab));
+
+ clk_lkup = msm_clocks_8960ab_only;
+ clk_size = sizeof(msm_clocks_8960ab_only);
+ msm8960_clock_init_data.size -=
+ ARRAY_SIZE(msm_clocks_8960_only);
+ }
+
+ gfx3d_clk.freq_tbl = tbl;
+
+ memcpy(msm_clocks_8960, msm_clocks_8960_common,
+ sizeof(msm_clocks_8960_common));
+ memcpy(msm_clocks_8960 + ARRAY_SIZE(msm_clocks_8960_common),
+ clk_lkup, clk_size);
+
+ if ((readl_relaxed(PRNG_CLK_NS_REG) & 0x7F) == 0x2B)
+ prng_clk.freq_tbl = clk_tbl_prng_64;
+
+ clk_ops_local_pll.enable = sr_pll_clk_enable;
+}
+
+static void __init msm8064_clock_pre_init(void)
+{
+ unsigned long *fmax = fmax_gfx3d_8064;
+
+ /* Initialize clock registers. */
+ reg_init_8064();
+
+ vdd_sr2_hdmi_pll.set_vdd = set_vdd_sr2_hdmi_pll_8064;
+
+ /* Detect PLL4 programmed for alternate 491.52MHz clock plan. */
+ if (readl_relaxed(LCC_PLL0_L_VAL_REG) == 0x12) {
+ pll4_clk.c.rate = 491520000;
+ audio_slimbus_clk.freq_tbl = clk_tbl_aif_osr_492;
+ mi2s_osr_clk.freq_tbl = clk_tbl_aif_osr_492;
+ codec_i2s_mic_osr_clk.freq_tbl = clk_tbl_aif_osr_492;
+ spare_i2s_mic_osr_clk.freq_tbl = clk_tbl_aif_osr_492;
+ codec_i2s_spkr_osr_clk.freq_tbl = clk_tbl_aif_osr_492;
+ spare_i2s_spkr_osr_clk.freq_tbl = clk_tbl_aif_osr_492;
+ pcm_clk.freq_tbl = clk_tbl_pcm_492;
+ }
if (cpu_is_apq8064ab())
- gfx3d_clk.c.fmax = fmax_gfx3d_8064ab;
+ fmax = fmax_gfx3d_8064ab;
if ((cpu_is_apq8064() &&
SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 2) ||
cpu_is_apq8064ab() || cpu_is_apq8064aa()) {
-
vcodec_clk.c.fmax = fmax_vcodec_8064v2;
ce3_src_clk.c.fmax = fmax_ce3_8064v2;
sdc1_clk.c.fmax = fmax_sdc1_8064v2;
}
- if (soc_class_is_apq8064()) {
- ijpeg_clk.c.fmax = fmax_ijpeg_8064;
- mdp_clk.c.fmax = fmax_mdp_8064;
- tv_src_clk.c.fmax = fmax_tv_src_8064;
- vfe_clk.c.fmax = fmax_vfe_8064;
- gmem_axi_clk.c.depends = &gfx3d_axi_clk.c;
+
+ gfx3d_clk.c.fmax = fmax;
+ ijpeg_clk.c.fmax = fmax_ijpeg_8064;
+ mdp_clk.c.fmax = fmax_mdp_8064;
+ tv_src_clk.c.fmax = fmax_tv_src_8064;
+ vfe_clk.c.fmax = fmax_vfe_8064;
+
+ gmem_axi_clk.c.depends = &gfx3d_axi_clk.c;
+
+ if ((readl_relaxed(PRNG_CLK_NS_REG) & 0x7F) == 0x2B)
+ prng_clk.freq_tbl = clk_tbl_prng_64;
+
+ clk_ops_local_pll.enable = sr_pll_clk_enable;
+}
+
+static void __init __msm8930_clock_pre_init(void)
+{
+ unsigned long rate = 900000000;
+ unsigned long *fmax = fmax_gfx3d_8930;
+
+ /* Initialize clock registers. */
+ reg_init_8930();
+
+ /* Detect PLL4 programmed for alternate 491.52MHz clock plan. */
+ if (readl_relaxed(LCC_PLL0_L_VAL_REG) == 0x12) {
+ pll4_clk.c.rate = 491520000;
+ audio_slimbus_clk.freq_tbl = clk_tbl_aif_osr_492;
+ mi2s_osr_clk.freq_tbl = clk_tbl_aif_osr_492;
+ codec_i2s_mic_osr_clk.freq_tbl = clk_tbl_aif_osr_492;
+ spare_i2s_mic_osr_clk.freq_tbl = clk_tbl_aif_osr_492;
+ codec_i2s_spkr_osr_clk.freq_tbl = clk_tbl_aif_osr_492;
+ spare_i2s_spkr_osr_clk.freq_tbl = clk_tbl_aif_osr_492;
+ pcm_clk.freq_tbl = clk_tbl_pcm_492;
}
- /*
- * Change the freq tables and voltage requirements for
- * clocks which differ between 8960 and 8930.
- */
- if (cpu_is_msm8930() || cpu_is_msm8627())
- gfx3d_clk.c.fmax = fmax_gfx3d_8930;
- else if (cpu_is_msm8930aa())
- gfx3d_clk.c.fmax = fmax_gfx3d_8930aa;
- if (cpu_is_msm8930() || cpu_is_msm8930aa() || cpu_is_msm8627()) {
- pll15_clk.c.rate = 900000000;
- gmem_axi_clk.c.depends = &gfx3d_axi_clk_8930.c;
- } else if (cpu_is_msm8930ab()) {
+ if (cpu_is_msm8930aa())
+ fmax = fmax_gfx3d_8930aa;
+
+ if (cpu_is_msm8930ab()) {
+ rate = 1000000000;
+ fmax = fmax_gfx3d_8930ab;
gfx3d_clk.freq_tbl = clk_tbl_gfx3d_8930ab;
- pll15_clk.c.rate = 1000000000;
- gfx3d_clk.c.fmax = fmax_gfx3d_8930ab;
- gmem_axi_clk.c.depends = &gfx3d_axi_clk_8930.c;
vcodec_clk.c.fmax = fmax_vcodec_8930ab;
}
+
+ pll15_clk.c.rate = rate;
+ gfx3d_clk.c.fmax = fmax;
+ gmem_axi_clk.c.depends = &gfx3d_axi_clk_8930.c;
+
if ((readl_relaxed(PRNG_CLK_NS_REG) & 0x7F) == 0x2B)
prng_clk.freq_tbl = clk_tbl_prng_64;
@@ -6746,7 +6913,7 @@
rpm_vreg_dig_8930 = RPM_VREG_ID_PM8917_VDD_DIG_CORNER;
vdd_sr2_hdmi_pll.set_vdd = set_vdd_sr2_hdmi_pll_8930_pm8917;
- msm8960_clock_pre_init();
+ __msm8930_clock_pre_init();
}
static void __init msm8930_clock_pre_init(void)
@@ -6754,10 +6921,10 @@
vdd_dig.set_vdd = set_vdd_dig_8930;
vdd_sr2_hdmi_pll.set_vdd = set_vdd_sr2_hdmi_pll_8930;
- msm8960_clock_pre_init();
+ __msm8930_clock_pre_init();
}
-static void __init msm8960_clock_post_init(void)
+static void __init common_clock_post_init(void)
{
/* Keep PXO on whenever APPS cpu is active */
clk_prepare_enable(&pxo_a_clk.c);
@@ -6777,18 +6944,12 @@
clk_set_rate(&tsif_ref_clk.c, 105000);
clk_set_rate(&tssc_clk.c, 27000000);
clk_set_rate(&usb_hs1_xcvr_clk.c, 60000000);
- if (soc_class_is_apq8064()) {
- clk_set_rate(&usb_hs3_xcvr_clk.c, 60000000);
- clk_set_rate(&usb_hs4_xcvr_clk.c, 60000000);
- }
clk_set_rate(&usb_fs1_src_clk.c, 60000000);
- if (cpu_is_msm8960ab() || cpu_is_msm8960() || cpu_is_msm8930() ||
- cpu_is_msm8930aa() || cpu_is_msm8627() || cpu_is_msm8930ab())
- clk_set_rate(&usb_fs2_src_clk.c, 60000000);
clk_set_rate(&usb_hsic_xcvr_fs_clk.c, 60000000);
clk_set_rate(&usb_hsic_hsic_src_clk.c, 480000000);
clk_set_rate(&usb_hsic_hsio_cal_clk.c, 9000000);
clk_set_rate(&usb_hsic_system_clk.c, 60000000);
+
/*
* Set the CSI rates to a safe default to avoid warnings when
* switching csi pix and rdi clocks.
@@ -6817,6 +6978,19 @@
clk_prepare_enable(&sfab_tmr_a_clk.c);
}
+static void __init msm8960_clock_post_init(void)
+{
+ common_clock_post_init();
+ clk_set_rate(&usb_fs2_src_clk.c, 60000000);
+}
+
+static void __init msm8064_clock_post_init(void)
+{
+ common_clock_post_init();
+ clk_set_rate(&usb_hs3_xcvr_clk.c, 60000000);
+ clk_set_rate(&usb_hs4_xcvr_clk.c, 60000000);
+}
+
static int __init msm8960_clock_late_init(void)
{
int rc;
@@ -6859,8 +7033,8 @@
struct clock_init_data apq8064_clock_init_data __initdata = {
.table = msm_clocks_8064,
.size = ARRAY_SIZE(msm_clocks_8064),
- .pre_init = msm8960_clock_pre_init,
- .post_init = msm8960_clock_post_init,
+ .pre_init = msm8064_clock_pre_init,
+ .post_init = msm8064_clock_post_init,
.late_init = msm8960_clock_late_init,
};
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index 707e6b6..f5af727 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -638,7 +638,7 @@
VDD_DIG_NUM
};
-static const int *vdd_corner[] = {
+static int *vdd_corner[] = {
[VDD_DIG_NONE] = VDD_UV(RPM_REGULATOR_CORNER_NONE),
[VDD_DIG_LOW] = VDD_UV(RPM_REGULATOR_CORNER_SVS_SOC),
[VDD_DIG_NOMINAL] = VDD_UV(RPM_REGULATOR_CORNER_NORMAL),
@@ -920,6 +920,7 @@
};
static struct clk_freq_tbl ftbl_gcc_blsp1_2_qup1_6_i2c_apps_clk[] = {
+ F(19200000, cxo, 1, 0, 0),
F(50000000, gpll0, 12, 0, 0),
F_END
};
@@ -4894,6 +4895,7 @@
CLK_LOOKUP("alt_iface_clk", mdss_hdmi_ahb_clk.c,
"fd922100.qcom,hdmi_tx"),
CLK_LOOKUP("core_clk", mdss_hdmi_clk.c, "fd922100.qcom,hdmi_tx"),
+ CLK_LOOKUP("mdp_core_clk", mdss_mdp_clk.c, "fd922100.qcom,hdmi_tx"),
CLK_LOOKUP("extp_clk", mdss_extpclk_clk.c, "fd922100.qcom,hdmi_tx"),
CLK_LOOKUP("core_clk", mdss_mdp_clk.c, "mdp.0"),
CLK_LOOKUP("lut_clk", mdss_mdp_lut_clk.c, "mdp.0"),
@@ -5121,6 +5123,17 @@
CLK_LOOKUP("bus_clk", venus0_axi_clk.c, "fdc00000.qcom,vidc"),
CLK_LOOKUP("mem_clk", venus0_ocmemnoc_clk.c, "fdc00000.qcom,vidc"),
+ CLK_LOOKUP("core_clk", venus0_vcodec0_clk.c, "fd8c1024.qcom,gdsc"),
+ CLK_LOOKUP("core_clk", mdss_mdp_clk.c, "fd8c2304.qcom,gdsc"),
+ CLK_LOOKUP("lut_clk", mdss_mdp_lut_clk.c, "fd8c2304.qcom,gdsc"),
+ CLK_LOOKUP("core0_clk", camss_jpeg_jpeg0_clk.c, "fd8c35a4.qcom,gdsc"),
+ CLK_LOOKUP("core1_clk", camss_jpeg_jpeg1_clk.c, "fd8c35a4.qcom,gdsc"),
+ CLK_LOOKUP("core2_clk", camss_jpeg_jpeg2_clk.c, "fd8c35a4.qcom,gdsc"),
+ CLK_LOOKUP("core0_clk", camss_vfe_vfe0_clk.c, "fd8c36a4.qcom,gdsc"),
+ CLK_LOOKUP("core1_clk", camss_vfe_vfe1_clk.c, "fd8c36a4.qcom,gdsc"),
+ CLK_LOOKUP("csi0_clk", camss_csi_vfe0_clk.c, "fd8c36a4.qcom,gdsc"),
+ CLK_LOOKUP("csi1_clk", camss_csi_vfe1_clk.c, "fd8c36a4.qcom,gdsc"),
+ CLK_LOOKUP("cpp_clk", camss_vfe_cpp_clk.c, "fd8c36a4.qcom,gdsc"),
CLK_LOOKUP("core_clk", oxili_gfx3d_clk.c, "fd8c4024.qcom,gdsc"),
/* LPASS clocks */
diff --git a/arch/arm/mach-msm/clock-9625.c b/arch/arm/mach-msm/clock-9625.c
index 9a768e5..65176b4 100644
--- a/arch/arm/mach-msm/clock-9625.c
+++ b/arch/arm/mach-msm/clock-9625.c
@@ -280,7 +280,7 @@
VDD_DIG_NUM
};
-static const int *vdd_corner[] = {
+static int *vdd_corner[] = {
[VDD_DIG_NONE] = VDD_UV(RPM_REGULATOR_CORNER_NONE),
[VDD_DIG_LOW] = VDD_UV(RPM_REGULATOR_CORNER_SVS_SOC),
[VDD_DIG_NOMINAL] = VDD_UV(RPM_REGULATOR_CORNER_NORMAL),
diff --git a/arch/arm/mach-msm/clock-generic.c b/arch/arm/mach-msm/clock-generic.c
new file mode 100644
index 0000000..4d74533
--- /dev/null
+++ b/arch/arm/mach-msm/clock-generic.c
@@ -0,0 +1,405 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+
+#include <linux/clk.h>
+#include <mach/clk-provider.h>
+#include <mach/clock-generic.h>
+
+/* ==================== Mux clock ==================== */
+
+static int parent_to_src_sel(struct mux_clk *mux, struct clk *p)
+{
+ int i;
+
+ for (i = 0; i < mux->num_parents; i++) {
+ if (mux->parents[i].src == p)
+ return mux->parents[i].sel;
+ }
+
+ return -EINVAL;
+}
+
+static int mux_set_parent(struct clk *c, struct clk *p)
+{
+ struct mux_clk *mux = to_mux_clk(c);
+ int sel = parent_to_src_sel(mux, p);
+ struct clk *old_parent;
+ int rc = 0;
+ unsigned long flags;
+
+ if (sel < 0)
+ return sel;
+
+ rc = __clk_pre_reparent(c, p, &flags);
+ if (rc)
+ goto out;
+
+ rc = mux->ops->set_mux_sel(mux, sel);
+ if (rc)
+ goto set_fail;
+
+ old_parent = c->parent;
+ c->parent = p;
+ __clk_post_reparent(c, old_parent, &flags);
+
+ return 0;
+
+set_fail:
+ __clk_post_reparent(c, p, &flags);
+out:
+ return rc;
+}
+
+static long mux_round_rate(struct clk *c, unsigned long rate)
+{
+ struct mux_clk *mux = to_mux_clk(c);
+ int i;
+ long prate, max_prate = 0, rrate = LONG_MAX;
+
+ for (i = 0; i < mux->num_parents; i++) {
+ prate = clk_round_rate(mux->parents[i].src, rate);
+ if (prate < rate) {
+ max_prate = max(prate, max_prate);
+ continue;
+ }
+
+ rrate = min(rrate, prate);
+ }
+ if (rrate == LONG_MAX)
+ rrate = max_prate;
+
+ return rrate ? rrate : -EINVAL;
+}
+
+static int mux_set_rate(struct clk *c, unsigned long rate)
+{
+ struct mux_clk *mux = to_mux_clk(c);
+ struct clk *new_parent = NULL;
+ int rc = 0, i;
+ unsigned long new_par_curr_rate;
+
+ for (i = 0; i < mux->num_parents; i++) {
+ if (clk_round_rate(mux->parents[i].src, rate) == rate) {
+ new_parent = mux->parents[i].src;
+ break;
+ }
+ }
+ if (new_parent == NULL)
+ return -EINVAL;
+
+ /*
+ * Switch to safe parent since the old and new parent might be the
+ * same and the parent might temporarily turn off while switching
+ * rates.
+ */
+ if (mux->safe_sel >= 0)
+ rc = mux->ops->set_mux_sel(mux, mux->safe_sel);
+ if (rc)
+ return rc;
+
+ new_par_curr_rate = clk_get_rate(new_parent);
+ rc = clk_set_rate(new_parent, rate);
+ if (rc)
+ goto set_rate_fail;
+
+ rc = mux_set_parent(c, new_parent);
+ if (rc)
+ goto set_par_fail;
+
+ return 0;
+
+set_par_fail:
+ clk_set_rate(new_parent, new_par_curr_rate);
+set_rate_fail:
+ WARN(mux->ops->set_mux_sel(mux, parent_to_src_sel(mux, c->parent)),
+ "Set rate failed for %s. Also in bad state!\n", c->dbg_name);
+ return rc;
+}
+
+static int mux_enable(struct clk *c)
+{
+ struct mux_clk *mux = to_mux_clk(c);
+ if (mux->ops->enable)
+ return mux->ops->enable(mux);
+ return 0;
+}
+
+static void mux_disable(struct clk *c)
+{
+ struct mux_clk *mux = to_mux_clk(c);
+ if (mux->ops->disable)
+ return mux->ops->disable(mux);
+}
+
+static struct clk *mux_get_parent(struct clk *c)
+{
+ struct mux_clk *mux = to_mux_clk(c);
+ int sel = mux->ops->get_mux_sel(mux);
+ int i;
+
+ for (i = 0; i < mux->num_parents; i++) {
+ if (mux->parents[i].sel == sel)
+ return mux->parents[i].src;
+ }
+
+ /* Unfamiliar parent. */
+ return NULL;
+}
+
+static enum handoff mux_handoff(struct clk *c)
+{
+ struct mux_clk *mux = to_mux_clk(c);
+
+ c->rate = clk_get_rate(c->parent);
+ mux->safe_sel = parent_to_src_sel(mux, mux->safe_parent);
+
+ if (mux->en_mask && mux->ops && mux->ops->is_enabled)
+ return mux->ops->is_enabled(mux)
+ ? HANDOFF_ENABLED_CLK
+ : HANDOFF_DISABLED_CLK;
+
+ /*
+ * If this function returns 'enabled' even when the clock downstream
+ * of this clock is disabled, then handoff code will unnecessarily
+ * enable the current parent of this clock. If this function always
+ * returns 'disabled' and a clock downstream is on, the clock handoff
+ * code will bump up the ref count for this clock and its current
+ * parent as necessary. So, clocks without an actual HW gate can
+ * always return disabled.
+ */
+ return HANDOFF_DISABLED_CLK;
+}
+
+struct clk_ops clk_ops_gen_mux = {
+ .enable = mux_enable,
+ .disable = mux_disable,
+ .set_parent = mux_set_parent,
+ .round_rate = mux_round_rate,
+ .set_rate = mux_set_rate,
+ .handoff = mux_handoff,
+ .get_parent = mux_get_parent,
+};
+
+
+/* ==================== Divider clock ==================== */
+
+static long __div_round_rate(struct clk *c, unsigned long rate, int *best_div)
+{
+ struct div_clk *d = to_div_clk(c);
+ unsigned int div, min_div, max_div;
+ long p_rrate, rrate = LONG_MAX;
+
+ rate = max(rate, 1UL);
+
+ if (!d->ops || !d->ops->set_div)
+ min_div = max_div = d->div;
+ else {
+ min_div = max(d->min_div, 1U);
+ max_div = min(d->max_div, (unsigned int) (LONG_MAX / rate));
+ }
+
+ for (div = min_div; div <= max_div; div++) {
+ p_rrate = clk_round_rate(c->parent, rate * div);
+ if (p_rrate < 0)
+ break;
+
+ p_rrate /= div;
+ /*
+ * Trying higher dividers is only going to ask the parent for
+ * a higher rate. If it can't even output a rate higher than
+ * the one we request for this divider, the parent is not
+ * going to be able to output an even higher rate required
+ * for a higher divider. So, stop trying higher dividers.
+ */
+ if (p_rrate < rate) {
+ if (rrate == LONG_MAX) {
+ rrate = p_rrate;
+ if (best_div)
+ *best_div = div;
+ }
+ break;
+ }
+ if (p_rrate < rrate) {
+ rrate = p_rrate;
+ if (best_div)
+ *best_div = div;
+ }
+
+ if (rrate <= rate + d->rate_margin)
+ break;
+ }
+
+ if (rrate == LONG_MAX)
+ return -EINVAL;
+
+ return rrate;
+}
+
+static long div_round_rate(struct clk *c, unsigned long rate)
+{
+ return __div_round_rate(c, rate, NULL);
+}
+
+static int div_set_rate(struct clk *c, unsigned long rate)
+{
+ struct div_clk *d = to_div_clk(c);
+ int div, rc = 0;
+ long rrate, old_prate;
+
+ rrate = __div_round_rate(c, rate, &div);
+ if (rrate != rate)
+ return -EINVAL;
+
+ if (div > d->div)
+ rc = d->ops->set_div(d, div);
+ if (rc)
+ return rc;
+
+ old_prate = clk_get_rate(c->parent);
+ rc = clk_set_rate(c->parent, rate * div);
+ if (rc)
+ goto set_rate_fail;
+
+ if (div < d->div)
+ rc = d->ops->set_div(d, div);
+ if (rc)
+ goto div_dec_fail;
+
+ d->div = div;
+
+ return 0;
+
+div_dec_fail:
+ WARN(clk_set_rate(c->parent, old_prate),
+ "Set rate failed for %s. Also in bad state!\n", c->dbg_name);
+set_rate_fail:
+ if (div > d->div)
+ WARN(d->ops->set_div(d, d->div),
+ "Set rate failed for %s. Also in bad state!\n",
+ c->dbg_name);
+ return rc;
+}
+
+static int div_enable(struct clk *c)
+{
+ struct div_clk *d = to_div_clk(c);
+ if (d->ops->enable)
+ return d->ops->enable(d);
+ return 0;
+}
+
+static void div_disable(struct clk *c)
+{
+ struct div_clk *d = to_div_clk(c);
+ if (d->ops->disable)
+ return d->ops->disable(d);
+}
+
+static enum handoff div_handoff(struct clk *c)
+{
+ struct div_clk *d = to_div_clk(c);
+
+ if (d->ops->get_div)
+ d->div = max(d->ops->get_div(d), 1);
+ d->div = max(d->div, 1U);
+ c->rate = clk_get_rate(c->parent) / d->div;
+
+ if (d->en_mask && d->ops && d->ops->is_enabled)
+ return d->ops->is_enabled(d)
+ ? HANDOFF_ENABLED_CLK
+ : HANDOFF_DISABLED_CLK;
+
+ /*
+ * If this function returns 'enabled' even when the clock downstream
+ * of this clock is disabled, then handoff code will unnecessarily
+ * enable the current parent of this clock. If this function always
+ * returns 'disabled' and a clock downstream is on, the clock handoff
+ * code will bump up the ref count for this clock and its current
+ * parent as necessary. So, clocks without an actual HW gate can
+ * always return disabled.
+ */
+ return HANDOFF_DISABLED_CLK;
+}
+
+struct clk_ops clk_ops_div = {
+ .enable = div_enable,
+ .disable = div_disable,
+ .round_rate = div_round_rate,
+ .set_rate = div_set_rate,
+ .handoff = div_handoff,
+};
+
+static long __slave_div_round_rate(struct clk *c, unsigned long rate,
+ int *best_div)
+{
+ struct div_clk *d = to_div_clk(c);
+ unsigned int div, min_div, max_div;
+ long p_rate;
+
+ rate = max(rate, 1UL);
+
+ if (!d->ops || !d->ops->set_div)
+ min_div = max_div = d->div;
+ else {
+ min_div = d->min_div;
+ max_div = d->max_div;
+ }
+
+ p_rate = clk_get_rate(c->parent);
+ div = p_rate / rate;
+ div = max(div, min_div);
+ div = min(div, max_div);
+ if (best_div)
+ *best_div = div;
+
+ return p_rate / div;
+}
+
+static long slave_div_round_rate(struct clk *c, unsigned long rate)
+{
+ return __slave_div_round_rate(c, rate, NULL);
+}
+
+static int slave_div_set_rate(struct clk *c, unsigned long rate)
+{
+ struct div_clk *d = to_div_clk(c);
+ int div, rc = 0;
+ long rrate;
+
+ rrate = __slave_div_round_rate(c, rate, &div);
+ if (rrate != rate)
+ return -EINVAL;
+
+ if (div == d->div)
+ return 0;
+
+ if (d->ops->set_div)
+ rc = d->ops->set_div(d, div);
+ if (rc)
+ return rc;
+
+ d->div = div;
+
+ return 0;
+}
+
+struct clk_ops clk_ops_slave_div = {
+ .enable = div_enable,
+ .disable = div_disable,
+ .round_rate = slave_div_round_rate,
+ .set_rate = slave_div_set_rate,
+ .handoff = div_handoff,
+};
diff --git a/arch/arm/mach-msm/clock-local2.c b/arch/arm/mach-msm/clock-local2.c
index f6c11b0..e67d973 100644
--- a/arch/arm/mach-msm/clock-local2.c
+++ b/arch/arm/mach-msm/clock-local2.c
@@ -667,7 +667,7 @@
return HANDOFF_ENABLED_CLK;
}
-static enum handoff byte_rcg_handoff(struct clk *clk)
+enum handoff byte_rcg_handoff(struct clk *clk)
{
struct rcg_clk *rcg = to_rcg_clk(clk);
u32 div_val;
@@ -718,7 +718,7 @@
return 0;
}
-static enum handoff pixel_rcg_handoff(struct clk *clk)
+enum handoff pixel_rcg_handoff(struct clk *clk)
{
struct rcg_clk *rcg = to_rcg_clk(clk);
u32 div_val, mval, nval, cfg_regval;
@@ -815,18 +815,18 @@
/*
* mux clock functions
*/
-static void mux_clk_halt_check(void)
+static void cam_mux_clk_halt_check(void)
{
/* Ensure that the delay starts after the mux disable/enable. */
mb();
udelay(HALT_CHECK_DELAY_US);
}
-static int mux_clk_enable(struct clk *c)
+static int cam_mux_clk_enable(struct clk *c)
{
unsigned long flags;
u32 regval;
- struct mux_clk *mux = to_mux_clk(c);
+ struct cam_mux_clk *mux = to_cam_mux_clk(c);
spin_lock_irqsave(&local_clock_reg_lock, flags);
regval = readl_relaxed(ENABLE_REG(mux));
@@ -835,15 +835,15 @@
spin_unlock_irqrestore(&local_clock_reg_lock, flags);
/* Wait for clock to enable before continuing. */
- mux_clk_halt_check();
+ cam_mux_clk_halt_check();
return 0;
}
-static void mux_clk_disable(struct clk *c)
+static void cam_mux_clk_disable(struct clk *c)
{
unsigned long flags;
- struct mux_clk *mux = to_mux_clk(c);
+ struct cam_mux_clk *mux = to_cam_mux_clk(c);
u32 regval;
spin_lock_irqsave(&local_clock_reg_lock, flags);
@@ -853,10 +853,10 @@
spin_unlock_irqrestore(&local_clock_reg_lock, flags);
/* Wait for clock to disable before continuing. */
- mux_clk_halt_check();
+ cam_mux_clk_halt_check();
}
-static int mux_source_switch(struct mux_clk *mux, struct mux_source *dest)
+static int mux_source_switch(struct cam_mux_clk *mux, struct mux_source *dest)
{
unsigned long flags;
u32 regval;
@@ -879,9 +879,9 @@
return ret;
}
-static int mux_clk_set_parent(struct clk *c, struct clk *parent)
+static int cam_mux_clk_set_parent(struct clk *c, struct clk *parent)
{
- struct mux_clk *mux = to_mux_clk(c);
+ struct cam_mux_clk *mux = to_cam_mux_clk(c);
struct mux_source *dest = NULL;
int ret;
@@ -908,9 +908,9 @@
return 0;
}
-static enum handoff mux_clk_handoff(struct clk *c)
+static enum handoff cam_mux_clk_handoff(struct clk *c)
{
- struct mux_clk *mux = to_mux_clk(c);
+ struct cam_mux_clk *mux = to_cam_mux_clk(c);
u32 mask = mux->enable_mask;
u32 regval = readl_relaxed(ENABLE_REG(mux));
@@ -922,9 +922,9 @@
return HANDOFF_DISABLED_CLK;
}
-static struct clk *mux_clk_get_parent(struct clk *c)
+static struct clk *cam_mux_clk_get_parent(struct clk *c)
{
- struct mux_clk *mux = to_mux_clk(c);
+ struct cam_mux_clk *mux = to_cam_mux_clk(c);
struct mux_source *parent = NULL;
u32 regval = readl_relaxed(SELECT_REG(mux));
@@ -943,9 +943,9 @@
return ERR_PTR(-EPERM);
}
-static int mux_clk_list_rate(struct clk *c, unsigned n)
+static int cam_mux_clk_list_rate(struct clk *c, unsigned n)
{
- struct mux_clk *mux = to_mux_clk(c);
+ struct cam_mux_clk *mux = to_cam_mux_clk(c);
int i;
for (i = 0; i < n; i++)
@@ -1022,13 +1022,13 @@
.handoff = local_vote_clk_handoff,
};
-struct clk_ops clk_ops_mux = {
- .enable = mux_clk_enable,
- .disable = mux_clk_disable,
- .set_parent = mux_clk_set_parent,
- .get_parent = mux_clk_get_parent,
- .handoff = mux_clk_handoff,
- .list_rate = mux_clk_list_rate,
+struct clk_ops clk_ops_cam_mux = {
+ .enable = cam_mux_clk_enable,
+ .disable = cam_mux_clk_disable,
+ .set_parent = cam_mux_clk_set_parent,
+ .get_parent = cam_mux_clk_get_parent,
+ .handoff = cam_mux_clk_handoff,
+ .list_rate = cam_mux_clk_list_rate,
};
diff --git a/arch/arm/mach-msm/clock-local2.h b/arch/arm/mach-msm/clock-local2.h
index 7882edb..f307a2f 100644
--- a/arch/arm/mach-msm/clock-local2.h
+++ b/arch/arm/mach-msm/clock-local2.h
@@ -163,7 +163,7 @@
};
/**
- * struct mux_clk - branch clock
+ * struct cam_mux_clk - branch clock
* @c: clk
* @enable_reg: register that contains the enable bit(s) for the mux
* @select_reg: register that contains the source selection bits for the mux
@@ -172,7 +172,7 @@
* @sources: list of mux sources
* @base: pointer to base address of ioremapped registers.
*/
-struct mux_clk {
+struct cam_mux_clk {
struct clk c;
const u32 enable_reg;
const u32 select_reg;
@@ -184,9 +184,9 @@
void *const __iomem *base;
};
-static inline struct mux_clk *to_mux_clk(struct clk *clk)
+static inline struct cam_mux_clk *to_cam_mux_clk(struct clk *clk)
{
- return container_of(clk, struct mux_clk, c);
+ return container_of(clk, struct cam_mux_clk, c);
}
/*
@@ -200,7 +200,7 @@
*/
extern spinlock_t local_clock_reg_lock;
-extern struct clk_ops clk_ops_mux;
+extern struct clk_ops clk_ops_cam_mux;
extern struct clk_ops clk_ops_empty;
extern struct clk_ops clk_ops_rcg;
extern struct clk_ops clk_ops_rcg_mnd;
@@ -210,6 +210,9 @@
extern struct clk_ops clk_ops_byte;
extern struct clk_ops clk_ops_pixel;
+enum handoff pixel_rcg_handoff(struct clk *clk);
+enum handoff byte_rcg_handoff(struct clk *clk);
+
/*
* Clock definition macros
*/
diff --git a/arch/arm/mach-msm/clock.c b/arch/arm/mach-msm/clock.c
index 044fc2c..2e12e27 100644
--- a/arch/arm/mach-msm/clock.c
+++ b/arch/arm/mach-msm/clock.c
@@ -62,7 +62,7 @@
{
int level, rc = 0, i;
struct regulator **r = vdd_class->regulator;
- const int **vdd_uv = vdd_class->vdd_uv;
+ int **vdd_uv = vdd_class->vdd_uv;
int max_level = vdd_class->num_levels - 1;
for (level = max_level; level > 0; level--)
diff --git a/arch/arm/mach-msm/cpufreq.c b/arch/arm/mach-msm/cpufreq.c
index d02ab66..d5084e4 100644
--- a/arch/arm/mach-msm/cpufreq.c
+++ b/arch/arm/mach-msm/cpufreq.c
@@ -3,7 +3,7 @@
* MSM architecture cpufreq driver
*
* Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2007-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2007-2013, The Linux Foundation. All rights reserved.
* Author: Mike A. Chan <mikechan@google.com>
*
* This software is licensed under the terms of the GNU General Public
@@ -261,6 +261,7 @@
{
int cur_freq;
int index;
+ int ret = 0;
struct cpufreq_frequency_table *table;
struct cpufreq_work_struct *cpu_work = NULL;
@@ -296,19 +297,16 @@
policy->cpu, cur_freq);
return -EINVAL;
}
-
- if (cur_freq != table[index].frequency) {
- int ret = 0;
- ret = acpuclk_set_rate(policy->cpu, table[index].frequency,
- SETRATE_CPUFREQ);
- if (ret)
- return ret;
- pr_info("cpufreq: cpu%d init at %d switching to %d\n",
- policy->cpu, cur_freq, table[index].frequency);
- cur_freq = table[index].frequency;
- }
-
- policy->cur = cur_freq;
+ /*
+ * Call set_cpu_freq unconditionally so that when cpu is set to
+ * online, frequency limit will always be updated.
+ */
+ ret = set_cpu_freq(policy, table[index].frequency);
+ if (ret)
+ return ret;
+ pr_debug("cpufreq: cpu%d init at %d switching to %d\n",
+ policy->cpu, cur_freq, table[index].frequency);
+ policy->cur = table[index].frequency;
policy->cpuinfo.transition_latency =
acpuclk_get_switch_time() * NSEC_PER_USEC;
@@ -410,4 +408,4 @@
return cpufreq_register_driver(&msm_cpufreq_driver);
}
-late_initcall(msm_cpufreq_register);
+device_initcall(msm_cpufreq_register);
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index 837aef3..cb8ffc1 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -2510,6 +2510,11 @@
.id = -1,
};
+struct platform_device msm_fm_loopback = {
+ .name = "msm-pcm-loopback",
+ .id = -1,
+};
+
static struct fs_driver_data gfx2d0_fs_data = {
.clks = (struct fs_clk_data[]){
{ .name = "core_clk" },
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index 327c11d..eb12383 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -260,6 +260,7 @@
extern struct platform_device msm_i2s_cpudai4;
extern struct platform_device msm_i2s_cpudai5;
extern struct platform_device msm_cpudai_stub;
+extern struct platform_device msm_fm_loopback;
extern struct platform_device msm_pil_q6v3;
extern struct platform_device msm_pil_modem;
diff --git a/arch/arm/mach-msm/gdsc.c b/arch/arm/mach-msm/gdsc.c
index 6665d66..30a034e 100644
--- a/arch/arm/mach-msm/gdsc.c
+++ b/arch/arm/mach-msm/gdsc.c
@@ -22,6 +22,7 @@
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/of_regulator.h>
+#include <linux/slab.h>
#include <linux/clk.h>
#include <mach/clk.h>
@@ -44,7 +45,9 @@
struct regulator_dev *rdev;
struct regulator_desc rdesc;
void __iomem *gdscr;
- struct clk *core_clk;
+ struct clk **clocks;
+ int clock_count;
+ bool toggle_mems;
};
static int gdsc_is_enabled(struct regulator_dev *rdev)
@@ -58,7 +61,7 @@
{
struct gdsc *sc = rdev_get_drvdata(rdev);
uint32_t regval;
- int ret;
+ int i, ret;
regval = readl_relaxed(sc->gdscr);
regval &= ~SW_COLLAPSE_MASK;
@@ -71,9 +74,18 @@
return ret;
}
+ if (sc->toggle_mems) {
+ for (i = 0; i < sc->clock_count; i++) {
+ clk_set_flags(sc->clocks[i], CLKFLAG_RETAIN_MEM);
+ clk_set_flags(sc->clocks[i], CLKFLAG_RETAIN_PERIPH);
+ }
+ }
+
/*
* If clocks to this power domain were already on, they will take an
* additional 4 clock cycles to re-enable after the rail is enabled.
+ * Delay to account for this. A delay is also needed to ensure clocks
+ * are not enabled within 400ns of enabling power to the memories.
*/
udelay(1);
@@ -84,7 +96,7 @@
{
struct gdsc *sc = rdev_get_drvdata(rdev);
uint32_t regval;
- int ret;
+ int i, ret;
regval = readl_relaxed(sc->gdscr);
regval |= SW_COLLAPSE_MASK;
@@ -95,6 +107,13 @@
if (ret)
dev_err(&rdev->dev, "%s disable timed out\n", sc->rdesc.name);
+ if (sc->toggle_mems) {
+ for (i = 0; i < sc->clock_count; i++) {
+ clk_set_flags(sc->clocks[i], CLKFLAG_NORETAIN_MEM);
+ clk_set_flags(sc->clocks[i], CLKFLAG_NORETAIN_PERIPH);
+ }
+ }
+
return ret;
}
@@ -112,7 +131,7 @@
struct gdsc *sc;
uint32_t regval;
bool retain_mems;
- int ret;
+ int i, ret;
sc = devm_kzalloc(&pdev->dev, sizeof(struct gdsc), GFP_KERNEL);
if (sc == NULL)
@@ -137,6 +156,34 @@
if (sc->gdscr == NULL)
return -ENOMEM;
+ sc->clock_count = of_property_count_strings(pdev->dev.of_node,
+ "qcom,clock-names");
+ if (sc->clock_count == -EINVAL) {
+ sc->clock_count = 0;
+ } else if (IS_ERR_VALUE(sc->clock_count)) {
+ dev_err(&pdev->dev, "Failed to get clock names\n");
+ return -EINVAL;
+ }
+
+ sc->clocks = devm_kzalloc(&pdev->dev,
+ sizeof(struct clk *) * sc->clock_count, GFP_KERNEL);
+ if (!sc->clocks)
+ return -ENOMEM;
+ for (i = 0; i < sc->clock_count; i++) {
+ const char *clock_name;
+ of_property_read_string_index(pdev->dev.of_node,
+ "qcom,clock-names", i,
+ &clock_name);
+ sc->clocks[i] = devm_clk_get(&pdev->dev, clock_name);
+ if (IS_ERR(sc->clocks[i])) {
+ int rc = PTR_ERR(sc->clocks[i]);
+ if (rc != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "Failed to get %s\n",
+ clock_name);
+ return rc;
+ }
+ }
+
sc->rdesc.id = atomic_inc_return(&gdsc_count);
sc->rdesc.ops = &gdsc_ops;
sc->rdesc.type = REGULATOR_VOLTAGE;
@@ -157,13 +204,16 @@
retain_mems = of_property_read_bool(pdev->dev.of_node,
"qcom,retain-mems");
- if (retain_mems) {
- sc->core_clk = devm_clk_get(&pdev->dev, "core_clk");
- if (IS_ERR(sc->core_clk))
- return PTR_ERR(sc->core_clk);
- clk_set_flags(sc->core_clk, CLKFLAG_RETAIN_MEM);
- clk_set_flags(sc->core_clk, CLKFLAG_RETAIN_PERIPH);
+ for (i = 0; i < sc->clock_count; i++) {
+ if (retain_mems || (regval & PWR_ON_MASK)) {
+ clk_set_flags(sc->clocks[i], CLKFLAG_RETAIN_MEM);
+ clk_set_flags(sc->clocks[i], CLKFLAG_RETAIN_PERIPH);
+ } else {
+ clk_set_flags(sc->clocks[i], CLKFLAG_NORETAIN_MEM);
+ clk_set_flags(sc->clocks[i], CLKFLAG_NORETAIN_PERIPH);
+ }
}
+ sc->toggle_mems = !retain_mems;
sc->rdev = regulator_register(&sc->rdesc, &pdev->dev, init_data, sc,
pdev->dev.of_node);
diff --git a/arch/arm/mach-msm/include/mach/clk-provider.h b/arch/arm/mach-msm/include/mach/clk-provider.h
index 2a33228..b358b53 100644
--- a/arch/arm/mach-msm/include/mach/clk-provider.h
+++ b/arch/arm/mach-msm/include/mach/clk-provider.h
@@ -59,7 +59,7 @@
struct regulator **regulator;
int num_regulators;
int (*set_vdd)(struct clk_vdd_class *v_class, int level);
- const int **vdd_uv;
+ int **vdd_uv;
int *level_votes;
int num_levels;
unsigned long cur_level;
diff --git a/arch/arm/mach-msm/include/mach/clock-generic.h b/arch/arm/mach-msm/include/mach/clock-generic.h
new file mode 100644
index 0000000..0f689f1
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/clock-generic.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MACH_CLOCK_GENERIC_H
+#define __MACH_CLOCK_GENERIC_H
+
+#include <mach/clk-provider.h>
+
+/* ==================== Mux clock ==================== */
+
+struct clk_src {
+ struct clk *src;
+ int sel;
+};
+
+struct mux_clk;
+
+struct clk_mux_ops {
+ int (*set_mux_sel)(struct mux_clk *clk, int sel);
+ int (*get_mux_sel)(struct mux_clk *clk);
+
+ /* Optional */
+ bool (*is_enabled)(struct mux_clk *clk);
+ int (*enable)(struct mux_clk *clk);
+ void (*disable)(struct mux_clk *clk);
+};
+
+#define MUX_SRC_LIST(...) \
+ .parents = (struct clk_src[]){__VA_ARGS__}, \
+ .num_parents = ARRAY_SIZE(((struct clk_src[]){__VA_ARGS__}))
+
+struct mux_clk {
+ /* Parents in decreasing order of preference for obtaining rates. */
+ struct clk_src *parents;
+ int num_parents;
+ struct clk *safe_parent;
+ int safe_sel;
+ struct clk_mux_ops *ops;
+
+ /* Fields not used by helper function. */
+ void *const __iomem *base;
+ u32 offset;
+ u32 mask;
+ u32 shift;
+ u32 en_mask;
+ void *priv;
+
+ struct clk c;
+};
+
+static inline struct mux_clk *to_mux_clk(struct clk *c)
+{
+ return container_of(c, struct mux_clk, c);
+}
+
+extern struct clk_ops clk_ops_gen_mux;
+
+/* ==================== Divider clock ==================== */
+
+struct div_clk;
+
+struct clk_div_ops {
+ int (*set_div)(struct div_clk *clk, int div);
+ int (*get_div)(struct div_clk *clk);
+
+ /* Optional */
+ bool (*is_enabled)(struct div_clk *clk);
+ int (*enable)(struct div_clk *clk);
+ void (*disable)(struct div_clk *clk);
+};
+
+struct div_clk {
+ unsigned int div;
+ unsigned int min_div;
+ unsigned int max_div;
+ unsigned long rate_margin;
+ struct clk_div_ops *ops;
+
+ /* Fields not used by helper function. */
+ void *const __iomem *base;
+ u32 offset;
+ u32 mask;
+ u32 shift;
+ u32 en_mask;
+ void *priv;
+ struct clk c;
+};
+
+static inline struct div_clk *to_div_clk(struct clk *c)
+{
+ return container_of(c, struct div_clk, c);
+}
+
+extern struct clk_ops clk_ops_div;
+extern struct clk_ops clk_ops_slave_div;
+
+#define DEFINE_FIXED_DIV_CLK(clk_name, _div, _parent) \
+static struct div_clk clk_name = { \
+ .div = _div, \
+ .c = { \
+ .parent = _parent, \
+ .dbg_name = #clk_name, \
+ .ops = &clk_ops_div, \
+ CLK_INIT(clk_name.c), \
+ } \
+}
+
+#define DEFINE_FIXED_SLAVE_DIV_CLK(clk_name, _div, _parent) \
+static struct div_clk clk_name = { \
+ .div = _div, \
+ .c = { \
+ .parent = _parent, \
+ .dbg_name = #clk_name, \
+ .ops = &clk_ops_slave_div, \
+ CLK_INIT(clk_name.c), \
+ } \
+}
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/ipa.h b/arch/arm/mach-msm/include/mach/ipa.h
index 90757b6..db5e126 100644
--- a/arch/arm/mach-msm/include/mach/ipa.h
+++ b/arch/arm/mach-msm/include/mach/ipa.h
@@ -464,6 +464,13 @@
int ipa_disconnect(u32 clnt_hdl);
/*
+ * Resume / Suspend
+ */
+int ipa_resume(u32 clnt_hdl);
+
+int ipa_suspend(u32 clnt_hdl);
+
+/*
* Configuration
*/
int ipa_cfg_ep(u32 clnt_hdl, const struct ipa_ep_cfg *ipa_ep_cfg);
@@ -583,6 +590,8 @@
*/
int ipa_rm_create_resource(struct ipa_rm_create_params *create_params);
+int ipa_rm_delete_resource(enum ipa_rm_resource_name resource_name);
+
int ipa_rm_register(enum ipa_rm_resource_name resource_name,
struct ipa_rm_register_params *reg_params);
@@ -694,6 +703,19 @@
}
/*
+ * Resume / Suspend
+ */
+static inline int ipa_resume(u32 clnt_hdl)
+{
+ return -EPERM;
+}
+
+static inline int ipa_suspend(u32 clnt_hdl)
+{
+ return -EPERM;
+}
+
+/*
* Configuration
*/
static inline int ipa_cfg_ep(u32 clnt_hdl,
@@ -955,6 +977,12 @@
return -EPERM;
}
+static inline int ipa_rm_delete_resource(
+ enum ipa_rm_resource_name resource_name)
+{
+ return -EPERM;
+}
+
static inline int ipa_rm_register(enum ipa_rm_resource_name resource_name,
struct ipa_rm_register_params *reg_params)
{
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-8610.h b/arch/arm/mach-msm/include/mach/msm_iomap-8610.h
index 2a62460..18e448d 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-8610.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-8610.h
@@ -24,6 +24,9 @@
#define MSM8610_MSM_SHARED_RAM_PHYS 0x0D900000
+#define MSM8610_QGIC_DIST_PHYS 0xF9000000
+#define MSM8610_QGIC_DIST_SIZE SZ_4K
+
#define MSM8610_APCS_GCC_PHYS 0xF9011000
#define MSM8610_APCS_GCC_SIZE SZ_4K
diff --git a/arch/arm/mach-msm/include/mach/socinfo.h b/arch/arm/mach-msm/include/mach/socinfo.h
index d4ea4ac..64531f0 100644
--- a/arch/arm/mach-msm/include/mach/socinfo.h
+++ b/arch/arm/mach-msm/include/mach/socinfo.h
@@ -36,11 +36,14 @@
#define of_board_is_rumi() of_machine_is_compatible("qcom,rumi")
#define of_board_is_fluid() of_machine_is_compatible("qcom,fluid")
#define of_board_is_liquid() of_machine_is_compatible("qcom,liquid")
+#define of_board_is_dragonboard() \
+ of_machine_is_compatible("qcom,dragonboard")
#define machine_is_msm8974() of_machine_is_compatible("qcom,msm8974")
#define machine_is_msm9625() of_machine_is_compatible("qcom,msm9625")
#define machine_is_msm8610() of_machine_is_compatible("qcom,msm8610")
#define machine_is_msm8226() of_machine_is_compatible("qcom,msm8226")
+#define machine_is_apq8074() of_machine_is_compatible("qcom,apq8074")
#define early_machine_is_msm8610() \
of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,msm8610")
@@ -55,11 +58,13 @@
#define of_board_is_rumi() 0
#define of_board_is_fluid() 0
#define of_board_is_liquid() 0
+#define of_board_is_dragonboard() 0
#define machine_is_msm8974() 0
#define machine_is_msm9625() 0
#define machine_is_msm8610() 0
#define machine_is_msm8226() 0
+#define machine_is_apq8074() 0
#define early_machine_is_msm8610() 0
#define early_machine_is_mpq8092() 0
@@ -67,6 +72,7 @@
#define early_machine_is_msmkrypton() 0
#endif
+#define PLATFORM_SUBTYPE_MDM 1
#define PLATFORM_SUBTYPE_SGLTE 6
enum msm_cpu {
diff --git a/arch/arm/mach-msm/include/mach/subsystem_restart.h b/arch/arm/mach-msm/include/mach/subsystem_restart.h
index 67f643e..4d4703f 100644
--- a/arch/arm/mach-msm/include/mach/subsystem_restart.h
+++ b/arch/arm/mach-msm/include/mach/subsystem_restart.h
@@ -55,6 +55,7 @@
int (*powerup)(const struct subsys_desc *desc);
void (*crash_shutdown)(const struct subsys_desc *desc);
int (*ramdump)(int, const struct subsys_desc *desc);
+ unsigned int err_ready_irq;
};
#if defined(CONFIG_MSM_SUBSYSTEM_RESTART)
diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c
index 37dbbab..1c4a317 100644
--- a/arch/arm/mach-msm/io.c
+++ b/arch/arm/mach-msm/io.c
@@ -574,6 +574,7 @@
#ifdef CONFIG_ARCH_MSM8610
static struct map_desc msm8610_io_desc[] __initdata = {
+ MSM_CHIP_DEVICE(QGIC_DIST, MSM8610),
MSM_CHIP_DEVICE(APCS_GCC, MSM8610),
MSM_CHIP_DEVICE(TLMM, MSM8610),
MSM_CHIP_DEVICE(MPM2_PSHOLD, MSM8610),
diff --git a/arch/arm/mach-msm/krait-regulator.c b/arch/arm/mach-msm/krait-regulator.c
index 33a0aff..9014f37 100644
--- a/arch/arm/mach-msm/krait-regulator.c
+++ b/arch/arm/mach-msm/krait-regulator.c
@@ -133,6 +133,7 @@
#define LDO_DELTA_MIN 10000
#define LDO_DELTA_MAX 100000
+#define MSM_L2_SAW_PHYS 0xf9012000
/**
* struct pmic_gang_vreg -
* @name: the string used to represent the gang
@@ -1336,6 +1337,7 @@
void secondary_cpu_hs_init(void *base_ptr)
{
uint32_t reg_val;
+ void *l2_saw_base;
/* Turn on the BHS, turn off LDO Bypass and power down LDO */
reg_val = BHS_CNT_DEFAULT << BHS_CNT_BIT_POS
@@ -1361,9 +1363,26 @@
/* Finally turn on the bypass so that BHS supplies power */
reg_val |= LDO_BYP_MASK;
writel_relaxed(reg_val, base_ptr + APC_PWR_GATE_CTL);
+
+ if (the_gang && the_gang->manage_phases)
+ return;
+
+ /*
+ * If the driver has not yet started to manage phases then enable
+ * max phases.
+ */
+ l2_saw_base = ioremap_nocache(MSM_L2_SAW_PHYS, SZ_4K);
+ if (!l2_saw_base) {
+ __WARN();
+ return;
+ }
+ writel_relaxed(0x10003, l2_saw_base + 0x1c);
+ mb();
+ udelay(PHASE_SETTLING_TIME_US);
+
+ iounmap(l2_saw_base);
}
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("KRAIT POWER regulator driver");
-MODULE_VERSION("1.0");
MODULE_ALIAS("platform:"KRAIT_REGULATOR_DRIVER_NAME);
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_arb.c b/arch/arm/mach-msm/msm_bus/msm_bus_arb.c
index 6ff8152..5002a7d 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_arb.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_arb.c
@@ -574,6 +574,10 @@
curr = client->curr;
pdata = client->pdata;
+ if (!pdata) {
+ MSM_BUS_ERR("Null pdata passed to update-request\n");
+ return -ENXIO;
+ }
if (index >= pdata->num_usecases) {
MSM_BUS_ERR("Client %u passed invalid index: %d\n",
@@ -718,7 +722,7 @@
{
int i, src, pnode, index;
struct msm_bus_client *client = (struct msm_bus_client *)(cl);
- if (IS_ERR(client)) {
+ if (IS_ERR_OR_NULL(client)) {
MSM_BUS_ERR("msm_bus_scale_reset_pnodes error\n");
return;
}
@@ -739,7 +743,7 @@
void msm_bus_scale_unregister_client(uint32_t cl)
{
struct msm_bus_client *client = (struct msm_bus_client *)(cl);
- if (IS_ERR(client) || (!client))
+ if (IS_ERR_OR_NULL(client))
return;
if (client->curr != 0)
msm_bus_scale_client_update_request(cl, 0);
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_board_8064.c b/arch/arm/mach-msm/msm_bus/msm_bus_board_8064.c
index b45efad..ff3dc21 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_board_8064.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_board_8064.c
@@ -437,10 +437,7 @@
},
};
-static int mport_mdp[] = {
- MSM_BUS_MASTER_PORT_MDP_PORT0,
- MSM_BUS_MASTER_PORT_MDP_PORT1,
-};
+static int mport_mdp[] = {MSM_BUS_MASTER_PORT_MDP_PORT0,};
static int mport_mdp1[] = {MSM_BUS_MASTER_PORT_MDP_PORT1,};
static int mport_rotator[] = {MSM_BUS_MASTER_PORT_ROTATOR,};
static int mport_graphics_3d_port0[] = {MSM_BUS_MASTER_PORT_GRAPHICS_3D_PORT0,};
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_board_8930.c b/arch/arm/mach-msm/msm_bus/msm_bus_board_8930.c
index 91d106e..af51355 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_board_8930.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_board_8930.c
@@ -377,10 +377,7 @@
},
};
-static int mport_mdp[] = {
- MSM_BUS_MASTER_PORT_MDP_PORT0,
- MSM_BUS_MASTER_PORT_MDP_PORT1,
-};
+static int mport_mdp[] = {MSM_BUS_MASTER_PORT_MDP_PORT0,};
static int mport_mdp1[] = {MSM_BUS_MASTER_PORT_MDP_PORT1,};
static int mport_rotator[] = {MSM_BUS_MASTER_PORT_ROTATOR,};
static int mport_graphics_3d[] = {MSM_BUS_MASTER_PORT_GRAPHICS_3D,};
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_board_8960.c b/arch/arm/mach-msm/msm_bus/msm_bus_board_8960.c
index 158dee3..295b91b 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_board_8960.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_board_8960.c
@@ -440,10 +440,7 @@
},
};
-static int mport_mdp[] = {
- MSM_BUS_MASTER_PORT_MDP_PORT0,
- MSM_BUS_MASTER_PORT_MDP_PORT1,
-};
+static int mport_mdp[] = {MSM_BUS_MASTER_PORT_MDP_PORT0,};
static int mport_mdp1[] = {MSM_BUS_MASTER_PORT_MDP_PORT1,};
static int mport_rotator[] = {MSM_BUS_MASTER_PORT_ROTATOR,};
static int mport_graphics_3d[] = {MSM_BUS_MASTER_PORT_GRAPHICS_3D,};
diff --git a/arch/arm/mach-msm/pil-pronto.c b/arch/arm/mach-msm/pil-pronto.c
index cf29cf1..b186a4d 100644
--- a/arch/arm/mach-msm/pil-pronto.c
+++ b/arch/arm/mach-msm/pil-pronto.c
@@ -515,6 +515,17 @@
drv->subsys_desc.start = pronto_start;
drv->subsys_desc.stop = pronto_stop;
+ ret = of_get_named_gpio(pdev->dev.of_node,
+ "qcom,gpio-err-ready", 0);
+ if (ret < 0)
+ return ret;
+
+ ret = gpio_to_irq(ret);
+ if (ret < 0)
+ return ret;
+
+ drv->subsys_desc.err_ready_irq = ret;
+
INIT_DELAYED_WORK(&drv->cancel_vote_work, wcnss_post_bootup);
drv->subsys = subsys_register(&drv->subsys_desc);
diff --git a/arch/arm/mach-msm/pil-q6v5-mss.c b/arch/arm/mach-msm/pil-q6v5-mss.c
index c1c3100..3ce1283 100644
--- a/arch/arm/mach-msm/pil-q6v5-mss.c
+++ b/arch/arm/mach-msm/pil-q6v5-mss.c
@@ -650,6 +650,17 @@
drv->subsys_desc.start = mss_start;
drv->subsys_desc.stop = mss_stop;
+ ret = of_get_named_gpio(pdev->dev.of_node,
+ "qcom,gpio-err-ready", 0);
+ if (ret < 0)
+ return ret;
+
+ ret = gpio_to_irq(ret);
+ if (ret < 0)
+ return ret;
+
+ drv->subsys_desc.err_ready_irq = ret;
+
drv->subsys = subsys_register(&drv->subsys_desc);
if (IS_ERR(drv->subsys)) {
ret = PTR_ERR(drv->subsys);
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index a39e38b..4fca346 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -1368,7 +1368,7 @@
if (!data)
return -EINVAL;
- if (!bufu || count < 0)
+ if (!bufu)
return -EINVAL;
if (!access_ok(VERIFY_WRITE, bufu, count))
diff --git a/arch/arm/mach-msm/spm_devices.c b/arch/arm/mach-msm/spm_devices.c
index b20c7f5..8e94b3a 100644
--- a/arch/arm/mach-msm/spm_devices.c
+++ b/arch/arm/mach-msm/spm_devices.c
@@ -76,7 +76,7 @@
info.vlevel = vlevel;
info.err = -ENODEV;
- if (cpu_online(cpu)) {
+ if ((smp_processor_id() != cpu) && cpu_online(cpu)) {
/**
* We do not want to set the voltage of another core from
* this core, as its possible that we may race the vdd change
diff --git a/arch/arm/mach-msm/subsystem_restart.c b/arch/arm/mach-msm/subsystem_restart.c
index 5fe7a29..fb44e16 100644
--- a/arch/arm/mach-msm/subsystem_restart.c
+++ b/arch/arm/mach-msm/subsystem_restart.c
@@ -31,6 +31,7 @@
#include <linux/idr.h>
#include <linux/debugfs.h>
#include <linux/miscdevice.h>
+#include <linux/interrupt.h>
#include <asm/current.h>
@@ -132,6 +133,7 @@
* @restart_order: order of other devices this devices restarts with
* @dentry: debugfs directory for this device
* @do_ramdump_on_put: ramdump on subsystem_put() if true
+ * @err_ready: completion variable to record error ready from subsystem
*/
struct subsys_device {
struct subsys_desc *desc;
@@ -154,6 +156,7 @@
bool do_ramdump_on_put;
struct miscdevice misc_dev;
char miscdevice_name[32];
+ struct completion err_ready;
};
static struct subsys_device *to_subsys(struct device *d)
@@ -412,6 +415,21 @@
}
}
+static int wait_for_err_ready(struct subsys_device *subsys)
+{
+ int ret;
+
+ if (!subsys->desc->err_ready_irq)
+ return 0;
+
+ ret = wait_for_completion_timeout(&subsys->err_ready,
+ msecs_to_jiffies(10000));
+ if (!ret)
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
static void subsystem_shutdown(struct subsys_device *dev, void *data)
{
const char *name = dev->desc->name;
@@ -436,10 +454,17 @@
static void subsystem_powerup(struct subsys_device *dev, void *data)
{
const char *name = dev->desc->name;
+ int ret;
pr_info("[%p]: Powering up %s\n", current, name);
+ init_completion(&dev->err_ready);
if (dev->desc->powerup(dev->desc) < 0)
- panic("[%p]: Failed to powerup %s!", current, name);
+ panic("[%p]: Powerup error: %s!", current, name);
+
+ ret = wait_for_err_ready(dev);
+ if (ret)
+ panic("[%p]: Timed out waiting for error ready: %s!",
+ current, name);
subsys_set_state(dev, SUBSYS_ONLINE);
}
@@ -465,8 +490,18 @@
{
int ret;
+ init_completion(&subsys->err_ready);
ret = subsys->desc->start(subsys->desc);
- if (!ret)
+ if (ret)
+ return ret;
+
+ ret = wait_for_err_ready(subsys);
+ if (ret)
+ /* pil-boot succeeded but we need to shutdown
+ * the device because error ready timed out.
+ */
+ subsys->desc->stop(subsys->desc);
+ else
subsys_set_state(subsys, SUBSYS_ONLINE);
return ret;
@@ -895,6 +930,14 @@
ida_simple_remove(&subsys_ida, subsys->id);
kfree(subsys);
}
+static irqreturn_t subsys_err_ready_intr_handler(int irq, void *subsys)
+{
+ struct subsys_device *subsys_dev = subsys;
+ pr_info("Error ready interrupt occured for %s\n",
+ subsys_dev->desc->name);
+ complete(&subsys_dev->err_ready);
+ return IRQ_HANDLED;
+}
static int subsys_misc_device_add(struct subsys_device *subsys_dev)
{
@@ -971,8 +1014,24 @@
goto err_register;
}
+ if (subsys->desc->err_ready_irq) {
+ ret = devm_request_irq(&subsys->dev,
+ subsys->desc->err_ready_irq,
+ subsys_err_ready_intr_handler,
+ IRQF_TRIGGER_RISING,
+ "error_ready_interrupt", subsys);
+ if (ret < 0) {
+ dev_err(&subsys->dev,
+ "[%s]: Unable to register err ready handler\n",
+ subsys->desc->name);
+ goto err_misc_device;
+ }
+ }
+
return subsys;
+err_misc_device:
+ subsys_misc_device_remove(subsys);
err_register:
subsys_debugfs_remove(subsys);
err_debugfs:
diff --git a/drivers/crypto/msm/qce50.c b/drivers/crypto/msm/qce50.c
index 1f16497..58fa5c9 100644
--- a/drivers/crypto/msm/qce50.c
+++ b/drivers/crypto/msm/qce50.c
@@ -1704,7 +1704,14 @@
bam.summing_threshold = 64;
/* SPS driver wll handle the crypto BAM IRQ */
bam.irq = (u32)pce_dev->ce_sps.bam_irq;
- bam.manage = SPS_BAM_MGR_LOCAL;
+ /*
+ * Set flag to indicate BAM global device control is managed
+ * remotely.
+ */
+ if (pce_dev->support_cmd_dscr == false)
+ bam.manage = SPS_BAM_MGR_DEVICE_REMOTE;
+ else
+ bam.manage = SPS_BAM_MGR_LOCAL;
bam.ee = 1;
pr_debug("bam physical base=0x%x\n", (u32)bam.phys_addr);
@@ -2990,8 +2997,6 @@
pce_dev->dir = c_req->dir;
if ((pce_dev->ce_sps.minor_version == 0) && (c_req->dir == QCE_DECRYPT)
&& (c_req->mode == QCE_MODE_CBC)) {
- struct ablkcipher_request *areq =
- (struct ablkcipher_request *)pce_dev->areq;
memcpy(pce_dev->dec_iv, (unsigned char *)sg_virt(areq->src) +
areq->src->length - 16,
NUM_OF_CRYPTO_CNTR_IV_REG * CRYPTO_REG_SIZE);
@@ -3140,8 +3145,6 @@
pce_dev->is_shared = of_property_read_bool((&pdev->dev)->of_node,
"qcom,ce-hw-shared");
- pce_dev->support_cmd_dscr = of_property_read_bool((&pdev->dev)->of_node,
- "qcom,ce-hw-support-cmd-dscr");
if (of_property_read_u32((&pdev->dev)->of_node,
"qcom,bam-pipe-pair",
&pce_dev->ce_sps.pipe_pair_index)) {
@@ -3176,7 +3179,7 @@
pce_dev->ce_sps.bam_mem = resource->start;
pce_dev->ce_sps.bam_iobase = ioremap_nocache(resource->start,
resource_size(resource));
- if (!pce_dev->iobase) {
+ if (!pce_dev->ce_sps.bam_iobase) {
rc = -ENOMEM;
pr_err("Can not map BAM io memory\n");
goto err_getting_bam_info;
@@ -3189,7 +3192,6 @@
pr_warn("ce_bam_phy_reg_base=0x%x ", pce_dev->ce_sps.bam_mem);
pr_warn("ce_bam_virt_reg_base=0x%x\n",
(uint32_t)pce_dev->ce_sps.bam_iobase);
-
resource = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (resource) {
pce_dev->ce_sps.bam_irq = resource->start;
@@ -3355,6 +3357,7 @@
void *qce_open(struct platform_device *pdev, int *rc)
{
struct qce_device *pce_dev;
+ uint32_t bam_cfg = 0 ;
pce_dev = kzalloc(sizeof(struct qce_device), GFP_KERNEL);
if (!pce_dev) {
@@ -3396,10 +3399,16 @@
goto err;
}
*rc = 0;
+
+ bam_cfg = readl_relaxed(pce_dev->ce_sps.bam_iobase +
+ CRYPTO_BAM_CNFG_BITS_REG);
+ pce_dev->support_cmd_dscr = (bam_cfg & CRYPTO_BAM_CD_ENABLE_MASK) ?
+ true : false;
qce_init_ce_cfg_val(pce_dev);
qce_setup_ce_sps_data(pce_dev);
qce_sps_init(pce_dev);
+
qce_disable_clk(pce_dev);
return pce_dev;
@@ -3429,6 +3438,9 @@
if (handle == NULL)
return -ENODEV;
+ qce_enable_clk(pce_dev);
+ qce_sps_exit(pce_dev);
+
if (pce_dev->iobase)
iounmap(pce_dev->iobase);
if (pce_dev->coh_vmem)
@@ -3438,7 +3450,6 @@
qce_disable_clk(pce_dev);
__qce_deinit_clk(pce_dev);
- qce_sps_exit(pce_dev);
kfree(handle);
return 0;
diff --git a/drivers/crypto/msm/qcedev.c b/drivers/crypto/msm/qcedev.c
index 7666e74..a09bb42 100644
--- a/drivers/crypto/msm/qcedev.c
+++ b/drivers/crypto/msm/qcedev.c
@@ -323,10 +323,10 @@
u32 qcedev_sha_fail;
};
-static struct qcedev_stat _qcedev_stat[MAX_QCE_DEVICE];
+static struct qcedev_stat _qcedev_stat;
static struct dentry *_debug_dent;
static char _debug_read_buf[DEBUG_MAX_RW_BUF];
-static int _debug_qcedev[MAX_QCE_DEVICE];
+static int _debug_qcedev;
static struct qcedev_control *qcedev_minor_to_control(unsigned n)
{
@@ -693,7 +693,7 @@
if (ret)
qcedev_areq->err = -EIO;
- pstat = &_qcedev_stat[podev->pdev->id];
+ pstat = &_qcedev_stat;
if (qcedev_areq->op_type == QCEDEV_CRYPTO_OPER_CIPHER) {
switch (qcedev_areq->cipher_op_req.op) {
case QCEDEV_OPER_DEC:
@@ -1739,7 +1739,7 @@
return -ENOTTY;
init_completion(&qcedev_areq.complete);
- pstat = &_qcedev_stat[podev->pdev->id];
+ pstat = &_qcedev_stat;
switch (cmd) {
case QCEDEV_IOCTL_LOCK_CE:
@@ -2026,11 +2026,7 @@
struct qcedev_stat *pstat;
int len = 0;
- if (id < 0) {
- pr_err("Crypto id is %d, cannot be negative\n", id);
- return len;
- }
- pstat = &_qcedev_stat[id];
+ pstat = &_qcedev_stat;
len = snprintf(_debug_read_buf, DEBUG_MAX_RW_BUF - 1,
"\nQualcomm QCE dev driver %d Statistics:\n",
id + 1);
@@ -2076,10 +2072,7 @@
static ssize_t _debug_stats_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
-
- int qcedev = *((int *) file->private_data);
-
- memset((char *)&_qcedev_stat[qcedev], 0, sizeof(struct qcedev_stat));
+ memset((char *)&_qcedev_stat, 0, sizeof(struct qcedev_stat));
return count;
};
@@ -2093,7 +2086,6 @@
{
int rc;
char name[DEBUG_MAX_FNAME];
- int i;
struct dentry *dent;
_debug_dent = debugfs_create_dir("qcedev", NULL);
@@ -2103,17 +2095,15 @@
return PTR_ERR(_debug_dent);
}
- for (i = 0; i < MAX_QCE_DEVICE; i++) {
- snprintf(name, DEBUG_MAX_FNAME-1, "stats-%d", i+1);
- _debug_qcedev[i] = i;
- dent = debugfs_create_file(name, 0644, _debug_dent,
- &_debug_qcedev[i], &_debug_stats_ops);
- if (dent == NULL) {
- pr_err("qcedev debugfs_create_file fail, error %ld\n",
- PTR_ERR(dent));
- rc = PTR_ERR(dent);
- goto err;
- }
+ snprintf(name, DEBUG_MAX_FNAME-1, "stats-%d", 1);
+ _debug_qcedev = 0;
+ dent = debugfs_create_file(name, 0644, _debug_dent,
+ &_debug_qcedev, &_debug_stats_ops);
+ if (dent == NULL) {
+ pr_err("qcedev debugfs_create_file fail, error %ld\n",
+ PTR_ERR(dent));
+ rc = PTR_ERR(dent);
+ goto err;
}
return 0;
err:
diff --git a/drivers/crypto/msm/qcrypto.c b/drivers/crypto/msm/qcrypto.c
index 40fb29ac..d1cb933 100644
--- a/drivers/crypto/msm/qcrypto.c
+++ b/drivers/crypto/msm/qcrypto.c
@@ -42,7 +42,6 @@
#include "qce.h"
-#define MAX_CRYPTO_DEVICE 3
#define DEBUG_MAX_FNAME 16
#define DEBUG_MAX_RW_BUF 1024
@@ -53,6 +52,8 @@
u32 aead_sha1_des_dec;
u32 aead_sha1_3des_enc;
u32 aead_sha1_3des_dec;
+ u32 aead_ccm_aes_enc;
+ u32 aead_ccm_aes_dec;
u32 aead_op_success;
u32 aead_op_fail;
u32 ablk_cipher_aes_enc;
@@ -72,7 +73,7 @@
u32 sha_hmac_op_success;
u32 sha_hmac_op_fail;
};
-static struct crypto_stat _qcrypto_stat[MAX_CRYPTO_DEVICE];
+static struct crypto_stat _qcrypto_stat;
static struct dentry *_debug_dent;
static char _debug_read_buf[DEBUG_MAX_RW_BUF];
@@ -405,6 +406,39 @@
return i;
}
+size_t qcrypto_sg_copy_from_buffer(struct scatterlist *sgl, unsigned int nents,
+ void *buf, size_t buflen)
+{
+ int i;
+ size_t offset, len;
+
+ for (i = 0, offset = 0; i < nents; ++i) {
+ len = sg_copy_from_buffer(sgl, 1, buf, buflen);
+ buf += len;
+ buflen -= len;
+ offset += len;
+ sgl = scatterwalk_sg_next(sgl);
+ }
+
+ return offset;
+}
+
+size_t qcrypto_sg_copy_to_buffer(struct scatterlist *sgl, unsigned int nents,
+ void *buf, size_t buflen)
+{
+ int i;
+ size_t offset, len;
+
+ for (i = 0, offset = 0; i < nents; ++i) {
+ len = sg_copy_to_buffer(sgl, 1, buf, buflen);
+ buf += len;
+ buflen -= len;
+ offset += len;
+ sgl = scatterwalk_sg_next(sgl);
+ }
+
+ return offset;
+}
static struct qcrypto_alg *_qcrypto_sha_alg_alloc(struct crypto_priv *cp,
struct ahash_alg *template)
{
@@ -581,11 +615,7 @@
struct crypto_stat *pstat;
int len = 0;
- if (id < 0) {
- pr_err("Crypto id is %d, cannot be negative\n", id);
- return len;
- }
- pstat = &_qcrypto_stat[id];
+ pstat = &_qcrypto_stat;
len = snprintf(_debug_read_buf, DEBUG_MAX_RW_BUF - 1,
"\nQualcomm crypto accelerator %d Statistics:\n",
id + 1);
@@ -641,6 +671,13 @@
pstat->aead_sha1_3des_dec);
len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ " AEAD CCM-AES encryption : %d\n",
+ pstat->aead_ccm_aes_enc);
+ len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ " AEAD CCM-AES decryption : %d\n",
+ pstat->aead_ccm_aes_dec);
+
+ len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" AEAD operation success : %d\n",
pstat->aead_op_success);
len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
@@ -858,7 +895,7 @@
uint32_t diglen = crypto_ahash_digestsize(ahash);
uint32_t *auth32 = (uint32_t *)authdata;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
#ifdef QCRYPTO_DEBUG
dev_info(&cp->pdev->dev, "_qce_ahash_complete: %p ret %d\n",
@@ -916,7 +953,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
#ifdef QCRYPTO_DEBUG
dev_info(&cp->pdev->dev, "_qce_ablk_cipher_complete: %p ret %d\n",
@@ -943,7 +980,7 @@
areq->dst = rctx->orig_dst;
num_sg = qcrypto_count_sg(areq->dst, areq->nbytes);
- bytes = sg_copy_from_buffer(areq->dst, num_sg,
+ bytes = qcrypto_sg_copy_from_buffer(areq->dst, num_sg,
rctx->data, areq->nbytes);
if (bytes != areq->nbytes)
pr_warn("bytes copied=0x%x bytes to copy= 0x%x", bytes,
@@ -967,7 +1004,7 @@
struct qcrypto_cipher_req_ctx *rctx;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
rctx = aead_request_ctx(areq);
@@ -988,7 +1025,7 @@
nbytes = areq->cryptlen -
crypto_aead_authsize(aead);
num_sg = qcrypto_count_sg(areq->dst, nbytes);
- bytes = sg_copy_from_buffer(areq->dst, num_sg,
+ bytes = qcrypto_sg_copy_from_buffer(areq->dst, num_sg,
((char *)rctx->data + areq->assoclen),
nbytes);
if (bytes != nbytes)
@@ -1118,7 +1155,7 @@
qreq->assoclen = ALIGN((alen + len), 16);
num_sg = qcrypto_count_sg(sg, alen);
- bytes = sg_copy_to_buffer(sg, num_sg, adata, alen);
+ bytes = qcrypto_sg_copy_to_buffer(sg, num_sg, adata, alen);
if (bytes != alen)
pr_warn("bytes copied=0x%x bytes to copy= 0x%x", bytes, alen);
@@ -1145,7 +1182,7 @@
rctx->orig_src = req->src;
rctx->orig_dst = req->dst;
- rctx->data = kzalloc((req->nbytes + 64), GFP_KERNEL);
+ rctx->data = kzalloc((req->nbytes + 64), GFP_ATOMIC);
if (rctx->data == NULL) {
pr_err("Mem Alloc fail rctx->data, err %ld for 0x%x\n",
@@ -1153,7 +1190,7 @@
return -ENOMEM;
}
num_sg = qcrypto_count_sg(req->src, req->nbytes);
- bytes = sg_copy_to_buffer(req->src, num_sg, rctx->data,
+ bytes = qcrypto_sg_copy_to_buffer(req->src, num_sg, rctx->data,
req->nbytes);
if (bytes != req->nbytes)
pr_warn("bytes copied=0x%x bytes to copy= 0x%x", bytes,
@@ -1294,7 +1331,7 @@
rctx->orig_src = req->src;
rctx->orig_dst = req->dst;
rctx->data = kzalloc((req->cryptlen + qreq.assoclen +
- qreq.authsize + 64*2), GFP_KERNEL);
+ qreq.authsize + 64*2), GFP_ATOMIC);
if (rctx->data == NULL) {
pr_err("Mem Alloc fail rctx->data, err %ld\n",
PTR_ERR(rctx->data));
@@ -1305,7 +1342,7 @@
memcpy((char *)rctx->data, qreq.assoc, qreq.assoclen);
num_sg = qcrypto_count_sg(req->src, req->cryptlen);
- bytes = sg_copy_to_buffer(req->src, num_sg,
+ bytes = qcrypto_sg_copy_to_buffer(req->src, num_sg,
rctx->data + qreq.assoclen , req->cryptlen);
if (bytes != req->cryptlen)
pr_warn("bytes copied=0x%x bytes to copy= 0x%x",
@@ -1358,7 +1395,7 @@
int ret = 0;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
again:
spin_lock_irqsave(&cp->lock, flags);
@@ -1434,7 +1471,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
BUG_ON(crypto_tfm_alg_type(req->base.tfm) !=
CRYPTO_ALG_TYPE_ABLKCIPHER);
@@ -1458,7 +1495,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
BUG_ON(crypto_tfm_alg_type(req->base.tfm) !=
CRYPTO_ALG_TYPE_ABLKCIPHER);
@@ -1482,7 +1519,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
BUG_ON(crypto_tfm_alg_type(req->base.tfm) !=
CRYPTO_ALG_TYPE_ABLKCIPHER);
@@ -1506,7 +1543,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
BUG_ON(crypto_tfm_alg_type(req->base.tfm) !=
CRYPTO_ALG_TYPE_ABLKCIPHER);
@@ -1533,7 +1570,7 @@
(ctx->auth_key_len != AES_KEYSIZE_256))
return -EINVAL;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
rctx = aead_request_ctx(req);
rctx->aead = 1;
@@ -1542,7 +1579,7 @@
rctx->mode = QCE_MODE_CCM;
rctx->iv = req->iv;
- pstat->aead_sha1_aes_enc++;
+ pstat->aead_ccm_aes_enc++;
return _qcrypto_queue_req(cp, &req->base);
}
@@ -1553,7 +1590,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
BUG_ON(crypto_tfm_alg_type(req->base.tfm) !=
CRYPTO_ALG_TYPE_ABLKCIPHER);
@@ -1574,7 +1611,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
BUG_ON(crypto_tfm_alg_type(req->base.tfm) !=
CRYPTO_ALG_TYPE_ABLKCIPHER);
@@ -1595,7 +1632,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
BUG_ON(crypto_tfm_alg_type(req->base.tfm) !=
CRYPTO_ALG_TYPE_ABLKCIPHER);
@@ -1616,7 +1653,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
BUG_ON(crypto_tfm_alg_type(req->base.tfm) !=
CRYPTO_ALG_TYPE_ABLKCIPHER);
@@ -1637,7 +1674,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
BUG_ON(crypto_tfm_alg_type(req->base.tfm) !=
CRYPTO_ALG_TYPE_ABLKCIPHER);
@@ -1661,7 +1698,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
BUG_ON(crypto_tfm_alg_type(req->base.tfm) !=
CRYPTO_ALG_TYPE_ABLKCIPHER);
@@ -1686,7 +1723,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
BUG_ON(crypto_tfm_alg_type(req->base.tfm) !=
CRYPTO_ALG_TYPE_ABLKCIPHER);
@@ -1712,7 +1749,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
BUG_ON(crypto_tfm_alg_type(req->base.tfm) !=
CRYPTO_ALG_TYPE_ABLKCIPHER);
@@ -1733,7 +1770,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
BUG_ON(crypto_tfm_alg_type(req->base.tfm) !=
CRYPTO_ALG_TYPE_ABLKCIPHER);
@@ -1754,7 +1791,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
BUG_ON(crypto_tfm_alg_type(req->base.tfm) !=
CRYPTO_ALG_TYPE_ABLKCIPHER);
@@ -1775,7 +1812,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
BUG_ON(crypto_tfm_alg_type(req->base.tfm) !=
CRYPTO_ALG_TYPE_ABLKCIPHER);
@@ -1796,7 +1833,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
BUG_ON(crypto_tfm_alg_type(req->base.tfm) !=
CRYPTO_ALG_TYPE_ABLKCIPHER);
@@ -1824,7 +1861,7 @@
(ctx->auth_key_len != AES_KEYSIZE_256))
return -EINVAL;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
rctx = aead_request_ctx(req);
rctx->aead = 1;
@@ -1833,7 +1870,7 @@
rctx->mode = QCE_MODE_CCM;
rctx->iv = req->iv;
- pstat->aead_sha1_aes_dec++;
+ pstat->aead_ccm_aes_dec++;
return _qcrypto_queue_req(cp, &req->base);
}
@@ -1939,7 +1976,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
#ifdef QCRYPTO_DEBUG
dev_info(&cp->pdev->dev, "_qcrypto_aead_encrypt_aes_cbc: %p\n", req);
@@ -1963,7 +2000,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
#ifdef QCRYPTO_DEBUG
dev_info(&cp->pdev->dev, "_qcrypto_aead_decrypt_aes_cbc: %p\n", req);
@@ -1988,7 +2025,7 @@
struct qcrypto_cipher_req_ctx *rctx;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
rctx = aead_request_ctx(areq);
rctx->aead = 1;
@@ -2012,7 +2049,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
rctx = aead_request_ctx(req);
rctx->aead = 1;
@@ -2032,7 +2069,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
rctx = aead_request_ctx(req);
rctx->aead = 1;
@@ -2057,7 +2094,7 @@
struct qcrypto_cipher_req_ctx *rctx;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
rctx = aead_request_ctx(areq);
rctx->aead = 1;
@@ -2081,7 +2118,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
rctx = aead_request_ctx(req);
rctx->aead = 1;
@@ -2101,7 +2138,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
rctx = aead_request_ctx(req);
rctx->aead = 1;
@@ -2123,7 +2160,7 @@
struct qcrypto_cipher_req_ctx *rctx;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
rctx = aead_request_ctx(areq);
rctx->aead = 1;
@@ -2146,7 +2183,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
rctx = aead_request_ctx(req);
rctx->aead = 1;
@@ -2166,7 +2203,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
rctx = aead_request_ctx(req);
rctx->aead = 1;
@@ -2188,7 +2225,7 @@
struct qcrypto_cipher_req_ctx *rctx;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
rctx = aead_request_ctx(areq);
rctx->aead = 1;
@@ -2220,10 +2257,9 @@
static int _sha1_init(struct ahash_request *req)
{
struct qcrypto_sha_ctx *sha_ctx = crypto_tfm_ctx(req->base.tfm);
- struct crypto_priv *cp = sha_ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
_sha_init(sha_ctx);
sha_ctx->alg = QCE_HASH_SHA1;
@@ -2241,10 +2277,9 @@
static int _sha256_init(struct ahash_request *req)
{
struct qcrypto_sha_ctx *sha_ctx = crypto_tfm_ctx(req->base.tfm);
- struct crypto_priv *cp = sha_ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
_sha_init(sha_ctx);
sha_ctx->alg = QCE_HASH_SHA256;
@@ -2347,7 +2382,7 @@
srctx = ahash_request_ctx(req);
srctx->orig_src = req->src;
- srctx->data = kzalloc((req->nbytes + 64), GFP_KERNEL);
+ srctx->data = kzalloc((req->nbytes + 64), GFP_ATOMIC);
if (srctx->data == NULL) {
pr_err("Mem Alloc fail rctx->data, err %ld for 0x%x\n",
PTR_ERR(srctx->data), (req->nbytes + 64));
@@ -2355,7 +2390,8 @@
}
num_sg = qcrypto_count_sg(req->src, req->nbytes);
- bytes = sg_copy_to_buffer(req->src, num_sg, srctx->data, req->nbytes);
+ bytes = qcrypto_sg_copy_to_buffer(req->src, num_sg, srctx->data,
+ req->nbytes);
if (bytes != req->nbytes)
pr_warn("bytes copied=0x%x bytes to copy= 0x%x", bytes,
req->nbytes);
@@ -2390,7 +2426,7 @@
if (total <= sha_block_size) {
k_src = &sha_ctx->trailing_buf[sha_ctx->trailing_buf_len];
num_sg = qcrypto_count_sg(req->src, len);
- bytes = sg_copy_to_buffer(req->src, num_sg, k_src, len);
+ bytes = qcrypto_sg_copy_to_buffer(req->src, num_sg, k_src, len);
sha_ctx->trailing_buf_len = total;
if (sha_ctx->alg == QCE_HASH_SHA1)
@@ -2431,13 +2467,13 @@
if (sha_ctx->trailing_buf_len) {
if (cp->ce_support.aligned_only) {
sha_ctx->sg = kzalloc(sizeof(struct scatterlist),
- GFP_KERNEL);
+ GFP_ATOMIC);
if (sha_ctx->sg == NULL) {
pr_err("MemAlloc fail sha_ctx->sg, error %ld\n",
PTR_ERR(sha_ctx->sg));
return -ENOMEM;
}
- rctx->data2 = kzalloc((req->nbytes + 64), GFP_KERNEL);
+ rctx->data2 = kzalloc((req->nbytes + 64), GFP_ATOMIC);
if (rctx->data2 == NULL) {
pr_err("Mem Alloc fail srctx->data2, err %ld\n",
PTR_ERR(rctx->data2));
@@ -2458,7 +2494,7 @@
} else {
sg_mark_end(sg_last);
sha_ctx->sg = kzalloc(2 * (sizeof(struct scatterlist)),
- GFP_KERNEL);
+ GFP_ATOMIC);
if (sha_ctx->sg == NULL) {
pr_err("MEMalloc fail sha_ctx->sg, error %ld\n",
PTR_ERR(sha_ctx->sg));
@@ -2688,7 +2724,7 @@
struct crypto_stat *pstat;
int ret = 0;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
pstat->sha1_hmac_digest++;
_sha_init(sha_ctx);
@@ -2715,7 +2751,7 @@
struct crypto_stat *pstat;
int ret = 0;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
pstat->sha256_hmac_digest++;
_sha_init(sha_ctx);
@@ -2853,10 +2889,9 @@
static int _sha1_hmac_digest(struct ahash_request *req)
{
struct qcrypto_sha_ctx *sha_ctx = crypto_tfm_ctx(req->base.tfm);
- struct crypto_priv *cp = sha_ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
pstat->sha1_hmac_digest++;
_sha_init(sha_ctx);
@@ -2871,10 +2906,9 @@
static int _sha256_hmac_digest(struct ahash_request *req)
{
struct qcrypto_sha_ctx *sha_ctx = crypto_tfm_ctx(req->base.tfm);
- struct crypto_priv *cp = sha_ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
pstat->sha256_hmac_digest++;
_sha_init(sha_ctx);
@@ -3327,12 +3361,6 @@
int i;
struct msm_ce_hw_support *platform_support;
- if (pdev->id >= MAX_CRYPTO_DEVICE) {
- pr_err("%s: device id %d exceeds allowed %d\n",
- __func__, pdev->id, MAX_CRYPTO_DEVICE);
- return -ENOENT;
- }
-
cp = kzalloc(sizeof(*cp), GFP_KERNEL);
if (!cp) {
pr_err("qcrypto Memory allocation of q_alg FAIL, error %ld\n",
@@ -3572,7 +3600,7 @@
},
};
-static int _debug_qcrypto[MAX_CRYPTO_DEVICE];
+static int _debug_qcrypto;
static int _debug_stats_open(struct inode *inode, struct file *file)
{
@@ -3599,9 +3627,7 @@
size_t count, loff_t *ppos)
{
- int qcrypto = *((int *) file->private_data);
-
- memset((char *)&_qcrypto_stat[qcrypto], 0, sizeof(struct crypto_stat));
+ memset((char *)&_qcrypto_stat, 0, sizeof(struct crypto_stat));
return count;
};
@@ -3615,7 +3641,6 @@
{
int rc;
char name[DEBUG_MAX_FNAME];
- int i;
struct dentry *dent;
_debug_dent = debugfs_create_dir("qcrypto", NULL);
@@ -3625,17 +3650,15 @@
return PTR_ERR(_debug_dent);
}
- for (i = 0; i < MAX_CRYPTO_DEVICE; i++) {
- snprintf(name, DEBUG_MAX_FNAME-1, "stats-%d", i+1);
- _debug_qcrypto[i] = i;
- dent = debugfs_create_file(name, 0644, _debug_dent,
- &_debug_qcrypto[i], &_debug_stats_ops);
- if (dent == NULL) {
- pr_err("qcrypto debugfs_create_file fail, error %ld\n",
- PTR_ERR(dent));
- rc = PTR_ERR(dent);
- goto err;
- }
+ snprintf(name, DEBUG_MAX_FNAME-1, "stats-%d", 1);
+ _debug_qcrypto = 0;
+ dent = debugfs_create_file(name, 0644, _debug_dent,
+ &_debug_qcrypto, &_debug_stats_ops);
+ if (dent == NULL) {
+ pr_err("qcrypto debugfs_create_file fail, error %ld\n",
+ PTR_ERR(dent));
+ rc = PTR_ERR(dent);
+ goto err;
}
return 0;
err:
diff --git a/drivers/crypto/msm/qcryptohw_50.h b/drivers/crypto/msm/qcryptohw_50.h
index 245d737..2210dc8 100644
--- a/drivers/crypto/msm/qcryptohw_50.h
+++ b/drivers/crypto/msm/qcryptohw_50.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -14,6 +14,10 @@
#define _DRIVERS_CRYPTO_MSM_QCRYPTOHW_50_H_
+#define CRYPTO_BAM_CNFG_BITS_REG 0x0007C
+#define CRYPTO_BAM_CD_ENABLE 27
+#define CRYPTO_BAM_CD_ENABLE_MASK (1 << CRYPTO_BAM_CD_ENABLE)
+
#define QCE_AUTH_REG_BYTE_COUNT 4
#define CRYPTO_VERSION_REG 0x1A000
@@ -28,7 +32,7 @@
#define CRYPTO_DATA_OUT3_REG 0x1A02C
#define CRYPTO_STATUS_REG 0x1A100
-#define CRYPTO_STATUS2_REG 0x1A100
+#define CRYPTO_STATUS2_REG 0x1A104
#define CRYPTO_ENGINES_AVAIL 0x1A108
#define CRYPTO_FIFO_SIZES_REG 0x1A10C
@@ -64,9 +68,9 @@
#define CRYPTO_ENCR_PIPE0_KEY2_REG 0x1E008
#define CRYPTO_ENCR_PIPE0_KEY3_REG 0x1E00C
#define CRYPTO_ENCR_PIPE0_KEY4_REG 0x1E010
-#define CRYPTO_ENCR_PIPE0_KEY5_REG 0x1E004
-#define CRYPTO_ENCR_PIPE0_KEY6_REG 0x1E008
-#define CRYPTO_ENCR_PIPE0_KEY7_REG 0x1E00C
+#define CRYPTO_ENCR_PIPE0_KEY5_REG 0x1E014
+#define CRYPTO_ENCR_PIPE0_KEY6_REG 0x1E018
+#define CRYPTO_ENCR_PIPE0_KEY7_REG 0x1E01C
#define CRYPTO_ENCR_PIPE1_KEY0_REG 0x1E020
#define CRYPTO_ENCR_PIPE1_KEY1_REG 0x1E024
@@ -185,56 +189,56 @@
#define CRYPTO_AUTH_PIPE0_KEY14_REG 0x1E838
#define CRYPTO_AUTH_PIPE0_KEY15_REG 0x1E83C
-#define CRYPTO_AUTH_PIPE1_KEY0_REG 0x1E800
-#define CRYPTO_AUTH_PIPE1_KEY1_REG 0x1E804
-#define CRYPTO_AUTH_PIPE1_KEY2_REG 0x1E808
-#define CRYPTO_AUTH_PIPE1_KEY3_REG 0x1E80C
-#define CRYPTO_AUTH_PIPE1_KEY4_REG 0x1E810
-#define CRYPTO_AUTH_PIPE1_KEY5_REG 0x1E814
-#define CRYPTO_AUTH_PIPE1_KEY6_REG 0x1E818
-#define CRYPTO_AUTH_PIPE1_KEY7_REG 0x1E81C
-#define CRYPTO_AUTH_PIPE1_KEY8_REG 0x1E820
-#define CRYPTO_AUTH_PIPE1_KEY9_REG 0x1E824
-#define CRYPTO_AUTH_PIPE1_KEY10_REG 0x1E828
-#define CRYPTO_AUTH_PIPE1_KEY11_REG 0x1E82C
-#define CRYPTO_AUTH_PIPE1_KEY12_REG 0x1E830
-#define CRYPTO_AUTH_PIPE1_KEY13_REG 0x1E834
-#define CRYPTO_AUTH_PIPE1_KEY14_REG 0x1E838
-#define CRYPTO_AUTH_PIPE1_KEY15_REG 0x1E83C
+#define CRYPTO_AUTH_PIPE1_KEY0_REG 0x1E880
+#define CRYPTO_AUTH_PIPE1_KEY1_REG 0x1E884
+#define CRYPTO_AUTH_PIPE1_KEY2_REG 0x1E888
+#define CRYPTO_AUTH_PIPE1_KEY3_REG 0x1E88C
+#define CRYPTO_AUTH_PIPE1_KEY4_REG 0x1E890
+#define CRYPTO_AUTH_PIPE1_KEY5_REG 0x1E894
+#define CRYPTO_AUTH_PIPE1_KEY6_REG 0x1E898
+#define CRYPTO_AUTH_PIPE1_KEY7_REG 0x1E89C
+#define CRYPTO_AUTH_PIPE1_KEY8_REG 0x1E8A0
+#define CRYPTO_AUTH_PIPE1_KEY9_REG 0x1E8A4
+#define CRYPTO_AUTH_PIPE1_KEY10_REG 0x1E8A8
+#define CRYPTO_AUTH_PIPE1_KEY11_REG 0x1E8AC
+#define CRYPTO_AUTH_PIPE1_KEY12_REG 0x1E8B0
+#define CRYPTO_AUTH_PIPE1_KEY13_REG 0x1E8B4
+#define CRYPTO_AUTH_PIPE1_KEY14_REG 0x1E8B8
+#define CRYPTO_AUTH_PIPE1_KEY15_REG 0x1E8BC
-#define CRYPTO_AUTH_PIPE2_KEY0_REG 0x1E840
-#define CRYPTO_AUTH_PIPE2_KEY1_REG 0x1E844
-#define CRYPTO_AUTH_PIPE2_KEY2_REG 0x1E848
-#define CRYPTO_AUTH_PIPE2_KEY3_REG 0x1E84C
-#define CRYPTO_AUTH_PIPE2_KEY4_REG 0x1E850
-#define CRYPTO_AUTH_PIPE2_KEY5_REG 0x1E854
-#define CRYPTO_AUTH_PIPE2_KEY6_REG 0x1E858
-#define CRYPTO_AUTH_PIPE2_KEY7_REG 0x1E85C
-#define CRYPTO_AUTH_PIPE2_KEY8_REG 0x1E860
-#define CRYPTO_AUTH_PIPE2_KEY9_REG 0x1E864
-#define CRYPTO_AUTH_PIPE2_KEY10_REG 0x1E868
-#define CRYPTO_AUTH_PIPE2_KEY11_REG 0x1E86C
-#define CRYPTO_AUTH_PIPE2_KEY12_REG 0x1E870
-#define CRYPTO_AUTH_PIPE2_KEY13_REG 0x1E874
-#define CRYPTO_AUTH_PIPE2_KEY14_REG 0x1E878
-#define CRYPTO_AUTH_PIPE2_KEY15_REG 0x1E87C
+#define CRYPTO_AUTH_PIPE2_KEY0_REG 0x1E900
+#define CRYPTO_AUTH_PIPE2_KEY1_REG 0x1E904
+#define CRYPTO_AUTH_PIPE2_KEY2_REG 0x1E908
+#define CRYPTO_AUTH_PIPE2_KEY3_REG 0x1E90C
+#define CRYPTO_AUTH_PIPE2_KEY4_REG 0x1E910
+#define CRYPTO_AUTH_PIPE2_KEY5_REG 0x1E914
+#define CRYPTO_AUTH_PIPE2_KEY6_REG 0x1E918
+#define CRYPTO_AUTH_PIPE2_KEY7_REG 0x1E91C
+#define CRYPTO_AUTH_PIPE2_KEY8_REG 0x1E920
+#define CRYPTO_AUTH_PIPE2_KEY9_REG 0x1E924
+#define CRYPTO_AUTH_PIPE2_KEY10_REG 0x1E928
+#define CRYPTO_AUTH_PIPE2_KEY11_REG 0x1E92C
+#define CRYPTO_AUTH_PIPE2_KEY12_REG 0x1E930
+#define CRYPTO_AUTH_PIPE2_KEY13_REG 0x1E934
+#define CRYPTO_AUTH_PIPE2_KEY14_REG 0x1E938
+#define CRYPTO_AUTH_PIPE2_KEY15_REG 0x1E93C
-#define CRYPTO_AUTH_PIPE3_KEY0_REG 0x1E880
-#define CRYPTO_AUTH_PIPE3_KEY1_REG 0x1E884
-#define CRYPTO_AUTH_PIPE3_KEY2_REG 0x1E888
-#define CRYPTO_AUTH_PIPE3_KEY3_REG 0x1E88C
-#define CRYPTO_AUTH_PIPE3_KEY4_REG 0x1E890
-#define CRYPTO_AUTH_PIPE3_KEY5_REG 0x1E894
-#define CRYPTO_AUTH_PIPE3_KEY6_REG 0x1E898
-#define CRYPTO_AUTH_PIPE3_KEY7_REG 0x1E89C
-#define CRYPTO_AUTH_PIPE3_KEY8_REG 0x1E8A0
-#define CRYPTO_AUTH_PIPE3_KEY9_REG 0x1E8A4
-#define CRYPTO_AUTH_PIPE3_KEY10_REG 0x1E8A8
-#define CRYPTO_AUTH_PIPE3_KEY11_REG 0x1E8AC
-#define CRYPTO_AUTH_PIPE3_KEY12_REG 0x1E8B0
-#define CRYPTO_AUTH_PIPE3_KEY13_REG 0x1E8B4
-#define CRYPTO_AUTH_PIPE3_KEY14_REG 0x1E8B8
-#define CRYPTO_AUTH_PIPE3_KEY15_REG 0x1E8BC
+#define CRYPTO_AUTH_PIPE3_KEY0_REG 0x1E980
+#define CRYPTO_AUTH_PIPE3_KEY1_REG 0x1E984
+#define CRYPTO_AUTH_PIPE3_KEY2_REG 0x1E988
+#define CRYPTO_AUTH_PIPE3_KEY3_REG 0x1E98C
+#define CRYPTO_AUTH_PIPE3_KEY4_REG 0x1E990
+#define CRYPTO_AUTH_PIPE3_KEY5_REG 0x1E994
+#define CRYPTO_AUTH_PIPE3_KEY6_REG 0x1E998
+#define CRYPTO_AUTH_PIPE3_KEY7_REG 0x1E99C
+#define CRYPTO_AUTH_PIPE3_KEY8_REG 0x1E9A0
+#define CRYPTO_AUTH_PIPE3_KEY9_REG 0x1E9A4
+#define CRYPTO_AUTH_PIPE3_KEY10_REG 0x1E9A8
+#define CRYPTO_AUTH_PIPE3_KEY11_REG 0x1E9AC
+#define CRYPTO_AUTH_PIPE3_KEY12_REG 0x1E9B0
+#define CRYPTO_AUTH_PIPE3_KEY13_REG 0x1E9B4
+#define CRYPTO_AUTH_PIPE3_KEY14_REG 0x1E9B8
+#define CRYPTO_AUTH_PIPE3_KEY15_REG 0x1E9BC
#define CRYPTO_AUTH_IV0_REG 0x1A310
@@ -421,6 +425,7 @@
#define CRYPTO_AUTH_ALG_AES 2
#define CRYPTO_AUTH_ALG_KASUMI 3
#define CRYPTO_AUTH_ALG_SNOW3G 4
+#define CRYPTO_AUTH_ALG_ZUC 5
/* encr_xts_du_size reg */
#define CRYPTO_ENCR_XTS_DU_SIZE 0 /* bit 19-0 */
@@ -471,33 +476,49 @@
#define CRYPTO_ENCR_KEY_SZ_3DES 1
#define CRYPTO_ENCR_KEY_SZ_AES128 0
#define CRYPTO_ENCR_KEY_SZ_AES256 2
-#define CRYPTO_ENCR_KEY_SZ_UEA1 0
-#define CRYPTO_ENCR_KEY_SZ_UEA2 1
#define CRYPTO_ENCR_ALG 0 /* bit 2-0 */
#define CRYPTO_ENCR_ALG_MASK (7 << CRYPTO_ENCR_ALG)
#define CRYPTO_ENCR_ALG_NONE 0
#define CRYPTO_ENCR_ALG_DES 1
#define CRYPTO_ENCR_ALG_AES 2
-#define CRYPTO_ENCR_ALG_KASUMI 3
+#define CRYPTO_ENCR_ALG_KASUMI 4
#define CRYPTO_ENCR_ALG_SNOW_3G 5
+#define CRYPTO_ENCR_ALG_ZUC 6
/* goproc reg */
#define CRYPTO_GO 0
#define CRYPTO_CLR_CNTXT 1
#define CRYPTO_RESULTS_DUMP 2
+/* F8 definition of CRYPTO_ENCR_CNTR1_IV1 REG */
+#define CRYPTO_CNTR1_IV1_REG_F8_PKT_CNT 16 /* bit 31 - 16 */
+#define CRYPTO_CNTR1_IV1_REG_F8_PKT_CNT_MASK \
+ (0xffff << CRYPTO_CNTR1_IV1_REG_F8_PKT_CNT)
+
+#define CRYPTO_CNTR1_IV1_REG_F8_BEARER 0 /* bit 4 - 0 */
+#define CRYPTO_CNTR1_IV1_REG_F8_BEARER_MASK \
+ (0x1f << CRYPTO_CNTR1_IV1_REG_F8_BEARER)
+
+/* F9 definition of CRYPTO_AUTH_IV4 REG */
+#define CRYPTO_AUTH_IV4_REG_F9_VALID_BIS 0 /* bit 2 - 0 */
+#define CRYPTO_AUTH_IV4_REG_F9_VALID_BIS_MASK \
+ (0x7 << CRYPTO_AUTH_IV4_REG_F9_VALID_BIS)
/* engines_avail */
#define CRYPTO_ENCR_AES_SEL 0
-#define CRYPTO_DES_SEL 3
-#define CRYPTO_ENCR_SNOW3G_SEL 4
-#define CRYPTO_ENCR_KASUMI_SEL 5
-#define CRYPTO_SHA_SEL 6
-#define CRYPTO_SHA512_SEL 7
-#define CRYPTO_AUTH_AES_SEL 8
-#define CRYPTO_AUTH_SNOW3G_SEL 9
-#define CRYPTO_AUTH_KASUMI_SEL 10
-#define CRYPTO_BAM_SEL 11
-
+#define CRYPTO_DES_SEL 1
+#define CRYPTO_ENCR_SNOW3G_SEL 2
+#define CRYPTO_ENCR_KASUMI_SEL 3
+#define CRYPTO_SHA_SEL 4
+#define CRYPTO_SHA512_SEL 5
+#define CRYPTO_AUTH_AES_SEL 6
+#define CRYPTO_AUTH_SNOW3G_SEL 7
+#define CRYPTO_AUTH_KASUMI_SEL 8
+#define CRYPTO_BAM_PIPE_SETS 9 /* bit 12 - 9 */
+#define CRYPTO_AXI_WR_BEATS 13 /* bit 18 - 13 */
+#define CRYPTO_AXI_RD_BEATS 19 /* bit 24 - 19 */
+#define CRYPTO_ENCR_ZUC_SEL 26
+#define CRYPTO_AUTH_ZUC_SEL 27
+#define CRYPTO_ZUC_ENABLE 28
#endif /* _DRIVERS_CRYPTO_MSM_QCRYPTOHW_50_H_ */
diff --git a/drivers/gpu/ion/Kconfig b/drivers/gpu/ion/Kconfig
index 39133b5..5bb254b 100644
--- a/drivers/gpu/ion/Kconfig
+++ b/drivers/gpu/ion/Kconfig
@@ -16,12 +16,3 @@
depends on ARCH_MSM && ION
help
Choose this option if you wish to use ion on an MSM target.
-
-config ION_LEAK_CHECK
- bool "Check for leaked Ion buffers (debugging)"
- depends on ION
- help
- Choose this option if you wish to enable checking for leaked
- ion buffers at runtime. Choosing this option will also add a
- debugfs node under the ion directory that can be used to
- enable/disable the leak checking.
diff --git a/drivers/gpu/ion/Makefile b/drivers/gpu/ion/Makefile
index d7ff73a..0e460c8 100644
--- a/drivers/gpu/ion/Makefile
+++ b/drivers/gpu/ion/Makefile
@@ -1,6 +1,5 @@
-obj-$(CONFIG_ION) += ion.o ion_heap.o ion_system_heap.o ion_carveout_heap.o \
- ion_iommu_heap.o ion_cp_heap.o ion_removed_heap.o \
- ion_page_pool.o ion_chunk_heap.o
+obj-$(CONFIG_ION) += ion.o ion_heap.o ion_page_pool.o ion_system_heap.o \
+ ion_carveout_heap.o ion_chunk_heap.o
obj-$(CONFIG_CMA) += ion_cma_heap.o ion_cma_secure_heap.o
obj-$(CONFIG_ION_TEGRA) += tegra/
-obj-$(CONFIG_ION_MSM) += msm/
+obj-$(CONFIG_ION_MSM) += ion_iommu_heap.o ion_cp_heap.o ion_removed_heap.o msm/
diff --git a/drivers/gpu/ion/ion.c b/drivers/gpu/ion/ion.c
index fbe4da0..250b387 100644
--- a/drivers/gpu/ion/ion.c
+++ b/drivers/gpu/ion/ion.c
@@ -16,7 +16,6 @@
*
*/
-#include <linux/module.h>
#include <linux/device.h>
#include <linux/file.h>
#include <linux/freezer.h>
@@ -27,6 +26,7 @@
#include <linux/list.h>
#include <linux/memblock.h>
#include <linux/miscdevice.h>
+#include <linux/export.h>
#include <linux/mm.h>
#include <linux/mm_types.h>
#include <linux/rbtree.h>
@@ -41,7 +41,6 @@
#include <trace/events/kmem.h>
-#include <mach/iommu_domains.h>
#include "ion_priv.h"
/**
@@ -83,7 +82,6 @@
struct ion_device *dev;
struct rb_root handles;
struct mutex lock;
- unsigned int heap_type_mask;
char *name;
struct task_struct *task;
pid_t pid;
@@ -108,7 +106,6 @@
struct ion_buffer *buffer;
struct rb_node node;
unsigned int kmap_cnt;
- unsigned int iommu_map_cnt;
};
bool ion_buffer_fault_user_mappings(struct ion_buffer *buffer)
@@ -545,8 +542,8 @@
mutex_lock(&client->lock);
valid_handle = ion_handle_validate(client, handle);
if (!valid_handle) {
- mutex_unlock(&client->lock);
WARN(1, "%s: invalid handle passed to free.\n", __func__);
+ mutex_unlock(&client->lock);
return;
}
ion_handle_put(handle);
@@ -678,30 +675,21 @@
struct ion_client *client = s->private;
struct rb_node *n;
- seq_printf(s, "%16.16s: %16.16s : %16.16s : %12.12s : %12.12s : %s\n",
+ seq_printf(s, "%16.16s: %16.16s : %16.16s : %12.12s\n",
"heap_name", "size_in_bytes", "handle refcount",
- "buffer", "physical", "[domain,partition] - virt");
+ "buffer");
mutex_lock(&client->lock);
for (n = rb_first(&client->handles); n; n = rb_next(n)) {
struct ion_handle *handle = rb_entry(n, struct ion_handle,
node);
- enum ion_heap_type type = handle->buffer->heap->type;
-
seq_printf(s, "%16.16s: %16x : %16d : %12p",
handle->buffer->heap->name,
handle->buffer->size,
atomic_read(&handle->ref.refcount),
handle->buffer);
- if (type == ION_HEAP_TYPE_SYSTEM_CONTIG ||
- type == ION_HEAP_TYPE_CARVEOUT ||
- type == (enum ion_heap_type) ION_HEAP_TYPE_CP)
- seq_printf(s, " : %12pa", &handle->buffer->priv_phys);
- else
- seq_printf(s, " : %12s", "N/A");
-
seq_printf(s, "\n");
}
mutex_unlock(&client->lock);
@@ -1287,8 +1275,8 @@
ion_free(client, data.handle);
break;
}
- case ION_IOC_MAP:
case ION_IOC_SHARE:
+ case ION_IOC_MAP:
{
struct ion_fd_data data;
if (copy_from_user(&data, (void __user *)arg, sizeof(data)))
@@ -1391,7 +1379,7 @@
};
static size_t ion_debug_heap_total(struct ion_client *client,
- enum ion_heap_ids id)
+ unsigned int id)
{
size_t size = 0;
struct rb_node *n;
@@ -1560,7 +1548,6 @@
size_t total_size = 0;
size_t total_orphaned_size = 0;
- mutex_lock(&dev->buffer_lock);
seq_printf(s, "%16.s %16.s %16.s\n", "client", "pid", "size");
seq_printf(s, "----------------------------------------------------\n");
@@ -1584,25 +1571,31 @@
seq_printf(s, "----------------------------------------------------\n");
seq_printf(s, "orphaned allocations (info is from last known client):"
"\n");
+ mutex_lock(&dev->buffer_lock);
for (n = rb_first(&dev->buffers); n; n = rb_next(n)) {
struct ion_buffer *buffer = rb_entry(n, struct ion_buffer,
node);
- if (buffer->heap->type == heap->type)
- total_size += buffer->size;
+ if (buffer->heap->id != heap->id)
+ continue;
+ total_size += buffer->size;
if (!buffer->handle_count) {
- seq_printf(s, "%16.s %16u %16u\n", buffer->task_comm,
- buffer->pid, buffer->size);
+ seq_printf(s, "%16.s %16u %16u %d %d\n", buffer->task_comm,
+ buffer->pid, buffer->size, buffer->kmap_cnt,
+ atomic_read(&buffer->ref.refcount));
total_orphaned_size += buffer->size;
}
}
+ mutex_unlock(&dev->buffer_lock);
seq_printf(s, "----------------------------------------------------\n");
seq_printf(s, "%16.s %16u\n", "total orphaned",
total_orphaned_size);
seq_printf(s, "%16.s %16u\n", "total ", total_size);
seq_printf(s, "----------------------------------------------------\n");
+ if (heap->debug_show)
+ heap->debug_show(heap, s, unused);
+
ion_heap_print_debug(s, heap);
- mutex_unlock(&dev->buffer_lock);
return 0;
}
diff --git a/drivers/gpu/ion/ion_carveout_heap.c b/drivers/gpu/ion/ion_carveout_heap.c
index 0dd3054..08921299 100644
--- a/drivers/gpu/ion/ion_carveout_heap.c
+++ b/drivers/gpu/ion/ion_carveout_heap.c
@@ -37,7 +37,6 @@
ion_phys_addr_t base;
unsigned long allocated_bytes;
unsigned long total_size;
- unsigned int has_outer_cache;
};
ion_phys_addr_t ion_carveout_allocate(struct ion_heap *heap,
@@ -254,7 +253,6 @@
carveout_heap->heap.type = ION_HEAP_TYPE_CARVEOUT;
carveout_heap->allocated_bytes = 0;
carveout_heap->total_size = heap_data->size;
- carveout_heap->has_outer_cache = heap_data->has_outer_cache;
return &carveout_heap->heap;
}
diff --git a/drivers/gpu/ion/ion_priv.h b/drivers/gpu/ion/ion_priv.h
index 4b724df..e3fbbda 100644
--- a/drivers/gpu/ion/ion_priv.h
+++ b/drivers/gpu/ion/ion_priv.h
@@ -247,14 +247,12 @@
unsigned long align);
void ion_carveout_free(struct ion_heap *heap, ion_phys_addr_t addr,
unsigned long size);
-
/**
* The carveout heap returns physical addresses, since 0 may be a valid
* physical address, this is used to indicate allocation failed
*/
#define ION_CARVEOUT_ALLOCATE_FAIL -1
-
/**
* functions for creating and destroying a heap pool -- allows you
* to keep a pool of pre allocated memory to use from your heap. Keeping
diff --git a/drivers/gpu/ion/ion_system_heap.c b/drivers/gpu/ion/ion_system_heap.c
index a44011f..fb6dc2d 100644
--- a/drivers/gpu/ion/ion_system_heap.c
+++ b/drivers/gpu/ion/ion_system_heap.c
@@ -26,9 +26,6 @@
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include "ion_priv.h"
-#include <mach/memory.h>
-#include <asm/cacheflush.h>
-#include <linux/msm_ion.h>
#include <linux/dma-mapping.h>
#include <trace/events/kmem.h>
@@ -265,7 +262,27 @@
.map_user = ion_heap_map_user,
};
-struct ion_heap *ion_system_heap_create(struct ion_platform_heap *pheap)
+static int ion_system_heap_debug_show(struct ion_heap *heap, struct seq_file *s,
+ void *unused)
+{
+
+ struct ion_system_heap *sys_heap = container_of(heap,
+ struct ion_system_heap,
+ heap);
+ int i;
+ for (i = 0; i < num_orders; i++) {
+ struct ion_page_pool *pool = sys_heap->pools[i];
+ seq_printf(s, "%d order %u highmem pages in pool = %lu total\n",
+ pool->high_count, pool->order,
+ (1 << pool->order) * PAGE_SIZE * pool->high_count);
+ seq_printf(s, "%d order %u lowmem pages in pool = %lu total\n",
+ pool->low_count, pool->order,
+ (1 << pool->order) * PAGE_SIZE * pool->low_count);
+ }
+ return 0;
+}
+
+struct ion_heap *ion_system_heap_create(struct ion_platform_heap *unused)
{
struct ion_system_heap *heap;
int i;
@@ -291,6 +308,7 @@
goto err_create_pool;
heap->pools[i] = pool;
}
+ heap->heap.debug_show = ion_system_heap_debug_show;
return &heap->heap;
err_create_pool:
for (i = 0; i < num_orders; i++)
@@ -378,7 +396,7 @@
.map_user = ion_heap_map_user,
};
-struct ion_heap *ion_system_contig_heap_create(struct ion_platform_heap *pheap)
+struct ion_heap *ion_system_contig_heap_create(struct ion_platform_heap *unused)
{
struct ion_heap *heap;
diff --git a/drivers/gpu/ion/msm/ion_iommu_map.c b/drivers/gpu/ion/msm/ion_iommu_map.c
index 5ce03db..c8fb3c1 100644
--- a/drivers/gpu/ion/msm/ion_iommu_map.c
+++ b/drivers/gpu/ion/msm/ion_iommu_map.c
@@ -11,6 +11,7 @@
*
*/
+#include <linux/dma-buf.h>
#include <linux/export.h>
#include <linux/iommu.h>
#include <linux/ion.h>
@@ -69,6 +70,7 @@
struct sg_table *table;
unsigned long size;
struct mutex lock;
+ struct dma_buf *dbuf;
};
static struct rb_root iommu_root;
@@ -85,9 +87,9 @@
parent = *p;
entry = rb_entry(parent, struct ion_iommu_meta, node);
- if (meta->handle < entry->handle) {
+ if (meta->table < entry->table) {
p = &(*p)->rb_left;
- } else if (meta->handle > entry->handle) {
+ } else if (meta->table > entry->table) {
p = &(*p)->rb_right;
} else {
pr_err("%s: handle %p already exists\n", __func__,
@@ -101,7 +103,7 @@
}
-static struct ion_iommu_meta *ion_iommu_meta_lookup(struct ion_handle *handle)
+static struct ion_iommu_meta *ion_iommu_meta_lookup(struct sg_table *table)
{
struct rb_root *root = &iommu_root;
struct rb_node **p = &root->rb_node;
@@ -112,9 +114,9 @@
parent = *p;
entry = rb_entry(parent, struct ion_iommu_meta, node);
- if (handle < entry->handle)
+ if (table < entry->table)
p = &(*p)->rb_left;
- else if (handle > entry->handle)
+ else if (table > entry->table)
p = &(*p)->rb_right;
else
return entry;
@@ -319,7 +321,8 @@
return ERR_PTR(ret);
}
-static struct ion_iommu_meta *ion_iommu_meta_create(struct ion_handle *handle,
+static struct ion_iommu_meta *ion_iommu_meta_create(struct ion_client *client,
+ struct ion_handle *handle,
struct sg_table *table,
unsigned long size)
{
@@ -333,6 +336,7 @@
meta->handle = handle;
meta->table = table;
meta->size = size;
+ meta->dbuf = ion_share_dma_buf(client, handle);
kref_init(&meta->ref);
mutex_init(&meta->lock);
ion_iommu_meta_add(meta);
@@ -347,6 +351,7 @@
rb_erase(&meta->node, &iommu_root);
+ dma_buf_put(meta->dbuf);
kfree(meta);
}
@@ -427,13 +432,13 @@
}
mutex_lock(&msm_iommu_map_mutex);
- iommu_meta = ion_iommu_meta_lookup(handle);
+ iommu_meta = ion_iommu_meta_lookup(table);
if (!iommu_meta)
- iommu_meta = ion_iommu_meta_create(handle, table, size);
+ iommu_meta = ion_iommu_meta_create(client, handle, table, size);
else
kref_get(&iommu_meta->ref);
-
+ BUG_ON(iommu_meta->size != size);
mutex_unlock(&msm_iommu_map_mutex);
iommu_map = ion_iommu_lookup(iommu_meta, domain_num, partition_num);
@@ -493,6 +498,7 @@
{
struct ion_iommu_map *iommu_map;
struct ion_iommu_meta *meta;
+ struct sg_table *table;
if (IS_ERR_OR_NULL(client)) {
pr_err("%s: client pointer is invalid\n", __func__);
@@ -503,9 +509,10 @@
return;
}
+ table = ion_sg_table(client, handle);
mutex_lock(&msm_iommu_map_mutex);
- meta = ion_iommu_meta_lookup(handle);
+ meta = ion_iommu_meta_lookup(table);
if (!meta) {
WARN(1, "%s: (%d,%d) was never mapped for %p\n", __func__,
domain_num, partition_num, handle);
diff --git a/drivers/gpu/ion/msm/msm_ion.c b/drivers/gpu/ion/msm/msm_ion.c
index f43d276..4a45313 100644
--- a/drivers/gpu/ion/msm/msm_ion.c
+++ b/drivers/gpu/ion/msm/msm_ion.c
@@ -89,7 +89,7 @@
},
{
.id = ION_QSECOM_HEAP_ID,
- .type = ION_HEAP_TYPE_CARVEOUT,
+ .type = ION_HEAP_TYPE_DMA,
.name = ION_QSECOM_HEAP_NAME,
},
{
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 08791a3..e6c345b 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -2323,7 +2323,7 @@
}
/* Check if we detected a long running IB, if false return */
- if (adreno_dev->long_ib) {
+ if ((adreno_context) && (adreno_dev->long_ib)) {
long_ib = _adreno_check_long_ib(device);
if (!long_ib) {
adreno_context->flags &= ~CTXT_FLAGS_GPU_HANG;
diff --git a/drivers/gpu/msm/adreno_snapshot.c b/drivers/gpu/msm/adreno_snapshot.c
index a76ed87..967e4ab 100644
--- a/drivers/gpu/msm/adreno_snapshot.c
+++ b/drivers/gpu/msm/adreno_snapshot.c
@@ -785,13 +785,13 @@
struct kgsl_memdesc *memdesc =
adreno_find_ctxtmem(device, ptbase, ibaddr,
- ibsize);
+ ibsize << 2);
/* IOMMU uses a NOP IB placed in setsate memory */
if (NULL == memdesc)
if (kgsl_gpuaddr_in_memdesc(
&device->mmu.setstate_memory,
- ibaddr, ibsize))
+ ibaddr, ibsize << 2))
memdesc = &device->mmu.setstate_memory;
/*
* The IB from CP_IB1_BASE and the IBs for legacy
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 5275267..60e457d 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -144,10 +144,13 @@
* @ptbase - the pagetable base of the object
* @gpuaddr - the GPU address of the object
* @size - Size of the region to search
+ *
+ * Caller must kgsl_mem_entry_put() the returned entry when finished using it.
*/
-struct kgsl_mem_entry *kgsl_get_mem_entry(struct kgsl_device *device,
- unsigned int ptbase, unsigned int gpuaddr, unsigned int size)
+struct kgsl_mem_entry * __must_check
+kgsl_get_mem_entry(struct kgsl_device *device, unsigned int ptbase,
+ unsigned int gpuaddr, unsigned int size)
{
struct kgsl_process_private *priv;
struct kgsl_mem_entry *entry;
@@ -157,15 +160,12 @@
list_for_each_entry(priv, &kgsl_driver.process_list, list) {
if (!kgsl_mmu_pt_equal(&device->mmu, priv->pagetable, ptbase))
continue;
- spin_lock(&priv->mem_lock);
entry = kgsl_sharedmem_find_region(priv, gpuaddr, size);
if (entry) {
- spin_unlock(&priv->mem_lock);
mutex_unlock(&kgsl_driver.process_mutex);
return entry;
}
- spin_unlock(&priv->mem_lock);
}
mutex_unlock(&kgsl_driver.process_mutex);
@@ -913,8 +913,17 @@
return result;
}
-/*call with private->mem_lock locked */
-struct kgsl_mem_entry *
+/**
+ * kgsl_sharedmem_find_region() - Find a gpu memory allocation
+ *
+ * @private: private data for the process to check.
+ * @gpuaddr: start address of the region
+ * @size: size of the region
+ *
+ * Find a gpu allocation. Caller must kgsl_mem_entry_put()
+ * the returned entry when finished using it.
+ */
+struct kgsl_mem_entry * __must_check
kgsl_sharedmem_find_region(struct kgsl_process_private *private,
unsigned int gpuaddr, size_t size)
{
@@ -923,46 +932,57 @@
if (!kgsl_mmu_gpuaddr_in_range(private->pagetable, gpuaddr))
return NULL;
+ spin_lock(&private->mem_lock);
while (node != NULL) {
struct kgsl_mem_entry *entry;
entry = rb_entry(node, struct kgsl_mem_entry, node);
-
- if (kgsl_gpuaddr_in_memdesc(&entry->memdesc, gpuaddr, size))
+ if (kgsl_gpuaddr_in_memdesc(&entry->memdesc, gpuaddr, size)) {
+ kgsl_mem_entry_get(entry);
+ spin_unlock(&private->mem_lock);
return entry;
-
+ }
if (gpuaddr < entry->memdesc.gpuaddr)
node = node->rb_left;
else if (gpuaddr >=
(entry->memdesc.gpuaddr + entry->memdesc.size))
node = node->rb_right;
else {
+ spin_unlock(&private->mem_lock);
return NULL;
}
}
+ spin_unlock(&private->mem_lock);
return NULL;
}
EXPORT_SYMBOL(kgsl_sharedmem_find_region);
-/*call with private->mem_lock locked */
-static inline struct kgsl_mem_entry *
+/**
+ * kgsl_sharedmem_find() - Find a gpu memory allocation
+ *
+ * @private: private data for the process to check.
+ * @gpuaddr: start address of the region
+ *
+ * Find a gpu allocation. Caller must kgsl_mem_entry_put()
+ * the returned entry when finished using it.
+ */
+static inline struct kgsl_mem_entry * __must_check
kgsl_sharedmem_find(struct kgsl_process_private *private, unsigned int gpuaddr)
{
return kgsl_sharedmem_find_region(private, gpuaddr, 1);
}
/**
- * kgsl_sharedmem_region_empty - Check if an addression region is empty
+ * kgsl_sharedmem_region_empty() - Check if an addression region is empty
*
* @private: private data for the process to check.
* @gpuaddr: start address of the region
* @size: length of the region.
*
* Checks that there are no existing allocations within an address
- * region. Note that unlike other kgsl_sharedmem* search functions,
- * this one manages locking on its own.
+ * region.
*/
int
kgsl_sharedmem_region_empty(struct kgsl_process_private *private,
@@ -1006,19 +1026,24 @@
}
/**
- * kgsl_sharedmem_find_id - find a memory entry by id
+ * kgsl_sharedmem_find_id() - find a memory entry by id
* @process: the owning process
* @id: id to find
*
* @returns - the mem_entry or NULL
+ *
+ * Caller must kgsl_mem_entry_put() the returned entry, when finished using
+ * it.
*/
-static inline struct kgsl_mem_entry *
+static inline struct kgsl_mem_entry * __must_check
kgsl_sharedmem_find_id(struct kgsl_process_private *process, unsigned int id)
{
struct kgsl_mem_entry *entry;
rcu_read_lock();
entry = idr_find(&process->mem_idr, id);
+ if (entry)
+ kgsl_mem_entry_get(entry);
rcu_read_unlock();
return entry;
@@ -1314,15 +1339,12 @@
struct kgsl_device *device = dev_priv->device;
unsigned int context_id = context ? context->id : KGSL_MEMSTORE_GLOBAL;
- spin_lock(&dev_priv->process_priv->mem_lock);
entry = kgsl_sharedmem_find(dev_priv->process_priv, gpuaddr);
- spin_unlock(&dev_priv->process_priv->mem_lock);
if (!entry) {
KGSL_DRV_ERR(dev_priv->device,
"invalid gpuaddr %08x\n", gpuaddr);
- result = -EINVAL;
- goto done;
+ return -EINVAL;
}
trace_kgsl_mem_timestamp_queue(device, entry, context_id,
kgsl_readtimestamp(device, context,
@@ -1330,7 +1352,7 @@
timestamp);
result = kgsl_add_event(dev_priv->device, context_id, timestamp,
kgsl_freemem_event_cb, entry, dev_priv);
-done:
+ kgsl_mem_entry_put(entry);
return result;
}
@@ -1416,15 +1438,13 @@
struct kgsl_process_private *private = dev_priv->process_priv;
struct kgsl_mem_entry *entry = NULL;
- spin_lock(&private->mem_lock);
entry = kgsl_sharedmem_find(private, param->gpuaddr);
- spin_unlock(&private->mem_lock);
-
if (!entry) {
KGSL_MEM_INFO(dev_priv->device, "invalid gpuaddr %08x\n",
param->gpuaddr);
return -EINVAL;
}
+
trace_kgsl_mem_free(entry);
kgsl_memfree_hist_set_event(entry->priv->pid,
@@ -1433,6 +1453,7 @@
entry->memdesc.flags);
kgsl_mem_entry_detach_process(entry);
+ kgsl_mem_entry_put(entry);
return 0;
}
@@ -1457,6 +1478,7 @@
entry->memdesc.flags);
kgsl_mem_entry_detach_process(entry);
+ kgsl_mem_entry_put(entry);
return 0;
}
@@ -1990,6 +2012,7 @@
struct kgsl_gpumem_sync_cache *param = data;
struct kgsl_process_private *private = dev_priv->process_priv;
struct kgsl_mem_entry *entry = NULL;
+ long ret;
if (param->id != 0) {
entry = kgsl_sharedmem_find_id(private, param->id);
@@ -1999,9 +2022,7 @@
return -EINVAL;
}
} else if (param->gpuaddr != 0) {
- spin_lock(&private->mem_lock);
entry = kgsl_sharedmem_find(private, param->gpuaddr);
- spin_unlock(&private->mem_lock);
if (entry == NULL) {
KGSL_MEM_INFO(dev_priv->device,
"can't find gpuaddr %x\n",
@@ -2012,7 +2033,9 @@
return -EINVAL;
}
- return _kgsl_gpumem_sync_cache(entry, param->op);
+ ret = _kgsl_gpumem_sync_cache(entry, param->op);
+ kgsl_mem_entry_put(entry);
+ return ret;
}
/* Legacy cache function, does a flush (clean + invalidate) */
@@ -2024,10 +2047,9 @@
struct kgsl_sharedmem_free *param = data;
struct kgsl_process_private *private = dev_priv->process_priv;
struct kgsl_mem_entry *entry = NULL;
+ long ret;
- spin_lock(&private->mem_lock);
entry = kgsl_sharedmem_find(private, param->gpuaddr);
- spin_unlock(&private->mem_lock);
if (entry == NULL) {
KGSL_MEM_INFO(dev_priv->device,
"can't find gpuaddr %x\n",
@@ -2035,7 +2057,9 @@
return -EINVAL;
}
- return _kgsl_gpumem_sync_cache(entry, KGSL_GPUMEM_CACHE_FLUSH);
+ ret = _kgsl_gpumem_sync_cache(entry, KGSL_GPUMEM_CACHE_FLUSH);
+ kgsl_mem_entry_put(entry);
+ return ret;
}
/*
@@ -2173,9 +2197,7 @@
return -EINVAL;
}
} else if (param->gpuaddr != 0) {
- spin_lock(&private->mem_lock);
entry = kgsl_sharedmem_find(private, param->gpuaddr);
- spin_unlock(&private->mem_lock);
if (entry == NULL) {
KGSL_MEM_INFO(dev_priv->device,
"can't find gpuaddr %lx\n",
@@ -2191,6 +2213,8 @@
param->size = entry->memdesc.size;
param->mmapsize = kgsl_memdesc_mmapsize(&entry->memdesc);
param->useraddr = entry->memdesc.useraddr;
+
+ kgsl_mem_entry_put(entry);
return result;
}
@@ -2202,14 +2226,14 @@
struct kgsl_process_private *private = dev_priv->process_priv;
struct kgsl_mem_entry *entry = NULL;
- spin_lock(&private->mem_lock);
entry = kgsl_sharedmem_find_region(private, param->gpuaddr, param->len);
- if (entry)
- kgsl_cffdump_syncmem(dev_priv, &entry->memdesc, param->gpuaddr,
- param->len, true);
- else
- result = -EINVAL;
- spin_unlock(&private->mem_lock);
+ if (!entry)
+ return -EINVAL;
+
+ kgsl_cffdump_syncmem(dev_priv, &entry->memdesc, param->gpuaddr,
+ param->len, true);
+
+ kgsl_mem_entry_put(entry);
return result;
}
@@ -2601,21 +2625,17 @@
struct kgsl_mem_entry **out_entry, unsigned long pgoff,
unsigned long len)
{
- int ret = -EINVAL;
+ int ret = 0;
struct kgsl_mem_entry *entry;
entry = kgsl_sharedmem_find_id(private, pgoff);
if (entry == NULL) {
- spin_lock(&private->mem_lock);
entry = kgsl_sharedmem_find(private, pgoff << PAGE_SHIFT);
- spin_unlock(&private->mem_lock);
}
if (!entry)
return -EINVAL;
- kgsl_mem_entry_get(entry);
-
if (!entry->memdesc.ops ||
!entry->memdesc.ops->vmflags ||
!entry->memdesc.ops->vmfault) {
@@ -2768,6 +2788,10 @@
if (vma_offset == device->memstore.gpuaddr)
return kgsl_mmap_memstore(device, vma);
+ /*
+ * The reference count on the entry that we get from
+ * get_mmap_entry() will be held until kgsl_gpumem_vm_close().
+ */
ret = get_mmap_entry(private, &entry, vma->vm_pgoff,
vma->vm_end - vma->vm_start);
if (ret)
@@ -2837,7 +2861,6 @@
entry->memdesc.useraddr = vma->vm_start;
trace_kgsl_mem_mmap(entry);
-
return 0;
}
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index 869ab25..206f4ef 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -268,6 +268,8 @@
void *base = kgsl_driver.memfree_hist.base_hist_rb;
struct kgsl_memfree_hist_elem *wptr;
struct kgsl_memfree_hist_elem *p;
+ char name[32];
+ memset(name, 0, sizeof(name));
mutex_lock(&kgsl_driver.memfree_hist_mutex);
wptr = kgsl_driver.memfree_hist.wptr;
@@ -277,12 +279,15 @@
if (addr >= p->gpuaddr &&
addr < (p->gpuaddr + p->size)) {
+ kgsl_get_memory_usage(name, sizeof(name) - 1,
+ p->flags),
KGSL_LOG_DUMP(iommu_dev->kgsldev,
"---- premature free ----\n");
KGSL_LOG_DUMP(iommu_dev->kgsldev,
- "[%8.8X-%8.8X] was already freed by pid %d\n",
+ "[%8.8X-%8.8X] (%s) was already freed by pid %d\n",
p->gpuaddr,
p->gpuaddr + p->size,
+ name,
p->pid);
}
p++;
@@ -347,22 +352,17 @@
KGSL_IOMMU_V1_FSYNR0_WNR_SHIFT)) ? 1 : 0);
pid = kgsl_mmu_get_ptname_from_ptbase(mmu, ptbase);
- KGSL_MEM_CRIT(iommu_dev->kgsldev,
- "GPU PAGE FAULT: addr = %lX pid = %d\n", addr, pid);
- KGSL_MEM_CRIT(iommu_dev->kgsldev,
- "context = %d FSR = %X FSYNR0 = %X FSYNR1 = %X(%s fault)\n",
- iommu_dev->ctx_id, fsr, fsynr0, fsynr1,
- write ? "write" : "read");
if (adreno_dev->ft_pf_policy & KGSL_FT_PAGEFAULT_LOG_ONE_PER_PAGE)
no_page_fault_log = kgsl_mmu_log_fault_addr(mmu, ptbase, addr);
if (!no_page_fault_log) {
KGSL_MEM_CRIT(iommu_dev->kgsldev,
- "GPU PAGE FAULT: addr = %lX pid = %d\n",
- addr, kgsl_mmu_get_ptname_from_ptbase(mmu, ptbase));
- KGSL_MEM_CRIT(iommu_dev->kgsldev, "context = %d FSR = %X\n",
- iommu_dev->ctx_id, fsr);
+ "GPU PAGE FAULT: addr = %lX pid = %d\n", addr, pid);
+ KGSL_MEM_CRIT(iommu_dev->kgsldev,
+ "context = %d FSR = %X FSYNR0 = %X FSYNR1 = %X(%s fault)\n",
+ iommu_dev->ctx_id, fsr, fsynr0, fsynr1,
+ write ? "write" : "read");
_check_if_freed(iommu_dev, addr, pid);
diff --git a/drivers/gpu/msm/kgsl_snapshot.c b/drivers/gpu/msm/kgsl_snapshot.c
index abcebfb..4165690 100644
--- a/drivers/gpu/msm/kgsl_snapshot.c
+++ b/drivers/gpu/msm/kgsl_snapshot.c
@@ -345,6 +345,7 @@
struct kgsl_mem_entry *entry;
struct kgsl_snapshot_object *obj;
int offset;
+ int ret = -EINVAL;
entry = kgsl_get_mem_entry(device, ptbase, gpuaddr, size);
@@ -358,7 +359,7 @@
if (entry->memtype != KGSL_MEM_ENTRY_KERNEL) {
KGSL_DRV_ERR(device,
"Only internal GPU buffers can be frozen\n");
- return -EINVAL;
+ goto err_put;
}
/*
@@ -381,7 +382,7 @@
if (size + offset > entry->memdesc.size) {
KGSL_DRV_ERR(device, "Invalid size for GPU buffer %8.8X\n",
gpuaddr);
- return -EINVAL;
+ goto err_put;
}
/* If the buffer is already on the list, skip it */
@@ -390,27 +391,24 @@
/* If the size is different, use the bigger size */
if (obj->size < size)
obj->size = size;
-
- return 0;
+ ret = 0;
+ goto err_put;
}
}
if (kgsl_memdesc_map(&entry->memdesc) == NULL) {
KGSL_DRV_ERR(device, "Unable to map GPU buffer %X\n",
gpuaddr);
- return -EINVAL;
+ goto err_put;
}
obj = kzalloc(sizeof(*obj), GFP_KERNEL);
if (obj == NULL) {
KGSL_DRV_ERR(device, "Unable to allocate memory\n");
- return -EINVAL;
+ goto err_put;
}
- /* Ref count the mem entry */
- kgsl_mem_entry_get(entry);
-
obj->type = type;
obj->entry = entry;
obj->gpuaddr = gpuaddr;
@@ -428,12 +426,15 @@
* 0 so it doesn't get counted twice
*/
- if (entry->memdesc.priv & KGSL_MEMDESC_FROZEN)
- return 0;
+ ret = (entry->memdesc.priv & KGSL_MEMDESC_FROZEN) ? 0
+ : entry->memdesc.size;
entry->memdesc.priv |= KGSL_MEMDESC_FROZEN;
- return entry->memdesc.size;
+ return ret;
+err_put:
+ kgsl_mem_entry_put(entry);
+ return ret;
}
EXPORT_SYMBOL(kgsl_snapshot_get_object);
diff --git a/drivers/gpu/msm/kgsl_sync.c b/drivers/gpu/msm/kgsl_sync.c
index 813305a..aad8ef1 100644
--- a/drivers/gpu/msm/kgsl_sync.c
+++ b/drivers/gpu/msm/kgsl_sync.c
@@ -168,7 +168,6 @@
fail_event:
fail_copy_fd:
/* clean up sync_fence_install */
- sync_fence_put(fence);
put_unused_fd(priv.fence_fd);
fail_fd:
/* clean up sync_fence_create */
diff --git a/drivers/gpu/msm/z180_postmortem.c b/drivers/gpu/msm/z180_postmortem.c
index c1e5f07..55b8faa 100644
--- a/drivers/gpu/msm/z180_postmortem.c
+++ b/drivers/gpu/msm/z180_postmortem.c
@@ -168,6 +168,7 @@
KGSL_LOG_DUMP(device,
"Could not map IB to kernel memory, Ringbuffer Slot: %d\n",
rb_slot_num);
+ kgsl_mem_entry_put(entry);
continue;
}
@@ -190,6 +191,7 @@
linebuf);
}
KGSL_LOG_DUMP(device, "IB Dump Finished\n");
+ kgsl_mem_entry_put(entry);
}
}
}
diff --git a/drivers/hwmon/qpnp-adc-common.c b/drivers/hwmon/qpnp-adc-common.c
index 0fab4d1..8e350f0 100644
--- a/drivers/hwmon/qpnp-adc-common.c
+++ b/drivers/hwmon/qpnp-adc-common.c
@@ -130,6 +130,60 @@
{790, 203}
};
+static const struct qpnp_vadc_map_pt adcmap_qrd_btm_threshold[] = {
+ {-200, 1672},
+ {-180, 1656},
+ {-160, 1639},
+ {-140, 1620},
+ {-120, 1599},
+ {-100, 1577},
+ {-80, 1553},
+ {-60, 1527},
+ {-40, 1550},
+ {-20, 1471},
+ {0, 1440},
+ {20, 1408},
+ {40, 1374},
+ {60, 1339},
+ {80, 1303},
+ {100, 1266},
+ {120, 1228},
+ {140, 1190},
+ {160, 1150},
+ {180, 1111},
+ {200, 1071},
+ {220, 1032},
+ {240, 992},
+ {260, 953},
+ {280, 915},
+ {300, 877},
+ {320, 841},
+ {340, 805},
+ {360, 770},
+ {380, 736},
+ {400, 704},
+ {420, 673},
+ {440, 643},
+ {460, 614},
+ {480, 587},
+ {500, 561},
+ {520, 536},
+ {540, 513},
+ {560, 491},
+ {580, 470},
+ {600, 450},
+ {620, 431},
+ {640, 414},
+ {660, 397},
+ {680, 382},
+ {700, 367},
+ {720, 353},
+ {740, 340},
+ {760, 328},
+ {780, 317},
+ {800, 306},
+};
+
/* Voltage to temperature */
static const struct qpnp_vadc_map_pt adcmap_100k_104ef_104fb[] = {
{1758, -40},
@@ -463,6 +517,24 @@
}
EXPORT_SYMBOL(qpnp_adc_scale_batt_therm);
+int32_t qpnp_adc_scale_qrd_batt_therm(int32_t adc_code,
+ const struct qpnp_adc_properties *adc_properties,
+ const struct qpnp_vadc_chan_properties *chan_properties,
+ struct qpnp_vadc_result *adc_chan_result)
+{
+ int64_t bat_voltage = 0;
+
+ bat_voltage = qpnp_adc_scale_ratiometric_calib(adc_code,
+ adc_properties, chan_properties);
+
+ return qpnp_adc_map_temp_voltage(
+ adcmap_qrd_btm_threshold,
+ ARRAY_SIZE(adcmap_qrd_btm_threshold),
+ bat_voltage,
+ &adc_chan_result->physical);
+}
+EXPORT_SYMBOL(qpnp_adc_scale_qrd_batt_therm);
+
int32_t qpnp_adc_scale_therm_pu1(int32_t adc_code,
const struct qpnp_adc_properties *adc_properties,
const struct qpnp_vadc_chan_properties *chan_properties,
diff --git a/drivers/hwmon/qpnp-adc-voltage.c b/drivers/hwmon/qpnp-adc-voltage.c
index 68cff09..edb1d66 100644
--- a/drivers/hwmon/qpnp-adc-voltage.c
+++ b/drivers/hwmon/qpnp-adc-voltage.c
@@ -112,6 +112,7 @@
[SCALE_XOTHERM] = {qpnp_adc_tdkntcg_therm},
[SCALE_THERM_100K_PULLUP] = {qpnp_adc_scale_therm_pu2},
[SCALE_THERM_150K_PULLUP] = {qpnp_adc_scale_therm_pu1},
+ [SCALE_QRD_BATT_THERM] = {qpnp_adc_scale_qrd_batt_therm},
};
static int32_t qpnp_vadc_read_reg(int16_t reg, u8 *data)
@@ -431,12 +432,32 @@
return 0;
}
-static uint32_t qpnp_vadc_calib_device(void)
+static void qpnp_vadc_625mv_channel_sel(uint32_t *ref_channel_sel)
+{
+ struct qpnp_vadc_drv *vadc = qpnp_vadc;
+ uint32_t dt_index = 0;
+
+ /* Check if the buffered 625mV channel exists */
+ while ((vadc->adc->adc_channels[dt_index].channel_num
+ != SPARE1) && (dt_index < vadc->max_channels_available))
+ dt_index++;
+
+ if (dt_index >= vadc->max_channels_available) {
+ pr_debug("Use default 625mV ref channel\n");
+ *ref_channel_sel = REF_625MV;
+ } else {
+ pr_debug("Use buffered 625mV ref channel\n");
+ *ref_channel_sel = SPARE1;
+ }
+}
+
+static int32_t qpnp_vadc_calib_device(void)
{
struct qpnp_vadc_drv *vadc = qpnp_vadc;
struct qpnp_adc_amux_properties conv;
int rc, calib_read_1, calib_read_2, count = 0;
u8 status1 = 0;
+ uint32_t ref_channel_sel = 0;
conv.amux_channel = REF_125V;
conv.decimation = DECIMATION_TYPE2;
@@ -470,7 +491,8 @@
goto calib_fail;
}
- conv.amux_channel = REF_625MV;
+ qpnp_vadc_625mv_channel_sel(&ref_channel_sel);
+ conv.amux_channel = ref_channel_sel;
conv.decimation = DECIMATION_TYPE2;
conv.mode_sel = ADC_OP_NORMAL_MODE << QPNP_VADC_OP_MODE_SHIFT;
conv.hw_settle_time = ADC_CHANNEL_HW_SETTLE_DELAY_0US;
@@ -647,6 +669,7 @@
{
struct qpnp_vadc_drv *vadc = qpnp_vadc;
int rc = 0, scale_type, amux_prescaling, dt_index = 0;
+ uint32_t ref_channel;
if (!vadc || !vadc->vadc_initialized)
return -EPROBE_DEFER;
@@ -666,6 +689,11 @@
vadc->vadc_init_calib = true;
}
+ if (channel == REF_625MV) {
+ qpnp_vadc_625mv_channel_sel(&ref_channel);
+ channel = ref_channel;
+ }
+
vadc->adc->amux_prop->amux_channel = channel;
while ((vadc->adc->adc_channels[dt_index].channel_num
diff --git a/drivers/input/touchscreen/synaptics_i2c_rmi4.c b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
index 4a021e1..426c7e7 100644
--- a/drivers/input/touchscreen/synaptics_i2c_rmi4.c
+++ b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
@@ -1082,17 +1082,25 @@
bool enable)
{
int retval = 0;
- unsigned char intr_status;
+ unsigned char *intr_status;
if (enable) {
if (rmi4_data->irq_enabled)
return retval;
+ intr_status = kzalloc(rmi4_data->num_of_intr_regs, GFP_KERNEL);
+ if (!intr_status) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to alloc memory\n",
+ __func__);
+ return -ENOMEM;
+ }
/* Clear interrupts first */
retval = synaptics_rmi4_i2c_read(rmi4_data,
rmi4_data->f01_data_base_addr + 1,
- &intr_status,
+ intr_status,
rmi4_data->num_of_intr_regs);
+ kfree(intr_status);
if (retval < 0)
return retval;
diff --git a/drivers/media/dvb/dvb-core/demux.h b/drivers/media/dvb/dvb-core/demux.h
index 89500f9..fcade49 100644
--- a/drivers/media/dvb/dvb-core/demux.h
+++ b/drivers/media/dvb/dvb-core/demux.h
@@ -246,7 +246,10 @@
struct dmx_secure_mode *sec_mode);
int (*oob_command) (struct dmx_ts_feed *feed,
struct dmx_oob_command *cmd);
-
+ int (*ts_insertion_init)(struct dmx_ts_feed *feed);
+ int (*ts_insertion_terminate)(struct dmx_ts_feed *feed);
+ int (*ts_insertion_insert_buffer)(struct dmx_ts_feed *feed,
+ char *data, size_t size);
};
/*--------------------------------------------------------------------------*/
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index 5e7a09e..7347b37 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -34,6 +34,8 @@
#include <linux/uaccess.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
+#include <linux/timer.h>
+#include <linux/jiffies.h>
#include "dmxdev.h"
static int debug;
@@ -416,7 +418,33 @@
return 0;
}
-static ssize_t dvb_dmxdev_buffer_read(struct dvb_ringbuffer *src,
+static inline int dvb_dmxdev_check_data(struct dmxdev_filter *filter,
+ struct dvb_ringbuffer *src)
+{
+ int data_status_change;
+
+ if (filter)
+ if (mutex_lock_interruptible(&filter->mutex))
+ return -ERESTARTSYS;
+
+ if (!src->data ||
+ !dvb_ringbuffer_empty(src) ||
+ src->error ||
+ (filter &&
+ (filter->state != DMXDEV_STATE_GO) &&
+ (filter->state != DMXDEV_STATE_DONE)))
+ data_status_change = 1;
+ else
+ data_status_change = 0;
+
+ if (filter)
+ mutex_unlock(&filter->mutex);
+
+ return data_status_change;
+}
+
+static ssize_t dvb_dmxdev_buffer_read(struct dmxdev_filter *filter,
+ struct dvb_ringbuffer *src,
int non_blocking, char __user *buf,
size_t count, loff_t *ppos)
{
@@ -439,9 +467,26 @@
break;
}
- ret = wait_event_interruptible(src->queue, (!src->data) ||
- !dvb_ringbuffer_empty(src) ||
- (src->error != 0));
+ if (filter) {
+ if ((filter->state == DMXDEV_STATE_DONE) &&
+ dvb_ringbuffer_empty(src))
+ break;
+
+ mutex_unlock(&filter->mutex);
+ }
+
+ ret = wait_event_interruptible(src->queue,
+ dvb_dmxdev_check_data(filter, src));
+
+ if (filter) {
+ if (mutex_lock_interruptible(&filter->mutex))
+ return -ERESTARTSYS;
+
+ if ((filter->state != DMXDEV_STATE_GO) &&
+ (filter->state != DMXDEV_STATE_DONE))
+ return -ENODEV;
+ }
+
if (ret < 0)
break;
@@ -1108,9 +1153,9 @@
if (dmxdev->exit)
return -ENODEV;
- res = dvb_dmxdev_buffer_read(&dmxdev->dvr_buffer,
- file->f_flags & O_NONBLOCK,
- buf, count, ppos);
+ res = dvb_dmxdev_buffer_read(NULL, &dmxdev->dvr_buffer,
+ file->f_flags & O_NONBLOCK,
+ buf, count, ppos);
if (res > 0) {
dvb_dmxdev_notify_data_read(dmxdev->dvr_feed, res);
@@ -1751,6 +1796,213 @@
return 0;
}
+static void dvb_dmxdev_ts_insertion_timer(unsigned long data)
+{
+ struct ts_insertion_buffer *ts_buffer =
+ (struct ts_insertion_buffer *)data;
+
+ if (ts_buffer && !ts_buffer->abort)
+ schedule_work(&ts_buffer->work);
+}
+
+static void dvb_dmxdev_ts_insertion_work(struct work_struct *worker)
+{
+ struct ts_insertion_buffer *ts_buffer =
+ container_of(worker, struct ts_insertion_buffer, work);
+ struct dmxdev_feed *feed;
+ size_t free_bytes;
+ struct dmx_ts_feed *ts;
+
+ mutex_lock(&ts_buffer->dmxdevfilter->mutex);
+
+ if (ts_buffer->abort ||
+ (ts_buffer->dmxdevfilter->state != DMXDEV_STATE_GO)) {
+ mutex_unlock(&ts_buffer->dmxdevfilter->mutex);
+ return;
+ }
+
+ feed = list_first_entry(&ts_buffer->dmxdevfilter->feed.ts,
+ struct dmxdev_feed, next);
+ ts = feed->ts;
+ free_bytes = dvb_ringbuffer_free(&ts_buffer->dmxdevfilter->buffer);
+
+ mutex_unlock(&ts_buffer->dmxdevfilter->mutex);
+
+ if (ts_buffer->size < free_bytes)
+ ts->ts_insertion_insert_buffer(ts,
+ ts_buffer->buffer, ts_buffer->size);
+
+ if (ts_buffer->repetition_time)
+ mod_timer(&ts_buffer->timer, jiffies +
+ msecs_to_jiffies(ts_buffer->repetition_time));
+}
+
+static void dvb_dmxdev_queue_ts_insertion(
+ struct ts_insertion_buffer *ts_buffer)
+{
+ size_t tsp_size;
+
+ if (ts_buffer->dmxdevfilter->dmx_tsp_format == DMX_TSP_FORMAT_188)
+ tsp_size = 188;
+ else
+ tsp_size = 192;
+
+ if (ts_buffer->size % tsp_size) {
+ printk(KERN_ERR "%s: Wrong buffer alignment, size=%d, tsp_size=%d\n",
+ __func__, ts_buffer->size, tsp_size);
+ return;
+ }
+
+ ts_buffer->abort = 0;
+ schedule_work(&ts_buffer->work);
+}
+
+static void dvb_dmxdev_cancel_ts_insertion(
+ struct ts_insertion_buffer *ts_buffer)
+{
+ /*
+ * This function assumes it is called while mutex
+ * of demux filter is taken. Since work in workqueue
+ * captures the filter's mutex to protect against the DB,
+ * mutex needs to be released before waiting for the work
+ * to get finished otherwise work in workqueue will
+ * never be finished.
+ */
+ if (!mutex_is_locked(&ts_buffer->dmxdevfilter->mutex)) {
+ printk(KERN_ERR "%s: mutex is not locked!\n", __func__);
+ return;
+ }
+
+ /*
+ * Work should be stopped first as it might re-trigger the timer
+ * until it is stopped. Timer would not re-schedule the work
+ * due to the abort flag.
+ */
+ ts_buffer->abort = 1;
+
+ mutex_unlock(&ts_buffer->dmxdevfilter->mutex);
+ cancel_work_sync(&ts_buffer->work);
+ del_timer_sync(&ts_buffer->timer);
+ mutex_lock(&ts_buffer->dmxdevfilter->mutex);
+}
+
+static int dvb_dmxdev_set_ts_insertion(struct dmxdev_filter *dmxdevfilter,
+ struct dmx_set_ts_insertion *params)
+{
+ int ret = 0;
+ int first_buffer;
+ struct dmxdev_feed *feed;
+ struct ts_insertion_buffer *ts_buffer;
+
+ if (!params ||
+ !params->size ||
+ !(dmxdevfilter->dev->capabilities & DMXDEV_CAP_TS_INSERTION) ||
+ (dmxdevfilter->state < DMXDEV_STATE_SET) ||
+ (dmxdevfilter->type != DMXDEV_TYPE_PES) ||
+ ((dmxdevfilter->params.pes.output != DMX_OUT_TS_TAP) &&
+ (dmxdevfilter->params.pes.output != DMX_OUT_TSDEMUX_TAP)))
+ return -EINVAL;
+
+ ts_buffer = vmalloc(sizeof(struct ts_insertion_buffer));
+ if (!ts_buffer)
+ return -ENOMEM;
+
+ ts_buffer->buffer = vmalloc(params->size);
+ if (!ts_buffer->buffer) {
+ vfree(ts_buffer);
+ return -ENOMEM;
+ }
+
+ if (copy_from_user(ts_buffer->buffer,
+ params->ts_packets, params->size)) {
+ vfree(ts_buffer->buffer);
+ vfree(ts_buffer);
+ return -EFAULT;
+ }
+
+ if (params->repetition_time &&
+ params->repetition_time < DMX_MIN_INSERTION_REPETITION_TIME)
+ params->repetition_time = DMX_MIN_INSERTION_REPETITION_TIME;
+
+ ts_buffer->size = params->size;
+ ts_buffer->identifier = params->identifier;
+ ts_buffer->repetition_time = params->repetition_time;
+ ts_buffer->dmxdevfilter = dmxdevfilter;
+ init_timer(&ts_buffer->timer);
+ ts_buffer->timer.function = dvb_dmxdev_ts_insertion_timer;
+ ts_buffer->timer.data = (unsigned long)ts_buffer;
+ ts_buffer->timer.expires = 0xffffffffL;
+ INIT_WORK(&ts_buffer->work, dvb_dmxdev_ts_insertion_work);
+
+ first_buffer = list_empty(&dmxdevfilter->insertion_buffers);
+ list_add_tail(&ts_buffer->next, &dmxdevfilter->insertion_buffers);
+
+ if (dmxdevfilter->state != DMXDEV_STATE_GO)
+ return 0;
+
+ feed = list_first_entry(&dmxdevfilter->feed.ts,
+ struct dmxdev_feed, next);
+
+ if (first_buffer && feed->ts->ts_insertion_init)
+ ret = feed->ts->ts_insertion_init(feed->ts);
+
+ if (!ret) {
+ dvb_dmxdev_queue_ts_insertion(ts_buffer);
+ } else {
+ list_del(&ts_buffer->next);
+ vfree(ts_buffer->buffer);
+ vfree(ts_buffer);
+ }
+
+ return ret;
+}
+
+static int dvb_dmxdev_abort_ts_insertion(struct dmxdev_filter *dmxdevfilter,
+ struct dmx_abort_ts_insertion *params)
+{
+ int ret = 0;
+ int found_buffer;
+ struct dmxdev_feed *feed;
+ struct ts_insertion_buffer *ts_buffer, *tmp;
+
+ if (!params ||
+ !(dmxdevfilter->dev->capabilities & DMXDEV_CAP_TS_INSERTION) ||
+ (dmxdevfilter->state < DMXDEV_STATE_SET) ||
+ (dmxdevfilter->type != DMXDEV_TYPE_PES) ||
+ ((dmxdevfilter->params.pes.output != DMX_OUT_TS_TAP) &&
+ (dmxdevfilter->params.pes.output != DMX_OUT_TSDEMUX_TAP)))
+ return -EINVAL;
+
+ found_buffer = 0;
+ list_for_each_entry_safe(ts_buffer, tmp,
+ &dmxdevfilter->insertion_buffers, next) {
+ if (ts_buffer->identifier == params->identifier) {
+ list_del(&ts_buffer->next);
+ found_buffer = 1;
+ break;
+ }
+ }
+
+ if (!found_buffer)
+ return -EINVAL;
+
+ if (dmxdevfilter->state == DMXDEV_STATE_GO) {
+ dvb_dmxdev_cancel_ts_insertion(ts_buffer);
+ if (list_empty(&dmxdevfilter->insertion_buffers)) {
+ feed = list_first_entry(&dmxdevfilter->feed.ts,
+ struct dmxdev_feed, next);
+ if (feed->ts->ts_insertion_terminate)
+ ret = feed->ts->ts_insertion_terminate(
+ feed->ts);
+ }
+ }
+
+ vfree(ts_buffer->buffer);
+ vfree(ts_buffer);
+
+ return ret;
+}
+
static int dvb_dmxdev_ts_fullness_callback(struct dmx_ts_feed *filter,
int required_space)
{
@@ -2006,6 +2258,9 @@
dvb_ringbuffer_flush(&dmxdevfilter->buffer);
dvb_dmxdev_notify_data_read(dmxdevfilter, flush_len);
dmxdevfilter->buffer.error = 0;
+ } else if (event->type == DMX_EVENT_SECTION_TIMEOUT) {
+ /* clear buffer error now that user was notified */
+ dmxdevfilter->buffer.error = 0;
}
/*
@@ -2036,10 +2291,13 @@
static void dvb_dmxdev_filter_timeout(unsigned long data)
{
struct dmxdev_filter *dmxdevfilter = (struct dmxdev_filter *)data;
+ struct dmx_filter_event event;
dmxdevfilter->buffer.error = -ETIMEDOUT;
spin_lock_irq(&dmxdevfilter->dev->lock);
dmxdevfilter->state = DMXDEV_STATE_TIMEDOUT;
+ event.type = DMX_EVENT_SECTION_TIMEOUT;
+ dvb_dmxdev_add_event(&dmxdevfilter->events, &event);
spin_unlock_irq(&dmxdevfilter->dev->lock);
wake_up_all(&dmxdevfilter->buffer.queue);
}
@@ -2612,6 +2870,7 @@
{
struct dmxdev_feed *feed;
struct dmx_demux *demux;
+ struct ts_insertion_buffer *ts_buffer;
if (dmxdevfilter->state < DMXDEV_STATE_GO)
return 0;
@@ -2631,6 +2890,18 @@
case DMXDEV_TYPE_PES:
dvb_dmxdev_feed_stop(dmxdevfilter);
demux = dmxdevfilter->dev->demux;
+
+ if (!list_empty(&dmxdevfilter->insertion_buffers)) {
+ feed = list_first_entry(&dmxdevfilter->feed.ts,
+ struct dmxdev_feed, next);
+
+ list_for_each_entry(ts_buffer,
+ &dmxdevfilter->insertion_buffers, next)
+ dvb_dmxdev_cancel_ts_insertion(ts_buffer);
+ if (feed->ts->ts_insertion_terminate)
+ feed->ts->ts_insertion_terminate(feed->ts);
+ }
+
list_for_each_entry(feed, &dmxdevfilter->feed.ts, next) {
demux->release_ts_feed(demux, feed->ts);
feed->ts = NULL;
@@ -2971,6 +3242,29 @@
}
dvb_dmxdev_filter_state_set(filter, DMXDEV_STATE_GO);
+
+ if ((filter->type == DMXDEV_TYPE_PES) &&
+ !list_empty(&filter->insertion_buffers)) {
+ struct ts_insertion_buffer *ts_buffer;
+
+ feed = list_first_entry(&filter->feed.ts,
+ struct dmxdev_feed, next);
+
+ ret = 0;
+ if (feed->ts->ts_insertion_init)
+ ret = feed->ts->ts_insertion_init(feed->ts);
+ if (!ret) {
+ list_for_each_entry(ts_buffer,
+ &filter->insertion_buffers, next)
+ dvb_dmxdev_queue_ts_insertion(
+ ts_buffer);
+ } else {
+ printk(KERN_ERR
+ "%s: ts_insertion_init failed, err %d\n",
+ __func__, ret);
+ }
+ }
+
return 0;
}
@@ -3017,6 +3311,8 @@
dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED);
init_timer(&dmxdevfilter->timer);
+ INIT_LIST_HEAD(&dmxdevfilter->insertion_buffers);
+
dmxdevfilter->dmx_tsp_format = DMX_TSP_FORMAT_188;
dvbdev->users++;
@@ -3027,6 +3323,8 @@
static int dvb_dmxdev_filter_free(struct dmxdev *dmxdev,
struct dmxdev_filter *dmxdevfilter)
{
+ struct ts_insertion_buffer *ts_buffer, *tmp;
+
mutex_lock(&dmxdev->mutex);
mutex_lock(&dmxdevfilter->mutex);
@@ -3034,6 +3332,13 @@
dvb_dmxdev_filter_reset(dmxdevfilter);
+ list_for_each_entry_safe(ts_buffer, tmp,
+ &dmxdevfilter->insertion_buffers, next) {
+ list_del(&ts_buffer->next);
+ vfree(ts_buffer->buffer);
+ vfree(ts_buffer);
+ }
+
if (dmxdevfilter->buffer.data) {
void *mem = dmxdevfilter->buffer.data;
@@ -3098,12 +3403,20 @@
static int dvb_dmxdev_remove_pid(struct dmxdev *dmxdev,
struct dmxdev_filter *filter, u16 pid)
{
+ int feed_count;
struct dmxdev_feed *feed, *tmp;
if ((filter->type != DMXDEV_TYPE_PES) ||
(filter->state < DMXDEV_STATE_SET))
return -EINVAL;
+ feed_count = 0;
+ list_for_each_entry(tmp, &filter->feed.ts, next)
+ feed_count++;
+
+ if (feed_count <= 1)
+ return -EINVAL;
+
list_for_each_entry_safe(feed, tmp, &filter->feed.ts, next) {
if (feed->pid == pid) {
if (feed->ts != NULL) {
@@ -3283,7 +3596,7 @@
hcount = 3 + dfil->todo;
if (hcount > count)
hcount = count;
- result = dvb_dmxdev_buffer_read(&dfil->buffer,
+ result = dvb_dmxdev_buffer_read(dfil, &dfil->buffer,
file->f_flags & O_NONBLOCK,
buf, hcount, ppos);
if (result < 0) {
@@ -3304,7 +3617,7 @@
}
if (count > dfil->todo)
count = dfil->todo;
- result = dvb_dmxdev_buffer_read(&dfil->buffer,
+ result = dvb_dmxdev_buffer_read(dfil, &dfil->buffer,
file->f_flags & O_NONBLOCK,
buf, count, ppos);
if (result < 0)
@@ -3333,9 +3646,10 @@
if (dmxdevfilter->type == DMXDEV_TYPE_SEC)
ret = dvb_dmxdev_read_sec(dmxdevfilter, file, buf, count, ppos);
else
- ret = dvb_dmxdev_buffer_read(&dmxdevfilter->buffer,
- file->f_flags & O_NONBLOCK,
- buf, count, ppos);
+ ret = dvb_dmxdev_buffer_read(dmxdevfilter,
+ &dmxdevfilter->buffer,
+ file->f_flags & O_NONBLOCK,
+ buf, count, ppos);
if (ret > 0) {
dvb_dmxdev_notify_data_read(dmxdevfilter, ret);
@@ -3625,6 +3939,24 @@
mutex_unlock(&dmxdevfilter->mutex);
break;
+ case DMX_SET_TS_INSERTION:
+ if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+ mutex_unlock(&dmxdev->mutex);
+ return -ERESTARTSYS;
+ }
+ ret = dvb_dmxdev_set_ts_insertion(dmxdevfilter, parg);
+ mutex_unlock(&dmxdevfilter->mutex);
+ break;
+
+ case DMX_ABORT_TS_INSERTION:
+ if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+ mutex_unlock(&dmxdev->mutex);
+ return -ERESTARTSYS;
+ }
+ ret = dvb_dmxdev_abort_ts_insertion(dmxdevfilter, parg);
+ mutex_unlock(&dmxdevfilter->mutex);
+ break;
+
default:
ret = -EINVAL;
break;
diff --git a/drivers/media/dvb/dvb-core/dmxdev.h b/drivers/media/dvb/dvb-core/dmxdev.h
index 2ed99ae..d8cd982 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.h
+++ b/drivers/media/dvb/dvb-core/dmxdev.h
@@ -114,6 +114,35 @@
struct dmx_filter_event queue[DMX_EVENT_QUEUE_SIZE];
};
+#define DMX_MIN_INSERTION_REPETITION_TIME 25 /* in msec */
+struct ts_insertion_buffer {
+ /* work scheduled for insertion of this buffer */
+ struct work_struct work;
+
+ struct list_head next;
+
+ /* buffer holding TS packets for insertion */
+ char *buffer;
+
+ /* buffer size */
+ size_t size;
+
+ /* buffer ID from user */
+ u32 identifier;
+
+ /* repetition time for the buffer insertion */
+ u32 repetition_time;
+
+ /* timer used for insertion of the buffer */
+ struct timer_list timer;
+
+ /* the recording filter to which this buffer belongs */
+ struct dmxdev_filter *dmxdevfilter;
+
+ /* indication whether insertion should be aborted */
+ int abort;
+};
+
struct dmxdev_filter {
union {
struct dmx_section_filter *sec;
@@ -145,6 +174,9 @@
enum dmx_tsp_format_t dmx_tsp_format;
u32 rec_chunk_size;
+ /* list of buffers used for insertion (struct ts_insertion_buffer) */
+ struct list_head insertion_buffers;
+
/* End-of-stream indication has been received */
int eos_state;
@@ -170,6 +202,8 @@
#define DMXDEV_CAP_PULL_MODE 0x02
#define DMXDEV_CAP_INDEXING 0x04
#define DMXDEV_CAP_EXTERNAL_BUFFS_ONLY 0x08
+#define DMXDEV_CAP_TS_INSERTION 0x10
+
enum dmx_playback_mode_t playback_mode;
dmx_source_t source;
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
index 3f3d222..939d591 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -2331,6 +2331,25 @@
return ret;
}
+static int dvbdmx_ts_insertion_insert_buffer(struct dmx_ts_feed *ts_feed,
+ char *data, size_t size)
+{
+ struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed;
+ struct dvb_demux *demux = feed->demux;
+
+ spin_lock(&demux->lock);
+ if (!ts_feed->is_filtering) {
+ spin_unlock(&demux->lock);
+ return 0;
+ }
+
+ feed->cb.ts(data, size, NULL, 0, ts_feed, DMX_OK);
+
+ spin_unlock(&demux->lock);
+
+ return 0;
+}
+
static int dmx_ts_set_tsp_out_format(
struct dmx_ts_feed *ts_feed,
enum dmx_tsp_format_t tsp_format)
@@ -2401,6 +2420,10 @@
(*ts_feed)->notify_data_read = NULL;
(*ts_feed)->set_secure_mode = dmx_ts_set_secure_mode;
(*ts_feed)->oob_command = dvbdmx_ts_feed_oob_cmd;
+ (*ts_feed)->ts_insertion_init = NULL;
+ (*ts_feed)->ts_insertion_terminate = NULL;
+ (*ts_feed)->ts_insertion_insert_buffer =
+ dvbdmx_ts_insertion_insert_buffer;
if (!(feed->filter = dvb_dmx_filter_alloc(demux))) {
feed->state = DMX_STATE_FREE;
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
index 8ea1a00..59858b5 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
@@ -256,6 +256,13 @@
buf_info->state ==
MSM_ISP_BUFFER_STATE_INITIALIZED)
continue;
+
+ if (!BUF_SRC(bufq->stream_id)) {
+ if (buf_info->state == MSM_ISP_BUFFER_STATE_DEQUEUED ||
+ buf_info->state == MSM_ISP_BUFFER_STATE_DIVERTED)
+ buf_mgr->vb2_ops->put_buf(buf_info->vb2_buf,
+ bufq->session_id, bufq->stream_id);
+ }
msm_isp_unprepare_v4l2_buf(buf_mgr, buf_info);
}
return 0;
@@ -378,7 +385,6 @@
switch (buf_info->state) {
case MSM_ISP_BUFFER_STATE_PREPARED:
case MSM_ISP_BUFFER_STATE_DEQUEUED:
- case MSM_ISP_BUFFER_STATE_DISPATCHED:
case MSM_ISP_BUFFER_STATE_DIVERTED:
if (BUF_SRC(bufq->stream_id))
list_add_tail(&buf_info->list, &bufq->head);
@@ -388,6 +394,13 @@
buf_info->state = MSM_ISP_BUFFER_STATE_QUEUED;
rc = 0;
break;
+ case MSM_ISP_BUFFER_STATE_DISPATCHED:
+ buf_info->state = MSM_ISP_BUFFER_STATE_QUEUED;
+ rc = 0;
+ break;
+ case MSM_ISP_BUFFER_STATE_QUEUED:
+ rc = 0;
+ break;
default:
pr_err("%s: incorrect state = %d",
__func__, buf_info->state);
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 a251f0a..679c5cb 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
@@ -142,14 +142,13 @@
return;
if (irq_status0 & BIT(0)) {
- ISP_DBG("%s: PIX0 frame id: %lu\n", __func__,
- vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id);
- msm_isp_sof_notify(vfe_dev, VFE_PIX_0, ts);
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);
+ 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 5a17635..731056b 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
@@ -299,6 +299,8 @@
&& vfe_dev->axi_data.src_info[VFE_PIX_0].
pix_stream_count == 0) {
msm_isp_sof_notify(vfe_dev, VFE_PIX_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 728e172..13160ee 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
@@ -399,7 +399,10 @@
uint32_t framedrop_period = msm_isp_get_framedrop_period(
stream_cfg_cmd->frame_skip_pattern);
- stream_info->framedrop_pattern = 0x1;
+ if (stream_cfg_cmd->frame_skip_pattern == SKIP_ALL)
+ stream_info->framedrop_pattern = 0x0;
+ else
+ stream_info->framedrop_pattern = 0x1;
stream_info->framedrop_period = framedrop_period - 1;
if (stream_cfg_cmd->init_frame_drop < framedrop_period) {
@@ -706,35 +709,60 @@
}
}
-enum msm_isp_camif_update_state
- msm_isp_update_camif_output_count(
- struct vfe_device *vfe_dev,
+static enum msm_isp_camif_update_state
+ msm_isp_get_camif_update_state(struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd)
{
int i;
struct msm_vfe_axi_stream *stream_info;
struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
- uint8_t cur_pix_count = axi_data->src_info[VFE_PIX_0].
- pix_stream_count;
- uint8_t cur_raw_count = axi_data->src_info[VFE_PIX_0].
- raw_stream_count;
- uint8_t pix_stream_cnt = 0;
+ uint8_t pix_stream_cnt = 0, cur_pix_stream_cnt;
+ cur_pix_stream_cnt =
+ axi_data->src_info[VFE_PIX_0].pix_stream_count +
+ axi_data->src_info[VFE_PIX_0].raw_stream_count;
for (i = 0; i < stream_cfg_cmd->num_streams; i++) {
stream_info =
&axi_data->stream_info[
HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])];
if (stream_info->stream_src < RDI_INTF_0)
pix_stream_cnt++;
+ }
+
+ if (pix_stream_cnt) {
+ if (cur_pix_stream_cnt == 0 && pix_stream_cnt &&
+ stream_cfg_cmd->cmd == START_STREAM)
+ return ENABLE_CAMIF;
+ else if (cur_pix_stream_cnt &&
+ (cur_pix_stream_cnt - pix_stream_cnt) == 0 &&
+ stream_cfg_cmd->cmd == STOP_STREAM)
+ return DISABLE_CAMIF;
+ }
+ return NO_UPDATE;
+}
+
+static void msm_isp_update_camif_output_count(
+ struct vfe_device *vfe_dev,
+ struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd)
+{
+ int i;
+ struct msm_vfe_axi_stream *stream_info;
+ struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
+ for (i = 0; i < stream_cfg_cmd->num_streams; i++) {
+ stream_info =
+ &axi_data->stream_info[
+ HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])];
+ if (stream_info->stream_src >= RDI_INTF_0)
+ return;
if (stream_info->stream_src == PIX_ENCODER ||
- stream_info->stream_src == PIX_VIEWFINDER) {
+ stream_info->stream_src == PIX_VIEWFINDER ||
+ stream_info->stream_src == IDEAL_RAW) {
if (stream_cfg_cmd->cmd == START_STREAM)
vfe_dev->axi_data.src_info[VFE_PIX_0].
pix_stream_count++;
else
vfe_dev->axi_data.src_info[VFE_PIX_0].
pix_stream_count--;
- } else if (stream_info->stream_src == CAMIF_RAW ||
- stream_info->stream_src == IDEAL_RAW) {
+ } else if (stream_info->stream_src == CAMIF_RAW) {
if (stream_cfg_cmd->cmd == START_STREAM)
vfe_dev->axi_data.src_info[VFE_PIX_0].
raw_stream_count++;
@@ -743,25 +771,6 @@
raw_stream_count--;
}
}
- if (pix_stream_cnt) {
- if ((cur_pix_count + cur_raw_count == 0) &&
- (axi_data->src_info[VFE_PIX_0].
- pix_stream_count +
- axi_data->src_info[VFE_PIX_0].
- raw_stream_count != 0)) {
- return ENABLE_CAMIF;
- }
-
- if ((cur_pix_count + cur_raw_count != 0) &&
- (axi_data->src_info[VFE_PIX_0].
- pix_stream_count +
- axi_data->src_info[VFE_PIX_0].
- raw_stream_count == 0)) {
- return DISABLE_CAMIF;
- }
- }
-
- return NO_UPDATE;
}
void msm_camera_io_dump_2(void __iomem *addr, int size)
@@ -886,6 +895,20 @@
return rc;
}
+static void msm_isp_deinit_stream_ping_pong_reg(
+ struct vfe_device *vfe_dev,
+ struct msm_vfe_axi_stream *stream_info)
+{
+ int i;
+ for (i = 0; i < 2; i++) {
+ struct msm_isp_buffer *buf;
+ buf = stream_info->buf[i];
+ if (buf)
+ vfe_dev->buf_mgr->ops->put_buf(vfe_dev->buf_mgr,
+ buf->bufq_handle, buf->buf_idx);
+ }
+}
+
static void msm_isp_get_stream_wm_mask(
struct msm_vfe_axi_stream *stream_info,
uint32_t *wm_reload_mask)
@@ -937,6 +960,7 @@
vfe_dev->hw_info->vfe_ops.axi_ops.reload_wm(vfe_dev, wm_reload_mask);
vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev);
+ msm_isp_update_camif_output_count(vfe_dev, stream_cfg_cmd);
if (camif_update == ENABLE_CAMIF)
vfe_dev->hw_info->vfe_ops.core_ops.
update_camif_state(vfe_dev, camif_update);
@@ -969,6 +993,13 @@
if (camif_update == DISABLE_CAMIF)
vfe_dev->hw_info->vfe_ops.core_ops.
update_camif_state(vfe_dev, DISABLE_CAMIF);
+ msm_isp_update_camif_output_count(vfe_dev, stream_cfg_cmd);
+
+ for (i = 0; i < stream_cfg_cmd->num_streams; i++) {
+ stream_info = &axi_data->stream_info[
+ HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])];
+ msm_isp_deinit_stream_ping_pong_reg(vfe_dev, stream_info);
+ }
return rc;
}
@@ -990,8 +1021,7 @@
/*Configure UB*/
vfe_dev->hw_info->vfe_ops.axi_ops.cfg_ub(vfe_dev);
}
- camif_update =
- msm_isp_update_camif_output_count(vfe_dev, stream_cfg_cmd);
+ camif_update = msm_isp_get_camif_update_state(vfe_dev, stream_cfg_cmd);
if (stream_cfg_cmd->cmd == START_STREAM)
rc = msm_isp_start_axi_stream(
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
index e08dea2..ce71235 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
@@ -206,7 +206,11 @@
framedrop_period = msm_isp_get_framedrop_period(
stream_req_cmd->framedrop_pattern);
- stream_info->framedrop_pattern = 0x1;
+
+ if (stream_req_cmd->framedrop_pattern == SKIP_ALL)
+ stream_info->framedrop_pattern = 0x0;
+ else
+ stream_info->framedrop_pattern = 0x1;
stream_info->framedrop_period = framedrop_period - 1;
if (!stream_info->composite_flag)
@@ -277,6 +281,20 @@
return rc;
}
+static void msm_isp_deinit_stats_ping_pong_reg(
+ struct vfe_device *vfe_dev,
+ struct msm_vfe_stats_stream *stream_info)
+{
+ int i;
+ struct msm_isp_buffer *buf;
+ for (i = 0; i < 2; i++) {
+ buf = stream_info->buf[i];
+ if (buf)
+ vfe_dev->buf_mgr->ops->put_buf(vfe_dev->buf_mgr,
+ buf->bufq_handle, buf->buf_idx);
+ }
+}
+
void msm_isp_stats_stream_update(struct vfe_device *vfe_dev)
{
int i;
@@ -415,6 +433,12 @@
vfe_dev->hw_info->vfe_ops.stats_ops.cfg_comp_mask(
vfe_dev, comp_stats_mask, 0);
}
+
+ for (i = 0; i < stream_cfg_cmd->num_streams; i++) {
+ idx = STATS_IDX(stream_cfg_cmd->stream_handle[i]);
+ stream_info = &stats_data->stream_info[idx];
+ msm_isp_deinit_stats_ping_pong_reg(vfe_dev, stream_info);
+ }
return rc;
}
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 c981901..613ad86 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
@@ -174,6 +174,8 @@
case EVERY_32FRAME:
return 32;
break;
+ case SKIP_ALL:
+ return 1;
default:
return 1;
}
diff --git a/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c b/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c
index 35210a0..b0ff832 100644
--- a/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c
+++ b/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c
@@ -35,7 +35,7 @@
new_entry->vb2_buf = buf_mngr_dev->vb2_ops.get_buf(buf_info->session_id,
buf_info->stream_id);
if (!new_entry->vb2_buf) {
- pr_err("%s:Get buf is null\n", __func__);
+ pr_debug("%s:Get buf is null\n", __func__);
kfree(new_entry);
return -EINVAL;
}
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
index 8cdaa4b..5a174f5 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
@@ -860,7 +860,7 @@
rc = v4l2_subdev_call(cpp_dev->buf_mgr_subdev, core, ioctl,
buff_mgr_ops, buff_mgr_info);
if (rc < 0)
- pr_err("%s: line %d rc = %d\n", __func__, __LINE__, rc);
+ pr_debug("%s: line %d rc = %d\n", __func__, __LINE__, rc);
return rc;
}
@@ -1010,7 +1010,7 @@
&buff_mgr_info);
if (rc < 0) {
rc = -EAGAIN;
- pr_err("error getting buffer rc:%d\n", rc);
+ pr_debug("error getting buffer rc:%d\n", rc);
goto ERROR2;
}
diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.h b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.h
index 76aa695..ac697fb 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.h
+++ b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.h
@@ -40,7 +40,7 @@
struct msm_flash_fn_t *func_tbl;
const char *led_trigger_name[MAX_LED_TRIGGERS];
struct led_trigger *led_trigger[MAX_LED_TRIGGERS];
- uint32_t max_current[MAX_LED_TRIGGERS];
+ uint32_t op_current[MAX_LED_TRIGGERS];
void *data;
};
diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_trigger.c b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_trigger.c
index 1a75a5a..c6f1f72 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_trigger.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_trigger.c
@@ -59,11 +59,11 @@
case MSM_CAMERA_LED_LOW:
led_trigger_event(fctrl->led_trigger[0],
- fctrl->max_current[0] / 2);
+ fctrl->op_current[0] / 2);
break;
case MSM_CAMERA_LED_HIGH:
- led_trigger_event(fctrl->led_trigger[0], fctrl->max_current[0]);
+ led_trigger_event(fctrl->led_trigger[0], fctrl->op_current[0]);
break;
case MSM_CAMERA_LED_INIT:
@@ -144,7 +144,7 @@
CDBG("default trigger %s\n", fctrl.led_trigger_name[i]);
rc = of_property_read_u32(flash_src_node,
- "qcom,max-current", &fctrl.max_current[i]);
+ "qcom,current", &fctrl.op_current[i]);
if (rc < 0) {
pr_err("failed rc %d\n", rc);
of_node_put(flash_src_node);
@@ -153,7 +153,7 @@
of_node_put(flash_src_node);
- CDBG("max_current[%d] %d\n", i, fctrl.max_current[i]);
+ CDBG("max_current[%d] %d\n", i, fctrl.op_current[i]);
led_trigger_register_simple(fctrl.led_trigger_name[i],
&fctrl.led_trigger[i]);
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tsif.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tsif.c
index 8855e85..29369de 100644
--- a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tsif.c
+++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tsif.c
@@ -703,7 +703,8 @@
mpq_demux->dmxdev.capabilities =
DMXDEV_CAP_DUPLEX |
DMXDEV_CAP_PULL_MODE |
- DMXDEV_CAP_INDEXING;
+ DMXDEV_CAP_INDEXING |
+ DMXDEV_CAP_TS_INSERTION;
mpq_demux->dmxdev.demux->set_source = mpq_dmx_set_source;
mpq_demux->dmxdev.demux->get_stc = mpq_tsif_dmx_get_stc;
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v1.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v1.c
index 43a65e9..5e14d0c 100644
--- a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v1.c
+++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v1.c
@@ -1759,7 +1759,8 @@
mpq_demux->dmxdev.capabilities =
DMXDEV_CAP_DUPLEX |
DMXDEV_CAP_PULL_MODE |
- DMXDEV_CAP_INDEXING;
+ DMXDEV_CAP_INDEXING |
+ DMXDEV_CAP_TS_INSERTION;
mpq_demux->dmxdev.demux->set_source = mpq_dmx_set_source;
mpq_demux->dmxdev.demux->get_stc = mpq_tspp_dmx_get_stc;
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v2.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v2.c
index c306488..60e3cb4 100644
--- a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v2.c
+++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v2.c
@@ -143,7 +143,8 @@
mpq_demux->dmxdev.capabilities =
DMXDEV_CAP_DUPLEX |
DMXDEV_CAP_PULL_MODE |
- DMXDEV_CAP_INDEXING;
+ DMXDEV_CAP_INDEXING |
+ DMXDEV_CAP_TS_INSERTION;
mpq_demux->dmxdev.demux->set_source = mpq_dmx_set_source;
mpq_demux->dmxdev.demux->get_caps = mpq_tspp_dmx_get_caps;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index feb239e..eb5a03c 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -729,6 +729,8 @@
vb->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME;
if (fill_buf_done->flags1 & HAL_BUFFERFLAG_EOSEQ)
vb->v4l2_buf.flags |= V4L2_QCOM_BUF_FLAG_EOSEQ;
+ if (fill_buf_done->flags1 & HAL_BUFFERFLAG_DECODEONLY)
+ vb->v4l2_buf.flags |= V4L2_QCOM_BUF_FLAG_DECODEONLY;
switch (fill_buf_done->picture_type) {
case HAL_PICTURE_IDR:
case HAL_PICTURE_I:
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.c b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
index 3208df9..ae1e9b7 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_debug.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
@@ -198,6 +198,7 @@
write_str(&dbg_buf, "core: 0x%p\n", inst->core);
write_str(&dbg_buf, "height: %d\n", inst->prop.height);
write_str(&dbg_buf, "width: %d\n", inst->prop.width);
+ write_str(&dbg_buf, "fps: %d\n", inst->prop.fps);
write_str(&dbg_buf, "state: %d\n", inst->state);
write_str(&dbg_buf, "-----------Formats-------------\n");
for (i = 0; i < MAX_PORT_NUM; i++) {
diff --git a/drivers/media/platform/msm/wfd/enc-mfc-subdev.c b/drivers/media/platform/msm/wfd/enc-mfc-subdev.c
index ceb0149..26e24da 100644
--- a/drivers/media/platform/msm/wfd/enc-mfc-subdev.c
+++ b/drivers/media/platform/msm/wfd/enc-mfc-subdev.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -20,6 +20,7 @@
#include <media/msm/vcd_property.h>
#include <linux/time.h>
#include <linux/ktime.h>
+#include <linux/slab.h>
#define VID_ENC_MAX_ENCODER_CLIENTS 1
#define MAX_NUM_CTRLS 20
diff --git a/drivers/media/platform/msm/wfd/enc-venus-subdev.c b/drivers/media/platform/msm/wfd/enc-venus-subdev.c
index 4f7fb44..722aa8f 100644
--- a/drivers/media/platform/msm/wfd/enc-venus-subdev.c
+++ b/drivers/media/platform/msm/wfd/enc-venus-subdev.c
@@ -18,6 +18,7 @@
#include <linux/list.h>
#include <linux/mutex.h>
#include <linux/wait.h>
+#include <linux/slab.h>
#include <mach/iommu_domains.h>
#include <media/msm_vidc.h>
#include <media/v4l2-subdev.h>
diff --git a/drivers/media/platform/msm/wfd/mdp-4-subdev.c b/drivers/media/platform/msm/wfd/mdp-4-subdev.c
index 465ec21..2d79622 100644
--- a/drivers/media/platform/msm/wfd/mdp-4-subdev.c
+++ b/drivers/media/platform/msm/wfd/mdp-4-subdev.c
@@ -11,6 +11,7 @@
*
*/
#include <linux/msm_mdp.h>
+#include <linux/slab.h>
#include <mach/iommu_domains.h>
#include <media/videobuf2-core.h>
#include "enc-subdev.h"
diff --git a/drivers/media/platform/msm/wfd/mdp-5-subdev.c b/drivers/media/platform/msm/wfd/mdp-5-subdev.c
index 3c546d0..6399117 100644
--- a/drivers/media/platform/msm/wfd/mdp-5-subdev.c
+++ b/drivers/media/platform/msm/wfd/mdp-5-subdev.c
@@ -11,6 +11,7 @@
*
*/
#include <linux/msm_mdp.h>
+#include <linux/slab.h>
#include <mach/iommu_domains.h>
#include <media/videobuf2-core.h>
#include "enc-subdev.h"
diff --git a/drivers/media/platform/msm/wfd/mdp-dummy-subdev.c b/drivers/media/platform/msm/wfd/mdp-dummy-subdev.c
index 2242c76..10ba3c3 100644
--- a/drivers/media/platform/msm/wfd/mdp-dummy-subdev.c
+++ b/drivers/media/platform/msm/wfd/mdp-dummy-subdev.c
@@ -12,6 +12,7 @@
*/
#include <linux/list.h>
#include <linux/msm_mdp.h>
+#include <linux/slab.h>
#include <media/videobuf2-core.h>
#include "enc-subdev.h"
diff --git a/drivers/media/platform/msm/wfd/vsg-subdev.c b/drivers/media/platform/msm/wfd/vsg-subdev.c
index 90b1957..e0a46cc 100644
--- a/drivers/media/platform/msm/wfd/vsg-subdev.c
+++ b/drivers/media/platform/msm/wfd/vsg-subdev.c
@@ -13,6 +13,7 @@
#include <linux/hrtimer.h>
#include <linux/time.h>
#include <linux/list.h>
+#include <linux/slab.h>
#include <media/videobuf2-core.h>
#include "enc-subdev.h"
#include "vsg-subdev.h"
diff --git a/drivers/media/platform/msm/wfd/wfd-ioctl.c b/drivers/media/platform/msm/wfd/wfd-ioctl.c
index b1b1980..d44792c 100644
--- a/drivers/media/platform/msm/wfd/wfd-ioctl.c
+++ b/drivers/media/platform/msm/wfd/wfd-ioctl.c
@@ -14,14 +14,14 @@
#include <linux/types.h>
#include <linux/list.h>
#include <linux/ioctl.h>
-#include <linux/spinlock.h>
+#include <linux/mutex.h>
#include <linux/init.h>
#include <linux/version.h>
#include <linux/platform_device.h>
-
#include <linux/sched.h>
#include <linux/kthread.h>
#include <linux/time.h>
+#include <linux/slab.h>
#include <mach/board.h>
#include <media/v4l2-dev.h>
@@ -78,7 +78,8 @@
struct wfd_inst {
struct vb2_queue vid_bufq;
- spinlock_t inst_lock;
+ struct mutex lock;
+ struct mutex vb2_lock;
u32 buf_count;
struct task_struct *mdp_task;
void *mdp_inst;
@@ -114,7 +115,6 @@
{
struct file *priv_data = (struct file *)(q->drv_priv);
struct wfd_inst *inst = file_to_inst(priv_data);
- unsigned long flags;
int i;
WFD_MSG_DBG("In %s\n", __func__);
@@ -122,12 +122,12 @@
return -EINVAL;
*num_planes = 1;
- spin_lock_irqsave(&inst->inst_lock, flags);
+ mutex_lock(&inst->lock);
for (i = 0; i < *num_planes; ++i) {
sizes[i] = inst->out_buf_size;
alloc_ctxs[i] = inst;
}
- spin_unlock_irqrestore(&inst->inst_lock, flags);
+ mutex_unlock(&inst->lock);
return 0;
}
@@ -257,16 +257,15 @@
struct mem_region *enc_mregion, *mdp_mregion;
struct mem_region_pair *mpair;
int rc;
- unsigned long flags;
struct mdp_buf_info mdp_buf = {0};
struct mem_region_map mmap_context = {0};
- spin_lock_irqsave(&inst->inst_lock, flags);
+ mutex_lock(&inst->lock);
if (inst->input_bufs_allocated) {
- spin_unlock_irqrestore(&inst->inst_lock, flags);
+ mutex_unlock(&inst->lock);
return 0;
}
inst->input_bufs_allocated = true;
- spin_unlock_irqrestore(&inst->inst_lock, flags);
+ mutex_unlock(&inst->lock);
for (i = 0; i < VENC_INPUT_BUFFERS; ++i) {
mpair = kzalloc(sizeof(*mpair), GFP_KERNEL);
@@ -409,15 +408,14 @@
{
struct list_head *ptr, *next;
struct mem_region_pair *mpair;
- unsigned long flags;
int rc = 0;
- spin_lock_irqsave(&inst->inst_lock, flags);
+ mutex_lock(&inst->lock);
if (!inst->input_bufs_allocated) {
- spin_unlock_irqrestore(&inst->inst_lock, flags);
+ mutex_unlock(&inst->lock);
return;
}
inst->input_bufs_allocated = false;
- spin_unlock_irqrestore(&inst->inst_lock, flags);
+ mutex_unlock(&inst->lock);
if (!list_empty(&inst->input_mem_list)) {
list_for_each_safe(ptr, next,
&inst->input_mem_list) {
@@ -470,8 +468,7 @@
{
struct mem_info_entry *temp;
struct mem_info *ret = NULL;
- unsigned long flags;
- spin_lock_irqsave(&inst->inst_lock, flags);
+ mutex_lock(&inst->lock);
if (!list_empty(&inst->minfo_list)) {
list_for_each_entry(temp, &inst->minfo_list, list) {
if (temp && temp->userptr == userptr) {
@@ -480,7 +477,7 @@
}
}
}
- spin_unlock_irqrestore(&inst->inst_lock, flags);
+ mutex_unlock(&inst->lock);
return ret;
}
@@ -489,8 +486,7 @@
{
struct list_head *ptr, *next;
struct mem_info_entry *temp;
- unsigned long flags;
- spin_lock_irqsave(&inst->inst_lock, flags);
+ mutex_lock(&inst->lock);
if (!list_empty(&inst->minfo_list)) {
list_for_each_safe(ptr, next,
&inst->minfo_list) {
@@ -502,7 +498,7 @@
}
}
}
- spin_unlock_irqrestore(&inst->inst_lock, flags);
+ mutex_unlock(&inst->lock);
}
static void wfd_unregister_out_buf(struct wfd_inst *inst,
struct mem_info *minfo)
@@ -806,7 +802,6 @@
struct v4l2_format *fmt)
{
struct wfd_inst *inst = file_to_inst(filp);
- unsigned long flags;
if (!fmt) {
WFD_MSG_ERR("Invalid argument\n");
return -EINVAL;
@@ -815,13 +810,13 @@
WFD_MSG_ERR("Only V4L2_BUF_TYPE_VIDEO_CAPTURE is supported\n");
return -EINVAL;
}
- spin_lock_irqsave(&inst->inst_lock, flags);
+ mutex_lock(&inst->lock);
fmt->fmt.pix.width = inst->width;
fmt->fmt.pix.height = inst->height;
fmt->fmt.pix.pixelformat = inst->pixelformat;
fmt->fmt.pix.sizeimage = inst->out_buf_size;
fmt->fmt.pix.priv = 0;
- spin_unlock_irqrestore(&inst->inst_lock, flags);
+ mutex_unlock(&inst->lock);
return 0;
}
@@ -832,7 +827,6 @@
struct wfd_inst *inst = file_to_inst(filp);
struct wfd_device *wfd_dev = video_drvdata(filp);
struct mdp_prop prop;
- unsigned long flags;
struct bufreq breq;
if (!fmt) {
WFD_MSG_ERR("Invalid argument\n");
@@ -864,13 +858,13 @@
WFD_MSG_ERR("Failed to set buffer reqs on encoder\n");
return rc;
}
- spin_lock_irqsave(&inst->inst_lock, flags);
+ mutex_lock(&inst->lock);
inst->input_buf_size = breq.size;
inst->out_buf_size = fmt->fmt.pix.sizeimage;
prop.height = inst->height = fmt->fmt.pix.height;
prop.width = inst->width = fmt->fmt.pix.width;
prop.inst = inst->mdp_inst;
- spin_unlock_irqrestore(&inst->inst_lock, flags);
+ mutex_unlock(&inst->lock);
rc = v4l2_subdev_call(&wfd_dev->mdp_sdev, core, ioctl, MDP_SET_PROP,
(void *)&prop);
if (rc)
@@ -882,7 +876,6 @@
{
struct wfd_inst *inst = file_to_inst(filp);
struct wfd_device *wfd_dev = video_drvdata(filp);
- unsigned long flags;
int rc = 0;
if (b->type != V4L2_CAP_VIDEO_CAPTURE ||
@@ -897,9 +890,9 @@
WFD_MSG_ERR("Failed to get buf reqs from encoder\n");
return rc;
}
- spin_lock_irqsave(&inst->inst_lock, flags);
+ mutex_lock(&inst->lock);
inst->buf_count = b->count;
- spin_unlock_irqrestore(&inst->inst_lock, flags);
+ mutex_unlock(&inst->lock);
rc = vb2_reqbufs(&inst->vid_bufq, b);
return rc;
}
@@ -908,7 +901,6 @@
{
struct mem_info_entry *minfo_entry;
struct mem_info *minfo;
- unsigned long flags;
if (!b || !inst || !b->reserved) {
WFD_MSG_ERR("Invalid arguments\n");
return -EINVAL;
@@ -924,9 +916,9 @@
return -EINVAL;
}
minfo_entry->userptr = b->m.userptr;
- spin_lock_irqsave(&inst->inst_lock, flags);
+ mutex_lock(&inst->lock);
list_add_tail(&minfo_entry->list, &inst->minfo_list);
- spin_unlock_irqrestore(&inst->inst_lock, flags);
+ mutex_unlock(&inst->lock);
} else
WFD_MSG_DBG("Buffer already registered\n");
@@ -948,7 +940,10 @@
return rc;
}
+ mutex_lock(&inst->vb2_lock);
rc = vb2_qbuf(&inst->vid_bufq, b);
+ mutex_unlock(&inst->vb2_lock);
+
if (rc)
WFD_MSG_ERR("Failed to queue buffer\n");
else
@@ -962,16 +957,15 @@
{
int rc = 0;
struct wfd_inst *inst = file_to_inst(filp);
- unsigned long flags;
if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
WFD_MSG_ERR("stream on for buffer type = %d is not "
"supported.\n", i);
return -EINVAL;
}
- spin_lock_irqsave(&inst->inst_lock, flags);
+ mutex_lock(&inst->lock);
inst->streamoff = false;
- spin_unlock_irqrestore(&inst->inst_lock, flags);
+ mutex_unlock(&inst->lock);
rc = vb2_streamon(&inst->vid_bufq, i);
if (rc) {
@@ -988,7 +982,6 @@
enum v4l2_buf_type i)
{
struct wfd_inst *inst = file_to_inst(filp);
- unsigned long flags;
if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
WFD_MSG_ERR("stream off for buffer type = %d is not "
@@ -996,14 +989,14 @@
return -EINVAL;
}
- spin_lock_irqsave(&inst->inst_lock, flags);
+ mutex_lock(&inst->lock);
if (inst->streamoff) {
WFD_MSG_ERR("Module is already in streamoff state\n");
- spin_unlock_irqrestore(&inst->inst_lock, flags);
+ mutex_unlock(&inst->lock);
return -EINVAL;
}
inst->streamoff = true;
- spin_unlock_irqrestore(&inst->inst_lock, flags);
+ mutex_unlock(&inst->lock);
WFD_MSG_DBG("Calling videobuf_streamoff\n");
vb2_streamoff(&inst->vid_bufq, i);
wake_up(&inst->event_handler.wait);
@@ -1016,7 +1009,10 @@
int rc;
WFD_MSG_DBG("Waiting to dequeue buffer\n");
- rc = vb2_dqbuf(&inst->vid_bufq, b, 0);
+
+ /* XXX: If we switch to non-blocking mode in the future,
+ * we'll need to lock this with vb2_lock */
+ rc = vb2_dqbuf(&inst->vid_bufq, b, false /* blocking */);
if (rc)
WFD_MSG_ERR("Failed to dequeue buffer\n");
@@ -1233,7 +1229,6 @@
};
static int wfd_set_default_properties(struct file *filp)
{
- unsigned long flags;
struct v4l2_format fmt;
struct v4l2_control ctrl;
struct wfd_inst *inst = file_to_inst(filp);
@@ -1241,13 +1236,13 @@
WFD_MSG_ERR("Invalid argument\n");
return -EINVAL;
}
- spin_lock_irqsave(&inst->inst_lock, flags);
+ mutex_lock(&inst->lock);
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.height = inst->height = DEFAULT_WFD_HEIGHT;
fmt.fmt.pix.width = inst->width = DEFAULT_WFD_WIDTH;
fmt.fmt.pix.pixelformat = inst->pixelformat
= V4L2_PIX_FMT_H264;
- spin_unlock_irqrestore(&inst->inst_lock, flags);
+ mutex_unlock(&inst->lock);
wfdioc_s_fmt(filp, filp->private_data, &fmt);
ctrl.id = V4L2_CID_MPEG_VIDEO_HEADER_MODE;
@@ -1258,8 +1253,13 @@
static void venc_op_buffer_done(void *cookie, u32 status,
struct vb2_buffer *buf)
{
+ struct file *filp = cookie;
+ struct wfd_inst *inst = file_to_inst(filp);
+
WFD_MSG_DBG("yay!! got callback\n");
+ mutex_lock(&inst->vb2_lock);
vb2_buffer_done(buf, VB2_BUF_STATE_DONE);
+ mutex_unlock(&inst->vb2_lock);
}
static void venc_ip_buffer_done(void *cookie, u32 status,
@@ -1430,7 +1430,8 @@
goto err_mdp_open;
}
filp->private_data = &inst->event_handler;
- spin_lock_init(&inst->inst_lock);
+ mutex_init(&inst->lock);
+ mutex_init(&inst->vb2_lock);
INIT_LIST_HEAD(&inst->input_mem_list);
INIT_LIST_HEAD(&inst->minfo_list);
@@ -1531,6 +1532,8 @@
wfd_stats_deinit(&inst->stats);
v4l2_fh_del(&inst->event_handler);
+ mutex_destroy(&inst->lock);
+ mutex_destroy(&inst->vb2_lock);
kfree(inst);
}
@@ -1546,22 +1549,21 @@
unsigned int wfd_poll(struct file *filp, struct poll_table_struct *pt)
{
struct wfd_inst *inst = file_to_inst(filp);
- unsigned int poll_flags = 0;
- unsigned long flags;
+ unsigned long flags = 0;
bool streamoff = false;
poll_wait(filp, &inst->event_handler.wait, pt);
- spin_lock_irqsave(&inst->inst_lock, flags);
+ mutex_lock(&inst->lock);
streamoff = inst->streamoff;
- spin_unlock_irqrestore(&inst->inst_lock, flags);
+ mutex_unlock(&inst->lock);
if (v4l2_event_pending(&inst->event_handler))
- poll_flags |= POLLPRI;
+ flags |= POLLPRI;
if (streamoff)
- poll_flags |= POLLERR;
+ flags |= POLLERR;
- return poll_flags;
+ return flags;
}
static const struct v4l2_file_operations g_wfd_fops = {
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 2573a16..a7932ba 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -51,10 +51,6 @@
To compile this driver as a module, choose M here: the
module will be called ad525x_dpot-spi.
-config ANDROID_PMEM
- bool "Android pmem allocator"
- default y
-
config ATMEL_PWM
tristate "Atmel AT32/AT91 PWM support"
depends on HAVE_CLK
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 327d1ec..760f768 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -19,7 +19,6 @@
obj-$(CONFIG_SENSORS_BH1780) += bh1780gli.o
obj-$(CONFIG_SENSORS_BH1770) += bh1770glc.o
obj-$(CONFIG_SENSORS_APDS990X) += apds990x.o
-obj-$(CONFIG_ANDROID_PMEM) += pmem.o
obj-$(CONFIG_SGI_IOC4) += ioc4.o
obj-$(CONFIG_ENCLOSURE_SERVICES) += enclosure.o
obj-$(CONFIG_KGDB_TESTS) += kgdbts.o
diff --git a/drivers/misc/pmem.c b/drivers/misc/pmem.c
deleted file mode 100644
index e91db7a..0000000
--- a/drivers/misc/pmem.c
+++ /dev/null
@@ -1,2961 +0,0 @@
-/* drivers/android/pmem.c
- *
- * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/export.h>
-#include <linux/miscdevice.h>
-#include <linux/platform_device.h>
-#include <linux/fs.h>
-#include <linux/file.h>
-#include <linux/fmem.h>
-#include <linux/mm.h>
-#include <linux/list.h>
-#include <linux/debugfs.h>
-#include <linux/android_pmem.h>
-#include <linux/mempolicy.h>
-#include <linux/sched.h>
-#include <linux/kobject.h>
-#include <linux/pm_runtime.h>
-#include <linux/memory_alloc.h>
-#include <linux/vmalloc.h>
-#include <linux/io.h>
-#include <linux/mm_types.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/cacheflush.h>
-#include <asm/sizes.h>
-#include <asm/mach/map.h>
-#include <asm/page.h>
-
-#define PMEM_MAX_DEVICES (10)
-
-#define PMEM_MAX_ORDER (128)
-#define PMEM_MIN_ALLOC PAGE_SIZE
-
-#define PMEM_INITIAL_NUM_BITMAP_ALLOCATIONS (64)
-
-#define PMEM_32BIT_WORD_ORDER (5)
-#define PMEM_BITS_PER_WORD_MASK (BITS_PER_LONG - 1)
-
-#ifdef CONFIG_ANDROID_PMEM_DEBUG
-#define PMEM_DEBUG 1
-#else
-#define PMEM_DEBUG 0
-#endif
-
-#define SYSTEM_ALLOC_RETRY 10
-
-/* indicates that a refernce to this file has been taken via get_pmem_file,
- * the file should not be released until put_pmem_file is called */
-#define PMEM_FLAGS_BUSY 0x1
-/* indicates that this is a suballocation of a larger master range */
-#define PMEM_FLAGS_CONNECTED 0x1 << 1
-/* indicates this is a master and not a sub allocation and that it is mmaped */
-#define PMEM_FLAGS_MASTERMAP 0x1 << 2
-/* submap and unsubmap flags indicate:
- * 00: subregion has never been mmaped
- * 10: subregion has been mmaped, reference to the mm was taken
- * 11: subretion has ben released, refernece to the mm still held
- * 01: subretion has been released, reference to the mm has been released
- */
-#define PMEM_FLAGS_SUBMAP 0x1 << 3
-#define PMEM_FLAGS_UNSUBMAP 0x1 << 4
-
-struct pmem_data {
- /* in alloc mode: an index into the bitmap
- * in no_alloc mode: the size of the allocation */
- int index;
- /* see flags above for descriptions */
- unsigned int flags;
- /* protects this data field, if the mm_mmap sem will be held at the
- * same time as this sem, the mm sem must be taken first (as this is
- * the order for vma_open and vma_close ops */
- struct rw_semaphore sem;
- /* info about the mmaping process */
- struct vm_area_struct *vma;
- /* task struct of the mapping process */
- struct task_struct *task;
- /* process id of teh mapping process */
- pid_t pid;
- /* file descriptor of the master */
- int master_fd;
- /* file struct of the master */
- struct file *master_file;
- /* a list of currently available regions if this is a suballocation */
- struct list_head region_list;
- /* a linked list of data so we can access them for debugging */
- struct list_head list;
-#if PMEM_DEBUG
- int ref;
-#endif
-};
-
-struct pmem_bits {
- unsigned allocated:1; /* 1 if allocated, 0 if free */
- unsigned order:7; /* size of the region in pmem space */
-};
-
-struct pmem_region_node {
- struct pmem_region region;
- struct list_head list;
-};
-
-#define PMEM_DEBUG_MSGS 0
-#if PMEM_DEBUG_MSGS
-#define DLOG(fmt,args...) \
- do { pr_debug("[%s:%s:%d] "fmt, __FILE__, __func__, __LINE__, \
- ##args); } \
- while (0)
-#else
-#define DLOG(x...) do {} while (0)
-#endif
-
-enum pmem_align {
- PMEM_ALIGN_4K,
- PMEM_ALIGN_1M,
-};
-
-#define PMEM_NAME_SIZE 16
-
-struct alloc_list {
- void *addr; /* physical addr of allocation */
- void *aaddr; /* aligned physical addr */
- unsigned int size; /* total size of allocation */
- unsigned char __iomem *vaddr; /* Virtual addr */
- struct list_head allocs;
-};
-
-struct pmem_info {
- struct miscdevice dev;
- /* physical start address of the remaped pmem space */
- unsigned long base;
- /* vitual start address of the remaped pmem space */
- unsigned char __iomem *vbase;
- /* total size of the pmem space */
- unsigned long size;
- /* number of entries in the pmem space */
- unsigned long num_entries;
- /* pfn of the garbage page in memory */
- unsigned long garbage_pfn;
- /* which memory type (i.e. SMI, EBI1) this PMEM device is backed by */
- unsigned memory_type;
-
- char name[PMEM_NAME_SIZE];
-
- /* index of the garbage page in the pmem space */
- int garbage_index;
- /* reserved virtual address range */
- struct vm_struct *area;
-
- enum pmem_allocator_type allocator_type;
-
- int (*allocate)(const int,
- const unsigned long,
- const unsigned int);
- int (*free)(int, int);
- int (*free_space)(int, struct pmem_freespace *);
- unsigned long (*len)(int, struct pmem_data *);
- unsigned long (*start_addr)(int, struct pmem_data *);
-
- /* actual size of memory element, e.g.: (4 << 10) is 4K */
- unsigned int quantum;
-
- /* indicates maps of this region should be cached, if a mix of
- * cached and uncached is desired, set this and open the device with
- * O_SYNC to get an uncached region */
- unsigned cached;
- unsigned buffered;
- union {
- struct {
- /* in all_or_nothing allocator mode the first mapper
- * gets the whole space and sets this flag */
- unsigned allocated;
- } all_or_nothing;
-
- struct {
- /* the buddy allocator bitmap for the region
- * indicating which entries are allocated and which
- * are free.
- */
-
- struct pmem_bits *buddy_bitmap;
- } buddy_bestfit;
-
- struct {
- unsigned int bitmap_free; /* # of zero bits/quanta */
- uint32_t *bitmap;
- int32_t bitmap_allocs;
- struct {
- short bit;
- unsigned short quanta;
- } *bitm_alloc;
- } bitmap;
-
- struct {
- unsigned long used; /* Bytes currently allocated */
- struct list_head alist; /* List of allocations */
- } system_mem;
- } allocator;
-
- int id;
- struct kobject kobj;
-
- /* for debugging, creates a list of pmem file structs, the
- * data_list_mutex should be taken before pmem_data->sem if both are
- * needed */
- struct mutex data_list_mutex;
- struct list_head data_list;
- /* arena_mutex protects the global allocation arena
- *
- * IF YOU TAKE BOTH LOCKS TAKE THEM IN THIS ORDER:
- * down(pmem_data->sem) => mutex_lock(arena_mutex)
- */
- struct mutex arena_mutex;
-
- long (*ioctl)(struct file *, unsigned int, unsigned long);
- int (*release)(struct inode *, struct file *);
- /* reference count of allocations */
- atomic_t allocation_cnt;
- /*
- * request function for a region when the allocation count goes
- * from 0 -> 1
- */
- int (*mem_request)(void *);
- /*
- * release function for a region when the allocation count goes
- * from 1 -> 0
- */
- int (*mem_release)(void *);
- /*
- * private data for the request/release callback
- */
- void *region_data;
- /*
- * map and unmap as needed
- */
- int map_on_demand;
- /*
- * memory will be reused through fmem
- */
- int reusable;
-};
-#define to_pmem_info_id(a) (container_of(a, struct pmem_info, kobj)->id)
-
-static void ioremap_pmem(int id);
-static void pmem_put_region(int id);
-static int pmem_get_region(int id);
-
-static struct pmem_info pmem[PMEM_MAX_DEVICES];
-static int id_count;
-
-#define PMEM_SYSFS_DIR_NAME "pmem_regions" /* under /sys/kernel/ */
-static struct kset *pmem_kset;
-
-#define PMEM_IS_FREE_BUDDY(id, index) \
- (!(pmem[id].allocator.buddy_bestfit.buddy_bitmap[index].allocated))
-#define PMEM_BUDDY_ORDER(id, index) \
- (pmem[id].allocator.buddy_bestfit.buddy_bitmap[index].order)
-#define PMEM_BUDDY_INDEX(id, index) \
- (index ^ (1 << PMEM_BUDDY_ORDER(id, index)))
-#define PMEM_BUDDY_NEXT_INDEX(id, index) \
- (index + (1 << PMEM_BUDDY_ORDER(id, index)))
-#define PMEM_OFFSET(index) (index * pmem[id].quantum)
-#define PMEM_START_ADDR(id, index) \
- (PMEM_OFFSET(index) + pmem[id].base)
-#define PMEM_BUDDY_LEN(id, index) \
- ((1 << PMEM_BUDDY_ORDER(id, index)) * pmem[id].quantum)
-#define PMEM_END_ADDR(id, index) \
- (PMEM_START_ADDR(id, index) + PMEM_LEN(id, index))
-#define PMEM_START_VADDR(id, index) \
- (PMEM_OFFSET(id, index) + pmem[id].vbase)
-#define PMEM_END_VADDR(id, index) \
- (PMEM_START_VADDR(id, index) + PMEM_LEN(id, index))
-#define PMEM_REVOKED(data) (data->flags & PMEM_FLAGS_REVOKED)
-#define PMEM_IS_PAGE_ALIGNED(addr) (!((addr) & (~PAGE_MASK)))
-#define PMEM_IS_SUBMAP(data) \
- ((data->flags & PMEM_FLAGS_SUBMAP) && \
- (!(data->flags & PMEM_FLAGS_UNSUBMAP)))
-
-static int pmem_release(struct inode *, struct file *);
-static int pmem_mmap(struct file *, struct vm_area_struct *);
-static int pmem_open(struct inode *, struct file *);
-static long pmem_ioctl(struct file *, unsigned int, unsigned long);
-
-struct file_operations pmem_fops = {
- .release = pmem_release,
- .mmap = pmem_mmap,
- .open = pmem_open,
- .unlocked_ioctl = pmem_ioctl,
-};
-
-#define PMEM_ATTR(_name, _mode, _show, _store) { \
- .attr = {.name = __stringify(_name), .mode = _mode }, \
- .show = _show, \
- .store = _store, \
-}
-
-struct pmem_attr {
- struct attribute attr;
- ssize_t(*show) (const int id, char * const);
- ssize_t(*store) (const int id, const char * const, const size_t count);
-};
-#define to_pmem_attr(a) container_of(a, struct pmem_attr, attr)
-
-#define RW_PMEM_ATTR(name) \
-static struct pmem_attr pmem_attr_## name = \
- PMEM_ATTR(name, S_IRUGO | S_IWUSR, show_pmem_## name, store_pmem_## name)
-
-#define RO_PMEM_ATTR(name) \
-static struct pmem_attr pmem_attr_## name = \
- PMEM_ATTR(name, S_IRUGO, show_pmem_## name, NULL)
-
-#define WO_PMEM_ATTR(name) \
-static struct pmem_attr pmem_attr_## name = \
- PMEM_ATTR(name, S_IWUSR, NULL, store_pmem_## name)
-
-static ssize_t show_pmem(struct kobject *kobj,
- struct attribute *attr,
- char *buf)
-{
- struct pmem_attr *a = to_pmem_attr(attr);
- return a->show ? a->show(to_pmem_info_id(kobj), buf) : -EIO;
-}
-
-static ssize_t store_pmem(struct kobject *kobj, struct attribute *attr,
- const char *buf, size_t count)
-{
- struct pmem_attr *a = to_pmem_attr(attr);
- return a->store ? a->store(to_pmem_info_id(kobj), buf, count) : -EIO;
-}
-
-static struct sysfs_ops pmem_ops = {
- .show = show_pmem,
- .store = store_pmem,
-};
-
-static ssize_t show_pmem_base(int id, char *buf)
-{
- return scnprintf(buf, PAGE_SIZE, "%lu(%#lx)\n",
- pmem[id].base, pmem[id].base);
-}
-RO_PMEM_ATTR(base);
-
-static ssize_t show_pmem_size(int id, char *buf)
-{
- return scnprintf(buf, PAGE_SIZE, "%lu(%#lx)\n",
- pmem[id].size, pmem[id].size);
-}
-RO_PMEM_ATTR(size);
-
-static ssize_t show_pmem_allocator_type(int id, char *buf)
-{
- switch (pmem[id].allocator_type) {
- case PMEM_ALLOCATORTYPE_ALLORNOTHING:
- return scnprintf(buf, PAGE_SIZE, "%s\n", "All or Nothing");
- case PMEM_ALLOCATORTYPE_BUDDYBESTFIT:
- return scnprintf(buf, PAGE_SIZE, "%s\n", "Buddy Bestfit");
- case PMEM_ALLOCATORTYPE_BITMAP:
- return scnprintf(buf, PAGE_SIZE, "%s\n", "Bitmap");
- case PMEM_ALLOCATORTYPE_SYSTEM:
- return scnprintf(buf, PAGE_SIZE, "%s\n", "System heap");
- default:
- return scnprintf(buf, PAGE_SIZE,
- "??? Invalid allocator type (%d) for this region! "
- "Something isn't right.\n",
- pmem[id].allocator_type);
- }
-}
-RO_PMEM_ATTR(allocator_type);
-
-static ssize_t show_pmem_mapped_regions(int id, char *buf)
-{
- struct list_head *elt;
- int ret;
-
- ret = scnprintf(buf, PAGE_SIZE,
- "pid #: mapped regions (offset, len) (offset,len)...\n");
-
- mutex_lock(&pmem[id].data_list_mutex);
- list_for_each(elt, &pmem[id].data_list) {
- struct pmem_data *data =
- list_entry(elt, struct pmem_data, list);
- struct list_head *elt2;
-
- down_read(&data->sem);
- ret += scnprintf(buf + ret, PAGE_SIZE - ret, "pid %u:",
- data->pid);
- list_for_each(elt2, &data->region_list) {
- struct pmem_region_node *region_node = list_entry(elt2,
- struct pmem_region_node,
- list);
- ret += scnprintf(buf + ret, PAGE_SIZE - ret,
- "(%lx,%lx) ",
- region_node->region.offset,
- region_node->region.len);
- }
- up_read(&data->sem);
- ret += scnprintf(buf + ret, PAGE_SIZE - ret, "\n");
- }
- mutex_unlock(&pmem[id].data_list_mutex);
- return ret;
-}
-RO_PMEM_ATTR(mapped_regions);
-
-#define PMEM_COMMON_SYSFS_ATTRS \
- &pmem_attr_base.attr, \
- &pmem_attr_size.attr, \
- &pmem_attr_allocator_type.attr, \
- &pmem_attr_mapped_regions.attr
-
-
-static ssize_t show_pmem_allocated(int id, char *buf)
-{
- ssize_t ret;
-
- mutex_lock(&pmem[id].arena_mutex);
- ret = scnprintf(buf, PAGE_SIZE, "%s\n",
- pmem[id].allocator.all_or_nothing.allocated ?
- "is allocated" : "is NOT allocated");
- mutex_unlock(&pmem[id].arena_mutex);
- return ret;
-}
-RO_PMEM_ATTR(allocated);
-
-static struct attribute *pmem_allornothing_attrs[] = {
- PMEM_COMMON_SYSFS_ATTRS,
-
- &pmem_attr_allocated.attr,
-
- NULL
-};
-
-static struct kobj_type pmem_allornothing_ktype = {
- .sysfs_ops = &pmem_ops,
- .default_attrs = pmem_allornothing_attrs,
-};
-
-static ssize_t show_pmem_total_entries(int id, char *buf)
-{
- return scnprintf(buf, PAGE_SIZE, "%lu\n", pmem[id].num_entries);
-}
-RO_PMEM_ATTR(total_entries);
-
-static ssize_t show_pmem_quantum_size(int id, char *buf)
-{
- return scnprintf(buf, PAGE_SIZE, "%u (%#x)\n",
- pmem[id].quantum, pmem[id].quantum);
-}
-RO_PMEM_ATTR(quantum_size);
-
-static ssize_t show_pmem_buddy_bitmap_dump(int id, char *buf)
-{
- int ret, i;
-
- mutex_lock(&pmem[id].data_list_mutex);
- ret = scnprintf(buf, PAGE_SIZE, "index\torder\tlength\tallocated\n");
-
- for (i = 0; i < pmem[id].num_entries && (PAGE_SIZE - ret);
- i = PMEM_BUDDY_NEXT_INDEX(id, i))
- ret += scnprintf(buf + ret, PAGE_SIZE - ret, "%d\t%d\t%d\t%d\n",
- i, PMEM_BUDDY_ORDER(id, i),
- PMEM_BUDDY_LEN(id, i),
- !PMEM_IS_FREE_BUDDY(id, i));
-
- mutex_unlock(&pmem[id].data_list_mutex);
- return ret;
-}
-RO_PMEM_ATTR(buddy_bitmap_dump);
-
-#define PMEM_BITMAP_BUDDY_BESTFIT_COMMON_SYSFS_ATTRS \
- &pmem_attr_quantum_size.attr, \
- &pmem_attr_total_entries.attr
-
-static struct attribute *pmem_buddy_bestfit_attrs[] = {
- PMEM_COMMON_SYSFS_ATTRS,
-
- PMEM_BITMAP_BUDDY_BESTFIT_COMMON_SYSFS_ATTRS,
-
- &pmem_attr_buddy_bitmap_dump.attr,
-
- NULL
-};
-
-static struct kobj_type pmem_buddy_bestfit_ktype = {
- .sysfs_ops = &pmem_ops,
- .default_attrs = pmem_buddy_bestfit_attrs,
-};
-
-static ssize_t show_pmem_free_quanta(int id, char *buf)
-{
- ssize_t ret;
-
- mutex_lock(&pmem[id].arena_mutex);
- ret = scnprintf(buf, PAGE_SIZE, "%u\n",
- pmem[id].allocator.bitmap.bitmap_free);
- mutex_unlock(&pmem[id].arena_mutex);
- return ret;
-}
-RO_PMEM_ATTR(free_quanta);
-
-static ssize_t show_pmem_bits_allocated(int id, char *buf)
-{
- ssize_t ret;
- unsigned int i;
-
- mutex_lock(&pmem[id].arena_mutex);
-
- ret = scnprintf(buf, PAGE_SIZE,
- "id: %d\nbitnum\tindex\tquanta allocated\n", id);
-
- for (i = 0; i < pmem[id].allocator.bitmap.bitmap_allocs; i++)
- if (pmem[id].allocator.bitmap.bitm_alloc[i].bit != -1)
- ret += scnprintf(buf + ret, PAGE_SIZE - ret,
- "%u\t%u\t%u\n",
- i,
- pmem[id].allocator.bitmap.bitm_alloc[i].bit,
- pmem[id].allocator.bitmap.bitm_alloc[i].quanta
- );
-
- mutex_unlock(&pmem[id].arena_mutex);
- return ret;
-}
-RO_PMEM_ATTR(bits_allocated);
-
-static struct attribute *pmem_bitmap_attrs[] = {
- PMEM_COMMON_SYSFS_ATTRS,
-
- PMEM_BITMAP_BUDDY_BESTFIT_COMMON_SYSFS_ATTRS,
-
- &pmem_attr_free_quanta.attr,
- &pmem_attr_bits_allocated.attr,
-
- NULL
-};
-
-static struct attribute *pmem_system_attrs[] = {
- PMEM_COMMON_SYSFS_ATTRS,
-
- NULL
-};
-
-static struct kobj_type pmem_bitmap_ktype = {
- .sysfs_ops = &pmem_ops,
- .default_attrs = pmem_bitmap_attrs,
-};
-
-static struct kobj_type pmem_system_ktype = {
- .sysfs_ops = &pmem_ops,
- .default_attrs = pmem_system_attrs,
-};
-
-static int pmem_allocate_from_id(const int id, const unsigned long size,
- const unsigned int align)
-{
- int ret;
- ret = pmem_get_region(id);
-
- if (ret)
- return -1;
-
- ret = pmem[id].allocate(id, size, align);
-
- if (ret < 0)
- pmem_put_region(id);
-
- return ret;
-}
-
-static int pmem_free_from_id(const int id, const int index)
-{
- pmem_put_region(id);
- return pmem[id].free(id, index);
-}
-
-static int pmem_get_region(int id)
-{
- /* Must be called with arena mutex locked */
- atomic_inc(&pmem[id].allocation_cnt);
- if (!pmem[id].vbase) {
- DLOG("PMEMDEBUG: mapping for %s", pmem[id].name);
- if (pmem[id].mem_request) {
- int ret = pmem[id].mem_request(pmem[id].region_data);
- if (ret) {
- atomic_dec(&pmem[id].allocation_cnt);
- return 1;
- }
- }
- ioremap_pmem(id);
- }
-
- if (pmem[id].vbase) {
- return 0;
- } else {
- if (pmem[id].mem_release)
- pmem[id].mem_release(pmem[id].region_data);
- atomic_dec(&pmem[id].allocation_cnt);
- return 1;
- }
-}
-
-static void pmem_put_region(int id)
-{
- /* Must be called with arena mutex locked */
- if (atomic_dec_and_test(&pmem[id].allocation_cnt)) {
- DLOG("PMEMDEBUG: unmapping for %s", pmem[id].name);
- BUG_ON(!pmem[id].vbase);
- if (pmem[id].map_on_demand) {
- /* unmap_kernel_range() flushes the caches
- * and removes the page table entries
- */
- unmap_kernel_range((unsigned long)pmem[id].vbase,
- pmem[id].size);
- pmem[id].vbase = NULL;
- if (pmem[id].mem_release) {
- int ret = pmem[id].mem_release(
- pmem[id].region_data);
- WARN(ret, "mem_release failed");
- }
-
- }
- }
-}
-
-static int get_id(struct file *file)
-{
- return MINOR(file->f_dentry->d_inode->i_rdev);
-}
-
-static char *get_name(struct file *file)
-{
- int id = get_id(file);
- return pmem[id].name;
-}
-
-static int is_pmem_file(struct file *file)
-{
- int id;
-
- if (unlikely(!file || !file->f_dentry || !file->f_dentry->d_inode))
- return 0;
-
- id = get_id(file);
- return (unlikely(id >= PMEM_MAX_DEVICES ||
- file->f_dentry->d_inode->i_rdev !=
- MKDEV(MISC_MAJOR, pmem[id].dev.minor))) ? 0 : 1;
-}
-
-static int has_allocation(struct file *file)
-{
- /* must be called with at least read lock held on
- * ((struct pmem_data *)(file->private_data))->sem which
- * means that file is guaranteed not to be NULL upon entry!!
- * check is_pmem_file first if not accessed via pmem_file_ops */
- struct pmem_data *pdata = file->private_data;
- return pdata && pdata->index != -1;
-}
-
-static int is_master_owner(struct file *file)
-{
- struct file *master_file;
- struct pmem_data *data = file->private_data;
- int put_needed, ret = 0;
-
- if (!has_allocation(file))
- return 0;
- if (PMEM_FLAGS_MASTERMAP & data->flags)
- return 1;
- master_file = fget_light(data->master_fd, &put_needed);
- if (master_file && data->master_file == master_file)
- ret = 1;
- if (master_file)
- fput_light(master_file, put_needed);
- return ret;
-}
-
-static int pmem_free_all_or_nothing(int id, int index)
-{
- /* caller should hold the lock on arena_mutex! */
- DLOG("index %d\n", index);
-
- pmem[id].allocator.all_or_nothing.allocated = 0;
- return 0;
-}
-
-static int pmem_free_space_all_or_nothing(int id,
- struct pmem_freespace *fs)
-{
- /* caller should hold the lock on arena_mutex! */
- fs->total = (unsigned long)
- pmem[id].allocator.all_or_nothing.allocated == 0 ?
- pmem[id].size : 0;
-
- fs->largest = fs->total;
- return 0;
-}
-
-
-static int pmem_free_buddy_bestfit(int id, int index)
-{
- /* caller should hold the lock on arena_mutex! */
- int curr = index;
- DLOG("index %d\n", index);
-
-
- /* clean up the bitmap, merging any buddies */
- pmem[id].allocator.buddy_bestfit.buddy_bitmap[curr].allocated = 0;
- /* find a slots buddy Buddy# = Slot# ^ (1 << order)
- * if the buddy is also free merge them
- * repeat until the buddy is not free or end of the bitmap is reached
- */
- do {
- int buddy = PMEM_BUDDY_INDEX(id, curr);
- if (buddy < pmem[id].num_entries &&
- PMEM_IS_FREE_BUDDY(id, buddy) &&
- PMEM_BUDDY_ORDER(id, buddy) ==
- PMEM_BUDDY_ORDER(id, curr)) {
- PMEM_BUDDY_ORDER(id, buddy)++;
- PMEM_BUDDY_ORDER(id, curr)++;
- curr = min(buddy, curr);
- } else {
- break;
- }
- } while (curr < pmem[id].num_entries);
-
- return 0;
-}
-
-
-static int pmem_free_space_buddy_bestfit(int id,
- struct pmem_freespace *fs)
-{
- /* caller should hold the lock on arena_mutex! */
- int curr;
- unsigned long size;
- fs->total = 0;
- fs->largest = 0;
-
- for (curr = 0; curr < pmem[id].num_entries;
- curr = PMEM_BUDDY_NEXT_INDEX(id, curr)) {
- if (PMEM_IS_FREE_BUDDY(id, curr)) {
- size = PMEM_BUDDY_LEN(id, curr);
- if (size > fs->largest)
- fs->largest = size;
- fs->total += size;
- }
- }
- return 0;
-}
-
-
-static inline uint32_t start_mask(int bit_start)
-{
- return (uint32_t)(~0) << (bit_start & PMEM_BITS_PER_WORD_MASK);
-}
-
-static inline uint32_t end_mask(int bit_end)
-{
- return (uint32_t)(~0) >>
- ((BITS_PER_LONG - bit_end) & PMEM_BITS_PER_WORD_MASK);
-}
-
-static inline int compute_total_words(int bit_end, int word_index)
-{
- return ((bit_end + BITS_PER_LONG - 1) >>
- PMEM_32BIT_WORD_ORDER) - word_index;
-}
-
-static void bitmap_bits_clear_all(uint32_t *bitp, int bit_start, int bit_end)
-{
- int word_index = bit_start >> PMEM_32BIT_WORD_ORDER, total_words;
-
- total_words = compute_total_words(bit_end, word_index);
- if (total_words > 0) {
- if (total_words == 1) {
- bitp[word_index] &=
- ~(start_mask(bit_start) & end_mask(bit_end));
- } else {
- bitp[word_index++] &= ~start_mask(bit_start);
- if (total_words > 2) {
- int total_bytes;
-
- total_words -= 2;
- total_bytes = total_words << 2;
-
- memset(&bitp[word_index], 0, total_bytes);
- word_index += total_words;
- }
- bitp[word_index] &= ~end_mask(bit_end);
- }
- }
-}
-
-static int pmem_free_bitmap(int id, int bitnum)
-{
- /* caller should hold the lock on arena_mutex! */
- int i;
- char currtask_name[FIELD_SIZEOF(struct task_struct, comm) + 1];
-
- DLOG("bitnum %d\n", bitnum);
-
- for (i = 0; i < pmem[id].allocator.bitmap.bitmap_allocs; i++) {
- const int curr_bit =
- pmem[id].allocator.bitmap.bitm_alloc[i].bit;
-
- if (curr_bit == bitnum) {
- const int curr_quanta =
- pmem[id].allocator.bitmap.bitm_alloc[i].quanta;
-
- bitmap_bits_clear_all(pmem[id].allocator.bitmap.bitmap,
- curr_bit, curr_bit + curr_quanta);
- pmem[id].allocator.bitmap.bitmap_free += curr_quanta;
- pmem[id].allocator.bitmap.bitm_alloc[i].bit = -1;
- pmem[id].allocator.bitmap.bitm_alloc[i].quanta = 0;
- return 0;
- }
- }
- printk(KERN_ALERT "pmem: %s: Attempt to free unallocated index %d, id"
- " %d, pid %d(%s)\n", __func__, bitnum, id, current->pid,
- get_task_comm(currtask_name, current));
-
- return -1;
-}
-
-static int pmem_free_system(int id, int index)
-{
- /* caller should hold the lock on arena_mutex! */
- struct alloc_list *item;
-
- DLOG("index %d\n", index);
- if (index != 0)
- item = (struct alloc_list *)index;
- else
- return 0;
-
- if (item->vaddr != NULL) {
- iounmap(item->vaddr);
- kfree(__va(item->addr));
- list_del(&item->allocs);
- kfree(item);
- }
-
- return 0;
-}
-
-static int pmem_free_space_bitmap(int id, struct pmem_freespace *fs)
-{
- int i, j;
- int max_allocs = pmem[id].allocator.bitmap.bitmap_allocs;
- int alloc_start = 0;
- int next_alloc;
- unsigned long size = 0;
-
- fs->total = 0;
- fs->largest = 0;
-
- for (i = 0; i < max_allocs; i++) {
-
- int alloc_quanta = 0;
- int alloc_idx = 0;
- next_alloc = pmem[id].num_entries;
-
- /* Look for the lowest bit where next allocation starts */
- for (j = 0; j < max_allocs; j++) {
- const int curr_alloc = pmem[id].allocator.
- bitmap.bitm_alloc[j].bit;
- if (curr_alloc != -1) {
- if (alloc_start == curr_alloc)
- alloc_idx = j;
- if (alloc_start >= curr_alloc)
- continue;
- if (curr_alloc < next_alloc)
- next_alloc = curr_alloc;
- }
- }
- alloc_quanta = pmem[id].allocator.bitmap.
- bitm_alloc[alloc_idx].quanta;
- size = (next_alloc - (alloc_start + alloc_quanta)) *
- pmem[id].quantum;
-
- if (size > fs->largest)
- fs->largest = size;
- fs->total += size;
-
- if (next_alloc == pmem[id].num_entries)
- break;
- else
- alloc_start = next_alloc;
- }
-
- return 0;
-}
-
-static int pmem_free_space_system(int id, struct pmem_freespace *fs)
-{
- fs->total = pmem[id].size;
- fs->largest = pmem[id].size;
-
- return 0;
-}
-
-static void pmem_revoke(struct file *file, struct pmem_data *data);
-
-static int pmem_release(struct inode *inode, struct file *file)
-{
- struct pmem_data *data = file->private_data;
- struct pmem_region_node *region_node;
- struct list_head *elt, *elt2;
- int id = get_id(file), ret = 0;
-
-#if PMEM_DEBUG_MSGS
- char currtask_name[FIELD_SIZEOF(struct task_struct, comm) + 1];
-#endif
- DLOG("releasing memory pid %u(%s) file %p(%ld) dev %s(id: %d)\n",
- current->pid, get_task_comm(currtask_name, current),
- file, file_count(file), get_name(file), id);
- mutex_lock(&pmem[id].data_list_mutex);
- /* if this file is a master, revoke all the memory in the connected
- * files */
- if (PMEM_FLAGS_MASTERMAP & data->flags) {
- list_for_each(elt, &pmem[id].data_list) {
- struct pmem_data *sub_data =
- list_entry(elt, struct pmem_data, list);
- int is_master;
-
- down_read(&sub_data->sem);
- is_master = (PMEM_IS_SUBMAP(sub_data) &&
- file == sub_data->master_file);
- up_read(&sub_data->sem);
-
- if (is_master)
- pmem_revoke(file, sub_data);
- }
- }
- list_del(&data->list);
- mutex_unlock(&pmem[id].data_list_mutex);
-
- down_write(&data->sem);
-
- /* if it is not a connected file and it has an allocation, free it */
- if (!(PMEM_FLAGS_CONNECTED & data->flags) && has_allocation(file)) {
- mutex_lock(&pmem[id].arena_mutex);
- ret = pmem_free_from_id(id, data->index);
- mutex_unlock(&pmem[id].arena_mutex);
- }
-
- /* if this file is a submap (mapped, connected file), downref the
- * task struct */
- if (PMEM_FLAGS_SUBMAP & data->flags)
- if (data->task) {
- put_task_struct(data->task);
- data->task = NULL;
- }
-
- file->private_data = NULL;
-
- list_for_each_safe(elt, elt2, &data->region_list) {
- region_node = list_entry(elt, struct pmem_region_node, list);
- list_del(elt);
- kfree(region_node);
- }
- BUG_ON(!list_empty(&data->region_list));
-
- up_write(&data->sem);
- kfree(data);
- if (pmem[id].release)
- ret = pmem[id].release(inode, file);
-
- return ret;
-}
-
-static int pmem_open(struct inode *inode, struct file *file)
-{
- struct pmem_data *data;
- int id = get_id(file);
- int ret = 0;
-#if PMEM_DEBUG_MSGS
- char currtask_name[FIELD_SIZEOF(struct task_struct, comm) + 1];
-#endif
-
- DLOG("pid %u(%s) file %p(%ld) dev %s(id: %d)\n",
- current->pid, get_task_comm(currtask_name, current),
- file, file_count(file), get_name(file), id);
- data = kmalloc(sizeof(struct pmem_data), GFP_KERNEL);
- if (!data) {
- printk(KERN_ALERT "pmem: %s: unable to allocate memory for "
- "pmem metadata.", __func__);
- return -1;
- }
- data->flags = 0;
- data->index = -1;
- data->task = NULL;
- data->vma = NULL;
- data->pid = 0;
- data->master_file = NULL;
-#if PMEM_DEBUG
- data->ref = 0;
-#endif
- INIT_LIST_HEAD(&data->region_list);
- init_rwsem(&data->sem);
-
- file->private_data = data;
- INIT_LIST_HEAD(&data->list);
-
- mutex_lock(&pmem[id].data_list_mutex);
- list_add(&data->list, &pmem[id].data_list);
- mutex_unlock(&pmem[id].data_list_mutex);
- return ret;
-}
-
-static unsigned long pmem_order(unsigned long len, int id)
-{
- int i;
-
- len = (len + pmem[id].quantum - 1)/pmem[id].quantum;
- len--;
- for (i = 0; i < sizeof(len)*8; i++)
- if (len >> i == 0)
- break;
- return i;
-}
-
-static int pmem_allocator_all_or_nothing(const int id,
- const unsigned long len,
- const unsigned int align)
-{
- /* caller should hold the lock on arena_mutex! */
- DLOG("all or nothing\n");
- if ((len > pmem[id].size) ||
- pmem[id].allocator.all_or_nothing.allocated)
- return -1;
- pmem[id].allocator.all_or_nothing.allocated = 1;
- return len;
-}
-
-static int pmem_allocator_buddy_bestfit(const int id,
- const unsigned long len,
- unsigned int align)
-{
- /* caller should hold the lock on arena_mutex! */
- int curr;
- int best_fit = -1;
- unsigned long order;
-
- DLOG("buddy bestfit\n");
- order = pmem_order(len, id);
- if (order > PMEM_MAX_ORDER)
- goto out;
-
- DLOG("order %lx\n", order);
-
- /* Look through the bitmap.
- * If a free slot of the correct order is found, use it.
- * Otherwise, use the best fit (smallest with size > order) slot.
- */
- for (curr = 0;
- curr < pmem[id].num_entries;
- curr = PMEM_BUDDY_NEXT_INDEX(id, curr))
- if (PMEM_IS_FREE_BUDDY(id, curr)) {
- if (PMEM_BUDDY_ORDER(id, curr) ==
- (unsigned char)order) {
- /* set the not free bit and clear others */
- best_fit = curr;
- break;
- }
- if (PMEM_BUDDY_ORDER(id, curr) >
- (unsigned char)order &&
- (best_fit < 0 ||
- PMEM_BUDDY_ORDER(id, curr) <
- PMEM_BUDDY_ORDER(id, best_fit)))
- best_fit = curr;
- }
-
- /* if best_fit < 0, there are no suitable slots; return an error */
- if (best_fit < 0) {
-#if PMEM_DEBUG
- printk(KERN_ALERT "pmem: %s: no space left to allocate!\n",
- __func__);
-#endif
- goto out;
- }
-
- /* now partition the best fit:
- * split the slot into 2 buddies of order - 1
- * repeat until the slot is of the correct order
- */
- while (PMEM_BUDDY_ORDER(id, best_fit) > (unsigned char)order) {
- int buddy;
- PMEM_BUDDY_ORDER(id, best_fit) -= 1;
- buddy = PMEM_BUDDY_INDEX(id, best_fit);
- PMEM_BUDDY_ORDER(id, buddy) = PMEM_BUDDY_ORDER(id, best_fit);
- }
- pmem[id].allocator.buddy_bestfit.buddy_bitmap[best_fit].allocated = 1;
-out:
- return best_fit;
-}
-
-
-static inline unsigned long paddr_from_bit(const int id, const int bitnum)
-{
- return pmem[id].base + pmem[id].quantum * bitnum;
-}
-
-static inline unsigned long bit_from_paddr(const int id,
- const unsigned long paddr)
-{
- return (paddr - pmem[id].base) / pmem[id].quantum;
-}
-
-static void bitmap_bits_set_all(uint32_t *bitp, int bit_start, int bit_end)
-{
- int word_index = bit_start >> PMEM_32BIT_WORD_ORDER, total_words;
-
- total_words = compute_total_words(bit_end, word_index);
- if (total_words > 0) {
- if (total_words == 1) {
- bitp[word_index] |=
- (start_mask(bit_start) & end_mask(bit_end));
- } else {
- bitp[word_index++] |= start_mask(bit_start);
- if (total_words > 2) {
- int total_bytes;
-
- total_words -= 2;
- total_bytes = total_words << 2;
-
- memset(&bitp[word_index], ~0, total_bytes);
- word_index += total_words;
- }
- bitp[word_index] |= end_mask(bit_end);
- }
- }
-}
-
-static int
-bitmap_allocate_contiguous(uint32_t *bitp, int num_bits_to_alloc,
- int total_bits, int spacing, int start_bit)
-{
- int bit_start, last_bit, word_index;
-
- if (num_bits_to_alloc <= 0)
- return -1;
-
- for (bit_start = start_bit; ;
- bit_start = ((last_bit +
- (word_index << PMEM_32BIT_WORD_ORDER) + spacing - 1)
- & ~(spacing - 1)) + start_bit) {
- int bit_end = bit_start + num_bits_to_alloc, total_words;
-
- if (bit_end > total_bits)
- return -1; /* out of contiguous memory */
-
- word_index = bit_start >> PMEM_32BIT_WORD_ORDER;
- total_words = compute_total_words(bit_end, word_index);
-
- if (total_words <= 0)
- return -1;
-
- if (total_words == 1) {
- last_bit = fls(bitp[word_index] &
- (start_mask(bit_start) &
- end_mask(bit_end)));
- if (last_bit)
- continue;
- } else {
- int end_word = word_index + (total_words - 1);
- last_bit =
- fls(bitp[word_index] & start_mask(bit_start));
- if (last_bit)
- continue;
-
- for (word_index++;
- word_index < end_word;
- word_index++) {
- last_bit = fls(bitp[word_index]);
- if (last_bit)
- break;
- }
- if (last_bit)
- continue;
-
- last_bit = fls(bitp[word_index] & end_mask(bit_end));
- if (last_bit)
- continue;
- }
- bitmap_bits_set_all(bitp, bit_start, bit_end);
- return bit_start;
- }
- return -1;
-}
-
-static int reserve_quanta(const unsigned int quanta_needed,
- const int id,
- unsigned int align)
-{
- /* alignment should be a valid power of 2 */
- int ret = -1, start_bit = 0, spacing = 1;
-
- /* Sanity check */
- if (quanta_needed > pmem[id].allocator.bitmap.bitmap_free) {
-#if PMEM_DEBUG
- printk(KERN_ALERT "pmem: %s: request (%d) too big for"
- " available free (%d)\n", __func__, quanta_needed,
- pmem[id].allocator.bitmap.bitmap_free);
-#endif
- return -1;
- }
-
- start_bit = bit_from_paddr(id,
- (pmem[id].base + align - 1) & ~(align - 1));
- if (start_bit <= -1) {
-#if PMEM_DEBUG
- printk(KERN_ALERT
- "pmem: %s: bit_from_paddr fails for"
- " %u alignment.\n", __func__, align);
-#endif
- return -1;
- }
- spacing = align / pmem[id].quantum;
- spacing = spacing > 1 ? spacing : 1;
-
- ret = bitmap_allocate_contiguous(pmem[id].allocator.bitmap.bitmap,
- quanta_needed,
- (pmem[id].size + pmem[id].quantum - 1) / pmem[id].quantum,
- spacing,
- start_bit);
-
-#if PMEM_DEBUG
- if (ret < 0)
- printk(KERN_ALERT "pmem: %s: not enough contiguous bits free "
- "in bitmap! Region memory is either too fragmented or"
- " request is too large for available memory.\n",
- __func__);
-#endif
-
- return ret;
-}
-
-static int pmem_allocator_bitmap(const int id,
- const unsigned long len,
- const unsigned int align)
-{
- /* caller should hold the lock on arena_mutex! */
- int bitnum, i;
- unsigned int quanta_needed;
-
- DLOG("bitmap id %d, len %ld, align %u\n", id, len, align);
- if (!pmem[id].allocator.bitmap.bitm_alloc) {
-#if PMEM_DEBUG
- printk(KERN_ALERT "pmem: bitm_alloc not present! id: %d\n",
- id);
-#endif
- return -1;
- }
-
- quanta_needed = (len + pmem[id].quantum - 1) / pmem[id].quantum;
- DLOG("quantum size %u quanta needed %u free %u id %d\n",
- pmem[id].quantum, quanta_needed,
- pmem[id].allocator.bitmap.bitmap_free, id);
-
- if (pmem[id].allocator.bitmap.bitmap_free < quanta_needed) {
-#if PMEM_DEBUG
- printk(KERN_ALERT "pmem: memory allocation failure. "
- "PMEM memory region exhausted, id %d."
- " Unable to comply with allocation request.\n", id);
-#endif
- return -1;
- }
-
- bitnum = reserve_quanta(quanta_needed, id, align);
- if (bitnum == -1)
- goto leave;
-
- for (i = 0;
- i < pmem[id].allocator.bitmap.bitmap_allocs &&
- pmem[id].allocator.bitmap.bitm_alloc[i].bit != -1;
- i++)
- ;
-
- if (i >= pmem[id].allocator.bitmap.bitmap_allocs) {
- void *temp;
- int32_t new_bitmap_allocs =
- pmem[id].allocator.bitmap.bitmap_allocs << 1;
- int j;
-
- if (!new_bitmap_allocs) { /* failed sanity check!! */
-#if PMEM_DEBUG
- pr_alert("pmem: bitmap_allocs number"
- " wrapped around to zero! Something "
- "is VERY wrong.\n");
-#endif
- return -1;
- }
-
- if (new_bitmap_allocs > pmem[id].num_entries) {
- /* failed sanity check!! */
-#if PMEM_DEBUG
- pr_alert("pmem: required bitmap_allocs"
- " number exceeds maximum entries possible"
- " for current quanta\n");
-#endif
- return -1;
- }
-
- temp = krealloc(pmem[id].allocator.bitmap.bitm_alloc,
- new_bitmap_allocs *
- sizeof(*pmem[id].allocator.bitmap.bitm_alloc),
- GFP_KERNEL);
- if (!temp) {
-#if PMEM_DEBUG
- pr_alert("pmem: can't realloc bitmap_allocs,"
- "id %d, current num bitmap allocs %d\n",
- id, pmem[id].allocator.bitmap.bitmap_allocs);
-#endif
- return -1;
- }
- pmem[id].allocator.bitmap.bitmap_allocs = new_bitmap_allocs;
- pmem[id].allocator.bitmap.bitm_alloc = temp;
-
- for (j = i; j < new_bitmap_allocs; j++) {
- pmem[id].allocator.bitmap.bitm_alloc[j].bit = -1;
- pmem[id].allocator.bitmap.bitm_alloc[i].quanta = 0;
- }
-
- DLOG("increased # of allocated regions to %d for id %d\n",
- pmem[id].allocator.bitmap.bitmap_allocs, id);
- }
-
- DLOG("bitnum %d, bitm_alloc index %d\n", bitnum, i);
-
- pmem[id].allocator.bitmap.bitmap_free -= quanta_needed;
- pmem[id].allocator.bitmap.bitm_alloc[i].bit = bitnum;
- pmem[id].allocator.bitmap.bitm_alloc[i].quanta = quanta_needed;
-leave:
- return bitnum;
-}
-
-static int pmem_allocator_system(const int id,
- const unsigned long len,
- const unsigned int align)
-{
- /* caller should hold the lock on arena_mutex! */
- struct alloc_list *list;
- unsigned long aligned_len;
- int count = SYSTEM_ALLOC_RETRY;
- void *buf;
-
- DLOG("system id %d, len %ld, align %u\n", id, len, align);
-
- if ((pmem[id].allocator.system_mem.used + len) > pmem[id].size) {
- DLOG("requested size would be larger than quota\n");
- return -1;
- }
-
- /* Handle alignment */
- aligned_len = len + align;
-
- /* Attempt allocation */
- list = kmalloc(sizeof(struct alloc_list), GFP_KERNEL);
- if (list == NULL) {
- printk(KERN_ERR "pmem: failed to allocate system metadata\n");
- return -1;
- }
- list->vaddr = NULL;
-
- buf = NULL;
- while ((buf == NULL) && count--) {
- buf = kmalloc((aligned_len), GFP_KERNEL);
- if (buf == NULL) {
- DLOG("pmem: kmalloc %d temporarily failed len= %ld\n",
- count, aligned_len);
- }
- }
- if (!buf) {
- printk(KERN_CRIT "pmem: kmalloc failed for id= %d len= %ld\n",
- id, aligned_len);
- kfree(list);
- return -1;
- }
- list->size = aligned_len;
- list->addr = (void *)__pa(buf);
- list->aaddr = (void *)(((unsigned int)(list->addr) + (align - 1)) &
- ~(align - 1));
-
- if (!pmem[id].cached)
- list->vaddr = ioremap(__pa(buf), aligned_len);
- else
- list->vaddr = ioremap_cached(__pa(buf), aligned_len);
-
- INIT_LIST_HEAD(&list->allocs);
- list_add(&list->allocs, &pmem[id].allocator.system_mem.alist);
-
- return (int)list;
-}
-
-static pgprot_t pmem_phys_mem_access_prot(struct file *file, pgprot_t vma_prot)
-{
- int id = get_id(file);
-#ifdef pgprot_writecombine
- if (pmem[id].cached == 0 || file->f_flags & O_SYNC)
- /* on ARMv6 and ARMv7 this expands to Normal Noncached */
- return pgprot_writecombine(vma_prot);
-#endif
-#ifdef pgprot_ext_buffered
- else if (pmem[id].buffered)
- return pgprot_ext_buffered(vma_prot);
-#endif
- return vma_prot;
-}
-
-static unsigned long pmem_start_addr_all_or_nothing(int id,
- struct pmem_data *data)
-{
- return PMEM_START_ADDR(id, 0);
-}
-
-static unsigned long pmem_start_addr_buddy_bestfit(int id,
- struct pmem_data *data)
-{
- return PMEM_START_ADDR(id, data->index);
-}
-
-static unsigned long pmem_start_addr_bitmap(int id, struct pmem_data *data)
-{
- return data->index * pmem[id].quantum + pmem[id].base;
-}
-
-static unsigned long pmem_start_addr_system(int id, struct pmem_data *data)
-{
- return (unsigned long)(((struct alloc_list *)(data->index))->aaddr);
-}
-
-static void *pmem_start_vaddr(int id, struct pmem_data *data)
-{
- if (pmem[id].allocator_type == PMEM_ALLOCATORTYPE_SYSTEM)
- return ((struct alloc_list *)(data->index))->vaddr;
- else
- return pmem[id].start_addr(id, data) - pmem[id].base + pmem[id].vbase;
-}
-
-static unsigned long pmem_len_all_or_nothing(int id, struct pmem_data *data)
-{
- return data->index;
-}
-
-static unsigned long pmem_len_buddy_bestfit(int id, struct pmem_data *data)
-{
- return PMEM_BUDDY_LEN(id, data->index);
-}
-
-static unsigned long pmem_len_bitmap(int id, struct pmem_data *data)
-{
- int i;
- unsigned long ret = 0;
-
- mutex_lock(&pmem[id].arena_mutex);
-
- for (i = 0; i < pmem[id].allocator.bitmap.bitmap_allocs; i++)
- if (pmem[id].allocator.bitmap.bitm_alloc[i].bit ==
- data->index) {
- ret = pmem[id].allocator.bitmap.bitm_alloc[i].quanta *
- pmem[id].quantum;
- break;
- }
-
- mutex_unlock(&pmem[id].arena_mutex);
-#if PMEM_DEBUG
- if (i >= pmem[id].allocator.bitmap.bitmap_allocs)
- pr_alert("pmem: %s: can't find bitnum %d in "
- "alloc'd array!\n", __func__, data->index);
-#endif
- return ret;
-}
-
-static unsigned long pmem_len_system(int id, struct pmem_data *data)
-{
- unsigned long ret = 0;
-
- mutex_lock(&pmem[id].arena_mutex);
-
- ret = ((struct alloc_list *)data->index)->size;
- mutex_unlock(&pmem[id].arena_mutex);
-
- return ret;
-}
-
-static int pmem_map_garbage(int id, struct vm_area_struct *vma,
- struct pmem_data *data, unsigned long offset,
- unsigned long len)
-{
- int i, garbage_pages = len >> PAGE_SHIFT;
-
- vma->vm_flags |= VM_IO | VM_RESERVED | VM_PFNMAP | VM_SHARED | VM_WRITE;
- for (i = 0; i < garbage_pages; i++) {
- if (vm_insert_pfn(vma, vma->vm_start + offset + (i * PAGE_SIZE),
- pmem[id].garbage_pfn))
- return -EAGAIN;
- }
- return 0;
-}
-
-static int pmem_unmap_pfn_range(int id, struct vm_area_struct *vma,
- struct pmem_data *data, unsigned long offset,
- unsigned long len)
-{
- int garbage_pages;
- DLOG("unmap offset %lx len %lx\n", offset, len);
-
- BUG_ON(!PMEM_IS_PAGE_ALIGNED(len));
-
- garbage_pages = len >> PAGE_SHIFT;
- zap_page_range(vma, vma->vm_start + offset, len, NULL);
- pmem_map_garbage(id, vma, data, offset, len);
- return 0;
-}
-
-static int pmem_map_pfn_range(int id, struct vm_area_struct *vma,
- struct pmem_data *data, unsigned long offset,
- unsigned long len)
-{
- int ret;
- DLOG("map offset %lx len %lx\n", offset, len);
- BUG_ON(!PMEM_IS_PAGE_ALIGNED(vma->vm_start));
- BUG_ON(!PMEM_IS_PAGE_ALIGNED(vma->vm_end));
- BUG_ON(!PMEM_IS_PAGE_ALIGNED(len));
- BUG_ON(!PMEM_IS_PAGE_ALIGNED(offset));
-
- ret = io_remap_pfn_range(vma, vma->vm_start + offset,
- (pmem[id].start_addr(id, data) + offset) >> PAGE_SHIFT,
- len, vma->vm_page_prot);
- if (ret) {
-#if PMEM_DEBUG
- pr_alert("pmem: %s: io_remap_pfn_range fails with "
- "return value: %d!\n", __func__, ret);
-#endif
-
- ret = -EAGAIN;
- }
- return ret;
-}
-
-static int pmem_remap_pfn_range(int id, struct vm_area_struct *vma,
- struct pmem_data *data, unsigned long offset,
- unsigned long len)
-{
- /* hold the mm semp for the vma you are modifying when you call this */
- BUG_ON(!vma);
- zap_page_range(vma, vma->vm_start + offset, len, NULL);
- return pmem_map_pfn_range(id, vma, data, offset, len);
-}
-
-static void pmem_vma_open(struct vm_area_struct *vma)
-{
- struct file *file = vma->vm_file;
- struct pmem_data *data = file->private_data;
- int id = get_id(file);
-
-#if PMEM_DEBUG_MSGS
- char currtask_name[FIELD_SIZEOF(struct task_struct, comm) + 1];
-#endif
- DLOG("Dev %s(id: %d) pid %u(%s) ppid %u file %p count %ld\n",
- get_name(file), id, current->pid,
- get_task_comm(currtask_name, current),
- current->parent->pid, file, file_count(file));
- /* this should never be called as we don't support copying pmem
- * ranges via fork */
- down_read(&data->sem);
- BUG_ON(!has_allocation(file));
- /* remap the garbage pages, forkers don't get access to the data */
- pmem_unmap_pfn_range(id, vma, data, 0, vma->vm_start - vma->vm_end);
- up_read(&data->sem);
-}
-
-static void pmem_vma_close(struct vm_area_struct *vma)
-{
- struct file *file = vma->vm_file;
- struct pmem_data *data = file->private_data;
-
-#if PMEM_DEBUG_MSGS
- char currtask_name[FIELD_SIZEOF(struct task_struct, comm) + 1];
-#endif
- DLOG("Dev %s(id: %d) pid %u(%s) ppid %u file %p count %ld\n",
- get_name(file), get_id(file), current->pid,
- get_task_comm(currtask_name, current),
- current->parent->pid, file, file_count(file));
-
- if (unlikely(!is_pmem_file(file))) {
- pr_warning("pmem: something is very wrong, you are "
- "closing a vm backing an allocation that doesn't "
- "exist!\n");
- return;
- }
-
- down_write(&data->sem);
- if (unlikely(!has_allocation(file))) {
- up_write(&data->sem);
- pr_warning("pmem: something is very wrong, you are "
- "closing a vm backing an allocation that doesn't "
- "exist!\n");
- return;
- }
- if (data->vma == vma) {
- data->vma = NULL;
- if ((data->flags & PMEM_FLAGS_CONNECTED) &&
- (data->flags & PMEM_FLAGS_SUBMAP))
- data->flags |= PMEM_FLAGS_UNSUBMAP;
- }
- /* the kernel is going to free this vma now anyway */
- up_write(&data->sem);
-}
-
-static struct vm_operations_struct vm_ops = {
- .open = pmem_vma_open,
- .close = pmem_vma_close,
-};
-
-static int pmem_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct pmem_data *data = file->private_data;
- int index = -1;
- unsigned long vma_size = vma->vm_end - vma->vm_start;
- int ret = 0, id = get_id(file);
-#if PMEM_DEBUG_MSGS
- char currtask_name[FIELD_SIZEOF(struct task_struct, comm) + 1];
-#endif
-
- if (!data) {
- pr_err("pmem: Invalid file descriptor, no private data\n");
- return -EINVAL;
- }
- DLOG("pid %u(%s) mmap vma_size %lu on dev %s(id: %d)\n", current->pid,
- get_task_comm(currtask_name, current), vma_size,
- get_name(file), id);
- if (vma->vm_pgoff || !PMEM_IS_PAGE_ALIGNED(vma_size)) {
-#if PMEM_DEBUG
- pr_err("pmem: mmaps must be at offset zero, aligned"
- " and a multiple of pages_size.\n");
-#endif
- return -EINVAL;
- }
-
- down_write(&data->sem);
- /* check this file isn't already mmaped, for submaps check this file
- * has never been mmaped */
- if ((data->flags & PMEM_FLAGS_SUBMAP) ||
- (data->flags & PMEM_FLAGS_UNSUBMAP)) {
-#if PMEM_DEBUG
- pr_err("pmem: you can only mmap a pmem file once, "
- "this file is already mmaped. %x\n", data->flags);
-#endif
- ret = -EINVAL;
- goto error;
- }
- /* if file->private_data == unalloced, alloc*/
- if (data->index == -1) {
- mutex_lock(&pmem[id].arena_mutex);
- index = pmem_allocate_from_id(id,
- vma->vm_end - vma->vm_start,
- SZ_4K);
- mutex_unlock(&pmem[id].arena_mutex);
- /* either no space was available or an error occured */
- if (index == -1) {
- pr_err("pmem: mmap unable to allocate memory"
- "on %s\n", get_name(file));
- ret = -ENOMEM;
- goto error;
- }
- /* store the index of a successful allocation */
- data->index = index;
- }
-
- if (pmem[id].len(id, data) < vma_size) {
-#if PMEM_DEBUG
- pr_err("pmem: mmap size [%lu] does not match"
- " size of backing region [%lu].\n", vma_size,
- pmem[id].len(id, data));
-#endif
- ret = -EINVAL;
- goto error;
- }
-
- vma->vm_pgoff = pmem[id].start_addr(id, data) >> PAGE_SHIFT;
-
- vma->vm_page_prot = pmem_phys_mem_access_prot(file, vma->vm_page_prot);
-
- if (data->flags & PMEM_FLAGS_CONNECTED) {
- struct pmem_region_node *region_node;
- struct list_head *elt;
- if (pmem_map_garbage(id, vma, data, 0, vma_size)) {
- pr_alert("pmem: mmap failed in kernel!\n");
- ret = -EAGAIN;
- goto error;
- }
- list_for_each(elt, &data->region_list) {
- region_node = list_entry(elt, struct pmem_region_node,
- list);
- DLOG("remapping file: %p %lx %lx\n", file,
- region_node->region.offset,
- region_node->region.len);
- if (pmem_remap_pfn_range(id, vma, data,
- region_node->region.offset,
- region_node->region.len)) {
- ret = -EAGAIN;
- goto error;
- }
- }
- data->flags |= PMEM_FLAGS_SUBMAP;
- get_task_struct(current->group_leader);
- data->task = current->group_leader;
- data->vma = vma;
-#if PMEM_DEBUG
- data->pid = current->pid;
-#endif
- DLOG("submmapped file %p vma %p pid %u\n", file, vma,
- current->pid);
- } else {
- if (pmem_map_pfn_range(id, vma, data, 0, vma_size)) {
- pr_err("pmem: mmap failed in kernel!\n");
- ret = -EAGAIN;
- goto error;
- }
- data->flags |= PMEM_FLAGS_MASTERMAP;
- data->pid = current->pid;
- }
- vma->vm_ops = &vm_ops;
-error:
- up_write(&data->sem);
- return ret;
-}
-
-/* the following are the api for accessing pmem regions by other drivers
- * from inside the kernel */
-int get_pmem_user_addr(struct file *file, unsigned long *start,
- unsigned long *len)
-{
- int ret = -1;
-
- if (is_pmem_file(file)) {
- struct pmem_data *data = file->private_data;
-
- down_read(&data->sem);
- if (has_allocation(file)) {
- if (data->vma) {
- *start = data->vma->vm_start;
- *len = data->vma->vm_end - data->vma->vm_start;
- } else {
- *start = *len = 0;
-#if PMEM_DEBUG
- pr_err("pmem: %s: no vma present.\n",
- __func__);
-#endif
- }
- ret = 0;
- }
- up_read(&data->sem);
- }
-
-#if PMEM_DEBUG
- if (ret)
- pr_err("pmem: %s: requested pmem data from invalid"
- "file.\n", __func__);
-#endif
- return ret;
-}
-
-int get_pmem_addr(struct file *file, unsigned long *start,
- unsigned long *vstart, unsigned long *len)
-{
- int ret = -1;
-
- if (is_pmem_file(file)) {
- struct pmem_data *data = file->private_data;
-
- down_read(&data->sem);
- if (has_allocation(file)) {
- int id = get_id(file);
-
- *start = pmem[id].start_addr(id, data);
- *len = pmem[id].len(id, data);
- *vstart = (unsigned long)
- pmem_start_vaddr(id, data);
- up_read(&data->sem);
-#if PMEM_DEBUG
- down_write(&data->sem);
- data->ref++;
- up_write(&data->sem);
-#endif
- DLOG("returning start %#lx len %lu "
- "vstart %#lx\n",
- *start, *len, *vstart);
- ret = 0;
- } else {
- up_read(&data->sem);
- }
- }
- return ret;
-}
-
-int get_pmem_file(unsigned int fd, unsigned long *start, unsigned long *vstart,
- unsigned long *len, struct file **filp)
-{
- int ret = -1;
- struct file *file = fget(fd);
-
- if (unlikely(file == NULL)) {
- pr_err("pmem: %s: requested data from file "
- "descriptor that doesn't exist.\n", __func__);
- } else {
-#if PMEM_DEBUG_MSGS
- char currtask_name[FIELD_SIZEOF(struct task_struct, comm) + 1];
-#endif
- DLOG("filp %p rdev %d pid %u(%s) file %p(%ld)"
- " dev %s(id: %d)\n", filp,
- file->f_dentry->d_inode->i_rdev,
- current->pid, get_task_comm(currtask_name, current),
- file, file_count(file), get_name(file), get_id(file));
-
- if (!get_pmem_addr(file, start, vstart, len)) {
- if (filp)
- *filp = file;
- ret = 0;
- } else {
- fput(file);
- }
- }
- return ret;
-}
-EXPORT_SYMBOL(get_pmem_file);
-
-int get_pmem_fd(int fd, unsigned long *start, unsigned long *len)
-{
- unsigned long vstart;
- return get_pmem_file(fd, start, &vstart, len, NULL);
-}
-EXPORT_SYMBOL(get_pmem_fd);
-
-void put_pmem_file(struct file *file)
-{
-#if PMEM_DEBUG_MSGS
- char currtask_name[FIELD_SIZEOF(struct task_struct, comm) + 1];
-#endif
- DLOG("rdev %d pid %u(%s) file %p(%ld)" " dev %s(id: %d)\n",
- file->f_dentry->d_inode->i_rdev, current->pid,
- get_task_comm(currtask_name, current), file,
- file_count(file), get_name(file), get_id(file));
- if (is_pmem_file(file)) {
-#if PMEM_DEBUG
- struct pmem_data *data = file->private_data;
-
- down_write(&data->sem);
- if (!data->ref--) {
- data->ref++;
- pr_alert("pmem: pmem_put > pmem_get %s "
- "(pid %d)\n",
- pmem[get_id(file)].dev.name, data->pid);
- BUG();
- }
- up_write(&data->sem);
-#endif
- fput(file);
- }
-}
-EXPORT_SYMBOL(put_pmem_file);
-
-void put_pmem_fd(int fd)
-{
- int put_needed;
- struct file *file = fget_light(fd, &put_needed);
-
- if (file) {
- put_pmem_file(file);
- fput_light(file, put_needed);
- }
-}
-
-void flush_pmem_fd(int fd, unsigned long offset, unsigned long len)
-{
- int fput_needed;
- struct file *file = fget_light(fd, &fput_needed);
-
- if (file) {
- flush_pmem_file(file, offset, len);
- fput_light(file, fput_needed);
- }
-}
-
-void flush_pmem_file(struct file *file, unsigned long offset, unsigned long len)
-{
- struct pmem_data *data;
- int id;
- void *vaddr;
- struct pmem_region_node *region_node;
- struct list_head *elt;
- void *flush_start, *flush_end;
-#ifdef CONFIG_OUTER_CACHE
- unsigned long phy_start, phy_end;
-#endif
- if (!is_pmem_file(file))
- return;
-
- id = get_id(file);
- if (!pmem[id].cached)
- return;
-
- /* is_pmem_file fails if !file */
- data = file->private_data;
-
- down_read(&data->sem);
- if (!has_allocation(file))
- goto end;
-
- vaddr = pmem_start_vaddr(id, data);
-
- if (pmem[id].allocator_type == PMEM_ALLOCATORTYPE_SYSTEM) {
- dmac_flush_range(vaddr,
- (void *)((unsigned long)vaddr +
- ((struct alloc_list *)(data->index))->size));
-#ifdef CONFIG_OUTER_CACHE
- phy_start = pmem_start_addr_system(id, data);
-
- phy_end = phy_start +
- ((struct alloc_list *)(data->index))->size;
-
- outer_flush_range(phy_start, phy_end);
-#endif
- goto end;
- }
- /* if this isn't a submmapped file, flush the whole thing */
- if (unlikely(!(data->flags & PMEM_FLAGS_CONNECTED))) {
- dmac_flush_range(vaddr, vaddr + pmem[id].len(id, data));
-#ifdef CONFIG_OUTER_CACHE
- phy_start = (unsigned long)vaddr -
- (unsigned long)pmem[id].vbase + pmem[id].base;
-
- phy_end = phy_start + pmem[id].len(id, data);
-
- outer_flush_range(phy_start, phy_end);
-#endif
- goto end;
- }
- /* otherwise, flush the region of the file we are drawing */
- list_for_each(elt, &data->region_list) {
- region_node = list_entry(elt, struct pmem_region_node, list);
- if ((offset >= region_node->region.offset) &&
- ((offset + len) <= (region_node->region.offset +
- region_node->region.len))) {
- flush_start = vaddr + region_node->region.offset;
- flush_end = flush_start + region_node->region.len;
- dmac_flush_range(flush_start, flush_end);
-#ifdef CONFIG_OUTER_CACHE
-
- phy_start = (unsigned long)flush_start -
- (unsigned long)pmem[id].vbase + pmem[id].base;
-
- phy_end = phy_start + region_node->region.len;
-
- outer_flush_range(phy_start, phy_end);
-#endif
- break;
- }
- }
-end:
- up_read(&data->sem);
-}
-
-int pmem_cache_maint(struct file *file, unsigned int cmd,
- struct pmem_addr *pmem_addr)
-{
- struct pmem_data *data;
- int id;
- unsigned long vaddr, paddr, length, offset,
- pmem_len, pmem_start_addr;
-
- /* Called from kernel-space so file may be NULL */
- if (!file)
- return -EBADF;
-
- /*
- * check that the vaddr passed for flushing is valid
- * so that you don't crash the kernel
- */
- if (!pmem_addr->vaddr)
- return -EINVAL;
-
- data = file->private_data;
- id = get_id(file);
-
- if (!pmem[id].cached)
- return 0;
-
- offset = pmem_addr->offset;
- length = pmem_addr->length;
-
- down_read(&data->sem);
- if (!has_allocation(file)) {
- up_read(&data->sem);
- return -EINVAL;
- }
- pmem_len = pmem[id].len(id, data);
- pmem_start_addr = pmem[id].start_addr(id, data);
- up_read(&data->sem);
-
- if (offset + length > pmem_len)
- return -EINVAL;
-
- vaddr = pmem_addr->vaddr;
- paddr = pmem_start_addr + offset;
-
- DLOG("pmem cache maint on dev %s(id: %d)"
- "(vaddr %lx paddr %lx len %lu bytes)\n",
- get_name(file), id, vaddr, paddr, length);
- if (cmd == PMEM_CLEAN_INV_CACHES)
- clean_and_invalidate_caches(vaddr,
- length, paddr);
- else if (cmd == PMEM_CLEAN_CACHES)
- clean_caches(vaddr, length, paddr);
- else if (cmd == PMEM_INV_CACHES)
- invalidate_caches(vaddr, length, paddr);
-
- return 0;
-}
-EXPORT_SYMBOL(pmem_cache_maint);
-
-static int pmem_connect(unsigned long connect, struct file *file)
-{
- int ret = 0, put_needed;
- struct file *src_file;
-
- if (!file) {
- pr_err("pmem: %s: NULL file pointer passed in, "
- "bailing out!\n", __func__);
- ret = -EINVAL;
- goto leave;
- }
-
- src_file = fget_light(connect, &put_needed);
-
- if (!src_file) {
- pr_err("pmem: %s: src file not found!\n", __func__);
- ret = -EBADF;
- goto leave;
- }
-
- if (src_file == file) { /* degenerative case, operator error */
- pr_err("pmem: %s: src_file and passed in file are "
- "the same; refusing to connect to self!\n", __func__);
- ret = -EINVAL;
- goto put_src_file;
- }
-
- if (unlikely(!is_pmem_file(src_file))) {
- pr_err("pmem: %s: src file is not a pmem file!\n",
- __func__);
- ret = -EINVAL;
- goto put_src_file;
- } else {
- struct pmem_data *src_data = src_file->private_data;
-
- if (!src_data) {
- pr_err("pmem: %s: src file pointer has no"
- "private data, bailing out!\n", __func__);
- ret = -EINVAL;
- goto put_src_file;
- }
-
- down_read(&src_data->sem);
-
- if (unlikely(!has_allocation(src_file))) {
- up_read(&src_data->sem);
- pr_err("pmem: %s: src file has no allocation!\n",
- __func__);
- ret = -EINVAL;
- } else {
- struct pmem_data *data;
- int src_index = src_data->index;
-
- up_read(&src_data->sem);
-
- data = file->private_data;
- if (!data) {
- pr_err("pmem: %s: passed in file "
- "pointer has no private data, bailing"
- " out!\n", __func__);
- ret = -EINVAL;
- goto put_src_file;
- }
-
- down_write(&data->sem);
- if (has_allocation(file) &&
- (data->index != src_index)) {
- up_write(&data->sem);
-
- pr_err("pmem: %s: file is already "
- "mapped but doesn't match this "
- "src_file!\n", __func__);
- ret = -EINVAL;
- } else {
- data->index = src_index;
- data->flags |= PMEM_FLAGS_CONNECTED;
- data->master_fd = connect;
- data->master_file = src_file;
-
- up_write(&data->sem);
-
- DLOG("connect %p to %p\n", file, src_file);
- }
- }
- }
-put_src_file:
- fput_light(src_file, put_needed);
-leave:
- return ret;
-}
-
-static void pmem_unlock_data_and_mm(struct pmem_data *data,
- struct mm_struct *mm)
-{
- up_write(&data->sem);
- if (mm != NULL) {
- up_write(&mm->mmap_sem);
- mmput(mm);
- }
-}
-
-static int pmem_lock_data_and_mm(struct file *file, struct pmem_data *data,
- struct mm_struct **locked_mm)
-{
- int ret = 0;
- struct mm_struct *mm = NULL;
-#if PMEM_DEBUG_MSGS
- char currtask_name[FIELD_SIZEOF(struct task_struct, comm) + 1];
-#endif
- DLOG("pid %u(%s) file %p(%ld)\n",
- current->pid, get_task_comm(currtask_name, current),
- file, file_count(file));
-
- *locked_mm = NULL;
-lock_mm:
- down_read(&data->sem);
- if (PMEM_IS_SUBMAP(data)) {
- mm = get_task_mm(data->task);
- if (!mm) {
- up_read(&data->sem);
-#if PMEM_DEBUG
- pr_alert("pmem: can't remap - task is gone!\n");
-#endif
- return -1;
- }
- }
- up_read(&data->sem);
-
- if (mm)
- down_write(&mm->mmap_sem);
-
- down_write(&data->sem);
- /* check that the file didn't get mmaped before we could take the
- * data sem, this should be safe b/c you can only submap each file
- * once */
- if (PMEM_IS_SUBMAP(data) && !mm) {
- pmem_unlock_data_and_mm(data, mm);
- DLOG("mapping contention, repeating mmap op\n");
- goto lock_mm;
- }
- /* now check that vma.mm is still there, it could have been
- * deleted by vma_close before we could get the data->sem */
- if ((data->flags & PMEM_FLAGS_UNSUBMAP) && (mm != NULL)) {
- /* might as well release this */
- if (data->flags & PMEM_FLAGS_SUBMAP) {
- put_task_struct(data->task);
- data->task = NULL;
- /* lower the submap flag to show the mm is gone */
- data->flags &= ~(PMEM_FLAGS_SUBMAP);
- }
- pmem_unlock_data_and_mm(data, mm);
-#if PMEM_DEBUG
- pr_alert("pmem: vma.mm went away!\n");
-#endif
- return -1;
- }
- *locked_mm = mm;
- return ret;
-}
-
-int pmem_remap(struct pmem_region *region, struct file *file,
- unsigned operation)
-{
- int ret;
- struct pmem_region_node *region_node;
- struct mm_struct *mm = NULL;
- struct list_head *elt, *elt2;
- int id = get_id(file);
- struct pmem_data *data;
-
- DLOG("operation %#x, region offset %ld, region len %ld\n",
- operation, region->offset, region->len);
-
- if (!is_pmem_file(file)) {
-#if PMEM_DEBUG
- pr_err("pmem: remap request for non-pmem file descriptor\n");
-#endif
- return -EINVAL;
- }
-
- /* is_pmem_file fails if !file */
- data = file->private_data;
-
- /* pmem region must be aligned on a page boundry */
- if (unlikely(!PMEM_IS_PAGE_ALIGNED(region->offset) ||
- !PMEM_IS_PAGE_ALIGNED(region->len))) {
-#if PMEM_DEBUG
- pr_err("pmem: request for unaligned pmem"
- "suballocation %lx %lx\n",
- region->offset, region->len);
-#endif
- return -EINVAL;
- }
-
- /* if userspace requests a region of len 0, there's nothing to do */
- if (region->len == 0)
- return 0;
-
- /* lock the mm and data */
- ret = pmem_lock_data_and_mm(file, data, &mm);
- if (ret)
- return 0;
-
- /* only the owner of the master file can remap the client fds
- * that back in it */
- if (!is_master_owner(file)) {
-#if PMEM_DEBUG
- pr_err("pmem: remap requested from non-master process\n");
-#endif
- ret = -EINVAL;
- goto err;
- }
-
- /* check that the requested range is within the src allocation */
- if (unlikely((region->offset > pmem[id].len(id, data)) ||
- (region->len > pmem[id].len(id, data)) ||
- (region->offset + region->len > pmem[id].len(id, data)))) {
-#if PMEM_DEBUG
- pr_err("pmem: suballoc doesn't fit in src_file!\n");
-#endif
- ret = -EINVAL;
- goto err;
- }
-
- if (operation == PMEM_MAP) {
- region_node = kmalloc(sizeof(struct pmem_region_node),
- GFP_KERNEL);
- if (!region_node) {
- ret = -ENOMEM;
-#if PMEM_DEBUG
- pr_alert("pmem: No space to allocate remap metadata!");
-#endif
- goto err;
- }
- region_node->region = *region;
- list_add(®ion_node->list, &data->region_list);
- } else if (operation == PMEM_UNMAP) {
- int found = 0;
- list_for_each_safe(elt, elt2, &data->region_list) {
- region_node = list_entry(elt, struct pmem_region_node,
- list);
- if (region->len == 0 ||
- (region_node->region.offset == region->offset &&
- region_node->region.len == region->len)) {
- list_del(elt);
- kfree(region_node);
- found = 1;
- }
- }
- if (!found) {
-#if PMEM_DEBUG
- pr_err("pmem: Unmap region does not map any"
- " mapped region!");
-#endif
- ret = -EINVAL;
- goto err;
- }
- }
-
- if (data->vma && PMEM_IS_SUBMAP(data)) {
- if (operation == PMEM_MAP)
- ret = pmem_remap_pfn_range(id, data->vma, data,
- region->offset, region->len);
- else if (operation == PMEM_UNMAP)
- ret = pmem_unmap_pfn_range(id, data->vma, data,
- region->offset, region->len);
- }
-
-err:
- pmem_unlock_data_and_mm(data, mm);
- return ret;
-}
-
-static void pmem_revoke(struct file *file, struct pmem_data *data)
-{
- struct pmem_region_node *region_node;
- struct list_head *elt, *elt2;
- struct mm_struct *mm = NULL;
- int id = get_id(file);
- int ret = 0;
-
- data->master_file = NULL;
- ret = pmem_lock_data_and_mm(file, data, &mm);
- /* if lock_data_and_mm fails either the task that mapped the fd, or
- * the vma that mapped it have already gone away, nothing more
- * needs to be done */
- if (ret)
- return;
- /* unmap everything */
- /* delete the regions and region list nothing is mapped any more */
- if (data->vma)
- list_for_each_safe(elt, elt2, &data->region_list) {
- region_node = list_entry(elt, struct pmem_region_node,
- list);
- pmem_unmap_pfn_range(id, data->vma, data,
- region_node->region.offset,
- region_node->region.len);
- list_del(elt);
- kfree(region_node);
- }
- /* delete the master file */
- pmem_unlock_data_and_mm(data, mm);
-}
-
-static void pmem_get_size(struct pmem_region *region, struct file *file)
-{
- /* called via ioctl file op, so file guaranteed to be not NULL */
- struct pmem_data *data = file->private_data;
- int id = get_id(file);
-
- down_read(&data->sem);
- if (!has_allocation(file)) {
- region->offset = 0;
- region->len = 0;
- } else {
- region->offset = pmem[id].start_addr(id, data);
- region->len = pmem[id].len(id, data);
- }
- up_read(&data->sem);
- DLOG("offset 0x%lx len 0x%lx\n", region->offset, region->len);
-}
-
-
-static long pmem_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-{
- /* called from user space as file op, so file guaranteed to be not
- * NULL
- */
- struct pmem_data *data = file->private_data;
- int id = get_id(file);
-#if PMEM_DEBUG_MSGS
- char currtask_name[
- FIELD_SIZEOF(struct task_struct, comm) + 1];
-#endif
-
- DLOG("pid %u(%s) file %p(%ld) cmd %#x, dev %s(id: %d)\n",
- current->pid, get_task_comm(currtask_name, current),
- file, file_count(file), cmd, get_name(file), id);
-
- switch (cmd) {
- case PMEM_GET_PHYS:
- {
- struct pmem_region region;
-
- DLOG("get_phys\n");
- down_read(&data->sem);
- if (!has_allocation(file)) {
- region.offset = 0;
- region.len = 0;
- } else {
- region.offset = pmem[id].start_addr(id, data);
- region.len = pmem[id].len(id, data);
- }
- up_read(&data->sem);
-
- if (copy_to_user((void __user *)arg, ®ion,
- sizeof(struct pmem_region)))
- return -EFAULT;
-
- DLOG("pmem: successful request for "
- "physical address of pmem region id %d, "
- "offset 0x%lx, len 0x%lx\n",
- id, region.offset, region.len);
-
- break;
- }
- case PMEM_MAP:
- {
- struct pmem_region region;
- DLOG("map\n");
- if (copy_from_user(®ion, (void __user *)arg,
- sizeof(struct pmem_region)))
- return -EFAULT;
- return pmem_remap(®ion, file, PMEM_MAP);
- }
- break;
- case PMEM_UNMAP:
- {
- struct pmem_region region;
- DLOG("unmap\n");
- if (copy_from_user(®ion, (void __user *)arg,
- sizeof(struct pmem_region)))
- return -EFAULT;
- return pmem_remap(®ion, file, PMEM_UNMAP);
- break;
- }
- case PMEM_GET_SIZE:
- {
- struct pmem_region region;
- DLOG("get_size\n");
- pmem_get_size(®ion, file);
- if (copy_to_user((void __user *)arg, ®ion,
- sizeof(struct pmem_region)))
- return -EFAULT;
- break;
- }
- case PMEM_GET_TOTAL_SIZE:
- {
- struct pmem_region region;
- DLOG("get total size\n");
- region.offset = 0;
- get_id(file);
- region.len = pmem[id].size;
- if (copy_to_user((void __user *)arg, ®ion,
- sizeof(struct pmem_region)))
- return -EFAULT;
- break;
- }
- case PMEM_GET_FREE_SPACE:
- {
- struct pmem_freespace fs;
- DLOG("get freespace on %s(id: %d)\n",
- get_name(file), id);
-
- mutex_lock(&pmem[id].arena_mutex);
- pmem[id].free_space(id, &fs);
- mutex_unlock(&pmem[id].arena_mutex);
-
- DLOG("%s(id: %d) total free %lu, largest %lu\n",
- get_name(file), id, fs.total, fs.largest);
-
- if (copy_to_user((void __user *)arg, &fs,
- sizeof(struct pmem_freespace)))
- return -EFAULT;
- break;
- }
-
- case PMEM_ALLOCATE:
- {
- int ret = 0;
- DLOG("allocate, id %d\n", id);
- down_write(&data->sem);
- if (has_allocation(file)) {
- pr_err("pmem: Existing allocation found on "
- "this file descrpitor\n");
- up_write(&data->sem);
- return -EINVAL;
- }
-
- mutex_lock(&pmem[id].arena_mutex);
- data->index = pmem_allocate_from_id(id,
- arg,
- SZ_4K);
- mutex_unlock(&pmem[id].arena_mutex);
- ret = data->index == -1 ? -ENOMEM :
- data->index;
- up_write(&data->sem);
- return ret;
- }
- case PMEM_ALLOCATE_ALIGNED:
- {
- struct pmem_allocation alloc;
- int ret = 0;
-
- if (copy_from_user(&alloc, (void __user *)arg,
- sizeof(struct pmem_allocation)))
- return -EFAULT;
- DLOG("allocate id align %d %u\n", id, alloc.align);
- down_write(&data->sem);
- if (has_allocation(file)) {
- pr_err("pmem: Existing allocation found on "
- "this file descrpitor\n");
- up_write(&data->sem);
- return -EINVAL;
- }
-
- if (alloc.align & (alloc.align - 1)) {
- pr_err("pmem: Alignment is not a power of 2\n");
- return -EINVAL;
- }
-
- if (alloc.align != SZ_4K &&
- (pmem[id].allocator_type !=
- PMEM_ALLOCATORTYPE_BITMAP)) {
- pr_err("pmem: Non 4k alignment requires bitmap"
- " allocator on %s\n", pmem[id].name);
- return -EINVAL;
- }
-
- if (alloc.align > SZ_1M ||
- alloc.align < SZ_4K) {
- pr_err("pmem: Invalid Alignment (%u) "
- "specified\n", alloc.align);
- return -EINVAL;
- }
-
- mutex_lock(&pmem[id].arena_mutex);
- data->index = pmem_allocate_from_id(id,
- alloc.size,
- alloc.align);
- mutex_unlock(&pmem[id].arena_mutex);
- ret = data->index == -1 ? -ENOMEM :
- data->index;
- up_write(&data->sem);
- return ret;
- }
- case PMEM_CONNECT:
- DLOG("connect\n");
- return pmem_connect(arg, file);
- case PMEM_CLEAN_INV_CACHES:
- case PMEM_CLEAN_CACHES:
- case PMEM_INV_CACHES:
- {
- struct pmem_addr pmem_addr;
-
- if (copy_from_user(&pmem_addr, (void __user *)arg,
- sizeof(struct pmem_addr)))
- return -EFAULT;
-
- return pmem_cache_maint(file, cmd, &pmem_addr);
- }
- default:
- if (pmem[id].ioctl)
- return pmem[id].ioctl(file, cmd, arg);
-
- DLOG("ioctl invalid (%#x)\n", cmd);
- return -EINVAL;
- }
- return 0;
-}
-
-static void ioremap_pmem(int id)
-{
- unsigned long addr;
- const struct mem_type *type;
-
- DLOG("PMEMDEBUG: ioremaping for %s\n", pmem[id].name);
- if (pmem[id].map_on_demand) {
- addr = (unsigned long)pmem[id].area->addr;
- if (pmem[id].cached)
- type = get_mem_type(MT_DEVICE_CACHED);
- else
- type = get_mem_type(MT_DEVICE);
- DLOG("PMEMDEBUG: Remap phys %lx to virt %lx on %s\n",
- pmem[id].base, addr, pmem[id].name);
- if (ioremap_pages(addr, pmem[id].base, pmem[id].size, type)) {
- pr_err("pmem: Failed to map pages\n");
- BUG();
- }
- pmem[id].vbase = pmem[id].area->addr;
- /* Flush the cache after installing page table entries to avoid
- * aliasing when these pages are remapped to user space.
- */
- flush_cache_vmap(addr, addr + pmem[id].size);
- } else {
- if (pmem[id].cached)
- pmem[id].vbase = ioremap_cached(pmem[id].base,
- pmem[id].size);
- #ifdef ioremap_ext_buffered
- else if (pmem[id].buffered)
- pmem[id].vbase = ioremap_ext_buffered(pmem[id].base,
- pmem[id].size);
- #endif
- else
- pmem[id].vbase = ioremap(pmem[id].base, pmem[id].size);
- }
-}
-
-int pmem_setup(struct android_pmem_platform_data *pdata,
- long (*ioctl)(struct file *, unsigned int, unsigned long),
- int (*release)(struct inode *, struct file *))
-{
- int i, index = 0, id;
- struct vm_struct *pmem_vma = NULL;
- struct page *page;
-
- if (id_count >= PMEM_MAX_DEVICES) {
- pr_alert("pmem: %s: unable to register driver(%s) - no more "
- "devices available!\n", __func__, pdata->name);
- goto err_no_mem;
- }
-
- if (!pdata->size) {
- pr_alert("pmem: %s: unable to register pmem driver(%s) - zero "
- "size passed in!\n", __func__, pdata->name);
- goto err_no_mem;
- }
-
- id = id_count++;
-
- pmem[id].id = id;
-
- if (pmem[id].allocate) {
- pr_alert("pmem: %s: unable to register pmem driver - "
- "duplicate registration of %s!\n",
- __func__, pdata->name);
- goto err_no_mem;
- }
-
- pmem[id].allocator_type = pdata->allocator_type;
-
- /* 'quantum' is a "hidden" variable that defaults to 0 in the board
- * files */
- pmem[id].quantum = pdata->quantum ?: PMEM_MIN_ALLOC;
- if (pmem[id].quantum < PMEM_MIN_ALLOC ||
- !is_power_of_2(pmem[id].quantum)) {
- pr_alert("pmem: %s: unable to register pmem driver %s - "
- "invalid quantum value (%#x)!\n",
- __func__, pdata->name, pmem[id].quantum);
- goto err_reset_pmem_info;
- }
-
- if (pdata->size % pmem[id].quantum) {
- /* bad alignment for size! */
- pr_alert("pmem: %s: Unable to register driver %s - "
- "memory region size (%#lx) is not a multiple of "
- "quantum size(%#x)!\n", __func__, pdata->name,
- pdata->size, pmem[id].quantum);
- goto err_reset_pmem_info;
- }
-
- pmem[id].cached = pdata->cached;
- pmem[id].buffered = pdata->buffered;
- pmem[id].size = pdata->size;
- pmem[id].memory_type = pdata->memory_type;
- strlcpy(pmem[id].name, pdata->name, PMEM_NAME_SIZE);
-
- pmem[id].num_entries = pmem[id].size / pmem[id].quantum;
-
- memset(&pmem[id].kobj, 0, sizeof(pmem[0].kobj));
- pmem[id].kobj.kset = pmem_kset;
-
- switch (pmem[id].allocator_type) {
- case PMEM_ALLOCATORTYPE_ALLORNOTHING:
- pmem[id].allocate = pmem_allocator_all_or_nothing;
- pmem[id].free = pmem_free_all_or_nothing;
- pmem[id].free_space = pmem_free_space_all_or_nothing;
- pmem[id].len = pmem_len_all_or_nothing;
- pmem[id].start_addr = pmem_start_addr_all_or_nothing;
- pmem[id].num_entries = 1;
- pmem[id].quantum = pmem[id].size;
- pmem[id].allocator.all_or_nothing.allocated = 0;
-
- if (kobject_init_and_add(&pmem[id].kobj,
- &pmem_allornothing_ktype, NULL,
- "%s", pdata->name))
- goto out_put_kobj;
-
- break;
-
- case PMEM_ALLOCATORTYPE_BUDDYBESTFIT:
- pmem[id].allocator.buddy_bestfit.buddy_bitmap = kmalloc(
- pmem[id].num_entries * sizeof(struct pmem_bits),
- GFP_KERNEL);
- if (!pmem[id].allocator.buddy_bestfit.buddy_bitmap)
- goto err_reset_pmem_info;
-
- memset(pmem[id].allocator.buddy_bestfit.buddy_bitmap, 0,
- sizeof(struct pmem_bits) * pmem[id].num_entries);
-
- for (i = sizeof(pmem[id].num_entries) * 8 - 1; i >= 0; i--)
- if ((pmem[id].num_entries) & 1<<i) {
- PMEM_BUDDY_ORDER(id, index) = i;
- index = PMEM_BUDDY_NEXT_INDEX(id, index);
- }
- pmem[id].allocate = pmem_allocator_buddy_bestfit;
- pmem[id].free = pmem_free_buddy_bestfit;
- pmem[id].free_space = pmem_free_space_buddy_bestfit;
- pmem[id].len = pmem_len_buddy_bestfit;
- pmem[id].start_addr = pmem_start_addr_buddy_bestfit;
- if (kobject_init_and_add(&pmem[id].kobj,
- &pmem_buddy_bestfit_ktype, NULL,
- "%s", pdata->name))
- goto out_put_kobj;
-
- break;
-
- case PMEM_ALLOCATORTYPE_BITMAP: /* 0, default if not explicit */
- pmem[id].allocator.bitmap.bitm_alloc = kmalloc(
- PMEM_INITIAL_NUM_BITMAP_ALLOCATIONS *
- sizeof(*pmem[id].allocator.bitmap.bitm_alloc),
- GFP_KERNEL);
- if (!pmem[id].allocator.bitmap.bitm_alloc) {
- pr_alert("pmem: %s: Unable to register pmem "
- "driver %s - can't allocate "
- "bitm_alloc!\n",
- __func__, pdata->name);
- goto err_reset_pmem_info;
- }
-
- if (kobject_init_and_add(&pmem[id].kobj,
- &pmem_bitmap_ktype, NULL,
- "%s", pdata->name))
- goto out_put_kobj;
-
- for (i = 0; i < PMEM_INITIAL_NUM_BITMAP_ALLOCATIONS; i++) {
- pmem[id].allocator.bitmap.bitm_alloc[i].bit = -1;
- pmem[id].allocator.bitmap.bitm_alloc[i].quanta = 0;
- }
-
- pmem[id].allocator.bitmap.bitmap_allocs =
- PMEM_INITIAL_NUM_BITMAP_ALLOCATIONS;
-
- pmem[id].allocator.bitmap.bitmap =
- kcalloc((pmem[id].num_entries + 31) / 32,
- sizeof(unsigned int), GFP_KERNEL);
- if (!pmem[id].allocator.bitmap.bitmap) {
- pr_alert("pmem: %s: Unable to register pmem "
- "driver - can't allocate bitmap!\n",
- __func__);
- goto err_cant_register_device;
- }
- pmem[id].allocator.bitmap.bitmap_free = pmem[id].num_entries;
-
- pmem[id].allocate = pmem_allocator_bitmap;
- pmem[id].free = pmem_free_bitmap;
- pmem[id].free_space = pmem_free_space_bitmap;
- pmem[id].len = pmem_len_bitmap;
- pmem[id].start_addr = pmem_start_addr_bitmap;
-
- DLOG("bitmap allocator id %d (%s), num_entries %u, raw size "
- "%lu, quanta size %u\n",
- id, pdata->name, pmem[id].allocator.bitmap.bitmap_free,
- pmem[id].size, pmem[id].quantum);
- break;
-
- case PMEM_ALLOCATORTYPE_SYSTEM:
-
- INIT_LIST_HEAD(&pmem[id].allocator.system_mem.alist);
-
- pmem[id].allocator.system_mem.used = 0;
- pmem[id].vbase = NULL;
-
- if (kobject_init_and_add(&pmem[id].kobj,
- &pmem_system_ktype, NULL,
- "%s", pdata->name))
- goto out_put_kobj;
-
- pmem[id].allocate = pmem_allocator_system;
- pmem[id].free = pmem_free_system;
- pmem[id].free_space = pmem_free_space_system;
- pmem[id].len = pmem_len_system;
- pmem[id].start_addr = pmem_start_addr_system;
- pmem[id].num_entries = 0;
- pmem[id].quantum = PAGE_SIZE;
-
- DLOG("system allocator id %d (%s), raw size %lu\n",
- id, pdata->name, pmem[id].size);
- break;
-
- default:
- pr_alert("Invalid allocator type (%d) for pmem driver\n",
- pdata->allocator_type);
- goto err_reset_pmem_info;
- }
-
- pmem[id].ioctl = ioctl;
- pmem[id].release = release;
- mutex_init(&pmem[id].arena_mutex);
- mutex_init(&pmem[id].data_list_mutex);
- INIT_LIST_HEAD(&pmem[id].data_list);
-
- pmem[id].dev.name = pdata->name;
- pmem[id].dev.minor = id;
- pmem[id].dev.fops = &pmem_fops;
- pmem[id].reusable = pdata->reusable;
- pr_info("pmem: Initializing %s as %s\n",
- pdata->name, pdata->cached ? "cached" : "non-cached");
-
- if (misc_register(&pmem[id].dev)) {
- pr_alert("Unable to register pmem driver!\n");
- goto err_cant_register_device;
- }
-
- if (!pmem[id].reusable) {
- pmem[id].base = allocate_contiguous_memory_nomap(pmem[id].size,
- pmem[id].memory_type, PAGE_SIZE);
- if (!pmem[id].base) {
- pr_err("pmem: Cannot allocate from reserved memory for %s\n",
- pdata->name);
- goto err_misc_deregister;
- }
- }
-
- /* reusable pmem requires map on demand */
- pmem[id].map_on_demand = pdata->map_on_demand || pdata->reusable;
- if (pmem[id].map_on_demand) {
- if (pmem[id].reusable) {
- const struct fmem_data *fmem_info = fmem_get_info();
- pmem[id].area = fmem_info->area;
- pmem[id].base = fmem_info->phys;
- } else {
- pmem_vma = get_vm_area(pmem[id].size, VM_IOREMAP);
- if (!pmem_vma) {
- pr_err("pmem: Failed to allocate virtual space for "
- "%s\n", pdata->name);
- goto err_free;
- }
- pr_err("pmem: Reserving virtual address range %lx - %lx for"
- " %s\n", (unsigned long) pmem_vma->addr,
- (unsigned long) pmem_vma->addr + pmem[id].size,
- pdata->name);
- pmem[id].area = pmem_vma;
- }
- } else
- pmem[id].area = NULL;
-
- page = alloc_page(GFP_KERNEL);
- if (!page) {
- pr_err("pmem: Failed to allocate page for %s\n", pdata->name);
- goto cleanup_vm;
- }
- pmem[id].garbage_pfn = page_to_pfn(page);
- atomic_set(&pmem[id].allocation_cnt, 0);
-
- if (pdata->setup_region)
- pmem[id].region_data = pdata->setup_region();
-
- if (pdata->request_region)
- pmem[id].mem_request = pdata->request_region;
-
- if (pdata->release_region)
- pmem[id].mem_release = pdata->release_region;
-
- pr_info("allocating %lu bytes at %lx physical for %s\n",
- pmem[id].size, pmem[id].base, pmem[id].name);
-
- return 0;
-
-cleanup_vm:
- if (!pmem[id].reusable)
- remove_vm_area(pmem_vma);
-err_free:
- if (!pmem[id].reusable)
- free_contiguous_memory_by_paddr(pmem[id].base);
-err_misc_deregister:
- misc_deregister(&pmem[id].dev);
-err_cant_register_device:
-out_put_kobj:
- kobject_put(&pmem[id].kobj);
- if (pmem[id].allocator_type == PMEM_ALLOCATORTYPE_BUDDYBESTFIT)
- kfree(pmem[id].allocator.buddy_bestfit.buddy_bitmap);
- else if (pmem[id].allocator_type == PMEM_ALLOCATORTYPE_BITMAP) {
- kfree(pmem[id].allocator.bitmap.bitmap);
- kfree(pmem[id].allocator.bitmap.bitm_alloc);
- }
-err_reset_pmem_info:
- pmem[id].allocate = 0;
- pmem[id].dev.minor = -1;
-err_no_mem:
- return -1;
-}
-
-static int pmem_probe(struct platform_device *pdev)
-{
- struct android_pmem_platform_data *pdata;
-
- if (!pdev || !pdev->dev.platform_data) {
- pr_alert("Unable to probe pmem!\n");
- return -1;
- }
- pdata = pdev->dev.platform_data;
-
- pm_runtime_set_active(&pdev->dev);
- pm_runtime_enable(&pdev->dev);
-
- return pmem_setup(pdata, NULL, NULL);
-}
-
-static int pmem_remove(struct platform_device *pdev)
-{
- int id = pdev->id;
- __free_page(pfn_to_page(pmem[id].garbage_pfn));
- pm_runtime_disable(&pdev->dev);
- if (pmem[id].vbase)
- iounmap(pmem[id].vbase);
- if (pmem[id].map_on_demand && !pmem[id].reusable && pmem[id].area)
- free_vm_area(pmem[id].area);
- if (pmem[id].base)
- free_contiguous_memory_by_paddr(pmem[id].base);
- kobject_put(&pmem[id].kobj);
- if (pmem[id].allocator_type == PMEM_ALLOCATORTYPE_BUDDYBESTFIT)
- kfree(pmem[id].allocator.buddy_bestfit.buddy_bitmap);
- else if (pmem[id].allocator_type == PMEM_ALLOCATORTYPE_BITMAP) {
- kfree(pmem[id].allocator.bitmap.bitmap);
- kfree(pmem[id].allocator.bitmap.bitm_alloc);
- }
- misc_deregister(&pmem[id].dev);
- return 0;
-}
-
-static int pmem_runtime_suspend(struct device *dev)
-{
- dev_dbg(dev, "pm_runtime: suspending...\n");
- return 0;
-}
-
-static int pmem_runtime_resume(struct device *dev)
-{
- dev_dbg(dev, "pm_runtime: resuming...\n");
- return 0;
-}
-
-static const struct dev_pm_ops pmem_dev_pm_ops = {
- .runtime_suspend = pmem_runtime_suspend,
- .runtime_resume = pmem_runtime_resume,
-};
-
-static struct platform_driver pmem_driver = {
- .probe = pmem_probe,
- .remove = pmem_remove,
- .driver = { .name = "android_pmem",
- .pm = &pmem_dev_pm_ops,
- }
-};
-
-
-static int __init pmem_init(void)
-{
- /* create /sys/kernel/<PMEM_SYSFS_DIR_NAME> directory */
- pmem_kset = kset_create_and_add(PMEM_SYSFS_DIR_NAME,
- NULL, kernel_kobj);
- if (!pmem_kset) {
- pr_err("pmem(%s):kset_create_and_add fail\n", __func__);
- return -ENOMEM;
- }
-
- return platform_driver_register(&pmem_driver);
-}
-
-static void __exit pmem_exit(void)
-{
- platform_driver_unregister(&pmem_driver);
-}
-
-module_init(pmem_init);
-module_exit(pmem_exit);
-
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 9f12142..21e65b9 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -228,6 +228,7 @@
md = mmc_blk_get(dev_to_disk(dev));
card = md->queue.card;
+ mmc_rpm_hold(card->host, &card->dev);
mmc_claim_host(card->host);
ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_WP,
@@ -240,6 +241,7 @@
card->ext_csd.boot_ro_lock |= EXT_CSD_BOOT_WP_B_PWR_WP_EN;
mmc_release_host(card->host);
+ mmc_rpm_release(card->host, &card->dev);
if (!ret) {
pr_info("%s: Locking boot partition ro until next power on\n",
@@ -602,7 +604,7 @@
md = mmc_blk_get(bdev->bd_disk);
if (!md) {
err = -EINVAL;
- goto cmd_done;
+ goto blk_err;
}
card = md->queue.card;
@@ -707,6 +709,7 @@
cmd_done:
mmc_blk_put(md);
+blk_err:
kfree(idata->buf);
kfree(idata);
return err;
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 73a1b41..9fc599b 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -2864,6 +2864,40 @@
return ret;
}
+static int mmc_clk_update_freq(struct mmc_host *host,
+ unsigned long freq, enum mmc_load state)
+{
+ int err = 0;
+
+ if (host->ops->notify_load) {
+ err = host->ops->notify_load(host, state);
+ if (err)
+ goto out;
+ }
+
+ if (freq != host->clk_scaling.curr_freq) {
+ if (!mmc_is_vaild_state_for_clk_scaling(host)) {
+ err = -EAGAIN;
+ goto error;
+ }
+
+ err = host->bus_ops->change_bus_speed(host, &freq);
+ if (!err)
+ host->clk_scaling.curr_freq = freq;
+ else
+ pr_err("%s: %s: failed (%d) at freq=%lu\n",
+ mmc_hostname(host), __func__, err, freq);
+ }
+error:
+ if (err) {
+ /* restore previous state */
+ if (host->ops->notify_load)
+ host->ops->notify_load(host, host->clk_scaling.state);
+ }
+out:
+ return err;
+}
+
/**
* mmc_clk_scaling() - clock scaling decision algorithm
* @host: pointer to mmc host structure
@@ -2889,6 +2923,7 @@
unsigned int up_threshold = host->clk_scaling.up_threshold;
unsigned int down_threshold = host->clk_scaling.down_threshold;
bool queue_scale_down_work = false;
+ enum mmc_load state;
if (!card || !host->bus_ops || !host->bus_ops->change_bus_speed) {
pr_err("%s: %s: invalid entry\n", mmc_hostname(host), __func__);
@@ -2916,6 +2951,7 @@
busy_time_ms = host->clk_scaling.busy_time_us / USEC_PER_MSEC;
freq = host->clk_scaling.curr_freq;
+ state = host->clk_scaling.state;
/*
* Note that the max. and min. frequency should be based
@@ -2924,28 +2960,24 @@
*/
if ((busy_time_ms * 100 > total_time_ms * up_threshold)) {
freq = mmc_get_max_frequency(host);
+ state = MMC_LOAD_HIGH;
} else if ((busy_time_ms * 100 < total_time_ms * down_threshold)) {
if (!from_wq)
queue_scale_down_work = true;
freq = mmc_get_min_frequency(host);
+ state = MMC_LOAD_LOW;
}
- if (freq != host->clk_scaling.curr_freq) {
+ if (state != host->clk_scaling.state) {
if (!queue_scale_down_work) {
if (!from_wq)
cancel_delayed_work_sync(
&host->clk_scaling.work);
-
- if (!mmc_is_vaild_state_for_clk_scaling(host))
- goto bypass_scaling;
-
- err = host->bus_ops->change_bus_speed(host, &freq);
+ err = mmc_clk_update_freq(host, freq, state);
if (!err)
- host->clk_scaling.curr_freq = freq;
- else
- pr_err("%s: %s: failed (%d) at freq=%lu\n",
- mmc_hostname(host), __func__, err,
- freq);
+ host->clk_scaling.state = state;
+ else if (err == -EAGAIN)
+ goto no_reset_stats;
} else {
/*
* We hold claim host while queueing the scale down
@@ -2954,13 +2986,12 @@
*/
queue_delayed_work(system_nrt_wq,
&host->clk_scaling.work, 1);
- host->clk_scaling.in_progress = false;
- goto out;
+ goto no_reset_stats;
}
}
mmc_reset_clk_scale_stats(host);
-bypass_scaling:
+no_reset_stats:
host->clk_scaling.in_progress = false;
out:
return;
@@ -3007,6 +3038,9 @@
INIT_DELAYED_WORK(&host->clk_scaling.work, mmc_clk_scale_work);
host->clk_scaling.curr_freq = mmc_get_max_frequency(host);
+ if (host->ops->notify_load)
+ host->ops->notify_load(host, MMC_LOAD_HIGH);
+ host->clk_scaling.state = MMC_LOAD_HIGH;
mmc_reset_clk_scale_stats(host);
host->clk_scaling.enable = true;
host->clk_scaling.initialized = true;
diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
index 8b7e0bd..903decf 100644
--- a/drivers/mmc/core/debugfs.c
+++ b/drivers/mmc/core/debugfs.c
@@ -176,9 +176,11 @@
if (val > host->f_max)
return -EINVAL;
+ mmc_rpm_hold(host, &host->class_dev);
mmc_claim_host(host);
mmc_set_clock(host, (unsigned int) val);
mmc_release_host(host);
+ mmc_rpm_release(host, &host->class_dev);
return 0;
}
@@ -208,6 +210,7 @@
if (!host || (val < host->f_min))
goto out;
+ mmc_rpm_hold(host, &host->class_dev);
mmc_claim_host(host);
if (host->bus_ops && host->bus_ops->change_bus_speed) {
old_freq = host->f_max;
@@ -219,6 +222,7 @@
host->f_max = old_freq;
}
mmc_release_host(host);
+ mmc_rpm_release(host, &host->class_dev);
out:
return err;
}
@@ -286,6 +290,7 @@
u32 status;
int ret;
+ mmc_rpm_hold(card->host, &card->dev);
mmc_claim_host(card->host);
ret = mmc_send_status(data, &status);
@@ -293,6 +298,7 @@
*val = status;
mmc_release_host(card->host);
+ mmc_rpm_release(card->host, &card->dev);
return ret;
}
@@ -319,9 +325,11 @@
goto out_free;
}
+ mmc_rpm_hold(card->host, &card->dev);
mmc_claim_host(card->host);
err = mmc_send_ext_csd(card, ext_csd);
mmc_release_host(card->host);
+ mmc_rpm_release(card->host, &card->dev);
if (err)
goto out_free;
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index c0a4cef..6c03bfc 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -466,12 +466,8 @@
goto err;
if (value && !mmc_can_scale_clk(host)) {
- if (mmc_card_ddr_mode(host->card) ||
- mmc_card_hs200(host->card) ||
- mmc_card_uhs(host->card)) {
- host->caps2 |= MMC_CAP2_CLK_SCALE;
- mmc_init_clk_scaling(host);
- }
+ host->caps2 |= MMC_CAP2_CLK_SCALE;
+ mmc_init_clk_scaling(host);
if (!mmc_can_scale_clk(host)) {
host->caps2 &= ~MMC_CAP2_CLK_SCALE;
@@ -487,6 +483,10 @@
if (host->bus_ops->change_bus_speed(host, &freq))
goto err;
}
+ if (host->ops->notify_load &&
+ host->ops->notify_load(host, MMC_LOAD_HIGH))
+ goto err;
+ host->clk_scaling.state = MMC_LOAD_HIGH;
host->clk_scaling.initialized = false;
}
retval = count;
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 8a866cf..89f8c91 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1734,9 +1734,7 @@
if (err)
goto remove_card;
- /* Initialize clock scaling only for high frequency modes */
- if (mmc_card_hs200(host->card) || mmc_card_ddr_mode(host->card))
- mmc_init_clk_scaling(host);
+ mmc_init_clk_scaling(host);
return 0;
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 60e0640..ddf9a87 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -1415,9 +1415,7 @@
if (err)
goto remove_card;
- /* Initialize clock scaling only for high frequency modes */
- if (mmc_card_uhs(host->card))
- mmc_init_clk_scaling(host);
+ mmc_init_clk_scaling(host);
return 0;
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index 3f3687b..caf5fe4 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -958,7 +958,7 @@
struct msmsdcc_nc_dmadata *nc;
dmov_box *box;
uint32_t rows;
- unsigned int n;
+ int n;
int i, err = 0, box_cmd_cnt = 0;
struct scatterlist *sg = data->sg;
unsigned int len, offset;
@@ -4393,6 +4393,39 @@
return data_cnt;
}
+static int msmsdcc_notify_load(struct mmc_host *mmc, enum mmc_load state)
+{
+ int err = 0;
+ unsigned long rate;
+ struct msmsdcc_host *host = mmc_priv(mmc);
+
+ if (IS_ERR_OR_NULL(host->bus_clk))
+ goto out;
+
+ switch (state) {
+ case MMC_LOAD_HIGH:
+ rate = MSMSDCC_BUS_VOTE_MAX_RATE;
+ break;
+ case MMC_LOAD_LOW:
+ rate = MSMSDCC_BUS_VOTE_MIN_RATE;
+ break;
+ default:
+ err = -EINVAL;
+ goto out;
+ }
+
+ if (rate != host->bus_clk_rate) {
+ err = clk_set_rate(host->bus_clk, rate);
+ if (err)
+ pr_err("%s: %s: bus clk set rate %lu Hz err %d\n",
+ mmc_hostname(mmc), __func__, rate, err);
+ else
+ host->bus_clk_rate = rate;
+ }
+out:
+ return err;
+}
+
static const struct mmc_host_ops msmsdcc_ops = {
.enable = msmsdcc_enable,
.disable = msmsdcc_disable,
@@ -4407,6 +4440,7 @@
.hw_reset = msmsdcc_hw_reset,
.stop_request = msmsdcc_stop_request,
.get_xfer_remain = msmsdcc_get_xfer_remain,
+ .notify_load = msmsdcc_notify_load,
};
static void msmsdcc_enable_status_gpio(struct msmsdcc_host *host)
@@ -5975,12 +6009,13 @@
host->bus_clk = clk_get(&pdev->dev, "bus_clk");
if (!IS_ERR_OR_NULL(host->bus_clk)) {
/* Vote for max. clk rate for max. performance */
- ret = clk_set_rate(host->bus_clk, INT_MAX);
+ ret = clk_set_rate(host->bus_clk, MSMSDCC_BUS_VOTE_MAX_RATE);
if (ret)
goto bus_clk_put;
ret = clk_prepare_enable(host->bus_clk);
if (ret)
goto bus_clk_put;
+ host->bus_clk_rate = MSMSDCC_BUS_VOTE_MAX_RATE;
}
/*
diff --git a/drivers/mmc/host/msm_sdcc.h b/drivers/mmc/host/msm_sdcc.h
index 4ed2d96..bcfde57 100644
--- a/drivers/mmc/host/msm_sdcc.h
+++ b/drivers/mmc/host/msm_sdcc.h
@@ -260,6 +260,12 @@
#define MMC_MAX_DMA_CMDS (MAX_NR_SG_DMA_PIO * (MMC_MAX_REQ_SIZE / \
MMC_MAX_DMA_BOX_LENGTH))
+/*
+ * Peripheral bus clock scaling vote rates
+ */
+#define MSMSDCC_BUS_VOTE_MAX_RATE 64000000 /* Hz */
+#define MSMSDCC_BUS_VOTE_MIN_RATE 32000000 /* Hz */
+
struct clk;
struct msmsdcc_nc_dmadata {
@@ -360,6 +366,7 @@
struct clk *clk; /* main MMC bus clock */
struct clk *pclk; /* SDCC peripheral bus clock */
struct clk *bus_clk; /* SDCC bus voter clock */
+ unsigned long bus_clk_rate; /* peripheral bus clk rate */
atomic_t clks_on; /* set if clocks are enabled */
unsigned int eject; /* eject state */
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 15e36a8..89730b0 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -2137,6 +2137,7 @@
int ret = 0, dead = 0;
u32 vdd_max_current;
u16 host_version;
+ u32 pwr;
pr_debug("%s: Enter %s\n", dev_name(&pdev->dev), __func__);
msm_host = devm_kzalloc(&pdev->dev, sizeof(struct sdhci_msm_host),
@@ -2245,7 +2246,21 @@
}
/* Set SW_RST bit in POWER register (Offset 0x0) */
- writel_relaxed(CORE_SW_RST, msm_host->core_mem + CORE_POWER);
+ writel_relaxed(readl_relaxed(msm_host->core_mem + CORE_POWER) |
+ CORE_SW_RST, msm_host->core_mem + CORE_POWER);
+ /*
+ * SW reset can take upto 10HCLK + 15MCLK cycles.
+ * Calculating based on min clk rates (hclk = 27MHz,
+ * mclk = 400KHz) it comes to ~40us. Let's poll for
+ * max. 1ms for reset completion.
+ */
+ ret = readl_poll_timeout(msm_host->core_mem + CORE_POWER,
+ pwr, !(pwr & CORE_SW_RST), 100, 10);
+
+ if (ret) {
+ dev_err(&pdev->dev, "reset failed (%d)\n", ret);
+ goto vreg_deinit;
+ }
/* Set HC_MODE_EN bit in HC_MODE register */
writel_relaxed(HC_MODE_EN, (msm_host->core_mem + CORE_HC_MODE));
diff --git a/drivers/net/ethernet/msm/ecm_ipa.c b/drivers/net/ethernet/msm/ecm_ipa.c
index 1f50e1c..3c3a62b 100644
--- a/drivers/net/ethernet/msm/ecm_ipa.c
+++ b/drivers/net/ethernet/msm/ecm_ipa.c
@@ -49,18 +49,11 @@
/**
* struct ecm_ipa_dev - main driver context parameters
* @net: network interface struct implemented by this driver
- * @folder: debugfs folder for various debuging switches
+ * @directory: debugfs directory for various debuging switches
* @tx_enable: flag that enable/disable Tx path to continue to IPA
* @rx_enable: flag that enable/disable Rx path to continue to IPA
* @rm_enable: flag that enable/disable Resource manager request prior to Tx
* @dma_enable: flag that allow on-the-fly DMA mode for IPA
- * @tx_file: saved debugfs entry to allow cleanup
- * @rx_file: saved debugfs entry to allow cleanup
- * @rm_file: saved debugfs entry to allow cleanup
- * @outstanding_file: saved debugfs entry to allow cleanup
- * @outstanding_high_file saved debugfs entry to allow cleanup
- * @outstanding_low_file saved debugfs entry to allow cleanup
- * @dma_file: saved debugfs entry to allow cleanup
* @eth_ipv4_hdr_hdl: saved handle for ipv4 header-insertion table
* @eth_ipv6_hdr_hdl: saved handle for ipv6 header-insertion table
* @usb_to_ipa_hdl: save handle for IPA pipe operations
@@ -72,18 +65,11 @@
*/
struct ecm_ipa_dev {
struct net_device *net;
- bool tx_enable;
- bool rx_enable;
- bool rm_enable;
+ u32 tx_enable;
+ u32 rx_enable;
+ u32 rm_enable;
bool dma_enable;
- struct dentry *folder;
- struct dentry *tx_file;
- struct dentry *rx_file;
- struct dentry *rm_file;
- struct dentry *outstanding_high_file;
- struct dentry *outstanding_low_file;
- struct dentry *dma_file;
- struct dentry *outstanding_file;
+ struct dentry *directory;
uint32_t eth_ipv4_hdr_hdl;
uint32_t eth_ipv6_hdr_hdl;
u32 usb_to_ipa_hdl;
@@ -127,9 +113,6 @@
static void ecm_ipa_deregister_properties(void);
static int ecm_ipa_debugfs_init(struct ecm_ipa_dev *dev);
static void ecm_ipa_debugfs_destroy(struct ecm_ipa_dev *dev);
-static int ecm_ipa_debugfs_tx_open(struct inode *inode, struct file *file);
-static int ecm_ipa_debugfs_rx_open(struct inode *inode, struct file *file);
-static int ecm_ipa_debugfs_rm_open(struct inode *inode, struct file *file);
static int ecm_ipa_debugfs_dma_open(struct inode *inode, struct file *file);
static int ecm_ipa_debugfs_atomic_open(struct inode *inode, struct file *file);
static ssize_t ecm_ipa_debugfs_enable_read(struct file *file,
@@ -149,25 +132,12 @@
.ndo_start_xmit = ecm_ipa_start_xmit,
.ndo_set_mac_address = eth_mac_addr,
};
+
static const struct ethtool_ops ops = {
.get_drvinfo = eth_get_drvinfo,
.get_link = ethtool_op_get_link,
};
-const struct file_operations ecm_ipa_debugfs_tx_ops = {
- .open = ecm_ipa_debugfs_tx_open,
- .read = ecm_ipa_debugfs_enable_read,
- .write = ecm_ipa_debugfs_enable_write,
-};
-const struct file_operations ecm_ipa_debugfs_rx_ops = {
- .open = ecm_ipa_debugfs_rx_open,
- .read = ecm_ipa_debugfs_enable_read,
- .write = ecm_ipa_debugfs_enable_write,
-};
-const struct file_operations ecm_ipa_debugfs_rm_ops = {
- .open = ecm_ipa_debugfs_rm_open,
- .read = ecm_ipa_debugfs_enable_read,
- .write = ecm_ipa_debugfs_enable_write,
-};
+
const struct file_operations ecm_ipa_debugfs_dma_ops = {
.open = ecm_ipa_debugfs_dma_open,
.read = ecm_ipa_debugfs_enable_read,
@@ -814,33 +784,6 @@
return;
}
-static int ecm_ipa_debugfs_tx_open(struct inode *inode, struct file *file)
-{
- struct ecm_ipa_dev *dev = inode->i_private;
- ECM_IPA_LOG_ENTRY();
- file->private_data = &(dev->tx_enable);
- ECM_IPA_LOG_ENTRY();
- return 0;
-}
-
-static int ecm_ipa_debugfs_rx_open(struct inode *inode, struct file *file)
-{
- struct ecm_ipa_dev *dev = inode->i_private;
- ECM_IPA_LOG_ENTRY();
- file->private_data = &(dev->rx_enable);
- ECM_IPA_LOG_EXIT();
- return 0;
-}
-
-static int ecm_ipa_debugfs_rm_open(struct inode *inode, struct file *file)
-{
- struct ecm_ipa_dev *dev = inode->i_private;
- ECM_IPA_LOG_ENTRY();
- file->private_data = &(dev->rm_enable);
- ECM_IPA_LOG_EXIT();
- return 0;
-}
-
static int ecm_ipa_debugfs_atomic_open(struct inode *inode, struct file *file)
{
struct ecm_ipa_dev *dev = inode->i_private;
@@ -935,82 +878,74 @@
static int ecm_ipa_debugfs_init(struct ecm_ipa_dev *dev)
{
- const mode_t flags = S_IRUGO | S_IWUGO;
+ const mode_t flags_read_write = S_IRUGO | S_IWUGO;
const mode_t flags_read_only = S_IRUGO;
+ struct dentry *file;
- int ret = -EINVAL;
ECM_IPA_LOG_ENTRY();
+
if (!dev)
return -EINVAL;
- dev->folder = debugfs_create_dir("ecm_ipa", NULL);
- if (!dev->folder) {
- ECM_IPA_ERROR("could not create debugfs folder entry\n");
- ret = -EFAULT;
- goto fail_folder;
- }
- dev->tx_file = debugfs_create_file("tx_enable", flags, dev->folder, dev,
- &ecm_ipa_debugfs_tx_ops);
- if (!dev->tx_file) {
- ECM_IPA_ERROR("could not create debugfs tx file\n");
- ret = -EFAULT;
- goto fail_file;
- }
- dev->rx_file = debugfs_create_file("rx_enable", flags, dev->folder, dev,
- &ecm_ipa_debugfs_rx_ops);
- if (!dev->rx_file) {
- ECM_IPA_ERROR("could not create debugfs rx file\n");
- ret = -EFAULT;
- goto fail_file;
- }
- dev->rm_file = debugfs_create_file("rm_enable", flags, dev->folder, dev,
- &ecm_ipa_debugfs_rm_ops);
- if (!dev->rm_file) {
- ECM_IPA_ERROR("could not create debugfs rm file\n");
- ret = -EFAULT;
- goto fail_file;
- }
- dev->dma_file = debugfs_create_file("dma_enable", flags, dev->folder,
- dev, &ecm_ipa_debugfs_dma_ops);
- if (!dev->dma_file) {
- ECM_IPA_ERROR("could not create debugfs dma file\n");
- ret = -EFAULT;
- goto fail_file;
- }
- dev->outstanding_high_file = debugfs_create_u8("outstanding_high",
- flags, dev->folder, &dev->outstanding_high);
- if (!dev->outstanding_high_file) {
+ dev->directory = debugfs_create_dir("ecm_ipa", NULL);
+ if (!dev->directory) {
+ ECM_IPA_ERROR("could not create debugfs directory entry\n");
+ goto fail_directory;
+ }
+ file = debugfs_create_bool("tx_enable", flags_read_write,
+ dev->directory, &dev->tx_enable);
+ if (!file) {
+ ECM_IPA_ERROR("could not create debugfs tx file\n");
+ goto fail_file;
+ }
+ file = debugfs_create_bool("rx_enable", flags_read_write,
+ dev->directory, &dev->rx_enable);
+ if (!file) {
+ ECM_IPA_ERROR("could not create debugfs rx file\n");
+ goto fail_file;
+ }
+ file = debugfs_create_bool("rm_enable", flags_read_write,
+ dev->directory, &dev->rm_enable);
+ if (!file) {
+ ECM_IPA_ERROR("could not create debugfs rm file\n");
+ goto fail_file;
+ }
+ file = debugfs_create_u8("outstanding_high", flags_read_write,
+ dev->directory, &dev->outstanding_high);
+ if (!file) {
ECM_IPA_ERROR("could not create outstanding_high file\n");
- ret = -EFAULT;
goto fail_file;
}
- dev->outstanding_low_file = debugfs_create_u8("outstanding_low",
- flags, dev->folder, &dev->outstanding_low);
- if (!dev->outstanding_low_file) {
+ file = debugfs_create_u8("outstanding_low", flags_read_write,
+ dev->directory, &dev->outstanding_low);
+ if (!file) {
ECM_IPA_ERROR("could not create outstanding_low file\n");
- ret = -EFAULT;
goto fail_file;
}
- dev->outstanding_file = debugfs_create_file("outstanding",
- flags_read_only, dev->folder, dev,
- &ecm_ipa_debugfs_atomic_ops);
- if (!dev->outstanding_file) {
+ file = debugfs_create_file("dma_enable", flags_read_write,
+ dev->directory, dev, &ecm_ipa_debugfs_dma_ops);
+ if (!file) {
+ ECM_IPA_ERROR("could not create debugfs dma file\n");
+ goto fail_file;
+ }
+ file = debugfs_create_file("outstanding", flags_read_only,
+ dev->directory, dev, &ecm_ipa_debugfs_atomic_ops);
+ if (!file) {
ECM_IPA_ERROR("could not create outstanding file\n");
- ret = -EFAULT;
goto fail_file;
}
ECM_IPA_LOG_EXIT();
return 0;
fail_file:
- debugfs_remove_recursive(dev->folder);
-fail_folder:
- return ret;
+ debugfs_remove_recursive(dev->directory);
+fail_directory:
+ return -EFAULT;
}
static void ecm_ipa_debugfs_destroy(struct ecm_ipa_dev *dev)
{
- debugfs_remove_recursive(dev->folder);
+ debugfs_remove_recursive(dev->directory);
}
static void eth_get_drvinfo(struct net_device *net,
diff --git a/drivers/platform/msm/ipa/a2_service.c b/drivers/platform/msm/ipa/a2_service.c
index 1b33dc0..26353ec 100644
--- a/drivers/platform/msm/ipa/a2_service.c
+++ b/drivers/platform/msm/ipa/a2_service.c
@@ -86,8 +86,10 @@
struct list_head bam_tx_pool;
spinlock_t bam_tx_pool_spinlock;
struct workqueue_struct *a2_mux_tx_workqueue;
+ struct workqueue_struct *a2_mux_rx_workqueue;
int a2_mux_initialized;
bool bam_is_connected;
+ bool bam_connect_in_progress;
int a2_mux_send_power_vote_on_init_once;
int a2_mux_sw_bridge_is_connected;
u32 a2_device_handle;
@@ -237,7 +239,6 @@
INIT_COMPLETION(a2_mux_ctx->ul_wakeup_ack_completion);
power_vote(0);
}
- a2_mux_ctx->bam_is_connected = false;
}
static void ul_wakeup(void)
@@ -245,7 +246,8 @@
int ret;
mutex_lock(&a2_mux_ctx->wakeup_lock);
- if (a2_mux_ctx->bam_is_connected) {
+ if (a2_mux_ctx->bam_is_connected &&
+ !a2_mux_ctx->bam_connect_in_progress) {
IPADBG("%s Already awake\n", __func__);
mutex_unlock(&a2_mux_ctx->wakeup_lock);
return;
@@ -259,7 +261,6 @@
grab_wakelock();
else
a2_mux_ctx->a2_pc_disabled_wakelock_skipped = 1;
- a2_mux_ctx->bam_is_connected = true;
mutex_unlock(&a2_mux_ctx->wakeup_lock);
return;
}
@@ -298,7 +299,6 @@
goto bail;
}
}
- a2_mux_ctx->bam_is_connected = true;
IPADBG("%s complete\n", __func__);
mutex_unlock(&a2_mux_ctx->wakeup_lock);
return;
@@ -367,26 +367,82 @@
dev_kfree_skb_any(skb);
}
+static bool msm_bam_dmux_kickoff_ul_power_down(void)
+
+{
+ bool is_connected;
+
+ write_lock(&a2_mux_ctx->ul_wakeup_lock);
+ if (a2_mux_ctx->bam_connect_in_progress) {
+ a2_mux_ctx->bam_is_connected = false;
+ is_connected = true;
+ } else {
+ is_connected = a2_mux_ctx->bam_is_connected;
+ a2_mux_ctx->bam_is_connected = false;
+ if (is_connected) {
+ a2_mux_ctx->bam_connect_in_progress = true;
+ queue_work(a2_mux_ctx->a2_mux_tx_workqueue,
+ &a2_mux_ctx->kickoff_ul_power_down);
+ }
+ }
+ write_unlock(&a2_mux_ctx->ul_wakeup_lock);
+ return is_connected;
+}
+
+static bool msm_bam_dmux_kickoff_ul_wakeup(void)
+{
+ bool is_connected;
+
+ write_lock(&a2_mux_ctx->ul_wakeup_lock);
+ if (a2_mux_ctx->bam_connect_in_progress) {
+ a2_mux_ctx->bam_is_connected = true;
+ is_connected = false;
+ } else {
+ is_connected = a2_mux_ctx->bam_is_connected;
+ a2_mux_ctx->bam_is_connected = true;
+ if (!is_connected) {
+ a2_mux_ctx->bam_connect_in_progress = true;
+ queue_work(a2_mux_ctx->a2_mux_tx_workqueue,
+ &a2_mux_ctx->kickoff_ul_wakeup);
+ }
+ }
+ write_unlock(&a2_mux_ctx->ul_wakeup_lock);
+ return is_connected;
+}
+
static void kickoff_ul_power_down_func(struct work_struct *work)
{
- unsigned long flags;
+ bool is_connected;
- write_lock_irqsave(&a2_mux_ctx->ul_wakeup_lock, flags);
- if (a2_mux_ctx->bam_is_connected) {
- IPADBG("%s: UL active - forcing powerdown\n", __func__);
- ul_powerdown();
- }
- write_unlock_irqrestore(&a2_mux_ctx->ul_wakeup_lock, flags);
- ipa_rm_notify_completion(IPA_RM_RESOURCE_RELEASED,
- IPA_RM_RESOURCE_A2_CONS);
+ IPADBG("%s: UL active - forcing powerdown\n", __func__);
+ ul_powerdown();
+ write_lock(&a2_mux_ctx->ul_wakeup_lock);
+ is_connected = a2_mux_ctx->bam_is_connected;
+ a2_mux_ctx->bam_is_connected = false;
+ a2_mux_ctx->bam_connect_in_progress = false;
+ write_unlock(&a2_mux_ctx->ul_wakeup_lock);
+ if (is_connected)
+ msm_bam_dmux_kickoff_ul_wakeup();
+ else
+ ipa_rm_notify_completion(IPA_RM_RESOURCE_RELEASED,
+ IPA_RM_RESOURCE_A2_CONS);
}
static void kickoff_ul_wakeup_func(struct work_struct *work)
{
- if (!a2_mux_ctx->bam_is_connected)
- ul_wakeup();
- ipa_rm_notify_completion(IPA_RM_RESOURCE_GRANTED,
+ bool is_connected;
+
+ ul_wakeup();
+ write_lock(&a2_mux_ctx->ul_wakeup_lock);
+ is_connected = a2_mux_ctx->bam_is_connected;
+ a2_mux_ctx->bam_is_connected = true;
+ a2_mux_ctx->bam_connect_in_progress = false;
+ write_unlock(&a2_mux_ctx->ul_wakeup_lock);
+ if (is_connected)
+ ipa_rm_notify_completion(IPA_RM_RESOURCE_GRANTED,
IPA_RM_RESOURCE_A2_CONS);
+ else
+ msm_bam_dmux_kickoff_ul_power_down();
}
static void kickoff_ul_request_resource_func(struct work_struct *work)
@@ -414,33 +470,6 @@
toggle_apps_ack();
}
-static bool msm_bam_dmux_kickoff_ul_wakeup(void)
-{
- bool is_connected;
-
- read_lock(&a2_mux_ctx->ul_wakeup_lock);
- is_connected = a2_mux_ctx->bam_is_connected;
- read_unlock(&a2_mux_ctx->ul_wakeup_lock);
- if (!is_connected)
- queue_work(a2_mux_ctx->a2_mux_tx_workqueue,
- &a2_mux_ctx->kickoff_ul_wakeup);
- return is_connected;
-}
-
-static bool msm_bam_dmux_kickoff_ul_power_down(void)
-
-{
- bool is_connected;
-
- read_lock(&a2_mux_ctx->ul_wakeup_lock);
- is_connected = a2_mux_ctx->bam_is_connected;
- read_unlock(&a2_mux_ctx->ul_wakeup_lock);
- if (is_connected)
- queue_work(a2_mux_ctx->a2_mux_tx_workqueue,
- &a2_mux_ctx->kickoff_ul_power_down);
- return is_connected;
-}
-
static void ipa_embedded_notify(void *priv,
enum ipa_dp_evt_type evt,
unsigned long data)
@@ -491,10 +520,6 @@
__func__);
return -EFAULT;
}
- ret = sps_device_reset(a2_mux_ctx->a2_device_handle);
- if (ret)
- IPAERR("%s: device reset failed ret = %d\n",
- __func__, ret);
memset(&connect_params, 0, sizeof(struct ipa_sys_connect_params));
connect_params.client = IPA_CLIENT_A2_TETHERED_CONS;
connect_params.notify = ipa_tethered_notify;
@@ -606,12 +631,6 @@
__func__, ret);
return ret;
}
- ret = sps_device_reset(a2_mux_ctx->a2_device_handle);
- if (ret) {
- IPAERR("%s: device reset failed ret = %d\n",
- __func__, ret);
- return ret;
- }
verify_tx_queue_is_empty(__func__);
(void) ipa_rm_release_resource(IPA_RM_RESOURCE_A2_PROD);
if (a2_mux_ctx->disconnect_ack)
@@ -641,7 +660,7 @@
IPA_STATS_INC_CNT(ipa_ctx->stats.a2_power_on_reqs_in);
grab_wakelock();
(void) connect_to_bam();
- queue_work(a2_mux_ctx->a2_mux_tx_workqueue,
+ queue_work(a2_mux_ctx->a2_mux_rx_workqueue,
&a2_mux_ctx->kickoff_ul_request_resource);
} else if (!(new_state & SMSM_A2_POWER_CONTROL)) {
IPADBG("%s: MODEM PWR CTRL 0\n", __func__);
@@ -936,7 +955,8 @@
}
spin_unlock_irqrestore(&a2_mux_ctx->bam_ch[id].lock, flags);
read_lock(&a2_mux_ctx->ul_wakeup_lock);
- is_connected = a2_mux_ctx->bam_is_connected;
+ is_connected = a2_mux_ctx->bam_is_connected &&
+ !a2_mux_ctx->bam_connect_in_progress;
read_unlock(&a2_mux_ctx->ul_wakeup_lock);
if (!is_connected)
return -ENODEV;
@@ -1240,7 +1260,8 @@
a2_mux_ctx->bam_ch[lcid].use_wm = 0;
spin_unlock_irqrestore(&a2_mux_ctx->bam_ch[lcid].lock, flags);
read_lock(&a2_mux_ctx->ul_wakeup_lock);
- is_connected = a2_mux_ctx->bam_is_connected;
+ is_connected = a2_mux_ctx->bam_is_connected &&
+ !a2_mux_ctx->bam_connect_in_progress;
read_unlock(&a2_mux_ctx->ul_wakeup_lock);
if (!is_connected)
return -ENODEV;
@@ -1309,7 +1330,8 @@
if (!a2_mux_ctx->a2_mux_initialized)
return -ENODEV;
read_lock(&a2_mux_ctx->ul_wakeup_lock);
- is_connected = a2_mux_ctx->bam_is_connected;
+ is_connected = a2_mux_ctx->bam_is_connected &&
+ !a2_mux_ctx->bam_connect_in_progress;
read_unlock(&a2_mux_ctx->ul_wakeup_lock);
if (!is_connected && !bam_ch_is_in_reset(lcid))
return -ENODEV;
@@ -1456,6 +1478,13 @@
__func__);
return -ENOMEM;
}
+ a2_mux_ctx->a2_mux_rx_workqueue =
+ create_singlethread_workqueue("a2_mux_rx");
+ if (!a2_mux_ctx->a2_mux_rx_workqueue) {
+ IPAERR("%s: a2_mux_rx_workqueue alloc failed\n",
+ __func__);
+ return -ENOMEM;
+ }
return 0;
}
@@ -1581,5 +1610,7 @@
NULL);
if (a2_mux_ctx->a2_mux_tx_workqueue)
destroy_workqueue(a2_mux_ctx->a2_mux_tx_workqueue);
+ if (a2_mux_ctx->a2_mux_rx_workqueue)
+ destroy_workqueue(a2_mux_ctx->a2_mux_rx_workqueue);
return 0;
}
diff --git a/drivers/platform/msm/ipa/ipa.c b/drivers/platform/msm/ipa/ipa.c
index 466e694..35b2561 100644
--- a/drivers/platform/msm/ipa/ipa.c
+++ b/drivers/platform/msm/ipa/ipa.c
@@ -778,66 +778,6 @@
return ret;
}
-static int ipa_handle_tx_poll_for_pipe(struct ipa_sys_context *sys,
- bool process_all)
-{
- struct ipa_tx_pkt_wrapper *tx_pkt, *t;
- struct sps_iovec iov;
- unsigned long irq_flags;
- int ret;
- int cnt = 0;
-
- do {
- iov.addr = 0;
- ret = sps_get_iovec(sys->ep->ep_hdl, &iov);
- if (ret) {
- pr_err("%s: sps_get_iovec failed %d\n", __func__, ret);
- break;
- }
- if (!iov.addr)
- break;
- spin_lock_irqsave(&sys->spinlock, irq_flags);
- tx_pkt = list_first_entry(&sys->head_desc_list,
- struct ipa_tx_pkt_wrapper, link);
- spin_unlock_irqrestore(&sys->spinlock, irq_flags);
-
- switch (tx_pkt->cnt) {
- case 1:
- ipa_wq_write_done(&tx_pkt->work);
- ++cnt;
- break;
- case 0xFFFF:
- /* reached end of set */
- spin_lock_irqsave(&sys->spinlock, irq_flags);
- list_for_each_entry_safe(tx_pkt, t,
- &sys->wait_desc_list, link) {
- list_del(&tx_pkt->link);
- list_add(&tx_pkt->link, &sys->head_desc_list);
- }
- tx_pkt =
- list_first_entry(&sys->head_desc_list,
- struct ipa_tx_pkt_wrapper, link);
- spin_unlock_irqrestore(&sys->spinlock, irq_flags);
- ipa_wq_write_done(&tx_pkt->work);
- ++cnt;
- break;
- default:
- /* keep looping till reach the end of the set */
- spin_lock_irqsave(&sys->spinlock,
- irq_flags);
- list_del(&tx_pkt->link);
- list_add_tail(&tx_pkt->link,
- &sys->wait_desc_list);
- spin_unlock_irqrestore(&sys->spinlock,
- irq_flags);
- ++cnt;
- break;
- }
- } while (process_all);
-
- return cnt;
-}
-
static void ipa_poll_function(struct work_struct *work)
{
int ret;
@@ -857,13 +797,15 @@
/* check all the system pipes for tx comp and rx avail */
if (ipa_ctx->sys[IPA_A5_LAN_WAN_IN].ep->valid)
- cnt |= ipa_handle_rx_core(false, true);
+ cnt |= ipa_handle_rx_core(
+ &ipa_ctx->sys[IPA_A5_LAN_WAN_IN],
+ false, true);
for (i = 0; i < num_tx_pipes; i++)
if (ipa_ctx->sys[tx_pipes[i]].ep->valid)
- cnt |= ipa_handle_tx_poll_for_pipe(
+ cnt |= ipa_handle_tx_core(
&ipa_ctx->sys[tx_pipes[i]],
- false);
+ false, true);
} while (cnt);
/* re-post the poll work */
@@ -1666,10 +1608,6 @@
IPADBG("polling_mode=%u delay_ms=%u\n", polling_mode, polling_delay_ms);
ipa_ctx->polling_mode = polling_mode;
- if (ipa_ctx->polling_mode)
- atomic_set(&ipa_ctx->curr_polling_state, 1);
- else
- atomic_set(&ipa_ctx->curr_polling_state, 0);
IPADBG("hdr_lcl=%u ip4_rt=%u ip6_rt=%u ip4_flt=%u ip6_flt=%u\n",
hdr_tbl_lcl, ip4_rt_tbl_lcl, ip6_rt_tbl_lcl, ip4_flt_tbl_lcl,
ip6_flt_tbl_lcl);
@@ -1891,7 +1829,10 @@
ipa_ctx->sys[i].ep = &ipa_ctx->ep[i];
else
ipa_ctx->sys[i].ep = &ipa_ctx->ep[WLAN_AMPDU_TX_EP];
- INIT_LIST_HEAD(&ipa_ctx->sys[i].wait_desc_list);
+ if (ipa_ctx->polling_mode)
+ atomic_set(&ipa_ctx->sys[i].curr_polling_state, 1);
+ else
+ atomic_set(&ipa_ctx->sys[i].curr_polling_state, 0);
}
ipa_ctx->rx_wq = create_singlethread_workqueue("ipa rx wq");
@@ -1901,7 +1842,8 @@
goto fail_rx_wq;
}
- ipa_ctx->tx_wq = create_singlethread_workqueue("ipa tx wq");
+ ipa_ctx->tx_wq = alloc_workqueue("ipa tx wq", WQ_MEM_RECLAIM |
+ WQ_CPU_INTENSIVE, 2);
if (!ipa_ctx->tx_wq) {
IPAERR(":fail to create tx wq\n");
result = -ENOMEM;
diff --git a/drivers/platform/msm/ipa/ipa_client.c b/drivers/platform/msm/ipa/ipa_client.c
index a78879d..a95eafe 100644
--- a/drivers/platform/msm/ipa/ipa_client.c
+++ b/drivers/platform/msm/ipa/ipa_client.c
@@ -15,18 +15,14 @@
static void ipa_enable_data_path(u32 clnt_hdl)
{
- struct ipa_ep_context *ep = &ipa_ctx->ep[clnt_hdl];
-
if (ipa_ctx->ipa_hw_mode == IPA_HW_MODE_VIRTUAL) {
/* IPA_HW_MODE_VIRTUAL lacks support for TAG IC & EP suspend */
return;
}
- if (ipa_ctx->ipa_hw_type == IPA_HW_v1_1 && ep->suspended) {
+ if (ipa_ctx->ipa_hw_type == IPA_HW_v1_1)
ipa_write_reg(ipa_ctx->mmio,
IPA_ENDP_INIT_CTRL_n_OFST(clnt_hdl), 0);
- ep->suspended = false;
- }
}
static int ipa_disable_data_path(u32 clnt_hdl)
@@ -50,7 +46,7 @@
goto fail_alloc;
}
- if (ipa_ctx->ipa_hw_type == IPA_HW_v1_1 && !ep->suspended) {
+ if (ipa_ctx->ipa_hw_type == IPA_HW_v1_1) {
ipa_write_reg(ipa_ctx->mmio,
IPA_ENDP_INIT_CTRL_n_OFST(clnt_hdl), 1);
@@ -85,7 +81,6 @@
ep->cfg.aggr.aggr_en == IPA_ENABLE_AGGR &&
ep->cfg.aggr.aggr_time_limit)
msleep(ep->cfg.aggr.aggr_time_limit);
- ep->suspended = true;
}
return 0;
@@ -298,7 +293,9 @@
if (in->client == IPA_CLIENT_HSIC1_CONS ||
in->client == IPA_CLIENT_HSIC2_CONS ||
in->client == IPA_CLIENT_HSIC3_CONS ||
- in->client == IPA_CLIENT_HSIC4_CONS) {
+ in->client == IPA_CLIENT_HSIC4_CONS ||
+ in->client == IPA_CLIENT_A2_TETHERED_CONS ||
+ in->client == IPA_CLIENT_A2_EMBEDDED_CONS) {
IPADBG("disable holb for ep=%d tmr=%d\n", ipa_ep_idx,
ipa_ctx->hol_timer);
ipa_write_reg(ipa_ctx->mmio,
@@ -367,6 +364,11 @@
ep = &ipa_ctx->ep[clnt_hdl];
+ if (ep->suspended) {
+ ipa_inc_client_enable_clks();
+ ep->suspended = false;
+ }
+
result = ipa_disable_data_path(clnt_hdl);
if (result) {
IPAERR("disable data path failed res=%d clnt=%d.\n", result,
@@ -422,55 +424,79 @@
EXPORT_SYMBOL(ipa_disconnect);
/**
- * ipa_connection_suspend() - suspend B2B connection to/from IPA
+ * ipa_resume() - low-level IPA client resume
* @clnt_hdl: [in] opaque client handle assigned by IPA to client
*
- * Should be called by the driver of the peripheral that wants to suspend
- * its BAM-BAM connection to/from IPA in BAM-BAM mode. The pipe is not
- * disconnected and must later be resumed before data transfer can begin
+ * Should be called by the driver of the peripheral that wants to resume IPA
+ * connection. Resume IPA connection results in turning on IPA clocks in
+ * case they were off as a result of suspend.
+ * this api can be called only if a call to ipa_suspend() was
+ * made.
*
* Returns: 0 on success, negative on failure
*
* Note: Should not be called from atomic context
*/
-int ipa_connection_suspend(u32 clnt_hdl)
+int ipa_resume(u32 clnt_hdl)
{
- int result;
+ struct ipa_ep_context *ep;
if (clnt_hdl >= IPA_NUM_PIPES || ipa_ctx->ep[clnt_hdl].valid == 0) {
- IPAERR("bad parm.\n");
- return -EINVAL;
- }
- result = ipa_disable_data_path(clnt_hdl);
- if (result)
- IPAERR("disable data path failed res=%d clnt=%d.\n", result,
- clnt_hdl);
-
- return result;
-}
-EXPORT_SYMBOL(ipa_connection_suspend);
-
-/**
- * ipa_connection_resume() - resume B2B connection to/from IPA
- * @clnt_hdl: [in] opaque client handle assigned by IPA to client
- *
- * Should be called by the driver of the peripheral that wants to resume
- * its previously suspended BAM-BAM connection to/from IPA in BAM-BAM mode.
- *
- * Returns: 0 on success, negative on failure
- *
- * Note: Should not be called from atomic context
- */
-int ipa_connection_resume(u32 clnt_hdl)
-{
- if (clnt_hdl >= IPA_NUM_PIPES || ipa_ctx->ep[clnt_hdl].valid == 0) {
- IPAERR("bad parm.\n");
+ IPAERR("bad parm. clnt_hdl %d\n", clnt_hdl);
return -EINVAL;
}
- ipa_enable_data_path(clnt_hdl);
+ ep = &ipa_ctx->ep[clnt_hdl];
+
+ if (!ep->suspended) {
+ IPAERR("EP not suspended. clnt_hdl %d\n", clnt_hdl);
+ return -EPERM;
+ }
+
+ ipa_inc_client_enable_clks();
+ ep->suspended = false;
return 0;
}
-EXPORT_SYMBOL(ipa_connection_resume);
+EXPORT_SYMBOL(ipa_resume);
+/**
+* ipa_suspend() - low-level IPA client suspend
+* @clnt_hdl: [in] opaque client handle assigned by IPA to client
+*
+* Should be called by the driver of the peripheral that wants to suspend IPA
+* connection. Suspend IPA connection results in turning off IPA clocks in
+* case that there is no active clients using IPA. Pipes remains connected in
+* case of suspend.
+*
+* Returns: 0 on success, negative on failure
+*
+* Note: Should not be called from atomic context
+*/
+int ipa_suspend(u32 clnt_hdl)
+{
+ struct ipa_ep_context *ep;
+
+ if (clnt_hdl >= IPA_NUM_PIPES || ipa_ctx->ep[clnt_hdl].valid == 0) {
+ IPAERR("bad parm. clnt_hdl %d\n", clnt_hdl);
+ return -EINVAL;
+ }
+
+ ep = &ipa_ctx->ep[clnt_hdl];
+
+ if (ep->suspended) {
+ IPAERR("EP already suspended. clnt_hdl %d\n", clnt_hdl);
+ return -EPERM;
+ }
+
+ if (IPA_CLIENT_IS_CONS(ep->client) &&
+ ep->cfg.aggr.aggr_en == IPA_ENABLE_AGGR &&
+ ep->cfg.aggr.aggr_time_limit)
+ msleep(ep->cfg.aggr.aggr_time_limit);
+
+ ipa_dec_client_disable_clks();
+ ep->suspended = true;
+
+ return 0;
+}
+EXPORT_SYMBOL(ipa_suspend);
diff --git a/drivers/platform/msm/ipa/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_debugfs.c
index fb69817..b11c7da 100644
--- a/drivers/platform/msm/ipa/ipa_debugfs.c
+++ b/drivers/platform/msm/ipa/ipa_debugfs.c
@@ -104,6 +104,7 @@
static struct dentry *dfile_stats;
static struct dentry *dfile_dbg_cnt;
static struct dentry *dfile_msg;
+static struct dentry *dfile_ip4_nat;
static char dbg_buff[IPA_MAX_MSG_LEN];
static s8 ep_reg_idx;
@@ -608,6 +609,7 @@
"rx=%u\n"
"rx_repl_repost=%u\n"
"x_intr_repost=%u\n"
+ "x_intr_repost_tx=%u\n"
"rx_q_len=%u\n"
"act_clnt=%u\n"
"con_clnt_bmap=0x%x\n"
@@ -622,6 +624,7 @@
ipa_ctx->stats.rx_pkts,
ipa_ctx->stats.rx_repl_repost,
ipa_ctx->stats.x_intr_repost,
+ ipa_ctx->stats.x_intr_repost_tx,
ipa_ctx->stats.rx_q_len,
ipa_ctx->ipa_active_clients,
connect,
@@ -720,6 +723,238 @@
return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, cnt);
}
+static ssize_t ipa_read_nat4(struct file *file,
+ char __user *ubuf, size_t count,
+ loff_t *ppos) {
+
+#define ENTRY_U32_FIELDS 8
+#define NAT_ENTRY_ENABLE 0x8000
+#define NAT_ENTRY_RST_FIN_BIT 0x4000
+#define BASE_TABLE 0
+#define EXPANSION_TABLE 1
+
+ u32 *base_tbl, *indx_tbl;
+ u32 tbl_size, *tmp;
+ u32 value, i, j, rule_id;
+ u16 enable, tbl_entry, flag;
+ int nbytes, cnt;
+
+ cnt = 0;
+ value = ipa_ctx->nat_mem.public_ip_addr;
+ nbytes = scnprintf(dbg_buff + cnt,
+ IPA_MAX_MSG_LEN,
+ "Table IP Address:%d.%d.%d.%d\n",
+ ((value & 0xFF000000) >> 24),
+ ((value & 0x00FF0000) >> 16),
+ ((value & 0x0000FF00) >> 8),
+ ((value & 0x000000FF)));
+ cnt += nbytes;
+
+ nbytes = scnprintf(dbg_buff + cnt,
+ IPA_MAX_MSG_LEN,
+ "Table Size:%d\n",
+ ipa_ctx->nat_mem.size_base_tables);
+ cnt += nbytes;
+
+ nbytes = scnprintf(dbg_buff + cnt,
+ IPA_MAX_MSG_LEN,
+ "Expansion Table Size:%d\n",
+ ipa_ctx->nat_mem.size_expansion_tables);
+ cnt += nbytes;
+
+ if (!ipa_ctx->nat_mem.is_sys_mem) {
+ nbytes = scnprintf(dbg_buff + cnt,
+ IPA_MAX_MSG_LEN,
+ "Not supported for local(shared) memory\n");
+ cnt += nbytes;
+
+ return simple_read_from_buffer(ubuf, count,
+ ppos, dbg_buff, cnt);
+ }
+
+
+ /* Print Base tables */
+ rule_id = 0;
+ for (j = 0; j < 2; j++) {
+ if (j == BASE_TABLE) {
+ tbl_size = ipa_ctx->nat_mem.size_base_tables;
+ base_tbl = (u32 *)ipa_ctx->nat_mem.ipv4_rules_addr;
+
+ nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN,
+ "\nBase Table:\n");
+ cnt += nbytes;
+ } else {
+ tbl_size = ipa_ctx->nat_mem.size_expansion_tables;
+ base_tbl =
+ (u32 *)ipa_ctx->nat_mem.ipv4_expansion_rules_addr;
+
+ nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN,
+ "\nExpansion Base Table:\n");
+ cnt += nbytes;
+ }
+
+ if (base_tbl != NULL) {
+ for (i = 0; i <= tbl_size; i++, rule_id++) {
+ tmp = base_tbl;
+ value = tmp[4];
+ enable = ((value & 0xFFFF0000) >> 16);
+
+ if (enable & NAT_ENTRY_ENABLE) {
+ nbytes = scnprintf(dbg_buff + cnt,
+ IPA_MAX_MSG_LEN,
+ "Rule:%d ",
+ rule_id);
+ cnt += nbytes;
+
+ value = *tmp;
+ nbytes = scnprintf(dbg_buff + cnt,
+ IPA_MAX_MSG_LEN,
+ "Private_IP:%d.%d.%d.%d ",
+ ((value & 0xFF000000) >> 24),
+ ((value & 0x00FF0000) >> 16),
+ ((value & 0x0000FF00) >> 8),
+ ((value & 0x000000FF)));
+ cnt += nbytes;
+ tmp++;
+
+ value = *tmp;
+ nbytes = scnprintf(dbg_buff + cnt,
+ IPA_MAX_MSG_LEN,
+ "Target_IP:%d.%d.%d.%d ",
+ ((value & 0xFF000000) >> 24),
+ ((value & 0x00FF0000) >> 16),
+ ((value & 0x0000FF00) >> 8),
+ ((value & 0x000000FF)));
+ cnt += nbytes;
+ tmp++;
+
+ value = *tmp;
+ nbytes = scnprintf(dbg_buff + cnt,
+ IPA_MAX_MSG_LEN,
+ "Next_Index:%d Public_Port:%d ",
+ (value & 0x0000FFFF),
+ ((value & 0xFFFF0000) >> 16));
+ cnt += nbytes;
+ tmp++;
+
+ value = *tmp;
+ nbytes = scnprintf(dbg_buff + cnt,
+ IPA_MAX_MSG_LEN,
+ "Private_Port:%d Target_Port:%d ",
+ (value & 0x0000FFFF),
+ ((value & 0xFFFF0000) >> 16));
+ cnt += nbytes;
+ tmp++;
+
+ value = *tmp;
+ nbytes = scnprintf(dbg_buff + cnt,
+ IPA_MAX_MSG_LEN,
+ "IP-CKSM-delta:0x%x ",
+ (value & 0x0000FFFF));
+ cnt += nbytes;
+
+ flag = ((value & 0xFFFF0000) >> 16);
+ if (flag & NAT_ENTRY_RST_FIN_BIT) {
+ nbytes =
+ scnprintf(dbg_buff + cnt,
+ IPA_MAX_MSG_LEN,
+ "IP_CKSM_delta:0x%x Flags:%s ",
+ (value & 0x0000FFFF),
+ "Direct_To_A5");
+ cnt += nbytes;
+ } else {
+ nbytes =
+ scnprintf(dbg_buff + cnt,
+ IPA_MAX_MSG_LEN,
+ "IP_CKSM_delta:0x%x Flags:%s ",
+ (value & 0x0000FFFF),
+ "Fwd_to_route");
+ cnt += nbytes;
+ }
+ tmp++;
+
+ value = *tmp;
+ nbytes = scnprintf(dbg_buff + cnt,
+ IPA_MAX_MSG_LEN,
+ "Time_stamp:0x%x Proto:%d ",
+ (value & 0x00FFFFFF),
+ ((value & 0xFF000000) >> 27));
+ cnt += nbytes;
+ tmp++;
+
+ value = *tmp;
+ nbytes = scnprintf(dbg_buff + cnt,
+ IPA_MAX_MSG_LEN,
+ "Prev_Index:%d Indx_tbl_entry:%d ",
+ (value & 0x0000FFFF),
+ ((value & 0xFFFF0000) >> 16));
+ cnt += nbytes;
+ tmp++;
+
+ value = *tmp;
+ nbytes = scnprintf(dbg_buff + cnt,
+ IPA_MAX_MSG_LEN,
+ "TCP_UDP_cksum_delta:0x%x\n",
+ ((value & 0xFFFF0000) >> 16));
+ cnt += nbytes;
+ }
+
+ base_tbl += ENTRY_U32_FIELDS;
+
+ }
+ }
+ }
+
+ /* Print Index tables */
+ rule_id = 0;
+ for (j = 0; j < 2; j++) {
+ if (j == BASE_TABLE) {
+ tbl_size = ipa_ctx->nat_mem.size_base_tables;
+ indx_tbl = (u32 *)ipa_ctx->nat_mem.index_table_addr;
+
+ nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN,
+ "\nIndex Table:\n");
+ cnt += nbytes;
+ } else {
+ tbl_size = ipa_ctx->nat_mem.size_expansion_tables;
+ indx_tbl =
+ (u32 *)ipa_ctx->nat_mem.index_table_expansion_addr;
+
+ nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN,
+ "\nExpansion Index Table:\n");
+ cnt += nbytes;
+ }
+
+ if (indx_tbl != NULL) {
+ for (i = 0; i <= tbl_size; i++, rule_id++) {
+ tmp = indx_tbl;
+ value = *tmp;
+ tbl_entry = (value & 0x0000FFFF);
+
+ if (tbl_entry) {
+ nbytes = scnprintf(dbg_buff + cnt,
+ IPA_MAX_MSG_LEN,
+ "Rule:%d ",
+ rule_id);
+ cnt += nbytes;
+
+ value = *tmp;
+ nbytes = scnprintf(dbg_buff + cnt,
+ IPA_MAX_MSG_LEN,
+ "Table_Entry:%d Next_Index:%d\n",
+ tbl_entry,
+ ((value & 0xFFFF0000) >> 16));
+ cnt += nbytes;
+ }
+
+ indx_tbl++;
+ }
+ }
+ }
+
+ return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, cnt);
+}
+
const struct file_operations ipa_gen_reg_ops = {
.read = ipa_read_gen_reg,
};
@@ -763,6 +998,10 @@
.write = ipa_write_dbg_cnt,
};
+const struct file_operations ipa_nat4_ops = {
+ .read = ipa_read_nat4,
+};
+
void ipa_debugfs_init(void)
{
const mode_t read_only_mode = S_IRUSR | S_IRGRP | S_IROTH;
@@ -860,6 +1099,13 @@
goto fail;
}
+ dfile_ip4_nat = debugfs_create_file("ip4_nat", read_only_mode, dent,
+ 0, &ipa_nat4_ops);
+ if (!dfile_ip4_nat || IS_ERR(dfile_ip4_nat)) {
+ IPAERR("fail to create file for debug_fs ip4 nat\n");
+ goto fail;
+ }
+
return;
fail:
diff --git a/drivers/platform/msm/ipa/ipa_dp.c b/drivers/platform/msm/ipa/ipa_dp.c
index 228c77fe..67728c2 100644
--- a/drivers/platform/msm/ipa/ipa_dp.c
+++ b/drivers/platform/msm/ipa/ipa_dp.c
@@ -20,14 +20,15 @@
#define list_next_entry(pos, member) \
list_entry(pos->member.next, typeof(*pos), member)
#define IPA_LAST_DESC_CNT 0xFFFF
-#define POLLING_INACTIVITY 40
-#define POLLING_MIN_SLEEP 950
-#define POLLING_MAX_SLEEP 1050
+#define POLLING_INACTIVITY_RX 40
+#define POLLING_MIN_SLEEP_RX 950
+#define POLLING_MAX_SLEEP_RX 1050
+#define POLLING_INACTIVITY_TX 40
+#define POLLING_MIN_SLEEP_TX 400
+#define POLLING_MAX_SLEEP_TX 500
static void replenish_rx_work_func(struct work_struct *work);
static struct delayed_work replenish_rx_work;
-static void switch_to_intr_work_func(struct work_struct *work);
-static struct delayed_work switch_to_intr_work;
static void ipa_wq_handle_rx(struct work_struct *work);
static DECLARE_WORK(rx_work, ipa_wq_handle_rx);
@@ -47,57 +48,164 @@
void ipa_wq_write_done(struct work_struct *work)
{
struct ipa_tx_pkt_wrapper *tx_pkt;
- struct ipa_tx_pkt_wrapper *next_pkt;
struct ipa_tx_pkt_wrapper *tx_pkt_expected;
unsigned long irq_flags;
- struct ipa_mem_buffer mult = { 0 };
- int i;
- u32 cnt;
tx_pkt = container_of(work, struct ipa_tx_pkt_wrapper, work);
- cnt = tx_pkt->cnt;
- IPADBG("cnt=%d\n", cnt);
- if (unlikely(cnt == 0))
+ if (unlikely(tx_pkt == NULL))
WARN_ON(1);
+ WARN_ON(tx_pkt->cnt != 1);
- if (cnt > 1 && cnt != IPA_LAST_DESC_CNT)
- mult = tx_pkt->mult;
+ spin_lock_irqsave(&tx_pkt->sys->spinlock, irq_flags);
+ tx_pkt_expected = list_first_entry(&tx_pkt->sys->head_desc_list,
+ struct ipa_tx_pkt_wrapper,
+ link);
+ if (unlikely(tx_pkt != tx_pkt_expected)) {
+ spin_unlock_irqrestore(&tx_pkt->sys->spinlock,
+ irq_flags);
+ WARN_ON(1);
+ }
+ list_del(&tx_pkt->link);
+ spin_unlock_irqrestore(&tx_pkt->sys->spinlock, irq_flags);
+ if (unlikely(ipa_ctx->ipa_hw_type == IPA_HW_v1_0)) {
+ dma_pool_free(ipa_ctx->dma_pool,
+ tx_pkt->bounce,
+ tx_pkt->mem.phys_base);
+ } else {
+ dma_unmap_single(NULL, tx_pkt->mem.phys_base,
+ tx_pkt->mem.size,
+ DMA_TO_DEVICE);
+ }
- for (i = 0; i < cnt; i++) {
- if (unlikely(tx_pkt == NULL))
- WARN_ON(1);
- spin_lock_irqsave(&tx_pkt->sys->spinlock, irq_flags);
- tx_pkt_expected = list_first_entry(&tx_pkt->sys->head_desc_list,
- struct ipa_tx_pkt_wrapper,
- link);
- if (unlikely(tx_pkt != tx_pkt_expected)) {
- spin_unlock_irqrestore(&tx_pkt->sys->spinlock,
- irq_flags);
- WARN_ON(1);
+ if (tx_pkt->callback)
+ tx_pkt->callback(tx_pkt->user1, tx_pkt->user2);
+
+ kmem_cache_free(ipa_ctx->tx_pkt_wrapper_cache, tx_pkt);
+}
+
+int ipa_handle_tx_core(struct ipa_sys_context *sys, bool process_all,
+ bool in_poll_state)
+{
+ struct ipa_tx_pkt_wrapper *tx_pkt;
+ struct sps_iovec iov;
+ int ret;
+ int cnt = 0;
+ unsigned long irq_flags;
+
+ while ((in_poll_state ? atomic_read(&sys->curr_polling_state) :
+ !atomic_read(&sys->curr_polling_state))) {
+ if (cnt && !process_all)
+ break;
+ ret = sps_get_iovec(sys->ep->ep_hdl, &iov);
+ if (ret) {
+ IPAERR("sps_get_iovec failed %d\n", ret);
+ break;
}
- next_pkt = list_next_entry(tx_pkt, link);
+
+ if (iov.addr == 0)
+ break;
+
+ if (unlikely(list_empty(&sys->head_desc_list)))
+ continue;
+
+ spin_lock_irqsave(&sys->spinlock, irq_flags);
+ tx_pkt = list_first_entry(&sys->head_desc_list,
+ struct ipa_tx_pkt_wrapper, link);
+
+ sys->len--;
list_del(&tx_pkt->link);
- spin_unlock_irqrestore(&tx_pkt->sys->spinlock, irq_flags);
- if (unlikely(ipa_ctx->ipa_hw_type == IPA_HW_v1_0)) {
+ spin_unlock_irqrestore(&sys->spinlock, irq_flags);
+
+ IPADBG("--curr_cnt=%d\n", sys->len);
+
+ if (unlikely(ipa_ctx->ipa_hw_type == IPA_HW_v1_0))
dma_pool_free(ipa_ctx->dma_pool,
tx_pkt->bounce,
tx_pkt->mem.phys_base);
- } else {
+ else
dma_unmap_single(NULL, tx_pkt->mem.phys_base,
tx_pkt->mem.size,
DMA_TO_DEVICE);
- }
if (tx_pkt->callback)
tx_pkt->callback(tx_pkt->user1, tx_pkt->user2);
+ if (tx_pkt->cnt > 1 && tx_pkt->cnt != IPA_LAST_DESC_CNT)
+ dma_pool_free(ipa_ctx->dma_pool, tx_pkt->mult.base,
+ tx_pkt->mult.phys_base);
+
kmem_cache_free(ipa_ctx->tx_pkt_wrapper_cache, tx_pkt);
- tx_pkt = next_pkt;
+ cnt++;
+ };
+
+ return cnt;
+}
+
+/**
+ * ipa_tx_switch_to_intr_mode() - Operate the Tx data path in interrupt mode
+ */
+static void ipa_tx_switch_to_intr_mode(struct ipa_sys_context *sys)
+{
+ int ret;
+
+ if (!atomic_read(&sys->curr_polling_state)) {
+ IPAERR("already in intr mode\n");
+ goto fail;
}
- if (mult.phys_base)
- dma_pool_free(ipa_ctx->dma_pool, mult.base, mult.phys_base);
+ ret = sps_get_config(sys->ep->ep_hdl, &sys->ep->connect);
+ if (ret) {
+ IPAERR("sps_get_config() failed %d\n", ret);
+ goto fail;
+ }
+ sys->event.options = SPS_O_EOT;
+ ret = sps_register_event(sys->ep->ep_hdl, &sys->event);
+ if (ret) {
+ IPAERR("sps_register_event() failed %d\n", ret);
+ goto fail;
+ }
+ sys->ep->connect.options =
+ SPS_O_AUTO_ENABLE | SPS_O_ACK_TRANSFERS | SPS_O_EOT;
+ ret = sps_set_config(sys->ep->ep_hdl, &sys->ep->connect);
+ if (ret) {
+ IPAERR("sps_set_config() failed %d\n", ret);
+ goto fail;
+ }
+ atomic_set(&sys->curr_polling_state, 0);
+ ipa_handle_tx_core(sys, true, false);
+ return;
+
+fail:
+ IPA_STATS_INC_CNT(ipa_ctx->stats.x_intr_repost_tx);
+ schedule_delayed_work(&sys->switch_to_intr_work, msecs_to_jiffies(1));
+ return;
+}
+
+static void ipa_handle_tx(struct ipa_sys_context *sys)
+{
+ int inactive_cycles = 0;
+ int cnt;
+
+ do {
+ cnt = ipa_handle_tx_core(sys, true, true);
+ if (cnt == 0) {
+ inactive_cycles++;
+ usleep_range(POLLING_MIN_SLEEP_TX,
+ POLLING_MAX_SLEEP_TX);
+ } else {
+ inactive_cycles = 0;
+ }
+ } while (inactive_cycles <= POLLING_INACTIVITY_TX);
+
+ ipa_tx_switch_to_intr_mode(sys);
+}
+
+static void ipa_wq_handle_tx(struct work_struct *work)
+{
+ struct ipa_tx_pkt_wrapper *tx_pkt;
+ tx_pkt = container_of(work, struct ipa_tx_pkt_wrapper, work);
+ ipa_handle_tx(tx_pkt->sys);
}
/**
@@ -165,7 +273,6 @@
}
INIT_LIST_HEAD(&tx_pkt->link);
- INIT_WORK(&tx_pkt->work, ipa_wq_write_done);
tx_pkt->type = desc->type;
tx_pkt->cnt = 1; /* only 1 desc in this "set" */
@@ -187,10 +294,15 @@
IPADBG("sending cmd=%d pyld_len=%d sps_flags=%x\n",
desc->opcode, desc->len, sps_flags);
IPA_DUMP_BUFF(desc->pyld, dma_address, desc->len);
+ INIT_WORK(&tx_pkt->work, ipa_wq_write_done);
} else {
len = desc->len;
+ INIT_WORK(&tx_pkt->work, ipa_wq_handle_tx);
}
+ if (unlikely(ipa_ctx->polling_mode))
+ INIT_WORK(&tx_pkt->work, ipa_wq_handle_tx);
+
spin_lock_irqsave(&sys->spinlock, irq_flags);
list_add_tail(&tx_pkt->link, &sys->head_desc_list);
result = sps_transfer_one(sys->ep->ep_hdl, dma_address, len, tx_pkt,
@@ -286,7 +398,7 @@
tx_pkt->mult.base = transfer.iovec;
tx_pkt->mult.size = size;
tx_pkt->cnt = num_desc;
- INIT_WORK(&tx_pkt->work, ipa_wq_write_done);
+ INIT_WORK(&tx_pkt->work, ipa_wq_handle_tx);
}
iovec = &transfer.iovec[i];
@@ -475,6 +587,49 @@
/**
* ipa_sps_irq_tx_notify() - Callback function which will be called by
+ * the SPS driver to start a Tx poll operation.
+ * Called in an interrupt context.
+ * @notify: SPS driver supplied notification struct
+ *
+ * This function defer the work for this event to the tx workqueue.
+ */
+static void ipa_sps_irq_tx_notify(struct sps_event_notify *notify)
+{
+ struct ipa_sys_context *sys = &ipa_ctx->sys[IPA_A5_LAN_WAN_OUT];
+ struct ipa_tx_pkt_wrapper *tx_pkt;
+ int ret;
+
+ IPADBG("event %d notified\n", notify->event_id);
+
+ switch (notify->event_id) {
+ case SPS_EVENT_EOT:
+ tx_pkt = notify->data.transfer.user;
+ if (!atomic_read(&sys->curr_polling_state)) {
+ ret = sps_get_config(sys->ep->ep_hdl,
+ &sys->ep->connect);
+ if (ret) {
+ IPAERR("sps_get_config() failed %d\n", ret);
+ break;
+ }
+ sys->ep->connect.options = SPS_O_AUTO_ENABLE |
+ SPS_O_ACK_TRANSFERS | SPS_O_POLL;
+ ret = sps_set_config(sys->ep->ep_hdl,
+ &sys->ep->connect);
+ if (ret) {
+ IPAERR("sps_set_config() failed %d\n", ret);
+ break;
+ }
+ atomic_set(&sys->curr_polling_state, 1);
+ queue_work(ipa_ctx->tx_wq, &tx_pkt->work);
+ }
+ break;
+ default:
+ IPAERR("recieved unexpected event id %d\n", notify->event_id);
+ }
+}
+
+/**
+ * ipa_sps_irq_tx_no_aggr_notify() - Callback function which will be called by
* the SPS driver after a Tx operation is complete.
* Called in an interrupt context.
* @notify: SPS driver supplied notification struct
@@ -482,7 +637,7 @@
* This function defer the work for this event to the tx workqueue.
* This event will be later handled by ipa_write_done.
*/
-static void ipa_sps_irq_tx_notify(struct sps_event_notify *notify)
+static void ipa_sps_irq_tx_no_aggr_notify(struct sps_event_notify *notify)
{
struct ipa_tx_pkt_wrapper *tx_pkt;
@@ -512,7 +667,8 @@
* - Call the endpoints notify function, passing the skb in the parameters
* - Replenish the rx cache
*/
-int ipa_handle_rx_core(bool process_all, bool in_poll_state)
+int ipa_handle_rx_core(struct ipa_sys_context *sys, bool process_all,
+ bool in_poll_state)
{
struct ipa_a5_mux_hdr *mux_hdr;
struct ipa_rx_pkt_wrapper *rx_pkt;
@@ -521,15 +677,14 @@
unsigned int pull_len;
unsigned int padding;
int ret;
- struct ipa_sys_context *sys = &ipa_ctx->sys[IPA_A5_LAN_WAN_IN];
struct ipa_ep_context *ep;
int cnt = 0;
struct completion *compl;
struct ipa_tree_node *node;
unsigned int src_pipe;
- while ((in_poll_state ? atomic_read(&ipa_ctx->curr_polling_state) :
- !atomic_read(&ipa_ctx->curr_polling_state))) {
+ while ((in_poll_state ? atomic_read(&sys->curr_polling_state) :
+ !atomic_read(&sys->curr_polling_state))) {
if (cnt && !process_all)
break;
@@ -654,19 +809,15 @@
/**
* ipa_rx_switch_to_intr_mode() - Operate the Rx data path in interrupt mode
*/
-static void ipa_rx_switch_to_intr_mode(void)
+static void ipa_rx_switch_to_intr_mode(struct ipa_sys_context *sys)
{
int ret;
- struct ipa_sys_context *sys;
- IPADBG("Enter");
- if (!atomic_read(&ipa_ctx->curr_polling_state)) {
+ if (!atomic_read(&sys->curr_polling_state)) {
IPAERR("already in intr mode\n");
goto fail;
}
- sys = &ipa_ctx->sys[IPA_A5_LAN_WAN_IN];
-
ret = sps_get_config(sys->ep->ep_hdl, &sys->ep->connect);
if (ret) {
IPAERR("sps_get_config() failed %d\n", ret);
@@ -685,15 +836,16 @@
IPAERR("sps_set_config() failed %d\n", ret);
goto fail;
}
- atomic_set(&ipa_ctx->curr_polling_state, 0);
- ipa_handle_rx_core(true, false);
+ atomic_set(&sys->curr_polling_state, 0);
+ ipa_handle_rx_core(sys, true, false);
return;
fail:
IPA_STATS_INC_CNT(ipa_ctx->stats.x_intr_repost);
- schedule_delayed_work(&switch_to_intr_work, msecs_to_jiffies(1));
+ schedule_delayed_work(&sys->switch_to_intr_work, msecs_to_jiffies(1));
}
+
/**
* ipa_rx_notify() - Callback function which is called by the SPS driver when a
* a packet is received
@@ -709,29 +861,29 @@
*/
static void ipa_sps_irq_rx_notify(struct sps_event_notify *notify)
{
- struct ipa_ep_context *ep;
+ struct ipa_sys_context *sys = &ipa_ctx->sys[IPA_A5_LAN_WAN_IN];
int ret;
IPADBG("event %d notified\n", notify->event_id);
switch (notify->event_id) {
case SPS_EVENT_EOT:
- if (!atomic_read(&ipa_ctx->curr_polling_state)) {
- ep = ipa_ctx->sys[IPA_A5_LAN_WAN_IN].ep;
-
- ret = sps_get_config(ep->ep_hdl, &ep->connect);
+ if (!atomic_read(&sys->curr_polling_state)) {
+ ret = sps_get_config(sys->ep->ep_hdl,
+ &sys->ep->connect);
if (ret) {
IPAERR("sps_get_config() failed %d\n", ret);
break;
}
- ep->connect.options = SPS_O_AUTO_ENABLE |
+ sys->ep->connect.options = SPS_O_AUTO_ENABLE |
SPS_O_ACK_TRANSFERS | SPS_O_POLL;
- ret = sps_set_config(ep->ep_hdl, &ep->connect);
+ ret = sps_set_config(sys->ep->ep_hdl,
+ &sys->ep->connect);
if (ret) {
IPAERR("sps_set_config() failed %d\n", ret);
break;
}
- atomic_set(&ipa_ctx->curr_polling_state, 1);
+ atomic_set(&sys->curr_polling_state, 1);
queue_work(ipa_ctx->rx_wq, &rx_work);
}
break;
@@ -740,6 +892,51 @@
}
}
+static void switch_to_intr_tx_work_func(struct work_struct *work)
+{
+ struct delayed_work *dwork;
+ struct ipa_sys_context *sys;
+ dwork = container_of(work, struct delayed_work, work);
+ sys = container_of(dwork, struct ipa_sys_context, switch_to_intr_work);
+ ipa_handle_tx(sys);
+}
+
+/**
+ * ipa_handle_rx() - handle packet reception. This function is executed in the
+ * context of a work queue.
+ * @work: work struct needed by the work queue
+ *
+ * ipa_handle_rx_core() is run in polling mode. After all packets has been
+ * received, the driver switches back to interrupt mode.
+ */
+static void ipa_handle_rx(struct ipa_sys_context *sys)
+{
+ int inactive_cycles = 0;
+ int cnt;
+
+ do {
+ cnt = ipa_handle_rx_core(sys, true, true);
+ if (cnt == 0) {
+ inactive_cycles++;
+ usleep_range(POLLING_MIN_SLEEP_RX,
+ POLLING_MAX_SLEEP_RX);
+ } else {
+ inactive_cycles = 0;
+ }
+ } while (inactive_cycles <= POLLING_INACTIVITY_RX);
+
+ ipa_rx_switch_to_intr_mode(sys);
+}
+
+static void switch_to_intr_rx_work_func(struct work_struct *work)
+{
+ struct delayed_work *dwork;
+ struct ipa_sys_context *sys;
+ dwork = container_of(work, struct delayed_work, work);
+ sys = container_of(dwork, struct ipa_sys_context, switch_to_intr_work);
+ ipa_handle_rx(sys);
+}
+
/**
* ipa_setup_sys_pipe() - Setup an IPA end-point in system-BAM mode and perform
* IPA EP configuration
@@ -858,14 +1055,18 @@
switch (ipa_ep_idx) {
case 1:
- /* fall through */
+ sys_idx = ipa_ep_idx;
+ break;
case 2:
- /* fall through */
+ sys_idx = ipa_ep_idx;
+ INIT_DELAYED_WORK(&ipa_ctx->sys[sys_idx].switch_to_intr_work,
+ switch_to_intr_tx_work_func);
+ break;
case 3:
sys_idx = ipa_ep_idx;
INIT_DELAYED_WORK(&replenish_rx_work, replenish_rx_work_func);
- INIT_DELAYED_WORK(&switch_to_intr_work,
- switch_to_intr_work_func);
+ INIT_DELAYED_WORK(&ipa_ctx->sys[sys_idx].switch_to_intr_work,
+ switch_to_intr_rx_work_func);
break;
case WLAN_AMPDU_TX_EP:
sys_idx = IPA_A5_WLAN_AMPDU_OUT;
@@ -886,7 +1087,10 @@
ipa_ctx->sys[sys_idx].event.callback =
IPA_CLIENT_IS_CONS(sys_in->client) ?
ipa_sps_irq_rx_notify :
- ipa_sps_irq_tx_notify;
+ (sys_in->client ==
+ IPA_CLIENT_A5_LAN_WAN_PROD ?
+ ipa_sps_irq_tx_notify :
+ ipa_sps_irq_tx_no_aggr_notify);
result = sps_register_event(ipa_ctx->ep[ipa_ep_idx].ep_hdl,
&ipa_ctx->sys[sys_idx].event);
if (result < 0) {
@@ -1078,37 +1282,9 @@
}
EXPORT_SYMBOL(ipa_tx_dp);
-static void ipa_handle_rx(void)
-{
- int inactive_cycles = 0;
- int cnt;
-
- ipa_inc_client_enable_clks();
- do {
- cnt = ipa_handle_rx_core(true, true);
- if (cnt == 0) {
- inactive_cycles++;
- usleep_range(POLLING_MIN_SLEEP, POLLING_MAX_SLEEP);
- } else {
- inactive_cycles = 0;
- }
- } while (inactive_cycles <= POLLING_INACTIVITY);
-
- ipa_rx_switch_to_intr_mode();
- ipa_dec_client_disable_clks();
-}
-
-/**
- * ipa_handle_rx() - handle packet reception. This function is executed in the
- * context of a work queue.
- * @work: work struct needed by the work queue
- *
- * ipa_handle_rx_core() is run in polling mode. After all packets has been
- * received, the driver switches back to interrupt mode.
- */
static void ipa_wq_handle_rx(struct work_struct *work)
{
- ipa_handle_rx();
+ ipa_handle_rx(&ipa_ctx->sys[IPA_A5_LAN_WAN_IN]);
}
/**
@@ -1202,11 +1378,6 @@
ipa_replenish_rx_cache();
}
-static void switch_to_intr_work_func(struct work_struct *work)
-{
- ipa_handle_rx();
-}
-
/**
* ipa_cleanup_rx() - release RX queue resources
*
diff --git a/drivers/platform/msm/ipa/ipa_i.h b/drivers/platform/msm/ipa/ipa_i.h
index cc3e630..b57194e 100644
--- a/drivers/platform/msm/ipa/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_i.h
@@ -372,7 +372,6 @@
* @spinlock: protects the list and its size
* @event: used to request CALLBACK mode from SPS driver
* @ep: IPA EP context
- * @wait_desc_list: used to hold completed Tx packets
*
* IPA context specific to the system-bam pipes a.k.a LAN IN/OUT and WAN
*/
@@ -382,7 +381,8 @@
spinlock_t spinlock;
struct sps_register_event event;
struct ipa_ep_context *ep;
- struct list_head wait_desc_list;
+ atomic_t curr_polling_state;
+ struct delayed_work switch_to_intr_work;
};
/**
@@ -479,6 +479,14 @@
* @is_sys_mem: flag indicating if NAT memory is sys memory
* @is_dev_init: flag indicating if NAT device is initialized
* @lock: NAT memory mutex
+ * @nat_base_address: nat table virutal address
+ * @ipv4_rules_addr: base nat table address
+ * @ipv4_expansion_rules_addr: expansion table address
+ * @index_table_addr: index table address
+ * @index_table_expansion_addr: index expansion table address
+ * @size_base_tables: base table size
+ * @size_expansion_tables: expansion table size
+ * @public_ip_addr: ip address of nat table
*/
struct ipa_nat_mem {
struct class *class;
@@ -492,6 +500,14 @@
bool is_sys_mem;
bool is_dev_init;
struct mutex lock;
+ void *nat_base_address;
+ char *ipv4_rules_addr;
+ char *ipv4_expansion_rules_addr;
+ char *index_table_addr;
+ char *index_table_expansion_addr;
+ u32 size_base_tables;
+ u32 size_expansion_tables;
+ u32 public_ip_addr;
};
/**
@@ -530,6 +546,7 @@
u32 bridged_pkts[IPA_BRIDGE_TYPE_MAX][IPA_BRIDGE_DIR_MAX];
u32 rx_repl_repost;
u32 x_intr_repost;
+ u32 x_intr_repost_tx;
u32 rx_q_len;
u32 msg_w[IPA_EVENT_MAX];
u32 msg_r[IPA_EVENT_MAX];
@@ -641,7 +658,6 @@
uint aggregation_type;
uint aggregation_byte_limit;
uint aggregation_time_limit;
- atomic_t curr_polling_state;
struct delayed_work poll_work;
bool hdr_tbl_lcl;
struct ipa_mem_buffer hdr_mem;
@@ -800,7 +816,10 @@
void ipa_cleanup_rx(void);
int ipa_cfg_filter(u32 disable);
void ipa_wq_write_done(struct work_struct *work);
-int ipa_handle_rx_core(bool process_all, bool in_poll_state);
+int ipa_handle_rx_core(struct ipa_sys_context *sys, bool process_all,
+ bool in_poll_state);
+int ipa_handle_tx_core(struct ipa_sys_context *sys, bool process_all,
+ bool in_poll_state);
int ipa_pipe_mem_init(u32 start_ofst, u32 size);
int ipa_pipe_mem_alloc(u32 *ofst, u32 size);
int ipa_pipe_mem_free(u32 ofst, u32 size);
diff --git a/drivers/platform/msm/ipa/ipa_nat.c b/drivers/platform/msm/ipa/ipa_nat.c
index befa2cf..e2c344f 100644
--- a/drivers/platform/msm/ipa/ipa_nat.c
+++ b/drivers/platform/msm/ipa/ipa_nat.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -75,6 +75,7 @@
IPAERR("unable to map memory. Err:%d\n", result);
goto bail;
}
+ ipa_ctx->nat_mem.nat_base_address = nat_ctx->vaddr;
} else {
IPADBG("Mapping shared(local) memory\n");
IPADBG("map sz=0x%lx\n", vsize);
@@ -88,7 +89,7 @@
result = -EAGAIN;
goto bail;
}
-
+ ipa_ctx->nat_mem.nat_base_address = (void *)vma->vm_start;
}
nat_ctx->is_mapped = true;
vma->vm_ops = &ipa_nat_remap_vm_ops;
@@ -299,6 +300,35 @@
goto free_cmd;
}
+ ipa_ctx->nat_mem.public_ip_addr = init->ip_addr;
+ IPADBG("Table ip address:0x%x", ipa_ctx->nat_mem.public_ip_addr);
+
+ ipa_ctx->nat_mem.ipv4_rules_addr =
+ (char *)ipa_ctx->nat_mem.nat_base_address + init->ipv4_rules_offset;
+ IPADBG("ipv4_rules_addr: 0x%p\n",
+ ipa_ctx->nat_mem.ipv4_rules_addr);
+
+ ipa_ctx->nat_mem.ipv4_expansion_rules_addr =
+ (char *)ipa_ctx->nat_mem.nat_base_address + init->expn_rules_offset;
+ IPADBG("ipv4_expansion_rules_addr: 0x%p\n",
+ ipa_ctx->nat_mem.ipv4_expansion_rules_addr);
+
+ ipa_ctx->nat_mem.index_table_addr =
+ (char *)ipa_ctx->nat_mem.nat_base_address + init->index_offset;
+ IPADBG("index_table_addr: 0x%p\n",
+ ipa_ctx->nat_mem.index_table_addr);
+
+ ipa_ctx->nat_mem.index_table_expansion_addr =
+ (char *)ipa_ctx->nat_mem.nat_base_address + init->index_expn_offset;
+ IPADBG("index_table_expansion_addr: 0x%p\n",
+ ipa_ctx->nat_mem.index_table_expansion_addr);
+
+ IPADBG("size_base_tables: %d\n", init->table_entries);
+ ipa_ctx->nat_mem.size_base_tables = init->table_entries;
+
+ IPADBG("size_expansion_tables: %d\n", init->expn_table_entries);
+ ipa_ctx->nat_mem.size_expansion_tables = init->expn_table_entries;
+
IPADBG("return\n");
result = 0;
free_cmd:
diff --git a/drivers/platform/msm/ipa/ipa_rm.c b/drivers/platform/msm/ipa/ipa_rm.c
index 1fdd300..88a49c4 100644
--- a/drivers/platform/msm/ipa/ipa_rm.c
+++ b/drivers/platform/msm/ipa/ipa_rm.c
@@ -21,6 +21,7 @@
struct ipa_rm_context_type {
struct ipa_rm_dep_graph *dep_graph;
struct workqueue_struct *ipa_rm_wq;
+ rwlock_t lock;
};
static struct ipa_rm_context_type *ipa_rm_ctx;
@@ -41,10 +42,9 @@
struct ipa_rm_resource *resource;
int result;
- if (!create_params) {
- result = -EINVAL;
- goto bail;
- }
+ if (!create_params)
+ return -EINVAL;
+ write_lock(&ipa_rm_ctx->lock);
if (ipa_rm_dep_graph_get_resource(ipa_rm_ctx->dep_graph,
create_params->name,
&resource) == 0) {
@@ -59,11 +59,51 @@
if (result)
ipa_rm_resource_delete(resource);
bail:
+ write_unlock(&ipa_rm_ctx->lock);
return result;
}
EXPORT_SYMBOL(ipa_rm_create_resource);
/**
+ * ipa_rm_delete_resource() - delete resource
+ * @resource_name: name of resource to be deleted
+ *
+ * Returns: 0 on success, negative on failure
+ *
+ * This function is called by IPA RM client to delete client's resources.
+ *
+ */
+int ipa_rm_delete_resource(enum ipa_rm_resource_name resource_name)
+{
+ struct ipa_rm_resource *resource;
+ int result;
+
+ IPADBG("IPA RM ::ipa_rm_delete_resource num[%d] ENTER\n",
+ resource_name);
+ write_lock(&ipa_rm_ctx->lock);
+ if (ipa_rm_dep_graph_get_resource(ipa_rm_ctx->dep_graph,
+ resource_name,
+ &resource) != 0) {
+ IPADBG("ipa_rm_delete_resource param are bad********\n");
+ result = -EINVAL;
+ goto bail;
+ }
+ result = ipa_rm_resource_delete(resource);
+ if (result) {
+ IPADBG("error in ipa_rm_resource_delete\n");
+ goto bail;
+ }
+ result = ipa_rm_dep_graph_remove(ipa_rm_ctx->dep_graph,
+ resource_name);
+ IPADBG("IPA RM ::ipa_rm_delete_resource [%d] SUCCESS\n",
+ resource_name);
+bail:
+ write_unlock(&ipa_rm_ctx->lock);
+ return result;
+}
+EXPORT_SYMBOL(ipa_rm_delete_resource);
+
+/**
* ipa_rm_add_dependency() - create dependency
* between 2 resources
* @resource_name: name of dependent resource
@@ -77,13 +117,19 @@
int ipa_rm_add_dependency(enum ipa_rm_resource_name resource_name,
enum ipa_rm_resource_name depends_on_name)
{
- return ipa_rm_dep_graph_add_dependency(
- ipa_rm_ctx->dep_graph,
- resource_name,
- depends_on_name);
+ int result;
+
+ read_lock(&ipa_rm_ctx->lock);
+ result = ipa_rm_dep_graph_add_dependency(
+ ipa_rm_ctx->dep_graph,
+ resource_name,
+ depends_on_name);
+ read_unlock(&ipa_rm_ctx->lock);
+ return result;
}
EXPORT_SYMBOL(ipa_rm_add_dependency);
+
/**
* ipa_rm_delete_dependency() - create dependency
* between 2 resources
@@ -98,10 +144,14 @@
int ipa_rm_delete_dependency(enum ipa_rm_resource_name resource_name,
enum ipa_rm_resource_name depends_on_name)
{
- return ipa_rm_dep_graph_delete_dependency(
- ipa_rm_ctx->dep_graph,
- resource_name,
- depends_on_name);
+ int result;
+ read_lock(&ipa_rm_ctx->lock);
+ result = ipa_rm_dep_graph_delete_dependency(
+ ipa_rm_ctx->dep_graph,
+ resource_name,
+ depends_on_name);
+ read_unlock(&ipa_rm_ctx->lock);
+ return result;
}
EXPORT_SYMBOL(ipa_rm_delete_dependency);
@@ -120,10 +170,9 @@
int result;
IPADBG("IPA RM ::ipa_rm_request_resource ENTER\n");
- if (!IPA_RM_RESORCE_IS_PROD(resource_name)) {
- result = -EINVAL;
- goto bail;
- }
+ if (!IPA_RM_RESORCE_IS_PROD(resource_name))
+ return -EINVAL;
+ read_lock(&ipa_rm_ctx->lock);
if (ipa_rm_dep_graph_get_resource(ipa_rm_ctx->dep_graph,
resource_name,
&resource) != 0) {
@@ -136,6 +185,7 @@
bail:
IPADBG("IPA RM ::ipa_rm_request_resource EXIT [%d]\n", result);
+ read_unlock(&ipa_rm_ctx->lock);
return result;
}
EXPORT_SYMBOL(ipa_rm_request_resource);
@@ -155,10 +205,9 @@
int result;
IPADBG("IPA RM ::ipa_rm_release_resource ENTER\n");
- if (!IPA_RM_RESORCE_IS_PROD(resource_name)) {
- result = -EINVAL;
- goto bail;
- }
+ if (!IPA_RM_RESORCE_IS_PROD(resource_name))
+ return -EINVAL;
+ read_lock(&ipa_rm_ctx->lock);
if (ipa_rm_dep_graph_get_resource(ipa_rm_ctx->dep_graph,
resource_name,
&resource) != 0) {
@@ -170,6 +219,7 @@
bail:
IPADBG("IPA RM ::ipa_rm_release_resource EXIT [%d]\n", result);
+ read_unlock(&ipa_rm_ctx->lock);
return result;
}
EXPORT_SYMBOL(ipa_rm_release_resource);
@@ -189,10 +239,10 @@
{
int result;
struct ipa_rm_resource *resource;
- if (!IPA_RM_RESORCE_IS_PROD(resource_name)) {
- result = -EINVAL;
- goto bail;
- }
+
+ if (!IPA_RM_RESORCE_IS_PROD(resource_name))
+ return -EINVAL;
+ read_lock(&ipa_rm_ctx->lock);
if (ipa_rm_dep_graph_get_resource(ipa_rm_ctx->dep_graph,
resource_name,
&resource) != 0) {
@@ -203,6 +253,7 @@
(struct ipa_rm_resource_prod *)resource,
reg_params);
bail:
+ read_unlock(&ipa_rm_ctx->lock);
return result;
}
EXPORT_SYMBOL(ipa_rm_register);
@@ -222,10 +273,10 @@
{
int result;
struct ipa_rm_resource *resource;
- if (!IPA_RM_RESORCE_IS_PROD(resource_name)) {
- result = -EINVAL;
- goto bail;
- }
+
+ if (!IPA_RM_RESORCE_IS_PROD(resource_name))
+ return -EINVAL;
+ read_lock(&ipa_rm_ctx->lock);
if (ipa_rm_dep_graph_get_resource(ipa_rm_ctx->dep_graph,
resource_name,
&resource) != 0) {
@@ -236,6 +287,7 @@
(struct ipa_rm_resource_prod *)resource,
reg_params);
bail:
+ read_unlock(&ipa_rm_ctx->lock);
return result;
}
EXPORT_SYMBOL(ipa_rm_deregister);
@@ -278,25 +330,32 @@
case IPA_RM_WQ_NOTIFY_PROD:
if (!IPA_RM_RESORCE_IS_PROD(ipa_rm_work->resource_name))
return;
+ read_lock(&ipa_rm_ctx->lock);
if (ipa_rm_dep_graph_get_resource(ipa_rm_ctx->dep_graph,
ipa_rm_work->resource_name,
- &resource) != 0)
+ &resource) != 0){
+ read_unlock(&ipa_rm_ctx->lock);
return;
+ }
ipa_rm_resource_producer_notify_clients(
(struct ipa_rm_resource_prod *)resource,
ipa_rm_work->event);
-
+ read_unlock(&ipa_rm_ctx->lock);
break;
case IPA_RM_WQ_NOTIFY_CONS:
break;
case IPA_RM_WQ_RESOURCE_CB:
+ read_lock(&ipa_rm_ctx->lock);
if (ipa_rm_dep_graph_get_resource(ipa_rm_ctx->dep_graph,
ipa_rm_work->resource_name,
- &resource) != 0)
+ &resource) != 0){
+ read_unlock(&ipa_rm_ctx->lock);
return;
+ }
ipa_rm_resource_consumer_handle_cb(
(struct ipa_rm_resource_cons *)resource,
ipa_rm_work->event);
+ read_unlock(&ipa_rm_ctx->lock);
break;
default:
break;
@@ -351,6 +410,7 @@
result = ipa_rm_dep_graph_create(&(ipa_rm_ctx->dep_graph));
if (result)
goto graph_alloc_fail;
+ rwlock_init(&ipa_rm_ctx->lock);
IPADBG("IPA RM ipa_rm_initialize SUCCESS\n");
return 0;
diff --git a/drivers/platform/msm/ipa/ipa_rm_dependency_graph.c b/drivers/platform/msm/ipa/ipa_rm_dependency_graph.c
index 6afab42..8144a42 100644
--- a/drivers/platform/msm/ipa/ipa_rm_dependency_graph.c
+++ b/drivers/platform/msm/ipa/ipa_rm_dependency_graph.c
@@ -39,7 +39,6 @@
result = -ENOMEM;
goto bail;
}
- rwlock_init(&((*dep_graph)->lock));
bail:
return result;
}
@@ -55,12 +54,10 @@
int resource_index;
if (!graph)
return;
- write_lock(&graph->lock);
for (resource_index = 0;
resource_index < IPA_RM_RESOURCE_MAX;
resource_index++)
kfree(graph->resource_table[resource_index]);
- write_unlock(&graph->lock);
memset(graph->resource_table, 0, sizeof(graph->resource_table));
}
@@ -88,9 +85,7 @@
result = -EINVAL;
goto bail;
}
- read_lock(&graph->lock);
*resource = graph->resource_table[resource_index];
- read_unlock(&graph->lock);
if (!*resource) {
result = -EINVAL;
goto bail;
@@ -112,6 +107,7 @@
{
int result = 0;
int resource_index;
+
if (!graph || !resource) {
result = -EINVAL;
goto bail;
@@ -121,14 +117,29 @@
result = -EINVAL;
goto bail;
}
- write_lock(&graph->lock);
graph->resource_table[resource_index] = resource;
- write_unlock(&graph->lock);
bail:
return result;
}
/**
+ * ipa_rm_dep_graph_remove() - removes resource from graph
+ * @graph: [in] dependency graph
+ * @resource: [in] resource to add
+ *
+ * Returns: 0 on success, negative on failure
+ */
+int ipa_rm_dep_graph_remove(struct ipa_rm_dep_graph *graph,
+ enum ipa_rm_resource_name resource_name)
+{
+ if (!graph)
+ return -EINVAL;
+
+ graph->resource_table[resource_name] = NULL;
+ return 0;
+}
+
+/**
* ipa_rm_dep_graph_add_dependency() - adds dependency between
* two nodes in graph
* @graph: [in] dependency graph
diff --git a/drivers/platform/msm/ipa/ipa_rm_dependency_graph.h b/drivers/platform/msm/ipa/ipa_rm_dependency_graph.h
index 19d9461..4126819 100644
--- a/drivers/platform/msm/ipa/ipa_rm_dependency_graph.h
+++ b/drivers/platform/msm/ipa/ipa_rm_dependency_graph.h
@@ -19,7 +19,6 @@
struct ipa_rm_dep_graph {
struct ipa_rm_resource *resource_table[IPA_RM_RESOURCE_MAX];
- rwlock_t lock;
};
int ipa_rm_dep_graph_get_resource(
@@ -34,6 +33,9 @@
int ipa_rm_dep_graph_add(struct ipa_rm_dep_graph *graph,
struct ipa_rm_resource *resource);
+int ipa_rm_dep_graph_remove(struct ipa_rm_dep_graph *graph,
+ enum ipa_rm_resource_name resource_name);
+
int ipa_rm_dep_graph_add_dependency(struct ipa_rm_dep_graph *graph,
enum ipa_rm_resource_name resource_name,
enum ipa_rm_resource_name depends_on_name);
diff --git a/drivers/platform/msm/ipa/ipa_rm_resource.c b/drivers/platform/msm/ipa/ipa_rm_resource.c
index 3615952..0fc4826 100644
--- a/drivers/platform/msm/ipa/ipa_rm_resource.c
+++ b/drivers/platform/msm/ipa/ipa_rm_resource.c
@@ -80,8 +80,8 @@
int result = 0;
int driver_result;
unsigned long flags;
- IPADBG("IPA RM ::ipa_rm_resource_consumer_request %d ENTER\n",
- consumer->resource.name);
+ IPADBG("IPA RM ::%s name %d ENTER\n",
+ __func__, consumer->resource.name);
spin_lock_irqsave(&consumer->resource.state_lock, flags);
switch (consumer->resource.state) {
case IPA_RM_RELEASED:
@@ -115,8 +115,7 @@
consumer->usage_count++;
bail:
spin_unlock_irqrestore(&consumer->resource.state_lock, flags);
- IPADBG("IPA RM ::ipa_rm_resource_consumer_request %d EXIT %d\n",
- consumer->resource.name, result);
+ IPADBG("IPA RM ::ipa_rm_resource_consumer_request EXIT [%d]\n", result);
return result;
}
@@ -127,8 +126,8 @@
int driver_result;
unsigned long flags;
enum ipa_rm_resource_state save_state;
- IPADBG("IPA RM ::ipa_rm_resource_consumer_release %d ENTER\n",
- consumer->resource.name);
+ IPADBG("IPA RM ::%s name %d ENTER\n",
+ __func__, consumer->resource.name);
spin_lock_irqsave(&consumer->resource.state_lock, flags);
switch (consumer->resource.state) {
case IPA_RM_RELEASED:
@@ -163,8 +162,7 @@
}
bail:
spin_unlock_irqrestore(&consumer->resource.state_lock, flags);
- IPADBG("IPA RM ::ipa_rm_resource_consumer_release %d EXIT %d\n",
- consumer->resource.name, result);
+ IPADBG("IPA RM ::ipa_rm_resource_consumer_release EXIT [%d]\n", result);
return result;
}
@@ -332,19 +330,56 @@
* ipa_rm_resource_delete() - deletes resource
* @resource: [in] resource
* for resource initialization with IPA RM
+ *
+ * Returns: 0 on success, negative on failure
*/
-void ipa_rm_resource_delete(struct ipa_rm_resource *resource)
+int ipa_rm_resource_delete(struct ipa_rm_resource *resource)
{
- if (!resource)
- return;
- if (resource->peers_list)
- ipa_rm_peers_list_delete(resource->peers_list);
+ struct ipa_rm_resource *consumer, *producer;
+ int i, result = 0;
+
+ IPADBG("IPA RM: %s ENTER\n", __func__);
+
+ if (!resource) {
+ IPADBG("ipa_rm_resource_delete ENTER with invalid param\n");
+ return -EINVAL;
+ }
if (resource->type == IPA_RM_PRODUCER) {
+ if (resource->peers_list) {
+ for (i = IPA_RM_RESOURCE_PROD_MAX;
+ i < IPA_RM_RESOURCE_MAX;
+ ++i) {
+ consumer = ipa_rm_peers_list_get_resource(
+ i,
+ resource->peers_list);
+ if (consumer) {
+ ipa_rm_resource_delete_dependency(
+ resource,
+ consumer);
+ }
+ }
+ ipa_rm_peers_list_delete(resource->peers_list);
+ }
ipa_rm_resource_producer_delete(
(struct ipa_rm_resource_prod *) resource);
kfree((struct ipa_rm_resource_prod *) resource);
- } else
+ } else if (resource->type == IPA_RM_CONSUMER) {
+ if (resource->peers_list) {
+ for (i = 0; i < IPA_RM_RESOURCE_PROD_MAX; ++i) {
+ producer = ipa_rm_peers_list_get_resource(
+ i,
+ resource->peers_list);
+ if (producer)
+ ipa_rm_resource_delete_dependency(
+ producer,
+ resource);
+ }
+ ipa_rm_peers_list_delete(resource->peers_list);
+ }
kfree((struct ipa_rm_resource_cons *) resource);
+ }
+ IPADBG("ipa_rm_resource_delete SUCCESS\n");
+ return result;
}
/**
@@ -367,6 +402,8 @@
result = -EPERM;
goto bail;
}
+ IPADBG("IPA RM: %s name %d ENTER\n",
+ __func__, producer->resource.name);
read_lock(&producer->event_listeners_lock);
list_for_each(pos, &(producer->event_listeners)) {
reg_info = list_entry(pos,
@@ -511,6 +548,10 @@
unsigned long flags;
if (!resource || !depends_on)
return -EINVAL;
+ IPADBG("IPA RM: %s from %d to %d ENTER\n",
+ __func__,
+ resource->name,
+ depends_on->name);
if (!ipa_rm_peers_list_check_dependency(resource->peers_list,
resource->name,
depends_on->peers_list,
@@ -539,8 +580,6 @@
goto bail;
}
spin_unlock_irqrestore(&resource->state_lock, flags);
- (void) ipa_rm_resource_consumer_release(
- (struct ipa_rm_resource_cons *)depends_on);
if (ipa_rm_peers_list_has_last_peer(resource->peers_list)) {
(void) ipa_rm_wq_send_cmd(IPA_RM_WQ_NOTIFY_PROD,
resource->name,
@@ -551,6 +590,12 @@
depends_on->name);
ipa_rm_peers_list_remove_peer(depends_on->peers_list,
resource->name);
+ (void) ipa_rm_resource_consumer_release(
+ (struct ipa_rm_resource_cons *)depends_on);
+ IPADBG("IPA RM: %s from %d to %d SUCCESS\n",
+ __func__,
+ resource->name,
+ depends_on->name);
bail:
return result;
}
@@ -568,7 +613,7 @@
unsigned long flags;
struct ipa_rm_resource *consumer;
int consumer_result;
- IPADBG("IPA RM ::ipa_rm_resource_producer_request %d ENTER\n",
+ IPADBG("IPA RM ::ipa_rm_resource_producer_request [%d] ENTER\n",
producer->resource.name);
if (ipa_rm_peers_list_is_empty(producer->resource.peers_list)) {
spin_lock_irqsave(&producer->resource.state_lock, flags);
@@ -628,12 +673,11 @@
if (producer->pending_request == 0)
producer->resource.state = IPA_RM_GRANTED;
spin_unlock_irqrestore(&producer->resource.state_lock, flags);
- return result;
+ goto bail;
unlock_and_bail:
spin_unlock_irqrestore(&producer->resource.state_lock, flags);
bail:
- IPADBG("IPA RM ::ipa_rm_resource_producer_request %d EXIT %d\n",
- producer->resource.name, result);
+ IPADBG("IPA RM ::ipa_rm_resource_producer_request EXIT[%d]\n", result);
return result;
}
@@ -651,8 +695,9 @@
unsigned long flags;
struct ipa_rm_resource *consumer;
int consumer_result;
- IPADBG("IPA RM ::ipa_rm_resource_producer_release %d ENTER\n",
- producer->resource.name);
+ IPADBG("IPA RM: %s name %d ENTER\n",
+ __func__,
+ producer->resource.name);
if (ipa_rm_peers_list_is_empty(producer->resource.peers_list)) {
spin_lock_irqsave(&producer->resource.state_lock, flags);
producer->resource.state = IPA_RM_RELEASED;
@@ -708,8 +753,7 @@
return result;
bail:
spin_unlock_irqrestore(&producer->resource.state_lock, flags);
- IPADBG("IPA RM ::ipa_rm_resource_producer_release %d EXIT %d\n",
- producer->resource.name, result);
+ IPADBG("IPA RM ::ipa_rm_resource_producer_release EXIT[%d]\n", result);
return result;
}
diff --git a/drivers/platform/msm/ipa/ipa_rm_resource.h b/drivers/platform/msm/ipa/ipa_rm_resource.h
index b9c2e91..81ccc53 100644
--- a/drivers/platform/msm/ipa/ipa_rm_resource.h
+++ b/drivers/platform/msm/ipa/ipa_rm_resource.h
@@ -99,7 +99,7 @@
struct ipa_rm_create_params *create_params,
struct ipa_rm_resource **resource);
-void ipa_rm_resource_delete(struct ipa_rm_resource *resource);
+int ipa_rm_resource_delete(struct ipa_rm_resource *resource);
int ipa_rm_resource_producer_register(struct ipa_rm_resource_prod *producer,
struct ipa_rm_register_params *reg_params);
diff --git a/drivers/platform/msm/ipa/teth_bridge.c b/drivers/platform/msm/ipa/teth_bridge.c
index 40c8fc7..9062ab8 100644
--- a/drivers/platform/msm/ipa/teth_bridge.c
+++ b/drivers/platform/msm/ipa/teth_bridge.c
@@ -69,6 +69,13 @@
#define TETH_TOTAL_FLT_ENTRIES_IP 2
#define TETH_IP_FAMILIES 2
+/**
+ * struct mac_addresses_type - store host PC and device MAC addresses
+ * @host_pc_mac_addr: MAC address of the host PC
+ * @host_pc_mac_addr_known: is the MAC address of the host PC known ?
+ * @device_mac_addr: MAC address of the device
+ * @device_mac_addr_known: is the MAC address of the device known ?
+ */
struct mac_addresses_type {
u8 host_pc_mac_addr[ETH_ALEN];
bool host_pc_mac_addr_known;
@@ -76,12 +83,59 @@
bool device_mac_addr_known;
};
+/**
+ * struct stats - driver statistics, viewable using debugfs
+ * @a2_to_usb_num_sw_tx_packets: number of packets bridged from A2 to USB using
+ * the SW bridge
+ * @usb_to_a2_num_sw_tx_packets: number of packets bridged from USB to A2 using
+ * the SW bridge
+ * @num_sw_tx_packets_during_resource_wakeup: number of packets bridged during a
+ * resource wakeup period, there is a special treatment for these kind of
+ * packets
+ */
struct stats {
u64 a2_to_usb_num_sw_tx_packets;
u64 usb_to_a2_num_sw_tx_packets;
u64 num_sw_tx_packets_during_resource_wakeup;
};
+/**
+ * struct teth_bridge_ctx - Tethering bridge driver context information
+ * @class: kernel class pointer
+ * @dev_num: kernel device number
+ * @dev: kernel device struct pointer
+ * @cdev: kernel character device struct
+ * @usb_ipa_pipe_hdl: USB to IPA pipe handle
+ * @ipa_usb_pipe_hdl: IPA to USB pipe handle
+ * @a2_ipa_pipe_hdl: A2 to IPA pipe handle
+ * @ipa_a2_pipe_hdl: IPA to A2 pipe handle
+ * @is_connected: is the tethered bridge connected ?
+ * @link_protocol: IP / Ethernet
+ * @mac_addresses: Struct which holds host pc and device MAC addresses, relevant
+ * in ethernet mode only
+ * @is_hw_bridge_complete: is HW bridge setup ?
+ * @aggr_params: aggregation parmeters
+ * @aggr_params_known: are the aggregation parameters known ?
+ * @tethering_mode: Rmnet / MBIM
+ * @is_bridge_prod_up: completion object signaled when the bridge producer
+ * finished its resource request procedure
+ * @is_bridge_prod_down: completion object signaled when the bridge producer
+ * finished its resource release procedure
+ * @comp_hw_bridge_work: used for setting up the HW bridge using a workqueue
+ * @comp_hw_bridge_in_progress: true when the HW bridge setup is in progress
+ * @aggr_caps: aggregation capabilities
+ * @stats: statistics, how many packets were transmitted using the SW bridge
+ * @teth_wq: dedicated workqueue, used for setting up the HW bridge and for
+ * sending packets using the SW bridge when the system is waking up from power
+ * collapse
+ * @a2_ipa_hdr_len: A2 to IPA header length, used to configure the A2 endpoint
+ * for header removal
+ * @hdr_del: array to store the headers handles in order to delete them later
+ * @routing_del: array of routing rules handles, one array for IPv4 and one for
+ * IPv6
+ * @filtering_del: array of routing rules handles, one array for IPv4 and one
+ * for IPv6
+ */
struct teth_bridge_ctx {
struct class *class;
dev_t dev_num;
@@ -117,6 +171,12 @@
TETH_A2_TO_USB,
};
+/**
+ * struct teth_work - wrapper for an skb which is sent using a workqueue
+ * @work: used by the workqueue
+ * @skb: pointer to the skb to be sent
+ * @dir: direction of send, A2 to USB or USB to A2
+ */
struct teth_work {
struct work_struct work;
struct sk_buff *skb;
@@ -128,6 +188,15 @@
static char dbg_buff[TETH_MAX_MSG_LEN];
#endif
+/**
+ * add_eth_hdrs() - add Ethernet headers to IPA
+ * @hdr_name_ipv4: header name for IPv4
+ * @hdr_name_ipv6: header name for IPv6
+ * @src_mac_addr: source MAC address
+ * @dst_mac_addr: destination MAC address
+ *
+ * This function is called only when link protocol is Ethernet
+ */
static int add_eth_hdrs(char *hdr_name_ipv4, char *hdr_name_ipv6,
u8 *src_mac_addr, u8 *dst_mac_addr)
{
@@ -269,6 +338,12 @@
return res;
}
+/**
+ * configure_ipa_header_block() - adds headers and configures endpoint registers
+ *
+ * - For IP link protocol and MBIM aggregation, configure MBIM header
+ * - For Ethernet link protocol, configure Ethernet headers
+ */
static int configure_ipa_header_block(void)
{
int res;
@@ -412,6 +487,14 @@
return res;
}
+/**
+ * configure_ipa_routing_block() - Configure the IPA routing block
+ *
+ * This function configures IPA for:
+ * - Route all packets from USB to A2
+ * - Route all packets from A2 to USB
+ * - Use the correct headers in Ethernet or MBIM cases
+ */
static int configure_ipa_routing_block(void)
{
int res;
@@ -547,6 +630,13 @@
return res;
}
+/**
+ * configure_ipa_filtering_block() - Configures IPA filtering block
+ *
+ * This function configures IPA for:
+ * - Filter all traffic coming from USB to A2 pointing routing table
+ * - Filter all traffic coming from A2 to USB pointing routing table
+ */
static int configure_ipa_filtering_block(void)
{
int res;
@@ -663,6 +753,11 @@
}
}
+/**
+ * teth_set_aggregation() - set aggregation parameters to IPA
+ *
+ * The parameters to this function are passed in the context variable ipa_ctx.
+ */
static int teth_set_aggregation(void)
{
int res;
@@ -727,6 +822,14 @@
return res;
}
+/**
+ * teth_request_resource() - wrapper function to
+ * ipa_rm_inactivity_timer_request_resource()
+ *
+ * - initialize the is_bridge_prod_up completion object
+ * - request the resource
+ * - error handling
+ */
static int teth_request_resource(void)
{
int res;
@@ -744,6 +847,10 @@
return 0;
}
+/**
+ * complete_hw_bridge() - setup the HW bridge from USB to A2 and back through
+ * IPA
+ */
static void complete_hw_bridge(struct work_struct *work)
{
int res;
@@ -812,6 +919,20 @@
mac_addr[4], mac_addr[5]);
}
+/**
+ * check_to_complete_hw_bridge() - can HW bridge be set up ?
+ * @param skb: pointer to socket buffer
+ * @param my_mac_addr: pointer to write 'my' extracted MAC address to
+ * @param my_mac_addr_known: pointer to update whether 'my' extracted MAC
+ * address is known
+ * @param peer_mac_addr_known: pointer to update whether the 'peer' extracted
+ * MAC address is known
+ *
+ * This function is used by both A2 and USB callback functions, therefore the
+ * meaning of 'my' and 'peer' changes according to the context.
+ * Extracts MAC address from the packet in Ethernet link protocol,
+ * Sets up the HW bridge in case all conditions are met.
+ */
static void check_to_complete_hw_bridge(struct sk_buff *skb,
u8 *my_mac_addr,
bool *my_mac_addr_known,
@@ -841,6 +962,9 @@
}
}
+/**
+ * teth_send_skb_work() - workqueue function for sending a packet
+ */
static void teth_send_skb_work(struct work_struct *work)
{
struct teth_work *work_data =
@@ -887,6 +1011,15 @@
kfree(work_data);
}
+/**
+ * defer_skb_send() - defer sending an skb using the SW bridge to a workqueue
+ * @param skb: pointer to the socket buffer
+ * @param dir: direction of send
+ *
+ * In case where during a packet send, the A2 or USB needs to wake up from power
+ * collapse, defer the send and return the context to IPA driver. This is
+ * important since IPA driver has a single threaded Rx path.
+ */
static void defer_skb_send(struct sk_buff *skb, enum teth_packet_direction dir)
{
struct teth_work *work = kmalloc(sizeof(struct teth_work), GFP_KERNEL);
@@ -909,6 +1042,30 @@
queue_work(teth_ctx->teth_wq, &work->work);
}
+/**
+ * usb_notify_cb() - callback function for sending packets from USB to A2
+ * @param priv: private data
+ * @param evt: event - RECEIVE or WRITE_DONE
+ * @param data: pointer to skb to be sent
+ *
+ * This callback function is installed by the IPA driver, it is invoked in 2
+ * cases:
+ * 1. When a packet comes from the USB pipe and is routed to A5 (SW bridging)
+ * 2. After a packet has been bridged from USB to A2 and its skb should be freed
+ *
+ * Invocation: sps driver --> IPA driver --> bridge driver
+ *
+ * In the event of IPA_RECEIVE:
+ * - Checks whether the HW bridge can be set up..
+ * - Requests the BRIDGE_PROD resource so that A2 and USB are not in power
+ * collapse. In case where the resource is waking up, defer the send operation
+ * to a workqueue in order to not block the IPA driver single threaded Rx path.
+ * - Sends the packets to A2 using a2_service driver API.
+ * - Releases the BRIDGE_PROD resource.
+ *
+ * In the event of IPA_WRITE_DONE:
+ * - Frees the skb memory
+ */
static void usb_notify_cb(void *priv,
enum ipa_dp_evt_type evt,
unsigned long data)
@@ -969,6 +1126,30 @@
return;
}
+/**
+ * a2_notify_cb() - callback function for sending packets from A2 to USB
+ * @param user_data: private data
+ * @param event: event - RECEIVE or WRITE_DONE
+ * @param data: pointer to skb to be sent
+ *
+ * This callback function is installed by the IPA driver, it is invoked in 2
+ * cases:
+ * 1. When a packet comes from the A2 pipe and is routed to A5 (SW bridging)
+ * 2. After a packet has been bridged from A2 to USB and its skb should be freed
+ *
+ * Invocation: sps driver --> IPA driver --> a2_service driver --> bridge driver
+ *
+ * In the event of A2_MUX_RECEIVE:
+ * - Checks whether the HW bridge can be set up..
+ * - Requests the BRIDGE_PROD resource so that A2 and USB are not in power
+ * collapse. In case where the resource is waking up, defer the send operation
+ * to a workqueue in order to not block the IPA driver single threaded Rx path.
+ * - Sends the packets to USB using IPA drivers ipa_tx_dp() API.
+ * - Releases the BRIDGE_PROD resource.
+ *
+ * In the event of A2_MUX_WRITE_DONE:
+ * - Frees the skb memory
+ */
static void a2_notify_cb(void *user_data,
enum a2_mux_event_type event,
unsigned long data)
@@ -1031,6 +1212,15 @@
return;
}
+/**
+ * bridge_prod_notify_cb() - IPA Resource Manager callback function
+ * @param notify_cb_data: private data
+ * @param event: RESOURCE_GRANTED / RESOURCE_RELEASED
+ * @param data: not used in this case
+ *
+ * This callback function is called by IPA resource manager to notify the
+ * BRIDGE_PROD entity of events like RESOURCE_GRANTED and RESOURCE_RELEASED.
+ */
static void bridge_prod_notify_cb(void *notify_cb_data,
enum ipa_rm_event event,
unsigned long data)
@@ -1075,10 +1265,17 @@
/**
* teth_bridge_init() - Initialize the Tethering bridge driver
-* @usb_notify_cb_ptr: Callback function which should be used
-* by the caller. Output parameter.
-* @private_data_ptr: Data for the callback function. Should
-* be used by the caller. Output parameter.
+* @usb_notify_cb_ptr: Callback function which should be used by the caller.
+* Output parameter.
+* @private_data_ptr: Data for the callback function. Should be used by the
+* caller. Output parameter.
+*
+* USB driver gets a pointer to a callback function (usb_notify_cb) and an
+* associated data. USB driver installs this callback function in the call to
+* ipa_connect().
+*
+* Builds IPA resource manager dependency graph.
+*
* Return codes: 0: success,
* -EINVAL - Bad parameter
* Other negative value - Failure
@@ -1145,6 +1342,9 @@
}
EXPORT_SYMBOL(teth_bridge_init);
+/**
+ * initialize_context() - Initialize the ipa_ctx struct
+ */
static void initialize_context(void)
{
TETH_DBG_FUNC_ENTRY();
@@ -1198,10 +1398,6 @@
/**
* teth_bridge_disconnect() - Disconnect tethering bridge module
-*
-* Return codes: 0: success
-* -EPERM: Operation not permitted as the bridge is already
-* disconnected
*/
int teth_bridge_disconnect(void)
{
@@ -1214,19 +1410,38 @@
goto bail;
}
- /* Request the BRIDGE_PROD resource */
+ /*
+ * Delete part of IPA resource manager dependency graph. Only the
+ * BRIDGE_PROD <-> A2 dependency remains intact
+ */
+ res = ipa_rm_delete_dependency(IPA_RM_RESOURCE_BRIDGE_PROD,
+ IPA_RM_RESOURCE_USB_CONS);
+ if ((res != 0) && (res != -EINPROGRESS))
+ TETH_ERR(
+ "Failed deleting ipa_rm dependency BRIDGE_PROD <-> USB_CONS\n");
+ res = ipa_rm_delete_dependency(IPA_RM_RESOURCE_USB_PROD,
+ IPA_RM_RESOURCE_A2_CONS);
+ if ((res != 0) && (res != -EINPROGRESS))
+ TETH_ERR(
+ "Failed deleting ipa_rm dependency USB_PROD <-> A2_CONS\n");
+ res = ipa_rm_delete_dependency(IPA_RM_RESOURCE_A2_PROD,
+ IPA_RM_RESOURCE_USB_CONS);
+ if ((res != 0) && (res != -EINPROGRESS))
+ TETH_ERR(
+ "Failed deleting ipa_rm dependency A2_PROD <-> USB_CONS\n");
+
+ /* Request the BRIDGE_PROD resource, A2 and IPA should power up */
res = teth_request_resource();
if (res) {
TETH_ERR("request_resource() failed.\n");
goto bail;
}
- teth_ctx->is_connected = false;
-
/* Close the channel to A2 */
if (a2_mux_close_channel(A2_MUX_TETHERED_0))
TETH_ERR("a2_mux_close_channel() failed\n");
+ /* Teardown the IPA HW bridge */
if (teth_ctx->is_hw_bridge_complete) {
/* Delete header entries */
if (ipa_del_hdr(teth_ctx->hdr_del))
@@ -1256,27 +1471,14 @@
ipa_rm_inactivity_timer_release_resource(IPA_RM_RESOURCE_BRIDGE_PROD);
- /* Delete IPA Resource manager dependency graph */
- res = ipa_rm_delete_dependency(IPA_RM_RESOURCE_BRIDGE_PROD,
- IPA_RM_RESOURCE_USB_CONS);
- if ((res != 0) && (res != -EINPROGRESS))
- TETH_ERR(
- "Failed deleting ipa_rm dependency BRIDGE_PROD <-> USB_CONS\n");
+ /* Delete the last ipa_rm dependency - BRIDGE_PROD <-> A2 */
res = ipa_rm_delete_dependency(IPA_RM_RESOURCE_BRIDGE_PROD,
IPA_RM_RESOURCE_A2_CONS);
if ((res != 0) && (res != -EINPROGRESS))
TETH_ERR(
"Failed deleting ipa_rm dependency BRIDGE_PROD <-> A2_CONS\n");
- res = ipa_rm_delete_dependency(IPA_RM_RESOURCE_USB_PROD,
- IPA_RM_RESOURCE_A2_CONS);
- if ((res != 0) && (res != -EINPROGRESS))
- TETH_ERR(
- "Failed deleting ipa_rm dependency USB_PROD <-> A2_CONS\n");
- res = ipa_rm_delete_dependency(IPA_RM_RESOURCE_A2_PROD,
- IPA_RM_RESOURCE_USB_CONS);
- if ((res != 0) && (res != -EINPROGRESS))
- TETH_ERR(
- "Failed deleting ipa_rm dependency A2_PROD <-> USB_CONS\n");
+
+ teth_ctx->is_connected = false;
bail:
TETH_DBG_FUNC_EXIT();
@@ -1384,6 +1586,9 @@
TETH_AGGR_MAX_AGGR_PACKET_SIZE_DEFAULT;
}
+/**
+ * teth_set_bridge_mode() - set the link protocol (IP / Ethernet)
+ */
static void teth_set_bridge_mode(enum teth_link_protocol_type link_protocol)
{
teth_ctx->link_protocol = link_protocol;
@@ -1391,6 +1596,14 @@
memset(&teth_ctx->mac_addresses, 0, sizeof(teth_ctx->mac_addresses));
}
+/**
+ * teth_bridge_set_aggr_params() - kernel API to set aggregation parameters
+ * @param aggr_params: aggregation parmeters for uplink and downlink
+ *
+ * Besides setting the aggregation parameters, the function enforces max tranfer
+ * size which is less then 8K and also forbids Ethernet link protocol with MBIM
+ * aggregation which is not supported by HW.
+ */
int teth_bridge_set_aggr_params(struct teth_aggr_params *aggr_params)
{
int res;
@@ -1540,6 +1753,10 @@
return res;
}
+/**
+ * set_aggr_capabilities() - allocates and fills the aggregation capabilities
+ * struct
+ */
static int set_aggr_capabilities(void)
{
u16 NUM_PROTOCOLS = 2;
diff --git a/drivers/power/qpnp-bms.c b/drivers/power/qpnp-bms.c
index fd42c47..866b921 100644
--- a/drivers/power/qpnp-bms.c
+++ b/drivers/power/qpnp-bms.c
@@ -375,7 +375,7 @@
#define CC_READING_RESOLUTION_N 542535
#define CC_READING_RESOLUTION_D 100000
-static int cc_reading_to_uv(int16_t reading)
+static s64 cc_reading_to_uv(s64 reading)
{
return div_s64(reading * CC_READING_RESOLUTION_N,
CC_READING_RESOLUTION_D);
@@ -582,7 +582,7 @@
return false;
}
-static bool is_batfet_open(struct qpnp_bms_chip *chip)
+static bool is_battery_full(struct qpnp_bms_chip *chip)
{
union power_supply_propval ret = {0,};
@@ -610,18 +610,32 @@
iadc_channel = chip->use_external_rsense ?
EXTERNAL_RSENSE : INTERNAL_RSENSE;
- rc = qpnp_iadc_vadc_sync_read(iadc_channel, &i_result,
- VBAT_SNS, &v_result);
- if (rc) {
- pr_err("vadc read failed with rc: %d\n", rc);
- return rc;
+ if (is_battery_full(chip)) {
+ rc = get_battery_current(chip, ibat_ua);
+ if (rc) {
+ pr_err("bms current read failed with rc: %d\n", rc);
+ return rc;
+ }
+ rc = qpnp_vadc_read(VBAT_SNS, &v_result);
+ if (rc) {
+ pr_err("vadc read failed with rc: %d\n", rc);
+ return rc;
+ }
+ *vbat_uv = (int)v_result.physical;
+ } else {
+ rc = qpnp_iadc_vadc_sync_read(iadc_channel, &i_result,
+ VBAT_SNS, &v_result);
+ if (rc) {
+ pr_err("adc sync read failed with rc: %d\n", rc);
+ return rc;
+ }
+ /*
+ * reverse the current read by the iadc, since the bms uses
+ * flipped battery current polarity.
+ */
+ *ibat_ua = -1 * (int)i_result.result_ua;
+ *vbat_uv = (int)v_result.physical;
}
- /*
- * reverse the current read by the iadc, since the bms uses
- * flipped battery current polarity.
- */
- *ibat_ua = -1 * (int)i_result.result_ua;
- *vbat_uv = (int)v_result.physical;
return 0;
}
@@ -774,14 +788,6 @@
return (fcc_uah * pc) / 100;
}
-#define CC_RESOLUTION_N 542535
-#define CC_RESOLUTION_D 100000
-
-static s64 cc_to_uv(s64 cc)
-{
- return div_s64(cc * CC_RESOLUTION_N, CC_RESOLUTION_D);
-}
-
#define CC_READING_TICKS 56
#define SLEEP_CLK_HZ 32764
#define SECONDS_PER_HOUR 3600
@@ -817,7 +823,7 @@
qpnp_iadc_get_gain_and_offset(&calibration);
pr_debug("cc = %lld\n", cc);
- cc_voltage_uv = cc_to_uv(cc);
+ cc_voltage_uv = cc_reading_to_uv(cc);
cc_voltage_uv = cc_adjust_for_gain(cc_voltage_uv,
calibration.gain_raw
- calibration.offset_raw);
@@ -1409,7 +1415,7 @@
goto out;
}
- if (ibat_ua < 0 && !is_batfet_open(chip)) {
+ if (ibat_ua < 0 && !is_battery_full(chip)) {
soc = charging_adjustments(chip, params, soc, vbat_uv, ibat_ua,
batt_temp);
goto out;
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index 6a2ce8d..993b2cb 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -546,6 +546,9 @@
/* Don't run on battery for batteryless hardware */
if (chip->use_default_batt_values)
return 0;
+ /* Don't force on battery if battery is not present */
+ if (!qpnp_chg_is_batt_present(chip))
+ return 0;
/* This bit forces the charger to run off of the battery rather
* than a connected charger */
@@ -1564,9 +1567,9 @@
rc |= devm_request_irq(chip->dev, chip->chg_failed_irq,
qpnp_chg_chgr_chg_failed_irq_handler,
- IRQF_TRIGGER_RISING, "chg_failed", chip);
+ IRQF_TRIGGER_RISING, "chg-failed", chip);
if (rc < 0) {
- pr_err("Can't request %d chg_failed chg: %d\n",
+ pr_err("Can't request %d chg-failed: %d\n",
chip->chg_failed_irq, rc);
return rc;
}
@@ -1584,7 +1587,7 @@
rc |= devm_request_irq(chip->dev, chip->chg_trklchg_irq,
qpnp_chg_chgr_chg_trklchg_irq_handler,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
- "fast-chg-on", chip);
+ "trkl-chg-on", chip);
if (rc < 0) {
pr_err("Can't request %d trkl-chg-on: %d\n",
chip->chg_trklchg_irq, rc);
@@ -1607,7 +1610,7 @@
rc = devm_request_irq(chip->dev, chip->batt_pres_irq,
qpnp_chg_bat_if_batt_pres_irq_handler,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
- "bat_if_batt_pres", chip);
+ "batt-pres", chip);
if (rc < 0) {
pr_err("Can't request %d batt-pres irq: %d\n",
chip->batt_pres_irq, rc);
@@ -1628,9 +1631,9 @@
rc = devm_request_irq(chip->dev, chip->usbin_valid_irq,
qpnp_chg_usb_usbin_valid_irq_handler,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
- "chg_usbin_valid", chip);
+ "usbin-valid", chip);
if (rc < 0) {
- pr_err("Can't request %d usbinvalid: %d\n",
+ pr_err("Can't request %d usbin-valid: %d\n",
chip->usbin_valid_irq, rc);
return rc;
}
@@ -1644,9 +1647,9 @@
rc = devm_request_irq(chip->dev, chip->chg_gone_irq,
qpnp_chg_usb_chg_gone_irq_handler,
IRQF_TRIGGER_RISING,
- "chg_gone_irq", chip);
+ "chg-gone", chip);
if (rc < 0) {
- pr_err("Can't request %d chg_gone: %d\n",
+ pr_err("Can't request %d chg-gone: %d\n",
chip->chg_gone_irq, rc);
return rc;
}
@@ -1663,9 +1666,9 @@
rc = devm_request_irq(chip->dev, chip->dcin_valid_irq,
qpnp_chg_dc_dcin_valid_irq_handler,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
- "chg_dcin_valid", chip);
+ "dcin-valid", chip);
if (rc < 0) {
- pr_err("Can't request %d dcinvalid: %d\n",
+ pr_err("Can't request %d dcin-valid: %d\n",
chip->dcin_valid_irq, rc);
return rc;
}
@@ -2120,9 +2123,10 @@
}
INIT_WORK(&chip->adc_measure_work,
qpnp_bat_if_adc_measure_work);
- INIT_DELAYED_WORK(&chip->arb_stop_work, qpnp_arb_stop_work);
}
+ INIT_DELAYED_WORK(&chip->arb_stop_work, qpnp_arb_stop_work);
+
if (chip->dc_chgpth_base) {
chip->dc_psy.name = "qpnp-dc";
chip->dc_psy.type = POWER_SUPPLY_TYPE_MAINS;
@@ -2245,7 +2249,7 @@
return rc;
}
-static const struct dev_pm_ops qpnp_bms_pm_ops = {
+static const struct dev_pm_ops qpnp_chg_pm_ops = {
.resume = qpnp_chg_resume,
.suspend = qpnp_chg_suspend,
};
@@ -2254,9 +2258,10 @@
.probe = qpnp_charger_probe,
.remove = __devexit_p(qpnp_charger_remove),
.driver = {
- .name = QPNP_CHARGER_DEV_NAME,
- .owner = THIS_MODULE,
- .of_match_table = qpnp_charger_match_table,
+ .name = QPNP_CHARGER_DEV_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = qpnp_charger_match_table,
+ .pm = &qpnp_chg_pm_ops,
},
};
diff --git a/drivers/power/smb350_charger.c b/drivers/power/smb350_charger.c
index 21d7aea..11fff43 100644
--- a/drivers/power/smb350_charger.c
+++ b/drivers/power/smb350_charger.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -263,6 +263,9 @@
if (!chg_enabled) {
pr_warn("Charging not enabled.\n");
+ /* release the wake-lock when DC power removed */
+ if (wake_lock_active(&dev->chg_wake_lock))
+ wake_unlock(&dev->chg_wake_lock);
return POWER_SUPPLY_CHARGE_TYPE_NONE;
}
diff --git a/drivers/thermal/msm_thermal.c b/drivers/thermal/msm_thermal.c
index 42119aa..2b9af47 100644
--- a/drivers/thermal/msm_thermal.c
+++ b/drivers/thermal/msm_thermal.c
@@ -28,6 +28,7 @@
#include <linux/of.h>
#include <linux/sysfs.h>
#include <linux/types.h>
+#include <linux/android_alarm.h>
#include <mach/cpufreq.h>
#include <mach/rpm-regulator.h>
#include <mach/rpm-regulator-smd.h>
@@ -41,6 +42,10 @@
static bool core_control_enabled;
static uint32_t cpus_offlined;
static DEFINE_MUTEX(core_control_mutex);
+static uint32_t wakeup_ms;
+static struct alarm thermal_rtc;
+static struct kobject *tt_kobj;
+static struct work_struct timer_work;
static int enabled;
static int rails_cnt;
@@ -58,6 +63,7 @@
static bool psm_enabled;
static bool psm_nodes_called;
static bool psm_probed;
+static int *tsens_id_map;
static DEFINE_MUTEX(vdd_rstr_mutex);
static DEFINE_MUTEX(psm_mutex);
@@ -66,7 +72,7 @@
uint32_t freq_req;
uint32_t min_level;
uint32_t num_levels;
- uint32_t curr_level;
+ int32_t curr_level;
uint32_t levels[3];
struct kobj_attribute value_attr;
struct kobj_attribute level_attr;
@@ -153,6 +159,7 @@
{
int cpu = 0;
int ret = 0;
+ struct cpufreq_policy *policy = NULL;
if (!freq_table_get) {
ret = check_freq_table();
@@ -168,16 +175,20 @@
for_each_possible_cpu(cpu) {
ret = msm_cpufreq_set_freq_limits(cpu, min, limited_max_freq);
-
if (ret) {
pr_err("%s:Fail to set limits for cpu%d\n",
__func__, cpu);
return ret;
}
- if (cpufreq_update_policy(cpu))
- pr_debug("%s: Cannot update policy for cpu%d\n",
- __func__, cpu);
+ if (cpu_online(cpu)) {
+ policy = cpufreq_cpu_get(cpu);
+ if (!policy)
+ continue;
+ cpufreq_driver_target(policy, policy->cur,
+ CPUFREQ_RELATION_L);
+ cpufreq_cpu_put(policy);
+ }
}
return ret;
@@ -187,6 +198,9 @@
{
int ret = 0;
+ if (level == r->curr_level)
+ return ret;
+
/* level = -1: disable, level = 0,1,2..n: enable */
if (level == -1) {
ret = update_cpu_min_freq_all(r->min_level);
@@ -217,6 +231,9 @@
r->name);
return -EFAULT;
}
+ if (level == r->curr_level)
+ return ret;
+
/* level = -1: disable, level = 0,1,2..n: enable */
if (level == -1) {
ret = regulator_set_voltage(r->reg, r->min_level,
@@ -235,32 +252,6 @@
return ret;
}
-/* 1:enable, 0:disable */
-static int vdd_restriction_apply_all(int en)
-{
- int i = 0;
- int fail_cnt = 0;
- int ret = 0;
-
- for (i = 0; i < rails_cnt; i++) {
- if (rails[i].freq_req == 1 && freq_table_get)
- ret = vdd_restriction_apply_freq(&rails[i],
- en ? 0 : -1);
- else
- ret = vdd_restriction_apply_voltage(&rails[i],
- en ? 0 : -1);
- if (ret) {
- pr_err("Cannot set voltage for %s", rails[i].name);
- fail_cnt++;
- }
- }
- /* Check fail_cnt again to make sure all of the rails are applied
- * restriction successfully or not */
- if (fail_cnt)
- return -EFAULT;
-
- return ret;
-}
/* Setting all rails the same mode */
static int psm_set_mode_all(int mode)
@@ -322,8 +313,10 @@
ret = vdd_restriction_apply_voltage(&rails[i],
(val) ? 0 : -1);
- /* Even if fail to set one rail, still try to set the
- * others. Continue the loop */
+ /*
+ * Even if fail to set one rail, still try to set the
+ * others. Continue the loop
+ */
if (ret)
pr_err("Set vdd restriction for %s failed\n",
rails[i].name);
@@ -373,7 +366,7 @@
else
val = reg->levels[reg->curr_level];
- return snprintf(buf, PAGE_SIZE, "%d\n", reg->levels[reg->curr_level]);
+ return snprintf(buf, PAGE_SIZE, "%d\n", val);
}
static int vdd_rstr_reg_level_show(
@@ -395,7 +388,7 @@
if (vdd_rstr_en.enabled == 0)
goto done_store_level;
- ret = kstrtoint(buf, 10, &val);
+ ret = kstrtouint(buf, 10, &val);
if (ret) {
pr_err("Invalid input %s for level\n", buf);
goto done_store_level;
@@ -468,6 +461,103 @@
return count;
}
+static int check_sensor_id(int sensor_id)
+{
+ int i = 0;
+ bool hw_id_found;
+ int ret = 0;
+
+ for (i = 0; i < max_tsens_num; i++) {
+ if (sensor_id == tsens_id_map[i]) {
+ hw_id_found = true;
+ break;
+ }
+ }
+ if (!hw_id_found) {
+ pr_err("%s: Invalid sensor hw id :%d\n", __func__, sensor_id);
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+static int create_sensor_id_map(void)
+{
+ int i = 0;
+ int ret = 0;
+
+ tsens_id_map = kzalloc(sizeof(int) * max_tsens_num,
+ GFP_KERNEL);
+ if (!tsens_id_map) {
+ pr_err("%s: Cannot allocate memory for tsens_id_map\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < max_tsens_num; i++) {
+ ret = tsens_get_hw_id_mapping(i, &tsens_id_map[i]);
+ /* If return -ENXIO, hw_id is default in sequence */
+ if (ret) {
+ if (ret == -ENXIO) {
+ tsens_id_map[i] = i;
+ ret = 0;
+ } else {
+ pr_err( \
+ "%s: Failed to get hw id for sw id %d\n",
+ __func__, i);
+ goto fail;
+ }
+ }
+ }
+
+ return ret;
+fail:
+ kfree(tsens_id_map);
+ return ret;
+}
+
+/* 1:enable, 0:disable */
+static int vdd_restriction_apply_all(int en)
+{
+ int i = 0;
+ int en_cnt = 0;
+ int dis_cnt = 0;
+ int fail_cnt = 0;
+ int ret = 0;
+
+ for (i = 0; i < rails_cnt; i++) {
+ if (rails[i].freq_req == 1 && freq_table_get)
+ ret = vdd_restriction_apply_freq(&rails[i],
+ en ? 0 : -1);
+ else
+ ret = vdd_restriction_apply_voltage(&rails[i],
+ en ? 0 : -1);
+ if (ret) {
+ pr_err("Cannot set voltage for %s", rails[i].name);
+ fail_cnt++;
+ } else {
+ if (en)
+ en_cnt++;
+ else
+ dis_cnt++;
+ }
+ }
+
+ /* As long as one rail is enabled, vdd rstr is enabled */
+ if (en && en_cnt)
+ vdd_rstr_en.enabled = 1;
+ else if (!en && (dis_cnt == rails_cnt))
+ vdd_rstr_en.enabled = 0;
+
+ /*
+ * Check fail_cnt again to make sure all of the rails are applied
+ * restriction successfully or not
+ */
+ if (fail_cnt)
+ return -EFAULT;
+ return ret;
+}
+
static int msm_thermal_get_freq_table(void)
{
int ret = 0;
@@ -545,7 +635,8 @@
cpus_offlined &= ~BIT(i);
pr_info("%s: Allow Online CPU%d Temp: %ld\n",
KBUILD_MODNAME, i, temp);
- /* If this core is already online, then bring up the
+ /*
+ * If this core is already online, then bring up the
* next offlined core.
*/
if (cpu_online(i))
@@ -578,7 +669,7 @@
mutex_lock(&vdd_rstr_mutex);
for (i = 0; i < max_tsens_num; i++) {
- tsens_dev.sensor_num = i;
+ tsens_dev.sensor_num = tsens_id_map[i];
ret = tsens_get_temp(&tsens_dev, &temp);
if (ret) {
pr_debug("%s: Unable to read TSENS sensor %d\n",
@@ -586,18 +677,15 @@
dis_cnt++;
continue;
}
- if (temp <= msm_thermal_info.vdd_rstr_temp_hyst_degC &&
- vdd_rstr_en.enabled == 0) {
+ if (temp <= msm_thermal_info.vdd_rstr_temp_degC) {
ret = vdd_restriction_apply_all(1);
if (ret) {
pr_err( \
"Enable vdd rstr votlage for all failed\n");
goto exit;
}
- vdd_rstr_en.enabled = 1;
goto exit;
- } else if (temp > msm_thermal_info.vdd_rstr_temp_degC &&
- vdd_rstr_en.enabled == 1)
+ } else if (temp > msm_thermal_info.vdd_rstr_temp_hyst_degC)
dis_cnt++;
}
if (dis_cnt == max_tsens_num) {
@@ -606,7 +694,6 @@
pr_err("Disable vdd rstr votlage for all failed\n");
goto exit;
}
- vdd_rstr_en.enabled = 0;
}
exit:
mutex_unlock(&vdd_rstr_mutex);
@@ -623,7 +710,7 @@
mutex_lock(&psm_mutex);
for (i = 0; i < max_tsens_num; i++) {
- tsens_dev.sensor_num = i;
+ tsens_dev.sensor_num = tsens_id_map[i];
ret = tsens_get_temp(&tsens_dev, &temp);
if (ret) {
pr_debug("%s: Unable to read TSENS sensor %d\n",
@@ -632,9 +719,11 @@
continue;
}
- /* As long as one sensor is above the threshold, set PWM mode
+ /*
+ * As long as one sensor is above the threshold, set PWM mode
* on all rails, and loop stops. Set auto mode when all rails
- * are below thershold */
+ * are below thershold
+ */
if (temp > msm_thermal_info.psm_temp_degC) {
ret = psm_set_mode_all(PMIC_PWM_MODE);
if (ret) {
@@ -749,7 +838,40 @@
.notifier_call = msm_thermal_cpu_callback,
};
-/**
+static void thermal_rtc_setup(void)
+{
+ ktime_t wakeup_time;
+ ktime_t curr_time;
+
+ curr_time = alarm_get_elapsed_realtime();
+ wakeup_time = ktime_add_us(curr_time,
+ (wakeup_ms * USEC_PER_MSEC));
+ alarm_start_range(&thermal_rtc, wakeup_time,
+ wakeup_time);
+ pr_debug("%s: Current Time: %ld %ld, Alarm set to: %ld %ld\n",
+ KBUILD_MODNAME,
+ ktime_to_timeval(curr_time).tv_sec,
+ ktime_to_timeval(curr_time).tv_usec,
+ ktime_to_timeval(wakeup_time).tv_sec,
+ ktime_to_timeval(wakeup_time).tv_usec);
+
+}
+
+static void timer_work_fn(struct work_struct *work)
+{
+ sysfs_notify(tt_kobj, NULL, "wakeup_ms");
+}
+
+static void thermal_rtc_callback(struct alarm *al)
+{
+ struct timeval ts;
+ ts = ktime_to_timeval(alarm_get_elapsed_realtime());
+ schedule_work(&timer_work);
+ pr_debug("%s: Time on alarm expiry: %ld %ld\n", KBUILD_MODNAME,
+ ts.tv_sec, ts.tv_usec);
+}
+
+/*
* We will reset the cpu frequencies limits here. The core online/offline
* status will be carried over to the process stopping the msm_thermal, as
* we dont want to online a core and bring in the thermal issues.
@@ -905,6 +1027,52 @@
.attrs = cc_attrs,
};
+static ssize_t show_wakeup_ms(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n", wakeup_ms);
+}
+
+static ssize_t store_wakeup_ms(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf, size_t count)
+{
+ int ret;
+ ret = kstrtouint(buf, 10, &wakeup_ms);
+
+ if (ret) {
+ pr_err("%s: Trying to set invalid wakeup timer\n",
+ KBUILD_MODNAME);
+ return ret;
+ }
+
+ if (wakeup_ms > 0) {
+ thermal_rtc_setup();
+ pr_debug("%s: Timer started for %ums\n", KBUILD_MODNAME,
+ wakeup_ms);
+ } else {
+ ret = alarm_cancel(&thermal_rtc);
+ if (ret)
+ pr_debug("%s: Timer canceled\n", KBUILD_MODNAME);
+ else
+ pr_debug("%s: No active timer present to cancel\n",
+ KBUILD_MODNAME);
+
+ }
+ return count;
+}
+
+static __cpuinitdata struct kobj_attribute timer_attr =
+__ATTR(wakeup_ms, 0644, show_wakeup_ms, store_wakeup_ms);
+
+static __cpuinitdata struct attribute *tt_attrs[] = {
+ &timer_attr.attr,
+ NULL,
+};
+
+static __cpuinitdata struct attribute_group tt_attr_group = {
+ .attrs = tt_attrs,
+};
+
static __init int msm_thermal_add_cc_nodes(void)
{
struct kobject *module_kobj = NULL;
@@ -941,15 +1109,54 @@
return ret;
}
+static __init int msm_thermal_add_timer_nodes(void)
+{
+ struct kobject *module_kobj = NULL;
+ int ret = 0;
+
+ module_kobj = kset_find_obj(module_kset, KBUILD_MODNAME);
+ if (!module_kobj) {
+ pr_err("%s: cannot find kobject for module\n",
+ KBUILD_MODNAME);
+ ret = -ENOENT;
+ goto failed;
+ }
+
+ tt_kobj = kobject_create_and_add("thermal_timer", module_kobj);
+ if (!tt_kobj) {
+ pr_err("%s: cannot create timer kobj\n",
+ KBUILD_MODNAME);
+ ret = -ENOMEM;
+ goto failed;
+ }
+
+ ret = sysfs_create_group(tt_kobj, &tt_attr_group);
+ if (ret) {
+ pr_err("%s: cannot create group\n", KBUILD_MODNAME);
+ goto failed;
+ }
+
+ return 0;
+
+failed:
+ if (tt_kobj)
+ kobject_del(tt_kobj);
+ return ret;
+}
+
int __devinit msm_thermal_init(struct msm_thermal_data *pdata)
{
int ret = 0;
BUG_ON(!pdata);
tsens_get_max_sensor_num(&max_tsens_num);
- BUG_ON(msm_thermal_info.sensor_id >= max_tsens_num);
memcpy(&msm_thermal_info, pdata, sizeof(struct msm_thermal_data));
+ if (create_sensor_id_map())
+ return -EINVAL;
+ if (check_sensor_id(msm_thermal_info.sensor_id))
+ return -EINVAL;
+
enabled = 1;
core_control_enabled = 1;
INIT_DELAYED_WORK(&check_temp_work, check_temp);
@@ -969,8 +1176,10 @@
if (rails[i].freq_req == 1) {
usefreq |= BIT(i);
check_freq_table();
- /* Restrict frequency by default until we have made
- * our first temp reading */
+ /*
+ * Restrict frequency by default until we have made
+ * our first temp reading
+ */
if (freq_table_get)
ret = vdd_restriction_apply_freq(&rails[i], 0);
else
@@ -991,8 +1200,10 @@
}
return ret;
}
- /* Restrict votlage by default until we have made
- * our first temp reading */
+ /*
+ * Restrict votlage by default until we have made
+ * our first temp reading
+ */
ret = vdd_restriction_apply_voltage(&rails[i], 0);
}
}
@@ -1396,9 +1607,11 @@
key = "qcom,core-control-mask";
ret = of_property_read_u32(node, key, &data.core_control_mask);
- /* Probe optional properties below. Call probe_psm before
+ /*
+ * Probe optional properties below. Call probe_psm before
* probe_vdd_rstr because rpm_regulator_get has to be called
- * before devm_regulator_get*/
+ * before devm_regulator_get
+ */
ret = probe_psm(node, &data, pdev);
if (ret == -EPROBE_DEFER)
goto fail;
@@ -1406,8 +1619,10 @@
if (ret == -EPROBE_DEFER)
goto fail;
- /* In case sysfs add nodes get called before probe function.
- * Need to make sure sysfs node is created again */
+ /*
+ * In case sysfs add nodes get called before probe function.
+ * Need to make sure sysfs node is created again
+ */
if (psm_nodes_called) {
msm_thermal_add_psm_nodes();
psm_nodes_called = false;
@@ -1452,6 +1667,10 @@
msm_thermal_add_cc_nodes();
msm_thermal_add_psm_nodes();
msm_thermal_add_vdd_rstr_nodes();
+ alarm_init(&thermal_rtc, ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP,
+ thermal_rtc_callback);
+ INIT_WORK(&timer_work, timer_work_fn);
+ msm_thermal_add_timer_nodes();
return 0;
}
diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c
index ede2ef1..1d02e32 100644
--- a/drivers/tty/vt/vt_ioctl.c
+++ b/drivers/tty/vt/vt_ioctl.c
@@ -110,6 +110,34 @@
wake_up_interruptible(&vt_event_waitqueue);
}
+static void __vt_event_queue(struct vt_event_wait *vw)
+{
+ unsigned long flags;
+ /* Prepare the event */
+ INIT_LIST_HEAD(&vw->list);
+ vw->done = 0;
+ /* Queue our event */
+ spin_lock_irqsave(&vt_event_lock, flags);
+ list_add(&vw->list, &vt_events);
+ spin_unlock_irqrestore(&vt_event_lock, flags);
+}
+
+static void __vt_event_wait(struct vt_event_wait *vw)
+{
+ /* Wait for it to pass */
+ wait_event_interruptible(vt_event_waitqueue, vw->done);
+}
+
+static void __vt_event_dequeue(struct vt_event_wait *vw)
+{
+ unsigned long flags;
+
+ /* Dequeue it */
+ spin_lock_irqsave(&vt_event_lock, flags);
+ list_del(&vw->list);
+ spin_unlock_irqrestore(&vt_event_lock, flags);
+}
+
/**
* vt_event_wait - wait for an event
* @vw: our event
@@ -121,20 +149,9 @@
static void vt_event_wait(struct vt_event_wait *vw)
{
- unsigned long flags;
- /* Prepare the event */
- INIT_LIST_HEAD(&vw->list);
- vw->done = 0;
- /* Queue our event */
- spin_lock_irqsave(&vt_event_lock, flags);
- list_add(&vw->list, &vt_events);
- spin_unlock_irqrestore(&vt_event_lock, flags);
- /* Wait for it to pass */
- wait_event_interruptible(vt_event_waitqueue, vw->done);
- /* Dequeue it */
- spin_lock_irqsave(&vt_event_lock, flags);
- list_del(&vw->list);
- spin_unlock_irqrestore(&vt_event_lock, flags);
+ __vt_event_queue(vw);
+ __vt_event_wait(vw);
+ __vt_event_dequeue(vw);
}
/**
@@ -177,10 +194,14 @@
{
struct vt_event_wait vw;
do {
- if (n == fg_console + 1)
- break;
vw.event.event = VT_EVENT_SWITCH;
- vt_event_wait(&vw);
+ __vt_event_queue(&vw);
+ if (n == fg_console + 1) {
+ __vt_event_dequeue(&vw);
+ break;
+ }
+ __vt_event_wait(&vw);
+ __vt_event_dequeue(&vw);
if (vw.done == 0)
return -EINTR;
} while (vw.event.newev != n);
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index b8e02d2..a27eb09 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -1309,8 +1309,14 @@
data |= (0x7F | (1 << 14));
dwc3_msm_ssusb_write_phycreg(msm->base, 0x1002, data);
- /* Set LOS_BIAS to 0x5 */
- dwc3_msm_write_readback(msm->base, SS_PHY_PARAM_CTRL_1, 0x07, 0x5);
+ /*
+ * Set the QSCRATCH SS_PHY_PARAM_CTRL1 parameters as follows
+ * TX_FULL_SWING [26:20] amplitude to 127
+ * TX_DEEMPH_3_5DB [13:8] to 22
+ * LOS_BIAS [2:0] to 0x5
+ */
+ dwc3_msm_write_readback(msm->base, SS_PHY_PARAM_CTRL_1,
+ 0x07f03f07, 0x07f01605);
}
/* Initialize QSCRATCH registers for HSPHY and SSPHY operation */
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
index 8d2ec97..bb0b2fb 100644
--- a/drivers/usb/dwc3/ep0.c
+++ b/drivers/usb/dwc3/ep0.c
@@ -751,6 +751,9 @@
dwc->ep0_next_event = DWC3_EP0_NRDY_STATUS;
r = next_request(&ep0->request_list);
+ if (r == NULL)
+ return;
+
ur = &r->request;
if ((epnum & 1) && ur->zero &&
(ur->length % ep0->endpoint.maxpacket == 0)) {
diff --git a/drivers/video/msm/mdss/dsi_v2.h b/drivers/video/msm/mdss/dsi_v2.h
index f68527c..54b772b 100644
--- a/drivers/video/msm/mdss/dsi_v2.h
+++ b/drivers/video/msm/mdss/dsi_v2.h
@@ -181,7 +181,7 @@
struct dsi_panel_cmds_list {
struct dsi_cmd_desc *buf;
- char size;
+ int size;
char ctrl_state;
};
diff --git a/drivers/video/msm/mdss/mdss_dsi.c b/drivers/video/msm/mdss/mdss_dsi.c
index 8c4c021..5d56df4 100644
--- a/drivers/video/msm/mdss/mdss_dsi.c
+++ b/drivers/video/msm/mdss/mdss_dsi.c
@@ -414,6 +414,8 @@
/* disable DSI controller */
mdss_dsi_controller_cfg(0, pdata);
+ /* disable DSI phy */
+ mdss_dsi_phy_enable(ctrl_pdata->ctrl_base, 0);
ret = mdss_dsi_panel_power_on(pdata, 0);
if (ret) {
pr_err("%s: Panel power off failed\n", __func__);
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index 97a07ed..72ad67e 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -627,12 +627,7 @@
static int mdss_fb_blank(int blank_mode, struct fb_info *info)
{
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
- if (blank_mode == FB_BLANK_POWERDOWN) {
- struct fb_event event;
- event.info = info;
- event.data = &blank_mode;
- fb_notifier_call_chain(FB_EVENT_BLANK, &event);
- }
+
mdss_fb_pan_idle(mfd);
if (mfd->op_enable == 0) {
if (blank_mode == FB_BLANK_UNBLANK)
@@ -957,6 +952,7 @@
result = mdss_fb_blank_sub(FB_BLANK_UNBLANK, info,
mfd->op_enable);
if (result) {
+ pm_runtime_put(info->dev);
pr_err("mdss_fb_open: can't turn on display!\n");
return result;
}
diff --git a/drivers/video/msm/mdss/mdss_hdmi_mhl.h b/drivers/video/msm/mdss/mdss_hdmi_mhl.h
index 8fef63e..8a9d4fc 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_mhl.h
+++ b/drivers/video/msm/mdss/mdss_hdmi_mhl.h
@@ -19,9 +19,9 @@
struct msm_hdmi_mhl_ops {
u8 (*tmds_enabled)(struct platform_device *pdev);
int (*set_mhl_max_pclk)(struct platform_device *pdev, u32 max_val);
+ int (*set_upstream_hpd)(struct platform_device *pdev, uint8_t on);
};
int msm_hdmi_register_mhl(struct platform_device *pdev,
- struct msm_hdmi_mhl_ops *ops);
-
+ struct msm_hdmi_mhl_ops *ops, void *data);
#endif /* __MDSS_HDMI_MHL_H__ */
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.c b/drivers/video/msm/mdss/mdss_hdmi_tx.c
index dc51b1b..ad4cbd2 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.c
@@ -81,6 +81,7 @@
struct hdmi_tx_audio_acr lut[AUDIO_SAMPLE_RATE_MAX];
};
+static int hdmi_tx_set_mhl_hpd(struct platform_device *pdev, uint8_t on);
static int hdmi_tx_sysfs_enable_hpd(struct hdmi_tx_ctrl *hdmi_ctrl, int on);
static irqreturn_t hdmi_tx_isr(int irq, void *data);
static void hdmi_tx_hpd_off(struct hdmi_tx_ctrl *hdmi_ctrl);
@@ -1950,7 +1951,7 @@
}
int msm_hdmi_register_mhl(struct platform_device *pdev,
- struct msm_hdmi_mhl_ops *ops)
+ struct msm_hdmi_mhl_ops *ops, void *data)
{
struct hdmi_tx_ctrl *hdmi_ctrl = platform_get_drvdata(pdev);
@@ -1966,6 +1967,8 @@
ops->tmds_enabled = hdmi_tx_tmds_enabled;
ops->set_mhl_max_pclk = hdmi_tx_set_mhl_max_pclk;
+ ops->set_upstream_hpd = hdmi_tx_set_mhl_hpd;
+
return 0;
}
@@ -2438,6 +2441,41 @@
return rc;
} /* hdmi_tx_sysfs_enable_hpd */
+static int hdmi_tx_set_mhl_hpd(struct platform_device *pdev, uint8_t on)
+{
+ int rc = 0;
+ struct hdmi_tx_ctrl *hdmi_ctrl = NULL;
+
+ hdmi_ctrl = platform_get_drvdata(pdev);
+
+ if (!hdmi_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return -EINVAL;
+ }
+
+ if (!on && hdmi_ctrl->hpd_feature_on) {
+ rc = hdmi_tx_sysfs_enable_hpd(hdmi_ctrl, false);
+ } else if (on && !hdmi_ctrl->hpd_feature_on) {
+ rc = hdmi_tx_sysfs_enable_hpd(hdmi_ctrl, true);
+ } else {
+ DEV_DBG("%s: hpd is already '%s'. return\n", __func__,
+ hdmi_ctrl->hpd_feature_on ? "enabled" : "disabled");
+ return rc;
+ }
+
+ if (!rc) {
+ hdmi_ctrl->hpd_feature_on =
+ (~hdmi_ctrl->hpd_feature_on) & BIT(0);
+ DEV_DBG("%s: '%d'\n", __func__, hdmi_ctrl->hpd_feature_on);
+ } else {
+ DEV_ERR("%s: failed to '%s' hpd. rc = %d\n", __func__,
+ on ? "enable" : "disable", rc);
+ }
+
+ return rc;
+
+}
+
static irqreturn_t hdmi_tx_isr(int irq, void *data)
{
struct dss_io_data *io = NULL;
@@ -2868,7 +2906,7 @@
switch (module_type) {
case HDMI_TX_HPD_PM:
- mp->num_clk = 2;
+ mp->num_clk = 3;
mp->clk_config = devm_kzalloc(dev, sizeof(struct dss_clk) *
mp->num_clk, GFP_KERNEL);
if (!mp->clk_config) {
@@ -2884,6 +2922,16 @@
snprintf(mp->clk_config[1].clk_name, 32, "%s", "core_clk");
mp->clk_config[1].type = DSS_CLK_OTHER;
mp->clk_config[1].rate = 19200000;
+
+ /*
+ * This clock is required to clock MDSS interrupt registers
+ * when HDMI is the only block turned on within MDSS. Since
+ * rate for this clock is controlled by MDP driver, treat this
+ * similar to AHB clock and do not set rate for it.
+ */
+ snprintf(mp->clk_config[2].clk_name, 32, "%s", "mdp_core_clk");
+ mp->clk_config[2].type = DSS_CLK_AHB;
+ mp->clk_config[2].rate = 0;
break;
case HDMI_TX_CORE_PM:
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index 22de7e4..b9457be 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -388,12 +388,11 @@
bus_idx = (current_bus_idx % (num_cases - 1)) + 1;
- /* aligning to avoid performing updates for small changes */
- ab_quota = ALIGN(ab_quota, SZ_64M);
- ib_quota = ALIGN(ib_quota, SZ_64M);
-
vect = mdp_bus_scale_table.usecase[current_bus_idx].vectors;
- if ((ab_quota == vect->ab) && (ib_quota == vect->ib)) {
+
+ /* avoid performing updates for small changes */
+ if ((ALIGN(ab_quota, SZ_64M) == ALIGN(vect->ab, SZ_64M)) &&
+ (ALIGN(ib_quota, SZ_64M) == ALIGN(vect->ib, SZ_64M))) {
pr_debug("skip bus scaling, no change in vectors\n");
return 0;
}
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index 6be2b73..e18722c 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -110,8 +110,8 @@
typedef void (*mdp_vsync_handler_t)(struct mdss_mdp_ctl *, ktime_t);
struct mdss_mdp_vsync_handler {
+ bool enabled;
mdp_vsync_handler_t vsync_handler;
- u32 ref_cnt;
struct list_head list;
};
@@ -385,7 +385,7 @@
irqreturn_t mdss_mdp_isr(int irq, void *ptr);
int mdss_iommu_attach(struct mdss_data_type *mdata);
-int mdss_mdp_copy_splash_screen(struct mdss_panel_data *pdata);
+int mdss_mdp_video_copy_splash_screen(struct mdss_panel_data *pdata);
void mdss_mdp_irq_clear(struct mdss_data_type *mdata,
u32 intr_type, u32 intf_num);
int mdss_mdp_irq_enable(u32 intr_type, u32 intf_num);
@@ -415,6 +415,10 @@
struct mdss_mdp_ctl *mdss_mdp_ctl_init(struct mdss_panel_data *pdata,
struct msm_fb_data_type *mfd);
+int mdss_mdp_video_reconfigure_splash_done(struct mdss_mdp_ctl *ctl);
+int mdss_mdp_video_copy_splash_screen(struct mdss_panel_data *pdata);
+void mdss_mdp_ctl_splash_start(struct mdss_panel_data *pdata);
+int mdss_mdp_ctl_splash_finish(struct mdss_mdp_ctl *ctl);
int mdss_mdp_ctl_setup(struct mdss_mdp_ctl *ctl);
int mdss_mdp_ctl_split_display_setup(struct mdss_mdp_ctl *ctl,
struct mdss_panel_data *pdata);
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index eef41b5..b2147c3 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -451,6 +451,29 @@
return 0;
}
+void mdss_mdp_ctl_splash_start(struct mdss_panel_data *pdata)
+{
+ switch (pdata->panel_info.type) {
+ case MIPI_VIDEO_PANEL:
+ mdss_mdp_video_copy_splash_screen(pdata);
+ break;
+ case MIPI_CMD_PANEL:
+ default:
+ break;
+ }
+}
+
+int mdss_mdp_ctl_splash_finish(struct mdss_mdp_ctl *ctl)
+{
+ switch (ctl->panel_data->panel_info.type) {
+ case MIPI_VIDEO_PANEL:
+ return mdss_mdp_video_reconfigure_splash_done(ctl);
+ case MIPI_CMD_PANEL:
+ default:
+ return 0;
+ }
+}
+
static inline int mdss_mdp_set_split_ctl(struct mdss_mdp_ctl *ctl,
struct mdss_mdp_ctl *split_ctl)
{
@@ -938,7 +961,7 @@
ret = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_RESET, NULL);
if (ret) {
pr_err("panel power on failed ctl=%d\n", ctl->num);
- return ret;
+ goto error;
}
ret = mdss_mdp_ctl_start_sub(ctl);
@@ -961,6 +984,7 @@
}
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+error:
mutex_unlock(&ctl->lock);
return ret;
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_video.c b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
index d68a3d4..72cbed9 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_video.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
@@ -14,6 +14,8 @@
#define pr_fmt(fmt) "%s: " fmt, __func__
#include <linux/iopoll.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
#include "mdss_fb.h"
#include "mdss_mdp.h"
@@ -201,13 +203,13 @@
}
-static inline void video_vsync_irq_enable(struct mdss_mdp_ctl *ctl)
+static inline void video_vsync_irq_enable(struct mdss_mdp_ctl *ctl, bool clear)
{
struct mdss_mdp_video_ctx *ctx = ctl->priv_data;
if (atomic_inc_return(&ctx->vsync_ref) == 1)
mdss_mdp_irq_enable(MDSS_MDP_IRQ_INTF_VSYNC, ctl->intf_num);
- else
+ else if (clear)
mdss_mdp_irq_clear(ctl->mdata, MDSS_MDP_IRQ_INTF_VSYNC,
ctl->intf_num);
}
@@ -225,9 +227,8 @@
{
struct mdss_mdp_video_ctx *ctx;
unsigned long flags;
- struct mdss_mdp_vsync_handler *tmp;
- bool exist = false;
int ret = 0;
+ bool irq_en = false;
if (!handle || !(handle->vsync_handler)) {
ret = -EINVAL;
@@ -242,32 +243,24 @@
}
spin_lock_irqsave(&ctx->vsync_lock, flags);
- list_for_each_entry(tmp, &(ctx->vsync_handlers), list) {
- if (tmp->vsync_handler == handle->vsync_handler) {
- exist = true;
- tmp->ref_cnt++;
- }
- }
- if (!exist) {
- handle->ref_cnt = 1;
+ if (!handle->enabled) {
+ handle->enabled = true;
list_add(&handle->list, &ctx->vsync_handlers);
+ irq_en = true;
}
-
- video_vsync_irq_enable(ctl);
spin_unlock_irqrestore(&ctx->vsync_lock, flags);
+ if (irq_en)
+ video_vsync_irq_enable(ctl, false);
exit:
return ret;
}
-/* passing NULL as handle or vsync_handler will clear all handlers */
static int mdss_mdp_video_remove_vsync_handler(struct mdss_mdp_ctl *ctl,
struct mdss_mdp_vsync_handler *handle)
{
struct mdss_mdp_video_ctx *ctx;
unsigned long flags;
- struct mdss_mdp_vsync_handler *tmp, *q;
- bool exist = true;
- bool used = false;
+ bool irq_dis = false;
ctx = (struct mdss_mdp_video_ctx *) ctl->priv_data;
if (!ctx) {
@@ -276,26 +269,21 @@
}
spin_lock_irqsave(&ctx->vsync_lock, flags);
- list_for_each_entry_safe(tmp, q, &ctx->vsync_handlers, list) {
- if (handle && handle->vsync_handler)
- exist = (tmp->vsync_handler == handle->vsync_handler);
- if (exist) {
- tmp->ref_cnt--;
- if (handle && handle->vsync_handler)
- used = (tmp->ref_cnt != 0);
- if (!used) {
- video_vsync_irq_disable(ctl);
- list_del_init(&tmp->list);
- }
- }
+ if (handle->enabled) {
+ handle->enabled = false;
+ list_del_init(&handle->list);
+ irq_dis = true;
}
spin_unlock_irqrestore(&ctx->vsync_lock, flags);
+ if (irq_dis)
+ video_vsync_irq_disable(ctl);
return 0;
}
static int mdss_mdp_video_stop(struct mdss_mdp_ctl *ctl)
{
struct mdss_mdp_video_ctx *ctx;
+ struct mdss_mdp_vsync_handler *tmp, *handle;
int rc;
pr_debug("stop ctl=%d\n", ctl->num);
@@ -326,7 +314,8 @@
ctl->intf_num);
}
- mdss_mdp_video_remove_vsync_handler(ctl, NULL);
+ list_for_each_entry_safe(handle, tmp, &ctx->vsync_handlers, list)
+ mdss_mdp_video_remove_vsync_handler(ctl, handle);
mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_INTF_VSYNC, ctl->intf_num,
NULL, NULL);
@@ -429,6 +418,8 @@
ctl->num);
ctx->polling_en++;
rc = mdss_mdp_video_pollwait(ctl);
+ } else {
+ rc = 0;
}
}
@@ -466,7 +457,7 @@
if (!ctx->wait_pending) {
ctx->wait_pending++;
- video_vsync_irq_enable(ctl);
+ video_vsync_irq_enable(ctl, true);
INIT_COMPLETION(ctx->vsync_comp);
} else {
WARN(1, "commit without wait! ctl=%d", ctl->num);
@@ -474,7 +465,13 @@
if (!ctx->timegen_en) {
rc = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_UNBLANK, NULL);
- WARN(rc, "intf %d unblank error (%d)\n", ctl->intf_num, rc);
+ if (rc) {
+ pr_warn("intf #%d unblank error (%d)\n",
+ ctl->intf_num, rc);
+ video_vsync_irq_disable(ctl);
+ ctx->wait_pending = 0;
+ return rc;
+ }
pr_debug("enabling timing gen for intf=%d\n", ctl->intf_num);
@@ -497,6 +494,92 @@
return 0;
}
+int mdss_mdp_video_copy_splash_screen(struct mdss_panel_data *pdata)
+{
+ void *virt = NULL;
+ unsigned long bl_fb_addr = 0;
+ unsigned long *bl_fb_addr_va;
+ unsigned long pipe_addr, pipe_src_size;
+ u32 height, width, rgb_size, bpp;
+ size_t size;
+ static struct ion_handle *ihdl;
+ struct ion_client *iclient = mdss_get_ionclient();
+ static ion_phys_addr_t phys;
+
+ pipe_addr = MDSS_MDP_REG_SSPP_OFFSET(3) +
+ MDSS_MDP_REG_SSPP_SRC0_ADDR;
+ pipe_src_size =
+ MDSS_MDP_REG_SSPP_OFFSET(3) + MDSS_MDP_REG_SSPP_SRC_SIZE;
+
+ bpp = 3;
+ rgb_size = MDSS_MDP_REG_READ(pipe_src_size);
+ bl_fb_addr = MDSS_MDP_REG_READ(pipe_addr);
+
+ height = (rgb_size >> 16) & 0xffff;
+ width = rgb_size & 0xffff;
+ size = PAGE_ALIGN(height * width * bpp);
+ pr_debug("%s:%d splash_height=%d splash_width=%d Buffer size=%d\n",
+ __func__, __LINE__, height, width, size);
+
+ ihdl = ion_alloc(iclient, size, SZ_1M,
+ ION_HEAP(ION_QSECOM_HEAP_ID), 0);
+ if (IS_ERR_OR_NULL(ihdl)) {
+ pr_err("unable to alloc fbmem from ion (%p)\n", ihdl);
+ return -ENOMEM;
+ }
+
+ pdata->panel_info.splash_ihdl = ihdl;
+
+ virt = ion_map_kernel(iclient, ihdl);
+ ion_phys(iclient, ihdl, &phys, &size);
+
+ pr_debug("%s %d Allocating %u bytes at 0x%lx (%pa phys)\n",
+ __func__, __LINE__, size,
+ (unsigned long int)virt, &phys);
+
+ bl_fb_addr_va = (unsigned long *)ioremap(bl_fb_addr, size);
+
+ memcpy(virt, bl_fb_addr_va, size);
+
+ MDSS_MDP_REG_WRITE(pipe_addr, phys);
+ MDSS_MDP_REG_WRITE(MDSS_MDP_REG_CTL_FLUSH + MDSS_MDP_REG_CTL_OFFSET(0),
+ 0x48);
+
+ return 0;
+}
+
+int mdss_mdp_video_reconfigure_splash_done(struct mdss_mdp_ctl *ctl)
+{
+ struct ion_client *iclient = mdss_get_ionclient();
+ struct mdss_panel_data *pdata;
+ int ret = 0, off;
+ int mdss_mdp_rev = MDSS_MDP_REG_READ(MDSS_MDP_REG_HW_VERSION);
+ int mdss_v2_intf_off = 0;
+
+ off = 0;
+
+ pdata = ctl->panel_data;
+
+ pdata->panel_info.cont_splash_enabled = 0;
+
+
+ mdss_mdp_ctl_write(ctl, 0, MDSS_MDP_LM_BORDER_COLOR);
+ off = MDSS_MDP_REG_INTF_OFFSET(ctl->intf_num);
+
+ if (mdss_mdp_rev == MDSS_MDP_HW_REV_102)
+ mdss_v2_intf_off = 0xEC00;
+
+ MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_INTF_TIMING_ENGINE_EN -
+ mdss_v2_intf_off, 0);
+ /* wait for 1 VSYNC for the pipe to be unstaged */
+ msleep(20);
+ ion_free(iclient, pdata->panel_info.splash_ihdl);
+ ret = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_CONT_SPLASH_FINISH,
+ NULL);
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+ return ret;
+}
+
int mdss_mdp_video_start(struct mdss_mdp_ctl *ctl)
{
struct mdss_data_type *mdata;
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index af47d0f..ac1c4ce 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -39,6 +39,7 @@
static atomic_t ov_active_panels = ATOMIC_INIT(0);
static int mdss_mdp_overlay_free_fb_pipe(struct msm_fb_data_type *mfd);
static int mdss_mdp_overlay_fb_parse_dt(struct msm_fb_data_type *mfd);
+static int mdss_mdp_overlay_off(struct msm_fb_data_type *mfd);
static int mdss_mdp_overlay_get(struct msm_fb_data_type *mfd,
struct mdp_overlay *req)
@@ -179,6 +180,14 @@
req->src_rect.h, req->dst_rect.h);
return -EINVAL;
}
+
+ if (req->flags & MDP_BWC_EN) {
+ if ((req->src.width != req->src_rect.w) ||
+ (req->src.height != req->src_rect.h)) {
+ pr_err("BWC: unequal src img and rect w,h\n");
+ return -EINVAL;
+ }
+ }
}
if (fmt->is_yuv) {
@@ -189,6 +198,13 @@
}
}
+ if (req->flags & MDP_DEINTERLACE) {
+ if ((req->src.width % 4 != 0) || (req->src.height % 4 != 0)) {
+ pr_err("interlaced fmt w,h need to be even post div\n");
+ return -EINVAL;
+ }
+ }
+
return 0;
}
@@ -322,7 +338,7 @@
if (pipe && pipe->ndx != req->id) {
pr_debug("replacing pnum=%d at stage=%d mux=%d\n",
pipe->num, req->z_order, mixer_mux);
- pipe->params_changed = true;
+ mdss_mdp_mixer_pipe_unstage(pipe);
}
mixer = mdss_mdp_mixer_get(mdp5_data->ctl, mixer_mux);
@@ -588,7 +604,7 @@
return 0;
}
-static int mdss_mdp_overlay_cleanup(struct msm_fb_data_type *mfd)
+static void mdss_mdp_overlay_cleanup(struct msm_fb_data_type *mfd)
{
struct mdss_mdp_pipe *pipe, *tmp;
struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
@@ -613,96 +629,6 @@
mutex_unlock(&mfd->lock);
list_for_each_entry_safe(pipe, tmp, &destroy_pipes, cleanup_list)
mdss_mdp_pipe_destroy(pipe);
-
- return 0;
-}
-
-int mdss_mdp_copy_splash_screen(struct mdss_panel_data *pdata)
-{
- void *virt = NULL;
- unsigned long bl_fb_addr = 0;
- unsigned long *bl_fb_addr_va;
- unsigned long pipe_addr, pipe_src_size;
- u32 height, width, rgb_size, bpp;
- size_t size;
- static struct ion_handle *ihdl;
- struct ion_client *iclient = mdss_get_ionclient();
- static ion_phys_addr_t phys;
-
- pipe_addr = MDSS_MDP_REG_SSPP_OFFSET(3) +
- MDSS_MDP_REG_SSPP_SRC0_ADDR;
- pipe_src_size =
- MDSS_MDP_REG_SSPP_OFFSET(3) + MDSS_MDP_REG_SSPP_SRC_SIZE;
-
- bpp = 3;
- rgb_size = MDSS_MDP_REG_READ(pipe_src_size);
- bl_fb_addr = MDSS_MDP_REG_READ(pipe_addr);
-
- height = (rgb_size >> 16) & 0xffff;
- width = rgb_size & 0xffff;
- size = PAGE_ALIGN(height * width * bpp);
- pr_debug("%s:%d splash_height=%d splash_width=%d Buffer size=%d\n",
- __func__, __LINE__, height, width, size);
-
- ihdl = ion_alloc(iclient, size, SZ_1M,
- ION_HEAP(ION_QSECOM_HEAP_ID), 0);
- if (IS_ERR_OR_NULL(ihdl)) {
- pr_err("unable to alloc fbmem from ion (%p)\n", ihdl);
- return -ENOMEM;
- }
-
- pdata->panel_info.splash_ihdl = ihdl;
-
- virt = ion_map_kernel(iclient, ihdl);
- ion_phys(iclient, ihdl, &phys, &size);
-
- pr_debug("%s %d Allocating %u bytes at 0x%lx (%pa phys)\n",
- __func__, __LINE__, size,
- (unsigned long int)virt, &phys);
-
- bl_fb_addr_va = (unsigned long *)ioremap(bl_fb_addr, size);
-
- memcpy(virt, bl_fb_addr_va, size);
-
- MDSS_MDP_REG_WRITE(pipe_addr, phys);
- MDSS_MDP_REG_WRITE(MDSS_MDP_REG_CTL_FLUSH + MDSS_MDP_REG_CTL_OFFSET(0),
- 0x48);
-
- return 0;
-
-}
-
-int mdss_mdp_reconfigure_splash_done(struct mdss_mdp_ctl *ctl)
-{
- struct ion_client *iclient = mdss_get_ionclient();
- struct mdss_panel_data *pdata;
- int ret = 0, off;
- int mdss_mdp_rev = MDSS_MDP_REG_READ(MDSS_MDP_REG_HW_VERSION);
- int mdss_v2_intf_off = 0;
-
- off = 0;
-
- pdata = ctl->panel_data;
-
- pdata->panel_info.cont_splash_enabled = 0;
-
- ion_free(iclient, pdata->panel_info.splash_ihdl);
-
- mdss_mdp_ctl_write(ctl, 0, MDSS_MDP_LM_BORDER_COLOR);
- off = MDSS_MDP_REG_INTF_OFFSET(ctl->intf_num);
-
- if (mdss_mdp_rev == MDSS_MDP_HW_REV_102)
- mdss_v2_intf_off = 0xEC00;
-
- /* wait for 1 VSYNC for the pipe to be unstaged */
- msleep(20);
- MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_INTF_TIMING_ENGINE_EN -
- mdss_v2_intf_off, 0);
- ret = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_CONT_SPLASH_FINISH,
- NULL);
- mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
- mdss_mdp_footswitch_ctrl_splash(0);
- return ret;
}
static int mdss_mdp_overlay_start(struct msm_fb_data_type *mfd)
@@ -721,8 +647,10 @@
return rc;
}
- if (mfd->panel_info->cont_splash_enabled)
- mdss_mdp_reconfigure_splash_done(mdp5_data->ctl);
+ if (mfd->panel_info->cont_splash_enabled) {
+ mdss_mdp_ctl_splash_finish(mdp5_data->ctl);
+ mdss_mdp_footswitch_ctrl_splash(0);
+ }
if (!is_mdss_iommu_attached()) {
mdss_iommu_attach(mdss_res);
@@ -811,7 +739,7 @@
mutex_unlock(&mfd->no_update.lock);
commit_fail:
- ret = mdss_mdp_overlay_cleanup(mfd);
+ mdss_mdp_overlay_cleanup(mfd);
mutex_unlock(&mdp5_data->ov_lock);
@@ -1006,7 +934,7 @@
return ret;
}
-static int mdss_mdp_overlay_force_cleanup(struct msm_fb_data_type *mfd)
+static void mdss_mdp_overlay_force_cleanup(struct msm_fb_data_type *mfd)
{
struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
struct mdss_mdp_ctl *ctl = mdp5_data->ctl;
@@ -1024,9 +952,7 @@
mdss_mdp_display_wait4comp(ctl);
}
- ret = mdss_mdp_overlay_cleanup(mfd);
-
- return ret;
+ mdss_mdp_overlay_cleanup(mfd);
}
static void mdss_mdp_overlay_force_dma_cleanup(struct mdss_data_type *mdata)
@@ -1899,7 +1825,10 @@
return rc;
}
- if (!IS_ERR_VALUE(rc) && mdp5_data->vsync_pending) {
+ if (IS_ERR_VALUE(rc)) {
+ pr_err("Failed to turn on fb%d\n", mfd->index);
+ mdss_mdp_overlay_off(mfd);
+ } else if (mdp5_data->vsync_pending) {
mdp5_data->vsync_pending = 0;
mdss_mdp_overlay_vsync_ctrl(mfd, mdp5_data->vsync_pending);
}
@@ -1956,7 +1885,7 @@
if (pdata->panel_info.cont_splash_enabled) {
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
mdss_mdp_footswitch_ctrl_splash(1);
- mdss_mdp_copy_splash_screen(pdata);
+ mdss_mdp_ctl_splash_start(pdata);
}
return 0;
}
diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c
index 12ff943..ce4c47c 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pp.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -671,7 +671,7 @@
else
scale_config |= /* RGB, A */
(MDSS_MDP_SCALE_FILTER_PCMN << 10) |
- (MDSS_MDP_SCALE_FILTER_NEAREST << 18);
+ (MDSS_MDP_SCALE_FILTER_PCMN << 18);
}
phasey_step = mdss_mdp_scale_phase_step(
@@ -728,7 +728,7 @@
else
scale_config |= /* RGB, A */
(MDSS_MDP_SCALE_FILTER_PCMN << 8) |
- (MDSS_MDP_SCALE_FILTER_NEAREST << 16);
+ (MDSS_MDP_SCALE_FILTER_PCMN << 16);
}
phasex_step = mdss_mdp_scale_phase_step(
diff --git a/drivers/video/msm/mdss/mdss_mdp_rotator.c b/drivers/video/msm/mdss/mdss_mdp_rotator.c
index 016c973..5d9396a 100644
--- a/drivers/video/msm/mdss/mdss_mdp_rotator.c
+++ b/drivers/video/msm/mdss/mdss_mdp_rotator.c
@@ -367,6 +367,7 @@
int mdss_mdp_rotator_release(u32 ndx)
{
+ int rc = 0;
struct mdss_mdp_rotator_session *rot;
mutex_lock(&rotator_lock);
rot = mdss_mdp_rotator_session_get(ndx);
@@ -374,11 +375,11 @@
mdss_mdp_rotator_finish(rot);
} else {
pr_warn("unknown session id=%x\n", ndx);
- return -ENOENT;
+ rc = -ENOENT;
}
mutex_unlock(&rotator_lock);
- return 0;
+ return rc;
}
int mdss_mdp_rotator_release_all(void)
diff --git a/drivers/video/msm/mdss/mdss_mdp_wb.c b/drivers/video/msm/mdss/mdss_mdp_wb.c
index 7ccf1b9..1f8244d 100644
--- a/drivers/video/msm/mdss/mdss_mdp_wb.c
+++ b/drivers/video/msm/mdss/mdss_mdp_wb.c
@@ -194,6 +194,7 @@
{
struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
struct mdss_mdp_wb *wb = mfd_to_wb(mfd);
+ int rc = 0;
mutex_lock(&mdss_mdp_wb_buf_lock);
if (wb == NULL) {
@@ -202,7 +203,8 @@
mdp5_data->wb = wb;
} else if (mfd->index != wb->fb_ndx) {
pr_err("only one writeback intf supported at a time\n");
- return -EMLINK;
+ rc = -EMLINK;
+ goto error;
} else {
pr_debug("writeback already initialized\n");
}
@@ -217,8 +219,9 @@
init_waitqueue_head(&wb->wait_q);
mdp5_data->wb = wb;
+error:
mutex_unlock(&mdss_mdp_wb_buf_lock);
- return 0;
+ return rc;
}
static int mdss_mdp_wb_terminate(struct msm_fb_data_type *mfd)
diff --git a/drivers/video/msm/mdss/mdss_panel.h b/drivers/video/msm/mdss/mdss_panel.h
index d230100..9e8cfa7 100644
--- a/drivers/video/msm/mdss/mdss_panel.h
+++ b/drivers/video/msm/mdss/mdss_panel.h
@@ -55,8 +55,35 @@
MAX_PHYS_TARGET_NUM,
};
+/**
+ * enum mdss_intf_events - Different events generated by MDP core
+ *
+ * @MDSS_EVENT_RESET: MDP control path is being (re)initialized.
+ * @MDSS_EVENT_UNBLANK: Sent before first frame update from MDP is
+ * sent to panel.
+ * @MDSS_EVENT_PANEL_ON: After first frame update from MDP.
+ * @MDSS_EVENT_BLANK: MDP has no contents to display only blank screen
+ * is shown in panel. Sent before panel off.
+ * @MDSS_EVENT_PANEL_OFF: MDP has suspended frame updates, panel should be
+ * completely shutdown after this call.
+ * @MDSS_EVENT_CLOSE: MDP has tore down entire session.
+ * @MDSS_EVENT_SUSPEND: Propagation of power suspend event.
+ * @MDSS_EVENT_RESUME: Propagation of power resume event.
+ * @MDSS_EVENT_CHECK_PARAMS: Event generated when a panel reconfiguration is
+ * requested including when resolution changes.
+ * The event handler receives pointer to
+ * struct mdss_panel_info and should return one of:
+ * - negative if the configuration is invalid
+ * - 0 if there is no panel reconfig needed
+ * - 1 if reconfig is needed to take effect
+ * @MDSS_EVENT_CONT_SPLASH_FINISH: Special event used to handle transition of
+ * display state from boot loader to panel driver.
+ * @MDSS_EVENT_FB_REGISTERED: Called after fb dev driver has been registered,
+ * panel driver gets ptr to struct fb_info which
+ * holds fb dev information.
+ */
enum mdss_intf_events {
- MDSS_EVENT_RESET,
+ MDSS_EVENT_RESET = 1,
MDSS_EVENT_UNBLANK,
MDSS_EVENT_PANEL_ON,
MDSS_EVENT_BLANK,
@@ -214,7 +241,18 @@
void (*set_backlight) (struct mdss_panel_data *pdata, u32 bl_level);
unsigned char *mmss_cc_base;
- /* function entry chain */
+ /**
+ * event_handler() - callback handler for MDP core events
+ * @pdata: Pointer refering to the panel struct associated to this
+ * event. Can be used to retrieve panel info.
+ * @e: Event being generated, see enum mdss_intf_events
+ * @arg: Optional argument to pass some info from some events.
+ *
+ * Used to register handler to be used to propagate different events
+ * happening in MDP core driver. Panel driver can listen for any of
+ * these events to perform appropriate actions for panel initialization
+ * and teardown.
+ */
int (*event_handler) (struct mdss_panel_data *pdata, int e, void *arg);
struct mdss_panel_data *next;
diff --git a/drivers/video/msm/mdss/mhl_msc.c b/drivers/video/msm/mdss/mhl_msc.c
index 96e8b67..08d0693 100644
--- a/drivers/video/msm/mdss/mhl_msc.c
+++ b/drivers/video/msm/mdss/mhl_msc.c
@@ -169,6 +169,7 @@
cmd_env = vmalloc(sizeof(struct msc_cmd_envelope));
if (!cmd_env) {
pr_err("%s: out of memory!\n", __func__);
+ mutex_unlock(&msc_send_workqueue_mutex);
return -ENOMEM;
}
diff --git a/drivers/video/msm/mdss/mhl_sii8334.c b/drivers/video/msm/mdss/mhl_sii8334.c
index a3a1a4e..21b6f24 100644
--- a/drivers/video/msm/mdss/mhl_sii8334.c
+++ b/drivers/video/msm/mdss/mhl_sii8334.c
@@ -190,7 +190,7 @@
static irqreturn_t mhl_tx_isr(int irq, void *dev_id);
static void switch_mode(struct mhl_tx_ctrl *mhl_ctrl,
- enum mhl_st_type to_mode);
+ enum mhl_st_type to_mode, bool hpd_off);
static void mhl_init_reg_settings(struct mhl_tx_ctrl *mhl_ctrl,
bool mhl_disc_en);
@@ -703,9 +703,18 @@
}
-static void switch_mode(struct mhl_tx_ctrl *mhl_ctrl, enum mhl_st_type to_mode)
+static void switch_mode(struct mhl_tx_ctrl *mhl_ctrl, enum mhl_st_type to_mode,
+ bool hpd_off)
{
struct i2c_client *client = mhl_ctrl->i2c_handle;
+ unsigned long flags;
+ int rc;
+ struct msm_hdmi_mhl_ops *hdmi_mhl_ops = mhl_ctrl->hdmi_mhl_ops;
+
+ pr_debug("%s: tx pwr on\n", __func__);
+ spin_lock_irqsave(&mhl_ctrl->lock, flags);
+ mhl_ctrl->tx_powered_off = false;
+ spin_unlock_irqrestore(&mhl_ctrl->lock, flags);
switch (to_mode) {
case POWER_STATE_D0_NO_MHL:
@@ -722,8 +731,11 @@
mhl_ctrl->cur_state = to_mode;
break;
case POWER_STATE_D3:
- if (mhl_ctrl->cur_state == POWER_STATE_D3)
+ if (mhl_ctrl->cur_state == POWER_STATE_D3) {
+ pr_debug("%s: mhl tx already in low power mode\n",
+ __func__);
break;
+ }
/* Force HPD to 0 when not in MHL mode. */
mhl_drive_hpd(mhl_ctrl, HPD_DOWN);
@@ -736,7 +748,19 @@
msleep(50);
if (!mhl_ctrl->disc_enabled)
MHL_SII_REG_NAME_MOD(REG_DISC_CTRL1, BIT1 | BIT0, 0x00);
- MHL_SII_PAGE3_MOD(0x003D, BIT0, 0x00);
+
+ spin_lock_irqsave(&mhl_ctrl->lock, flags);
+ mhl_ctrl->tx_powered_off = true;
+ spin_unlock_irqrestore(&mhl_ctrl->lock, flags);
+
+ if (hdmi_mhl_ops && hpd_off) {
+ rc = hdmi_mhl_ops->set_upstream_hpd(
+ mhl_ctrl->pdata->hdmi_pdev, 0);
+ pr_debug("%s: hdmi unset hpd %s\n", __func__,
+ rc ? "failed" : "passed");
+ }
+ msleep(200);
+ MHL_SII_PAGE1_MOD(0x003D, BIT0, 0x00);
mhl_ctrl->cur_state = POWER_STATE_D3;
break;
default:
@@ -744,6 +768,22 @@
}
}
+static bool is_mhl_powered(void *mhl_ctx)
+{
+ struct mhl_tx_ctrl *mhl_ctrl = (struct mhl_tx_ctrl *)mhl_ctx;
+ unsigned long flags;
+ bool r = false;
+
+ spin_lock_irqsave(&mhl_ctrl->lock, flags);
+ if (mhl_ctrl->tx_powered_off)
+ r = false;
+ else
+ r = true;
+ spin_unlock_irqrestore(&mhl_ctrl->lock, flags);
+
+ pr_debug("%s: ret pwr state as %x\n", __func__, r);
+ return r;
+}
void mhl_tmds_ctrl(struct mhl_tx_ctrl *mhl_ctrl, uint8_t on)
{
@@ -759,6 +799,7 @@
void mhl_drive_hpd(struct mhl_tx_ctrl *mhl_ctrl, uint8_t to_state)
{
struct i2c_client *client = mhl_ctrl->i2c_handle;
+ unsigned long flags;
pr_debug("%s: To state=[0x%x]\n", __func__, to_state);
if (to_state == HPD_UP) {
@@ -769,10 +810,13 @@
* propogate to src let HPD float by clearing
* HPD OUT OVRRD EN
*/
- MHL_SII_REG_NAME_MOD(REG_INT_CTRL, BIT4, 0x00);
+ spin_lock_irqsave(&mhl_ctrl->lock, flags);
+ mhl_ctrl->tx_powered_off = false;
+ spin_unlock_irqrestore(&mhl_ctrl->lock, flags);
+ MHL_SII_REG_NAME_MOD(REG_INT_CTRL, BIT4, 0);
} else {
/* Drive HPD to DOWN state */
- MHL_SII_REG_NAME_MOD(REG_INT_CTRL, BIT4, BIT4);
+ MHL_SII_REG_NAME_MOD(REG_INT_CTRL, (BIT4 | BIT5), BIT4);
}
}
@@ -789,9 +833,7 @@
pr_err("%s: cur st not D0\n", __func__);
return;
}
- /* spin_lock_irqsave(&mhl_state_lock, flags); */
- switch_mode(mhl_ctrl, POWER_STATE_D0_MHL);
- /* spin_unlock_irqrestore(&mhl_state_lock, flags); */
+ switch_mode(mhl_ctrl, POWER_STATE_D0_MHL, true);
MHL_SII_REG_NAME_WR(REG_MHLTX_CTL1, 0x10);
MHL_SII_CBUS_WR(0x07, 0xF2);
@@ -823,19 +865,29 @@
static void mhl_msm_disconnection(struct mhl_tx_ctrl *mhl_ctrl)
{
struct i2c_client *client = mhl_ctrl->i2c_handle;
- /*
- * MHL TX CTL1
- * Disabling Tx termination
- */
- MHL_SII_PAGE3_WR(0x30, 0xD0);
+ unsigned long flags;
- switch_mode(mhl_ctrl, POWER_STATE_D3);
+ spin_lock_irqsave(&mhl_ctrl->lock, flags);
+ mhl_ctrl->dwnstream_hpd &= ~BIT6;
+ spin_unlock_irqrestore(&mhl_ctrl->lock, flags);
+
+ /* disabling Tx termination */
+ MHL_SII_REG_NAME_WR(REG_MHLTX_CTL1, 0xD0);
+ switch_mode(mhl_ctrl, POWER_STATE_D3, true);
}
static int mhl_msm_read_rgnd_int(struct mhl_tx_ctrl *mhl_ctrl)
{
uint8_t rgnd_imp;
struct i2c_client *client = mhl_ctrl->i2c_handle;
+ struct msm_hdmi_mhl_ops *hdmi_mhl_ops = mhl_ctrl->hdmi_mhl_ops;
+ unsigned long flags;
+ int rc;
+
+ spin_lock_irqsave(&mhl_ctrl->lock, flags);
+ mhl_ctrl->tx_powered_off = false;
+ spin_unlock_irqrestore(&mhl_ctrl->lock, flags);
+
/* DISC STATUS REG 2 */
rgnd_imp = (mhl_i2c_reg_read(client, TX_PAGE_3, 0x001C) &
(BIT1 | BIT0));
@@ -843,6 +895,12 @@
if (0x02 == rgnd_imp) {
pr_debug("%s: mhl sink\n", __func__);
+ if (hdmi_mhl_ops) {
+ rc = hdmi_mhl_ops->set_upstream_hpd(
+ mhl_ctrl->pdata->hdmi_pdev, 1);
+ pr_debug("%s: hdmi set hpd %s\n", __func__,
+ rc ? "failed" : "passed");
+ }
mhl_ctrl->mhl_mode = 1;
power_supply_changed(&mhl_ctrl->mhl_psy);
if (mhl_ctrl->notify_usb_online)
@@ -850,7 +908,7 @@
} else {
pr_debug("%s: non-mhl sink\n", __func__);
mhl_ctrl->mhl_mode = 0;
- switch_mode(mhl_ctrl, POWER_STATE_D3);
+ switch_mode(mhl_ctrl, POWER_STATE_D3, true);
}
complete(&mhl_ctrl->rgnd_done);
return mhl_ctrl->mhl_mode ?
@@ -904,9 +962,9 @@
}
-static void dev_detect_isr(struct mhl_tx_ctrl *mhl_ctrl)
+static int dev_detect_isr(struct mhl_tx_ctrl *mhl_ctrl)
{
- uint8_t status, reg ;
+ uint8_t status, reg;
struct i2c_client *client = mhl_ctrl->i2c_handle;
/* INTR_STATUS4 */
@@ -916,13 +974,13 @@
if ((0x00 == status) &&\
(mhl_ctrl->cur_state == POWER_STATE_D3)) {
pr_err("%s: invalid intr\n", __func__);
- return;
+ return 0;
}
if (0xFF == status) {
pr_debug("%s: invalid intr 0xff\n", __func__);
MHL_SII_REG_NAME_WR(REG_INTR4, status);
- return;
+ return 0;
}
if ((status & BIT0) && (mhl_ctrl->chip_rev_id < 1)) {
@@ -940,31 +998,35 @@
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(0);
+ return -EACCES;
}
if (status & BIT5) {
/* clr intr - reg int4 */
pr_debug("%s: mhl discon: int4 st=%02X\n", __func__,
(int)status);
+
reg = MHL_SII_REG_NAME_RD(REG_INTR4);
MHL_SII_REG_NAME_WR(REG_INTR4, reg);
mhl_msm_disconnection(mhl_ctrl);
power_supply_changed(&mhl_ctrl->mhl_psy);
if (mhl_ctrl->notify_usb_online)
mhl_ctrl->notify_usb_online(0);
+ return -EACCES;
}
if ((mhl_ctrl->cur_state != POWER_STATE_D0_NO_MHL) &&\
(status & BIT6)) {
/* rgnd rdy Intr */
pr_debug("%s: rgnd ready intr\n", __func__);
- switch_mode(mhl_ctrl, POWER_STATE_D0_NO_MHL);
+ switch_mode(mhl_ctrl, POWER_STATE_D0_NO_MHL, true);
mhl_msm_read_rgnd_int(mhl_ctrl);
}
@@ -981,6 +1043,7 @@
release_usb_switch_open(mhl_ctrl);
}
MHL_SII_REG_NAME_WR(REG_INTR4, status);
+ return 0;
}
static void mhl_misc_isr(struct mhl_tx_ctrl *mhl_ctrl)
@@ -1000,10 +1063,13 @@
static void mhl_hpd_stat_isr(struct mhl_tx_ctrl *mhl_ctrl)
{
- uint8_t intr_1_stat;
- uint8_t cbus_stat;
+ uint8_t intr_1_stat, cbus_stat, t;
+ unsigned long flags;
struct i2c_client *client = mhl_ctrl->i2c_handle;
+ if (!is_mhl_powered(mhl_ctrl))
+ return;
+
/* INTR STATUS 1 */
intr_1_stat = MHL_SII_PAGE0_RD(0x0071);
@@ -1012,6 +1078,7 @@
/* Clear interrupts */
MHL_SII_PAGE0_WR(0x0071, intr_1_stat);
+
if (BIT6 & intr_1_stat) {
/*
* HPD status change event is pending
@@ -1019,11 +1086,21 @@
* MSC REQ ABRT REASON
*/
cbus_stat = MHL_SII_CBUS_RD(0x0D);
- if (BIT6 & cbus_stat)
- mhl_drive_hpd(mhl_ctrl, HPD_UP);
- else
- mhl_drive_hpd(mhl_ctrl, HPD_DOWN);
+ pr_debug("%s: cbus_stat=[0x%02x] cur_pwr=[%u]\n",
+ __func__, cbus_stat, mhl_ctrl->cur_state);
+ spin_lock_irqsave(&mhl_ctrl->lock, flags);
+ t = mhl_ctrl->dwnstream_hpd;
+ spin_unlock_irqrestore(&mhl_ctrl->lock, flags);
+
+ if (BIT6 & (cbus_stat ^ t)) {
+ u8 status = cbus_stat & BIT6;
+ mhl_drive_hpd(mhl_ctrl, status ? HPD_UP : HPD_DOWN);
+
+ spin_lock_irqsave(&mhl_ctrl->lock, flags);
+ mhl_ctrl->dwnstream_hpd = cbus_stat;
+ spin_unlock_irqrestore(&mhl_ctrl->lock, flags);
+ }
}
}
@@ -1257,122 +1334,9 @@
}
-static void clear_all_intrs(struct i2c_client *client)
-{
- uint8_t regval = 0x00;
-
- pr_debug_intr("********* exiting isr mask check ?? *************\n");
- pr_debug_intr("int1 mask = %02X\n",
- (int) MHL_SII_REG_NAME_RD(REG_INTR1));
- pr_debug_intr("int3 mask = %02X\n",
- (int) MHL_SII_PAGE0_RD(0x0077));
- pr_debug_intr("int4 mask = %02X\n",
- (int) MHL_SII_REG_NAME_RD(REG_INTR4));
- pr_debug_intr("int5 mask = %02X\n",
- (int) MHL_SII_REG_NAME_RD(REG_INTR5));
- pr_debug_intr("cbus1 mask = %02X\n",
- (int) MHL_SII_CBUS_RD(0x0009));
- pr_debug_intr("cbus2 mask = %02X\n",
- (int) MHL_SII_CBUS_RD(0x001F));
- pr_debug_intr("********* end of isr mask check *************\n");
-
- regval = MHL_SII_REG_NAME_RD(REG_INTR1);
- pr_debug_intr("int1 st = %02X\n", (int)regval);
- MHL_SII_REG_NAME_WR(REG_INTR1, regval);
-
- regval = MHL_SII_REG_NAME_RD(REG_INTR2);
- pr_debug_intr("int2 st = %02X\n", (int)regval);
- MHL_SII_REG_NAME_WR(REG_INTR2, regval);
-
- regval = MHL_SII_PAGE0_RD(0x0073);
- pr_debug_intr("int3 st = %02X\n", (int)regval);
- MHL_SII_PAGE0_WR(0x0073, regval);
-
- regval = MHL_SII_REG_NAME_RD(REG_INTR4);
- pr_debug_intr("int4 st = %02X\n", (int)regval);
- MHL_SII_REG_NAME_WR(REG_INTR4, regval);
-
- regval = MHL_SII_REG_NAME_RD(REG_INTR5);
- pr_debug_intr("int5 st = %02X\n", (int)regval);
- MHL_SII_REG_NAME_WR(REG_INTR5, regval);
-
- regval = MHL_SII_CBUS_RD(0x0008);
- pr_debug_intr("cbusInt st = %02X\n", (int)regval);
- MHL_SII_CBUS_WR(0x0008, regval);
-
- regval = MHL_SII_CBUS_RD(0x001E);
- pr_debug_intr("CBUS intR_2: %d\n", (int)regval);
- MHL_SII_CBUS_WR(0x001E, regval);
-
- regval = MHL_SII_CBUS_RD(0x00A0);
- pr_debug_intr("A0 int set = %02X\n", (int)regval);
- MHL_SII_CBUS_WR(0x00A0, regval);
-
- regval = MHL_SII_CBUS_RD(0x00A1);
- pr_debug_intr("A1 int set = %02X\n", (int)regval);
- MHL_SII_CBUS_WR(0x00A1, regval);
-
- regval = MHL_SII_CBUS_RD(0x00A2);
- pr_debug_intr("A2 int set = %02X\n", (int)regval);
- MHL_SII_CBUS_WR(0x00A2, regval);
-
- regval = MHL_SII_CBUS_RD(0x00A3);
- pr_debug_intr("A3 int set = %02X\n", (int)regval);
- MHL_SII_CBUS_WR(0x00A3, regval);
-
- regval = MHL_SII_CBUS_RD(0x00B0);
- pr_debug_intr("B0 st set = %02X\n", (int)regval);
- MHL_SII_CBUS_WR(0x00B0, regval);
-
- regval = MHL_SII_CBUS_RD(0x00B1);
- pr_debug_intr("B1 st set = %02X\n", (int)regval);
- MHL_SII_CBUS_WR(0x00B1, regval);
-
- regval = MHL_SII_CBUS_RD(0x00B2);
- pr_debug_intr("B2 st set = %02X\n", (int)regval);
- MHL_SII_CBUS_WR(0x00B2, regval);
-
- regval = MHL_SII_CBUS_RD(0x00B3);
- pr_debug_intr("B3 st set = %02X\n", (int)regval);
- MHL_SII_CBUS_WR(0x00B3, regval);
-
- regval = MHL_SII_CBUS_RD(0x00E0);
- pr_debug_intr("E0 st set = %02X\n", (int)regval);
- MHL_SII_CBUS_WR(0x00E0, regval);
-
- regval = MHL_SII_CBUS_RD(0x00E1);
- pr_debug_intr("E1 st set = %02X\n", (int)regval);
- MHL_SII_CBUS_WR(0x00E1, regval);
-
- regval = MHL_SII_CBUS_RD(0x00E2);
- pr_debug_intr("E2 st set = %02X\n", (int)regval);
- MHL_SII_CBUS_WR(0x00E2, regval);
-
- regval = MHL_SII_CBUS_RD(0x00E3);
- pr_debug_intr("E3 st set = %02X\n", (int)regval);
- MHL_SII_CBUS_WR(0x00E3, regval);
-
- regval = MHL_SII_CBUS_RD(0x00F0);
- pr_debug_intr("F0 int set = %02X\n", (int)regval);
- MHL_SII_CBUS_WR(0x00F0, regval);
-
- regval = MHL_SII_CBUS_RD(0x00F1);
- pr_debug_intr("F1 int set = %02X\n", (int)regval);
- MHL_SII_CBUS_WR(0x00F1, regval);
-
- regval = MHL_SII_CBUS_RD(0x00F2);
- pr_debug_intr("F2 int set = %02X\n", (int)regval);
- MHL_SII_CBUS_WR(0x00F2, regval);
-
- regval = MHL_SII_CBUS_RD(0x00F3);
- pr_debug_intr("F3 int set = %02X\n", (int)regval);
- MHL_SII_CBUS_WR(0x00F3, regval);
- pr_debug_intr("********* end of exiting in isr *************\n");
-}
-
-
static irqreturn_t mhl_tx_isr(int irq, void *data)
{
+ int rc;
struct mhl_tx_ctrl *mhl_ctrl = (struct mhl_tx_ctrl *)data;
pr_debug("%s: Getting Interrupts\n", __func__);
@@ -1380,7 +1344,11 @@
* Check RGND, MHL_EST, CBUS_LOCKOUT, SCDT
* interrupts. In D3, we get only RGND
*/
- dev_detect_isr(mhl_ctrl);
+ rc = dev_detect_isr(mhl_ctrl);
+ if (rc) {
+ pr_info("%s: dev_detect_isr rc=[%d]\n", __func__, rc);
+ return IRQ_HANDLED;
+ }
pr_debug("%s: cur pwr state is [0x%x]\n",
__func__, mhl_ctrl->cur_state);
@@ -1401,8 +1369,6 @@
mhl_hpd_stat_isr(mhl_ctrl);
}
- clear_all_intrs(mhl_ctrl->i2c_handle);
-
return IRQ_HANDLED;
}
@@ -1410,6 +1376,13 @@
{
uint8_t chip_rev_id = 0x00;
struct i2c_client *client = mhl_ctrl->i2c_handle;
+ unsigned long flags;
+
+
+ spin_lock_irqsave(&mhl_ctrl->lock, flags);
+ mhl_ctrl->dwnstream_hpd = 0;
+ mhl_ctrl->tx_powered_off = false;
+ spin_unlock_irqrestore(&mhl_ctrl->lock, flags);
/* Reset the TX chip */
mhl_sii_reset_pin(mhl_ctrl, 0);
@@ -1428,7 +1401,7 @@
* MHL-USB handshake is implemented
*/
mhl_init_reg_settings(mhl_ctrl, true);
- switch_mode(mhl_ctrl, POWER_STATE_D3);
+ switch_mode(mhl_ctrl, POWER_STATE_D0_NO_MHL, false);
return 0;
}
@@ -1710,6 +1683,7 @@
mhl_ctrl->cur_state = POWER_STATE_D0_MHL;
INIT_LIST_HEAD(&mhl_ctrl->list_cmd);
init_completion(&mhl_ctrl->msc_cmd_done);
+ spin_lock_init(&mhl_ctrl->lock);
mhl_ctrl->msc_send_workqueue = create_singlethread_workqueue
("mhl_msc_cmd_queue");
@@ -1813,7 +1787,7 @@
pr_debug("%s: i2c client addr is [%x]\n", __func__, client->addr);
if (mhl_ctrl->pdata->hdmi_pdev) {
rc = msm_hdmi_register_mhl(mhl_ctrl->pdata->hdmi_pdev,
- hdmi_mhl_ops);
+ hdmi_mhl_ops, mhl_ctrl);
if (rc) {
pr_err("%s: register with hdmi failed\n", __func__);
rc = -EPROBE_DEFER;
diff --git a/drivers/video/msm/mdss/msm_mdss_io_8974.c b/drivers/video/msm/mdss/msm_mdss_io_8974.c
index 2b07e43..5564ceb 100644
--- a/drivers/video/msm/mdss/msm_mdss_io_8974.c
+++ b/drivers/video/msm/mdss/msm_mdss_io_8974.c
@@ -275,8 +275,8 @@
} else {
MIPI_OUTP(ctrl_base + 0x0220, 0x006);
- usleep(10);
MIPI_OUTP(ctrl_base + 0x0470, 0x000);
+ MIPI_OUTP(ctrl_base + 0x0598, 0x000);
wmb();
}
}
diff --git a/include/linux/dvb/dmx.h b/include/linux/dvb/dmx.h
index c219725..aa1eba5 100644
--- a/include/linux/dvb/dmx.h
+++ b/include/linux/dvb/dmx.h
@@ -229,7 +229,15 @@
DMX_EVENT_MARKER = 0x00000100,
/* New indexing entry is ready */
- DMX_EVENT_NEW_INDEX_ENTRY = 0x00000200
+ DMX_EVENT_NEW_INDEX_ENTRY = 0x00000200,
+
+ /*
+ * Section filter timer expired. This is notified
+ * when timeout is configured to section filter
+ * (dmx_sct_filter_params) and no sections were
+ * received for the given time.
+ */
+ DMX_EVENT_SECTION_TIMEOUT = 0x00000400
};
enum dmx_oob_cmd {
@@ -706,6 +714,46 @@
__u64 types;
};
+struct dmx_set_ts_insertion {
+ /*
+ * Unique identifier managed by the caller.
+ * This identifier can be used later to remove the
+ * insertion using DMX_ABORT_TS_INSERTION ioctl.
+ */
+ __u32 identifier;
+
+ /*
+ * Repetition time in msec, minimum allowed value is 25msec.
+ * 0 repetition time means one-shot insertion is done.
+ * Insertion done based on wall-clock.
+ */
+ __u32 repetition_time;
+
+ /*
+ * TS packets buffer to be inserted.
+ * The buffer is inserted as-is to the recording buffer
+ * without any modification.
+ * It is advised to set discontinuity flag in the very
+ * first TS packet in the buffer.
+ */
+ const __u8 *ts_packets;
+
+ /*
+ * Size in bytes of the TS packets buffer to be inserted.
+ * Should be in multiples of 188 or 192 bytes
+ * depending on recording filter output format.
+ */
+ size_t size;
+};
+
+struct dmx_abort_ts_insertion {
+ /*
+ * Identifier of the insertion buffer previously set
+ * using DMX_SET_TS_INSERTION.
+ */
+ __u32 identifier;
+};
+
#define DMX_START _IO('o', 41)
#define DMX_STOP _IO('o', 42)
#define DMX_SET_FILTER _IOW('o', 43, struct dmx_sct_filter_params)
@@ -734,5 +782,7 @@
#define DMX_GET_EVENTS_MASK _IOR('o', 67, struct dmx_events_mask)
#define DMX_PUSH_OOB_COMMAND _IOW('o', 68, struct dmx_oob_command)
#define DMX_SET_INDEXING_PARAMS _IOW('o', 69, struct dmx_indexing_params)
+#define DMX_SET_TS_INSERTION _IOW('o', 70, struct dmx_set_ts_insertion)
+#define DMX_ABORT_TS_INSERTION _IOW('o', 71, struct dmx_abort_ts_insertion)
#endif /*_DVBDMX_H_*/
diff --git a/include/linux/mhl_8334.h b/include/linux/mhl_8334.h
index d8eb494..a66a411 100644
--- a/include/linux/mhl_8334.h
+++ b/include/linux/mhl_8334.h
@@ -158,6 +158,9 @@
int scrpd_busy;
int wr_burst_pending;
struct completion req_write_done;
+ spinlock_t lock;
+ bool tx_powered_off;
+ uint8_t dwnstream_hpd;
};
int mhl_i2c_reg_read(struct i2c_client *client,
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 9eef3a0..48be19a 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -82,6 +82,12 @@
#define MMC_SET_DRIVER_TYPE_D 3
};
+/* states to represent load on the host */
+enum mmc_load {
+ MMC_LOAD_HIGH,
+ MMC_LOAD_LOW,
+};
+
struct mmc_host_ops {
/*
* 'enable' is called when the host is claimed and 'disable' is called
@@ -140,6 +146,7 @@
void (*hw_reset)(struct mmc_host *host);
unsigned long (*get_max_frequency)(struct mmc_host *host);
unsigned long (*get_min_frequency)(struct mmc_host *host);
+ int (*notify_load)(struct mmc_host *, enum mmc_load);
int (*stop_request)(struct mmc_host *host);
unsigned int (*get_xfer_remain)(struct mmc_host *host);
};
@@ -401,6 +408,7 @@
bool initialized;
bool in_progress;
struct delayed_work work;
+ enum mmc_load state;
} clk_scaling;
unsigned long private[0] ____cacheline_aligned;
};
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index ca7a586..d63232a 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -72,11 +72,9 @@
#ifdef CONFIG_CMA
bool is_cma_pageblock(struct page *page);
# define is_migrate_cma(migratetype) unlikely((migratetype) == MIGRATE_CMA)
-# define cma_wmark_pages(zone) zone->min_cma_pages
#else
# define is_cma_pageblock(page) false
# define is_migrate_cma(migratetype) false
-# define cma_wmark_pages(zone) 0
#endif
#define for_each_migratetype_order(order, type) \
@@ -385,11 +383,6 @@
seqlock_t span_seqlock;
#endif
#ifdef CONFIG_CMA
- /*
- * CMA needs to increase watermark levels during the allocation
- * process to make sure that the system is not starved.
- */
- unsigned long min_cma_pages;
bool cma_alloc;
#endif
struct free_area free_area[MAX_ORDER];
diff --git a/include/linux/qpnp/qpnp-adc.h b/include/linux/qpnp/qpnp-adc.h
index 15e5dc9..13d0b80 100644
--- a/include/linux/qpnp/qpnp-adc.h
+++ b/include/linux/qpnp/qpnp-adc.h
@@ -197,15 +197,18 @@
/**
* enum qpnp_adc_scale_fn_type - Scaling function for pm8941 pre calibrated
* digital data relative to ADC reference.
- * %ADC_SCALE_DEFAULT: Default scaling to convert raw adc code to voltage.
- * %ADC_SCALE_BATT_THERM: Conversion to temperature based on btm parameters.
- * %ADC_SCALE_THERM_100K_PULLUP: Returns temperature in degC.
+ * %SCALE_DEFAULT: Default scaling to convert raw adc code to voltage (uV).
+ * %SCALE_BATT_THERM: Conversion to temperature(decidegC) based on btm
+ * parameters.
+ * %SCALE_THERM_100K_PULLUP: Returns temperature in degC.
* Uses a mapping table with 100K pullup.
- * %ADC_SCALE_PMIC_THERM: Returns result in milli degree's Centigrade.
- * %ADC_SCALE_XOTHERM: Returns XO thermistor voltage in degree's Centigrade.
- * %ADC_SCALE_THERM_150K_PULLUP: Returns temperature in degC.
+ * %SCALE_PMIC_THERM: Returns result in milli degree's Centigrade.
+ * %SCALE_XOTHERM: Returns XO thermistor voltage in degree's Centigrade.
+ * %SCALE_THERM_150K_PULLUP: Returns temperature in degC.
* Uses a mapping table with 150K pullup.
- * %ADC_SCALE_NONE: Do not use this scaling type.
+ * %SCALE_QRD_BATT_THERM: Conversion to temperature(decidegC) based on
+ * btm parameters.
+ * %SCALE_NONE: Do not use this scaling type.
*/
enum qpnp_adc_scale_fn_type {
SCALE_DEFAULT = 0,
@@ -214,6 +217,7 @@
SCALE_PMIC_THERM,
SCALE_XOTHERM,
SCALE_THERM_150K_PULLUP,
+ SCALE_QRD_BATT_THERM,
SCALE_NONE,
};
@@ -1039,7 +1043,7 @@
/**
* qpnp_adc_scale_batt_therm() - Scales the pre-calibrated digital output
* of an ADC to the ADC reference and compensates for the
- * gain and offset. Returns the temperature in degC.
+ * gain and offset. Returns the temperature in decidegC.
* @adc_code: pre-calibrated digital ouput of the ADC.
* @adc_prop: adc properties of the pm8xxx adc such as bit resolution,
* reference voltage.
@@ -1052,6 +1056,21 @@
const struct qpnp_vadc_chan_properties *chan_prop,
struct qpnp_vadc_result *chan_rslt);
/**
+ * qpnp_adc_scale_qrd_batt_therm() - Scales the pre-calibrated digital output
+ * of an ADC to the ADC reference and compensates for the
+ * gain and offset. Returns the temperature in decidegC.
+ * @adc_code: pre-calibrated digital ouput of the ADC.
+ * @adc_prop: adc properties of the pm8xxx adc such as bit resolution,
+ * reference voltage.
+ * @chan_prop: individual channel properties to compensate the i/p scaling,
+ * slope and offset.
+ * @chan_rslt: physical result to be stored.
+ */
+int32_t qpnp_adc_scale_qrd_batt_therm(int32_t adc_code,
+ const struct qpnp_adc_properties *adc_prop,
+ const struct qpnp_vadc_chan_properties *chan_prop,
+ struct qpnp_vadc_result *chan_rslt);
+/**
* qpnp_adc_scale_batt_id() - Scales the pre-calibrated digital output
* of an ADC to the ADC reference and compensates for the
* gain and offset.
@@ -1257,6 +1276,11 @@
const struct qpnp_vadc_chan_properties *chan_prop,
struct qpnp_vadc_result *chan_rslt)
{ return -ENXIO; }
+static inline int32_t qpnp_adc_scale_qrd_batt_therm(int32_t adc_code,
+ const struct qpnp_adc_properties *adc_prop,
+ const struct qpnp_vadc_chan_properties *chan_prop,
+ struct qpnp_vadc_result *chan_rslt);
+{ return -ENXIO; }
static inline int32_t qpnp_adc_scale_batt_id(int32_t adc_code,
const struct qpnp_adc_properties *adc_prop,
const struct qpnp_vadc_chan_properties *chan_prop,
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 74b09cb..4bce95c 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -700,6 +700,7 @@
#define V4L2_QCOM_BUF_FLAG_CODECCONFIG 0x4000
#define V4L2_QCOM_BUF_FLAG_EOSEQ 0x8000
#define V4L2_QCOM_BUF_TIMESTAMP_INVALID 0x10000
+#define V4L2_QCOM_BUF_FLAG_DECODEONLY 0x40000
/*
* O V E R L A Y P R E V I E W
diff --git a/include/media/msmb_isp.h b/include/media/msmb_isp.h
index bf6b23b..3775ddd 100644
--- a/include/media/msmb_isp.h
+++ b/include/media/msmb_isp.h
@@ -64,6 +64,7 @@
EVERY_8FRAME,
EVERY_16FRAME,
EVERY_32FRAME,
+ SKIP_ALL,
MAX_SKIP,
};
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
index 87730b1..f064837 100644
--- a/include/sound/apr_audio-v2.h
+++ b/include/sound/apr_audio-v2.h
@@ -6516,6 +6516,11 @@
#define AANC_HW_BLOCK_VERSION_1 (1)
#define AANC_HW_BLOCK_VERSION_2 (2)
+/*Clip bank selection*/
+#define AFE_API_VERSION_CLIP_BANK_SEL_CFG 0x1
+#define AFE_CLIP_MAX_BANKS 4
+#define AFE_PARAM_ID_CLIP_BANK_SEL_CFG 0x00010242
+
struct afe_param_aanc_port_cfg {
/* Minor version used for tracking the version of the module's
* source port configuration.
@@ -6550,6 +6555,18 @@
uint32_t aanc_hw_version;
} __packed;
+struct afe_param_id_clip_bank_sel {
+ /* Minor version used for tracking the version of the module's
+ * hw version
+ */
+ uint32_t minor_version;
+
+ /* Number of banks to be read */
+ uint32_t num_banks;
+
+ uint32_t bank_map[AFE_CLIP_MAX_BANKS];
+} __packed;
+
/* ERROR CODES */
/* Success. The operation completed with no errors. */
#define ADSP_EOK 0x00000000
@@ -6782,6 +6799,8 @@
AFE_SLIMBUS_SLAVE_CONFIG,
AFE_CDC_REGISTERS_CONFIG,
AFE_AANC_VERSION,
+ AFE_CDC_CLIP_REGISTERS_CONFIG,
+ AFE_CLIP_BANK_SEL,
AFE_MAX_CONFIG_TYPES,
};
@@ -6903,4 +6922,10 @@
/* Dolby DAP topology */
#define DOLBY_ADM_COPP_TOPOLOGY_ID 0x0001033B
+struct afe_svc_cmd_set_clip_bank_selection {
+ struct apr_hdr hdr;
+ struct afe_svc_cmd_set_param param;
+ struct afe_port_param_data_v2 pdata;
+ struct afe_param_id_clip_bank_sel bank_sel;
+} __packed;
#endif /*_APR_AUDIO_V2_H_ */
diff --git a/include/sound/apr_audio.h b/include/sound/apr_audio.h
index 40b0e1e..81636a3 100644
--- a/include/sound/apr_audio.h
+++ b/include/sound/apr_audio.h
@@ -1453,6 +1453,23 @@
u32 read_format;
} __attribute__((packed));
+#define ASM_STREAM_CMD_OPEN_LOOPBACK 0x00010D6E
+struct asm_stream_cmd_open_loopback {
+ struct apr_hdr hdr;
+ u32 mode_flags;
+/* Mode flags.
+ * Bit 0-31: reserved; client should set these bits to 0
+ */
+ u16 src_endpointype;
+ /* Endpoint type. 0 = Tx Matrix */
+ u16 sink_endpointype;
+ /* Endpoint type. 0 = Rx Matrix */
+ u32 postprocopo_id;
+/* Postprocessor topology ID. Specifies the topology of
+ * postprocessing algorithms.
+ */
+} __packed;
+
#define ADM_CMD_CONNECT_AFE_PORT 0x00010320
#define ADM_CMD_DISCONNECT_AFE_PORT 0x00010321
@@ -1909,5 +1926,4 @@
int srs_ss3d_open(int port_id, int srs_tech_id, void *srs_params);
/* SRS Studio Sound 3D end */
-
#endif /*_APR_AUDIO_H_*/
diff --git a/include/sound/q6asm.h b/include/sound/q6asm.h
index 406407d..41f875b 100644
--- a/include/sound/q6asm.h
+++ b/include/sound/q6asm.h
@@ -207,6 +207,8 @@
uint32_t rd_format,
uint32_t wr_format);
+int q6asm_open_loopack(struct audio_client *ac);
+
int q6asm_write(struct audio_client *ac, uint32_t len, uint32_t msw_ts,
uint32_t lsw_ts, uint32_t flags);
int q6asm_write_nolock(struct audio_client *ac, uint32_t len, uint32_t msw_ts,
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c
index e6a2e35..edd656c 100644
--- a/kernel/hrtimer.c
+++ b/kernel/hrtimer.c
@@ -224,13 +224,10 @@
raw_spin_unlock(&base->cpu_base->lock);
raw_spin_lock(&new_base->cpu_base->lock);
- this_cpu = smp_processor_id();
-
- if (cpu != this_cpu && (hrtimer_check_target(timer, new_base)
- || !cpu_online(cpu))) {
+ if (cpu != this_cpu && hrtimer_check_target(timer, new_base)) {
+ cpu = this_cpu;
raw_spin_unlock(&new_base->cpu_base->lock);
raw_spin_lock(&base->cpu_base->lock);
- cpu = smp_processor_id();
timer->base = base;
goto again;
}
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 69b9521..798c750 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -785,6 +785,10 @@
set_pageblock_migratetype(page, MIGRATE_CMA);
__free_pages(page, pageblock_order);
totalram_pages += pageblock_nr_pages;
+#ifdef CONFIG_HIGHMEM
+ if (PageHighMem(page))
+ totalhigh_pages += pageblock_nr_pages;
+#endif
}
#endif
@@ -5199,10 +5203,6 @@
zone->watermark[WMARK_LOW] = min_wmark_pages(zone) + (tmp >> 2);
zone->watermark[WMARK_HIGH] = min_wmark_pages(zone) + (tmp >> 1);
- zone->watermark[WMARK_MIN] += cma_wmark_pages(zone);
- zone->watermark[WMARK_LOW] += cma_wmark_pages(zone);
- zone->watermark[WMARK_HIGH] += cma_wmark_pages(zone);
-
setup_zone_migrate_reserve(zone);
spin_unlock_irqrestore(&zone->lock, flags);
}
@@ -5820,54 +5820,6 @@
return ret > 0 ? 0 : ret;
}
-/*
- * Update zone's cma pages counter used for watermark level calculation.
- */
-static inline void __update_cma_watermarks(struct zone *zone, int count)
-{
- unsigned long flags;
- spin_lock_irqsave(&zone->lock, flags);
- zone->min_cma_pages += count;
- spin_unlock_irqrestore(&zone->lock, flags);
- setup_per_zone_wmarks();
-}
-
-/*
- * Trigger memory pressure bump to reclaim some pages in order to be able to
- * allocate 'count' pages in single page units. Does similar work as
- *__alloc_pages_slowpath() function.
- */
-static int __reclaim_pages(struct zone *zone, gfp_t gfp_mask, int count)
-{
- enum zone_type high_zoneidx = gfp_zone(gfp_mask);
- struct zonelist *zonelist = node_zonelist(0, gfp_mask);
- int did_some_progress = 0;
- int order = 1;
-
- /*
- * Increase level of watermarks to force kswapd do his job
- * to stabilise at new watermark level.
- */
- __update_cma_watermarks(zone, count);
-
- /* Obey watermarks as if the page was being allocated */
- while (!zone_watermark_ok(zone, 0, low_wmark_pages(zone), 0, 0)) {
- wake_all_kswapd(order, zonelist, high_zoneidx, zone_idx(zone));
-
- did_some_progress = __perform_reclaim(gfp_mask, order, zonelist,
- NULL);
- if (!did_some_progress) {
- /* Exhausted what can be done so it's blamo time */
- out_of_memory(zonelist, gfp_mask, order, NULL, false);
- }
- }
-
- /* Restore original watermark levels. */
- __update_cma_watermarks(zone, -count);
-
- return count;
-}
-
/**
* alloc_contig_range() -- tries to allocate given range of pages
* @start: start PFN to allocate
@@ -5968,11 +5920,6 @@
goto done;
}
- /*
- * Reclaim enough pages to make sure that contiguous allocation
- * will not starve the system.
- */
- __reclaim_pages(zone, GFP_HIGHUSER_MOVABLE, end-start);
/* Grab isolated pages from freelists. */
outer_end = isolate_freepages_range(outer_start, end);
diff --git a/sound/soc/codecs/msm8x10-wcd.c b/sound/soc/codecs/msm8x10-wcd.c
index c8647fb1..e1a904f 100644
--- a/sound/soc/codecs/msm8x10-wcd.c
+++ b/sound/soc/codecs/msm8x10-wcd.c
@@ -34,6 +34,7 @@
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/tlv.h>
+#include <mach/qdsp6v2/apr.h>
#include "msm8x10-wcd.h"
#include "wcd9xxx-resmgr.h"
#include "msm8x10_wcd_registers.h"
@@ -52,7 +53,7 @@
#define MAX_MSM8X10_WCD_DEVICE 4
#define CODEC_DT_MAX_PROP_SIZE 40
-#define MSM8X10_WCD_I2C_GSBI_SLAVE_ID "1-000d"
+#define MSM8X10_WCD_I2C_GSBI_SLAVE_ID "5-000d"
enum {
MSM8X10_WCD_I2C_TOP_LEVEL = 0,
@@ -82,6 +83,12 @@
static struct snd_soc_dai_driver msm8x10_wcd_i2s_dai[];
static const DECLARE_TLV_DB_SCALE(aux_pga_gain, 0, 2, 0);
+#define MSM8X10_WCD_ACQUIRE_LOCK(x) do { \
+ mutex_lock_nested(&x, SINGLE_DEPTH_NESTING); \
+} while (0)
+#define MSM8X10_WCD_RELEASE_LOCK(x) do { mutex_unlock(&x); } while (0)
+
+
/* Codec supports 2 IIR filters */
enum {
IIR1 = 0,
@@ -99,6 +106,12 @@
BAND_MAX,
};
+enum msm8x10_wcd_bandgap_type {
+ MSM8X10_WCD_BANDGAP_OFF = 0,
+ MSM8X10_WCD_BANDGAP_AUDIO_MODE,
+ MSM8X10_WCD_BANDGAP_MBHC_MODE,
+};
+
struct hpf_work {
struct msm8x10_wcd_priv *msm8x10_wcd;
u32 decimator;
@@ -113,11 +126,14 @@
u32 adc_count;
u32 rx_bias_count;
s32 dmic_1_2_clk_cnt;
-
+ enum msm8x10_wcd_bandgap_type bandgap_type;
+ bool mclk_enabled;
+ bool clock_active;
+ bool config_mode_active;
+ bool mbhc_polling_active;
+ struct mutex codec_resource_lock;
/* resmgr module */
struct wcd9xxx_resmgr resmgr;
- /* mbhc module */
- struct wcd9xxx_mbhc mbhc;
};
static unsigned short rx_digital_gain_reg[] = {
@@ -139,8 +155,8 @@
};
static char *msm8x10_wcd_supplies[] = {
- "cdc-vdd-mic-bias", "cdc-vdda-h", "cdc-vdd-1p2", "cdc-vdd-px",
- "cdc-vdda-cp",
+ "cdc-vdda-cp", "cdc-vdda-h", "cdc-vdd-px", "cdc-vdd-1p2v",
+ "cdc-vdd-mic-bias",
};
static int msm8x10_wcd_dt_parse_vreg_info(struct device *dev,
@@ -158,7 +174,6 @@
{
int rtn = 0;
int value = ((reg & 0x0f00) >> 8) & 0x000f;
- pr_debug("%s: reg(0x%x) value(%d)\n", __func__, reg, value);
switch (value) {
case 0:
case 1:
@@ -171,7 +186,7 @@
return rtn;
}
-static int msm8x10_wcd_abh_write_device(u16 reg, unsigned int *value, u32 bytes)
+static int msm8x10_wcd_abh_write_device(u16 reg, u8 *value, u32 bytes)
{
u32 temp = ((u32)(*value)) & 0x000000FF;
u32 offset = (((u32)(reg)) ^ 0x00000400) & 0x00000FFF;
@@ -179,11 +194,13 @@
return 0;
}
-static int msm8x10_wcd_abh_read_device(u16 reg, u32 bytes, unsigned int *value)
+static int msm8x10_wcd_abh_read_device(u16 reg, u32 bytes, u8 *value)
{
+ u32 temp;
u32 offset = (((u32)(reg)) ^ 0x00000400) & 0x00000FFF;
- *value = ioread32(ioremap(MSM8X10_DINO_CODEC_BASE_ADDR +
+ temp = ioread32(ioremap(MSM8X10_DINO_CODEC_BASE_ADDR +
offset, 4));
+ *value = (u8)temp;
return 0;
}
@@ -274,7 +291,7 @@
}
}
}
- pr_debug("%s: Reg 0x%x = 0x%x\n", __func__, reg, *dest);
+ pr_debug("%s: reg 0x%x = 0x%x\n", __func__, reg, *dest);
return 0;
}
@@ -292,20 +309,22 @@
u16 reg, unsigned int *val)
{
int ret = -EINVAL;
+ u8 temp;
/* check if use I2C interface for Helicon or AHB for Dino */
mutex_lock(&msm8x10_wcd->io_lock);
if (MSM8X10_WCD_IS_HELICON_REG(reg))
- ret = msm8x10_wcd_i2c_read(reg, 1, val);
+ ret = msm8x10_wcd_i2c_read(reg, 1, &temp);
else if (MSM8X10_WCD_IS_DINO_REG(reg))
- ret = msm8x10_wcd_abh_read_device(reg, 1, val);
+ ret = msm8x10_wcd_abh_read_device(reg, 1, &temp);
mutex_unlock(&msm8x10_wcd->io_lock);
+ *val = temp;
return ret;
}
static int msm8x10_wcd_reg_write(struct msm8x10_wcd *msm8x10_wcd, u16 reg,
- unsigned int val)
+ u8 val)
{
int ret = -EINVAL;
@@ -393,7 +412,7 @@
reg, ret);
}
- return msm8x10_wcd_reg_write(codec->control_data, reg, value);
+ return msm8x10_wcd_reg_write(codec->control_data, reg, (u8)value);
}
static unsigned int msm8x10_wcd_read(struct snd_soc_codec *codec,
@@ -438,10 +457,14 @@
regnode = of_parse_phandle(dev->of_node, prop_name, 0);
if (!regnode) {
- dev_err(dev, "Looking up %s property in node %s failed",
+ dev_err(dev, "Looking up %s property in node %s failed\n",
prop_name, dev->of_node->full_name);
return -ENODEV;
}
+
+ dev_dbg(dev, "Looking up %s property in node %s\n",
+ prop_name, dev->of_node->full_name);
+
vreg->name = vreg_name;
snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
@@ -481,17 +504,7 @@
u32 prop_val;
snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
- "qcom,cdc-micbias-ldoh-v");
- ret = of_property_read_u32(dev->of_node, prop_name, &prop_val);
- if (ret) {
- dev_err(dev, "Looking up %s property in node %s failed",
- prop_name, dev->of_node->full_name);
- return -ENODEV;
- }
- micbias->ldoh_v = (u8)prop_val;
-
- snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
- "qcom,cdc-micbias-cfilt1-mv");
+ "qcom,cdc-micbias-cfilt-mv");
ret = of_property_read_u32(dev->of_node, prop_name,
&micbias->cfilt1_mv);
if (ret) {
@@ -501,7 +514,7 @@
}
snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
- "qcom,cdc-micbias1-cfilt-sel");
+ "qcom,cdc-micbias-cfilt-sel");
ret = of_property_read_u32(dev->of_node, prop_name, &prop_val);
if (ret) {
dev_err(dev, "Looking up %s property in node %s failed",
@@ -559,23 +572,14 @@
if (ret)
goto err;
}
-
ret = msm8x10_wcd_dt_parse_micbias_info(dev, &pdata->micbias);
if (ret)
goto err;
-
- pdata->reset_gpio = of_get_named_gpio(dev->of_node,
- "qcom,cdc-reset-gpio", 0);
- if (pdata->reset_gpio < 0) {
- dev_err(dev, "Looking up %s property in node %s failed %d\n",
- "qcom, cdc-reset-gpio", dev->of_node->full_name,
- pdata->reset_gpio);
- goto err;
- }
- dev_dbg(dev, "%s: reset gpio %d", __func__, pdata->reset_gpio);
return pdata;
err:
devm_kfree(dev, pdata);
+ dev_err(dev, "%s: Failed to populate DT data ret = %d\n",
+ __func__, ret);
return NULL;
}
@@ -611,6 +615,9 @@
MSM8X10_WCD_A_CDC_CLK_OTHR_CTL, 0x01,
0x00);
snd_soc_update_bits(codec,
+ MSM8X10_WCD_A_CDC_CLK_OTHR_RESET_B1_CTL,
+ 0x01, 0x01);
+ snd_soc_update_bits(codec,
MSM8X10_WCD_A_CP_STATIC, 0x08, 0x00);
break;
}
@@ -846,7 +853,7 @@
SOC_ENUM_EXT("EAR PA Gain", msm8x10_wcd_ear_pa_gain_enum[0],
msm8x10_wcd_pa_gain_get, msm8x10_wcd_pa_gain_put),
- SOC_SINGLE_TLV("LINEOUT1 Volume", MSM8X10_WCD_A_RX_LINE_1_GAIN,
+ SOC_SINGLE_TLV("LINEOUT Volume", MSM8X10_WCD_A_RX_LINE_1_GAIN,
0, 12, 1, line_gain),
SOC_SINGLE_TLV("HPHL Volume", MSM8X10_WCD_A_RX_HPH_L_GAIN,
@@ -1102,9 +1109,6 @@
switch (decimator) {
case 1:
case 2:
- if (dec_mux == 1)
- adc_dmic_sel = 0x1;
- else
adc_dmic_sel = 0x0;
break;
default:
@@ -1148,68 +1152,6 @@
SOC_DAPM_SINGLE("Switch", MSM8X10_WCD_A_RX_HPH_L_DAC_CTL, 6, 1, 0)
};
-/* virtual port entries */
-static int slim_tx_mixer_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
- struct snd_soc_dapm_widget *widget = wlist->widgets[0];
-
- ucontrol->value.integer.value[0] = widget->value;
- return 0;
-}
-
-static int slim_tx_mixer_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- return 0;
-}
-
-static int slim_rx_mux_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
- struct snd_soc_dapm_widget *widget = wlist->widgets[0];
-
- ucontrol->value.enumerated.item[0] = widget->value;
- return 0;
-}
-
-static int slim_rx_mux_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- return 0;
-}
-
-
-static const char *const slim_rx_mux_text[] = {
- "ZERO", "AIF1_PB"
-};
-
-static const struct soc_enum slim_rx_mux_enum =
- SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(slim_rx_mux_text), slim_rx_mux_text);
-
-static const struct snd_kcontrol_new slim_rx_mux[MSM8X10_WCD_RX_MAX] = {
- SOC_DAPM_ENUM_EXT("I2S RX1 Mux", slim_rx_mux_enum,
- slim_rx_mux_get, slim_rx_mux_put),
- SOC_DAPM_ENUM_EXT("I2S RX2 Mux", slim_rx_mux_enum,
- slim_rx_mux_get, slim_rx_mux_put),
- SOC_DAPM_ENUM_EXT("I2S RX3 Mux", slim_rx_mux_enum,
- slim_rx_mux_get, slim_rx_mux_put),
-};
-
-static const struct snd_kcontrol_new aif_cap_mixer[] = {
- SOC_SINGLE_EXT("I2S TX1", SND_SOC_NOPM, MSM8X10_WCD_TX1, 1, 0,
- slim_tx_mixer_get, slim_tx_mixer_put),
- SOC_SINGLE_EXT("I2S TX2", SND_SOC_NOPM, MSM8X10_WCD_TX2, 1, 0,
- slim_tx_mixer_get, slim_tx_mixer_put),
- SOC_SINGLE_EXT("I2S TX3", SND_SOC_NOPM, MSM8X10_WCD_TX3, 1, 0,
- slim_tx_mixer_get, slim_tx_mixer_put),
- SOC_SINGLE_EXT("I2S TX4", SND_SOC_NOPM, MSM8X10_WCD_TX4, 1, 0,
- slim_tx_mixer_get, slim_tx_mixer_put),
-};
-
-
static void msm8x10_wcd_codec_enable_adc_block(struct snd_soc_codec *codec,
int enable)
{
@@ -1243,7 +1185,7 @@
if (w->reg == MSM8X10_WCD_A_TX_1_EN)
init_bit_shift = 7;
- else if (adc_reg == MSM8X10_WCD_A_TX_2_EN)
+ else if (w->reg == MSM8X10_WCD_A_TX_2_EN)
init_bit_shift = 6;
else {
dev_err(codec->dev, "%s: Error, invalid adc register\n",
@@ -1365,54 +1307,36 @@
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = w->codec;
- struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
u16 micb_int_reg;
- u8 cfilt_sel_val = 0;
char *internal1_text = "Internal1";
char *internal2_text = "Internal2";
char *internal3_text = "Internal3";
- enum wcd9xxx_notify_event e_post_off, e_pre_on, e_post_on;
dev_dbg(codec->dev, "%s %d\n", __func__, event);
switch (w->reg) {
case MSM8X10_WCD_A_MICB_1_CTL:
micb_int_reg = MSM8X10_WCD_A_MICB_1_INT_RBIAS;
- cfilt_sel_val =
- msm8x10_wcd->resmgr.pdata->micbias.bias1_cfilt_sel;
- e_pre_on = WCD9XXX_EVENT_PRE_MICBIAS_1_ON;
- e_post_on = WCD9XXX_EVENT_POST_MICBIAS_1_ON;
- e_post_off = WCD9XXX_EVENT_POST_MICBIAS_1_OFF;
break;
default:
dev_err(codec->dev,
- "%s: Error, invalid micbias register\n", __func__);
+ "%s: Error, invalid micbias register 0x%x\n",
+ __func__, w->reg);
return -EINVAL;
}
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
- /* Let MBHC module know so micbias switch to be off */
- wcd9xxx_resmgr_notifier_call(&msm8x10_wcd->resmgr, e_pre_on);
-
- /* Get cfilt */
- wcd9xxx_resmgr_cfilt_get(&msm8x10_wcd->resmgr, cfilt_sel_val);
-
if (strnstr(w->name, internal1_text, 30))
- snd_soc_update_bits(codec, micb_int_reg, 0xE0, 0xE0);
+ snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x80);
else if (strnstr(w->name, internal2_text, 30))
- snd_soc_update_bits(codec, micb_int_reg, 0x1C, 0x1C);
+ snd_soc_update_bits(codec, micb_int_reg, 0x10, 0x10);
else if (strnstr(w->name, internal3_text, 30))
- snd_soc_update_bits(codec, micb_int_reg, 0x3, 0x3);
+ snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x2);
break;
case SND_SOC_DAPM_POST_PMU:
usleep_range(20000, 20100);
- /* Let MBHC module know so micbias is on */
- wcd9xxx_resmgr_notifier_call(&msm8x10_wcd->resmgr, e_post_on);
break;
case SND_SOC_DAPM_POST_PMD:
- /* Let MBHC module know so micbias switch to be off */
- wcd9xxx_resmgr_notifier_call(&msm8x10_wcd->resmgr, e_post_off);
-
if (strnstr(w->name, internal1_text, 30))
snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x00);
else if (strnstr(w->name, internal2_text, 30))
@@ -1420,14 +1344,36 @@
else if (strnstr(w->name, internal3_text, 30))
snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x0);
- /* Put cfilt */
- wcd9xxx_resmgr_cfilt_put(&msm8x10_wcd->resmgr, cfilt_sel_val);
break;
}
-
return 0;
}
+static void tx_hpf_corner_freq_callback(struct work_struct *work)
+{
+ struct delayed_work *hpf_delayed_work;
+ struct hpf_work *hpf_work;
+ struct msm8x10_wcd_priv *msm8x10_wcd;
+ struct snd_soc_codec *codec;
+ u16 tx_mux_ctl_reg;
+ u8 hpf_cut_of_freq;
+
+ hpf_delayed_work = to_delayed_work(work);
+ hpf_work = container_of(hpf_delayed_work, struct hpf_work, dwork);
+ msm8x10_wcd = hpf_work->msm8x10_wcd;
+ codec = hpf_work->msm8x10_wcd->codec;
+ hpf_cut_of_freq = hpf_work->tx_hpf_cut_of_freq;
+
+ tx_mux_ctl_reg = MSM8X10_WCD_A_CDC_TX1_MUX_CTL +
+ (hpf_work->decimator - 1) * 32;
+
+ dev_info(codec->dev, "%s(): decimator %u hpf_cut_of_freq 0x%x\n",
+ __func__, hpf_work->decimator, (unsigned int)hpf_cut_of_freq);
+
+ snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30, hpf_cut_of_freq << 4);
+}
+
+
#define TX_MUX_CTL_CUT_OFF_FREQ_MASK 0x30
#define CF_MIN_3DB_4HZ 0x0
#define CF_MIN_3DB_75HZ 0x1
@@ -1582,6 +1528,7 @@
{
struct snd_soc_codec *codec = w->codec;
struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
+ msm8x10_wcd->resmgr.codec = codec;
dev_dbg(codec->dev, "%s %d\n", __func__, event);
@@ -1697,21 +1644,12 @@
{"I2S TX1", NULL, "TX_I2S_CLK"},
{"I2S TX2", NULL, "TX_I2S_CLK"},
- {"I2S TX3", NULL, "TX_I2S_CLK"},
- {"I2S TX4", NULL, "TX_I2S_CLK"},
- {"AIF1 CAP", NULL, "AIF1_CAP Mixer"},
+ {"DEC1 MUX", NULL, "TX CLK"},
+ {"DEC2 MUX", NULL, "TX CLK"},
- {"AIF1_CAP Mixer", "I2S TX1", "I2S TX1 MUX"},
- {"AIF1_CAP Mixer", "I2S TX2", "I2S TX2 MUX"},
- {"AIF1_CAP Mixer", "I2S TX3", "I2S TX3 MUX"},
- {"AIF1_CAP Mixer", "I2S TX4", "I2S TX4 MUX"},
-
- {"I2S TX1 MUX", NULL, "DEC1 MUX"},
- {"I2S TX2 MUX", NULL, "DEC2 MUX"},
- {"I2S TX3 MUX", NULL, "RX1 MIX1"},
- {"I2S TX4 MUX", "RMIX2", "RX1 MIX2"},
- {"I2S TX4 MUX", "RMIX3", "RX1 MIX3"},
+ {"I2S TX1", NULL, "DEC1 MUX"},
+ {"I2S TX2", NULL, "DEC2 MUX"},
/* Earpiece (RX MIX1) */
{"EAR", NULL, "EAR PA"},
@@ -1725,33 +1663,32 @@
{"HPHL", NULL, "HPHL DAC"},
{"HPHR", NULL, "HPHR DAC"},
- {"HPHR_PA_MIXER", NULL, "HPHR DAC"},
{"HPHL DAC", NULL, "CP"},
{"HPHR DAC", NULL, "CP"},
+ {"SPK DAC", NULL, "CP"},
{"DAC1", "Switch", "RX1 CHAIN"},
{"HPHL DAC", "Switch", "RX1 CHAIN"},
{"HPHR DAC", NULL, "RX2 CHAIN"},
- {"LINEOUT1", NULL, "LINEOUT1 PA"},
+ {"LINEOUT", NULL, "LINEOUT PA"},
{"SPK_OUT", NULL, "SPK PA"},
- {"LINEOUT1 PA", NULL, "CP"},
- {"LINEOUT1 PA", NULL, "LINEOUT1 DAC"},
+ {"LINEOUT PA", NULL, "CP"},
+ {"LINEOUT PA", NULL, "LINEOUT DAC"},
- {"LINEOUT1 DAC", "RX2 INPUT", "RX2 MIX1"},
- {"LINEOUT1 DAC", "RX3 INPUT", "RX3 MIX1"},
-
+ {"CP", NULL, "RX_BIAS"},
{"SPK PA", NULL, "SPK DAC"},
- {"SPK DAC", NULL, "RX7 MIX2"},
+ {"SPK DAC", NULL, "RX3 CHAIN"},
+ {"RX1 CHAIN", NULL, "RX1 CLK"},
+ {"RX2 CHAIN", NULL, "RX2 CLK"},
+ {"RX3 CHAIN", NULL, "RX3 CLK"},
{"RX1 CHAIN", NULL, "RX1 MIX2"},
{"RX2 CHAIN", NULL, "RX2 MIX2"},
-
- {"LINEOUT1 DAC", NULL, "RX_BIAS"},
- {"SPK DAC", NULL, "RX_BIAS"},
+ {"RX3 CHAIN", NULL, "RX3 MIX1"},
{"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
{"RX1 MIX1", NULL, "RX1 MIX1 INP2"},
@@ -1761,19 +1698,7 @@
{"RX3 MIX1", NULL, "RX3 MIX1 INP1"},
{"RX3 MIX1", NULL, "RX3 MIX1 INP2"},
{"RX1 MIX2", NULL, "RX1 MIX1"},
- {"RX1 MIX2", NULL, "RX1 MIX2 INP1"},
- {"RX1 MIX2", NULL, "RX1 MIX2 INP2"},
{"RX2 MIX2", NULL, "RX2 MIX1"},
- {"RX2 MIX2", NULL, "RX2 MIX2 INP1"},
- {"RX2 MIX2", NULL, "RX2 MIX2 INP2"},
-
- {"I2S RX1 MUX", "AIF1_PB", "AIF1 PB"},
- {"I2S RX2 MUX", "AIF1_PB", "AIF1 PB"},
- {"I2S RX3 MUX", "AIF1_PB", "AIF1 PB"},
-
- {"I2S RX1", NULL, "I2S RX1 MUX"},
- {"I2S RX2", NULL, "I2S RX2 MUX"},
- {"I2S RX3", NULL, "I2S RX3 MUX"},
{"RX1 MIX1 INP1", "RX1", "I2S RX1"},
{"RX1 MIX1 INP1", "RX2", "I2S RX2"},
@@ -1825,41 +1750,109 @@
{"IIR1", NULL, "IIR1 INP1 MUX"},
{"IIR1 INP1 MUX", "DEC1", "DEC1 MUX"},
{"IIR1 INP1 MUX", "DEC2", "DEC2 MUX"},
-
- /* There is no LDO_H in Helicon */
- {"MIC BIAS1 Internal1", NULL, "LDO_H"},
- {"MIC BIAS1 Internal2", NULL, "LDO_H"},
- {"MIC BIAS1 External", NULL, "LDO_H"},
+ {"MIC BIAS Internal2", NULL, "INT_LDO_H"},
+ {"MIC BIAS External", NULL, "INT_LDO_H"},
};
static int msm8x10_wcd_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct msm8x10_wcd *msm8x10_wcd_core =
- dev_get_drvdata(dai->codec->dev);
dev_dbg(dai->codec->dev, "%s(): substream = %s stream = %d\n",
__func__,
substream->name, substream->stream);
- if ((msm8x10_wcd_core != NULL) &&
- (msm8x10_wcd_core->dev != NULL))
- pm_runtime_get_sync(msm8x10_wcd_core->dev);
-
return 0;
}
static void msm8x10_wcd_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct msm8x10_wcd *msm8x10_wcd_core =
- dev_get_drvdata(dai->codec->dev);
dev_dbg(dai->codec->dev,
"%s(): substream = %s stream = %d\n" , __func__,
substream->name, substream->stream);
- if ((msm8x10_wcd_core != NULL) &&
- (msm8x10_wcd_core->dev != NULL)) {
- pm_runtime_mark_last_busy(msm8x10_wcd_core->dev);
- pm_runtime_put(msm8x10_wcd_core->dev);
+}
+
+static int msm8x10_wcd_codec_enable_clock_block(struct snd_soc_codec *codec,
+ int enable)
+{
+ if (enable) {
+ snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLK_MCLK_CTL,
+ 0x01, 0x01);
+ snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLK_PDM_CTL,
+ 0x03, 0x03);
+ snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_TOP_CLK_CTL,
+ 0x0f, 0x0d);
+ } else {
+ snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_TOP_CLK_CTL,
+ 0x0f, 0x00);
+ snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLK_MCLK_CTL,
+ 0x01, 0x01);
+ snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLK_MCLK_CTL,
+ 0x03, 0x00);
}
+ return 0;
+}
+
+static void msm8x10_wcd_codec_enable_audio_mode_bandgap(struct snd_soc_codec
+ *codec)
+{
+ snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL, 0x80,
+ 0x80);
+ snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL, 0x04,
+ 0x04);
+ snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL, 0x01,
+ 0x01);
+ usleep_range(1000, 1000);
+ snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL, 0x80,
+ 0x00);
+}
+
+static void msm8x10_wcd_codec_enable_bandgap(struct snd_soc_codec *codec,
+ enum msm8x10_wcd_bandgap_type choice)
+{
+ struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
+
+ /* TODO lock resources accessed by audio streams and threaded
+ * interrupt handlers
+ */
+
+ dev_dbg(codec->dev, "%s, choice is %d, current is %d\n",
+ __func__, choice,
+ msm8x10_wcd->bandgap_type);
+
+ if (msm8x10_wcd->bandgap_type == choice)
+ return;
+
+ if ((msm8x10_wcd->bandgap_type == MSM8X10_WCD_BANDGAP_OFF) &&
+ (choice == MSM8X10_WCD_BANDGAP_AUDIO_MODE)) {
+ msm8x10_wcd_codec_enable_audio_mode_bandgap(codec);
+ } else if (choice == MSM8X10_WCD_BANDGAP_MBHC_MODE) {
+ /* bandgap mode becomes fast,
+ * mclk should be off or clk buff source souldn't be VBG
+ * Let's turn off mclk always */
+ snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL,
+ 0x2, 0x2);
+ snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL,
+ 0x80, 0x80);
+ snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL,
+ 0x4, 0x4);
+ snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL,
+ 0x01, 0x01);
+ usleep_range(1000, 1000);
+ snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL,
+ 0x80, 0x00);
+ } else if ((msm8x10_wcd->bandgap_type ==
+ MSM8X10_WCD_BANDGAP_MBHC_MODE) &&
+ (choice == MSM8X10_WCD_BANDGAP_AUDIO_MODE)) {
+ snd_soc_write(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL, 0x50);
+ usleep_range(100, 100);
+ msm8x10_wcd_codec_enable_audio_mode_bandgap(codec);
+ } else if (choice == MSM8X10_WCD_BANDGAP_OFF) {
+ snd_soc_write(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL, 0x50);
+ } else {
+ dev_err(codec->dev,
+ "%s: Error, Invalid bandgap settings\n", __func__);
+ }
+ msm8x10_wcd->bandgap_type = choice;
}
int msm8x10_wcd_mclk_enable(struct snd_soc_codec *codec,
@@ -1867,24 +1860,30 @@
{
struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
- dev_dbg(codec->dev,
- "%s: mclk_enable = %u, dapm = %d\n", __func__,
- mclk_enable, dapm);
- WCD9XXX_BCL_LOCK(&msm8x10_wcd->resmgr);
+ dev_dbg(codec->dev, "%s: mclk_enable = %u, dapm = %d\n",
+ __func__, mclk_enable, dapm);
+ if (dapm)
+ MSM8X10_WCD_ACQUIRE_LOCK(msm8x10_wcd->codec_resource_lock);
if (mclk_enable) {
- wcd9xxx_resmgr_get_bandgap(&msm8x10_wcd->resmgr,
- WCD9XXX_BANDGAP_AUDIO_MODE);
- wcd9xxx_resmgr_get_clk_block(&msm8x10_wcd->resmgr,
- WCD9XXX_CLK_MCLK);
+ msm8x10_wcd->mclk_enabled = true;
+ msm8x10_wcd_codec_enable_bandgap(codec,
+ MSM8X10_WCD_BANDGAP_AUDIO_MODE);
+ msm8x10_wcd_codec_enable_clock_block(codec, 1);
} else {
- /* Put clock and BG */
- wcd9xxx_resmgr_put_clk_block(&msm8x10_wcd->resmgr,
- WCD9XXX_CLK_MCLK);
- wcd9xxx_resmgr_put_bandgap(&msm8x10_wcd->resmgr,
- WCD9XXX_BANDGAP_AUDIO_MODE);
+ if (!msm8x10_wcd->mclk_enabled) {
+ if (dapm)
+ MSM8X10_WCD_RELEASE_LOCK(
+ msm8x10_wcd->codec_resource_lock);
+ dev_err(codec->dev, "Error, MCLK already diabled\n");
+ return -EINVAL;
+ }
+ msm8x10_wcd->mclk_enabled = false;
+ msm8x10_wcd_codec_enable_clock_block(codec, 0);
+ msm8x10_wcd_codec_enable_bandgap(codec,
+ MSM8X10_WCD_BANDGAP_OFF);
}
- WCD9XXX_BCL_UNLOCK(&msm8x10_wcd->resmgr);
-
+ if (dapm)
+ MSM8X10_WCD_RELEASE_LOCK(msm8x10_wcd->codec_resource_lock);
return 0;
}
@@ -2027,7 +2026,7 @@
.rate_max = 192000,
.rate_min = 8000,
.channels_min = 1,
- .channels_max = 4,
+ .channels_max = 3,
},
.ops = &msm8x10_wcd_dai_ops,
},
@@ -2077,23 +2076,16 @@
SND_SOC_DAPM_MIXER("DAC1", MSM8X10_WCD_A_RX_EAR_EN, 6, 0, dac1_switch,
ARRAY_SIZE(dac1_switch)),
- SND_SOC_DAPM_AIF_IN("AIF1 PB", "AIF1 Playback", 0, SND_SOC_NOPM,
- AIF1_PB, 0),
+ SND_SOC_DAPM_AIF_IN("I2S RX1", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
- SND_SOC_DAPM_MUX("I2S RX1 MUX", SND_SOC_NOPM, MSM8X10_WCD_RX1, 0,
- &slim_rx_mux[MSM8X10_WCD_RX1]),
- SND_SOC_DAPM_MUX("I2S RX2 MUX", SND_SOC_NOPM, MSM8X10_WCD_RX2, 0,
- &slim_rx_mux[MSM8X10_WCD_RX2]),
- SND_SOC_DAPM_MUX("I2S RX3 MUX", SND_SOC_NOPM, MSM8X10_WCD_RX3, 0,
- &slim_rx_mux[MSM8X10_WCD_RX3]),
+ SND_SOC_DAPM_AIF_IN("I2S RX2", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
- SND_SOC_DAPM_MIXER("I2S RX1", SND_SOC_NOPM, 0, 0, NULL, 0),
- SND_SOC_DAPM_MIXER("I2S RX2", SND_SOC_NOPM, 0, 0, NULL, 0),
- SND_SOC_DAPM_MIXER("I2S RX3", SND_SOC_NOPM, 0, 0, NULL, 0),
- SND_SOC_DAPM_MIXER("I2S RX4", SND_SOC_NOPM, 0, 0, NULL, 0),
- SND_SOC_DAPM_MIXER("I2S RX5", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_AIF_IN("I2S RX3", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
- /* Headphone */
+ SND_SOC_DAPM_SUPPLY("TX CLK", MSM8X10_WCD_A_CDC_DIG_CLK_CTL,
+ 4, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("INT_LDO_H", SND_SOC_NOPM, 1, 0, NULL, 0),
+
SND_SOC_DAPM_OUTPUT("HEADPHONE"),
SND_SOC_DAPM_PGA_E("HPHL", MSM8X10_WCD_A_RX_HPH_CNP_EN,
5, 0, NULL, 0,
@@ -2114,10 +2106,10 @@
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
/* Speaker */
- SND_SOC_DAPM_OUTPUT("LINEOUT1"),
+ SND_SOC_DAPM_OUTPUT("LINEOUT"),
SND_SOC_DAPM_OUTPUT("SPK_OUT"),
- SND_SOC_DAPM_PGA_E("LINEOUT1 PA", MSM8X10_WCD_A_RX_LINE_CNP_EN,
+ SND_SOC_DAPM_PGA_E("LINEOUT PA", MSM8X10_WCD_A_RX_LINE_CNP_EN,
0, 0, NULL, 0, msm8x10_wcd_codec_enable_lineout,
SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
@@ -2127,7 +2119,7 @@
SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_DAC_E("LINEOUT1 DAC", NULL,
+ SND_SOC_DAPM_DAC_E("LINEOUT DAC", NULL,
MSM8X10_WCD_A_RX_LINE_1_DAC_CTL, 7, 0,
msm8x10_wcd_lineout_dac_event,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
@@ -2152,10 +2144,18 @@
0, msm8x10_wcd_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_SUPPLY("RX1 CLK", MSM8X10_WCD_A_CDC_DIG_CLK_CTL,
+ 0, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("RX2 CLK", MSM8X10_WCD_A_CDC_DIG_CLK_CTL,
+ 1, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("RX3 CLK", MSM8X10_WCD_A_CDC_DIG_CLK_CTL,
+ 2, 0, NULL, 0),
SND_SOC_DAPM_MIXER("RX1 CHAIN", MSM8X10_WCD_A_CDC_RX1_B6_CTL,
5, 0, NULL, 0),
SND_SOC_DAPM_MIXER("RX2 CHAIN", MSM8X10_WCD_A_CDC_RX2_B6_CTL,
5, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("RX3 CHAIN", MSM8X10_WCD_A_CDC_RX3_B6_CTL,
+ 5, 0, NULL, 0),
SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
&rx_mix1_inp1_mux),
@@ -2191,26 +2191,28 @@
SND_SOC_DAPM_INPUT("AMIC1"),
- SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 External",
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS Internal1",
MSM8X10_WCD_A_MICB_1_CTL, 7, 0,
msm8x10_wcd_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal1",
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS Internal2",
MSM8X10_WCD_A_MICB_1_CTL, 7, 0,
msm8x10_wcd_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal2",
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS Internal3",
MSM8X10_WCD_A_MICB_1_CTL, 7, 0,
msm8x10_wcd_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_ADC_E("ADC1", NULL, MSM8X10_WCD_A_TX_1_EN, 7, 0,
msm8x10_wcd_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-
- SND_SOC_DAPM_ADC_E("ADC1", NULL, MSM8X10_WCD_A_TX_2_EN, 7, 0,
+ SND_SOC_DAPM_ADC_E("ADC2", NULL, MSM8X10_WCD_A_TX_2_EN, 7, 0,
msm8x10_wcd_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MICBIAS("MIC BIAS External", MSM8X10_WCD_A_MICB_1_CTL,
+ 7, 0),
+
SND_SOC_DAPM_INPUT("AMIC3"),
SND_SOC_DAPM_MUX_E("DEC1 MUX",
@@ -2226,11 +2228,13 @@
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_INPUT("AMIC2"),
- SND_SOC_DAPM_AIF_OUT("AIF1 CAP", "AIF1 Capture", 0, SND_SOC_NOPM,
- AIF1_CAP, 0),
- SND_SOC_DAPM_MIXER("AIF1_CAP Mixer", SND_SOC_NOPM, AIF1_CAP, 0,
- aif_cap_mixer, ARRAY_SIZE(aif_cap_mixer)),
+ SND_SOC_DAPM_AIF_OUT("I2S TX1", "AIF1 Capture", 0, SND_SOC_NOPM,
+ 0, 0),
+ SND_SOC_DAPM_AIF_OUT("I2S TX2", "AIF1 Capture", 0, SND_SOC_NOPM,
+ 0, 0),
+ SND_SOC_DAPM_AIF_OUT("I2S TX3", "AIF1 Capture", 0, SND_SOC_NOPM,
+ 0, 0),
/* Digital Mic Inputs */
SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
@@ -2254,7 +2258,7 @@
static const struct msm8x10_wcd_reg_mask_val msm8x10_wcd_reg_defaults[] = {
/* set MCLk to 9.6 */
- MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CHIP_CTL, 0x0A),
+ MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CHIP_CTL, 0x00),
/* EAR PA deafults */
MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_RX_EAR_CMBUFF, 0x05),
@@ -2280,7 +2284,12 @@
/* Disable TX7 internal biasing path which can cause leakage */
- MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_TX_SUP_SWITCH_CTRL_1, 0xBF),
+ MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_BIAS_CURR_CTL_2, 0x04),
+ MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_MICB_CFILT_1_VAL, 0x60),
+ MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_MICB_1_CTL, 0x82),
+ MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_TX_COM_BIAS, 0xE0),
+ MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_TX_1_EN, 0x32),
+ MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_TX_2_EN, 0x32),
};
static void msm8x10_wcd_update_reg_defaults(struct snd_soc_codec *codec)
@@ -2338,12 +2347,36 @@
static int msm8x10_wcd_codec_probe(struct snd_soc_codec *codec)
{
+ struct msm8x10_wcd_priv *msm8x10_wcd;
+ int i;
dev_dbg(codec->dev, "%s()\n", __func__);
+ msm8x10_wcd = kzalloc(sizeof(struct msm8x10_wcd_priv), GFP_KERNEL);
+ if (!msm8x10_wcd) {
+ dev_err(codec->dev, "Failed to allocate private data\n");
+ return -ENOMEM;
+ }
+
+ for (i = 0 ; i < NUM_DECIMATORS; i++) {
+ tx_hpf_work[i].msm8x10_wcd = msm8x10_wcd;
+ tx_hpf_work[i].decimator = i + 1;
+ INIT_DELAYED_WORK(&tx_hpf_work[i].dwork,
+ tx_hpf_corner_freq_callback);
+ }
+
codec->control_data = dev_get_drvdata(codec->dev);
+ snd_soc_codec_set_drvdata(codec, msm8x10_wcd);
+ msm8x10_wcd->codec = codec;
msm8x10_wcd_codec_init_reg(codec);
msm8x10_wcd_update_reg_defaults(codec);
+ msm8x10_wcd->mclk_enabled = false;
+ msm8x10_wcd->bandgap_type = MSM8X10_WCD_BANDGAP_OFF;
+ msm8x10_wcd->clock_active = false;
+ msm8x10_wcd->config_mode_active = false;
+ msm8x10_wcd->mbhc_polling_active = false;
+ mutex_init(&msm8x10_wcd->codec_resource_lock);
+ msm8x10_wcd->codec = codec;
return 0;
}
@@ -2353,18 +2386,6 @@
return 0;
}
-static int msm8x10_wcd_device_init(struct msm8x10_wcd *msm8x10)
-{
-
- mutex_init(&msm8x10->io_lock);
- mutex_init(&msm8x10->xfer_lock);
- mutex_init(&msm8x10->pm_lock);
- msm8x10->wlock_holders = 0;
-
- return 0;
-}
-
-
static struct snd_soc_codec_driver soc_codec_dev_msm8x10_wcd = {
.probe = msm8x10_wcd_codec_probe,
.remove = msm8x10_wcd_codec_remove,
@@ -2387,6 +2408,124 @@
.num_dapm_routes = ARRAY_SIZE(audio_map),
};
+static int msm8x10_wcd_enable_supplies(struct msm8x10_wcd *msm8x10,
+ struct msm8x10_wcd_pdata *pdata)
+{
+ int ret;
+ int i;
+ msm8x10->supplies = kzalloc(sizeof(struct regulator_bulk_data) *
+ ARRAY_SIZE(pdata->regulator),
+ GFP_KERNEL);
+ if (!msm8x10->supplies) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ msm8x10->num_of_supplies = 0;
+
+ if (ARRAY_SIZE(pdata->regulator) > MAX_REGULATOR) {
+ dev_err(msm8x10->dev, "%s: Array Size out of bound\n",
+ __func__);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(pdata->regulator); i++) {
+ if (pdata->regulator[i].name) {
+ msm8x10->supplies[i].supply = pdata->regulator[i].name;
+ msm8x10->num_of_supplies++;
+ }
+ }
+
+ ret = regulator_bulk_get(msm8x10->dev, msm8x10->num_of_supplies,
+ msm8x10->supplies);
+ if (ret != 0) {
+ dev_err(msm8x10->dev, "Failed to get supplies: err = %d\n",
+ ret);
+ goto err_supplies;
+ }
+
+ for (i = 0; i < msm8x10->num_of_supplies; i++) {
+ ret = regulator_set_voltage(msm8x10->supplies[i].consumer,
+ pdata->regulator[i].min_uV, pdata->regulator[i].max_uV);
+ if (ret) {
+ dev_err(msm8x10->dev, "%s: Setting regulator voltage failed for regulator %s err = %d\n",
+ __func__, msm8x10->supplies[i].supply, ret);
+ goto err_get;
+ }
+
+ ret = regulator_set_optimum_mode(msm8x10->supplies[i].consumer,
+ pdata->regulator[i].optimum_uA);
+ if (ret < 0) {
+ dev_err(msm8x10->dev, "%s: Setting regulator optimum mode failed for regulator %s err = %d\n",
+ __func__, msm8x10->supplies[i].supply, ret);
+ goto err_get;
+ }
+ }
+
+ ret = regulator_bulk_enable(msm8x10->num_of_supplies,
+ msm8x10->supplies);
+ if (ret != 0) {
+ dev_err(msm8x10->dev, "Failed to enable supplies: err = %d\n",
+ ret);
+ goto err_configure;
+ }
+ return ret;
+
+err_configure:
+ for (i = 0; i < msm8x10->num_of_supplies; i++) {
+ regulator_set_voltage(msm8x10->supplies[i].consumer, 0,
+ pdata->regulator[i].max_uV);
+ regulator_set_optimum_mode(msm8x10->supplies[i].consumer, 0);
+ }
+err_get:
+ regulator_bulk_free(msm8x10->num_of_supplies, msm8x10->supplies);
+err_supplies:
+ kfree(msm8x10->supplies);
+err:
+ return ret;
+}
+
+static void msm8x10_wcd_disable_supplies(struct msm8x10_wcd *msm8x10,
+ struct msm8x10_wcd_pdata *pdata)
+{
+ int i;
+
+ regulator_bulk_disable(msm8x10->num_of_supplies,
+ msm8x10->supplies);
+ for (i = 0; i < msm8x10->num_of_supplies; i++) {
+ regulator_set_voltage(msm8x10->supplies[i].consumer, 0,
+ pdata->regulator[i].max_uV);
+ regulator_set_optimum_mode(msm8x10->supplies[i].consumer, 0);
+ }
+ regulator_bulk_free(msm8x10->num_of_supplies, msm8x10->supplies);
+ kfree(msm8x10->supplies);
+}
+
+static int msm8x10_wcd_bringup(struct msm8x10_wcd *msm8x10)
+{
+ msm8x10->read_dev = msm8x10_wcd_reg_read;
+ msm8x10->write_dev(msm8x10, MSM8X10_WCD_A_CDC_RST_CTL, 0x02);
+ msm8x10->write_dev(msm8x10, MSM8X10_WCD_A_CHIP_CTL, 0x00);
+ usleep_range(5000, 5000);
+ msm8x10->write_dev(msm8x10, MSM8X10_WCD_A_CDC_RST_CTL, 0x03);
+ return 0;
+}
+
+static int msm8x10_wcd_device_init(struct msm8x10_wcd *msm8x10)
+{
+ mutex_init(&msm8x10->io_lock);
+ mutex_init(&msm8x10->xfer_lock);
+ mutex_init(&msm8x10->pm_lock);
+ msm8x10->wlock_holders = 0;
+
+ iowrite32(0x03C00000, ioremap(0xFD512050, 4));
+ usleep_range(5000, 5000);
+
+ msm8x10_wcd_bringup(msm8x10);
+ return 0;
+}
+
static int __devinit msm8x10_wcd_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -2401,7 +2540,7 @@
if (device_id > 0) {
msm8x10_wcd_modules[device_id++].client = client;
- return ret;
+ goto rtn;
}
dev = &client->dev;
@@ -2421,19 +2560,25 @@
dev_err(&client->dev,
"%s: error, allocation failed\n", __func__);
ret = -ENOMEM;
- goto fail;
+ goto rtn;
}
msm8x10->dev = &client->dev;
msm8x10_wcd_modules[device_id++].client = client;
msm8x10->read_dev = msm8x10_wcd_reg_read;
msm8x10->write_dev = msm8x10_wcd_reg_write;
+ ret = msm8x10_wcd_enable_supplies(msm8x10, pdata);
+ if (ret) {
+ dev_err(&client->dev, "%s: Fail to enable Codec supplies\n",
+ __func__);
+ goto err_codec;
+ }
ret = msm8x10_wcd_device_init(msm8x10);
if (ret) {
dev_err(&client->dev,
"%s:msm8x10_wcd_device_init failed with error %d\n",
__func__, ret);
- goto fail;
+ goto err_supplies;
}
dev_set_drvdata(&client->dev, msm8x10);
ret = snd_soc_register_codec(&client->dev, &soc_codec_dev_msm8x10_wcd,
@@ -2443,7 +2588,14 @@
dev_err(&client->dev,
"%s:snd_soc_register_codec failed with error %d\n",
__func__, ret);
-fail:
+ else
+ goto rtn;
+
+err_supplies:
+ msm8x10_wcd_disable_supplies(msm8x10, pdata);
+err_codec:
+ kfree(msm8x10);
+rtn:
return ret;
}
diff --git a/sound/soc/codecs/msm8x10-wcd.h b/sound/soc/codecs/msm8x10-wcd.h
index 44e8a6d..d250e0a 100644
--- a/sound/soc/codecs/msm8x10-wcd.h
+++ b/sound/soc/codecs/msm8x10-wcd.h
@@ -199,7 +199,7 @@
int (*read_dev)(struct msm8x10_wcd *msm8x10,
unsigned short reg, unsigned int *val);
int (*write_dev)(struct msm8x10_wcd *msm8x10,
- unsigned short reg, unsigned int val);
+ unsigned short reg, u8 val);
u32 num_of_supplies;
struct regulator_bulk_data *supplies;
diff --git a/sound/soc/codecs/wcd9306.c b/sound/soc/codecs/wcd9306.c
index 67674f3..b71dd65 100644
--- a/sound/soc/codecs/wcd9306.c
+++ b/sound/soc/codecs/wcd9306.c
@@ -461,8 +461,8 @@
kcontrol->private_value)->shift;
ucontrol->value.integer.value[0] =
- snd_soc_read(codec, (TAPAN_A_CDC_IIR1_CTL + 16 * iir_idx)) &
- (1 << band_idx);
+ (snd_soc_read(codec, (TAPAN_A_CDC_IIR1_CTL + 16 * iir_idx)) &
+ (1 << band_idx)) != 0;
dev_dbg(codec->dev, "%s: IIR #%d band #%d enable %d\n", __func__,
iir_idx, band_idx,
@@ -485,23 +485,54 @@
snd_soc_update_bits(codec, (TAPAN_A_CDC_IIR1_CTL + 16 * iir_idx),
(1 << band_idx), (value << band_idx));
- dev_dbg(codec->dev, "%s: IIR #%d band #%d enable %d\n", __func__,
- iir_idx, band_idx, value);
+ pr_debug("%s: IIR #%d band #%d enable %d\n", __func__,
+ iir_idx, band_idx,
+ ((snd_soc_read(codec, (TAPAN_A_CDC_IIR1_CTL + 16 * iir_idx)) &
+ (1 << band_idx)) != 0));
return 0;
}
static uint32_t get_iir_band_coeff(struct snd_soc_codec *codec,
int iir_idx, int band_idx,
int coeff_idx)
{
+ uint32_t value = 0;
+
/* Address does not automatically update if reading */
snd_soc_write(codec,
(TAPAN_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
- (band_idx * BAND_MAX + coeff_idx) & 0x1F);
+ ((band_idx * BAND_MAX + coeff_idx)
+ * sizeof(uint32_t)) & 0x7F);
+
+ value |= snd_soc_read(codec,
+ (TAPAN_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx));
+
+ snd_soc_write(codec,
+ (TAPAN_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
+ ((band_idx * BAND_MAX + coeff_idx)
+ * sizeof(uint32_t) + 1) & 0x7F);
+
+ value |= (snd_soc_read(codec,
+ (TAPAN_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx)) << 8);
+
+ snd_soc_write(codec,
+ (TAPAN_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
+ ((band_idx * BAND_MAX + coeff_idx)
+ * sizeof(uint32_t) + 2) & 0x7F);
+
+ value |= (snd_soc_read(codec,
+ (TAPAN_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx)) << 16);
+
+ snd_soc_write(codec,
+ (TAPAN_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
+ ((band_idx * BAND_MAX + coeff_idx)
+ * sizeof(uint32_t) + 3) & 0x7F);
/* Mask bits top 2 bits since they are reserved */
- return ((snd_soc_read(codec,
- (TAPAN_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx)) << 24)) &
- 0x3FFFFFFF;
+ value |= ((snd_soc_read(codec,
+ (TAPAN_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx)) & 0x3F) << 24);
+
+ return value;
+
}
static int tapan_get_iir_band_audio_mixer(
@@ -545,13 +576,19 @@
static void set_iir_band_coeff(struct snd_soc_codec *codec,
int iir_idx, int band_idx,
- int coeff_idx, uint32_t value)
+ uint32_t value)
{
- /* Mask top 3 bits, 6-8 are reserved */
- /* Update address manually each time */
snd_soc_write(codec,
- (TAPAN_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
- (band_idx * BAND_MAX + coeff_idx) & 0x1F);
+ (TAPAN_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx),
+ (value & 0xFF));
+
+ snd_soc_write(codec,
+ (TAPAN_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx),
+ (value >> 8) & 0xFF);
+
+ snd_soc_write(codec,
+ (TAPAN_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx),
+ (value >> 16) & 0xFF);
/* Mask top 2 bits, 7-8 are reserved */
snd_soc_write(codec,
@@ -570,15 +607,21 @@
int band_idx = ((struct soc_multi_mixer_control *)
kcontrol->private_value)->shift;
- set_iir_band_coeff(codec, iir_idx, band_idx, 0,
+ /* Mask top bit it is reserved */
+ /* Updates addr automatically for each B2 write */
+ snd_soc_write(codec,
+ (TAPAN_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
+ (band_idx * BAND_MAX * sizeof(uint32_t)) & 0x7F);
+
+ set_iir_band_coeff(codec, iir_idx, band_idx,
ucontrol->value.integer.value[0]);
- set_iir_band_coeff(codec, iir_idx, band_idx, 1,
+ set_iir_band_coeff(codec, iir_idx, band_idx,
ucontrol->value.integer.value[1]);
- set_iir_band_coeff(codec, iir_idx, band_idx, 2,
+ set_iir_band_coeff(codec, iir_idx, band_idx,
ucontrol->value.integer.value[2]);
- set_iir_band_coeff(codec, iir_idx, band_idx, 3,
+ set_iir_band_coeff(codec, iir_idx, band_idx,
ucontrol->value.integer.value[3]);
- set_iir_band_coeff(codec, iir_idx, band_idx, 4,
+ set_iir_band_coeff(codec, iir_idx, band_idx,
ucontrol->value.integer.value[4]);
dev_dbg(codec->dev, "%s: IIR #%d band #%d b0 = 0x%x\n"
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index 43a1042..845f1a2 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -110,6 +110,15 @@
AANC_FF_GAIN_ADAPTIVE,
AANC_FFGAIN_ADAPTIVE_EN,
AANC_GAIN_CONTROL,
+ SPKR_CLIP_PIPE_BANK_SEL,
+ SPKR_CLIPDET_VAL0,
+ SPKR_CLIPDET_VAL1,
+ SPKR_CLIPDET_VAL2,
+ SPKR_CLIPDET_VAL3,
+ SPKR_CLIPDET_VAL4,
+ SPKR_CLIPDET_VAL5,
+ SPKR_CLIPDET_VAL6,
+ SPKR_CLIPDET_VAL7,
MAX_CFG_REGISTERS,
};
@@ -182,6 +191,74 @@
(TAIKO_REGISTER_START_OFFSET + TAIKO_A_CDC_ANC1_GAIN_CTL),
AANC_GAIN_CONTROL, 0xFF, 8, 0
},
+ {
+ 1,
+ (TAIKO_REGISTER_START_OFFSET + TAIKO_A_INTR_DESTN3),
+ MAD_CLIP_INT_DEST_SELECT_REG, 0x8, 8, 0
+ },
+ {
+ 1,
+ (TAIKO_REGISTER_START_OFFSET + TAIKO_A_INTR_MASK3),
+ MAD_CLIP_INT_MASK_REG, 0x8, 8, 0
+ },
+ {
+ 1,
+ (TAIKO_REGISTER_START_OFFSET + TAIKO_A_INTR_STATUS3),
+ MAD_CLIP_INT_STATUS_REG, 0x8, 8, 0
+ },
+ {
+ 1,
+ (TAIKO_REGISTER_START_OFFSET + TAIKO_A_INTR_CLEAR3),
+ MAD_CLIP_INT_CLEAR_REG, 0x8, 8, 0
+ },
+};
+
+static struct afe_param_cdc_reg_cfg clip_reg_cfg[] = {
+ {
+ 1,
+ (TAIKO_REGISTER_START_OFFSET + TAIKO_A_CDC_SPKR_CLIPDET_B1_CTL),
+ SPKR_CLIP_PIPE_BANK_SEL, 0x3, 8, 0
+ },
+ {
+ 1,
+ (TAIKO_REGISTER_START_OFFSET + TAIKO_A_CDC_SPKR_CLIPDET_VAL0),
+ SPKR_CLIPDET_VAL0, 0xff, 8, 0
+ },
+ {
+ 1,
+ (TAIKO_REGISTER_START_OFFSET + TAIKO_A_CDC_SPKR_CLIPDET_VAL1),
+ SPKR_CLIPDET_VAL1, 0xff, 8, 0
+ },
+ {
+ 1,
+ (TAIKO_REGISTER_START_OFFSET + TAIKO_A_CDC_SPKR_CLIPDET_VAL2),
+ SPKR_CLIPDET_VAL2, 0xff, 8, 0
+ },
+ {
+ 1,
+ (TAIKO_REGISTER_START_OFFSET + TAIKO_A_CDC_SPKR_CLIPDET_VAL3),
+ SPKR_CLIPDET_VAL3, 0xff, 8, 0
+ },
+ {
+ 1,
+ (TAIKO_REGISTER_START_OFFSET + TAIKO_A_CDC_SPKR_CLIPDET_VAL4),
+ SPKR_CLIPDET_VAL4, 0xff, 8, 0
+ },
+ {
+ 1,
+ (TAIKO_REGISTER_START_OFFSET + TAIKO_A_CDC_SPKR_CLIPDET_VAL5),
+ SPKR_CLIPDET_VAL5, 0xff, 8, 0
+ },
+ {
+ 1,
+ (TAIKO_REGISTER_START_OFFSET + TAIKO_A_CDC_SPKR_CLIPDET_VAL6),
+ SPKR_CLIPDET_VAL6, 0xff, 8, 0
+ },
+ {
+ 1,
+ (TAIKO_REGISTER_START_OFFSET + TAIKO_A_CDC_SPKR_CLIPDET_VAL7),
+ SPKR_CLIPDET_VAL7, 0xff, 8, 0
+ },
};
static struct afe_param_cdc_reg_cfg_data taiko_audio_reg_cfg = {
@@ -189,11 +266,22 @@
.reg_data = audio_reg_cfg,
};
+static struct afe_param_cdc_reg_cfg_data taiko_clip_reg_cfg = {
+ .num_registers = ARRAY_SIZE(clip_reg_cfg),
+ .reg_data = clip_reg_cfg,
+};
+
static struct afe_param_id_cdc_aanc_version taiko_cdc_aanc_version = {
.cdc_aanc_minor_version = AFE_API_VERSION_CDC_AANC_VERSION,
.aanc_hw_version = AANC_HW_BLOCK_VERSION_2,
};
+static struct afe_param_id_clip_bank_sel clip_bank_sel = {
+ .minor_version = AFE_API_VERSION_CLIP_BANK_SEL_CFG,
+ .num_banks = AFE_CLIP_MAX_BANKS,
+ .bank_map = {0, 1, 2, 3},
+};
+
module_param_cb(spkr_drv_wrnd, &spkr_drv_wrnd_param_ops, &spkr_drv_wrnd, 0644);
MODULE_PARM_DESC(spkr_drv_wrnd,
"Run software workaround to avoid leakage on the speaker drive");
@@ -4620,9 +4708,6 @@
dai = &taiko_p->dai[w->shift];
switch (event) {
case SND_SOC_DAPM_POST_PMU:
- /*Enable Clip Detection*/
- snd_soc_update_bits(codec, TAIKO_A_SPKR_DRV_CLIP_DET,
- 0x8, 0x8);
/*Enable V&I sensing*/
snd_soc_update_bits(codec, TAIKO_A_SPKR_PROT_EN,
0x88, 0x88);
@@ -4635,6 +4720,7 @@
/*Enable Current Decimator*/
snd_soc_update_bits(codec,
TAIKO_A_CDC_CONN_TX_SB_B10_CTL, 0x1F, 0x13);
+ (void) taiko_codec_enable_slim_chmask(dai, true);
ret = wcd9xxx_cfg_slim_sch_tx(core, &dai->wcd9xxx_ch_list,
dai->rate, dai->bit_width,
&dai->grph);
@@ -4657,9 +4743,6 @@
/*Disable V&I sensing*/
snd_soc_update_bits(codec, TAIKO_A_SPKR_PROT_EN,
0x88, 0x00);
- /*Disable clip detection*/
- snd_soc_update_bits(codec, TAIKO_A_SPKR_DRV_CLIP_DET,
- 0x8, 0x0);
break;
}
out_vi:
@@ -5949,6 +6032,7 @@
enum afe_config_type config_type)
{
struct taiko_priv *priv = snd_soc_codec_get_drvdata(codec);
+ struct wcd9xxx *taiko_core = dev_get_drvdata(codec->dev->parent);
switch (config_type) {
case AFE_SLIMBUS_SLAVE_CONFIG:
@@ -5959,6 +6043,16 @@
return &taiko_slimbus_slave_port_cfg;
case AFE_AANC_VERSION:
return &taiko_cdc_aanc_version;
+ case AFE_CLIP_BANK_SEL:
+ if (!TAIKO_IS_1_0(taiko_core->version))
+ return &clip_bank_sel;
+ else
+ return NULL;
+ case AFE_CDC_CLIP_REGISTERS_CONFIG:
+ if (!TAIKO_IS_1_0(taiko_core->version))
+ return &taiko_clip_reg_cfg;
+ else
+ return NULL;
default:
pr_err("%s: Unknown config_type 0x%x\n", __func__, config_type);
return NULL;
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.c b/sound/soc/codecs/wcd9xxx-mbhc.c
index daba6d5..a37b4eb 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.c
+++ b/sound/soc/codecs/wcd9xxx-mbhc.c
@@ -2786,6 +2786,7 @@
wcd9xxx_turn_onoff_rel_detection(codec, true);
pr_debug("%s: leave\n", __func__);
+ return;
gen_err:
pr_err("%s: Error returned, ret: %d\n", __func__, ret);
diff --git a/sound/soc/msm/Makefile b/sound/soc/msm/Makefile
index ebde90b..7ab4811 100644
--- a/sound/soc/msm/Makefile
+++ b/sound/soc/msm/Makefile
@@ -55,8 +55,7 @@
# for MSM 8960 sound card driver
obj-$(CONFIG_SND_SOC_MSM_QDSP6_INTF) += qdsp6/
-
-snd-soc-qdsp6-objs := msm-dai-q6.o msm-pcm-q6.o msm-multi-ch-pcm-q6.o msm-lowlatency-pcm-q6.o msm-pcm-routing.o msm-dai-fe.o msm-compr-q6.o msm-dai-stub.o
+snd-soc-qdsp6-objs := msm-dai-q6.o msm-pcm-q6.o msm-multi-ch-pcm-q6.o msm-lowlatency-pcm-q6.o msm-pcm-loopback.o msm-pcm-routing.o msm-dai-fe.o msm-compr-q6.o msm-dai-stub.o
obj-$(CONFIG_SND_SOC_MSM_QDSP6_HDMI_AUDIO) += msm-dai-q6-hdmi.o
obj-$(CONFIG_SND_SOC_VOICE) += msm-pcm-voice.o msm-pcm-voip.o msm-pcm-dtmf.o msm-pcm-host-voice.o
snd-soc-qdsp6-objs += msm-pcm-lpa.o msm-pcm-afe.o
diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c
index 8db13f6..1b51595 100644
--- a/sound/soc/msm/msm-dai-fe.c
+++ b/sound/soc/msm/msm-dai-fe.c
@@ -236,6 +236,17 @@
.rate_min = 8000,
.rate_max = 192000,
},
+ .capture = {
+ .stream_name = "MultiMedia6 Capture",
+ .aif_name = "MM_UL6",
+ .rates = (SNDRV_PCM_RATE_8000_48000|
+ SNDRV_PCM_RATE_KNOT),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
.ops = &msm_fe_Multimedia_dai_ops,
.name = "MultiMedia6",
},
@@ -549,6 +560,34 @@
.name = "SEC_I2S_RX_HOSTLESS",
},
{
+ .capture = {
+ .stream_name = "Primary MI2S_TX Hostless Capture",
+ .aif_name = "PRI_MI2S_UL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "PRI_MI2S_TX_HOSTLESS",
+ },
+ {
+ .playback = {
+ .stream_name = "Secondary MI2S_RX Hostless Playback",
+ .aif_name = "SEC_MI2S_DL_HL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "SEC_MI2S_RX_HOSTLESS",
+ },
+ {
.playback = {
.stream_name = "Voice2 Playback",
.aif_name = "VOICE2_DL",
diff --git a/sound/soc/msm/msm-pcm-loopback.c b/sound/soc/msm/msm-pcm-loopback.c
new file mode 100644
index 0000000..84ea9c6
--- /dev/null
+++ b/sound/soc/msm/msm-pcm-loopback.c
@@ -0,0 +1,362 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License version 2 and
+* only version 2 as published by the Free Software Foundation.
+
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*/
+
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <sound/apr_audio.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/q6asm.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <asm/dma.h>
+#include <linux/dma-mapping.h>
+
+#include "msm-pcm-routing.h"
+
+struct msm_pcm_loopback {
+ struct snd_pcm_substream *playback_substream;
+ struct snd_pcm_substream *capture_substream;
+
+ int instance;
+
+ struct mutex lock;
+
+ uint32_t samp_rate;
+ uint32_t channel_mode;
+
+ int playback_start;
+ int capture_start;
+ int session_id;
+ struct audio_client *audio_client;
+};
+
+static void stop_pcm(struct msm_pcm_loopback *pcm);
+
+static const struct snd_pcm_hardware dummy_pcm_hardware = {
+ .formats = 0xffffffff,
+ .channels_min = 1,
+ .channels_max = UINT_MAX,
+
+ /* Random values to keep userspace happy when checking constraints */
+ .info = SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER,
+ .buffer_bytes_max = 128*1024,
+ .period_bytes_min = 1024,
+ .period_bytes_max = 1024*2,
+ .periods_min = 2,
+ .periods_max = 128,
+};
+
+static void msm_pcm_route_event_handler(enum msm_pcm_routing_event event,
+ void *priv_data)
+{
+ struct msm_pcm_loopback *pcm = priv_data;
+
+ BUG_ON(!pcm);
+
+ pr_debug("%s: event %x\n", __func__, event);
+
+ switch (event) {
+ case MSM_PCM_RT_EVT_DEVSWITCH:
+ q6asm_cmd(pcm->audio_client, CMD_PAUSE);
+ q6asm_cmd(pcm->audio_client, CMD_FLUSH);
+ q6asm_run(pcm->audio_client, 0, 0, 0);
+ default:
+ break;
+ }
+}
+
+static void msm_pcm_loopback_event_handler(uint32_t opcode,
+ uint32_t token, uint32_t *payload, void *priv)
+{
+ pr_debug("%s\n", __func__);
+ switch (opcode) {
+ case APR_BASIC_RSP_RESULT: {
+ switch (payload[0]) {
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ default:
+ pr_err("Not Supported Event opcode[0x%x]\n", opcode);
+ break;
+ }
+}
+
+static int msm_pcm_open(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+ struct msm_pcm_loopback *pcm;
+ int ret = 0;
+ struct msm_pcm_routing_evt event;
+
+ pcm = dev_get_drvdata(rtd->platform->dev);
+ mutex_lock(&pcm->lock);
+
+ snd_soc_set_runtime_hwparams(substream, &dummy_pcm_hardware);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ pcm->playback_substream = substream;
+ else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ pcm->capture_substream = substream;
+
+ pcm->instance++;
+ dev_dbg(rtd->platform->dev, "%s: pcm out open: %d,%d\n", __func__,
+ pcm->instance, substream->stream);
+ if (pcm->instance == 2) {
+ struct snd_soc_pcm_runtime *soc_pcm_rx =
+ pcm->playback_substream->private_data;
+ struct snd_soc_pcm_runtime *soc_pcm_tx =
+ pcm->capture_substream->private_data;
+ if (pcm->audio_client != NULL)
+ stop_pcm(pcm);
+
+ pcm->audio_client = q6asm_audio_client_alloc(
+ (app_cb)msm_pcm_loopback_event_handler, pcm);
+ if (!pcm->audio_client) {
+ dev_err(rtd->platform->dev,
+ "%s: Could not allocate memory\n", __func__);
+ mutex_unlock(&pcm->lock);
+ return -ENOMEM;
+ }
+ pcm->session_id = pcm->audio_client->session;
+ pcm->audio_client->perf_mode = false;
+ ret = q6asm_open_loopack(pcm->audio_client);
+ if (ret < 0) {
+ dev_err(rtd->platform->dev,
+ "%s: pcm out open failed\n", __func__);
+ q6asm_audio_client_free(pcm->audio_client);
+ mutex_unlock(&pcm->lock);
+ return -ENOMEM;
+ }
+ event.event_func = msm_pcm_route_event_handler;
+ event.priv_data = (void *) pcm;
+ msm_pcm_routing_reg_phy_stream(soc_pcm_tx->dai_link->be_id,
+ pcm->audio_client->perf_mode,
+ pcm->session_id, pcm->capture_substream->stream);
+ msm_pcm_routing_reg_phy_stream_v2(soc_pcm_rx->dai_link->be_id,
+ pcm->audio_client->perf_mode,
+ pcm->session_id, pcm->playback_substream->stream,
+ event);
+ }
+ dev_info(rtd->platform->dev, "%s: Instance = %d, Stream ID = %s\n",
+ __func__ , pcm->instance, substream->pcm->id);
+ runtime->private_data = pcm;
+
+ mutex_unlock(&pcm->lock);
+
+ return 0;
+}
+
+static void stop_pcm(struct msm_pcm_loopback *pcm)
+{
+ struct snd_soc_pcm_runtime *soc_pcm_rx =
+ pcm->playback_substream->private_data;
+ struct snd_soc_pcm_runtime *soc_pcm_tx =
+ pcm->capture_substream->private_data;
+
+ if (pcm->audio_client == NULL)
+ return;
+ q6asm_cmd(pcm->audio_client, CMD_CLOSE);
+
+ msm_pcm_routing_dereg_phy_stream(soc_pcm_rx->dai_link->be_id,
+ SNDRV_PCM_STREAM_PLAYBACK);
+ msm_pcm_routing_dereg_phy_stream(soc_pcm_tx->dai_link->be_id,
+ SNDRV_PCM_STREAM_CAPTURE);
+ q6asm_audio_client_free(pcm->audio_client);
+ pcm->audio_client = NULL;
+}
+
+static int msm_pcm_close(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct msm_pcm_loopback *pcm = runtime->private_data;
+ struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+ int ret = 0;
+
+ mutex_lock(&pcm->lock);
+
+ dev_dbg(rtd->platform->dev, "%s: end pcm call:%d\n",
+ __func__, substream->stream);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ pcm->playback_start = 0;
+ else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ pcm->capture_start = 0;
+
+ pcm->instance--;
+ if (!pcm->playback_start || !pcm->capture_start) {
+ dev_dbg(rtd->platform->dev, "%s: end pcm call\n", __func__);
+ stop_pcm(pcm);
+ }
+
+ mutex_unlock(&pcm->lock);
+ return ret;
+}
+
+static int msm_pcm_prepare(struct snd_pcm_substream *substream)
+{
+ int ret = 0;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct msm_pcm_loopback *pcm = runtime->private_data;
+ struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+
+ mutex_lock(&pcm->lock);
+
+ dev_dbg(rtd->platform->dev, "%s: ASM loopback stream:%d\n",
+ __func__, substream->stream);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ if (!pcm->playback_start)
+ pcm->playback_start = 1;
+ } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ if (!pcm->capture_start)
+ pcm->capture_start = 1;
+ }
+ mutex_unlock(&pcm->lock);
+
+ return ret;
+}
+
+static int msm_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct msm_pcm_loopback *pcm = runtime->private_data;
+ struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ dev_dbg(rtd->platform->dev,
+ "%s: playback_start:%d,capture_start:%d\n", __func__,
+ pcm->playback_start, pcm->capture_start);
+ if (pcm->playback_start && pcm->capture_start)
+ q6asm_run_nowait(pcm->audio_client, 0, 0, 0);
+ break;
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ case SNDRV_PCM_TRIGGER_STOP:
+ dev_dbg(rtd->platform->dev,
+ "%s:Pause/Stop - playback_start:%d,capture_start:%d\n",
+ __func__, pcm->playback_start, pcm->capture_start);
+ if (pcm->playback_start && pcm->capture_start)
+ q6asm_cmd_nowait(pcm->audio_client, CMD_PAUSE);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int msm_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
+
+ dev_dbg(rtd->platform->dev, "%s: ASM loopback\n", __func__);
+
+ return snd_pcm_lib_alloc_vmalloc_buffer(substream,
+ params_buffer_bytes(params));
+}
+
+static int msm_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+ return snd_pcm_lib_free_vmalloc_buffer(substream);
+}
+
+static struct snd_pcm_ops msm_pcm_ops = {
+ .open = msm_pcm_open,
+ .hw_params = msm_pcm_hw_params,
+ .hw_free = msm_pcm_hw_free,
+ .close = msm_pcm_close,
+ .prepare = msm_pcm_prepare,
+ .trigger = msm_pcm_trigger,
+};
+
+
+static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_card *card = rtd->card->snd_card;
+ int ret = 0;
+
+ if (!card->dev->coherent_dma_mask)
+ card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+ return ret;
+}
+
+static struct snd_soc_platform_driver msm_soc_platform = {
+ .ops = &msm_pcm_ops,
+ .pcm_new = msm_asoc_pcm_new,
+};
+
+static __devinit int msm_pcm_probe(struct platform_device *pdev)
+{
+ struct msm_pcm_loopback *pcm;
+
+ dev_dbg(&pdev->dev, "%s: dev name %s\n",
+ __func__, dev_name(&pdev->dev));
+
+ pcm = kzalloc(sizeof(struct msm_pcm_loopback), GFP_KERNEL);
+ if (!pcm) {
+ dev_err(&pdev->dev, "%s Failed to allocate memory for pcm\n",
+ __func__);
+ return -ENOMEM;
+ } else {
+ mutex_init(&pcm->lock);
+ dev_set_drvdata(&pdev->dev, pcm);
+ }
+ return snd_soc_register_platform(&pdev->dev,
+ &msm_soc_platform);
+}
+
+static int msm_pcm_remove(struct platform_device *pdev)
+{
+ struct msm_pcm_loopback *pcm;
+
+ pcm = dev_get_drvdata(&pdev->dev);
+ mutex_destroy(&pcm->lock);
+
+ snd_soc_unregister_platform(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver msm_pcm_driver = {
+ .driver = {
+ .name = "msm-pcm-loopback",
+ .owner = THIS_MODULE,
+ },
+ .probe = msm_pcm_probe,
+ .remove = __devexit_p(msm_pcm_remove),
+};
+
+static int __init msm_soc_platform_init(void)
+{
+ return platform_driver_register(&msm_pcm_driver);
+}
+module_init(msm_soc_platform_init);
+
+static void __exit msm_soc_platform_exit(void)
+{
+ platform_driver_unregister(&msm_pcm_driver);
+}
+module_exit(msm_soc_platform_exit);
+
+MODULE_DESCRIPTION("PCM loopback platform driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/msm-pcm-routing.c b/sound/soc/msm/msm-pcm-routing.c
index e74a0dd..2c3c6df 100644
--- a/sound/soc/msm/msm-pcm-routing.c
+++ b/sound/soc/msm/msm-pcm-routing.c
@@ -658,6 +658,11 @@
msm_bedais[reg].sample_rate, channels,
DEFAULT_COPP_TOPOLOGY);
+ if (session_type == SESSION_TYPE_RX &&
+ fdai->event_info.event_func)
+ fdai->event_info.event_func(
+ MSM_PCM_RT_EVT_DEVSWITCH,
+ fdai->event_info.priv_data);
msm_pcm_routing_build_matrix(val,
fdai->strm_id, path_type);
@@ -976,10 +981,8 @@
static int msm_routing_set_fm_vol_mixer(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- afe_loopback_gain(INT_FM_TX , ucontrol->value.integer.value[0]);
-
+ afe_loopback_gain(INT_FM_TX, ucontrol->value.integer.value[0]);
msm_route_fm_vol_control = ucontrol->value.integer.value[0];
-
return 0;
}
@@ -1660,6 +1663,9 @@
SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_INT_BT_SCO_RX,
MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new int_fm_rx_mixer_controls[] = {
@@ -1696,6 +1702,9 @@
SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_AFE_PCM_RX,
MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_AFE_PCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new auxpcm_rx_mixer_controls[] = {
@@ -1714,6 +1723,9 @@
SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_AUXPCM_RX,
MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new sec_auxpcm_rx_mixer_controls[] = {
@@ -1810,6 +1822,12 @@
msm_routing_put_audio_mixer),
};
+static const struct snd_kcontrol_new mmul6_mixer_controls[] = {
+ SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
static const struct snd_kcontrol_new pri_rx_voice_mixer_controls[] = {
SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_PRI_I2S_RX,
MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
@@ -2715,6 +2733,7 @@
SND_SOC_DAPM_AIF_OUT("MM_UL2", "MultiMedia2 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MM_UL4", "MultiMedia4 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MM_UL5", "MultiMedia5 Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("MM_UL6", "MultiMedia6 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("CS-VOICE_DL1", "CS-VOICE Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("CS-VOICE_UL1", "CS-VOICE Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("VoLTE_DL", "VoLTE Playback", 0, 0, 0, 0),
@@ -2828,6 +2847,8 @@
mmul4_mixer_controls, ARRAY_SIZE(mmul4_mixer_controls)),
SND_SOC_DAPM_MIXER("MultiMedia5 Mixer", SND_SOC_NOPM, 0, 0,
mmul5_mixer_controls, ARRAY_SIZE(mmul5_mixer_controls)),
+ SND_SOC_DAPM_MIXER("MultiMedia6 Mixer", SND_SOC_NOPM, 0, 0,
+ mmul6_mixer_controls, ARRAY_SIZE(mmul6_mixer_controls)),
SND_SOC_DAPM_MIXER("AUX_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
auxpcm_rx_mixer_controls, ARRAY_SIZE(auxpcm_rx_mixer_controls)),
SND_SOC_DAPM_MIXER("SEC_AUX_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
@@ -3008,6 +3029,7 @@
{"MI2S_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
{"MI2S_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
{"MI2S_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"MI2S_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
{"MI2S_RX", NULL, "MI2S_RX Audio Mixer"},
{"MultiMedia1 Mixer", "PRI_TX", "PRI_I2S_TX"},
@@ -3026,6 +3048,7 @@
{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
{"INT_BT_SCO_RX", NULL, "INTERNAL_BT_SCO_RX Audio Mixer"},
{"INTERNAL_FM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -3040,12 +3063,14 @@
{"AFE_PCM_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
{"AFE_PCM_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
{"AFE_PCM_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"AFE_PCM_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
{"PCM_RX", NULL, "AFE_PCM_RX Audio Mixer"},
{"MultiMedia1 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
{"MultiMedia5 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
{"MultiMedia1 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
{"MultiMedia5 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+ {"MultiMedia6 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
{"MultiMedia1 Mixer", "AFE_PCM_TX", "PCM_TX"},
{"MultiMedia5 Mixer", "AFE_PCM_TX", "PCM_TX"},
@@ -3054,12 +3079,14 @@
{"MM_UL2", NULL, "MultiMedia2 Mixer"},
{"MM_UL4", NULL, "MultiMedia4 Mixer"},
{"MM_UL5", NULL, "MultiMedia5 Mixer"},
+ {"MM_UL6", NULL, "MultiMedia6 Mixer"},
{"AUX_PCM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
{"AUX_PCM_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
{"AUX_PCM_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
{"AUX_PCM_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
{"AUX_PCM_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"AUX_PCM_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
{"AUX_PCM_RX", NULL, "AUX_PCM_RX Audio Mixer"},
{"SEC_AUX_PCM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
diff --git a/sound/soc/msm/msm-pcm-routing.h b/sound/soc/msm/msm-pcm-routing.h
index c42e155..e25a44a 100644
--- a/sound/soc/msm/msm-pcm-routing.h
+++ b/sound/soc/msm/msm-pcm-routing.h
@@ -117,6 +117,7 @@
enum msm_pcm_routing_event {
MSM_PCM_RT_EVT_BUF_RECFG,
+ MSM_PCM_RT_EVT_DEVSWITCH,
MSM_PCM_RT_EVT_MAX,
};
/* dai_id: front-end ID,
diff --git a/sound/soc/msm/msm8930.c b/sound/soc/msm/msm8930.c
index 737317c..dd92e34 100644
--- a/sound/soc/msm/msm8930.c
+++ b/sound/soc/msm/msm8930.c
@@ -1143,6 +1143,22 @@
.ignore_pmdown_time = 1,
.be_id = MSM_FRONTEND_DAI_MULTIMEDIA5,
},
+ {
+ .name = "MSM8960 FM",
+ .stream_name = "MultiMedia6",
+ .cpu_dai_name = "MultiMedia6",
+ .platform_name = "msm-pcm-loopback",
+ .dynamic = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .ignore_suspend = 1,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA6,
+ },
/* Backend DAI Links */
{
.name = LPASS_BE_SLIMBUS_0_RX,
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index a458713..51334f2 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -1424,7 +1424,26 @@
__func__, err);
goto out;
}
-
+ config_data = taiko_get_afe_config(codec,
+ AFE_CDC_CLIP_REGISTERS_CONFIG);
+ if (config_data) {
+ err = afe_set_config(AFE_CDC_CLIP_REGISTERS_CONFIG,
+ config_data, 0);
+ if (err) {
+ pr_err("%s: Failed to set clip registers %d\n",
+ __func__, err);
+ return err;
+ }
+ }
+ config_data = taiko_get_afe_config(codec, AFE_CLIP_BANK_SEL);
+ if (config_data) {
+ err = afe_set_config(AFE_CLIP_BANK_SEL, config_data, 0);
+ if (err) {
+ pr_err("%s: Failed to set AFE bank selection %d\n",
+ __func__, err);
+ return err;
+ }
+ }
/* start mbhc */
mbhc_cfg.calibration = def_taiko_mbhc_cal();
if (mbhc_cfg.calibration) {
diff --git a/sound/soc/msm/msm8x10.c b/sound/soc/msm/msm8x10.c
index 4dd85fc..1f7712f 100644
--- a/sound/soc/msm/msm8x10.c
+++ b/sound/soc/msm/msm8x10.c
@@ -18,6 +18,7 @@
#include <linux/slab.h>
#include <linux/mfd/pm8xxx/pm8921.h>
#include <linux/qpnp/clkdiv.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
@@ -26,8 +27,196 @@
#include <asm/mach-types.h>
#include <mach/socinfo.h>
#include <qdsp6v2/msm-pcm-routing-v2.h>
+#include <sound/q6afe-v2.h>
#include <linux/module.h>
+#include "../codecs/msm8x10-wcd.h"
#define DRV_NAME "msm8x10-asoc-wcd"
+#define BTSCO_RATE_8KHZ 8000
+#define BTSCO_RATE_16KHZ 16000
+
+static int msm_btsco_rate = BTSCO_RATE_8KHZ;
+static int msm_btsco_ch = 1;
+
+static int msm_proxy_rx_ch = 2;
+
+#define MSM8X10_DINO_LPASS_AUDIO_CORE_DIG_CODEC_CLK_SEL 0xFE03B004
+#define MSM8X10_DINO_LPASS_DIGCODEC_CMD_RCGR 0xFE02C000
+#define MSM8X10_DINO_LPASS_DIGCODEC_CFG_RCGR 0xFE02C004
+#define MSM8X10_DINO_LPASS_DIGCODEC_M 0xFE02C008
+#define MSM8X10_DINO_LPASS_DIGCODEC_N 0xFE02C00C
+#define MSM8X10_DINO_LPASS_DIGCODEC_D 0xFE02C010
+#define MSM8X10_DINO_LPASS_DIGCODEC_CBCR 0xFE02C014
+#define MSM8X10_DINO_LPASS_DIGCODEC_AHB_CBCR 0xFE02C018
+
+/*
+ * There is limitation for the clock root selection from
+ * either MI2S or DIG_CODEC.
+ * If DIG_CODEC root can only provide 9.6MHz clock
+ * to codec while MI2S only can provide
+ * 12.288MHz.
+ */
+enum {
+ DIG_CDC_CLK_SEL_DIG_CODEC,
+ DIG_CDC_CLK_SEL_PRI_MI2S,
+ DIG_CDC_CLK_SEL_SEC_MI2S,
+};
+
+static struct afe_clk_cfg mi2s_rx_clk = {
+ AFE_API_VERSION_I2S_CONFIG,
+ Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ,
+ Q6AFE_LPASS_OSR_CLK_12_P288_MHZ,
+ Q6AFE_LPASS_CLK_SRC_INTERNAL,
+ Q6AFE_LPASS_CLK_ROOT_DEFAULT,
+ Q6AFE_LPASS_MODE_BOTH_VALID,
+ 0,
+};
+
+static struct afe_clk_cfg mi2s_tx_clk = {
+ AFE_API_VERSION_I2S_CONFIG,
+ Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ,
+ Q6AFE_LPASS_OSR_CLK_12_P288_MHZ,
+ Q6AFE_LPASS_CLK_SRC_INTERNAL,
+ Q6AFE_LPASS_CLK_ROOT_DEFAULT,
+ Q6AFE_LPASS_MODE_BOTH_VALID,
+ 0,
+};
+
+static struct afe_digital_clk_cfg digital_cdc_clk = {
+ AFE_API_VERSION_I2S_CONFIG,
+ 9600000,
+ 5, /* Digital Codec root */
+ 0,
+};
+
+static atomic_t aud_init_rsc_ref;
+
+static int msm8x10_mclk_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event);
+
+static const struct snd_soc_dapm_route msm8x10_common_audio_map[] = {
+ {"RX_BIAS", NULL, "MCLK"},
+ {"INT_LDO_H", NULL, "MCLK"},
+ {"MIC BIAS External", NULL, "Handset Mic"},
+ {"MIC BIAS Internal2", NULL, "Headset Mic"},
+ {"AMIC1", NULL, "MIC BIAS External"},
+ {"AMIC2", NULL, "MIC BIAS Internal2"},
+
+};
+
+static const struct snd_soc_dapm_widget msm8x10_dapm_widgets[] = {
+
+ SND_SOC_DAPM_SUPPLY("MCLK", SND_SOC_NOPM, 0, 0,
+ msm8x10_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIC("Handset Mic", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+
+};
+
+/*
+ * This function will be replaced by
+ * afe_set_lpass_internal_digital_codec_clock(port_id, cfg)
+ * in the future after LPASS API fix
+ */
+static int msm_enable_lpass_mclk(void)
+{
+ /* Select the codec root */
+ iowrite32(DIG_CDC_CLK_SEL_DIG_CODEC,
+ ioremap(MSM8X10_DINO_LPASS_AUDIO_CORE_DIG_CODEC_CLK_SEL,
+ 4));
+ /* Div-2 */
+ iowrite32(0x3, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_CFG_RCGR, 4));
+ iowrite32(0x0, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_M, 4));
+ iowrite32(0x0, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_N, 4));
+ iowrite32(0x0, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_D, 4));
+ /* Digital codec clock enable */
+ iowrite32(0x1, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_CBCR, 4));
+ /* AHB clock enable */
+ iowrite32(0x1, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_AHB_CBCR, 4));
+ /* Set the update bit to make the settings go through */
+ iowrite32(0x1, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_CMD_RCGR, 4));
+
+ return 0;
+}
+
+static int msm_enable_mclk_root(u16 port_id, struct afe_digital_clk_cfg *cfg)
+{
+ int ret = 0;
+ /*
+ * msm_enable_lpass_mclk() function call will be replaced by
+ * ret = afe_set_lpass_internal_digital_codec_clock(port_id, cfg)
+ * in the future. Currentlt there is a bug in LPASS plan which
+ * doesn't consider the digital codec clock. It will be fixed soon
+ * in new Q6 image
+ */
+ msm_enable_lpass_mclk();
+ pr_debug("%s(): return = %d\n", __func__, ret);
+ return ret;
+}
+
+static int msm_config_mclk(u16 port_id, struct afe_digital_clk_cfg *cfg)
+{
+ /* Select the codec root */
+ iowrite32(DIG_CDC_CLK_SEL_DIG_CODEC,
+ ioremap(MSM8X10_DINO_LPASS_AUDIO_CORE_DIG_CODEC_CLK_SEL,
+ 4));
+ /* Div-2 */
+ iowrite32(0x3, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_CFG_RCGR, 4));
+ iowrite32(0x0, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_M, 4));
+ iowrite32(0x0, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_N, 4));
+ iowrite32(0x0, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_D, 4));
+ /* Digital codec clock enable */
+ if (cfg->clk_val == 0) {
+ iowrite32(0x0, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_CBCR, 4));
+ pr_debug("%s(line %d)\n", __func__, __LINE__);
+ } else {
+ iowrite32(0x1, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_CBCR, 4));
+ pr_debug("%s(line %d)\n", __func__, __LINE__);
+ }
+ iowrite32(0x1, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_CBCR, 4));
+ /* AHB clock enable */
+ iowrite32(0x1, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_AHB_CBCR, 4));
+ /* Set the update bit to make the settings go through */
+ iowrite32(0x1, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_CMD_RCGR, 4));
+
+ return 0;
+
+}
+
+static int msm_config_mi2s_clk(int enable)
+{
+ int ret = 0;
+ pr_debug("%s(line %d):enable = %x\n", __func__, __LINE__, enable);
+ if (enable) {
+ digital_cdc_clk.clk_val = 9600000;
+ mi2s_rx_clk.clk_val2 = Q6AFE_LPASS_OSR_CLK_12_P288_MHZ;
+ mi2s_rx_clk.clk_val1 = Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ;
+ ret = afe_set_lpass_clock(AFE_PORT_ID_SECONDARY_MI2S_RX,
+ &mi2s_rx_clk);
+ mi2s_tx_clk.clk_val2 = Q6AFE_LPASS_OSR_CLK_12_P288_MHZ;
+ mi2s_tx_clk.clk_val1 = Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ;
+ ret = afe_set_lpass_clock(AFE_PORT_ID_PRIMARY_MI2S_RX,
+ &mi2s_tx_clk);
+ if (ret < 0)
+ pr_err("%s:afe_set_lpass_clock failed\n", __func__);
+
+ } else {
+ digital_cdc_clk.clk_val = 0;
+ mi2s_rx_clk.clk_val2 = Q6AFE_LPASS_OSR_CLK_DISABLE;
+ mi2s_rx_clk.clk_val1 = Q6AFE_LPASS_IBIT_CLK_DISABLE;
+ ret = afe_set_lpass_clock(AFE_PORT_ID_SECONDARY_MI2S_RX,
+ &mi2s_rx_clk);
+ mi2s_tx_clk.clk_val2 = Q6AFE_LPASS_OSR_CLK_DISABLE;
+ mi2s_tx_clk.clk_val1 = Q6AFE_LPASS_IBIT_CLK_DISABLE;
+ ret = afe_set_lpass_clock(AFE_PORT_ID_PRIMARY_MI2S_RX,
+ &mi2s_tx_clk);
+ if (ret < 0)
+ pr_err("%s:afe_set_lpass_clock failed\n", __func__);
+
+ }
+ ret = msm_config_mclk(AFE_PORT_ID_SECONDARY_MI2S_RX, &digital_cdc_clk);
+ return ret;
+}
+
static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
@@ -41,13 +230,22 @@
return 0;
}
-static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
+static int msm_btsco_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
{
- pr_info("%s(), dev_name%s\n", __func__, dev_name(rtd->cpu_dai->dev));
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ rate->min = rate->max = msm_btsco_rate;
+ channels->min = channels->max = msm_btsco_ch;
+
return 0;
}
-static int msm_snd_hw_params(struct snd_pcm_substream *substream,
+static int msm_mi2s_snd_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
pr_debug("%s(): substream = %s stream = %d\n", __func__,
@@ -55,34 +253,184 @@
return 0;
}
-static int msm_snd_startup(struct snd_pcm_substream *substream)
+static int mi2s_clk_ctl(struct snd_pcm_substream *substream, bool enable)
{
+ int ret = 0;
+ if (enable) {
+ digital_cdc_clk.clk_val = 9600000;
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ mi2s_rx_clk.clk_val2 = Q6AFE_LPASS_OSR_CLK_12_P288_MHZ;
+ mi2s_rx_clk.clk_val1 = Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ;
+ ret = afe_set_lpass_clock(AFE_PORT_ID_SECONDARY_MI2S_RX,
+ &mi2s_rx_clk);
+ } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ mi2s_tx_clk.clk_val2 = Q6AFE_LPASS_OSR_CLK_12_P288_MHZ;
+ mi2s_tx_clk.clk_val1 = Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ;
+ ret = afe_set_lpass_clock(AFE_PORT_ID_PRIMARY_MI2S_RX,
+ &mi2s_tx_clk);
+ } else
+ pr_err("%s:Not valid substream.\n", __func__);
+
+ if (ret < 0)
+ pr_err("%s:afe_set_lpass_clock failed\n", __func__);
+
+ } else {
+ digital_cdc_clk.clk_val = 0;
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ mi2s_rx_clk.clk_val2 = Q6AFE_LPASS_OSR_CLK_DISABLE;
+ mi2s_rx_clk.clk_val1 = Q6AFE_LPASS_IBIT_CLK_DISABLE;
+ ret = afe_set_lpass_clock(AFE_PORT_ID_SECONDARY_MI2S_RX,
+ &mi2s_rx_clk);
+ } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ mi2s_tx_clk.clk_val2 = Q6AFE_LPASS_OSR_CLK_DISABLE;
+ mi2s_tx_clk.clk_val1 = Q6AFE_LPASS_IBIT_CLK_DISABLE;
+ ret = afe_set_lpass_clock(AFE_PORT_ID_PRIMARY_MI2S_RX,
+ &mi2s_tx_clk);
+ } else
+ pr_err("%s:Not valid substream.\n", __func__);
+
+ if (ret < 0)
+ pr_err("%s:afe_set_lpass_clock failed\n", __func__);
+
+ }
+ ret = msm_config_mclk(AFE_PORT_ID_SECONDARY_MI2S_RX, &digital_cdc_clk);
+ return ret;
+}
+
+static int msm8x10_enable_codec_ext_clk(struct snd_soc_codec *codec,
+ int enable, bool dapm)
+{
+ int ret = 0;
+
+ pr_debug("%s: enable = %d codec name %s enable %x\n",
+ __func__, enable, codec->name, enable);
+ if (enable) {
+ digital_cdc_clk.clk_val = 9600000;
+ msm_config_mi2s_clk(1);
+ ret = msm_config_mclk(AFE_PORT_ID_SECONDARY_MI2S_RX,
+ &digital_cdc_clk);
+ msm8x10_wcd_mclk_enable(codec, 1, dapm);
+ } else {
+ msm8x10_wcd_mclk_enable(codec, 0, dapm);
+ ret = msm_config_mclk(AFE_PORT_ID_SECONDARY_MI2S_RX,
+ &digital_cdc_clk);
+ msm_config_mi2s_clk(0);
+ }
+ return ret;
+}
+
+static int msm8x10_mclk_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ pr_debug("%s: event = %d\n", __func__, event);
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ return msm8x10_enable_codec_ext_clk(w->codec, 1, true);
+ case SND_SOC_DAPM_POST_PMD:
+ return msm8x10_enable_codec_ext_clk(w->codec, 0, true);
+ default:
+ return -EINVAL;
+ }
+}
+
+static void msm_mi2s_snd_shutdown(struct snd_pcm_substream *substream)
+{
+ int ret;
+
pr_debug("%s(): substream = %s stream = %d\n", __func__,
substream->name, substream->stream);
+ ret = mi2s_clk_ctl(substream, false);
+ if (ret < 0)
+ pr_err("%s:clock disable failed\n", __func__);
+}
+
+static int msm_mi2s_snd_startup(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ int ret = 0;
+
+ pr_debug("%s(): substream = %s stream = %d\n", __func__,
+ substream->name, substream->stream);
+
+ ret = mi2s_clk_ctl(substream, true);
+
+ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBS_CFS);
+ if (ret < 0)
+ pr_err("set fmt cpu dai failed\n");
+
+ return ret;
+}
+
+static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
+{
+
+ struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_dapm_context *dapm = &codec->dapm;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ int ret = 0;
+
+ pr_debug("%s(),dev_name%s\n", __func__, dev_name(cpu_dai->dev));
+
+ pr_debug("%s(): aud_init_rsc_ref counter = %d\n",
+ __func__, atomic_read(&aud_init_rsc_ref));
+ if (atomic_inc_return(&aud_init_rsc_ref) != 1)
+ goto exit;
+
+ snd_soc_dapm_new_controls(dapm, msm8x10_dapm_widgets,
+ ARRAY_SIZE(msm8x10_dapm_widgets));
+
+ snd_soc_dapm_add_routes(dapm, msm8x10_common_audio_map,
+ ARRAY_SIZE(msm8x10_common_audio_map));
+
+ snd_soc_dapm_sync(dapm);
+ ret = msm_enable_mclk_root(AFE_PORT_ID_SECONDARY_MI2S_RX,
+ &digital_cdc_clk);
+exit:
+ return ret;
+}
+
+static int msm_proxy_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ pr_debug("%s: msm_proxy_rx_ch =%d\n", __func__, msm_proxy_rx_ch);
+
+ if (channels->max < 2)
+ channels->min = channels->max = 2;
+ channels->min = channels->max = msm_proxy_rx_ch;
+ rate->min = rate->max = 48000;
return 0;
}
-
-static void msm_snd_shutdown(struct snd_pcm_substream *substream)
+static int msm_proxy_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
{
- pr_debug("%s(): substream = %s stream = %d\n", __func__,
- substream->name, substream->stream);
-}
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
-static struct snd_soc_ops msm8x10_be_ops = {
- .startup = msm_snd_startup,
- .hw_params = msm_snd_hw_params,
- .shutdown = msm_snd_shutdown,
+ rate->min = rate->max = 48000;
+ return 0;
+}
+static struct snd_soc_ops msm8x10_mi2s_be_ops = {
+ .startup = msm_mi2s_snd_startup,
+ .hw_params = msm_mi2s_snd_hw_params,
+ .shutdown = msm_mi2s_snd_shutdown,
};
/* Digital audio interface glue - connects codec <---> CPU */
static struct snd_soc_dai_link msm8x10_dai[] = {
/* FrontEnd DAI Links */
- {
+ {/* hw:x,0 */
.name = "MSM8X10 Media1",
.stream_name = "MultiMedia1",
.cpu_dai_name = "MultiMedia1",
- .platform_name = "msm-pcm-dsp",
+ .platform_name = "msm-pcm-dsp.0",
.dynamic = 1,
.trigger = {SND_SOC_DPCM_TRIGGER_POST,
SND_SOC_DPCM_TRIGGER_POST},
@@ -93,11 +441,11 @@
.ignore_pmdown_time = 1,
.be_id = MSM_FRONTEND_DAI_MULTIMEDIA1
},
- {
+ {/* hw:x,1 */
.name = "MSM8X10 Media2",
.stream_name = "MultiMedia2",
.cpu_dai_name = "MultiMedia2",
- .platform_name = "msm-pcm-dsp",
+ .platform_name = "msm-pcm-dsp.0",
.dynamic = 1,
.codec_dai_name = "snd-soc-dummy-dai",
.codec_name = "snd-soc-dummy",
@@ -108,31 +456,347 @@
.ignore_pmdown_time = 1,
.be_id = MSM_FRONTEND_DAI_MULTIMEDIA2,
},
+ {/* hw:x,2 */
+ .name = "Circuit-Switch Voice",
+ .stream_name = "CS-Voice",
+ .cpu_dai_name = "CS-VOICE",
+ .platform_name = "msm-pcm-voice",
+ .dynamic = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_CS_VOICE,
+ },
+ {/* hw:x,3 */
+ .name = "MSM VoIP",
+ .stream_name = "VoIP",
+ .cpu_dai_name = "VoIP",
+ .platform_name = "msm-voip-dsp",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_VOIP,
+ },
+ {/* hw:x,4 */
+ .name = "MSM8X10 LPA",
+ .stream_name = "LPA",
+ .cpu_dai_name = "MultiMedia3",
+ .platform_name = "msm-pcm-lpa",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA3,
+ },
+ /* Hostless PCM purpose */
+ {/* hw:x,5 */
+ .name = "Secondary MI2S RX Hostless",
+ .stream_name = "Secondary MI2S_RX Hostless Playback",
+ .cpu_dai_name = "SEC_MI2S_RX_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ /* This dainlink has MI2S support */
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {/* hw:x,6 */
+ .name = "INT_FM Hostless",
+ .stream_name = "INT_FM Hostless",
+ .cpu_dai_name = "INT_FM_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {/* hw:x,7 */
+ .name = "MSM AFE-PCM RX",
+ .stream_name = "AFE-PROXY RX",
+ .cpu_dai_name = "msm-dai-q6-dev.241",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .platform_name = "msm-pcm-afe",
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ },
+ {/* hw:x,8 */
+ .name = "MSM AFE-PCM TX",
+ .stream_name = "AFE-PROXY TX",
+ .cpu_dai_name = "msm-dai-q6-dev.240",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .platform_name = "msm-pcm-afe",
+ .ignore_suspend = 1,
+ },
+ {/* hw:x,9 */
+ .name = "MSM8X10 Compr",
+ .stream_name = "COMPR",
+ .cpu_dai_name = "MultiMedia4",
+ .platform_name = "msm-compr-dsp",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ /* this dainlink has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA4,
+ },
+ {/* hw:x,10 */
+ .name = "AUXPCM Hostless",
+ .stream_name = "AUXPCM Hostless",
+ .cpu_dai_name = "AUXPCM_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {/* hw:x,11 */
+ .name = "Primary MI2S TX Hostless",
+ .stream_name = "Primary MI2S_TX Hostless Capture",
+ .cpu_dai_name = "PRI_MI2S_TX_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ /* This dainlink has MI2S support */
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {/* hw:x,12 */
+ .name = "MSM8x10 LowLatency",
+ .stream_name = "MultiMedia5",
+ .cpu_dai_name = "MultiMedia5",
+ .platform_name = "msm-pcm-dsp.1",
+ .dynamic = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA5,
+ },
/* Backend I2S DAI Links */
{
- .name = LPASS_BE_MI2S_RX,
- .stream_name = "Primary MI2S Playback",
- .cpu_dai_name = "msm-dai-q6-mi2s.0",
- .platform_name = "msm-pcm-routing",
- .codec_name = "msm8x10-wcd-i2c-core.1-000d",
- .codec_dai_name = "msm8x10_wcd_i2s_rx1",
- .no_pcm = 1,
- .be_id = MSM_BACKEND_DAI_MI2S_RX,
- .init = &msm_audrx_init,
- .be_hw_params_fixup = msm_be_hw_params_fixup,
- .ops = &msm8x10_be_ops,
- },
- {
- .name = LPASS_BE_SEC_MI2S_TX,
- .stream_name = "Secondary MI2S Capture",
+ .name = LPASS_BE_SEC_MI2S_RX,
+ .stream_name = "Secondary MI2S Playback",
.cpu_dai_name = "msm-dai-q6-mi2s.1",
.platform_name = "msm-pcm-routing",
- .codec_name = "msm8x10-wcd-i2c-core.1-000d",
+ .codec_name = "msm8x10-wcd-i2c-core.5-000d",
+ .codec_dai_name = "msm8x10_wcd_i2s_rx1",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ .init = &msm_audrx_init,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &msm8x10_mi2s_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_PRI_MI2S_TX,
+ .stream_name = "Primary MI2S Capture",
+ .cpu_dai_name = "msm-dai-q6-mi2s.0",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm8x10-wcd-i2c-core.5-000d",
.codec_dai_name = "msm8x10_wcd_i2s_tx1",
.no_pcm = 1,
- .be_id = MSM_BACKEND_DAI_SECONDARY_MI2S_TX,
+ .be_id = MSM_BACKEND_DAI_PRI_MI2S_TX,
+ .init = &msm_audrx_init,
.be_hw_params_fixup = msm_be_hw_params_fixup,
- .ops = &msm8x10_be_ops,
+ .ops = &msm8x10_mi2s_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_INT_BT_SCO_RX,
+ .stream_name = "Internal BT-SCO Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.12288",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_INT_BT_SCO_RX,
+ .be_hw_params_fixup = msm_btsco_be_hw_params_fixup,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_INT_BT_SCO_TX,
+ .stream_name = "Internal BT-SCO Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.12289",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_INT_BT_SCO_TX,
+ .be_hw_params_fixup = msm_btsco_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_INT_FM_RX,
+ .stream_name = "Internal FM Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.12292",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_INT_FM_RX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_INT_FM_TX,
+ .stream_name = "Internal FM Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.12293",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_INT_FM_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_AFE_PCM_RX,
+ .stream_name = "AFE Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.224",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_AFE_PCM_RX,
+ .be_hw_params_fixup = msm_proxy_rx_be_hw_params_fixup,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_AFE_PCM_TX,
+ .stream_name = "AFE Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.225",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_AFE_PCM_TX,
+ .be_hw_params_fixup = msm_proxy_tx_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+ /* Incall Record Uplink BACK END DAI Link */
+ {
+ .name = LPASS_BE_INCALL_RECORD_TX,
+ .stream_name = "Voice Uplink Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.32772",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_INCALL_RECORD_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+ /* Incall Record Downlink BACK END DAI Link */
+ {
+ .name = LPASS_BE_INCALL_RECORD_RX,
+ .stream_name = "Voice Downlink Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.32771",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_INCALL_RECORD_RX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+ /* Incall Music BACK END DAI Link */
+ {
+ .name = LPASS_BE_VOICE_PLAYBACK_TX,
+ .stream_name = "Voice Farend Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.32773",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_VOICE_PLAYBACK_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+ /* Incall Record Uplink BACK END DAI Link */
+ {
+ .name = LPASS_BE_INCALL_RECORD_TX,
+ .stream_name = "Voice Uplink Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.32772",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_INCALL_RECORD_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+ /* Incall Record Downlink BACK END DAI Link */
+ {
+ .name = LPASS_BE_INCALL_RECORD_RX,
+ .stream_name = "Voice Downlink Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.32771",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_INCALL_RECORD_RX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+ /* Incall Music BACK END DAI Link */
+ {
+ .name = LPASS_BE_VOICE_PLAYBACK_TX,
+ .stream_name = "Voice Farend Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.32773",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_VOICE_PLAYBACK_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_suspend = 1,
},
};
@@ -165,6 +829,8 @@
goto err;
}
+ atomic_set(&aud_init_rsc_ref, 0);
+
return 0;
err:
return ret;
diff --git a/sound/soc/msm/qdsp6/q6asm.c b/sound/soc/msm/qdsp6/q6asm.c
index f15f4d1..659d5a2 100644
--- a/sound/soc/msm/qdsp6/q6asm.c
+++ b/sound/soc/msm/qdsp6/q6asm.c
@@ -912,6 +912,7 @@
case ASM_STREAM_CMD_OPEN_WRITE:
case ASM_STREAM_CMD_OPEN_WRITE_V2_1:
case ASM_STREAM_CMD_OPEN_READWRITE:
+ case ASM_STREAM_CMD_OPEN_LOOPBACK:
case ASM_DATA_CMD_MEDIA_FORMAT_UPDATE:
case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
case ASM_STREAM_CMD_OPEN_WRITE_COMPRESSED:
@@ -1852,6 +1853,45 @@
return -EINVAL;
}
+int q6asm_open_loopack(struct audio_client *ac)
+{
+ int rc = 0x00;
+ struct asm_stream_cmd_open_loopback open;
+
+ if ((ac == NULL) || (ac->apr == NULL)) {
+ pr_err("APR handle NULL\n");
+ return -EINVAL;
+ }
+ pr_debug("%s: session[%d]", __func__, ac->session);
+
+ q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
+ open.hdr.opcode = ASM_STREAM_CMD_OPEN_LOOPBACK;
+
+ open.mode_flags = 0;
+ open.src_endpointype = 0;
+ open.sink_endpointype = 0;
+ /* source endpoint : matrix */
+ open.postprocopo_id = get_asm_topology();
+ if (open.postprocopo_id == 0)
+ open.postprocopo_id = DEFAULT_POPP_TOPOLOGY;
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
+ if (rc < 0) {
+ pr_err("open failed op[0x%x]rc[%d]\n", \
+ open.hdr.opcode, rc);
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+ if (!rc) {
+ pr_err("timeout. waited for OPEN_WRITE rc[%d]\n", rc);
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return -EINVAL;
+}
+
int q6asm_run(struct audio_client *ac, uint32_t flags,
uint32_t msw_ts, uint32_t lsw_ts)
{
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
index 7d9cc16..04b090a 100644
--- a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
@@ -1482,7 +1482,7 @@
case SNDRV_PCM_STREAM_PLAYBACK:
switch (mi2s_id) {
case MSM_PRIM_MI2S:
- *port_id = MI2S_RX;
+ *port_id = AFE_PORT_ID_PRIMARY_MI2S_RX;
break;
case MSM_SEC_MI2S:
*port_id = AFE_PORT_ID_SECONDARY_MI2S_RX;
@@ -1502,7 +1502,7 @@
case SNDRV_PCM_STREAM_CAPTURE:
switch (mi2s_id) {
case MSM_PRIM_MI2S:
- *port_id = MI2S_TX;
+ *port_id = AFE_PORT_ID_PRIMARY_MI2S_TX;
break;
case MSM_SEC_MI2S:
*port_id = AFE_PORT_ID_SECONDARY_MI2S_TX;
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
index 717e63b..9fbf749 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
@@ -420,6 +420,12 @@
}
data = q6asm_is_cpu_buf_avail(IN, prtd->audio_client, &size, &idx);
+ if (size < fbytes) {
+ pr_err("%s: size mismatch error size %d fbytes %d\n",
+ __func__ , size , fbytes);
+ ret = -EFAULT;
+ goto fail;
+ }
bufptr = data;
if (bufptr) {
pr_debug("%s:fbytes =%d: xfer=%d size=%d\n",
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index e7c4a8a..fa476ee 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -1406,6 +1406,9 @@
SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new secondary_mi2s_rx_mixer_controls[] = {
@@ -1421,6 +1424,18 @@
SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new mi2s_hl_mixer_controls[] = {
+ SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_BACKEND_DAI_PRI_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_BACKEND_DAI_INT_FM_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
};
static const struct snd_kcontrol_new primary_mi2s_rx_mixer_controls[] = {
@@ -1436,6 +1451,9 @@
SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_PRI_MI2S_RX,
MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_PRI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new hdmi_mixer_controls[] = {
@@ -1571,6 +1589,9 @@
SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_MI2S_TX,
MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX,
MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
@@ -1646,6 +1667,9 @@
SOC_SINGLE_EXT("SEC_AUX_PCM_TX", MSM_BACKEND_DAI_SEC_AUXPCM_TX,
MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new pri_rx_voice_mixer_controls[] = {
@@ -1684,6 +1708,24 @@
msm_routing_put_voice_mixer),
};
+static const struct snd_kcontrol_new sec_mi2s_rx_voice_mixer_controls[] = {
+ SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voice2", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+};
+
static const struct snd_kcontrol_new slimbus_rx_voice_mixer_controls[] = {
SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_SLIMBUS_0_RX,
MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
@@ -1865,6 +1907,9 @@
SOC_SINGLE_EXT("SEC_AUX_PCM_TX_Voice", MSM_BACKEND_DAI_SEC_AUXPCM_TX,
MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("PRI_MI2S_TX_Voice", MSM_BACKEND_DAI_PRI_MI2S_TX,
+ MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
};
static const struct snd_kcontrol_new tx_voice2_mixer_controls[] = {
@@ -1934,6 +1979,9 @@
SOC_SINGLE_EXT("SEC_AUX_PCM_TX_Voip", MSM_BACKEND_DAI_SEC_AUXPCM_TX,
MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("PRI_MI2S_TX_Voip", MSM_BACKEND_DAI_PRI_MI2S_TX,
+ MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
};
static const struct snd_kcontrol_new tx_voice_stub_mixer_controls[] = {
@@ -2516,12 +2564,19 @@
SND_SOC_DAPM_AIF_IN("HDMI_DL_HL", "HDMI_HOSTLESS Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("SEC_I2S_DL_HL", "SEC_I2S_RX_HOSTLESS Playback",
0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SEC_MI2S_DL_HL",
+ "Secondary MI2S_RX Hostless Playback",
+ 0, 0, 0, 0),
+
SND_SOC_DAPM_AIF_IN("AUXPCM_DL_HL", "AUXPCM_HOSTLESS Playback",
0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("AUXPCM_UL_HL", "AUXPCM_HOSTLESS Capture",
0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MI2S_UL_HL", "MI2S_TX_HOSTLESS Capture",
0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("PRI_MI2S_UL_HL",
+ "Primary MI2S_TX Hostless Capture",
+ 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MI2S_DL_HL", "MI2S_RX_HOSTLESS Playback",
0, 0, 0, 0),
@@ -2549,6 +2604,8 @@
SND_SOC_DAPM_AIF_IN("MI2S_TX", "MI2S Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("QUAT_MI2S_TX", "Quaternary MI2S Capture",
0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("PRI_MI2S_TX", "Primary MI2S Capture",
+ 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("SEC_MI2S_TX", "Secondary MI2S Capture",
0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("SLIMBUS_0_TX", "Slimbus Capture", 0, 0, 0, 0),
@@ -2627,6 +2684,9 @@
SND_SOC_DAPM_MIXER("SEC_MI2S_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
secondary_mi2s_rx_mixer_controls,
ARRAY_SIZE(secondary_mi2s_rx_mixer_controls)),
+ SND_SOC_DAPM_MIXER("SEC_MI2S_RX Port Mixer", SND_SOC_NOPM, 0, 0,
+ mi2s_hl_mixer_controls,
+ ARRAY_SIZE(mi2s_hl_mixer_controls)),
SND_SOC_DAPM_MIXER("PRI_MI2S_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
primary_mi2s_rx_mixer_controls,
ARRAY_SIZE(primary_mi2s_rx_mixer_controls)),
@@ -2657,6 +2717,10 @@
SND_SOC_NOPM, 0, 0,
sec_i2s_rx_voice_mixer_controls,
ARRAY_SIZE(sec_i2s_rx_voice_mixer_controls)),
+ SND_SOC_DAPM_MIXER("SEC_MI2S_RX_Voice Mixer",
+ SND_SOC_NOPM, 0, 0,
+ sec_mi2s_rx_voice_mixer_controls,
+ ARRAY_SIZE(sec_mi2s_rx_voice_mixer_controls)),
SND_SOC_DAPM_MIXER("SLIM_0_RX_Voice Mixer",
SND_SOC_NOPM, 0, 0,
slimbus_rx_voice_mixer_controls,
@@ -2805,6 +2869,7 @@
{"QUAT_MI2S_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
{"QUAT_MI2S_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
{"QUAT_MI2S_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"QUAT_MI2S_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
{"QUAT_MI2S_RX", NULL, "QUAT_MI2S_RX Audio Mixer"},
@@ -2812,17 +2877,23 @@
{"SEC_MI2S_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
{"SEC_MI2S_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
{"SEC_MI2S_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"SEC_MI2S_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
{"SEC_MI2S_RX", NULL, "SEC_MI2S_RX Audio Mixer"},
+ {"SEC_MI2S_RX Port Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+ {"SEC_MI2S_RX Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+
{"PRI_MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
{"PRI_MI2S_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
{"PRI_MI2S_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
{"PRI_MI2S_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"PRI_MI2S_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
{"PRI_MI2S_RX", NULL, "PRI_MI2S_RX Audio Mixer"},
{"MultiMedia1 Mixer", "PRI_TX", "PRI_I2S_TX"},
{"MultiMedia1 Mixer", "MI2S_TX", "MI2S_TX"},
{"MultiMedia2 Mixer", "MI2S_TX", "MI2S_TX"},
+ {"MultiMedia5 Mixer", "MI2S_TX", "MI2S_TX"},
{"MultiMedia1 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
{"MultiMedia1 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
{"MultiMedia1 Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
@@ -2831,6 +2902,7 @@
{"MultiMedia5 Mixer", "SEC_AUX_PCM_TX", "SEC_AUX_PCM_TX"},
{"MultiMedia2 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
{"MultiMedia1 Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"},
+ {"MultiMedia1 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
@@ -2901,6 +2973,13 @@
{"SEC_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
{"SEC_I2S_RX", NULL, "SEC_RX_Voice Mixer"},
+ {"SEC_MI2S_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
+ {"SEC_MI2S_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
+ {"SEC_MI2S_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
+ {"SEC_MI2S_RX_Voice Mixer", "Voip", "VOIP_DL"},
+ {"SEC_MI2S_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
+ {"SEC_MI2S_RX", NULL, "SEC_MI2S_RX_Voice Mixer"},
+
{"SLIM_0_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
{"SLIM_0_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
{"SLIM_0_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
@@ -2951,6 +3030,7 @@
{"MI2S_RX", NULL, "MI2S_RX_Voice Mixer"},
{"Voice_Tx Mixer", "PRI_TX_Voice", "PRI_I2S_TX"},
+ {"Voice_Tx Mixer", "PRI_MI2S_TX_Voice", "PRI_MI2S_TX"},
{"Voice_Tx Mixer", "MI2S_TX_Voice", "MI2S_TX"},
{"Voice_Tx Mixer", "SLIM_0_TX_Voice", "SLIMBUS_0_TX"},
{"Voice_Tx Mixer", "INTERNAL_BT_SCO_TX_Voice", "INT_BT_SCO_TX"},
@@ -2982,6 +3062,7 @@
{"Voip_Tx Mixer", "AFE_PCM_TX_Voip", "PCM_TX"},
{"Voip_Tx Mixer", "AUX_PCM_TX_Voip", "AUX_PCM_TX"},
{"Voip_Tx Mixer", "SEC_AUX_PCM_TX_Voip", "SEC_AUX_PCM_TX"},
+ {"Voip_Tx Mixer", "PRI_MI2S_TX_Voip", "PRI_MI2S_TX"},
{"VOIP_UL", NULL, "Voip_Tx Mixer"},
{"SLIMBUS_DL_HL", "Switch", "SLIM0_DL_HL"},
@@ -3014,6 +3095,9 @@
{"PCM_RX", NULL, "PCM_RX_DL_HL"},
{"MI2S_UL_HL", NULL, "MI2S_TX"},
{"SEC_I2S_RX", NULL, "SEC_I2S_DL_HL"},
+ {"PRI_MI2S_UL_HL", NULL, "PRI_MI2S_TX"},
+ {"SEC_MI2S_RX", NULL, "SEC_MI2S_DL_HL"},
+
{"SLIMBUS_0_RX Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
{"SLIMBUS_0_RX Port Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
{"SLIMBUS_0_RX Port Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
@@ -3098,6 +3182,7 @@
{"PRI_I2S_TX", NULL, "BE_IN"},
{"MI2S_TX", NULL, "BE_IN"},
{"QUAT_MI2S_TX", NULL, "BE_IN"},
+ {"PRI_MI2S_TX", NULL, "BE_IN"},
{"SEC_MI2S_TX", NULL, "BE_IN"},
{"SLIMBUS_0_TX", NULL, "BE_IN" },
{"SLIMBUS_1_TX", NULL, "BE_IN" },
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
index 3598977..5b4244e 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -899,6 +899,44 @@
return ret;
}
+static int afe_send_bank_selection_clip(
+ struct afe_param_id_clip_bank_sel *param)
+{
+ int ret;
+ struct afe_svc_cmd_set_clip_bank_selection config;
+ if (!param) {
+ pr_err("%s: Invalid params", __func__);
+ return -EINVAL;
+ }
+ config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ config.hdr.pkt_size = sizeof(config);
+ config.hdr.src_port = 0;
+ config.hdr.dest_port = 0;
+ config.hdr.token = IDX_GLOBAL_CFG;
+ config.hdr.opcode = AFE_SVC_CMD_SET_PARAM;
+
+ config.param.payload_size = sizeof(struct afe_port_param_data_v2) +
+ sizeof(struct afe_param_id_clip_bank_sel);
+ config.param.payload_address_lsw = 0x00;
+ config.param.payload_address_msw = 0x00;
+ config.param.mem_map_handle = 0x00;
+
+ config.pdata.module_id = AFE_MODULE_CDC_DEV_CFG;
+ config.pdata.param_id = AFE_PARAM_ID_CLIP_BANK_SEL_CFG;
+ config.pdata.param_size =
+ sizeof(struct afe_param_id_clip_bank_sel);
+ config.bank_sel = *param;
+ ret = afe_apr_send_pkt(&config, &this_afe.wait[IDX_GLOBAL_CFG]);
+ if (ret) {
+ pr_err("%s: AFE_PARAM_ID_CLIP_BANK_SEL_CFG failed %d\n",
+ __func__, ret);
+ } else if (atomic_read(&this_afe.status) != 0) {
+ pr_err("%s: config cmd failed\n", __func__);
+ ret = -EAGAIN;
+ }
+ return ret;
+}
int afe_send_aanc_version(
struct afe_param_id_cdc_aanc_version *version_cfg)
{
@@ -991,6 +1029,12 @@
case AFE_AANC_VERSION:
ret = afe_send_aanc_version(config_data);
break;
+ case AFE_CLIP_BANK_SEL:
+ ret = afe_send_bank_selection_clip(config_data);
+ break;
+ case AFE_CDC_CLIP_REGISTERS_CONFIG:
+ ret = afe_send_codec_reg_config(config_data);
+ break;
default:
pr_err("%s: unknown configuration type", __func__);
ret = -EINVAL;
@@ -1149,21 +1193,20 @@
config.hdr.token = index;
switch (port_id) {
- case PRIMARY_I2S_RX:
- case PRIMARY_I2S_TX:
- cfg_type = AFE_PARAM_ID_PCM_CONFIG;
- break;
case AFE_PORT_ID_PRIMARY_PCM_RX:
case AFE_PORT_ID_PRIMARY_PCM_TX:
case AFE_PORT_ID_SECONDARY_PCM_RX:
case AFE_PORT_ID_SECONDARY_PCM_TX:
cfg_type = AFE_PARAM_ID_PCM_CONFIG;
break;
+ case PRIMARY_I2S_RX:
+ case PRIMARY_I2S_TX:
case SECONDARY_I2S_RX:
case SECONDARY_I2S_TX:
case MI2S_RX:
case MI2S_TX:
case AFE_PORT_ID_PRIMARY_MI2S_RX:
+ case AFE_PORT_ID_PRIMARY_MI2S_TX:
case AFE_PORT_ID_SECONDARY_MI2S_RX:
case AFE_PORT_ID_SECONDARY_MI2S_TX:
case AFE_PORT_ID_TERTIARY_MI2S_RX:
@@ -1288,6 +1331,8 @@
case SLIMBUS_5_TX: return IDX_SLIMBUS_5_TX;
case AFE_PORT_ID_PRIMARY_MI2S_RX:
return IDX_AFE_PORT_ID_PRIMARY_MI2S_RX;
+ case AFE_PORT_ID_PRIMARY_MI2S_TX:
+ return IDX_AFE_PORT_ID_PRIMARY_MI2S_TX;
case AFE_PORT_ID_QUATERNARY_MI2S_RX:
return IDX_AFE_PORT_ID_QUATERNARY_MI2S_RX;
case AFE_PORT_ID_QUATERNARY_MI2S_TX:
diff --git a/sound/soc/msm/qdsp6v2/q6audio-v2.c b/sound/soc/msm/qdsp6v2/q6audio-v2.c
index 3cb7a1f..dae1ebd 100644
--- a/sound/soc/msm/qdsp6v2/q6audio-v2.c
+++ b/sound/soc/msm/qdsp6v2/q6audio-v2.c
@@ -60,6 +60,8 @@
case RT_PROXY_PORT_001_TX: return IDX_RT_PROXY_PORT_001_TX;
case AFE_PORT_ID_PRIMARY_MI2S_RX:
return IDX_AFE_PORT_ID_PRIMARY_MI2S_RX;
+ case AFE_PORT_ID_PRIMARY_MI2S_TX:
+ return IDX_AFE_PORT_ID_PRIMARY_MI2S_TX;
case AFE_PORT_ID_QUATERNARY_MI2S_RX:
return IDX_AFE_PORT_ID_QUATERNARY_MI2S_RX;
case AFE_PORT_ID_QUATERNARY_MI2S_TX:
@@ -76,8 +78,8 @@
int q6audio_get_port_id(u16 port_id)
{
switch (port_id) {
- case PRIMARY_I2S_RX: return AFE_PORT_ID_PRIMARY_MI2S_RX;
- case PRIMARY_I2S_TX: return AFE_PORT_ID_PRIMARY_MI2S_TX;
+ case PRIMARY_I2S_RX: return PRIMARY_I2S_RX;
+ case PRIMARY_I2S_TX: return PRIMARY_I2S_TX;
case AFE_PORT_ID_PRIMARY_PCM_RX:
return AFE_PORT_ID_PRIMARY_PCM_RX;
case AFE_PORT_ID_PRIMARY_PCM_TX:
@@ -114,6 +116,8 @@
case RT_PROXY_PORT_001_TX: return AFE_PORT_ID_RT_PROXY_PORT_001_TX;
case AFE_PORT_ID_PRIMARY_MI2S_RX:
return AFE_PORT_ID_PRIMARY_MI2S_RX;
+ case AFE_PORT_ID_PRIMARY_MI2S_TX:
+ return AFE_PORT_ID_PRIMARY_MI2S_TX;
case AFE_PORT_ID_QUATERNARY_MI2S_RX:
return AFE_PORT_ID_QUATERNARY_MI2S_RX;
case AFE_PORT_ID_QUATERNARY_MI2S_TX:
@@ -168,6 +172,10 @@
case AFE_PORT_ID_TERTIARY_MI2S_RX:
case AFE_PORT_ID_QUATERNARY_MI2S_RX:
case AFE_PORT_ID_QUATERNARY_MI2S_TX:
+ case AFE_PORT_ID_PRIMARY_MI2S_RX:
+ case AFE_PORT_ID_PRIMARY_MI2S_TX:
+ case AFE_PORT_ID_SECONDARY_MI2S_RX:
+ case AFE_PORT_ID_SECONDARY_MI2S_TX:
break;
default:
ret = -EINVAL;
@@ -214,6 +222,7 @@
case RT_PROXY_PORT_001_RX:
case RT_PROXY_PORT_001_TX:
case AFE_PORT_ID_PRIMARY_MI2S_RX:
+ case AFE_PORT_ID_PRIMARY_MI2S_TX:
case AFE_PORT_ID_QUATERNARY_MI2S_RX:
case AFE_PORT_ID_QUATERNARY_MI2S_TX:
case AFE_PORT_ID_SECONDARY_MI2S_RX: