/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
 */

#ifndef SDE_ROTATOR_CORE_H
#define SDE_ROTATOR_CORE_H

#include <linux/list.h>
#include <linux/file.h>
#include <linux/ktime.h>
#include <linux/mutex.h>
#include <linux/types.h>
#include <linux/cdev.h>
#include <linux/pm_runtime.h>
#include <linux/kthread.h>

#include "sde_rotator_base.h"
#include "sde_rotator_util.h"
#include "sde_rotator_sync.h"

/**********************************************************************
 * Rotation request flag
 **********************************************************************/
/* no rotation flag */
#define SDE_ROTATION_NOP	0x01

/* left/right flip */
#define SDE_ROTATION_FLIP_LR	0x02

/* up/down flip */
#define SDE_ROTATION_FLIP_UD	0x04

/* rotate 90 degree */
#define SDE_ROTATION_90	0x08

/* rotate 180 degre */
#define SDE_ROTATION_180	(SDE_ROTATION_FLIP_LR | SDE_ROTATION_FLIP_UD)

/* rotate 270 degree */
#define SDE_ROTATION_270	(SDE_ROTATION_90 | SDE_ROTATION_180)

/* format is interlaced */
#define SDE_ROTATION_DEINTERLACE	0x10

/* secure data */
#define SDE_ROTATION_SECURE		0x80

/* verify input configuration only */
#define SDE_ROTATION_VERIFY_INPUT_ONLY	0x10000

/* use client provided dma buf instead of ion fd */
#define SDE_ROTATION_EXT_DMA_BUF	0x20000

/* secure camera operation*/
#define SDE_ROTATION_SECURE_CAMERA	0x40000

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

/* use client provided clock/bandwidth parameters */
#define SDE_ROTATION_EXT_PERF		0x100000
#define SDE_ROTATION_BUS_PATH_MAX	0x2

/*
 * The AMC bucket denotes constraints that are applied to hardware when
 * icc_set_bw() completes, whereas the WAKE and SLEEP constraints are applied
 * when the execution environment transitions between active and low power mode.
 */
#define QCOM_ICC_BUCKET_AMC            0
#define QCOM_ICC_BUCKET_WAKE           1
#define QCOM_ICC_BUCKET_SLEEP          2
#define QCOM_ICC_NUM_BUCKETS           3
#define QCOM_ICC_TAG_AMC               BIT(QCOM_ICC_BUCKET_AMC)
#define QCOM_ICC_TAG_WAKE              BIT(QCOM_ICC_BUCKET_WAKE)
#define QCOM_ICC_TAG_SLEEP             BIT(QCOM_ICC_BUCKET_SLEEP)
#define QCOM_ICC_TAG_ACTIVE_ONLY       (QCOM_ICC_TAG_AMC | QCOM_ICC_TAG_WAKE)
#define QCOM_ICC_TAG_ALWAYS            (QCOM_ICC_TAG_AMC | QCOM_ICC_TAG_WAKE |\
                                        QCOM_ICC_TAG_SLEEP)

/**********************************************************************
 * configuration structures
 **********************************************************************/

/*
 * struct sde_rotation_buf_info - input/output buffer configuration
 * @width: width of buffer region to be processed
 * @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;
};

/*
 * struct sde_rotation_config - rotation configuration for given session
 * @session_id: identifier of the given session
 * @input: input buffer information
 * @output: output buffer information
 * @frame_rate: session frame rate in fps
 * @clk_rate: requested rotator clock rate if SDE_ROTATION_EXT_PERF is set
 * @data_bw: requested data bus bandwidth if SDE_ROTATION_EXT_PERF is set
 * @flags: configuration flags, e.g. rotation angle, flip, etc...
 */
struct sde_rotation_config {
	uint32_t	session_id;
	struct sde_rotation_buf_info	input;
	struct sde_rotation_buf_info	output;
	uint32_t	frame_rate;
	uint64_t	clk_rate;
	uint64_t	data_bw;
	uint32_t	flags;
};

