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

Commit 6bc6462b authored by Alan Kwong's avatar Alan Kwong
Browse files

msm: sde: add inline rotation support to sde rotator



Add new inline interface and support for inline rotation.
Inline rotation reduces ddr usage by streaming rotated
image to sde vig/dma source pipe using system cache.

CRs-Fixed: 2009714
Change-Id: Ifa5bcb50067a6b873c2dad037f8fcac0f8d80822
Signed-off-by: default avatarAlan Kwong <akwong@codeaurora.org>
parent cd838975
Loading
Loading
Loading
Loading
+15 −0
Original line number Diff line number Diff line
@@ -15,6 +15,8 @@ Required properties
- clocks:		List of Phandles for clock device nodes
			needed by the device.
- clock-names:		List of clock names needed by the device.
- #list-cells:		Number of rotator cells, must be 1

Bus Scaling Data:
- qcom,msm-bus,name:		String property describing rotator client.
- qcom,msm-bus,num-cases:	This is the the number of Bus Scaling use cases
@@ -81,6 +83,12 @@ Optional properties
				  priority for rotator clients.
- qcom,mdss-rot-mode:		This is integer value indicates operation mode
				of the rotator device
- qcom,mdss-sbuf-headroom:	This integer value indicates stream buffer headroom in lines.
- cache-slice-names:		A set of names that identify the usecase names of a client that uses
				cache slice. These strings are used to look up the cache slice
				entries by name.
- cache-slices:			The tuple has phandle to llcc device as the first argument and the
				second argument is the usecase id of the client.

Subnode properties:
- compatible:		Compatible name used in smmu v2.
@@ -102,6 +110,9 @@ Example:
		reg = <0xfd900000 0x22100>,
			<0xfd925000 0x1000>;
		reg-names = "mdp_phys", "rot_vbif_phys";

		#list-cells = <1>;

		interrupt-parent = <&mdss_mdp>;
		interrupts = <2 0>;

