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 */