162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2016 BayLibre, SAS 462306a36Sopenharmony_ci * Author: Neil Armstrong <narmstrong@baylibre.com> 562306a36Sopenharmony_ci * Copyright (C) 2015 Amlogic, Inc. All rights reserved. 662306a36Sopenharmony_ci * Copyright (C) 2014 Endless Mobile 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Written by: 962306a36Sopenharmony_ci * Jasper St. Pierre <jstpierre@mecheye.net> 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <linux/bitfield.h> 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include <drm/drm_atomic.h> 1562306a36Sopenharmony_ci#include <drm/drm_atomic_helper.h> 1662306a36Sopenharmony_ci#include <drm/drm_blend.h> 1762306a36Sopenharmony_ci#include <drm/drm_device.h> 1862306a36Sopenharmony_ci#include <drm/drm_fb_dma_helper.h> 1962306a36Sopenharmony_ci#include <drm/drm_fourcc.h> 2062306a36Sopenharmony_ci#include <drm/drm_framebuffer.h> 2162306a36Sopenharmony_ci#include <drm/drm_gem_atomic_helper.h> 2262306a36Sopenharmony_ci#include <drm/drm_gem_dma_helper.h> 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#include "meson_plane.h" 2562306a36Sopenharmony_ci#include "meson_registers.h" 2662306a36Sopenharmony_ci#include "meson_viu.h" 2762306a36Sopenharmony_ci#include "meson_osd_afbcd.h" 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci/* OSD_SCI_WH_M1 */ 3062306a36Sopenharmony_ci#define SCI_WH_M1_W(w) FIELD_PREP(GENMASK(28, 16), w) 3162306a36Sopenharmony_ci#define SCI_WH_M1_H(h) FIELD_PREP(GENMASK(12, 0), h) 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci/* OSD_SCO_H_START_END */ 3462306a36Sopenharmony_ci/* OSD_SCO_V_START_END */ 3562306a36Sopenharmony_ci#define SCO_HV_START(start) FIELD_PREP(GENMASK(27, 16), start) 3662306a36Sopenharmony_ci#define SCO_HV_END(end) FIELD_PREP(GENMASK(11, 0), end) 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci/* OSD_SC_CTRL0 */ 3962306a36Sopenharmony_ci#define SC_CTRL0_PATH_EN BIT(3) 4062306a36Sopenharmony_ci#define SC_CTRL0_SEL_OSD1 BIT(2) 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci/* OSD_VSC_CTRL0 */ 4362306a36Sopenharmony_ci#define VSC_BANK_LEN(value) FIELD_PREP(GENMASK(2, 0), value) 4462306a36Sopenharmony_ci#define VSC_TOP_INI_RCV_NUM(value) FIELD_PREP(GENMASK(6, 3), value) 4562306a36Sopenharmony_ci#define VSC_TOP_RPT_L0_NUM(value) FIELD_PREP(GENMASK(9, 8), value) 4662306a36Sopenharmony_ci#define VSC_BOT_INI_RCV_NUM(value) FIELD_PREP(GENMASK(14, 11), value) 4762306a36Sopenharmony_ci#define VSC_BOT_RPT_L0_NUM(value) FIELD_PREP(GENMASK(17, 16), value) 4862306a36Sopenharmony_ci#define VSC_PROG_INTERLACE BIT(23) 4962306a36Sopenharmony_ci#define VSC_VERTICAL_SCALER_EN BIT(24) 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci/* OSD_VSC_INI_PHASE */ 5262306a36Sopenharmony_ci#define VSC_INI_PHASE_BOT(bottom) FIELD_PREP(GENMASK(31, 16), bottom) 5362306a36Sopenharmony_ci#define VSC_INI_PHASE_TOP(top) FIELD_PREP(GENMASK(15, 0), top) 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci/* OSD_HSC_CTRL0 */ 5662306a36Sopenharmony_ci#define HSC_BANK_LENGTH(value) FIELD_PREP(GENMASK(2, 0), value) 5762306a36Sopenharmony_ci#define HSC_INI_RCV_NUM0(value) FIELD_PREP(GENMASK(6, 3), value) 5862306a36Sopenharmony_ci#define HSC_RPT_P0_NUM0(value) FIELD_PREP(GENMASK(9, 8), value) 5962306a36Sopenharmony_ci#define HSC_HORIZ_SCALER_EN BIT(22) 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci/* VPP_OSD_VSC_PHASE_STEP */ 6262306a36Sopenharmony_ci/* VPP_OSD_HSC_PHASE_STEP */ 6362306a36Sopenharmony_ci#define SC_PHASE_STEP(value) FIELD_PREP(GENMASK(27, 0), value) 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_cistruct meson_plane { 6662306a36Sopenharmony_ci struct drm_plane base; 6762306a36Sopenharmony_ci struct meson_drm *priv; 6862306a36Sopenharmony_ci bool enabled; 6962306a36Sopenharmony_ci}; 7062306a36Sopenharmony_ci#define to_meson_plane(x) container_of(x, struct meson_plane, base) 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci#define FRAC_16_16(mult, div) (((mult) << 16) / (div)) 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_cistatic int meson_plane_atomic_check(struct drm_plane *plane, 7562306a36Sopenharmony_ci struct drm_atomic_state *state) 7662306a36Sopenharmony_ci{ 7762306a36Sopenharmony_ci struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, 7862306a36Sopenharmony_ci plane); 7962306a36Sopenharmony_ci struct drm_crtc_state *crtc_state; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci if (!new_plane_state->crtc) 8262306a36Sopenharmony_ci return 0; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci crtc_state = drm_atomic_get_crtc_state(state, 8562306a36Sopenharmony_ci new_plane_state->crtc); 8662306a36Sopenharmony_ci if (IS_ERR(crtc_state)) 8762306a36Sopenharmony_ci return PTR_ERR(crtc_state); 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci /* 9062306a36Sopenharmony_ci * Only allow : 9162306a36Sopenharmony_ci * - Upscaling up to 5x, vertical and horizontal 9262306a36Sopenharmony_ci * - Final coordinates must match crtc size 9362306a36Sopenharmony_ci */ 9462306a36Sopenharmony_ci return drm_atomic_helper_check_plane_state(new_plane_state, 9562306a36Sopenharmony_ci crtc_state, 9662306a36Sopenharmony_ci FRAC_16_16(1, 5), 9762306a36Sopenharmony_ci DRM_PLANE_NO_SCALING, 9862306a36Sopenharmony_ci false, true); 9962306a36Sopenharmony_ci} 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci#define MESON_MOD_AFBC_VALID_BITS (AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 | \ 10262306a36Sopenharmony_ci AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 | \ 10362306a36Sopenharmony_ci AFBC_FORMAT_MOD_YTR | \ 10462306a36Sopenharmony_ci AFBC_FORMAT_MOD_SPARSE | \ 10562306a36Sopenharmony_ci AFBC_FORMAT_MOD_SPLIT) 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci/* Takes a fixed 16.16 number and converts it to integer. */ 10862306a36Sopenharmony_cistatic inline int64_t fixed16_to_int(int64_t value) 10962306a36Sopenharmony_ci{ 11062306a36Sopenharmony_ci return value >> 16; 11162306a36Sopenharmony_ci} 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_cistatic u32 meson_g12a_afbcd_line_stride(struct meson_drm *priv) 11462306a36Sopenharmony_ci{ 11562306a36Sopenharmony_ci u32 line_stride = 0; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci switch (priv->afbcd.format) { 11862306a36Sopenharmony_ci case DRM_FORMAT_RGB565: 11962306a36Sopenharmony_ci line_stride = ((priv->viu.osd1_width << 4) + 127) >> 7; 12062306a36Sopenharmony_ci break; 12162306a36Sopenharmony_ci case DRM_FORMAT_RGB888: 12262306a36Sopenharmony_ci case DRM_FORMAT_XRGB8888: 12362306a36Sopenharmony_ci case DRM_FORMAT_ARGB8888: 12462306a36Sopenharmony_ci case DRM_FORMAT_XBGR8888: 12562306a36Sopenharmony_ci case DRM_FORMAT_ABGR8888: 12662306a36Sopenharmony_ci line_stride = ((priv->viu.osd1_width << 5) + 127) >> 7; 12762306a36Sopenharmony_ci break; 12862306a36Sopenharmony_ci } 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci return ((line_stride + 1) >> 1) << 1; 13162306a36Sopenharmony_ci} 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_cistatic void meson_plane_atomic_update(struct drm_plane *plane, 13462306a36Sopenharmony_ci struct drm_atomic_state *state) 13562306a36Sopenharmony_ci{ 13662306a36Sopenharmony_ci struct meson_plane *meson_plane = to_meson_plane(plane); 13762306a36Sopenharmony_ci struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, 13862306a36Sopenharmony_ci plane); 13962306a36Sopenharmony_ci struct drm_rect dest = drm_plane_state_dest(new_state); 14062306a36Sopenharmony_ci struct meson_drm *priv = meson_plane->priv; 14162306a36Sopenharmony_ci struct drm_framebuffer *fb = new_state->fb; 14262306a36Sopenharmony_ci struct drm_gem_dma_object *gem; 14362306a36Sopenharmony_ci unsigned long flags; 14462306a36Sopenharmony_ci int vsc_ini_rcv_num, vsc_ini_rpt_p0_num; 14562306a36Sopenharmony_ci int vsc_bot_rcv_num, vsc_bot_rpt_p0_num; 14662306a36Sopenharmony_ci int hsc_ini_rcv_num, hsc_ini_rpt_p0_num; 14762306a36Sopenharmony_ci int hf_phase_step, vf_phase_step; 14862306a36Sopenharmony_ci int src_w, src_h, dst_w, dst_h; 14962306a36Sopenharmony_ci int bot_ini_phase; 15062306a36Sopenharmony_ci int hf_bank_len; 15162306a36Sopenharmony_ci int vf_bank_len; 15262306a36Sopenharmony_ci u8 canvas_id_osd1; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci /* 15562306a36Sopenharmony_ci * Update Coordinates 15662306a36Sopenharmony_ci * Update Formats 15762306a36Sopenharmony_ci * Update Buffer 15862306a36Sopenharmony_ci * Enable Plane 15962306a36Sopenharmony_ci */ 16062306a36Sopenharmony_ci spin_lock_irqsave(&priv->drm->event_lock, flags); 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci /* Check if AFBC decoder is required for this buffer */ 16362306a36Sopenharmony_ci if ((meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) || 16462306a36Sopenharmony_ci meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) && 16562306a36Sopenharmony_ci fb->modifier & DRM_FORMAT_MOD_ARM_AFBC(MESON_MOD_AFBC_VALID_BITS)) 16662306a36Sopenharmony_ci priv->viu.osd1_afbcd = true; 16762306a36Sopenharmony_ci else 16862306a36Sopenharmony_ci priv->viu.osd1_afbcd = false; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci /* Enable OSD and BLK0, set max global alpha */ 17162306a36Sopenharmony_ci priv->viu.osd1_ctrl_stat = OSD_ENABLE | 17262306a36Sopenharmony_ci (0x100 << OSD_GLOBAL_ALPHA_SHIFT) | 17362306a36Sopenharmony_ci OSD_BLK0_ENABLE; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci priv->viu.osd1_ctrl_stat2 = readl(priv->io_base + 17662306a36Sopenharmony_ci _REG(VIU_OSD1_CTRL_STAT2)); 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci canvas_id_osd1 = priv->canvas_id_osd1; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci /* Set up BLK0 to point to the right canvas */ 18162306a36Sopenharmony_ci priv->viu.osd1_blk0_cfg[0] = canvas_id_osd1 << OSD_CANVAS_SEL; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci if (priv->viu.osd1_afbcd) { 18462306a36Sopenharmony_ci if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) { 18562306a36Sopenharmony_ci /* This is the internal decoding memory address */ 18662306a36Sopenharmony_ci priv->viu.osd1_blk1_cfg4 = MESON_G12A_AFBCD_OUT_ADDR; 18762306a36Sopenharmony_ci priv->viu.osd1_blk0_cfg[0] |= OSD_ENDIANNESS_BE; 18862306a36Sopenharmony_ci priv->viu.osd1_ctrl_stat2 |= OSD_PENDING_STAT_CLEAN; 18962306a36Sopenharmony_ci priv->viu.osd1_ctrl_stat |= VIU_OSD1_CFG_SYN_EN; 19062306a36Sopenharmony_ci } 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM)) { 19362306a36Sopenharmony_ci priv->viu.osd1_blk0_cfg[0] |= OSD_ENDIANNESS_LE; 19462306a36Sopenharmony_ci priv->viu.osd1_ctrl_stat2 |= OSD_DPATH_MALI_AFBCD; 19562306a36Sopenharmony_ci } 19662306a36Sopenharmony_ci } else { 19762306a36Sopenharmony_ci priv->viu.osd1_blk0_cfg[0] |= OSD_ENDIANNESS_LE; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM)) 20062306a36Sopenharmony_ci priv->viu.osd1_ctrl_stat2 &= ~OSD_DPATH_MALI_AFBCD; 20162306a36Sopenharmony_ci } 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci /* On GXBB, Use the old non-HDR RGB2YUV converter */ 20462306a36Sopenharmony_ci if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXBB)) 20562306a36Sopenharmony_ci priv->viu.osd1_blk0_cfg[0] |= OSD_OUTPUT_COLOR_RGB; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci if (priv->viu.osd1_afbcd && 20862306a36Sopenharmony_ci meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) { 20962306a36Sopenharmony_ci priv->viu.osd1_blk0_cfg[0] |= OSD_MALI_SRC_EN | 21062306a36Sopenharmony_ci priv->afbcd.ops->fmt_to_blk_mode(fb->modifier, 21162306a36Sopenharmony_ci fb->format->format); 21262306a36Sopenharmony_ci } else { 21362306a36Sopenharmony_ci switch (fb->format->format) { 21462306a36Sopenharmony_ci case DRM_FORMAT_XRGB8888: 21562306a36Sopenharmony_ci case DRM_FORMAT_ARGB8888: 21662306a36Sopenharmony_ci priv->viu.osd1_blk0_cfg[0] |= OSD_BLK_MODE_32 | 21762306a36Sopenharmony_ci OSD_COLOR_MATRIX_32_ARGB; 21862306a36Sopenharmony_ci break; 21962306a36Sopenharmony_ci case DRM_FORMAT_XBGR8888: 22062306a36Sopenharmony_ci case DRM_FORMAT_ABGR8888: 22162306a36Sopenharmony_ci priv->viu.osd1_blk0_cfg[0] |= OSD_BLK_MODE_32 | 22262306a36Sopenharmony_ci OSD_COLOR_MATRIX_32_ABGR; 22362306a36Sopenharmony_ci break; 22462306a36Sopenharmony_ci case DRM_FORMAT_RGB888: 22562306a36Sopenharmony_ci priv->viu.osd1_blk0_cfg[0] |= OSD_BLK_MODE_24 | 22662306a36Sopenharmony_ci OSD_COLOR_MATRIX_24_RGB; 22762306a36Sopenharmony_ci break; 22862306a36Sopenharmony_ci case DRM_FORMAT_RGB565: 22962306a36Sopenharmony_ci priv->viu.osd1_blk0_cfg[0] |= OSD_BLK_MODE_16 | 23062306a36Sopenharmony_ci OSD_COLOR_MATRIX_16_RGB565; 23162306a36Sopenharmony_ci break; 23262306a36Sopenharmony_ci } 23362306a36Sopenharmony_ci } 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci switch (fb->format->format) { 23662306a36Sopenharmony_ci case DRM_FORMAT_XRGB8888: 23762306a36Sopenharmony_ci case DRM_FORMAT_XBGR8888: 23862306a36Sopenharmony_ci /* For XRGB, replace the pixel's alpha by 0xFF */ 23962306a36Sopenharmony_ci priv->viu.osd1_ctrl_stat2 |= OSD_REPLACE_EN; 24062306a36Sopenharmony_ci break; 24162306a36Sopenharmony_ci case DRM_FORMAT_ARGB8888: 24262306a36Sopenharmony_ci case DRM_FORMAT_ABGR8888: 24362306a36Sopenharmony_ci /* For ARGB, use the pixel's alpha */ 24462306a36Sopenharmony_ci priv->viu.osd1_ctrl_stat2 &= ~OSD_REPLACE_EN; 24562306a36Sopenharmony_ci break; 24662306a36Sopenharmony_ci } 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci /* Default scaler parameters */ 24962306a36Sopenharmony_ci vsc_bot_rcv_num = 0; 25062306a36Sopenharmony_ci vsc_bot_rpt_p0_num = 0; 25162306a36Sopenharmony_ci hf_bank_len = 4; 25262306a36Sopenharmony_ci vf_bank_len = 4; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci if (new_state->crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) { 25562306a36Sopenharmony_ci vsc_bot_rcv_num = 6; 25662306a36Sopenharmony_ci vsc_bot_rpt_p0_num = 2; 25762306a36Sopenharmony_ci } 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci hsc_ini_rcv_num = hf_bank_len; 26062306a36Sopenharmony_ci vsc_ini_rcv_num = vf_bank_len; 26162306a36Sopenharmony_ci hsc_ini_rpt_p0_num = (hf_bank_len / 2) - 1; 26262306a36Sopenharmony_ci vsc_ini_rpt_p0_num = (vf_bank_len / 2) - 1; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci src_w = fixed16_to_int(new_state->src_w); 26562306a36Sopenharmony_ci src_h = fixed16_to_int(new_state->src_h); 26662306a36Sopenharmony_ci dst_w = new_state->crtc_w; 26762306a36Sopenharmony_ci dst_h = new_state->crtc_h; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci /* 27062306a36Sopenharmony_ci * When the output is interlaced, the OSD must switch between 27162306a36Sopenharmony_ci * each field using the INTERLACE_SEL_ODD (0) of VIU_OSD1_BLK0_CFG_W0 27262306a36Sopenharmony_ci * at each vsync. 27362306a36Sopenharmony_ci * But the vertical scaler can provide such funtionnality if 27462306a36Sopenharmony_ci * is configured for 2:1 scaling with interlace options enabled. 27562306a36Sopenharmony_ci */ 27662306a36Sopenharmony_ci if (new_state->crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) { 27762306a36Sopenharmony_ci dest.y1 /= 2; 27862306a36Sopenharmony_ci dest.y2 /= 2; 27962306a36Sopenharmony_ci dst_h /= 2; 28062306a36Sopenharmony_ci } 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci hf_phase_step = ((src_w << 18) / dst_w) << 6; 28362306a36Sopenharmony_ci vf_phase_step = (src_h << 20) / dst_h; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci if (new_state->crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) 28662306a36Sopenharmony_ci bot_ini_phase = ((vf_phase_step / 2) >> 4); 28762306a36Sopenharmony_ci else 28862306a36Sopenharmony_ci bot_ini_phase = 0; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci vf_phase_step = (vf_phase_step << 4); 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci /* In interlaced mode, scaler is always active */ 29362306a36Sopenharmony_ci if (src_h != dst_h || src_w != dst_w) { 29462306a36Sopenharmony_ci priv->viu.osd_sc_i_wh_m1 = SCI_WH_M1_W(src_w - 1) | 29562306a36Sopenharmony_ci SCI_WH_M1_H(src_h - 1); 29662306a36Sopenharmony_ci priv->viu.osd_sc_o_h_start_end = SCO_HV_START(dest.x1) | 29762306a36Sopenharmony_ci SCO_HV_END(dest.x2 - 1); 29862306a36Sopenharmony_ci priv->viu.osd_sc_o_v_start_end = SCO_HV_START(dest.y1) | 29962306a36Sopenharmony_ci SCO_HV_END(dest.y2 - 1); 30062306a36Sopenharmony_ci /* Enable OSD Scaler */ 30162306a36Sopenharmony_ci priv->viu.osd_sc_ctrl0 = SC_CTRL0_PATH_EN | SC_CTRL0_SEL_OSD1; 30262306a36Sopenharmony_ci } else { 30362306a36Sopenharmony_ci priv->viu.osd_sc_i_wh_m1 = 0; 30462306a36Sopenharmony_ci priv->viu.osd_sc_o_h_start_end = 0; 30562306a36Sopenharmony_ci priv->viu.osd_sc_o_v_start_end = 0; 30662306a36Sopenharmony_ci priv->viu.osd_sc_ctrl0 = 0; 30762306a36Sopenharmony_ci } 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci /* In interlaced mode, vertical scaler is always active */ 31062306a36Sopenharmony_ci if (src_h != dst_h) { 31162306a36Sopenharmony_ci priv->viu.osd_sc_v_ctrl0 = 31262306a36Sopenharmony_ci VSC_BANK_LEN(vf_bank_len) | 31362306a36Sopenharmony_ci VSC_TOP_INI_RCV_NUM(vsc_ini_rcv_num) | 31462306a36Sopenharmony_ci VSC_TOP_RPT_L0_NUM(vsc_ini_rpt_p0_num) | 31562306a36Sopenharmony_ci VSC_VERTICAL_SCALER_EN; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci if (new_state->crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) 31862306a36Sopenharmony_ci priv->viu.osd_sc_v_ctrl0 |= 31962306a36Sopenharmony_ci VSC_BOT_INI_RCV_NUM(vsc_bot_rcv_num) | 32062306a36Sopenharmony_ci VSC_BOT_RPT_L0_NUM(vsc_bot_rpt_p0_num) | 32162306a36Sopenharmony_ci VSC_PROG_INTERLACE; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci priv->viu.osd_sc_v_phase_step = SC_PHASE_STEP(vf_phase_step); 32462306a36Sopenharmony_ci priv->viu.osd_sc_v_ini_phase = VSC_INI_PHASE_BOT(bot_ini_phase); 32562306a36Sopenharmony_ci } else { 32662306a36Sopenharmony_ci priv->viu.osd_sc_v_ctrl0 = 0; 32762306a36Sopenharmony_ci priv->viu.osd_sc_v_phase_step = 0; 32862306a36Sopenharmony_ci priv->viu.osd_sc_v_ini_phase = 0; 32962306a36Sopenharmony_ci } 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci /* Horizontal scaler is only used if width does not match */ 33262306a36Sopenharmony_ci if (src_w != dst_w) { 33362306a36Sopenharmony_ci priv->viu.osd_sc_h_ctrl0 = 33462306a36Sopenharmony_ci HSC_BANK_LENGTH(hf_bank_len) | 33562306a36Sopenharmony_ci HSC_INI_RCV_NUM0(hsc_ini_rcv_num) | 33662306a36Sopenharmony_ci HSC_RPT_P0_NUM0(hsc_ini_rpt_p0_num) | 33762306a36Sopenharmony_ci HSC_HORIZ_SCALER_EN; 33862306a36Sopenharmony_ci priv->viu.osd_sc_h_phase_step = SC_PHASE_STEP(hf_phase_step); 33962306a36Sopenharmony_ci priv->viu.osd_sc_h_ini_phase = 0; 34062306a36Sopenharmony_ci } else { 34162306a36Sopenharmony_ci priv->viu.osd_sc_h_ctrl0 = 0; 34262306a36Sopenharmony_ci priv->viu.osd_sc_h_phase_step = 0; 34362306a36Sopenharmony_ci priv->viu.osd_sc_h_ini_phase = 0; 34462306a36Sopenharmony_ci } 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci /* 34762306a36Sopenharmony_ci * The format of these registers is (x2 << 16 | x1), 34862306a36Sopenharmony_ci * where x2 is exclusive. 34962306a36Sopenharmony_ci * e.g. +30x1920 would be (1919 << 16) | 30 35062306a36Sopenharmony_ci */ 35162306a36Sopenharmony_ci priv->viu.osd1_blk0_cfg[1] = 35262306a36Sopenharmony_ci ((fixed16_to_int(new_state->src.x2) - 1) << 16) | 35362306a36Sopenharmony_ci fixed16_to_int(new_state->src.x1); 35462306a36Sopenharmony_ci priv->viu.osd1_blk0_cfg[2] = 35562306a36Sopenharmony_ci ((fixed16_to_int(new_state->src.y2) - 1) << 16) | 35662306a36Sopenharmony_ci fixed16_to_int(new_state->src.y1); 35762306a36Sopenharmony_ci priv->viu.osd1_blk0_cfg[3] = ((dest.x2 - 1) << 16) | dest.x1; 35862306a36Sopenharmony_ci priv->viu.osd1_blk0_cfg[4] = ((dest.y2 - 1) << 16) | dest.y1; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) { 36162306a36Sopenharmony_ci priv->viu.osd_blend_din0_scope_h = ((dest.x2 - 1) << 16) | dest.x1; 36262306a36Sopenharmony_ci priv->viu.osd_blend_din0_scope_v = ((dest.y2 - 1) << 16) | dest.y1; 36362306a36Sopenharmony_ci priv->viu.osb_blend0_size = dst_h << 16 | dst_w; 36462306a36Sopenharmony_ci priv->viu.osb_blend1_size = dst_h << 16 | dst_w; 36562306a36Sopenharmony_ci } 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci /* Update Canvas with buffer address */ 36862306a36Sopenharmony_ci gem = drm_fb_dma_get_gem_obj(fb, 0); 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci priv->viu.osd1_addr = gem->dma_addr; 37162306a36Sopenharmony_ci priv->viu.osd1_stride = fb->pitches[0]; 37262306a36Sopenharmony_ci priv->viu.osd1_height = fb->height; 37362306a36Sopenharmony_ci priv->viu.osd1_width = fb->width; 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci if (priv->viu.osd1_afbcd) { 37662306a36Sopenharmony_ci priv->afbcd.modifier = fb->modifier; 37762306a36Sopenharmony_ci priv->afbcd.format = fb->format->format; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci /* Calculate decoder write stride */ 38062306a36Sopenharmony_ci if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) 38162306a36Sopenharmony_ci priv->viu.osd1_blk2_cfg4 = 38262306a36Sopenharmony_ci meson_g12a_afbcd_line_stride(priv); 38362306a36Sopenharmony_ci } 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci if (!meson_plane->enabled) { 38662306a36Sopenharmony_ci /* Reset OSD1 before enabling it on GXL+ SoCs */ 38762306a36Sopenharmony_ci if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) || 38862306a36Sopenharmony_ci meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXL)) 38962306a36Sopenharmony_ci meson_viu_osd1_reset(priv); 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci meson_plane->enabled = true; 39262306a36Sopenharmony_ci } 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci priv->viu.osd1_enabled = true; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci spin_unlock_irqrestore(&priv->drm->event_lock, flags); 39762306a36Sopenharmony_ci} 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_cistatic void meson_plane_atomic_disable(struct drm_plane *plane, 40062306a36Sopenharmony_ci struct drm_atomic_state *state) 40162306a36Sopenharmony_ci{ 40262306a36Sopenharmony_ci struct meson_plane *meson_plane = to_meson_plane(plane); 40362306a36Sopenharmony_ci struct meson_drm *priv = meson_plane->priv; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci if (priv->afbcd.ops) { 40662306a36Sopenharmony_ci priv->afbcd.ops->reset(priv); 40762306a36Sopenharmony_ci priv->afbcd.ops->disable(priv); 40862306a36Sopenharmony_ci } 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci /* Disable OSD1 */ 41162306a36Sopenharmony_ci if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) 41262306a36Sopenharmony_ci writel_bits_relaxed(VIU_OSD1_POSTBLD_SRC_OSD1, 0, 41362306a36Sopenharmony_ci priv->io_base + _REG(OSD1_BLEND_SRC_CTRL)); 41462306a36Sopenharmony_ci else 41562306a36Sopenharmony_ci writel_bits_relaxed(VPP_OSD1_POSTBLEND, 0, 41662306a36Sopenharmony_ci priv->io_base + _REG(VPP_MISC)); 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci meson_plane->enabled = false; 41962306a36Sopenharmony_ci priv->viu.osd1_enabled = false; 42062306a36Sopenharmony_ci} 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_cistatic const struct drm_plane_helper_funcs meson_plane_helper_funcs = { 42362306a36Sopenharmony_ci .atomic_check = meson_plane_atomic_check, 42462306a36Sopenharmony_ci .atomic_disable = meson_plane_atomic_disable, 42562306a36Sopenharmony_ci .atomic_update = meson_plane_atomic_update, 42662306a36Sopenharmony_ci}; 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_cistatic bool meson_plane_format_mod_supported(struct drm_plane *plane, 42962306a36Sopenharmony_ci u32 format, u64 modifier) 43062306a36Sopenharmony_ci{ 43162306a36Sopenharmony_ci struct meson_plane *meson_plane = to_meson_plane(plane); 43262306a36Sopenharmony_ci struct meson_drm *priv = meson_plane->priv; 43362306a36Sopenharmony_ci int i; 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci if (modifier == DRM_FORMAT_MOD_INVALID) 43662306a36Sopenharmony_ci return false; 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci if (modifier == DRM_FORMAT_MOD_LINEAR) 43962306a36Sopenharmony_ci return true; 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci if (!meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) && 44262306a36Sopenharmony_ci !meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) 44362306a36Sopenharmony_ci return false; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci if (modifier & ~DRM_FORMAT_MOD_ARM_AFBC(MESON_MOD_AFBC_VALID_BITS)) 44662306a36Sopenharmony_ci return false; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci for (i = 0 ; i < plane->modifier_count ; ++i) 44962306a36Sopenharmony_ci if (plane->modifiers[i] == modifier) 45062306a36Sopenharmony_ci break; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci if (i == plane->modifier_count) { 45362306a36Sopenharmony_ci DRM_DEBUG_KMS("Unsupported modifier\n"); 45462306a36Sopenharmony_ci return false; 45562306a36Sopenharmony_ci } 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci if (priv->afbcd.ops && priv->afbcd.ops->supported_fmt) 45862306a36Sopenharmony_ci return priv->afbcd.ops->supported_fmt(modifier, format); 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci DRM_DEBUG_KMS("AFBC Unsupported\n"); 46162306a36Sopenharmony_ci return false; 46262306a36Sopenharmony_ci} 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_cistatic const struct drm_plane_funcs meson_plane_funcs = { 46562306a36Sopenharmony_ci .update_plane = drm_atomic_helper_update_plane, 46662306a36Sopenharmony_ci .disable_plane = drm_atomic_helper_disable_plane, 46762306a36Sopenharmony_ci .destroy = drm_plane_cleanup, 46862306a36Sopenharmony_ci .reset = drm_atomic_helper_plane_reset, 46962306a36Sopenharmony_ci .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, 47062306a36Sopenharmony_ci .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, 47162306a36Sopenharmony_ci .format_mod_supported = meson_plane_format_mod_supported, 47262306a36Sopenharmony_ci}; 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_cistatic const uint32_t supported_drm_formats[] = { 47562306a36Sopenharmony_ci DRM_FORMAT_ARGB8888, 47662306a36Sopenharmony_ci DRM_FORMAT_ABGR8888, 47762306a36Sopenharmony_ci DRM_FORMAT_XRGB8888, 47862306a36Sopenharmony_ci DRM_FORMAT_XBGR8888, 47962306a36Sopenharmony_ci DRM_FORMAT_RGB888, 48062306a36Sopenharmony_ci DRM_FORMAT_RGB565, 48162306a36Sopenharmony_ci}; 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_cistatic const uint64_t format_modifiers_afbc_gxm[] = { 48462306a36Sopenharmony_ci DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 | 48562306a36Sopenharmony_ci AFBC_FORMAT_MOD_SPARSE | 48662306a36Sopenharmony_ci AFBC_FORMAT_MOD_YTR), 48762306a36Sopenharmony_ci /* SPLIT mandates SPARSE, RGB modes mandates YTR */ 48862306a36Sopenharmony_ci DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 | 48962306a36Sopenharmony_ci AFBC_FORMAT_MOD_YTR | 49062306a36Sopenharmony_ci AFBC_FORMAT_MOD_SPARSE | 49162306a36Sopenharmony_ci AFBC_FORMAT_MOD_SPLIT), 49262306a36Sopenharmony_ci DRM_FORMAT_MOD_LINEAR, 49362306a36Sopenharmony_ci DRM_FORMAT_MOD_INVALID, 49462306a36Sopenharmony_ci}; 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_cistatic const uint64_t format_modifiers_afbc_g12a[] = { 49762306a36Sopenharmony_ci /* 49862306a36Sopenharmony_ci * - TOFIX Support AFBC modifiers for YUV formats (16x16 + TILED) 49962306a36Sopenharmony_ci * - SPLIT is mandatory for performances reasons when in 16x16 50062306a36Sopenharmony_ci * block size 50162306a36Sopenharmony_ci * - 32x8 block size + SPLIT is mandatory with 4K frame size 50262306a36Sopenharmony_ci * for performances reasons 50362306a36Sopenharmony_ci */ 50462306a36Sopenharmony_ci DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 | 50562306a36Sopenharmony_ci AFBC_FORMAT_MOD_SPARSE | 50662306a36Sopenharmony_ci AFBC_FORMAT_MOD_SPLIT), 50762306a36Sopenharmony_ci DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 | 50862306a36Sopenharmony_ci AFBC_FORMAT_MOD_YTR | 50962306a36Sopenharmony_ci AFBC_FORMAT_MOD_SPARSE | 51062306a36Sopenharmony_ci AFBC_FORMAT_MOD_SPLIT), 51162306a36Sopenharmony_ci DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 | 51262306a36Sopenharmony_ci AFBC_FORMAT_MOD_SPARSE), 51362306a36Sopenharmony_ci DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 | 51462306a36Sopenharmony_ci AFBC_FORMAT_MOD_YTR | 51562306a36Sopenharmony_ci AFBC_FORMAT_MOD_SPARSE), 51662306a36Sopenharmony_ci DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 | 51762306a36Sopenharmony_ci AFBC_FORMAT_MOD_SPARSE | 51862306a36Sopenharmony_ci AFBC_FORMAT_MOD_SPLIT), 51962306a36Sopenharmony_ci DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 | 52062306a36Sopenharmony_ci AFBC_FORMAT_MOD_YTR | 52162306a36Sopenharmony_ci AFBC_FORMAT_MOD_SPARSE | 52262306a36Sopenharmony_ci AFBC_FORMAT_MOD_SPLIT), 52362306a36Sopenharmony_ci DRM_FORMAT_MOD_LINEAR, 52462306a36Sopenharmony_ci DRM_FORMAT_MOD_INVALID, 52562306a36Sopenharmony_ci}; 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_cistatic const uint64_t format_modifiers_default[] = { 52862306a36Sopenharmony_ci DRM_FORMAT_MOD_LINEAR, 52962306a36Sopenharmony_ci DRM_FORMAT_MOD_INVALID, 53062306a36Sopenharmony_ci}; 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ciint meson_plane_create(struct meson_drm *priv) 53362306a36Sopenharmony_ci{ 53462306a36Sopenharmony_ci struct meson_plane *meson_plane; 53562306a36Sopenharmony_ci struct drm_plane *plane; 53662306a36Sopenharmony_ci const uint64_t *format_modifiers = format_modifiers_default; 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci meson_plane = devm_kzalloc(priv->drm->dev, sizeof(*meson_plane), 53962306a36Sopenharmony_ci GFP_KERNEL); 54062306a36Sopenharmony_ci if (!meson_plane) 54162306a36Sopenharmony_ci return -ENOMEM; 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci meson_plane->priv = priv; 54462306a36Sopenharmony_ci plane = &meson_plane->base; 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM)) 54762306a36Sopenharmony_ci format_modifiers = format_modifiers_afbc_gxm; 54862306a36Sopenharmony_ci else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) 54962306a36Sopenharmony_ci format_modifiers = format_modifiers_afbc_g12a; 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci drm_universal_plane_init(priv->drm, plane, 0xFF, 55262306a36Sopenharmony_ci &meson_plane_funcs, 55362306a36Sopenharmony_ci supported_drm_formats, 55462306a36Sopenharmony_ci ARRAY_SIZE(supported_drm_formats), 55562306a36Sopenharmony_ci format_modifiers, 55662306a36Sopenharmony_ci DRM_PLANE_TYPE_PRIMARY, "meson_primary_plane"); 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci drm_plane_helper_add(plane, &meson_plane_helper_funcs); 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci /* For now, OSD Primary plane is always on the front */ 56162306a36Sopenharmony_ci drm_plane_create_zpos_immutable_property(plane, 1); 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci priv->primary_plane = plane; 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci return 0; 56662306a36Sopenharmony_ci} 567