xref: /openbmc/linux/drivers/gpu/drm/meson/meson_viu.c (revision d2574c33)
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 void meson_viu_set_osd_matrix(struct meson_drm *priv,
94 			      enum viu_matrix_sel_e m_select,
95 			      int *m, bool csc_on)
96 {
97 	if (m_select == VIU_MATRIX_OSD) {
98 		/* osd matrix, VIU_MATRIX_0 */
99 		writel(((m[0] & 0xfff) << 16) | (m[1] & 0xfff),
100 			priv->io_base + _REG(VIU_OSD1_MATRIX_PRE_OFFSET0_1));
101 		writel(m[2] & 0xfff,
102 			priv->io_base + _REG(VIU_OSD1_MATRIX_PRE_OFFSET2));
103 		writel(((m[3] & 0x1fff) << 16) | (m[4] & 0x1fff),
104 			priv->io_base + _REG(VIU_OSD1_MATRIX_COEF00_01));
105 		writel(((m[5] & 0x1fff) << 16) | (m[6] & 0x1fff),
106 			priv->io_base + _REG(VIU_OSD1_MATRIX_COEF02_10));
107 		writel(((m[7] & 0x1fff) << 16) | (m[8] & 0x1fff),
108 			priv->io_base + _REG(VIU_OSD1_MATRIX_COEF11_12));
109 		writel(((m[9] & 0x1fff) << 16) | (m[10] & 0x1fff),
110 			priv->io_base + _REG(VIU_OSD1_MATRIX_COEF20_21));
111 
112 		if (m[21]) {
113 			writel(((m[11] & 0x1fff) << 16) | (m[12] & 0x1fff),
114 				priv->io_base +
115 					_REG(VIU_OSD1_MATRIX_COEF22_30));
116 			writel(((m[13] & 0x1fff) << 16) | (m[14] & 0x1fff),
117 				priv->io_base +
118 					_REG(VIU_OSD1_MATRIX_COEF31_32));
119 			writel(((m[15] & 0x1fff) << 16) | (m[16] & 0x1fff),
120 				priv->io_base +
121 					_REG(VIU_OSD1_MATRIX_COEF40_41));
122 			writel(m[17] & 0x1fff, priv->io_base +
123 				_REG(VIU_OSD1_MATRIX_COLMOD_COEF42));
124 		} else
125 			writel((m[11] & 0x1fff) << 16, priv->io_base +
126 				_REG(VIU_OSD1_MATRIX_COEF22_30));
127 
128 		writel(((m[18] & 0xfff) << 16) | (m[19] & 0xfff),
129 			priv->io_base + _REG(VIU_OSD1_MATRIX_OFFSET0_1));
130 		writel(m[20] & 0xfff,
131 			priv->io_base + _REG(VIU_OSD1_MATRIX_OFFSET2));
132 
133 		writel_bits_relaxed(3 << 30, m[21] << 30,
134 			priv->io_base + _REG(VIU_OSD1_MATRIX_COLMOD_COEF42));
135 		writel_bits_relaxed(7 << 16, m[22] << 16,
136 			priv->io_base + _REG(VIU_OSD1_MATRIX_COLMOD_COEF42));
137 
138 		/* 23 reserved for clipping control */
139 		writel_bits_relaxed(BIT(0), csc_on ? BIT(0) : 0,
140 			priv->io_base + _REG(VIU_OSD1_MATRIX_CTRL));
141 		writel_bits_relaxed(BIT(1), 0,
142 			priv->io_base + _REG(VIU_OSD1_MATRIX_CTRL));
143 	} else if (m_select == VIU_MATRIX_OSD_EOTF) {
144 		int i;
145 
146 		/* osd eotf matrix, VIU_MATRIX_OSD_EOTF */
147 		for (i = 0; i < 5; i++)
148 			writel(((m[i * 2] & 0x1fff) << 16) |
149 				(m[i * 2 + 1] & 0x1fff), priv->io_base +
150 				_REG(VIU_OSD1_EOTF_CTL + i + 1));
151 
152 		writel_bits_relaxed(BIT(30), csc_on ? BIT(30) : 0,
153 			priv->io_base + _REG(VIU_OSD1_EOTF_CTL));
154 		writel_bits_relaxed(BIT(31), csc_on ? BIT(31) : 0,
155 			priv->io_base + _REG(VIU_OSD1_EOTF_CTL));
156 	}
157 }
158 
159 #define OSD_EOTF_LUT_SIZE 33
160 #define OSD_OETF_LUT_SIZE 41
161 
162 void meson_viu_set_osd_lut(struct meson_drm *priv, enum viu_lut_sel_e lut_sel,
163 			   unsigned int *r_map, unsigned int *g_map,
164 			   unsigned int *b_map,
165 			   bool csc_on)
166 {
167 	unsigned int addr_port;
168 	unsigned int data_port;
169 	unsigned int ctrl_port;
170 	int i;
171 
172 	if (lut_sel == VIU_LUT_OSD_EOTF) {
173 		addr_port = VIU_OSD1_EOTF_LUT_ADDR_PORT;
174 		data_port = VIU_OSD1_EOTF_LUT_DATA_PORT;
175 		ctrl_port = VIU_OSD1_EOTF_CTL;
176 	} else if (lut_sel == VIU_LUT_OSD_OETF) {
177 		addr_port = VIU_OSD1_OETF_LUT_ADDR_PORT;
178 		data_port = VIU_OSD1_OETF_LUT_DATA_PORT;
179 		ctrl_port = VIU_OSD1_OETF_CTL;
180 	} else
181 		return;
182 
183 	if (lut_sel == VIU_LUT_OSD_OETF) {
184 		writel(0, priv->io_base + _REG(addr_port));
185 
186 		for (i = 0; i < (OSD_OETF_LUT_SIZE / 2); i++)
187 			writel(r_map[i * 2] | (r_map[i * 2 + 1] << 16),
188 				priv->io_base + _REG(data_port));
189 
190 		writel(r_map[OSD_OETF_LUT_SIZE - 1] | (g_map[0] << 16),
191 			priv->io_base + _REG(data_port));
192 
193 		for (i = 0; i < (OSD_OETF_LUT_SIZE / 2); i++)
194 			writel(g_map[i * 2 + 1] | (g_map[i * 2 + 2] << 16),
195 				priv->io_base + _REG(data_port));
196 
197 		for (i = 0; i < (OSD_OETF_LUT_SIZE / 2); i++)
198 			writel(b_map[i * 2] | (b_map[i * 2 + 1] << 16),
199 				priv->io_base + _REG(data_port));
200 
201 		writel(b_map[OSD_OETF_LUT_SIZE - 1],
202 			priv->io_base + _REG(data_port));
203 
204 		if (csc_on)
205 			writel_bits_relaxed(0x7 << 29, 7 << 29,
206 					    priv->io_base + _REG(ctrl_port));
207 		else
208 			writel_bits_relaxed(0x7 << 29, 0,
209 					    priv->io_base + _REG(ctrl_port));
210 	} else if (lut_sel == VIU_LUT_OSD_EOTF) {
211 		writel(0, priv->io_base + _REG(addr_port));
212 
213 		for (i = 0; i < (OSD_EOTF_LUT_SIZE / 2); i++)
214 			writel(r_map[i * 2] | (r_map[i * 2 + 1] << 16),
215 				priv->io_base + _REG(data_port));
216 
217 		writel(r_map[OSD_EOTF_LUT_SIZE - 1] | (g_map[0] << 16),
218 			priv->io_base + _REG(data_port));
219 
220 		for (i = 0; i < (OSD_EOTF_LUT_SIZE / 2); i++)
221 			writel(g_map[i * 2 + 1] | (g_map[i * 2 + 2] << 16),
222 				priv->io_base + _REG(data_port));
223 
224 		for (i = 0; i < (OSD_EOTF_LUT_SIZE / 2); i++)
225 			writel(b_map[i * 2] | (b_map[i * 2 + 1] << 16),
226 				priv->io_base + _REG(data_port));
227 
228 		writel(b_map[OSD_EOTF_LUT_SIZE - 1],
229 			priv->io_base + _REG(data_port));
230 
231 		if (csc_on)
232 			writel_bits_relaxed(7 << 27, 7 << 27,
233 					    priv->io_base + _REG(ctrl_port));
234 		else
235 			writel_bits_relaxed(7 << 27, 0,
236 					    priv->io_base + _REG(ctrl_port));
237 
238 		writel_bits_relaxed(BIT(31), BIT(31),
239 				    priv->io_base + _REG(ctrl_port));
240 	}
241 }
242 
243 /* eotf lut: linear */
244 static unsigned int eotf_33_linear_mapping[OSD_EOTF_LUT_SIZE] = {
245 	0x0000,	0x0200,	0x0400, 0x0600,
246 	0x0800, 0x0a00, 0x0c00, 0x0e00,
247 	0x1000, 0x1200, 0x1400, 0x1600,
248 	0x1800, 0x1a00, 0x1c00, 0x1e00,
249 	0x2000, 0x2200, 0x2400, 0x2600,
250 	0x2800, 0x2a00, 0x2c00, 0x2e00,
251 	0x3000, 0x3200, 0x3400, 0x3600,
252 	0x3800, 0x3a00, 0x3c00, 0x3e00,
253 	0x4000
254 };
255 
256 /* osd oetf lut: linear */
257 static unsigned int oetf_41_linear_mapping[OSD_OETF_LUT_SIZE] = {
258 	0, 0, 0, 0,
259 	0, 32, 64, 96,
260 	128, 160, 196, 224,
261 	256, 288, 320, 352,
262 	384, 416, 448, 480,
263 	512, 544, 576, 608,
264 	640, 672, 704, 736,
265 	768, 800, 832, 864,
266 	896, 928, 960, 992,
267 	1023, 1023, 1023, 1023,
268 	1023
269 };
270 
271 static void meson_viu_load_matrix(struct meson_drm *priv)
272 {
273 	/* eotf lut bypass */
274 	meson_viu_set_osd_lut(priv, VIU_LUT_OSD_EOTF,
275 			      eotf_33_linear_mapping, /* R */
276 			      eotf_33_linear_mapping, /* G */
277 			      eotf_33_linear_mapping, /* B */
278 			      false);
279 
280 	/* eotf matrix bypass */
281 	meson_viu_set_osd_matrix(priv, VIU_MATRIX_OSD_EOTF,
282 				 eotf_bypass_coeff,
283 				 false);
284 
285 	/* oetf lut bypass */
286 	meson_viu_set_osd_lut(priv, VIU_LUT_OSD_OETF,
287 			      oetf_41_linear_mapping, /* R */
288 			      oetf_41_linear_mapping, /* G */
289 			      oetf_41_linear_mapping, /* B */
290 			      false);
291 
292 	/* osd matrix RGB709 to YUV709 limit */
293 	meson_viu_set_osd_matrix(priv, VIU_MATRIX_OSD,
294 				 RGB709_to_YUV709l_coeff,
295 				 true);
296 }
297 
298 /* VIU OSD1 Reset as workaround for GXL+ Alpha OSD Bug */
299 void meson_viu_osd1_reset(struct meson_drm *priv)
300 {
301 	uint32_t osd1_fifo_ctrl_stat, osd1_ctrl_stat2;
302 
303 	/* Save these 2 registers state */
304 	osd1_fifo_ctrl_stat = readl_relaxed(
305 				priv->io_base + _REG(VIU_OSD1_FIFO_CTRL_STAT));
306 	osd1_ctrl_stat2 = readl_relaxed(
307 				priv->io_base + _REG(VIU_OSD1_CTRL_STAT2));
308 
309 	/* Reset OSD1 */
310 	writel_bits_relaxed(BIT(0), BIT(0),
311 			    priv->io_base + _REG(VIU_SW_RESET));
312 	writel_bits_relaxed(BIT(0), 0,
313 			    priv->io_base + _REG(VIU_SW_RESET));
314 
315 	/* Rewrite these registers state lost in the reset */
316 	writel_relaxed(osd1_fifo_ctrl_stat,
317 		       priv->io_base + _REG(VIU_OSD1_FIFO_CTRL_STAT));
318 	writel_relaxed(osd1_ctrl_stat2,
319 		       priv->io_base + _REG(VIU_OSD1_CTRL_STAT2));
320 
321 	/* Reload the conversion matrix */
322 	meson_viu_load_matrix(priv);
323 }
324 
325 void meson_viu_init(struct meson_drm *priv)
326 {
327 	uint32_t reg;
328 
329 	/* Disable OSDs */
330 	writel_bits_relaxed(BIT(0) | BIT(21), 0,
331 			priv->io_base + _REG(VIU_OSD1_CTRL_STAT));
332 	writel_bits_relaxed(BIT(0) | BIT(21), 0,
333 			priv->io_base + _REG(VIU_OSD2_CTRL_STAT));
334 
335 	/* On GXL/GXM, Use the 10bit HDR conversion matrix */
336 	if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") ||
337 	    meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu"))
338 		meson_viu_load_matrix(priv);
339 
340 	/* Initialize OSD1 fifo control register */
341 	reg = BIT(0) |	/* Urgent DDR request priority */
342 	      (4 << 5) | /* hold_fifo_lines */
343 	      (3 << 10) | /* burst length 64 */
344 	      (32 << 12) | /* fifo_depth_val: 32*8=256 */
345 	      (2 << 22) | /* 4 words in 1 burst */
346 	      (2 << 24);
347 	writel_relaxed(reg, priv->io_base + _REG(VIU_OSD1_FIFO_CTRL_STAT));
348 	writel_relaxed(reg, priv->io_base + _REG(VIU_OSD2_FIFO_CTRL_STAT));
349 
350 	/* Set OSD alpha replace value */
351 	writel_bits_relaxed(0xff << OSD_REPLACE_SHIFT,
352 			    0xff << OSD_REPLACE_SHIFT,
353 			    priv->io_base + _REG(VIU_OSD1_CTRL_STAT2));
354 	writel_bits_relaxed(0xff << OSD_REPLACE_SHIFT,
355 			    0xff << OSD_REPLACE_SHIFT,
356 			    priv->io_base + _REG(VIU_OSD2_CTRL_STAT2));
357 
358 	/* Disable VD1 AFBC */
359 	/* di_mif0_en=0 mif0_to_vpp_en=0 di_mad_en=0 */
360 	writel_bits_relaxed(0x7 << 16, 0,
361 			priv->io_base + _REG(VIU_MISC_CTRL0));
362 	/* afbc vd1 set=0 */
363 	writel_bits_relaxed(BIT(20), 0,
364 			priv->io_base + _REG(VIU_MISC_CTRL0));
365 	writel_relaxed(0, priv->io_base + _REG(AFBC_ENABLE));
366 
367 	writel_relaxed(0x00FF00C0,
368 			priv->io_base + _REG(VD1_IF0_LUMA_FIFO_SIZE));
369 	writel_relaxed(0x00FF00C0,
370 			priv->io_base + _REG(VD2_IF0_LUMA_FIFO_SIZE));
371 
372 
373 	priv->viu.osd1_enabled = false;
374 	priv->viu.osd1_commit = false;
375 	priv->viu.osd1_interlace = false;
376 }
377