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