Commit f9a23481 authored by Neil Armstrong's avatar Neil Armstrong

drm/meson: Support Overlay plane for video rendering

The Amlogic Meson GX SoCs support an Overlay plane behind the primary
plane for video rendering.

This Overlay plane support various YUV layouts :
- YUYV
- NV12 / NV21
- YUV444 / 422 / 420 / 411 / 410

The scaler supports a wide range of scaling ratios, but for simplicity,
plane atomic check limits the scaling from x5 to /5 in vertical and
horizontal scaling.

The z-order is fixed and always behind the primary plane and cannot be changed.

The scaling parameter algorithm was taken from the Amlogic vendor kernel
code and rewritten to match the atomic universal plane requirements.

The video rendering using this overlay plane support has been tested using
the new Kodi DRM-KMS Prime rendering path along the in-review V4L2 Mem2Mem
Hardware Video Decoder up to 3840x2160 NV12 frames on various display modes.
Signed-off-by: default avatarNeil Armstrong <narmstrong@baylibre.com>
Acked-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
Tested-by: default avatarMaxime Jourdan <mjourdan@baylibre.com>
Link: https://patchwork.freedesktop.org/patch/msgid/1541497202-20570-2-git-send-email-narmstrong@baylibre.com
parent 9ef60bd6
meson-drm-y := meson_drv.o meson_plane.o meson_crtc.o meson_venc_cvbs.o 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_canvas.o meson-drm-y += meson_viu.o meson_vpp.o meson_venc.o meson_vclk.o meson_canvas.o meson_overlay.o
obj-$(CONFIG_DRM_MESON) += meson-drm.o obj-$(CONFIG_DRM_MESON) += meson-drm.o
obj-$(CONFIG_DRM_MESON_DW_HDMI) += meson_dw_hdmi.o obj-$(CONFIG_DRM_MESON_DW_HDMI) += meson_dw_hdmi.o
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
#define CANVAS_WIDTH_HBIT 0 #define CANVAS_WIDTH_HBIT 0
#define CANVAS_HEIGHT_BIT 9 #define CANVAS_HEIGHT_BIT 9
#define CANVAS_BLKMODE_BIT 24 #define CANVAS_BLKMODE_BIT 24
#define CANVAS_ENDIAN_BIT 26
#define DMC_CAV_LUT_ADDR 0x50 /* 0x14 offset in data sheet */ #define DMC_CAV_LUT_ADDR 0x50 /* 0x14 offset in data sheet */
#define CANVAS_LUT_WR_EN (0x2 << 8) #define CANVAS_LUT_WR_EN (0x2 << 8)
#define CANVAS_LUT_RD_EN (0x1 << 8) #define CANVAS_LUT_RD_EN (0x1 << 8)
...@@ -47,7 +48,8 @@ void meson_canvas_setup(struct meson_drm *priv, ...@@ -47,7 +48,8 @@ void meson_canvas_setup(struct meson_drm *priv,
uint32_t canvas_index, uint32_t addr, uint32_t canvas_index, uint32_t addr,
uint32_t stride, uint32_t height, uint32_t stride, uint32_t height,
unsigned int wrap, unsigned int wrap,
unsigned int blkmode) unsigned int blkmode,
unsigned int endian)
{ {
unsigned int val; unsigned int val;
...@@ -60,7 +62,8 @@ void meson_canvas_setup(struct meson_drm *priv, ...@@ -60,7 +62,8 @@ void meson_canvas_setup(struct meson_drm *priv,
CANVAS_WIDTH_HBIT) | CANVAS_WIDTH_HBIT) |
(height << CANVAS_HEIGHT_BIT) | (height << CANVAS_HEIGHT_BIT) |
(wrap << 22) | (wrap << 22) |
(blkmode << CANVAS_BLKMODE_BIT)); (blkmode << CANVAS_BLKMODE_BIT) |
(endian << CANVAS_ENDIAN_BIT));
regmap_write(priv->dmc, DMC_CAV_LUT_ADDR, regmap_write(priv->dmc, DMC_CAV_LUT_ADDR,
CANVAS_LUT_WR_EN | canvas_index); CANVAS_LUT_WR_EN | canvas_index);
......
...@@ -23,6 +23,9 @@ ...@@ -23,6 +23,9 @@
#define __MESON_CANVAS_H #define __MESON_CANVAS_H
#define MESON_CANVAS_ID_OSD1 0x4e #define MESON_CANVAS_ID_OSD1 0x4e
#define MESON_CANVAS_ID_VD1_0 0x60
#define MESON_CANVAS_ID_VD1_1 0x61
#define MESON_CANVAS_ID_VD1_2 0x62
/* Canvas configuration. */ /* Canvas configuration. */
#define MESON_CANVAS_WRAP_NONE 0x00 #define MESON_CANVAS_WRAP_NONE 0x00
...@@ -33,10 +36,16 @@ ...@@ -33,10 +36,16 @@
#define MESON_CANVAS_BLKMODE_32x32 0x01 #define MESON_CANVAS_BLKMODE_32x32 0x01
#define MESON_CANVAS_BLKMODE_64x64 0x02 #define MESON_CANVAS_BLKMODE_64x64 0x02
#define MESON_CANVAS_ENDIAN_SWAP16 0x1
#define MESON_CANVAS_ENDIAN_SWAP32 0x3
#define MESON_CANVAS_ENDIAN_SWAP64 0x7
#define MESON_CANVAS_ENDIAN_SWAP128 0xf
void meson_canvas_setup(struct meson_drm *priv, void meson_canvas_setup(struct meson_drm *priv,
uint32_t canvas_index, uint32_t addr, uint32_t canvas_index, uint32_t addr,
uint32_t stride, uint32_t height, uint32_t stride, uint32_t height,
unsigned int wrap, unsigned int wrap,
unsigned int blkmode); unsigned int blkmode,
unsigned int endian);
#endif /* __MESON_CANVAS_H */ #endif /* __MESON_CANVAS_H */
This diff is collapsed.
...@@ -41,6 +41,7 @@ ...@@ -41,6 +41,7 @@
#include "meson_drv.h" #include "meson_drv.h"
#include "meson_plane.h" #include "meson_plane.h"
#include "meson_overlay.h"
#include "meson_crtc.h" #include "meson_crtc.h"
#include "meson_venc_cvbs.h" #include "meson_venc_cvbs.h"
...@@ -213,6 +214,24 @@ static int meson_drv_bind_master(struct device *dev, bool has_components) ...@@ -213,6 +214,24 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_osd1); ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_osd1);
if (ret) if (ret)
goto free_drm; goto free_drm;
ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_vd1_0);
if (ret) {
meson_canvas_free(priv->canvas, priv->canvas_id_osd1);
goto free_drm;
}
ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_vd1_1);
if (ret) {
meson_canvas_free(priv->canvas, priv->canvas_id_osd1);
meson_canvas_free(priv->canvas, priv->canvas_id_vd1_0);
goto free_drm;
}
ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_vd1_2);
if (ret) {
meson_canvas_free(priv->canvas, priv->canvas_id_osd1);
meson_canvas_free(priv->canvas, priv->canvas_id_vd1_0);
meson_canvas_free(priv->canvas, priv->canvas_id_vd1_1);
goto free_drm;
}
} else { } else {
priv->canvas = NULL; priv->canvas = NULL;
...@@ -273,6 +292,10 @@ static int meson_drv_bind_master(struct device *dev, bool has_components) ...@@ -273,6 +292,10 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
if (ret) if (ret)
goto free_drm; goto free_drm;
ret = meson_overlay_create(priv);
if (ret)
goto free_drm;
ret = meson_crtc_create(priv); ret = meson_crtc_create(priv);
if (ret) if (ret)
goto free_drm; goto free_drm;
...@@ -311,8 +334,12 @@ static void meson_drv_unbind(struct device *dev) ...@@ -311,8 +334,12 @@ static void meson_drv_unbind(struct device *dev)
struct drm_device *drm = dev_get_drvdata(dev); struct drm_device *drm = dev_get_drvdata(dev);
struct meson_drm *priv = drm->dev_private; struct meson_drm *priv = drm->dev_private;
if (priv->canvas) if (priv->canvas) {
meson_canvas_free(priv->canvas, priv->canvas_id_osd1); meson_canvas_free(priv->canvas, priv->canvas_id_osd1);
meson_canvas_free(priv->canvas, priv->canvas_id_vd1_0);
meson_canvas_free(priv->canvas, priv->canvas_id_vd1_1);
meson_canvas_free(priv->canvas, priv->canvas_id_vd1_2);
}
drm_dev_unregister(drm); drm_dev_unregister(drm);
drm_kms_helper_poll_fini(drm); drm_kms_helper_poll_fini(drm);
......
...@@ -34,10 +34,14 @@ struct meson_drm { ...@@ -34,10 +34,14 @@ struct meson_drm {
struct meson_canvas *canvas; struct meson_canvas *canvas;
u8 canvas_id_osd1; u8 canvas_id_osd1;
u8 canvas_id_vd1_0;
u8 canvas_id_vd1_1;
u8 canvas_id_vd1_2;
struct drm_device *drm; struct drm_device *drm;
struct drm_crtc *crtc; struct drm_crtc *crtc;
struct drm_plane *primary_plane; struct drm_plane *primary_plane;
struct drm_plane *overlay_plane;
/* Components Data */ /* Components Data */
struct { struct {
...@@ -49,6 +53,54 @@ struct meson_drm { ...@@ -49,6 +53,54 @@ struct meson_drm {
uint32_t osd1_addr; uint32_t osd1_addr;
uint32_t osd1_stride; uint32_t osd1_stride;
uint32_t osd1_height; 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; } viu;
struct { struct {
......
This diff is collapsed.
/* 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 */
...@@ -286,6 +286,7 @@ ...@@ -286,6 +286,7 @@
#define VIU_OSD1_MATRIX_COEF22_30 0x1a9d #define VIU_OSD1_MATRIX_COEF22_30 0x1a9d
#define VIU_OSD1_MATRIX_COEF31_32 0x1a9e #define VIU_OSD1_MATRIX_COEF31_32 0x1a9e
#define VIU_OSD1_MATRIX_COEF40_41 0x1a9f #define VIU_OSD1_MATRIX_COEF40_41 0x1a9f
#define VD1_IF0_GEN_REG3 0x1aa7
#define VIU_OSD1_EOTF_CTL 0x1ad4 #define VIU_OSD1_EOTF_CTL 0x1ad4
#define VIU_OSD1_EOTF_COEF00_01 0x1ad5 #define VIU_OSD1_EOTF_COEF00_01 0x1ad5
#define VIU_OSD1_EOTF_COEF02_10 0x1ad6 #define VIU_OSD1_EOTF_COEF02_10 0x1ad6
...@@ -297,6 +298,7 @@ ...@@ -297,6 +298,7 @@
#define VIU_OSD1_OETF_CTL 0x1adc #define VIU_OSD1_OETF_CTL 0x1adc
#define VIU_OSD1_OETF_LUT_ADDR_PORT 0x1add #define VIU_OSD1_OETF_LUT_ADDR_PORT 0x1add
#define VIU_OSD1_OETF_LUT_DATA_PORT 0x1ade #define VIU_OSD1_OETF_LUT_DATA_PORT 0x1ade
#define AFBC_ENABLE 0x1ae0
/* vpp */ /* vpp */
#define VPP_DUMMY_DATA 0x1d00 #define VPP_DUMMY_DATA 0x1d00
...@@ -349,6 +351,7 @@ ...@@ -349,6 +351,7 @@
#define VPP_VD2_PREBLEND BIT(15) #define VPP_VD2_PREBLEND BIT(15)
#define VPP_OSD1_PREBLEND BIT(16) #define VPP_OSD1_PREBLEND BIT(16)
#define VPP_OSD2_PREBLEND BIT(17) #define VPP_OSD2_PREBLEND BIT(17)
#define VPP_COLOR_MNG_ENABLE BIT(28)
#define VPP_OFIFO_SIZE 0x1d27 #define VPP_OFIFO_SIZE 0x1d27
#define VPP_FIFO_STATUS 0x1d28 #define VPP_FIFO_STATUS 0x1d28
#define VPP_SMOKE_CTRL 0x1d29 #define VPP_SMOKE_CTRL 0x1d29
......
...@@ -329,6 +329,21 @@ void meson_viu_init(struct meson_drm *priv) ...@@ -329,6 +329,21 @@ void meson_viu_init(struct meson_drm *priv)
0xff << OSD_REPLACE_SHIFT, 0xff << OSD_REPLACE_SHIFT,
priv->io_base + _REG(VIU_OSD2_CTRL_STAT2)); 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_enabled = false;
priv->viu.osd1_commit = false; priv->viu.osd1_commit = false;
priv->viu.osd1_interlace = false; priv->viu.osd1_interlace = false;
......
...@@ -122,6 +122,31 @@ static void meson_vpp_write_scaling_filter_coefs(struct meson_drm *priv, ...@@ -122,6 +122,31 @@ static void meson_vpp_write_scaling_filter_coefs(struct meson_drm *priv,
priv->io_base + _REG(VPP_OSD_SCALE_COEF)); 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) void meson_vpp_init(struct meson_drm *priv)
{ {
/* set dummy data default YUV black */ /* set dummy data default YUV black */
...@@ -150,17 +175,34 @@ void meson_vpp_init(struct meson_drm *priv) ...@@ -150,17 +175,34 @@ void meson_vpp_init(struct meson_drm *priv)
/* Force all planes off */ /* Force all planes off */
writel_bits_relaxed(VPP_OSD1_POSTBLEND | VPP_OSD2_POSTBLEND | 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)); 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 */ /* Disable Scalers */
writel_relaxed(0, priv->io_base + _REG(VPP_OSD_SC_CTRL0)); 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_VSC_CTRL0));
writel_relaxed(0, priv->io_base + _REG(VPP_OSD_HSC_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. */ /* Write in the proper filter coefficients. */
meson_vpp_write_scaling_filter_coefs(priv, meson_vpp_write_scaling_filter_coefs(priv,
vpp_filter_coefs_4point_bspline, false); vpp_filter_coefs_4point_bspline, false);
meson_vpp_write_scaling_filter_coefs(priv, meson_vpp_write_scaling_filter_coefs(priv,
vpp_filter_coefs_4point_bspline, true); 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);
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment