On Tue, Feb 26, 2019 at 04:20:56PM +0000, Ayan Halder wrote:
From: Ayan Kumar Halder ayan.halder@arm.com
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:-
- AFBC is not supported for the formats defined in
malidp_hw_format_is_linear_only()
- 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.
AFBC_FORMAT_MOD_YTR needs to be provided for any RGB format.
Formats <= 16bpp cannot support AFBC_FORMAT_MOD_SPLIT.
CBR should not be set for non-subsampled formats.
SMART layer does not support framebuffer with AFBC modifiers.
Return -EINVAL for such a scenario.
AFBC_FORMAT_MOD_YTR is not supported for any YUV formats.
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.
- 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.
- 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.
- 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 ayan.halder@arm.com
Reviewed-by: Liviu Dudau liviu.dudau@arm.com
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,
return false;mode_cmd->modifier[0]) == 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);
if (mw_state->format == MALIDP_INVALID_FORMAT_ID) { struct drm_format_name_buf format_name;fb->format->format, !!fb->modifier);
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,
if (ms->format == MALIDP_INVALID_FORMAT_ID) return -EINVAL;!!fb->modifier);
@@ -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