[RFC PATCH] drm/bridge: add support for DSC in mhdp8546 driver

From: Damian Kos
Date: Thu Nov 08 2018 - 11:21:30 EST


From: Przemyslaw Gaj <pgaj@xxxxxxxxxxx>

This patch enables DSC (Digital Stream Compression) on Cadence DisplayPort
controller.

I think that a little bit of an explanation is needed here from our side
before we go into the patch contents.
One might ask, why not just put everything together for mhdp8546 IP and send
it when it's actually complete?
Well, the original mhdp8546 driver was ready in January and supported only SST
mode at that time. MST, DSC, FEC and HDCP were distant future things back then.
Unfortunately, when we were preparing to submit it, it turned out that there's
already a driver for cdns dp (though, quite different IP). That held us till
July when we've sent the first patch and started the review process.
DSC, FEC, HDCP were still, pretty much, nonexistent and the MST was slowly
moving towards the testing stage. In the last mhdp8546 patch version (v6)
we've included the MST and PHY support, but received comment that is not a
nice thing to do, especially when no one was asking for it. Thus, this (and
FEC) patch is sent as a separate one.

Please let us know if they can be (should be?) appended to mhdp8546 patch
series v7 :)

Anyway, back to the DSC patch. The DSC here relies on the code that is present
in Intel's patch https://patchwork.kernel.org/cover/10596631/ which is not yet
in the mainline. So... we did a not very pretty copy&paste hack and included
some of its code in our code (these parts are easy to identify as they're
explicitly marked, so please ignore them) just to have it running and the DSC
is working fine (all patches we've send are made from a working code).
We know that this is a no-no and because of that this patch will be rejected.
We only ask for comments on non-borrowed code. Any suggestions on how to deal
with relying on not-yet-in-mainline code are also welcome.

Signed-off-by: Przemyslaw Gaj <pgaj@xxxxxxxxxxx>
Signed-off-by: Damian Kos <dkos@xxxxxxxxxxx>
---
drivers/gpu/drm/bridge/Makefile | 2 +-
drivers/gpu/drm/bridge/cdns-mhdp-dsc.c | 1468 ++++++++++++++++++++++++
drivers/gpu/drm/bridge/cdns-mhdp-dsc.h | 304 +++++
drivers/gpu/drm/bridge/cdns-mhdp-mst.c | 2 +-
drivers/gpu/drm/bridge/cdns-mhdp.c | 105 +-
drivers/gpu/drm/bridge/cdns-mhdp.h | 9 +-
include/drm/bridge/cdns-mhdp-common.h | 520 +++++++++
7 files changed, 2381 insertions(+), 29 deletions(-)
create mode 100644 drivers/gpu/drm/bridge/cdns-mhdp-dsc.c
create mode 100644 drivers/gpu/drm/bridge/cdns-mhdp-dsc.h

diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
index b80f3d6ed2a6..ca3622fd715f 100644
--- a/drivers/gpu/drm/bridge/Makefile
+++ b/drivers/gpu/drm/bridge/Makefile
@@ -19,4 +19,4 @@ obj-$(CONFIG_DRM_TI_TFP410) += ti-tfp410.o
obj-$(CONFIG_DRM_CDNS_MHDP) += mhdp8546.o
obj-y += synopsys/

-mhdp8546-objs := cdns-mhdp-common.o cdns-mhdp.o cdns-mhdp-mst.o
+mhdp8546-objs := cdns-mhdp-common.o cdns-mhdp.o cdns-mhdp-mst.o cdns-mhdp-dsc.o
diff --git a/drivers/gpu/drm/bridge/cdns-mhdp-dsc.c b/drivers/gpu/drm/bridge/cdns-mhdp-dsc.c
new file mode 100644
index 000000000000..742e893d9a01
--- /dev/null
+++ b/drivers/gpu/drm/bridge/cdns-mhdp-dsc.c
@@ -0,0 +1,1468 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) Cadence Design Systems, Inc.
+ * Author: Przemyslaw Gaj <pgaj@xxxxxxxxxxx>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+#include <drm/drm_dp_helper.h>
+#include <drm/bridge/cdns-mhdp-common.h>
+
+#include "cdns-mhdp.h"
+#include "cdns-mhdp-dsc.h"
+
+/*
+ * TODO DK: The following functions and declarations are borrowed from
+ * drm/drm_dsc.c and drm/drm_dp_helper.c introduced in not-yet-accepted
+ * patch: https://patchwork.kernel.org/cover/10596631/
+ * Remove when patch is accepted.
+ */
+
+#define DP_SDP_PPS_HEADER_PAYLOAD_BYTES_MINUS_1 0x7F
+
+#define DP_DSC_RC_PIXELS_PER_GROUP 3
+#define DP_DSC_SCALE_DECREMENT_INTERVAL_MAX 4095
+#define DP_DSC_RECEIVER_CAP_SIZE 0xf
+
+struct rc_params {
+ u16 initial_xmit_delay;
+ u8 first_line_bpg_offset;
+ u16 initial_offset;
+ u8 flatness_min_qp;
+ u8 flatness_max_qp;
+ u8 rc_quant_incr_limit0;
+ u8 rc_quant_incr_limit1;
+ struct dsc_rc_range_params rc_range_params[DSC_NUM_BUF_RANGES];
+};
+
+/**
+ * dsc_dp_pps_header_init() - Initializes the PPS Header
+ * for DisplayPort as per the DP 1.4 spec.
+ * @pps_sdp: Secondary data packet for DSC Picture Parameter Set
+ */
+static void dsc_dp_pps_header_init(struct dsc_pps_infoframe *pps_sdp)
+{
+ memset(&pps_sdp->pps_header, 0, sizeof(pps_sdp->pps_header));
+
+ pps_sdp->pps_header.HB1 = DP_SDP_PPS;
+ pps_sdp->pps_header.HB2 = DP_SDP_PPS_HEADER_PAYLOAD_BYTES_MINUS_1;
+}
+
+static u8 dp_dsc_sink_line_buf_depth(
+ const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE])
+{
+ u8 line_buf_depth = dsc_dpcd[DP_DSC_LINE_BUF_BIT_DEPTH - DP_DSC_SUPPORT];
+
+ switch (line_buf_depth & DP_DSC_LINE_BUF_BIT_DEPTH_MASK) {
+ case DP_DSC_LINE_BUF_BIT_DEPTH_9:
+ return 9;
+ case DP_DSC_LINE_BUF_BIT_DEPTH_10:
+ return 10;
+ case DP_DSC_LINE_BUF_BIT_DEPTH_11:
+ return 11;
+ case DP_DSC_LINE_BUF_BIT_DEPTH_12:
+ return 12;
+ case DP_DSC_LINE_BUF_BIT_DEPTH_13:
+ return 13;
+ case DP_DSC_LINE_BUF_BIT_DEPTH_14:
+ return 14;
+ case DP_DSC_LINE_BUF_BIT_DEPTH_15:
+ return 15;
+ case DP_DSC_LINE_BUF_BIT_DEPTH_16:
+ return 16;
+ case DP_DSC_LINE_BUF_BIT_DEPTH_8:
+ return 8;
+ }
+
+ return 0;
+}
+/** XXX DK: End of borrowed stuff. */
+
+// DSC spec recommended values
+static u16 rc_buf_thresh[] = {
+ 896, 1792, 2688, 3584, 4480, 5376, 6272, 6720, 7168, 7616,
+ 7744, 7872, 8000, 8064
+};
+
+// DSC spec recommended values
+static struct rc_params rc_params[][MAX_COLUMN_INDEX] = {
+{
+ /* 6BPP/8BPC */
+ { 768, 15, 6144, 3, 13, 11, 11, {
+ { 0, 4, 0 }, { 1, 6, -2 }, { 3, 8, -2 }, { 4, 8, -4 },
+ { 5, 9, -6 }, { 5, 9, -6 }, { 6, 9, -6 }, { 6, 10, -8 },
+ { 7, 11, -8 }, { 8, 12, -10 }, { 9, 12, -10 }, { 10, 12, -12 },
+ { 10, 12, -12 }, { 11, 12, -12 }, { 13, 14, -12 }
+ }
+ },
+ /* 6BPP/10BPC */
+ { 768, 15, 6144, 7, 17, 15, 15, {
+ { 0, 8, 0 }, { 3, 10, -2 }, { 7, 12, -2 }, { 8, 12, -4 },
+ { 9, 13, -6 }, { 9, 13, -6 }, { 10, 13, -6 }, { 10, 14, -8 },
+ { 11, 15, -8 }, { 12, 16, -10 }, { 13, 16, -10 },
+ { 14, 16, -12 }, { 14, 16, -12 }, { 15, 16, -12 },
+ { 17, 18, -12 }
+ }
+ },
+ /* 6BPP/12BPC */
+ { 768, 15, 6144, 11, 21, 19, 19, {
+ { 0, 12, 0 }, { 5, 14, -2 }, { 11, 16, -2 }, { 12, 16, -4 },
+ { 13, 17, -6 }, { 13, 17, -6 }, { 14, 17, -6 }, { 14, 18, -8 },
+ { 15, 19, -8 }, { 16, 20, -10 }, { 17, 20, -10 },
+ { 18, 20, -12 }, { 18, 20, -12 }, { 19, 20, -12 },
+ { 21, 22, -12 }
+ }
+ },
+ /* 6BPP/14BPC */
+ { 768, 15, 6144, 15, 25, 23, 27, {
+ { 0, 16, 0 }, { 7, 18, -2 }, { 15, 20, -2 }, { 16, 20, -4 },
+ { 17, 21, -6 }, { 17, 21, -6 }, { 18, 21, -6 }, { 18, 22, -8 },
+ { 19, 23, -8 }, { 20, 24, -10 }, { 21, 24, -10 },
+ { 22, 24, -12 }, { 22, 24, -12 }, { 23, 24, -12 },
+ { 25, 26, -12 }
+ }
+ },
+ /* 6BPP/16BPC */
+ { 768, 15, 6144, 19, 29, 27, 27, {
+ { 0, 20, 0 }, { 9, 22, -2 }, { 19, 24, -2 }, { 20, 24, -4 },
+ { 21, 25, -6 }, { 21, 25, -6 }, { 22, 25, -6 }, { 22, 26, -8 },
+ { 23, 27, -8 }, { 24, 28, -10 }, { 25, 28, -10 },
+ { 26, 28, -12 }, { 26, 28, -12 }, { 27, 28, -12 },
+ { 29, 30, -12 }
+ }
+ },
+},
+{
+ /* 8BPP/8BPC */
+ { 512, 12, 6144, 3, 12, 11, 11, {
+ { 0, 4, 2 }, { 0, 4, 0 }, { 1, 5, 0 }, { 1, 6, -2 },
+ { 3, 7, -4 }, { 3, 7, -6 }, { 3, 7, -8 }, { 3, 8, -8 },
+ { 3, 9, -8 }, { 3, 10, -10 }, { 5, 11, -10 }, { 5, 12, -12 },
+ { 5, 13, -12 }, { 7, 13, -12 }, { 13, 15, -12 }
+ }
+ },
+ /* 8BPP/10BPC */
+ { 512, 12, 6144, 7, 16, 15, 15, {
+ { 0, 4, 2 }, { 4, 8, 0 }, { 5, 9, 0 }, { 5, 10, -2 },
+ { 7, 11, -4 }, { 7, 11, -6 }, { 7, 11, -8 }, { 7, 12, -8 },
+ { 7, 13, -8 }, { 7, 14, -10 }, { 9, 15, -10 }, { 9, 16, -12 },
+ { 9, 17, -12 }, { 11, 17, -12 }, { 17, 19, -12 }
+ }
+ },
+ /* 8BPP/12BPC */
+ { 512, 12, 6144, 11, 20, 19, 19, {
+ { 0, 12, 2 }, { 4, 12, 0 }, { 9, 13, 0 }, { 9, 14, -2 },
+ { 11, 15, -4 }, { 11, 15, -6 }, { 11, 15, -8 }, { 11, 16, -8 },
+ { 11, 17, -8 }, { 11, 18, -10 }, { 13, 19, -10 },
+ { 13, 20, -12 }, { 13, 21, -12 }, { 15, 21, -12 },
+ { 21, 23, -12 }
+ }
+ },
+ /* 8BPP/14BPC */
+ { 512, 12, 6144, 15, 24, 23, 23, {
+ { 0, 12, 0 }, { 5, 13, 0 }, { 11, 15, 0 }, { 12, 17, -2 },
+ { 15, 19, -4 }, { 15, 19, -6 }, { 15, 19, -8 }, { 15, 20, -8 },
+ { 15, 21, -8 }, { 15, 22, -10 }, { 17, 22, -10 },
+ { 17, 23, -12 }, { 17, 23, -12 }, { 21, 24, -12 },
+ { 24, 25, -12 }
+ }
+ },
+ /* 8BPP/16BPC */
+ { 512, 12, 6144, 19, 28, 27, 27, {
+ { 0, 12, 2 }, { 6, 14, 0 }, { 13, 17, 0 }, { 15, 20, -2 },
+ { 19, 23, -4 }, { 19, 23, -6 }, { 19, 23, -8 }, { 19, 24, -8 },
+ { 19, 25, -8 }, { 19, 26, -10 }, { 21, 26, -10 },
+ { 21, 27, -12 }, { 21, 27, -12 }, { 25, 28, -12 },
+ { 28, 29, -12 }
+ }
+ },
+},
+{
+ /* 10BPP/8BPC */
+ { 410, 15, 5632, 3, 12, 11, 11, {
+ { 0, 3, 2 }, { 0, 4, 0 }, { 1, 5, 0 }, { 2, 6, -2 },
+ { 3, 7, -4 }, { 3, 7, -6 }, { 3, 7, -8 }, { 3, 8, -8 },
+ { 3, 9, -8 }, { 3, 9, -10 }, { 5, 10, -10 }, { 5, 10, -10 },
+ { 5, 11, -12 }, { 7, 11, -12 }, { 11, 12, -12 }
+ }
+ },
+ /* 10BPP/10BPC */
+ { 410, 15, 5632, 7, 16, 15, 15, {
+ { 0, 7, 2 }, { 4, 8, 0 }, { 5, 9, 0 }, { 6, 10, -2 },
+ { 7, 11, -4 }, { 7, 11, -6 }, { 7, 11, -8 }, { 7, 12, -8 },
+ { 7, 13, -8 }, { 7, 13, -10 }, { 9, 14, -10 }, { 9, 14, -10 },
+ { 9, 15, -12 }, { 11, 15, -12 }, { 15, 16, -12 }
+ }
+ },
+ /* 10BPP/12BPC */
+ { 410, 15, 5632, 11, 20, 19, 19, {
+ { 0, 11, 2 }, { 4, 12, 0 }, { 9, 13, 0 }, { 10, 14, -2 },
+ { 11, 15, -4 }, { 11, 15, -6 }, { 11, 15, -8 }, { 11, 16, -8 },
+ { 11, 17, -8 }, { 11, 17, -10 }, { 13, 18, -10 },
+ { 13, 18, -10 }, { 13, 19, -12 }, { 15, 19, -12 },
+ { 19, 20, -12 }
+ }
+ },
+ /* 10BPP/14BPC */
+ { 410, 15, 5632, 15, 24, 23, 23, {
+ { 0, 11, 2 }, { 5, 13, 0 }, { 11, 15, 0 }, { 13, 18, -2 },
+ { 15, 19, -4 }, { 15, 19, -6 }, { 15, 19, -8 }, { 15, 20, -8 },
+ { 15, 21, -8 }, { 15, 21, -10 }, { 17, 22, -10 },
+ { 17, 22, -10 }, { 17, 23, -12 }, { 19, 23, -12 },
+ { 23, 24, -12 }
+ }
+ },
+ /* 10BPP/16BPC */
+ { 410, 15, 5632, 19, 28, 27, 27, {
+ { 0, 11, 2 }, { 6, 14, 0 }, { 13, 17, 0 }, { 16, 20, -2 },
+ { 19, 23, -4 }, { 19, 23, -6 }, { 19, 23, -8 }, { 19, 24, -8 },
+ { 19, 25, -8 }, { 19, 25, -10 }, { 21, 26, -10 },
+ { 21, 26, -10 }, { 21, 27, -12 }, { 23, 27, -12 },
+ { 27, 28, -12 }
+ }
+ },
+},
+{
+ /* 12BPP/8BPC */
+ { 341, 15, 2048, 3, 12, 11, 11, {
+ { 0, 2, 2 }, { 0, 4, 0 }, { 1, 5, 0 }, { 1, 6, -2 },
+ { 3, 7, -4 }, { 3, 7, -6 }, { 3, 7, -8 }, { 3, 8, -8 },
+ { 3, 9, -8 }, { 3, 10, -10 }, { 5, 11, -10 },
+ { 5, 12, -12 }, { 5, 13, -12 }, { 7, 13, -12 }, { 13, 15, -12 }
+ }
+ },
+ /* 12BPP/10BPC */
+ { 341, 15, 2048, 7, 16, 15, 15, {
+ { 0, 2, 2 }, { 2, 5, 0 }, { 3, 7, 0 }, { 4, 8, -2 },
+ { 6, 9, -4 }, { 7, 10, -6 }, { 7, 11, -8 }, { 7, 12, -8 },
+ { 7, 13, -8 }, { 7, 14, -10 }, { 9, 15, -10 }, { 9, 16, -12 },
+ { 9, 17, -12 }, { 11, 17, -12 }, { 17, 19, -12 }
+ }
+ },
+ /* 12BPP/12BPC */
+ { 341, 15, 2048, 11, 20, 19, 19, {
+ { 0, 6, 2 }, { 4, 9, 0 }, { 7, 11, 0 }, { 8, 12, -2 },
+ { 10, 13, -4 }, { 11, 14, -6 }, { 11, 15, -8 }, { 11, 16, -8 },
+ { 11, 17, -8 }, { 11, 18, -10 }, { 13, 19, -10 },
+ { 13, 20, -12 }, { 13, 21, -12 }, { 15, 21, -12 },
+ { 21, 23, -12 }
+ }
+ },
+ /* 12BPP/14BPC */
+ { 341, 15, 2048, 15, 24, 23, 23, {
+ { 0, 6, 2 }, { 7, 10, 0 }, { 9, 13, 0 }, { 11, 16, -2 },
+ { 14, 17, -4 }, { 15, 18, -6 }, { 15, 19, -8 }, { 15, 20, -8 },
+ { 15, 20, -8 }, { 15, 21, -10 }, { 17, 21, -10 },
+ { 17, 21, -12 }, { 17, 21, -12 }, { 19, 22, -12 },
+ { 22, 23, -12 }
+ }
+ },
+ /* 12BPP/16BPC */
+ { 341, 15, 2048, 19, 28, 27, 27, {
+ { 0, 6, 2 }, { 6, 11, 0 }, { 11, 15, 0 }, { 14, 18, -2 },
+ { 18, 21, -4 }, { 19, 22, -6 }, { 19, 23, -8 }, { 19, 24, -8 },
+ { 19, 24, -8 }, { 19, 25, -10 }, { 21, 25, -10 },
+ { 21, 25, -12 }, { 21, 25, -12 }, { 23, 26, -12 },
+ { 26, 27, -12 }
+ }
+ },
+},
+{
+ /* 15BPP/8BPC */
+ { 273, 15, 2048, 3, 12, 11, 11, {
+ { 0, 0, 10 }, { 0, 1, 8 }, { 0, 1, 6 }, { 0, 2, 4 },
+ { 1, 2, 2 }, { 1, 3, 0 }, { 1, 3, -2 }, { 2, 4, -4 },
+ { 2, 5, -6 }, { 3, 5, -8 }, { 4, 6, -10 }, { 4, 7, -10 },
+ { 5, 7, -12 }, { 7, 8, -12 }, { 8, 9, -12 }
+ }
+ },
+ /* 15BPP/10BPC */
+ { 273, 15, 2048, 7, 16, 15, 15, {
+ { 0, 2, 10 }, { 2, 5, 8 }, { 3, 5, 6 }, { 4, 6, 4 },
+ { 5, 6, 2 }, { 5, 7, 0 }, { 5, 7, -2 }, { 6, 8, -4 },
+ { 6, 9, -6 }, { 7, 9, -8 }, { 8, 10, -10 }, { 8, 11, -10 },
+ { 9, 11, -12 }, { 11, 12, -12 }, { 12, 13, -12 }
+ }
+ },
+ /* 15BPP/12BPC */
+ { 273, 15, 2048, 11, 20, 19, 19, {
+ { 0, 4, 10 }, { 2, 7, 8 }, { 4, 9, 6 }, { 6, 11, 4 },
+ { 9, 11, 2 }, { 9, 11, 0 }, { 9, 12, -2 }, { 10, 12, -4 },
+ { 11, 13, -6 }, { 11, 13, -8 }, { 12, 14, -10 },
+ { 13, 15, -10 }, { 13, 15, -12 }, { 15, 16, -12 },
+ { 16, 17, -12 }
+ }
+ },
+ /* 15BPP/14BPC */
+ { 273, 15, 2048, 15, 24, 23, 23, {
+ { 0, 4, 10 }, { 3, 8, 8 }, { 6, 11, 6 }, { 9, 14, 4 },
+ { 13, 15, 2 }, { 13, 15, 0 }, { 13, 16, -2 }, { 14, 16, -4 },
+ { 15, 17, -6 }, { 15, 17, -8 }, { 16, 18, -10 },
+ { 17, 19, -10 }, { 17, 19, -12 }, { 19, 20, -12 },
+ { 20, 21, -12 }
+ }
+ },
+ /* 15BPP/16BPC */
+ { 273, 15, 2048, 19, 28, 27, 27, {
+ { 0, 4, 10 }, { 4, 9, 8 }, { 8, 13, 6 }, { 12, 17, 4 },
+ { 17, 19, 2 }, { 17, 20, 0 }, { 17, 20, -2 }, { 18, 20, -4 },
+ { 19, 21, -6 }, { 19, 21, -8 }, { 20, 22, -10 },
+ { 21, 23, -10 }, { 21, 23, -12 }, { 23, 24, -12 },
+ { 24, 25, -12 }
+ }
+ }
+}
+};
+/**
+ * dsc_pps_infoframe_pack() - Populates the DSC PPS infoframe
+ * using the DSC configuration parameters in the order expected
+ * by the DSC Display Sink device. For the DSC, the sink device
+ * expects the PPS payload in the big endian format for the fields
+ * that span more than 1 byte.
+ *
+ * @pps_sdp:
+ * Secondary data packet for DSC Picture Parameter Set
+ * @dsc_cfg:
+ * DSC Configuration data filled by driver
+ */
+static void dsc_pps_infoframe_pack(struct dsc_pps_infoframe *pps_sdp,
+ struct dsc_config *dsc_cfg)
+{
+ u8 i = 0;
+
+ memset(&pps_sdp->pps_payload, 0, sizeof(pps_sdp->pps_payload));
+
+ /* PPS 0 */
+ pps_sdp->pps_payload.dsc_version = dsc_cfg->dsc_version_minor |
+ dsc_cfg->dsc_version_major << DSC_PPS_VERSION_MAJOR_SHIFT;
+
+ /* PPS 1, 2 is 0 */
+
+ /* PPS 3 */
+ pps_sdp->pps_payload.pps_3 = dsc_cfg->line_buf_depth |
+ dsc_cfg->bits_per_component << DSC_PPS_BPC_SHIFT;
+
+ /* PPS 4 */
+ pps_sdp->pps_payload.pps_4 = (u8)((dsc_cfg->bits_per_pixel &
+ DSC_PPS_BPP_HIGH_MASK) >>
+ DSC_PPS_MSB_SHIFT) |
+ (u8)dsc_cfg->vbr_enable << DSC_PPS_VBR_EN_SHIFT |
+ (u8)dsc_cfg->enable422 << DSC_PPS_SIMPLE422_SHIFT |
+ (u8)dsc_cfg->convert_rgb << DSC_PPS_CONVERT_RGB_SHIFT |
+ (u8)dsc_cfg->block_pred_enable << DSC_PPS_BLOCK_PRED_EN_SHIFT;
+
+ /* PPS 5 */
+ pps_sdp->pps_payload.bits_per_pixel_low = (u8)(dsc_cfg->bits_per_pixel &
+ DSC_PPS_LSB_MASK);
+
+ /*
+ * The DSC panel expects the PPS packet to have big endian format
+ * for data spanning 2 bytes. Use a macro cpu_to_be16() to convert
+ * to big endian format. If format is little endian, it will swap
+ * bytes to convert to Big endian else keep it unchanged.
+ */
+
+ /* PPS 6, 7 */
+ pps_sdp->pps_payload.pic_height = cpu_to_be16(dsc_cfg->pic_height);
+
+ /* PPS 8, 9 */
+ pps_sdp->pps_payload.pic_width = cpu_to_be16(dsc_cfg->pic_width);
+
+ /* PPS 10, 11 */
+ pps_sdp->pps_payload.slice_height = cpu_to_be16(dsc_cfg->slice_height);
+
+ /* PPS 12, 13 */
+ pps_sdp->pps_payload.slice_width = cpu_to_be16(dsc_cfg->slice_width);
+
+ /* PPS 14, 15 */
+ pps_sdp->pps_payload.chunk_size = cpu_to_be16(dsc_cfg->slice_chunk_size);
+
+ /* PPS 16 */
+ pps_sdp->pps_payload.initial_xmit_delay_high = (u8)((dsc_cfg->initial_xmit_delay &
+ DSC_PPS_INIT_XMIT_DELAY_HIGH_MASK) >>
+ DSC_PPS_MSB_SHIFT);
+
+ /* PPS 17 */
+ pps_sdp->pps_payload.initial_xmit_delay_low = (u8)(dsc_cfg->initial_xmit_delay &
+ DSC_PPS_LSB_MASK);
+
+ /* PPS 18, 19 */
+ pps_sdp->pps_payload.initial_dec_delay = cpu_to_be16(dsc_cfg->initial_dec_delay);
+
+ /* PPS 20 is 0 */
+
+ /* PPS 21 */
+ pps_sdp->pps_payload.initial_scale_value = (u8)dsc_cfg->initial_scale_value;
+
+ /* PPS 22, 23 */
+ pps_sdp->pps_payload.scale_increment_interval = cpu_to_be16(dsc_cfg->scale_increment_interval);
+
+ /* PPS 24 */
+ pps_sdp->pps_payload.scale_decrement_interval_high = (u8)((dsc_cfg->scale_decrement_interval &
+ DSC_PPS_SCALE_DEC_INT_HIGH_MASK) >>
+ DSC_PPS_MSB_SHIFT);
+
+ /* PPS 25 */
+ pps_sdp->pps_payload.scale_decrement_interval_low = (u8)(dsc_cfg->scale_decrement_interval &
+ DSC_PPS_LSB_MASK);
+
+ /* PPS 26[7:0], PPS 27[7:5] RESERVED */
+
+ /* PPS 27 */
+ pps_sdp->pps_payload.first_line_bpg_offset = (u8)dsc_cfg->first_line_bpg_offset;
+
+ /* PPS 28, 29 */
+ pps_sdp->pps_payload.nfl_bpg_offset = cpu_to_be16(dsc_cfg->nfl_bpg_offset);
+
+ /* PPS 30, 31 */
+ pps_sdp->pps_payload.slice_bpg_offset = cpu_to_be16(dsc_cfg->slice_bpg_offset);
+
+ /* PPS 32, 33 */
+ pps_sdp->pps_payload.initial_offset = cpu_to_be16(dsc_cfg->initial_offset);
+
+ /* PPS 34, 35 */
+ pps_sdp->pps_payload.final_offset = cpu_to_be16(dsc_cfg->final_offset);
+
+ /* PPS 36 */
+ pps_sdp->pps_payload.flatness_min_qp = (u8)dsc_cfg->flatness_min_qp;
+
+ /* PPS 37 */
+ pps_sdp->pps_payload.flatness_max_qp = (u8)dsc_cfg->flatness_max_qp;
+
+ /* PPS 38, 39 */
+ pps_sdp->pps_payload.rc_model_size = cpu_to_be16((u16)DSC_RC_MODEL_SIZE_CONST);
+
+ /* PPS 40 */
+ pps_sdp->pps_payload.rc_edge_factor = (u8)DSC_RC_EDGE_FACTOR_CONST;
+
+ /* PPS 41 */
+ pps_sdp->pps_payload.rc_quant_incr_limit0 = (u8)dsc_cfg->rc_quant_incr_limit0;
+
+ /* PPS 42 */
+ pps_sdp->pps_payload.rc_quant_incr_limit1 = (u8)dsc_cfg->rc_quant_incr_limit1;
+
+ /* PPS 43 */
+ pps_sdp->pps_payload.rc_tgt_offset = (u8)DSC_RC_TGT_OFFSET_LO_CONST |
+ (u8)DSC_RC_TGT_OFFSET_HI_CONST << DSC_PPS_RC_TGT_OFFSET_HI_SHIFT;
+
+ /* PPS 44 - 57 */
+ for (i = 0; i < DSC_NUM_BUF_RANGES - 1; i++)
+ pps_sdp->pps_payload.rc_buf_thresh[i] = dsc_cfg->rc_buf_thresh[i];
+
+ /* PPS 58 - 87 */
+ /*
+ * For DSC sink programming the RC Range parameter fields
+ * are as follows: Min_qp[15:11], max_qp[10:6], offset[5:0]
+ */
+ for (i = 0; i < DSC_NUM_BUF_RANGES; i++) {
+ pps_sdp->pps_payload.rc_range_parameters[i] =
+ (u16)((dsc_cfg->rc_range_params[i].range_min_qp <<
+ DSC_PPS_RC_RANGE_MINQP_SHIFT) |
+ (dsc_cfg->rc_range_params[i].range_max_qp <<
+ DSC_PPS_RC_RANGE_MAXQP_SHIFT) |
+ (dsc_cfg->rc_range_params[i].range_bpg_offset));
+ pps_sdp->pps_payload.rc_range_parameters[i] = cpu_to_be16(pps_sdp->pps_payload.rc_range_parameters[i]);
+ }
+
+ /* PPS 88 */
+ pps_sdp->pps_payload.native_422_420 = (u8)dsc_cfg->native_422 |
+ (u8)dsc_cfg->native_420 << DSC_PPS_NATIVE_420_SHIFT;
+
+ /* PPS 89 */
+ pps_sdp->pps_payload.second_line_bpg_offset = (u8)dsc_cfg->second_line_bpg_offset;
+
+ /* PPS 90, 91 */
+ pps_sdp->pps_payload.nsl_bpg_offset = cpu_to_be16(dsc_cfg->nsl_bpg_offset);
+
+ /* PPS 92, 93 */
+ pps_sdp->pps_payload.second_line_offset_adj = cpu_to_be16(dsc_cfg->second_line_offset_adj);
+
+ /* PPS 94 - 127 are O */
+}
+/** XXX DK: End of borrowed stuff. */
+
+void cdns_mhdp_dsc_write_config(struct cdns_mhdp_device *mhdp)
+{
+ u32 main_conf = 0;
+
+ main_conf = CDNS_DP_COM_MAIN_CONF_INPUT_MODE |
+ CDNS_DP_COM_MAIN_CONF_MUX_EOC_EN;
+
+ if (mhdp->dsc_params.dsc_split) {
+ main_conf |= CDNS_DP_COM_MAIN_CONF_MUX_MODE |
+ CDNS_DP_COM_MAIN_CONF_SPLIT_PANEL;
+ }
+
+ writel(main_conf, mhdp->regs + CDNS_DP_COM_MAIN_CONF_MUX_EOC_EN);
+}
+
+static u8 cdns_mhdp_dsc_compute_initial_lines(struct cdns_mhdp_device *mhdp)
+{
+ struct dsc_config *dsc_cfg = &mhdp->dsc_config;
+ unsigned long k1;
+
+ if (dsc_cfg->bits_per_component == 8U)
+ k1 = 296;
+ else
+ k1 = 320;
+
+ if (mhdp->dsc_params.dsc_split) {
+ return (u8)((k1 + dsc_cfg->initial_xmit_delay +
+ (dsc_cfg->slice_chunk_size * 8 + 144) /
+ dsc_cfg->bits_per_pixel) / dsc_cfg->slice_width);
+ } else {
+ return (u8)((k1 + dsc_cfg->initial_xmit_delay +
+ (((dsc_cfg->slice_chunk_size * 8) -
+ (dsc_cfg->bits_per_pixel / 48) *
+ (dsc_cfg->slice_chunk_size * 8)) + 144) /
+ dsc_cfg->bits_per_pixel) / dsc_cfg->slice_width);
+ }
+}
+
+static void write_enc_main_conf(struct cdns_mhdp_device *mhdp,
+ int stream_id)
+{
+ u32 reg_val = 0;
+
+ if (mhdp->dsc_config.convert_rgb)
+ reg_val |= CDNS_DP_ENC_MAIN_CONF_CONVERT_RGB;
+
+ reg_val |= (mhdp->dsc_config.line_buf_depth <<
+ CDNS_DP_ENC_MAIN_CONF_LINEBUF_DEPTH_SHIFT) &
+ CDNS_DP_ENC_MAIN_CONF_LINEBUF_DEPTH;
+
+ reg_val |= (mhdp->dsc_config.bits_per_pixel <<
+ CDNS_DP_ENC_MAIN_CONF_BITS_PER_PIXEL_SHIFT) &
+ CDNS_DP_ENC_MAIN_CONF_BITS_PER_PIXEL;
+
+ if (mhdp->dsc_config.block_pred_enable)
+ reg_val |= CDNS_DP_ENC_MAIN_CONF_BLOCK_PRED_EN;
+
+ reg_val |= CDNS_DP_ENC_MAIN_CONF_VIDEO_MODE;
+
+ if (mhdp->dsc_config.block_pred_enable)
+ reg_val |= CDNS_DP_ENC_MAIN_CONF_BLOCK_PRED_EN;
+
+ reg_val |= (cdns_mhdp_dsc_compute_initial_lines(mhdp) <<
+ CDNS_DP_ENC_MAIN_CONF_INITIAL_LINES_SHIFT) &
+ CDNS_DP_ENC_MAIN_CONF_INITIAL_LINES;
+
+ writel(reg_val, mhdp->regs + CDNS_DP_ENC_MAIN_CONF(stream_id));
+}
+
+static void write_enc_picture_size(struct cdns_mhdp_device *mhdp,
+ int stream_id)
+{
+ u32 reg_val = 0;
+
+ reg_val = (mhdp->dsc_config.pic_width &
+ CDNS_DP_ENC_PICTURE_SIZE_WIDTH);
+
+ reg_val |= (mhdp->dsc_config.pic_height <<
+ CDNS_DP_ENC_PICTURE_SIZE_HEIGHT_SHIFT) &
+ CDNS_DP_ENC_PICTURE_SIZE_HEIGHT;
+
+ writel(reg_val, mhdp->regs + CDNS_DP_ENC_PICTURE_SIZE(stream_id));
+}
+
+static void write_enc_slice_size(struct cdns_mhdp_device *mhdp,
+ int stream_id)
+{
+ u32 reg_val = 0;
+
+ reg_val = (mhdp->dsc_config.slice_width &
+ CDNS_DP_ENC_SLICE_SIZE_WIDTH);
+
+ reg_val |= (mhdp->dsc_config.slice_height <<
+ CDNS_DP_ENC_SLICE_SIZE_HEIGHT_SHIFT) &
+ CDNS_DP_ENC_SLICE_SIZE_HEIGHT;
+
+ writel(reg_val, mhdp->regs + CDNS_DP_ENC_SLICE_SIZE(stream_id));
+}
+
+static void write_enc_misc_size(struct cdns_mhdp_device *mhdp,
+ int stream_id)
+{
+ u32 reg_val = 0;
+
+ reg_val = ((mhdp->dsc_config.slice_width + 2) % 3) &
+ CDNS_DP_ENC_MISC_SIZE_LAST_GRP_SIZE;
+
+ reg_val |= (DSC_OUTPUT_BUFFER_MAX_ADDRESS <<
+ CDNS_DP_ENC_MISC_SIZE_OB_MAX_ADDR_SHIFT) &
+ CDNS_DP_ENC_MISC_SIZE_OB_MAX_ADDR;
+
+ reg_val |= (mhdp->dsc_config.slice_chunk_size <<
+ CDNS_DP_ENC_MISC_SIZE_CHUNK_SIZE_SHIFT) &
+ CDNS_DP_ENC_MISC_SIZE_CHUNK_SIZE;
+
+ writel(reg_val, mhdp->regs + CDNS_DP_ENC_MISC_SIZE(stream_id));
+}
+
+static void write_enc_hrd_delays(struct cdns_mhdp_device *mhdp,
+ int stream_id)
+{
+ u32 reg_val = 0;
+
+ reg_val = (mhdp->dsc_config.initial_xmit_delay &
+ CDNS_DP_ENC_HRD_DELAYS_INIT_XMIT_DELAY);
+
+ reg_val |= (mhdp->dsc_config.initial_dec_delay <<
+ CDNS_DP_ENC_HRD_DELAYS_INIT_DEC_DELAY_SHIFT) &
+ CDNS_DP_ENC_HRD_DELAYS_INIT_DEC_DELAY;
+
+ writel(reg_val, mhdp->regs + CDNS_DP_ENC_HRD_DELAYS(stream_id));
+}
+
+static void write_enc_rc_scale(struct cdns_mhdp_device *mhdp,
+ int stream_id)
+{
+ u32 reg_val = 0;
+
+ reg_val = (mhdp->dsc_config.initial_scale_value &
+ CDNS_DP_ENC_RC_SCALE_INIT_SCALE_VALUE);
+
+ writel(reg_val, mhdp->regs + CDNS_DP_ENC_RC_SCALE(stream_id));
+}
+
+static void write_enc_rc_scale_inc_dec(struct cdns_mhdp_device *mhdp,
+ int stream_id)
+{
+ u32 reg_val = 0;
+
+ reg_val = (mhdp->dsc_config.scale_increment_interval &
+ CDNS_DP_ENC_RC_SCALE_INC_INTERVAL);
+
+ reg_val |= (mhdp->dsc_config.scale_decrement_interval <<
+ CDNS_DP_ENC_RC_SCALE_DEC_INTERVAL_SHIFT) &
+ CDNS_DP_ENC_RC_SCALE_DEC_INTERVAL;
+
+ writel(reg_val, mhdp->regs + CDNS_DP_ENC_RC_SCALE_INC_DEC(stream_id));
+}
+
+static void write_enc_rc_offsets(struct cdns_mhdp_device *mhdp,
+ int stream_id)
+{
+ u32 reg_val;
+
+ reg_val = (mhdp->dsc_config.first_line_bpg_offset &
+ CDNS_DP_ENC_RC_OFFSETS_1_FL_BGP_OFFSET);
+ writel(reg_val, mhdp->regs + CDNS_DP_ENC_RC_OFFSETS_1(stream_id));
+
+ reg_val = (mhdp->dsc_config.nfl_bpg_offset &
+ CDNS_DP_ENC_RC_OFFSETS_2_NFL_BGP_OFFSET);
+
+ reg_val |= (mhdp->dsc_config.slice_bpg_offset <<
+ CDNS_DP_ENC_RC_OFFSETS_2_SL_BGP_OFFSET_SHIFT) &
+ CDNS_DP_ENC_RC_OFFSETS_2_SL_BGP_OFFSET;
+ writel(reg_val, mhdp->regs + CDNS_DP_ENC_RC_OFFSETS_2(stream_id));
+
+ reg_val = (mhdp->dsc_config.initial_offset &
+ CDNS_DP_ENC_RC_OFFSETS_3_INIT_OFFSET);
+
+ reg_val |= (mhdp->dsc_config.final_offset <<
+ CDNS_DP_ENC_RC_OFFSETS_3_FINAL_OFFSET_SHIFT) &
+ CDNS_DP_ENC_RC_OFFSETS_3_FINAL_OFFSET;
+ writel(reg_val, mhdp->regs + CDNS_DP_ENC_RC_OFFSETS_3(stream_id));
+}
+
+static void write_enc_flatness_detection(struct cdns_mhdp_device *mhdp,
+ int stream_id)
+{
+ u32 reg_val;
+
+ reg_val = (mhdp->dsc_config.flatness_min_qp &
+ CDNS_DP_ENC_FLATNESS_DETECTION_MIN_QP);
+
+ reg_val |= (mhdp->dsc_config.flatness_max_qp <<
+ CDNS_DP_ENC_FLATNESS_DETECTION_MAX_QP_SHIFT) &
+ CDNS_DP_ENC_FLATNESS_DETECTION_MAX_QP;
+ // FIXME: hardcoded value
+ reg_val |= (2 <<
+ CDNS_DP_ENC_FLATNESS_DETECTION_THRESH_SHIFT) &
+ CDNS_DP_ENC_FLATNESS_DETECTION_THRESH;
+ writel(reg_val, mhdp->regs + CDNS_DP_ENC_FLATNESS_DETECTION(stream_id));
+}
+
+static void write_enc_rc_model_size(struct cdns_mhdp_device *mhdp,
+ int stream_id)
+{
+ u32 reg_val;
+
+ reg_val = (mhdp->dsc_config.rc_model_size &
+ CDNS_DP_ENC_RC_MODEL_SIZE_RC_MODEL_SIZE);
+
+ writel(reg_val, mhdp->regs + CDNS_DP_ENC_RC_MODEL_SIZE(stream_id));
+}
+
+static void write_enc_rc_config(struct cdns_mhdp_device *mhdp,
+ int stream_id)
+{
+ u32 reg_val;
+
+ reg_val = (mhdp->dsc_config.rc_edge_factor &
+ CDNS_DP_ENC_RC_CONFIG_EDGE_FACTOR);
+
+ reg_val |= (mhdp->dsc_config.rc_quant_incr_limit0 <<
+ CDNS_DP_ENC_RC_CONFIG_QUANT_INC_LIM_0_SHIFT) &
+ CDNS_DP_ENC_RC_CONFIG_QUANT_INC_LIM_0;
+
+ reg_val |= (mhdp->dsc_config.rc_quant_incr_limit1 <<
+ CDNS_DP_ENC_RC_CONFIG_QUANT_INC_LIM_1_SHIFT) &
+ CDNS_DP_ENC_RC_CONFIG_QUANT_INC_LIM_1;
+
+ reg_val |= (mhdp->dsc_config.rc_tgt_offset_high <<
+ CDNS_DP_ENC_RC_CONFIG_TGT_OFFSET_HI_SHIFT) &
+ CDNS_DP_ENC_RC_CONFIG_TGT_OFFSET_HI;
+
+ reg_val |= (mhdp->dsc_config.rc_tgt_offset_low <<
+ CDNS_DP_ENC_RC_CONFIG_TGT_OFFSET_LO_SHIFT) &
+ CDNS_DP_ENC_RC_CONFIG_TGT_OFFSET_LO;
+ writel(reg_val, mhdp->regs + CDNS_DP_ENC_RC_CONFIG(stream_id));
+}
+
+void write_enc_rc_buf_thresh(struct cdns_mhdp_device *mhdp,
+ int stream_id)
+{
+ u32 reg_val;
+ int index = 0;
+
+ reg_val = (mhdp->dsc_config.rc_buf_thresh[index++] &
+ CDNS_DP_ENC_RC_BUF_THRESH_0_THRESH_0);
+
+ reg_val |= (mhdp->dsc_config.rc_buf_thresh[index++] <<
+ CDNS_DP_ENC_RC_BUF_THRESH_THRESH_1_SHIFT) &
+ CDNS_DP_ENC_RC_BUF_THRESH_0_THRESH_1;
+
+ reg_val |= (mhdp->dsc_config.rc_buf_thresh[index++] <<
+ CDNS_DP_ENC_RC_BUF_THRESH_THRESH_2_SHIFT) &
+ CDNS_DP_ENC_RC_BUF_THRESH_0_THRESH_2;
+
+ reg_val |= (mhdp->dsc_config.rc_buf_thresh[index++] <<
+ CDNS_DP_ENC_RC_BUF_THRESH_THRESH_3_SHIFT) &
+ CDNS_DP_ENC_RC_BUF_THRESH_0_THRESH_3;
+ writel(reg_val, mhdp->regs + CDNS_DP_ENC_RC_BUF_THRESH_0(stream_id));
+
+ reg_val = (mhdp->dsc_config.rc_buf_thresh[index++] &
+ CDNS_DP_ENC_RC_BUF_THRESH_1_THRESH_4);
+
+ reg_val |= (mhdp->dsc_config.rc_buf_thresh[index++] <<
+ CDNS_DP_ENC_RC_BUF_THRESH_THRESH_1_SHIFT) &
+ CDNS_DP_ENC_RC_BUF_THRESH_1_THRESH_5;
+
+ reg_val |= (mhdp->dsc_config.rc_buf_thresh[index++] <<
+ CDNS_DP_ENC_RC_BUF_THRESH_THRESH_2_SHIFT) &
+ CDNS_DP_ENC_RC_BUF_THRESH_1_THRESH_6;
+
+ reg_val |= (mhdp->dsc_config.rc_buf_thresh[index++] <<
+ CDNS_DP_ENC_RC_BUF_THRESH_THRESH_3_SHIFT) &
+ CDNS_DP_ENC_RC_BUF_THRESH_1_THRESH_7;
+ writel(reg_val, mhdp->regs + CDNS_DP_ENC_RC_BUF_THRESH_1(stream_id));
+
+ reg_val = (mhdp->dsc_config.rc_buf_thresh[index++] &
+ CDNS_DP_ENC_RC_BUF_THRESH_2_THRESH_8);
+
+ reg_val |= (mhdp->dsc_config.rc_buf_thresh[index++] <<
+ CDNS_DP_ENC_RC_BUF_THRESH_THRESH_1_SHIFT) &
+ CDNS_DP_ENC_RC_BUF_THRESH_2_THRESH_9;
+
+ reg_val |= (mhdp->dsc_config.rc_buf_thresh[index++] <<
+ CDNS_DP_ENC_RC_BUF_THRESH_THRESH_2_SHIFT) &
+ CDNS_DP_ENC_RC_BUF_THRESH_2_THRESH_10;
+
+ reg_val |= (mhdp->dsc_config.rc_buf_thresh[index++] <<
+ CDNS_DP_ENC_RC_BUF_THRESH_THRESH_3_SHIFT) &
+ CDNS_DP_ENC_RC_BUF_THRESH_2_THRESH_11;
+ writel(reg_val, mhdp->regs + CDNS_DP_ENC_RC_BUF_THRESH_2(stream_id));
+
+ reg_val = (mhdp->dsc_config.rc_buf_thresh[index++] &
+ CDNS_DP_ENC_RC_BUF_THRESH_3_THRESH_12);
+
+ reg_val |= (mhdp->dsc_config.rc_buf_thresh[index++] <<
+ CDNS_DP_ENC_RC_BUF_THRESH_THRESH_1_SHIFT) &
+ CDNS_DP_ENC_RC_BUF_THRESH_3_THRESH_13;
+
+ writel(reg_val, mhdp->regs + CDNS_DP_ENC_RC_BUF_THRESH_3(stream_id));
+}
+
+void write_enc_rc_min_qp(struct cdns_mhdp_device *mhdp,
+ int stream_id)
+{
+ u32 reg_val;
+ int index = 0;
+
+ reg_val = (mhdp->dsc_config.rc_range_params[index++].range_min_qp &
+ CDNS_DP_ENC_RC_MIN_QP_0_RANGE_0);
+
+ reg_val |= (mhdp->dsc_config.rc_range_params[index++].range_min_qp <<
+ CDNS_DP_ENC_RC_QP_RANGE_1_SHIFT) &
+ CDNS_DP_ENC_RC_MIN_QP_0_RANGE_1;
+
+ reg_val |= (mhdp->dsc_config.rc_range_params[index++].range_min_qp <<
+ CDNS_DP_ENC_RC_QP_RANGE_2_SHIFT) &
+ CDNS_DP_ENC_RC_MIN_QP_0_RANGE_2;
+
+ reg_val |= (mhdp->dsc_config.rc_range_params[index++].range_min_qp <<
+ CDNS_DP_ENC_RC_QP_RANGE_3_SHIFT) &
+ CDNS_DP_ENC_RC_MIN_QP_0_RANGE_3;
+
+ reg_val |= (mhdp->dsc_config.rc_range_params[index++].range_min_qp <<
+ CDNS_DP_ENC_RC_QP_RANGE_4_SHIFT) &
+ CDNS_DP_ENC_RC_MIN_QP_0_RANGE_4;
+ writel(reg_val, mhdp->regs + CDNS_DP_ENC_RC_MIN_QP_0(stream_id));
+
+ reg_val = (mhdp->dsc_config.rc_range_params[index++].range_min_qp &
+ CDNS_DP_ENC_RC_MIN_QP_1_RANGE_5);
+
+ reg_val |= (mhdp->dsc_config.rc_range_params[index++].range_min_qp <<
+ CDNS_DP_ENC_RC_QP_RANGE_1_SHIFT) &
+ CDNS_DP_ENC_RC_MIN_QP_1_RANGE_6;
+
+ reg_val |= (mhdp->dsc_config.rc_range_params[index++].range_min_qp <<
+ CDNS_DP_ENC_RC_QP_RANGE_2_SHIFT) &
+ CDNS_DP_ENC_RC_MIN_QP_1_RANGE_7;
+
+ reg_val |= (mhdp->dsc_config.rc_range_params[index++].range_min_qp <<
+ CDNS_DP_ENC_RC_QP_RANGE_3_SHIFT) &
+ CDNS_DP_ENC_RC_MIN_QP_1_RANGE_8;
+
+ reg_val |= (mhdp->dsc_config.rc_range_params[index++].range_min_qp <<
+ CDNS_DP_ENC_RC_QP_RANGE_4_SHIFT) &
+ CDNS_DP_ENC_RC_MIN_QP_1_RANGE_9;
+ writel(reg_val, mhdp->regs + CDNS_DP_ENC_RC_MIN_QP_1(stream_id));
+
+ reg_val = (mhdp->dsc_config.rc_range_params[index++].range_min_qp &
+ CDNS_DP_ENC_RC_MIN_QP_2_RANGE_10);
+
+ reg_val |= (mhdp->dsc_config.rc_range_params[index++].range_min_qp <<
+ CDNS_DP_ENC_RC_QP_RANGE_1_SHIFT) &
+ CDNS_DP_ENC_RC_MIN_QP_2_RANGE_11;
+
+ reg_val |= (mhdp->dsc_config.rc_range_params[index++].range_min_qp <<
+ CDNS_DP_ENC_RC_QP_RANGE_2_SHIFT) &
+ CDNS_DP_ENC_RC_MIN_QP_2_RANGE_12;
+
+ reg_val |= (mhdp->dsc_config.rc_range_params[index++].range_min_qp <<
+ CDNS_DP_ENC_RC_QP_RANGE_3_SHIFT) &
+ CDNS_DP_ENC_RC_MIN_QP_2_RANGE_13;
+
+ reg_val |= (mhdp->dsc_config.rc_range_params[index++].range_min_qp <<
+ CDNS_DP_ENC_RC_QP_RANGE_4_SHIFT) &
+ CDNS_DP_ENC_RC_MIN_QP_2_RANGE_14;
+ writel(reg_val, mhdp->regs + CDNS_DP_ENC_RC_MIN_QP_2(stream_id));
+}
+
+void write_enc_rc_max_qp(struct cdns_mhdp_device *mhdp,
+ int stream_id)
+{
+ u32 reg_val;
+ int index = 0;
+
+ reg_val = (mhdp->dsc_config.rc_range_params[index++].range_max_qp &
+ CDNS_DP_ENC_RC_MAX_QP_0_RANGE_0);
+
+ reg_val |= (mhdp->dsc_config.rc_range_params[index++].range_max_qp <<
+ CDNS_DP_ENC_RC_QP_RANGE_1_SHIFT) &
+ CDNS_DP_ENC_RC_MAX_QP_0_RANGE_1;
+
+ reg_val |= (mhdp->dsc_config.rc_range_params[index++].range_max_qp <<
+ CDNS_DP_ENC_RC_QP_RANGE_2_SHIFT) &
+ CDNS_DP_ENC_RC_MAX_QP_0_RANGE_2;
+
+ reg_val |= (mhdp->dsc_config.rc_range_params[index++].range_max_qp <<
+ CDNS_DP_ENC_RC_QP_RANGE_3_SHIFT) &
+ CDNS_DP_ENC_RC_MAX_QP_0_RANGE_3;
+
+ reg_val |= (mhdp->dsc_config.rc_range_params[index++].range_max_qp <<
+ CDNS_DP_ENC_RC_QP_RANGE_4_SHIFT) &
+ CDNS_DP_ENC_RC_MAX_QP_0_RANGE_4;
+ writel(reg_val, mhdp->regs + CDNS_DP_ENC_RC_MAX_QP_0(stream_id));
+
+ reg_val = (mhdp->dsc_config.rc_range_params[index++].range_max_qp &
+ CDNS_DP_ENC_RC_MAX_QP_1_RANGE_5);
+
+ reg_val |= (mhdp->dsc_config.rc_range_params[index++].range_max_qp <<
+ CDNS_DP_ENC_RC_QP_RANGE_1_SHIFT) &
+ CDNS_DP_ENC_RC_MAX_QP_1_RANGE_6;
+
+ reg_val |= (mhdp->dsc_config.rc_range_params[index++].range_max_qp <<
+ CDNS_DP_ENC_RC_QP_RANGE_2_SHIFT) &
+ CDNS_DP_ENC_RC_MAX_QP_1_RANGE_7;
+
+ reg_val |= (mhdp->dsc_config.rc_range_params[index++].range_max_qp <<
+ CDNS_DP_ENC_RC_QP_RANGE_3_SHIFT) &
+ CDNS_DP_ENC_RC_MAX_QP_1_RANGE_8;
+
+ reg_val |= (mhdp->dsc_config.rc_range_params[index++].range_max_qp <<
+ CDNS_DP_ENC_RC_QP_RANGE_4_SHIFT) &
+ CDNS_DP_ENC_RC_MAX_QP_1_RANGE_9;
+ writel(reg_val, mhdp->regs + CDNS_DP_ENC_RC_MAX_QP_1(stream_id));
+
+ reg_val = (mhdp->dsc_config.rc_range_params[index++].range_max_qp &
+ CDNS_DP_ENC_RC_MAX_QP_2_RANGE_10);
+
+ reg_val |= (mhdp->dsc_config.rc_range_params[index++].range_max_qp <<
+ CDNS_DP_ENC_RC_QP_RANGE_1_SHIFT) &
+ CDNS_DP_ENC_RC_MAX_QP_2_RANGE_11;
+
+ reg_val |= (mhdp->dsc_config.rc_range_params[index++].range_max_qp <<
+ CDNS_DP_ENC_RC_QP_RANGE_2_SHIFT) &
+ CDNS_DP_ENC_RC_MAX_QP_2_RANGE_12;
+
+ reg_val |= (mhdp->dsc_config.rc_range_params[index++].range_max_qp <<
+ CDNS_DP_ENC_RC_QP_RANGE_3_SHIFT) &
+ CDNS_DP_ENC_RC_MAX_QP_2_RANGE_13;
+
+ reg_val |= (mhdp->dsc_config.rc_range_params[index++].range_max_qp <<
+ CDNS_DP_ENC_RC_QP_RANGE_4_SHIFT) &
+ CDNS_DP_ENC_RC_MAX_QP_2_RANGE_14;
+ writel(reg_val, mhdp->regs + CDNS_DP_ENC_RC_MAX_QP_2(stream_id));
+}
+
+void write_enc_rc_range_bgp(struct cdns_mhdp_device *mhdp,
+ int stream_id)
+{
+ u32 reg_val;
+ int index = 0;
+
+ reg_val = (mhdp->dsc_config.rc_range_params[index++].range_bpg_offset &
+ CDNS_DP_ENC_RC_RANGE_BPG_OFFSETS_0_0);
+
+ reg_val |= (mhdp->dsc_config.rc_range_params[index++].range_bpg_offset <<
+ CDNS_DP_ENC_RC_QP_RANGE_1_SHIFT) &
+ CDNS_DP_ENC_RC_RANGE_BPG_OFFSETS_0_1;
+
+ reg_val |= (mhdp->dsc_config.rc_range_params[index++].range_bpg_offset <<
+ CDNS_DP_ENC_RC_QP_RANGE_2_SHIFT) &
+ CDNS_DP_ENC_RC_RANGE_BPG_OFFSETS_0_2;
+
+ reg_val |= (mhdp->dsc_config.rc_range_params[index++].range_bpg_offset <<
+ CDNS_DP_ENC_RC_QP_RANGE_3_SHIFT) &
+ CDNS_DP_ENC_RC_RANGE_BPG_OFFSETS_0_3;
+
+ reg_val |= (mhdp->dsc_config.rc_range_params[index++].range_bpg_offset <<
+ CDNS_DP_ENC_RC_QP_RANGE_4_SHIFT) &
+ CDNS_DP_ENC_RC_RANGE_BPG_OFFSETS_0_4;
+ writel(reg_val, mhdp->regs +
+ CDNS_DP_ENC_RC_RANGE_BPG_OFFSETS_0(stream_id));
+
+ reg_val = (mhdp->dsc_config.rc_range_params[index++].range_bpg_offset &
+ CDNS_DP_ENC_RC_RANGE_BPG_OFFSETS_0_5);
+
+ reg_val |= (mhdp->dsc_config.rc_range_params[index++].range_bpg_offset <<
+ CDNS_DP_ENC_RC_QP_RANGE_1_SHIFT) &
+ CDNS_DP_ENC_RC_RANGE_BPG_OFFSETS_0_6;
+
+ reg_val |= (mhdp->dsc_config.rc_range_params[index++].range_bpg_offset <<
+ CDNS_DP_ENC_RC_QP_RANGE_2_SHIFT) &
+ CDNS_DP_ENC_RC_RANGE_BPG_OFFSETS_0_7;
+
+ reg_val |= (mhdp->dsc_config.rc_range_params[index++].range_bpg_offset <<
+ CDNS_DP_ENC_RC_QP_RANGE_3_SHIFT) &
+ CDNS_DP_ENC_RC_RANGE_BPG_OFFSETS_0_8;
+
+ reg_val |= (mhdp->dsc_config.rc_range_params[index++].range_bpg_offset <<
+ CDNS_DP_ENC_RC_QP_RANGE_4_SHIFT) &
+ CDNS_DP_ENC_RC_RANGE_BPG_OFFSETS_0_9;
+ writel(reg_val, mhdp->regs +
+ CDNS_DP_ENC_RC_RANGE_BPG_OFFSETS_1(stream_id));
+
+ reg_val = (mhdp->dsc_config.rc_range_params[index++].range_bpg_offset &
+ CDNS_DP_ENC_RC_RANGE_BPG_OFFSETS_0_10);
+
+ reg_val |= (mhdp->dsc_config.rc_range_params[index++].range_bpg_offset <<
+ CDNS_DP_ENC_RC_QP_RANGE_1_SHIFT) &
+ CDNS_DP_ENC_RC_RANGE_BPG_OFFSETS_0_11;
+
+ reg_val |= (mhdp->dsc_config.rc_range_params[index++].range_bpg_offset <<
+ CDNS_DP_ENC_RC_QP_RANGE_2_SHIFT) &
+ CDNS_DP_ENC_RC_RANGE_BPG_OFFSETS_0_12;
+
+ reg_val |= (mhdp->dsc_config.rc_range_params[index++].range_bpg_offset <<
+ CDNS_DP_ENC_RC_QP_RANGE_3_SHIFT) &
+ CDNS_DP_ENC_RC_RANGE_BPG_OFFSETS_0_13;
+
+ reg_val |= (mhdp->dsc_config.rc_range_params[index++].range_bpg_offset <<
+ CDNS_DP_ENC_RC_QP_RANGE_4_SHIFT) &
+ CDNS_DP_ENC_RC_RANGE_BPG_OFFSETS_0_14;
+ writel(reg_val, mhdp->regs +
+ CDNS_DP_ENC_RC_RANGE_BPG_OFFSETS_2(stream_id));
+}
+
+void write_enc_dpi_ctrl(struct cdns_mhdp_device *mhdp,
+ int stream_id)
+{
+ struct drm_display_mode *mode = &mhdp->mode;
+ u32 reg_val = 0;
+
+ reg_val =
+ ((mode->vdisplay * cdns_mhdp_dsc_compute_initial_lines(mhdp)) &
+ CDNS_DP_ENC_DPI_CTRL_OUT_DELAY_CYCLES);
+
+ writel(reg_val, mhdp->regs + CDNS_DP_ENC_DPI_CTRL_OUT_DELAY(stream_id));
+}
+
+void cdns_mhdp_dsc_write_enc_config(struct cdns_mhdp_device *mhdp,
+ int stream_id)
+{
+ write_enc_main_conf(mhdp, stream_id);
+ write_enc_picture_size(mhdp, stream_id);
+ write_enc_slice_size(mhdp, stream_id);
+ write_enc_misc_size(mhdp, stream_id);
+ write_enc_hrd_delays(mhdp, stream_id);
+ write_enc_rc_scale(mhdp, stream_id);
+ write_enc_rc_scale_inc_dec(mhdp, stream_id);
+ write_enc_rc_offsets(mhdp, stream_id);
+ write_enc_flatness_detection(mhdp, stream_id);
+ write_enc_rc_model_size(mhdp, stream_id);
+ write_enc_rc_config(mhdp, stream_id);
+ write_enc_rc_buf_thresh(mhdp, stream_id);
+ write_enc_rc_min_qp(mhdp, stream_id);
+ write_enc_rc_max_qp(mhdp, stream_id);
+ write_enc_rc_range_bgp(mhdp, stream_id);
+ write_enc_dpi_ctrl(mhdp, stream_id);
+}
+
+int cdns_mhdp_dsc_sink_support(struct cdns_mhdp_device *mhdp)
+{
+ int ret;
+ u16 dpcd_buffer;
+ size_t size = 1;
+
+ ret = drm_dp_dpcd_read(&mhdp->aux, DP_DSC_SUPPORT, &dpcd_buffer, size);
+ if (ret != size) {
+ DRM_DEV_ERROR(mhdp->dev, "cannot read sink DSC DPCD: %d\n",
+ ret);
+ goto err;
+ }
+ if (!(dpcd_buffer & DP_DSC_DECOMPRESSION_IS_SUPPORTED)) {
+ ret = -ENOTSUPP;
+ DRM_DEV_ERROR(mhdp->dev, "sink does not support DSC: %d\n",
+ ret);
+ goto err;
+ }
+
+ ret = 0;
+
+err:
+ return ret;
+}
+
+static int get_row_index_for_rc_params(u16 compressed_bpp)
+{
+ switch (compressed_bpp) {
+ case 6:
+ return ROW_INDEX_6BPP;
+ case 8:
+ return ROW_INDEX_8BPP;
+ case 10:
+ return ROW_INDEX_10BPP;
+ case 12:
+ return ROW_INDEX_12BPP;
+ case 15:
+ return ROW_INDEX_15BPP;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int get_column_index_for_rc_params(u8 bits_per_component)
+{
+ switch (bits_per_component) {
+ case 8:
+ return COLUMN_INDEX_8BPC;
+ case 10:
+ return COLUMN_INDEX_10BPC;
+ case 12:
+ return COLUMN_INDEX_12BPC;
+ case 14:
+ return COLUMN_INDEX_14BPC;
+ case 16:
+ return COLUMN_INDEX_16BPC;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int cdns_mhdp_compute_rc_params(struct dsc_config *dsc_cfg)
+{
+ unsigned long groups_per_line = 0;
+ unsigned long groups_total = 0;
+ unsigned long num_extra_mux_bits = 0;
+ unsigned long slice_bits = 0;
+ unsigned long hrd_delay = 0;
+ unsigned long final_scale = 0;
+ unsigned long rbs_min = 0;
+
+ /* RC_MODEL_SIZE is a constant across all configurations */
+ dsc_cfg->rc_model_size = DSC_RC_MODEL_SIZE_CONST;
+ /* Number of groups used to code each line of a slice */
+ groups_per_line = DIV_ROUND_UP(dsc_cfg->slice_width,
+ DP_DSC_RC_PIXELS_PER_GROUP);
+
+ /* chunksize in Bytes */
+ dsc_cfg->slice_chunk_size = DIV_ROUND_UP(dsc_cfg->slice_width *
+ dsc_cfg->bits_per_pixel, 8);
+
+ if (dsc_cfg->convert_rgb)
+ num_extra_mux_bits = 3 * (dsc_cfg->mux_word_size +
+ (4 * dsc_cfg->bits_per_component + 4)
+ - 2);
+ else
+ num_extra_mux_bits = 3 * dsc_cfg->mux_word_size +
+ (4 * dsc_cfg->bits_per_component + 4) +
+ 2 * (4 * dsc_cfg->bits_per_component) - 2;
+ /* Number of bits in one Slice */
+ slice_bits = 8 * dsc_cfg->slice_chunk_size * dsc_cfg->slice_height;
+
+ while ((num_extra_mux_bits > 0) &&
+ ((slice_bits - num_extra_mux_bits) % dsc_cfg->mux_word_size))
+ num_extra_mux_bits--;
+
+ if (groups_per_line < dsc_cfg->initial_scale_value - 8)
+ dsc_cfg->initial_scale_value = groups_per_line + 8;
+
+ /* scale_decrement_interval calculation according to DSC spec 1.11 */
+ if (dsc_cfg->initial_scale_value > 8)
+ dsc_cfg->scale_decrement_interval = groups_per_line /
+ (8 * dsc_cfg->initial_scale_value - 8);
+ else
+ dsc_cfg->scale_decrement_interval =
+ DP_DSC_SCALE_DECREMENT_INTERVAL_MAX;
+
+ dsc_cfg->final_offset = dsc_cfg->rc_model_size -
+ ((dsc_cfg->initial_xmit_delay *
+ dsc_cfg->bits_per_pixel + 8) >> 4) + num_extra_mux_bits;
+
+ if (dsc_cfg->final_offset >= dsc_cfg->rc_model_size) {
+ DRM_ERROR("FinalOfs < RcModelSze for this InitialXmitDelay\n");
+ return -1;
+ }
+
+ final_scale = (dsc_cfg->rc_model_size << 3) /
+ (dsc_cfg->rc_model_size - dsc_cfg->final_offset);
+ if (dsc_cfg->slice_height > 1)
+ /*
+ * NflBpgOffset is 16 bit value with 11 fractional bits
+ * hence we multiply by 2^11 for preserving the
+ * fractional part
+ */
+ dsc_cfg->nfl_bpg_offset =
+ DIV_ROUND_UP((dsc_cfg->first_line_bpg_offset << 11),
+ (dsc_cfg->slice_height - 1));
+ else
+ dsc_cfg->nfl_bpg_offset = 0;
+
+ /* 2^16 - 1 */
+ if (dsc_cfg->nfl_bpg_offset > 65535) {
+ DRM_ERROR("NflBpgOffset is too large for this slice height\n");
+ return -1;
+ }
+
+ /* Number of groups used to code the entire slice */
+ groups_total = groups_per_line * dsc_cfg->slice_height;
+
+ /* slice_bpg_offset is 16 bit value with 11 fractional bits */
+ dsc_cfg->slice_bpg_offset = DIV_ROUND_UP(((dsc_cfg->rc_model_size -
+ dsc_cfg->initial_offset +
+ num_extra_mux_bits) << 11),
+ groups_total);
+
+ if (final_scale > 0x9) {
+ /*
+ * ScaleIncrementInterval = finaloffset/((NflBpgOffset +
+ * SliceBpgOffset)*8(finalscale - 1.125))
+ * as (NflBpgOffset + SliceBpgOffset) has 11 bit fractional
+ * value, we need divide by 2^11 from pstDscCfg values
+ */
+ dsc_cfg->scale_increment_interval =
+ (dsc_cfg->final_offset * (1 << 11)) /
+ ((dsc_cfg->nfl_bpg_offset +
+ dsc_cfg->slice_bpg_offset)*
+ (final_scale - 9));
+ } else {
+ /*
+ * If finalScaleValue is less than or equal to 9,
+ * a value of 0 should be used to disable the scale
+ * increment at the end of the slice
+ */
+ dsc_cfg->scale_increment_interval = 0;
+ }
+
+ if (dsc_cfg->scale_increment_interval > 65535) {
+ DRM_ERROR("ScaleIncrementInterval is large for slice height\n");
+ return -1;
+ }
+
+ /*
+ * DSC spec mentions that bits_per_pixel specifies the target
+ * bits/pixel (bpp) rate that is used by the encoder,
+ * in steps of 1/16 of a bit per pixel
+ */
+ rbs_min = dsc_cfg->rc_model_size - dsc_cfg->initial_offset +
+ DIV_ROUND_UP(dsc_cfg->initial_xmit_delay *
+ dsc_cfg->bits_per_pixel, 16) +
+ groups_per_line * dsc_cfg->first_line_bpg_offset;
+
+ hrd_delay = DIV_ROUND_UP((rbs_min * 16), dsc_cfg->bits_per_pixel);
+ dsc_cfg->rc_bits = (hrd_delay * dsc_cfg->bits_per_pixel) / 16;
+ dsc_cfg->initial_dec_delay = hrd_delay - dsc_cfg->initial_xmit_delay;
+
+ return 0;
+}
+
+int cdns_mhdp_compute_dsc_params(struct cdns_mhdp_device *mhdp)
+{
+ struct drm_bridge *bridge = &mhdp->bridge.base;
+ struct dsc_config *dsc_cfg = &mhdp->dsc_config;
+ struct drm_crtc_state *crtc_state = bridge->encoder->crtc->state;
+ struct drm_display_info *disp_info =
+ &mhdp->connector.base.display_info;
+ u8 dsc_dpcd[DP_RECEIVER_CAP_SIZE];
+ int i, row_index, column_index;
+ u8 line_buf_depth;
+
+ drm_dp_dpcd_read(&mhdp->aux, DP_DSC_SUPPORT, dsc_dpcd,
+ DP_RECEIVER_CAP_SIZE);
+
+ dsc_cfg->pic_width = crtc_state->adjusted_mode.crtc_hdisplay;
+ dsc_cfg->pic_height = crtc_state->adjusted_mode.crtc_vdisplay;
+
+ dsc_cfg->slice_width = dsc_cfg->pic_width;
+ dsc_cfg->slice_height = DIV_ROUND_UP(dsc_cfg->pic_height,
+ mhdp->dsc_params.slice_count);
+
+
+ dsc_cfg->dsc_version_major = (dsc_dpcd[DP_DSC_REV - DP_DSC_SUPPORT] &
+ DP_DSC_MAJOR_MASK) >> DP_DSC_MAJOR_SHIFT;
+ dsc_cfg->dsc_version_minor =
+ min(DSC_SUPPORTED_VERSION_MIN,
+ (dsc_dpcd[DP_DSC_REV - DP_DSC_SUPPORT] &
+ DP_DSC_MINOR_MASK) >> DP_DSC_MINOR_SHIFT);
+
+ dsc_cfg->convert_rgb =
+ dsc_dpcd[DP_DSC_DEC_COLOR_FORMAT_CAP - DP_DSC_SUPPORT] &
+ DP_DSC_RGB;
+
+ line_buf_depth = dp_dsc_sink_line_buf_depth(dsc_dpcd);
+ if (dsc_cfg->dsc_version_minor == 2)
+ dsc_cfg->line_buf_depth =
+ (line_buf_depth == DSC_1_2_MAX_LINEBUF_DEPTH_BITS) ?
+ DSC_1_2_MAX_LINEBUF_DEPTH_VAL : line_buf_depth;
+ else
+ dsc_cfg->line_buf_depth =
+ (line_buf_depth > DSC_1_1_MAX_LINEBUF_DEPTH_BITS) ?
+ DSC_1_1_MAX_LINEBUF_DEPTH_BITS : line_buf_depth;
+
+ dsc_cfg->vbr_enable = false;
+
+ dsc_cfg->block_pred_enable =
+ dsc_dpcd[DP_DSC_BLK_PREDICTION_SUPPORT - DP_DSC_SUPPORT] &
+ DP_DSC_BLK_PREDICTION_IS_SUPPORTED;
+
+ dsc_cfg->bits_per_pixel = mhdp->dsc_params.compressed_bpp << 4;
+
+ dsc_cfg->bits_per_component = disp_info->bpc;
+
+ for (i = 0; i < DSC_NUM_BUF_RANGES - 1; i++)
+ dsc_cfg->rc_buf_thresh[i] = rc_buf_thresh[i] >> 6;
+
+ if (mhdp->dsc_params.compressed_bpp == 6) {
+ dsc_cfg->rc_buf_thresh[12] = 0x7C;
+ dsc_cfg->rc_buf_thresh[13] = 0x7D;
+ }
+
+ row_index =
+ get_row_index_for_rc_params(mhdp->dsc_params.compressed_bpp);
+ column_index =
+ get_column_index_for_rc_params(dsc_cfg->bits_per_component);
+
+ if (row_index < 0 || column_index < 0)
+ return -EINVAL;
+
+ dsc_cfg->first_line_bpg_offset =
+ rc_params[row_index][column_index].first_line_bpg_offset;
+ dsc_cfg->initial_xmit_delay =
+ rc_params[row_index][column_index].initial_xmit_delay;
+ dsc_cfg->initial_offset =
+ rc_params[row_index][column_index].initial_offset;
+ dsc_cfg->flatness_min_qp =
+ rc_params[row_index][column_index].flatness_min_qp;
+ dsc_cfg->flatness_max_qp =
+ rc_params[row_index][column_index].flatness_max_qp;
+ dsc_cfg->rc_quant_incr_limit0 =
+ rc_params[row_index][column_index].rc_quant_incr_limit0;
+ dsc_cfg->rc_quant_incr_limit1 =
+ rc_params[row_index][column_index].rc_quant_incr_limit1;
+
+ for (i = 0; i < DSC_NUM_BUF_RANGES; i++)
+ dsc_cfg->rc_range_params[i] =
+ rc_params[row_index][column_index].rc_range_params[i];
+
+ if (dsc_cfg->bits_per_component == 8 ||
+ dsc_cfg->bits_per_component == 10)
+ dsc_cfg->mux_word_size = DSC_MUX_WORD_SIZE_8_10_BPC;
+ else if (dsc_cfg->bits_per_component == 12)
+ dsc_cfg->mux_word_size = DSC_MUX_WORD_SIZE_12_BPC;
+
+ dsc_cfg->initial_scale_value = (dsc_cfg->rc_model_size << 3) /
+ (dsc_cfg->rc_model_size - dsc_cfg->initial_offset);
+
+ dsc_cfg->slice_count = mhdp->dsc_params.slice_count;
+
+ if (cdns_mhdp_compute_rc_params(dsc_cfg) < 0)
+ return -1;
+
+ /* FIXME: hardcoded values */
+ dsc_cfg->rc_tgt_offset_high = 3;
+ dsc_cfg->rc_tgt_offset_low = 3;
+ dsc_cfg->rc_edge_factor = 6;
+
+ return 0;
+}
+
+static int cdns_mhdp_dsc_wait_for_completion(struct cdns_mhdp_device *mhdp,
+ u32 event, int stream_id)
+{
+ u32 dsc_ctrl;
+ int ret;
+ unsigned long timeout;
+
+ ret = cdns_mhdp_reg_write_bit(mhdp, CDNS_DP_DSC_CTRL(stream_id),
+ event, 1, true);
+ if (ret)
+ return ret;
+
+
+ timeout = jiffies + msecs_to_jiffies(1000);
+
+ do {
+ cdns_mhdp_reg_read(mhdp, CDNS_DP_DSC_CTRL(stream_id),
+ &dsc_ctrl);
+ cpu_relax();
+ } while (((dsc_ctrl & event) != 0) &&
+ time_before(jiffies, timeout));
+
+ if (time_after_eq(jiffies, timeout)) {
+ DRM_DEV_ERROR(mhdp->dev,
+ "Timeout while waiting for SW reset.\n");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+int cdns_mhdp_dsc_reset(struct cdns_mhdp_device *mhdp)
+{
+ return cdns_mhdp_dsc_wait_for_completion(
+ mhdp, CDNS_DP_DSC_CTRL_SW_RST, 0);
+}
+
+int cdns_mhdp_dsc_update(struct cdns_mhdp_device *mhdp, int stream_id)
+{
+ return cdns_mhdp_dsc_wait_for_completion(
+ mhdp, CDNS_DP_DSC_CTRL_REG_UPDATE, stream_id);
+}
+
+int cdns_mhdp_dsc_enable(struct cdns_mhdp_device *mhdp,
+ int stream_id, bool enable)
+{
+ return cdns_mhdp_reg_write_bit(mhdp, CDNS_DP_DSC_CTRL(stream_id),
+ CDNS_DP_DSC_CTRL_EN, 1, enable);
+}
+
+int cdns_mhdp_dsc_sink_enable(struct cdns_mhdp_device *mhdp,
+ bool enable)
+{
+ return drm_dp_dpcd_writeb(&mhdp->aux, DP_DSC_ENABLE, enable);
+}
+
+static void cdns_mhdp_write_data_packet(struct cdns_mhdp_device *mhdp,
+ u32 *buf, int length)
+{
+ int i;
+ u32 reg_val;
+
+ for (i = 0; i < length; i++) {
+ reg_val = buf[i];
+ writel(reg_val, mhdp->regs + SOURCE_PIF_DATA_WR);
+ }
+}
+
+static void cdns_mhdp_write_pps_header(struct cdns_mhdp_device *mhdp,
+ u32 *buf)
+{
+ writel(SOURCE_PIF_PPS_PPS, mhdp->regs + SOURCE_PIF_PPS);
+
+ writel(*buf, mhdp->regs + SOURCE_PIF_PPS_HEADER);
+}
+
+static int cdns_mhdp_write_pps_infoframe(struct cdns_mhdp_device *mhdp,
+ struct dsc_pps_infoframe *pps_infoframe)
+{
+ u32 reg_val;
+ u32 entry_id = 0;
+
+ cdns_mhdp_write_pps_header(mhdp, (u32 *)&pps_infoframe->pps_header);
+ cdns_mhdp_write_data_packet(mhdp, (u32 *)&pps_infoframe->pps_payload,
+ DP_DSC_PPS_SIZE);
+
+ /* Entry ID */
+ writel(entry_id, mhdp->regs + SOURCE_PIF_WR_ADDR);
+
+ writel(SOURCE_PIF_WR_REQ_HOST_WR, mhdp->regs + SOURCE_PIF_WR_REQ);
+
+ reg_val = SOURCE_PIF_PKT_ALLOC_REG_ACTIVE_IDLE_TYPE |
+ SOURCE_PIF_PKT_ALLOC_REG_TYPE_VALID |
+ ((DP_SDP_PPS & SOURCE_PIF_PKT_ALLOC_REG_PACKET_TYPE) <<
+ SOURCE_PIF_PKT_ALLOC_REG_PACKET_TYPE_SHIFT) |
+ (entry_id & SOURCE_PIF_PKT_ALLOC_REG_PKT_ALLOC_ADDR);
+ writel(reg_val, mhdp->regs + SOURCE_PIF_PKT_ALLOC_REG);
+
+ writel(SOURCE_PIF_PKT_ALLOC_WR_EN_EN, mhdp->regs +
+ SOURCE_PIF_PKT_ALLOC_WR_EN);
+
+ return 0;
+}
+int cdns_mhdp_dsc_send_pps_sdp(struct cdns_mhdp_device *mhdp)
+{
+ struct dsc_config *dsc_cfg = &mhdp->dsc_config;
+ struct dsc_pps_infoframe dp_dsc_pps_sdp;
+
+ dsc_dp_pps_header_init(&dp_dsc_pps_sdp);
+
+ dsc_pps_infoframe_pack(&dp_dsc_pps_sdp, dsc_cfg);
+
+ return cdns_mhdp_write_pps_infoframe(mhdp, &dp_dsc_pps_sdp);
+}
+
+int cdns_mhdp_dsc_set_stream_compressed(struct cdns_mhdp_device *mhdp,
+ int stream_id,
+ bool compressed)
+{
+ u32 reg_val;
+ int ret;
+
+ ret = cdns_mhdp_reg_read(mhdp, CDNS_DP_VB_ID(stream_id),
+ &reg_val);
+ if (ret)
+ return ret;
+
+ if (compressed)
+ reg_val |= CDNS_DP_VB_ID_COMPRESSED;
+ else
+ reg_val &= ~CDNS_DP_VB_ID_COMPRESSED;
+
+ ret = cdns_mhdp_reg_write(mhdp, CDNS_DP_VB_ID(stream_id),
+ reg_val);
+ return ret;
+}
diff --git a/drivers/gpu/drm/bridge/cdns-mhdp-dsc.h b/drivers/gpu/drm/bridge/cdns-mhdp-dsc.h
new file mode 100644
index 000000000000..fec1d360962d
--- /dev/null
+++ b/drivers/gpu/drm/bridge/cdns-mhdp-dsc.h
@@ -0,0 +1,304 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) Cadence Design Systems, Inc.
+ * Author: Przemyslaw Gaj <pgaj@xxxxxxxxxxx>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef CDNS_MHDP_DSC_H_
+#define CDNS_MHDP_DSC_H_
+
+#include <linux/bitops.h>
+#include <linux/io.h>
+#include <drm/drm_print.h>
+#include <drm/drm_bridge.h>
+#include <drm/drm_connector.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/bridge/cdns-mhdp-common.h>
+
+#define DSC_SUPPORTED_VERSION_MIN 1
+
+#define DSC_OUTPUT_BUFFER_MAX_ADDRESS 3667U
+
+#define CDNS_DP_DSC_CTRL(d) (0x00B14 + ((d) * 0x20))
+#define CDNS_DP_DSC_CTRL_EN BIT(0)
+#define CDNS_DP_DSC_CTRL_SW_RST BIT(1)
+#define CDNS_DP_DSC_CTRL_REG_UPDATE BIT(2)
+
+#define CDNS_DP_COM_MAIN_CONF 0x30C00
+#define CDNS_DP_COM_MAIN_CONF_SPLIT_PANEL BIT(0)
+#define CDNS_DP_COM_MAIN_CONF_MUX_MODE BIT(1)
+#define CDNS_DP_COM_MAIN_CONF_MUX_SEL_OUT BIT(2)
+#define CDNS_DP_COM_MAIN_CONF_DE_RASTER_EN BIT(3)
+#define CDNS_DP_COM_MAIN_CONF_INPUT_MODE BIT(4)
+#define CDNS_DP_COM_MAIN_CONF_MUX_EOC_EN BIT(5)
+#define CDNS_DP_COM_MAIN_CONF_AUTO_DB_UPDATE BIT(6)
+
+#define CDNS_DP_ENC_MAIN_CONF(d) (0x30D20 + ((d) * 0x100))
+#define CDNS_DP_ENC_MAIN_CONF_INPUT_BPC GENMASK(1, 0)
+#define CDNS_DP_ENC_MAIN_CONF_CONVERT_RGB BIT(2)
+#define CDNS_DP_ENC_MAIN_CONF_ENABLE_422 BIT(3)
+#define CDNS_DP_ENC_MAIN_CONF_LINEBUF_DEPTH GENMASK(7, 4)
+#define CDNS_DP_ENC_MAIN_CONF_LINEBUF_DEPTH_SHIFT 4
+#define CDNS_DP_ENC_MAIN_CONF_BITS_PER_PIXEL GENMASK(17, 8)
+#define CDNS_DP_ENC_MAIN_CONF_BITS_PER_PIXEL_SHIFT 8
+#define CDNS_DP_ENC_MAIN_CONF_BLOCK_PRED_EN BIT(18)
+#define CDNS_DP_ENC_MAIN_CONF_VIDEO_MODE BIT(19)
+#define CDNS_DP_ENC_MAIN_CONF_ICH_RST_EOL BIT(20)
+#define CDNS_DP_ENC_MAIN_CONF_INITIAL_LINES GENMASK(31, 24)
+#define CDNS_DP_ENC_MAIN_CONF_INITIAL_LINES_SHIFT 24
+
+#define CDNS_DP_ENC_PICTURE_SIZE(d) (CDNS_DP_ENC_MAIN_CONF(d) + 0x4)
+#define CDNS_DP_ENC_PICTURE_SIZE_HEIGHT GENMASK(31, 16)
+#define CDNS_DP_ENC_PICTURE_SIZE_HEIGHT_SHIFT 16
+#define CDNS_DP_ENC_PICTURE_SIZE_WIDTH GENMASK(15, 0)
+
+#define CDNS_DP_ENC_SLICE_SIZE(d) (CDNS_DP_ENC_MAIN_CONF(d) + 0x8)
+#define CDNS_DP_ENC_SLICE_SIZE_HEIGHT GENMASK(31, 16)
+#define CDNS_DP_ENC_SLICE_SIZE_HEIGHT_SHIFT 16
+#define CDNS_DP_ENC_SLICE_SIZE_WIDTH GENMASK(15, 0)
+
+#define CDNS_DP_ENC_MISC_SIZE(d) (CDNS_DP_ENC_MAIN_CONF(d) + 0xc)
+#define CDNS_DP_ENC_MISC_SIZE_CHUNK_SIZE GENMASK(31, 16)
+#define CDNS_DP_ENC_MISC_SIZE_CHUNK_SIZE_SHIFT 16
+#define CDNS_DP_ENC_MISC_SIZE_OB_MAX_ADDR GENMASK(15, 2)
+#define CDNS_DP_ENC_MISC_SIZE_OB_MAX_ADDR_SHIFT 2
+#define CDNS_DP_ENC_MISC_SIZE_LAST_GRP_SIZE GENMASK(1, 0)
+
+#define CDNS_DP_ENC_HRD_DELAYS(d) (CDNS_DP_ENC_MAIN_CONF(d) + 0x10)
+#define CDNS_DP_ENC_HRD_DELAYS_INIT_DEC_DELAY GENMASK(31, 16)
+#define CDNS_DP_ENC_HRD_DELAYS_INIT_DEC_DELAY_SHIFT 16
+#define CDNS_DP_ENC_HRD_DELAYS_INIT_XMIT_DELAY GENMASK(9, 0)
+
+#define CDNS_DP_ENC_RC_SCALE(d) (CDNS_DP_ENC_MAIN_CONF(d) + 0x14)
+#define CDNS_DP_ENC_RC_SCALE_INIT_SCALE_VALUE GENMASK(9, 0)
+
+#define CDNS_DP_ENC_RC_SCALE_INC_DEC(d) (CDNS_DP_ENC_MAIN_CONF(d) + 0x18)
+#define CDNS_DP_ENC_RC_SCALE_DEC_INTERVAL GENMASK(27, 16)
+#define CDNS_DP_ENC_RC_SCALE_DEC_INTERVAL_SHIFT 16
+#define CDNS_DP_ENC_RC_SCALE_INC_INTERVAL GENMASK(15, 0)
+
+#define CDNS_DP_ENC_RC_OFFSETS_1(d) (CDNS_DP_ENC_MAIN_CONF(d) + 0x1c)
+#define CDNS_DP_ENC_RC_OFFSETS_1_FL_BGP_OFFSET GENMASK(4, 0)
+
+#define CDNS_DP_ENC_RC_OFFSETS_2(d) (CDNS_DP_ENC_MAIN_CONF(d) + 0x20)
+#define CDNS_DP_ENC_RC_OFFSETS_2_SL_BGP_OFFSET GENMASK(31, 16)
+#define CDNS_DP_ENC_RC_OFFSETS_2_SL_BGP_OFFSET_SHIFT 16
+#define CDNS_DP_ENC_RC_OFFSETS_2_NFL_BGP_OFFSET GENMASK(15, 0)
+
+#define CDNS_DP_ENC_RC_OFFSETS_3(d) (CDNS_DP_ENC_MAIN_CONF(d) + 0x24)
+#define CDNS_DP_ENC_RC_OFFSETS_3_FINAL_OFFSET GENMASK(31, 16)
+#define CDNS_DP_ENC_RC_OFFSETS_3_FINAL_OFFSET_SHIFT 16
+#define CDNS_DP_ENC_RC_OFFSETS_3_INIT_OFFSET GENMASK(15, 0)
+
+#define CDNS_DP_ENC_FLATNESS_DETECTION(d) (CDNS_DP_ENC_MAIN_CONF(d) + 0x28)
+#define CDNS_DP_ENC_FLATNESS_DETECTION_THRESH GENMASK(17, 10)
+#define CDNS_DP_ENC_FLATNESS_DETECTION_THRESH_SHIFT 10
+#define CDNS_DP_ENC_FLATNESS_DETECTION_MAX_QP GENMASK(9, 5)
+#define CDNS_DP_ENC_FLATNESS_DETECTION_MAX_QP_SHIFT 5
+#define CDNS_DP_ENC_FLATNESS_DETECTION_MIN_QP GENMASK(4, 0)
+
+#define CDNS_DP_ENC_RC_MODEL_SIZE(d) (CDNS_DP_ENC_MAIN_CONF(d) + 0x2c)
+#define CDNS_DP_ENC_RC_MODEL_SIZE_RC_MODEL_SIZE GENMASK(15, 0)
+
+#define CDNS_DP_ENC_RC_CONFIG(d) (CDNS_DP_ENC_MAIN_CONF(d) + 0x30)
+#define CDNS_DP_ENC_RC_CONFIG_TGT_OFFSET_LO GENMASK(27, 24)
+#define CDNS_DP_ENC_RC_CONFIG_TGT_OFFSET_LO_SHIFT 24
+#define CDNS_DP_ENC_RC_CONFIG_TGT_OFFSET_HI GENMASK(23, 20)
+#define CDNS_DP_ENC_RC_CONFIG_TGT_OFFSET_HI_SHIFT 20
+#define CDNS_DP_ENC_RC_CONFIG_QUANT_INC_LIM_1 GENMASK(17, 13)
+#define CDNS_DP_ENC_RC_CONFIG_QUANT_INC_LIM_1_SHIFT 13
+#define CDNS_DP_ENC_RC_CONFIG_QUANT_INC_LIM_0 GENMASK(12, 8)
+#define CDNS_DP_ENC_RC_CONFIG_QUANT_INC_LIM_0_SHIFT 8
+#define CDNS_DP_ENC_RC_CONFIG_EDGE_FACTOR GENMASK(3, 0)
+
+#define CDNS_DP_ENC_RC_BUF_THRESH_0(d) (CDNS_DP_ENC_MAIN_CONF(d) + 0x34)
+#define CDNS_DP_ENC_RC_BUF_THRESH_0_THRESH_3 GENMASK(31, 24)
+#define CDNS_DP_ENC_RC_BUF_THRESH_0_THRESH_2 GENMASK(23, 16)
+#define CDNS_DP_ENC_RC_BUF_THRESH_0_THRESH_1 GENMASK(15, 8)
+#define CDNS_DP_ENC_RC_BUF_THRESH_0_THRESH_0 GENMASK(7, 0)
+
+#define CDNS_DP_ENC_RC_BUF_THRESH_1(d) (CDNS_DP_ENC_MAIN_CONF(d) + 0x38)
+#define CDNS_DP_ENC_RC_BUF_THRESH_1_THRESH_7 GENMASK(31, 24)
+#define CDNS_DP_ENC_RC_BUF_THRESH_1_THRESH_6 GENMASK(23, 16)
+#define CDNS_DP_ENC_RC_BUF_THRESH_1_THRESH_5 GENMASK(15, 8)
+#define CDNS_DP_ENC_RC_BUF_THRESH_1_THRESH_4 GENMASK(7, 0)
+
+#define CDNS_DP_ENC_RC_BUF_THRESH_2(d) (CDNS_DP_ENC_MAIN_CONF(d) + 0x3c)
+#define CDNS_DP_ENC_RC_BUF_THRESH_2_THRESH_11 GENMASK(31, 24)
+#define CDNS_DP_ENC_RC_BUF_THRESH_2_THRESH_10 GENMASK(23, 16)
+#define CDNS_DP_ENC_RC_BUF_THRESH_2_THRESH_9 GENMASK(15, 8)
+#define CDNS_DP_ENC_RC_BUF_THRESH_2_THRESH_8 GENMASK(7, 0)
+
+#define CDNS_DP_ENC_RC_BUF_THRESH_3(d) (CDNS_DP_ENC_MAIN_CONF(d) + 0x40)
+#define CDNS_DP_ENC_RC_BUF_THRESH_3_THRESH_13 GENMASK(15, 8)
+#define CDNS_DP_ENC_RC_BUF_THRESH_3_THRESH_12 GENMASK(7, 0)
+
+#define CDNS_DP_ENC_RC_BUF_THRESH_THRESH_3_SHIFT 24
+#define CDNS_DP_ENC_RC_BUF_THRESH_THRESH_2_SHIFT 16
+#define CDNS_DP_ENC_RC_BUF_THRESH_THRESH_1_SHIFT 8
+
+#define CDNS_DP_ENC_RC_MIN_QP_0(d) (CDNS_DP_ENC_MAIN_CONF(d) + 0x44)
+#define CDNS_DP_ENC_RC_MIN_QP_0_RANGE_4 GENMASK(24, 20)
+#define CDNS_DP_ENC_RC_MIN_QP_0_RANGE_3 GENMASK(19, 15)
+#define CDNS_DP_ENC_RC_MIN_QP_0_RANGE_2 GENMASK(14, 10)
+#define CDNS_DP_ENC_RC_MIN_QP_0_RANGE_1 GENMASK(9, 5)
+#define CDNS_DP_ENC_RC_MIN_QP_0_RANGE_0 GENMASK(4, 0)
+
+#define CDNS_DP_ENC_RC_MIN_QP_1(d) (CDNS_DP_ENC_MAIN_CONF(d) + 0x48)
+#define CDNS_DP_ENC_RC_MIN_QP_1_RANGE_9 GENMASK(24, 20)
+#define CDNS_DP_ENC_RC_MIN_QP_1_RANGE_8 GENMASK(19, 15)
+#define CDNS_DP_ENC_RC_MIN_QP_1_RANGE_7 GENMASK(14, 10)
+#define CDNS_DP_ENC_RC_MIN_QP_1_RANGE_6 GENMASK(9, 5)
+#define CDNS_DP_ENC_RC_MIN_QP_1_RANGE_5 GENMASK(4, 0)
+
+#define CDNS_DP_ENC_RC_MIN_QP_2(d) (CDNS_DP_ENC_MAIN_CONF(d) + 0x4c)
+#define CDNS_DP_ENC_RC_MIN_QP_2_RANGE_14 GENMASK(24, 20)
+#define CDNS_DP_ENC_RC_MIN_QP_2_RANGE_13 GENMASK(19, 15)
+#define CDNS_DP_ENC_RC_MIN_QP_2_RANGE_12 GENMASK(14, 10)
+#define CDNS_DP_ENC_RC_MIN_QP_2_RANGE_11 GENMASK(9, 5)
+#define CDNS_DP_ENC_RC_MIN_QP_2_RANGE_10 GENMASK(4, 0)
+
+#define CDNS_DP_ENC_RC_MAX_QP_0(d) (CDNS_DP_ENC_MAIN_CONF(d) + 0x50)
+#define CDNS_DP_ENC_RC_MAX_QP_0_RANGE_4 GENMASK(24, 20)
+#define CDNS_DP_ENC_RC_MAX_QP_0_RANGE_3 GENMASK(19, 15)
+#define CDNS_DP_ENC_RC_MAX_QP_0_RANGE_2 GENMASK(14, 10)
+#define CDNS_DP_ENC_RC_MAX_QP_0_RANGE_1 GENMASK(9, 5)
+#define CDNS_DP_ENC_RC_MAX_QP_0_RANGE_0 GENMASK(4, 0)
+
+#define CDNS_DP_ENC_RC_MAX_QP_1(d) (CDNS_DP_ENC_MAIN_CONF(d) + 0x54)
+#define CDNS_DP_ENC_RC_MAX_QP_1_RANGE_9 GENMASK(24, 20)
+#define CDNS_DP_ENC_RC_MAX_QP_1_RANGE_8 GENMASK(19, 15)
+#define CDNS_DP_ENC_RC_MAX_QP_1_RANGE_7 GENMASK(14, 10)
+#define CDNS_DP_ENC_RC_MAX_QP_1_RANGE_6 GENMASK(9, 5)
+#define CDNS_DP_ENC_RC_MAX_QP_1_RANGE_5 GENMASK(4, 0)
+
+#define CDNS_DP_ENC_RC_MAX_QP_2(d) (CDNS_DP_ENC_MAIN_CONF(d) + 0x58)
+#define CDNS_DP_ENC_RC_MAX_QP_2_RANGE_14 GENMASK(24, 20)
+#define CDNS_DP_ENC_RC_MAX_QP_2_RANGE_13 GENMASK(19, 15)
+#define CDNS_DP_ENC_RC_MAX_QP_2_RANGE_12 GENMASK(14, 10)
+#define CDNS_DP_ENC_RC_MAX_QP_2_RANGE_11 GENMASK(9, 5)
+#define CDNS_DP_ENC_RC_MAX_QP_2_RANGE_10 GENMASK(4, 0)
+
+#define CDNS_DP_ENC_RC_QP_RANGE_4_SHIFT 20
+#define CDNS_DP_ENC_RC_QP_RANGE_3_SHIFT 15
+#define CDNS_DP_ENC_RC_QP_RANGE_2_SHIFT 10
+#define CDNS_DP_ENC_RC_QP_RANGE_1_SHIFT 5
+
+#define CDNS_DP_ENC_RC_RANGE_BPG_OFFSETS_0(d) (CDNS_DP_ENC_MAIN_CONF(d) + 0x5c)
+#define CDNS_DP_ENC_RC_RANGE_BPG_OFFSETS_0_4 GENMASK(24, 20)
+#define CDNS_DP_ENC_RC_RANGE_BPG_OFFSETS_0_3 GENMASK(19, 15)
+#define CDNS_DP_ENC_RC_RANGE_BPG_OFFSETS_0_2 GENMASK(14, 10)
+#define CDNS_DP_ENC_RC_RANGE_BPG_OFFSETS_0_1 GENMASK(9, 5)
+#define CDNS_DP_ENC_RC_RANGE_BPG_OFFSETS_0_0 GENMASK(4, 0)
+
+#define CDNS_DP_ENC_RC_RANGE_BPG_OFFSETS_1(d) (CDNS_DP_ENC_MAIN_CONF(d) + 0x60)
+#define CDNS_DP_ENC_RC_RANGE_BPG_OFFSETS_0_9 GENMASK(24, 20)
+#define CDNS_DP_ENC_RC_RANGE_BPG_OFFSETS_0_8 GENMASK(19, 15)
+#define CDNS_DP_ENC_RC_RANGE_BPG_OFFSETS_0_7 GENMASK(14, 10)
+#define CDNS_DP_ENC_RC_RANGE_BPG_OFFSETS_0_6 GENMASK(9, 5)
+#define CDNS_DP_ENC_RC_RANGE_BPG_OFFSETS_0_5 GENMASK(4, 0)
+
+#define CDNS_DP_ENC_RC_RANGE_BPG_OFFSETS_2(d) (CDNS_DP_ENC_MAIN_CONF(d) + 0x64)
+#define CDNS_DP_ENC_RC_RANGE_BPG_OFFSETS_0_14 GENMASK(24, 20)
+#define CDNS_DP_ENC_RC_RANGE_BPG_OFFSETS_0_13 GENMASK(19, 15)
+#define CDNS_DP_ENC_RC_RANGE_BPG_OFFSETS_0_12 GENMASK(14, 10)
+#define CDNS_DP_ENC_RC_RANGE_BPG_OFFSETS_0_11 GENMASK(9, 5)
+#define CDNS_DP_ENC_RC_RANGE_BPG_OFFSETS_0_10 GENMASK(4, 0)
+
+#define CDNS_DP_ENC_DPI_CTRL_OUT_DELAY(d) (CDNS_DP_ENC_MAIN_CONF(d) + 0x68)
+#define CDNS_DP_ENC_DPI_CTRL_OUT_DELAY_CYCLES GENMASK(15, 0)
+
+#define CDNS_DP_ENC_GENERAL_STATUS(d) (CDNS_DP_ENC_MAIN_CONF(d) + 0xa0)
+#define CDNS_DP_ENC_GENERAL_STATUS_OUT_BUFF_FULL_1 BIT(6)
+#define CDNS_DP_ENC_GENERAL_STATUS_OUT_BUFF_FULL_0 BIT(5)
+#define CDNS_DP_ENC_GENERAL_STATUS_OUT_BUFF_EMPTY_1 BIT(4)
+#define CDNS_DP_ENC_GENERAL_STATUS_OUT_BUFF_EMPTY_0 BIT(3)
+#define CDNS_DP_ENC_GENERAL_STATUS_FRAME_DONE BIT(2)
+#define CDNS_DP_ENC_GENERAL_STATUS_FRAME_STARTED BIT(1)
+#define CDNS_DP_ENC_GENERAL_STATUS_CE BIT(0)
+
+#define CDNS_DP_ENC_HSLICE_STATUS(d) (CDNS_DP_ENC_MAIN_CONF(d) + 0xa4)
+#define CDNS_DP_ENC_HSLICE_STATUS_ACTUAL_SLICE GENMASK(31, 16)
+#define CDNS_DP_ENC_HSLICE_STATUS_ACTUAL_LINE GENMASK(15, 0)
+
+#define CDNS_DP_ENC_OUT_STATUS(d) (CDNS_DP_ENC_MAIN_CONF(d) + 0xa8)
+#define CDNS_DP_ENC_OUT_STATUS_ACTUAL_SLICE GENMASK(31, 16)
+#define CDNS_DP_ENC_OUT_STATUS_ACTUAL_LINE GENMASK(15, 0)
+
+#define CDNS_DP_ENC_INT_STAT(d) (CDNS_DP_ENC_MAIN_CONF(d) + 0xac)
+#define CDNS_DP_ENC_INT_STAT_OUT_BUFF_FULL_1 BIT(10)
+#define CDNS_DP_ENC_INT_STAT_OUT_BUFF_FULL_0 BIT(9)
+#define CDNS_DP_ENC_INT_STAT_OUT_BUFF_EMPTY_1 BIT(8)
+#define CDNS_DP_ENC_INT_STAT_OUT_BUFF_EMPTY_0 BIT(7)
+#define CDNS_DP_ENC_INT_STAT_FRAME_DONE BIT(6)
+#define CDNS_DP_ENC_INT_STAT_FRAME_STARTED BIT(5)
+#define CDNS_DP_ENC_INT_STAT_CE BIT(4)
+#define CDNS_DP_ENC_INT_STAT_RC_BUFF_OVER_1 BIT(3)
+#define CDNS_DP_ENC_INT_STAT_RC_BUFF_OVER_0 BIT(2)
+#define CDNS_DP_ENC_INT_STAT_OUT_BUFF_UND_1 BIT(1)
+#define CDNS_DP_ENC_INT_STAT_OUT_BUFF_UND_0 BIT(0)
+
+#define CDNS_DP_ENC_INT_CLR(d) (CDNS_DP_ENC_MAIN_CONF(d) + 0xb0)
+#define CDNS_DP_ENC_INT_CLR_OUT_BUFF_FULL_1 BIT(10)
+#define CDNS_DP_ENC_INT_CLR_OUT_BUFF_FULL_0 BIT(9)
+#define CDNS_DP_ENC_INT_CLR_OUT_BUFF_EMPTY_1 BIT(8)
+#define CDNS_DP_ENC_INT_CLR_OUT_BUFF_EMPTY_0 BIT(7)
+#define CDNS_DP_ENC_INT_CLR_FRAME_DONE BIT(6)
+#define CDNS_DP_ENC_INT_CLR_FRAME_STARTED BIT(5)
+#define CDNS_DP_ENC_INT_CLR_CE BIT(4)
+#define CDNS_DP_ENC_INT_CLR_RC_BUFF_OVER_1 BIT(3)
+#define CDNS_DP_ENC_INT_CLR_RC_BUFF_OVER_0 BIT(2)
+#define CDNS_DP_ENC_INT_CLR_OUT_BUFF_UND_1 BIT(1)
+#define CDNS_DP_ENC_INT_CLR_OUT_BUFF_UND_0 BIT(0)
+
+#define CDNS_DP_ENC_INT_MASK(d) (CDNS_DP_ENC_MAIN_CONF(d) + 0xb4)
+#define CDNS_DP_ENC_INT_MASK_OUT_BUFF_FULL_1 BIT(10)
+#define CDNS_DP_ENC_INT_MASK_OUT_BUFF_FULL_0 BIT(9)
+#define CDNS_DP_ENC_INT_MASK_OUT_BUFF_EMPTY_1 BIT(8)
+#define CDNS_DP_ENC_INT_MASK_OUT_BUFF_EMPTY_0 BIT(7)
+#define CDNS_DP_ENC_INT_MASK_FRAME_DONE BIT(6)
+#define CDNS_DP_ENC_INT_MASK_FRAME_STARTED BIT(5)
+#define CDNS_DP_ENC_INT_MASK_CE BIT(4)
+#define CDNS_DP_ENC_INT_MASK_RC_BUFF_OVER_1 BIT(3)
+#define CDNS_DP_ENC_INT_MASK_RC_BUFF_OVER_0 BIT(2)
+#define CDNS_DP_ENC_INT_MASK_OUT_BUFF_UND_1 BIT(1)
+#define CDNS_DP_ENC_INT_MASK_OUT_BUFF_UND_0 BIT(0)
+
+#define CDNS_DP_ENC_INT_TEST(d) (CDNS_DP_ENC_MAIN_CONF(d) + 0xbb)
+#define CDNS_DP_ENC_INT_TEST_OUT_BUFF_FULL_1 BIT(10)
+#define CDNS_DP_ENC_INT_TEST_OUT_BUFF_FULL_0 BIT(9)
+#define CDNS_DP_ENC_INT_TEST_OUT_BUFF_EMPTY_1 BIT(8)
+#define CDNS_DP_ENC_INT_TEST_OUT_BUFF_EMPTY_0 BIT(7)
+#define CDNS_DP_ENC_INT_TEST_FRAME_DONE BIT(6)
+#define CDNS_DP_ENC_INT_TEST_FRAME_STARTED BIT(5)
+#define CDNS_DP_ENC_INT_TEST_CE BIT(4)
+#define CDNS_DP_ENC_INT_TEST_RC_BUFF_OVER_1 BIT(3)
+#define CDNS_DP_ENC_INT_TEST_RC_BUFF_OVER_0 BIT(2)
+#define CDNS_DP_ENC_INT_TEST_OUT_BUFF_UND_1 BIT(1)
+#define CDNS_DP_ENC_INT_TEST_OUT_BUFF_UND_0 BIT(0)
+
+int cdns_mhdp_dsc_enable(struct cdns_mhdp_device *mhdp,
+ int stream_id, bool enable);
+int cdns_mhdp_dsc_sink_enable(struct cdns_mhdp_device *mhdp,
+ bool enable);
+int cdns_mhdp_dsc_reset(struct cdns_mhdp_device *mhdp);
+void cdns_mhdp_dsc_write_config(struct cdns_mhdp_device *mhdp);
+void cdns_mhdp_dsc_write_enc_config(struct cdns_mhdp_device *mhdp,
+ int stream_id);
+int cdns_mhdp_dsc_sink_support(struct cdns_mhdp_device *mhdp);
+int cdns_mhdp_compute_dsc_params(struct cdns_mhdp_device *mhdp);
+int cdns_mhdp_dsc_set_stream_compressed(struct cdns_mhdp_device *mhdp,
+ int stream_id,
+ bool compressed);
+int cdns_mhdp_dsc_send_pps_sdp(struct cdns_mhdp_device *mhdp);
+
+#endif /* MHDP_DSC_H_ */
diff --git a/drivers/gpu/drm/bridge/cdns-mhdp-mst.c b/drivers/gpu/drm/bridge/cdns-mhdp-mst.c
index 37a0c773ee54..86b26326e73a 100644
--- a/drivers/gpu/drm/bridge/cdns-mhdp-mst.c
+++ b/drivers/gpu/drm/bridge/cdns-mhdp-mst.c
@@ -286,7 +286,7 @@ void cdns_mhdp_mst_enable(struct drm_bridge *bridge)
disp_info = &mhdp_bridge->connector->base.display_info;

pxlfmt = cdns_mhdp_get_pxlfmt(disp_info->color_formats);
- bpp = cdns_mhdp_get_bpp(disp_info->bpc, pxlfmt);
+ bpp = cdns_mhdp_get_bpp(mhdp, disp_info->bpc, pxlfmt);

mhdp_connector = mhdp_bridge->connector;
if (mhdp_bridge->stream_id > -1) {
diff --git a/drivers/gpu/drm/bridge/cdns-mhdp.c b/drivers/gpu/drm/bridge/cdns-mhdp.c
index 2f857da4691a..ad4aa2a667f2 100644
--- a/drivers/gpu/drm/bridge/cdns-mhdp.c
+++ b/drivers/gpu/drm/bridge/cdns-mhdp.c
@@ -32,6 +32,7 @@
#include <linux/of_irq.h>

#include "cdns-mhdp.h"
+#include "cdns-mhdp-dsc.h"

#define DEBUG_MSG

@@ -913,6 +914,33 @@ static int cdns_mhdp_link_up(struct cdns_mhdp_device *mhdp)
return 0;
}

+u32 cdns_mhdp_get_bpp(struct cdns_mhdp_device *mhdp, u32 bpc,
+ enum pixel_format pxlfmt)
+{
+ u32 bpp;
+
+ if (mhdp->dsc_params.compression_enable)
+ return mhdp->dsc_params.compressed_bpp;
+
+ switch (pxlfmt) {
+ case PIXEL_FORMAT_RGB:
+ bpp = bpc * 3;
+ break;
+ case PIXEL_FORMAT_YCBCR_444:
+ bpp = bpc * 3;
+ break;
+ case PIXEL_FORMAT_YCBCR_422:
+ bpp = bpc * 2;
+ break;
+ case PIXEL_FORMAT_YCBCR_420:
+ bpp = bpc * 3 / 2;
+ break;
+ default:
+ bpp = bpc;
+ }
+ return bpp;
+}
+
static int cdns_mhdp_sst_enable(struct drm_bridge *bridge)
{
struct cdns_mhdp_bridge *mhdp_bridge = to_mhdp_bridge(bridge);
@@ -933,7 +961,7 @@ static int cdns_mhdp_sst_enable(struct drm_bridge *bridge)
rate = mhdp->link.rate / 1000;

pxlfmt = cdns_mhdp_get_pxlfmt(disp_info->color_formats);
- bpp = cdns_mhdp_get_bpp(disp_info->bpc, pxlfmt);
+ bpp = cdns_mhdp_get_bpp(mhdp, disp_info->bpc, pxlfmt);

if (mhdp->fec_enabled && cdns_mhdp_fec_enable(mhdp, true)) {
mhdp->fec_enabled = false;
@@ -942,6 +970,34 @@ static int cdns_mhdp_sst_enable(struct drm_bridge *bridge)
mhdp->fec_enabled = true;
}

+ if (!cdns_mhdp_dsc_sink_support(mhdp)) {
+ int ret;
+
+ ret = cdns_mhdp_dsc_reset(mhdp);
+ if (ret)
+ dev_err(mhdp->dev, "DSC reset failed. ret = %d\n", ret);
+ mhdp->dsc_params.compressed_bpp = 8;
+ mhdp->dsc_params.slice_count = 10;
+ ret = cdns_mhdp_compute_dsc_params(mhdp);
+ if (ret < 0) {
+ dev_err(mhdp->dev, "DSC params computation failed. ret = %d\n", ret);
+ } else {
+ mhdp->dsc_params.compression_enable = true;
+ /* Write config for stream 0 */
+ cdns_mhdp_dsc_write_enc_config(mhdp, 0);
+ }
+ }
+
+ /* Enable DSC for stream 0 */
+ if (mhdp->dsc_params.compression_enable) {
+ cdns_mhdp_dsc_enable(mhdp, 0, true);
+
+ if (cdns_mhdp_dsc_sink_enable(mhdp, true))
+ dev_err(mhdp->dev, "Cannot enable DSC in sink.\n");
+
+ cdns_mhdp_dsc_send_pps_sdp(mhdp);
+ cdns_mhdp_dsc_set_stream_compressed(mhdp, 0, true);
+ }

/* find optimal tu_size */
required_bandwidth = pxlclock * bpp / 8;
@@ -983,6 +1039,17 @@ static int cdns_mhdp_sst_enable(struct drm_bridge *bridge)

cdns_mhdp_configure_video(bridge);

+ if (mhdp->dsc_params.compression_enable) {
+ u32 pxl_repr;
+
+ cdns_mhdp_reg_read(mhdp, CDNS_DP_FRAMER_PXL_REPR(0), &pxl_repr);
+ pxl_repr &= ~(CDNS_DP_FRAMER_PXL_REPR_M << CDNS_DP_FRAMER_PXL_REPR_M_SHIFT);
+ pxl_repr &= ~(CDNS_DP_FRAMER_PXL_REPR_DIFF << CDNS_DP_FRAMER_PXL_REPR_DIFF_SHIFT);
+ pxl_repr |= ((vs_f / 10) & CDNS_DP_FRAMER_PXL_REPR_M) << CDNS_DP_FRAMER_PXL_REPR_M_SHIFT |
+ ((100 - (vs_f / 10)) & CDNS_DP_FRAMER_PXL_REPR_DIFF) << CDNS_DP_FRAMER_PXL_REPR_DIFF_SHIFT;
+ cdns_mhdp_reg_write(mhdp, CDNS_DP_FRAMER_PXL_REPR(0), pxl_repr);
+ }
+
cdns_mhdp_set_video_status(mhdp, 1);

return 0;
@@ -1005,30 +1072,6 @@ enum pixel_format cdns_mhdp_get_pxlfmt(u32 color_formats)
return pxlfmt;
}

-
-u32 cdns_mhdp_get_bpp(u32 bpc, enum pixel_format pxlfmt)
-{
- u32 bpp;
-
- switch (pxlfmt) {
- case PIXEL_FORMAT_RGB:
- bpp = bpc * 3;
- break;
- case PIXEL_FORMAT_YCBCR_444:
- bpp = bpc * 3;
- break;
- case PIXEL_FORMAT_YCBCR_422:
- bpp = bpc * 2;
- break;
- case PIXEL_FORMAT_YCBCR_420:
- bpp = bpc * 3 / 2;
- break;
- default:
- bpp = bpc;
- }
- return bpp;
-}
-
void cdns_mhdp_configure_video(struct drm_bridge *bridge)
{
struct cdns_mhdp_bridge *mhdp_bridge = to_mhdp_bridge(bridge);
@@ -1057,7 +1100,7 @@ void cdns_mhdp_configure_video(struct drm_bridge *bridge)
pxlfmt == PIXEL_FORMAT_YCBCR_422) && mode->crtc_vdisplay >= 720)
misc0 = DP_YCBCR_COEFFICIENTS_ITU709;

- bpp = cdns_mhdp_get_bpp(disp_info->bpc, pxlfmt);
+ bpp = cdns_mhdp_get_bpp(mhdp, disp_info->bpc, pxlfmt);

switch (pxlfmt) {
case PIXEL_FORMAT_RGB:
@@ -1135,8 +1178,18 @@ void cdns_mhdp_configure_video(struct drm_bridge *bridge)
CDNS_DP_FRONT_PORCH(front_porch) |
CDNS_DP_BACK_PORCH(back_porch));

+ if (mhdp->dsc_params.compression_enable) {
+ u8 num_lanes = mhdp->link.num_lanes;
+
+ if (mhdp->is_mst)
+ num_lanes = 4;
+ cdns_mhdp_reg_write(mhdp, CDNS_DP_BYTE_COUNT(stream_id),
+ ((mhdp->dsc_config.slice_chunk_size / num_lanes) + 1) |
+ ((mhdp->dsc_config.slice_chunk_size / num_lanes) + 1) << CDNS_DP_BYTE_COUNT_BYTES_IN_CHUNK_SHIFT);
+ } else {
cdns_mhdp_reg_write(mhdp, CDNS_DP_BYTE_COUNT(stream_id),
mode->crtc_hdisplay * bpp / 8);
+ }

msa_h0 = mode->crtc_htotal - mode->crtc_hsync_start;
cdns_mhdp_reg_write(mhdp, CDNS_DP_MSA_HORIZONTAL_0(stream_id),
diff --git a/drivers/gpu/drm/bridge/cdns-mhdp.h b/drivers/gpu/drm/bridge/cdns-mhdp.h
index 857e2becb67d..9efa6970c521 100644
--- a/drivers/gpu/drm/bridge/cdns-mhdp.h
+++ b/drivers/gpu/drm/bridge/cdns-mhdp.h
@@ -133,6 +133,12 @@
#define CDNS_DP_FRAMER_YCBCR422 BIT(2)
#define CDNS_DP_FRAMER_YCBCR420 BIT(3)
#define CDNS_DP_FRAMER_Y_ONLY BIT(4)
+#define CDNS_DP_FRAMER_PXL_REPR_ENC_FMT GENMASK(12, 8)
+#define CDNS_DP_FRAMER_PXL_REPR_M GENMASK(22, 16)
+#define CDNS_DP_FRAMER_PXL_REPR_DIFF GENMASK(30, 24)
+#define CDNS_DP_FRAMER_PXL_REPR_ENC_FMT_SHIFT 8
+#define CDNS_DP_FRAMER_PXL_REPR_M_SHIFT 16
+#define CDNS_DP_FRAMER_PXL_REPR_DIFF_SHIFT 24

#define CDNS_DP_FRAMER_SP(s) (CDNS_DPTX_STREAM(s) + 0x10)
#define CDNS_DP_FRAMER_VSYNC_POL_LOW BIT(0)
@@ -202,7 +208,8 @@ int cdns_mhdp_mst_init(struct cdns_mhdp_device *mhdp);
void cdns_mhdp_mst_deinit(struct cdns_mhdp_device *mhdp);
bool cdns_mhdp_mst_probe(struct cdns_mhdp_device *mhdp);
enum pixel_format cdns_mhdp_get_pxlfmt(u32 color_formats);
-u32 cdns_mhdp_get_bpp(u32 bpc, u32 color_formats);
+u32 cdns_mhdp_get_bpp(struct cdns_mhdp_device *mhdp, u32 bpc,
+ enum pixel_format pxlfmt);
void cdns_mhdp_configure_video(struct drm_bridge *bridge);
void cdns_mhdp_mst_enable(struct drm_bridge *bridge);
void cdns_mhdp_mst_disable(struct drm_bridge *bridge);
diff --git a/include/drm/bridge/cdns-mhdp-common.h b/include/drm/bridge/cdns-mhdp-common.h
index 671a07696f24..1dda689f44f9 100644
--- a/include/drm/bridge/cdns-mhdp-common.h
+++ b/include/drm/bridge/cdns-mhdp-common.h
@@ -22,6 +22,504 @@
#include <drm/drm_bridge.h>
#include <drm/bridge/cdns-mhdp-cbs.h>

+/**
+ * TODO DK: The following defines are borrowed from a include/drm/drm_dsc.h
+ * introduced in not-yet-accepted patch:
+ * https://patchwork.kernel.org/cover/10596631/
+ * Remove when patch is accepted.
+ */
+
+/* VESA Display Stream Compression DSC 1.2 constants */
+#define DSC_NUM_BUF_RANGES 15
+#define DSC_MUX_WORD_SIZE_8_10_BPC 48
+#define DSC_MUX_WORD_SIZE_12_BPC 64
+
+/* DSC Rate Control Constants */
+#define DSC_RC_MODEL_SIZE_CONST 8192
+#define DSC_RC_EDGE_FACTOR_CONST 6
+#define DSC_RC_TGT_OFFSET_HI_CONST 3
+#define DSC_RC_TGT_OFFSET_LO_CONST 3
+
+/* DSC PPS constants and macros */
+#define DSC_PPS_VERSION_MAJOR_SHIFT 4
+#define DSC_PPS_BPC_SHIFT 4
+#define DSC_PPS_MSB_SHIFT 8
+#define DSC_PPS_LSB_MASK (0xFF << 0)
+#define DSC_PPS_BPP_HIGH_MASK (0x3 << 8)
+#define DSC_PPS_VBR_EN_SHIFT 2
+#define DSC_PPS_SIMPLE422_SHIFT 3
+#define DSC_PPS_CONVERT_RGB_SHIFT 4
+#define DSC_PPS_BLOCK_PRED_EN_SHIFT 5
+#define DSC_PPS_INIT_XMIT_DELAY_HIGH_MASK (0x3 << 8)
+#define DSC_PPS_SCALE_DEC_INT_HIGH_MASK (0xF << 8)
+#define DSC_PPS_RC_TGT_OFFSET_HI_SHIFT 4
+#define DSC_PPS_RC_RANGE_MINQP_SHIFT 11
+#define DSC_PPS_RC_RANGE_MAXQP_SHIFT 6
+#define DSC_PPS_NATIVE_420_SHIFT 1
+#define DSC_1_2_MAX_LINEBUF_DEPTH_BITS 16
+#define DSC_1_2_MAX_LINEBUF_DEPTH_VAL 0
+#define DSC_1_1_MAX_LINEBUF_DEPTH_BITS 13
+
+enum ROW_INDEX_BPP {
+ ROW_INDEX_6BPP = 0,
+ ROW_INDEX_8BPP,
+ ROW_INDEX_10BPP,
+ ROW_INDEX_12BPP,
+ ROW_INDEX_15BPP,
+ MAX_ROW_INDEX
+};
+
+enum COLUMN_INDEX_BPC {
+ COLUMN_INDEX_8BPC = 0,
+ COLUMN_INDEX_10BPC,
+ COLUMN_INDEX_12BPC,
+ COLUMN_INDEX_14BPC,
+ COLUMN_INDEX_16BPC,
+ MAX_COLUMN_INDEX
+};
+
+/* Configuration for a single Rate Control model range */
+struct dsc_rc_range_params {
+ /* Min Quantization Parameters allowed for this range */
+ u8 range_min_qp;
+ /* Max Quantization Parameters allowed for this range */
+ u8 range_max_qp;
+ /* Bits/group offset to apply to target for this group */
+ s8 range_bpg_offset;
+};
+
+struct dsc_config {
+ /* Bits / component for previous reconstructed line buffer */
+ u8 line_buf_depth;
+ /* Bits per component to code (must be 8, 10, or 12) */
+ u8 bits_per_component;
+ /*
+ * Flag indicating to do RGB - YCoCg conversion
+ * and back (should be 1 for RGB input)
+ */
+ bool convert_rgb;
+ u8 slice_count;
+ /* Slice Width */
+ u16 slice_width;
+ /* Slice Height */
+ u16 slice_height;
+ /*
+ * 4:2:2 enable mode (from PPS, 4:2:2 conversion happens
+ * outside of DSC encode/decode algorithm)
+ */
+ bool enable422;
+ /* Picture Width */
+ u16 pic_width;
+ /* Picture Height */
+ u16 pic_height;
+ /* Offset to bits/group used by RC to determine QP adjustment */
+ u8 rc_tgt_offset_high;
+ /* Offset to bits/group used by RC to determine QP adjustment */
+ u8 rc_tgt_offset_low;
+ /* Bits/pixel target << 4 (ie., 4 fractional bits) */
+ u16 bits_per_pixel;
+ /*
+ * Factor to determine if an edge is present based
+ * on the bits produced
+ */
+ u8 rc_edge_factor;
+ /* Slow down incrementing once the range reaches this value */
+ u8 rc_quant_incr_limit1;
+ /* Slow down incrementing once the range reaches this value */
+ u8 rc_quant_incr_limit0;
+ /* Number of pixels to delay the initial transmission */
+ u16 initial_xmit_delay;
+ /* Number of pixels to delay the VLD on the decoder,not including SSM */
+ u16 initial_dec_delay;
+ /* Block prediction enable */
+ bool block_pred_enable;
+ /* Bits/group offset to use for first line of the slice */
+ u8 first_line_bpg_offset;
+ /* Value to use for RC model offset at slice start */
+ u16 initial_offset;
+ /* Thresholds defining each of the buffer ranges */
+ u16 rc_buf_thresh[DSC_NUM_BUF_RANGES - 1];
+ /* Parameters for each of the RC ranges */
+ struct dsc_rc_range_params rc_range_params[DSC_NUM_BUF_RANGES];
+ /* Total size of RC model */
+ u16 rc_model_size;
+ /* Minimum QP where flatness information is sent */
+ u8 flatness_min_qp;
+ /* Maximum QP where flatness information is sent */
+ u8 flatness_max_qp;
+ /* Initial value for scale factor */
+ u8 initial_scale_value;
+ /* Decrement scale factor every scale_decrement_interval groups */
+ u16 scale_decrement_interval;
+ /* Increment scale factor every scale_increment_interval groups */
+ u16 scale_increment_interval;
+ /* Non-first line BPG offset to use */
+ u16 nfl_bpg_offset;
+ /* BPG offset used to enforce slice bit */
+ u16 slice_bpg_offset;
+ /* Final RC linear transformation offset value */
+ u16 final_offset;
+ /* Enable on-off VBR (ie., disable stuffing bits) */
+ bool vbr_enable;
+ /* Mux word size (in bits) for SSM mode */
+ u8 mux_word_size;
+ /*
+ * The (max) size in bytes of the "chunks" that are
+ * used in slice multiplexing
+ */
+ u16 slice_chunk_size;
+ /* Rate Control buffer siz in bits */
+ u16 rc_bits;
+ /* DSC Minor Version */
+ u8 dsc_version_minor;
+ /* DSC Major version */
+ u8 dsc_version_major;
+ /* Native 4:2:2 support */
+ bool native_422;
+ /* Native 4:2:0 support */
+ bool native_420;
+ /* Additional bits/grp for seconnd line of slice for native 4:2:0 */
+ u8 second_line_bpg_offset;
+ /* Num of bits deallocated for each grp that is not in second line of slice */
+ u16 nsl_bpg_offset;
+ /* Offset adj fr second line in Native 4:2:0 mode */
+ u16 second_line_offset_adj;
+};
+
+/**
+ * struct picture_parameter_set - Represents 128 bytes of Picture Parameter Set
+ *
+ * The VESA DSC standard defines picture parameter set (PPS) which display
+ * stream compression encoders must communicate to decoders.
+ * The PPS is encapsulated in 128 bytes (PPS 0 through PPS 127). The fields in
+ * this structure are as per Table 4.1 in Vesa DSC specification v1.1/v1.2.
+ * The PPS fields that span over more than a byte should be stored in Big Endian
+ * format.
+ */
+struct picture_parameter_set {
+ /**
+ * @dsc_version:
+ * PPS0[3:0] - dsc_version_minor: Contains Minor version of DSC
+ * PPS0[7:4] - dsc_version_major: Contains major version of DSC
+ */
+ u8 dsc_version;
+ /**
+ * @pps_identifier:
+ * PPS1[7:0] - Application specific identifier that can be
+ * used to differentiate between different PPS tables.
+ */
+ u8 pps_identifier;
+ /**
+ * @pps_reserved:
+ * PPS2[7:0]- RESERVED Byte
+ */
+ u8 pps_reserved;
+ /**
+ * @pps_3:
+ * PPS3[3:0] - linebuf_depth: Contains linebuffer bit depth used to
+ * generate the bitstream. (0x0 - 16 bits for DSC 1.2, 0x8 - 8 bits,
+ * 0xA - 10 bits, 0xB - 11 bits, 0xC - 12 bits, 0xD - 13 bits,
+ * 0xE - 14 bits for DSC1.2, 0xF - 14 bits for DSC 1.2.
+ * PPS3[7:4] - bits_per_component: Bits per component for the original
+ * pixels of the encoded picture.
+ * 0x0 = 16bpc (allowed only when dsc_version_minor = 0x2)
+ * 0x8 = 8bpc, 0xA = 10bpc, 0xC = 12bpc, 0xE = 14bpc (also
+ * allowed only when dsc_minor_version = 0x2)
+ */
+ u8 pps_3;
+ /**
+ * @pps_4:
+ * PPS4[1:0] -These are the most significant 2 bits of
+ * compressed BPP bits_per_pixel[9:0] syntax element.
+ * PPS4[2] - vbr_enable: 0 = VBR disabled, 1 = VBR enabled
+ * PPS4[3] - simple_422: Indicates if decoder drops samples to
+ * reconstruct the 4:2:2 picture.
+ * PPS4[4] - Convert_rgb: Indicates if DSC color space conversion is
+ * active.
+ * PPS4[5] - blobk_pred_enable: Indicates if BP is used to code any
+ * groups in picture
+ * PPS4[7:6] - Reseved bits
+ */
+ u8 pps_4;
+ /**
+ * @bits_per_pixel_low:
+ * PPS5[7:0] - This indicates the lower significant 8 bits of
+ * the compressed BPP bits_per_pixel[9:0] element.
+ */
+ u8 bits_per_pixel_low;
+ /**
+ * @pic_height:
+ * PPS6[7:0], PPS7[7:0] -pic_height: Specifies the number of pixel rows
+ * within the raster.
+ */
+ __be16 pic_height;
+ /**
+ * @pic_width:
+ * PPS8[7:0], PPS9[7:0] - pic_width: Number of pixel columns within
+ * the raster.
+ */
+ __be16 pic_width;
+ /**
+ * @slice_height:
+ * PPS10[7:0], PPS11[7:0] - Slice height in units of pixels.
+ */
+ __be16 slice_height;
+ /**
+ * @slice_width:
+ * PPS12[7:0], PPS13[7:0] - Slice width in terms of pixels.
+ */
+ __be16 slice_width;
+ /**
+ * @chunk_size:
+ * PPS14[7:0], PPS15[7:0] - Size in units of bytes of the chunks
+ * that are used for slice multiplexing.
+ */
+ __be16 chunk_size;
+ /**
+ * @initial_xmit_delay_high:
+ * PPS16[1:0] - Most Significant two bits of initial transmission delay.
+ * It specifies the number of pixel times that the encoder waits before
+ * transmitting data from its rate buffer.
+ * PPS16[7:2] - Reserved
+ */
+ u8 initial_xmit_delay_high;
+ /**
+ * @initial_xmit_delay_low:
+ * PPS17[7:0] - Least significant 8 bits of initial transmission delay.
+ */
+ u8 initial_xmit_delay_low;
+ /**
+ * @initial_dec_delay:
+ *
+ * PPS18[7:0], PPS19[7:0] - Initial decoding delay which is the number
+ * of pixel times that the decoder accumulates data in its rate buffer
+ * before starting to decode and output pixels.
+ */
+ __be16 initial_dec_delay;
+ /**
+ * @pps20_reserved:
+ *
+ * PPS20[7:0] - Reserved
+ */
+ u8 pps20_reserved;
+ /**
+ * @initial_scale_value:
+ * PPS21[5:0] - Initial rcXformScale factor used at beginning
+ * of a slice.
+ * PPS21[7:6] - Reserved
+ */
+ u8 initial_scale_value;
+ /**
+ * @scale_increment_interval:
+ * PPS22[7:0], PPS23[7:0] - Number of group times between incrementing
+ * the rcXformScale factor at end of a slice.
+ */
+ __be16 scale_increment_interval;
+ /**
+ * @scale_decrement_interval_high:
+ * PPS24[3:0] - Higher 4 bits indicating number of group times between
+ * decrementing the rcXformScale factor at beginning of a slice.
+ * PPS24[7:4] - Reserved
+ */
+ u8 scale_decrement_interval_high;
+ /**
+ * @scale_decrement_interval_low:
+ * PPS25[7:0] - Lower 8 bits of scale decrement interval
+ */
+ u8 scale_decrement_interval_low;
+ /**
+ * @pps26_reserved:
+ * PPS26[7:0]
+ */
+ u8 pps26_reserved;
+ /**
+ * @first_line_bpg_offset:
+ * PPS27[4:0] - Number of additional bits that are allocated
+ * for each group on first line of a slice.
+ * PPS27[7:5] - Reserved
+ */
+ u8 first_line_bpg_offset;
+ /**
+ * @nfl_bpg_offset:
+ * PPS28[7:0], PPS29[7:0] - Number of bits including frac bits
+ * deallocated for each group for groups after the first line of slice.
+ */
+ __be16 nfl_bpg_offset;
+ /**
+ * @slice_bpg_offset:
+ * PPS30, PPS31[7:0] - Number of bits that are deallocated for each
+ * group to enforce the slice constraint.
+ */
+ __be16 slice_bpg_offset;
+ /**
+ * @initial_offset:
+ * PPS32,33[7:0] - Initial value for rcXformOffset
+ */
+ __be16 initial_offset;
+ /**
+ * @final_offset:
+ * PPS34,35[7:0] - Maximum end-of-slice value for rcXformOffset
+ */
+ __be16 final_offset;
+ /**
+ * @flatness_min_qp:
+ * PPS36[4:0] - Minimum QP at which flatness is signaled and
+ * flatness QP adjustment is made.
+ * PPS36[7:5] - Reserved
+ */
+ u8 flatness_min_qp;
+ /**
+ * @flatness_max_qp:
+ * PPS37[4:0] - Max QP at which flatness is signalled and
+ * the flatness adjustment is made.
+ * PPS37[7:5] - Reserved
+ */
+ u8 flatness_max_qp;
+ /**
+ * @rc_model_size:
+ * PPS38,39[7:0] - Number of bits within RC Model.
+ */
+ __be16 rc_model_size;
+ /**
+ * @rc_edge_factor:
+ * PPS40[3:0] - Ratio of current activity vs, previous
+ * activity to determine presence of edge.
+ * PPS40[7:4] - Reserved
+ */
+ u8 rc_edge_factor;
+ /**
+ * @rc_quant_incr_limit0:
+ * PPS41[4:0] - QP threshold used in short term RC
+ * PPS41[7:5] - Reserved
+ */
+ u8 rc_quant_incr_limit0;
+ /**
+ * @rc_quant_incr_limit1:
+ * PPS42[4:0] - QP threshold used in short term RC
+ * PPS42[7:5] - Reserved
+ */
+ u8 rc_quant_incr_limit1;
+ /**
+ * @rc_tgt_offset:
+ * PPS43[3:0] - Lower end of the variability range around the target
+ * bits per group that is allowed by short term RC.
+ * PPS43[7:4]- Upper end of the variability range around the target
+ * bits per group that i allowed by short term rc.
+ */
+ u8 rc_tgt_offset;
+ /**
+ * @rc_buf_thresh:
+ * PPS44[7:0] - PPS57[7:0] - Specifies the thresholds in RC model for
+ * the 15 ranges defined by 14 thresholds.
+ */
+ u8 rc_buf_thresh[DSC_NUM_BUF_RANGES - 1];
+ /**
+ * @rc_range_parameters:
+ * PPS58[7:0] - PPS87[7:0]
+ * Parameters that correspond to each of the 15 ranges.
+ */
+ __be16 rc_range_parameters[DSC_NUM_BUF_RANGES];
+ /**
+ * @native_422_420:
+ * PPS88[0] - 0 = Native 4:2:2 not used
+ * 1 = Native 4:2:2 used
+ * PPS88[1] - 0 = Native 4:2:0 not use
+ * 1 = Native 4:2:0 used
+ * PPS88[7:2] - Reserved 6 bits
+ */
+ u8 native_422_420;
+ /**
+ * @second_line_bpg_offset:
+ * PPS89[4:0] - Additional bits/group budget for the
+ * second line of a slice in Native 4:2:0 mode.
+ * Set to 0 if DSC minor version is 1 or native420 is 0.
+ * PPS89[7:5] - Reserved
+ */
+ u8 second_line_bpg_offset;
+ /**
+ * @nsl_bpg_offset:
+ * PPS90[7:0], PPS91[7:0] - Number of bits that are deallocated
+ * for each group that is not in the second line of a slice.
+ */
+ __be16 nsl_bpg_offset;
+ /**
+ * @second_line_offset_adj:
+ * PPS92[7:0], PPS93[7:0] - Used as offset adjustment for the second
+ * line in Native 4:2:0 mode.
+ */
+ __be16 second_line_offset_adj;
+ /**
+ * @pps_long_94_reserved:
+ * PPS 94, 95, 96, 97 - Reserved
+ */
+ u32 pps_long_94_reserved;
+ /**
+ * @pps_long_98_reserved:
+ * PPS 98, 99, 100, 101 - Reserved
+ */
+ u32 pps_long_98_reserved;
+ /**
+ * @pps_long_102_reserved:
+ * PPS 102, 103, 104, 105 - Reserved
+ */
+ u32 pps_long_102_reserved;
+ /**
+ * @pps_long_106_reserved:
+ * PPS 106, 107, 108, 109 - reserved
+ */
+ u32 pps_long_106_reserved;
+ /**
+ * @pps_long_110_reserved:
+ * PPS 110, 111, 112, 113 - reserved
+ */
+ u32 pps_long_110_reserved;
+ /**
+ * @pps_long_114_reserved:
+ * PPS 114 - 117 - reserved
+ */
+ u32 pps_long_114_reserved;
+ /**
+ * @pps_long_118_reserved:
+ * PPS 118 - 121 - reserved
+ */
+ u32 pps_long_118_reserved;
+ /**
+ * @pps_long_122_reserved:
+ * PPS 122- 125 - reserved
+ */
+ u32 pps_long_122_reserved;
+ /**
+ * @pps_short_126_reserved:
+ * PPS 126, 127 - reserved
+ */
+ __be16 pps_short_126_reserved;
+};
+
+/**
+ * struct dsc_pps_infoframe - DSC infoframe carrying the Picture Parameter
+ * Set Metadata
+ *
+ * This structure represents the DSC PPS infoframe required to send the Picture
+ * Parameter Set metadata required before enabling VESA Display Stream
+ * Compression. This is based on the DP Secondary Data Packet structure and
+ * comprises of SDP Header as defined in drm_dp_helper.h and PPS payload.
+ *
+ * @pps_header:
+ *
+ * Header for PPS as per DP SDP header format
+ *
+ * @pps_payload:
+ *
+ * PPS payload fields as per DSC specification Table 4-1
+ */
+struct dsc_pps_infoframe {
+ struct dp_sdp_header pps_header;
+ struct picture_parameter_set pps_payload;
+} __packed;
+/** XXX DK: End of borrowed stuff. */
+
+#define DP_DSC_PPS_SIZE 128
+
#define ADDR_IMEM 0x10000
#define ADDR_DMEM 0x20000

@@ -77,6 +575,7 @@
/* source pif addr */
#define SOURCE_PIF_WR_ADDR 0x30800
#define SOURCE_PIF_WR_REQ 0x30804
+#define SOURCE_PIF_WR_REQ_HOST_WR BIT(0)
#define SOURCE_PIF_RD_ADDR 0x30808
#define SOURCE_PIF_RD_REQ 0x3080c
#define SOURCE_PIF_DATA_WR 0x30810
@@ -87,8 +586,20 @@
#define SOURCE_PIF_INTERRUPT_SOURCE 0x30824
#define SOURCE_PIF_INTERRUPT_MASK 0x30828
#define SOURCE_PIF_PKT_ALLOC_REG 0x3082c
+#define SOURCE_PIF_PKT_ALLOC_REG_ACTIVE_IDLE_TYPE BIT(17)
+#define SOURCE_PIF_PKT_ALLOC_REG_TYPE_VALID BIT(16)
+#define SOURCE_PIF_PKT_ALLOC_REG_PACKET_TYPE GENMASK(15, 8)
+#define SOURCE_PIF_PKT_ALLOC_REG_PACKET_TYPE_SHIFT 8
+#define SOURCE_PIF_PKT_ALLOC_REG_PKT_ALLOC_ADDR GENMASK(3, 0)
+
#define SOURCE_PIF_PKT_ALLOC_WR_EN 0x30830
+#define SOURCE_PIF_PKT_ALLOC_WR_EN_EN BIT(0)
+
#define SOURCE_PIF_SW_RESET 0x30834
+#define SOURCE_PIF_PPS_HEADER 0x30838
+#define SOURCE_PIF_PPS 0x3083c
+#define SOURCE_PIF_PPS_PPS BIT(0)
+

/* bellow registers need access by mailbox */
/* source car addr */
@@ -552,6 +1063,7 @@ struct cdns_mhdp_device {
struct cdns_mhdp_host host;
struct cdns_mhdp_sink sink;
struct cdns_mhdp_bridge bridge;
+ struct dsc_config dsc_config;
struct phy *phy;
void __iomem *dbg_regs;

@@ -569,6 +1081,14 @@ struct cdns_mhdp_device {
bool plugged;

bool fec_enabled;
+
+ /* Display Stream compression state */
+ struct {
+ bool compression_enable;
+ bool dsc_split;
+ u16 compressed_bpp;
+ u8 slice_count;
+ } dsc_params;
};

void cdns_mhdp_clock_reset(struct cdns_mhdp_device *mhdp);
--
2.17.1