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