xref: /openbmc/linux/drivers/gpu/drm/meson/meson_viu.c (revision 612a462a)
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 < 20; 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 < 20; 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 < 20; 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 < 20; 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 < 20; 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 < 20; 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 void meson_viu_init(struct meson_drm *priv)
300 {
301 	uint32_t reg;
302 
303 	/* Disable OSDs */
304 	writel_bits_relaxed(BIT(0) | BIT(21), 0,
305 			priv->io_base + _REG(VIU_OSD1_CTRL_STAT));
306 	writel_bits_relaxed(BIT(0) | BIT(21), 0,
307 			priv->io_base + _REG(VIU_OSD2_CTRL_STAT));
308 
309 	/* On GXL/GXM, Use the 10bit HDR conversion matrix */
310 	if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") ||
311 	    meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu"))
312 		meson_viu_load_matrix(priv);
313 
314 	/* Initialize OSD1 fifo control register */
315 	reg = BIT(0) |	/* Urgent DDR request priority */
316 	      (4 << 5) | /* hold_fifo_lines */
317 	      (3 << 10) | /* burst length 64 */
318 	      (32 << 12) | /* fifo_depth_val: 32*8=256 */
319 	      (2 << 22) | /* 4 words in 1 burst */
320 	      (2 << 24);
321 	writel_relaxed(reg, priv->io_base + _REG(VIU_OSD1_FIFO_CTRL_STAT));
322 	writel_relaxed(reg, priv->io_base + _REG(VIU_OSD2_FIFO_CTRL_STAT));
323 
324 	/* Set OSD alpha replace value */
325 	writel_bits_relaxed(0xff << OSD_REPLACE_SHIFT,
326 			    0xff << OSD_REPLACE_SHIFT,
327 			    priv->io_base + _REG(VIU_OSD1_CTRL_STAT2));
328 	writel_bits_relaxed(0xff << OSD_REPLACE_SHIFT,
329 			    0xff << OSD_REPLACE_SHIFT,
330 			    priv->io_base + _REG(VIU_OSD2_CTRL_STAT2));
331 
332 	priv->viu.osd1_enabled = false;
333 	priv->viu.osd1_commit = false;
334 	priv->viu.osd1_interlace = false;
335 }
336