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