enum sde_rotator_ts {
	SDE_ROTATOR_TS_SRCQB,		/* enqueue source buffer */
	SDE_ROTATOR_TS_DSTQB,		/* enqueue destination buffer */
	SDE_ROTATOR_TS_FENCE,		/* wait for source buffer fence */
	SDE_ROTATOR_TS_QUEUE,		/* wait for h/w resource */
	SDE_ROTATOR_TS_COMMIT,		/* prepare h/w command */
	SDE_ROTATOR_TS_START,		/* wait for h/w kickoff rdy (inline) */
	SDE_ROTATOR_TS_FLUSH,		/* initiate h/w processing */
	SDE_ROTATOR_TS_DONE,		/* receive h/w completion */
	SDE_ROTATOR_TS_RETIRE,		/* signal destination buffer fence */
	SDE_ROTATOR_TS_SRCDQB,		/* dequeue source buffer */
	SDE_ROTATOR_TS_DSTDQB,		/* dequeue destination buffer */
	SDE_ROTATOR_TS_MAX
};

enum sde_rotator_clk_type {
	SDE_ROTATOR_CLK_MDSS_AHB,
	SDE_ROTATOR_CLK_MDSS_AXI,
	SDE_ROTATOR_CLK_MDSS_ROT_SUB,
	SDE_ROTATOR_CLK_MDSS_ROT,
	SDE_ROTATOR_CLK_MNOC_AHB,
	SDE_ROTATOR_CLK_GCC_AHB,
	SDE_ROTATOR_CLK_GCC_AXI,
	SDE_ROTATOR_CLK_MAX
};

enum sde_rotator_trigger {
	SDE_ROTATOR_TRIGGER_IMMEDIATE,
	SDE_ROTATOR_TRIGGER_VIDEO,
	SDE_ROTATOR_TRIGGER_COMMAND,
};

enum sde_rotator_mode {
	SDE_ROTATOR_MODE_OFFLINE,
	SDE_ROTATOR_MODE_SBUF,
	SDE_ROTATOR_MODE_MAX,
};

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

	/* rotation trigger mode */
	uint32_t	trigger;

	/* prefill bandwidth in Bps */
	uint64_t	prefill_bw;

	/* Source crop rectangle */
	struct sde_rect	src_rect;

	/* Destination rectangle */
	struct sde_rect	dst_rect;

	/* Input buffer for the request */
	struct sde_layer_buffer	input;

	/* The output buffer for the request */
	struct sde_layer_buffer	output;

	/*
	 * DMA pipe selection for this request by client:
	 * 0: DMA pipe 0
	 * 1: DMA pipe 1
	 * or SDE_ROTATION_HW_ANY if client wants
	 * driver to allocate any that is available
	 *
	 * OR
	 *
	 * Reserved
	 */
	uint32_t	pipe_idx;

	/*
	 * Write-back block selection for this request by client:
	 * 0: Write-back block 0
	 * 1: Write-back block 1
	 * or SDE_ROTATION_HW_ANY if client wants
	 * driver to allocate any that is available
	 *
	 * OR
	 *
	 * Priority selection for this request by client:
	 * 0: Highest
	 * 1..n: Limited by the lowest available priority
	 */
	uint32_t	wb_idx;

	/*
	 * Sequence ID of this request within the session
	 */
	uint32_t	sequence_id;

	/* Which session ID is this request scheduled on */
	uint32_t	session_id;

	/* Time stamp for profiling purposes */
	ktime_t		*ts;

	/* Completion structure for inline rotation */
	struct completion inline_start;
};

/*
 * Defining characteristics about rotation work, that has corresponding
 * fmt and roi checks in open session
 */
#define SDE_ROT_DEFINING_FLAG_BITS SDE_ROTATION_90

struct sde_rot_entry;
struct sde_rot_perf;

struct sde_rot_clk {
	struct clk *clk;
	char clk_name[32];
	unsigned long rate;
};

struct sde_rot_hw_resource {
	u32 wb_id;
	u32 pending_count;
	atomic_t num_active;
	int max_active;
	wait_queue_head_t wait_queue;
};

struct sde_rot_queue {
	struct kthread_worker rot_kw;
	struct task_struct *rot_thread;
	struct sde_rot_timeline *timeline;
	struct sde_rot_hw_resource *hw;
};

struct sde_rot_queue_v1 {
	struct kthread_worker *rot_kw;
	struct task_struct *rot_thread;
	struct sde_rot_timeline *timeline;
	struct sde_rot_hw_resource *hw;
};
/*
 * struct sde_rot_entry_container - rotation request
 * @list: list of active requests managed by rotator manager
 * @flags: reserved
 * @count: size of rotation entries
 * @pending_count: count of entries pending completion
 * @failed_count: count of entries failed completion
 * @finished: true if client is finished with the request
 * @retireq: workqueue to post completion notification
 * @retire_work: work for completion notification
 * @entries: array of rotation entries
 */
