Linux Audio

Check our new training course

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