|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
| 2 | +/* |
| 3 | + * Copyright (c) 2020-2022, Linaro Limited |
| 4 | + */ |
| 5 | + |
| 6 | +#include "dpu_kms.h" |
| 7 | +#include "dpu_hw_catalog.h" |
| 8 | +#include "dpu_hwio.h" |
| 9 | +#include "dpu_hw_mdss.h" |
| 10 | +#include "dpu_hw_dsc.h" |
| 11 | + |
| 12 | +#define DSC_COMMON_MODE 0x000 |
| 13 | +#define DSC_ENC 0x004 |
| 14 | +#define DSC_PICTURE 0x008 |
| 15 | +#define DSC_SLICE 0x00C |
| 16 | +#define DSC_CHUNK_SIZE 0x010 |
| 17 | +#define DSC_DELAY 0x014 |
| 18 | +#define DSC_SCALE_INITIAL 0x018 |
| 19 | +#define DSC_SCALE_DEC_INTERVAL 0x01C |
| 20 | +#define DSC_SCALE_INC_INTERVAL 0x020 |
| 21 | +#define DSC_FIRST_LINE_BPG_OFFSET 0x024 |
| 22 | +#define DSC_BPG_OFFSET 0x028 |
| 23 | +#define DSC_DSC_OFFSET 0x02C |
| 24 | +#define DSC_FLATNESS 0x030 |
| 25 | +#define DSC_RC_MODEL_SIZE 0x034 |
| 26 | +#define DSC_RC 0x038 |
| 27 | +#define DSC_RC_BUF_THRESH 0x03C |
| 28 | +#define DSC_RANGE_MIN_QP 0x074 |
| 29 | +#define DSC_RANGE_MAX_QP 0x0B0 |
| 30 | +#define DSC_RANGE_BPG_OFFSET 0x0EC |
| 31 | + |
| 32 | +static void dpu_hw_dsc_disable(struct dpu_hw_dsc *dsc) |
| 33 | +{ |
| 34 | + struct dpu_hw_blk_reg_map *c = &dsc->hw; |
| 35 | + |
| 36 | + DPU_REG_WRITE(c, DSC_COMMON_MODE, 0); |
| 37 | +} |
| 38 | + |
| 39 | +static void dpu_hw_dsc_config(struct dpu_hw_dsc *hw_dsc, |
| 40 | + struct msm_display_dsc_config *dsc, |
| 41 | + u32 mode, |
| 42 | + u32 initial_lines) |
| 43 | +{ |
| 44 | + struct dpu_hw_blk_reg_map *c = &hw_dsc->hw; |
| 45 | + u32 data, lsb, bpp; |
| 46 | + u32 slice_last_group_size; |
| 47 | + u32 det_thresh_flatness; |
| 48 | + bool is_cmd_mode = !(mode & DSC_MODE_VIDEO); |
| 49 | + |
| 50 | + DPU_REG_WRITE(c, DSC_COMMON_MODE, mode); |
| 51 | + |
| 52 | + if (is_cmd_mode) |
| 53 | + initial_lines += 1; |
| 54 | + |
| 55 | + slice_last_group_size = 3 - (dsc->drm->slice_width % 3); |
| 56 | + data = (initial_lines << 20); |
| 57 | + data |= ((slice_last_group_size - 1) << 18); |
| 58 | + /* bpp is 6.4 format, 4 LSBs bits are for fractional part */ |
| 59 | + data |= dsc->drm->bits_per_pixel << 12; |
| 60 | + lsb = dsc->drm->bits_per_pixel % 4; |
| 61 | + bpp = dsc->drm->bits_per_pixel / 4; |
| 62 | + bpp *= 4; |
| 63 | + bpp <<= 4; |
| 64 | + bpp |= lsb; |
| 65 | + |
| 66 | + data |= bpp << 8; |
| 67 | + data |= (dsc->drm->block_pred_enable << 7); |
| 68 | + data |= (dsc->drm->line_buf_depth << 3); |
| 69 | + data |= (dsc->drm->simple_422 << 2); |
| 70 | + data |= (dsc->drm->convert_rgb << 1); |
| 71 | + data |= dsc->drm->bits_per_component; |
| 72 | + |
| 73 | + DPU_REG_WRITE(c, DSC_ENC, data); |
| 74 | + |
| 75 | + data = dsc->drm->pic_width << 16; |
| 76 | + data |= dsc->drm->pic_height; |
| 77 | + DPU_REG_WRITE(c, DSC_PICTURE, data); |
| 78 | + |
| 79 | + data = dsc->drm->slice_width << 16; |
| 80 | + data |= dsc->drm->slice_height; |
| 81 | + DPU_REG_WRITE(c, DSC_SLICE, data); |
| 82 | + |
| 83 | + data = dsc->drm->slice_chunk_size << 16; |
| 84 | + DPU_REG_WRITE(c, DSC_CHUNK_SIZE, data); |
| 85 | + |
| 86 | + data = dsc->drm->initial_dec_delay << 16; |
| 87 | + data |= dsc->drm->initial_xmit_delay; |
| 88 | + DPU_REG_WRITE(c, DSC_DELAY, data); |
| 89 | + |
| 90 | + data = dsc->drm->initial_scale_value; |
| 91 | + DPU_REG_WRITE(c, DSC_SCALE_INITIAL, data); |
| 92 | + |
| 93 | + data = dsc->drm->scale_decrement_interval; |
| 94 | + DPU_REG_WRITE(c, DSC_SCALE_DEC_INTERVAL, data); |
| 95 | + |
| 96 | + data = dsc->drm->scale_increment_interval; |
| 97 | + DPU_REG_WRITE(c, DSC_SCALE_INC_INTERVAL, data); |
| 98 | + |
| 99 | + data = dsc->drm->first_line_bpg_offset; |
| 100 | + DPU_REG_WRITE(c, DSC_FIRST_LINE_BPG_OFFSET, data); |
| 101 | + |
| 102 | + data = dsc->drm->nfl_bpg_offset << 16; |
| 103 | + data |= dsc->drm->slice_bpg_offset; |
| 104 | + DPU_REG_WRITE(c, DSC_BPG_OFFSET, data); |
| 105 | + |
| 106 | + data = dsc->drm->initial_offset << 16; |
| 107 | + data |= dsc->drm->final_offset; |
| 108 | + DPU_REG_WRITE(c, DSC_DSC_OFFSET, data); |
| 109 | + |
| 110 | + det_thresh_flatness = 7 + 2 * (dsc->drm->bits_per_component - 8); |
| 111 | + data = det_thresh_flatness << 10; |
| 112 | + data |= dsc->drm->flatness_max_qp << 5; |
| 113 | + data |= dsc->drm->flatness_min_qp; |
| 114 | + DPU_REG_WRITE(c, DSC_FLATNESS, data); |
| 115 | + |
| 116 | + data = dsc->drm->rc_model_size; |
| 117 | + DPU_REG_WRITE(c, DSC_RC_MODEL_SIZE, data); |
| 118 | + |
| 119 | + data = dsc->drm->rc_tgt_offset_low << 18; |
| 120 | + data |= dsc->drm->rc_tgt_offset_high << 14; |
| 121 | + data |= dsc->drm->rc_quant_incr_limit1 << 9; |
| 122 | + data |= dsc->drm->rc_quant_incr_limit0 << 4; |
| 123 | + data |= dsc->drm->rc_edge_factor; |
| 124 | + DPU_REG_WRITE(c, DSC_RC, data); |
| 125 | +} |
| 126 | + |
| 127 | +static void dpu_hw_dsc_config_thresh(struct dpu_hw_dsc *hw_dsc, |
| 128 | + struct msm_display_dsc_config *dsc) |
| 129 | +{ |
| 130 | + struct drm_dsc_rc_range_parameters *rc = dsc->drm->rc_range_params; |
| 131 | + struct dpu_hw_blk_reg_map *c = &hw_dsc->hw; |
| 132 | + u32 off; |
| 133 | + int i; |
| 134 | + |
| 135 | + off = DSC_RC_BUF_THRESH; |
| 136 | + for (i = 0; i < DSC_NUM_BUF_RANGES - 1 ; i++) { |
| 137 | + DPU_REG_WRITE(c, off, dsc->drm->rc_buf_thresh[i]); |
| 138 | + off += 4; |
| 139 | + } |
| 140 | + |
| 141 | + off = DSC_RANGE_MIN_QP; |
| 142 | + for (i = 0; i < DSC_NUM_BUF_RANGES; i++) { |
| 143 | + DPU_REG_WRITE(c, off, rc[i].range_min_qp); |
| 144 | + off += 4; |
| 145 | + } |
| 146 | + |
| 147 | + off = DSC_RANGE_MAX_QP; |
| 148 | + for (i = 0; i < 15; i++) { |
| 149 | + DPU_REG_WRITE(c, off, rc[i].range_max_qp); |
| 150 | + off += 4; |
| 151 | + } |
| 152 | + |
| 153 | + off = DSC_RANGE_BPG_OFFSET; |
| 154 | + for (i = 0; i < 15; i++) { |
| 155 | + DPU_REG_WRITE(c, off, rc[i].range_bpg_offset); |
| 156 | + off += 4; |
| 157 | + } |
| 158 | +} |
| 159 | + |
| 160 | +static struct dpu_dsc_cfg *_dsc_offset(enum dpu_dsc dsc, |
| 161 | + struct dpu_mdss_cfg *m, |
| 162 | + void __iomem *addr, |
| 163 | + struct dpu_hw_blk_reg_map *b) |
| 164 | +{ |
| 165 | + int i; |
| 166 | + |
| 167 | + for (i = 0; i < m->dsc_count; i++) { |
| 168 | + if (dsc == m->dsc[i].id) { |
| 169 | + b->base_off = addr; |
| 170 | + b->blk_off = m->dsc[i].base; |
| 171 | + b->length = m->dsc[i].len; |
| 172 | + b->hwversion = m->hwversion; |
| 173 | + b->log_mask = DPU_DBG_MASK_DSC; |
| 174 | + return &m->dsc[i]; |
| 175 | + } |
| 176 | + } |
| 177 | + |
| 178 | + return NULL; |
| 179 | +} |
| 180 | + |
| 181 | +static void _setup_dsc_ops(struct dpu_hw_dsc_ops *ops, |
| 182 | + unsigned long cap) |
| 183 | +{ |
| 184 | + ops->dsc_disable = dpu_hw_dsc_disable; |
| 185 | + ops->dsc_config = dpu_hw_dsc_config; |
| 186 | + ops->dsc_config_thresh = dpu_hw_dsc_config_thresh; |
| 187 | +}; |
| 188 | + |
| 189 | +struct dpu_hw_dsc *dpu_hw_dsc_init(enum dpu_dsc idx, void __iomem *addr, |
| 190 | + struct dpu_mdss_cfg *m) |
| 191 | +{ |
| 192 | + struct dpu_hw_dsc *c; |
| 193 | + struct dpu_dsc_cfg *cfg; |
| 194 | + |
| 195 | + c = kzalloc(sizeof(*c), GFP_KERNEL); |
| 196 | + if (!c) |
| 197 | + return ERR_PTR(-ENOMEM); |
| 198 | + |
| 199 | + cfg = _dsc_offset(idx, m, addr, &c->hw); |
| 200 | + if (IS_ERR_OR_NULL(cfg)) { |
| 201 | + kfree(c); |
| 202 | + return ERR_PTR(-EINVAL); |
| 203 | + } |
| 204 | + |
| 205 | + c->idx = idx; |
| 206 | + c->caps = cfg; |
| 207 | + _setup_dsc_ops(&c->ops, c->caps->features); |
| 208 | + |
| 209 | + return c; |
| 210 | +} |
| 211 | + |
| 212 | +void dpu_hw_dsc_destroy(struct dpu_hw_dsc *dsc) |
| 213 | +{ |
| 214 | + kfree(dsc); |
| 215 | +} |
0 commit comments