2019-02-26 16:23:44

by Ayan Halder

[permalink] [raw]
Subject: [PATCH v3 00/10] Add support for Arm Framebuffer Compression(AFBC) in mali display driver

This patchset aims to add support for AFBC in mali display driver with
the help of format modifiers. AFBC modifiers add some constraints to
framebuffer size, alignment, pitch, formats, etc

In the initial patchset ie
https://lists.freedesktop.org/archives/dri-devel/2018-June/180124.html

I had illustrated how to add support for one format (ie BGR888) with
one valid combination of AFBC modifiers ie
AFBC_SIZE_16X16 | AFBC_YTR | AFBC_SPARSE

Changes from v1:-
Enabled the support for all AFBC modifiers
(which are supported on DP500, DP550 and DP650) with all the pixel formats.
Also, we have introduced some new pixel formats which are supported with
AFBC modifiers only as well some other pixel formats which are supported with
LINEAR only.

Changes from v2 (ie https://patchwork.freedesktop.org/patch/265212/):-
- Addressed the review comments on the previous patchset.
- Rebased on top of the drm-misc-next


Ayan Kumar Halder (9):
drm: Added a new format DRM_FORMAT_XVYU2101010
drm/arm/malidp: Set the AFBC register bits if the framebuffer has AFBC
modifier
drm/arm/malidp:- Added support for new YUV formats for DP500, DP550
and DP650
drm/arm/malidp:- Define a common list of AFBC format modifiers
supported for DP500, DP550 and DP650
drm/arm/malidp: Specified the rotation memory requirements for AFBC
YUV formats
drm/arm/malidp:- Writeback framebuffer does not support any modifiers
drm/arm/malidp:- Use the newly introduced malidp_format_get_bpp()
instead of relying on cpp for calculating framebuffer size
drm/arm/malidp:- Disregard the pitch alignment constraint for AFBC
framebuffer.
drm/arm/malidp: Added support for AFBC modifiers for all layers except
DE_SMART

Brian Starkey (1):
drm/fourcc: Add AFBC yuv fourccs for Mali

drivers/gpu/drm/arm/malidp_drv.c | 48 +++----
drivers/gpu/drm/arm/malidp_drv.h | 6 +
drivers/gpu/drm/arm/malidp_hw.c | 249 +++++++++++++++++++++++++++++----
drivers/gpu/drm/arm/malidp_hw.h | 31 ++++-
drivers/gpu/drm/arm/malidp_mw.c | 7 +-
drivers/gpu/drm/arm/malidp_planes.c | 271 +++++++++++++++++++++++++++++++++---
drivers/gpu/drm/arm/malidp_regs.h | 20 +++
drivers/gpu/drm/drm_fourcc.c | 17 +++
include/uapi/drm/drm_fourcc.h | 23 ++-
9 files changed, 586 insertions(+), 86 deletions(-)

--
2.7.4



2019-02-26 16:21:54

by Ayan Halder

[permalink] [raw]
Subject: [PATCH 06/10] drm/arm/malidp: Specified the rotation memory requirements for AFBC YUV formats

From: Ayan Kumar Halder <[email protected]>

The newly supported AFBC YUV formats have the following rotation memory
constraints (in DP550/DP650).
1. DRM_FORMAT_VUY888/DRM_FORMAT_VUY101010 :- It can rotate upto 8
horizontal lines in the AFBC output buffer.
2. DRM_FORMAT_YUV420_8BIT :- It can rotate upto 16 horizontal lines
in the AFBC output buffer.

Also some of the pixel formats are specified in bits per pixel (rather
than bytes per pixel), so the calculation needs to take note of this.

Besides there are some difference between DP550 and DP650 and these are
as follows:-
1. DRM_FORMAT_X0L2 (in uncompressed format) does not support rotation in
DP550. For DP650, it can rotate upto 16 horizontal lines in the AFBC
output buffer, whereas in DP550 (with AFBC), it can rotate upto 8
horizontal lines.
2. DRM_FORMAT_YUV420_10BIT :- It can rotate upto 8 horizontal lines in
dp550 and 16 horizontal lines in DP650.

Signed-off-by: Ayan Kumar halder <[email protected]>
Reviewed-by: Liviu Dudau <[email protected]>
---
drivers/gpu/drm/arm/malidp_hw.c | 101 ++++++++++++++++++++++++++++++++----
drivers/gpu/drm/arm/malidp_hw.h | 5 +-
drivers/gpu/drm/arm/malidp_planes.c | 3 +-
3 files changed, 98 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/arm/malidp_hw.c b/drivers/gpu/drm/arm/malidp_hw.c
index 0ac2762..8df12e9 100644
--- a/drivers/gpu/drm/arm/malidp_hw.c
+++ b/drivers/gpu/drm/arm/malidp_hw.c
@@ -380,14 +380,39 @@ static void malidp500_modeset(struct malidp_hw_device *hwdev, struct videomode *
malidp_hw_clearbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC);
}

-static int malidp500_rotmem_required(struct malidp_hw_device *hwdev, u16 w, u16 h, u32 fmt)
+int malidp_format_get_bpp(u32 fmt)
+{
+ int bpp = drm_format_plane_cpp(fmt, 0) * 8;
+
+ if (bpp == 0) {
+ switch (fmt) {
+ case DRM_FORMAT_VUY101010:
+ bpp = 30;
+ case DRM_FORMAT_YUV420_10BIT:
+ bpp = 15;
+ break;
+ case DRM_FORMAT_YUV420_8BIT:
+ bpp = 12;
+ break;
+ default:
+ bpp = 0;
+ }
+ }
+
+ return bpp;
+}
+
+static int malidp500_rotmem_required(struct malidp_hw_device *hwdev, u16 w,
+ u16 h, u32 fmt, bool has_modifier)
{
/*
* Each layer needs enough rotation memory to fit 8 lines
* worth of pixel data. Required size is then:
* size = rotated_width * (bpp / 8) * 8;
*/
- return w * drm_format_plane_cpp(fmt, 0) * 8;
+ int bpp = malidp_format_get_bpp(fmt);
+
+ return w * bpp;
}

static void malidp500_se_write_pp_coefftab(struct malidp_hw_device *hwdev,
@@ -665,9 +690,9 @@ static void malidp550_modeset(struct malidp_hw_device *hwdev, struct videomode *
malidp_hw_clearbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC);
}

