xref: /openbmc/linux/drivers/gpu/drm/meson/meson_viu.c (revision 7b73a9c8)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (C) 2016 BayLibre, SAS
4  * Author: Neil Armstrong <narmstrong@baylibre.com>
5  * Copyright (C) 2015 Amlogic, Inc. All rights reserved.
6  * Copyright (C) 2014 Endless Mobile
7  */
8 
9 #include <linux/export.h>
10 
11 #include "meson_drv.h"
12 #include "meson_viu.h"
13 #include "meson_registers.h"
14 
15 /**
16  * DOC: Video Input Unit
17  *
18  * VIU Handles the Pixel scanout and the basic Colorspace conversions
19  * We handle the following features :
20  *
21  * - OSD1 RGB565/RGB888/xRGB8888 scanout
22  * - RGB conversion to x/cb/cr
23  * - Progressive or Interlace buffer scanout
24  * - OSD1 Commit on Vsync
25  * - HDR OSD matrix for GXL/GXM
26  *
27  * What is missing :
28  *
29  * - BGR888/xBGR8888/BGRx8888/BGRx8888 modes
30  * - YUV4:2:2 Y0CbY1Cr scanout
31  * - Conversion to YUV 4:4:4 from 4:2:2 input
32  * - Colorkey Alpha matching
33  * - Big endian scanout
34  * - X/Y reverse scanout
35  * - Global alpha setup
36  * - OSD2 support, would need interlace switching on vsync
37  * - OSD1 full scaling to support TV overscan
38  */
39 
40 /* OSD csc defines */
41 
42 enum viu_matrix_sel_e {
43 	VIU_MATRIX_OSD_EOTF = 0,
44 	VIU_MATRIX_OSD,
45 };
46 
47 enum viu_lut_sel_e {
48 	VIU_LUT_OSD_EOTF = 0,
49 	VIU_LUT_OSD_OETF,
50 };
51 
52 #define COEFF_NORM(a) ((int)((((a) * 2048.0) + 1) / 2))
53 #define MATRIX_5X3_COEF_SIZE 24
54 
55 #define EOTF_COEFF_NORM(a) ((int)((((a) * 4096.0) + 1) / 2))
56 #define EOTF_COEFF_SIZE 10
57 #define EOTF_COEFF_RIGHTSHIFT 1
58 
59 static int RGB709_to_YUV709l_coeff[MATRIX_5X3_COEF_SIZE] = {
60 	0, 0, 0, /* pre offset */
61 	COEFF_NORM(0.181873),	COEFF_NORM(0.611831),	COEFF_NORM(0.061765),
62 	COEFF_NORM(-0.100251),	COEFF_NORM(-0.337249),	COEFF_NORM(0.437500),
63 	COEFF_NORM(0.437500),	COEFF_NORM(-0.397384),	COEFF_NORM(-0.040116),
64 	0, 0, 0, /* 10'/11'/12' */
65 	0, 0, 0, /* 20'/21'/22' */
66 	64, 512, 512, /* offset */
67 	0, 0, 0 /* mode, right_shift, clip_en */
68 };
69 
70 /*  eotf matrix: bypass */
71 static int eotf_bypass_coeff[EOTF_COEFF_SIZE] = {
72 	EOTF_COEFF_NORM(1.0),	EOTF_COEFF_NORM(0.0),	EOTF_COEFF_NORM(0.0),
73 	EOTF_COEFF_NORM(0.0),	EOTF_COEFF_NORM(1.0),	EOTF_COEFF_NORM(0.0),
74 	EOTF_COEFF_NORM(0.0),	EOTF_COEFF_NORM(0.0),	EOTF_COEFF_NORM(1.0),
75 	EOTF_COEFF_RIGHTSHIFT /* right shift */
76 };
77 
78 static void meson_viu_set_g12a_osd1_matrix(struct meson_drm *priv,
79 					   int *m, bool csc_on)
80 {
81 	/* VPP WRAP OSD1 matrix */
82 	writel(((m[0] & 0xfff) << 16) | (m[1] & 0xfff),
83 		priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_PRE_OFFSET0_1));
84 	writel(m[2] & 0xfff,
85 		priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_PRE_OFFSET2));
86 	writel(((m[3] & 0x1fff) << 16) | (m[4] & 0x1fff),
87 		priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_COEF00_01));
88 	writel(((m[5] & 0x1fff) << 16) | (m[6] & 0x1fff),
89 		priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_COEF02_10));
90 	writel(((m[7] & 0x1fff) << 16) | (m[8] & 0x1fff),
91 		priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_COEF11_12));
92 	writel(((m[9] & 0x1fff) << 16) | (m[10] & 0x1fff),
93 		priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_COEF20_21));
94 	writel((m[11] & 0x1fff) << 16,
95 		priv->io_base +	_REG(VPP_WRAP_OSD1_MATRIX_COEF22));
96 
97 	writel(((m[18] & 0xfff) << 16) | (m[19] & 0xfff),
98 		priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_OFFSET0_1));
99 	writel(m[20] & 0xfff,
100 		priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_OFFSET2));
101 
102 	writel_bits_relaxed(BIT(0), csc_on ? BIT(0) : 0,
103 		priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_EN_CTRL));
104 }
105 
106 static void meson_viu_set_osd_matrix(struct meson_drm *priv,
107 				     enum viu_matrix_sel_e m_select,
108 			      int *m, bool csc_on)
109 {
110 	if (m_select == VIU_MATRIX_OSD) {
111 		/* osd matrix, VIU_MATRIX_0 */
112 		writel(((m[0] & 0xfff) << 16) | (m[1] & 0xfff),
113 			priv->io_base + _REG(VIU_OSD1_MATRIX_PRE_OFFSET0_1));
114 		writel(m[2] & 0xfff,
115 			priv->io_base + _REG(VIU_OSD1_MATRIX_PRE_OFFSET2));
116 		writel(((m[3] & 0x1fff) << 16) | (m[4] & 0x1fff),
117 			priv->io_base + _REG(VIU_OSD1_MATRIX_COEF00_01));
118 		writel(((m[5] & 0x1fff) << 16) | (m[6] & 0x1fff),
119 			priv->io_base + _REG(VIU_OSD1_MATRIX_COEF02_10));
120 		writel(((m[7] & 0x1fff) << 16) | (m[8] & 0x1fff),
121 			priv->io_base + _REG(VIU_OSD1_MATRIX_COEF11_12));
122 		writel(((m[9] & 0x1fff) << 16) | (m[10] & 0x1fff),
123 			priv->io_base + _REG(VIU_OSD1_MATRIX_COEF20_21));
124 
125 		if (m[21]) {
126 			writel(((m[11] & 0x1fff) << 16) | (m[12] & 0x1fff),
127 				priv->io_base +
128 					_REG(VIU_OSD1_MATRIX_COEF22_30));
129 			writel(((m[13] & 0x1fff) << 16) | (m[14] & 0x1fff),
130 				priv->io_base +
131 					_REG(VIU_OSD1_MATRIX_COEF31_32));
132 			writel(((m[15] & 0x1fff) << 16) | (m[16] & 0x1fff),
133 				priv->io_base +
134 					_REG(VIU_OSD1_MATRIX_COEF40_41));
135 			writel(m[17] & 0x1fff, priv->io_base +
136 				_REG(VIU_OSD1_MATRIX_COLMOD_COEF42));
137 		} else
138 			writel((m[11] & 0x1fff) << 16, priv->io_base +
139 				_REG(VIU_OSD1_MATRIX_COEF22_30));
140 
141 		writel(((m[18] & 0xfff) << 16) | (m[19] & 0xfff),
142 			priv->io_base + _REG(VIU_OSD1_MATRIX_OFFSET0_1));
143 		writel(m[20] & 0xfff,
144 			priv->io_base + _REG(VIU_OSD1_MATRIX_OFFSET2));
145 
146 		writel_bits_relaxed(3 << 30, m[21] << 30,
147 			priv->io_base + _REG(VIU_OSD1_MATRIX_COLMOD_COEF42));
148 		writel_bits_relaxed(7 << 16, m[22] << 16,
149 			priv->io_base + _REG(VIU_OSD1_MATRIX_COLMOD_COEF42));
150 
151 		/* 23 reserved for clipping control */
152 		writel_bits_relaxed(BIT(0), csc_on ? BIT(0) : 0,
153 			priv->io_base + _REG(VIU_OSD1_MATRIX_CTRL));
154 		writel_bits_relaxed(BIT(1), 0,
155 			priv->io_base + _REG(VIU_OSD1_MATRIX_CTRL));
156 	} else if (m_select == VIU_MATRIX_OSD_EOTF) {
157 		int i;
158 
159 		/* osd eotf matrix, VIU_MATRIX_OSD_EOTF */
160 		for (i = 0; i < 5; i++)
161 			writel(((m[i * 2] & 0x1fff) << 16) |
162 				(m[i * 2 + 1] & 0x1fff), priv->io_base +
163 				_REG(VIU_OSD1_EOTF_CTL + i + 1));
164 
165 		writel_bits_relaxed(BIT(30), csc_on ? BIT(30) : 0,
166 			priv->io_base + _REG(VIU_OSD1_EOTF_CTL));
167 		writel_bits_relaxed(BIT(31), csc_on ? BIT(31) : 0,
168 			priv->io_base + _REG(VIU_OSD1_EOTF_CTL));
169 	}
170 }
171 
172 #define OSD_EOTF_LUT_SIZE 33
173 #define OSD_OETF_LUT_SIZE 41
174 
175 static void
176 meson_viu_set_osd_lut(struct meson_drm *priv, enum viu_lut_sel_e lut_sel,
177 		      unsigned int *r_map, unsigned int *g_map,
178 		      unsigned int *b_map, bool csc_on)
179 {
180 	unsigned int addr_port;
181 	unsigned int data_port;
182 	unsigned int ctrl_port;
183 	int i;
184 
185 	if (lut_sel == VIU_LUT_OSD_EOTF) {
186 		addr_port = VIU_OSD1_EOTF_LUT_ADDR_PORT;
187 		data_port = VIU_OSD1_EOTF_LUT_DATA_PORT;
188 		ctrl_port = VIU_OSD1_EOTF_CTL;
189 	} else if (lut_sel == VIU_LUT_OSD_OETF) {
190 		addr_port = VIU_OSD1_OETF_LUT_ADDR_PORT;
191 		data_port = VIU_OSD1_OETF_LUT_DATA_PORT;
192 		ctrl_port = VIU_OSD1_OETF_CTL;
193 	} else
194 		return;
195 
196 	if (lut_sel == VIU_LUT_OSD_OETF) {
197 		writel(0, priv->io_base + _REG(addr_port));
198 
199 		for (i = 0; i < (OSD_OETF_LUT_SIZE / 2); i++)
200 			writel(r_map[i * 2] | (r_map[i * 2 + 1] << 16),
201 				priv->io_base + _REG(data_port));
202 
203 		writel(r_map[OSD_OETF_LUT_SIZE - 1] | (g_map[0] << 16),
204 			priv->io_base + _REG(data_port));
205 
206 		for (i = 0; i < (OSD_OETF_LUT_SIZE / 2); i++)
207 			writel(g_map[i * 2 + 1] | (g_map[i * 2 + 2] << 16),
208 				priv->io_base + _REG(data_port));
209 
210 		for (i = 0; i < (OSD_OETF_LUT_SIZE / 2); i++)
211 			writel(b_map[i * 2] | (b_map[i * 2 + 1] << 16),
212 				priv->io_base + _REG(data_port));
213 
214 		writel(b_map[OSD_OETF_LUT_SIZE - 1],
215 			priv->io_base + _REG(data_port));
216 
217 		if (csc_on)
218 			writel_bits_relaxed(0x7 << 29, 7 << 29,
219 					    priv->io_base + _REG(ctrl_port));
220 		else
221 			writel_bits_relaxed(0x7 << 29, 0,
222 					    priv->io_base + _REG(ctrl_port));
223 	} else if (lut_sel == VIU_LUT_OSD_EOTF) {
224 		writel(0, priv->io_base + _REG(addr_port));
225 
226 		for (i = 0; i < (OSD_EOTF_LUT_SIZE / 2); i++)
227 			writel(r_map[i * 2] | (r_map[i * 2 + 1] << 16),
228 				priv->io_base + _REG(data_port));
229 
230 		writel(r_map[OSD_EOTF_LUT_SIZE - 1] | (g_map[0] << 16),
231 			priv->io_base + _REG(data_port));
232 
233 		for (i = 0; i < (OSD_EOTF_LUT_SIZE / 2); i++)
234 			writel(g_map[i * 2 + 1] | (g_map[i * 2 + 2] << 16),
235 				priv->io_base + _REG(data_port));
236 
237 		for (i = 0; i < (OSD_EOTF_LUT_SIZE / 2); i++)
238 			writel(b_map[i * 2] | (b_map[i * 2 + 1] << 16),
239 				priv->io_base + _REG(data_port));
240 
241 		writel(b_map[OSD_EOTF_LUT_SIZE - 1],
242 			priv->io_base + _REG(data_port));
243 
244 		if (csc_on)
245 			writel_bits_relaxed(7 << 27, 7 << 27,
246 					    priv->io_base + _REG(ctrl_port));
247 		else
248 			writel_bits_relaxed(7 << 27, 0,
249 					    priv->io_base + _REG(ctrl_port));
250 
251 		writel_bits_relaxed(BIT(31), BIT(31),
252 				    priv->io_base + _REG(ctrl_port));
253 	}
254 }
255 
256 /* eotf lut: linear */
257 static unsigned int eotf_33_linear_mapping[OSD_EOTF_LUT_SIZE] = {
258 	0x0000,	0x0200,	0x0400, 0x0600,
259 	0x0800, 0x0a00, 0x0c00, 0x0e00,
260 	0x1000, 0x1200, 0x1400, 0x1600,
261 	0x1800, 0x1a00, 0x1c00, 0x1e00,
262 	0x2000, 0x2200, 0x2400, 0x2600,
263 	0x2800, 0x2a00, 0x2c00, 0x2e00,
264 	0x3000, 0x3200, 0x3400, 0x3600,
265 	0x3800, 0x3a00, 0x3c00, 0x3e00,
266 	0x4000
267 };
268 
269 /* osd oetf lut: linear */
270 static unsigned int oetf_41_linear_mapping[OSD_OETF_LUT_SIZE] = {
271 	0, 0, 0, 0,
272 	0, 32, 64, 96,
273 	128, 160, 196, 224,
274 	256, 288, 320, 352,
275 	384, 416, 448, 480,
276 	512, 544, 576, 608,
277 	640, 672, 704, 736,
278 	768, 800, 832, 864,
279 	896, 928, 960, 992,
280 	1023, 1023, 1023, 1023,
281 	1023
282 };
283 
284 static void meson_viu_load_matrix(struct meson_drm *priv)
285 {
286 	/* eotf lut bypass */
287 	meson_viu_set_osd_lut(priv, VIU_LUT_OSD_EOTF,
288 			      eotf_33_linear_mapping, /* R */
289 			      eotf_33_linear_mapping, /* G */
290 			      eotf_33_linear_mapping, /* B */
291 			      false);
292 
293 	/* eotf matrix bypass */
294 	meson_viu_set_osd_matrix(priv, VIU_MATRIX_OSD_EOTF,
295 				 eotf_bypass_coeff,
296 				 false);
297 
298 	/* oetf lut bypass */
299 	meson_viu_set_osd_lut(priv, VIU_LUT_OSD_OETF,
300 			      oetf_41_linear_mapping, /* R */
301 			      oetf_41_linear_mapping, /* G */
302 			      oetf_41_linear_mapping, /* B */
303 			      false);
304 
305 	/* osd matrix RGB709 to YUV709 limit */
306 	meson_viu_set_osd_matrix(priv, VIU_MATRIX_OSD,
307 				 RGB709_to_YUV709l_coeff,
308 				 true);
309 }
310 
311 /* VIU OSD1 Reset as workaround for GXL+ Alpha OSD Bug */
312 void meson_viu_osd1_reset(struct meson_drm *priv)
313 {
314 	uint32_t osd1_fifo_ctrl_stat, osd1_ctrl_stat2;
315 
316 	/* Save these 2 registers state */
317 	osd1_fifo_ctrl_stat = readl_relaxed(
318 				priv->io_base + _REG(VIU_OSD1_FIFO_CTRL_STAT));
319 	osd1_ctrl_stat2 = readl_relaxed(
320 				priv->io_base + _REG(VIU_OSD1_CTRL_STAT2));
321 
322 	/* Reset OSD1 */
323 	writel_bits_relaxed(VIU_SW_RESET_OSD1, VIU_SW_RESET_OSD1,
324 			    priv->io_base + _REG(VIU_SW_RESET));
325 	writel_bits_relaxed(VIU_SW_RESET_OSD1, 0,
326 			    priv->io_base + _REG(VIU_SW_RESET));
327 
328 	/* Rewrite these registers state lost in the reset */
329 	writel_relaxed(osd1_fifo_ctrl_stat,
330 		       priv->io_base + _REG(VIU_OSD1_FIFO_CTRL_STAT));
331 	writel_relaxed(osd1_ctrl_stat2,
332 		       priv->io_base + _REG(VIU_OSD1_CTRL_STAT2));
333 
334 	/* Reload the conversion matrix */
335 	meson_viu_load_matrix(priv);
336 }
337 
338 static inline uint32_t meson_viu_osd_burst_length_reg(uint32_t length)
339 {
340 	uint32_t val = (((length & 0x80) % 24) / 12);
341 
342 	return (((val & 0x3) << 10) | (((val & 0x4) >> 2) << 31));
343 }
344 
345 void meson_viu_init(struct meson_drm *priv)
346 {
347 	uint32_t reg;
348 
349 	/* Disable OSDs */
350 	writel_bits_relaxed(VIU_OSD1_OSD_BLK_ENABLE | VIU_OSD1_OSD_ENABLE, 0,
351 			    priv->io_base + _REG(VIU_OSD1_CTRL_STAT));
352 	writel_bits_relaxed(VIU_OSD1_OSD_BLK_ENABLE | VIU_OSD1_OSD_ENABLE, 0,
353 			    priv->io_base + _REG(VIU_OSD2_CTRL_STAT));
354 
355 	/* On GXL/GXM, Use the 10bit HDR conversion matrix */
356 	if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) ||
357 	    meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXL))
358 		meson_viu_load_matrix(priv);
359 	else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A))
360 		meson_viu_set_g12a_osd1_matrix(priv, RGB709_to_YUV709l_coeff,
361 					       true);
362 
363 	/* Initialize OSD1 fifo control register */
364 	reg = VIU_OSD_DDR_PRIORITY_URGENT |
365 		VIU_OSD_HOLD_FIFO_LINES(4) |
366 		VIU_OSD_FIFO_DEPTH_VAL(32) | /* fifo_depth_val: 32*8=256 */
367 		VIU_OSD_WORDS_PER_BURST(4) | /* 4 words in 1 burst */
368 		VIU_OSD_FIFO_LIMITS(2);      /* fifo_lim: 2*16=32 */
369 
370 	if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A))
371 		reg |= meson_viu_osd_burst_length_reg(32);
372 	else
373 		reg |= meson_viu_osd_burst_length_reg(64);
374 
375 	writel_relaxed(reg, priv->io_base + _REG(VIU_OSD1_FIFO_CTRL_STAT));
376 	writel_relaxed(reg, priv->io_base + _REG(VIU_OSD2_FIFO_CTRL_STAT));
377 
378 	/* Set OSD alpha replace value */
379 	writel_bits_relaxed(0xff << OSD_REPLACE_SHIFT,
380 			    0xff << OSD_REPLACE_SHIFT,
381 			    priv->io_base + _REG(VIU_OSD1_CTRL_STAT2));
382 	writel_bits_relaxed(0xff << OSD_REPLACE_SHIFT,
383 			    0xff << OSD_REPLACE_SHIFT,
384 			    priv->io_base + _REG(VIU_OSD2_CTRL_STAT2));
385 
386 	/* Disable VD1 AFBC */
387 	/* di_mif0_en=0 mif0_to_vpp_en=0 di_mad_en=0 and afbc vd1 set=0*/
388 	writel_bits_relaxed(VIU_CTRL0_VD1_AFBC_MASK, 0,
389 			    priv->io_base + _REG(VIU_MISC_CTRL0));
390 	writel_relaxed(0, priv->io_base + _REG(AFBC_ENABLE));
391 
392 	writel_relaxed(0x00FF00C0,
393 			priv->io_base + _REG(VD1_IF0_LUMA_FIFO_SIZE));
394 	writel_relaxed(0x00FF00C0,
395 			priv->io_base + _REG(VD2_IF0_LUMA_FIFO_SIZE));
396 
397 	if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) {
398 		writel_relaxed(VIU_OSD_BLEND_REORDER(0, 1) |
399 			       VIU_OSD_BLEND_REORDER(1, 0) |
400 			       VIU_OSD_BLEND_REORDER(2, 0) |
401 			       VIU_OSD_BLEND_REORDER(3, 0) |
402 			       VIU_OSD_BLEND_DIN_EN(1) |
403 			       VIU_OSD_BLEND1_DIN3_BYPASS_TO_DOUT1 |
404 			       VIU_OSD_BLEND1_DOUT_BYPASS_TO_BLEND2 |
405 			       VIU_OSD_BLEND_DIN0_BYPASS_TO_DOUT0 |
406 			       VIU_OSD_BLEND_BLEN2_PREMULT_EN(1) |
407 			       VIU_OSD_BLEND_HOLD_LINES(4),
408 			       priv->io_base + _REG(VIU_OSD_BLEND_CTRL));
409 
410 		writel_relaxed(OSD_BLEND_PATH_SEL_ENABLE,
411 			       priv->io_base + _REG(OSD1_BLEND_SRC_CTRL));
412 		writel_relaxed(OSD_BLEND_PATH_SEL_ENABLE,
413 			       priv->io_base + _REG(OSD2_BLEND_SRC_CTRL));
414 		writel_relaxed(0, priv->io_base + _REG(VD1_BLEND_SRC_CTRL));
415 		writel_relaxed(0, priv->io_base + _REG(VD2_BLEND_SRC_CTRL));
416 		writel_relaxed(0,
417 				priv->io_base + _REG(VIU_OSD_BLEND_DUMMY_DATA0));
418 		writel_relaxed(0,
419 				priv->io_base + _REG(VIU_OSD_BLEND_DUMMY_ALPHA));
420 
421 		writel_bits_relaxed(DOLBY_BYPASS_EN(0xc), DOLBY_BYPASS_EN(0xc),
422 				    priv->io_base + _REG(DOLBY_PATH_CTRL));
423 	}
424 
425 	priv->viu.osd1_enabled = false;
426 	priv->viu.osd1_commit = false;
427 	priv->viu.osd1_interlace = false;
428 }
429