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

Commit 2444c32d authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: sde: Add dynamic OT support for rotator REGDMA"

parents bfa25adf e19f8e05
Loading
Loading
Loading
Loading
+47 −29
Original line number Diff line number Diff line
@@ -138,47 +138,68 @@ static bool force_on_xin_clk(u32 bit_off, u32 clk_ctl_reg_off, bool enable)
	return clk_forced_on;
}

static void apply_dynamic_ot_limit(u32 *ot_lim,
	struct sde_mdp_set_ot_params *params)
u32 sde_mdp_get_ot_limit(u32 width, u32 height, u32 pixfmt, u32 fps, u32 is_rd)
{
	struct sde_rot_data_type *mdata = sde_rot_get_mdata();
	struct sde_mdp_format_params *fmt;
	u32 ot_lim;
	u32 is_yuv;
	u32 res;

	ot_lim = (is_rd) ? mdata->default_ot_rd_limit :
				mdata->default_ot_wr_limit;

	/*
	 * If default ot is not set from dt,
	 * then do not configure it.
	 */
	if (ot_lim == 0)
		goto exit;

	/* Modify the limits if the target and the use case requires it */
	if (false == test_bit(SDE_QOS_OTLIM, mdata->sde_qos_map))
		return;
		goto exit;

	res = params->width * params->height;
	res = width * height;

	SDEROT_DBG("w:%d h:%d rot:%d yuv:%d wb:%d res:%d\n",
		params->width, params->height, params->is_rot,
		params->is_yuv, params->is_wb, res);
	fmt = sde_get_format_params(pixfmt);

	if ((params->is_rot && params->is_yuv) ||
		params->is_wb) {
		if (res <= RES_1080p) {
			*ot_lim = 2;
		} else if (res <= RES_UHD) {
			if (params->is_rot && params->is_yuv)
				*ot_lim = 8;
			else
				*ot_lim = 16;
		}
	if (!fmt) {
		SDEROT_WARN("invalid format %8.8x\n", pixfmt);
		goto exit;
	}

	is_yuv = sde_mdp_is_yuv_format(fmt);

	SDEROT_DBG("w:%d h:%d fps:%d pixfmt:%8.8x yuv:%d res:%d rd:%d\n",
		width, height, fps, pixfmt, is_yuv, res, is_rd);

	if (!is_yuv)
		goto exit;

	if ((res <= RES_1080p) && (fps <= 30))
		ot_lim = 2;
	else if ((res <= RES_1080p) && (fps <= 60))
		ot_lim = 4;
	else if ((res <= RES_UHD) && (fps <= 30))
		ot_lim = 8;

exit:
	SDEROT_DBG("ot_lim=%d\n", ot_lim);
	return ot_lim;
}

static u32 get_ot_limit(u32 reg_off, u32 bit_off,
	struct sde_mdp_set_ot_params *params)
{
	struct sde_rot_data_type *mdata = sde_rot_get_mdata();
	u32 ot_lim = 0;
	u32 ot_lim;
	u32 val;

	if (mdata->default_ot_wr_limit &&
		(params->reg_off_vbif_lim_conf == MMSS_VBIF_WR_LIM_CONF))
		ot_lim = mdata->default_ot_wr_limit;
	else if (mdata->default_ot_rd_limit &&
		(params->reg_off_vbif_lim_conf == MMSS_VBIF_RD_LIM_CONF))
		ot_lim = mdata->default_ot_rd_limit;
	ot_lim = sde_mdp_get_ot_limit(
			params->width, params->height,
			params->fmt, params->fps,
			params->reg_off_vbif_lim_conf == MMSS_VBIF_RD_LIM_CONF);

	/*
	 * If default ot is not set from dt,
@@ -187,9 +208,6 @@ static u32 get_ot_limit(u32 reg_off, u32 bit_off,
	if (ot_lim == 0)
		goto exit;

	/* Modify the limits if the target and the use case requires it */
	apply_dynamic_ot_limit(&ot_lim, params);

	val = SDE_VBIF_READ(mdata, reg_off);
	val &= (0xFF << bit_off);
	val = val >> bit_off;
+4 −3
Original line number Diff line number Diff line
@@ -34,9 +34,8 @@ struct sde_mdp_set_ot_params {
	u32 num;
	u32 width;
	u32 height;
	bool is_rot;
	bool is_wb;
	bool is_yuv;
	u32 fps;
	u32 fmt;
	u32 reg_off_vbif_lim_conf;
	u32 reg_off_mdp_clk_ctrl;
	u32 bit_off_mdp_clk_ctrl;
@@ -143,6 +142,8 @@ u32 sde_apply_comp_ratio_factor(u32 quota,
	struct sde_mdp_format_params *fmt,
	struct sde_mult_factor *factor);

u32 sde_mdp_get_ot_limit(u32 width, u32 height, u32 pixfmt, u32 fps, u32 is_rd);

void sde_mdp_set_ot_limit(struct sde_mdp_set_ot_params *params);

#define SDE_VBIF_WRITE(mdata, offset, value) \
+134 −20
Original line number Diff line number Diff line
@@ -607,59 +607,165 @@ static int sde_rotator_import_data(struct sde_rot_mgr *mgr,
	return ret;
}

/*
 * sde_rotator_require_reconfiguration - check if reconfiguration is required
 * @mgr: Pointer to rotator manager
 * @hw: Pointer to rotator hw resource
 * @entry: Pointer to next rotation entry
 *
 * Parameters are validated by caller.
 */
static int sde_rotator_require_reconfiguration(struct sde_rot_mgr *mgr,
		struct sde_rot_hw_resource *hw, struct sde_rot_entry *entry)
{
	/* OT setting change may impact queued entries */
	if (entry->perf && (entry->perf->rdot_limit != mgr->rdot_limit ||
			entry->perf->wrot_limit != mgr->wrot_limit))
		return true;

	return false;
}

/*
 * sde_rotator_is_hw_idle - check if hw block is not processing request
 * @mgr: Pointer to rotator manager
 * @hw: Pointer to rotator hw resource
 *
 * Parameters are validated by caller.
 */
static int sde_rotator_is_hw_idle(struct sde_rot_mgr *mgr,
		struct sde_rot_hw_resource *hw)
{
	int i;

	/*
	 * Wait until all queues are idle in order to update global
	 * setting such as VBIF QoS.  This check can be relaxed if global
	 * settings can be updated individually by entries already
	 * queued in hw queue, i.e. REGDMA can update VBIF directly.
	 */
	for (i = 0; i < mgr->queue_count; i++) {
		struct sde_rot_hw_resource *hw_res = mgr->commitq[i].hw;

		if (hw_res && atomic_read(&hw_res->num_active))
			return false;
	}

	return true;
}

/*
 * sde_rotator_is_hw_available - check if hw is available for the given entry
 * @mgr: Pointer to rotator manager
 * @hw: Pointer to rotator hw resource
 * @entry: Pointer to rotation entry
 *
 * Parameters are validated by caller.
 */
static int sde_rotator_is_hw_available(struct sde_rot_mgr *mgr,
		struct sde_rot_hw_resource *hw, struct sde_rot_entry *entry)
{
	/*
	 * Wait until hw is idle if reconfiguration is required; otherwise,
	 * wait until free queue entry is available
	 */
	if (sde_rotator_require_reconfiguration(mgr, hw, entry)) {
		SDEROT_DBG(
			"wait4idle active=%d pending=%d rdot:%u/%u wrot:%u/%u s:%d.%d\n",
				atomic_read(&hw->num_active), hw->pending_count,
				mgr->rdot_limit, entry->perf->rdot_limit,
				mgr->wrot_limit, entry->perf->wrot_limit,
				entry->item.session_id,
				entry->item.sequence_id);
		return sde_rotator_is_hw_idle(mgr, hw);
	} else {
		return (atomic_read(&hw->num_active) < hw->max_active);
	}
}

/*
 * sde_rotator_get_hw_resource - block waiting for hw availability or timeout
 * @queue: Pointer to rotator queue
 * @entry: Pointer to rotation entry
 */
static struct sde_rot_hw_resource *sde_rotator_get_hw_resource(
	struct sde_rot_queue *queue, struct sde_rot_entry *entry)
{
	struct sde_rot_hw_resource *hw = queue->hw;
	struct sde_rot_hw_resource *hw;
	struct sde_rot_mgr *mgr;
	int ret;

	if (!hw) {
		SDEROT_ERR("no hw in the queue\n");
	if (!queue || !entry || !queue->hw) {
		SDEROT_ERR("null parameters\n");
		return NULL;
	}

	hw = queue->hw;
	mgr = entry->private->mgr;

	BUG_ON(atomic_read(&hw->num_active) > hw->max_active);
	while (atomic_read(&hw->num_active) >= hw->max_active) {
		sde_rot_mgr_unlock(entry->private->mgr);
	while (!sde_rotator_is_hw_available(mgr, hw, entry)) {
		sde_rot_mgr_unlock(mgr);
		ret = wait_event_timeout(hw->wait_queue,
			(atomic_read(&hw->num_active) < hw->max_active),
			sde_rotator_is_hw_available(mgr, hw, entry),
			msecs_to_jiffies(mgr->hwacquire_timeout));
		sde_rot_mgr_lock(entry->private->mgr);
		sde_rot_mgr_lock(mgr);
		if (!ret) {
			SDEROT_ERR(
				"timeout waiting for hw resource, a:%d p:%d\n",
				atomic_read(&hw->num_active),
				hw->pending_count);
			if (hw->workload)
				SDEROT_ERR("possible faulty workload s:%d.%d\n",
						hw->workload->item.session_id,
						hw->workload->item.sequence_id);
			return NULL;
		}
	}
	atomic_inc(&hw->num_active);
	SDEROT_DBG("active=%d pending=%d s:%d.%d\n",
	SDEROT_DBG("active=%d pending=%d rdot=%u/%u wrot=%u/%u s:%d.%d\n",
			atomic_read(&hw->num_active), hw->pending_count,
			mgr->rdot_limit, entry->perf->rdot_limit,
			mgr->wrot_limit, entry->perf->wrot_limit,
			entry->item.session_id, entry->item.sequence_id);
	hw->workload = entry;
	mgr->rdot_limit = entry->perf->rdot_limit;
	mgr->wrot_limit = entry->perf->wrot_limit;
	return hw;
}

/*
 * sde_rotator_put_hw_resource - return hw resource and wake up waiting clients
 * @queue: Pointer to rotator queue
 * @entry: Pointer to rotation entry
 * @hw: Pointer to hw resource to be returned
 */
static void sde_rotator_put_hw_resource(struct sde_rot_queue *queue,
	struct sde_rot_hw_resource *hw)
		struct sde_rot_entry *entry, struct sde_rot_hw_resource *hw)
{
	struct sde_rot_entry *entry = hw->workload;
	struct sde_rot_mgr *mgr;
	int i;

	if (!queue || !entry || !hw) {
		SDEROT_ERR("null parameters\n");
		return;
	}

	mgr = entry->private->mgr;

	BUG_ON(atomic_read(&hw->num_active) < 1);
	hw->workload = NULL;
	if (!atomic_add_unless(&hw->num_active, -1, 0))
		SDEROT_ERR("underflow active=%d pending=%d s:%d.%d\n",
			atomic_read(&hw->num_active), hw->pending_count,
			entry->item.session_id, entry->item.sequence_id);
	wake_up(&hw->wait_queue);
	/*
	 * Wake up all queues in case any entry is waiting for hw idle,
	 * in order to update global settings, such as VBIF QoS.
	 * This can be relaxed to the given hw resource if global
	 * settings can be updated individually by entries already
	 * queued in hw queue.
	 */
	for (i = 0; i < mgr->queue_count; i++) {
		struct sde_rot_hw_resource *hw_res = mgr->commitq[i].hw;

		if (hw_res)
			wake_up(&hw_res->wait_queue);
	}
	SDEROT_DBG("active=%d pending=%d s:%d.%d\n",
			atomic_read(&hw->num_active), hw->pending_count,
			entry->item.session_id, entry->item.sequence_id);
@@ -908,6 +1014,14 @@ static int sde_rotator_calc_perf(struct sde_rot_mgr *mgr,
			&config->output.comp_ratio);

	perf->bw = read_bw + write_bw;

	perf->rdot_limit = sde_mdp_get_ot_limit(
			config->input.width, config->input.height,
			config->input.format, config->frame_rate, true);
	perf->wrot_limit = sde_mdp_get_ot_limit(
			config->input.width, config->input.height,
			config->input.format, config->frame_rate, false);

	return 0;
}

@@ -1069,7 +1183,7 @@ static void sde_rotator_commit_handler(struct work_struct *work)
	sde_rot_mgr_unlock(mgr);
	return;
error:
	sde_rotator_put_hw_resource(entry->commitq, hw);
	sde_rotator_put_hw_resource(entry->commitq, entry, hw);
get_hw_res_err:
	sde_rotator_signal_output(entry);
	sde_rotator_release_entry(mgr, entry);
@@ -1141,7 +1255,7 @@ static void sde_rotator_done_handler(struct work_struct *work)
		entry->item.dst_rect.w, entry->item.dst_rect.h);

	sde_rot_mgr_lock(mgr);
	sde_rotator_put_hw_resource(entry->commitq, entry->commitq->hw);
	sde_rotator_put_hw_resource(entry->commitq, entry, entry->commitq->hw);
	sde_rotator_signal_output(entry);
	sde_rotator_release_entry(mgr, entry);
	atomic_dec(&request->pending_count);
@@ -2275,7 +2389,7 @@ int sde_rotator_core_init(struct sde_rot_mgr **pmgr,
	sde_rotator_clk_ctrl(mgr, true);

	mdata->mdss_version = SDE_REG_READ(mdata, SDE_REG_HW_VERSION);
	SDEROT_INFO("mdss revision %x\n", mdata->mdss_version);
	SDEROT_DBG("mdss revision %x\n", mdata->mdss_version);

	if ((mdata->mdss_version & 0xFFFF0000) == 0x10070000) {
		mgr->ops_hw_init = sde_rotator_r1_init;
+4 −1
Original line number Diff line number Diff line
@@ -169,7 +169,6 @@ struct sde_rot_hw_resource {
	atomic_t num_active;
	int max_active;
	wait_queue_head_t wait_queue;
	struct sde_rot_entry *workload;
};

struct sde_rot_queue {
@@ -225,6 +224,8 @@ struct sde_rot_perf {
	struct mutex work_dis_lock;
	u32 *work_distribution;
	int last_wb_idx; /* last known wb index, used when above count is 0 */
	u32 rdot_limit;
	u32 wrot_limit;
};

struct sde_rot_file_private {
@@ -275,6 +276,8 @@ struct sde_rot_mgr {
	struct sde_rot_clk *rot_clk;
	int num_rot_clk;
	int core_clk_idx;
	u32 rdot_limit;
	u32 wrot_limit;

	u32 hwacquire_timeout;
	struct sde_mult_factor pixel_per_clk;
+1 −0
Original line number Diff line number Diff line
@@ -116,6 +116,7 @@ struct sde_mdp_pipe {
	struct sde_mdp_plane_sizes src_planes;
	struct sde_mdp_mixer *mixer_left;
	struct sde_mdp_mixer *mixer_right;
	struct sde_mdp_shared_reg_ctrl clk_ctrl;
	u32 params_changed;
	u32 offset;
};
Loading