Merge "ARM: dts: msm: Add memory dump device for SDM845" into msm-4.9
diff --git a/Documentation/devicetree/bindings/interrupt-controller/qti,pdc.txt b/Documentation/devicetree/bindings/interrupt-controller/qti,pdc.txt
new file mode 100644
index 0000000..8598d0c
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/qti,pdc.txt
@@ -0,0 +1,63 @@
+QTI PDC interrupt controller
+
+PDC is QTI's platform parent interrupt controller that serves as wakeup source.
+
+Newer QTI SOCs are replacing MPM (MSM sleep Power Manager) with PDC (Power
+Domain Controller) to manage subsystem wakeups and resources during sleep.
+This driver marks the wakeup interrupts in APSS PDC such that it monitors the
+interrupts when the system is asleep, wakes up the APSS when one of these
+interrupts occur and replays it to the subsystem interrupt controller after it
+becomes operational.
+
+Earlier MPM architecture used arch-extension of GIC interrupt
+controller to mark enabled wake-up interrupts and monitor these when the
+system goes to sleep. Since the arch-extensions are no-longer available
+on newer kernel versions, this driver is implemented as hierarchical irq
+domain. GIC is parent interrupt controller at the highest level.
+Platform interrupt controller PDC is next in hierarchy, followed by others.
+This driver only configures the interrupts, does not handle them.
+
+PDC interrupt configuration involves programming of 2 set of registers:
+IRQ_ENABLE_BANK - Enable the irq
+IRQ_i_CFG - Configure the interrupt i
+
+Properties:
+
+- compatible:
+ Usage: required
+ Value type: <string>
+ Definition: Should contain "qcom,pdc-<target>"
+
+- reg:
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: Specifies the base physical address for PDC hardware
+ block for DRV2.
+
+- interrupt-cells:
+ Usage: required
+ Value type: <u32>
+ Definition: Specifies the number of cells needed to encode an interrupt source.
+ Value must be 3.
+ The encoding of these cells are same as described in
+ Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.txt
+
+- interrupt-parent:
+ Usage: required
+ Value type: <phandle>
+ Definition: Specifies the interrupt parent necessary for hierarchical domain to operate.
+
+- interrupt-controller:
+ Usage: required
+ Value type: <bool>
+ Definition: Identifies the node as an interrupt controller.
+
+Example:
+
+pdcgic: interrupt-controller@0xb220000{
+ compatible = "qcom,pdc-sdm845";
+ reg = <0xb220000 0x30000>;
+ #interrupt-cells = <3>;
+ interrupt-parent = <&intc>;
+ interrupt-controller;
+};
diff --git a/Documentation/devicetree/bindings/media/video/msm-sde-rotator.txt b/Documentation/devicetree/bindings/media/video/msm-sde-rotator.txt
index 0295e1b..937ccb9 100644
--- a/Documentation/devicetree/bindings/media/video/msm-sde-rotator.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-sde-rotator.txt
@@ -81,6 +81,32 @@
limits.
- qcom,mdss-rot-vbif-qos-setting: This array is used to program vbif qos remapper register
priority for rotator clients.
+- qcom,mdss-rot-cdp-setting: Integer array of size two, to indicate client driven
+ prefetch is available or not. Index 0 represents
+ if CDP is enabled for read and index 1, if CDP
+ is enabled for write operation.
+- qcom,mdss-rot-qos-lut A 4 cell property with the format of <rd_lut_0,
+ rd_lut_1, wr_lut_0, wr_lut_1> indicating the qos
+ lut settings for the rotator sspp and writeback
+ client.
+- qcom,mdss-rot-danger-lut A two cell property with the format of <rd_lut,
+ wr_lut> indicating the danger lut settings for
+ the rotator sspp and writeback client.
+- qcom,mdss-rot-safe-lut A two cell property with the format of <rd_lut,
+ wr_lut> indicating the safe lut settings for the
+ rotator sspp and writeback client.
+- qcom,mdss-inline-rot-qos-lut: A 4 cell property with the format of <rd_lut_0,
+ rd_lut_1, wr_lut_0, wr_lut_1> indicating the qos
+ lut settings for the inline rotator sspp and
+ writeback client.
+- qcom,mdss-inline-rot-danger-lut: A two cell property with the format of
+ <rd_lut, wr_lut> indicating the danger lut
+ settings for the inline rotator sspp and
+ writeback client.
+- qcom,mdss-inline-rot-safe-lut: A two cell property with the format of
+ <rd_lut, wr_lut> indicating the safe lut
+ settings for the inline rotator sspp and
+ writeback client.
- qcom,mdss-rot-mode: This is integer value indicates operation mode
of the rotator device
- qcom,mdss-sbuf-headroom: This integer value indicates stream buffer headroom in lines.
@@ -146,9 +172,19 @@
/* VBIF QoS remapper settings*/
qcom,mdss-rot-vbif-qos-setting = <1 1 1 1>;
+ com,mdss-rot-cdp-setting = <1 1>;
+
qcom,mdss-default-ot-rd-limit = <8>;
qcom,mdss-default-ot-wr-limit = <16>;
+ qcom,mdss-rot-qos-lut = <0x0 0x0 0x0 0x0>;
+ qcom,mdss-rot-danger-lut = <0x0 0x0>;
+ qcom,mdss-rot-safe-lut = <0x0000ffff 0x0>;
+
+ qcom,mdss-inline-rot-qos-lut = <0x0 0x0 0x00112233 0x44556677>;
+ qcom,mdss-inline-rot-danger-lut = <0x0 0x0000ffff>;
+ qcom,mdss-inline-rot-safe-lut = <0x0 0x0000ff00>;
+
qcom,mdss-sbuf-headroom = <20>;
cache-slice-names = "rotator";
cache-slices = <&llcc 4>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi b/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
index b51996d..0aaac6f 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
@@ -14,6 +14,27 @@
#include <dt-bindings/gpio/gpio.h>
/{
+ bluetooth: bt_wcn3990 {
+ compatible = "qca,wcn3990";
+ qca,bt-vdd-io-supply = <&pm8998_s3>;
+ qca,bt-vdd-xtal-supply = <&pm8998_s5>;
+ qca,bt-vdd-core-supply = <&pm8998_l7>;
+ qca,bt-vdd-pa-supply = <&pm8998_l17>;
+ qca,bt-vdd-ldo-supply = <&pm8998_l25>;
+
+ qca,bt-vdd-io-voltage-level = <1352000 1352000>;
+ qca,bt-vdd-xtal-voltage-level = <2040000 2040000>;
+ qca,bt-vdd-core-voltage-level = <1800000 1800000>;
+ qca,bt-vdd-pa-voltage-level = <1304000 1304000>;
+ qca,bt-vdd-ldo-voltage-level = <3312000 3312000>;
+
+ qca,bt-vdd-io-current-level = <1>; /* LPM/PFM */
+ qca,bt-vdd-xtal-current-level = <1>; /* LPM/PFM */
+ qca,bt-vdd-core-current-level = <1>; /* LPM/PFM */
+ qca,bt-vdd-pa-current-level = <1>; /* LPM/PFM */
+ qca,bt-vdd-ldo-current-level = <1>; /* LPM/PFM */
+ };
+
qrd_batterydata: qcom,battery-data {
qcom,batt-id-range-pct = <15>;
#include "fg-gen3-batterydata-itech-3000mah.dtsi"
diff --git a/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi b/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi
index 7ae63af..19b8744 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi
@@ -36,7 +36,7 @@
reg = <0x3500 0x100>;
regulator-name = "pm8998_s12";
regulator-min-microvolt = <568000>;
- regulator-max-microvolt = <1056000>;
+ regulator-max-microvolt = <1136000>;
qcom,enable-time = <500>;
regulator-always-on;
};
@@ -114,9 +114,9 @@
regulator-max-microvolt = <19>;
qcom,cpr-fuse-corners = <4>;
- qcom,cpr-fuse-combos = <16>;
- qcom,cpr-speed-bins = <2>;
- qcom,cpr-speed-bin-corners = <19 19>;
+ qcom,cpr-fuse-combos = <24>;
+ qcom,cpr-speed-bins = <3>;
+ qcom,cpr-speed-bin-corners = <19 19 19>;
qcom,cpr-corners = <19>;
qcom,cpr-corner-fmax-map = <6 12 17 19>;
@@ -137,6 +137,11 @@
<568000 568000 568000 568000 568000
568000 568000 568000 568000 584000
584000 584000 632000 632000 632000
+ 632000 672000 712000 712000>,
+ /* Speed bin 2 */
+ <568000 568000 568000 568000 568000
+ 568000 568000 568000 568000 584000
+ 584000 584000 632000 632000 632000
632000 672000 712000 712000>;
qcom,cpr-floor-to-ceiling-max-range =
@@ -146,13 +151,30 @@
32000 32000 40000 40000>;
qcom,corner-frequencies =
+ /* Speed bin 0 */
<300000000 422400000 499200000
576000000 652800000 748800000
825600000 902400000 979200000
1056000000 1132800000 1209600000
1286400000 1363200000 1440000000
1516800000 1593600000 1651200000
- 1708800000>;
+ 1708800000>,
+ /* Speed bin 1 */
+ <300000000 422400000 499200000
+ 576000000 652800000 748800000
+ 825600000 902400000 979200000
+ 1056000000 1132800000 1209600000
+ 1286400000 1363200000 1440000000
+ 1516800000 1593600000 1651200000
+ 1708800000>,
+ /* Speed bin 2 */
+ <300000000 422400000 499200000
+ 576000000 652800000 748800000
+ 825600000 902400000 979200000
+ 1056000000 1132800000 1209600000
+ 1286400000 1363200000 1440000000
+ 1516800000 1593600000 1670400000
+ 1747200000>;
qcom,cpr-ro-scaling-factor =
<2594 2795 2576 2761 2469 2673 2198
@@ -185,6 +207,8 @@
/* Speed bin 0 */
<0 1 1 1 1 1 1 1>,
/* Speed bin 1 */
+ <0 1 1 1 1 1 1 1>,
+ /* Speed bin 2 */
<0 1 1 1 1 1 1 1>;
qcom,allow-aging-open-loop-voltage-adjustment =
<1>;
@@ -201,20 +225,41 @@
apc0_l3_vreg: regulator {
regulator-name = "apc0_l3_corner";
regulator-min-microvolt = <1>;
- regulator-max-microvolt = <11>;
+ regulator-max-microvolt = <13>;
qcom,cpr-fuse-corners = <4>;
- qcom,cpr-fuse-combos = <16>;
- qcom,cpr-speed-bins = <2>;
- qcom,cpr-speed-bin-corners = <11 11>;
- qcom,cpr-corners = <11>;
+ qcom,cpr-fuse-combos = <24>;
+ qcom,cpr-speed-bins = <3>;
+ qcom,cpr-speed-bin-corners = <11 11 13>;
+ qcom,cpr-corners =
+ /* Speed bin 0 */
+ <11 11 11 11 11 11 11 11>,
+ /* Speed bin 1 */
+ <11 11 11 11 11 11 11 11>,
+ /* Speed bin 2 */
+ <13 13 13 13 13 13 13 13>;
- qcom,cpr-corner-fmax-map = <4 7 9 11>;
+ qcom,cpr-corner-fmax-map =
+ /* Speed bin 0 */
+ <4 7 9 11>,
+ /* Speed bin 1 */
+ <4 7 9 11>,
+ /* Speed bin 2 */
+ <4 7 9 13>;
qcom,cpr-voltage-ceiling =
+ /* Speed bin 0 */
<872000 872000 872000 872000 872000
872000 872000 872000 928000 996000
- 996000>;
+ 996000>,
+ /* Speed bin 1 */
+ <872000 872000 872000 872000 872000
+ 872000 872000 872000 928000 996000
+ 996000>,
+ /* Speed bin 2 */
+ <872000 872000 872000 872000 872000
+ 872000 872000 872000 928000 996000
+ 996000 996000 996000>;
qcom,cpr-voltage-floor =
/* Speed bin 0 */
@@ -224,18 +269,43 @@
/* Speed bin 1 */
<568000 568000 568000 568000 568000
584000 584000 632000 672000 712000
- 712000>;
+ 712000>,
+ /* Speed bin 2 */
+ <568000 568000 568000 568000 568000
+ 584000 584000 632000 672000 712000
+ 712000 712000 712000>;
qcom,cpr-floor-to-ceiling-max-range =
+ /* Speed bin 0 */
<32000 32000 32000 32000 32000
32000 32000 32000 32000 40000
- 40000>;
+ 40000>,
+ /* Speed bin 1 */
+ <32000 32000 32000 32000 32000
+ 32000 32000 32000 32000 40000
+ 40000>,
+ /* Speed bin 2 */
+ <32000 32000 32000 32000 32000
+ 32000 32000 32000 32000 40000
+ 40000 40000 40000>;
qcom,corner-frequencies =
+ /* Speed bin 0 */
<300000000 422400000 499200000
576000000 652800000 729600000
806400000 883200000 960000000
- 1036800000 1094400000>;
+ 1036800000 1094400000>,
+ /* Speed bin 1 */
+ <300000000 422400000 499200000
+ 576000000 652800000 729600000
+ 806400000 883200000 960000000
+ 1036800000 1094400000>,
+ /* Speed bin 2 */
+ <300000000 422400000 499200000
+ 576000000 652800000 729600000
+ 806400000 883200000 960000000
+ 1036800000 1113600000 1209600000
+ 1305600000>;
qcom,cpr-ro-scaling-factor =
<2857 3056 2828 2952 2699 2796 2447
@@ -262,12 +332,14 @@
qcom,cpr-scaled-open-loop-voltage-as-ceiling;
qcom,cpr-aging-max-voltage-adjustment = <15000>;
- qcom,cpr-aging-ref-corner = <11>;
+ qcom,cpr-aging-ref-corner = <11 11 13>;
qcom,cpr-aging-ro-scaling-factor = <1620>;
qcom,allow-aging-voltage-adjustment =
/* Speed bin 0 */
<0 1 1 1 1 1 1 1>,
/* Speed bin 1 */
+ <0 1 1 1 1 1 1 1>,
+ /* Speed bin 2 */
<0 1 1 1 1 1 1 1>;
qcom,allow-aging-open-loop-voltage-adjustment =
<1>;
@@ -320,7 +392,7 @@
qcom,cpr-panic-reg-name-list =
"APSS_GOLD_CPRH_STATUS_0", "GOLD_SAW4_PMIC_STS";
- qcom,cpr-aging-ref-voltage = <1056000>;
+ qcom,cpr-aging-ref-voltage = <1136000>;
vdd-supply = <&pm8998_s12>;
thread@0 {
@@ -333,23 +405,27 @@
apc1_perfcl_vreg: regulator {
regulator-name = "apc1_perfcl_corner";
regulator-min-microvolt = <1>;
- regulator-max-microvolt = <26>;
+ regulator-max-microvolt = <27>;
qcom,cpr-fuse-corners = <3>;
- qcom,cpr-fuse-combos = <16>;
- qcom,cpr-speed-bins = <2>;
- qcom,cpr-speed-bin-corners = <22 24>;
+ qcom,cpr-fuse-combos = <24>;
+ qcom,cpr-speed-bins = <3>;
+ qcom,cpr-speed-bin-corners = <22 24 25>;
qcom,cpr-corners =
/* Speed bin 0 */
<22 22 22 22 22 22 22 22>,
/* Speed bin 1 */
- <24 24 24 24 24 24 24 24>;
+ <24 24 24 24 24 24 24 24>,
+ /* Speed bin 2 */
+ <25 25 25 25 25 25 25 25>;
qcom,cpr-corner-fmax-map =
/* Speed bin 0 */
<10 17 22>,
/* Speed bin 1 */
- <10 17 24>;
+ <10 17 24>,
+ /* Speed bin 2 */
+ <10 17 25>;
qcom,cpr-voltage-ceiling =
/* Speed bin 0 */
@@ -357,13 +433,20 @@
828000 828000 828000 828000 828000
828000 828000 828000 828000 828000
828000 828000 884000 952000 952000
- 1056000 1056000>,
+ 1136000 1136000>,
/* Speed bin 1 */
<828000 828000 828000 828000 828000
828000 828000 828000 828000 828000
828000 828000 828000 828000 828000
828000 828000 884000 952000 952000
- 1056000 1056000 1056000 1056000>;
+ 1136000 1136000 1136000 1136000>,
+ /* Speed bin 2 */
+ <828000 828000 828000 828000 828000
+ 828000 828000 828000 828000 828000
+ 828000 828000 828000 828000 828000
+ 828000 828000 884000 952000 952000
+ 1136000 1136000 1136000 1136000
+ 1136000>;
qcom,cpr-voltage-floor =
/* Speed bin 0 */
@@ -377,7 +460,14 @@
568000 568000 568000 568000 568000
584000 584000 632000 632000 632000
632000 632000 672000 712000 712000
- 772000 772000 772000 772000>;
+ 772000 772000 772000 772000>,
+ /* Speed bin 2 */
+ <568000 568000 568000 568000 568000
+ 568000 568000 568000 568000 568000
+ 584000 584000 632000 632000 632000
+ 632000 632000 672000 712000 712000
+ 772000 772000 772000 772000
+ 772000>;
qcom,cpr-floor-to-ceiling-max-range =
/* Speed bin 0 */
@@ -391,7 +481,13 @@
32000 32000 32000 32000 32000
32000 32000 32000 32000 32000
32000 32000 40000 40000 40000
- 40000 40000 40000 40000>;
+ 40000 40000 40000 40000>,
+ /* Speed bin 2 */
+ <32000 32000 32000 32000 32000
+ 32000 32000 32000 32000 32000
+ 32000 32000 32000 32000 32000
+ 32000 32000 40000 40000 40000
+ 40000 40000 40000 40000 40000>;
qcom,corner-frequencies =
/* Speed bin 0 */
@@ -411,7 +507,17 @@
1267200000 1344000000 1420800000
1497600000 1574400000 1651200000
1728000000 1804800000 1881600000
- 1958400000 2035200000 2092800000>;
+ 1958400000 2035200000 2092800000>,
+ /* Speed bin 2 */
+ <300000000 422400000 499200000
+ 576000000 652800000 729600000
+ 806400000 883200000 960000000
+ 1036800000 1113600000 1190400000
+ 1267200000 1344000000 1420800000
+ 1497600000 1574400000 1651200000
+ 1728000000 1804800000 1881600000
+ 1958400000 2035200000 2112000000
+ 2208000000>;
qcom,cpr-ro-scaling-factor =
<2857 3056 2828 2952 2699 2796 2447
@@ -442,6 +548,15 @@
< 0 0 0>,
< 0 0 0>,
< 0 0 0>,
+ < 0 0 0>,
+ /* Speed bin 2 */
+ <100000 100000 100000>,
+ < 0 0 0>,
+ < 0 0 0>,
+ < 0 0 0>,
+ < 0 0 0>,
+ < 0 0 0>,
+ < 0 0 0>,
< 0 0 0>;
qcom,cpr-closed-loop-voltage-fuse-adjustment =
@@ -462,6 +577,15 @@
< 0 0 0>,
< 0 0 0>,
< 0 0 0>,
+ < 0 0 0>,
+ /* Speed bin 2 */
+ <100000 100000 100000>,
+ < 0 0 0>,
+ < 0 0 0>,
+ < 0 0 0>,
+ < 0 0 0>,
+ < 0 0 0>,
+ < 0 0 0>,
< 0 0 0>;
qcom,allow-voltage-interpolation;
@@ -469,12 +593,14 @@
qcom,cpr-scaled-open-loop-voltage-as-ceiling;
qcom,cpr-aging-max-voltage-adjustment = <15000>;
- qcom,cpr-aging-ref-corner = <22 24>;
+ qcom,cpr-aging-ref-corner = <22 24 25>;
qcom,cpr-aging-ro-scaling-factor = <1700>;
qcom,allow-aging-voltage-adjustment =
/* Speed bin 0 */
<0 1 1 1 1 1 1 1>,
/* Speed bin 1 */
+ <0 1 1 1 1 1 1 1>,
+ /* Speed bin 2 */
<0 1 1 1 1 1 1 1>;
qcom,allow-aging-open-loop-voltage-adjustment =
<1>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi
index afaac40..c806627 100644
--- a/arch/arm64/boot/dts/qcom/sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi
@@ -1718,7 +1718,7 @@
qcom,ssc@5c00000 {
compatible = "qcom,pil-tz-generic";
reg = <0x5c00000 0x4000>;
- interrupts = <0 377 1>;
+ interrupts = <0 494 1>;
vdd_cx-supply = <&pm8998_l27_level>;
vdd_px-supply = <&pm8998_lvs2>;
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h
index 5dcdf46..2d7b174 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h
@@ -142,7 +142,8 @@
void dsi_ctrl_hw_cmn_setup_cmd_stream(struct dsi_ctrl_hw *ctrl,
struct dsi_mode_info *mode,
u32 h_stride,
- u32 vc_id);
+ u32 vc_id,
+ struct dsi_rect *roi);
void dsi_ctrl_hw_cmn_phy_sw_reset(struct dsi_ctrl_hw *ctrl);
void dsi_ctrl_hw_cmn_soft_reset(struct dsi_ctrl_hw *ctrl);
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
index f187ad1..39b797e 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
@@ -1558,7 +1558,6 @@
int dsi_ctrl_setup(struct dsi_ctrl *dsi_ctrl)
{
- struct dsi_mode_info video_timing;
int rc = 0;
if (!dsi_ctrl) {
@@ -1568,12 +1567,6 @@
mutex_lock(&dsi_ctrl->ctrl_lock);
- /* replace video mode width with actual roi width */
- memcpy(&video_timing, &dsi_ctrl->host_config.video_timing,
- sizeof(video_timing));
- video_timing.h_active = dsi_ctrl->roi.w;
- video_timing.v_active = dsi_ctrl->roi.h;
-
dsi_ctrl->hw.ops.setup_lane_map(&dsi_ctrl->hw,
&dsi_ctrl->host_config.lane_map);
@@ -1586,9 +1579,10 @@
&dsi_ctrl->host_config.u.cmd_engine);
dsi_ctrl->hw.ops.setup_cmd_stream(&dsi_ctrl->hw,
- &video_timing,
- video_timing.h_active * 3,
- 0x0);
+ &dsi_ctrl->host_config.video_timing,
+ dsi_ctrl->host_config.video_timing.h_active * 3,
+ 0x0,
+ &dsi_ctrl->roi);
dsi_ctrl->hw.ops.cmd_engine_en(&dsi_ctrl->hw, true);
} else {
dsi_ctrl->hw.ops.video_engine_setup(&dsi_ctrl->hw,
@@ -1690,7 +1684,8 @@
dsi_ctrl->hw.ops.setup_cmd_stream(&dsi_ctrl->hw,
&dsi_ctrl->host_config.video_timing,
dsi_ctrl->host_config.video_timing.h_active * 3,
- 0x0);
+ 0x0,
+ NULL);
} else {
dsi_ctrl->hw.ops.video_engine_setup(&dsi_ctrl->hw,
&dsi_ctrl->host_config.common_config,
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h
index 859d707..bb72807 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h
@@ -319,7 +319,8 @@
void (*setup_cmd_stream)(struct dsi_ctrl_hw *ctrl,
struct dsi_mode_info *mode,
u32 h_stride,
- u32 vc_id);
+ u32 vc_id,
+ struct dsi_rect *roi);
/**
* ctrl_en() - enable DSI controller engine
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c
index 48c2370..a024c43 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c
@@ -19,6 +19,7 @@
#include "dsi_ctrl_hw.h"
#include "dsi_ctrl_reg.h"
#include "dsi_hw.h"
+#include "dsi_panel.h"
#define MMSS_MISC_CLAMP_REG_OFF 0x0014
#define DSI_CTRL_DYNAMIC_FORCE_ON (0x23F|BIT(8)|BIT(9)|BIT(11)|BIT(21))
@@ -234,21 +235,36 @@
void dsi_ctrl_hw_cmn_setup_cmd_stream(struct dsi_ctrl_hw *ctrl,
struct dsi_mode_info *mode,
u32 h_stride,
- u32 vc_id)
+ u32 vc_id,
+ struct dsi_rect *roi)
{
- u32 reg = 0;
u32 width_final, stride_final;
+ u32 height_final;
+ u32 stream_total = 0, stream_ctrl = 0;
+ u32 reg_ctrl = 0, reg_ctrl2 = 0;
+
+ if (roi && (!roi->w || !roi->h))
+ return;
if (mode->dsc_enabled && mode->dsc) {
+ u32 reg = 0;
u32 offset = 0;
- u32 reg_ctrl, reg_ctrl2;
+ int pic_width, this_frame_slices, intf_ip_w;
+ struct msm_display_dsc_info dsc;
+
+ memcpy(&dsc, mode->dsc, sizeof(dsc));
+ pic_width = roi ? roi->w : mode->h_active;
+ this_frame_slices = pic_width / dsc.slice_width;
+ intf_ip_w = this_frame_slices * dsc.slice_width;
+ dsi_dsc_pclk_param_calc(&dsc, intf_ip_w);
if (vc_id != 0)
offset = 16;
reg_ctrl = DSI_R32(ctrl, DSI_COMMAND_COMPRESSION_MODE_CTRL);
reg_ctrl2 = DSI_R32(ctrl, DSI_COMMAND_COMPRESSION_MODE_CTRL2);
- width_final = mode->dsc->pclk_per_line;
- stride_final = mode->dsc->bytes_per_pkt;
+ width_final = dsc.pclk_per_line;
+ stride_final = dsc.bytes_per_pkt;
+ height_final = roi ? roi->h : mode->v_active;
reg = 0x39 << 8;
/*
@@ -258,34 +274,45 @@
* 2 == 4 pkt
* 3 pkt is not support
*/
- if (mode->dsc->pkt_per_line == 4)
- reg |= (mode->dsc->pkt_per_line - 2) << 6;
+ if (dsc.pkt_per_line == 4)
+ reg |= (dsc.pkt_per_line - 2) << 6;
else
- reg |= (mode->dsc->pkt_per_line - 1) << 6;
- reg |= mode->dsc->eol_byte_num << 4;
+ reg |= (dsc.pkt_per_line - 1) << 6;
+ reg |= dsc.eol_byte_num << 4;
reg |= 1;
reg_ctrl &= ~(0xFFFF << offset);
reg_ctrl |= (reg << offset);
reg_ctrl2 &= ~(0xFFFF << offset);
- reg_ctrl2 |= (mode->dsc->bytes_in_slice << offset);
+ reg_ctrl2 |= (dsc.bytes_in_slice << offset);
DSI_W32(ctrl, DSI_COMMAND_COMPRESSION_MODE_CTRL, reg_ctrl);
DSI_W32(ctrl, DSI_COMMAND_COMPRESSION_MODE_CTRL2, reg_ctrl2);
+
+ pr_debug("ctrl %d reg_ctrl 0x%x reg_ctrl2 0x%x\n", ctrl->index,
+ reg_ctrl, reg_ctrl2);
+ } else if (roi) {
+ width_final = roi->w;
+ stride_final = roi->w * 3;
+ height_final = roi->h;
} else {
width_final = mode->h_active;
stride_final = h_stride;
+ height_final = mode->v_active;
}
- reg = (stride_final + 1) << 16;
- reg |= (vc_id & 0x3) << 8;
- reg |= 0x39; /* packet data type */
+ stream_ctrl = (stride_final + 1) << 16;
+ stream_ctrl |= (vc_id & 0x3) << 8;
+ stream_ctrl |= 0x39; /* packet data type */
- DSI_W32(ctrl, DSI_COMMAND_MODE_MDP_STREAM0_CTRL, reg);
- DSI_W32(ctrl, DSI_COMMAND_MODE_MDP_STREAM1_CTRL, reg);
+ DSI_W32(ctrl, DSI_COMMAND_MODE_MDP_STREAM0_CTRL, stream_ctrl);
+ DSI_W32(ctrl, DSI_COMMAND_MODE_MDP_STREAM1_CTRL, stream_ctrl);
- reg = (mode->v_active << 16) | width_final;
- DSI_W32(ctrl, DSI_COMMAND_MODE_MDP_STREAM0_TOTAL, reg);
- DSI_W32(ctrl, DSI_COMMAND_MODE_MDP_STREAM1_TOTAL, reg);
+ stream_total = (height_final << 16) | width_final;
+ DSI_W32(ctrl, DSI_COMMAND_MODE_MDP_STREAM0_TOTAL, stream_total);
+ DSI_W32(ctrl, DSI_COMMAND_MODE_MDP_STREAM1_TOTAL, stream_total);
+
+ pr_debug("ctrl %d stream_ctrl 0x%x stream_total 0x%x\n", ctrl->index,
+ stream_ctrl, stream_total);
}
/**
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h
index 4c9fbbe..f254af5 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h
@@ -249,4 +249,6 @@
int dsi_panel_send_roi_dcs(struct dsi_panel *panel, int ctrl_idx,
struct dsi_rect *roi);
+void dsi_dsc_pclk_param_calc(struct msm_display_dsc_info *dsc, int intf_width);
+
#endif /* _DSI_PANEL_H_ */
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c
index a457938..79fcfb7 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.c
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.c
@@ -612,12 +612,15 @@
int i;
if (!dim_layer->rect.w || !dim_layer->rect.h) {
- SDE_DEBUG("empty dim layer\n");
+ SDE_DEBUG("empty dim_layer\n");
return;
}
cstate = to_sde_crtc_state(crtc->state);
+ SDE_DEBUG("dim_layer - flags:%d, stage:%d\n",
+ dim_layer->flags, dim_layer->stage);
+
split_dim_layer.stage = dim_layer->stage;
split_dim_layer.color_fill = dim_layer->color_fill;
@@ -651,9 +654,13 @@
} else {
split_dim_layer.rect.x =
split_dim_layer.rect.x -
- cstate->lm_bounds[i].w;
+ cstate->lm_bounds[i].x;
}
+ SDE_DEBUG("split_dim_layer - LM:%d, rect:{%d,%d,%d,%d}}\n",
+ i, split_dim_layer.rect.x, split_dim_layer.rect.y,
+ split_dim_layer.rect.w, split_dim_layer.rect.h);
+
lm = mixer[i].hw_lm;
mixer[i].mixer_op_mode |= 1 << split_dim_layer.stage;
lm->ops.setup_dim_layer(lm, &split_dim_layer);
@@ -858,9 +865,24 @@
sde_crtc = to_sde_crtc(crtc);
crtc_state = to_sde_crtc_state(state);
- for (i = 0; i < sde_crtc->num_mixers; i++) {
- if (!sde_kms_rect_is_null(&crtc_state->lm_roi[i]))
- disp_bitmask |= BIT(i);
+ /* pingpong split: one ROI, one LM, two physical displays */
+ if (crtc_state->is_ppsplit) {
+ u32 lm_split_width = crtc_state->lm_bounds[0].w / 2;
+ struct sde_rect *roi = &crtc_state->lm_roi[0];
+
+ if (sde_kms_rect_is_null(roi))
+ disp_bitmask = 0;
+ else if ((u32)roi->x + (u32)roi->w <= lm_split_width)
+ disp_bitmask = BIT(0); /* left only */
+ else if (roi->x >= lm_split_width)
+ disp_bitmask = BIT(1); /* right only */
+ else
+ disp_bitmask = BIT(0) | BIT(1); /* left and right */
+ } else {
+ for (i = 0; i < sde_crtc->num_mixers; i++) {
+ if (!sde_kms_rect_is_null(&crtc_state->lm_roi[i]))
+ disp_bitmask |= BIT(i);
+ }
}
SDE_DEBUG("affected displays 0x%x\n", disp_bitmask);
@@ -881,9 +903,6 @@
sde_crtc = to_sde_crtc(crtc);
crtc_state = to_sde_crtc_state(state);
- if (sde_crtc->num_mixers == 1)
- return 0;
-
if (sde_crtc->num_mixers > CRTC_DUAL_MIXERS) {
SDE_ERROR("%s: unsupported number of mixers: %d\n",
sde_crtc->name, sde_crtc->num_mixers);
@@ -891,9 +910,41 @@
}
/*
- * On certain HW, ROIs must be centered on the split between LMs,
- * and be of equal width.
+ * If using pingpong split: one ROI, one LM, two physical displays
+ * then the ROI must be centered on the panel split boundary and
+ * be of equal width across the split.
*/
+ if (crtc_state->is_ppsplit) {
+ u16 panel_split_width;
+ u32 display_mask;
+
+ roi[0] = &crtc_state->lm_roi[0];
+
+ if (sde_kms_rect_is_null(roi[0]))
+ return 0;
+
+ display_mask = _sde_crtc_get_displays_affected(crtc, state);
+ if (display_mask != (BIT(0) | BIT(1)))
+ return 0;
+
+ panel_split_width = crtc_state->lm_bounds[0].w / 2;
+ if (roi[0]->x + roi[0]->w / 2 != panel_split_width) {
+ SDE_ERROR("%s: roi x %d w %d split %d\n",
+ sde_crtc->name, roi[0]->x, roi[0]->w,
+ panel_split_width);
+ return -EINVAL;
+ }
+
+ return 0;
+ }
+
+ /*
+ * On certain HW, if using 2 LM, ROIs must be split evenly between the
+ * LMs and be of equal width.
+ */
+ if (sde_crtc->num_mixers == 1)
+ return 0;
+
roi[0] = &crtc_state->lm_roi[0];
roi[1] = &crtc_state->lm_roi[1];
@@ -1181,6 +1232,69 @@
_sde_crtc_program_lm_output_roi(crtc);
}
+static void _sde_crtc_swap_mixers_for_right_partial_update(
+ struct drm_crtc *crtc)
+{
+ struct sde_crtc *sde_crtc;
+ struct sde_crtc_state *cstate;
+ struct drm_encoder *drm_enc;
+ bool is_right_only;
+ bool encoder_in_dsc_merge = false;
+
+ if (!crtc || !crtc->state)
+ return;
+
+ sde_crtc = to_sde_crtc(crtc);
+ cstate = to_sde_crtc_state(crtc->state);
+
+ if (sde_crtc->num_mixers != CRTC_DUAL_MIXERS)
+ return;
+
+ drm_for_each_encoder(drm_enc, crtc->dev) {
+ if (drm_enc->crtc == crtc &&
+ sde_encoder_is_dsc_merge(drm_enc)) {
+ encoder_in_dsc_merge = true;
+ break;
+ }
+ }
+
+ /**
+ * For right-only partial update with DSC merge, we swap LM0 & LM1.
+ * This is due to two reasons:
+ * - On 8996, there is a DSC HW requirement that in DSC Merge Mode,
+ * the left DSC must be used, right DSC cannot be used alone.
+ * For right-only partial update, this means swap layer mixers to map
+ * Left LM to Right INTF. On later HW this was relaxed.
+ * - In DSC Merge mode, the physical encoder has already registered
+ * PP0 as the master, to switch to right-only we would have to
+ * reprogram to be driven by PP1 instead.
+ * To support both cases, we prefer to support the mixer swap solution.
+ */
+ if (!encoder_in_dsc_merge)
+ return;
+
+ is_right_only = sde_kms_rect_is_null(&cstate->lm_roi[0]) &&
+ !sde_kms_rect_is_null(&cstate->lm_roi[1]);
+
+ if (is_right_only && !sde_crtc->mixers_swapped) {
+ /* right-only update swap mixers */
+ swap(sde_crtc->mixers[0], sde_crtc->mixers[1]);
+ sde_crtc->mixers_swapped = true;
+ } else if (!is_right_only && sde_crtc->mixers_swapped) {
+ /* left-only or full update, swap back */
+ swap(sde_crtc->mixers[0], sde_crtc->mixers[1]);
+ sde_crtc->mixers_swapped = false;
+ }
+
+ SDE_DEBUG("%s: right_only %d swapped %d, mix0->lm%d, mix1->lm%d\n",
+ sde_crtc->name, is_right_only, sde_crtc->mixers_swapped,
+ sde_crtc->mixers[0].hw_lm->idx - LM_0,
+ sde_crtc->mixers[1].hw_lm->idx - LM_0);
+ SDE_EVT32(DRMID(crtc), is_right_only, sde_crtc->mixers_swapped,
+ sde_crtc->mixers[0].hw_lm->idx - LM_0,
+ sde_crtc->mixers[1].hw_lm->idx - LM_0);
+}
+
/**
* _sde_crtc_blend_setup - configure crtc mixers
* @crtc: Pointer to drm crtc structure
@@ -1226,6 +1340,8 @@
lm->ops.clear_dim_layer(lm);
}
+ _sde_crtc_swap_mixers_for_right_partial_update(crtc);
+
/* initialize stage cfg */
memset(&sde_crtc->stage_cfg, 0, sizeof(struct sde_hw_stage_cfg));
@@ -1534,26 +1650,28 @@
{
struct sde_drm_dim_layer_v1 dim_layer_v1;
struct sde_drm_dim_layer_cfg *user_cfg;
+ struct sde_hw_dim_layer *dim_layer;
u32 count, i;
if (!cstate) {
SDE_ERROR("invalid cstate\n");
return;
}
+ dim_layer = cstate->dim_layer;
if (!usr_ptr) {
- SDE_DEBUG("dim layer data removed\n");
+ SDE_DEBUG("dim_layer data removed\n");
return;
}
if (copy_from_user(&dim_layer_v1, usr_ptr, sizeof(dim_layer_v1))) {
- SDE_ERROR("failed to copy dim layer data\n");
+ SDE_ERROR("failed to copy dim_layer data\n");
return;
}
count = dim_layer_v1.num_layers;
- if (!count || (count > SDE_MAX_DIM_LAYERS)) {
- SDE_ERROR("invalid number of Dim Layers:%d", count);
+ if (count > SDE_MAX_DIM_LAYERS) {
+ SDE_ERROR("invalid number of dim_layers:%d", count);
return;
}
@@ -1561,22 +1679,31 @@
cstate->num_dim_layers = count;
for (i = 0; i < count; i++) {
user_cfg = &dim_layer_v1.layer_cfg[i];
- cstate->dim_layer[i].flags = user_cfg->flags;
- cstate->dim_layer[i].stage = user_cfg->stage + SDE_STAGE_0;
- cstate->dim_layer[i].rect.x = user_cfg->rect.x1;
- cstate->dim_layer[i].rect.y = user_cfg->rect.y1;
- cstate->dim_layer[i].rect.w = user_cfg->rect.x2 -
- user_cfg->rect.x1 + 1;
- cstate->dim_layer[i].rect.h = user_cfg->rect.y2 -
- user_cfg->rect.y1 + 1;
+ dim_layer[i].flags = user_cfg->flags;
+ dim_layer[i].stage = user_cfg->stage + SDE_STAGE_0;
- cstate->dim_layer[i].color_fill = (struct sde_mdss_color) {
+ dim_layer[i].rect.x = user_cfg->rect.x1;
+ dim_layer[i].rect.y = user_cfg->rect.y1;
+ dim_layer[i].rect.w = user_cfg->rect.x2 - user_cfg->rect.x1;
+ dim_layer[i].rect.h = user_cfg->rect.y2 - user_cfg->rect.y1;
+
+ dim_layer[i].color_fill = (struct sde_mdss_color) {
user_cfg->color_fill.color_0,
user_cfg->color_fill.color_1,
user_cfg->color_fill.color_2,
user_cfg->color_fill.color_3,
};
+
+ SDE_DEBUG("dim_layer[%d] - flags:%d, stage:%d\n",
+ i, dim_layer[i].flags, dim_layer[i].stage);
+ SDE_DEBUG(" rect:{%d,%d,%d,%d}, color:{%d,%d,%d,%d}\n",
+ dim_layer[i].rect.x, dim_layer[i].rect.y,
+ dim_layer[i].rect.w, dim_layer[i].rect.h,
+ dim_layer[i].color_fill.color_0,
+ dim_layer[i].color_fill.color_1,
+ dim_layer[i].color_fill.color_2,
+ dim_layer[i].color_fill.color_3);
}
}
@@ -1700,6 +1827,23 @@
mutex_unlock(&sde_crtc->crtc_lock);
}
+static void _sde_crtc_setup_is_ppsplit(struct drm_crtc_state *state)
+{
+ int i;
+ struct sde_crtc_state *cstate;
+
+ cstate = to_sde_crtc_state(state);
+
+ cstate->is_ppsplit = false;
+ for (i = 0; i < cstate->num_connectors; i++) {
+ struct drm_connector *conn = cstate->connectors[i];
+
+ if (sde_connector_get_topology_name(conn) ==
+ SDE_RM_TOPOLOGY_PPSPLIT)
+ cstate->is_ppsplit = true;
+ }
+}
+
static void _sde_crtc_setup_lm_bounds(struct drm_crtc *crtc,
struct drm_crtc_state *state)
{
@@ -1764,6 +1908,7 @@
if (!sde_crtc->num_mixers) {
_sde_crtc_setup_mixers(crtc);
+ _sde_crtc_setup_is_ppsplit(crtc->state);
_sde_crtc_setup_lm_bounds(crtc, crtc->state);
}
@@ -2486,6 +2631,7 @@
mixer_width = sde_crtc_mixer_width(sde_crtc, mode);
+ _sde_crtc_setup_is_ppsplit(state);
_sde_crtc_setup_lm_bounds(crtc, state);
/* get plane state for all drm planes associated with crtc state */
@@ -2508,9 +2654,10 @@
/* check dim layer stage with every plane */
for (i = 0; i < cstate->num_dim_layers; i++) {
if (pstates[cnt].stage == cstate->dim_layer[i].stage) {
- SDE_ERROR("plane%d/dimlayer in same stage:%d\n",
- plane->base.id,
- cstate->dim_layer[i].stage);
+ SDE_ERROR(
+ "plane:%d/dim_layer:%i-same stage:%d\n",
+ plane->base.id, i,
+ cstate->dim_layer[i].stage);
rc = -EINVAL;
goto end;
}
@@ -2781,16 +2928,18 @@
msm_property_install_blob(&sde_crtc->property_info, "capabilities",
DRM_MODE_PROP_IMMUTABLE, CRTC_PROP_INFO);
- if (catalog->has_dim_layer) {
- msm_property_install_volatile_range(&sde_crtc->property_info,
- "dim_layer_v1", 0x0, 0, ~0, 0, CRTC_PROP_DIM_LAYER_V1);
- }
-
msm_property_install_volatile_range(&sde_crtc->property_info,
"sde_drm_roi_v1", 0x0, 0, ~0, 0, CRTC_PROP_ROI_V1);
sde_kms_info_reset(info);
+ if (catalog->has_dim_layer) {
+ msm_property_install_volatile_range(&sde_crtc->property_info,
+ "dim_layer_v1", 0x0, 0, ~0, 0, CRTC_PROP_DIM_LAYER_V1);
+ sde_kms_info_add_keyint(info, "dim_layer_v1_max_layers",
+ SDE_MAX_DIM_LAYERS);
+ }
+
sde_kms_info_add_keyint(info, "hw_version", catalog->hwversion);
sde_kms_info_add_keyint(info, "max_linewidth",
catalog->max_mixer_width);
@@ -2990,6 +3139,7 @@
struct drm_display_mode *mode;
struct drm_framebuffer *fb;
struct drm_plane_state *state;
+ struct sde_crtc_state *cstate;
int i, out_width;
@@ -2998,6 +3148,7 @@
sde_crtc = s->private;
crtc = &sde_crtc->base;
+ cstate = to_sde_crtc_state(crtc->state);
mutex_lock(&sde_crtc->crtc_lock);
mode = &crtc->state->adjusted_mode;
@@ -3022,6 +3173,23 @@
seq_puts(s, "\n");
+ for (i = 0; i < cstate->num_dim_layers; i++) {
+ struct sde_hw_dim_layer *dim_layer = &cstate->dim_layer[i];
+
+ seq_printf(s, "\tdim_layer:%d] stage:%d flags:%d\n",
+ i, dim_layer->stage, dim_layer->flags);
+ seq_printf(s, "\tdst_x:%d dst_y:%d dst_w:%d dst_h:%d\n",
+ dim_layer->rect.x, dim_layer->rect.y,
+ dim_layer->rect.w, dim_layer->rect.h);
+ seq_printf(s,
+ "\tcolor_0:%d color_1:%d color_2:%d color_3:%d\n",
+ dim_layer->color_fill.color_0,
+ dim_layer->color_fill.color_1,
+ dim_layer->color_fill.color_2,
+ dim_layer->color_fill.color_3);
+ seq_puts(s, "\n");
+ }
+
drm_atomic_crtc_for_each_plane(plane, crtc) {
pstate = to_sde_plane_state(plane->state);
state = plane->state;
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.h b/drivers/gpu/drm/msm/sde/sde_crtc.h
index 6a22115..9ef6f25 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.h
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.h
@@ -108,6 +108,8 @@
* @name : ASCII description of this crtc
* @num_ctls : Number of ctl paths in use
* @num_mixers : Number of mixers in use
+ * @mixers_swapped: Whether the mixers have been swapped for left/right update
+ * especially in the case of DSC Merge.
* @mixers : List of active mixers
* @event : Pointer to last received drm vblank event. If there is a
* pending vblank event, this will be non-null.
@@ -147,6 +149,7 @@
/* HW Resources reserved for the crtc */
u32 num_ctls;
u32 num_mixers;
+ bool mixers_swapped;
struct sde_crtc_mixer mixers[CRTC_DUAL_MIXERS];
struct drm_pending_vblank_event *event;
@@ -251,6 +254,7 @@
* @num_connectors: Number of associated drm connectors
* @intf_mode : Interface mode of the primary connector
* @rsc_client : sde rsc client when mode is valid
+ * @is_ppsplit : Whether current topology requires PPSplit special handling
* @crtc_roi : Current CRTC ROI. Possibly sub-rectangle of mode.
* Origin top left of CRTC.
* @lm_bounds : LM boundaries based on current mode full resolution, no ROI.
@@ -277,6 +281,7 @@
struct sde_rsc_client *rsc_client;
bool rsc_update;
+ bool is_ppsplit;
struct sde_rect crtc_roi;
struct sde_rect lm_bounds[CRTC_DUAL_MIXERS];
struct sde_rect lm_roi[CRTC_DUAL_MIXERS];
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c
index f11ba51..e3ad960 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder.c
@@ -123,8 +123,11 @@
* @cur_master: Pointer to the current master in this mode. Optimization
* Only valid after enable. Cleared as disable.
* @hw_pp Handle to the pingpong blocks used for the display. No.
- * pingpong blocks can be different than num_phys_encs.
+ * pingpong blocks can be different than num_phys_encs.
* @hw_dsc: Array of DSC block handles used for the display.
+ * @intfs_swapped Whether or not the phys_enc interfaces have been swapped
+ * for partial update right-only cases, such as pingpong
+ * split where virtual pingpong does not generate IRQs
* @crtc_vblank_cb: Callback into the upper layer / CRTC for
* notification of the VBLANK
* @crtc_vblank_cb_data: Data from upper layer for VBLANK notification
@@ -155,6 +158,8 @@
* @topology: topology of the display
* @mode_set_complete: flag to indicate modeset completion
* @rsc_cfg: rsc configuration
+ * @cur_conn_roi: current connector roi
+ * @prv_conn_roi: previous connector roi to optimize if unchanged
*/
struct sde_encoder_virt {
struct drm_encoder base;
@@ -169,6 +174,8 @@
struct sde_hw_pingpong *hw_pp[MAX_CHANNELS_PER_ENC];
struct sde_hw_dsc *hw_dsc[MAX_CHANNELS_PER_ENC];
+ bool intfs_swapped;
+
void (*crtc_vblank_cb)(void *);
void *crtc_vblank_cb_data;
@@ -195,17 +202,51 @@
bool mode_set_complete;
struct sde_encoder_rsc_config rsc_cfg;
+ struct sde_rect cur_conn_roi;
+ struct sde_rect prv_conn_roi;
};
#define to_sde_encoder_virt(x) container_of(x, struct sde_encoder_virt, base)
-inline bool _sde_is_dsc_enabled(struct sde_encoder_virt *sde_enc)
+bool sde_encoder_is_dsc_enabled(struct drm_encoder *drm_enc)
+
{
- struct msm_compression_info *comp_info = &sde_enc->disp_info.comp_info;
+ struct sde_encoder_virt *sde_enc;
+ struct msm_compression_info *comp_info;
+
+ if (!drm_enc)
+ return false;
+
+ sde_enc = to_sde_encoder_virt(drm_enc);
+ comp_info = &sde_enc->disp_info.comp_info;
return (comp_info->comp_type == MSM_DISPLAY_COMPRESSION_DSC);
}
+bool sde_encoder_is_dsc_merge(struct drm_encoder *drm_enc)
+{
+ enum sde_rm_topology_name topology;
+ struct sde_encoder_virt *sde_enc;
+ struct drm_connector *drm_conn;
+
+ if (!drm_enc)
+ return false;
+
+ sde_enc = to_sde_encoder_virt(drm_enc);
+ if (!sde_enc->cur_master)
+ return false;
+
+ drm_conn = sde_enc->cur_master->connector;
+ if (!drm_conn)
+ return false;
+
+ topology = sde_connector_get_topology_name(drm_conn);
+ if (topology == SDE_RM_TOPOLOGY_DUALPIPE_DSCMERGE)
+ return true;
+
+ return false;
+}
+
static inline int _sde_encoder_power_enable(struct sde_encoder_virt *sde_enc,
bool enable)
{
@@ -320,7 +361,22 @@
sde_enc = to_sde_encoder_virt(phys_enc->parent);
hw_mdptop = phys_enc->hw_mdptop;
- cfg.en = phys_enc->split_role != ENC_ROLE_SOLO;
+
+ /**
+ * disable split modes since encoder will be operating in as the only
+ * encoder, either for the entire use case in the case of, for example,
+ * single DSI, or for this frame in the case of left/right only partial
+ * update.
+ */
+ if (phys_enc->split_role == ENC_ROLE_SOLO) {
+ if (hw_mdptop->ops.setup_split_pipe)
+ hw_mdptop->ops.setup_split_pipe(hw_mdptop, &cfg);
+ if (hw_mdptop->ops.setup_pp_split)
+ hw_mdptop->ops.setup_pp_split(hw_mdptop, &cfg);
+ return;
+ }
+
+ cfg.en = true;
cfg.mode = phys_enc->intf_mode;
cfg.intf = interface;
@@ -334,8 +390,7 @@
else
cfg.pp_split_slave = INTF_MAX;
- if (phys_enc->split_role != ENC_ROLE_SLAVE) {
- /* master/solo encoder */
+ if (phys_enc->split_role == ENC_ROLE_MASTER) {
SDE_DEBUG_ENC(sde_enc, "enable %d\n", cfg.en);
if (hw_mdptop->ops.setup_split_pipe)
@@ -555,8 +610,14 @@
static void _sde_encoder_dsc_pipe_cfg(struct sde_hw_dsc *hw_dsc,
struct sde_hw_pingpong *hw_pp, struct msm_display_dsc_info *dsc,
- u32 common_mode, bool ich_reset)
+ u32 common_mode, bool ich_reset, bool enable)
{
+ if (!enable) {
+ if (hw_pp->ops.disable_dsc)
+ hw_pp->ops.disable_dsc(hw_pp);
+ return;
+ }
+
if (hw_dsc->ops.dsc_config)
hw_dsc->ops.dsc_config(hw_dsc, dsc, common_mode, ich_reset);
@@ -570,9 +631,27 @@
hw_pp->ops.enable_dsc(hw_pp);
}
+static void _sde_encoder_get_connector_roi(
+ struct sde_encoder_virt *sde_enc,
+ struct sde_rect *merged_conn_roi)
+{
+ struct drm_connector *drm_conn;
+ struct sde_connector_state *c_state;
+
+ if (!sde_enc || !merged_conn_roi)
+ return;
+
+ drm_conn = sde_enc->phys_encs[0]->connector;
+
+ if (!drm_conn || !drm_conn->state)
+ return;
+
+ c_state = to_sde_connector_state(drm_conn->state);
+ sde_kms_rect_merge_rectangles(&c_state->rois, merged_conn_roi);
+}
+
static int _sde_encoder_dsc_1_lm_1_enc_1_intf(struct sde_encoder_virt *sde_enc)
{
- int pic_width, pic_height;
int this_frame_slices;
int intf_ip_w, enc_ip_w;
int ich_res, dsc_common_mode = 0;
@@ -580,22 +659,18 @@
struct sde_hw_pingpong *hw_pp = sde_enc->hw_pp[0];
struct sde_hw_dsc *hw_dsc = sde_enc->hw_dsc[0];
struct sde_encoder_phys *enc_master = sde_enc->cur_master;
- struct sde_hw_mdp *hw_mdp_top = enc_master->hw_mdptop;
+ const struct sde_rect *roi = &sde_enc->cur_conn_roi;
struct msm_display_dsc_info *dsc =
&sde_enc->disp_info.comp_info.dsc_info;
- if (dsc == NULL || hw_dsc == NULL || hw_pp == NULL ||
- hw_mdp_top == NULL) {
+ if (dsc == NULL || hw_dsc == NULL || hw_pp == NULL || !enc_master) {
SDE_ERROR_ENC(sde_enc, "invalid params for DSC\n");
return -EINVAL;
}
- pic_width = dsc->pic_width;
- pic_height = dsc->pic_height;
+ _sde_encoder_dsc_update_pic_dim(dsc, roi->w, roi->h);
- _sde_encoder_dsc_update_pic_dim(dsc, pic_width, pic_height);
-
- this_frame_slices = pic_width / dsc->slice_width;
+ this_frame_slices = roi->w / dsc->slice_width;
intf_ip_w = this_frame_slices * dsc->slice_width;
_sde_encoder_dsc_pclk_param_calc(dsc, intf_ip_w);
@@ -608,132 +683,208 @@
dsc_common_mode = DSC_MODE_VIDEO;
SDE_DEBUG_ENC(sde_enc, "pic_w: %d pic_h: %d mode:%d\n",
- pic_width, pic_height, dsc_common_mode);
- SDE_EVT32(DRMID(&sde_enc->base), pic_width, pic_height,
- dsc_common_mode);
+ roi->w, roi->h, dsc_common_mode);
+ SDE_EVT32(DRMID(&sde_enc->base), roi->w, roi->h, dsc_common_mode);
_sde_encoder_dsc_pipe_cfg(hw_dsc, hw_pp, dsc, dsc_common_mode,
- ich_res);
+ ich_res, true);
return 0;
}
-static int _sde_encoder_dsc_2_lm_2_enc_2_intf(struct sde_encoder_virt *sde_enc)
+static int _sde_encoder_dsc_2_lm_2_enc_2_intf(struct sde_encoder_virt *sde_enc,
+ struct sde_encoder_kickoff_params *params)
{
- int pic_width, pic_height;
int this_frame_slices;
int intf_ip_w, enc_ip_w;
int ich_res, dsc_common_mode;
struct sde_encoder_phys *enc_master = sde_enc->cur_master;
- struct sde_hw_dsc *l_hw_dsc = sde_enc->hw_dsc[0];
- struct sde_hw_dsc *r_hw_dsc = sde_enc->hw_dsc[1];
- struct sde_hw_pingpong *l_hw_pp = sde_enc->hw_pp[0];
- struct sde_hw_pingpong *r_hw_pp = sde_enc->hw_pp[1];
- struct sde_hw_mdp *hw_mdp_top = enc_master->hw_mdptop;
- struct msm_display_dsc_info *dsc =
- &sde_enc->disp_info.comp_info.dsc_info;
+ const struct sde_rect *roi = &sde_enc->cur_conn_roi;
+ struct sde_hw_dsc *hw_dsc[MAX_CHANNELS_PER_ENC];
+ struct sde_hw_pingpong *hw_pp[MAX_CHANNELS_PER_ENC];
+ struct msm_display_dsc_info dsc[MAX_CHANNELS_PER_ENC];
+ bool half_panel_partial_update;
+ int i;
- if (l_hw_dsc == NULL || r_hw_dsc == NULL || hw_mdp_top == NULL ||
- l_hw_pp == NULL || r_hw_pp == NULL) {
- SDE_ERROR_ENC(sde_enc, "invalid params for DSC\n");
- return -EINVAL;
+ for (i = 0; i < MAX_CHANNELS_PER_ENC; i++) {
+ hw_pp[i] = sde_enc->hw_pp[i];
+ hw_dsc[i] = sde_enc->hw_dsc[i];
+
+ if (!hw_pp[i] || !hw_dsc[i]) {
+ SDE_ERROR_ENC(sde_enc, "invalid params for DSC\n");
+ return -EINVAL;
+ }
}
- pic_width = dsc->pic_width * sde_enc->display_num_of_h_tiles;
- pic_height = dsc->pic_height;
+ half_panel_partial_update =
+ hweight_long(params->affected_displays) == 1;
- _sde_encoder_dsc_update_pic_dim(dsc, pic_width, pic_height);
-
- this_frame_slices = pic_width / dsc->slice_width;
- intf_ip_w = this_frame_slices * dsc->slice_width;
-
- intf_ip_w /= 2;
- _sde_encoder_dsc_pclk_param_calc(dsc, intf_ip_w);
-
- enc_ip_w = intf_ip_w;
- _sde_encoder_dsc_initial_line_calc(dsc, enc_ip_w);
-
- ich_res = _sde_encoder_dsc_ich_reset_override_needed(false, dsc);
-
- dsc_common_mode = DSC_MODE_SPLIT_PANEL;
+ dsc_common_mode = 0;
+ if (!half_panel_partial_update)
+ dsc_common_mode |= DSC_MODE_SPLIT_PANEL;
if (enc_master->intf_mode == INTF_MODE_VIDEO)
dsc_common_mode |= DSC_MODE_VIDEO;
- SDE_DEBUG_ENC(sde_enc, "pic_w: %d pic_h: %d mode:%d\n",
- pic_width, pic_height, dsc_common_mode);
- SDE_EVT32(DRMID(&sde_enc->base), pic_width, pic_height,
- dsc_common_mode);
+ memcpy(&dsc[0], &sde_enc->disp_info.comp_info.dsc_info, sizeof(dsc[0]));
+ memcpy(&dsc[1], &sde_enc->disp_info.comp_info.dsc_info, sizeof(dsc[1]));
- _sde_encoder_dsc_pipe_cfg(l_hw_dsc, l_hw_pp, dsc, dsc_common_mode,
- ich_res);
- _sde_encoder_dsc_pipe_cfg(r_hw_dsc, r_hw_pp, dsc, dsc_common_mode,
- ich_res);
+ /*
+ * Since both DSC use same pic dimension, set same pic dimension
+ * to both DSC structures.
+ */
+ _sde_encoder_dsc_update_pic_dim(&dsc[0], roi->w, roi->h);
+ _sde_encoder_dsc_update_pic_dim(&dsc[1], roi->w, roi->h);
+
+ this_frame_slices = roi->w / dsc[0].slice_width;
+ intf_ip_w = this_frame_slices * dsc[0].slice_width;
+
+ if (!half_panel_partial_update)
+ intf_ip_w /= 2;
+
+ /*
+ * In this topology when both interfaces are active, they have same
+ * load so intf_ip_w will be same.
+ */
+ _sde_encoder_dsc_pclk_param_calc(&dsc[0], intf_ip_w);
+ _sde_encoder_dsc_pclk_param_calc(&dsc[1], intf_ip_w);
+
+ /*
+ * In this topology, since there is no dsc_merge, uncompressed input
+ * to encoder and interface is same.
+ */
+ enc_ip_w = intf_ip_w;
+ _sde_encoder_dsc_initial_line_calc(&dsc[0], enc_ip_w);
+ _sde_encoder_dsc_initial_line_calc(&dsc[1], enc_ip_w);
+
+ /*
+ * __is_ich_reset_override_needed should be called only after
+ * updating pic dimension, mdss_panel_dsc_update_pic_dim.
+ */
+ ich_res = _sde_encoder_dsc_ich_reset_override_needed(
+ half_panel_partial_update, &dsc[0]);
+
+ SDE_DEBUG_ENC(sde_enc, "pic_w: %d pic_h: %d mode:%d\n",
+ roi->w, roi->h, dsc_common_mode);
+
+ for (i = 0; i < sde_enc->num_phys_encs; i++) {
+ bool active = !!((1 << i) & params->affected_displays);
+
+ SDE_EVT32(DRMID(&sde_enc->base), roi->w, roi->h,
+ dsc_common_mode, i, active);
+ _sde_encoder_dsc_pipe_cfg(hw_dsc[i], hw_pp[i], &dsc[i],
+ dsc_common_mode, ich_res, active);
+ }
return 0;
}
-static int _sde_encoder_dsc_2_lm_2_enc_1_intf(struct sde_encoder_virt *sde_enc)
+static int _sde_encoder_dsc_2_lm_2_enc_1_intf(struct sde_encoder_virt *sde_enc,
+ struct sde_encoder_kickoff_params *params)
{
- int pic_width, pic_height;
int this_frame_slices;
int intf_ip_w, enc_ip_w;
int ich_res, dsc_common_mode;
struct sde_encoder_phys *enc_master = sde_enc->cur_master;
- struct sde_hw_dsc *l_hw_dsc = sde_enc->hw_dsc[0];
- struct sde_hw_dsc *r_hw_dsc = sde_enc->hw_dsc[1];
- struct sde_hw_pingpong *l_hw_pp = sde_enc->hw_pp[0];
- struct sde_hw_pingpong *r_hw_pp = sde_enc->hw_pp[1];
- struct sde_hw_mdp *hw_mdp_top = enc_master->hw_mdptop;
+ const struct sde_rect *roi = &sde_enc->cur_conn_roi;
+ struct sde_hw_dsc *hw_dsc[MAX_CHANNELS_PER_ENC];
+ struct sde_hw_pingpong *hw_pp[MAX_CHANNELS_PER_ENC];
struct msm_display_dsc_info *dsc =
&sde_enc->disp_info.comp_info.dsc_info;
+ bool half_panel_partial_update;
+ int i;
- if (l_hw_dsc == NULL || r_hw_dsc == NULL || hw_mdp_top == NULL ||
- l_hw_pp == NULL || r_hw_pp == NULL) {
- SDE_ERROR_ENC(sde_enc, "invalid params for DSC\n");
- return -EINVAL;
+ for (i = 0; i < MAX_CHANNELS_PER_ENC; i++) {
+ hw_pp[i] = sde_enc->hw_pp[i];
+ hw_dsc[i] = sde_enc->hw_dsc[i];
+
+ if (!hw_pp[i] || !hw_dsc[i]) {
+ SDE_ERROR_ENC(sde_enc, "invalid params for DSC\n");
+ return -EINVAL;
+ }
}
- pic_width = dsc->pic_width;
- pic_height = dsc->pic_height;
- _sde_encoder_dsc_update_pic_dim(dsc, pic_width, pic_height);
+ half_panel_partial_update =
+ hweight_long(params->affected_displays) == 1;
- this_frame_slices = pic_width / dsc->slice_width;
+ dsc_common_mode = 0;
+ if (!half_panel_partial_update)
+ dsc_common_mode |= DSC_MODE_SPLIT_PANEL | DSC_MODE_MULTIPLEX;
+ if (enc_master->intf_mode == INTF_MODE_VIDEO)
+ dsc_common_mode |= DSC_MODE_VIDEO;
+
+ _sde_encoder_dsc_update_pic_dim(dsc, roi->w, roi->h);
+
+ this_frame_slices = roi->w / dsc->slice_width;
intf_ip_w = this_frame_slices * dsc->slice_width;
_sde_encoder_dsc_pclk_param_calc(dsc, intf_ip_w);
/*
- * when using 2 encoders for the same stream, no. of slices
- * need to be same on both the encoders.
+ * dsc merge case: when using 2 encoders for the same stream,
+ * no. of slices need to be same on both the encoders.
*/
enc_ip_w = intf_ip_w / 2;
_sde_encoder_dsc_initial_line_calc(dsc, enc_ip_w);
- ich_res = _sde_encoder_dsc_ich_reset_override_needed(false, dsc);
-
- dsc_common_mode = DSC_MODE_MULTIPLEX | DSC_MODE_SPLIT_PANEL;
- if (enc_master->intf_mode == INTF_MODE_VIDEO)
- dsc_common_mode |= DSC_MODE_VIDEO;
+ ich_res = _sde_encoder_dsc_ich_reset_override_needed(
+ half_panel_partial_update, dsc);
SDE_DEBUG_ENC(sde_enc, "pic_w: %d pic_h: %d mode:%d\n",
- pic_width, pic_height, dsc_common_mode);
- SDE_EVT32(DRMID(&sde_enc->base), pic_width, pic_height,
- dsc_common_mode);
+ roi->w, roi->h, dsc_common_mode);
+ SDE_EVT32(DRMID(&sde_enc->base), roi->w, roi->h,
+ dsc_common_mode, i, params->affected_displays);
- _sde_encoder_dsc_pipe_cfg(l_hw_dsc, l_hw_pp, dsc, dsc_common_mode,
- ich_res);
- _sde_encoder_dsc_pipe_cfg(r_hw_dsc, r_hw_pp, dsc, dsc_common_mode,
- ich_res);
+ _sde_encoder_dsc_pipe_cfg(hw_dsc[0], hw_pp[0], dsc, dsc_common_mode,
+ ich_res, true);
+ _sde_encoder_dsc_pipe_cfg(hw_dsc[1], hw_pp[1], dsc, dsc_common_mode,
+ ich_res, !half_panel_partial_update);
return 0;
}
-static int _sde_encoder_dsc_setup(struct sde_encoder_virt *sde_enc)
+static int _sde_encoder_update_roi(struct drm_encoder *drm_enc)
+{
+ struct sde_encoder_virt *sde_enc;
+ struct drm_connector *drm_conn;
+ struct drm_display_mode *adj_mode;
+ struct sde_rect roi;
+
+ if (!drm_enc || !drm_enc->crtc || !drm_enc->crtc->state)
+ return -EINVAL;
+ sde_enc = to_sde_encoder_virt(drm_enc);
+
+ if (!sde_enc->cur_master)
+ return -EINVAL;
+
+ adj_mode = &sde_enc->base.crtc->state->adjusted_mode;
+ drm_conn = sde_enc->cur_master->connector;
+
+ _sde_encoder_get_connector_roi(sde_enc, &roi);
+ if (sde_kms_rect_is_null(&roi)) {
+ roi.w = adj_mode->hdisplay;
+ roi.h = adj_mode->vdisplay;
+ }
+
+ memcpy(&sde_enc->prv_conn_roi, &sde_enc->cur_conn_roi,
+ sizeof(sde_enc->prv_conn_roi));
+ memcpy(&sde_enc->cur_conn_roi, &roi, sizeof(sde_enc->cur_conn_roi));
+
+ return 0;
+}
+
+static int _sde_encoder_dsc_setup(struct sde_encoder_virt *sde_enc,
+ struct sde_encoder_kickoff_params *params)
{
enum sde_rm_topology_name topology;
- struct drm_connector *drm_conn = sde_enc->phys_encs[0]->connector;
+ struct drm_connector *drm_conn;
int ret = 0;
+ if (!sde_enc || !params || !sde_enc->phys_encs[0] ||
+ !sde_enc->phys_encs[0]->connector)
+ return -EINVAL;
+
+ drm_conn = sde_enc->phys_encs[0]->connector;
+
topology = sde_connector_get_topology_name(drm_conn);
if (topology == SDE_RM_TOPOLOGY_NONE) {
SDE_ERROR_ENC(sde_enc, "topology not set yet\n");
@@ -743,15 +894,19 @@
SDE_DEBUG_ENC(sde_enc, "\n");
SDE_EVT32(DRMID(&sde_enc->base));
+ if (sde_kms_rect_is_equal(&sde_enc->cur_conn_roi,
+ &sde_enc->prv_conn_roi))
+ return ret;
+
switch (topology) {
case SDE_RM_TOPOLOGY_SINGLEPIPE_DSC:
ret = _sde_encoder_dsc_1_lm_1_enc_1_intf(sde_enc);
break;
case SDE_RM_TOPOLOGY_DUALPIPE_DSCMERGE:
- ret = _sde_encoder_dsc_2_lm_2_enc_1_intf(sde_enc);
+ ret = _sde_encoder_dsc_2_lm_2_enc_1_intf(sde_enc, params);
break;
case SDE_RM_TOPOLOGY_DUALPIPE_DSC:
- ret = _sde_encoder_dsc_2_lm_2_enc_2_intf(sde_enc);
+ ret = _sde_encoder_dsc_2_lm_2_enc_2_intf(sde_enc, params);
break;
default:
SDE_ERROR_ENC(sde_enc, "No DSC support for topology %d",
@@ -1217,7 +1372,6 @@
struct sde_kms *sde_kms;
struct sde_hw_mdp *hw_mdptop;
int i = 0;
- int ret = 0;
struct sde_watchdog_te_status te_cfg = { 0 };
if (!drm_enc || !drm_enc->dev || !drm_enc->dev->dev_private) {
@@ -1252,12 +1406,6 @@
sde_enc->cur_master->hw_mdptop,
sde_kms->catalog);
- if (_sde_is_dsc_enabled(sde_enc)) {
- ret = _sde_encoder_dsc_setup(sde_enc);
- if (ret)
- SDE_ERROR_ENC(sde_enc, "failed to setup DSC:%d\n", ret);
- }
-
if (hw_mdptop->ops.setup_vsync_sel) {
for (i = 0; i < sde_enc->num_phys_encs; i++)
te_cfg.ppnumber[i] = sde_enc->hw_pp[i]->idx;
@@ -1763,6 +1911,65 @@
spin_unlock_irqrestore(&sde_enc->enc_spinlock, lock_flags);
}
+static void _sde_encoder_ppsplit_swap_intf_for_right_only_update(
+ struct drm_encoder *drm_enc,
+ unsigned long *affected_displays,
+ int num_active_phys)
+{
+ struct sde_encoder_virt *sde_enc;
+ struct sde_encoder_phys *master;
+ enum sde_rm_topology_name topology;
+ bool is_right_only;
+
+ if (!drm_enc || !affected_displays)
+ return;
+
+ sde_enc = to_sde_encoder_virt(drm_enc);
+ master = sde_enc->cur_master;
+ if (!master || !master->connector)
+ return;
+
+ topology = sde_connector_get_topology_name(master->connector);
+ if (topology != SDE_RM_TOPOLOGY_PPSPLIT)
+ return;
+
+ /*
+ * For pingpong split, the slave pingpong won't generate IRQs. For
+ * right-only updates, we can't swap pingpongs, or simply swap the
+ * master/slave assignment, we actually have to swap the interfaces
+ * so that the master physical encoder will use a pingpong/interface
+ * that generates irqs on which to wait.
+ */
+ is_right_only = !test_bit(0, affected_displays) &&
+ test_bit(1, affected_displays);
+
+ if (is_right_only && !sde_enc->intfs_swapped) {
+ /* right-only update swap interfaces */
+ swap(sde_enc->phys_encs[0]->intf_idx,
+ sde_enc->phys_encs[1]->intf_idx);
+ sde_enc->intfs_swapped = true;
+ } else if (!is_right_only && sde_enc->intfs_swapped) {
+ /* left-only or full update, swap back */
+ swap(sde_enc->phys_encs[0]->intf_idx,
+ sde_enc->phys_encs[1]->intf_idx);
+ sde_enc->intfs_swapped = false;
+ }
+
+ SDE_DEBUG_ENC(sde_enc,
+ "right_only %d swapped %d phys0->intf%d, phys1->intf%d\n",
+ is_right_only, sde_enc->intfs_swapped,
+ sde_enc->phys_encs[0]->intf_idx - INTF_0,
+ sde_enc->phys_encs[1]->intf_idx - INTF_0);
+ SDE_EVT32(DRMID(drm_enc), is_right_only, sde_enc->intfs_swapped,
+ sde_enc->phys_encs[0]->intf_idx - INTF_0,
+ sde_enc->phys_encs[1]->intf_idx - INTF_0,
+ *affected_displays);
+
+ /* ppsplit always uses master since ppslave invalid for irqs*/
+ if (num_active_phys == 1)
+ *affected_displays = BIT(0);
+}
+
static void _sde_encoder_update_master(struct drm_encoder *drm_enc,
struct sde_encoder_kickoff_params *params)
{
@@ -1785,6 +1992,10 @@
SDE_DEBUG_ENC(sde_enc, "affected_displays 0x%lx num_active_phys %d\n",
params->affected_displays, num_active_phys);
+ /* for left/right only update, ppsplit master switches interface */
+ _sde_encoder_ppsplit_swap_intf_for_right_only_update(drm_enc,
+ ¶ms->affected_displays, num_active_phys);
+
for (i = 0; i < sde_enc->num_phys_encs; i++) {
enum sde_enc_split_role prv_role, new_role;
bool active;
@@ -1814,6 +2025,9 @@
SDE_DEBUG_ENC(sde_enc, "pp %d role prv %d new %d active %d\n",
phys->hw_pp->idx - PINGPONG_0, prv_role,
phys->split_role, active);
+ SDE_EVT32(DRMID(drm_enc), params->affected_displays,
+ phys->hw_pp->idx - PINGPONG_0, prv_role,
+ phys->split_role, active, num_active_phys);
}
}
@@ -1892,6 +2106,8 @@
_sde_encoder_update_master(drm_enc, params);
+ _sde_encoder_update_roi(drm_enc);
+
if (sde_enc->cur_master && sde_enc->cur_master->connector) {
rc = sde_connector_pre_kickoff(sde_enc->cur_master->connector);
if (rc)
@@ -1899,6 +2115,12 @@
sde_enc->cur_master->connector->base.id,
rc);
}
+
+ if (sde_encoder_is_dsc_enabled(drm_enc)) {
+ rc = _sde_encoder_dsc_setup(sde_enc, params);
+ if (rc)
+ SDE_ERROR_ENC(sde_enc, "failed to setup DSC: %d\n", rc);
+ }
}
void sde_encoder_kickoff(struct drm_encoder *drm_enc)
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.h b/drivers/gpu/drm/msm/sde/sde_encoder.h
index 7292a12..6ef245b 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder.h
+++ b/drivers/gpu/drm/msm/sde/sde_encoder.h
@@ -149,6 +149,20 @@
void sde_encoder_virt_restore(struct drm_encoder *encoder);
/**
+ * sde_encoder_is_dsc_enabled - check if encoder is in DSC mode
+ * @drm_enc: Pointer to drm encoder object
+ * @Return: true if encoder is in DSC mode
+ */
+bool sde_encoder_is_dsc_enabled(struct drm_encoder *drm_enc);
+
+/**
+ * sde_encoder_is_dsc_merge - check if encoder is in DSC merge mode
+ * @drm_enc: Pointer to drm encoder object
+ * @Return: true if encoder is in DSC merge mode
+ */
+bool sde_encoder_is_dsc_merge(struct drm_encoder *drm_enc);
+
+/**
* sde_encoder_init - initialize virtual encoder object
* @dev: Pointer to drm device structure
* @disp_info: Pointer to display information structure
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c
index 572bd9e..53f5b89 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c
@@ -615,7 +615,8 @@
phys_enc->hw_pp->idx - PINGPONG_0);
drm_mode_debug_printmodeline(&phys_enc->cached_mode);
- _sde_encoder_phys_cmd_update_intf_cfg(phys_enc);
+ if (!_sde_encoder_phys_is_ppsplit_slave(phys_enc))
+ _sde_encoder_phys_cmd_update_intf_cfg(phys_enc);
sde_encoder_phys_cmd_tearcheck_config(phys_enc);
}
@@ -832,15 +833,28 @@
struct sde_encoder_phys *phys_enc,
enum sde_enc_split_role role)
{
- struct sde_encoder_phys_cmd *cmd_enc =
- to_sde_encoder_phys_cmd(phys_enc);
- enum sde_enc_split_role old_role = phys_enc->split_role;
+ struct sde_encoder_phys_cmd *cmd_enc;
+ enum sde_enc_split_role old_role;
+ bool is_ppsplit;
+
+ if (!phys_enc)
+ return;
+
+ cmd_enc = to_sde_encoder_phys_cmd(phys_enc);
+ old_role = phys_enc->split_role;
+ is_ppsplit = _sde_encoder_phys_is_ppsplit(phys_enc);
+
+ phys_enc->split_role = role;
SDE_DEBUG_CMDENC(cmd_enc, "old role %d new role %d\n",
old_role, role);
- phys_enc->split_role = role;
- if (role == ENC_ROLE_SKIP || role == old_role)
+ /*
+ * ppsplit solo needs to reprogram because intf may have swapped without
+ * role changing on left-only, right-only back-to-back commits
+ */
+ if (!(is_ppsplit && role == ENC_ROLE_SOLO) &&
+ (role == old_role || role == ENC_ROLE_SKIP))
return;
sde_encoder_helper_split_config(phys_enc, phys_enc->intf_idx);
diff --git a/drivers/gpu/drm/msm/sde/sde_kms_utils.c b/drivers/gpu/drm/msm/sde/sde_kms_utils.c
index dcc0bd5..b77d64d 100644
--- a/drivers/gpu/drm/msm/sde/sde_kms_utils.c
+++ b/drivers/gpu/drm/msm/sde/sde_kms_utils.c
@@ -166,7 +166,7 @@
r = min((r1->x + r1->w), (r2->x + r2->w));
b = min((r1->y + r1->h), (r2->y + r2->h));
- if (r < l || b < t) {
+ if (r <= l || b <= t) {
memset(result, 0, sizeof(*result));
} else {
result->x = l;
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index 41515bb..ee50a61 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -299,3 +299,5 @@
config STM32_EXTI
bool
select IRQ_DOMAIN
+
+source "drivers/irqchip/qcom/Kconfig"
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index 987bd89..450059c 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -75,3 +75,4 @@
obj-$(CONFIG_EZNPS_GIC) += irq-eznps.o
obj-$(CONFIG_ARCH_ASPEED) += irq-aspeed-vic.o
obj-$(CONFIG_STM32_EXTI) += irq-stm32-exti.o
+obj-$(CONFIG_QTI_PDC) += qcom/
diff --git a/drivers/irqchip/qcom/Kconfig b/drivers/irqchip/qcom/Kconfig
new file mode 100644
index 0000000..e4a7a88
--- /dev/null
+++ b/drivers/irqchip/qcom/Kconfig
@@ -0,0 +1,15 @@
+config QTI_PDC
+ bool "QTI PDC"
+ depends on ARCH_QCOM
+ select IRQ_DOMAIN
+ select IRQ_DOMAIN_HIERARCHY
+ help
+ QTI Power Domain Controller driver to manage and configure wakeup
+ IRQs
+
+config QTI_PDC_SDM845
+ bool "QTI PDC SDM845"
+ select QTI_PDC
+ default y if ARCH_SDM845
+ help
+ QTI Power Domain Controller for SDM845
diff --git a/drivers/irqchip/qcom/Makefile b/drivers/irqchip/qcom/Makefile
new file mode 100644
index 0000000..1b7856d
--- /dev/null
+++ b/drivers/irqchip/qcom/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_QTI_PDC) += pdc.o
+obj-$(CONFIG_QTI_PDC_SDM845) += pdc-sdm845.o
diff --git a/drivers/irqchip/qcom/pdc-sdm845.c b/drivers/irqchip/qcom/pdc-sdm845.c
new file mode 100644
index 0000000..178cf1f0
--- /dev/null
+++ b/drivers/irqchip/qcom/pdc-sdm845.c
@@ -0,0 +1,139 @@
+/* Copyright (c) 2017, 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/irqchip.h>
+#include "pdc.h"
+
+static struct pdc_pin sdm845_data[] = {
+ {0, 512}, /* rpmh_wake */
+ {1, 513}, /* ee0_apps_hlos_spmi_periph_irq */
+ {2, 514}, /* ee1_apps_trustzone_spmi_periph_irq */
+ {3, 515}, /* secure_wdog_expired */
+ {4, 516}, /* secure_wdog_bark_irq */
+ {5, 517}, /* aop_wdog_expired_irq */
+ {6, 518}, /* qmp_usb3_lfps_rxterm_irq */
+ {7, 519}, /* qmp_usb3_lfps_rxterm_irq */
+ {8, 520}, /* eud_p0_dmse_int_mx */
+ {9, 521}, /* eud_p0_dpse_int_mx */
+ {10, 522}, /* eud_p1_dmse_int_mx */
+ {11, 523}, /* eud_p1_dpse_int_mx */
+ {12, 524}, /* eud_int_mx[1] */
+ {13, 525}, /* ssc_xpu_irq_summary */
+ {14, 526}, /* wd_bite_apps */
+ {15, 527}, /* ssc_vmidmt_irq_summary */
+ {16, 528}, /* q6ss_irq_out_apps_ipc[4] */
+ {17, 529}, /* not-connected */
+ {18, 530}, /* aoss_pmic_arb_mpu_xpu_summary_irq */
+ {19, 531}, /* apps_pdc_irq_in_19 */
+ {20, 532}, /* apps_pdc_irq_in_20 */
+ {21, 533}, /* apps_pdc_irq_in_21 */
+ {22, 534}, /* pdc_apps_epcb_timeout_summary_irq */
+ {23, 535}, /* spmi_protocol_irq */
+ {24, 536}, /* tsense0_tsense_max_min_int */
+ {25, 537}, /* tsense1_tsense_max_min_int */
+ {26, 538}, /* tsense0_upper_lower_intr */
+ {27, 539}, /* tsense1_upper_lower_intr */
+ {28, 540}, /* tsense0_critical_intr */
+ {29, 541}, /* tsense1_critical_intr */
+ {30, 542}, /* core_bi_px_gpio_1 */
+ {31, 543}, /* core_bi_px_gpio_3 */
+ {32, 544}, /* core_bi_px_gpio_5 */
+ {33, 545}, /* core_bi_px_gpio_10 */
+ {34, 546}, /* core_bi_px_gpio_11 */
+ {35, 547}, /* core_bi_px_gpio_20 */
+ {36, 548}, /* core_bi_px_gpio_22 */
+ {37, 549}, /* core_bi_px_gpio_24 */
+ {38, 550}, /* core_bi_px_gpio_26 */
+ {39, 551}, /* core_bi_px_gpio_30 */
+ {41, 553}, /* core_bi_px_gpio_32 */
+ {42, 554}, /* core_bi_px_gpio_34 */
+ {43, 555}, /* core_bi_px_gpio_36 */
+ {44, 556}, /* core_bi_px_gpio_37 */
+ {45, 557}, /* core_bi_px_gpio_38 */
+ {46, 558}, /* core_bi_px_gpio_39 */
+ {47, 559}, /* core_bi_px_gpio_40 */
+ {49, 561}, /* core_bi_px_gpio_43 */
+ {50, 562}, /* core_bi_px_gpio_44 */
+ {51, 563}, /* core_bi_px_gpio_46 */
+ {52, 564}, /* core_bi_px_gpio_48 */
+ {54, 566}, /* core_bi_px_gpio_52 */
+ {55, 567}, /* core_bi_px_gpio_53 */
+ {56, 568}, /* core_bi_px_gpio_54 */
+ {57, 569}, /* core_bi_px_gpio_56 */
+ {58, 570}, /* core_bi_px_gpio_57 */
+ {59, 571}, /* core_bi_px_gpio_58 */
+ {60, 572}, /* core_bi_px_gpio_59 */
+ {61, 573}, /* core_bi_px_gpio_60 */
+ {62, 574}, /* core_bi_px_gpio_61 */
+ {63, 575}, /* core_bi_px_gpio_62 */
+ {64, 576}, /* core_bi_px_gpio_63 */
+ {65, 577}, /* core_bi_px_gpio_64 */
+ {66, 578}, /* core_bi_px_gpio_66 */
+ {67, 579}, /* core_bi_px_gpio_68 */
+ {68, 580}, /* core_bi_px_gpio_71 */
+ {69, 581}, /* core_bi_px_gpio_73 */
+ {70, 582}, /* core_bi_px_gpio_77 */
+ {71, 583}, /* core_bi_px_gpio_78 */
+ {72, 584}, /* core_bi_px_gpio_79 */
+ {73, 585}, /* core_bi_px_gpio_80 */
+ {74, 586}, /* core_bi_px_gpio_84 */
+ {75, 587}, /* core_bi_px_gpio_85 */
+ {76, 588}, /* core_bi_px_gpio_86 */
+ {77, 589}, /* core_bi_px_gpio_88 */
+ {79, 591}, /* core_bi_px_gpio_91 */
+ {80, 592}, /* core_bi_px_gpio_92 */
+ {81, 593}, /* core_bi_px_gpio_95 */
+ {82, 594}, /* core_bi_px_gpio_96 */
+ {83, 595}, /* core_bi_px_gpio_97 */
+ {84, 596}, /* core_bi_px_gpio_101 */
+ {85, 597}, /* core_bi_px_gpio_103 */
+ {86, 598}, /* core_bi_px_gpio_104 */
+ {87, 599}, /* core_bi_px_to_mpm[6] */
+ {88, 600}, /* core_bi_px_to_mpm[0] */
+ {89, 601}, /* core_bi_px_to_mpm[1] */
+ {90, 602}, /* core_bi_px_gpio_115 */
+ {91, 603}, /* core_bi_px_gpio_116 */
+ {92, 604}, /* core_bi_px_gpio_117 */
+ {93, 605}, /* core_bi_px_gpio_118 */
+ {94, 641}, /* core_bi_px_gpio_119 */
+ {95, 642}, /* core_bi_px_gpio_120 */
+ {96, 643}, /* core_bi_px_gpio_121 */
+ {97, 644}, /* core_bi_px_gpio_122 */
+ {98, 645}, /* core_bi_px_gpio_123 */
+ {99, 646}, /* core_bi_px_gpio_124 */
+ {100, 647}, /* core_bi_px_gpio_125 */
+ {101, 648}, /* core_bi_px_to_mpm[5] */
+ {102, 649}, /* core_bi_px_gpio_127 */
+ {103, 650}, /* core_bi_px_gpio_128 */
+ {104, 651}, /* core_bi_px_gpio_129 */
+ {105, 652}, /* core_bi_px_gpio_130 */
+ {106, 653}, /* core_bi_px_gpio_132 */
+ {107, 654}, /* core_bi_px_gpio_133 */
+ {108, 655}, /* core_bi_px_gpio_145 */
+ {119, 666}, /* core_bi_px_to_mpm[2] */
+ {120, 667}, /* core_bi_px_to_mpm[3] */
+ {121, 668}, /* core_bi_px_to_mpm[4] */
+ {122, 669}, /* core_bi_px_gpio_41 */
+ {123, 670}, /* core_bi_px_gpio_89 */
+ {124, 671}, /* core_bi_px_gpio_31 */
+ {125, 672}, /* core_bi_px_gpio_49 */
+ {-1}
+};
+
+static int __init qcom_pdc_gic_init(struct device_node *node,
+ struct device_node *parent)
+{
+ return qcom_pdc_init(node, parent, sdm845_data);
+}
+
+IRQCHIP_DECLARE(pdc_sdm845, "qcom,pdc-sdm845", qcom_pdc_gic_init);
diff --git a/drivers/irqchip/qcom/pdc.c b/drivers/irqchip/qcom/pdc.c
new file mode 100644
index 0000000..923552f
--- /dev/null
+++ b/drivers/irqchip/qcom/pdc.c
@@ -0,0 +1,299 @@
+/* Copyright (c) 2017, 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/delay.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/irqchip.h>
+#include <linux/irqdomain.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include "pdc.h"
+#define CREATE_TRACE_POINTS
+#include "trace/events/pdc.h"
+
+#define MAX_IRQS 126
+#define CLEAR_INTR(reg, intr) (reg & ~(1 << intr))
+#define ENABLE_INTR(reg, intr) (reg | (1 << intr))
+
+enum pdc_register_offsets {
+ IRQ_ENABLE_BANK = 0x10,
+ IRQ_i_CFG = 0x110,
+};
+
+static DEFINE_SPINLOCK(pdc_lock);
+static void __iomem *pdc_base;
+
+static int get_pdc_pin(irq_hw_number_t hwirq, void *data)
+{
+ int i;
+ struct pdc_pin *pdc_data = (struct pdc_pin *) data;
+
+ for (i = 0; pdc_data[i].pin >= 0; i++) {
+ if (pdc_data[i].hwirq == hwirq)
+ return pdc_data[i].pin;
+ }
+
+ return -EINVAL;
+}
+
+static inline int pdc_enable_intr(struct irq_data *d, bool on)
+{
+ int pin_out = get_pdc_pin(d->hwirq, d->chip_data);
+ unsigned int index, mask;
+ u32 enable, r_enable;
+ unsigned long flags;
+
+ if (pin_out < 0)
+ return 0;
+
+ index = pin_out / 32;
+ mask = pin_out % 32;
+ spin_lock_irqsave(&pdc_lock, flags);
+
+ enable = readl_relaxed(pdc_base + IRQ_ENABLE_BANK + (index *
+ sizeof(uint32_t)));
+ if (on)
+ enable = ENABLE_INTR(enable, mask);
+ else
+ enable = CLEAR_INTR(enable, mask);
+
+ writel_relaxed(enable, pdc_base + IRQ_ENABLE_BANK + (index *
+ sizeof(uint32_t)));
+
+ do {
+ r_enable = readl_relaxed(pdc_base + IRQ_ENABLE_BANK +
+ (index * sizeof(uint32_t)));
+ if (r_enable == enable)
+ break;
+ udelay(5);
+ } while (1);
+
+ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ trace_irq_pin_config("enable", (u32)pin_out, (u32)d->hwirq,
+ 0, on);
+
+ return 0;
+}
+
+static void qcom_pdc_gic_mask(struct irq_data *d)
+{
+ pdc_enable_intr(d, false);
+ irq_chip_mask_parent(d);
+}
+
+static void qcom_pdc_gic_unmask(struct irq_data *d)
+{
+ pdc_enable_intr(d, true);
+ irq_chip_unmask_parent(d);
+}
+
+static void qcom_pdc_gic_enable(struct irq_data *d)
+{
+ pdc_enable_intr(d, true);
+ irq_chip_enable_parent(d);
+}
+
+static void qcom_pdc_gic_disable(struct irq_data *d)
+{
+ pdc_enable_intr(d, false);
+ irq_chip_disable_parent(d);
+}
+
+/*
+ * GIC does not handle falling edge or active low. To allow falling edge and
+ * active low interrupts to be handled at GIC, PDC has an inverter that inverts
+ * falling edge into a rising edge and active low into an active high.
+ * For the inverter to work, the polarity bit in the IRQ_CONFIG register has to
+ * set as per the table below.
+ * (polarity, falling edge, rising edge ) ORIG POL CONV POLARITY
+ * 3'b0 00 Level sensitive active low (~~~|_____) (___|~~~~~) LOW
+ * 3'b0 01 Rising edge sensitive (___|~~|__) (~~~|__|~~) NOT USED
+ * 3'b0 10 Falling edge sensitive (~~~|__|~~) (___|~~|__) LOW
+ * 3'b0 11 Dual Edge sensitive NOT USED
+ * 3'b1 00 Level senstive active High (___|~~~~~) (___|~~~~~) HIGH
+ * 3'b1 01 Falling Edge sensitive (~~~|__|~~) (~~~|__|~~) NOT USED
+ * 3'b1 10 Rising edge sensitive (___|~~|__) (___|~~|__) HIGH
+ * 3'b1 11 Dual Edge sensitive HIGH
+ */
+enum pdc_irq_config_bits {
+ POLARITY_LOW = 0, //0 00
+ FALLING_EDGE = 2, //0 10
+ POLARITY_HIGH = 4,//1 00
+ RISING_EDGE = 6, //1 10
+ DUAL_EDGE = 7, //1 11
+};
+
+static int qcom_pdc_gic_set_type(struct irq_data *d, unsigned int type)
+{
+ int pin_out = get_pdc_pin(d->hwirq, d->chip_data);
+ u32 pdc_type = 0, config;
+
+ if (pin_out < 0)
+ goto fwd_to_parent;
+
+ switch (type) {
+ case IRQ_TYPE_EDGE_RISING:
+ pdc_type = RISING_EDGE;
+ break;
+ case IRQ_TYPE_EDGE_FALLING:
+ pdc_type = FALLING_EDGE;
+ break;
+ case IRQ_TYPE_EDGE_BOTH:
+ pdc_type = DUAL_EDGE;
+ break;
+ case IRQ_TYPE_LEVEL_HIGH:
+ pdc_type = POLARITY_HIGH;
+ break;
+ case IRQ_TYPE_LEVEL_LOW:
+ pdc_type = POLARITY_LOW;
+ break;
+ default:
+ pdc_type = POLARITY_HIGH;
+ break;
+ }
+ writel_relaxed(pdc_type, pdc_base + IRQ_i_CFG +
+ (pin_out * sizeof(uint32_t)));
+
+ do {
+ config = readl_relaxed(pdc_base + IRQ_i_CFG +
+ (pin_out * sizeof(uint32_t)));
+ if (config == pdc_type)
+ break;
+ udelay(5);
+ } while (1);
+
+ trace_irq_pin_config("type_config", (u32)pin_out, (u32)d->hwirq,
+ pdc_type, 0);
+
+ /*
+ * If type is edge triggered, forward that as Rising edge as PDC
+ * takes care of converting falling edge to rising edge signal
+ */
+ if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
+ type = IRQ_TYPE_EDGE_RISING;
+
+ /*
+ * If type is level, then forward that as level high as PDC
+ * takes care of converting falling edge to rising edge signal
+ */
+ if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
+ type = IRQ_TYPE_LEVEL_HIGH;
+
+fwd_to_parent:
+
+ return irq_chip_set_type_parent(d, type);
+}
+
+static struct irq_chip qcom_pdc_gic_chip = {
+ .name = "PDC-GIC",
+ .irq_eoi = irq_chip_eoi_parent,
+ .irq_mask = qcom_pdc_gic_mask,
+ .irq_enable = qcom_pdc_gic_enable,
+ .irq_unmask = qcom_pdc_gic_unmask,
+ .irq_disable = qcom_pdc_gic_disable,
+ .irq_retrigger = irq_chip_retrigger_hierarchy,
+ .irq_set_type = qcom_pdc_gic_set_type,
+ .flags = IRQCHIP_MASK_ON_SUSPEND |
+ IRQCHIP_SET_TYPE_MASKED |
+ IRQCHIP_SKIP_SET_WAKE,
+ .irq_set_vcpu_affinity = irq_chip_set_vcpu_affinity_parent,
+#ifdef CONFIG_SMP
+ .irq_set_affinity = irq_chip_set_affinity_parent,
+#endif
+};
+
+static int qcom_pdc_translate(struct irq_domain *d,
+ struct irq_fwspec *fwspec, unsigned long *hwirq, unsigned int *type)
+{
+ return d->parent->ops->translate(d->parent, fwspec, hwirq, type);
+}
+
+static int qcom_pdc_alloc(struct irq_domain *domain,
+ unsigned int virq, unsigned int nr_irqs, void *data)
+{
+ struct irq_fwspec *fwspec = data;
+ struct irq_fwspec parent_fwspec;
+ irq_hw_number_t hwirq;
+ int i;
+ unsigned int type;
+ int ret;
+
+ ret = qcom_pdc_translate(domain, fwspec, &hwirq, &type);
+ if (ret)
+ return -EINVAL;
+
+ for (i = 0; i < nr_irqs; i++)
+ irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i,
+ &qcom_pdc_gic_chip, domain->host_data);
+
+ parent_fwspec = *fwspec;
+ parent_fwspec.fwnode = domain->parent->fwnode;
+
+ return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs,
+ &parent_fwspec);
+}
+
+static const struct irq_domain_ops qcom_pdc_ops = {
+ .translate = qcom_pdc_translate,
+ .alloc = qcom_pdc_alloc,
+ .free = irq_domain_free_irqs_common,
+};
+
+int qcom_pdc_init(struct device_node *node,
+ struct device_node *parent, void *data)
+{
+ struct irq_domain *parent_domain;
+ int ret;
+ struct irq_domain *pdc_domain;
+
+ pdc_base = of_iomap(node, 0);
+ if (!pdc_base) {
+ pr_err("%s(): unable to map PDC registers\n", node->full_name);
+ return -ENXIO;
+ }
+
+ parent_domain = irq_find_host(parent);
+ if (!parent_domain) {
+ pr_err("unable to obtain PDC parent domain\n");
+ ret = -ENXIO;
+ goto failure;
+ }
+
+ pdc_domain = irq_domain_add_hierarchy(parent_domain, 0, MAX_IRQS,
+ node, &qcom_pdc_ops, data);
+ if (!pdc_domain) {
+ pr_err("GIC domain add failed\n");
+ ret = -ENOMEM;
+ goto failure;
+ }
+
+ pdc_domain->name = "qcom,pdc";
+
+ return 0;
+
+failure:
+ iounmap(pdc_base);
+
+ return ret;
+}
+EXPORT_SYMBOL(qcom_pdc_init);
diff --git a/drivers/irqchip/qcom/pdc.h b/drivers/irqchip/qcom/pdc.h
new file mode 100644
index 0000000..7c4d89c
--- /dev/null
+++ b/drivers/irqchip/qcom/pdc.h
@@ -0,0 +1,23 @@
+/* Copyright (c) 2017, 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/irq.h>
+#include <linux/device.h>
+
+struct pdc_pin {
+ int pin;
+ irq_hw_number_t hwirq;
+};
+
+int qcom_pdc_init(struct device_node *node,
+ struct device_node *parent, void *data);
diff --git a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c
index 76dd1f3..5a4e6e9 100644
--- a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c
+++ b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c
@@ -59,15 +59,22 @@
}
if (!bubble_state) {
- CDBG("%s: Sync success: fd 0x%x\n", __func__,
+ CDBG("%s: Sync with success: fd 0x%x\n", __func__,
req_isp->fence_map_out[j].sync_id);
- cam_sync_signal(req_isp->fence_map_out[j].sync_id,
+ rc = cam_sync_signal(req_isp->fence_map_out[j].sync_id,
CAM_SYNC_STATE_SIGNALED_SUCCESS);
+ if (rc)
+ pr_err("%s: Sync failed with rc = %d\n",
+ __func__, rc);
+
} else if (!req_isp->bubble_report) {
- CDBG("%s: Sync failure: fd 0x%x\n", __func__,
+ CDBG("%s: Sync with failure: fd 0x%x\n", __func__,
req_isp->fence_map_out[j].sync_id);
- cam_sync_signal(req_isp->fence_map_out[j].sync_id,
+ rc = cam_sync_signal(req_isp->fence_map_out[j].sync_id,
CAM_SYNC_STATE_SIGNALED_ERROR);
+ if (rc)
+ pr_err("%s: Sync failed with rc = %d\n",
+ __func__, rc);
} else {
/*
* Ignore the buffer done if bubble detect is on
@@ -277,7 +284,7 @@
ctx_isp->frame_id++;
ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_SOF;
- pr_err("%s: next substate %d\n", __func__,
+ CDBG("%s: next substate %d\n", __func__,
ctx_isp->substate_activated);
return rc;
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c
index 259e773..49085d7 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c
@@ -1493,19 +1493,6 @@
if (i == ctx->num_base)
master_base_idx = ctx->base[0].idx;
- /* Stop the master CIDs first */
- cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_cid,
- master_base_idx, CAM_CSID_HALT_AT_FRAME_BOUNDARY);
-
- /* stop rest of the CIDs */
- for (i = 0; i < ctx->num_base; i++) {
- if (i == master_base_idx)
- continue;
- cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_cid,
- ctx->base[i].idx, CAM_CSID_HALT_AT_FRAME_BOUNDARY);
- }
-
-
/* Stop the master CSID path first */
cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_csid,
master_base_idx, CAM_CSID_HALT_AT_FRAME_BOUNDARY);
@@ -1519,6 +1506,18 @@
ctx->base[i].idx, CAM_CSID_HALT_AT_FRAME_BOUNDARY);
}
+ /* Stop the master CIDs first */
+ cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_cid,
+ master_base_idx, CAM_CSID_HALT_AT_FRAME_BOUNDARY);
+
+ /* stop rest of the CIDs */
+ for (i = 0; i < ctx->num_base; i++) {
+ if (i == master_base_idx)
+ continue;
+ cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_cid,
+ ctx->base[i].idx, CAM_CSID_HALT_AT_FRAME_BOUNDARY);
+ }
+
if (cam_cdm_stream_off(ctx->cdm_handle))
pr_err("%s%d: CDM stream off failed %d\n",
__func__, __LINE__, ctx->cdm_handle);
@@ -2884,7 +2883,7 @@
int i, j;
struct cam_iommu_handle cdm_handles;
- pr_info("%s: Enter\n", __func__);
+ CDBG("%s: Enter\n", __func__);
memset(&g_ife_hw_mgr, 0, sizeof(g_ife_hw_mgr));
@@ -3037,7 +3036,7 @@
hw_mgr_intf->hw_prepare_update = cam_ife_mgr_prepare_hw_update;
hw_mgr_intf->hw_config = cam_ife_mgr_config_hw;
- pr_info("%s: Exit\n", __func__);
+ CDBG("%s: Exit\n", __func__);
return 0;
end:
if (rc) {
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c
index 6306df3..3ec9aa6 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c
@@ -1133,7 +1133,7 @@
if (rc)
return rc;
- /**
+ /*
* configure the IPP and enable the time stamp capture.
* enable the HW measrurement blocks
*/
@@ -1417,7 +1417,7 @@
if (rc)
return rc;
- /**
+ /*
* RDI path config and enable the time stamp capture
* Enable the measurement blocks
*/
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_base.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_base.c
index 34243e6..15b8a2d 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_base.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_base.c
@@ -227,9 +227,10 @@
{
struct sde_rot_data_type *mdata = sde_rot_get_mdata();
u32 ot_lim;
- u32 reg_off_vbif_lim_conf = (params->xin_id / 4) * 4 +
- params->reg_off_vbif_lim_conf;
- u32 bit_off_vbif_lim_conf = (params->xin_id % 4) * 8;
+ u32 reg_off_vbif_lim_conf = ((params->xin_id / mdata->npriority_lvl)
+ * mdata->npriority_lvl)
+ + params->reg_off_vbif_lim_conf;
+ u32 bit_off_vbif_lim_conf = (params->xin_id % mdata->npriority_lvl) * 8;
u32 reg_val;
u32 sts;
bool forced_on;
@@ -420,6 +421,136 @@
}
}
+static void sde_mdp_parse_cdp_setting(struct platform_device *pdev,
+ struct sde_rot_data_type *mdata)
+{
+ int rc;
+ u32 len, data[SDE_ROT_OP_MAX] = {0};
+
+ len = sde_mdp_parse_dt_prop_len(pdev,
+ "qcom,mdss-rot-cdp-setting");
+ if (len == SDE_ROT_OP_MAX) {
+ rc = sde_mdp_parse_dt_handler(pdev,
+ "qcom,mdss-rot-cdp-setting", data, len);
+ if (rc) {
+ SDEROT_ERR("invalid CDP setting\n");
+ goto end;
+ }
+
+ set_bit(SDE_QOS_CDP, mdata->sde_qos_map);
+ mdata->enable_cdp[SDE_ROT_RD] = data[SDE_ROT_RD];
+ mdata->enable_cdp[SDE_ROT_WR] = data[SDE_ROT_WR];
+ return;
+ }
+end:
+ clear_bit(SDE_QOS_CDP, mdata->sde_qos_map);
+}
+
+static void sde_mdp_parse_rot_lut_setting(struct platform_device *pdev,
+ struct sde_rot_data_type *mdata)
+{
+ int rc;
+ u32 len, data[4];
+
+ len = sde_mdp_parse_dt_prop_len(pdev, "qcom,mdss-rot-qos-lut");
+ if (len == 4) {
+ rc = sde_mdp_parse_dt_handler(pdev,
+ "qcom,mdss-rot-qos-lut", data, len);
+ if (!rc) {
+ mdata->lut_cfg[SDE_ROT_RD].creq_lut_0 = data[0];
+ mdata->lut_cfg[SDE_ROT_RD].creq_lut_1 = data[1];
+ mdata->lut_cfg[SDE_ROT_WR].creq_lut_0 = data[2];
+ mdata->lut_cfg[SDE_ROT_WR].creq_lut_1 = data[3];
+ set_bit(SDE_QOS_LUT, mdata->sde_qos_map);
+ } else {
+ SDEROT_DBG("qos lut setting not found\n");
+ }
+ }
+
+ len = sde_mdp_parse_dt_prop_len(pdev, "qcom,mdss-rot-danger-lut");
+ if (len == SDE_ROT_OP_MAX) {
+ rc = sde_mdp_parse_dt_handler(pdev,
+ "qcom,mdss-rot-danger-lut", data, len);
+ if (!rc) {
+ mdata->lut_cfg[SDE_ROT_RD].danger_lut
+ = data[SDE_ROT_RD];
+ mdata->lut_cfg[SDE_ROT_WR].danger_lut
+ = data[SDE_ROT_WR];
+ set_bit(SDE_QOS_DANGER_LUT, mdata->sde_qos_map);
+ } else {
+ SDEROT_DBG("danger lut setting not found\n");
+ }
+ }
+
+ len = sde_mdp_parse_dt_prop_len(pdev, "qcom,mdss-rot-safe-lut");
+ if (len == SDE_ROT_OP_MAX) {
+ rc = sde_mdp_parse_dt_handler(pdev,
+ "qcom,mdss-rot-safe-lut", data, len);
+ if (!rc) {
+ mdata->lut_cfg[SDE_ROT_RD].safe_lut = data[SDE_ROT_RD];
+ mdata->lut_cfg[SDE_ROT_WR].safe_lut = data[SDE_ROT_WR];
+ set_bit(SDE_QOS_SAFE_LUT, mdata->sde_qos_map);
+ } else {
+ SDEROT_DBG("safe lut setting not found\n");
+ }
+ }
+}
+
+static void sde_mdp_parse_inline_rot_lut_setting(struct platform_device *pdev,
+ struct sde_rot_data_type *mdata)
+{
+ int rc;
+ u32 len, data[4];
+
+ len = sde_mdp_parse_dt_prop_len(pdev, "qcom,mdss-inline-rot-qos-lut");
+ if (len == 4) {
+ rc = sde_mdp_parse_dt_handler(pdev,
+ "qcom,mdss-inline-rot-qos-lut", data, len);
+ if (!rc) {
+ mdata->inline_lut_cfg[SDE_ROT_RD].creq_lut_0 = data[0];
+ mdata->inline_lut_cfg[SDE_ROT_RD].creq_lut_1 = data[1];
+ mdata->inline_lut_cfg[SDE_ROT_WR].creq_lut_0 = data[2];
+ mdata->inline_lut_cfg[SDE_ROT_WR].creq_lut_1 = data[3];
+ set_bit(SDE_INLINE_QOS_LUT, mdata->sde_inline_qos_map);
+ } else {
+ SDEROT_DBG("inline qos lut setting not found\n");
+ }
+ }
+
+ len = sde_mdp_parse_dt_prop_len(pdev,
+ "qcom,mdss-inline-rot-danger-lut");
+ if (len == SDE_ROT_OP_MAX) {
+ rc = sde_mdp_parse_dt_handler(pdev,
+ "qcom,mdss-inline-rot-danger-lut", data, len);
+ if (!rc) {
+ mdata->inline_lut_cfg[SDE_ROT_RD].danger_lut
+ = data[SDE_ROT_RD];
+ mdata->inline_lut_cfg[SDE_ROT_WR].danger_lut
+ = data[SDE_ROT_WR];
+ set_bit(SDE_INLINE_QOS_DANGER_LUT,
+ mdata->sde_inline_qos_map);
+ } else {
+ SDEROT_DBG("inline danger lut setting not found\n");
+ }
+ }
+
+ len = sde_mdp_parse_dt_prop_len(pdev, "qcom,mdss-inline-rot-safe-lut");
+ if (len == SDE_ROT_OP_MAX) {
+ rc = sde_mdp_parse_dt_handler(pdev,
+ "qcom,mdss-inline-rot-safe-lut", data, len);
+ if (!rc) {
+ mdata->inline_lut_cfg[SDE_ROT_RD].safe_lut
+ = data[SDE_ROT_RD];
+ mdata->inline_lut_cfg[SDE_ROT_WR].safe_lut
+ = data[SDE_ROT_WR];
+ set_bit(SDE_INLINE_QOS_SAFE_LUT,
+ mdata->sde_inline_qos_map);
+ } else {
+ SDEROT_DBG("inline safe lut setting not found\n");
+ }
+ }
+}
+
static int sde_mdp_parse_dt_misc(struct platform_device *pdev,
struct sde_rot_data_type *mdata)
{
@@ -444,8 +575,14 @@
SDEROT_DBG(
"Could not read optional property: highest bank bit\n");
+ sde_mdp_parse_cdp_setting(pdev, mdata);
+
sde_mdp_parse_vbif_qos(pdev, mdata);
+ sde_mdp_parse_rot_lut_setting(pdev, mdata);
+
+ sde_mdp_parse_inline_rot_lut_setting(pdev, mdata);
+
mdata->mdp_base = mdata->sde_io.base + SDE_MDP_OFFSET;
return 0;
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_base.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_base.h
index 9194b44..ee2561f 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_base.h
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_base.h
@@ -40,6 +40,9 @@
#define SDE_MDP_HW_REV_301 SDE_MDP_REV(3, 0, 1) /* 8998 v1.1 */
#define SDE_MDP_HW_REV_400 SDE_MDP_REV(4, 0, 0) /* sdm845 v1.0 */
+#define SDE_MDP_VBIF_4_LEVEL_REMAPPER 4
+#define SDE_MDP_VBIF_8_LEVEL_REMAPPER 8
+
struct sde_mult_factor {
uint32_t numer;
uint32_t denom;
@@ -77,9 +80,19 @@
SDE_QOS_PER_PIPE_LUT,
SDE_QOS_SIMPLIFIED_PREFILL,
SDE_QOS_VBLANK_PANIC_CTRL,
+ SDE_QOS_LUT,
+ SDE_QOS_DANGER_LUT,
+ SDE_QOS_SAFE_LUT,
SDE_QOS_MAX,
};
+enum sde_inline_qos_settings {
+ SDE_INLINE_QOS_LUT,
+ SDE_INLINE_QOS_DANGER_LUT,
+ SDE_INLINE_QOS_SAFE_LUT,
+ SDE_INLINE_QOS_MAX,
+};
+
/**
* enum sde_rot_type: SDE rotator HW version
* @SDE_ROT_TYPE_V1_0: V1.0 HW version
@@ -115,6 +128,12 @@
SDE_MAX_BUS_CLIENTS
};
+enum sde_rot_op {
+ SDE_ROT_RD,
+ SDE_ROT_WR,
+ SDE_ROT_OP_MAX
+};
+
enum sde_rot_regdump_access {
SDE_ROT_REGDUMP_READ,
SDE_ROT_REGDUMP_WRITE,
@@ -165,6 +184,13 @@
enum sde_rot_regdump_access access;
};
+struct sde_rot_lut_cfg {
+ u32 creq_lut_0;
+ u32 creq_lut_1;
+ u32 danger_lut;
+ u32 safe_lut;
+};
+
struct sde_rot_data_type {
u32 mdss_version;
@@ -177,6 +203,7 @@
/* bitmap to track qos applicable settings */
DECLARE_BITMAP(sde_qos_map, SDE_QOS_MAX);
+ DECLARE_BITMAP(sde_inline_qos_map, SDE_QOS_MAX);
/* bitmap to track capability settings */
DECLARE_BITMAP(sde_caps_map, SDE_CAPS_MAX);
@@ -210,6 +237,11 @@
void *sde_rot_hw;
int sec_cam_en;
+ u32 enable_cdp[SDE_ROT_OP_MAX];
+
+ struct sde_rot_lut_cfg lut_cfg[SDE_ROT_OP_MAX];
+ struct sde_rot_lut_cfg inline_lut_cfg[SDE_ROT_OP_MAX];
+
struct ion_client *iclient;
bool clk_always_on;
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_hwio.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_hwio.h
index 051db78..de448a4 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_hwio.h
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_hwio.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -65,6 +65,8 @@
#define MMSS_VBIF_NRT_VBIF_IN_WR_LIM_CONF2 0x00C8
#define MMSS_VBIF_NRT_VBIF_OUT_RD_LIM_CONF0 0x00D0
#define MMSS_VBIF_NRT_VBIF_OUT_WR_LIM_CONF0 0x00D4
+#define MMSS_VBIF_NRT_VBIF_QOS_RP_REMAP_000 0x0550
+#define MMSS_VBIF_NRT_VBIF_QOS_LVL_REMAP_000 0x0590
#define SDE_MDP_REG_TRAFFIC_SHAPER_EN BIT(31)
#define SDE_MDP_REG_TRAFFIC_SHAPER_RD_CLIENT(num) (0x030 + (num * 4))
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
index 980df9f..56cdaa3 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
@@ -493,6 +493,12 @@
SDE_ROT_REGDUMP_VBIF },
};
+struct sde_rot_cdp_params {
+ bool enable;
+ struct sde_mdp_format_params *fmt;
+ u32 offset;
+};
+
/* Invalid software timestamp value for initialization */
#define SDE_REGDMA_SWTS_INVALID (~0)
@@ -741,6 +747,76 @@
}
/*
+ * sde_hw_rotator_vbif_setting - helper function to set vbif QoS remapper
+ * levels, enable write gather enable and avoid clk gating setting for
+ * debug purpose.
+ *
+ * @rot: Pointer to rotator hw
+ */
+static void sde_hw_rotator_vbif_setting(struct sde_hw_rotator *rot)
+{
+ u32 i, mask, vbif_qos, reg_val = 0;
+ struct sde_rot_data_type *mdata = sde_rot_get_mdata();
+
+ /* VBIF_ROT QoS remapper setting */
+ switch (mdata->npriority_lvl) {
+
+ case SDE_MDP_VBIF_4_LEVEL_REMAPPER:
+ for (i = 0; i < mdata->npriority_lvl; i++) {
+ reg_val = SDE_VBIF_READ(mdata,
+ MMSS_VBIF_NRT_VBIF_QOS_REMAP_00 + i*4);
+ mask = 0x3 << (XIN_SSPP * 2);
+ vbif_qos = mdata->vbif_nrt_qos[i];
+ reg_val |= vbif_qos << (XIN_SSPP * 2);
+ /* ensure write is issued after the read operation */
+ mb();
+ SDE_VBIF_WRITE(mdata,
+ MMSS_VBIF_NRT_VBIF_QOS_REMAP_00 + i*4,
+ reg_val);
+ }
+ break;
+
+ case SDE_MDP_VBIF_8_LEVEL_REMAPPER:
+ mask = mdata->npriority_lvl - 1;
+ for (i = 0; i < mdata->npriority_lvl; i++) {
+ /* RD and WR client */
+ reg_val |= (mdata->vbif_nrt_qos[i] & mask)
+ << (XIN_SSPP * 4);
+ reg_val |= (mdata->vbif_nrt_qos[i] & mask)
+ << (XIN_WRITEBACK * 4);
+
+ SDE_VBIF_WRITE(mdata,
+ MMSS_VBIF_NRT_VBIF_QOS_RP_REMAP_000 + i*8,
+ reg_val);
+ SDE_VBIF_WRITE(mdata,
+ MMSS_VBIF_NRT_VBIF_QOS_LVL_REMAP_000 + i*8,
+ reg_val);
+ }
+ break;
+
+ default:
+ SDEROT_DBG("invalid vbif remapper levels\n");
+ }
+
+ /* Enable write gather for writeback to remove write gaps, which
+ * may hang AXI/BIMC/SDE.
+ */
+ SDE_VBIF_WRITE(mdata, MMSS_VBIF_NRT_VBIF_WRITE_GATHTER_EN,
+ BIT(XIN_WRITEBACK));
+
+ /*
+ * For debug purpose, disable clock gating, i.e. Clocks always on
+ */
+ if (mdata->clk_always_on) {
+ SDE_VBIF_WRITE(mdata, MMSS_VBIF_CLKON, 0x3);
+ SDE_VBIF_WRITE(mdata, MMSS_VBIF_NRT_VBIF_CLK_FORCE_CTRL0, 0x3);
+ SDE_VBIF_WRITE(mdata, MMSS_VBIF_NRT_VBIF_CLK_FORCE_CTRL1,
+ 0xFFFF);
+ SDE_ROTREG_WRITE(rot->mdss_base, ROTTOP_CLK_CTRL, 1);
+ }
+}
+
+/*
* sde_hw_rotator_setup_timestamp_packet - setup timestamp writeback command
* @ctx: Pointer to rotator context
* @mask: Bit mask location of the timestamp
@@ -796,6 +872,156 @@
}
/*
+ * sde_hw_rotator_cdp_configs - configures the CDP registers
+ * @ctx: Pointer to rotator context
+ * @params: Pointer to parameters needed for CDP configs
+ */
+static void sde_hw_rotator_cdp_configs(struct sde_hw_rotator_context *ctx,
+ struct sde_rot_cdp_params *params)
+{
+ int reg_val;
+ u32 *wrptr = sde_hw_rotator_get_regdma_segment(ctx);
+
+ if (!params->enable) {
+ SDE_REGDMA_WRITE(wrptr, params->offset, 0x0);
+ goto end;
+ }
+
+ reg_val = BIT(0); /* enable cdp */
+
+ if (sde_mdp_is_ubwc_format(params->fmt))
+ reg_val |= BIT(1); /* enable UBWC meta cdp */
+
+ if (sde_mdp_is_ubwc_format(params->fmt)
+ || sde_mdp_is_tilea4x_format(params->fmt)
+ || sde_mdp_is_tilea5x_format(params->fmt))
+ reg_val |= BIT(2); /* enable tile amortize */
+
+ reg_val |= BIT(3); /* enable preload addr ahead cnt 64 */
+
+ SDE_REGDMA_WRITE(wrptr, params->offset, reg_val);
+
+end:
+ sde_hw_rotator_put_regdma_segment(ctx, wrptr);
+}
+
+/*
+ * sde_hw_rotator_setup_qos_lut_wr - Set QoS LUT/Danger LUT/Safe LUT configs
+ * for the WRITEBACK rotator for inline and offline rotation.
+ *
+ * @ctx: Pointer to rotator context
+ */
+static void sde_hw_rotator_setup_qos_lut_wr(struct sde_hw_rotator_context *ctx)
+{
+ struct sde_rot_data_type *mdata = sde_rot_get_mdata();
+ u32 *wrptr = sde_hw_rotator_get_regdma_segment(ctx);
+
+ /* Offline rotation setting */
+ if (!ctx->sbuf_mode) {
+ /* QOS LUT WR setting */
+ if (test_bit(SDE_QOS_LUT, mdata->sde_qos_map)) {
+ SDE_REGDMA_WRITE(wrptr, ROT_WB_CREQ_LUT_0,
+ mdata->lut_cfg[SDE_ROT_WR].creq_lut_0);
+ SDE_REGDMA_WRITE(wrptr, ROT_WB_CREQ_LUT_1,
+ mdata->lut_cfg[SDE_ROT_WR].creq_lut_1);
+ }
+
+ /* Danger LUT WR setting */
+ if (test_bit(SDE_QOS_DANGER_LUT, mdata->sde_qos_map))
+ SDE_REGDMA_WRITE(wrptr, ROT_WB_DANGER_LUT,
+ mdata->lut_cfg[SDE_ROT_WR].danger_lut);
+
+ /* Safe LUT WR setting */
+ if (test_bit(SDE_QOS_SAFE_LUT, mdata->sde_qos_map))
+ SDE_REGDMA_WRITE(wrptr, ROT_WB_SAFE_LUT,
+ mdata->lut_cfg[SDE_ROT_WR].safe_lut);
+
+ /* Inline rotation setting */
+ } else {
+ /* QOS LUT WR setting */
+ if (test_bit(SDE_INLINE_QOS_LUT, mdata->sde_inline_qos_map)) {
+ SDE_REGDMA_WRITE(wrptr, ROT_WB_CREQ_LUT_0,
+ mdata->inline_lut_cfg[SDE_ROT_WR].creq_lut_0);
+ SDE_REGDMA_WRITE(wrptr, ROT_WB_CREQ_LUT_1,
+ mdata->inline_lut_cfg[SDE_ROT_WR].creq_lut_1);
+ }
+
+ /* Danger LUT WR setting */
+ if (test_bit(SDE_INLINE_QOS_DANGER_LUT,
+ mdata->sde_inline_qos_map))
+ SDE_REGDMA_WRITE(wrptr, ROT_WB_DANGER_LUT,
+ mdata->inline_lut_cfg[SDE_ROT_WR].danger_lut);
+
+ /* Safe LUT WR setting */
+ if (test_bit(SDE_INLINE_QOS_SAFE_LUT,
+ mdata->sde_inline_qos_map))
+ SDE_REGDMA_WRITE(wrptr, ROT_WB_SAFE_LUT,
+ mdata->inline_lut_cfg[SDE_ROT_WR].safe_lut);
+ }
+
+ /* Update command queue write ptr */
+ sde_hw_rotator_put_regdma_segment(ctx, wrptr);
+}
+
+/*
+ * sde_hw_rotator_setup_qos_lut_rd - Set QoS LUT/Danger LUT/Safe LUT configs
+ * for the SSPP rotator for inline and offline rotation.
+ *
+ * @ctx: Pointer to rotator context
+ */
+static void sde_hw_rotator_setup_qos_lut_rd(struct sde_hw_rotator_context *ctx)
+{
+ struct sde_rot_data_type *mdata = sde_rot_get_mdata();
+ u32 *wrptr = sde_hw_rotator_get_regdma_segment(ctx);
+
+ /* Offline rotation setting */
+ if (!ctx->sbuf_mode) {
+ /* QOS LUT RD setting */
+ if (test_bit(SDE_QOS_LUT, mdata->sde_qos_map)) {
+ SDE_REGDMA_WRITE(wrptr, ROT_SSPP_CREQ_LUT_0,
+ mdata->lut_cfg[SDE_ROT_RD].creq_lut_0);
+ SDE_REGDMA_WRITE(wrptr, ROT_SSPP_CREQ_LUT_1,
+ mdata->lut_cfg[SDE_ROT_RD].creq_lut_1);
+ }
+
+ /* Danger LUT RD setting */
+ if (test_bit(SDE_QOS_DANGER_LUT, mdata->sde_qos_map))
+ SDE_REGDMA_WRITE(wrptr, ROT_SSPP_DANGER_LUT,
+ mdata->lut_cfg[SDE_ROT_RD].danger_lut);
+
+ /* Safe LUT RD setting */
+ if (test_bit(SDE_QOS_SAFE_LUT, mdata->sde_qos_map))
+ SDE_REGDMA_WRITE(wrptr, ROT_SSPP_SAFE_LUT,
+ mdata->lut_cfg[SDE_ROT_RD].safe_lut);
+
+ /* inline rotation setting */
+ } else {
+ /* QOS LUT RD setting */
+ if (test_bit(SDE_INLINE_QOS_LUT, mdata->sde_inline_qos_map)) {
+ SDE_REGDMA_WRITE(wrptr, ROT_SSPP_CREQ_LUT_0,
+ mdata->inline_lut_cfg[SDE_ROT_RD].creq_lut_0);
+ SDE_REGDMA_WRITE(wrptr, ROT_SSPP_CREQ_LUT_1,
+ mdata->inline_lut_cfg[SDE_ROT_RD].creq_lut_1);
+ }
+
+ /* Danger LUT RD setting */
+ if (test_bit(SDE_INLINE_QOS_DANGER_LUT,
+ mdata->sde_inline_qos_map))
+ SDE_REGDMA_WRITE(wrptr, ROT_SSPP_DANGER_LUT,
+ mdata->inline_lut_cfg[SDE_ROT_RD].danger_lut);
+
+ /* Safe LUT RD setting */
+ if (test_bit(SDE_INLINE_QOS_SAFE_LUT,
+ mdata->sde_inline_qos_map))
+ SDE_REGDMA_WRITE(wrptr, ROT_SSPP_SAFE_LUT,
+ mdata->inline_lut_cfg[SDE_ROT_RD].safe_lut);
+ }
+
+ /* Update command queue write ptr */
+ sde_hw_rotator_put_regdma_segment(ctx, wrptr);
+}
+
+/*
* sde_hw_rotator_setup_fetchengine - setup fetch engine
* @ctx: Pointer to rotator context
* @queue_id: Priority queue identifier
@@ -814,6 +1040,7 @@
struct sde_hw_rotator *rot = ctx->rot;
struct sde_mdp_format_params *fmt;
struct sde_mdp_data *data;
+ struct sde_rot_cdp_params cdp_params = {0};
struct sde_rot_data_type *mdata = sde_rot_get_mdata();
u32 *wrptr;
u32 opmode = 0;
@@ -985,13 +1212,29 @@
ctx->is_secure = false;
}
+ /* Update command queue write ptr */
+ sde_hw_rotator_put_regdma_segment(ctx, wrptr);
+
+ /* CDP register RD setting */
+ cdp_params.enable = test_bit(SDE_QOS_CDP, mdata->sde_qos_map) ?
+ mdata->enable_cdp[SDE_ROT_RD] : false;
+ cdp_params.fmt = fmt;
+ cdp_params.offset = ROT_SSPP_CDP_CNTL;
+ sde_hw_rotator_cdp_configs(ctx, &cdp_params);
+
+ /* QOS LUT/ Danger LUT/ Safe Lut WR setting */
+ sde_hw_rotator_setup_qos_lut_rd(ctx);
+
+ wrptr = sde_hw_rotator_get_regdma_segment(ctx);
+
/*
* Determine if traffic shaping is required. Only enable traffic
* shaping when content is 4k@30fps. The actual traffic shaping
* bandwidth calculation is done in output setup.
*/
- if (((cfg->src_rect->w * cfg->src_rect->h) >= RES_UHD) &&
- (cfg->fps <= 30)) {
+ if (((!ctx->sbuf_mode)
+ && (cfg->src_rect->w * cfg->src_rect->h) >= RES_UHD)
+ && (cfg->fps <= 30)) {
SDEROT_DBG("Enable Traffic Shaper\n");
ctx->is_traffic_shaping = true;
} else {
@@ -1017,6 +1260,7 @@
{
struct sde_rot_data_type *mdata = sde_rot_get_mdata();
struct sde_mdp_format_params *fmt;
+ struct sde_rot_cdp_params cdp_params = {0};
u32 *wrptr;
u32 pack = 0;
u32 dst_format = 0;
@@ -1120,8 +1364,23 @@
SDE_REGDMA_WRITE(wrptr, ROTTOP_OP_MODE, ctx->op_mode |
(flags & SDE_ROT_FLAG_ROT_90 ? BIT(1) : 0) | BIT(0));
+ sde_hw_rotator_put_regdma_segment(ctx, wrptr);
+
+ /* CDP register WR setting */
+ cdp_params.enable = test_bit(SDE_QOS_CDP, mdata->sde_qos_map) ?
+ mdata->enable_cdp[SDE_ROT_WR] : false;
+ cdp_params.fmt = fmt;
+ cdp_params.offset = ROT_WB_CDP_CNTL;
+ sde_hw_rotator_cdp_configs(ctx, &cdp_params);
+
+ /* QOS LUT/ Danger LUT/ Safe LUT WR setting */
+ sde_hw_rotator_setup_qos_lut_wr(ctx);
+
+ wrptr = sde_hw_rotator_get_regdma_segment(ctx);
+
/* setup traffic shaper for 4k 30fps content or if prefill_bw is set */
- if (ctx->is_traffic_shaping || cfg->prefill_bw) {
+ if (!ctx->sbuf_mode &&
+ (ctx->is_traffic_shaping || cfg->prefill_bw)) {
u32 bw;
/*
@@ -2136,7 +2395,7 @@
item->input.format, item->output.format,
entry->perf->config.frame_rate);
- if (mdata->default_ot_rd_limit) {
+ if (!ctx->sbuf_mode && mdata->default_ot_rd_limit) {
struct sde_mdp_set_ot_params ot_params;
memset(&ot_params, 0, sizeof(struct sde_mdp_set_ot_params));
@@ -2158,7 +2417,7 @@
sde_mdp_set_ot_limit(&ot_params);
}
- if (mdata->default_ot_wr_limit) {
+ if (!ctx->sbuf_mode && mdata->default_ot_wr_limit) {
struct sde_mdp_set_ot_params ot_params;
memset(&ot_params, 0, sizeof(struct sde_mdp_set_ot_params));
@@ -2189,46 +2448,9 @@
SDE_ROTREG_WRITE(rot->mdss_base, ROT_SSPP_CREQ_LUT, qos_lut);
}
- /* Set CDP control registers to 0 if CDP is disabled */
- if (!test_bit(SDE_QOS_CDP, mdata->sde_qos_map)) {
- SDE_ROTREG_WRITE(rot->mdss_base, ROT_SSPP_CDP_CNTL, 0x0);
- SDE_ROTREG_WRITE(rot->mdss_base, ROT_WB_CDP_CNTL, 0x0);
- }
-
- if (mdata->npriority_lvl > 0) {
- u32 mask, reg_val, i, vbif_qos;
-
- for (i = 0; i < mdata->npriority_lvl; i++) {
- reg_val = SDE_VBIF_READ(mdata,
- MMSS_VBIF_NRT_VBIF_QOS_REMAP_00 + i*4);
- mask = 0x3 << (XIN_SSPP * 2);
- reg_val &= ~(mask);
- vbif_qos = mdata->vbif_nrt_qos[i];
- reg_val |= vbif_qos << (XIN_SSPP * 2);
- /* ensure write is issued after the read operation */
- mb();
- SDE_VBIF_WRITE(mdata,
- MMSS_VBIF_NRT_VBIF_QOS_REMAP_00 + i*4,
- reg_val);
- }
- }
-
- /* Enable write gather for writeback to remove write gaps, which
- * may hang AXI/BIMC/SDE.
- */
- SDE_VBIF_WRITE(mdata, MMSS_VBIF_NRT_VBIF_WRITE_GATHTER_EN,
- BIT(XIN_WRITEBACK));
-
- /*
- * For debug purpose, disable clock gating, i.e. Clocks always on
- */
- if (mdata->clk_always_on) {
- SDE_VBIF_WRITE(mdata, MMSS_VBIF_CLKON, 0x3);
- SDE_VBIF_WRITE(mdata, MMSS_VBIF_NRT_VBIF_CLK_FORCE_CTRL0, 0x3);
- SDE_VBIF_WRITE(mdata, MMSS_VBIF_NRT_VBIF_CLK_FORCE_CTRL1,
- 0xFFFF);
- SDE_ROTREG_WRITE(rot->mdss_base, ROTTOP_CLK_CTRL, 1);
- }
+ /* VBIF QoS and other settings */
+ if (!ctx->sbuf_mode)
+ sde_hw_rotator_vbif_setting(rot);
return 0;
@@ -2337,7 +2559,6 @@
clear_bit(SDE_QOS_PER_PIPE_IB, mdata->sde_qos_map);
set_bit(SDE_QOS_OVERHEAD_FACTOR, mdata->sde_qos_map);
- clear_bit(SDE_QOS_CDP, mdata->sde_qos_map);
set_bit(SDE_QOS_OTLIM, mdata->sde_qos_map);
set_bit(SDE_QOS_PER_PIPE_LUT, mdata->sde_qos_map);
clear_bit(SDE_QOS_SIMPLIFIED_PREFILL, mdata->sde_qos_map);
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_hwio.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_hwio.h
index aa762dd..d2b81d5 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_hwio.h
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_hwio.h
@@ -81,6 +81,8 @@
#define ROT_SSPP_CREQ_LUT (SDE_ROT_SSPP_OFFSET+0x68)
#define ROT_SSPP_QOS_CTRL (SDE_ROT_SSPP_OFFSET+0x6C)
#define ROT_SSPP_SRC_ADDR_SW_STATUS (SDE_ROT_SSPP_OFFSET+0x70)
+#define ROT_SSPP_CREQ_LUT_0 (SDE_ROT_SSPP_OFFSET+0x74)
+#define ROT_SSPP_CREQ_LUT_1 (SDE_ROT_SSPP_OFFSET+0x78)
#define ROT_SSPP_CURRENT_SRC0_ADDR (SDE_ROT_SSPP_OFFSET+0xA4)
#define ROT_SSPP_CURRENT_SRC1_ADDR (SDE_ROT_SSPP_OFFSET+0xA8)
#define ROT_SSPP_CURRENT_SRC2_ADDR (SDE_ROT_SSPP_OFFSET+0xAC)
@@ -167,6 +169,8 @@
#define ROT_WB_CREQ_LUT (SDE_ROT_WB_OFFSET+0x08C)
#define ROT_WB_QOS_CTRL (SDE_ROT_WB_OFFSET+0x090)
#define ROT_WB_SYS_CACHE_MODE (SDE_ROT_WB_OFFSET+0x094)
+#define ROT_WB_CREQ_LUT_0 (SDE_ROT_WB_OFFSET+0x098)
+#define ROT_WB_CREQ_LUT_1 (SDE_ROT_WB_OFFSET+0x09C)
#define ROT_WB_UBWC_STATIC_CTRL (SDE_ROT_WB_OFFSET+0x144)
#define ROT_WB_SBUF_STATUS_PLANE0 (SDE_ROT_WB_OFFSET+0x148)
#define ROT_WB_SBUF_STATUS_PLANE1 (SDE_ROT_WB_OFFSET+0x14C)
diff --git a/drivers/media/platform/msm/vidc/hfi_packetization.c b/drivers/media/platform/msm/vidc/hfi_packetization.c
index a477340..5970236 100644
--- a/drivers/media/platform/msm/vidc/hfi_packetization.c
+++ b/drivers/media/platform/msm/vidc/hfi_packetization.c
@@ -515,13 +515,13 @@
buffer = HFI_BUFFER_EXTRADATA_OUTPUT2;
break;
case HAL_BUFFER_INTERNAL_SCRATCH:
- buffer = HFI_BUFFER_INTERNAL_SCRATCH;
+ buffer = HFI_BUFFER_COMMON_INTERNAL_SCRATCH;
break;
case HAL_BUFFER_INTERNAL_SCRATCH_1:
- buffer = HFI_BUFFER_INTERNAL_SCRATCH_1;
+ buffer = HFI_BUFFER_COMMON_INTERNAL_SCRATCH_1;
break;
case HAL_BUFFER_INTERNAL_SCRATCH_2:
- buffer = HFI_BUFFER_INTERNAL_SCRATCH_2;
+ buffer = HFI_BUFFER_COMMON_INTERNAL_SCRATCH_2;
break;
case HAL_BUFFER_INTERNAL_PERSIST:
buffer = HFI_BUFFER_INTERNAL_PERSIST;
diff --git a/drivers/media/platform/msm/vidc/hfi_response_handler.c b/drivers/media/platform/msm/vidc/hfi_response_handler.c
index b424fbb..89e8356 100644
--- a/drivers/media/platform/msm/vidc/hfi_response_handler.c
+++ b/drivers/media/platform/msm/vidc/hfi_response_handler.c
@@ -1082,19 +1082,19 @@
buffreq->buffer[5].buffer_type =
HAL_BUFFER_EXTRADATA_OUTPUT2;
break;
- case HFI_BUFFER_INTERNAL_SCRATCH:
+ case HFI_BUFFER_COMMON_INTERNAL_SCRATCH:
memcpy(&buffreq->buffer[6], hfi_buf_req,
sizeof(struct hfi_buffer_requirements));
buffreq->buffer[6].buffer_type =
HAL_BUFFER_INTERNAL_SCRATCH;
break;
- case HFI_BUFFER_INTERNAL_SCRATCH_1:
+ case HFI_BUFFER_COMMON_INTERNAL_SCRATCH_1:
memcpy(&buffreq->buffer[7], hfi_buf_req,
sizeof(struct hfi_buffer_requirements));
buffreq->buffer[7].buffer_type =
HAL_BUFFER_INTERNAL_SCRATCH_1;
break;
- case HFI_BUFFER_INTERNAL_SCRATCH_2:
+ case HFI_BUFFER_COMMON_INTERNAL_SCRATCH_2:
memcpy(&buffreq->buffer[8], hfi_buf_req,
sizeof(struct hfi_buffer_requirements));
buffreq->buffer[8].buffer_type =
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi.h b/drivers/media/platform/msm/vidc/vidc_hfi.h
index 48a6f17..5601f1b 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi.h
@@ -56,13 +56,6 @@
#define HFI_ERR_SESSION_START_CODE_NOT_FOUND \
(HFI_OX_BASE + 0x1004)
-#define HFI_BUFFER_INTERNAL_SCRATCH (HFI_OX_BASE + 0x1)
-#define HFI_BUFFER_EXTRADATA_INPUT (HFI_OX_BASE + 0x2)
-#define HFI_BUFFER_EXTRADATA_OUTPUT (HFI_OX_BASE + 0x3)
-#define HFI_BUFFER_EXTRADATA_OUTPUT2 (HFI_OX_BASE + 0x4)
-#define HFI_BUFFER_INTERNAL_SCRATCH_1 (HFI_OX_BASE + 0x5)
-#define HFI_BUFFER_INTERNAL_SCRATCH_2 (HFI_OX_BASE + 0x6)
-#define HFI_BUFFER_INTERNAL_RECON (HFI_OX_BASE + 0x9)
#define HFI_BUFFER_MODE_DYNAMIC (HFI_OX_BASE + 0x3)
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
index fc638f0..592f0b8 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
@@ -155,6 +155,13 @@
#define HFI_BUFFER_OUTPUT2 (HFI_COMMON_BASE + 0x3)
#define HFI_BUFFER_INTERNAL_PERSIST (HFI_COMMON_BASE + 0x4)
#define HFI_BUFFER_INTERNAL_PERSIST_1 (HFI_COMMON_BASE + 0x5)
+#define HFI_BUFFER_COMMON_INTERNAL_SCRATCH (HFI_COMMON_BASE + 0x6)
+#define HFI_BUFFER_COMMON_INTERNAL_SCRATCH_1 (HFI_COMMON_BASE + 0x7)
+#define HFI_BUFFER_COMMON_INTERNAL_SCRATCH_2 (HFI_COMMON_BASE + 0x8)
+#define HFI_BUFFER_COMMON_INTERNAL_RECON (HFI_COMMON_BASE + 0x9)
+#define HFI_BUFFER_EXTRADATA_OUTPUT (HFI_COMMON_BASE + 0xA)
+#define HFI_BUFFER_EXTRADATA_OUTPUT2 (HFI_COMMON_BASE + 0xB)
+#define HFI_BUFFER_EXTRADATA_INPUT (HFI_COMMON_BASE + 0xC)
#define HFI_BITDEPTH_8 (HFI_COMMON_BASE + 0x0)
#define HFI_BITDEPTH_9 (HFI_COMMON_BASE + 0x1)
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
index bf13ac5..04d807f 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
@@ -3659,7 +3659,6 @@
struct ipa_mem_buffer mem_info = {0};
static int total_cnt;
- IPADBG("\n");
if (clnt_hdl >= ipa3_ctx->ipa_num_pipes ||
ipa3_ctx->ep[clnt_hdl].valid == 0) {
IPAERR("bad parm 0x%x\n", clnt_hdl);
diff --git a/drivers/regulator/cprh-kbss-regulator.c b/drivers/regulator/cprh-kbss-regulator.c
index cf7c35d..deb0ce5 100644
--- a/drivers/regulator/cprh-kbss-regulator.c
+++ b/drivers/regulator/cprh-kbss-regulator.c
@@ -86,7 +86,7 @@
*/
#define CPRH_MSM8998_KBSS_FUSE_COMBO_COUNT 32
#define CPRH_SDM660_KBSS_FUSE_COMBO_COUNT 16
-#define CPRH_SDM845_KBSS_FUSE_COMBO_COUNT 16
+#define CPRH_SDM845_KBSS_FUSE_COMBO_COUNT 24
/*
* Constants which define the name of each fuse corner.
diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c
index 119ede3..8aff84c 100644
--- a/drivers/soc/qcom/socinfo.c
+++ b/drivers/soc/qcom/socinfo.c
@@ -36,6 +36,7 @@
#include <soc/qcom/boot_stats.h>
#define BUILD_ID_LENGTH 32
+#define CHIP_ID_LENGTH 32
#define SMEM_IMAGE_VERSION_BLOCKS_COUNT 32
#define SMEM_IMAGE_VERSION_SINGLE_BLOCK_SIZE 128
#define SMEM_IMAGE_VERSION_SIZE 4096
@@ -199,6 +200,20 @@
struct socinfo_v0_13 {
struct socinfo_v0_12 v0_12;
uint32_t nproduct_id;
+ char chip_name[CHIP_ID_LENGTH];
+};
+
+struct socinfo_v0_14 {
+ struct socinfo_v0_13 v0_13;
+ uint32_t num_clusters;
+ uint32_t ncluster_array_offset;
+ uint32_t num_defective_parts;
+ uint32_t ndefective_parts_array_offset;
+};
+
+struct socinfo_v0_15 {
+ struct socinfo_v0_14 v0_14;
+ uint32_t nmodem_supported;
};
static union {
@@ -215,10 +230,12 @@
struct socinfo_v0_11 v0_11;
struct socinfo_v0_12 v0_12;
struct socinfo_v0_13 v0_13;
+ struct socinfo_v0_14 v0_14;
+ struct socinfo_v0_15 v0_15;
} *socinfo;
/* max socinfo format version supported */
-#define MAX_SOCINFO_FORMAT SOCINFO_VERSION(0, 13)
+#define MAX_SOCINFO_FORMAT SOCINFO_VERSION(0, 15)
static struct msm_soc_info cpu_of_id[] = {
@@ -705,6 +722,14 @@
: 0;
}
+static char *socinfo_get_chip_name(void)
+{
+ return socinfo ?
+ (socinfo_format >= SOCINFO_VERSION(0, 13) ?
+ socinfo->v0_13.chip_name : "N/A")
+ : "N/A";
+}
+
static uint32_t socinfo_get_nproduct_id(void)
{
return socinfo ?
@@ -713,6 +738,46 @@
: 0;
}
+static uint32_t socinfo_get_num_clusters(void)
+{
+ return socinfo ?
+ (socinfo_format >= SOCINFO_VERSION(0, 14) ?
+ socinfo->v0_14.num_clusters : 0)
+ : 0;
+}
+
+static uint32_t socinfo_get_ncluster_array_offset(void)
+{
+ return socinfo ?
+ (socinfo_format >= SOCINFO_VERSION(0, 14) ?
+ socinfo->v0_14.ncluster_array_offset : 0)
+ : 0;
+}
+
+static uint32_t socinfo_get_num_defective_parts(void)
+{
+ return socinfo ?
+ (socinfo_format >= SOCINFO_VERSION(0, 14) ?
+ socinfo->v0_14.num_defective_parts : 0)
+ : 0;
+}
+
+static uint32_t socinfo_get_ndefective_parts_array_offset(void)
+{
+ return socinfo ?
+ (socinfo_format >= SOCINFO_VERSION(0, 14) ?
+ socinfo->v0_14.ndefective_parts_array_offset : 0)
+ : 0;
+}
+
+static uint32_t socinfo_get_nmodem_supported(void)
+{
+ return socinfo ?
+ (socinfo_format >= SOCINFO_VERSION(0, 15) ?
+ socinfo->v0_15.nmodem_supported : 0)
+ : 0;
+}
+
enum pmic_model socinfo_get_pmic_model(void)
{
return socinfo ?
@@ -890,6 +955,15 @@
}
static ssize_t
+msm_get_chip_name(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%-.32s\n",
+ socinfo_get_chip_name());
+}
+
+static ssize_t
msm_get_nproduct_id(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -899,6 +973,51 @@
}
static ssize_t
+msm_get_num_clusters(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "0x%x\n",
+ socinfo_get_num_clusters());
+}
+
+static ssize_t
+msm_get_ncluster_array_offset(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "0x%x\n",
+ socinfo_get_ncluster_array_offset());
+}
+
+static ssize_t
+msm_get_num_defective_parts(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "0x%x\n",
+ socinfo_get_num_defective_parts());
+}
+
+static ssize_t
+msm_get_ndefective_parts_array_offset(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "0x%x\n",
+ socinfo_get_ndefective_parts_array_offset());
+}
+
+static ssize_t
+msm_get_nmodem_supported(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "0x%x\n",
+ socinfo_get_nmodem_supported());
+}
+
+static ssize_t
msm_get_pmic_model(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -1146,10 +1265,34 @@
__ATTR(raw_device_number, S_IRUGO,
msm_get_raw_device_number, NULL);
+static struct device_attribute msm_soc_attr_chip_name =
+ __ATTR(chip_name, 0444,
+ msm_get_chip_name, NULL);
+
static struct device_attribute msm_soc_attr_nproduct_id =
__ATTR(nproduct_id, 0444,
msm_get_nproduct_id, NULL);
+static struct device_attribute msm_soc_attr_num_clusters =
+ __ATTR(num_clusters, 0444,
+ msm_get_num_clusters, NULL);
+
+static struct device_attribute msm_soc_attr_ncluster_array_offset =
+ __ATTR(ncluster_array_offset, 0444,
+ msm_get_ncluster_array_offset, NULL);
+
+static struct device_attribute msm_soc_attr_num_defective_parts =
+ __ATTR(num_defective_parts, 0444,
+ msm_get_num_defective_parts, NULL);
+
+static struct device_attribute msm_soc_attr_ndefective_parts_array_offset =
+ __ATTR(ndefective_parts_array_offset, 0444,
+ msm_get_ndefective_parts_array_offset, NULL);
+
+static struct device_attribute msm_soc_attr_nmodem_supported =
+ __ATTR(nmodem_supported, 0444,
+ msm_get_nmodem_supported, NULL);
+
static struct device_attribute msm_soc_attr_pmic_model =
__ATTR(pmic_model, S_IRUGO,
msm_get_pmic_model, NULL);
@@ -1280,9 +1423,23 @@
device_create_file(msm_soc_device, &images);
switch (socinfo_format) {
+ case SOCINFO_VERSION(0, 15):
+ device_create_file(msm_soc_device,
+ &msm_soc_attr_nmodem_supported);
+ case SOCINFO_VERSION(0, 14):
+ device_create_file(msm_soc_device,
+ &msm_soc_attr_num_clusters);
+ device_create_file(msm_soc_device,
+ &msm_soc_attr_ncluster_array_offset);
+ device_create_file(msm_soc_device,
+ &msm_soc_attr_num_defective_parts);
+ device_create_file(msm_soc_device,
+ &msm_soc_attr_ndefective_parts_array_offset);
case SOCINFO_VERSION(0, 13):
device_create_file(msm_soc_device,
&msm_soc_attr_nproduct_id);
+ device_create_file(msm_soc_device,
+ &msm_soc_attr_chip_name);
case SOCINFO_VERSION(0, 12):
device_create_file(msm_soc_device,
&msm_soc_attr_chip_family);
@@ -1522,6 +1679,53 @@
socinfo->v0_13.nproduct_id);
break;
+ case SOCINFO_VERSION(0, 14):
+ pr_info("v%u.%u, id=%u, ver=%u.%u, raw_id=%u, raw_ver=%u, hw_plat=%u, hw_plat_ver=%u\n accessory_chip=%u, hw_plat_subtype=%u, pmic_model=%u, pmic_die_revision=%u foundry_id=%u serial_number=%u num_pmics=%u chip_family=0x%x raw_device_family=0x%x raw_device_number=0x%x nproduct_id=0x%x num_clusters=0x%x ncluster_array_offset=0x%x num_defective_parts=0x%x ndefective_parts_array_offset=0x%x\n",
+ f_maj, f_min, socinfo->v0_1.id, v_maj, v_min,
+ socinfo->v0_2.raw_id, socinfo->v0_2.raw_version,
+ socinfo->v0_3.hw_platform,
+ socinfo->v0_4.platform_version,
+ socinfo->v0_5.accessory_chip,
+ socinfo->v0_6.hw_platform_subtype,
+ socinfo->v0_7.pmic_model,
+ socinfo->v0_7.pmic_die_revision,
+ socinfo->v0_9.foundry_id,
+ socinfo->v0_10.serial_number,
+ socinfo->v0_11.num_pmics,
+ socinfo->v0_12.chip_family,
+ socinfo->v0_12.raw_device_family,
+ socinfo->v0_12.raw_device_number,
+ socinfo->v0_13.nproduct_id,
+ socinfo->v0_14.num_clusters,
+ socinfo->v0_14.ncluster_array_offset,
+ socinfo->v0_14.num_defective_parts,
+ socinfo->v0_14.ndefective_parts_array_offset);
+ break;
+
+ case SOCINFO_VERSION(0, 15):
+ pr_info("v%u.%u, id=%u, ver=%u.%u, raw_id=%u, raw_ver=%u, hw_plat=%u, hw_plat_ver=%u\n accessory_chip=%u, hw_plat_subtype=%u, pmic_model=%u, pmic_die_revision=%u foundry_id=%u serial_number=%u num_pmics=%u chip_family=0x%x raw_device_family=0x%x raw_device_number=0x%x nproduct_id=0x%x num_clusters=0x%x ncluster_array_offset=0x%x num_defective_parts=0x%x ndefective_parts_array_offset=0x%x nmodem_supported=0x%x\n",
+ f_maj, f_min, socinfo->v0_1.id, v_maj, v_min,
+ socinfo->v0_2.raw_id, socinfo->v0_2.raw_version,
+ socinfo->v0_3.hw_platform,
+ socinfo->v0_4.platform_version,
+ socinfo->v0_5.accessory_chip,
+ socinfo->v0_6.hw_platform_subtype,
+ socinfo->v0_7.pmic_model,
+ socinfo->v0_7.pmic_die_revision,
+ socinfo->v0_9.foundry_id,
+ socinfo->v0_10.serial_number,
+ socinfo->v0_11.num_pmics,
+ socinfo->v0_12.chip_family,
+ socinfo->v0_12.raw_device_family,
+ socinfo->v0_12.raw_device_number,
+ socinfo->v0_13.nproduct_id,
+ socinfo->v0_14.num_clusters,
+ socinfo->v0_14.ncluster_array_offset,
+ socinfo->v0_14.num_defective_parts,
+ socinfo->v0_14.ndefective_parts_array_offset,
+ socinfo->v0_15.nmodem_supported);
+ break;
+
default:
pr_err("Unknown format found: v%u.%u\n", f_maj, f_min);
break;
diff --git a/include/trace/events/pdc.h b/include/trace/events/pdc.h
new file mode 100644
index 0000000..400e959
--- /dev/null
+++ b/include/trace/events/pdc.h
@@ -0,0 +1,50 @@
+/* Copyright (c) 2017, 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.
+ */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM pdc
+
+#if !defined(_TRACE_PDC_) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_PDC_H_
+
+#include <linux/tracepoint.h>
+
+TRACE_EVENT(irq_pin_config,
+
+ TP_PROTO(char *func, u32 pin, u32 hwirq, u32 type, u32 enable),
+
+ TP_ARGS(func, pin, hwirq, type, enable),
+
+ TP_STRUCT__entry(
+ __field(char *, func)
+ __field(u32, pin)
+ __field(u32, hwirq)
+ __field(u32, type)
+ __field(u32, enable)
+ ),
+
+ TP_fast_assign(
+ __entry->pin = pin;
+ __entry->func = func;
+ __entry->hwirq = hwirq;
+ __entry->type = type;
+ __entry->enable = enable;
+ ),
+
+ TP_printk("%s hwirq:%u pin:%u type:%u enable:%u",
+ __entry->func, __entry->pin, __entry->hwirq, __entry->type,
+ __entry->enable)
+);
+
+#endif
+#define TRACE_INCLUDE_FILE pdc
+#include <trace/define_trace.h>
diff --git a/kernel/locking/mutex.c b/kernel/locking/mutex.c
index a70b90d..c61c56f 100644
--- a/kernel/locking/mutex.c
+++ b/kernel/locking/mutex.c
@@ -26,6 +26,7 @@
#include <linux/interrupt.h>
#include <linux/debug_locks.h>
#include <linux/osq_lock.h>
+#include <linux/delay.h>
/*
* In the DEBUG case we are using the "NULL fastpath" for mutexes,
@@ -378,6 +379,17 @@
* values at the cost of a few extra spins.
*/
cpu_relax_lowlatency();
+
+ /*
+ * On arm systems, we must slow down the waiter's repeated
+ * aquisition of spin_mlock and atomics on the lock count, or
+ * we risk starving out a thread attempting to release the
+ * mutex. The mutex slowpath release must take spin lock
+ * wait_lock. This spin lock can share a monitor with the
+ * other waiter atomics in the mutex data structure, so must
+ * take care to rate limit the waiters.
+ */
+ udelay(1);
}
osq_unlock(&lock->osq);
diff --git a/sound/soc/codecs/wcd9330.c b/sound/soc/codecs/wcd9330.c
index 0b07393..4278e36 100644
--- a/sound/soc/codecs/wcd9330.c
+++ b/sound/soc/codecs/wcd9330.c
@@ -1536,6 +1536,13 @@
tomtom_mad_input = ucontrol->value.integer.value[0];
micb_4_int_reg = tomtom->resmgr.reg_addr->micb_4_int_rbias;
+ if (tomtom_mad_input >= ARRAY_SIZE(tomtom_conn_mad_text)) {
+ dev_err(codec->dev,
+ "%s: tomtom_mad_input = %d out of bounds\n",
+ __func__, tomtom_mad_input);
+ return -EINVAL;
+ }
+
pr_debug("%s: tomtom_mad_input = %s\n", __func__,
tomtom_conn_mad_text[tomtom_mad_input]);
diff --git a/sound/soc/msm/qdsp6v2/Makefile b/sound/soc/msm/qdsp6v2/Makefile
index d4db55f..36382ba 100644
--- a/sound/soc/msm/qdsp6v2/Makefile
+++ b/sound/soc/msm/qdsp6v2/Makefile
@@ -1,5 +1,5 @@
-snd-soc-qdsp6v2-objs += msm-dai-q6-v2.o msm-pcm-q6-v2.o msm-pcm-routing-v2.o \
- msm-compress-q6-v2.o msm-compr-q6-v2.o \
+snd-soc-qdsp6v2-objs += msm-dai-q6-v2.o msm-pcm-q6-v2.o \
+ msm-pcm-routing-v2.o msm-compress-q6-v2.o \
msm-pcm-afe-v2.o msm-pcm-voip-v2.o \
msm-pcm-voice-v2.o msm-dai-q6-hdmi-v2.o \
msm-lsm-client.o msm-pcm-host-voice-v2.o \
diff --git a/sound/soc/msm/qdsp6v2/audio_cal_utils.c b/sound/soc/msm/qdsp6v2/audio_cal_utils.c
index 5d4a0ba..820aa1b 100644
--- a/sound/soc/msm/qdsp6v2/audio_cal_utils.c
+++ b/sound/soc/msm/qdsp6v2/audio_cal_utils.c
@@ -646,7 +646,9 @@
return cal_block;
err:
kfree(cal_block->cal_info);
+ cal_block->cal_info = NULL;
kfree(cal_block->client_info);
+ cal_block->client_info = NULL;
kfree(cal_block);
cal_block = NULL;
return cal_block;
diff --git a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
deleted file mode 100644
index 449325c..0000000
--- a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
+++ /dev/null
@@ -1,1714 +0,0 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-
-#include <linux/init.h>
-#include <linux/err.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/time.h>
-#include <linux/wait.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <sound/core.h>
-#include <sound/soc.h>
-#include <sound/soc-dapm.h>
-#include <sound/pcm.h>
-#include <sound/initval.h>
-#include <sound/control.h>
-#include <sound/q6asm-v2.h>
-#include <sound/pcm_params.h>
-#include <asm/dma.h>
-#include <linux/dma-mapping.h>
-#include <linux/msm_audio_ion.h>
-
-#include <sound/timer.h>
-
-#include "msm-compr-q6-v2.h"
-#include "msm-pcm-routing-v2.h"
-#include <sound/tlv.h>
-
-#define COMPRE_CAPTURE_NUM_PERIODS 16
-/* Allocate the worst case frame size for compressed audio */
-#define COMPRE_CAPTURE_HEADER_SIZE (sizeof(struct snd_compr_audio_info))
-/* Changing period size to 4032. 4032 will make sure COMPRE_CAPTURE_PERIOD_SIZE
- * is 4096 with meta data size of 64 and MAX_NUM_FRAMES_PER_BUFFER 1
- */
-#define COMPRE_CAPTURE_MAX_FRAME_SIZE (4032)
-#define COMPRE_CAPTURE_PERIOD_SIZE ((COMPRE_CAPTURE_MAX_FRAME_SIZE + \
- COMPRE_CAPTURE_HEADER_SIZE) * \
- MAX_NUM_FRAMES_PER_BUFFER)
-#define COMPRE_OUTPUT_METADATA_SIZE (sizeof(struct output_meta_data_st))
-#define COMPRESSED_LR_VOL_MAX_STEPS 0x20002000
-
-#define MAX_AC3_PARAM_SIZE (18*2*sizeof(int))
-#define AMR_WB_BAND_MODE 8
-#define AMR_WB_DTX_MODE 0
-
-
-const DECLARE_TLV_DB_LINEAR(compr_rx_vol_gain, 0,
- COMPRESSED_LR_VOL_MAX_STEPS);
-
-static struct audio_locks the_locks;
-
-static struct snd_pcm_hardware msm_compr_hardware_capture = {
- .info = (SNDRV_PCM_INFO_MMAP |
- SNDRV_PCM_INFO_BLOCK_TRANSFER |
- SNDRV_PCM_INFO_MMAP_VALID |
- SNDRV_PCM_INFO_INTERLEAVED |
- SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
- .rates = SNDRV_PCM_RATE_8000_48000,
- .rate_min = 8000,
- .rate_max = 48000,
- .channels_min = 1,
- .channels_max = 8,
- .buffer_bytes_max =
- COMPRE_CAPTURE_PERIOD_SIZE * COMPRE_CAPTURE_NUM_PERIODS,
- .period_bytes_min = COMPRE_CAPTURE_PERIOD_SIZE,
- .period_bytes_max = COMPRE_CAPTURE_PERIOD_SIZE,
- .periods_min = COMPRE_CAPTURE_NUM_PERIODS,
- .periods_max = COMPRE_CAPTURE_NUM_PERIODS,
- .fifo_size = 0,
-};
-
-static struct snd_pcm_hardware msm_compr_hardware_playback = {
- .info = (SNDRV_PCM_INFO_MMAP |
- SNDRV_PCM_INFO_BLOCK_TRANSFER |
- SNDRV_PCM_INFO_MMAP_VALID |
- SNDRV_PCM_INFO_INTERLEAVED |
- SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
- .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
- .rates = SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_KNOT,
- .rate_min = 8000,
- .rate_max = 48000,
- .channels_min = 1,
- .channels_max = 8,
- .buffer_bytes_max = 1024 * 1024,
- .period_bytes_min = 128 * 1024,
- .period_bytes_max = 256 * 1024,
- .periods_min = 4,
- .periods_max = 8,
- .fifo_size = 0,
-};
-
-/* Conventional and unconventional sample rate supported */
-static unsigned int supported_sample_rates[] = {
- 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
-};
-
-/* Add supported codecs for compress capture path */
-static uint32_t supported_compr_capture_codecs[] = {
- SND_AUDIOCODEC_AMRWB
-};
-
-static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
- .count = ARRAY_SIZE(supported_sample_rates),
- .list = supported_sample_rates,
- .mask = 0,
-};
-
-static bool msm_compr_capture_codecs(uint32_t req_codec)
-{
- int i;
-
- pr_debug("%s req_codec:%d\n", __func__, req_codec);
- if (req_codec == 0)
- return false;
- for (i = 0; i < ARRAY_SIZE(supported_compr_capture_codecs); i++) {
- if (req_codec == supported_compr_capture_codecs[i])
- return true;
- }
- return false;
-}
-
-static void compr_event_handler(uint32_t opcode,
- uint32_t token, uint32_t *payload, void *priv)
-{
- struct compr_audio *compr = priv;
- struct msm_audio *prtd = &compr->prtd;
- struct snd_pcm_substream *substream = prtd->substream;
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct audio_aio_write_param param;
- struct audio_aio_read_param read_param;
- struct audio_buffer *buf = NULL;
- phys_addr_t temp;
- struct output_meta_data_st output_meta_data;
- uint32_t *ptrmem = (uint32_t *)payload;
- int i = 0;
- int time_stamp_flag = 0;
- int buffer_length = 0;
- int stop_playback = 0;
-
- pr_debug("%s opcode =%08x\n", __func__, opcode);
- switch (opcode) {
- case ASM_DATA_EVENT_WRITE_DONE_V2: {
- uint32_t *ptrmem = (uint32_t *)¶m;
-
- pr_debug("ASM_DATA_EVENT_WRITE_DONE\n");
- pr_debug("Buffer Consumed = 0x%08x\n", *ptrmem);
- prtd->pcm_irq_pos += prtd->pcm_count;
- if (atomic_read(&prtd->start))
- snd_pcm_period_elapsed(substream);
- else
- if (substream->timer_running)
- snd_timer_interrupt(substream->timer, 1);
- atomic_inc(&prtd->out_count);
- wake_up(&the_locks.write_wait);
- if (!atomic_read(&prtd->start)) {
- atomic_set(&prtd->pending_buffer, 1);
- break;
- }
- atomic_set(&prtd->pending_buffer, 0);
-
- /*
- * check for underrun
- */
- snd_pcm_stream_lock_irq(substream);
- if (runtime->status->hw_ptr >= runtime->control->appl_ptr) {
- runtime->render_flag |= SNDRV_RENDER_STOPPED;
- stop_playback = 1;
- }
- snd_pcm_stream_unlock_irq(substream);
-
- if (stop_playback) {
- pr_err("underrun! render stopped\n");
- break;
- }
-
- buf = prtd->audio_client->port[IN].buf;
- pr_debug("%s:writing %d bytes of buffer[%d] to dsp 2\n",
- __func__, prtd->pcm_count, prtd->out_head);
- temp = buf[0].phys + (prtd->out_head * prtd->pcm_count);
- pr_debug("%s:writing buffer[%d] from 0x%pK\n",
- __func__, prtd->out_head, &temp);
-
- if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE)
- time_stamp_flag = SET_TIMESTAMP;
- else
- time_stamp_flag = NO_TIMESTAMP;
- memcpy(&output_meta_data, (char *)(buf->data +
- prtd->out_head * prtd->pcm_count),
- COMPRE_OUTPUT_METADATA_SIZE);
-
- buffer_length = output_meta_data.frame_size;
- pr_debug("meta_data_length: %d, frame_length: %d\n",
- output_meta_data.meta_data_length,
- output_meta_data.frame_size);
- pr_debug("timestamp_msw: %d, timestamp_lsw: %d\n",
- output_meta_data.timestamp_msw,
- output_meta_data.timestamp_lsw);
- if (buffer_length == 0) {
- pr_debug("Received a zero length buffer-break out");
- break;
- }
- param.paddr = temp + output_meta_data.meta_data_length;
- param.len = buffer_length;
- param.msw_ts = output_meta_data.timestamp_msw;
- param.lsw_ts = output_meta_data.timestamp_lsw;
- param.flags = time_stamp_flag;
- param.uid = prtd->session_id;
- for (i = 0; i < sizeof(struct audio_aio_write_param)/4;
- i++, ++ptrmem)
- pr_debug("cmd[%d]=0x%08x\n", i, *ptrmem);
- if (q6asm_async_write(prtd->audio_client,
- ¶m) < 0)
- pr_err("%s:q6asm_async_write failed\n",
- __func__);
- else
- prtd->out_head =
- (prtd->out_head + 1) & (runtime->periods - 1);
- break;
- }
- case ASM_DATA_EVENT_RENDERED_EOS:
- pr_debug("ASM_DATA_CMDRSP_EOS\n");
- if (atomic_read(&prtd->eos)) {
- pr_debug("ASM_DATA_CMDRSP_EOS wake up\n");
- prtd->cmd_ack = 1;
- wake_up(&the_locks.eos_wait);
- atomic_set(&prtd->eos, 0);
- }
- break;
- case ASM_DATA_EVENT_READ_DONE_V2: {
- pr_debug("ASM_DATA_EVENT_READ_DONE\n");
- pr_debug("buf = %pK, data = 0x%X, *data = %pK,\n"
- "prtd->pcm_irq_pos = %d\n",
- prtd->audio_client->port[OUT].buf,
- *(uint32_t *)prtd->audio_client->port[OUT].buf->data,
- prtd->audio_client->port[OUT].buf->data,
- prtd->pcm_irq_pos);
-
- memcpy(prtd->audio_client->port[OUT].buf->data +
- prtd->pcm_irq_pos, (ptrmem + READDONE_IDX_SIZE),
- COMPRE_CAPTURE_HEADER_SIZE);
- pr_debug("buf = %pK, updated data = 0x%X, *data = %pK\n",
- prtd->audio_client->port[OUT].buf,
- *(uint32_t *)(prtd->audio_client->port[OUT].buf->data +
- prtd->pcm_irq_pos),
- prtd->audio_client->port[OUT].buf->data);
- if (!atomic_read(&prtd->start))
- break;
- pr_debug("frame size=%d, buffer = 0x%X\n",
- ptrmem[READDONE_IDX_SIZE],
- ptrmem[READDONE_IDX_BUFADD_LSW]);
- if (ptrmem[READDONE_IDX_SIZE] > COMPRE_CAPTURE_MAX_FRAME_SIZE) {
- pr_err("Frame length exceeded the max length");
- break;
- }
- buf = prtd->audio_client->port[OUT].buf;
-
- pr_debug("pcm_irq_pos=%d, buf[0].phys = 0x%pK\n",
- prtd->pcm_irq_pos, &buf[0].phys);
- read_param.len = prtd->pcm_count - COMPRE_CAPTURE_HEADER_SIZE;
- read_param.paddr = buf[0].phys +
- prtd->pcm_irq_pos + COMPRE_CAPTURE_HEADER_SIZE;
- prtd->pcm_irq_pos += prtd->pcm_count;
-
- if (atomic_read(&prtd->start))
- snd_pcm_period_elapsed(substream);
-
- q6asm_async_read(prtd->audio_client, &read_param);
- break;
- }
- case APR_BASIC_RSP_RESULT: {
- switch (payload[0]) {
- case ASM_SESSION_CMD_RUN_V2: {
- if (substream->stream
- != SNDRV_PCM_STREAM_PLAYBACK) {
- atomic_set(&prtd->start, 1);
- break;
- }
- if (!atomic_read(&prtd->pending_buffer))
- break;
- pr_debug("%s: writing %d bytes of buffer[%d] to dsp\n",
- __func__, prtd->pcm_count, prtd->out_head);
- buf = prtd->audio_client->port[IN].buf;
- pr_debug("%s: writing buffer[%d] from 0x%pK head %d count %d\n",
- __func__, prtd->out_head, &buf[0].phys,
- prtd->pcm_count, prtd->out_head);
- if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE)
- time_stamp_flag = SET_TIMESTAMP;
- else
- time_stamp_flag = NO_TIMESTAMP;
- memcpy(&output_meta_data, (char *)(buf->data +
- prtd->out_head * prtd->pcm_count),
- COMPRE_OUTPUT_METADATA_SIZE);
- buffer_length = output_meta_data.frame_size;
- pr_debug("meta_data_length: %d, frame_length: %d\n",
- output_meta_data.meta_data_length,
- output_meta_data.frame_size);
- pr_debug("timestamp_msw: %d, timestamp_lsw: %d\n",
- output_meta_data.timestamp_msw,
- output_meta_data.timestamp_lsw);
- param.paddr = buf[prtd->out_head].phys
- + output_meta_data.meta_data_length;
- param.len = buffer_length;
- param.msw_ts = output_meta_data.timestamp_msw;
- param.lsw_ts = output_meta_data.timestamp_lsw;
- param.flags = time_stamp_flag;
- param.uid = prtd->session_id;
- param.metadata_len = COMPRE_OUTPUT_METADATA_SIZE;
- if (q6asm_async_write(prtd->audio_client,
- ¶m) < 0)
- pr_err("%s:q6asm_async_write failed\n",
- __func__);
- else
- prtd->out_head =
- (prtd->out_head + 1)
- & (runtime->periods - 1);
- atomic_set(&prtd->pending_buffer, 0);
- }
- break;
- case ASM_STREAM_CMD_FLUSH:
- pr_debug("ASM_STREAM_CMD_FLUSH\n");
- prtd->cmd_ack = 1;
- wake_up(&the_locks.flush_wait);
- break;
- default:
- break;
- }
- break;
- }
- default:
- pr_debug("Not Supported Event opcode[0x%x]\n", opcode);
- break;
- }
-}
-
-static int msm_compr_send_ddp_cfg(struct audio_client *ac,
- struct snd_dec_ddp *ddp)
-{
- int i, rc;
-
- pr_debug("%s\n", __func__);
-
- if (ddp->params_length / 2 > SND_DEC_DDP_MAX_PARAMS) {
- pr_err("%s: Invalid number of params %u, max allowed %u\n",
- __func__, ddp->params_length / 2,
- SND_DEC_DDP_MAX_PARAMS);
- return -EINVAL;
- }
-
- for (i = 0; i < ddp->params_length/2; i++) {
- rc = q6asm_ds1_set_endp_params(ac, ddp->params_id[i],
- ddp->params_value[i]);
- if (rc) {
- pr_err("sending params_id: %d failed\n",
- ddp->params_id[i]);
- return rc;
- }
- }
- return 0;
-}
-
-static int msm_compr_playback_prepare(struct snd_pcm_substream *substream)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct compr_audio *compr = runtime->private_data;
- struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
- struct msm_audio *prtd = &compr->prtd;
- struct snd_pcm_hw_params *params;
- struct asm_aac_cfg aac_cfg;
- uint16_t bits_per_sample = 16;
- int ret;
-
- struct asm_softpause_params softpause = {
- .enable = SOFT_PAUSE_ENABLE,
- .period = SOFT_PAUSE_PERIOD,
- .step = SOFT_PAUSE_STEP,
- .rampingcurve = SOFT_PAUSE_CURVE_LINEAR,
- };
- struct asm_softvolume_params softvol = {
- .period = SOFT_VOLUME_PERIOD,
- .step = SOFT_VOLUME_STEP,
- .rampingcurve = SOFT_VOLUME_CURVE_LINEAR,
- };
-
- pr_debug("%s\n", __func__);
-
- params = &soc_prtd->dpcm[substream->stream].hw_params;
- if (runtime->format == SNDRV_PCM_FORMAT_S24_LE)
- bits_per_sample = 24;
-
- ret = q6asm_open_write_v2(prtd->audio_client,
- compr->codec, bits_per_sample);
- if (ret < 0) {
- pr_err("%s: Session out open failed\n",
- __func__);
- return -ENOMEM;
- }
- msm_pcm_routing_reg_phy_stream(
- soc_prtd->dai_link->id,
- prtd->audio_client->perf_mode,
- prtd->session_id,
- substream->stream);
- /*
- * the number of channels are required to call volume api
- * accoridngly. So, get channels from hw params
- */
- if ((params_channels(params) > 0) &&
- (params_periods(params) <= runtime->hw.channels_max))
- prtd->channel_mode = params_channels(params);
-
- ret = q6asm_set_softpause(prtd->audio_client, &softpause);
- if (ret < 0)
- pr_err("%s: Send SoftPause Param failed ret=%d\n",
- __func__, ret);
- ret = q6asm_set_softvolume(prtd->audio_client, &softvol);
- if (ret < 0)
- pr_err("%s: Send SoftVolume Param failed ret=%d\n",
- __func__, ret);
-
- ret = q6asm_set_io_mode(prtd->audio_client,
- (COMPRESSED_IO | ASYNC_IO_MODE));
- if (ret < 0) {
- pr_err("%s: Set IO mode failed\n", __func__);
- return -ENOMEM;
- }
-
- prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
- prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
- prtd->pcm_irq_pos = 0;
- /* rate and channels are sent to audio driver */
- prtd->samp_rate = runtime->rate;
- prtd->channel_mode = runtime->channels;
- prtd->out_head = 0;
- atomic_set(&prtd->out_count, runtime->periods);
-
- if (prtd->enabled)
- return 0;
-
- switch (compr->info.codec_param.codec.id) {
- case SND_AUDIOCODEC_MP3:
- /* No media format block for mp3 */
- break;
- case SND_AUDIOCODEC_AAC:
- pr_debug("%s: SND_AUDIOCODEC_AAC\n", __func__);
- memset(&aac_cfg, 0x0, sizeof(struct asm_aac_cfg));
- aac_cfg.aot = AAC_ENC_MODE_EAAC_P;
- aac_cfg.format = 0x03;
- aac_cfg.ch_cfg = runtime->channels;
- aac_cfg.sample_rate = runtime->rate;
- ret = q6asm_media_format_block_aac(prtd->audio_client,
- &aac_cfg);
- if (ret < 0)
- pr_err("%s: CMD Format block failed\n", __func__);
- break;
- case SND_AUDIOCODEC_AC3: {
- struct snd_dec_ddp *ddp =
- &compr->info.codec_param.codec.options.ddp;
- pr_debug("%s: SND_AUDIOCODEC_AC3\n", __func__);
- ret = msm_compr_send_ddp_cfg(prtd->audio_client, ddp);
- if (ret < 0)
- pr_err("%s: DDP CMD CFG failed\n", __func__);
- break;
- }
- case SND_AUDIOCODEC_EAC3: {
- struct snd_dec_ddp *ddp =
- &compr->info.codec_param.codec.options.ddp;
- pr_debug("%s: SND_AUDIOCODEC_EAC3\n", __func__);
- ret = msm_compr_send_ddp_cfg(prtd->audio_client, ddp);
- if (ret < 0)
- pr_err("%s: DDP CMD CFG failed\n", __func__);
- break;
- }
- default:
- return -EINVAL;
- }
-
- prtd->enabled = 1;
- prtd->cmd_ack = 0;
- prtd->cmd_interrupt = 0;
-
- return 0;
-}
-
-static int msm_compr_capture_prepare(struct snd_pcm_substream *substream)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct compr_audio *compr = runtime->private_data;
- struct msm_audio *prtd = &compr->prtd;
- struct audio_buffer *buf = prtd->audio_client->port[OUT].buf;
- struct snd_codec *codec = &compr->info.codec_param.codec;
- struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
- struct audio_aio_read_param read_param;
- uint16_t bits_per_sample = 16;
- int ret = 0;
- int i;
-
- prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
- prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
- prtd->pcm_irq_pos = 0;
-
- if (runtime->format == SNDRV_PCM_FORMAT_S24_LE)
- bits_per_sample = 24;
-
- if (!msm_compr_capture_codecs(
- compr->info.codec_param.codec.id)) {
- /*
- * request codec invalid or not supported,
- * use default compress format
- */
- compr->info.codec_param.codec.id =
- SND_AUDIOCODEC_AMRWB;
- }
- switch (compr->info.codec_param.codec.id) {
- case SND_AUDIOCODEC_AMRWB:
- pr_debug("q6asm_open_read(FORMAT_AMRWB)\n");
- ret = q6asm_open_read(prtd->audio_client,
- FORMAT_AMRWB);
- if (ret < 0) {
- pr_err("%s: compressed Session out open failed\n",
- __func__);
- return -ENOMEM;
- }
- pr_debug("msm_pcm_routing_reg_phy_stream\n");
- msm_pcm_routing_reg_phy_stream(
- soc_prtd->dai_link->id,
- prtd->audio_client->perf_mode,
- prtd->session_id, substream->stream);
- break;
- default:
- pr_debug("q6asm_open_read_compressed(COMPRESSED_META_DATA_MODE)\n");
- /*
- * ret = q6asm_open_read_compressed(prtd->audio_client,
- * MAX_NUM_FRAMES_PER_BUFFER,
- * COMPRESSED_META_DATA_MODE);
- */
- ret = -EINVAL;
- break;
- }
-
- if (ret < 0) {
- pr_err("%s: compressed Session out open failed\n",
- __func__);
- return -ENOMEM;
- }
-
- ret = q6asm_set_io_mode(prtd->audio_client,
- (COMPRESSED_IO | ASYNC_IO_MODE));
- if (ret < 0) {
- pr_err("%s: Set IO mode failed\n", __func__);
- return -ENOMEM;
- }
-
- if (!msm_compr_capture_codecs(codec->id)) {
- /*
- * request codec invalid or not supported,
- * use default compress format
- */
- codec->id = SND_AUDIOCODEC_AMRWB;
- }
- /* rate and channels are sent to audio driver */
- prtd->samp_rate = runtime->rate;
- prtd->channel_mode = runtime->channels;
-
- if (prtd->enabled)
- return ret;
- read_param.len = prtd->pcm_count;
-
- switch (codec->id) {
- case SND_AUDIOCODEC_AMRWB:
- pr_debug("SND_AUDIOCODEC_AMRWB\n");
- ret = q6asm_enc_cfg_blk_amrwb(prtd->audio_client,
- MAX_NUM_FRAMES_PER_BUFFER,
- /*
- * use fixed band mode and dtx mode
- * band mode - 23.85 kbps
- */
- AMR_WB_BAND_MODE,
- /* dtx mode - disable */
- AMR_WB_DTX_MODE);
- if (ret < 0)
- pr_err("%s: CMD Format block failed: %d\n",
- __func__, ret);
- break;
- default:
- pr_debug("No config for codec %d\n", codec->id);
- }
- pr_debug("%s: Samp_rate = %d, Channel = %d, pcm_size = %d,\n"
- "pcm_count = %d, periods = %d\n",
- __func__, prtd->samp_rate, prtd->channel_mode,
- prtd->pcm_size, prtd->pcm_count, runtime->periods);
-
- for (i = 0; i < runtime->periods; i++) {
- read_param.uid = i;
- switch (codec->id) {
- case SND_AUDIOCODEC_AMRWB:
- read_param.len = prtd->pcm_count
- - COMPRE_CAPTURE_HEADER_SIZE;
- read_param.paddr = buf[i].phys
- + COMPRE_CAPTURE_HEADER_SIZE;
- pr_debug("Push buffer [%d] to DSP, paddr: %pK, vaddr: %pK\n",
- i, &read_param.paddr,
- buf[i].data);
- q6asm_async_read(prtd->audio_client, &read_param);
- break;
- default:
- read_param.paddr = buf[i].phys;
- /* q6asm_async_read_compressed(prtd->audio_client,
- * &read_param);
- */
- pr_debug("%s: To add support for read compressed\n",
- __func__);
- ret = -EINVAL;
- break;
- }
- }
- prtd->periods = runtime->periods;
-
- prtd->enabled = 1;
-
- return ret;
-}
-
-static int msm_compr_trigger(struct snd_pcm_substream *substream, int cmd)
-{
- int ret = 0;
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
- struct compr_audio *compr = runtime->private_data;
- struct msm_audio *prtd = &compr->prtd;
-
- pr_debug("%s\n", __func__);
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
- prtd->pcm_irq_pos = 0;
-
- if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
- if (!msm_compr_capture_codecs(
- compr->info.codec_param.codec.id)) {
- /*
- * request codec invalid or not supported,
- * use default compress format
- */
- compr->info.codec_param.codec.id =
- SND_AUDIOCODEC_AMRWB;
- }
- switch (compr->info.codec_param.codec.id) {
- case SND_AUDIOCODEC_AMRWB:
- break;
- default:
- msm_pcm_routing_reg_psthr_stream(
- soc_prtd->dai_link->id,
- prtd->session_id, substream->stream);
- break;
- }
- }
- atomic_set(&prtd->pending_buffer, 1);
- /* fallthrough */
- case SNDRV_PCM_TRIGGER_RESUME:
- case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- pr_debug("%s: Trigger start\n", __func__);
- q6asm_run_nowait(prtd->audio_client, 0, 0, 0);
- atomic_set(&prtd->start, 1);
- break;
- case SNDRV_PCM_TRIGGER_STOP:
- pr_debug("SNDRV_PCM_TRIGGER_STOP\n");
- if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
- switch (compr->info.codec_param.codec.id) {
- case SND_AUDIOCODEC_AMRWB:
- break;
- default:
- msm_pcm_routing_reg_psthr_stream(
- soc_prtd->dai_link->id,
- prtd->session_id, substream->stream);
- break;
- }
- }
- atomic_set(&prtd->start, 0);
- runtime->render_flag &= ~SNDRV_RENDER_STOPPED;
- break;
- case SNDRV_PCM_TRIGGER_SUSPEND:
- case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- pr_debug("SNDRV_PCM_TRIGGER_PAUSE\n");
- q6asm_cmd_nowait(prtd->audio_client, CMD_PAUSE);
- atomic_set(&prtd->start, 0);
- runtime->render_flag &= ~SNDRV_RENDER_STOPPED;
- break;
- default:
- ret = -EINVAL;
- break;
- }
-
- return ret;
-}
-
-static void populate_codec_list(struct compr_audio *compr,
- struct snd_pcm_runtime *runtime)
-{
- pr_debug("%s\n", __func__);
- /* MP3 Block */
- compr->info.compr_cap.num_codecs = 5;
- compr->info.compr_cap.min_fragment_size = runtime->hw.period_bytes_min;
- compr->info.compr_cap.max_fragment_size = runtime->hw.period_bytes_max;
- compr->info.compr_cap.min_fragments = runtime->hw.periods_min;
- compr->info.compr_cap.max_fragments = runtime->hw.periods_max;
- compr->info.compr_cap.codecs[0] = SND_AUDIOCODEC_MP3;
- compr->info.compr_cap.codecs[1] = SND_AUDIOCODEC_AAC;
- compr->info.compr_cap.codecs[2] = SND_AUDIOCODEC_AC3;
- compr->info.compr_cap.codecs[3] = SND_AUDIOCODEC_EAC3;
- compr->info.compr_cap.codecs[4] = SND_AUDIOCODEC_AMRWB;
- /* Add new codecs here */
-}
-
-static int msm_compr_open(struct snd_pcm_substream *substream)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct compr_audio *compr;
- struct msm_audio *prtd;
- int ret = 0;
-
- pr_debug("%s\n", __func__);
- compr = kzalloc(sizeof(struct compr_audio), GFP_KERNEL);
- if (compr == NULL) {
- pr_err("Failed to allocate memory for msm_audio\n");
- return -ENOMEM;
- }
- prtd = &compr->prtd;
- prtd->substream = substream;
- runtime->render_flag = SNDRV_DMA_MODE;
- prtd->audio_client = q6asm_audio_client_alloc(
- (app_cb)compr_event_handler, compr);
- if (!prtd->audio_client) {
- pr_info("%s: Could not allocate memory\n", __func__);
- kfree(prtd);
- return -ENOMEM;
- }
-
- prtd->audio_client->perf_mode = false;
- pr_info("%s: session ID %d\n", __func__, prtd->audio_client->session);
-
- prtd->session_id = prtd->audio_client->session;
-
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- runtime->hw = msm_compr_hardware_playback;
- prtd->cmd_ack = 1;
- } else {
- runtime->hw = msm_compr_hardware_capture;
- }
-
-
- ret = snd_pcm_hw_constraint_list(runtime, 0,
- SNDRV_PCM_HW_PARAM_RATE,
- &constraints_sample_rates);
- if (ret < 0)
- pr_info("snd_pcm_hw_constraint_list failed\n");
- /* Ensure that buffer size is a multiple of period size */
- ret = snd_pcm_hw_constraint_integer(runtime,
- SNDRV_PCM_HW_PARAM_PERIODS);
- if (ret < 0)
- pr_info("snd_pcm_hw_constraint_integer failed\n");
-
- prtd->dsp_cnt = 0;
- atomic_set(&prtd->pending_buffer, 1);
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- compr->codec = FORMAT_MP3;
- populate_codec_list(compr, runtime);
- runtime->private_data = compr;
- atomic_set(&prtd->eos, 0);
- return 0;
-}
-
-static int compressed_set_volume(struct msm_audio *prtd, uint32_t volume)
-{
- int rc = 0;
- int avg_vol = 0;
- int lgain = (volume >> 16) & 0xFFFF;
- int rgain = volume & 0xFFFF;
-
- if (prtd && prtd->audio_client) {
- pr_debug("%s: channels %d volume 0x%x\n", __func__,
- prtd->channel_mode, volume);
- if ((prtd->channel_mode == 2) &&
- (lgain != rgain)) {
- pr_debug("%s: call q6asm_set_lrgain\n", __func__);
- rc = q6asm_set_lrgain(prtd->audio_client, lgain, rgain);
- } else {
- avg_vol = (lgain + rgain)/2;
- pr_debug("%s: call q6asm_set_volume\n", __func__);
- rc = q6asm_set_volume(prtd->audio_client, avg_vol);
- }
- if (rc < 0) {
- pr_err("%s: Send Volume command failed rc=%d\n",
- __func__, rc);
- }
- }
- return rc;
-}
-
-static int msm_compr_playback_close(struct snd_pcm_substream *substream)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
- struct compr_audio *compr = runtime->private_data;
- struct msm_audio *prtd = &compr->prtd;
- int dir = 0;
-
- pr_debug("%s\n", __func__);
-
- dir = IN;
- atomic_set(&prtd->pending_buffer, 0);
-
- prtd->pcm_irq_pos = 0;
- q6asm_cmd(prtd->audio_client, CMD_CLOSE);
- q6asm_audio_client_buf_free_contiguous(dir,
- prtd->audio_client);
- msm_pcm_routing_dereg_phy_stream(
- soc_prtd->dai_link->id,
- SNDRV_PCM_STREAM_PLAYBACK);
- q6asm_audio_client_free(prtd->audio_client);
- kfree(prtd);
- return 0;
-}
-
-static int msm_compr_capture_close(struct snd_pcm_substream *substream)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
- struct compr_audio *compr = runtime->private_data;
- struct msm_audio *prtd = &compr->prtd;
- int dir = OUT;
-
- pr_debug("%s\n", __func__);
- atomic_set(&prtd->pending_buffer, 0);
- q6asm_cmd(prtd->audio_client, CMD_CLOSE);
- q6asm_audio_client_buf_free_contiguous(dir,
- prtd->audio_client);
- msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->id,
- SNDRV_PCM_STREAM_CAPTURE);
- q6asm_audio_client_free(prtd->audio_client);
- kfree(prtd);
- return 0;
-}
-
-static int msm_compr_close(struct snd_pcm_substream *substream)
-{
- int ret = 0;
-
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- ret = msm_compr_playback_close(substream);
- else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
- ret = msm_compr_capture_close(substream);
- return ret;
-}
-
-static int msm_compr_prepare(struct snd_pcm_substream *substream)
-{
- int ret = 0;
-
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- ret = msm_compr_playback_prepare(substream);
- else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
- ret = msm_compr_capture_prepare(substream);
- return ret;
-}
-
-static snd_pcm_uframes_t msm_compr_pointer(struct snd_pcm_substream *substream)
-{
-
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct compr_audio *compr = runtime->private_data;
- struct msm_audio *prtd = &compr->prtd;
-
- if (prtd->pcm_irq_pos >= prtd->pcm_size)
- prtd->pcm_irq_pos = 0;
-
- pr_debug("%s: pcm_irq_pos = %d, pcm_size = %d, sample_bits = %d,\n"
- "frame_bits = %d\n", __func__, prtd->pcm_irq_pos,
- prtd->pcm_size, runtime->sample_bits,
- runtime->frame_bits);
- return bytes_to_frames(runtime, (prtd->pcm_irq_pos));
-}
-
-static int msm_compr_mmap(struct snd_pcm_substream *substream,
- struct vm_area_struct *vma)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct msm_audio *prtd = runtime->private_data;
- struct audio_client *ac = prtd->audio_client;
- struct audio_port_data *apd = ac->port;
- struct audio_buffer *ab;
- int dir = -1;
-
- prtd->mmap_flag = 1;
- runtime->render_flag = SNDRV_NON_DMA_MODE;
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- dir = IN;
- else
- dir = OUT;
- ab = &(apd[dir].buf[0]);
-
- return msm_audio_ion_mmap(ab, vma);
-}
-
-static int msm_compr_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct compr_audio *compr = runtime->private_data;
- struct msm_audio *prtd = &compr->prtd;
- struct snd_dma_buffer *dma_buf = &substream->dma_buffer;
- struct audio_buffer *buf;
- int dir, ret;
-
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- dir = IN;
- else
- dir = OUT;
- /* Modifying kernel hardware params based on userspace config */
- if (params_periods(params) > 0 &&
- (params_periods(params) != runtime->hw.periods_max)) {
- runtime->hw.periods_max = params_periods(params);
- }
- if (params_period_bytes(params) > 0 &&
- (params_period_bytes(params) != runtime->hw.period_bytes_min)) {
- runtime->hw.period_bytes_min = params_period_bytes(params);
- }
- runtime->hw.buffer_bytes_max =
- runtime->hw.period_bytes_min * runtime->hw.periods_max;
- pr_debug("allocate %zd buffers each of size %d\n",
- runtime->hw.period_bytes_min,
- runtime->hw.periods_max);
- ret = q6asm_audio_client_buf_alloc_contiguous(dir,
- prtd->audio_client,
- runtime->hw.period_bytes_min,
- runtime->hw.periods_max);
- if (ret < 0) {
- pr_err("Audio Start: Buffer Allocation failed rc = %d\n",
- ret);
- return -ENOMEM;
- }
- buf = prtd->audio_client->port[dir].buf;
-
- dma_buf->dev.type = SNDRV_DMA_TYPE_DEV;
- dma_buf->dev.dev = substream->pcm->card->dev;
- dma_buf->private_data = NULL;
- dma_buf->area = buf[0].data;
- dma_buf->addr = buf[0].phys;
- dma_buf->bytes = runtime->hw.buffer_bytes_max;
-
- pr_debug("%s: buf[%pK]dma_buf->area[%pK]dma_buf->addr[%pK]\n"
- "dma_buf->bytes[%zd]\n", __func__,
- (void *)buf, (void *)dma_buf->area,
- &dma_buf->addr, dma_buf->bytes);
- if (!dma_buf->area)
- return -ENOMEM;
-
- snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
- return 0;
-}
-
-static int msm_compr_ioctl_shared(struct snd_pcm_substream *substream,
- unsigned int cmd, void *arg)
-{
- int rc = 0;
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct compr_audio *compr = runtime->private_data;
- struct msm_audio *prtd = &compr->prtd;
- uint64_t timestamp;
- uint64_t temp;
-
- switch (cmd) {
- case SNDRV_COMPRESS_TSTAMP: {
- struct snd_compr_tstamp *tstamp;
-
- pr_debug("SNDRV_COMPRESS_TSTAMP\n");
- tstamp = arg;
- memset(tstamp, 0x0, sizeof(*tstamp));
- rc = q6asm_get_session_time(prtd->audio_client, ×tamp);
- if (rc < 0) {
- pr_err("%s: Get Session Time return value =%lld\n",
- __func__, timestamp);
- return -EAGAIN;
- }
- temp = (timestamp * 2 * runtime->channels);
- temp = temp * (runtime->rate/1000);
- temp = div_u64(temp, 1000);
- tstamp->sampling_rate = runtime->rate;
- tstamp->timestamp = timestamp;
- pr_debug("%s: bytes_consumed:,timestamp = %lld,\n",
- __func__,
- tstamp->timestamp);
- return 0;
- }
- case SNDRV_COMPRESS_GET_CAPS: {
- struct snd_compr_caps *caps;
-
- caps = arg;
- memset(caps, 0, sizeof(*caps));
- pr_debug("SNDRV_COMPRESS_GET_CAPS\n");
- memcpy(caps, &compr->info.compr_cap, sizeof(*caps));
- return 0;
- }
- case SNDRV_COMPRESS_SET_PARAMS:
- pr_debug("SNDRV_COMPRESS_SET_PARAMS:\n");
- memcpy(&compr->info.codec_param, (void *) arg,
- sizeof(struct snd_compr_params));
- switch (compr->info.codec_param.codec.id) {
- case SND_AUDIOCODEC_MP3:
- /* For MP3 we dont need any other parameter */
- pr_debug("SND_AUDIOCODEC_MP3\n");
- compr->codec = FORMAT_MP3;
- break;
- case SND_AUDIOCODEC_AAC:
- pr_debug("SND_AUDIOCODEC_AAC\n");
- compr->codec = FORMAT_MPEG4_AAC;
- break;
- case SND_AUDIOCODEC_AC3: {
- char params_value[MAX_AC3_PARAM_SIZE];
- int *params_value_data = (int *)params_value;
- /* 36 is the max param length for ddp */
- int i;
- struct snd_dec_ddp *ddp =
- &compr->info.codec_param.codec.options.ddp;
- uint32_t params_length = 0;
-
- memset(params_value, 0, MAX_AC3_PARAM_SIZE);
- /* check integer overflow */
- if (ddp->params_length > UINT_MAX/sizeof(int)) {
- pr_err("%s: Integer overflow ddp->params_length %d\n",
- __func__, ddp->params_length);
- return -EINVAL;
- }
- params_length = ddp->params_length*sizeof(int);
- if (params_length > MAX_AC3_PARAM_SIZE) {
- /*MAX is 36*sizeof(int) this should not happen*/
- pr_err("%s: params_length(%d) is greater than %zd\n",
- __func__, params_length, MAX_AC3_PARAM_SIZE);
- return -EINVAL;
- }
- pr_debug("SND_AUDIOCODEC_AC3\n");
- compr->codec = FORMAT_AC3;
- pr_debug("params_length: %d\n", ddp->params_length);
- for (i = 0; i < params_length/sizeof(int); i++)
- pr_debug("params_value[%d]: %x\n", i,
- params_value_data[i]);
- for (i = 0; i < ddp->params_length/2; i++) {
- ddp->params_id[i] = params_value_data[2*i];
- ddp->params_value[i] = params_value_data[2*i+1];
- }
- if (atomic_read(&prtd->start)) {
- rc = msm_compr_send_ddp_cfg(prtd->audio_client,
- ddp);
- if (rc < 0)
- pr_err("%s: DDP CMD CFG failed\n",
- __func__);
- }
- break;
- }
- case SND_AUDIOCODEC_EAC3: {
- char params_value[MAX_AC3_PARAM_SIZE];
- int *params_value_data = (int *)params_value;
- /* 36 is the max param length for ddp */
- int i;
- struct snd_dec_ddp *ddp =
- &compr->info.codec_param.codec.options.ddp;
- uint32_t params_length = 0;
-
- memset(params_value, 0, MAX_AC3_PARAM_SIZE);
- /* check integer overflow */
- if (ddp->params_length > UINT_MAX/sizeof(int)) {
- pr_err("%s: Integer overflow ddp->params_length %d\n",
- __func__, ddp->params_length);
- return -EINVAL;
- }
- params_length = ddp->params_length*sizeof(int);
- if (params_length > MAX_AC3_PARAM_SIZE) {
- /*MAX is 36*sizeof(int) this should not happen*/
- pr_err("%s: params_length(%d) is greater than %zd\n",
- __func__, params_length, MAX_AC3_PARAM_SIZE);
- return -EINVAL;
- }
- pr_debug("SND_AUDIOCODEC_EAC3\n");
- compr->codec = FORMAT_EAC3;
- pr_debug("params_length: %d\n", ddp->params_length);
- for (i = 0; i < ddp->params_length; i++)
- pr_debug("params_value[%d]: %x\n", i,
- params_value_data[i]);
- for (i = 0; i < ddp->params_length/2; i++) {
- ddp->params_id[i] = params_value_data[2*i];
- ddp->params_value[i] = params_value_data[2*i+1];
- }
- if (atomic_read(&prtd->start)) {
- rc = msm_compr_send_ddp_cfg(prtd->audio_client,
- ddp);
- if (rc < 0)
- pr_err("%s: DDP CMD CFG failed\n",
- __func__);
- }
- break;
- }
- default:
- pr_debug("FORMAT_LINEAR_PCM\n");
- compr->codec = FORMAT_LINEAR_PCM;
- break;
- }
- return 0;
- case SNDRV_PCM_IOCTL1_RESET:
- pr_debug("SNDRV_PCM_IOCTL1_RESET\n");
- /* Flush only when session is started during CAPTURE,
- * while PLAYBACK has no such restriction.
- */
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ||
- (substream->stream == SNDRV_PCM_STREAM_CAPTURE &&
- atomic_read(&prtd->start))) {
- if (atomic_read(&prtd->eos)) {
- prtd->cmd_interrupt = 1;
- wake_up(&the_locks.eos_wait);
- atomic_set(&prtd->eos, 0);
- }
-
- /* A unlikely race condition possible with FLUSH
- * DRAIN if ack is set by flush and reset by drain
- */
- prtd->cmd_ack = 0;
- rc = q6asm_cmd(prtd->audio_client, CMD_FLUSH);
- if (rc < 0) {
- pr_err("%s: flush cmd failed rc=%d\n",
- __func__, rc);
- return rc;
- }
- rc = wait_event_timeout(the_locks.flush_wait,
- prtd->cmd_ack, 5 * HZ);
- if (!rc)
- pr_err("Flush cmd timeout\n");
- prtd->pcm_irq_pos = 0;
- }
- break;
- case SNDRV_COMPRESS_DRAIN:
- pr_debug("%s: SNDRV_COMPRESS_DRAIN\n", __func__);
- if (atomic_read(&prtd->pending_buffer)) {
- pr_debug("%s: no pending writes, drain would block\n",
- __func__);
- return -EWOULDBLOCK;
- }
-
- atomic_set(&prtd->eos, 1);
- atomic_set(&prtd->pending_buffer, 0);
- prtd->cmd_ack = 0;
- q6asm_cmd_nowait(prtd->audio_client, CMD_EOS);
- /* Wait indefinitely for DRAIN. Flush can also signal this*/
- rc = wait_event_interruptible(the_locks.eos_wait,
- (prtd->cmd_ack || prtd->cmd_interrupt));
-
- if (rc < 0)
- pr_err("EOS cmd interrupted\n");
- pr_debug("%s: SNDRV_COMPRESS_DRAIN out of wait\n", __func__);
-
- if (prtd->cmd_interrupt)
- rc = -EINTR;
-
- prtd->cmd_interrupt = 0;
- return rc;
- default:
- break;
- }
- return snd_pcm_lib_ioctl(substream, cmd, arg);
-}
-#ifdef CONFIG_COMPAT
-struct snd_enc_wma32 {
- u32 super_block_align; /* WMA Type-specific data */
- u32 encodeopt1;
- u32 encodeopt2;
-};
-
-struct snd_enc_vorbis32 {
- s32 quality;
- u32 managed;
- u32 max_bit_rate;
- u32 min_bit_rate;
- u32 downmix;
-};
-
-struct snd_enc_real32 {
- u32 quant_bits;
- u32 start_region;
- u32 num_regions;
-};
-
-struct snd_enc_flac32 {
- u32 num;
- u32 gain;
-};
-
-struct snd_enc_generic32 {
- u32 bw; /* encoder bandwidth */
- s32 reserved[15];
-};
-struct snd_dec_ddp32 {
- u32 params_length;
- u32 params_id[18];
- u32 params_value[18];
-};
-
-union snd_codec_options32 {
- struct snd_enc_wma32 wma;
- struct snd_enc_vorbis32 vorbis;
- struct snd_enc_real32 real;
- struct snd_enc_flac32 flac;
- struct snd_enc_generic32 generic;
- struct snd_dec_ddp32 ddp;
-};
-
-struct snd_codec32 {
- u32 id;
- u32 ch_in;
- u32 ch_out;
- u32 sample_rate;
- u32 bit_rate;
- u32 rate_control;
- u32 profile;
- u32 level;
- u32 ch_mode;
- u32 format;
- u32 align;
- union snd_codec_options32 options;
- u32 reserved[3];
-};
-
-struct snd_compressed_buffer32 {
- u32 fragment_size;
- u32 fragments;
-};
-
-struct snd_compr_params32 {
- struct snd_compressed_buffer32 buffer;
- struct snd_codec32 codec;
- u8 no_wake_mode;
-};
-
-struct snd_compr_caps32 {
- u32 num_codecs;
- u32 direction;
- u32 min_fragment_size;
- u32 max_fragment_size;
- u32 min_fragments;
- u32 max_fragments;
- u32 codecs[MAX_NUM_CODECS];
- u32 reserved[11];
-};
-struct snd_compr_tstamp32 {
- u32 byte_offset;
- u32 copied_total;
- compat_ulong_t pcm_frames;
- compat_ulong_t pcm_io_frames;
- u32 sampling_rate;
- compat_u64 timestamp;
-};
-enum {
- SNDRV_COMPRESS_TSTAMP32 = _IOR('C', 0x20, struct snd_compr_tstamp32),
- SNDRV_COMPRESS_GET_CAPS32 = _IOWR('C', 0x10, struct snd_compr_caps32),
- SNDRV_COMPRESS_SET_PARAMS32 =
- _IOW('C', 0x12, struct snd_compr_params32),
-};
-static int msm_compr_compat_ioctl(struct snd_pcm_substream *substream,
- unsigned int cmd, void *arg)
-{
- int err = 0;
-
- switch (cmd) {
- case SNDRV_COMPRESS_TSTAMP32: {
- struct snd_compr_tstamp tstamp;
- struct snd_compr_tstamp32 tstamp32;
-
- memset(&tstamp, 0, sizeof(tstamp));
- memset(&tstamp32, 0, sizeof(tstamp32));
- cmd = SNDRV_COMPRESS_TSTAMP;
- err = msm_compr_ioctl_shared(substream, cmd, &tstamp);
- if (err) {
- pr_err("%s: COMPRESS_TSTAMP failed rc %d\n",
- __func__, err);
- goto bail_out;
- }
- tstamp32.byte_offset = tstamp.byte_offset;
- tstamp32.copied_total = tstamp.copied_total;
- tstamp32.pcm_frames = tstamp.pcm_frames;
- tstamp32.pcm_io_frames = tstamp.pcm_io_frames;
- tstamp32.sampling_rate = tstamp.sampling_rate;
- tstamp32.timestamp = tstamp.timestamp;
- if (copy_to_user(arg, &tstamp32, sizeof(tstamp32))) {
- pr_err("%s: copytouser failed COMPRESS_TSTAMP32\n",
- __func__);
- err = -EFAULT;
- }
- break;
- }
- case SNDRV_COMPRESS_GET_CAPS32: {
- struct snd_compr_caps caps;
- struct snd_compr_caps32 caps32;
- u32 i;
-
- memset(&caps, 0, sizeof(caps));
- memset(&caps32, 0, sizeof(caps32));
- cmd = SNDRV_COMPRESS_GET_CAPS;
- err = msm_compr_ioctl_shared(substream, cmd, &caps);
- if (err) {
- pr_err("%s: GET_CAPS failed rc %d\n",
- __func__, err);
- goto bail_out;
- }
- pr_debug("SNDRV_COMPRESS_GET_CAPS_32\n");
- if (!err && caps.num_codecs >= MAX_NUM_CODECS) {
- pr_err("%s: Invalid number of codecs\n", __func__);
- err = -EINVAL;
- goto bail_out;
- }
- caps32.direction = caps.direction;
- caps32.max_fragment_size = caps.max_fragment_size;
- caps32.max_fragments = caps.max_fragments;
- caps32.min_fragment_size = caps.min_fragment_size;
- caps32.num_codecs = caps.num_codecs;
- for (i = 0; i < caps.num_codecs; i++)
- caps32.codecs[i] = caps.codecs[i];
- if (copy_to_user(arg, &caps32, sizeof(caps32))) {
- pr_err("%s: copytouser failed COMPRESS_GETCAPS32\n",
- __func__);
- err = -EFAULT;
- }
- break;
- }
- case SNDRV_COMPRESS_SET_PARAMS32: {
- struct snd_compr_params32 params32;
- struct snd_compr_params params;
-
- memset(¶ms32, 0, sizeof(params32));
- memset(¶ms, 0, sizeof(params));
- cmd = SNDRV_COMPRESS_SET_PARAMS;
- if (copy_from_user(¶ms32, arg, sizeof(params32))) {
- pr_err("%s: copyfromuser failed SET_PARAMS32\n",
- __func__);
- err = -EFAULT;
- goto bail_out;
- }
- params.no_wake_mode = params32.no_wake_mode;
- params.codec.id = params32.codec.id;
- params.codec.ch_in = params32.codec.ch_in;
- params.codec.ch_out = params32.codec.ch_out;
- params.codec.sample_rate = params32.codec.sample_rate;
- params.codec.bit_rate = params32.codec.bit_rate;
- params.codec.rate_control = params32.codec.rate_control;
- params.codec.profile = params32.codec.profile;
- params.codec.level = params32.codec.level;
- params.codec.ch_mode = params32.codec.ch_mode;
- params.codec.format = params32.codec.format;
- params.codec.align = params32.codec.align;
-
- switch (params.codec.id) {
- case SND_AUDIOCODEC_WMA:
- case SND_AUDIOCODEC_WMA_PRO:
- params.codec.options.wma.encodeopt1 =
- params32.codec.options.wma.encodeopt1;
- params.codec.options.wma.encodeopt2 =
- params32.codec.options.wma.encodeopt2;
- params.codec.options.wma.super_block_align =
- params32.codec.options.wma.super_block_align;
- break;
- case SND_AUDIOCODEC_VORBIS:
- params.codec.options.vorbis.downmix =
- params32.codec.options.vorbis.downmix;
- params.codec.options.vorbis.managed =
- params32.codec.options.vorbis.managed;
- params.codec.options.vorbis.max_bit_rate =
- params32.codec.options.vorbis.max_bit_rate;
- params.codec.options.vorbis.min_bit_rate =
- params32.codec.options.vorbis.min_bit_rate;
- params.codec.options.vorbis.quality =
- params32.codec.options.vorbis.quality;
- break;
- case SND_AUDIOCODEC_REAL:
- params.codec.options.real.num_regions =
- params32.codec.options.real.num_regions;
- params.codec.options.real.quant_bits =
- params32.codec.options.real.quant_bits;
- params.codec.options.real.start_region =
- params32.codec.options.real.start_region;
- break;
- case SND_AUDIOCODEC_FLAC:
- params.codec.options.flac.gain =
- params32.codec.options.flac.gain;
- params.codec.options.flac.num =
- params32.codec.options.flac.num;
- break;
- case SND_AUDIOCODEC_DTS:
- case SND_AUDIOCODEC_DTS_PASS_THROUGH:
- case SND_AUDIOCODEC_DTS_LBR:
- case SND_AUDIOCODEC_DTS_LBR_PASS_THROUGH:
- case SND_AUDIOCODEC_DTS_TRANSCODE_LOOPBACK:
- break;
- case SND_AUDIOCODEC_AC3:
- case SND_AUDIOCODEC_EAC3:
- params.codec.options.ddp.params_length =
- params32.codec.options.ddp.params_length;
- memcpy(params.codec.options.ddp.params_value,
- params32.codec.options.ddp.params_value,
- sizeof(params32.codec.options.ddp.params_value));
- memcpy(params.codec.options.ddp.params_id,
- params32.codec.options.ddp.params_id,
- sizeof(params32.codec.options.ddp.params_id));
- break;
- default:
- params.codec.options.generic.bw =
- params32.codec.options.generic.bw;
- break;
- }
- if (!err)
- err = msm_compr_ioctl_shared(substream, cmd, ¶ms);
- break;
- }
- default:
- err = msm_compr_ioctl_shared(substream, cmd, arg);
- }
-bail_out:
- return err;
-
-}
-#endif
-static int msm_compr_ioctl(struct snd_pcm_substream *substream,
- unsigned int cmd, void *arg)
-{
- int err = 0;
-
- if (!substream) {
- pr_err("%s: Invalid params\n", __func__);
- return -EINVAL;
- }
- pr_debug("%s called with cmd = %d\n", __func__, cmd);
- switch (cmd) {
- case SNDRV_COMPRESS_TSTAMP: {
- struct snd_compr_tstamp tstamp;
-
- if (!arg) {
- pr_err("%s: Invalid params Tstamp\n", __func__);
- return -EINVAL;
- }
- err = msm_compr_ioctl_shared(substream, cmd, &tstamp);
- if (err)
- pr_err("%s: COMPRESS_TSTAMP failed rc %d\n",
- __func__, err);
- if (!err && copy_to_user(arg, &tstamp, sizeof(tstamp))) {
- pr_err("%s: copytouser failed COMPRESS_TSTAMP\n",
- __func__);
- err = -EFAULT;
- }
- break;
- }
- case SNDRV_COMPRESS_GET_CAPS: {
- struct snd_compr_caps cap;
-
- if (!arg) {
- pr_err("%s: Invalid params getcaps\n", __func__);
- return -EINVAL;
- }
- pr_debug("SNDRV_COMPRESS_GET_CAPS\n");
- err = msm_compr_ioctl_shared(substream, cmd, &cap);
- if (err)
- pr_err("%s: GET_CAPS failed rc %d\n",
- __func__, err);
- if (!err && copy_to_user(arg, &cap, sizeof(cap))) {
- pr_err("%s: copytouser failed GET_CAPS\n",
- __func__);
- err = -EFAULT;
- }
- break;
- }
- case SNDRV_COMPRESS_SET_PARAMS: {
- struct snd_compr_params params;
-
- if (!arg) {
- pr_err("%s: Invalid params setparam\n", __func__);
- return -EINVAL;
- }
- if (copy_from_user(¶ms, arg,
- sizeof(struct snd_compr_params))) {
- pr_err("%s: SET_PARAMS\n", __func__);
- return -EFAULT;
- }
- err = msm_compr_ioctl_shared(substream, cmd, ¶ms);
- if (err)
- pr_err("%s: SET_PARAMS failed rc %d\n",
- __func__, err);
- break;
- }
- default:
- err = msm_compr_ioctl_shared(substream, cmd, arg);
- }
- return err;
-}
-
-static int msm_compr_restart(struct snd_pcm_substream *substream)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct compr_audio *compr = runtime->private_data;
- struct msm_audio *prtd = &compr->prtd;
- struct audio_aio_write_param param;
- struct audio_buffer *buf = NULL;
- struct output_meta_data_st output_meta_data;
- int time_stamp_flag = 0;
- int buffer_length = 0;
-
- pr_debug("%s, trigger restart\n", __func__);
-
- if (runtime->render_flag & SNDRV_RENDER_STOPPED) {
- buf = prtd->audio_client->port[IN].buf;
- pr_debug("%s:writing %d bytes of buffer[%d] to dsp 2\n",
- __func__, prtd->pcm_count, prtd->out_head);
- pr_debug("%s:writing buffer[%d] from 0x%08x\n",
- __func__, prtd->out_head,
- ((unsigned int)buf[0].phys
- + (prtd->out_head * prtd->pcm_count)));
-
- if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE)
- time_stamp_flag = SET_TIMESTAMP;
- else
- time_stamp_flag = NO_TIMESTAMP;
- memcpy(&output_meta_data, (char *)(buf->data +
- prtd->out_head * prtd->pcm_count),
- COMPRE_OUTPUT_METADATA_SIZE);
-
- buffer_length = output_meta_data.frame_size;
- pr_debug("meta_data_length: %d, frame_length: %d\n",
- output_meta_data.meta_data_length,
- output_meta_data.frame_size);
- pr_debug("timestamp_msw: %d, timestamp_lsw: %d\n",
- output_meta_data.timestamp_msw,
- output_meta_data.timestamp_lsw);
-
- param.paddr = (unsigned long)buf[0].phys
- + (prtd->out_head * prtd->pcm_count)
- + output_meta_data.meta_data_length;
- param.len = buffer_length;
- param.msw_ts = output_meta_data.timestamp_msw;
- param.lsw_ts = output_meta_data.timestamp_lsw;
- param.flags = time_stamp_flag;
- param.uid = prtd->session_id;
- if (q6asm_async_write(prtd->audio_client,
- ¶m) < 0)
- pr_err("%s:q6asm_async_write failed\n",
- __func__);
- else
- prtd->out_head =
- (prtd->out_head + 1) & (runtime->periods - 1);
-
- runtime->render_flag &= ~SNDRV_RENDER_STOPPED;
- return 0;
- }
- return 0;
-}
-
-static int msm_compr_volume_ctl_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- int rc = 0;
- struct snd_pcm_volume *vol = snd_kcontrol_chip(kcontrol);
- struct snd_pcm_substream *substream =
- vol->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
- struct msm_audio *prtd;
- int volume = ucontrol->value.integer.value[0];
-
- pr_debug("%s: volume : %x\n", __func__, volume);
- if (!substream)
- return -ENODEV;
- if (!substream->runtime)
- return 0;
- prtd = substream->runtime->private_data;
- if (prtd)
- rc = compressed_set_volume(prtd, volume);
-
- return rc;
-}
-
-static int msm_compr_volume_ctl_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_pcm_volume *vol = snd_kcontrol_chip(kcontrol);
- struct snd_pcm_substream *substream =
- vol->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
- struct msm_audio *prtd;
-
- pr_debug("%s\n", __func__);
- if (!substream)
- return -ENODEV;
- if (!substream->runtime)
- return 0;
- prtd = substream->runtime->private_data;
- if (prtd)
- ucontrol->value.integer.value[0] = prtd->volume;
- return 0;
-}
-
-static int msm_compr_add_controls(struct snd_soc_pcm_runtime *rtd)
-{
- int ret = 0;
- struct snd_pcm *pcm = rtd->pcm;
- struct snd_pcm_volume *volume_info;
- struct snd_kcontrol *kctl;
-
- dev_dbg(rtd->dev, "%s, Volume cntrl add\n", __func__);
- ret = snd_pcm_add_volume_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
- NULL, 1, rtd->dai_link->id,
- &volume_info);
- if (ret < 0)
- return ret;
- kctl = volume_info->kctl;
- kctl->put = msm_compr_volume_ctl_put;
- kctl->get = msm_compr_volume_ctl_get;
- kctl->tlv.p = compr_rx_vol_gain;
- return 0;
-}
-
-static const struct snd_pcm_ops msm_compr_ops = {
- .open = msm_compr_open,
- .hw_params = msm_compr_hw_params,
- .close = msm_compr_close,
- .ioctl = msm_compr_ioctl,
- .prepare = msm_compr_prepare,
- .trigger = msm_compr_trigger,
- .pointer = msm_compr_pointer,
- .mmap = msm_compr_mmap,
- .restart = msm_compr_restart,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = msm_compr_compat_ioctl,
-#endif
-};
-
-static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_card *card = rtd->card->snd_card;
- int ret = 0;
-
- if (!card->dev->coherent_dma_mask)
- card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
-
- ret = msm_compr_add_controls(rtd);
- if (ret)
- pr_err("%s, kctl add failed\n", __func__);
- return ret;
-}
-
-static struct snd_soc_platform_driver msm_soc_platform = {
- .ops = &msm_compr_ops,
- .pcm_new = msm_asoc_pcm_new,
-};
-
-static int msm_compr_probe(struct platform_device *pdev)
-{
-
- dev_info(&pdev->dev, "%s: dev name %s\n",
- __func__, dev_name(&pdev->dev));
-
- return snd_soc_register_platform(&pdev->dev,
- &msm_soc_platform);
-}
-
-static int msm_compr_remove(struct platform_device *pdev)
-{
- snd_soc_unregister_platform(&pdev->dev);
- return 0;
-}
-
-static const struct of_device_id msm_compr_dt_match[] = {
- {.compatible = "qcom,msm-compr-dsp"},
- {}
-};
-MODULE_DEVICE_TABLE(of, msm_compr_dt_match);
-
-static struct platform_driver msm_compr_driver = {
- .driver = {
- .name = "msm-compr-dsp",
- .owner = THIS_MODULE,
- .of_match_table = msm_compr_dt_match,
- },
- .probe = msm_compr_probe,
- .remove = msm_compr_remove,
-};
-
-static int __init msm_soc_platform_init(void)
-{
- init_waitqueue_head(&the_locks.enable_wait);
- init_waitqueue_head(&the_locks.eos_wait);
- init_waitqueue_head(&the_locks.write_wait);
- init_waitqueue_head(&the_locks.read_wait);
- init_waitqueue_head(&the_locks.flush_wait);
-
- return platform_driver_register(&msm_compr_driver);
-}
-module_init(msm_soc_platform_init);
-
-static void __exit msm_soc_platform_exit(void)
-{
- platform_driver_unregister(&msm_compr_driver);
-}
-module_exit(msm_soc_platform_exit);
-
-MODULE_DESCRIPTION("PCM module platform driver");
-MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.h b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.h
deleted file mode 100644
index d6e3ec6..0000000
--- a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (c) 2012, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#ifndef _MSM_COMPR_H
-#define _MSM_COMPR_H
-#include <sound/apr_audio-v2.h>
-#include <sound/q6asm-v2.h>
-#include <sound/compress_params.h>
-#include <sound/compress_offload.h>
-#include <sound/compress_driver.h>
-
-#include "msm-pcm-q6-v2.h"
-
-struct compr_info {
- struct snd_compr_caps compr_cap;
- struct snd_compr_codec_caps codec_caps;
- struct snd_compr_params codec_param;
-};
-
-struct compr_audio {
- struct msm_audio prtd;
- struct compr_info info;
- uint32_t codec;
-};
-
-#endif /*_MSM_COMPR_H*/