162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2018 BayLibre, SAS
462306a36Sopenharmony_ci * Author: Neil Armstrong <narmstrong@baylibre.com>
562306a36Sopenharmony_ci * Copyright (C) 2015 Amlogic, Inc. All rights reserved.
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/bitfield.h>
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <drm/drm_atomic.h>
1162306a36Sopenharmony_ci#include <drm/drm_atomic_helper.h>
1262306a36Sopenharmony_ci#include <drm/drm_blend.h>
1362306a36Sopenharmony_ci#include <drm/drm_device.h>
1462306a36Sopenharmony_ci#include <drm/drm_fb_dma_helper.h>
1562306a36Sopenharmony_ci#include <drm/drm_fourcc.h>
1662306a36Sopenharmony_ci#include <drm/drm_framebuffer.h>
1762306a36Sopenharmony_ci#include <drm/drm_gem_atomic_helper.h>
1862306a36Sopenharmony_ci#include <drm/drm_gem_dma_helper.h>
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#include "meson_overlay.h"
2162306a36Sopenharmony_ci#include "meson_registers.h"
2262306a36Sopenharmony_ci#include "meson_viu.h"
2362306a36Sopenharmony_ci#include "meson_vpp.h"
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci/* VD1_IF0_GEN_REG */
2662306a36Sopenharmony_ci#define VD_URGENT_CHROMA		BIT(28)
2762306a36Sopenharmony_ci#define VD_URGENT_LUMA			BIT(27)
2862306a36Sopenharmony_ci#define VD_HOLD_LINES(lines)		FIELD_PREP(GENMASK(24, 19), lines)
2962306a36Sopenharmony_ci#define VD_DEMUX_MODE_RGB		BIT(16)
3062306a36Sopenharmony_ci#define VD_BYTES_PER_PIXEL(val)		FIELD_PREP(GENMASK(15, 14), val)
3162306a36Sopenharmony_ci#define VD_CHRO_RPT_LASTL_CTRL		BIT(6)
3262306a36Sopenharmony_ci#define VD_LITTLE_ENDIAN		BIT(4)
3362306a36Sopenharmony_ci#define VD_SEPARATE_EN			BIT(1)
3462306a36Sopenharmony_ci#define VD_ENABLE			BIT(0)
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci/* VD1_IF0_CANVAS0 */
3762306a36Sopenharmony_ci#define CANVAS_ADDR2(addr)		FIELD_PREP(GENMASK(23, 16), addr)
3862306a36Sopenharmony_ci#define CANVAS_ADDR1(addr)		FIELD_PREP(GENMASK(15, 8), addr)
3962306a36Sopenharmony_ci#define CANVAS_ADDR0(addr)		FIELD_PREP(GENMASK(7, 0), addr)
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci/* VD1_IF0_LUMA_X0 VD1_IF0_CHROMA_X0 */
4262306a36Sopenharmony_ci#define VD_X_START(value)		FIELD_PREP(GENMASK(14, 0), value)
4362306a36Sopenharmony_ci#define VD_X_END(value)			FIELD_PREP(GENMASK(30, 16), value)
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci/* VD1_IF0_LUMA_Y0 VD1_IF0_CHROMA_Y0 */
4662306a36Sopenharmony_ci#define VD_Y_START(value)		FIELD_PREP(GENMASK(12, 0), value)
4762306a36Sopenharmony_ci#define VD_Y_END(value)			FIELD_PREP(GENMASK(28, 16), value)
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci/* VD1_IF0_GEN_REG2 */
5062306a36Sopenharmony_ci#define VD_COLOR_MAP(value)		FIELD_PREP(GENMASK(1, 0), value)
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci/* VIU_VD1_FMT_CTRL */
5362306a36Sopenharmony_ci#define VD_HORZ_Y_C_RATIO(value)	FIELD_PREP(GENMASK(22, 21), value)
5462306a36Sopenharmony_ci#define VD_HORZ_FMT_EN			BIT(20)
5562306a36Sopenharmony_ci#define VD_VERT_RPT_LINE0		BIT(16)
5662306a36Sopenharmony_ci#define VD_VERT_INITIAL_PHASE(value)	FIELD_PREP(GENMASK(11, 8), value)
5762306a36Sopenharmony_ci#define VD_VERT_PHASE_STEP(value)	FIELD_PREP(GENMASK(7, 1), value)
5862306a36Sopenharmony_ci#define VD_VERT_FMT_EN			BIT(0)
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci/* VPP_POSTBLEND_VD1_H_START_END */
6162306a36Sopenharmony_ci#define VD_H_END(value)			FIELD_PREP(GENMASK(11, 0), value)
6262306a36Sopenharmony_ci#define VD_H_START(value)		FIELD_PREP(GENMASK(27, 16), \
6362306a36Sopenharmony_ci						   ((value) & GENMASK(13, 0)))
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci/* VPP_POSTBLEND_VD1_V_START_END */
6662306a36Sopenharmony_ci#define VD_V_END(value)			FIELD_PREP(GENMASK(11, 0), value)
6762306a36Sopenharmony_ci#define VD_V_START(value)		FIELD_PREP(GENMASK(27, 16), value)
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci/* VPP_BLEND_VD2_V_START_END */
7062306a36Sopenharmony_ci#define VD2_V_END(value)		FIELD_PREP(GENMASK(11, 0), value)
7162306a36Sopenharmony_ci#define VD2_V_START(value)		FIELD_PREP(GENMASK(27, 16), value)
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci/* VIU_VD1_FMT_W */
7462306a36Sopenharmony_ci#define VD_V_WIDTH(value)		FIELD_PREP(GENMASK(11, 0), value)
7562306a36Sopenharmony_ci#define VD_H_WIDTH(value)		FIELD_PREP(GENMASK(27, 16), value)
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci/* VPP_HSC_REGION12_STARTP VPP_HSC_REGION34_STARTP */
7862306a36Sopenharmony_ci#define VD_REGION24_START(value)	FIELD_PREP(GENMASK(11, 0), value)
7962306a36Sopenharmony_ci#define VD_REGION13_END(value)		FIELD_PREP(GENMASK(27, 16), value)
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci/* AFBC_ENABLE */
8262306a36Sopenharmony_ci#define AFBC_DEC_ENABLE			BIT(8)
8362306a36Sopenharmony_ci#define AFBC_FRM_START			BIT(0)
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci/* AFBC_MODE */
8662306a36Sopenharmony_ci#define AFBC_HORZ_SKIP_UV(value)	FIELD_PREP(GENMASK(1, 0), value)
8762306a36Sopenharmony_ci#define AFBC_VERT_SKIP_UV(value)	FIELD_PREP(GENMASK(3, 2), value)
8862306a36Sopenharmony_ci#define AFBC_HORZ_SKIP_Y(value)		FIELD_PREP(GENMASK(5, 4), value)
8962306a36Sopenharmony_ci#define AFBC_VERT_SKIP_Y(value)		FIELD_PREP(GENMASK(7, 6), value)
9062306a36Sopenharmony_ci#define AFBC_COMPBITS_YUV(value)	FIELD_PREP(GENMASK(13, 8), value)
9162306a36Sopenharmony_ci#define AFBC_COMPBITS_8BIT		0
9262306a36Sopenharmony_ci#define AFBC_COMPBITS_10BIT		(2 | (2 << 2) | (2 << 4))
9362306a36Sopenharmony_ci#define AFBC_BURST_LEN(value)		FIELD_PREP(GENMASK(15, 14), value)
9462306a36Sopenharmony_ci#define AFBC_HOLD_LINE_NUM(value)	FIELD_PREP(GENMASK(22, 16), value)
9562306a36Sopenharmony_ci#define AFBC_MIF_URGENT(value)		FIELD_PREP(GENMASK(25, 24), value)
9662306a36Sopenharmony_ci#define AFBC_REV_MODE(value)		FIELD_PREP(GENMASK(27, 26), value)
9762306a36Sopenharmony_ci#define AFBC_BLK_MEM_MODE		BIT(28)
9862306a36Sopenharmony_ci#define AFBC_SCATTER_MODE		BIT(29)
9962306a36Sopenharmony_ci#define AFBC_SOFT_RESET			BIT(31)
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci/* AFBC_SIZE_IN */
10262306a36Sopenharmony_ci#define AFBC_HSIZE_IN(value)		FIELD_PREP(GENMASK(28, 16), value)
10362306a36Sopenharmony_ci#define AFBC_VSIZE_IN(value)		FIELD_PREP(GENMASK(12, 0), value)
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci/* AFBC_DEC_DEF_COLOR */
10662306a36Sopenharmony_ci#define AFBC_DEF_COLOR_Y(value)		FIELD_PREP(GENMASK(29, 20), value)
10762306a36Sopenharmony_ci#define AFBC_DEF_COLOR_U(value)		FIELD_PREP(GENMASK(19, 10), value)
10862306a36Sopenharmony_ci#define AFBC_DEF_COLOR_V(value)		FIELD_PREP(GENMASK(9, 0), value)
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci/* AFBC_CONV_CTRL */
11162306a36Sopenharmony_ci#define AFBC_CONV_LBUF_LEN(value)	FIELD_PREP(GENMASK(11, 0), value)
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci/* AFBC_LBUF_DEPTH */
11462306a36Sopenharmony_ci#define AFBC_DEC_LBUF_DEPTH(value)	FIELD_PREP(GENMASK(27, 16), value)
11562306a36Sopenharmony_ci#define AFBC_MIF_LBUF_DEPTH(value)	FIELD_PREP(GENMASK(11, 0), value)
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci/* AFBC_OUT_XSCOPE/AFBC_SIZE_OUT */
11862306a36Sopenharmony_ci#define AFBC_HSIZE_OUT(value)		FIELD_PREP(GENMASK(28, 16), value)
11962306a36Sopenharmony_ci#define AFBC_VSIZE_OUT(value)		FIELD_PREP(GENMASK(12, 0), value)
12062306a36Sopenharmony_ci#define AFBC_OUT_HORZ_BGN(value)	FIELD_PREP(GENMASK(28, 16), value)
12162306a36Sopenharmony_ci#define AFBC_OUT_HORZ_END(value)	FIELD_PREP(GENMASK(12, 0), value)
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci/* AFBC_OUT_YSCOPE */
12462306a36Sopenharmony_ci#define AFBC_OUT_VERT_BGN(value)	FIELD_PREP(GENMASK(28, 16), value)
12562306a36Sopenharmony_ci#define AFBC_OUT_VERT_END(value)	FIELD_PREP(GENMASK(12, 0), value)
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci/* AFBC_VD_CFMT_CTRL */
12862306a36Sopenharmony_ci#define AFBC_HORZ_RPT_PIXEL0		BIT(23)
12962306a36Sopenharmony_ci#define AFBC_HORZ_Y_C_RATIO(value)	FIELD_PREP(GENMASK(22, 21), value)
13062306a36Sopenharmony_ci#define AFBC_HORZ_FMT_EN		BIT(20)
13162306a36Sopenharmony_ci#define AFBC_VERT_RPT_LINE0		BIT(16)
13262306a36Sopenharmony_ci#define AFBC_VERT_INITIAL_PHASE(value)	FIELD_PREP(GENMASK(11, 8), value)
13362306a36Sopenharmony_ci#define AFBC_VERT_PHASE_STEP(value)	FIELD_PREP(GENMASK(7, 1), value)
13462306a36Sopenharmony_ci#define AFBC_VERT_FMT_EN		BIT(0)
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci/* AFBC_VD_CFMT_W */
13762306a36Sopenharmony_ci#define AFBC_VD_V_WIDTH(value)		FIELD_PREP(GENMASK(11, 0), value)
13862306a36Sopenharmony_ci#define AFBC_VD_H_WIDTH(value)		FIELD_PREP(GENMASK(27, 16), value)
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci/* AFBC_MIF_HOR_SCOPE */
14162306a36Sopenharmony_ci#define AFBC_MIF_BLK_BGN_H(value)	FIELD_PREP(GENMASK(25, 16), value)
14262306a36Sopenharmony_ci#define AFBC_MIF_BLK_END_H(value)	FIELD_PREP(GENMASK(9, 0), value)
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci/* AFBC_MIF_VER_SCOPE */
14562306a36Sopenharmony_ci#define AFBC_MIF_BLK_BGN_V(value)	FIELD_PREP(GENMASK(27, 16), value)
14662306a36Sopenharmony_ci#define AFBC_MIF_BLK_END_V(value)	FIELD_PREP(GENMASK(11, 0), value)
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci/* AFBC_PIXEL_HOR_SCOPE */
14962306a36Sopenharmony_ci#define AFBC_DEC_PIXEL_BGN_H(value)	FIELD_PREP(GENMASK(28, 16), \
15062306a36Sopenharmony_ci						   ((value) & GENMASK(12, 0)))
15162306a36Sopenharmony_ci#define AFBC_DEC_PIXEL_END_H(value)	FIELD_PREP(GENMASK(12, 0), value)
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci/* AFBC_PIXEL_VER_SCOPE */
15462306a36Sopenharmony_ci#define AFBC_DEC_PIXEL_BGN_V(value)	FIELD_PREP(GENMASK(28, 16), value)
15562306a36Sopenharmony_ci#define AFBC_DEC_PIXEL_END_V(value)	FIELD_PREP(GENMASK(12, 0), value)
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci/* AFBC_VD_CFMT_H */
15862306a36Sopenharmony_ci#define AFBC_VD_HEIGHT(value)		FIELD_PREP(GENMASK(12, 0), value)
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_cistruct meson_overlay {
16162306a36Sopenharmony_ci	struct drm_plane base;
16262306a36Sopenharmony_ci	struct meson_drm *priv;
16362306a36Sopenharmony_ci};
16462306a36Sopenharmony_ci#define to_meson_overlay(x) container_of(x, struct meson_overlay, base)
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci#define FRAC_16_16(mult, div)    (((mult) << 16) / (div))
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_cistatic int meson_overlay_atomic_check(struct drm_plane *plane,
16962306a36Sopenharmony_ci				      struct drm_atomic_state *state)
17062306a36Sopenharmony_ci{
17162306a36Sopenharmony_ci	struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
17262306a36Sopenharmony_ci										 plane);
17362306a36Sopenharmony_ci	struct drm_crtc_state *crtc_state;
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	if (!new_plane_state->crtc)
17662306a36Sopenharmony_ci		return 0;
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	crtc_state = drm_atomic_get_crtc_state(state,
17962306a36Sopenharmony_ci					       new_plane_state->crtc);
18062306a36Sopenharmony_ci	if (IS_ERR(crtc_state))
18162306a36Sopenharmony_ci		return PTR_ERR(crtc_state);
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	return drm_atomic_helper_check_plane_state(new_plane_state,
18462306a36Sopenharmony_ci						   crtc_state,
18562306a36Sopenharmony_ci						   FRAC_16_16(1, 5),
18662306a36Sopenharmony_ci						   FRAC_16_16(5, 1),
18762306a36Sopenharmony_ci						   true, true);
18862306a36Sopenharmony_ci}
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci/* Takes a fixed 16.16 number and converts it to integer. */
19162306a36Sopenharmony_cistatic inline int64_t fixed16_to_int(int64_t value)
19262306a36Sopenharmony_ci{
19362306a36Sopenharmony_ci	return value >> 16;
19462306a36Sopenharmony_ci}
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_cistatic const uint8_t skip_tab[6] = {
19762306a36Sopenharmony_ci	0x24, 0x04, 0x68, 0x48, 0x28, 0x08,
19862306a36Sopenharmony_ci};
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_cistatic void meson_overlay_get_vertical_phase(unsigned int ratio_y, int *phase,
20162306a36Sopenharmony_ci					     int *repeat, bool interlace)
20262306a36Sopenharmony_ci{
20362306a36Sopenharmony_ci	int offset_in = 0;
20462306a36Sopenharmony_ci	int offset_out = 0;
20562306a36Sopenharmony_ci	int repeat_skip = 0;
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	if (!interlace && ratio_y > (1 << 18))
20862306a36Sopenharmony_ci		offset_out = (1 * ratio_y) >> 10;
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	while ((offset_in + (4 << 8)) <= offset_out) {
21162306a36Sopenharmony_ci		repeat_skip++;
21262306a36Sopenharmony_ci		offset_in += 4 << 8;
21362306a36Sopenharmony_ci	}
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	*phase = (offset_out - offset_in) >> 2;
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	if (*phase > 0x100)
21862306a36Sopenharmony_ci		repeat_skip++;
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	*phase = *phase & 0xff;
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	if (repeat_skip > 5)
22362306a36Sopenharmony_ci		repeat_skip = 5;
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	*repeat = skip_tab[repeat_skip];
22662306a36Sopenharmony_ci}
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_cistatic void meson_overlay_setup_scaler_params(struct meson_drm *priv,
22962306a36Sopenharmony_ci					      struct drm_plane *plane,
23062306a36Sopenharmony_ci					      bool interlace_mode)
23162306a36Sopenharmony_ci{
23262306a36Sopenharmony_ci	struct drm_crtc_state *crtc_state = priv->crtc->state;
23362306a36Sopenharmony_ci	int video_top, video_left, video_width, video_height;
23462306a36Sopenharmony_ci	struct drm_plane_state *state = plane->state;
23562306a36Sopenharmony_ci	unsigned int vd_start_lines, vd_end_lines;
23662306a36Sopenharmony_ci	unsigned int hd_start_lines, hd_end_lines;
23762306a36Sopenharmony_ci	unsigned int crtc_height, crtc_width;
23862306a36Sopenharmony_ci	unsigned int vsc_startp, vsc_endp;
23962306a36Sopenharmony_ci	unsigned int hsc_startp, hsc_endp;
24062306a36Sopenharmony_ci	unsigned int crop_top, crop_left;
24162306a36Sopenharmony_ci	int vphase, vphase_repeat_skip;
24262306a36Sopenharmony_ci	unsigned int ratio_x, ratio_y;
24362306a36Sopenharmony_ci	int temp_height, temp_width;
24462306a36Sopenharmony_ci	unsigned int w_in, h_in;
24562306a36Sopenharmony_ci	int afbc_left, afbc_right;
24662306a36Sopenharmony_ci	int afbc_top_src, afbc_bottom_src;
24762306a36Sopenharmony_ci	int afbc_top, afbc_bottom;
24862306a36Sopenharmony_ci	int temp, start, end;
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	if (!crtc_state) {
25162306a36Sopenharmony_ci		DRM_ERROR("Invalid crtc_state\n");
25262306a36Sopenharmony_ci		return;
25362306a36Sopenharmony_ci	}
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	crtc_height = crtc_state->mode.vdisplay;
25662306a36Sopenharmony_ci	crtc_width = crtc_state->mode.hdisplay;
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	w_in = fixed16_to_int(state->src_w);
25962306a36Sopenharmony_ci	h_in = fixed16_to_int(state->src_h);
26062306a36Sopenharmony_ci	crop_top = fixed16_to_int(state->src_y);
26162306a36Sopenharmony_ci	crop_left = fixed16_to_int(state->src_x);
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	video_top = state->crtc_y;
26462306a36Sopenharmony_ci	video_left = state->crtc_x;
26562306a36Sopenharmony_ci	video_width = state->crtc_w;
26662306a36Sopenharmony_ci	video_height = state->crtc_h;
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	DRM_DEBUG("crtc_width %d crtc_height %d interlace %d\n",
26962306a36Sopenharmony_ci		  crtc_width, crtc_height, interlace_mode);
27062306a36Sopenharmony_ci	DRM_DEBUG("w_in %d h_in %d crop_top %d crop_left %d\n",
27162306a36Sopenharmony_ci		  w_in, h_in, crop_top, crop_left);
27262306a36Sopenharmony_ci	DRM_DEBUG("video top %d left %d width %d height %d\n",
27362306a36Sopenharmony_ci		  video_top, video_left, video_width, video_height);
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	ratio_x = (w_in << 18) / video_width;
27662306a36Sopenharmony_ci	ratio_y = (h_in << 18) / video_height;
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	if (ratio_x * video_width < (w_in << 18))
27962306a36Sopenharmony_ci		ratio_x++;
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	DRM_DEBUG("ratio x 0x%x y 0x%x\n", ratio_x, ratio_y);
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	meson_overlay_get_vertical_phase(ratio_y, &vphase, &vphase_repeat_skip,
28462306a36Sopenharmony_ci					 interlace_mode);
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	DRM_DEBUG("vphase 0x%x skip %d\n", vphase, vphase_repeat_skip);
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	/* Vertical */
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	start = video_top + video_height / 2 - ((h_in << 17) / ratio_y);
29162306a36Sopenharmony_ci	end = (h_in << 18) / ratio_y + start - 1;
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	if (video_top < 0 && start < 0)
29462306a36Sopenharmony_ci		vd_start_lines = (-(start) * ratio_y) >> 18;
29562306a36Sopenharmony_ci	else if (start < video_top)
29662306a36Sopenharmony_ci		vd_start_lines = ((video_top - start) * ratio_y) >> 18;
29762306a36Sopenharmony_ci	else
29862306a36Sopenharmony_ci		vd_start_lines = 0;
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	if (video_top < 0)
30162306a36Sopenharmony_ci		temp_height = min_t(unsigned int,
30262306a36Sopenharmony_ci				    video_top + video_height - 1,
30362306a36Sopenharmony_ci				    crtc_height - 1);
30462306a36Sopenharmony_ci	else
30562306a36Sopenharmony_ci		temp_height = min_t(unsigned int,
30662306a36Sopenharmony_ci				    video_top + video_height - 1,
30762306a36Sopenharmony_ci				    crtc_height - 1) - video_top + 1;
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	temp = vd_start_lines + (temp_height * ratio_y >> 18);
31062306a36Sopenharmony_ci	vd_end_lines = (temp <= (h_in - 1)) ? temp : (h_in - 1);
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	vd_start_lines += crop_left;
31362306a36Sopenharmony_ci	vd_end_lines += crop_left;
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	/*
31662306a36Sopenharmony_ci	 * TOFIX: Input frames are handled and scaled like progressive frames,
31762306a36Sopenharmony_ci	 * proper handling of interlaced field input frames need to be figured
31862306a36Sopenharmony_ci	 * out using the proper framebuffer flags set by userspace.
31962306a36Sopenharmony_ci	 */
32062306a36Sopenharmony_ci	if (interlace_mode) {
32162306a36Sopenharmony_ci		start >>= 1;
32262306a36Sopenharmony_ci		end >>= 1;
32362306a36Sopenharmony_ci	}
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	vsc_startp = max_t(int, start,
32662306a36Sopenharmony_ci			   max_t(int, 0, video_top));
32762306a36Sopenharmony_ci	vsc_endp = min_t(int, end,
32862306a36Sopenharmony_ci			 min_t(int, crtc_height - 1,
32962306a36Sopenharmony_ci			       video_top + video_height - 1));
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	DRM_DEBUG("vsc startp %d endp %d start_lines %d end_lines %d\n",
33262306a36Sopenharmony_ci		 vsc_startp, vsc_endp, vd_start_lines, vd_end_lines);
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci	afbc_top = round_down(vd_start_lines, 4);
33562306a36Sopenharmony_ci	afbc_bottom = round_up(vd_end_lines + 1, 4);
33662306a36Sopenharmony_ci	afbc_top_src = 0;
33762306a36Sopenharmony_ci	afbc_bottom_src = round_up(h_in + 1, 4);
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	DRM_DEBUG("afbc top %d (src %d) bottom %d (src %d)\n",
34062306a36Sopenharmony_ci		  afbc_top, afbc_top_src, afbc_bottom, afbc_bottom_src);
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	/* Horizontal */
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	start = video_left + video_width / 2 - ((w_in << 17) / ratio_x);
34562306a36Sopenharmony_ci	end = (w_in << 18) / ratio_x + start - 1;
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	if (video_left < 0 && start < 0)
34862306a36Sopenharmony_ci		hd_start_lines = (-(start) * ratio_x) >> 18;
34962306a36Sopenharmony_ci	else if (start < video_left)
35062306a36Sopenharmony_ci		hd_start_lines = ((video_left - start) * ratio_x) >> 18;
35162306a36Sopenharmony_ci	else
35262306a36Sopenharmony_ci		hd_start_lines = 0;
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	if (video_left < 0)
35562306a36Sopenharmony_ci		temp_width = min_t(unsigned int,
35662306a36Sopenharmony_ci				   video_left + video_width - 1,
35762306a36Sopenharmony_ci				   crtc_width - 1);
35862306a36Sopenharmony_ci	else
35962306a36Sopenharmony_ci		temp_width = min_t(unsigned int,
36062306a36Sopenharmony_ci				   video_left + video_width - 1,
36162306a36Sopenharmony_ci				   crtc_width - 1) - video_left + 1;
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	temp = hd_start_lines + (temp_width * ratio_x >> 18);
36462306a36Sopenharmony_ci	hd_end_lines = (temp <= (w_in - 1)) ? temp : (w_in - 1);
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	priv->viu.vpp_line_in_length = hd_end_lines - hd_start_lines + 1;
36762306a36Sopenharmony_ci	hsc_startp = max_t(int, start, max_t(int, 0, video_left));
36862306a36Sopenharmony_ci	hsc_endp = min_t(int, end, min_t(int, crtc_width - 1,
36962306a36Sopenharmony_ci					 video_left + video_width - 1));
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	hd_start_lines += crop_top;
37262306a36Sopenharmony_ci	hd_end_lines += crop_top;
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	DRM_DEBUG("hsc startp %d endp %d start_lines %d end_lines %d\n",
37562306a36Sopenharmony_ci		 hsc_startp, hsc_endp, hd_start_lines, hd_end_lines);
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	if (hd_start_lines > 0 || (hd_end_lines < w_in)) {
37862306a36Sopenharmony_ci		afbc_left = 0;
37962306a36Sopenharmony_ci		afbc_right = round_up(w_in, 32);
38062306a36Sopenharmony_ci	} else {
38162306a36Sopenharmony_ci		afbc_left = round_down(hd_start_lines, 32);
38262306a36Sopenharmony_ci		afbc_right = round_up(hd_end_lines + 1, 32);
38362306a36Sopenharmony_ci	}
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	DRM_DEBUG("afbc left %d right %d\n", afbc_left, afbc_right);
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	priv->viu.vpp_vsc_start_phase_step = ratio_y << 6;
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	priv->viu.vpp_vsc_ini_phase = vphase << 8;
39062306a36Sopenharmony_ci	priv->viu.vpp_vsc_phase_ctrl = (1 << 13) | (4 << 8) |
39162306a36Sopenharmony_ci				       vphase_repeat_skip;
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	priv->viu.vd1_if0_luma_x0 = VD_X_START(hd_start_lines) |
39462306a36Sopenharmony_ci				    VD_X_END(hd_end_lines);
39562306a36Sopenharmony_ci	priv->viu.vd1_if0_chroma_x0 = VD_X_START(hd_start_lines >> 1) |
39662306a36Sopenharmony_ci				      VD_X_END(hd_end_lines >> 1);
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	priv->viu.viu_vd1_fmt_w =
39962306a36Sopenharmony_ci			VD_H_WIDTH(hd_end_lines - hd_start_lines + 1) |
40062306a36Sopenharmony_ci			VD_V_WIDTH(hd_end_lines/2 - hd_start_lines/2 + 1);
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	priv->viu.vd1_afbc_vd_cfmt_w =
40362306a36Sopenharmony_ci			AFBC_VD_H_WIDTH(afbc_right - afbc_left) |
40462306a36Sopenharmony_ci			AFBC_VD_V_WIDTH(afbc_right / 2 - afbc_left / 2);
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	priv->viu.vd1_afbc_vd_cfmt_h =
40762306a36Sopenharmony_ci			AFBC_VD_HEIGHT((afbc_bottom - afbc_top) / 2);
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	priv->viu.vd1_afbc_mif_hor_scope = AFBC_MIF_BLK_BGN_H(afbc_left / 32) |
41062306a36Sopenharmony_ci				AFBC_MIF_BLK_END_H((afbc_right / 32) - 1);
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	priv->viu.vd1_afbc_mif_ver_scope = AFBC_MIF_BLK_BGN_V(afbc_top / 4) |
41362306a36Sopenharmony_ci				AFBC_MIF_BLK_END_H((afbc_bottom / 4) - 1);
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	priv->viu.vd1_afbc_size_out =
41662306a36Sopenharmony_ci			AFBC_HSIZE_OUT(afbc_right - afbc_left) |
41762306a36Sopenharmony_ci			AFBC_VSIZE_OUT(afbc_bottom - afbc_top);
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	priv->viu.vd1_afbc_pixel_hor_scope =
42062306a36Sopenharmony_ci			AFBC_DEC_PIXEL_BGN_H(hd_start_lines - afbc_left) |
42162306a36Sopenharmony_ci			AFBC_DEC_PIXEL_END_H(hd_end_lines - afbc_left);
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	priv->viu.vd1_afbc_pixel_ver_scope =
42462306a36Sopenharmony_ci			AFBC_DEC_PIXEL_BGN_V(vd_start_lines - afbc_top) |
42562306a36Sopenharmony_ci			AFBC_DEC_PIXEL_END_V(vd_end_lines - afbc_top);
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	priv->viu.vd1_afbc_size_in =
42862306a36Sopenharmony_ci				AFBC_HSIZE_IN(afbc_right - afbc_left) |
42962306a36Sopenharmony_ci				AFBC_VSIZE_IN(afbc_bottom_src - afbc_top_src);
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	priv->viu.vd1_if0_luma_y0 = VD_Y_START(vd_start_lines) |
43262306a36Sopenharmony_ci				    VD_Y_END(vd_end_lines);
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	priv->viu.vd1_if0_chroma_y0 = VD_Y_START(vd_start_lines >> 1) |
43562306a36Sopenharmony_ci				      VD_Y_END(vd_end_lines >> 1);
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	priv->viu.vpp_pic_in_height = h_in;
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	priv->viu.vpp_postblend_vd1_h_start_end = VD_H_START(hsc_startp) |
44062306a36Sopenharmony_ci						  VD_H_END(hsc_endp);
44162306a36Sopenharmony_ci	priv->viu.vpp_blend_vd2_h_start_end = VD_H_START(hd_start_lines) |
44262306a36Sopenharmony_ci					      VD_H_END(hd_end_lines);
44362306a36Sopenharmony_ci	priv->viu.vpp_hsc_region12_startp = VD_REGION13_END(0) |
44462306a36Sopenharmony_ci					    VD_REGION24_START(hsc_startp);
44562306a36Sopenharmony_ci	priv->viu.vpp_hsc_region34_startp =
44662306a36Sopenharmony_ci				VD_REGION13_END(hsc_startp) |
44762306a36Sopenharmony_ci				VD_REGION24_START(hsc_endp - hsc_startp);
44862306a36Sopenharmony_ci	priv->viu.vpp_hsc_region4_endp = hsc_endp - hsc_startp;
44962306a36Sopenharmony_ci	priv->viu.vpp_hsc_start_phase_step = ratio_x << 6;
45062306a36Sopenharmony_ci	priv->viu.vpp_hsc_region1_phase_slope = 0;
45162306a36Sopenharmony_ci	priv->viu.vpp_hsc_region3_phase_slope = 0;
45262306a36Sopenharmony_ci	priv->viu.vpp_hsc_phase_ctrl = (1 << 21) | (4 << 16);
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	priv->viu.vpp_line_in_length = hd_end_lines - hd_start_lines + 1;
45562306a36Sopenharmony_ci	priv->viu.vpp_preblend_h_size = hd_end_lines - hd_start_lines + 1;
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	priv->viu.vpp_postblend_vd1_v_start_end = VD_V_START(vsc_startp) |
45862306a36Sopenharmony_ci						  VD_V_END(vsc_endp);
45962306a36Sopenharmony_ci	priv->viu.vpp_blend_vd2_v_start_end =
46062306a36Sopenharmony_ci				VD2_V_START((vd_end_lines + 1) >> 1) |
46162306a36Sopenharmony_ci				VD2_V_END(vd_end_lines);
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	priv->viu.vpp_vsc_region12_startp = 0;
46462306a36Sopenharmony_ci	priv->viu.vpp_vsc_region34_startp =
46562306a36Sopenharmony_ci				VD_REGION13_END(vsc_endp - vsc_startp) |
46662306a36Sopenharmony_ci				VD_REGION24_START(vsc_endp - vsc_startp);
46762306a36Sopenharmony_ci	priv->viu.vpp_vsc_region4_endp = vsc_endp - vsc_startp;
46862306a36Sopenharmony_ci	priv->viu.vpp_vsc_start_phase_step = ratio_y << 6;
46962306a36Sopenharmony_ci}
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_cistatic void meson_overlay_atomic_update(struct drm_plane *plane,
47262306a36Sopenharmony_ci					struct drm_atomic_state *state)
47362306a36Sopenharmony_ci{
47462306a36Sopenharmony_ci	struct meson_overlay *meson_overlay = to_meson_overlay(plane);
47562306a36Sopenharmony_ci	struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
47662306a36Sopenharmony_ci									   plane);
47762306a36Sopenharmony_ci	struct drm_framebuffer *fb = new_state->fb;
47862306a36Sopenharmony_ci	struct meson_drm *priv = meson_overlay->priv;
47962306a36Sopenharmony_ci	struct drm_gem_dma_object *gem;
48062306a36Sopenharmony_ci	unsigned long flags;
48162306a36Sopenharmony_ci	bool interlace_mode;
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	DRM_DEBUG_DRIVER("\n");
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	interlace_mode = new_state->crtc->mode.flags & DRM_MODE_FLAG_INTERLACE;
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci	spin_lock_irqsave(&priv->drm->event_lock, flags);
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci	if ((fb->modifier & DRM_FORMAT_MOD_AMLOGIC_FBC(0, 0)) ==
49062306a36Sopenharmony_ci			    DRM_FORMAT_MOD_AMLOGIC_FBC(0, 0)) {
49162306a36Sopenharmony_ci		priv->viu.vd1_afbc = true;
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci		priv->viu.vd1_afbc_mode = AFBC_MIF_URGENT(3) |
49462306a36Sopenharmony_ci					  AFBC_HOLD_LINE_NUM(8) |
49562306a36Sopenharmony_ci					  AFBC_BURST_LEN(2);
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci		if (fb->modifier & DRM_FORMAT_MOD_AMLOGIC_FBC(0,
49862306a36Sopenharmony_ci						AMLOGIC_FBC_OPTION_MEM_SAVING))
49962306a36Sopenharmony_ci			priv->viu.vd1_afbc_mode |= AFBC_BLK_MEM_MODE;
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci		if ((fb->modifier & __fourcc_mod_amlogic_layout_mask) ==
50262306a36Sopenharmony_ci				AMLOGIC_FBC_LAYOUT_SCATTER)
50362306a36Sopenharmony_ci			priv->viu.vd1_afbc_mode |= AFBC_SCATTER_MODE;
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci		priv->viu.vd1_afbc_en = 0x1600 | AFBC_DEC_ENABLE;
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci		priv->viu.vd1_afbc_conv_ctrl = AFBC_CONV_LBUF_LEN(256);
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci		priv->viu.vd1_afbc_dec_def_color = AFBC_DEF_COLOR_Y(1023);
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci		/* 420: horizontal / 2, vertical / 4 */
51262306a36Sopenharmony_ci		priv->viu.vd1_afbc_vd_cfmt_ctrl = AFBC_HORZ_RPT_PIXEL0 |
51362306a36Sopenharmony_ci						  AFBC_HORZ_Y_C_RATIO(1) |
51462306a36Sopenharmony_ci						  AFBC_HORZ_FMT_EN |
51562306a36Sopenharmony_ci						  AFBC_VERT_RPT_LINE0 |
51662306a36Sopenharmony_ci						  AFBC_VERT_INITIAL_PHASE(12) |
51762306a36Sopenharmony_ci						  AFBC_VERT_PHASE_STEP(8) |
51862306a36Sopenharmony_ci						  AFBC_VERT_FMT_EN;
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci		switch (fb->format->format) {
52162306a36Sopenharmony_ci		/* AFBC Only formats */
52262306a36Sopenharmony_ci		case DRM_FORMAT_YUV420_10BIT:
52362306a36Sopenharmony_ci			priv->viu.vd1_afbc_mode |=
52462306a36Sopenharmony_ci				AFBC_COMPBITS_YUV(AFBC_COMPBITS_10BIT);
52562306a36Sopenharmony_ci			priv->viu.vd1_afbc_dec_def_color |=
52662306a36Sopenharmony_ci					AFBC_DEF_COLOR_U(512) |
52762306a36Sopenharmony_ci					AFBC_DEF_COLOR_V(512);
52862306a36Sopenharmony_ci			break;
52962306a36Sopenharmony_ci		case DRM_FORMAT_YUV420_8BIT:
53062306a36Sopenharmony_ci			priv->viu.vd1_afbc_dec_def_color |=
53162306a36Sopenharmony_ci					AFBC_DEF_COLOR_U(128) |
53262306a36Sopenharmony_ci					AFBC_DEF_COLOR_V(128);
53362306a36Sopenharmony_ci			break;
53462306a36Sopenharmony_ci		}
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci		priv->viu.vd1_if0_gen_reg = 0;
53762306a36Sopenharmony_ci		priv->viu.vd1_if0_canvas0 = 0;
53862306a36Sopenharmony_ci		priv->viu.viu_vd1_fmt_ctrl = 0;
53962306a36Sopenharmony_ci	} else {
54062306a36Sopenharmony_ci		priv->viu.vd1_afbc = false;
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci		priv->viu.vd1_if0_gen_reg = VD_URGENT_CHROMA |
54362306a36Sopenharmony_ci					    VD_URGENT_LUMA |
54462306a36Sopenharmony_ci					    VD_HOLD_LINES(9) |
54562306a36Sopenharmony_ci					    VD_CHRO_RPT_LASTL_CTRL |
54662306a36Sopenharmony_ci					    VD_ENABLE;
54762306a36Sopenharmony_ci	}
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	/* Setup scaler params */
55062306a36Sopenharmony_ci	meson_overlay_setup_scaler_params(priv, plane, interlace_mode);
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci	priv->viu.vd1_if0_repeat_loop = 0;
55362306a36Sopenharmony_ci	priv->viu.vd1_if0_luma0_rpt_pat = interlace_mode ? 8 : 0;
55462306a36Sopenharmony_ci	priv->viu.vd1_if0_chroma0_rpt_pat = interlace_mode ? 8 : 0;
55562306a36Sopenharmony_ci	priv->viu.vd1_range_map_y = 0;
55662306a36Sopenharmony_ci	priv->viu.vd1_range_map_cb = 0;
55762306a36Sopenharmony_ci	priv->viu.vd1_range_map_cr = 0;
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	/* Default values for RGB888/YUV444 */
56062306a36Sopenharmony_ci	priv->viu.vd1_if0_gen_reg2 = 0;
56162306a36Sopenharmony_ci	priv->viu.viu_vd1_fmt_ctrl = 0;
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci	/* None will match for AFBC Only formats */
56462306a36Sopenharmony_ci	switch (fb->format->format) {
56562306a36Sopenharmony_ci	/* TOFIX DRM_FORMAT_RGB888 should be supported */
56662306a36Sopenharmony_ci	case DRM_FORMAT_YUYV:
56762306a36Sopenharmony_ci		priv->viu.vd1_if0_gen_reg |= VD_BYTES_PER_PIXEL(1);
56862306a36Sopenharmony_ci		priv->viu.vd1_if0_canvas0 =
56962306a36Sopenharmony_ci					CANVAS_ADDR2(priv->canvas_id_vd1_0) |
57062306a36Sopenharmony_ci					CANVAS_ADDR1(priv->canvas_id_vd1_0) |
57162306a36Sopenharmony_ci					CANVAS_ADDR0(priv->canvas_id_vd1_0);
57262306a36Sopenharmony_ci		priv->viu.viu_vd1_fmt_ctrl = VD_HORZ_Y_C_RATIO(1) | /* /2 */
57362306a36Sopenharmony_ci					     VD_HORZ_FMT_EN |
57462306a36Sopenharmony_ci					     VD_VERT_RPT_LINE0 |
57562306a36Sopenharmony_ci					     VD_VERT_INITIAL_PHASE(12) |
57662306a36Sopenharmony_ci					     VD_VERT_PHASE_STEP(16) | /* /2 */
57762306a36Sopenharmony_ci					     VD_VERT_FMT_EN;
57862306a36Sopenharmony_ci		break;
57962306a36Sopenharmony_ci	case DRM_FORMAT_NV12:
58062306a36Sopenharmony_ci	case DRM_FORMAT_NV21:
58162306a36Sopenharmony_ci		priv->viu.vd1_if0_gen_reg |= VD_SEPARATE_EN;
58262306a36Sopenharmony_ci		priv->viu.vd1_if0_canvas0 =
58362306a36Sopenharmony_ci					CANVAS_ADDR2(priv->canvas_id_vd1_1) |
58462306a36Sopenharmony_ci					CANVAS_ADDR1(priv->canvas_id_vd1_1) |
58562306a36Sopenharmony_ci					CANVAS_ADDR0(priv->canvas_id_vd1_0);
58662306a36Sopenharmony_ci		if (fb->format->format == DRM_FORMAT_NV12)
58762306a36Sopenharmony_ci			priv->viu.vd1_if0_gen_reg2 = VD_COLOR_MAP(1);
58862306a36Sopenharmony_ci		else
58962306a36Sopenharmony_ci			priv->viu.vd1_if0_gen_reg2 = VD_COLOR_MAP(2);
59062306a36Sopenharmony_ci		priv->viu.viu_vd1_fmt_ctrl = VD_HORZ_Y_C_RATIO(1) | /* /2 */
59162306a36Sopenharmony_ci					     VD_HORZ_FMT_EN |
59262306a36Sopenharmony_ci					     VD_VERT_RPT_LINE0 |
59362306a36Sopenharmony_ci					     VD_VERT_INITIAL_PHASE(12) |
59462306a36Sopenharmony_ci					     VD_VERT_PHASE_STEP(8) | /* /4 */
59562306a36Sopenharmony_ci					     VD_VERT_FMT_EN;
59662306a36Sopenharmony_ci		break;
59762306a36Sopenharmony_ci	case DRM_FORMAT_YUV444:
59862306a36Sopenharmony_ci	case DRM_FORMAT_YUV422:
59962306a36Sopenharmony_ci	case DRM_FORMAT_YUV420:
60062306a36Sopenharmony_ci	case DRM_FORMAT_YUV411:
60162306a36Sopenharmony_ci	case DRM_FORMAT_YUV410:
60262306a36Sopenharmony_ci		priv->viu.vd1_if0_gen_reg |= VD_SEPARATE_EN;
60362306a36Sopenharmony_ci		priv->viu.vd1_if0_canvas0 =
60462306a36Sopenharmony_ci					CANVAS_ADDR2(priv->canvas_id_vd1_2) |
60562306a36Sopenharmony_ci					CANVAS_ADDR1(priv->canvas_id_vd1_1) |
60662306a36Sopenharmony_ci					CANVAS_ADDR0(priv->canvas_id_vd1_0);
60762306a36Sopenharmony_ci		switch (fb->format->format) {
60862306a36Sopenharmony_ci		case DRM_FORMAT_YUV422:
60962306a36Sopenharmony_ci			priv->viu.viu_vd1_fmt_ctrl =
61062306a36Sopenharmony_ci					VD_HORZ_Y_C_RATIO(1) | /* /2 */
61162306a36Sopenharmony_ci					VD_HORZ_FMT_EN |
61262306a36Sopenharmony_ci					VD_VERT_RPT_LINE0 |
61362306a36Sopenharmony_ci					VD_VERT_INITIAL_PHASE(12) |
61462306a36Sopenharmony_ci					VD_VERT_PHASE_STEP(16) | /* /2 */
61562306a36Sopenharmony_ci					VD_VERT_FMT_EN;
61662306a36Sopenharmony_ci			break;
61762306a36Sopenharmony_ci		case DRM_FORMAT_YUV420:
61862306a36Sopenharmony_ci			priv->viu.viu_vd1_fmt_ctrl =
61962306a36Sopenharmony_ci					VD_HORZ_Y_C_RATIO(1) | /* /2 */
62062306a36Sopenharmony_ci					VD_HORZ_FMT_EN |
62162306a36Sopenharmony_ci					VD_VERT_RPT_LINE0 |
62262306a36Sopenharmony_ci					VD_VERT_INITIAL_PHASE(12) |
62362306a36Sopenharmony_ci					VD_VERT_PHASE_STEP(8) | /* /4 */
62462306a36Sopenharmony_ci					VD_VERT_FMT_EN;
62562306a36Sopenharmony_ci			break;
62662306a36Sopenharmony_ci		case DRM_FORMAT_YUV411:
62762306a36Sopenharmony_ci			priv->viu.viu_vd1_fmt_ctrl =
62862306a36Sopenharmony_ci					VD_HORZ_Y_C_RATIO(2) | /* /4 */
62962306a36Sopenharmony_ci					VD_HORZ_FMT_EN |
63062306a36Sopenharmony_ci					VD_VERT_RPT_LINE0 |
63162306a36Sopenharmony_ci					VD_VERT_INITIAL_PHASE(12) |
63262306a36Sopenharmony_ci					VD_VERT_PHASE_STEP(16) | /* /2 */
63362306a36Sopenharmony_ci					VD_VERT_FMT_EN;
63462306a36Sopenharmony_ci			break;
63562306a36Sopenharmony_ci		case DRM_FORMAT_YUV410:
63662306a36Sopenharmony_ci			priv->viu.viu_vd1_fmt_ctrl =
63762306a36Sopenharmony_ci					VD_HORZ_Y_C_RATIO(2) | /* /4 */
63862306a36Sopenharmony_ci					VD_HORZ_FMT_EN |
63962306a36Sopenharmony_ci					VD_VERT_RPT_LINE0 |
64062306a36Sopenharmony_ci					VD_VERT_INITIAL_PHASE(12) |
64162306a36Sopenharmony_ci					VD_VERT_PHASE_STEP(8) | /* /4 */
64262306a36Sopenharmony_ci					VD_VERT_FMT_EN;
64362306a36Sopenharmony_ci			break;
64462306a36Sopenharmony_ci		}
64562306a36Sopenharmony_ci		break;
64662306a36Sopenharmony_ci	}
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci	/* Update Canvas with buffer address */
64962306a36Sopenharmony_ci	priv->viu.vd1_planes = fb->format->num_planes;
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci	switch (priv->viu.vd1_planes) {
65262306a36Sopenharmony_ci	case 3:
65362306a36Sopenharmony_ci		gem = drm_fb_dma_get_gem_obj(fb, 2);
65462306a36Sopenharmony_ci		priv->viu.vd1_addr2 = gem->dma_addr + fb->offsets[2];
65562306a36Sopenharmony_ci		priv->viu.vd1_stride2 = fb->pitches[2];
65662306a36Sopenharmony_ci		priv->viu.vd1_height2 =
65762306a36Sopenharmony_ci			drm_format_info_plane_height(fb->format,
65862306a36Sopenharmony_ci						fb->height, 2);
65962306a36Sopenharmony_ci		DRM_DEBUG("plane 2 addr 0x%x stride %d height %d\n",
66062306a36Sopenharmony_ci			 priv->viu.vd1_addr2,
66162306a36Sopenharmony_ci			 priv->viu.vd1_stride2,
66262306a36Sopenharmony_ci			 priv->viu.vd1_height2);
66362306a36Sopenharmony_ci		fallthrough;
66462306a36Sopenharmony_ci	case 2:
66562306a36Sopenharmony_ci		gem = drm_fb_dma_get_gem_obj(fb, 1);
66662306a36Sopenharmony_ci		priv->viu.vd1_addr1 = gem->dma_addr + fb->offsets[1];
66762306a36Sopenharmony_ci		priv->viu.vd1_stride1 = fb->pitches[1];
66862306a36Sopenharmony_ci		priv->viu.vd1_height1 =
66962306a36Sopenharmony_ci			drm_format_info_plane_height(fb->format,
67062306a36Sopenharmony_ci						fb->height, 1);
67162306a36Sopenharmony_ci		DRM_DEBUG("plane 1 addr 0x%x stride %d height %d\n",
67262306a36Sopenharmony_ci			 priv->viu.vd1_addr1,
67362306a36Sopenharmony_ci			 priv->viu.vd1_stride1,
67462306a36Sopenharmony_ci			 priv->viu.vd1_height1);
67562306a36Sopenharmony_ci		fallthrough;
67662306a36Sopenharmony_ci	case 1:
67762306a36Sopenharmony_ci		gem = drm_fb_dma_get_gem_obj(fb, 0);
67862306a36Sopenharmony_ci		priv->viu.vd1_addr0 = gem->dma_addr + fb->offsets[0];
67962306a36Sopenharmony_ci		priv->viu.vd1_stride0 = fb->pitches[0];
68062306a36Sopenharmony_ci		priv->viu.vd1_height0 =
68162306a36Sopenharmony_ci			drm_format_info_plane_height(fb->format,
68262306a36Sopenharmony_ci						     fb->height, 0);
68362306a36Sopenharmony_ci		DRM_DEBUG("plane 0 addr 0x%x stride %d height %d\n",
68462306a36Sopenharmony_ci			 priv->viu.vd1_addr0,
68562306a36Sopenharmony_ci			 priv->viu.vd1_stride0,
68662306a36Sopenharmony_ci			 priv->viu.vd1_height0);
68762306a36Sopenharmony_ci	}
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci	if (priv->viu.vd1_afbc) {
69062306a36Sopenharmony_ci		if (priv->viu.vd1_afbc_mode & AFBC_SCATTER_MODE) {
69162306a36Sopenharmony_ci			/*
69262306a36Sopenharmony_ci			 * In Scatter mode, the header contains the physical
69362306a36Sopenharmony_ci			 * body content layout, thus the body content
69462306a36Sopenharmony_ci			 * size isn't needed.
69562306a36Sopenharmony_ci			 */
69662306a36Sopenharmony_ci			priv->viu.vd1_afbc_head_addr = priv->viu.vd1_addr0 >> 4;
69762306a36Sopenharmony_ci			priv->viu.vd1_afbc_body_addr = 0;
69862306a36Sopenharmony_ci		} else {
69962306a36Sopenharmony_ci			/* Default mode is 4k per superblock */
70062306a36Sopenharmony_ci			unsigned long block_size = 4096;
70162306a36Sopenharmony_ci			unsigned long body_size;
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci			/* 8bit mem saving mode is 3072bytes per superblock */
70462306a36Sopenharmony_ci			if (priv->viu.vd1_afbc_mode & AFBC_BLK_MEM_MODE)
70562306a36Sopenharmony_ci				block_size = 3072;
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci			body_size = (ALIGN(priv->viu.vd1_stride0, 64) / 64) *
70862306a36Sopenharmony_ci				    (ALIGN(priv->viu.vd1_height0, 32) / 32) *
70962306a36Sopenharmony_ci				    block_size;
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci			priv->viu.vd1_afbc_body_addr = priv->viu.vd1_addr0 >> 4;
71262306a36Sopenharmony_ci			/* Header is after body content */
71362306a36Sopenharmony_ci			priv->viu.vd1_afbc_head_addr = (priv->viu.vd1_addr0 +
71462306a36Sopenharmony_ci							body_size) >> 4;
71562306a36Sopenharmony_ci		}
71662306a36Sopenharmony_ci	}
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_ci	priv->viu.vd1_enabled = true;
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci	spin_unlock_irqrestore(&priv->drm->event_lock, flags);
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_ci	DRM_DEBUG_DRIVER("\n");
72362306a36Sopenharmony_ci}
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_cistatic void meson_overlay_atomic_disable(struct drm_plane *plane,
72662306a36Sopenharmony_ci				       struct drm_atomic_state *state)
72762306a36Sopenharmony_ci{
72862306a36Sopenharmony_ci	struct meson_overlay *meson_overlay = to_meson_overlay(plane);
72962306a36Sopenharmony_ci	struct meson_drm *priv = meson_overlay->priv;
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci	DRM_DEBUG_DRIVER("\n");
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci	priv->viu.vd1_enabled = false;
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci	/* Disable VD1 */
73662306a36Sopenharmony_ci	if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) {
73762306a36Sopenharmony_ci		writel_relaxed(0, priv->io_base + _REG(VD1_BLEND_SRC_CTRL));
73862306a36Sopenharmony_ci		writel_relaxed(0, priv->io_base + _REG(VD2_BLEND_SRC_CTRL));
73962306a36Sopenharmony_ci		writel_relaxed(0, priv->io_base + _REG(VD1_IF0_GEN_REG + 0x17b0));
74062306a36Sopenharmony_ci		writel_relaxed(0, priv->io_base + _REG(VD2_IF0_GEN_REG + 0x17b0));
74162306a36Sopenharmony_ci	} else
74262306a36Sopenharmony_ci		writel_bits_relaxed(VPP_VD1_POSTBLEND | VPP_VD1_PREBLEND, 0,
74362306a36Sopenharmony_ci				    priv->io_base + _REG(VPP_MISC));
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_ci}
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_cistatic const struct drm_plane_helper_funcs meson_overlay_helper_funcs = {
74862306a36Sopenharmony_ci	.atomic_check	= meson_overlay_atomic_check,
74962306a36Sopenharmony_ci	.atomic_disable	= meson_overlay_atomic_disable,
75062306a36Sopenharmony_ci	.atomic_update	= meson_overlay_atomic_update,
75162306a36Sopenharmony_ci};
75262306a36Sopenharmony_ci
75362306a36Sopenharmony_cistatic bool meson_overlay_format_mod_supported(struct drm_plane *plane,
75462306a36Sopenharmony_ci					       u32 format, u64 modifier)
75562306a36Sopenharmony_ci{
75662306a36Sopenharmony_ci	if (modifier == DRM_FORMAT_MOD_LINEAR &&
75762306a36Sopenharmony_ci	    format != DRM_FORMAT_YUV420_8BIT &&
75862306a36Sopenharmony_ci	    format != DRM_FORMAT_YUV420_10BIT)
75962306a36Sopenharmony_ci		return true;
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ci	if ((modifier & DRM_FORMAT_MOD_AMLOGIC_FBC(0, 0)) ==
76262306a36Sopenharmony_ci			DRM_FORMAT_MOD_AMLOGIC_FBC(0, 0)) {
76362306a36Sopenharmony_ci		unsigned int layout = modifier &
76462306a36Sopenharmony_ci			DRM_FORMAT_MOD_AMLOGIC_FBC(
76562306a36Sopenharmony_ci				__fourcc_mod_amlogic_layout_mask, 0);
76662306a36Sopenharmony_ci		unsigned int options =
76762306a36Sopenharmony_ci			(modifier >> __fourcc_mod_amlogic_options_shift) &
76862306a36Sopenharmony_ci			__fourcc_mod_amlogic_options_mask;
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ci		if (format != DRM_FORMAT_YUV420_8BIT &&
77162306a36Sopenharmony_ci		    format != DRM_FORMAT_YUV420_10BIT) {
77262306a36Sopenharmony_ci			DRM_DEBUG_KMS("%llx invalid format 0x%08x\n",
77362306a36Sopenharmony_ci				      modifier, format);
77462306a36Sopenharmony_ci			return false;
77562306a36Sopenharmony_ci		}
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_ci		if (layout != AMLOGIC_FBC_LAYOUT_BASIC &&
77862306a36Sopenharmony_ci		    layout != AMLOGIC_FBC_LAYOUT_SCATTER) {
77962306a36Sopenharmony_ci			DRM_DEBUG_KMS("%llx invalid layout %x\n",
78062306a36Sopenharmony_ci				      modifier, layout);
78162306a36Sopenharmony_ci			return false;
78262306a36Sopenharmony_ci		}
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_ci		if (options &&
78562306a36Sopenharmony_ci		    options != AMLOGIC_FBC_OPTION_MEM_SAVING) {
78662306a36Sopenharmony_ci			DRM_DEBUG_KMS("%llx invalid layout %x\n",
78762306a36Sopenharmony_ci				      modifier, layout);
78862306a36Sopenharmony_ci			return false;
78962306a36Sopenharmony_ci		}
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_ci		return true;
79262306a36Sopenharmony_ci	}
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_ci	DRM_DEBUG_KMS("invalid modifier %llx for format 0x%08x\n",
79562306a36Sopenharmony_ci		      modifier, format);
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_ci	return false;
79862306a36Sopenharmony_ci}
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_cistatic const struct drm_plane_funcs meson_overlay_funcs = {
80162306a36Sopenharmony_ci	.update_plane		= drm_atomic_helper_update_plane,
80262306a36Sopenharmony_ci	.disable_plane		= drm_atomic_helper_disable_plane,
80362306a36Sopenharmony_ci	.destroy		= drm_plane_cleanup,
80462306a36Sopenharmony_ci	.reset			= drm_atomic_helper_plane_reset,
80562306a36Sopenharmony_ci	.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
80662306a36Sopenharmony_ci	.atomic_destroy_state	= drm_atomic_helper_plane_destroy_state,
80762306a36Sopenharmony_ci	.format_mod_supported   = meson_overlay_format_mod_supported,
80862306a36Sopenharmony_ci};
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_cistatic const uint32_t supported_drm_formats[] = {
81162306a36Sopenharmony_ci	DRM_FORMAT_YUYV,
81262306a36Sopenharmony_ci	DRM_FORMAT_NV12,
81362306a36Sopenharmony_ci	DRM_FORMAT_NV21,
81462306a36Sopenharmony_ci	DRM_FORMAT_YUV444,
81562306a36Sopenharmony_ci	DRM_FORMAT_YUV422,
81662306a36Sopenharmony_ci	DRM_FORMAT_YUV420,
81762306a36Sopenharmony_ci	DRM_FORMAT_YUV411,
81862306a36Sopenharmony_ci	DRM_FORMAT_YUV410,
81962306a36Sopenharmony_ci	DRM_FORMAT_YUV420_8BIT, /* Amlogic FBC Only */
82062306a36Sopenharmony_ci	DRM_FORMAT_YUV420_10BIT, /* Amlogic FBC Only */
82162306a36Sopenharmony_ci};
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_cistatic const uint64_t format_modifiers[] = {
82462306a36Sopenharmony_ci	DRM_FORMAT_MOD_AMLOGIC_FBC(AMLOGIC_FBC_LAYOUT_SCATTER,
82562306a36Sopenharmony_ci				   AMLOGIC_FBC_OPTION_MEM_SAVING),
82662306a36Sopenharmony_ci	DRM_FORMAT_MOD_AMLOGIC_FBC(AMLOGIC_FBC_LAYOUT_BASIC,
82762306a36Sopenharmony_ci				   AMLOGIC_FBC_OPTION_MEM_SAVING),
82862306a36Sopenharmony_ci	DRM_FORMAT_MOD_AMLOGIC_FBC(AMLOGIC_FBC_LAYOUT_SCATTER, 0),
82962306a36Sopenharmony_ci	DRM_FORMAT_MOD_AMLOGIC_FBC(AMLOGIC_FBC_LAYOUT_BASIC, 0),
83062306a36Sopenharmony_ci	DRM_FORMAT_MOD_LINEAR,
83162306a36Sopenharmony_ci	DRM_FORMAT_MOD_INVALID,
83262306a36Sopenharmony_ci};
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ciint meson_overlay_create(struct meson_drm *priv)
83562306a36Sopenharmony_ci{
83662306a36Sopenharmony_ci	struct meson_overlay *meson_overlay;
83762306a36Sopenharmony_ci	struct drm_plane *plane;
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_ci	DRM_DEBUG_DRIVER("\n");
84062306a36Sopenharmony_ci
84162306a36Sopenharmony_ci	meson_overlay = devm_kzalloc(priv->drm->dev, sizeof(*meson_overlay),
84262306a36Sopenharmony_ci				   GFP_KERNEL);
84362306a36Sopenharmony_ci	if (!meson_overlay)
84462306a36Sopenharmony_ci		return -ENOMEM;
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_ci	meson_overlay->priv = priv;
84762306a36Sopenharmony_ci	plane = &meson_overlay->base;
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_ci	drm_universal_plane_init(priv->drm, plane, 0xFF,
85062306a36Sopenharmony_ci				 &meson_overlay_funcs,
85162306a36Sopenharmony_ci				 supported_drm_formats,
85262306a36Sopenharmony_ci				 ARRAY_SIZE(supported_drm_formats),
85362306a36Sopenharmony_ci				 format_modifiers,
85462306a36Sopenharmony_ci				 DRM_PLANE_TYPE_OVERLAY, "meson_overlay_plane");
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_ci	drm_plane_helper_add(plane, &meson_overlay_helper_funcs);
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_ci	/* For now, VD Overlay plane is always on the back */
85962306a36Sopenharmony_ci	drm_plane_create_zpos_immutable_property(plane, 0);
86062306a36Sopenharmony_ci
86162306a36Sopenharmony_ci	priv->overlay_plane = plane;
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_ci	DRM_DEBUG_DRIVER("\n");
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_ci	return 0;
86662306a36Sopenharmony_ci}
867