-static int malidp550_rotmem_required(struct malidp_hw_device *hwdev, u16 w, u16 h, u32 fmt)
+static int malidpx50_get_bytes_per_column(u32 fmt)
{
- u32 bytes_per_col;
+ u32 bytes_per_column;

switch (fmt) {
/* 8 lines at 4 bytes per pixel */
@@ -693,19 +718,77 @@ static int malidp550_rotmem_required(struct malidp_hw_device *hwdev, u16 w, u16
case DRM_FORMAT_UYVY:
case DRM_FORMAT_YUYV:
case DRM_FORMAT_X0L0:
- case DRM_FORMAT_X0L2:
- bytes_per_col = 32;
+ bytes_per_column = 32;
break;
/* 16 lines at 1.5 bytes per pixel */
case DRM_FORMAT_NV12:
case DRM_FORMAT_YUV420:
- bytes_per_col = 24;
+ /* 8 lines at 3 bytes per pixel */
+ case DRM_FORMAT_VUY888:
+ /* 16 lines at 12 bits per pixel */
+ case DRM_FORMAT_YUV420_8BIT:
+ /* 8 lines at 3 bytes per pixel */
+ case DRM_FORMAT_P010:
+ bytes_per_column = 24;
+ break;
+ /* 8 lines at 30 bits per pixel */
+ case DRM_FORMAT_VUY101010:
+ /* 16 lines at 15 bits per pixel */
+ case DRM_FORMAT_YUV420_10BIT:
+ bytes_per_column = 30;
break;
default:
return -EINVAL;
}

- return w * bytes_per_col;
+ return bytes_per_column;
+}
+
+static int malidp550_rotmem_required(struct malidp_hw_device *hwdev, u16 w,
+ u16 h, u32 fmt, bool has_modifier)
+{
+ int bytes_per_column = 0;
+
+ switch (fmt) {
+ /* 8 lines at 15 bits per pixel */
+ case DRM_FORMAT_YUV420_10BIT:
+ bytes_per_column = 15;
+ break;
+ /* Uncompressed YUV 420 10 bit single plane cannot be rotated */
+ case DRM_FORMAT_X0L2:
+ if (has_modifier)
+ bytes_per_column = 8;
+ else
+ return -EINVAL;
+ break;
+ default:
+ bytes_per_column = malidpx50_get_bytes_per_column(fmt);
+ }
+
+ if (bytes_per_column == -EINVAL)
+ return bytes_per_column;
+
+ return w * bytes_per_column;
+}
+
+static int malidp650_rotmem_required(struct malidp_hw_device *hwdev, u16 w,
+ u16 h, u32 fmt, bool has_modifier)
+{
+ int bytes_per_column = 0;
+
+ switch (fmt) {
+ /* 16 lines at 2 bytes per pixel */
+ case DRM_FORMAT_X0L2:
+ bytes_per_column = 32;
+ break;
+ default:
+ bytes_per_column = malidpx50_get_bytes_per_column(fmt);
+ }
+
+ if (bytes_per_column == -EINVAL)
+ return bytes_per_column;
+
+ return w * bytes_per_column;
}

static int malidp550_se_set_scaling_coeffs(struct malidp_hw_device *hwdev,
@@ -984,7 +1067,7 @@ const struct malidp_hw malidp_device[MALIDP_MAX_DEVICES] = {
.in_config_mode = malidp550_in_config_mode,
.set_config_valid = malidp550_set_config_valid,
.modeset = malidp550_modeset,
- .rotmem_required = malidp550_rotmem_required,
+ .rotmem_required = malidp650_rotmem_required,
.se_set_scaling_coeffs = malidp550_se_set_scaling_coeffs,
.se_calc_mclk = malidp550_se_calc_mclk,
.enable_memwrite = malidp550_enable_memwrite,
diff --git a/drivers/gpu/drm/arm/malidp_hw.h b/drivers/gpu/drm/arm/malidp_hw.h
index 0859302..207c3ce 100644
--- a/drivers/gpu/drm/arm/malidp_hw.h
+++ b/drivers/gpu/drm/arm/malidp_hw.h
@@ -184,7 +184,8 @@ struct malidp_hw {
* Calculate the required rotation memory given the active area
* and the buffer format.
*/
- int (*rotmem_required)(struct malidp_hw_device *hwdev, u16 w, u16 h, u32 fmt);
+ int (*rotmem_required)(struct malidp_hw_device *hwdev, u16 w, u16 h,
+ u32 fmt, bool has_modifier);

int (*se_set_scaling_coeffs)(struct malidp_hw_device *hwdev,
struct malidp_se_config *se_config,
@@ -326,6 +327,8 @@ void malidp_se_irq_fini(struct malidp_hw_device *hwdev);
u8 malidp_hw_get_format_id(const struct malidp_hw_regmap *map,
u8 layer_id, u32 format, bool has_modifier);

+int malidp_format_get_bpp(u32 fmt);
+
static inline u8 malidp_hw_get_pitch_align(struct malidp_hw_device *hwdev, bool rotated)
{
/*
diff --git a/drivers/gpu/drm/arm/malidp_planes.c b/drivers/gpu/drm/arm/malidp_planes.c
index 79e00bf..3dc8a6f 100644
--- a/drivers/gpu/drm/arm/malidp_planes.c
+++ b/drivers/gpu/drm/arm/malidp_planes.c
@@ -597,7 +597,8 @@ static int malidp_de_plane_check(struct drm_plane *plane,

val = mp->hwdev->hw->rotmem_required(mp->hwdev, state->crtc_w,
state->crtc_h,
- fb->format->format);
+ fb->format->format,
+ !!(fb->modifier));
if (val < 0)
return val;

--
2.7.4


2019-02-26 16:22:01

by Ayan Halder

[permalink] [raw]
Subject: [PATCH 07/10] drm/arm/malidp:- Writeback framebuffer does not support any modifiers

From: Ayan Kumar Halder <[email protected]>

In malidp, the writeback pipeline does not support writing crtc output
to a framebuffer with modifiers ie the memory writeback content is
devoid of any compression or tiling, etc.
So we have added a commit check in memory writeback encoder helper function
to validate if the framebuffer has any modifier and if so, return EINVAL.

Signed-off-by: Ayan Kumar halder <[email protected]>
Acked-by: Liviu Dudau <[email protected]>
---
drivers/gpu/drm/arm/malidp_mw.c | 5 +++++
1 file changed, 5 insertions(+)

diff --git a/drivers/gpu/drm/arm/malidp_mw.c b/drivers/gpu/drm/arm/malidp_mw.c
index 28cd351..2865f7a 100644
--- a/drivers/gpu/drm/arm/malidp_mw.c
+++ b/drivers/gpu/drm/arm/malidp_mw.c
@@ -141,6 +141,11 @@ malidp_mw_encoder_atomic_check(struct drm_encoder *encoder,
return -EINVAL;
}

+ if (fb->modifier) {
+ DRM_DEBUG_KMS("Writeback framebuffer does not support modifiers\n");
+ return -EINVAL;
+ }
+
mw_state->format =
malidp_hw_get_format_id(&malidp->dev->hw->map, SE_MEMWRITE,
fb->format->format, !!fb->modifier);
--
2.7.4


2019-02-26 16:22:14

by Ayan Halder

[permalink] [raw]
Subject: [PATCH 08/10] drm/arm/malidp:- Use the newly introduced malidp_format_get_bpp() instead of relying on cpp for calculating framebuffer size

From: Ayan Kumar Halder <[email protected]>

Formats like DRM_FORMAT_VUY101010, DRM_FORMAT_YUV420_8BIT and
DRM_FORMAT_YUV420_10BIT are expressed in bits per pixel as they have a non
integer value of cpp (thus denoted as '0' in drm_format_info[]). Therefore,
the calculation of AFBC framebuffer size needs to use malidp_format_get_bpp().

Signed-off-by: Ayan Kumar halder <[email protected]>
Reviewed-by: Liviu Dudau <[email protected]>
---
drivers/gpu/drm/arm/malidp_drv.c | 15 ++++++++++-----
1 file changed, 10 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/arm/malidp_drv.c b/drivers/gpu/drm/arm/malidp_drv.c
index c697664..4106f5d 100644
--- a/drivers/gpu/drm/arm/malidp_drv.c
+++ b/drivers/gpu/drm/arm/malidp_drv.c
@@ -298,6 +298,7 @@ malidp_verify_afbc_framebuffer_size(struct drm_device *dev,
struct drm_gem_object *objs = NULL;
u32 afbc_superblock_size = 0, afbc_superblock_height = 0;
u32 afbc_superblock_width = 0, afbc_size = 0;
+ int bpp = 0;

switch (mode_cmd->modifier[0] & AFBC_SIZE_MASK) {
case AFBC_SIZE_16X16:
@@ -314,15 +315,19 @@ malidp_verify_afbc_framebuffer_size(struct drm_device *dev,
n_superblocks = (mode_cmd->width / afbc_superblock_width) *
(mode_cmd->height / afbc_superblock_height);

- afbc_superblock_size = info->cpp[0] * afbc_superblock_width *
- afbc_superblock_height;
+ bpp = malidp_format_get_bpp(info->format);
+
+ afbc_superblock_size = (bpp * afbc_superblock_width * afbc_superblock_height)
+ / BITS_PER_BYTE;

afbc_size = ALIGN(n_superblocks * AFBC_HEADER_SIZE, AFBC_SUPERBLK_ALIGNMENT);
afbc_size += n_superblocks * ALIGN(afbc_superblock_size, AFBC_SUPERBLK_ALIGNMENT);

- if (mode_cmd->width * info->cpp[0] != mode_cmd->pitches[0]) {
- DRM_DEBUG_KMS("Invalid value of pitch (=%u) should be same as width (=%u) * cpp (=%u)\n",
- mode_cmd->pitches[0], mode_cmd->width, info->cpp[0]);
+ if ((mode_cmd->width * bpp) != (mode_cmd->pitches[0] * BITS_PER_BYTE)) {
+ DRM_DEBUG_KMS("Invalid value of (pitch * BITS_PER_BYTE) (=%u) "
+ "should be same as width (=%u) * bpp (=%u)\n",
+ (mode_cmd->pitches[0] * BITS_PER_BYTE),
+ mode_cmd->width, bpp);
return false;
}

--
2.7.4


2019-02-26 16:22:24

by Ayan Halder

[permalink] [raw]
Subject: [PATCH 09/10] drm/arm/malidp:- Disregard the pitch alignment constraint for AFBC framebuffer.

From: Ayan Kumar Halder <[email protected]>

Considering the fact that some of the AFBC specific pixel formats are expressed
in bits per pixel (ie bpp which is not byte aligned), the pitch (ie width * bpp)
is not guaranteed to be aligned to burst size (ie 8 or 16 bytes).
For example, DRM_FORMAT_VUY101010 is 30 bits per pixel. For a framebuffer of
width 32 pixels, the pitch will be 120 bytes which is not aligned to burst size
(ie 16 bytes) for DP650.

Signed-off-by: Ayan Kumar halder <[email protected]>
Acked-by: Liviu Dudau <[email protected]>
---
drivers/gpu/drm/arm/malidp_planes.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/arm/malidp_planes.c b/drivers/gpu/drm/arm/malidp_planes.c
index 3dc8a6f..044bf7f 100644
--- a/drivers/gpu/drm/arm/malidp_planes.c
+++ b/drivers/gpu/drm/arm/malidp_planes.c
@@ -531,8 +531,8 @@ static int malidp_de_plane_check(struct drm_plane *plane,
for (i = 0; i < ms->n_planes; i++) {
u8 alignment = malidp_hw_get_pitch_align(mp->hwdev, rotated);

- if ((fb->pitches[i] * drm_format_info_block_height(fb->format, i))
- & (alignment - 1)) {
+ if (((fb->pitches[i] * drm_format_info_block_height(fb->format, i))
+ & (alignment - 1)) && !(fb->modifier)) {
DRM_DEBUG_KMS("Invalid pitch %u for plane %d\n",
fb->pitches[i], i);
return -EINVAL;
--
2.7.4


2019-02-26 16:22:26

by Ayan Halder

[permalink] [raw]
Subject: [PATCH v2 05/10] drm/arm/malidp:- Define a common list of AFBC format modifiers supported for DP500, DP550 and DP650

From: Ayan Kumar Halder <[email protected]>

We need to define a common list of format modifiers supported by each of
the Mali display processors.

The following are the constraints with AFBC:-

1. AFBC is not supported for the formats defined in
malidp_hw_format_is_linear_only()

2. Some of the formats are supported only with AFBC modifiers. Thus we have
introduced a new function 'malidp_hw_format_is_afbc_only()' which verifies
the same.

3. AFBC_FORMAT_MOD_YTR needs to be provided for any RGB format.

4. Formats <= 16bpp cannot support AFBC_FORMAT_MOD_SPLIT.

5. CBR should not be set for non-subsampled formats.

6. SMART layer does not support framebuffer with AFBC modifiers.
Return -EINVAL for such a scenario.

7. AFBC_FORMAT_MOD_YTR is not supported for any YUV formats.

8. Formats which are subsampled cannot support AFBC_FORMAT_MOD_SPLIT.
However in DP550, YUV_420_10BIT is supported with AFBC_FORMAT_MOD_SPLIT.
This feature has been identified with
MALIDP_DEVICE_AFBC_YUV_420_10_SUPPORT_SPLIT.

9. In DP550 and DP650, for YUYV, the hardware supports different
format-ids to be used with and without AFBC modifier. We have used the
feature 'MALIDP_DEVICE_AFBC_YUYV_USE_422_P2' to identify this
characteristic.

10. DP500 does not support split mode (ie AFBC_FORMAT_MOD_SPLIT). We have
used the feature 'MALIDP_DEVICE_AFBC_SUPPORT_SPLIT' to identify the DPs
which support SPLIT mode.

11. DP550 supports YUV420 with split mode. We have defined the feature
'AFBC_SUPPORT_SPLIT_WITH_YUV_420_10' to identify this characteristic.

Changes since v1:-
- Merged https://patchwork.freedesktop.org/patch/265215/ into this patch
- As Liviu pointed out in the last patch, we can pull the checks outside
of the 'while (*modifiers != DRM_FORMAT_MOD_INVALID)' loop
- Rebased

Signed-off-by: Ayan Kumar halder <[email protected]>
---
drivers/gpu/drm/arm/malidp_drv.c | 32 ++-------
drivers/gpu/drm/arm/malidp_drv.h | 6 ++
drivers/gpu/drm/arm/malidp_hw.c | 96 +++++++++++++++++++++++++--
drivers/gpu/drm/arm/malidp_hw.h | 24 +++++--
drivers/gpu/drm/arm/malidp_mw.c | 2 +-
drivers/gpu/drm/arm/malidp_planes.c | 126 +++++++++++++++++++++++++++++++++++-
6 files changed, 246 insertions(+), 40 deletions(-)

diff --git a/drivers/gpu/drm/arm/malidp_drv.c b/drivers/gpu/drm/arm/malidp_drv.c
index ab50ad0..c697664 100644
--- a/drivers/gpu/drm/arm/malidp_drv.c
+++ b/drivers/gpu/drm/arm/malidp_drv.c
@@ -264,37 +264,17 @@ static bool
malidp_verify_afbc_framebuffer_caps(struct drm_device *dev,
const struct drm_mode_fb_cmd2 *mode_cmd)
{
- const struct drm_format_info *info;
-
- if ((mode_cmd->modifier[0] >> 56) != DRM_FORMAT_MOD_VENDOR_ARM) {
- DRM_DEBUG_KMS("Unknown modifier (not Arm)\n");
+ if (malidp_format_mod_supported(dev, mode_cmd->pixel_format,
+ mode_cmd->modifier[0]) == false)
return false;
- }
-
- if (mode_cmd->modifier[0] &
- ~DRM_FORMAT_MOD_ARM_AFBC(AFBC_MOD_VALID_BITS)) {
- DRM_DEBUG_KMS("Unsupported modifiers\n");
- return false;
- }
-
- info = drm_get_format_info(dev, mode_cmd);
- if (!info) {
- DRM_DEBUG_KMS("Unable to get the format information\n");
- return false;
- }
-
- if (info->num_planes != 1) {
- DRM_DEBUG_KMS("AFBC buffers expect one plane\n");
- return false;
- }

if (mode_cmd->offsets[0] != 0) {
DRM_DEBUG_KMS("AFBC buffers' plane offset should be 0\n");
return false;
}

- switch (mode_cmd->modifier[0] & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) {
- case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16:
+ switch (mode_cmd->modifier[0] & AFBC_SIZE_MASK) {
+ case AFBC_SIZE_16X16:
if ((mode_cmd->width % 16) || (mode_cmd->height % 16)) {
DRM_DEBUG_KMS("AFBC buffers must be aligned to 16 pixels\n");
return false;
@@ -319,8 +299,8 @@ malidp_verify_afbc_framebuffer_size(struct drm_device *dev,
u32 afbc_superblock_size = 0, afbc_superblock_height = 0;
u32 afbc_superblock_width = 0, afbc_size = 0;

- switch (mode_cmd->modifier[0] & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) {
- case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16:
+ switch (mode_cmd->modifier[0] & AFBC_SIZE_MASK) {
+ case AFBC_SIZE_16X16:
afbc_superblock_height = 16;
afbc_superblock_width = 16;
break;
diff --git a/drivers/gpu/drm/arm/malidp_drv.h b/drivers/gpu/drm/arm/malidp_drv.h
index b76c86f..019a682 100644
--- a/drivers/gpu/drm/arm/malidp_drv.h
+++ b/drivers/gpu/drm/arm/malidp_drv.h
@@ -90,6 +90,12 @@ struct malidp_crtc_state {
int malidp_de_planes_init(struct drm_device *drm);
int malidp_crtc_init(struct drm_device *drm);

+bool malidp_hw_format_is_linear_only(u32 format);
+bool malidp_hw_format_is_afbc_only(u32 format);
+
+bool malidp_format_mod_supported(struct drm_device *drm,
+ u32 format, u64 modifier);
+
#ifdef CONFIG_DEBUG_FS
void malidp_error(struct malidp_drm *malidp,
struct malidp_error_stats *error_stats, u32 status,
diff --git a/drivers/gpu/drm/arm/malidp_hw.c b/drivers/gpu/drm/arm/malidp_hw.c
index b4a0e11..0ac2762 100644
--- a/drivers/gpu/drm/arm/malidp_hw.c
+++ b/drivers/gpu/drm/arm/malidp_hw.c
@@ -60,6 +60,8 @@ static const struct malidp_format_id malidp500_de_formats[] = {
#define MALIDP_ID(__group, __format) \
((((__group) & 0x7) << 3) | ((__format) & 0x7))

+#define AFBC_YUV_422_FORMAT_ID MALIDP_ID(5, 1)
+
#define MALIDP_COMMON_FORMATS \
/* fourcc, layers supporting the format, internal id */ \
{ DRM_FORMAT_ARGB2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | SE_MEMWRITE, MALIDP_ID(0, 0) }, \
@@ -162,6 +164,32 @@ static const struct malidp_layer malidp650_layers[] = {
ROTATE_NONE, 0 },
};

+const u64 malidp_format_modifiers[] = {
+ /* All RGB formats (except XRGB, RGBX, XBGR, BGRX) */
+ DRM_FORMAT_MOD_ARM_AFBC(AFBC_SIZE_16X16 | AFBC_YTR | AFBC_SPARSE),
+ DRM_FORMAT_MOD_ARM_AFBC(AFBC_SIZE_16X16 | AFBC_YTR),
+
+ /* All RGB formats > 16bpp (except XRGB, RGBX, XBGR, BGRX) */
+ DRM_FORMAT_MOD_ARM_AFBC(AFBC_SIZE_16X16 | AFBC_YTR | AFBC_SPARSE | AFBC_SPLIT),
+
+ /* All 8 or 10 bit YUV 444 formats. */
+ /* In DP550, 10 bit YUV 420 format also supported */
+ DRM_FORMAT_MOD_ARM_AFBC(AFBC_SIZE_16X16 | AFBC_SPARSE | AFBC_SPLIT),
+
+ /* YUV 420, 422 P1 8 bit and YUV 444 8 bit/10 bit formats */
+ DRM_FORMAT_MOD_ARM_AFBC(AFBC_SIZE_16X16 | AFBC_SPARSE),
+ DRM_FORMAT_MOD_ARM_AFBC(AFBC_SIZE_16X16),
+
+ /* YUV 420, 422 P1 8, 10 bit formats */
+ DRM_FORMAT_MOD_ARM_AFBC(AFBC_SIZE_16X16 | AFBC_CBR | AFBC_SPARSE),
+ DRM_FORMAT_MOD_ARM_AFBC(AFBC_SIZE_16X16 | AFBC_CBR),
+
+ /* All formats */
+ DRM_FORMAT_MOD_LINEAR,
+
+ DRM_FORMAT_MOD_INVALID
+};
+
#define SE_N_SCALING_COEFFS 96
static const u16 dp500_se_scaling_coeffs[][SE_N_SCALING_COEFFS] = {
[MALIDP_UPSCALING_COEFFS - 1] = {
@@ -866,7 +894,10 @@ const struct malidp_hw malidp_device[MALIDP_MAX_DEVICES] = {
.se_base = MALIDP550_SE_BASE,
.dc_base = MALIDP550_DC_BASE,
.out_depth_base = MALIDP550_DE_OUTPUT_DEPTH,
- .features = MALIDP_REGMAP_HAS_CLEARIRQ,
+ .features = MALIDP_REGMAP_HAS_CLEARIRQ |
+ MALIDP_DEVICE_AFBC_SUPPORT_SPLIT |
+ MALIDP_DEVICE_AFBC_YUV_420_10_SUPPORT_SPLIT |
+ MALIDP_DEVICE_AFBC_YUYV_USE_422_P2,
.n_layers = ARRAY_SIZE(malidp550_layers),
.layers = malidp550_layers,
.de_irq_map = {
@@ -912,7 +943,9 @@ const struct malidp_hw malidp_device[MALIDP_MAX_DEVICES] = {
.se_base = MALIDP550_SE_BASE,
.dc_base = MALIDP550_DC_BASE,
.out_depth_base = MALIDP550_DE_OUTPUT_DEPTH,
- .features = MALIDP_REGMAP_HAS_CLEARIRQ,
+ .features = MALIDP_REGMAP_HAS_CLEARIRQ |
+ MALIDP_DEVICE_AFBC_SUPPORT_SPLIT |
+ MALIDP_DEVICE_AFBC_YUYV_USE_422_P2,
.n_layers = ARRAY_SIZE(malidp650_layers),
.layers = malidp650_layers,
.de_irq_map = {
@@ -961,19 +994,72 @@ const struct malidp_hw malidp_device[MALIDP_MAX_DEVICES] = {
};

u8 malidp_hw_get_format_id(const struct malidp_hw_regmap *map,
- u8 layer_id, u32 format)
+ u8 layer_id, u32 format, bool has_modifier)
{
unsigned int i;

for (i = 0; i < map->n_pixel_formats; i++) {
if (((map->pixel_formats[i].layer & layer_id) == layer_id) &&
- (map->pixel_formats[i].format == format))
- return map->pixel_formats[i].id;
+ (map->pixel_formats[i].format == format)) {
+ /*
+ * In some DP550 and DP650, DRM_FORMAT_YUYV + AFBC modifier
+ * is supported by a different h/w format id than
+ * DRM_FORMAT_YUYV (only).
+ */
+ if (format == DRM_FORMAT_YUYV &&
+ (has_modifier) &&
+ (map->features & MALIDP_DEVICE_AFBC_YUYV_USE_422_P2))
+ return AFBC_YUV_422_FORMAT_ID;
+ else
+ return map->pixel_formats[i].id;
+ }
}

return MALIDP_INVALID_FORMAT_ID;
}

+bool malidp_hw_format_is_linear_only(u32 format)
+{
+ switch (format) {
+ case DRM_FORMAT_ARGB2101010:
+ case DRM_FORMAT_RGBA1010102:
+ case DRM_FORMAT_BGRA1010102:
+ case DRM_FORMAT_ARGB8888:
+ case DRM_FORMAT_RGBA8888:
+ case DRM_FORMAT_BGRA8888:
+ case DRM_FORMAT_XBGR8888:
+ case DRM_FORMAT_XRGB8888:
+ case DRM_FORMAT_RGBX8888:
+ case DRM_FORMAT_BGRX8888:
+ case DRM_FORMAT_RGB888:
+ case DRM_FORMAT_RGB565:
+ case DRM_FORMAT_ARGB1555:
+ case DRM_FORMAT_RGBA5551:
+ case DRM_FORMAT_BGRA5551:
+ case DRM_FORMAT_UYVY:
+ case DRM_FORMAT_XYUV8888:
+ case DRM_FORMAT_XVYU2101010:
+ case DRM_FORMAT_X0L2:
+ case DRM_FORMAT_X0L0:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool malidp_hw_format_is_afbc_only(u32 format)
+{
+ switch (format) {
+ case DRM_FORMAT_VUY888:
+ case DRM_FORMAT_VUY101010:
+ case DRM_FORMAT_YUV420_8BIT:
+ case DRM_FORMAT_YUV420_10BIT:
+ return true;
+ default:
+ return false;
+ }
+}
+
static void malidp_hw_clear_irq(struct malidp_hw_device *hwdev, u8 block, u32 irq)
{
u32 base = malidp_get_block_base(hwdev, block);
diff --git a/drivers/gpu/drm/arm/malidp_hw.h b/drivers/gpu/drm/arm/malidp_hw.h
index 651558f..0859302 100644
--- a/drivers/gpu/drm/arm/malidp_hw.h
+++ b/drivers/gpu/drm/arm/malidp_hw.h
@@ -95,7 +95,10 @@ struct malidp_se_config {
};

/* regmap features */
-#define MALIDP_REGMAP_HAS_CLEARIRQ (1 << 0)
+#define MALIDP_REGMAP_HAS_CLEARIRQ BIT(0)
+#define MALIDP_DEVICE_AFBC_SUPPORT_SPLIT BIT(1)
+#define MALIDP_DEVICE_AFBC_YUV_420_10_SUPPORT_SPLIT BIT(2)
+#define MALIDP_DEVICE_AFBC_YUYV_USE_422_P2 BIT(3)

struct malidp_hw_regmap {
/* address offset of the DE register bank */
@@ -321,7 +324,7 @@ int malidp_se_irq_init(struct drm_device *drm, int irq);
void malidp_se_irq_fini(struct malidp_hw_device *hwdev);

u8 malidp_hw_get_format_id(const struct malidp_hw_regmap *map,
- u8 layer_id, u32 format);
+ u8 layer_id, u32 format, bool has_modifier);

static inline u8 malidp_hw_get_pitch_align(struct malidp_hw_device *hwdev, bool rotated)
{
@@ -390,9 +393,18 @@ static inline void malidp_se_set_enh_coeffs(struct malidp_hw_device *hwdev)

#define MALIDP_GAMMA_LUT_SIZE 4096

-#define AFBC_MOD_VALID_BITS (AFBC_FORMAT_MOD_BLOCK_SIZE_MASK | \
- AFBC_FORMAT_MOD_YTR | AFBC_FORMAT_MOD_SPLIT | \
- AFBC_FORMAT_MOD_SPARSE | AFBC_FORMAT_MOD_CBR | \
- AFBC_FORMAT_MOD_TILED | AFBC_FORMAT_MOD_SC)
+#define AFBC_SIZE_MASK AFBC_FORMAT_MOD_BLOCK_SIZE_MASK
+#define AFBC_SIZE_16X16 AFBC_FORMAT_MOD_BLOCK_SIZE_16x16
+#define AFBC_YTR AFBC_FORMAT_MOD_YTR
+#define AFBC_SPARSE AFBC_FORMAT_MOD_SPARSE
+#define AFBC_CBR AFBC_FORMAT_MOD_CBR
+#define AFBC_SPLIT AFBC_FORMAT_MOD_SPLIT
+#define AFBC_TILED AFBC_FORMAT_MOD_TILED
+#define AFBC_SC AFBC_FORMAT_MOD_SC
+
+#define AFBC_MOD_VALID_BITS (AFBC_SIZE_MASK | AFBC_YTR | AFBC_SPLIT | \
+ AFBC_SPARSE | AFBC_CBR | AFBC_TILED | AFBC_SC)
+
+extern const u64 malidp_format_modifiers[];

#endif /* __MALIDP_HW_H__ */
diff --git a/drivers/gpu/drm/arm/malidp_mw.c b/drivers/gpu/drm/arm/malidp_mw.c
index 041a64d..28cd351 100644
--- a/drivers/gpu/drm/arm/malidp_mw.c
+++ b/drivers/gpu/drm/arm/malidp_mw.c
@@ -143,7 +143,7 @@ malidp_mw_encoder_atomic_check(struct drm_encoder *encoder,

mw_state->format =
malidp_hw_get_format_id(&malidp->dev->hw->map, SE_MEMWRITE,
- fb->format->format);
+ fb->format->format, !!fb->modifier);
if (mw_state->format == MALIDP_INVALID_FORMAT_ID) {
struct drm_format_name_buf format_name;

diff --git a/drivers/gpu/drm/arm/malidp_planes.c b/drivers/gpu/drm/arm/malidp_planes.c
index 181957c..79e00bf 100644
--- a/drivers/gpu/drm/arm/malidp_planes.c
+++ b/drivers/gpu/drm/arm/malidp_planes.c
@@ -52,6 +52,8 @@
#define MALIDP550_LS_ENABLE 0x01c
#define MALIDP550_LS_R1_IN_SIZE 0x020

+#define MODIFIERS_COUNT_MAX 15
+
/*
* This 4-entry look-up-table is used to determine the full 8-bit alpha value
* for formats with 1- or 2-bit alpha channels.
@@ -145,6 +147,119 @@ static void malidp_plane_atomic_print_state(struct drm_printer *p,
drm_printf(p, "\tmmu_prefetch_pgsize=%d\n", ms->mmu_prefetch_pgsize);
}

+bool malidp_format_mod_supported(struct drm_device *drm,
+ u32 format, u64 modifier)
+{
+ const struct drm_format_info *info;
+ const u64 *modifiers;
+ struct malidp_drm *malidp = drm->dev_private;
+ const struct malidp_hw_regmap *map = &malidp->dev->hw->map;
+
+ if (WARN_ON(modifier == DRM_FORMAT_MOD_INVALID))
+ return false;
+
+ /* Some pixel formats are supported without any modifier */
+ if (modifier == DRM_FORMAT_MOD_LINEAR) {
+ /*
+ * However these pixel formats need to be supported with
+ * modifiers only
+ */
+ return !malidp_hw_format_is_afbc_only(format);
+ }
+
+ if ((modifier >> 56) != DRM_FORMAT_MOD_VENDOR_ARM) {
+ DRM_ERROR("Unknown modifier (not Arm)\n");
+ return false;
+ }
+
+ if (modifier &
+ ~DRM_FORMAT_MOD_ARM_AFBC(AFBC_MOD_VALID_BITS)) {
+ DRM_DEBUG_KMS("Unsupported modifiers\n");
+ return false;
+ }
+
+ modifiers = malidp_format_modifiers;
+
+ /* SPLIT buffers must use SPARSE layout */
+ if (WARN_ON_ONCE((modifier & AFBC_SPLIT) && !(modifier & AFBC_SPARSE)))
+ return false;
+
+ /* CBR only applies to YUV formats, where YTR should be always 0 */
+ if (WARN_ON_ONCE((modifier & AFBC_CBR) && (modifier & AFBC_YTR)))
+ return false;
+
+ while (*modifiers != DRM_FORMAT_MOD_INVALID) {
+ if (*modifiers == modifier)
+ break;
+
+ modifiers++;
+ }
+
+ /* return false, if the modifier was not found */
+ if (*modifiers == DRM_FORMAT_MOD_INVALID) {
+ DRM_DEBUG_KMS("Unsupported modifier\n");
+ return false;
+ }
+
+ info = drm_format_info(format);
+
+ if (info->num_planes != 1) {
+ DRM_DEBUG_KMS("AFBC buffers expect one plane\n");
+ return false;
+ }
+
+ if (malidp_hw_format_is_linear_only(format) == true) {
+ DRM_DEBUG_KMS("Given format (0x%x) is supported is linear mode only\n",
+ format);
+ return false;
+ }
+
+ /*
+ * RGB formats need to provide YTR modifier and YUV formats should not
+ * provide YTR modifier.
+ */
+ if (!(info->is_yuv) != !!(modifier & AFBC_FORMAT_MOD_YTR)) {
+ DRM_DEBUG_KMS("AFBC_FORMAT_MOD_YTR is %s for %s formats\n",
+ info->is_yuv ? "disallowed" : "mandatory",
+ info->is_yuv ? "YUV" : "RGB");
+ return false;
+ }
+
+ if (modifier & AFBC_SPLIT) {
+ if (!info->is_yuv) {
+ if (drm_format_plane_cpp(format, 0) <= 2) {
+ DRM_DEBUG_KMS("RGB formats <= 16bpp are not supported with SPLIT\n");
+ return false;
+ }
+ }
+
+ if ((drm_format_horz_chroma_subsampling(format) != 1) ||
+ (drm_format_vert_chroma_subsampling(format) != 1)) {
+ if (!(format == DRM_FORMAT_YUV420_10BIT &&
+ (map->features & MALIDP_DEVICE_AFBC_YUV_420_10_SUPPORT_SPLIT))) {
+ DRM_DEBUG_KMS("Formats which are sub-sampled should never be split\n");
+ return false;
+ }
+ }
+ }
+
+ if (modifier & AFBC_CBR) {
+ if ((drm_format_horz_chroma_subsampling(format) == 1) ||
+ (drm_format_vert_chroma_subsampling(format) == 1)) {
+ DRM_DEBUG_KMS("Formats which are not sub-sampled should not have CBR set\n");
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static bool malidp_format_mod_supported_per_plane(struct drm_plane *plane,
+ u32 format, u64 modifier)
+{
+ return malidp_format_mod_supported(plane->dev, format, modifier);
+}
+
static const struct drm_plane_funcs malidp_de_plane_funcs = {
.update_plane = drm_atomic_helper_update_plane,
.disable_plane = drm_atomic_helper_disable_plane,
@@ -153,6 +268,7 @@ static const struct drm_plane_funcs malidp_de_plane_funcs = {
.atomic_duplicate_state = malidp_duplicate_plane_state,
.atomic_destroy_state = malidp_destroy_plane_state,
.atomic_print_state = malidp_plane_atomic_print_state,
+ .format_mod_supported = malidp_format_mod_supported_per_plane,
};

static int malidp_se_check_scaling(struct malidp_plane *mp,
@@ -406,8 +522,8 @@ static int malidp_de_plane_check(struct drm_plane *plane,
fb = state->fb;

ms->format = malidp_hw_get_format_id(&mp->hwdev->hw->map,
- mp->layer->id,
- fb->format->format);
+ mp->layer->id, fb->format->format,
+ !!fb->modifier);
if (ms->format == MALIDP_INVALID_FORMAT_ID)
return -EINVAL;

@@ -469,6 +585,12 @@ static int malidp_de_plane_check(struct drm_plane *plane,
return -EINVAL;
}

+ /* SMART layer does not support AFBC */
+ if (mp->layer->id == DE_SMART && fb->modifier) {
+ DRM_ERROR("AFBC framebuffer not supported in SMART layer");
+ return -EINVAL;
+ }
+
ms->rotmem_size = 0;
if (state->rotation & MALIDP_ROTATED_MASK) {
int val;
--
2.7.4


2019-02-26 16:22:40

by Ayan Halder

[permalink] [raw]
Subject: [PATCH 04/10] drm/arm/malidp:- Added support for new YUV formats for DP500, DP550 and DP650

From: Ayan Kumar Halder <[email protected]>

We have added support for some AFBC only pixel formats like :-
DRM_FORMAT_YUV420_8BIT (single plane YUV 420 8 bit format)
DRM_FORMAT_VUY888 (single plane YUV 444 8 bit format)
DRM_FORMAT_VUY101010 (single plane YUV 444 10 bit format)
DRM_FORMAT_YUV420_10BIT (single plane YUV 420 10 bit format)

Generally, these formats are supported by our hardware using the same
hw-ids as the equivalent multi plane pixel formats.

Also we have added support for XYUV 444 8 and 10 bit formats

Signed-off-by: Ayan Kumar Halder <[email protected]>
Reviewed-by: Liviu Dudau <[email protected]>
---
drivers/gpu/drm/arm/malidp_hw.c | 22 +++++++++++++++++++++-
1 file changed, 21 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/arm/malidp_hw.c b/drivers/gpu/drm/arm/malidp_hw.c
index 64c2ca3..b4a0e11 100644
--- a/drivers/gpu/drm/arm/malidp_hw.c
+++ b/drivers/gpu/drm/arm/malidp_hw.c
@@ -49,6 +49,12 @@ static const struct malidp_format_id malidp500_de_formats[] = {
{ DRM_FORMAT_YUYV, DE_VIDEO1, 13 },
{ DRM_FORMAT_NV12, DE_VIDEO1 | SE_MEMWRITE, 14 },
{ DRM_FORMAT_YUV420, DE_VIDEO1, 15 },
+ { DRM_FORMAT_XYUV8888, DE_VIDEO1, 16 },
+ /* These are supported with AFBC only */
+ { DRM_FORMAT_YUV420_8BIT, DE_VIDEO1, 14 },
+ { DRM_FORMAT_VUY888, DE_VIDEO1, 16 },
+ { DRM_FORMAT_VUY101010, DE_VIDEO1, 17 },
+ { DRM_FORMAT_YUV420_10BIT, DE_VIDEO1, 18 }
};

#define MALIDP_ID(__group, __format) \
@@ -74,11 +80,25 @@ static const struct malidp_format_id malidp500_de_formats[] = {
{ DRM_FORMAT_ABGR1555, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 1) }, \
{ DRM_FORMAT_RGB565, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 2) }, \
{ DRM_FORMAT_BGR565, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 3) }, \
+ /* This is only supported with linear modifier */ \
+ { DRM_FORMAT_XYUV8888, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 0) },\
+ /* This is only supported with AFBC modifier */ \
+ { DRM_FORMAT_VUY888, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 0) }, \
{ DRM_FORMAT_YUYV, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 2) }, \
+ /* This is only supported with linear modifier */ \
{ DRM_FORMAT_UYVY, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 3) }, \
{ DRM_FORMAT_NV12, DE_VIDEO1 | DE_VIDEO2 | SE_MEMWRITE, MALIDP_ID(5, 6) }, \
+ /* This is only supported with AFBC modifier */ \
+ { DRM_FORMAT_YUV420_8BIT, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 6) }, \
{ DRM_FORMAT_YUV420, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 7) }, \
- { DRM_FORMAT_X0L2, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(6, 6)}
+ /* This is only supported with linear modifier */ \
+ { DRM_FORMAT_XVYU2101010, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(6, 0)}, \
+ /* This is only supported with AFBC modifier */ \
+ { DRM_FORMAT_VUY101010, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(6, 0)}, \
+ { DRM_FORMAT_X0L2, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(6, 6)}, \
+ /* This is only supported with AFBC modifier */ \
+ { DRM_FORMAT_YUV420_10BIT, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(6, 7)}, \
+ { DRM_FORMAT_P010, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(6, 7)}

static const struct malidp_format_id malidp550_de_formats[] = {
MALIDP_COMMON_FORMATS,
--
2.7.4


2019-02-26 16:23:01

by Ayan Halder

[permalink] [raw]
Subject: [PATCH 02/10] drm: Added a new format DRM_FORMAT_XVYU2101010

From: Ayan Kumar Halder <[email protected]>

This new format is supported by DP550 and DP650

Signed-off-by: Ayan Kumar halder <[email protected]>
Reviewed-by: Liviu Dudau <[email protected]>
---
drivers/gpu/drm/drm_fourcc.c | 1 +
include/uapi/drm/drm_fourcc.h | 1 +
2 files changed, 2 insertions(+)

diff --git a/drivers/gpu/drm/drm_fourcc.c b/drivers/gpu/drm/drm_fourcc.c
index 0a3efa5..8681f01 100644
--- a/drivers/gpu/drm/drm_fourcc.c
+++ b/drivers/gpu/drm/drm_fourcc.c
@@ -229,6 +229,7 @@ const struct drm_format_info *__drm_format_info(u32 format)
{ .format = DRM_FORMAT_VUY888, .depth = 0, .num_planes = 1, .cpp = { 3, 0, 0 }, .hsub = 1, .vsub = 1, .is_yuv = true },
{ .format = DRM_FORMAT_Y410, .depth = 0, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true, .is_yuv = true },
{ .format = DRM_FORMAT_AYUV, .depth = 0, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true, .is_yuv = true },
+ { .format = DRM_FORMAT_XVYU2101010, .depth = 0, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .is_yuv = true },
{ .format = DRM_FORMAT_Y0L0, .depth = 0, .num_planes = 1,
.char_per_block = { 8, 0, 0 }, .block_w = { 2, 0, 0 }, .block_h = { 2, 0, 0 },
.hsub = 2, .vsub = 2, .has_alpha = true, .is_yuv = true },
diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h
index b4fb674..5fed518 100644
--- a/include/uapi/drm/drm_fourcc.h
+++ b/include/uapi/drm/drm_fourcc.h
@@ -153,6 +153,7 @@ extern "C" {

#define DRM_FORMAT_AYUV fourcc_code('A', 'Y', 'U', 'V') /* [31:0] A:Y:Cb:Cr 8:8:8:8 little endian */
#define DRM_FORMAT_XYUV8888 fourcc_code('X', 'Y', 'U', 'V') /* [31:0] X:Y:Cb:Cr 8:8:8:8 little endian */
+#define DRM_FORMAT_XVYU2101010 fourcc_code('X', 'V', '3', '0') /* [31:0] X:Cr:Y:Cb 2:10:10:10 little endian */
#define DRM_FORMAT_VUY888 fourcc_code('V', 'U', '2', '4') /* [23:0] Cr:Cb:Y 8:8:8 little endian */
#define DRM_FORMAT_Y410 fourcc_code('Y', '4', '1', '0') /* [31:0] A:Cr:Y:Cb 2:10:10:10 little endian */
#define DRM_FORMAT_VUY101010 fourcc_code('V', 'U', '3', '0') /* Y followed by U then V, 10:10:10. Non-linear modifier only */
--
2.7.4


2019-02-26 16:23:06

by Ayan Halder

[permalink] [raw]
Subject: [PATCH v3 01/10] drm/fourcc: Add AFBC yuv fourccs for Mali

From: Brian Starkey <[email protected]>

As we look to enable AFBC using DRM format modifiers, we run into
problems which we've historically handled via vendor-private details
(i.e. gralloc, on Android).

AFBC (as an encoding) is fully flexible, and for example YUV data can
be encoded into 1, 2 or 3 encoded "planes", much like the linear
equivalents. Component order is also meaningful, as AFBC doesn't
necessarily care about what each "channel" of the data it encodes
contains. Therefore ABGR8888 and RGBA8888 can be encoded in AFBC with
different representations. Similarly, 'X' components may be encoded
into AFBC streams in cases where a decoder expects to decode a 4th
component.

In addition, AFBC is a licensable IP, meaning that to support the
ecosystem we need to ensure that _all_ AFBC users are able to describe
the encodings that they need. This is much better achieved by
preserving meaning in the fourcc codes when they are combined with an
AFBC modifier.

In essence, we want to use the modifier to describe the parameters of
the AFBC encode/decode, and use the fourcc code to describe the data
being encoded/decoded.

To do anything different would be to introduce redundancy - we would
need to duplicate in the modifier information which is _already_
conveyed clearly and non-ambigiously by a fourcc code.

I hope that for RGB this is non-controversial.
(BGRA8888 + MODIFIER_AFBC) is a different format from
(RGBA8888 + MODIFIER_AFBC).

Possibly more controversial is that (XBGR8888 + MODIFIER_AFBC)
is different from (BGR888 + MODIFIER_AFBC). I understand that in some
schemes it is not the case - but in AFBC it is so.

Where we run into problems is where there are not already fourcc codes
which represent the data which the AFBC encoder/decoder is processing.
To that end, we want to introduce new fourcc codes to describe the
data being encoded/decoded, in the places where none of the existing
fourcc codes are applicable.

Where we don't support an equivalent non-compressed layout, or where
no "obvious" linear layout exists, we are proposing adding fourcc
codes which have no associated linear layout - because any layout we
proposed would be completely arbitrary.

Some formats are following the naming conventions from [2].

The summary of the new formats is:
DRM_FORMAT_VUY888 - Packed 8-bit YUV 444. Y followed by U then V.
DRM_FORMAT_VUY101010 - Packed 10-bit YUV 444. Y followed by U then
V. No defined linear encoding.
DRM_FORMAT_Y210 - Packed 10-bit YUV 422. Y followed by U (then Y)
then V. 10-bit samples in 16-bit words.
DRM_FORMAT_Y410 - Packed 10-bit YUV 444, with 2-bit alpha.
DRM_FORMAT_P210 - Semi-planar 10-bit YUV 422. Y plane, followed by
interleaved U-then-V plane. 10-bit samples in
16-bit words.
DRM_FORMAT_YUV420_8BIT - Packed 8-bit YUV 420. Y followed by U then
V. No defined linear encoding
DRM_FORMAT_YUV420_10BIT - Packed 10-bit YUV 420. Y followed by U
then V. No defined linear encoding

Please also note that in the absence of AFBC, we would still need to
add Y410, Y210 and P210.

Full rationale follows:

YUV 444 8-bit, 1-plane
----------------------
The currently defined AYUV format encodes a 4th alpha component,
which makes it unsuitable for representing a 3-component YUV 444
AFBC stream.

The proposed[1] XYUV format which is supported by Mali-DP in linear
layout is also unsuitable, because the component order is the
opposite of the AFBC version, and it encodes a 4th 'X' component.

DRM_FORMAT_VUY888 is the "obvious" format for a 3-component, packed,
YUV 444 8-bit format, with the component order which our HW expects to
encode/decode. It conforms to the same naming convention as the
existing packed YUV 444 format.
The naming here is meant to be consistent with DRM_FORMAT_AYUV and
DRM_FORMAT_XYUV[1]

YUV 444 10-bit, 1-plane
-----------------------
There is no currently-defined YUV 444 10-bit format in
drm_fourcc.h, irrespective of number of planes.

The proposed[1] XVYU2101010 format which is supported by Mali-DP in
linear layout uses the wrong component order, and also encodes a 4th
'X' component, which doesn't match the AFBC version of YUV 444
10-bit which we support.

DRM_FORMAT_Y410 is the same layout as XVYU2101010, but with 2 bits of
alpha. This format is supported with linear layout by Mali GPUs. The
naming follows[2].

There is no "obvious" linear encoding for a 3-component 10:10:10
packed format, and so DRM_FORMAT_VUY101010 defines a component
order, but not a bit encoding. Again, the naming is meant to be
consistent with DRM_FORMAT_AYUV.

YUV 422 8-bit, 1-plane
----------------------
The existing DRM_FORMAT_YUYV (and the other component orders) are
single-planar YUV 422 8-bit formats. Following the convention of
the component orders of the RGB formats, YUYV has the correct
component order for our AFBC encoding (Y followed by U followed by
V). We can use YUYV for AFBC YUV 422 8-bit.

YUV 422 10-bit, 1-plane
-----------------------
There is no currently-defined YUV 422 10-bit format in drm_fourcc.h

DRM_FORMAT_Y210 is analogous to YUYV, but with 10-bits per sample
packed into the upper 10-bits of 16-bit samples. This format is
supported in both linear and AFBC by Mali GPUs.

YUV 422 10-bit, 2-plane
-----------------------
The recently defined DRM_FORMAT_P010 format is a 10-bit semi-planar
YUV 420 format, which has the correct component ordering for an AFBC
2-plane YUV 420 buffer. The linear layout contains meaningless padding
bits, which will not be encoded in an AFBC stream.

YUV 420 8-bit, 1-plane
----------------------
There is no currently defined single-planar YUV 420, 8-bit format
in drm_fourcc.h. There's differing opinions on whether using the
existing fourcc-implied n_planes where possible is a good idea or
not when using modifiers.

For me, it's much more "obvious" to use NV12 for 2-plane AFBC and
YUV420 for 3-plane AFBC. This keeps the aforementioned separation
between the AFBC codec settings (in the modifier) and the pixel data
format (in the fourcc). With different vendors using AFBC, this helps
to ensure that there is no confusion in interoperation. It also
ensures that the AFBC modifiers describe AFBC itself (which is a
licensable component), and not implementation details which are not
defined by AFBC.

The proposed[1] X0L0 format which Mali-DP supports with Linear layout
is unsuitable, as it contains a 4th 'X' component, and our AFBC
decoder expects only 3 components.

To that end, we propose a new YUV 420 8-bit format. There is no
"obvious" linear encoding for a 3-component 8:8:8, 420, packed format,
and so DRM_FORMAT_YUV420_8BIT defines a component order, but not a
bit encoding. I'm happy to hear different naming suggestions.

YUV 420 8-bit, 2-, 3-plane
--------------------------
These already exist, we can use NV12 and YUV420.

YUV 420 10-bit, 1-plane
-----------------------
As above, no current definition exists, and X0L2 encodes a 4th 'X'
channel.

Analogous to DRM_FORMAT_YUV420_8BIT, we define DRM_FORMAT_YUV420_10BIT.

[1] https://lists.freedesktop.org/archives/dri-devel/2018-July/184598.html
[2] https://docs.microsoft.com/en-us/windows/desktop/medfound/10-bit-and-16-bit-yuv-video-formats

Changes since RFC v1:
- Fix confusing subsampling vs bit-depth X:X:X notation in
descriptions (danvet)
- Rename DRM_FORMAT_AVYU1101010 to DRM_FORMAT_Y410 (Lisa Wu)
- Add drm_format_info structures for the new formats, using the
new 'bpp' field for those with non-integer bytes-per-pixel
- Rebase, including Juha-Pekka Heikkila's format definitions

Changes since RFC v2:
- Rebase on top of latest changes in drm-misc-next
- Change the description of DRM_FORMAT_P210 in __drm_format_info and
drm_fourcc.h so as to make it consistent with other DRM_FORMAT_PXXX
formats.

Signed-off-by: Brian Starkey <[email protected]>
Signed-off-by: Ayan Kumar Halder <[email protected]>
Reviewed-by: Liviu Dudau <[email protected]>
---
drivers/gpu/drm/drm_fourcc.c | 16 ++++++++++++++++
include/uapi/drm/drm_fourcc.h | 22 +++++++++++++++++++++-
2 files changed, 37 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/drm_fourcc.c b/drivers/gpu/drm/drm_fourcc.c
index ba7e19d..0a3efa5 100644
--- a/drivers/gpu/drm/drm_fourcc.c
+++ b/drivers/gpu/drm/drm_fourcc.c
@@ -225,6 +225,9 @@ const struct drm_format_info *__drm_format_info(u32 format)
{ .format = DRM_FORMAT_UYVY, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 2, .vsub = 1, .is_yuv = true },
{ .format = DRM_FORMAT_VYUY, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 2, .vsub = 1, .is_yuv = true },
{ .format = DRM_FORMAT_XYUV8888, .depth = 0, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .is_yuv = true },
+ { .format = DRM_FORMAT_Y210, .depth = 0, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 2, .vsub = 1, .is_yuv = true },
+ { .format = DRM_FORMAT_VUY888, .depth = 0, .num_planes = 1, .cpp = { 3, 0, 0 }, .hsub = 1, .vsub = 1, .is_yuv = true },
+ { .format = DRM_FORMAT_Y410, .depth = 0, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true, .is_yuv = true },
{ .format = DRM_FORMAT_AYUV, .depth = 0, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true, .is_yuv = true },
{ .format = DRM_FORMAT_Y0L0, .depth = 0, .num_planes = 1,
.char_per_block = { 8, 0, 0 }, .block_w = { 2, 0, 0 }, .block_h = { 2, 0, 0 },
@@ -247,6 +250,19 @@ const struct drm_format_info *__drm_format_info(u32 format)
{ .format = DRM_FORMAT_P016, .depth = 0, .num_planes = 2,
.char_per_block = { 2, 4, 0 }, .block_w = { 1, 0, 0 }, .block_h = { 1, 0, 0 },
.hsub = 2, .vsub = 2, .is_yuv = true},
+ { .format = DRM_FORMAT_P210, .depth = 0,
+ .num_planes = 2, .char_per_block = { 2, 4, 0 },
+ .block_w = { 1, 0, 0 }, .block_h = { 1, 0, 0 }, .hsub = 2,
+ .vsub = 1, .is_yuv = true },
+ { .format = DRM_FORMAT_VUY101010, .depth = 0,
+ .num_planes = 1, .cpp = { 0, 0, 0 }, .hsub = 1, .vsub = 1,
+ .is_yuv = true },
+ { .format = DRM_FORMAT_YUV420_8BIT, .depth = 0,
+ .num_planes = 1, .cpp = { 0, 0, 0 }, .hsub = 2, .vsub = 2,
+ .is_yuv = true },
+ { .format = DRM_FORMAT_YUV420_10BIT, .depth = 0,
+ .num_planes = 1, .cpp = { 0, 0, 0 }, .hsub = 2, .vsub = 2,
+ .is_yuv = true },
};

unsigned int i;
diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h
index bab2029..b4fb674 100644
--- a/include/uapi/drm/drm_fourcc.h
+++ b/include/uapi/drm/drm_fourcc.h
@@ -149,9 +149,13 @@ extern "C" {
#define DRM_FORMAT_YVYU fourcc_code('Y', 'V', 'Y', 'U') /* [31:0] Cb0:Y1:Cr0:Y0 8:8:8:8 little endian */
#define DRM_FORMAT_UYVY fourcc_code('U', 'Y', 'V', 'Y') /* [31:0] Y1:Cr0:Y0:Cb0 8:8:8:8 little endian */
#define DRM_FORMAT_VYUY fourcc_code('V', 'Y', 'U', 'Y') /* [31:0] Y1:Cb0:Y0:Cr0 8:8:8:8 little endian */
+#define DRM_FORMAT_Y210 fourcc_code('Y', '2', '1', '0') /* [63:0] Cr0:0:Y1:0:Cb0:0:Y0:0 10:6:10:6:10:6:10:6 little endian */

#define DRM_FORMAT_AYUV fourcc_code('A', 'Y', 'U', 'V') /* [31:0] A:Y:Cb:Cr 8:8:8:8 little endian */
-#define DRM_FORMAT_XYUV8888 fourcc_code('X', 'Y', 'U', 'V') /* [31:0] X:Y:Cb:Cr 8:8:8:8 little endian */
+#define DRM_FORMAT_XYUV8888 fourcc_code('X', 'Y', 'U', 'V') /* [31:0] X:Y:Cb:Cr 8:8:8:8 little endian */
+#define DRM_FORMAT_VUY888 fourcc_code('V', 'U', '2', '4') /* [23:0] Cr:Cb:Y 8:8:8 little endian */
+#define DRM_FORMAT_Y410 fourcc_code('Y', '4', '1', '0') /* [31:0] A:Cr:Y:Cb 2:10:10:10 little endian */
+#define DRM_FORMAT_VUY101010 fourcc_code('V', 'U', '3', '0') /* Y followed by U then V, 10:10:10. Non-linear modifier only */

/*
* packed YCbCr420 2x2 tiled formats
@@ -168,6 +172,15 @@ extern "C" {
#define DRM_FORMAT_X0L2 fourcc_code('X', '0', 'L', '2')

/*
+ * 1-plane YUV 4:2:0
+ * In these formats, the component ordering is specified (Y, followed by U
+ * then V), but the exact Linear layout is undefined.
+ * These formats can only be used with a non-Linear modifier.
+ */
+#define DRM_FORMAT_YUV420_8BIT fourcc_code('Y', 'U', '0', '8')
+#define DRM_FORMAT_YUV420_10BIT fourcc_code('Y', 'U', '1', '0')
+
+/*
* 2 plane RGB + A
* index 0 = RGB plane, same format as the corresponding non _A8 format has
* index 1 = A plane, [7:0] A
@@ -200,6 +213,13 @@ extern "C" {
* index 0 = Y plane, [15:0] Y:x [10:6] little endian
* index 1 = Cr:Cb plane, [31:0] Cr:x:Cb:x [10:6:10:6] little endian
*/
+#define DRM_FORMAT_P210 fourcc_code('P', '2', '1', '0') /* 2x1 subsampled Cr:Cb plane, 10 bit per channel */
+
+/*
+ * 2 plane YCbCr MSB aligned
+ * index 0 = Y plane, [15:0] Y:x [10:6] little endian
+ * index 1 = Cr:Cb plane, [31:0] Cr:x:Cb:x [10:6:10:6] little endian
+ */
#define DRM_FORMAT_P010 fourcc_code('P', '0', '1', '0') /* 2x2 subsampled Cr:Cb plane 10 bits per channel */

/*
--
2.7.4


2019-02-26 16:23:19

by Ayan Halder

[permalink] [raw]
Subject: [PATCH v3 10/10] drm/arm/malidp: Added support for AFBC modifiers for all layers except DE_SMART

From: Ayan Kumar Halder <[email protected]>

The list of modifiers to be supported for each plane has been dynamically generated
from 'malidp_format_modifiers[]' and 'malidp_hw_regmap->features'.

Changes from v1:-
1. Replaced DRM_ERROR() with DRM_DEBUG_KMS() in malidp_format_mod_supported()
to report unsupported modifiers.

Changes from v2:-
1. Removed malidp_format_mod_supported() from the current patch. This has been added
in "PATCH 7/12"
2. Dynamically generate the list of modifiers (to be supported for each plane) from
'malidp_format_modifiers' and features.

Signed-off-by: Ayan Kumar halder <[email protected]>
Reviewed-by: Liviu Dudau <[email protected]>
---
drivers/gpu/drm/arm/malidp_drv.c | 1 +
drivers/gpu/drm/arm/malidp_planes.c | 31 ++++++++++++++++++++++++++++---
2 files changed, 29 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/arm/malidp_drv.c b/drivers/gpu/drm/arm/malidp_drv.c
index 4106f5d..21725c9 100644
--- a/drivers/gpu/drm/arm/malidp_drv.c
+++ b/drivers/gpu/drm/arm/malidp_drv.c
@@ -391,6 +391,7 @@ static int malidp_init(struct drm_device *drm)
drm->mode_config.max_height = hwdev->max_line_size;
drm->mode_config.funcs = &malidp_mode_config_funcs;
drm->mode_config.helper_private = &malidp_mode_config_helpers;
+ drm->mode_config.allow_fb_modifiers = true;

ret = malidp_crtc_init(drm);
if (ret)
diff --git a/drivers/gpu/drm/arm/malidp_planes.c b/drivers/gpu/drm/arm/malidp_planes.c
index 044bf7f..d42e0ea 100644
--- a/drivers/gpu/drm/arm/malidp_planes.c
+++ b/drivers/gpu/drm/arm/malidp_planes.c
@@ -939,7 +939,26 @@ int malidp_de_planes_init(struct drm_device *drm)
BIT(DRM_MODE_BLEND_PREMULTI) |
BIT(DRM_MODE_BLEND_COVERAGE);
u32 *formats;
- int ret, i, j, n;
+ int ret, i = 0, j = 0, n;
+ u64 supported_modifiers[MODIFIERS_COUNT_MAX];
+ const u64 *modifiers;
+
+ modifiers = malidp_format_modifiers;
+
+ if (!(map->features & MALIDP_DEVICE_AFBC_SUPPORT_SPLIT)) {
+ /*
+ * Since our hardware does not support SPLIT, so build the list
+ * of supported modifiers excluding SPLIT ones.
+ */
+ while (*modifiers != DRM_FORMAT_MOD_INVALID) {
+ if (!(*modifiers & AFBC_SPLIT))
+ supported_modifiers[j++] = *modifiers;
+
+ modifiers++;
+ }
+ supported_modifiers[j++] = DRM_FORMAT_MOD_INVALID;
+ modifiers = supported_modifiers;
+ }

formats = kcalloc(map->n_pixel_formats, sizeof(*formats), GFP_KERNEL);
if (!formats) {
@@ -964,9 +983,15 @@ int malidp_de_planes_init(struct drm_device *drm)

plane_type = (i == 0) ? DRM_PLANE_TYPE_PRIMARY :
DRM_PLANE_TYPE_OVERLAY;
+
+ /*
+ * All the layers except smart layer supports AFBC modifiers.
+ */
ret = drm_universal_plane_init(drm, &plane->base, crtcs,
- &malidp_de_plane_funcs, formats,
- n, NULL, plane_type, NULL);
+ &malidp_de_plane_funcs, formats, n,
+ (id == DE_SMART) ? NULL : modifiers, plane_type,
+ NULL);
+
if (ret < 0)
goto cleanup;

--
2.7.4


2019-02-26 16:24:09

by Ayan Halder

[permalink] [raw]
Subject: [PATCH v4 03/10] drm/arm/malidp: Set the AFBC register bits if the framebuffer has AFBC modifier

From: Ayan Kumar Halder <[email protected]>

Added the AFBC decoder registers for DP500 , DP550 and DP650.
These registers control the processing of AFBC buffers. It controls various
features like AFBC decoder enable, lossless transformation and block split
as well as setting of the left, right, top and bottom cropping of AFBC
buffers (in number of pixels).
All the layers (except DE_SMART) support framebuffers with AFBC modifiers.
One needs to set the pixel values of the top, left, bottom and right
cropping for the AFBC framebuffer.
Cropping an AFBC framebuffer is controlled by the AFBC crop registers.
In that case, the layer input size registers should be configured with
framebuffer's dimensions and not with drm_plane_state source width/height
values (which is used for non AFBC framebuffer to denote cropping).

Changes from v1:
- Removed the "if (fb->modifier)" check from malidp_de_plane_update()
and added it in malidp_de_set_plane_afbc(). This will consolidate all the
AFBC specific register configurations in a single function ie
malidp_de_set_plane_afbc().

Changes from v2:
- For AFBC framebuffer, layer input size register should be set to
framebuffer's width and height.

Changes from v3:
- Rebased on top of latest drm-misc-next
- Some cleanups/sanity changes based on Liviu's comments

Signed-off-by: Ayan Kumar Halder <[email protected]>
---
drivers/gpu/drm/arm/malidp_hw.c | 30 ++++++----
drivers/gpu/drm/arm/malidp_hw.h | 2 +
drivers/gpu/drm/arm/malidp_planes.c | 107 ++++++++++++++++++++++++++++++++----
drivers/gpu/drm/arm/malidp_regs.h | 20 +++++++
4 files changed, 136 insertions(+), 23 deletions(-)

diff --git a/drivers/gpu/drm/arm/malidp_hw.c b/drivers/gpu/drm/arm/malidp_hw.c
index b9bed11..64c2ca3 100644
--- a/drivers/gpu/drm/arm/malidp_hw.c
+++ b/drivers/gpu/drm/arm/malidp_hw.c
@@ -94,11 +94,14 @@ static const struct malidp_layer malidp500_layers[] = {
* yuv2rgb matrix offset, mmu control register offset, rotation_features
*/
{ DE_VIDEO1, MALIDP500_DE_LV_BASE, MALIDP500_DE_LV_PTR_BASE,
- MALIDP_DE_LV_STRIDE0, MALIDP500_LV_YUV2RGB, 0, ROTATE_ANY },
+ MALIDP_DE_LV_STRIDE0, MALIDP500_LV_YUV2RGB, 0, ROTATE_ANY,
+ MALIDP500_DE_LV_AD_CTRL },
{ DE_GRAPHICS1, MALIDP500_DE_LG1_BASE, MALIDP500_DE_LG1_PTR_BASE,
- MALIDP_DE_LG_STRIDE, 0, 0, ROTATE_ANY },
+ MALIDP_DE_LG_STRIDE, 0, 0, ROTATE_ANY,
+ MALIDP500_DE_LG1_AD_CTRL },
{ DE_GRAPHICS2, MALIDP500_DE_LG2_BASE, MALIDP500_DE_LG2_PTR_BASE,
- MALIDP_DE_LG_STRIDE, 0, 0, ROTATE_ANY },
+ MALIDP_DE_LG_STRIDE, 0, 0, ROTATE_ANY,
+ MALIDP500_DE_LG2_AD_CTRL },
};

static const struct malidp_layer malidp550_layers[] = {
@@ -106,13 +109,16 @@ static const struct malidp_layer malidp550_layers[] = {
* yuv2rgb matrix offset, mmu control register offset, rotation_features
*/
{ DE_VIDEO1, MALIDP550_DE_LV1_BASE, MALIDP550_DE_LV1_PTR_BASE,
- MALIDP_DE_LV_STRIDE0, MALIDP550_LV_YUV2RGB, 0, ROTATE_ANY },
+ MALIDP_DE_LV_STRIDE0, MALIDP550_LV_YUV2RGB, 0, ROTATE_ANY,
+ MALIDP550_DE_LV1_AD_CTRL },
{ DE_GRAPHICS1, MALIDP550_DE_LG_BASE, MALIDP550_DE_LG_PTR_BASE,
- MALIDP_DE_LG_STRIDE, 0, 0, ROTATE_ANY },
+ MALIDP_DE_LG_STRIDE, 0, 0, ROTATE_ANY,
+ MALIDP550_DE_LG_AD_CTRL },
{ DE_VIDEO2, MALIDP550_DE_LV2_BASE, MALIDP550_DE_LV2_PTR_BASE,
- MALIDP_DE_LV_STRIDE0, MALIDP550_LV_YUV2RGB, 0, ROTATE_ANY },
+ MALIDP_DE_LV_STRIDE0, MALIDP550_LV_YUV2RGB, 0, ROTATE_ANY,
+ MALIDP550_DE_LV2_AD_CTRL },
{ DE_SMART, MALIDP550_DE_LS_BASE, MALIDP550_DE_LS_PTR_BASE,
- MALIDP550_DE_LS_R1_STRIDE, 0, 0, ROTATE_NONE },
+ MALIDP550_DE_LS_R1_STRIDE, 0, 0, ROTATE_NONE, 0 },
};

static const struct malidp_layer malidp650_layers[] = {
@@ -122,16 +128,18 @@ static const struct malidp_layer malidp650_layers[] = {
*/
{ DE_VIDEO1, MALIDP550_DE_LV1_BASE, MALIDP550_DE_LV1_PTR_BASE,
MALIDP_DE_LV_STRIDE0, MALIDP550_LV_YUV2RGB,
- MALIDP650_DE_LV_MMU_CTRL, ROTATE_ANY },
+ MALIDP650_DE_LV_MMU_CTRL, ROTATE_ANY,
+ MALIDP550_DE_LV1_AD_CTRL },
{ DE_GRAPHICS1, MALIDP550_DE_LG_BASE, MALIDP550_DE_LG_PTR_BASE,
MALIDP_DE_LG_STRIDE, 0, MALIDP650_DE_LG_MMU_CTRL,
- ROTATE_COMPRESSED },
+ ROTATE_COMPRESSED, MALIDP550_DE_LG_AD_CTRL },
{ DE_VIDEO2, MALIDP550_DE_LV2_BASE, MALIDP550_DE_LV2_PTR_BASE,
MALIDP_DE_LV_STRIDE0, MALIDP550_LV_YUV2RGB,
- MALIDP650_DE_LV_MMU_CTRL, ROTATE_ANY },
+ MALIDP650_DE_LV_MMU_CTRL, ROTATE_ANY,
+ MALIDP550_DE_LV2_AD_CTRL },
{ DE_SMART, MALIDP550_DE_LS_BASE, MALIDP550_DE_LS_PTR_BASE,
MALIDP550_DE_LS_R1_STRIDE, 0, MALIDP650_DE_LS_MMU_CTRL,
- ROTATE_NONE },
+ ROTATE_NONE, 0 },
};

#define SE_N_SCALING_COEFFS 96
diff --git a/drivers/gpu/drm/arm/malidp_hw.h b/drivers/gpu/drm/arm/malidp_hw.h
index 40155e2..651558f 100644
--- a/drivers/gpu/drm/arm/malidp_hw.h
+++ b/drivers/gpu/drm/arm/malidp_hw.h
@@ -70,6 +70,8 @@ struct malidp_layer {
s16 yuv2rgb_offset; /* offset to the YUV->RGB matrix entries */
u16 mmu_ctrl_offset; /* offset to the MMU control register */
enum rotation_features rot; /* type of rotation supported */
+ /* address offset for the AFBC decoder registers */
+ u16 afbc_decoder_offset;
};

enum malidp_scaling_coeff_set {
diff --git a/drivers/gpu/drm/arm/malidp_planes.c b/drivers/gpu/drm/arm/malidp_planes.c
index c9a6d3e..181957c 100644
--- a/drivers/gpu/drm/arm/malidp_planes.c
+++ b/drivers/gpu/drm/arm/malidp_planes.c
@@ -592,6 +592,83 @@ static void malidp_de_set_mmu_control(struct malidp_plane *mp,
mp->layer->base + mp->layer->mmu_ctrl_offset);
}

+static void malidp_set_plane_base_addr(struct drm_framebuffer *fb,
+ struct malidp_plane *mp,
+ int plane_index)
+{
+ dma_addr_t paddr;
+ u16 ptr;
+ struct drm_plane *plane = &mp->base;
+ bool afbc = fb->modifier ? true : false;
+
+ ptr = mp->layer->ptr + (plane_index << 4);
+
+ /*
+ * drm_fb_cma_get_gem_addr() alters the physical base address of the
+ * framebuffer as per the plane's src_x, src_y co-ordinates (ie to
+ * take care of source cropping).
+ * For AFBC, this is not needed as the cropping is handled by _AD_CROP_H
+ * and _AD_CROP_V registers.
+ */
+ if (!afbc) {
+ paddr = drm_fb_cma_get_gem_addr(fb, plane->state,
+ plane_index);
+ } else {
+ struct drm_gem_cma_object *obj;
+
+ obj = drm_fb_cma_get_gem_obj(fb, plane_index);
+
+ if (WARN_ON(!obj))
+ return;
+ paddr = obj->paddr;
+ }
+
+ malidp_hw_write(mp->hwdev, lower_32_bits(paddr), ptr);
+ malidp_hw_write(mp->hwdev, upper_32_bits(paddr), ptr + 4);
+}
+
+static void malidp_de_set_plane_afbc(struct drm_plane *plane)
+{
+ struct malidp_plane *mp;
+ u32 src_w, src_h, val = 0, src_x, src_y;
+ struct drm_framebuffer *fb = plane->state->fb;
+
+ mp = to_malidp_plane(plane);
+
+ /* no afbc_decoder_offset means AFBC is not supported on this plane */
+ if (!mp->layer->afbc_decoder_offset)
+ return;
+
+ if (!fb->modifier) {
+ malidp_hw_write(mp->hwdev, 0, mp->layer->afbc_decoder_offset);
+ return;
+ }
+
+ /* convert src values from Q16 fixed point to integer */
+ src_w = plane->state->src_w >> 16;
+ src_h = plane->state->src_h >> 16;
+ src_x = plane->state->src_x >> 16;
+ src_y = plane->state->src_y >> 16;
+
+ val = ((fb->width - (src_x + src_w)) << MALIDP_AD_CROP_RIGHT_OFFSET) |
+ src_x;
+ malidp_hw_write(mp->hwdev, val,
+ mp->layer->afbc_decoder_offset + MALIDP_AD_CROP_H);
+
+ val = ((fb->height - (src_y + src_h)) << MALIDP_AD_CROP_BOTTOM_OFFSET) |
+ src_y;
+ malidp_hw_write(mp->hwdev, val,
+ mp->layer->afbc_decoder_offset + MALIDP_AD_CROP_V);
+
+ val = MALIDP_AD_EN;
+ if (fb->modifier & AFBC_FORMAT_MOD_SPLIT)
+ val |= MALIDP_AD_BS;
+ if (fb->modifier & AFBC_FORMAT_MOD_YTR)
+ val |= MALIDP_AD_YTR;
+
+ malidp_hw_write(mp->hwdev, val, mp->layer->afbc_decoder_offset);
+}
+
static void malidp_de_plane_update(struct drm_plane *plane,
struct drm_plane_state *old_state)
{
@@ -602,12 +679,23 @@ static void malidp_de_plane_update(struct drm_plane *plane,
u8 plane_alpha = state->alpha >> 8;
u32 src_w, src_h, dest_w, dest_h, val;
int i;
+ struct drm_framebuffer *fb = plane->state->fb;

mp = to_malidp_plane(plane);

- /* convert src values from Q16 fixed point to integer */
- src_w = state->src_w >> 16;
- src_h = state->src_h >> 16;
+ /*
+ * For AFBC framebuffer, use the framebuffer width and height for
+ * configuring layer input size register.
+ */
+ if (fb->modifier) {
+ src_w = fb->width;
+ src_h = fb->height;
+ } else {
+ /* convert src values from Q16 fixed point to integer */
+ src_w = state->src_w >> 16;
+ src_h = state->src_h >> 16;
+ }
+
dest_w = state->crtc_w;
dest_h = state->crtc_h;

@@ -615,15 +703,8 @@ static void malidp_de_plane_update(struct drm_plane *plane,
val = (val & ~LAYER_FORMAT_MASK) | ms->format;
malidp_hw_write(mp->hwdev, val, mp->layer->base);

- for (i = 0; i < ms->n_planes; i++) {
- /* calculate the offset for the layer's plane registers */
- u16 ptr = mp->layer->ptr + (i << 4);
- dma_addr_t fb_addr = drm_fb_cma_get_gem_addr(state->fb,
- state, i);
-
- malidp_hw_write(mp->hwdev, lower_32_bits(fb_addr), ptr);
- malidp_hw_write(mp->hwdev, upper_32_bits(fb_addr), ptr + 4);
- }
+ for (i = 0; i < ms->n_planes; i++)
+ malidp_set_plane_base_addr(fb, mp, i);

malidp_de_set_mmu_control(mp, ms);

@@ -657,6 +738,8 @@ static void malidp_de_plane_update(struct drm_plane *plane,
mp->layer->base + MALIDP550_LS_R1_IN_SIZE);
}

+ malidp_de_set_plane_afbc(plane);
+
/* first clear the rotation bits */
val = malidp_hw_read(mp->hwdev, mp->layer->base + MALIDP_LAYER_CONTROL);
val &= ~LAYER_ROT_MASK;
diff --git a/drivers/gpu/drm/arm/malidp_regs.h b/drivers/gpu/drm/arm/malidp_regs.h
index 7ce3e14..a0dd6e1 100644
--- a/drivers/gpu/drm/arm/malidp_regs.h
+++ b/drivers/gpu/drm/arm/malidp_regs.h
@@ -198,10 +198,13 @@
#define MALIDP500_LV_YUV2RGB ((s16)(-0xB8))
#define MALIDP500_DE_LV_BASE 0x00100
#define MALIDP500_DE_LV_PTR_BASE 0x00124
+#define MALIDP500_DE_LV_AD_CTRL 0x00400
#define MALIDP500_DE_LG1_BASE 0x00200
#define MALIDP500_DE_LG1_PTR_BASE 0x0021c
+#define MALIDP500_DE_LG1_AD_CTRL 0x0040c
#define MALIDP500_DE_LG2_BASE 0x00300
#define MALIDP500_DE_LG2_PTR_BASE 0x0031c
+#define MALIDP500_DE_LG2_AD_CTRL 0x00418
#define MALIDP500_SE_BASE 0x00c00
#define MALIDP500_SE_CONTROL 0x00c0c
#define MALIDP500_SE_MEMWRITE_OUT_SIZE 0x00c2c
@@ -228,10 +231,13 @@
#define MALIDP550_LV_YUV2RGB 0x00084
#define MALIDP550_DE_LV1_BASE 0x00100
#define MALIDP550_DE_LV1_PTR_BASE 0x00124
+#define MALIDP550_DE_LV1_AD_CTRL 0x001B8
#define MALIDP550_DE_LV2_BASE 0x00200
#define MALIDP550_DE_LV2_PTR_BASE 0x00224
+#define MALIDP550_DE_LV2_AD_CTRL 0x002B8
#define MALIDP550_DE_LG_BASE 0x00300
#define MALIDP550_DE_LG_PTR_BASE 0x0031c
+#define MALIDP550_DE_LG_AD_CTRL 0x00330
#define MALIDP550_DE_LS_BASE 0x00400
#define MALIDP550_DE_LS_PTR_BASE 0x0042c
#define MALIDP550_DE_PERF_BASE 0x00500
@@ -258,6 +264,20 @@
#define MALIDP_MMU_CTRL_PX_PS(x) (1 << (8 + (x)))
#define MALIDP_MMU_CTRL_PP_NUM_REQ(x) (((x) & 0x7f) << 12)

+/* AFBC register offsets relative to MALIDPXXX_DE_LX_AD_CTRL */
+/* The following register offsets are common for DP500, DP550 and DP650 */
+#define MALIDP_AD_CROP_H 0x4
+#define MALIDP_AD_CROP_V 0x8
+#define MALIDP_AD_END_PTR_LOW 0xc
+#define MALIDP_AD_END_PTR_HIGH 0x10
+
+/* AFBC decoder Registers */
+#define MALIDP_AD_EN BIT(0)
+#define MALIDP_AD_YTR BIT(4)
+#define MALIDP_AD_BS BIT(8)
+#define MALIDP_AD_CROP_RIGHT_OFFSET 16
+#define MALIDP_AD_CROP_BOTTOM_OFFSET 16
+
/*
* Starting with DP550 the register map blocks has been standardised to the
* following layout:
--
2.7.4


2019-03-01 18:08:15

by Liviu Dudau

[permalink] [raw]
Subject: Re: [PATCH v4 03/10] drm/arm/malidp: Set the AFBC register bits if the framebuffer has AFBC modifier

On Tue, Feb 26, 2019 at 04:20:54PM +0000, Ayan Halder wrote:
> From: Ayan Kumar Halder <[email protected]>
>
> Added the AFBC decoder registers for DP500 , DP550 and DP650.
> These registers control the processing of AFBC buffers. It controls various
> features like AFBC decoder enable, lossless transformation and block split
> as well as setting of the left, right, top and bottom cropping of AFBC
> buffers (in number of pixels).
> All the layers (except DE_SMART) support framebuffers with AFBC modifiers.
> One needs to set the pixel values of the top, left, bottom and right
> cropping for the AFBC framebuffer.
> Cropping an AFBC framebuffer is controlled by the AFBC crop registers.
> In that case, the layer input size registers should be configured with
> framebuffer's dimensions and not with drm_plane_state source width/height
> values (which is used for non AFBC framebuffer to denote cropping).
>
> Changes from v1:
> - Removed the "if (fb->modifier)" check from malidp_de_plane_update()
> and added it in malidp_de_set_plane_afbc(). This will consolidate all the
> AFBC specific register configurations in a single function ie
> malidp_de_set_plane_afbc().
>
> Changes from v2:
> - For AFBC framebuffer, layer input size register should be set to
> framebuffer's width and height.
>
> Changes from v3:
> - Rebased on top of latest drm-misc-next
> - Some cleanups/sanity changes based on Liviu's comments
>
> Signed-off-by: Ayan Kumar Halder <[email protected]>

Reviewed-by: Liviu Dudau <[email protected]>

Best regards,
Liviu

> ---
> drivers/gpu/drm/arm/malidp_hw.c | 30 ++++++----
> drivers/gpu/drm/arm/malidp_hw.h | 2 +
> drivers/gpu/drm/arm/malidp_planes.c | 107 ++++++++++++++++++++++++++++++++----
> drivers/gpu/drm/arm/malidp_regs.h | 20 +++++++
> 4 files changed, 136 insertions(+), 23 deletions(-)
>
> diff --git a/drivers/gpu/drm/arm/malidp_hw.c b/drivers/gpu/drm/arm/malidp_hw.c
> index b9bed11..64c2ca3 100644
> --- a/drivers/gpu/drm/arm/malidp_hw.c
> +++ b/drivers/gpu/drm/arm/malidp_hw.c
> @@ -94,11 +94,14 @@ static const struct malidp_layer malidp500_layers[] = {
> * yuv2rgb matrix offset, mmu control register offset, rotation_features
> */
> { DE_VIDEO1, MALIDP500_DE_LV_BASE, MALIDP500_DE_LV_PTR_BASE,
> - MALIDP_DE_LV_STRIDE0, MALIDP500_LV_YUV2RGB, 0, ROTATE_ANY },
> + MALIDP_DE_LV_STRIDE0, MALIDP500_LV_YUV2RGB, 0, ROTATE_ANY,
> + MALIDP500_DE_LV_AD_CTRL },
> { DE_GRAPHICS1, MALIDP500_DE_LG1_BASE, MALIDP500_DE_LG1_PTR_BASE,
> - MALIDP_DE_LG_STRIDE, 0, 0, ROTATE_ANY },
> + MALIDP_DE_LG_STRIDE, 0, 0, ROTATE_ANY,
> + MALIDP500_DE_LG1_AD_CTRL },
> { DE_GRAPHICS2, MALIDP500_DE_LG2_BASE, MALIDP500_DE_LG2_PTR_BASE,
> - MALIDP_DE_LG_STRIDE, 0, 0, ROTATE_ANY },
> + MALIDP_DE_LG_STRIDE, 0, 0, ROTATE_ANY,
> + MALIDP500_DE_LG2_AD_CTRL },
> };
>
> static const struct malidp_layer malidp550_layers[] = {
> @@ -106,13 +109,16 @@ static const struct malidp_layer malidp550_layers[] = {
> * yuv2rgb matrix offset, mmu control register offset, rotation_features
> */
> { DE_VIDEO1, MALIDP550_DE_LV1_BASE, MALIDP550_DE_LV1_PTR_BASE,
> - MALIDP_DE_LV_STRIDE0, MALIDP550_LV_YUV2RGB, 0, ROTATE_ANY },
> + MALIDP_DE_LV_STRIDE0, MALIDP550_LV_YUV2RGB, 0, ROTATE_ANY,
> + MALIDP550_DE_LV1_AD_CTRL },
> { DE_GRAPHICS1, MALIDP550_DE_LG_BASE, MALIDP550_DE_LG_PTR_BASE,
> - MALIDP_DE_LG_STRIDE, 0, 0, ROTATE_ANY },
> + MALIDP_DE_LG_STRIDE, 0, 0, ROTATE_ANY,
> + MALIDP550_DE_LG_AD_CTRL },
> { DE_VIDEO2, MALIDP550_DE_LV2_BASE, MALIDP550_DE_LV2_PTR_BASE,
> - MALIDP_DE_LV_STRIDE0, MALIDP550_LV_YUV2RGB, 0, ROTATE_ANY },
> + MALIDP_DE_LV_STRIDE0, MALIDP550_LV_YUV2RGB, 0, ROTATE_ANY,
> + MALIDP550_DE_LV2_AD_CTRL },
> { DE_SMART, MALIDP550_DE_LS_BASE, MALIDP550_DE_LS_PTR_BASE,
> - MALIDP550_DE_LS_R1_STRIDE, 0, 0, ROTATE_NONE },
> + MALIDP550_DE_LS_R1_STRIDE, 0, 0, ROTATE_NONE, 0 },
> };
>
> static const struct malidp_layer malidp650_layers[] = {
> @@ -122,16 +128,18 @@ static const struct malidp_layer malidp650_layers[] = {
> */
> { DE_VIDEO1, MALIDP550_DE_LV1_BASE, MALIDP550_DE_LV1_PTR_BASE,
> MALIDP_DE_LV_STRIDE0, MALIDP550_LV_YUV2RGB,
> - MALIDP650_DE_LV_MMU_CTRL, ROTATE_ANY },
> + MALIDP650_DE_LV_MMU_CTRL, ROTATE_ANY,
> + MALIDP550_DE_LV1_AD_CTRL },
> { DE_GRAPHICS1, MALIDP550_DE_LG_BASE, MALIDP550_DE_LG_PTR_BASE,
> MALIDP_DE_LG_STRIDE, 0, MALIDP650_DE_LG_MMU_CTRL,
> - ROTATE_COMPRESSED },
> + ROTATE_COMPRESSED, MALIDP550_DE_LG_AD_CTRL },
> { DE_VIDEO2, MALIDP550_DE_LV2_BASE, MALIDP550_DE_LV2_PTR_BASE,
> MALIDP_DE_LV_STRIDE0, MALIDP550_LV_YUV2RGB,
> - MALIDP650_DE_LV_MMU_CTRL, ROTATE_ANY },
> + MALIDP650_DE_LV_MMU_CTRL, ROTATE_ANY,
> + MALIDP550_DE_LV2_AD_CTRL },
> { DE_SMART, MALIDP550_DE_LS_BASE, MALIDP550_DE_LS_PTR_BASE,
> MALIDP550_DE_LS_R1_STRIDE, 0, MALIDP650_DE_LS_MMU_CTRL,
> - ROTATE_NONE },
> + ROTATE_NONE, 0 },
> };
>
> #define SE_N_SCALING_COEFFS 96
> diff --git a/drivers/gpu/drm/arm/malidp_hw.h b/drivers/gpu/drm/arm/malidp_hw.h
> index 40155e2..651558f 100644
> --- a/drivers/gpu/drm/arm/malidp_hw.h
> +++ b/drivers/gpu/drm/arm/malidp_hw.h
> @@ -70,6 +70,8 @@ struct malidp_layer {
> s16 yuv2rgb_offset; /* offset to the YUV->RGB matrix entries */
> u16 mmu_ctrl_offset; /* offset to the MMU control register */
> enum rotation_features rot; /* type of rotation supported */
> + /* address offset for the AFBC decoder registers */
> + u16 afbc_decoder_offset;
> };
>
> enum malidp_scaling_coeff_set {
> diff --git a/drivers/gpu/drm/arm/malidp_planes.c b/drivers/gpu/drm/arm/malidp_planes.c
> index c9a6d3e..181957c 100644
> --- a/drivers/gpu/drm/arm/malidp_planes.c
> +++ b/drivers/gpu/drm/arm/malidp_planes.c
> @@ -592,6 +592,83 @@ static void malidp_de_set_mmu_control(struct malidp_plane *mp,
> mp->layer->base + mp->layer->mmu_ctrl_offset);
> }
>
> +static void malidp_set_plane_base_addr(struct drm_framebuffer *fb,
> + struct malidp_plane *mp,
> + int plane_index)
> +{
> + dma_addr_t paddr;
> + u16 ptr;
> + struct drm_plane *plane = &mp->base;
> + bool afbc = fb->modifier ? true : false;
> +
> + ptr = mp->layer->ptr + (plane_index << 4);
> +
> + /*
> + * drm_fb_cma_get_gem_addr() alters the physical base address of the
> + * framebuffer as per the plane's src_x, src_y co-ordinates (ie to
> + * take care of source cropping).
> + * For AFBC, this is not needed as the cropping is handled by _AD_CROP_H
> + * and _AD_CROP_V registers.
> + */
> + if (!afbc) {
> + paddr = drm_fb_cma_get_gem_addr(fb, plane->state,
> + plane_index);
> + } else {
> + struct drm_gem_cma_object *obj;
> +
> + obj = drm_fb_cma_get_gem_obj(fb, plane_index);
> +
> + if (WARN_ON(!obj))
> + return;
> + paddr = obj->paddr;
> + }
> +
> + malidp_hw_write(mp->hwdev, lower_32_bits(paddr), ptr);
> + malidp_hw_write(mp->hwdev, upper_32_bits(paddr), ptr + 4);
> +}
> +
> +static void malidp_de_set_plane_afbc(struct drm_plane *plane)
> +{
> + struct malidp_plane *mp;
> + u32 src_w, src_h, val = 0, src_x, src_y;
> + struct drm_framebuffer *fb = plane->state->fb;
> +
> + mp = to_malidp_plane(plane);
> +
> + /* no afbc_decoder_offset means AFBC is not supported on this plane */
> + if (!mp->layer->afbc_decoder_offset)
> + return;
> +
> + if (!fb->modifier) {
> + malidp_hw_write(mp->hwdev, 0, mp->layer->afbc_decoder_offset);
> + return;
> + }
> +
> + /* convert src values from Q16 fixed point to integer */
> + src_w = plane->state->src_w >> 16;
> + src_h = plane->state->src_h >> 16;
> + src_x = plane->state->src_x >> 16;
> + src_y = plane->state->src_y >> 16;
> +
> + val = ((fb->width - (src_x + src_w)) << MALIDP_AD_CROP_RIGHT_OFFSET) |
> + src_x;
> + malidp_hw_write(mp->hwdev, val,
> + mp->layer->afbc_decoder_offset + MALIDP_AD_CROP_H);
> +
> + val = ((fb->height - (src_y + src_h)) << MALIDP_AD_CROP_BOTTOM_OFFSET) |
> + src_y;
> + malidp_hw_write(mp->hwdev, val,
> + mp->layer->afbc_decoder_offset + MALIDP_AD_CROP_V);
> +
> + val = MALIDP_AD_EN;
> + if (fb->modifier & AFBC_FORMAT_MOD_SPLIT)
> + val |= MALIDP_AD_BS;
> + if (fb->modifier & AFBC_FORMAT_MOD_YTR)
> + val |= MALIDP_AD_YTR;
> +
> + malidp_hw_write(mp->hwdev, val, mp->layer->afbc_decoder_offset);
> +}
> +
> static void malidp_de_plane_update(struct drm_plane *plane,
> struct drm_plane_state *old_state)
> {
> @@ -602,12 +679,23 @@ static void malidp_de_plane_update(struct drm_plane *plane,
> u8 plane_alpha = state->alpha >> 8;
> u32 src_w, src_h, dest_w, dest_h, val;
> int i;
> + struct drm_framebuffer *fb = plane->state->fb;
>
> mp = to_malidp_plane(plane);
>
> - /* convert src values from Q16 fixed point to integer */
> - src_w = state->src_w >> 16;
> - src_h = state->src_h >> 16;
> + /*
> + * For AFBC framebuffer, use the framebuffer width and height for
> + * configuring layer input size register.
> + */
> + if (fb->modifier) {
> + src_w = fb->width;
> + src_h = fb->height;
> + } else {
> + /* convert src values from Q16 fixed point to integer */
> + src_w = state->src_w >> 16;
> + src_h = state->src_h >> 16;
> + }
> +
> dest_w = state->crtc_w;
> dest_h = state->crtc_h;
>
> @@ -615,15 +703,8 @@ static void malidp_de_plane_update(struct drm_plane *plane,
> val = (val & ~LAYER_FORMAT_MASK) | ms->format;
> malidp_hw_write(mp->hwdev, val, mp->layer->base);
>
> - for (i = 0; i < ms->n_planes; i++) {
> - /* calculate the offset for the layer's plane registers */
> - u16 ptr = mp->layer->ptr + (i << 4);
> - dma_addr_t fb_addr = drm_fb_cma_get_gem_addr(state->fb,
> - state, i);
> -
> - malidp_hw_write(mp->hwdev, lower_32_bits(fb_addr), ptr);
> - malidp_hw_write(mp->hwdev, upper_32_bits(fb_addr), ptr + 4);
> - }
> + for (i = 0; i < ms->n_planes; i++)
> + malidp_set_plane_base_addr(fb, mp, i);
>
> malidp_de_set_mmu_control(mp, ms);
>
> @@ -657,6 +738,8 @@ static void malidp_de_plane_update(struct drm_plane *plane,
> mp->layer->base + MALIDP550_LS_R1_IN_SIZE);
> }
>
> + malidp_de_set_plane_afbc(plane);
> +
> /* first clear the rotation bits */
> val = malidp_hw_read(mp->hwdev, mp->layer->base + MALIDP_LAYER_CONTROL);
> val &= ~LAYER_ROT_MASK;
> diff --git a/drivers/gpu/drm/arm/malidp_regs.h b/drivers/gpu/drm/arm/malidp_regs.h
> index 7ce3e14..a0dd6e1 100644
> --- a/drivers/gpu/drm/arm/malidp_regs.h
> +++ b/drivers/gpu/drm/arm/malidp_regs.h
> @@ -198,10 +198,13 @@
> #define MALIDP500_LV_YUV2RGB ((s16)(-0xB8))
> #define MALIDP500_DE_LV_BASE 0x00100
> #define MALIDP500_DE_LV_PTR_BASE 0x00124
> +#define MALIDP500_DE_LV_AD_CTRL 0x00400
> #define MALIDP500_DE_LG1_BASE 0x00200
> #define MALIDP500_DE_LG1_PTR_BASE 0x0021c
> +#define MALIDP500_DE_LG1_AD_CTRL 0x0040c
> #define MALIDP500_DE_LG2_BASE 0x00300
> #define MALIDP500_DE_LG2_PTR_BASE 0x0031c
> +#define MALIDP500_DE_LG2_AD_CTRL 0x00418
> #define MALIDP500_SE_BASE 0x00c00
> #define MALIDP500_SE_CONTROL 0x00c0c
> #define MALIDP500_SE_MEMWRITE_OUT_SIZE 0x00c2c
> @@ -228,10 +231,13 @@
> #define MALIDP550_LV_YUV2RGB 0x00084
> #define MALIDP550_DE_LV1_BASE 0x00100
> #define MALIDP550_DE_LV1_PTR_BASE 0x00124
> +#define MALIDP550_DE_LV1_AD_CTRL 0x001B8
> #define MALIDP550_DE_LV2_BASE 0x00200
> #define MALIDP550_DE_LV2_PTR_BASE 0x00224
> +#define MALIDP550_DE_LV2_AD_CTRL 0x002B8
> #define MALIDP550_DE_LG_BASE 0x00300
> #define MALIDP550_DE_LG_PTR_BASE 0x0031c
> +#define MALIDP550_DE_LG_AD_CTRL 0x00330
> #define MALIDP550_DE_LS_BASE 0x00400
> #define MALIDP550_DE_LS_PTR_BASE 0x0042c
> #define MALIDP550_DE_PERF_BASE 0x00500
> @@ -258,6 +264,20 @@
> #define MALIDP_MMU_CTRL_PX_PS(x) (1 << (8 + (x)))
> #define MALIDP_MMU_CTRL_PP_NUM_REQ(x) (((x) & 0x7f) << 12)
>
> +/* AFBC register offsets relative to MALIDPXXX_DE_LX_AD_CTRL */
> +/* The following register offsets are common for DP500, DP550 and DP650 */
> +#define MALIDP_AD_CROP_H 0x4
> +#define MALIDP_AD_CROP_V 0x8
> +#define MALIDP_AD_END_PTR_LOW 0xc
> +#define MALIDP_AD_END_PTR_HIGH 0x10
> +
> +/* AFBC decoder Registers */
> +#define MALIDP_AD_EN BIT(0)
> +#define MALIDP_AD_YTR BIT(4)
> +#define MALIDP_AD_BS BIT(8)
> +#define MALIDP_AD_CROP_RIGHT_OFFSET 16
> +#define MALIDP_AD_CROP_BOTTOM_OFFSET 16
> +
> /*
> * Starting with DP550 the register map blocks has been standardised to the
> * following layout:
> --
> 2.7.4
>

--
====================
| I would like to |
| fix the world, |
| but they're not |
| giving me the |
\ source code! /
---------------
¯\_(ツ)_/¯

2019-03-01 18:14:49

by Liviu Dudau

[permalink] [raw]
Subject: Re: [PATCH v2 05/10] drm/arm/malidp:- Define a common list of AFBC format modifiers supported for DP500, DP550 and DP650

On Tue, Feb 26, 2019 at 04:20:56PM +0000, Ayan Halder wrote:
> From: Ayan Kumar Halder <[email protected]>
>
> We need to define a common list of format modifiers supported by each of
> the Mali display processors.
>
> The following are the constraints with AFBC:-
>
> 1. AFBC is not supported for the formats defined in
> malidp_hw_format_is_linear_only()
>
> 2. Some of the formats are supported only with AFBC modifiers. Thus we have
> introduced a new function 'malidp_hw_format_is_afbc_only()' which verifies
> the same.
>
> 3. AFBC_FORMAT_MOD_YTR needs to be provided for any RGB format.
>
> 4. Formats <= 16bpp cannot support AFBC_FORMAT_MOD_SPLIT.
>
> 5. CBR should not be set for non-subsampled formats.
>
> 6. SMART layer does not support framebuffer with AFBC modifiers.
> Return -EINVAL for such a scenario.
>
> 7. AFBC_FORMAT_MOD_YTR is not supported for any YUV formats.
>
> 8. Formats which are subsampled cannot support AFBC_FORMAT_MOD_SPLIT.
> However in DP550, YUV_420_10BIT is supported with AFBC_FORMAT_MOD_SPLIT.
> This feature has been identified with
> MALIDP_DEVICE_AFBC_YUV_420_10_SUPPORT_SPLIT.
>
> 9. In DP550 and DP650, for YUYV, the hardware supports different
> format-ids to be used with and without AFBC modifier. We have used the
> feature 'MALIDP_DEVICE_AFBC_YUYV_USE_422_P2' to identify this
> characteristic.
>
> 10. DP500 does not support split mode (ie AFBC_FORMAT_MOD_SPLIT). We have
> used the feature 'MALIDP_DEVICE_AFBC_SUPPORT_SPLIT' to identify the DPs
> which support SPLIT mode.
>
> 11. DP550 supports YUV420 with split mode. We have defined the feature
> 'AFBC_SUPPORT_SPLIT_WITH_YUV_420_10' to identify this characteristic.
>
> Changes since v1:-
> - Merged https://patchwork.freedesktop.org/patch/265215/ into this patch
> - As Liviu pointed out in the last patch, we can pull the checks outside
> of the 'while (*modifiers != DRM_FORMAT_MOD_INVALID)' loop
> - Rebased
>
> Signed-off-by: Ayan Kumar halder <[email protected]>

Reviewed-by: Liviu Dudau <[email protected]>

Best regards,
Liviu

> ---
> drivers/gpu/drm/arm/malidp_drv.c | 32 ++-------
> drivers/gpu/drm/arm/malidp_drv.h | 6 ++
> drivers/gpu/drm/arm/malidp_hw.c | 96 +++++++++++++++++++++++++--
> drivers/gpu/drm/arm/malidp_hw.h | 24 +++++--
> drivers/gpu/drm/arm/malidp_mw.c | 2 +-
> drivers/gpu/drm/arm/malidp_planes.c | 126 +++++++++++++++++++++++++++++++++++-
> 6 files changed, 246 insertions(+), 40 deletions(-)
>
> diff --git a/drivers/gpu/drm/arm/malidp_drv.c b/drivers/gpu/drm/arm/malidp_drv.c
> index ab50ad0..c697664 100644
> --- a/drivers/gpu/drm/arm/malidp_drv.c
> +++ b/drivers/gpu/drm/arm/malidp_drv.c
> @@ -264,37 +264,17 @@ static bool
> malidp_verify_afbc_framebuffer_caps(struct drm_device *dev,
> const struct drm_mode_fb_cmd2 *mode_cmd)
> {
> - const struct drm_format_info *info;
> -
> - if ((mode_cmd->modifier[0] >> 56) != DRM_FORMAT_MOD_VENDOR_ARM) {
> - DRM_DEBUG_KMS("Unknown modifier (not Arm)\n");
> + if (malidp_format_mod_supported(dev, mode_cmd->pixel_format,
> + mode_cmd->modifier[0]) == false)
> return false;
> - }
> -
> - if (mode_cmd->modifier[0] &
> - ~DRM_FORMAT_MOD_ARM_AFBC(AFBC_MOD_VALID_BITS)) {
> - DRM_DEBUG_KMS("Unsupported modifiers\n");
> - return false;
> - }
> -
> - info = drm_get_format_info(dev, mode_cmd);
> - if (!info) {
> - DRM_DEBUG_KMS("Unable to get the format information\n");
> - return false;
> - }
> -
> - if (info->num_planes != 1) {
> - DRM_DEBUG_KMS("AFBC buffers expect one plane\n");
> - return false;
> - }
>
> if (mode_cmd->offsets[0] != 0) {
> DRM_DEBUG_KMS("AFBC buffers' plane offset should be 0\n");
> return false;
> }
>
> - switch (mode_cmd->modifier[0] & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) {
> - case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16:
> + switch (mode_cmd->modifier[0] & AFBC_SIZE_MASK) {
> + case AFBC_SIZE_16X16:
> if ((mode_cmd->width % 16) || (mode_cmd->height % 16)) {
> DRM_DEBUG_KMS("AFBC buffers must be aligned to 16 pixels\n");
> return false;
> @@ -319,8 +299,8 @@ malidp_verify_afbc_framebuffer_size(struct drm_device *dev,
> u32 afbc_superblock_size = 0, afbc_superblock_height = 0;
> u32 afbc_superblock_width = 0, afbc_size = 0;
>
> - switch (mode_cmd->modifier[0] & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) {
> - case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16:
> + switch (mode_cmd->modifier[0] & AFBC_SIZE_MASK) {
> + case AFBC_SIZE_16X16:
> afbc_superblock_height = 16;
> afbc_superblock_width = 16;
> break;
> diff --git a/drivers/gpu/drm/arm/malidp_drv.h b/drivers/gpu/drm/arm/malidp_drv.h
> index b76c86f..019a682 100644
> --- a/drivers/gpu/drm/arm/malidp_drv.h
> +++ b/drivers/gpu/drm/arm/malidp_drv.h
> @@ -90,6 +90,12 @@ struct malidp_crtc_state {
> int malidp_de_planes_init(struct drm_device *drm);
> int malidp_crtc_init(struct drm_device *drm);
>
> +bool malidp_hw_format_is_linear_only(u32 format);
> +bool malidp_hw_format_is_afbc_only(u32 format);
> +
> +bool malidp_format_mod_supported(struct drm_device *drm,
> + u32 format, u64 modifier);
> +
> #ifdef CONFIG_DEBUG_FS
> void malidp_error(struct malidp_drm *malidp,
> struct malidp_error_stats *error_stats, u32 status,
> diff --git a/drivers/gpu/drm/arm/malidp_hw.c b/drivers/gpu/drm/arm/malidp_hw.c
> index b4a0e11..0ac2762 100644
> --- a/drivers/gpu/drm/arm/malidp_hw.c
> +++ b/drivers/gpu/drm/arm/malidp_hw.c
> @@ -60,6 +60,8 @@ static const struct malidp_format_id malidp500_de_formats[] = {
> #define MALIDP_ID(__group, __format) \
> ((((__group) & 0x7) << 3) | ((__format) & 0x7))
>
> +#define AFBC_YUV_422_FORMAT_ID MALIDP_ID(5, 1)
> +
> #define MALIDP_COMMON_FORMATS \
> /* fourcc, layers supporting the format, internal id */ \
> { DRM_FORMAT_ARGB2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | SE_MEMWRITE, MALIDP_ID(0, 0) }, \
> @@ -162,6 +164,32 @@ static const struct malidp_layer malidp650_layers[] = {
> ROTATE_NONE, 0 },
> };
>
> +const u64 malidp_format_modifiers[] = {
> + /* All RGB formats (except XRGB, RGBX, XBGR, BGRX) */
> + DRM_FORMAT_MOD_ARM_AFBC(AFBC_SIZE_16X16 | AFBC_YTR | AFBC_SPARSE),
> + DRM_FORMAT_MOD_ARM_AFBC(AFBC_SIZE_16X16 | AFBC_YTR),
> +
> + /* All RGB formats > 16bpp (except XRGB, RGBX, XBGR, BGRX) */
> + DRM_FORMAT_MOD_ARM_AFBC(AFBC_SIZE_16X16 | AFBC_YTR | AFBC_SPARSE | AFBC_SPLIT),
> +
> + /* All 8 or 10 bit YUV 444 formats. */
> + /* In DP550, 10 bit YUV 420 format also supported */
> + DRM_FORMAT_MOD_ARM_AFBC(AFBC_SIZE_16X16 | AFBC_SPARSE | AFBC_SPLIT),
> +
> + /* YUV 420, 422 P1 8 bit and YUV 444 8 bit/10 bit formats */
> + DRM_FORMAT_MOD_ARM_AFBC(AFBC_SIZE_16X16 | AFBC_SPARSE),
> + DRM_FORMAT_MOD_ARM_AFBC(AFBC_SIZE_16X16),
> +
> + /* YUV 420, 422 P1 8, 10 bit formats */
> + DRM_FORMAT_MOD_ARM_AFBC(AFBC_SIZE_16X16 | AFBC_CBR | AFBC_SPARSE),
> + DRM_FORMAT_MOD_ARM_AFBC(AFBC_SIZE_16X16 | AFBC_CBR),
> +
> + /* All formats */
> + DRM_FORMAT_MOD_LINEAR,
> +
> + DRM_FORMAT_MOD_INVALID
> +};
> +
> #define SE_N_SCALING_COEFFS 96
> static const u16 dp500_se_scaling_coeffs[][SE_N_SCALING_COEFFS] = {
> [MALIDP_UPSCALING_COEFFS - 1] = {
> @@ -866,7 +894,10 @@ const struct malidp_hw malidp_device[MALIDP_MAX_DEVICES] = {
> .se_base = MALIDP550_SE_BASE,
> .dc_base = MALIDP550_DC_BASE,
> .out_depth_base = MALIDP550_DE_OUTPUT_DEPTH,
> - .features = MALIDP_REGMAP_HAS_CLEARIRQ,
> + .features = MALIDP_REGMAP_HAS_CLEARIRQ |
> + MALIDP_DEVICE_AFBC_SUPPORT_SPLIT |
> + MALIDP_DEVICE_AFBC_YUV_420_10_SUPPORT_SPLIT |
> + MALIDP_DEVICE_AFBC_YUYV_USE_422_P2,
> .n_layers = ARRAY_SIZE(malidp550_layers),
> .layers = malidp550_layers,
> .de_irq_map = {
> @@ -912,7 +943,9 @@ const struct malidp_hw malidp_device[MALIDP_MAX_DEVICES] = {
> .se_base = MALIDP550_SE_BASE,
> .dc_base = MALIDP550_DC_BASE,
> .out_depth_base = MALIDP550_DE_OUTPUT_DEPTH,
> - .features = MALIDP_REGMAP_HAS_CLEARIRQ,
> + .features = MALIDP_REGMAP_HAS_CLEARIRQ |
> + MALIDP_DEVICE_AFBC_SUPPORT_SPLIT |
> + MALIDP_DEVICE_AFBC_YUYV_USE_422_P2,
> .n_layers = ARRAY_SIZE(malidp650_layers),
> .layers = malidp650_layers,
> .de_irq_map = {
> @@ -961,19 +994,72 @@ const struct malidp_hw malidp_device[MALIDP_MAX_DEVICES] = {
> };
>
> u8 malidp_hw_get_format_id(const struct malidp_hw_regmap *map,
> - u8 layer_id, u32 format)
> + u8 layer_id, u32 format, bool has_modifier)
> {
> unsigned int i;
>
> for (i = 0; i < map->n_pixel_formats; i++) {
> if (((map->pixel_formats[i].layer & layer_id) == layer_id) &&
> - (map->pixel_formats[i].format == format))
> - return map->pixel_formats[i].id;
> + (map->pixel_formats[i].format == format)) {
> + /*
> + * In some DP550 and DP650, DRM_FORMAT_YUYV + AFBC modifier
> + * is supported by a different h/w format id than
> + * DRM_FORMAT_YUYV (only).
> + */
> + if (format == DRM_FORMAT_YUYV &&
> + (has_modifier) &&
> + (map->features & MALIDP_DEVICE_AFBC_YUYV_USE_422_P2))
> + return AFBC_YUV_422_FORMAT_ID;
> + else
> + return map->pixel_formats[i].id;
> + }
> }
>
> return MALIDP_INVALID_FORMAT_ID;
> }
>
> +bool malidp_hw_format_is_linear_only(u32 format)
> +{
> + switch (format) {
> + case DRM_FORMAT_ARGB2101010:
> + case DRM_FORMAT_RGBA1010102:
> + case DRM_FORMAT_BGRA1010102:
> + case DRM_FORMAT_ARGB8888:
> + case DRM_FORMAT_RGBA8888:
> + case DRM_FORMAT_BGRA8888:
> + case DRM_FORMAT_XBGR8888:
> + case DRM_FORMAT_XRGB8888:
> + case DRM_FORMAT_RGBX8888:
> + case DRM_FORMAT_BGRX8888:
> + case DRM_FORMAT_RGB888:
> + case DRM_FORMAT_RGB565:
> + case DRM_FORMAT_ARGB1555:
> + case DRM_FORMAT_RGBA5551:
> + case DRM_FORMAT_BGRA5551:
> + case DRM_FORMAT_UYVY:
> + case DRM_FORMAT_XYUV8888:
> + case DRM_FORMAT_XVYU2101010:
> + case DRM_FORMAT_X0L2:
> + case DRM_FORMAT_X0L0:
> + return true;
> + default:
> + return false;
> + }
> +}
> +
> +bool malidp_hw_format_is_afbc_only(u32 format)
> +{
> + switch (format) {
> + case DRM_FORMAT_VUY888:
> + case DRM_FORMAT_VUY101010:
> + case DRM_FORMAT_YUV420_8BIT:
> + case DRM_FORMAT_YUV420_10BIT:
> + return true;
> + default:
> + return false;
> + }
> +}
> +
> static void malidp_hw_clear_irq(struct malidp_hw_device *hwdev, u8 block, u32 irq)
> {
> u32 base = malidp_get_block_base(hwdev, block);
> diff --git a/drivers/gpu/drm/arm/malidp_hw.h b/drivers/gpu/drm/arm/malidp_hw.h
> index 651558f..0859302 100644
> --- a/drivers/gpu/drm/arm/malidp_hw.h
> +++ b/drivers/gpu/drm/arm/malidp_hw.h
> @@ -95,7 +95,10 @@ struct malidp_se_config {
> };
>
> /* regmap features */
> -#define MALIDP_REGMAP_HAS_CLEARIRQ (1 << 0)
> +#define MALIDP_REGMAP_HAS_CLEARIRQ BIT(0)
> +#define MALIDP_DEVICE_AFBC_SUPPORT_SPLIT BIT(1)
> +#define MALIDP_DEVICE_AFBC_YUV_420_10_SUPPORT_SPLIT BIT(2)
> +#define MALIDP_DEVICE_AFBC_YUYV_USE_422_P2 BIT(3)
>
> struct malidp_hw_regmap {
> /* address offset of the DE register bank */
> @@ -321,7 +324,7 @@ int malidp_se_irq_init(struct drm_device *drm, int irq);
> void malidp_se_irq_fini(struct malidp_hw_device *hwdev);
>
> u8 malidp_hw_get_format_id(const struct malidp_hw_regmap *map,
> - u8 layer_id, u32 format);
> + u8 layer_id, u32 format, bool has_modifier);
>
> static inline u8 malidp_hw_get_pitch_align(struct malidp_hw_device *hwdev, bool rotated)
> {
> @@ -390,9 +393,18 @@ static inline void malidp_se_set_enh_coeffs(struct malidp_hw_device *hwdev)
>
> #define MALIDP_GAMMA_LUT_SIZE 4096
>
> -#define AFBC_MOD_VALID_BITS (AFBC_FORMAT_MOD_BLOCK_SIZE_MASK | \
> - AFBC_FORMAT_MOD_YTR | AFBC_FORMAT_MOD_SPLIT | \
> - AFBC_FORMAT_MOD_SPARSE | AFBC_FORMAT_MOD_CBR | \
> - AFBC_FORMAT_MOD_TILED | AFBC_FORMAT_MOD_SC)
> +#define AFBC_SIZE_MASK AFBC_FORMAT_MOD_BLOCK_SIZE_MASK
> +#define AFBC_SIZE_16X16 AFBC_FORMAT_MOD_BLOCK_SIZE_16x16
> +#define AFBC_YTR AFBC_FORMAT_MOD_YTR
> +#define AFBC_SPARSE AFBC_FORMAT_MOD_SPARSE
> +#define AFBC_CBR AFBC_FORMAT_MOD_CBR
> +#define AFBC_SPLIT AFBC_FORMAT_MOD_SPLIT
> +#define AFBC_TILED AFBC_FORMAT_MOD_TILED
> +#define AFBC_SC AFBC_FORMAT_MOD_SC
> +
> +#define AFBC_MOD_VALID_BITS (AFBC_SIZE_MASK | AFBC_YTR | AFBC_SPLIT | \
> + AFBC_SPARSE | AFBC_CBR | AFBC_TILED | AFBC_SC)
> +
> +extern const u64 malidp_format_modifiers[];
>
> #endif /* __MALIDP_HW_H__ */
> diff --git a/drivers/gpu/drm/arm/malidp_mw.c b/drivers/gpu/drm/arm/malidp_mw.c
> index 041a64d..28cd351 100644
> --- a/drivers/gpu/drm/arm/malidp_mw.c
> +++ b/drivers/gpu/drm/arm/malidp_mw.c
> @@ -143,7 +143,7 @@ malidp_mw_encoder_atomic_check(struct drm_encoder *encoder,
>
> mw_state->format =
> malidp_hw_get_format_id(&malidp->dev->hw->map, SE_MEMWRITE,
> - fb->format->format);
> + fb->format->format, !!fb->modifier);
> if (mw_state->format == MALIDP_INVALID_FORMAT_ID) {
> struct drm_format_name_buf format_name;
>
> diff --git a/drivers/gpu/drm/arm/malidp_planes.c b/drivers/gpu/drm/arm/malidp_planes.c
> index 181957c..79e00bf 100644
> --- a/drivers/gpu/drm/arm/malidp_planes.c
> +++ b/drivers/gpu/drm/arm/malidp_planes.c
> @@ -52,6 +52,8 @@
> #define MALIDP550_LS_ENABLE 0x01c
> #define MALIDP550_LS_R1_IN_SIZE 0x020
>
> +#define MODIFIERS_COUNT_MAX 15
> +
> /*
> * This 4-entry look-up-table is used to determine the full 8-bit alpha value
> * for formats with 1- or 2-bit alpha channels.
> @@ -145,6 +147,119 @@ static void malidp_plane_atomic_print_state(struct drm_printer *p,
> drm_printf(p, "\tmmu_prefetch_pgsize=%d\n", ms->mmu_prefetch_pgsize);
> }
>
> +bool malidp_format_mod_supported(struct drm_device *drm,
> + u32 format, u64 modifier)
> +{
> + const struct drm_format_info *info;
> + const u64 *modifiers;
> + struct malidp_drm *malidp = drm->dev_private;
> + const struct malidp_hw_regmap *map = &malidp->dev->hw->map;
> +
> + if (WARN_ON(modifier == DRM_FORMAT_MOD_INVALID))
> + return false;
> +
> + /* Some pixel formats are supported without any modifier */
> + if (modifier == DRM_FORMAT_MOD_LINEAR) {
> + /*
> + * However these pixel formats need to be supported with
> + * modifiers only
> + */
> + return !malidp_hw_format_is_afbc_only(format);
> + }
> +
> + if ((modifier >> 56) != DRM_FORMAT_MOD_VENDOR_ARM) {
> + DRM_ERROR("Unknown modifier (not Arm)\n");
> + return false;
> + }
> +
> + if (modifier &
> + ~DRM_FORMAT_MOD_ARM_AFBC(AFBC_MOD_VALID_BITS)) {
> + DRM_DEBUG_KMS("Unsupported modifiers\n");
> + return false;
> + }
> +
> + modifiers = malidp_format_modifiers;
> +
> + /* SPLIT buffers must use SPARSE layout */
> + if (WARN_ON_ONCE((modifier & AFBC_SPLIT) && !(modifier & AFBC_SPARSE)))
> + return false;
> +
> + /* CBR only applies to YUV formats, where YTR should be always 0 */
> + if (WARN_ON_ONCE((modifier & AFBC_CBR) && (modifier & AFBC_YTR)))
> + return false;
> +
> + while (*modifiers != DRM_FORMAT_MOD_INVALID) {
> + if (*modifiers == modifier)
> + break;
> +
> + modifiers++;
> + }
> +
> + /* return false, if the modifier was not found */
> + if (*modifiers == DRM_FORMAT_MOD_INVALID) {
> + DRM_DEBUG_KMS("Unsupported modifier\n");
> + return false;
> + }
> +
> + info = drm_format_info(format);
> +
> + if (info->num_planes != 1) {
> + DRM_DEBUG_KMS("AFBC buffers expect one plane\n");
> + return false;
> + }
> +
> + if (malidp_hw_format_is_linear_only(format) == true) {
> + DRM_DEBUG_KMS("Given format (0x%x) is supported is linear mode only\n",
> + format);
> + return false;
> + }
> +
> + /*
> + * RGB formats need to provide YTR modifier and YUV formats should not
> + * provide YTR modifier.
> + */
> + if (!(info->is_yuv) != !!(modifier & AFBC_FORMAT_MOD_YTR)) {
> + DRM_DEBUG_KMS("AFBC_FORMAT_MOD_YTR is %s for %s formats\n",
> + info->is_yuv ? "disallowed" : "mandatory",
> + info->is_yuv ? "YUV" : "RGB");
> + return false;
> + }
> +
> + if (modifier & AFBC_SPLIT) {
> + if (!info->is_yuv) {
> + if (drm_format_plane_cpp(format, 0) <= 2) {
> + DRM_DEBUG_KMS("RGB formats <= 16bpp are not supported with SPLIT\n");
> + return false;
> + }
> + }
> +
> + if ((drm_format_horz_chroma_subsampling(format) != 1) ||
> + (drm_format_vert_chroma_subsampling(format) != 1)) {
> + if (!(format == DRM_FORMAT_YUV420_10BIT &&
> + (map->features & MALIDP_DEVICE_AFBC_YUV_420_10_SUPPORT_SPLIT))) {
> + DRM_DEBUG_KMS("Formats which are sub-sampled should never be split\n");
> + return false;
> + }
> + }
> + }
> +
> + if (modifier & AFBC_CBR) {
> + if ((drm_format_horz_chroma_subsampling(format) == 1) ||
> + (drm_format_vert_chroma_subsampling(format) == 1)) {
> + DRM_DEBUG_KMS("Formats which are not sub-sampled should not have CBR set\n");
> + return false;
> + }
> + }
> +
> + return true;
> +}
> +
> +static bool malidp_format_mod_supported_per_plane(struct drm_plane *plane,
> + u32 format, u64 modifier)
> +{
> + return malidp_format_mod_supported(plane->dev, format, modifier);
> +}
> +
> static const struct drm_plane_funcs malidp_de_plane_funcs = {
> .update_plane = drm_atomic_helper_update_plane,
> .disable_plane = drm_atomic_helper_disable_plane,
> @@ -153,6 +268,7 @@ static const struct drm_plane_funcs malidp_de_plane_funcs = {
> .atomic_duplicate_state = malidp_duplicate_plane_state,
> .atomic_destroy_state = malidp_destroy_plane_state,
> .atomic_print_state = malidp_plane_atomic_print_state,
> + .format_mod_supported = malidp_format_mod_supported_per_plane,
> };
>
> static int malidp_se_check_scaling(struct malidp_plane *mp,
> @@ -406,8 +522,8 @@ static int malidp_de_plane_check(struct drm_plane *plane,
> fb = state->fb;
>
> ms->format = malidp_hw_get_format_id(&mp->hwdev->hw->map,
> - mp->layer->id,
> - fb->format->format);
> + mp->layer->id, fb->format->format,
> + !!fb->modifier);
> if (ms->format == MALIDP_INVALID_FORMAT_ID)
> return -EINVAL;
>
> @@ -469,6 +585,12 @@ static int malidp_de_plane_check(struct drm_plane *plane,
> return -EINVAL;
> }
>
> + /* SMART layer does not support AFBC */
> + if (mp->layer->id == DE_SMART && fb->modifier) {
> + DRM_ERROR("AFBC framebuffer not supported in SMART layer");
> + return -EINVAL;
> + }
> +
> ms->rotmem_size = 0;
> if (state->rotation & MALIDP_ROTATED_MASK) {
> int val;
> --
> 2.7.4
>

--
====================
| I would like to |
| fix the world, |
| but they're not |
| giving me the |
\ source code! /
---------------
¯\_(ツ)_/¯