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