162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2016 BayLibre, SAS
462306a36Sopenharmony_ci * Author: Neil Armstrong <narmstrong@baylibre.com>
562306a36Sopenharmony_ci * Copyright (C) 2015 Amlogic, Inc. All rights reserved.
662306a36Sopenharmony_ci * Copyright (C) 2014 Endless Mobile
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/export.h>
1062306a36Sopenharmony_ci#include <linux/bitfield.h>
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <drm/drm_fourcc.h>
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#include "meson_drv.h"
1562306a36Sopenharmony_ci#include "meson_viu.h"
1662306a36Sopenharmony_ci#include "meson_registers.h"
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci/**
1962306a36Sopenharmony_ci * DOC: Video Input Unit
2062306a36Sopenharmony_ci *
2162306a36Sopenharmony_ci * VIU Handles the Pixel scanout and the basic Colorspace conversions
2262306a36Sopenharmony_ci * We handle the following features :
2362306a36Sopenharmony_ci *
2462306a36Sopenharmony_ci * - OSD1 RGB565/RGB888/xRGB8888 scanout
2562306a36Sopenharmony_ci * - RGB conversion to x/cb/cr
2662306a36Sopenharmony_ci * - Progressive or Interlace buffer scanout
2762306a36Sopenharmony_ci * - OSD1 Commit on Vsync
2862306a36Sopenharmony_ci * - HDR OSD matrix for GXL/GXM
2962306a36Sopenharmony_ci *
3062306a36Sopenharmony_ci * What is missing :
3162306a36Sopenharmony_ci *
3262306a36Sopenharmony_ci * - BGR888/xBGR8888/BGRx8888/BGRx8888 modes
3362306a36Sopenharmony_ci * - YUV4:2:2 Y0CbY1Cr scanout
3462306a36Sopenharmony_ci * - Conversion to YUV 4:4:4 from 4:2:2 input
3562306a36Sopenharmony_ci * - Colorkey Alpha matching
3662306a36Sopenharmony_ci * - Big endian scanout
3762306a36Sopenharmony_ci * - X/Y reverse scanout
3862306a36Sopenharmony_ci * - Global alpha setup
3962306a36Sopenharmony_ci * - OSD2 support, would need interlace switching on vsync
4062306a36Sopenharmony_ci * - OSD1 full scaling to support TV overscan
4162306a36Sopenharmony_ci */
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci/* OSD csc defines */
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_cienum viu_matrix_sel_e {
4662306a36Sopenharmony_ci	VIU_MATRIX_OSD_EOTF = 0,
4762306a36Sopenharmony_ci	VIU_MATRIX_OSD,
4862306a36Sopenharmony_ci};
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_cienum viu_lut_sel_e {
5162306a36Sopenharmony_ci	VIU_LUT_OSD_EOTF = 0,
5262306a36Sopenharmony_ci	VIU_LUT_OSD_OETF,
5362306a36Sopenharmony_ci};
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci#define COEFF_NORM(a) ((int)((((a) * 2048.0) + 1) / 2))
5662306a36Sopenharmony_ci#define MATRIX_5X3_COEF_SIZE 24
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci#define EOTF_COEFF_NORM(a) ((int)((((a) * 4096.0) + 1) / 2))
5962306a36Sopenharmony_ci#define EOTF_COEFF_SIZE 10
6062306a36Sopenharmony_ci#define EOTF_COEFF_RIGHTSHIFT 1
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_cistatic int RGB709_to_YUV709l_coeff[MATRIX_5X3_COEF_SIZE] = {
6362306a36Sopenharmony_ci	0, 0, 0, /* pre offset */
6462306a36Sopenharmony_ci	COEFF_NORM(0.181873),	COEFF_NORM(0.611831),	COEFF_NORM(0.061765),
6562306a36Sopenharmony_ci	COEFF_NORM(-0.100251),	COEFF_NORM(-0.337249),	COEFF_NORM(0.437500),
6662306a36Sopenharmony_ci	COEFF_NORM(0.437500),	COEFF_NORM(-0.397384),	COEFF_NORM(-0.040116),
6762306a36Sopenharmony_ci	0, 0, 0, /* 10'/11'/12' */
6862306a36Sopenharmony_ci	0, 0, 0, /* 20'/21'/22' */
6962306a36Sopenharmony_ci	64, 512, 512, /* offset */
7062306a36Sopenharmony_ci	0, 0, 0 /* mode, right_shift, clip_en */
7162306a36Sopenharmony_ci};
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci/*  eotf matrix: bypass */
7462306a36Sopenharmony_cistatic int eotf_bypass_coeff[EOTF_COEFF_SIZE] = {
7562306a36Sopenharmony_ci	EOTF_COEFF_NORM(1.0),	EOTF_COEFF_NORM(0.0),	EOTF_COEFF_NORM(0.0),
7662306a36Sopenharmony_ci	EOTF_COEFF_NORM(0.0),	EOTF_COEFF_NORM(1.0),	EOTF_COEFF_NORM(0.0),
7762306a36Sopenharmony_ci	EOTF_COEFF_NORM(0.0),	EOTF_COEFF_NORM(0.0),	EOTF_COEFF_NORM(1.0),
7862306a36Sopenharmony_ci	EOTF_COEFF_RIGHTSHIFT /* right shift */
7962306a36Sopenharmony_ci};
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_cistatic void meson_viu_set_g12a_osd1_matrix(struct meson_drm *priv,
8262306a36Sopenharmony_ci					   int *m, bool csc_on)
8362306a36Sopenharmony_ci{
8462306a36Sopenharmony_ci	/* VPP WRAP OSD1 matrix */
8562306a36Sopenharmony_ci	writel(((m[0] & 0xfff) << 16) | (m[1] & 0xfff),
8662306a36Sopenharmony_ci		priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_PRE_OFFSET0_1));
8762306a36Sopenharmony_ci	writel(m[2] & 0xfff,
8862306a36Sopenharmony_ci		priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_PRE_OFFSET2));
8962306a36Sopenharmony_ci	writel(((m[3] & 0x1fff) << 16) | (m[4] & 0x1fff),
9062306a36Sopenharmony_ci		priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_COEF00_01));
9162306a36Sopenharmony_ci	writel(((m[5] & 0x1fff) << 16) | (m[6] & 0x1fff),
9262306a36Sopenharmony_ci		priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_COEF02_10));
9362306a36Sopenharmony_ci	writel(((m[7] & 0x1fff) << 16) | (m[8] & 0x1fff),
9462306a36Sopenharmony_ci		priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_COEF11_12));
9562306a36Sopenharmony_ci	writel(((m[9] & 0x1fff) << 16) | (m[10] & 0x1fff),
9662306a36Sopenharmony_ci		priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_COEF20_21));
9762306a36Sopenharmony_ci	writel((m[11] & 0x1fff),
9862306a36Sopenharmony_ci		priv->io_base +	_REG(VPP_WRAP_OSD1_MATRIX_COEF22));
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	writel(((m[18] & 0xfff) << 16) | (m[19] & 0xfff),
10162306a36Sopenharmony_ci		priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_OFFSET0_1));
10262306a36Sopenharmony_ci	writel(m[20] & 0xfff,
10362306a36Sopenharmony_ci		priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_OFFSET2));
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	writel_bits_relaxed(BIT(0), csc_on ? BIT(0) : 0,
10662306a36Sopenharmony_ci		priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_EN_CTRL));
10762306a36Sopenharmony_ci}
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_cistatic void meson_viu_set_osd_matrix(struct meson_drm *priv,
11062306a36Sopenharmony_ci				     enum viu_matrix_sel_e m_select,
11162306a36Sopenharmony_ci			      int *m, bool csc_on)
11262306a36Sopenharmony_ci{
11362306a36Sopenharmony_ci	if (m_select == VIU_MATRIX_OSD) {
11462306a36Sopenharmony_ci		/* osd matrix, VIU_MATRIX_0 */
11562306a36Sopenharmony_ci		writel(((m[0] & 0xfff) << 16) | (m[1] & 0xfff),
11662306a36Sopenharmony_ci			priv->io_base + _REG(VIU_OSD1_MATRIX_PRE_OFFSET0_1));
11762306a36Sopenharmony_ci		writel(m[2] & 0xfff,
11862306a36Sopenharmony_ci			priv->io_base + _REG(VIU_OSD1_MATRIX_PRE_OFFSET2));
11962306a36Sopenharmony_ci		writel(((m[3] & 0x1fff) << 16) | (m[4] & 0x1fff),
12062306a36Sopenharmony_ci			priv->io_base + _REG(VIU_OSD1_MATRIX_COEF00_01));
12162306a36Sopenharmony_ci		writel(((m[5] & 0x1fff) << 16) | (m[6] & 0x1fff),
12262306a36Sopenharmony_ci			priv->io_base + _REG(VIU_OSD1_MATRIX_COEF02_10));
12362306a36Sopenharmony_ci		writel(((m[7] & 0x1fff) << 16) | (m[8] & 0x1fff),
12462306a36Sopenharmony_ci			priv->io_base + _REG(VIU_OSD1_MATRIX_COEF11_12));
12562306a36Sopenharmony_ci		writel(((m[9] & 0x1fff) << 16) | (m[10] & 0x1fff),
12662306a36Sopenharmony_ci			priv->io_base + _REG(VIU_OSD1_MATRIX_COEF20_21));
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci		if (m[21]) {
12962306a36Sopenharmony_ci			writel(((m[11] & 0x1fff) << 16) | (m[12] & 0x1fff),
13062306a36Sopenharmony_ci				priv->io_base +
13162306a36Sopenharmony_ci					_REG(VIU_OSD1_MATRIX_COEF22_30));
13262306a36Sopenharmony_ci			writel(((m[13] & 0x1fff) << 16) | (m[14] & 0x1fff),
13362306a36Sopenharmony_ci				priv->io_base +
13462306a36Sopenharmony_ci					_REG(VIU_OSD1_MATRIX_COEF31_32));
13562306a36Sopenharmony_ci			writel(((m[15] & 0x1fff) << 16) | (m[16] & 0x1fff),
13662306a36Sopenharmony_ci				priv->io_base +
13762306a36Sopenharmony_ci					_REG(VIU_OSD1_MATRIX_COEF40_41));
13862306a36Sopenharmony_ci			writel(m[17] & 0x1fff, priv->io_base +
13962306a36Sopenharmony_ci				_REG(VIU_OSD1_MATRIX_COLMOD_COEF42));
14062306a36Sopenharmony_ci		} else
14162306a36Sopenharmony_ci			writel((m[11] & 0x1fff) << 16, priv->io_base +
14262306a36Sopenharmony_ci				_REG(VIU_OSD1_MATRIX_COEF22_30));
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci		writel(((m[18] & 0xfff) << 16) | (m[19] & 0xfff),
14562306a36Sopenharmony_ci			priv->io_base + _REG(VIU_OSD1_MATRIX_OFFSET0_1));
14662306a36Sopenharmony_ci		writel(m[20] & 0xfff,
14762306a36Sopenharmony_ci			priv->io_base + _REG(VIU_OSD1_MATRIX_OFFSET2));
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci		writel_bits_relaxed(3 << 30, m[21] << 30,
15062306a36Sopenharmony_ci			priv->io_base + _REG(VIU_OSD1_MATRIX_COLMOD_COEF42));
15162306a36Sopenharmony_ci		writel_bits_relaxed(7 << 16, m[22] << 16,
15262306a36Sopenharmony_ci			priv->io_base + _REG(VIU_OSD1_MATRIX_COLMOD_COEF42));
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci		/* 23 reserved for clipping control */
15562306a36Sopenharmony_ci		writel_bits_relaxed(BIT(0), csc_on ? BIT(0) : 0,
15662306a36Sopenharmony_ci			priv->io_base + _REG(VIU_OSD1_MATRIX_CTRL));
15762306a36Sopenharmony_ci		writel_bits_relaxed(BIT(1), 0,
15862306a36Sopenharmony_ci			priv->io_base + _REG(VIU_OSD1_MATRIX_CTRL));
15962306a36Sopenharmony_ci	} else if (m_select == VIU_MATRIX_OSD_EOTF) {
16062306a36Sopenharmony_ci		int i;
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci		/* osd eotf matrix, VIU_MATRIX_OSD_EOTF */
16362306a36Sopenharmony_ci		for (i = 0; i < 5; i++)
16462306a36Sopenharmony_ci			writel(((m[i * 2] & 0x1fff) << 16) |
16562306a36Sopenharmony_ci				(m[i * 2 + 1] & 0x1fff), priv->io_base +
16662306a36Sopenharmony_ci				_REG(VIU_OSD1_EOTF_CTL + i + 1));
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci		writel_bits_relaxed(BIT(30), csc_on ? BIT(30) : 0,
16962306a36Sopenharmony_ci			priv->io_base + _REG(VIU_OSD1_EOTF_CTL));
17062306a36Sopenharmony_ci		writel_bits_relaxed(BIT(31), csc_on ? BIT(31) : 0,
17162306a36Sopenharmony_ci			priv->io_base + _REG(VIU_OSD1_EOTF_CTL));
17262306a36Sopenharmony_ci	}
17362306a36Sopenharmony_ci}
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci#define OSD_EOTF_LUT_SIZE 33
17662306a36Sopenharmony_ci#define OSD_OETF_LUT_SIZE 41
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_cistatic void
17962306a36Sopenharmony_cimeson_viu_set_osd_lut(struct meson_drm *priv, enum viu_lut_sel_e lut_sel,
18062306a36Sopenharmony_ci		      unsigned int *r_map, unsigned int *g_map,
18162306a36Sopenharmony_ci		      unsigned int *b_map, bool csc_on)
18262306a36Sopenharmony_ci{
18362306a36Sopenharmony_ci	unsigned int addr_port;
18462306a36Sopenharmony_ci	unsigned int data_port;
18562306a36Sopenharmony_ci	unsigned int ctrl_port;
18662306a36Sopenharmony_ci	int i;
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	if (lut_sel == VIU_LUT_OSD_EOTF) {
18962306a36Sopenharmony_ci		addr_port = VIU_OSD1_EOTF_LUT_ADDR_PORT;
19062306a36Sopenharmony_ci		data_port = VIU_OSD1_EOTF_LUT_DATA_PORT;
19162306a36Sopenharmony_ci		ctrl_port = VIU_OSD1_EOTF_CTL;
19262306a36Sopenharmony_ci	} else if (lut_sel == VIU_LUT_OSD_OETF) {
19362306a36Sopenharmony_ci		addr_port = VIU_OSD1_OETF_LUT_ADDR_PORT;
19462306a36Sopenharmony_ci		data_port = VIU_OSD1_OETF_LUT_DATA_PORT;
19562306a36Sopenharmony_ci		ctrl_port = VIU_OSD1_OETF_CTL;
19662306a36Sopenharmony_ci	} else
19762306a36Sopenharmony_ci		return;
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	if (lut_sel == VIU_LUT_OSD_OETF) {
20062306a36Sopenharmony_ci		writel(0, priv->io_base + _REG(addr_port));
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci		for (i = 0; i < (OSD_OETF_LUT_SIZE / 2); i++)
20362306a36Sopenharmony_ci			writel(r_map[i * 2] | (r_map[i * 2 + 1] << 16),
20462306a36Sopenharmony_ci				priv->io_base + _REG(data_port));
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci		writel(r_map[OSD_OETF_LUT_SIZE - 1] | (g_map[0] << 16),
20762306a36Sopenharmony_ci			priv->io_base + _REG(data_port));
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci		for (i = 0; i < (OSD_OETF_LUT_SIZE / 2); i++)
21062306a36Sopenharmony_ci			writel(g_map[i * 2 + 1] | (g_map[i * 2 + 2] << 16),
21162306a36Sopenharmony_ci				priv->io_base + _REG(data_port));
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci		for (i = 0; i < (OSD_OETF_LUT_SIZE / 2); i++)
21462306a36Sopenharmony_ci			writel(b_map[i * 2] | (b_map[i * 2 + 1] << 16),
21562306a36Sopenharmony_ci				priv->io_base + _REG(data_port));
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci		writel(b_map[OSD_OETF_LUT_SIZE - 1],
21862306a36Sopenharmony_ci			priv->io_base + _REG(data_port));
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci		if (csc_on)
22162306a36Sopenharmony_ci			writel_bits_relaxed(0x7 << 29, 7 << 29,
22262306a36Sopenharmony_ci					    priv->io_base + _REG(ctrl_port));
22362306a36Sopenharmony_ci		else
22462306a36Sopenharmony_ci			writel_bits_relaxed(0x7 << 29, 0,
22562306a36Sopenharmony_ci					    priv->io_base + _REG(ctrl_port));
22662306a36Sopenharmony_ci	} else if (lut_sel == VIU_LUT_OSD_EOTF) {
22762306a36Sopenharmony_ci		writel(0, priv->io_base + _REG(addr_port));
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci		for (i = 0; i < (OSD_EOTF_LUT_SIZE / 2); i++)
23062306a36Sopenharmony_ci			writel(r_map[i * 2] | (r_map[i * 2 + 1] << 16),
23162306a36Sopenharmony_ci				priv->io_base + _REG(data_port));
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci		writel(r_map[OSD_EOTF_LUT_SIZE - 1] | (g_map[0] << 16),
23462306a36Sopenharmony_ci			priv->io_base + _REG(data_port));
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci		for (i = 0; i < (OSD_EOTF_LUT_SIZE / 2); i++)
23762306a36Sopenharmony_ci			writel(g_map[i * 2 + 1] | (g_map[i * 2 + 2] << 16),
23862306a36Sopenharmony_ci				priv->io_base + _REG(data_port));
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci		for (i = 0; i < (OSD_EOTF_LUT_SIZE / 2); i++)
24162306a36Sopenharmony_ci			writel(b_map[i * 2] | (b_map[i * 2 + 1] << 16),
24262306a36Sopenharmony_ci				priv->io_base + _REG(data_port));
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci		writel(b_map[OSD_EOTF_LUT_SIZE - 1],
24562306a36Sopenharmony_ci			priv->io_base + _REG(data_port));
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci		if (csc_on)
24862306a36Sopenharmony_ci			writel_bits_relaxed(7 << 27, 7 << 27,
24962306a36Sopenharmony_ci					    priv->io_base + _REG(ctrl_port));
25062306a36Sopenharmony_ci		else
25162306a36Sopenharmony_ci			writel_bits_relaxed(7 << 27, 0,
25262306a36Sopenharmony_ci					    priv->io_base + _REG(ctrl_port));
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci		writel_bits_relaxed(BIT(31), BIT(31),
25562306a36Sopenharmony_ci				    priv->io_base + _REG(ctrl_port));
25662306a36Sopenharmony_ci	}
25762306a36Sopenharmony_ci}
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci/* eotf lut: linear */
26062306a36Sopenharmony_cistatic unsigned int eotf_33_linear_mapping[OSD_EOTF_LUT_SIZE] = {
26162306a36Sopenharmony_ci	0x0000,	0x0200,	0x0400, 0x0600,
26262306a36Sopenharmony_ci	0x0800, 0x0a00, 0x0c00, 0x0e00,
26362306a36Sopenharmony_ci	0x1000, 0x1200, 0x1400, 0x1600,
26462306a36Sopenharmony_ci	0x1800, 0x1a00, 0x1c00, 0x1e00,
26562306a36Sopenharmony_ci	0x2000, 0x2200, 0x2400, 0x2600,
26662306a36Sopenharmony_ci	0x2800, 0x2a00, 0x2c00, 0x2e00,
26762306a36Sopenharmony_ci	0x3000, 0x3200, 0x3400, 0x3600,
26862306a36Sopenharmony_ci	0x3800, 0x3a00, 0x3c00, 0x3e00,
26962306a36Sopenharmony_ci	0x4000
27062306a36Sopenharmony_ci};
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci/* osd oetf lut: linear */
27362306a36Sopenharmony_cistatic unsigned int oetf_41_linear_mapping[OSD_OETF_LUT_SIZE] = {
27462306a36Sopenharmony_ci	0, 0, 0, 0,
27562306a36Sopenharmony_ci	0, 32, 64, 96,
27662306a36Sopenharmony_ci	128, 160, 196, 224,
27762306a36Sopenharmony_ci	256, 288, 320, 352,
27862306a36Sopenharmony_ci	384, 416, 448, 480,
27962306a36Sopenharmony_ci	512, 544, 576, 608,
28062306a36Sopenharmony_ci	640, 672, 704, 736,
28162306a36Sopenharmony_ci	768, 800, 832, 864,
28262306a36Sopenharmony_ci	896, 928, 960, 992,
28362306a36Sopenharmony_ci	1023, 1023, 1023, 1023,
28462306a36Sopenharmony_ci	1023
28562306a36Sopenharmony_ci};
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_cistatic void meson_viu_load_matrix(struct meson_drm *priv)
28862306a36Sopenharmony_ci{
28962306a36Sopenharmony_ci	/* eotf lut bypass */
29062306a36Sopenharmony_ci	meson_viu_set_osd_lut(priv, VIU_LUT_OSD_EOTF,
29162306a36Sopenharmony_ci			      eotf_33_linear_mapping, /* R */
29262306a36Sopenharmony_ci			      eotf_33_linear_mapping, /* G */
29362306a36Sopenharmony_ci			      eotf_33_linear_mapping, /* B */
29462306a36Sopenharmony_ci			      false);
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	/* eotf matrix bypass */
29762306a36Sopenharmony_ci	meson_viu_set_osd_matrix(priv, VIU_MATRIX_OSD_EOTF,
29862306a36Sopenharmony_ci				 eotf_bypass_coeff,
29962306a36Sopenharmony_ci				 false);
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	/* oetf lut bypass */
30262306a36Sopenharmony_ci	meson_viu_set_osd_lut(priv, VIU_LUT_OSD_OETF,
30362306a36Sopenharmony_ci			      oetf_41_linear_mapping, /* R */
30462306a36Sopenharmony_ci			      oetf_41_linear_mapping, /* G */
30562306a36Sopenharmony_ci			      oetf_41_linear_mapping, /* B */
30662306a36Sopenharmony_ci			      false);
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	/* osd matrix RGB709 to YUV709 limit */
30962306a36Sopenharmony_ci	meson_viu_set_osd_matrix(priv, VIU_MATRIX_OSD,
31062306a36Sopenharmony_ci				 RGB709_to_YUV709l_coeff,
31162306a36Sopenharmony_ci				 true);
31262306a36Sopenharmony_ci}
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci/* VIU OSD1 Reset as workaround for GXL+ Alpha OSD Bug */
31562306a36Sopenharmony_civoid meson_viu_osd1_reset(struct meson_drm *priv)
31662306a36Sopenharmony_ci{
31762306a36Sopenharmony_ci	uint32_t osd1_fifo_ctrl_stat, osd1_ctrl_stat2;
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	/* Save these 2 registers state */
32062306a36Sopenharmony_ci	osd1_fifo_ctrl_stat = readl_relaxed(
32162306a36Sopenharmony_ci				priv->io_base + _REG(VIU_OSD1_FIFO_CTRL_STAT));
32262306a36Sopenharmony_ci	osd1_ctrl_stat2 = readl_relaxed(
32362306a36Sopenharmony_ci				priv->io_base + _REG(VIU_OSD1_CTRL_STAT2));
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	/* Reset OSD1 */
32662306a36Sopenharmony_ci	writel_bits_relaxed(VIU_SW_RESET_OSD1, VIU_SW_RESET_OSD1,
32762306a36Sopenharmony_ci			    priv->io_base + _REG(VIU_SW_RESET));
32862306a36Sopenharmony_ci	writel_bits_relaxed(VIU_SW_RESET_OSD1, 0,
32962306a36Sopenharmony_ci			    priv->io_base + _REG(VIU_SW_RESET));
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	/* Rewrite these registers state lost in the reset */
33262306a36Sopenharmony_ci	writel_relaxed(osd1_fifo_ctrl_stat,
33362306a36Sopenharmony_ci		       priv->io_base + _REG(VIU_OSD1_FIFO_CTRL_STAT));
33462306a36Sopenharmony_ci	writel_relaxed(osd1_ctrl_stat2,
33562306a36Sopenharmony_ci		       priv->io_base + _REG(VIU_OSD1_CTRL_STAT2));
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	/* Reload the conversion matrix */
33862306a36Sopenharmony_ci	meson_viu_load_matrix(priv);
33962306a36Sopenharmony_ci}
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci#define OSD1_MALI_ORDER_ABGR				\
34262306a36Sopenharmony_ci	(FIELD_PREP(VIU_OSD1_MALI_AFBCD_A_REORDER,	\
34362306a36Sopenharmony_ci		    VIU_OSD1_MALI_REORDER_A) |		\
34462306a36Sopenharmony_ci	 FIELD_PREP(VIU_OSD1_MALI_AFBCD_B_REORDER,	\
34562306a36Sopenharmony_ci		    VIU_OSD1_MALI_REORDER_B) |		\
34662306a36Sopenharmony_ci	 FIELD_PREP(VIU_OSD1_MALI_AFBCD_G_REORDER,	\
34762306a36Sopenharmony_ci		    VIU_OSD1_MALI_REORDER_G) |		\
34862306a36Sopenharmony_ci	 FIELD_PREP(VIU_OSD1_MALI_AFBCD_R_REORDER,	\
34962306a36Sopenharmony_ci		    VIU_OSD1_MALI_REORDER_R))
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci#define OSD1_MALI_ORDER_ARGB				\
35262306a36Sopenharmony_ci	(FIELD_PREP(VIU_OSD1_MALI_AFBCD_A_REORDER,	\
35362306a36Sopenharmony_ci		    VIU_OSD1_MALI_REORDER_A) |		\
35462306a36Sopenharmony_ci	 FIELD_PREP(VIU_OSD1_MALI_AFBCD_B_REORDER,	\
35562306a36Sopenharmony_ci		    VIU_OSD1_MALI_REORDER_R) |		\
35662306a36Sopenharmony_ci	 FIELD_PREP(VIU_OSD1_MALI_AFBCD_G_REORDER,	\
35762306a36Sopenharmony_ci		    VIU_OSD1_MALI_REORDER_G) |		\
35862306a36Sopenharmony_ci	 FIELD_PREP(VIU_OSD1_MALI_AFBCD_R_REORDER,	\
35962306a36Sopenharmony_ci		    VIU_OSD1_MALI_REORDER_B))
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_civoid meson_viu_g12a_enable_osd1_afbc(struct meson_drm *priv)
36262306a36Sopenharmony_ci{
36362306a36Sopenharmony_ci	u32 afbc_order = OSD1_MALI_ORDER_ARGB;
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	/* Enable Mali AFBC Unpack */
36662306a36Sopenharmony_ci	writel_bits_relaxed(VIU_OSD1_MALI_UNPACK_EN,
36762306a36Sopenharmony_ci			    VIU_OSD1_MALI_UNPACK_EN,
36862306a36Sopenharmony_ci			    priv->io_base + _REG(VIU_OSD1_MALI_UNPACK_CTRL));
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	switch (priv->afbcd.format) {
37162306a36Sopenharmony_ci	case DRM_FORMAT_XBGR8888:
37262306a36Sopenharmony_ci	case DRM_FORMAT_ABGR8888:
37362306a36Sopenharmony_ci		afbc_order = OSD1_MALI_ORDER_ABGR;
37462306a36Sopenharmony_ci		break;
37562306a36Sopenharmony_ci	}
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	/* Setup RGBA Reordering */
37862306a36Sopenharmony_ci	writel_bits_relaxed(VIU_OSD1_MALI_AFBCD_A_REORDER |
37962306a36Sopenharmony_ci			    VIU_OSD1_MALI_AFBCD_B_REORDER |
38062306a36Sopenharmony_ci			    VIU_OSD1_MALI_AFBCD_G_REORDER |
38162306a36Sopenharmony_ci			    VIU_OSD1_MALI_AFBCD_R_REORDER,
38262306a36Sopenharmony_ci			    afbc_order,
38362306a36Sopenharmony_ci			    priv->io_base + _REG(VIU_OSD1_MALI_UNPACK_CTRL));
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	/* Select AFBCD path for OSD1 */
38662306a36Sopenharmony_ci	writel_bits_relaxed(OSD_PATH_OSD_AXI_SEL_OSD1_AFBCD,
38762306a36Sopenharmony_ci			    OSD_PATH_OSD_AXI_SEL_OSD1_AFBCD,
38862306a36Sopenharmony_ci			    priv->io_base + _REG(OSD_PATH_MISC_CTRL));
38962306a36Sopenharmony_ci}
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_civoid meson_viu_g12a_disable_osd1_afbc(struct meson_drm *priv)
39262306a36Sopenharmony_ci{
39362306a36Sopenharmony_ci	/* Disable AFBCD path for OSD1 */
39462306a36Sopenharmony_ci	writel_bits_relaxed(OSD_PATH_OSD_AXI_SEL_OSD1_AFBCD, 0,
39562306a36Sopenharmony_ci			    priv->io_base + _REG(OSD_PATH_MISC_CTRL));
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	/* Disable AFBCD unpack */
39862306a36Sopenharmony_ci	writel_bits_relaxed(VIU_OSD1_MALI_UNPACK_EN, 0,
39962306a36Sopenharmony_ci			    priv->io_base + _REG(VIU_OSD1_MALI_UNPACK_CTRL));
40062306a36Sopenharmony_ci}
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_civoid meson_viu_gxm_enable_osd1_afbc(struct meson_drm *priv)
40362306a36Sopenharmony_ci{
40462306a36Sopenharmony_ci	writel_bits_relaxed(MALI_AFBC_MISC, FIELD_PREP(MALI_AFBC_MISC, 0x90),
40562306a36Sopenharmony_ci			    priv->io_base + _REG(VIU_MISC_CTRL1));
40662306a36Sopenharmony_ci}
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_civoid meson_viu_gxm_disable_osd1_afbc(struct meson_drm *priv)
40962306a36Sopenharmony_ci{
41062306a36Sopenharmony_ci	writel_bits_relaxed(MALI_AFBC_MISC, FIELD_PREP(MALI_AFBC_MISC, 0x00),
41162306a36Sopenharmony_ci			    priv->io_base + _REG(VIU_MISC_CTRL1));
41262306a36Sopenharmony_ci}
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_civoid meson_viu_init(struct meson_drm *priv)
41562306a36Sopenharmony_ci{
41662306a36Sopenharmony_ci	uint32_t reg;
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	/* Disable OSDs */
41962306a36Sopenharmony_ci	writel_bits_relaxed(VIU_OSD1_OSD_BLK_ENABLE | VIU_OSD1_OSD_ENABLE, 0,
42062306a36Sopenharmony_ci			    priv->io_base + _REG(VIU_OSD1_CTRL_STAT));
42162306a36Sopenharmony_ci	writel_bits_relaxed(VIU_OSD1_OSD_BLK_ENABLE | VIU_OSD1_OSD_ENABLE, 0,
42262306a36Sopenharmony_ci			    priv->io_base + _REG(VIU_OSD2_CTRL_STAT));
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	/* On GXL/GXM, Use the 10bit HDR conversion matrix */
42562306a36Sopenharmony_ci	if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) ||
42662306a36Sopenharmony_ci	    meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXL))
42762306a36Sopenharmony_ci		meson_viu_load_matrix(priv);
42862306a36Sopenharmony_ci	else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) {
42962306a36Sopenharmony_ci		meson_viu_set_g12a_osd1_matrix(priv, RGB709_to_YUV709l_coeff,
43062306a36Sopenharmony_ci					       true);
43162306a36Sopenharmony_ci		/* fix green/pink color distortion from vendor u-boot */
43262306a36Sopenharmony_ci		writel_bits_relaxed(OSD1_HDR2_CTRL_REG_ONLY_MAT |
43362306a36Sopenharmony_ci				OSD1_HDR2_CTRL_VDIN0_HDR2_TOP_EN, 0,
43462306a36Sopenharmony_ci				priv->io_base + _REG(OSD1_HDR2_CTRL));
43562306a36Sopenharmony_ci	}
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	/* Initialize OSD1 fifo control register */
43862306a36Sopenharmony_ci	reg = VIU_OSD_DDR_PRIORITY_URGENT |
43962306a36Sopenharmony_ci		VIU_OSD_FIFO_DEPTH_VAL(32) | /* fifo_depth_val: 32*8=256 */
44062306a36Sopenharmony_ci		VIU_OSD_WORDS_PER_BURST(4) | /* 4 words in 1 burst */
44162306a36Sopenharmony_ci		VIU_OSD_FIFO_LIMITS(2);      /* fifo_lim: 2*16=32 */
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A))
44462306a36Sopenharmony_ci		reg |= (VIU_OSD_BURST_LENGTH_32 | VIU_OSD_HOLD_FIFO_LINES(31));
44562306a36Sopenharmony_ci	else
44662306a36Sopenharmony_ci		reg |= (VIU_OSD_BURST_LENGTH_64 | VIU_OSD_HOLD_FIFO_LINES(4));
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	writel_relaxed(reg, priv->io_base + _REG(VIU_OSD1_FIFO_CTRL_STAT));
44962306a36Sopenharmony_ci	writel_relaxed(reg, priv->io_base + _REG(VIU_OSD2_FIFO_CTRL_STAT));
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	/* Set OSD alpha replace value */
45262306a36Sopenharmony_ci	writel_bits_relaxed(0xff << OSD_REPLACE_SHIFT,
45362306a36Sopenharmony_ci			    0xff << OSD_REPLACE_SHIFT,
45462306a36Sopenharmony_ci			    priv->io_base + _REG(VIU_OSD1_CTRL_STAT2));
45562306a36Sopenharmony_ci	writel_bits_relaxed(0xff << OSD_REPLACE_SHIFT,
45662306a36Sopenharmony_ci			    0xff << OSD_REPLACE_SHIFT,
45762306a36Sopenharmony_ci			    priv->io_base + _REG(VIU_OSD2_CTRL_STAT2));
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci	/* Disable VD1 AFBC */
46062306a36Sopenharmony_ci	/* di_mif0_en=0 mif0_to_vpp_en=0 di_mad_en=0 and afbc vd1 set=0*/
46162306a36Sopenharmony_ci	writel_bits_relaxed(VIU_CTRL0_VD1_AFBC_MASK, 0,
46262306a36Sopenharmony_ci			    priv->io_base + _REG(VIU_MISC_CTRL0));
46362306a36Sopenharmony_ci	writel_relaxed(0, priv->io_base + _REG(AFBC_ENABLE));
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci	writel_relaxed(0x00FF00C0,
46662306a36Sopenharmony_ci			priv->io_base + _REG(VD1_IF0_LUMA_FIFO_SIZE));
46762306a36Sopenharmony_ci	writel_relaxed(0x00FF00C0,
46862306a36Sopenharmony_ci			priv->io_base + _REG(VD2_IF0_LUMA_FIFO_SIZE));
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci	if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) {
47162306a36Sopenharmony_ci		u32 val = (u32)VIU_OSD_BLEND_REORDER(0, 1) |
47262306a36Sopenharmony_ci			  (u32)VIU_OSD_BLEND_REORDER(1, 0) |
47362306a36Sopenharmony_ci			  (u32)VIU_OSD_BLEND_REORDER(2, 0) |
47462306a36Sopenharmony_ci			  (u32)VIU_OSD_BLEND_REORDER(3, 0) |
47562306a36Sopenharmony_ci			  (u32)VIU_OSD_BLEND_DIN_EN(1) |
47662306a36Sopenharmony_ci			  (u32)VIU_OSD_BLEND1_DIN3_BYPASS_TO_DOUT1 |
47762306a36Sopenharmony_ci			  (u32)VIU_OSD_BLEND1_DOUT_BYPASS_TO_BLEND2 |
47862306a36Sopenharmony_ci			  (u32)VIU_OSD_BLEND_DIN0_BYPASS_TO_DOUT0 |
47962306a36Sopenharmony_ci			  (u32)VIU_OSD_BLEND_BLEN2_PREMULT_EN(1) |
48062306a36Sopenharmony_ci			  (u32)VIU_OSD_BLEND_HOLD_LINES(4);
48162306a36Sopenharmony_ci		writel_relaxed(val, priv->io_base + _REG(VIU_OSD_BLEND_CTRL));
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci		writel_relaxed(OSD_BLEND_PATH_SEL_ENABLE,
48462306a36Sopenharmony_ci			       priv->io_base + _REG(OSD1_BLEND_SRC_CTRL));
48562306a36Sopenharmony_ci		writel_relaxed(OSD_BLEND_PATH_SEL_ENABLE,
48662306a36Sopenharmony_ci			       priv->io_base + _REG(OSD2_BLEND_SRC_CTRL));
48762306a36Sopenharmony_ci		writel_relaxed(0, priv->io_base + _REG(VD1_BLEND_SRC_CTRL));
48862306a36Sopenharmony_ci		writel_relaxed(0, priv->io_base + _REG(VD2_BLEND_SRC_CTRL));
48962306a36Sopenharmony_ci		writel_relaxed(0,
49062306a36Sopenharmony_ci				priv->io_base + _REG(VIU_OSD_BLEND_DUMMY_DATA0));
49162306a36Sopenharmony_ci		writel_relaxed(0,
49262306a36Sopenharmony_ci				priv->io_base + _REG(VIU_OSD_BLEND_DUMMY_ALPHA));
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci		writel_bits_relaxed(DOLBY_BYPASS_EN(0xc), DOLBY_BYPASS_EN(0xc),
49562306a36Sopenharmony_ci				    priv->io_base + _REG(DOLBY_PATH_CTRL));
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci		meson_viu_g12a_disable_osd1_afbc(priv);
49862306a36Sopenharmony_ci	}
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci	if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM))
50162306a36Sopenharmony_ci		meson_viu_gxm_disable_osd1_afbc(priv);
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci	priv->viu.osd1_enabled = false;
50462306a36Sopenharmony_ci	priv->viu.osd1_commit = false;
50562306a36Sopenharmony_ci	priv->viu.osd1_interlace = false;
50662306a36Sopenharmony_ci}
507