diff options
| author | Lloyd Atkinson <latkinso@codeaurora.org> | 2016-05-25 15:16:03 -0400 |
|---|---|---|
| committer | Dhaval Patel <pdhaval@codeaurora.org> | 2016-08-01 12:35:45 -0700 |
| commit | 89c2d41346a9e1151d3967dc143dc0864c8d71bb (patch) | |
| tree | e0628662e2b538282f9281da1c3dcf69650205b5 /drivers/gpu | |
| parent | a4670abc599ca4c935931e74e2c9f0b9913c50ae (diff) | |
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>
Diffstat (limited to 'drivers/gpu')
| -rw-r--r-- | drivers/gpu/drm/msm/sde/sde_formats.c | 731 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/sde/sde_formats.h | 121 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/sde/sde_hw_cdm.c | 2 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/sde/sde_hw_intf.c | 2 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/sde/sde_hw_mdss.h | 104 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/sde/sde_hw_sspp.c | 21 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/sde/sde_hw_sspp.h | 6 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/sde/sde_hw_wb.h | 2 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/sde/sde_kms.c | 6 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/sde/sde_plane.c | 118 |
10 files changed, 856 insertions, 257 deletions
diff --git a/drivers/gpu/drm/msm/sde/sde_formats.c b/drivers/gpu/drm/msm/sde/sde_formats.c index 78d672ee8fd5..25dac8cf1929 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 @@ const struct sde_format *sde_get_sde_format_ext( } } - 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 545633b9011c..3400b145c5a6 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 @@ const struct sde_format *sde_get_sde_format_ext( #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 struct msm_format *sde_get_msm_format( 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 sde_populate_formats( 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 77cddba9e59e..c6ec854d01b7 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 @@ int sde_hw_cdm_enable(struct sde_hw_cdm *ctx, 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 77142bbec228..db5781cc58f1 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 @@ static void sde_hw_intf_setup_timing_engine(struct sde_hw_intf *ctx, (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 d696cb85f5de..9d2fea7320fe 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_chroma_samp_type { }; /** - * 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 @@ enum sde_fetch_type { * 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 @@ enum sde_alpha_blend_type { ALPHA_MAX }; - /** * enum sde_3d_blend_mode * Desribes how the 3d data is blended @@ -274,26 +281,24 @@ enum sde_3d_blend_mode { 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 @@ struct sde_format { 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 94539ce70427..400a5539ce8b 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 @@ static void sde_hw_sspp_setup_format(struct sde_hw_pipe *ctx, 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 @@ static void sde_hw_sspp_setup_format(struct sde_hw_pipe *ctx, 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 @@ static void sde_hw_sspp_setup_rects(struct sde_hw_pipe *ctx, 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 @@ static void sde_hw_sspp_setup_sourceaddress(struct sde_hw_pipe *ctx, 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 ab7ed86a2379..7eb4981f79c5 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_scaler3_cfg { /** * 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 @@ struct sde_hw_scaler3_cfg { * 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 b5a12eb7c5eb..093d2fbad91b 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 22d87f35b6a5..38afae405517 100644 --- a/drivers/gpu/drm/msm/sde/sde_kms.c +++ b/drivers/gpu/drm/msm/sde/sde_kms.c @@ -318,6 +318,7 @@ static const struct msm_kms_funcs kms_funcs = { .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 @@ struct msm_kms *sde_kms_init(struct drm_device *dev) 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 6a27a6dcc1b2..f3f639cf7836 100644 --- a/drivers/gpu/drm/msm/sde/sde_plane.c +++ b/drivers/gpu/drm/msm/sde/sde_plane.c @@ -43,7 +43,7 @@ struct sde_plane { 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 @@ int sde_plane_wait_input_fence(struct drm_plane *plane, uint32_t wait_ms) 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; - } + 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; + } - /* 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); + 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; - /* hw driver */ + 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 @@ static int _sde_plane_mode_set(struct drm_plane *plane, 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 @@ static int _sde_plane_mode_set(struct drm_plane *plane, 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 @@ static int _sde_plane_mode_set(struct drm_plane *plane, 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 @@ static int _sde_plane_atomic_check_fb(struct sde_plane *psde, 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 @@ static int sde_plane_atomic_check(struct drm_plane *plane, } } - 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; |
