Message ID | 1682033114-28483-2-git-send-email-quic_khsieh@quicinc.com |
---|---|
State | New |
Headers | show |
Series | add DSC 1.2 dpu supports | expand |
On 21/04/2023 02:25, Kuogee Hsieh wrote: > Add support for DSC 1.2 by providing the necessary hooks to program > the DPU DSC 1.2 encoder. > > Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com> > --- > drivers/gpu/drm/msm/Makefile | 1 + > drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h | 38 ++- > drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h | 17 +- > drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c | 388 +++++++++++++++++++++++++ > drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c | 7 +- > 5 files changed, 444 insertions(+), 7 deletions(-) > create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c > > diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile > index b814fc8..b9af5e4 100644 > --- a/drivers/gpu/drm/msm/Makefile > +++ b/drivers/gpu/drm/msm/Makefile > @@ -65,6 +65,7 @@ msm-$(CONFIG_DRM_MSM_DPU) += \ > disp/dpu1/dpu_hw_catalog.o \ > disp/dpu1/dpu_hw_ctl.o \ > disp/dpu1/dpu_hw_dsc.o \ > + disp/dpu1/dpu_hw_dsc_1_2.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 71584cd..22421b9 100644 > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h > @@ -1,6 +1,6 @@ > /* SPDX-License-Identifier: GPL-2.0-only */ > /* > - * Copyright (c) 2022. Qualcomm Innovation Center, Inc. All rights reserved. > + * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved. > * Copyright (c) 2015-2018, 2020 The Linux Foundation. All rights reserved. > */ > > @@ -241,12 +241,20 @@ enum { > }; > > /** > - * DSC features > - * @DPU_DSC_OUTPUT_CTRL Configure which PINGPONG block gets > - * the pixel output from this DSC. > + * DSC sub-blocks/features > + * @DPU_DSC_OUTPUT_CTRL Configure which PINGPONG block gets > + * the pixel output from this DSC. Any reason to change the alignment > + * @DPU_DSC_HW_REV_1_1 DSC block supports dsc 1.1 only > + * @DPU_DSC_HW_REV_1_2 DSC block supports dsc 1.1 and 1.2 > + * @DPU_DSC_NATIVE_422_EN Supports native422 and native420 encoding > + * @DPU_DSC_MAX > */ > enum { > DPU_DSC_OUTPUT_CTRL = 0x1, > + DPU_DSC_HW_REV_1_1, > + DPU_DSC_HW_REV_1_2, > + DPU_DSC_NATIVE_422_EN, > + DPU_DSC_MAX > }; > > /** > @@ -311,6 +319,14 @@ struct dpu_pp_blk { > }; > > /** > + * struct dpu_dsc_blk - DSC Encoder sub-blk information > + * @info: HW register and features supported by this sub-blk > + */ > +struct dpu_dsc_blk { > + DPU_HW_SUBBLK_INFO; > +}; > + > +/** > * enum dpu_qos_lut_usage - define QoS LUT use cases > */ > enum dpu_qos_lut_usage { > @@ -459,6 +475,17 @@ struct dpu_pingpong_sub_blks { > }; > > /** > + * struct dpu_dsc_sub_blks - DSC sub-blks > + * @enc: DSC encoder sub block > + * @ctl: DSC controller sub block > + * > + */ > +struct dpu_dsc_sub_blks { > + struct dpu_dsc_blk enc; > + struct dpu_dsc_blk ctl; > +}; > + > +/** > * dpu_clk_ctrl_type - Defines top level clock control signals > */ > enum dpu_clk_ctrl_type { > @@ -612,10 +639,13 @@ struct dpu_merge_3d_cfg { > * struct dpu_dsc_cfg - information of DSC blocks > * @id enum identifying this block > * @base register offset of this block > + * @len: length of hardware block > * @features bit mask identifying sub-blocks/features > + * @sblk sub-blocks information > */ > struct dpu_dsc_cfg { > DPU_HW_BLK_INFO; > + const struct dpu_dsc_sub_blks *sblk; > }; > > /** > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h > index ae9b5db..d0f8b8b 100644 > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h > @@ -1,5 +1,8 @@ > /* SPDX-License-Identifier: GPL-2.0-only */ > -/* Copyright (c) 2020-2022, Linaro Limited */ > +/* > + * Copyright (c) 2020-2022, Linaro Limited > + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved > + */ > > #ifndef _DPU_HW_DSC_H > #define _DPU_HW_DSC_H > @@ -61,7 +64,7 @@ struct dpu_hw_dsc { > }; > > /** > - * dpu_hw_dsc_init - initializes the dsc block for the passed dsc idx. > + * dpu_hw_dsc_init - initializes the v1.1 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 > @@ -71,6 +74,16 @@ struct dpu_hw_dsc *dpu_hw_dsc_init(enum dpu_dsc idx, void __iomem *addr, > const struct dpu_mdss_cfg *m); > > /** > + * dpu_hw_dsc_init_1_2 - initializes the v1.2 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_1_2(enum dpu_dsc idx, void __iomem *addr, > + const 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 > */ > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c > new file mode 100644 > index 00000000..455d7f2 > --- /dev/null > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c > @@ -0,0 +1,388 @@ > +// SPDX-License-Identifier: GPL-2.0-only > +/* > + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. > + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved > + */ > + > +#include <drm/display/drm_dsc_helper.h> > + > +#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_CMN_MAIN_CNF 0x00 > + > +/* DPU_DSC_ENC register offsets */ > +#define ENC_DF_CTRL 0x00 > +#define ENC_GENERAL_STATUS 0x04 > +#define ENC_HSLICE_STATUS 0x08 > +#define ENC_OUT_STATUS 0x0C > +#define ENC_INT_STAT 0x10 > +#define ENC_INT_CLR 0x14 > +#define ENC_INT_MASK 0x18 > +#define DSC_MAIN_CONF 0x30 > +#define DSC_PICTURE_SIZE 0x34 > +#define DSC_SLICE_SIZE 0x38 > +#define DSC_MISC_SIZE 0x3C > +#define DSC_HRD_DELAYS 0x40 > +#define DSC_RC_SCALE 0x44 > +#define DSC_RC_SCALE_INC_DEC 0x48 > +#define DSC_RC_OFFSETS_1 0x4C > +#define DSC_RC_OFFSETS_2 0x50 > +#define DSC_RC_OFFSETS_3 0x54 > +#define DSC_RC_OFFSETS_4 0x58 > +#define DSC_FLATNESS_QP 0x5C > +#define DSC_RC_MODEL_SIZE 0x60 > +#define DSC_RC_CONFIG 0x64 > +#define DSC_RC_BUF_THRESH_0 0x68 > +#define DSC_RC_BUF_THRESH_1 0x6C > +#define DSC_RC_BUF_THRESH_2 0x70 > +#define DSC_RC_BUF_THRESH_3 0x74 > +#define DSC_RC_MIN_QP_0 0x78 > +#define DSC_RC_MIN_QP_1 0x7C > +#define DSC_RC_MIN_QP_2 0x80 > +#define DSC_RC_MAX_QP_0 0x84 > +#define DSC_RC_MAX_QP_1 0x88 > +#define DSC_RC_MAX_QP_2 0x8C As you are adding new definitions, could please make them aligned from the beginning? > +#define DSC_RC_RANGE_BPG_OFFSETS_0 0x90 > +#define DSC_RC_RANGE_BPG_OFFSETS_1 0x94 > +#define DSC_RC_RANGE_BPG_OFFSETS_2 0x98 > + > +/* DPU_DSC_CTL register offsets */ > +#define DSC_CTL 0x00 > +#define DSC_CFG 0x04 > +#define DSC_DATA_IN_SWAP 0x08 > +#define DSC_CLK_CTRL 0x0C > + > +/* > + * @DPU_DSC_ENC DSC encoder sub block > + * @DPU_DSC_CTL DSC controller sub block > + */ > +enum { > + DPU_DSC_ENC, > + DPU_DSC_CTL, > +}; > + > +static int _dsc_calc_ob_max_addr(struct dpu_hw_dsc *hw_dsc, int num_ss) If this is used from a single place, please inline this function. > +{ > + int max_addr = 2400 / num_ss; > + > + if (hw_dsc->caps->features & BIT(DPU_DSC_NATIVE_422_EN)) > + max_addr /= 2; Is this really guarded by the hw block feature or by native_422 being enabled? > + > + return max_addr - 1; > +}; > + > [skipped] > +static void dpu_hw_dsc_config_thresh_1_2(struct dpu_hw_dsc *hw_dsc, > + struct drm_dsc_config *dsc) > +{ > + struct dpu_hw_blk_reg_map *hw; > + u32 offset, off; > + int i, j = 0; > + struct drm_dsc_rc_range_parameters *rc; > + u32 data = 0, min_qp = 0, max_qp = 0, bpg_off = 0; > + > + if (!hw_dsc || !dsc) > + return; > + > + _dsc_subblk_offset(hw_dsc, DPU_DSC_ENC, &offset); > + > + hw = &hw_dsc->hw; > + > + rc = dsc->rc_range_params; > + > + off = 0; > + for (i = 0; i < DSC_NUM_BUF_RANGES - 1; i++) { > + data |= dsc->rc_buf_thresh[i] << (8 * j); > + j++; > + if ((j == 4) || (i == DSC_NUM_BUF_RANGES - 2)) { > + DPU_REG_WRITE(hw, offset + DSC_RC_BUF_THRESH_0 + off, > + data); > + off += 4; > + j = 0; > + data = 0; > + } > + } > + > + off = 0; > + for (i = 0; i < DSC_NUM_BUF_RANGES; i++) { > + min_qp |= rc[i].range_min_qp << (5 * j); > + max_qp |= rc[i].range_max_qp << (5 * j); > + bpg_off |= rc[i].range_bpg_offset << (6 * j); > + j++; > + if (j == 5) { > + DPU_REG_WRITE(hw, offset + DSC_RC_MIN_QP_0 + off, > + min_qp); > + DPU_REG_WRITE(hw, offset + DSC_RC_MAX_QP_0 + off, > + max_qp); > + DPU_REG_WRITE(hw, > + offset + DSC_RC_RANGE_BPG_OFFSETS_0 + off, > + bpg_off); > + off += 4; > + j = 0; > + min_qp = 0; > + max_qp = 0; > + bpg_off = 0; > + } > + } Unrolling these loops would make it easier to understand them. > +} > + > +static void dpu_hw_dsc_bind_pingpong_blk_1_2( > + struct dpu_hw_dsc *hw_dsc, > + bool enable, > + const enum dpu_pingpong pp) > +{ > + struct dpu_hw_blk_reg_map *hw; > + int offset; > + int mux_cfg = 0xf; /* Disabled */ > + > + _dsc_subblk_offset(hw_dsc, DPU_DSC_CTL, &offset); > + > + hw = &hw_dsc->hw; > + if (enable) > + mux_cfg = (pp - PINGPONG_0) & 0x7; > + > + DPU_REG_WRITE(hw, offset + DSC_CTL, mux_cfg); > +} > + > +static const struct dpu_dsc_cfg *_dsc_offset(enum dpu_dsc dsc, > + const 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->blk_addr = addr + m->dsc[i].base; > + b->log_mask = DPU_DBG_MASK_DSC; > + return &m->dsc[i]; > + } > + } > + > + return NULL; > +} > + > +static void _setup_dcs_ops_1_2(struct dpu_hw_dsc_ops *ops, > + const unsigned long features) > +{ > + ops->dsc_disable = dpu_hw_dsc_disable_1_2; > + ops->dsc_config = dpu_hw_dsc_config_1_2; > + ops->dsc_config_thresh = dpu_hw_dsc_config_thresh_1_2; > + ops->dsc_bind_pingpong_blk = dpu_hw_dsc_bind_pingpong_blk_1_2; > +} > + > +struct dpu_hw_dsc *dpu_hw_dsc_init_1_2(enum dpu_dsc idx, void __iomem *addr, > + const struct dpu_mdss_cfg *m) > +{ Please rebase on top of https://patchwork.freedesktop.org/series/116615/ > + struct dpu_hw_dsc *c; > + const 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_dcs_ops_1_2(&c->ops, c->caps->features); > + > + return c; > +} > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c > index f4dda88..f7014f5 100644 > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c > @@ -1,6 +1,7 @@ > // SPDX-License-Identifier: GPL-2.0-only > /* > * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. > + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. > */ > > #define pr_fmt(fmt) "[drm:%s] " fmt, __func__ > @@ -250,7 +251,11 @@ int dpu_rm_init(struct dpu_rm *rm, > struct dpu_hw_dsc *hw; > const struct dpu_dsc_cfg *dsc = &cat->dsc[i]; > > - hw = dpu_hw_dsc_init(dsc->id, mmio, cat); > + if (test_bit(DPU_DSC_HW_REV_1_2, &dsc->features)) > + hw = dpu_hw_dsc_init_1_2(dsc->id, mmio, cat); > + else > + hw = dpu_hw_dsc_init(dsc->id, mmio, cat); > + > if (IS_ERR_OR_NULL(hw)) { > rc = PTR_ERR(hw); > DPU_ERROR("failed dsc object creation: err %d\n", rc);
Hi Kuogee, kernel test robot noticed the following build warnings: [auto build test WARNING on drm-misc/drm-misc-next] [also build test WARNING on drm/drm-next drm-exynos/exynos-drm-next drm-intel/for-linux-next drm-intel/for-linux-next-fixes drm-tip/drm-tip linus/master v6.3-rc7 next-20230420] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information] url: https://github.com/intel-lab-lkp/linux/commits/Kuogee-Hsieh/drm-msm-dpu-add-support-for-DSC-encoder-v1-2-engine/20230421-072925 base: git://anongit.freedesktop.org/drm/drm-misc drm-misc-next patch link: https://lore.kernel.org/r/1682033114-28483-2-git-send-email-quic_khsieh%40quicinc.com patch subject: [PATCH v1 1/5] drm/msm/dpu: add support for DSC encoder v1.2 engine config: sparc-allyesconfig (https://download.01.org/0day-ci/archive/20230421/202304211131.LQJKi60t-lkp@intel.com/config) compiler: sparc64-linux-gcc (GCC) 12.1.0 reproduce (this is a W=1 build): wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # https://github.com/intel-lab-lkp/linux/commit/1c3eede9e4f8fc63f52eddb0c55f63d59fad4b68 git remote add linux-review https://github.com/intel-lab-lkp/linux git fetch --no-tags linux-review Kuogee-Hsieh/drm-msm-dpu-add-support-for-DSC-encoder-v1-2-engine/20230421-072925 git checkout 1c3eede9e4f8fc63f52eddb0c55f63d59fad4b68 # save the config file mkdir build_dir && cp config build_dir/.config COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=sparc olddefconfig COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=sparc SHELL=/bin/bash drivers/gpu/drm/msm/ If you fix the issue, kindly add following tag where applicable | Reported-by: kernel test robot <lkp@intel.com> | Link: https://lore.kernel.org/oe-kbuild-all/202304211131.LQJKi60t-lkp@intel.com/ All warnings (new ones prefixed by >>): drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c: In function 'dpu_hw_dsc_config_1_2': drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c:227:31: error: implicit declaration of function 'drm_dsc_calculate_flatness_det_thresh' [-Werror=implicit-function-declaration] 227 | det_thresh_flatness = drm_dsc_calculate_flatness_det_thresh(dsc); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ >> drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c:124:23: warning: variable 'off' set but not used [-Wunused-but-set-variable] 124 | void __iomem *off; | ^~~ cc1: some warnings being treated as errors vim +/off +124 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c 112 113 static void dpu_hw_dsc_config_1_2(struct dpu_hw_dsc *hw_dsc, 114 struct drm_dsc_config *dsc, 115 u32 mode, 116 u32 initial_lines) 117 { 118 struct dpu_hw_blk_reg_map *hw; 119 u32 offset; 120 u32 data = 0; 121 u32 det_thresh_flatness; 122 u32 num_active_ss_per_enc; 123 u32 bpp; > 124 void __iomem *off; 125 126 if (!hw_dsc || !dsc) 127 return; 128 129 hw = &hw_dsc->hw; 130 131 _dsc_subblk_offset(hw_dsc, DPU_DSC_ENC, &offset); 132 133 if (mode & DSC_MODE_SPLIT_PANEL) 134 data |= BIT(0); 135 136 if (mode & DSC_MODE_MULTIPLEX) 137 data |= BIT(1); 138 139 num_active_ss_per_enc = dsc->slice_count; 140 if (mode & DSC_MODE_MULTIPLEX) 141 num_active_ss_per_enc = dsc->slice_count >> 1; 142 143 data |= (num_active_ss_per_enc & 0x3) << 7; 144 145 DPU_REG_WRITE(hw, DSC_CMN_MAIN_CNF, data); 146 147 data = (initial_lines & 0xff); 148 149 if (mode & DSC_MODE_VIDEO) 150 data |= BIT(9); 151 152 data |= (_dsc_calc_ob_max_addr(hw_dsc, num_active_ss_per_enc) << 18); 153 154 DPU_REG_WRITE(hw, offset + ENC_DF_CTRL, data); 155 156 data = (dsc->dsc_version_minor & 0xf) << 28; 157 if (dsc->dsc_version_minor == 0x2) { 158 if (dsc->native_422) 159 data |= BIT(22); 160 if (dsc->native_420) 161 data |= BIT(21); 162 } 163 164 bpp = dsc->bits_per_pixel; 165 /* as per hw requirement bpp should be programmed 166 * twice the actual value in case of 420 or 422 encoding 167 */ 168 if (dsc->native_422 || dsc->native_420) 169 bpp = 2 * bpp; 170 data |= (dsc->block_pred_enable ? 1 : 0) << 20; 171 data |= bpp << 10; 172 data |= (dsc->line_buf_depth & 0xf) << 6; 173 data |= dsc->convert_rgb << 4; 174 data |= dsc->bits_per_component & 0xf; 175 176 DPU_REG_WRITE(hw, offset + DSC_MAIN_CONF, data); 177 178 data = (dsc->pic_width & 0xffff) | 179 ((dsc->pic_height & 0xffff) << 16); 180 181 DPU_REG_WRITE(hw, offset + DSC_PICTURE_SIZE, data); 182 183 data = (dsc->slice_width & 0xffff) | 184 ((dsc->slice_height & 0xffff) << 16); 185 186 DPU_REG_WRITE(hw, offset + DSC_SLICE_SIZE, data); 187 188 DPU_REG_WRITE(hw, offset + DSC_MISC_SIZE, 189 (dsc->slice_chunk_size) & 0xffff); 190 191 data = (dsc->initial_xmit_delay & 0xffff) | 192 ((dsc->initial_dec_delay & 0xffff) << 16); 193 194 DPU_REG_WRITE(hw, offset + DSC_HRD_DELAYS, data); 195 196 DPU_REG_WRITE(hw, offset + DSC_RC_SCALE, 197 dsc->initial_scale_value & 0x3f); 198 199 data = (dsc->scale_increment_interval & 0xffff) | 200 ((dsc->scale_decrement_interval & 0x7ff) << 16); 201 202 DPU_REG_WRITE(hw, offset + DSC_RC_SCALE_INC_DEC, data); 203 204 data = (dsc->first_line_bpg_offset & 0x1f) | 205 ((dsc->second_line_bpg_offset & 0x1f) << 5); 206 207 DPU_REG_WRITE(hw, offset + DSC_RC_OFFSETS_1, data); 208 209 data = (dsc->nfl_bpg_offset & 0xffff) | 210 ((dsc->slice_bpg_offset & 0xffff) << 16); 211 212 DPU_REG_WRITE(hw, offset + DSC_RC_OFFSETS_2, data); 213 214 data = (dsc->initial_offset & 0xffff) | 215 ((dsc->final_offset & 0xffff) << 16); 216 217 DPU_REG_WRITE(hw, offset + DSC_RC_OFFSETS_3, data); 218 219 data = (dsc->nsl_bpg_offset & 0xffff) | 220 ((dsc->second_line_offset_adj & 0xffff) << 16); 221 222 DPU_REG_WRITE(hw, offset + DSC_RC_OFFSETS_4, data); 223 224 data = (dsc->flatness_min_qp & 0x1f); 225 data |= (dsc->flatness_max_qp & 0x1f) << 5; 226 227 det_thresh_flatness = drm_dsc_calculate_flatness_det_thresh(dsc); 228 data |= (det_thresh_flatness & 0xff) << 10; 229 230 DPU_REG_WRITE(hw, offset + DSC_FLATNESS_QP, data); 231 232 DPU_REG_WRITE(hw, offset + DSC_RC_MODEL_SIZE, 233 (dsc->rc_model_size) & 0xffff); 234 235 data = dsc->rc_edge_factor & 0xf; 236 data |= (dsc->rc_quant_incr_limit0 & 0x1f) << 8; 237 data |= (dsc->rc_quant_incr_limit1 & 0x1f) << 13; 238 data |= (dsc->rc_tgt_offset_high & 0xf) << 20; 239 data |= (dsc->rc_tgt_offset_low & 0xf) << 24; 240 241 DPU_REG_WRITE(hw, offset + DSC_RC_CONFIG, data); 242 243 /* program the dsc wrapper */ 244 _dsc_subblk_offset(hw_dsc, DPU_DSC_CTL, &offset); 245 246 off = hw->blk_addr + offset; 247 248 data = BIT(0); /* encoder enable */ 249 if (dsc->native_422) 250 data |= BIT(8); 251 else if (dsc->native_420) 252 data |= BIT(9); 253 if (!dsc->convert_rgb) 254 data |= BIT(10); 255 if (dsc->bits_per_component == 8) 256 data |= BIT(11); 257 if (mode & DSC_MODE_SPLIT_PANEL) 258 data |= BIT(12); 259 if (mode & DSC_MODE_MULTIPLEX) 260 data |= BIT(13); 261 if (!(mode & DSC_MODE_VIDEO)) 262 data |= BIT(17); 263 264 DPU_REG_WRITE(hw, offset + DSC_CFG, data); 265 } 266
Hi Kuogee, kernel test robot noticed the following build errors: [auto build test ERROR on drm-misc/drm-misc-next] [also build test ERROR on drm/drm-next drm-exynos/exynos-drm-next drm-intel/for-linux-next drm-intel/for-linux-next-fixes drm-tip/drm-tip linus/master v6.3-rc7 next-20230420] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information] url: https://github.com/intel-lab-lkp/linux/commits/Kuogee-Hsieh/drm-msm-dpu-add-support-for-DSC-encoder-v1-2-engine/20230421-072925 base: git://anongit.freedesktop.org/drm/drm-misc drm-misc-next patch link: https://lore.kernel.org/r/1682033114-28483-2-git-send-email-quic_khsieh%40quicinc.com patch subject: [PATCH v1 1/5] drm/msm/dpu: add support for DSC encoder v1.2 engine config: riscv-randconfig-r013-20230421 (https://download.01.org/0day-ci/archive/20230422/202304220258.dmrglaf1-lkp@intel.com/config) compiler: clang version 17.0.0 (https://github.com/llvm/llvm-project 437b7602e4a998220871de78afcb020b9c14a661) reproduce (this is a W=1 build): wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # install riscv cross compiling tool for clang build # apt-get install binutils-riscv64-linux-gnu # https://github.com/intel-lab-lkp/linux/commit/1c3eede9e4f8fc63f52eddb0c55f63d59fad4b68 git remote add linux-review https://github.com/intel-lab-lkp/linux git fetch --no-tags linux-review Kuogee-Hsieh/drm-msm-dpu-add-support-for-DSC-encoder-v1-2-engine/20230421-072925 git checkout 1c3eede9e4f8fc63f52eddb0c55f63d59fad4b68 # save the config file mkdir build_dir && cp config build_dir/.config COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=riscv olddefconfig COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=riscv SHELL=/bin/bash drivers/gpu/drm/msm/ If you fix the issue, kindly add following tag where applicable | Reported-by: kernel test robot <lkp@intel.com> | Link: https://lore.kernel.org/oe-kbuild-all/202304220258.dmrglaf1-lkp@intel.com/ All error/warnings (new ones prefixed by >>): >> drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c:227:24: error: call to undeclared function 'drm_dsc_calculate_flatness_det_thresh'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration] det_thresh_flatness = drm_dsc_calculate_flatness_det_thresh(dsc); ^ >> drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c:124:16: warning: variable 'off' set but not used [-Wunused-but-set-variable] void __iomem *off; ^ 1 warning and 1 error generated. vim +/drm_dsc_calculate_flatness_det_thresh +227 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c 112 113 static void dpu_hw_dsc_config_1_2(struct dpu_hw_dsc *hw_dsc, 114 struct drm_dsc_config *dsc, 115 u32 mode, 116 u32 initial_lines) 117 { 118 struct dpu_hw_blk_reg_map *hw; 119 u32 offset; 120 u32 data = 0; 121 u32 det_thresh_flatness; 122 u32 num_active_ss_per_enc; 123 u32 bpp; > 124 void __iomem *off; 125 126 if (!hw_dsc || !dsc) 127 return; 128 129 hw = &hw_dsc->hw; 130 131 _dsc_subblk_offset(hw_dsc, DPU_DSC_ENC, &offset); 132 133 if (mode & DSC_MODE_SPLIT_PANEL) 134 data |= BIT(0); 135 136 if (mode & DSC_MODE_MULTIPLEX) 137 data |= BIT(1); 138 139 num_active_ss_per_enc = dsc->slice_count; 140 if (mode & DSC_MODE_MULTIPLEX) 141 num_active_ss_per_enc = dsc->slice_count >> 1; 142 143 data |= (num_active_ss_per_enc & 0x3) << 7; 144 145 DPU_REG_WRITE(hw, DSC_CMN_MAIN_CNF, data); 146 147 data = (initial_lines & 0xff); 148 149 if (mode & DSC_MODE_VIDEO) 150 data |= BIT(9); 151 152 data |= (_dsc_calc_ob_max_addr(hw_dsc, num_active_ss_per_enc) << 18); 153 154 DPU_REG_WRITE(hw, offset + ENC_DF_CTRL, data); 155 156 data = (dsc->dsc_version_minor & 0xf) << 28; 157 if (dsc->dsc_version_minor == 0x2) { 158 if (dsc->native_422) 159 data |= BIT(22); 160 if (dsc->native_420) 161 data |= BIT(21); 162 } 163 164 bpp = dsc->bits_per_pixel; 165 /* as per hw requirement bpp should be programmed 166 * twice the actual value in case of 420 or 422 encoding 167 */ 168 if (dsc->native_422 || dsc->native_420) 169 bpp = 2 * bpp; 170 data |= (dsc->block_pred_enable ? 1 : 0) << 20; 171 data |= bpp << 10; 172 data |= (dsc->line_buf_depth & 0xf) << 6; 173 data |= dsc->convert_rgb << 4; 174 data |= dsc->bits_per_component & 0xf; 175 176 DPU_REG_WRITE(hw, offset + DSC_MAIN_CONF, data); 177 178 data = (dsc->pic_width & 0xffff) | 179 ((dsc->pic_height & 0xffff) << 16); 180 181 DPU_REG_WRITE(hw, offset + DSC_PICTURE_SIZE, data); 182 183 data = (dsc->slice_width & 0xffff) | 184 ((dsc->slice_height & 0xffff) << 16); 185 186 DPU_REG_WRITE(hw, offset + DSC_SLICE_SIZE, data); 187 188 DPU_REG_WRITE(hw, offset + DSC_MISC_SIZE, 189 (dsc->slice_chunk_size) & 0xffff); 190 191 data = (dsc->initial_xmit_delay & 0xffff) | 192 ((dsc->initial_dec_delay & 0xffff) << 16); 193 194 DPU_REG_WRITE(hw, offset + DSC_HRD_DELAYS, data); 195 196 DPU_REG_WRITE(hw, offset + DSC_RC_SCALE, 197 dsc->initial_scale_value & 0x3f); 198 199 data = (dsc->scale_increment_interval & 0xffff) | 200 ((dsc->scale_decrement_interval & 0x7ff) << 16); 201 202 DPU_REG_WRITE(hw, offset + DSC_RC_SCALE_INC_DEC, data); 203 204 data = (dsc->first_line_bpg_offset & 0x1f) | 205 ((dsc->second_line_bpg_offset & 0x1f) << 5); 206 207 DPU_REG_WRITE(hw, offset + DSC_RC_OFFSETS_1, data); 208 209 data = (dsc->nfl_bpg_offset & 0xffff) | 210 ((dsc->slice_bpg_offset & 0xffff) << 16); 211 212 DPU_REG_WRITE(hw, offset + DSC_RC_OFFSETS_2, data); 213 214 data = (dsc->initial_offset & 0xffff) | 215 ((dsc->final_offset & 0xffff) << 16); 216 217 DPU_REG_WRITE(hw, offset + DSC_RC_OFFSETS_3, data); 218 219 data = (dsc->nsl_bpg_offset & 0xffff) | 220 ((dsc->second_line_offset_adj & 0xffff) << 16); 221 222 DPU_REG_WRITE(hw, offset + DSC_RC_OFFSETS_4, data); 223 224 data = (dsc->flatness_min_qp & 0x1f); 225 data |= (dsc->flatness_max_qp & 0x1f) << 5; 226 > 227 det_thresh_flatness = drm_dsc_calculate_flatness_det_thresh(dsc); 228 data |= (det_thresh_flatness & 0xff) << 10; 229 230 DPU_REG_WRITE(hw, offset + DSC_FLATNESS_QP, data); 231 232 DPU_REG_WRITE(hw, offset + DSC_RC_MODEL_SIZE, 233 (dsc->rc_model_size) & 0xffff); 234 235 data = dsc->rc_edge_factor & 0xf; 236 data |= (dsc->rc_quant_incr_limit0 & 0x1f) << 8; 237 data |= (dsc->rc_quant_incr_limit1 & 0x1f) << 13; 238 data |= (dsc->rc_tgt_offset_high & 0xf) << 20; 239 data |= (dsc->rc_tgt_offset_low & 0xf) << 24; 240 241 DPU_REG_WRITE(hw, offset + DSC_RC_CONFIG, data); 242 243 /* program the dsc wrapper */ 244 _dsc_subblk_offset(hw_dsc, DPU_DSC_CTL, &offset); 245 246 off = hw->blk_addr + offset; 247 248 data = BIT(0); /* encoder enable */ 249 if (dsc->native_422) 250 data |= BIT(8); 251 else if (dsc->native_420) 252 data |= BIT(9); 253 if (!dsc->convert_rgb) 254 data |= BIT(10); 255 if (dsc->bits_per_component == 8) 256 data |= BIT(11); 257 if (mode & DSC_MODE_SPLIT_PANEL) 258 data |= BIT(12); 259 if (mode & DSC_MODE_MULTIPLEX) 260 data |= BIT(13); 261 if (!(mode & DSC_MODE_VIDEO)) 262 data |= BIT(17); 263 264 DPU_REG_WRITE(hw, offset + DSC_CFG, data); 265 } 266
On 21/04/2023 02:25, Kuogee Hsieh wrote: > Add support for DSC 1.2 by providing the necessary hooks to program > the DPU DSC 1.2 encoder. > > Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com> > --- > drivers/gpu/drm/msm/Makefile | 1 + > drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h | 38 ++- > drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h | 17 +- > drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c | 388 +++++++++++++++++++++++++ > drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c | 7 +- > 5 files changed, 444 insertions(+), 7 deletions(-) > create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c > [skipped] > +static inline void _dsc_subblk_offset(struct dpu_hw_dsc *hw_dsc, int s_id, > + u32 *offset) > +{ > + const struct dpu_dsc_sub_blks *sblk; > + > + sblk = hw_dsc->caps->sblk; > + > + if (s_id == DPU_DSC_ENC) > + *offset = sblk->enc.base; > + else if (s_id == DPU_DSC_CTL) > + *offset = sblk->ctl.base; > + else > + DPU_ERROR("invalid DSC sub block=%d\n", s_id); > +} I have just sent a patchset removing the _sspp_subblk_offset. Could you please inline this function too? > + > +static void dpu_hw_dsc_disable_1_2(struct dpu_hw_dsc *hw_dsc) > +{ > + struct dpu_hw_blk_reg_map *hw; > + u32 offset; > + > + if (!hw_dsc) > + return; > + > + _dsc_subblk_offset(hw_dsc, DPU_DSC_CTL, &offset); > + > + hw = &hw_dsc->hw; > + DPU_REG_WRITE(hw, offset + DSC_CFG, 0); > + > + _dsc_subblk_offset(hw_dsc, DPU_DSC_ENC, &offset); > + > + DPU_REG_WRITE(hw, offset + ENC_DF_CTRL, 0); > + DPU_REG_WRITE(hw, offset + DSC_MAIN_CONF, 0); > +} > +
On 4/20/2023 4:54 PM, Dmitry Baryshkov wrote: > On 21/04/2023 02:25, Kuogee Hsieh wrote: >> Add support for DSC 1.2 by providing the necessary hooks to program >> the DPU DSC 1.2 encoder. >> >> Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com> >> --- >> drivers/gpu/drm/msm/Makefile | 1 + >> drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h | 38 ++- >> drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h | 17 +- >> drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c | 388 >> +++++++++++++++++++++++++ >> drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c | 7 +- >> 5 files changed, 444 insertions(+), 7 deletions(-) >> create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c >> >> diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile >> index b814fc8..b9af5e4 100644 >> --- a/drivers/gpu/drm/msm/Makefile >> +++ b/drivers/gpu/drm/msm/Makefile >> @@ -65,6 +65,7 @@ msm-$(CONFIG_DRM_MSM_DPU) += \ >> disp/dpu1/dpu_hw_catalog.o \ >> disp/dpu1/dpu_hw_ctl.o \ >> disp/dpu1/dpu_hw_dsc.o \ >> + disp/dpu1/dpu_hw_dsc_1_2.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 71584cd..22421b9 100644 >> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h >> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h >> @@ -1,6 +1,6 @@ >> /* SPDX-License-Identifier: GPL-2.0-only */ >> /* >> - * Copyright (c) 2022. Qualcomm Innovation Center, Inc. All rights >> reserved. >> + * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All >> rights reserved. >> * Copyright (c) 2015-2018, 2020 The Linux Foundation. All rights >> reserved. >> */ >> @@ -241,12 +241,20 @@ enum { >> }; >> /** >> - * DSC features >> - * @DPU_DSC_OUTPUT_CTRL Configure which PINGPONG block gets >> - * the pixel output from this DSC. >> + * DSC sub-blocks/features >> + * @DPU_DSC_OUTPUT_CTRL Configure which PINGPONG block gets >> + * the pixel output from this DSC. > > Any reason to change the alignment > >> + * @DPU_DSC_HW_REV_1_1 DSC block supports dsc 1.1 only >> + * @DPU_DSC_HW_REV_1_2 DSC block supports dsc 1.1 and 1.2 >> + * @DPU_DSC_NATIVE_422_EN Supports native422 and native420 >> encoding >> + * @DPU_DSC_MAX >> */ >> enum { >> DPU_DSC_OUTPUT_CTRL = 0x1, >> + DPU_DSC_HW_REV_1_1, >> + DPU_DSC_HW_REV_1_2, >> + DPU_DSC_NATIVE_422_EN, >> + DPU_DSC_MAX >> }; >> /** >> @@ -311,6 +319,14 @@ struct dpu_pp_blk { >> }; >> /** >> + * struct dpu_dsc_blk - DSC Encoder sub-blk information >> + * @info: HW register and features supported by this sub-blk >> + */ >> +struct dpu_dsc_blk { >> + DPU_HW_SUBBLK_INFO; >> +}; >> + >> +/** >> * enum dpu_qos_lut_usage - define QoS LUT use cases >> */ >> enum dpu_qos_lut_usage { >> @@ -459,6 +475,17 @@ struct dpu_pingpong_sub_blks { >> }; >> /** >> + * struct dpu_dsc_sub_blks - DSC sub-blks >> + * @enc: DSC encoder sub block >> + * @ctl: DSC controller sub block >> + * >> + */ >> +struct dpu_dsc_sub_blks { >> + struct dpu_dsc_blk enc; >> + struct dpu_dsc_blk ctl; >> +}; >> + >> +/** >> * dpu_clk_ctrl_type - Defines top level clock control signals >> */ >> enum dpu_clk_ctrl_type { >> @@ -612,10 +639,13 @@ struct dpu_merge_3d_cfg { >> * struct dpu_dsc_cfg - information of DSC blocks >> * @id enum identifying this block >> * @base register offset of this block >> + * @len: length of hardware block >> * @features bit mask identifying sub-blocks/features >> + * @sblk sub-blocks information >> */ >> struct dpu_dsc_cfg { >> DPU_HW_BLK_INFO; >> + const struct dpu_dsc_sub_blks *sblk; >> }; >> /** >> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h >> b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h >> index ae9b5db..d0f8b8b 100644 >> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h >> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h >> @@ -1,5 +1,8 @@ >> /* SPDX-License-Identifier: GPL-2.0-only */ >> -/* Copyright (c) 2020-2022, Linaro Limited */ >> +/* >> + * Copyright (c) 2020-2022, Linaro Limited >> + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights >> reserved >> + */ >> #ifndef _DPU_HW_DSC_H >> #define _DPU_HW_DSC_H >> @@ -61,7 +64,7 @@ struct dpu_hw_dsc { >> }; >> /** >> - * dpu_hw_dsc_init - initializes the dsc block for the passed dsc idx. >> + * dpu_hw_dsc_init - initializes the v1.1 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 >> @@ -71,6 +74,16 @@ struct dpu_hw_dsc *dpu_hw_dsc_init(enum dpu_dsc >> idx, void __iomem *addr, >> const struct dpu_mdss_cfg *m); >> /** >> + * dpu_hw_dsc_init_1_2 - initializes the v1.2 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_1_2(enum dpu_dsc idx, void >> __iomem *addr, >> + const 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 >> */ >> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c >> b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c >> new file mode 100644 >> index 00000000..455d7f2 >> --- /dev/null >> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c >> @@ -0,0 +1,388 @@ >> +// SPDX-License-Identifier: GPL-2.0-only >> +/* >> + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. >> + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights >> reserved >> + */ >> + >> +#include <drm/display/drm_dsc_helper.h> >> + >> +#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_CMN_MAIN_CNF 0x00 >> + >> +/* DPU_DSC_ENC register offsets */ >> +#define ENC_DF_CTRL 0x00 >> +#define ENC_GENERAL_STATUS 0x04 >> +#define ENC_HSLICE_STATUS 0x08 >> +#define ENC_OUT_STATUS 0x0C >> +#define ENC_INT_STAT 0x10 >> +#define ENC_INT_CLR 0x14 >> +#define ENC_INT_MASK 0x18 >> +#define DSC_MAIN_CONF 0x30 >> +#define DSC_PICTURE_SIZE 0x34 >> +#define DSC_SLICE_SIZE 0x38 >> +#define DSC_MISC_SIZE 0x3C >> +#define DSC_HRD_DELAYS 0x40 >> +#define DSC_RC_SCALE 0x44 >> +#define DSC_RC_SCALE_INC_DEC 0x48 >> +#define DSC_RC_OFFSETS_1 0x4C >> +#define DSC_RC_OFFSETS_2 0x50 >> +#define DSC_RC_OFFSETS_3 0x54 >> +#define DSC_RC_OFFSETS_4 0x58 >> +#define DSC_FLATNESS_QP 0x5C >> +#define DSC_RC_MODEL_SIZE 0x60 >> +#define DSC_RC_CONFIG 0x64 >> +#define DSC_RC_BUF_THRESH_0 0x68 >> +#define DSC_RC_BUF_THRESH_1 0x6C >> +#define DSC_RC_BUF_THRESH_2 0x70 >> +#define DSC_RC_BUF_THRESH_3 0x74 >> +#define DSC_RC_MIN_QP_0 0x78 >> +#define DSC_RC_MIN_QP_1 0x7C >> +#define DSC_RC_MIN_QP_2 0x80 >> +#define DSC_RC_MAX_QP_0 0x84 >> +#define DSC_RC_MAX_QP_1 0x88 >> +#define DSC_RC_MAX_QP_2 0x8C > > As you are adding new definitions, could please make them aligned from > the beginning? > >> +#define DSC_RC_RANGE_BPG_OFFSETS_0 0x90 >> +#define DSC_RC_RANGE_BPG_OFFSETS_1 0x94 >> +#define DSC_RC_RANGE_BPG_OFFSETS_2 0x98 >> + >> +/* DPU_DSC_CTL register offsets */ >> +#define DSC_CTL 0x00 >> +#define DSC_CFG 0x04 >> +#define DSC_DATA_IN_SWAP 0x08 >> +#define DSC_CLK_CTRL 0x0C >> + >> +/* >> + * @DPU_DSC_ENC DSC encoder sub block >> + * @DPU_DSC_CTL DSC controller sub block >> + */ >> +enum { >> + DPU_DSC_ENC, >> + DPU_DSC_CTL, >> +}; >> + >> +static int _dsc_calc_ob_max_addr(struct dpu_hw_dsc *hw_dsc, int num_ss) > > If this is used from a single place, please inline this function. > >> +{ >> + int max_addr = 2400 / num_ss; >> + >> + if (hw_dsc->caps->features & BIT(DPU_DSC_NATIVE_422_EN)) >> + max_addr /= 2; > > Is this really guarded by the hw block feature or by native_422 being > enabled? > >> + >> + return max_addr - 1; >> +}; >> + >> > > [skipped] > >> +static void dpu_hw_dsc_config_thresh_1_2(struct dpu_hw_dsc *hw_dsc, >> + struct drm_dsc_config *dsc) >> +{ >> + struct dpu_hw_blk_reg_map *hw; >> + u32 offset, off; >> + int i, j = 0; >> + struct drm_dsc_rc_range_parameters *rc; >> + u32 data = 0, min_qp = 0, max_qp = 0, bpg_off = 0; >> + >> + if (!hw_dsc || !dsc) >> + return; >> + >> + _dsc_subblk_offset(hw_dsc, DPU_DSC_ENC, &offset); >> + >> + hw = &hw_dsc->hw; >> + >> + rc = dsc->rc_range_params; >> + >> + off = 0; >> + for (i = 0; i < DSC_NUM_BUF_RANGES - 1; i++) { >> + data |= dsc->rc_buf_thresh[i] << (8 * j); >> + j++; >> + if ((j == 4) || (i == DSC_NUM_BUF_RANGES - 2)) { >> + DPU_REG_WRITE(hw, offset + DSC_RC_BUF_THRESH_0 + off, >> + data); >> + off += 4; >> + j = 0; >> + data = 0; >> + } >> + } >> + >> + off = 0; >> + for (i = 0; i < DSC_NUM_BUF_RANGES; i++) { >> + min_qp |= rc[i].range_min_qp << (5 * j); >> + max_qp |= rc[i].range_max_qp << (5 * j); >> + bpg_off |= rc[i].range_bpg_offset << (6 * j); >> + j++; >> + if (j == 5) { >> + DPU_REG_WRITE(hw, offset + DSC_RC_MIN_QP_0 + off, >> + min_qp); >> + DPU_REG_WRITE(hw, offset + DSC_RC_MAX_QP_0 + off, >> + max_qp); >> + DPU_REG_WRITE(hw, >> + offset + DSC_RC_RANGE_BPG_OFFSETS_0 + off, >> + bpg_off); >> + off += 4; >> + j = 0; >> + min_qp = 0; >> + max_qp = 0; >> + bpg_off = 0; >> + } >> + } > > Unrolling these loops would make it easier to understand them. it is kind of difficult to unrolling the for loop. I will add comments to explain the loop. > >> +} >> + >> +static void dpu_hw_dsc_bind_pingpong_blk_1_2( >> + struct dpu_hw_dsc *hw_dsc, >> + bool enable, >> + const enum dpu_pingpong pp) >> +{ >> + struct dpu_hw_blk_reg_map *hw; >> + int offset; >> + int mux_cfg = 0xf; /* Disabled */ >> + >> + _dsc_subblk_offset(hw_dsc, DPU_DSC_CTL, &offset); >> + >> + hw = &hw_dsc->hw; >> + if (enable) >> + mux_cfg = (pp - PINGPONG_0) & 0x7; >> + >> + DPU_REG_WRITE(hw, offset + DSC_CTL, mux_cfg); >> +} >> + >> +static const struct dpu_dsc_cfg *_dsc_offset(enum dpu_dsc dsc, >> + const 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->blk_addr = addr + m->dsc[i].base; >> + b->log_mask = DPU_DBG_MASK_DSC; >> + return &m->dsc[i]; >> + } >> + } >> + >> + return NULL; >> +} >> + >> +static void _setup_dcs_ops_1_2(struct dpu_hw_dsc_ops *ops, >> + const unsigned long features) >> +{ >> + ops->dsc_disable = dpu_hw_dsc_disable_1_2; >> + ops->dsc_config = dpu_hw_dsc_config_1_2; >> + ops->dsc_config_thresh = dpu_hw_dsc_config_thresh_1_2; >> + ops->dsc_bind_pingpong_blk = dpu_hw_dsc_bind_pingpong_blk_1_2; >> +} >> + >> +struct dpu_hw_dsc *dpu_hw_dsc_init_1_2(enum dpu_dsc idx, void >> __iomem *addr, >> + const struct dpu_mdss_cfg *m) >> +{ > > Please rebase on top of https://patchwork.freedesktop.org/series/116615/ > >> + struct dpu_hw_dsc *c; >> + const 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_dcs_ops_1_2(&c->ops, c->caps->features); >> + >> + return c; >> +} >> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c >> b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c >> index f4dda88..f7014f5 100644 >> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c >> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c >> @@ -1,6 +1,7 @@ >> // SPDX-License-Identifier: GPL-2.0-only >> /* >> * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. >> + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights >> reserved. >> */ >> #define pr_fmt(fmt) "[drm:%s] " fmt, __func__ >> @@ -250,7 +251,11 @@ int dpu_rm_init(struct dpu_rm *rm, >> struct dpu_hw_dsc *hw; >> const struct dpu_dsc_cfg *dsc = &cat->dsc[i]; >> - hw = dpu_hw_dsc_init(dsc->id, mmio, cat); >> + if (test_bit(DPU_DSC_HW_REV_1_2, &dsc->features)) >> + hw = dpu_hw_dsc_init_1_2(dsc->id, mmio, cat); >> + else >> + hw = dpu_hw_dsc_init(dsc->id, mmio, cat); >> + >> if (IS_ERR_OR_NULL(hw)) { >> rc = PTR_ERR(hw); >> DPU_ERROR("failed dsc object creation: err %d\n", rc); >
diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile index b814fc8..b9af5e4 100644 --- a/drivers/gpu/drm/msm/Makefile +++ b/drivers/gpu/drm/msm/Makefile @@ -65,6 +65,7 @@ msm-$(CONFIG_DRM_MSM_DPU) += \ disp/dpu1/dpu_hw_catalog.o \ disp/dpu1/dpu_hw_ctl.o \ disp/dpu1/dpu_hw_dsc.o \ + disp/dpu1/dpu_hw_dsc_1_2.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 71584cd..22421b9 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2022. Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2015-2018, 2020 The Linux Foundation. All rights reserved. */ @@ -241,12 +241,20 @@ enum { }; /** - * DSC features - * @DPU_DSC_OUTPUT_CTRL Configure which PINGPONG block gets - * the pixel output from this DSC. + * DSC sub-blocks/features + * @DPU_DSC_OUTPUT_CTRL Configure which PINGPONG block gets + * the pixel output from this DSC. + * @DPU_DSC_HW_REV_1_1 DSC block supports dsc 1.1 only + * @DPU_DSC_HW_REV_1_2 DSC block supports dsc 1.1 and 1.2 + * @DPU_DSC_NATIVE_422_EN Supports native422 and native420 encoding + * @DPU_DSC_MAX */ enum { DPU_DSC_OUTPUT_CTRL = 0x1, + DPU_DSC_HW_REV_1_1, + DPU_DSC_HW_REV_1_2, + DPU_DSC_NATIVE_422_EN, + DPU_DSC_MAX }; /** @@ -311,6 +319,14 @@ struct dpu_pp_blk { }; /** + * struct dpu_dsc_blk - DSC Encoder sub-blk information + * @info: HW register and features supported by this sub-blk + */ +struct dpu_dsc_blk { + DPU_HW_SUBBLK_INFO; +}; + +/** * enum dpu_qos_lut_usage - define QoS LUT use cases */ enum dpu_qos_lut_usage { @@ -459,6 +475,17 @@ struct dpu_pingpong_sub_blks { }; /** + * struct dpu_dsc_sub_blks - DSC sub-blks + * @enc: DSC encoder sub block + * @ctl: DSC controller sub block + * + */ +struct dpu_dsc_sub_blks { + struct dpu_dsc_blk enc; + struct dpu_dsc_blk ctl; +}; + +/** * dpu_clk_ctrl_type - Defines top level clock control signals */ enum dpu_clk_ctrl_type { @@ -612,10 +639,13 @@ struct dpu_merge_3d_cfg { * struct dpu_dsc_cfg - information of DSC blocks * @id enum identifying this block * @base register offset of this block + * @len: length of hardware block * @features bit mask identifying sub-blocks/features + * @sblk sub-blocks information */ struct dpu_dsc_cfg { DPU_HW_BLK_INFO; + const struct dpu_dsc_sub_blks *sblk; }; /** diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h index ae9b5db..d0f8b8b 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h @@ -1,5 +1,8 @@ /* SPDX-License-Identifier: GPL-2.0-only */ -/* Copyright (c) 2020-2022, Linaro Limited */ +/* + * Copyright (c) 2020-2022, Linaro Limited + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved + */ #ifndef _DPU_HW_DSC_H #define _DPU_HW_DSC_H @@ -61,7 +64,7 @@ struct dpu_hw_dsc { }; /** - * dpu_hw_dsc_init - initializes the dsc block for the passed dsc idx. + * dpu_hw_dsc_init - initializes the v1.1 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 @@ -71,6 +74,16 @@ struct dpu_hw_dsc *dpu_hw_dsc_init(enum dpu_dsc idx, void __iomem *addr, const struct dpu_mdss_cfg *m); /** + * dpu_hw_dsc_init_1_2 - initializes the v1.2 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_1_2(enum dpu_dsc idx, void __iomem *addr, + const 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 */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c new file mode 100644 index 00000000..455d7f2 --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c @@ -0,0 +1,388 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved + */ + +#include <drm/display/drm_dsc_helper.h> + +#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_CMN_MAIN_CNF 0x00 + +/* DPU_DSC_ENC register offsets */ +#define ENC_DF_CTRL 0x00 +#define ENC_GENERAL_STATUS 0x04 +#define ENC_HSLICE_STATUS 0x08 +#define ENC_OUT_STATUS 0x0C +#define ENC_INT_STAT 0x10 +#define ENC_INT_CLR 0x14 +#define ENC_INT_MASK 0x18 +#define DSC_MAIN_CONF 0x30 +#define DSC_PICTURE_SIZE 0x34 +#define DSC_SLICE_SIZE 0x38 +#define DSC_MISC_SIZE 0x3C +#define DSC_HRD_DELAYS 0x40 +#define DSC_RC_SCALE 0x44 +#define DSC_RC_SCALE_INC_DEC 0x48 +#define DSC_RC_OFFSETS_1 0x4C +#define DSC_RC_OFFSETS_2 0x50 +#define DSC_RC_OFFSETS_3 0x54 +#define DSC_RC_OFFSETS_4 0x58 +#define DSC_FLATNESS_QP 0x5C +#define DSC_RC_MODEL_SIZE 0x60 +#define DSC_RC_CONFIG 0x64 +#define DSC_RC_BUF_THRESH_0 0x68 +#define DSC_RC_BUF_THRESH_1 0x6C +#define DSC_RC_BUF_THRESH_2 0x70 +#define DSC_RC_BUF_THRESH_3 0x74 +#define DSC_RC_MIN_QP_0 0x78 +#define DSC_RC_MIN_QP_1 0x7C +#define DSC_RC_MIN_QP_2 0x80 +#define DSC_RC_MAX_QP_0 0x84 +#define DSC_RC_MAX_QP_1 0x88 +#define DSC_RC_MAX_QP_2 0x8C +#define DSC_RC_RANGE_BPG_OFFSETS_0 0x90 +#define DSC_RC_RANGE_BPG_OFFSETS_1 0x94 +#define DSC_RC_RANGE_BPG_OFFSETS_2 0x98 + +/* DPU_DSC_CTL register offsets */ +#define DSC_CTL 0x00 +#define DSC_CFG 0x04 +#define DSC_DATA_IN_SWAP 0x08 +#define DSC_CLK_CTRL 0x0C + +/* + * @DPU_DSC_ENC DSC encoder sub block + * @DPU_DSC_CTL DSC controller sub block + */ +enum { + DPU_DSC_ENC, + DPU_DSC_CTL, +}; + +static int _dsc_calc_ob_max_addr(struct dpu_hw_dsc *hw_dsc, int num_ss) +{ + int max_addr = 2400 / num_ss; + + if (hw_dsc->caps->features & BIT(DPU_DSC_NATIVE_422_EN)) + max_addr /= 2; + + return max_addr - 1; +}; + +static inline void _dsc_subblk_offset(struct dpu_hw_dsc *hw_dsc, int s_id, + u32 *offset) +{ + const struct dpu_dsc_sub_blks *sblk; + + sblk = hw_dsc->caps->sblk; + + if (s_id == DPU_DSC_ENC) + *offset = sblk->enc.base; + else if (s_id == DPU_DSC_CTL) + *offset = sblk->ctl.base; + else + DPU_ERROR("invalid DSC sub block=%d\n", s_id); +} + +static void dpu_hw_dsc_disable_1_2(struct dpu_hw_dsc *hw_dsc) +{ + struct dpu_hw_blk_reg_map *hw; + u32 offset; + + if (!hw_dsc) + return; + + _dsc_subblk_offset(hw_dsc, DPU_DSC_CTL, &offset); + + hw = &hw_dsc->hw; + DPU_REG_WRITE(hw, offset + DSC_CFG, 0); + + _dsc_subblk_offset(hw_dsc, DPU_DSC_ENC, &offset); + + DPU_REG_WRITE(hw, offset + ENC_DF_CTRL, 0); + DPU_REG_WRITE(hw, offset + DSC_MAIN_CONF, 0); +} + +static void dpu_hw_dsc_config_1_2(struct dpu_hw_dsc *hw_dsc, + struct drm_dsc_config *dsc, + u32 mode, + u32 initial_lines) +{ + struct dpu_hw_blk_reg_map *hw; + u32 offset; + u32 data = 0; + u32 det_thresh_flatness; + u32 num_active_ss_per_enc; + u32 bpp; + void __iomem *off; + + if (!hw_dsc || !dsc) + return; + + hw = &hw_dsc->hw; + + _dsc_subblk_offset(hw_dsc, DPU_DSC_ENC, &offset); + + if (mode & DSC_MODE_SPLIT_PANEL) + data |= BIT(0); + + if (mode & DSC_MODE_MULTIPLEX) + data |= BIT(1); + + num_active_ss_per_enc = dsc->slice_count; + if (mode & DSC_MODE_MULTIPLEX) + num_active_ss_per_enc = dsc->slice_count >> 1; + + data |= (num_active_ss_per_enc & 0x3) << 7; + + DPU_REG_WRITE(hw, DSC_CMN_MAIN_CNF, data); + + data = (initial_lines & 0xff); + + if (mode & DSC_MODE_VIDEO) + data |= BIT(9); + + data |= (_dsc_calc_ob_max_addr(hw_dsc, num_active_ss_per_enc) << 18); + + DPU_REG_WRITE(hw, offset + ENC_DF_CTRL, data); + + data = (dsc->dsc_version_minor & 0xf) << 28; + if (dsc->dsc_version_minor == 0x2) { + if (dsc->native_422) + data |= BIT(22); + if (dsc->native_420) + data |= BIT(21); + } + + bpp = dsc->bits_per_pixel; + /* as per hw requirement bpp should be programmed + * twice the actual value in case of 420 or 422 encoding + */ + if (dsc->native_422 || dsc->native_420) + bpp = 2 * bpp; + data |= (dsc->block_pred_enable ? 1 : 0) << 20; + data |= bpp << 10; + data |= (dsc->line_buf_depth & 0xf) << 6; + data |= dsc->convert_rgb << 4; + data |= dsc->bits_per_component & 0xf; + + DPU_REG_WRITE(hw, offset + DSC_MAIN_CONF, data); + + data = (dsc->pic_width & 0xffff) | + ((dsc->pic_height & 0xffff) << 16); + + DPU_REG_WRITE(hw, offset + DSC_PICTURE_SIZE, data); + + data = (dsc->slice_width & 0xffff) | + ((dsc->slice_height & 0xffff) << 16); + + DPU_REG_WRITE(hw, offset + DSC_SLICE_SIZE, data); + + DPU_REG_WRITE(hw, offset + DSC_MISC_SIZE, + (dsc->slice_chunk_size) & 0xffff); + + data = (dsc->initial_xmit_delay & 0xffff) | + ((dsc->initial_dec_delay & 0xffff) << 16); + + DPU_REG_WRITE(hw, offset + DSC_HRD_DELAYS, data); + + DPU_REG_WRITE(hw, offset + DSC_RC_SCALE, + dsc->initial_scale_value & 0x3f); + + data = (dsc->scale_increment_interval & 0xffff) | + ((dsc->scale_decrement_interval & 0x7ff) << 16); + + DPU_REG_WRITE(hw, offset + DSC_RC_SCALE_INC_DEC, data); + + data = (dsc->first_line_bpg_offset & 0x1f) | + ((dsc->second_line_bpg_offset & 0x1f) << 5); + + DPU_REG_WRITE(hw, offset + DSC_RC_OFFSETS_1, data); + + data = (dsc->nfl_bpg_offset & 0xffff) | + ((dsc->slice_bpg_offset & 0xffff) << 16); + + DPU_REG_WRITE(hw, offset + DSC_RC_OFFSETS_2, data); + + data = (dsc->initial_offset & 0xffff) | + ((dsc->final_offset & 0xffff) << 16); + + DPU_REG_WRITE(hw, offset + DSC_RC_OFFSETS_3, data); + + data = (dsc->nsl_bpg_offset & 0xffff) | + ((dsc->second_line_offset_adj & 0xffff) << 16); + + DPU_REG_WRITE(hw, offset + DSC_RC_OFFSETS_4, data); + + data = (dsc->flatness_min_qp & 0x1f); + data |= (dsc->flatness_max_qp & 0x1f) << 5; + + det_thresh_flatness = drm_dsc_calculate_flatness_det_thresh(dsc); + data |= (det_thresh_flatness & 0xff) << 10; + + DPU_REG_WRITE(hw, offset + DSC_FLATNESS_QP, data); + + DPU_REG_WRITE(hw, offset + DSC_RC_MODEL_SIZE, + (dsc->rc_model_size) & 0xffff); + + data = dsc->rc_edge_factor & 0xf; + data |= (dsc->rc_quant_incr_limit0 & 0x1f) << 8; + data |= (dsc->rc_quant_incr_limit1 & 0x1f) << 13; + data |= (dsc->rc_tgt_offset_high & 0xf) << 20; + data |= (dsc->rc_tgt_offset_low & 0xf) << 24; + + DPU_REG_WRITE(hw, offset + DSC_RC_CONFIG, data); + + /* program the dsc wrapper */ + _dsc_subblk_offset(hw_dsc, DPU_DSC_CTL, &offset); + + off = hw->blk_addr + offset; + + data = BIT(0); /* encoder enable */ + if (dsc->native_422) + data |= BIT(8); + else if (dsc->native_420) + data |= BIT(9); + if (!dsc->convert_rgb) + data |= BIT(10); + if (dsc->bits_per_component == 8) + data |= BIT(11); + if (mode & DSC_MODE_SPLIT_PANEL) + data |= BIT(12); + if (mode & DSC_MODE_MULTIPLEX) + data |= BIT(13); + if (!(mode & DSC_MODE_VIDEO)) + data |= BIT(17); + + DPU_REG_WRITE(hw, offset + DSC_CFG, data); +} + +static void dpu_hw_dsc_config_thresh_1_2(struct dpu_hw_dsc *hw_dsc, + struct drm_dsc_config *dsc) +{ + struct dpu_hw_blk_reg_map *hw; + u32 offset, off; + int i, j = 0; + struct drm_dsc_rc_range_parameters *rc; + u32 data = 0, min_qp = 0, max_qp = 0, bpg_off = 0; + + if (!hw_dsc || !dsc) + return; + + _dsc_subblk_offset(hw_dsc, DPU_DSC_ENC, &offset); + + hw = &hw_dsc->hw; + + rc = dsc->rc_range_params; + + off = 0; + for (i = 0; i < DSC_NUM_BUF_RANGES - 1; i++) { + data |= dsc->rc_buf_thresh[i] << (8 * j); + j++; + if ((j == 4) || (i == DSC_NUM_BUF_RANGES - 2)) { + DPU_REG_WRITE(hw, offset + DSC_RC_BUF_THRESH_0 + off, + data); + off += 4; + j = 0; + data = 0; + } + } + + off = 0; + for (i = 0; i < DSC_NUM_BUF_RANGES; i++) { + min_qp |= rc[i].range_min_qp << (5 * j); + max_qp |= rc[i].range_max_qp << (5 * j); + bpg_off |= rc[i].range_bpg_offset << (6 * j); + j++; + if (j == 5) { + DPU_REG_WRITE(hw, offset + DSC_RC_MIN_QP_0 + off, + min_qp); + DPU_REG_WRITE(hw, offset + DSC_RC_MAX_QP_0 + off, + max_qp); + DPU_REG_WRITE(hw, + offset + DSC_RC_RANGE_BPG_OFFSETS_0 + off, + bpg_off); + off += 4; + j = 0; + min_qp = 0; + max_qp = 0; + bpg_off = 0; + } + } +} + +static void dpu_hw_dsc_bind_pingpong_blk_1_2( + struct dpu_hw_dsc *hw_dsc, + bool enable, + const enum dpu_pingpong pp) +{ + struct dpu_hw_blk_reg_map *hw; + int offset; + int mux_cfg = 0xf; /* Disabled */ + + _dsc_subblk_offset(hw_dsc, DPU_DSC_CTL, &offset); + + hw = &hw_dsc->hw; + if (enable) + mux_cfg = (pp - PINGPONG_0) & 0x7; + + DPU_REG_WRITE(hw, offset + DSC_CTL, mux_cfg); +} + +static const struct dpu_dsc_cfg *_dsc_offset(enum dpu_dsc dsc, + const 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->blk_addr = addr + m->dsc[i].base; + b->log_mask = DPU_DBG_MASK_DSC; + return &m->dsc[i]; + } + } + + return NULL; +} + +static void _setup_dcs_ops_1_2(struct dpu_hw_dsc_ops *ops, + const unsigned long features) +{ + ops->dsc_disable = dpu_hw_dsc_disable_1_2; + ops->dsc_config = dpu_hw_dsc_config_1_2; + ops->dsc_config_thresh = dpu_hw_dsc_config_thresh_1_2; + ops->dsc_bind_pingpong_blk = dpu_hw_dsc_bind_pingpong_blk_1_2; +} + +struct dpu_hw_dsc *dpu_hw_dsc_init_1_2(enum dpu_dsc idx, void __iomem *addr, + const struct dpu_mdss_cfg *m) +{ + struct dpu_hw_dsc *c; + const 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_dcs_ops_1_2(&c->ops, c->caps->features); + + return c; +} diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c index f4dda88..f7014f5 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #define pr_fmt(fmt) "[drm:%s] " fmt, __func__ @@ -250,7 +251,11 @@ int dpu_rm_init(struct dpu_rm *rm, struct dpu_hw_dsc *hw; const struct dpu_dsc_cfg *dsc = &cat->dsc[i]; - hw = dpu_hw_dsc_init(dsc->id, mmio, cat); + if (test_bit(DPU_DSC_HW_REV_1_2, &dsc->features)) + hw = dpu_hw_dsc_init_1_2(dsc->id, mmio, cat); + else + hw = dpu_hw_dsc_init(dsc->id, mmio, cat); + if (IS_ERR_OR_NULL(hw)) { rc = PTR_ERR(hw); DPU_ERROR("failed dsc object creation: err %d\n", rc);
Add support for DSC 1.2 by providing the necessary hooks to program the DPU DSC 1.2 encoder. Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com> --- drivers/gpu/drm/msm/Makefile | 1 + drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h | 38 ++- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h | 17 +- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c | 388 +++++++++++++++++++++++++ drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c | 7 +- 5 files changed, 444 insertions(+), 7 deletions(-) create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c