struct sde_rot_entry_container {
	struct list_head list;
	u32 flags;
	u32 count;
	atomic_t pending_count;
	atomic_t failed_count;
	struct kthread_worker *retire_kw;
	struct kthread_work *retire_work;
	bool finished;
	struct sde_rot_entry *entries;
};

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 kthread_work commit_work;
	struct kthread_work done_work;
	struct sde_rot_queue *commitq;
	struct sde_rot_queue_v1 *fenceq;
	struct sde_rot_queue *doneq;
	struct sde_rot_entry_container *request;

	struct sde_mdp_data src_buf;
	struct sde_mdp_data dst_buf;

	struct sde_rot_sync_fence *input_fence;

	struct sde_rot_sync_fence *output_fence;
	bool output_signaled;

	u32 dnsc_factor_w;
	u32 dnsc_factor_h;

	struct sde_rot_perf *perf;
	bool work_assigned; /* Used when cleaning up work_distribution */
	struct sde_rot_file_private *private;
};

/*
 * struct sde_rot_trace_entry - structure used to pass info to trace
 */
struct sde_rot_trace_entry {
	u32 wb_idx;
	u32 flags;
	u32 input_format;
	u32 input_width;
	u32 input_height;
	u32 src_x;
	u32 src_y;
	u32 src_w;
	u32 src_h;
	u32 output_format;
	u32 output_width;
	u32 output_height;
	u32 dst_x;
	u32 dst_y;
	u32 dst_w;
	u32 dst_h;
};

/*
 * 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;
	unsigned long clk_rate;
	u64 bw;
	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 - 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;
	struct list_head perf_list;
	struct sde_rot_mgr *mgr;
	struct sde_rot_queue_v1 *fenceq;
};

/**
 * struct sde_rot_bus_data_type: power handle struct for data bus
 * @data_paths_cnt: number of rt data path ports
 * @curr_quota_val: save the current bus value
 * @curr_bw_uc_idx: current reg bus value index
 * @bus_active_only: AMC support, can set the bus path WAKE/SLEEP
 */
struct sde_rot_bus_data_type {
	struct icc_path *data_bus_hdl[SDE_ROTATION_BUS_PATH_MAX];
	u32 data_paths_cnt;
	u64 curr_quota_val;
	u32 curr_bw_uc_idx;
	bool bus_active_only;
};

/*
 * 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
 * @minimum_bw_vote: minimum bandwidth required for current use case
 * @enable_bw_vote: minimum bandwidth required for power enable
 * @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
 * @min_rot_clk: minimum rotator clock rate
 * @max_rot_clk: maximum allowed rotator clock rate
 * @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;
	struct platform_device *pdev;
	struct device *device;

	/*
	 * Managing rotation queues, depends on
	 * how many hw pipes available on the system
	 */
	int queue_count;
	struct sde_rot_queue *commitq;
	struct sde_rot_queue *doneq;

	/*
	 * managing all the open file sessions to bw calculations,
	 * and resource clean up during suspend
	 */
	struct list_head file_list;

	u64 pending_close_bw_vote;
	u64 minimum_bw_vote;
	u64 enable_bw_vote;
	struct sde_rot_bus_data_type data_bus;
	struct sde_rot_bus_data_type reg_bus;

	/* Module power is only used for regulator management */
	struct sde_module_power module_power;
	bool regulator_enable;

	int res_ref_cnt;
	int rot_enable_clk_cnt;
	struct sde_rot_clk *rot_clk;
	int num_rot_clk;
	u32 rdot_limit;
	u32 wrot_limit;

	u32 hwacquire_timeout;
	struct sde_mult_factor pixel_per_clk;
	struct sde_mult_factor fudge_factor;
	struct sde_mult_factor overhead;
	unsigned long min_rot_clk;
	unsigned long max_rot_clk;

	struct sde_rot_file_private *sbuf_ctx;

	int (*ops_config_hw)(struct sde_rot_hw_resource *hw,
			struct sde_rot_entry *entry);
	int (*ops_cancel_hw)(struct sde_rot_hw_resource *hw,
			struct sde_rot_entry *entry);
	int (*ops_abort_hw)(struct sde_rot_hw_resource *hw,
			struct sde_rot_entry *entry);
	int (*ops_kickoff_entry)(struct sde_rot_hw_resource *hw,
			struct sde_rot_entry *entry);
	int (*ops_wait_for_entry)(struct sde_rot_hw_resource *hw,
			struct sde_rot_entry *entry);
	struct sde_rot_hw_resource *(*ops_hw_alloc)(struct sde_rot_mgr *mgr,
			u32 pipe_id, u32 wb_id);
	void (*ops_hw_free)(struct sde_rot_mgr *mgr,
			struct sde_rot_hw_resource *hw);
	int (*ops_hw_init)(struct sde_rot_mgr *mgr);
	void (*ops_hw_pre_pmevent)(struct sde_rot_mgr *mgr, bool pmon);
	void (*ops_hw_post_pmevent)(struct sde_rot_mgr *mgr, bool pmon);
	void (*ops_hw_destroy)(struct sde_rot_mgr *mgr);
	ssize_t (*ops_hw_show_caps)(struct sde_rot_mgr *mgr,
			struct device_attribute *attr, char *buf, ssize_t len);
	ssize_t (*ops_hw_show_state)(struct sde_rot_mgr *mgr,
			struct device_attribute *attr, char *buf, ssize_t len);
	int (*ops_hw_create_debugfs)(struct sde_rot_mgr *mgr,
			struct dentry *debugfs_root);
	int (*ops_hw_validate_entry)(struct sde_rot_mgr *mgr,
			struct sde_rot_entry *entry);
	u32 (*ops_hw_get_pixfmt)(struct sde_rot_mgr *mgr, int index,
			bool input, u32 mode);
	int (*ops_hw_is_valid_pixfmt)(struct sde_rot_mgr *mgr, u32 pixfmt,
			bool input, u32 mode);
	int (*ops_hw_get_downscale_caps)(struct sde_rot_mgr *mgr, char *caps,
			int len);
	int (*ops_hw_get_maxlinewidth)(struct sde_rot_mgr *mgr);
	void (*ops_hw_dump_status)(struct sde_rot_mgr *mgr);

	void *hw_data;
};

