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