1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Amlogic Meson Video Processing Unit driver
4  *
5  * Copyright (c) 2018 BayLibre, SAS.
6  * Author: Neil Armstrong <narmstrong@baylibre.com>
7  */
8 
9 #define DEBUG
10 
11 #include "meson_vpu.h"
12 
13 /* HHI Registers */
14 #define HHI_VDAC_CNTL0		0x2F4 /* 0xbd offset in data sheet */
15 #define HHI_VDAC_CNTL1		0x2F8 /* 0xbe offset in data sheet */
16 #define HHI_HDMI_PHY_CNTL0	0x3a0 /* 0xe8 offset in data sheet */
17 
18 /* OSDx_CTRL_STAT2 */
19 #define OSD_REPLACE_EN		BIT(14)
20 #define OSD_REPLACE_SHIFT	6
21 
22 void meson_vpp_setup_mux(struct meson_vpu_priv *priv, unsigned int mux)
23 {
24 	writel(mux, priv->io_base + _REG(VPU_VIU_VENC_MUX_CTRL));
25 }
26 
27 static unsigned int vpp_filter_coefs_4point_bspline[] = {
28 	0x15561500, 0x14561600, 0x13561700, 0x12561800,
29 	0x11551a00, 0x11541b00, 0x10541c00, 0x0f541d00,
30 	0x0f531e00, 0x0e531f00, 0x0d522100, 0x0c522200,
31 	0x0b522300, 0x0b512400, 0x0a502600, 0x0a4f2700,
32 	0x094e2900, 0x084e2a00, 0x084d2b00, 0x074c2c01,
33 	0x074b2d01, 0x064a2f01, 0x06493001, 0x05483201,
34 	0x05473301, 0x05463401, 0x04453601, 0x04433702,
35 	0x04423802, 0x03413a02, 0x03403b02, 0x033f3c02,
36 	0x033d3d03
37 };
38 
39 static void meson_vpp_write_scaling_filter_coefs(struct meson_vpu_priv *priv,
40 						 const unsigned int *coefs,
41 						 bool is_horizontal)
42 {
43 	int i;
44 
45 	writel(is_horizontal ? BIT(8) : 0,
46 	       priv->io_base + _REG(VPP_OSD_SCALE_COEF_IDX));
47 	for (i = 0; i < 33; i++)
48 		writel(coefs[i],
49 		       priv->io_base + _REG(VPP_OSD_SCALE_COEF));
50 }
51 
52 static const u32 vpp_filter_coefs_bicubic[] = {
53 	0x00800000, 0x007f0100, 0xff7f0200, 0xfe7f0300,
54 	0xfd7e0500, 0xfc7e0600, 0xfb7d0800, 0xfb7c0900,
55 	0xfa7b0b00, 0xfa7a0dff, 0xf9790fff, 0xf97711ff,
56 	0xf87613ff, 0xf87416fe, 0xf87218fe, 0xf8701afe,
57 	0xf76f1dfd, 0xf76d1ffd, 0xf76b21fd, 0xf76824fd,
58 	0xf76627fc, 0xf76429fc, 0xf7612cfc, 0xf75f2ffb,
59 	0xf75d31fb, 0xf75a34fb, 0xf75837fa, 0xf7553afa,
60 	0xf8523cfa, 0xf8503ff9, 0xf84d42f9, 0xf84a45f9,
61 	0xf84848f8
62 };
63 
64 static void meson_vpp_write_vd_scaling_filter_coefs(struct meson_vpu_priv *priv,
65 						    const unsigned int *coefs,
66 						    bool is_horizontal)
67 {
68 	int i;
69 
70 	writel(is_horizontal ? BIT(8) : 0,
71 	       priv->io_base + _REG(VPP_SCALE_COEF_IDX));
72 	for (i = 0; i < 33; i++)
73 		writel(coefs[i],
74 		       priv->io_base + _REG(VPP_SCALE_COEF));
75 }
76 
77 /* OSD csc defines */
78 
79 enum viu_matrix_sel_e {
80 	VIU_MATRIX_OSD_EOTF = 0,
81 	VIU_MATRIX_OSD,
82 };
83 
84 enum viu_lut_sel_e {
85 	VIU_LUT_OSD_EOTF = 0,
86 	VIU_LUT_OSD_OETF,
87 };
88 
89 #define COEFF_NORM(a) ((int)((((a) * 2048.0) + 1) / 2))
90 #define MATRIX_5X3_COEF_SIZE 24
91 
92 #define EOTF_COEFF_NORM(a) ((int)((((a) * 4096.0) + 1) / 2))
93 #define EOTF_COEFF_SIZE 10
94 #define EOTF_COEFF_RIGHTSHIFT 1
95 
96 static int RGB709_to_YUV709l_coeff[MATRIX_5X3_COEF_SIZE] = {
97 	0, 0, 0, /* pre offset */
98 	COEFF_NORM(0.181873),	COEFF_NORM(0.611831),	COEFF_NORM(0.061765),
99 	COEFF_NORM(-0.100251),	COEFF_NORM(-0.337249),	COEFF_NORM(0.437500),
100 	COEFF_NORM(0.437500),	COEFF_NORM(-0.397384),	COEFF_NORM(-0.040116),
101 	0, 0, 0, /* 10'/11'/12' */
102 	0, 0, 0, /* 20'/21'/22' */
103 	64, 512, 512, /* offset */
104 	0, 0, 0 /* mode, right_shift, clip_en */
105 };
106 
107 /*  eotf matrix: bypass */
108 static int eotf_bypass_coeff[EOTF_COEFF_SIZE] = {
109 	EOTF_COEFF_NORM(1.0),	EOTF_COEFF_NORM(0.0),	EOTF_COEFF_NORM(0.0),
110 	EOTF_COEFF_NORM(0.0),	EOTF_COEFF_NORM(1.0),	EOTF_COEFF_NORM(0.0),
111 	EOTF_COEFF_NORM(0.0),	EOTF_COEFF_NORM(0.0),	EOTF_COEFF_NORM(1.0),
112 	EOTF_COEFF_RIGHTSHIFT /* right shift */
113 };
114 
115 static void meson_viu_set_osd_matrix(struct meson_vpu_priv *priv,
116 				     enum viu_matrix_sel_e m_select,
117 				     int *m, bool csc_on)
118 {
119 	if (m_select == VIU_MATRIX_OSD) {
120 		/* osd matrix, VIU_MATRIX_0 */
121 		writel(((m[0] & 0xfff) << 16) | (m[1] & 0xfff),
122 		       priv->io_base + _REG(VIU_OSD1_MATRIX_PRE_OFFSET0_1));
123 		writel(m[2] & 0xfff,
124 		       priv->io_base + _REG(VIU_OSD1_MATRIX_PRE_OFFSET2));
125 		writel(((m[3] & 0x1fff) << 16) | (m[4] & 0x1fff),
126 		       priv->io_base + _REG(VIU_OSD1_MATRIX_COEF00_01));
127 		writel(((m[5] & 0x1fff) << 16) | (m[6] & 0x1fff),
128 		       priv->io_base + _REG(VIU_OSD1_MATRIX_COEF02_10));
129 		writel(((m[7] & 0x1fff) << 16) | (m[8] & 0x1fff),
130 		       priv->io_base + _REG(VIU_OSD1_MATRIX_COEF11_12));
131 		writel(((m[9] & 0x1fff) << 16) | (m[10] & 0x1fff),
132 		       priv->io_base + _REG(VIU_OSD1_MATRIX_COEF20_21));
133 
134 		if (m[21]) {
135 			writel(((m[11] & 0x1fff) << 16) | (m[12] & 0x1fff),
136 			       priv->io_base +
137 					_REG(VIU_OSD1_MATRIX_COEF22_30));
138 			writel(((m[13] & 0x1fff) << 16) | (m[14] & 0x1fff),
139 			       priv->io_base +
140 					_REG(VIU_OSD1_MATRIX_COEF31_32));
141 			writel(((m[15] & 0x1fff) << 16) | (m[16] & 0x1fff),
142 			       priv->io_base +
143 					_REG(VIU_OSD1_MATRIX_COEF40_41));
144 			writel(m[17] & 0x1fff, priv->io_base +
145 			       _REG(VIU_OSD1_MATRIX_COLMOD_COEF42));
146 		} else {
147 			writel((m[11] & 0x1fff) << 16, priv->io_base +
148 			       _REG(VIU_OSD1_MATRIX_COEF22_30));
149 		}
150 
151 		writel(((m[18] & 0xfff) << 16) | (m[19] & 0xfff),
152 		       priv->io_base + _REG(VIU_OSD1_MATRIX_OFFSET0_1));
153 		writel(m[20] & 0xfff,
154 		       priv->io_base + _REG(VIU_OSD1_MATRIX_OFFSET2));
155 
156 		writel_bits(3 << 30, m[21] << 30,
157 			    priv->io_base +
158 			    _REG(VIU_OSD1_MATRIX_COLMOD_COEF42));
159 		writel_bits(7 << 16, m[22] << 16,
160 			    priv->io_base +
161 			    _REG(VIU_OSD1_MATRIX_COLMOD_COEF42));
162 
163 		/* 23 reserved for clipping control */
164 		writel_bits(BIT(0), csc_on ? BIT(0) : 0,
165 			    priv->io_base + _REG(VIU_OSD1_MATRIX_CTRL));
166 		writel_bits(BIT(1), 0,
167 			    priv->io_base + _REG(VIU_OSD1_MATRIX_CTRL));
168 	} else if (m_select == VIU_MATRIX_OSD_EOTF) {
169 		int i;
170 
171 		/* osd eotf matrix, VIU_MATRIX_OSD_EOTF */
172 		for (i = 0; i < 5; i++)
173 			writel(((m[i * 2] & 0x1fff) << 16) |
174 				(m[i * 2 + 1] & 0x1fff), priv->io_base +
175 				_REG(VIU_OSD1_EOTF_CTL + i + 1));
176 
177 		writel_bits(BIT(30), csc_on ? BIT(30) : 0,
178 			    priv->io_base + _REG(VIU_OSD1_EOTF_CTL));
179 		writel_bits(BIT(31), csc_on ? BIT(31) : 0,
180 			    priv->io_base + _REG(VIU_OSD1_EOTF_CTL));
181 	}
182 }
183 
184 #define OSD_EOTF_LUT_SIZE 33
185 #define OSD_OETF_LUT_SIZE 41
186 
187 static void meson_viu_set_osd_lut(struct meson_vpu_priv *priv,
188 				  enum viu_lut_sel_e lut_sel,
189 				  unsigned int *r_map, unsigned int *g_map,
190 				  unsigned int *b_map,
191 				  bool csc_on)
192 {
193 	unsigned int addr_port;
194 	unsigned int data_port;
195 	unsigned int ctrl_port;
196 	int i;
197 
198 	if (lut_sel == VIU_LUT_OSD_EOTF) {
199 		addr_port = VIU_OSD1_EOTF_LUT_ADDR_PORT;
200 		data_port = VIU_OSD1_EOTF_LUT_DATA_PORT;
201 		ctrl_port = VIU_OSD1_EOTF_CTL;
202 	} else if (lut_sel == VIU_LUT_OSD_OETF) {
203 		addr_port = VIU_OSD1_OETF_LUT_ADDR_PORT;
204 		data_port = VIU_OSD1_OETF_LUT_DATA_PORT;
205 		ctrl_port = VIU_OSD1_OETF_CTL;
206 	} else {
207 		return;
208 	}
209 
210 	if (lut_sel == VIU_LUT_OSD_OETF) {
211 		writel(0, priv->io_base + _REG(addr_port));
212 
213 		for (i = 0; i < 20; 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_OETF_LUT_SIZE - 1] | (g_map[0] << 16),
218 		       priv->io_base + _REG(data_port));
219 
220 		for (i = 0; i < 20; 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 < 20; 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_OETF_LUT_SIZE - 1],
229 		       priv->io_base + _REG(data_port));
230 
231 		if (csc_on)
232 			writel_bits(0x7 << 29, 7 << 29,
233 				    priv->io_base + _REG(ctrl_port));
234 		else
235 			writel_bits(0x7 << 29, 0,
236 				    priv->io_base + _REG(ctrl_port));
237 	} else if (lut_sel == VIU_LUT_OSD_EOTF) {
238 		writel(0, priv->io_base + _REG(addr_port));
239 
240 		for (i = 0; i < 20; i++)
241 			writel(r_map[i * 2] | (r_map[i * 2 + 1] << 16),
242 			       priv->io_base + _REG(data_port));
243 
244 		writel(r_map[OSD_EOTF_LUT_SIZE - 1] | (g_map[0] << 16),
245 		       priv->io_base + _REG(data_port));
246 
247 		for (i = 0; i < 20; i++)
248 			writel(g_map[i * 2 + 1] | (g_map[i * 2 + 2] << 16),
249 			       priv->io_base + _REG(data_port));
250 
251 		for (i = 0; i < 20; i++)
252 			writel(b_map[i * 2] | (b_map[i * 2 + 1] << 16),
253 			       priv->io_base + _REG(data_port));
254 
255 		writel(b_map[OSD_EOTF_LUT_SIZE - 1],
256 		       priv->io_base + _REG(data_port));
257 
258 		if (csc_on)
259 			writel_bits(7 << 27, 7 << 27,
260 				    priv->io_base + _REG(ctrl_port));
261 		else
262 			writel_bits(7 << 27, 0,
263 				    priv->io_base + _REG(ctrl_port));
264 
265 		writel_bits(BIT(31), BIT(31),
266 			    priv->io_base + _REG(ctrl_port));
267 	}
268 }
269 
270 /* eotf lut: linear */
271 static unsigned int eotf_33_linear_mapping[OSD_EOTF_LUT_SIZE] = {
272 	0x0000,	0x0200,	0x0400, 0x0600,
273 	0x0800, 0x0a00, 0x0c00, 0x0e00,
274 	0x1000, 0x1200, 0x1400, 0x1600,
275 	0x1800, 0x1a00, 0x1c00, 0x1e00,
276 	0x2000, 0x2200, 0x2400, 0x2600,
277 	0x2800, 0x2a00, 0x2c00, 0x2e00,
278 	0x3000, 0x3200, 0x3400, 0x3600,
279 	0x3800, 0x3a00, 0x3c00, 0x3e00,
280 	0x4000
281 };
282 
283 /* osd oetf lut: linear */
284 static unsigned int oetf_41_linear_mapping[OSD_OETF_LUT_SIZE] = {
285 	0, 0, 0, 0,
286 	0, 32, 64, 96,
287 	128, 160, 196, 224,
288 	256, 288, 320, 352,
289 	384, 416, 448, 480,
290 	512, 544, 576, 608,
291 	640, 672, 704, 736,
292 	768, 800, 832, 864,
293 	896, 928, 960, 992,
294 	1023, 1023, 1023, 1023,
295 	1023
296 };
297 
298 static void meson_viu_load_matrix(struct meson_vpu_priv *priv)
299 {
300 	/* eotf lut bypass */
301 	meson_viu_set_osd_lut(priv, VIU_LUT_OSD_EOTF,
302 			      eotf_33_linear_mapping, /* R */
303 			      eotf_33_linear_mapping, /* G */
304 			      eotf_33_linear_mapping, /* B */
305 			      false);
306 
307 	/* eotf matrix bypass */
308 	meson_viu_set_osd_matrix(priv, VIU_MATRIX_OSD_EOTF,
309 				 eotf_bypass_coeff,
310 				 false);
311 
312 	/* oetf lut bypass */
313 	meson_viu_set_osd_lut(priv, VIU_LUT_OSD_OETF,
314 			      oetf_41_linear_mapping, /* R */
315 			      oetf_41_linear_mapping, /* G */
316 			      oetf_41_linear_mapping, /* B */
317 			      false);
318 
319 	/* osd matrix RGB709 to YUV709 limit */
320 	meson_viu_set_osd_matrix(priv, VIU_MATRIX_OSD,
321 				 RGB709_to_YUV709l_coeff,
322 				 true);
323 }
324 
325 void meson_vpu_init(struct udevice *dev)
326 {
327 	struct meson_vpu_priv *priv = dev_get_priv(dev);
328 	u32 reg;
329 
330 	/* vpu initialization */
331 	writel(0x210000, priv->io_base + _REG(VPU_RDARB_MODE_L1C1));
332 	writel(0x10000, priv->io_base + _REG(VPU_RDARB_MODE_L1C2));
333 	writel(0x900000, priv->io_base + _REG(VPU_RDARB_MODE_L2C1));
334 	writel(0x20000, priv->io_base + _REG(VPU_WRARB_MODE_L2C1));
335 
336 	/* Disable CVBS VDAC */
337 	hhi_write(HHI_VDAC_CNTL0, 0);
338 	hhi_write(HHI_VDAC_CNTL1, 8);
339 
340 	/* Power Down Dacs */
341 	writel(0xff, priv->io_base + _REG(VENC_VDAC_SETTING));
342 
343 	/* Disable HDMI PHY */
344 	hhi_write(HHI_HDMI_PHY_CNTL0, 0);
345 
346 	/* Disable HDMI */
347 	writel_bits(0x3, 0, priv->io_base + _REG(VPU_HDMI_SETTING));
348 
349 	/* Disable all encoders */
350 	writel(0, priv->io_base + _REG(ENCI_VIDEO_EN));
351 	writel(0, priv->io_base + _REG(ENCP_VIDEO_EN));
352 	writel(0, priv->io_base + _REG(ENCL_VIDEO_EN));
353 
354 	/* Disable VSync IRQ */
355 	writel(0, priv->io_base + _REG(VENC_INTCTRL));
356 
357 	/* set dummy data default YUV black */
358 	if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXL)) {
359 		writel(0x108080, priv->io_base + _REG(VPP_DUMMY_DATA1));
360 	} else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM)) {
361 		writel_bits(0xff << 16, 0xff << 16,
362 			    priv->io_base + _REG(VIU_MISC_CTRL1));
363 		writel(0x20000, priv->io_base + _REG(VPP_DOLBY_CTRL));
364 		writel(0x1020080,
365 		       priv->io_base + _REG(VPP_DUMMY_DATA1));
366 	}
367 
368 	/* Initialize vpu fifo control registers */
369 	writel(readl(priv->io_base + _REG(VPP_OFIFO_SIZE)) |
370 			0x77f, priv->io_base + _REG(VPP_OFIFO_SIZE));
371 	writel(0x08080808, priv->io_base + _REG(VPP_HOLD_LINES));
372 
373 	/* Turn off preblend */
374 	writel_bits(VPP_PREBLEND_ENABLE, 0,
375 		    priv->io_base + _REG(VPP_MISC));
376 
377 	/* Turn off POSTBLEND */
378 	writel_bits(VPP_POSTBLEND_ENABLE, 0,
379 		    priv->io_base + _REG(VPP_MISC));
380 
381 	/* Force all planes off */
382 	writel_bits(VPP_OSD1_POSTBLEND | VPP_OSD2_POSTBLEND |
383 		    VPP_VD1_POSTBLEND | VPP_VD2_POSTBLEND |
384 		    VPP_VD1_PREBLEND | VPP_VD2_PREBLEND, 0,
385 		    priv->io_base + _REG(VPP_MISC));
386 
387 	/* Setup default VD settings */
388 	writel(4096,
389 	       priv->io_base + _REG(VPP_PREBLEND_VD1_H_START_END));
390 	writel(4096,
391 	       priv->io_base + _REG(VPP_BLEND_VD2_H_START_END));
392 
393 	/* Disable Scalers */
394 	writel(0, priv->io_base + _REG(VPP_OSD_SC_CTRL0));
395 	writel(0, priv->io_base + _REG(VPP_OSD_VSC_CTRL0));
396 	writel(0, priv->io_base + _REG(VPP_OSD_HSC_CTRL0));
397 	writel(4 | (4 << 8) | BIT(15),
398 	       priv->io_base + _REG(VPP_SC_MISC));
399 
400 	/* Write in the proper filter coefficients. */
401 	meson_vpp_write_scaling_filter_coefs(priv,
402 				vpp_filter_coefs_4point_bspline, false);
403 	meson_vpp_write_scaling_filter_coefs(priv,
404 				vpp_filter_coefs_4point_bspline, true);
405 
406 	/* Write the VD proper filter coefficients. */
407 	meson_vpp_write_vd_scaling_filter_coefs(priv, vpp_filter_coefs_bicubic,
408 						false);
409 	meson_vpp_write_vd_scaling_filter_coefs(priv, vpp_filter_coefs_bicubic,
410 						true);
411 
412 	/* Disable OSDs */
413 	writel_bits(BIT(0) | BIT(21), 0,
414 		    priv->io_base + _REG(VIU_OSD1_CTRL_STAT));
415 	writel_bits(BIT(0) | BIT(21), 0,
416 		    priv->io_base + _REG(VIU_OSD2_CTRL_STAT));
417 
418 	/* On GXL/GXM, Use the 10bit HDR conversion matrix */
419 	if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) ||
420 	    meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXL))
421 		meson_viu_load_matrix(priv);
422 
423 	/* Initialize OSD1 fifo control register */
424 	reg = BIT(0) |	/* Urgent DDR request priority */
425 	      (4 << 5) | /* hold_fifo_lines */
426 	      (3 << 10) | /* burst length 64 */
427 	      (32 << 12) | /* fifo_depth_val: 32*8=256 */
428 	      (2 << 22) | /* 4 words in 1 burst */
429 	      (2 << 24);
430 	writel(reg, priv->io_base + _REG(VIU_OSD1_FIFO_CTRL_STAT));
431 	writel(reg, priv->io_base + _REG(VIU_OSD2_FIFO_CTRL_STAT));
432 
433 	/* Set OSD alpha replace value */
434 	writel_bits(0xff << OSD_REPLACE_SHIFT,
435 		    0xff << OSD_REPLACE_SHIFT,
436 		    priv->io_base + _REG(VIU_OSD1_CTRL_STAT2));
437 	writel_bits(0xff << OSD_REPLACE_SHIFT,
438 		    0xff << OSD_REPLACE_SHIFT,
439 		    priv->io_base + _REG(VIU_OSD2_CTRL_STAT2));
440 }
441