* [PATCH v4 01/13] drm/msm/dsi: add support for dsc data
2022-02-10 6:37 [PATCH v4 00/13] drm/msm: Add Display Stream Compression Support Vinod Koul
@ 2022-02-10 6:37 ` Vinod Koul
2022-02-10 6:37 ` [PATCH v4 02/13] drm/msm/dsi: Pass DSC params to drm_panel Vinod Koul
2022-02-10 6:37 ` [PATCH v4 03/13] drm/msm/disp/dpu1: Add support for DSC Vinod Koul
2 siblings, 0 replies; 4+ messages in thread
From: Vinod Koul @ 2022-02-10 6:37 UTC (permalink / raw)
To: Rob Clark
Cc: linux-arm-msm, Bjorn Andersson, Vinod Koul, David Airlie,
Daniel Vetter, Jonathan Marek, Dmitry Baryshkov, Abhinav Kumar,
linux-kernel, dri-devel, freedreno
Display Stream Compression (DSC) parameters need to be calculated. Add
helpers and struct msm_display_dsc_config in msm_drv for this
msm_display_dsc_config uses drm_dsc_config for DSC parameters.
Signed-off-by: Vinod Koul <vkoul@kernel.org>
---
drivers/gpu/drm/msm/dsi/dsi_host.c | 132 +++++++++++++++++++++++++++++
drivers/gpu/drm/msm/msm_drv.h | 15 ++++
2 files changed, 147 insertions(+)
diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c
index 6b3ced4aaaf5..27553194f9fa 100644
--- a/drivers/gpu/drm/msm/dsi/dsi_host.c
+++ b/drivers/gpu/drm/msm/dsi/dsi_host.c
@@ -31,6 +31,8 @@
#define DSI_RESET_TOGGLE_DELAY_MS 20
+static int dsi_populate_dsc_params(struct msm_display_dsc_config *dsc);
+
static int dsi_get_version(const void __iomem *base, u32 *major, u32 *minor)
{
u32 ver;
@@ -157,6 +159,7 @@ struct msm_dsi_host {
struct regmap *sfpb;
struct drm_display_mode *mode;
+ struct msm_display_dsc_config *dsc;
/* connected device info */
struct device_node *device_node;
@@ -1718,6 +1721,135 @@ static int dsi_host_parse_lane_data(struct msm_dsi_host *msm_host,
return -EINVAL;
}
+static u32 dsi_dsc_rc_buf_thresh[DSC_NUM_BUF_RANGES - 1] = {
+ 0x0e, 0x1c, 0x2a, 0x38, 0x46, 0x54, 0x62,
+ 0x69, 0x70, 0x77, 0x79, 0x7b, 0x7d, 0x7e
+};
+
+/* only 8bpc, 8bpp added */
+static char min_qp[DSC_NUM_BUF_RANGES] = {
+ 0, 0, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 7, 13
+};
+
+static char max_qp[DSC_NUM_BUF_RANGES] = {
+ 4, 4, 5, 6, 7, 7, 7, 8, 9, 10, 11, 12, 13, 13, 15
+};
+
+static char bpg_offset[DSC_NUM_BUF_RANGES] = {
+ 2, 0, 0, -2, -4, -6, -8, -8, -8, -10, -10, -12, -12, -12, -12
+};
+
+static int dsi_populate_dsc_params(struct msm_display_dsc_config *dsc)
+{
+ int mux_words_size;
+ int groups_per_line, groups_total;
+ int min_rate_buffer_size;
+ int hrd_delay;
+ int pre_num_extra_mux_bits, num_extra_mux_bits;
+ int slice_bits;
+ int target_bpp_x16;
+ int data;
+ int final_value, final_scale;
+ int i;
+
+ dsc->drm->rc_model_size = 8192;
+ dsc->drm->first_line_bpg_offset = 12;
+ dsc->drm->rc_edge_factor = 6;
+ dsc->drm->rc_tgt_offset_high = 3;
+ dsc->drm->rc_tgt_offset_low = 3;
+ dsc->drm->simple_422 = 0;
+ dsc->drm->convert_rgb = 1;
+ dsc->drm->vbr_enable = 0;
+
+ /* handle only bpp = bpc = 8 */
+ for (i = 0; i < DSC_NUM_BUF_RANGES - 1 ; i++)
+ dsc->drm->rc_buf_thresh[i] = dsi_dsc_rc_buf_thresh[i];
+
+ for (i = 0; i < DSC_NUM_BUF_RANGES; i++) {
+ dsc->drm->rc_range_params[i].range_min_qp = min_qp[i];
+ dsc->drm->rc_range_params[i].range_max_qp = max_qp[i];
+ dsc->drm->rc_range_params[i].range_bpg_offset = bpg_offset[i];
+ }
+
+ dsc->drm->initial_offset = 6144; /* Not bpp 12 */
+ if (dsc->drm->bits_per_pixel != 8)
+ dsc->drm->initial_offset = 2048; /* bpp = 12 */
+
+ mux_words_size = 48; /* bpc == 8/10 */
+ if (dsc->drm->bits_per_component == 12)
+ mux_words_size = 64;
+
+ dsc->drm->initial_xmit_delay = 512;
+ dsc->drm->initial_scale_value = 32;
+ dsc->drm->first_line_bpg_offset = 12;
+ dsc->drm->line_buf_depth = dsc->drm->bits_per_component + 1;
+
+ /* bpc 8 */
+ dsc->drm->flatness_min_qp = 3;
+ dsc->drm->flatness_max_qp = 12;
+ dsc->det_thresh_flatness = 7 + 2 * (dsc->drm->bits_per_component - 8);
+ dsc->drm->rc_quant_incr_limit0 = 11;
+ dsc->drm->rc_quant_incr_limit1 = 11;
+ dsc->drm->mux_word_size = DSC_MUX_WORD_SIZE_8_10_BPC;
+
+ /* FIXME: need to call drm_dsc_compute_rc_parameters() so that rest of
+ * params are calculated
+ */
+ dsc->slice_last_group_size = 3 - (dsc->drm->slice_width % 3);
+ groups_per_line = DIV_ROUND_UP(dsc->drm->slice_width, 3);
+ dsc->drm->slice_chunk_size = dsc->drm->slice_width * dsc->drm->bits_per_pixel / 8;
+ if ((dsc->drm->slice_width * dsc->drm->bits_per_pixel) % 8)
+ dsc->drm->slice_chunk_size++;
+
+ /* rbs-min */
+ min_rate_buffer_size = dsc->drm->rc_model_size - dsc->drm->initial_offset +
+ dsc->drm->initial_xmit_delay * dsc->drm->bits_per_pixel +
+ groups_per_line * dsc->drm->first_line_bpg_offset;
+
+ hrd_delay = DIV_ROUND_UP(min_rate_buffer_size, dsc->drm->bits_per_pixel);
+
+ dsc->drm->initial_dec_delay = hrd_delay - dsc->drm->initial_xmit_delay;
+
+ dsc->drm->initial_scale_value = 8 * dsc->drm->rc_model_size /
+ (dsc->drm->rc_model_size - dsc->drm->initial_offset);
+
+ slice_bits = 8 * dsc->drm->slice_chunk_size * dsc->drm->slice_height;
+
+ groups_total = groups_per_line * dsc->drm->slice_height;
+
+ data = dsc->drm->first_line_bpg_offset * 2048;
+
+ dsc->drm->nfl_bpg_offset = DIV_ROUND_UP(data, (dsc->drm->slice_height - 1));
+
+ pre_num_extra_mux_bits = 3 * (mux_words_size + (4 * dsc->drm->bits_per_component + 4) - 2);
+
+ num_extra_mux_bits = pre_num_extra_mux_bits - (mux_words_size -
+ ((slice_bits - pre_num_extra_mux_bits) % mux_words_size));
+
+ data = 2048 * (dsc->drm->rc_model_size - dsc->drm->initial_offset + num_extra_mux_bits);
+ dsc->drm->slice_bpg_offset = DIV_ROUND_UP(data, groups_total);
+
+ /* bpp * 16 + 0.5 */
+ data = dsc->drm->bits_per_pixel * 16;
+ data *= 2;
+ data++;
+ data /= 2;
+ target_bpp_x16 = data;
+
+ data = (dsc->drm->initial_xmit_delay * target_bpp_x16) / 16;
+ final_value = dsc->drm->rc_model_size - data + num_extra_mux_bits;
+ dsc->drm->final_offset = final_value;
+
+ final_scale = 8 * dsc->drm->rc_model_size / (dsc->drm->rc_model_size - final_value);
+
+ data = (final_scale - 9) * (dsc->drm->nfl_bpg_offset + dsc->drm->slice_bpg_offset);
+ dsc->drm->scale_increment_interval = (2048 * dsc->drm->final_offset) / data;
+
+ dsc->drm->scale_decrement_interval = groups_per_line / (dsc->drm->initial_scale_value - 8);
+
+ return 0;
+}
+
static int dsi_host_parse_dt(struct msm_dsi_host *msm_host)
{
struct device *dev = &msm_host->pdev->dev;
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index d7574e6bd4e4..384f9bad4760 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -30,6 +30,7 @@
#include <drm/drm_plane_helper.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_fb_helper.h>
+#include <drm/drm_dsc.h>
#include <drm/msm_drm.h>
#include <drm/drm_gem.h>
@@ -134,6 +135,20 @@ struct msm_drm_thread {
struct kthread_worker *worker;
};
+/* DSC config */
+struct msm_display_dsc_config {
+ struct drm_dsc_config *drm;
+
+ u32 initial_lines;
+ u32 pkt_per_line;
+ u32 bytes_in_slice;
+ u32 bytes_per_pkt;
+ u32 eol_byte_num;
+ u32 pclk_per_line;
+ u32 slice_last_group_size;
+ u32 det_thresh_flatness;
+};
+
struct msm_drm_private {
struct drm_device *dev;
--
2.31.1
^ permalink raw reply [flat|nested] 4+ messages in thread* [PATCH v4 02/13] drm/msm/dsi: Pass DSC params to drm_panel
2022-02-10 6:37 [PATCH v4 00/13] drm/msm: Add Display Stream Compression Support Vinod Koul
2022-02-10 6:37 ` [PATCH v4 01/13] drm/msm/dsi: add support for dsc data Vinod Koul
@ 2022-02-10 6:37 ` Vinod Koul
2022-02-10 6:37 ` [PATCH v4 03/13] drm/msm/disp/dpu1: Add support for DSC Vinod Koul
2 siblings, 0 replies; 4+ messages in thread
From: Vinod Koul @ 2022-02-10 6:37 UTC (permalink / raw)
To: Rob Clark
Cc: linux-arm-msm, Bjorn Andersson, Vinod Koul, David Airlie,
Daniel Vetter, Jonathan Marek, Dmitry Baryshkov, Abhinav Kumar,
linux-kernel, dri-devel, freedreno
When DSC is enabled, we need to pass the DSC parameters to panel driver
as well, so add a dsc parameter in panel and set it when DSC is enabled
Also, fetch and pass DSC configuration for DSI panels to DPU encoder,
which will enable and configure DSC hardware blocks accordingly.
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Signed-off-by: Vinod Koul <vkoul@kernel.org>
---
drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 2 ++
drivers/gpu/drm/msm/dsi/dsi.c | 5 +++++
drivers/gpu/drm/msm/dsi/dsi.h | 1 +
drivers/gpu/drm/msm/dsi/dsi_host.c | 22 ++++++++++++++++++++++
drivers/gpu/drm/msm/msm_drv.h | 8 ++++++++
include/drm/drm_panel.h | 7 +++++++
6 files changed, 45 insertions(+)
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
index 47fe11a84a77..ef6ddac22767 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
@@ -578,6 +578,8 @@ static int _dpu_kms_initialize_dsi(struct drm_device *dev,
MSM_DISPLAY_CAP_CMD_MODE :
MSM_DISPLAY_CAP_VID_MODE;
+ info.dsc = msm_dsi_get_dsc_config(priv->dsi[i]);
+
if (msm_dsi_is_bonded_dsi(priv->dsi[i]) && priv->dsi[other]) {
rc = msm_dsi_modeset_init(priv->dsi[other], dev, encoder);
if (rc) {
diff --git a/drivers/gpu/drm/msm/dsi/dsi.c b/drivers/gpu/drm/msm/dsi/dsi.c
index 052548883d27..3aeac15e7421 100644
--- a/drivers/gpu/drm/msm/dsi/dsi.c
+++ b/drivers/gpu/drm/msm/dsi/dsi.c
@@ -20,6 +20,11 @@ bool msm_dsi_is_cmd_mode(struct msm_dsi *msm_dsi)
return !(host_flags & MIPI_DSI_MODE_VIDEO);
}
+struct msm_display_dsc_config *msm_dsi_get_dsc_config(struct msm_dsi *msm_dsi)
+{
+ return msm_dsi_host_get_dsc_config(msm_dsi->host);
+}
+
static int dsi_get_phy(struct msm_dsi *msm_dsi)
{
struct platform_device *pdev = msm_dsi->pdev;
diff --git a/drivers/gpu/drm/msm/dsi/dsi.h b/drivers/gpu/drm/msm/dsi/dsi.h
index c8dedc95428c..16cd9b2fce86 100644
--- a/drivers/gpu/drm/msm/dsi/dsi.h
+++ b/drivers/gpu/drm/msm/dsi/dsi.h
@@ -152,6 +152,7 @@ int dsi_calc_clk_rate_v2(struct msm_dsi_host *msm_host, bool is_bonded_dsi);
int dsi_calc_clk_rate_6g(struct msm_dsi_host *msm_host, bool is_bonded_dsi);
void msm_dsi_host_snapshot(struct msm_disp_state *disp_state, struct mipi_dsi_host *host);
void msm_dsi_host_test_pattern_en(struct mipi_dsi_host *host);
+struct msm_display_dsc_config *msm_dsi_host_get_dsc_config(struct mipi_dsi_host *host);
/* dsi phy */
struct msm_dsi_phy;
diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c
index 27553194f9fa..7e9913eff724 100644
--- a/drivers/gpu/drm/msm/dsi/dsi_host.c
+++ b/drivers/gpu/drm/msm/dsi/dsi_host.c
@@ -2059,9 +2059,24 @@ int msm_dsi_host_modeset_init(struct mipi_dsi_host *host,
{
struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd;
+ struct drm_panel *panel;
int ret;
msm_host->dev = dev;
+ panel = msm_dsi_host_get_panel(&msm_host->base);
+
+ if (panel && panel->dsc) {
+ struct msm_display_dsc_config *dsc = msm_host->dsc;
+
+ if (!dsc) {
+ dsc = devm_kzalloc(&msm_host->pdev->dev, sizeof(*dsc), GFP_KERNEL);
+ if (!dsc)
+ return -ENOMEM;
+ dsc->drm = panel->dsc;
+ msm_host->dsc = dsc;
+ }
+ }
+
ret = cfg_hnd->ops->tx_buf_alloc(msm_host, SZ_4K);
if (ret) {
pr_err("%s: alloc tx gem obj failed, %d\n", __func__, ret);
@@ -2626,3 +2641,10 @@ void msm_dsi_host_test_pattern_en(struct mipi_dsi_host *host)
dsi_write(msm_host, REG_DSI_TEST_PATTERN_GEN_CMD_STREAM0_TRIGGER,
DSI_TEST_PATTERN_GEN_CMD_STREAM0_TRIGGER_SW_TRIGGER);
}
+
+struct msm_display_dsc_config *msm_dsi_host_get_dsc_config(struct mipi_dsi_host *host)
+{
+ struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
+
+ return msm_host->dsc;
+}
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index 384f9bad4760..e7a312edfe67 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -119,6 +119,7 @@ struct msm_display_topology {
* based on num_of_h_tiles
* @is_te_using_watchdog_timer: Boolean to indicate watchdog TE is
* used instead of panel TE in cmd mode panels
+ * @dsc: DSC configuration data for DSC-enabled displays
*/
struct msm_display_info {
int intf_type;
@@ -126,6 +127,7 @@ struct msm_display_info {
uint32_t num_of_h_tiles;
uint32_t h_tile_instance[MAX_H_TILES_PER_DISPLAY];
bool is_te_using_watchdog_timer;
+ struct msm_display_dsc_config *dsc;
};
/* Commit/Event thread specific structure */
@@ -365,6 +367,7 @@ void msm_dsi_snapshot(struct msm_disp_state *disp_state, struct msm_dsi *msm_dsi
bool msm_dsi_is_cmd_mode(struct msm_dsi *msm_dsi);
bool msm_dsi_is_bonded_dsi(struct msm_dsi *msm_dsi);
bool msm_dsi_is_master_dsi(struct msm_dsi *msm_dsi);
+struct msm_display_dsc_config *msm_dsi_get_dsc_config(struct msm_dsi *msm_dsi);
#else
static inline void __init msm_dsi_register(void)
{
@@ -393,6 +396,11 @@ static inline bool msm_dsi_is_master_dsi(struct msm_dsi *msm_dsi)
{
return false;
}
+
+static inline struct msm_display_dsc_config *msm_dsi_get_dsc_config(struct msm_dsi *msm_dsi)
+{
+ return NULL;
+}
#endif
#ifdef CONFIG_DRM_MSM_DP
diff --git a/include/drm/drm_panel.h b/include/drm/drm_panel.h
index 4602f833eb51..eb8ae9bf32ed 100644
--- a/include/drm/drm_panel.h
+++ b/include/drm/drm_panel.h
@@ -171,6 +171,13 @@ struct drm_panel {
* Panel entry in registry.
*/
struct list_head list;
+
+ /**
+ * @dsc:
+ *
+ * Panel DSC pps payload to be sent
+ */
+ struct drm_dsc_config *dsc;
};
void drm_panel_init(struct drm_panel *panel, struct device *dev,
--
2.31.1
^ permalink raw reply [flat|nested] 4+ messages in thread* [PATCH v4 03/13] drm/msm/disp/dpu1: Add support for DSC
2022-02-10 6:37 [PATCH v4 00/13] drm/msm: Add Display Stream Compression Support Vinod Koul
2022-02-10 6:37 ` [PATCH v4 01/13] drm/msm/dsi: add support for dsc data Vinod Koul
2022-02-10 6:37 ` [PATCH v4 02/13] drm/msm/dsi: Pass DSC params to drm_panel Vinod Koul
@ 2022-02-10 6:37 ` Vinod Koul
2 siblings, 0 replies; 4+ messages in thread
From: Vinod Koul @ 2022-02-10 6:37 UTC (permalink / raw)
To: Rob Clark
Cc: linux-arm-msm, Bjorn Andersson, Vinod Koul, David Airlie,
Daniel Vetter, Jonathan Marek, Dmitry Baryshkov, Abhinav Kumar,
linux-kernel, dri-devel, freedreno
Display Stream Compression (DSC) is one of the hw blocks in dpu, so add
support by adding hw blocks for DSC
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Signed-off-by: Vinod Koul <vkoul@kernel.org>
---
drivers/gpu/drm/msm/Makefile | 1 +
.../gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h | 13 ++
drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c | 210 ++++++++++++++++++
drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h | 77 +++++++
drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h | 13 ++
5 files changed, 314 insertions(+)
create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c
create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h
diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index 03ab55c37beb..7ec3c70c77ce 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -56,6 +56,7 @@ msm-y := \
disp/dpu1/dpu_formats.o \
disp/dpu1/dpu_hw_catalog.o \
disp/dpu1/dpu_hw_ctl.o \
+ disp/dpu1/dpu_hw_dsc.o \
disp/dpu1/dpu_hw_interrupts.o \
disp/dpu1/dpu_hw_intf.o \
disp/dpu1/dpu_hw_lm.o \
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
index 31af04afda7d..5fc0888351c7 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
@@ -556,6 +556,16 @@ struct dpu_merge_3d_cfg {
const struct dpu_merge_3d_sub_blks *sblk;
};
+/**
+ * struct dpu_dsc_cfg - information of DSC blocks
+ * @id enum identifying this block
+ * @base register offset of this block
+ * @features bit mask identifying sub-blocks/features
+ */
+struct dpu_dsc_cfg {
+ DPU_HW_BLK_INFO;
+};
+
/**
* struct dpu_intf_cfg - information of timing engine blocks
* @id enum identifying this block
@@ -752,6 +762,9 @@ struct dpu_mdss_cfg {
u32 merge_3d_count;
const struct dpu_merge_3d_cfg *merge_3d;
+ u32 dsc_count;
+ struct dpu_dsc_cfg *dsc;
+
u32 intf_count;
const struct dpu_intf_cfg *intf;
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c
new file mode 100644
index 000000000000..449d6f1dad28
--- /dev/null
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c
@@ -0,0 +1,210 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2020-2021, Linaro Limited
+ */
+
+#include "dpu_kms.h"
+#include "dpu_hw_catalog.h"
+#include "dpu_hwio.h"
+#include "dpu_hw_mdss.h"
+#include "dpu_hw_dsc.h"
+
+#define DSC_COMMON_MODE 0x000
+#define DSC_ENC 0X004
+#define DSC_PICTURE 0x008
+#define DSC_SLICE 0x00C
+#define DSC_CHUNK_SIZE 0x010
+#define DSC_DELAY 0x014
+#define DSC_SCALE_INITIAL 0x018
+#define DSC_SCALE_DEC_INTERVAL 0x01C
+#define DSC_SCALE_INC_INTERVAL 0x020
+#define DSC_FIRST_LINE_BPG_OFFSET 0x024
+#define DSC_BPG_OFFSET 0x028
+#define DSC_DSC_OFFSET 0x02C
+#define DSC_FLATNESS 0x030
+#define DSC_RC_MODEL_SIZE 0x034
+#define DSC_RC 0x038
+#define DSC_RC_BUF_THRESH 0x03C
+#define DSC_RANGE_MIN_QP 0x074
+#define DSC_RANGE_MAX_QP 0x0B0
+#define DSC_RANGE_BPG_OFFSET 0x0EC
+
+static void dpu_hw_dsc_disable(struct dpu_hw_dsc *dsc)
+{
+ struct dpu_hw_blk_reg_map *c = &dsc->hw;
+
+ DPU_REG_WRITE(c, DSC_COMMON_MODE, 0);
+}
+
+static void dpu_hw_dsc_config(struct dpu_hw_dsc *hw_dsc,
+ struct msm_display_dsc_config *dsc, u32 mode)
+{
+ struct dpu_hw_blk_reg_map *c = &hw_dsc->hw;
+ u32 data, lsb, bpp;
+ u32 initial_lines = dsc->initial_lines;
+ bool is_cmd_mode = !(mode & DSC_MODE_VIDEO);
+
+ DPU_REG_WRITE(c, DSC_COMMON_MODE, mode);
+
+ if (is_cmd_mode)
+ initial_lines += 1;
+
+ data = (initial_lines << 20);
+ data |= ((dsc->slice_last_group_size - 1) << 18);
+ /* bpp is 6.4 format, 4 LSBs bits are for fractional part */
+ data |= dsc->drm->bits_per_pixel << 12;
+ lsb = dsc->drm->bits_per_pixel % 4;
+ bpp = dsc->drm->bits_per_pixel / 4;
+ bpp *= 4;
+ bpp <<= 4;
+ bpp |= lsb;
+
+ data |= bpp << 8;
+ data |= (dsc->drm->block_pred_enable << 7);
+ data |= (dsc->drm->line_buf_depth << 3);
+ data |= (dsc->drm->simple_422 << 2);
+ data |= (dsc->drm->convert_rgb << 1);
+ data |= dsc->drm->bits_per_component;
+
+ DPU_REG_WRITE(c, DSC_ENC, data);
+
+ data = dsc->drm->pic_width << 16;
+ data |= dsc->drm->pic_height;
+ DPU_REG_WRITE(c, DSC_PICTURE, data);
+
+ data = dsc->drm->slice_width << 16;
+ data |= dsc->drm->slice_height;
+ DPU_REG_WRITE(c, DSC_SLICE, data);
+
+ data = dsc->drm->slice_chunk_size << 16;
+ DPU_REG_WRITE(c, DSC_CHUNK_SIZE, data);
+
+ data = dsc->drm->initial_dec_delay << 16;
+ data |= dsc->drm->initial_xmit_delay;
+ DPU_REG_WRITE(c, DSC_DELAY, data);
+
+ data = dsc->drm->initial_scale_value;
+ DPU_REG_WRITE(c, DSC_SCALE_INITIAL, data);
+
+ data = dsc->drm->scale_decrement_interval;
+ DPU_REG_WRITE(c, DSC_SCALE_DEC_INTERVAL, data);
+
+ data = dsc->drm->scale_increment_interval;
+ DPU_REG_WRITE(c, DSC_SCALE_INC_INTERVAL, data);
+
+ data = dsc->drm->first_line_bpg_offset;
+ DPU_REG_WRITE(c, DSC_FIRST_LINE_BPG_OFFSET, data);
+
+ data = dsc->drm->nfl_bpg_offset << 16;
+ data |= dsc->drm->slice_bpg_offset;
+ DPU_REG_WRITE(c, DSC_BPG_OFFSET, data);
+
+ data = dsc->drm->initial_offset << 16;
+ data |= dsc->drm->final_offset;
+ DPU_REG_WRITE(c, DSC_DSC_OFFSET, data);
+
+ data = dsc->det_thresh_flatness << 10;
+ data |= dsc->drm->flatness_max_qp << 5;
+ data |= dsc->drm->flatness_min_qp;
+ DPU_REG_WRITE(c, DSC_FLATNESS, data);
+
+ data = dsc->drm->rc_model_size;
+ DPU_REG_WRITE(c, DSC_RC_MODEL_SIZE, data);
+
+ data = dsc->drm->rc_tgt_offset_low << 18;
+ data |= dsc->drm->rc_tgt_offset_high << 14;
+ data |= dsc->drm->rc_quant_incr_limit1 << 9;
+ data |= dsc->drm->rc_quant_incr_limit0 << 4;
+ data |= dsc->drm->rc_edge_factor;
+ DPU_REG_WRITE(c, DSC_RC, data);
+}
+
+static void dpu_hw_dsc_config_thresh(struct dpu_hw_dsc *hw_dsc,
+ struct msm_display_dsc_config *dsc)
+{
+ struct drm_dsc_rc_range_parameters *rc = dsc->drm->rc_range_params;
+ struct dpu_hw_blk_reg_map *c = &hw_dsc->hw;
+ u32 off;
+ int i;
+
+ off = DSC_RC_BUF_THRESH;
+ for (i = 0; i < DSC_NUM_BUF_RANGES - 1 ; i++) {
+ DPU_REG_WRITE(c, off, dsc->drm->rc_buf_thresh[i]);
+ off += 4;
+ }
+
+ off = DSC_RANGE_MIN_QP;
+ for (i = 0; i < DSC_NUM_BUF_RANGES; i++) {
+ DPU_REG_WRITE(c, off, rc[i].range_min_qp);
+ off += 4;
+ }
+
+ off = DSC_RANGE_MAX_QP;
+ for (i = 0; i < 15; i++) {
+ DPU_REG_WRITE(c, off, rc[i].range_max_qp);
+ off += 4;
+ }
+
+ off = DSC_RANGE_BPG_OFFSET;
+ for (i = 0; i < 15; i++) {
+ DPU_REG_WRITE(c, off, rc[i].range_bpg_offset);
+ off += 4;
+ }
+}
+
+static struct dpu_dsc_cfg *_dsc_offset(enum dpu_dsc dsc,
+ struct dpu_mdss_cfg *m,
+ void __iomem *addr,
+ struct dpu_hw_blk_reg_map *b)
+{
+ int i;
+
+ for (i = 0; i < m->dsc_count; i++) {
+ if (dsc == m->dsc[i].id) {
+ b->base_off = addr;
+ b->blk_off = m->dsc[i].base;
+ b->length = m->dsc[i].len;
+ b->hwversion = m->hwversion;
+ b->log_mask = DPU_DBG_MASK_DSC;
+ return &m->dsc[i];
+ }
+ }
+
+ return NULL;
+}
+
+static void _setup_dsc_ops(struct dpu_hw_dsc_ops *ops,
+ unsigned long cap)
+{
+ ops->dsc_disable = dpu_hw_dsc_disable;
+ ops->dsc_config = dpu_hw_dsc_config;
+ ops->dsc_config_thresh = dpu_hw_dsc_config_thresh;
+};
+
+struct dpu_hw_dsc *dpu_hw_dsc_init(enum dpu_dsc idx, void __iomem *addr,
+ struct dpu_mdss_cfg *m)
+{
+ struct dpu_hw_dsc *c;
+ struct dpu_dsc_cfg *cfg;
+
+ c = kzalloc(sizeof(*c), GFP_KERNEL);
+ if (!c)
+ return ERR_PTR(-ENOMEM);
+
+ cfg = _dsc_offset(idx, m, addr, &c->hw);
+ if (IS_ERR_OR_NULL(cfg)) {
+ kfree(c);
+ return ERR_PTR(-EINVAL);
+ }
+
+ c->idx = idx;
+ c->caps = cfg;
+ _setup_dsc_ops(&c->ops, c->caps->features);
+
+ return c;
+}
+
+void dpu_hw_dsc_destroy(struct dpu_hw_dsc *dsc)
+{
+ kfree(dsc);
+}
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h
new file mode 100644
index 000000000000..648c9e4d8749
--- /dev/null
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h
@@ -0,0 +1,77 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (c) 2020-2021, Linaro Limited */
+
+#ifndef _DPU_HW_DSC_H
+#define _DPU_HW_DSC_H
+
+#include <drm/drm_dsc.h>
+
+#define DSC_MODE_SPLIT_PANEL BIT(0)
+#define DSC_MODE_MULTIPLEX BIT(1)
+#define DSC_MODE_VIDEO BIT(2)
+
+struct dpu_hw_dsc;
+
+/**
+ * struct dpu_hw_dsc_ops - interface to the dsc hardware driver functions
+ * Assumption is these functions will be called after clocks are enabled
+ */
+struct dpu_hw_dsc_ops {
+ /**
+ * dsc_disable - disable dsc
+ * @hw_dsc: Pointer to dsc context
+ */
+ void (*dsc_disable)(struct dpu_hw_dsc *hw_dsc);
+
+ /**
+ * dsc_config - configures dsc encoder
+ * @hw_dsc: Pointer to dsc context
+ * @dsc: panel dsc parameters
+ * @mode: dsc topology mode to be set
+ */
+ void (*dsc_config)(struct dpu_hw_dsc *hw_dsc,
+ struct msm_display_dsc_config *dsc, u32 mode);
+
+ /**
+ * dsc_config_thresh - programs panel thresholds
+ * @hw_dsc: Pointer to dsc context
+ * @dsc: panel dsc parameters
+ */
+ void (*dsc_config_thresh)(struct dpu_hw_dsc *hw_dsc,
+ struct msm_display_dsc_config *dsc);
+};
+
+struct dpu_hw_dsc {
+ struct dpu_hw_blk base;
+ struct dpu_hw_blk_reg_map hw;
+
+ /* dsc */
+ enum dpu_dsc idx;
+ const struct dpu_dsc_cfg *caps;
+
+ /* ops */
+ struct dpu_hw_dsc_ops ops;
+};
+
+/**
+ * dpu_hw_dsc_init - initializes the dsc block for the passed dsc idx.
+ * @idx: DSC index for which driver object is required
+ * @addr: Mapped register io address of MDP
+ * @m: Pointer to mdss catalog data
+ * Returns: Error code or allocated dpu_hw_dsc context
+ */
+struct dpu_hw_dsc *dpu_hw_dsc_init(enum dpu_dsc idx, void __iomem *addr,
+ struct dpu_mdss_cfg *m);
+
+/**
+ * dpu_hw_dsc_destroy - destroys dsc driver context
+ * @dsc: Pointer to dsc driver context returned by dpu_hw_dsc_init
+ */
+void dpu_hw_dsc_destroy(struct dpu_hw_dsc *dsc);
+
+static inline struct dpu_hw_dsc *to_dpu_hw_dsc(struct dpu_hw_blk *hw)
+{
+ return container_of(hw, struct dpu_hw_dsc, base);
+}
+
+#endif /* _DPU_HW_DSC_H */
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h
index bb9ceadeb0bb..b0ce8cb97d22 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h
@@ -97,6 +97,7 @@ enum dpu_hw_blk_type {
DPU_HW_BLK_WB,
DPU_HW_BLK_DSPP,
DPU_HW_BLK_MERGE_3D,
+ DPU_HW_BLK_DSC,
DPU_HW_BLK_MAX,
};
@@ -176,6 +177,17 @@ enum dpu_ctl {
CTL_MAX
};
+enum dpu_dsc {
+ DSC_NONE = 0,
+ DSC_0,
+ DSC_1,
+ DSC_2,
+ DSC_3,
+ DSC_4,
+ DSC_5,
+ DSC_MAX
+};
+
enum dpu_pingpong {
PINGPONG_0 = 1,
PINGPONG_1,
@@ -437,5 +449,6 @@ struct dpu_mdss_color {
#define DPU_DBG_MASK_VBIF (1 << 8)
#define DPU_DBG_MASK_ROT (1 << 9)
#define DPU_DBG_MASK_DSPP (1 << 10)
+#define DPU_DBG_MASK_DSC (1 << 11)
#endif /* _DPU_HW_MDSS_H */
--
2.31.1
^ permalink raw reply [flat|nested] 4+ messages in thread