Linux Audio

Check our new training course

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