162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-or-later */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2017 Samsung Electronics Co., Ltd.
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#ifndef _EXYNOS_DRM_IPP_H_
762306a36Sopenharmony_ci#define _EXYNOS_DRM_IPP_H_
862306a36Sopenharmony_ci
962306a36Sopenharmony_cistruct exynos_drm_ipp;
1062306a36Sopenharmony_cistruct exynos_drm_ipp_task;
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci/**
1362306a36Sopenharmony_ci * struct exynos_drm_ipp_funcs - exynos_drm_ipp control functions
1462306a36Sopenharmony_ci */
1562306a36Sopenharmony_cistruct exynos_drm_ipp_funcs {
1662306a36Sopenharmony_ci	/**
1762306a36Sopenharmony_ci	 * @commit:
1862306a36Sopenharmony_ci	 *
1962306a36Sopenharmony_ci	 * This is the main entry point to start framebuffer processing
2062306a36Sopenharmony_ci	 * in the hardware. The exynos_drm_ipp_task has been already validated.
2162306a36Sopenharmony_ci	 * This function must not wait until the device finishes processing.
2262306a36Sopenharmony_ci	 * When the driver finishes processing, it has to call
2362306a36Sopenharmony_ci	 * exynos_exynos_drm_ipp_task_done() function.
2462306a36Sopenharmony_ci	 *
2562306a36Sopenharmony_ci	 * RETURNS:
2662306a36Sopenharmony_ci	 *
2762306a36Sopenharmony_ci	 * 0 on success or negative error codes in case of failure.
2862306a36Sopenharmony_ci	 */
2962306a36Sopenharmony_ci	int (*commit)(struct exynos_drm_ipp *ipp,
3062306a36Sopenharmony_ci		      struct exynos_drm_ipp_task *task);
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci	/**
3362306a36Sopenharmony_ci	 * @abort:
3462306a36Sopenharmony_ci	 *
3562306a36Sopenharmony_ci	 * Informs the driver that it has to abort the currently running
3662306a36Sopenharmony_ci	 * task as soon as possible (i.e. as soon as it can stop the device
3762306a36Sopenharmony_ci	 * safely), even if the task would not have been finished by then.
3862306a36Sopenharmony_ci	 * After the driver performs the necessary steps, it has to call
3962306a36Sopenharmony_ci	 * exynos_drm_ipp_task_done() (as if the task ended normally).
4062306a36Sopenharmony_ci	 * This function does not have to (and will usually not) wait
4162306a36Sopenharmony_ci	 * until the device enters a state when it can be stopped.
4262306a36Sopenharmony_ci	 */
4362306a36Sopenharmony_ci	void (*abort)(struct exynos_drm_ipp *ipp,
4462306a36Sopenharmony_ci		      struct exynos_drm_ipp_task *task);
4562306a36Sopenharmony_ci};
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci/**
4862306a36Sopenharmony_ci * struct exynos_drm_ipp - central picture processor module structure
4962306a36Sopenharmony_ci */
5062306a36Sopenharmony_cistruct exynos_drm_ipp {
5162306a36Sopenharmony_ci	struct drm_device *drm_dev;
5262306a36Sopenharmony_ci	struct device *dev;
5362306a36Sopenharmony_ci	struct list_head head;
5462306a36Sopenharmony_ci	unsigned int id;
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	const char *name;
5762306a36Sopenharmony_ci	const struct exynos_drm_ipp_funcs *funcs;
5862306a36Sopenharmony_ci	unsigned int capabilities;
5962306a36Sopenharmony_ci	const struct exynos_drm_ipp_formats *formats;
6062306a36Sopenharmony_ci	unsigned int num_formats;
6162306a36Sopenharmony_ci	atomic_t sequence;
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	spinlock_t lock;
6462306a36Sopenharmony_ci	struct exynos_drm_ipp_task *task;
6562306a36Sopenharmony_ci	struct list_head todo_list;
6662306a36Sopenharmony_ci	wait_queue_head_t done_wq;
6762306a36Sopenharmony_ci};
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_cistruct exynos_drm_ipp_buffer {
7062306a36Sopenharmony_ci	struct drm_exynos_ipp_task_buffer buf;
7162306a36Sopenharmony_ci	struct drm_exynos_ipp_task_rect rect;
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	struct exynos_drm_gem *exynos_gem[MAX_FB_BUFFER];
7462306a36Sopenharmony_ci	const struct drm_format_info *format;
7562306a36Sopenharmony_ci	dma_addr_t dma_addr[MAX_FB_BUFFER];
7662306a36Sopenharmony_ci};
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci/**
7962306a36Sopenharmony_ci * struct exynos_drm_ipp_task - a structure describing transformation that
8062306a36Sopenharmony_ci * has to be performed by the picture processor hardware module
8162306a36Sopenharmony_ci */
8262306a36Sopenharmony_cistruct exynos_drm_ipp_task {
8362306a36Sopenharmony_ci	struct device *dev;
8462306a36Sopenharmony_ci	struct exynos_drm_ipp *ipp;
8562306a36Sopenharmony_ci	struct list_head head;
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	struct exynos_drm_ipp_buffer src;
8862306a36Sopenharmony_ci	struct exynos_drm_ipp_buffer dst;
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	struct drm_exynos_ipp_task_transform transform;
9162306a36Sopenharmony_ci	struct drm_exynos_ipp_task_alpha alpha;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	struct work_struct cleanup_work;
9462306a36Sopenharmony_ci	unsigned int flags;
9562306a36Sopenharmony_ci	int ret;
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	struct drm_pending_exynos_ipp_event *event;
9862306a36Sopenharmony_ci};
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci#define DRM_EXYNOS_IPP_TASK_DONE	(1 << 0)
10162306a36Sopenharmony_ci#define DRM_EXYNOS_IPP_TASK_ASYNC	(1 << 1)
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_cistruct exynos_drm_ipp_formats {
10462306a36Sopenharmony_ci	uint32_t fourcc;
10562306a36Sopenharmony_ci	uint32_t type;
10662306a36Sopenharmony_ci	uint64_t modifier;
10762306a36Sopenharmony_ci	const struct drm_exynos_ipp_limit *limits;
10862306a36Sopenharmony_ci	unsigned int num_limits;
10962306a36Sopenharmony_ci};
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci/* helper macros to set exynos_drm_ipp_formats structure and limits*/
11262306a36Sopenharmony_ci#define IPP_SRCDST_MFORMAT(f, m, l) \
11362306a36Sopenharmony_ci	.fourcc = DRM_FORMAT_##f, .modifier = m, .limits = l, \
11462306a36Sopenharmony_ci	.num_limits = ARRAY_SIZE(l), \
11562306a36Sopenharmony_ci	.type = (DRM_EXYNOS_IPP_FORMAT_SOURCE | \
11662306a36Sopenharmony_ci		 DRM_EXYNOS_IPP_FORMAT_DESTINATION)
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci#define IPP_SRCDST_FORMAT(f, l) IPP_SRCDST_MFORMAT(f, 0, l)
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci#define IPP_SIZE_LIMIT(l, val...)	\
12162306a36Sopenharmony_ci	.type = (DRM_EXYNOS_IPP_LIMIT_TYPE_SIZE | \
12262306a36Sopenharmony_ci		 DRM_EXYNOS_IPP_LIMIT_SIZE_##l), val
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci#define IPP_SCALE_LIMIT(val...)		\
12562306a36Sopenharmony_ci	.type = (DRM_EXYNOS_IPP_LIMIT_TYPE_SCALE), val
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ciint exynos_drm_ipp_register(struct device *dev, struct exynos_drm_ipp *ipp,
12862306a36Sopenharmony_ci		const struct exynos_drm_ipp_funcs *funcs, unsigned int caps,
12962306a36Sopenharmony_ci		const struct exynos_drm_ipp_formats *formats,
13062306a36Sopenharmony_ci		unsigned int num_formats, const char *name);
13162306a36Sopenharmony_civoid exynos_drm_ipp_unregister(struct device *dev,
13262306a36Sopenharmony_ci			       struct exynos_drm_ipp *ipp);
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_civoid exynos_drm_ipp_task_done(struct exynos_drm_ipp_task *task, int ret);
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci#ifdef CONFIG_DRM_EXYNOS_IPP
13762306a36Sopenharmony_ciint exynos_drm_ipp_get_res_ioctl(struct drm_device *dev, void *data,
13862306a36Sopenharmony_ci				 struct drm_file *file_priv);
13962306a36Sopenharmony_ciint exynos_drm_ipp_get_caps_ioctl(struct drm_device *dev, void *data,
14062306a36Sopenharmony_ci				  struct drm_file *file_priv);
14162306a36Sopenharmony_ciint exynos_drm_ipp_get_limits_ioctl(struct drm_device *dev, void *data,
14262306a36Sopenharmony_ci				    struct drm_file *file_priv);
14362306a36Sopenharmony_ciint exynos_drm_ipp_commit_ioctl(struct drm_device *dev,
14462306a36Sopenharmony_ci				void *data, struct drm_file *file_priv);
14562306a36Sopenharmony_ci#else
14662306a36Sopenharmony_cistatic inline int exynos_drm_ipp_get_res_ioctl(struct drm_device *dev,
14762306a36Sopenharmony_ci	 void *data, struct drm_file *file_priv)
14862306a36Sopenharmony_ci{
14962306a36Sopenharmony_ci	struct drm_exynos_ioctl_ipp_get_res *resp = data;
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	resp->count_ipps = 0;
15262306a36Sopenharmony_ci	return 0;
15362306a36Sopenharmony_ci}
15462306a36Sopenharmony_cistatic inline int exynos_drm_ipp_get_caps_ioctl(struct drm_device *dev,
15562306a36Sopenharmony_ci	 void *data, struct drm_file *file_priv)
15662306a36Sopenharmony_ci{
15762306a36Sopenharmony_ci	return -ENODEV;
15862306a36Sopenharmony_ci}
15962306a36Sopenharmony_cistatic inline int exynos_drm_ipp_get_limits_ioctl(struct drm_device *dev,
16062306a36Sopenharmony_ci	 void *data, struct drm_file *file_priv)
16162306a36Sopenharmony_ci{
16262306a36Sopenharmony_ci	return -ENODEV;
16362306a36Sopenharmony_ci}
16462306a36Sopenharmony_cistatic inline int exynos_drm_ipp_commit_ioctl(struct drm_device *dev,
16562306a36Sopenharmony_ci	 void *data, struct drm_file *file_priv)
16662306a36Sopenharmony_ci{
16762306a36Sopenharmony_ci	return -ENODEV;
16862306a36Sopenharmony_ci}
16962306a36Sopenharmony_ci#endif
17062306a36Sopenharmony_ci#endif
171