From db37c5bdcc2a751c26556988500ac1d0be2f15aa Mon Sep 17 00:00:00 2001 From: Dhaval Patel Date: Wed, 20 Apr 2016 17:35:25 -0700 Subject: [PATCH] msm: mdp: reserve cdm block only for output yuv format WB and HDMI interface reserves the CDM block on start irrespective of output format selection. This blocks other interface open operation. CDM block is only needed for output yuv format to downsample the chroma. This change starts allocating cdm block on each kickoff for writeback interface. It allocates cdm block only for yuv format for hdmi interface. Change-Id: I4368d1b5c4453c6c4697c060c880833c5ddc17bb Signed-off-by: Dhaval Patel Signed-off-by: Krishna Srinivas --- drivers/video/fbdev/msm/mdss_mdp.c | 1 + drivers/video/fbdev/msm/mdss_mdp_cdm.c | 38 +++++++++++----- drivers/video/fbdev/msm/mdss_mdp_cdm.h | 3 +- drivers/video/fbdev/msm/mdss_mdp_intf_video.c | 44 +++++++++++-------- .../video/fbdev/msm/mdss_mdp_intf_writeback.c | 32 +++++++------- 5 files changed, 71 insertions(+), 47 deletions(-) diff --git a/drivers/video/fbdev/msm/mdss_mdp.c b/drivers/video/fbdev/msm/mdss_mdp.c index 1dae41391795..066ee193e165 100644 --- a/drivers/video/fbdev/msm/mdss_mdp.c +++ b/drivers/video/fbdev/msm/mdss_mdp.c @@ -3584,6 +3584,7 @@ static int mdss_mdp_cdm_addr_setup(struct mdss_data_type *mdata, head[i].base = (mdata->mdss_io.base) + cdm_offsets[i]; atomic_set(&head[i].kref.refcount, 0); mutex_init(&head[i].lock); + init_completion(&head[i].free_comp); pr_debug("%s: cdm off (%d) = %pK\n", __func__, i, head[i].base); } diff --git a/drivers/video/fbdev/msm/mdss_mdp_cdm.c b/drivers/video/fbdev/msm/mdss_mdp_cdm.c index e0bf1cdf1361..6cc848d93eb9 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_cdm.c +++ b/drivers/video/fbdev/msm/mdss_mdp_cdm.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2016, 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 @@ -26,6 +26,8 @@ static u32 cdm_cdwn2_offsite_h_coeff[] = {0x000b0005, 0x01db01eb, 0x00e40046}; static u32 cdm_cdwn2_cosite_v_coeff[] = {0x00080004}; static u32 cdm_cdwn2_offsite_v_coeff[] = {0x00060002}; +#define VSYNC_TIMEOUT_US 16000 + /** * @mdss_mdp_cdm_alloc() - Allocates a cdm block by parsing the list of * available cdm blocks. @@ -66,6 +68,7 @@ static void mdss_mdp_cdm_free(struct kref *kref) if (!cdm) return; + complete_all(&cdm->free_comp); pr_debug("free cdm_num = %d\n", cdm->num); } @@ -84,6 +87,28 @@ struct mdss_mdp_cdm *mdss_mdp_cdm_init(struct mdss_mdp_ctl *ctl, u32 intf_type) cdm = mdss_mdp_cdm_alloc(mdata); + /** + * give hdmi interface priority to alloc the cdm block. It will wait + * for one vsync cycle to allow wfd to finish its job and try to reserve + * the block the again. + */ + if (!cdm && (intf_type == MDP_CDM_CDWN_OUTPUT_HDMI)) { + /* always wait for first cdm block */ + cdm = mdata->cdm_off; + if (cdm) { + reinit_completion(&cdm->free_comp); + /* + * no need to check the return status of completion + * timeout. Next cdm_alloc call will try to reserve + * the cdm block and returns failure if allocation + * fails. + */ + wait_for_completion_timeout(&cdm->free_comp, + usecs_to_jiffies(VSYNC_TIMEOUT_US)); + cdm = mdss_mdp_cdm_alloc(mdata); + } + } + if (!cdm) { pr_err("%s: Unable to allocate cdm\n", __func__); return ERR_PTR(-EBUSY); @@ -350,17 +375,6 @@ int mdss_mdp_cdm_destroy(struct mdss_mdp_cdm *cdm) return -EINVAL; } - mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON); - mutex_lock(&cdm->lock); - /* Disable HDMI packer */ - writel_relaxed(0x0, cdm->base + MDSS_MDP_REG_CDM_HDMI_PACK_OP_MODE); - - /* Put CDM in bypass */ - writel_relaxed(0x0, cdm->mdata->mdp_base + MDSS_MDP_MDP_OUT_CTL_0); - - mutex_unlock(&cdm->lock); - mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF); - kref_put(&cdm->kref, mdss_mdp_cdm_free); return rc; diff --git a/drivers/video/fbdev/msm/mdss_mdp_cdm.h b/drivers/video/fbdev/msm/mdss_mdp_cdm.h index 4515628da0e7..3b7fdced6623 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_cdm.h +++ b/drivers/video/fbdev/msm/mdss_mdp_cdm.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, The Linux Foundation. All rights reserved. + * Copyright (c) 2014,2016, 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 @@ -59,6 +59,7 @@ struct mdss_mdp_cdm { u32 out_intf; bool is_bypassed; struct mdp_cdm_cfg setup; + struct completion free_comp; }; struct mdss_mdp_cdm *mdss_mdp_cdm_init(struct mdss_mdp_ctl *ctl, diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c index 048e5fce30c6..bf1e3617f18a 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c +++ b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c @@ -1793,19 +1793,10 @@ static inline bool mdss_mdp_video_need_pixel_drop(u32 vic) } static int mdss_mdp_video_cdm_setup(struct mdss_mdp_cdm *cdm, - struct mdss_panel_info *pinfo) + struct mdss_panel_info *pinfo, struct mdss_mdp_format_params *fmt) { - struct mdss_mdp_format_params *fmt; struct mdp_cdm_cfg setup; - fmt = mdss_mdp_get_format_params(pinfo->out_format); - - if (!fmt) { - pr_err("%s: format %d not supported\n", __func__, - pinfo->out_format); - return -EINVAL; - } - setup.out_format = pinfo->out_format; if (fmt->is_yuv) setup.csc_type = MDSS_MDP_CSC_RGB2YUV_601L; else @@ -1835,6 +1826,7 @@ static int mdss_mdp_video_cdm_setup(struct mdss_mdp_cdm *cdm, return -EINVAL; } + setup.out_format = pinfo->out_format; setup.mdp_csc_bit_depth = MDP_CDM_CSC_8BIT; setup.output_width = pinfo->xres + pinfo->lcdc.xres_pad; setup.output_height = pinfo->yres + pinfo->lcdc.yres_pad; @@ -1868,6 +1860,7 @@ static int mdss_mdp_video_ctx_setup(struct mdss_mdp_ctl *ctl, { struct intf_timing_params *itp = &ctx->itp; u32 dst_bpp; + struct mdss_mdp_format_params *fmt; struct mdss_data_type *mdata = ctl->mdata; struct dsc_desc *dsc = NULL; u32 hdmi_dp_core; @@ -1902,17 +1895,32 @@ static int mdss_mdp_video_ctx_setup(struct mdss_mdp_ctl *ctl, } if (mdss_mdp_is_cdm_supported(mdata, ctl->intf_type, 0)) { - ctl->cdm = mdss_mdp_cdm_init(ctl, MDP_CDM_CDWN_OUTPUT_HDMI); - if (!IS_ERR_OR_NULL(ctl->cdm)) { - if (mdss_mdp_video_cdm_setup(ctl->cdm, pinfo)) { - pr_err("%s: setting up cdm failed\n", - __func__); + + fmt = mdss_mdp_get_format_params(pinfo->out_format); + if (!fmt) { + pr_err("%s: format %d not supported\n", __func__, + pinfo->out_format); + return -EINVAL; + } + if (fmt->is_yuv) { + ctl->cdm = + mdss_mdp_cdm_init(ctl, MDP_CDM_CDWN_OUTPUT_HDMI); + if (!IS_ERR_OR_NULL(ctl->cdm)) { + if (mdss_mdp_video_cdm_setup(ctl->cdm, + pinfo, fmt)) { + pr_err("%s: setting up cdm failed\n", + __func__); + return -EINVAL; + } + ctl->flush_bits |= BIT(26); + } else { + pr_err("%s: failed to initialize cdm\n", + __func__); return -EINVAL; } - ctl->flush_bits |= BIT(26); } else { - pr_err("%s: failed to initialize cdm\n", __func__); - return -EINVAL; + pr_debug("%s: Format is not YUV,cdm not required\n", + __func__); } } else { pr_debug("%s: cdm not supported\n", __func__); diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_writeback.c b/drivers/video/fbdev/msm/mdss_mdp_intf_writeback.c index e6e03e7d54b2..11406e036534 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_intf_writeback.c +++ b/drivers/video/fbdev/msm/mdss_mdp_intf_writeback.c @@ -202,16 +202,14 @@ static int mdss_mdp_writeback_addr_setup(struct mdss_mdp_writeback_ctx *ctx, } static int mdss_mdp_writeback_cdm_setup(struct mdss_mdp_writeback_ctx *ctx, - struct mdss_mdp_cdm *cdm, u32 format) + struct mdss_mdp_cdm *cdm, struct mdss_mdp_format_params *fmt) { - struct mdss_mdp_format_params *fmt; struct mdp_cdm_cfg setup; - fmt = mdss_mdp_get_format_params(format); - if (!fmt) { - pr_err("%s: format %d not supported\n", __func__, format); - return -EINVAL; - } + if (fmt->is_yuv) + setup.csc_type = MDSS_MDP_CSC_RGB2YUV_601L; + else + setup.csc_type = MDSS_MDP_CSC_RGB2RGB; if (fmt->is_yuv) setup.csc_type = MDSS_MDP_CSC_RGB2YUV_601L; @@ -237,7 +235,7 @@ static int mdss_mdp_writeback_cdm_setup(struct mdss_mdp_writeback_ctx *ctx, return -EINVAL; } - setup.out_format = format; + setup.out_format = fmt->format; setup.mdp_csc_bit_depth = MDP_CDM_CSC_8BIT; setup.output_width = ctx->width; setup.output_height = ctx->height; @@ -353,10 +351,9 @@ static int mdss_mdp_writeback_format_setup(struct mdss_mdp_writeback_ctx *ctx, chroma_samp = fmt->chroma_sample; if (ctl->cdm) { - - rc = mdss_mdp_writeback_cdm_setup(ctx, ctl->cdm, format); + rc = mdss_mdp_writeback_cdm_setup(ctx, ctl->cdm, fmt); if (rc) { - pr_err("%s: CDM configuration failed with error %d\n", + pr_err("%s: CDM config failed with error %d\n", __func__, rc); return rc; } @@ -1014,6 +1011,7 @@ int mdss_mdp_writeback_start(struct mdss_mdp_ctl *ctl) struct mdss_mdp_writeback_ctx *ctx; struct mdss_mdp_writeback *wb; u32 mixer_type = MDSS_MDP_MIXER_TYPE_UNUSED; + struct mdss_mdp_format_params *fmt = NULL; bool is_rot; pr_debug("start ctl=%d\n", ctl->num); @@ -1037,6 +1035,10 @@ int mdss_mdp_writeback_start(struct mdss_mdp_ctl *ctl) return -EINVAL; } + fmt = mdss_mdp_get_format_params(ctl->dst_format); + if (!fmt) + return -EINVAL; + is_rot = (ctx->type == MDSS_MDP_WRITEBACK_TYPE_ROTATOR) ? true : false; if (ctl->mixer_left) { @@ -1050,15 +1052,13 @@ int mdss_mdp_writeback_start(struct mdss_mdp_ctl *ctl) } if (mdss_mdp_is_cdm_supported(ctl->mdata, ctl->intf_type, - mixer_type)) { + mixer_type) && fmt->is_yuv) { ctl->cdm = mdss_mdp_cdm_init(ctl, MDP_CDM_CDWN_OUTPUT_WB); if (IS_ERR_OR_NULL(ctl->cdm)) { - pr_err("%s failed to init cdm\n", __func__); + pr_err("cdm block already in use\n"); + ctl->cdm = NULL; return -EBUSY; } - } else { - ctl->cdm = NULL; - pr_debug("%s: cdm not supported\n", __func__); } ctl->priv_data = ctx; ctx->wb_num = wb->num;