msm: sde: Adjust SDE rotator clock and BW calculation

Optimize the initial rotator session opening time by moving the clock
and BW voting to the start of rotator. Also adjusting the clock
calcuation to include overhead and fudge factor. Create debugfs entry
for supporting override the clock and BW calculation

CRs-Fixed: 1071288
Change-Id: Ia6a84f160d0288ced98bf9f1818d9eabfc2e3963
Signed-off-by: Benjamin Chan <bkchan@codeaurora.org>
This commit is contained in:
Benjamin Chan 2016-09-26 12:10:06 -04:00
parent 626caf4e54
commit 6c700903fc
5 changed files with 135 additions and 55 deletions

View file

@ -41,8 +41,12 @@
#define ROT_HW_ACQUIRE_TIMEOUT_IN_MS 100
/* default pixel per clock ratio */
#define ROT_PIXEL_PER_CLK_NUMERATOR 4
#define ROT_PIXEL_PER_CLK_DENOMINATOR 1
#define ROT_PIXEL_PER_CLK_NUMERATOR 36
#define ROT_PIXEL_PER_CLK_DENOMINATOR 10
#define ROT_FUDGE_FACTOR_NUMERATOR 105
#define ROT_FUDGE_FACTOR_DENOMINATOR 100
#define ROT_OVERHEAD_NUMERATOR 27
#define ROT_OVERHEAD_DENOMINATOR 10000
/*
* Max rotator hw blocks possible. Used for upper array limits instead of
@ -998,12 +1002,33 @@ static u32 sde_rotator_calc_buf_bw(struct sde_mdp_format_params *fmt,
return bw;
}
static int sde_rotator_find_max_fps(struct sde_rot_mgr *mgr)
{
struct sde_rot_file_private *priv;
struct sde_rot_perf *perf;
int max_fps = 0;
list_for_each_entry(priv, &mgr->file_list, list) {
list_for_each_entry(perf, &priv->perf_list, list) {
if (perf->config.frame_rate > max_fps)
max_fps = perf->config.frame_rate;
}
}
SDEROT_DBG("Max fps:%d\n", max_fps);
return max_fps;
}
static int sde_rotator_calc_perf(struct sde_rot_mgr *mgr,
struct sde_rot_perf *perf)
{
struct sde_rotation_config *config = &perf->config;
u32 read_bw, write_bw;
struct sde_mdp_format_params *in_fmt, *out_fmt;
struct sde_rotator_device *rot_dev;
int max_fps;
rot_dev = platform_get_drvdata(mgr->pdev);
in_fmt = sde_get_format_params(config->input.format);
if (!in_fmt) {
@ -1016,17 +1041,44 @@ static int sde_rotator_calc_perf(struct sde_rot_mgr *mgr,
return -EINVAL;
}
/*
* rotator processes 4 pixels per clock, but the actual throughtput
* is 3.6. We also need to take into account for overhead time. Final
* equation is:
* W x H / throughput / (1/fps - overhead) * fudge_factor
*/
max_fps = sde_rotator_find_max_fps(mgr);
perf->clk_rate = config->input.width * config->input.height;
perf->clk_rate *= config->frame_rate;
/* rotator processes 4 pixels per clock */
perf->clk_rate = (perf->clk_rate * mgr->pixel_per_clk.denom) /
mgr->pixel_per_clk.numer;
perf->clk_rate *= max_fps;
perf->clk_rate = (perf->clk_rate * mgr->fudge_factor.numer) /
mgr->fudge_factor.denom;
perf->clk_rate *= mgr->overhead.denom;
/*
* check for override overhead default value
*/
if (rot_dev->min_overhead_us > (mgr->overhead.numer * 100))
perf->clk_rate = DIV_ROUND_UP_ULL(perf->clk_rate,
(mgr->overhead.denom - max_fps *
(rot_dev->min_overhead_us / 100)));
else
perf->clk_rate = DIV_ROUND_UP_ULL(perf->clk_rate,
(mgr->overhead.denom - max_fps *
mgr->overhead.numer));
/*
* check for Override clock calcualtion
*/
if (rot_dev->min_rot_clk > perf->clk_rate)
perf->clk_rate = rot_dev->min_rot_clk;
read_bw = sde_rotator_calc_buf_bw(in_fmt, config->input.width,
config->input.height, config->frame_rate);
config->input.height, max_fps);
write_bw = sde_rotator_calc_buf_bw(out_fmt, config->output.width,
config->output.height, config->frame_rate);
config->output.height, max_fps);
read_bw = sde_apply_comp_ratio_factor(read_bw, in_fmt,
&config->input.comp_ratio);
@ -1035,13 +1087,22 @@ static int sde_rotator_calc_perf(struct sde_rot_mgr *mgr,
perf->bw = read_bw + write_bw;
/*
* check for override bw calculation
*/
if (rot_dev->min_bw > perf->bw)
perf->bw = rot_dev->min_bw;
perf->rdot_limit = sde_mdp_get_ot_limit(
config->input.width, config->input.height,
config->input.format, config->frame_rate, true);
config->input.format, max_fps, true);
perf->wrot_limit = sde_mdp_get_ot_limit(
config->input.width, config->input.height,
config->input.format, config->frame_rate, false);
config->input.format, max_fps, false);
SDEROT_DBG("clk:%lu, rdBW:%d, wrBW:%d, rdOT:%d, wrOT:%d\n",
perf->clk_rate, read_bw, write_bw, perf->rdot_limit,
perf->wrot_limit);
return 0;
}
@ -1747,16 +1808,9 @@ static int sde_rotator_open_session(struct sde_rot_mgr *mgr,
config.session_id = session_id;
perf->config = config;
perf->last_wb_idx = -1;
perf->last_wb_idx = 0;
INIT_LIST_HEAD(&perf->list);
ret = sde_rotator_calc_perf(mgr, perf);
if (ret) {
SDEROT_ERR("error setting the session %d\n", ret);
goto copy_user_err;
}
list_add(&perf->list, &private->perf_list);
ret = sde_rotator_resource_ctrl(mgr, true);
@ -1777,25 +1831,17 @@ static int sde_rotator_open_session(struct sde_rot_mgr *mgr,
goto enable_clk_err;
}
ret = sde_rotator_update_perf(mgr);
if (ret) {
SDEROT_ERR("fail to open session, not enough clk/bw\n");
goto perf_err;
}
SDEROT_DBG("open session id=%u in{%u,%u}f:%u out{%u,%u}f:%u\n",
config.session_id, config.input.width, config.input.height,
config.input.format, config.output.width, config.output.height,
config.output.format);
goto done;
perf_err:
sde_rotator_clk_ctrl(mgr, false);
enable_clk_err:
update_clk_err:
sde_rotator_resource_ctrl(mgr, false);
resource_err:
list_del_init(&perf->list);
copy_user_err:
devm_kfree(&mgr->pdev->dev, perf->work_distribution);
alloc_err:
devm_kfree(&mgr->pdev->dev, perf);
@ -1867,11 +1913,23 @@ static int sde_rotator_config_session(struct sde_rot_mgr *mgr,
}
ret = sde_rotator_update_perf(mgr);
if (ret) {
SDEROT_ERR("error in updating perf: %d\n", ret);
goto done;
}
SDEROT_DBG("reconfig session id=%u in{%u,%u}f:%u out{%u,%u}f:%u\n",
ret = sde_rotator_update_clk(mgr);
if (ret) {
SDEROT_ERR("error in updating the rotator clk: %d\n", ret);
goto done;
}
SDEROT_DBG(
"reconfig session id=%u in{%u,%u}f:%u out{%u,%u}f:%u fps:%d clk:%lu, bw:%llu\n",
config->session_id, config->input.width, config->input.height,
config->input.format, config->output.width,
config->output.height, config->output.format);
config->output.height, config->output.format,
config->frame_rate, perf->clk_rate, perf->bw);
done:
return ret;
}
@ -2386,6 +2444,10 @@ int sde_rotator_core_init(struct sde_rot_mgr **pmgr,
mgr->queue_count = 1;
mgr->pixel_per_clk.numer = ROT_PIXEL_PER_CLK_NUMERATOR;
mgr->pixel_per_clk.denom = ROT_PIXEL_PER_CLK_DENOMINATOR;
mgr->fudge_factor.numer = ROT_FUDGE_FACTOR_NUMERATOR;
mgr->fudge_factor.denom = ROT_FUDGE_FACTOR_DENOMINATOR;
mgr->overhead.numer = ROT_OVERHEAD_NUMERATOR;
mgr->overhead.denom = ROT_OVERHEAD_DENOMINATOR;
mutex_init(&mgr->lock);
atomic_set(&mgr->device_suspended, 0);

View file

@ -281,6 +281,8 @@ struct sde_rot_mgr {
u32 hwacquire_timeout;
struct sde_mult_factor pixel_per_clk;
struct sde_mult_factor fudge_factor;
struct sde_mult_factor overhead;
int (*ops_config_hw)(struct sde_rot_hw_resource *hw,
struct sde_rot_entry *entry);

View file

@ -914,6 +914,34 @@ static int sde_rotator_evtlog_create_debugfs(
return 0;
}
static int sde_rotator_perf_create_debugfs(
struct sde_rotator_device *rot_dev,
struct dentry *debugfs_root)
{
rot_dev->perf_root = debugfs_create_dir("perf", debugfs_root);
if (IS_ERR_OR_NULL(rot_dev->perf_root)) {
pr_err("debugfs_create_dir for perf failed, error %ld\n",
PTR_ERR(rot_dev->perf_root));
rot_dev->perf_root = NULL;
return -ENODEV;
}
rot_dev->min_rot_clk = 0;
debugfs_create_u32("min_rot_clk", S_IRUGO | S_IWUSR,
rot_dev->perf_root, &rot_dev->min_rot_clk);
rot_dev->min_bw = 0;
debugfs_create_u32("min_bw", S_IRUGO | S_IWUSR,
rot_dev->perf_root, &rot_dev->min_bw);
rot_dev->min_overhead_us = 0;
debugfs_create_u32("min_overhead_us", S_IRUGO | S_IWUSR,
rot_dev->perf_root, &rot_dev->min_overhead_us);
return 0;
}
/*
* struct sde_rotator_stat_ops - processed statistics file operations
*/
@ -1006,6 +1034,12 @@ struct dentry *sde_rotator_create_debugfs(
return NULL;
}
if (sde_rotator_perf_create_debugfs(rot_dev, debugfs_root)) {
SDEROT_ERR("fail create perf debugfs\n");
debugfs_remove_recursive(debugfs_root);
return NULL;
}
return debugfs_root;
}

View file

@ -546,22 +546,8 @@ static struct vb2_mem_ops sde_rotator_vb2_mem_ops = {
static int sde_rotator_s_ctx_ctrl(struct sde_rotator_ctx *ctx,
s32 *ctx_ctrl, struct v4l2_ctrl *ctrl)
{
struct sde_rotator_device *rot_dev = ctx->rot_dev;
struct sde_rotation_config config;
s32 prev_val;
int ret;
prev_val = *ctx_ctrl;
*ctx_ctrl = ctrl->val;
sde_rotator_get_config_from_ctx(ctx, &config);
ret = sde_rotator_session_config(rot_dev->mgr, ctx->private, &config);
if (ret) {
SDEDEV_WARN(rot_dev->dev, "fail %s:%d s:%d\n",
ctrl->name, ctrl->val, ctx->session_id);
*ctx_ctrl = prev_val;
}
return ret;
return 0;
}
/*
@ -1213,7 +1199,6 @@ static int sde_rotator_s_fmt_vid_cap(struct file *file,
{
struct sde_rotator_ctx *ctx = sde_rotator_ctx_from_fh(fh);
struct sde_rotator_device *rot_dev = ctx->rot_dev;
struct sde_rotation_config config;
int ret;
ret = sde_rotator_try_fmt_vid_cap(file, fh, f);
@ -1235,12 +1220,6 @@ static int sde_rotator_s_fmt_vid_cap(struct file *file,
f->fmt.pix.field,
f->fmt.pix.width, f->fmt.pix.height);
/* configure hal to current input/output setting */
sde_rot_mgr_lock(rot_dev->mgr);
sde_rotator_get_config_from_ctx(ctx, &config);
sde_rotator_session_config(rot_dev->mgr, ctx->private, &config);
sde_rot_mgr_unlock(rot_dev->mgr);
return 0;
}
@ -1524,7 +1503,6 @@ static int sde_rotator_s_crop(struct file *file, void *fh,
{
struct sde_rotator_ctx *ctx = sde_rotator_ctx_from_fh(fh);
struct sde_rotator_device *rot_dev = ctx->rot_dev;
struct sde_rotation_config config;
struct sde_rotation_item item;
struct v4l2_rect rect;
@ -1597,12 +1575,6 @@ static int sde_rotator_s_crop(struct file *file, void *fh,
return -EINVAL;
}
/* configure hal to current input/output setting */
sde_rot_mgr_lock(rot_dev->mgr);
sde_rotator_get_config_from_ctx(ctx, &config);
sde_rotator_session_config(rot_dev->mgr, ctx->private, &config);
sde_rot_mgr_unlock(rot_dev->mgr);
return 0;
}
@ -2336,6 +2308,9 @@ static int sde_rotator_probe(struct platform_device *pdev)
rot_dev->early_submit = SDE_ROTATOR_EARLY_SUBMIT;
rot_dev->fence_timeout = SDE_ROTATOR_FENCE_TIMEOUT;
rot_dev->streamoff_timeout = SDE_ROTATOR_STREAM_OFF_TIMEOUT;
rot_dev->min_rot_clk = 0;
rot_dev->min_bw = 0;
rot_dev->min_overhead_us = 0;
rot_dev->drvdata = sde_rotator_get_drv_data(&pdev->dev);
rot_dev->pdev = pdev;

View file

@ -160,6 +160,9 @@ struct sde_rotator_statistics {
* @session_id: Next context session identifier
* @fence_timeout: Timeout value in msec for fence wait
* @streamoff_timeout: Timeout value in msec for stream off
* @min_rot_clk: Override the minimum rotator clock from perf calculation
* @min_bw: Override the minimum bandwidth from perf calculation
* @min_overhead_us: Override the minimum overhead in us from perf calculation
* @debugfs_root: Pointer to debugfs directory entry.
* @stats: placeholder for rotator statistics
*/
@ -177,8 +180,12 @@ struct sde_rotator_device {
u32 session_id;
u32 fence_timeout;
u32 streamoff_timeout;
u32 min_rot_clk;
u32 min_bw;
u32 min_overhead_us;
struct sde_rotator_statistics stats;
struct dentry *debugfs_root;
struct dentry *perf_root;
};
static inline