Merge "msm: kgsl: Add NULL check for next_event hook"
diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
index a9528c5..7ed873f 100644
--- a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
@@ -56,9 +56,9 @@
- qcom,enable-gpio: Specifies the panel lcd/display enable gpio.
- qcom,rst-gpio: Specifies the panel reset gpio.
- qcom,te-gpio: Specifies the gpio used for TE.
-- qcom,dsi-lpg-channel : LPG channel for backlight.
-- qcom,dsi-pwm-period : PWM period in microseconds.
-- qcom,dsi-pwm-gpio : PWM gpio.
+- qcom,pwm-lpg-channel: LPG channel for backlight.
+- qcom,pwm-period: PWM period in microseconds.
+- qcom,pwm-pmic-gpio: PMIC gpio binding to backlight.
- qcom,mdss-pan-broadcast-mode: Boolean used to enable broadcast mode.
- qcom,cont-splash-enabled: Boolean used to enable continuous splash mode.
- qcom,fbc-enabled: Boolean used to enable frame buffer compression mode.
@@ -174,6 +174,19 @@
- qcom,off-cmds-dsi-state: A string that Specifies the ctrl state for sending ON commands.
Supported modes are "DSI_LP_MODE" and "DSI_HS_MODE".
+
+- qcom,panel-on-cmds: A byte stream formed by multiple dcs packets base on
+ qcom dsi controller protocol.
+ byte 0 : dcs data type
+ byte 1 : set to indicate this is an individual packet
+ (no chain).
+ byte 2 : virtual channel number
+ byte 3 : expect ack from client (dcs read command)
+ byte 4 : wait number of specified ms after dcs command
+ transmitted
+ byte 5, 6: 16 bits length in network byte order
+ byte 7 and beyond: number byte of payload
+
Note, if a given optional qcom,* binding is not present, then the driver will configure
the default values specified.
@@ -204,7 +217,7 @@
qcom,mdss-pan-dsi-mdp-tr = <0x04>;
qcom,mdss-pan-dsi-dma-tr = <0x04>;
qcom,mdss-pan-frame-rate = <60>;
- qcom,panel-on-cmds = [32 01 00 00 00 02 00 00];
+ qcom,panel-on-cmds = [32 01 00 00 00 00 02 00 00];
qcom,on-cmds-dsi-state = "DSI_LP_MODE";
qcom,panel-off-cmds = [22 01 00 00 00 00 00];
qcom,off-cmds-dsi-state = "DSI LP MODE";
diff --git a/Documentation/devicetree/bindings/media/video/msm-cci.txt b/Documentation/devicetree/bindings/media/video/msm-cci.txt
index 9a7fa90..7616505 100644
--- a/Documentation/devicetree/bindings/media/video/msm-cci.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-cci.txt
@@ -91,6 +91,7 @@
- gpios : should contain phandle to gpio controller node and array of
#gpio-cells specifying specific gpio (controller specific)
- qcom,gpio-reset : should contain index to gpio used by sensors reset_n
+- qcom,gpio-standby : should contain index to gpio used by sensors standby_n
- qcom,gpio-req-tbl-num : should contain index to gpios specific to this sensor
- qcom,gpio-req-tbl-flags : should contain direction of gpios present in
qcom,gpio-req-tbl-num property (in the same order)
@@ -201,11 +202,15 @@
qcom,cam-vreg-op-mode = <105000 80000 0 100000>;
qcom,gpio-no-mux = <0>;
gpios = <&msmgpio 15 0>,
+ <&msmgpio 90 0>,
+ <&msmgpio 89 0>;
qcom,gpio-reset = <1>;
- qcom,gpio-req-tbl-num = <0 1>;
- qcom,gpio-req-tbl-flags = <1 0>;
+ qcom,gpio-standby = <2>;
+ qcom,gpio-req-tbl-num = <0 1 2>;
+ qcom,gpio-req-tbl-flags = <1 0 0>;
qcom,gpio-req-tbl-label = "CAMIF_MCLK",
- "CAM_RESET1";
+ "CAM_RESET1",
+ "CAM_STANDBY";
qcom,gpio-set-tbl-num = <1 1>;
qcom,gpio-set-tbl-flags = <0 2>;
qcom,gpio-set-tbl-delay = <1000 4000>;
diff --git a/Documentation/devicetree/bindings/power/qpnp-bms.txt b/Documentation/devicetree/bindings/power/qpnp-bms.txt
index e6f0da5..b350e24 100644
--- a/Documentation/devicetree/bindings/power/qpnp-bms.txt
+++ b/Documentation/devicetree/bindings/power/qpnp-bms.txt
@@ -64,6 +64,9 @@
curve.
- qcom,hold-soc-est: if the voltage-based estimated SoC is above this percent,
the BMS will clamp SoC to be at least 1.
+- qcom,tm-temp-margin: if the pmic die temperature changes by more than this
+ value, recalibrate the ADCs. The unit of this property
+ is in millidegrees celsius.
Parent node optional properties:
- qcom,ignore-shutdown-soc: A boolean that controls whether BMS will
@@ -122,6 +125,7 @@
qcom,low-ocv-correction-limit-uv = <100>;
qcom,high-ocv-correction-limit-uv = <50>;
qcom,hold-soc-est = <3>;
+ qcom,tm-temp-margin = <5000>;
qcom,bms-iadc@3800 {
reg = <0x3800 0x100>;
diff --git a/arch/arm/boot/dts/dsi-panel-nt35590-720p-video.dtsi b/arch/arm/boot/dts/dsi-panel-nt35590-720p-video.dtsi
index 10ca8a8..7bc748d 100644
--- a/arch/arm/boot/dts/dsi-panel-nt35590-720p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-nt35590-720p-video.dtsi
@@ -51,474 +51,474 @@
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 03
- 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,panel-on-cmds = [29 01 00 00 00 00 02 FF EE
+ 29 01 00 00 00 00 02 26 08
+ 29 01 00 00 00 00 02 26 00
+ 29 01 00 00 10 00 02 FF 00
+ 29 01 00 00 00 00 02 BA 03
+ 29 01 00 00 00 00 02 C2 03
+ 29 01 00 00 00 00 02 FF 01
+ 29 01 00 00 00 00 02 FB 01
+ 29 01 00 00 00 00 02 00 4A
+ 29 01 00 00 00 00 02 01 33
+ 29 01 00 00 00 00 02 02 53
+ 29 01 00 00 00 00 02 03 55
+ 29 01 00 00 00 00 02 04 55
+ 29 01 00 00 00 00 02 05 33
+ 29 01 00 00 00 00 02 06 22
+ 29 01 00 00 00 00 02 08 56
+ 29 01 00 00 00 00 02 09 8F
+ 29 01 00 00 00 00 02 36 73
+ 29 01 00 00 00 00 02 0B 9F
+ 29 01 00 00 00 00 02 0C 9F
+ 29 01 00 00 00 00 02 0D 2F
+ 29 01 00 00 00 00 02 0E 24
+ 29 01 00 00 00 00 02 11 83
+ 29 01 00 00 00 00 02 12 03
+ 29 01 00 00 00 00 02 71 2C
+ 29 01 00 00 00 00 02 6F 03
+ 29 01 00 00 00 00 02 0F 0A
+ 29 01 00 00 00 00 02 FF 05
+ 29 01 00 00 00 00 02 FB 01
+ 29 01 00 00 00 00 02 01 00
+ 29 01 00 00 00 00 02 02 8B
+ 29 01 00 00 00 00 02 03 82
+ 29 01 00 00 00 00 02 04 82
+ 29 01 00 00 00 00 02 05 30
+ 29 01 00 00 00 00 02 06 33
+ 29 01 00 00 00 00 02 07 01
+ 29 01 00 00 00 00 02 08 00
+ 29 01 00 00 00 00 02 09 46
+ 29 01 00 00 00 00 02 0A 46
+ 29 01 00 00 00 00 02 0D 0B
+ 29 01 00 00 00 00 02 0E 1D
+ 29 01 00 00 00 00 02 0F 08
+ 29 01 00 00 00 00 02 10 53
+ 29 01 00 00 00 00 02 11 00
+ 29 01 00 00 00 00 02 12 00
+ 29 01 00 00 00 00 02 14 01
+ 29 01 00 00 00 00 02 15 00
+ 29 01 00 00 00 00 02 16 05
+ 29 01 00 00 00 00 02 17 00
+ 29 01 00 00 00 00 02 19 7F
+ 29 01 00 00 00 00 02 1A FF
+ 29 01 00 00 00 00 02 1B 0F
+ 29 01 00 00 00 00 02 1C 00
+ 29 01 00 00 00 00 02 1D 00
+ 29 01 00 00 00 00 02 1E 00
+ 29 01 00 00 00 00 02 1F 07
+ 29 01 00 00 00 00 02 20 00
+ 29 01 00 00 00 00 02 21 06
+ 29 01 00 00 00 00 02 22 55
+ 29 01 00 00 00 00 02 23 4D
+ 29 01 00 00 00 00 02 2D 02
+ 29 01 00 00 00 00 02 28 01
+ 29 01 00 00 00 00 02 2F 02
+ 29 01 00 00 00 00 02 83 01
+ 29 01 00 00 00 00 02 9E 58
+ 29 01 00 00 00 00 02 9F 6A
+ 29 01 00 00 00 00 02 A0 01
+ 29 01 00 00 00 00 02 A2 10
+ 29 01 00 00 00 00 02 BB 0A
+ 29 01 00 00 00 00 02 BC 0A
+ 29 01 00 00 00 00 02 32 08
+ 29 01 00 00 00 00 02 33 B8
+ 29 01 00 00 00 00 02 36 01
+ 29 01 00 00 00 00 02 37 00
+ 29 01 00 00 00 00 02 43 00
+ 29 01 00 00 00 00 02 4B 21
+ 29 01 00 00 00 00 02 4C 03
+ 29 01 00 00 00 00 02 50 21
+ 29 01 00 00 00 00 02 51 03
+ 29 01 00 00 00 00 02 58 21
+ 29 01 00 00 00 00 02 59 03
+ 29 01 00 00 00 00 02 5D 21
+ 29 01 00 00 00 00 02 5E 03
+ 29 01 00 00 00 00 02 6C 00
+ 29 01 00 00 00 00 02 6D 00
+ 29 01 00 00 00 00 02 FB 01
+ 29 01 00 00 00 00 02 FF 01
+ 29 01 00 00 00 00 02 FB 01
+ 29 01 00 00 00 00 02 75 00
+ 29 01 00 00 00 00 02 76 7D
+ 29 01 00 00 00 00 02 77 00
+ 29 01 00 00 00 00 02 78 8A
+ 29 01 00 00 00 00 02 79 00
+ 29 01 00 00 00 00 02 7A 9C
+ 29 01 00 00 00 00 02 7B 00
+ 29 01 00 00 00 00 02 7C B1
+ 29 01 00 00 00 00 02 7D 00
+ 29 01 00 00 00 00 02 7E BF
+ 29 01 00 00 00 00 02 7F 00
+ 29 01 00 00 00 00 02 80 CF
+ 29 01 00 00 00 00 02 81 00
+ 29 01 00 00 00 00 02 82 DD
+ 29 01 00 00 00 00 02 83 00
+ 29 01 00 00 00 00 02 84 E8
+ 29 01 00 00 00 00 02 85 00
+ 29 01 00 00 00 00 02 86 F2
+ 29 01 00 00 00 00 02 87 01
+ 29 01 00 00 00 00 02 88 1F
+ 29 01 00 00 00 00 02 89 01
+ 29 01 00 00 00 00 02 8A 41
+ 29 01 00 00 00 00 02 8B 01
+ 29 01 00 00 00 00 02 8C 78
+ 29 01 00 00 00 00 02 8D 01
+ 29 01 00 00 00 00 02 8E A5
+ 29 01 00 00 00 00 02 8F 01
+ 29 01 00 00 00 00 02 90 EE
+ 29 01 00 00 00 00 02 91 02
+ 29 01 00 00 00 00 02 92 29
+ 29 01 00 00 00 00 02 93 02
+ 29 01 00 00 00 00 02 94 2A
+ 29 01 00 00 00 00 02 95 02
+ 29 01 00 00 00 00 02 96 5D
+ 29 01 00 00 00 00 02 97 02
+ 29 01 00 00 00 00 02 98 93
+ 29 01 00 00 00 00 02 99 02
+ 29 01 00 00 00 00 02 9A B8
+ 29 01 00 00 00 00 02 9B 02
+ 29 01 00 00 00 00 02 9C E7
+ 29 01 00 00 00 00 02 9D 03
+ 29 01 00 00 00 00 02 9E 07
+ 29 01 00 00 00 00 02 9F 03
+ 29 01 00 00 00 00 02 A0 37
+ 29 01 00 00 00 00 02 A2 03
+ 29 01 00 00 00 00 02 A3 46
+ 29 01 00 00 00 00 02 A4 03
+ 29 01 00 00 00 00 02 A5 56
+ 29 01 00 00 00 00 02 A6 03
+ 29 01 00 00 00 00 02 A7 66
+ 29 01 00 00 00 00 02 A9 03
+ 29 01 00 00 00 00 02 AA 7A
+ 29 01 00 00 00 00 02 AB 03
+ 29 01 00 00 00 00 02 AC 93
+ 29 01 00 00 00 00 02 AD 03
+ 29 01 00 00 00 00 02 AE A3
+ 29 01 00 00 00 00 02 AF 03
+ 29 01 00 00 00 00 02 B0 B4
+ 29 01 00 00 00 00 02 B1 03
+ 29 01 00 00 00 00 02 B2 CB
+ 29 01 00 00 00 00 02 B3 00
+ 29 01 00 00 00 00 02 B4 7D
+ 29 01 00 00 00 00 02 B5 00
+ 29 01 00 00 00 00 02 B6 8A
+ 29 01 00 00 00 00 02 B7 00
+ 29 01 00 00 00 00 02 B8 9C
+ 29 01 00 00 00 00 02 B9 00
+ 29 01 00 00 00 00 02 BA B1
+ 29 01 00 00 00 00 02 BB 00
+ 29 01 00 00 00 00 02 BC BF
+ 29 01 00 00 00 00 02 BD 00
+ 29 01 00 00 00 00 02 BE CF
+ 29 01 00 00 00 00 02 BF 00
+ 29 01 00 00 00 00 02 C0 DD
+ 29 01 00 00 00 00 02 C1 00
+ 29 01 00 00 00 00 02 C2 E8
+ 29 01 00 00 00 00 02 C3 00
+ 29 01 00 00 00 00 02 C4 F2
+ 29 01 00 00 00 00 02 C5 01
+ 29 01 00 00 00 00 02 C6 1F
+ 29 01 00 00 00 00 02 C7 01
+ 29 01 00 00 00 00 02 C8 41
+ 29 01 00 00 00 00 02 C9 01
+ 29 01 00 00 00 00 02 CA 78
+ 29 01 00 00 00 00 02 CB 01
+ 29 01 00 00 00 00 02 CC A5
+ 29 01 00 00 00 00 02 CD 01
+ 29 01 00 00 00 00 02 CE EE
+ 29 01 00 00 00 00 02 CF 02
+ 29 01 00 00 00 00 02 D0 29
+ 29 01 00 00 00 00 02 D1 02
+ 29 01 00 00 00 00 02 D2 2A
+ 29 01 00 00 00 00 02 D3 02
+ 29 01 00 00 00 00 02 D4 5D
+ 29 01 00 00 00 00 02 D5 02
+ 29 01 00 00 00 00 02 D6 93
+ 29 01 00 00 00 00 02 D7 02
+ 29 01 00 00 00 00 02 D8 B8
+ 29 01 00 00 00 00 02 D9 02
+ 29 01 00 00 00 00 02 DA E7
+ 29 01 00 00 00 00 02 DB 03
+ 29 01 00 00 00 00 02 DC 07
+ 29 01 00 00 00 00 02 DD 03
+ 29 01 00 00 00 00 02 DE 37
+ 29 01 00 00 00 00 02 DF 03
+ 29 01 00 00 00 00 02 E0 46
+ 29 01 00 00 00 00 02 E1 03
+ 29 01 00 00 00 00 02 E2 56
+ 29 01 00 00 00 00 02 E3 03
+ 29 01 00 00 00 00 02 E4 66
+ 29 01 00 00 00 00 02 E5 03
+ 29 01 00 00 00 00 02 E6 7A
+ 29 01 00 00 00 00 02 E7 03
+ 29 01 00 00 00 00 02 E8 93
+ 29 01 00 00 00 00 02 E9 03
+ 29 01 00 00 00 00 02 EA A3
+ 29 01 00 00 00 00 02 EB 03
+ 29 01 00 00 00 00 02 EC B4
+ 29 01 00 00 00 00 02 ED 03
+ 29 01 00 00 00 00 02 EE CB
+ 29 01 00 00 00 00 02 EF 00
+ 29 01 00 00 00 00 02 F0 ED
+ 29 01 00 00 00 00 02 F1 00
+ 29 01 00 00 00 00 02 F2 F3
+ 29 01 00 00 00 00 02 F3 00
+ 29 01 00 00 00 00 02 F4 FE
+ 29 01 00 00 00 00 02 F5 01
+ 29 01 00 00 00 00 02 F6 09
+ 29 01 00 00 00 00 02 F7 01
+ 29 01 00 00 00 00 02 F8 13
+ 29 01 00 00 00 00 02 F9 01
+ 29 01 00 00 00 00 02 FA 1D
+ 29 01 00 00 00 00 02 FF 02
+ 29 01 00 00 00 00 02 FB 01
+ 29 01 00 00 00 00 02 00 01
+ 29 01 00 00 00 00 02 01 26
+ 29 01 00 00 00 00 02 02 01
+ 29 01 00 00 00 00 02 03 2F
+ 29 01 00 00 00 00 02 04 01
+ 29 01 00 00 00 00 02 05 37
+ 29 01 00 00 00 00 02 06 01
+ 29 01 00 00 00 00 02 07 56
+ 29 01 00 00 00 00 02 08 01
+ 29 01 00 00 00 00 02 09 70
+ 29 01 00 00 00 00 02 0A 01
+ 29 01 00 00 00 00 02 0B 9D
+ 29 01 00 00 00 00 02 0C 01
+ 29 01 00 00 00 00 02 0D C2
+ 29 01 00 00 00 00 02 0E 01
+ 29 01 00 00 00 00 02 0F FF
+ 29 01 00 00 00 00 02 10 02
+ 29 01 00 00 00 00 02 11 31
+ 29 01 00 00 00 00 02 12 02
+ 29 01 00 00 00 00 02 13 32
+ 29 01 00 00 00 00 02 14 02
+ 29 01 00 00 00 00 02 15 60
+ 29 01 00 00 00 00 02 16 02
+ 29 01 00 00 00 00 02 17 94
+ 29 01 00 00 00 00 02 18 02
+ 29 01 00 00 00 00 02 19 B5
+ 29 01 00 00 00 00 02 1A 02
+ 29 01 00 00 00 00 02 1B E3
+ 29 01 00 00 00 00 02 1C 03
+ 29 01 00 00 00 00 02 1D 03
+ 29 01 00 00 00 00 02 1E 03
+ 29 01 00 00 00 00 02 1F 2D
+ 29 01 00 00 00 00 02 20 03
+ 29 01 00 00 00 00 02 21 3A
+ 29 01 00 00 00 00 02 22 03
+ 29 01 00 00 00 00 02 23 48
+ 29 01 00 00 00 00 02 24 03
+ 29 01 00 00 00 00 02 25 57
+ 29 01 00 00 00 00 02 26 03
+ 29 01 00 00 00 00 02 27 68
+ 29 01 00 00 00 00 02 28 03
+ 29 01 00 00 00 00 02 29 7B
+ 29 01 00 00 00 00 02 2A 03
+ 29 01 00 00 00 00 02 2B 90
+ 29 01 00 00 00 00 02 2D 03
+ 29 01 00 00 00 00 02 2F A0
+ 29 01 00 00 00 00 02 30 03
+ 29 01 00 00 00 00 02 31 CB
+ 29 01 00 00 00 00 02 32 00
+ 29 01 00 00 00 00 02 33 ED
+ 29 01 00 00 00 00 02 34 00
+ 29 01 00 00 00 00 02 35 F3
+ 29 01 00 00 00 00 02 36 00
+ 29 01 00 00 00 00 02 37 FE
+ 29 01 00 00 00 00 02 38 01
+ 29 01 00 00 00 00 02 39 09
+ 29 01 00 00 00 00 02 3A 01
+ 29 01 00 00 00 00 02 3B 13
+ 29 01 00 00 00 00 02 3D 01
+ 29 01 00 00 00 00 02 3F 1D
+ 29 01 00 00 00 00 02 40 01
+ 29 01 00 00 00 00 02 41 26
+ 29 01 00 00 00 00 02 42 01
+ 29 01 00 00 00 00 02 43 2F
+ 29 01 00 00 00 00 02 44 01
+ 29 01 00 00 00 00 02 45 37
+ 29 01 00 00 00 00 02 46 01
+ 29 01 00 00 00 00 02 47 56
+ 29 01 00 00 00 00 02 48 01
+ 29 01 00 00 00 00 02 49 70
+ 29 01 00 00 00 00 02 4A 01
+ 29 01 00 00 00 00 02 4B 9D
+ 29 01 00 00 00 00 02 4C 01
+ 29 01 00 00 00 00 02 4D C2
+ 29 01 00 00 00 00 02 4E 01
+ 29 01 00 00 00 00 02 4F FF
+ 29 01 00 00 00 00 02 50 02
+ 29 01 00 00 00 00 02 51 31
+ 29 01 00 00 00 00 02 52 02
+ 29 01 00 00 00 00 02 53 32
+ 29 01 00 00 00 00 02 54 02
+ 29 01 00 00 00 00 02 55 60
+ 29 01 00 00 00 00 02 56 02
+ 29 01 00 00 00 00 02 58 94
+ 29 01 00 00 00 00 02 59 02
+ 29 01 00 00 00 00 02 5A B5
+ 29 01 00 00 00 00 02 5B 02
+ 29 01 00 00 00 00 02 5C E3
+ 29 01 00 00 00 00 02 5D 03
+ 29 01 00 00 00 00 02 5E 03
+ 29 01 00 00 00 00 02 5F 03
+ 29 01 00 00 00 00 02 60 2D
+ 29 01 00 00 00 00 02 61 03
+ 29 01 00 00 00 00 02 62 3A
+ 29 01 00 00 00 00 02 63 03
+ 29 01 00 00 00 00 02 64 48
+ 29 01 00 00 00 00 02 65 03
+ 29 01 00 00 00 00 02 66 57
+ 29 01 00 00 00 00 02 67 03
+ 29 01 00 00 00 00 02 68 68
+ 29 01 00 00 00 00 02 69 03
+ 29 01 00 00 00 00 02 6A 7B
+ 29 01 00 00 00 00 02 6B 03
+ 29 01 00 00 00 00 02 6C 90
+ 29 01 00 00 00 00 02 6D 03
+ 29 01 00 00 00 00 02 6E A0
+ 29 01 00 00 00 00 02 6F 03
+ 29 01 00 00 00 00 02 70 CB
+ 29 01 00 00 00 00 02 71 00
+ 29 01 00 00 00 00 02 72 19
+ 29 01 00 00 00 00 02 73 00
+ 29 01 00 00 00 00 02 74 36
+ 29 01 00 00 00 00 02 75 00
+ 29 01 00 00 00 00 02 76 55
+ 29 01 00 00 00 00 02 77 00
+ 29 01 00 00 00 00 02 78 70
+ 29 01 00 00 00 00 02 79 00
+ 29 01 00 00 00 00 02 7A 83
+ 29 01 00 00 00 00 02 7B 00
+ 29 01 00 00 00 00 02 7C 99
+ 29 01 00 00 00 00 02 7D 00
+ 29 01 00 00 00 00 02 7E A8
+ 29 01 00 00 00 00 02 7F 00
+ 29 01 00 00 00 00 02 80 B7
+ 29 01 00 00 00 00 02 81 00
+ 29 01 00 00 00 00 02 82 C5
+ 29 01 00 00 00 00 02 83 00
+ 29 01 00 00 00 00 02 84 F7
+ 29 01 00 00 00 00 02 85 01
+ 29 01 00 00 00 00 02 86 1E
+ 29 01 00 00 00 00 02 87 01
+ 29 01 00 00 00 00 02 88 60
+ 29 01 00 00 00 00 02 89 01
+ 29 01 00 00 00 00 02 8A 95
+ 29 01 00 00 00 00 02 8B 01
+ 29 01 00 00 00 00 02 8C E1
+ 29 01 00 00 00 00 02 8D 02
+ 29 01 00 00 00 00 02 8E 20
+ 29 01 00 00 00 00 02 8F 02
+ 29 01 00 00 00 00 02 90 23
+ 29 01 00 00 00 00 02 91 02
+ 29 01 00 00 00 00 02 92 59
+ 29 01 00 00 00 00 02 93 02
+ 29 01 00 00 00 00 02 94 94
+ 29 01 00 00 00 00 02 95 02
+ 29 01 00 00 00 00 02 96 B4
+ 29 01 00 00 00 00 02 97 02
+ 29 01 00 00 00 00 02 98 E1
+ 29 01 00 00 00 00 02 99 03
+ 29 01 00 00 00 00 02 9A 01
+ 29 01 00 00 00 00 02 9B 03
+ 29 01 00 00 00 00 02 9C 28
+ 29 01 00 00 00 00 02 9D 03
+ 29 01 00 00 00 00 02 9E 30
+ 29 01 00 00 00 00 02 9F 03
+ 29 01 00 00 00 00 02 A0 37
+ 29 01 00 00 00 00 02 A2 03
+ 29 01 00 00 00 00 02 A3 3B
+ 29 01 00 00 00 00 02 A4 03
+ 29 01 00 00 00 00 02 A5 40
+ 29 01 00 00 00 00 02 A6 03
+ 29 01 00 00 00 00 02 A7 50
+ 29 01 00 00 00 00 02 A9 03
+ 29 01 00 00 00 00 02 AA 6D
+ 29 01 00 00 00 00 02 AB 03
+ 29 01 00 00 00 00 02 AC 80
+ 29 01 00 00 00 00 02 AD 03
+ 29 01 00 00 00 00 02 AE CB
+ 29 01 00 00 00 00 02 AF 00
+ 29 01 00 00 00 00 02 B0 19
+ 29 01 00 00 00 00 02 B1 00
+ 29 01 00 00 00 00 02 B2 36
+ 29 01 00 00 00 00 02 B3 00
+ 29 01 00 00 00 00 02 B4 55
+ 29 01 00 00 00 00 02 B5 00
+ 29 01 00 00 00 00 02 B6 70
+ 29 01 00 00 00 00 02 B7 00
+ 29 01 00 00 00 00 02 B8 83
+ 29 01 00 00 00 00 02 B9 00
+ 29 01 00 00 00 00 02 BA 99
+ 29 01 00 00 00 00 02 BB 00
+ 29 01 00 00 00 00 02 BC A8
+ 29 01 00 00 00 00 02 BD 00
+ 29 01 00 00 00 00 02 BE B7
+ 29 01 00 00 00 00 02 BF 00
+ 29 01 00 00 00 00 02 C0 C5
+ 29 01 00 00 00 00 02 C1 00
+ 29 01 00 00 00 00 02 C2 F7
+ 29 01 00 00 00 00 02 C3 01
+ 29 01 00 00 00 00 02 C4 1E
+ 29 01 00 00 00 00 02 C5 01
+ 29 01 00 00 00 00 02 C6 60
+ 29 01 00 00 00 00 02 C7 01
+ 29 01 00 00 00 00 02 C8 95
+ 29 01 00 00 00 00 02 C9 01
+ 29 01 00 00 00 00 02 CA E1
+ 29 01 00 00 00 00 02 CB 02
+ 29 01 00 00 00 00 02 CC 20
+ 29 01 00 00 00 00 02 CD 02
+ 29 01 00 00 00 00 02 CE 23
+ 29 01 00 00 00 00 02 CF 02
+ 29 01 00 00 00 00 02 D0 59
+ 29 01 00 00 00 00 02 D1 02
+ 29 01 00 00 00 00 02 D2 94
+ 29 01 00 00 00 00 02 D3 02
+ 29 01 00 00 00 00 02 D4 B4
+ 29 01 00 00 00 00 02 D5 02
+ 29 01 00 00 00 00 02 D6 E1
+ 29 01 00 00 00 00 02 D7 03
+ 29 01 00 00 00 00 02 D8 01
+ 29 01 00 00 00 00 02 D9 03
+ 29 01 00 00 00 00 02 DA 28
+ 29 01 00 00 00 00 02 DB 03
+ 29 01 00 00 00 00 02 DC 30
+ 29 01 00 00 00 00 02 DD 03
+ 29 01 00 00 00 00 02 DE 37
+ 29 01 00 00 00 00 02 DF 03
+ 29 01 00 00 00 00 02 E0 3B
+ 29 01 00 00 00 00 02 E1 03
+ 29 01 00 00 00 00 02 E2 40
+ 29 01 00 00 00 00 02 E3 03
+ 29 01 00 00 00 00 02 E4 50
+ 29 01 00 00 00 00 02 E5 03
+ 29 01 00 00 00 00 02 E6 6D
+ 29 01 00 00 00 00 02 E7 03
+ 29 01 00 00 00 00 02 E8 80
+ 29 01 00 00 00 00 02 E9 03
+ 29 01 00 00 00 00 02 EA CB
+ 29 01 00 00 00 00 02 FF 01
+ 29 01 00 00 00 00 02 FB 01
+ 29 01 00 00 00 00 02 FF 02
+ 29 01 00 00 00 00 02 FB 01
+ 29 01 00 00 00 00 02 FF 04
+ 29 01 00 00 00 00 02 FB 01
+ 29 01 00 00 00 00 02 FF 00
+ 29 01 00 00 64 00 02 11 00
+ 29 01 00 00 00 00 02 FF EE
+ 29 01 00 00 00 00 02 12 50
+ 29 01 00 00 00 00 02 13 02
+ 29 01 00 00 00 00 02 6A 60
+ 29 01 00 00 00 00 02 FF 00
+ 29 01 00 00 78 00 02 29 00];
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,panel-off-cmds = [05 01 00 00 32 00 02 28 00
+ 05 01 00 00 78 00 02 10 00];
qcom,off-cmds-dsi-state = "DSI_HS_MODE";
};
};
diff --git a/arch/arm/boot/dts/dsi-panel-orise-720p-video.dtsi b/arch/arm/boot/dts/dsi-panel-orise-720p-video.dtsi
index a27a88a..478541f 100644
--- a/arch/arm/boot/dts/dsi-panel-orise-720p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-orise-720p-video.dtsi
@@ -50,11 +50,11 @@
00 c2 45 00 00 00 00 01 75 /* lane3 config */
00 02 45 00 00 00 00 01 97]; /* Clk ln config */
- qcom,panel-on-cmds = [05 01 00 00 78 02 11 00
- 05 01 00 00 78 02 29 00];
+ qcom,panel-on-cmds = [05 01 00 00 78 00 02 11 00
+ 05 01 00 00 78 00 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,panel-off-cmds = [05 01 00 00 32 00 02 28 00
+ 05 01 00 00 78 00 02 10 00];
qcom,off-cmds-dsi-state = "DSI_LP_MODE";
};
};
diff --git a/arch/arm/boot/dts/dsi-panel-sharp-qhd-video.dtsi b/arch/arm/boot/dts/dsi-panel-sharp-qhd-video.dtsi
index d182bac..45d396c 100644
--- a/arch/arm/boot/dts/dsi-panel-sharp-qhd-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-sharp-qhd-video.dtsi
@@ -52,16 +52,16 @@
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 = [05 01 00 00 32 02 01 00 /* sw reset */
- 05 01 00 00 0a 02 11 00 /* exit sleep */
- 15 01 00 00 0a 02 53 2c /* backlight on */
- 15 01 00 00 0a 02 51 ff /* brightness max */
- 05 01 00 00 0a 02 29 00 /* display on */
- 15 01 00 00 0a 02 ae 03 /* set num of lanes */
- 15 01 00 00 0a 02 3a 77 /* rgb_888 */];
+ qcom,panel-on-cmds = [05 01 00 00 32 00 02 01 00 /* sw reset */
+ 05 01 00 00 0a 00 02 11 00 /* exit sleep */
+ 15 01 00 00 0a 00 02 53 2c /* backlight on */
+ 15 01 00 00 0a 00 02 51 ff /* brightness max */
+ 05 01 00 00 0a 00 02 29 00 /* display on */
+ 15 01 00 00 0a 00 02 ae 03 /* set num of lanes */
+ 15 01 00 00 0a 00 02 3a 77 /* rgb_888 */];
qcom,on-cmds-dsi-state = "DSI_LP_MODE";
- qcom,panel-off-cmds = [05 01 00 00 0a 02 28 00 /* display off */
- 05 01 00 00 78 02 10 00 /* enter sleep */];
+ qcom,panel-off-cmds = [05 01 00 00 0a 00 02 28 00 /* display off */
+ 05 01 00 00 78 00 02 10 00 /* enter sleep */];
qcom,off-cmds-dsi-state = "DSI_HS_MODE";
};
};
diff --git a/arch/arm/boot/dts/dsi-panel-sim-video.dtsi b/arch/arm/boot/dts/dsi-panel-sim-video.dtsi
index 3b39dea..271e373 100644
--- a/arch/arm/boot/dts/dsi-panel-sim-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-sim-video.dtsi
@@ -38,9 +38,9 @@
qcom,mdss-pan-dsi-mdp-tr = <0x04>;
qcom,mdss-pan-dsi-dma-tr = <0x04>;
qcom,mdss-pan-dsi-frame-rate = <60>;
- qcom,panel-on-cmds = [32 01 00 00 00 02 00 00];
+ qcom,panel-on-cmds = [32 01 00 00 00 00 02 00 00];
qcom,on-cmds-dsi-state = "DSI_LP_MODE";
- qcom,panel-off-cmds = [22 01 00 00 00 02 00 00];
+ qcom,panel-off-cmds = [22 01 00 00 00 00 02 00 00];
qcom,off-cmds-dsi-state = "DSI_LP_MODE";
};
};
diff --git a/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi b/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi
index 82b57cd..5c37cf8 100644
--- a/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi
@@ -54,71 +54,71 @@
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 = [23 01 00 00 0a 02 b0 00
- 23 01 00 00 0a 02 b2 00
- 23 01 00 00 0a 02 b3 0c
- 23 01 00 00 0a 02 b4 02
- 29 01 00 00 00 06
+ qcom,panel-on-cmds = [23 01 00 00 0a 00 02 b0 00
+ 23 01 00 00 0a 00 02 b2 00
+ 23 01 00 00 0a 00 02 b3 0c
+ 23 01 00 00 0a 00 02 b4 02
+ 29 01 00 00 00 00 06
c0 40 02 7f c8 08
- 29 01 00 00 00 10
+ 29 01 00 00 00 00 10
c1 00 a8 00 00 00
00 00 9d 08 27 00
00 00 00 00
- 29 01 00 00 00 06
+ 29 01 00 00 00 00 06
c2 00 00 09 00 00
- 23 01 00 00 0a 02 c3 04
- 29 01 00 00 00 04
+ 23 01 00 00 0a 00 02 c3 04
+ 29 01 00 00 00 00 04
c4 4d 83 00
- 29 01 00 00 00 0b
+ 29 01 00 00 00 00 0b
c6 12 00 08 71 00
00 00 80 00 04
- 23 01 00 00 0a 02 c7 22
- 29 01 00 00 00 05
+ 23 01 00 00 0a 00 02 c7 22
+ 29 01 00 00 00 00 05
c8 4c 0c 0c 0c
- 29 01 00 00 00 0e
+ 29 01 00 00 00 00 0e
c9 00 40 00 16 32
2e 3a 43 3e 3c 45
79 3f
- 29 01 00 00 00 0e
+ 29 01 00 00 00 00 0e
ca 00 46 1a 23 21
1c 25 31 2d 49 5f
7f 3f
- 29 01 00 00 00 0e
+ 29 01 00 00 00 00 0e
cb 00 4c 20 3a 42
40 47 4b 42 3e 46
7e 3f
- 29 01 00 00 00 0e
+ 29 01 00 00 00 00 0e
cc 00 41 19 21 1d
14 18 1f 1d 25 3f
73 3f
- 29 01 00 00 00 0e
+ 29 01 00 00 00 00 0e
cd 23 79 5a 5f 57
4c 51 51 45 3f 4b
7f 3f
- 29 01 00 00 00 0e
+ 29 01 00 00 00 00 0e
ce 00 40 14 20 1a
0e 0e 13 08 00 05
46 1c
- 29 01 00 00 00 04
+ 29 01 00 00 00 00 04
d0 6a 64 01
- 29 01 00 00 00 03 d1 77 d4
- 23 01 00 00 0a 02 d3 33
- 29 01 00 00 00 03 d5 0f 0f
- 29 01 00 00 00 07
+ 29 01 00 00 00 00 03 d1 77 d4
+ 23 01 00 00 0a 00 02 d3 33
+ 29 01 00 00 00 00 03 d5 0f 0f
+ 29 01 00 00 00 00 07
d8 34 64 23 25 62
32
- 29 01 00 00 00 0c
+ 29 01 00 00 00 00 0c
de 10 7b 11 0a 00
00 00 00 00 00 00
- 29 01 00 00 00 09
+ 29 01 00 00 00 00 09
fd 04 55 53 00 70
ff 10 73
- 23 01 00 00 0a 02 e2 00
- 05 01 00 00 78 02 11 00
- 05 01 00 00 32 02 29 00];
+ 23 01 00 00 0a 00 02 e2 00
+ 05 01 00 00 78 00 02 11 00
+ 05 01 00 00 32 00 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,panel-off-cmds = [05 01 00 00 32 00 02 28 00
+ 05 01 00 00 78 00 02 10 00];
qcom,off-cmds-dsi-state = "DSI_HS_MODE";
};
};
diff --git a/arch/arm/boot/dts/mpq8092-ion.dtsi b/arch/arm/boot/dts/mpq8092-ion.dtsi
index ee3fbc4..f9f5985 100644
--- a/arch/arm/boot/dts/mpq8092-ion.dtsi
+++ b/arch/arm/boot/dts/mpq8092-ion.dtsi
@@ -20,58 +20,14 @@
reg = <30>;
};
- qcom,ion-heap@8 { /* CP_MM HEAP */
- compatible = "qcom,msm-ion-reserve";
- reg = <8>;
- qcom,heap-align = <0x1000>;
- qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
- qcom,memory-reservation-size = <0x7800000>;
- };
-
- qcom,ion-heap@29 { /* FIRMWARE HEAP */
- compatible = "qcom,msm-ion-reserve";
- reg = <29>;
- qcom,heap-align = <0x20000>;
- qcom,heap-adjacent = <8>;
- qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
- qcom,memory-reservation-size = <0xA00000>;
- };
-
- qcom,ion-heap@12 { /* MFC HEAP */
- compatible = "qcom,msm-ion-reserve";
- reg = <12>;
- qcom,heap-align = <0x1000>;
- qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
- qcom,memory-reservation-size = <0x2000>;
- };
-
- qcom,ion-heap@24 { /* SF HEAP */
- compatible = "qcom,msm-ion-reserve";
- reg = <24>;
- qcom,heap-align = <0x1000>;
- qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
- qcom,memory-reservation-size = <0x2800000>;
+ qcom,ion-heap@21 { /* SYSTEM CONTIG HEAP */
+ reg = <21>;
};
qcom,ion-heap@25 { /* IOMMU HEAP */
reg = <25>;
};
- 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 = <0x600000>;
- };
-
- qcom,ion-heap@28 { /* AUDIO HEAP */
- compatible = "qcom,msm-ion-reserve";
- reg = <28>;
- qcom,heap-align = <0x1000>;
- qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
- qcom,memory-reservation-size = <0x2B4000>;
- };
};
};
diff --git a/arch/arm/boot/dts/mpq8092-sim.dts b/arch/arm/boot/dts/mpq8092-sim.dts
index ce97d4d..676ef3b 100644
--- a/arch/arm/boot/dts/mpq8092-sim.dts
+++ b/arch/arm/boot/dts/mpq8092-sim.dts
@@ -16,7 +16,7 @@
/ {
model = "Qualcomm MPQ8092 Simulator";
- compatible = "qcom,mpq8092-sim", "qcom,mpq8092";
+ compatible = "qcom,mpq8092-sim", "qcom,mpq8092", "qcom,sim";
qcom,msm-id = <126 16 0>;
};
diff --git a/arch/arm/boot/dts/msm-pm8110.dtsi b/arch/arm/boot/dts/msm-pm8110.dtsi
index e22e398..e1f0e61 100644
--- a/arch/arm/boot/dts/msm-pm8110.dtsi
+++ b/arch/arm/boot/dts/msm-pm8110.dtsi
@@ -286,6 +286,7 @@
qcom,chg-term-ua = <100000>;
qcom,batt-type = <0>;
qcom,low-voltage-threshold = <3420000>;
+ qcom,tm-temp-margin = <5000>;
qcom,low-ocv-correction-limit-uv = <100>;
qcom,high-ocv-correction-limit-uv = <50>;
qcom,hold-soc-est = <3>;
diff --git a/arch/arm/boot/dts/msm-pm8226.dtsi b/arch/arm/boot/dts/msm-pm8226.dtsi
index 4d6751c..0db886b 100644
--- a/arch/arm/boot/dts/msm-pm8226.dtsi
+++ b/arch/arm/boot/dts/msm-pm8226.dtsi
@@ -173,6 +173,7 @@
qcom,calculate-soc-ms = <20000>;
qcom,chg-term-ua = <100000>;
qcom,batt-type = <0>;
+ qcom,tm-temp-margin = <5000>;
qcom,low-ocv-correction-limit-uv = <100>;
qcom,high-ocv-correction-limit-uv = <50>;
qcom,hold-soc-est = <3>;
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index ce6bc63..34ea33d 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -116,6 +116,7 @@
qcom,chg-term-ua = <100000>;
qcom,batt-type = <0>;
qcom,low-voltage-threshold = <3420000>;
+ qcom,tm-temp-margin = <5000>;
qcom,low-ocv-correction-limit-uv = <100>;
qcom,high-ocv-correction-limit-uv = <50>;
qcom,hold-soc-est = <3>;
@@ -173,7 +174,7 @@
qcom,vddmax-mv = <4200>;
qcom,vddsafe-mv = <4200>;
- qcom,vinmin-mv = <4200>;
+ qcom,vinmin-mv = <4300>;
qcom,ibatmax-ma = <1500>;
qcom,ibatterm-ma = <100>;
qcom,ibatsafe-ma = <1500>;
diff --git a/arch/arm/boot/dts/msm8226-camera-sensor-cdp.dtsi b/arch/arm/boot/dts/msm8226-camera-sensor-cdp.dtsi
index 07f16b9..41d6b7e 100644
--- a/arch/arm/boot/dts/msm8226-camera-sensor-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8226-camera-sensor-cdp.dtsi
@@ -73,7 +73,7 @@
reg = <0x6d>;
qcom,slave-id = <0x20 0x0 0x9724>;
qcom,csiphy-sd-index = <1>;
- qcom,csid-sd-index = <0>;
+ qcom,csid-sd-index = <1>;
qcom,mount-angle = <0>;
qcom,sensor-name = "ov9724";
cam_vdig-supply = <&pm8226_l5>;
diff --git a/arch/arm/boot/dts/msm8226-camera-sensor-mtp.dtsi b/arch/arm/boot/dts/msm8226-camera-sensor-mtp.dtsi
index f06033e..53860ac 100644
--- a/arch/arm/boot/dts/msm8226-camera-sensor-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8226-camera-sensor-mtp.dtsi
@@ -73,8 +73,8 @@
reg = <0x6d>;
qcom,slave-id = <0x20 0x0 0x9724>;
qcom,csiphy-sd-index = <1>;
- qcom,csid-sd-index = <0>;
- qcom,mount-angle = <90>;
+ qcom,csid-sd-index = <1>;
+ qcom,mount-angle = <270>;
qcom,sensor-name = "ov9724";
cam_vdig-supply = <&pm8226_l5>;
cam_vana-supply = <&pm8226_l19>;
diff --git a/arch/arm/boot/dts/msm8226-camera-sensor-qrd.dtsi b/arch/arm/boot/dts/msm8226-camera-sensor-qrd.dtsi
index 47f4049..3935dbb 100644
--- a/arch/arm/boot/dts/msm8226-camera-sensor-qrd.dtsi
+++ b/arch/arm/boot/dts/msm8226-camera-sensor-qrd.dtsi
@@ -73,8 +73,8 @@
reg = <0x6d>;
qcom,slave-id = <0x20 0x0 0x9724>;
qcom,csiphy-sd-index = <1>;
- qcom,csid-sd-index = <0>;
- qcom,mount-angle = <90>;
+ qcom,csid-sd-index = <1>;
+ qcom,mount-angle = <270>;
qcom,sensor-name = "ov9724";
cam_vdig-supply = <&pm8226_l5>;
cam_vana-supply = <&pm8226_l19>;
diff --git a/arch/arm/boot/dts/msm8226-camera.dtsi b/arch/arm/boot/dts/msm8226-camera.dtsi
index 0dae162..ec0092d 100644
--- a/arch/arm/boot/dts/msm8226-camera.dtsi
+++ b/arch/arm/boot/dts/msm8226-camera.dtsi
@@ -21,8 +21,9 @@
qcom,csiphy@fda0ac00 {
cell-index = <0>;
compatible = "qcom,csiphy";
- reg = <0xfda0ac00 0x200>;
- reg-names = "csiphy";
+ reg = <0xfda0ac00 0x200>,
+ <0xfda00030 0x4>;
+ reg-names = "csiphy", "csiphy_clk_mux";
interrupts = <0 78 0>;
interrupt-names = "csiphy";
};
@@ -30,8 +31,9 @@
qcom,csiphy@fda0b000 {
cell-index = <1>;
compatible = "qcom,csiphy";
- reg = <0xfda0b000 0x200>;
- reg-names = "csiphy";
+ reg = <0xfda0b000 0x200>,
+ <0xfda00038 0x4>;
+ reg-names = "csiphy", "csiphy_clk_mux";
interrupts = <0 79 0>;
interrupt-names = "csiphy";
};
@@ -61,8 +63,9 @@
qcom,ispif@fda0a000 {
cell-index = <0>;
compatible = "qcom,ispif";
- reg = <0xfda0a000 0x500>;
- reg-names = "ispif";
+ reg = <0xfda0a000 0x500>,
+ <0xfda00020 0x10>;
+ reg-names = "ispif", "csi_clk_mux";
interrupts = <0 55 0>;
interrupt-names = "ispif";
};
diff --git a/arch/arm/boot/dts/msm8610-coresight.dtsi b/arch/arm/boot/dts/msm8610-coresight.dtsi
index 0d9ae9a..516522e 100644
--- a/arch/arm/boot/dts/msm8610-coresight.dtsi
+++ b/arch/arm/boot/dts/msm8610-coresight.dtsi
@@ -340,4 +340,18 @@
coresight-name = "coresight-cti-cpu3";
coresight-nr-inports = <0>;
};
+
+ hwevent: hwevent@fd820018 {
+ compatible = "qcom,coresight-hwevent";
+ reg = <0xfd820018 0x80>,
+ <0xf9011080 0x80>,
+ <0xfd4ab160 0x80>;
+ reg-names = "mmss-mux", "apcs-mux", "ppss-mux";
+
+ coresight-id = <27>;
+ coresight-name = "coresight-hwevent";
+ coresight-nr-inports = <0>;
+
+ qcom,hwevent-clks = "core_mmss_clk";
+ };
};
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-cdp.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-cdp.dtsi
index b574a31..efd9c32 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-cdp.dtsi
@@ -89,11 +89,15 @@
qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
qcom,gpio-no-mux = <0>;
gpios = <&msmgpio 15 0>,
- <&msmgpio 90 0>;
+ <&msmgpio 90 0>,
+ <&msmgpio 89 0>;
qcom,gpio-reset = <1>;
- qcom,gpio-req-tbl-num = <0 1>;
- qcom,gpio-req-tbl-flags = <1 0>;
- qcom,gpio-req-tbl-label = "CAMIF_MCLK", "CAM_RESET1";
+ qcom,gpio-standby = <2>;
+ qcom,gpio-req-tbl-num = <0 1 2>;
+ qcom,gpio-req-tbl-flags = <1 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+ "CAM_RESET1",
+ "CAM_STANDBY";
qcom,gpio-set-tbl-num = <1 1>;
qcom,gpio-set-tbl-flags = <0 2>;
qcom,gpio-set-tbl-delay = <1000 30000>;
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-fluid.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-fluid.dtsi
index 748d5f7..9cbd45c 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-fluid.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-fluid.dtsi
@@ -90,11 +90,15 @@
qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
qcom,gpio-no-mux = <0>;
gpios = <&msmgpio 15 0>,
- <&msmgpio 90 0>;
+ <&msmgpio 90 0>,
+ <&msmgpio 89 0>;
qcom,gpio-reset = <1>;
- qcom,gpio-req-tbl-num = <0 1>;
- qcom,gpio-req-tbl-flags = <1 0>;
- qcom,gpio-req-tbl-label = "CAMIF_MCLK", "CAM_RESET1";
+ qcom,gpio-standby = <2>;
+ qcom,gpio-req-tbl-num = <0 1 2>;
+ qcom,gpio-req-tbl-flags = <1 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+ "CAM_RESET1",
+ "CAM_STANDBY";
qcom,gpio-set-tbl-num = <1 1>;
qcom,gpio-set-tbl-flags = <0 2>;
qcom,gpio-set-tbl-delay = <1000 30000>;
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi
index 5a97a11..e9d3d75 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi
@@ -86,11 +86,15 @@
qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
qcom,gpio-no-mux = <0>;
gpios = <&msmgpio 15 0>,
- <&msmgpio 90 0>;
+ <&msmgpio 90 0>,
+ <&msmgpio 89 0>;
qcom,gpio-reset = <1>;
- qcom,gpio-req-tbl-num = <0 1>;
- qcom,gpio-req-tbl-flags = <1 0>;
- qcom,gpio-req-tbl-label = "CAMIF_MCLK", "CAM_RESET1";
+ qcom,gpio-standby = <2>;
+ qcom,gpio-req-tbl-num = <0 1 2>;
+ qcom,gpio-req-tbl-flags = <1 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+ "CAM_RESET1",
+ "CAM_STANDBY";
qcom,gpio-set-tbl-num = <1 1>;
qcom,gpio-set-tbl-flags = <0 2>;
qcom,gpio-set-tbl-delay = <1000 30000>;
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-mtp.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-mtp.dtsi
index 53f6e9e..68af4a6 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-mtp.dtsi
@@ -90,11 +90,15 @@
qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
qcom,gpio-no-mux = <0>;
gpios = <&msmgpio 15 0>,
- <&msmgpio 90 0>;
+ <&msmgpio 90 0>,
+ <&msmgpio 89 0>;
qcom,gpio-reset = <1>;
- qcom,gpio-req-tbl-num = <0 1>;
- qcom,gpio-req-tbl-flags = <1 0>;
- qcom,gpio-req-tbl-label = "CAMIF_MCLK", "CAM_RESET1";
+ qcom,gpio-standby = <2>;
+ qcom,gpio-req-tbl-num = <0 1 2>;
+ qcom,gpio-req-tbl-flags = <1 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+ "CAM_RESET1",
+ "CAM_STANDBY";
qcom,gpio-set-tbl-num = <1 1>;
qcom,gpio-set-tbl-flags = <0 2>;
qcom,gpio-set-tbl-delay = <1000 30000>;
diff --git a/arch/arm/boot/dts/msm8974-cdp.dtsi b/arch/arm/boot/dts/msm8974-cdp.dtsi
index 5fa7c08..3e65b8a 100644
--- a/arch/arm/boot/dts/msm8974-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8974-cdp.dtsi
@@ -247,7 +247,7 @@
<85 512 40000 160000>,
<85 512 40000 320000>,
<85 512 40000 480000>,
- <85 512 40000 640000>;
+ <85 512 40000 800000>;
};
};
diff --git a/arch/arm/configs/mpq8092_defconfig b/arch/arm/configs/mpq8092_defconfig
index 28ca32f..c06161d 100644
--- a/arch/arm/configs/mpq8092_defconfig
+++ b/arch/arm/configs/mpq8092_defconfig
@@ -54,6 +54,7 @@
CONFIG_MSM_RUN_QUEUE_STATS=y
CONFIG_MSM_SPM_V2=y
CONFIG_MSM_L2_SPM=y
+CONFIG_MSM_MULTIMEDIA_USE_ION=y
CONFIG_MSM_OCMEM=y
CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y
CONFIG_MSM_OCMEM_DEBUG=y
@@ -268,6 +269,8 @@
CONFIG_REGULATOR_QPNP=y
CONFIG_MEDIA_SUPPORT=y
CONFIG_MEDIA_CONTROLLER=y
+CONFIG_ION=y
+CONFIG_ION_MSM=y
CONFIG_MSM_KGSL=y
CONFIG_FB=y
CONFIG_FB_MSM=y
@@ -299,6 +302,16 @@
CONFIG_USB_STORAGE_KARMA=y
CONFIG_USB_STORAGE_CYPRESS_ATACB=y
CONFIG_USB_STORAGE_ENE_UB6250=y
+CONFIG_MMC=y
+CONFIG_MMC_PERF_PROFILING=y
+CONFIG_MMC_UNSAFE_RESUME=y
+CONFIG_MMC_CLKGATE=y
+CONFIG_MMC_PARANOID_SD_INIT=y
+CONFIG_MMC_BLOCK_MINORS=32
+# CONFIG_MMC_BLOCK_BOUNCE is not set
+CONFIG_MMC_TEST=m
+CONFIG_MMC_BLOCK_TEST=m
+CONFIG_MMC_MSM=y
CONFIG_LEDS_QPNP=y
CONFIG_LEDS_TRIGGERS=y
CONFIG_LEDS_TRIGGER_BACKLIGHT=y
@@ -319,6 +332,7 @@
CONFIG_QPNP_POWER_ON=y
CONFIG_QPNP_CLKDIV=y
CONFIG_MSM_IOMMU=y
+CONFIG_IOMMU_PGTABLES_L2=y
CONFIG_EXT2_FS=y
CONFIG_EXT2_FS_XATTR=y
CONFIG_EXT3_FS=y
diff --git a/arch/arm/configs/msm7627a-perf_defconfig b/arch/arm/configs/msm7627a-perf_defconfig
index aea092e..ba36df1 100644
--- a/arch/arm/configs/msm7627a-perf_defconfig
+++ b/arch/arm/configs/msm7627a-perf_defconfig
@@ -370,6 +370,7 @@
CONFIG_PRINTK_TIME=y
CONFIG_MAGIC_SYSRQ=y
CONFIG_DEBUG_SHIRQ=y
+CONFIG_SCHEDSTATS=y
CONFIG_TIMER_STATS=y
CONFIG_DEBUG_STACK_USAGE=y
CONFIG_DEBUG_INFO=y
diff --git a/arch/arm/configs/msm8660-perf_defconfig b/arch/arm/configs/msm8660-perf_defconfig
index dda9bd3..5885c6e 100644
--- a/arch/arm/configs/msm8660-perf_defconfig
+++ b/arch/arm/configs/msm8660-perf_defconfig
@@ -428,6 +428,7 @@
CONFIG_NLS_ISO8859_1=y
CONFIG_PRINTK_TIME=y
CONFIG_MAGIC_SYSRQ=y
+CONFIG_SCHEDSTATS=y
CONFIG_TIMER_STATS=y
# CONFIG_DEBUG_PREEMPT is not set
CONFIG_DEBUG_INFO=y
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index f90e5f3..6c18a97 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -510,6 +510,7 @@
CONFIG_NLS_ISO8859_1=y
CONFIG_PRINTK_TIME=y
CONFIG_MAGIC_SYSRQ=y
+CONFIG_SCHEDSTATS=y
CONFIG_TIMER_STATS=y
# CONFIG_DEBUG_PREEMPT is not set
CONFIG_DEBUG_INFO=y
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index bae4ee9..72032dc 100644
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -459,6 +459,7 @@
CONFIG_PRINTK_TIME=y
CONFIG_MAGIC_SYSRQ=y
CONFIG_TIMER_STATS=y
+CONFIG_SCHEDSTATS=y
# CONFIG_DEBUG_PREEMPT is not set
CONFIG_DEBUG_INFO=y
CONFIG_DEBUG_MEMORY_INIT=y
diff --git a/arch/arm/configs/msm9625-perf_defconfig b/arch/arm/configs/msm9625-perf_defconfig
index 662d555..f434199 100644
--- a/arch/arm/configs/msm9625-perf_defconfig
+++ b/arch/arm/configs/msm9625-perf_defconfig
@@ -258,6 +258,7 @@
CONFIG_USB_STORAGE_CYPRESS_ATACB=y
CONFIG_USB_EHSET_TEST_FIXTURE=y
CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_DEBUG_FILES=y
CONFIG_USB_CI13XXX_MSM=y
CONFIG_USB_G_ANDROID=y
CONFIG_MMC=y
diff --git a/arch/arm/configs/msm9625_defconfig b/arch/arm/configs/msm9625_defconfig
index 7891990..2a1215d 100644
--- a/arch/arm/configs/msm9625_defconfig
+++ b/arch/arm/configs/msm9625_defconfig
@@ -258,6 +258,7 @@
CONFIG_USB_STORAGE_CYPRESS_ATACB=y
CONFIG_USB_EHSET_TEST_FIXTURE=y
CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_DEBUG_FILES=y
CONFIG_USB_CI13XXX_MSM=y
CONFIG_USB_G_ANDROID=y
CONFIG_MMC=y
@@ -319,8 +320,8 @@
CONFIG_CRYPTO_DES=y
CONFIG_CRYPTO_TWOFISH=y
CONFIG_CRYPTO_DEFLATE=y
-CONFIG_CRYPTO_DEV_QCRYPTO=m
-CONFIG_CRYPTO_DEV_QCE=m
-CONFIG_CRYPTO_DEV_QCEDEV=m
+#CONFIG_CRYPTO_DEV_QCRYPTO is not set
+#CONFIG_CRYPTO_DEV_QCE is not set
+#CONFIG_CRYPTO_DEV_QCEDEV is not set
CONFIG_CRC_CCITT=y
CONFIG_LIBCRC32C=y
diff --git a/arch/arm/include/asm/setup.h b/arch/arm/include/asm/setup.h
index 2a46914..07a09b5 100644
--- a/arch/arm/include/asm/setup.h
+++ b/arch/arm/include/asm/setup.h
@@ -196,7 +196,7 @@
struct membank {
phys_addr_t start;
- unsigned long size;
+ phys_addr_t size;
unsigned int highmem;
};
@@ -218,7 +218,7 @@
#define bank_phys_end(bank) ((bank)->start + (bank)->size)
#define bank_phys_size(bank) (bank)->size
-extern int arm_add_memory(phys_addr_t start, unsigned long size);
+extern int arm_add_memory(phys_addr_t start, phys_addr_t size);
extern void early_print(const char *str, ...);
extern void dump_machine_table(void);
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index 4aabf0e..28b114f 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -510,7 +510,7 @@
/* can't use cpu_relax() here as it may require MMU setup */;
}
-int __init arm_add_memory(phys_addr_t start, unsigned long size)
+int __init arm_add_memory(phys_addr_t start, phys_addr_t size)
{
struct membank *bank = &meminfo.bank[meminfo.nr_banks];
@@ -540,7 +540,7 @@
}
#endif
- bank->size = size & PAGE_MASK;
+ bank->size = size & ~(phys_addr_t)(PAGE_SIZE - 1);
/*
* Check whether this memory region has non-zero size or
@@ -560,7 +560,7 @@
static int __init early_mem(char *p)
{
static int usermem __initdata = 0;
- unsigned long size;
+ phys_addr_t size;
phys_addr_t start;
char *endp;
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 0eecffd..be0daf3 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -145,7 +145,7 @@
select CPU_V7
select GPIO_MSM_V2
select MSM_GPIOMUX
- select MSM_SCM if SMP
+ select MSM_SCM
select MSM_DIRECT_SCLK_ACCESS
select REGULATOR
select MSM_RPM_REGULATOR
@@ -187,7 +187,7 @@
select CPU_V7
select GPIO_MSM_V2
select MSM_GPIOMUX
- select MSM_SCM if SMP
+ select MSM_SCM
select MSM_DIRECT_SCLK_ACCESS
select REGULATOR
select MSM_RPM_REGULATOR
@@ -223,7 +223,7 @@
select GPIO_MSM_V2
select ARM_GIC
select CPU_V7
- select MSM_SCM if SMP
+ select MSM_SCM
select MSM_GPIOMUX
select MSM_REMOTE_SPINLOCK_SFPB
select MSM_PIL
@@ -257,7 +257,7 @@
select GPIO_MSM_V3
select ARM_GIC
select CPU_V7
- select MSM_SCM if SMP
+ select MSM_SCM
select MSM_GPIOMUX
select MULTI_IRQ_HANDLER
select MSM_MULTIMEDIA_USE_ION
@@ -292,7 +292,7 @@
select GPIO_MSM_V3
select ARM_GIC
select CPU_V7
- select MSM_SCM if SMP
+ select MSM_SCM
select MSM_GPIOMUX
select MULTI_IRQ_HANDLER
select MSM_NATIVE_RESTART
@@ -317,6 +317,25 @@
select SPARSE_IRQ
select MSM_NOPM
+config ARCH_FSM9900
+ bool "FSM9900"
+ select ARCH_MSM_KRAITMP
+ select GPIO_MSM_V3
+ select ARM_GIC
+ select CPU_V7
+ select MSM_SCM
+ select MSM_GPIOMUX
+ select MULTI_IRQ_HANDLER
+ select MSM_PIL
+ select MSM_NATIVE_RESTART
+ select MSM_RESTART_V2
+ select MAY_HAVE_SPARSE_IRQ
+ select SPARSE_IRQ
+ select REGULATOR
+ select ARM_HAS_SG_CHAIN
+ select MSM_RUN_QUEUE_STATS
+ select MSM_NOPM
+
config ARCH_FSM9XXX
bool "FSM9XXX"
select ARCH_MSM_SCORPION
@@ -378,7 +397,6 @@
select MSM_RESTART_V2
select MSM_SPM_V2
select MSM_PM8X60 if PM
- select MSM_SCM if SMP
select MULTI_IRQ_HANDLER
select GPIO_MSM_V3
select MAY_HAVE_SPARSE_IRQ
@@ -414,7 +432,7 @@
select GIC_SECURE
select ARCH_MSM_CORTEXMP
select CPU_V7
- select MSM_SCM if SMP
+ select MSM_SCM
select MAY_HAVE_SPARSE_IRQ
select SPARSE_IRQ
select MULTI_IRQ_HANDLER
@@ -456,7 +474,7 @@
select GIC_SECURE
select ARCH_MSM_CORTEXMP
select CPU_V7
- select MSM_SCM if SMP
+ select MSM_SCM
select MAY_HAVE_SPARSE_IRQ
select SPARSE_IRQ
select MULTI_IRQ_HANDLER
@@ -1094,6 +1112,7 @@
default "0x00000000" if ARCH_MSM8226
default "0x00000000" if ARCH_MSM8610
default "0x10000000" if ARCH_FSM9XXX
+ default "0x00000000" if ARCH_FSM9900
default "0x00200000" if ARCH_MSM9625
default "0x00000000" if ARCH_MSMKRYPTON
default "0x00200000" if !MSM_STACKED_MEMORY
@@ -1257,6 +1276,14 @@
help
Say Y here if you want the debug print routines to direct
their output to the serial port on MSM9625 devices.
+
+ config DEBUG_FSM9900_UART
+ bool "Kernel low-level debugging messages via FSM9900 UART"
+ depends on ARCH_FSM9900
+ select MSM_HAS_DEBUG_UART_HS_V14
+ help
+ Say Y here if you want the debug print routines to direct
+ their output to the serial port on FSM9900 devices.
endchoice
choice
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 321040e..f53b7fe 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -75,7 +75,7 @@
$(obj)/smd_rpc_sym.c: $(src)/smd_rpc_sym $(src)/mkrpcsym.pl
$(call if_changed,mkrpcsym)
-obj-$(CONFIG_MSM_SMD) += smd.o smd_debug.o remote_spinlock.o smd_private.o
+obj-$(CONFIG_MSM_SMD) += smd.o smd_debug.o remote_spinlock.o smd_private.o smem.o
obj-$(CONFIG_MSM_SMP2P) += smp2p.o smp2p_debug.o smp2p_gpio.o
obj-$(CONFIG_MSM_SMP2P_TEST) += smp2p_loopback.o smp2p_test.o smp2p_gpio_test.o smp2p_spinlock_test.o
obj-$(CONFIG_MSM_SCM) += scm.o scm-boot.o
@@ -121,6 +121,7 @@
ifndef CONFIG_ARCH_MSM8610
ifndef CONFIG_ARCH_APQ8084
ifndef CONFIG_ARCH_MSMKRYPTON
+ifndef CONFIG_ARCH_FSM9900
obj-y += nand_partitions.o
endif
endif
@@ -132,6 +133,7 @@
endif
endif
endif
+endif
obj-$(CONFIG_MSM_SDIO_TTY) += sdio_tty.o
obj-$(CONFIG_MSM_SMD_TTY) += smd_tty.o
obj-$(CONFIG_MSM_SMD_QMI) += smd_qmi.o
@@ -230,6 +232,7 @@
obj-$(CONFIG_ARCH_FSM9XXX) += clock-fsm9xxx.o clock-local.o acpuclock-fsm9xxx.o
obj-$(CONFIG_ARCH_FSM9XXX) += dfe-fsm9xxx.o rfic-fsm9xxx.o
obj-$(CONFIG_ARCH_FSM9XXX) += restart-fsm9xxx.o xo-fsm9xxx.o
+obj-$(CONFIG_ARCH_FSM9900) += board-fsm9900.o board-fsm9900-gpiomux.o
obj-$(CONFIG_MSM_WATCHDOG) += msm_watchdog.o
obj-$(CONFIG_MSM_WATCHDOG) += msm_watchdog_asm.o
@@ -377,6 +380,7 @@
obj-$(CONFIG_ARCH_MSM8226) += gpiomux-v2.o gpiomux.o
obj-$(CONFIG_ARCH_MSM8610) += gpiomux-v2.o gpiomux.o
obj-$(CONFIG_ARCH_APQ8084) += gpiomux-v2.o gpiomux.o
+obj-$(CONFIG_ARCH_FSM9900) += gpiomux-v2.o gpiomux.o
obj-$(CONFIG_MSM_SLEEP_STATS_DEVICE) += idle_stats_device.o
obj-$(CONFIG_MSM_DCVS) += msm_dcvs_scm.o msm_dcvs.o msm_mpdecision.o
diff --git a/arch/arm/mach-msm/Makefile.boot b/arch/arm/mach-msm/Makefile.boot
index 2827e65..07969e0 100644
--- a/arch/arm/mach-msm/Makefile.boot
+++ b/arch/arm/mach-msm/Makefile.boot
@@ -93,6 +93,11 @@
params_phys-$(CONFIG_ARCH_FSM9XXX) := 0x10000100
initrd_phys-$(CONFIG_ARCH_FSM9XXX) := 0x12000000
+# FSM9900
+ zreladdr-$(CONFIG_ARCH_FSM9900) := 0x00008000
+ dtb-$(CONFIG_ARCH_FSM9900) := fsm9900-rumi.dtb
+ dtb-$(CONFIG_ARCH_FSM9900) := fsm9900-sim.dtb
+
# MPQ8092
zreladdr-$(CONFIG_ARCH_MPQ8092) := 0x00008000
diff --git a/arch/arm/mach-msm/board-8092.c b/arch/arm/mach-msm/board-8092.c
index 6adff30..cd95bf3 100644
--- a/arch/arm/mach-msm/board-8092.c
+++ b/arch/arm/mach-msm/board-8092.c
@@ -38,6 +38,11 @@
static struct clk_lookup msm_clocks_dummy[] = {
CLK_DUMMY("core_clk", BLSP1_UART_CLK, "msm_serial_hsl.0", OFF),
CLK_DUMMY("iface_clk", BLSP1_UART_CLK, "msm_serial_hsl.0", OFF),
+ CLK_DUMMY("core_clk", SDC1_CLK, "msm_sdcc.1", OFF),
+ CLK_DUMMY("iface_clk", SDC1_P_CLK, "msm_sdcc.1", OFF),
+ CLK_DUMMY("core_clk", SDC2_CLK, "msm_sdcc.2", OFF),
+ CLK_DUMMY("iface_clk", SDC2_P_CLK, "msm_sdcc.2", OFF),
+
};
struct clock_init_data mpq8092_clock_init_data __initdata = {
diff --git a/arch/arm/mach-msm/board-fsm9900-gpiomux.c b/arch/arm/mach-msm/board-fsm9900-gpiomux.c
new file mode 100644
index 0000000..dede706
--- /dev/null
+++ b/arch/arm/mach-msm/board-fsm9900-gpiomux.c
@@ -0,0 +1,29 @@
+/* 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/gpio.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <mach/board.h>
+#include <mach/gpiomux.h>
+
+void __init fsm9900_init_gpiomux(void)
+{
+ int rc;
+
+ rc = msm_gpiomux_init_dt();
+ if (rc) {
+ pr_err("%s failed %d\n", __func__, rc);
+ return;
+ }
+}
diff --git a/arch/arm/mach-msm/board-fsm9900.c b/arch/arm/mach-msm/board-fsm9900.c
new file mode 100644
index 0000000..7177355
--- /dev/null
+++ b/arch/arm/mach-msm/board-fsm9900.c
@@ -0,0 +1,102 @@
+/* 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/err.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/memory.h>
+#include <asm/hardware/gic.h>
+#include <asm/mach/map.h>
+#include <asm/mach/arch.h>
+#include <mach/board.h>
+#include <mach/gpiomux.h>
+#include <mach/msm_iomap.h>
+#include <mach/msm_smd.h>
+#include <mach/restart.h>
+#include <mach/socinfo.h>
+#include <mach/clk-provider.h>
+#include "board-dt.h"
+#include "clock.h"
+#include "devices.h"
+#include "platsmp.h"
+
+void __init fsm9900_reserve(void)
+{
+}
+
+static void __init fsm9900_early_memory(void)
+{
+}
+
+static struct clk_lookup msm_clocks_dummy[] = {
+ CLK_DUMMY("core_clk", BLSP2_UART_CLK, "f9960000.serial", OFF),
+ CLK_DUMMY("iface_clk", BLSP2_UART_CLK, "f9960000.serial", OFF),
+ CLK_DUMMY("core_clk", BLSP1_UART_CLK, "f991f000.serial", OFF),
+ CLK_DUMMY("iface_clk", BLSP1_UART_CLK, "f991f000.serial", OFF),
+};
+
+static struct clock_init_data msm_dummy_clock_init_data __initdata = {
+ .table = msm_clocks_dummy,
+ .size = ARRAY_SIZE(msm_clocks_dummy),
+};
+
+/*
+ * Used to satisfy dependencies for devices that need to be
+ * run early or in a particular order. Most likely your device doesn't fall
+ * into this category, and thus the driver should not be added here. The
+ * EPROBE_DEFER can satisfy most dependency problems.
+ */
+void __init fsm9900_add_drivers(void)
+{
+ msm_smd_init();
+ msm_clock_init(&msm_dummy_clock_init_data);
+}
+
+static void __init fsm9900_map_io(void)
+{
+ msm_map_fsm9900_io();
+}
+
+void __init fsm9900_init(void)
+{
+ if (socinfo_init() < 0)
+ pr_err("%s: socinfo_init() failed\n", __func__);
+
+ fsm9900_init_gpiomux();
+ board_dt_populate(NULL);
+ fsm9900_add_drivers();
+}
+
+void __init fsm9900_init_very_early(void)
+{
+ fsm9900_early_memory();
+}
+
+static const char *fsm9900_dt_match[] __initconst = {
+ "qcom,fsm9900",
+ NULL
+};
+
+DT_MACHINE_START(FSM9900_DT, "Qualcomm FSM 9900 (Flattened Device Tree)")
+ .map_io = fsm9900_map_io,
+ .init_irq = msm_dt_init_irq,
+ .init_machine = fsm9900_init,
+ .handle_irq = gic_handle_irq,
+ .timer = &msm_dt_timer,
+ .dt_compat = fsm9900_dt_match,
+ .reserve = fsm9900_reserve,
+ .init_very_early = fsm9900_init_very_early,
+ .restart = msm_restart,
+ .smp = &msm8974_smp_ops,
+MACHINE_END
diff --git a/arch/arm/mach-msm/clock-8226.c b/arch/arm/mach-msm/clock-8226.c
index ac5efc1..7fe3f97 100644
--- a/arch/arm/mach-msm/clock-8226.c
+++ b/arch/arm/mach-msm/clock-8226.c
@@ -3327,31 +3327,40 @@
"fda0b000.qcom,csiphy"),
/* CSID clocks */
- CLK_LOOKUP("camss_top_ahb_clk", camss_top_ahb_clk.c,
- "fda08000.qcom,csid"),
CLK_LOOKUP("ispif_ahb_clk", camss_ispif_ahb_clk.c,
- "fda08000.qcom,csid"),
- CLK_LOOKUP("csi0_ahb_clk", camss_csi0_ahb_clk.c, "fda08000.qcom,csid"),
- CLK_LOOKUP("csi0_src_clk", csi0_clk_src.c, "fda08000.qcom,csid"),
- CLK_LOOKUP("csi0_phy_clk", camss_csi0phy_clk.c, "fda08000.qcom,csid"),
- CLK_LOOKUP("csi0_clk", camss_csi0_clk.c, "fda08000.qcom,csid"),
- CLK_LOOKUP("csi0_pix_clk", camss_csi0pix_clk.c, "fda08000.qcom,csid"),
- CLK_LOOKUP("csi0_rdi_clk", camss_csi0rdi_clk.c, "fda08000.qcom,csid"),
+ "fda08000.qcom,csid"),
+ CLK_LOOKUP("camss_top_ahb_clk", camss_top_ahb_clk.c,
+ "fda08000.qcom,csid"),
+ CLK_LOOKUP("csi_ahb_clk", camss_csi0_ahb_clk.c,
+ "fda08000.qcom,csid"),
+ CLK_LOOKUP("csi_src_clk", csi0_clk_src.c,
+ "fda08000.qcom,csid"),
+ CLK_LOOKUP("csi_phy_clk", camss_csi0phy_clk.c,
+ "fda08000.qcom,csid"),
+ CLK_LOOKUP("csi_clk", camss_csi0_clk.c,
+ "fda08000.qcom,csid"),
+ CLK_LOOKUP("csi_pix_clk", camss_csi0pix_clk.c,
+ "fda08000.qcom,csid"),
+ CLK_LOOKUP("csi_rdi_clk", camss_csi0rdi_clk.c,
+ "fda08000.qcom,csid"),
- CLK_LOOKUP("camss_top_ahb_clk", camss_top_ahb_clk.c,
- "fda08400.qcom,csid"),
+
CLK_LOOKUP("ispif_ahb_clk", camss_ispif_ahb_clk.c,
- "fda08400.qcom,csid"),
- CLK_LOOKUP("csi0_ahb_clk", camss_csi0_ahb_clk.c, "fda08400.qcom,csid"),
- CLK_LOOKUP("csi1_ahb_clk", camss_csi1_ahb_clk.c, "fda08400.qcom,csid"),
- CLK_LOOKUP("csi0_src_clk", csi0_clk_src.c, "fda08400.qcom,csid"),
- CLK_LOOKUP("csi1_src_clk", csi1_clk_src.c, "fda08400.qcom,csid"),
- CLK_LOOKUP("csi0_phy_clk", camss_csi0phy_clk.c, "fda08400.qcom,csid"),
- CLK_LOOKUP("csi1_phy_clk", camss_csi1phy_clk.c, "fda08400.qcom,csid"),
- CLK_LOOKUP("csi0_pix_clk", camss_csi0pix_clk.c, "fda08400.qcom,csid"),
- CLK_LOOKUP("csi1_pix_clk", camss_csi1pix_clk.c, "fda08400.qcom,csid"),
- CLK_LOOKUP("csi0_rdi_clk", camss_csi0rdi_clk.c, "fda08400.qcom,csid"),
- CLK_LOOKUP("csi1_rdi_clk", camss_csi1rdi_clk.c, "fda08400.qcom,csid"),
+ "fda08400.qcom,csid"),
+ CLK_LOOKUP("camss_top_ahb_clk", camss_top_ahb_clk.c,
+ "fda08400.qcom,csid"),
+ CLK_LOOKUP("csi_ahb_clk", camss_csi1_ahb_clk.c,
+ "fda08400.qcom,csid"),
+ CLK_LOOKUP("csi_src_clk", csi1_clk_src.c,
+ "fda08400.qcom,csid"),
+ CLK_LOOKUP("csi_phy_clk", camss_csi1phy_clk.c,
+ "fda08400.qcom,csid"),
+ CLK_LOOKUP("csi_clk", camss_csi1_clk.c,
+ "fda08400.qcom,csid"),
+ CLK_LOOKUP("csi_pix_clk", camss_csi1pix_clk.c,
+ "fda08400.qcom,csid"),
+ CLK_LOOKUP("csi_rdi_clk", camss_csi1rdi_clk.c,
+ "fda08400.qcom,csid"),
/* ISPIF clocks */
CLK_LOOKUP("ispif_ahb_clk", camss_ispif_ahb_clk.c,
diff --git a/arch/arm/mach-msm/clock-8610.c b/arch/arm/mach-msm/clock-8610.c
index aa9368d..17468d2 100644
--- a/arch/arm/mach-msm/clock-8610.c
+++ b/arch/arm/mach-msm/clock-8610.c
@@ -2819,6 +2819,7 @@
CLK_LOOKUP("core_clk", qdss_clk.c, "fc34d000.jtagmm"),
CLK_LOOKUP("core_clk", qdss_clk.c, "fc34e000.jtagmm"),
CLK_LOOKUP("core_clk", qdss_clk.c, "fc34f000.jtagmm"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fd820018.hwevent"),
CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc326000.tmc"),
@@ -2852,8 +2853,9 @@
CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc34d000.jtagmm"),
CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc34e000.jtagmm"),
CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc34f000.jtagmm"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fd820018.hwevent"),
-
+ CLK_LOOKUP("core_mmss_clk", mmss_misc_ahb_clk.c, "fd820018.hwevent"),
CLK_LOOKUP("core_clk_src", blsp1_qup1_spi_apps_clk_src.c, ""),
CLK_LOOKUP("core_clk_src", blsp1_qup2_spi_apps_clk_src.c, ""),
diff --git a/arch/arm/mach-msm/clock-mdss-8974.c b/arch/arm/mach-msm/clock-mdss-8974.c
index bf95615..17a6801 100644
--- a/arch/arm/mach-msm/clock-mdss-8974.c
+++ b/arch/arm/mach-msm/clock-mdss-8974.c
@@ -409,9 +409,9 @@
static enum handoff mdss_dsi_pll_byte_handoff(struct clk *c)
{
if (mdss_gdsc_enabled() && mdss_dsi_check_pll_lock()) {
- c->rate = 53000000;
- dsi_pll_rate = 53000000;
- pll_byte_clk_rate = 53000000;
+ c->rate = 52954560;
+ dsi_pll_rate = 52954560;
+ pll_byte_clk_rate = 52954560;
pll_pclk_rate = 105000000;
dsipll_refcount++;
return HANDOFF_ENABLED_CLK;
diff --git a/arch/arm/mach-msm/clock-pll.c b/arch/arm/mach-msm/clock-pll.c
index d2be1f9..8d99ad1 100644
--- a/arch/arm/mach-msm/clock-pll.c
+++ b/arch/arm/mach-msm/clock-pll.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
@@ -19,10 +19,10 @@
#include <mach/scm-io.h>
#include <mach/msm_iomap.h>
+#include <mach/msm_smem.h>
#include "clock.h"
#include "clock-pll.h"
-#include "smd_private.h"
#ifdef CONFIG_MSM_SECURE_IO
#undef readl_relaxed
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index 22f74c8..690e52a 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -599,6 +599,8 @@
void msm_map_apq8064_io(void);
void msm_map_msm7x30_io(void);
void msm_map_fsm9xxx_io(void);
+void msm_map_fsm9900_io(void);
+void fsm9900_init_gpiomux(void);
void msm_map_8974_io(void);
void msm_map_8084_io(void);
void msm_map_msmkrypton_io(void);
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-fsm9900.h b/arch/arm/mach-msm/include/mach/msm_iomap-fsm9900.h
new file mode 100644
index 0000000..02b8917
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-fsm9900.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * 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.
+ */
+
+#ifndef __ASM_ARCH_MSM_IOMAP_FSM9900_H
+#define __ASM_ARCH_MSM_IOMAP_FSM9900_H
+
+/* Physical base address and size of peripherals.
+ * Ordered by the virtual base addresses they will be mapped at.
+ *
+ * If you add or remove entries here, you'll want to edit the
+ * io desc array in arch/arm/mach-msm/io.c to reflect your
+ * changes.
+ *
+ */
+
+#define FSM9900_SHARED_RAM_PHYS 0x98000000
+
+#define FSM9900_QGIC_DIST_PHYS 0xF9000000
+#define FSM9900_QGIC_DIST_SIZE SZ_4K
+
+#define FSM9900_TLMM_PHYS 0xFD510000
+#define FSM9900_TLMM_SIZE SZ_16K
+
+#ifdef CONFIG_DEBUG_FSM9900_UART
+#define MSM_DEBUG_UART_BASE IOMEM(0xFA71E000)
+#define MSM_DEBUG_UART_PHYS 0xF9960000
+#endif
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap.h b/arch/arm/mach-msm/include/mach/msm_iomap.h
index 8f48e94..185958c 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap.h
@@ -136,7 +136,7 @@
#include "msm_iomap-8226.h"
#include "msm_iomap-8610.h"
#include "msm_iomap-krypton.h"
-
+#include "msm_iomap-fsm9900.h"
#endif
#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_smd.h b/arch/arm/mach-msm/include/mach/msm_smd.h
index d155c6f..2cc7b10 100644
--- a/arch/arm/mach-msm/include/mach/msm_smd.h
+++ b/arch/arm/mach-msm/include/mach/msm_smd.h
@@ -19,7 +19,9 @@
#define __ASM_ARCH_MSM_SMD_H
#include <linux/io.h>
-#include <mach/msm_smsm.h>
+#include <linux/notifier.h>
+
+#include <mach/msm_smem.h>
typedef struct smd_channel smd_channel_t;
@@ -40,13 +42,13 @@
* SMD, the entry will only exist in this enum.
*/
enum {
- SMD_APPS = SMSM_APPS,
- SMD_MODEM = SMSM_MODEM,
- SMD_Q6 = SMSM_Q6,
- SMD_WCNSS = SMSM_WCNSS,
- SMD_DSPS = SMSM_DSPS,
- SMD_MODEM_Q6_FW,
- SMD_RPM,
+ SMD_APPS = SMEM_APPS,
+ SMD_MODEM = SMEM_MODEM,
+ SMD_Q6 = SMEM_Q6,
+ SMD_DSPS = SMEM_DSPS,
+ SMD_WCNSS = SMEM_WCNSS,
+ SMD_MODEM_Q6_FW = SMEM_MODEM_Q6_FW,
+ SMD_RPM = SMEM_RPM,
NUM_SMD_SUBSYSTEMS,
};
diff --git a/arch/arm/mach-msm/include/mach/msm_smem.h b/arch/arm/mach-msm/include/mach/msm_smem.h
new file mode 100644
index 0000000..57f22cc
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_smem.h
@@ -0,0 +1,180 @@
+/* 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 _ARCH_ARM_MACH_MSM_SMEM_H_
+#define _ARCH_ARM_MACH_MSM_SMEM_H_
+
+#include <linux/types.h>
+
+enum {
+ SMEM_APPS,
+ SMEM_MODEM,
+ SMEM_Q6,
+ SMEM_DSPS,
+ SMEM_WCNSS,
+ SMEM_MODEM_Q6_FW,
+ SMEM_RPM,
+ NUM_SMEM_SUBSYSTEMS,
+};
+
+#define SMEM_NUM_SMD_STREAM_CHANNELS 64
+#define SMEM_NUM_SMD_BLOCK_CHANNELS 64
+
+enum {
+ /* fixed items */
+ SMEM_PROC_COMM = 0,
+ SMEM_HEAP_INFO,
+ SMEM_ALLOCATION_TABLE,
+ SMEM_VERSION_INFO,
+ SMEM_HW_RESET_DETECT,
+ SMEM_AARM_WARM_BOOT,
+ SMEM_DIAG_ERR_MESSAGE,
+ SMEM_SPINLOCK_ARRAY,
+ SMEM_MEMORY_BARRIER_LOCATION,
+ SMEM_FIXED_ITEM_LAST = SMEM_MEMORY_BARRIER_LOCATION,
+
+ /* dynamic items */
+ SMEM_AARM_PARTITION_TABLE,
+ SMEM_AARM_BAD_BLOCK_TABLE,
+ SMEM_RESERVE_BAD_BLOCKS,
+ SMEM_WM_UUID,
+ SMEM_CHANNEL_ALLOC_TBL,
+ SMEM_SMD_BASE_ID,
+ SMEM_SMEM_LOG_IDX = SMEM_SMD_BASE_ID + SMEM_NUM_SMD_STREAM_CHANNELS,
+ SMEM_SMEM_LOG_EVENTS,
+ SMEM_SMEM_STATIC_LOG_IDX,
+ SMEM_SMEM_STATIC_LOG_EVENTS,
+ SMEM_SMEM_SLOW_CLOCK_SYNC,
+ SMEM_SMEM_SLOW_CLOCK_VALUE,
+ SMEM_BIO_LED_BUF,
+ SMEM_SMSM_SHARED_STATE,
+ SMEM_SMSM_INT_INFO,
+ SMEM_SMSM_SLEEP_DELAY,
+ SMEM_SMSM_LIMIT_SLEEP,
+ SMEM_SLEEP_POWER_COLLAPSE_DISABLED,
+ SMEM_KEYPAD_KEYS_PRESSED,
+ SMEM_KEYPAD_STATE_UPDATED,
+ SMEM_KEYPAD_STATE_IDX,
+ SMEM_GPIO_INT,
+ SMEM_MDDI_LCD_IDX,
+ SMEM_MDDI_HOST_DRIVER_STATE,
+ SMEM_MDDI_LCD_DISP_STATE,
+ SMEM_LCD_CUR_PANEL,
+ SMEM_MARM_BOOT_SEGMENT_INFO,
+ SMEM_AARM_BOOT_SEGMENT_INFO,
+ SMEM_SLEEP_STATIC,
+ SMEM_SCORPION_FREQUENCY,
+ SMEM_SMD_PROFILES,
+ SMEM_TSSC_BUSY,
+ SMEM_HS_SUSPEND_FILTER_INFO,
+ SMEM_BATT_INFO,
+ SMEM_APPS_BOOT_MODE,
+ SMEM_VERSION_FIRST,
+ SMEM_VERSION_SMD = SMEM_VERSION_FIRST,
+ SMEM_VERSION_LAST = SMEM_VERSION_FIRST + 24,
+ SMEM_OSS_RRCASN1_BUF1,
+ SMEM_OSS_RRCASN1_BUF2,
+ SMEM_ID_VENDOR0,
+ SMEM_ID_VENDOR1,
+ SMEM_ID_VENDOR2,
+ SMEM_HW_SW_BUILD_ID,
+ SMEM_SMD_BLOCK_PORT_BASE_ID,
+ SMEM_SMD_BLOCK_PORT_PROC0_HEAP = SMEM_SMD_BLOCK_PORT_BASE_ID +
+ SMEM_NUM_SMD_BLOCK_CHANNELS,
+ SMEM_SMD_BLOCK_PORT_PROC1_HEAP = SMEM_SMD_BLOCK_PORT_PROC0_HEAP +
+ SMEM_NUM_SMD_BLOCK_CHANNELS,
+ SMEM_I2C_MUTEX = SMEM_SMD_BLOCK_PORT_PROC1_HEAP +
+ SMEM_NUM_SMD_BLOCK_CHANNELS,
+ SMEM_SCLK_CONVERSION,
+ SMEM_SMD_SMSM_INTR_MUX,
+ SMEM_SMSM_CPU_INTR_MASK,
+ SMEM_APPS_DEM_SLAVE_DATA,
+ SMEM_QDSP6_DEM_SLAVE_DATA,
+ SMEM_CLKREGIM_BSP,
+ SMEM_CLKREGIM_SOURCES,
+ SMEM_SMD_FIFO_BASE_ID,
+ SMEM_USABLE_RAM_PARTITION_TABLE = SMEM_SMD_FIFO_BASE_ID +
+ SMEM_NUM_SMD_STREAM_CHANNELS,
+ SMEM_POWER_ON_STATUS_INFO,
+ SMEM_DAL_AREA,
+ SMEM_SMEM_LOG_POWER_IDX,
+ SMEM_SMEM_LOG_POWER_WRAP,
+ SMEM_SMEM_LOG_POWER_EVENTS,
+ SMEM_ERR_CRASH_LOG,
+ SMEM_ERR_F3_TRACE_LOG,
+ SMEM_SMD_BRIDGE_ALLOC_TABLE,
+ SMEM_SMDLITE_TABLE,
+ SMEM_SD_IMG_UPGRADE_STATUS,
+ SMEM_SEFS_INFO,
+ SMEM_RESET_LOG,
+ SMEM_RESET_LOG_SYMBOLS,
+ SMEM_MODEM_SW_BUILD_ID,
+ SMEM_SMEM_LOG_MPROC_WRAP,
+ SMEM_BOOT_INFO_FOR_APPS,
+ SMEM_SMSM_SIZE_INFO,
+ SMEM_SMD_LOOPBACK_REGISTER,
+ SMEM_SSR_REASON_MSS0,
+ SMEM_SSR_REASON_WCNSS0,
+ SMEM_SSR_REASON_LPASS0,
+ SMEM_SSR_REASON_DSPS0,
+ SMEM_SSR_REASON_VCODEC0,
+ SMEM_SMP2P_APPS_BASE = 427,
+ SMEM_SMP2P_MODEM_BASE = SMEM_SMP2P_APPS_BASE + 8, /* 435 */
+ SMEM_SMP2P_AUDIO_BASE = SMEM_SMP2P_MODEM_BASE + 8, /* 443 */
+ SMEM_SMP2P_WIRLESS_BASE = SMEM_SMP2P_AUDIO_BASE + 8, /* 451 */
+ SMEM_SMP2P_POWER_BASE = SMEM_SMP2P_WIRLESS_BASE + 8, /* 459 */
+ SMEM_FLASH_DEVICE_INFO = SMEM_SMP2P_POWER_BASE + 8, /* 467 */
+ SMEM_BAM_PIPE_MEMORY, /* 468 */
+ SMEM_IMAGE_VERSION_TABLE, /* 469 */
+ SMEM_LC_DEBUGGER, /* 470 */
+ SMEM_NUM_ITEMS,
+};
+
+#ifdef CONFIG_MSM_SMD
+void *smem_alloc(unsigned id, unsigned size);
+void *smem_alloc2(unsigned id, unsigned size_in);
+void *smem_get_entry(unsigned id, unsigned *size);
+void *smem_find(unsigned id, unsigned size);
+/**
+ * smem_virt_to_phys() - Convert SMEM address to physical address.
+ *
+ * @smem_address: Virtual address returned by smem_alloc()/smem_alloc2()
+ * @returns: Physical address (or NULL if there is a failure)
+ *
+ * This function should only be used if an SMEM item needs to be handed
+ * off to a DMA engine.
+ */
+phys_addr_t smem_virt_to_phys(void *smem_address);
+
+#else
+static inline void *smem_alloc(unsigned id, unsigned size)
+{
+ return NULL;
+}
+static inline void *smem_alloc2(unsigned id, unsigned size_in)
+{
+ return NULL;
+}
+static inline void *smem_get_entry(unsigned id, unsigned *size)
+{
+ return NULL;
+}
+static inline void *smem_find(unsigned id, unsigned size)
+{
+ return NULL;
+}
+static inline phys_addr_t smem_virt_to_phys(void *smem_address)
+{
+ return (phys_addr_t) NULL;
+}
+#endif /* CONFIG_MSM_SMD */
+#endif /* _ARCH_ARM_MACH_MSM_SMEM_H_ */
diff --git a/arch/arm/mach-msm/include/mach/msm_smsm.h b/arch/arm/mach-msm/include/mach/msm_smsm.h
index 81a6399..733f5a9 100644
--- a/arch/arm/mach-msm/include/mach/msm_smsm.h
+++ b/arch/arm/mach-msm/include/mach/msm_smsm.h
@@ -14,6 +14,9 @@
#define _ARCH_ARM_MACH_MSM_SMSM_H_
#include <linux/notifier.h>
+
+#include <mach/msm_smem.h>
+
#if defined(CONFIG_MSM_N_WAY_SMSM)
enum {
SMSM_APPS_STATE,
@@ -37,11 +40,11 @@
#endif
enum {
- SMSM_APPS,
- SMSM_MODEM,
- SMSM_Q6,
- SMSM_WCNSS,
- SMSM_DSPS,
+ SMSM_APPS = SMEM_APPS,
+ SMSM_MODEM = SMEM_MODEM,
+ SMSM_Q6 = SMEM_Q6,
+ SMSM_DSPS = SMEM_DSPS,
+ SMSM_WCNSS = SMEM_WCNSS,
};
extern uint32_t SMSM_NUM_HOSTS;
@@ -97,119 +100,6 @@
#define SMSM_SUBSYS2AP_STATUS 0x00008000
-#define SMEM_NUM_SMD_STREAM_CHANNELS 64
-#define SMEM_NUM_SMD_BLOCK_CHANNELS 64
-
-enum {
- /* fixed items */
- SMEM_PROC_COMM = 0,
- SMEM_HEAP_INFO,
- SMEM_ALLOCATION_TABLE,
- SMEM_VERSION_INFO,
- SMEM_HW_RESET_DETECT,
- SMEM_AARM_WARM_BOOT,
- SMEM_DIAG_ERR_MESSAGE,
- SMEM_SPINLOCK_ARRAY,
- SMEM_MEMORY_BARRIER_LOCATION,
- SMEM_FIXED_ITEM_LAST = SMEM_MEMORY_BARRIER_LOCATION,
-
- /* dynamic items */
- SMEM_AARM_PARTITION_TABLE,
- SMEM_AARM_BAD_BLOCK_TABLE,
- SMEM_RESERVE_BAD_BLOCKS,
- SMEM_WM_UUID,
- SMEM_CHANNEL_ALLOC_TBL,
- SMEM_SMD_BASE_ID,
- SMEM_SMEM_LOG_IDX = SMEM_SMD_BASE_ID + SMEM_NUM_SMD_STREAM_CHANNELS,
- SMEM_SMEM_LOG_EVENTS,
- SMEM_SMEM_STATIC_LOG_IDX,
- SMEM_SMEM_STATIC_LOG_EVENTS,
- SMEM_SMEM_SLOW_CLOCK_SYNC,
- SMEM_SMEM_SLOW_CLOCK_VALUE,
- SMEM_BIO_LED_BUF,
- SMEM_SMSM_SHARED_STATE,
- SMEM_SMSM_INT_INFO,
- SMEM_SMSM_SLEEP_DELAY,
- SMEM_SMSM_LIMIT_SLEEP,
- SMEM_SLEEP_POWER_COLLAPSE_DISABLED,
- SMEM_KEYPAD_KEYS_PRESSED,
- SMEM_KEYPAD_STATE_UPDATED,
- SMEM_KEYPAD_STATE_IDX,
- SMEM_GPIO_INT,
- SMEM_MDDI_LCD_IDX,
- SMEM_MDDI_HOST_DRIVER_STATE,
- SMEM_MDDI_LCD_DISP_STATE,
- SMEM_LCD_CUR_PANEL,
- SMEM_MARM_BOOT_SEGMENT_INFO,
- SMEM_AARM_BOOT_SEGMENT_INFO,
- SMEM_SLEEP_STATIC,
- SMEM_SCORPION_FREQUENCY,
- SMEM_SMD_PROFILES,
- SMEM_TSSC_BUSY,
- SMEM_HS_SUSPEND_FILTER_INFO,
- SMEM_BATT_INFO,
- SMEM_APPS_BOOT_MODE,
- SMEM_VERSION_FIRST,
- SMEM_VERSION_SMD = SMEM_VERSION_FIRST,
- SMEM_VERSION_LAST = SMEM_VERSION_FIRST + 24,
- SMEM_OSS_RRCASN1_BUF1,
- SMEM_OSS_RRCASN1_BUF2,
- SMEM_ID_VENDOR0,
- SMEM_ID_VENDOR1,
- SMEM_ID_VENDOR2,
- SMEM_HW_SW_BUILD_ID,
- SMEM_SMD_BLOCK_PORT_BASE_ID,
- SMEM_SMD_BLOCK_PORT_PROC0_HEAP = SMEM_SMD_BLOCK_PORT_BASE_ID +
- SMEM_NUM_SMD_BLOCK_CHANNELS,
- SMEM_SMD_BLOCK_PORT_PROC1_HEAP = SMEM_SMD_BLOCK_PORT_PROC0_HEAP +
- SMEM_NUM_SMD_BLOCK_CHANNELS,
- SMEM_I2C_MUTEX = SMEM_SMD_BLOCK_PORT_PROC1_HEAP +
- SMEM_NUM_SMD_BLOCK_CHANNELS,
- SMEM_SCLK_CONVERSION,
- SMEM_SMD_SMSM_INTR_MUX,
- SMEM_SMSM_CPU_INTR_MASK,
- SMEM_APPS_DEM_SLAVE_DATA,
- SMEM_QDSP6_DEM_SLAVE_DATA,
- SMEM_CLKREGIM_BSP,
- SMEM_CLKREGIM_SOURCES,
- SMEM_SMD_FIFO_BASE_ID,
- SMEM_USABLE_RAM_PARTITION_TABLE = SMEM_SMD_FIFO_BASE_ID +
- SMEM_NUM_SMD_STREAM_CHANNELS,
- SMEM_POWER_ON_STATUS_INFO,
- SMEM_DAL_AREA,
- SMEM_SMEM_LOG_POWER_IDX,
- SMEM_SMEM_LOG_POWER_WRAP,
- SMEM_SMEM_LOG_POWER_EVENTS,
- SMEM_ERR_CRASH_LOG,
- SMEM_ERR_F3_TRACE_LOG,
- SMEM_SMD_BRIDGE_ALLOC_TABLE,
- SMEM_SMDLITE_TABLE,
- SMEM_SD_IMG_UPGRADE_STATUS,
- SMEM_SEFS_INFO,
- SMEM_RESET_LOG,
- SMEM_RESET_LOG_SYMBOLS,
- SMEM_MODEM_SW_BUILD_ID,
- SMEM_SMEM_LOG_MPROC_WRAP,
- SMEM_BOOT_INFO_FOR_APPS,
- SMEM_SMSM_SIZE_INFO,
- SMEM_SMD_LOOPBACK_REGISTER,
- SMEM_SSR_REASON_MSS0,
- SMEM_SSR_REASON_WCNSS0,
- SMEM_SSR_REASON_LPASS0,
- SMEM_SSR_REASON_DSPS0,
- SMEM_SSR_REASON_VCODEC0,
- SMEM_SMP2P_APPS_BASE = 427,
- SMEM_SMP2P_MODEM_BASE = SMEM_SMP2P_APPS_BASE + 8, /* 435 */
- SMEM_SMP2P_AUDIO_BASE = SMEM_SMP2P_MODEM_BASE + 8, /* 443 */
- SMEM_SMP2P_WIRLESS_BASE = SMEM_SMP2P_AUDIO_BASE + 8, /* 451 */
- SMEM_SMP2P_POWER_BASE = SMEM_SMP2P_WIRLESS_BASE + 8, /* 459 */
- SMEM_FLASH_DEVICE_INFO = SMEM_SMP2P_POWER_BASE + 8, /* 467 */
- SMEM_BAM_PIPE_MEMORY, /* 468 */
- SMEM_IMAGE_VERSION_TABLE, /* 469 */
- SMEM_LC_DEBUGGER, /* 470 */
- SMEM_NUM_ITEMS,
-};
-
enum {
SMEM_APPS_Q6_SMSM = 3,
SMEM_Q6_APPS_SMSM = 5,
@@ -217,9 +107,6 @@
};
#ifdef CONFIG_MSM_SMD
-void *smem_alloc(unsigned id, unsigned size);
-void *smem_alloc2(unsigned id, unsigned size_in);
-void *smem_get_entry(unsigned id, unsigned *size);
int smsm_change_state(uint32_t smsm_entry,
uint32_t clear_mask, uint32_t set_mask);
@@ -254,36 +141,8 @@
int smsm_check_for_modem_crash(void);
-void *smem_find(unsigned id, unsigned size);
-void *smem_get_entry(unsigned id, unsigned *size);
-
-/**
- * smem_virt_to_phys() - Convert SMEM address to physical address.
- *
- * @smem_address: Virtual address returned by smem_alloc()/smem_alloc2()
- * @returns: Physical address (or NULL if there is a failure)
- *
- * This function should only be used if an SMEM item needs to be handed
- * off to a DMA engine.
- */
-phys_addr_t smem_virt_to_phys(void *smem_address);
#else
-static inline void *smem_alloc(unsigned id, unsigned size)
-{
- return NULL;
-}
-
-static inline void *smem_alloc2(unsigned id, unsigned size_in)
-{
- return NULL;
-}
-
-static inline void *smem_get_entry(unsigned id, unsigned *size)
-{
- return NULL;
-}
-
static inline int smsm_change_state(uint32_t smsm_entry,
uint32_t clear_mask, uint32_t set_mask)
{
@@ -347,13 +206,5 @@
{
return -ENODEV;
}
-static inline void *smem_find(unsigned id, unsigned size)
-{
- return NULL;
-}
-static inline phys_addr_t smem_virt_to_phys(void *smem_address)
-{
- return NULL;
-}
#endif
#endif
diff --git a/arch/arm/mach-msm/include/mach/socinfo.h b/arch/arm/mach-msm/include/mach/socinfo.h
index 64531f0..dc8cbaa 100644
--- a/arch/arm/mach-msm/include/mach/socinfo.h
+++ b/arch/arm/mach-msm/include/mach/socinfo.h
@@ -53,6 +53,8 @@
of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,apq8084")
#define early_machine_is_msmkrypton() \
of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,msmkrypton")
+#define early_machine_is_fsm9900() \
+ of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,fsm9900")
#else
#define of_board_is_sim() 0
#define of_board_is_rumi() 0
@@ -70,6 +72,7 @@
#define early_machine_is_mpq8092() 0
#define early_machine_is_apq8084() 0
#define early_machine_is_msmkrypton() 0
+#define early_machine_is_fsm9900() 0
#endif
#define PLATFORM_SUBTYPE_MDM 1
@@ -110,6 +113,7 @@
MSM_CPU_8625Q,
MSM_CPU_8084,
MSM_CPU_KRYPTON,
+ FSM_CPU_9900,
};
enum pmic_model {
diff --git a/arch/arm/mach-msm/include/mach/usb_bam.h b/arch/arm/mach-msm/include/mach/usb_bam.h
index da7c039..5ecc63b 100644
--- a/arch/arm/mach-msm/include/mach/usb_bam.h
+++ b/arch/arm/mach-msm/include/mach/usb_bam.h
@@ -101,6 +101,7 @@
* @desc_mem_buf: descriptor fifo buffer.
* @event: event for wakeup.
* @enabled: true if pipe is enabled.
+* @ipa_clnt_hdl : pipe handle to ipa api.
* @priv: private data to return upon activity_notify
* or inactivity_notify callbacks.
* @activity_notify: callback to invoke on activity on one of the in pipes.
@@ -125,6 +126,7 @@
struct sps_mem_buffer desc_mem_buf;
struct usb_bam_event_info event;
bool enabled;
+ int ipa_clnt_hdl;
void *priv;
int (*activity_notify)(void *priv);
int (*inactivity_notify)(void *priv);
@@ -195,6 +197,14 @@
struct usb_bam_connect_ipa_params *ipa_params);
/**
+ * Wait for Consumer granted from Resource Manager.
+ *
+ * @ipa_params - in/out parameters
+ *
+ */
+void usb_bam_wait_for_cons_granted(
+ struct usb_bam_connect_ipa_params *ipa_params);
+/**
* Register a wakeup callback from peer BAM.
*
* @idx - Connection index.
@@ -221,6 +231,39 @@
int usb_bam_register_peer_reset_cb(int (*callback)(void *), void *param);
/**
+ * Register callbacks for start/stop of transfers.
+ *
+ * @start - the callback function that will be called in USB
+ * driver to start transfers
+ * @stop - the callback function that will be called in USB
+ * driver to stop transfers
+ *
+ * @param - context that the caller can supply
+ *
+ * @return 0 on success, negative value on error
+ *
+ */
+int usb_bam_register_start_stop_cbs(
+ void (*start)(void *, enum usb_bam_pipe_dir),
+ void (*stop)(void *, enum usb_bam_pipe_dir),
+ void *param);
+
+/**
+ * Start usb suspend sequence
+ *
+ * @ipa_params - in/out parameters
+ *
+ */
+void usb_bam_suspend(struct usb_bam_connect_ipa_params *ipa_params);
+
+/**
+ * Start usb resume sequence
+ *
+ * @ipa_params - in/out parameters
+ *
+ */
+void usb_bam_resume(struct usb_bam_connect_ipa_params *ipa_params);
+/**
* Disconnect USB-to-Periperal SPS connection.
*
* @idx - Connection index.
@@ -315,6 +358,12 @@
return -ENODEV;
}
+static inline void usb_bam_wait_for_cons_granted(
+ struct usb_bam_connect_ipa_params *ipa_params)
+{
+ return;
+}
+
static inline int usb_bam_register_wake_cb(u8 idx,
int (*callback)(void *), void* param)
{
@@ -327,6 +376,20 @@
return -ENODEV;
}
+static inline int usb_bam_register_start_stop_cbs(
+ void (*start)(void *, enum usb_bam_pipe_dir),
+ void (*stop)(void *, enum usb_bam_pipe_dir),
+ void *param)
+{
+ return -ENODEV;
+}
+
+static inline void usb_bam_suspend(
+ struct usb_bam_connect_ipa_params *ipa_params){}
+
+static inline void usb_bam_resume(
+ struct usb_bam_connect_ipa_params *ipa_params) {}
+
static inline int usb_bam_disconnect_pipe(u8 idx)
{
return -ENODEV;
diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c
index 1c4a317..099862f 100644
--- a/arch/arm/mach-msm/io.c
+++ b/arch/arm/mach-msm/io.c
@@ -406,6 +406,28 @@
}
#endif /* CONFIG_ARCH_FSM9XXX */
+#ifdef CONFIG_ARCH_FSM9900
+static struct map_desc fsm9900_io_desc[] __initdata = {
+ MSM_CHIP_DEVICE(QGIC_DIST, FSM9900),
+ MSM_CHIP_DEVICE(TLMM, FSM9900),
+ {
+ .virtual = (unsigned long) MSM_SHARED_RAM_BASE,
+ .length = MSM_SHARED_RAM_SIZE,
+ .type = MT_DEVICE,
+ },
+#ifdef CONFIG_DEBUG_FSM9900_UART
+ MSM_DEVICE(DEBUG_UART),
+#endif
+};
+
+void __init msm_map_fsm9900_io(void)
+{
+ msm_shared_ram_phys = FSM9900_SHARED_RAM_PHYS;
+ msm_map_io(fsm9900_io_desc, ARRAY_SIZE(fsm9900_io_desc));
+ of_scan_flat_dt(msm_scan_dt_map_imem, NULL);
+}
+#endif /* CONFIG_ARCH_FSM9900 */
+
#ifdef CONFIG_ARCH_MSM9615
static struct map_desc msm9615_io_desc[] __initdata = {
MSM_CHIP_DEVICE(QGIC_DIST, MSM9615),
diff --git a/arch/arm/mach-msm/ipc_router.c b/arch/arm/mach-msm/ipc_router.c
index a328b2b..aee691f 100644
--- a/arch/arm/mach-msm/ipc_router.c
+++ b/arch/arm/mach-msm/ipc_router.c
@@ -2253,12 +2253,11 @@
return ret;
}
- /* Achieve Flow control */
rport_ptr = msm_ipc_router_lookup_remote_port(dst_node_id,
dst_port_id);
if (!rport_ptr) {
- pr_err("%s: Could not create remote port\n", __func__);
- return -ENOMEM;
+ pr_err("%s: Remote port not found\n", __func__);
+ return -ENODEV;
}
if (src->check_send_permissions) {
diff --git a/arch/arm/mach-msm/lpm_resources.c b/arch/arm/mach-msm/lpm_resources.c
index f0e5ebd..624a27c 100644
--- a/arch/arm/mach-msm/lpm_resources.c
+++ b/arch/arm/mach-msm/lpm_resources.c
@@ -429,7 +429,7 @@
trace_lpm_resources(rs->sleep_value, rs->name);
}
-static void msm_lpm_set_l2_mode(int sleep_mode, int notify_rpm)
+static void msm_lpm_set_l2_mode(int sleep_mode)
{
int lpm, rc;
@@ -453,7 +453,7 @@
break;
}
- rc = msm_spm_l2_set_low_power_mode(lpm, notify_rpm);
+ rc = msm_spm_l2_set_low_power_mode(lpm, true);
if (rc < 0)
pr_err("%s: Failed to set L2 low power mode %d",
@@ -474,7 +474,7 @@
{
struct msm_lpm_resource *rs = &msm_lpm_l2;
- msm_lpm_set_l2_mode(rs->sleep_value, notify_rpm);
+ msm_lpm_set_l2_mode(rs->sleep_value);
}
int msm_lpm_get_l2_cache_value(struct device_node *node,
@@ -786,7 +786,7 @@
msm_mpm_exit_sleep(from_idle);
if (msm_lpm_l2.valid)
- msm_lpm_set_l2_mode(msm_lpm_l2.rs_data.default_value, false);
+ msm_lpm_set_l2_mode(msm_lpm_l2.rs_data.default_value);
}
static int msm_lpm_cpu_callback(struct notifier_block *cpu_nb,
diff --git a/arch/arm/mach-msm/memory_topology.c b/arch/arm/mach-msm/memory_topology.c
index 781cd69..97195e3 100644
--- a/arch/arm/mach-msm/memory_topology.c
+++ b/arch/arm/mach-msm/memory_topology.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -19,6 +19,7 @@
#include <linux/memory.h>
#include <mach/msm_memtypes.h>
#include <mach/socinfo.h>
+#include <mach/msm_smem.h>
#include "smd_private.h"
#if defined(CONFIG_ARCH_MSM8960)
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c b/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
index 2c7ceab..62da5ac 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
@@ -364,7 +364,7 @@
{
struct msm_bus_fabric *fabric = to_msm_bus_fabric(fabdev);
void *sel_cdata;
- int i;
+ long rounded_rate;
sel_cdata = fabric->cdata[ctx];
@@ -379,8 +379,17 @@
}
/* Enable clocks before accessing QoS registers */
- for (i = 0; i < NUM_CTX; i++)
- clk_prepare_enable(fabric->info.nodeclk[i].clk);
+ if (fabric->info.nodeclk[DUAL_CTX].clk)
+ if (fabric->info.nodeclk[DUAL_CTX].rate == 0) {
+ rounded_rate = clk_round_rate(fabric->
+ info.nodeclk[DUAL_CTX].clk, 1);
+ if (clk_set_rate(fabric->info.nodeclk[DUAL_CTX].clk,
+ rounded_rate))
+ MSM_BUS_ERR("Error: clk: en: Node: %d rate: %ld",
+ fabric->fabdev.id, rounded_rate);
+
+ clk_prepare_enable(fabric->info.nodeclk[DUAL_CTX].clk);
+ }
if (info->iface_clk.clk)
clk_prepare_enable(info->iface_clk.clk);
@@ -392,8 +401,9 @@
master_tiers, add_bw);
/* Disable clocks after accessing QoS registers */
- for (i = 0; i < NUM_CTX; i++)
- clk_disable_unprepare(fabric->info.nodeclk[i].clk);
+ if (fabric->info.nodeclk[DUAL_CTX].clk &&
+ fabric->info.nodeclk[DUAL_CTX].rate == 0)
+ clk_disable_unprepare(fabric->info.nodeclk[DUAL_CTX].clk);
if (info->iface_clk.clk) {
MSM_BUS_DBG("Commented: Will disable clock for info: %d\n",
diff --git a/arch/arm/mach-msm/msm_smem_iface.h b/arch/arm/mach-msm/msm_smem_iface.h
index bc3e73b..c9c56d9 100644
--- a/arch/arm/mach-msm/msm_smem_iface.h
+++ b/arch/arm/mach-msm/msm_smem_iface.h
@@ -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
@@ -16,6 +16,7 @@
#define __ARCH_ARM_MACH_MSM_SMEM_IFACE_H
#include <mach/msm_smsm.h>
+#include <mach/msm_smem.h>
#define MAX_KEY_EVENTS 10
#define MAX_SEC_KEY_PAYLOAD 32
diff --git a/arch/arm/mach-msm/nand_partitions.c b/arch/arm/mach-msm/nand_partitions.c
index ea5fb9c..ad2a10e 100644
--- a/arch/arm/mach-msm/nand_partitions.c
+++ b/arch/arm/mach-msm/nand_partitions.c
@@ -4,7 +4,7 @@
* bootloader.
*
* Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2008-2009,2011 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2008-2009,2011,2013 The Linux Foundation. All rights reserved.
* Author: Brian Swetland <swetland@google.com>
*
* This software is licensed under the terms of the GNU General Public
@@ -34,7 +34,7 @@
#include <mach/board.h>
#ifdef CONFIG_MSM_SMD
-#include "smd_private.h"
+#include <mach/msm_smem.h>
#endif
/* configuration tags specific to msm */
diff --git a/arch/arm/mach-msm/pil-dsps.c b/arch/arm/mach-msm/pil-dsps.c
index df5ea35..73b58ab 100644
--- a/arch/arm/mach-msm/pil-dsps.c
+++ b/arch/arm/mach-msm/pil-dsps.c
@@ -22,6 +22,7 @@
#include <mach/subsystem_restart.h>
#include <mach/msm_smsm.h>
#include <mach/ramdump.h>
+#include <mach/msm_smem.h>
#include "peripheral-loader.h"
#include "scm-pas.h"
diff --git a/arch/arm/mach-msm/pil-gss.c b/arch/arm/mach-msm/pil-gss.c
index 65f86bc..840c90f 100644
--- a/arch/arm/mach-msm/pil-gss.c
+++ b/arch/arm/mach-msm/pil-gss.c
@@ -30,6 +30,7 @@
#include <mach/msm_bus.h>
#include <mach/subsystem_restart.h>
#include <mach/ramdump.h>
+#include <mach/msm_smem.h>
#include "peripheral-loader.h"
#include "scm-pas.h"
diff --git a/arch/arm/mach-msm/pil-pronto.c b/arch/arm/mach-msm/pil-pronto.c
index b186a4d..098cbd5 100644
--- a/arch/arm/mach-msm/pil-pronto.c
+++ b/arch/arm/mach-msm/pil-pronto.c
@@ -30,6 +30,7 @@
#include <mach/subsystem_restart.h>
#include <mach/msm_smsm.h>
#include <mach/ramdump.h>
+#include <mach/msm_smem.h>
#include "peripheral-loader.h"
#include "scm-pas.h"
@@ -329,12 +330,13 @@
drv->crash = true;
+ disable_irq_nosync(drv->irq);
+
if (drv->restart_inprogress) {
pr_err("Ignoring wcnss bite irq, restart in progress\n");
return IRQ_HANDLED;
}
- disable_irq_nosync(drv->irq);
drv->restart_inprogress = true;
restart_wcnss(drv);
diff --git a/arch/arm/mach-msm/pil-q6v4-lpass.c b/arch/arm/mach-msm/pil-q6v4-lpass.c
index f05bcdb..7acb599 100644
--- a/arch/arm/mach-msm/pil-q6v4-lpass.c
+++ b/arch/arm/mach-msm/pil-q6v4-lpass.c
@@ -25,6 +25,7 @@
#include <mach/subsystem_restart.h>
#include <mach/subsystem_notif.h>
#include <mach/ramdump.h>
+#include <mach/msm_smem.h>
#include "smd_private.h"
#include "sysmon.h"
diff --git a/arch/arm/mach-msm/pil-q6v4-mss.c b/arch/arm/mach-msm/pil-q6v4-mss.c
index 1821ab1..c4b6038 100644
--- a/arch/arm/mach-msm/pil-q6v4-mss.c
+++ b/arch/arm/mach-msm/pil-q6v4-mss.c
@@ -23,6 +23,7 @@
#include <mach/subsystem_restart.h>
#include <mach/msm_smsm.h>
#include <mach/ramdump.h>
+#include <mach/msm_smem.h>
#include "smd_private.h"
#include "peripheral-loader.h"
diff --git a/arch/arm/mach-msm/pil-q6v5-lpass.c b/arch/arm/mach-msm/pil-q6v5-lpass.c
index 6e8e79e..19b5671 100644
--- a/arch/arm/mach-msm/pil-q6v5-lpass.c
+++ b/arch/arm/mach-msm/pil-q6v5-lpass.c
@@ -29,6 +29,7 @@
#include <mach/subsystem_notif.h>
#include <mach/scm.h>
#include <mach/ramdump.h>
+#include <mach/msm_smem.h>
#include "peripheral-loader.h"
#include "pil-q6v5.h"
@@ -409,12 +410,6 @@
drv->err_fatal_irq = ret;
ret = gpio_to_irq(of_get_named_gpio(pdev->dev.of_node,
- "qcom,gpio-err-ready", 0));
- if (ret < 0)
- return ret;
- drv->subsys_desc.err_ready_irq = ret;
-
- ret = gpio_to_irq(of_get_named_gpio(pdev->dev.of_node,
"qcom,gpio-proxy-unvote", 0));
if (ret < 0)
return ret;
diff --git a/arch/arm/mach-msm/pil-q6v5-mss.c b/arch/arm/mach-msm/pil-q6v5-mss.c
index 979458e..5ef6638 100644
--- a/arch/arm/mach-msm/pil-q6v5-mss.c
+++ b/arch/arm/mach-msm/pil-q6v5-mss.c
@@ -31,6 +31,7 @@
#include <mach/clk.h>
#include <mach/msm_smsm.h>
#include <mach/ramdump.h>
+#include <mach/msm_smem.h>
#include "peripheral-loader.h"
#include "pil-q6v5.h"
diff --git a/arch/arm/mach-msm/pil-riva.c b/arch/arm/mach-msm/pil-riva.c
index d72b848..5419bf0 100644
--- a/arch/arm/mach-msm/pil-riva.c
+++ b/arch/arm/mach-msm/pil-riva.c
@@ -24,6 +24,7 @@
#include <mach/subsystem_restart.h>
#include <mach/ramdump.h>
+#include <mach/msm_smem.h>
#include "peripheral-loader.h"
#include "scm-pas.h"
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index 33ad83f..afb2b84 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -671,7 +671,7 @@
u64 modified_time_ns = modified_time_us * NSEC_PER_USEC;
ktime_t modified_ktime = ns_to_ktime(modified_time_ns);
pm_hrtimer.function = pm_hrtimer_cb;
- hrtimer_start(&pm_hrtimer, modified_ktime, HRTIMER_MODE_ABS);
+ hrtimer_start(&pm_hrtimer, modified_ktime, HRTIMER_MODE_REL);
}
/******************************************************************************
@@ -1283,7 +1283,7 @@
msm_pm_mode_sysfs_add();
msm_pm_add_stats(enable_stats, ARRAY_SIZE(enable_stats));
suspend_set_ops(&msm_pm_ops);
- hrtimer_init(&pm_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
+ hrtimer_init(&pm_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
msm_cpuidle_init();
if (msm_pm_pc_reset_timer) {
diff --git a/arch/arm/mach-msm/pm2.c b/arch/arm/mach-msm/pm2.c
index a2da8b0..9f97a59 100644
--- a/arch/arm/mach-msm/pm2.c
+++ b/arch/arm/mach-msm/pm2.c
@@ -3,7 +3,7 @@
* MSM Power Management Routines
*
* Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2008-2012 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2008-2013 The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -44,9 +44,10 @@
#endif
#include <mach/socinfo.h>
#include <mach/proc_comm.h>
+#include <mach/msm_smem.h>
+#include <mach/msm_smsm.h>
#include <asm/smp_scu.h>
-#include "smd_private.h"
#include "smd_rpcrouter.h"
#include "acpuclock.h"
#include "clock.h"
diff --git a/arch/arm/mach-msm/remote_spinlock.c b/arch/arm/mach-msm/remote_spinlock.c
index 62e3e05..a9ebd7c 100644
--- a/arch/arm/mach-msm/remote_spinlock.c
+++ b/arch/arm/mach-msm/remote_spinlock.c
@@ -25,6 +25,7 @@
#include <mach/msm_iomap.h>
#include <mach/remote_spinlock.h>
#include <mach/dal.h>
+#include <mach/msm_smem.h>
#include "smd_private.h"
diff --git a/arch/arm/mach-msm/rmt_storage_client.c b/arch/arm/mach-msm/rmt_storage_client.c
index a4562e9..550624c 100644
--- a/arch/arm/mach-msm/rmt_storage_client.c
+++ b/arch/arm/mach-msm/rmt_storage_client.c
@@ -35,7 +35,7 @@
#ifdef CONFIG_MSM_SDIO_SMEM
#include <mach/sdio_smem.h>
#endif
-#include "smd_private.h"
+#include <mach/msm_smem.h>
enum {
RMT_STORAGE_EVNT_OPEN = 0,
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index 3590e6b..a177593 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -47,11 +47,13 @@
#include <mach/msm_ipc_logging.h>
#include <mach/ramdump.h>
#include <mach/board.h>
+#include <mach/msm_smem.h>
#include <asm/cacheflush.h>
#include "smd_private.h"
#include "modem_notifier.h"
+#include "smem_private.h"
#if defined(CONFIG_ARCH_QSD8X50) || defined(CONFIG_ARCH_MSM8X60) \
|| defined(CONFIG_ARCH_MSM8960) || defined(CONFIG_ARCH_FSM9XXX) \
@@ -175,16 +177,6 @@
},
};
-struct smem_area {
- phys_addr_t phys_addr;
- resource_size_t size;
- void __iomem *virt_addr;
-};
-static uint32_t num_smem_areas;
-static struct smem_area *smem_areas;
-static struct ramdump_segment *smem_ramdump_segments;
-static void *smem_ramdump_dev;
-static void *smem_phys_to_virt(phys_addr_t base, unsigned offset);
static void *smd_dev;
struct interrupt_stat interrupt_stats[NUM_SMD_SUBSYSTEMS];
@@ -380,9 +372,6 @@
#define SMD_LOOPBACK_CID 100
-#define SMEM_SPINLOCK_SMEM_ALLOC "S:3"
-static remote_spinlock_t remote_spinlock;
-
static LIST_HEAD(smd_ch_list_loopback);
static void smd_fake_irq_handler(unsigned long arg);
static void smsm_cb_snapshot(uint32_t use_wakelock);
@@ -392,7 +381,6 @@
static DECLARE_WORK(smsm_cb_work, notify_smsm_cb_clients_worker);
static DEFINE_MUTEX(smsm_lock);
static struct smsm_state_info *smsm_states;
-static int spinlocks_initialized;
/**
* Variables to indicate smd module initialization.
@@ -2408,222 +2396,6 @@
}
EXPORT_SYMBOL(smd_is_pkt_avail);
-
-/* -------------------------------------------------------------------------- */
-
-/**
- * smem_phys_to_virt() - Convert a physical base and offset to virtual address
- *
- * @base: physical base address to check
- * @offset: offset from the base to get the final address
- * @returns: virtual SMEM address; NULL for failure
- *
- * Takes a physical address and an offset and checks if the resulting physical
- * address would fit into one of the smem regions. If so, returns the
- * corresponding virtual address. Otherwise returns NULL.
- */
-static void *smem_phys_to_virt(phys_addr_t base, unsigned offset)
-{
- int i;
- phys_addr_t phys_addr;
- resource_size_t size;
-
- if (OVERFLOW_ADD_UNSIGNED(phys_addr_t, base, offset))
- return NULL;
-
- if (!smem_areas) {
- /*
- * Early boot - no area configuration yet, so default
- * to using the main memory region.
- *
- * To remove the MSM_SHARED_RAM_BASE and the static
- * mapping of SMEM in the future, add dump_stack()
- * to identify the early callers of smem_get_entry()
- * (which calls this function) and replace those calls
- * with a new function that knows how to lookup the
- * SMEM base address before SMEM has been probed.
- */
- phys_addr = msm_shared_ram_phys;
- size = MSM_SHARED_RAM_SIZE;
-
- if (base >= phys_addr && base + offset < phys_addr + size) {
- if (OVERFLOW_ADD_UNSIGNED(uintptr_t,
- (uintptr_t)MSM_SHARED_RAM_BASE, offset)) {
- pr_err("%s: overflow %p %x\n", __func__,
- MSM_SHARED_RAM_BASE, offset);
- return NULL;
- }
-
- return MSM_SHARED_RAM_BASE + offset;
- } else {
- return NULL;
- }
- }
- for (i = 0; i < num_smem_areas; ++i) {
- phys_addr = smem_areas[i].phys_addr;
- size = smem_areas[i].size;
-
- if (base < phys_addr || base + offset >= phys_addr + size)
- continue;
-
- if (OVERFLOW_ADD_UNSIGNED(uintptr_t,
- (uintptr_t)smem_areas[i].virt_addr, offset)) {
- pr_err("%s: overflow %p %x\n", __func__,
- smem_areas[i].virt_addr, offset);
- return NULL;
- }
-
- return smem_areas[i].virt_addr + offset;
- }
-
- return NULL;
-}
-
-/**
- * smem_virt_to_phys() - Convert SMEM address to physical address.
- *
- * @smem_address: Address of SMEM item (returned by smem_alloc(), etc)
- * @returns: Physical address (or NULL if there is a failure)
- *
- * This function should only be used if an SMEM item needs to be handed
- * off to a DMA engine.
- */
-phys_addr_t smem_virt_to_phys(void *smem_address)
-{
- phys_addr_t phys_addr = 0;
- int i;
- void *vend;
-
- if (!smem_areas)
- return phys_addr;
-
- for (i = 0; i < num_smem_areas; ++i) {
- vend = (void *)(smem_areas[i].virt_addr + smem_areas[i].size);
-
- if (smem_address >= smem_areas[i].virt_addr &&
- smem_address < vend) {
- phys_addr = smem_address - smem_areas[i].virt_addr;
- phys_addr += smem_areas[i].phys_addr;
- break;
- }
- }
-
- return phys_addr;
-}
-EXPORT_SYMBOL(smem_virt_to_phys);
-
-/* smem_alloc returns the pointer to smem item if it is already allocated.
- * Otherwise, it returns NULL.
- */
-void *smem_alloc(unsigned id, unsigned size)
-{
- return smem_find(id, size);
-}
-EXPORT_SYMBOL(smem_alloc);
-
-/* smem_alloc2 returns the pointer to smem item. If it is not allocated,
- * it allocates it and then returns the pointer to it.
- */
-void *smem_alloc2(unsigned id, unsigned size_in)
-{
- struct smem_shared *shared = (void *) MSM_SHARED_RAM_BASE;
- struct smem_heap_entry *toc = shared->heap_toc;
- unsigned long flags;
- void *ret = NULL;
-
- if (!shared->heap_info.initialized) {
- pr_err("%s: smem heap info not initialized\n", __func__);
- return NULL;
- }
-
- if (id >= SMEM_NUM_ITEMS)
- return NULL;
-
- size_in = ALIGN(size_in, 8);
- remote_spin_lock_irqsave(&remote_spinlock, flags);
- if (toc[id].allocated) {
- SMD_DBG("%s: %u already allocated\n", __func__, id);
- if (size_in != toc[id].size)
- pr_err("%s: wrong size %u (expected %u)\n",
- __func__, toc[id].size, size_in);
- else
- ret = (void *)(MSM_SHARED_RAM_BASE + toc[id].offset);
- } else if (id > SMEM_FIXED_ITEM_LAST) {
- SMD_DBG("%s: allocating %u\n", __func__, id);
- if (shared->heap_info.heap_remaining >= size_in) {
- toc[id].offset = shared->heap_info.free_offset;
- toc[id].size = size_in;
- wmb();
- toc[id].allocated = 1;
-
- shared->heap_info.free_offset += size_in;
- shared->heap_info.heap_remaining -= size_in;
- ret = (void *)(MSM_SHARED_RAM_BASE + toc[id].offset);
- } else
- pr_err("%s: not enough memory %u (required %u)\n",
- __func__, shared->heap_info.heap_remaining,
- size_in);
- }
- wmb();
- remote_spin_unlock_irqrestore(&remote_spinlock, flags);
- return ret;
-}
-EXPORT_SYMBOL(smem_alloc2);
-
-void *smem_get_entry(unsigned id, unsigned *size)
-{
- struct smem_shared *shared = (void *) MSM_SHARED_RAM_BASE;
- struct smem_heap_entry *toc = shared->heap_toc;
- int use_spinlocks = spinlocks_initialized;
- void *ret = 0;
- unsigned long flags = 0;
-
- if (id >= SMEM_NUM_ITEMS)
- return ret;
-
- if (use_spinlocks)
- remote_spin_lock_irqsave(&remote_spinlock, flags);
- /* toc is in device memory and cannot be speculatively accessed */
- if (toc[id].allocated) {
- phys_addr_t phys_base;
-
- *size = toc[id].size;
- barrier();
-
- phys_base = toc[id].reserved & BASE_ADDR_MASK;
- if (!phys_base)
- phys_base = (phys_addr_t)msm_shared_ram_phys;
- ret = smem_phys_to_virt(phys_base, toc[id].offset);
- } else {
- *size = 0;
- }
- if (use_spinlocks)
- remote_spin_unlock_irqrestore(&remote_spinlock, flags);
-
- return ret;
-}
-EXPORT_SYMBOL(smem_get_entry);
-
-void *smem_find(unsigned id, unsigned size_in)
-{
- unsigned size;
- void *ptr;
-
- ptr = smem_get_entry(id, &size);
- if (!ptr)
- return 0;
-
- size_in = ALIGN(size_in, 8);
- if (size_in != size) {
- pr_err("smem_find(%d, %d): wrong size %d\n",
- id, size_in, size);
- return 0;
- }
-
- return ptr;
-}
-EXPORT_SYMBOL(smem_find);
-
static int smsm_cb_init(void)
{
struct smsm_state_info *state_info;
@@ -3313,17 +3085,6 @@
}
EXPORT_SYMBOL(smsm_state_cb_deregister);
-/**
- * smem_get_remote_spinlock - Remote spinlock pointer for unit testing.
- *
- * @returns: pointer to SMEM remote spinlock
- */
-remote_spinlock_t *smem_get_remote_spinlock(void)
-{
- return &remote_spinlock;
-}
-EXPORT_SYMBOL(smem_get_remote_spinlock);
-
int smd_module_init_notifier_register(struct notifier_block *nb)
{
int ret;
@@ -4126,23 +3887,6 @@
remote_spin_release(&remote_spinlock, notifier->processor);
remote_spin_release_all(notifier->processor);
- if (smem_ramdump_dev) {
- int ret;
-
- SMD_INFO("%s: saving ramdump\n", __func__);
- /*
- * XPU protection does not currently allow the
- * auxiliary memory regions to be dumped. If this
- * changes, then num_smem_areas + 1 should be passed
- * into do_elf_ramdump() to dump all regions.
- */
- ret = do_elf_ramdump(smem_ramdump_dev,
- smem_ramdump_segments, 1);
- if (ret < 0)
- pr_err("%s: unable to dump smem %d\n", __func__,
- ret);
- }
-
smd_channel_reset(notifier->processor);
}
@@ -4155,13 +3899,6 @@
void *handle;
struct restart_notifier_block *nb;
- smem_ramdump_dev = create_ramdump_device("smem-smd", smd_dev);
- if (IS_ERR_OR_NULL(smem_ramdump_dev)) {
- pr_err("%s: Unable to create smem ramdump device.\n",
- __func__);
- smem_ramdump_dev = NULL;
- }
-
for (i = 0; i < ARRAY_SIZE(restart_notifiers); i++) {
nb = &restart_notifiers[i];
handle = subsys_notif_register_notifier(nb->name, &nb->nb);
@@ -4202,12 +3939,11 @@
}
registered = true;
- rc = remote_spin_lock_init(&remote_spinlock, SMEM_SPINLOCK_SMEM_ALLOC);
+ rc = init_smem_remote_spinlock();
if (rc) {
pr_err("%s: remote spinlock init failed %d\n", __func__, rc);
return rc;
}
- spinlocks_initialized = 1;
rc = platform_driver_register(&msm_smd_driver);
if (rc) {
diff --git a/arch/arm/mach-msm/smd_debug.c b/arch/arm/mach-msm/smd_debug.c
index 4dcf72f..b66e258 100644
--- a/arch/arm/mach-msm/smd_debug.c
+++ b/arch/arm/mach-msm/smd_debug.c
@@ -21,8 +21,10 @@
#include <linux/jiffies.h>
#include <mach/msm_iomap.h>
+#include <mach/msm_smem.h>
#include "smd_private.h"
+#include "smem_private.h"
#if defined(CONFIG_DEBUG_FS)
diff --git a/arch/arm/mach-msm/smd_private.h b/arch/arm/mach-msm/smd_private.h
index 4a6a509..4fe9592 100644
--- a/arch/arm/mach-msm/smd_private.h
+++ b/arch/arm/mach-msm/smd_private.h
@@ -34,37 +34,6 @@
#define VERSION_MODEM 9
#define VERSION_DSPS 10
-#define SMD_HEAP_SIZE 512
-
-struct smem_heap_info {
- unsigned initialized;
- unsigned free_offset;
- unsigned heap_remaining;
- unsigned reserved;
-};
-
-struct smem_heap_entry {
- unsigned allocated;
- unsigned offset;
- unsigned size;
- unsigned reserved; /* bits 1:0 reserved, bits 31:2 aux smem base addr */
-};
-#define BASE_ADDR_MASK 0xfffffffc
-
-struct smem_proc_comm {
- unsigned command;
- unsigned status;
- unsigned data1;
- unsigned data2;
-};
-
-struct smem_shared {
- struct smem_proc_comm proc_comm[4];
- unsigned version[32];
- struct smem_heap_info heap_info;
- struct smem_heap_entry heap_toc[SMD_HEAP_SIZE];
-};
-
#if defined(CONFIG_MSM_SMD_PKG4)
struct smsm_interrupt_info {
uint32_t aArm_en_mask;
@@ -313,7 +282,4 @@
uint32_t smsm_interrupt_id;
};
extern struct interrupt_stat interrupt_stats[NUM_SMD_SUBSYSTEMS];
-
-/* used for unit testing spinlocks */
-remote_spinlock_t *smem_get_remote_spinlock(void);
#endif
diff --git a/arch/arm/mach-msm/smem.c b/arch/arm/mach-msm/smem.c
new file mode 100644
index 0000000..2204609
--- /dev/null
+++ b/arch/arm/mach-msm/smem.c
@@ -0,0 +1,403 @@
+/* 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/export.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/moduleparam.h>
+#include <linux/printk.h>
+
+#include <mach/board.h>
+#include <mach/msm_iomap.h>
+#include <mach/msm_smem.h>
+#include <mach/ramdump.h>
+#include <mach/subsystem_notif.h>
+
+#include "smem_private.h"
+
+/**
+ * OVERFLOW_ADD_UNSIGNED() - check for unsigned overflow
+ *
+ * @type: type to check for overflow
+ * @a: left value to use
+ * @b: right value to use
+ * @returns: true if a + b will result in overflow; false otherwise
+ */
+#define OVERFLOW_ADD_UNSIGNED(type, a, b) \
+ (((type)~0 - (a)) < (b) ? true : false)
+
+enum {
+ MSM_SMEM_DEBUG = 1U << 0,
+ MSM_SMEM_INFO = 1U << 1,
+};
+
+static int msm_smem_debug_mask;
+module_param_named(debug_mask, msm_smem_debug_mask,
+ int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+#define SMEM_DBG(x...) do { \
+ if (msm_smem_debug_mask & MSM_SMEM_DEBUG) \
+ pr_debug(x); \
+ } while (0)
+
+remote_spinlock_t remote_spinlock;
+int spinlocks_initialized;
+uint32_t num_smem_areas;
+struct smem_area *smem_areas;
+struct ramdump_segment *smem_ramdump_segments;
+
+static void *smem_ramdump_dev;
+static DEFINE_MUTEX(spinlock_init_lock);
+
+struct restart_notifier_block {
+ unsigned processor;
+ char *name;
+ struct notifier_block nb;
+};
+
+static int restart_notifier_cb(struct notifier_block *this,
+ unsigned long code,
+ void *data);
+
+static struct restart_notifier_block restart_notifiers[] = {
+ {SMEM_MODEM, "modem", .nb.notifier_call = restart_notifier_cb},
+ {SMEM_Q6, "lpass", .nb.notifier_call = restart_notifier_cb},
+ {SMEM_WCNSS, "wcnss", .nb.notifier_call = restart_notifier_cb},
+ {SMEM_DSPS, "dsps", .nb.notifier_call = restart_notifier_cb},
+ {SMEM_MODEM, "gss", .nb.notifier_call = restart_notifier_cb},
+ {SMEM_Q6, "adsp", .nb.notifier_call = restart_notifier_cb},
+};
+
+/**
+ * smem_phys_to_virt() - Convert a physical base and offset to virtual address
+ *
+ * @base: physical base address to check
+ * @offset: offset from the base to get the final address
+ * @returns: virtual SMEM address; NULL for failure
+ *
+ * Takes a physical address and an offset and checks if the resulting physical
+ * address would fit into one of the smem regions. If so, returns the
+ * corresponding virtual address. Otherwise returns NULL.
+ */
+static void *smem_phys_to_virt(phys_addr_t base, unsigned offset)
+{
+ int i;
+ phys_addr_t phys_addr;
+ resource_size_t size;
+
+ if (OVERFLOW_ADD_UNSIGNED(phys_addr_t, base, offset))
+ return NULL;
+
+ if (!smem_areas) {
+ /*
+ * Early boot - no area configuration yet, so default
+ * to using the main memory region.
+ *
+ * To remove the MSM_SHARED_RAM_BASE and the static
+ * mapping of SMEM in the future, add dump_stack()
+ * to identify the early callers of smem_get_entry()
+ * (which calls this function) and replace those calls
+ * with a new function that knows how to lookup the
+ * SMEM base address before SMEM has been probed.
+ */
+ phys_addr = msm_shared_ram_phys;
+ size = MSM_SHARED_RAM_SIZE;
+
+ if (base >= phys_addr && base + offset < phys_addr + size) {
+ if (OVERFLOW_ADD_UNSIGNED(uintptr_t,
+ (uintptr_t)MSM_SHARED_RAM_BASE, offset)) {
+ pr_err("%s: overflow %p %x\n", __func__,
+ MSM_SHARED_RAM_BASE, offset);
+ return NULL;
+ }
+
+ return MSM_SHARED_RAM_BASE + offset;
+ } else {
+ return NULL;
+ }
+ }
+ for (i = 0; i < num_smem_areas; ++i) {
+ phys_addr = smem_areas[i].phys_addr;
+ size = smem_areas[i].size;
+
+ if (base < phys_addr || base + offset >= phys_addr + size)
+ continue;
+
+ if (OVERFLOW_ADD_UNSIGNED(uintptr_t,
+ (uintptr_t)smem_areas[i].virt_addr, offset)) {
+ pr_err("%s: overflow %p %x\n", __func__,
+ smem_areas[i].virt_addr, offset);
+ return NULL;
+ }
+
+ return smem_areas[i].virt_addr + offset;
+ }
+
+ return NULL;
+}
+
+/**
+ * smem_virt_to_phys() - Convert SMEM address to physical address.
+ *
+ * @smem_address: Address of SMEM item (returned by smem_alloc(), etc)
+ * @returns: Physical address (or NULL if there is a failure)
+ *
+ * This function should only be used if an SMEM item needs to be handed
+ * off to a DMA engine.
+ */
+phys_addr_t smem_virt_to_phys(void *smem_address)
+{
+ phys_addr_t phys_addr = 0;
+ int i;
+ void *vend;
+
+ if (!smem_areas)
+ return phys_addr;
+
+ for (i = 0; i < num_smem_areas; ++i) {
+ vend = (void *)(smem_areas[i].virt_addr + smem_areas[i].size);
+
+ if (smem_address >= smem_areas[i].virt_addr &&
+ smem_address < vend) {
+ phys_addr = smem_address - smem_areas[i].virt_addr;
+ phys_addr += smem_areas[i].phys_addr;
+ break;
+ }
+ }
+
+ return phys_addr;
+}
+EXPORT_SYMBOL(smem_virt_to_phys);
+
+/* smem_alloc returns the pointer to smem item if it is already allocated.
+ * Otherwise, it returns NULL.
+ */
+void *smem_alloc(unsigned id, unsigned size)
+{
+ return smem_find(id, size);
+}
+EXPORT_SYMBOL(smem_alloc);
+
+void *smem_find(unsigned id, unsigned size_in)
+{
+ unsigned size;
+ void *ptr;
+
+ ptr = smem_get_entry(id, &size);
+ if (!ptr)
+ return 0;
+
+ size_in = ALIGN(size_in, 8);
+ if (size_in != size) {
+ pr_err("smem_find(%d, %d): wrong size %d\n",
+ id, size_in, size);
+ return 0;
+ }
+
+ return ptr;
+}
+EXPORT_SYMBOL(smem_find);
+
+/* smem_alloc2 returns the pointer to smem item. If it is not allocated,
+ * it allocates it and then returns the pointer to it.
+ */
+void *smem_alloc2(unsigned id, unsigned size_in)
+{
+ struct smem_shared *shared = (void *) MSM_SHARED_RAM_BASE;
+ struct smem_heap_entry *toc = shared->heap_toc;
+ unsigned long flags;
+ void *ret = NULL;
+ int rc;
+
+ if (!shared->heap_info.initialized) {
+ pr_err("%s: smem heap info not initialized\n", __func__);
+ return NULL;
+ }
+
+ if (id >= SMEM_NUM_ITEMS)
+ return NULL;
+
+ if (unlikely(!spinlocks_initialized)) {
+ rc = init_smem_remote_spinlock();
+ if (unlikely(rc)) {
+ pr_err("%s: remote spinlock init failed %d\n",
+ __func__, rc);
+ return NULL;
+ }
+ }
+
+ size_in = ALIGN(size_in, 8);
+ remote_spin_lock_irqsave(&remote_spinlock, flags);
+ if (toc[id].allocated) {
+ SMEM_DBG("%s: %u already allocated\n", __func__, id);
+ if (size_in != toc[id].size)
+ pr_err("%s: wrong size %u (expected %u)\n",
+ __func__, toc[id].size, size_in);
+ else
+ ret = (void *)(MSM_SHARED_RAM_BASE + toc[id].offset);
+ } else if (id > SMEM_FIXED_ITEM_LAST) {
+ SMEM_DBG("%s: allocating %u\n", __func__, id);
+ if (shared->heap_info.heap_remaining >= size_in) {
+ toc[id].offset = shared->heap_info.free_offset;
+ toc[id].size = size_in;
+ wmb();
+ toc[id].allocated = 1;
+
+ shared->heap_info.free_offset += size_in;
+ shared->heap_info.heap_remaining -= size_in;
+ ret = (void *)(MSM_SHARED_RAM_BASE + toc[id].offset);
+ } else
+ pr_err("%s: not enough memory %u (required %u)\n",
+ __func__, shared->heap_info.heap_remaining,
+ size_in);
+ }
+ wmb();
+ remote_spin_unlock_irqrestore(&remote_spinlock, flags);
+ return ret;
+}
+EXPORT_SYMBOL(smem_alloc2);
+
+void *smem_get_entry(unsigned id, unsigned *size)
+{
+ struct smem_shared *shared = (void *) MSM_SHARED_RAM_BASE;
+ struct smem_heap_entry *toc = shared->heap_toc;
+ int use_spinlocks = spinlocks_initialized;
+ void *ret = 0;
+ unsigned long flags = 0;
+
+ if (id >= SMEM_NUM_ITEMS)
+ return ret;
+
+ if (use_spinlocks)
+ remote_spin_lock_irqsave(&remote_spinlock, flags);
+ /* toc is in device memory and cannot be speculatively accessed */
+ if (toc[id].allocated) {
+ phys_addr_t phys_base;
+
+ *size = toc[id].size;
+ barrier();
+
+ phys_base = toc[id].reserved & BASE_ADDR_MASK;
+ if (!phys_base)
+ phys_base = (phys_addr_t)msm_shared_ram_phys;
+ ret = smem_phys_to_virt(phys_base, toc[id].offset);
+ } else {
+ *size = 0;
+ }
+ if (use_spinlocks)
+ remote_spin_unlock_irqrestore(&remote_spinlock, flags);
+
+ return ret;
+}
+EXPORT_SYMBOL(smem_get_entry);
+
+
+/**
+ * smem_get_remote_spinlock - Remote spinlock pointer for unit testing.
+ *
+ * @returns: pointer to SMEM remote spinlock
+ */
+remote_spinlock_t *smem_get_remote_spinlock(void)
+{
+ return &remote_spinlock;
+}
+EXPORT_SYMBOL(smem_get_remote_spinlock);
+
+/**
+ * init_smem_remote_spinlock - Reentrant remote spinlock initialization
+ *
+ * @returns: sucess or error code for failure
+ */
+int init_smem_remote_spinlock(void)
+{
+ int rc = 0;
+
+ /*
+ * Optimistic locking. Init only needs to be done once by the first
+ * caller. After that, serializing inits between different callers
+ * is unnecessary. The second check after the lock ensures init
+ * wasn't previously completed by someone else before the lock could
+ * be grabbed.
+ */
+ if (!spinlocks_initialized) {
+ mutex_lock(&spinlock_init_lock);
+ if (!spinlocks_initialized) {
+ rc = remote_spin_lock_init(&remote_spinlock,
+ SMEM_SPINLOCK_SMEM_ALLOC);
+ if (!rc)
+ spinlocks_initialized = 1;
+ }
+ mutex_unlock(&spinlock_init_lock);
+ }
+ return rc;
+}
+
+static int restart_notifier_cb(struct notifier_block *this,
+ unsigned long code,
+ void *data)
+{
+ if (code == SUBSYS_AFTER_SHUTDOWN) {
+ struct restart_notifier_block *notifier;
+
+ notifier = container_of(this,
+ struct restart_notifier_block, nb);
+ SMEM_DBG("%s: ssrestart for processor %d ('%s')\n",
+ __func__, notifier->processor,
+ notifier->name);
+
+ remote_spin_release(&remote_spinlock, notifier->processor);
+ remote_spin_release_all(notifier->processor);
+
+ if (smem_ramdump_dev) {
+ int ret;
+
+ SMEM_DBG("%s: saving ramdump\n", __func__);
+ /*
+ * XPU protection does not currently allow the
+ * auxiliary memory regions to be dumped. If this
+ * changes, then num_smem_areas + 1 should be passed
+ * into do_elf_ramdump() to dump all regions.
+ */
+ ret = do_elf_ramdump(smem_ramdump_dev,
+ smem_ramdump_segments, 1);
+ if (ret < 0)
+ pr_err("%s: unable to dump smem %d\n", __func__,
+ ret);
+ }
+ }
+
+ return NOTIFY_DONE;
+}
+
+static __init int modem_restart_late_init(void)
+{
+ int i;
+ void *handle;
+ struct restart_notifier_block *nb;
+
+ smem_ramdump_dev = create_ramdump_device("smem", NULL);
+ if (IS_ERR_OR_NULL(smem_ramdump_dev)) {
+ pr_err("%s: Unable to create smem ramdump device.\n",
+ __func__);
+ smem_ramdump_dev = NULL;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(restart_notifiers); i++) {
+ nb = &restart_notifiers[i];
+ handle = subsys_notif_register_notifier(nb->name, &nb->nb);
+ SMEM_DBG("%s: registering notif for '%s', handle=%p\n",
+ __func__, nb->name, handle);
+ }
+
+ return 0;
+}
+late_initcall(modem_restart_late_init);
diff --git a/arch/arm/mach-msm/smem_log.c b/arch/arm/mach-msm/smem_log.c
index 361df33..87f141d2 100644
--- a/arch/arm/mach-msm/smem_log.c
+++ b/arch/arm/mach-msm/smem_log.c
@@ -32,6 +32,7 @@
#include <mach/msm_iomap.h>
#include <mach/smem_log.h>
+#include <mach/msm_smem.h>
#include <asm/arch_timer.h>
diff --git a/arch/arm/mach-msm/smem_private.h b/arch/arm/mach-msm/smem_private.h
new file mode 100644
index 0000000..b631e7c
--- /dev/null
+++ b/arch/arm/mach-msm/smem_private.h
@@ -0,0 +1,74 @@
+/* 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 _ARCH_ARM_MACH_MSM_SMEM_PRIVATE_H_
+#define _ARCH_ARM_MACH_MSM_SMEM_PRIVATE_H_
+
+#include <linux/remote_spinlock.h>
+
+#include <mach/ramdump.h>
+
+#define SMEM_SPINLOCK_SMEM_ALLOC "S:3"
+extern remote_spinlock_t remote_spinlock;
+extern int spinlocks_initialized; /* only modify in init_smem_remote_spinlock */
+
+#define SMD_HEAP_SIZE 512
+
+struct smem_heap_info {
+ unsigned initialized;
+ unsigned free_offset;
+ unsigned heap_remaining;
+ unsigned reserved;
+};
+
+struct smem_heap_entry {
+ unsigned allocated;
+ unsigned offset;
+ unsigned size;
+ unsigned reserved; /* bits 1:0 reserved, bits 31:2 aux smem base addr */
+};
+#define BASE_ADDR_MASK 0xfffffffc
+
+struct smem_proc_comm {
+ unsigned command;
+ unsigned status;
+ unsigned data1;
+ unsigned data2;
+};
+
+struct smem_shared {
+ struct smem_proc_comm proc_comm[4];
+ unsigned version[32];
+ struct smem_heap_info heap_info;
+ struct smem_heap_entry heap_toc[SMD_HEAP_SIZE];
+};
+
+struct smem_area {
+ phys_addr_t phys_addr;
+ resource_size_t size;
+ void __iomem *virt_addr;
+};
+
+extern uint32_t num_smem_areas;
+extern struct smem_area *smem_areas;
+
+extern struct ramdump_segment *smem_ramdump_segments;
+
+/* used for unit testing spinlocks */
+remote_spinlock_t *smem_get_remote_spinlock(void);
+
+/*
+ * used to ensure the remote spinlock is only inited once since local
+ * spinlock init code appears non-reentrant
+ */
+int init_smem_remote_spinlock(void);
+#endif /* _ARCH_ARM_MACH_MSM_SMEM_PRIVATE_H_ */
diff --git a/arch/arm/mach-msm/smp2p.c b/arch/arm/mach-msm/smp2p.c
index 7bdcce9..ee262b0 100644
--- a/arch/arm/mach-msm/smp2p.c
+++ b/arch/arm/mach-msm/smp2p.c
@@ -19,7 +19,7 @@
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
-#include <mach/msm_smsm.h>
+#include <mach/msm_smem.h>
#include <mach/msm_ipc_logging.h>
#include "smp2p_private_api.h"
#include "smp2p_private.h"
diff --git a/arch/arm/mach-msm/smp2p_loopback.c b/arch/arm/mach-msm/smp2p_loopback.c
index d95c93f..5df3d70 100644
--- a/arch/arm/mach-msm/smp2p_loopback.c
+++ b/arch/arm/mach-msm/smp2p_loopback.c
@@ -21,7 +21,7 @@
#include <linux/termios.h>
#include <linux/module.h>
#include <linux/remote_spinlock.h>
-#include "smd_private.h"
+#include "smem_private.h"
#include "smp2p_private.h"
/**
diff --git a/arch/arm/mach-msm/smp2p_spinlock_test.c b/arch/arm/mach-msm/smp2p_spinlock_test.c
index 09d7c0d..c14bac0 100644
--- a/arch/arm/mach-msm/smp2p_spinlock_test.c
+++ b/arch/arm/mach-msm/smp2p_spinlock_test.c
@@ -17,8 +17,8 @@
#include <linux/delay.h>
#include <linux/completion.h>
#include <linux/remote_spinlock.h>
-#include <mach/msm_smsm.h>
-#include "smd_private.h"
+#include <mach/msm_smem.h>
+#include "smem_private.h"
#include "smp2p_private.h"
#include "smp2p_test_common.h"
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index d316496..0c02b51 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -27,8 +27,8 @@
#include <asm/mach-types.h>
#include <mach/socinfo.h>
+#include <mach/msm_smem.h>
-#include "smd_private.h"
#include "boot_stats.h"
#define BUILD_ID_LENGTH 32
@@ -361,6 +361,9 @@
/* krypton IDs */
[187] = MSM_CPU_KRYPTON,
+ /* FSM9900 ID */
+ [188] = FSM_CPU_9900,
+
/* Uninitialized IDs are not known to run Linux.
MSM_CPU_UNKNOWN is set to 0 to ensure these IDs are
considered as unknown CPU. */
diff --git a/arch/arm/mach-msm/spm_devices.c b/arch/arm/mach-msm/spm_devices.c
index 8e94b3a..fc05fce 100644
--- a/arch/arm/mach-msm/spm_devices.c
+++ b/arch/arm/mach-msm/spm_devices.c
@@ -392,7 +392,7 @@
};
struct mode_of of_l2_modes[] = {
- {"qcom,saw2-spm-cmd-ret", MSM_SPM_L2_MODE_RETENTION, 0},
+ {"qcom,saw2-spm-cmd-ret", MSM_SPM_L2_MODE_RETENTION, 1},
{"qcom,saw2-spm-cmd-gdhs", MSM_SPM_L2_MODE_GDHS, 1},
{"qcom,saw2-spm-cmd-pc", MSM_SPM_L2_MODE_POWER_COLLAPSE, 1},
};
diff --git a/arch/arm/mach-msm/subsystem_restart.c b/arch/arm/mach-msm/subsystem_restart.c
index 26f0210..c971896 100644
--- a/arch/arm/mach-msm/subsystem_restart.c
+++ b/arch/arm/mach-msm/subsystem_restart.c
@@ -938,6 +938,10 @@
struct subsys_device *subsys_dev = subsys;
pr_info("Error ready interrupt occured for %s\n",
subsys_dev->desc->name);
+
+ if (subsys_dev->desc->is_not_loadable)
+ return IRQ_HANDLED;
+
complete(&subsys_dev->err_ready);
return IRQ_HANDLED;
}
diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c
index 06a4c29..1ea0f2d 100644
--- a/arch/arm/mach-msm/timer.c
+++ b/arch/arm/mach-msm/timer.c
@@ -36,7 +36,8 @@
#include <mach/socinfo.h>
#if defined(CONFIG_MSM_SMD)
-#include "smd_private.h"
+#include <mach/msm_smem.h>
+#include <mach/msm_smsm.h>
#endif
#include "timer.h"
diff --git a/drivers/coresight/Makefile b/drivers/coresight/Makefile
index 0e2e2d9..2b14f86 100644
--- a/drivers/coresight/Makefile
+++ b/drivers/coresight/Makefile
@@ -2,7 +2,6 @@
# Makefile for CoreSight drivers.
#
obj-$(CONFIG_CORESIGHT) += coresight.o
-obj-$(CONFIG_OF) += of_coresight.o
obj-$(CONFIG_CORESIGHT_CTI) += coresight-cti.o
obj-$(CONFIG_CORESIGHT_CSR) += coresight-csr.o
obj-$(CONFIG_CORESIGHT_TMC) += coresight-tmc.o
diff --git a/drivers/coresight/coresight-tpiu.c b/drivers/coresight/coresight-tpiu.c
index 8597e29..53df0f9 100644
--- a/drivers/coresight/coresight-tpiu.c
+++ b/drivers/coresight/coresight-tpiu.c
@@ -548,7 +548,6 @@
prop = of_get_property(node, "qcom,vdd-voltage-level", &len);
if (!prop || (len != (2 * sizeof(__be32)))) {
- of_node_put(reg_node);
dev_err(dev, "sdc voltage levels not specified\n");
} else {
drvdata->reg_low = be32_to_cpup(&prop[0]);
@@ -557,7 +556,6 @@
prop = of_get_property(node, "qcom,vdd-current-level", &len);
if (!prop || (len != (2 * sizeof(__be32)))) {
- of_node_put(reg_node);
dev_err(dev, "sdc current levels not specified\n");
} else {
drvdata->reg_lpm = be32_to_cpup(&prop[0]);
@@ -633,6 +631,8 @@
for (i = 0; i < drvdata->seta_gpiocnt; i++)
drvdata->seta_cfgs[i].dir = seta_cfgs[i];
+
+ devm_kfree(dev, seta_cfgs);
} else {
dev_err(dev, "seta gpios not specified\n");
}
@@ -699,6 +699,8 @@
for (i = 0; i < drvdata->setb_gpiocnt; i++)
drvdata->setb_cfgs[i].dir = setb_cfgs[i];
+
+ devm_kfree(dev, setb_cfgs);
} else {
dev_err(dev, "setb gpios not specified\n");
}
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index bf022ac..a506aa8 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -878,9 +878,10 @@
freq_next = dbs_tuners_ins.sync_freq;
if (max_load_freq >
- (dbs_tuners_ins.up_threshold_multi_core -
+ ((dbs_tuners_ins.up_threshold_multi_core -
dbs_tuners_ins.down_differential_multi_core) *
- policy->cur)
+ policy->cur) &&
+ freq_next < dbs_tuners_ins.optimal_freq)
freq_next = dbs_tuners_ins.optimal_freq;
}
diff --git a/drivers/crypto/msm/qce50.c b/drivers/crypto/msm/qce50.c
index 58fa5c9..2b70d3f 100644
--- a/drivers/crypto/msm/qce50.c
+++ b/drivers/crypto/msm/qce50.c
@@ -717,6 +717,9 @@
bool sha1 = false;
uint32_t auth_cfg = 0;
+ /* clear status */
+ writel_relaxed(0, pce_dev->iobase + CRYPTO_STATUS_REG);
+
writel_relaxed(pce_dev->reg.crypto_cfg_be, (pce_dev->iobase +
CRYPTO_CONFIG_REG));
/*
@@ -896,6 +899,9 @@
uint32_t ivsize = creq->ivsize;
int i;
+ /* clear status */
+ writel_relaxed(0, pce_dev->iobase + CRYPTO_STATUS_REG);
+
writel_relaxed(pce_dev->reg.crypto_cfg_be, (pce_dev->iobase +
CRYPTO_CONFIG_REG));
/*
@@ -1213,6 +1219,7 @@
{
struct aead_request *areq;
unsigned char mac[SHA256_DIGEST_SIZE];
+ uint32_t status;
areq = (struct aead_request *) pce_dev->areq;
if (areq->src != areq->dst) {
@@ -1227,16 +1234,55 @@
/* check MAC */
memcpy(mac, (char *)(&pce_dev->ce_sps.result->auth_iv[0]),
SHA256_DIGEST_SIZE);
+
+ /* read status before unlock */
+ status = readl_relaxed(pce_dev->iobase + CRYPTO_STATUS_REG);
+
if (_qce_unlock_other_pipes(pce_dev))
return -EINVAL;
if (pce_dev->mode == QCE_MODE_CCM) {
- uint32_t result_status;
+ int32_t result_status;
+
+ /*
+ * Don't use result dump status. The operation may not
+ * be complete.
+ * Instead, use the status we just read of device.
+ * In case, we need to use result_status from result
+ * dump the result_status needs to be byte swapped,
+ * since we set the device to little endian.
+ */
+
result_status = pce_dev->ce_sps.result->status;
- result_status &= (1 << CRYPTO_MAC_FAILED);
- result_status |= (pce_dev->ce_sps.consumer_status |
- pce_dev->ce_sps.producer_status);
+ pce_dev->ce_sps.result->status = 0;
+
+ if (status & ((1 << CRYPTO_SW_ERR) | (1 << CRYPTO_AXI_ERR)
+ | (1 << CRYPTO_HSD_ERR))) {
+
+ pr_err("aead operation error. Status %x\n",
+ status);
+ result_status = -ENXIO;
+ } else if (pce_dev->ce_sps.consumer_status |
+ pce_dev->ce_sps.producer_status) {
+ pr_err("aead sps operation error. sps status %x %x\n",
+ pce_dev->ce_sps.consumer_status,
+ pce_dev->ce_sps.producer_status);
+ result_status = -ENXIO;
+ } else if ((status & (1 << CRYPTO_OPERATION_DONE)) == 0) {
+ pr_err("aead operation not done? Status %x, sps status %x %x\n",
+ status,
+ pce_dev->ce_sps.consumer_status,
+ pce_dev->ce_sps.producer_status);
+ result_status = -ENXIO;
+
+ } else if (status & (1 << CRYPTO_MAC_FAILED)) {
+ result_status = -EBADMSG;
+ } else {
+ result_status = 0;
+ }
+
pce_dev->qce_cb(areq, mac, NULL, result_status);
+
} else {
uint32_t ivsize = 0;
struct crypto_aead *aead;
@@ -1260,6 +1306,8 @@
struct ahash_request *areq;
unsigned char digest[SHA256_DIGEST_SIZE];
uint32_t bytecount32[2];
+ int32_t result_status = pce_dev->ce_sps.result->status;
+ uint32_t status;
areq = (struct ahash_request *) pce_dev->areq;
qce_dma_unmap_sg(pce_dev->pdev, areq->src, pce_dev->src_nents,
@@ -1269,10 +1317,39 @@
_byte_stream_to_net_words(bytecount32,
(unsigned char *)pce_dev->ce_sps.result->auth_byte_count,
2 * CRYPTO_REG_SIZE);
+
+ /* read status before unlock */
+ status = readl_relaxed(pce_dev->iobase + CRYPTO_STATUS_REG);
+
if (_qce_unlock_other_pipes(pce_dev))
return -EINVAL;
+
+ /*
+ * Don't use result dump status. The operation may not be complete.
+ * Instead, use the status we just read of device.
+ * In case, we need to use result_status from result
+ * dump the result_status needs to be byte swapped,
+ * since we set the device to little endian.
+ */
+
+ if (status & ((1 << CRYPTO_SW_ERR) | (1 << CRYPTO_AXI_ERR)
+ | (1 << CRYPTO_HSD_ERR))) {
+
+ pr_err("sha operation error. Status %x\n", status);
+ result_status = -ENXIO;
+ } else if (pce_dev->ce_sps.consumer_status) {
+ pr_err("sha sps operation error. sps status %x\n",
+ pce_dev->ce_sps.consumer_status);
+ result_status = -ENXIO;
+ } else if ((status & (1 << CRYPTO_OPERATION_DONE)) == 0) {
+ pr_err("sha operation not done? Status %x, sps status %x\n",
+ status, pce_dev->ce_sps.consumer_status);
+ result_status = -ENXIO;
+ } else {
+ result_status = 0;
+ }
pce_dev->qce_cb(areq, digest, (char *)bytecount32,
- pce_dev->ce_sps.consumer_status);
+ result_status);
return 0;
};
@@ -1280,6 +1357,8 @@
{
struct ablkcipher_request *areq;
unsigned char iv[NUM_OF_CRYPTO_CNTR_IV_REG * CRYPTO_REG_SIZE];
+ uint32_t status;
+ int32_t result_status;
areq = (struct ablkcipher_request *) pce_dev->areq;
@@ -1290,13 +1369,46 @@
qce_dma_unmap_sg(pce_dev->pdev, areq->src, pce_dev->src_nents,
(areq->src == areq->dst) ? DMA_BIDIRECTIONAL :
DMA_TO_DEVICE);
+
+ /* read status before unlock */
+ status = readl_relaxed(pce_dev->iobase + CRYPTO_STATUS_REG);
+
if (_qce_unlock_other_pipes(pce_dev))
return -EINVAL;
+ /*
+ * Don't use result dump status. The operation may not be complete.
+ * Instead, use the status we just read of device.
+ * In case, we need to use result_status from result
+ * dump the result_status needs to be byte swapped,
+ * since we set the device to little endian.
+ */
+ if (status & ((1 << CRYPTO_SW_ERR) | (1 << CRYPTO_AXI_ERR)
+ | (1 << CRYPTO_HSD_ERR))) {
+ pr_err("ablk_cipher operation error. Status %x\n",
+ status);
+ result_status = -ENXIO;
+ } else if (pce_dev->ce_sps.consumer_status |
+ pce_dev->ce_sps.producer_status) {
+ pr_err("ablk_cipher sps operation error. sps status %x %x\n",
+ pce_dev->ce_sps.consumer_status,
+ pce_dev->ce_sps.producer_status);
+ result_status = -ENXIO;
+ } else if ((status & (1 << CRYPTO_OPERATION_DONE)) == 0) {
+ pr_err("ablk_cipher operation not done? Status %x, sps status %x %x\n",
+ status,
+ pce_dev->ce_sps.consumer_status,
+ pce_dev->ce_sps.producer_status);
+ result_status = -ENXIO;
+
+ } else {
+ result_status = 0;
+ }
+
if (pce_dev->mode == QCE_MODE_ECB) {
pce_dev->qce_cb(areq, NULL, NULL,
pce_dev->ce_sps.consumer_status |
- pce_dev->ce_sps.producer_status);
+ result_status);
} else {
if (pce_dev->ce_sps.minor_version == 0) {
if (pce_dev->mode == QCE_MODE_CBC) {
@@ -1342,9 +1454,7 @@
(char *)(pce_dev->ce_sps.result->encr_cntr_iv),
sizeof(iv));
}
- pce_dev->qce_cb(areq, NULL, iv,
- pce_dev->ce_sps.consumer_status |
- pce_dev->ce_sps.producer_status);
+ pce_dev->qce_cb(areq, NULL, iv, result_status);
}
return 0;
};
@@ -1993,6 +2103,9 @@
break;
}
+ /* clear status register */
+ qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_STATUS_REG, 0, NULL);
+
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
pdev->reg.crypto_cfg_be, &pcl_info->crypto_cfg);
@@ -2037,13 +2150,9 @@
if (mode == QCE_MODE_XTS) {
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_SIZE_REG,
0, &pcl_info->auth_seg_size);
- qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_CFG_REG,
- 0, &pcl_info->auth_seg_size);
} else {
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_SIZE_REG,
0, &pcl_info->auth_seg_size);
- qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_CFG_REG,
- 0, &pcl_info->auth_seg_size);
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_START_REG,
0, &pcl_info->auth_seg_size);
}
@@ -2130,6 +2239,9 @@
break;
}
+ /* clear status register */
+ qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_STATUS_REG, 0, NULL);
+
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
pdev->reg.crypto_cfg_be, &pcl_info->crypto_cfg);
@@ -2156,13 +2268,7 @@
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CNTR1_IV1_REG, 0,
NULL);
}
- /* Add dummy to align size to burst-size multiple */
- if (!mode_cbc) {
- qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_SIZE_REG,
- 0, &pcl_info->auth_seg_size);
- qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_CFG_REG,
- 0, &pcl_info->auth_seg_size);
- }
+
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
pdev->reg.crypto_cfg_le, NULL);
@@ -2206,10 +2312,13 @@
auth_cfg = pdev->reg.auth_cfg_sha1;
iv_reg = 5;
+
+ /* clear status register */
+ qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_STATUS_REG,
+ 0, NULL);
+
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
pdev->reg.crypto_cfg_be, &pcl_info->crypto_cfg);
- qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_CFG_REG,
- 0, NULL);
break;
case QCE_HASH_SHA256:
@@ -2218,13 +2327,16 @@
auth_cfg = pdev->reg.auth_cfg_sha256;
iv_reg = 8;
+
+ /* clear status register */
+ qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_STATUS_REG,
+ 0, NULL);
+
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
pdev->reg.crypto_cfg_be, &pcl_info->crypto_cfg);
/* 1 dummy write */
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_SIZE_REG,
0, NULL);
- qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_CFG_REG,
- 0, NULL);
break;
case QCE_HASH_SHA1_HMAC:
cmdlistptr->auth_sha1_hmac.cmdlist = (uint32_t)ce_vaddr;
@@ -2233,10 +2345,13 @@
auth_cfg = pdev->reg.auth_cfg_hmac_sha1;
key_reg = 16;
iv_reg = 5;
+
+ /* clear status register */
+ qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_STATUS_REG,
+ 0, NULL);
+
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
pdev->reg.crypto_cfg_be, &pcl_info->crypto_cfg);
- qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_CFG_REG,
- 0, NULL);
break;
case QCE_AEAD_SHA1_HMAC:
cmdlistptr->aead_sha1_hmac.cmdlist = (uint32_t)ce_vaddr;
@@ -2245,13 +2360,16 @@
auth_cfg = pdev->reg.auth_cfg_aead_sha1_hmac;
key_reg = 16;
iv_reg = 5;
+
+ /* clear status register */
+ qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_STATUS_REG,
+ 0, NULL);
+
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
pdev->reg.crypto_cfg_be, &pcl_info->crypto_cfg);
/* 1 dummy write */
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_SIZE_REG,
0, NULL);
- qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_CFG_REG,
- 0, NULL);
break;
case QCE_HASH_SHA256_HMAC:
cmdlistptr->auth_sha256_hmac.cmdlist = (uint32_t)ce_vaddr;
@@ -2261,13 +2379,15 @@
key_reg = 16;
iv_reg = 8;
+ /* clear status register */
+ qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_STATUS_REG, 0,
+ NULL);
+
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
pdev->reg.crypto_cfg_be, &pcl_info->crypto_cfg);
/* 1 dummy write */
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_SIZE_REG,
0, NULL);
- qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_CFG_REG,
- 0, NULL);
break;
case QCE_HASH_AES_CMAC:
if (key_128 == true) {
@@ -2285,13 +2405,16 @@
auth_cfg = pdev->reg.auth_cfg_cmac_256;
key_reg = 8;
}
+
+ /* clear status register */
+ qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_STATUS_REG, 0,
+ NULL);
+
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
pdev->reg.crypto_cfg_be, &pcl_info->crypto_cfg);
/* 1 dummy write */
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_SIZE_REG,
0, NULL);
- qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_CFG_REG,
- 0, NULL);
break;
default:
pr_err("Unknown algorithms %d received, exiting now\n", alg);
@@ -2395,10 +2518,13 @@
key_reg = 8;
}
+
+ /* clear status register */
+ qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_STATUS_REG, 0, NULL);
+
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
pdev->reg.crypto_cfg_be, &pcl_info->crypto_cfg);
- qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_SIZE_REG, 0, NULL);
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_CFG_REG, 0, NULL);
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_START_REG, 0,
NULL);
diff --git a/drivers/crypto/msm/qcryptohw_50.h b/drivers/crypto/msm/qcryptohw_50.h
index 1be2702..e93e25c 100644
--- a/drivers/crypto/msm/qcryptohw_50.h
+++ b/drivers/crypto/msm/qcryptohw_50.h
@@ -297,6 +297,7 @@
#define CRYPTO_DOUT_SIZE_AVAIL_MASK (0x1F << CRYPTO_DOUT_SIZE_AVAIL)
#define CRYPTO_DIN_SIZE_AVAIL 21 /* bit 21-25 */
#define CRYPTO_DIN_SIZE_AVAIL_MASK (0x1F << CRYPTO_DIN_SIZE_AVAIL)
+#define CRYPTO_HSD_ERR 20
#define CRYPTO_ACCESS_VIOL 19
#define CRYPTO_PIPE_ACTIVE_ERR 18
#define CRYPTO_CFG_CHNG_ERR 17
diff --git a/drivers/gpio/gpio-msm-v1.c b/drivers/gpio/gpio-msm-v1.c
index f28ebb4..058a3f9 100644
--- a/drivers/gpio/gpio-msm-v1.c
+++ b/drivers/gpio/gpio-msm-v1.c
@@ -1,7 +1,7 @@
/* linux/arch/arm/mach-msm/gpio.c
*
* Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -24,7 +24,7 @@
#include <asm/mach/irq.h>
#include <mach/gpiomux.h>
#include <mach/msm_iomap.h>
-#include <mach/msm_smsm.h>
+#include <mach/msm_smem.h>
#include <mach/proc_comm.h>
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index e80721a..3ee9e4e 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -194,6 +194,7 @@
int snapshot_maxsize; /* Max size of the snapshot region */
int snapshot_size; /* Current size of the snapshot region */
u32 snapshot_timestamp; /* Timestamp of the last valid snapshot */
+ u32 snapshot_faultcount; /* Total number of faults since boot */
int snapshot_frozen; /* 1 if the snapshot output is frozen until
it gets read by the user. This avoids
losing the output on multiple hangs */
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index e071650..52340cc 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -1454,6 +1454,8 @@
}
if (ret == 0)
device->active_cnt++;
+ trace_kgsl_active_count(device,
+ (unsigned long) __builtin_return_address(0));
return ret;
}
EXPORT_SYMBOL(kgsl_active_count_get);
@@ -1482,6 +1484,8 @@
}
device->active_cnt++;
+ trace_kgsl_active_count(device,
+ (unsigned long) __builtin_return_address(0));
return 0;
}
EXPORT_SYMBOL(kgsl_active_count_get_light);
@@ -1504,6 +1508,8 @@
kgsl_pwrscale_idle(device);
if (device->active_cnt > 1) {
device->active_cnt--;
+ trace_kgsl_active_count(device,
+ (unsigned long) __builtin_return_address(0));
return;
}
@@ -1520,6 +1526,8 @@
}
device->active_cnt--;
+ trace_kgsl_active_count(device,
+ (unsigned long) __builtin_return_address(0));
if (device->active_cnt == 0)
complete(&device->suspend_gate);
}
diff --git a/drivers/gpu/msm/kgsl_snapshot.c b/drivers/gpu/msm/kgsl_snapshot.c
index f09c623..6fcd912 100644
--- a/drivers/gpu/msm/kgsl_snapshot.c
+++ b/drivers/gpu/msm/kgsl_snapshot.c
@@ -536,6 +536,10 @@
void *snapshot;
struct timespec boot;
+ /* increment the hang count (on hang) for good book keeping */
+ if (hang)
+ device->snapshot_faultcount++;
+
/*
* The first hang is always the one we are interested in. To
* avoid a subsequent hang blowing away the first, the snapshot
@@ -674,6 +678,22 @@
return itr.write;
}
+/* Show the total number of hangs since device boot */
+static ssize_t faultcount_show(struct kgsl_device *device, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n", device->snapshot_faultcount);
+}
+
+/* Reset the total number of hangs since device boot */
+static ssize_t faultcount_store(struct kgsl_device *device, const char *buf,
+ size_t count)
+{
+ if (device && count > 0)
+ device->snapshot_faultcount = 0;
+
+ return count;
+}
+
/* Show the timestamp of the last collected snapshot */
static ssize_t timestamp_show(struct kgsl_device *device, char *buf)
{
@@ -709,6 +729,7 @@
SNAPSHOT_ATTR(trigger, 0600, NULL, trigger_store);
SNAPSHOT_ATTR(timestamp, 0444, timestamp_show, NULL);
+SNAPSHOT_ATTR(faultcount, 0644, faultcount_show, faultcount_store);
static void snapshot_sysfs_release(struct kobject *kobj)
{
@@ -774,6 +795,7 @@
device->snapshot_maxsize = KGSL_SNAPSHOT_MEMSIZE;
device->snapshot_timestamp = 0;
+ device->snapshot_faultcount = 0;
INIT_LIST_HEAD(&device->snapshot_obj_list);
@@ -791,6 +813,10 @@
goto done;
ret = sysfs_create_file(&device->snapshot_kobj, &attr_timestamp.attr);
+ if (ret)
+ goto done;
+
+ ret = sysfs_create_file(&device->snapshot_kobj, &attr_faultcount.attr);
done:
return ret;
@@ -817,5 +843,6 @@
device->snapshot = NULL;
device->snapshot_maxsize = 0;
device->snapshot_timestamp = 0;
+ device->snapshot_faultcount = 0;
}
EXPORT_SYMBOL(kgsl_device_snapshot_close);
diff --git a/drivers/gpu/msm/kgsl_trace.h b/drivers/gpu/msm/kgsl_trace.h
index 5f7ee3c..08677ef 100644
--- a/drivers/gpu/msm/kgsl_trace.h
+++ b/drivers/gpu/msm/kgsl_trace.h
@@ -739,6 +739,30 @@
__entry->id, __entry->ts, __entry->age)
);
+TRACE_EVENT(kgsl_active_count,
+
+ TP_PROTO(struct kgsl_device *device, unsigned long ip),
+
+ TP_ARGS(device, ip),
+
+ TP_STRUCT__entry(
+ __string(device_name, device->name)
+ __field(unsigned int, count)
+ __field(unsigned long, ip)
+ ),
+
+ TP_fast_assign(
+ __assign_str(device_name, device->name);
+ __entry->count = device->active_cnt;
+ __entry->ip = ip;
+ ),
+
+ TP_printk(
+ "d_name=%s active_cnt=%x func=%pf",
+ __get_str(device_name), __entry->count, (void *) __entry->ip
+ )
+);
+
#endif /* _KGSL_TRACE_H */
/* This part must be outside protection */
diff --git a/drivers/hwmon/qpnp-adc-current.c b/drivers/hwmon/qpnp-adc-current.c
index 09fcd0e..f6ab3c2 100644
--- a/drivers/hwmon/qpnp-adc-current.c
+++ b/drivers/hwmon/qpnp-adc-current.c
@@ -305,8 +305,9 @@
static int32_t qpnp_iadc_comp(int64_t *result, struct qpnp_iadc_comp comp,
int64_t die_temp)
{
- int64_t temp_var = 0, sign_coeff = 0, sys_gain_coeff = 0;
+ int64_t temp_var = 0, sign_coeff = 0, sys_gain_coeff = 0, old;
+ old = *result;
*result = *result * 1000000;
if (comp.revision == QPNP_IADC_VER_3_1) {
@@ -315,9 +316,12 @@
sys_gain_coeff = -QPNP_COEFF_6 * (comp.sys_gain - 128);
else
sys_gain_coeff = QPNP_COEFF_6 * comp.sys_gain;
+ } else if (comp.revision != QPNP_IADC_VER_3_0) {
+ /* unsupported revision, do not compensate */
+ *result = old;
+ return 0;
}
- comp.id = 0;
if (!comp.ext_rsense) {
/* internal rsense */
switch (comp.id) {
@@ -335,8 +339,8 @@
if (comp.revision == QPNP_IADC_VER_3_0)
temp_var = QPNP_COEFF_1 * (1000000 - temp_var);
else if (comp.revision == QPNP_IADC_VER_3_1)
- temp_var = (1000000 - temp_var);
- *result = div64_s64(*result, temp_var);
+ temp_var = 1000000 * (1000000 - temp_var);
+ *result = div64_s64(*result * 1000000, temp_var);
}
sign_coeff = *result < 0 ? QPNP_COEFF_7 : QPNP_COEFF_5;
@@ -353,6 +357,7 @@
}
*result = div64_s64(*result, temp_var);
}
+ pr_debug("%lld compensated into %lld\n", old, *result);
return 0;
}
diff --git a/drivers/hwmon/qpnp-adc-voltage.c b/drivers/hwmon/qpnp-adc-voltage.c
index cc7073e..4306b1d 100644
--- a/drivers/hwmon/qpnp-adc-voltage.c
+++ b/drivers/hwmon/qpnp-adc-voltage.c
@@ -83,6 +83,14 @@
#define QPNP_VADC_M1_LOW_THR_MSB 0x6a
#define QPNP_VADC_M1_HIGH_THR_LSB 0x6b
#define QPNP_VADC_M1_HIGH_THR_MSB 0x6c
+#define QPNP_VADC_ACCESS 0xd0
+#define QPNP_VADC_ACCESS_DATA 0xa5
+#define QPNP_VADC_PERH_RESET_CTL3 0xda
+#define QPNP_FOLLOW_OTST2_RB BIT(3)
+#define QPNP_FOLLOW_WARM_RB BIT(2)
+#define QPNP_FOLLOW_SHUTDOWN1_RB BIT(1)
+#define QPNP_FOLLOW_SHUTDOWN2_RB BIT(0)
+
#define QPNP_INT_TEST_VAL 0xE1
#define QPNP_VADC_DATA0 0x60
@@ -150,6 +158,40 @@
return 0;
}
+static int32_t qpnp_vadc_warm_rst_configure(void)
+{
+ int rc = 0;
+ u8 data = 0;
+
+ rc = qpnp_vadc_write_reg(QPNP_VADC_ACCESS, QPNP_VADC_ACCESS_DATA);
+ if (rc < 0) {
+ pr_err("VADC write access failed\n");
+ return rc;
+ }
+
+ rc = qpnp_vadc_read_reg(QPNP_VADC_PERH_RESET_CTL3, &data);
+ if (rc < 0) {
+ pr_err("VADC perh reset ctl3 read failed\n");
+ return rc;
+ }
+
+ rc = qpnp_vadc_write_reg(QPNP_VADC_ACCESS, QPNP_VADC_ACCESS_DATA);
+ if (rc < 0) {
+ pr_err("VADC write access failed\n");
+ return rc;
+ }
+
+ data |= QPNP_FOLLOW_WARM_RB;
+
+ rc = qpnp_vadc_write_reg(QPNP_VADC_PERH_RESET_CTL3, data);
+ if (rc < 0) {
+ pr_err("VADC perh reset ctl3 write failed\n");
+ return rc;
+ }
+
+ return 0;
+}
+
static int32_t qpnp_vadc_enable(bool state)
{
int rc = 0;
@@ -437,6 +479,7 @@
static int32_t qpnp_vbat_sns_comp(int64_t *result, u8 id, int64_t die_temp)
{
int64_t temp_var = 0;
+ int64_t old = *result;
if (die_temp < 25000)
return 0;
@@ -462,6 +505,7 @@
*result = *result * temp_var;
*result = div64_s64(*result, 1000000);
+ pr_debug("%lld compensated into %lld\n", old, *result);
return 0;
}
@@ -1124,6 +1168,12 @@
}
vadc->id = fab_id;
+ rc = qpnp_vadc_warm_rst_configure();
+ if (rc < 0) {
+ pr_err("Setting perp reset on warm reset failed %d\n", rc);
+ return rc;
+ }
+
vadc->vadc_initialized = true;
vadc->vadc_iadc_sync_lock = false;
diff --git a/drivers/iommu/msm_iommu-v0.c b/drivers/iommu/msm_iommu-v0.c
index b92ec7f..06f4a0f 100644
--- a/drivers/iommu/msm_iommu-v0.c
+++ b/drivers/iommu/msm_iommu-v0.c
@@ -31,7 +31,7 @@
#include <mach/iommu_hw-v0.h>
#include <mach/msm_iommu_priv.h>
#include <mach/iommu.h>
-#include <mach/msm_smsm.h>
+#include <mach/msm_smem.h>
#define MRC(reg, processor, op1, crn, crm, op2) \
__asm__ __volatile__ ( \
diff --git a/drivers/media/dvb/dvb-core/demux.h b/drivers/media/dvb/dvb-core/demux.h
index fcade49..2c2b339 100644
--- a/drivers/media/dvb/dvb-core/demux.h
+++ b/drivers/media/dvb/dvb-core/demux.h
@@ -75,7 +75,8 @@
DMX_FIFO_ERROR, /* Receiver FIFO overrun */
DMX_MISSED_ERROR, /* Receiver missed packet */
DMX_OK_DECODER_BUF, /* Received OK, new ES data in decoder buffer */
- DMX_OK_IDX /* Received OK, new index event */
+ DMX_OK_IDX, /* Received OK, new index event */
+ DMX_OK_SCRAMBLING_STATUS, /* Received OK, new scrambling status */
} ;
@@ -135,6 +136,7 @@
} marker;
struct dmx_index_event_info idx_event;
+ struct dmx_scrambling_status_event_info scrambling_bits;
};
};
@@ -250,6 +252,7 @@
int (*ts_insertion_terminate)(struct dmx_ts_feed *feed);
int (*ts_insertion_insert_buffer)(struct dmx_ts_feed *feed,
char *data, size_t size);
+ int (*get_scrambling_bits)(struct dmx_ts_feed *feed, u8 *value);
};
/*--------------------------------------------------------------------------*/
@@ -300,6 +303,7 @@
struct dmx_secure_mode *sec_mode);
int (*oob_command) (struct dmx_section_feed *feed,
struct dmx_oob_command *cmd);
+ int (*get_scrambling_bits)(struct dmx_section_feed *feed, u8 *value);
};
/*--------------------------------------------------------------------------*/
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index 2a750a6..6734da8 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -1796,6 +1796,35 @@
return 0;
}
+static int dvb_dmxdev_get_scrambling_bits(struct dmxdev_filter *filter,
+ struct dmx_scrambling_bits *scrambling_bits)
+{
+ struct dmxdev_feed *feed;
+
+ if (!scrambling_bits ||
+ (filter->state != DMXDEV_STATE_GO))
+ return -EINVAL;
+
+ if (filter->type == DMXDEV_TYPE_SEC) {
+ if (filter->feed.sec.feed->get_scrambling_bits)
+ return filter->feed.sec.feed->get_scrambling_bits(
+ filter->feed.sec.feed,
+ &scrambling_bits->value);
+ return -EINVAL;
+ }
+
+ list_for_each_entry(feed, &filter->feed.ts, next) {
+ if (feed->pid == scrambling_bits->pid) {
+ if (feed->ts->get_scrambling_bits)
+ return feed->ts->get_scrambling_bits(feed->ts,
+ &scrambling_bits->value);
+ return -EINVAL;
+ }
+ }
+
+ return -EINVAL;
+}
+
static void dvb_dmxdev_ts_insertion_work(struct work_struct *worker)
{
struct ts_insertion_buffer *ts_buffer =
@@ -2519,6 +2548,13 @@
dvb_dmxdev_add_event(&dmxdevfilter->events, &event);
spin_unlock(&dmxdevfilter->dev->lock);
wake_up_all(&dmxdevfilter->buffer.queue);
+ } else if (dmx_data_ready->status == DMX_OK_SCRAMBLING_STATUS) {
+ event.type = DMX_EVENT_SCRAMBLING_STATUS_CHANGE;
+ event.params.scrambling_status =
+ dmx_data_ready->scrambling_bits;
+ dvb_dmxdev_add_event(&dmxdevfilter->events, &event);
+ spin_unlock(&dmxdevfilter->dev->lock);
+ wake_up_all(&dmxdevfilter->buffer.queue);
} else {
spin_unlock(&dmxdevfilter->dev->lock);
}
@@ -2635,6 +2671,16 @@
return 0;
}
+ if (dmx_data_ready->status == DMX_OK_SCRAMBLING_STATUS) {
+ event.type = DMX_EVENT_SCRAMBLING_STATUS_CHANGE;
+ event.params.scrambling_status =
+ dmx_data_ready->scrambling_bits;
+ dvb_dmxdev_add_event(events, &event);
+ spin_unlock(&dmxdevfilter->dev->lock);
+ wake_up_all(&buffer->queue);
+ return 0;
+ }
+
if (dmx_data_ready->status == DMX_OK_DECODER_BUF) {
event.type = DMX_EVENT_NEW_ES_DATA;
event.params.es_data.buf_handle = dmx_data_ready->buf.handle;
@@ -3938,6 +3984,15 @@
mutex_unlock(&dmxdevfilter->mutex);
break;
+ case DMX_GET_SCRAMBLING_BITS:
+ if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+ mutex_unlock(&dmxdev->mutex);
+ return -ERESTARTSYS;
+ }
+ ret = dvb_dmxdev_get_scrambling_bits(dmxdevfilter, parg);
+ mutex_unlock(&dmxdevfilter->mutex);
+ break;
+
default:
ret = -EINVAL;
break;
@@ -4193,6 +4248,7 @@
struct dmxdev_filter *filter;
int active_count = 0;
struct dmx_buffer_status buffer_status;
+ struct dmx_scrambling_bits scrambling_bits;
const char *pes_feeds[] = {"DEC", "PES", "DVR", "REC"};
if (!dmxdev)
@@ -4209,23 +4265,32 @@
seq_printf(s, "type: SEC, ");
seq_printf(s, "PID %04d ",
filter->params.sec.pid);
+ scrambling_bits.pid = filter->params.sec.pid;
} else {
seq_printf(s, "type: %s, ",
pes_feeds[filter->params.pes.output]);
seq_printf(s, "PID: %04d ",
filter->params.pes.pid);
+ scrambling_bits.pid = filter->params.pes.pid;
}
+ dvb_dmxdev_get_scrambling_bits(filter,
+ &scrambling_bits);
+
if (0 == dvb_dmxdev_get_buffer_status(
filter, &buffer_status)) {
seq_printf(s, "size: %08d, ",
buffer_status.size);
seq_printf(s, "fullness: %08d, ",
buffer_status.fullness);
- seq_printf(s, "error: %d\n",
+ seq_printf(s, "error: %d, ",
buffer_status.error);
+ seq_printf(s, "scramble: %d\n",
+ scrambling_bits.value);
+
} else {
- seq_printf(s, "\n");
+ seq_printf(s, "scramble: %d\n",
+ scrambling_bits.value);
}
}
}
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
index 9844c64..8caa9dd 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -164,6 +164,11 @@
return ((buf[1] & 0x1f) << 8) + buf[2];
}
+static inline u16 ts_scrambling_ctrl(const u8 *buf)
+{
+ return (buf[3] >> 6) & 0x3;
+}
+
static inline u8 payload(const u8 *tsp)
{
if (!(tsp[3] & 0x10)) // no payload?
@@ -1287,6 +1292,32 @@
static inline void dvb_dmx_swfilter_packet_type(struct dvb_demux_feed *feed,
const u8 *buf, const u8 timestamp[TIMESTAMP_LEN])
{
+ u16 pid = ts_pid(buf);
+ u8 scrambling_bits = ts_scrambling_ctrl(buf);
+ struct dmx_data_ready dmx_data_ready;
+
+ /*
+ * Notify on scrambling status change only when we move
+ * from clear (0) to non-clear and vise-versa
+ */
+ if ((scrambling_bits && !feed->scrambling_bits) ||
+ (!scrambling_bits && feed->scrambling_bits)) {
+ dmx_data_ready.status = DMX_OK_SCRAMBLING_STATUS;
+ dmx_data_ready.data_length = 0;
+ dmx_data_ready.scrambling_bits.pid = pid;
+ dmx_data_ready.scrambling_bits.old_value =
+ feed->scrambling_bits;
+ dmx_data_ready.scrambling_bits.new_value = scrambling_bits;
+
+ if (feed->type == DMX_TYPE_SEC)
+ feed->data_ready_cb.sec(&feed->filter->filter,
+ &dmx_data_ready);
+ else
+ feed->data_ready_cb.ts(&feed->feed.ts, &dmx_data_ready);
+ }
+
+ feed->scrambling_bits = scrambling_bits;
+
switch (feed->type) {
case DMX_TYPE_TS:
if (!feed->feed.ts.is_filtering)
@@ -2047,6 +2078,7 @@
}
feed->first_cc = 1;
+ feed->scrambling_bits = 0;
if ((feed->ts_type & TS_PACKET) &&
!(feed->ts_type & TS_PAYLOAD_ONLY)) {
@@ -2302,6 +2334,25 @@
return ret;
}
+static int dvbdmx_ts_get_scrambling_bits(struct dmx_ts_feed *ts_feed,
+ u8 *value)
+{
+ 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 -EINVAL;
+ }
+
+ *value = feed->scrambling_bits;
+ spin_unlock(&demux->lock);
+
+ return 0;
+}
+
static int dvbdmx_ts_insertion_insert_buffer(struct dmx_ts_feed *ts_feed,
char *data, size_t size)
{
@@ -2391,6 +2442,7 @@
(*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)->get_scrambling_bits = dvbdmx_ts_get_scrambling_bits;
(*ts_feed)->ts_insertion_init = NULL;
(*ts_feed)->ts_insertion_terminate = NULL;
(*ts_feed)->ts_insertion_insert_buffer =
@@ -2557,6 +2609,7 @@
dvbdmxfeed->feed.sec.secbufp = 0;
dvbdmxfeed->feed.sec.seclen = 0;
dvbdmxfeed->first_cc = 1;
+ dvbdmxfeed->scrambling_bits = 0;
if (!dvbdmx->start_feed) {
mutex_unlock(&dvbdmx->mutex);
@@ -2723,6 +2776,25 @@
return ret;
}
+static int dvbdmx_section_get_scrambling_bits(
+ struct dmx_section_feed *section_feed, u8 *value)
+{
+ struct dvb_demux_feed *feed = (struct dvb_demux_feed *)section_feed;
+ struct dvb_demux *demux = feed->demux;
+
+ spin_lock(&demux->lock);
+
+ if (!section_feed->is_filtering) {
+ spin_unlock(&demux->lock);
+ return -EINVAL;
+ }
+
+ *value = feed->scrambling_bits;
+ spin_unlock(&demux->lock);
+
+ return 0;
+}
+
static int dvbdmx_allocate_section_feed(struct dmx_demux *demux,
struct dmx_section_feed **feed,
dmx_section_cb callback)
@@ -2763,6 +2835,7 @@
(*feed)->notify_data_read = NULL;
(*feed)->set_secure_mode = dmx_section_set_secure_mode;
(*feed)->oob_command = dvbdmx_section_feed_oob_cmd;
+ (*feed)->get_scrambling_bits = dvbdmx_section_get_scrambling_bits;
mutex_unlock(&dvbdmx->mutex);
return 0;
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.h b/drivers/media/dvb/dvb-core/dvb_demux.h
index 879aad2..9fb1a12 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.h
+++ b/drivers/media/dvb/dvb-core/dvb_demux.h
@@ -187,6 +187,8 @@
int first_cc;
int pusi_seen; /* prevents feeding of garbage from previous section */
+ u8 scrambling_bits;
+
struct dvb_demux_rec_info *rec_info;
u64 prev_tsp_num;
u64 prev_stc;
diff --git a/drivers/media/platform/msm/camera_v2/Kconfig b/drivers/media/platform/msm/camera_v2/Kconfig
index d9552e2..52864ae 100644
--- a/drivers/media/platform/msm/camera_v2/Kconfig
+++ b/drivers/media/platform/msm/camera_v2/Kconfig
@@ -153,3 +153,8 @@
This module serves as the common driver
for the JPEG 1.0 encoder and decoder.
+config MSM_GEMINI
+ tristate "Qualcomm MSM Gemini JPEG engine support"
+ depends on MSMB_CAMERA && (ARCH_MSM7X30 || ARCH_MSM8X60 || ARCH_MSM8960)
+ ---help---
+ Enables support for the Gemini JPEG encoder engine for 8x60.
diff --git a/drivers/media/platform/msm/camera_v2/Makefile b/drivers/media/platform/msm/camera_v2/Makefile
index a1c5ea5..02eb3dd 100644
--- a/drivers/media/platform/msm/camera_v2/Makefile
+++ b/drivers/media/platform/msm/camera_v2/Makefile
@@ -16,3 +16,4 @@
obj-$(CONFIG_MSMB_JPEG) += jpeg_10/
obj-$(CONFIG_MSMB_CAMERA) += msm_buf_mgr/
obj-$(CONFIG_MSMB_CAMERA) += pproc/
+obj-$(CONFIG_MSMB_CAMERA) += gemini/
diff --git a/drivers/media/platform/msm/camera_v2/gemini/Makefile b/drivers/media/platform/msm/camera_v2/gemini/Makefile
new file mode 100644
index 0000000..74d7294
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/gemini/Makefile
@@ -0,0 +1,5 @@
+GCC_VERSION := $(shell $(CONFIG_SHELL) $(PWD)/scripts/gcc-version.sh $(CROSS_COMPILE)gcc)
+ccflags-y += -Idrivers/media/video/msm
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io
+
+obj-$(CONFIG_MSM_GEMINI) += msm_gemini_dev.o msm_gemini_sync.o msm_gemini_core.o msm_gemini_hw.o msm_gemini_platform.o
diff --git a/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_common.h b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_common.h
new file mode 100644
index 0000000..eefad6d
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_common.h
@@ -0,0 +1,39 @@
+/* Copyright (c) 2010,2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MSM_GEMINI_COMMON_H
+#define MSM_GEMINI_COMMON_H
+
+#define MSM_GEMINI_DEBUG
+#ifdef MSM_GEMINI_DEBUG
+#define GMN_DBG(fmt, args...) pr_debug(fmt, ##args)
+#else
+#define GMN_DBG(fmt, args...) do { } while (0)
+#endif
+
+#define GMN_PR_ERR pr_err
+
+enum GEMINI_MODE {
+ GEMINI_MODE_DISABLE,
+ GEMINI_MODE_OFFLINE,
+ GEMINI_MODE_REALTIME,
+ GEMINI_MODE_REALTIME_ROTATION
+};
+
+enum GEMINI_ROTATION {
+ GEMINI_ROTATION_0,
+ GEMINI_ROTATION_90,
+ GEMINI_ROTATION_180,
+ GEMINI_ROTATION_270
+};
+
+#endif /* MSM_GEMINI_COMMON_H */
diff --git a/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_core.c b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_core.c
new file mode 100644
index 0000000..88fa9e7
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_core.c
@@ -0,0 +1,250 @@
+/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include "msm_gemini_hw.h"
+#include "msm_gemini_core.h"
+#include "msm_gemini_platform.h"
+#include "msm_gemini_common.h"
+
+static struct msm_gemini_hw_pingpong fe_pingpong_buf;
+static struct msm_gemini_hw_pingpong we_pingpong_buf;
+static int we_pingpong_index;
+static int reset_done_ack;
+static spinlock_t reset_lock;
+static wait_queue_head_t reset_wait;
+
+int msm_gemini_core_reset(uint8_t op_mode, void *base, int size)
+{
+ unsigned long flags;
+ int rc = 0;
+ int tm = 500;
+ memset(&fe_pingpong_buf, 0, sizeof(fe_pingpong_buf));
+ fe_pingpong_buf.is_fe = 1;
+ we_pingpong_index = 0;
+ memset(&we_pingpong_buf, 0, sizeof(we_pingpong_buf));
+ spin_lock_irqsave(&reset_lock, flags);
+ reset_done_ack = 0;
+ msm_gemini_hw_reset(base, size);
+ spin_unlock_irqrestore(&reset_lock, flags);
+ rc = wait_event_interruptible_timeout(
+ reset_wait,
+ reset_done_ack,
+ msecs_to_jiffies(tm));
+
+ if (!reset_done_ack) {
+ GMN_DBG("%s: reset ACK failed %d", __func__, rc);
+ return -EBUSY;
+ }
+
+ GMN_DBG("%s: reset_done_ack rc %d", __func__, rc);
+ spin_lock_irqsave(&reset_lock, flags);
+ reset_done_ack = 0;
+ spin_unlock_irqrestore(&reset_lock, flags);
+
+ if (op_mode == MSM_GEMINI_MODE_REALTIME_ENCODE) {
+ /* Nothing needed for fe buffer cfg, config we only */
+ msm_gemini_hw_we_buffer_cfg(1);
+ } else {
+ /* Nothing needed for fe buffer cfg, config we only */
+ msm_gemini_hw_we_buffer_cfg(0);
+ }
+
+ /* @todo wait for reset done irq */
+
+ return 0;
+}
+
+void msm_gemini_core_release(int release_buf)
+{
+ int i = 0;
+ for (i = 0; i < 2; i++) {
+ if (we_pingpong_buf.buf_status[i] && release_buf)
+ msm_gemini_platform_p2v(we_pingpong_buf.buf[i].file,
+ &we_pingpong_buf.buf[i].handle);
+ we_pingpong_buf.buf_status[i] = 0;
+ }
+}
+
+void msm_gemini_core_init(void)
+{
+ init_waitqueue_head(&reset_wait);
+ spin_lock_init(&reset_lock);
+}
+
+int msm_gemini_core_fe_start(void)
+{
+ msm_gemini_hw_fe_start();
+ return 0;
+}
+
+/* fetch engine */
+int msm_gemini_core_fe_buf_update(struct msm_gemini_core_buf *buf)
+{
+ GMN_DBG("%s:%d] 0x%08x %d 0x%08x %d\n", __func__, __LINE__,
+ (int) buf->y_buffer_addr, buf->y_len,
+ (int) buf->cbcr_buffer_addr, buf->cbcr_len);
+ return msm_gemini_hw_pingpong_update(&fe_pingpong_buf, buf);
+}
+
+void *msm_gemini_core_fe_pingpong_irq(int gemini_irq_status, void *context)
+{
+ return msm_gemini_hw_pingpong_irq(&fe_pingpong_buf);
+}
+
+/* write engine */
+int msm_gemini_core_we_buf_update(struct msm_gemini_core_buf *buf)
+{
+ int rc;
+ GMN_DBG("%s:%d] 0x%08x 0x%08x %d\n", __func__, __LINE__,
+ (int) buf->y_buffer_addr, (int) buf->cbcr_buffer_addr,
+ buf->y_len);
+ we_pingpong_buf.buf_status[we_pingpong_index] = 0;
+ we_pingpong_index = (we_pingpong_index + 1)%2;
+ rc = msm_gemini_hw_pingpong_update(&we_pingpong_buf, buf);
+ return 0;
+}
+
+int msm_gemini_core_we_buf_reset(struct msm_gemini_hw_buf *buf)
+{
+ int i;
+ for (i = 0; i < 2; i++) {
+ if (we_pingpong_buf.buf[i].y_buffer_addr
+ == buf->y_buffer_addr)
+ we_pingpong_buf.buf_status[i] = 0;
+ }
+ return 0;
+}
+
+void *msm_gemini_core_we_pingpong_irq(int gemini_irq_status, void *context)
+{
+ GMN_DBG("%s:%d]\n", __func__, __LINE__);
+
+ return msm_gemini_hw_pingpong_irq(&we_pingpong_buf);
+}
+
+void *msm_gemini_core_framedone_irq(int gemini_irq_status, void *context)
+{
+ struct msm_gemini_hw_buf *buf_p;
+
+ GMN_DBG("%s:%d]\n", __func__, __LINE__);
+
+ buf_p = msm_gemini_hw_pingpong_active_buffer(&we_pingpong_buf);
+ if (buf_p) {
+ buf_p->framedone_len = msm_gemini_hw_encode_output_size();
+ GMN_DBG("%s:%d] framedone_len %d\n", __func__, __LINE__,
+ buf_p->framedone_len);
+ }
+
+ return buf_p;
+}
+
+void *msm_gemini_core_reset_ack_irq(int gemini_irq_status, void *context)
+{
+ /* @todo return the status back to msm_gemini_core_reset */
+ GMN_DBG("%s:%d]\n", __func__, __LINE__);
+ return NULL;
+}
+
+void *msm_gemini_core_err_irq(int gemini_irq_status, void *context)
+{
+ GMN_PR_ERR("%s:%d]\n", __func__, gemini_irq_status);
+ return NULL;
+}
+
+static int (*msm_gemini_irq_handler) (int, void *, void *);
+
+irqreturn_t msm_gemini_core_irq(int irq_num, void *context)
+{
+ void *data = NULL;
+ unsigned long flags;
+ int gemini_irq_status;
+
+ GMN_DBG("%s:%d] irq_num = %d\n", __func__, __LINE__, irq_num);
+
+ spin_lock_irqsave(&reset_lock, flags);
+ reset_done_ack = 1;
+ spin_unlock_irqrestore(&reset_lock, flags);
+ gemini_irq_status = msm_gemini_hw_irq_get_status();
+
+ GMN_DBG("%s:%d] gemini_irq_status = %0x\n", __func__, __LINE__,
+ gemini_irq_status);
+
+ /* For reset and framedone IRQs, clear all bits */
+ if (gemini_irq_status & 0x400) {
+ wake_up(&reset_wait);
+ msm_gemini_hw_irq_clear(HWIO_JPEG_IRQ_CLEAR_RMSK,
+ JPEG_IRQ_CLEAR_ALL);
+ } else if (gemini_irq_status & 0x1) {
+ msm_gemini_hw_irq_clear(HWIO_JPEG_IRQ_CLEAR_RMSK,
+ JPEG_IRQ_CLEAR_ALL);
+ } else {
+ msm_gemini_hw_irq_clear(HWIO_JPEG_IRQ_CLEAR_RMSK,
+ gemini_irq_status);
+ }
+
+ if (msm_gemini_hw_irq_is_frame_done(gemini_irq_status)) {
+ data = msm_gemini_core_framedone_irq(gemini_irq_status,
+ context);
+ if (msm_gemini_irq_handler)
+ msm_gemini_irq_handler(
+ MSM_GEMINI_HW_MASK_COMP_FRAMEDONE,
+ context, data);
+ }
+
+ if (msm_gemini_hw_irq_is_fe_pingpong(gemini_irq_status)) {
+ data = msm_gemini_core_fe_pingpong_irq(gemini_irq_status,
+ context);
+ if (msm_gemini_irq_handler)
+ msm_gemini_irq_handler(MSM_GEMINI_HW_MASK_COMP_FE,
+ context, data);
+ }
+
+ if (msm_gemini_hw_irq_is_we_pingpong(gemini_irq_status) &&
+ !msm_gemini_hw_irq_is_frame_done(gemini_irq_status)) {
+ data = msm_gemini_core_we_pingpong_irq(gemini_irq_status,
+ context);
+ if (msm_gemini_irq_handler)
+ msm_gemini_irq_handler(MSM_GEMINI_HW_MASK_COMP_WE,
+ context, data);
+ }
+
+ if (msm_gemini_hw_irq_is_reset_ack(gemini_irq_status)) {
+ data = msm_gemini_core_reset_ack_irq(gemini_irq_status,
+ context);
+ if (msm_gemini_irq_handler)
+ msm_gemini_irq_handler(
+ MSM_GEMINI_HW_MASK_COMP_RESET_ACK,
+ context, data);
+ }
+
+ /* Unexpected/unintended HW interrupt */
+ if (msm_gemini_hw_irq_is_err(gemini_irq_status)) {
+ data = msm_gemini_core_err_irq(gemini_irq_status, context);
+ if (msm_gemini_irq_handler)
+ msm_gemini_irq_handler(MSM_GEMINI_HW_MASK_COMP_ERR,
+ context, data);
+ }
+
+ return IRQ_HANDLED;
+}
+
+void msm_gemini_core_irq_install(int (*irq_handler) (int, void *, void *))
+{
+ msm_gemini_irq_handler = irq_handler;
+}
+
+void msm_gemini_core_irq_remove(void)
+{
+ msm_gemini_irq_handler = NULL;
+}
diff --git a/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_core.h b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_core.h
new file mode 100644
index 0000000..3aac25a
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_core.h
@@ -0,0 +1,35 @@
+/* Copyright (c) 2010,2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MSM_GEMINI_CORE_H
+#define MSM_GEMINI_CORE_H
+
+#include <linux/interrupt.h>
+#include "msm_gemini_hw.h"
+
+#define msm_gemini_core_buf msm_gemini_hw_buf
+
+irqreturn_t msm_gemini_core_irq(int irq_num, void *context);
+
+void msm_gemini_core_irq_install(int (*irq_handler) (int, void *, void *));
+void msm_gemini_core_irq_remove(void);
+
+int msm_gemini_core_fe_buf_update(struct msm_gemini_core_buf *buf);
+int msm_gemini_core_we_buf_update(struct msm_gemini_core_buf *buf);
+int msm_gemini_core_we_buf_reset(struct msm_gemini_hw_buf *buf);
+
+int msm_gemini_core_reset(uint8_t op_mode, void *base, int size);
+int msm_gemini_core_fe_start(void);
+
+void msm_gemini_core_release(int);
+void msm_gemini_core_init(void);
+#endif /* MSM_GEMINI_CORE_H */
diff --git a/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_dev.c b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_dev.c
new file mode 100644
index 0000000..13c1e11
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_dev.c
@@ -0,0 +1,265 @@
+/* Copyright (c) 2010-2011,2013 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/uaccess.h>
+#include <media/msm_gemini.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include <mach/board.h>
+#include "../msm.h"
+#include "msm_gemini_sync.h"
+#include "msm_gemini_common.h"
+
+#define MSM_GEMINI_NAME "gemini"
+#define MSM_GEMINI_DRV_NAME "msm_gemini"
+
+static int msm_gemini_open(struct inode *inode, struct file *filp)
+{
+ int rc;
+
+ struct msm_gemini_device *pgmn_dev = container_of(inode->i_cdev,
+ struct msm_gemini_device, cdev);
+ filp->private_data = pgmn_dev;
+
+ GMN_DBG("%s:%d]\n", __func__, __LINE__);
+
+ rc = __msm_gemini_open(pgmn_dev);
+
+ GMN_DBG("%s:%d] %s open_count = %d\n", __func__, __LINE__,
+ filp->f_path.dentry->d_name.name, pgmn_dev->open_count);
+
+ return rc;
+}
+
+static int msm_gemini_release(struct inode *inode, struct file *filp)
+{
+ int rc;
+
+ struct msm_gemini_device *pgmn_dev = filp->private_data;
+
+ GMN_DBG("%s:%d]\n", __func__, __LINE__);
+
+ rc = __msm_gemini_release(pgmn_dev);
+
+ GMN_DBG("%s:%d] %s open_count = %d\n", __func__, __LINE__,
+ filp->f_path.dentry->d_name.name, pgmn_dev->open_count);
+ return rc;
+}
+
+static long msm_gemini_ioctl(struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ int rc;
+ struct msm_gemini_device *pgmn_dev = filp->private_data;
+
+ GMN_DBG("%s:%d] cmd=%d pgmn_dev=0x%x arg=0x%x\n", __func__,
+ __LINE__, _IOC_NR(cmd), (uint32_t)pgmn_dev, (uint32_t)arg);
+
+ rc = __msm_gemini_ioctl(pgmn_dev, cmd, arg);
+
+ GMN_DBG("%s:%d]\n", __func__, __LINE__);
+ return rc;
+}
+
+static const struct file_operations msm_gemini_fops = {
+ .owner = THIS_MODULE,
+ .open = msm_gemini_open,
+ .release = msm_gemini_release,
+ .unlocked_ioctl = msm_gemini_ioctl,
+};
+
+static struct class *msm_gemini_class;
+static dev_t msm_gemini_devno;
+static struct msm_gemini_device *msm_gemini_device_p;
+
+int msm_gemini_subdev_init(struct v4l2_subdev *gemini_sd)
+{
+ int rc;
+ struct msm_gemini_device *pgmn_dev =
+ (struct msm_gemini_device *)gemini_sd->host_priv;
+
+ GMN_DBG("%s:%d: gemini_sd=0x%x pgmn_dev=0x%x\n",
+ __func__, __LINE__, (uint32_t)gemini_sd, (uint32_t)pgmn_dev);
+ rc = __msm_gemini_open(pgmn_dev);
+ GMN_DBG("%s:%d: rc=%d\n",
+ __func__, __LINE__, rc);
+ return rc;
+}
+
+static long msm_gemini_subdev_ioctl(struct v4l2_subdev *sd,
+ unsigned int cmd, void *arg)
+{
+ long rc;
+ struct msm_gemini_device *pgmn_dev =
+ (struct msm_gemini_device *)sd->host_priv;
+
+ GMN_DBG("%s: cmd=%d\n", __func__, cmd);
+
+ GMN_DBG("%s: pgmn_dev 0x%x", __func__, (uint32_t)pgmn_dev);
+
+ GMN_DBG("%s: Calling __msm_gemini_ioctl\n", __func__);
+
+ rc = __msm_gemini_ioctl(pgmn_dev, cmd, (unsigned long)arg);
+ GMN_DBG("%s: X\n", __func__);
+ return rc;
+}
+
+void msm_gemini_subdev_release(struct v4l2_subdev *gemini_sd)
+{
+ int rc;
+ struct msm_gemini_device *pgmn_dev =
+ (struct msm_gemini_device *)gemini_sd->host_priv;
+ GMN_DBG("%s:pgmn_dev=0x%x", __func__, (uint32_t)pgmn_dev);
+ rc = __msm_gemini_release(pgmn_dev);
+ GMN_DBG("%s:rc=%d", __func__, rc);
+}
+
+static const struct v4l2_subdev_core_ops msm_gemini_subdev_core_ops = {
+ .ioctl = msm_gemini_subdev_ioctl,
+};
+
+static const struct v4l2_subdev_ops msm_gemini_subdev_ops = {
+ .core = &msm_gemini_subdev_core_ops,
+};
+
+static int msm_gemini_init(struct platform_device *pdev)
+{
+ int rc = -1;
+ struct device *dev;
+
+ GMN_DBG("%s:\n", __func__);
+ msm_gemini_device_p = __msm_gemini_init(pdev);
+ if (msm_gemini_device_p == NULL) {
+ GMN_PR_ERR("%s: initialization failed\n", __func__);
+ goto fail;
+ }
+
+ v4l2_subdev_init(&msm_gemini_device_p->subdev, &msm_gemini_subdev_ops);
+ v4l2_set_subdev_hostdata(&msm_gemini_device_p->subdev,
+ msm_gemini_device_p);
+ GMN_DBG("%s: msm_gemini_device_p 0x%x", __func__,
+ (uint32_t)msm_gemini_device_p);
+ GMN_DBG("%s:gemini: platform_set_drvdata\n", __func__);
+ platform_set_drvdata(pdev, &msm_gemini_device_p->subdev);
+
+ rc = alloc_chrdev_region(&msm_gemini_devno, 0, 1, MSM_GEMINI_NAME);
+ if (rc < 0) {
+ GMN_PR_ERR("%s: failed to allocate chrdev\n", __func__);
+ goto fail_1;
+ }
+
+ if (!msm_gemini_class) {
+ msm_gemini_class = class_create(THIS_MODULE, MSM_GEMINI_NAME);
+ if (IS_ERR(msm_gemini_class)) {
+ rc = PTR_ERR(msm_gemini_class);
+ GMN_PR_ERR("%s: create device class failed\n",
+ __func__);
+ goto fail_2;
+ }
+ }
+
+ dev = device_create(msm_gemini_class, NULL,
+ MKDEV(MAJOR(msm_gemini_devno), MINOR(msm_gemini_devno)), NULL,
+ "%s%d", MSM_GEMINI_NAME, 0);
+
+ if (IS_ERR(dev)) {
+ GMN_PR_ERR("%s: error creating device\n", __func__);
+ rc = -ENODEV;
+ goto fail_3;
+ }
+
+ cdev_init(&msm_gemini_device_p->cdev, &msm_gemini_fops);
+ msm_gemini_device_p->cdev.owner = THIS_MODULE;
+ msm_gemini_device_p->cdev.ops =
+ (const struct file_operations *) &msm_gemini_fops;
+ rc = cdev_add(&msm_gemini_device_p->cdev, msm_gemini_devno, 1);
+ if (rc < 0) {
+ GMN_PR_ERR("%s: error adding cdev\n", __func__);
+ rc = -ENODEV;
+ goto fail_4;
+ }
+
+ GMN_DBG("%s %s: success\n", __func__, MSM_GEMINI_NAME);
+
+ return rc;
+
+fail_4:
+ device_destroy(msm_gemini_class, msm_gemini_devno);
+
+fail_3:
+ class_destroy(msm_gemini_class);
+
+fail_2:
+ unregister_chrdev_region(msm_gemini_devno, 1);
+
+fail_1:
+ __msm_gemini_exit(msm_gemini_device_p);
+
+fail:
+ return rc;
+}
+
+static void msm_gemini_exit(void)
+{
+ cdev_del(&msm_gemini_device_p->cdev);
+ device_destroy(msm_gemini_class, msm_gemini_devno);
+ class_destroy(msm_gemini_class);
+ unregister_chrdev_region(msm_gemini_devno, 1);
+
+ __msm_gemini_exit(msm_gemini_device_p);
+}
+
+static int __msm_gemini_probe(struct platform_device *pdev)
+{
+ return msm_gemini_init(pdev);
+}
+
+static int __msm_gemini_remove(struct platform_device *pdev)
+{
+ msm_gemini_exit();
+ return 0;
+}
+
+static struct platform_driver msm_gemini_driver = {
+ .probe = __msm_gemini_probe,
+ .remove = __msm_gemini_remove,
+ .driver = {
+ .name = MSM_GEMINI_DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init msm_gemini_driver_init(void)
+{
+ int rc;
+ rc = platform_driver_register(&msm_gemini_driver);
+ return rc;
+}
+
+static void __exit msm_gemini_driver_exit(void)
+{
+ platform_driver_unregister(&msm_gemini_driver);
+}
+
+MODULE_DESCRIPTION("MSM Gemini JPEG driver");
+MODULE_VERSION("msm gemini 0.1");
+
+module_init(msm_gemini_driver_init);
+module_exit(msm_gemini_driver_exit);
+
diff --git a/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_hw.c b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_hw.c
new file mode 100644
index 0000000..96470fd
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_hw.c
@@ -0,0 +1,520 @@
+/* Copyright (c) 2010,2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include "msm_gemini_hw.h"
+#include "msm_gemini_common.h"
+
+
+static void *gemini_region_base;
+static uint32_t gemini_region_size;
+
+int msm_gemini_hw_pingpong_update(struct msm_gemini_hw_pingpong *pingpong_hw,
+ struct msm_gemini_hw_buf *buf)
+{
+ int buf_free_index = -1;
+
+ if (!pingpong_hw->buf_status[0])
+ buf_free_index = 0;
+ else if (!pingpong_hw->buf_status[1])
+ buf_free_index = 1;
+ else {
+ GMN_PR_ERR("%s:%d: pingpong buffer busy\n", __func__, __LINE__);
+ return -EBUSY;
+ }
+
+ pingpong_hw->buf[buf_free_index] = *buf;
+ pingpong_hw->buf_status[buf_free_index] = 1;
+
+ if (pingpong_hw->is_fe)
+ msm_gemini_hw_fe_buffer_update(
+ &pingpong_hw->buf[buf_free_index], buf_free_index);
+ else
+ msm_gemini_hw_we_buffer_update(
+ &pingpong_hw->buf[buf_free_index], buf_free_index);
+ return 0;
+}
+
+void *msm_gemini_hw_pingpong_irq(struct msm_gemini_hw_pingpong *pingpong_hw)
+{
+ struct msm_gemini_hw_buf *buf_p = NULL;
+
+ if (pingpong_hw->buf_status[pingpong_hw->buf_active_index]) {
+ buf_p = &pingpong_hw->buf[pingpong_hw->buf_active_index];
+ pingpong_hw->buf_status[pingpong_hw->buf_active_index] = 0;
+ }
+
+ pingpong_hw->buf_active_index = !pingpong_hw->buf_active_index;
+
+ return (void *) buf_p;
+}
+
+void *msm_gemini_hw_pingpong_active_buffer(
+ struct msm_gemini_hw_pingpong *pingpong_hw)
+{
+ struct msm_gemini_hw_buf *buf_p = NULL;
+
+ if (pingpong_hw->buf_status[pingpong_hw->buf_active_index])
+ buf_p = &pingpong_hw->buf[pingpong_hw->buf_active_index];
+
+ return (void *) buf_p;
+}
+
+struct msm_gemini_hw_cmd hw_cmd_irq_get_status[] = {
+ /* type, repeat n times, offset, mask, data or pdata */
+ {MSM_GEMINI_HW_CMD_TYPE_READ, 1, HWIO_JPEG_IRQ_STATUS_ADDR,
+ HWIO_JPEG_IRQ_STATUS_RMSK, {0} },
+};
+
+int msm_gemini_hw_irq_get_status(void)
+{
+ uint32_t n_irq_status = 0;
+ n_irq_status = msm_gemini_hw_read(&hw_cmd_irq_get_status[0]);
+ return n_irq_status;
+}
+
+struct msm_gemini_hw_cmd hw_cmd_encode_output_size[] = {
+ /* type, repeat n times, offset, mask, data or pdata */
+ {MSM_GEMINI_HW_CMD_TYPE_READ, 1,
+ HWIO_JPEG_STATUS_ENCODE_OUTPUT_SIZE_ADDR,
+ HWIO_JPEG_STATUS_ENCODE_OUTPUT_SIZE_RMSK, {0} },
+};
+
+long msm_gemini_hw_encode_output_size(void)
+{
+ long encode_output_size;
+
+ encode_output_size = msm_gemini_hw_read(&hw_cmd_encode_output_size[0]);
+
+ return encode_output_size;
+}
+
+struct msm_gemini_hw_cmd hw_cmd_irq_clear[] = {
+ /* type, repeat n times, offset, mask, data or pdata */
+ {MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_IRQ_CLEAR_ADDR,
+ HWIO_JPEG_IRQ_CLEAR_RMSK, {JPEG_IRQ_CLEAR_ALL} },
+};
+
+void msm_gemini_hw_irq_clear(uint32_t mask, uint32_t data)
+{
+ GMN_DBG("%s:%d] mask %0x data %0x", __func__, __LINE__, mask, data);
+ hw_cmd_irq_clear[0].mask = mask;
+ hw_cmd_irq_clear[0].data = data;
+ msm_gemini_hw_write(&hw_cmd_irq_clear[0]);
+}
+
+struct msm_gemini_hw_cmd hw_cmd_fe_ping_update[] = {
+ /* type, repeat n times, offset, mask, data or pdata */
+ {MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_FE_BUFFER_CFG_ADDR,
+ HWIO_JPEG_FE_BUFFER_CFG_RMSK, {0} },
+ {MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_FE_Y_PING_ADDR_ADDR,
+ HWIO_JPEG_FE_Y_PING_ADDR_RMSK, {0} },
+ {MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_FE_CBCR_PING_ADDR_ADDR,
+ HWIO_JPEG_FE_CBCR_PING_ADDR_RMSK, {0} },
+ {MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_FE_CMD_ADDR,
+ HWIO_JPEG_FE_CMD_RMSK, {JPEG_FE_CMD_BUFFERRELOAD} },
+};
+
+struct msm_gemini_hw_cmd hw_cmd_fe_pong_update[] = {
+ /* type, repeat n times, offset, mask, data or pdata */
+ {MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_FE_BUFFER_CFG_ADDR,
+ HWIO_JPEG_FE_BUFFER_CFG_RMSK, {0} },
+ {MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_FE_Y_PONG_ADDR_ADDR,
+ HWIO_JPEG_FE_Y_PONG_ADDR_RMSK, {0} },
+ {MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_FE_CBCR_PONG_ADDR_ADDR,
+ HWIO_JPEG_FE_CBCR_PONG_ADDR_RMSK, {0} },
+ {MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_FE_CMD_ADDR,
+ HWIO_JPEG_FE_CMD_RMSK, {JPEG_FE_CMD_BUFFERRELOAD} },
+};
+
+void msm_gemini_hw_fe_buffer_update(struct msm_gemini_hw_buf *p_input,
+ uint8_t pingpong_index)
+{
+ uint32_t n_reg_val = 0;
+
+ struct msm_gemini_hw_cmd *hw_cmd_p;
+
+ if (pingpong_index == 0) {
+ hw_cmd_p = &hw_cmd_fe_ping_update[0];
+ n_reg_val = ((((p_input->num_of_mcu_rows - 1) <<
+ HWIO_JPEG_FE_BUFFER_CFG_CBCR_MCU_ROWS_SHFT) &
+ HWIO_JPEG_FE_BUFFER_CFG_CBCR_MCU_ROWS_BMSK) |
+ (((p_input->num_of_mcu_rows - 1) <<
+ HWIO_JPEG_FE_BUFFER_CFG_Y_MCU_ROWS_SHFT) &
+ HWIO_JPEG_FE_BUFFER_CFG_Y_MCU_ROWS_BMSK));
+ hw_cmd_p->data = n_reg_val;
+ msm_gemini_hw_write(hw_cmd_p++);
+
+ n_reg_val = ((p_input->y_buffer_addr <<
+ HWIO_JPEG_FE_Y_PING_ADDR_FE_Y_PING_START_ADDR_SHFT) &
+ HWIO_JPEG_FE_Y_PING_ADDR_FE_Y_PING_START_ADDR_BMSK);
+ hw_cmd_p->data = n_reg_val;
+ msm_gemini_hw_write(hw_cmd_p++);
+
+ n_reg_val = ((p_input->cbcr_buffer_addr<<
+ HWIO_JPEG_FE_CBCR_PING_ADDR_FE_CBCR_PING_START_ADDR_SHFT) &
+ HWIO_JPEG_FE_CBCR_PING_ADDR_FE_CBCR_PING_START_ADDR_BMSK);
+ hw_cmd_p->data = n_reg_val;
+ msm_gemini_hw_write(hw_cmd_p++);
+
+ msm_gemini_hw_write(hw_cmd_p);
+ } else if (pingpong_index == 1) {
+ hw_cmd_p = &hw_cmd_fe_pong_update[0];
+ n_reg_val = ((((p_input->num_of_mcu_rows - 1) <<
+ HWIO_JPEG_FE_BUFFER_CFG_CBCR_MCU_ROWS_SHFT) &
+ HWIO_JPEG_FE_BUFFER_CFG_CBCR_MCU_ROWS_BMSK) |
+ (((p_input->num_of_mcu_rows - 1) <<
+ HWIO_JPEG_FE_BUFFER_CFG_Y_MCU_ROWS_SHFT) &
+ HWIO_JPEG_FE_BUFFER_CFG_Y_MCU_ROWS_BMSK));
+ hw_cmd_p->data = n_reg_val;
+ msm_gemini_hw_write(hw_cmd_p++);
+
+ n_reg_val = ((p_input->y_buffer_addr <<
+ HWIO_JPEG_FE_Y_PONG_ADDR_FE_Y_PONG_START_ADDR_SHFT) &
+ HWIO_JPEG_FE_Y_PONG_ADDR_FE_Y_PONG_START_ADDR_BMSK);
+ hw_cmd_p->data = n_reg_val;
+ msm_gemini_hw_write(hw_cmd_p++);
+
+ n_reg_val = ((p_input->cbcr_buffer_addr<<
+ HWIO_JPEG_FE_CBCR_PONG_ADDR_FE_CBCR_PONG_START_ADDR_SHFT) &
+ HWIO_JPEG_FE_CBCR_PONG_ADDR_FE_CBCR_PONG_START_ADDR_BMSK);
+ hw_cmd_p->data = n_reg_val;
+ msm_gemini_hw_write(hw_cmd_p++);
+
+ msm_gemini_hw_write(hw_cmd_p);
+ } else {
+ /* shall not get to here */
+ }
+
+ return;
+}
+
+struct msm_gemini_hw_cmd hw_cmd_fe_start[] = {
+ /* type, repeat n times, offset, mask, data or pdata */
+ {MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_FE_CMD_ADDR,
+ HWIO_JPEG_FE_CMD_RMSK, {JPEG_OFFLINE_CMD_START} },
+};
+
+void msm_gemini_hw_fe_start(void)
+{
+ msm_gemini_hw_write(&hw_cmd_fe_start[0]);
+
+ return;
+}
+
+struct msm_gemini_hw_cmd hw_cmd_we_buffer_cfg[] = {
+ /* type, repeat n times, offset, mask, data or pdata */
+ {MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_WE_Y_THRESHOLD_ADDR,
+ HWIO_JPEG_WE_Y_THRESHOLD_RMSK, {0} },
+ {MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_WE_Y_UB_CFG_ADDR,
+ HWIO_JPEG_WE_Y_UB_CFG_RMSK, {JPEG_WE_YUB_ENCODE} },
+ {MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_WE_CBCR_THRESHOLD_ADDR,
+ HWIO_JPEG_WE_CBCR_THRESHOLD_RMSK, {0} },
+};
+
+/*
+ * first dimension is WE_ASSERT_STALL_TH and WE_DEASSERT_STALL_TH
+ * second dimension is for offline and real-time settings
+ */
+static const uint32_t GEMINI_WE_Y_THRESHOLD[2][2] = {
+ { 0x00000190, 0x000001ff },
+ { 0x0000016a, 0x000001ff }
+};
+
+/*
+ * first dimension is WE_ASSERT_STALL_TH and WE_DEASSERT_STALL_TH
+ * second dimension is for offline and real-time settings
+ */
+static const uint32_t GEMINI_WE_CBCR_THRESHOLD[2][2] = {
+ { 0x00000190, 0x000001ff },
+ { 0x0000016a, 0x000001ff }
+};
+
+void msm_gemini_hw_we_buffer_cfg(uint8_t is_realtime)
+{
+ uint32_t n_reg_val = 0;
+
+ struct msm_gemini_hw_cmd *hw_cmd_p = &hw_cmd_we_buffer_cfg[0];
+
+ n_reg_val = (((GEMINI_WE_Y_THRESHOLD[1][is_realtime] <<
+ HWIO_JPEG_WE_Y_THRESHOLD_WE_DEASSERT_STALL_TH_SHFT) &
+ HWIO_JPEG_WE_Y_THRESHOLD_WE_DEASSERT_STALL_TH_BMSK) |
+ ((GEMINI_WE_Y_THRESHOLD[0][is_realtime] <<
+ HWIO_JPEG_WE_Y_THRESHOLD_WE_ASSERT_STALL_TH_SHFT) &
+ HWIO_JPEG_WE_Y_THRESHOLD_WE_ASSERT_STALL_TH_BMSK));
+ hw_cmd_p->data = n_reg_val;
+ msm_gemini_hw_write(hw_cmd_p++);
+
+ msm_gemini_hw_write(hw_cmd_p++);
+
+ /* @todo maybe not for realtime? */
+ n_reg_val = (((GEMINI_WE_CBCR_THRESHOLD[1][is_realtime] <<
+ HWIO_JPEG_WE_CBCR_THRESHOLD_WE_DEASSERT_STALL_TH_SHFT) &
+ HWIO_JPEG_WE_CBCR_THRESHOLD_WE_DEASSERT_STALL_TH_BMSK) |
+ ((GEMINI_WE_CBCR_THRESHOLD[0][is_realtime] <<
+ HWIO_JPEG_WE_CBCR_THRESHOLD_WE_ASSERT_STALL_TH_SHFT) &
+ HWIO_JPEG_WE_CBCR_THRESHOLD_WE_ASSERT_STALL_TH_BMSK));
+ hw_cmd_p->data = n_reg_val;
+ msm_gemini_hw_write(hw_cmd_p);
+
+ return;
+}
+
+struct msm_gemini_hw_cmd hw_cmd_we_ping_update[] = {
+ /* type, repeat n times, offset, mask, data or pdata */
+ {MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_WE_Y_PING_BUFFER_CFG_ADDR,
+ HWIO_JPEG_WE_Y_PING_BUFFER_CFG_RMSK, {0} },
+ {MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_WE_Y_PING_ADDR_ADDR,
+ HWIO_JPEG_WE_Y_PING_ADDR_RMSK, {0} },
+};
+
+struct msm_gemini_hw_cmd hw_cmd_we_pong_update[] = {
+ /* type, repeat n times, offset, mask, data or pdata */
+ {MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_WE_Y_PONG_BUFFER_CFG_ADDR,
+ HWIO_JPEG_WE_Y_PONG_BUFFER_CFG_RMSK, {0} },
+ {MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_WE_Y_PONG_ADDR_ADDR,
+ HWIO_JPEG_WE_Y_PONG_ADDR_RMSK, {0} },
+};
+
+void msm_gemini_hw_we_buffer_update(struct msm_gemini_hw_buf *p_input,
+ uint8_t pingpong_index)
+{
+ uint32_t n_reg_val = 0;
+
+ struct msm_gemini_hw_cmd *hw_cmd_p;
+
+ GMN_DBG("%s:%d] pingpong index %d", __func__, __LINE__,
+ pingpong_index);
+ if (pingpong_index == 0) {
+ hw_cmd_p = &hw_cmd_we_ping_update[0];
+
+ n_reg_val = ((p_input->y_len <<
+ HWIO_JPEG_WE_Y_PING_BUFFER_CFG_WE_BUFFER_LENGTH_SHFT) &
+ HWIO_JPEG_WE_Y_PING_BUFFER_CFG_WE_BUFFER_LENGTH_BMSK);
+ hw_cmd_p->data = n_reg_val;
+ msm_gemini_hw_write(hw_cmd_p++);
+
+ n_reg_val = p_input->y_buffer_addr;
+ hw_cmd_p->data = n_reg_val;
+ msm_gemini_hw_write(hw_cmd_p++);
+ } else if (pingpong_index == 1) {
+ hw_cmd_p = &hw_cmd_we_pong_update[0];
+
+ n_reg_val = ((p_input->y_len <<
+ HWIO_JPEG_WE_Y_PONG_BUFFER_CFG_WE_BUFFER_LENGTH_SHFT) &
+ HWIO_JPEG_WE_Y_PONG_BUFFER_CFG_WE_BUFFER_LENGTH_BMSK);
+ hw_cmd_p->data = n_reg_val;
+ msm_gemini_hw_write(hw_cmd_p++);
+
+ n_reg_val = p_input->y_buffer_addr;
+ hw_cmd_p->data = n_reg_val;
+ msm_gemini_hw_write(hw_cmd_p++);
+ } else {
+ /* shall not get to here */
+ }
+
+ return;
+}
+
+struct msm_gemini_hw_cmd hw_cmd_reset[] = {
+ /* type, repeat n times, offset, mask, data or pdata */
+ {MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_IRQ_MASK_ADDR,
+ HWIO_JPEG_IRQ_MASK_RMSK, {JPEG_IRQ_DISABLE_ALL} },
+ {MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_IRQ_CLEAR_ADDR,
+ HWIO_JPEG_IRQ_MASK_RMSK, {JPEG_IRQ_CLEAR_ALL} },
+ {MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_IRQ_MASK_ADDR,
+ HWIO_JPEG_IRQ_MASK_RMSK, {JPEG_IRQ_ALLSOURCES_ENABLE} },
+ {MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_RESET_CMD_ADDR,
+ HWIO_JPEG_RESET_CMD_RMSK, {JPEG_RESET_DEFAULT} },
+};
+
+void msm_gemini_hw_init(void *base, int size)
+{
+ gemini_region_base = base;
+ gemini_region_size = size;
+}
+
+void msm_gemini_hw_reset(void *base, int size)
+{
+ struct msm_gemini_hw_cmd *hw_cmd_p;
+
+ hw_cmd_p = &hw_cmd_reset[0];
+
+ msm_gemini_hw_write(hw_cmd_p++);
+ msm_gemini_hw_write(hw_cmd_p++);
+ msm_gemini_hw_write(hw_cmd_p++);
+ msm_gemini_hw_write(hw_cmd_p);
+}
+
+uint32_t msm_gemini_hw_read(struct msm_gemini_hw_cmd *hw_cmd_p)
+{
+ uint32_t *paddr;
+ uint32_t data;
+
+ paddr = gemini_region_base + hw_cmd_p->offset;
+
+ data = readl_relaxed(paddr);
+ data &= hw_cmd_p->mask;
+
+ GMN_DBG("%s:%d] type-%d n-%d offset-0x%4x mask-0x%8x data-0x%8x\n",
+ __func__, __LINE__, hw_cmd_p->type, hw_cmd_p->n,
+ hw_cmd_p->offset, hw_cmd_p->mask, data);
+ return data;
+}
+
+void msm_gemini_hw_write(struct msm_gemini_hw_cmd *hw_cmd_p)
+{
+ uint32_t *paddr;
+ uint32_t old_data, new_data;
+
+ /* type, repeat n times, offset, mask, data or pdata */
+ GMN_DBG("%s:%d] type-%d n-%d offset-0x%4x mask-0x%8x data-0x%8x\n",
+ __func__, __LINE__, hw_cmd_p->type, hw_cmd_p->n,
+ hw_cmd_p->offset, hw_cmd_p->mask, hw_cmd_p->data);
+
+ paddr = gemini_region_base + hw_cmd_p->offset;
+
+ if (hw_cmd_p->mask == 0xffffffff) {
+ old_data = 0;
+ } else {
+ old_data = readl_relaxed(paddr);
+ old_data &= ~hw_cmd_p->mask;
+ }
+
+ new_data = hw_cmd_p->data & hw_cmd_p->mask;
+ new_data |= old_data;
+ writel_relaxed(new_data, paddr);
+}
+
+int msm_gemini_hw_wait(struct msm_gemini_hw_cmd *hw_cmd_p, int m_us)
+{
+ int tm = hw_cmd_p->n;
+ uint32_t data;
+ uint32_t wait_data = hw_cmd_p->data & hw_cmd_p->mask;
+
+ data = msm_gemini_hw_read(hw_cmd_p);
+ if (data != wait_data) {
+ while (tm) {
+ udelay(m_us);
+ data = msm_gemini_hw_read(hw_cmd_p);
+ if (data == wait_data)
+ break;
+ tm--;
+ }
+ }
+ hw_cmd_p->data = data;
+ return tm;
+}
+
+void msm_gemini_hw_delay(struct msm_gemini_hw_cmd *hw_cmd_p, int m_us)
+{
+ int tm = hw_cmd_p->n;
+ while (tm) {
+ udelay(m_us);
+ tm--;
+ }
+}
+
+int msm_gemini_hw_exec_cmds(struct msm_gemini_hw_cmd *hw_cmd_p, int m_cmds)
+{
+ int is_copy_to_user = -1;
+ uint32_t data;
+
+ while (m_cmds--) {
+ if (hw_cmd_p->offset > gemini_region_size) {
+ GMN_PR_ERR("%s:%d] %d exceed hw region %d\n", __func__,
+ __LINE__, hw_cmd_p->offset, gemini_region_size);
+ return -EFAULT;
+ }
+
+ switch (hw_cmd_p->type) {
+ case MSM_GEMINI_HW_CMD_TYPE_READ:
+ hw_cmd_p->data = msm_gemini_hw_read(hw_cmd_p);
+ is_copy_to_user = 1;
+ break;
+
+ case MSM_GEMINI_HW_CMD_TYPE_WRITE:
+ msm_gemini_hw_write(hw_cmd_p);
+ break;
+
+ case MSM_GEMINI_HW_CMD_TYPE_WRITE_OR:
+ data = msm_gemini_hw_read(hw_cmd_p);
+ hw_cmd_p->data = (hw_cmd_p->data & hw_cmd_p->mask) |
+ data;
+ msm_gemini_hw_write(hw_cmd_p);
+ break;
+
+ case MSM_GEMINI_HW_CMD_TYPE_UWAIT:
+ msm_gemini_hw_wait(hw_cmd_p, 1);
+ break;
+
+ case MSM_GEMINI_HW_CMD_TYPE_MWAIT:
+ msm_gemini_hw_wait(hw_cmd_p, 1000);
+ break;
+
+ case MSM_GEMINI_HW_CMD_TYPE_UDELAY:
+ /* Userspace driver provided delay duration */
+ msm_gemini_hw_delay(hw_cmd_p, 1);
+ break;
+
+ case MSM_GEMINI_HW_CMD_TYPE_MDELAY:
+ /* Userspace driver provided delay duration */
+ msm_gemini_hw_delay(hw_cmd_p, 1000);
+ break;
+
+ default:
+ GMN_PR_ERR("wrong hw command type\n");
+ break;
+ }
+
+ hw_cmd_p++;
+ }
+ return is_copy_to_user;
+}
+
+#ifdef MSM_GMN_DBG_DUMP
+void msm_gemini_io_dump(int size)
+{
+ char line_str[128], *p_str;
+ void __iomem *addr = gemini_region_base;
+ int i;
+ u32 *p = (u32 *) addr;
+ u32 data;
+ pr_info("%s: %p %d reg_size %d\n", __func__, addr, size,
+ gemini_region_size);
+ line_str[0] = '\0';
+ p_str = line_str;
+ for (i = 0; i < size/4; i++) {
+ if (i % 4 == 0) {
+ snprintf(p_str, 12, "%08x: ", (u32) p);
+ p_str += 10;
+ }
+ data = readl_relaxed(p++);
+ snprintf(p_str, 12, "%08x ", data);
+ p_str += 9;
+ if ((i + 1) % 4 == 0) {
+ pr_info("%s\n", line_str);
+ line_str[0] = '\0';
+ p_str = line_str;
+ }
+ }
+ if (line_str[0] != '\0')
+ pr_info("%s\n", line_str);
+}
+#else
+void msm_gemini_io_dump(int size)
+{
+
+}
+#endif
diff --git a/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_hw.h b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_hw.h
new file mode 100644
index 0000000..84eed72
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_hw.h
@@ -0,0 +1,104 @@
+/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MSM_GEMINI_HW_H
+#define MSM_GEMINI_HW_H
+
+#include <linux/msm_ion.h>
+#include <media/msm_gemini.h>
+#include <mach/iommu_domains.h>
+#include "msm_gemini_hw_reg.h"
+
+struct msm_gemini_hw_buf {
+ struct msm_gemini_buf vbuf;
+ struct file *file;
+ uint32_t framedone_len;
+ uint32_t y_buffer_addr;
+ uint32_t y_len;
+ uint32_t cbcr_buffer_addr;
+ uint32_t cbcr_len;
+ uint32_t num_of_mcu_rows;
+ struct ion_handle *handle;
+};
+
+struct msm_gemini_hw_pingpong {
+ uint8_t is_fe; /* 1: fe; 0: we */
+ struct msm_gemini_hw_buf buf[2];
+ int buf_status[2];
+ int buf_active_index;
+};
+
+int msm_gemini_hw_pingpong_update(struct msm_gemini_hw_pingpong *pingpong_hw,
+ struct msm_gemini_hw_buf *buf);
+void *msm_gemini_hw_pingpong_irq(struct msm_gemini_hw_pingpong *pingpong_hw);
+void *msm_gemini_hw_pingpong_active_buffer(struct msm_gemini_hw_pingpong
+ *pingpong_hw);
+
+void msm_gemini_hw_irq_clear(uint32_t, uint32_t);
+int msm_gemini_hw_irq_get_status(void);
+long msm_gemini_hw_encode_output_size(void);
+#define MSM_GEMINI_HW_MASK_COMP_FRAMEDONE \
+ MSM_GEMINI_HW_IRQ_STATUS_FRAMEDONE_MASK
+#define MSM_GEMINI_HW_MASK_COMP_FE \
+ MSM_GEMINI_HW_IRQ_STATUS_FE_RD_DONE_MASK
+#define MSM_GEMINI_HW_MASK_COMP_WE \
+ (MSM_GEMINI_HW_IRQ_STATUS_WE_Y_PINGPONG_MASK | \
+ MSM_GEMINI_HW_IRQ_STATUS_WE_CBCR_PINGPONG_MASK)
+#define MSM_GEMINI_HW_MASK_COMP_RESET_ACK \
+ MSM_GEMINI_HW_IRQ_STATUS_RESET_ACK_MASK
+#define MSM_GEMINI_HW_MASK_COMP_ERR \
+ (MSM_GEMINI_HW_IRQ_STATUS_FE_RTOVF_MASK | \
+ MSM_GEMINI_HW_IRQ_STATUS_FE_VFE_OVERFLOW_MASK | \
+ MSM_GEMINI_HW_IRQ_STATUS_WE_Y_BUFFER_OVERFLOW_MASK | \
+ MSM_GEMINI_HW_IRQ_STATUS_WE_CBCR_BUFFER_OVERFLOW_MASK | \
+ MSM_GEMINI_HW_IRQ_STATUS_WE_CH0_DATAFIFO_OVERFLOW_MASK | \
+ MSM_GEMINI_HW_IRQ_STATUS_WE_CH1_DATAFIFO_OVERFLOW_MASK | \
+ MSM_GEMINI_HW_IRQ_STATUS_BUS_ERROR_MASK | \
+ MSM_GEMINI_HW_IRQ_STATUS_VIOLATION_MASK)
+
+#define msm_gemini_hw_irq_is_frame_done(gemini_irq_status) \
+ (gemini_irq_status & MSM_GEMINI_HW_MASK_COMP_FRAMEDONE)
+#define msm_gemini_hw_irq_is_fe_pingpong(gemini_irq_status) \
+ (gemini_irq_status & MSM_GEMINI_HW_MASK_COMP_FE)
+#define msm_gemini_hw_irq_is_we_pingpong(gemini_irq_status) \
+ (gemini_irq_status & MSM_GEMINI_HW_MASK_COMP_WE)
+#define msm_gemini_hw_irq_is_reset_ack(gemini_irq_status) \
+ (gemini_irq_status & MSM_GEMINI_HW_MASK_COMP_RESET_ACK)
+#define msm_gemini_hw_irq_is_err(gemini_irq_status) \
+ (gemini_irq_status & MSM_GEMINI_HW_MASK_COMP_ERR)
+
+void msm_gemini_hw_fe_buffer_update(struct msm_gemini_hw_buf *p_input,
+ uint8_t pingpong_index);
+void msm_gemini_hw_we_buffer_update(struct msm_gemini_hw_buf *p_input,
+ uint8_t pingpong_index);
+
+void msm_gemini_hw_we_buffer_cfg(uint8_t is_realtime);
+
+void msm_gemini_hw_fe_start(void);
+void msm_gemini_hw_clk_cfg(void);
+
+void msm_gemini_hw_reset(void *base, int size);
+void msm_gemini_hw_irq_cfg(void);
+void msm_gemini_hw_init(void *base, int size);
+
+uint32_t msm_gemini_hw_read(struct msm_gemini_hw_cmd *hw_cmd_p);
+void msm_gemini_hw_write(struct msm_gemini_hw_cmd *hw_cmd_p);
+int msm_gemini_hw_wait(struct msm_gemini_hw_cmd *hw_cmd_p, int m_us);
+void msm_gemini_hw_delay(struct msm_gemini_hw_cmd *hw_cmd_p, int m_us);
+int msm_gemini_hw_exec_cmds(struct msm_gemini_hw_cmd *hw_cmd_p, int m_cmds);
+void msm_gemini_io_dump(int size);
+
+#define MSM_GEMINI_PIPELINE_CLK_128MHZ 128 /* 8MP 128MHz */
+#define MSM_GEMINI_PIPELINE_CLK_140MHZ 140 /* 9MP 140MHz */
+#define MSM_GEMINI_PIPELINE_CLK_200MHZ 153 /* 12MP 153MHz */
+
+#endif /* MSM_GEMINI_HW_H */
diff --git a/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_hw_reg.h b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_hw_reg.h
new file mode 100644
index 0000000..4f05650
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_hw_reg.h
@@ -0,0 +1,176 @@
+/* Copyright (c) 2010,2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MSM_GEMINI_HW_REG_H
+#define MSM_GEMINI_HW_REG_H
+
+#define GEMINI_REG_BASE 0
+
+#define MSM_GEMINI_HW_IRQ_MASK_ADDR 0x00000014
+#define MSM_GEMINI_HW_IRQ_MASK_RMSK 0xffffffff
+#define MSM_GEMINI_HW_IRQ_MASK_SHFT 0
+#define MSM_GEMINI_HW_IRQ_DISABLE 0
+#define MSM_GEMINI_HW_IRQ_ENABLE 0xffffffff
+
+#define MSM_GEMINI_HW_IRQ_CLEAR_ADDR 0x00000018
+#define MSM_GEMINI_HW_IRQ_CLEAR_RMSK 0xffffffff
+#define MSM_GEMINI_HW_IRQ_CLEAR_SHFT 0
+#define MSM_GEMINI_HW_IRQ_CLEAR 0xffffffff
+
+#define MSM_GEMINI_HW_IRQ_STATUS_FRAMEDONE_MASK 0x00000001
+#define MSM_GEMINI_HW_IRQ_STATUS_FRAMEDONE_SHIFT 0x00000000
+
+#define MSM_GEMINI_HW_IRQ_STATUS_FE_RD_DONE_MASK 0x00000002
+#define MSM_GEMINI_HW_IRQ_STATUS_FE_RD_DONE_SHIFT 0x00000001
+
+#define MSM_GEMINI_HW_IRQ_STATUS_FE_RTOVF_MASK 0x00000004
+#define MSM_GEMINI_HW_IRQ_STATUS_FE_RTOVF_SHIFT 0x00000002
+
+#define MSM_GEMINI_HW_IRQ_STATUS_FE_VFE_OVERFLOW_MASK 0x00000008
+#define MSM_GEMINI_HW_IRQ_STATUS_FE_VFE_OVERFLOW_SHIFT 0x00000003
+
+#define MSM_GEMINI_HW_IRQ_STATUS_WE_Y_PINGPONG_MASK 0x00000010
+#define MSM_GEMINI_HW_IRQ_STATUS_WE_Y_PINGPONG_SHIFT 0x00000004
+
+#define MSM_GEMINI_HW_IRQ_STATUS_WE_CBCR_PINGPONG_MASK 0x00000020
+#define MSM_GEMINI_HW_IRQ_STATUS_WE_CBCR_PINGPONG_SHIFT 0x00000005
+
+#define MSM_GEMINI_HW_IRQ_STATUS_WE_Y_BUFFER_OVERFLOW_MASK 0x00000040
+#define MSM_GEMINI_HW_IRQ_STATUS_WE_Y_BUFFER_OVERFLOW_SHIFT 0x00000006
+
+#define MSM_GEMINI_HW_IRQ_STATUS_WE_CBCR_BUFFER_OVERFLOW_MASK 0x00000080
+#define MSM_GEMINI_HW_IRQ_STATUS_WE_CBCR_BUFFER_OVERFLOW_SHIFT 0x00000007
+
+#define MSM_GEMINI_HW_IRQ_STATUS_WE_CH0_DATAFIFO_OVERFLOW_MASK 0x00000100
+#define MSM_GEMINI_HW_IRQ_STATUS_WE_CH0_DATAFIFO_OVERFLOW_SHIFT 0x00000008
+
+#define MSM_GEMINI_HW_IRQ_STATUS_WE_CH1_DATAFIFO_OVERFLOW_MASK 0x00000200
+#define MSM_GEMINI_HW_IRQ_STATUS_WE_CH1_DATAFIFO_OVERFLOW_SHIFT 0x00000009
+
+#define MSM_GEMINI_HW_IRQ_STATUS_RESET_ACK_MASK 0x00000400
+#define MSM_GEMINI_HW_IRQ_STATUS_RESET_ACK_SHIFT 0x0000000a
+
+#define MSM_GEMINI_HW_IRQ_STATUS_BUS_ERROR_MASK 0x00000800
+#define MSM_GEMINI_HW_IRQ_STATUS_BUS_ERROR_SHIFT 0x0000000b
+
+#define MSM_GEMINI_HW_IRQ_STATUS_VIOLATION_MASK 0x00001000
+#define MSM_GEMINI_HW_IRQ_STATUS_VIOLATION_SHIFT 0x0000000c
+
+#define JPEG_BUS_CMD_HALT_REQ 0x00000001
+
+#define JPEG_REALTIME_CMD_STOP_FB 0x00000000
+#define JPEG_REALTIME_CMD_STOP_IM 0x00000003
+#define JPEG_REALTIME_CMD_START 0x00000001
+
+#define JPEG_OFFLINE_CMD_START 0x00000003
+
+#define JPEG_DMI_CFG_DISABLE 0x00000000
+#define JPEG_DMI_ADDR_START 0x00000000
+
+#define JPEG_FE_CMD_BUFFERRELOAD 0x00000001
+
+#define JPEG_WE_YUB_ENCODE 0x01ff0000
+
+#define JPEG_RESET_DEFAULT 0x0004ffff /* cfff? */
+
+#define JPEG_IRQ_DISABLE_ALL 0x00000000
+#define JPEG_IRQ_CLEAR_ALL 0xffffffff
+#define JPEG_IRQ_ALLSOURCES_ENABLE 0xffffffff
+
+#define HWIO_JPEG_FE_BUFFER_CFG_ADDR (GEMINI_REG_BASE + 0x00000080)
+#define HWIO_JPEG_FE_BUFFER_CFG_RMSK 0x1fff1fff
+
+#define HWIO_JPEG_FE_Y_PING_ADDR_ADDR (GEMINI_REG_BASE + 0x00000084)
+#define HWIO_JPEG_FE_Y_PING_ADDR_RMSK 0xffffffff
+
+#define HWIO_JPEG_FE_Y_PONG_ADDR_ADDR (GEMINI_REG_BASE + 0x00000088)
+#define HWIO_JPEG_FE_Y_PONG_ADDR_RMSK 0xffffffff
+
+#define HWIO_JPEG_FE_CBCR_PING_ADDR_ADDR (GEMINI_REG_BASE + 0x0000008c)
+#define HWIO_JPEG_FE_CBCR_PING_ADDR_RMSK 0xffffffff
+
+#define HWIO_JPEG_FE_CBCR_PONG_ADDR_ADDR (GEMINI_REG_BASE + 0x00000090)
+#define HWIO_JPEG_FE_CBCR_PONG_ADDR_RMSK 0xffffffff
+
+#define HWIO_JPEG_FE_CMD_ADDR (GEMINI_REG_BASE + 0x00000094)
+#define HWIO_JPEG_FE_CMD_RMSK 0x3
+
+#define HWIO_JPEG_FE_BUFFER_CFG_CBCR_MCU_ROWS_BMSK 0x1fff0000
+#define HWIO_JPEG_FE_BUFFER_CFG_CBCR_MCU_ROWS_SHFT 0x10
+#define HWIO_JPEG_FE_BUFFER_CFG_Y_MCU_ROWS_BMSK 0x1fff
+#define HWIO_JPEG_FE_BUFFER_CFG_Y_MCU_ROWS_SHFT 0
+
+#define HWIO_JPEG_FE_Y_PING_ADDR_FE_Y_PING_START_ADDR_BMSK 0xffffffff
+#define HWIO_JPEG_FE_Y_PING_ADDR_FE_Y_PING_START_ADDR_SHFT 0
+
+#define HWIO_JPEG_FE_CBCR_PING_ADDR_FE_CBCR_PING_START_ADDR_BMSK 0xffffffff
+#define HWIO_JPEG_FE_CBCR_PING_ADDR_FE_CBCR_PING_START_ADDR_SHFT 0
+
+#define HWIO_JPEG_FE_Y_PONG_ADDR_FE_Y_PONG_START_ADDR_BMSK 0xffffffff
+#define HWIO_JPEG_FE_Y_PONG_ADDR_FE_Y_PONG_START_ADDR_SHFT 0
+
+#define HWIO_JPEG_FE_CBCR_PONG_ADDR_FE_CBCR_PONG_START_ADDR_BMSK 0xffffffff
+#define HWIO_JPEG_FE_CBCR_PONG_ADDR_FE_CBCR_PONG_START_ADDR_SHFT 0
+
+#define HWIO_JPEG_WE_Y_THRESHOLD_ADDR (GEMINI_REG_BASE + 0x000000c0)
+#define HWIO_JPEG_WE_Y_THRESHOLD_RMSK 0x1ff01ff
+
+#define HWIO_JPEG_WE_CBCR_THRESHOLD_ADDR (GEMINI_REG_BASE + 0x000000c4)
+#define HWIO_JPEG_WE_CBCR_THRESHOLD_RMSK 0x1ff01ff
+
+#define HWIO_JPEG_WE_Y_UB_CFG_ADDR (GEMINI_REG_BASE + 0x000000e8)
+#define HWIO_JPEG_WE_Y_UB_CFG_RMSK 0x1ff01ff
+
+#define HWIO_JPEG_WE_Y_THRESHOLD_WE_DEASSERT_STALL_TH_BMSK 0x1ff0000
+#define HWIO_JPEG_WE_Y_THRESHOLD_WE_DEASSERT_STALL_TH_SHFT 0x10
+#define HWIO_JPEG_WE_Y_THRESHOLD_WE_ASSERT_STALL_TH_BMSK 0x1ff
+#define HWIO_JPEG_WE_Y_THRESHOLD_WE_ASSERT_STALL_TH_SHFT 0
+
+#define HWIO_JPEG_WE_CBCR_THRESHOLD_WE_DEASSERT_STALL_TH_BMSK 0x1ff0000
+#define HWIO_JPEG_WE_CBCR_THRESHOLD_WE_DEASSERT_STALL_TH_SHFT 0x10
+#define HWIO_JPEG_WE_CBCR_THRESHOLD_WE_ASSERT_STALL_TH_BMSK 0x1ff
+#define HWIO_JPEG_WE_CBCR_THRESHOLD_WE_ASSERT_STALL_TH_SHFT 0
+
+#define HWIO_JPEG_WE_Y_PING_BUFFER_CFG_ADDR (GEMINI_REG_BASE + 0x000000c8)
+#define HWIO_JPEG_WE_Y_PING_BUFFER_CFG_RMSK 0x7fffff
+
+#define HWIO_JPEG_WE_Y_PING_ADDR_ADDR (GEMINI_REG_BASE + 0x000000d8)
+#define HWIO_JPEG_WE_Y_PING_ADDR_RMSK 0xfffffff8
+
+#define HWIO_JPEG_WE_Y_PONG_BUFFER_CFG_ADDR (GEMINI_REG_BASE + 0x000000cc)
+#define HWIO_JPEG_WE_Y_PONG_BUFFER_CFG_RMSK 0x7fffff
+
+#define HWIO_JPEG_WE_Y_PONG_ADDR_ADDR (GEMINI_REG_BASE + 0x000000dc)
+#define HWIO_JPEG_WE_Y_PONG_ADDR_RMSK 0xfffffff8
+
+#define HWIO_JPEG_WE_Y_PING_BUFFER_CFG_WE_BUFFER_LENGTH_BMSK 0x7fffff
+#define HWIO_JPEG_WE_Y_PING_BUFFER_CFG_WE_BUFFER_LENGTH_SHFT 0
+
+#define HWIO_JPEG_WE_Y_PONG_BUFFER_CFG_WE_BUFFER_LENGTH_BMSK 0x7fffff
+#define HWIO_JPEG_WE_Y_PONG_BUFFER_CFG_WE_BUFFER_LENGTH_SHFT 0
+
+#define HWIO_JPEG_IRQ_MASK_ADDR (GEMINI_REG_BASE + 0x00000014)
+#define HWIO_JPEG_IRQ_MASK_RMSK 0xffffffff
+
+#define HWIO_JPEG_IRQ_CLEAR_ADDR (GEMINI_REG_BASE + 0x00000018)
+#define HWIO_JPEG_IRQ_CLEAR_RMSK 0xffffffff
+
+#define HWIO_JPEG_RESET_CMD_ADDR (GEMINI_REG_BASE + 0x00000004)
+#define HWIO_JPEG_RESET_CMD_RMSK 0xe004ffff
+
+#define HWIO_JPEG_IRQ_STATUS_ADDR (GEMINI_REG_BASE + 0x0000001c)
+#define HWIO_JPEG_IRQ_STATUS_RMSK 0xffffffff
+
+#define HWIO_JPEG_STATUS_ENCODE_OUTPUT_SIZE_ADDR (GEMINI_REG_BASE + 0x00000034)
+#define HWIO_JPEG_STATUS_ENCODE_OUTPUT_SIZE_RMSK 0xffffffff
+
+#endif /* MSM_GEMINI_HW_REG_H */
diff --git a/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_platform.c b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_platform.c
new file mode 100644
index 0000000..f442068
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_platform.c
@@ -0,0 +1,283 @@
+/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/pm_qos.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/android_pmem.h>
+#include <mach/clk.h>
+#include <mach/camera2.h>
+#include <mach/iommu_domains.h>
+#include "msm_gemini_platform.h"
+#include "msm_gemini_sync.h"
+#include "msm_gemini_common.h"
+#include "msm_gemini_hw.h"
+#include "msm_camera_io_util.h"
+
+/* AXI rate in KHz */
+#define MSM_SYSTEM_BUS_RATE 160000
+struct ion_client *gemini_client;
+
+
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+void msm_gemini_platform_p2v(struct file *file,
+ struct ion_handle **ionhandle)
+{
+ ion_unmap_iommu(gemini_client, *ionhandle, CAMERA_DOMAIN, GEN_POOL);
+ ion_free(gemini_client, *ionhandle);
+ *ionhandle = NULL;
+}
+#else
+void msm_gemini_platform_p2v(struct file *file,
+ struct ion_handle **ionhandle)
+{
+
+}
+#endif
+
+
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+uint32_t msm_gemini_platform_v2p(int fd, uint32_t len, struct file **file_p,
+ struct ion_handle **ionhandle)
+{
+ unsigned long paddr;
+ unsigned long size;
+ int rc;
+
+ *ionhandle = ion_import_dma_buf(gemini_client, fd);
+ if (IS_ERR_OR_NULL(*ionhandle))
+ return 0;
+
+ rc = ion_map_iommu(gemini_client, *ionhandle, CAMERA_DOMAIN, GEN_POOL,
+ SZ_4K, 0, &paddr, (unsigned long *)&size, 0, 0);
+ if (rc < 0) {
+ GMN_PR_ERR("%s: get_pmem_file fd %d error %d\n", __func__, fd,
+ rc);
+ goto error1;
+ }
+ /* validate user input */
+ if (len > size) {
+ GMN_PR_ERR("%s: invalid offset + len\n", __func__);
+ goto error1;
+ }
+
+ return paddr;
+error1:
+ ion_free(gemini_client, *ionhandle);
+
+ return 0;
+}
+#else
+uint32_t msm_gemini_platform_v2p(int fd, uint32_t len, struct file **file_p,
+ struct ion_handle **ionhandle)
+{
+ return 0;
+}
+#endif
+
+static struct msm_cam_clk_info gemini_8x_clk_info[] = {
+ {"core_clk", 228571000, 0},
+ {"iface_clk", -1, 0},
+};
+
+static struct msm_cam_clk_info gemini_7x_clk_info[] = {
+ {"core_clk", 153600000, 0},
+ {"iface_clk", -1, 0},
+};
+
+static struct msm_cam_clk_info gemini_imem_clk_info[] = {
+ {"mem_clk", -1, 0},
+};
+
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+static struct ion_client *msm_gemini_ion_client_create(unsigned int heap_mask,
+ const char *name)
+{
+ return msm_ion_client_create(heap_mask, name);
+}
+#else
+static struct ion_client *msm_gemini_ion_client_create(unsigned int heap_mask,
+ const char *name)
+{
+ return NULL;
+}
+#endif
+
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+void msm_gemini_ion_client_destroy(struct ion_client *client)
+{
+ ion_client_destroy(client);
+}
+#else
+void msm_gemini_ion_client_destroy(struct ion_client *client)
+{
+
+}
+#endif
+
+int msm_gemini_platform_init(struct platform_device *pdev,
+ struct resource **mem,
+ void **base,
+ int *irq,
+ irqreturn_t (*handler) (int, void *),
+ void *context)
+{
+ int rc = -1;
+ int gemini_irq;
+ struct resource *gemini_mem, *gemini_io, *gemini_irq_res;
+ void *gemini_base;
+ struct msm_gemini_device *pgmn_dev =
+ (struct msm_gemini_device *) context;
+
+ gemini_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!gemini_mem) {
+ GMN_PR_ERR("%s: no mem resource!\n", __func__);
+ return -ENODEV;
+ }
+
+ gemini_irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!gemini_irq_res) {
+ GMN_PR_ERR("no irq resource!\n");
+ return -ENODEV;
+ }
+ gemini_irq = gemini_irq_res->start;
+
+ gemini_io = request_mem_region(gemini_mem->start,
+ resource_size(gemini_mem), pdev->name);
+ if (!gemini_io) {
+ GMN_PR_ERR("%s: region already claimed\n", __func__);
+ return -EBUSY;
+ }
+
+ gemini_base = ioremap(gemini_mem->start, resource_size(gemini_mem));
+ if (!gemini_base) {
+ rc = -ENOMEM;
+ GMN_PR_ERR("%s: ioremap failed\n", __func__);
+ goto fail1;
+ }
+ pgmn_dev->hw_version = GEMINI_8X60;
+ rc = msm_cam_clk_enable(&pgmn_dev->pdev->dev, gemini_8x_clk_info,
+ pgmn_dev->gemini_clk, ARRAY_SIZE(gemini_8x_clk_info), 1);
+ if (rc < 0) {
+ pgmn_dev->hw_version = GEMINI_7X;
+ rc = msm_cam_clk_enable(&pgmn_dev->pdev->dev,
+ gemini_7x_clk_info, pgmn_dev->gemini_clk,
+ ARRAY_SIZE(gemini_7x_clk_info), 1);
+ if (rc < 0) {
+ GMN_PR_ERR("%s: clk failed rc = %d\n", __func__, rc);
+ goto fail2;
+ }
+ } else {
+ rc = msm_cam_clk_enable(&pgmn_dev->pdev->dev,
+ gemini_imem_clk_info, &pgmn_dev->gemini_clk[2],
+ ARRAY_SIZE(gemini_imem_clk_info), 1);
+ if (!rc)
+ pgmn_dev->hw_version = GEMINI_8960;
+ }
+
+ if (pgmn_dev->hw_version != GEMINI_7X) {
+ if (pgmn_dev->gemini_fs == NULL) {
+ pgmn_dev->gemini_fs =
+ regulator_get(&pgmn_dev->pdev->dev, "vdd");
+ if (IS_ERR(pgmn_dev->gemini_fs)) {
+ GMN_PR_ERR("%s: regulator_get failed %ld\n",
+ __func__, PTR_ERR(pgmn_dev->gemini_fs));
+ pgmn_dev->gemini_fs = NULL;
+ goto gemini_fs_failed;
+ } else if (regulator_enable(pgmn_dev->gemini_fs)) {
+ GMN_PR_ERR("%s: regulator_enable failed\n",
+ __func__);
+ regulator_put(pgmn_dev->gemini_fs);
+ pgmn_dev->gemini_fs = NULL;
+ goto gemini_fs_failed;
+ }
+ }
+ }
+
+ msm_gemini_hw_init(gemini_base, resource_size(gemini_mem));
+ rc = request_irq(gemini_irq, handler, IRQF_TRIGGER_RISING, "gemini",
+ context);
+ if (rc) {
+ GMN_PR_ERR("%s: request_irq failed, %d\n", __func__,
+ gemini_irq);
+ goto fail3;
+ }
+
+ *mem = gemini_mem;
+ *base = gemini_base;
+ *irq = gemini_irq;
+
+ gemini_client = msm_gemini_ion_client_create(-1, "camera/gemini");
+
+ GMN_DBG("%s:%d] success\n", __func__, __LINE__);
+
+ return rc;
+
+fail3:
+ if (pgmn_dev->hw_version != GEMINI_7X) {
+ regulator_disable(pgmn_dev->gemini_fs);
+ regulator_put(pgmn_dev->gemini_fs);
+ pgmn_dev->gemini_fs = NULL;
+ }
+gemini_fs_failed:
+ if (pgmn_dev->hw_version == GEMINI_8960)
+ msm_cam_clk_enable(&pgmn_dev->pdev->dev, gemini_imem_clk_info,
+ &pgmn_dev->gemini_clk[2], ARRAY_SIZE(gemini_imem_clk_info), 0);
+ if (pgmn_dev->hw_version != GEMINI_7X)
+ msm_cam_clk_enable(&pgmn_dev->pdev->dev, gemini_8x_clk_info,
+ pgmn_dev->gemini_clk, ARRAY_SIZE(gemini_8x_clk_info), 0);
+ else
+ msm_cam_clk_enable(&pgmn_dev->pdev->dev, gemini_7x_clk_info,
+ pgmn_dev->gemini_clk, ARRAY_SIZE(gemini_7x_clk_info), 0);
+fail2:
+ iounmap(gemini_base);
+fail1:
+ release_mem_region(gemini_mem->start, resource_size(gemini_mem));
+ GMN_DBG("%s:%d] fail\n", __func__, __LINE__);
+ return rc;
+}
+
+int msm_gemini_platform_release(struct resource *mem, void *base, int irq,
+ void *context)
+{
+ int result = 0;
+ struct msm_gemini_device *pgmn_dev =
+ (struct msm_gemini_device *) context;
+
+ free_irq(irq, context);
+
+ if (pgmn_dev->hw_version != GEMINI_7X) {
+ regulator_disable(pgmn_dev->gemini_fs);
+ regulator_put(pgmn_dev->gemini_fs);
+ pgmn_dev->gemini_fs = NULL;
+ }
+
+ if (pgmn_dev->hw_version == GEMINI_8960)
+ msm_cam_clk_enable(&pgmn_dev->pdev->dev, gemini_imem_clk_info,
+ &pgmn_dev->gemini_clk[2], ARRAY_SIZE(gemini_imem_clk_info), 0);
+ if (pgmn_dev->hw_version != GEMINI_7X)
+ msm_cam_clk_enable(&pgmn_dev->pdev->dev, gemini_8x_clk_info,
+ pgmn_dev->gemini_clk, ARRAY_SIZE(gemini_8x_clk_info), 0);
+ else
+ msm_cam_clk_enable(&pgmn_dev->pdev->dev, gemini_7x_clk_info,
+ pgmn_dev->gemini_clk, ARRAY_SIZE(gemini_7x_clk_info), 0);
+
+ iounmap(base);
+ release_mem_region(mem->start, resource_size(mem));
+
+ msm_gemini_ion_client_destroy(gemini_client);
+
+ GMN_DBG("%s:%d] success\n", __func__, __LINE__);
+ return result;
+}
+
diff --git a/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_platform.h b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_platform.h
new file mode 100644
index 0000000..a071df9
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_platform.h
@@ -0,0 +1,37 @@
+/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MSM_GEMINI_PLATFORM_H
+#define MSM_GEMINI_PLATFORM_H
+
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/msm_ion.h>
+#include <linux/iommu.h>
+void msm_gemini_platform_p2v(struct file *file,
+ struct ion_handle **ionhandle);
+uint32_t msm_gemini_platform_v2p(int fd, uint32_t len, struct file **file,
+ struct ion_handle **ionhandle);
+
+int msm_gemini_platform_clk_enable(void);
+int msm_gemini_platform_clk_disable(void);
+
+int msm_gemini_platform_init(struct platform_device *pdev,
+ struct resource **mem,
+ void **base,
+ int *irq,
+ irqreturn_t (*handler) (int, void *),
+ void *context);
+int msm_gemini_platform_release(struct resource *mem, void *base, int irq,
+ void *context);
+
+#endif /* MSM_GEMINI_PLATFORM_H */
diff --git a/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_sync.c b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_sync.c
new file mode 100644
index 0000000..8f84a2c
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_sync.c
@@ -0,0 +1,1081 @@
+/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/list.h>
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+#include <media/msm_gemini.h>
+#include <mach/msm_bus.h>
+#include <mach/msm_bus_board.h>
+#include "msm_gemini_sync.h"
+#include "msm_gemini_core.h"
+#include "msm_gemini_platform.h"
+#include "msm_gemini_common.h"
+
+static int release_buf;
+
+/* size is based on 4k page size */
+static const int g_max_out_size = 0x7ff000;
+
+/*************** queue helper ****************/
+static inline void msm_gemini_q_init(char const *name, struct msm_gemini_q *q_p)
+{
+ GMN_DBG("%s:%d] %s\n", __func__, __LINE__, name);
+ q_p->name = name;
+ spin_lock_init(&q_p->lck);
+ INIT_LIST_HEAD(&q_p->q);
+ init_waitqueue_head(&q_p->wait);
+ q_p->unblck = 0;
+}
+
+static inline void *msm_gemini_q_out(struct msm_gemini_q *q_p)
+{
+ unsigned long flags;
+ struct msm_gemini_q_entry *q_entry_p = NULL;
+ void *data = NULL;
+
+ GMN_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+ spin_lock_irqsave(&q_p->lck, flags);
+ if (!list_empty(&q_p->q)) {
+ q_entry_p = list_first_entry(&q_p->q, struct msm_gemini_q_entry,
+ list);
+ list_del_init(&q_entry_p->list);
+ }
+ spin_unlock_irqrestore(&q_p->lck, flags);
+
+ if (q_entry_p) {
+ data = q_entry_p->data;
+ kfree(q_entry_p);
+ } else {
+ GMN_DBG("%s:%d] %s no entry\n", __func__, __LINE__,
+ q_p->name);
+ }
+
+ return data;
+}
+
+static inline int msm_gemini_q_in(struct msm_gemini_q *q_p, void *data)
+{
+ unsigned long flags;
+
+ struct msm_gemini_q_entry *q_entry_p;
+
+ GMN_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+
+ q_entry_p = kmalloc(sizeof(struct msm_gemini_q_entry), GFP_ATOMIC);
+ if (!q_entry_p) {
+ GMN_PR_ERR("%s: no mem\n", __func__);
+ return -ENOMEM;
+ }
+ q_entry_p->data = data;
+
+ spin_lock_irqsave(&q_p->lck, flags);
+ list_add_tail(&q_entry_p->list, &q_p->q);
+ spin_unlock_irqrestore(&q_p->lck, flags);
+
+ return 0;
+}
+
+static inline int msm_gemini_q_in_buf(struct msm_gemini_q *q_p,
+ struct msm_gemini_core_buf *buf)
+{
+ struct msm_gemini_core_buf *buf_p;
+
+ GMN_DBG("%s:%d]\n", __func__, __LINE__);
+ buf_p = kmalloc(sizeof(struct msm_gemini_core_buf), GFP_ATOMIC);
+ if (!buf_p) {
+ GMN_PR_ERR("%s: no mem\n", __func__);
+ return -ENOMEM;
+ }
+
+ memcpy(buf_p, buf, sizeof(struct msm_gemini_core_buf));
+
+ msm_gemini_q_in(q_p, buf_p);
+ return 0;
+}
+
+static inline int msm_gemini_q_wait(struct msm_gemini_q *q_p)
+{
+ int tm = MAX_SCHEDULE_TIMEOUT;
+ int rc;
+
+ GMN_DBG("%s:%d] %s wait\n", __func__, __LINE__, q_p->name);
+ rc = wait_event_interruptible_timeout(q_p->wait,
+ (!list_empty_careful(&q_p->q) || q_p->unblck),
+ msecs_to_jiffies(tm));
+ GMN_DBG("%s:%d] %s wait done\n", __func__, __LINE__, q_p->name);
+ if (list_empty_careful(&q_p->q)) {
+ if (rc == 0) {
+ rc = -ETIMEDOUT;
+ GMN_PR_ERR("%s:%d] %s timeout\n", __func__, __LINE__,
+ q_p->name);
+ } else if (q_p->unblck) {
+ GMN_DBG("%s:%d] %s unblock is true\n", __func__,
+ __LINE__, q_p->name);
+ q_p->unblck = 0;
+ rc = -ECANCELED;
+ } else if (rc < 0) {
+ GMN_PR_ERR("%s:%d] %s rc %d\n", __func__, __LINE__,
+ q_p->name, rc);
+ }
+ }
+ return rc;
+}
+
+static inline int msm_gemini_q_wakeup(struct msm_gemini_q *q_p)
+{
+ GMN_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+ wake_up(&q_p->wait);
+ return 0;
+}
+
+static inline int msm_gemini_q_unblock(struct msm_gemini_q *q_p)
+{
+ GMN_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+ q_p->unblck = 1;
+ wake_up(&q_p->wait);
+ return 0;
+}
+
+static inline void msm_gemini_outbuf_q_cleanup(struct msm_gemini_q *q_p)
+{
+ struct msm_gemini_core_buf *buf_p;
+ GMN_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+ do {
+ buf_p = msm_gemini_q_out(q_p);
+ if (buf_p) {
+ msm_gemini_platform_p2v(buf_p->file,
+ &buf_p->handle);
+ GMN_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+ kfree(buf_p);
+ }
+ } while (buf_p);
+ q_p->unblck = 0;
+}
+
+static inline void msm_gemini_q_cleanup(struct msm_gemini_q *q_p)
+{
+ void *data;
+ GMN_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+ do {
+ data = msm_gemini_q_out(q_p);
+ if (data) {
+ GMN_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+ kfree(data);
+ }
+ } while (data);
+ q_p->unblck = 0;
+}
+
+/*************** event queue ****************/
+
+int msm_gemini_framedone_irq(struct msm_gemini_device *pgmn_dev,
+ struct msm_gemini_core_buf *buf_in)
+{
+ int rc = 0;
+
+ GMN_DBG("%s:%d] buf_in %p", __func__, __LINE__, buf_in);
+
+ if (buf_in) {
+ buf_in->vbuf.framedone_len = buf_in->framedone_len;
+ buf_in->vbuf.type = MSM_GEMINI_EVT_FRAMEDONE;
+ GMN_DBG("%s:%d] 0x%08x %d framedone_len %d\n",
+ __func__, __LINE__,
+ (int) buf_in->y_buffer_addr, buf_in->y_len,
+ buf_in->vbuf.framedone_len);
+ rc = msm_gemini_q_in_buf(&pgmn_dev->evt_q, buf_in);
+ } else {
+ GMN_DBG("%s:%d] no output return buffer\n",
+ __func__, __LINE__);
+ rc = -1;
+ }
+
+ if (buf_in)
+ rc = msm_gemini_q_wakeup(&pgmn_dev->evt_q);
+
+ return rc;
+}
+
+int msm_gemini_evt_get(struct msm_gemini_device *pgmn_dev,
+ void __user *to)
+{
+ struct msm_gemini_core_buf *buf_p;
+ struct msm_gemini_ctrl_cmd ctrl_cmd;
+
+ GMN_DBG("%s:%d] Enter\n", __func__, __LINE__);
+
+ msm_gemini_q_wait(&pgmn_dev->evt_q);
+ buf_p = msm_gemini_q_out(&pgmn_dev->evt_q);
+
+ if (!buf_p) {
+ GMN_DBG("%s:%d] no buffer\n", __func__, __LINE__);
+ return -EAGAIN;
+ }
+
+ memset(&ctrl_cmd, 0, sizeof(struct msm_gemini_ctrl_cmd));
+ ctrl_cmd.type = buf_p->vbuf.type;
+ kfree(buf_p);
+
+ GMN_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__,
+ (int) ctrl_cmd.value, ctrl_cmd.len);
+
+ if (copy_to_user(to, &ctrl_cmd, sizeof(ctrl_cmd))) {
+ GMN_PR_ERR("%s:%d]\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+int msm_gemini_evt_get_unblock(struct msm_gemini_device *pgmn_dev)
+{
+ GMN_DBG("%s:%d] Enter\n", __func__, __LINE__);
+ msm_gemini_q_unblock(&pgmn_dev->evt_q);
+ return 0;
+}
+
+void msm_gemini_reset_ack_irq(struct msm_gemini_device *pgmn_dev)
+{
+ GMN_DBG("%s:%d]\n", __func__, __LINE__);
+}
+
+void msm_gemini_err_irq(struct msm_gemini_device *pgmn_dev,
+ int event)
+{
+ int rc = 0;
+ struct msm_gemini_core_buf buf;
+
+ GMN_DBG("%s:%d] error: %d\n", __func__, __LINE__, event);
+
+ buf.vbuf.type = MSM_GEMINI_EVT_ERR;
+ rc = msm_gemini_q_in_buf(&pgmn_dev->evt_q, &buf);
+ if (!rc)
+ rc = msm_gemini_q_wakeup(&pgmn_dev->evt_q);
+
+ if (!rc)
+ GMN_PR_ERR("%s:%d] err err\n", __func__, __LINE__);
+
+ return;
+}
+
+/*************** output queue ****************/
+
+int msm_gemini_get_out_buffer(struct msm_gemini_device *pgmn_dev,
+ struct msm_gemini_hw_buf *p_outbuf)
+{
+ int buf_size = 0;
+ int bytes_remaining = 0;
+ if (pgmn_dev->out_offset >= pgmn_dev->out_buf.y_len) {
+ GMN_PR_ERR("%s:%d] no more buffers", __func__, __LINE__);
+ return -EINVAL;
+ }
+ bytes_remaining = pgmn_dev->out_buf.y_len - pgmn_dev->out_offset;
+ buf_size = min(bytes_remaining, pgmn_dev->max_out_size);
+
+ pgmn_dev->out_frag_cnt++;
+ GMN_DBG("%s:%d] buf_size[%d] %d", __func__, __LINE__,
+ pgmn_dev->out_frag_cnt, buf_size);
+ p_outbuf->y_len = buf_size;
+ p_outbuf->y_buffer_addr = pgmn_dev->out_buf.y_buffer_addr +
+ pgmn_dev->out_offset;
+ pgmn_dev->out_offset += buf_size;
+ return 0;
+}
+
+int msm_gemini_outmode_single_we_pingpong_irq(
+ struct msm_gemini_device *pgmn_dev,
+ struct msm_gemini_core_buf *buf_in)
+{
+ int rc = 0;
+ struct msm_gemini_core_buf out_buf;
+ int frame_done = buf_in &&
+ buf_in->vbuf.type == MSM_GEMINI_EVT_FRAMEDONE;
+ GMN_DBG("%s:%d] framedone %d", __func__, __LINE__, frame_done);
+ if (!pgmn_dev->out_buf_set) {
+ GMN_PR_ERR("%s:%d] output buffer not set",
+ __func__, __LINE__);
+ return -EFAULT;
+ }
+ if (frame_done) {
+ /* send the buffer back */
+ pgmn_dev->out_buf.vbuf.framedone_len = buf_in->framedone_len;
+ pgmn_dev->out_buf.vbuf.type = MSM_GEMINI_EVT_FRAMEDONE;
+ rc = msm_gemini_q_in_buf(&pgmn_dev->output_rtn_q,
+ &pgmn_dev->out_buf);
+ if (rc) {
+ GMN_PR_ERR("%s:%d] cannot queue the output buffer",
+ __func__, __LINE__);
+ return -EFAULT;
+ }
+ rc = msm_gemini_q_wakeup(&pgmn_dev->output_rtn_q);
+ /*
+ * reset the output buffer since the ownership is
+ * transferred to the rtn queue
+ */
+ if (!rc)
+ pgmn_dev->out_buf_set = 0;
+ } else {
+ /* configure ping/pong */
+ rc = msm_gemini_get_out_buffer(pgmn_dev, &out_buf);
+ if (rc)
+ msm_gemini_core_we_buf_reset(&out_buf);
+ else
+ msm_gemini_core_we_buf_update(&out_buf);
+ }
+ return rc;
+}
+
+int msm_gemini_we_pingpong_irq(struct msm_gemini_device *pgmn_dev,
+ struct msm_gemini_core_buf *buf_in)
+{
+ int rc = 0;
+ struct msm_gemini_core_buf *buf_out;
+
+ GMN_DBG("%s:%d] Enter mode %d", __func__, __LINE__,
+ pgmn_dev->out_mode);
+
+ if (pgmn_dev->out_mode == MSM_GMN_OUTMODE_SINGLE)
+ return msm_gemini_outmode_single_we_pingpong_irq(pgmn_dev,
+ buf_in);
+
+ if (buf_in) {
+ GMN_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__,
+ (int) buf_in->y_buffer_addr, buf_in->y_len);
+ rc = msm_gemini_q_in_buf(&pgmn_dev->output_rtn_q, buf_in);
+ } else {
+ GMN_DBG("%s:%d] no output return buffer\n", __func__,
+ __LINE__);
+ rc = -1;
+ return rc;
+ }
+
+ buf_out = msm_gemini_q_out(&pgmn_dev->output_buf_q);
+
+ if (buf_out) {
+ rc = msm_gemini_core_we_buf_update(buf_out);
+ kfree(buf_out);
+ } else {
+ msm_gemini_core_we_buf_reset(buf_in);
+ GMN_DBG("%s:%d] no output buffer\n", __func__, __LINE__);
+ rc = -2;
+ }
+
+ if (buf_in)
+ rc = msm_gemini_q_wakeup(&pgmn_dev->output_rtn_q);
+
+ return rc;
+}
+
+int msm_gemini_output_get(struct msm_gemini_device *pgmn_dev, void __user *to)
+{
+ struct msm_gemini_core_buf *buf_p;
+ struct msm_gemini_buf buf_cmd;
+
+ GMN_DBG("%s:%d] Enter\n", __func__, __LINE__);
+
+ msm_gemini_q_wait(&pgmn_dev->output_rtn_q);
+ buf_p = msm_gemini_q_out(&pgmn_dev->output_rtn_q);
+
+ if (!buf_p) {
+ GMN_DBG("%s:%d] no output buffer return\n",
+ __func__, __LINE__);
+ return -EAGAIN;
+ }
+
+ buf_cmd = buf_p->vbuf;
+ msm_gemini_platform_p2v(buf_p->file, &buf_p->handle);
+ kfree(buf_p);
+
+ GMN_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__,
+ (int) buf_cmd.vaddr, buf_cmd.y_len);
+
+ if (copy_to_user(to, &buf_cmd, sizeof(buf_cmd))) {
+ GMN_PR_ERR("%s:%d]", __func__, __LINE__);
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+int msm_gemini_output_get_unblock(struct msm_gemini_device *pgmn_dev)
+{
+ GMN_DBG("%s:%d] Enter\n", __func__, __LINE__);
+ msm_gemini_q_unblock(&pgmn_dev->output_rtn_q);
+ return 0;
+}
+
+int msm_gemini_set_output_buf(struct msm_gemini_device *pgmn_dev,
+ void __user *arg)
+{
+ struct msm_gemini_buf buf_cmd;
+
+ if (pgmn_dev->out_buf_set) {
+ GMN_PR_ERR("%s:%d] outbuffer buffer already provided",
+ __func__, __LINE__);
+ return -EINVAL;
+ }
+
+ if (copy_from_user(&buf_cmd, arg, sizeof(struct msm_gemini_buf))) {
+ GMN_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+
+ GMN_DBG("%s:%d] output addr 0x%08x len %d", __func__, __LINE__,
+ (int) buf_cmd.vaddr,
+ buf_cmd.y_len);
+
+ pgmn_dev->out_buf.y_buffer_addr = msm_gemini_platform_v2p(
+ buf_cmd.fd,
+ buf_cmd.y_len,
+ &pgmn_dev->out_buf.file,
+ &pgmn_dev->out_buf.handle);
+ if (!pgmn_dev->out_buf.y_buffer_addr) {
+ GMN_PR_ERR("%s:%d] cannot map the output address",
+ __func__, __LINE__);
+ return -EFAULT;
+ }
+ pgmn_dev->out_buf.y_len = buf_cmd.y_len;
+ pgmn_dev->out_buf.vbuf = buf_cmd;
+ pgmn_dev->out_buf_set = 1;
+
+ return 0;
+}
+
+int msm_gemini_output_buf_enqueue(struct msm_gemini_device *pgmn_dev,
+ void __user *arg)
+{
+ struct msm_gemini_buf buf_cmd;
+ struct msm_gemini_core_buf *buf_p;
+
+ GMN_DBG("%s:%d] Enter\n", __func__, __LINE__);
+ if (copy_from_user(&buf_cmd, arg, sizeof(struct msm_gemini_buf))) {
+ GMN_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+
+ buf_p = kmalloc(sizeof(struct msm_gemini_core_buf), GFP_ATOMIC);
+ if (!buf_p) {
+ GMN_PR_ERR("%s:%d] no mem\n", __func__, __LINE__);
+ return -ENOMEM;
+ }
+
+ GMN_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__, (int) buf_cmd.vaddr,
+ buf_cmd.y_len);
+
+ buf_p->y_buffer_addr = msm_gemini_platform_v2p(buf_cmd.fd,
+ buf_cmd.y_len, &buf_p->file, &buf_p->handle);
+ if (!buf_p->y_buffer_addr) {
+ GMN_PR_ERR("%s:%d] v2p wrong\n", __func__, __LINE__);
+ kfree(buf_p);
+ return -ENOMEM;
+ }
+ buf_p->y_len = buf_cmd.y_len;
+ buf_p->vbuf = buf_cmd;
+
+ msm_gemini_q_in(&pgmn_dev->output_buf_q, buf_p);
+ return 0;
+}
+
+/*************** input queue ****************/
+
+int msm_gemini_fe_pingpong_irq(struct msm_gemini_device *pgmn_dev,
+ struct msm_gemini_core_buf *buf_in)
+{
+ struct msm_gemini_core_buf *buf_out;
+ int rc = 0;
+
+ GMN_DBG("%s:%d] Enter\n", __func__, __LINE__);
+ if (buf_in) {
+ GMN_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__,
+ (int) buf_in->y_buffer_addr, buf_in->y_len);
+ rc = msm_gemini_q_in_buf(&pgmn_dev->input_rtn_q, buf_in);
+ } else {
+ GMN_DBG("%s:%d] no input return buffer\n", __func__,
+ __LINE__);
+ rc = -1;
+ }
+
+ buf_out = msm_gemini_q_out(&pgmn_dev->input_buf_q);
+
+ if (buf_out) {
+ rc = msm_gemini_core_fe_buf_update(buf_out);
+ kfree(buf_out);
+ msm_gemini_core_fe_start();
+ } else {
+ GMN_DBG("%s:%d] no input buffer\n", __func__, __LINE__);
+ rc = -2;
+ }
+
+ if (buf_in)
+ rc = msm_gemini_q_wakeup(&pgmn_dev->input_rtn_q);
+
+ return rc;
+}
+
+int msm_gemini_input_get(struct msm_gemini_device *pgmn_dev, void __user *to)
+{
+ struct msm_gemini_core_buf *buf_p;
+ struct msm_gemini_buf buf_cmd;
+
+ GMN_DBG("%s:%d] Enter\n", __func__, __LINE__);
+ msm_gemini_q_wait(&pgmn_dev->input_rtn_q);
+ buf_p = msm_gemini_q_out(&pgmn_dev->input_rtn_q);
+
+ if (!buf_p) {
+ GMN_DBG("%s:%d] no input buffer return\n",
+ __func__, __LINE__);
+ return -EAGAIN;
+ }
+
+ buf_cmd = buf_p->vbuf;
+ if (pgmn_dev->op_mode == MSM_GEMINI_MODE_OFFLINE_ENCODE ||
+ pgmn_dev->op_mode == MSM_GEMINI_MODE_OFFLINE_ROTATION) {
+ msm_gemini_platform_p2v(buf_p->file, &buf_p->handle);
+ }
+ kfree(buf_p);
+
+ GMN_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__,
+ (int) buf_cmd.vaddr, buf_cmd.y_len);
+
+ if (copy_to_user(to, &buf_cmd, sizeof(buf_cmd))) {
+ GMN_PR_ERR("%s:%d]\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+int msm_gemini_input_get_unblock(struct msm_gemini_device *pgmn_dev)
+{
+ GMN_DBG("%s:%d] Enter\n", __func__, __LINE__);
+ msm_gemini_q_unblock(&pgmn_dev->input_rtn_q);
+ return 0;
+}
+
+int msm_gemini_input_buf_enqueue(struct msm_gemini_device *pgmn_dev,
+ void __user *arg)
+{
+ struct msm_gemini_core_buf *buf_p;
+ struct msm_gemini_buf buf_cmd;
+ int rc = 0;
+ struct msm_bus_scale_pdata *p_bus_scale_data = NULL;
+
+ if (copy_from_user(&buf_cmd, arg, sizeof(struct msm_gemini_buf))) {
+ GMN_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+
+ buf_p = kmalloc(sizeof(struct msm_gemini_core_buf), GFP_ATOMIC);
+ if (!buf_p) {
+ GMN_PR_ERR("%s:%d] no mem\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+
+ GMN_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__,
+ (int) buf_cmd.vaddr, buf_cmd.y_len);
+
+ if (pgmn_dev->op_mode == MSM_GEMINI_MODE_REALTIME_ENCODE) {
+ rc = msm_iommu_map_contig_buffer(
+ (unsigned long)buf_cmd.y_off, CAMERA_DOMAIN, GEN_POOL,
+ ((buf_cmd.y_len + buf_cmd.cbcr_len + 4095) & (~4095)),
+ SZ_4K, IOMMU_WRITE | IOMMU_READ,
+ (unsigned long *)&buf_p->y_buffer_addr);
+ if (rc < 0) {
+ GMN_PR_ERR("%s iommu mapping failed with error %d\n",
+ __func__, rc);
+ kfree(buf_p);
+ return rc;
+ }
+ } else {
+ buf_p->y_buffer_addr = msm_gemini_platform_v2p(buf_cmd.fd,
+ buf_cmd.y_len + buf_cmd.cbcr_len, &buf_p->file,
+ &buf_p->handle) + buf_cmd.offset + buf_cmd.y_off;
+ }
+ buf_p->y_len = buf_cmd.y_len;
+
+ buf_p->cbcr_buffer_addr = buf_p->y_buffer_addr + buf_cmd.y_len +
+ buf_cmd.cbcr_off;
+ buf_p->cbcr_len = buf_cmd.cbcr_len;
+ buf_p->num_of_mcu_rows = buf_cmd.num_of_mcu_rows;
+ GMN_DBG("%s: y_addr=%x,y_len=%x,cbcr_addr=%x,cbcr_len=%x\n", __func__,
+ buf_p->y_buffer_addr, buf_p->y_len, buf_p->cbcr_buffer_addr,
+ buf_p->cbcr_len);
+
+ if (!buf_p->y_buffer_addr || !buf_p->cbcr_buffer_addr) {
+ GMN_PR_ERR("%s:%d] v2p wrong\n", __func__, __LINE__);
+ kfree(buf_p);
+ return -EINVAL;
+ }
+ buf_p->vbuf = buf_cmd;
+ buf_p->vbuf.type = MSM_GEMINI_EVT_RESET;
+
+ /* Set bus vectors */
+ p_bus_scale_data = (struct msm_bus_scale_pdata *)
+ pgmn_dev->pdev->dev.platform_data;
+ if (pgmn_dev->bus_perf_client &&
+ (MSM_GMN_OUTMODE_SINGLE == pgmn_dev->out_mode)) {
+ int rc;
+ struct msm_bus_paths *path = &(p_bus_scale_data->usecase[1]);
+ GMN_DBG("%s:%d] Update bus bandwidth", __func__, __LINE__);
+ if (pgmn_dev->op_mode & MSM_GEMINI_MODE_OFFLINE_ENCODE) {
+ path->vectors[0].ab = (buf_p->y_len + buf_p->cbcr_len) *
+ 15 * 2;
+ path->vectors[0].ib = path->vectors[0].ab;
+ path->vectors[1].ab = 0;
+ path->vectors[1].ib = 0;
+ }
+ rc = msm_bus_scale_client_update_request(
+ pgmn_dev->bus_perf_client, 1);
+ if (rc < 0) {
+ GMN_PR_ERR("%s:%d] update_request fails %d",
+ __func__, __LINE__, rc);
+ }
+ }
+
+ msm_gemini_q_in(&pgmn_dev->input_buf_q, buf_p);
+
+ return 0;
+}
+
+int msm_gemini_irq(int event, void *context, void *data)
+{
+ struct msm_gemini_device *pgmn_dev =
+ (struct msm_gemini_device *) context;
+
+ switch (event) {
+ case MSM_GEMINI_HW_MASK_COMP_FRAMEDONE:
+ msm_gemini_framedone_irq(pgmn_dev, data);
+ msm_gemini_we_pingpong_irq(pgmn_dev, data);
+ break;
+
+ case MSM_GEMINI_HW_MASK_COMP_FE:
+ msm_gemini_fe_pingpong_irq(pgmn_dev, data);
+ break;
+
+ case MSM_GEMINI_HW_MASK_COMP_WE:
+ msm_gemini_we_pingpong_irq(pgmn_dev, data);
+ break;
+
+ case MSM_GEMINI_HW_MASK_COMP_RESET_ACK:
+ msm_gemini_reset_ack_irq(pgmn_dev);
+ break;
+
+ case MSM_GEMINI_HW_MASK_COMP_ERR:
+ default:
+ msm_gemini_err_irq(pgmn_dev, event);
+ break;
+ }
+
+ return 0;
+}
+
+int __msm_gemini_open(struct msm_gemini_device *pgmn_dev)
+{
+ int rc;
+ struct msm_bus_scale_pdata *p_bus_scale_data =
+ (struct msm_bus_scale_pdata *)pgmn_dev->pdev->dev.
+ platform_data;
+
+ mutex_lock(&pgmn_dev->lock);
+ if (pgmn_dev->open_count) {
+ /* only open once */
+ GMN_PR_ERR("%s:%d] busy\n", __func__, __LINE__);
+ mutex_unlock(&pgmn_dev->lock);
+ return -EBUSY;
+ }
+ pgmn_dev->open_count++;
+ mutex_unlock(&pgmn_dev->lock);
+
+ msm_gemini_core_irq_install(msm_gemini_irq);
+
+
+ rc = msm_gemini_platform_init(pgmn_dev->pdev,
+ &pgmn_dev->mem, &pgmn_dev->base,
+ &pgmn_dev->irq, msm_gemini_core_irq, pgmn_dev);
+ if (rc) {
+ GMN_PR_ERR("%s:%d] platform_init fail %d\n", __func__,
+ __LINE__, rc);
+ return rc;
+ }
+
+ GMN_DBG("%s:%d] platform resources - mem %p, base %p, irq %d\n",
+ __func__, __LINE__,
+ pgmn_dev->mem, pgmn_dev->base, pgmn_dev->irq);
+
+ msm_gemini_q_cleanup(&pgmn_dev->evt_q);
+ msm_gemini_q_cleanup(&pgmn_dev->output_rtn_q);
+ msm_gemini_outbuf_q_cleanup(&pgmn_dev->output_buf_q);
+ msm_gemini_q_cleanup(&pgmn_dev->input_rtn_q);
+ msm_gemini_q_cleanup(&pgmn_dev->input_buf_q);
+ msm_gemini_core_init();
+ pgmn_dev->out_mode = MSM_GMN_OUTMODE_FRAGMENTED;
+ pgmn_dev->out_buf_set = 0;
+ pgmn_dev->out_offset = 0;
+ pgmn_dev->max_out_size = g_max_out_size;
+ pgmn_dev->out_frag_cnt = 0;
+ pgmn_dev->bus_perf_client = 0;
+
+ if (p_bus_scale_data) {
+ GMN_DBG("%s:%d] register bus client", __func__, __LINE__);
+ pgmn_dev->bus_perf_client =
+ msm_bus_scale_register_client(p_bus_scale_data);
+ if (!pgmn_dev->bus_perf_client) {
+ GMN_PR_ERR("%s:%d] bus client register failed",
+ __func__, __LINE__);
+ return -EINVAL;
+ }
+ }
+ GMN_DBG("%s:%d] success\n", __func__, __LINE__);
+ return rc;
+}
+
+int __msm_gemini_release(struct msm_gemini_device *pgmn_dev)
+{
+ GMN_DBG("%s:%d] Enter\n", __func__, __LINE__);
+ mutex_lock(&pgmn_dev->lock);
+ if (!pgmn_dev->open_count) {
+ GMN_PR_ERR("%s: not opened\n", __func__);
+ mutex_unlock(&pgmn_dev->lock);
+ return -EINVAL;
+ }
+ pgmn_dev->open_count--;
+ mutex_unlock(&pgmn_dev->lock);
+
+ if (pgmn_dev->out_mode == MSM_GMN_OUTMODE_FRAGMENTED) {
+ msm_gemini_core_release(release_buf);
+ } else if (pgmn_dev->out_buf_set) {
+ msm_gemini_platform_p2v(pgmn_dev->out_buf.file,
+ &pgmn_dev->out_buf.handle);
+ }
+ msm_gemini_q_cleanup(&pgmn_dev->evt_q);
+ msm_gemini_q_cleanup(&pgmn_dev->output_rtn_q);
+ msm_gemini_outbuf_q_cleanup(&pgmn_dev->output_buf_q);
+ msm_gemini_q_cleanup(&pgmn_dev->input_rtn_q);
+ msm_gemini_outbuf_q_cleanup(&pgmn_dev->input_buf_q);
+
+ if (pgmn_dev->bus_perf_client) {
+ msm_bus_scale_unregister_client(pgmn_dev->bus_perf_client);
+ pgmn_dev->bus_perf_client = 0;
+ }
+
+ if (pgmn_dev->open_count)
+ GMN_PR_ERR("%s: multiple opens\n", __func__);
+
+ msm_gemini_platform_release(pgmn_dev->mem, pgmn_dev->base,
+ pgmn_dev->irq, pgmn_dev);
+
+ return 0;
+}
+
+int msm_gemini_ioctl_hw_cmd(struct msm_gemini_device *pgmn_dev,
+ void * __user arg)
+{
+ struct msm_gemini_hw_cmd hw_cmd;
+ int is_copy_to_user;
+
+ if (copy_from_user(&hw_cmd, arg, sizeof(struct msm_gemini_hw_cmd))) {
+ GMN_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+
+ is_copy_to_user = msm_gemini_hw_exec_cmds(&hw_cmd, 1);
+ GMN_DBG("%s:%d] type %d, n %d, offset %d, mask %x, data %x, pdata %x\n",
+ __func__, __LINE__, hw_cmd.type, hw_cmd.n, hw_cmd.offset,
+ hw_cmd.mask, hw_cmd.data, (int) hw_cmd.pdata);
+
+ if (is_copy_to_user >= 0) {
+ if (copy_to_user(arg, &hw_cmd, sizeof(hw_cmd))) {
+ GMN_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+ }
+
+ return 0;
+}
+
+static int msm_gemini_ioctl_hw_cmds(struct msm_gemini_device *pgmn_dev,
+ void * __user arg)
+{
+ int is_copy_to_user;
+ int len;
+ uint32_t m;
+ struct msm_gemini_hw_cmds *hw_cmds_p;
+ struct msm_gemini_hw_cmd *hw_cmd_p;
+
+ if (copy_from_user(&m, arg, sizeof(m))) {
+ GMN_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+
+ len = sizeof(struct msm_gemini_hw_cmds) +
+ sizeof(struct msm_gemini_hw_cmd) * (m - 1);
+ hw_cmds_p = kmalloc(len, GFP_KERNEL);
+ if (!hw_cmds_p) {
+ GMN_PR_ERR("%s:%d] no mem %d\n", __func__, __LINE__, len);
+ return -EFAULT;
+ }
+
+ if (copy_from_user(hw_cmds_p, arg, len)) {
+ GMN_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+ kfree(hw_cmds_p);
+ return -EFAULT;
+ }
+
+ hw_cmd_p = (struct msm_gemini_hw_cmd *) &(hw_cmds_p->hw_cmd);
+
+ is_copy_to_user = msm_gemini_hw_exec_cmds(hw_cmd_p, m);
+
+ if (is_copy_to_user >= 0) {
+ if (copy_to_user(arg, hw_cmds_p, len)) {
+ GMN_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+ kfree(hw_cmds_p);
+ return -EFAULT;
+ }
+ }
+ kfree(hw_cmds_p);
+ return 0;
+}
+
+static int msm_gemini_start(struct msm_gemini_device *pgmn_dev,
+ void * __user arg)
+{
+ struct msm_gemini_core_buf *buf_out;
+ struct msm_gemini_core_buf *buf_out_free[2] = {NULL, NULL};
+ int i, rc;
+
+ GMN_DBG("%s:%d] Enter\n", __func__, __LINE__);
+
+ release_buf = 1;
+ for (i = 0; i < 2; i++) {
+ buf_out = msm_gemini_q_out(&pgmn_dev->input_buf_q);
+
+ if (buf_out) {
+ msm_gemini_core_fe_buf_update(buf_out);
+ kfree(buf_out);
+ } else {
+ GMN_DBG("%s:%d] no input buffer\n", __func__, __LINE__);
+ break;
+ }
+ }
+
+ if (pgmn_dev->out_mode == MSM_GMN_OUTMODE_FRAGMENTED) {
+ for (i = 0; i < 2; i++) {
+ buf_out_free[i] =
+ msm_gemini_q_out(&pgmn_dev->output_buf_q);
+
+ if (buf_out_free[i]) {
+ msm_gemini_core_we_buf_update(buf_out_free[i]);
+ } else if (i == 1) {
+ /* set the pong to same address as ping */
+ buf_out_free[0]->y_len >>= 1;
+ buf_out_free[0]->y_buffer_addr +=
+ buf_out_free[0]->y_len;
+ msm_gemini_core_we_buf_update(buf_out_free[0]);
+ /*
+ * since ping and pong are same buf
+ * release only once
+ */
+ release_buf = 0;
+ } else {
+ GMN_DBG("%s:%d] no output buffer\n",
+ __func__, __LINE__);
+ break;
+ }
+ }
+ for (i = 0; i < 2; i++)
+ kfree(buf_out_free[i]);
+ } else {
+ struct msm_gemini_core_buf out_buf;
+ /*
+ * Since the same buffer is fragmented, p2v need not be
+ * called for all the buffers
+ */
+ release_buf = 0;
+ if (!pgmn_dev->out_buf_set) {
+ GMN_PR_ERR("%s:%d] output buffer not set",
+ __func__, __LINE__);
+ return -EFAULT;
+ }
+ /* configure ping */
+ rc = msm_gemini_get_out_buffer(pgmn_dev, &out_buf);
+ if (rc) {
+ GMN_PR_ERR("%s:%d] no output buffer for ping",
+ __func__, __LINE__);
+ return rc;
+ }
+ msm_gemini_core_we_buf_update(&out_buf);
+ /* configure pong */
+ rc = msm_gemini_get_out_buffer(pgmn_dev, &out_buf);
+ if (rc) {
+ GMN_DBG("%s:%d] no output buffer for pong",
+ __func__, __LINE__);
+ /* fall through to configure same buffer */
+ }
+ msm_gemini_core_we_buf_update(&out_buf);
+ msm_gemini_io_dump(0x150);
+ }
+
+ rc = msm_gemini_ioctl_hw_cmds(pgmn_dev, arg);
+ GMN_DBG("%s:%d]\n", __func__, __LINE__);
+ return rc;
+}
+
+static int msm_gemini_ioctl_reset(struct msm_gemini_device *pgmn_dev,
+ void * __user arg)
+{
+ int rc;
+ struct msm_gemini_ctrl_cmd ctrl_cmd;
+
+ GMN_DBG("%s:%d] Enter\n", __func__, __LINE__);
+ if (copy_from_user(&ctrl_cmd, arg, sizeof(ctrl_cmd))) {
+ GMN_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+
+ pgmn_dev->op_mode = ctrl_cmd.type;
+
+ rc = msm_gemini_core_reset(pgmn_dev->op_mode, pgmn_dev->base,
+ resource_size(pgmn_dev->mem));
+ return rc;
+}
+
+static int msm_gemini_ioctl_set_outmode(struct msm_gemini_device *pgmn_dev,
+ void * __user arg)
+{
+ int rc = 0;
+ enum msm_gmn_out_mode mode;
+
+ if (copy_from_user(&mode, arg, sizeof(mode))) {
+ GMN_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+ GMN_DBG("%s:%d] mode %d", __func__, __LINE__, mode);
+
+ if ((mode == MSM_GMN_OUTMODE_FRAGMENTED)
+ || (mode == MSM_GMN_OUTMODE_SINGLE))
+ pgmn_dev->out_mode = mode;
+ return rc;
+}
+
+long __msm_gemini_ioctl(struct msm_gemini_device *pgmn_dev,
+ unsigned int cmd, unsigned long arg)
+{
+ int rc = 0;
+ switch (cmd) {
+ case MSM_GMN_IOCTL_GET_HW_VERSION:
+ GMN_DBG("%s:%d] VERSION 1\n", __func__, __LINE__);
+ rc = msm_gemini_ioctl_hw_cmd(pgmn_dev, (void __user *) arg);
+ break;
+
+ case MSM_GMN_IOCTL_RESET:
+ rc = msm_gemini_ioctl_reset(pgmn_dev, (void __user *) arg);
+ break;
+
+ case MSM_GMN_IOCTL_STOP:
+ rc = msm_gemini_ioctl_hw_cmds(pgmn_dev, (void __user *) arg);
+ break;
+
+ case MSM_GMN_IOCTL_START:
+ rc = msm_gemini_start(pgmn_dev, (void __user *) arg);
+ break;
+
+ case MSM_GMN_IOCTL_INPUT_BUF_ENQUEUE:
+ rc = msm_gemini_input_buf_enqueue(pgmn_dev,
+ (void __user *) arg);
+ break;
+
+ case MSM_GMN_IOCTL_INPUT_GET:
+ rc = msm_gemini_input_get(pgmn_dev, (void __user *) arg);
+ break;
+
+ case MSM_GMN_IOCTL_INPUT_GET_UNBLOCK:
+ rc = msm_gemini_input_get_unblock(pgmn_dev);
+ break;
+
+ case MSM_GMN_IOCTL_OUTPUT_BUF_ENQUEUE:
+ if (pgmn_dev->out_mode == MSM_GMN_OUTMODE_FRAGMENTED)
+ rc = msm_gemini_output_buf_enqueue(pgmn_dev,
+ (void __user *) arg);
+ else
+ rc = msm_gemini_set_output_buf(pgmn_dev,
+ (void __user *) arg);
+ break;
+
+ case MSM_GMN_IOCTL_OUTPUT_GET:
+ rc = msm_gemini_output_get(pgmn_dev, (void __user *) arg);
+ break;
+
+ case MSM_GMN_IOCTL_OUTPUT_GET_UNBLOCK:
+ rc = msm_gemini_output_get_unblock(pgmn_dev);
+ break;
+
+ case MSM_GMN_IOCTL_EVT_GET:
+ rc = msm_gemini_evt_get(pgmn_dev, (void __user *) arg);
+ break;
+
+ case MSM_GMN_IOCTL_EVT_GET_UNBLOCK:
+ rc = msm_gemini_evt_get_unblock(pgmn_dev);
+ break;
+
+ case MSM_GMN_IOCTL_HW_CMD:
+ rc = msm_gemini_ioctl_hw_cmd(pgmn_dev, (void __user *) arg);
+ break;
+
+ case MSM_GMN_IOCTL_HW_CMDS:
+ rc = msm_gemini_ioctl_hw_cmds(pgmn_dev, (void __user *) arg);
+ break;
+
+ case MSM_GMN_IOCTL_SET_MODE:
+ rc = msm_gemini_ioctl_set_outmode(pgmn_dev, (void __user *)arg);
+ break;
+
+ default:
+ GMN_PR_ERR("%s:%d] cmd = %d not supported\n",
+ __func__, __LINE__, _IOC_NR(cmd));
+ rc = -EINVAL;
+ break;
+ }
+ return rc;
+}
+
+struct msm_gemini_device *__msm_gemini_init(struct platform_device *pdev)
+{
+ struct msm_gemini_device *pgmn_dev;
+
+ pgmn_dev = kzalloc(sizeof(struct msm_gemini_device), GFP_ATOMIC);
+ if (!pgmn_dev) {
+ GMN_PR_ERR("%s:%d]no mem\n", __func__, __LINE__);
+ return NULL;
+ }
+
+ mutex_init(&pgmn_dev->lock);
+
+ pgmn_dev->pdev = pdev;
+
+ msm_gemini_q_init("evt_q", &pgmn_dev->evt_q);
+ msm_gemini_q_init("output_rtn_q", &pgmn_dev->output_rtn_q);
+ msm_gemini_q_init("output_buf_q", &pgmn_dev->output_buf_q);
+ msm_gemini_q_init("input_rtn_q", &pgmn_dev->input_rtn_q);
+ msm_gemini_q_init("input_buf_q", &pgmn_dev->input_buf_q);
+
+ return pgmn_dev;
+}
+
+int __msm_gemini_exit(struct msm_gemini_device *pgmn_dev)
+{
+ mutex_destroy(&pgmn_dev->lock);
+ kfree(pgmn_dev);
+ return 0;
+}
+
diff --git a/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_sync.h b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_sync.h
new file mode 100644
index 0000000..6982a78
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_sync.h
@@ -0,0 +1,98 @@
+/* Copyright (c) 2010,2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MSM_GEMINI_SYNC_H
+#define MSM_GEMINI_SYNC_H
+
+#include <linux/fs.h>
+#include <linux/list.h>
+#include <linux/cdev.h>
+#include <linux/platform_device.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include "msm_gemini_core.h"
+
+#define GEMINI_7X 0x1
+#define GEMINI_8X60 (0x1 << 1)
+#define GEMINI_8960 (0x1 << 2)
+
+struct msm_gemini_q {
+ char const *name;
+ struct list_head q;
+ spinlock_t lck;
+ wait_queue_head_t wait;
+ int unblck;
+};
+
+struct msm_gemini_q_entry {
+ struct list_head list;
+ void *data;
+};
+
+struct msm_gemini_device {
+ struct platform_device *pdev;
+ struct resource *mem;
+ int irq;
+ void *base;
+ struct clk *gemini_clk[3];
+ struct regulator *gemini_fs;
+ uint32_t hw_version;
+
+ struct device *device;
+ struct cdev cdev;
+ struct mutex lock;
+ char open_count;
+ uint8_t op_mode;
+
+ /* event queue including frame done & err indications
+ */
+ struct msm_gemini_q evt_q;
+
+ /* output return queue
+ */
+ struct msm_gemini_q output_rtn_q;
+
+ /* output buf queue
+ */
+ struct msm_gemini_q output_buf_q;
+
+ /* input return queue
+ */
+ struct msm_gemini_q input_rtn_q;
+
+ /* input buf queue
+ */
+ struct msm_gemini_q input_buf_q;
+
+ struct v4l2_subdev subdev;
+ enum msm_gmn_out_mode out_mode;
+
+ /*single out mode parameters*/
+ struct msm_gemini_hw_buf out_buf;
+ int out_offset;
+ int out_buf_set;
+ int max_out_size;
+ int out_frag_cnt;
+
+ uint32_t bus_perf_client;
+};
+
+int __msm_gemini_open(struct msm_gemini_device *pgmn_dev);
+int __msm_gemini_release(struct msm_gemini_device *pgmn_dev);
+
+long __msm_gemini_ioctl(struct msm_gemini_device *pgmn_dev,
+ unsigned int cmd, unsigned long arg);
+
+struct msm_gemini_device *__msm_gemini_init(struct platform_device *pdev);
+int __msm_gemini_exit(struct msm_gemini_device *pgmn_dev);
+
+#endif /* MSM_GEMINI_SYNC_H */
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 59858b5..88f2f08 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
@@ -80,13 +80,20 @@
}
static uint32_t msm_isp_get_buf_handle(
- struct msm_isp_buf_mgr *buf_mgr)
+ struct msm_isp_buf_mgr *buf_mgr,
+ uint32_t session_id, uint32_t stream_id)
{
int i;
if ((buf_mgr->buf_handle_cnt << 8) == 0)
buf_mgr->buf_handle_cnt++;
for (i = 0; i < buf_mgr->num_buf_q; i++) {
+ if (buf_mgr->bufq[i].session_id == session_id &&
+ buf_mgr->bufq[i].stream_id == stream_id)
+ return 0;
+ }
+
+ for (i = 0; i < buf_mgr->num_buf_q; i++) {
if (buf_mgr->bufq[i].bufq_handle == 0) {
memset(&buf_mgr->bufq[i],
0, sizeof(struct msm_isp_bufq));
@@ -604,7 +611,8 @@
return rc;
}
- buf_request->handle = msm_isp_get_buf_handle(buf_mgr);
+ buf_request->handle = msm_isp_get_buf_handle(buf_mgr,
+ buf_request->session_id, buf_request->stream_id);
if (!buf_request->handle) {
pr_err("Invalid buffer handle\n");
return rc;
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
index 7bc2b7d..6de6e74 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
@@ -38,6 +38,8 @@
#define VFE_PING_FLAG 0xFFFFFFFF
#define VFE_PONG_FLAG 0x0
+#define VFE_MAX_CFG_TIMEOUT 3000
+
struct vfe_device;
struct msm_vfe_axi_stream;
struct msm_vfe_stats_stream;
@@ -88,7 +90,7 @@
void (*enable_wm) (struct vfe_device *vfe_dev,
uint8_t wm_idx, uint8_t enable);
void (*cfg_io_format) (struct vfe_device *vfe_dev,
- struct msm_vfe_axi_stream_request_cmd *stream_req_cmd);
+ struct msm_vfe_axi_stream *stream_info);
void (*cfg_framedrop) (struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream *stream_info);
void (*clear_framedrop) (struct vfe_device *vfe_dev,
@@ -103,13 +105,13 @@
struct msm_vfe_axi_stream *stream_info);
void (*cfg_wm_reg) (struct vfe_device *vfe_dev,
- struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd,
+ struct msm_vfe_axi_stream *stream_info,
uint8_t plane_idx);
void (*clear_wm_reg) (struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx);
void (*cfg_wm_xbar_reg) (struct vfe_device *vfe_dev,
- struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd,
+ struct msm_vfe_axi_stream *stream_info,
uint8_t plane_idx);
void (*clear_wm_xbar_reg) (struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx);
@@ -231,7 +233,8 @@
enum msm_vfe_axi_stream_src stream_src;
uint8_t num_planes;
uint8_t wm[MAX_PLANES_PER_STREAM];
- uint32_t plane_offset[MAX_PLANES_PER_STREAM];
+ uint32_t output_format;/*Planar/RAW/Misc*/
+ struct msm_vfe_axi_plane_cfg plane_cfg[MAX_PLANES_PER_STREAM];
uint8_t comp_mask_index;
struct msm_isp_buffer *buf[2];
uint32_t session_id;
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 679c5cb..3a94af3 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
@@ -441,11 +441,11 @@
}
static void msm_vfe32_cfg_io_format(struct vfe_device *vfe_dev,
- struct msm_vfe_axi_stream_request_cmd *stream_req_cmd)
+ struct msm_vfe_axi_stream *stream_info)
{
int bpp, bpp_reg = 0;
uint32_t io_format_reg;
- bpp = msm_isp_get_bit_per_pixel(stream_req_cmd->output_format);
+ bpp = msm_isp_get_bit_per_pixel(stream_info->output_format);
switch (bpp) {
case 8:
@@ -459,7 +459,7 @@
break;
}
io_format_reg = msm_camera_io_r(vfe_dev->vfe_base + 0x6F8);
- switch (stream_req_cmd->stream_src) {
+ switch (stream_info->stream_src) {
case CAMIF_RAW:
io_format_reg &= 0xFFFFCFFF;
io_format_reg |= bpp_reg << 12;
@@ -565,44 +565,40 @@
static void msm_vfe32_axi_cfg_wm_reg(
struct vfe_device *vfe_dev,
- struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd,
+ struct msm_vfe_axi_stream *stream_info,
uint8_t plane_idx)
{
uint32_t val;
- struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
- struct msm_vfe_axi_stream *stream_info =
- &axi_data->stream_info[
- (stream_cfg_cmd->axi_stream_handle & 0xFF)];
uint32_t wm_base = VFE32_WM_BASE(stream_info->wm[plane_idx]);
if (!stream_info->frame_based) {
/*WR_IMAGE_SIZE*/
val =
((msm_isp_cal_word_per_line(
- stream_cfg_cmd->output_format,
- stream_cfg_cmd->plane_cfg[plane_idx].
+ stream_info->output_format,
+ stream_info->plane_cfg[plane_idx].
output_width)+1)/2 - 1) << 16 |
- (stream_cfg_cmd->plane_cfg[plane_idx].
+ (stream_info->plane_cfg[plane_idx].
output_height - 1);
msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x10);
/*WR_BUFFER_CFG*/
val =
msm_isp_cal_word_per_line(
- stream_cfg_cmd->output_format,
- stream_cfg_cmd->plane_cfg[plane_idx].
+ stream_info->output_format,
+ stream_info->plane_cfg[plane_idx].
output_stride) << 16 |
- (stream_cfg_cmd->plane_cfg[plane_idx].
+ (stream_info->plane_cfg[plane_idx].
output_height - 1) << 4 | VFE32_BURST_LEN;
msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14);
} else {
msm_camera_io_w(0x2, vfe_dev->vfe_base + wm_base);
val =
msm_isp_cal_word_per_line(
- stream_cfg_cmd->output_format,
- stream_cfg_cmd->plane_cfg[plane_idx].
+ stream_info->output_format,
+ stream_info->plane_cfg[plane_idx].
output_width) << 16 |
- (stream_cfg_cmd->plane_cfg[plane_idx].
+ (stream_info->plane_cfg[plane_idx].
output_height - 1) << 4 | VFE32_BURST_LEN;
msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14);
}
@@ -624,19 +620,15 @@
static void msm_vfe32_axi_cfg_wm_xbar_reg(
struct vfe_device *vfe_dev,
- struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd,
- uint8_t plane_idx)
+ struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx)
{
- struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
- struct msm_vfe_axi_stream *stream_info =
- &axi_data->stream_info[(stream_cfg_cmd->axi_stream_handle & 0xFF)];
struct msm_vfe_axi_plane_cfg *plane_cfg =
- &stream_cfg_cmd->plane_cfg[plane_idx];
+ &stream_info->plane_cfg[plane_idx];
uint8_t wm = stream_info->wm[plane_idx];
uint32_t xbar_cfg = 0;
uint32_t xbar_reg_cfg = 0;
- switch (stream_cfg_cmd->stream_src) {
+ switch (stream_info->stream_src) {
case PIX_ENCODER:
case PIX_VIEWFINDER: {
if (plane_cfg->output_plane_format != CRCB_PLANE &&
@@ -644,7 +636,7 @@
/*SINGLE_STREAM_SEL*/
xbar_cfg |= plane_cfg->output_plane_format << 5;
} else {
- switch (stream_cfg_cmd->output_format) {
+ switch (stream_info->output_format) {
case V4L2_PIX_FMT_NV12:
case V4L2_PIX_FMT_NV16:
xbar_cfg |= 0x3 << 3; /*PAIR_STREAM_SWAP_CTRL*/
@@ -652,7 +644,7 @@
}
xbar_cfg |= BIT(1); /*PAIR_STREAM_EN*/
}
- if (stream_cfg_cmd->stream_src == PIX_VIEWFINDER)
+ if (stream_info->stream_src == PIX_VIEWFINDER)
xbar_cfg |= 0x1; /*VIEW_STREAM_EN*/
break;
}
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 756cb41..c4a1b63 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
@@ -436,6 +436,8 @@
{
*irq_status0 = msm_camera_io_r(vfe_dev->vfe_base + 0x38);
*irq_status1 = msm_camera_io_r(vfe_dev->vfe_base + 0x3C);
+ /*Ignore composite 3 irq which is used for dual VFE only*/
+ *irq_status0 &= ~BIT(28);
msm_camera_io_w(*irq_status0, vfe_dev->vfe_base + 0x30);
msm_camera_io_w(*irq_status1, vfe_dev->vfe_base + 0x34);
msm_camera_io_w_mb(1, vfe_dev->vfe_base + 0x24);
@@ -521,14 +523,14 @@
comp_mask &= ~(0x7F << (comp_mask_index * 8));
comp_mask |= (axi_data->composite_info[comp_mask_index].
stream_composite_mask << (comp_mask_index * 8));
- if (stream_info->plane_offset[0])
+ if (stream_info->plane_cfg[0].plane_addr_offset)
comp_mask |= (axi_data->composite_info[comp_mask_index].
stream_composite_mask << 24);
msm_camera_io_w(comp_mask, vfe_dev->vfe_base + 0x40);
irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x28);
irq_mask |= 1 << (comp_mask_index + 25);
- if (stream_info->plane_offset[0] && (comp_mask >> 24))
+ if (stream_info->plane_cfg[0].plane_addr_offset && (comp_mask >> 24))
irq_mask |= BIT(28);
msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x28);
}
@@ -542,14 +544,14 @@
comp_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x40);
comp_mask &= ~(0x7F << (comp_mask_index * 8));
- if (stream_info->plane_offset[0])
+ if (stream_info->plane_cfg[0].plane_addr_offset)
comp_mask &= ~(axi_data->composite_info[comp_mask_index].
stream_composite_mask << 24);
msm_camera_io_w(comp_mask, vfe_dev->vfe_base + 0x40);
irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x28);
irq_mask &= ~(1 << (comp_mask_index + 25));
- if (stream_info->plane_offset[0] && !(comp_mask >> 24))
+ if (stream_info->plane_cfg[0].plane_addr_offset && (comp_mask >> 24))
irq_mask &= ~BIT(28);
msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x28);
}
@@ -612,11 +614,11 @@
}
static void msm_vfe40_cfg_io_format(struct vfe_device *vfe_dev,
- struct msm_vfe_axi_stream_request_cmd *stream_req_cmd)
+ struct msm_vfe_axi_stream *stream_info)
{
int bpp, bpp_reg = 0;
uint32_t io_format_reg;
- bpp = msm_isp_get_bit_per_pixel(stream_req_cmd->output_format);
+ bpp = msm_isp_get_bit_per_pixel(stream_info->output_format);
switch (bpp) {
case 8:
@@ -630,7 +632,7 @@
break;
}
io_format_reg = msm_camera_io_r(vfe_dev->vfe_base + 0x54);
- switch (stream_req_cmd->stream_src) {
+ switch (stream_info->stream_src) {
case CAMIF_RAW:
io_format_reg &= 0xFFFFCFFF;
io_format_reg |= bpp_reg << 12;
@@ -751,43 +753,39 @@
static void msm_vfe40_axi_cfg_wm_reg(
struct vfe_device *vfe_dev,
- struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd,
+ struct msm_vfe_axi_stream *stream_info,
uint8_t plane_idx)
{
uint32_t val;
- struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
- struct msm_vfe_axi_stream *stream_info =
- &axi_data->stream_info[
- (stream_cfg_cmd->axi_stream_handle & 0xFF)];
uint32_t wm_base = VFE40_WM_BASE(stream_info->wm[plane_idx]);
if (!stream_info->frame_based) {
/*WR_IMAGE_SIZE*/
val =
((msm_isp_cal_word_per_line(
- stream_cfg_cmd->output_format,
- stream_cfg_cmd->plane_cfg[plane_idx].
+ stream_info->output_format,
+ stream_info->plane_cfg[plane_idx].
output_width)+1)/2 - 1) << 16 |
- (stream_cfg_cmd->plane_cfg[plane_idx].
+ (stream_info->plane_cfg[plane_idx].
output_height - 1);
msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14);
/*WR_BUFFER_CFG*/
val =
- msm_isp_cal_word_per_line(stream_cfg_cmd->output_format,
- stream_cfg_cmd->plane_cfg[
+ msm_isp_cal_word_per_line(stream_info->output_format,
+ stream_info->plane_cfg[
plane_idx].output_stride) << 16 |
- (stream_cfg_cmd->plane_cfg[
+ (stream_info->plane_cfg[
plane_idx].output_height - 1) << 4 |
VFE40_BURST_LEN;
msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x18);
} else {
msm_camera_io_w(0x2, vfe_dev->vfe_base + wm_base);
val =
- msm_isp_cal_word_per_line(stream_cfg_cmd->output_format,
- stream_cfg_cmd->plane_cfg[
+ msm_isp_cal_word_per_line(stream_info->output_format,
+ stream_info->plane_cfg[
plane_idx].output_width) << 16 |
- (stream_cfg_cmd->plane_cfg[
+ (stream_info->plane_cfg[
plane_idx].output_height - 1) << 4 |
VFE40_BURST_LEN;
msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x18);
@@ -819,20 +817,16 @@
static void msm_vfe40_axi_cfg_wm_xbar_reg(
struct vfe_device *vfe_dev,
- struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd,
+ struct msm_vfe_axi_stream *stream_info,
uint8_t plane_idx)
{
- struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
- struct msm_vfe_axi_stream *stream_info =
- &axi_data->stream_info[
- (stream_cfg_cmd->axi_stream_handle & 0xFF)];
struct msm_vfe_axi_plane_cfg *plane_cfg =
- &stream_cfg_cmd->plane_cfg[plane_idx];
+ &stream_info->plane_cfg[plane_idx];
uint8_t wm = stream_info->wm[plane_idx];
uint32_t xbar_cfg = 0;
uint32_t xbar_reg_cfg = 0;
- switch (stream_cfg_cmd->stream_src) {
+ switch (stream_info->stream_src) {
case PIX_ENCODER:
case PIX_VIEWFINDER: {
if (plane_cfg->output_plane_format != CRCB_PLANE &&
@@ -840,7 +834,7 @@
/*SINGLE_STREAM_SEL*/
xbar_cfg |= plane_cfg->output_plane_format << 8;
} else {
- switch (stream_cfg_cmd->output_format) {
+ switch (stream_info->output_format) {
case V4L2_PIX_FMT_NV12:
case V4L2_PIX_FMT_NV16:
xbar_cfg |= 0x3 << 4; /*PAIR_STREAM_SWAP_CTRL*/
@@ -848,7 +842,7 @@
}
xbar_cfg |= 0x1 << 1; /*PAIR_STREAM_EN*/
}
- if (stream_cfg_cmd->stream_src == PIX_VIEWFINDER)
+ if (stream_info->stream_src == PIX_VIEWFINDER)
xbar_cfg |= 0x1; /*VIEW_STREAM_EN*/
break;
}
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 13160ee..e3d036f6 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
@@ -136,23 +136,23 @@
}
for (i = 0; i < stream_info->num_planes; i++) {
- stream_info->plane_offset[i] =
- stream_cfg_cmd->plane_cfg[i].plane_addr_offset;
+ stream_info->plane_cfg[i] = stream_cfg_cmd->plane_cfg[i];
stream_info->max_width = max(stream_info->max_width,
stream_cfg_cmd->plane_cfg[i].output_width);
}
+ stream_info->output_format = stream_cfg_cmd->output_format;
stream_info->stream_src = stream_cfg_cmd->stream_src;
stream_info->frame_based = stream_cfg_cmd->frame_base;
return 0;
}
static uint32_t msm_isp_axi_get_plane_size(
- struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd, int plane_idx)
+ struct msm_vfe_axi_stream *stream_info, int plane_idx)
{
uint32_t size = 0;
- struct msm_vfe_axi_plane_cfg *plane_cfg = stream_cfg_cmd->plane_cfg;
- switch (stream_cfg_cmd->output_format) {
+ struct msm_vfe_axi_plane_cfg *plane_cfg = stream_info->plane_cfg;
+ switch (stream_info->output_format) {
case V4L2_PIX_FMT_SBGGR8:
case V4L2_PIX_FMT_SGBRG8:
case V4L2_PIX_FMT_SGRBG8:
@@ -211,21 +211,17 @@
}
void msm_isp_axi_reserve_wm(struct msm_vfe_axi_shared_data *axi_data,
- struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd)
+ struct msm_vfe_axi_stream *stream_info)
{
int i, j;
- struct msm_vfe_axi_stream *stream_info =
- &axi_data->stream_info[
- HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle)];
-
for (i = 0; i < stream_info->num_planes; i++) {
for (j = 0; j < axi_data->hw_info->num_wm; j++) {
if (!axi_data->free_wm[j]) {
axi_data->free_wm[j] =
- stream_cfg_cmd->axi_stream_handle;
+ stream_info->stream_handle;
axi_data->wm_image_size[j] =
msm_isp_axi_get_plane_size(
- stream_cfg_cmd, i);
+ stream_info, i);
axi_data->num_used_wm++;
break;
}
@@ -246,20 +242,17 @@
void msm_isp_axi_reserve_comp_mask(
struct msm_vfe_axi_shared_data *axi_data,
- struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd)
+ struct msm_vfe_axi_stream *stream_info)
{
int i;
uint8_t comp_mask = 0;
- struct msm_vfe_axi_stream *stream_info =
- &axi_data->stream_info[
- HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle)];
for (i = 0; i < stream_info->num_planes; i++)
comp_mask |= 1 << stream_info->wm[i];
for (i = 0; i < axi_data->hw_info->num_comp_mask; i++) {
if (!axi_data->composite_info[i].stream_handle) {
axi_data->composite_info[i].stream_handle =
- stream_cfg_cmd->axi_stream_handle;
+ stream_info->stream_handle;
axi_data->composite_info[i].
stream_composite_mask = comp_mask;
axi_data->num_used_composite_mask++;
@@ -384,7 +377,7 @@
break;
}
- sof_event.frame_id = vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id;
+ sof_event.frame_id = vfe_dev->axi_data.src_info[frame_src].frame_id;
sof_event.timestamp = ts->event_time;
msm_isp_send_event(vfe_dev, ISP_EVENT_SOF, &sof_event);
}
@@ -471,18 +464,18 @@
stream_info = &vfe_dev->axi_data.
stream_info[HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle)];
- msm_isp_axi_reserve_wm(&vfe_dev->axi_data, stream_cfg_cmd);
+ msm_isp_axi_reserve_wm(&vfe_dev->axi_data, stream_info);
if (stream_cfg_cmd->stream_src == CAMIF_RAW ||
stream_cfg_cmd->stream_src == IDEAL_RAW)
vfe_dev->hw_info->vfe_ops.axi_ops.
- cfg_io_format(vfe_dev, stream_cfg_cmd);
+ cfg_io_format(vfe_dev, stream_info);
msm_isp_calculate_framedrop(&vfe_dev->axi_data, stream_cfg_cmd);
if (stream_info->num_planes > 1) {
msm_isp_axi_reserve_comp_mask(
- &vfe_dev->axi_data, stream_cfg_cmd);
+ &vfe_dev->axi_data, stream_info);
vfe_dev->hw_info->vfe_ops.axi_ops.
cfg_comp_mask(vfe_dev, stream_info);
} else {
@@ -492,10 +485,10 @@
for (i = 0; i < stream_info->num_planes; i++) {
vfe_dev->hw_info->vfe_ops.axi_ops.
- cfg_wm_reg(vfe_dev, stream_cfg_cmd, i);
+ cfg_wm_reg(vfe_dev, stream_info, i);
vfe_dev->hw_info->vfe_ops.axi_ops.
- cfg_wm_xbar_reg(vfe_dev, stream_cfg_cmd, i);
+ cfg_wm_xbar_reg(vfe_dev, stream_info, i);
}
return rc;
}
@@ -610,7 +603,7 @@
vfe_dev->hw_info->vfe_ops.axi_ops.update_ping_pong_addr(
vfe_dev, stream_info->wm[i],
VFE_PONG_FLAG, buf->mapped_info[i].paddr +
- stream_info->plane_offset[i]);
+ stream_info->plane_cfg[i].plane_addr_offset);
stream_info->buf[1] = buf;
}
@@ -657,7 +650,7 @@
vfe_dev->hw_info->vfe_ops.axi_ops.update_ping_pong_addr(
vfe_dev, stream_info->wm[i],
pingpong_status, buf->mapped_info[i].paddr +
- stream_info->plane_offset[i]);
+ stream_info->plane_cfg[i].plane_addr_offset);
pingpong_bit = (~(pingpong_status >> stream_info->wm[0]) & 0x1);
stream_info->buf[pingpong_bit] = buf;
@@ -852,7 +845,7 @@
spin_unlock_irqrestore(&vfe_dev->shared_data_lock, flags);
rc = wait_for_completion_interruptible_timeout(
&vfe_dev->stream_config_complete,
- msecs_to_jiffies(500));
+ msecs_to_jiffies(VFE_MAX_CFG_TIMEOUT));
if (rc == 0) {
pr_err("%s: wait timeout\n", __func__);
rc = -1;
@@ -976,18 +969,33 @@
enum msm_isp_camif_update_state camif_update)
{
int i, rc = 0;
+ uint8_t wait_for_complete = 0;
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])];
+
stream_info->state = STOP_PENDING;
+ if (stream_info->stream_type == BURST_STREAM &&
+ stream_info->runtime_num_burst_capture == 0) {
+ /*Configure AXI writemasters to stop immediately
+ *since for burst case, write masters already skip
+ *all frames.
+ */
+ msm_isp_axi_stream_enable_cfg(vfe_dev, stream_info);
+ stream_info->state = INACTIVE;
+ } else {
+ wait_for_complete = 1;
+ }
}
- rc = msm_isp_axi_wait_for_cfg_done(vfe_dev, camif_update);
- if (rc < 0) {
- pr_err("%s: wait for config done failed\n", __func__);
- return rc;
+ if (wait_for_complete) {
+ rc = msm_isp_axi_wait_for_cfg_done(vfe_dev, camif_update);
+ if (rc < 0) {
+ pr_err("%s: wait for config done failed\n", __func__);
+ return rc;
+ }
}
msm_isp_update_stream_bandwidth(vfe_dev);
if (camif_update == DISABLE_CAMIF)
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h
index f592a60..3d775f9 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h
@@ -27,15 +27,11 @@
void msm_isp_axi_reserve_wm(
struct msm_vfe_axi_shared_data *axi_data,
- struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd);
-
-void msm_isp_axi_reserve_rdi(
- struct msm_vfe_axi_shared_data *axi_data,
- struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd);
+ struct msm_vfe_axi_stream *stream_info);
void msm_isp_axi_reserve_comp_mask(
struct msm_vfe_axi_shared_data *axi_data,
- struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd);
+ struct msm_vfe_axi_stream *stream_info);
int msm_isp_axi_check_stream_state(
struct vfe_device *vfe_dev,
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 ce71235..d857a14 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
@@ -343,7 +343,7 @@
atomic_set(&vfe_dev->stats_data.stats_update, 2);
rc = wait_for_completion_interruptible_timeout(
&vfe_dev->stats_config_complete,
- msecs_to_jiffies(500));
+ msecs_to_jiffies(VFE_MAX_CFG_TIMEOUT));
if (rc == 0) {
pr_err("%s: wait timeout\n", __func__);
rc = -1;
diff --git a/drivers/media/platform/msm/camera_v2/pproc/Makefile b/drivers/media/platform/msm/camera_v2/pproc/Makefile
index 854e4e7..4193adc 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/Makefile
+++ b/drivers/media/platform/msm/camera_v2/pproc/Makefile
@@ -1 +1,2 @@
obj-$(CONFIG_MSMB_CAMERA) += cpp/
+obj-$(CONFIG_MSMB_CAMERA) += vpe/
diff --git a/drivers/media/platform/msm/camera_v2/pproc/vpe/Makefile b/drivers/media/platform/msm/camera_v2/pproc/vpe/Makefile
new file mode 100644
index 0000000..65a7e34
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/pproc/vpe/Makefile
@@ -0,0 +1,3 @@
+ccflags-y += -Idrivers/media/platform/msm/camera_v2
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io
+obj-$(CONFIG_MSMB_CAMERA) += msm_vpe.o
diff --git a/drivers/media/platform/msm/camera_v2/pproc/vpe/msm_vpe.c b/drivers/media/platform/msm/camera_v2/pproc/vpe/msm_vpe.c
new file mode 100644
index 0000000..d53d766
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/pproc/vpe/msm_vpe.c
@@ -0,0 +1,1643 @@
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "MSM-VPE %s:%d " fmt, __func__, __LINE__
+
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/videodev2.h>
+#include <linux/msm_ion.h>
+#include <linux/iommu.h>
+#include <mach/iommu_domains.h>
+#include <mach/iommu.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-subdev.h>
+#include <media/media-entity.h>
+#include <media/msmb_pproc.h>
+#include <media/msmb_generic_buf_mgr.h>
+#include "msm_vpe.h"
+#include "msm_camera_io_util.h"
+
+#define MSM_VPE_IDENT_TO_SESSION_ID(identity) ((identity >> 16) & 0xFFFF)
+#define MSM_VPE_IDENT_TO_STREAM_ID(identity) (identity & 0xFFFF)
+
+#define MSM_VPE_DRV_NAME "msm_vpe"
+
+#define MSM_VPE_MAX_BUFF_QUEUE 16
+
+#define CONFIG_MSM_VPE_DBG 0
+
+#if CONFIG_MSM_VPE_DBG
+#define VPE_DBG(fmt, args...) pr_err(fmt, ##args)
+#else
+#define VPE_DBG(fmt, args...) pr_debug(fmt, ##args)
+#endif
+
+static void vpe_mem_dump(const char * const name, const void * const addr,
+ int size)
+{
+ char line_str[128], *p_str;
+ int i;
+ u32 *p = (u32 *) addr;
+ u32 data;
+ VPE_DBG("%s: (%s) %p %d\n", __func__, name, addr, size);
+ line_str[0] = '\0';
+ p_str = line_str;
+ for (i = 0; i < size/4; i++) {
+ if (i % 4 == 0) {
+ snprintf(p_str, 12, "%08x: ", (u32) p);
+ p_str += 10;
+ }
+ data = *p++;
+ snprintf(p_str, 12, "%08x ", data);
+ p_str += 9;
+ if ((i + 1) % 4 == 0) {
+ VPE_DBG("%s\n", line_str);
+ line_str[0] = '\0';
+ p_str = line_str;
+ }
+ }
+ if (line_str[0] != '\0')
+ VPE_DBG("%s\n", line_str);
+}
+
+static inline long long vpe_do_div(long long num, long long den)
+{
+ do_div(num, den);
+ return num;
+}
+
+#define msm_dequeue(queue, member) ({ \
+ unsigned long flags; \
+ struct msm_device_queue *__q = (queue); \
+ struct msm_queue_cmd *qcmd = 0; \
+ spin_lock_irqsave(&__q->lock, flags); \
+ if (!list_empty(&__q->list)) { \
+ __q->len--; \
+ qcmd = list_first_entry(&__q->list, \
+ struct msm_queue_cmd, \
+ member); \
+ list_del_init(&qcmd->member); \
+ } \
+ spin_unlock_irqrestore(&__q->lock, flags); \
+ qcmd; \
+ })
+
+static void msm_queue_init(struct msm_device_queue *queue, const char *name)
+{
+ spin_lock_init(&queue->lock);
+ queue->len = 0;
+ queue->max = 0;
+ queue->name = name;
+ INIT_LIST_HEAD(&queue->list);
+ init_waitqueue_head(&queue->wait);
+}
+
+static struct msm_cam_clk_info vpe_clk_info[] = {
+ {"vpe_clk", 160000000},
+ {"vpe_pclk", -1},
+};
+
+static int msm_vpe_notify_frame_done(struct vpe_device *vpe_dev);
+
+static void msm_enqueue(struct msm_device_queue *queue,
+ struct list_head *entry)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&queue->lock, flags);
+ queue->len++;
+ if (queue->len > queue->max) {
+ queue->max = queue->len;
+ pr_debug("queue %s new max is %d\n", queue->name, queue->max);
+ }
+ list_add_tail(entry, &queue->list);
+ wake_up(&queue->wait);
+ VPE_DBG("woke up %s\n", queue->name);
+ spin_unlock_irqrestore(&queue->lock, flags);
+}
+
+static struct msm_vpe_buff_queue_info_t *msm_vpe_get_buff_queue_entry(
+ struct vpe_device *vpe_dev, uint32_t session_id, uint32_t stream_id)
+{
+ uint32_t i = 0;
+ struct msm_vpe_buff_queue_info_t *buff_queue_info = NULL;
+
+ for (i = 0; i < vpe_dev->num_buffq; i++) {
+ if ((vpe_dev->buff_queue[i].used == 1) &&
+ (vpe_dev->buff_queue[i].session_id == session_id) &&
+ (vpe_dev->buff_queue[i].stream_id == stream_id)) {
+ buff_queue_info = &vpe_dev->buff_queue[i];
+ break;
+ }
+ }
+
+ if (buff_queue_info == NULL) {
+ pr_err("error buffer queue entry for sess:%d strm:%d not found\n",
+ session_id, stream_id);
+ }
+ return buff_queue_info;
+}
+
+static unsigned long msm_vpe_get_phy_addr(struct vpe_device *vpe_dev,
+ struct msm_vpe_buff_queue_info_t *buff_queue_info, uint32_t buff_index,
+ uint8_t native_buff)
+{
+ unsigned long phy_add = 0;
+ struct list_head *buff_head;
+ struct msm_vpe_buffer_map_list_t *buff, *save;
+
+ if (native_buff)
+ buff_head = &buff_queue_info->native_buff_head;
+ else
+ buff_head = &buff_queue_info->vb2_buff_head;
+
+ list_for_each_entry_safe(buff, save, buff_head, entry) {
+ if (buff->map_info.buff_info.index == buff_index) {
+ phy_add = buff->map_info.phy_addr;
+ break;
+ }
+ }
+
+ return phy_add;
+}
+
+static unsigned long msm_vpe_queue_buffer_info(struct vpe_device *vpe_dev,
+ struct msm_vpe_buff_queue_info_t *buff_queue,
+ struct msm_vpe_buffer_info_t *buffer_info)
+{
+ struct list_head *buff_head;
+ struct msm_vpe_buffer_map_list_t *buff, *save;
+ int rc = 0;
+
+ if (buffer_info->native_buff)
+ buff_head = &buff_queue->native_buff_head;
+ else
+ buff_head = &buff_queue->vb2_buff_head;
+
+ list_for_each_entry_safe(buff, save, buff_head, entry) {
+ if (buff->map_info.buff_info.index == buffer_info->index) {
+ pr_err("error buffer index already queued\n");
+ return -EINVAL;
+ }
+ }
+
+ buff = kzalloc(
+ sizeof(struct msm_vpe_buffer_map_list_t), GFP_KERNEL);
+ if (!buff) {
+ pr_err("error allocating memory\n");
+ return -EINVAL;
+ }
+
+ buff->map_info.buff_info = *buffer_info;
+ buff->map_info.ion_handle = ion_import_dma_buf(vpe_dev->client,
+ buffer_info->fd);
+ if (IS_ERR_OR_NULL(buff->map_info.ion_handle)) {
+ pr_err("ION import failed\n");
+ goto queue_buff_error1;
+ }
+
+ rc = ion_map_iommu(vpe_dev->client, buff->map_info.ion_handle,
+ vpe_dev->domain_num, 0, SZ_4K, 0,
+ (unsigned long *)&buff->map_info.phy_addr,
+ &buff->map_info.len, 0, 0);
+ if (rc < 0) {
+ pr_err("ION mmap failed\n");
+ goto queue_buff_error2;
+ }
+
+ INIT_LIST_HEAD(&buff->entry);
+ list_add_tail(&buff->entry, buff_head);
+
+ return buff->map_info.phy_addr;
+
+queue_buff_error2:
+ ion_unmap_iommu(vpe_dev->client, buff->map_info.ion_handle,
+ vpe_dev->domain_num, 0);
+queue_buff_error1:
+ ion_free(vpe_dev->client, buff->map_info.ion_handle);
+ buff->map_info.ion_handle = NULL;
+ kzfree(buff);
+
+ return 0;
+}
+
+static void msm_vpe_dequeue_buffer_info(struct vpe_device *vpe_dev,
+ struct msm_vpe_buffer_map_list_t *buff)
+{
+ ion_unmap_iommu(vpe_dev->client, buff->map_info.ion_handle,
+ vpe_dev->domain_num, 0);
+ ion_free(vpe_dev->client, buff->map_info.ion_handle);
+ buff->map_info.ion_handle = NULL;
+
+ list_del_init(&buff->entry);
+ kzfree(buff);
+
+ return;
+}
+
+static unsigned long msm_vpe_fetch_buffer_info(struct vpe_device *vpe_dev,
+ struct msm_vpe_buffer_info_t *buffer_info, uint32_t session_id,
+ uint32_t stream_id)
+{
+ unsigned long phy_addr = 0;
+ struct msm_vpe_buff_queue_info_t *buff_queue_info;
+ uint8_t native_buff = buffer_info->native_buff;
+
+ buff_queue_info = msm_vpe_get_buff_queue_entry(vpe_dev, session_id,
+ stream_id);
+ if (buff_queue_info == NULL) {
+ pr_err("error finding buffer queue entry for sessid:%d strmid:%d\n",
+ session_id, stream_id);
+ return phy_addr;
+ }
+
+ phy_addr = msm_vpe_get_phy_addr(vpe_dev, buff_queue_info,
+ buffer_info->index, native_buff);
+ if ((phy_addr == 0) && (native_buff)) {
+ phy_addr = msm_vpe_queue_buffer_info(vpe_dev, buff_queue_info,
+ buffer_info);
+ }
+ return phy_addr;
+}
+
+static int32_t msm_vpe_enqueue_buff_info_list(struct vpe_device *vpe_dev,
+ struct msm_vpe_stream_buff_info_t *stream_buff_info)
+{
+ uint32_t j;
+ struct msm_vpe_buff_queue_info_t *buff_queue_info;
+
+ buff_queue_info = msm_vpe_get_buff_queue_entry(vpe_dev,
+ (stream_buff_info->identity >> 16) & 0xFFFF,
+ stream_buff_info->identity & 0xFFFF);
+ if (buff_queue_info == NULL) {
+ pr_err("error finding buffer queue entry for sessid:%d strmid:%d\n",
+ (stream_buff_info->identity >> 16) & 0xFFFF,
+ stream_buff_info->identity & 0xFFFF);
+ return -EINVAL;
+ }
+
+ for (j = 0; j < stream_buff_info->num_buffs; j++) {
+ msm_vpe_queue_buffer_info(vpe_dev, buff_queue_info,
+ &stream_buff_info->buffer_info[j]);
+ }
+ return 0;
+}
+
+static int32_t msm_vpe_dequeue_buff_info_list(struct vpe_device *vpe_dev,
+ struct msm_vpe_buff_queue_info_t *buff_queue_info)
+{
+ struct msm_vpe_buffer_map_list_t *buff, *save;
+ struct list_head *buff_head;
+
+ buff_head = &buff_queue_info->native_buff_head;
+ list_for_each_entry_safe(buff, save, buff_head, entry) {
+ msm_vpe_dequeue_buffer_info(vpe_dev, buff);
+ }
+
+ buff_head = &buff_queue_info->vb2_buff_head;
+ list_for_each_entry_safe(buff, save, buff_head, entry) {
+ msm_vpe_dequeue_buffer_info(vpe_dev, buff);
+ }
+
+ return 0;
+}
+
+static int32_t msm_vpe_add_buff_queue_entry(struct vpe_device *vpe_dev,
+ uint16_t session_id, uint16_t stream_id)
+{
+ uint32_t i;
+ struct msm_vpe_buff_queue_info_t *buff_queue_info;
+
+ for (i = 0; i < vpe_dev->num_buffq; i++) {
+ if (vpe_dev->buff_queue[i].used == 0) {
+ buff_queue_info = &vpe_dev->buff_queue[i];
+ buff_queue_info->used = 1;
+ buff_queue_info->session_id = session_id;
+ buff_queue_info->stream_id = stream_id;
+ INIT_LIST_HEAD(&buff_queue_info->vb2_buff_head);
+ INIT_LIST_HEAD(&buff_queue_info->native_buff_head);
+ return 0;
+ }
+ }
+ pr_err("buffer queue full. error for sessionid: %d streamid: %d\n",
+ session_id, stream_id);
+ return -EINVAL;
+}
+
+static int32_t msm_vpe_free_buff_queue_entry(struct vpe_device *vpe_dev,
+ uint32_t session_id, uint32_t stream_id)
+{
+ struct msm_vpe_buff_queue_info_t *buff_queue_info;
+
+ buff_queue_info = msm_vpe_get_buff_queue_entry(vpe_dev, session_id,
+ stream_id);
+ if (buff_queue_info == NULL) {
+ pr_err("error finding buffer queue entry for sessid:%d strmid:%d\n",
+ session_id, stream_id);
+ return -EINVAL;
+ }
+
+ buff_queue_info->used = 0;
+ buff_queue_info->session_id = 0;
+ buff_queue_info->stream_id = 0;
+ INIT_LIST_HEAD(&buff_queue_info->vb2_buff_head);
+ INIT_LIST_HEAD(&buff_queue_info->native_buff_head);
+ return 0;
+}
+
+static int32_t msm_vpe_create_buff_queue(struct vpe_device *vpe_dev,
+ uint32_t num_buffq)
+{
+ struct msm_vpe_buff_queue_info_t *buff_queue;
+ buff_queue = kzalloc(
+ sizeof(struct msm_vpe_buff_queue_info_t) * num_buffq,
+ GFP_KERNEL);
+ if (!buff_queue) {
+ pr_err("Buff queue allocation failure\n");
+ return -ENOMEM;
+ }
+
+ if (vpe_dev->buff_queue) {
+ pr_err("Buff queue not empty\n");
+ kzfree(buff_queue);
+ return -EINVAL;
+ } else {
+ vpe_dev->buff_queue = buff_queue;
+ vpe_dev->num_buffq = num_buffq;
+ }
+ return 0;
+}
+
+static void msm_vpe_delete_buff_queue(struct vpe_device *vpe_dev)
+{
+ uint32_t i;
+
+ for (i = 0; i < vpe_dev->num_buffq; i++) {
+ if (vpe_dev->buff_queue[i].used == 1) {
+ pr_err("Queue not free sessionid: %d, streamid: %d\n",
+ vpe_dev->buff_queue[i].session_id,
+ vpe_dev->buff_queue[i].stream_id);
+ msm_vpe_free_buff_queue_entry(vpe_dev,
+ vpe_dev->buff_queue[i].session_id,
+ vpe_dev->buff_queue[i].stream_id);
+ }
+ }
+ kzfree(vpe_dev->buff_queue);
+ vpe_dev->buff_queue = NULL;
+ vpe_dev->num_buffq = 0;
+ return;
+}
+
+void vpe_release_ion_client(struct kref *ref)
+{
+ struct vpe_device *vpe_dev = container_of(ref,
+ struct vpe_device, refcount);
+ ion_client_destroy(vpe_dev->client);
+}
+
+static int vpe_init_mem(struct vpe_device *vpe_dev)
+{
+ kref_init(&vpe_dev->refcount);
+ kref_get(&vpe_dev->refcount);
+ vpe_dev->client = msm_ion_client_create(-1, "vpe");
+
+ if (!vpe_dev->client) {
+ pr_err("couldn't create ion client\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static void vpe_deinit_mem(struct vpe_device *vpe_dev)
+{
+ kref_put(&vpe_dev->refcount, vpe_release_ion_client);
+}
+
+static irqreturn_t msm_vpe_irq(int irq_num, void *data)
+{
+ unsigned long flags;
+ uint32_t irq_status;
+ struct msm_vpe_tasklet_queue_cmd *queue_cmd;
+ struct vpe_device *vpe_dev = (struct vpe_device *) data;
+
+ irq_status = msm_camera_io_r_mb(vpe_dev->base +
+ VPE_INTR_STATUS_OFFSET);
+
+ spin_lock_irqsave(&vpe_dev->tasklet_lock, flags);
+ queue_cmd = &vpe_dev->tasklet_queue_cmd[vpe_dev->taskletq_idx];
+ if (queue_cmd->cmd_used) {
+ VPE_DBG("%s: vpe tasklet queue overflow\n", __func__);
+ list_del(&queue_cmd->list);
+ } else {
+ atomic_add(1, &vpe_dev->irq_cnt);
+ }
+ queue_cmd->irq_status = irq_status;
+
+ queue_cmd->cmd_used = 1;
+ vpe_dev->taskletq_idx =
+ (vpe_dev->taskletq_idx + 1) % MSM_VPE_TASKLETQ_SIZE;
+ list_add_tail(&queue_cmd->list, &vpe_dev->tasklet_q);
+ spin_unlock_irqrestore(&vpe_dev->tasklet_lock, flags);
+
+ tasklet_schedule(&vpe_dev->vpe_tasklet);
+
+ msm_camera_io_w_mb(irq_status, vpe_dev->base + VPE_INTR_CLEAR_OFFSET);
+ msm_camera_io_w(0, vpe_dev->base + VPE_INTR_ENABLE_OFFSET);
+ VPE_DBG("%s: irq_status=0x%x.\n", __func__, irq_status);
+
+ return IRQ_HANDLED;
+}
+
+static void msm_vpe_do_tasklet(unsigned long data)
+{
+ unsigned long flags;
+ struct vpe_device *vpe_dev = (struct vpe_device *)data;
+ struct msm_vpe_tasklet_queue_cmd *queue_cmd;
+
+ while (atomic_read(&vpe_dev->irq_cnt)) {
+ spin_lock_irqsave(&vpe_dev->tasklet_lock, flags);
+ queue_cmd = list_first_entry(&vpe_dev->tasklet_q,
+ struct msm_vpe_tasklet_queue_cmd, list);
+ if (!queue_cmd) {
+ atomic_set(&vpe_dev->irq_cnt, 0);
+ spin_unlock_irqrestore(&vpe_dev->tasklet_lock, flags);
+ return;
+ }
+ atomic_sub(1, &vpe_dev->irq_cnt);
+ list_del(&queue_cmd->list);
+ queue_cmd->cmd_used = 0;
+
+ spin_unlock_irqrestore(&vpe_dev->tasklet_lock, flags);
+
+ VPE_DBG("Frame done!!\n");
+ msm_vpe_notify_frame_done(vpe_dev);
+ }
+}
+
+static int vpe_init_hardware(struct vpe_device *vpe_dev)
+{
+ int rc = 0;
+
+ if (vpe_dev->fs_vpe == NULL) {
+ vpe_dev->fs_vpe =
+ regulator_get(&vpe_dev->pdev->dev, "vdd");
+ if (IS_ERR(vpe_dev->fs_vpe)) {
+ pr_err("Regulator vpe vdd get failed %ld\n",
+ PTR_ERR(vpe_dev->fs_vpe));
+ vpe_dev->fs_vpe = NULL;
+ rc = -ENODEV;
+ goto fail;
+ } else if (regulator_enable(vpe_dev->fs_vpe)) {
+ pr_err("Regulator vpe vdd enable failed\n");
+ regulator_put(vpe_dev->fs_vpe);
+ vpe_dev->fs_vpe = NULL;
+ rc = -ENODEV;
+ goto fail;
+ }
+ }
+
+ rc = msm_cam_clk_enable(&vpe_dev->pdev->dev, vpe_clk_info,
+ vpe_dev->vpe_clk, ARRAY_SIZE(vpe_clk_info), 1);
+ if (rc < 0) {
+ rc = -ENODEV;
+ pr_err("clk enable failed\n");
+ goto disable_and_put_regulator;
+ }
+
+ vpe_dev->base = ioremap(vpe_dev->mem->start,
+ resource_size(vpe_dev->mem));
+ if (!vpe_dev->base) {
+ rc = -ENOMEM;
+ pr_err("ioremap failed\n");
+ goto disable_and_put_regulator;
+ }
+
+ if (vpe_dev->state != VPE_STATE_BOOT) {
+ rc = request_irq(vpe_dev->irq->start, msm_vpe_irq,
+ IRQF_TRIGGER_RISING,
+ "vpe", vpe_dev);
+ if (rc < 0) {
+ pr_err("irq request fail! start=%u\n",
+ vpe_dev->irq->start);
+ rc = -EBUSY;
+ goto unmap_base;
+ } else {
+ VPE_DBG("Got irq! %d\n", vpe_dev->irq->start);
+ }
+ } else {
+ VPE_DBG("Skip requesting the irq since device is booting\n");
+ }
+ vpe_dev->buf_mgr_subdev = msm_buf_mngr_get_subdev();
+
+ msm_vpe_create_buff_queue(vpe_dev, MSM_VPE_MAX_BUFF_QUEUE);
+ return rc;
+
+unmap_base:
+ iounmap(vpe_dev->base);
+disable_and_put_regulator:
+ regulator_disable(vpe_dev->fs_vpe);
+ regulator_put(vpe_dev->fs_vpe);
+fail:
+ return rc;
+}
+
+static int vpe_release_hardware(struct vpe_device *vpe_dev)
+{
+ if (vpe_dev->state != VPE_STATE_BOOT) {
+ free_irq(vpe_dev->irq->start, vpe_dev);
+ tasklet_kill(&vpe_dev->vpe_tasklet);
+ atomic_set(&vpe_dev->irq_cnt, 0);
+ }
+
+ msm_vpe_delete_buff_queue(vpe_dev);
+ iounmap(vpe_dev->base);
+ msm_cam_clk_enable(&vpe_dev->pdev->dev, vpe_clk_info,
+ vpe_dev->vpe_clk, ARRAY_SIZE(vpe_clk_info), 0);
+ return 0;
+}
+
+static int vpe_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+ int rc = 0;
+ uint32_t i;
+ struct vpe_device *vpe_dev = v4l2_get_subdevdata(sd);
+
+ mutex_lock(&vpe_dev->mutex);
+ if (vpe_dev->vpe_open_cnt == MAX_ACTIVE_VPE_INSTANCE) {
+ pr_err("No free VPE instance\n");
+ rc = -ENODEV;
+ goto err_mutex_unlock;
+ }
+
+ for (i = 0; i < MAX_ACTIVE_VPE_INSTANCE; i++) {
+ if (vpe_dev->vpe_subscribe_list[i].active == 0) {
+ vpe_dev->vpe_subscribe_list[i].active = 1;
+ vpe_dev->vpe_subscribe_list[i].vfh = &fh->vfh;
+ break;
+ }
+ }
+ if (i == MAX_ACTIVE_VPE_INSTANCE) {
+ pr_err("No free instance\n");
+ rc = -ENODEV;
+ goto err_mutex_unlock;
+ }
+
+ VPE_DBG("open %d %p\n", i, &fh->vfh);
+ vpe_dev->vpe_open_cnt++;
+ if (vpe_dev->vpe_open_cnt == 1) {
+ rc = vpe_init_hardware(vpe_dev);
+ if (rc < 0) {
+ pr_err("%s: Couldn't init vpe hardware\n", __func__);
+ vpe_dev->vpe_open_cnt--;
+ rc = -ENODEV;
+ goto err_fixup_sub_list;
+ }
+ rc = vpe_init_mem(vpe_dev);
+ if (rc < 0) {
+ pr_err("%s: Couldn't init mem\n", __func__);
+ vpe_dev->vpe_open_cnt--;
+ rc = -ENODEV;
+ goto err_release_hardware;
+ }
+ vpe_dev->state = VPE_STATE_IDLE;
+ }
+ mutex_unlock(&vpe_dev->mutex);
+
+ return rc;
+
+err_release_hardware:
+ vpe_release_hardware(vpe_dev);
+err_fixup_sub_list:
+ for (i = 0; i < MAX_ACTIVE_VPE_INSTANCE; i++) {
+ if (vpe_dev->vpe_subscribe_list[i].vfh == &fh->vfh) {
+ vpe_dev->vpe_subscribe_list[i].active = 0;
+ vpe_dev->vpe_subscribe_list[i].vfh = NULL;
+ break;
+ }
+ }
+err_mutex_unlock:
+ mutex_unlock(&vpe_dev->mutex);
+ return rc;
+}
+
+static int vpe_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+ uint32_t i;
+ struct vpe_device *vpe_dev = v4l2_get_subdevdata(sd);
+ mutex_lock(&vpe_dev->mutex);
+ for (i = 0; i < MAX_ACTIVE_VPE_INSTANCE; i++) {
+ if (vpe_dev->vpe_subscribe_list[i].vfh == &fh->vfh) {
+ vpe_dev->vpe_subscribe_list[i].active = 0;
+ vpe_dev->vpe_subscribe_list[i].vfh = NULL;
+ break;
+ }
+ }
+ if (i == MAX_ACTIVE_VPE_INSTANCE) {
+ pr_err("Invalid close\n");
+ mutex_unlock(&vpe_dev->mutex);
+ return -ENODEV;
+ }
+
+ VPE_DBG("close %d %p\n", i, &fh->vfh);
+ vpe_dev->vpe_open_cnt--;
+ if (vpe_dev->vpe_open_cnt == 0) {
+ vpe_deinit_mem(vpe_dev);
+ vpe_release_hardware(vpe_dev);
+ vpe_dev->state = VPE_STATE_OFF;
+ }
+ mutex_unlock(&vpe_dev->mutex);
+ return 0;
+}
+
+static const struct v4l2_subdev_internal_ops msm_vpe_internal_ops = {
+ .open = vpe_open_node,
+ .close = vpe_close_node,
+};
+
+static int msm_vpe_buffer_ops(struct vpe_device *vpe_dev,
+ uint32_t buff_mgr_ops, struct msm_buf_mngr_info *buff_mgr_info)
+{
+ int rc = -EINVAL;
+
+ rc = v4l2_subdev_call(vpe_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);
+ return rc;
+}
+
+static int msm_vpe_notify_frame_done(struct vpe_device *vpe_dev)
+{
+ struct v4l2_event v4l2_evt;
+ struct msm_queue_cmd *frame_qcmd;
+ struct msm_queue_cmd *event_qcmd;
+ struct msm_vpe_frame_info_t *processed_frame;
+ struct msm_device_queue *queue = &vpe_dev->processing_q;
+ struct msm_buf_mngr_info buff_mgr_info;
+ int rc = 0;
+
+ if (queue->len > 0) {
+ frame_qcmd = msm_dequeue(queue, list_frame);
+ processed_frame = frame_qcmd->command;
+ do_gettimeofday(&(processed_frame->out_time));
+ kfree(frame_qcmd);
+ event_qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_ATOMIC);
+ if (!event_qcmd) {
+ pr_err("%s: Insufficient memory\n", __func__);
+ return -ENOMEM;
+ }
+ atomic_set(&event_qcmd->on_heap, 1);
+ event_qcmd->command = processed_frame;
+ VPE_DBG("fid %d\n", processed_frame->frame_id);
+ msm_enqueue(&vpe_dev->eventData_q, &event_qcmd->list_eventdata);
+
+ if (!processed_frame->output_buffer_info.processed_divert) {
+ memset(&buff_mgr_info, 0 ,
+ sizeof(buff_mgr_info));
+ buff_mgr_info.session_id =
+ ((processed_frame->identity >> 16) & 0xFFFF);
+ buff_mgr_info.stream_id =
+ (processed_frame->identity & 0xFFFF);
+ buff_mgr_info.frame_id = processed_frame->frame_id;
+ buff_mgr_info.timestamp = processed_frame->timestamp;
+ buff_mgr_info.index =
+ processed_frame->output_buffer_info.index;
+ rc = msm_vpe_buffer_ops(vpe_dev,
+ VIDIOC_MSM_BUF_MNGR_BUF_DONE,
+ &buff_mgr_info);
+ if (rc < 0) {
+ pr_err("%s: error doing VIDIOC_MSM_BUF_MNGR_BUF_DONE\n",
+ __func__);
+ rc = -EINVAL;
+ }
+ }
+
+ v4l2_evt.id = processed_frame->inst_id;
+ v4l2_evt.type = V4L2_EVENT_VPE_FRAME_DONE;
+ v4l2_event_queue(vpe_dev->msm_sd.sd.devnode, &v4l2_evt);
+ }
+ return rc;
+}
+
+static void vpe_update_scaler_params(struct vpe_device *vpe_dev,
+ struct msm_vpe_frame_strip_info strip_info)
+{
+ uint32_t out_ROI_width, out_ROI_height;
+ uint32_t src_ROI_width, src_ROI_height;
+
+ /*
+ * phase_step_x, phase_step_y, phase_init_x and phase_init_y
+ * are represented in fixed-point, unsigned 3.29 format
+ */
+ uint32_t phase_step_x = 0;
+ uint32_t phase_step_y = 0;
+ uint32_t phase_init_x = 0;
+ uint32_t phase_init_y = 0;
+
+ uint32_t src_roi, src_x, src_y, src_xy, temp;
+ uint32_t yscale_filter_sel, xscale_filter_sel;
+ uint32_t scale_unit_sel_x, scale_unit_sel_y;
+ uint64_t numerator, denominator;
+
+ /*
+ * assumption is both direction need zoom. this can be
+ * improved.
+ */
+ temp = msm_camera_io_r(vpe_dev->base + VPE_OP_MODE_OFFSET) | 0x3;
+ msm_camera_io_w(temp, vpe_dev->base + VPE_OP_MODE_OFFSET);
+
+ src_ROI_width = strip_info.src_w;
+ src_ROI_height = strip_info.src_h;
+ out_ROI_width = strip_info.dst_w;
+ out_ROI_height = strip_info.dst_h;
+
+ VPE_DBG("src w = %u, h=%u, dst w = %u, h =%u.\n",
+ src_ROI_width, src_ROI_height, out_ROI_width,
+ out_ROI_height);
+ src_roi = (src_ROI_height << 16) + src_ROI_width;
+
+ msm_camera_io_w(src_roi, vpe_dev->base + VPE_SRC_SIZE_OFFSET);
+
+ src_x = strip_info.src_x;
+ src_y = strip_info.src_y;
+
+ VPE_DBG("src_x = %d, src_y=%d.\n", src_x, src_y);
+
+ src_xy = src_y*(1<<16) + src_x;
+ msm_camera_io_w(src_xy, vpe_dev->base +
+ VPE_SRC_XY_OFFSET);
+ VPE_DBG("src_xy = 0x%x, src_roi=0x%x.\n", src_xy, src_roi);
+
+ /* decide whether to use FIR or M/N for scaling */
+ if ((out_ROI_width == 1 && src_ROI_width < 4) ||
+ (src_ROI_width < 4 * out_ROI_width - 3))
+ scale_unit_sel_x = 0;/* use FIR scalar */
+ else
+ scale_unit_sel_x = 1;/* use M/N scalar */
+
+ if ((out_ROI_height == 1 && src_ROI_height < 4) ||
+ (src_ROI_height < 4 * out_ROI_height - 3))
+ scale_unit_sel_y = 0;/* use FIR scalar */
+ else
+ scale_unit_sel_y = 1;/* use M/N scalar */
+
+ /* calculate phase step for the x direction */
+
+ /*
+ * if destination is only 1 pixel wide, the value of
+ * phase_step_x is unimportant. Assigning phase_step_x to src
+ * ROI width as an arbitrary value.
+ */
+ if (out_ROI_width == 1)
+ phase_step_x = (uint32_t) ((src_ROI_width) <<
+ SCALER_PHASE_BITS);
+
+ /* if using FIR scalar */
+ else if (scale_unit_sel_x == 0) {
+
+ /*
+ * Calculate the quotient ( src_ROI_width - 1 ) (
+ * out_ROI_width - 1) with u3.29 precision. Quotient
+ * is rounded up to the larger 29th decimal point
+ */
+ numerator = (uint64_t)(src_ROI_width - 1) <<
+ SCALER_PHASE_BITS;
+ /*
+ * never equals to 0 because of the "(out_ROI_width ==
+ * 1 )"
+ */
+ denominator = (uint64_t)(out_ROI_width - 1);
+ /*
+ * divide and round up to the larger 29th decimal
+ * point.
+ */
+ phase_step_x = (uint32_t) vpe_do_div((numerator +
+ denominator - 1), denominator);
+ } else if (scale_unit_sel_x == 1) { /* if M/N scalar */
+ /*
+ * Calculate the quotient ( src_ROI_width ) / (
+ * out_ROI_width) with u3.29 precision. Quotient is
+ * rounded down to the smaller 29th decimal point.
+ */
+ numerator = (uint64_t)(src_ROI_width) <<
+ SCALER_PHASE_BITS;
+ denominator = (uint64_t)(out_ROI_width);
+ phase_step_x =
+ (uint32_t) vpe_do_div(numerator, denominator);
+ }
+ /* calculate phase step for the y direction */
+
+ /*
+ * if destination is only 1 pixel wide, the value of
+ * phase_step_x is unimportant. Assigning phase_step_x to src
+ * ROI width as an arbitrary value.
+ */
+ if (out_ROI_height == 1)
+ phase_step_y =
+ (uint32_t) ((src_ROI_height) << SCALER_PHASE_BITS);
+
+ /* if FIR scalar */
+ else if (scale_unit_sel_y == 0) {
+ /*
+ * Calculate the quotient ( src_ROI_height - 1 ) / (
+ * out_ROI_height - 1) with u3.29 precision. Quotient
+ * is rounded up to the larger 29th decimal point.
+ */
+ numerator = (uint64_t)(src_ROI_height - 1) <<
+ SCALER_PHASE_BITS;
+ /*
+ * never equals to 0 because of the " ( out_ROI_height
+ * == 1 )" case
+ */
+ denominator = (uint64_t)(out_ROI_height - 1);
+ /*
+ * Quotient is rounded up to the larger 29th decimal
+ * point.
+ */
+ phase_step_y =
+ (uint32_t) vpe_do_div(
+ (numerator + denominator - 1), denominator);
+ } else if (scale_unit_sel_y == 1) { /* if M/N scalar */
+ /*
+ * Calculate the quotient ( src_ROI_height ) (
+ * out_ROI_height) with u3.29 precision. Quotient is
+ * rounded down to the smaller 29th decimal point.
+ */
+ numerator = (uint64_t)(src_ROI_height) <<
+ SCALER_PHASE_BITS;
+ denominator = (uint64_t)(out_ROI_height);
+ phase_step_y = (uint32_t) vpe_do_div(
+ numerator, denominator);
+ }
+
+ /* decide which set of FIR coefficients to use */
+ if (phase_step_x > HAL_MDP_PHASE_STEP_2P50)
+ xscale_filter_sel = 0;
+ else if (phase_step_x > HAL_MDP_PHASE_STEP_1P66)
+ xscale_filter_sel = 1;
+ else if (phase_step_x > HAL_MDP_PHASE_STEP_1P25)
+ xscale_filter_sel = 2;
+ else
+ xscale_filter_sel = 3;
+
+ if (phase_step_y > HAL_MDP_PHASE_STEP_2P50)
+ yscale_filter_sel = 0;
+ else if (phase_step_y > HAL_MDP_PHASE_STEP_1P66)
+ yscale_filter_sel = 1;
+ else if (phase_step_y > HAL_MDP_PHASE_STEP_1P25)
+ yscale_filter_sel = 2;
+ else
+ yscale_filter_sel = 3;
+
+ /* calculate phase init for the x direction */
+
+ /* if using FIR scalar */
+ if (scale_unit_sel_x == 0) {
+ if (out_ROI_width == 1)
+ phase_init_x =
+ (uint32_t) ((src_ROI_width - 1) <<
+ SCALER_PHASE_BITS);
+ else
+ phase_init_x = 0;
+ } else if (scale_unit_sel_x == 1) /* M over N scalar */
+ phase_init_x = 0;
+
+ /*
+ * calculate phase init for the y direction if using FIR
+ * scalar
+ */
+ if (scale_unit_sel_y == 0) {
+ if (out_ROI_height == 1)
+ phase_init_y =
+ (uint32_t) ((src_ROI_height -
+ 1) << SCALER_PHASE_BITS);
+ else
+ phase_init_y = 0;
+ } else if (scale_unit_sel_y == 1) /* M over N scalar */
+ phase_init_y = 0;
+
+ strip_info.phase_step_x = phase_step_x;
+ strip_info.phase_step_y = phase_step_y;
+ strip_info.phase_init_x = phase_init_x;
+ strip_info.phase_init_y = phase_init_y;
+ VPE_DBG("phase step x = %d, step y = %d.\n",
+ strip_info.phase_step_x, strip_info.phase_step_y);
+ VPE_DBG("phase init x = %d, init y = %d.\n",
+ strip_info.phase_init_x, strip_info.phase_init_y);
+
+ msm_camera_io_w(strip_info.phase_step_x, vpe_dev->base +
+ VPE_SCALE_PHASEX_STEP_OFFSET);
+ msm_camera_io_w(strip_info.phase_step_y, vpe_dev->base +
+ VPE_SCALE_PHASEY_STEP_OFFSET);
+
+ msm_camera_io_w(strip_info.phase_init_x, vpe_dev->base +
+ VPE_SCALE_PHASEX_INIT_OFFSET);
+ msm_camera_io_w(strip_info.phase_init_y, vpe_dev->base +
+ VPE_SCALE_PHASEY_INIT_OFFSET);
+}
+
+static void vpe_program_buffer_addresses(
+ struct vpe_device *vpe_dev,
+ unsigned long srcP0,
+ unsigned long srcP1,
+ unsigned long outP0,
+ unsigned long outP1)
+{
+ VPE_DBG("%s VPE Configured with:\n"
+ "Src %x, %x Dest %x, %x",
+ __func__, (uint32_t)srcP0, (uint32_t)srcP1,
+ (uint32_t)outP0, (uint32_t)outP1);
+
+ msm_camera_io_w(srcP0, vpe_dev->base + VPE_SRCP0_ADDR_OFFSET);
+ msm_camera_io_w(srcP1, vpe_dev->base + VPE_SRCP1_ADDR_OFFSET);
+ msm_camera_io_w(outP0, vpe_dev->base + VPE_OUTP0_ADDR_OFFSET);
+ msm_camera_io_w(outP1, vpe_dev->base + VPE_OUTP1_ADDR_OFFSET);
+}
+
+static int vpe_start(struct vpe_device *vpe_dev)
+{
+ /* enable the frame irq, bit 0 = Display list 0 ROI done */
+ msm_camera_io_w_mb(1, vpe_dev->base + VPE_INTR_ENABLE_OFFSET);
+ msm_camera_io_dump(vpe_dev->base, 0x120);
+ msm_camera_io_dump(vpe_dev->base + 0x00400, 0x18);
+ msm_camera_io_dump(vpe_dev->base + 0x10000, 0x250);
+ msm_camera_io_dump(vpe_dev->base + 0x30000, 0x20);
+ msm_camera_io_dump(vpe_dev->base + 0x50000, 0x30);
+ msm_camera_io_dump(vpe_dev->base + 0x50400, 0x10);
+
+ /*
+ * This triggers the operation. When the VPE is done,
+ * msm_vpe_irq will fire.
+ */
+ msm_camera_io_w_mb(1, vpe_dev->base + VPE_DL0_START_OFFSET);
+ return 0;
+}
+
+static void vpe_config_axi_default(struct vpe_device *vpe_dev)
+{
+ msm_camera_io_w(0x25, vpe_dev->base + VPE_AXI_ARB_2_OFFSET);
+}
+
+static int vpe_reset(struct vpe_device *vpe_dev)
+{
+ uint32_t vpe_version;
+ uint32_t rc = 0;
+
+ vpe_version = msm_camera_io_r(
+ vpe_dev->base + VPE_HW_VERSION_OFFSET);
+ VPE_DBG("vpe_version = 0x%x\n", vpe_version);
+ /* disable all interrupts.*/
+ msm_camera_io_w(0, vpe_dev->base + VPE_INTR_ENABLE_OFFSET);
+ /* clear all pending interrupts*/
+ msm_camera_io_w(0x1fffff, vpe_dev->base + VPE_INTR_CLEAR_OFFSET);
+ /* write sw_reset to reset the core. */
+ msm_camera_io_w(0x10, vpe_dev->base + VPE_SW_RESET_OFFSET);
+ /* then poll the reset bit, it should be self-cleared. */
+ while (1) {
+ rc = msm_camera_io_r(vpe_dev->base + VPE_SW_RESET_OFFSET) \
+ & 0x10;
+ if (rc == 0)
+ break;
+ cpu_relax();
+ }
+ /*
+ * at this point, hardware is reset. Then pogram to default
+ * values.
+ */
+ msm_camera_io_w(VPE_AXI_RD_ARB_CONFIG_VALUE,
+ vpe_dev->base + VPE_AXI_RD_ARB_CONFIG_OFFSET);
+
+ msm_camera_io_w(VPE_CGC_ENABLE_VALUE,
+ vpe_dev->base + VPE_CGC_EN_OFFSET);
+ msm_camera_io_w(1, vpe_dev->base + VPE_CMD_MODE_OFFSET);
+ msm_camera_io_w(VPE_DEFAULT_OP_MODE_VALUE,
+ vpe_dev->base + VPE_OP_MODE_OFFSET);
+ msm_camera_io_w(VPE_DEFAULT_SCALE_CONFIG,
+ vpe_dev->base + VPE_SCALE_CONFIG_OFFSET);
+ vpe_config_axi_default(vpe_dev);
+ return rc;
+}
+
+static void vpe_update_scale_coef(struct vpe_device *vpe_dev, uint32_t *p)
+{
+ uint32_t i, offset;
+ offset = *p;
+ for (i = offset; i < (VPE_SCALE_COEFF_NUM + offset); i++) {
+ VPE_DBG("Setting scale table %d\n", i);
+ msm_camera_io_w(*(++p),
+ vpe_dev->base + VPE_SCALE_COEFF_LSBn(i));
+ msm_camera_io_w(*(++p),
+ vpe_dev->base + VPE_SCALE_COEFF_MSBn(i));
+ }
+}
+
+static void vpe_input_plane_config(struct vpe_device *vpe_dev, uint32_t *p)
+{
+ msm_camera_io_w(*p, vpe_dev->base + VPE_SRC_FORMAT_OFFSET);
+ msm_camera_io_w(*(++p),
+ vpe_dev->base + VPE_SRC_UNPACK_PATTERN1_OFFSET);
+ msm_camera_io_w(*(++p), vpe_dev->base + VPE_SRC_IMAGE_SIZE_OFFSET);
+ msm_camera_io_w(*(++p), vpe_dev->base + VPE_SRC_YSTRIDE1_OFFSET);
+ msm_camera_io_w(*(++p), vpe_dev->base + VPE_SRC_SIZE_OFFSET);
+ msm_camera_io_w(*(++p), vpe_dev->base + VPE_SRC_XY_OFFSET);
+}
+
+static void vpe_output_plane_config(struct vpe_device *vpe_dev, uint32_t *p)
+{
+ msm_camera_io_w(*p, vpe_dev->base + VPE_OUT_FORMAT_OFFSET);
+ msm_camera_io_w(*(++p),
+ vpe_dev->base + VPE_OUT_PACK_PATTERN1_OFFSET);
+ msm_camera_io_w(*(++p), vpe_dev->base + VPE_OUT_YSTRIDE1_OFFSET);
+ msm_camera_io_w(*(++p), vpe_dev->base + VPE_OUT_SIZE_OFFSET);
+ msm_camera_io_w(*(++p), vpe_dev->base + VPE_OUT_XY_OFFSET);
+}
+
+static void vpe_operation_config(struct vpe_device *vpe_dev, uint32_t *p)
+{
+ msm_camera_io_w(*p, vpe_dev->base + VPE_OP_MODE_OFFSET);
+}
+
+/**
+ * msm_vpe_transaction_setup() - send setup for one frame to VPE
+ * @vpe_dev: vpe device
+ * @data: packed setup commands
+ *
+ * See msm_vpe.h for the expected format of `data'
+ */
+static void msm_vpe_transaction_setup(struct vpe_device *vpe_dev, void *data)
+{
+ int i;
+ void *iter = data;
+
+ vpe_mem_dump("vpe_transaction", data, VPE_TRANSACTION_SETUP_CONFIG_LEN);
+
+ for (i = 0; i < VPE_NUM_SCALER_TABLES; ++i) {
+ vpe_update_scale_coef(vpe_dev, (uint32_t *)iter);
+ iter += VPE_SCALER_CONFIG_LEN;
+ }
+ vpe_input_plane_config(vpe_dev, (uint32_t *)iter);
+ iter += VPE_INPUT_PLANE_CFG_LEN;
+ vpe_output_plane_config(vpe_dev, (uint32_t *)iter);
+ iter += VPE_OUTPUT_PLANE_CFG_LEN;
+ vpe_operation_config(vpe_dev, (uint32_t *)iter);
+}
+
+static int msm_vpe_send_frame_to_hardware(struct vpe_device *vpe_dev,
+ struct msm_queue_cmd *frame_qcmd)
+{
+ struct msm_vpe_frame_info_t *process_frame;
+
+ if (vpe_dev->processing_q.len < MAX_VPE_PROCESSING_FRAME) {
+ process_frame = frame_qcmd->command;
+ msm_enqueue(&vpe_dev->processing_q,
+ &frame_qcmd->list_frame);
+
+ vpe_update_scaler_params(vpe_dev, process_frame->strip_info);
+ vpe_program_buffer_addresses(
+ vpe_dev,
+ process_frame->src_phyaddr,
+ process_frame->src_phyaddr
+ + process_frame->src_chroma_plane_offset,
+ process_frame->dest_phyaddr,
+ process_frame->dest_phyaddr
+ + process_frame->dest_chroma_plane_offset);
+ vpe_start(vpe_dev);
+ do_gettimeofday(&(process_frame->in_time));
+ }
+ return 0;
+}
+
+static int msm_vpe_cfg(struct vpe_device *vpe_dev,
+ struct msm_camera_v4l2_ioctl_t *ioctl_ptr)
+{
+ int rc = 0;
+ struct msm_queue_cmd *frame_qcmd = NULL;
+ struct msm_vpe_frame_info_t *new_frame =
+ kzalloc(sizeof(struct msm_vpe_frame_info_t), GFP_KERNEL);
+ unsigned long in_phyaddr, out_phyaddr;
+ struct msm_buf_mngr_info buff_mgr_info;
+
+ if (!new_frame) {
+ pr_err("Insufficient memory. return\n");
+ return -ENOMEM;
+ }
+
+ rc = copy_from_user(new_frame, (void __user *)ioctl_ptr->ioctl_ptr,
+ sizeof(struct msm_vpe_frame_info_t));
+ if (rc) {
+ pr_err("%s:%d copy from user\n", __func__, __LINE__);
+ rc = -EINVAL;
+ goto err_free_new_frame;
+ }
+
+ in_phyaddr = msm_vpe_fetch_buffer_info(vpe_dev,
+ &new_frame->input_buffer_info,
+ ((new_frame->identity >> 16) & 0xFFFF),
+ (new_frame->identity & 0xFFFF));
+ if (!in_phyaddr) {
+ pr_err("error gettting input physical address\n");
+ rc = -EINVAL;
+ goto err_free_new_frame;
+ }
+
+ memset(&new_frame->output_buffer_info, 0,
+ sizeof(struct msm_vpe_buffer_info_t));
+ memset(&buff_mgr_info, 0, sizeof(struct msm_buf_mngr_info));
+ buff_mgr_info.session_id = ((new_frame->identity >> 16) & 0xFFFF);
+ buff_mgr_info.stream_id = (new_frame->identity & 0xFFFF);
+ rc = msm_vpe_buffer_ops(vpe_dev, VIDIOC_MSM_BUF_MNGR_GET_BUF,
+ &buff_mgr_info);
+ if (rc < 0) {
+ pr_err("error getting buffer\n");
+ rc = -EINVAL;
+ goto err_free_new_frame;
+ }
+
+ new_frame->output_buffer_info.index = buff_mgr_info.index;
+ out_phyaddr = msm_vpe_fetch_buffer_info(vpe_dev,
+ &new_frame->output_buffer_info,
+ ((new_frame->identity >> 16) & 0xFFFF),
+ (new_frame->identity & 0xFFFF));
+ if (!out_phyaddr) {
+ pr_err("error gettting output physical address\n");
+ rc = -EINVAL;
+ goto err_put_buf;
+ }
+
+ new_frame->src_phyaddr = in_phyaddr;
+ new_frame->dest_phyaddr = out_phyaddr;
+
+ frame_qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_KERNEL);
+ if (!frame_qcmd) {
+ pr_err("Insufficient memory. return\n");
+ rc = -ENOMEM;
+ goto err_put_buf;
+ }
+
+ atomic_set(&frame_qcmd->on_heap, 1);
+ frame_qcmd->command = new_frame;
+ rc = msm_vpe_send_frame_to_hardware(vpe_dev, frame_qcmd);
+ if (rc < 0) {
+ pr_err("error cannot send frame to hardware\n");
+ rc = -EINVAL;
+ goto err_free_frame_qcmd;
+ }
+
+ return rc;
+
+err_free_frame_qcmd:
+ kfree(frame_qcmd);
+err_put_buf:
+ msm_vpe_buffer_ops(vpe_dev, VIDIOC_MSM_BUF_MNGR_PUT_BUF,
+ &buff_mgr_info);
+err_free_new_frame:
+ kfree(new_frame);
+ return rc;
+}
+
+static long msm_vpe_subdev_ioctl(struct v4l2_subdev *sd,
+ unsigned int cmd, void *arg)
+{
+ struct vpe_device *vpe_dev = v4l2_get_subdevdata(sd);
+ struct msm_camera_v4l2_ioctl_t *ioctl_ptr = arg;
+ int rc = 0;
+
+ mutex_lock(&vpe_dev->mutex);
+ switch (cmd) {
+ case VIDIOC_MSM_VPE_TRANSACTION_SETUP: {
+ struct msm_vpe_transaction_setup_cfg *cfg;
+ VPE_DBG("VIDIOC_MSM_VPE_TRANSACTION_SETUP\n");
+ if (sizeof(*cfg) != ioctl_ptr->len) {
+ pr_err("%s: size mismatch cmd=%d, len=%d, expected=%d",
+ __func__, cmd, ioctl_ptr->len,
+ sizeof(*cfg));
+ rc = -EINVAL;
+ break;
+ }
+
+ cfg = kzalloc(ioctl_ptr->len, GFP_KERNEL);
+ if (!cfg) {
+ pr_err("%s:%d: malloc error\n", __func__, __LINE__);
+ mutex_unlock(&vpe_dev->mutex);
+ return -EINVAL;
+ }
+
+ rc = copy_from_user(cfg, (void __user *)ioctl_ptr->ioctl_ptr,
+ ioctl_ptr->len);
+ if (rc) {
+ pr_err("%s:%d copy from user\n", __func__, __LINE__);
+ kfree(cfg);
+ break;
+ }
+
+ msm_vpe_transaction_setup(vpe_dev, (void *)cfg);
+ kfree(cfg);
+ break;
+ }
+ case VIDIOC_MSM_VPE_CFG: {
+ VPE_DBG("VIDIOC_MSM_VPE_CFG\n");
+ rc = msm_vpe_cfg(vpe_dev, ioctl_ptr);
+ break;
+ }
+ case VIDIOC_MSM_VPE_ENQUEUE_STREAM_BUFF_INFO: {
+ struct msm_vpe_stream_buff_info_t *u_stream_buff_info;
+ struct msm_vpe_stream_buff_info_t k_stream_buff_info;
+
+ VPE_DBG("VIDIOC_MSM_VPE_ENQUEUE_STREAM_BUFF_INFO\n");
+
+ if (sizeof(struct msm_vpe_stream_buff_info_t) !=
+ ioctl_ptr->len) {
+ pr_err("%s:%d: invalid length\n", __func__, __LINE__);
+ mutex_unlock(&vpe_dev->mutex);
+ return -EINVAL;
+ }
+
+ u_stream_buff_info = kzalloc(ioctl_ptr->len, GFP_KERNEL);
+ if (!u_stream_buff_info) {
+ pr_err("%s:%d: malloc error\n", __func__, __LINE__);
+ mutex_unlock(&vpe_dev->mutex);
+ return -EINVAL;
+ }
+
+ rc = (copy_from_user(u_stream_buff_info,
+ (void __user *)ioctl_ptr->ioctl_ptr,
+ ioctl_ptr->len) ? -EFAULT : 0);
+ if (rc) {
+ pr_err("%s:%d copy from user\n", __func__, __LINE__);
+ kfree(u_stream_buff_info);
+ mutex_unlock(&vpe_dev->mutex);
+ return -EINVAL;
+ }
+
+ k_stream_buff_info.num_buffs = u_stream_buff_info->num_buffs;
+ k_stream_buff_info.identity = u_stream_buff_info->identity;
+ k_stream_buff_info.buffer_info =
+ kzalloc(k_stream_buff_info.num_buffs *
+ sizeof(struct msm_vpe_buffer_info_t), GFP_KERNEL);
+ if (!k_stream_buff_info.buffer_info) {
+ pr_err("%s:%d: malloc error\n", __func__, __LINE__);
+ kfree(u_stream_buff_info);
+ mutex_unlock(&vpe_dev->mutex);
+ return -EINVAL;
+ }
+
+ rc = (copy_from_user(k_stream_buff_info.buffer_info,
+ (void __user *)u_stream_buff_info->buffer_info,
+ k_stream_buff_info.num_buffs *
+ sizeof(struct msm_vpe_buffer_info_t)) ?
+ -EFAULT : 0);
+ if (rc) {
+ pr_err("%s:%d copy from user\n", __func__, __LINE__);
+ kfree(k_stream_buff_info.buffer_info);
+ kfree(u_stream_buff_info);
+ mutex_unlock(&vpe_dev->mutex);
+ return -EINVAL;
+ }
+
+ rc = msm_vpe_add_buff_queue_entry(vpe_dev,
+ ((k_stream_buff_info.identity >> 16) & 0xFFFF),
+ (k_stream_buff_info.identity & 0xFFFF));
+ if (!rc)
+ rc = msm_vpe_enqueue_buff_info_list(vpe_dev,
+ &k_stream_buff_info);
+
+ kfree(k_stream_buff_info.buffer_info);
+ kfree(u_stream_buff_info);
+ break;
+ }
+ case VIDIOC_MSM_VPE_DEQUEUE_STREAM_BUFF_INFO: {
+ uint32_t identity;
+ struct msm_vpe_buff_queue_info_t *buff_queue_info;
+
+ VPE_DBG("VIDIOC_MSM_VPE_DEQUEUE_STREAM_BUFF_INFO\n");
+
+ rc = (copy_from_user(&identity,
+ (void __user *)ioctl_ptr->ioctl_ptr,
+ ioctl_ptr->len) ? -EFAULT : 0);
+ if (rc) {
+ pr_err("%s:%d copy from user\n", __func__, __LINE__);
+ mutex_unlock(&vpe_dev->mutex);
+ return -EINVAL;
+ }
+
+ buff_queue_info = msm_vpe_get_buff_queue_entry(vpe_dev,
+ ((identity >> 16) & 0xFFFF), (identity & 0xFFFF));
+ if (buff_queue_info == NULL) {
+ pr_err("error finding buffer queue entry for identity:%d\n",
+ identity);
+ mutex_unlock(&vpe_dev->mutex);
+ return -EINVAL;
+ }
+
+ msm_vpe_dequeue_buff_info_list(vpe_dev, buff_queue_info);
+ rc = msm_vpe_free_buff_queue_entry(vpe_dev,
+ buff_queue_info->session_id,
+ buff_queue_info->stream_id);
+ break;
+ }
+ case VIDIOC_MSM_VPE_GET_EVENTPAYLOAD: {
+ struct msm_device_queue *queue = &vpe_dev->eventData_q;
+ struct msm_queue_cmd *event_qcmd;
+ struct msm_vpe_frame_info_t *process_frame;
+ VPE_DBG("VIDIOC_MSM_VPE_GET_EVENTPAYLOAD\n");
+ event_qcmd = msm_dequeue(queue, list_eventdata);
+ process_frame = event_qcmd->command;
+ VPE_DBG("fid %d\n", process_frame->frame_id);
+ if (copy_to_user((void __user *)ioctl_ptr->ioctl_ptr,
+ process_frame,
+ sizeof(struct msm_vpe_frame_info_t))) {
+ mutex_unlock(&vpe_dev->mutex);
+ return -EINVAL;
+ }
+
+ kfree(process_frame);
+ kfree(event_qcmd);
+ break;
+ }
+ }
+ mutex_unlock(&vpe_dev->mutex);
+ return rc;
+}
+
+static int msm_vpe_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
+ struct v4l2_event_subscription *sub)
+{
+ return v4l2_event_subscribe(fh, sub, MAX_VPE_V4l2_EVENTS);
+}
+
+static int msm_vpe_unsubscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
+ struct v4l2_event_subscription *sub)
+{
+ return v4l2_event_unsubscribe(fh, sub);
+}
+
+static struct v4l2_subdev_core_ops msm_vpe_subdev_core_ops = {
+ .ioctl = msm_vpe_subdev_ioctl,
+ .subscribe_event = msm_vpe_subscribe_event,
+ .unsubscribe_event = msm_vpe_unsubscribe_event,
+};
+
+static const struct v4l2_subdev_ops msm_vpe_subdev_ops = {
+ .core = &msm_vpe_subdev_core_ops,
+};
+
+static struct v4l2_file_operations msm_vpe_v4l2_subdev_fops;
+
+static long msm_vpe_subdev_do_ioctl(
+ struct file *file, unsigned int cmd, void *arg)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
+ struct v4l2_fh *vfh = file->private_data;
+
+ switch (cmd) {
+ case VIDIOC_DQEVENT:
+ if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS))
+ return -ENOIOCTLCMD;
+
+ return v4l2_event_dequeue(vfh, arg, file->f_flags & O_NONBLOCK);
+
+ case VIDIOC_SUBSCRIBE_EVENT:
+ return v4l2_subdev_call(sd, core, subscribe_event, vfh, arg);
+
+ case VIDIOC_UNSUBSCRIBE_EVENT:
+ return v4l2_subdev_call(sd, core, unsubscribe_event, vfh, arg);
+ case VIDIOC_MSM_VPE_GET_INST_INFO: {
+ uint32_t i;
+ struct vpe_device *vpe_dev = v4l2_get_subdevdata(sd);
+ struct msm_camera_v4l2_ioctl_t *ioctl_ptr = arg;
+ struct msm_vpe_frame_info_t inst_info;
+ for (i = 0; i < MAX_ACTIVE_VPE_INSTANCE; i++) {
+ if (vpe_dev->vpe_subscribe_list[i].vfh == vfh) {
+ inst_info.inst_id = i;
+ break;
+ }
+ }
+ if (copy_to_user(
+ (void __user *)ioctl_ptr->ioctl_ptr, &inst_info,
+ sizeof(struct msm_vpe_frame_info_t))) {
+ return -EINVAL;
+ }
+ }
+ default:
+ return v4l2_subdev_call(sd, core, ioctl, cmd, arg);
+ }
+
+ return 0;
+}
+
+static long msm_vpe_subdev_fops_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ return video_usercopy(file, cmd, arg, msm_vpe_subdev_do_ioctl);
+}
+
+static int vpe_register_domain(void)
+{
+ struct msm_iova_partition vpe_iommu_partition = {
+ /* TODO: verify that these are correct? */
+ .start = SZ_128K,
+ .size = SZ_2G - SZ_128K,
+ };
+ struct msm_iova_layout vpe_iommu_layout = {
+ .partitions = &vpe_iommu_partition,
+ .npartitions = 1,
+ .client_name = "camera_vpe",
+ .domain_flags = 0,
+ };
+
+ return msm_register_domain(&vpe_iommu_layout);
+}
+
+static int __devinit vpe_probe(struct platform_device *pdev)
+{
+ struct vpe_device *vpe_dev;
+ int rc = 0;
+
+ vpe_dev = kzalloc(sizeof(struct vpe_device), GFP_KERNEL);
+ if (!vpe_dev) {
+ pr_err("not enough memory\n");
+ return -ENOMEM;
+ }
+
+ vpe_dev->vpe_clk = kzalloc(sizeof(struct clk *) *
+ ARRAY_SIZE(vpe_clk_info), GFP_KERNEL);
+ if (!vpe_dev->vpe_clk) {
+ pr_err("not enough memory\n");
+ rc = -ENOMEM;
+ goto err_free_vpe_dev;
+ }
+
+ v4l2_subdev_init(&vpe_dev->msm_sd.sd, &msm_vpe_subdev_ops);
+ vpe_dev->msm_sd.sd.internal_ops = &msm_vpe_internal_ops;
+ snprintf(vpe_dev->msm_sd.sd.name, ARRAY_SIZE(vpe_dev->msm_sd.sd.name),
+ "vpe");
+ vpe_dev->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ vpe_dev->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_EVENTS;
+ v4l2_set_subdevdata(&vpe_dev->msm_sd.sd, vpe_dev);
+ platform_set_drvdata(pdev, &vpe_dev->msm_sd.sd);
+ mutex_init(&vpe_dev->mutex);
+ spin_lock_init(&vpe_dev->tasklet_lock);
+
+ vpe_dev->pdev = pdev;
+
+ vpe_dev->mem = platform_get_resource_byname(pdev,
+ IORESOURCE_MEM, "vpe");
+ if (!vpe_dev->mem) {
+ pr_err("no mem resource?\n");
+ rc = -ENODEV;
+ goto err_free_vpe_clk;
+ }
+
+ vpe_dev->irq = platform_get_resource_byname(pdev,
+ IORESOURCE_IRQ, "vpe");
+ if (!vpe_dev->irq) {
+ pr_err("%s: no irq resource?\n", __func__);
+ rc = -ENODEV;
+ goto err_release_mem;
+ }
+
+ vpe_dev->domain_num = vpe_register_domain();
+ if (vpe_dev->domain_num < 0) {
+ pr_err("%s: could not register domain\n", __func__);
+ rc = -ENODEV;
+ goto err_release_mem;
+ }
+
+ vpe_dev->domain =
+ msm_get_iommu_domain(vpe_dev->domain_num);
+ if (!vpe_dev->domain) {
+ pr_err("%s: cannot find domain\n", __func__);
+ rc = -ENODEV;
+ goto err_release_mem;
+ }
+
+ vpe_dev->iommu_ctx_src = msm_iommu_get_ctx("vpe_src");
+ vpe_dev->iommu_ctx_dst = msm_iommu_get_ctx("vpe_dst");
+ if (!vpe_dev->iommu_ctx_src || !vpe_dev->iommu_ctx_dst) {
+ pr_err("%s: cannot get iommu_ctx\n", __func__);
+ rc = -ENODEV;
+ goto err_release_mem;
+ }
+
+ media_entity_init(&vpe_dev->msm_sd.sd.entity, 0, NULL, 0);
+ vpe_dev->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
+ vpe_dev->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_VPE;
+ vpe_dev->msm_sd.sd.entity.name = pdev->name;
+ msm_sd_register(&vpe_dev->msm_sd);
+ msm_vpe_v4l2_subdev_fops.owner = v4l2_subdev_fops.owner;
+ msm_vpe_v4l2_subdev_fops.open = v4l2_subdev_fops.open;
+ msm_vpe_v4l2_subdev_fops.unlocked_ioctl = msm_vpe_subdev_fops_ioctl;
+ msm_vpe_v4l2_subdev_fops.release = v4l2_subdev_fops.release;
+ msm_vpe_v4l2_subdev_fops.poll = v4l2_subdev_fops.poll;
+
+ vpe_dev->msm_sd.sd.devnode->fops = &msm_vpe_v4l2_subdev_fops;
+ vpe_dev->msm_sd.sd.entity.revision = vpe_dev->msm_sd.sd.devnode->num;
+ vpe_dev->state = VPE_STATE_BOOT;
+ rc = vpe_init_hardware(vpe_dev);
+ if (rc < 0) {
+ pr_err("%s: Couldn't init vpe hardware\n", __func__);
+ rc = -ENODEV;
+ goto err_unregister_sd;
+ }
+ vpe_reset(vpe_dev);
+ vpe_release_hardware(vpe_dev);
+ vpe_dev->state = VPE_STATE_OFF;
+
+ rc = iommu_attach_device(vpe_dev->domain, vpe_dev->iommu_ctx_src);
+ if (rc < 0) {
+ pr_err("Couldn't attach to vpe_src context bank\n");
+ rc = -ENODEV;
+ goto err_unregister_sd;
+ }
+ rc = iommu_attach_device(vpe_dev->domain, vpe_dev->iommu_ctx_dst);
+ if (rc < 0) {
+ pr_err("Couldn't attach to vpe_dst context bank\n");
+ rc = -ENODEV;
+ goto err_detach_src;
+ }
+
+ vpe_dev->state = VPE_STATE_OFF;
+
+ msm_queue_init(&vpe_dev->eventData_q, "vpe-eventdata");
+ msm_queue_init(&vpe_dev->processing_q, "vpe-frame");
+ INIT_LIST_HEAD(&vpe_dev->tasklet_q);
+ tasklet_init(&vpe_dev->vpe_tasklet, msm_vpe_do_tasklet,
+ (unsigned long)vpe_dev);
+ vpe_dev->vpe_open_cnt = 0;
+
+ return rc;
+
+err_detach_src:
+ iommu_detach_device(vpe_dev->domain, vpe_dev->iommu_ctx_src);
+err_unregister_sd:
+ msm_sd_unregister(&vpe_dev->msm_sd);
+err_release_mem:
+ release_mem_region(vpe_dev->mem->start, resource_size(vpe_dev->mem));
+err_free_vpe_clk:
+ kfree(vpe_dev->vpe_clk);
+err_free_vpe_dev:
+ kfree(vpe_dev);
+ return rc;
+}
+
+static int vpe_device_remove(struct platform_device *dev)
+{
+ struct v4l2_subdev *sd = platform_get_drvdata(dev);
+ struct vpe_device *vpe_dev;
+ if (!sd) {
+ pr_err("%s: Subdevice is NULL\n", __func__);
+ return 0;
+ }
+
+ vpe_dev = (struct vpe_device *)v4l2_get_subdevdata(sd);
+ if (!vpe_dev) {
+ pr_err("%s: vpe device is NULL\n", __func__);
+ return 0;
+ }
+
+ iommu_detach_device(vpe_dev->domain, vpe_dev->iommu_ctx_dst);
+ iommu_detach_device(vpe_dev->domain, vpe_dev->iommu_ctx_src);
+ msm_sd_unregister(&vpe_dev->msm_sd);
+ release_mem_region(vpe_dev->mem->start, resource_size(vpe_dev->mem));
+ mutex_destroy(&vpe_dev->mutex);
+ kfree(vpe_dev);
+ return 0;
+}
+
+static struct platform_driver vpe_driver = {
+ .probe = vpe_probe,
+ .remove = __devexit_p(vpe_device_remove),
+ .driver = {
+ .name = MSM_VPE_DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init msm_vpe_init_module(void)
+{
+ return platform_driver_register(&vpe_driver);
+}
+
+static void __exit msm_vpe_exit_module(void)
+{
+ platform_driver_unregister(&vpe_driver);
+}
+
+module_init(msm_vpe_init_module);
+module_exit(msm_vpe_exit_module);
+MODULE_DESCRIPTION("MSM VPE driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/camera_v2/pproc/vpe/msm_vpe.h b/drivers/media/platform/msm/camera_v2/pproc/vpe/msm_vpe.h
new file mode 100644
index 0000000..c02432e
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/pproc/vpe/msm_vpe.h
@@ -0,0 +1,255 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MSM_VPE_H__
+#define __MSM_VPE_H__
+
+#include <linux/interrupt.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-subdev.h>
+#include "msm_sd.h"
+
+/*********** start of register offset *********************/
+#define VPE_INTR_ENABLE_OFFSET 0x0020
+#define VPE_INTR_STATUS_OFFSET 0x0024
+#define VPE_INTR_CLEAR_OFFSET 0x0028
+#define VPE_DL0_START_OFFSET 0x0030
+#define VPE_HW_VERSION_OFFSET 0x0070
+#define VPE_SW_RESET_OFFSET 0x0074
+#define VPE_AXI_RD_ARB_CONFIG_OFFSET 0x0078
+#define VPE_SEL_CLK_OR_HCLK_TEST_BUS_OFFSET 0x007C
+#define VPE_CGC_EN_OFFSET 0x0100
+#define VPE_CMD_STATUS_OFFSET 0x10008
+#define VPE_PROFILE_EN_OFFSET 0x10010
+#define VPE_PROFILE_COUNT_OFFSET 0x10014
+#define VPE_CMD_MODE_OFFSET 0x10060
+#define VPE_SRC_SIZE_OFFSET 0x10108
+#define VPE_SRCP0_ADDR_OFFSET 0x1010C
+#define VPE_SRCP1_ADDR_OFFSET 0x10110
+#define VPE_SRC_YSTRIDE1_OFFSET 0x1011C
+#define VPE_SRC_FORMAT_OFFSET 0x10124
+#define VPE_SRC_UNPACK_PATTERN1_OFFSET 0x10128
+#define VPE_OP_MODE_OFFSET 0x10138
+#define VPE_SCALE_PHASEX_INIT_OFFSET 0x1013C
+#define VPE_SCALE_PHASEY_INIT_OFFSET 0x10140
+#define VPE_SCALE_PHASEX_STEP_OFFSET 0x10144
+#define VPE_SCALE_PHASEY_STEP_OFFSET 0x10148
+#define VPE_OUT_FORMAT_OFFSET 0x10150
+#define VPE_OUT_PACK_PATTERN1_OFFSET 0x10154
+#define VPE_OUT_SIZE_OFFSET 0x10164
+#define VPE_OUTP0_ADDR_OFFSET 0x10168
+#define VPE_OUTP1_ADDR_OFFSET 0x1016C
+#define VPE_OUT_YSTRIDE1_OFFSET 0x10178
+#define VPE_OUT_XY_OFFSET 0x1019C
+#define VPE_SRC_XY_OFFSET 0x10200
+#define VPE_SRC_IMAGE_SIZE_OFFSET 0x10208
+#define VPE_SCALE_CONFIG_OFFSET 0x10230
+#define VPE_DEINT_STATUS_OFFSET 0x30000
+#define VPE_DEINT_DECISION_OFFSET 0x30004
+#define VPE_DEINT_COEFF0_OFFSET 0x30010
+#define VPE_SCALE_STATUS_OFFSET 0x50000
+#define VPE_SCALE_SVI_PARAM_OFFSET 0x50010
+#define VPE_SCALE_SHARPEN_CFG_OFFSET 0x50020
+#define VPE_SCALE_COEFF_LSP_0_OFFSET 0x50400
+#define VPE_SCALE_COEFF_MSP_0_OFFSET 0x50404
+
+#define VPE_AXI_ARB_1_OFFSET 0x00408
+#define VPE_AXI_ARB_2_OFFSET 0x0040C
+
+#define VPE_SCALE_COEFF_LSBn(n) (0x50400 + 8 * (n))
+#define VPE_SCALE_COEFF_MSBn(n) (0x50404 + 8 * (n))
+#define VPE_SCALE_COEFF_NUM 32
+
+/*********** end of register offset ********************/
+
+
+#define VPE_HARDWARE_VERSION 0x00080308
+#define VPE_SW_RESET_VALUE 0x00000010 /* bit 4 for PPP*/
+#define VPE_AXI_RD_ARB_CONFIG_VALUE 0x124924
+#define VPE_CMD_MODE_VALUE 0x1
+#define VPE_DEFAULT_OP_MODE_VALUE 0x40FC0004
+#define VPE_CGC_ENABLE_VALUE 0xffff
+#define VPE_DEFAULT_SCALE_CONFIG 0x3c
+
+#define VPE_NORMAL_MODE_CLOCK_RATE 150000000
+#define VPE_TURBO_MODE_CLOCK_RATE 200000000
+#define VPE_SUBDEV_MAX_EVENTS 30
+
+/**************************************************/
+/*********** End of command id ********************/
+/**************************************************/
+
+#define SCALER_PHASE_BITS 29
+#define HAL_MDP_PHASE_STEP_2P50 0x50000000
+#define HAL_MDP_PHASE_STEP_1P66 0x35555555
+#define HAL_MDP_PHASE_STEP_1P25 0x28000000
+
+
+#define MAX_ACTIVE_VPE_INSTANCE 8
+#define MAX_VPE_PROCESSING_FRAME 2
+#define MAX_VPE_V4l2_EVENTS 30
+
+#define MSM_VPE_TASKLETQ_SIZE 16
+
+/**
+ * The format of the msm_vpe_transaction_setup_cfg is as follows:
+ *
+ * - vpe_update_scale_coef (65*4 uint32_t's)
+ * - Each table is 65 uint32_t's long
+ * - 1st uint32_t in each table indicates offset
+ * - Following 64 uint32_t's are the data
+ *
+ * - vpe_input_plane_config (6 uint32_t's)
+ * - VPE_SRC_FORMAT_OFFSET
+ * - VPE_SRC_UNPACK_PATTERN1_OFFSET
+ * - VPE_SRC_IMAGE_SIZE_OFFSET
+ * - VPE_SRC_YSTRIDE1_OFFSET
+ * - VPE_SRC_SIZE_OFFSET
+ * - VPE_SRC_XY_OFFSET
+ *
+ * - vpe_output_plane_config (5 uint32_t's)
+ * - VPE_OUT_FORMAT_OFFSET
+ * - VPE_OUT_PACK_PATTERN1_OFFSET
+ * - VPE_OUT_YSTRIDE1_OFFSET
+ * - VPE_OUT_SIZE_OFFSET
+ * - VPE_OUT_XY_OFFSET
+ *
+ * - vpe_operation_config (1 uint32_t)
+ * - VPE_OP_MODE_OFFSET
+ *
+ */
+
+#define VPE_SCALER_CONFIG_LEN 260
+#define VPE_INPUT_PLANE_CFG_LEN 24
+#define VPE_OUTPUT_PLANE_CFG_LEN 20
+#define VPE_OPERATION_MODE_CFG_LEN 4
+#define VPE_NUM_SCALER_TABLES 4
+
+#define VPE_TRANSACTION_SETUP_CONFIG_LEN ( \
+ (VPE_SCALER_CONFIG_LEN * VPE_NUM_SCALER_TABLES) \
+ + VPE_INPUT_PLANE_CFG_LEN \
+ + VPE_OUTPUT_PLANE_CFG_LEN \
+ + VPE_OPERATION_MODE_CFG_LEN)
+/* VPE_TRANSACTION_SETUP_CONFIG_LEN = 1088 */
+
+struct msm_vpe_transaction_setup_cfg {
+ uint8_t scaler_cfg[VPE_TRANSACTION_SETUP_CONFIG_LEN];
+};
+
+struct vpe_subscribe_info {
+ struct v4l2_fh *vfh;
+ uint32_t active;
+};
+
+enum vpe_state {
+ VPE_STATE_BOOT,
+ VPE_STATE_IDLE,
+ VPE_STATE_ACTIVE,
+ VPE_STATE_OFF,
+};
+
+struct msm_queue_cmd {
+ struct list_head list_config;
+ struct list_head list_control;
+ struct list_head list_frame;
+ struct list_head list_pict;
+ struct list_head list_vpe_frame;
+ struct list_head list_eventdata;
+ void *command;
+ atomic_t on_heap;
+ struct timespec ts;
+ uint32_t error_code;
+ uint32_t trans_code;
+};
+
+struct msm_device_queue {
+ struct list_head list;
+ spinlock_t lock;
+ wait_queue_head_t wait;
+ int max;
+ int len;
+ const char *name;
+};
+
+struct msm_vpe_tasklet_queue_cmd {
+ struct list_head list;
+ uint32_t irq_status;
+ uint8_t cmd_used;
+};
+
+struct msm_vpe_buffer_map_info_t {
+ unsigned long len;
+ unsigned long phy_addr;
+ struct ion_handle *ion_handle;
+ struct msm_vpe_buffer_info_t buff_info;
+};
+
+struct msm_vpe_buffer_map_list_t {
+ struct msm_vpe_buffer_map_info_t map_info;
+ struct list_head entry;
+};
+
+struct msm_vpe_buff_queue_info_t {
+ uint32_t used;
+ uint16_t session_id;
+ uint16_t stream_id;
+ struct list_head vb2_buff_head;
+ struct list_head native_buff_head;
+};
+
+struct vpe_device {
+ struct platform_device *pdev;
+ struct msm_sd_subdev msm_sd;
+ struct v4l2_subdev subdev;
+ struct resource *mem;
+ struct resource *irq;
+ void __iomem *base;
+ struct clk **vpe_clk;
+ struct regulator *fs_vpe;
+ struct mutex mutex;
+ enum vpe_state state;
+
+ int domain_num;
+ struct iommu_domain *domain;
+ struct device *iommu_ctx_src;
+ struct device *iommu_ctx_dst;
+ struct ion_client *client;
+ struct kref refcount;
+
+ /* Reusing proven tasklet from msm isp */
+ atomic_t irq_cnt;
+ uint8_t taskletq_idx;
+ spinlock_t tasklet_lock;
+ struct list_head tasklet_q;
+ struct tasklet_struct vpe_tasklet;
+ struct msm_vpe_tasklet_queue_cmd
+ tasklet_queue_cmd[MSM_VPE_TASKLETQ_SIZE];
+
+ struct vpe_subscribe_info vpe_subscribe_list[MAX_ACTIVE_VPE_INSTANCE];
+ uint32_t vpe_open_cnt;
+
+ struct msm_device_queue eventData_q; /* V4L2 Event Payload Queue */
+
+ /*
+ * Processing Queue: store frame info for frames sent to
+ * microcontroller
+ */
+ struct msm_device_queue processing_q;
+
+ struct msm_vpe_buff_queue_info_t *buff_queue;
+ uint32_t num_buffq;
+ struct v4l2_subdev *buf_mgr_subdev;
+};
+
+#endif /* __MSM_VPE_H__ */
diff --git a/drivers/media/platform/msm/camera_v2/sensor/imx135.c b/drivers/media/platform/msm/camera_v2/sensor/imx135.c
index c9476ee..9b02b17 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/imx135.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/imx135.c
@@ -36,6 +36,12 @@
.delay = 0,
},
{
+ .seq_type = SENSOR_VREG,
+ .seq_val = CAM_VAF,
+ .config_val = 0,
+ .delay = 0,
+ },
+ {
.seq_type = SENSOR_GPIO,
.seq_val = SENSOR_GPIO_RESET,
.config_val = GPIO_OUT_LOW,
@@ -48,6 +54,18 @@
.delay = 30,
},
{
+ .seq_type = SENSOR_GPIO,
+ .seq_val = SENSOR_GPIO_STANDBY,
+ .config_val = GPIO_OUT_LOW,
+ .delay = 1,
+ },
+ {
+ .seq_type = SENSOR_GPIO,
+ .seq_val = SENSOR_GPIO_STANDBY,
+ .config_val = GPIO_OUT_HIGH,
+ .delay = 30,
+ },
+ {
.seq_type = SENSOR_CLK,
.seq_val = SENSOR_CAM_MCLK,
.config_val = 0,
diff --git a/drivers/media/platform/msm/vidc/hfi_packetization.c b/drivers/media/platform/msm/vidc/hfi_packetization.c
index 82a4f3c..42d4f95 100644
--- a/drivers/media/platform/msm/vidc/hfi_packetization.c
+++ b/drivers/media/platform/msm/vidc/hfi_packetization.c
@@ -45,6 +45,22 @@
[ilog2(HAL_H264_CABAC_MODEL_2)] = HFI_H264_CABAC_MODEL_2,
};
+static int color_format[] = {
+ [ilog2(HAL_COLOR_FORMAT_MONOCHROME)] = HFI_COLOR_FORMAT_MONOCHROME,
+ [ilog2(HAL_COLOR_FORMAT_NV12)] = HFI_COLOR_FORMAT_NV12,
+ [ilog2(HAL_COLOR_FORMAT_NV21)] = HFI_COLOR_FORMAT_NV21,
+ [ilog2(HAL_COLOR_FORMAT_NV12_4x4TILE)] = HFI_COLOR_FORMAT_NV12_4x4TILE,
+ [ilog2(HAL_COLOR_FORMAT_NV21_4x4TILE)] = HFI_COLOR_FORMAT_NV21_4x4TILE,
+ [ilog2(HAL_COLOR_FORMAT_YUYV)] = HFI_COLOR_FORMAT_YUYV,
+ [ilog2(HAL_COLOR_FORMAT_YVYU)] = HFI_COLOR_FORMAT_YVYU,
+ [ilog2(HAL_COLOR_FORMAT_UYVY)] = HFI_COLOR_FORMAT_UYVY,
+ [ilog2(HAL_COLOR_FORMAT_VYUY)] = HFI_COLOR_FORMAT_VYUY,
+ [ilog2(HAL_COLOR_FORMAT_RGB565)] = HFI_COLOR_FORMAT_RGB565,
+ [ilog2(HAL_COLOR_FORMAT_BGR565)] = HFI_COLOR_FORMAT_BGR565,
+ [ilog2(HAL_COLOR_FORMAT_RGB888)] = HFI_COLOR_FORMAT_RGB888,
+ [ilog2(HAL_COLOR_FORMAT_BGR888)] = HFI_COLOR_FORMAT_BGR888,
+};
+
static inline int hal_to_hfi_type(int property, int hal_type)
{
if (hal_type && (roundup_pow_of_two(hal_type) != hal_type)) {
@@ -66,6 +82,9 @@
case HAL_PARAM_VENC_H264_ENTROPY_CABAC_MODEL:
return (hal_type >= ARRAY_SIZE(cabac_model)) ?
-ENOTSUPP : cabac_model[hal_type];
+ case HAL_PARAM_UNCOMPRESSED_FORMAT_SELECT:
+ return (hal_type >= ARRAY_SIZE(color_format)) ?
+ -ENOTSUPP : color_format[hal_type];
default:
return -ENOTSUPP;
}
@@ -632,11 +651,13 @@
hfi->buffer_type = buffer_type;
else
return -EINVAL;
- hfi->format = prop->format;
+ hfi->format = hal_to_hfi_type(
+ HAL_PARAM_UNCOMPRESSED_FORMAT_SELECT,
+ prop->format);
pkt->size += sizeof(u32) +
sizeof(struct hfi_uncompressed_format_select);
break;
- }
+ }
case HAL_PARAM_UNCOMPRESSED_PLANE_ACTUAL_CONSTRAINTS_INFO:
break;
case HAL_PARAM_UNCOMPRESSED_PLANE_ACTUAL_INFO:
diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c
index 511a478..1885379 100644
--- a/drivers/media/platform/msm/vidc/msm_vdec.c
+++ b/drivers/media/platform/msm/vidc/msm_vdec.c
@@ -1498,6 +1498,6 @@
kfree(curr->cluster);
kfree(curr);
}
-
+ v4l2_ctrl_handler_free(&inst->ctrl_handler);
return 0;
}
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index b6e77dc..20cb08d 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -687,7 +687,7 @@
static u32 get_frame_size_nv21(int plane, u32 height, u32 width)
{
- return height * width * 2;
+ return VENUS_BUFFER_SIZE(COLOR_FMT_NV21, width, height);
}
static u32 get_frame_size_compressed(int plane, u32 height, u32 width)
@@ -2035,7 +2035,6 @@
int msm_venc_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
{
struct msm_vidc_format *fmt = NULL;
- struct hal_frame_size frame_sz;
int rc = 0;
int i;
struct hfi_device *hdev;
@@ -2063,6 +2062,9 @@
goto exit;
}
} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ struct hal_uncompressed_format_select hal_fmt = {0};
+ struct hal_frame_size frame_sz;
+
inst->prop.width = f->fmt.pix_mp.width;
inst->prop.height = f->fmt.pix_mp.height;
rc = msm_vidc_check_session_supported(inst);
@@ -2101,6 +2103,29 @@
rc = -EINVAL;
goto exit;
}
+
+ switch (fmt->fourcc) {
+ case V4L2_PIX_FMT_NV12:
+ hal_fmt.format = HAL_COLOR_FORMAT_NV12;
+ break;
+ case V4L2_PIX_FMT_NV21:
+ hal_fmt.format = HAL_COLOR_FORMAT_NV21;
+ break;
+ default:
+ /* we really shouldn't be here */
+ rc = -ENOTSUPP;
+ goto exit;
+ }
+
+ hal_fmt.buffer_type = HAL_BUFFER_INPUT;
+ rc = call_hfi_op(hdev, session_set_property, (void *)
+ inst->session, HAL_PARAM_UNCOMPRESSED_FORMAT_SELECT,
+ &hal_fmt);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to set input color format\n");
+ goto exit;
+ }
}
if (fmt) {
@@ -2516,6 +2541,6 @@
kfree(curr->cluster);
kfree(curr);
}
-
+ v4l2_ctrl_handler_free(&inst->ctrl_handler);
return 0;
}
diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c
index 0fbfd72..1c43f1e 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -565,6 +565,7 @@
struct msm_vidc_core *core;
struct list_head *ptr, *next;
int rc = 0;
+ int i;
if (!inst)
return -EINVAL;
@@ -592,6 +593,9 @@
if (rc)
dprintk(VIDC_ERR,
"Failed to move video instance to uninit state\n");
+ for (i = 0; i < MAX_PORT_NUM; i++)
+ vb2_queue_release(&inst->bufq[i].vb2_bufq);
+
pr_info(VIDC_DBG_TAG "Closed video instance: %p\n", VIDC_INFO, inst);
kfree(inst);
return 0;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index cf051b6..91fcdb6 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -2383,38 +2383,27 @@
struct msm_vidc_core_capability *capability;
int rc = 0;
struct v4l2_event dqevent;
+ struct hfi_device *hdev;
- if (!inst) {
+ if (!inst || !inst->core || !inst->core->device) {
dprintk(VIDC_WARN, "%s: Invalid parameter\n", __func__);
return -EINVAL;
}
capability = &inst->capability;
+ hdev = inst->core->device;
if (inst->capability.capability_set) {
- if (msm_vp8_low_tier &&
- inst->core->hfi_type == VIDC_HFI_VENUS &&
- inst->fmts[OUTPUT_PORT]->fourcc == V4L2_PIX_FMT_VP8) {
- capability->width.max = DEFAULT_WIDTH;
- capability->height.max = DEFAULT_HEIGHT;
- }
- if (inst->prop.width < capability->width.min ||
- inst->prop.width > capability->width.max ||
- (inst->prop.width % capability->width.step_size != 0)) {
- dprintk(VIDC_ERR,
- "Unsupported width = %d range min(%u) - max(%u) step_size(%u)",
- inst->prop.width, capability->width.min,
- capability->width.max, capability->width.step_size);
- rc = -ENOTSUPP;
- }
+ rc = call_hfi_op(hdev, capability_check,
+ inst->fmts[OUTPUT_PORT]->fourcc,
+ inst->prop.width, &capability->width.max,
+ &capability->height.max);
- if (inst->prop.height < capability->height.min ||
- inst->prop.height > capability->height.max ||
- (inst->prop.height %
- capability->height.step_size != 0)) {
+ if (!rc && (inst->prop.height * inst->prop.width >
+ capability->width.max * capability->height.max)) {
dprintk(VIDC_ERR,
- "Unsupported height = %d range min(%u) - max(%u) step_size(%u)",
- inst->prop.height, capability->height.min,
- capability->height.max, capability->height.step_size);
+ "Unsupported WxH = (%u)x(%u), Max supported is - (%u)x(%u)",
+ inst->prop.width, inst->prop.height,
+ capability->width.max, capability->height.max);
rc = -ENOTSUPP;
}
}
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index 964167f..74733c2 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -2849,6 +2849,28 @@
return 0;
}
+int venus_hfi_capability_check(u32 fourcc, u32 width,
+ u32 *max_width, u32 *max_height)
+{
+ int rc = 0;
+ if (!max_width || !max_height) {
+ dprintk(VIDC_ERR, "%s - invalid parameter\n", __func__);
+ return -EINVAL;
+ }
+
+ if (msm_vp8_low_tier && fourcc == V4L2_PIX_FMT_VP8) {
+ *max_width = DEFAULT_WIDTH;
+ *max_height = DEFAULT_HEIGHT;
+ }
+ if (width > *max_width) {
+ dprintk(VIDC_ERR,
+ "Unsupported width = %u supported max width = %u",
+ width, *max_width);
+ rc = -ENOTSUPP;
+ }
+ return rc;
+}
+
static void *venus_hfi_add_device(u32 device_id,
struct msm_vidc_platform_resources *res,
hfi_cmd_response_callback callback)
@@ -2988,6 +3010,7 @@
hdev->unload_fw = venus_hfi_unload_fw;
hdev->get_fw_info = venus_hfi_get_fw_info;
hdev->get_stride_scanline = venus_hfi_get_stride_scanline;
+ hdev->capability_check = venus_hfi_capability_check;
}
int venus_hfi_initialize(struct hfi_device *hdev, u32 device_id,
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
index bf1c70b..01395e5 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
@@ -391,20 +391,20 @@
};
enum hal_uncompressed_format {
- HAL_COLOR_FORMAT_MONOCHROME,
- HAL_COLOR_FORMAT_NV12,
- HAL_COLOR_FORMAT_NV21,
- HAL_COLOR_FORMAT_NV12_4x4TILE,
- HAL_COLOR_FORMAT_NV21_4x4TILE,
- HAL_COLOR_FORMAT_YUYV,
- HAL_COLOR_FORMAT_YVYU,
- HAL_COLOR_FORMAT_UYVY,
- HAL_COLOR_FORMAT_VYUY,
- HAL_COLOR_FORMAT_RGB565,
- HAL_COLOR_FORMAT_BGR565,
- HAL_COLOR_FORMAT_RGB888,
- HAL_COLOR_FORMAT_BGR888,
- HAL_UNUSED_COLOR = 0x10000000,
+ HAL_COLOR_FORMAT_MONOCHROME = 0x00000001,
+ HAL_COLOR_FORMAT_NV12 = 0x00000002,
+ HAL_COLOR_FORMAT_NV21 = 0x00000004,
+ HAL_COLOR_FORMAT_NV12_4x4TILE = 0x00000008,
+ HAL_COLOR_FORMAT_NV21_4x4TILE = 0x00000010,
+ HAL_COLOR_FORMAT_YUYV = 0x00000020,
+ HAL_COLOR_FORMAT_YVYU = 0x00000040,
+ HAL_COLOR_FORMAT_UYVY = 0x00000080,
+ HAL_COLOR_FORMAT_VYUY = 0x00000100,
+ HAL_COLOR_FORMAT_RGB565 = 0x00000200,
+ HAL_COLOR_FORMAT_BGR565 = 0x00000400,
+ HAL_COLOR_FORMAT_RGB888 = 0x00000800,
+ HAL_COLOR_FORMAT_BGR888 = 0x00001000,
+ HAL_UNUSED_COLOR = 0x10000000,
};
enum hal_ssr_trigger_type {
@@ -1075,6 +1075,8 @@
int (*get_fw_info)(void *dev, enum fw_info info);
int (*get_stride_scanline)(int color_fmt, int width,
int height, int *stride, int *scanlines);
+ int (*capability_check)(u32 fourcc, u32 width,
+ u32 *max_width, u32 *max_height);
};
typedef void (*hfi_cmd_response_callback) (enum command_response cmd,
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index fa28d6a..f139b21 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -540,6 +540,8 @@
unsigned long flags;
struct qseecom_client_listener_data_irsp send_data_rsp;
struct qseecom_registered_listener_list *ptr_svc = NULL;
+ sigset_t new_sigset;
+ sigset_t old_sigset;
while (resp->result == QSEOS_RESULT_INCOMPLETE) {
lstnr = resp->data;
@@ -564,17 +566,24 @@
}
pr_debug("waking up rcv_req_wq and "
"waiting for send_resp_wq\n");
- if (wait_event_freezable(qseecom.send_resp_wq,
- __qseecom_listener_has_sent_rsp(data))) {
- pr_warning("Interrupted: exiting send_cmd loop\n");
- ret = -ERESTARTSYS;
- }
- if ((data->abort) || (ret == -ERESTARTSYS)) {
+ /* initialize the new signal mask with all signals*/
+ sigfillset(&new_sigset);
+ /* block all signals */
+ sigprocmask(SIG_SETMASK, &new_sigset, &old_sigset);
+
+ do {
+ if (!wait_event_freezable(qseecom.send_resp_wq,
+ __qseecom_listener_has_sent_rsp(data)))
+ break;
+ } while (1);
+
+ /* restore signal mask */
+ sigprocmask(SIG_SETMASK, &old_sigset, NULL);
+ if (data->abort) {
pr_err("Abort clnt %d waiting on lstnr svc %d, ret %d",
data->client.app_id, lstnr, ret);
- if (data->abort)
- rc = -ENODEV;
+ rc = -ENODEV;
send_data_rsp.status = QSEOS_RESULT_FAILURE;
} else {
send_data_rsp.status = QSEOS_RESULT_SUCCESS;
diff --git a/drivers/mtd/devices/msm_qpic_nand.c b/drivers/mtd/devices/msm_qpic_nand.c
index 0b04bbf..5fda343 100644
--- a/drivers/mtd/devices/msm_qpic_nand.c
+++ b/drivers/mtd/devices/msm_qpic_nand.c
@@ -30,7 +30,7 @@
#include <linux/of.h>
#include <linux/ctype.h>
#include <mach/sps.h>
-#include <mach/msm_smsm.h>
+#include <mach/msm_smem.h>
#define PAGE_SIZE_2K 2048
#define PAGE_SIZE_4K 4096
#define WRITE 1
diff --git a/drivers/net/ethernet/msm/ecm_ipa.c b/drivers/net/ethernet/msm/ecm_ipa.c
index 6fbf971..be9058b 100644
--- a/drivers/net/ethernet/msm/ecm_ipa.c
+++ b/drivers/net/ethernet/msm/ecm_ipa.c
@@ -46,7 +46,8 @@
#define ECM_IPA_LOG_ENTRY() pr_debug("begin\n")
#define ECM_IPA_LOG_EXIT() pr_debug("end\n")
-/** enum ecm_ipa_state - specify the current driver internal state
+/**
+ * enum ecm_ipa_state - specify the current driver internal state.
*
* The driver internal state changes due to its API usage.
* The driver saves its internal state to guard from caller illegal
@@ -65,7 +66,8 @@
ECM_IPA_UP,
};
-#define ECM_IPA_MODE(dev) pr_debug("Driver mode changed - %d", dev->mode);
+#define ECM_IPA_MODE(ecm_ipa_ctx) \
+ pr_debug("Driver mode changed - %d", ecm_ipa_ctx->mode);
/**
* struct ecm_ipa_dev - main driver context parameters
@@ -102,32 +104,26 @@
enum ecm_ipa_mode mode;
};
-/**
- * struct ecm_ipa_ctx - saved pointer for the ecm_ipa network device
- * which allow ecm_ipa to be a singleton
- */
-static struct ecm_ipa_dev *ecm_ipa_ctx;
-
static int ecm_ipa_open(struct net_device *net);
static void ecm_ipa_packet_receive_notify(void *priv,
enum ipa_dp_evt_type evt, unsigned long data);
static void ecm_ipa_tx_complete_notify(void *priv,
enum ipa_dp_evt_type evt, unsigned long data);
static int ecm_ipa_stop(struct net_device *net);
-static int ecm_ipa_rules_cfg(struct ecm_ipa_dev *dev,
+static int ecm_ipa_rules_cfg(struct ecm_ipa_dev *ecm_ipa_ctx,
const void *dst_mac, const void *src_mac);
-static void ecm_ipa_rules_destroy(struct ecm_ipa_dev *dev);
+static void ecm_ipa_rules_destroy(struct ecm_ipa_dev *ecm_ipa_ctx);
static int ecm_ipa_register_properties(void);
static void ecm_ipa_deregister_properties(void);
static void ecm_ipa_rm_notify(void *user_data, enum ipa_rm_event event,
unsigned long data);
-static int ecm_ipa_create_rm_resource(struct ecm_ipa_dev *dev);
-static void ecm_ipa_destory_rm_resource(struct ecm_ipa_dev *dev);
+static int ecm_ipa_create_rm_resource(struct ecm_ipa_dev *ecm_ipa_ctx);
+static void ecm_ipa_destory_rm_resource(struct ecm_ipa_dev *ecm_ipa_ctx);
static bool rx_filter(struct sk_buff *skb);
static bool tx_filter(struct sk_buff *skb);
-static bool rm_enabled(struct ecm_ipa_dev *dev);
-static int resource_request(struct ecm_ipa_dev *dev);
-static void resource_release(struct ecm_ipa_dev *dev);
+static bool rm_enabled(struct ecm_ipa_dev *ecm_ipa_ctx);
+static int resource_request(struct ecm_ipa_dev *ecm_ipa_ctx);
+static void resource_release(struct ecm_ipa_dev *ecm_ipa_ctx);
static netdev_tx_t ecm_ipa_start_xmit(struct sk_buff *skb,
struct net_device *net);
static int ecm_ipa_debugfs_atomic_open(struct inode *inode, struct file *file);
@@ -140,8 +136,8 @@
char __user *ubuf, size_t count, loff_t *ppos);
static ssize_t ecm_ipa_debugfs_atomic_read(struct file *file,
char __user *ubuf, size_t count, loff_t *ppos);
-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_init(struct ecm_ipa_dev *ecm_ipa_ctx);
+static void ecm_ipa_debugfs_destroy(struct ecm_ipa_dev *ecm_ipa_ctx);
static int ecm_ipa_ep_registers_cfg(u32 usb_to_ipa_hdl, u32 ipa_to_usb_hdl);
static int ecm_ipa_ep_registers_dma_cfg(u32 usb_to_ipa_hdl);
static int ecm_ipa_set_device_ethernet_addr(u8 *dev_ethaddr,
@@ -171,7 +167,7 @@
/**
* ecm_ipa_init() - create network device and initializes internal
- * data structures
+ * data structures
* @params: in/out parameters required for ecm_ipa initialization
*
* Shall be called prior to pipe connection.
@@ -195,7 +191,7 @@
{
int result = 0;
struct net_device *net;
- struct ecm_ipa_dev *dev;
+ struct ecm_ipa_dev *ecm_ipa_ctx;
ECM_IPA_LOG_ENTRY();
pr_debug("%s initializing\n", DRIVER_NAME);
@@ -213,26 +209,25 @@
}
pr_debug("network device was successfully allocated\n");
- dev = netdev_priv(net);
- memset(dev, 0, sizeof(*dev));
- dev->net = net;
- ecm_ipa_ctx = dev;
- dev->tx_enable = true;
- dev->rx_enable = true;
- dev->rm_enable = true;
- dev->outstanding_high = DEFAULT_OUTSTANDING_HIGH;
- dev->outstanding_low = DEFAULT_OUTSTANDING_LOW;
- atomic_set(&dev->outstanding_pkts, 0);
+ ecm_ipa_ctx = netdev_priv(net);
+ memset(ecm_ipa_ctx, 0, sizeof(*ecm_ipa_ctx));
+ ecm_ipa_ctx->net = net;
+ ecm_ipa_ctx->tx_enable = true;
+ ecm_ipa_ctx->rx_enable = true;
+ ecm_ipa_ctx->rm_enable = true;
+ ecm_ipa_ctx->outstanding_high = DEFAULT_OUTSTANDING_HIGH;
+ ecm_ipa_ctx->outstanding_low = DEFAULT_OUTSTANDING_LOW;
+ atomic_set(&ecm_ipa_ctx->outstanding_pkts, 0);
snprintf(net->name, sizeof(net->name), "%s%%d", "ecm");
net->netdev_ops = &ecm_ipa_netdev_ops;
pr_debug("internal data structures were intialized and defaults set\n");
- result = ecm_ipa_debugfs_init(dev);
+ result = ecm_ipa_debugfs_init(ecm_ipa_ctx);
if (result)
goto fail_debugfs;
pr_debug("debugfs entries were created\n");
- result = ecm_ipa_create_rm_resource(dev);
+ result = ecm_ipa_create_rm_resource(ecm_ipa_ctx);
if (result) {
ECM_IPA_ERROR("fail on RM create\n");
goto fail_create_rm;
@@ -247,7 +242,7 @@
}
pr_debug("Device Ethernet address set %pM\n", net->dev_addr);
- result = ecm_ipa_rules_cfg(dev, params->host_ethaddr,
+ result = ecm_ipa_rules_cfg(ecm_ipa_ctx, params->host_ethaddr,
params->device_ethaddr);
if (result) {
ECM_IPA_ERROR("fail on ipa rules set\n");
@@ -274,9 +269,9 @@
params->ecm_ipa_rx_dp_notify = ecm_ipa_packet_receive_notify;
params->ecm_ipa_tx_dp_notify = ecm_ipa_tx_complete_notify;
- params->private = (void *)dev;
- dev->mode = ECM_IPA_INITIALIZED;
- ECM_IPA_MODE(dev);
+ params->private = (void *)ecm_ipa_ctx;
+ ecm_ipa_ctx->mode = ECM_IPA_INITIALIZED;
+ ECM_IPA_MODE(ecm_ipa_ctx);
ECM_IPA_LOG_EXIT();
@@ -285,12 +280,12 @@
fail_register_netdev:
ecm_ipa_deregister_properties();
fail_register_tx:
- ecm_ipa_rules_destroy(dev);
+ ecm_ipa_rules_destroy(ecm_ipa_ctx);
fail_set_device_ethernet:
fail_rules_cfg:
- ecm_ipa_destory_rm_resource(dev);
+ ecm_ipa_destory_rm_resource(ecm_ipa_ctx);
fail_create_rm:
- ecm_ipa_debugfs_destroy(dev);
+ ecm_ipa_debugfs_destroy(ecm_ipa_ctx);
fail_debugfs:
free_netdev(net);
fail_alloc_etherdev:
@@ -298,18 +293,34 @@
}
EXPORT_SYMBOL(ecm_ipa_init);
-
+/**
+ * ecm_ipa_connect() - notify ecm_ipa for IPA<->USB pipes connection
+ * @usb_to_ipa_hdl: handle of IPA driver client for USB->IPA
+ * @ipa_to_usb_hdl: handle of IPA driver client for IPA->USB
+ * @priv: same value that was set by ecm_ipa_init(), this
+ * parameter holds the network device pointer.
+ *
+ * Once USB driver finishes the pipe connection between IPA core
+ * and USB core this method shall be called in order to
+ * allow ecm_ipa complete the data path configurations.
+ * Detailed description:
+ * - configure the IPA end-points register
+ * - notify the Linux kernel for "carrier_on"
+ * After this function is done the driver state changes to "Connected".
+ * This API is expected to be called after ecm_ipa_init() or
+ * after a call to ecm_ipa_disconnect.
+ */
int ecm_ipa_connect(u32 usb_to_ipa_hdl, u32 ipa_to_usb_hdl,
void *priv)
{
- struct ecm_ipa_dev *dev = priv;
+ struct ecm_ipa_dev *ecm_ipa_ctx = priv;
ECM_IPA_LOG_ENTRY();
NULL_CHECK(priv);
pr_debug("usb_to_ipa_hdl = %d, ipa_to_usb_hdl = %d, priv=0x%p\n",
usb_to_ipa_hdl, ipa_to_usb_hdl, priv);
- if (!ecm_ipa_state_validate(dev->mode, ECM_IPA_CONNECTED)) {
+ if (!ecm_ipa_state_validate(ecm_ipa_ctx->mode, ECM_IPA_CONNECTED)) {
ECM_IPA_ERROR("can't call connect before driver init\n");
return -EPERM;
}
@@ -324,20 +335,20 @@
ipa_to_usb_hdl);
return -EINVAL;
}
- dev->ipa_to_usb_hdl = ipa_to_usb_hdl;
- dev->usb_to_ipa_hdl = usb_to_ipa_hdl;
+ ecm_ipa_ctx->ipa_to_usb_hdl = ipa_to_usb_hdl;
+ ecm_ipa_ctx->usb_to_ipa_hdl = usb_to_ipa_hdl;
ecm_ipa_ep_registers_cfg(usb_to_ipa_hdl, ipa_to_usb_hdl);
pr_debug("end-point configured\n");
- netif_carrier_on(dev->net);
- if (!netif_carrier_ok(dev->net)) {
+ netif_carrier_on(ecm_ipa_ctx->net);
+ if (!netif_carrier_ok(ecm_ipa_ctx->net)) {
ECM_IPA_ERROR("netif_carrier_ok error\n");
return -EBUSY;
}
pr_debug("carrier_on notified, ecm_ipa is operational\n");
- dev->mode = ECM_IPA_CONNECTED;
- ECM_IPA_MODE(dev);
+ ecm_ipa_ctx->mode = ECM_IPA_CONNECTED;
+ ECM_IPA_MODE(ecm_ipa_ctx);
ECM_IPA_LOG_EXIT();
@@ -345,15 +356,24 @@
}
EXPORT_SYMBOL(ecm_ipa_connect);
+/**
+ * ecm_ipa_open() - notify Linux network stack to start sending packets
+ * @net: the network interface supplied by the network stack
+ *
+ * Linux uses this API to notify the driver that the network interface
+ * transitions to the up state.
+ * The driver will instruct the Linux network stack to start
+ * delivering data packets.
+ */
static int ecm_ipa_open(struct net_device *net)
{
- struct ecm_ipa_dev *dev;
+ struct ecm_ipa_dev *ecm_ipa_ctx;
ECM_IPA_LOG_ENTRY();
- dev = netdev_priv(net);
+ ecm_ipa_ctx = netdev_priv(net);
- if (!ecm_ipa_state_validate(dev->mode, ECM_IPA_UP)) {
+ if (!ecm_ipa_state_validate(ecm_ipa_ctx->mode, ECM_IPA_UP)) {
ECM_IPA_ERROR("can't bring driver up before cable connect\n");
return -EPERM;
}
@@ -364,8 +384,8 @@
netif_start_queue(net);
pr_debug("queue started\n");
- dev->mode = ECM_IPA_UP;
- ECM_IPA_MODE(dev);
+ ecm_ipa_ctx->mode = ECM_IPA_UP;
+ ECM_IPA_MODE(ecm_ipa_ctx);
ECM_IPA_LOG_EXIT();
@@ -374,28 +394,37 @@
/**
* ecm_ipa_start_xmit() - send data from APPs to USB core via IPA core
- * @skb: packet received from Linux stack
+ * @skb: packet received from Linux network stack
* @net: the network device being used to send this packet
*
* Several conditions needed in order to send the packet to IPA:
- * - we are in a valid state were the queue is not stopped
+ * - Transmit queue for the network driver is currently
+ * in "send" state
+ * - The driver internal state is in "UP" state.
* - Filter Tx switch is turned off
- * - The resources required for actual Tx are all up
+ * - The IPA resource manager state for the driver producer client
+ * is "Granted" which implies that all the resources in the dependency
+ * graph are valid for data flow.
+ * - outstanding high boundary did not reach.
*
+ * In case all of the above conditions are met, the network driver will
+ * send the packet by using the IPA API for Tx.
+ * In case the outstanding packet high boundary is reached, the driver will
+ * stop the send queue until enough packet were proceeded by the IPA core.
*/
static netdev_tx_t ecm_ipa_start_xmit(struct sk_buff *skb,
struct net_device *net)
{
int ret;
netdev_tx_t status = NETDEV_TX_BUSY;
- struct ecm_ipa_dev *dev = netdev_priv(net);
+ struct ecm_ipa_dev *ecm_ipa_ctx = netdev_priv(net);
if (unlikely(netif_queue_stopped(net))) {
ECM_IPA_ERROR("interface queue is stopped\n");
goto out;
}
- if (unlikely(dev->mode != ECM_IPA_UP)) {
+ if (unlikely(ecm_ipa_ctx->mode != ECM_IPA_UP)) {
ECM_IPA_ERROR("can't send without network interface up\n");
return -NETDEV_TX_BUSY;
}
@@ -406,16 +435,17 @@
status = NETDEV_TX_OK;
goto out;
}
- ret = resource_request(dev);
+ ret = resource_request(ecm_ipa_ctx);
if (ret) {
pr_debug("Waiting to resource\n");
netif_stop_queue(net);
goto resource_busy;
}
- if (atomic_read(&dev->outstanding_pkts) >= dev->outstanding_high) {
+ if (atomic_read(&ecm_ipa_ctx->outstanding_pkts) >=
+ ecm_ipa_ctx->outstanding_high) {
pr_debug("Outstanding high boundary reached (%d)- stopping queue\n",
- dev->outstanding_high);
+ ecm_ipa_ctx->outstanding_high);
netif_stop_queue(net);
status = -NETDEV_TX_BUSY;
goto out;
@@ -427,7 +457,7 @@
goto fail_tx_packet;
}
- atomic_inc(&dev->outstanding_pkts);
+ atomic_inc(&ecm_ipa_ctx->outstanding_pkts);
net->stats.tx_packets++;
net->stats.tx_bytes += skb->len;
status = NETDEV_TX_OK;
@@ -435,7 +465,7 @@
fail_tx_packet:
out:
- resource_release(dev);
+ resource_release(ecm_ipa_ctx);
resource_busy:
return status;
}
@@ -447,14 +477,15 @@
* @evt: event type
* @data: data provided with event
*
- * IPA will pass a packet with skb->data pointing to Ethernet packet frame
+ * IPA will pass a packet to the Linux network stack with skb->data pointing
+ * to Ethernet packet frame.
*/
static void ecm_ipa_packet_receive_notify(void *priv,
enum ipa_dp_evt_type evt,
unsigned long data)
{
struct sk_buff *skb = (struct sk_buff *)data;
- struct ecm_ipa_dev *dev = priv;
+ struct ecm_ipa_dev *ecm_ipa_ctx = priv;
int result;
if (evt != IPA_RECEIVE) {
@@ -462,8 +493,8 @@
return;
}
- skb->dev = dev->net;
- skb->protocol = eth_type_trans(skb, dev->net);
+ skb->dev = ecm_ipa_ctx->net;
+ skb->protocol = eth_type_trans(skb, ecm_ipa_ctx->net);
if (rx_filter(skb)) {
pr_debug("packet got filtered out on Rx path\n");
dev_kfree_skb_any(skb);
@@ -473,19 +504,28 @@
result = netif_rx(skb);
if (result)
ECM_IPA_ERROR("fail on netif_rx\n");
- dev->net->stats.rx_packets++;
- dev->net->stats.rx_bytes += skb->len;
+ ecm_ipa_ctx->net->stats.rx_packets++;
+ ecm_ipa_ctx->net->stats.rx_bytes += skb->len;
return;
}
+/** ecm_ipa_stop() - called when network device transitions to the down
+ * state.
+ * @net: the network device being stopped.
+ *
+ * This API is used by Linux network stack to notify the network driver that
+ * its state was changed to "down"
+ * The driver will stop the "send" queue and change its internal
+ * state to "Connected".
+ */
static int ecm_ipa_stop(struct net_device *net)
{
- struct ecm_ipa_dev *dev = netdev_priv(net);
+ struct ecm_ipa_dev *ecm_ipa_ctx = netdev_priv(net);
ECM_IPA_LOG_ENTRY();
- if (!ecm_ipa_state_validate(dev->mode, ECM_IPA_CONNECTED)) {
+ if (!ecm_ipa_state_validate(ecm_ipa_ctx->mode, ECM_IPA_CONNECTED)) {
ECM_IPA_ERROR("can't do network interface down without up\n");
return -EPERM;
}
@@ -493,34 +533,44 @@
netif_stop_queue(net);
pr_debug("network device stopped\n");
- dev->mode = ECM_IPA_CONNECTED;
- ECM_IPA_MODE(dev);
+ ecm_ipa_ctx->mode = ECM_IPA_CONNECTED;
+ ECM_IPA_MODE(ecm_ipa_ctx);
ECM_IPA_LOG_EXIT();
return 0;
}
+/** ecm_ipa_disconnect() - called when the USB cable is unplugged.
+ * @priv: same value that was set by ecm_ipa_init(), this
+ * parameter holds the network device pointer.
+ *
+ * Once the USB cable is unplugged the USB driver will notify the network
+ * interface driver.
+ * The internal driver state will returned to its initialized state and
+ * Linux network stack will be informed for carrier off and the send queue
+ * will be stopped.
+ */
int ecm_ipa_disconnect(void *priv)
{
- struct ecm_ipa_dev *dev = priv;
+ struct ecm_ipa_dev *ecm_ipa_ctx = priv;
ECM_IPA_LOG_ENTRY();
- NULL_CHECK(dev);
+ NULL_CHECK(ecm_ipa_ctx);
pr_debug("priv=0x%p\n", priv);
- if (!ecm_ipa_state_validate(dev->mode, ECM_IPA_INITIALIZED)) {
+ if (!ecm_ipa_state_validate(ecm_ipa_ctx->mode, ECM_IPA_INITIALIZED)) {
ECM_IPA_ERROR("can't disconnect without connect first\n");
return -EPERM;
}
- netif_carrier_off(dev->net);
+ netif_carrier_off(ecm_ipa_ctx->net);
pr_debug("carrier_off notifcation was sent\n");
- netif_stop_queue(dev->net);
+ netif_stop_queue(ecm_ipa_ctx->net);
pr_debug("queue stopped\n");
- dev->mode = ECM_IPA_INITIALIZED;
- ECM_IPA_MODE(dev);
+ ecm_ipa_ctx->mode = ECM_IPA_INITIALIZED;
+ ECM_IPA_MODE(ecm_ipa_ctx);
ECM_IPA_LOG_EXIT();
@@ -530,33 +580,43 @@
/**
- * ecm_ipa_cleanup() - destroys all
- * ecm information
- * @priv: main driver context parameters
+ * ecm_ipa_cleanup() - unregister the network interface driver and free
+ * internal data structs.
+ * @priv: same value that was set by ecm_ipa_init(), this
+ * parameter holds the network device pointer.
*
+ * This function shall be called once the network interface is not
+ * needed anymore, e.g: when the USB composition does not support ECM.
+ * This function shall be called after the pipes were disconnected.
+ * Detailed description:
+ * - delete the driver dependency defined for IPA resource manager and
+ * destroy the producer resource.
+ * - remove the debugfs entries
+ * - deregister the network interface from Linux network stack
+ * - free all internal data structs
*/
void ecm_ipa_cleanup(void *priv)
{
- struct ecm_ipa_dev *dev = priv;
+ struct ecm_ipa_dev *ecm_ipa_ctx = priv;
ECM_IPA_LOG_ENTRY();
pr_debug("priv=0x%p\n", priv);
- if (!dev) {
- ECM_IPA_ERROR("dev NULL pointer\n");
+ if (!ecm_ipa_ctx) {
+ ECM_IPA_ERROR("ecm_ipa_ctx NULL pointer\n");
return;
}
- if (!ecm_ipa_state_validate(dev->mode, ECM_IPA_LOADED))
+ if (!ecm_ipa_state_validate(ecm_ipa_ctx->mode, ECM_IPA_LOADED))
ECM_IPA_ERROR("can't clean driver without cable disconnect\n");
- ecm_ipa_destory_rm_resource(dev);
- ecm_ipa_debugfs_destroy(dev);
+ ecm_ipa_destory_rm_resource(ecm_ipa_ctx);
+ ecm_ipa_debugfs_destroy(ecm_ipa_ctx);
- unregister_netdev(dev->net);
- free_netdev(dev->net);
+ unregister_netdev(ecm_ipa_ctx->net);
+ free_netdev(ecm_ipa_ctx->net);
pr_debug("cleanup done\n");
ecm_ipa_ctx = NULL;
@@ -567,34 +627,15 @@
EXPORT_SYMBOL(ecm_ipa_cleanup);
/**
- * @ecm_ipa_rx_dp_notify: supplied callback to be called by the IPA
- * driver upon data packets received from USB pipe into IPA core.
- * @ecm_ipa_rt_dp_notify: supplied callback to be called by the IPA
- * driver upon exception packets sent from IPA pipe into USB core.
- * @priv: should be passed later on to ecm_ipa_configure, hold the network
- * structure allocated for STD ECM interface.
- *
- * Shall be called prior to pipe connection.
- * The out parameters (the callbacks) shall be supplied to ipa_connect.
- * Detailed description:
- * - set the callbacks to be used by the caller upon ipa_connect
- * - allocate the network device
- * - set the priv argument with a reference to the network device
- *
- * Returns negative errno, or zero on success
- */
-
-
-/**
* ecm_ipa_rules_cfg() - set header insertion and register Tx/Rx properties
* Headers will be commited to HW
- * @dev: main driver context parameters
+ * @ecm_ipa_ctx: main driver context parameters
* @dst_mac: destination MAC address
* @src_mac: source MAC address
*
* Returns negative errno, or zero on success
*/
-static int ecm_ipa_rules_cfg(struct ecm_ipa_dev *dev,
+static int ecm_ipa_rules_cfg(struct ecm_ipa_dev *ecm_ipa_ctx,
const void *dst_mac, const void *src_mac)
{
struct ipa_ioc_add_hdr *hdrs;
@@ -646,8 +687,8 @@
result = ipv6_hdr->status;
goto out_free_mem;
}
- dev->eth_ipv4_hdr_hdl = ipv4_hdr->hdr_hdl;
- dev->eth_ipv6_hdr_hdl = ipv6_hdr->hdr_hdl;
+ ecm_ipa_ctx->eth_ipv4_hdr_hdl = ipv4_hdr->hdr_hdl;
+ ecm_ipa_ctx->eth_ipv6_hdr_hdl = ipv6_hdr->hdr_hdl;
ECM_IPA_LOG_EXIT();
out_free_mem:
kfree(hdrs);
@@ -655,7 +696,14 @@
return result;
}
-static void ecm_ipa_rules_destroy(struct ecm_ipa_dev *dev)
+/**
+ * ecm_ipa_rules_destroy() - remove the IPA core configuration done for
+ * the driver data path.
+ * @ecm_ipa_ctx: the driver context
+ *
+ * Revert the work done on ecm_ipa_rules_cfg.
+ */
+static void ecm_ipa_rules_destroy(struct ecm_ipa_dev *ecm_ipa_ctx)
{
struct ipa_ioc_del_hdr *del_hdr;
struct ipa_hdr_del *ipv4;
@@ -668,9 +716,9 @@
del_hdr->commit = 1;
del_hdr->num_hdls = 2;
ipv4 = &del_hdr->hdl[0];
- ipv4->hdl = dev->eth_ipv4_hdr_hdl;
+ ipv4->hdl = ecm_ipa_ctx->eth_ipv4_hdr_hdl;
ipv6 = &del_hdr->hdl[1];
- ipv6->hdl = dev->eth_ipv6_hdr_hdl;
+ ipv6->hdl = ecm_ipa_ctx->eth_ipv6_hdr_hdl;
result = ipa_del_hdr(del_hdr);
if (result || ipv4->status || ipv6->status)
ECM_IPA_ERROR("ipa_del_hdr failed");
@@ -764,25 +812,25 @@
static void ecm_ipa_rm_notify(void *user_data, enum ipa_rm_event event,
unsigned long data)
{
- struct ecm_ipa_dev *dev = user_data;
+ struct ecm_ipa_dev *ecm_ipa_ctx = user_data;
ECM_IPA_LOG_ENTRY();
if (event == IPA_RM_RESOURCE_GRANTED &&
- netif_queue_stopped(dev->net)) {
+ netif_queue_stopped(ecm_ipa_ctx->net)) {
pr_debug("Resource Granted - waking queue\n");
- netif_wake_queue(dev->net);
+ netif_wake_queue(ecm_ipa_ctx->net);
} else {
pr_debug("Resource released\n");
}
ECM_IPA_LOG_EXIT();
}
-static int ecm_ipa_create_rm_resource(struct ecm_ipa_dev *dev)
+static int ecm_ipa_create_rm_resource(struct ecm_ipa_dev *ecm_ipa_ctx)
{
struct ipa_rm_create_params create_params = {0};
int result;
ECM_IPA_LOG_ENTRY();
create_params.name = IPA_RM_RESOURCE_STD_ECM_PROD;
- create_params.reg_params.user_data = dev;
+ create_params.reg_params.user_data = ecm_ipa_ctx;
create_params.reg_params.notify_cb = ecm_ipa_rm_notify;
result = ipa_rm_create_resource(&create_params);
if (result) {
@@ -814,7 +862,7 @@
return result;
}
-static void ecm_ipa_destory_rm_resource(struct ecm_ipa_dev *dev)
+static void ecm_ipa_destory_rm_resource(struct ecm_ipa_dev *ecm_ipa_ctx)
{
int result;
@@ -832,26 +880,26 @@
static bool rx_filter(struct sk_buff *skb)
{
- struct ecm_ipa_dev *dev = netdev_priv(skb->dev);
- return !dev->rx_enable;
+ struct ecm_ipa_dev *ecm_ipa_ctx = netdev_priv(skb->dev);
+ return !ecm_ipa_ctx->rx_enable;
}
static bool tx_filter(struct sk_buff *skb)
{
- struct ecm_ipa_dev *dev = netdev_priv(skb->dev);
- return !dev->tx_enable;
+ struct ecm_ipa_dev *ecm_ipa_ctx = netdev_priv(skb->dev);
+ return !ecm_ipa_ctx->tx_enable;
}
-static bool rm_enabled(struct ecm_ipa_dev *dev)
+static bool rm_enabled(struct ecm_ipa_dev *ecm_ipa_ctx)
{
- return dev->rm_enable;
+ return ecm_ipa_ctx->rm_enable;
}
-static int resource_request(struct ecm_ipa_dev *dev)
+static int resource_request(struct ecm_ipa_dev *ecm_ipa_ctx)
{
int result = 0;
- if (!rm_enabled(dev))
+ if (!rm_enabled(ecm_ipa_ctx))
goto out;
result = ipa_rm_inactivity_timer_request_resource(
IPA_RM_RESOURCE_STD_ECM_PROD);
@@ -859,9 +907,9 @@
return result;
}
-static void resource_release(struct ecm_ipa_dev *dev)
+static void resource_release(struct ecm_ipa_dev *ecm_ipa_ctx)
{
- if (!rm_enabled(dev))
+ if (!rm_enabled(ecm_ipa_ctx))
goto out;
ipa_rm_inactivity_timer_release_resource(IPA_RM_RESOURCE_STD_ECM_PROD);
out:
@@ -883,22 +931,23 @@
unsigned long data)
{
struct sk_buff *skb = (struct sk_buff *)data;
- struct ecm_ipa_dev *dev = priv;
+ struct ecm_ipa_dev *ecm_ipa_ctx = priv;
- if (!dev) {
- ECM_IPA_ERROR("dev is NULL pointer\n");
+ if (!ecm_ipa_ctx) {
+ ECM_IPA_ERROR("ecm_ipa_ctx is NULL pointer\n");
return;
}
if (evt != IPA_WRITE_DONE) {
ECM_IPA_ERROR("unsupported event on Tx callback\n");
return;
}
- atomic_dec(&dev->outstanding_pkts);
- if (netif_queue_stopped(dev->net) &&
- atomic_read(&dev->outstanding_pkts) < (dev->outstanding_low)) {
+ atomic_dec(&ecm_ipa_ctx->outstanding_pkts);
+ if (netif_queue_stopped(ecm_ipa_ctx->net) &&
+ atomic_read(&ecm_ipa_ctx->outstanding_pkts) <
+ (ecm_ipa_ctx->outstanding_low)) {
pr_debug("Outstanding low boundary reached (%d) - waking up queue\n",
- dev->outstanding_low);
- netif_wake_queue(dev->net);
+ ecm_ipa_ctx->outstanding_low);
+ netif_wake_queue(ecm_ipa_ctx->net);
}
dev_kfree_skb_any(skb);
@@ -907,9 +956,9 @@
static int ecm_ipa_debugfs_atomic_open(struct inode *inode, struct file *file)
{
- struct ecm_ipa_dev *dev = inode->i_private;
+ struct ecm_ipa_dev *ecm_ipa_ctx = inode->i_private;
ECM_IPA_LOG_ENTRY();
- file->private_data = &(dev->outstanding_pkts);
+ file->private_data = &(ecm_ipa_ctx->outstanding_pkts);
ECM_IPA_LOG_EXIT();
return 0;
}
@@ -917,25 +966,25 @@
static ssize_t ecm_ipa_debugfs_enable_write_dma(struct file *file,
const char __user *buf, size_t count, loff_t *ppos)
{
- struct ecm_ipa_dev *dev = file->private_data;
+ struct ecm_ipa_dev *ecm_ipa_ctx = file->private_data;
int result;
ECM_IPA_LOG_ENTRY();
- file->private_data = &dev->dma_enable;
+ file->private_data = &ecm_ipa_ctx->dma_enable;
result = ecm_ipa_debugfs_enable_write(file, buf, count, ppos);
- if (dev->dma_enable)
- ecm_ipa_ep_registers_dma_cfg(dev->usb_to_ipa_hdl);
+ if (ecm_ipa_ctx->dma_enable)
+ ecm_ipa_ep_registers_dma_cfg(ecm_ipa_ctx->usb_to_ipa_hdl);
else
- ecm_ipa_ep_registers_cfg(dev->usb_to_ipa_hdl,
- dev->usb_to_ipa_hdl);
+ ecm_ipa_ep_registers_cfg(ecm_ipa_ctx->usb_to_ipa_hdl,
+ ecm_ipa_ctx->usb_to_ipa_hdl);
ECM_IPA_LOG_EXIT();
return result;
}
static int ecm_ipa_debugfs_dma_open(struct inode *inode, struct file *file)
{
- struct ecm_ipa_dev *dev = inode->i_private;
+ struct ecm_ipa_dev *ecm_ipa_ctx = inode->i_private;
ECM_IPA_LOG_ENTRY();
- file->private_data = dev;
+ file->private_data = ecm_ipa_ctx;
ECM_IPA_LOG_EXIT();
return 0;
}
@@ -997,7 +1046,7 @@
}
-static int ecm_ipa_debugfs_init(struct ecm_ipa_dev *dev)
+static int ecm_ipa_debugfs_init(struct ecm_ipa_dev *ecm_ipa_ctx)
{
const mode_t flags_read_write = S_IRUGO | S_IWUGO;
const mode_t flags_read_only = S_IRUGO;
@@ -1005,52 +1054,54 @@
ECM_IPA_LOG_ENTRY();
- if (!dev)
+ if (!ecm_ipa_ctx)
return -EINVAL;
- dev->directory = debugfs_create_dir("ecm_ipa", NULL);
- if (!dev->directory) {
+ ecm_ipa_ctx->directory = debugfs_create_dir("ecm_ipa", NULL);
+ if (!ecm_ipa_ctx->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);
+ ecm_ipa_ctx->directory, &ecm_ipa_ctx->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);
+ ecm_ipa_ctx->directory, &ecm_ipa_ctx->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);
+ ecm_ipa_ctx->directory, &ecm_ipa_ctx->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);
+ ecm_ipa_ctx->directory, &ecm_ipa_ctx->outstanding_high);
if (!file) {
ECM_IPA_ERROR("could not create outstanding_high file\n");
goto fail_file;
}
file = debugfs_create_u8("outstanding_low", flags_read_write,
- dev->directory, &dev->outstanding_low);
+ ecm_ipa_ctx->directory, &ecm_ipa_ctx->outstanding_low);
if (!file) {
ECM_IPA_ERROR("could not create outstanding_low file\n");
goto fail_file;
}
file = debugfs_create_file("dma_enable", flags_read_write,
- dev->directory, dev, &ecm_ipa_debugfs_dma_ops);
+ ecm_ipa_ctx->directory,
+ ecm_ipa_ctx, &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);
+ ecm_ipa_ctx->directory,
+ ecm_ipa_ctx, &ecm_ipa_debugfs_atomic_ops);
if (!file) {
ECM_IPA_ERROR("could not create outstanding file\n");
goto fail_file;
@@ -1060,14 +1111,14 @@
return 0;
fail_file:
- debugfs_remove_recursive(dev->directory);
+ debugfs_remove_recursive(ecm_ipa_ctx->directory);
fail_directory:
return -EFAULT;
}
-static void ecm_ipa_debugfs_destroy(struct ecm_ipa_dev *dev)
+static void ecm_ipa_debugfs_destroy(struct ecm_ipa_dev *ecm_ipa_ctx)
{
- debugfs_remove_recursive(dev->directory);
+ debugfs_remove_recursive(ecm_ipa_ctx->directory);
}
/**
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
index fe151b5..acd42ae3 100644
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -107,4 +107,10 @@
help
OpenFirmware SLIMBUS accessors
+config OF_CORESIGHT
+ def_bool y
+ depends on CORESIGHT
+ help
+ OpenFirmware CoreSight accessors
+
endmenu # OF
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
index c3a31c8..61a99f2 100644
--- a/drivers/of/Makefile
+++ b/drivers/of/Makefile
@@ -15,3 +15,4 @@
obj-$(CONFIG_OF_SPMI) += of_spmi.o
obj-$(CONFIG_OF_MTD) += of_mtd.o
obj-$(CONFIG_OF_SLIMBUS) += of_slimbus.o
+obj-$(CONFIG_OF_CORESIGHT) += of_coresight.o
diff --git a/drivers/coresight/of_coresight.c b/drivers/of/of_coresight.c
similarity index 100%
rename from drivers/coresight/of_coresight.c
rename to drivers/of/of_coresight.c
diff --git a/drivers/platform/msm/ipa/ipa_bridge.c b/drivers/platform/msm/ipa/ipa_bridge.c
index 3ff604c..919a119 100644
--- a/drivers/platform/msm/ipa/ipa_bridge.c
+++ b/drivers/platform/msm/ipa/ipa_bridge.c
@@ -12,7 +12,7 @@
#include <linux/delay.h>
#include <linux/ratelimit.h>
-#include <mach/msm_smsm.h>
+#include <mach/msm_smem.h>
#include "ipa_i.h"
/*
diff --git a/drivers/platform/msm/usb_bam.c b/drivers/platform/msm/usb_bam.c
index 64e8d7a..fc85dba 100644
--- a/drivers/platform/msm/usb_bam.c
+++ b/drivers/platform/msm/usb_bam.c
@@ -129,15 +129,40 @@
[HSIC_BAM] = hsic_cons_release_resource,
};
-static enum ipa_rm_event cur_prod_state[MAX_BAMS];
-static enum ipa_rm_event cur_cons_state[MAX_BAMS];
-static int sched_lpm;
-static int lpm_wait_handshake;
-static struct completion prod_avail[MAX_BAMS];
-static struct completion cons_avail[MAX_BAMS];
-static struct completion cons_released[MAX_BAMS];
-static struct completion prod_released[MAX_BAMS];
+struct usb_bam_ipa_handshake_info {
+ enum ipa_rm_event cur_prod_state[MAX_BAMS];
+ enum ipa_rm_event cur_cons_state[MAX_BAMS];
+ int lpm_wait_handshake;
+ int connect_complete;
+ bool lpm_wait_pipes;
+ int bus_suspend;
+ bool in_lpm;
+
+ int (*wake_cb)(void *);
+ void *wake_param;
+ void (*start)(void *, enum usb_bam_pipe_dir);
+ void (*stop)(void *, enum usb_bam_pipe_dir);
+ void *start_stop_param;
+
+ u32 src_idx;
+ u32 dst_idx;
+ bool cons_stopped;
+ bool prod_stopped;
+
+ struct completion prod_avail[MAX_BAMS];
+ struct completion cons_avail[MAX_BAMS];
+ struct completion cons_released[MAX_BAMS];
+ struct completion prod_released[MAX_BAMS];
+
+ struct mutex suspend_resume_mutex;
+ struct work_struct resume_work;
+ struct work_struct suspend_work;
+ struct work_struct finish_suspend_work;
+};
+
+static spinlock_t usb_bam_ipa_handshake_info_lock;
+static struct usb_bam_ipa_handshake_info info;
static spinlock_t usb_bam_peer_handshake_info_lock;
static struct usb_bam_peer_handshake_info peer_handshake_info;
static spinlock_t usb_bam_lock; /* Protect ctx and usb_bam_connections */
@@ -457,6 +482,7 @@
pr_err("%s: ipa_connect failed\n", __func__);
return ret;
}
+ pipe_connect->ipa_clnt_hdl = clnt_hdl;
*pipe = sps_alloc_endpoint();
if (*pipe == NULL) {
@@ -579,6 +605,31 @@
return 0;
}
+static void usb_bam_resume_core(enum usb_bam cur_bam)
+{
+ struct usb_phy *trans = usb_get_transceiver();
+
+ if (cur_bam != HSUSB_BAM)
+ return;
+ BUG_ON(trans == NULL);
+ pr_debug("%s: resume core", __func__);
+ pm_runtime_resume(trans->dev);
+}
+
+static void usb_bam_start_lpm(bool disconnect)
+{
+ struct usb_phy *trans = usb_get_transceiver();
+ BUG_ON(trans == NULL);
+ pr_debug("%s: Going to LPM\n", __func__);
+ spin_lock(&usb_bam_ipa_handshake_info_lock);
+ info.lpm_wait_handshake = false;
+ info.lpm_wait_pipes = 0;
+ if (disconnect)
+ pm_runtime_put_noidle(trans->dev);
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
+ pm_runtime_suspend(trans->dev);
+}
+
int usb_bam_connect(u8 idx, u32 *bam_pipe_idx)
{
int ret;
@@ -608,26 +659,136 @@
}
spin_lock(&usb_bam_lock);
-
/* Check if BAM requires RESET before connect and reset of first pipe */
if ((pdata->reset_on_connect[pipe_connect->bam_type] == true) &&
(ctx.pipes_enabled_per_bam[pipe_connect->bam_type] == 0))
sps_device_reset(ctx.h_bam[pipe_connect->bam_type]);
+ spin_unlock(&usb_bam_lock);
ret = connect_pipe(idx, bam_pipe_idx);
if (ret) {
pr_err("%s: pipe connection[%d] failure\n", __func__, idx);
- spin_unlock(&usb_bam_lock);
return ret;
}
pipe_connect->enabled = 1;
+ spin_lock(&usb_bam_lock);
ctx.pipes_enabled_per_bam[pipe_connect->bam_type] += 1;
-
spin_unlock(&usb_bam_lock);
+
return 0;
}
+static int ipa_suspend_pipes(void)
+{
+ struct usb_bam_pipe_connect *dst_pipe_connect, *src_pipe_connect;
+ int ret1, ret2;
+
+ dst_pipe_connect = &usb_bam_connections[info.dst_idx];
+ src_pipe_connect = &usb_bam_connections[info.src_idx];
+
+ if (dst_pipe_connect->ipa_clnt_hdl == -1 ||
+ src_pipe_connect->ipa_clnt_hdl == -1) {
+ pr_err("%s: One of handles is -1, not connected?", __func__);
+ }
+
+ ret1 = ipa_suspend(dst_pipe_connect->ipa_clnt_hdl);
+ if (ret1)
+ pr_err("%s: ipa_suspend on dst failed with %d", __func__, ret1);
+ ret2 = ipa_suspend(src_pipe_connect->ipa_clnt_hdl);
+ if (ret2)
+ pr_err("%s: ipa_suspend on src failed with %d", __func__, ret2);
+
+ return ret1 | ret2;
+}
+
+static int ipa_resume_pipes(void)
+{
+ struct usb_bam_pipe_connect *dst_pipe_connect, *src_pipe_connect;
+ int ret1, ret2;
+
+ src_pipe_connect = &usb_bam_connections[info.src_idx];
+ dst_pipe_connect = &usb_bam_connections[info.dst_idx];
+
+ if (dst_pipe_connect->ipa_clnt_hdl == -1 ||
+ src_pipe_connect->ipa_clnt_hdl == -1) {
+ pr_err("%s: One of handles is -1, not connected?", __func__);
+ }
+
+ ret1 = ipa_resume(dst_pipe_connect->ipa_clnt_hdl);
+ if (ret1)
+ pr_err("%s: ipa_resume on dst failed with %d", __func__, ret1);
+ ret2 = ipa_resume(src_pipe_connect->ipa_clnt_hdl);
+ if (ret2)
+ pr_err("%s: ipa_resume on src failed with %d", __func__, ret2);
+
+ return ret1 | ret2;
+}
+
+static void usb_bam_finish_suspend(void)
+{
+ int ret;
+ u32 cons_empty;
+ struct sps_pipe *cons_pipe = ctx.usb_bam_sps.sps_pipes[info.dst_idx];
+ struct usb_bam_pipe_connect *pipe_connect = &
+ usb_bam_connections[info.dst_idx];
+ enum usb_bam cur_bam = pipe_connect->bam_type;
+
+ if (cur_bam != HSUSB_BAM) {
+ pr_err("%s: Wrong type of BAM=%s\n", __func__,
+ bam_enable_strings[cur_bam]);
+ return;
+ }
+
+ mutex_lock(&info.suspend_resume_mutex);
+
+ /* If resume was called don't finish this work */
+ spin_lock(&usb_bam_ipa_handshake_info_lock);
+ if (!info.bus_suspend) {
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
+ pr_err("%s: Bus suspend in progress\n", __func__);
+ goto no_lpm;
+ }
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
+
+ ret = sps_is_pipe_empty(cons_pipe, &cons_empty);
+ if (ret) {
+ pr_err("%s: sps_is_pipe_empty failed with %d\n", __func__, ret);
+ goto no_lpm;
+ }
+
+ /* Stop CONS transfers and go to lpm if no more data in the pipe */
+ if (cons_empty) {
+ if (info.stop && !info.cons_stopped)
+ info.stop(info.start_stop_param,
+ PEER_PERIPHERAL_TO_USB);
+ pr_err("%s: Starting LPM on Bus Suspend\n", __func__);
+ info.cons_stopped = 1;
+ if (info.cur_cons_state[cur_bam] == IPA_RM_RESOURCE_RELEASED) {
+ ipa_rm_notify_completion(IPA_RM_RESOURCE_RELEASED,
+ ipa_rm_resource_cons[cur_bam]);
+ }
+ ipa_suspend_pipes();
+ mutex_unlock(&info.suspend_resume_mutex);
+ usb_bam_start_lpm(0);
+ return;
+ }
+
+no_lpm:
+
+ /* Finish the handshake. Resume Sequence will start automatically
+ by the data in the pipes */
+ if (info.cur_cons_state[cur_bam] == IPA_RM_RESOURCE_RELEASED)
+ ipa_rm_notify_completion(IPA_RM_RESOURCE_RELEASED,
+ ipa_rm_resource_cons[cur_bam]);
+ mutex_unlock(&info.suspend_resume_mutex);
+}
+
+void usb_bam_finish_suspend_(struct work_struct *w)
+{
+ usb_bam_finish_suspend();
+}
+
static void usb_prod_notify_cb(void *user_data, enum ipa_rm_event event,
unsigned long data)
{
@@ -637,14 +798,14 @@
case IPA_RM_RESOURCE_GRANTED:
pr_debug("%s: %s_PROD resource granted\n",
__func__, bam_enable_strings[*cur_bam]);
- cur_prod_state[*cur_bam] = IPA_RM_RESOURCE_GRANTED;
- complete_all(&prod_avail[*cur_bam]);
+ info.cur_prod_state[*cur_bam] = IPA_RM_RESOURCE_GRANTED;
+ complete_all(&info.prod_avail[*cur_bam]);
break;
case IPA_RM_RESOURCE_RELEASED:
pr_debug("%s: %s_PROD resource released\n",
__func__, bam_enable_strings[*cur_bam]);
- cur_prod_state[*cur_bam] = IPA_RM_RESOURCE_RELEASED;
- complete_all(&prod_released[*cur_bam]);
+ info.cur_prod_state[*cur_bam] = IPA_RM_RESOURCE_RELEASED;
+ complete_all(&info.prod_released[*cur_bam]);
break;
default:
break;
@@ -657,12 +818,33 @@
pr_debug("%s: Request %s_CONS resource\n",
__func__, bam_enable_strings[cur_bam]);
- cur_cons_state[cur_bam] = IPA_RM_RESOURCE_GRANTED;
- complete_all(&cons_avail[cur_bam]);
+ spin_lock(&usb_bam_ipa_handshake_info_lock);
+ info.cur_cons_state[cur_bam] = IPA_RM_RESOURCE_GRANTED;
+ complete_all(&info.cons_avail[cur_bam]);
- if (ctx.pipes_enabled_per_bam[cur_bam])
+ spin_lock(&usb_bam_lock);
+ if (ctx.pipes_enabled_per_bam[cur_bam] && info.connect_complete &&
+ !info.bus_suspend && !info.prod_stopped) {
+ spin_unlock(&usb_bam_lock);
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
+ pr_debug("%s: ACK on cons_request", __func__);
return 0;
+ }
+ /* A2 wakeup from LPM */
+ if (cur_bam == HSUSB_BAM && ctx.pipes_enabled_per_bam[cur_bam] &&
+ info.connect_complete && info.bus_suspend) {
+ info.bus_suspend = 0;
+ spin_unlock(&usb_bam_lock);
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
+ if (info.wake_cb)
+ info.wake_cb(info.wake_param);
+ } else {
+ spin_unlock(&usb_bam_lock);
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
+ }
+
+ pr_debug("%s: EINPROGRESS on cons_request", __func__);
return -EINPROGRESS;
}
@@ -681,12 +863,23 @@
pr_debug("%s: Release %s_CONS resource\n",
__func__, bam_enable_strings[cur_bam]);
- cur_cons_state[cur_bam] = IPA_RM_RESOURCE_RELEASED;
- complete_all(&cons_released[cur_bam]);
+ info.cur_cons_state[cur_bam] = IPA_RM_RESOURCE_RELEASED;
+ complete_all(&info.cons_released[cur_bam]);
- if (!ctx.pipes_enabled_per_bam[cur_bam])
+ spin_lock(&usb_bam_lock);
+ if (!ctx.pipes_enabled_per_bam[cur_bam]) {
+ spin_unlock(&usb_bam_lock);
+ pr_debug("%s: ACK on cons_release", __func__);
return 0;
+ }
+ spin_unlock(&usb_bam_lock);
+ spin_lock(&usb_bam_ipa_handshake_info_lock);
+ if (cur_bam == HSUSB_BAM && info.bus_suspend)
+ queue_work(ctx.usb_bam_wq, &info.finish_suspend_work);
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
+
+ pr_debug("%s: EINPROGRESS cons_release", __func__);
return -EINPROGRESS;
}
@@ -747,24 +940,24 @@
pr_debug("%s Request %s_PROD_RES\n", __func__,
bam_enable_strings[cur_bam]);
- if (cur_cons_state[cur_bam] == IPA_RM_RESOURCE_GRANTED)
+ if (info.cur_cons_state[cur_bam] == IPA_RM_RESOURCE_GRANTED)
pr_debug("%s: CONS already granted for some reason\n",
__func__);
- if (cur_prod_state[cur_bam] == IPA_RM_RESOURCE_GRANTED)
+ if (info.cur_prod_state[cur_bam] == IPA_RM_RESOURCE_GRANTED)
pr_debug("%s: PROD already granted for some reason\n",
__func__);
- init_completion(&prod_avail[cur_bam]);
- init_completion(&cons_avail[cur_bam]);
+ init_completion(&info.prod_avail[cur_bam]);
+ init_completion(&info.cons_avail[cur_bam]);
ret = ipa_rm_request_resource(ipa_rm_resource_prod[cur_bam]);
if (!ret) {
- cur_prod_state[cur_bam] = IPA_RM_RESOURCE_GRANTED;
- complete_all(&prod_avail[cur_bam]);
+ info.cur_prod_state[cur_bam] = IPA_RM_RESOURCE_GRANTED;
+ complete_all(&info.prod_avail[cur_bam]);
pr_debug("%s: PROD_GRANTED without wait\n", __func__);
} else if (ret == -EINPROGRESS) {
pr_debug("%s: Waiting for PROD_GRANTED\n", __func__);
- if (!wait_for_completion_timeout(&prod_avail[cur_bam],
+ if (!wait_for_completion_timeout(&info.prod_avail[cur_bam],
USB_BAM_TIMEOUT))
pr_err("%s: Timeout wainting for PROD_GRANTED\n",
__func__);
@@ -772,6 +965,261 @@
pr_err("%s: ipa_rm_request_resource ret =%d\n", __func__, ret);
}
+void wait_for_cons_granted(enum usb_bam cur_bam)
+{
+ pr_debug("%s: Waiting for CONS\n", __func__);
+ if (info.cur_cons_state[cur_bam] != IPA_RM_RESOURCE_GRANTED) {
+ if (!wait_for_completion_timeout(&info.cons_avail[cur_bam],
+ USB_BAM_TIMEOUT*6))
+ pr_err("%s: Timeout wainting for CONS_REQUEST\n",
+ __func__);
+ pr_err("%s: Finished waiting for CONS\n", __func__);
+ }
+
+ spin_lock(&usb_bam_ipa_handshake_info_lock);
+ info.connect_complete = 1;
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
+ pr_debug("%s: CONS is granted\n", __func__);
+
+ if (info.cur_cons_state[HSUSB_BAM] == IPA_RM_RESOURCE_GRANTED) {
+ pr_debug("%s: Notify CONS_GRANTED\n", __func__);
+ ipa_rm_notify_completion(IPA_RM_RESOURCE_GRANTED,
+ ipa_rm_resource_cons[HSUSB_BAM]);
+ }
+}
+
+void usb_bam_wait_for_cons_granted(
+ struct usb_bam_connect_ipa_params *ipa_params)
+{
+ struct usb_bam_pipe_connect *pipe_connect;
+ enum usb_bam cur_bam;
+ u8 src_idx;
+
+ src_idx = ipa_params->src_idx;
+ pipe_connect = &usb_bam_connections[src_idx];
+ cur_bam = pipe_connect->bam_type;
+
+ wait_for_cons_granted(cur_bam);
+}
+
+static void wait_for_prod_release(enum usb_bam cur_bam)
+{
+ int ret;
+
+ if (info.cur_cons_state[cur_bam] == IPA_RM_RESOURCE_RELEASED)
+ pr_debug("%s consumer already released\n", __func__);
+ if (info.cur_prod_state[cur_bam] == IPA_RM_RESOURCE_RELEASED)
+ pr_debug("%s producer already released\n", __func__);
+
+ init_completion(&info.prod_released[cur_bam]);
+ init_completion(&info.cons_released[cur_bam]);
+ pr_debug("%s: Releasing %s_PROD\n", __func__,
+ bam_enable_strings[cur_bam]);
+ ret = ipa_rm_release_resource(ipa_rm_resource_prod[cur_bam]);
+ if (!ret) {
+ pr_debug("%s: Released without waiting\n", __func__);
+ info.cur_prod_state[cur_bam] = IPA_RM_RESOURCE_RELEASED;
+ complete_all(&info.prod_released[cur_bam]);
+ } else if (ret == -EINPROGRESS) {
+ pr_debug("%s: Waiting for PROD_RELEASED\n", __func__);
+ if (!wait_for_completion_timeout(&info.prod_released[cur_bam],
+ USB_BAM_TIMEOUT))
+ pr_err("%s: Timeout waiting for PROD_RELEASED\n",
+ __func__);
+ } else
+ pr_err("%s: ipa_rm_request_resource ret =%d", __func__, ret);
+}
+
+static int check_pipes_empty(u8 src_idx, u8 dst_idx)
+{
+ struct sps_pipe *prod_pipe, *cons_pipe;
+ u32 prod_empty, cons_empty;
+
+ /* If we have any remaints in the pipes we don't go to sleep */
+ prod_pipe = ctx.usb_bam_sps.sps_pipes[src_idx];
+ cons_pipe = ctx.usb_bam_sps.sps_pipes[dst_idx];
+ if (sps_is_pipe_empty(prod_pipe, &prod_empty) ||
+ sps_is_pipe_empty(cons_pipe, &cons_empty)) {
+ pr_err("%s: sps_is_pipe_empty failed with\n", __func__);
+ return 0;
+ }
+ if (!prod_empty || !cons_empty) {
+ pr_err("%s: pipes not empty prod=%d cond=%d", __func__,
+ prod_empty, cons_empty);
+ return 0;
+ }
+
+ return 1;
+}
+
+void usb_bam_suspend(struct usb_bam_connect_ipa_params *ipa_params)
+{
+ struct usb_bam_pipe_connect *pipe_connect;
+ enum usb_bam cur_bam;
+ u8 src_idx, dst_idx;
+
+ if (!ipa_params) {
+ pr_err("%s: Invalid ipa params\n", __func__);
+ return;
+ }
+
+ src_idx = ipa_params->src_idx;
+ dst_idx = ipa_params->dst_idx;
+
+ if (src_idx >= ctx.max_connections || dst_idx >= ctx.max_connections) {
+ pr_err("%s: Invalid connection index src=%d dst=%d\n",
+ __func__, src_idx, dst_idx);
+ }
+
+ pipe_connect = &usb_bam_connections[src_idx];
+ cur_bam = pipe_connect->bam_type;
+ if (cur_bam != HSUSB_BAM)
+ return;
+
+ info.src_idx = src_idx;
+ info.dst_idx = dst_idx;
+
+ pr_err("%s: Starting suspend sequence(BAM=%s)\n", __func__,
+ bam_enable_strings[cur_bam]);
+
+ spin_lock(&usb_bam_ipa_handshake_info_lock);
+ info.bus_suspend = 1;
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
+
+ /* Stop PROD transfers */
+ if (info.stop) {
+ spin_lock(&usb_bam_ipa_handshake_info_lock);
+ info.stop(info.start_stop_param, USB_TO_PEER_PERIPHERAL);
+ info.prod_stopped = true;
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
+ }
+
+ /* Don't go to LPM if data in the pipes */
+ if (!check_pipes_empty(src_idx, dst_idx)) {
+ pr_err("%s: pipes not empty, won't start suspend", __func__);
+ return;
+ }
+
+ queue_work(ctx.usb_bam_wq, &info.suspend_work);
+}
+
+static void usb_bam_start_suspend(struct work_struct *w)
+{
+ pr_debug("%s: enter", __func__);
+ mutex_lock(&info.suspend_resume_mutex);
+
+ spin_lock(&usb_bam_ipa_handshake_info_lock);
+ if (!info.bus_suspend) {
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
+ pr_err("%s: Resume started, not suspending", __func__);
+ return;
+ }
+
+ /* Stop PROD transfers in case they were started */
+ if (info.stop && !info.prod_stopped) {
+ info.stop(info.start_stop_param, USB_TO_PEER_PERIPHERAL);
+ info.prod_stopped = true;
+ }
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
+
+ /* Don't start LPM seq if data in the pipes */
+ if (!check_pipes_empty(info.src_idx, info.dst_idx)) {
+ mutex_unlock(&info.suspend_resume_mutex);
+ return;
+ }
+
+ spin_lock(&usb_bam_ipa_handshake_info_lock);
+ info.lpm_wait_handshake = true;
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
+
+ wait_for_prod_release(HSUSB_BAM);
+
+ mutex_unlock(&info.suspend_resume_mutex);
+ if (info.cur_cons_state[HSUSB_BAM] == IPA_RM_RESOURCE_RELEASED)
+ usb_bam_finish_suspend();
+ else
+ pr_debug("Consumer not released yet\n");
+}
+
+static void usb_bam_finish_resume(struct work_struct *w)
+{
+ struct usb_phy *trans = usb_get_transceiver();
+
+ BUG_ON(trans == NULL);
+ pr_debug("%s: enter", __func__);
+ mutex_lock(&info.suspend_resume_mutex);
+ /* Suspend happened in the meantime */
+ spin_lock(&usb_bam_ipa_handshake_info_lock);
+ if (info.bus_suspend) {
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
+ pr_err("%s: Bus suspended, not resuming", __func__);
+ mutex_unlock(&info.suspend_resume_mutex);
+ return;
+ }
+ info.lpm_wait_handshake = true;
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
+
+ wait_for_prod_granted(HSUSB_BAM);
+ wait_for_cons_granted(HSUSB_BAM);
+ if (info.cons_stopped) {
+ ipa_resume_pipes();
+ if (info.start) {
+ pr_debug("%s: Enqueue CONS transfer", __func__);
+ info.start(info.start_stop_param,
+ PEER_PERIPHERAL_TO_USB);
+ info.cons_stopped = 0;
+ }
+ }
+
+ if (info.start) {
+ spin_lock(&usb_bam_ipa_handshake_info_lock);
+ info.start(info.start_stop_param, USB_TO_PEER_PERIPHERAL);
+ info.prod_stopped = false;
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
+ }
+ if (info.cur_cons_state[HSUSB_BAM] == IPA_RM_RESOURCE_GRANTED) {
+ pr_debug("%s: Notify CONS_GRANTED\n", __func__);
+ ipa_rm_notify_completion(IPA_RM_RESOURCE_GRANTED,
+ ipa_rm_resource_cons[HSUSB_BAM]);
+ }
+ mutex_unlock(&info.suspend_resume_mutex);
+ pr_debug("%s: done", __func__);
+}
+
+void usb_bam_resume(struct usb_bam_connect_ipa_params *ipa_params)
+{
+ enum usb_bam cur_bam;
+ u8 src_idx, dst_idx;
+ struct usb_bam_pipe_connect *pipe_connect;
+
+ pr_debug("%s: Resuming\n", __func__);
+
+ if (!ipa_params) {
+ pr_err("%s: Invalid ipa params\n", __func__);
+ return;
+ }
+
+ src_idx = ipa_params->src_idx;
+ dst_idx = ipa_params->dst_idx;
+
+ if (src_idx >= ctx.max_connections || dst_idx >= ctx.max_connections) {
+ pr_err("%s: Invalid connection index src=%d dst=%d\n",
+ __func__, src_idx, dst_idx);
+ return;
+ }
+
+ pipe_connect = &usb_bam_connections[src_idx];
+ cur_bam = pipe_connect->bam_type;
+ if (cur_bam != HSUSB_BAM)
+ return;
+
+ info.in_lpm = false;
+ spin_lock(&usb_bam_ipa_handshake_info_lock);
+ info.bus_suspend = 0;
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
+ queue_work(ctx.usb_bam_wq, &info.resume_work);
+}
+
int usb_bam_connect_ipa(struct usb_bam_connect_ipa_params *ipa_params)
{
u8 idx;
@@ -800,27 +1248,38 @@
pipe_connect = &usb_bam_connections[idx];
cur_bam = pipe_connect->bam_type;
- if (cur_bam == HSUSB_BAM) {
- spin_lock(&usb_bam_lock);
- sched_lpm = 0;
- lpm_wait_handshake = 1;
- spin_unlock(&usb_bam_lock);
- }
-
if (pipe_connect->enabled) {
- pr_debug("%s: connection %d was already established\n",
+ pr_err("%s: connection %d was already established\n",
__func__, idx);
return 0;
}
+ pr_debug("%s: enter", __func__);
+ mutex_lock(&info.suspend_resume_mutex);
+
spin_lock(&usb_bam_lock);
+ if (ctx.pipes_enabled_per_bam[cur_bam] == 0) {
+ spin_unlock(&usb_bam_lock);
+ if (cur_bam == HSUSB_BAM) {
+ spin_lock(&usb_bam_ipa_handshake_info_lock);
+ info.lpm_wait_handshake = 1;
+ info.connect_complete = 0;
+ info.lpm_wait_pipes = 1;
+ info.bus_suspend = 0;
+ info.cons_stopped = 0;
+ info.prod_stopped = 0;
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
+ }
+ usb_bam_resume_core(cur_bam);
+ } else
+ spin_unlock(&usb_bam_lock);
/* Check if BAM requires RESET before connect and reset first pipe */
+ spin_lock(&usb_bam_lock);
if ((pdata->reset_on_connect[cur_bam] == true) &&
(ctx.pipes_enabled_per_bam[cur_bam] == 0))
sps_device_reset(ctx.h_bam[cur_bam]);
-
- spin_unlock(&usb_bam_lock);
+ spin_unlock(&usb_bam_lock);
if (ipa_params->dir == USB_TO_PEER_PERIPHERAL) {
pr_debug("%s: Starting connect sequence\n", __func__);
@@ -830,23 +1289,19 @@
ret = connect_pipe_ipa(idx, ipa_params);
if (ret) {
pr_err("%s: pipe connection failure\n", __func__);
+ mutex_unlock(&info.suspend_resume_mutex);
return ret;
}
spin_lock(&usb_bam_lock);
-
pipe_connect->enabled = 1;
ctx.pipes_enabled_per_bam[cur_bam] += 1;
-
- if (ipa_params->dir == PEER_PERIPHERAL_TO_USB &&
- cur_cons_state[cur_bam] == IPA_RM_RESOURCE_GRANTED) {
- pr_debug("%s: Notify CONS_GRANTED\n", __func__);
- ipa_rm_notify_completion(IPA_RM_RESOURCE_GRANTED,
- ipa_rm_resource_cons[cur_bam]);
- pr_debug("%s: Ended connect sequence\n", __func__);
- }
-
spin_unlock(&usb_bam_lock);
+ if (ipa_params->dir == PEER_PERIPHERAL_TO_USB && cur_bam == HSUSB_BAM)
+ wait_for_cons_granted(cur_bam);
+
+ mutex_unlock(&info.suspend_resume_mutex);
+ pr_debug("%s: done", __func__);
return 0;
}
@@ -904,6 +1359,14 @@
usb_bam_set_inactivity_timer(pipe_connect->bam_type);
spin_unlock(&usb_bam_lock);
+ /* A2 wakeup not from LPM (CONS was up) */
+ wait_for_prod_granted(pipe_connect->bam_type);
+ if (info.start) {
+ pr_debug("%s: Enqueue PROD transfer", __func__);
+ info.start(info.start_stop_param,
+ USB_TO_PEER_PERIPHERAL);
+ }
+
break;
case USB_BAM_EVENT_INACTIVITY:
@@ -1111,9 +1574,22 @@
int usb_bam_register_wake_cb(u8 idx, int (*callback)(void *user),
void *param)
{
+ info.wake_cb = callback;
+ info.wake_param = param;
return __usb_bam_register_wake_cb(idx, callback, param, true);
}
+int usb_bam_register_start_stop_cbs(
+ void (*start)(void *, enum usb_bam_pipe_dir),
+ void (*stop)(void *, enum usb_bam_pipe_dir),
+ void *param)
+{
+ info.start = start;
+ info.stop = stop;
+ info.start_stop_param = param;
+ return 0;
+}
+
int usb_bam_register_peer_reset_cb(int (*callback)(void *), void *param)
{
u32 ret = 0;
@@ -1156,78 +1632,29 @@
return 0;
}
- spin_lock(&usb_bam_lock);
-
ret = disconnect_pipe(idx);
if (ret) {
pr_err("%s: src pipe disconnection failure\n", __func__);
- spin_unlock(&usb_bam_lock);
return ret;
}
pipe_connect->enabled = 0;
-
+ spin_lock(&usb_bam_lock);
if (ctx.pipes_enabled_per_bam[pipe_connect->bam_type] == 0)
pr_err("%s: wrong pipes enabled counter for bam_type=%d\n",
__func__, pipe_connect->bam_type);
else
ctx.pipes_enabled_per_bam[pipe_connect->bam_type] -= 1;
-
spin_unlock(&usb_bam_lock);
return 0;
}
-static void usb_bam_start_lpm(void)
-{
- struct usb_phy *trans = usb_get_transceiver();
- BUG_ON(trans == NULL);
- spin_lock(&usb_bam_lock);
- lpm_wait_handshake = 0;
- if (sched_lpm) {
- pr_debug("%s: Going to LPM\n", __func__);
- spin_unlock(&usb_bam_lock);
- pm_runtime_resume(trans->dev);
- pm_runtime_put_noidle(trans->dev);
- pm_runtime_suspend(trans->dev);
- return;
- }
- spin_unlock(&usb_bam_lock);
-}
-
-static void wait_for_prod_release(enum usb_bam cur_bam)
-{
- int ret;
-
- if (cur_cons_state[cur_bam] == IPA_RM_RESOURCE_RELEASED)
- pr_debug("%s consumer already released\n", __func__);
- if (cur_prod_state[cur_bam] == IPA_RM_RESOURCE_RELEASED)
- pr_debug("%s producer already released\n", __func__);
-
- init_completion(&prod_released[cur_bam]);
- init_completion(&cons_released[cur_bam]);
- pr_debug("%s: Releasing %s_PROD\n", __func__,
- bam_enable_strings[cur_bam]);
- ret = ipa_rm_release_resource(ipa_rm_resource_prod[cur_bam]);
- if (!ret) {
- pr_debug("%s: Released without waiting\n", __func__);
- cur_prod_state[cur_bam] = IPA_RM_RESOURCE_RELEASED;
- complete_all(&prod_released[cur_bam]);
- } else if (ret == -EINPROGRESS) {
- pr_debug("%s: Waiting for PROD_RELEASED\n", __func__);
- if (!wait_for_completion_timeout(&prod_released[cur_bam],
- USB_BAM_TIMEOUT))
- pr_err("%s: Timeout waiting for PROD_RELEASED\n",
- __func__);
- } else
- pr_err("%s: ipa_rm_request_resource ret =%d", __func__, ret);
-}
-
static void wait_for_cons_release(enum usb_bam cur_bam)
{
pr_debug("%s: Waiting for CONS release\n", __func__);
- if (cur_prod_state[cur_bam] != IPA_RM_RESOURCE_RELEASED) {
- if (!wait_for_completion_timeout(&cons_released[cur_bam],
+ if (info.cur_cons_state[cur_bam] != IPA_RM_RESOURCE_RELEASED) {
+ if (!wait_for_completion_timeout(&info.cons_released[cur_bam],
USB_BAM_TIMEOUT))
pr_err("%s: Timeout wainting for CONS_RELEASE\n",
__func__);
@@ -1244,13 +1671,17 @@
struct sps_connect *sps_connection;
enum usb_bam cur_bam;
-
if (!ipa_params->prod_clnt_hdl && !ipa_params->cons_clnt_hdl) {
pr_err("%s: Both of the handles is missing\n", __func__);
return -EINVAL;
}
pr_debug("%s: Starting disconnect sequence\n", __func__);
+ spin_lock(&usb_bam_ipa_handshake_info_lock);
+ info.connect_complete = 0;
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
+
+ mutex_lock(&info.suspend_resume_mutex);
/* Delay USB core to go into lpm before we finish our handshake */
if (ipa_params->prod_clnt_hdl) {
idx = ipa_params->dst_idx;
@@ -1258,12 +1689,15 @@
/* Do the release handshake with the A2 via RM */
cur_bam = pipe_connect->bam_type;
+ info.lpm_wait_pipes = 1;
wait_for_prod_release(cur_bam);
/* close USB -> IPA pipe */
+ usb_bam_resume_core(cur_bam);
ret = ipa_disconnect(ipa_params->prod_clnt_hdl);
if (ret) {
pr_err("%s: dst pipe disconnection failure\n",
__func__);
+ mutex_unlock(&info.suspend_resume_mutex);
return ret;
}
sps_connection = &ctx.usb_bam_sps.sps_connections[idx];
@@ -1274,6 +1708,7 @@
if (ret) {
pr_err("%s: failure to disconnect pipe %d\n",
__func__, idx);
+ mutex_unlock(&info.suspend_resume_mutex);
return ret;
}
}
@@ -1288,6 +1723,7 @@
if (ret) {
pr_err("%s: src pipe disconnection failure\n",
__func__);
+ mutex_unlock(&info.suspend_resume_mutex);
return ret;
}
@@ -1299,17 +1735,24 @@
if (ret) {
pr_err("%s: failure to disconnect pipe %d\n",
__func__, idx);
+ mutex_unlock(&info.suspend_resume_mutex);
return ret;
}
- pr_debug("%s: Notify CONS release\n", __func__);
- if (cur_cons_state[cur_bam] == IPA_RM_RESOURCE_RELEASED)
+ pipe_connect->ipa_clnt_hdl = -1;
+
+ if (info.cur_cons_state[cur_bam] == IPA_RM_RESOURCE_RELEASED) {
+ pr_debug("%s Notify CONS _RELEASED\n", __func__);
ipa_rm_notify_completion(IPA_RM_RESOURCE_RELEASED,
ipa_rm_resource_cons[cur_bam]);
+ }
pr_debug("%s Ended disconnect sequence\n", __func__);
- usb_bam_start_lpm();
+ mutex_unlock(&info.suspend_resume_mutex);
+ usb_bam_start_lpm(1);
+ return 0;
}
+ mutex_unlock(&info.suspend_resume_mutex);
return 0;
}
EXPORT_SYMBOL(usb_bam_disconnect_ipa);
@@ -1810,18 +2253,23 @@
ctx.pipes_enabled_per_bam[i] = 0;
ctx.inactivity_timer_ms[i] = 0;
ctx.is_bam_inactivity[i] = false;
- init_completion(&prod_avail[i]);
- complete(&prod_avail[i]);
- init_completion(&cons_avail[i]);
- complete(&cons_avail[i]);
- init_completion(&cons_released[i]);
- complete(&cons_released[i]);
- init_completion(&prod_released[i]);
- complete(&prod_released[i]);
- cur_prod_state[i] = IPA_RM_RESOURCE_RELEASED;
- cur_cons_state[i] = IPA_RM_RESOURCE_RELEASED;
+ init_completion(&info.prod_avail[i]);
+ complete(&info.prod_avail[i]);
+ init_completion(&info.cons_avail[i]);
+ complete(&info.cons_avail[i]);
+ init_completion(&info.cons_released[i]);
+ complete(&info.cons_released[i]);
+ init_completion(&info.prod_released[i]);
+ complete(&info.prod_released[i]);
+ info.cur_prod_state[i] = IPA_RM_RESOURCE_RELEASED;
+ info.cur_cons_state[i] = IPA_RM_RESOURCE_RELEASED;
}
+ INIT_WORK(&info.resume_work, usb_bam_finish_resume);
+ INIT_WORK(&info.suspend_work, usb_bam_start_suspend);
+ INIT_WORK(&info.finish_suspend_work, usb_bam_finish_suspend_);
+ mutex_init(&info.suspend_resume_mutex);
+
spin_lock_init(&usb_bam_peer_handshake_info_lock);
INIT_WORK(&peer_handshake_info.reset_event.event_w, usb_bam_sm_work);
@@ -1837,8 +2285,8 @@
destroy_workqueue(ctx.usb_bam_wq);
return ret;
}
+ spin_lock_init(&usb_bam_ipa_handshake_info_lock);
usb_bam_ipa_create_resources();
-
spin_lock_init(&usb_bam_lock);
return ret;
@@ -1911,14 +2359,14 @@
bool msm_bam_lpm_ok(void)
{
- spin_lock(&usb_bam_lock);
- if (lpm_wait_handshake) {
- sched_lpm = 1;
- spin_unlock(&usb_bam_lock);
+ spin_lock(&usb_bam_ipa_handshake_info_lock);
+ if (info.lpm_wait_handshake || info.lpm_wait_pipes) {
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
pr_err("%s: Scheduling LPM for later\n", __func__);
return 0;
} else {
- spin_unlock(&usb_bam_lock);
+ info.in_lpm = 1;
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
pr_err("%s: Going to LPM now\n", __func__);
return 1;
}
diff --git a/drivers/power/pm8xxx-ccadc.c b/drivers/power/pm8xxx-ccadc.c
index 5313593..c53bcd2 100644
--- a/drivers/power/pm8xxx-ccadc.c
+++ b/drivers/power/pm8xxx-ccadc.c
@@ -790,6 +790,15 @@
return 0;
}
+static int pm8xxx_ccadc_suspend(struct device *dev)
+{
+ struct pm8xxx_ccadc_chip *chip = dev_get_drvdata(dev);
+
+ cancel_delayed_work_sync(&chip->calib_ccadc_work);
+
+ return 0;
+}
+
#define CCADC_CALIB_TEMP_THRESH 20
static int pm8xxx_ccadc_resume(struct device *dev)
{
@@ -823,8 +832,11 @@
|| delta_temp > CCADC_CALIB_TEMP_THRESH) {
the_chip->last_calib_time = current_time_sec;
the_chip->last_calib_temp = batt_temp;
- cancel_delayed_work(&the_chip->calib_ccadc_work);
schedule_delayed_work(&the_chip->calib_ccadc_work, 0);
+ } else {
+ schedule_delayed_work(&the_chip->calib_ccadc_work,
+ msecs_to_jiffies(the_chip->calib_delay_ms -
+ (time_since_last_calib * 1000)));
}
}
@@ -832,6 +844,7 @@
}
static const struct dev_pm_ops pm8xxx_ccadc_pm_ops = {
+ .suspend = pm8xxx_ccadc_suspend,
.resume = pm8xxx_ccadc_resume,
};
diff --git a/drivers/power/qpnp-bms.c b/drivers/power/qpnp-bms.c
index 1ece59b..eac8953 100644
--- a/drivers/power/qpnp-bms.c
+++ b/drivers/power/qpnp-bms.c
@@ -117,7 +117,9 @@
u8 revision1;
u8 revision2;
int battery_present;
+ int battery_status;
bool new_battery;
+ bool done_charging;
bool last_soc_invalid;
/* platform data */
int r_sense_uohm;
@@ -140,7 +142,6 @@
struct delayed_work calculate_soc_delayed_work;
struct work_struct recalc_work;
- struct work_struct battery_insertion_work;
struct mutex bms_output_lock;
struct mutex last_ocv_uv_mutex;
@@ -189,6 +190,8 @@
struct single_row_lut *adjusted_fcc_temp_lut;
struct qpnp_adc_tm_btm_param vbat_monitor_params;
+ struct qpnp_adc_tm_btm_param die_temp_monitor_params;
+ int temperature_margin;
unsigned int vadc_v0625;
unsigned int vadc_v1250;
@@ -223,7 +226,6 @@
};
static enum power_supply_property msm_bms_power_props[] = {
- POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_CAPACITY,
POWER_SUPPLY_PROP_CURRENT_NOW,
POWER_SUPPLY_PROP_RESISTANCE,
@@ -372,12 +374,17 @@
static inline int convert_vbatt_raw_to_uv(struct qpnp_bms_chip *chip,
uint16_t reading)
{
- int uv;
+ int64_t uv;
+ int rc;
uv = vadc_reading_to_uv(reading);
- pr_debug("%u raw converted into %d uv\n", reading, uv);
+ pr_debug("%u raw converted into %lld uv\n", reading, uv);
uv = adjust_vbatt_reading(chip, uv);
- pr_debug("adjusted into %d uv\n", uv);
+ pr_debug("adjusted into %lld uv\n", uv);
+ rc = qpnp_vbat_sns_comp_result(&uv);
+ if (rc)
+ pr_debug("could not compensate vbatt\n");
+ pr_debug("compensated into %lld uv\n", uv);
return uv;
}
@@ -581,7 +588,7 @@
pr_err("cc reenable failed: %d\n", rc);
}
-static bool is_battery_charging(struct qpnp_bms_chip *chip)
+static int get_battery_status(struct qpnp_bms_chip *chip)
{
union power_supply_propval ret = {0,};
@@ -591,12 +598,17 @@
/* if battery has been registered, use the status property */
chip->batt_psy->get_property(chip->batt_psy,
POWER_SUPPLY_PROP_STATUS, &ret);
- return ret.intval == POWER_SUPPLY_STATUS_CHARGING;
+ return ret.intval;
}
/* Default to false if the battery power supply is not registered. */
pr_debug("battery power supply is not registered\n");
- return false;
+ return POWER_SUPPLY_STATUS_UNKNOWN;
+}
+
+static bool is_battery_charging(struct qpnp_bms_chip *chip)
+{
+ return get_battery_status(chip) == POWER_SUPPLY_STATUS_CHARGING;
}
static bool is_battery_present(struct qpnp_bms_chip *chip)
@@ -619,20 +631,7 @@
static bool is_battery_full(struct qpnp_bms_chip *chip)
{
- union power_supply_propval ret = {0,};
-
- if (chip->batt_psy == NULL)
- chip->batt_psy = power_supply_get_by_name("battery");
- if (chip->batt_psy) {
- /* if battery has been registered, use the status property */
- chip->batt_psy->get_property(chip->batt_psy,
- POWER_SUPPLY_PROP_STATUS, &ret);
- return ret.intval == POWER_SUPPLY_STATUS_FULL;
- }
-
- /* Default to true if the battery power supply is not registered. */
- pr_debug("battery power supply is not registered\n");
- return true;
+ return get_battery_status(chip) == POWER_SUPPLY_STATUS_FULL;
}
static int get_simultaneous_batt_v_and_i(struct qpnp_bms_chip *chip,
@@ -769,6 +768,19 @@
raw->cc = 0;
raw->last_good_ocv_uv = chip->last_ocv_uv;
chip->new_battery = false;
+ } else if (chip->done_charging) {
+ chip->done_charging = false;
+ /* if we just finished charging, reset CC and fake 100% */
+ chip->ocv_reading_at_100 = raw->last_good_ocv_raw;
+ chip->last_ocv_uv = chip->max_voltage_uv;
+ raw->last_good_ocv_uv = chip->max_voltage_uv;
+ raw->cc = 0;
+ reset_cc(chip);
+ chip->last_ocv_temp = batt_temp;
+ chip->software_cc_uah = 0;
+ chip->last_cc_uah = INT_MIN;
+ pr_debug("EOC Battery full ocv_reading = 0x%x\n",
+ chip->ocv_reading_at_100);
} else if (chip->prev_last_good_ocv_raw != raw->last_good_ocv_raw) {
convert_and_store_ocv(chip, raw, batt_temp);
/* forget the old cc value upon ocv */
@@ -777,21 +789,10 @@
raw->last_good_ocv_uv = chip->last_ocv_uv;
}
- /* fake a high OCV if done charging */
- if (chip->ocv_reading_at_100 != raw->last_good_ocv_raw) {
+ /* stop faking a high OCV if we get a new OCV */
+ if (chip->ocv_reading_at_100 != raw->last_good_ocv_raw)
chip->ocv_reading_at_100 = OCV_RAW_UNINITIALIZED;
- } else {
- /*
- * force 100% ocv by selecting the highest voltage the
- * battery could ever reach
- */
- raw->last_good_ocv_uv = chip->max_voltage_uv;
- chip->last_ocv_uv = chip->max_voltage_uv;
- chip->last_ocv_temp = batt_temp;
- reset_cc(chip);
- chip->software_cc_uah = 0;
- raw->cc = 0;
- }
+
pr_debug("last_good_ocv_raw= 0x%x, last_good_ocv_uv= %duV\n",
raw->last_good_ocv_raw, raw->last_good_ocv_uv);
pr_debug("cc_raw= 0x%llx\n", raw->cc);
@@ -1811,6 +1812,7 @@
if (chip->use_voltage_soc) {
soc = calculate_soc_from_voltage(chip);
} else {
+ qpnp_iadc_calibrate_for_trim();
rc = qpnp_vadc_read(LR_MUX1_BATT_THERM, &result);
if (rc) {
pr_err("error reading vadc LR_MUX1_BATT_THERM = %d, rc = %d\n",
@@ -2244,11 +2246,56 @@
return 0;
}
-static void battery_insertion_work(struct work_struct *work)
+static void charging_began(struct qpnp_bms_chip *chip)
{
- struct qpnp_bms_chip *chip = container_of(work,
- struct qpnp_bms_chip,
- battery_insertion_work);
+ mutex_lock(&chip->last_soc_mutex);
+ chip->charge_start_tm_sec = 0;
+ chip->catch_up_time_sec = 0;
+ mutex_unlock(&chip->last_soc_mutex);
+
+ mutex_lock(&chip->last_ocv_uv_mutex);
+ chip->soc_at_cv = -EINVAL;
+ chip->prev_chg_soc = -EINVAL;
+ mutex_unlock(&chip->last_ocv_uv_mutex);
+}
+
+static void charging_ended(struct qpnp_bms_chip *chip)
+{
+ mutex_lock(&chip->last_soc_mutex);
+ chip->charge_start_tm_sec = 0;
+ chip->catch_up_time_sec = 0;
+ mutex_unlock(&chip->last_soc_mutex);
+
+ mutex_lock(&chip->last_ocv_uv_mutex);
+ chip->soc_at_cv = -EINVAL;
+ chip->prev_chg_soc = -EINVAL;
+ if (get_battery_status(chip) == POWER_SUPPLY_STATUS_FULL)
+ chip->done_charging = true;
+ mutex_unlock(&chip->last_ocv_uv_mutex);
+}
+
+static void battery_status_check(struct qpnp_bms_chip *chip)
+{
+ int status = get_battery_status(chip);
+
+ if (chip->battery_status != status) {
+ if (status == POWER_SUPPLY_STATUS_CHARGING) {
+ pr_debug("charging started\n");
+ charging_began(chip);
+ } else if (chip->battery_status
+ == POWER_SUPPLY_STATUS_CHARGING) {
+ pr_debug("charging ended\n");
+ charging_ended(chip);
+ }
+ chip->battery_status = status;
+ /* a new battery was inserted or removed, so force a soc
+ * recalculation to update the SoC */
+ schedule_work(&chip->recalc_work);
+ }
+}
+
+static void battery_insertion_check(struct qpnp_bms_chip *chip)
+{
bool present = is_battery_present(chip);
mutex_lock(&chip->vbat_monitor_mutex);
@@ -2300,18 +2347,13 @@
return chip->fcc_mah * 1000;
}
-static int get_prop_bms_present(struct qpnp_bms_chip *chip)
-{
- return is_battery_present(chip);
-}
-
-static void set_prop_bms_present(struct qpnp_bms_chip *chip, int present)
-{
- schedule_work(&chip->battery_insertion_work);
-}
-
static void qpnp_bms_external_power_changed(struct power_supply *psy)
{
+ struct qpnp_bms_chip *chip = container_of(psy, struct qpnp_bms_chip,
+ bms_psy);
+
+ battery_insertion_check(chip);
+ battery_status_check(chip);
}
static int qpnp_bms_power_get_property(struct power_supply *psy,
@@ -2334,26 +2376,6 @@
case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
val->intval = get_prop_bms_charge_full_design(chip);
break;
- case POWER_SUPPLY_PROP_PRESENT:
- val->intval = get_prop_bms_present(chip);
- break;
- default:
- return -EINVAL;
- }
- return 0;
-}
-
-static int qpnp_bms_power_set_property(struct power_supply *psy,
- enum power_supply_property psp,
- const union power_supply_propval *val)
-{
- struct qpnp_bms_chip *chip = container_of(psy, struct qpnp_bms_chip,
- bms_psy);
-
- switch (psp) {
- case POWER_SUPPLY_PROP_PRESENT:
- set_prop_bms_present(chip, val->intval);
- break;
default:
return -EINVAL;
}
@@ -2572,6 +2594,7 @@
SPMI_PROP_READ(ocv_low_threshold_uv,
"ocv-voltage-low-threshold-uv", rc);
SPMI_PROP_READ(low_voltage_threshold, "low-voltage-threshold", rc);
+ SPMI_PROP_READ(temperature_margin, "tm-temp-margin", rc);
if (chip->adjust_soc_low_threshold >= 45)
chip->adjust_soc_low_threshold = 45;
@@ -2599,6 +2622,7 @@
chip->last_soc = -EINVAL;
chip->last_soc_est = -EINVAL;
chip->battery_present = -EINVAL;
+ chip->battery_status = POWER_SUPPLY_STATUS_UNKNOWN;
chip->last_cc_uah = INT_MIN;
chip->ocv_reading_at_100 = OCV_RAW_UNINITIALIZED;
chip->prev_last_good_ocv_raw = OCV_RAW_UNINITIALIZED;
@@ -2745,6 +2769,64 @@
return 0;
}
+static int refresh_die_temp_monitor(struct qpnp_bms_chip *chip)
+{
+ struct qpnp_vadc_result result;
+ int rc;
+
+ rc = qpnp_vadc_read(DIE_TEMP, &result);
+
+ pr_debug("low = %lld, high = %lld\n",
+ result.physical - chip->temperature_margin,
+ result.physical + chip->temperature_margin);
+ chip->die_temp_monitor_params.high_temp = result.physical
+ + chip->temperature_margin;
+ chip->die_temp_monitor_params.low_temp = result.physical
+ - chip->temperature_margin;
+ chip->die_temp_monitor_params.state_request =
+ ADC_TM_HIGH_LOW_THR_ENABLE;
+ return qpnp_adc_tm_channel_measure(&chip->die_temp_monitor_params);
+}
+
+static void btm_notify_die_temp(enum qpnp_tm_state state, void *ctx)
+{
+ struct qpnp_bms_chip *chip = ctx;
+ struct qpnp_vadc_result result;
+ int rc;
+
+ rc = qpnp_vadc_read(DIE_TEMP, &result);
+
+ if (state == ADC_TM_LOW_STATE)
+ pr_debug("low state triggered\n");
+ else if (state == ADC_TM_HIGH_STATE)
+ pr_debug("high state triggered\n");
+ pr_debug("die temp = %lld, raw = 0x%x\n",
+ result.physical, result.adc_code);
+ schedule_work(&chip->recalc_work);
+ refresh_die_temp_monitor(chip);
+}
+
+static int setup_die_temp_monitoring(struct qpnp_bms_chip *chip)
+{
+ int rc = qpnp_adc_tm_is_ready();
+ if (rc) {
+ pr_info("adc tm is not ready yet: %d, defer probe\n", rc);
+ return -EPROBE_DEFER;
+ }
+ chip->die_temp_monitor_params.channel = DIE_TEMP;
+ chip->die_temp_monitor_params.btm_ctx = (void *)chip;
+ chip->die_temp_monitor_params.timer_interval = ADC_MEAS1_INTERVAL_1S;
+ chip->die_temp_monitor_params.threshold_notification =
+ &btm_notify_die_temp;
+ refresh_die_temp_monitor(chip);
+ if (rc) {
+ pr_err("tm setup failed: %d\n", rc);
+ return rc;
+ }
+ pr_debug("setup complete\n");
+ return 0;
+}
+
static int __devinit qpnp_bms_probe(struct spmi_device *spmi)
{
struct qpnp_bms_chip *chip;
@@ -2844,7 +2926,6 @@
INIT_DELAYED_WORK(&chip->calculate_soc_delayed_work,
calculate_soc_work);
INIT_WORK(&chip->recalc_work, recalculate_work);
- INIT_WORK(&chip->battery_insertion_work, battery_insertion_work);
read_shutdown_soc_and_iavg(chip);
@@ -2857,6 +2938,12 @@
goto error_setup;
}
+ rc = setup_die_temp_monitoring(chip);
+ if (rc < 0) {
+ pr_err("failed to set up die temp notifications: %d\n", rc);
+ goto error_setup;
+ }
+
calculate_soc_work(&(chip->calculate_soc_delayed_work.work));
/* setup & register the battery power supply */
@@ -2865,7 +2952,6 @@
chip->bms_psy.properties = msm_bms_power_props;
chip->bms_psy.num_properties = ARRAY_SIZE(msm_bms_power_props);
chip->bms_psy.get_property = qpnp_bms_power_get_property;
- chip->bms_psy.set_property = qpnp_bms_power_set_property;
chip->bms_psy.external_power_changed =
qpnp_bms_external_power_changed;
chip->bms_psy.supplied_to = qpnp_bms_supplicants;
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index 4be1760..3d8a75d 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -729,9 +729,6 @@
}
}
- if (chip->bms_psy)
- power_supply_set_present(chip->bms_psy, batt_present);
-
return IRQ_HANDLED;
}
@@ -928,6 +925,10 @@
"battery",
};
+static char *pm_batt_supplied_to[] = {
+ "bms",
+};
+
#define USB_WALL_THRESHOLD_MA 500
static int
qpnp_power_get_property_mains(struct power_supply *psy,
@@ -2111,7 +2112,6 @@
struct qpnp_chg_chip *chip;
struct resource *resource;
struct spmi_resource *spmi_resource;
- bool present;
int rc = 0;
chip = kzalloc(sizeof *chip, GFP_KERNEL);
@@ -2268,14 +2268,6 @@
if (rc)
goto fail_chg_enable;
- /* if bms exists, notify it of the presence of the battery */
- if (!chip->bms_psy)
- chip->bms_psy = power_supply_get_by_name("bms");
- if (chip->bms_psy) {
- present = get_prop_batt_present(chip);
- power_supply_set_present(chip->bms_psy, present);
- }
-
chip->batt_psy.name = "battery";
chip->batt_psy.type = POWER_SUPPLY_TYPE_BATTERY;
chip->batt_psy.properties = msm_batt_power_props;
@@ -2287,6 +2279,9 @@
qpnp_batt_property_is_writeable;
chip->batt_psy.external_power_changed =
qpnp_batt_external_power_changed;
+ chip->batt_psy.supplied_to = pm_batt_supplied_to;
+ chip->batt_psy.num_supplicants =
+ ARRAY_SIZE(pm_batt_supplied_to);
rc = power_supply_register(chip->dev, &chip->batt_psy);
if (rc < 0) {
@@ -2361,6 +2356,11 @@
power_supply_set_present(chip->usb_psy,
qpnp_chg_is_usb_chg_plugged_in(chip));
+ /* Set USB psy online to avoid userspace from shutting down if battery
+ * capacity is at zero and no chargers online. */
+ if (qpnp_chg_is_usb_chg_plugged_in(chip))
+ power_supply_set_online(chip->usb_psy, 1);
+
pr_info("success chg_dis = %d, usb = %d, dc = %d b_health = %d batt_present = %d\n",
chip->charging_disabled,
qpnp_chg_is_usb_chg_plugged_in(chip),
diff --git a/drivers/usb/gadget/f_mbim.c b/drivers/usb/gadget/f_mbim.c
index 22f8dc9..a1b02be 100644
--- a/drivers/usb/gadget/f_mbim.c
+++ b/drivers/usb/gadget/f_mbim.c
@@ -798,8 +798,6 @@
{
struct usb_request *req = mbim->not_port.notify_req;
struct usb_cdc_notification *event;
- struct usb_composite_dev *cdev = mbim->cdev;
- __le32 *data;
int status;
pr_debug("notify_state: %d", mbim->not_port.notify_state);
@@ -836,36 +834,6 @@
}
return;
-
- case NCM_NOTIFY_CONNECT:
- event->bNotificationType = USB_CDC_NOTIFY_NETWORK_CONNECTION;
- if (mbim->is_open)
- event->wValue = cpu_to_le16(1);
- else
- event->wValue = cpu_to_le16(0);
- event->wLength = 0;
- req->length = sizeof *event;
-
- pr_info("notify connect %s\n",
- mbim->is_open ? "true" : "false");
- mbim->not_port.notify_state = NCM_NOTIFY_RESPONSE_AVAILABLE;
- break;
-
- case NCM_NOTIFY_SPEED:
- event->bNotificationType = USB_CDC_NOTIFY_SPEED_CHANGE;
- event->wValue = cpu_to_le16(0);
- event->wLength = cpu_to_le16(8);
- req->length = NCM_STATUS_BYTECOUNT;
-
- /* SPEED_CHANGE data is up/down speeds in bits/sec */
- data = req->buf + sizeof *event;
- data[0] = cpu_to_le32(mbim_bitrate(cdev->gadget));
- data[1] = data[0];
-
- pr_info("notify speed %d\n",
- mbim_bitrate(cdev->gadget));
- mbim->not_port.notify_state = NCM_NOTIFY_CONNECT;
- break;
}
event->bmRequestType = 0xA1;
@@ -888,22 +856,6 @@
}
}
-/*
- * Context: mbim->lock held
- */
-static void mbim_notify(struct f_mbim *mbim)
-{
- /*
- * If mbim_notify() is called before the second (CONNECT)
- * notification is sent, then it will reset to send the SPEED
- * notificaion again (and again, and again), but it's not a problem
- */
- pr_debug("dev:%p\n", mbim);
-
- mbim->not_port.notify_state = NCM_NOTIFY_RESPONSE_AVAILABLE;
- mbim_do_notify(mbim);
-}
-
static void mbim_notify_complete(struct usb_ep *ep, struct usb_request *req)
{
struct f_mbim *mbim = req->context;
@@ -1391,7 +1343,7 @@
mbim->data_alt_int = alt;
spin_lock(&mbim->lock);
- mbim_notify(mbim);
+ mbim->not_port.notify_state = NCM_NOTIFY_RESPONSE_AVAILABLE;
spin_unlock(&mbim->lock);
} else {
goto fail;
diff --git a/drivers/usb/gadget/f_qc_ecm.c b/drivers/usb/gadget/f_qc_ecm.c
index a395d15..5e68296 100644
--- a/drivers/usb/gadget/f_qc_ecm.c
+++ b/drivers/usb/gadget/f_qc_ecm.c
@@ -599,7 +599,7 @@
DBG(cdev, "activate ecm\n");
if (ecm->xport != USB_GADGET_XPORT_BAM2BAM_IPA) {
net = gether_qc_connect_name(&ecm->port,
- "ecm0");
+ "ecm0", true);
if (IS_ERR(net))
return PTR_ERR(net);
}
diff --git a/drivers/usb/gadget/f_qc_rndis.c b/drivers/usb/gadget/f_qc_rndis.c
index 8b01176..baea664 100644
--- a/drivers/usb/gadget/f_qc_rndis.c
+++ b/drivers/usb/gadget/f_qc_rndis.c
@@ -725,7 +725,7 @@
rndis->port.cdc_filter = 0;
DBG(cdev, "RNDIS RX/TX early activation ...\n");
- net = gether_qc_connect_name(&rndis->port, "rndis0");
+ net = gether_qc_connect_name(&rndis->port, "rndis0", false);
if (IS_ERR(net))
return PTR_ERR(net);
diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c
index 1017900..1288bfd 100644
--- a/drivers/usb/gadget/f_rndis.c
+++ b/drivers/usb/gadget/f_rndis.c
@@ -74,7 +74,7 @@
static unsigned int rndis_ul_max_pkt_per_xfer = 1;
module_param(rndis_ul_max_pkt_per_xfer, uint, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(rndis_ul_max_pkt_per_xfer,
- "Disable RNDIS Multi-packet support in DownLink");
+ "Maximum packets per transfer for UL aggregation");
struct f_rndis {
struct gether port;
diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c
index 07f4d26..bff7eb1 100644
--- a/drivers/usb/gadget/rndis.c
+++ b/drivers/usb/gadget/rndis.c
@@ -947,6 +947,10 @@
rndis_per_dev_params[configNr].dev = dev;
rndis_per_dev_params[configNr].filter = cdc_filter;
+ /* reset aggregation stats for every set_alt */
+ rndis_ul_max_xfer_size_rcvd = 0;
+ rndis_ul_max_pkt_per_xfer_rcvd = 0;
+
return 0;
}
@@ -1060,7 +1064,7 @@
struct sk_buff *skb,
struct sk_buff_head *list)
{
- int num_pkts = 1;
+ int num_pkts = 0;
if (skb->len > rndis_ul_max_xfer_size_rcvd)
rndis_ul_max_xfer_size_rcvd = skb->len;
@@ -1072,6 +1076,8 @@
/* some rndis hosts send extra byte to avoid zlp, ignore it */
if (skb->len == 1) {
+ if (num_pkts > rndis_ul_max_pkt_per_xfer_rcvd)
+ rndis_ul_max_pkt_per_xfer_rcvd = num_pkts;
dev_kfree_skb_any(skb);
return 0;
}
@@ -1105,6 +1111,8 @@
return -EINVAL;
}
+ num_pkts++;
+
skb_pull(skb, data_offset + 8);
if (msg_len == skb->len) {
@@ -1122,8 +1130,6 @@
skb_pull(skb, msg_len - sizeof *hdr);
skb_trim(skb2, data_len);
skb_queue_tail(list, skb2);
-
- num_pkts++;
}
if (num_pkts > rndis_ul_max_pkt_per_xfer_rcvd)
@@ -1148,7 +1154,9 @@
"speed : %d\n"
"cable : %s\n"
"vendor ID : 0x%08X\n"
- "vendor : %s\n",
+ "vendor : %s\n"
+ "ul-max-xfer-size:%d max-xfer-size-rcvd: %d\n"
+ "ul-max-pkts-per-xfer:%d max-pkts-per-xfer-rcvd:%d\n",
param->confignr, (param->used) ? "y" : "n",
({ char *s = "?";
switch (param->state) {
@@ -1162,7 +1170,13 @@
param->medium,
(param->media_state) ? 0 : param->speed*100,
(param->media_state) ? "disconnected" : "connected",
- param->vendorID, param->vendorDescr);
+ param->vendorID, param->vendorDescr,
+ param->max_pkt_per_xfer *
+ (param->dev->mtu + sizeof(struct ethhdr) +
+ sizeof(struct rndis_packet_msg_type) + 22),
+ rndis_ul_max_xfer_size_rcvd,
+ param->max_pkt_per_xfer,
+ rndis_ul_max_pkt_per_xfer_rcvd);
return 0;
}
diff --git a/drivers/usb/gadget/u_bam.c b/drivers/usb/gadget/u_bam.c
index c05f683..b71f903 100644
--- a/drivers/usb/gadget/u_bam.c
+++ b/drivers/usb/gadget/u_bam.c
@@ -539,9 +539,12 @@
struct bam_ch_info *d = &port->data_ch;
int status;
- if (!port->port_usb)
+ if (!port->port_usb) {
+ pr_err("%s: port->port_usb is NULL", __func__);
return;
+ }
+ pr_debug("%s: enqueue\n", __func__);
status = usb_ep_queue(port->port_usb->out, d->rx_req, GFP_ATOMIC);
if (status)
pr_err("%s: error enqueuing transfer, %d\n", __func__, status);
@@ -552,14 +555,69 @@
struct bam_ch_info *d = &port->data_ch;
int status;
- if (!port->port_usb)
+ if (!port->port_usb) {
+ pr_err("%s: port->port_usb is NULL", __func__);
return;
+ }
+ pr_debug("%s: enqueue\n", __func__);
status = usb_ep_queue(port->port_usb->in, d->tx_req, GFP_ATOMIC);
if (status)
pr_err("%s: error enqueuing transfer, %d\n", __func__, status);
}
+static void gbam_stop_endless_rx(struct gbam_port *port)
+{
+ struct bam_ch_info *d = &port->data_ch;
+ int status;
+
+ if (!port->port_usb) {
+ pr_err("%s: port->port_usb is NULL", __func__);
+ return;
+ }
+ pr_debug("%s: dequeue\n", __func__);
+
+ status = usb_ep_dequeue(port->port_usb->out, d->rx_req);
+ if (status)
+ pr_err("%s: error dequeuing transfer, %d\n", __func__, status);
+
+}
+static void gbam_stop_endless_tx(struct gbam_port *port)
+{
+ struct bam_ch_info *d = &port->data_ch;
+ int status;
+
+ if (!port->port_usb) {
+ pr_err("%s: port->port_usb is NULL", __func__);
+ return;
+ }
+
+ pr_debug("%s: dequeue\n", __func__);
+ status = usb_ep_dequeue(port->port_usb->in, d->tx_req);
+ if (status)
+ pr_err("%s: error dequeuing transfer, %d\n", __func__, status);
+}
+
+static void gbam_start(void *param, enum usb_bam_pipe_dir dir)
+{
+ struct gbam_port *port = param;
+
+ if (dir == USB_TO_PEER_PERIPHERAL)
+ gbam_start_endless_rx(port);
+ else
+ gbam_start_endless_tx(port);
+}
+
+static void gbam_stop(void *param, enum usb_bam_pipe_dir dir)
+{
+ struct gbam_port *port = param;
+
+ if (dir == USB_TO_PEER_PERIPHERAL)
+ gbam_stop_endless_rx(port);
+ else
+ gbam_stop_endless_tx(port);
+}
+
static void gbam_start_io(struct gbam_port *port)
{
unsigned long flags;
@@ -1409,6 +1467,10 @@
pr_debug("%s: suspended port %d\n", __func__, port_num);
usb_bam_register_wake_cb(d->dst_connection_idx, gbam_wake_cb, port);
+ if (trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
+ usb_bam_register_start_stop_cbs(gbam_start, gbam_stop, port);
+ usb_bam_suspend(&d->ipa_params);
+ }
}
void gbam_resume(struct grmnet *gr, u8 port_num, enum transport_type trans)
@@ -1426,4 +1488,6 @@
pr_debug("%s: resumed port %d\n", __func__, port_num);
usb_bam_register_wake_cb(d->dst_connection_idx, NULL, NULL);
+ if (trans == USB_GADGET_XPORT_BAM2BAM_IPA)
+ usb_bam_resume(&d->ipa_params);
}
diff --git a/drivers/usb/gadget/u_bam_data.c b/drivers/usb/gadget/u_bam_data.c
index 2abe2ef..081a09c 100644
--- a/drivers/usb/gadget/u_bam_data.c
+++ b/drivers/usb/gadget/u_bam_data.c
@@ -92,6 +92,7 @@
if (!port->port_usb)
return;
+ pr_debug("%s: enqueue\n", __func__);
status = usb_ep_queue(port->port_usb->out, d->rx_req, GFP_ATOMIC);
if (status)
pr_err("error enqueuing transfer, %d\n", status);
@@ -105,11 +106,40 @@
if (!port->port_usb)
return;
+ pr_debug("%s: enqueue\n", __func__);
status = usb_ep_queue(port->port_usb->in, d->tx_req, GFP_ATOMIC);
if (status)
pr_err("error enqueuing transfer, %d\n", status);
}
+static void bam_data_stop_endless_rx(struct bam_data_port *port)
+{
+ struct bam_data_ch_info *d = &port->data_ch;
+ int status;
+
+ if (!port->port_usb)
+ return;
+
+ pr_debug("%s: dequeue\n", __func__);
+ status = usb_ep_dequeue(port->port_usb->out, d->rx_req);
+ if (status)
+ pr_err("%s: error dequeuing transfer, %d\n", __func__, status);
+
+}
+static void bam_data_stop_endless_tx(struct bam_data_port *port)
+{
+ struct bam_data_ch_info *d = &port->data_ch;
+ int status;
+
+ if (!port->port_usb)
+ return;
+
+ pr_debug("%s: dequeue\n", __func__);
+ status = usb_ep_dequeue(port->port_usb->in, d->tx_req);
+ if (status)
+ pr_err("%s: error dequeuing transfer, %d\n", __func__, status);
+}
+
static int bam_data_peer_reset_cb(void *param)
{
struct bam_data_port *port = (struct bam_data_port *)param;
@@ -529,9 +559,28 @@
return usb_gadget_wakeup(d_port->cdev->gadget);
}
+static void bam_data_start(void *param, enum usb_bam_pipe_dir dir)
+{
+ struct bam_data_port *port = param;
+
+ if (dir == USB_TO_PEER_PERIPHERAL)
+ bam_data_start_endless_rx(port);
+ else
+ bam_data_start_endless_tx(port);
+}
+
+static void bam_data_stop(void *param, enum usb_bam_pipe_dir dir)
+{
+ struct bam_data_port *port = param;
+
+ if (dir == USB_TO_PEER_PERIPHERAL)
+ bam_data_stop_endless_rx(port);
+ else
+ bam_data_stop_endless_tx(port);
+}
+
void bam_data_suspend(u8 port_num)
{
-
struct bam_data_port *port;
struct bam_data_ch_info *d;
@@ -540,6 +589,11 @@
pr_debug("%s: suspended port %d\n", __func__, port_num);
usb_bam_register_wake_cb(d->dst_connection_idx, bam_data_wake_cb, port);
+ if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
+ usb_bam_register_start_stop_cbs(bam_data_start, bam_data_stop,
+ port);
+ usb_bam_suspend(&d->ipa_params);
+ }
}
void bam_data_resume(u8 port_num)
@@ -553,5 +607,6 @@
pr_debug("%s: resumed port %d\n", __func__, port_num);
usb_bam_register_wake_cb(d->dst_connection_idx, NULL, NULL);
+ if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA)
+ usb_bam_resume(&d->ipa_params);
}
-
diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c
index d4c21dd..dbffa4e 100644
--- a/drivers/usb/gadget/u_ether.c
+++ b/drivers/usb/gadget/u_ether.c
@@ -70,7 +70,7 @@
struct sk_buff_head rx_frames;
unsigned header_len;
- unsigned ul_max_pkts_per_xfer;
+ unsigned int ul_max_pkts_per_xfer;
struct sk_buff *(*wrap)(struct gether *, struct sk_buff *skb);
int (*unwrap)(struct gether *,
struct sk_buff *skb,
diff --git a/drivers/usb/gadget/u_qc_ether.c b/drivers/usb/gadget/u_qc_ether.c
index e10ec25..044da47 100644
--- a/drivers/usb/gadget/u_qc_ether.c
+++ b/drivers/usb/gadget/u_qc_ether.c
@@ -354,12 +354,13 @@
* current device speed, and any framing wrapper(s) set up.
* @netname: name for network device (for example, "usb")
* Context: irqs blocked
+ * @netif_enable: if true, net interface will be turned on
*
* This is called to let the network layer know the connection
* is active ("carrier detect").
*/
struct net_device *gether_qc_connect_name(struct qc_gether *link,
- const char *netname)
+ const char *netname, bool netif_enable)
{
struct net_device *net_dev;
struct eth_qc_dev *dev;
@@ -390,9 +391,11 @@
}
spin_unlock(&dev->lock);
- netif_carrier_on(dev->net);
- if (netif_running(dev->net))
- netif_wake_queue(dev->net);
+ if (netif_enable) {
+ netif_carrier_on(dev->net);
+ if (netif_running(dev->net))
+ netif_wake_queue(dev->net);
+ }
return dev->net;
}
diff --git a/drivers/usb/gadget/u_qc_ether.h b/drivers/usb/gadget/u_qc_ether.h
index 25562da..5d9f738 100644
--- a/drivers/usb/gadget/u_qc_ether.h
+++ b/drivers/usb/gadget/u_qc_ether.h
@@ -82,7 +82,7 @@
/* connect/disconnect is handled by individual functions */
struct net_device *gether_qc_connect_name(struct qc_gether *link,
- const char *netname);
+ const char *netname, bool netif_enable);
void gether_qc_disconnect_name(struct qc_gether *link, const char *netname);
/* each configuration may bind one instance of an ethernet link */
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index d4d7ee9..833bab2 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -870,7 +870,7 @@
return 0;
if (motg->pdata->delay_lpm_hndshk_on_disconnect && !msm_bam_lpm_ok())
- return 0;
+ return -EBUSY;
disable_irq(motg->irq);
host_bus_suspend = !test_bit(MHL, &motg->inputs) && phy->otg->host &&
diff --git a/drivers/video/msm/mdss/Makefile b/drivers/video/msm/mdss/Makefile
index 2c58e49..43eda51 100644
--- a/drivers/video/msm/mdss/Makefile
+++ b/drivers/video/msm/mdss/Makefile
@@ -1,4 +1,5 @@
mdss-mdp3-objs = mdp3.o mdp3_dma.o mdp3_ctrl.o
+mdss-mdp3-objs += mdp3_ppp.o mdp3_ppp_hwio.o mdp3_ppp_data.o
obj-$(CONFIG_FB_MSM_MDSS) += mdss-mdp3.o
mdss-mdp-objs := mdss_mdp.o mdss_mdp_ctl.o mdss_mdp_pipe.o mdss_mdp_util.o
diff --git a/drivers/video/msm/mdss/mdp3.c b/drivers/video/msm/mdss/mdp3.c
index 290e317..5223e66 100644
--- a/drivers/video/msm/mdss/mdp3.c
+++ b/drivers/video/msm/mdss/mdp3.c
@@ -48,11 +48,12 @@
#include "mdss_fb.h"
#include "mdp3_hwio.h"
#include "mdp3_ctrl.h"
+#include "mdp3_ppp.h"
#define MDP_CORE_HW_VERSION 0x03040310
struct mdp3_hw_resource *mdp3_res;
-#define MDP_BUS_VECTOR_ENTRY(ab_val, ib_val) \
+#define MDP_BUS_VECTOR_ENTRY_DMA(ab_val, ib_val) \
{ \
.src = MSM_BUS_MASTER_MDP_PORT0, \
.dst = MSM_BUS_SLAVE_EBI_CH0, \
@@ -60,20 +61,59 @@
.ib = (ib_val), \
}
-static struct msm_bus_vectors mdp_bus_vectors[] = {
- MDP_BUS_VECTOR_ENTRY(0, 0),
- MDP_BUS_VECTOR_ENTRY(SZ_128M, SZ_256M),
- MDP_BUS_VECTOR_ENTRY(SZ_256M, SZ_512M),
+static struct msm_bus_vectors mdp_bus_dma_vectors[] = {
+ MDP_BUS_VECTOR_ENTRY_DMA(0, 0),
+ MDP_BUS_VECTOR_ENTRY_DMA(SZ_128M, SZ_256M),
+ MDP_BUS_VECTOR_ENTRY_DMA(SZ_256M, SZ_512M),
+};
+static struct msm_bus_paths
+ mdp_bus_dma_usecases[ARRAY_SIZE(mdp_bus_dma_vectors)];
+static struct msm_bus_scale_pdata mdp_bus_dma_scale_table = {
+ .usecase = mdp_bus_dma_usecases,
+ .num_usecases = ARRAY_SIZE(mdp_bus_dma_usecases),
+ .name = "mdp3",
};
-static struct msm_bus_paths mdp_bus_usecases[ARRAY_SIZE(mdp_bus_vectors)];
+#define MDP_BUS_VECTOR_ENTRY_PPP(ab_val, ib_val) \
+ { \
+ .src = MSM_BUS_MASTER_MDPE, \
+ .dst = MSM_BUS_SLAVE_EBI_CH0, \
+ .ab = (ab_val), \
+ .ib = (ib_val), \
+ }
-static struct msm_bus_scale_pdata mdp_bus_scale_table = {
- .usecase = mdp_bus_usecases,
- .num_usecases = ARRAY_SIZE(mdp_bus_usecases),
+static struct msm_bus_vectors mdp_bus_ppp_vectors[] = {
+ MDP_BUS_VECTOR_ENTRY_PPP(0, 0),
+ MDP_BUS_VECTOR_ENTRY_PPP(SZ_128M, SZ_256M),
+ MDP_BUS_VECTOR_ENTRY_PPP(SZ_256M, SZ_512M),
+};
+
+static struct msm_bus_paths
+ mdp_bus_ppp_usecases[ARRAY_SIZE(mdp_bus_ppp_vectors)];
+
+static struct msm_bus_scale_pdata mdp_bus_ppp_scale_table = {
+ .usecase = mdp_bus_ppp_usecases,
+ .num_usecases = ARRAY_SIZE(mdp_bus_ppp_usecases),
.name = "mdp3",
};
+struct mdp3_bus_handle_map mdp3_bus_handle[MDP3_BUS_HANDLE_MAX] = {
+ [MDP3_BUS_HANDLE_DMA] = {
+ .bus_vector = mdp_bus_dma_vectors,
+ .usecases = mdp_bus_dma_usecases,
+ .scale_pdata = &mdp_bus_dma_scale_table,
+ .current_bus_idx = 0,
+ .handle = 0,
+ },
+ [MDP3_BUS_HANDLE_PPP] = {
+ .bus_vector = mdp_bus_ppp_vectors,
+ .usecases = mdp_bus_ppp_usecases,
+ .scale_pdata = &mdp_bus_ppp_scale_table,
+ .current_bus_idx = 0,
+ .handle = 0,
+ },
+};
+
struct mdp3_iommu_domain_map mdp3_iommu_domains[MDP3_IOMMU_DOMAIN_MAX] = {
[MDP3_IOMMU_DOMAIN] = {
.domain_type = MDP3_IOMMU_DOMAIN,
@@ -213,71 +253,106 @@
static int mdp3_bus_scale_register(void)
{
+ int i;
+
if (!mdp3_res->bus_handle) {
- struct msm_bus_scale_pdata *bus_pdata = &mdp_bus_scale_table;
- int i;
+ pr_err("No bus handle\n");
+ return -EINVAL;
+ }
+ for (i = 0; i < MDP3_BUS_HANDLE_MAX; i++) {
+ struct mdp3_bus_handle_map *bus_handle =
+ &mdp3_res->bus_handle[i];
- for (i = 0; i < bus_pdata->num_usecases; i++) {
- mdp_bus_usecases[i].num_paths = 1;
- mdp_bus_usecases[i].vectors = &mdp_bus_vectors[i];
- }
+ if (!bus_handle->handle) {
+ int j;
+ struct msm_bus_scale_pdata *bus_pdata =
+ bus_handle->scale_pdata;
- mdp3_res->bus_handle = msm_bus_scale_register_client(bus_pdata);
- if (!mdp3_res->bus_handle) {
- pr_err("not able to get bus scale\n");
- return -ENOMEM;
+ for (j = 0; j < bus_pdata->num_usecases; j++) {
+ bus_handle->usecases[j].num_paths = 1;
+ bus_handle->usecases[j].vectors =
+ &bus_handle->bus_vector[j];
+ }
+
+ bus_handle->handle =
+ msm_bus_scale_register_client(bus_pdata);
+ if (!bus_handle->handle) {
+ pr_err("not able to get bus scale i=%d\n", i);
+ return -ENOMEM;
+ }
+ pr_debug("register bus_hdl=%x\n",
+ bus_handle->handle);
}
- pr_debug("register bus_hdl=%x\n", mdp3_res->bus_handle);
}
return 0;
}
static void mdp3_bus_scale_unregister(void)
{
- pr_debug("unregister bus_handle=%x\n", mdp3_res->bus_handle);
-
- if (mdp3_res->bus_handle)
- msm_bus_scale_unregister_client(mdp3_res->bus_handle);
+ int i;
+ for (i = 0; i < MDP3_BUS_HANDLE_MAX; i++) {
+ pr_debug("unregister index=%d bus_handle=%x\n",
+ i, mdp3_res->bus_handle[i].handle);
+ if (mdp3_res->bus_handle[i].handle) {
+ msm_bus_scale_unregister_client(
+ mdp3_res->bus_handle[i].handle);
+ mdp3_res->bus_handle[i].handle = 0;
+ }
+ }
}
int mdp3_bus_scale_set_quota(int client, u64 ab_quota, u64 ib_quota)
{
- static int current_bus_idx;
+ struct mdp3_bus_handle_map *bus_handle;
+ int cur_bus_idx;
int bus_idx;
+ int client_idx;
int rc;
- if (mdp3_res->bus_handle < 1) {
- pr_err("invalid bus handle %d\n", mdp3_res->bus_handle);
+ if (client == MDP3_CLIENT_DMA_P) {
+ client_idx = MDP3_BUS_HANDLE_DMA;
+ } else if (client == MDP3_CLIENT_PPP) {
+ client_idx = MDP3_BUS_HANDLE_PPP;
+ } else {
+ pr_err("invalid client %d\n", client);
+ return -EINVAL;
+ }
+
+ bus_handle = &mdp3_res->bus_handle[client_idx];
+ cur_bus_idx = bus_handle->current_bus_idx;
+
+ if (bus_handle->handle < 1) {
+ pr_err("invalid bus handle %d\n", bus_handle->handle);
return -EINVAL;
}
if ((ab_quota | ib_quota) == 0) {
bus_idx = 0;
} else {
- int num_cases = mdp_bus_scale_table.num_usecases;
+ int num_cases = bus_handle->scale_pdata->num_usecases;
struct msm_bus_vectors *vect = NULL;
- bus_idx = (current_bus_idx % (num_cases - 1)) + 1;
+ bus_idx = (cur_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;
+ vect = bus_handle->scale_pdata->usecase[cur_bus_idx].vectors;
if ((ab_quota == vect->ab) && (ib_quota == vect->ib)) {
pr_debug("skip bus scaling, no change in vectors\n");
return 0;
}
- vect = mdp_bus_scale_table.usecase[bus_idx].vectors;
+ vect = bus_handle->scale_pdata->usecase[bus_idx].vectors;
vect->ab = ab_quota;
vect->ib = ib_quota;
pr_debug("bus scale idx=%d ab=%llu ib=%llu\n", bus_idx,
vect->ab, vect->ib);
}
- current_bus_idx = bus_idx;
- rc = msm_bus_scale_client_update_request(mdp3_res->bus_handle, bus_idx);
+ bus_handle->current_bus_idx = bus_idx;
+ rc = msm_bus_scale_client_update_request(bus_handle->handle, bus_idx);
return rc;
}
@@ -298,7 +373,7 @@
mdp3_res->clock_ref_count[clk_idx]--;
count = mdp3_res->clock_ref_count[clk_idx];
- if (count == 1) {
+ if (count == 1 && enable) {
pr_debug("clk=%d en=%d\n", clk_idx, enable);
ret = clk_prepare_enable(clk);
} else if (count == 0) {
@@ -655,6 +730,7 @@
pr_err("fail to attach DMA-P context 0\n");
return rc;
}
+ mdp3_res->bus_handle = mdp3_bus_handle;
rc = mdp3_bus_scale_register();
if (rc) {
pr_err("unable to register bus scaling\n");
@@ -800,9 +876,28 @@
return ret;
}
+int mdp3_ppp_iommu_attach(void)
+{
+ int rc;
+ rc = mdp3_iommu_attach(MDP3_IOMMU_CTX_PPP_0);
+ rc |= mdp3_iommu_attach(MDP3_IOMMU_CTX_PPP_1);
+ return rc;
+}
+
+int mdp3_ppp_iommu_dettach(void)
+{
+ int rc;
+ rc = mdp3_iommu_dettach(MDP3_IOMMU_CTX_PPP_0);
+ rc = mdp3_iommu_dettach(MDP3_IOMMU_CTX_PPP_1);
+ return rc;
+}
+
static int mdp3_init(struct msm_fb_data_type *mfd)
{
- return mdp3_ctrl_init(mfd);
+ int rc;
+ rc = mdp3_ctrl_init(mfd);
+ rc |= mdp3_ppp_res_init();
+ return rc;
}
u32 mdp3_fb_stride(u32 fb_index, u32 xres, int bpp)
diff --git a/drivers/video/msm/mdss/mdp3.h b/drivers/video/msm/mdss/mdp3.h
index 7e395e1..878fe25 100644
--- a/drivers/video/msm/mdss/mdp3.h
+++ b/drivers/video/msm/mdss/mdp3.h
@@ -35,6 +35,12 @@
};
enum {
+ MDP3_BUS_HANDLE_DMA,
+ MDP3_BUS_HANDLE_PPP,
+ MDP3_BUS_HANDLE_MAX,
+};
+
+enum {
MDP3_IOMMU_DOMAIN,
MDP3_IOMMU_DOMAIN_MAX
};
@@ -48,10 +54,16 @@
};
enum {
- MDP3_BW_CLIENT_DMA_P,
- MDP3_BW_CLIENT_DMA_S,
- MDP3_BW_CLIENT_DMA_E,
- MDP3_BW_CLIENT_PPP,
+ MDP3_CLIENT_DMA_P,
+ MDP3_CLIENT_PPP,
+};
+
+struct mdp3_bus_handle_map {
+ struct msm_bus_vectors *bus_vector;
+ struct msm_bus_paths *usecases;
+ struct msm_bus_scale_pdata *scale_pdata;
+ int current_bus_idx;
+ u32 handle;
};
struct mdp3_iommu_domain_map {
@@ -86,12 +98,14 @@
struct clk *clocks[MDP3_MAX_CLK];
int clock_ref_count[MDP3_MAX_CLK];
+ unsigned long dma_core_clk_request;
+ unsigned long ppp_core_clk_request;
char __iomem *mdp_base;
size_t mdp_reg_size;
u32 irq;
- u32 bus_handle;
+ struct mdp3_bus_handle_map *bus_handle;
struct ion_client *ion_client;
struct mdp3_iommu_domain_map *domains;
@@ -130,6 +144,8 @@
int mdp3_bus_scale_set_quota(int client, u64 ab_quota, u64 ib_quota);
int mdp3_put_img(struct mdp3_img_data *data);
int mdp3_get_img(struct msmfb_data *img, struct mdp3_img_data *data);
+int mdp3_ppp_iommu_attach(void);
+int mdp3_ppp_iommu_dettach(void);
#define MDP3_REG_WRITE(addr, val) writel_relaxed(val, mdp3_res->mdp_base + addr)
#define MDP3_REG_READ(addr) readl_relaxed(mdp3_res->mdp_base + addr)
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.c b/drivers/video/msm/mdss/mdp3_ctrl.c
index f5ac5e9..3d990c2 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.c
+++ b/drivers/video/msm/mdss/mdp3_ctrl.c
@@ -22,6 +22,7 @@
#include "mdp3_ctrl.h"
#include "mdp3.h"
+#include "mdp3_ppp.h"
#define MDP_VSYNC_CLK_RATE 19200000
#define VSYNC_PERIOD 16
@@ -127,6 +128,53 @@
return 0;
}
+static int mdp3_ctrl_blit_req(struct msm_fb_data_type *mfd, void __user *p)
+{
+ const int MAX_LIST_WINDOW = 16;
+ struct mdp_blit_req req_list[MAX_LIST_WINDOW];
+ struct mdp_blit_req_list req_list_header;
+ int rc, count, i, req_list_count;
+
+ if (copy_from_user(&req_list_header, p, sizeof(req_list_header)))
+ return -EFAULT;
+ p += sizeof(req_list_header);
+ count = req_list_header.count;
+ if (count < 0 || count >= MAX_BLIT_REQ)
+ return -EINVAL;
+ while (count > 0) {
+ /*
+ * Access the requests through a narrow window to decrease copy
+ * overhead and make larger requests accessible to the
+ * coherency management code.
+ * NOTE: The window size is intended to be larger than the
+ * typical request size, but not require more than 2
+ * kbytes of stack storage.
+ */
+ req_list_count = count;
+ if (req_list_count > MAX_LIST_WINDOW)
+ req_list_count = MAX_LIST_WINDOW;
+ if (copy_from_user(&req_list, p,
+ sizeof(struct mdp_blit_req)*req_list_count))
+ return -EFAULT;
+ /*
+ * Do the blit DMA, if required -- returning early only if
+ * there is a failure.
+ */
+ for (i = 0; i < req_list_count; i++) {
+ if (!(req_list[i].flags & MDP_NO_BLIT)) {
+ /* Do the actual blit. */
+ rc = mdp3_ppp_start_blit(mfd, &(req_list[i]));
+ if (rc)
+ return rc;
+ }
+ }
+
+ /* Go to next window of requests. */
+ count -= req_list_count;
+ p += sizeof(struct mdp_blit_req)*req_list_count;
+ }
+ return 0;
+}
static ssize_t mdp3_vsync_show_event(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -181,9 +229,9 @@
ab = panel_info->xres * panel_info->yres * 4;
ab *= panel_info->mipi.frame_rate;
ib = (ab * 3) / 2;
- rc = mdp3_bus_scale_set_quota(MDP3_BW_CLIENT_DMA_P, ab, ib);
+ rc = mdp3_bus_scale_set_quota(MDP3_CLIENT_DMA_P, ab, ib);
} else {
- rc = mdp3_bus_scale_set_quota(MDP3_BW_CLIENT_DMA_P, 0, 0);
+ rc = mdp3_bus_scale_set_quota(MDP3_CLIENT_DMA_P, 0, 0);
}
return rc;
}
@@ -394,6 +442,12 @@
goto on_error;
}
+ rc = mdp3_ppp_init();
+ if (rc) {
+ pr_err("ppp init failed\n");
+ goto on_error;
+ }
+
rc = mdp3_ctrl_intf_init(mfd, mdp3_session->intf);
if (rc) {
pr_err("display interface init failed\n");
@@ -701,6 +755,9 @@
rc = -EFAULT;
}
break;
+ case MSMFB_BLIT:
+ rc = mdp3_ctrl_blit_req(mfd, argp);
+ break;
case MSMFB_METADATA_GET:
rc = copy_from_user(&metadata, argp, sizeof(metadata));
if (rc)
diff --git a/drivers/video/msm/mdss/mdp3_hwio.h b/drivers/video/msm/mdss/mdp3_hwio.h
index 2763f46..1c5bf46 100644
--- a/drivers/video/msm/mdss/mdp3_hwio.h
+++ b/drivers/video/msm/mdss/mdp3_hwio.h
@@ -148,6 +148,70 @@
#define MDP3_REG_DSI_CMD_MODE_ID_MAP 0xF1000
#define MDP3_REG_DSI_CMD_MODE_TRIGGER_EN 0xF1004
+#define MDP3_PPP_CSC_PFMVn(n) (0x40400 + (4 * (n)))
+#define MDP3_PPP_CSC_PRMVn(n) (0x40440 + (4 * (n)))
+#define MDP3_PPP_CSC_PBVn(n) (0x40500 + (4 * (n)))
+#define MDP3_PPP_CSC_PLVn(n) (0x40580 + (4 * (n)))
+
+#define MDP3_PPP_CSC_SFMVn(n) (0x40480 + (4 * (n)))
+#define MDP3_PPP_CSC_SRMVn(n) (0x404C0 + (4 * (n)))
+#define MDP3_PPP_CSC_SBVn(n) (0x40540 + (4 * (n)))
+#define MDP3_PPP_CSC_SLVn(n) (0x405C0 + (4 * (n)))
+
+#define MDP3_PPP_SCALE_PHASEX_INIT 0x1013C
+#define MDP3_PPP_SCALE_PHASEY_INIT 0x10140
+#define MDP3_PPP_SCALE_PHASEX_STEP 0x10144
+#define MDP3_PPP_SCALE_PHASEY_STEP 0x10148
+
+#define MDP3_PPP_OP_MODE 0x10138
+
+#define MDP3_PPP_PRE_LUT 0x40800
+#define MDP3_PPP_POST_LUT 0x40C00
+#define MDP3_PPP_LUTn(n) ((4 * (n)))
+
+#define MDP3_PPP_BG_EDGE_REP 0x101BC
+#define MDP3_PPP_SRC_EDGE_REP 0x101B8
+
+#define MDP3_PPP_STRIDE_MASK 0x3FFF
+#define MDP3_PPP_STRIDE1_OFFSET 16
+
+#define MDP3_PPP_XY_MASK 0x0FFF
+#define MDP3_PPP_XY_OFFSET 16
+
+#define MDP3_PPP_SRC_SIZE 0x10108
+#define MDP3_PPP_SRCP0_ADDR 0x1010C
+#define MDP3_PPP_SRCP1_ADDR 0x10110
+#define MDP3_PPP_SRCP3_ADDR 0x10118
+#define MDP3_PPP_SRC_YSTRIDE1_ADDR 0x1011C
+#define MDP3_PPP_SRC_YSTRIDE2_ADDR 0x10120
+#define MDP3_PPP_SRC_FORMAT 0x10124
+#define MDP3_PPP_SRC_UNPACK_PATTERN1 0x10128
+#define MDP3_PPP_SRC_UNPACK_PATTERN2 0x1012C
+
+#define MDP3_PPP_OUT_FORMAT 0x10150
+#define MDP3_PPP_OUT_PACK_PATTERN1 0x10154
+#define MDP3_PPP_OUT_PACK_PATTERN2 0x10158
+#define MDP3_PPP_OUT_SIZE 0x10164
+#define MDP3_PPP_OUTP0_ADDR 0x10168
+#define MDP3_PPP_OUTP1_ADDR 0x1016C
+#define MDP3_PPP_OUTP3_ADDR 0x10174
+#define MDP3_PPP_OUT_YSTRIDE1_ADDR 0x10178
+#define MDP3_PPP_OUT_YSTRIDE2_ADDR 0x1017C
+#define MDP3_PPP_OUT_XY 0x1019C
+
+#define MDP3_PPP_BGP0_ADDR 0x101C0
+#define MDP3_PPP_BGP1_ADDR 0x101C4
+#define MDP3_PPP_BGP3_ADDR 0x101C8
+#define MDP3_PPP_BG_YSTRIDE1_ADDR 0x101CC
+#define MDP3_PPP_BG_YSTRIDE2_ADDR 0x101D0
+#define MDP3_PPP_BG_FORMAT 0x101D4
+#define MDP3_PPP_BG_UNPACK_PATTERN1 0x101D8
+#define MDP3_PPP_BG_UNPACK_PATTERN2 0x101DC
+
+#define MDP3_PPP_BLEND_PARAM 0x1014C
+
+#define MDP3_PPP_BLEND_BG_ALPHA_SEL 0x70010
+
/*interrupt mask*/
#define MDP3_INTR_DP0_ROI_DONE_BIT BIT(0)
@@ -212,5 +276,6 @@
#define MDP3_DMA_P_HIST_INTR_RESET_DONE_BIT BIT(0)
#define MDP3_DMA_P_HIST_INTR_HIST_DONE_BIT BIT(1)
+#define MDP3_PPP_DONE MDP3_INTR_DP0_ROI_DONE
#endif /* MDP3_HWIO_H */
diff --git a/drivers/video/msm/mdss/mdp3_ppp.c b/drivers/video/msm/mdss/mdp3_ppp.c
new file mode 100644
index 0000000..7164086
--- /dev/null
+++ b/drivers/video/msm/mdss/mdp3_ppp.c
@@ -0,0 +1,760 @@
+/* Copyright (c) 2007, 2013 The Linux Foundation. All rights reserved.
+ * Copyright (C) 2007 Google Incorporated
+ *
+ * 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/file.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+#include <linux/mutex.h>
+#include "linux/proc_fs.h"
+
+#include "mdss_fb.h"
+#include "mdp3_ppp.h"
+#include "mdp3_hwio.h"
+#include "mdp3.h"
+
+#define MDP_IS_IMGTYPE_BAD(x) ((x) >= MDP_IMGTYPE_LIMIT)
+
+static const bool valid_fmt[MDP_IMGTYPE_LIMIT] = {
+ [MDP_RGB_565] = true,
+ [MDP_BGR_565] = true,
+ [MDP_RGB_888] = true,
+ [MDP_BGR_888] = true,
+ [MDP_BGRA_8888] = true,
+ [MDP_RGBA_8888] = true,
+ [MDP_ARGB_8888] = true,
+ [MDP_XRGB_8888] = true,
+ [MDP_RGBX_8888] = true,
+ [MDP_Y_CRCB_H2V2] = true,
+ [MDP_Y_CBCR_H2V2] = true,
+ [MDP_Y_CBCR_H2V2_ADRENO] = true,
+ [MDP_YCRYCB_H2V1] = true,
+ [MDP_Y_CBCR_H2V1] = true,
+ [MDP_Y_CRCB_H2V1] = true,
+};
+
+struct ppp_status {
+ int busy;
+ spinlock_t ppp_lock;
+ struct completion ppp_comp;
+ struct mutex config_mutex;
+};
+
+static struct ppp_status *ppp_stat;
+
+
+int ppp_get_bpp(uint32_t format, uint32_t fb_format)
+{
+ int bpp = -EINVAL;
+ if (format == MDP_FB_FORMAT)
+ format = fb_format;
+
+ bpp = ppp_bpp(format);
+ if (bpp <= 0)
+ pr_err("%s incorrect format %d\n", __func__, format);
+ return bpp;
+}
+
+int mdp3_ppp_get_img(struct mdp_img *img, struct mdp_blit_req *req,
+ struct mdp3_img_data *data)
+{
+ struct msmfb_data fb_data;
+ fb_data.flags = img->priv;
+ fb_data.memory_id = img->memory_id;
+ fb_data.offset = 0;
+
+ return mdp3_get_img(&fb_data, data);
+}
+
+/* Check format */
+int mdp3_ppp_verify_fmt(struct mdp_blit_req *req)
+{
+ if (MDP_IS_IMGTYPE_BAD(req->src.format) ||
+ MDP_IS_IMGTYPE_BAD(req->dst.format)) {
+ pr_err("%s: Color format out of range\n", __func__);
+ return -EINVAL;
+ }
+
+ if (!valid_fmt[req->src.format] ||
+ !valid_fmt[req->dst.format]) {
+ pr_err("%s: Color format not supported\n", __func__);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/* Check resolution */
+int mdp3_ppp_verify_res(struct mdp_blit_req *req)
+{
+ if ((req->src.width == 0) || (req->src.height == 0) ||
+ (req->src_rect.w == 0) || (req->src_rect.h == 0) ||
+ (req->dst.width == 0) || (req->dst.height == 0) ||
+ (req->dst_rect.w == 0) || (req->dst_rect.h == 0)) {
+ pr_err("%s: Height/width can't be 0\n", __func__);
+ return -EINVAL;
+ }
+
+ if (((req->src_rect.x + req->src_rect.w) > req->src.width) ||
+ ((req->src_rect.y + req->src_rect.h) > req->src.height)) {
+ pr_err("%s: src roi larger than boundary\n", __func__);
+ return -EINVAL;
+ }
+
+ if (((req->dst_rect.x + req->dst_rect.w) > req->dst.width) ||
+ ((req->dst_rect.y + req->dst_rect.h) > req->dst.height)) {
+ pr_err("%s: dst roi larger than boundary\n", __func__);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/* scaling range check */
+int mdp3_ppp_verify_scale(struct mdp_blit_req *req)
+{
+ u32 src_width, src_height, dst_width, dst_height;
+
+ src_width = req->src_rect.w;
+ src_height = req->src_rect.h;
+
+ if (req->flags & MDP_ROT_90) {
+ dst_width = req->dst_rect.h;
+ dst_height = req->dst_rect.w;
+ } else {
+ dst_width = req->dst_rect.w;
+ dst_height = req->dst_rect.h;
+ }
+
+ switch (req->dst.format) {
+ case MDP_Y_CRCB_H2V2:
+ case MDP_Y_CBCR_H2V2:
+ src_width = (src_width / 2) * 2;
+ src_height = (src_height / 2) * 2;
+ dst_width = (dst_width / 2) * 2;
+ dst_height = (dst_height / 2) * 2;
+ break;
+
+ case MDP_Y_CRCB_H2V1:
+ case MDP_Y_CBCR_H2V1:
+ case MDP_YCRYCB_H2V1:
+ src_width = (src_width / 2) * 2;
+ dst_width = (dst_width / 2) * 2;
+ break;
+
+ default:
+ break;
+ }
+
+ if (((MDP_SCALE_Q_FACTOR * dst_width) / src_width >
+ MDP_MAX_X_SCALE_FACTOR)
+ || ((MDP_SCALE_Q_FACTOR * dst_width) / src_width <
+ MDP_MIN_X_SCALE_FACTOR)) {
+ pr_err("%s: x req scale factor beyond capability\n", __func__);
+ return -EINVAL;
+ }
+
+ if (((MDP_SCALE_Q_FACTOR * dst_height) / src_height >
+ MDP_MAX_Y_SCALE_FACTOR)
+ || ((MDP_SCALE_Q_FACTOR * dst_height) / src_height <
+ MDP_MIN_Y_SCALE_FACTOR)) {
+ pr_err("%s: y req scale factor beyond capability\n", __func__);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/* operation check */
+int mdp3_ppp_verify_op(struct mdp_blit_req *req)
+{
+ if (req->flags & MDP_DEINTERLACE) {
+ pr_err("\n%s(): deinterlace not supported", __func__);
+ return -EINVAL;
+ }
+
+ if (req->flags & MDP_SHARPENING) {
+ pr_err("\n%s(): sharpening not supported", __func__);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+int mdp3_ppp_verify_req(struct mdp_blit_req *req)
+{
+ int rc;
+
+ if (req == NULL) {
+ pr_err("%s: req == null\n", __func__);
+ return -EINVAL;
+ }
+
+ rc = mdp3_ppp_verify_fmt(req);
+ rc |= mdp3_ppp_verify_res(req);
+ rc |= mdp3_ppp_verify_scale(req);
+ rc |= mdp3_ppp_verify_op(req);
+
+ return rc;
+}
+
+int mdp3_ppp_pipe_wait(void)
+{
+ int ret = 1;
+ int wait;
+ unsigned long flag;
+
+ /*
+ * wait 5 secs for operation to complete before declaring
+ * the MDP hung
+ */
+ spin_lock_irqsave(&ppp_stat->ppp_lock, flag);
+ wait = ppp_stat->busy;
+ spin_unlock_irqrestore(&ppp_stat->ppp_lock, flag);
+
+ if (wait) {
+ ret = wait_for_completion_interruptible_timeout(
+ &ppp_stat->ppp_comp, 5 * HZ);
+ if (!ret)
+ pr_err("%s: Timed out waiting for the MDP.\n",
+ __func__);
+ }
+
+ return ret;
+}
+
+uint32_t mdp3_calc_tpval(struct ppp_img_desc *img, uint32_t old_tp)
+{
+ uint32_t tpVal;
+ uint8_t plane_tp;
+
+ tpVal = 0;
+ if ((img->color_fmt == MDP_RGB_565)
+ || (img->color_fmt == MDP_BGR_565)) {
+ /* transparent color conversion into 24 bpp */
+ plane_tp = (uint8_t) ((old_tp & 0xF800) >> 11);
+ tpVal |= ((plane_tp << 3) | ((plane_tp & 0x1C) >> 2)) << 16;
+ plane_tp = (uint8_t) (old_tp & 0x1F);
+ tpVal |= ((plane_tp << 3) | ((plane_tp & 0x1C) >> 2)) << 8;
+
+ plane_tp = (uint8_t) ((old_tp & 0x7E0) >> 5);
+ tpVal |= ((plane_tp << 2) | ((plane_tp & 0x30) >> 4));
+ } else {
+ /* 24bit RGB to RBG conversion */
+ tpVal = (old_tp & 0xFF00) >> 8;
+ tpVal |= (old_tp & 0xFF) << 8;
+ tpVal |= (old_tp & 0xFF0000);
+ }
+
+ return tpVal;
+}
+
+static void mdp3_ppp_intr_handler(int type, void *arg)
+{
+ spin_lock(&ppp_stat->ppp_lock);
+ ppp_stat->busy = false;
+ spin_unlock(&ppp_stat->ppp_lock);
+ complete(&ppp_stat->ppp_comp);
+ mdp3_irq_disable_nosync(type);
+}
+
+static int mdp3_ppp_callback_setup(void)
+{
+ int rc;
+ struct mdp3_intr_cb ppp_done_cb = {
+ .cb = mdp3_ppp_intr_handler,
+ .data = NULL,
+ };
+
+ rc = mdp3_set_intr_callback(MDP3_PPP_DONE, &ppp_done_cb);
+ return rc;
+}
+
+void mdp3_ppp_kickoff(void)
+{
+ unsigned long flag;
+ mdp3_irq_enable(MDP3_PPP_DONE);
+
+ init_completion(&ppp_stat->ppp_comp);
+
+ spin_lock_irqsave(&ppp_stat->ppp_lock, flag);
+ ppp_stat->busy = true;
+ spin_unlock_irqrestore(&ppp_stat->ppp_lock, flag);
+ ppp_enable();
+
+ mdp3_ppp_pipe_wait();
+}
+
+int mdp3_ppp_turnon(struct ppp_blit_op *blit_op, int on_off)
+{
+ unsigned long clk_rate = 0, dst_rate = 0, src_rate = 0;
+ int ab = 0;
+ int ib = 0;
+ if (on_off) {
+ dst_rate = blit_op->dst.roi.width * blit_op->dst.roi.height;
+ src_rate = blit_op->src.roi.width * blit_op->src.roi.height;
+ clk_rate = max(dst_rate, src_rate);
+ clk_rate = clk_rate * 36 * 12;
+
+ ab = blit_op->dst.roi.width * blit_op->dst.roi.height *
+ ppp_bpp(blit_op->dst.color_fmt) * 2 +
+ blit_op->src.roi.width * blit_op->src.roi.height *
+ ppp_bpp(blit_op->src.color_fmt);
+ ab = ab * 120;
+ ib = (ab * 3) / 2;
+ }
+ mdp3_clk_enable(on_off);
+ mdp3_bus_scale_set_quota(MDP3_CLIENT_PPP, ab, ib);
+ return 0;
+}
+
+void mdp3_start_ppp(struct ppp_blit_op *blit_op)
+{
+ /* Wait for the pipe to clear */
+ do { } while (mdp3_ppp_pipe_wait() <= 0);
+ mutex_lock(&ppp_stat->config_mutex);
+ config_ppp_op_mode(blit_op);
+ mdp3_ppp_kickoff();
+ mutex_unlock(&ppp_stat->config_mutex);
+}
+
+static void mdp3_ppp_process_req(struct ppp_blit_op *blit_op,
+ struct mdp_blit_req *req, struct mdp3_img_data *src_data,
+ struct mdp3_img_data *dst_data)
+{
+ unsigned long srcp0_start, srcp0_len, dst_start, dst_len;
+ uint32_t dst_width, dst_height;
+
+ srcp0_start = (unsigned long) src_data->addr;
+ srcp0_len = (unsigned long) src_data->len;
+ dst_start = (unsigned long) dst_data->addr;
+ dst_len = (unsigned long) dst_data->len;
+
+ blit_op->dst.prop.width = req->dst.width;
+ blit_op->dst.prop.height = req->dst.height;
+
+ blit_op->dst.color_fmt = req->dst.format;
+ blit_op->dst.p0 = (void *) dst_start;
+ blit_op->dst.p0 += req->dst.offset;
+
+ blit_op->dst.roi.x = req->dst_rect.x;
+ blit_op->dst.roi.y = req->dst_rect.y;
+ blit_op->dst.roi.width = req->dst_rect.w;
+ blit_op->dst.roi.height = req->dst_rect.h;
+
+ blit_op->src.roi.x = req->src_rect.x;
+ blit_op->src.roi.y = req->src_rect.y;
+ blit_op->src.roi.width = req->src_rect.w;
+ blit_op->src.roi.height = req->src_rect.h;
+
+ blit_op->src.prop.width = req->src.width;
+ blit_op->src.color_fmt = req->src.format;
+
+
+ blit_op->src.p0 = (void *) (srcp0_start + req->src.offset);
+ if (blit_op->src.color_fmt == MDP_Y_CBCR_H2V2_ADRENO)
+ blit_op->src.p1 =
+ (void *) ((uint32_t) blit_op->src.p0 +
+ ALIGN((ALIGN(req->src.width, 32) *
+ ALIGN(req->src.height, 32)), 4096));
+ else
+ blit_op->src.p1 = (void *) ((uint32_t) blit_op->src.p0 +
+ req->src.width * req->src.height);
+
+ if (req->flags & MDP_IS_FG)
+ blit_op->mdp_op |= MDPOP_LAYER_IS_FG;
+
+ /* blending check */
+ if (req->transp_mask != MDP_TRANSP_NOP) {
+ blit_op->mdp_op |= MDPOP_TRANSP;
+ blit_op->blend.trans_color =
+ mdp3_calc_tpval(&blit_op->src, req->transp_mask);
+ } else {
+ blit_op->blend.trans_color = 0;
+ }
+
+ req->alpha &= 0xff;
+ if (req->alpha < MDP_ALPHA_NOP) {
+ blit_op->mdp_op |= MDPOP_ALPHAB;
+ blit_op->blend.const_alpha = req->alpha;
+ } else {
+ blit_op->blend.const_alpha = 0xff;
+ }
+
+ /* rotation check */
+ if (req->flags & MDP_FLIP_LR)
+ blit_op->mdp_op |= MDPOP_LR;
+ if (req->flags & MDP_FLIP_UD)
+ blit_op->mdp_op |= MDPOP_UD;
+ if (req->flags & MDP_ROT_90)
+ blit_op->mdp_op |= MDPOP_ROT90;
+ if (req->flags & MDP_DITHER)
+ blit_op->mdp_op |= MDPOP_DITHER;
+
+ if (req->flags & MDP_BLEND_FG_PREMULT)
+ blit_op->mdp_op |= MDPOP_FG_PM_ALPHA;
+
+ /* scale check */
+ if (req->flags & MDP_ROT_90) {
+ dst_width = req->dst_rect.h;
+ dst_height = req->dst_rect.w;
+ } else {
+ dst_width = req->dst_rect.w;
+ dst_height = req->dst_rect.h;
+ }
+
+ if ((blit_op->src.roi.width != dst_width) ||
+ (blit_op->src.roi.height != dst_height))
+ blit_op->mdp_op |= MDPOP_ASCALE;
+
+ if (req->flags & MDP_BLUR)
+ blit_op->mdp_op |= MDPOP_ASCALE | MDPOP_BLUR;
+}
+
+static void mdp3_ppp_tile_workaround(struct ppp_blit_op *blit_op,
+ struct mdp_blit_req *req)
+{
+ int dst_h, src_w, i;
+ uint32_t mdp_op = blit_op->mdp_op;
+
+ src_w = req->src_rect.w;
+ dst_h = blit_op->dst.roi.height;
+ /* bg tile fetching HW workaround */
+ for (i = 0; i < (req->dst_rect.h / 16); i++) {
+ /* this tile size */
+ blit_op->dst.roi.height = 16;
+ blit_op->src.roi.width =
+ (16 * req->src_rect.w) / req->dst_rect.h;
+
+ /* if it's out of scale range... */
+ if (((MDP_SCALE_Q_FACTOR * blit_op->dst.roi.height) /
+ blit_op->src.roi.width) > MDP_MAX_X_SCALE_FACTOR)
+ blit_op->src.roi.width =
+ (MDP_SCALE_Q_FACTOR * blit_op->dst.roi.height) /
+ MDP_MAX_X_SCALE_FACTOR;
+ else if (((MDP_SCALE_Q_FACTOR * blit_op->dst.roi.height) /
+ blit_op->src.roi.width) < MDP_MIN_X_SCALE_FACTOR)
+ blit_op->src.roi.width =
+ (MDP_SCALE_Q_FACTOR * blit_op->dst.roi.height) /
+ MDP_MIN_X_SCALE_FACTOR;
+
+ mdp3_start_ppp(blit_op);
+
+ /* next tile location */
+ blit_op->dst.roi.y += 16;
+ blit_op->src.roi.x += blit_op->src.roi.width;
+
+ /* this is for a remainder update */
+ dst_h -= 16;
+ src_w -= blit_op->src.roi.width;
+ /* restore mdp_op since MDPOP_ASCALE have been cleared */
+ blit_op->mdp_op = mdp_op;
+ }
+
+ if ((dst_h < 0) || (src_w < 0))
+ pr_err
+ ("msm_fb: mdp_blt_ex() unexpected result! line:%d\n",
+ __LINE__);
+
+ /* remainder update */
+ if ((dst_h > 0) && (src_w > 0)) {
+ u32 tmp_v;
+
+ blit_op->dst.roi.height = dst_h;
+ blit_op->src.roi.width = src_w;
+
+ if (((MDP_SCALE_Q_FACTOR * blit_op->dst.roi.height) /
+ blit_op->src.roi.width) > MDP_MAX_X_SCALE_FACTOR) {
+ tmp_v =
+ (MDP_SCALE_Q_FACTOR * blit_op->dst.roi.height) /
+ MDP_MAX_X_SCALE_FACTOR +
+ (MDP_SCALE_Q_FACTOR * blit_op->dst.roi.height) %
+ MDP_MAX_X_SCALE_FACTOR ? 1 : 0;
+
+ /* move x location as roi width gets bigger */
+ blit_op->src.roi.x -= tmp_v - blit_op->src.roi.width;
+ blit_op->src.roi.width = tmp_v;
+ } else if (((MDP_SCALE_Q_FACTOR * blit_op->dst.roi.height) /
+ blit_op->src.roi.width) < MDP_MIN_X_SCALE_FACTOR) {
+ tmp_v =
+ (MDP_SCALE_Q_FACTOR * blit_op->dst.roi.height) /
+ MDP_MIN_X_SCALE_FACTOR +
+ (MDP_SCALE_Q_FACTOR * blit_op->dst.roi.height) %
+ MDP_MIN_X_SCALE_FACTOR ? 1 : 0;
+
+ /*
+ * we don't move x location for continuity of
+ * source image
+ */
+ blit_op->src.roi.width = tmp_v;
+ }
+
+
+ mdp3_start_ppp(blit_op);
+ }
+}
+
+static int mdp3_ppp_blit_addr(struct msm_fb_data_type *mfd,
+ struct mdp_blit_req *req, struct mdp3_img_data *src_data,
+ struct mdp3_img_data *dst_data)
+{
+ struct ppp_blit_op blit_op;
+
+ memset(&blit_op, 0, sizeof(blit_op));
+
+ if (req->dst.format == MDP_FB_FORMAT)
+ req->dst.format = mfd->fb_imgType;
+ if (req->src.format == MDP_FB_FORMAT)
+ req->src.format = mfd->fb_imgType;
+
+ if (mdp3_ppp_verify_req(req)) {
+ pr_err("%s: invalid image!\n", __func__);
+ return -EINVAL;
+ }
+
+ mdp3_ppp_process_req(&blit_op, req, src_data, dst_data);
+
+ mdp3_ppp_turnon(&blit_op, 1);
+
+ if (((blit_op.mdp_op & (MDPOP_TRANSP | MDPOP_ALPHAB)) ||
+ (req->src.format == MDP_ARGB_8888) ||
+ (req->src.format == MDP_BGRA_8888) ||
+ (req->src.format == MDP_RGBA_8888)) &&
+ (blit_op.mdp_op & MDPOP_ROT90) && (req->dst_rect.w <= 16)) {
+ mdp3_ppp_tile_workaround(&blit_op, req);
+ } else {
+ mdp3_start_ppp(&blit_op);
+ }
+
+ /* MDP cmd block disable */
+ mdp3_ppp_turnon(&blit_op, 0);
+
+ return 0;
+}
+
+static int mdp3_ppp_blit(struct msm_fb_data_type *mfd, struct mdp_blit_req *req)
+{
+ struct mdp3_img_data src_data;
+ struct mdp3_img_data dst_data;
+ int rc;
+ mdp3_ppp_iommu_attach();
+
+ mdp3_ppp_get_img(&req->src, req, &src_data);
+ if (src_data.len == 0) {
+ pr_err("mdp_ppp: couldn't retrieve src img from mem\n");
+ return -EINVAL;
+ }
+
+ mdp3_ppp_get_img(&req->dst, req, &dst_data);
+ if (dst_data.len == 0) {
+ mdp3_put_img(&src_data);
+ pr_err("mdp_ppp: couldn't retrieve dest img from mem\n");
+ return -EINVAL;
+ }
+
+ rc = mdp3_ppp_blit_addr(mfd, req, &src_data, &dst_data);
+ mdp3_put_img(&src_data);
+ mdp3_put_img(&dst_data);
+ mdp3_ppp_iommu_dettach();
+ return rc;
+}
+
+static int mdp3_ppp_blit_workaround(struct msm_fb_data_type *mfd,
+ struct mdp_blit_req *req, unsigned int remainder)
+{
+ int ret;
+ struct mdp_blit_req splitreq;
+ int s_x_0, s_x_1, s_w_0, s_w_1, s_y_0, s_y_1, s_h_0, s_h_1;
+ int d_x_0, d_x_1, d_w_0, d_w_1, d_y_0, d_y_1, d_h_0, d_h_1;
+
+ /* make new request as provide by user */
+ splitreq = *req;
+
+ /* break dest roi at width*/
+ d_y_0 = d_y_1 = req->dst_rect.y;
+ d_h_0 = d_h_1 = req->dst_rect.h;
+ d_x_0 = req->dst_rect.x;
+
+ if (remainder == 14 || remainder == 6)
+ d_w_1 = req->dst_rect.w / 2;
+ else
+ d_w_1 = (req->dst_rect.w - 1) / 2 - 1;
+
+ d_w_0 = req->dst_rect.w - d_w_1;
+ d_x_1 = d_x_0 + d_w_0;
+ /* blit first region */
+ if (((splitreq.flags & 0x07) == 0x07) ||
+ ((splitreq.flags & 0x07) == 0x05) ||
+ ((splitreq.flags & 0x07) == 0x02) ||
+ ((splitreq.flags & 0x07) == 0x0)) {
+
+ if (splitreq.flags & MDP_ROT_90) {
+ s_x_0 = s_x_1 = req->src_rect.x;
+ s_w_0 = s_w_1 = req->src_rect.w;
+ s_y_0 = req->src_rect.y;
+ s_h_1 = (req->src_rect.h * d_w_1) /
+ req->dst_rect.w;
+ s_h_0 = req->src_rect.h - s_h_1;
+ s_y_1 = s_y_0 + s_h_0;
+ if (d_w_1 >= 8 * s_h_1) {
+ s_h_1++;
+ s_y_1--;
+ }
+ } else {
+ s_y_0 = s_y_1 = req->src_rect.y;
+ s_h_0 = s_h_1 = req->src_rect.h;
+ s_x_0 = req->src_rect.x;
+ s_w_1 = (req->src_rect.w * d_w_1) /
+ req->dst_rect.w;
+ s_w_0 = req->src_rect.w - s_w_1;
+ s_x_1 = s_x_0 + s_w_0;
+ if (d_w_1 >= 8 * s_w_1) {
+ s_w_1++;
+ s_x_1--;
+ }
+ }
+
+ splitreq.src_rect.h = s_h_0;
+ splitreq.src_rect.y = s_y_0;
+ splitreq.dst_rect.h = d_h_0;
+ splitreq.dst_rect.y = d_y_0;
+ splitreq.src_rect.x = s_x_0;
+ splitreq.src_rect.w = s_w_0;
+ splitreq.dst_rect.x = d_x_0;
+ splitreq.dst_rect.w = d_w_0;
+ } else {
+ if (splitreq.flags & MDP_ROT_90) {
+ s_x_0 = s_x_1 = req->src_rect.x;
+ s_w_0 = s_w_1 = req->src_rect.w;
+ s_y_0 = req->src_rect.y;
+ s_h_1 = (req->src_rect.h * d_w_0) /
+ req->dst_rect.w;
+ s_h_0 = req->src_rect.h - s_h_1;
+ s_y_1 = s_y_0 + s_h_0;
+ if (d_w_0 >= 8 * s_h_1) {
+ s_h_1++;
+ s_y_1--;
+ }
+ } else {
+ s_y_0 = s_y_1 = req->src_rect.y;
+ s_h_0 = s_h_1 = req->src_rect.h;
+ s_x_0 = req->src_rect.x;
+ s_w_1 = (req->src_rect.w * d_w_0) /
+ req->dst_rect.w;
+ s_w_0 = req->src_rect.w - s_w_1;
+ s_x_1 = s_x_0 + s_w_0;
+ if (d_w_0 >= 8 * s_w_1) {
+ s_w_1++;
+ s_x_1--;
+ }
+ }
+ splitreq.src_rect.h = s_h_0;
+ splitreq.src_rect.y = s_y_0;
+ splitreq.dst_rect.h = d_h_1;
+ splitreq.dst_rect.y = d_y_1;
+ splitreq.src_rect.x = s_x_0;
+ splitreq.src_rect.w = s_w_0;
+ splitreq.dst_rect.x = d_x_1;
+ splitreq.dst_rect.w = d_w_1;
+ }
+
+ /* No need to split in height */
+ ret = mdp3_ppp_blit(mfd, &splitreq);
+
+ if (ret)
+ return ret;
+ /* blit second region */
+ if (((splitreq.flags & 0x07) == 0x07) ||
+ ((splitreq.flags & 0x07) == 0x05) ||
+ ((splitreq.flags & 0x07) == 0x02) ||
+ ((splitreq.flags & 0x07) == 0x0)) {
+ splitreq.src_rect.h = s_h_1;
+ splitreq.src_rect.y = s_y_1;
+ splitreq.dst_rect.h = d_h_1;
+ splitreq.dst_rect.y = d_y_1;
+ splitreq.src_rect.x = s_x_1;
+ splitreq.src_rect.w = s_w_1;
+ splitreq.dst_rect.x = d_x_1;
+ splitreq.dst_rect.w = d_w_1;
+ } else {
+ splitreq.src_rect.h = s_h_1;
+ splitreq.src_rect.y = s_y_1;
+ splitreq.dst_rect.h = d_h_0;
+ splitreq.dst_rect.y = d_y_0;
+ splitreq.src_rect.x = s_x_1;
+ splitreq.src_rect.w = s_w_1;
+ splitreq.dst_rect.x = d_x_0;
+ splitreq.dst_rect.w = d_w_0;
+ }
+
+ /* No need to split in height ... just width */
+ return mdp3_ppp_blit(mfd, &splitreq);
+}
+
+int mdp3_ppp_start_blit(struct msm_fb_data_type *mfd,
+ struct mdp_blit_req *req)
+{
+ int ret;
+ unsigned int remainder = 0, is_bpp_4 = 0;
+
+ if (unlikely(req->src_rect.h == 0 || req->src_rect.w == 0)) {
+ pr_err("mdp_ppp: src img of zero size!\n");
+ return -EINVAL;
+ }
+ if (unlikely(req->dst_rect.h == 0 || req->dst_rect.w == 0))
+ return 0;
+
+ if (req->flags & MDP_ROT_90) {
+ if (((req->dst_rect.h == 1) && ((req->src_rect.w != 1) ||
+ (req->dst_rect.w != req->src_rect.h))) ||
+ ((req->dst_rect.w == 1) && ((req->src_rect.h != 1) ||
+ (req->dst_rect.h != req->src_rect.w)))) {
+ pr_err("mdp_ppp: error scaling when size is 1!\n");
+ return -EINVAL;
+ }
+ } else {
+ if (((req->dst_rect.w == 1) && ((req->src_rect.w != 1) ||
+ (req->dst_rect.h != req->src_rect.h))) ||
+ ((req->dst_rect.h == 1) && ((req->src_rect.h != 1) ||
+ (req->dst_rect.w != req->src_rect.w)))) {
+ pr_err("mdp_ppp: error scaling when size is 1!\n");
+ return -EINVAL;
+ }
+ }
+
+ /* MDP width split workaround */
+ remainder = (req->dst_rect.w) % 16;
+ ret = ppp_get_bpp(req->dst.format, mfd->fb_imgType);
+ if (ret <= 0) {
+ pr_err("mdp_ppp: incorrect bpp!\n");
+ return -EINVAL;
+ }
+ is_bpp_4 = (ret == 4) ? 1 : 0;
+
+ if ((is_bpp_4 && (remainder == 6 || remainder == 14)))
+ ret = mdp3_ppp_blit_workaround(mfd, req, remainder);
+ else
+ ret = mdp3_ppp_blit(mfd, req);
+
+ return ret;
+}
+
+int mdp3_ppp_res_init(void)
+{
+ ppp_stat = kmalloc(sizeof(struct ppp_status), GFP_KERNEL);
+ spin_lock_init(&ppp_stat->ppp_lock);
+ mutex_init(&ppp_stat->config_mutex);
+ ppp_stat->busy = false;
+ mdp3_ppp_callback_setup();
+ return 0;
+}
diff --git a/drivers/video/msm/mdss/mdp3_ppp.h b/drivers/video/msm/mdss/mdp3_ppp.h
new file mode 100644
index 0000000..afac419
--- /dev/null
+++ b/drivers/video/msm/mdss/mdp3_ppp.h
@@ -0,0 +1,413 @@
+/* Copyright (c) 2007, 2013 The Linux Foundation. All rights reserved.
+ * Copyright (C) 2007 Google Incorporated
+ *
+ * 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.
+ */
+
+#ifndef MDP3_PPP_H
+#define MDP3_PPP_H
+#include "mdp3.h"
+#include "mdss_fb.h"
+
+#define PPP_WRITEL(val, off) MDP3_REG_WRITE(off, val)
+
+#define MAX_BLIT_REQ 256
+#define PPP_UPSCALE_MAX 64
+#define PPP_BLUR_SCALE_MAX 128
+#define PPP_LUT_MAX 256
+
+/* MDP PPP Operations */
+#define MDPOP_NOP 0
+#define MDPOP_LR BIT(0) /* left to right flip */
+#define MDPOP_UD BIT(1) /* up and down flip */
+#define MDPOP_ROT90 BIT(2) /* rotate image to 90 degree */
+#define MDPOP_ROT180 (MDPOP_UD|MDPOP_LR)
+#define MDPOP_ROT270 (MDPOP_ROT90|MDPOP_UD|MDPOP_LR)
+#define MDPOP_ASCALE BIT(7)
+#define MDPOP_ALPHAB BIT(8) /* enable alpha blending */
+#define MDPOP_TRANSP BIT(9) /* enable transparency */
+#define MDPOP_DITHER BIT(10) /* enable dither */
+#define MDPOP_SHARPENING BIT(11) /* enable sharpening */
+#define MDPOP_BLUR BIT(12) /* enable blur */
+#define MDPOP_FG_PM_ALPHA BIT(13)
+#define MDPOP_LAYER_IS_FG BIT(14)
+
+#define MDPOP_ROTATION (MDPOP_ROT90|MDPOP_LR|MDPOP_UD)
+
+#define PPP_OP_CONVERT_YCBCR2RGB BIT(2)
+#define PPP_OP_CONVERT_ON BIT(3)
+#define PPP_OP_SCALE_X_ON BIT(0)
+#define PPP_OP_SCALE_Y_ON BIT(1)
+#define PPP_OP_ROT_ON BIT(8)
+#define PPP_OP_ROT_90 BIT(9)
+#define PPP_OP_FLIP_LR BIT(10)
+#define PPP_OP_FLIP_UD BIT(11)
+#define PPP_OP_BLEND_ON BIT(12)
+#define PPP_OP_BLEND_CONSTANT_ALPHA BIT(14)
+#define PPP_OP_DITHER_EN BIT(16)
+#define PPP_BLEND_CALPHA_TRNASP BIT(24)
+
+#define PPP_OP_BLEND_SRCPIXEL_ALPHA 0
+#define PPP_OP_BLEND_ALPHA_BLEND_NORMAL 0
+#define PPP_OP_BLEND_ALPHA_BLEND_REVERSE BIT(15)
+
+#define PPP_BLEND_BG_USE_ALPHA_SEL (1 << 0)
+#define PPP_BLEND_BG_ALPHA_REVERSE (1 << 3)
+#define PPP_BLEND_BG_SRCPIXEL_ALPHA (0 << 1)
+#define PPP_BLEND_BG_DSTPIXEL_ALPHA (1 << 1)
+#define PPP_BLEND_BG_CONSTANT_ALPHA (2 << 1)
+#define PPP_BLEND_BG_CONST_ALPHA_VAL(x) ((x) << 24)
+#define PPP_OP_BG_CHROMA_H2V1 BIT(25)
+
+#define CLR_G 0x0
+#define CLR_B 0x1
+#define CLR_R 0x2
+#define CLR_ALPHA 0x3
+
+#define CLR_Y CLR_G
+#define CLR_CB CLR_B
+#define CLR_CR CLR_R
+
+/* from lsb to msb */
+#define PPP_GET_PACK_PATTERN(a, x, y, z, bit) \
+ (((a)<<(bit*3))|((x)<<(bit*2))|((y)<<bit)|(z))
+
+/* Frame unpacking */
+#define PPP_C0G_8BITS (BIT(1)|BIT(0))
+#define PPP_C1B_8BITS (BIT(3)|BIT(2))
+#define PPP_C2R_8BITS (BIT(5)|BIT(4))
+#define PPP_C3A_8BITS (BIT(7)|BIT(6))
+
+#define PPP_C0G_6BITS BIT(1)
+#define PPP_C1B_6BITS BIT(3)
+#define PPP_C2R_6BITS BIT(5)
+
+#define PPP_C0G_5BITS BIT(0)
+#define PPP_C1B_5BITS BIT(2)
+#define PPP_C2R_5BITS BIT(4)
+
+#define PPP_SRC_C3_ALPHA_EN BIT(8)
+
+#define PPP_SRC_BPP_INTERLVD_1BYTES 0
+#define PPP_SRC_BPP_INTERLVD_2BYTES BIT(9)
+#define PPP_SRC_BPP_INTERLVD_3BYTES BIT(10)
+#define PPP_SRC_BPP_INTERLVD_4BYTES (BIT(10)|BIT(9))
+
+#define PPP_SRC_BPP_ROI_ODD_X BIT(11)
+#define PPP_SRC_BPP_ROI_ODD_Y BIT(12)
+#define PPP_SRC_INTERLVD_2COMPONENTS BIT(13)
+#define PPP_SRC_INTERLVD_3COMPONENTS BIT(14)
+#define PPP_SRC_INTERLVD_4COMPONENTS (BIT(14)|BIT(13))
+
+#define PPP_SRC_UNPACK_TIGHT BIT(17)
+#define PPP_SRC_UNPACK_LOOSE 0
+#define PPP_SRC_UNPACK_ALIGN_LSB 0
+#define PPP_SRC_UNPACK_ALIGN_MSB BIT(18)
+
+#define PPP_SRC_FETCH_PLANES_INTERLVD 0
+#define PPP_SRC_FETCH_PLANES_PSEUDOPLNR BIT(20)
+
+#define PPP_OP_SRC_CHROMA_H2V1 BIT(18)
+#define PPP_OP_SRC_CHROMA_H1V2 BIT(19)
+#define PPP_OP_SRC_CHROMA_420 (BIT(18)|BIT(19))
+#define PPP_OP_SRC_CHROMA_OFFSITE BIT(20)
+
+#define PPP_DST_PACKET_CNT_INTERLVD_2ELEM BIT(9)
+#define PPP_DST_PACKET_CNT_INTERLVD_3ELEM BIT(10)
+#define PPP_DST_PACKET_CNT_INTERLVD_4ELEM (BIT(10)|BIT(9))
+#define PPP_DST_PACKET_CNT_INTERLVD_6ELEM (BIT(11)|BIT(9))
+
+#define PPP_DST_C3A_8BIT (BIT(7)|BIT(6))
+#define PPP_DST_C3ALPHA_EN BIT(8)
+
+#define PPP_DST_PACK_LOOSE 0
+#define PPP_DST_PACK_TIGHT BIT(13)
+#define PPP_DST_PACK_ALIGN_LSB 0
+#define PPP_DST_PACK_ALIGN_MSB BIT(14)
+
+#define PPP_DST_OUT_SEL_AXI 0
+#define PPP_DST_OUT_SEL_MDDI BIT(15)
+
+#define PPP_DST_BPP_2BYTES BIT(16)
+#define PPP_DST_BPP_3BYTES BIT(17)
+#define PPP_DST_BPP_4BYTES (BIT(17)|BIT(16))
+
+#define PPP_DST_PLANE_INTERLVD 0
+#define PPP_DST_PLANE_PLANAR BIT(18)
+#define PPP_DST_PLANE_PSEUDOPLN BIT(19)
+
+#define PPP_OP_DST_CHROMA_H2V1 BIT(21)
+#define PPP_OP_DST_CHROMA_420 (BIT(21)|BIT(22))
+#define PPP_OP_COLOR_SPACE_YCBCR BIT(17)
+
+#define MDP_SCALE_Q_FACTOR 512
+#define MDP_MAX_X_SCALE_FACTOR (MDP_SCALE_Q_FACTOR*4)
+#define MDP_MIN_X_SCALE_FACTOR (MDP_SCALE_Q_FACTOR/4)
+#define MDP_MAX_Y_SCALE_FACTOR (MDP_SCALE_Q_FACTOR*4)
+#define MDP_MIN_Y_SCALE_FACTOR (MDP_SCALE_Q_FACTOR/4)
+
+#define MDP_TOP_LUMA 16
+#define MDP_TOP_CHROMA 0
+#define MDP_BOTTOM_LUMA 19
+#define MDP_BOTTOM_CHROMA 3
+#define MDP_LEFT_LUMA 22
+#define MDP_LEFT_CHROMA 6
+#define MDP_RIGHT_LUMA 25
+#define MDP_RIGHT_CHROMA 9
+
+#define MDP_RGB_565_SRC_REG (PPP_C2R_5BITS | PPP_C0G_6BITS | \
+ PPP_C1B_5BITS | PPP_SRC_BPP_INTERLVD_2BYTES | \
+ PPP_SRC_INTERLVD_3COMPONENTS | PPP_SRC_UNPACK_TIGHT | \
+ PPP_SRC_UNPACK_ALIGN_LSB | \
+ PPP_SRC_FETCH_PLANES_INTERLVD)
+
+#define MDP_RGB_888_SRC_REG (PPP_C2R_8BITS | PPP_C0G_8BITS | \
+ PPP_C1B_8BITS | PPP_SRC_BPP_INTERLVD_3BYTES | \
+ PPP_SRC_INTERLVD_3COMPONENTS | PPP_SRC_UNPACK_TIGHT | \
+ PPP_SRC_UNPACK_ALIGN_LSB | PPP_SRC_FETCH_PLANES_INTERLVD)
+
+#define MDP_RGBX_8888_SRC_REG (PPP_C2R_8BITS | PPP_C0G_8BITS | \
+ PPP_C1B_8BITS | PPP_C3A_8BITS | \
+ PPP_SRC_C3_ALPHA_EN | PPP_SRC_BPP_INTERLVD_4BYTES | \
+ PPP_SRC_INTERLVD_4COMPONENTS | PPP_SRC_UNPACK_TIGHT | \
+ PPP_SRC_UNPACK_ALIGN_LSB | \
+ PPP_SRC_FETCH_PLANES_INTERLVD)
+
+#define MDP_Y_CBCR_H2V2_SRC_REG (PPP_C2R_8BITS | PPP_C0G_8BITS | \
+ PPP_C1B_8BITS | PPP_SRC_BPP_INTERLVD_2BYTES | \
+ PPP_SRC_INTERLVD_2COMPONENTS | PPP_SRC_UNPACK_TIGHT | \
+ PPP_SRC_UNPACK_ALIGN_LSB | \
+ PPP_SRC_FETCH_PLANES_PSEUDOPLNR)
+
+#define MDP_YCRYCB_H2V1_SRC_REG (PPP_C2R_8BITS | \
+ PPP_C0G_8BITS | PPP_C1B_8BITS | \
+ PPP_C3A_8BITS | PPP_SRC_BPP_INTERLVD_2BYTES | \
+ PPP_SRC_INTERLVD_4COMPONENTS | \
+ PPP_SRC_UNPACK_TIGHT | PPP_SRC_UNPACK_ALIGN_LSB)
+
+#define MDP_Y_CRCB_H2V1_SRC_REG (PPP_C2R_8BITS | \
+ PPP_C0G_8BITS | PPP_C1B_8BITS | \
+ PPP_C3A_8BITS | PPP_SRC_BPP_INTERLVD_2BYTES | \
+ PPP_SRC_INTERLVD_2COMPONENTS | PPP_SRC_UNPACK_TIGHT | \
+ PPP_SRC_UNPACK_ALIGN_LSB | PPP_SRC_FETCH_PLANES_PSEUDOPLNR)
+
+#define MDP_RGB_565_DST_REG (PPP_C0G_6BITS | \
+ PPP_C1B_5BITS | PPP_C2R_5BITS | \
+ PPP_DST_PACKET_CNT_INTERLVD_3ELEM | \
+ PPP_DST_PACK_TIGHT | PPP_DST_PACK_ALIGN_LSB | \
+ PPP_DST_OUT_SEL_AXI | PPP_DST_BPP_2BYTES | \
+ PPP_DST_PLANE_INTERLVD)
+
+#define MDP_RGB_888_DST_REG (PPP_C0G_8BITS | \
+ PPP_C1B_8BITS | PPP_C2R_8BITS | \
+ PPP_DST_PACKET_CNT_INTERLVD_3ELEM | PPP_DST_PACK_TIGHT | \
+ PPP_DST_PACK_ALIGN_LSB | PPP_DST_OUT_SEL_AXI | \
+ PPP_DST_BPP_3BYTES | PPP_DST_PLANE_INTERLVD)
+
+#define MDP_RGBX_8888_DST_REG (PPP_C0G_8BITS | \
+ PPP_C1B_8BITS | PPP_C2R_8BITS | PPP_C3A_8BITS | \
+ PPP_DST_C3ALPHA_EN | PPP_DST_PACKET_CNT_INTERLVD_4ELEM | \
+ PPP_DST_PACK_TIGHT | PPP_DST_PACK_ALIGN_LSB | \
+ PPP_DST_OUT_SEL_AXI | PPP_DST_BPP_4BYTES | \
+ PPP_DST_PLANE_INTERLVD)
+
+#define MDP_Y_CBCR_H2V2_DST_REG (PPP_C2R_8BITS | \
+ PPP_C0G_8BITS | PPP_C1B_8BITS | PPP_C3A_8BITS | \
+ PPP_DST_PACKET_CNT_INTERLVD_2ELEM | \
+ PPP_DST_PACK_TIGHT | PPP_DST_PACK_ALIGN_LSB | \
+ PPP_DST_OUT_SEL_AXI | PPP_DST_BPP_2BYTES)
+
+#define MDP_YCRYCB_H2V1_DST_REG (PPP_C2R_8BITS | PPP_C0G_8BITS | \
+ PPP_C1B_8BITS | PPP_C3A_8BITS | PPP_DST_PACKET_CNT_INTERLVD_4ELEM | \
+ PPP_DST_PACK_TIGHT | PPP_DST_PACK_ALIGN_LSB | \
+ PPP_DST_OUT_SEL_AXI | PPP_DST_BPP_2BYTES | \
+ PPP_DST_PLANE_INTERLVD)
+
+#define MDP_Y_CRCB_H2V1_DST_REG (PPP_C2R_8BITS | \
+ PPP_C0G_8BITS | PPP_C1B_8BITS | PPP_C3A_8BITS | \
+ PPP_DST_PACKET_CNT_INTERLVD_2ELEM | PPP_DST_PACK_TIGHT | \
+ PPP_DST_PACK_ALIGN_LSB | PPP_DST_OUT_SEL_AXI | \
+ PPP_DST_BPP_2BYTES)
+
+/* LUT */
+#define MDP_LUT_C0_EN BIT(5)
+#define MDP_LUT_C1_EN BIT(6)
+#define MDP_LUT_C2_EN BIT(7)
+
+/* Dither */
+#define MDP_OP_DITHER_EN BIT(16)
+
+/* Rotator */
+#define MDP_OP_ROT_ON BIT(8)
+#define MDP_OP_ROT_90 BIT(9)
+#define MDP_OP_FLIP_LR BIT(10)
+#define MDP_OP_FLIP_UD BIT(11)
+
+/* Blend */
+#define MDP_OP_BLEND_EN BIT(12)
+#define MDP_OP_BLEND_EQ_SEL BIT(15)
+#define MDP_OP_BLEND_TRANSP_EN BIT(24)
+#define MDP_BLEND_MASK (MDP_OP_BLEND_EN | MDP_OP_BLEND_EQ_SEL | \
+ MDP_OP_BLEND_TRANSP_EN | BIT(14) | BIT(13))
+
+#define MDP_BLEND_ALPHA_SEL 13
+#define MDP_BLEND_ALPHA_MASK 0x3
+#define MDP_BLEND_CONST_ALPHA 24
+#define MDP_BLEND_TRASP_COL_MASK 0xFFFFFF
+
+/* CSC Matrix */
+#define MDP_CSC_RGB2YUV 0
+#define MDP_CSC_YUV2RGB 1
+
+#define MDP_CSC_SIZE 9
+#define MDP_BV_SIZE 3
+#define MDP_LV_SIZE 4
+
+enum ppp_lut_type {
+ LUT_PRE_TABLE = 0,
+ LUT_POST_TABLE,
+};
+
+enum ppp_csc_matrix {
+ CSC_PRIMARY_MATRIX = 0,
+ CSC_SECONDARY_MATRIX,
+};
+
+/* scale tables */
+enum {
+ PPP_DOWNSCALE_PT2TOPT4,
+ PPP_DOWNSCALE_PT4TOPT6,
+ PPP_DOWNSCALE_PT6TOPT8,
+ PPP_DOWNSCALE_PT8TOPT1,
+ PPP_DOWNSCALE_MAX,
+};
+
+struct ppp_table {
+ uint32_t reg;
+ uint32_t val;
+};
+
+struct ppp_csc_table {
+ int direction; /* MDP_CCS_RGB2YUV or YUV2RGB */
+ uint16_t fwd_matrix[MDP_CCS_SIZE]; /* 3x3 color coefficients */
+ uint16_t rev_matrix[MDP_CCS_SIZE]; /* 3x3 color coefficients */
+ uint16_t bv[MDP_BV_SIZE]; /* 1x3 bias vector */
+ uint16_t lv[MDP_LV_SIZE]; /* 1x3 limit vector */
+};
+
+struct ppp_blend {
+ int const_alpha;
+ int trans_color; /*color keying*/
+};
+
+struct ppp_img_prop {
+ int32_t x;
+ int32_t y;
+ uint32_t width;
+ uint32_t height;
+};
+
+struct ppp_img_desc {
+ struct ppp_img_prop prop;
+ struct ppp_img_prop roi;
+ int color_fmt;
+ void *p0; /* plane 0 */
+ void *p1;
+ void *p3;
+ int stride0;
+ int stride1;
+ int stride2;
+};
+
+struct ppp_blit_op {
+ struct ppp_img_desc src;
+ struct ppp_img_desc dst;
+ struct ppp_img_desc bg;
+ struct ppp_blend blend;
+ uint32_t mdp_op; /* Operations */
+};
+
+struct ppp_edge_rep {
+ uint32_t dst_roi_width;
+ uint32_t dst_roi_height;
+ uint32_t is_scale_enabled;
+
+ /*
+ * positions of the luma pixel(relative to the image ) required for
+ * scaling the ROI
+ */
+ int32_t luma_interp_point_left;
+ int32_t luma_interp_point_right;
+ int32_t luma_interp_point_top;
+ int32_t luma_interp_point_bottom;
+
+ /*
+ * positions of the chroma pixel(relative to the image ) required for
+ * interpolating a chroma value at all required luma positions
+ */
+ int32_t chroma_interp_point_left;
+ int32_t chroma_interp_point_right;
+ int32_t chroma_interp_point_top;
+ int32_t chroma_interp_point_bottom;
+
+ /*
+ * a rectangular region within the chroma plane of the "image".
+ * Chroma pixels falling inside of this rectangle belongs to the ROI
+ */
+ int32_t chroma_bound_left;
+ int32_t chroma_bound_right;
+ int32_t chroma_bound_top;
+ int32_t chroma_bound_bottom;
+
+ /*
+ * number of chroma pixels to replicate on the left, right,
+ * top and bottom edge of the ROI.
+ */
+ int32_t chroma_repeat_left;
+ int32_t chroma_repeat_right;
+ int32_t chroma_repeat_top;
+ int32_t chroma_repeat_bottom;
+
+ /*
+ * number of luma pixels to replicate on the left, right,
+ * top and bottom edge of the ROI.
+ */
+ int32_t luma_repeat_left;
+ int32_t luma_repeat_right;
+ int32_t luma_repeat_top;
+ int32_t luma_repeat_bottom;
+};
+
+/* func for ppp register values */
+uint32_t ppp_bpp(uint32_t type);
+uint32_t ppp_src_config(uint32_t type);
+uint32_t ppp_out_config(uint32_t type);
+uint32_t ppp_pack_pattern(uint32_t type);
+uint32_t ppp_dst_op_reg(uint32_t type);
+uint32_t ppp_src_op_reg(uint32_t type);
+bool ppp_per_p_alpha(uint32_t type);
+bool ppp_multi_plane(uint32_t type);
+uint32_t *ppp_default_pre_lut(void);
+uint32_t *ppp_default_post_lut(void);
+struct ppp_csc_table *ppp_csc_rgb2yuv(void);
+struct ppp_csc_table *ppp_csc_table2(void);
+void ppp_load_up_lut(void);
+void ppp_load_gaussian_lut(void);
+void ppp_load_x_scale_table(int idx);
+void ppp_load_y_scale_table(int idx);
+
+int mdp3_ppp_start_blit(struct msm_fb_data_type *mfd,
+ struct mdp_blit_req *req);
+int mdp3_ppp_res_init(void);
+int mdp3_ppp_init(void);
+int config_ppp_op_mode(struct ppp_blit_op *blit_op);
+void ppp_enable(void);
+
+#endif
diff --git a/drivers/video/msm/mdss/mdp3_ppp_data.c b/drivers/video/msm/mdss/mdp3_ppp_data.c
new file mode 100644
index 0000000..d68faad
--- /dev/null
+++ b/drivers/video/msm/mdss/mdp3_ppp_data.c
@@ -0,0 +1,1572 @@
+/* Copyright (c) 2007, 2012-2013 The Linux Foundation. All rights reserved.
+ * Copyright (C) 2007 Google Incorporated
+ *
+ * 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/types.h>
+
+#include "mdss_fb.h"
+#include "mdp3_ppp.h"
+
+/* bg_config_lut not needed since it is same as src */
+const uint32_t src_cfg_lut[MDP_IMGTYPE_LIMIT] = {
+ [MDP_RGB_565] = MDP_RGB_565_SRC_REG,
+ [MDP_BGR_565] = MDP_RGB_565_SRC_REG,
+ [MDP_RGB_888] = MDP_RGB_888_SRC_REG,
+ [MDP_BGR_888] = MDP_RGB_888_SRC_REG,
+ [MDP_BGRA_8888] = MDP_RGBX_8888_SRC_REG,
+ [MDP_RGBA_8888] = MDP_RGBX_8888_SRC_REG,
+ [MDP_ARGB_8888] = MDP_RGBX_8888_SRC_REG,
+ [MDP_XRGB_8888] = MDP_RGBX_8888_SRC_REG,
+ [MDP_RGBX_8888] = MDP_RGBX_8888_SRC_REG,
+ [MDP_Y_CRCB_H2V2] = MDP_Y_CBCR_H2V2_SRC_REG,
+ [MDP_Y_CBCR_H2V2] = MDP_Y_CBCR_H2V2_SRC_REG,
+ [MDP_Y_CBCR_H2V2_ADRENO] = MDP_Y_CBCR_H2V2_SRC_REG,
+ [MDP_YCRYCB_H2V1] = MDP_YCRYCB_H2V1_SRC_REG,
+ [MDP_Y_CBCR_H2V1] = MDP_Y_CRCB_H2V1_SRC_REG,
+ [MDP_Y_CRCB_H2V1] = MDP_Y_CRCB_H2V1_SRC_REG,
+};
+
+const uint32_t out_cfg_lut[MDP_IMGTYPE_LIMIT] = {
+ [MDP_RGB_565] = MDP_RGB_565_DST_REG,
+ [MDP_BGR_565] = MDP_RGB_565_DST_REG,
+ [MDP_RGB_888] = MDP_RGB_888_DST_REG,
+ [MDP_BGR_888] = MDP_RGB_888_DST_REG,
+ [MDP_BGRA_8888] = MDP_RGBX_8888_DST_REG,
+ [MDP_RGBA_8888] = MDP_RGBX_8888_DST_REG,
+ [MDP_ARGB_8888] = MDP_RGBX_8888_DST_REG,
+ [MDP_XRGB_8888] = MDP_RGBX_8888_DST_REG,
+ [MDP_RGBX_8888] = MDP_RGBX_8888_DST_REG,
+ [MDP_Y_CRCB_H2V2] = MDP_Y_CBCR_H2V2_DST_REG,
+ [MDP_Y_CBCR_H2V2] = MDP_Y_CBCR_H2V2_DST_REG,
+ [MDP_Y_CBCR_H2V2_ADRENO] = MDP_Y_CBCR_H2V2_DST_REG,
+ [MDP_YCRYCB_H2V1] = MDP_YCRYCB_H2V1_DST_REG,
+ [MDP_Y_CBCR_H2V1] = MDP_Y_CRCB_H2V1_DST_REG,
+ [MDP_Y_CRCB_H2V1] = MDP_Y_CRCB_H2V1_DST_REG,
+};
+
+const uint32_t pack_patt_lut[MDP_IMGTYPE_LIMIT] = {
+ [MDP_RGB_565] = PPP_GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 8),
+ [MDP_BGR_565] = PPP_GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 8),
+ [MDP_RGB_888] = PPP_GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8),
+ [MDP_BGR_888] = PPP_GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 8),
+ [MDP_BGRA_8888] = PPP_GET_PACK_PATTERN(CLR_ALPHA, CLR_R,
+ CLR_G, CLR_B, 8),
+ [MDP_RGBA_8888] = PPP_GET_PACK_PATTERN(CLR_ALPHA, CLR_R,
+ CLR_G, CLR_B, 8),
+ [MDP_ARGB_8888] = PPP_GET_PACK_PATTERN(CLR_ALPHA, CLR_R,
+ CLR_G, CLR_B, 8),
+ [MDP_XRGB_8888] = PPP_GET_PACK_PATTERN(CLR_ALPHA, CLR_R,
+ CLR_G, CLR_B, 8),
+ [MDP_RGBX_8888] = PPP_GET_PACK_PATTERN(CLR_ALPHA, CLR_R,
+ CLR_G, CLR_B, 8),
+ [MDP_Y_CRCB_H2V2] = PPP_GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
+ [MDP_Y_CBCR_H2V2] = PPP_GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
+ [MDP_Y_CBCR_H2V2_ADRENO] = PPP_GET_PACK_PATTERN(0, 0, CLR_CB,
+ CLR_CR, 8),
+ [MDP_YCRYCB_H2V1] = PPP_GET_PACK_PATTERN(CLR_Y,
+ CLR_CR, CLR_Y, CLR_CB, 8),
+ [MDP_Y_CBCR_H2V1] = PPP_GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
+ [MDP_Y_CRCB_H2V1] = PPP_GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
+};
+
+const uint32_t dst_op_reg[MDP_IMGTYPE_LIMIT] = {
+ [MDP_Y_CRCB_H2V2] = PPP_OP_DST_CHROMA_420,
+ [MDP_Y_CBCR_H2V2] = PPP_OP_DST_CHROMA_420,
+ [MDP_Y_CBCR_H2V1] = PPP_OP_DST_CHROMA_H2V1,
+ [MDP_Y_CRCB_H2V1] = PPP_OP_DST_CHROMA_H2V1,
+ [MDP_YCRYCB_H2V1] = PPP_OP_DST_CHROMA_H2V1,
+};
+
+const uint32_t src_op_reg[MDP_IMGTYPE_LIMIT] = {
+ [MDP_Y_CRCB_H2V2] = PPP_OP_SRC_CHROMA_420 | PPP_OP_COLOR_SPACE_YCBCR,
+ [MDP_Y_CBCR_H2V2] = PPP_OP_SRC_CHROMA_420 | PPP_OP_COLOR_SPACE_YCBCR,
+ [MDP_Y_CBCR_H2V2_ADRENO] = PPP_OP_SRC_CHROMA_420 |
+ PPP_OP_COLOR_SPACE_YCBCR,
+ [MDP_Y_CBCR_H2V1] = PPP_OP_SRC_CHROMA_H2V1,
+ [MDP_Y_CRCB_H2V1] = PPP_OP_SRC_CHROMA_H2V1,
+ [MDP_YCRYCB_H2V1] = PPP_OP_SRC_CHROMA_H2V1,
+};
+
+const uint32_t bytes_per_pixel[MDP_IMGTYPE_LIMIT] = {
+ [MDP_RGB_565] = 2,
+ [MDP_BGR_565] = 2,
+ [MDP_RGB_888] = 3,
+ [MDP_BGR_888] = 3,
+ [MDP_XRGB_8888] = 4,
+ [MDP_ARGB_8888] = 4,
+ [MDP_RGBA_8888] = 4,
+ [MDP_BGRA_8888] = 4,
+ [MDP_RGBX_8888] = 4,
+ [MDP_Y_CBCR_H2V1] = 1,
+ [MDP_Y_CBCR_H2V2] = 1,
+ [MDP_Y_CBCR_H2V2_ADRENO] = 1,
+ [MDP_Y_CRCB_H2V1] = 1,
+ [MDP_Y_CRCB_H2V2] = 1,
+ [MDP_YCRYCB_H2V1] = 2,
+};
+
+const bool per_pixel_alpha[MDP_IMGTYPE_LIMIT] = {
+ [MDP_BGRA_8888] = true,
+ [MDP_RGBA_8888] = true,
+ [MDP_ARGB_8888] = true,
+};
+
+const bool multi_plane[MDP_IMGTYPE_LIMIT] = {
+ [MDP_Y_CRCB_H2V2] = true,
+ [MDP_Y_CBCR_H2V2] = true,
+ [MDP_Y_CBCR_H2V1] = true,
+ [MDP_Y_CRCB_H2V1] = true,
+};
+
+/* lut default */
+uint32_t default_pre_lut_val[PPP_LUT_MAX] = {
+ 0x0,
+ 0x151515,
+ 0x1d1d1d,
+ 0x232323,
+ 0x272727,
+ 0x2b2b2b,
+ 0x2f2f2f,
+ 0x333333,
+ 0x363636,
+ 0x393939,
+ 0x3b3b3b,
+ 0x3e3e3e,
+ 0x404040,
+ 0x434343,
+ 0x454545,
+ 0x474747,
+ 0x494949,
+ 0x4b4b4b,
+ 0x4d4d4d,
+ 0x4f4f4f,
+ 0x515151,
+ 0x535353,
+ 0x555555,
+ 0x565656,
+ 0x585858,
+ 0x5a5a5a,
+ 0x5b5b5b,
+ 0x5d5d5d,
+ 0x5e5e5e,
+ 0x606060,
+ 0x616161,
+ 0x636363,
+ 0x646464,
+ 0x666666,
+ 0x676767,
+ 0x686868,
+ 0x6a6a6a,
+ 0x6b6b6b,
+ 0x6c6c6c,
+ 0x6e6e6e,
+ 0x6f6f6f,
+ 0x707070,
+ 0x717171,
+ 0x727272,
+ 0x747474,
+ 0x757575,
+ 0x767676,
+ 0x777777,
+ 0x787878,
+ 0x797979,
+ 0x7a7a7a,
+ 0x7c7c7c,
+ 0x7d7d7d,
+ 0x7e7e7e,
+ 0x7f7f7f,
+ 0x808080,
+ 0x818181,
+ 0x828282,
+ 0x838383,
+ 0x848484,
+ 0x858585,
+ 0x868686,
+ 0x878787,
+ 0x888888,
+ 0x898989,
+ 0x8a8a8a,
+ 0x8b8b8b,
+ 0x8c8c8c,
+ 0x8d8d8d,
+ 0x8e8e8e,
+ 0x8f8f8f,
+ 0x8f8f8f,
+ 0x909090,
+ 0x919191,
+ 0x929292,
+ 0x939393,
+ 0x949494,
+ 0x959595,
+ 0x969696,
+ 0x969696,
+ 0x979797,
+ 0x989898,
+ 0x999999,
+ 0x9a9a9a,
+ 0x9b9b9b,
+ 0x9c9c9c,
+ 0x9c9c9c,
+ 0x9d9d9d,
+ 0x9e9e9e,
+ 0x9f9f9f,
+ 0xa0a0a0,
+ 0xa0a0a0,
+ 0xa1a1a1,
+ 0xa2a2a2,
+ 0xa3a3a3,
+ 0xa4a4a4,
+ 0xa4a4a4,
+ 0xa5a5a5,
+ 0xa6a6a6,
+ 0xa7a7a7,
+ 0xa7a7a7,
+ 0xa8a8a8,
+ 0xa9a9a9,
+ 0xaaaaaa,
+ 0xaaaaaa,
+ 0xababab,
+ 0xacacac,
+ 0xadadad,
+ 0xadadad,
+ 0xaeaeae,
+ 0xafafaf,
+ 0xafafaf,
+ 0xb0b0b0,
+ 0xb1b1b1,
+ 0xb2b2b2,
+ 0xb2b2b2,
+ 0xb3b3b3,
+ 0xb4b4b4,
+ 0xb4b4b4,
+ 0xb5b5b5,
+ 0xb6b6b6,
+ 0xb6b6b6,
+ 0xb7b7b7,
+ 0xb8b8b8,
+ 0xb8b8b8,
+ 0xb9b9b9,
+ 0xbababa,
+ 0xbababa,
+ 0xbbbbbb,
+ 0xbcbcbc,
+ 0xbcbcbc,
+ 0xbdbdbd,
+ 0xbebebe,
+ 0xbebebe,
+ 0xbfbfbf,
+ 0xc0c0c0,
+ 0xc0c0c0,
+ 0xc1c1c1,
+ 0xc1c1c1,
+ 0xc2c2c2,
+ 0xc3c3c3,
+ 0xc3c3c3,
+ 0xc4c4c4,
+ 0xc5c5c5,
+ 0xc5c5c5,
+ 0xc6c6c6,
+ 0xc6c6c6,
+ 0xc7c7c7,
+ 0xc8c8c8,
+ 0xc8c8c8,
+ 0xc9c9c9,
+ 0xc9c9c9,
+ 0xcacaca,
+ 0xcbcbcb,
+ 0xcbcbcb,
+ 0xcccccc,
+ 0xcccccc,
+ 0xcdcdcd,
+ 0xcecece,
+ 0xcecece,
+ 0xcfcfcf,
+ 0xcfcfcf,
+ 0xd0d0d0,
+ 0xd0d0d0,
+ 0xd1d1d1,
+ 0xd2d2d2,
+ 0xd2d2d2,
+ 0xd3d3d3,
+ 0xd3d3d3,
+ 0xd4d4d4,
+ 0xd4d4d4,
+ 0xd5d5d5,
+ 0xd6d6d6,
+ 0xd6d6d6,
+ 0xd7d7d7,
+ 0xd7d7d7,
+ 0xd8d8d8,
+ 0xd8d8d8,
+ 0xd9d9d9,
+ 0xd9d9d9,
+ 0xdadada,
+ 0xdbdbdb,
+ 0xdbdbdb,
+ 0xdcdcdc,
+ 0xdcdcdc,
+ 0xdddddd,
+ 0xdddddd,
+ 0xdedede,
+ 0xdedede,
+ 0xdfdfdf,
+ 0xdfdfdf,
+ 0xe0e0e0,
+ 0xe0e0e0,
+ 0xe1e1e1,
+ 0xe1e1e1,
+ 0xe2e2e2,
+ 0xe3e3e3,
+ 0xe3e3e3,
+ 0xe4e4e4,
+ 0xe4e4e4,
+ 0xe5e5e5,
+ 0xe5e5e5,
+ 0xe6e6e6,
+ 0xe6e6e6,
+ 0xe7e7e7,
+ 0xe7e7e7,
+ 0xe8e8e8,
+ 0xe8e8e8,
+ 0xe9e9e9,
+ 0xe9e9e9,
+ 0xeaeaea,
+ 0xeaeaea,
+ 0xebebeb,
+ 0xebebeb,
+ 0xececec,
+ 0xececec,
+ 0xededed,
+ 0xededed,
+ 0xeeeeee,
+ 0xeeeeee,
+ 0xefefef,
+ 0xefefef,
+ 0xf0f0f0,
+ 0xf0f0f0,
+ 0xf1f1f1,
+ 0xf1f1f1,
+ 0xf2f2f2,
+ 0xf2f2f2,
+ 0xf2f2f2,
+ 0xf3f3f3,
+ 0xf3f3f3,
+ 0xf4f4f4,
+ 0xf4f4f4,
+ 0xf5f5f5,
+ 0xf5f5f5,
+ 0xf6f6f6,
+ 0xf6f6f6,
+ 0xf7f7f7,
+ 0xf7f7f7,
+ 0xf8f8f8,
+ 0xf8f8f8,
+ 0xf9f9f9,
+ 0xf9f9f9,
+ 0xfafafa,
+ 0xfafafa,
+ 0xfafafa,
+ 0xfbfbfb,
+ 0xfbfbfb,
+ 0xfcfcfc,
+ 0xfcfcfc,
+ 0xfdfdfd,
+ 0xfdfdfd,
+ 0xfefefe,
+ 0xfefefe,
+ 0xffffff,
+ 0xffffff,
+};
+
+uint32_t default_post_lut_val[PPP_LUT_MAX] = {
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x10101,
+ 0x10101,
+ 0x10101,
+ 0x10101,
+ 0x10101,
+ 0x10101,
+ 0x10101,
+ 0x10101,
+ 0x10101,
+ 0x10101,
+ 0x20202,
+ 0x20202,
+ 0x20202,
+ 0x20202,
+ 0x20202,
+ 0x20202,
+ 0x30303,
+ 0x30303,
+ 0x30303,
+ 0x30303,
+ 0x30303,
+ 0x40404,
+ 0x40404,
+ 0x40404,
+ 0x40404,
+ 0x40404,
+ 0x50505,
+ 0x50505,
+ 0x50505,
+ 0x50505,
+ 0x60606,
+ 0x60606,
+ 0x60606,
+ 0x70707,
+ 0x70707,
+ 0x70707,
+ 0x70707,
+ 0x80808,
+ 0x80808,
+ 0x80808,
+ 0x90909,
+ 0x90909,
+ 0xa0a0a,
+ 0xa0a0a,
+ 0xa0a0a,
+ 0xb0b0b,
+ 0xb0b0b,
+ 0xb0b0b,
+ 0xc0c0c,
+ 0xc0c0c,
+ 0xd0d0d,
+ 0xd0d0d,
+ 0xe0e0e,
+ 0xe0e0e,
+ 0xe0e0e,
+ 0xf0f0f,
+ 0xf0f0f,
+ 0x101010,
+ 0x101010,
+ 0x111111,
+ 0x111111,
+ 0x121212,
+ 0x121212,
+ 0x131313,
+ 0x131313,
+ 0x141414,
+ 0x151515,
+ 0x151515,
+ 0x161616,
+ 0x161616,
+ 0x171717,
+ 0x171717,
+ 0x181818,
+ 0x191919,
+ 0x191919,
+ 0x1a1a1a,
+ 0x1b1b1b,
+ 0x1b1b1b,
+ 0x1c1c1c,
+ 0x1c1c1c,
+ 0x1d1d1d,
+ 0x1e1e1e,
+ 0x1f1f1f,
+ 0x1f1f1f,
+ 0x202020,
+ 0x212121,
+ 0x212121,
+ 0x222222,
+ 0x232323,
+ 0x242424,
+ 0x242424,
+ 0x252525,
+ 0x262626,
+ 0x272727,
+ 0x272727,
+ 0x282828,
+ 0x292929,
+ 0x2a2a2a,
+ 0x2b2b2b,
+ 0x2c2c2c,
+ 0x2c2c2c,
+ 0x2d2d2d,
+ 0x2e2e2e,
+ 0x2f2f2f,
+ 0x303030,
+ 0x313131,
+ 0x323232,
+ 0x333333,
+ 0x333333,
+ 0x343434,
+ 0x353535,
+ 0x363636,
+ 0x373737,
+ 0x383838,
+ 0x393939,
+ 0x3a3a3a,
+ 0x3b3b3b,
+ 0x3c3c3c,
+ 0x3d3d3d,
+ 0x3e3e3e,
+ 0x3f3f3f,
+ 0x404040,
+ 0x414141,
+ 0x424242,
+ 0x434343,
+ 0x444444,
+ 0x464646,
+ 0x474747,
+ 0x484848,
+ 0x494949,
+ 0x4a4a4a,
+ 0x4b4b4b,
+ 0x4c4c4c,
+ 0x4d4d4d,
+ 0x4f4f4f,
+ 0x505050,
+ 0x515151,
+ 0x525252,
+ 0x535353,
+ 0x545454,
+ 0x565656,
+ 0x575757,
+ 0x585858,
+ 0x595959,
+ 0x5b5b5b,
+ 0x5c5c5c,
+ 0x5d5d5d,
+ 0x5e5e5e,
+ 0x606060,
+ 0x616161,
+ 0x626262,
+ 0x646464,
+ 0x656565,
+ 0x666666,
+ 0x686868,
+ 0x696969,
+ 0x6a6a6a,
+ 0x6c6c6c,
+ 0x6d6d6d,
+ 0x6f6f6f,
+ 0x707070,
+ 0x717171,
+ 0x737373,
+ 0x747474,
+ 0x767676,
+ 0x777777,
+ 0x797979,
+ 0x7a7a7a,
+ 0x7c7c7c,
+ 0x7d7d7d,
+ 0x7f7f7f,
+ 0x808080,
+ 0x828282,
+ 0x838383,
+ 0x858585,
+ 0x868686,
+ 0x888888,
+ 0x898989,
+ 0x8b8b8b,
+ 0x8d8d8d,
+ 0x8e8e8e,
+ 0x909090,
+ 0x919191,
+ 0x939393,
+ 0x959595,
+ 0x969696,
+ 0x989898,
+ 0x9a9a9a,
+ 0x9b9b9b,
+ 0x9d9d9d,
+ 0x9f9f9f,
+ 0xa1a1a1,
+ 0xa2a2a2,
+ 0xa4a4a4,
+ 0xa6a6a6,
+ 0xa7a7a7,
+ 0xa9a9a9,
+ 0xababab,
+ 0xadadad,
+ 0xafafaf,
+ 0xb0b0b0,
+ 0xb2b2b2,
+ 0xb4b4b4,
+ 0xb6b6b6,
+ 0xb8b8b8,
+ 0xbababa,
+ 0xbbbbbb,
+ 0xbdbdbd,
+ 0xbfbfbf,
+ 0xc1c1c1,
+ 0xc3c3c3,
+ 0xc5c5c5,
+ 0xc7c7c7,
+ 0xc9c9c9,
+ 0xcbcbcb,
+ 0xcdcdcd,
+ 0xcfcfcf,
+ 0xd1d1d1,
+ 0xd3d3d3,
+ 0xd5d5d5,
+ 0xd7d7d7,
+ 0xd9d9d9,
+ 0xdbdbdb,
+ 0xdddddd,
+ 0xdfdfdf,
+ 0xe1e1e1,
+ 0xe3e3e3,
+ 0xe5e5e5,
+ 0xe7e7e7,
+ 0xe9e9e9,
+ 0xebebeb,
+ 0xeeeeee,
+ 0xf0f0f0,
+ 0xf2f2f2,
+ 0xf4f4f4,
+ 0xf6f6f6,
+ 0xf8f8f8,
+ 0xfbfbfb,
+ 0xfdfdfd,
+ 0xffffff,
+};
+
+struct ppp_csc_table rgb2yuv = {
+ .fwd_matrix = {
+ 0x83,
+ 0x102,
+ 0x32,
+ 0xffb5,
+ 0xff6c,
+ 0xe1,
+ 0xe1,
+ 0xff45,
+ 0xffdc,
+ },
+ .rev_matrix = {
+ 0x254,
+ 0x0,
+ 0x331,
+ 0x254,
+ 0xff38,
+ 0xfe61,
+ 0x254,
+ 0x409,
+ 0x0,
+ },
+ .bv = {
+ 0x10,
+ 0x80,
+ 0x80,
+ },
+ .lv = {
+ 0x10,
+ 0xeb,
+ 0x10,
+ 0xf0,
+ },
+};
+
+struct ppp_csc_table default_table2 = {
+ .fwd_matrix = {
+ 0x5d,
+ 0x13a,
+ 0x20,
+ 0xffcd,
+ 0xff54,
+ 0xe1,
+ 0xe1,
+ 0xff35,
+ },
+ .rev_matrix = {
+ 0x254,
+ 0x0,
+ 0x396,
+ 0x254,
+ 0xff94,
+ 0xfef0,
+ 0x254,
+ 0x43a,
+ 0x0,
+ },
+ .bv = {
+ 0x10,
+ 0x80,
+ 0x80,
+ },
+ .lv = {
+ 0x10,
+ 0xeb,
+ 0x10,
+ 0xf0,
+ },
+};
+
+const struct ppp_table upscale_table[PPP_UPSCALE_MAX] = {
+ { 0x5fffc, 0x0 },
+ { 0x50200, 0x7fc00000 },
+ { 0x5fffc, 0xff80000d },
+ { 0x50204, 0x7ec003f9 },
+ { 0x5fffc, 0xfec0001c },
+ { 0x50208, 0x7d4003f3 },
+ { 0x5fffc, 0xfe40002b },
+ { 0x5020c, 0x7b8003ed },
+ { 0x5fffc, 0xfd80003c },
+ { 0x50210, 0x794003e8 },
+ { 0x5fffc, 0xfcc0004d },
+ { 0x50214, 0x76c003e4 },
+ { 0x5fffc, 0xfc40005f },
+ { 0x50218, 0x73c003e0 },
+ { 0x5fffc, 0xfb800071 },
+ { 0x5021c, 0x708003de },
+ { 0x5fffc, 0xfac00085 },
+ { 0x50220, 0x6d0003db },
+ { 0x5fffc, 0xfa000098 },
+ { 0x50224, 0x698003d9 },
+ { 0x5fffc, 0xf98000ac },
+ { 0x50228, 0x654003d8 },
+ { 0x5fffc, 0xf8c000c1 },
+ { 0x5022c, 0x610003d7 },
+ { 0x5fffc, 0xf84000d5 },
+ { 0x50230, 0x5c8003d7 },
+ { 0x5fffc, 0xf7c000e9 },
+ { 0x50234, 0x580003d7 },
+ { 0x5fffc, 0xf74000fd },
+ { 0x50238, 0x534003d8 },
+ { 0x5fffc, 0xf6c00112 },
+ { 0x5023c, 0x4e8003d8 },
+ { 0x5fffc, 0xf6800126 },
+ { 0x50240, 0x494003da },
+ { 0x5fffc, 0xf600013a },
+ { 0x50244, 0x448003db },
+ { 0x5fffc, 0xf600014d },
+ { 0x50248, 0x3f4003dd },
+ { 0x5fffc, 0xf5c00160 },
+ { 0x5024c, 0x3a4003df },
+ { 0x5fffc, 0xf5c00172 },
+ { 0x50250, 0x354003e1 },
+ { 0x5fffc, 0xf5c00184 },
+ { 0x50254, 0x304003e3 },
+ { 0x5fffc, 0xf6000195 },
+ { 0x50258, 0x2b0003e6 },
+ { 0x5fffc, 0xf64001a6 },
+ { 0x5025c, 0x260003e8 },
+ { 0x5fffc, 0xf6c001b4 },
+ { 0x50260, 0x214003eb },
+ { 0x5fffc, 0xf78001c2 },
+ { 0x50264, 0x1c4003ee },
+ { 0x5fffc, 0xf80001cf },
+ { 0x50268, 0x17c003f1 },
+ { 0x5fffc, 0xf90001db },
+ { 0x5026c, 0x134003f3 },
+ { 0x5fffc, 0xfa0001e5 },
+ { 0x50270, 0xf0003f6 },
+ { 0x5fffc, 0xfb4001ee },
+ { 0x50274, 0xac003f9 },
+ { 0x5fffc, 0xfcc001f5 },
+ { 0x50278, 0x70003fb },
+ { 0x5fffc, 0xfe4001fb },
+ { 0x5027c, 0x34003fe },
+};
+
+const struct ppp_table mdp_gaussian_blur_table[PPP_BLUR_SCALE_MAX] = {
+ /* max variance */
+ { 0x5fffc, 0x20000080 },
+ { 0x50280, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50284, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50288, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x5028c, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50290, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50294, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50298, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x5029c, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502a0, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502a4, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502a8, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502ac, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502b0, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502b4, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502b8, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502bc, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502c0, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502c4, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502c8, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502cc, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502d0, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502d4, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502d8, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502dc, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502e0, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502e4, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502e8, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502ec, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502f0, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502f4, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502f8, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502fc, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50300, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50304, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50308, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x5030c, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50310, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50314, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50318, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x5031c, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50320, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50324, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50328, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x5032c, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50330, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50334, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50338, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x5033c, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50340, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50344, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50348, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x5034c, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50350, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50354, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50358, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x5035c, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50360, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50364, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50368, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x5036c, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50370, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50374, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50378, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x5037c, 0x20000080 },
+};
+
+const struct ppp_table downscale_x_table_pt2topt4[] = {
+ { 0x5fffc, 0x740008c },
+ { 0x50280, 0x33800088 },
+ { 0x5fffc, 0x800008e },
+ { 0x50284, 0x33400084 },
+ { 0x5fffc, 0x8400092 },
+ { 0x50288, 0x33000080 },
+ { 0x5fffc, 0x9000094 },
+ { 0x5028c, 0x3300007b },
+ { 0x5fffc, 0x9c00098 },
+ { 0x50290, 0x32400077 },
+ { 0x5fffc, 0xa40009b },
+ { 0x50294, 0x32000073 },
+ { 0x5fffc, 0xb00009d },
+ { 0x50298, 0x31c0006f },
+ { 0x5fffc, 0xbc000a0 },
+ { 0x5029c, 0x3140006b },
+ { 0x5fffc, 0xc8000a2 },
+ { 0x502a0, 0x31000067 },
+ { 0x5fffc, 0xd8000a5 },
+ { 0x502a4, 0x30800062 },
+ { 0x5fffc, 0xe4000a8 },
+ { 0x502a8, 0x2fc0005f },
+ { 0x5fffc, 0xec000aa },
+ { 0x502ac, 0x2fc0005b },
+ { 0x5fffc, 0xf8000ad },
+ { 0x502b0, 0x2f400057 },
+ { 0x5fffc, 0x108000b0 },
+ { 0x502b4, 0x2e400054 },
+ { 0x5fffc, 0x114000b2 },
+ { 0x502b8, 0x2e000050 },
+ { 0x5fffc, 0x124000b4 },
+ { 0x502bc, 0x2d80004c },
+ { 0x5fffc, 0x130000b6 },
+ { 0x502c0, 0x2d000049 },
+ { 0x5fffc, 0x140000b8 },
+ { 0x502c4, 0x2c800045 },
+ { 0x5fffc, 0x150000b9 },
+ { 0x502c8, 0x2c000042 },
+ { 0x5fffc, 0x15c000bd },
+ { 0x502cc, 0x2b40003e },
+ { 0x5fffc, 0x16c000bf },
+ { 0x502d0, 0x2a80003b },
+ { 0x5fffc, 0x17c000bf },
+ { 0x502d4, 0x2a000039 },
+ { 0x5fffc, 0x188000c2 },
+ { 0x502d8, 0x29400036 },
+ { 0x5fffc, 0x19c000c4 },
+ { 0x502dc, 0x28800032 },
+ { 0x5fffc, 0x1ac000c5 },
+ { 0x502e0, 0x2800002f },
+ { 0x5fffc, 0x1bc000c7 },
+ { 0x502e4, 0x2740002c },
+ { 0x5fffc, 0x1cc000c8 },
+ { 0x502e8, 0x26c00029 },
+ { 0x5fffc, 0x1dc000c9 },
+ { 0x502ec, 0x26000027 },
+ { 0x5fffc, 0x1ec000cc },
+ { 0x502f0, 0x25000024 },
+ { 0x5fffc, 0x200000cc },
+ { 0x502f4, 0x24800021 },
+ { 0x5fffc, 0x210000cd },
+ { 0x502f8, 0x23800020 },
+ { 0x5fffc, 0x220000ce },
+ { 0x502fc, 0x2300001d },
+};
+
+static const struct ppp_table downscale_x_table_pt4topt6[] = {
+ { 0x5fffc, 0x740008c },
+ { 0x50280, 0x33800088 },
+ { 0x5fffc, 0x800008e },
+ { 0x50284, 0x33400084 },
+ { 0x5fffc, 0x8400092 },
+ { 0x50288, 0x33000080 },
+ { 0x5fffc, 0x9000094 },
+ { 0x5028c, 0x3300007b },
+ { 0x5fffc, 0x9c00098 },
+ { 0x50290, 0x32400077 },
+ { 0x5fffc, 0xa40009b },
+ { 0x50294, 0x32000073 },
+ { 0x5fffc, 0xb00009d },
+ { 0x50298, 0x31c0006f },
+ { 0x5fffc, 0xbc000a0 },
+ { 0x5029c, 0x3140006b },
+ { 0x5fffc, 0xc8000a2 },
+ { 0x502a0, 0x31000067 },
+ { 0x5fffc, 0xd8000a5 },
+ { 0x502a4, 0x30800062 },
+ { 0x5fffc, 0xe4000a8 },
+ { 0x502a8, 0x2fc0005f },
+ { 0x5fffc, 0xec000aa },
+ { 0x502ac, 0x2fc0005b },
+ { 0x5fffc, 0xf8000ad },
+ { 0x502b0, 0x2f400057 },
+ { 0x5fffc, 0x108000b0 },
+ { 0x502b4, 0x2e400054 },
+ { 0x5fffc, 0x114000b2 },
+ { 0x502b8, 0x2e000050 },
+ { 0x5fffc, 0x124000b4 },
+ { 0x502bc, 0x2d80004c },
+ { 0x5fffc, 0x130000b6 },
+ { 0x502c0, 0x2d000049 },
+ { 0x5fffc, 0x140000b8 },
+ { 0x502c4, 0x2c800045 },
+ { 0x5fffc, 0x150000b9 },
+ { 0x502c8, 0x2c000042 },
+ { 0x5fffc, 0x15c000bd },
+ { 0x502cc, 0x2b40003e },
+ { 0x5fffc, 0x16c000bf },
+ { 0x502d0, 0x2a80003b },
+ { 0x5fffc, 0x17c000bf },
+ { 0x502d4, 0x2a000039 },
+ { 0x5fffc, 0x188000c2 },
+ { 0x502d8, 0x29400036 },
+ { 0x5fffc, 0x19c000c4 },
+ { 0x502dc, 0x28800032 },
+ { 0x5fffc, 0x1ac000c5 },
+ { 0x502e0, 0x2800002f },
+ { 0x5fffc, 0x1bc000c7 },
+ { 0x502e4, 0x2740002c },
+ { 0x5fffc, 0x1cc000c8 },
+ { 0x502e8, 0x26c00029 },
+ { 0x5fffc, 0x1dc000c9 },
+ { 0x502ec, 0x26000027 },
+ { 0x5fffc, 0x1ec000cc },
+ { 0x502f0, 0x25000024 },
+ { 0x5fffc, 0x200000cc },
+ { 0x502f4, 0x24800021 },
+ { 0x5fffc, 0x210000cd },
+ { 0x502f8, 0x23800020 },
+ { 0x5fffc, 0x220000ce },
+ { 0x502fc, 0x2300001d },
+};
+
+static const struct ppp_table downscale_x_table_pt6topt8[] = {
+ { 0x5fffc, 0xfe000070 },
+ { 0x50280, 0x4bc00068 },
+ { 0x5fffc, 0xfe000078 },
+ { 0x50284, 0x4bc00060 },
+ { 0x5fffc, 0xfe000080 },
+ { 0x50288, 0x4b800059 },
+ { 0x5fffc, 0xfe000089 },
+ { 0x5028c, 0x4b000052 },
+ { 0x5fffc, 0xfe400091 },
+ { 0x50290, 0x4a80004b },
+ { 0x5fffc, 0xfe40009a },
+ { 0x50294, 0x4a000044 },
+ { 0x5fffc, 0xfe8000a3 },
+ { 0x50298, 0x4940003d },
+ { 0x5fffc, 0xfec000ac },
+ { 0x5029c, 0x48400037 },
+ { 0x5fffc, 0xff0000b4 },
+ { 0x502a0, 0x47800031 },
+ { 0x5fffc, 0xff8000bd },
+ { 0x502a4, 0x4640002b },
+ { 0x5fffc, 0xc5 },
+ { 0x502a8, 0x45000026 },
+ { 0x5fffc, 0x8000ce },
+ { 0x502ac, 0x43800021 },
+ { 0x5fffc, 0x10000d6 },
+ { 0x502b0, 0x4240001c },
+ { 0x5fffc, 0x18000df },
+ { 0x502b4, 0x40800018 },
+ { 0x5fffc, 0x24000e6 },
+ { 0x502b8, 0x3f000014 },
+ { 0x5fffc, 0x30000ee },
+ { 0x502bc, 0x3d400010 },
+ { 0x5fffc, 0x40000f5 },
+ { 0x502c0, 0x3b80000c },
+ { 0x5fffc, 0x50000fc },
+ { 0x502c4, 0x39800009 },
+ { 0x5fffc, 0x6000102 },
+ { 0x502c8, 0x37c00006 },
+ { 0x5fffc, 0x7000109 },
+ { 0x502cc, 0x35800004 },
+ { 0x5fffc, 0x840010e },
+ { 0x502d0, 0x33800002 },
+ { 0x5fffc, 0x9800114 },
+ { 0x502d4, 0x31400000 },
+ { 0x5fffc, 0xac00119 },
+ { 0x502d8, 0x2f4003fe },
+ { 0x5fffc, 0xc40011e },
+ { 0x502dc, 0x2d0003fc },
+ { 0x5fffc, 0xdc00121 },
+ { 0x502e0, 0x2b0003fb },
+ { 0x5fffc, 0xf400125 },
+ { 0x502e4, 0x28c003fa },
+ { 0x5fffc, 0x11000128 },
+ { 0x502e8, 0x268003f9 },
+ { 0x5fffc, 0x12c0012a },
+ { 0x502ec, 0x244003f9 },
+ { 0x5fffc, 0x1480012c },
+ { 0x502f0, 0x224003f8 },
+ { 0x5fffc, 0x1640012e },
+ { 0x502f4, 0x200003f8 },
+ { 0x5fffc, 0x1800012f },
+ { 0x502f8, 0x1e0003f8 },
+ { 0x5fffc, 0x1a00012f },
+ { 0x502fc, 0x1c0003f8 },
+};
+
+static const struct ppp_table downscale_x_table_pt8topt1[] = {
+ { 0x5fffc, 0x0 },
+ { 0x50280, 0x7fc00000 },
+ { 0x5fffc, 0xff80000d },
+ { 0x50284, 0x7ec003f9 },
+ { 0x5fffc, 0xfec0001c },
+ { 0x50288, 0x7d4003f3 },
+ { 0x5fffc, 0xfe40002b },
+ { 0x5028c, 0x7b8003ed },
+ { 0x5fffc, 0xfd80003c },
+ { 0x50290, 0x794003e8 },
+ { 0x5fffc, 0xfcc0004d },
+ { 0x50294, 0x76c003e4 },
+ { 0x5fffc, 0xfc40005f },
+ { 0x50298, 0x73c003e0 },
+ { 0x5fffc, 0xfb800071 },
+ { 0x5029c, 0x708003de },
+ { 0x5fffc, 0xfac00085 },
+ { 0x502a0, 0x6d0003db },
+ { 0x5fffc, 0xfa000098 },
+ { 0x502a4, 0x698003d9 },
+ { 0x5fffc, 0xf98000ac },
+ { 0x502a8, 0x654003d8 },
+ { 0x5fffc, 0xf8c000c1 },
+ { 0x502ac, 0x610003d7 },
+ { 0x5fffc, 0xf84000d5 },
+ { 0x502b0, 0x5c8003d7 },
+ { 0x5fffc, 0xf7c000e9 },
+ { 0x502b4, 0x580003d7 },
+ { 0x5fffc, 0xf74000fd },
+ { 0x502b8, 0x534003d8 },
+ { 0x5fffc, 0xf6c00112 },
+ { 0x502bc, 0x4e8003d8 },
+ { 0x5fffc, 0xf6800126 },
+ { 0x502c0, 0x494003da },
+ { 0x5fffc, 0xf600013a },
+ { 0x502c4, 0x448003db },
+ { 0x5fffc, 0xf600014d },
+ { 0x502c8, 0x3f4003dd },
+ { 0x5fffc, 0xf5c00160 },
+ { 0x502cc, 0x3a4003df },
+ { 0x5fffc, 0xf5c00172 },
+ { 0x502d0, 0x354003e1 },
+ { 0x5fffc, 0xf5c00184 },
+ { 0x502d4, 0x304003e3 },
+ { 0x5fffc, 0xf6000195 },
+ { 0x502d8, 0x2b0003e6 },
+ { 0x5fffc, 0xf64001a6 },
+ { 0x502dc, 0x260003e8 },
+ { 0x5fffc, 0xf6c001b4 },
+ { 0x502e0, 0x214003eb },
+ { 0x5fffc, 0xf78001c2 },
+ { 0x502e4, 0x1c4003ee },
+ { 0x5fffc, 0xf80001cf },
+ { 0x502e8, 0x17c003f1 },
+ { 0x5fffc, 0xf90001db },
+ { 0x502ec, 0x134003f3 },
+ { 0x5fffc, 0xfa0001e5 },
+ { 0x502f0, 0xf0003f6 },
+ { 0x5fffc, 0xfb4001ee },
+ { 0x502f4, 0xac003f9 },
+ { 0x5fffc, 0xfcc001f5 },
+ { 0x502f8, 0x70003fb },
+ { 0x5fffc, 0xfe4001fb },
+ { 0x502fc, 0x34003fe },
+};
+
+static const struct ppp_table *downscale_x_table[PPP_DOWNSCALE_MAX] = {
+ [PPP_DOWNSCALE_PT2TOPT4] = downscale_x_table_pt2topt4,
+ [PPP_DOWNSCALE_PT4TOPT6] = downscale_x_table_pt4topt6,
+ [PPP_DOWNSCALE_PT6TOPT8] = downscale_x_table_pt6topt8,
+ [PPP_DOWNSCALE_PT8TOPT1] = downscale_x_table_pt8topt1,
+};
+
+static const struct ppp_table downscale_y_table_pt2topt4[] = {
+ { 0x5fffc, 0x740008c },
+ { 0x50300, 0x33800088 },
+ { 0x5fffc, 0x800008e },
+ { 0x50304, 0x33400084 },
+ { 0x5fffc, 0x8400092 },
+ { 0x50308, 0x33000080 },
+ { 0x5fffc, 0x9000094 },
+ { 0x5030c, 0x3300007b },
+ { 0x5fffc, 0x9c00098 },
+ { 0x50310, 0x32400077 },
+ { 0x5fffc, 0xa40009b },
+ { 0x50314, 0x32000073 },
+ { 0x5fffc, 0xb00009d },
+ { 0x50318, 0x31c0006f },
+ { 0x5fffc, 0xbc000a0 },
+ { 0x5031c, 0x3140006b },
+ { 0x5fffc, 0xc8000a2 },
+ { 0x50320, 0x31000067 },
+ { 0x5fffc, 0xd8000a5 },
+ { 0x50324, 0x30800062 },
+ { 0x5fffc, 0xe4000a8 },
+ { 0x50328, 0x2fc0005f },
+ { 0x5fffc, 0xec000aa },
+ { 0x5032c, 0x2fc0005b },
+ { 0x5fffc, 0xf8000ad },
+ { 0x50330, 0x2f400057 },
+ { 0x5fffc, 0x108000b0 },
+ { 0x50334, 0x2e400054 },
+ { 0x5fffc, 0x114000b2 },
+ { 0x50338, 0x2e000050 },
+ { 0x5fffc, 0x124000b4 },
+ { 0x5033c, 0x2d80004c },
+ { 0x5fffc, 0x130000b6 },
+ { 0x50340, 0x2d000049 },
+ { 0x5fffc, 0x140000b8 },
+ { 0x50344, 0x2c800045 },
+ { 0x5fffc, 0x150000b9 },
+ { 0x50348, 0x2c000042 },
+ { 0x5fffc, 0x15c000bd },
+ { 0x5034c, 0x2b40003e },
+ { 0x5fffc, 0x16c000bf },
+ { 0x50350, 0x2a80003b },
+ { 0x5fffc, 0x17c000bf },
+ { 0x50354, 0x2a000039 },
+ { 0x5fffc, 0x188000c2 },
+ { 0x50358, 0x29400036 },
+ { 0x5fffc, 0x19c000c4 },
+ { 0x5035c, 0x28800032 },
+ { 0x5fffc, 0x1ac000c5 },
+ { 0x50360, 0x2800002f },
+ { 0x5fffc, 0x1bc000c7 },
+ { 0x50364, 0x2740002c },
+ { 0x5fffc, 0x1cc000c8 },
+ { 0x50368, 0x26c00029 },
+ { 0x5fffc, 0x1dc000c9 },
+ { 0x5036c, 0x26000027 },
+ { 0x5fffc, 0x1ec000cc },
+ { 0x50370, 0x25000024 },
+ { 0x5fffc, 0x200000cc },
+ { 0x50374, 0x24800021 },
+ { 0x5fffc, 0x210000cd },
+ { 0x50378, 0x23800020 },
+ { 0x5fffc, 0x220000ce },
+ { 0x5037c, 0x2300001d },
+};
+
+static const struct ppp_table downscale_y_table_pt4topt6[] = {
+ { 0x5fffc, 0x740008c },
+ { 0x50300, 0x33800088 },
+ { 0x5fffc, 0x800008e },
+ { 0x50304, 0x33400084 },
+ { 0x5fffc, 0x8400092 },
+ { 0x50308, 0x33000080 },
+ { 0x5fffc, 0x9000094 },
+ { 0x5030c, 0x3300007b },
+ { 0x5fffc, 0x9c00098 },
+ { 0x50310, 0x32400077 },
+ { 0x5fffc, 0xa40009b },
+ { 0x50314, 0x32000073 },
+ { 0x5fffc, 0xb00009d },
+ { 0x50318, 0x31c0006f },
+ { 0x5fffc, 0xbc000a0 },
+ { 0x5031c, 0x3140006b },
+ { 0x5fffc, 0xc8000a2 },
+ { 0x50320, 0x31000067 },
+ { 0x5fffc, 0xd8000a5 },
+ { 0x50324, 0x30800062 },
+ { 0x5fffc, 0xe4000a8 },
+ { 0x50328, 0x2fc0005f },
+ { 0x5fffc, 0xec000aa },
+ { 0x5032c, 0x2fc0005b },
+ { 0x5fffc, 0xf8000ad },
+ { 0x50330, 0x2f400057 },
+ { 0x5fffc, 0x108000b0 },
+ { 0x50334, 0x2e400054 },
+ { 0x5fffc, 0x114000b2 },
+ { 0x50338, 0x2e000050 },
+ { 0x5fffc, 0x124000b4 },
+ { 0x5033c, 0x2d80004c },
+ { 0x5fffc, 0x130000b6 },
+ { 0x50340, 0x2d000049 },
+ { 0x5fffc, 0x140000b8 },
+ { 0x50344, 0x2c800045 },
+ { 0x5fffc, 0x150000b9 },
+ { 0x50348, 0x2c000042 },
+ { 0x5fffc, 0x15c000bd },
+ { 0x5034c, 0x2b40003e },
+ { 0x5fffc, 0x16c000bf },
+ { 0x50350, 0x2a80003b },
+ { 0x5fffc, 0x17c000bf },
+ { 0x50354, 0x2a000039 },
+ { 0x5fffc, 0x188000c2 },
+ { 0x50358, 0x29400036 },
+ { 0x5fffc, 0x19c000c4 },
+ { 0x5035c, 0x28800032 },
+ { 0x5fffc, 0x1ac000c5 },
+ { 0x50360, 0x2800002f },
+ { 0x5fffc, 0x1bc000c7 },
+ { 0x50364, 0x2740002c },
+ { 0x5fffc, 0x1cc000c8 },
+ { 0x50368, 0x26c00029 },
+ { 0x5fffc, 0x1dc000c9 },
+ { 0x5036c, 0x26000027 },
+ { 0x5fffc, 0x1ec000cc },
+ { 0x50370, 0x25000024 },
+ { 0x5fffc, 0x200000cc },
+ { 0x50374, 0x24800021 },
+ { 0x5fffc, 0x210000cd },
+ { 0x50378, 0x23800020 },
+ { 0x5fffc, 0x220000ce },
+ { 0x5037c, 0x2300001d },
+};
+
+static const struct ppp_table downscale_y_table_pt6topt8[] = {
+ { 0x5fffc, 0xfe000070 },
+ { 0x50300, 0x4bc00068 },
+ { 0x5fffc, 0xfe000078 },
+ { 0x50304, 0x4bc00060 },
+ { 0x5fffc, 0xfe000080 },
+ { 0x50308, 0x4b800059 },
+ { 0x5fffc, 0xfe000089 },
+ { 0x5030c, 0x4b000052 },
+ { 0x5fffc, 0xfe400091 },
+ { 0x50310, 0x4a80004b },
+ { 0x5fffc, 0xfe40009a },
+ { 0x50314, 0x4a000044 },
+ { 0x5fffc, 0xfe8000a3 },
+ { 0x50318, 0x4940003d },
+ { 0x5fffc, 0xfec000ac },
+ { 0x5031c, 0x48400037 },
+ { 0x5fffc, 0xff0000b4 },
+ { 0x50320, 0x47800031 },
+ { 0x5fffc, 0xff8000bd },
+ { 0x50324, 0x4640002b },
+ { 0x5fffc, 0xc5 },
+ { 0x50328, 0x45000026 },
+ { 0x5fffc, 0x8000ce },
+ { 0x5032c, 0x43800021 },
+ { 0x5fffc, 0x10000d6 },
+ { 0x50330, 0x4240001c },
+ { 0x5fffc, 0x18000df },
+ { 0x50334, 0x40800018 },
+ { 0x5fffc, 0x24000e6 },
+ { 0x50338, 0x3f000014 },
+ { 0x5fffc, 0x30000ee },
+ { 0x5033c, 0x3d400010 },
+ { 0x5fffc, 0x40000f5 },
+ { 0x50340, 0x3b80000c },
+ { 0x5fffc, 0x50000fc },
+ { 0x50344, 0x39800009 },
+ { 0x5fffc, 0x6000102 },
+ { 0x50348, 0x37c00006 },
+ { 0x5fffc, 0x7000109 },
+ { 0x5034c, 0x35800004 },
+ { 0x5fffc, 0x840010e },
+ { 0x50350, 0x33800002 },
+ { 0x5fffc, 0x9800114 },
+ { 0x50354, 0x31400000 },
+ { 0x5fffc, 0xac00119 },
+ { 0x50358, 0x2f4003fe },
+ { 0x5fffc, 0xc40011e },
+ { 0x5035c, 0x2d0003fc },
+ { 0x5fffc, 0xdc00121 },
+ { 0x50360, 0x2b0003fb },
+ { 0x5fffc, 0xf400125 },
+ { 0x50364, 0x28c003fa },
+ { 0x5fffc, 0x11000128 },
+ { 0x50368, 0x268003f9 },
+ { 0x5fffc, 0x12c0012a },
+ { 0x5036c, 0x244003f9 },
+ { 0x5fffc, 0x1480012c },
+ { 0x50370, 0x224003f8 },
+ { 0x5fffc, 0x1640012e },
+ { 0x50374, 0x200003f8 },
+ { 0x5fffc, 0x1800012f },
+ { 0x50378, 0x1e0003f8 },
+ { 0x5fffc, 0x1a00012f },
+ { 0x5037c, 0x1c0003f8 },
+};
+
+static const struct ppp_table downscale_y_table_pt8topt1[] = {
+ { 0x5fffc, 0x0 },
+ { 0x50300, 0x7fc00000 },
+ { 0x5fffc, 0xff80000d },
+ { 0x50304, 0x7ec003f9 },
+ { 0x5fffc, 0xfec0001c },
+ { 0x50308, 0x7d4003f3 },
+ { 0x5fffc, 0xfe40002b },
+ { 0x5030c, 0x7b8003ed },
+ { 0x5fffc, 0xfd80003c },
+ { 0x50310, 0x794003e8 },
+ { 0x5fffc, 0xfcc0004d },
+ { 0x50314, 0x76c003e4 },
+ { 0x5fffc, 0xfc40005f },
+ { 0x50318, 0x73c003e0 },
+ { 0x5fffc, 0xfb800071 },
+ { 0x5031c, 0x708003de },
+ { 0x5fffc, 0xfac00085 },
+ { 0x50320, 0x6d0003db },
+ { 0x5fffc, 0xfa000098 },
+ { 0x50324, 0x698003d9 },
+ { 0x5fffc, 0xf98000ac },
+ { 0x50328, 0x654003d8 },
+ { 0x5fffc, 0xf8c000c1 },
+ { 0x5032c, 0x610003d7 },
+ { 0x5fffc, 0xf84000d5 },
+ { 0x50330, 0x5c8003d7 },
+ { 0x5fffc, 0xf7c000e9 },
+ { 0x50334, 0x580003d7 },
+ { 0x5fffc, 0xf74000fd },
+ { 0x50338, 0x534003d8 },
+ { 0x5fffc, 0xf6c00112 },
+ { 0x5033c, 0x4e8003d8 },
+ { 0x5fffc, 0xf6800126 },
+ { 0x50340, 0x494003da },
+ { 0x5fffc, 0xf600013a },
+ { 0x50344, 0x448003db },
+ { 0x5fffc, 0xf600014d },
+ { 0x50348, 0x3f4003dd },
+ { 0x5fffc, 0xf5c00160 },
+ { 0x5034c, 0x3a4003df },
+ { 0x5fffc, 0xf5c00172 },
+ { 0x50350, 0x354003e1 },
+ { 0x5fffc, 0xf5c00184 },
+ { 0x50354, 0x304003e3 },
+ { 0x5fffc, 0xf6000195 },
+ { 0x50358, 0x2b0003e6 },
+ { 0x5fffc, 0xf64001a6 },
+ { 0x5035c, 0x260003e8 },
+ { 0x5fffc, 0xf6c001b4 },
+ { 0x50360, 0x214003eb },
+ { 0x5fffc, 0xf78001c2 },
+ { 0x50364, 0x1c4003ee },
+ { 0x5fffc, 0xf80001cf },
+ { 0x50368, 0x17c003f1 },
+ { 0x5fffc, 0xf90001db },
+ { 0x5036c, 0x134003f3 },
+ { 0x5fffc, 0xfa0001e5 },
+ { 0x50370, 0xf0003f6 },
+ { 0x5fffc, 0xfb4001ee },
+ { 0x50374, 0xac003f9 },
+ { 0x5fffc, 0xfcc001f5 },
+ { 0x50378, 0x70003fb },
+ { 0x5fffc, 0xfe4001fb },
+ { 0x5037c, 0x34003fe },
+};
+
+static const struct ppp_table *downscale_y_table[PPP_DOWNSCALE_MAX] = {
+ [PPP_DOWNSCALE_PT2TOPT4] = downscale_y_table_pt2topt4,
+ [PPP_DOWNSCALE_PT4TOPT6] = downscale_y_table_pt4topt6,
+ [PPP_DOWNSCALE_PT6TOPT8] = downscale_y_table_pt6topt8,
+ [PPP_DOWNSCALE_PT8TOPT1] = downscale_y_table_pt8topt1,
+};
+
+void ppp_load_table(const struct ppp_table *table, int len)
+{
+ int i;
+ for (i = 0; i < len; i++)
+ PPP_WRITEL(table[i].val, table[i].reg);
+}
+
+void ppp_load_up_lut(void)
+{
+ ppp_load_table(upscale_table,
+ PPP_UPSCALE_MAX);
+}
+
+void ppp_load_gaussian_lut(void)
+{
+ ppp_load_table(mdp_gaussian_blur_table,
+ PPP_BLUR_SCALE_MAX);
+}
+
+void ppp_load_x_scale_table(int idx)
+{
+ ppp_load_table(downscale_x_table[idx], 64);
+}
+
+void ppp_load_y_scale_table(int idx)
+{
+ ppp_load_table(downscale_y_table[idx], 64);
+}
+
+uint32_t ppp_bpp(uint32_t type)
+{
+ if (type > MDP_IMGTYPE_LIMIT)
+ return 0;
+ return bytes_per_pixel[type];
+}
+
+uint32_t ppp_src_config(uint32_t type)
+{
+ if (type > MDP_IMGTYPE_LIMIT)
+ return 0;
+ return src_cfg_lut[type];
+}
+
+uint32_t ppp_out_config(uint32_t type)
+{
+ if (type > MDP_IMGTYPE_LIMIT)
+ return 0;
+ return out_cfg_lut[type];
+}
+
+uint32_t ppp_pack_pattern(uint32_t type)
+{
+ if (type > MDP_IMGTYPE_LIMIT)
+ return 0;
+ return pack_patt_lut[type];
+}
+
+uint32_t ppp_dst_op_reg(uint32_t type)
+{
+ if (type > MDP_IMGTYPE_LIMIT)
+ return 0;
+ return dst_op_reg[type];
+}
+
+uint32_t ppp_src_op_reg(uint32_t type)
+{
+ if (type > MDP_IMGTYPE_LIMIT)
+ return 0;
+ return src_op_reg[type];
+}
+
+bool ppp_per_p_alpha(uint32_t type)
+{
+ if (type > MDP_IMGTYPE_LIMIT)
+ return 0;
+ return per_pixel_alpha[type];
+}
+
+bool ppp_multi_plane(uint32_t type)
+{
+ if (type > MDP_IMGTYPE_LIMIT)
+ return 0;
+ return multi_plane[type];
+}
+
+uint32_t *ppp_default_pre_lut(void)
+{
+ return default_pre_lut_val;
+}
+
+uint32_t *ppp_default_post_lut(void)
+{
+ return default_post_lut_val;
+}
+
+struct ppp_csc_table *ppp_csc_rgb2yuv(void)
+{
+ return &rgb2yuv;
+}
+
+struct ppp_csc_table *ppp_csc_table2(void)
+{
+ return &default_table2;
+}
diff --git a/drivers/video/msm/mdss/mdp3_ppp_hwio.c b/drivers/video/msm/mdss/mdp3_ppp_hwio.c
new file mode 100644
index 0000000..309effc
--- /dev/null
+++ b/drivers/video/msm/mdss/mdp3_ppp_hwio.c
@@ -0,0 +1,1184 @@
+/* Copyright (c) 2007, 2012-2013 The Linux Foundation. All rights reserved.
+ * Copyright (C) 2007 Google Incorporated
+ *
+ * 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/file.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/uaccess.h>
+#include "linux/proc_fs.h"
+
+#include "mdss_fb.h"
+#include "mdp3_ppp.h"
+#include "mdp3_hwio.h"
+
+/* SHIM Q Factor */
+#define PHI_Q_FACTOR 29
+#define PQF_PLUS_5 (PHI_Q_FACTOR + 5) /* due to 32 phases */
+#define PQF_PLUS_4 (PHI_Q_FACTOR + 4)
+#define PQF_PLUS_2 (PHI_Q_FACTOR + 2) /* to get 4.0 */
+#define PQF_MINUS_2 (PHI_Q_FACTOR - 2) /* to get 0.25 */
+#define PQF_PLUS_5_PLUS_2 (PQF_PLUS_5 + 2)
+#define PQF_PLUS_5_MINUS_2 (PQF_PLUS_5 - 2)
+
+static long long mdp_do_div(long long num, long long den)
+{
+ do_div(num, den);
+ return num;
+}
+
+static int mdp_calc_scale_params(uint32_t org, uint32_t dim_in,
+ uint32_t dim_out, bool is_W, int32_t *phase_init_ptr,
+ uint32_t *phase_step_ptr)
+{
+ bool rpa_on = false;
+ int init_phase = 0;
+ uint64_t numer = 0;
+ uint64_t denom = 0;
+ int64_t point5 = 1;
+ int64_t one = 1;
+ int64_t k1, k2, k3, k4; /* linear equation coefficients */
+ uint64_t int_mask;
+ uint64_t fract_mask;
+ uint64_t Os;
+ int64_t Osprime;
+ int64_t Od;
+ int64_t Odprime;
+ int64_t Oreq;
+ uint32_t mult;
+
+ /*
+ * The phase accumulator should really be rational for all cases in a
+ * general purpose polyphase scaler for a tiled architecture with
+ * non-zero * origin capability because there is no way to represent
+ * certain scale factors in fixed point regardless of precision.
+ * The error incurred in attempting to use fixed point is most
+ * eggregious for SF where 1/SF is an integral multiple of 1/3.
+ *
+ * Set the RPA flag for this dimension.
+ *
+ * In order for 1/SF (dim_in/dim_out) to be an integral multiple of
+ * 1/3, dim_out must be an integral multiple of 3.
+ */
+ if (!(dim_out % 3)) {
+ mult = dim_out / 3;
+ rpa_on = (!(dim_in % mult));
+ }
+
+ numer = dim_out;
+ denom = dim_in;
+
+ /*
+ * convert to U30.34 before division
+ *
+ * The K vectors carry 4 extra bits of precision
+ * and are rounded.
+ *
+ * We initially go 5 bits over then round by adding
+ * 1 and right shifting by 1
+ * so final result is U31.33
+ */
+ numer <<= PQF_PLUS_5;
+
+ /* now calculate the scale factor (aka k3) */
+ k3 = ((mdp_do_div(numer, denom) + 1) >> 1);
+
+ /* check scale factor for legal range [0.25 - 4.0] */
+ if (((k3 >> 4) < (1LL << PQF_MINUS_2)) ||
+ ((k3 >> 4) > (1LL << PQF_PLUS_2))) {
+ return -EINVAL;
+ }
+
+ /* calculate inverse scale factor (aka k1) for phase init */
+ numer = dim_in;
+ denom = dim_out;
+ numer <<= PQF_PLUS_5;
+ k1 = ((mdp_do_div(numer, denom) + 1) >> 1);
+
+ /*
+ * calculate initial phase and ROI overfetch
+ */
+ /* convert point5 & one to S39.24 (will always be positive) */
+ point5 <<= (PQF_PLUS_4 - 1);
+ one <<= PQF_PLUS_4;
+ k2 = ((k1 - one) >> 1);
+ init_phase = (int)(k2 >> 4);
+ k4 = ((k3 - one) >> 1);
+ if (k3 != one) {
+ /* calculate the masks */
+ fract_mask = one - 1;
+ int_mask = ~fract_mask;
+
+ if (!rpa_on) {
+ /*
+ * FIXED POINT IMPLEMENTATION
+ */
+ if (org) {
+ /*
+ * The complicated case; ROI origin != 0
+ * init_phase needs to be adjusted
+ * OF is also position dependent
+ */
+
+ /* map (org - .5) into destination space */
+ Os = ((uint64_t) org << 1) - 1;
+ Od = ((k3 * Os) >> 1) + k4;
+
+ /* take the ceiling */
+ Odprime = (Od & int_mask);
+ if (Odprime != Od)
+ Odprime += one;
+
+ /* now map that back to source space */
+ Osprime = (k1 * (Odprime >> PQF_PLUS_4)) + k2;
+
+ /* then floor & decrement to calc the required
+ starting coordinate */
+ Oreq = (Osprime & int_mask) - one;
+
+ /* calculate initial phase */
+ init_phase = (int)((Osprime - Oreq) >> 4);
+ }
+ } else {
+ /*
+ * RPA IMPLEMENTATION
+ *
+ * init_phase needs to be calculated in all RPA_on cases
+ * because it's a numerator, not a fixed point value.
+ */
+
+ /* map (org - .5) into destination space */
+ Os = ((uint64_t) org << PQF_PLUS_4) - point5;
+ Od = mdp_do_div((dim_out * (Os + point5)),
+ dim_in);
+ Od -= point5;
+
+ /* take the ceiling */
+ Odprime = (Od & int_mask);
+ if (Odprime != Od)
+ Odprime += one;
+
+ /* now map that back to source space */
+ Osprime =
+ mdp_do_div((dim_in * (Odprime + point5)),
+ dim_out);
+ Osprime -= point5;
+
+ /* then floor & decrement to calculate the required
+ starting coordinate */
+ Oreq = (Osprime & int_mask) - one;
+
+ /* calculate initial phase */
+ init_phase = (int)((Osprime - Oreq) >> 4);
+ }
+ }
+
+ /* return the scale parameters */
+ *phase_init_ptr = init_phase;
+ *phase_step_ptr = (uint32_t) (k1 >> 4);
+
+ return 0;
+}
+
+static int scale_idx(int factor)
+{
+ int idx;
+
+ if (factor > 80)
+ idx = PPP_DOWNSCALE_PT8TOPT1;
+ else if (factor > 60)
+ idx = PPP_DOWNSCALE_PT6TOPT8;
+ else if (factor > 40)
+ idx = PPP_DOWNSCALE_PT4TOPT6;
+ else
+ idx = PPP_DOWNSCALE_PT2TOPT4;
+
+ return idx;
+}
+
+inline int32_t comp_conv_rgb2yuv(int32_t comp, int32_t y_high,
+ int32_t y_low, int32_t c_high, int32_t c_low)
+{
+ if (comp < 0)
+ comp = 0;
+ if (comp > 255)
+ comp = 255;
+
+ /* clamp */
+ if (comp < y_low)
+ comp = y_low;
+ if (comp > y_high)
+ comp = y_high;
+ return comp;
+}
+
+static uint32_t conv_rgb2yuv(uint32_t input_pixel,
+ uint16_t *matrix_vector,
+ uint16_t *bv,
+ uint16_t *clamp_vector)
+{
+ uint8_t input_C2, input_C0, input_C1;
+ uint32_t output;
+ int32_t comp_C2, comp_C1, comp_C0, temp;
+ int32_t temp1, temp2, temp3;
+ int32_t matrix[9];
+ int32_t bias_vector[3];
+ int32_t Y_low_limit, Y_high_limit, C_low_limit, C_high_limit;
+ int32_t i;
+
+ input_C2 = (input_pixel >> 16) & 0xFF;
+ input_C1 = (input_pixel >> 8) & 0xFF;
+ input_C0 = (input_pixel >> 0) & 0xFF;
+
+ comp_C0 = input_C0;
+ comp_C1 = input_C1;
+ comp_C2 = input_C2;
+
+ for (i = 0; i < MDP_CSC_SIZE; i++)
+ matrix[i] =
+ ((int32_t) (((int32_t) matrix_vector[i]) << 20)) >> 20;
+
+ bias_vector[0] = (int32_t) (bv[0] & 0xFF);
+ bias_vector[1] = (int32_t) (bv[1] & 0xFF);
+ bias_vector[2] = (int32_t) (bv[2] & 0xFF);
+
+ Y_low_limit = (int32_t) clamp_vector[0];
+ Y_high_limit = (int32_t) clamp_vector[1];
+ C_low_limit = (int32_t) clamp_vector[2];
+ C_high_limit = (int32_t) clamp_vector[3];
+
+ /*
+ * Color Conversion
+ * reorder input colors
+ */
+ temp = comp_C2;
+ comp_C2 = comp_C1;
+ comp_C1 = comp_C0;
+ comp_C0 = temp;
+
+ /* matrix multiplication */
+ temp1 = comp_C0 * matrix[0] + comp_C1 * matrix[1] + comp_C2 * matrix[2];
+ temp2 = comp_C0 * matrix[3] + comp_C1 * matrix[4] + comp_C2 * matrix[5];
+ temp3 = comp_C0 * matrix[6] + comp_C1 * matrix[7] + comp_C2 * matrix[8];
+
+ comp_C0 = temp1 + 0x100;
+ comp_C1 = temp2 + 0x100;
+ comp_C2 = temp3 + 0x100;
+
+ /* take interger part */
+ comp_C0 >>= 9;
+ comp_C1 >>= 9;
+ comp_C2 >>= 9;
+
+ /* post bias (+) */
+ comp_C0 += bias_vector[0];
+ comp_C1 += bias_vector[1];
+ comp_C2 += bias_vector[2];
+
+ /* limit pixel to 8-bit */
+ comp_C0 = comp_conv_rgb2yuv(comp_C0, Y_high_limit,
+ Y_low_limit, C_high_limit, C_low_limit);
+ comp_C1 = comp_conv_rgb2yuv(comp_C1, Y_high_limit,
+ Y_low_limit, C_high_limit, C_low_limit);
+ comp_C2 = comp_conv_rgb2yuv(comp_C2, Y_high_limit,
+ Y_low_limit, C_high_limit, C_low_limit);
+
+ output = (comp_C2 << 16) | (comp_C1 << 8) | comp_C0;
+ return output;
+}
+
+inline void y_h_even_num(struct ppp_img_desc *img)
+{
+ img->roi.y = (img->roi.y / 2) * 2;
+ img->roi.height = (img->roi.height / 2) * 2;
+}
+
+inline void x_w_even_num(struct ppp_img_desc *img)
+{
+ img->roi.x = (img->roi.x / 2) * 2;
+ img->roi.width = (img->roi.width / 2) * 2;
+}
+
+bool check_if_rgb(int color)
+{
+ bool rgb = false;
+ switch (color) {
+ case MDP_RGB_565:
+ case MDP_BGR_565:
+ case MDP_RGB_888:
+ case MDP_BGR_888:
+ case MDP_BGRA_8888:
+ case MDP_RGBA_8888:
+ case MDP_ARGB_8888:
+ case MDP_XRGB_8888:
+ case MDP_RGBX_8888:
+ rgb = true;
+ default:
+ break;
+ }
+ return rgb;
+}
+
+static uint8_t *mdp_adjust_rot_addr(struct ppp_blit_op *iBuf,
+ uint8_t *addr, uint32_t bpp, uint32_t uv)
+{
+ uint32_t dest_ystride = iBuf->dst.prop.width * bpp;
+ uint32_t h_slice = 1;
+ if (0)
+ return 0;
+
+ if (uv && ((iBuf->dst.color_fmt == MDP_Y_CBCR_H2V2) ||
+ (iBuf->dst.color_fmt == MDP_Y_CRCB_H2V2)))
+ h_slice = 2;
+
+ if (((iBuf->mdp_op & MDPOP_ROT90) == MDPOP_ROT90) ^
+ ((iBuf->mdp_op & MDPOP_LR) == MDPOP_LR)) {
+ addr +=
+ (iBuf->dst.roi.width -
+ MIN(16, iBuf->dst.roi.width)) * bpp;
+ }
+ if ((iBuf->mdp_op & MDPOP_UD) == MDPOP_UD) {
+ if (1) {
+ addr +=
+ ((iBuf->dst.roi.height -
+ MIN(16, iBuf->dst.roi.height))/h_slice) *
+ dest_ystride;
+ } else {
+ addr +=
+ (iBuf->dst.roi.width -
+ MIN(16, iBuf->dst.roi.width)) * bpp;
+ }
+ }
+
+ return addr;
+}
+
+void mdp_adjust_start_addr(struct ppp_blit_op *blit_op,
+ struct ppp_img_desc *img, int v_slice,
+ int h_slice, int layer)
+{
+ uint32_t bpp = ppp_bpp(img->color_fmt);
+ int x = img->roi.x;
+ int y = img->roi.y;
+ uint32_t width = img->prop.width;
+
+ if (img->color_fmt == MDP_Y_CBCR_H2V2_ADRENO && layer == 0)
+ img->p0 += (x + y * ALIGN(width, 32)) * bpp;
+ else
+ img->p0 += (x + y * width) * bpp;
+ if (layer != 0)
+ img->p0 = mdp_adjust_rot_addr(blit_op, img->p0, bpp, 0);
+
+ if (img->p1) {
+ /*
+ * MDP_Y_CBCR_H2V2/MDP_Y_CRCB_H2V2 cosite for now
+ * we need to shift x direction same as y dir for offsite
+ */
+ if (img->color_fmt == MDP_Y_CBCR_H2V2_ADRENO
+ && layer == 0)
+ img->p1 += ((x / h_slice) * h_slice + ((y == 0) ? 0 :
+ (((y + 1) / v_slice - 1) * (ALIGN(width/2, 32) * 2))))
+ * bpp;
+ else
+ img->p1 += ((x / h_slice) * h_slice +
+ ((y == 0) ? 0 : ((y + 1) / v_slice - 1) * width)) * bpp;
+ if (layer != 0)
+ img->p1 = mdp_adjust_rot_addr(blit_op, img->p1, bpp, 1);
+ }
+}
+
+int load_ppp_lut(int tableType, uint32_t *lut)
+{
+ int i;
+ uint32_t base_addr;
+
+ base_addr = tableType ? MDP3_PPP_POST_LUT : MDP3_PPP_PRE_LUT;
+ for (i = 0; i < PPP_LUT_MAX; i++)
+ PPP_WRITEL(lut[i], base_addr + MDP3_PPP_LUTn(i));
+
+ return 0;
+}
+
+/* Configure Primary CSC Matrix */
+int load_primary_matrix(struct ppp_csc_table *csc)
+{
+ int i;
+
+ for (i = 0; i < MDP_CSC_SIZE; i++)
+ PPP_WRITEL(csc->fwd_matrix[i], MDP3_PPP_CSC_PFMVn(i));
+
+ for (i = 0; i < MDP_CSC_SIZE; i++)
+ PPP_WRITEL(csc->rev_matrix[i], MDP3_PPP_CSC_PRMVn(i));
+
+ for (i = 0; i < MDP_BV_SIZE; i++)
+ PPP_WRITEL(csc->bv[i], MDP3_PPP_CSC_PBVn(i));
+
+ for (i = 0; i < MDP_LV_SIZE; i++)
+ PPP_WRITEL(csc->lv[i], MDP3_PPP_CSC_PLVn(i));
+
+ return 0;
+}
+
+/* Load Secondary CSC Matrix */
+int load_secondary_matrix(struct ppp_csc_table *csc)
+{
+ int i;
+
+ for (i = 0; i < MDP_CSC_SIZE; i++)
+ PPP_WRITEL(csc->fwd_matrix[i], MDP3_PPP_CSC_SFMVn(i));
+
+ for (i = 0; i < MDP_CSC_SIZE; i++)
+ PPP_WRITEL(csc->rev_matrix[i], MDP3_PPP_CSC_SRMVn(i));
+
+ for (i = 0; i < MDP_BV_SIZE; i++)
+ PPP_WRITEL(csc->bv[i], MDP3_PPP_CSC_SBVn(i));
+
+ for (i = 0; i < MDP_LV_SIZE; i++)
+ PPP_WRITEL(csc->lv[i], MDP3_PPP_CSC_SLVn(i));
+ return 0;
+}
+
+int load_csc_matrix(int matrix_type, struct ppp_csc_table *csc)
+{
+ if (matrix_type == CSC_PRIMARY_MATRIX)
+ return load_primary_matrix(csc);
+
+ return load_secondary_matrix(csc);
+}
+
+int config_ppp_src(struct ppp_img_desc *src)
+{
+ uint32_t val;
+
+ val = ((src->roi.height & MDP3_PPP_XY_MASK) << MDP3_PPP_XY_OFFSET) |
+ (src->roi.width & MDP3_PPP_XY_MASK);
+ PPP_WRITEL(val, MDP3_PPP_SRC_SIZE);
+
+ PPP_WRITEL(src->p0, MDP3_PPP_SRCP0_ADDR);
+ PPP_WRITEL(src->p1, MDP3_PPP_SRCP1_ADDR);
+ PPP_WRITEL(src->p3, MDP3_PPP_SRCP3_ADDR);
+
+ val = (src->stride0 & MDP3_PPP_STRIDE_MASK) |
+ ((src->stride1 & MDP3_PPP_STRIDE_MASK) <<
+ MDP3_PPP_STRIDE1_OFFSET);
+ PPP_WRITEL(val, MDP3_PPP_SRC_YSTRIDE1_ADDR);
+ val = ((src->stride2 & MDP3_PPP_STRIDE_MASK) <<
+ MDP3_PPP_STRIDE1_OFFSET);
+ PPP_WRITEL(val, MDP3_PPP_SRC_YSTRIDE2_ADDR);
+
+ val = ppp_src_config(src->color_fmt);
+ val |= (src->roi.x % 2) ? PPP_SRC_BPP_ROI_ODD_X : 0;
+ val |= (src->roi.y % 2) ? PPP_SRC_BPP_ROI_ODD_Y : 0;
+ PPP_WRITEL(val, MDP3_PPP_SRC_FORMAT);
+ PPP_WRITEL(ppp_pack_pattern(src->color_fmt),
+ MDP3_PPP_SRC_UNPACK_PATTERN1);
+ return 0;
+}
+
+int config_ppp_out(struct ppp_img_desc *dst)
+{
+ uint32_t val;
+ bool pseudoplanr_output = false;
+
+ switch (dst->color_fmt) {
+ case MDP_Y_CBCR_H2V2:
+ case MDP_Y_CRCB_H2V2:
+ case MDP_Y_CBCR_H2V1:
+ case MDP_Y_CRCB_H2V1:
+ pseudoplanr_output = true;
+ break;
+ default:
+ break;
+ }
+ val = ppp_out_config(dst->color_fmt);
+ if (pseudoplanr_output)
+ val |= PPP_DST_PLANE_PSEUDOPLN;
+ PPP_WRITEL(val, MDP3_PPP_OUT_FORMAT);
+ PPP_WRITEL(ppp_pack_pattern(dst->color_fmt),
+ MDP3_PPP_OUT_PACK_PATTERN1);
+
+ val = ((dst->roi.height & MDP3_PPP_XY_MASK) << MDP3_PPP_XY_OFFSET) |
+ (dst->roi.width & MDP3_PPP_XY_MASK);
+ PPP_WRITEL(val, MDP3_PPP_OUT_SIZE);
+
+ PPP_WRITEL(dst->p0, MDP3_PPP_OUTP0_ADDR);
+ PPP_WRITEL(dst->p1, MDP3_PPP_OUTP1_ADDR);
+ PPP_WRITEL(dst->p3, MDP3_PPP_OUTP3_ADDR);
+
+ val = (dst->stride0 & MDP3_PPP_STRIDE_MASK) |
+ ((dst->stride1 & MDP3_PPP_STRIDE_MASK) <<
+ MDP3_PPP_STRIDE1_OFFSET);
+ PPP_WRITEL(val, MDP3_PPP_OUT_YSTRIDE1_ADDR);
+ val = ((dst->stride2 & MDP3_PPP_STRIDE_MASK) <<
+ MDP3_PPP_STRIDE1_OFFSET);
+ PPP_WRITEL(val, MDP3_PPP_OUT_YSTRIDE2_ADDR);
+ return 0;
+}
+
+int config_ppp_background(struct ppp_img_desc *bg)
+{
+ uint32_t val;
+
+ PPP_WRITEL(bg->p0, MDP3_PPP_BGP0_ADDR);
+ PPP_WRITEL(bg->p1, MDP3_PPP_BGP1_ADDR);
+ PPP_WRITEL(bg->p3, MDP3_PPP_BGP3_ADDR);
+
+ val = (bg->stride0 & MDP3_PPP_STRIDE_MASK) |
+ ((bg->stride1 & MDP3_PPP_STRIDE_MASK) <<
+ MDP3_PPP_STRIDE1_OFFSET);
+ PPP_WRITEL(val, MDP3_PPP_BG_YSTRIDE1_ADDR);
+ val = ((bg->stride2 & MDP3_PPP_STRIDE_MASK) <<
+ MDP3_PPP_STRIDE1_OFFSET);
+ PPP_WRITEL(val, MDP3_PPP_BG_YSTRIDE2_ADDR);
+
+ PPP_WRITEL(ppp_src_config(bg->color_fmt),
+ MDP3_PPP_BG_FORMAT);
+ PPP_WRITEL(ppp_pack_pattern(bg->color_fmt),
+ MDP3_PPP_BG_UNPACK_PATTERN1);
+ return 0;
+}
+
+void ppp_edge_rep_luma_pixel(struct ppp_blit_op *blit_op,
+ struct ppp_edge_rep *er)
+{
+ if (blit_op->mdp_op & MDPOP_ASCALE) {
+
+ er->is_scale_enabled = 1;
+
+ if (blit_op->mdp_op & MDPOP_ROT90) {
+ er->dst_roi_width = blit_op->dst.roi.height;
+ er->dst_roi_height = blit_op->dst.roi.width;
+ } else {
+ er->dst_roi_width = blit_op->dst.roi.width;
+ er->dst_roi_height = blit_op->dst.roi.height;
+ }
+
+ /*
+ * Find out the luma pixels needed for scaling in the
+ * x direction (LEFT and RIGHT). Locations of pixels are
+ * relative to the ROI. Upper-left corner of ROI corresponds
+ * to coordinates (0,0). Also set the number of luma pixel
+ * to repeat.
+ */
+ if (blit_op->src.roi.width > 3 * er->dst_roi_width) {
+ /* scale factor < 1/3 */
+ er->luma_interp_point_right =
+ (blit_op->src.roi.width - 1);
+ } else if (blit_op->src.roi.width == 3 * er->dst_roi_width) {
+ /* scale factor == 1/3 */
+ er->luma_interp_point_right =
+ (blit_op->src.roi.width - 1) + 1;
+ er->luma_repeat_right = 1;
+ } else if ((blit_op->src.roi.width > er->dst_roi_width) &&
+ (blit_op->src.roi.width < 3 * er->dst_roi_width)) {
+ /* 1/3 < scale factor < 1 */
+ er->luma_interp_point_left = -1;
+ er->luma_interp_point_right =
+ (blit_op->src.roi.width - 1) + 1;
+ er->luma_repeat_left = 1;
+ er->luma_repeat_right = 1;
+ } else if (blit_op->src.roi.width == er->dst_roi_width) {
+ /* scale factor == 1 */
+ er->luma_interp_point_left = -1;
+ er->luma_interp_point_right =
+ (blit_op->src.roi.width - 1) + 2;
+ er->luma_repeat_left = 1;
+ er->luma_repeat_right = 2;
+ } else {
+ /* scale factor > 1 */
+ er->luma_interp_point_left = -2;
+ er->luma_interp_point_right =
+ (blit_op->src.roi.width - 1) + 2;
+ er->luma_repeat_left = 2;
+ er->luma_repeat_right = 2;
+ }
+
+ /*
+ * Find out the number of pixels needed for scaling in the
+ * y direction (TOP and BOTTOM). Locations of pixels are
+ * relative to the ROI. Upper-left corner of ROI corresponds
+ * to coordinates (0,0). Also set the number of luma pixel
+ * to repeat.
+ */
+ if (blit_op->src.roi.height > 3 * er->dst_roi_height) {
+ er->luma_interp_point_bottom =
+ (blit_op->src.roi.height - 1);
+ } else if (blit_op->src.roi.height == 3 * er->dst_roi_height) {
+ er->luma_interp_point_bottom =
+ (blit_op->src.roi.height - 1) + 1;
+ er->luma_repeat_bottom = 1;
+ } else if ((blit_op->src.roi.height > er->dst_roi_height) &&
+ (blit_op->src.roi.height < 3 * er->dst_roi_height)) {
+ er->luma_interp_point_top = -1;
+ er->luma_interp_point_bottom =
+ (blit_op->src.roi.height - 1) + 1;
+ er->luma_repeat_top = 1;
+ er->luma_repeat_bottom = 1;
+ } else if (blit_op->src.roi.height == er->dst_roi_height) {
+ er->luma_interp_point_top = -1;
+ er->luma_interp_point_bottom =
+ (blit_op->src.roi.height - 1) + 2;
+ er->luma_repeat_top = 1;
+ er->luma_repeat_bottom = 2;
+ } else {
+ er->luma_interp_point_top = -2;
+ er->luma_interp_point_bottom =
+ (blit_op->src.roi.height - 1) + 2;
+ er->luma_repeat_top = 2;
+ er->luma_repeat_bottom = 2;
+ }
+ } else {
+ /*
+ * Since no scaling needed, Tile Fetch does not require any
+ * more luma pixel than what the ROI contains.
+ */
+ er->luma_interp_point_right =
+ (int32_t) (blit_op->src.roi.width - 1);
+ er->luma_interp_point_bottom =
+ (int32_t) (blit_op->src.roi.height - 1);
+ }
+ /* After adding the ROI offsets, we have locations of
+ * luma_interp_points relative to the image.
+ */
+ er->luma_interp_point_left += (int32_t) (blit_op->src.roi.x);
+ er->luma_interp_point_right += (int32_t) (blit_op->src.roi.x);
+ er->luma_interp_point_top += (int32_t) (blit_op->src.roi.y);
+ er->luma_interp_point_bottom += (int32_t) (blit_op->src.roi.y);
+}
+
+void ppp_edge_rep_chroma_pixel(struct ppp_blit_op *blit_op,
+ struct ppp_edge_rep *er)
+{
+ bool chroma_edge_enable = true;
+ uint32_t is_yuv_offsite_vertical = 0;
+
+ /* find out which chroma pixels are needed for chroma upsampling. */
+ switch (blit_op->src.color_fmt) {
+ case MDP_Y_CBCR_H2V1:
+ case MDP_Y_CRCB_H2V1:
+ case MDP_YCRYCB_H2V1:
+ er->chroma_interp_point_left = er->luma_interp_point_left >> 1;
+ er->chroma_interp_point_right =
+ (er->luma_interp_point_right + 1) >> 1;
+ er->chroma_interp_point_top = er->luma_interp_point_top;
+ er->chroma_interp_point_bottom = er->luma_interp_point_bottom;
+ break;
+
+ case MDP_Y_CBCR_H2V2:
+ case MDP_Y_CBCR_H2V2_ADRENO:
+ case MDP_Y_CRCB_H2V2:
+ er->chroma_interp_point_left = er->luma_interp_point_left >> 1;
+ er->chroma_interp_point_right =
+ (er->luma_interp_point_right + 1) >> 1;
+ er->chroma_interp_point_top =
+ (er->luma_interp_point_top - 1) >> 1;
+ er->chroma_interp_point_bottom =
+ (er->luma_interp_point_bottom + 1) >> 1;
+ is_yuv_offsite_vertical = 1;
+ break;
+
+ default:
+ chroma_edge_enable = false;
+ er->chroma_interp_point_left = er->luma_interp_point_left;
+ er->chroma_interp_point_right = er->luma_interp_point_right;
+ er->chroma_interp_point_top = er->luma_interp_point_top;
+ er->chroma_interp_point_bottom = er->luma_interp_point_bottom;
+
+ break;
+ }
+
+ if (chroma_edge_enable) {
+ /* Defines which chroma pixels belongs to the roi */
+ switch (blit_op->src.color_fmt) {
+ case MDP_Y_CBCR_H2V1:
+ case MDP_Y_CRCB_H2V1:
+ case MDP_YCRYCB_H2V1:
+ er->chroma_bound_left = blit_op->src.roi.x / 2;
+ /* there are half as many chroma pixel as luma pixels */
+ er->chroma_bound_right =
+ (blit_op->src.roi.width +
+ blit_op->src.roi.x - 1) / 2;
+ er->chroma_bound_top = blit_op->src.roi.y;
+ er->chroma_bound_bottom =
+ (blit_op->src.roi.height + blit_op->src.roi.y - 1);
+ break;
+ case MDP_Y_CBCR_H2V2:
+ case MDP_Y_CBCR_H2V2_ADRENO:
+ case MDP_Y_CRCB_H2V2:
+ /*
+ * cosite in horizontal dir, and offsite in vertical dir
+ * width of chroma ROI is 1/2 of size of luma ROI
+ * height of chroma ROI is 1/2 of size of luma ROI
+ */
+ er->chroma_bound_left = blit_op->src.roi.x / 2;
+ er->chroma_bound_right =
+ (blit_op->src.roi.width +
+ blit_op->src.roi.x - 1) / 2;
+ er->chroma_bound_top = blit_op->src.roi.y / 2;
+ er->chroma_bound_bottom =
+ (blit_op->src.roi.height +
+ blit_op->src.roi.y - 1) / 2;
+ break;
+
+ default:
+ /*
+ * If no valid chroma sub-sampling format specified,
+ * assume 4:4:4 ( i.e. fully sampled).
+ */
+ er->chroma_bound_left = blit_op->src.roi.x;
+ er->chroma_bound_right = blit_op->src.roi.width +
+ blit_op->src.roi.x - 1;
+ er->chroma_bound_top = blit_op->src.roi.y;
+ er->chroma_bound_bottom =
+ (blit_op->src.roi.height + blit_op->src.roi.y - 1);
+ break;
+ }
+
+ /*
+ * Knowing which chroma pixels are needed, and which chroma
+ * pixels belong to the ROI (i.e. available for fetching ),
+ * calculate how many chroma pixels Tile Fetch needs to
+ * duplicate. If any required chroma pixels falls outside
+ * of the ROI, Tile Fetch must obtain them by replicating
+ * pixels.
+ */
+ if (er->chroma_bound_left > er->chroma_interp_point_left)
+ er->chroma_repeat_left =
+ er->chroma_bound_left -
+ er->chroma_interp_point_left;
+ else
+ er->chroma_repeat_left = 0;
+
+ if (er->chroma_interp_point_right > er->chroma_bound_right)
+ er->chroma_repeat_right =
+ er->chroma_interp_point_right -
+ er->chroma_bound_right;
+ else
+ er->chroma_repeat_right = 0;
+
+ if (er->chroma_bound_top > er->chroma_interp_point_top)
+ er->chroma_repeat_top =
+ er->chroma_bound_top -
+ er->chroma_interp_point_top;
+ else
+ er->chroma_repeat_top = 0;
+
+ if (er->chroma_interp_point_bottom > er->chroma_bound_bottom)
+ er->chroma_repeat_bottom =
+ er->chroma_interp_point_bottom -
+ er->chroma_bound_bottom;
+ else
+ er->chroma_repeat_bottom = 0;
+
+ if (er->is_scale_enabled && (blit_op->src.roi.height == 1)
+ && is_yuv_offsite_vertical) {
+ er->chroma_repeat_bottom = 3;
+ er->chroma_repeat_top = 0;
+ }
+ }
+}
+
+int config_ppp_edge_rep(struct ppp_blit_op *blit_op)
+{
+ uint32_t reg = 0;
+ struct ppp_edge_rep er;
+
+ memset(&er, 0, sizeof(er));
+
+ ppp_edge_rep_luma_pixel(blit_op, &er);
+
+ /*
+ * After adding the ROI offsets, we have locations of
+ * chroma_interp_points relative to the image.
+ */
+ er.chroma_interp_point_left = er.luma_interp_point_left;
+ er.chroma_interp_point_right = er.luma_interp_point_right;
+ er.chroma_interp_point_top = er.luma_interp_point_top;
+ er.chroma_interp_point_bottom = er.luma_interp_point_bottom;
+
+ ppp_edge_rep_chroma_pixel(blit_op, &er);
+ /* ensure repeats are >=0 and no larger than 3 pixels */
+ if ((er.chroma_repeat_left < 0) || (er.chroma_repeat_right < 0) ||
+ (er.chroma_repeat_top < 0) || (er.chroma_repeat_bottom < 0))
+ return -EINVAL;
+ if ((er.chroma_repeat_left > 3) || (er.chroma_repeat_right > 3) ||
+ (er.chroma_repeat_top > 3) || (er.chroma_repeat_bottom > 3))
+ return -EINVAL;
+ if ((er.luma_repeat_left < 0) || (er.luma_repeat_right < 0) ||
+ (er.luma_repeat_top < 0) || (er.luma_repeat_bottom < 0))
+ return -EINVAL;
+ if ((er.luma_repeat_left > 3) || (er.luma_repeat_right > 3) ||
+ (er.luma_repeat_top > 3) || (er.luma_repeat_bottom > 3))
+ return -EINVAL;
+
+ reg |= (er.chroma_repeat_left & 3) << MDP_LEFT_CHROMA;
+ reg |= (er.chroma_repeat_right & 3) << MDP_RIGHT_CHROMA;
+ reg |= (er.chroma_repeat_top & 3) << MDP_TOP_CHROMA;
+ reg |= (er.chroma_repeat_bottom & 3) << MDP_BOTTOM_CHROMA;
+ reg |= (er.luma_repeat_left & 3) << MDP_LEFT_LUMA;
+ reg |= (er.luma_repeat_right & 3) << MDP_RIGHT_LUMA;
+ reg |= (er.luma_repeat_top & 3) << MDP_TOP_LUMA;
+ reg |= (er.luma_repeat_bottom & 3) << MDP_BOTTOM_LUMA;
+ PPP_WRITEL(reg, MDP3_PPP_SRC_EDGE_REP);
+ return 0;
+}
+
+int config_ppp_bg_edge_rep(struct ppp_blit_op *blit_op)
+{
+ uint32_t reg = 0;
+
+ switch (blit_op->dst.color_fmt) {
+ case MDP_Y_CBCR_H2V2:
+ case MDP_Y_CRCB_H2V2:
+ if (blit_op->dst.roi.y == 0)
+ reg |= BIT(MDP_TOP_CHROMA);
+
+ if ((blit_op->dst.roi.y + blit_op->dst.roi.height) ==
+ blit_op->dst.prop.height) {
+ reg |= BIT(MDP_BOTTOM_CHROMA);
+ }
+
+ if (((blit_op->dst.roi.x + blit_op->dst.roi.width) ==
+ blit_op->dst.prop.width) &&
+ ((blit_op->dst.roi.width % 2) == 0))
+ reg |= BIT(MDP_RIGHT_CHROMA);
+ break;
+ case MDP_Y_CBCR_H2V1:
+ case MDP_Y_CRCB_H2V1:
+ case MDP_YCRYCB_H2V1:
+ if (((blit_op->dst.roi.x + blit_op->dst.roi.width) ==
+ blit_op->dst.prop.width) &&
+ ((blit_op->dst.roi.width % 2) == 0))
+ reg |= BIT(MDP_RIGHT_CHROMA);
+ break;
+ default:
+ break;
+ }
+ PPP_WRITEL(reg, MDP3_PPP_BG_EDGE_REP);
+ return 0;
+}
+
+int config_ppp_lut(uint32_t *pppop_reg_ptr, int lut_c0_en,
+ int lut_c1_en, int lut_c2_en)
+{
+ if (lut_c0_en)
+ *pppop_reg_ptr |= MDP_LUT_C0_EN;
+ if (lut_c1_en)
+ *pppop_reg_ptr |= MDP_LUT_C1_EN;
+ if (lut_c2_en)
+ *pppop_reg_ptr |= MDP_LUT_C2_EN;
+ return 0;
+}
+
+int config_ppp_scale(struct ppp_blit_op *blit_op, uint32_t *pppop_reg_ptr)
+{
+ struct ppp_img_desc *src = &blit_op->src;
+ struct ppp_img_desc *dst = &blit_op->dst;
+ uint32_t dstW, dstH;
+ uint32_t x_fac, y_fac;
+ uint32_t mdp_blur = 0;
+ uint32_t phase_init_x, phase_init_y, phase_step_x, phase_step_y;
+ int x_idx, y_idx;
+
+ if (blit_op->mdp_op & MDPOP_ASCALE) {
+ if (blit_op->mdp_op & MDPOP_ROT90) {
+ dstW = dst->roi.height;
+ dstH = dst->roi.width;
+ } else {
+ dstW = dst->roi.width;
+ dstH = dst->roi.height;
+ }
+ *pppop_reg_ptr |=
+ (PPP_OP_SCALE_Y_ON | PPP_OP_SCALE_X_ON);
+
+ mdp_blur = blit_op->mdp_op & MDPOP_BLUR;
+
+ if ((dstW != src->roi.width) ||
+ (dstH != src->roi.height) || mdp_blur) {
+
+ mdp_calc_scale_params(blit_op->src.roi.x,
+ blit_op->src.roi.width,
+ dstW, 1, &phase_init_x,
+ &phase_step_x);
+ mdp_calc_scale_params(blit_op->src.roi.y,
+ blit_op->src.roi.height,
+ dstH, 0, &phase_init_y,
+ &phase_step_y);
+
+ PPP_WRITEL(phase_init_x, MDP3_PPP_SCALE_PHASEX_INIT);
+ PPP_WRITEL(phase_init_y, MDP3_PPP_SCALE_PHASEY_INIT);
+ PPP_WRITEL(phase_step_x, MDP3_PPP_SCALE_PHASEX_STEP);
+ PPP_WRITEL(phase_step_y, MDP3_PPP_SCALE_PHASEY_STEP);
+
+
+ if (dstW > src->roi.width || dstW > src->roi.height)
+ ppp_load_up_lut();
+
+ if (mdp_blur)
+ ppp_load_gaussian_lut();
+
+ if (dstW <= src->roi.width) {
+ x_fac = (dstW * 100) / src->roi.width;
+ x_idx = scale_idx(x_fac);
+ ppp_load_x_scale_table(x_idx);
+ }
+ if (dstH <= src->roi.height) {
+ y_fac = (dstH * 100) / src->roi.height;
+ y_idx = scale_idx(y_fac);
+ ppp_load_y_scale_table(y_idx);
+ }
+
+ } else {
+ blit_op->mdp_op &= ~(MDPOP_ASCALE);
+ }
+ }
+ config_ppp_edge_rep(blit_op);
+ config_ppp_bg_edge_rep(blit_op);
+ return 0;
+}
+
+int config_ppp_csc(int src_color, int dst_color, uint32_t *pppop_reg_ptr)
+{
+ bool inputRGB, outputRGB;
+
+ inputRGB = check_if_rgb(src_color);
+ outputRGB = check_if_rgb(dst_color);
+
+ if ((!inputRGB) && (outputRGB))
+ *pppop_reg_ptr |= PPP_OP_CONVERT_YCBCR2RGB |
+ PPP_OP_CONVERT_ON;
+ if ((inputRGB) && (!outputRGB))
+ *pppop_reg_ptr |= PPP_OP_CONVERT_ON;
+
+ return 0;
+}
+
+int config_ppp_blend(struct ppp_blit_op *blit_op,
+ uint32_t *pppop_reg_ptr)
+{
+ struct ppp_csc_table *csc;
+ uint32_t alpha, trans_color;
+ uint32_t val = 0;
+ int c_fmt = blit_op->src.color_fmt;
+ int bg_alpha;
+
+ csc = ppp_csc_rgb2yuv();
+ alpha = blit_op->blend.const_alpha;
+ trans_color = blit_op->blend.trans_color;
+ if (blit_op->mdp_op & MDPOP_FG_PM_ALPHA) {
+ if (ppp_per_p_alpha(c_fmt)) {
+ *pppop_reg_ptr |= PPP_OP_ROT_ON |
+ PPP_OP_BLEND_ON |
+ PPP_OP_BLEND_CONSTANT_ALPHA;
+ } else {
+ if ((blit_op->mdp_op & MDPOP_ALPHAB)
+ && (blit_op->blend.const_alpha == 0xff)) {
+ blit_op->mdp_op &= ~(MDPOP_ALPHAB);
+ }
+
+ if ((blit_op->mdp_op & MDPOP_ALPHAB)
+ || (blit_op->mdp_op & MDPOP_TRANSP)) {
+
+ *pppop_reg_ptr |= PPP_OP_ROT_ON |
+ PPP_OP_BLEND_ON |
+ PPP_OP_BLEND_CONSTANT_ALPHA |
+ PPP_OP_BLEND_ALPHA_BLEND_NORMAL;
+ }
+ }
+
+ bg_alpha = PPP_BLEND_BG_USE_ALPHA_SEL |
+ PPP_BLEND_BG_ALPHA_REVERSE;
+
+ if ((ppp_per_p_alpha(c_fmt)) && !(blit_op->mdp_op &
+ MDPOP_LAYER_IS_FG)) {
+ bg_alpha |= PPP_BLEND_BG_SRCPIXEL_ALPHA;
+ } else {
+ bg_alpha |= PPP_BLEND_BG_CONSTANT_ALPHA;
+ bg_alpha |= blit_op->blend.const_alpha << 24;
+ }
+ PPP_WRITEL(bg_alpha, MDP3_PPP_BLEND_BG_ALPHA_SEL);
+
+ if (blit_op->mdp_op & MDPOP_TRANSP)
+ *pppop_reg_ptr |= PPP_BLEND_CALPHA_TRNASP;
+ } else if (ppp_per_p_alpha(c_fmt)) {
+ if (blit_op->mdp_op & MDPOP_LAYER_IS_FG)
+ *pppop_reg_ptr |= PPP_OP_ROT_ON |
+ PPP_OP_BLEND_ON |
+ PPP_OP_BLEND_CONSTANT_ALPHA;
+ else
+ *pppop_reg_ptr |= PPP_OP_ROT_ON |
+ PPP_OP_BLEND_ON |
+ PPP_OP_BLEND_SRCPIXEL_ALPHA;
+ PPP_WRITEL(0, MDP3_PPP_BLEND_BG_ALPHA_SEL);
+ } else {
+ if ((blit_op->mdp_op & MDPOP_ALPHAB)
+ && (blit_op->blend.const_alpha == 0xff)) {
+ blit_op->mdp_op &=
+ ~(MDPOP_ALPHAB);
+ }
+
+ if ((blit_op->mdp_op & MDPOP_ALPHAB)
+ || (blit_op->mdp_op & MDPOP_TRANSP)) {
+ *pppop_reg_ptr |= PPP_OP_ROT_ON |
+ PPP_OP_BLEND_ON |
+ PPP_OP_BLEND_CONSTANT_ALPHA |
+ PPP_OP_BLEND_ALPHA_BLEND_NORMAL;
+ }
+
+ if (blit_op->mdp_op & MDPOP_TRANSP)
+ *pppop_reg_ptr |=
+ PPP_BLEND_CALPHA_TRNASP;
+ PPP_WRITEL(0, MDP3_PPP_BLEND_BG_ALPHA_SEL);
+ }
+
+ if (*pppop_reg_ptr & PPP_OP_BLEND_ON) {
+ blit_op->bg = blit_op->dst;
+ config_ppp_background(&blit_op->bg);
+
+ if (blit_op->dst.color_fmt == MDP_YCRYCB_H2V1) {
+ *pppop_reg_ptr |= PPP_OP_BG_CHROMA_H2V1;
+ if (blit_op->mdp_op & MDPOP_TRANSP) {
+ trans_color = conv_rgb2yuv(trans_color,
+ &csc->fwd_matrix[0],
+ &csc->bv[0],
+ &csc->lv[0]);
+ }
+ }
+ }
+ val = (alpha << MDP_BLEND_CONST_ALPHA);
+ val |= (trans_color & MDP_BLEND_TRASP_COL_MASK);
+ PPP_WRITEL(val, MDP3_PPP_BLEND_PARAM);
+ return 0;
+}
+
+int config_ppp_rotation(uint32_t mdp_op, uint32_t *pppop_reg_ptr)
+{
+ *pppop_reg_ptr |= PPP_OP_ROT_ON;
+
+ if (mdp_op & MDPOP_ROT90)
+ *pppop_reg_ptr |= PPP_OP_ROT_90;
+ if (mdp_op & MDPOP_LR)
+ *pppop_reg_ptr |= PPP_OP_FLIP_LR;
+ if (mdp_op & MDPOP_UD)
+ *pppop_reg_ptr |= PPP_OP_FLIP_UD;
+
+ return 0;
+}
+
+int config_ppp_op_mode(struct ppp_blit_op *blit_op)
+{
+ uint32_t ppp_operation_reg = 0;
+ int sv_slice, sh_slice;
+ int dv_slice, dh_slice;
+
+ sv_slice = sh_slice = dv_slice = dh_slice = 1;
+
+ ppp_operation_reg |= ppp_dst_op_reg(blit_op->dst.color_fmt);
+ switch (blit_op->dst.color_fmt) {
+ case MDP_Y_CBCR_H2V2:
+ case MDP_Y_CRCB_H2V2:
+ y_h_even_num(&blit_op->dst);
+ y_h_even_num(&blit_op->src);
+ dv_slice = 2;
+ case MDP_Y_CBCR_H2V1:
+ case MDP_Y_CRCB_H2V1:
+ case MDP_YCRYCB_H2V1:
+ x_w_even_num(&blit_op->dst);
+ x_w_even_num(&blit_op->src);
+ dh_slice = 2;
+ break;
+ default:
+ break;
+ }
+
+ ppp_operation_reg |= ppp_src_op_reg(blit_op->src.color_fmt);
+ switch (blit_op->src.color_fmt) {
+ case MDP_Y_CBCR_H2V2:
+ case MDP_Y_CBCR_H2V2_ADRENO:
+ case MDP_Y_CRCB_H2V2:
+ sh_slice = sv_slice = 2;
+ break;
+ case MDP_YCRYCB_H2V1:
+ x_w_even_num(&blit_op->dst);
+ x_w_even_num(&blit_op->src);
+ case MDP_Y_CBCR_H2V1:
+ case MDP_Y_CRCB_H2V1:
+ sh_slice = 2;
+ break;
+ default:
+ break;
+ }
+
+ config_ppp_csc(blit_op->src.color_fmt,
+ blit_op->dst.color_fmt, &ppp_operation_reg);
+
+ if (blit_op->mdp_op & MDPOP_DITHER)
+ ppp_operation_reg |= PPP_OP_DITHER_EN;
+
+ if (blit_op->mdp_op & MDPOP_ROTATION)
+ config_ppp_rotation(blit_op->mdp_op, &ppp_operation_reg);
+
+ if (blit_op->src.color_fmt == MDP_Y_CBCR_H2V2_ADRENO) {
+ blit_op->src.stride0 = ALIGN(blit_op->src.prop.width, 32) *
+ ppp_bpp(blit_op->src.color_fmt);
+ blit_op->src.stride1 = 2 * ALIGN(blit_op->src.prop.width/2, 32);
+ } else {
+ blit_op->src.stride0 = blit_op->src.prop.width *
+ ppp_bpp(blit_op->src.color_fmt);
+ blit_op->src.stride1 = blit_op->src.stride0;
+ }
+
+ blit_op->dst.stride0 = blit_op->dst.prop.width *
+ ppp_bpp(blit_op->dst.color_fmt);
+
+ if (ppp_multi_plane(blit_op->dst.color_fmt)) {
+ blit_op->dst.p1 = blit_op->dst.p0;
+ blit_op->dst.p1 += blit_op->dst.prop.width *
+ blit_op->dst.prop.height *
+ ppp_bpp(blit_op->dst.color_fmt);
+ } else {
+ blit_op->dst.p1 = NULL;
+ }
+
+ /* Jumping from Y-Plane to Chroma Plane */
+ /* first pixel addr calculation */
+ mdp_adjust_start_addr(blit_op, &blit_op->src, sv_slice, sh_slice, 0);
+ mdp_adjust_start_addr(blit_op, &blit_op->dst, dv_slice, dh_slice, 2);
+
+ config_ppp_scale(blit_op, &ppp_operation_reg);
+
+ config_ppp_blend(blit_op, &ppp_operation_reg);
+
+ config_ppp_src(&blit_op->src);
+ config_ppp_out(&blit_op->dst);
+ PPP_WRITEL(ppp_operation_reg, MDP3_PPP_OP_MODE);
+ mb();
+ return 0;
+}
+
+void ppp_enable(void)
+{
+ PPP_WRITEL(0x1000, 0x30);
+ mb();
+}
+
+int mdp3_ppp_init(void)
+{
+ load_ppp_lut(LUT_PRE_TABLE, ppp_default_pre_lut());
+ load_ppp_lut(LUT_POST_TABLE, ppp_default_post_lut());
+ load_csc_matrix(CSC_PRIMARY_MATRIX, ppp_csc_rgb2yuv());
+ load_csc_matrix(CSC_SECONDARY_MATRIX, ppp_csc_table2());
+ return 0;
+}
diff --git a/drivers/video/msm/mdss/mdss_dsi.c b/drivers/video/msm/mdss/mdss_dsi.c
index 5d56df4..c663170 100644
--- a/drivers/video/msm/mdss/mdss_dsi.c
+++ b/drivers/video/msm/mdss/mdss_dsi.c
@@ -408,12 +408,14 @@
pr_debug("%s+: ctrl=%p ndx=%d\n", __func__,
ctrl_pdata, ctrl_pdata->ndx);
- mdss_dsi_clk_disable(pdata);
- mdss_dsi_unprepare_clocks(ctrl_pdata);
+ if (pdata->panel_info.type == MIPI_CMD_PANEL)
+ mdss_dsi_clk_ctrl(ctrl_pdata, 1);
/* disable DSI controller */
mdss_dsi_controller_cfg(0, pdata);
+ mdss_dsi_clk_ctrl(ctrl_pdata, 0);
+
/* disable DSI phy */
mdss_dsi_phy_enable(ctrl_pdata->ctrl_base, 0);
ret = mdss_dsi_panel_power_on(pdata, 0);
@@ -431,6 +433,7 @@
{
int ret = 0;
struct mipi_panel_info *mipi;
+ struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
pr_info("%s:%d DSI on for continuous splash.\n", __func__, __LINE__);
@@ -439,20 +442,24 @@
return -EINVAL;
}
- mipi = &pdata->panel_info.mipi;
+ mipi = &pdata->panel_info.mipi;
- ret = mdss_dsi_panel_power_on(pdata, 1);
- if (ret) {
- pr_err("%s: Panel power on failed\n", __func__);
- return ret;
- }
+ ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
+ panel_data);
+
+ pr_debug("%s+: ctrl=%p ndx=%d\n", __func__,
+ ctrl_pdata, ctrl_pdata->ndx);
+
+ WARN(ctrl_pdata->panel_state != UNKNOWN_STATE,
+ "incorrect panel state=%d\n", ctrl_pdata->panel_state);
+
mdss_dsi_sw_reset(pdata);
mdss_dsi_host_init(mipi, pdata);
- pdata->panel_info.panel_power_on = 1;
-
mdss_dsi_op_mode_config(mipi->mode, pdata);
+ ctrl_pdata->panel_state = PANEL_ON;
+
pr_debug("%s-:End\n", __func__);
return ret;
}
@@ -498,8 +505,7 @@
mdss_dsi_phy_sw_reset((ctrl_pdata->ctrl_base));
mdss_dsi_phy_init(pdata);
- mdss_dsi_prepare_clocks(ctrl_pdata);
- mdss_dsi_clk_enable(pdata);
+ mdss_dsi_clk_ctrl(ctrl_pdata, 1);
clk_rate = pdata->panel_info.clk_rate;
clk_rate = min(clk_rate, pdata->panel_info.clk_max);
@@ -577,6 +583,9 @@
wmb();
}
+ if (pdata->panel_info.type == MIPI_CMD_PANEL)
+ mdss_dsi_clk_ctrl(ctrl_pdata, 0);
+
pr_debug("%s-:\n", __func__);
return 0;
}
@@ -598,12 +607,15 @@
panel_data);
mipi = &pdata->panel_info.mipi;
- ret = ctrl_pdata->on(pdata);
- if (ret) {
- pr_err("%s: unable to initialize the panel\n", __func__);
- return ret;
+ if (ctrl_pdata->panel_state != PANEL_ON) {
+ ret = ctrl_pdata->on(pdata);
+ if (ret) {
+ pr_err("%s: unable to initialize the panel\n",
+ __func__);
+ return ret;
+ }
+ ctrl_pdata->panel_state = PANEL_ON;
}
-
mdss_dsi_op_mode_config(mipi->mode, pdata);
pr_debug("%s-:\n", __func__);
@@ -628,12 +640,14 @@
mdss_dsi_op_mode_config(DSI_CMD_MODE, pdata);
- ret = ctrl_pdata->off(pdata);
- if (ret) {
- pr_err("%s: Panel OFF failed\n", __func__);
- return ret;
+ if (ctrl_pdata->panel_state == PANEL_ON) {
+ ret = ctrl_pdata->off(pdata);
+ if (ret) {
+ pr_err("%s: Panel OFF failed\n", __func__);
+ return ret;
+ }
+ ctrl_pdata->panel_state = PANEL_OFF;
}
-
pr_debug("%s-:End\n", __func__);
return ret;
}
@@ -655,35 +669,38 @@
switch (event) {
case MDSS_EVENT_UNBLANK:
rc = mdss_dsi_on(pdata);
- if (ctrl_pdata->on_cmds->ctrl_state == DSI_LP_MODE) {
+ if (ctrl_pdata->on_cmds.link_state == DSI_LP_MODE)
rc = mdss_dsi_unblank(pdata);
- }
break;
case MDSS_EVENT_PANEL_ON:
- if (ctrl_pdata->on_cmds->ctrl_state == DSI_HS_MODE)
+ if (ctrl_pdata->on_cmds.link_state == DSI_HS_MODE)
rc = mdss_dsi_unblank(pdata);
break;
case MDSS_EVENT_BLANK:
- if (ctrl_pdata->off_cmds->ctrl_state == DSI_HS_MODE) {
+ if (ctrl_pdata->off_cmds.link_state == DSI_HS_MODE)
rc = mdss_dsi_blank(pdata);
- }
break;
case MDSS_EVENT_PANEL_OFF:
- if (ctrl_pdata->off_cmds->ctrl_state == DSI_LP_MODE) {
+ if (ctrl_pdata->off_cmds.link_state == DSI_LP_MODE)
rc = mdss_dsi_blank(pdata);
- }
rc = mdss_dsi_off(pdata);
break;
case MDSS_EVENT_CONT_SPLASH_FINISH:
- if (ctrl_pdata->on_cmds->ctrl_state == DSI_LP_MODE) {
+ if (ctrl_pdata->on_cmds.link_state == DSI_LP_MODE) {
rc = mdss_dsi_cont_splash_on(pdata);
} else {
pr_debug("%s:event=%d, Dsi On not called: ctrl_state: %d\n",
__func__, event,
- ctrl_pdata->on_cmds->ctrl_state);
+ ctrl_pdata->on_cmds.link_state);
rc = -EINVAL;
}
break;
+ case MDSS_EVENT_PANEL_CLK_CTRL:
+ mdss_dsi_clk_req(ctrl_pdata, (int)arg);
+ break;
+ case MDSS_EVENT_DSI_CMDLIST_KOFF:
+ mdss_dsi_cmdlist_commit(ctrl_pdata, 1);
+ break;
default:
pr_debug("%s: unhandled event=%d\n", __func__, event);
break;
@@ -1055,17 +1072,16 @@
ctrl_pdata->panel_data.event_handler = mdss_dsi_event_handler;
- ctrl_pdata->on_cmds = panel_data->dsi_panel_on_cmds;
- ctrl_pdata->off_cmds = panel_data->dsi_panel_off_cmds;
+ ctrl_pdata->on_cmds = panel_data->on_cmds;
+ ctrl_pdata->off_cmds = panel_data->off_cmds;
memcpy(&((ctrl_pdata->panel_data).panel_info),
&(panel_data->panel_info),
sizeof(struct mdss_panel_info));
- mdss_dsi_irq_handler_config(ctrl_pdata);
ctrl_pdata->panel_data.set_backlight = panel_data->bl_fnc;
ctrl_pdata->bklt_ctrl = panel_data->panel_info.bklt_ctrl;
- ctrl_pdata->pwm_gpio = panel_data->panel_info.pwm_gpio;
+ ctrl_pdata->pwm_pmic_gpio = panel_data->panel_info.pwm_pmic_gpio;
ctrl_pdata->pwm_period = panel_data->panel_info.pwm_period;
ctrl_pdata->pwm_lpg_chan = panel_data->panel_info.pwm_lpg_chan;
ctrl_pdata->bklt_max = panel_data->panel_info.bl_max;
@@ -1073,6 +1089,7 @@
if (ctrl_pdata->bklt_ctrl == BL_PWM)
mdss_dsi_panel_pwm_cfg(ctrl_pdata);
+ mdss_dsi_ctrl_init(ctrl_pdata);
/*
* register in mdp driver
*/
@@ -1090,13 +1107,20 @@
ctrl_pdata->panel_data.panel_info.cont_splash_enabled = 1;
ctrl_pdata->panel_data.panel_info.panel_power_on = 1;
+ rc = mdss_dsi_panel_power_on(&(ctrl_pdata->panel_data), 1);
+ if (rc) {
+ pr_err("%s: Panel power on failed\n", __func__);
+ return rc;
+ }
}
+ ctrl_pdata->pclk_rate = dsi_pclk_rate;
+ ctrl_pdata->byte_clk_rate = panel_data->panel_info.clk_rate / 8;
+ pr_debug("%s: pclk=%d, bclk=%d\n", __func__,
+ ctrl_pdata->pclk_rate, ctrl_pdata->byte_clk_rate);
- if (ctrl_pdata->panel_data.panel_info.cont_splash_enabled) {
- mdss_dsi_prepare_clocks(ctrl_pdata);
- mdss_dsi_clk_enable(&(ctrl_pdata->panel_data));
- }
+ if (ctrl_pdata->panel_data.panel_info.cont_splash_enabled)
+ mdss_dsi_clk_ctrl(ctrl_pdata, 1);
rc = mdss_register_panel(ctrl_pdev, &(ctrl_pdata->panel_data));
if (rc) {
@@ -1111,11 +1135,6 @@
ctrl_pdata->on = panel_data->on;
ctrl_pdata->off = panel_data->off;
- ctrl_pdata->pclk_rate = dsi_pclk_rate;
- ctrl_pdata->byte_clk_rate = panel_data->panel_info.clk_rate / 8;
- pr_debug("%s: pclk=%d, bclk=%d\n", __func__,
- ctrl_pdata->pclk_rate, ctrl_pdata->byte_clk_rate);
-
if (panel_data->panel_info.pdest == DISPLAY_1) {
mdss_debug_register_base("dsi0",
ctrl_pdata->ctrl_base, ctrl_pdata->reg_size);
@@ -1126,6 +1145,7 @@
ctrl_pdata->ndx = 1;
}
+ ctrl_pdata->panel_state = UNKNOWN_STATE;
pr_debug("%s: Panal data initialized\n", __func__);
return 0;
}
@@ -1155,8 +1175,6 @@
{
int ret;
- mdss_dsi_init();
-
ret = mdss_dsi_register_driver();
if (ret) {
pr_err("mdss_dsi_register_driver() failed!\n");
diff --git a/drivers/video/msm/mdss/mdss_dsi.h b/drivers/video/msm/mdss/mdss_dsi.h
index 197ff7a..602ed9e 100644
--- a/drivers/video/msm/mdss/mdss_dsi.h
+++ b/drivers/video/msm/mdss/mdss_dsi.h
@@ -89,6 +89,12 @@
DSI_HS_MODE,
};
+enum dsi_panel_state {
+ UNKNOWN_STATE,
+ PANEL_ON,
+ PANEL_OFF,
+};
+
#define DSI_NON_BURST_SYNCH_PULSE 0
#define DSI_NON_BURST_SYNCH_EVENT 1
#define DSI_BURST_MODE 2
@@ -127,6 +133,10 @@
#define DSI_CMD_TRIGGER_SW_SEOF 0x05 /* cmd dma only */
#define DSI_CMD_TRIGGER_SW_TE 0x06
+#define DSI_VIDEO_TERM BIT(16)
+#define DSI_MDP_TERM BIT(8)
+#define DSI_CMD_TERM BIT(0)
+
extern struct device dsi_dev;
extern int mdss_dsi_clk_on;
extern u32 dsi_irq;
@@ -182,7 +192,6 @@
#define DSI_HDR_DATA1(data) ((data) & 0x0ff)
#define DSI_HDR_WC(wc) ((wc) & 0x0ffff)
-#define DSI_BUF_SIZE 1024
#define MDSS_DSI_MRPS 0x04 /* Maximum Return Packet Size */
#define MDSS_DSI_LEN 8 /* 4 x 4 - 6 - 2, bytes dcs header+crc-align */
@@ -234,35 +243,67 @@
#define DTYPE_DCS_READ1_RESP 0x21 /* 1 parameter, short */
#define DTYPE_DCS_READ2_RESP 0x22 /* 2 parameter, short */
+
+struct dsi_ctrl_hdr {
+ char dtype; /* data type */
+ char last; /* last in chain */
+ char vc; /* virtual chan */
+ char ack; /* ask ACK from peripheral */
+ char wait; /* ms */
+ short dlen; /* 16 bits */
+} __packed;
+
struct dsi_cmd_desc {
- int dtype;
- int last;
- int vc;
- int ack; /* ask ACK from peripheral */
- int wait;
- int dlen;
+ struct dsi_ctrl_hdr dchdr;
char *payload;
};
+struct dsi_panel_cmds {
+ char *buf;
+ int blen;
+ struct dsi_cmd_desc *cmds;
+ int cmd_cnt;
+ int link_state;
+};
+
+#define CMD_REQ_MAX 4
+
+typedef void (*fxn)(u32 data);
+
+#define CMD_REQ_RX 0x0001
+#define CMD_REQ_COMMIT 0x0002
+#define CMD_CLK_CTRL 0x0004
+#define CMD_REQ_NO_MAX_PKT_SIZE 0x0008
+
+struct dcs_cmd_req {
+ struct dsi_cmd_desc *cmds;
+ int cmds_cnt;
+ u32 flags;
+ int rlen; /* rx length */
+ fxn cb;
+};
+
+struct dcs_cmd_list {
+ int put;
+ int get;
+ int tot;
+ struct dcs_cmd_req list[CMD_REQ_MAX];
+};
+
struct dsi_kickoff_action {
struct list_head act_entry;
void (*action) (void *);
void *data;
};
-struct dsi_panel_cmds_list {
- struct dsi_cmd_desc *buf;
- u32 size;
- char ctrl_state;
-};
-
struct mdss_panel_common_pdata {
struct mdss_panel_info panel_info;
int (*on) (struct mdss_panel_data *pdata);
int (*off) (struct mdss_panel_data *pdata);
void (*bl_fnc) (struct mdss_panel_data *pdata, u32 bl_level);
- struct dsi_panel_cmds_list *dsi_panel_on_cmds;
- struct dsi_panel_cmds_list *dsi_panel_off_cmds;
+
+ struct dsi_panel_cmds on_cmds;
+ struct dsi_panel_cmds off_cmds;
};
struct dsi_drv_cm_data {
@@ -272,17 +313,24 @@
int broadcast_enable;
};
+enum {
+ DSI_CTRL_0,
+ DSI_CTRL_1,
+ DSI_CTRL_MAX,
+};
+
struct mdss_dsi_ctrl_pdata {
- int ndx;
+ int ndx; /* panel_num */
int (*on) (struct mdss_panel_data *pdata);
int (*off) (struct mdss_panel_data *pdata);
struct mdss_panel_data panel_data;
- struct mdss_hw *mdss_hw;
unsigned char *ctrl_base;
int reg_size;
+ u32 clk_cnt;
struct clk *byte_clk;
struct clk *esc_clk;
struct clk *pixel_clk;
+ u8 panel_state;
int irq_cnt;
int mdss_dsi_clk_on;
int rst_gpio;
@@ -290,16 +338,32 @@
int disp_te_gpio;
int bklt_ctrl; /* backlight ctrl */
int pwm_period;
- int pwm_gpio;
+ int pwm_pmic_gpio;
int pwm_lpg_chan;
int bklt_max;
struct pwm_device *pwm_bl;
- struct dsi_panel_cmds_list *on_cmds;
- struct dsi_panel_cmds_list *off_cmds;
struct dsi_drv_cm_data shared_pdata;
u32 pclk_rate;
u32 byte_clk_rate;
struct dss_module_power power_data;
+ u32 dsi_irq_mask;
+ struct mdss_hw *dsi_hw;
+
+ struct dsi_panel_cmds on_cmds;
+ struct dsi_panel_cmds off_cmds;
+
+ struct dcs_cmd_list cmdlist;
+ struct completion dma_comp;
+ struct completion mdp_comp;
+ struct completion video_comp;
+ spinlock_t irq_lock;
+ spinlock_t mdp_lock;
+ int mdp_busy;
+ struct mutex mutex;
+ struct mutex cmd_mutex;
+
+ struct dsi_buf tx_buf;
+ struct dsi_buf rx_buf;
};
int dsi_panel_device_register(struct platform_device *pdev,
@@ -310,29 +374,26 @@
void mdss_dsi_init(void);
int mdss_dsi_buf_alloc(struct dsi_buf *, int size);
int mdss_dsi_cmd_dma_add(struct dsi_buf *dp, struct dsi_cmd_desc *cm);
-int mdss_dsi_cmds_tx(struct mdss_panel_data *pdata,
- struct dsi_buf *dp, struct dsi_cmd_desc *cmds, int cnt);
+int mdss_dsi_cmds_tx(struct mdss_dsi_ctrl_pdata *ctrl,
+ struct dsi_cmd_desc *cmds, int cnt);
-int mdss_dsi_cmd_dma_tx(struct dsi_buf *dp,
- struct mdss_panel_data *pdata);
-int mdss_dsi_cmd_reg_tx(u32 data,
- unsigned char *ctrl_base);
-int mdss_dsi_cmds_rx(struct mdss_panel_data *pdata,
- struct dsi_buf *tp, struct dsi_buf *rp,
- struct dsi_cmd_desc *cmds, int len);
-int mdss_dsi_cmd_dma_rx(struct dsi_buf *tp, int rlen,
- struct mdss_panel_data *pdata);
+int mdss_dsi_cmds_rx(struct mdss_dsi_ctrl_pdata *ctrl,
+ struct dsi_cmd_desc *cmds, int rlen, u32 rx_flags);
+
void mdss_dsi_host_init(struct mipi_panel_info *pinfo,
struct mdss_panel_data *pdata);
void mdss_dsi_op_mode_config(int mode,
struct mdss_panel_data *pdata);
void mdss_dsi_cmd_mode_ctrl(int enable);
void mdp4_dsi_cmd_trigger(void);
-void mdss_dsi_cmd_mdp_start(struct mdss_panel_data *pdata);
+void mdss_dsi_cmd_mdp_start(struct mdss_dsi_ctrl_pdata *ctrl);
void mdss_dsi_cmd_bta_sw_trigger(struct mdss_panel_data *pdata);
void mdss_dsi_ack_err_status(unsigned char *dsi_base);
-void mdss_dsi_clk_enable(struct mdss_panel_data *pdata);
-void mdss_dsi_clk_disable(struct mdss_panel_data *pdata);
+void mdss_dsi_clk_enable(struct mdss_dsi_ctrl_pdata *ctrl);
+void mdss_dsi_clk_disable(struct mdss_dsi_ctrl_pdata *ctrl);
+void mdss_dsi_clk_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, int enable);
+void mdss_dsi_clk_req(struct mdss_dsi_ctrl_pdata *ctrl,
+ int enable);
void mdss_dsi_controller_cfg(int enable,
struct mdss_panel_data *pdata);
void mdss_dsi_sw_reset(struct mdss_panel_data *pdata);
@@ -355,4 +416,13 @@
void mdss_dsi_cmd_test_pattern(struct mdss_panel_data *pdata);
void mdss_dsi_panel_pwm_cfg(struct mdss_dsi_ctrl_pdata *ctrl);
+void mdss_dsi_ctrl_init(struct mdss_dsi_ctrl_pdata *ctrl);
+void mdss_dsi_cmd_mdp_busy(struct mdss_dsi_ctrl_pdata *ctrl);
+void mdss_dsi_wait4video_done(struct mdss_dsi_ctrl_pdata *ctrl);
+void mdss_dsi_cmdlist_commit(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp);
+int mdss_dsi_cmdlist_put(struct mdss_dsi_ctrl_pdata *ctrl,
+ struct dcs_cmd_req *cmdreq);
+struct dcs_cmd_req *mdss_dsi_cmdlist_get(struct mdss_dsi_ctrl_pdata *ctrl);
+void mdss_dsi_cmdlist_kickoff(int intf);
+
#endif /* MDSS_DSI_H */
diff --git a/drivers/video/msm/mdss/mdss_dsi_host.c b/drivers/video/msm/mdss/mdss_dsi_host.c
index 3c0dfc2..6b210af 100644
--- a/drivers/video/msm/mdss/mdss_dsi_host.c
+++ b/drivers/video/msm/mdss/mdss_dsi_host.c
@@ -25,12 +25,11 @@
#include "mdss.h"
#include "mdss_dsi.h"
-static struct completion dsi_dma_comp;
-static spinlock_t dsi_irq_lock;
-static spinlock_t dsi_mdp_lock;
-static int dsi_mdp_busy;
static struct mdss_dsi_ctrl_pdata *left_ctrl_pdata;
+static struct mdss_dsi_ctrl_pdata *ctrl_list[DSI_CTRL_MAX];
+
+
struct mdss_hw mdss_dsi0_hw = {
.hw_ndx = MDSS_HW_DSI0,
.ptr = NULL,
@@ -43,58 +42,128 @@
.irq_handler = mdss_dsi_isr,
};
-void mdss_dsi_init(void)
+void mdss_dsi_ctrl_init(struct mdss_dsi_ctrl_pdata *ctrl)
{
- init_completion(&dsi_dma_comp);
- spin_lock_init(&dsi_irq_lock);
- spin_lock_init(&dsi_mdp_lock);
-}
-
-void mdss_dsi_irq_handler_config(struct mdss_dsi_ctrl_pdata *ctrl)
-{
- int ret;
-
if (ctrl->panel_data.panel_info.pdest == DISPLAY_1) {
mdss_dsi0_hw.ptr = (void *)(ctrl);
- ctrl->mdss_hw = &mdss_dsi0_hw;
+ ctrl->dsi_hw = &mdss_dsi0_hw;
+ ctrl->ndx = DSI_CTRL_0;
} else {
mdss_dsi1_hw.ptr = (void *)(ctrl);
- ctrl->mdss_hw = &mdss_dsi1_hw;
+ ctrl->dsi_hw = &mdss_dsi1_hw;
+ ctrl->ndx = DSI_CTRL_1;
}
- ret = mdss_register_irq(ctrl->mdss_hw);
- if (ret)
+ ctrl_list[ctrl->ndx] = ctrl; /* keep it */
+
+ if (mdss_register_irq(ctrl->dsi_hw))
pr_err("%s: mdss_register_irq failed.\n", __func__);
+
+ pr_debug("%s: ndx=%d base=%p\n", __func__, ctrl->ndx, ctrl->ctrl_base);
+
+ init_completion(&ctrl->dma_comp);
+ init_completion(&ctrl->mdp_comp);
+ init_completion(&ctrl->video_comp);
+ spin_lock_init(&ctrl->irq_lock);
+ spin_lock_init(&ctrl->mdp_lock);
+ mutex_init(&ctrl->mutex);
+ mutex_init(&ctrl->cmd_mutex);
+ mdss_dsi_buf_alloc(&ctrl->tx_buf, SZ_4K);
+ mdss_dsi_buf_alloc(&ctrl->rx_buf, SZ_4K);
}
-void mdss_dsi_irq_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, int enable, int isr)
+/*
+ * acquire ctrl->mutex first
+ */
+void mdss_dsi_clk_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, int enable)
{
- unsigned long flags;
-
- if (ctrl == NULL) {
- pr_err("%s: Invalid ctrl\n", __func__);
- return;
- }
-
- spin_lock_irqsave(&dsi_irq_lock, flags);
+ mutex_lock(&ctrl->mutex);
if (enable) {
- if (ctrl->irq_cnt == 0)
- mdss_enable_irq(ctrl->mdss_hw);
- ctrl->irq_cnt++;
+ if (ctrl->clk_cnt == 0) {
+ mdss_dsi_prepare_clocks(ctrl);
+ mdss_dsi_clk_enable(ctrl);
+ }
+ ctrl->clk_cnt++;
} else {
- if (ctrl->irq_cnt) {
- ctrl->irq_cnt--;
- if (ctrl->irq_cnt == 0) {
- if (isr)
- mdss_disable_irq_nosync(ctrl->mdss_hw);
- else
- mdss_disable_irq(ctrl->mdss_hw);
+ if (ctrl->clk_cnt) {
+ ctrl->clk_cnt--;
+ if (ctrl->clk_cnt == 0) {
+ mdss_dsi_clk_disable(ctrl);
+ mdss_dsi_unprepare_clocks(ctrl);
}
}
}
- pr_debug("%s: ctrl=%d enable=%d cnt=%d\n", __func__,
- ctrl->ndx, enable, ctrl->irq_cnt);
- spin_unlock_irqrestore(&dsi_irq_lock, flags);
+ pr_debug("%s: ctrl ndx=%d enabled=%d clk_cnt=%d\n",
+ __func__, ctrl->ndx, enable, ctrl->clk_cnt);
+ mutex_unlock(&ctrl->mutex);
+}
+
+void mdss_dsi_clk_req(struct mdss_dsi_ctrl_pdata *ctrl, int enable)
+{
+ if (enable == 0) {
+ /* need wait before disable */
+ mutex_lock(&ctrl->cmd_mutex);
+ mdss_dsi_cmd_mdp_busy(ctrl);
+ mutex_unlock(&ctrl->cmd_mutex);
+ }
+
+ mdss_dsi_clk_ctrl(ctrl, enable);
+}
+
+void mdss_dsi_enable_irq(struct mdss_dsi_ctrl_pdata *ctrl, u32 term)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ctrl->irq_lock, flags);
+ if (ctrl->dsi_irq_mask & term) {
+ spin_unlock_irqrestore(&ctrl->irq_lock, flags);
+ return;
+ }
+ if (ctrl->dsi_irq_mask == 0) {
+ mdss_enable_irq(ctrl->dsi_hw);
+ pr_debug("%s: IRQ Enable, ndx=%d mask=%x term=%x\n", __func__,
+ ctrl->ndx, (int)ctrl->dsi_irq_mask, (int)term);
+ }
+ ctrl->dsi_irq_mask |= term;
+ spin_unlock_irqrestore(&ctrl->irq_lock, flags);
+}
+
+void mdss_dsi_disable_irq(struct mdss_dsi_ctrl_pdata *ctrl, u32 term)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ctrl->irq_lock, flags);
+ if (!(ctrl->dsi_irq_mask & term)) {
+ spin_unlock_irqrestore(&ctrl->irq_lock, flags);
+ return;
+ }
+ ctrl->dsi_irq_mask &= ~term;
+ if (ctrl->dsi_irq_mask == 0) {
+ mdss_disable_irq(ctrl->dsi_hw);
+ pr_debug("%s: IRQ Disable, ndx=%d mask=%x term=%x\n", __func__,
+ ctrl->ndx, (int)ctrl->dsi_irq_mask, (int)term);
+ }
+ spin_unlock_irqrestore(&ctrl->irq_lock, flags);
+}
+
+/*
+ * mdss_dsi_disale_irq_nosync() should be called
+ * from interrupt context
+ */
+void mdss_dsi_disable_irq_nosync(struct mdss_dsi_ctrl_pdata *ctrl, u32 term)
+{
+ spin_lock(&ctrl->irq_lock);
+ if (!(ctrl->dsi_irq_mask & term)) {
+ spin_unlock(&ctrl->irq_lock);
+ return;
+ }
+ ctrl->dsi_irq_mask &= ~term;
+ if (ctrl->dsi_irq_mask == 0) {
+ mdss_disable_irq_nosync(ctrl->dsi_hw);
+ pr_debug("%s: IRQ Disable, ndx=%d mask=%x term=%x\n", __func__,
+ ctrl->ndx, (int)ctrl->dsi_irq_mask, (int)term);
+ }
+ spin_unlock(&ctrl->irq_lock);
}
/*
@@ -165,18 +234,20 @@
*/
static int mdss_dsi_generic_lwrite(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
{
+ struct dsi_ctrl_hdr *dchdr;
char *bp;
u32 *hp;
int i, len;
+ dchdr = &cm->dchdr;
bp = mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
/* fill up payload */
if (cm->payload) {
- len = cm->dlen;
+ len = dchdr->dlen;
len += 3;
len &= ~0x03; /* multipled by 4 */
- for (i = 0; i < cm->dlen; i++)
+ for (i = 0; i < dchdr->dlen; i++)
*bp++ = cm->payload[i];
/* append 0xff to the end */
@@ -189,11 +260,11 @@
/* fill up header */
hp = dp->hdr;
*hp = 0;
- *hp = DSI_HDR_WC(cm->dlen);
- *hp |= DSI_HDR_VC(cm->vc);
+ *hp = DSI_HDR_WC(dchdr->dlen);
+ *hp |= DSI_HDR_VC(dchdr->vc);
*hp |= DSI_HDR_LONG_PKT;
*hp |= DSI_HDR_DTYPE(DTYPE_GEN_LWRITE);
- if (cm->last)
+ if (dchdr->last)
*hp |= DSI_HDR_LAST;
mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
@@ -206,10 +277,12 @@
*/
static int mdss_dsi_generic_swrite(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
{
+ struct dsi_ctrl_hdr *dchdr;
u32 *hp;
int len;
- if (cm->dlen && cm->payload == 0) {
+ dchdr = &cm->dchdr;
+ if (dchdr->dlen && cm->payload == 0) {
pr_err("%s: NO payload error\n", __func__);
return 0;
}
@@ -217,12 +290,12 @@
mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
hp = dp->hdr;
*hp = 0;
- *hp |= DSI_HDR_VC(cm->vc);
- if (cm->last)
+ *hp |= DSI_HDR_VC(dchdr->vc);
+ if (dchdr->last)
*hp |= DSI_HDR_LAST;
- len = (cm->dlen > 2) ? 2 : cm->dlen;
+ len = (dchdr->dlen > 2) ? 2 : dchdr->dlen;
if (len == 1) {
*hp |= DSI_HDR_DTYPE(DTYPE_GEN_WRITE1);
@@ -248,10 +321,12 @@
*/
static int mdss_dsi_generic_read(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
{
+ struct dsi_ctrl_hdr *dchdr;
u32 *hp;
int len;
- if (cm->dlen && cm->payload == 0) {
+ dchdr = &cm->dchdr;
+ if (dchdr->dlen && cm->payload == 0) {
pr_err("%s: NO payload error\n", __func__);
return 0;
}
@@ -259,12 +334,12 @@
mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
hp = dp->hdr;
*hp = 0;
- *hp |= DSI_HDR_VC(cm->vc);
+ *hp |= DSI_HDR_VC(dchdr->vc);
*hp |= DSI_HDR_BTA;
- if (cm->last)
+ if (dchdr->last)
*hp |= DSI_HDR_LAST;
- len = (cm->dlen > 2) ? 2 : cm->dlen;
+ len = (dchdr->dlen > 2) ? 2 : dchdr->dlen;
if (len == 1) {
*hp |= DSI_HDR_DTYPE(DTYPE_GEN_READ1);
@@ -289,10 +364,12 @@
*/
static int mdss_dsi_dcs_lwrite(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
{
+ struct dsi_ctrl_hdr *dchdr;
char *bp;
u32 *hp;
int i, len;
+ dchdr = &cm->dchdr;
bp = mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
/*
@@ -300,10 +377,10 @@
* dcs command byte (first byte) followed by payload
*/
if (cm->payload) {
- len = cm->dlen;
+ len = dchdr->dlen;
len += 3;
len &= ~0x03; /* multipled by 4 */
- for (i = 0; i < cm->dlen; i++)
+ for (i = 0; i < dchdr->dlen; i++)
*bp++ = cm->payload[i];
/* append 0xff to the end */
@@ -316,11 +393,11 @@
/* fill up header */
hp = dp->hdr;
*hp = 0;
- *hp = DSI_HDR_WC(cm->dlen);
- *hp |= DSI_HDR_VC(cm->vc);
+ *hp = DSI_HDR_WC(dchdr->dlen);
+ *hp |= DSI_HDR_VC(dchdr->vc);
*hp |= DSI_HDR_LONG_PKT;
*hp |= DSI_HDR_DTYPE(DTYPE_DCS_LWRITE);
- if (cm->last)
+ if (dchdr->last)
*hp |= DSI_HDR_LAST;
mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
@@ -333,9 +410,11 @@
*/
static int mdss_dsi_dcs_swrite(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
{
+ struct dsi_ctrl_hdr *dchdr;
u32 *hp;
int len;
+ dchdr = &cm->dchdr;
if (cm->payload == 0) {
pr_err("%s: NO payload error\n", __func__);
return -EINVAL;
@@ -344,13 +423,13 @@
mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
hp = dp->hdr;
*hp = 0;
- *hp |= DSI_HDR_VC(cm->vc);
- if (cm->ack) /* ask ACK trigger msg from peripeheral */
+ *hp |= DSI_HDR_VC(dchdr->vc);
+ if (dchdr->ack) /* ask ACK trigger msg from peripeheral */
*hp |= DSI_HDR_BTA;
- if (cm->last)
+ if (dchdr->last)
*hp |= DSI_HDR_LAST;
- len = (cm->dlen > 1) ? 1 : cm->dlen;
+ len = (dchdr->dlen > 1) ? 1 : dchdr->dlen;
*hp |= DSI_HDR_DTYPE(DTYPE_DCS_WRITE);
*hp |= DSI_HDR_DATA1(cm->payload[0]); /* dcs command byte */
@@ -365,9 +444,11 @@
*/
static int mdss_dsi_dcs_swrite1(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
{
+ struct dsi_ctrl_hdr *dchdr;
u32 *hp;
- if (cm->dlen < 2 || cm->payload == 0) {
+ dchdr = &cm->dchdr;
+ if (dchdr->dlen < 2 || cm->payload == 0) {
pr_err("%s: NO payload error\n", __func__);
return -EINVAL;
}
@@ -375,10 +456,10 @@
mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
hp = dp->hdr;
*hp = 0;
- *hp |= DSI_HDR_VC(cm->vc);
- if (cm->ack) /* ask ACK trigger msg from peripeheral */
+ *hp |= DSI_HDR_VC(dchdr->vc);
+ if (dchdr->ack) /* ask ACK trigger msg from peripeheral */
*hp |= DSI_HDR_BTA;
- if (cm->last)
+ if (dchdr->last)
*hp |= DSI_HDR_LAST;
*hp |= DSI_HDR_DTYPE(DTYPE_DCS_WRITE1);
@@ -395,8 +476,10 @@
static int mdss_dsi_dcs_read(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
{
+ struct dsi_ctrl_hdr *dchdr;
u32 *hp;
+ dchdr = &cm->dchdr;
if (cm->payload == 0) {
pr_err("%s: NO payload error\n", __func__);
return -EINVAL;
@@ -405,10 +488,10 @@
mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
hp = dp->hdr;
*hp = 0;
- *hp |= DSI_HDR_VC(cm->vc);
+ *hp |= DSI_HDR_VC(dchdr->vc);
*hp |= DSI_HDR_BTA;
*hp |= DSI_HDR_DTYPE(DTYPE_DCS_READ);
- if (cm->last)
+ if (dchdr->last)
*hp |= DSI_HDR_LAST;
*hp |= DSI_HDR_DATA1(cm->payload[0]); /* dcs command byte */
@@ -421,14 +504,16 @@
static int mdss_dsi_cm_on(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
{
+ struct dsi_ctrl_hdr *dchdr;
u32 *hp;
+ dchdr = &cm->dchdr;
mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
hp = dp->hdr;
*hp = 0;
- *hp |= DSI_HDR_VC(cm->vc);
+ *hp |= DSI_HDR_VC(dchdr->vc);
*hp |= DSI_HDR_DTYPE(DTYPE_CM_ON);
- if (cm->last)
+ if (dchdr->last)
*hp |= DSI_HDR_LAST;
mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
@@ -438,14 +523,16 @@
static int mdss_dsi_cm_off(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
{
+ struct dsi_ctrl_hdr *dchdr;
u32 *hp;
+ dchdr = &cm->dchdr;
mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
hp = dp->hdr;
*hp = 0;
- *hp |= DSI_HDR_VC(cm->vc);
+ *hp |= DSI_HDR_VC(dchdr->vc);
*hp |= DSI_HDR_DTYPE(DTYPE_CM_OFF);
- if (cm->last)
+ if (dchdr->last)
*hp |= DSI_HDR_LAST;
mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
@@ -455,14 +542,16 @@
static int mdss_dsi_peripheral_on(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
{
+ struct dsi_ctrl_hdr *dchdr;
u32 *hp;
+ dchdr = &cm->dchdr;
mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
hp = dp->hdr;
*hp = 0;
- *hp |= DSI_HDR_VC(cm->vc);
+ *hp |= DSI_HDR_VC(dchdr->vc);
*hp |= DSI_HDR_DTYPE(DTYPE_PERIPHERAL_ON);
- if (cm->last)
+ if (dchdr->last)
*hp |= DSI_HDR_LAST;
mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
@@ -472,14 +561,16 @@
static int mdss_dsi_peripheral_off(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
{
+ struct dsi_ctrl_hdr *dchdr;
u32 *hp;
+ dchdr = &cm->dchdr;
mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
hp = dp->hdr;
*hp = 0;
- *hp |= DSI_HDR_VC(cm->vc);
+ *hp |= DSI_HDR_VC(dchdr->vc);
*hp |= DSI_HDR_DTYPE(DTYPE_PERIPHERAL_OFF);
- if (cm->last)
+ if (dchdr->last)
*hp |= DSI_HDR_LAST;
mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
@@ -489,8 +580,10 @@
static int mdss_dsi_set_max_pktsize(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
{
+ struct dsi_ctrl_hdr *dchdr;
u32 *hp;
+ dchdr = &cm->dchdr;
if (cm->payload == 0) {
pr_err("%s: NO payload error\n", __func__);
return 0;
@@ -499,9 +592,9 @@
mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
hp = dp->hdr;
*hp = 0;
- *hp |= DSI_HDR_VC(cm->vc);
+ *hp |= DSI_HDR_VC(dchdr->vc);
*hp |= DSI_HDR_DTYPE(DTYPE_MAX_PKTSIZE);
- if (cm->last)
+ if (dchdr->last)
*hp |= DSI_HDR_LAST;
*hp |= DSI_HDR_DATA1(cm->payload[0]);
@@ -514,16 +607,18 @@
static int mdss_dsi_null_pkt(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
{
+ struct dsi_ctrl_hdr *dchdr;
u32 *hp;
+ dchdr = &cm->dchdr;
mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
hp = dp->hdr;
*hp = 0;
- *hp = DSI_HDR_WC(cm->dlen);
+ *hp = DSI_HDR_WC(dchdr->dlen);
*hp |= DSI_HDR_LONG_PKT;
- *hp |= DSI_HDR_VC(cm->vc);
+ *hp |= DSI_HDR_VC(dchdr->vc);
*hp |= DSI_HDR_DTYPE(DTYPE_NULL_PKT);
- if (cm->last)
+ if (dchdr->last)
*hp |= DSI_HDR_LAST;
mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
@@ -533,16 +628,18 @@
static int mdss_dsi_blank_pkt(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
{
+ struct dsi_ctrl_hdr *dchdr;
u32 *hp;
+ dchdr = &cm->dchdr;
mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
hp = dp->hdr;
*hp = 0;
- *hp = DSI_HDR_WC(cm->dlen);
+ *hp = DSI_HDR_WC(dchdr->dlen);
*hp |= DSI_HDR_LONG_PKT;
- *hp |= DSI_HDR_VC(cm->vc);
+ *hp |= DSI_HDR_VC(dchdr->vc);
*hp |= DSI_HDR_DTYPE(DTYPE_BLANK_PKT);
- if (cm->last)
+ if (dchdr->last)
*hp |= DSI_HDR_LAST;
mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
@@ -555,9 +652,12 @@
*/
int mdss_dsi_cmd_dma_add(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
{
+ struct dsi_ctrl_hdr *dchdr;
int len = 0;
- switch (cm->dtype) {
+ dchdr = &cm->dchdr;
+
+ switch (dchdr->dtype) {
case DTYPE_GEN_WRITE:
case DTYPE_GEN_WRITE1:
case DTYPE_GEN_WRITE2:
@@ -606,7 +706,7 @@
break;
default:
pr_debug("%s: dtype=%x NOT supported\n",
- __func__, cm->dtype);
+ __func__, dchdr->dtype);
break;
}
@@ -820,7 +920,7 @@
wmb();
}
-void mipi_set_tx_power_mode(int mode, struct mdss_panel_data *pdata)
+void mdss_set_tx_power_mode(int mode, struct mdss_panel_data *pdata)
{
struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
u32 data;
@@ -1034,94 +1134,84 @@
return 4;
}
+
+static int mdss_dsi_cmd_dma_tx(struct mdss_dsi_ctrl_pdata *ctrl,
+ struct dsi_buf *tp);
+
+static int mdss_dsi_cmd_dma_rx(struct mdss_dsi_ctrl_pdata *ctrl,
+ struct dsi_buf *rp, int rlen);
/*
* mdss_dsi_cmds_tx:
- * ov_mutex need to be acquired before call this function.
+ * thread context only
*/
-int mdss_dsi_cmds_tx(struct mdss_panel_data *pdata,
- struct dsi_buf *tp, struct dsi_cmd_desc *cmds, int cnt)
+int mdss_dsi_cmds_tx(struct mdss_dsi_ctrl_pdata *ctrl,
+ struct dsi_cmd_desc *cmds, int cnt)
{
+ struct dsi_buf *tp;
struct dsi_cmd_desc *cm;
- u32 dsi_ctrl, ctrl;
+ struct dsi_ctrl_hdr *dchdr;
+ u32 dsi_ctrl, data;
int i, video_mode;
- unsigned long flag;
- struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
- if (pdata == NULL) {
- pr_err("%s: Invalid input data\n", __func__);
- return -EINVAL;
- }
-
- ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
- panel_data);
-
- if (ctrl_pdata->shared_pdata.broadcast_enable)
- if (pdata->panel_info.pdest == DISPLAY_1) {
+ if (ctrl->shared_pdata.broadcast_enable) {
+ if (ctrl->ndx == DSI_CTRL_0) {
pr_debug("%s: Broadcast mode. 1st ctrl\n",
__func__);
return 0;
}
+ }
+
+ if (ctrl->shared_pdata.broadcast_enable) {
+ if ((ctrl->ndx == DSI_CTRL_1)
+ && (left_ctrl_pdata != NULL)) {
+ dsi_ctrl = MIPI_INP(left_ctrl_pdata->ctrl_base
+ + 0x0004);
+ video_mode = dsi_ctrl & 0x02; /* VIDEO_MODE_EN */
+ if (video_mode) {
+ data = dsi_ctrl | 0x04; /* CMD_MODE_EN */
+ MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x0004,
+ data);
+ }
+ }
+ }
/* turn on cmd mode
* for video mode, do not send cmds more than
* one pixel line, since it only transmit it
* during BLLP.
*/
-
- if (ctrl_pdata->shared_pdata.broadcast_enable)
- if ((pdata->panel_info.pdest == DISPLAY_2)
- && (left_ctrl_pdata != NULL)) {
- dsi_ctrl = MIPI_INP(left_ctrl_pdata->ctrl_base
- + 0x0004);
- video_mode = dsi_ctrl & 0x02; /* VIDEO_MODE_EN */
- if (video_mode) {
- ctrl = dsi_ctrl | 0x04; /* CMD_MODE_EN */
- MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x0004,
- ctrl);
- }
- }
-
- dsi_ctrl = MIPI_INP((ctrl_pdata->ctrl_base) + 0x0004);
+ dsi_ctrl = MIPI_INP((ctrl->ctrl_base) + 0x0004);
video_mode = dsi_ctrl & 0x02; /* VIDEO_MODE_EN */
if (video_mode) {
- ctrl = dsi_ctrl | 0x04; /* CMD_MODE_EN */
- MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0004, ctrl);
+ data = dsi_ctrl | 0x04; /* CMD_MODE_EN */
+ MIPI_OUTP((ctrl->ctrl_base) + 0x0004, data);
}
- spin_lock_irqsave(&dsi_mdp_lock, flag);
- mdss_dsi_irq_ctrl(ctrl_pdata, 1, 0);
-
- dsi_mdp_busy = true;
- spin_unlock_irqrestore(&dsi_mdp_lock, flag);
-
+ tp = &ctrl->tx_buf;
cm = cmds;
- mdss_dsi_buf_init(tp);
for (i = 0; i < cnt; i++) {
+ mdss_dsi_enable_irq(ctrl, DSI_CMD_TERM);
mdss_dsi_buf_init(tp);
mdss_dsi_cmd_dma_add(tp, cm);
- mdss_dsi_cmd_dma_tx(tp, pdata);
- if (cm->wait)
- msleep(cm->wait);
+ mdss_dsi_cmd_dma_tx(ctrl, tp);
+ dchdr = &cm->dchdr;
+ if (dchdr->wait)
+ usleep(dchdr->wait * 1000);
cm++;
}
- spin_lock_irqsave(&dsi_mdp_lock, flag);
- dsi_mdp_busy = false;
- mdss_dsi_irq_ctrl(ctrl_pdata, 0, 0);
- spin_unlock_irqrestore(&dsi_mdp_lock, flag);
-
if (video_mode)
- MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0004,
+ MIPI_OUTP((ctrl->ctrl_base) + 0x0004,
dsi_ctrl); /* restore */
return cnt;
}
-/* MDSS_DSI_MRPS, Maximum Return Packet Size */
+/* MIPI_DSI_MRPS, Maximum Return Packet Size */
static char max_pktsize[2] = {0x00, 0x00}; /* LSB tx first, 10 bytes */
-static struct dsi_cmd_desc pkt_size_cmd[] = {
- {DTYPE_MAX_PKTSIZE, 1, 0, 0, 0,
- sizeof(max_pktsize), max_pktsize}
+static struct dsi_cmd_desc pkt_size_cmd = {
+ {DTYPE_MAX_PKTSIZE, 1, 0, 0, 0, sizeof(max_pktsize)},
+ max_pktsize,
};
/*
@@ -1129,31 +1219,24 @@
* plus DCS header, ECC and CRC for DCS long read response
* mdss_dsi_controller only have 4x32 bits register ( 16 bytes) to
* hold data per transaction.
- * MDSS_DSI_LEN equal to 8
+ * MIPI_DSI_LEN equal to 8
* len should be either 4 or 8
- * any return data more than MDSS_DSI_LEN need to be break down
+ * any return data more than MIPI_DSI_LEN need to be break down
* to multiple transactions.
*
* ov_mutex need to be acquired before call this function.
*/
-int mdss_dsi_cmds_rx(struct mdss_panel_data *pdata,
- struct dsi_buf *tp, struct dsi_buf *rp,
- struct dsi_cmd_desc *cmds, int rlen)
+
+int mdss_dsi_cmds_rx(struct mdss_dsi_ctrl_pdata *ctrl,
+ struct dsi_cmd_desc *cmds, int rlen, u32 rx_flags)
{
int cnt, len, diff, pkt_size;
- unsigned long flag;
+ struct dsi_buf *tp, *rp;
+ int no_max_pkt_size;
char cmd;
- struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
- if (pdata == NULL) {
- pr_err("%s: Invalid input data\n", __func__);
- return -EINVAL;
- }
-
- ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
- panel_data);
-
- if (pdata->panel_info.mipi.no_max_pkt_size)
+ no_max_pkt_size = rx_flags & CMD_REQ_NO_MAX_PKT_SIZE;
+ if (no_max_pkt_size)
rlen = ALIGN(rlen, 4); /* Only support rlen = 4*n */
len = rlen;
@@ -1178,33 +1261,33 @@
cnt = len + 6; /* 4 bytes header + 2 bytes crc */
}
- spin_lock_irqsave(&dsi_mdp_lock, flag);
- mdss_dsi_irq_ctrl(ctrl_pdata, 1, 0);
- dsi_mdp_busy = true;
- spin_unlock_irqrestore(&dsi_mdp_lock, flag);
+ tp = &ctrl->tx_buf;
+ rp = &ctrl->rx_buf;
- if (!pdata->panel_info.mipi.no_max_pkt_size) {
+ if (!no_max_pkt_size) {
/* packet size need to be set at every read */
pkt_size = len;
max_pktsize[0] = pkt_size;
+ mdss_dsi_enable_irq(ctrl, DSI_CMD_TERM);
mdss_dsi_buf_init(tp);
- mdss_dsi_cmd_dma_add(tp, pkt_size_cmd);
- mdss_dsi_cmd_dma_tx(tp, pdata);
+ mdss_dsi_cmd_dma_add(tp, &pkt_size_cmd);
+ mdss_dsi_cmd_dma_tx(ctrl, tp);
pr_debug("%s: Max packet size sent\n", __func__);
}
+ mdss_dsi_enable_irq(ctrl, DSI_CMD_TERM);
mdss_dsi_buf_init(tp);
mdss_dsi_cmd_dma_add(tp, cmds);
/* transmit read comamnd to client */
- mdss_dsi_cmd_dma_tx(tp, pdata);
+ mdss_dsi_cmd_dma_tx(ctrl, tp);
/*
* once cmd_dma_done interrupt received,
* return data from client is ready and stored
* at RDBK_DATA register already
*/
mdss_dsi_buf_init(rp);
- if (pdata->panel_info.mipi.no_max_pkt_size) {
+ if (no_max_pkt_size) {
/*
* expect rlen = n * 4
* short alignement for start addr
@@ -1212,14 +1295,9 @@
rp->data += 2;
}
- mdss_dsi_cmd_dma_rx(rp, cnt, pdata);
+ mdss_dsi_cmd_dma_rx(ctrl, rp, cnt);
- spin_lock_irqsave(&dsi_mdp_lock, flag);
- dsi_mdp_busy = false;
- mdss_dsi_irq_ctrl(ctrl_pdata, 0, 0);
- spin_unlock_irqrestore(&dsi_mdp_lock, flag);
-
- if (pdata->panel_info.mipi.no_max_pkt_size) {
+ if (no_max_pkt_size) {
/*
* remove extra 2 bytes from previous
* rx transaction at shift register
@@ -1257,22 +1335,16 @@
return rp->len;
}
-int mdss_dsi_cmd_dma_tx(struct dsi_buf *tp,
- struct mdss_panel_data *pdata)
+#define DMA_TX_TIMEOUT 200
+
+static int mdss_dsi_cmd_dma_tx(struct mdss_dsi_ctrl_pdata *ctrl,
+ struct dsi_buf *tp)
{
int len;
int domain = MDSS_IOMMU_DOMAIN_UNSECURE;
char *bp;
unsigned long size, addr;
- struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
- if (pdata == NULL) {
- pr_err("%s: Invalid input data\n", __func__);
- return -EINVAL;
- }
-
- ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
- panel_data);
bp = tp->data;
len = ALIGN(tp->len, 4);
@@ -1296,29 +1368,32 @@
addr = tp->dmap;
}
- INIT_COMPLETION(dsi_dma_comp);
+ INIT_COMPLETION(ctrl->dma_comp);
- if (ctrl_pdata->shared_pdata.broadcast_enable)
- if ((pdata->panel_info.pdest == DISPLAY_2)
+ if (ctrl->shared_pdata.broadcast_enable)
+ if ((ctrl->ndx == DSI_CTRL_1)
&& (left_ctrl_pdata != NULL)) {
MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x048, addr);
MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x04c, len);
}
- MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x048, addr);
- MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x04c, len);
+ MIPI_OUTP((ctrl->ctrl_base) + 0x048, addr);
+ MIPI_OUTP((ctrl->ctrl_base) + 0x04c, len);
wmb();
- if (ctrl_pdata->shared_pdata.broadcast_enable)
- if ((pdata->panel_info.pdest == DISPLAY_2)
+ if (ctrl->shared_pdata.broadcast_enable)
+ if ((ctrl->ndx == DSI_CTRL_1)
&& (left_ctrl_pdata != NULL)) {
MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x090, 0x01);
}
- MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x090, 0x01); /* trigger */
+ MIPI_OUTP((ctrl->ctrl_base) + 0x090, 0x01); /* trigger */
wmb();
- wait_for_completion(&dsi_dma_comp);
+ if (!wait_for_completion_timeout(&ctrl->dma_comp,
+ msecs_to_jiffies(DMA_TX_TIMEOUT))) {
+ pr_err("%s: dma timeout error\n", __func__);
+ }
if (is_mdss_iommu_attached())
msm_iommu_unmap_contig_buffer(addr,
@@ -1329,20 +1404,13 @@
return tp->len;
}
-int mdss_dsi_cmd_dma_rx(struct dsi_buf *rp, int rlen,
- struct mdss_panel_data *pdata)
+static int mdss_dsi_cmd_dma_rx(struct mdss_dsi_ctrl_pdata *ctrl,
+ struct dsi_buf *rp, int rlen)
+
{
u32 *lp, data;
int i, off, cnt;
- struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
- if (pdata == NULL) {
- pr_err("%s: Invalid input data\n", __func__);
- return -EINVAL;
- }
-
- ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
- panel_data);
lp = (u32 *)rp->data;
cnt = rlen;
cnt += 3;
@@ -1354,106 +1422,289 @@
off = 0x06c; /* DSI_RDBK_DATA0 */
off += ((cnt - 1) * 4);
-
for (i = 0; i < cnt; i++) {
- data = (u32)MIPI_INP((ctrl_pdata->ctrl_base) + off);
+ data = (u32)MIPI_INP((ctrl->ctrl_base) + off);
*lp++ = ntohl(data); /* to network byte order */
pr_debug("%s: data = 0x%x and ntohl(data) = 0x%x\n",
__func__, data, ntohl(data));
off -= 4;
rp->len += sizeof(*lp);
}
-
return rlen;
}
-void mdss_dsi_ack_err_status(unsigned char *dsi_base)
+#define VSYNC_PERIOD 17
+
+void mdss_dsi_wait4video_done(struct mdss_dsi_ctrl_pdata *ctrl)
+{
+ unsigned long flag;
+
+ spin_lock_irqsave(&ctrl->mdp_lock, flag);
+ INIT_COMPLETION(ctrl->video_comp);
+ mdss_dsi_enable_irq(ctrl, DSI_VIDEO_TERM);
+ spin_unlock_irqrestore(&ctrl->mdp_lock, flag);
+
+ wait_for_completion_timeout(&ctrl->video_comp,
+ msecs_to_jiffies(VSYNC_PERIOD * 4));
+}
+
+static void mdss_dsi_wait4video_eng_busy(struct mdss_dsi_ctrl_pdata *ctrl)
+{
+ mdss_dsi_wait4video_done(ctrl);
+ /* delay 4 ms to skip BLLP */
+ usleep(4000);
+}
+
+void mdss_dsi_cmd_mdp_start(struct mdss_dsi_ctrl_pdata *ctrl)
+{
+ unsigned long flag;
+
+ spin_lock_irqsave(&ctrl->mdp_lock, flag);
+ mdss_dsi_enable_irq(ctrl, DSI_MDP_TERM);
+ ctrl->mdp_busy = true;
+ INIT_COMPLETION(ctrl->mdp_comp);
+ spin_unlock_irqrestore(&ctrl->mdp_lock, flag);
+}
+
+void mdss_dsi_cmd_mdp_busy(struct mdss_dsi_ctrl_pdata *ctrl)
+{
+ unsigned long flags;
+ int need_wait = 0;
+
+ pr_debug("%s: start pid=%d\n",
+ __func__, current->pid);
+ spin_lock_irqsave(&ctrl->mdp_lock, flags);
+ if (ctrl->mdp_busy == true)
+ need_wait++;
+ spin_unlock_irqrestore(&ctrl->mdp_lock, flags);
+
+ if (need_wait) {
+ /* wait until DMA finishes the current job */
+ pr_debug("%s: pending pid=%d\n",
+ __func__, current->pid);
+ wait_for_completion(&ctrl->mdp_comp);
+ }
+ pr_debug("%s: done pid=%d\n",
+ __func__, current->pid);
+}
+
+void mdss_dsi_cmdlist_tx(struct mdss_dsi_ctrl_pdata *ctrl,
+ struct dcs_cmd_req *req)
+{
+ int ret;
+
+ ret = mdss_dsi_cmds_tx(ctrl, req->cmds, req->cmds_cnt);
+
+ if (req->cb)
+ req->cb(ret);
+
+}
+
+void mdss_dsi_cmdlist_rx(struct mdss_dsi_ctrl_pdata *ctrl,
+ struct dcs_cmd_req *req)
+{
+ int len;
+ u32 data, *dp;
+ struct dsi_buf *rp;
+
+ len = mdss_dsi_cmds_rx(ctrl, req->cmds, req->rlen, req->flags);
+ rp = &ctrl->rx_buf;
+ dp = (u32 *)rp->data;
+ data = *dp;
+
+ if (req->cb)
+ req->cb(data);
+}
+
+void mdss_dsi_cmdlist_commit(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp)
+{
+ struct dcs_cmd_req *req;
+ u32 data;
+
+ mutex_lock(&ctrl->cmd_mutex);
+ req = mdss_dsi_cmdlist_get(ctrl);
+
+ /* make sure dsi_cmd_mdp is idle */
+ mdss_dsi_cmd_mdp_busy(ctrl);
+
+ if (req == NULL)
+ goto need_lock;
+
+ pr_debug("%s: from_mdp=%d pid=%d\n", __func__, from_mdp, current->pid);
+ mdss_dsi_clk_ctrl(ctrl, 1);
+
+ data = MIPI_INP((ctrl->ctrl_base) + 0x0004);
+ if (data & 0x02) {
+ /* video mode, make sure video engine is busy
+ * so dcs command will be sent at start of BLLP
+ */
+ mdss_dsi_wait4video_eng_busy(ctrl);
+ } else {
+ /* command mode */
+ if (!from_mdp) { /* cmdlist_put */
+ /* make sure dsi_cmd_mdp is idle */
+ mdss_dsi_cmd_mdp_busy(ctrl);
+ }
+ }
+
+ if (req->flags & CMD_REQ_RX)
+ mdss_dsi_cmdlist_rx(ctrl, req);
+ else
+ mdss_dsi_cmdlist_tx(ctrl, req);
+
+ mdss_dsi_clk_ctrl(ctrl, 0);
+
+need_lock:
+
+ if (from_mdp) /* from pipe_commit */
+ mdss_dsi_cmd_mdp_start(ctrl);
+
+ mutex_unlock(&ctrl->cmd_mutex);
+}
+
+/*
+ * mdss_dsi_cmd_get: ctrl->cmd_mutex acquired by caller
+ */
+struct dcs_cmd_req *mdss_dsi_cmdlist_get(struct mdss_dsi_ctrl_pdata *ctrl)
+{
+ struct dcs_cmd_list *clist;
+ struct dcs_cmd_req *req = NULL;
+
+ clist = &ctrl->cmdlist;
+ if (clist->get != clist->put) {
+ req = &clist->list[clist->get];
+ clist->get++;
+ clist->get %= CMD_REQ_MAX;
+ clist->tot--;
+ pr_debug("%s: tot=%d put=%d get=%d\n", __func__,
+ clist->tot, clist->put, clist->get);
+ }
+ return req;
+}
+
+int mdss_dsi_cmdlist_put(struct mdss_dsi_ctrl_pdata *ctrl,
+ struct dcs_cmd_req *cmdreq)
+{
+ struct dcs_cmd_req *req;
+ struct dcs_cmd_list *clist;
+ int ret = 0;
+
+ mutex_lock(&ctrl->cmd_mutex);
+ clist = &ctrl->cmdlist;
+ req = &clist->list[clist->put];
+ *req = *cmdreq;
+ clist->put++;
+ clist->put %= CMD_REQ_MAX;
+ clist->tot++;
+ if (clist->put == clist->get) {
+ /* drop the oldest one */
+ pr_debug("%s: DROP, tot=%d put=%d get=%d\n", __func__,
+ clist->tot, clist->put, clist->get);
+ clist->get++;
+ clist->get %= CMD_REQ_MAX;
+ clist->tot--;
+ }
+ mutex_unlock(&ctrl->cmd_mutex);
+
+ ret++;
+ pr_debug("%s: tot=%d put=%d get=%d\n", __func__,
+ clist->tot, clist->put, clist->get);
+
+ if (req->flags & CMD_REQ_COMMIT)
+ mdss_dsi_cmdlist_commit(ctrl, 0);
+
+ return ret;
+}
+
+void mdss_dsi_ack_err_status(unsigned char *base)
{
u32 status;
- status = MIPI_INP(dsi_base + 0x0068);/* DSI_ACK_ERR_STATUS */
+ status = MIPI_INP(base + 0x0068);/* DSI_ACK_ERR_STATUS */
if (status) {
- MIPI_OUTP(dsi_base + 0x0068, status);
+ MIPI_OUTP(base + 0x0068, status);
pr_debug("%s: status=%x\n", __func__, status);
}
}
-void mdss_dsi_timeout_status(unsigned char *dsi_base)
+void mdss_dsi_timeout_status(unsigned char *base)
{
u32 status;
- status = MIPI_INP(dsi_base + 0x00c0);/* DSI_TIMEOUT_STATUS */
+ status = MIPI_INP(base + 0x00c0);/* DSI_TIMEOUT_STATUS */
if (status & 0x0111) {
- MIPI_OUTP(dsi_base + 0x00c0, status);
+ MIPI_OUTP(base + 0x00c0, status);
pr_debug("%s: status=%x\n", __func__, status);
}
}
-void mdss_dsi_dln0_phy_err(unsigned char *dsi_base)
+void mdss_dsi_dln0_phy_err(unsigned char *base)
{
u32 status;
- status = MIPI_INP(dsi_base + 0x00b4);/* DSI_DLN0_PHY_ERR */
+ status = MIPI_INP(base + 0x00b4);/* DSI_DLN0_PHY_ERR */
if (status & 0x011111) {
- MIPI_OUTP(dsi_base + 0x00b4, status);
+ MIPI_OUTP(base + 0x00b4, status);
pr_debug("%s: status=%x\n", __func__, status);
}
}
-void mdss_dsi_fifo_status(unsigned char *dsi_base)
+void mdss_dsi_fifo_status(unsigned char *base)
{
u32 status;
- status = MIPI_INP(dsi_base + 0x000c);/* DSI_FIFO_STATUS */
+ status = MIPI_INP(base + 0x000c);/* DSI_FIFO_STATUS */
if (status & 0x44444489) {
- MIPI_OUTP(dsi_base + 0x000c, status);
+ MIPI_OUTP(base + 0x000c, status);
pr_debug("%s: status=%x\n", __func__, status);
}
}
-void mdss_dsi_status(unsigned char *dsi_base)
+void mdss_dsi_status(unsigned char *base)
{
u32 status;
- status = MIPI_INP(dsi_base + 0x0008);/* DSI_STATUS */
+ status = MIPI_INP(base + 0x0008);/* DSI_STATUS */
if (status & 0x80000000) {
- MIPI_OUTP(dsi_base + 0x0008, status);
+ MIPI_OUTP(base + 0x0008, status);
pr_debug("%s: status=%x\n", __func__, status);
}
}
-void mdss_dsi_error(unsigned char *dsi_base)
+void mdss_dsi_error(struct mdss_dsi_ctrl_pdata *ctrl)
{
+ unsigned char *base;
+
+ base = ctrl->ctrl_base;
+
/* DSI_ERR_INT_MASK0 */
- mdss_dsi_ack_err_status(dsi_base); /* mask0, 0x01f */
- mdss_dsi_timeout_status(dsi_base); /* mask0, 0x0e0 */
- mdss_dsi_fifo_status(dsi_base); /* mask0, 0x133d00 */
- mdss_dsi_status(dsi_base); /* mask0, 0xc0100 */
- mdss_dsi_dln0_phy_err(dsi_base); /* mask0, 0x3e00000 */
+ mdss_dsi_ack_err_status(base); /* mask0, 0x01f */
+ mdss_dsi_timeout_status(base); /* mask0, 0x0e0 */
+ mdss_dsi_fifo_status(base); /* mask0, 0x133d00 */
+ mdss_dsi_status(base); /* mask0, 0xc0100 */
+ mdss_dsi_dln0_phy_err(base); /* mask0, 0x3e00000 */
}
irqreturn_t mdss_dsi_isr(int irq, void *ptr)
{
u32 isr;
- unsigned char *dsi_base;
- struct mdss_dsi_ctrl_pdata *ctrl_pdata =
+ struct mdss_dsi_ctrl_pdata *ctrl =
(struct mdss_dsi_ctrl_pdata *)ptr;
- dsi_base = ctrl_pdata->ctrl_base;
- if (!dsi_base)
+ if (!ctrl->ctrl_base)
pr_err("%s:%d DSI base adr no Initialized",
__func__, __LINE__);
- isr = MIPI_INP(dsi_base + 0x0110);/* DSI_INTR_CTRL */
- MIPI_OUTP(dsi_base + 0x0110, isr);
+ isr = MIPI_INP(ctrl->ctrl_base + 0x0110);/* DSI_INTR_CTRL */
+ MIPI_OUTP(ctrl->ctrl_base + 0x0110, isr);
- if (ctrl_pdata->shared_pdata.broadcast_enable)
- if ((ctrl_pdata->panel_data.panel_info.pdest == DISPLAY_2)
+ if (ctrl->shared_pdata.broadcast_enable)
+ if ((ctrl->panel_data.panel_info.pdest == DISPLAY_2)
&& (left_ctrl_pdata != NULL)) {
u32 isr0;
isr0 = MIPI_INP(left_ctrl_pdata->ctrl_base
@@ -1461,24 +1712,38 @@
MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x0110, isr0);
}
- pr_debug("%s: isr=%x %x", __func__, isr, (int)DSI_INTR_ERROR);
+ pr_debug("%s: isr=%x", __func__, isr);
- if (isr & DSI_INTR_ERROR)
- mdss_dsi_error(dsi_base);
-
- if (isr & DSI_INTR_VIDEO_DONE) {
- /*
- * do something here
- */
+ if (isr & DSI_INTR_ERROR) {
+ pr_err("%s: isr=%x %x", __func__, isr, (int)DSI_INTR_ERROR);
+ spin_lock(&ctrl->mdp_lock);
+ ctrl->mdp_busy = false;
+ mdss_dsi_disable_irq_nosync(ctrl, DSI_MDP_TERM);
+ complete(&ctrl->mdp_comp);
+ mdss_dsi_error(ctrl);
+ spin_unlock(&ctrl->mdp_lock);
}
- if (isr & DSI_INTR_CMD_DMA_DONE)
- complete(&dsi_dma_comp);
+ if (isr & DSI_INTR_VIDEO_DONE) {
+ spin_lock(&ctrl->mdp_lock);
+ mdss_dsi_disable_irq_nosync(ctrl, DSI_VIDEO_TERM);
+ complete(&ctrl->video_comp);
+ spin_unlock(&ctrl->mdp_lock);
+ }
+
+ if (isr & DSI_INTR_CMD_DMA_DONE) {
+ spin_lock(&ctrl->mdp_lock);
+ mdss_dsi_disable_irq_nosync(ctrl, DSI_CMD_TERM);
+ complete(&ctrl->dma_comp);
+ spin_unlock(&ctrl->mdp_lock);
+ }
if (isr & DSI_INTR_CMD_MDP_DONE) {
- spin_lock(&dsi_mdp_lock);
- dsi_mdp_busy = false;
- spin_unlock(&dsi_mdp_lock);
+ spin_lock(&ctrl->mdp_lock);
+ ctrl->mdp_busy = false;
+ mdss_dsi_disable_irq_nosync(ctrl, DSI_MDP_TERM);
+ complete(&ctrl->mdp_comp);
+ spin_unlock(&ctrl->mdp_lock);
}
return IRQ_HANDLED;
diff --git a/drivers/video/msm/mdss/mdss_dsi_panel.c b/drivers/video/msm/mdss/mdss_dsi_panel.c
index c56cd41..6b0f68e 100644
--- a/drivers/video/msm/mdss/mdss_dsi_panel.c
+++ b/drivers/video/msm/mdss/mdss_dsi_panel.c
@@ -26,9 +26,6 @@
#define DT_CMD_HDR 6
-static struct dsi_buf dsi_panel_tx_buf;
-static struct dsi_buf dsi_panel_rx_buf;
-
DEFINE_LED_TRIGGER(bl_led_trigger);
static struct mdss_dsi_phy_ctrl phy_params;
@@ -37,16 +34,18 @@
{
int ret;
- if (!gpio_is_valid(ctrl->pwm_gpio)) {
- pr_err("%s: pwm_gpio=%d Invalid\n", __func__,
- ctrl->pwm_gpio);
+ if (!gpio_is_valid(ctrl->pwm_pmic_gpio)) {
+ pr_err("%s: pwm_pmic_gpio=%d Invalid\n", __func__,
+ ctrl->pwm_pmic_gpio);
+ ctrl->pwm_pmic_gpio = -1;
return;
}
- ret = gpio_request(ctrl->pwm_gpio, "disp_pwm");
+ ret = gpio_request(ctrl->pwm_pmic_gpio, "disp_pwm");
if (ret) {
- pr_err("%s: pwm_gpio=%d request failed\n", __func__,
- ctrl->pwm_gpio);
+ pr_err("%s: pwm_pmic_gpio=%d request failed\n", __func__,
+ ctrl->pwm_pmic_gpio);
+ ctrl->pwm_pmic_gpio = -1;
return;
}
@@ -54,8 +53,8 @@
if (ctrl->pwm_bl == NULL || IS_ERR(ctrl->pwm_bl)) {
pr_err("%s: lpg_chan=%d pwm request failed", __func__,
ctrl->pwm_lpg_chan);
- gpio_free(ctrl->pwm_gpio);
- ctrl->pwm_gpio = -1;
+ gpio_free(ctrl->pwm_pmic_gpio);
+ ctrl->pwm_pmic_gpio = -1;
}
}
@@ -74,7 +73,7 @@
pr_debug("%s: bklt_ctrl=%d pwm_period=%d pwm_gpio=%d pwm_lpg_chan=%d\n",
__func__, ctrl->bklt_ctrl, ctrl->pwm_period,
- ctrl->pwm_gpio, ctrl->pwm_lpg_chan);
+ ctrl->pwm_pmic_gpio, ctrl->pwm_lpg_chan);
pr_debug("%s: ndx=%d level=%d duty=%d\n", __func__,
ctrl->ndx, level, duty);
@@ -90,6 +89,71 @@
pr_err("%s: pwm_enable() failed err=%d\n", __func__, ret);
}
+static char dcs_cmd[2] = {0x54, 0x00}; /* DTYPE_DCS_READ */
+static struct dsi_cmd_desc dcs_read_cmd = {
+ {DTYPE_DCS_READ, 1, 0, 1, 5, sizeof(dcs_cmd)},
+ dcs_cmd
+};
+
+u32 mdss_dsi_dcs_read(struct mdss_dsi_ctrl_pdata *ctrl,
+ char cmd0, char cmd1)
+{
+ struct dcs_cmd_req cmdreq;
+
+ dcs_cmd[0] = cmd0;
+ dcs_cmd[1] = cmd1;
+ memset(&cmdreq, 0, sizeof(cmdreq));
+ cmdreq.cmds = &dcs_read_cmd;
+ cmdreq.cmds_cnt = 1;
+ cmdreq.flags = CMD_REQ_RX | CMD_REQ_COMMIT;
+ cmdreq.rlen = 1;
+ cmdreq.cb = NULL; /* call back */
+ mdss_dsi_cmdlist_put(ctrl, &cmdreq);
+ /*
+ * blocked here, until call back called
+ */
+
+ return 0;
+}
+
+static void mdss_dsi_panel_cmds_send(struct mdss_dsi_ctrl_pdata *ctrl,
+ struct dsi_panel_cmds *pcmds)
+{
+ struct dcs_cmd_req cmdreq;
+
+ memset(&cmdreq, 0, sizeof(cmdreq));
+ cmdreq.cmds = pcmds->cmds;
+ cmdreq.cmds_cnt = pcmds->cmd_cnt;
+ cmdreq.flags = CMD_REQ_COMMIT;
+ cmdreq.rlen = 0;
+ cmdreq.cb = NULL;
+
+ mdss_dsi_cmdlist_put(ctrl, &cmdreq);
+}
+
+static char led_pwm1[2] = {0x51, 0x0}; /* DTYPE_DCS_WRITE1 */
+static struct dsi_cmd_desc backlight_cmd = {
+ {DTYPE_DCS_WRITE1, 1, 0, 0, 1, sizeof(led_pwm1)},
+ led_pwm1
+};
+
+static void mdss_dsi_panel_bklt_dcs(struct mdss_dsi_ctrl_pdata *ctrl, int level)
+{
+ struct dcs_cmd_req cmdreq;
+
+ pr_debug("%s: level=%d\n", __func__, level);
+
+ led_pwm1[1] = (unsigned char)level;
+
+ memset(&cmdreq, 0, sizeof(cmdreq));
+ cmdreq.cmds = &backlight_cmd;
+ cmdreq.cmds_cnt = 1;
+ cmdreq.flags = CMD_REQ_COMMIT | CMD_CLK_CTRL;
+ cmdreq.rlen = 0;
+ cmdreq.cb = NULL;
+
+ mdss_dsi_cmdlist_put(ctrl, &cmdreq);
+}
void mdss_dsi_panel_reset(struct mdss_panel_data *pdata, int enable)
{
@@ -152,6 +216,9 @@
case BL_PWM:
mdss_dsi_panel_bklt_pwm(ctrl_pdata, bl_level);
break;
+ case BL_DCS_CMD:
+ mdss_dsi_panel_bklt_dcs(ctrl_pdata, bl_level);
+ break;
default:
pr_err("%s: Unknown bl_ctrl configuration\n",
__func__);
@@ -159,14 +226,6 @@
}
}
-static char set_tear_on[2] = {0x35, 0x00};
-static struct dsi_cmd_desc dsi_tear_on_cmd = {
- DTYPE_DCS_WRITE1, 1, 0, 0, 0, sizeof(set_tear_on), set_tear_on};
-
-static char set_tear_off[2] = {0x34, 0x00};
-static struct dsi_cmd_desc dsi_tear_off_cmd = {
- DTYPE_DCS_WRITE, 1, 0, 0, 0, sizeof(set_tear_off), set_tear_off};
-
static int mdss_dsi_panel_on(struct mdss_panel_data *pdata)
{
struct mipi_panel_info *mipi;
@@ -183,14 +242,10 @@
pr_debug("%s: ctrl=%p ndx=%d\n", __func__, ctrl, ctrl->ndx);
- if (ctrl->on_cmds->size)
- mdss_dsi_cmds_tx(pdata, &dsi_panel_tx_buf,
- ctrl->on_cmds->buf,
- ctrl->on_cmds->size);
+ if (ctrl->on_cmds.cmd_cnt)
+ mdss_dsi_panel_cmds_send(ctrl, &ctrl->on_cmds);
- mdss_dsi_cmds_tx(pdata, &dsi_panel_tx_buf,
- &dsi_tear_on_cmd, 1);
-
+ pr_debug("%s:-\n", __func__);
return 0;
}
@@ -211,17 +266,95 @@
mipi = &pdata->panel_info.mipi;
- mdss_dsi_cmds_tx(pdata, &dsi_panel_tx_buf,
- &dsi_tear_off_cmd, 1);
+ if (ctrl->off_cmds.cmd_cnt)
+ mdss_dsi_panel_cmds_send(ctrl, &ctrl->off_cmds);
- if (ctrl->off_cmds->size)
- mdss_dsi_cmds_tx(pdata, &dsi_panel_tx_buf,
- ctrl->off_cmds->buf,
- ctrl->off_cmds->size);
+ pr_debug("%s:-\n", __func__);
+ return 0;
+}
+
+
+static int mdss_dsi_parse_dcs_cmds(struct device_node *np,
+ struct dsi_panel_cmds *pcmds, char *cmd_key, char *link_key)
+{
+ const char *data;
+ int blen = 0, len;
+ char *buf, *bp;
+ struct dsi_ctrl_hdr *dchdr;
+ int i, cnt;
+
+ data = of_get_property(np, cmd_key, &blen);
+ if (!data) {
+ pr_err("%s: failed, key=%s\n", __func__, cmd_key);
+ return -ENOMEM;
+ }
+
+ buf = kzalloc(sizeof(char) * blen, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ memcpy(buf, data, blen);
+
+ /* scan dcs commands */
+ bp = buf;
+ len = blen;
+ cnt = 0;
+ while (len > sizeof(*dchdr)) {
+ dchdr = (struct dsi_ctrl_hdr *)bp;
+ dchdr->dlen = ntohs(dchdr->dlen);
+ if (dchdr->dlen > len) {
+ pr_err("%s: dtsi cmd=%x error, len=%d",
+ __func__, dchdr->dtype, dchdr->dlen);
+ return -ENOMEM;
+ }
+ bp += sizeof(*dchdr);
+ len -= sizeof(*dchdr);
+ bp += dchdr->dlen;
+ len -= dchdr->dlen;
+ cnt++;
+ }
+
+ if (len != 0) {
+ pr_err("%s: dcs_cmd=%x len=%d error!",
+ __func__, buf[0], blen);
+ kfree(buf);
+ return -ENOMEM;
+ }
+
+ pcmds->cmds = kzalloc(cnt * sizeof(struct dsi_cmd_desc),
+ GFP_KERNEL);
+ if (!pcmds->cmds)
+ return -ENOMEM;
+
+ pcmds->cmd_cnt = cnt;
+ pcmds->buf = buf;
+ pcmds->blen = blen;
+
+ bp = buf;
+ len = blen;
+ for (i = 0; i < cnt; i++) {
+ dchdr = (struct dsi_ctrl_hdr *)bp;
+ len -= sizeof(*dchdr);
+ bp += sizeof(*dchdr);
+ pcmds->cmds[i].dchdr = *dchdr;
+ pcmds->cmds[i].payload = bp;
+ bp += dchdr->dlen;
+ len -= dchdr->dlen;
+ }
+
+ pcmds->link_state = DSI_LP_MODE; /* default */
+
+ data = of_get_property(np, link_key, NULL);
+ if (!strncmp(data, "DSI_HS_MODE", 11))
+ pcmds->link_state = DSI_HS_MODE;
+
+ pr_debug("%s: dcs_cmd=%x len=%d, cmd_cnt=%d link_state=%d\n", __func__,
+ pcmds->buf[0], pcmds->blen, pcmds->cmd_cnt, pcmds->link_state);
return 0;
}
+
static int mdss_panel_parse_dt(struct platform_device *pdev,
struct mdss_panel_common_pdata *panel_data)
{
@@ -229,12 +362,8 @@
u32 res[6], tmp;
u32 fbc_res[7];
int rc, i, len;
- int cmd_plen, data_offset;
const char *data;
static const char *bl_ctrl_type, *pdest;
- static const char *on_cmds_state, *off_cmds_state;
- char *on_cmds = NULL, *off_cmds = NULL;
- int num_of_on_cmds = 0, num_of_off_cmds = 0;
bool fbc_enabled = false;
rc = of_property_read_u32_array(np, "qcom,mdss-pan-res", res, 2);
@@ -301,15 +430,15 @@
} else if (!strncmp(bl_ctrl_type, "bl_ctrl_pwm", 11)) {
panel_data->panel_info.bklt_ctrl = BL_PWM;
- rc = of_property_read_u32(np, "qcom,dsi-pwm-period", &tmp);
+ rc = of_property_read_u32(np, "qcom,pwm-period", &tmp);
if (rc) {
- pr_err("%s:%d, Error, dsi pwm_period\n",
+ pr_err("%s:%d, Error, panel pwm_period\n",
__func__, __LINE__);
return -EINVAL;
}
panel_data->panel_info.pwm_period = tmp;
- rc = of_property_read_u32(np, "qcom,dsi-lpg-channel", &tmp);
+ rc = of_property_read_u32(np, "qcom,pwm-lpg-channel", &tmp);
if (rc) {
pr_err("%s:%d, Error, dsi lpg channel\n",
__func__, __LINE__);
@@ -317,8 +446,10 @@
}
panel_data->panel_info.pwm_lpg_chan = tmp;
- tmp = of_get_named_gpio(np, "qcom,dsi-pwm-gpio", 0);
- panel_data->panel_info.pwm_gpio = tmp;
+ tmp = of_get_named_gpio(np, "qcom,pwm-pmic-gpio", 0);
+ panel_data->panel_info.pwm_pmic_gpio = tmp;
+ } else if (!strncmp(bl_ctrl_type, "bl_ctrl_dcs", 11)) {
+ panel_data->panel_info.bklt_ctrl = BL_DCS_CMD;
} else {
pr_debug("%s: Unknown backlight control\n", __func__);
panel_data->panel_info.bklt_ctrl = UNKNOWN_CTRL;
@@ -529,171 +660,15 @@
panel_data->panel_info.bpp;
}
- data = of_get_property(np, "qcom,panel-on-cmds", &len);
- if (!data) {
- pr_err("%s:%d, Unable to read ON cmds", __func__, __LINE__);
- goto error;
- }
+ mdss_dsi_parse_dcs_cmds(np, &panel_data->on_cmds,
+ "qcom,panel-on-cmds", "qcom,on-cmds-dsi-state");
- on_cmds = kzalloc(sizeof(char) * len, GFP_KERNEL);
- if (!on_cmds)
- return -ENOMEM;
-
- memcpy(on_cmds, data, len);
-
- data_offset = 0;
- cmd_plen = 0;
- while ((len - data_offset) >= DT_CMD_HDR) {
- data_offset += (DT_CMD_HDR - 1);
- cmd_plen = on_cmds[data_offset++];
- data_offset += cmd_plen;
- num_of_on_cmds++;
- }
- if (!num_of_on_cmds) {
- pr_err("%s:%d, No ON cmds specified", __func__, __LINE__);
- goto error;
- }
-
- panel_data->dsi_panel_on_cmds =
- kzalloc(sizeof(struct dsi_panel_cmds_list), GFP_KERNEL);
- if (!panel_data->dsi_panel_on_cmds)
- return -ENOMEM;
-
- (panel_data->dsi_panel_on_cmds)->buf =
- kzalloc((num_of_on_cmds * sizeof(struct dsi_cmd_desc)),
- GFP_KERNEL);
- if (!(panel_data->dsi_panel_on_cmds)->buf)
- return -ENOMEM;
-
- data_offset = 0;
- for (i = 0; i < num_of_on_cmds; i++) {
- panel_data->dsi_panel_on_cmds->buf[i].dtype =
- on_cmds[data_offset++];
- panel_data->dsi_panel_on_cmds->buf[i].last =
- on_cmds[data_offset++];
- panel_data->dsi_panel_on_cmds->buf[i].vc =
- on_cmds[data_offset++];
- panel_data->dsi_panel_on_cmds->buf[i].ack =
- on_cmds[data_offset++];
- panel_data->dsi_panel_on_cmds->buf[i].wait =
- on_cmds[data_offset++];
- panel_data->dsi_panel_on_cmds->buf[i].dlen =
- on_cmds[data_offset++];
- panel_data->dsi_panel_on_cmds->buf[i].payload =
- &on_cmds[data_offset];
- data_offset += (panel_data->dsi_panel_on_cmds->buf[i].dlen);
- }
-
- if (data_offset != len) {
- pr_err("%s:%d, Incorrect ON command entries",
- __func__, __LINE__);
- goto error;
- }
-
- (panel_data->dsi_panel_on_cmds)->size = num_of_on_cmds;
-
- on_cmds_state = of_get_property(pdev->dev.of_node,
- "qcom,on-cmds-dsi-state", NULL);
- if (!strncmp(on_cmds_state, "DSI_LP_MODE", 11)) {
- (panel_data->dsi_panel_on_cmds)->ctrl_state =
- DSI_LP_MODE;
- } else if (!strncmp(on_cmds_state, "DSI_HS_MODE", 11)) {
- (panel_data->dsi_panel_on_cmds)->ctrl_state =
- DSI_HS_MODE;
- } else {
- pr_debug("%s: ON cmds state not specified. Set Default\n",
- __func__);
- (panel_data->dsi_panel_on_cmds)->ctrl_state =
- DSI_LP_MODE;
- }
-
- data = of_get_property(np, "qcom,panel-off-cmds", &len);
- if (!data) {
- pr_err("%s:%d, Unable to read OFF cmds", __func__, __LINE__);
- goto error;
- }
-
- off_cmds = kzalloc(sizeof(char) * len, GFP_KERNEL);
- if (!off_cmds)
- return -ENOMEM;
-
- memcpy(off_cmds, data, len);
-
- data_offset = 0;
- cmd_plen = 0;
- while ((len - data_offset) >= DT_CMD_HDR) {
- data_offset += (DT_CMD_HDR - 1);
- cmd_plen = off_cmds[data_offset++];
- data_offset += cmd_plen;
- num_of_off_cmds++;
- }
- if (!num_of_off_cmds) {
- pr_err("%s:%d, No OFF cmds specified", __func__, __LINE__);
- goto error;
- }
-
- panel_data->dsi_panel_off_cmds =
- kzalloc(sizeof(struct dsi_panel_cmds_list), GFP_KERNEL);
- if (!panel_data->dsi_panel_off_cmds)
- return -ENOMEM;
-
- (panel_data->dsi_panel_off_cmds)->buf = kzalloc(num_of_off_cmds
- * sizeof(struct dsi_cmd_desc),
- GFP_KERNEL);
- if (!(panel_data->dsi_panel_off_cmds)->buf)
- return -ENOMEM;
-
- data_offset = 0;
- for (i = 0; i < num_of_off_cmds; i++) {
- panel_data->dsi_panel_off_cmds->buf[i].dtype =
- off_cmds[data_offset++];
- panel_data->dsi_panel_off_cmds->buf[i].last =
- off_cmds[data_offset++];
- panel_data->dsi_panel_off_cmds->buf[i].vc =
- off_cmds[data_offset++];
- panel_data->dsi_panel_off_cmds->buf[i].ack =
- off_cmds[data_offset++];
- panel_data->dsi_panel_off_cmds->buf[i].wait =
- off_cmds[data_offset++];
- panel_data->dsi_panel_off_cmds->buf[i].dlen =
- off_cmds[data_offset++];
- panel_data->dsi_panel_off_cmds->buf[i].payload =
- &off_cmds[data_offset];
- data_offset += (panel_data->dsi_panel_off_cmds->buf[i].dlen);
- }
-
- if (data_offset != len) {
- pr_err("%s:%d, Incorrect OFF command entries",
- __func__, __LINE__);
- goto error;
- }
-
- (panel_data->dsi_panel_off_cmds)->size = num_of_off_cmds;
-
- off_cmds_state = of_get_property(pdev->dev.of_node,
- "qcom,off-cmds-dsi-state", NULL);
- if (!strncmp(off_cmds_state, "DSI_LP_MODE", 11)) {
- (panel_data->dsi_panel_off_cmds)->ctrl_state =
- DSI_LP_MODE;
- } else if (!strncmp(off_cmds_state, "DSI_HS_MODE", 11)) {
- (panel_data->dsi_panel_off_cmds)->ctrl_state =
- DSI_HS_MODE;
- } else {
- pr_debug("%s: ON cmds state not specified. Set Default\n",
- __func__);
- (panel_data->dsi_panel_off_cmds)->ctrl_state =
- DSI_LP_MODE;
- }
+ mdss_dsi_parse_dcs_cmds(np, &panel_data->off_cmds,
+ "qcom,panel-off-cmds", "qcom,off-cmds-dsi-state");
return 0;
-error:
- kfree((panel_data->dsi_panel_on_cmds)->buf);
- kfree((panel_data->dsi_panel_off_cmds)->buf);
- kfree(panel_data->dsi_panel_on_cmds);
- kfree(panel_data->dsi_panel_off_cmds);
- kfree(on_cmds);
- kfree(off_cmds);
+error:
return -EINVAL;
}
@@ -744,9 +719,6 @@
static int __init mdss_dsi_panel_init(void)
{
- mdss_dsi_buf_alloc(&dsi_panel_tx_buf, ALIGN(DSI_BUF_SIZE, SZ_4K));
- mdss_dsi_buf_alloc(&dsi_panel_rx_buf, ALIGN(DSI_BUF_SIZE, SZ_4K));
-
return platform_driver_register(&this_driver);
}
module_init(mdss_dsi_panel_init);
diff --git a/drivers/video/msm/mdss/mdss_hdmi_hdcp.c b/drivers/video/msm/mdss/mdss_hdmi_hdcp.c
index f726e79..1f0efd3 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_hdcp.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_hdcp.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2013 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -287,7 +287,7 @@
timeout_count = 100;
keys_state = (link0_status >> 28) & 0x7;
while ((keys_state != HDCP_KEYS_STATE_VALID) &&
- timeout_count--) {
+ --timeout_count) {
link0_status = DSS_REG_R(io, HDMI_HDCP_LINK0_STATUS);
keys_state = (link0_status >> 28) & 0x7;
DEV_DBG("%s: %s: Keys not ready(%d). s=%d\n, l0=%0x08x",
@@ -320,7 +320,7 @@
link0_status);
msleep(20);
}
- } while (!an_ready && timeout_count--);
+ } while (!an_ready && --timeout_count);
if (!timeout_count) {
rc = -ETIMEDOUT;
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.c b/drivers/video/msm/mdss/mdss_hdmi_tx.c
index 12552bc..ab91320 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.c
@@ -130,9 +130,9 @@
{0x18, 0x18, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
0x28, 0x28, 0x28, 0x28, 0x18, 0x28, 0x18, 0x28, 0x28,
0x28, 0x28}, /*01*/
- {0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
- 0x04, 0x04, 0x04, 0x04, 0x88, 0x00, 0x04, 0x04, 0x04,
- 0x04, 0x04}, /*02*/
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00}, /*02*/
{0x02, 0x06, 0x11, 0x15, 0x04, 0x13, 0x10, 0x05, 0x1F,
0x14, 0x20, 0x22, 0x21, 0x01, 0x03, 0x11, 0x00, 0x00,
0x00, 0x00}, /*03*/
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
index eb2bd21..afbbe55 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
@@ -14,11 +14,12 @@
#include <linux/kernel.h>
#include "mdss_panel.h"
#include "mdss_mdp.h"
+#include "mdss_dsi.h"
#define VSYNC_EXPIRE_TICK 4
#define START_THRESHOLD 4
-#define CONTINUE_TRESHOLD 4
+#define CONTINUE_THRESHOLD 4
#define MAX_SESSIONS 2
@@ -26,11 +27,12 @@
#define KOFF_TIMEOUT msecs_to_jiffies(84)
struct mdss_mdp_cmd_ctx {
+ struct mdss_mdp_ctl *ctl;
u32 pp_num;
u8 ref_cnt;
+ struct completion vsync_comp;
struct completion pp_comp;
struct completion stop_comp;
- atomic_t vsync_ref;
mdp_vsync_handler_t send_vsync;
int panel_on;
int koff_cnt;
@@ -46,6 +48,7 @@
u8 tear_check;
u16 height; /* panel height */
u16 vporch; /* vertical porches */
+ u16 start_threshold;
u32 vclk_line; /* vsync clock per line */
};
@@ -83,7 +86,7 @@
ctx->height);
mdss_mdp_pingpong_write(mixer, MDSS_MDP_REG_PP_SYNC_THRESH,
- (CONTINUE_TRESHOLD << 16) | (START_THRESHOLD));
+ (CONTINUE_THRESHOLD << 16) | (ctx->start_threshold));
mdss_mdp_pingpong_write(mixer, MDSS_MDP_REG_PP_TEAR_CHECK_EN, enable);
return 0;
@@ -118,13 +121,16 @@
pinfo->lcdc.v_front_porch +
pinfo->lcdc.v_pulse_width;
+ ctx->start_threshold = START_THRESHOLD;
+
total_lines = ctx->height + ctx->vporch;
total_lines *= pinfo->mipi.frame_rate;
ctx->vclk_line = mdp_vsync_clk_speed_hz / total_lines;
- pr_debug("%s: fr=%d tline=%d vcnt=%d vrate=%d\n",
+ pr_debug("%s: fr=%d tline=%d vcnt=%d thold=%d vrate=%d\n",
__func__, pinfo->mipi.frame_rate, total_lines,
- ctx->vclk_line, mdp_vsync_clk_speed_hz);
+ ctx->vclk_line, ctx->start_threshold,
+ mdp_vsync_clk_speed_hz);
} else {
enable = 0;
}
@@ -151,6 +157,8 @@
return;
}
+ complete_all(&ctx->vsync_comp);
+
pr_debug("%s: num=%d ctx=%d expire=%d koff=%d\n", __func__, ctl->num,
ctx->pp_num, ctx->expire, ctx->koff_cnt);
@@ -226,6 +234,9 @@
mdss_mdp_irq_disable(MDSS_MDP_IRQ_PING_PONG_RD_PTR,
ctx->pp_num);
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+ /* disable dsi clock */
+ mdss_mdp_ctl_intf_event(ctx->ctl, MDSS_EVENT_PANEL_CLK_CTRL,
+ (void *)0);
complete(&ctx->stop_comp);
pr_debug("%s: SET_CLK_OFF, pid=%d\n", __func__, current->pid);
} else {
@@ -249,11 +260,12 @@
enable = (handler->vsync_handler != NULL);
+ mutex_lock(&ctx->clk_mtx);
+
pr_debug("%s: ctx=%p ctx=%d enabled=%d %d clk_enabled=%d clk_ctrl=%d\n",
__func__, ctx, ctx->pp_num, ctx->vsync_enabled, enable,
ctx->clk_enabled, ctx->clk_control);
- mutex_lock(&ctx->clk_mtx);
if (ctx->vsync_enabled == enable) {
mutex_unlock(&ctx->clk_mtx);
return 0;
@@ -266,6 +278,8 @@
ctx->send_vsync = handler->vsync_handler;
spin_unlock_irqrestore(&ctx->clk_lock, flags);
if (ctx->clk_enabled == 0) {
+ mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_PANEL_CLK_CTRL,
+ (void *)1);
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
mdss_mdp_irq_enable(MDSS_MDP_IRQ_PING_PONG_RD_PTR,
ctx->pp_num);
@@ -294,10 +308,11 @@
return;
}
+ mutex_lock(&ctx->clk_mtx);
+
pr_debug("%s: ctx=%p num=%d clk_enabled=%d\n", __func__,
ctx, ctx->pp_num, ctx->clk_enabled);
- mutex_lock(&ctx->clk_mtx);
spin_lock_irqsave(&ctx->clk_lock, flags);
ctx->koff_cnt++;
ctx->clk_control = 0;
@@ -309,6 +324,8 @@
spin_unlock_irqrestore(&ctx->clk_lock, flags);
if (set_clk_on) {
+ mdss_mdp_ctl_intf_event(ctx->ctl, MDSS_EVENT_PANEL_CLK_CTRL,
+ (void *)1);
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
ctx->vsync_enabled = 1;
mdss_mdp_irq_enable(MDSS_MDP_IRQ_PING_PONG_RD_PTR, ctx->pp_num);
@@ -331,16 +348,18 @@
pr_debug("%s: intf_num=%d ctx=%p\n", __func__, ctl->intf_num, ctx);
- rc = wait_for_completion_interruptible_timeout(&ctx->pp_comp,
+ rc = wait_for_completion_interruptible_timeout(&ctx->vsync_comp,
KOFF_TIMEOUT);
WARN(rc <= 0, "cmd kickoff timed out (%d) ctl=%d\n", rc, ctl->num);
- return rc;
+ return 0;
}
int mdss_mdp_cmd_kickoff(struct mdss_mdp_ctl *ctl, void *arg)
{
struct mdss_mdp_cmd_ctx *ctx;
+ unsigned long flags;
+ int need_wait = 0;
int rc;
ctx = (struct mdss_mdp_cmd_ctx *) ctl->priv_data;
@@ -349,10 +368,21 @@
return -ENODEV;
}
- pr_debug("%s: kickoff intf_num=%d ctx=%p\n", __func__,
- ctl->intf_num, ctx);
+ spin_lock_irqsave(&ctx->clk_lock, flags);
+ if (ctx->koff_cnt > 0)
+ need_wait = 1;
+ spin_unlock_irqrestore(&ctx->clk_lock, flags);
- mdss_mdp_cmd_chk_clock(ctx);
+ pr_debug("%s: need_wait=%d intf_num=%d ctx=%p\n",
+ __func__, need_wait, ctl->intf_num, ctx);
+
+ if (need_wait) {
+ rc = wait_for_completion_interruptible_timeout(
+ &ctx->pp_comp, KOFF_TIMEOUT);
+
+ WARN(rc <= 0, "cmd kickoff timed out (%d) ctl=%d\n",
+ rc, ctl->num);
+ }
if (ctx->panel_on == 0) {
rc = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_UNBLANK, NULL);
@@ -364,10 +394,19 @@
WARN(rc, "intf %d panel on error (%d)\n", ctl->intf_num, rc);
}
+ mdss_mdp_cmd_chk_clock(ctx);
+
+ /*
+ * tx dcs command if had any
+ */
+ mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_DSI_CMDLIST_KOFF, NULL);
+
+ INIT_COMPLETION(ctx->vsync_comp);
INIT_COMPLETION(ctx->pp_comp);
mdss_mdp_irq_enable(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num);
mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_START, 1);
+ mb();
return 0;
}
@@ -454,10 +493,11 @@
return -ENODEV;
}
+ ctx->ctl = ctl;
ctx->pp_num = mixer->num;
+ init_completion(&ctx->vsync_comp);
init_completion(&ctx->pp_comp);
init_completion(&ctx->stop_comp);
- atomic_set(&ctx->vsync_ref, 0);
spin_lock_init(&ctx->clk_lock);
mutex_init(&ctx->clk_mtx);
INIT_WORK(&ctx->clk_work, clk_ctrl_work);
diff --git a/drivers/video/msm/mdss/mdss_panel.h b/drivers/video/msm/mdss/mdss_panel.h
index 9e8cfa7..f138420 100644
--- a/drivers/video/msm/mdss/mdss_panel.h
+++ b/drivers/video/msm/mdss/mdss_panel.h
@@ -81,6 +81,10 @@
* @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.
+ * @MDSS_EVENT_PANEL_CLK_CTRL: panel clock control
+ - 0 clock disable
+ - 1 clock enable
+ * @MDSS_EVENT_DSI_CMDLIST_KOFF: kickoff sending dcs command from command list
*/
enum mdss_intf_events {
MDSS_EVENT_RESET = 1,
@@ -94,6 +98,8 @@
MDSS_EVENT_CHECK_PARAMS,
MDSS_EVENT_CONT_SPLASH_FINISH,
MDSS_EVENT_FB_REGISTERED,
+ MDSS_EVENT_PANEL_CLK_CTRL,
+ MDSS_EVENT_DSI_CMDLIST_KOFF,
};
struct lcd_panel_info {
@@ -222,7 +228,7 @@
u32 out_format;
u32 vic; /* video identification code */
int bklt_ctrl; /* backlight ctrl */
- int pwm_gpio;
+ int pwm_pmic_gpio;
int pwm_lpg_chan;
int pwm_period;
diff --git a/drivers/video/msm/mdss/msm_mdss_io_8974.c b/drivers/video/msm/mdss/msm_mdss_io_8974.c
index 5564ceb..12bc5e0 100644
--- a/drivers/video/msm/mdss/msm_mdss_io_8974.c
+++ b/drivers/video/msm/mdss/msm_mdss_io_8974.c
@@ -170,13 +170,10 @@
clk_unprepare(ctrl_pdata->byte_clk);
}
-void mdss_dsi_clk_enable(struct mdss_panel_data *pdata)
+void mdss_dsi_clk_enable(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
{
- struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
u32 esc_clk_rate = 19200000;
- ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
- panel_data);
if (!ctrl_pdata) {
pr_err("%s: Invalid input data\n", __func__);
return;
@@ -206,12 +203,8 @@
ctrl_pdata->mdss_dsi_clk_on = 1;
}
-void mdss_dsi_clk_disable(struct mdss_panel_data *pdata)
+void mdss_dsi_clk_disable(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
{
- struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
-
- ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
- panel_data);
if (!ctrl_pdata) {
pr_err("%s: Invalid input data\n", __func__);
return;
diff --git a/include/linux/dvb/dmx.h b/include/linux/dvb/dmx.h
index aa1eba5..ce9e5b9 100644
--- a/include/linux/dvb/dmx.h
+++ b/include/linux/dvb/dmx.h
@@ -195,7 +195,7 @@
/* write pointer offset in bytes */
unsigned int write_offset;
- /* non-zero if data error occured */
+ /* non-zero if data error occurred */
int error;
};
@@ -237,7 +237,10 @@
* (dmx_sct_filter_params) and no sections were
* received for the given time.
*/
- DMX_EVENT_SECTION_TIMEOUT = 0x00000400
+ DMX_EVENT_SECTION_TIMEOUT = 0x00000400,
+
+ /* Scrambling bits change between clear and scrambled */
+ DMX_EVENT_SCRAMBLING_STATUS_CHANGE = 0x00000800
};
enum dmx_oob_cmd {
@@ -256,7 +259,7 @@
/* Discontinuity indicator was set */
#define DMX_FILTER_DISCONTINUITY_INDICATOR 0x02
-/* PES legnth in PES header is not correct */
+/* PES length in PES header is not correct */
#define DMX_FILTER_PES_LENGTH_ERROR 0x04
@@ -412,7 +415,7 @@
/*
* The PID the index entry belongs to.
* In case of recording filter, multiple PIDs may exist in the same
- * filter through DMX_ADD_PID ioctl and each can be indexed seperatly.
+ * filter through DMX_ADD_PID ioctl and each can be indexed separately.
*/
__u16 pid;
@@ -423,7 +426,7 @@
__u64 match_tsp_num;
/*
- * The TS packet number in the recorded data preceeding
+ * The TS packet number in the recorded data preceding
* match_tsp_num and has PUSI set.
*/
__u64 last_pusi_tsp_num;
@@ -432,6 +435,23 @@
__u64 stc;
};
+/* Scrambling information associated with DMX_EVENT_SCRAMBLING_STATUS_CHANGE */
+struct dmx_scrambling_status_event_info {
+ /*
+ * The PID which its scrambling bit status changed.
+ * In case of recording filter, multiple PIDs may exist in the same
+ * filter through DMX_ADD_PID ioctl, each may have
+ * different scrambling bits status.
+ */
+ __u16 pid;
+
+ /* old value of scrambling bits */
+ __u8 old_value;
+
+ /* new value of scrambling bits */
+ __u8 new_value;
+};
+
/*
* Filter's event returned through DMX_GET_EVENT.
* poll with POLLPRI would block until events are available.
@@ -447,6 +467,7 @@
struct dmx_es_data_event_info es_data;
struct dmx_marker_event_info marker;
struct dmx_index_event_info index;
+ struct dmx_scrambling_status_event_info scrambling_status;
} params;
};
@@ -754,6 +775,19 @@
__u32 identifier;
};
+struct dmx_scrambling_bits {
+ /*
+ * The PID to return its scrambling bit value.
+ * In case of recording filter, multiple PIDs may exist in the same
+ * filter through DMX_ADD_PID ioctl, each may have different
+ * scrambling bits status.
+ */
+ __u16 pid;
+
+ /* Current value of scrambling bits: 0, 1, 2 or 3 */
+ __u8 value;
+};
+
#define DMX_START _IO('o', 41)
#define DMX_STOP _IO('o', 42)
#define DMX_SET_FILTER _IOW('o', 43, struct dmx_sct_filter_params)
@@ -784,5 +818,6 @@
#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)
+#define DMX_GET_SCRAMBLING_BITS _IOWR('o', 72, struct dmx_scrambling_bits)
#endif /*_DVBDMX_H_*/
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index 61e9cb1..e4df414 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -716,7 +716,7 @@
} data;
};
-#define MDP_MAX_FENCE_FD 10
+#define MDP_MAX_FENCE_FD 32
#define MDP_BUF_SYNC_FLAG_WAIT 1
struct mdp_buf_sync {
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index f551e75..6d7d178 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -3069,4 +3069,32 @@
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U = 1<<3,
};
+/**
+ * enum nl80211_connect_failed_reason - connection request failed reasons
+ * @NL80211_CONN_FAIL_MAX_CLIENTS: Maximum number of clients that can be
+ * handled by the AP is reached.
+ * @NL80211_CONN_FAIL_BLOCKED_CLIENT: Connection request is rejected due to ACL.
+ */
+enum nl80211_connect_failed_reason {
+ NL80211_CONN_FAIL_MAX_CLIENTS,
+ NL80211_CONN_FAIL_BLOCKED_CLIENT,
+};
+
+/**
+ * enum nl80211_acl_policy - access control policy
+ *
+ * Access control policy is applied on a MAC list set by
+ * %NL80211_CMD_START_AP and %NL80211_CMD_SET_MAC_ACL, to
+ * be used with %NL80211_ATTR_ACL_POLICY.
+ *
+ * @NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED: Deny stations which are
+ * listed in ACL, i.e. allow all the stations which are not listed
+ * in ACL to authenticate.
+ * @NL80211_ACL_POLICY_DENY_UNLESS_LISTED: Allow the stations which are listed
+ * in ACL, i.e. deny all the stations which are not listed in ACL.
+ */
+enum nl80211_acl_policy {
+ NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED,
+ NL80211_ACL_POLICY_DENY_UNLESS_LISTED,
+};
#endif /* __LINUX_NL80211_H */
diff --git a/include/linux/of_coresight.h b/include/linux/of_coresight.h
index 0943dda..eb20e80 100644
--- a/include/linux/of_coresight.h
+++ b/include/linux/of_coresight.h
@@ -13,7 +13,7 @@
#ifndef __LINUX_OF_CORESIGHT_H
#define __LINUX_OF_CORESIGHT_H
-#ifdef CONFIG_OF
+#ifdef CONFIG_OF_CORESIGHT
extern struct coresight_platform_data *of_get_coresight_platform_data(
struct device *dev, struct device_node *node);
extern struct coresight_cti_data *of_get_coresight_cti_data(
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 67889bf..952bcb1 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -2726,6 +2726,8 @@
#endif /* CONFIG_SMP */
+extern struct atomic_notifier_head migration_notifier_head;
+
extern long sched_setaffinity(pid_t pid, const struct cpumask *new_mask);
extern long sched_getaffinity(pid_t pid, struct cpumask *mask);
diff --git a/include/media/msm_media_info.h b/include/media/msm_media_info.h
index 993a4ab..65831db 100644
--- a/include/media/msm_media_info.h
+++ b/include/media/msm_media_info.h
@@ -7,6 +7,7 @@
enum color_fmts {
COLOR_FMT_NV12,
+ COLOR_FMT_NV21,
};
static inline unsigned int VENUS_Y_STRIDE(int color_fmt, int width)
@@ -16,6 +17,7 @@
goto invalid_input;
switch (color_fmt) {
+ case COLOR_FMT_NV21:
case COLOR_FMT_NV12:
alignment = 128;
stride = MSM_MEDIA_ALIGN(width, alignment);
@@ -34,6 +36,7 @@
goto invalid_input;
switch (color_fmt) {
+ case COLOR_FMT_NV21:
case COLOR_FMT_NV12:
alignment = 128;
stride = MSM_MEDIA_ALIGN(width, alignment);
@@ -52,6 +55,7 @@
goto invalid_input;
switch (color_fmt) {
+ case COLOR_FMT_NV21:
case COLOR_FMT_NV12:
alignment = 32;
sclines = MSM_MEDIA_ALIGN(height, alignment);
@@ -70,6 +74,7 @@
goto invalid_input;
switch (color_fmt) {
+ case COLOR_FMT_NV21:
case COLOR_FMT_NV12:
alignment = 16;
sclines = MSM_MEDIA_ALIGN(((height + 1) >> 1), alignment);
@@ -96,6 +101,7 @@
y_sclines = VENUS_Y_SCANLINES(color_fmt, height);
uv_sclines = VENUS_UV_SCANLINES(color_fmt, height);
switch (color_fmt) {
+ case COLOR_FMT_NV21:
case COLOR_FMT_NV12:
uv_alignment = 4096;
y_plane = y_stride * y_sclines;
diff --git a/include/media/msmb_pproc.h b/include/media/msmb_pproc.h
index c185096..aead2d2 100644
--- a/include/media/msmb_pproc.h
+++ b/include/media/msmb_pproc.h
@@ -18,6 +18,11 @@
MSM_CPP_REALTIME_FRAME,
};
+enum msm_vpe_frame_type {
+ MSM_VPE_OFFLINE_FRAME,
+ MSM_VPE_REALTIME_FRAME,
+};
+
struct msm_cpp_frame_strip_info {
int scale_v_en;
int scale_h_en;
@@ -117,6 +122,57 @@
uint32_t cpp_hw_caps;
};
+struct msm_vpe_frame_strip_info {
+ uint32_t src_w;
+ uint32_t src_h;
+ uint32_t dst_w;
+ uint32_t dst_h;
+ uint32_t src_x;
+ uint32_t src_y;
+ uint32_t phase_step_x;
+ uint32_t phase_step_y;
+ uint32_t phase_init_x;
+ uint32_t phase_init_y;
+};
+
+struct msm_vpe_buffer_info_t {
+ int fd;
+ uint32_t index;
+ uint32_t offset;
+ uint8_t native_buff;
+ uint8_t processed_divert;
+};
+
+struct msm_vpe_stream_buff_info_t {
+ uint32_t identity;
+ uint32_t num_buffs;
+ struct msm_vpe_buffer_info_t *buffer_info;
+};
+
+struct msm_vpe_frame_info_t {
+ int32_t frame_id;
+ struct timeval timestamp;
+ uint32_t inst_id;
+ uint32_t identity;
+ uint32_t client_id;
+ enum msm_vpe_frame_type frame_type;
+ struct msm_vpe_frame_strip_info strip_info;
+ int src_fd;
+ int dst_fd;
+ struct ion_handle *src_ion_handle;
+ struct ion_handle *dest_ion_handle;
+ unsigned long src_phyaddr;
+ unsigned long dest_phyaddr;
+ unsigned long src_chroma_plane_offset;
+ unsigned long dest_chroma_plane_offset;
+ struct timeval in_time, out_time;
+ void *cookie;
+
+ struct msm_vpe_buffer_info_t input_buffer_info;
+ struct msm_vpe_buffer_info_t output_buffer_info;
+};
+
+
#define VIDIOC_MSM_CPP_CFG \
_IOWR('V', BASE_VIDIOC_PRIVATE, struct msm_camera_v4l2_ioctl_t)
@@ -141,7 +197,27 @@
#define VIDIOC_MSM_CPP_DEQUEUE_STREAM_BUFF_INFO \
_IOWR('V', BASE_VIDIOC_PRIVATE + 7, struct msm_camera_v4l2_ioctl_t)
+
+#define VIDIOC_MSM_VPE_CFG \
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 8, struct msm_camera_v4l2_ioctl_t)
+
+#define VIDIOC_MSM_VPE_TRANSACTION_SETUP \
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 9, struct msm_camera_v4l2_ioctl_t)
+
+#define VIDIOC_MSM_VPE_GET_EVENTPAYLOAD \
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 10, struct msm_camera_v4l2_ioctl_t)
+
+#define VIDIOC_MSM_VPE_GET_INST_INFO \
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 11, struct msm_camera_v4l2_ioctl_t)
+
+#define VIDIOC_MSM_VPE_ENQUEUE_STREAM_BUFF_INFO \
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 12, struct msm_camera_v4l2_ioctl_t)
+
+#define VIDIOC_MSM_VPE_DEQUEUE_STREAM_BUFF_INFO \
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 13, struct msm_camera_v4l2_ioctl_t)
+
#define V4L2_EVENT_CPP_FRAME_DONE (V4L2_EVENT_PRIVATE_START + 0)
+#define V4L2_EVENT_VPE_FRAME_DONE (V4L2_EVENT_PRIVATE_START + 1)
struct msm_camera_v4l2_ioctl_t {
uint32_t id;
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index dc29eb9..fb2b57a 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -416,6 +416,26 @@
size_t probe_resp_len;
};
+struct mac_address {
+ u8 addr[ETH_ALEN];
+};
+
+/**
+ * struct cfg80211_acl_data - Access control list data
+ *
+ * @acl_policy: ACL policy to be applied on the station's
+ * entry specified by mac_addr
+ * @n_acl_entries: Number of MAC address entries passed
+ * @mac_addrs: List of MAC addresses of stations to be used for ACL
+ */
+struct cfg80211_acl_data {
+ enum nl80211_acl_policy acl_policy;
+ int n_acl_entries;
+
+ /* Keep it last */
+ struct mac_address mac_addrs[];
+};
+
/**
* struct cfg80211_ap_settings - AP configuration
*
@@ -432,6 +452,8 @@
* @privacy: the BSS uses privacy
* @auth_type: Authentication type (algorithm)
* @inactivity_timeout: time in seconds to determine station's inactivity.
+ * @acl: ACL configuration used by the drivers which has support for
+ * MAC address based access control
*/
struct cfg80211_ap_settings {
struct cfg80211_beacon_data beacon;
@@ -444,6 +466,7 @@
bool privacy;
enum nl80211_auth_type auth_type;
int inactivity_timeout;
+ const struct cfg80211_acl_data *acl;
};
/**
@@ -1559,6 +1582,13 @@
* later passes to cfg80211_probe_status().
*
* @set_noack_map: Set the NoAck Map for the TIDs.
+ * @set_mac_acl: Sets MAC address control list in AP and P2P GO mode.
+ * Parameters include ACL policy, an array of MAC address of stations
+ * and the number of MAC addresses. If there is already a list in driver
+ * this new list replaces the existing one. Driver has to clear its ACL
+ * when number of MAC addresses entries is passed as 0. Drivers which
+ * advertise the support for MAC based ACL have to implement this callback.
+ *
*/
struct cfg80211_ops {
int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
@@ -1757,6 +1787,9 @@
struct ieee80211_channel *(*get_channel)(struct wiphy *wiphy);
int (*update_ft_ies)(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_update_ft_ies_params *ftie);
+
+ int (*set_mac_acl)(struct wiphy *wiphy, struct net_device *dev,
+ const struct cfg80211_acl_data *params);
};
/*
@@ -1924,10 +1957,6 @@
bool beacon_int_infra_match;
};
-struct mac_address {
- u8 addr[ETH_ALEN];
-};
-
struct ieee80211_txrx_stypes {
u16 tx, rx;
};
@@ -2068,6 +2097,9 @@
* @ap_sme_capa: AP SME capabilities, flags from &enum nl80211_ap_sme_features.
* @ht_capa_mod_mask: Specify what ht_cap values can be over-ridden.
* If null, then none can be over-ridden.
+ *
+ * @max_acl_mac_addrs: Maximum number of MAC addresses that the device
+ * supports for ACL.
*/
struct wiphy {
/* assign these fields before you register the wiphy */
@@ -2089,6 +2121,8 @@
/* Supported interface modes, OR together BIT(NL80211_IFTYPE_...) */
u16 interface_modes;
+ u16 max_acl_mac_addrs;
+
u32 flags, features;
u32 ap_sme_capa;
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 862e172..1a07d2e 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -87,6 +87,8 @@
#define CREATE_TRACE_POINTS
#include <trace/events/sched.h>
+ATOMIC_NOTIFIER_HEAD(migration_notifier_head);
+
void start_bandwidth_timer(struct hrtimer *period_timer, ktime_t period)
{
unsigned long delta;
@@ -1589,15 +1591,17 @@
try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags)
{
unsigned long flags;
- int cpu, success = 0;
+ int cpu, src_cpu, success = 0;
smp_wmb();
raw_spin_lock_irqsave(&p->pi_lock, flags);
+ src_cpu = task_cpu(p);
+ cpu = src_cpu;
+
if (!(p->state & state))
goto out;
success = 1; /* we're going to change ->state */
- cpu = task_cpu(p);
if (p->on_rq && ttwu_remote(p, wake_flags))
goto stat;
@@ -1634,7 +1638,7 @@
p->sched_class->task_waking(p);
cpu = select_task_rq(p, SD_BALANCE_WAKE, wake_flags);
- if (task_cpu(p) != cpu) {
+ if (src_cpu != cpu) {
wake_flags |= WF_MIGRATED;
set_task_cpu(p, cpu);
}
@@ -1646,6 +1650,9 @@
out:
raw_spin_unlock_irqrestore(&p->pi_lock, flags);
+ if (src_cpu != cpu && task_notify_on_migrate(p))
+ atomic_notifier_call_chain(&migration_notifier_head,
+ cpu, (void *)src_cpu);
return success;
}
@@ -5068,6 +5075,7 @@
static int __migrate_task(struct task_struct *p, int src_cpu, int dest_cpu)
{
struct rq *rq_dest, *rq_src;
+ bool moved = false;
int ret = 0;
if (unlikely(!cpu_active(dest_cpu)))
@@ -5094,12 +5102,16 @@
set_task_cpu(p, dest_cpu);
enqueue_task(rq_dest, p, 0);
check_preempt_curr(rq_dest, p, 0);
+ moved = true;
}
done:
ret = 1;
fail:
double_rq_unlock(rq_src, rq_dest);
raw_spin_unlock(&p->pi_lock);
+ if (moved && task_notify_on_migrate(p))
+ atomic_notifier_call_chain(&migration_notifier_head,
+ dest_cpu, (void *)src_cpu);
return ret;
}
@@ -7731,6 +7743,24 @@
sched_move_task(task);
}
+static u64 cpu_notify_on_migrate_read_u64(struct cgroup *cgrp,
+ struct cftype *cft)
+{
+ struct task_group *tg = cgroup_tg(cgrp);
+
+ return tg->notify_on_migrate;
+}
+
+static int cpu_notify_on_migrate_write_u64(struct cgroup *cgrp,
+ struct cftype *cft, u64 notify)
+{
+ struct task_group *tg = cgroup_tg(cgrp);
+
+ tg->notify_on_migrate = (notify > 0);
+
+ return 0;
+}
+
#ifdef CONFIG_FAIR_GROUP_SCHED
static int cpu_shares_write_u64(struct cgroup *cgrp, struct cftype *cftype,
u64 shareval)
@@ -8002,6 +8032,11 @@
#endif /* CONFIG_RT_GROUP_SCHED */
static struct cftype cpu_files[] = {
+ {
+ .name = "notify_on_migrate",
+ .read_u64 = cpu_notify_on_migrate_read_u64,
+ .write_u64 = cpu_notify_on_migrate_write_u64,
+ },
#ifdef CONFIG_FAIR_GROUP_SCHED
{
.name = "shares",
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index 7e31770..103730d 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -2126,11 +2126,11 @@
static void hrtick_start_fair(struct rq *rq, struct task_struct *p)
{
struct sched_entity *se = &p->se;
- struct cfs_rq *cfs_rq = &rq->cfs;
+ struct cfs_rq *cfs_rq = cfs_rq_of(se);
WARN_ON(task_rq(p) != rq);
- if (cfs_rq->h_nr_running > 1) {
+ if (rq->cfs.h_nr_running > 1) {
u64 slice = sched_slice(cfs_rq, se);
u64 ran = se->sum_exec_runtime - se->prev_sum_exec_runtime;
s64 delta = slice - ran;
@@ -3101,6 +3101,8 @@
unsigned int loop_max;
};
+static DEFINE_PER_CPU(bool, dbs_boost_needed);
+
/*
* move_task - move a task from one runqueue to another runqueue.
* Both runqueues must be locked.
@@ -3111,6 +3113,8 @@
set_task_cpu(p, env->dst_cpu);
activate_task(env->dst_rq, p, 0);
check_preempt_curr(env->dst_rq, p, 0);
+ if (task_notify_on_migrate(p))
+ per_cpu(dbs_boost_needed, env->dst_cpu) = true;
}
/*
@@ -4541,9 +4545,15 @@
*/
sd->nr_balance_failed = sd->cache_nice_tries+1;
}
- } else
+ } else {
sd->nr_balance_failed = 0;
-
+ if (per_cpu(dbs_boost_needed, this_cpu)) {
+ per_cpu(dbs_boost_needed, this_cpu) = false;
+ atomic_notifier_call_chain(&migration_notifier_head,
+ this_cpu,
+ (void *)cpu_of(busiest));
+ }
+ }
if (likely(!active_balance)) {
/* We were unbalanced, so reset the balancing interval */
sd->balance_interval = sd->min_interval;
@@ -4698,6 +4708,12 @@
out_unlock:
busiest_rq->active_balance = 0;
raw_spin_unlock_irq(&busiest_rq->lock);
+ if (per_cpu(dbs_boost_needed, target_cpu)) {
+ per_cpu(dbs_boost_needed, target_cpu) = false;
+ atomic_notifier_call_chain(&migration_notifier_head,
+ target_cpu,
+ (void *)cpu_of(busiest_rq));
+ }
return 0;
}
diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c
index 8f32475..f8317df 100644
--- a/kernel/sched/rt.c
+++ b/kernel/sched/rt.c
@@ -1604,6 +1604,7 @@
struct task_struct *next_task;
struct rq *lowest_rq;
int ret = 0;
+ bool moved = false;
if (!rq->rt.overloaded)
return 0;
@@ -1673,6 +1674,7 @@
deactivate_task(rq, next_task, 0);
set_task_cpu(next_task, lowest_rq->cpu);
+ moved = true;
activate_task(lowest_rq, next_task, 0);
ret = 1;
@@ -1683,6 +1685,11 @@
out:
put_task_struct(next_task);
+ if (moved && task_notify_on_migrate(next_task))
+ atomic_notifier_call_chain(&migration_notifier_head,
+ cpu_of(lowest_rq),
+ (void *)cpu_of(rq));
+
return ret;
}
@@ -1696,8 +1703,10 @@
static int pull_rt_task(struct rq *this_rq)
{
int this_cpu = this_rq->cpu, ret = 0, cpu;
- struct task_struct *p;
+ struct task_struct *p = NULL;
struct rq *src_rq;
+ bool moved = false;
+ int src_cpu = 0;
if (likely(!rt_overloaded(this_rq)))
return 0;
@@ -1758,6 +1767,10 @@
deactivate_task(src_rq, p, 0);
set_task_cpu(p, this_cpu);
activate_task(this_rq, p, 0);
+
+ moved = true;
+ src_cpu = cpu_of(src_rq);
+
/*
* We continue with the search, just in
* case there's an even higher prio task
@@ -1769,6 +1782,11 @@
double_unlock_balance(this_rq, src_rq);
}
+ if (moved && task_notify_on_migrate(p))
+ atomic_notifier_call_chain(&migration_notifier_head,
+ this_cpu,
+ (void *)src_cpu);
+
return ret;
}
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index 451bd4f..5370bcb 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -104,6 +104,8 @@
struct task_group {
struct cgroup_subsys_state css;
+ bool notify_on_migrate;
+
#ifdef CONFIG_FAIR_GROUP_SCHED
/* schedulable entities of this group on each cpu */
struct sched_entity **se;
@@ -554,6 +556,11 @@
return autogroup_task_group(p, tg);
}
+static inline bool task_notify_on_migrate(struct task_struct *p)
+{
+ return task_group(p)->notify_on_migrate;
+}
+
/* Change a task's cfs_rq and parent entity if it moves across CPUs/groups */
static inline void set_task_rq(struct task_struct *p, unsigned int cpu)
{
@@ -579,7 +586,10 @@
{
return NULL;
}
-
+static inline bool task_notify_on_migrate(struct task_struct *p)
+{
+ return false;
+}
#endif /* CONFIG_CGROUP_SCHED */
static inline void __set_task_cpu(struct task_struct *p, unsigned int cpu)
diff --git a/net/wireless/core.c b/net/wireless/core.c
index ccdfed8..674c1fa 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -505,6 +505,11 @@
ETH_ALEN)))
return -EINVAL;
+ if (WARN_ON(wiphy->max_acl_mac_addrs &&
+ (!(wiphy->flags & WIPHY_FLAG_HAVE_AP_SME) ||
+ !rdev->ops->set_mac_acl)))
+ return -EINVAL;
+
if (wiphy->addresses)
memcpy(wiphy->perm_addr, wiphy->addresses[0].addr, ETH_ALEN);
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index e1fa62e..6ed6d3e 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -210,6 +210,8 @@
[NL80211_ATTR_USER_REG_HINT_TYPE] = { .type = NLA_U32 },
[NL80211_ATTR_SAE_DATA] = { .type = NLA_BINARY, },
[NL80211_ATTR_VHT_CAPABILITY] = { .len = NL80211_VHT_CAPABILITY_LEN },
+ [NL80211_ATTR_ACL_POLICY] = {. type = NLA_U32 },
+ [NL80211_ATTR_MAC_ADDRS] = { .type = NLA_NESTED },
[NL80211_ATTR_STA_CAPABILITY] = { .type = NLA_U16 },
[NL80211_ATTR_STA_EXT_CAPABILITY] = { .type = NLA_BINARY, },
[NL80211_ATTR_SPLIT_WIPHY_DUMP] = { .type = NLA_FLAG, },
@@ -1066,6 +1068,11 @@
sizeof(*dev->wiphy.ht_capa_mod_mask),
dev->wiphy.ht_capa_mod_mask);
+ if (dev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME &&
+ dev->wiphy.max_acl_mac_addrs)
+ NLA_PUT_U32(msg, NL80211_ATTR_MAC_ACL_MAX,
+ dev->wiphy.max_acl_mac_addrs);
+
return genlmsg_end(msg, hdr);
nla_put_failure:
@@ -2105,6 +2112,97 @@
return err;
}
+/* This function returns an error or the number of nested attributes */
+static int validate_acl_mac_addrs(struct nlattr *nl_attr)
+{
+ struct nlattr *attr;
+ int n_entries = 0, tmp;
+
+ nla_for_each_nested(attr, nl_attr, tmp) {
+ if (nla_len(attr) != ETH_ALEN)
+ return -EINVAL;
+
+ n_entries++;
+ }
+
+ return n_entries;
+}
+
+/*
+ * This function parses ACL information and allocates memory for ACL data.
+ * On successful return, the calling function is responsible to free the
+ * ACL buffer returned by this function.
+ */
+static struct cfg80211_acl_data *parse_acl_data(struct wiphy *wiphy,
+ struct genl_info *info)
+{
+ enum nl80211_acl_policy acl_policy;
+ struct nlattr *attr;
+ struct cfg80211_acl_data *acl;
+ int i = 0, n_entries, tmp;
+
+ if (!wiphy->max_acl_mac_addrs)
+ return ERR_PTR(-EOPNOTSUPP);
+
+ if (!info->attrs[NL80211_ATTR_ACL_POLICY])
+ return ERR_PTR(-EINVAL);
+
+ acl_policy = nla_get_u32(info->attrs[NL80211_ATTR_ACL_POLICY]);
+ if (acl_policy != NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED &&
+ acl_policy != NL80211_ACL_POLICY_DENY_UNLESS_LISTED)
+ return ERR_PTR(-EINVAL);
+
+ if (!info->attrs[NL80211_ATTR_MAC_ADDRS])
+ return ERR_PTR(-EINVAL);
+
+ n_entries = validate_acl_mac_addrs(info->attrs[NL80211_ATTR_MAC_ADDRS]);
+ if (n_entries < 0)
+ return ERR_PTR(n_entries);
+
+ if (n_entries > wiphy->max_acl_mac_addrs)
+ return ERR_PTR(-ENOTSUPP);
+
+ acl = kzalloc(sizeof(*acl) + (sizeof(struct mac_address) * n_entries),
+ GFP_KERNEL);
+ if (!acl)
+ return ERR_PTR(-ENOMEM);
+
+ nla_for_each_nested(attr, info->attrs[NL80211_ATTR_MAC_ADDRS], tmp) {
+ memcpy(acl->mac_addrs[i].addr, nla_data(attr), ETH_ALEN);
+ i++;
+ }
+
+ acl->n_acl_entries = n_entries;
+ acl->acl_policy = acl_policy;
+
+ return acl;
+}
+
+static int nl80211_set_mac_acl(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct net_device *dev = info->user_ptr[1];
+ struct cfg80211_acl_data *acl;
+ int err;
+
+ if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
+ dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
+ return -EOPNOTSUPP;
+
+ if (!dev->ieee80211_ptr->beacon_interval)
+ return -EINVAL;
+
+ acl = parse_acl_data(&rdev->wiphy, info);
+ if (IS_ERR(acl))
+ return PTR_ERR(acl);
+
+ err = rdev->ops->set_mac_acl(&rdev->wiphy, dev, acl);
+
+ kfree(acl);
+
+ return err;
+}
+
static int nl80211_parse_beacon(struct genl_info *info,
struct cfg80211_beacon_data *bcn)
{
@@ -2251,9 +2349,18 @@
info->attrs[NL80211_ATTR_INACTIVITY_TIMEOUT]);
}
+ if (info->attrs[NL80211_ATTR_ACL_POLICY]) {
+ params.acl = parse_acl_data(&rdev->wiphy, info);
+ if (IS_ERR(params.acl))
+ return PTR_ERR(params.acl);
+ }
+
err = rdev->ops->start_ap(&rdev->wiphy, dev, ¶ms);
if (!err)
wdev->beacon_interval = params.beacon_interval;
+
+ kfree(params.acl);
+
return err;
}
@@ -7063,6 +7170,14 @@
NL80211_FLAG_NEED_RTNL,
},
{
+ .cmd = NL80211_CMD_SET_MAC_ACL,
+ .doit = nl80211_set_mac_acl,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV |
+ NL80211_FLAG_NEED_RTNL,
+ },
+ {
.cmd = NL80211_CMD_UPDATE_FT_IES,
.doit = nl80211_update_ft_ies,
.policy = nl80211_policy,
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index 29703b9..bda43a5 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -2703,7 +2703,7 @@
}
snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x01, 0x01);
- msleep(250);
+ msleep(20);
snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
pr_debug("%s: leave\n", __func__);
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.c b/sound/soc/codecs/wcd9xxx-mbhc.c
index a37b4eb..cc22fd4 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.c
+++ b/sound/soc/codecs/wcd9xxx-mbhc.c
@@ -134,6 +134,14 @@
WCD9XXX_HPHR_DAC_OFF_ACK
};
+enum wcd9xxx_current_v_idx {
+ WCD9XXX_CURRENT_V_INS_H,
+ WCD9XXX_CURRENT_V_INS_HU,
+ WCD9XXX_CURRENT_V_B1_H,
+ WCD9XXX_CURRENT_V_B1_HU,
+ WCD9XXX_CURRENT_V_BR_H,
+};
+
static bool wcd9xxx_mbhc_polling(struct wcd9xxx_mbhc *mbhc)
{
return mbhc->polling_active;
@@ -266,6 +274,7 @@
int cfilt_k_val;
bool override;
struct snd_soc_codec *codec;
+ struct mbhc_internal_cal_data *d = &mbhc->mbhc_data;
codec = mbhc->codec;
@@ -278,7 +287,7 @@
if (!override)
wcd9xxx_turn_onoff_override(codec, true);
/* Adjust threshold if Mic Bias voltage changes */
- if (mbhc->mbhc_data.micb_mv != VDDIO_MICBIAS_MV) {
+ if (d->micb_mv != VDDIO_MICBIAS_MV) {
cfilt_k_val = wcd9xxx_resmgr_get_k_val(mbhc->resmgr,
VDDIO_MICBIAS_MV);
usleep_range(10000, 10000);
@@ -286,11 +295,28 @@
mbhc->mbhc_bias_regs.cfilt_val,
0xFC, (cfilt_k_val << 2));
usleep_range(10000, 10000);
+ /* Threshods for insertion/removal */
snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B1_CTL,
- mbhc->mbhc_data.adj_v_ins_hu & 0xFF);
+ d->v_ins_hu[MBHC_V_IDX_VDDIO] & 0xFF);
snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B2_CTL,
- (mbhc->mbhc_data.adj_v_ins_hu >> 8) &
+ (d->v_ins_hu[MBHC_V_IDX_VDDIO] >> 8) &
0xFF);
+ /* Threshods for button press */
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL,
+ d->v_b1_hu[MBHC_V_IDX_VDDIO] & 0xFF);
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B4_CTL,
+ (d->v_b1_hu[MBHC_V_IDX_VDDIO] >> 8) &
+ 0xFF);
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B5_CTL,
+ d->v_b1_h[MBHC_V_IDX_VDDIO] & 0xFF);
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B6_CTL,
+ (d->v_b1_h[MBHC_V_IDX_VDDIO] >> 8) &
+ 0xFF);
+ /* Threshods for button release */
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B9_CTL,
+ d->v_brh[MBHC_V_IDX_VDDIO] & 0xFF);
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B10_CTL,
+ (d->v_brh[MBHC_V_IDX_VDDIO] >> 8) & 0xFF);
pr_debug("%s: Programmed MBHC thresholds to VDDIO\n",
__func__);
}
@@ -312,18 +338,36 @@
restartpolling)
wcd9xxx_pause_hs_polling(mbhc);
/* Reprogram thresholds */
- if (mbhc->mbhc_data.micb_mv != VDDIO_MICBIAS_MV) {
+ if (d->micb_mv != VDDIO_MICBIAS_MV) {
cfilt_k_val =
wcd9xxx_resmgr_get_k_val(mbhc->resmgr,
- mbhc->mbhc_data.micb_mv);
+ d->micb_mv);
snd_soc_update_bits(codec,
mbhc->mbhc_bias_regs.cfilt_val,
0xFC, (cfilt_k_val << 2));
usleep_range(10000, 10000);
+ /* Revert threshods for insertion/removal */
snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B1_CTL,
- mbhc->mbhc_data.v_ins_hu & 0xFF);
+ d->v_ins_hu[MBHC_V_IDX_CFILT] & 0xFF);
snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B2_CTL,
- (mbhc->mbhc_data.v_ins_hu >> 8) & 0xFF);
+ (d->v_ins_hu[MBHC_V_IDX_CFILT] >> 8) &
+ 0xFF);
+ /* Revert threshods for button press */
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL,
+ d->v_b1_hu[MBHC_V_IDX_CFILT] & 0xFF);
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B4_CTL,
+ (d->v_b1_hu[MBHC_V_IDX_CFILT] >> 8) &
+ 0xFF);
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B5_CTL,
+ d->v_b1_h[MBHC_V_IDX_CFILT] & 0xFF);
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B6_CTL,
+ (d->v_b1_h[MBHC_V_IDX_CFILT] >> 8) &
+ 0xFF);
+ /* Revert threshods for button release */
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B9_CTL,
+ d->v_brh[MBHC_V_IDX_CFILT] & 0xFF);
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B10_CTL,
+ (d->v_brh[MBHC_V_IDX_CFILT] >> 8) & 0xFF);
pr_debug("%s: Programmed MBHC thresholds to MICBIAS\n",
__func__);
}
@@ -347,17 +391,37 @@
return __wcd9xxx_switch_micbias(mbhc, vddio_switch, true, true);
}
-static s16 wcd9xxx_get_current_v_ins(struct wcd9xxx_mbhc *mbhc, bool hu)
+static s16 wcd9xxx_get_current_v(struct wcd9xxx_mbhc *mbhc,
+ const enum wcd9xxx_current_v_idx idx)
{
- s16 v_ins;
+ enum mbhc_v_index vidx;
+ s16 ret = -EINVAL;
+
if ((mbhc->mbhc_data.micb_mv != VDDIO_MICBIAS_MV) &&
mbhc->mbhc_micbias_switched)
- v_ins = hu ? (s16)mbhc->mbhc_data.adj_v_ins_hu :
- (s16)mbhc->mbhc_data.adj_v_ins_h;
+ vidx = MBHC_V_IDX_VDDIO;
else
- v_ins = hu ? (s16)mbhc->mbhc_data.v_ins_hu :
- (s16)mbhc->mbhc_data.v_ins_h;
- return v_ins;
+ vidx = MBHC_V_IDX_CFILT;
+
+ switch (idx) {
+ case WCD9XXX_CURRENT_V_INS_H:
+ ret = (s16)mbhc->mbhc_data.v_ins_h[vidx];
+ break;
+ case WCD9XXX_CURRENT_V_INS_HU:
+ ret = (s16)mbhc->mbhc_data.v_ins_hu[vidx];
+ break;
+ case WCD9XXX_CURRENT_V_B1_H:
+ ret = (s16)mbhc->mbhc_data.v_b1_h[vidx];
+ break;
+ case WCD9XXX_CURRENT_V_B1_HU:
+ ret = (s16)mbhc->mbhc_data.v_b1_hu[vidx];
+ break;
+ case WCD9XXX_CURRENT_V_BR_H:
+ ret = (s16)mbhc->mbhc_data.v_brh[vidx];
+ break;
+ }
+
+ return ret;
}
void *wcd9xxx_mbhc_cal_btn_det_mp(
@@ -389,27 +453,25 @@
static void wcd9xxx_calibrate_hs_polling(struct wcd9xxx_mbhc *mbhc)
{
struct snd_soc_codec *codec = mbhc->codec;
- const s16 v_ins_hu = wcd9xxx_get_current_v_ins(mbhc, true);
+ const s16 v_ins_hu = wcd9xxx_get_current_v(mbhc,
+ WCD9XXX_CURRENT_V_INS_HU);
+ const s16 v_b1_hu = wcd9xxx_get_current_v(mbhc,
+ WCD9XXX_CURRENT_V_B1_HU);
+ const s16 v_b1_h = wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_B1_H);
+ const s16 v_brh = wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_BR_H);
snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B1_CTL, v_ins_hu & 0xFF);
snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B2_CTL,
(v_ins_hu >> 8) & 0xFF);
-
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL,
- mbhc->mbhc_data.v_b1_hu & 0xFF);
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL, v_b1_hu & 0xFF);
snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B4_CTL,
- (mbhc->mbhc_data.v_b1_hu >> 8) & 0xFF);
-
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B5_CTL,
- mbhc->mbhc_data.v_b1_h & 0xFF);
+ (v_b1_hu >> 8) & 0xFF);
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B5_CTL, v_b1_h & 0xFF);
snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B6_CTL,
- (mbhc->mbhc_data.v_b1_h >> 8) & 0xFF);
-
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B9_CTL,
- mbhc->mbhc_data.v_brh & 0xFF);
+ (v_b1_h >> 8) & 0xFF);
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B9_CTL, v_brh & 0xFF);
snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B10_CTL,
- (mbhc->mbhc_data.v_brh >> 8) & 0xFF);
-
+ (v_brh >> 8) & 0xFF);
snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B11_CTL,
mbhc->mbhc_data.v_brl & 0xFF);
snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B12_CTL,
@@ -813,6 +875,19 @@
WCD9XXX_BCL_LOCK(mbhc->resmgr);
}
+static s16 scale_v_micb_vddio(struct wcd9xxx_mbhc *mbhc, int v, bool tovddio)
+{
+ int r;
+ int vddio_k, mb_k;
+ vddio_k = wcd9xxx_resmgr_get_k_val(mbhc->resmgr, VDDIO_MICBIAS_MV);
+ mb_k = wcd9xxx_resmgr_get_k_val(mbhc->resmgr, mbhc->mbhc_data.micb_mv);
+ if (tovddio)
+ r = v * vddio_k / mb_k;
+ else
+ r = v * mb_k / vddio_k;
+ return r;
+}
+
static s16 wcd9xxx_get_current_v_hs_max(struct wcd9xxx_mbhc *mbhc)
{
s16 v_hs_max;
@@ -821,7 +896,7 @@
plug_type = WCD9XXX_MBHC_CAL_PLUG_TYPE_PTR(mbhc->mbhc_cfg->calibration);
if ((mbhc->mbhc_data.micb_mv != VDDIO_MICBIAS_MV) &&
mbhc->mbhc_micbias_switched)
- v_hs_max = mbhc->mbhc_data.adj_v_hs_max;
+ v_hs_max = scale_v_micb_vddio(mbhc, plug_type->v_hs_max, true);
else
v_hs_max = plug_type->v_hs_max;
return v_hs_max;
@@ -1032,19 +1107,6 @@
mbhc->mbhc_state = MBHC_STATE_NONE;
}
-static s16 scale_v_micb_vddio(struct wcd9xxx_mbhc *mbhc, int v, bool tovddio)
-{
- int r;
- int vddio_k, mb_k;
- vddio_k = wcd9xxx_resmgr_get_k_val(mbhc->resmgr, VDDIO_MICBIAS_MV);
- mb_k = wcd9xxx_resmgr_get_k_val(mbhc->resmgr, mbhc->mbhc_data.micb_mv);
- if (tovddio)
- r = v * vddio_k / mb_k;
- else
- r = v * mb_k / vddio_k;
- return r;
-}
-
/* called under codec_resource_lock acquisition */
static void wcd9xxx_codec_hphr_gnd_switch(struct snd_soc_codec *codec, bool on)
{
@@ -1680,7 +1742,8 @@
bias_value = wcd9xxx_codec_sta_dce(mbhc, 1, true);
pr_debug("%s: DCE %d,%d, %d us left\n", __func__, bias_value,
wcd9xxx_codec_sta_dce_v(mbhc, 1, bias_value), min_us);
- if (bias_value < wcd9xxx_get_current_v_ins(mbhc, false)) {
+ if (bias_value <
+ wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_INS_H)) {
pr_debug("%s: checking false removal\n", __func__);
msleep(500);
removed = !wcd9xxx_hs_remove_settle(mbhc);
@@ -1942,7 +2005,8 @@
static void wcd9xxx_mbhc_calc_thres(struct wcd9xxx_mbhc *mbhc)
{
struct snd_soc_codec *codec;
- s16 btn_mv = 0, btn_delta_mv;
+ s16 adj_v_hs_max;
+ s16 btn_mv = 0, btn_mv_sta[MBHC_V_IDX_NUM], btn_mv_dce[MBHC_V_IDX_NUM];
struct wcd9xxx_mbhc_btn_detect_cfg *btn_det;
struct wcd9xxx_mbhc_plug_type_cfg *plug_type;
u16 *btn_high;
@@ -1953,23 +2017,21 @@
btn_det = WCD9XXX_MBHC_CAL_BTN_DET_PTR(mbhc->mbhc_cfg->calibration);
plug_type = WCD9XXX_MBHC_CAL_PLUG_TYPE_PTR(mbhc->mbhc_cfg->calibration);
- mbhc->mbhc_data.v_ins_hu =
+ mbhc->mbhc_data.v_ins_hu[MBHC_V_IDX_CFILT] =
wcd9xxx_codec_v_sta_dce(mbhc, STA, plug_type->v_hs_max);
- mbhc->mbhc_data.v_ins_h =
+ mbhc->mbhc_data.v_ins_h[MBHC_V_IDX_CFILT] =
wcd9xxx_codec_v_sta_dce(mbhc, DCE, plug_type->v_hs_max);
mbhc->mbhc_data.v_inval_ins_low = FAKE_INS_LOW;
mbhc->mbhc_data.v_inval_ins_high = FAKE_INS_HIGH;
if (mbhc->mbhc_data.micb_mv != VDDIO_MICBIAS_MV) {
- mbhc->mbhc_data.adj_v_hs_max =
- scale_v_micb_vddio(mbhc, plug_type->v_hs_max, true);
- mbhc->mbhc_data.adj_v_ins_hu =
- wcd9xxx_codec_v_sta_dce(mbhc, STA,
- mbhc->mbhc_data.adj_v_hs_max);
- mbhc->mbhc_data.adj_v_ins_h =
- wcd9xxx_codec_v_sta_dce(mbhc, DCE,
- mbhc->mbhc_data.adj_v_hs_max);
+ adj_v_hs_max = scale_v_micb_vddio(mbhc, plug_type->v_hs_max,
+ true);
+ mbhc->mbhc_data.v_ins_hu[MBHC_V_IDX_VDDIO] =
+ wcd9xxx_codec_v_sta_dce(mbhc, STA, adj_v_hs_max);
+ mbhc->mbhc_data.v_ins_h[MBHC_V_IDX_VDDIO] =
+ wcd9xxx_codec_v_sta_dce(mbhc, DCE, adj_v_hs_max);
mbhc->mbhc_data.v_inval_ins_low =
scale_v_micb_vddio(mbhc, mbhc->mbhc_data.v_inval_ins_low,
false);
@@ -1983,17 +2045,27 @@
for (i = 0; i < btn_det->num_btn; i++)
btn_mv = btn_high[i] > btn_mv ? btn_high[i] : btn_mv;
- mbhc->mbhc_data.v_b1_h = wcd9xxx_codec_v_sta_dce(mbhc, DCE, btn_mv);
- btn_delta_mv = btn_mv + btn_det->v_btn_press_delta_sta;
- mbhc->mbhc_data.v_b1_hu =
- wcd9xxx_codec_v_sta_dce(mbhc, STA, btn_delta_mv);
+ btn_mv_sta[MBHC_V_IDX_CFILT] = btn_mv + btn_det->v_btn_press_delta_sta;
+ btn_mv_dce[MBHC_V_IDX_CFILT] = btn_mv + btn_det->v_btn_press_delta_cic;
+ btn_mv_sta[MBHC_V_IDX_VDDIO] =
+ scale_v_micb_vddio(mbhc, btn_mv_sta[MBHC_V_IDX_CFILT], true);
+ btn_mv_dce[MBHC_V_IDX_VDDIO] =
+ scale_v_micb_vddio(mbhc, btn_mv_dce[MBHC_V_IDX_CFILT], true);
- btn_delta_mv = btn_mv + btn_det->v_btn_press_delta_cic;
+ mbhc->mbhc_data.v_b1_hu[MBHC_V_IDX_CFILT] =
+ wcd9xxx_codec_v_sta_dce(mbhc, STA, btn_mv_sta[MBHC_V_IDX_CFILT]);
+ mbhc->mbhc_data.v_b1_h[MBHC_V_IDX_CFILT] =
+ wcd9xxx_codec_v_sta_dce(mbhc, DCE, btn_mv_dce[MBHC_V_IDX_CFILT]);
+ mbhc->mbhc_data.v_b1_hu[MBHC_V_IDX_VDDIO] =
+ wcd9xxx_codec_v_sta_dce(mbhc, STA, btn_mv_sta[MBHC_V_IDX_VDDIO]);
+ mbhc->mbhc_data.v_b1_h[MBHC_V_IDX_VDDIO] =
+ wcd9xxx_codec_v_sta_dce(mbhc, DCE, btn_mv_dce[MBHC_V_IDX_VDDIO]);
- mbhc->mbhc_data.v_b1_huc =
- wcd9xxx_codec_v_sta_dce(mbhc, DCE, btn_delta_mv);
+ mbhc->mbhc_data.v_brh[MBHC_V_IDX_CFILT] =
+ mbhc->mbhc_data.v_b1_h[MBHC_V_IDX_CFILT];
+ mbhc->mbhc_data.v_brh[MBHC_V_IDX_VDDIO] =
+ mbhc->mbhc_data.v_b1_h[MBHC_V_IDX_VDDIO];
- mbhc->mbhc_data.v_brh = mbhc->mbhc_data.v_b1_h;
mbhc->mbhc_data.v_brl = BUTTON_MIN;
mbhc->mbhc_data.v_no_mic =
@@ -2278,12 +2350,17 @@
static int wcd9xxx_is_fake_press(struct wcd9xxx_mbhc *mbhc)
{
int i;
+ s16 mb_v;
int r = 0;
const int dces = NUM_DCE_PLUG_DETECT;
- s16 mb_v, v_ins_hu, v_ins_h;
-
- v_ins_hu = wcd9xxx_get_current_v_ins(mbhc, true);
- v_ins_h = wcd9xxx_get_current_v_ins(mbhc, false);
+ const s16 v_ins_hu =
+ wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_INS_HU);
+ const s16 v_ins_h =
+ wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_INS_H);
+ const s16 v_b1_hu =
+ wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_B1_HU);
+ const s16 v_b1_h =
+ wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_B1_H);
for (i = 0; i < dces; i++) {
usleep_range(10000, 10000);
@@ -2291,8 +2368,7 @@
mb_v = wcd9xxx_codec_sta_dce(mbhc, 0, true);
pr_debug("%s: STA[0]: %d,%d\n", __func__, mb_v,
wcd9xxx_codec_sta_dce_v(mbhc, 0, mb_v));
- if (mb_v < (s16)mbhc->mbhc_data.v_b1_hu ||
- mb_v > v_ins_hu) {
+ if (mb_v < v_b1_hu || mb_v > v_ins_hu) {
r = 1;
break;
}
@@ -2300,8 +2376,7 @@
mb_v = wcd9xxx_codec_sta_dce(mbhc, 1, true);
pr_debug("%s: DCE[%d]: %d,%d\n", __func__, i, mb_v,
wcd9xxx_codec_sta_dce_v(mbhc, 1, mb_v));
- if (mb_v < (s16)mbhc->mbhc_data.v_b1_h ||
- mb_v > v_ins_h) {
+ if (mb_v < v_b1_h || mb_v > v_ins_h) {
r = 1;
break;
}
@@ -2995,8 +3070,16 @@
int n = 0;
struct wcd9xxx_mbhc *mbhc = file->private_data;
const struct mbhc_internal_cal_data *p = &mbhc->mbhc_data;
- const s16 v_ins_hu_cur = wcd9xxx_get_current_v_ins(mbhc, true);
- const s16 v_ins_h_cur = wcd9xxx_get_current_v_ins(mbhc, false);
+ const s16 v_ins_hu =
+ wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_INS_HU);
+ const s16 v_ins_h =
+ wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_INS_H);
+ const s16 v_b1_hu =
+ wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_B1_HU);
+ const s16 v_b1_h =
+ wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_B1_H);
+ const s16 v_br_h =
+ wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_BR_H);
n = scnprintf(buffer, size - n, "dce_z = %x(%dmv)\n", p->dce_z,
wcd9xxx_codec_sta_dce_v(mbhc, 1, p->dce_z));
@@ -3006,35 +3089,19 @@
p->sta_z, wcd9xxx_codec_sta_dce_v(mbhc, 0, p->sta_z));
n += scnprintf(buffer + n, size - n, "sta_mb = %x(%dmv)\n",
p->sta_mb, wcd9xxx_codec_sta_dce_v(mbhc, 0, p->sta_mb));
- n += scnprintf(buffer + n, size - n, "t_dce = %x\n", p->t_dce);
- n += scnprintf(buffer + n, size - n, "t_sta = %x\n", p->t_sta);
- n += scnprintf(buffer + n, size - n, "micb_mv = %dmv\n",
- p->micb_mv);
- n += scnprintf(buffer + n, size - n, "v_ins_hu = %x(%dmv)%s\n",
- p->v_ins_hu,
- wcd9xxx_codec_sta_dce_v(mbhc, 0, p->v_ins_hu),
- p->v_ins_hu == v_ins_hu_cur ? "*" : "");
- n += scnprintf(buffer + n, size - n, "v_ins_h = %x(%dmv)%s\n",
- p->v_ins_h, wcd9xxx_codec_sta_dce_v(mbhc, 1, p->v_ins_h),
- p->v_ins_h == v_ins_h_cur ? "*" : "");
- n += scnprintf(buffer + n, size - n, "adj_v_ins_hu = %x(%dmv)%s\n",
- p->adj_v_ins_hu,
- wcd9xxx_codec_sta_dce_v(mbhc, 0, p->adj_v_ins_hu),
- p->adj_v_ins_hu == v_ins_hu_cur ? "*" : "");
- n += scnprintf(buffer + n, size - n, "adj_v_ins_h = %x(%dmv)%s\n",
- p->adj_v_ins_h,
- wcd9xxx_codec_sta_dce_v(mbhc, 1, p->adj_v_ins_h),
- p->adj_v_ins_h == v_ins_h_cur ? "*" : "");
+ n += scnprintf(buffer + n, size - n, "t_dce = %d\n", p->t_dce);
+ n += scnprintf(buffer + n, size - n, "t_sta = %d\n", p->t_sta);
+ n += scnprintf(buffer + n, size - n, "micb_mv = %dmv\n", p->micb_mv);
+ n += scnprintf(buffer + n, size - n, "v_ins_hu = %x(%dmv)\n",
+ v_ins_hu, wcd9xxx_codec_sta_dce_v(mbhc, 0, v_ins_hu));
+ n += scnprintf(buffer + n, size - n, "v_ins_h = %x(%dmv)\n",
+ v_ins_h, wcd9xxx_codec_sta_dce_v(mbhc, 1, v_ins_h));
n += scnprintf(buffer + n, size - n, "v_b1_hu = %x(%dmv)\n",
- p->v_b1_hu,
- wcd9xxx_codec_sta_dce_v(mbhc, 0, p->v_b1_hu));
+ v_b1_hu, wcd9xxx_codec_sta_dce_v(mbhc, 0, v_b1_hu));
n += scnprintf(buffer + n, size - n, "v_b1_h = %x(%dmv)\n",
- p->v_b1_h, wcd9xxx_codec_sta_dce_v(mbhc, 1, p->v_b1_h));
- n += scnprintf(buffer + n, size - n, "v_b1_huc = %x(%dmv)\n",
- p->v_b1_huc,
- wcd9xxx_codec_sta_dce_v(mbhc, 1, p->v_b1_huc));
+ v_b1_h, wcd9xxx_codec_sta_dce_v(mbhc, 1, v_b1_h));
n += scnprintf(buffer + n, size - n, "v_brh = %x(%dmv)\n",
- p->v_brh, wcd9xxx_codec_sta_dce_v(mbhc, 1, p->v_brh));
+ v_br_h, wcd9xxx_codec_sta_dce_v(mbhc, 1, v_br_h));
n += scnprintf(buffer + n, size - n, "v_brl = %x(%dmv)\n", p->v_brl,
wcd9xxx_codec_sta_dce_v(mbhc, 0, p->v_brl));
n += scnprintf(buffer + n, size - n, "v_no_mic = %x(%dmv)\n",
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.h b/sound/soc/codecs/wcd9xxx-mbhc.h
index 300e34e..4f8f3cf 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.h
+++ b/sound/soc/codecs/wcd9xxx-mbhc.h
@@ -28,6 +28,12 @@
u8 cfilt_sel;
};
+enum mbhc_v_index {
+ MBHC_V_IDX_CFILT,
+ MBHC_V_IDX_VDDIO,
+ MBHC_V_IDX_NUM,
+};
+
/* Data used by MBHC */
struct mbhc_internal_cal_data {
u16 dce_z;
@@ -38,17 +44,13 @@
u32 t_dce;
u32 t_sta;
u32 micb_mv;
- u16 v_ins_hu;
- u16 v_ins_h;
- u16 v_b1_hu;
- u16 v_b1_h;
- u16 v_b1_huc;
- u16 v_brh;
+ u16 v_ins_hu[MBHC_V_IDX_NUM];
+ u16 v_ins_h[MBHC_V_IDX_NUM];
+ u16 v_b1_hu[MBHC_V_IDX_NUM];
+ u16 v_b1_h[MBHC_V_IDX_NUM];
+ u16 v_brh[MBHC_V_IDX_NUM];
u16 v_brl;
u16 v_no_mic;
- s16 adj_v_hs_max;
- u16 adj_v_ins_hu;
- u16 adj_v_ins_h;
s16 v_inval_ins_low;
s16 v_inval_ins_high;
};
diff --git a/sound/soc/msm/msm-pcm-routing.c b/sound/soc/msm/msm-pcm-routing.c
index 2c3c6df..95122b2 100644
--- a/sound/soc/msm/msm-pcm-routing.c
+++ b/sound/soc/msm/msm-pcm-routing.c
@@ -1464,8 +1464,8 @@
ret = voc_set_ext_ec_ref(msm_route_ext_ec_ref, false);
break;
}
- snd_soc_dapm_mux_update_power(widget, kcontrol, 1, mux, e);
mutex_unlock(&routing_lock);
+ snd_soc_dapm_mux_update_power(widget, kcontrol, 1, mux, e);
return ret;
}
diff --git a/sound/soc/msm/msm-pcm-voice.c b/sound/soc/msm/msm-pcm-voice.c
index 26e6ae6..6d0fcea 100644
--- a/sound/soc/msm/msm-pcm-voice.c
+++ b/sound/soc/msm/msm-pcm-voice.c
@@ -505,6 +505,9 @@
voc_set_tty_mode(voc_get_session_id(VOICE_SESSION_NAME), tty_mode);
voc_set_tty_mode(voc_get_session_id(VOICE2_SESSION_NAME), tty_mode);
+
+ voc_set_tty_mode(voc_get_session_id(VOLTE_SESSION_NAME), tty_mode);
+
return 0;
}
static int msm_voice_widevoice_put(struct snd_kcontrol *kcontrol,
diff --git a/sound/soc/msm/qdsp6v2/audio_ocmem.c b/sound/soc/msm/qdsp6v2/audio_ocmem.c
index 08d7277..bedaba0 100644
--- a/sound/soc/msm/qdsp6v2/audio_ocmem.c
+++ b/sound/soc/msm/qdsp6v2/audio_ocmem.c
@@ -243,7 +243,7 @@
struct ocmem_buf *buf = NULL;
struct avcs_cmd_rsp_get_low_power_segments_info_t *lp_segptr;
- pr_debug("%s\n", __func__);
+ pr_debug("%s, %p\n", __func__, &audio_ocmem_lcl);
atomic_set(&audio_ocmem_lcl.audio_state, OCMEM_STATE_DEFAULT);
if (audio_ocmem_lcl.lp_memseg_ptr == NULL) {
/* Retrieve low power segments */
@@ -329,6 +329,7 @@
if (ret) {
pr_err("%s: ocmem_map failed\n", __func__);
atomic_set(&audio_ocmem_lcl.audio_state, OCMEM_STATE_MAP_FAIL);
+ goto fail_cmd1;
}
wait_event_interruptible(audio_ocmem_lcl.audio_wait,
@@ -372,7 +373,7 @@
pr_err("%s: ocmem_unmap failed, state[%d]\n",
__func__,
atomic_read(&audio_ocmem_lcl.audio_state));
- goto fail_cmd;
+ goto fail_cmd1;
}
wait_event_interruptible(audio_ocmem_lcl.audio_wait,
@@ -384,7 +385,7 @@
pr_err("%s: ocmem_shrink failed, state[%d]\n",
__func__,
atomic_read(&audio_ocmem_lcl.audio_state));
- goto fail_cmd;
+ goto fail_cmd1;
}
atomic_set(&audio_ocmem_lcl.audio_cond, 1);
clear_bit_pos(audio_ocmem_lcl.audio_state,
@@ -405,7 +406,7 @@
pr_err("%s: ocmem_map failed, state[%d]\n",
__func__,
atomic_read(&audio_ocmem_lcl.audio_state));
- goto fail_cmd;
+ goto fail_cmd1;
}
wait_event_interruptible(audio_ocmem_lcl.audio_wait,
(atomic_read(&audio_ocmem_lcl.audio_state) &
@@ -428,7 +429,7 @@
pr_err("%s: ocmem_unmap failed, state[0x%x]\n",
__func__,
atomic_read(&audio_ocmem_lcl.audio_state));
- goto fail_cmd;
+ goto fail_cmd1;
}
wait_event_interruptible(
audio_ocmem_lcl.audio_wait,
@@ -446,14 +447,16 @@
pr_err("%s: ocmem_shrink failed, state[0x%x]\n",
__func__,
atomic_read(&audio_ocmem_lcl.audio_state));
- goto fail_cmd;
+ goto fail_cmd1;
}
clear_bit_pos(audio_ocmem_lcl.audio_state,
OCMEM_STATE_SHRINK);
}
- pr_debug("%s: calling ocmem free\n", __func__);
+ pr_debug("%s: calling ocmem free, state:0x%x\n",
+ __func__,
+ atomic_read(&audio_ocmem_lcl.audio_state));
ret = ocmem_free(OCMEM_LP_AUDIO, audio_ocmem_lcl.buf);
if (ret == -EAGAIN) {
pr_debug("%s: received EAGAIN\n", __func__);
@@ -466,7 +469,7 @@
pr_err("%s: ocmem_shrink failed, state[0x%x]\n",
__func__,
atomic_read(&audio_ocmem_lcl.audio_state));
- goto fail_cmd;
+ goto fail_cmd1;
}
pr_debug("calling free after EAGAIN");
ret = ocmem_free(OCMEM_LP_AUDIO,
@@ -474,19 +477,19 @@
if (ret) {
pr_err("%s: ocmem_free failed\n",
__func__);
- goto fail_cmd;
+ goto fail_cmd2;
}
} else {
pr_debug("%s: shrink callback already processed\n",
__func__);
- goto fail_cmd;
+ goto fail_cmd1;
}
} else if (ret) {
pr_err("%s: ocmem_free failed, state[0x%x], ret:%d\n",
__func__,
atomic_read(&audio_ocmem_lcl.audio_state),
ret);
- goto fail_cmd;
+ goto fail_cmd2;
}
pr_debug("%s: ocmem_free success\n", __func__);
/* Fall through */
@@ -508,6 +511,14 @@
mutex_unlock(&audio_ocmem_lcl.state_process_lock);
}
ret = 0;
+ goto fail_cmd;
+
+fail_cmd1:
+ ret = ocmem_free(OCMEM_LP_AUDIO, audio_ocmem_lcl.buf);
+ if (ret)
+ pr_err("%s: ocmem_free failed\n", __func__);
+fail_cmd2:
+ mutex_unlock(&audio_ocmem_lcl.state_process_lock);
fail_cmd:
pr_debug("%s: exit\n", __func__);
audio_ocmem_lcl.audio_ocmem_running = false;
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index c2fd2d7..ac26d0c 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -3363,6 +3363,7 @@
u32 lbuf_addr_lsw;
u32 liomode;
u32 io_compressed;
+ int dir = 0;
if (!ac || ac->apr == NULL) {
pr_err("%s: APR handle NULL\n", __func__);
@@ -3380,15 +3381,21 @@
read.seq_id = param->uid;
liomode = (NT_MODE | ASYNC_IO_MODE);
io_compressed = (ASYNC_IO_MODE | COMPRESSED_IO);
- if (ac->io_mode == liomode)
+ if (ac->io_mode == liomode) {
lbuf_addr_lsw = (read.buf_addr_lsw - 32);
- else if (ac->io_mode == io_compressed)
+ /*legacy wma driver case*/
+ dir = IN;
+ } else if (ac->io_mode == io_compressed) {
lbuf_addr_lsw = (read.buf_addr_lsw - 64);
- else
+ dir = OUT;
+ } else {
lbuf_addr_lsw = read.buf_addr_lsw;
+ dir = OUT;
+ }
- list_for_each_safe(ptr, next, &ac->port[OUT].mem_map_handle) {
- buf_node = list_entry(ptr, struct asm_buffer_node, list);
+ list_for_each_safe(ptr, next, &ac->port[dir].mem_map_handle) {
+ buf_node = list_entry(ptr, struct asm_buffer_node,
+ list);
if (buf_node->buf_addr_lsw == lbuf_addr_lsw) {
read.mem_map_handle = buf_node->mmap_hdl;
break;
diff --git a/sound/soc/msm/qdsp6v2/q6core.c b/sound/soc/msm/qdsp6v2/q6core.c
index 42cbcd1..5fec0c1 100644
--- a/sound/soc/msm/qdsp6v2/q6core.c
+++ b/sound/soc/msm/qdsp6v2/q6core.c
@@ -29,7 +29,7 @@
struct apr_svc *core_handle_q;
wait_queue_head_t bus_bw_req_wait;
u32 bus_bw_resp_received;
- struct avcs_cmd_rsp_get_low_power_segments_info_t *lp_ocm_payload;
+ struct avcs_cmd_rsp_get_low_power_segments_info_t lp_ocm_payload;
};
static struct q6core_str q6core_lcl;
@@ -74,19 +74,19 @@
pr_info("%s: cmd = AVCS_CMDRSP_GET_LOW_POWER_SEGMENTS_INFO num_segments = 0x%x\n",
__func__, payload1[0]);
nseg = payload1[0];
- q6core_lcl.lp_ocm_payload->num_segments = nseg;
- q6core_lcl.lp_ocm_payload->bandwidth = payload1[1];
+ q6core_lcl.lp_ocm_payload.num_segments = nseg;
+ q6core_lcl.lp_ocm_payload.bandwidth = payload1[1];
for (i = 0, j = 2; i < nseg; i++) {
- q6core_lcl.lp_ocm_payload->mem_segment[i].type =
+ q6core_lcl.lp_ocm_payload.mem_segment[i].type =
(payload1[j] & 0xffff);
- q6core_lcl.lp_ocm_payload->mem_segment[i].category =
+ q6core_lcl.lp_ocm_payload.mem_segment[i].category =
((payload1[j++] >> 16) & 0xffff);
- q6core_lcl.lp_ocm_payload->mem_segment[i].size =
+ q6core_lcl.lp_ocm_payload.mem_segment[i].size =
payload1[j++];
- q6core_lcl.lp_ocm_payload->
+ q6core_lcl.lp_ocm_payload.
mem_segment[i].start_address_lsw =
payload1[j++];
- q6core_lcl.lp_ocm_payload->
+ q6core_lcl.lp_ocm_payload.
mem_segment[i].start_address_msw =
payload1[j++];
}
@@ -152,7 +152,6 @@
struct avcs_cmd_rsp_get_low_power_segments_info_t **lp_memseg)
{
struct avcs_cmd_get_low_power_segments_info lp_ocm_cmd;
- u8 *cptr = NULL;
int ret = 0;
pr_debug("%s: ", __func__);
@@ -163,16 +162,6 @@
return -ENODEV;
}
- cptr = kzalloc(
- sizeof(struct avcs_cmd_rsp_get_low_power_segments_info_t),
- GFP_KERNEL);
- if (!cptr) {
- pr_err("%s: Failed to allocate memory for low power segment struct\n",
- __func__);
- return -ENOMEM;
- }
- q6core_lcl.lp_ocm_payload =
- (struct avcs_cmd_rsp_get_low_power_segments_info_t *) cptr;
lp_ocm_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
@@ -201,7 +190,7 @@
goto fail_cmd;
}
- *lp_memseg = q6core_lcl.lp_ocm_payload;
+ *lp_memseg = &q6core_lcl.lp_ocm_payload;
return 0;
fail_cmd:
@@ -215,14 +204,6 @@
q6core_lcl.bus_bw_resp_received = 0;
q6core_lcl.core_handle_q = NULL;
- q6core_lcl.lp_ocm_payload = kzalloc(
- sizeof(struct avcs_cmd_rsp_get_low_power_segments_info_t), GFP_KERNEL);
-
- if (!q6core_lcl.lp_ocm_payload) {
- pr_err("%s: Failed to allocate memory for low power segment struct\n",
- __func__);
- return -ENOMEM;
- }
return 0;
}
@@ -230,7 +211,7 @@
static void __exit core_exit(void)
{
- kfree(q6core_lcl.lp_ocm_payload);
+
}
module_exit(core_exit);
MODULE_DESCRIPTION("ADSP core driver");