From 31646184c9df479e0cd1b985b6fd09cfb78e2c3f Mon Sep 17 00:00:00 2001 From: Dhaval Patel Date: Fri, 22 Aug 2014 14:04:38 -0700 Subject: [PATCH] mdss: mdp: add UBWC format support in MDSS driver UBWC format is supported for pipe input and WB0 & WB1 output for MDPv(1.7). This new format also has specific buffer configuration requirement for bit stream and meta data. This change adds UBWC support in MDSS driver and put checks for format support in various use cases and register configuration. Change-Id: I29c262a94461d7571bead63f60517875eaaa5e5b Signed-off-by: Dhaval Patel --- drivers/video/fbdev/msm/mdss_mdp.h | 16 +- drivers/video/fbdev/msm/mdss_mdp_formats.h | 6 + .../video/fbdev/msm/mdss_mdp_intf_writeback.c | 16 +- drivers/video/fbdev/msm/mdss_mdp_pipe.c | 14 +- drivers/video/fbdev/msm/mdss_mdp_util.c | 208 ++++++++++++++++-- include/uapi/linux/msm_mdp.h | 3 + 6 files changed, 230 insertions(+), 33 deletions(-) diff --git a/drivers/video/fbdev/msm/mdss_mdp.h b/drivers/video/fbdev/msm/mdss_mdp.h index 0cafeaf2d550..7c0d89c31946 100644 --- a/drivers/video/fbdev/msm/mdss_mdp.h +++ b/drivers/video/fbdev/msm/mdss_mdp.h @@ -137,6 +137,7 @@ enum mdss_mdp_panic_signal_type { enum mdss_mdp_fetch_type { MDSS_MDP_FETCH_LINEAR, MDSS_MDP_FETCH_TILE, + MDSS_MDP_FETCH_UBWC, }; /** @@ -710,6 +711,16 @@ static inline bool mdss_mdp_is_tile_format(struct mdss_mdp_format_params *fmt) return fmt && (fmt->fetch_mode == MDSS_MDP_FETCH_TILE); } +static inline bool mdss_mdp_is_ubwc_format(struct mdss_mdp_format_params *fmt) +{ + return fmt && (fmt->fetch_mode == MDSS_MDP_FETCH_UBWC); +} + +static inline int mdss_mdp_is_ubwc_supported(struct mdss_data_type *mdata) +{ + return IS_MDSS_MAJOR_MINOR_SAME(mdata->mdp_rev, MDSS_MDP_HW_REV_107); +} + irqreturn_t mdss_mdp_isr(int irq, void *ptr); int mdss_iommu_attach(struct mdss_data_type *mdata); int mdss_iommu_dettach(struct mdss_data_type *mdata); @@ -899,8 +910,9 @@ int mdss_mdp_pipe_queue_data(struct mdss_mdp_pipe *pipe, int mdss_mdp_vbif_axi_halt(struct mdss_data_type *mdata); int mdss_mdp_data_check(struct mdss_mdp_data *data, - struct mdss_mdp_plane_sizes *ps); -int mdss_mdp_get_plane_sizes(u32 format, u32 w, u32 h, + struct mdss_mdp_plane_sizes *ps, + struct mdss_mdp_format_params *fmt); +int mdss_mdp_get_plane_sizes(struct mdss_mdp_format_params *fmt, u32 w, u32 h, struct mdss_mdp_plane_sizes *ps, u32 bwc_mode, bool rotation); int mdss_mdp_get_rau_strides(u32 w, u32 h, struct mdss_mdp_format_params *fmt, struct mdss_mdp_plane_sizes *ps); diff --git a/drivers/video/fbdev/msm/mdss_mdp_formats.h b/drivers/video/fbdev/msm/mdss_mdp_formats.h index bfda4986a088..fb76a254ebcf 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_formats.h +++ b/drivers/video/fbdev/msm/mdss_mdp_formats.h @@ -167,6 +167,8 @@ static struct mdss_mdp_format_params mdss_mdp_format_map[] = { C1_B_Cb, C0_G_Y, C2_R_Cr), FMT_RGB_565(MDP_BGR_565_TILE, MDSS_MDP_FETCH_TILE, C2_R_Cr, C0_G_Y, C1_B_Cb), + FMT_RGB_565(MDP_RGB_565_UBWC, MDSS_MDP_FETCH_UBWC, + C1_B_Cb, C0_G_Y, C2_R_Cr), FMT_RGB_888(MDP_RGB_888, MDSS_MDP_FETCH_LINEAR, C2_R_Cr, C0_G_Y, C1_B_Cb), FMT_RGB_888(MDP_BGR_888, MDSS_MDP_FETCH_LINEAR, @@ -200,6 +202,8 @@ static struct mdss_mdp_format_params mdss_mdp_format_map[] = { 0, C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr), FMT_RGB_8888(MDP_BGRX_8888_TILE, MDSS_MDP_FETCH_TILE, 0, C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA), + FMT_RGB_8888(MDP_RGBA_8888_UBWC, MDSS_MDP_FETCH_UBWC, + 1, C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA), FMT_YUV_PSEUDO(MDP_Y_CRCB_H1V1, MDSS_MDP_FETCH_LINEAR, MDSS_MDP_CHROMA_RGB, C2_R_Cr, C1_B_Cb), @@ -219,6 +223,8 @@ static struct mdss_mdp_format_params mdss_mdp_format_map[] = { MDSS_MDP_CHROMA_420, C1_B_Cb, C2_R_Cr), FMT_YUV_PSEUDO(MDP_Y_CBCR_H2V2_VENUS, MDSS_MDP_FETCH_LINEAR, MDSS_MDP_CHROMA_420, C1_B_Cb, C2_R_Cr), + FMT_YUV_PSEUDO(MDP_Y_CBCR_H2V2_UBWC, MDSS_MDP_FETCH_UBWC, + MDSS_MDP_CHROMA_420, C1_B_Cb, C2_R_Cr), FMT_YUV_PLANR(MDP_Y_CB_CR_H2V2, MDSS_MDP_FETCH_LINEAR, MDSS_MDP_CHROMA_420, C2_R_Cr, C1_B_Cb), diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_writeback.c b/drivers/video/fbdev/msm/mdss_mdp_intf_writeback.c index 680b5f4b565c..e095f963e08e 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_intf_writeback.c +++ b/drivers/video/fbdev/msm/mdss_mdp_intf_writeback.c @@ -123,7 +123,7 @@ static int mdss_mdp_writeback_addr_setup(struct mdss_mdp_writeback_ctx *ctx, if (ctx->bwc_mode) data.bwc_enabled = 1; - ret = mdss_mdp_data_check(&data, &ctx->dst_planes); + ret = mdss_mdp_data_check(&data, &ctx->dst_planes, ctx->dst_fmt); if (ret) return ret; @@ -153,15 +153,16 @@ static int mdss_mdp_writeback_format_setup(struct mdss_mdp_writeback_ctx *ctx, if (ctx->rot90) rotation = true; - mdss_mdp_get_plane_sizes(format, ctx->width, ctx->height, - &ctx->dst_planes, - ctx->opmode & MDSS_MDP_OP_BWC_EN, rotation); - fmt = mdss_mdp_get_format_params(format); if (!fmt) { pr_err("wb format=%d not supported\n", format); return -EINVAL; } + + mdss_mdp_get_plane_sizes(fmt, ctx->width, ctx->height, + &ctx->dst_planes, + ctx->opmode & MDSS_MDP_OP_BWC_EN, rotation); + ctx->dst_fmt = fmt; chroma_samp = fmt->chroma_sample; @@ -231,6 +232,11 @@ static int mdss_mdp_writeback_format_setup(struct mdss_mdp_writeback_ctx *ctx, (ctx->dst_planes.ystride[3] << 16); outsize = (ctx->dst_rect.h << 16) | ctx->dst_rect.w; + if (mdss_mdp_is_ubwc_format(fmt)) { + opmode |= BIT(0); + dst_format |= BIT(31); + } + if (ctx->type == MDSS_MDP_WRITEBACK_TYPE_ROTATOR && mdata->has_rot_dwnscale) { dnsc_factor = (ctx->dnsc_factor_h) | (ctx->dnsc_factor_w << 16); diff --git a/drivers/video/fbdev/msm/mdss_mdp_pipe.c b/drivers/video/fbdev/msm/mdss_mdp_pipe.c index 826b9bdc170c..22b9a2b6a242 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_pipe.c +++ b/drivers/video/fbdev/msm/mdss_mdp_pipe.c @@ -421,7 +421,7 @@ static int mdss_mdp_calc_stride(struct mdss_mdp_pipe *pipe, break; } } - rc = mdss_mdp_get_plane_sizes(format, width, pipe->src.h, + rc = mdss_mdp_get_plane_sizes(pipe->src_fmt, width, pipe->src.h, ps, 0, 0); if (rc) return rc; @@ -1321,11 +1321,12 @@ static int mdss_mdp_image_setup(struct mdss_mdp_pipe *pipe, if (pipe->flags & MDP_SOURCE_ROTATED_90) rotation = true; - mdss_mdp_get_plane_sizes(pipe->src_fmt->format, width, height, + mdss_mdp_get_plane_sizes(pipe->src_fmt, width, height, &pipe->src_planes, pipe->bwc_mode, rotation); if (data != NULL) { - ret = mdss_mdp_data_check(data, &pipe->src_planes); + ret = mdss_mdp_data_check(data, &pipe->src_planes, + pipe->src_fmt); if (ret) return ret; } @@ -1491,6 +1492,11 @@ static int mdss_mdp_format_setup(struct mdss_mdp_pipe *pipe) (fmt->unpack_align_msb << 18) | ((fmt->bpp - 1) << 9); + if (mdss_mdp_is_ubwc_format(fmt)) { + opmode |= BIT(0); + src_format |= BIT(31); + } + mdss_mdp_pipe_sspp_setup(pipe, &opmode); if (mdss_mdp_is_tile_format(fmt) && mdata->highest_bank_bit) { @@ -1546,7 +1552,7 @@ static int mdss_mdp_src_addr_setup(struct mdss_mdp_pipe *pipe, data.bwc_enabled = pipe->bwc_mode; - ret = mdss_mdp_data_check(&data, &pipe->src_planes); + ret = mdss_mdp_data_check(&data, &pipe->src_planes, pipe->src_fmt); if (ret) return ret; diff --git a/drivers/video/fbdev/msm/mdss_mdp_util.c b/drivers/video/fbdev/msm/mdss_mdp_util.c index f04d3d6a37f9..3a10c0556e9e 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_util.c +++ b/drivers/video/fbdev/msm/mdss_mdp_util.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -236,16 +236,21 @@ hist_isr_done: struct mdss_mdp_format_params *mdss_mdp_get_format_params(u32 format) { - if (format < MDP_IMGTYPE_LIMIT) { - struct mdss_mdp_format_params *fmt = NULL; - int i; - for (i = 0; i < ARRAY_SIZE(mdss_mdp_format_map); i++) { - fmt = &mdss_mdp_format_map[i]; - if (format == fmt->format) - return fmt; - } + struct mdss_mdp_format_params *fmt = NULL; + struct mdss_data_type *mdata = mdss_mdp_get_mdata(); + int i; + + if (format > MDP_IMGTYPE_LIMIT) + goto end; + + for (i = 0; i < ARRAY_SIZE(mdss_mdp_format_map); i++) { + fmt = &mdss_mdp_format_map[i]; + if (format == fmt->format) + break; } - return NULL; +end: + return (mdss_mdp_is_ubwc_format(fmt) && + !mdss_mdp_is_ubwc_supported(mdata)) ? NULL : fmt; } void mdss_mdp_intersect_rect(struct mdss_rect *res_rect, @@ -324,11 +329,68 @@ int mdss_mdp_get_rau_strides(u32 w, u32 h, return 0; } -int mdss_mdp_get_plane_sizes(u32 format, u32 w, u32 h, +static int mdss_mdp_get_ubwc_plane_size(struct mdss_mdp_format_params *fmt, + u32 width, u32 height, struct mdss_mdp_plane_sizes *ps) +{ + int rc = 0; + struct mdss_data_type *mdata = mdss_mdp_get_mdata(); + + if (!mdss_mdp_is_ubwc_supported(mdata)) { + pr_err("ubwc format is not supported for format: %d\n", + fmt->format); + return -EINVAL; + } + + if (fmt->format == MDP_Y_CBCR_H2V2_UBWC) { + ps->num_planes = 4; + /* Y bitstream stride and plane size */ + ps->ystride[0] = ALIGN(width, 128); + ps->plane_size[0] = ALIGN(ps->ystride[0] * ALIGN(height, 32), + 4096); + + /* CbCr bitstream stride and plane size */ + ps->ystride[1] = ALIGN(width, 64); + ps->plane_size[1] = ALIGN(ps->ystride[1] * ALIGN(height, 32), + 4096); + + /* Y meta data stride and plane size */ + ps->ystride[2] = ALIGN(DIV_ROUND_UP(width, 32), 64); + ps->plane_size[2] = ALIGN(ps->ystride[2] * + ALIGN(DIV_ROUND_UP(height, 8), 16), 4096); + + /* CbCr meta data stride and plane size */ + ps->ystride[3] = ALIGN(DIV_ROUND_UP(width, 16), 64); + ps->plane_size[3] = ALIGN(ps->ystride[3] * + ALIGN(DIV_ROUND_UP(height, 8), 16), 4096); + + } else if (fmt->format == MDP_RGBA_8888_UBWC || + fmt->format == MDP_RGB_565_UBWC) { + uint32_t stride_alignment = (fmt->format == MDP_RGBA_8888_UBWC) + ? 64 : 128; + ps->num_planes = 2; + + /* RGB bitstream stride and plane size */ + ps->ystride[0] = ALIGN(width, stride_alignment); + ps->plane_size[0] = ALIGN(4 * ps->ystride[0] * + ALIGN(height, 16), 4096); + + /* RGB meta data stride and plane size */ + ps->ystride[2] = ALIGN(DIV_ROUND_UP(width, 16), 64); + ps->plane_size[2] = ALIGN(ps->ystride[2] * + ALIGN(DIV_ROUND_UP(height, 4), 16), 4096); + } else { + pr_err("%s: UBWC format not supported for fmt:%d\n", + __func__, fmt->format); + rc = -EINVAL; + } + + return rc; +} + +int mdss_mdp_get_plane_sizes(struct mdss_mdp_format_params *fmt, u32 w, u32 h, struct mdss_mdp_plane_sizes *ps, u32 bwc_mode, bool rotation) { - struct mdss_mdp_format_params *fmt; - int i, rc; + int i, rc = 0; u32 bpp; if (ps == NULL) return -EINVAL; @@ -336,14 +398,12 @@ int mdss_mdp_get_plane_sizes(u32 format, u32 w, u32 h, if ((w > MAX_IMG_WIDTH) || (h > MAX_IMG_HEIGHT)) return -ERANGE; - fmt = mdss_mdp_get_format_params(format); - if (!fmt) - return -EINVAL; - bpp = fmt->bpp; memset(ps, 0, sizeof(struct mdss_mdp_plane_sizes)); - if (bwc_mode) { + if (mdss_mdp_is_ubwc_format(fmt)) { + rc = mdss_mdp_get_ubwc_plane_size(fmt, w, h, ps); + } else if (bwc_mode) { u32 height, meta_size; rc = mdss_mdp_get_rau_strides(w, h, fmt, ps); @@ -366,7 +426,7 @@ int mdss_mdp_get_plane_sizes(u32 format, u32 w, u32 h, ps->num_planes = 1; ps->plane_size[0] = w * h * bpp; ps->ystride[0] = w * bpp; - } else if (format == MDP_Y_CBCR_H2V2_VENUS) { + } else if (fmt->format == MDP_Y_CBCR_H2V2_VENUS) { int cf = COLOR_FMT_NV12; ps->num_planes = 2; ps->ystride[0] = VENUS_Y_STRIDE(cf, w); @@ -398,7 +458,7 @@ int mdss_mdp_get_plane_sizes(u32 format, u32 w, u32 h, horiz = hmap[chroma_samp]; vert = vmap[chroma_samp]; - switch (format) { + switch (fmt->format) { case MDP_Y_CR_CB_GH2V2: stride_align = 16; height_align = 1; @@ -426,14 +486,115 @@ int mdss_mdp_get_plane_sizes(u32 format, u32 w, u32 h, } } } + for (i = 0; i < ps->num_planes; i++) ps->total_size += ps->plane_size[i]; - return 0; + return rc; +} + +static int mdss_mdp_ubwc_data_check(struct mdss_mdp_data *data, + struct mdss_mdp_plane_sizes *ps, + struct mdss_mdp_format_params *fmt) +{ + int i, rc = 0; + struct mdss_data_type *mdata = mdss_mdp_get_mdata(); + unsigned long data_size = 0; + dma_addr_t base_addr; + + if (!mdss_mdp_is_ubwc_supported(mdata)) { + pr_err("ubwc format is not supported for format: %d\n", + fmt->format); + goto end; + } + + for (i = 0; i < MAX_PLANES; i++) + data_size += data->p[i].len; + + if (data_size < ps->total_size) { + pr_err("insufficient current mem len=%lu required mem len=%u\n", + data_size, ps->total_size); + rc = -ENOMEM; + goto end; + } + + if (data->p[0].len == ps->plane_size[0]) + goto end; + + base_addr = data->p[0].addr; + + if (fmt->format == MDP_Y_CBCR_H2V2_UBWC) { + /************************************************/ + /* UBWC ** */ + /* buffer ** MDP PLANE */ + /* format ** */ + /************************************************/ + /* ------------------- ** -------------------- */ + /* | Y meta | ** | Y bitstream | */ + /* | data | ** | plane | */ + /* ------------------- ** -------------------- */ + /* | CbCr meta | ** | CbCr bitstream | */ + /* | data | ** | plane | */ + /* ------------------- ** -------------------- */ + /* | Y bitstream | ** | Y meta | */ + /* | data | ** | plane | */ + /* ------------------- ** -------------------- */ + /* | CbCr bitstream | ** | CbCr meta | */ + /* | data | ** | plane | */ + /* ------------------- ** -------------------- */ + /************************************************/ + + /* configure Y bitstream plane */ + data->p[0].addr = base_addr + ps->plane_size[2]; + data->p[0].len = ps->plane_size[0]; + + /* configure CbCr bitstream plane */ + data->p[1].addr = base_addr + ps->plane_size[0] + + ps->plane_size[1] + ps->plane_size[2]; + data->p[1].len = ps->plane_size[1]; + + /* configure Y metadata plane */ + data->p[2].addr = base_addr; + data->p[2].len = ps->plane_size[2]; + + /* configure CbCr metadata plane */ + data->p[3].addr = base_addr + ps->plane_size[0] + + ps->plane_size[2]; + data->p[3].len = ps->plane_size[3]; + } else { + /************************************************/ + /* UBWC ** */ + /* buffer ** MDP PLANE */ + /* format ** */ + /************************************************/ + /* ------------------- ** -------------------- */ + /* | RGB meta | ** | RGB bitstream | */ + /* | data | ** | plane | */ + /* ------------------- ** -------------------- */ + /* | RGB bitstream | ** | NONE | */ + /* | data | ** | | */ + /* ------------------- ** -------------------- */ + /* ** | RGB meta | */ + /* ** | plane | */ + /* ** -------------------- */ + /************************************************/ + + /* configure RGB bitstream plane */ + data->p[0].addr = base_addr + ps->plane_size[2]; + data->p[0].len = ps->plane_size[0]; + + /* configure RGB metadata plane */ + data->p[2].addr = base_addr; + data->p[2].len = ps->plane_size[2]; + } + data->num_planes = ps->num_planes; +end: + return rc; } int mdss_mdp_data_check(struct mdss_mdp_data *data, - struct mdss_mdp_plane_sizes *ps) + struct mdss_mdp_plane_sizes *ps, + struct mdss_mdp_format_params *fmt) { struct mdss_mdp_img_data *prev, *curr; int i; @@ -444,6 +605,9 @@ int mdss_mdp_data_check(struct mdss_mdp_data *data, if (!data || data->num_planes == 0) return -ENOMEM; + if (mdss_mdp_is_ubwc_format(fmt)) + return mdss_mdp_ubwc_data_check(data, ps, fmt); + pr_debug("srcp0=%pa len=%lu frame_size=%u\n", &data->p[0].addr, data->p[0].len, ps->total_size); diff --git a/include/uapi/linux/msm_mdp.h b/include/uapi/linux/msm_mdp.h index 9095d91bc232..2c1fa359d591 100644 --- a/include/uapi/linux/msm_mdp.h +++ b/include/uapi/linux/msm_mdp.h @@ -165,6 +165,9 @@ enum { MDP_RGBA_5551, /*RGBA 5551*/ MDP_ARGB_4444, /*ARGB 4444*/ MDP_RGBA_4444, /*RGBA 4444*/ + MDP_RGB_565_UBWC, + MDP_RGBA_8888_UBWC, + MDP_Y_CBCR_H2V2_UBWC, MDP_IMGTYPE_LIMIT, MDP_RGB_BORDERFILL, /* border fill pipe */ MDP_FB_FORMAT = MDP_IMGTYPE2_START, /* framebuffer format */