static inline int sde_rotator_is_valid_pixfmt(struct sde_rot_mgr *mgr,
		u32 pixfmt, bool input, u32 mode)
{
	if (mgr && mgr->ops_hw_is_valid_pixfmt)
		return mgr->ops_hw_is_valid_pixfmt(mgr, pixfmt, input, mode);

	return false;
}

static inline u32 sde_rotator_get_pixfmt(struct sde_rot_mgr *mgr,
		int index, bool input, u32 mode)
{
	if (mgr && mgr->ops_hw_get_pixfmt)
		return mgr->ops_hw_get_pixfmt(mgr, index, input, mode);

	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 sde_rotator_get_maxlinewidth(struct sde_rot_mgr *mgr)
{
	if (mgr && mgr->ops_hw_get_maxlinewidth)
		return mgr->ops_hw_get_maxlinewidth(mgr);

	return 2048;
}

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)
{
	if ((s_rect->width != i_rect->w) || (s_rect->height != i_rect->h) ||
			(s_rect->format != i_fmt)) {
		SDEROT_DBG(
			"%s: session{%u,%u}f:%u mismatch from item{%u,%u}f:%u\n",
			(src ? "src":"dst"), s_rect->width, s_rect->height,
			s_rect->format, i_rect->w, i_rect->h, i_fmt);
		return -EINVAL;
	}
	return 0;
}

/*
 * Compare all important flag bits associated with rotation between session
 * config and item request. Format and roi validation is done during open
 * session and is based certain defining bits. If these defining bits are
 * different in item request, there is a possibility that rotation item
 * is not a valid configuration.
 */
static inline int __compare_session_rotations(uint32_t cfg_flag,
	uint32_t item_flag)
{
	cfg_flag &= SDE_ROT_DEFINING_FLAG_BITS;
	item_flag &= SDE_ROT_DEFINING_FLAG_BITS;
	if (cfg_flag != item_flag) {
		SDEROT_DBG(
			"Rotation degree request different from open session\n");
		return -EINVAL;
	}
	return 0;
}

/*
 * sde_rotator_core_init - initialize rotator manager for the given platform
 *	device
 * @pmgr: Pointer to pointer of the newly initialized rotator manager
 * @pdev: Pointer to platform device
 * return: 0 if success; error code otherwise
 */
int sde_rotator_core_init(struct sde_rot_mgr **pmgr,
		struct platform_device *pdev);

/*
 * sde_rotator_core_destroy - destroy given rotator manager
 * @mgr: Pointer to rotator manager
 * return: none
 */
