On Fri,  7 Jun 2024 23:00:03 +1200
Ryan Walklin <r...@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.skra...@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 <r...@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 <r...@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.skra...@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.skra...@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);

Reply via email to