@@ -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
new file mode 100644
@@ -0,0 +1,250 @@
+// 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"
+
+static u32 sun50i_afbc_get_base(struct sun8i_mixer *mixer, unsigned int channel)
+{
+ u32 base = sun8i_channel_base(mixer, channel);
+
+ if (mixer->cfg->de_type == sun8i_mixer_de3)
+ return base + SUN50I_AFBC_CH_OFFSET;
+
+ return base + 0x4000;
+}
+
+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->de_type == sun8i_mixer_de2)
+ 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 = sun50i_afbc_get_base(mixer, channel);
+ 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 = sun50i_afbc_get_base(mixer, channel);
+
+ regmap_write(mixer->engine.regs, SUN50I_FBD_CTL(base), 0);
+}
new file mode 100644
@@ -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
@@ -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"
@@ -101,7 +103,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;
@@ -186,7 +188,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;
@@ -196,7 +198,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;
@@ -359,6 +361,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)
{
@@ -402,6 +413,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->de_type >= sun8i_mixer_de3)
+ sun50i_afbc_disable(mixer, layer->channel);
}
static void sun8i_vi_layer_atomic_update(struct drm_plane *plane,
@@ -414,26 +427,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->de_type >= sun8i_mixer_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->de_type >= sun8i_mixer_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,
@@ -447,6 +487,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,
};
/*
@@ -530,6 +571,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[] = {
@@ -537,6 +583,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)
@@ -545,6 +603,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;
@@ -559,9 +618,11 @@ struct sun8i_vi_layer *sun8i_vi_layer_init_one(struct drm_device *drm,
if (mixer->cfg->de_type >= sun8i_mixer_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)
@@ -571,8 +632,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);