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