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;
}
diff --git a/drivers/gpu/drm/msm/sde/sde_formats.h b/drivers/gpu/drm/msm/sde/sde_formats.h
index 545633b..3400b14 100644
--- a/drivers/gpu/drm/msm/sde/sde_formats.h
+++ b/drivers/gpu/drm/msm/sde/sde_formats.h
@@ -16,93 +16,8 @@
#include <drm/drm_fourcc.h>
#include "sde_hw_mdss.h"
-#define SDE_FORMAT_FLAG_ROTATOR BIT(0)
-#define SDE_FORMAT_FLAG_UBWC BIT(1)
-
-#define SDE_FORMAT_IS_YUV(X) ((X)->is_yuv)
-#define SDE_FORMAT_IS_ROTATOR(X) ((X)->flag & SDE_FORMAT_FLAG_ROTATOR)
-#define SDE_FORMAT_IS_UBWC(X) ((X)->flag & SDE_FORMAT_FLAG_UBWC)
-
/**
- * 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) \
-{ \
- .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 = SDE_FETCH_LINEAR, \
- .is_yuv = false, \
- .flag = flg \
-}
-
-#define INTERLEAVED_YUV_FMT(fmt, a, r, g, b, e0, e1, e2, e3, \
-alpha, chroma, count, bp, flg) \
-{ \
- .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 = SDE_FETCH_LINEAR, \
- .is_yuv = true, \
- .flag = flg \
-}
-
-#define PSEDUO_YUV_FMT(fmt, a, r, g, b, e0, e1, chroma, flg) \
-{ \
- .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 = SDE_FETCH_LINEAR, \
- .is_yuv = true, \
- .flag = flg \
-}
-
-#define PLANAR_YUV_FMT(fmt, a, r, g, b, e0, e1, e2, alpha, chroma, bp, flg)\
-{ \
- .base.pixel_format = DRM_FORMAT_ ## fmt, \
- .fetch_planes = SDE_PLANE_INTERLEAVED, \
- .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 = 0, \
- .bpp = bp, \
- .fetch_mode = SDE_FETCH_LINEAR, \
- .is_yuv = true, \
- .flag = flg \
-}
-
-/**
- * sde_get_sde_format_ext(): Returns sde format structure pointer.
+ * sde_get_sde_format_ext() - Returns sde format structure pointer.
* @format: DRM FourCC Code
* @modifiers: format modifier array from client, one per plane
* @modifiers_len: number of planes and array size for plane_modifiers
@@ -115,7 +30,7 @@
#define sde_get_sde_format(f) sde_get_sde_format_ext(f, NULL, 0)
/**
- * sde_get_msm_format: get an sde_format by its msm_format base
+ * sde_get_msm_format - get an sde_format by its msm_format base
* callback function registers with the msm_kms layer
* @kms: kms driver
* @format: DRM FourCC Code
@@ -129,7 +44,7 @@
const uint32_t modifiers_len);
/**
- * sde_populate_formats: populate the given array with fourcc codes supported
+ * sde_populate_formats - populate the given array with fourcc codes supported
* @pixel_formats: array to populate with fourcc codes
* @max_formats: length of pixel formats array
* @rgb_only: exclude any non-rgb formats from the list
@@ -141,4 +56,34 @@
uint32_t max_formats,
bool rgb_only);
+/**
+ * sde_format_check_modified_format - validate format and buffers for
+ * sde non-standard, i.e. modified format
+ * @kms: kms driver
+ * @msm_fmt: pointer to the msm_fmt base pointer of an sde_format
+ * @cmd: fb_cmd2 structure user request
+ * @bos: gem buffer object list
+ *
+ * Return: error code on failure, 0 on success
+ */
+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);
+
+/**
+ * sde_format_populate_layout - populate the given format layout based on
+ * mmu, fb, and format found in the fb
+ * @mmu_id: mmu id handle
+ * @fb: framebuffer pointer
+ * @fmtl: format layout structure to populate
+ *
+ * Return: error code on failure, 0 on success
+ */
+int sde_format_populate_layout(
+ int mmu_id,
+ struct drm_framebuffer *fb,
+ struct sde_hw_fmt_layout *fmtl);
+
#endif /*_SDE_FORMATS_H */
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_cdm.c b/drivers/gpu/drm/msm/sde/sde_hw_cdm.c
index 77cddba..c6ec854 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_cdm.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_cdm.c
@@ -223,7 +223,7 @@
u32 cdm_enable = 0;
u32 csc = 0;
- if (!fmt->is_yuv)
+ if (!SDE_FORMAT_IS_YUV(fmt))
return 0;
if (cdm->output_type == CDM_CDWN_OUTPUT_HDMI) {
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_intf.c b/drivers/gpu/drm/msm/sde/sde_hw_intf.c
index fca3d792..d4c8a44 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_intf.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_intf.c
@@ -159,7 +159,7 @@
(vsync_polarity << 1) | /* VSYNC Polarity */
(hsync_polarity << 0); /* HSYNC Polarity */
- if (!fmt->is_yuv)
+ if (!SDE_FORMAT_IS_YUV(fmt))
panel_format = (fmt->bits[C0_G_Y] |
(fmt->bits[C1_B_Cb] << 2) |
(fmt->bits[C2_R_Cr] << 4) |
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_mdss.h b/drivers/gpu/drm/msm/sde/sde_hw_mdss.h
index d696cb8..9d2fea7 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_mdss.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_mdss.h
@@ -38,6 +38,13 @@
#define PIPES_PER_STAGE 2
+#define SDE_FORMAT_FLAG_YUV (1 << 0)
+#define SDE_FORMAT_FLAG_ROTATOR (1 << 1)
+
+#define SDE_FORMAT_IS_YUV(X) ((X)->flag & SDE_FORMAT_FLAG_YUV)
+#define SDE_FORMAT_IS_ROTATOR(X) ((X)->flag & SDE_FORMAT_FLAG_ROTATOR)
+#define SDE_FORMAT_IS_UBWC(X) ((X)->fetch_mode == SDE_FETCH_UBWC)
+
enum sde_mdp {
MDP_TOP = 0x1,
MDP_MAX,
@@ -223,11 +230,10 @@
};
/**
- * enum sde_fetch_type - format id, used by drm-driver only to map drm forcc
- * Defines How HW fetches data
- * @SDE_FETCH_LINEAR : Fetch is line by line
- * @SDE_FETCH_TILE : Fetches data in Z order from a tile
- * @SDE_FETCH_UBWC : Fetch and decompress data
+ * sde_fetch_type - Defines How SDE HW fetches data
+ * @SDE_FETCH_LINEAR : fetch is line by line
+ * @SDE_FETCH_TILE : fetches data in Z order from a tile
+ * @SDE_FETCH_UBWC : fetch and decompress data
*/
enum sde_fetch_type {
SDE_FETCH_LINEAR,
@@ -240,10 +246,12 @@
* expected by the HW programming.
*/
enum {
- COLOR_1BIT = 0,
- COLOR_5BIT = 1,
- COLOR_6BIT = 2,
- COLOR_8BIT = 3,
+ COLOR_ALPHA_1BIT = 0,
+ COLOR_ALPHA_4BIT = 1,
+ COLOR_4BIT = 0,
+ COLOR_5BIT = 1, /* No 5-bit Alpha */
+ COLOR_6BIT = 2, /* 6-Bit Alpha also = 2 */
+ COLOR_8BIT = 3, /* 8-Bit Alpha also = 3 */
};
enum sde_alpha_blend_type {
@@ -254,7 +262,6 @@
ALPHA_MAX
};
-
/**
* enum sde_3d_blend_mode
* Desribes how the 3d data is blended
@@ -274,26 +281,24 @@
BLEND_3D_MAX
};
-struct addr_info {
- u32 plane[SDE_MAX_PLANES];
-};
-
-/**
- * struct sde_format - defines the format configuration which
+/** struct sde_format - defines the format configuration which
* allows SDE HW to correctly fetch and decode the format
- * @base : Base msm_format structure containing fourcc code
- * @fetch_planes
- * @element
- * @bits
- * @chroma_sample
- * @unpack_align_msb
- * @unpack_tight
- * @unpack_count
- * @bpp
- * @alpha_enable
- * @fetch_mode
- * @is_yuv
- * @flag
+ * @base: base msm_format struture containing fourcc code
+ * @fetch_planes: how the color components are packed in pixel format
+ * @element: element color ordering
+ * @bits: element bit widths
+ * @chroma_sample: chroma sub-samplng type
+ * @unpack_align_msb: unpack aligned, 0 to LSB, 1 to MSB
+ * @unpack_tight: 0 for loose, 1 for tight
+ * @unpack_count: 0 = 1 component, 1 = 2 component
+ * @bpp: bytes per pixel
+ * @alpha_enable: whether the format has an alpha channel
+ * @num_planes: number of planes (including meta data planes)
+ * @fetch_mode: linear, tiled, or ubwc hw fetch behavior
+ * @is_yuv: is format a yuv variant
+ * @flag: usage bit flags
+ * @tile_width: format tile width
+ * @tile_height: format tile height
*/
struct sde_format {
struct msm_format base;
@@ -301,30 +306,39 @@
u8 element[SDE_MAX_PLANES];
u8 bits[SDE_MAX_PLANES];
enum sde_chroma_samp_type chroma_sample;
- u8 unpack_align_msb; /* 0 to LSB, 1 to MSB */
- u8 unpack_tight; /* 0 for loose, 1 for tight */
- u8 unpack_count; /* 0 = 1 component, 1 = 2 component ... */
- u8 bpp; /* Bytes per pixel */
- u8 alpha_enable; /* source has alpha */
+ u8 unpack_align_msb;
+ u8 unpack_tight;
+ u8 unpack_count;
+ u8 bpp;
+ u8 alpha_enable;
+ u8 num_planes;
enum sde_fetch_type fetch_mode;
- u8 is_yuv;
u32 flag;
+ u16 tile_width;
+ u16 tile_height;
};
#define to_sde_format(x) container_of(x, struct sde_format, base)
/**
- * struct sde_hw_source_info - format information of the source pixel data
- * @format : pixel format parameters
- * @width : image width @height: image height
- * @num_planes : number of planes including the meta data planes for the
- * compressed formats @plane: per plane information
+ * struct sde_hw_fmt_layout - format information of the source pixel data
+ * @format: pixel format parameters
+ * @num_planes: number of planes (including meta data planes)
+ * @width: image width
+ * @height: image height
+ * @total_size: total size in bytes
+ * @plane_addr: address of each plane
+ * @plane_size: length of each plane
+ * @plane_pitch: pitch of each plane
*/
-struct sde_hw_source_info {
+struct sde_hw_fmt_layout {
const struct sde_format *format;
- u32 width;
- u32 height;
- u32 num_planes;
- u32 ystride[SDE_MAX_PLANES];
+ uint32_t num_planes;
+ uint32_t width;
+ uint32_t height;
+ uint32_t total_size;
+ uint32_t plane_addr[SDE_MAX_PLANES];
+ uint32_t plane_size[SDE_MAX_PLANES];
+ uint32_t plane_pitch[SDE_MAX_PLANES];
};
struct sde_rect {
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_sspp.c b/drivers/gpu/drm/msm/sde/sde_hw_sspp.c
index 94539ce..400a553 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_sspp.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_sspp.c
@@ -194,8 +194,7 @@
if (flags & SDE_SSPP_ROT_90)
src_format |= BIT(11); /* ROT90 */
- if (fmt->alpha_enable &&
- fmt->fetch_planes != SDE_PLANE_INTERLEAVED)
+ if (fmt->alpha_enable && fmt->fetch_planes == SDE_PLANE_INTERLEAVED)
src_format |= BIT(8); /* SRCC3_EN */
if (flags & SDE_SSPP_SOLID_FILL)
@@ -220,12 +219,12 @@
opmode |= MDSS_MDP_OP_PE_OVERRIDE;
/* if this is YUV pixel format, enable CSC */
- if (fmt->is_yuv)
+ if (SDE_FORMAT_IS_YUV(fmt))
src_format |= BIT(15);
/* update scaler opmode, if appropriate */
_sspp_setup_opmode(ctx,
- VIG_OP_CSC_EN | VIG_OP_CSC_SRC_DATAFMT, fmt->is_yuv);
+ VIG_OP_CSC_EN | VIG_OP_CSC_SRC_DATAFMT, SDE_FORMAT_IS_YUV(fmt));
SDE_REG_WRITE(c, SSPP_SRC_FORMAT + idx, src_format);
SDE_REG_WRITE(c, SSPP_SRC_UNPACK_PATTERN + idx, unpack);
@@ -375,10 +374,10 @@
dst_xy = (cfg->dst_rect.y << 16) | (cfg->dst_rect.x);
dst_size = (cfg->dst_rect.h << 16) | (cfg->dst_rect.w);
- ystride0 = (cfg->src.ystride[0]) |
- (cfg->src.ystride[1] << 16);
- ystride1 = (cfg->src.ystride[2]) |
- (cfg->src.ystride[3] << 16);
+ ystride0 = (cfg->layout.plane_pitch[0]) |
+ (cfg->layout.plane_pitch[1] << 16);
+ ystride1 = (cfg->layout.plane_pitch[2]) |
+ (cfg->layout.plane_pitch[3] << 16);
/* program scaler, phase registers, if pipes supporting scaling */
if (ctx->cap->features & SDE_SSPP_SCALER) {
@@ -409,9 +408,9 @@
if (_sspp_subblk_offset(ctx, SDE_SSPP_SRC, &idx))
return;
- for (i = 0; i < cfg->src.num_planes; i++)
- SDE_REG_WRITE(&ctx->hw, SSPP_SRC0_ADDR + idx + i*0x4,
- cfg->addr.plane[i]);
+ for (i = 0; i < ARRAY_SIZE(cfg->layout.plane_addr); i++)
+ SDE_REG_WRITE(&ctx->hw, SSPP_SRC0_ADDR + idx + i * 0x4,
+ cfg->layout.plane_addr[i]);
}
static void sde_hw_sspp_setup_csc(struct sde_hw_pipe *ctx,
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_sspp.h b/drivers/gpu/drm/msm/sde/sde_hw_sspp.h
index ab7ed86..7eb4981 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_sspp.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_sspp.h
@@ -125,7 +125,7 @@
/**
* struct sde_hw_pipe_cfg : Pipe description
- * @src: source surface information
+ * @layout: format layout information for programming buffer to hardware
* @src_rect: src ROI, caller takes into account the different operations
* such as decimation, flip etc to program this field
* @dest_rect: destination ROI.
@@ -135,15 +135,13 @@
* 4: Read 1 line/pixel drop 3 lines/pixels
* 8: Read 1 line/pixel drop 7 lines/pixels
* 16: Read 1 line/pixel drop 15 line/pixels
- * @addr: source surface address
*/
struct sde_hw_pipe_cfg {
- struct sde_hw_source_info src;
+ struct sde_hw_fmt_layout layout;
struct sde_rect src_rect;
struct sde_rect dst_rect;
u8 horz_decimation;
u8 vert_decimation;
- struct addr_info addr;
};
/**
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_wb.h b/drivers/gpu/drm/msm/sde/sde_hw_wb.h
index b5a12eb..093d2fb 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_wb.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_wb.h
@@ -20,7 +20,7 @@
struct sde_hw_wb;
struct sde_hw_wb_cfg {
- struct sde_hw_source_info dest;
+ struct sde_hw_fmt_layout dest;
};
/**
diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c
index 22d87f3..38afae4 100644
--- a/drivers/gpu/drm/msm/sde/sde_kms.c
+++ b/drivers/gpu/drm/msm/sde/sde_kms.c
@@ -318,6 +318,7 @@
.wait_for_crtc_commit_done = sde_wait_for_crtc_commit_done,
.enable_vblank = sde_enable_vblank,
.disable_vblank = sde_disable_vblank,
+ .check_modified_format = sde_format_check_modified_format,
.get_format = sde_get_msm_format,
.round_pixclk = sde_round_pixclk,
.preclose = sde_preclose,
@@ -627,6 +628,11 @@
dev->mode_config.max_width = catalog->mixer[0].sblk->maxwidth;
dev->mode_config.max_height = 4096;
+ /*
+ * Support format modifiers for compression etc.
+ */
+ dev->mode_config.allow_fb_modifiers = true;
+
sde_kms->hw_intr = sde_rm_acquire_intr(sde_kms);
if (IS_ERR_OR_NULL(sde_kms->hw_intr))
diff --git a/drivers/gpu/drm/msm/sde/sde_plane.c b/drivers/gpu/drm/msm/sde/sde_plane.c
index a7c38bf..0f8a8e1 100644
--- a/drivers/gpu/drm/msm/sde/sde_plane.c
+++ b/drivers/gpu/drm/msm/sde/sde_plane.c
@@ -43,7 +43,7 @@
enum sde_sspp pipe;
uint32_t features; /* capabilities from catalog */
uint32_t nformats;
- uint32_t formats[32];
+ uint32_t formats[64];
struct sde_hw_pipe *pipe_hw;
struct sde_hw_pipe_cfg pipe_cfg;
@@ -135,39 +135,30 @@
static void _sde_plane_set_scanout(struct drm_plane *plane,
struct sde_plane_state *pstate,
- struct sde_hw_pipe_cfg *pipe_cfg, struct drm_framebuffer *fb)
+ struct sde_hw_pipe_cfg *pipe_cfg,
+ struct drm_framebuffer *fb)
{
struct sde_plane *psde;
- unsigned int shift;
- int i;
+ int ret, i;
if (!plane || !pstate || !pipe_cfg || !fb)
return;
psde = to_sde_plane(plane);
- if (psde->pipe_hw && psde->pipe_hw->ops.setup_sourceaddress) {
- /* stride */
- if (sde_plane_get_property(pstate, PLANE_PROP_SRC_CONFIG) &
- BIT(SDE_DRM_DEINTERLACE))
- shift = 1;
- else
- shift = 0;
-
- i = min_t(int, ARRAY_SIZE(fb->pitches), SDE_MAX_PLANES);
- while (i) {
- --i;
- pipe_cfg->src.ystride[i] = fb->pitches[i] << shift;
- }
-
- /* address */
- for (i = 0; i < ARRAY_SIZE(pipe_cfg->addr.plane); ++i)
- pipe_cfg->addr.plane[i] = msm_framebuffer_iova(fb,
- psde->mmu_id, i);
-
- /* hw driver */
- psde->pipe_hw->ops.setup_sourceaddress(psde->pipe_hw, pipe_cfg);
+ ret = sde_format_populate_layout(psde->mmu_id, fb, &pipe_cfg->layout);
+ if (ret) {
+ DRM_ERROR("failed to get format layout, error: %d\n", ret);
+ return;
}
+
+ if (sde_plane_get_property(pstate, PLANE_PROP_SRC_CONFIG) &
+ BIT(SDE_DRM_DEINTERLACE))
+ for (i = 0; i < SDE_MAX_PLANES; ++i)
+ pipe_cfg->layout.plane_pitch[i] <<= 1;
+
+ if (psde->pipe_hw && psde->pipe_hw->ops.setup_sourceaddress)
+ psde->pipe_hw->ops.setup_sourceaddress(psde->pipe_hw, pipe_cfg);
}
static void _sde_plane_setup_scaler3(struct sde_plane *psde,
@@ -712,9 +703,9 @@
psde = to_sde_plane(plane);
pstate = to_sde_plane_state(plane->state);
- nplanes = drm_format_num_planes(fb->pixel_format);
fmt = to_sde_format(msm_framebuffer_format(fb));
+ nplanes = fmt->num_planes;
/* src values are in Q16 fixed point, convert to integer */
src_x = src_x >> 16;
@@ -722,19 +713,17 @@
src_w = src_w >> 16;
src_h = src_h >> 16;
- DBG("%s: FB[%u] %u,%u,%u,%u -> CRTC[%u] %d,%d,%u,%u", psde->pipe_name,
+ DBG("%s: FB[%u] %u,%u,%u,%u -> CRTC[%u] %d,%d,%u,%u, %s ubwc %d",
+ psde->pipe_name,
fb->base.id, src_x, src_y, src_w, src_h,
- crtc->base.id, crtc_x, crtc_y, crtc_w, crtc_h);
+ crtc->base.id, crtc_x, crtc_y, crtc_w, crtc_h,
+ drm_get_format_name(fmt->base.pixel_format),
+ SDE_FORMAT_IS_UBWC(fmt));
/* update format configuration */
memset(&(psde->pipe_cfg), 0, sizeof(struct sde_hw_pipe_cfg));
src_flags = 0;
- psde->pipe_cfg.src.format = fmt;
- psde->pipe_cfg.src.width = fb->width;
- psde->pipe_cfg.src.height = fb->height;
- psde->pipe_cfg.src.num_planes = nplanes;
-
/* flags */
DBG("Flags 0x%llX, rotation 0x%llX",
sde_plane_get_property(pstate, PLANE_PROP_SRC_CONFIG),
@@ -762,9 +751,6 @@
psde->pipe_cfg.dst_rect.w = crtc_w;
psde->pipe_cfg.dst_rect.h = crtc_h;
- /* get sde pixel format definition */
- fmt = psde->pipe_cfg.src.format;
-
/* check for color fill */
psde->color_fill = (uint32_t)sde_plane_get_property(pstate,
PLANE_PROP_COLOR_FILL);
@@ -835,6 +821,42 @@
return 0;
}
+static void _sde_plane_atomic_check_mode_changed(struct sde_plane *psde,
+ struct drm_plane_state *state,
+ struct drm_plane_state *old_state)
+{
+ struct sde_plane_state *pstate = to_sde_plane_state(state);
+
+ if (!(sde_plane_enabled(state) && sde_plane_enabled(old_state))) {
+ DBG("%s: pipe enabling/disabling full modeset required",
+ psde->pipe_name);
+ pstate->mode_changed = true;
+ } else if (to_sde_plane_state(old_state)->pending) {
+ DBG("%s: still pending", psde->pipe_name);
+ pstate->mode_changed = true;
+ } else if (state->src_w != old_state->src_w ||
+ state->src_h != old_state->src_h) {
+ DBG("%s: src_w change", psde->pipe_name);
+ pstate->mode_changed = true;
+ } else if (state->fb->pixel_format != old_state->fb->pixel_format) {
+ DBG("%s: format change!", psde->pipe_name);
+ pstate->mode_changed = true;
+ } else {
+ uint64_t *new_mods = state->fb->modifier;
+ uint64_t *old_mods = old_state->fb->modifier;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(state->fb->modifier); i++) {
+ if (new_mods[i] != old_mods[i]) {
+ DBG("%s: format modifiers change",
+ psde->pipe_name);
+ pstate->mode_changed = true;
+ break;
+ }
+ }
+ }
+}
+
static int sde_plane_atomic_check(struct drm_plane *plane,
struct drm_plane_state *state)
{
@@ -994,32 +1016,8 @@
}
}
- if (!ret) {
- if (sde_plane_enabled(state) &&
- sde_plane_enabled(old_state)) {
- bool full_modeset = false;
-
- if (state->fb->pixel_format !=
- old_state->fb->pixel_format) {
- DBG("%s: format change!", psde->pipe_name);
- full_modeset = true;
- }
- if (state->src_w != old_state->src_w ||
- state->src_h != old_state->src_h) {
- DBG("%s: src_w change!", psde->pipe_name);
- full_modeset = true;
- }
- if (to_sde_plane_state(old_state)->pending) {
- DBG("%s: still pending!", psde->pipe_name);
- full_modeset = true;
- }
- if (full_modeset)
- to_sde_plane_state(state)->mode_changed = true;
-
- } else {
- to_sde_plane_state(state)->mode_changed = true;
- }
- }
+ if (!ret)
+ _sde_plane_atomic_check_mode_changed(psde, state, old_state);
exit:
return ret;