@@ -131,6 +142,10 @@ Example:
		qcom,mdss-default-ot-rd-limit = <8>;
		qcom,mdss-default-ot-wr-limit = <16>;

		qcom,mdss-sbuf-headroom = <20>;
		cache-slice-names = "rotator";
		cache-slices = <&llcc 3>;

		smmu_rot_unsec: qcom,smmu_rot_unsec_cb {
			compatible = "qcom,smmu_sde_rot_unsec";
			iommus = <&mdp_smmu 0xe00>;
+2 −0
Original line number Diff line number Diff line
@@ -96,12 +96,14 @@ enum sde_rot_type {
 * @SDE_CAPS_R1_WB: MDSS V1.x WB block
 * @SDE_CAPS_R3_WB: MDSS V3.x WB block
 * @SDE_CAPS_R3_1P5_DOWNSCALE: 1.5x downscale rotator support
 * @SDE_CAPS_SBUF_1: stream buffer support for inline rotation
 */
enum sde_caps_settings {
	SDE_CAPS_R1_WB,
	SDE_CAPS_R3_WB,
	SDE_CAPS_R3_1P5_DOWNSCALE,
	SDE_CAPS_SEC_ATTACH_DETACH_SMMU,
	SDE_CAPS_SBUF_1,
	SDE_CAPS_MAX,
};

+68 −1
Original line number Diff line number Diff line
@@ -532,6 +532,10 @@ static int sde_rotator_import_buffer(struct sde_layer_buffer *buffer,
	if (!input)
		dir = DMA_FROM_DEVICE;

	data->sbuf = buffer->sbuf;
	data->scid = buffer->scid;
	data->writeback = buffer->writeback;

	memset(planes, 0, sizeof(planes));

	for (i = 0; i < buffer->plane_count; i++) {
@@ -539,6 +543,8 @@ static int sde_rotator_import_buffer(struct sde_layer_buffer *buffer,
		planes[i].offset = buffer->planes[i].offset;
		planes[i].buffer = buffer->planes[i].buffer;
		planes[i].handle = buffer->planes[i].handle;
		planes[i].addr = buffer->planes[i].addr;
		planes[i].len = buffer->planes[i].len;
	}

	ret =  sde_mdp_data_get_and_validate_size(data, planes,
@@ -760,6 +766,9 @@ static int sde_rotator_import_data(struct sde_rot_mgr *mgr,
	if (entry->item.flags & SDE_ROTATION_EXT_DMA_BUF)
		flag |= SDE_ROT_EXT_DMA_BUF;

	if (entry->item.flags & SDE_ROTATION_EXT_IOVA)
		flag |= SDE_ROT_EXT_IOVA;

	if (entry->item.flags & SDE_ROTATION_SECURE_CAMERA)
		flag |= SDE_SECURE_CAMERA_SESSION;

@@ -800,6 +809,10 @@ static int sde_rotator_require_reconfiguration(struct sde_rot_mgr *mgr,
			entry->perf->wrot_limit != mgr->wrot_limit))
		return true;

	/* sbuf mode is exclusive and may impact queued entries */
	if (!mgr->sbuf_ctx && entry->perf && entry->perf->config.output.sbuf)
		return true;

	return false;
}

@@ -855,6 +868,9 @@ static int sde_rotator_is_hw_available(struct sde_rot_mgr *mgr,
				entry->item.session_id,
				entry->item.sequence_id);
		return sde_rotator_is_hw_idle(mgr, hw);
	} else if (mgr->sbuf_ctx && mgr->sbuf_ctx != entry->private) {
		SDEROT_DBG("wait until sbuf mode is off\n");
		return false;
	} else {
		return (atomic_read(&hw->num_active) < hw->max_active);
	}
@@ -907,6 +923,14 @@ static struct sde_rot_hw_resource *sde_rotator_get_hw_resource(
			entry->item.session_id, entry->item.sequence_id);
	mgr->rdot_limit = entry->perf->rdot_limit;
	mgr->wrot_limit = entry->perf->wrot_limit;

	if (!mgr->sbuf_ctx && entry->perf->config.output.sbuf) {
		SDEROT_DBG("acquire sbuf s:%d.%d\n", entry->item.session_id,
				entry->item.sequence_id);
		SDEROT_EVTLOG(entry->item.session_id, entry->item.sequence_id);
		mgr->sbuf_ctx = entry->private;
	}

	return hw;
}

@@ -1560,7 +1584,11 @@ static bool sde_rotator_verify_format(struct sde_rot_mgr *mgr,
	if ((in_fmt->is_yuv != out_fmt->is_yuv) ||
		(in_fmt->pixel_mode != out_fmt->pixel_mode) ||
		(in_fmt->unpack_tight != out_fmt->unpack_tight)) {
		SDEROT_ERR("Rotator does not support CSC\n");
		SDEROT_ERR(
			"Rotator does not support CSC yuv:%d/%d pm:%d/%d ut:%d/%d\n",
			in_fmt->is_yuv, out_fmt->is_yuv,
			in_fmt->pixel_mode, out_fmt->pixel_mode,
			in_fmt->unpack_tight, out_fmt->unpack_tight);
		goto verify_error;
	}

@@ -2029,6 +2057,34 @@ int sde_rotator_validate_request(struct sde_rot_mgr *mgr,
	return ret;
}

/*
 * sde_rotator_commit_request - commit the request to hardware
 * @mgr: pointer to rotator manager
 * @private: pointer to per file context
 * @req: pointer to rotation request
 *
 * This differs from sde_rotator_queue_request in that this
 * function will wait until request is committed to hardware.
 */
void sde_rotator_commit_request(struct sde_rot_mgr *mgr,
	struct sde_rot_file_private *ctx,
	struct sde_rot_entry_container *req)
{
	int i;

	if (!mgr || !ctx || !req || !req->entries) {
		SDEROT_ERR("null parameters\n");
		return;
	}

	sde_rotator_queue_request(mgr, ctx, req);

	sde_rot_mgr_unlock(mgr);
	for (i = 0; i < req->count; i++)
		flush_work(&req->entries[i].commit_work);
	sde_rot_mgr_lock(mgr);
}

static int sde_rotator_open_session(struct sde_rot_mgr *mgr,
	struct sde_rot_file_private *private, u32 session_id)
{
@@ -2139,6 +2195,12 @@ static int sde_rotator_close_session(struct sde_rot_mgr *mgr,
	sde_rotator_update_clk(mgr);
	sde_rotator_resource_ctrl(mgr, false);
done:
	if (mgr->sbuf_ctx == private) {
		SDEROT_DBG("release sbuf session id:%u\n", id);
		SDEROT_EVTLOG(id);
		mgr->sbuf_ctx = NULL;
	}

	SDEROT_DBG("Closed session id:%u\n", id);
	return 0;
}
@@ -2183,6 +2245,11 @@ static int sde_rotator_config_session(struct sde_rot_mgr *mgr,
		goto done;
	}

	if (config->output.sbuf && mgr->sbuf_ctx != private && mgr->sbuf_ctx) {
		SDEROT_ERR("too many sbuf sessions\n");
		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,
+115 −0
Original line number Diff line number Diff line
@@ -62,6 +62,9 @@
/* secure camera operation*/
#define SDE_ROTATION_SECURE_CAMERA	0x40000

/* use client mapped i/o virtual address */
#define SDE_ROTATION_EXT_IOVA		0x80000

/**********************************************************************
 * configuration structures
 **********************************************************************/
@@ -72,12 +75,14 @@
 * @height: height of buffer region to be processed
 * @format: pixel format of buffer
 * @comp_ratio: compression ratio for the session
 * @sbuf: true if buffer is streaming buffer
 */
struct sde_rotation_buf_info {
	uint32_t width;
	uint32_t height;
	uint32_t format;
	struct sde_mult_factor comp_ratio;
	bool sbuf;
};

/*
@@ -121,10 +126,19 @@ enum sde_rotator_clk_type {
	SDE_ROTATOR_CLK_MAX
};

enum sde_rotator_trigger {
	SDE_ROTATOR_TRIGGER_IMMEDIATE,
	SDE_ROTATOR_TRIGGER_VIDEO,
	SDE_ROTATOR_TRIGGER_COMMAND,
};

struct sde_rotation_item {
	/* rotation request flag */
	uint32_t	flags;

	/* rotation trigger mode */
	uint32_t	trigger;

	/* Source crop rectangle */
	struct sde_rect	src_rect;

@@ -233,6 +247,26 @@ struct sde_rot_entry_container {
struct sde_rot_mgr;
struct sde_rot_file_private;

/*
 * struct sde_rot_entry - rotation entry
 * @item: rotation item
 * @commit_work: work descriptor for commit handler
 * @done_work: work descriptor for done handler
 * @commitq: pointer to commit handler rotator queue
 * @fenceq: pointer to fence signaling rotator queue
 * @doneq: pointer to done handler rotator queue
 * @request: pointer to containing request
 * @src_buf: descriptor of source buffer
 * @dst_buf: descriptor of destination buffer
 * @input_fence: pointer to input fence for when input content is available
 * @output_fence: pointer to output fence for when output content is available
 * @output_signaled: true if output fence of this entry has been signaled
 * @dnsc_factor_w: calculated width downscale factor for this entry
 * @dnsc_factor_w: calculated height downscale factor for this entry
 * @perf: pointer to performance configuration associated with this entry
 * @work_assigned: true if this item is assigned to h/w queue/unit
 * @private: pointer to controlling session context
 */
struct sde_rot_entry {
	struct sde_rotation_item item;
	struct work_struct commit_work;
@@ -258,6 +292,18 @@ struct sde_rot_entry {
	struct sde_rot_file_private *private;
};

/*
 * struct sde_rot_perf - rotator session performance configuration
 * @list: list of performance configuration under one session
 * @config: current rotation configuration
 * @clk_rate: current clock rate in Hz
 * @bw: current bandwidth in byte per second
 * @work_dis_lock: serialization lock for updating work distribution (not used)
 * @work_distribution: work distribution among multiple hardware queue/unit
 * @last_wb_idx: last queue/unit index, used to account for pre-distributed work
 * @rdot_limit: read OT limit of this session
 * @wrot_limit: write OT limit of this session
 */
struct sde_rot_perf {
	struct list_head list;
	struct sde_rotation_config config;
@@ -270,6 +316,14 @@ struct sde_rot_perf {
	u32 wrot_limit;
};

/*
 * struct sde_rot_file_private - rotator manager per session context
 * @list: list of all session context
 * @req_list: list of rotation request for this session
 * @perf_list: list of performance configuration for this session (only one)
 * @mgr: pointer to the controlling rotator manager
 * @fenceq: pointer to rotator queue to signal when entry is done
 */
struct sde_rot_file_private {
	struct list_head list;
	struct list_head req_list;
@@ -278,6 +332,13 @@ struct sde_rot_file_private {
	struct sde_rot_queue *fenceq;
};

/*
 * struct sde_rot_bus_data_type - rotator bus scaling configuration
 * @bus_cale_pdata: pointer to bus scaling configuration table
 * @bus_hdl: msm bus scaling handle
 * @curr_bw_uc_idx; current usecase index into configuration table
 * @curr_quota_val: current bandwidth request in byte per second
 */
struct sde_rot_bus_data_type {
	struct msm_bus_scale_pdata *bus_scale_pdata;
	u32 bus_hdl;
@@ -285,6 +346,35 @@ struct sde_rot_bus_data_type {
	u64 curr_quota_val;
};

/*
 * struct sde_rot_mgr - core rotator manager
 * @lock: serialization lock to rotator manager functions
 * @device_suspended: 0 if device is not suspended; non-zero suspended
 * @pdev: pointer to controlling platform device
 * @device: pointer to controlling device
 * @queue_count: number of hardware queue/unit available
 * @commitq: array of rotator commit queue corresponding to hardware queue
 * @doneq: array of rotator done queue corresponding to hardware queue
 * @file_list: list of all sessions managed by rotator manager
 * @pending_close_bw_vote: bandwidth of closed sessions with pending work
 * @data_bus: data bus configuration state
 * @reg_bus: register bus configuration state
 * @module_power: power/clock configuration state
 * @regulator_enable: true if foot switch is enabled; false otherwise
 * @res_ref_cnt: reference count of how many times resource is requested
 * @rot_enable_clk_cnt: reference count of how many times clock is requested
 * @rot_clk: array of rotator and periphery clocks
 * @num_rot_clk: size of the rotator clock array
 * @rdot_limit: current read OT limit
 * @wrot_limit: current write OT limit
 * @hwacquire_timeout: maximum wait time for hardware availability in msec
 * @pixel_per_clk: rotator hardware performance in pixel for clock
 * @fudge_factor: fudge factor for clock calculation
 * @overhead: software overhead for offline rotation in msec
 * @sbuf_ctx: pointer to sbuf session context
 * @ops_xxx: function pointers of rotator HAL layer
 * @hw_data: private handle of rotator HAL layer
 */
struct sde_rot_mgr {
	struct mutex lock;
	atomic_t device_suspended;
@@ -325,6 +415,8 @@ struct sde_rot_mgr {
	struct sde_mult_factor fudge_factor;
	struct sde_mult_factor overhead;

	struct sde_rot_file_private *sbuf_ctx;

	int (*ops_config_hw)(struct sde_rot_hw_resource *hw,
			struct sde_rot_entry *entry);
	int (*ops_kickoff_entry)(struct sde_rot_hw_resource *hw,
@@ -351,6 +443,8 @@ struct sde_rot_mgr {
			bool input);
	int (*ops_hw_is_valid_pixfmt)(struct sde_rot_mgr *mgr, u32 pixfmt,
			bool input);
	int (*ops_hw_get_downscale_caps)(struct sde_rot_mgr *mgr, char *caps,
			int len);

	void *hw_data;
};
@@ -373,6 +467,15 @@ static inline u32 sde_rotator_get_pixfmt(struct sde_rot_mgr *mgr,
	return 0;
}

static inline int sde_rotator_get_downscale_caps(struct sde_rot_mgr *mgr,
		char *caps, int len)
{
	if (mgr && mgr->ops_hw_get_downscale_caps)
		return mgr->ops_hw_get_downscale_caps(mgr, caps, len);

	return 0;
}

static inline int __compare_session_item_rect(
	struct sde_rotation_buf_info *s_rect,
	struct sde_rect *i_rect, uint32_t i_fmt, bool src)
@@ -509,6 +612,18 @@ void sde_rotator_queue_request(struct sde_rot_mgr *rot_dev,
	struct sde_rot_file_private *ctx,
	struct sde_rot_entry_container *req);

/*
 * sde_rotator_commit_request - queue/schedule the given request and wait
 *	until h/w commit
 * @rot_dev: Pointer to rotator device
 * @private: Pointer to rotator manager per file context
 * @req: Pointer to rotation request
 * return: 0 if success; error code otherwise
 */
void sde_rotator_commit_request(struct sde_rot_mgr *mgr,
	struct sde_rot_file_private *ctx,
	struct sde_rot_entry_container *req);

/*
 * sde_rotator_verify_config_all - verify given rotation configuration
 * @rot_dev: Pointer to rotator device
+7 −0
Original line number Diff line number Diff line
@@ -1283,6 +1283,13 @@ struct dentry *sde_rotator_create_debugfs(
		return NULL;
	}

	if (!debugfs_create_u32("disable_syscache", 0644,
			debugfs_root, &rot_dev->disable_syscache)) {
		SDEROT_ERR("fail create disable_syscache\n");
		debugfs_remove_recursive(debugfs_root);
		return NULL;
	}

	if (!debugfs_create_u32("streamoff_timeout", 0644,
			debugfs_root, &rot_dev->streamoff_timeout)) {
		SDEROT_ERR("fail create streamoff_timeout\n");
Loading