mirror of
https://github.com/libretro/Lakka-LibreELEC.git
synced 2024-12-15 19:09:46 +00:00
575 lines
20 KiB
Diff
575 lines
20 KiB
Diff
From 98b6e69f14c6c670a4156d92860500f5adfb530f Mon Sep 17 00:00:00 2001
|
|
From: Jernej Skrabec <jernej.skrabec@gmail.com>
|
|
Date: Sun, 8 Oct 2023 13:01:01 +0200
|
|
Subject: [PATCH] drm/sun4i: de3: Implement AFBC support
|
|
|
|
Buffers, compressed with AFBC, are generally more efficient for memory
|
|
transfers. Add support for them.
|
|
|
|
Currently it's implemented only for VI layers, but vendor code and
|
|
documentation suggest UI layers can have them too. However, I haven't
|
|
observed any SoC with such feature.
|
|
|
|
Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
|
|
---
|
|
drivers/gpu/drm/sun4i/Makefile | 2 +-
|
|
drivers/gpu/drm/sun4i/sun50i_afbc.c | 240 +++++++++++++++++++++++++
|
|
drivers/gpu/drm/sun4i/sun50i_afbc.h | 87 +++++++++
|
|
drivers/gpu/drm/sun4i/sun8i_vi_layer.c | 84 +++++++--
|
|
4 files changed, 400 insertions(+), 13 deletions(-)
|
|
create mode 100644 drivers/gpu/drm/sun4i/sun50i_afbc.c
|
|
create mode 100644 drivers/gpu/drm/sun4i/sun50i_afbc.h
|
|
|
|
diff --git a/drivers/gpu/drm/sun4i/Makefile b/drivers/gpu/drm/sun4i/Makefile
|
|
index 3f516329f51e..78290f1660fb 100644
|
|
--- a/drivers/gpu/drm/sun4i/Makefile
|
|
+++ b/drivers/gpu/drm/sun4i/Makefile
|
|
@@ -17,7 +17,7 @@ sun8i-drm-hdmi-y += sun8i_hdmi_phy_clk.o
|
|
sun8i-mixer-y += sun8i_mixer.o sun8i_ui_layer.o \
|
|
sun8i_vi_layer.o sun8i_ui_scaler.o \
|
|
sun8i_vi_scaler.o sun8i_csc.o \
|
|
- sun50i_fmt.o
|
|
+ sun50i_fmt.o sun50i_afbc.o
|
|
|
|
sun4i-tcon-y += sun4i_crtc.o
|
|
sun4i-tcon-y += sun4i_tcon_dclk.o
|
|
diff --git a/drivers/gpu/drm/sun4i/sun50i_afbc.c b/drivers/gpu/drm/sun4i/sun50i_afbc.c
|
|
new file mode 100644
|
|
index 000000000000..27a771608eef
|
|
--- /dev/null
|
|
+++ b/drivers/gpu/drm/sun4i/sun50i_afbc.c
|
|
@@ -0,0 +1,240 @@
|
|
+// SPDX-License-Identifier: GPL-2.0-or-later
|
|
+/*
|
|
+ * Copyright (C) Jernej Skrabec <jernej.skrabec@gmail.com>
|
|
+ */
|
|
+
|
|
+#include <drm/drm_blend.h>
|
|
+#include <drm/drm_fb_dma_helper.h>
|
|
+#include <drm/drm_framebuffer.h>
|
|
+#include <drm/drm_gem_dma_helper.h>
|
|
+#include <drm/drm_plane.h>
|
|
+#include <uapi/drm/drm_fourcc.h>
|
|
+
|
|
+#include "sun50i_afbc.h"
|
|
+#include "sun8i_mixer.h"
|
|
+
|
|
+bool sun50i_afbc_format_mod_supported(struct sun8i_mixer *mixer,
|
|
+ u32 format, u64 modifier)
|
|
+{
|
|
+ u64 mode;
|
|
+
|
|
+ if (modifier == DRM_FORMAT_MOD_INVALID)
|
|
+ return false;
|
|
+
|
|
+ if (modifier == DRM_FORMAT_MOD_LINEAR) {
|
|
+ if (format == DRM_FORMAT_YUV420_8BIT ||
|
|
+ format == DRM_FORMAT_YUV420_10BIT ||
|
|
+ format == DRM_FORMAT_Y210)
|
|
+ return false;
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ if (!mixer->cfg->is_de3)
|
|
+ return false;
|
|
+
|
|
+ mode = AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
|
|
+ AFBC_FORMAT_MOD_SPARSE |
|
|
+ AFBC_FORMAT_MOD_SPLIT;
|
|
+
|
|
+ switch (format) {
|
|
+ case DRM_FORMAT_RGBA8888:
|
|
+ case DRM_FORMAT_RGB888:
|
|
+ case DRM_FORMAT_RGB565:
|
|
+ case DRM_FORMAT_RGBA4444:
|
|
+ case DRM_FORMAT_RGBA5551:
|
|
+ case DRM_FORMAT_RGBA1010102:
|
|
+ mode |= AFBC_FORMAT_MOD_YTR;
|
|
+ break;
|
|
+ case DRM_FORMAT_YUYV:
|
|
+ case DRM_FORMAT_Y210:
|
|
+ case DRM_FORMAT_YUV420_8BIT:
|
|
+ case DRM_FORMAT_YUV420_10BIT:
|
|
+ break;
|
|
+ default:
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ return modifier == DRM_FORMAT_MOD_ARM_AFBC(mode);
|
|
+}
|
|
+
|
|
+void sun50i_afbc_atomic_update(struct sun8i_mixer *mixer, unsigned int channel,
|
|
+ struct drm_plane *plane)
|
|
+{
|
|
+ struct drm_plane_state *state = plane->state;
|
|
+ struct drm_framebuffer *fb = state->fb;
|
|
+ const struct drm_format_info *format = fb->format;
|
|
+ struct drm_gem_dma_object *gem;
|
|
+ u32 base, val, src_w, src_h;
|
|
+ u32 def_color0, def_color1;
|
|
+ struct regmap *regs;
|
|
+ dma_addr_t dma_addr;
|
|
+
|
|
+ base = sun8i_channel_base(mixer, channel) + SUN50I_AFBC_CH_OFFSET;
|
|
+ regs = mixer->engine.regs;
|
|
+
|
|
+ src_w = drm_rect_width(&state->src) >> 16;
|
|
+ src_h = drm_rect_height(&state->src) >> 16;
|
|
+
|
|
+ val = SUN50I_FBD_SIZE_HEIGHT(src_h);
|
|
+ val |= SUN50I_FBD_SIZE_WIDTH(src_w);
|
|
+ regmap_write(regs, SUN50I_FBD_SIZE(base), val);
|
|
+
|
|
+ val = SUN50I_FBD_BLK_SIZE_HEIGHT(DIV_ROUND_UP(src_h, 16));
|
|
+ val = SUN50I_FBD_BLK_SIZE_WIDTH(DIV_ROUND_UP(src_w, 16));
|
|
+ regmap_write(regs, SUN50I_FBD_BLK_SIZE(base), val);
|
|
+
|
|
+ val = SUN50I_FBD_SRC_CROP_TOP(0);
|
|
+ val |= SUN50I_FBD_SRC_CROP_LEFT(0);
|
|
+ regmap_write(regs, SUN50I_FBD_SRC_CROP(base), val);
|
|
+
|
|
+ val = SUN50I_FBD_LAY_CROP_TOP(state->src.y1 >> 16);
|
|
+ val |= SUN50I_FBD_LAY_CROP_LEFT(state->src.x1 >> 16);
|
|
+ regmap_write(regs, SUN50I_FBD_LAY_CROP(base), val);
|
|
+
|
|
+ /*
|
|
+ * Default color is always set to white, in colorspace and bitness
|
|
+ * that coresponds to used format. If it is actually used or not
|
|
+ * depends on AFBC buffer. At least in Cedrus it can be turned on
|
|
+ * or off.
|
|
+ * NOTE: G and B channels are off by 1 (up). It's unclear if this
|
|
+ * is because HW need such value or it is due to good enough code
|
|
+ * in vendor driver and HW clips the value anyway.
|
|
+ */
|
|
+ def_color0 = 0;
|
|
+ def_color1 = 0;
|
|
+
|
|
+ val = 0;
|
|
+ switch (format->format) {
|
|
+ case DRM_FORMAT_YUYV:
|
|
+ case DRM_FORMAT_YUV420_10BIT:
|
|
+ val |= SUN50I_FBD_FMT_SBS1(2);
|
|
+ val |= SUN50I_FBD_FMT_SBS0(1);
|
|
+ break;
|
|
+ case DRM_FORMAT_Y210:
|
|
+ val |= SUN50I_FBD_FMT_SBS1(3);
|
|
+ val |= SUN50I_FBD_FMT_SBS0(2);
|
|
+ break;
|
|
+ default:
|
|
+ val |= SUN50I_FBD_FMT_SBS1(1);
|
|
+ val |= SUN50I_FBD_FMT_SBS0(1);
|
|
+ break;
|
|
+ }
|
|
+ switch (format->format) {
|
|
+ case DRM_FORMAT_RGBA8888:
|
|
+ val |= SUN50I_FBD_FMT_YUV_TRAN;
|
|
+ val |= SUN50I_FBD_FMT_IN_FMT(SUN50I_AFBC_RGBA_8888);
|
|
+ def_color0 = SUN50I_FBD_DEFAULT_COLOR0_ALPHA(255) |
|
|
+ SUN50I_FBD_DEFAULT_COLOR0_YR(255);
|
|
+ def_color1 = SUN50I_FBD_DEFAULT_COLOR1_UG(256) |
|
|
+ SUN50I_FBD_DEFAULT_COLOR1_VB(256);
|
|
+ break;
|
|
+ case DRM_FORMAT_RGB888:
|
|
+ val |= SUN50I_FBD_FMT_YUV_TRAN;
|
|
+ val |= SUN50I_FBD_FMT_IN_FMT(SUN50I_AFBC_RGB_888);
|
|
+ def_color0 = SUN50I_FBD_DEFAULT_COLOR0_ALPHA(0) |
|
|
+ SUN50I_FBD_DEFAULT_COLOR0_YR(255);
|
|
+ def_color1 = SUN50I_FBD_DEFAULT_COLOR1_UG(256) |
|
|
+ SUN50I_FBD_DEFAULT_COLOR1_VB(256);
|
|
+ break;
|
|
+ case DRM_FORMAT_RGB565:
|
|
+ val |= SUN50I_FBD_FMT_YUV_TRAN;
|
|
+ val |= SUN50I_FBD_FMT_IN_FMT(SUN50I_AFBC_RGB_565);
|
|
+ def_color0 = SUN50I_FBD_DEFAULT_COLOR0_ALPHA(0) |
|
|
+ SUN50I_FBD_DEFAULT_COLOR0_YR(31);
|
|
+ def_color1 = SUN50I_FBD_DEFAULT_COLOR1_UG(64) |
|
|
+ SUN50I_FBD_DEFAULT_COLOR1_VB(32);
|
|
+ break;
|
|
+ case DRM_FORMAT_RGBA4444:
|
|
+ val |= SUN50I_FBD_FMT_YUV_TRAN;
|
|
+ val |= SUN50I_FBD_FMT_IN_FMT(SUN50I_AFBC_RGBA_4444);
|
|
+ def_color0 = SUN50I_FBD_DEFAULT_COLOR0_ALPHA(15) |
|
|
+ SUN50I_FBD_DEFAULT_COLOR0_YR(15);
|
|
+ def_color1 = SUN50I_FBD_DEFAULT_COLOR1_UG(16) |
|
|
+ SUN50I_FBD_DEFAULT_COLOR1_VB(16);
|
|
+ break;
|
|
+ case DRM_FORMAT_RGBA5551:
|
|
+ val |= SUN50I_FBD_FMT_YUV_TRAN;
|
|
+ val |= SUN50I_FBD_FMT_IN_FMT(SUN50I_AFBC_RGBA_5551);
|
|
+ def_color0 = SUN50I_FBD_DEFAULT_COLOR0_ALPHA(1) |
|
|
+ SUN50I_FBD_DEFAULT_COLOR0_YR(31);
|
|
+ def_color1 = SUN50I_FBD_DEFAULT_COLOR1_UG(32) |
|
|
+ SUN50I_FBD_DEFAULT_COLOR1_VB(32);
|
|
+ break;
|
|
+ case DRM_FORMAT_RGBA1010102:
|
|
+ val |= SUN50I_FBD_FMT_YUV_TRAN;
|
|
+ val |= SUN50I_FBD_FMT_IN_FMT(SUN50I_AFBC_RGBA1010102);
|
|
+ def_color0 = SUN50I_FBD_DEFAULT_COLOR0_ALPHA(3) |
|
|
+ SUN50I_FBD_DEFAULT_COLOR0_YR(1023);
|
|
+ def_color1 = SUN50I_FBD_DEFAULT_COLOR1_UG(1024) |
|
|
+ SUN50I_FBD_DEFAULT_COLOR1_VB(1024);
|
|
+ break;
|
|
+ case DRM_FORMAT_YUV420_8BIT:
|
|
+ val |= SUN50I_FBD_FMT_IN_FMT(SUN50I_AFBC_YUV420);
|
|
+ def_color0 = SUN50I_FBD_DEFAULT_COLOR0_ALPHA(0) |
|
|
+ SUN50I_FBD_DEFAULT_COLOR0_YR(255);
|
|
+ def_color1 = SUN50I_FBD_DEFAULT_COLOR1_UG(128) |
|
|
+ SUN50I_FBD_DEFAULT_COLOR1_VB(128);
|
|
+ break;
|
|
+ case DRM_FORMAT_YUYV:
|
|
+ val |= SUN50I_FBD_FMT_IN_FMT(SUN50I_AFBC_YUV422);
|
|
+ def_color0 = SUN50I_FBD_DEFAULT_COLOR0_ALPHA(0) |
|
|
+ SUN50I_FBD_DEFAULT_COLOR0_YR(255);
|
|
+ def_color1 = SUN50I_FBD_DEFAULT_COLOR1_UG(128) |
|
|
+ SUN50I_FBD_DEFAULT_COLOR1_VB(128);
|
|
+ break;
|
|
+ case DRM_FORMAT_YUV420_10BIT:
|
|
+ val |= SUN50I_FBD_FMT_IN_FMT(SUN50I_AFBC_P010);
|
|
+ def_color0 = SUN50I_FBD_DEFAULT_COLOR0_ALPHA(0) |
|
|
+ SUN50I_FBD_DEFAULT_COLOR0_YR(1023);
|
|
+ def_color1 = SUN50I_FBD_DEFAULT_COLOR1_UG(512) |
|
|
+ SUN50I_FBD_DEFAULT_COLOR1_VB(512);
|
|
+ break;
|
|
+ case DRM_FORMAT_Y210:
|
|
+ val |= SUN50I_FBD_FMT_IN_FMT(SUN50I_AFBC_P210);
|
|
+ def_color0 = SUN50I_FBD_DEFAULT_COLOR0_ALPHA(0) |
|
|
+ SUN50I_FBD_DEFAULT_COLOR0_YR(1023);
|
|
+ def_color1 = SUN50I_FBD_DEFAULT_COLOR1_UG(512) |
|
|
+ SUN50I_FBD_DEFAULT_COLOR1_VB(512);
|
|
+ break;
|
|
+ }
|
|
+ regmap_write(regs, SUN50I_FBD_FMT(base), val);
|
|
+
|
|
+ /* Get the physical address of the buffer in memory */
|
|
+ gem = drm_fb_dma_get_gem_obj(fb, 0);
|
|
+
|
|
+ DRM_DEBUG_DRIVER("Using GEM @ %pad\n", &gem->dma_addr);
|
|
+
|
|
+ /* Compute the start of the displayed memory */
|
|
+ dma_addr = gem->dma_addr + fb->offsets[0];
|
|
+
|
|
+ regmap_write(regs, SUN50I_FBD_LADDR(base), lower_32_bits(dma_addr));
|
|
+ regmap_write(regs, SUN50I_FBD_HADDR(base), upper_32_bits(dma_addr));
|
|
+
|
|
+ val = SUN50I_FBD_OVL_SIZE_HEIGHT(src_h);
|
|
+ val |= SUN50I_FBD_OVL_SIZE_WIDTH(src_w);
|
|
+ regmap_write(regs, SUN50I_FBD_OVL_SIZE(base), val);
|
|
+
|
|
+ val = SUN50I_FBD_OVL_COOR_Y(0);
|
|
+ val |= SUN50I_FBD_OVL_COOR_X(0);
|
|
+ regmap_write(regs, SUN50I_FBD_OVL_COOR(base), val);
|
|
+
|
|
+ regmap_write(regs, SUN50I_FBD_OVL_BG_COLOR(base),
|
|
+ SUN8I_MIXER_BLEND_COLOR_BLACK);
|
|
+ regmap_write(regs, SUN50I_FBD_DEFAULT_COLOR0(base), def_color0);
|
|
+ regmap_write(regs, SUN50I_FBD_DEFAULT_COLOR1(base), def_color1);
|
|
+
|
|
+ val = SUN50I_FBD_CTL_GLB_ALPHA(state->alpha >> 16);
|
|
+ val |= SUN50I_FBD_CTL_CLK_GATE;
|
|
+ val |= (state->alpha == DRM_BLEND_ALPHA_OPAQUE) ?
|
|
+ SUN50I_FBD_CTL_ALPHA_MODE_PIXEL :
|
|
+ SUN50I_FBD_CTL_ALPHA_MODE_COMBINED;
|
|
+ val |= SUN50I_FBD_CTL_FBD_EN;
|
|
+ regmap_write(regs, SUN50I_FBD_CTL(base), val);
|
|
+}
|
|
+
|
|
+void sun50i_afbc_disable(struct sun8i_mixer *mixer, unsigned int channel)
|
|
+{
|
|
+ u32 base = sun8i_channel_base(mixer, channel) + SUN50I_AFBC_CH_OFFSET;
|
|
+
|
|
+ regmap_write(mixer->engine.regs, SUN50I_FBD_CTL(base), 0);
|
|
+}
|
|
diff --git a/drivers/gpu/drm/sun4i/sun50i_afbc.h b/drivers/gpu/drm/sun4i/sun50i_afbc.h
|
|
new file mode 100644
|
|
index 000000000000..cea685c86855
|
|
--- /dev/null
|
|
+++ b/drivers/gpu/drm/sun4i/sun50i_afbc.h
|
|
@@ -0,0 +1,87 @@
|
|
+/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
+/*
|
|
+ * Copyright (C) Jernej Skrabec <jernej.skrabec@gmail.com>
|
|
+ */
|
|
+
|
|
+#ifndef _SUN50I_AFBC_H_
|
|
+#define _SUN50I_AFBC_H_
|
|
+
|
|
+#include <linux/types.h>
|
|
+
|
|
+#define SUN50I_AFBC_CH_OFFSET 0x300
|
|
+
|
|
+#define SUN50I_AFBC_RGBA_8888 0x02
|
|
+#define SUN50I_AFBC_RGB_888 0x08
|
|
+#define SUN50I_AFBC_RGB_565 0x0a
|
|
+#define SUN50I_AFBC_RGBA_4444 0x0e
|
|
+#define SUN50I_AFBC_RGBA_5551 0x12
|
|
+#define SUN50I_AFBC_RGBA1010102 0x16
|
|
+#define SUN50I_AFBC_YUV422 0x26
|
|
+#define SUN50I_AFBC_YUV420 0x2a
|
|
+#define SUN50I_AFBC_P010 0x30
|
|
+#define SUN50I_AFBC_P210 0x32
|
|
+
|
|
+#define SUN50I_FBD_CTL(base) ((base) + 0x00)
|
|
+#define SUN50I_FBD_CTL_GLB_ALPHA(v) ((v) << 24)
|
|
+#define SUN50I_FBD_CTL_CLK_GATE BIT(4)
|
|
+#define SUN50I_FBD_CTL_ALPHA_MODE_PIXEL ((0) << 2)
|
|
+#define SUN50I_FBD_CTL_ALPHA_MODE_LAYER ((1) << 2)
|
|
+#define SUN50I_FBD_CTL_ALPHA_MODE_COMBINED ((2) << 2)
|
|
+#define SUN50I_FBD_CTL_FBD_FCEN BIT(1)
|
|
+#define SUN50I_FBD_CTL_FBD_EN BIT(0)
|
|
+
|
|
+#define SUN50I_FBD_SIZE(base) ((base) + 0x08)
|
|
+#define SUN50I_FBD_SIZE_HEIGHT(v) (((v) - 1) << 16)
|
|
+#define SUN50I_FBD_SIZE_WIDTH(v) (((v) - 1) << 0)
|
|
+
|
|
+#define SUN50I_FBD_BLK_SIZE(base) ((base) + 0x0c)
|
|
+#define SUN50I_FBD_BLK_SIZE_HEIGHT(v) ((v) << 16)
|
|
+#define SUN50I_FBD_BLK_SIZE_WIDTH(v) ((v) << 0)
|
|
+
|
|
+#define SUN50I_FBD_SRC_CROP(base) ((base) + 0x10)
|
|
+#define SUN50I_FBD_SRC_CROP_TOP(v) ((v) << 16)
|
|
+#define SUN50I_FBD_SRC_CROP_LEFT(v) ((v) << 0)
|
|
+
|
|
+#define SUN50I_FBD_LAY_CROP(base) ((base) + 0x14)
|
|
+#define SUN50I_FBD_LAY_CROP_TOP(v) ((v) << 16)
|
|
+#define SUN50I_FBD_LAY_CROP_LEFT(v) ((v) << 0)
|
|
+
|
|
+#define SUN50I_FBD_FMT(base) ((base) + 0x18)
|
|
+#define SUN50I_FBD_FMT_SBS1(v) ((v) << 18)
|
|
+#define SUN50I_FBD_FMT_SBS0(v) ((v) << 16)
|
|
+#define SUN50I_FBD_FMT_YUV_TRAN BIT(7)
|
|
+#define SUN50I_FBD_FMT_IN_FMT(v) ((v) << 0)
|
|
+
|
|
+#define SUN50I_FBD_LADDR(base) ((base) + 0x20)
|
|
+#define SUN50I_FBD_HADDR(base) ((base) + 0x24)
|
|
+
|
|
+#define SUN50I_FBD_OVL_SIZE(base) ((base) + 0x30)
|
|
+#define SUN50I_FBD_OVL_SIZE_HEIGHT(v) (((v) - 1) << 16)
|
|
+#define SUN50I_FBD_OVL_SIZE_WIDTH(v) (((v) - 1) << 0)
|
|
+
|
|
+#define SUN50I_FBD_OVL_COOR(base) ((base) + 0x34)
|
|
+#define SUN50I_FBD_OVL_COOR_Y(v) ((v) << 16)
|
|
+#define SUN50I_FBD_OVL_COOR_X(v) ((v) << 0)
|
|
+
|
|
+#define SUN50I_FBD_OVL_BG_COLOR(base) ((base) + 0x38)
|
|
+#define SUN50I_FBD_OVL_FILL_COLOR(base) ((base) + 0x3c)
|
|
+
|
|
+#define SUN50I_FBD_DEFAULT_COLOR0(base) ((base) + 0x50)
|
|
+#define SUN50I_FBD_DEFAULT_COLOR0_ALPHA(v) ((v) << 16)
|
|
+#define SUN50I_FBD_DEFAULT_COLOR0_YR(v) ((v) << 0)
|
|
+
|
|
+#define SUN50I_FBD_DEFAULT_COLOR1(base) ((base) + 0x54)
|
|
+#define SUN50I_FBD_DEFAULT_COLOR1_VB(v) ((v) << 16)
|
|
+#define SUN50I_FBD_DEFAULT_COLOR1_UG(v) ((v) << 0)
|
|
+
|
|
+struct sun8i_mixer;
|
|
+struct drm_plane;
|
|
+
|
|
+bool sun50i_afbc_format_mod_supported(struct sun8i_mixer *mixer,
|
|
+ u32 format, u64 modifier);
|
|
+
|
|
+void sun50i_afbc_atomic_update(struct sun8i_mixer *mixer, unsigned int channel,
|
|
+ struct drm_plane *plane);
|
|
+void sun50i_afbc_disable(struct sun8i_mixer *mixer, unsigned int channel);
|
|
+
|
|
+#endif
|
|
diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
|
|
index 329e8bf8cd20..bda91c3e2bb7 100644
|
|
--- a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
|
|
+++ b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
|
|
@@ -11,8 +11,10 @@
|
|
#include <drm/drm_framebuffer.h>
|
|
#include <drm/drm_gem_atomic_helper.h>
|
|
#include <drm/drm_gem_dma_helper.h>
|
|
+#include <drm/drm_gem_framebuffer_helper.h>
|
|
#include <drm/drm_probe_helper.h>
|
|
|
|
+#include "sun50i_afbc.h"
|
|
#include "sun8i_csc.h"
|
|
#include "sun8i_mixer.h"
|
|
#include "sun8i_vi_layer.h"
|
|
@@ -99,7 +101,7 @@ static void sun8i_vi_layer_update_alpha(struct sun8i_mixer *mixer, int channel,
|
|
|
|
static int sun8i_vi_layer_update_coord(struct sun8i_mixer *mixer, int channel,
|
|
int overlay, struct drm_plane *plane,
|
|
- unsigned int zpos)
|
|
+ unsigned int zpos, bool afbc)
|
|
{
|
|
struct drm_plane_state *state = plane->state;
|
|
const struct drm_format_info *format = state->fb->format;
|
|
@@ -182,7 +184,7 @@ static int sun8i_vi_layer_update_coord(struct sun8i_mixer *mixer, int channel,
|
|
|
|
required = src_h * 100 / dst_h;
|
|
|
|
- if (ability < required) {
|
|
+ if (!afbc && ability < required) {
|
|
DRM_DEBUG_DRIVER("Using vertical coarse scaling\n");
|
|
vm = src_h;
|
|
vn = (u32)ability * dst_h / 100;
|
|
@@ -192,7 +194,7 @@ static int sun8i_vi_layer_update_coord(struct sun8i_mixer *mixer, int channel,
|
|
/* it seems that every RGB scaler has buffer for 2048 pixels */
|
|
scanline = subsampled ? mixer->cfg->scanline_yuv : 2048;
|
|
|
|
- if (src_w > scanline) {
|
|
+ if (!afbc && src_w > scanline) {
|
|
DRM_DEBUG_DRIVER("Using horizontal coarse scaling\n");
|
|
hm = src_w;
|
|
hn = scanline;
|
|
@@ -356,6 +358,15 @@ static int sun8i_vi_layer_update_buffer(struct sun8i_mixer *mixer, int channel,
|
|
return 0;
|
|
}
|
|
|
|
+static void sun8i_vi_layer_prepare_non_linear(struct sun8i_mixer *mixer,
|
|
+ int channel, int overlay)
|
|
+{
|
|
+ u32 base = sun8i_channel_base(mixer, channel);
|
|
+
|
|
+ regmap_write(mixer->engine.regs,
|
|
+ SUN8I_MIXER_CHAN_VI_LAYER_ATTR(base, overlay), 0);
|
|
+}
|
|
+
|
|
static int sun8i_vi_layer_atomic_check(struct drm_plane *plane,
|
|
struct drm_atomic_state *state)
|
|
{
|
|
@@ -399,6 +410,8 @@ static void sun8i_vi_layer_atomic_disable(struct drm_plane *plane,
|
|
|
|
sun8i_vi_layer_enable(mixer, layer->channel, layer->overlay, false, 0,
|
|
old_zpos);
|
|
+ if (mixer->cfg->is_de3)
|
|
+ sun50i_afbc_disable(mixer, layer->channel);
|
|
}
|
|
|
|
static void sun8i_vi_layer_atomic_update(struct drm_plane *plane,
|
|
@@ -411,26 +424,53 @@ static void sun8i_vi_layer_atomic_update(struct drm_plane *plane,
|
|
struct sun8i_vi_layer *layer = plane_to_sun8i_vi_layer(plane);
|
|
unsigned int zpos = new_state->normalized_zpos;
|
|
unsigned int old_zpos = old_state->normalized_zpos;
|
|
+ struct drm_framebuffer *fb = plane->state->fb;
|
|
struct sun8i_mixer *mixer = layer->mixer;
|
|
+ bool afbc = drm_is_afbc(fb->modifier);
|
|
|
|
if (!new_state->visible) {
|
|
sun8i_vi_layer_enable(mixer, layer->channel,
|
|
layer->overlay, false, 0, old_zpos);
|
|
+ if (mixer->cfg->is_de3)
|
|
+ sun50i_afbc_disable(mixer, layer->channel);
|
|
return;
|
|
}
|
|
|
|
+ if (afbc) {
|
|
+ u32 fmt_type;
|
|
+
|
|
+ sun8i_vi_layer_prepare_non_linear(mixer, layer->channel,
|
|
+ layer->overlay);
|
|
+ sun50i_afbc_atomic_update(mixer, layer->channel, plane);
|
|
+
|
|
+ fmt_type = sun8i_vi_layer_get_format_type(fb->format);
|
|
+ sun8i_csc_set_ccsc(mixer, layer->channel, fmt_type,
|
|
+ plane->state->color_encoding,
|
|
+ plane->state->color_range);
|
|
+ } else {
|
|
+ if (mixer->cfg->is_de3)
|
|
+ sun50i_afbc_disable(mixer, layer->channel);
|
|
+ sun8i_vi_layer_update_alpha(mixer, layer->channel,
|
|
+ layer->overlay, plane);
|
|
+ sun8i_vi_layer_update_formats(mixer, layer->channel,
|
|
+ layer->overlay, plane);
|
|
+ sun8i_vi_layer_update_buffer(mixer, layer->channel,
|
|
+ layer->overlay, plane);
|
|
+ }
|
|
sun8i_vi_layer_update_coord(mixer, layer->channel,
|
|
- layer->overlay, plane, zpos);
|
|
- sun8i_vi_layer_update_alpha(mixer, layer->channel,
|
|
- layer->overlay, plane);
|
|
- sun8i_vi_layer_update_formats(mixer, layer->channel,
|
|
- layer->overlay, plane);
|
|
- sun8i_vi_layer_update_buffer(mixer, layer->channel,
|
|
- layer->overlay, plane);
|
|
+ layer->overlay, plane, zpos, afbc);
|
|
sun8i_vi_layer_enable(mixer, layer->channel, layer->overlay,
|
|
true, zpos, old_zpos);
|
|
}
|
|
|
|
+static bool sun8i_vi_layer_format_mod_supported(struct drm_plane *plane,
|
|
+ u32 format, u64 modifier)
|
|
+{
|
|
+ struct sun8i_vi_layer *layer = plane_to_sun8i_vi_layer(plane);
|
|
+
|
|
+ return sun50i_afbc_format_mod_supported(layer->mixer, format, modifier);
|
|
+}
|
|
+
|
|
static const struct drm_plane_helper_funcs sun8i_vi_layer_helper_funcs = {
|
|
.atomic_check = sun8i_vi_layer_atomic_check,
|
|
.atomic_disable = sun8i_vi_layer_atomic_disable,
|
|
@@ -444,6 +484,7 @@ static const struct drm_plane_funcs sun8i_vi_layer_funcs = {
|
|
.disable_plane = drm_atomic_helper_disable_plane,
|
|
.reset = drm_atomic_helper_plane_reset,
|
|
.update_plane = drm_atomic_helper_update_plane,
|
|
+ .format_mod_supported = sun8i_vi_layer_format_mod_supported,
|
|
};
|
|
|
|
/*
|
|
@@ -527,6 +568,11 @@ static const u32 sun8i_vi_layer_de3_formats[] = {
|
|
DRM_FORMAT_YVU411,
|
|
DRM_FORMAT_YVU420,
|
|
DRM_FORMAT_YVU422,
|
|
+
|
|
+ /* AFBC only formats */
|
|
+ DRM_FORMAT_YUV420_8BIT,
|
|
+ DRM_FORMAT_YUV420_10BIT,
|
|
+ DRM_FORMAT_Y210,
|
|
};
|
|
|
|
static const uint64_t sun8i_layer_modifiers[] = {
|
|
@@ -534,6 +580,18 @@ static const uint64_t sun8i_layer_modifiers[] = {
|
|
DRM_FORMAT_MOD_INVALID
|
|
};
|
|
|
|
+static const uint64_t sun50i_layer_de3_modifiers[] = {
|
|
+ DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
|
|
+ AFBC_FORMAT_MOD_SPARSE |
|
|
+ AFBC_FORMAT_MOD_SPLIT),
|
|
+ DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
|
|
+ AFBC_FORMAT_MOD_YTR |
|
|
+ AFBC_FORMAT_MOD_SPARSE |
|
|
+ AFBC_FORMAT_MOD_SPLIT),
|
|
+ DRM_FORMAT_MOD_LINEAR,
|
|
+ DRM_FORMAT_MOD_INVALID
|
|
+};
|
|
+
|
|
struct sun8i_vi_layer *sun8i_vi_layer_init_one(struct drm_device *drm,
|
|
struct sun8i_mixer *mixer,
|
|
int index)
|
|
@@ -542,6 +600,7 @@ struct sun8i_vi_layer *sun8i_vi_layer_init_one(struct drm_device *drm,
|
|
u32 supported_encodings, supported_ranges;
|
|
unsigned int plane_cnt, format_count;
|
|
struct sun8i_vi_layer *layer;
|
|
+ const uint64_t *modifiers;
|
|
const u32 *formats;
|
|
int ret;
|
|
|
|
@@ -556,9 +615,11 @@ struct sun8i_vi_layer *sun8i_vi_layer_init_one(struct drm_device *drm,
|
|
if (mixer->cfg->is_de3) {
|
|
formats = sun8i_vi_layer_de3_formats;
|
|
format_count = ARRAY_SIZE(sun8i_vi_layer_de3_formats);
|
|
+ modifiers = sun50i_layer_de3_modifiers;
|
|
} else {
|
|
formats = sun8i_vi_layer_formats;
|
|
format_count = ARRAY_SIZE(sun8i_vi_layer_formats);
|
|
+ modifiers = sun8i_layer_modifiers;
|
|
}
|
|
|
|
if (!mixer->cfg->ui_num && index == 0)
|
|
@@ -568,8 +629,7 @@ struct sun8i_vi_layer *sun8i_vi_layer_init_one(struct drm_device *drm,
|
|
ret = drm_universal_plane_init(drm, &layer->plane, 0,
|
|
&sun8i_vi_layer_funcs,
|
|
formats, format_count,
|
|
- sun8i_layer_modifiers,
|
|
- type, NULL);
|
|
+ modifiers, type, NULL);
|
|
if (ret) {
|
|
dev_err(drm->dev, "Couldn't initialize layer\n");
|
|
return ERR_PTR(ret);
|
|
--
|
|
2.42.0
|
|
|