drm/msm/sde: support more formats including compression
Add support for variants of RGBX, RGBA4444, RGBA5551, RGB565,
and the appropriate compressed variants.
Change-Id: I3fef703d094967d722472a20197d4ccbaa12bb6a
Signed-off-by: Lloyd Atkinson <latkinso@codeaurora.org>
diff --git a/drivers/gpu/drm/msm/sde/sde_formats.c b/drivers/gpu/drm/msm/sde/sde_formats.c
index 78d672e..25dac8c 100644
--- a/drivers/gpu/drm/msm/sde/sde_formats.c
+++ b/drivers/gpu/drm/msm/sde/sde_formats.c
@@ -10,136 +10,756 @@
* GNU General Public License for more details.
*/
+#include <uapi/drm/drm_fourcc.h>
+
#include "sde_kms.h"
#include "sde_formats.h"
-static struct sde_format sde_format_map[] = {
+#define SDE_UBWC_META_MACRO_W_H 16
+#define SDE_UBWC_META_BLOCK_SIZE 256
+#define SDE_MAX_IMG_WIDTH 0x3FFF
+#define SDE_MAX_IMG_HEIGHT 0x3FFF
+
+/**
+ * SDE supported format packing, bpp, and other format
+ * information.
+ * SDE currently only supports interleaved RGB formats
+ * UBWC support for a pixel format is indicated by the flag,
+ * there is additional meta data plane for such formats
+ */
+
+#define INTERLEAVED_RGB_FMT(fmt, a, r, g, b, e0, e1, e2, e3, uc, alpha, \
+bp, flg, fm, np) \
+{ \
+ .base.pixel_format = DRM_FORMAT_ ## fmt, \
+ .fetch_planes = SDE_PLANE_INTERLEAVED, \
+ .alpha_enable = alpha, \
+ .element = { (e0), (e1), (e2), (e3) }, \
+ .bits = { g, b, r, a }, \
+ .chroma_sample = SDE_CHROMA_RGB, \
+ .unpack_align_msb = 0, \
+ .unpack_tight = 1, \
+ .unpack_count = uc, \
+ .bpp = bp, \
+ .fetch_mode = fm, \
+ .flag = flg, \
+ .num_planes = np \
+}
+
+#define INTERLEAVED_YUV_FMT(fmt, a, r, g, b, e0, e1, e2, e3, \
+alpha, chroma, count, bp, flg, fm, np) \
+{ \
+ .base.pixel_format = DRM_FORMAT_ ## fmt, \
+ .fetch_planes = SDE_PLANE_INTERLEAVED, \
+ .alpha_enable = alpha, \
+ .element = { (e0), (e1), (e2), (e3)}, \
+ .bits = { g, b, r, a }, \
+ .chroma_sample = chroma, \
+ .unpack_align_msb = 0, \
+ .unpack_tight = 1, \
+ .unpack_count = count, \
+ .bpp = bp, \
+ .fetch_mode = fm, \
+ .flag = flg, \
+ .num_planes = np \
+}
+
+#define PSEDUO_YUV_FMT(fmt, a, r, g, b, e0, e1, chroma, flg, fm, np) \
+{ \
+ .base.pixel_format = DRM_FORMAT_ ## fmt, \
+ .fetch_planes = SDE_PLANE_PSEUDO_PLANAR, \
+ .alpha_enable = false, \
+ .element = { (e0), (e1), 0, 0 }, \
+ .bits = { g, b, r, a }, \
+ .chroma_sample = chroma, \
+ .unpack_align_msb = 0, \
+ .unpack_tight = 1, \
+ .unpack_count = 2, \
+ .bpp = 2, \
+ .fetch_mode = fm, \
+ .flag = flg, \
+ .num_planes = np \
+}
+
+#define PLANAR_YUV_FMT(fmt, a, r, g, b, e0, e1, e2, alpha, chroma, bp, \
+flg, fm, np) \
+{ \
+ .base.pixel_format = DRM_FORMAT_ ## fmt, \
+ .fetch_planes = SDE_PLANE_PLANAR, \
+ .alpha_enable = alpha, \
+ .element = { (e0), (e1), (e2), 0 }, \
+ .bits = { g, b, r, a }, \
+ .chroma_sample = chroma, \
+ .unpack_align_msb = 0, \
+ .unpack_tight = 1, \
+ .unpack_count = 1, \
+ .bpp = bp, \
+ .fetch_mode = fm, \
+ .flag = flg, \
+ .num_planes = np \
+}
+
+static const struct sde_format sde_format_map[] = {
INTERLEAVED_RGB_FMT(ARGB8888,
COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
- true, 4, SDE_FORMAT_FLAG_ROTATOR),
+ true, 4, 0,
+ SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(ABGR8888,
COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
- true, 4, SDE_FORMAT_FLAG_ROTATOR),
+ true, 4, 0,
+ SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(RGBA8888,
COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
- true, 4, SDE_FORMAT_FLAG_ROTATOR),
+ true, 4, 0,
+ SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(BGRA8888,
COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
- true, 4, SDE_FORMAT_FLAG_ROTATOR),
+ true, 4, 0,
+ SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(XRGB8888,
COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
- false, 4, SDE_FORMAT_FLAG_ROTATOR),
+ false, 4, 0,
+ SDE_FETCH_LINEAR, 1),
+
+ INTERLEAVED_RGB_FMT(RGBX8888,
+ COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
+ C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
+ false, 4, 0,
+ SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(RGB888,
0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
C1_B_Cb, C0_G_Y, C2_R_Cr, 0, 3,
- false, 3, SDE_FORMAT_FLAG_ROTATOR),
+ false, 3, 0,
+ SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(BGR888,
0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
C2_R_Cr, C0_G_Y, C1_B_Cb, 0, 3,
- false, 3, SDE_FORMAT_FLAG_ROTATOR),
+ false, 3, 0,
+ SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(RGB565,
0, COLOR_5BIT, COLOR_6BIT, COLOR_5BIT,
C1_B_Cb, C0_G_Y, C2_R_Cr, 0, 3,
- false, 2, SDE_FORMAT_FLAG_ROTATOR),
+ false, 2, 0,
+ SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(BGR565,
0, COLOR_5BIT, COLOR_6BIT, COLOR_5BIT,
C2_R_Cr, C0_G_Y, C1_B_Cb, 0, 3,
- false, 2, SDE_FORMAT_FLAG_ROTATOR),
+ false, 2, 0,
+ SDE_FETCH_LINEAR, 1),
+
+ INTERLEAVED_RGB_FMT(ARGB1555,
+ COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT,
+ C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
+ true, 2, 0,
+ SDE_FETCH_LINEAR, 1),
+
+ INTERLEAVED_RGB_FMT(ABGR1555,
+ COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT,
+ C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
+ true, 2, 0,
+ SDE_FETCH_LINEAR, 1),
+
+ INTERLEAVED_RGB_FMT(RGBA5551,
+ COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT,
+ C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
+ true, 2, 0,
+ SDE_FETCH_LINEAR, 1),
+
+ INTERLEAVED_RGB_FMT(BGRA5551,
+ COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT,
+ C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
+ true, 2, 0,
+ SDE_FETCH_LINEAR, 1),
+
+ INTERLEAVED_RGB_FMT(XRGB1555,
+ COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT,
+ C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
+ false, 2, 0,
+ SDE_FETCH_LINEAR, 1),
+
+ INTERLEAVED_RGB_FMT(XBGR1555,
+ COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT,
+ C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
+ false, 2, 0,
+ SDE_FETCH_LINEAR, 1),
+
+ INTERLEAVED_RGB_FMT(RGBX5551,
+ COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT,
+ C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
+ false, 2, 0,
+ SDE_FETCH_LINEAR, 1),
+
+ INTERLEAVED_RGB_FMT(BGRX5551,
+ COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT,
+ C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
+ false, 2, 0,
+ SDE_FETCH_LINEAR, 1),
+
+ INTERLEAVED_RGB_FMT(ARGB4444,
+ COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT,
+ C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
+ true, 2, 0,
+ SDE_FETCH_LINEAR, 1),
+
+ INTERLEAVED_RGB_FMT(ABGR4444,
+ COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT,
+ C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
+ true, 2, 0,
+ SDE_FETCH_LINEAR, 1),
+
+ INTERLEAVED_RGB_FMT(RGBA4444,
+ COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT,
+ C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
+ true, 2, 0,
+ SDE_FETCH_LINEAR, 1),
+
+ INTERLEAVED_RGB_FMT(BGRA4444,
+ COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT,
+ C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
+ true, 2, 0,
+ SDE_FETCH_LINEAR, 1),
+
+ INTERLEAVED_RGB_FMT(XRGB4444,
+ COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT,
+ C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
+ false, 2, 0,
+ SDE_FETCH_LINEAR, 1),
+
+ INTERLEAVED_RGB_FMT(XBGR4444,
+ COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT,
+ C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
+ false, 2, 0,
+ SDE_FETCH_LINEAR, 1),
+
+ INTERLEAVED_RGB_FMT(RGBX4444,
+ COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT,
+ C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
+ false, 2, 0,
+ SDE_FETCH_LINEAR, 1),
+
+ INTERLEAVED_RGB_FMT(BGRX4444,
+ COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT,
+ C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
+ false, 2, 0,
+ SDE_FETCH_LINEAR, 1),
PSEDUO_YUV_FMT(NV12,
0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
C1_B_Cb, C2_R_Cr,
- SDE_CHROMA_420, SDE_FORMAT_FLAG_ROTATOR),
+ SDE_CHROMA_420, SDE_FORMAT_FLAG_YUV,
+ SDE_FETCH_LINEAR, 2),
PSEDUO_YUV_FMT(NV21,
0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
C2_R_Cr, C1_B_Cb,
- SDE_CHROMA_420, SDE_FORMAT_FLAG_ROTATOR),
+ SDE_CHROMA_420, SDE_FORMAT_FLAG_YUV,
+ SDE_FETCH_LINEAR, 2),
PSEDUO_YUV_FMT(NV16,
0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
C1_B_Cb, C2_R_Cr,
- SDE_CHROMA_H2V1, SDE_FORMAT_FLAG_ROTATOR),
+ SDE_CHROMA_H2V1, SDE_FORMAT_FLAG_YUV,
+ SDE_FETCH_LINEAR, 2),
PSEDUO_YUV_FMT(NV61,
0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
C2_R_Cr, C1_B_Cb,
- SDE_CHROMA_H2V1, SDE_FORMAT_FLAG_ROTATOR),
+ SDE_CHROMA_H2V1, SDE_FORMAT_FLAG_YUV,
+ SDE_FETCH_LINEAR, 2),
INTERLEAVED_YUV_FMT(VYUY,
0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
C2_R_Cr, C0_G_Y, C1_B_Cb, C0_G_Y,
- false, SDE_CHROMA_H2V1, 4, 2,
- 0),
+ false, SDE_CHROMA_H2V1, 4, 2, SDE_FORMAT_FLAG_YUV,
+ SDE_FETCH_LINEAR, 2),
INTERLEAVED_YUV_FMT(UYVY,
0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
C1_B_Cb, C0_G_Y, C2_R_Cr, C0_G_Y,
- false, SDE_CHROMA_H2V1, 4, 2,
- 0),
+ false, SDE_CHROMA_H2V1, 4, 2, SDE_FORMAT_FLAG_YUV,
+ SDE_FETCH_LINEAR, 2),
INTERLEAVED_YUV_FMT(YUYV,
0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
C0_G_Y, C1_B_Cb, C0_G_Y, C2_R_Cr,
- false, SDE_CHROMA_H2V1, 4, 2,
- 0),
+ false, SDE_CHROMA_H2V1, 4, 2, SDE_FORMAT_FLAG_YUV,
+ SDE_FETCH_LINEAR, 2),
INTERLEAVED_YUV_FMT(YVYU,
0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
C0_G_Y, C2_R_Cr, C0_G_Y, C1_B_Cb,
- false, SDE_CHROMA_H2V1, 4, 2,
- 0),
+ false, SDE_CHROMA_H2V1, 4, 2, SDE_FORMAT_FLAG_YUV,
+ SDE_FETCH_LINEAR, 2),
PLANAR_YUV_FMT(YUV420,
0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
C2_R_Cr, C1_B_Cb, C0_G_Y,
- false, SDE_CHROMA_420, 2,
- SDE_FORMAT_FLAG_ROTATOR),
+ false, SDE_CHROMA_420, 1, SDE_FORMAT_FLAG_YUV,
+ SDE_FETCH_LINEAR, 3),
PLANAR_YUV_FMT(YVU420,
0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
C1_B_Cb, C2_R_Cr, C0_G_Y,
- false, SDE_CHROMA_420, 2,
- SDE_FORMAT_FLAG_ROTATOR),
+ false, SDE_CHROMA_420, 1, SDE_FORMAT_FLAG_YUV,
+ SDE_FETCH_LINEAR, 3),
};
+/*
+ * UBWC formats table:
+ * This table holds the UBWC formats supported.
+ * If a compression ratio needs to be used for this or any other format,
+ * the data will be passed by user-space.
+ */
+static const struct sde_format sde_format_map_ubwc[] = {
+ INTERLEAVED_RGB_FMT(RGB565,
+ 0, COLOR_5BIT, COLOR_6BIT, COLOR_5BIT,
+ C2_R_Cr, C0_G_Y, C1_B_Cb, 0, 3,
+ false, 2, 0,
+ SDE_FETCH_UBWC, 2),
+
+ INTERLEAVED_RGB_FMT(RGBA8888,
+ COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
+ C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
+ true, 4, 0,
+ SDE_FETCH_UBWC, 2),
+
+ INTERLEAVED_RGB_FMT(RGBX8888,
+ COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
+ C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
+ false, 4, 0,
+ SDE_FETCH_UBWC, 2),
+
+ PSEDUO_YUV_FMT(NV12,
+ 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
+ C1_B_Cb, C2_R_Cr,
+ SDE_CHROMA_420, SDE_FORMAT_FLAG_YUV,
+ SDE_FETCH_UBWC, 4),
+};
+
+/* _sde_get_v_h_subsample_rate - Get subsample rates for all formats we support
+ * Note: Not using the drm_format_*_subsampling since we have formats
+ */
+static void _sde_get_v_h_subsample_rate(
+ enum sde_chroma_samp_type chroma_sample,
+ uint32_t *v_sample,
+ uint32_t *h_sample)
+{
+ switch (chroma_sample) {
+ case SDE_CHROMA_H2V1:
+ *v_sample = 1;
+ *h_sample = 2;
+ break;
+ case SDE_CHROMA_H1V2:
+ *v_sample = 2;
+ *h_sample = 1;
+ break;
+ case SDE_CHROMA_420:
+ *v_sample = 2;
+ *h_sample = 2;
+ break;
+ default:
+ *v_sample = 1;
+ *h_sample = 1;
+ break;
+ }
+}
+
+static int _sde_format_get_plane_sizes_ubwc(
+ const struct sde_format *fmt,
+ const uint32_t width,
+ const uint32_t height,
+ struct sde_hw_fmt_layout *layout)
+{
+ int i;
+
+ memset(layout, 0, sizeof(struct sde_hw_fmt_layout));
+ layout->format = fmt;
+ layout->width = width;
+ layout->height = height;
+ layout->num_planes = fmt->num_planes;
+
+ if (fmt->base.pixel_format == DRM_FORMAT_NV12) {
+ uint32_t y_stride_alignment, uv_stride_alignment;
+ uint32_t y_height_alignment, uv_height_alignment;
+ uint32_t y_tile_width = 32;
+ uint32_t y_tile_height = 8;
+ uint32_t uv_tile_width = y_tile_width / 2;
+ uint32_t uv_tile_height = y_tile_height;
+ uint32_t y_bpp_numer = 1, y_bpp_denom = 1;
+ uint32_t uv_bpp_numer = 1, uv_bpp_denom = 1;
+
+ y_stride_alignment = 128;
+ uv_stride_alignment = 64;
+ y_height_alignment = 32;
+ uv_height_alignment = 32;
+ y_bpp_numer = 1;
+ uv_bpp_numer = 2;
+ y_bpp_denom = 1;
+ uv_bpp_denom = 1;
+
+ layout->num_planes = 4;
+ /* Y bitstream stride and plane size */
+ layout->plane_pitch[0] = ALIGN(width, y_stride_alignment);
+ layout->plane_pitch[0] = (layout->plane_pitch[0] * y_bpp_numer)
+ / y_bpp_denom;
+ layout->plane_size[0] = ALIGN(layout->plane_pitch[0] *
+ ALIGN(height, y_height_alignment), 4096);
+
+ /* CbCr bitstream stride and plane size */
+ layout->plane_pitch[1] = ALIGN(width / 2, uv_stride_alignment);
+ layout->plane_pitch[1] = (layout->plane_pitch[1] * uv_bpp_numer)
+ / uv_bpp_denom;
+ layout->plane_size[1] = ALIGN(layout->plane_pitch[1] *
+ ALIGN(height / 2, uv_height_alignment), 4096);
+
+ /* Y meta data stride and plane size */
+ layout->plane_pitch[2] = ALIGN(
+ DIV_ROUND_UP(width, y_tile_width), 64);
+ layout->plane_size[2] = ALIGN(layout->plane_pitch[2] *
+ ALIGN(DIV_ROUND_UP(height, y_tile_height), 16), 4096);
+
+ /* CbCr meta data stride and plane size */
+ layout->plane_pitch[3] = ALIGN(
+ DIV_ROUND_UP(width / 2, uv_tile_width), 64);
+ layout->plane_size[3] = ALIGN(layout->plane_pitch[3] *
+ ALIGN(DIV_ROUND_UP(height / 2, uv_tile_height), 16),
+ 4096);
+
+ } else if (fmt->base.pixel_format == DRM_FORMAT_RGBA8888 ||
+ fmt->base.pixel_format == DRM_FORMAT_RGBX8888 ||
+ fmt->base.pixel_format == DRM_FORMAT_RGB565) {
+ uint32_t stride_alignment, aligned_bitstream_width;
+
+ if (fmt->base.pixel_format == DRM_FORMAT_RGB565)
+ stride_alignment = 128;
+ else
+ stride_alignment = 64;
+ layout->num_planes = 3;
+
+ /* Nothing in plane[1] */
+
+ /* RGB bitstream stride and plane size */
+ aligned_bitstream_width = ALIGN(width, stride_alignment);
+ layout->plane_pitch[0] = aligned_bitstream_width * fmt->bpp;
+ layout->plane_size[0] = ALIGN(fmt->bpp * aligned_bitstream_width
+ * ALIGN(height, 16), 4096);
+
+ /* RGB meta data stride and plane size */
+ layout->plane_pitch[2] = ALIGN(DIV_ROUND_UP(
+ aligned_bitstream_width, 16), 64);
+ layout->plane_size[2] = ALIGN(layout->plane_pitch[2] *
+ ALIGN(DIV_ROUND_UP(height, 4), 16), 4096);
+ } else {
+ DRM_ERROR("UBWC format not supported for fmt:0x%X\n",
+ fmt->base.pixel_format);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < SDE_MAX_PLANES; i++)
+ layout->total_size += layout->plane_size[i];
+
+ return 0;
+}
+
+static int _sde_format_get_plane_sizes_linear(
+ const struct sde_format *fmt,
+ const uint32_t width,
+ const uint32_t height,
+ struct sde_hw_fmt_layout *layout)
+{
+ int i;
+
+ memset(layout, 0, sizeof(struct sde_hw_fmt_layout));
+ layout->format = fmt;
+ layout->width = width;
+ layout->height = height;
+ layout->num_planes = fmt->num_planes;
+
+ /* Due to memset above, only need to set planes of interest */
+ if (fmt->fetch_planes == SDE_PLANE_INTERLEAVED) {
+ layout->num_planes = 1;
+ layout->plane_size[0] = width * height * layout->format->bpp;
+ layout->plane_pitch[0] = width * layout->format->bpp;
+ } else {
+ uint32_t v_subsample, h_subsample;
+ uint32_t chroma_samp;
+
+ chroma_samp = fmt->chroma_sample;
+ _sde_get_v_h_subsample_rate(chroma_samp, &v_subsample,
+ &h_subsample);
+
+ if (width % h_subsample || height % v_subsample) {
+ DRM_ERROR("mismatch in subsample vs dimensions\n");
+ return -EINVAL;
+ }
+
+ layout->plane_pitch[0] = width;
+ layout->plane_pitch[1] = width / h_subsample;
+ layout->plane_size[0] = layout->plane_pitch[0] * height;
+ layout->plane_size[1] = layout->plane_pitch[1] *
+ (height / v_subsample);
+
+ if (fmt->fetch_planes == SDE_PLANE_PSEUDO_PLANAR) {
+ layout->num_planes = 2;
+ layout->plane_size[1] *= 2;
+ layout->plane_pitch[1] *= 2;
+ } else {
+ /* planar */
+ layout->num_planes = 3;
+ layout->plane_size[2] = layout->plane_size[1];
+ layout->plane_pitch[2] = layout->plane_pitch[1];
+ }
+ }
+
+ for (i = 0; i < SDE_MAX_PLANES; i++)
+ layout->total_size += layout->plane_size[i];
+
+ return 0;
+}
+
+static int _sde_format_get_plane_sizes(
+ const struct sde_format *fmt,
+ const uint32_t w,
+ const uint32_t h,
+ struct sde_hw_fmt_layout *layout)
+{
+ if (!layout || !fmt) {
+ DRM_ERROR("invalid pointer\n");
+ return -EINVAL;
+ }
+
+ if ((w > SDE_MAX_IMG_WIDTH) || (h > SDE_MAX_IMG_HEIGHT)) {
+ DRM_ERROR("image dimensions outside max range\n");
+ return -ERANGE;
+ }
+
+ if (SDE_FORMAT_IS_UBWC(fmt))
+ return _sde_format_get_plane_sizes_ubwc(fmt, w, h, layout);
+
+ return _sde_format_get_plane_sizes_linear(fmt, w, h, layout);
+}
+
+static int _sde_format_populate_addrs_ubwc(
+ int mmu_id,
+ struct drm_framebuffer *fb,
+ struct sde_hw_fmt_layout *layout)
+{
+ uint32_t base_addr;
+
+ if (!fb || !layout) {
+ DRM_ERROR("invalid pointers\n");
+ return -EINVAL;
+ }
+
+ base_addr = msm_framebuffer_iova(fb, mmu_id, 0);
+ if (!base_addr) {
+ DRM_ERROR("failed to retrieve base addr\n");
+ return -EFAULT;
+ }
+
+ /* Per-format logic for verifying active planes */
+ if (SDE_FORMAT_IS_YUV(layout->format)) {
+ /************************************************/
+ /* UBWC ** */
+ /* buffer ** SDE PLANE */
+ /* format ** */
+ /************************************************/
+ /* ------------------- ** -------------------- */
+ /* | Y meta | ** | Y bitstream | */
+ /* | data | ** | plane | */
+ /* ------------------- ** -------------------- */
+ /* | Y bitstream | ** | CbCr bitstream | */
+ /* | data | ** | plane | */
+ /* ------------------- ** -------------------- */
+ /* | Cbcr metadata | ** | Y meta | */
+ /* | data | ** | plane | */
+ /* ------------------- ** -------------------- */
+ /* | CbCr bitstream | ** | CbCr meta | */
+ /* | data | ** | plane | */
+ /* ------------------- ** -------------------- */
+ /************************************************/
+
+ /* configure Y bitstream plane */
+ layout->plane_addr[0] = base_addr + layout->plane_size[2];
+
+ /* configure CbCr bitstream plane */
+ layout->plane_addr[1] = base_addr + layout->plane_size[0]
+ + layout->plane_size[2] + layout->plane_size[3];
+
+ /* configure Y metadata plane */
+ layout->plane_addr[2] = base_addr;
+
+ /* configure CbCr metadata plane */
+ layout->plane_addr[3] = base_addr + layout->plane_size[0]
+ + layout->plane_size[2];
+
+ } else {
+ /************************************************/
+ /* UBWC ** */
+ /* buffer ** SDE PLANE */
+ /* format ** */
+ /************************************************/
+ /* ------------------- ** -------------------- */
+ /* | RGB meta | ** | RGB bitstream | */
+ /* | data | ** | plane | */
+ /* ------------------- ** -------------------- */
+ /* | RGB bitstream | ** | NONE | */
+ /* | data | ** | | */
+ /* ------------------- ** -------------------- */
+ /* ** | RGB meta | */
+ /* ** | plane | */
+ /* ** -------------------- */
+ /************************************************/
+
+ layout->plane_addr[0] = base_addr + layout->plane_size[2];
+ layout->plane_addr[1] = 0;
+ layout->plane_addr[2] = base_addr;
+ layout->plane_addr[3] = 0;
+ }
+
+ return 0;
+}
+
+static int _sde_format_populate_addrs_linear(
+ int mmu_id,
+ struct drm_framebuffer *fb,
+ struct sde_hw_fmt_layout *layout)
+{
+ unsigned int i;
+
+ /* Can now check the pitches given vs pitches expected */
+ for (i = 0; i < layout->num_planes; ++i) {
+ if (layout->plane_pitch[i] != fb->pitches[i]) {
+ DRM_ERROR("plane %u expected pitch %u, fb %u\n",
+ i, layout->plane_pitch[i], fb->pitches[i]);
+ return -EINVAL;
+ }
+ }
+
+ /* Populate addresses for simple formats here */
+ for (i = 0; i < layout->num_planes; ++i) {
+ layout->plane_addr[i] = msm_framebuffer_iova(fb, mmu_id, i);
+ if (!layout->plane_addr[i]) {
+ DRM_ERROR("failed to retrieve base addr\n");
+ return -EFAULT;
+ }
+ }
+
+ return 0;
+}
+
+int sde_format_populate_layout(
+ int mmu_id,
+ struct drm_framebuffer *fb,
+ struct sde_hw_fmt_layout *layout)
+{
+ int ret;
+
+ if (!fb || !layout) {
+ DRM_ERROR("invalid arguments\n");
+ return -EINVAL;
+ }
+
+ if ((fb->width > SDE_MAX_IMG_WIDTH) ||
+ (fb->height > SDE_MAX_IMG_HEIGHT)) {
+ DRM_ERROR("image dimensions outside max range\n");
+ return -ERANGE;
+ }
+
+ layout->format = to_sde_format(msm_framebuffer_format(fb));
+
+ /* Populate the plane sizes etc via get_format */
+ ret = _sde_format_get_plane_sizes(layout->format, fb->width, fb->height,
+ layout);
+ if (ret)
+ return ret;
+
+ /* Populate the addresses given the fb */
+ if (SDE_FORMAT_IS_UBWC(layout->format))
+ ret = _sde_format_populate_addrs_ubwc(mmu_id, fb, layout);
+ else
+ ret = _sde_format_populate_addrs_linear(mmu_id, fb, layout);
+
+ return ret;
+}
+
+int sde_format_check_modified_format(
+ const struct msm_kms *kms,
+ const struct msm_format *msm_fmt,
+ const struct drm_mode_fb_cmd2 *cmd,
+ struct drm_gem_object **bos)
+{
+ int ret, i, num_base_fmt_planes;
+ const struct sde_format *fmt;
+ struct sde_hw_fmt_layout layout;
+ uint32_t bos_total_size = 0;
+
+ if (!msm_fmt || !cmd || !bos) {
+ DRM_ERROR("invalid arguments\n");
+ return -EINVAL;
+ }
+
+ fmt = to_sde_format(msm_fmt);
+ num_base_fmt_planes = drm_format_num_planes(fmt->base.pixel_format);
+
+ ret = _sde_format_get_plane_sizes(fmt, cmd->width, cmd->height,
+ &layout);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < num_base_fmt_planes; i++) {
+ if (!bos[i]) {
+ DRM_ERROR("invalid handle for plane %d\n", i);
+ return -EINVAL;
+ }
+ bos_total_size += bos[i]->size;
+ }
+
+ if (bos_total_size < layout.total_size) {
+ DRM_ERROR("buffers total size too small %u expected %u\n",
+ bos_total_size, layout.total_size);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
const struct sde_format *sde_get_sde_format_ext(
const uint32_t format,
const uint64_t *modifiers,
const uint32_t modifiers_len)
{
- u32 i = 0;
- uint64_t modifier = 0;
- struct sde_format *fmt = NULL;
+ uint32_t i = 0;
+ uint64_t mod0 = 0;
+ const struct sde_format *fmt = NULL;
+ const struct sde_format *map = NULL;
+ ssize_t map_size = 0;
/*
- * Currently only support exactly zero or one modifier, and it must be
- * identical for all planes
+ * Currently only support exactly zero or one modifier.
+ * All planes used must specify the same modifier.
*/
- if ((modifiers_len && !modifiers) || (!modifiers_len && modifiers)) {
- DRM_ERROR("unexpected modifiers array or len\n");
+ if (modifiers_len && !modifiers) {
+ DRM_ERROR("invalid modifiers array\n");
return NULL;
- } else if (modifiers && modifiers_len) {
- modifier = modifiers[0];
- for (i = 0; i < modifiers_len; i++) {
- if (modifiers[i])
- DBG("plane %d format modifier 0x%llX", i,
- modifiers[i]);
-
- if (modifiers[i] != modifier) {
+ } else if (modifiers && modifiers_len && modifiers[0]) {
+ mod0 = modifiers[0];
+ DBG("plane format modifier 0x%llX", mod0);
+ for (i = 1; i < modifiers_len; i++) {
+ if (modifiers[i] != mod0) {
DRM_ERROR("bad fmt mod 0x%llX on plane %d\n",
modifiers[i], i);
return NULL;
@@ -147,17 +767,36 @@
}
}
- for (i = 0; i < ARRAY_SIZE(sde_format_map); i++)
- if (format == sde_format_map[i].base.pixel_format) {
- fmt = &sde_format_map[i];
+ switch (mod0) {
+ case 0:
+ map = sde_format_map;
+ map_size = ARRAY_SIZE(sde_format_map);
+ break;
+ case DRM_FORMAT_MOD_QCOM_COMPRESSED:
+ map = sde_format_map_ubwc;
+ map_size = ARRAY_SIZE(sde_format_map_ubwc);
+ DBG("found fmt 0x%X DRM_FORMAT_MOD_QCOM_COMPRESSED", format);
+ break;
+ default:
+ DRM_ERROR("unsupported format modifier %llX\n", mod0);
+ return NULL;
+ }
+
+ for (i = 0; i < map_size; i++) {
+ if (format == map[i].base.pixel_format) {
+ fmt = &map[i];
break;
}
+ }
if (fmt == NULL)
DRM_ERROR("unsupported fmt 0x%X modifier 0x%llX\n",
- format, modifier);
+ format, mod0);
else
- DBG("found fmt 0x%X modifier 0x%llX", format, modifier);
+ DBG("fmt %s mod 0x%llX ubwc %d yuv %d",
+ drm_get_format_name(format), mod0,
+ SDE_FORMAT_IS_UBWC(fmt),
+ SDE_FORMAT_IS_YUV(fmt));
return fmt;
}