736 lines
26 KiB
Diff
736 lines
26 KiB
Diff
|
From a026e2e9f55116e81ed49f48d918fdb91e28eff6 Mon Sep 17 00:00:00 2001
|
||
|
From: Neil Armstrong <narmstrong@baylibre.com>
|
||
|
Date: Fri, 24 Sep 2021 16:19:04 +0200
|
||
|
Subject: [PATCH 71/75] drm/meson: add cursor plane using OSD2
|
||
|
|
||
|
Tested on A311D using modetest, Weston & Sway, should work on SM1 & G12A.
|
||
|
|
||
|
Cursor doesn't move with Xorg, this would need some debugging.
|
||
|
|
||
|
Non tested on GXBB, GXL & GXM SoCs.
|
||
|
|
||
|
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||
|
Change-Id: I81994f13ad507748af3b577608d6cf40433b69ff
|
||
|
---
|
||
|
drivers/gpu/drm/meson/Makefile | 2 +-
|
||
|
drivers/gpu/drm/meson/meson_crtc.c | 89 +++++++++-
|
||
|
drivers/gpu/drm/meson/meson_cursor.c | 244 +++++++++++++++++++++++++++
|
||
|
drivers/gpu/drm/meson/meson_cursor.h | 14 ++
|
||
|
drivers/gpu/drm/meson/meson_drv.c | 8 +
|
||
|
drivers/gpu/drm/meson/meson_drv.h | 17 ++
|
||
|
drivers/gpu/drm/meson/meson_plane.c | 1 -
|
||
|
drivers/gpu/drm/meson/meson_viu.c | 69 ++++++--
|
||
|
8 files changed, 422 insertions(+), 22 deletions(-)
|
||
|
create mode 100644 drivers/gpu/drm/meson/meson_cursor.c
|
||
|
create mode 100644 drivers/gpu/drm/meson/meson_cursor.h
|
||
|
|
||
|
diff --git a/drivers/gpu/drm/meson/Makefile b/drivers/gpu/drm/meson/Makefile
|
||
|
index 28a519cdf66b..39c4ffcb7b18 100644
|
||
|
--- a/drivers/gpu/drm/meson/Makefile
|
||
|
+++ b/drivers/gpu/drm/meson/Makefile
|
||
|
@@ -1,5 +1,5 @@
|
||
|
# SPDX-License-Identifier: GPL-2.0-only
|
||
|
-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_cursor.o meson_crtc.o meson_venc_cvbs.o
|
||
|
meson-drm-y += meson_viu.o meson_vpp.o meson_venc.o meson_vclk.o meson_overlay.o
|
||
|
meson-drm-y += meson_rdma.o meson_osd_afbcd.o
|
||
|
|
||
|
diff --git a/drivers/gpu/drm/meson/meson_crtc.c b/drivers/gpu/drm/meson/meson_crtc.c
|
||
|
index d70616da8ce2..c1ba3b4fe7ce 100644
|
||
|
--- a/drivers/gpu/drm/meson/meson_crtc.c
|
||
|
+++ b/drivers/gpu/drm/meson/meson_crtc.c
|
||
|
@@ -36,6 +36,7 @@ struct meson_crtc {
|
||
|
struct drm_pending_vblank_event *event;
|
||
|
struct meson_drm *priv;
|
||
|
void (*enable_osd1)(struct meson_drm *priv);
|
||
|
+ void (*enable_osd2)(struct meson_drm *priv);
|
||
|
void (*enable_vd1)(struct meson_drm *priv);
|
||
|
void (*enable_osd1_afbc)(struct meson_drm *priv);
|
||
|
void (*disable_osd1_afbc)(struct meson_drm *priv);
|
||
|
@@ -110,6 +111,20 @@ static void meson_g12a_crtc_atomic_enable(struct drm_crtc *crtc,
|
||
|
writel_relaxed(0 << 16 |
|
||
|
(crtc_state->mode.vdisplay - 1),
|
||
|
priv->io_base + _REG(VPP_OSD1_BLD_V_SCOPE));
|
||
|
+ writel_relaxed(0 << 16 |
|
||
|
+ (crtc_state->mode.hdisplay - 1),
|
||
|
+ priv->io_base + _REG(VPP_OSD2_BLD_H_SCOPE));
|
||
|
+ writel_relaxed(0 << 16 |
|
||
|
+ (crtc_state->mode.vdisplay - 1),
|
||
|
+ priv->io_base + _REG(VPP_OSD2_BLD_V_SCOPE));
|
||
|
+ writel_relaxed(crtc_state->mode.hdisplay |
|
||
|
+ crtc_state->mode.vdisplay << 16,
|
||
|
+ priv->io_base +
|
||
|
+ _REG(VIU_OSD_BLEND_BLEND0_SIZE));
|
||
|
+ writel_relaxed(crtc_state->mode.hdisplay |
|
||
|
+ crtc_state->mode.vdisplay << 16,
|
||
|
+ priv->io_base +
|
||
|
+ _REG(VIU_OSD_BLEND_BLEND1_SIZE));
|
||
|
writel_relaxed(crtc_state->mode.hdisplay << 16 |
|
||
|
crtc_state->mode.vdisplay,
|
||
|
priv->io_base + _REG(VPP_OUT_H_V_SIZE));
|
||
|
@@ -158,6 +173,9 @@ static void meson_g12a_crtc_atomic_disable(struct drm_crtc *crtc,
|
||
|
priv->viu.osd1_enabled = false;
|
||
|
priv->viu.osd1_commit = false;
|
||
|
|
||
|
+ priv->viu.osd2_enabled = false;
|
||
|
+ priv->viu.osd2_commit = false;
|
||
|
+
|
||
|
priv->viu.vd1_enabled = false;
|
||
|
priv->viu.vd1_commit = false;
|
||
|
|
||
|
@@ -183,11 +201,14 @@ static void meson_crtc_atomic_disable(struct drm_crtc *crtc,
|
||
|
priv->viu.osd1_enabled = false;
|
||
|
priv->viu.osd1_commit = false;
|
||
|
|
||
|
+ priv->viu.osd2_enabled = false;
|
||
|
+ priv->viu.osd2_commit = false;
|
||
|
+
|
||
|
priv->viu.vd1_enabled = false;
|
||
|
priv->viu.vd1_commit = false;
|
||
|
|
||
|
/* Disable VPP Postblend */
|
||
|
- writel_bits_relaxed(VPP_OSD1_POSTBLEND | VPP_VD1_POSTBLEND |
|
||
|
+ writel_bits_relaxed(VPP_OSD1_POSTBLEND | VPP_OSD2_POSTBLEND | VPP_VD1_POSTBLEND |
|
||
|
VPP_VD1_PREBLEND | VPP_POSTBLEND_ENABLE, 0,
|
||
|
priv->io_base + _REG(VPP_MISC));
|
||
|
|
||
|
@@ -223,6 +244,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.osd2_commit = true;
|
||
|
priv->viu.vd1_commit = true;
|
||
|
}
|
||
|
|
||
|
@@ -246,6 +268,12 @@ static void meson_crtc_enable_osd1(struct meson_drm *priv)
|
||
|
priv->io_base + _REG(VPP_MISC));
|
||
|
}
|
||
|
|
||
|
+static void meson_crtc_enable_osd2(struct meson_drm *priv)
|
||
|
+{
|
||
|
+ writel_bits_relaxed(VPP_OSD2_POSTBLEND, VPP_OSD2_POSTBLEND,
|
||
|
+ priv->io_base + _REG(VPP_MISC));
|
||
|
+}
|
||
|
+
|
||
|
static void meson_crtc_g12a_enable_osd1_afbc(struct meson_drm *priv)
|
||
|
{
|
||
|
writel_relaxed(priv->viu.osd1_blk2_cfg4,
|
||
|
@@ -274,14 +302,20 @@ static void meson_g12a_crtc_enable_osd1(struct meson_drm *priv)
|
||
|
writel_relaxed(priv->viu.osd_blend_din0_scope_v,
|
||
|
priv->io_base +
|
||
|
_REG(VIU_OSD_BLEND_DIN0_SCOPE_V));
|
||
|
- writel_relaxed(priv->viu.osb_blend0_size,
|
||
|
+ writel_bits_relaxed(OSD_BLEND_POSTBLD_SRC_OSD1, OSD_BLEND_POSTBLD_SRC_OSD1,
|
||
|
+ priv->io_base + _REG(OSD1_BLEND_SRC_CTRL));
|
||
|
+}
|
||
|
+
|
||
|
+static void meson_g12a_crtc_enable_osd2(struct meson_drm *priv)
|
||
|
+{
|
||
|
+ writel_relaxed(priv->viu.osd_blend_din3_scope_h,
|
||
|
priv->io_base +
|
||
|
- _REG(VIU_OSD_BLEND_BLEND0_SIZE));
|
||
|
- writel_relaxed(priv->viu.osb_blend1_size,
|
||
|
+ _REG(VIU_OSD_BLEND_DIN1_SCOPE_H));
|
||
|
+ writel_relaxed(priv->viu.osd_blend_din3_scope_v,
|
||
|
priv->io_base +
|
||
|
- _REG(VIU_OSD_BLEND_BLEND1_SIZE));
|
||
|
- writel_bits_relaxed(3 << 8, 3 << 8,
|
||
|
- priv->io_base + _REG(OSD1_BLEND_SRC_CTRL));
|
||
|
+ _REG(VIU_OSD_BLEND_DIN1_SCOPE_V));
|
||
|
+ writel_bits_relaxed(OSD_BLEND_POSTBLD_SRC_OSD2, OSD_BLEND_POSTBLD_SRC_OSD2,
|
||
|
+ priv->io_base + _REG(OSD2_BLEND_SRC_CTRL));
|
||
|
}
|
||
|
|
||
|
static void meson_crtc_enable_vd1(struct meson_drm *priv)
|
||
|
@@ -388,6 +422,43 @@ void meson_crtc_irq(struct meson_drm *priv)
|
||
|
priv->viu.osd1_commit = false;
|
||
|
}
|
||
|
|
||
|
+ if (priv->viu.osd2_enabled && priv->viu.osd2_commit) {
|
||
|
+ writel_relaxed(priv->viu.osd2_ctrl_stat,
|
||
|
+ priv->io_base + _REG(VIU_OSD2_CTRL_STAT));
|
||
|
+ writel_relaxed(priv->viu.osd2_ctrl_stat2,
|
||
|
+ priv->io_base + _REG(VIU_OSD2_CTRL_STAT2));
|
||
|
+ writel_relaxed(priv->viu.osd2_blk0_cfg[0],
|
||
|
+ priv->io_base + _REG(VIU_OSD2_BLK0_CFG_W0));
|
||
|
+ writel_relaxed(priv->viu.osd2_blk0_cfg[1],
|
||
|
+ priv->io_base + _REG(VIU_OSD2_BLK0_CFG_W1));
|
||
|
+ writel_relaxed(priv->viu.osd2_blk0_cfg[2],
|
||
|
+ priv->io_base + _REG(VIU_OSD2_BLK0_CFG_W2));
|
||
|
+ writel_relaxed(priv->viu.osd2_blk0_cfg[3],
|
||
|
+ priv->io_base + _REG(VIU_OSD2_BLK0_CFG_W3));
|
||
|
+ writel_relaxed(priv->viu.osd2_blk0_cfg[4],
|
||
|
+ priv->io_base + _REG(VIU_OSD2_BLK0_CFG_W4));
|
||
|
+
|
||
|
+ /* vsync forced to update INTERLACE_SEL_ODD in interlace mode */
|
||
|
+ meson_crtc->vsync_forced = priv->viu.osd2_interlace;
|
||
|
+
|
||
|
+ meson_canvas_config(priv->canvas, priv->canvas_id_osd2,
|
||
|
+ priv->viu.osd2_addr,
|
||
|
+ priv->viu.osd2_stride,
|
||
|
+ priv->viu.osd2_height,
|
||
|
+ MESON_CANVAS_WRAP_NONE,
|
||
|
+ MESON_CANVAS_BLKMODE_LINEAR, 0);
|
||
|
+
|
||
|
+ /* Enable OSD2 */
|
||
|
+ if (meson_crtc->enable_osd2)
|
||
|
+ meson_crtc->enable_osd2(priv);
|
||
|
+
|
||
|
+ priv->viu.osd2_commit = false;
|
||
|
+ } else if (priv->viu.osd2_enabled && priv->viu.osd2_interlace) {
|
||
|
+ u32 reg = readl_relaxed(priv->io_base + _REG(VIU_OSD2_BLK0_CFG_W0)) & ~BIT(0);
|
||
|
+ writel_relaxed(reg | meson_venci_get_field(priv) ? 1 : 0,
|
||
|
+ priv->io_base + _REG(VIU_OSD2_BLK0_CFG_W0));
|
||
|
+ }
|
||
|
+
|
||
|
/* Update the VD1 registers */
|
||
|
if (priv->viu.vd1_enabled && priv->viu.vd1_commit) {
|
||
|
|
||
|
@@ -685,7 +756,7 @@ int meson_crtc_create(struct meson_drm *priv)
|
||
|
meson_crtc->priv = priv;
|
||
|
crtc = &meson_crtc->base;
|
||
|
ret = drm_crtc_init_with_planes(priv->drm, crtc,
|
||
|
- priv->primary_plane, NULL,
|
||
|
+ priv->primary_plane, priv->cursor_plane,
|
||
|
&meson_crtc_funcs, "meson_crtc");
|
||
|
if (ret) {
|
||
|
dev_err(priv->drm->dev, "Failed to init CRTC\n");
|
||
|
@@ -694,6 +765,7 @@ int meson_crtc_create(struct meson_drm *priv)
|
||
|
|
||
|
if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) {
|
||
|
meson_crtc->enable_osd1 = meson_g12a_crtc_enable_osd1;
|
||
|
+ meson_crtc->enable_osd2 = meson_g12a_crtc_enable_osd2;
|
||
|
meson_crtc->enable_vd1 = meson_g12a_crtc_enable_vd1;
|
||
|
meson_crtc->viu_offset = MESON_G12A_VIU_OFFSET;
|
||
|
meson_crtc->enable_osd1_afbc =
|
||
|
@@ -703,6 +775,7 @@ int meson_crtc_create(struct meson_drm *priv)
|
||
|
drm_crtc_helper_add(crtc, &meson_g12a_crtc_helper_funcs);
|
||
|
} else {
|
||
|
meson_crtc->enable_osd1 = meson_crtc_enable_osd1;
|
||
|
+ meson_crtc->enable_osd2 = meson_crtc_enable_osd2;
|
||
|
meson_crtc->enable_vd1 = meson_crtc_enable_vd1;
|
||
|
if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM)) {
|
||
|
meson_crtc->enable_osd1_afbc =
|
||
|
diff --git a/drivers/gpu/drm/meson/meson_cursor.c b/drivers/gpu/drm/meson/meson_cursor.c
|
||
|
new file mode 100644
|
||
|
index 000000000000..6ba733c511e7
|
||
|
--- /dev/null
|
||
|
+++ b/drivers/gpu/drm/meson/meson_cursor.c
|
||
|
@@ -0,0 +1,244 @@
|
||
|
+// SPDX-License-Identifier: GPL-2.0-or-later
|
||
|
+/*
|
||
|
+ * Copyright (C) 2021 BayLibre, SAS
|
||
|
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
|
||
|
+ */
|
||
|
+
|
||
|
+#include <linux/bitfield.h>
|
||
|
+
|
||
|
+#include <drm/drm_atomic.h>
|
||
|
+#include <drm/drm_atomic_helper.h>
|
||
|
+#include <drm/drm_device.h>
|
||
|
+#include <drm/drm_fb_cma_helper.h>
|
||
|
+#include <drm/drm_fourcc.h>
|
||
|
+#include <drm/drm_gem_atomic_helper.h>
|
||
|
+#include <drm/drm_gem_cma_helper.h>
|
||
|
+#include <drm/drm_plane_helper.h>
|
||
|
+
|
||
|
+#include "meson_cursor.h"
|
||
|
+#include "meson_registers.h"
|
||
|
+#include "meson_viu.h"
|
||
|
+
|
||
|
+struct meson_cursor {
|
||
|
+ struct drm_plane base;
|
||
|
+ struct meson_drm *priv;
|
||
|
+};
|
||
|
+#define to_meson_cursor(x) container_of(x, struct meson_cursor, base)
|
||
|
+
|
||
|
+static int meson_cursor_atomic_check(struct drm_plane *plane,
|
||
|
+ struct drm_atomic_state *state)
|
||
|
+{
|
||
|
+ struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
|
||
|
+ plane);
|
||
|
+ struct drm_crtc_state *crtc_state;
|
||
|
+
|
||
|
+ if (!new_plane_state->crtc)
|
||
|
+ return 0;
|
||
|
+
|
||
|
+ crtc_state = drm_atomic_get_crtc_state(state,
|
||
|
+ new_plane_state->crtc);
|
||
|
+ if (IS_ERR(crtc_state))
|
||
|
+ return PTR_ERR(crtc_state);
|
||
|
+
|
||
|
+ return drm_atomic_helper_check_plane_state(new_plane_state,
|
||
|
+ crtc_state,
|
||
|
+ DRM_PLANE_HELPER_NO_SCALING,
|
||
|
+ DRM_PLANE_HELPER_NO_SCALING,
|
||
|
+ 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 void meson_cursor_atomic_update(struct drm_plane *plane,
|
||
|
+ struct drm_atomic_state *state)
|
||
|
+{
|
||
|
+ struct meson_cursor *meson_cursor = to_meson_cursor(plane);
|
||
|
+ struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
|
||
|
+ plane);
|
||
|
+ struct drm_rect dest = drm_plane_state_dest(new_state);
|
||
|
+ struct meson_drm *priv = meson_cursor->priv;
|
||
|
+ struct drm_framebuffer *fb = new_state->fb;
|
||
|
+ struct drm_gem_cma_object *gem;
|
||
|
+ unsigned long flags;
|
||
|
+ int dst_w, dst_h;
|
||
|
+
|
||
|
+ /*
|
||
|
+ * Update Coordinates
|
||
|
+ * Update Formats
|
||
|
+ * Update Buffer
|
||
|
+ * Enable Plane
|
||
|
+ */
|
||
|
+ spin_lock_irqsave(&priv->drm->event_lock, flags);
|
||
|
+
|
||
|
+ /* Enable OSD and BLK0, set max global alpha */
|
||
|
+ priv->viu.osd2_ctrl_stat = OSD_ENABLE |
|
||
|
+ (0xFF << OSD_GLOBAL_ALPHA_SHIFT) |
|
||
|
+ OSD_BLK0_ENABLE;
|
||
|
+
|
||
|
+ priv->viu.osd2_ctrl_stat2 = readl(priv->io_base +
|
||
|
+ _REG(VIU_OSD2_CTRL_STAT2));
|
||
|
+
|
||
|
+ /* Set up BLK0 to point to the right canvas */
|
||
|
+ priv->viu.osd2_blk0_cfg[0] = priv->canvas_id_osd2 << OSD_CANVAS_SEL;
|
||
|
+ priv->viu.osd2_blk0_cfg[0] |= OSD_ENDIANNESS_LE;
|
||
|
+
|
||
|
+ /* On GXBB, Use the old non-HDR RGB2YUV converter */
|
||
|
+ if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXBB))
|
||
|
+ priv->viu.osd2_blk0_cfg[0] |= OSD_OUTPUT_COLOR_RGB;
|
||
|
+
|
||
|
+ switch (fb->format->format) {
|
||
|
+ case DRM_FORMAT_XRGB8888:
|
||
|
+ case DRM_FORMAT_ARGB8888:
|
||
|
+ priv->viu.osd2_blk0_cfg[0] |= OSD_BLK_MODE_32 |
|
||
|
+ OSD_COLOR_MATRIX_32_ARGB;
|
||
|
+ break;
|
||
|
+ case DRM_FORMAT_XBGR8888:
|
||
|
+ case DRM_FORMAT_ABGR8888:
|
||
|
+ priv->viu.osd2_blk0_cfg[0] |= OSD_BLK_MODE_32 |
|
||
|
+ OSD_COLOR_MATRIX_32_ABGR;
|
||
|
+ break;
|
||
|
+ case DRM_FORMAT_RGB888:
|
||
|
+ priv->viu.osd2_blk0_cfg[0] |= OSD_BLK_MODE_24 |
|
||
|
+ OSD_COLOR_MATRIX_24_RGB;
|
||
|
+ break;
|
||
|
+ case DRM_FORMAT_RGB565:
|
||
|
+ priv->viu.osd2_blk0_cfg[0] |= OSD_BLK_MODE_16 |
|
||
|
+ OSD_COLOR_MATRIX_16_RGB565;
|
||
|
+ break;
|
||
|
+ }
|
||
|
+
|
||
|
+ switch (fb->format->format) {
|
||
|
+ case DRM_FORMAT_XRGB8888:
|
||
|
+ case DRM_FORMAT_XBGR8888:
|
||
|
+ /* For XRGB, replace the pixel's alpha by 0xFF */
|
||
|
+ priv->viu.osd2_ctrl_stat2 |= OSD_REPLACE_EN;
|
||
|
+ break;
|
||
|
+ case DRM_FORMAT_ARGB8888:
|
||
|
+ case DRM_FORMAT_ABGR8888:
|
||
|
+ /* For ARGB, use the pixel's alpha */
|
||
|
+ priv->viu.osd2_ctrl_stat2 &= ~OSD_REPLACE_EN;
|
||
|
+ break;
|
||
|
+ }
|
||
|
+
|
||
|
+ dst_w = new_state->crtc_w;
|
||
|
+ dst_h = new_state->crtc_h;
|
||
|
+
|
||
|
+ if (new_state->crtc->mode.flags & DRM_MODE_FLAG_INTERLACE)
|
||
|
+ priv->viu.osd2_interlace = true;
|
||
|
+ else
|
||
|
+ priv->viu.osd2_interlace = false;
|
||
|
+
|
||
|
+ /*
|
||
|
+ * The format of these registers is (x2 << 16 | x1),
|
||
|
+ * where x2 is exclusive.
|
||
|
+ * e.g. +30x1920 would be (1919 << 16) | 30
|
||
|
+ */
|
||
|
+ priv->viu.osd2_blk0_cfg[1] =
|
||
|
+ ((fixed16_to_int(new_state->src.x2) - 1) << 16) |
|
||
|
+ fixed16_to_int(new_state->src.x1);
|
||
|
+ priv->viu.osd2_blk0_cfg[2] =
|
||
|
+ ((fixed16_to_int(new_state->src.y2) - 1) << 16) |
|
||
|
+ fixed16_to_int(new_state->src.y1);
|
||
|
+ priv->viu.osd2_blk0_cfg[3] = ((dest.x2 - 1) << 16) | dest.x1;
|
||
|
+ priv->viu.osd2_blk0_cfg[4] = ((dest.y2 - 1) << 16) | dest.y1;
|
||
|
+
|
||
|
+ if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) {
|
||
|
+ priv->viu.osd_blend_din3_scope_h = ((dest.x2 - 1) << 16) | dest.x1;
|
||
|
+ priv->viu.osd_blend_din3_scope_v = ((dest.y2 - 1) << 16) | dest.y1;
|
||
|
+ priv->viu.osb_blend1_size = dst_h << 16 | dst_w;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* Update Canvas with buffer address */
|
||
|
+ gem = drm_fb_cma_get_gem_obj(fb, 0);
|
||
|
+
|
||
|
+ priv->viu.osd2_addr = gem->paddr;
|
||
|
+ priv->viu.osd2_stride = fb->pitches[0];
|
||
|
+ priv->viu.osd2_height = fb->height;
|
||
|
+ priv->viu.osd2_width = fb->width;
|
||
|
+
|
||
|
+ /* TOFIX: Reset OSD2 before enabling it on GXL+ SoCs ? */
|
||
|
+
|
||
|
+ priv->viu.osd2_enabled = true;
|
||
|
+
|
||
|
+ spin_unlock_irqrestore(&priv->drm->event_lock, flags);
|
||
|
+}
|
||
|
+
|
||
|
+static void meson_cursor_atomic_disable(struct drm_plane *plane,
|
||
|
+ struct drm_atomic_state *state)
|
||
|
+{
|
||
|
+ struct meson_cursor *meson_cursor = to_meson_cursor(plane);
|
||
|
+ struct meson_drm *priv = meson_cursor->priv;
|
||
|
+
|
||
|
+ /* Disable OSD2 */
|
||
|
+ if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A))
|
||
|
+ writel_bits_relaxed(OSD_BLEND_POSTBLD_SRC_OSD2, 0,
|
||
|
+ priv->io_base + _REG(OSD2_BLEND_SRC_CTRL));
|
||
|
+ else
|
||
|
+ writel_bits_relaxed(VPP_OSD2_POSTBLEND, 0,
|
||
|
+ priv->io_base + _REG(VPP_MISC));
|
||
|
+
|
||
|
+ priv->viu.osd2_enabled = false;
|
||
|
+}
|
||
|
+
|
||
|
+static const struct drm_plane_helper_funcs meson_cursor_helper_funcs = {
|
||
|
+ .atomic_check = meson_cursor_atomic_check,
|
||
|
+ .atomic_disable = meson_cursor_atomic_disable,
|
||
|
+ .atomic_update = meson_cursor_atomic_update,
|
||
|
+};
|
||
|
+
|
||
|
+static const struct drm_plane_funcs meson_cursor_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_ARGB8888,
|
||
|
+ DRM_FORMAT_ABGR8888,
|
||
|
+ DRM_FORMAT_XRGB8888,
|
||
|
+ DRM_FORMAT_XBGR8888,
|
||
|
+ DRM_FORMAT_RGB888,
|
||
|
+ DRM_FORMAT_RGB565,
|
||
|
+};
|
||
|
+
|
||
|
+static const uint64_t format_modifiers_default[] = {
|
||
|
+ DRM_FORMAT_MOD_LINEAR,
|
||
|
+ DRM_FORMAT_MOD_INVALID,
|
||
|
+};
|
||
|
+
|
||
|
+int meson_cursor_create(struct meson_drm *priv)
|
||
|
+{
|
||
|
+ struct meson_cursor *meson_cursor;
|
||
|
+ struct drm_plane *cursor;
|
||
|
+
|
||
|
+ meson_cursor = devm_kzalloc(priv->drm->dev, sizeof(*meson_cursor),
|
||
|
+ GFP_KERNEL);
|
||
|
+ if (!meson_cursor)
|
||
|
+ return -ENOMEM;
|
||
|
+
|
||
|
+ meson_cursor->priv = priv;
|
||
|
+ cursor = &meson_cursor->base;
|
||
|
+
|
||
|
+ drm_universal_plane_init(priv->drm, cursor, 0xFF,
|
||
|
+ &meson_cursor_funcs,
|
||
|
+ supported_drm_formats,
|
||
|
+ ARRAY_SIZE(supported_drm_formats),
|
||
|
+ format_modifiers_default,
|
||
|
+ DRM_PLANE_TYPE_CURSOR, "meson_cursor_plane");
|
||
|
+
|
||
|
+ drm_plane_helper_add(cursor, &meson_cursor_helper_funcs);
|
||
|
+
|
||
|
+ /* For now, OSD Cursor is always on top of the primary plane */
|
||
|
+ drm_plane_create_zpos_immutable_property(cursor, 2);
|
||
|
+
|
||
|
+ priv->cursor_plane = cursor;
|
||
|
+
|
||
|
+ return 0;
|
||
|
+}
|
||
|
diff --git a/drivers/gpu/drm/meson/meson_cursor.h b/drivers/gpu/drm/meson/meson_cursor.h
|
||
|
new file mode 100644
|
||
|
index 000000000000..28b5de49a646
|
||
|
--- /dev/null
|
||
|
+++ b/drivers/gpu/drm/meson/meson_cursor.h
|
||
|
@@ -0,0 +1,14 @@
|
||
|
+/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||
|
+/*
|
||
|
+ * Copyright (C) 2021 BayLibre, SAS
|
||
|
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
|
||
|
+ */
|
||
|
+
|
||
|
+#ifndef __MESON_CURSOR_H
|
||
|
+#define __MESON_CURSOR_H
|
||
|
+
|
||
|
+#include "meson_drv.h"
|
||
|
+
|
||
|
+int meson_cursor_create(struct meson_drm *priv);
|
||
|
+
|
||
|
+#endif /* __MESON_CURSOR_H */
|
||
|
diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c
|
||
|
index 447a000178a1..9d932b4c7a4b 100644
|
||
|
--- a/drivers/gpu/drm/meson/meson_drv.c
|
||
|
+++ b/drivers/gpu/drm/meson/meson_drv.c
|
||
|
@@ -29,6 +29,7 @@
|
||
|
#include "meson_drv.h"
|
||
|
#include "meson_overlay.h"
|
||
|
#include "meson_plane.h"
|
||
|
+#include "meson_cursor.h"
|
||
|
#include "meson_osd_afbcd.h"
|
||
|
#include "meson_registers.h"
|
||
|
#include "meson_venc_cvbs.h"
|
||
|
@@ -242,6 +243,9 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
|
||
|
}
|
||
|
|
||
|
ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_osd1);
|
||
|
+ if (ret)
|
||
|
+ goto free_drm;
|
||
|
+ ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_osd2);
|
||
|
if (ret)
|
||
|
goto free_drm;
|
||
|
ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_vd1_0);
|
||
|
@@ -319,6 +323,10 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
+ ret = meson_cursor_create(priv);
|
||
|
+ if (ret)
|
||
|
+ goto free_drm;
|
||
|
+
|
||
|
ret = meson_plane_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 177dac3ca3be..ebe8b050c704 100644
|
||
|
--- a/drivers/gpu/drm/meson/meson_drv.h
|
||
|
+++ b/drivers/gpu/drm/meson/meson_drv.h
|
||
|
@@ -43,12 +43,14 @@ struct meson_drm {
|
||
|
|
||
|
struct meson_canvas *canvas;
|
||
|
u8 canvas_id_osd1;
|
||
|
+ u8 canvas_id_osd2;
|
||
|
u8 canvas_id_vd1_0;
|
||
|
u8 canvas_id_vd1_1;
|
||
|
u8 canvas_id_vd1_2;
|
||
|
|
||
|
struct drm_device *drm;
|
||
|
struct drm_crtc *crtc;
|
||
|
+ struct drm_plane *cursor_plane;
|
||
|
struct drm_plane *primary_plane;
|
||
|
struct drm_plane *overlay_plane;
|
||
|
|
||
|
@@ -82,6 +84,21 @@ struct meson_drm {
|
||
|
uint32_t osd_blend_din0_scope_h;
|
||
|
uint32_t osd_blend_din0_scope_v;
|
||
|
uint32_t osb_blend0_size;
|
||
|
+
|
||
|
+ bool osd2_enabled;
|
||
|
+ bool osd2_interlace;
|
||
|
+ bool osd2_commit;
|
||
|
+ uint32_t osd2_ctrl_stat;
|
||
|
+ uint32_t osd2_ctrl_stat2;
|
||
|
+ uint32_t osd2_blk0_cfg[5];
|
||
|
+ uint32_t osd2_blk1_cfg4;
|
||
|
+ uint32_t osd2_blk2_cfg4;
|
||
|
+ uint32_t osd2_addr;
|
||
|
+ uint32_t osd2_stride;
|
||
|
+ uint32_t osd2_height;
|
||
|
+ uint32_t osd2_width;
|
||
|
+ uint32_t osd_blend_din3_scope_h;
|
||
|
+ uint32_t osd_blend_din3_scope_v;
|
||
|
uint32_t osb_blend1_size;
|
||
|
|
||
|
bool vd1_enabled;
|
||
|
diff --git a/drivers/gpu/drm/meson/meson_plane.c b/drivers/gpu/drm/meson/meson_plane.c
|
||
|
index 8640a8a8a469..8163d6ecfda6 100644
|
||
|
--- a/drivers/gpu/drm/meson/meson_plane.c
|
||
|
+++ b/drivers/gpu/drm/meson/meson_plane.c
|
||
|
@@ -360,7 +360,6 @@ static void meson_plane_atomic_update(struct drm_plane *plane,
|
||
|
priv->viu.osd_blend_din0_scope_h = ((dest.x2 - 1) << 16) | dest.x1;
|
||
|
priv->viu.osd_blend_din0_scope_v = ((dest.y2 - 1) << 16) | dest.y1;
|
||
|
priv->viu.osb_blend0_size = dst_h << 16 | dst_w;
|
||
|
- priv->viu.osb_blend1_size = dst_h << 16 | dst_w;
|
||
|
}
|
||
|
|
||
|
/* Update Canvas with buffer address */
|
||
|
diff --git a/drivers/gpu/drm/meson/meson_viu.c b/drivers/gpu/drm/meson/meson_viu.c
|
||
|
index 1287444b1bc8..dba2ca484b26 100644
|
||
|
--- a/drivers/gpu/drm/meson/meson_viu.c
|
||
|
+++ b/drivers/gpu/drm/meson/meson_viu.c
|
||
|
@@ -78,32 +78,52 @@ static int eotf_bypass_coeff[EOTF_COEFF_SIZE] = {
|
||
|
EOTF_COEFF_RIGHTSHIFT /* right shift */
|
||
|
};
|
||
|
|
||
|
-static void meson_viu_set_g12a_osd1_matrix(struct meson_drm *priv,
|
||
|
- int *m, bool csc_on)
|
||
|
+static void meson_viu_set_g12a_osd_matrix(struct meson_drm *priv,
|
||
|
+ int *m, bool csc_on)
|
||
|
{
|
||
|
/* VPP WRAP OSD1 matrix */
|
||
|
writel(((m[0] & 0xfff) << 16) | (m[1] & 0xfff),
|
||
|
priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_PRE_OFFSET0_1));
|
||
|
+ writel(((m[0] & 0xfff) << 16) | (m[1] & 0xfff),
|
||
|
+ priv->io_base + _REG(VPP_WRAP_OSD2_MATRIX_PRE_OFFSET0_1));
|
||
|
writel(m[2] & 0xfff,
|
||
|
priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_PRE_OFFSET2));
|
||
|
+ writel(m[2] & 0xfff,
|
||
|
+ priv->io_base + _REG(VPP_WRAP_OSD2_MATRIX_PRE_OFFSET2));
|
||
|
writel(((m[3] & 0x1fff) << 16) | (m[4] & 0x1fff),
|
||
|
priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_COEF00_01));
|
||
|
+ writel(((m[3] & 0x1fff) << 16) | (m[4] & 0x1fff),
|
||
|
+ priv->io_base + _REG(VPP_WRAP_OSD2_MATRIX_COEF00_01));
|
||
|
writel(((m[5] & 0x1fff) << 16) | (m[6] & 0x1fff),
|
||
|
priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_COEF02_10));
|
||
|
+ writel(((m[5] & 0x1fff) << 16) | (m[6] & 0x1fff),
|
||
|
+ priv->io_base + _REG(VPP_WRAP_OSD2_MATRIX_COEF02_10));
|
||
|
writel(((m[7] & 0x1fff) << 16) | (m[8] & 0x1fff),
|
||
|
priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_COEF11_12));
|
||
|
+ writel(((m[7] & 0x1fff) << 16) | (m[8] & 0x1fff),
|
||
|
+ priv->io_base + _REG(VPP_WRAP_OSD2_MATRIX_COEF11_12));
|
||
|
writel(((m[9] & 0x1fff) << 16) | (m[10] & 0x1fff),
|
||
|
priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_COEF20_21));
|
||
|
+ writel(((m[9] & 0x1fff) << 16) | (m[10] & 0x1fff),
|
||
|
+ priv->io_base + _REG(VPP_WRAP_OSD2_MATRIX_COEF20_21));
|
||
|
writel((m[11] & 0x1fff) << 16,
|
||
|
priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_COEF22));
|
||
|
+ writel((m[11] & 0x1fff) << 16,
|
||
|
+ priv->io_base + _REG(VPP_WRAP_OSD2_MATRIX_COEF22));
|
||
|
|
||
|
writel(((m[18] & 0xfff) << 16) | (m[19] & 0xfff),
|
||
|
priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_OFFSET0_1));
|
||
|
+ writel(((m[18] & 0xfff) << 16) | (m[19] & 0xfff),
|
||
|
+ priv->io_base + _REG(VPP_WRAP_OSD2_MATRIX_OFFSET0_1));
|
||
|
writel(m[20] & 0xfff,
|
||
|
priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_OFFSET2));
|
||
|
+ writel(m[20] & 0xfff,
|
||
|
+ priv->io_base + _REG(VPP_WRAP_OSD2_MATRIX_OFFSET2));
|
||
|
|
||
|
writel_bits_relaxed(BIT(0), csc_on ? BIT(0) : 0,
|
||
|
priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_EN_CTRL));
|
||
|
+ writel_bits_relaxed(BIT(0), csc_on ? BIT(0) : 0,
|
||
|
+ priv->io_base + _REG(VPP_WRAP_OSD2_MATRIX_EN_CTRL));
|
||
|
}
|
||
|
|
||
|
static void meson_viu_set_osd_matrix(struct meson_drm *priv,
|
||
|
@@ -114,21 +134,36 @@ static void meson_viu_set_osd_matrix(struct meson_drm *priv,
|
||
|
/* osd matrix, VIU_MATRIX_0 */
|
||
|
writel(((m[0] & 0xfff) << 16) | (m[1] & 0xfff),
|
||
|
priv->io_base + _REG(VIU_OSD1_MATRIX_PRE_OFFSET0_1));
|
||
|
+ writel(((m[0] & 0xfff) << 16) | (m[1] & 0xfff),
|
||
|
+ priv->io_base + _REG(VIU_OSD2_MATRIX_PRE_OFFSET0_1));
|
||
|
writel(m[2] & 0xfff,
|
||
|
priv->io_base + _REG(VIU_OSD1_MATRIX_PRE_OFFSET2));
|
||
|
+ writel(m[2] & 0xfff,
|
||
|
+ priv->io_base + _REG(VIU_OSD2_MATRIX_PRE_OFFSET2));
|
||
|
writel(((m[3] & 0x1fff) << 16) | (m[4] & 0x1fff),
|
||
|
priv->io_base + _REG(VIU_OSD1_MATRIX_COEF00_01));
|
||
|
+ writel(((m[3] & 0x1fff) << 16) | (m[4] & 0x1fff),
|
||
|
+ priv->io_base + _REG(VIU_OSD2_MATRIX_COEF00_01));
|
||
|
writel(((m[5] & 0x1fff) << 16) | (m[6] & 0x1fff),
|
||
|
priv->io_base + _REG(VIU_OSD1_MATRIX_COEF02_10));
|
||
|
+ writel(((m[5] & 0x1fff) << 16) | (m[6] & 0x1fff),
|
||
|
+ priv->io_base + _REG(VIU_OSD2_MATRIX_COEF02_10));
|
||
|
writel(((m[7] & 0x1fff) << 16) | (m[8] & 0x1fff),
|
||
|
priv->io_base + _REG(VIU_OSD1_MATRIX_COEF11_12));
|
||
|
+ writel(((m[7] & 0x1fff) << 16) | (m[8] & 0x1fff),
|
||
|
+ priv->io_base + _REG(VIU_OSD2_MATRIX_COEF11_12));
|
||
|
writel(((m[9] & 0x1fff) << 16) | (m[10] & 0x1fff),
|
||
|
priv->io_base + _REG(VIU_OSD1_MATRIX_COEF20_21));
|
||
|
+ writel(((m[9] & 0x1fff) << 16) | (m[10] & 0x1fff),
|
||
|
+ priv->io_base + _REG(VIU_OSD2_MATRIX_COEF20_21));
|
||
|
|
||
|
if (m[21]) {
|
||
|
writel(((m[11] & 0x1fff) << 16) | (m[12] & 0x1fff),
|
||
|
priv->io_base +
|
||
|
_REG(VIU_OSD1_MATRIX_COEF22_30));
|
||
|
+ writel(((m[11] & 0x1fff) << 16),
|
||
|
+ priv->io_base +
|
||
|
+ _REG(VIU_OSD2_MATRIX_COEF22));
|
||
|
writel(((m[13] & 0x1fff) << 16) | (m[14] & 0x1fff),
|
||
|
priv->io_base +
|
||
|
_REG(VIU_OSD1_MATRIX_COEF31_32));
|
||
|
@@ -137,14 +172,21 @@ static void meson_viu_set_osd_matrix(struct meson_drm *priv,
|
||
|
_REG(VIU_OSD1_MATRIX_COEF40_41));
|
||
|
writel(m[17] & 0x1fff, priv->io_base +
|
||
|
_REG(VIU_OSD1_MATRIX_COLMOD_COEF42));
|
||
|
- } else
|
||
|
+ } else {
|
||
|
writel((m[11] & 0x1fff) << 16, priv->io_base +
|
||
|
_REG(VIU_OSD1_MATRIX_COEF22_30));
|
||
|
+ writel((m[11] & 0x1fff) << 16, priv->io_base +
|
||
|
+ _REG(VIU_OSD2_MATRIX_COEF22));
|
||
|
+ }
|
||
|
|
||
|
writel(((m[18] & 0xfff) << 16) | (m[19] & 0xfff),
|
||
|
priv->io_base + _REG(VIU_OSD1_MATRIX_OFFSET0_1));
|
||
|
+ writel(((m[18] & 0xfff) << 16) | (m[19] & 0xfff),
|
||
|
+ priv->io_base + _REG(VIU_OSD2_MATRIX_OFFSET0_1));
|
||
|
writel(m[20] & 0xfff,
|
||
|
priv->io_base + _REG(VIU_OSD1_MATRIX_OFFSET2));
|
||
|
+ writel(m[20] & 0xfff,
|
||
|
+ priv->io_base + _REG(VIU_OSD2_MATRIX_OFFSET2));
|
||
|
|
||
|
writel_bits_relaxed(3 << 30, m[21] << 30,
|
||
|
priv->io_base + _REG(VIU_OSD1_MATRIX_COLMOD_COEF42));
|
||
|
@@ -154,8 +196,12 @@ static void meson_viu_set_osd_matrix(struct meson_drm *priv,
|
||
|
/* 23 reserved for clipping control */
|
||
|
writel_bits_relaxed(BIT(0), csc_on ? BIT(0) : 0,
|
||
|
priv->io_base + _REG(VIU_OSD1_MATRIX_CTRL));
|
||
|
+ writel_bits_relaxed(BIT(0), csc_on ? BIT(0) : 0,
|
||
|
+ priv->io_base + _REG(VIU_OSD2_MATRIX_CTRL));
|
||
|
writel_bits_relaxed(BIT(1), 0,
|
||
|
priv->io_base + _REG(VIU_OSD1_MATRIX_CTRL));
|
||
|
+ writel_bits_relaxed(BIT(1), 0,
|
||
|
+ priv->io_base + _REG(VIU_OSD2_MATRIX_CTRL));
|
||
|
} else if (m_select == VIU_MATRIX_OSD_EOTF) {
|
||
|
int i;
|
||
|
|
||
|
@@ -428,7 +474,7 @@ void meson_viu_init(struct meson_drm *priv)
|
||
|
#if 0
|
||
|
/* FIXME: */
|
||
|
else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A))
|
||
|
- meson_viu_set_g12a_osd1_matrix(priv, RGB709_to_YUV709l_coeff,
|
||
|
+ meson_viu_set_g12a_osd_matrix(priv, RGB709_to_YUV709l_coeff,
|
||
|
true);
|
||
|
#endif
|
||
|
|
||
|
@@ -467,14 +513,13 @@ void meson_viu_init(struct meson_drm *priv)
|
||
|
priv->io_base + _REG(VD2_IF0_LUMA_FIFO_SIZE));
|
||
|
|
||
|
if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) {
|
||
|
- writel_relaxed(VIU_OSD_BLEND_REORDER(0, 1) |
|
||
|
- VIU_OSD_BLEND_REORDER(1, 0) |
|
||
|
- VIU_OSD_BLEND_REORDER(2, 0) |
|
||
|
- VIU_OSD_BLEND_REORDER(3, 0) |
|
||
|
- VIU_OSD_BLEND_DIN_EN(1) |
|
||
|
- VIU_OSD_BLEND1_DIN3_BYPASS_TO_DOUT1 |
|
||
|
- VIU_OSD_BLEND1_DOUT_BYPASS_TO_BLEND2 |
|
||
|
- VIU_OSD_BLEND_DIN0_BYPASS_TO_DOUT0 |
|
||
|
+ /* setup bypass to have OSD1->DOUT0 + OSD2->DOUT1 */
|
||
|
+ writel_relaxed(VIU_OSD_BLEND_REORDER(0, 1) | /* OSD1 to DIN0 */
|
||
|
+ VIU_OSD_BLEND_REORDER(1, 4) |
|
||
|
+ VIU_OSD_BLEND_REORDER(2, 4) |
|
||
|
+ VIU_OSD_BLEND_REORDER(3, 2) | /* OSD2 to DIN3 */
|
||
|
+ VIU_OSD_BLEND_DIN_EN(9) | /* Enable DIN0 & DIN3 */
|
||
|
+ VIU_OSD_BLEND_DIN0_BYPASS_TO_DOUT0 | /* DIN0 to DOUT0 */
|
||
|
VIU_OSD_BLEND_BLEN2_PREMULT_EN(1) |
|
||
|
VIU_OSD_BLEND_HOLD_LINES(4),
|
||
|
priv->io_base + _REG(VIU_OSD_BLEND_CTRL));
|
||
|
--
|
||
|
2.25.1
|
||
|
|