void sde_rotator_core_destroy(struct sde_rot_mgr *mgr);

/*
 * sde_rotator_core_dump - perform register dump
 * @mgr: Pointer to rotator manager
 */
void sde_rotator_core_dump(struct sde_rot_mgr *mgr);

/*
 * sde_rotator_session_open - open a new rotator per file session
 * @mgr: Pointer to rotator manager
 * @pprivate: Pointer to pointer of the newly initialized per file session
 * @session_id: identifier of the newly created session
 * @queue: Pointer to fence queue of the new session
 * return: 0 if success; error code otherwise
 */
int sde_rotator_session_open(struct sde_rot_mgr *mgr,
	struct sde_rot_file_private **pprivate, int session_id,
	struct sde_rot_queue_v1 *queue);

/*
 * sde_rotator_session_close - close the given rotator per file session
 * @mgr: Pointer to rotator manager
 * @private: Pointer to per file session
 * @session_id: identifier of the session
 * return: none
 */
void sde_rotator_session_close(struct sde_rot_mgr *mgr,
	struct sde_rot_file_private *private, int session_id);

/*
 * sde_rotator_session_config - configure the given rotator per file session
 * @mgr: Pointer to rotator manager
 * @private: Pointer to  per file session
 * @config: Pointer to rotator configuration
 * return: 0 if success; error code otherwise
 */
int sde_rotator_session_config(struct sde_rot_mgr *mgr,
	struct sde_rot_file_private *private,
	struct sde_rotation_config *config);

/*
 * sde_rotator_session_validate - validate session configuration
 * @mgr: Pointer to rotator manager
 * @private: Pointer to per file session
 * @config: Pointer to rotator configuration
 * return: 0 if success; error code otherwise
 */
int sde_rotator_session_validate(struct sde_rot_mgr *mgr,
	struct sde_rot_file_private *private,
	struct sde_rotation_config *config);

/*
 * sde_rotator_req_init - allocate a new request and initialzie with given
 *	array of rotation items
 * @rot_dev: Pointer to rotator device
 * @private: Pointer to rotator manager per file context
 * @items: Pointer to array of rotation item
 * @count: size of rotation item array
 * @flags: rotation request flags
 * return: Pointer to new rotation request if success; ERR_PTR otherwise
 */
struct sde_rot_entry_container *sde_rotator_req_init(
	struct sde_rot_mgr *rot_dev,
	struct sde_rot_file_private *private,
	struct sde_rotation_item *items,
	u32 count, u32 flags);

/*
 * sde_rotator_req_reset_start - reset inline h/w 'start' indicator
 *	For inline rotations, the time of rotation start is not controlled
 *	by the rotator driver. This function resets an internal 'start'
 *	indicator that allows the rotator to delay its rotator
 *	timeout waiting until such time as the inline rotation has
 *	really started.
 * @mgr: Pointer to rotator manager
 * @req: Pointer to rotation request
 */
void sde_rotator_req_reset_start(struct sde_rot_mgr *mgr,
		struct sde_rot_entry_container *req);

/*
 * sde_rotator_req_set_start - set inline h/w 'start' indicator
 * @mgr: Pointer to rotator manager
 * @req: Pointer to rotation request
 */
void sde_rotator_req_set_start(struct sde_rot_mgr *mgr,
		struct sde_rot_entry_container *req);

/*
 * sde_rotator_req_wait_start - wait for inline h/w 'start' indicator
 * @mgr: Pointer to rotator manager
 * @req: Pointer to rotation request
 * return: Zero on success
 */
int sde_rotator_req_wait_start(struct sde_rot_mgr *mgr,
		struct sde_rot_entry_container *req);

/*
 * sde_rotator_req_finish - notify manager that client is finished with the
 *	given request and manager can release the request as required
 * @mgr: Pointer to rotator manager
 * @private: Pointer to rotator manager per file context
 * @req: Pointer to rotation request
 * return: none
 */
void sde_rotator_req_finish(struct sde_rot_mgr *mgr,
	struct sde_rot_file_private *private,
	struct sde_rot_entry_container *req);

/*
 * sde_rotator_abort_inline_request - abort inline rotation request after start
 *	This function allows inline rotation requests to be aborted after
 *	sde_rotator_req_set_start has already been issued.
 * @mgr: Pointer to rotator manager
 * @private: Pointer to rotator manager per file context
 * @req: Pointer to rotation request
 * return: none
 */
