[PATCH RFC 7/8] drm/sun4i: de3: Implement AFBC support
Andre Przywara
andre.przywara at arm.com
Fri Jun 7 14:32:50 UTC 2024
On Fri, 7 Jun 2024 23:00:03 +1200
Ryan Walklin <ryan at testtoast.com> wrote:
Hi Ryan,
thanks for taking the time and posting those patches!
> 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 at gmail.com>
This signature suggests that it's indeed Jernej's patch, so it should
have his authorship, as in the other patches, indicated by a line starting
with "From:" before the commit message.
> Co-developed-by: Ryan Walklin <ryan at testtoast.com>
Is that really the case? I find an identical patch in Jernej's github,
committed end of February, created late last year. So it's entirely his
patch, then?
"Co-developed-by:" is only used if the patch really has two authors, both
having contributed significantly to the patch.
If you merely post a patch from someone else, then it just needs your
Signed-off-by, as you correctly do below.
That applies to the other patches as well.
Cheers,
Andre
> Signed-off-by: Ryan Walklin <ryan at testtoast.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 3f516329f51ee..78290f1660fbd 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 0000000000000..27a771608eef8
> --- /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 at 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 0000000000000..cea685c868550
> --- /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 at 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 329e8bf8cd20d..bda91c3e2bb75 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);
More information about the dri-devel
mailing list