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 <pdhaval@codeaurora.org>
Signed-off-by: Krishna Srinivas <krisrini@codeaurora.org>
This commit is contained in:
Dhaval Patel 2016-04-20 17:35:25 -07:00 committed by Harsh Sahu
parent 66c484153d
commit db37c5bdcc
5 changed files with 71 additions and 47 deletions

View file

@ -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]; head[i].base = (mdata->mdss_io.base) + cdm_offsets[i];
atomic_set(&head[i].kref.refcount, 0); atomic_set(&head[i].kref.refcount, 0);
mutex_init(&head[i].lock); mutex_init(&head[i].lock);
init_completion(&head[i].free_comp);
pr_debug("%s: cdm off (%d) = %pK\n", __func__, i, head[i].base); pr_debug("%s: cdm off (%d) = %pK\n", __func__, i, head[i].base);
} }

View file

@ -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 * 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 * 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_cosite_v_coeff[] = {0x00080004};
static u32 cdm_cdwn2_offsite_v_coeff[] = {0x00060002}; 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 * @mdss_mdp_cdm_alloc() - Allocates a cdm block by parsing the list of
* available cdm blocks. * available cdm blocks.
@ -66,6 +68,7 @@ static void mdss_mdp_cdm_free(struct kref *kref)
if (!cdm) if (!cdm)
return; return;
complete_all(&cdm->free_comp);
pr_debug("free cdm_num = %d\n", cdm->num); 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); 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) { if (!cdm) {
pr_err("%s: Unable to allocate cdm\n", __func__); pr_err("%s: Unable to allocate cdm\n", __func__);
return ERR_PTR(-EBUSY); return ERR_PTR(-EBUSY);
@ -350,17 +375,6 @@ int mdss_mdp_cdm_destroy(struct mdss_mdp_cdm *cdm)
return -EINVAL; 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); kref_put(&cdm->kref, mdss_mdp_cdm_free);
return rc; return rc;

View file

@ -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 * 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 * it under the terms of the GNU General Public License version 2 and
@ -59,6 +59,7 @@ struct mdss_mdp_cdm {
u32 out_intf; u32 out_intf;
bool is_bypassed; bool is_bypassed;
struct mdp_cdm_cfg setup; struct mdp_cdm_cfg setup;
struct completion free_comp;
}; };
struct mdss_mdp_cdm *mdss_mdp_cdm_init(struct mdss_mdp_ctl *ctl, struct mdss_mdp_cdm *mdss_mdp_cdm_init(struct mdss_mdp_ctl *ctl,

View file

@ -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, 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; 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) if (fmt->is_yuv)
setup.csc_type = MDSS_MDP_CSC_RGB2YUV_601L; setup.csc_type = MDSS_MDP_CSC_RGB2YUV_601L;
else else
@ -1835,6 +1826,7 @@ static int mdss_mdp_video_cdm_setup(struct mdss_mdp_cdm *cdm,
return -EINVAL; return -EINVAL;
} }
setup.out_format = pinfo->out_format;
setup.mdp_csc_bit_depth = MDP_CDM_CSC_8BIT; setup.mdp_csc_bit_depth = MDP_CDM_CSC_8BIT;
setup.output_width = pinfo->xres + pinfo->lcdc.xres_pad; setup.output_width = pinfo->xres + pinfo->lcdc.xres_pad;
setup.output_height = pinfo->yres + pinfo->lcdc.yres_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; struct intf_timing_params *itp = &ctx->itp;
u32 dst_bpp; u32 dst_bpp;
struct mdss_mdp_format_params *fmt;
struct mdss_data_type *mdata = ctl->mdata; struct mdss_data_type *mdata = ctl->mdata;
struct dsc_desc *dsc = NULL; struct dsc_desc *dsc = NULL;
u32 hdmi_dp_core; 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)) { 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)) { fmt = mdss_mdp_get_format_params(pinfo->out_format);
if (mdss_mdp_video_cdm_setup(ctl->cdm, pinfo)) { if (!fmt) {
pr_err("%s: setting up cdm failed\n", pr_err("%s: format %d not supported\n", __func__,
__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; return -EINVAL;
} }
ctl->flush_bits |= BIT(26);
} else { } else {
pr_err("%s: failed to initialize cdm\n", __func__); pr_debug("%s: Format is not YUV,cdm not required\n",
return -EINVAL; __func__);
} }
} else { } else {
pr_debug("%s: cdm not supported\n", __func__); pr_debug("%s: cdm not supported\n", __func__);

View file

@ -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, 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; struct mdp_cdm_cfg setup;
fmt = mdss_mdp_get_format_params(format); if (fmt->is_yuv)
if (!fmt) { setup.csc_type = MDSS_MDP_CSC_RGB2YUV_601L;
pr_err("%s: format %d not supported\n", __func__, format); else
return -EINVAL; setup.csc_type = MDSS_MDP_CSC_RGB2RGB;
}
if (fmt->is_yuv) if (fmt->is_yuv)
setup.csc_type = MDSS_MDP_CSC_RGB2YUV_601L; 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; return -EINVAL;
} }
setup.out_format = format; setup.out_format = fmt->format;
setup.mdp_csc_bit_depth = MDP_CDM_CSC_8BIT; setup.mdp_csc_bit_depth = MDP_CDM_CSC_8BIT;
setup.output_width = ctx->width; setup.output_width = ctx->width;
setup.output_height = ctx->height; 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; chroma_samp = fmt->chroma_sample;
if (ctl->cdm) { if (ctl->cdm) {
rc = mdss_mdp_writeback_cdm_setup(ctx, ctl->cdm, fmt);
rc = mdss_mdp_writeback_cdm_setup(ctx, ctl->cdm, format);
if (rc) { if (rc) {
pr_err("%s: CDM configuration failed with error %d\n", pr_err("%s: CDM config failed with error %d\n",
__func__, rc); __func__, rc);
return 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_ctx *ctx;
struct mdss_mdp_writeback *wb; struct mdss_mdp_writeback *wb;
u32 mixer_type = MDSS_MDP_MIXER_TYPE_UNUSED; u32 mixer_type = MDSS_MDP_MIXER_TYPE_UNUSED;
struct mdss_mdp_format_params *fmt = NULL;
bool is_rot; bool is_rot;
pr_debug("start ctl=%d\n", ctl->num); pr_debug("start ctl=%d\n", ctl->num);
@ -1037,6 +1035,10 @@ int mdss_mdp_writeback_start(struct mdss_mdp_ctl *ctl)
return -EINVAL; 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; is_rot = (ctx->type == MDSS_MDP_WRITEBACK_TYPE_ROTATOR) ? true : false;
if (ctl->mixer_left) { 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, 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); ctl->cdm = mdss_mdp_cdm_init(ctl, MDP_CDM_CDWN_OUTPUT_WB);
if (IS_ERR_OR_NULL(ctl->cdm)) { 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; return -EBUSY;
} }
} else {
ctl->cdm = NULL;
pr_debug("%s: cdm not supported\n", __func__);
} }
ctl->priv_data = ctx; ctl->priv_data = ctx;
ctx->wb_num = wb->num; ctx->wb_num = wb->num;