void sde_rotator_abort_inline_request(struct sde_rot_mgr *mgr,
		struct sde_rot_file_private *private,
		struct sde_rot_entry_container *req);

/*
 * sde_rotator_handle_request_common - add the given request to rotator
 *	manager and clean up completed requests
 * @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
 */
int sde_rotator_handle_request_common(struct sde_rot_mgr *rot_dev,
	struct sde_rot_file_private *ctx,
	struct sde_rot_entry_container *req);

/*
 * sde_rotator_queue_request - queue/schedule the given request for 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_queue_request(struct sde_rot_mgr *rot_dev,
	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
 * @config: Pointer to rotator configuration
 * return: 0 if success; error code otherwise
 */
int sde_rotator_verify_config_all(struct sde_rot_mgr *rot_dev,
	struct sde_rotation_config *config);

/*
 * sde_rotator_verify_config_input - verify rotation input configuration
 * @rot_dev: Pointer to rotator device
 * @config: Pointer to rotator configuration
 * return: 0 if success; error code otherwise
 */
int sde_rotator_verify_config_input(struct sde_rot_mgr *rot_dev,
	struct sde_rotation_config *config);

/*
 * sde_rotator_verify_config_output - verify rotation output configuration
 * @rot_dev: Pointer to rotator device
 * @config: Pointer to rotator configuration
 * return: 0 if success; error code otherwise
 */
int sde_rotator_verify_config_output(struct sde_rot_mgr *rot_dev,
	struct sde_rotation_config *config);

/*
 * sde_rotator_validate_request - validates given rotation request with
 *	previous rotator configuration
 * @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
 */
int sde_rotator_validate_request(struct sde_rot_mgr *rot_dev,
	struct sde_rot_file_private *ctx,
	struct sde_rot_entry_container *req);

/*
 * sde_rotator_clk_ctrl - enable/disable rotator clock with reference counting
 * @mgr: Pointer to rotator manager
 * @enable: true to enable clock; false to disable clock
 * return: 0 if success; error code otherwise
 */
int sde_rotator_clk_ctrl(struct sde_rot_mgr *mgr, int enable);

/* sde_rotator_resource_ctrl_enabled - check if resource control is enabled
 * @mgr: Pointer to rotator manager
 * Return: true if enabled; false otherwise
 */
static inline int sde_rotator_resource_ctrl_enabled(struct sde_rot_mgr *mgr)
{
	return mgr->regulator_enable;
}

/*
 * sde_rotator_cancel_all_requests - cancel all outstanding requests
 * @mgr: Pointer to rotator manager
 * @private: Pointer to rotator manager per file context
 */
void sde_rotator_cancel_all_requests(struct sde_rot_mgr *mgr,
	struct sde_rot_file_private *private);

/*
 * sde_rot_mgr_lock - serialization lock prior to rotator manager calls
 * @mgr: Pointer to rotator manager
 */
static inline void sde_rot_mgr_lock(struct sde_rot_mgr *mgr)
{
	mutex_lock(&mgr->lock);
}

/*
 * sde_rot_mgr_lock - serialization unlock after rotator manager calls
 * @mgr: Pointer to rotator manager
 */
static inline void sde_rot_mgr_unlock(struct sde_rot_mgr *mgr)
{
	mutex_unlock(&mgr->lock);
}

/*
 * sde_rot_mgr_pd_enabled - return true if power domain is enabled
 * @mgr: Pointer to rotator manager
 */
static inline bool sde_rot_mgr_pd_enabled(struct sde_rot_mgr *mgr)
{
	return mgr && mgr->device && mgr->device->pm_domain;
}

#if defined(CONFIG_PM)
int sde_rotator_runtime_resume(struct device *dev);
int sde_rotator_runtime_suspend(struct device *dev);
int sde_rotator_runtime_idle(struct device *dev);
#endif

#if defined(CONFIG_PM_SLEEP)
int sde_rotator_pm_suspend(struct device *dev);
int sde_rotator_pm_resume(struct device *dev);
#endif

#if defined(CONFIG_PM) && !defined(CONFIG_PM_SLEEP)
int sde_rotator_suspend(struct platform_device *dev, pm_message_t state);
int sde_rotator_resume(struct platform_device *dev);
#else
#define sde_rotator_suspend NULL
#define sde_rotator_resume NULL
#endif
#endif /* __SDE_ROTATOR_CORE_H__ */
