Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 00246cd5 authored by Kyle Yan's avatar Kyle Yan Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: sde: Adjust SDE rotator clock and BW calculation" into msm-4.8

parents aadda166 dbe13111
Loading
Loading
Loading
Loading
+88 −26
Original line number Diff line number Diff line
@@ -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;
	}

	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\n",
	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);
+2 −0
Original line number Diff line number Diff line
@@ -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);
+34 −0
Original line number Diff line number Diff line
@@ -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", 0644,
			rot_dev->perf_root, &rot_dev->min_rot_clk);

	rot_dev->min_bw = 0;
	debugfs_create_u32("min_bw", 0644,
			rot_dev->perf_root, &rot_dev->min_bw);

	rot_dev->min_overhead_us = 0;
	debugfs_create_u32("min_overhead_us", 0644,
			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;
}

+4 −29
Original line number Diff line number Diff line
@@ -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;
+7 −0
Original line number Diff line number Diff line
@@ -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