aboutsummaryrefslogtreecommitdiffstats
path: root/testing/linux-amlogic/0025-WIP-drm-meson-Support-Overlay-plane-for-video-render.patch
diff options
context:
space:
mode:
authorHe Yangxuan <yangxuan8282@gmail.com>2018-11-16 23:09:10 +0800
committerNatanael Copa <ncopa@alpinelinux.org>2018-11-26 15:26:48 +0000
commit8dc0e43d5a410a6f173c14caaa625adaf45f11f4 (patch)
tree8818259554accdf24310ae8aef8a0ed4a06427d5 /testing/linux-amlogic/0025-WIP-drm-meson-Support-Overlay-plane-for-video-render.patch
parent9a88176c5408adb5321fa11300cb63e4dbea80ed (diff)
downloadaports-8dc0e43d5a410a6f173c14caaa625adaf45f11f4.tar.bz2
aports-8dc0e43d5a410a6f173c14caaa625adaf45f11f4.tar.xz
testing/linux-amlogic: new aport
This kernel package add support for Amlogic S9xxx device. Supported devices include many android box and some SBC like Odroid C2, Khadas Vim, Nanopi K2. This package based on mainline kernel, and apply some patches from mainline amlogic developer.
Diffstat (limited to 'testing/linux-amlogic/0025-WIP-drm-meson-Support-Overlay-plane-for-video-render.patch')
-rw-r--r--testing/linux-amlogic/0025-WIP-drm-meson-Support-Overlay-plane-for-video-render.patch1141
1 files changed, 1141 insertions, 0 deletions
diff --git a/testing/linux-amlogic/0025-WIP-drm-meson-Support-Overlay-plane-for-video-render.patch b/testing/linux-amlogic/0025-WIP-drm-meson-Support-Overlay-plane-for-video-render.patch
new file mode 100644
index 0000000000..6102e1cdc3
--- /dev/null
+++ b/testing/linux-amlogic/0025-WIP-drm-meson-Support-Overlay-plane-for-video-render.patch
@@ -0,0 +1,1141 @@
+From 5d0ab03232cdda74b9eb4ce283e98aa60c40b0c9 Mon Sep 17 00:00:00 2001
+From: Neil Armstrong <narmstrong@baylibre.com>
+Date: Thu, 2 Aug 2018 10:00:01 +0200
+Subject: [PATCH] [WIP] drm/meson: Support Overlay plane for video rendering
+
+The Amlogic Meson GX SoCs support an Overlay plane behind the primary
+plan for video rendering.
+This Overlay plane support various YUV layouts and a non-alpha RGB32
+layout.
+---
+ drivers/gpu/drm/meson/Makefile | 2 +-
+ drivers/gpu/drm/meson/meson_crtc.c | 170 ++++++++-
+ drivers/gpu/drm/meson/meson_drv.c | 14 +
+ drivers/gpu/drm/meson/meson_drv.h | 52 +++
+ drivers/gpu/drm/meson/meson_overlay.c | 595 ++++++++++++++++++++++++++++++++
+ drivers/gpu/drm/meson/meson_overlay.h | 14 +
+ drivers/gpu/drm/meson/meson_registers.h | 3 +
+ drivers/gpu/drm/meson/meson_viu.c | 15 +
+ drivers/gpu/drm/meson/meson_vpp.c | 44 ++-
+ drivers/soc/amlogic/meson-gx-pwrc-vpu.c | 8 +-
+ 10 files changed, 910 insertions(+), 7 deletions(-)
+ create mode 100644 drivers/gpu/drm/meson/meson_overlay.c
+ create mode 100644 drivers/gpu/drm/meson/meson_overlay.h
+
+diff --git a/drivers/gpu/drm/meson/Makefile b/drivers/gpu/drm/meson/Makefile
+index bd67429..d4ea82f 100644
+--- a/drivers/gpu/drm/meson/Makefile
++++ b/drivers/gpu/drm/meson/Makefile
+@@ -1,5 +1,5 @@
+ meson-drm-y := meson_drv.o meson_plane.o meson_crtc.o meson_venc_cvbs.o
+-meson-drm-y += meson_viu.o meson_vpp.o meson_venc.o meson_vclk.o
++meson-drm-y += meson_viu.o meson_vpp.o meson_venc.o meson_vclk.o meson_overlay.o
+
+ obj-$(CONFIG_DRM_MESON) += meson-drm.o
+ obj-$(CONFIG_DRM_MESON_DW_HDMI) += meson_dw_hdmi.o
+diff --git a/drivers/gpu/drm/meson/meson_crtc.c b/drivers/gpu/drm/meson/meson_crtc.c
+index 7c8ad06..90c826b 100644
+--- a/drivers/gpu/drm/meson/meson_crtc.c
++++ b/drivers/gpu/drm/meson/meson_crtc.c
+@@ -25,6 +25,7 @@
+ #include <linux/module.h>
+ #include <linux/mutex.h>
+ #include <linux/platform_device.h>
++#include <linux/bitfield.h>
+ #include <drm/drmP.h>
+ #include <drm/drm_atomic.h>
+ #include <drm/drm_atomic_helper.h>
+@@ -97,6 +98,10 @@ static void meson_crtc_atomic_enable(struct drm_crtc *crtc,
+ writel(crtc_state->mode.hdisplay,
+ priv->io_base + _REG(VPP_POSTBLEND_H_SIZE));
+
++ /* VD1 Preblend vertical start/end */
++ writel(FIELD_PREP(GENMASK(11, 0), 2303),
++ priv->io_base + _REG(VPP_PREBLEND_VD1_V_START_END));
++
+ writel_bits_relaxed(VPP_POSTBLEND_ENABLE, VPP_POSTBLEND_ENABLE,
+ priv->io_base + _REG(VPP_MISC));
+
+@@ -118,8 +123,12 @@ static void meson_crtc_atomic_disable(struct drm_crtc *crtc,
+ priv->viu.osd1_enabled = false;
+ priv->viu.osd1_commit = false;
+
++ priv->viu.vd1_enabled = false;
++ priv->viu.vd1_commit = false;
++
+ /* Disable VPP Postblend */
+- writel_bits_relaxed(VPP_POSTBLEND_ENABLE, 0,
++ writel_bits_relaxed(VPP_OSD1_POSTBLEND | VPP_VD1_POSTBLEND |
++ VPP_VD1_PREBLEND | VPP_POSTBLEND_ENABLE, 0,
+ priv->io_base + _REG(VPP_MISC));
+
+ if (crtc->state->event && !crtc->state->active) {
+@@ -154,6 +163,7 @@ static void meson_crtc_atomic_flush(struct drm_crtc *crtc,
+ struct meson_drm *priv = meson_crtc->priv;
+
+ priv->viu.osd1_commit = true;
++ priv->viu.vd1_commit = true;
+ }
+
+ static const struct drm_crtc_helper_funcs meson_crtc_helper_funcs = {
+@@ -210,6 +220,164 @@ void meson_crtc_irq(struct meson_drm *priv)
+ priv->viu.osd1_commit = false;
+ }
+
++ /* Update the VD1 registers */
++ if (priv->viu.vd1_enabled && priv->viu.vd1_commit) {
++
++ switch (priv->viu.vd1_planes) {
++ case 3:
++ priv->canvas_ops->setup(priv->canvas_id_vd1_2,
++ priv->viu.vd1_addr2, priv->viu.vd1_stride2,
++ priv->viu.vd1_height2, MESON_CANVAS_WRAP_NONE,
++ MESON_CANVAS_BLKMODE_LINEAR, 7);
++ case 2:
++ priv->canvas_ops->setup(priv->canvas_id_vd1_1,
++ priv->viu.vd1_addr1, priv->viu.vd1_stride1,
++ priv->viu.vd1_height1, MESON_CANVAS_WRAP_NONE,
++ MESON_CANVAS_BLKMODE_LINEAR, 7);
++ case 1:
++ priv->canvas_ops->setup(priv->canvas_id_vd1_0,
++ priv->viu.vd1_addr0, priv->viu.vd1_stride0,
++ priv->viu.vd1_height0, MESON_CANVAS_WRAP_NONE,
++ MESON_CANVAS_BLKMODE_LINEAR, 7);
++ };
++
++ writel_relaxed(priv->viu.vd1_if0_gen_reg,
++ priv->io_base + _REG(VD1_IF0_GEN_REG));
++ writel_relaxed(priv->viu.vd1_if0_gen_reg,
++ priv->io_base + _REG(VD2_IF0_GEN_REG));
++ writel_relaxed(priv->viu.vd1_if0_gen_reg2,
++ priv->io_base + _REG(VD1_IF0_GEN_REG2));
++ writel_relaxed(priv->viu.viu_vd1_fmt_ctrl,
++ priv->io_base + _REG(VIU_VD1_FMT_CTRL));
++ writel_relaxed(priv->viu.viu_vd1_fmt_ctrl,
++ priv->io_base + _REG(VIU_VD2_FMT_CTRL));
++ writel_relaxed(priv->viu.viu_vd1_fmt_w,
++ priv->io_base + _REG(VIU_VD1_FMT_W));
++ writel_relaxed(priv->viu.viu_vd1_fmt_w,
++ priv->io_base + _REG(VIU_VD2_FMT_W));
++ writel_relaxed(priv->viu.vd1_if0_canvas0,
++ priv->io_base + _REG(VD1_IF0_CANVAS0));
++ writel_relaxed(priv->viu.vd1_if0_canvas0,
++ priv->io_base + _REG(VD1_IF0_CANVAS1));
++ writel_relaxed(priv->viu.vd1_if0_canvas0,
++ priv->io_base + _REG(VD2_IF0_CANVAS0));
++ writel_relaxed(priv->viu.vd1_if0_canvas0,
++ priv->io_base + _REG(VD2_IF0_CANVAS1));
++ writel_relaxed(priv->viu.vd1_if0_luma_x0,
++ priv->io_base + _REG(VD1_IF0_LUMA_X0));
++ writel_relaxed(priv->viu.vd1_if0_luma_x0,
++ priv->io_base + _REG(VD1_IF0_LUMA_X1));
++ writel_relaxed(priv->viu.vd1_if0_luma_x0,
++ priv->io_base + _REG(VD2_IF0_LUMA_X0));
++ writel_relaxed(priv->viu.vd1_if0_luma_x0,
++ priv->io_base + _REG(VD2_IF0_LUMA_X1));
++ writel_relaxed(priv->viu.vd1_if0_luma_y0,
++ priv->io_base + _REG(VD1_IF0_LUMA_Y0));
++ writel_relaxed(priv->viu.vd1_if0_luma_y0,
++ priv->io_base + _REG(VD1_IF0_LUMA_Y1));
++ writel_relaxed(priv->viu.vd1_if0_luma_y0,
++ priv->io_base + _REG(VD2_IF0_LUMA_Y0));
++ writel_relaxed(priv->viu.vd1_if0_luma_y0,
++ priv->io_base + _REG(VD2_IF0_LUMA_Y1));
++ writel_relaxed(priv->viu.vd1_if0_chroma_x0,
++ priv->io_base + _REG(VD1_IF0_CHROMA_X0));
++ writel_relaxed(priv->viu.vd1_if0_chroma_x0,
++ priv->io_base + _REG(VD1_IF0_CHROMA_X1));
++ writel_relaxed(priv->viu.vd1_if0_chroma_x0,
++ priv->io_base + _REG(VD2_IF0_CHROMA_X0));
++ writel_relaxed(priv->viu.vd1_if0_chroma_x0,
++ priv->io_base + _REG(VD2_IF0_CHROMA_X1));
++ writel_relaxed(priv->viu.vd1_if0_chroma_y0,
++ priv->io_base + _REG(VD1_IF0_CHROMA_Y0));
++ writel_relaxed(priv->viu.vd1_if0_chroma_y0,
++ priv->io_base + _REG(VD1_IF0_CHROMA_Y1));
++ writel_relaxed(priv->viu.vd1_if0_chroma_y0,
++ priv->io_base + _REG(VD2_IF0_CHROMA_Y0));
++ writel_relaxed(priv->viu.vd1_if0_chroma_y0,
++ priv->io_base + _REG(VD2_IF0_CHROMA_Y1));
++ writel_relaxed(priv->viu.vd1_if0_repeat_loop,
++ priv->io_base + _REG(VD1_IF0_RPT_LOOP));
++ writel_relaxed(priv->viu.vd1_if0_repeat_loop,
++ priv->io_base + _REG(VD2_IF0_RPT_LOOP));
++ writel_relaxed(priv->viu.vd1_if0_luma0_rpt_pat,
++ priv->io_base + _REG(VD1_IF0_LUMA0_RPT_PAT));
++ writel_relaxed(priv->viu.vd1_if0_luma0_rpt_pat,
++ priv->io_base + _REG(VD2_IF0_LUMA0_RPT_PAT));
++ writel_relaxed(priv->viu.vd1_if0_luma0_rpt_pat,
++ priv->io_base + _REG(VD1_IF0_LUMA1_RPT_PAT));
++ writel_relaxed(priv->viu.vd1_if0_luma0_rpt_pat,
++ priv->io_base + _REG(VD2_IF0_LUMA1_RPT_PAT));
++ writel_relaxed(priv->viu.vd1_if0_chroma0_rpt_pat,
++ priv->io_base + _REG(VD1_IF0_CHROMA0_RPT_PAT));
++ writel_relaxed(priv->viu.vd1_if0_chroma0_rpt_pat,
++ priv->io_base + _REG(VD2_IF0_CHROMA0_RPT_PAT));
++ writel_relaxed(priv->viu.vd1_if0_chroma0_rpt_pat,
++ priv->io_base + _REG(VD1_IF0_CHROMA1_RPT_PAT));
++ writel_relaxed(priv->viu.vd1_if0_chroma0_rpt_pat,
++ priv->io_base + _REG(VD2_IF0_CHROMA1_RPT_PAT));
++ writel_relaxed(0, priv->io_base + _REG(VD1_IF0_LUMA_PSEL));
++ writel_relaxed(0, priv->io_base + _REG(VD1_IF0_CHROMA_PSEL));
++ writel_relaxed(0, priv->io_base + _REG(VD2_IF0_LUMA_PSEL));
++ writel_relaxed(0, priv->io_base + _REG(VD2_IF0_CHROMA_PSEL));
++ writel_relaxed(priv->viu.vd1_range_map_y,
++ priv->io_base + _REG(VD1_IF0_RANGE_MAP_Y));
++ writel_relaxed(priv->viu.vd1_range_map_cb,
++ priv->io_base + _REG(VD1_IF0_RANGE_MAP_CB));
++ writel_relaxed(priv->viu.vd1_range_map_cr,
++ priv->io_base + _REG(VD1_IF0_RANGE_MAP_CR));
++ writel_relaxed(0x78404,
++ priv->io_base + _REG(VPP_SC_MISC));
++ writel_relaxed(priv->viu.vpp_pic_in_height,
++ priv->io_base + _REG(VPP_PIC_IN_HEIGHT));
++ writel_relaxed(priv->viu.vpp_postblend_vd1_h_start_end,
++ priv->io_base + _REG(VPP_POSTBLEND_VD1_H_START_END));
++ writel_relaxed(priv->viu.vpp_blend_vd2_h_start_end,
++ priv->io_base + _REG(VPP_BLEND_VD2_H_START_END));
++ writel_relaxed(priv->viu.vpp_postblend_vd1_v_start_end,
++ priv->io_base + _REG(VPP_POSTBLEND_VD1_V_START_END));
++ writel_relaxed(priv->viu.vpp_blend_vd2_v_start_end,
++ priv->io_base + _REG(VPP_BLEND_VD2_V_START_END));
++ writel_relaxed(priv->viu.vpp_hsc_region12_startp,
++ priv->io_base + _REG(VPP_HSC_REGION12_STARTP));
++ writel_relaxed(priv->viu.vpp_hsc_region34_startp,
++ priv->io_base + _REG(VPP_HSC_REGION34_STARTP));
++ writel_relaxed(priv->viu.vpp_hsc_region4_endp,
++ priv->io_base + _REG(VPP_HSC_REGION4_ENDP));
++ writel_relaxed(priv->viu.vpp_hsc_start_phase_step,
++ priv->io_base + _REG(VPP_HSC_START_PHASE_STEP));
++ writel_relaxed(priv->viu.vpp_hsc_region1_phase_slope,
++ priv->io_base + _REG(VPP_HSC_REGION1_PHASE_SLOPE));
++ writel_relaxed(priv->viu.vpp_hsc_region3_phase_slope,
++ priv->io_base + _REG(VPP_HSC_REGION3_PHASE_SLOPE));
++ writel_relaxed(priv->viu.vpp_line_in_length,
++ priv->io_base + _REG(VPP_LINE_IN_LENGTH));
++ writel_relaxed(priv->viu.vpp_preblend_h_size,
++ priv->io_base + _REG(VPP_PREBLEND_H_SIZE));
++ writel_relaxed(priv->viu.vpp_vsc_region12_startp,
++ priv->io_base + _REG(VPP_VSC_REGION12_STARTP));
++ writel_relaxed(priv->viu.vpp_vsc_region34_startp,
++ priv->io_base + _REG(VPP_VSC_REGION34_STARTP));
++ writel_relaxed(priv->viu.vpp_vsc_region4_endp,
++ priv->io_base + _REG(VPP_VSC_REGION4_ENDP));
++ writel_relaxed(priv->viu.vpp_vsc_start_phase_step,
++ priv->io_base + _REG(VPP_VSC_START_PHASE_STEP));
++ writel_relaxed(priv->viu.vpp_vsc_ini_phase,
++ priv->io_base + _REG(VPP_VSC_INI_PHASE));
++ writel_relaxed(priv->viu.vpp_vsc_phase_ctrl,
++ priv->io_base + _REG(VPP_VSC_PHASE_CTRL));
++ writel_relaxed(priv->viu.vpp_hsc_phase_ctrl,
++ priv->io_base + _REG(VPP_HSC_PHASE_CTRL));
++ writel_relaxed(0x00000042,
++ priv->io_base + _REG(VPP_SCALE_COEF_IDX));
++
++ /* Enable VD1 */
++ writel_bits_relaxed(VPP_VD1_PREBLEND | VPP_VD1_POSTBLEND | VPP_COLOR_MNG_ENABLE,
++ VPP_VD1_PREBLEND | VPP_VD1_POSTBLEND | VPP_COLOR_MNG_ENABLE,
++ priv->io_base + _REG(VPP_MISC));
++
++ priv->viu.vd1_commit = false;
++ }
++
+ drm_crtc_handle_vblank(priv->crtc);
+
+ spin_lock_irqsave(&priv->drm->event_lock, flags);
+diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c
+index de46833..2a002cc 100644
+--- a/drivers/gpu/drm/meson/meson_drv.c
++++ b/drivers/gpu/drm/meson/meson_drv.c
+@@ -42,6 +42,7 @@
+
+ #include "meson_drv.h"
+ #include "meson_plane.h"
++#include "meson_overlay.h"
+ #include "meson_crtc.h"
+ #include "meson_venc_cvbs.h"
+
+@@ -241,6 +242,15 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
+ ret = priv->canvas_ops->alloc(&priv->canvas_id_osd1);
+ if (ret)
+ goto free_drm;
++ ret = priv->canvas_ops->alloc(&priv->canvas_id_vd1_0);
++ if (ret)
++ goto free_drm;
++ ret = priv->canvas_ops->alloc(&priv->canvas_id_vd1_1);
++ if (ret)
++ goto free_drm;
++ ret = priv->canvas_ops->alloc(&priv->canvas_id_vd1_2);
++ if (ret)
++ goto free_drm;
+
+ priv->vsync_irq = platform_get_irq(pdev, 0);
+
+@@ -278,6 +288,10 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
+ if (ret)
+ goto free_drm;
+
++ ret = meson_overlay_create(priv);
++ if (ret)
++ goto free_drm;
++
+ ret = meson_crtc_create(priv);
+ if (ret)
+ goto free_drm;
+diff --git a/drivers/gpu/drm/meson/meson_drv.h b/drivers/gpu/drm/meson/meson_drv.h
+index dfea959..e9305d7 100644
+--- a/drivers/gpu/drm/meson/meson_drv.h
++++ b/drivers/gpu/drm/meson/meson_drv.h
+@@ -33,11 +33,15 @@ struct meson_drm {
+
+ struct meson_canvas_platform_data *canvas_ops;
+ uint8_t canvas_id_osd1;
++ uint8_t canvas_id_vd1_0;
++ uint8_t canvas_id_vd1_1;
++ uint8_t canvas_id_vd1_2;
+
+ struct drm_device *drm;
+ struct drm_crtc *crtc;
+ struct drm_fbdev_cma *fbdev;
+ struct drm_plane *primary_plane;
++ struct drm_plane *overlay_plane;
+
+ /* Components Data */
+ struct {
+@@ -49,6 +53,54 @@ struct meson_drm {
+ uint32_t osd1_addr;
+ uint32_t osd1_stride;
+ uint32_t osd1_height;
++
++ bool vd1_enabled;
++ bool vd1_commit;
++ unsigned int vd1_planes;
++ uint32_t vd1_if0_gen_reg;
++ uint32_t vd1_if0_luma_x0;
++ uint32_t vd1_if0_luma_y0;
++ uint32_t vd1_if0_chroma_x0;
++ uint32_t vd1_if0_chroma_y0;
++ uint32_t vd1_if0_repeat_loop;
++ uint32_t vd1_if0_luma0_rpt_pat;
++ uint32_t vd1_if0_chroma0_rpt_pat;
++ uint32_t vd1_range_map_y;
++ uint32_t vd1_range_map_cb;
++ uint32_t vd1_range_map_cr;
++ uint32_t viu_vd1_fmt_w;
++ uint32_t vd1_if0_canvas0;
++ uint32_t vd1_if0_gen_reg2;
++ uint32_t viu_vd1_fmt_ctrl;
++ uint32_t vd1_addr0;
++ uint32_t vd1_addr1;
++ uint32_t vd1_addr2;
++ uint32_t vd1_stride0;
++ uint32_t vd1_stride1;
++ uint32_t vd1_stride2;
++ uint32_t vd1_height0;
++ uint32_t vd1_height1;
++ uint32_t vd1_height2;
++ uint32_t vpp_pic_in_height;
++ uint32_t vpp_postblend_vd1_h_start_end;
++ uint32_t vpp_postblend_vd1_v_start_end;
++ uint32_t vpp_hsc_region12_startp;
++ uint32_t vpp_hsc_region34_startp;
++ uint32_t vpp_hsc_region4_endp;
++ uint32_t vpp_hsc_start_phase_step;
++ uint32_t vpp_hsc_region1_phase_slope;
++ uint32_t vpp_hsc_region3_phase_slope;
++ uint32_t vpp_line_in_length;
++ uint32_t vpp_preblend_h_size;
++ uint32_t vpp_vsc_region12_startp;
++ uint32_t vpp_vsc_region34_startp;
++ uint32_t vpp_vsc_region4_endp;
++ uint32_t vpp_vsc_start_phase_step;
++ uint32_t vpp_vsc_ini_phase;
++ uint32_t vpp_vsc_phase_ctrl;
++ uint32_t vpp_hsc_phase_ctrl;
++ uint32_t vpp_blend_vd2_h_start_end;
++ uint32_t vpp_blend_vd2_v_start_end;
+ } viu;
+
+ struct {
+diff --git a/drivers/gpu/drm/meson/meson_overlay.c b/drivers/gpu/drm/meson/meson_overlay.c
+new file mode 100644
+index 0000000..ea7261a
+--- /dev/null
++++ b/drivers/gpu/drm/meson/meson_overlay.c
+@@ -0,0 +1,595 @@
++// SPDX-License-Identifier: GPL-2.0+
++/*
++ * Copyright (C) 2018 BayLibre, SAS
++ * Author: Neil Armstrong <narmstrong@baylibre.com>
++ * Copyright (C) 2015 Amlogic, Inc. All rights reserved.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/mutex.h>
++#include <linux/bitfield.h>
++#include <linux/platform_device.h>
++#include <drm/drmP.h>
++#include <drm/drm_atomic.h>
++#include <drm/drm_atomic_helper.h>
++#include <drm/drm_plane_helper.h>
++#include <drm/drm_gem_cma_helper.h>
++#include <drm/drm_fb_cma_helper.h>
++#include <drm/drm_rect.h>
++
++#include "meson_overlay.h"
++#include "meson_vpp.h"
++#include "meson_viu.h"
++#include "meson_registers.h"
++
++/* VD1_IF0_GEN_REG */
++#define VD_URGENT_CHROMA BIT(28)
++#define VD_URGENT_LUMA BIT(27)
++#define VD_HOLD_LINES(lines) FIELD_PREP(GENMASK(24, 19), lines)
++#define VD_DEMUX_MODE_RGB BIT(16)
++#define VD_BYTES_PER_PIXEL(val) FIELD_PREP(GENMASK(15, 14), val)
++#define VD_CHRO_RPT_LASTL_CTRL BIT(6)
++#define VD_LITTLE_ENDIAN BIT(4)
++#define VD_SEPARATE_EN BIT(1)
++#define VD_ENABLE BIT(0)
++
++/* VD1_IF0_CANVAS0 */
++#define CANVAS_ADDR2(addr) FIELD_PREP(GENMASK(23, 16), addr)
++#define CANVAS_ADDR1(addr) FIELD_PREP(GENMASK(15, 8), addr)
++#define CANVAS_ADDR0(addr) FIELD_PREP(GENMASK(7, 0), addr)
++
++/* VD1_IF0_LUMA_X0 VD1_IF0_CHROMA_X0 */
++#define VD_X_START(value) FIELD_PREP(GENMASK(14, 0), value)
++#define VD_X_END(value) FIELD_PREP(GENMASK(30, 16), value)
++
++/* VD1_IF0_LUMA_Y0 VD1_IF0_CHROMA_Y0 */
++#define VD_Y_START(value) FIELD_PREP(GENMASK(12, 0), value)
++#define VD_Y_END(value) FIELD_PREP(GENMASK(28, 16), value)
++
++/* VD1_IF0_GEN_REG2 */
++#define VD_COLOR_MAP(value) FIELD_PREP(GENMASK(1, 0), value)
++
++/* VIU_VD1_FMT_CTRL */
++#define VD_HORZ_Y_C_RATIO(value) FIELD_PREP(GENMASK(22, 21), value)
++#define VD_HORZ_FMT_EN BIT(20)
++#define VD_VERT_RPT_LINE0 BIT(16)
++#define VD_VERT_INITIAL_PHASE(value) FIELD_PREP(GENMASK(11, 8), value)
++#define VD_VERT_PHASE_STEP(value) FIELD_PREP(GENMASK(7, 1), value)
++#define VD_VERT_FMT_EN BIT(0)
++
++/* VPP_POSTBLEND_VD1_H_START_END */
++#define VD_H_END(value) FIELD_PREP(GENMASK(11, 0), value)
++#define VD_H_START(value) FIELD_PREP(GENMASK(27, 16), value)
++
++/* VPP_POSTBLEND_VD1_V_START_END */
++#define VD_V_END(value) FIELD_PREP(GENMASK(11, 0), value)
++#define VD_V_START(value) FIELD_PREP(GENMASK(27, 16), value)
++
++/* VPP_BLEND_VD2_V_START_END */
++#define VD2_V_END(value) FIELD_PREP(GENMASK(11, 0), value)
++#define VD2_V_START(value) FIELD_PREP(GENMASK(27, 16), value)
++
++/* VIU_VD1_FMT_W */
++#define VD_V_WIDTH(value) FIELD_PREP(GENMASK(11, 0), value)
++#define VD_H_WIDTH(value) FIELD_PREP(GENMASK(27, 16), value)
++
++/* VPP_HSC_REGION12_STARTP VPP_HSC_REGION34_STARTP */
++#define VD_REGION24_START(value) FIELD_PREP(GENMASK(11, 0), value)
++#define VD_REGION13_END(value) FIELD_PREP(GENMASK(27, 16), value)
++
++struct meson_overlay {
++ struct drm_plane base;
++ struct meson_drm *priv;
++};
++#define to_meson_overlay(x) container_of(x, struct meson_overlay, base)
++
++#define FRAC_16_16(mult, div) (((mult) << 16) / (div))
++
++static int meson_overlay_atomic_check(struct drm_plane *plane,
++ struct drm_plane_state *state)
++{
++ struct drm_crtc_state *crtc_state;
++
++ if (!state->crtc)
++ return 0;
++
++ crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc);
++ if (IS_ERR(crtc_state))
++ return PTR_ERR(crtc_state);
++
++ return drm_atomic_helper_check_plane_state(state, crtc_state,
++ FRAC_16_16(1, 5),
++ FRAC_16_16(5, 1),
++ true, true);
++}
++
++/* Takes a fixed 16.16 number and converts it to integer. */
++static inline int64_t fixed16_to_int(int64_t value)
++{
++ return value >> 16;
++}
++
++static const uint8_t skip_tab[6] = {0x24, 0x04, 0x68, 0x48, 0x28, 0x08};
++
++static void meson_overlay_get_vertical_phase(unsigned ratio_y,
++ int *phase,
++ int *repeat,
++ bool interlace)
++{
++ int offset_in = 0;
++ int offset_out = 0;
++ int repeat_skip = 0;
++
++ if (!interlace && ratio_y > (1 << 18)) {
++ offset_out = (1 * ratio_y) >> 10;
++ }
++
++ while ((offset_in + (4 << 8)) <= offset_out) {
++ repeat_skip++;
++ offset_in += 4 << 8;
++ }
++
++ *phase = (offset_out - offset_in) >> 2;
++
++ if (*phase > 0x100)
++ repeat_skip++;
++
++ *phase = *phase & 0xff;
++
++ if (repeat_skip > 5)
++ repeat_skip = 5;
++
++ *repeat = skip_tab[repeat_skip];
++}
++
++static void meson_overlay_setup_scaler_params(struct meson_drm *priv,
++ struct drm_plane *plane,
++ bool interlace_mode)
++{
++ struct drm_plane_state *state = plane->state;
++ struct drm_crtc_state *crtc_state = priv->crtc->state;
++ int video_top, video_left, video_width, video_height;
++ unsigned int crop_top, crop_left;
++ unsigned int crtc_height, crtc_width;
++ unsigned int vd_start_lines, vd_end_lines;
++ unsigned int hd_start_lines, hd_end_lines;
++ unsigned int vsc_startp, vsc_endp;
++ unsigned int hsc_startp, hsc_endp;
++ unsigned int ratio_x, ratio_y;
++ unsigned int w_in, h_in;
++ int vphase, vphase_repeat_skip;
++ int temp_height, temp_width;
++ int temp, start, end;
++
++ if (!crtc_state) {
++ DRM_ERROR("Invalid crtc_state\n");
++ return;
++ }
++
++ crtc_height = crtc_state->mode.vdisplay;
++ crtc_width = crtc_state->mode.hdisplay;
++
++ w_in = fixed16_to_int(state->src_w);
++ h_in = fixed16_to_int(state->src_h);
++ crop_top = fixed16_to_int(state->src_x);
++ crop_left = fixed16_to_int(state->src_x);
++
++ video_top = state->crtc_y;
++ video_left = state->crtc_x;
++ video_width = state->crtc_w;
++ video_height = state->crtc_h;
++
++ DRM_DEBUG("crtc_width %d crtc_height %d interlace %d\n",
++ crtc_width, crtc_height, interlace_mode);
++ DRM_DEBUG("w_in %d h_in %d crop_top %d crop_left %d\n",
++ w_in, h_in, crop_top, crop_left);
++ DRM_DEBUG("video top %d left %d width %d height %d\n",
++ video_top, video_left, video_width, video_height);
++
++ ratio_x = (w_in << 18) / video_width;
++ ratio_y = (h_in << 18) / video_height;
++
++ /* TOFIX Interlace output */
++ if (interlace_mode)
++ ratio_y <<= 1;
++
++ if (ratio_x * video_width < (w_in << 18))
++ ratio_x++;
++
++ DRM_DEBUG("ratio x 0x%x y 0x%x\n", ratio_x, ratio_y);
++
++ meson_overlay_get_vertical_phase(ratio_y, &vphase, &vphase_repeat_skip,
++ interlace_mode);
++
++ DRM_DEBUG("vphase 0x%x skip %d\n", vphase, vphase_repeat_skip);
++
++ /* Vertical */
++
++ start = video_top + video_height / 2 - ((h_in << 17) / ratio_x);
++ end = (h_in << 18) / ratio_y + start - 1;
++
++ if (video_top < 0 && start < 0)
++ vd_start_lines = (-(start) * ratio_y) >> 18;
++ else if (start < video_top)
++ vd_start_lines = ((video_top - start) * ratio_y) >> 18;
++ else
++ vd_start_lines = 0;
++
++ if (video_top < 0)
++ temp_height = min_t(unsigned int, (video_top + video_height - 1),
++ (crtc_height - 1));
++ else
++ temp_height = min_t(unsigned int, (video_top + video_height - 1),
++ (crtc_height - 1)) - video_top + 1;
++
++ temp = vd_start_lines + (temp_height * ratio_y >> 18);
++ vd_end_lines = (temp <= (h_in - 1)) ? temp : (h_in - 1);
++
++ vd_start_lines += crop_left;
++ vd_end_lines += crop_left;
++
++ if (interlace_mode) {
++ start >>= 1;
++ end >>= 1;
++ }
++
++ vsc_startp = max_t(int, start,
++ max_t(int, 0, video_top));
++ vsc_endp = min_t(int, end,
++ min_t(int, crtc_height - 1,
++ video_top + video_height - 1));
++
++ DRM_DEBUG("vsc startp %d endp %d start_lines %d end_lines %d\n",
++ vsc_startp, vsc_endp, vd_start_lines, vd_end_lines);
++
++ /* Horizontal */
++
++ start = video_left + video_width / 2 - ((w_in << 17) / ratio_x);
++ end = (w_in << 18) / ratio_x + start - 1;
++
++ if (video_left < 0 && start < 0)
++ hd_start_lines = (-(start) * ratio_x) >> 18;
++ else if (start < video_left)
++ hd_start_lines = ((video_left - start) * ratio_x) >> 18;
++ else
++ hd_start_lines = 0;
++
++ if (video_left < 0)
++ temp_width = min_t(unsigned int, (video_left + video_width - 1),
++ (crtc_width - 1));
++ else
++ temp_width = min_t(unsigned int, (video_left + video_width - 1),
++ (crtc_width - 1)) - video_left + 1;
++
++ temp = hd_start_lines + (temp_width * ratio_x >> 18);
++ hd_end_lines = (temp <= (w_in - 1)) ? temp : (w_in - 1);
++
++ priv->viu.vpp_line_in_length = hd_end_lines - hd_start_lines + 1;
++ hsc_startp = max_t(int, start,
++ max_t(int, 0, video_left));
++ hsc_endp = min_t(int, end,
++ min_t(int, crtc_width - 1,
++ video_left + video_width - 1));
++
++ hd_start_lines += crop_top;
++ hd_end_lines += crop_top;
++
++ DRM_DEBUG("hsc startp %d endp %d start_lines %d end_lines %d\n",
++ hsc_startp, hsc_endp, hd_start_lines, hd_end_lines);
++
++ priv->viu.vpp_vsc_start_phase_step = ratio_y << 6;
++
++ priv->viu.vpp_vsc_ini_phase = vphase << 8;
++ priv->viu.vpp_vsc_phase_ctrl = (1 << 13) | (4 << 8) |
++ vphase_repeat_skip;
++
++ priv->viu.vd1_if0_luma_x0 = VD_X_START(hd_start_lines) |
++ VD_X_END(hd_end_lines);
++ priv->viu.vd1_if0_chroma_x0 = VD_X_START(hd_start_lines >> 1) |
++ VD_X_END(hd_end_lines >> 1);
++
++ priv->viu.viu_vd1_fmt_w = VD_H_WIDTH(hd_end_lines - hd_start_lines + 1) |
++ VD_V_WIDTH(hd_end_lines/2 - hd_start_lines/2 + 1);
++
++ priv->viu.vd1_if0_luma_y0 = VD_Y_START(vd_start_lines) |
++ VD_Y_END(vd_end_lines);
++
++ priv->viu.vd1_if0_chroma_y0 = VD_Y_START(vd_start_lines >> 1) |
++ VD_Y_END(vd_end_lines >> 1);
++
++ priv->viu.vpp_pic_in_height = h_in;
++
++ priv->viu.vpp_postblend_vd1_h_start_end = VD_H_START(hsc_startp) |
++ VD_H_END(hsc_endp);
++ priv->viu.vpp_blend_vd2_h_start_end = VD_H_START(hd_start_lines) |
++ VD_H_END(hd_end_lines);
++ priv->viu.vpp_hsc_region12_startp = VD_REGION13_END(0) |
++ VD_REGION24_START(hsc_startp);
++ priv->viu.vpp_hsc_region34_startp = VD_REGION13_END(hsc_startp) |
++ VD_REGION24_START(hsc_endp - hsc_startp);
++ priv->viu.vpp_hsc_region4_endp = hsc_endp - hsc_startp;
++ priv->viu.vpp_hsc_start_phase_step = ratio_x << 6;
++ priv->viu.vpp_hsc_region1_phase_slope = 0;
++ priv->viu.vpp_hsc_region3_phase_slope = 0;
++ priv->viu.vpp_hsc_phase_ctrl = (1 << 21) | (4 << 16);
++
++ priv->viu.vpp_line_in_length = hd_end_lines - hd_start_lines + 1;
++ priv->viu.vpp_preblend_h_size = hd_end_lines - hd_start_lines + 1;
++
++ priv->viu.vpp_postblend_vd1_v_start_end = VD_V_START(vsc_startp) |
++ VD_V_END(vsc_endp);
++ priv->viu.vpp_blend_vd2_v_start_end =
++ VD2_V_START((vd_end_lines + 1) >> 1) |
++ VD2_V_END(vd_end_lines);
++
++ priv->viu.vpp_vsc_region12_startp = 0;
++ priv->viu.vpp_vsc_region34_startp =
++ VD_REGION13_END(vsc_endp - vsc_startp) |
++ VD_REGION24_START(vsc_endp - vsc_startp);
++ priv->viu.vpp_vsc_region4_endp = vsc_endp - vsc_startp;
++ priv->viu.vpp_vsc_start_phase_step = ratio_y << 6;
++}
++
++static void meson_overlay_atomic_update(struct drm_plane *plane,
++ struct drm_plane_state *old_state)
++{
++ struct meson_overlay *meson_overlay = to_meson_overlay(plane);
++ struct drm_plane_state *state = plane->state;
++ struct drm_framebuffer *fb = state->fb;
++ struct meson_drm *priv = meson_overlay->priv;
++ struct drm_gem_cma_object *gem;
++ unsigned long flags;
++ bool interlace_mode;
++
++ DRM_DEBUG_DRIVER("\n");
++
++ interlace_mode = state->crtc->mode.flags & DRM_MODE_FLAG_INTERLACE;
++
++ /*
++ * Update Coordinates
++ * Update Formats
++ * Update Buffer
++ * Enable Plane
++ */
++ spin_lock_irqsave(&priv->drm->event_lock, flags);
++
++ priv->viu.vd1_if0_gen_reg = VD_URGENT_CHROMA |
++ VD_URGENT_LUMA |
++ VD_HOLD_LINES(9) |
++ VD_CHRO_RPT_LASTL_CTRL |
++ VD_ENABLE;
++
++ /* Setup scaler params */
++ meson_overlay_setup_scaler_params(priv, plane, interlace_mode);
++
++ //VD1_IF0_CANVAS1=0
++ //VD1_IF0_CHROMA_X1=0
++ //VD1_IF0_CHROMA_Y1=0
++ priv->viu.vd1_if0_repeat_loop = 0;
++ priv->viu.vd1_if0_luma0_rpt_pat = interlace_mode ? 8 : 0;
++ priv->viu.vd1_if0_chroma0_rpt_pat = interlace_mode ? 8 : 0;
++ //VD1_IF0_LUMA1_RPT_PAT=0
++ //VD1_IF0_CHROMA1_RPT_PAT=0
++ //VD1_IF0_LUMA_PSEL=0
++ //VD1_IF0_CHROMA_PSEL=0
++ //VD1_IF0_DUMMY_PIXEL=?
++ priv->viu.vd1_range_map_y = 0;
++ priv->viu.vd1_range_map_cb = 0;
++ priv->viu.vd1_range_map_cr = 0;
++
++ /* Default values for RGB888/YUV444 */
++ priv->viu.vd1_if0_gen_reg2 = 0;
++ priv->viu.viu_vd1_fmt_ctrl = 0;
++
++ switch (fb->format->format) {
++ case DRM_FORMAT_RGB888:
++ /* TOFIX enable RGB2YUV somewhere ! */
++ priv->viu.vd1_if0_gen_reg |= VD_DEMUX_MODE_RGB |
++ VD_BYTES_PER_PIXEL(2);
++ priv->viu.vd1_if0_canvas0 =
++ CANVAS_ADDR2(priv->canvas_id_vd1_0) |
++ CANVAS_ADDR1(priv->canvas_id_vd1_0) |
++ CANVAS_ADDR0(priv->canvas_id_vd1_0);
++ break;
++ case DRM_FORMAT_YUYV:
++ priv->viu.vd1_if0_gen_reg |= VD_BYTES_PER_PIXEL(1);
++ priv->viu.vd1_if0_canvas0 =
++ CANVAS_ADDR2(priv->canvas_id_vd1_0) |
++ CANVAS_ADDR1(priv->canvas_id_vd1_0) |
++ CANVAS_ADDR0(priv->canvas_id_vd1_0);
++ priv->viu.viu_vd1_fmt_ctrl = VD_HORZ_Y_C_RATIO(1) | /* /2 */
++ VD_HORZ_FMT_EN |
++ VD_VERT_RPT_LINE0 |
++ VD_VERT_INITIAL_PHASE(12) |
++ VD_VERT_PHASE_STEP(16) | /* /2 */
++ VD_VERT_FMT_EN;
++ break;
++ case DRM_FORMAT_NV12:
++ case DRM_FORMAT_NV21:
++ priv->viu.vd1_if0_gen_reg |= VD_SEPARATE_EN;
++ priv->viu.vd1_if0_canvas0 =
++ CANVAS_ADDR2(priv->canvas_id_vd1_1) |
++ CANVAS_ADDR1(priv->canvas_id_vd1_1) |
++ CANVAS_ADDR0(priv->canvas_id_vd1_0);
++ if (fb->format->format == DRM_FORMAT_NV12)
++ priv->viu.vd1_if0_gen_reg2 = VD_COLOR_MAP(1);
++ else
++ priv->viu.vd1_if0_gen_reg2 = VD_COLOR_MAP(2);
++ priv->viu.viu_vd1_fmt_ctrl = VD_HORZ_Y_C_RATIO(1) | /* /2 */
++ VD_HORZ_FMT_EN |
++ VD_VERT_RPT_LINE0 |
++ VD_VERT_INITIAL_PHASE(12) |
++ VD_VERT_PHASE_STEP(8) | /* /4 */
++ VD_VERT_FMT_EN;
++ break;
++ case DRM_FORMAT_YUV444:
++ case DRM_FORMAT_YUV422:
++ case DRM_FORMAT_YUV420:
++ case DRM_FORMAT_YUV411:
++ case DRM_FORMAT_YUV410:
++ priv->viu.vd1_if0_gen_reg |= VD_SEPARATE_EN;
++ priv->viu.vd1_if0_canvas0 =
++ CANVAS_ADDR2(priv->canvas_id_vd1_2) |
++ CANVAS_ADDR1(priv->canvas_id_vd1_1) |
++ CANVAS_ADDR0(priv->canvas_id_vd1_0);
++ switch (fb->format->format) {
++ case DRM_FORMAT_YUV422:
++ priv->viu.viu_vd1_fmt_ctrl =
++ VD_HORZ_Y_C_RATIO(1) | /* /2 */
++ VD_HORZ_FMT_EN |
++ VD_VERT_RPT_LINE0 |
++ VD_VERT_INITIAL_PHASE(12) |
++ VD_VERT_PHASE_STEP(16) | /* /2 */
++ VD_VERT_FMT_EN;
++ break;
++ case DRM_FORMAT_YUV420:
++ priv->viu.viu_vd1_fmt_ctrl =
++ VD_HORZ_Y_C_RATIO(1) | /* /2 */
++ VD_HORZ_FMT_EN |
++ VD_VERT_RPT_LINE0 |
++ VD_VERT_INITIAL_PHASE(12) |
++ VD_VERT_PHASE_STEP(8) | /* /4 */
++ VD_VERT_FMT_EN;
++ break;
++ case DRM_FORMAT_YUV411:
++ priv->viu.viu_vd1_fmt_ctrl =
++ VD_HORZ_Y_C_RATIO(2) | /* /4 */
++ VD_HORZ_FMT_EN |
++ VD_VERT_RPT_LINE0 |
++ VD_VERT_INITIAL_PHASE(12) |
++ VD_VERT_PHASE_STEP(16) | /* /2 */
++ VD_VERT_FMT_EN;
++ break;
++ case DRM_FORMAT_YUV410:
++ priv->viu.viu_vd1_fmt_ctrl =
++ VD_HORZ_Y_C_RATIO(2) | /* /4 */
++ VD_HORZ_FMT_EN |
++ VD_VERT_RPT_LINE0 |
++ VD_VERT_INITIAL_PHASE(12) |
++ VD_VERT_PHASE_STEP(8) | /* /4 */
++ VD_VERT_FMT_EN;
++ break;
++ }
++ break;
++ }
++
++ /* Update Canvas with buffer address */
++ priv->viu.vd1_planes = drm_format_num_planes(fb->format->format);
++
++ switch (priv->viu.vd1_planes) {
++ case 3:
++ gem = drm_fb_cma_get_gem_obj(fb, 2);
++ priv->viu.vd1_addr2 = gem->paddr + fb->offsets[2];
++ priv->viu.vd1_stride2 = fb->pitches[2];
++ priv->viu.vd1_height2 =
++ drm_format_plane_height(fb->height,
++ fb->format->format, 2);
++ DRM_DEBUG("plane 2 addr 0x%x stride %d height %d\n",
++ priv->viu.vd1_addr2,
++ priv->viu.vd1_stride2,
++ priv->viu.vd1_height2);
++ case 2:
++ gem = drm_fb_cma_get_gem_obj(fb, 1);
++ priv->viu.vd1_addr1 = gem->paddr + fb->offsets[1];
++ priv->viu.vd1_stride1 = fb->pitches[1];
++ priv->viu.vd1_height1 =
++ drm_format_plane_height(fb->height,
++ fb->format->format, 1);
++ DRM_DEBUG("plane 1 addr 0x%x stride %d height %d\n",
++ priv->viu.vd1_addr1,
++ priv->viu.vd1_stride1,
++ priv->viu.vd1_height1);
++ case 1:
++ gem = drm_fb_cma_get_gem_obj(fb, 0);
++ priv->viu.vd1_addr0 = gem->paddr + fb->offsets[0];
++ priv->viu.vd1_stride0 = fb->pitches[0];
++ priv->viu.vd1_height0 =
++ drm_format_plane_height(fb->height,
++ fb->format->format, 0);
++ DRM_DEBUG("plane 0 addr 0x%x stride %d height %d\n",
++ priv->viu.vd1_addr0,
++ priv->viu.vd1_stride0,
++ priv->viu.vd1_height0);
++ }
++
++ priv->viu.vd1_enabled = true;
++
++ spin_unlock_irqrestore(&priv->drm->event_lock, flags);
++
++ DRM_DEBUG_DRIVER("\n");
++}
++
++static void meson_overlay_atomic_disable(struct drm_plane *plane,
++ struct drm_plane_state *old_state)
++{
++ struct meson_overlay *meson_overlay = to_meson_overlay(plane);
++ struct meson_drm *priv = meson_overlay->priv;
++
++ DRM_DEBUG_DRIVER("\n");
++
++ priv->viu.vd1_enabled = false;
++
++ /* Disable VD1 */
++ writel_bits_relaxed(VPP_VD1_POSTBLEND | VPP_VD1_PREBLEND, 0,
++ priv->io_base + _REG(VPP_MISC));
++
++}
++
++static const struct drm_plane_helper_funcs meson_overlay_helper_funcs = {
++ .atomic_check = meson_overlay_atomic_check,
++ .atomic_disable = meson_overlay_atomic_disable,
++ .atomic_update = meson_overlay_atomic_update,
++};
++
++static const struct drm_plane_funcs meson_overlay_funcs = {
++ .update_plane = drm_atomic_helper_update_plane,
++ .disable_plane = drm_atomic_helper_disable_plane,
++ .destroy = drm_plane_cleanup,
++ .reset = drm_atomic_helper_plane_reset,
++ .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
++ .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
++};
++
++static const uint32_t supported_drm_formats[] = {
++ DRM_FORMAT_RGB888,
++ DRM_FORMAT_YUYV,
++ DRM_FORMAT_NV12,
++ DRM_FORMAT_NV21,
++ DRM_FORMAT_YUV444,
++ DRM_FORMAT_YUV422,
++ DRM_FORMAT_YUV420,
++ DRM_FORMAT_YUV411,
++ DRM_FORMAT_YUV410,
++};
++
++int meson_overlay_create(struct meson_drm *priv)
++{
++ struct meson_overlay *meson_overlay;
++ struct drm_plane *plane;
++
++ DRM_DEBUG_DRIVER("\n");
++
++ meson_overlay = devm_kzalloc(priv->drm->dev, sizeof(*meson_overlay),
++ GFP_KERNEL);
++ if (!meson_overlay)
++ return -ENOMEM;
++
++ meson_overlay->priv = priv;
++ plane = &meson_overlay->base;
++
++ drm_universal_plane_init(priv->drm, plane, 0xFF,
++ &meson_overlay_funcs,
++ supported_drm_formats,
++ ARRAY_SIZE(supported_drm_formats),
++ NULL,
++ DRM_PLANE_TYPE_OVERLAY, "meson_overlay_plane");
++
++ drm_plane_helper_add(plane, &meson_overlay_helper_funcs);
++
++ priv->overlay_plane = plane;
++
++ DRM_DEBUG_DRIVER("\n");
++
++ return 0;
++}
+diff --git a/drivers/gpu/drm/meson/meson_overlay.h b/drivers/gpu/drm/meson/meson_overlay.h
+new file mode 100644
+index 0000000..0fd63da
+--- /dev/null
++++ b/drivers/gpu/drm/meson/meson_overlay.h
+@@ -0,0 +1,14 @@
++// SPDX-License-Identifier: GPL-2.0+
++/*
++ * Copyright (C) 2018 BayLibre, SAS
++ * Author: Neil Armstrong <narmstrong@baylibre.com>
++ */
++
++#ifndef __MESON_OVERLAY_H
++#define __MESON_OVERLAY_H
++
++#include "meson_drv.h"
++
++int meson_overlay_create(struct meson_drm *priv);
++
++#endif /* __MESON_OVERLAY_H */
+diff --git a/drivers/gpu/drm/meson/meson_registers.h b/drivers/gpu/drm/meson/meson_registers.h
+index bca8714..5c7e02c 100644
+--- a/drivers/gpu/drm/meson/meson_registers.h
++++ b/drivers/gpu/drm/meson/meson_registers.h
+@@ -286,6 +286,7 @@
+ #define VIU_OSD1_MATRIX_COEF22_30 0x1a9d
+ #define VIU_OSD1_MATRIX_COEF31_32 0x1a9e
+ #define VIU_OSD1_MATRIX_COEF40_41 0x1a9f
++#define VD1_IF0_GEN_REG3 0x1aa7
+ #define VIU_OSD1_EOTF_CTL 0x1ad4
+ #define VIU_OSD1_EOTF_COEF00_01 0x1ad5
+ #define VIU_OSD1_EOTF_COEF02_10 0x1ad6
+@@ -297,6 +298,7 @@
+ #define VIU_OSD1_OETF_CTL 0x1adc
+ #define VIU_OSD1_OETF_LUT_ADDR_PORT 0x1add
+ #define VIU_OSD1_OETF_LUT_DATA_PORT 0x1ade
++#define AFBC_ENABLE 0x1ae0
+
+ /* vpp */
+ #define VPP_DUMMY_DATA 0x1d00
+@@ -349,6 +351,7 @@
+ #define VPP_VD2_PREBLEND BIT(15)
+ #define VPP_OSD1_PREBLEND BIT(16)
+ #define VPP_OSD2_PREBLEND BIT(17)
++#define VPP_COLOR_MNG_ENABLE BIT(28)
+ #define VPP_OFIFO_SIZE 0x1d27
+ #define VPP_FIFO_STATUS 0x1d28
+ #define VPP_SMOKE_CTRL 0x1d29
+diff --git a/drivers/gpu/drm/meson/meson_viu.c b/drivers/gpu/drm/meson/meson_viu.c
+index 5b48c4c..a423e7a 100644
+--- a/drivers/gpu/drm/meson/meson_viu.c
++++ b/drivers/gpu/drm/meson/meson_viu.c
+@@ -328,6 +328,21 @@ void meson_viu_init(struct meson_drm *priv)
+ 0xff << OSD_REPLACE_SHIFT,
+ priv->io_base + _REG(VIU_OSD2_CTRL_STAT2));
+
++ /* Disable VD1 AFBC */
++ /* di_mif0_en=0 mif0_to_vpp_en=0 di_mad_en=0 */
++ writel_bits_relaxed(0x7 << 16, 0,
++ priv->io_base + _REG(VIU_MISC_CTRL0));
++ /* afbc vd1 set=0 */
++ writel_bits_relaxed(BIT(20), 0,
++ priv->io_base + _REG(VIU_MISC_CTRL0));
++ writel_relaxed(0, priv->io_base + _REG(AFBC_ENABLE));
++
++ writel_relaxed(0x00FF00C0,
++ priv->io_base + _REG(VD1_IF0_LUMA_FIFO_SIZE));
++ writel_relaxed(0x00FF00C0,
++ priv->io_base + _REG(VD2_IF0_LUMA_FIFO_SIZE));
++
++
+ priv->viu.osd1_enabled = false;
+ priv->viu.osd1_commit = false;
+ priv->viu.osd1_interlace = false;
+diff --git a/drivers/gpu/drm/meson/meson_vpp.c b/drivers/gpu/drm/meson/meson_vpp.c
+index 27356f8..5dc24a9 100644
+--- a/drivers/gpu/drm/meson/meson_vpp.c
++++ b/drivers/gpu/drm/meson/meson_vpp.c
+@@ -122,6 +122,31 @@ static void meson_vpp_write_scaling_filter_coefs(struct meson_drm *priv,
+ priv->io_base + _REG(VPP_OSD_SCALE_COEF));
+ }
+
++static const uint32_t vpp_filter_coefs_bicubic[] = {
++ 0x00800000, 0x007f0100, 0xff7f0200, 0xfe7f0300,
++ 0xfd7e0500, 0xfc7e0600, 0xfb7d0800, 0xfb7c0900,
++ 0xfa7b0b00, 0xfa7a0dff, 0xf9790fff, 0xf97711ff,
++ 0xf87613ff, 0xf87416fe, 0xf87218fe, 0xf8701afe,
++ 0xf76f1dfd, 0xf76d1ffd, 0xf76b21fd, 0xf76824fd,
++ 0xf76627fc, 0xf76429fc, 0xf7612cfc, 0xf75f2ffb,
++ 0xf75d31fb, 0xf75a34fb, 0xf75837fa, 0xf7553afa,
++ 0xf8523cfa, 0xf8503ff9, 0xf84d42f9, 0xf84a45f9,
++ 0xf84848f8
++};
++
++static void meson_vpp_write_vd_scaling_filter_coefs(struct meson_drm *priv,
++ const unsigned int *coefs,
++ bool is_horizontal)
++{
++ int i;
++
++ writel_relaxed(is_horizontal ? BIT(8) : 0,
++ priv->io_base + _REG(VPP_SCALE_COEF_IDX));
++ for (i = 0; i < 33; i++)
++ writel_relaxed(coefs[i],
++ priv->io_base + _REG(VPP_SCALE_COEF));
++}
++
+ void meson_vpp_init(struct meson_drm *priv)
+ {
+ /* set dummy data default YUV black */
+@@ -150,17 +175,34 @@ void meson_vpp_init(struct meson_drm *priv)
+
+ /* Force all planes off */
+ writel_bits_relaxed(VPP_OSD1_POSTBLEND | VPP_OSD2_POSTBLEND |
+- VPP_VD1_POSTBLEND | VPP_VD2_POSTBLEND, 0,
++ VPP_VD1_POSTBLEND | VPP_VD2_POSTBLEND |
++ VPP_VD1_PREBLEND | VPP_VD2_PREBLEND, 0,
+ priv->io_base + _REG(VPP_MISC));
+
++ /* Setup default VD settings */
++ writel_relaxed(4096,
++ priv->io_base + _REG(VPP_PREBLEND_VD1_H_START_END));
++ writel_relaxed(4096,
++ priv->io_base + _REG(VPP_BLEND_VD2_H_START_END));
++
+ /* Disable Scalers */
+ writel_relaxed(0, priv->io_base + _REG(VPP_OSD_SC_CTRL0));
+ writel_relaxed(0, priv->io_base + _REG(VPP_OSD_VSC_CTRL0));
+ writel_relaxed(0, priv->io_base + _REG(VPP_OSD_HSC_CTRL0));
++ writel_relaxed(4 | (4 << 8) | BIT(15),
++ priv->io_base + _REG(VPP_SC_MISC));
++
++ writel_relaxed(1, priv->io_base + _REG(VPP_VADJ_CTRL));
+
+ /* Write in the proper filter coefficients. */
+ meson_vpp_write_scaling_filter_coefs(priv,
+ vpp_filter_coefs_4point_bspline, false);
+ meson_vpp_write_scaling_filter_coefs(priv,
+ vpp_filter_coefs_4point_bspline, true);
++
++ /* Write the VD proper filter coefficients. */
++ meson_vpp_write_vd_scaling_filter_coefs(priv, vpp_filter_coefs_bicubic,
++ false);
++ meson_vpp_write_vd_scaling_filter_coefs(priv, vpp_filter_coefs_bicubic,
++ true);
+ }
+diff --git a/drivers/soc/amlogic/meson-gx-pwrc-vpu.c b/drivers/soc/amlogic/meson-gx-pwrc-vpu.c
+index 6289965..05421d0 100644
+--- a/drivers/soc/amlogic/meson-gx-pwrc-vpu.c
++++ b/drivers/soc/amlogic/meson-gx-pwrc-vpu.c
+@@ -54,12 +54,12 @@ static int meson_gx_pwrc_vpu_power_off(struct generic_pm_domain *genpd)
+ /* Power Down Memories */
+ for (i = 0; i < 32; i += 2) {
+ regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG0,
+- 0x2 << i, 0x3 << i);
++ 0x3 << i, 0x3 << i);
+ udelay(5);
+ }
+ for (i = 0; i < 32; i += 2) {
+ regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG1,
+- 0x2 << i, 0x3 << i);
++ 0x3 << i, 0x3 << i);
+ udelay(5);
+ }
+ for (i = 8; i < 16; i++) {
+@@ -108,13 +108,13 @@ static int meson_gx_pwrc_vpu_power_on(struct generic_pm_domain *genpd)
+ /* Power Up Memories */
+ for (i = 0; i < 32; i += 2) {
+ regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG0,
+- 0x2 << i, 0);
++ 0x3 << i, 0);
+ udelay(5);
+ }
+
+ for (i = 0; i < 32; i += 2) {
+ regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG1,
+- 0x2 << i, 0);
++ 0x3 << i, 0);
+ udelay(5);
+ }
+